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,7 +1,7 @@
1
1
  import React, { memo, useState, useEffect, useCallback, useMemo } from 'react';
2
2
  import { nodePropsEqual } from './nodeMemoEquality';
3
3
  import { Handle, Position, NodeProps, useEdges, useNodes } from 'reactflow';
4
- import { NodeData } from '../types/NodeTypes';
4
+ import { NodeData, NodeStyle } from '../types/NodeTypes';
5
5
  import { useAppStore } from '../store/useAppStore';
6
6
  import { resolveNodeDescription } from '../lib/nodeSpec';
7
7
  import { useAppTheme } from '../hooks/useAppTheme';
@@ -38,7 +38,7 @@ interface TeamStatus {
38
38
 
39
39
  const TeamMonitorNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnectable, selected }) => {
40
40
  const theme = useAppTheme();
41
- const { setSelectedNode } = useAppStore();
41
+ const setSelectedNode = useAppStore((s) => s.setSelectedNode);
42
42
  const { sendRequest } = useWebSocket();
43
43
  const edges = useEdges();
44
44
  const nodes = useNodes();
@@ -123,20 +123,19 @@ const TeamMonitorNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConn
123
123
  };
124
124
 
125
125
  return (
126
+ // Visual styling (background, border, radius) lives in base.css `.node`
127
+ // defaults + per-theme overrides; reads `var(--node-color)` for accent.
126
128
  <div
129
+ className={`node ${selected ? 'selected' : ''}`}
127
130
  onClick={handleClick}
128
131
  style={{
132
+ '--node-color': nodeColor,
129
133
  width: 200,
130
134
  minHeight: 120,
131
- borderRadius: 8,
132
- background: theme.isDarkMode
133
- ? `linear-gradient(135deg, ${nodeColor}15 0%, ${theme.colors.background} 100%)`
134
- : `linear-gradient(145deg, #ffffff 0%, ${nodeColor}08 100%)`,
135
- border: `2px solid ${selected ? theme.colors.focus : nodeColor + '60'}`,
136
135
  fontFamily: 'system-ui, -apple-system, sans-serif',
137
136
  fontSize: 10,
138
137
  overflow: 'hidden',
139
- }}
138
+ } as NodeStyle}
140
139
  >
141
140
  {/* Header */}
142
141
  <div style={{
@@ -231,36 +230,35 @@ const TeamMonitorNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConn
231
230
  )}
232
231
  </div>
233
232
 
234
- {/* Input Handle */}
233
+ {/* Input Handle — visual styling owned by `.node-handle.in`
234
+ in base.css + per-theme overrides. Inline keeps layout only. */}
235
235
  <Handle
236
236
  id="input-team"
237
237
  type="target"
238
238
  position={Position.Left}
239
239
  isConnectable={isConnectable}
240
+ className="node-handle in"
240
241
  style={{
241
242
  left: -6,
242
243
  top: '50%',
243
244
  width: 10,
244
245
  height: 10,
245
- backgroundColor: theme.isDarkMode ? theme.colors.background : '#ffffff',
246
- border: `2px solid ${nodeColor}`,
247
246
  borderRadius: '50%',
248
247
  }}
249
248
  />
250
249
 
251
- {/* Output Handle */}
250
+ {/* Output Handle — visual styling owned by `.node-handle.out`. */}
252
251
  <Handle
253
252
  id="output-main"
254
253
  type="source"
255
254
  position={Position.Right}
256
255
  isConnectable={isConnectable}
256
+ className="node-handle out"
257
257
  style={{
258
258
  right: -6,
259
259
  top: '50%',
260
260
  width: 10,
261
261
  height: 10,
262
- backgroundColor: nodeColor,
263
- border: `2px solid ${theme.isDarkMode ? theme.colors.background : '#ffffff'}`,
264
262
  borderRadius: '50%',
265
263
  }}
266
264
  />
@@ -13,7 +13,7 @@
13
13
  import React, { memo, useCallback } from 'react';
14
14
  import { nodePropsEqual } from './nodeMemoEquality';
15
15
  import { Handle, Position, NodeProps } from 'reactflow';
16
- import { NodeData } from '../types/NodeTypes';
16
+ import { NodeData, NodeStyle } from '../types/NodeTypes';
17
17
  import { useAppStore } from '../store/useAppStore';
18
18
  import { resolveNodeDescription } from '../lib/nodeSpec';
19
19
  import { NodeIcon } from '../assets/icons';
@@ -27,7 +27,9 @@ const TOOLKIT_NODE_TYPES = ['androidTool'];
27
27
 
28
28
  const ToolkitNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnectable, selected }) => {
29
29
  const theme = useAppTheme();
30
- const { setSelectedNode, setRenamingNodeId, updateNodeData } = useAppStore();
30
+ const setSelectedNode = useAppStore((s) => s.setSelectedNode);
31
+ const setRenamingNodeId = useAppStore((s) => s.setRenamingNodeId);
32
+ const updateNodeData = useAppStore((s) => s.updateNodeData);
31
33
 
32
34
  // Get node status from WebSocket context
33
35
  const { getNodeStatus } = useWebSocket();
@@ -67,17 +69,27 @@ const ToolkitNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
67
69
  const iconSpec = useNodeSpec(type);
68
70
  const iconRef = (iconSpec?.icon as string | undefined) ?? (definition?.icon as string | undefined);
69
71
 
70
- // Get status indicator color
71
- const getStatusIndicatorColor = () => {
72
- if (isExecuting) return theme.dracula.cyan;
73
- if (executionStatus === 'success') return theme.dracula.green;
74
- if (executionStatus === 'error') return theme.dracula.red;
75
- return theme.dracula.green; // Toolkit is always ready
76
- };
72
+ // Pip status bucket — CSS owns the visual color via per-status rules.
73
+ // Toolkit's idle state always reads as "success" (it's always ready).
74
+ const pipStatus = (() => {
75
+ if (isExecuting) return 'executing';
76
+ if (executionStatus === 'success') return 'success';
77
+ if (executionStatus === 'error') return 'error';
78
+ return 'success';
79
+ })();
77
80
 
78
81
  return (
82
+ // `sq-node` + `selected` co-classes activate per-theme square-node
83
+ // decorations (Renaissance wax seal, Steampunk rivets, Edo hanko
84
+ // seal, Surveillance REC LED, Cyber neon underglow). Visuals
85
+ // (background, border, radius, shadow, executing pulse) live in
86
+ // base.css `.sq-node-box` defaults + per-theme overrides; reads
87
+ // `var(--node-color)` for the per-definition accent.
79
88
  <div
89
+ className={`sq-node ${selected ? 'selected' : ''}`}
90
+ data-executing={isExecuting ? '' : undefined}
80
91
  style={{
92
+ '--node-color': nodeColor,
81
93
  position: 'relative',
82
94
  display: 'flex',
83
95
  flexDirection: 'column',
@@ -85,95 +97,62 @@ const ToolkitNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
85
97
  fontFamily: 'system-ui, -apple-system, sans-serif',
86
98
  fontSize: '11px',
87
99
  cursor: 'pointer',
88
- }}
100
+ } as NodeStyle}
89
101
  >
90
- {/* Main Node - rectangular for toolkit, square for skills */}
102
+ {/* Main Node - rectangular for toolkit, square for skills.
103
+ Layout only; visuals live in CSS. */}
91
104
  <div
105
+ className="sq-node-box"
92
106
  style={{
93
107
  position: 'relative',
94
108
  width: isToolkitNode ? theme.nodeSize.toolkitWidth : theme.nodeSize.square,
95
109
  height: isToolkitNode ? theme.nodeSize.toolkitHeight : theme.nodeSize.square,
96
- borderRadius: theme.borderRadius.lg,
97
- background: theme.isDarkMode
98
- ? `linear-gradient(135deg, ${nodeColor}25 0%, ${theme.colors.background} 100%)`
99
- : `linear-gradient(145deg, #ffffff 0%, ${nodeColor}08 100%)`,
100
- border: `2px solid ${isExecuting
101
- ? (theme.isDarkMode ? theme.dracula.cyan : '#2563eb')
102
- : selected
103
- ? theme.colors.focus
104
- : theme.isDarkMode ? nodeColor + '80' : `${nodeColor}40`}`,
105
110
  display: 'flex',
106
111
  alignItems: 'center',
107
112
  justifyContent: 'center',
108
113
  color: theme.colors.text,
109
114
  fontSize: theme.nodeSize.squareIcon,
110
115
  fontWeight: '600',
111
- transition: 'all 0.2s ease',
112
- boxShadow: isExecuting
113
- ? theme.isDarkMode
114
- ? `0 4px 12px ${theme.dracula.cyan}66, 0 0 0 3px ${theme.dracula.cyan}4D`
115
- : `0 0 0 3px rgba(37, 99, 235, 0.5), 0 4px 16px rgba(37, 99, 235, 0.35)`
116
- : selected
117
- ? `0 4px 12px ${theme.colors.focusRing}, 0 0 0 1px ${theme.colors.focusRing}`
118
- : theme.isDarkMode
119
- ? `0 2px 8px ${nodeColor}40`
120
- : `0 2px 8px ${nodeColor}20, 0 4px 12px rgba(0,0,0,0.06)`,
121
- animation: isExecuting ? 'pulse 1.5s ease-in-out infinite' : 'none',
122
116
  }}
