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
@@ -0,0 +1,145 @@
1
+ """Idempotent plugin registries.
2
+
3
+ Single generic base for all the ``register_*`` plumbing that plugin
4
+ ``__init__.py`` files call into. Replaces five hand-rolled
5
+ implementations with the same shape.
6
+
7
+ Two flavours:
8
+
9
+ - :class:`IdempotentRegistry` -- key->value mapping with collision
10
+ detection. Used for WS handlers, FastAPI routers, filter builders,
11
+ trigger prechecks, output schemas. Re-registering the same value for
12
+ a key is a no-op (re-import safe); a different value raises
13
+ ``ValueError`` so plugin namespace clashes fail at import time.
14
+
15
+ - :class:`IdempotentList` -- fanout list with identity dedup. Used for
16
+ per-cycle callbacks like ``register_service_refresh`` where every
17
+ registered callable runs once per cycle. Re-registering the same
18
+ callable is a no-op; different callables coexist (fanout semantics).
19
+
20
+ Each module that exposes a ``register_*`` public API constructs one of
21
+ these and provides a thin wrapper. Module-level dicts that other code
22
+ reads directly (e.g. ``FILTER_BUILDERS``, ``NODE_OUTPUT_SCHEMAS``) can
23
+ be passed in as the backing store via the ``items`` kwarg, so existing
24
+ readers keep working.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ from types import MappingProxyType
30
+ from typing import (
31
+ Callable,
32
+ Dict,
33
+ Generic,
34
+ Iterator,
35
+ List,
36
+ Mapping,
37
+ Optional,
38
+ TypeVar,
39
+ )
40
+
41
+ K = TypeVar("K")
42
+ V = TypeVar("V")
43
+
44
+
45
+ def _qual(value: object) -> str:
46
+ """Best-effort qualified name for callable / class -- used in error messages."""
47
+ module = getattr(value, "__module__", None)
48
+ qualname = getattr(value, "__qualname__", None)
49
+ if module and qualname:
50
+ return f"{module}.{qualname}"
51
+ return repr(value)
52
+
53
+
54
+ class IdempotentRegistry(Generic[K, V]):
55
+ """Key->value registry with idempotent register + collision raise.
56
+
57
+ Args:
58
+ name: Human-readable label used in error messages
59
+ (``f"{name}: '{key}' already registered..."``).
60
+ items: Optional pre-existing dict to use as the backing store.
61
+ Lets a module expose its registry-backed dict as a
62
+ module-level constant for readers that grew up reading the
63
+ dict directly.
64
+ on_register: Optional callback fired after a successful
65
+ register. Used e.g. by ``register_output_schema`` to bust a
66
+ JSON-schema cache.
67
+ """
68
+
69
+ def __init__(
70
+ self,
71
+ name: str,
72
+ *,
73
+ items: Optional[Dict[K, V]] = None,
74
+ on_register: Optional[Callable[[K, V], None]] = None,
75
+ ) -> None:
76
+ self._name = name
77
+ self._items: Dict[K, V] = items if items is not None else {}
78
+ self._on_register = on_register
79
+
80
+ def register(self, key: K, value: V) -> None:
81
+ """Add ``key -> value``. Idempotent on identity; raises on conflict."""
82
+ existing = self._items.get(key)
83
+ if existing is not None and existing is not value:
84
+ raise ValueError(
85
+ f"{self._name}: {key!r} is already registered by "
86
+ f"{_qual(existing)}; refusing to overwrite with {_qual(value)}"
87
+ )
88
+ self._items[key] = value
89
+ if self._on_register is not None:
90
+ self._on_register(key, value)
91
+
92
+ def get(self, key: K) -> Optional[V]:
93
+ return self._items.get(key)
94
+
95
+ def items(self) -> Mapping[K, V]:
96
+ """Read-only view. Use ``dict(reg.items())`` for a mutable copy."""
97
+ return MappingProxyType(self._items)
98
+
99
+ def keys(self) -> List[K]:
100
+ return list(self._items.keys())
101
+
102
+ def values(self) -> List[V]:
103
+ return list(self._items.values())
104
+
105
+ def __contains__(self, key: object) -> bool:
106
+ return key in self._items
107
+
108
+ def __len__(self) -> int:
109
+ return len(self._items)
110
+
111
+ def __iter__(self) -> Iterator[K]:
112
+ return iter(self._items)
113
+
114
+
115
+ class IdempotentList(Generic[V]):
116
+ """Fanout list with identity dedup.
117
+
118
+ Args:
119
+ name: Human-readable label (used in repr / future logging).
120
+ items: Optional pre-existing list to use as the backing store.
121
+ """
122
+
123
+ def __init__(
124
+ self,
125
+ name: str,
126
+ *,
127
+ items: Optional[List[V]] = None,
128
+ ) -> None:
129
+ self._name = name
130
+ self._items: List[V] = items if items is not None else []
131
+
132
+ def register(self, value: V) -> None:
133
+ """Append if not already present (identity dedup)."""
134
+ if value in self._items:
135
+ return
136
+ self._items.append(value)
137
+
138
+ def __iter__(self) -> Iterator[V]:
139
+ return iter(self._items)
140
+
141
+ def __len__(self) -> int:
142
+ return len(self._items)
143
+
144
+ def __contains__(self, value: object) -> bool:
145
+ return value in self._items
@@ -0,0 +1,65 @@
1
+ """Service-singleton mixin for plugin-owned long-lived services.
2
+
3
+ Replaces the per-plugin ``_instance`` + ``get_instance()`` boilerplate
4
+ that each ``nodes/<plugin>/_service.py`` currently re-implements.
5
+ Pre-T inventory (Wave 11.I plan):
6
+
7
+ - ``nodes/telegram/_service.py:TelegramService`` -- ``_instance`` + sync
8
+ ``get_instance`` + async ``reset_instance`` (custom — disconnects).
9
+ - ``nodes/email/_service.py:EmailService`` -- ``_instance`` + sync
10
+ ``get_instance``, no reset.
11
+ - ``nodes/browser/_service.py`` -- module-level ``_instance`` global,
12
+ no class-level state (different shape, kept bespoke).
13
+ - ``nodes/whatsapp/_service.py`` -- supervisor-aware singleton via
14
+ ``BaseProcessSupervisor``, kept bespoke (different lifecycle).
15
+
16
+ Subclasses get :meth:`instance` for free. They override
17
+ :meth:`reset_instance` only if there's a side effect on reset
18
+ (Telegram disconnects the bot poll loop; that stays per-plugin).
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import ClassVar, Optional, TypeVar
24
+
25
+ T = TypeVar("T", bound="ServiceSingleton")
26
+
27
+
28
+ class ServiceSingleton:
29
+ """Mixin: per-class lazy singleton.
30
+
31
+ Each subclass that opts in gets its own ``_instance`` slot lazily
32
+ populated on first :meth:`instance` call. The Python attribute
33
+ rules guarantee per-class isolation (read climbs MRO, write goes
34
+ to the immediate class), so ``A.instance()`` and ``B.instance()``
35
+ return distinct singletons even though both inherit the same
36
+ declaration here.
37
+
38
+ Usage::
39
+
40
+ class TelegramService(ServiceSingleton):
41
+ ...
42
+
43
+ # module-level helper consumed by handler files:
44
+ def get_telegram_service() -> TelegramService:
45
+ return TelegramService.instance()
46
+
47
+ Subclasses may also override :meth:`reset_instance` to add side
48
+ effects (e.g. tear down a bot polling loop) before clearing.
49
+ """
50
+
51
+ _instance: ClassVar[Optional["ServiceSingleton"]] = None
52
+
53
+ @classmethod
54
+ def instance(cls: type[T]) -> T:
55
+ """Return the per-class singleton, constructing it on first call."""
56
+ if cls.__dict__.get("_instance") is None:
57
+ cls._instance = cls()
58
+ return cls._instance # type: ignore[return-value]
59
+
60
+ @classmethod
61
+ def reset_instance(cls) -> None:
62
+ """Drop the cached singleton. Override for async / cleanup
63
+ flows; the default is a sync no-side-effect clear."""
64
+ if cls.__dict__.get("_instance") is not None:
65
+ cls._instance = None
@@ -0,0 +1,81 @@
1
+ """WebSocket handler helpers (Wave 11.I, milestone T-residual).
2
+
3
+ Single helper today: :func:`ws_response`, an opt-in decorator that
4
+ collapses the duplicated ``try / except / return {success: False,
5
+ error: str(e)}`` block at the bottom of every plugin WS handler.
6
+
7
+ Audited 79 instances of this exact pattern across ``nodes/<plugin>/``
8
+ in the pre-T-residual codebase. The decorator is **opt-in** because
9
+ not every handler returns the ``{success: bool}`` envelope -- OAuth
10
+ lifecycle handlers built by
11
+ :mod:`services.events.oauth_lifecycle` return ``{connected: bool}``,
12
+ auto-wrapping would clobber that. Plugin authors decorate per-handler.
13
+
14
+ Honors the :class:`services.plugin.base.NodeUserError` contract: when
15
+ a handler raises ``NodeUserError`` (user-correctable failure -- bad
16
+ input, unknown enum value, missing required field), the wrapper logs
17
+ at WARN without a traceback. Genuinely unexpected exceptions log at
18
+ ERROR with full traceback via ``logger.exception``.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from functools import wraps
24
+ from typing import Any, Awaitable, Callable, Dict
25
+
26
+ from fastapi import WebSocket
27
+
28
+ from core.logging import get_logger
29
+ from services.plugin.base import NodeUserError
30
+
31
+ logger = get_logger(__name__)
32
+
33
+ WSHandlerFn = Callable[[Dict[str, Any], WebSocket], Awaitable[Dict[str, Any]]]
34
+
35
+
36
+ def ws_response(handler: WSHandlerFn) -> WSHandlerFn:
37
+ """Wrap a WS handler to convert exceptions into a ``{success: False,
38
+ error: ...}`` envelope.
39
+
40
+ Successful return values pass through untouched -- the wrapper
41
+ only intervenes on exceptions. Extra fields the handler adds to
42
+ the success envelope (``connected``, ``message``, ``result``, ...)
43
+ are preserved.
44
+
45
+ Two log levels:
46
+
47
+ * :class:`NodeUserError` -> WARN, no traceback. Reason: these are
48
+ expected and user-correctable; a stack trace just clutters the
49
+ operator log without adding signal.
50
+ * Anything else -> ERROR via ``logger.exception`` (full traceback).
51
+ Reason: it's a server bug, the trace is the diagnostic.
52
+
53
+ Usage::
54
+
55
+ from services.plugin.ws import ws_response
56
+
57
+ @ws_response
58
+ async def handle_thing(data, websocket):
59
+ ...
60
+ return {"success": True, "result": ...}
61
+ """
62
+
63
+ handler_name = getattr(handler, "__name__", repr(handler))
64
+
65
+ @wraps(handler)
66
+ async def wrapper(
67
+ data: Dict[str, Any], websocket: WebSocket,
68
+ ) -> Dict[str, Any]:
69
+ try:
70
+ return await handler(data, websocket)
71
+ except NodeUserError as exc:
72
+ logger.warning(f"[{handler_name}] {type(exc).__name__}: {exc}")
73
+ return {"success": False, "error": str(exc)}
74
+ except Exception as exc: # noqa: BLE001 -- surface as envelope
75
+ logger.exception(f"[{handler_name}] unexpected error")
76
+ return {"success": False, "error": str(exc)}
77
+
78
+ return wrapper
79
+
80
+
81
+ __all__ = ["ws_response"]
@@ -16,7 +16,7 @@ import shutil
16
16
  from dataclasses import dataclass, field
17
17
  from datetime import datetime
18
18
  from pathlib import Path
19
- from typing import Any, Dict, List, Optional
19
+ from typing import Any, Awaitable, Callable, Dict, List, Optional
20
20
 
21
21
  from core.logging import get_logger
22
22
  from services._supervisor.util import kill_tree
@@ -26,6 +26,10 @@ logger = get_logger(__name__)
26
26
  MAX_PROCESSES = 10 # Default limit, configurable via Settings panel
27
27
 
28
28
 
29
+ # (stream_name, line) -> awaitable. Invoked once per decoded stdout/stderr line.
30
+ LineHandler = Callable[[str, str], Awaitable[None]]
31
+
32
+
29
33
  @dataclass
30
34
  class ManagedProcess:
31
35
  name: str
@@ -43,6 +47,11 @@ class ManagedProcess:
43
47
  exit_code: Optional[int] = None
44
48
  stdout_lines: int = 0
45
49
  stderr_lines: int = 0
50
+ # Optional per-line callback: framework-level subscribers (e.g. the
51
+ # generalised event source `DaemonEventSource`) install this to ingest
52
+ # the daemon's stdout/stderr without re-tailing the log files we already
53
+ # write for the Terminal tab.
54
+ line_handler: Optional[LineHandler] = None
46
55
 
47
56
 
48
57
  class ProcessService:
@@ -70,8 +79,17 @@ class ProcessService:
70
79
  command: str,
71
80
  workflow_id: str = "default",
72
81
  working_directory: str = "",
82
+ *,
83
+ line_handler: Optional[LineHandler] = None,
73
84
  ) -> Dict[str, Any]:
74
- """Start a long-running process."""
85
+ """Start a long-running process.
86
+
87
+ ``line_handler``: optional ``async (stream_name, line) -> None``
88
+ callback invoked for every decoded stdout/stderr line, AFTER the
89
+ line has been written to the log file and broadcast to the
90
+ Terminal tab. Used by ``DaemonEventSource`` to parse subprocess
91
+ output into typed events without re-tailing the log files.
92
+ """
75
93
  if not command:
76
94
  return {"success": False, "error": "command is required"}
77
95
 
@@ -170,6 +188,7 @@ class ProcessService:
170
188
  working_directory=cwd,
171
189
  process=proc,
172
190
  log_dir=log_dir,
191
+ line_handler=line_handler,
173
192
  )
174
193
 
175
194
  managed.stdout_task = asyncio.create_task(
@@ -392,6 +411,16 @@ class ProcessService:
392
411
  "message": text,
393
412
  "source": source,
394
413
  })
414
+
415
+ # Optional framework-level subscriber.
416
+ if managed.line_handler is not None:
417
+ try:
418
+ await managed.line_handler(stream_name, text)
419
+ except Exception as cb_err:
420
+ logger.debug(
421
+ "[Process] line_handler %s/%s raised: %s",
422
+ managed.name, stream_name, cb_err,
423
+ )
395
424
  except asyncio.CancelledError:
396
425
  pass
397
426
  except Exception as e: