machinaos 0.0.76 → 0.0.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. package/README.md +143 -107
  2. package/client/dist/assets/ActionBar-Du2MSFSz.js +1 -0
  3. package/client/dist/assets/ApiKeyInput-k2LBmBjb.js +1 -0
  4. package/client/dist/assets/ApiKeyPanel-C_bV9U0X.js +1 -0
  5. package/client/dist/assets/ApiUsageSection-CmVfwZzL.js +1 -0
  6. package/client/dist/assets/EmailPanel-CeKIMGu-.js +1 -0
  7. package/client/dist/assets/OAuthPanel-KA3t3Q2K.js +1 -0
  8. package/client/dist/assets/QrPairingPanel-NgNpJNuk.js +1 -0
  9. package/client/dist/assets/RateLimitSection-Du5YNVIA.js +1 -0
  10. package/client/dist/assets/StatusCard-DNLyayXc.js +1 -0
  11. package/client/dist/assets/index-DQ0nwhec.js +257 -0
  12. package/client/dist/assets/index-DxmbVskS.css +1 -0
  13. package/client/dist/assets/vendor-flow-CZmBvHRo.js +1 -0
  14. package/client/dist/assets/vendor-icons-CVrPjN2Q.js +22 -0
  15. package/client/dist/assets/vendor-markdown-CRou3yQ5.js +62 -0
  16. package/client/dist/assets/vendor-misc-C4VxKHs5.js +1 -0
  17. package/client/dist/assets/vendor-query-SzWcOU0G.js +1 -0
  18. package/client/dist/assets/vendor-radix-Dnos29jG.js +56 -0
  19. package/client/dist/assets/vendor-react-DvWIbVx0.js +1 -0
  20. package/client/dist/index.html +37 -3
  21. package/client/index.html +28 -1
  22. package/client/package.json +44 -40
  23. package/client/src/App.tsx +2 -0
  24. package/client/src/Dashboard.tsx +157 -45
  25. package/client/src/ParameterPanel.tsx +3 -5
  26. package/client/src/adapters/nodeSpecToDescription.ts +1 -0
  27. package/client/src/assets/icons/NodeIcon.tsx +32 -0
  28. package/client/src/assets/icons/index.ts +4 -0
  29. package/client/src/assets/icons/stripe.svg +1 -0
  30. package/client/src/assets/icons/themedGlyphs.ts +404 -0
  31. package/client/src/components/AIAgentNode.tsx +77 -53
  32. package/client/src/components/GenericNode.tsx +34 -52
  33. package/client/src/components/OutputPanel.tsx +64 -147
  34. package/client/src/components/ParameterRenderer.tsx +5 -3
  35. package/client/src/components/SkillEditorModal.tsx +9 -18
  36. package/client/src/components/SquareNode.tsx +97 -115
  37. package/client/src/components/StartNode.tsx +32 -42
  38. package/client/src/components/SvgFilterDefs.tsx +54 -0
  39. package/client/src/components/TeamMonitorNode.tsx +12 -14
  40. package/client/src/components/ToolkitNode.tsx +35 -60
  41. package/client/src/components/TriggerNode.tsx +43 -77
  42. package/client/src/components/__tests__/CredentialsModal.test.tsx +49 -45
  43. package/client/src/components/credentials/CredentialsModal.tsx +98 -30
  44. package/client/src/components/credentials/CredentialsPalette.tsx +73 -5
  45. package/client/src/components/credentials/catalogueAdapter.ts +17 -1
  46. package/client/src/components/credentials/panels/ApiKeyPanel.tsx +102 -37
  47. package/client/src/components/credentials/panels/EmailPanel.tsx +7 -19
  48. package/client/src/components/credentials/panels/OAuthPanel.tsx +5 -1
  49. package/client/src/components/credentials/panels/QrPairingPanel.tsx +1 -3
  50. package/client/src/components/credentials/primitives/ActionBar.tsx +7 -11
  51. package/client/src/components/credentials/primitives/OAuthConnect.tsx +19 -28
  52. package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +24 -3
  53. package/client/src/components/credentials/types.ts +12 -2
  54. package/client/src/components/credentials/useCredentialPanel.ts +43 -19
  55. package/client/src/components/icons/AIProviderIcons.tsx +16 -0
  56. package/client/src/components/onboarding/OnboardingWizard.tsx +23 -63
  57. package/client/src/components/onboarding/nodeRoleClasses.ts +23 -0
  58. package/client/src/components/onboarding/steps/CanvasStep.tsx +15 -21
  59. package/client/src/components/onboarding/steps/ConceptsStep.tsx +2 -11
  60. package/client/src/components/onboarding/steps/GetStartedStep.tsx +2 -10
  61. package/client/src/components/parameterPanel/InputSection.tsx +9 -7
  62. package/client/src/components/parameterPanel/MasterSkillEditor.tsx +84 -198
  63. package/client/src/components/parameterPanel/MiddleSection.tsx +57 -80
  64. package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +31 -25
  65. package/client/src/components/parameterPanel/__tests__/InputSection.test.tsx +7 -2
  66. package/client/src/components/ui/AIResultModal.tsx +1 -1
  67. package/client/src/components/ui/CollapsibleSection.tsx +9 -5
  68. package/client/src/components/ui/CommandPalette.tsx +147 -0
  69. package/client/src/components/ui/CommandPaletteHost.tsx +189 -0
  70. package/client/src/components/ui/ComponentItem.tsx +13 -7
  71. package/client/src/components/ui/ComponentPalette.tsx +24 -13
  72. package/client/src/components/ui/ConsolePanel.tsx +19 -11
  73. package/client/src/components/ui/DropCap.tsx +28 -0
  74. package/client/src/components/ui/EditableNodeLabel.tsx +10 -2
  75. package/client/src/components/ui/InputNodesPanel.tsx +1 -1
  76. package/client/src/components/ui/Modal.tsx +38 -6
  77. package/client/src/components/ui/OutputDisplayPanel.tsx +1 -1
  78. package/client/src/components/ui/SettingsPanel.tsx +42 -13
  79. package/client/src/components/ui/StatusBar.tsx +108 -0
  80. package/client/src/components/ui/ThemeSwitcher.tsx +109 -0
  81. package/client/src/components/ui/TopToolbar.tsx +42 -25
  82. package/client/src/components/ui/WorkflowSidebar.tsx +32 -16
  83. package/client/src/components/ui/action-button.tsx +40 -15
  84. package/client/src/components/ui/button.tsx +24 -1
  85. package/client/src/components/ui/dropdown-menu.tsx +24 -2
  86. package/client/src/components/ui/input.tsx +19 -2
  87. package/client/src/components/ui/select.tsx +15 -0
  88. package/client/src/components/ui/textarea.tsx +15 -2
  89. package/client/src/contexts/AuthContext.tsx +148 -109
  90. package/client/src/contexts/ThemeContext.tsx +93 -17
  91. package/client/src/contexts/WebSocketContext.tsx +373 -206
  92. package/client/src/contexts/__tests__/AuthContext.test.tsx +221 -0
  93. package/client/src/hooks/__tests__/useDragVariable.test.ts +7 -1
  94. package/client/src/hooks/__tests__/useWorkflowOpsListener.test.ts +142 -0
  95. package/client/src/hooks/useAppTheme.ts +209 -7
  96. package/client/src/hooks/useAutoSkillEdges.ts +7 -2
  97. package/client/src/hooks/useCatalogueQuery.ts +67 -1
  98. package/client/src/hooks/useDragVariable.ts +1 -1
  99. package/client/src/hooks/useNodeAllowlist.ts +115 -8
  100. package/client/src/hooks/useOnboarding.ts +20 -8
  101. package/client/src/hooks/useParameterPanel.ts +2 -1
  102. package/client/src/hooks/useReactFlowNodes.ts +2 -1
  103. package/client/src/hooks/useSound.ts +185 -0
  104. package/client/src/hooks/useWorkflowManagement.ts +6 -8
  105. package/client/src/hooks/useWorkflowOpsListener.ts +90 -0
  106. package/client/src/index.css +65 -3
  107. package/client/src/lib/__tests__/connectionConfig.test.ts +91 -0
  108. package/client/src/lib/aiModelProviders.ts +8 -0
  109. package/client/src/lib/connectionConfig.ts +107 -0
  110. package/client/src/lib/queryPersist.ts +13 -5
  111. package/client/src/lib/sound.ts +393 -0
  112. package/client/src/main.tsx +20 -0
  113. package/client/src/store/useAppStore.ts +26 -0
  114. package/client/src/styles/canvasAnimations.ts +37 -36
  115. package/client/src/styles/theme.ts +36 -20
  116. package/client/src/test/setup.ts +1 -0
  117. package/client/src/themes/atomic.css +253 -0
  118. package/client/src/themes/base.css +373 -0
  119. package/client/src/themes/cyber.css +890 -0
  120. package/client/src/themes/dark.css +70 -0
  121. package/client/src/themes/edo.css +246 -0
  122. package/client/src/themes/greek.css +293 -0
  123. package/client/src/themes/light.css +78 -0
  124. package/client/src/themes/plague.css +253 -0
  125. package/client/src/themes/renaissance.css +727 -0
  126. package/client/src/themes/rot.css +249 -0
  127. package/client/src/themes/steampunk.css +272 -0
  128. package/client/src/themes/surveillance.css +289 -0
  129. package/client/src/themes/wasteland.css +250 -0
  130. package/client/src/types/INodeProperties.ts +5 -0
  131. package/client/src/types/NodeTypes.ts +11 -1
  132. package/client/src/types/__tests__/cloudEvents.test.ts +99 -0
  133. package/client/src/types/cloudEvents.ts +78 -0
  134. package/client/src/vite-env.d.ts +7 -0
  135. package/client/tsconfig.json +1 -1
  136. package/client/vite.config.js +62 -2
  137. package/install.ps1 +1 -1
  138. package/install.sh +1 -1
  139. package/machina/commands/build.py +51 -7
  140. package/machina/pyproject.toml +4 -0
  141. package/machina/supervisor.py +12 -2
  142. package/machina/tree.py +71 -21
  143. package/package.json +4 -4
  144. package/scripts/install.js +16 -1
  145. package/server/config/ai_cli_providers.json +54 -0
  146. package/server/config/credential_providers.json +109 -2
  147. package/server/config/llm_defaults.json +24 -0
  148. package/server/config/model_registry.json +338 -499
  149. package/server/config/node_allowlist.json +16 -1
  150. package/server/config/pricing.json +8 -0
  151. package/server/constants.py +38 -15
  152. package/server/core/container.py +2 -2
  153. package/server/core/credentials_database.py +35 -2
  154. package/server/core/logging.py +4 -3
  155. package/server/main.py +99 -13
  156. package/server/models/node_metadata.py +1 -0
  157. package/server/nodejs/package.json +8 -6
  158. package/server/nodejs/src/index.ts +22 -5
  159. package/server/nodes/README.md +31 -4
  160. package/server/nodes/agent/_inline.py +2 -0
  161. package/server/nodes/agent/_specialized.py +6 -3
  162. package/server/nodes/agent/ai_agent.py +13 -3
  163. package/server/nodes/agent/chat_agent.py +6 -3
  164. package/server/nodes/agent/claude_code_agent.py +287 -75
  165. package/server/nodes/agent/codex_agent.py +239 -0
  166. package/server/nodes/agent/deep_agent.py +3 -3
  167. package/server/nodes/agent/rlm_agent.py +3 -3
  168. package/server/nodes/android/__init__.py +31 -1
  169. package/server/nodes/android/_base.py +9 -5
  170. package/server/{services/android_service.py → nodes/android/_dispatcher.py} +2 -2
  171. package/server/nodes/android/_handlers.py +154 -0
  172. package/server/nodes/android/_option_loaders.py +44 -0
  173. package/server/nodes/android/_refresh.py +127 -0
  174. package/server/{services/android → nodes/android/_relay}/client.py +4 -4
  175. package/server/{routers/android.py → nodes/android/_router.py} +27 -8
  176. package/server/nodes/browser/browser.py +2 -2
  177. package/server/nodes/code/_base.py +6 -2
  178. package/server/nodes/code/_claude_code.py +134 -0
  179. package/server/nodes/document/embedding_generator.py +3 -3
  180. package/server/nodes/document/http_scraper.py +3 -3
  181. package/server/nodes/document/vector_store.py +5 -5
  182. package/server/nodes/email/__init__.py +11 -1
  183. package/server/nodes/email/_filters.py +21 -0
  184. package/server/{services/himalaya_service.py → nodes/email/_himalaya.py} +6 -10
  185. package/server/{services/email_service.py → nodes/email/_service.py} +9 -13
  186. package/server/nodes/email/email_read.py +1 -1
  187. package/server/nodes/email/email_receive.py +54 -5
  188. package/server/nodes/email/email_send.py +1 -1
  189. package/server/nodes/filesystem/shell.py +24 -1
  190. package/server/nodes/google/__init__.py +55 -1
  191. package/server/{services/handlers/google_auth.py → nodes/google/_auth_helper.py} +8 -5
  192. package/server/nodes/google/_base.py +2 -2
  193. package/server/nodes/google/_credentials.py +5 -5
  194. package/server/nodes/google/_filters.py +25 -0
  195. package/server/nodes/google/_handlers.py +57 -0
  196. package/server/{services/google_oauth.py → nodes/google/_oauth.py} +195 -162
  197. package/server/nodes/google/_option_loaders.py +107 -0
  198. package/server/nodes/google/_refresh.py +66 -0
  199. package/server/nodes/google/_router.py +131 -0
  200. package/server/nodes/google/gmail_receive.py +41 -4
  201. package/server/nodes/groups.py +1 -0
  202. package/server/nodes/location/_credentials.py +45 -1
  203. package/server/{services/maps.py → nodes/location/_service.py} +18 -3
  204. package/server/nodes/location/gmaps_create.py +4 -4
  205. package/server/nodes/location/gmaps_locations.py +4 -4
  206. package/server/nodes/location/gmaps_nearby_places.py +4 -4
  207. package/server/nodes/model/_base.py +8 -3
  208. package/server/nodes/model/_credentials.py +96 -8
  209. package/server/nodes/model/_local_validator.py +345 -0
  210. package/server/nodes/model/lmstudio_chat_model.py +23 -0
  211. package/server/nodes/model/ollama_chat_model.py +25 -0
  212. package/server/nodes/proxy/_usage.py +2 -2
  213. package/server/nodes/proxy/proxy_config.py +14 -14
  214. package/server/nodes/proxy/proxy_request.py +4 -4
  215. package/server/nodes/scraper/_credentials.py +29 -1
  216. package/server/nodes/scraper/apify_actor.py +9 -9
  217. package/server/nodes/scraper/crawlee_scraper.py +5 -5
  218. package/server/nodes/search/brave_search.py +4 -0
  219. package/server/nodes/search/perplexity_search.py +9 -0
  220. package/server/nodes/search/serper_search.py +3 -0
  221. package/server/nodes/skill/simple_memory.py +12 -0
  222. package/server/nodes/social/_base.py +2 -2
  223. package/server/nodes/stripe/__init__.py +46 -0
  224. package/server/nodes/stripe/_credentials.py +33 -0
  225. package/server/nodes/stripe/_handlers.py +270 -0
  226. package/server/nodes/stripe/_install.py +127 -0
  227. package/server/nodes/stripe/_source.py +174 -0
  228. package/server/nodes/stripe/stripe_action.py +81 -0
  229. package/server/nodes/stripe/stripe_receive.py +92 -0
  230. package/server/nodes/telegram/_credentials.py +52 -1
  231. package/server/nodes/telegram/_handlers.py +19 -18
  232. package/server/nodes/telegram/_service.py +134 -32
  233. package/server/nodes/telegram/telegram_send.py +5 -6
  234. package/server/nodes/text/file_handler.py +2 -2
  235. package/server/nodes/text/text_generator.py +2 -2
  236. package/server/nodes/tool/agent_builder.py +630 -0
  237. package/server/nodes/tool/task_manager.py +144 -2
  238. package/server/nodes/twitter/__init__.py +38 -1
  239. package/server/nodes/twitter/_base.py +7 -7
  240. package/server/nodes/twitter/_credentials.py +1 -1
  241. package/server/nodes/twitter/_filters.py +37 -0
  242. package/server/nodes/twitter/_handlers.py +77 -0
  243. package/server/nodes/twitter/_oauth.py +124 -0
  244. package/server/nodes/twitter/_refresh.py +78 -0
  245. package/server/nodes/twitter/_router.py +29 -0
  246. package/server/nodes/twitter/twitter_receive.py +4 -0
  247. package/server/nodes/visuals.json +64 -19
  248. package/server/nodes/whatsapp/__init__.py +45 -5
  249. package/server/nodes/whatsapp/_base.py +3 -3
  250. package/server/nodes/whatsapp/_filters.py +137 -0
  251. package/server/nodes/whatsapp/_handlers.py +167 -0
  252. package/server/nodes/whatsapp/_option_loaders.py +68 -0
  253. package/server/nodes/whatsapp/_refresh.py +62 -0
  254. package/server/nodes/whatsapp/_runtime.py +1 -1
  255. package/server/pyproject.toml +29 -7
  256. package/server/routers/schemas.py +2 -2
  257. package/server/routers/webhook.py +26 -9
  258. package/server/routers/websocket.py +149 -810
  259. package/server/services/ai.py +89 -8
  260. package/server/services/auth.py +220 -43
  261. package/server/services/claude_oauth.py +126 -100
  262. package/server/services/cli_agent/__init__.py +78 -0
  263. package/server/services/cli_agent/_handlers.py +237 -0
  264. package/server/services/cli_agent/config.py +112 -0
  265. package/server/services/cli_agent/factory.py +48 -0
  266. package/server/services/cli_agent/lockfile.py +141 -0
  267. package/server/services/cli_agent/mcp_server.py +482 -0
  268. package/server/services/cli_agent/protocol.py +173 -0
  269. package/server/services/cli_agent/providers/__init__.py +9 -0
  270. package/server/services/cli_agent/providers/anthropic_claude.py +419 -0
  271. package/server/services/cli_agent/providers/google_gemini.py +80 -0
  272. package/server/services/cli_agent/providers/openai_codex.py +310 -0
  273. package/server/services/cli_agent/service.py +607 -0
  274. package/server/services/cli_agent/session.py +618 -0
  275. package/server/services/cli_agent/types.py +227 -0
  276. package/server/services/cli_agent/workflow_tools.py +233 -0
  277. package/server/services/credential_registry.py +26 -1
  278. package/server/services/deployment/manager.py +26 -145
  279. package/server/services/deployment/poll_registry.py +59 -0
  280. package/server/services/event_waiter.py +76 -246
  281. package/server/services/events/__init__.py +54 -0
  282. package/server/services/events/cli.py +78 -0
  283. package/server/services/events/daemon.py +163 -0
  284. package/server/services/events/envelope.py +281 -0
  285. package/server/services/events/lifecycle.py +99 -0
  286. package/server/services/events/oauth_lifecycle.py +534 -0
  287. package/server/services/events/polling.py +60 -0
  288. package/server/services/events/push.py +36 -0
  289. package/server/services/events/source.py +63 -0
  290. package/server/services/events/triggers.py +118 -0
  291. package/server/services/events/verifiers/__init__.py +25 -0
  292. package/server/services/events/verifiers/base.py +28 -0
  293. package/server/services/events/verifiers/github.py +25 -0
  294. package/server/services/events/verifiers/hmac_basic.py +32 -0
  295. package/server/services/events/verifiers/standard_webhooks.py +47 -0
  296. package/server/services/events/verifiers/stripe.py +42 -0
  297. package/server/services/events/webhook.py +105 -0
  298. package/server/services/handlers/tools.py +28 -186
  299. package/server/services/llm/config.py +7 -0
  300. package/server/services/llm/factory.py +8 -2
  301. package/server/services/memory/__init__.py +52 -0
  302. package/server/services/memory/jsonl.py +80 -0
  303. package/server/services/memory/markdown.py +65 -0
  304. package/server/services/memory/state.py +112 -0
  305. package/server/services/memory/vector_store.py +40 -0
  306. package/server/services/model_registry.py +76 -0
  307. package/server/services/node_allowlist.py +71 -15
  308. package/server/services/node_executor.py +2 -2
  309. package/server/services/node_output_schemas.py +21 -10
  310. package/server/services/node_spec.py +1 -1
  311. package/server/services/oauth_utils.py +1 -1
  312. package/server/services/plugin/__init__.py +2 -0
  313. package/server/services/plugin/base.py +44 -2
  314. package/server/services/plugin/credential.py +288 -1
  315. package/server/services/plugin/deps.py +105 -0
  316. package/server/services/plugin/edge_walker.py +12 -4
  317. package/server/services/plugin/oauth.py +381 -0
  318. package/server/services/plugin/polling.py +247 -0
  319. package/server/services/plugin/registry.py +145 -0
  320. package/server/services/plugin/singleton.py +65 -0
  321. package/server/services/plugin/ws.py +81 -0
  322. package/server/services/process_service.py +31 -2
  323. package/server/services/status_broadcaster.py +155 -238
  324. package/server/services/temporal/workflow.py +7 -7
  325. package/server/services/workflow.py +21 -3
  326. package/server/services/ws_handler_registry.py +111 -28
  327. package/server/skills/GUIDE.md +16 -1
  328. package/server/skills/assistant/agent-builder-skill/SKILL.md +166 -0
  329. package/server/skills/payments_agent/stripe-skill/SKILL.md +306 -0
  330. package/server/tests/credentials/test_auth_service.py +16 -9
  331. package/server/tests/credentials/test_credential_broadcasts.py +219 -0
  332. package/server/tests/credentials/test_google_oauth.py +6 -6
  333. package/server/tests/credentials/test_oauth_utils.py +1 -1
  334. package/server/tests/credentials/test_twitter_oauth.py +2 -2
  335. package/server/tests/credentials/test_websocket_handlers.py +44 -20
  336. package/server/tests/llm/test_factory.py +1 -0
  337. package/server/tests/llm/test_wiring.py +5 -1
  338. package/server/tests/nodes/_compat.py +24 -24
  339. package/server/tests/nodes/test_agent_builder.py +439 -0
  340. package/server/tests/nodes/test_ai_tools.py +18 -14
  341. package/server/tests/nodes/test_code_fs_process.py +17 -8
  342. package/server/tests/nodes/test_email.py +10 -9
  343. package/server/tests/nodes/test_google_workspace.py +2 -2
  344. package/server/tests/nodes/test_specialized_agents.py +100 -53
  345. package/server/tests/nodes/test_stripe_plugin.py +293 -0
  346. package/server/tests/nodes/test_telegram_social.py +4 -4
  347. package/server/tests/nodes/test_twitter.py +1 -1
  348. package/server/tests/nodes/test_web_automation.py +2 -2
  349. package/server/tests/nodes/test_whatsapp.py +9 -9
  350. package/server/tests/services/cli_agent/__init__.py +0 -0
  351. package/server/tests/services/cli_agent/test_mcp_server.py +432 -0
  352. package/server/tests/services/cli_agent/test_providers.py +358 -0
  353. package/server/tests/services/cli_agent/test_service.py +298 -0
  354. package/server/tests/services/memory/__init__.py +0 -0
  355. package/server/tests/services/memory/test_jsonl.py +188 -0
  356. package/server/tests/services/test_events.py +333 -0
  357. package/server/tests/test_node_spec.py +56 -16
  358. package/server/tests/test_plugin_helpers.py +116 -0
  359. package/server/tests/test_plugin_self_containment.py +486 -0
  360. package/server/tests/test_status_broadcasts.py +425 -0
  361. package/workflows/{AI Assistant_workflow-1777421105154-0m4snkzjf.json → AI Assistant_workflow-1778504793388-ou1m1tz2x.json } +70 -266
  362. package/workflows/{AI Employee_workflow-1777720598005-u4cm858dv.json → AI Employee_example_workflow-1777720598005-u4cm858dv.json } +112 -112
  363. package/workflows/Claude Assistant_workflow-1778380124051-mdibn807c.json +709 -0
  364. package/client/dist/assets/ActionBar-vzPpSR77.js +0 -1
  365. package/client/dist/assets/ApiKeyInput-Ds7AKFe8.js +0 -1
  366. package/client/dist/assets/ApiKeyPanel-gfblELep.js +0 -1
  367. package/client/dist/assets/ApiUsageSection-BMNWTe2r.js +0 -1
  368. package/client/dist/assets/EmailPanel-B1Om64p5.js +0 -1
  369. package/client/dist/assets/OAuthPanel-CXyQYGBz.js +0 -1
  370. package/client/dist/assets/QrPairingPanel-BgNuI1we.js +0 -1
  371. package/client/dist/assets/RateLimitSection-YYK8sx1T.js +0 -1
  372. package/client/dist/assets/StatusCard-DuYA5hJR.js +0 -1
  373. package/client/dist/assets/index-D9tZfgvi.js +0 -363
  374. package/client/dist/assets/index-al7snTkG.css +0 -1
  375. package/client/src/components/credentials/providers.tsx +0 -177
  376. package/server/routers/google.py +0 -277
  377. package/server/routers/maps.py +0 -142
  378. package/server/routers/twitter.py +0 -365
  379. package/server/services/claude_code_service.py +0 -106
  380. package/server/services/memory.py +0 -159
  381. package/server/services/node_option_loaders/__init__.py +0 -77
  382. package/server/services/node_option_loaders/android_loaders.py +0 -55
  383. package/server/services/node_option_loaders/google_loaders.py +0 -97
  384. package/server/services/node_option_loaders/whatsapp_loaders.py +0 -69
  385. package/server/services/twitter_oauth.py +0 -411
  386. package/server/services/websocket_client.py +0 -29
  387. /package/server/{services/android → nodes/android/_relay}/__init__.py +0 -0
  388. /package/server/{services/android → nodes/android/_relay}/broadcaster.py +0 -0
  389. /package/server/{services/android → nodes/android/_relay}/manager.py +0 -0
  390. /package/server/{services/android → nodes/android/_relay}/protocol.py +0 -0
  391. /package/server/{services/browser_service.py → nodes/browser/_service.py} +0 -0
  392. /package/server/{services/whatsapp_service.py → nodes/whatsapp/_service.py} +0 -0
  393. /package/server/skills/{task_agent → assistant}/write-todos-skill/SKILL.md +0 -0
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "react-flow-client",
3
3
  "private": true,