123
117
  >
124
118
  {/* Service Icon */}
125
119
  <NodeIcon icon={iconRef} className="h-7 w-7 text-3xl" />
126
120
 
127
- {/* Parameters Button */}
121
+ {/* Parameters Button — CSS owns bg/border via .sq-node-gear */}
128
122
  <button
129
123
  onClick={handleParametersClick}
124
+ className="sq-node-gear"
130
125
  style={{
131
126
  position: 'absolute',
132
127
  top: '-8px',
133
128
  right: '-8px',
134
129
  width: theme.nodeSize.paramButton,
135
130
  height: theme.nodeSize.paramButton,
136
- borderRadius: theme.borderRadius.sm,
137
- backgroundColor: theme.isDarkMode ? theme.colors.backgroundAlt : '#ffffff',
138
- border: `1px solid ${theme.isDarkMode ? theme.colors.border : '#d1d5db'}`,
139
131
  cursor: 'pointer',
140
132
  display: 'flex',
141
133
  alignItems: 'center',
142
134
  justifyContent: 'center',
143
135
  fontSize: theme.fontSize.xs,
144
- color: theme.colors.textSecondary,
145
136
  fontWeight: '400',
146
137
  transition: theme.transitions.fast,
147
138
  zIndex: 30,
148
- boxShadow: theme.isDarkMode
149
- ? `0 1px 3px ${theme.colors.shadow}`
150
- : '0 1px 4px rgba(0,0,0,0.1)'
151
139
  }}
152
140
  title="Edit Toolkit Parameters"
153
141
  >
154
142
  ⚙️
155
143
  </button>
156
144
 
157
- {/* Status Indicator */}
145
+ {/* Status Indicator — CSS owns bg/animation via per-status rules. */}
158
146
  <div
147
+ className="sq-node-pip"
148
+ data-status={pipStatus}
159
149
  style={{
160
150
  position: 'absolute',
161
151
  top: '-4px',
162
152
  left: '-4px',
163
153
  width: theme.nodeSize.statusIndicator,
164
154
  height: theme.nodeSize.statusIndicator,
165
- borderRadius: '50%',
166
- backgroundColor: getStatusIndicatorColor(),
167
- border: `2px solid ${theme.isDarkMode ? theme.colors.background : '#ffffff'}`,
168
- boxShadow: isExecuting
169
- ? theme.isDarkMode
170
- ? `0 0 6px ${theme.dracula.cyan}80`
171
- : '0 0 4px rgba(37, 99, 235, 0.5)'
172
- : theme.isDarkMode
173
- ? `0 1px 2px ${theme.colors.shadow}`
174
- : '0 1px 3px rgba(0,0,0,0.15)',
175
155
  zIndex: 30,
176
- animation: isExecuting ? 'pulse 1s ease-in-out infinite' : 'none',
177
156
  }}
178
157
  title={isExecuting ? 'Executing...' : 'Toolkit ready'}
179
158
  />
@@ -184,6 +163,7 @@ const ToolkitNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
184
163
  type="source"
185
164
  position={Position.Top}
186
165
  isConnectable={isConnectable}
166
+ className="sq-node-handle out"
187
167
  style={{
188
168
  position: 'absolute',
189
169
  top: '-6px',
@@ -191,10 +171,7 @@ const ToolkitNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
191
171
  transform: 'translateX(-50%)',
192
172
  width: theme.nodeSize.handle,
193
173
  height: theme.nodeSize.handle,
194
- backgroundColor: nodeColor,
195
- border: `2px solid ${theme.isDarkMode ? theme.colors.background : '#ffffff'}`,
196
- borderRadius: '50%',
197
- zIndex: 20
174
+ zIndex: 20,
198
175
  }}
199
176
  title={isToolkitNode ? "Connect to AI Agent's tool input" : "Connect to agent's skill input"}
200
177
  />
@@ -206,6 +183,7 @@ const ToolkitNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
206
183
  type="target"
207
184
  position={Position.Bottom}
208
185
  isConnectable={isConnectable}
186
+ className="sq-node-handle in"
209
187
  style={{
210
188
  position: 'absolute',
211
189
  bottom: '-6px',
@@ -213,16 +191,13 @@ const ToolkitNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
213
191
  transform: 'translateX(-50%)',
214
192
  width: theme.nodeSize.handle,
215
193
  height: theme.nodeSize.handle,
216
- backgroundColor: theme.isDarkMode ? theme.colors.background : '#ffffff',
217
- border: `2px solid ${theme.isDarkMode ? theme.colors.textSecondary : '#6b7280'}`,
218
- borderRadius: '50%',
219
- zIndex: 20
194
+ zIndex: 20,
220
195
  }}
221
196
  title="Connect Android service nodes"
222
197
  />
223
198
  )}
224
199
 