4
- "version": "0.0.76",
4
+ "version": "0.0.78",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "vite --host 0.0.0.0",
8
8
  "build": "vite build",
9
9
  "lint": "eslint .",
10
10
  "preview": "vite preview",
11
+ "typecheck": "tsgo --noEmit",
12
+ "typecheck:tsc": "tsc --noEmit",
11
13
  "test": "vitest run",
12
14
  "test:watch": "vitest",
13
15
  "test:coverage": "vitest run --coverage",
@@ -15,59 +17,60 @@
15
17
  "test:nodepanels": "vitest run src/hooks/__tests__/useDragVariable.test.ts src/hooks/__tests__/useParameterPanel.test.ts src/components/parameterPanel/__tests__ src/components/__tests__/OutputPanel.test.tsx"
16
18
  },
17
19
  "dependencies": {
18
- "@eslint/js": "^9.33.0",
20
+ "@eslint/js": "^9.39.4",
19
21
  "@fontsource-variable/geist": "^5.2.8",
20
22
  "@hookform/resolvers": "^5.2.2",
21
- "@lobehub/icons": "^2.45.0",
23
+ "@lobehub/icons": "^2.48.0",
22
24
  "@lukemorales/query-key-factory": "^1.3.4",
23
25
  "@radix-ui/react-collapsible": "^1.1.12",
24
26
  "@radix-ui/react-dialog": "^1.1.15",
25
27
  "@radix-ui/react-slot": "^1.2.4",
26
28
  "@tailwindcss/typography": "^0.5.19",
27
- "@tanstack/query-sync-storage-persister": "^5.100.2",
28
- "@tanstack/react-query": "^5.100.2",
29
- "@tanstack/react-query-persist-client": "^5.100.2",
30
- "@types/google.maps": "^3.58.1",
31
- "@types/node": "^24.3.1",
32
- "@types/prismjs": "^1.26.5",
33
- "@types/react": "^19.1.10",
34
- "@types/react-dom": "^19.1.7",
29
+ "@tanstack/query-sync-storage-persister": "^5.100.10",
30
+ "@tanstack/react-query": "^5.100.10",
31
+ "@tanstack/react-query-persist-client": "^5.100.10",
32
+ "@types/google.maps": "^3.64.0",
33
+ "@types/node": "^24.12.3",
34
+ "@types/prismjs": "^1.26.6",
35
+ "@types/react": "^19.2.14",
36
+ "@types/react-dom": "^19.2.3",
35
37
  "@uiw/react-json-view": "2.0.0-alpha.41",
36
- "@vitejs/plugin-react": "^5.0.0",
37
- "autoprefixer": "^10.4.21",
38
+ "@vitejs/plugin-react": "^5.2.0",
39
+ "autoprefixer": "^10.5.0",
38
40
  "class-variance-authority": "^0.7.1",
39
41
  "clsx": "^2.1.1",
40
- "cmdk": "^1",
41
- "eslint": "^9.33.0",
42
- "eslint-plugin-react-hooks": "^7.0.1",
43
- "eslint-plugin-react-refresh": "^0.4.20",
44
- "fuzzysort": "^3",
45
- "globals": "^16.3.0",
46
- "idb-keyval": "^6",
47
- "lucide-react": "^1.8.0",
42
+ "cmdk": "^1.1.1",
43
+ "eslint": "^9.39.4",
44
+ "eslint-plugin-react-hooks": "^7.1.1",
45
+ "eslint-plugin-react-refresh": "^0.4.26",
46
+ "fuzzysort": "^3.1.0",
47
+ "globals": "^16.5.0",
48
+ "idb-keyval": "^6.2.2",
49
+ "lucide-react": "^1.14.0",
48
50
  "next-themes": "^0.4.6",
49
- "postcss": "^8.5.6",
51
+ "partysocket": "1.1.18",
52
+ "postcss": "^8.5.14",
50
53
  "prismjs": "^1.30.0",
51
54
  "qrcode.react": "^4.2.0",
52
55
  "radix-ui": "^1.4.3",
53
- "react": "^19.1.1",
54
- "react-dom": "^19.1.1",
55
- "react-hook-form": "^7.72.1",
56
+ "react": "^19.2.6",
57
+ "react-dom": "^19.2.6",
58
+ "react-hook-form": "^7.75.0",
56
59
  "react-markdown": "^10.1.0",
57
60
  "react-simple-code-editor": "^0.14.1",
58
- "react-virtuoso": "^4",
61
+ "react-virtuoso": "^4.18.7",
59
62
  "reactflow": "^11.11.4",
60
63
  "remark-breaks": "^4.0.0",
61
64
  "remark-gfm": "^4.0.1",
62
- "shadcn": "^4.2.0",
65
+ "shadcn": "^4.7.0",
63
66
  "sonner": "^2.0.7",
64
- "tailwind-merge": "^3.5.0",
65
- "tailwindcss": "^4.1.13",
67
+ "tailwind-merge": "^3.6.0",
68
+ "tailwindcss": "^4.3.0",
66
69
  "tw-animate-css": "^1.4.0",
67
- "typescript": "^5.9.2",
68
- "vite": "^7.1.2",
69
- "zod": "^4.3.6",
70
- "zustand": "^5.0.8"
70
+ "typescript": "^5.9.3",
71
+ "vite": "^7.3.3",
72
+ "zod": "^4.4.3",
73
+ "zustand": "^5.0.13"
71
74
  },