225
- {/* Output Data Indicator */}
200
+ {/* Output Data Indicator (bespoke; keeps inline style) */}
226
201
  {executionStatus === 'success' && nodeStatus?.data && (
227
202
  <div
228
203
  style={{
@@ -9,7 +9,7 @@
9
9
  import React, { memo, useState, useEffect, useCallback } from 'react';
10
10
  import { nodePropsEqual } from './nodeMemoEquality';
11
11
  import { Handle, Position, NodeProps } from 'reactflow';
12
- import { NodeData } from '../types/NodeTypes';
12
+ import { NodeData, NodeStyle } from '../types/NodeTypes';
13
13
  import { useAppStore } from '../store/useAppStore';
14
14
  import { resolveNodeDescription, useNodeSpec } from '../lib/nodeSpec';
15
15
  import { NodeIcon } from '../assets/icons';
@@ -19,7 +19,9 @@ import EditableNodeLabel from './ui/EditableNodeLabel';
19
19
 
20
20
  const TriggerNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnectable, selected }) => {
21
21
  const theme = useAppTheme();
22
- const { setSelectedNode, setRenamingNodeId, updateNodeData } = useAppStore();
22
+ const setSelectedNode = useAppStore((s) => s.setSelectedNode);
23
+ const setRenamingNodeId = useAppStore((s) => s.setRenamingNodeId);
24
+ const updateNodeData = useAppStore((s) => s.updateNodeData);
23
25
  const [isConfigured, setIsConfigured] = useState(false);
24
26
  const isDisabled = data?.disabled === true;
25
27
 
@@ -65,29 +67,21 @@ const TriggerNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
65
67
  setSelectedNode({ id, type, data, position: { x: 0, y: 0 } });
66
68
  };
67
69
 
68
- // Get status indicator color based on execution state
69
- const getStatusIndicatorColor = () => {
70
- // Combined executing/waiting state - show purple with glow
71
- if (isExecuting) {
72
- return theme.dracula.purple;
73
- }
74
- if (executionStatus === 'success') {
75
- return theme.dracula.green;
76
- }
77
- if (executionStatus === 'error') {
78
- return theme.dracula.red;
79
- }
80
-
81
- // WhatsApp trigger - use connection status when idle
70
+ // Compute pip status bucket for `data-status` attribute. CSS owns the
71
+ // visual color via per-status rules in base.css and per-theme overrides.
72
+ // For WhatsApp triggers in idle state, fold connection state into the
73
+ // bucket: connected -> success, pairing -> waiting, otherwise -> error.
74
+ const pipStatus = (() => {
75
+ if (executionStatus === 'executing' || executionStatus === 'waiting') return 'executing';
76
+ if (executionStatus === 'success') return 'success';
77
+ if (executionStatus === 'error') return 'error';
82
78
  if (isWhatsAppTrigger) {
83
- if (whatsappStatus.connected) return theme.dracula.green;
84
- if (whatsappStatus.pairing) return theme.dracula.orange;
85
- return theme.dracula.red;
79
+ if (whatsappStatus.connected) return 'success';
80
+ if (whatsappStatus.pairing) return 'waiting';
81
+ return 'error';
86
82
  }
87
-
88
- // Idle state - show configured status
89
- return isConfigured ? theme.dracula.green : theme.dracula.orange;
90
- };
83
+ return isConfigured ? 'success' : 'idle';
84
+ })();
91
85
 
92
86
  const getStatusTitle = () => {
93
87
  switch (executionStatus) {
@@ -120,8 +114,16 @@ const TriggerNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
120
114
  const nodeColor = definition?.defaults?.color || '#f59e0b';
121
115
 
122
116
  return (
117
+ // `sq-node` + `node-trigger` + `selected` co-classes activate per-theme
118
+ // square-node decorations (Renaissance wax seal, Steampunk rivets, Edo
119
+ // hanko seal, Surveillance REC LED, Cyber neon underglow). The
120
+ // `node-trigger` co-class lets per-type theme rules narrow further.
121
+ // `data-executing` binds the CSS pulse animation owned by base.css.
123
122
  <div
123
+ className={`sq-node node-trigger ${selected ? 'selected' : ''}`}
124
+ data-executing={isExecuting ? '' : undefined}
124
125
  style={{
126
+ '--node-color': nodeColor,
125
127
  position: 'relative',
126
128
  display: 'flex',
127
129
  flexDirection: 'column',
@@ -129,44 +131,24 @@ const TriggerNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
129
131
  fontFamily: 'system-ui, -apple-system, sans-serif',
130
132
  fontSize: '11px',
131
133
  cursor: 'pointer',
132
- }}
134
+ } as NodeStyle}
133
135
  >
134
- {/* Main Trigger Node */}
135
- {/* Show glow animation for both executing and waiting states */}
136
+ {/* Main Trigger Node — visual styling lives in base.css + per-theme
137
+ CSS targeting `.sq-node-box`. Inner box keeps only layout
138
+ (size, flex), and per-theme decorations like Cyber neon glow,
139
+ Renaissance wax seal, and Steampunk rivets reach the pixels. */}
136
140
  <div
141
+ className="sq-node-box"
137
142
  style={{
138
143
  position: 'relative',
139
144
  width: theme.nodeSize.square,
140
145
  height: theme.nodeSize.square,
141
- borderRadius: theme.borderRadius.lg,
142
- background: theme.isDarkMode
143
- ? `linear-gradient(135deg, ${nodeColor}25 0%, ${theme.colors.background} 100%)`
144
- : `linear-gradient(145deg, #ffffff 0%, ${nodeColor}08 100%)`,
145
- border: `2px solid ${
146
- isExecuting
147
- ? (theme.isDarkMode ? theme.dracula.purple : '#2563eb')
148
- : selected
149
- ? theme.colors.focus
150
- : theme.isDarkMode ? nodeColor + '80' : `${nodeColor}40`
151
- }`,
152
146
  display: 'flex',
153
147
  alignItems: 'center',
154
148
  justifyContent: 'center',
155
149
  color: theme.colors.text,
156
150
  fontSize: theme.nodeSize.squareIcon,
157
151
  fontWeight: '600',
158
- transition: 'all 0.2s ease',
159
- boxShadow: isExecuting
160
- ? theme.isDarkMode
161
- ? `0 4px 12px ${theme.dracula.purple}66, 0 0 0 3px ${theme.dracula.purple}4D`
162
- : `0 0 0 3px rgba(37, 99, 235, 0.5), 0 4px 16px rgba(37, 99, 235, 0.35)`
163
- : selected
164
- ? `0 4px 12px ${theme.colors.focusRing}, 0 0 0 1px ${theme.colors.focusRing}`
165
- : theme.isDarkMode
166
- ? `0 2px 8px ${nodeColor}40`
167
- : `0 2px 8px ${nodeColor}20, 0 4px 12px rgba(0,0,0,0.06)`,
168
- // Subtle animation for both modes
169
- animation: isExecuting ? 'pulse 1.5s ease-in-out infinite' : 'none',
170
152
  opacity: isDisabled ? 0.5 : 1,
171
153
  }}
172
154
  >
@@ -196,62 +178,48 @@ const TriggerNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
196
178
  {/* Parameters Button */}
197
179
  <button
198
180
  onClick={handleParametersClick}
181
+ className="sq-node-gear"
199
182
  style={{
200
183
  position: 'absolute',
201
184
  top: '-8px',
202
185
  right: '-8px',
203
186
  width: theme.nodeSize.paramButton,
204
187
  height: theme.nodeSize.paramButton,
205
- borderRadius: theme.borderRadius.sm,
206
- backgroundColor: theme.isDarkMode ? theme.colors.backgroundAlt : '#ffffff',
207
- border: `1px solid ${theme.isDarkMode ? theme.colors.border : '#d1d5db'}`,
208
188
  cursor: 'pointer',
209
189
  display: 'flex',
210
190
  alignItems: 'center',
211
191
  justifyContent: 'center',
212
192
  fontSize: theme.fontSize.xs,
213
- color: theme.colors.textSecondary,
214
193
  fontWeight: '400',
215
194
  transition: theme.transitions.fast,
216
195
  zIndex: 30,
217
- boxShadow: theme.isDarkMode
218
- ? `0 1px 3px ${theme.colors.shadow}`
219
- : '0 1px 4px rgba(0,0,0,0.1)'
220
196
  }}
221
197
  title="Configure Trigger"
222
198
  >
223
199
  ⚙️
224
200
  </button>
225
201
 
226
- {/* Execution Status Indicator */}
227
- {/* Status Indicator - glows for both waiting and executing states */}
202
+ {/* Status Indicator — CSS owns the bg color via per-status rule
203
+ on `.sq-node-pip[data-status="…"]`. Pulse on executing/waiting
204
+ also lives in CSS. */}
228
205
  <div
206
+ className="sq-node-pip"
207
+ data-status={pipStatus}
229
208
  style={{
230
209
  position: 'absolute',
231
210
  top: '-4px',
232
211
  left: '-4px',
233
212
  width: theme.nodeSize.statusIndicator,
234
213
  height: theme.nodeSize.statusIndicator,
235
- borderRadius: '50%',
236
- backgroundColor: getStatusIndicatorColor(),
237
- border: `2px solid ${theme.isDarkMode ? theme.colors.background : '#ffffff'}`,
238
- boxShadow: isExecuting
239
- ? theme.isDarkMode
240
- ? `0 0 6px ${theme.dracula.purple}80`
241
- : '0 0 4px rgba(37, 99, 235, 0.5)'
242
- : theme.isDarkMode
243
- ? `0 1px 2px ${theme.colors.shadow}`
244
- : '0 1px 3px rgba(0,0,0,0.15)',
245
214
  zIndex: 30,
246
- // Subtle pulse animation for both modes
247
- animation: isExecuting ? 'pulse 1s ease-in-out infinite' : 'none',
248
215
  }}
249
216
  title={getStatusTitle()}
250
217
  />
251
218
 
252
219
  {/* NO INPUT HANDLE - Trigger nodes don't have inputs */}
253
220
 
254
- {/* Trigger Badge - Lightning bolt indicator on bottom-left */}
221
+ {/* Trigger Badge - Lightning bolt indicator on bottom-left
222
+ (bespoke UI element, not in design schema; keeps inline style) */}
255
223
  <div
256
224
  style={{
257
225
  position: 'absolute',
@@ -276,12 +244,13 @@ const TriggerNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
276
244
  <span style={{ lineHeight: 1, color: theme.isDarkMode ? theme.colors.background : '#1a1d21' }}>⚡</span>
277
245
  </div>
278
246
 
279
- {/* Output Handle (right side) */}
247
+ {/* Output Handle (right side) — CSS owns bg/border via .sq-node-handle.out */}
280
248
  <Handle
281
249
  id="output-main"
282
250
  type="source"
283
251
  position={Position.Right}
284
252
  isConnectable={isConnectable}
253
+ className="sq-node-handle out"
285
254
  style={{
286
255
  position: 'absolute',
287
256
  right: '-6px',
@@ -289,15 +258,12 @@ const TriggerNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnecta
289
258
  transform: 'translateY(-50%)',
290
259
  width: theme.nodeSize.handle,
291
260
  height: theme.nodeSize.handle,
292
- backgroundColor: isConfigured ? nodeColor : theme.colors.textSecondary,
293
- border: `2px solid ${theme.isDarkMode ? theme.colors.background : '#ffffff'}`,
294
- borderRadius: '50%',
295
- zIndex: 20
261
+ zIndex: 20,
296
262
  }}
297
263
  title="Trigger Output"
298
264
  />
299
265
 
300
- {/* Output Data Indicator */}
266
+ {/* Output Data Indicator (bespoke; keeps inline style) */}
301
267
  {executionStatus === 'success' && nodeStatus?.data && (
302
268
  <div
303
269
  style={{
@@ -78,51 +78,55 @@ const wsMock = {
78
78
  // status getters aren't actually used here -- they're consumed via the dedicated hooks below
79
79
  };
80
80
 
81
- vi.mock('../../contexts/WebSocketContext', async () => {
82
- const actual = await vi.importActual<any>('../../contexts/WebSocketContext');
83
- return {
84
- ...actual,
85
- useWebSocket: () => wsMock,
86
- useWhatsAppStatus: () => ({
87
- connected: false,
88
- has_session: false,
89
- running: false,
90
- pairing: false,
91
- device_id: null,
92
- connected_phone: null,
93
- qr: null,
94
- }),
95
- useAndroidStatus: () => ({
96
- connected: false,
97
- paired: false,
98
- device_id: null,
99
- device_name: null,
100
- connected_devices: [],
101
- qr_data: null,
102
- session_token: null,
103
- }),
104
- useTwitterStatus: () => ({
105
- connected: false,
106
- username: null,
107
- user_id: null,
108
- name: null,
109
- profile_image_url: null,
110
- }),
111
- useGoogleStatus: () => ({
112
- connected: false,
113
- email: null,
114
- name: null,
115
- profile_image_url: null,
116
- }),
117
- useTelegramStatus: () => ({
118
- connected: false,
119
- bot_username: null,
120
- bot_name: null,
121
- bot_id: null,
122
- owner_chat_id: null,
123
- }),
124
- };
125
- });
81
+ // Replace the entire WebSocketContext module with stub exports. The
82
+ // `vi.importActual` + spread pattern was previously used here but failed
83
+ // to override `useWebSocket` reliably under React 19 — the real
84
+ // implementation's `useContext(WebSocketContext)` check fired against the
85
+ // undefined provider, throwing the "must be used within a WebSocketProvider"
86
+ // error before the mocked override could intercept. The full-replace style
87
+ // matches what useApiKeys.test.ts does and works in both vitest 1 and 2.
88
+ vi.mock('../../contexts/WebSocketContext', () => ({
89
+ useWebSocket: () => wsMock,
90
+ useWhatsAppStatus: () => ({
91
+ connected: false,
92
+ has_session: false,
93
+ running: false,
94
+ pairing: false,
95
+ device_id: null,
96
+ connected_phone: null,
97
+ qr: null,
98
+ }),
99
+ useAndroidStatus: () => ({
100
+ connected: false,
101
+ paired: false,
102
+ device_id: null,
103
+ device_name: null,
104
+ connected_devices: [],
105
+ qr_data: null,
106
+ session_token: null,
107
+ }),
108
+ useTwitterStatus: () => ({
109
+ connected: false,
110
+ username: null,
111
+ user_id: null,
112
+ name: null,
113
+ profile_image_url: null,
114
+ }),
115
+ useGoogleStatus: () => ({
116
+ connected: false,
117
+ email: null,
118
+ name: null,
119
+ profile_image_url: null,
120
+ }),
121
+ useTelegramStatus: () => ({
122
+ connected: false,
123
+ bot_username: null,
124
+ bot_name: null,
125
+ bot_id: null,
126
+ owner_chat_id: null,
127
+ }),
128
+ useNodeStatus: () => ({ status: 'idle', data: {} }),
129
+ }));
126
130
 
127
131
  vi.mock('../../hooks/useWhatsApp', () => ({
128
132
  useWhatsApp: () => ({