72
75
  "overrides": {
73
76
  "@emoji-mart/react": {
@@ -79,17 +82,18 @@
79
82
  }
80
83
  },
81
84
  "devDependencies": {
82
- "@tailwindcss/vite": "^4.2.2",
83
- "@tanstack/react-query-devtools": "^5.100.2",
85
+ "@tailwindcss/vite": "^4.3.0",
86
+ "@tanstack/react-query-devtools": "^5.100.10",
84
87
  "@testing-library/jest-dom": "^6.9.1",
85
88
  "@testing-library/react": "^16.3.2",
86
- "@testing-library/user-event": "^14.5.2",
87
- "@typescript-eslint/parser": "^8.54.0",
88
- "@vitest/coverage-v8": "^2.1.9",
89
+ "@testing-library/user-event": "^14.6.1",
90
+ "@typescript-eslint/parser": "^8.59.2",
91
+ "@typescript/native-preview": "7.0.0-dev.20260504.1",
92
+ "@vitest/coverage-v8": "^3.0.0",
89
93
  "babel-plugin-react-compiler": "19.1.0-rc.3",
90
94
  "jsdom": "^25.0.1",
91
95
  "rollup-plugin-visualizer": "^7.0.1",
92
- "typescript-eslint": "^8.54.0",
93
- "vitest": "^2.1.9"
96
+ "typescript-eslint": "^8.59.2",
97
+ "vitest": "^3.0.0"
94
98
  }
95
99
  }
@@ -1,6 +1,7 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import Dashboard from './Dashboard';
3
3
  import ProtectedRoute from './components/auth/ProtectedRoute';
4
+ import SvgFilterDefs from './components/SvgFilterDefs';
4
5
  import { useTheme } from './contexts/ThemeContext';
5
6
  import { Toaster } from '@/components/ui/sonner';
6
7
 
@@ -18,6 +19,7 @@ const App: React.FC = () => {
18
19
 
19
20
  return (
20
21
  <>
22
+ <SvgFilterDefs />
21
23
  <ProtectedRoute>
22
24
  <div className="flex h-screen w-screen">
23
25
  <Dashboard />
@@ -35,6 +35,9 @@ import CredentialsModal from './components/CredentialsModal';
35
35
  import OnboardingWizard from './components/onboarding/OnboardingWizard';
36
36
  import ErrorBoundary from './components/ui/ErrorBoundary';
37
37
  import ConsolePanel from './components/ui/ConsolePanel';
38
+ import StatusBar from './components/ui/StatusBar';
39
+ import CommandPaletteHost from './components/ui/CommandPaletteHost';
40
+ import { useSoundSync, withSound } from './hooks/useSound';
38
41
  import { useAppTheme } from './hooks/useAppTheme';
39
42
  import { useWorkflowManagement } from './hooks/useWorkflowManagement';
40
43
  import { useWorkflowsQuery, WORKFLOWS_QUERY_KEY } from './hooks/useWorkflowsQuery';
@@ -44,10 +47,10 @@ import { useDragAndDrop } from './hooks/useDragAndDrop';
44
47
  import { useComponentPalette } from './hooks/useComponentPalette';
45
48
  import { useReactFlowNodes } from './hooks/useReactFlowNodes';
46
49
  import { useAutoSkillEdges } from './hooks/useAutoSkillEdges';
50
+ import { useWorkflowOpsListener } from './hooks/useWorkflowOpsListener';
47
51
  import { useCopyPaste } from './hooks/useCopyPaste';
48
52
  import { useWebSocket } from './contexts/WebSocketContext';
49
53
  import { useNodeStatusStore } from './stores/nodeStatusStore';
50
- import { useTheme } from './contexts/ThemeContext';
51
54
  import {
52
55
  sanitizeNodesForComparison,
53
56
  sanitizeEdgesForComparison,
@@ -95,7 +98,7 @@ const createNodeTypes = (): Record<string, React.ComponentType<any>> => {
95
98
  types[spec.type] = COMPONENT_BY_KIND[kind];
96
99
  } else if (spec.type === 'teamMonitor') {
97
100
  types[spec.type] = TeamMonitorNode;
98
- } else if (spec.type === 'masterSkill') {
101
+ } else if ((spec.uiHints as any)?.isMasterSkillEditor === true) {
99
102
  types[spec.type] = ToolkitNode;
100
103
  } else {
101
104
  types[spec.type] = SquareNode;
@@ -120,35 +123,36 @@ const initialEdges: Edge[] = [];
120
123
  // Inner component that uses useReactFlow() - must be inside ReactFlowProvider
121
124
  const DashboardContent: React.FC = () => {
122
125
  const theme = useAppTheme();
123
- const { isDarkMode } = useTheme();
124
- const {
125
- currentWorkflow,
126
- hasUnsavedChanges,
127
- sidebarVisible,
128
- componentPaletteVisible,
129
- updateWorkflow,
130
- loadWorkflow,
131
- createNewWorkflow,
132
- saveWorkflow,
133
- deleteWorkflow,
134
- migrateCurrentWorkflow,
135
- toggleSidebar,
136
- toggleComponentPalette,
137
- proMode,
138
- toggleProMode,
139
- exportWorkflowToJSON,
140
- exportWorkflowToFile,
141
- setCurrentWorkflow,
142
- selectedNode,
143
- setSelectedNode,
144
- renamingNodeId,
145
- setRenamingNodeId,
146
- // Per-workflow UI state (n8n pattern)
147
- setWorkflowExecuting,
148
- setWorkflowExecutionOrder,
149
- setWorkflowViewport,
150
- clearWorkflowExecutionState,
151
- } = useAppStore();
126
+ // Slice selectors so a sidebar/palette toggle (or any other store
127
+ // mutation) does NOT re-render every node, edge, and toolbar in the
128
+ // Dashboard subtree. Action setters are stable refs from Zustand —
129
+ // single-field selectors are the cheapest way to read them.
130
+ const currentWorkflow = useAppStore((s) => s.currentWorkflow);
131
+ const hasUnsavedChanges = useAppStore((s) => s.hasUnsavedChanges);
132
+ const sidebarVisible = useAppStore((s) => s.sidebarVisible);
133
+ const componentPaletteVisible = useAppStore((s) => s.componentPaletteVisible);
134
+ const updateWorkflow = useAppStore((s) => s.updateWorkflow);
135
+ const loadWorkflow = useAppStore((s) => s.loadWorkflow);
136
+ const createNewWorkflow = useAppStore((s) => s.createNewWorkflow);
137
+ const saveWorkflow = useAppStore((s) => s.saveWorkflow);
138
+ const deleteWorkflow = useAppStore((s) => s.deleteWorkflow);
139
+ const migrateCurrentWorkflow = useAppStore((s) => s.migrateCurrentWorkflow);
140
+ const toggleSidebar = useAppStore((s) => s.toggleSidebar);
141
+ const toggleComponentPalette = useAppStore((s) => s.toggleComponentPalette);
142
+ const proMode = useAppStore((s) => s.proMode);
143
+ const toggleProMode = useAppStore((s) => s.toggleProMode);
144
+ const exportWorkflowToJSON = useAppStore((s) => s.exportWorkflowToJSON);
145
+ const exportWorkflowToFile = useAppStore((s) => s.exportWorkflowToFile);
146
+ const setCurrentWorkflow = useAppStore((s) => s.setCurrentWorkflow);
147
+ const selectedNode = useAppStore((s) => s.selectedNode);
148
+ const setSelectedNode = useAppStore((s) => s.setSelectedNode);
149
+ const renamingNodeId = useAppStore((s) => s.renamingNodeId);
150
+ const setRenamingNodeId = useAppStore((s) => s.setRenamingNodeId);
151
+ // Per-workflow UI state (n8n pattern)
152
+ const setWorkflowExecuting = useAppStore((s) => s.setWorkflowExecuting);
153
+ const setWorkflowExecutionOrder = useAppStore((s) => s.setWorkflowExecutionOrder);
154
+ const setWorkflowViewport = useAppStore((s) => s.setWorkflowViewport);
155
+ const clearWorkflowExecutionState = useAppStore((s) => s.clearWorkflowExecutionState);
152
156
 
153
157
  // Single source-to-store sync: push currentWorkflow.id into the
154
158
  // node-status Zustand store from the canonical app store. Previously
@@ -220,6 +224,9 @@ const DashboardContent: React.FC = () => {
220
224
  setNodes,
221
225
  setEdges,
222
226
  });
227
+ // Apply runtime canvas mutations pushed from the backend (e.g.,
228
+ // Agent Builder tools called by the LLM mid-execution).
229
+ useWorkflowOpsListener({ nodes, edges, setNodes, setEdges });
223
230
  const { copySelectedNodes, pasteNodes } = useCopyPaste({ nodes, edges, setNodes, setEdges, saveNodeParameters });
224
231
 
225
232
  // Override all agent nodes to use the global model. Agent membership is
@@ -273,11 +280,53 @@ const DashboardContent: React.FC = () => {
273
280
  const [settingsOpen, setSettingsOpen] = React.useState(false);
274
281
  const [credentialsOpen, setCredentialsOpen] = React.useState(false);
275
282
  const [onboardingReopenTrigger, setOnboardingReopenTrigger] = React.useState(0);
283
+ const [commandPaletteOpen, setCommandPaletteOpen] = React.useState(false);
276
284
 
277
285
  // Console panel visibility from store (database-backed)
278
286
  const consolePanelVisible = useAppStore((state) => state.consolePanelVisible);
279
287
  const toggleConsolePanelVisible = useAppStore((state) => state.toggleConsolePanelVisible);
280
288
 
289
+ // Sound effects: mirror the soundEnabled slice into the WebAudio
290
+ // engine and re-read --sound-pack from :root on every theme change.
291
+ // Mounting once here keeps every event handler that calls useSound()
292
+ // in lockstep with the active theme + user preference.
293
+ useSoundSync();
294
+
295
+ // Wave 33: pause CSS animations while the tab is in the background.
296
+ //
297
+ // Without this, browsers continue advancing CSS animation timing on
298
+ // hidden tabs (RAF is throttled to ~1Hz but `animation` keyframes
299
+ // accumulate paused frames in the compositor's queue). When the user
300
+ // returns, all 50+ executing nodes' three-layer box-shadow `node-pulse`
301
+ // animations resume simultaneously and the GPU compositor stalls for
302
+ // 100-200ms blending the paused frames + Cyber theme's full-viewport
303
+ // `cyber-flicker` / `cyber-roll` decorations. During the stall, input
304
+ // events queue but don't dispatch — first click on tab return appears
305
+ // unresponsive until the composite pass finishes (then the second
306
+ // click works, hence the "wakes up on interaction" pattern).
307
+ //
308
+ // Setting `animation-play-state: paused` on every element via a CSS
309
+ // rule keyed off `<html data-page-hidden>` flushes the queue. The
310
+ // requestAnimationFrame on resume defers the unpause until after the
311
+ // first input is ready to dispatch (one frame's delay, imperceptible).
312
+ useEffect(() => {
313
+ const handleVisibility = () => {
314
+ const root = document.documentElement;
315
+ if (document.hidden) {
316
+ root.setAttribute('data-page-hidden', '');
317
+ } else {
318
+ // Defer unpause to the next frame so the browser has a chance
319
+ // to clear the input queue before animations resume their
320
+ // composite work.
321
+ requestAnimationFrame(() => {
322
+ root.removeAttribute('data-page-hidden');
323
+ });
324
+ }
325
+ };
326
+ document.addEventListener('visibilitychange', handleVisibility);
327
+ return () => document.removeEventListener('visibilitychange', handleVisibility);
328
+ }, []);
329
+
281
330
  // Context menu state for node right-click
282
331
  const [contextMenu, setContextMenu] = React.useState<{
283
332
  nodeId: string;
@@ -500,11 +549,17 @@ const DashboardContent: React.FC = () => {
500
549
  strokeWidth: 2
501
550
  }), [theme.dracula.cyan]);
502
551
 
552
+ // `.react-flow` is intentionally transparent so the parent
553
+ // `.canvas-host` / `.canvas` background-image (per-theme
554
+ // `--canvas-grid` + multi-layer gradient stack from
555
+ // client/src/themes/<theme>.css) paints through. Painting a
556
+ // backgroundColor here would hide every theme decoration —
557
+ // Cyber perspective grid, Renaissance fleur-de-lis, Surveillance
558
+ // CCTV reticle, Steampunk brass bolts, etc.
503
559
  const reactFlowStyle = React.useMemo(() => ({
504
560
  width: '100%',
505
561
  height: '100%',
506
- backgroundColor: theme.colors.background,
507
- }), [theme.colors.background]);
562
+ }), []);
508
563
 
509
564
  const snapGrid: [number, number] = React.useMemo(() => [20, 20], []);
510
565
 
@@ -632,8 +687,8 @@ const DashboardContent: React.FC = () => {
632
687
  if (!currentWorkflow) return;
633
688
 
634
689
  // Check if there's at least one trigger node (workflow entry points)
635
- // Trigger types: start, cronScheduler, webhookTrigger, whatsappReceive, telegramReceive, twitterReceive, gmailReceive, workflowTrigger, chatTrigger, taskTrigger
636
- const triggerTypes = ['start', 'cronScheduler', 'webhookTrigger', 'whatsappReceive', 'telegramReceive', 'twitterReceive', 'gmailReceive', 'emailReceive', 'workflowTrigger', 'chatTrigger', 'taskTrigger'];
690
+ // Trigger types: start, cronScheduler, webhookTrigger, whatsappReceive, telegramReceive, twitterReceive, googleGmailReceive, workflowTrigger, chatTrigger, taskTrigger
691
+ const triggerTypes = ['start', 'cronScheduler', 'webhookTrigger', 'whatsappReceive', 'telegramReceive', 'twitterReceive', 'googleGmailReceive', 'emailReceive', 'workflowTrigger', 'chatTrigger', 'taskTrigger'];
637
692
  const hasTriggerNode = nodes.some(node => triggerTypes.includes(node.type || ''));
638
693
  if (!hasTriggerNode) {
639
694
  alert('No trigger node found in workflow.\n\nAdd a trigger node (Cron Scheduler, WhatsApp Receive, Webhook, Chat Trigger, etc.) to begin deployment.');
@@ -1057,7 +1112,8 @@ const DashboardContent: React.FC = () => {
1057
1112
  switch (event.key.toLowerCase()) {
1058
1113
  case 's':
1059
1114
  event.preventDefault();
1060
- handleSave();
1115
+ // Match the toolbar Save button — fire the per-theme save sound.
1116
+ withSound('save', handleSave)();
1061
1117
  break;
1062
1118
  case 'c':
1063
1119
  event.preventDefault();
@@ -1089,8 +1145,14 @@ const DashboardContent: React.FC = () => {
1089
1145
 
1090
1146
  return (
1091
1147
  <>
1092
- <style>{buildCanvasStyles(theme.colors, isDarkMode)}</style>
1093
- <div style={{
1148
+ <style>{buildCanvasStyles(theme.colors)}</style>
1149
+ {/* `app-frame` is the decorative-layer hook from the design handoff —
1150
+ per-theme CSS files target this class for outer ornaments
1151
+ (gilded corners under Renaissance, scanline overlay + corner
1152
+ brackets under Cyber, riveted ridged frame under Steampunk,
1153
+ REC dot under Surveillance, etc.). Decorations declare
1154
+ pointer-events: none so they don't intercept clicks. */}
1155
+ <div className="app-frame" style={{
1094
1156
  width: '100%',
1095
1157
  height: '100vh',
1096
1158
  display: 'flex',
@@ -1102,12 +1164,16 @@ const DashboardContent: React.FC = () => {
1102
1164
  <TopToolbar
1103
1165
  workflowName={currentWorkflow?.name || 'Untitled Workflow'}
1104
1166
  onWorkflowNameChange={handleWorkflowNameChange}
1105
- onSave={handleSave}
1167
+ // `withSound('save'|'run', ...)` fires the per-theme audio
1168
+ // cue BEFORE the async dispatch so feedback is instant
1169
+ // regardless of save/deploy latency. No-op when sound is
1170
+ // disabled or the active pack is `none`.
1171
+ onSave={withSound('save', handleSave)}
1106
1172
  onNew={handleNew}
1107
1173
  onOpen={handleOpen}
1108
- onRun={handleRun}
1174
+ onRun={withSound('run', handleRun)}
1109
1175
  isRunning={isExecuting}
1110
- onDeploy={handleDeploy}
1176
+ onDeploy={withSound('run', handleDeploy)}
1111
1177
  onCancelDeployment={handleCancelDeployment}
1112
1178
  isDeploying={isCurrentWorkflowActive}
1113
1179
  hasUnsavedChanges={hasUnsavedChanges}
@@ -1158,10 +1224,27 @@ const DashboardContent: React.FC = () => {
1158
1224
  display: 'flex',
1159
1225
  position: 'relative',
1160
1226
  }}>
1161
- <div style={{
1162
- flex: 1,
1163
- backgroundColor: theme.colors.backgroundAlt,
1164
- }}>
1227
+ {/* `canvas-host` + `canvas` activate per-theme canvas
1228
+ decorations (cyber grid backplane, atomic starburst, rot
1229
+ candlelight pools, surveillance crosshair brackets,
1230
+ renaissance fleur-de-lis + marginalia, greek temple key
1231
+ pattern). The `canvas` co-class is the handoff selector
1232
+ used by every per-theme CSS file. Decorative pseudo-
1233
+ elements declare pointer-events: none. */}
1234
+ <div
1235
+ className="canvas-host canvas"
1236
+ style={{
1237
+ flex: 1,
1238
+ // `backgroundColor` intentionally omitted — the per-theme
1239
+ // CSS in client/src/themes/<theme>.css owns the canvas
1240
+ // surface paint via the `:root[data-theme="..."] .canvas`
1241
+ // multi-layer `background` declaration (radial-gradient
1242
+ // vignette + grid pattern + noise texture + var(--bg-canvas)).
1243
+ // base.css `.canvas-host { background-image: var(--canvas-grid); }`
1244
+ // provides the fallback grid layer.
1245
+ position: 'relative',
1246
+ }}
1247
+ >
1165
1248
  <ErrorBoundary>
1166
1249
  <ReactFlow
1167
1250
  nodes={styledNodes}
@@ -1236,6 +1319,35 @@ const DashboardContent: React.FC = () => {
1236
1319
  nodes={nodes}
1237
1320
  />
1238
1321
 
1322
+ {/* Status bar — fixed-bottom system console line; surfaces
1323
+ connection state, workflow context, theme, clock. Always
1324
+ present below ConsolePanel. */}
1325
+ <StatusBar workflowName={currentWorkflow?.name} nodeCount={nodes.length} />
1326
+
1327
+ {/* Global command palette — ⌘K (Ctrl+K). Surface common shell
1328
+ actions; the registered list is local to this component
1329
+ because every handler is already in scope here. */}
1330
+ <CommandPaletteHost
1331
+ open={commandPaletteOpen}
1332
+ onOpenChange={setCommandPaletteOpen}
1333
+ handlers={{
1334
+ save: withSound('save', handleSave),
1335
+ newWorkflow: handleNew,
1336
+ open: handleOpen,
1337
+ run: withSound('run', handleDeploy),
1338
+ stop: handleCancelDeployment,
1339
+ isDeploying: isCurrentWorkflowActive,
1340
+ exportFile: handleExportFile,
1341
+ importJSON: handleImportJSON,
1342
+ openSettings: () => setSettingsOpen(true),
1343
+ openCredentials: () => setCredentialsOpen(true),
1344
+ toggleSidebar,
1345
+ toggleComponentPalette,
1346
+ toggleConsolePanel: toggleConsolePanelVisible,
1347
+ }}
1348
+ />
1349
+
1350
+
1239
1351
  {/* Parameter Panels */}
1240
1352
  <ErrorBoundary>
1241
1353
  <ParameterPanel />
@@ -5,12 +5,10 @@ import { useParameterPanel } from './hooks/useParameterPanel';
5
5
  import { useAppStore } from './store/useAppStore';
6
6
  import { useWebSocket } from './contexts/WebSocketContext';
7
7
  import { ExecutionService, ExecutionResult } from './services/executionService';
8
- import { useAppTheme } from './hooks/useAppTheme';
9
8
  import { ActionButton } from './components/ui/action-button';
10
9
  import { NodeIcon } from './assets/icons';
11
10
 
12
11
  const ParameterPanel: React.FC = () => {
13
- const theme = useAppTheme();
14
12
  const {
15
13
  selectedNode,
16
14
  nodeDefinition,
@@ -22,7 +20,7 @@ const ParameterPanel: React.FC = () => {
22
20
  isLoading,
23
21
  } = useParameterPanel();
24
22
 
25
- const { currentWorkflow } = useAppStore();
23
+ const currentWorkflow = useAppStore((s) => s.currentWorkflow);
26
24
  const { executeNode, getNodeParameters, clearNodeStatus, cancelEventWait, getNodeStatus } = useWebSocket();
27
25
 
28
26
  // Get current node status to check if waiting
@@ -136,13 +134,13 @@ const ParameterPanel: React.FC = () => {
136
134
  // Header actions with node name and buttons in middle area
137
135
  const headerActions = (
138
136
  <div className="flex items-center gap-4">
139
- <div className="flex items-center gap-2 text-[15px] font-semibold text-foreground">
137
+ <div className="flex items-center gap-2 font-display text-[15px] font-semibold tracking-[var(--type-tracking-display)] text-fg-default [text-transform:var(--type-uppercase)]">
140
138
  <NodeIcon
141
139
  icon={nodeDefinition.icon}
142
140
  className="h-5 w-5 text-xl"
143
141
  />
144
142
  <span>{nodeDefinition.displayName}</span>
145
- {hasUnsavedChanges && <span style={{ color: theme.accent.orange }}>*</span>}
143
+ {hasUnsavedChanges && <span className="text-warning">*</span>}
146
144
  </div>
147
145
  <div className="flex items-center gap-2">
148
146
  {canExecute && !hideRunButton && (
@@ -51,6 +51,7 @@ export interface NodeSpec {
51
51
  componentKind?: 'square' | 'circle' | 'trigger' | 'start' | 'agent' | 'chat' | 'tool' | 'model' | 'generic';
52
52
  handles?: NodeSpecHandle[];
53
53
  hideOutputHandle?: boolean;
54
+ hideInputHandle?: boolean;
54
55
  visibility?: 'all' | 'normal' | 'dev';
55
56
  }
56
57
 
@@ -27,6 +27,8 @@ import * as React from 'react';
27
27
 
28
28
  import { cn } from '@/lib/utils';
29
29
  import { resolveIcon, resolveLibraryIcon, isImageIcon } from '.';
30
+ import { useTheme } from '../../contexts/ThemeContext';
31
+ import { THEMED_GLYPHS, ICON_KEYS, type IconKey } from './themedGlyphs';
30
32
 
31
33
  export interface NodeIconProps {
32
34
  /** Backend-declared icon string. May be undefined while the spec
@@ -44,7 +46,37 @@ export const NodeIcon: React.FC<NodeIconProps> = ({
44
46
  className,
45
47
  fallback = null,
46
48
  }) => {
49
+ const { theme } = useTheme();
47
50
  let inner: React.ReactNode;
51
+
52
+ // 1. Per-theme glyph override. Activates only when the icon prop is one
53
+ // of the conceptual `IconKey`s (`agent`, `trigger`, `tool`, …) AND
54
+ // the active theme declares an entry for it. Anything else (URLs,
55
+ // `asset:foo`, `lobehub:Brand`, `lucide:Bot`, emoji) skips this
56
+ // branch and falls through to the existing dispatch chain below.
57
+ // The SVG strings come from `themedGlyphs.ts` — author-trusted
58
+ // markup committed to the repo, never user input — so injecting
59
+ // via `dangerouslySetInnerHTML` is safe here. Do not extend this
60
+ // branch with values built from runtime input.
61
+ if (icon && ICON_KEYS.has(icon as IconKey)) {
62
+ const themedSvg = THEMED_GLYPHS[theme]?.[icon as IconKey];
63
+ if (themedSvg) {
64
+ // SAFE: `themedSvg` is an author-trusted constant from
65
+ // `themedGlyphs.ts` — committed-to-repo markup, never user input.
66
+ // The repo's ESLint config does not enable `react/no-danger`, so
67
+ // no eslint-disable is needed; this comment documents the trust
68
+ // boundary so future reviewers don't second-guess it.
69
+ return (
70
+ <span
71
+ className={cn('inline-flex items-center justify-center', className)}
72
+ dangerouslySetInnerHTML={{ __html: themedSvg }}
73
+ />
74
+ );
75
+ }
76
+ // No entry for this theme/key — fall through to the default chain so
77
+ // the consumer's existing icon (lucide / asset / emoji) still renders.
78
+ }
79
+
48
80
  const LibIcon = resolveLibraryIcon(icon);
49
81
  if (LibIcon) {
50
82
  // LibIcon is a runtime-resolved component reference; using it as a JSX
@@ -44,6 +44,8 @@ import OpenRouter from '@lobehub/icons/es/OpenRouter';
44
44
  import DeepSeek from '@lobehub/icons/es/DeepSeek';
45
45
  import Kimi from '@lobehub/icons/es/Kimi';
46
46
  import Mistral from '@lobehub/icons/es/Mistral';
47
+ import Ollama from '@lobehub/icons/es/Ollama';
48
+ import LmStudio from '@lobehub/icons/es/LmStudio';
47
49
 
48
50
  type RawSvg = string;
49
51
 
@@ -135,6 +137,8 @@ const LOBEHUB_BRANDS: Readonly<Record<string, any>> = {
135
137
  deepseek: DeepSeek,
136
138
  kimi: Kimi,
137
139
  mistral: Mistral,
140
+ ollama: Ollama,
141
+ lmstudio: LmStudio,
138
142
  };
139
143
 
140
144
  const ICON_LIBRARIES: Readonly<Record<string, LibraryResolver>> = {
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="6" fill="#635BFF"/><path d="M14.4 13.2c0-.9.7-1.3 1.9-1.3 1.7 0 3.9.5 5.6 1.4V8.1c-1.9-.7-3.7-1-5.6-1-4.6 0-7.6 2.4-7.6 6.4 0 6.2 8.6 5.2 8.6 7.9 0 1.1-.9 1.4-2.2 1.4-1.9 0-4.3-.8-6.2-1.8v5.4c2.1.9 4.3 1.3 6.2 1.3 4.7 0 7.9-2.3 7.9-6.4 0-6.7-8.6-5.5-8.6-8.1z" fill="#fff"/></svg>