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,174 @@
1
+ """Stripe event source — supervised ``stripe listen`` daemon + the
2
+ companion ``WebhookSource`` that receives forwarded events.
3
+
4
+ Two cooperating sources:
5
+
6
+ * :class:`StripeListenSource` (DaemonEventSource) keeps the CLI alive,
7
+ captures the ``whsec_…`` signing secret from its stderr banner.
8
+ * :class:`StripeWebhookSource` (WebhookSource) is the actual event
9
+ producer — verifies the Stripe-Signature header on each forwarded
10
+ POST and turns the payload into a :class:`WorkflowEvent`.
11
+
12
+ Module-level singletons (``get_listen_source`` / ``get_webhook_source``)
13
+ plug into the framework registries from ``__init__.py``.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import asyncio
19
+ import os
20
+ import re
21
+ import shlex
22
+ from datetime import datetime, timezone
23
+ from pathlib import Path
24
+ from typing import Any, Dict, Optional
25
+
26
+ from fastapi import Request
27
+
28
+ from core.logging import get_logger
29
+ from services.events import (
30
+ DaemonEventSource,
31
+ StripeVerifier,
32
+ WebhookSource,
33
+ WorkflowEvent,
34
+ )
35
+
36
+ from ._credentials import StripeCredential
37
+
38
+ logger = get_logger(__name__)
39
+
40
+ _SECRET_RE = re.compile(r"whsec_[A-Za-z0-9_]+")
41
+ _SECRET_FIELD = "stripe_webhook_secret"
42
+
43
+
44
+ def stripe_config_path() -> Path:
45
+ """Default location for the Stripe CLI's credentials file
46
+ (``~/.config/stripe/config.toml``, ``XDG_CONFIG_HOME``-aware)."""
47
+ base = os.environ.get("XDG_CONFIG_HOME")
48
+ return (Path(base) if base else Path.home() / ".config") / "stripe" / "config.toml"
49
+
50
+
51
+ def is_logged_in() -> bool:
52
+ """Detect Stripe CLI login by sniffing its config file. Cheap
53
+ filesystem check — the CLI writes ``test_mode_api_key`` /
54
+ ``live_mode_api_key`` under a profile section on success."""
55
+ cfg = stripe_config_path()
56
+ if not cfg.exists():
57
+ return False
58
+ try:
59
+ return "_api_key" in cfg.read_text(encoding="utf-8", errors="replace")
60
+ except OSError:
61
+ return False
62
+
63
+
64
+ class StripeListenSource(DaemonEventSource):
65
+ """Supervises ``stripe listen`` and persists the captured webhook
66
+ signing secret. Emits no events itself — Stripe events arrive over
67
+ HTTP via :class:`StripeWebhookSource`."""
68
+
69
+ type = "stripe.listen"
70
+ process_name = "stripe-listen"
71
+ # Empty so DaemonEventSource skips its built-in PATH check; we
72
+ # do install + verification ourselves in start() via
73
+ # ensure_stripe_cli (which falls back to system PATH first, then
74
+ # workspace-local download).
75
+ binary_name = ""
76
+ workflow_namespace = "_stripe"
77
+ install_hint = "https://stripe.com/docs/stripe-cli#install"
78
+ credential = StripeCredential
79
+
80
+ def build_command(self, secrets: Dict) -> str:
81
+ # The CLI uses credentials it stored at ~/.config/stripe/config.toml
82
+ # (populated by `stripe login`). No --api-key flag here.
83
+ # Binary path is resolved by `ensure_stripe_cli` (called from
84
+ # the start() override below) and cached for sync access here.
85
+ # ``shlex.quote`` so Windows backslashes survive ProcessService's
86
+ # ``shlex.split`` round-trip (POSIX-mode parser eats raw ``\``).
87
+ from core.config import Settings
88
+ from ._install import stripe_cli_path
89
+
90
+ port = int(Settings().port)
91
+ binary = shlex.quote(str(stripe_cli_path() or "stripe"))
92
+ return (
93
+ f"{binary} listen --forward-to http://localhost:{port}/webhook/stripe "
94
+ f"--print-secret"
95
+ )
96
+
97
+ async def start(self) -> Dict[str, Any]:
98
+ """Ensure the CLI binary is downloaded before delegating to the
99
+ framework's daemon-start path (which calls ``build_command``)."""
100
+ from ._install import ensure_stripe_cli
101
+ try:
102
+ path = await ensure_stripe_cli()
103
+ logger.info("[Stripe] daemon start: CLI binary resolved at %s", path)
104
+ except Exception as e:
105
+ logger.warning("[Stripe] daemon start failed at install step: %s", e)
106
+ return {"success": False, "error": f"Stripe CLI install failed: {e}"}
107
+ return await super().start()
108
+
109
+ async def has_credential(self) -> bool:
110
+ """The Stripe CLI manages auth state in its own config file —
111
+ that's our 'credential' for the daemon's start gate."""
112
+ return is_logged_in()
113
+
114
+ def parse_line(self, stream: str, line: str) -> Optional[WorkflowEvent]:
115
+ if stream == "stderr" and (m := _SECRET_RE.search(line)):
116
+ secret = m.group(0)
117
+ logger.info("[Stripe] whsec_… signing secret detected in daemon stderr — persisting")
118
+ asyncio.create_task(self._persist_secret(secret))
119
+ return None
120
+
121
+ async def _persist_secret(self, secret: str) -> None:
122
+ try:
123
+ from services.plugin.deps import get_auth_service
124
+ await get_auth_service().store_api_key(_SECRET_FIELD, secret, models=[])
125
+ logger.info(
126
+ "[Stripe] webhook signing secret persisted (key=%s, len=%d)",
127
+ _SECRET_FIELD, len(secret),
128
+ )
129
+ except Exception as e:
130
+ logger.warning("[Stripe] persist secret failed: %s", e)
131
+
132
+
133
+ class StripeWebhookSource(WebhookSource):
134
+ """HTTP receiver for Stripe-forwarded events."""
135
+
136
+ type = "stripe.webhook"
137
+ path = "stripe"
138
+ verifier = StripeVerifier
139
+ secret_field = _SECRET_FIELD
140
+ credential = StripeCredential
141
+
142
+ async def shape(self, request: Request, body: bytes, payload: dict) -> WorkflowEvent:
143
+ created = payload.get("created")
144
+ try:
145
+ time = datetime.fromtimestamp(int(created), tz=timezone.utc) if created else datetime.now(timezone.utc)
146
+ except (TypeError, ValueError):
147
+ time = datetime.now(timezone.utc)
148
+ account = payload.get("account") or "default"
149
+ return WorkflowEvent(
150
+ id=payload.get("id") or "",
151
+ type=f"stripe.{payload.get('type', 'unknown')}",
152
+ source=f"stripe://{account}",
153
+ time=time,
154
+ data=payload.get("data") or {},
155
+ subject=payload.get("type"),
156
+ )
157
+
158
+
159
+ _listen: Optional[StripeListenSource] = None
160
+ _webhook: Optional[StripeWebhookSource] = None
161
+
162
+
163
+ def get_listen_source() -> StripeListenSource:
164
+ global _listen
165
+ if _listen is None:
166
+ _listen = StripeListenSource()
167
+ return _listen
168
+
169
+
170
+ def get_webhook_source() -> StripeWebhookSource:
171
+ global _webhook
172
+ if _webhook is None:
173
+ _webhook = StripeWebhookSource()
174
+ return _webhook
@@ -0,0 +1,81 @@
1
+ """Stripe Action — pass-through over the Stripe CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import shlex
6
+ from typing import Any, Optional
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field
9
+
10
+ from services.events import run_cli_command
11
+ from services.plugin import ActionNode, NodeContext, Operation, TaskQueue
12
+
13
+ from ._credentials import StripeCredential
14
+
15
+
16
+ class StripeActionParams(BaseModel):
17
+ command: str = Field(
18
+ default="",
19
+ description=(
20
+ "Stripe CLI command, exactly as you would type after 'stripe '. "
21
+ "Examples: 'customers create --email a@b.com', 'charges list --limit 10', "
22
+ "'trigger charge.succeeded'. Reference: https://stripe.com/docs/cli"
23
+ ),
24
+ )
25
+
26
+ model_config = ConfigDict(extra="ignore")
27
+
28
+
29
+ class StripeActionOutput(BaseModel):
30
+ command: Optional[str] = None
31
+ success: Optional[bool] = None
32
+ result: Optional[Any] = None
33
+ stdout: Optional[str] = None
34
+ error: Optional[str] = None
35
+
36
+ model_config = ConfigDict(extra="allow")
37
+
38
+
39
+ class StripeActionNode(ActionNode):
40
+ type = "stripeAction"
41
+ display_name = "Stripe"
42
+ subtitle = "CLI Command"
43
+ group = ("payments", "tool")
44
+ description = "Run any Stripe CLI command (customers, charges, payment_intents, refunds, invoices, trigger, …)"
45
+ component_kind = "square"
46
+ handles = (
47
+ {"name": "input-main", "kind": "input", "position": "left",
48
+ "label": "Input", "role": "main"},
49
+ {"name": "output-main", "kind": "output", "position": "right",
50
+ "label": "Output", "role": "main"},
51
+ )
52
+ annotations = {"destructive": False, "readonly": False, "open_world": True}
53
+ credentials = (StripeCredential,)
54
+ task_queue = TaskQueue.REST_API
55
+ usable_as_tool = True
56
+
57
+ Params = StripeActionParams
58
+ Output = StripeActionOutput
59
+
60
+ @Operation("run", cost={"service": "stripe", "action": "run", "count": 1})
61
+ async def run(self, ctx: NodeContext, params: StripeActionParams) -> Any:
62
+ from ._install import ensure_stripe_cli
63
+
64
+ cmd = params.command.strip()
65
+ if not cmd:
66
+ raise RuntimeError("command is required (e.g. 'customers create --email a@b.com')")
67
+ try:
68
+ binary = str(await ensure_stripe_cli())
69
+ except Exception as e:
70
+ raise RuntimeError(f"Stripe CLI install failed: {e}")
71
+ # No credential= — Stripe CLI reads its own creds from
72
+ # ~/.config/stripe/config.toml after `stripe login`.
73
+ result = await run_cli_command(binary=binary, argv=shlex.split(cmd))
74
+ if not result["success"]:
75
+ raise RuntimeError(result.get("error") or "Stripe CLI invocation failed")
76
+ return {
77
+ "command": cmd,
78
+ "success": True,
79
+ "result": result.get("result"),
80
+ "stdout": result.get("stdout"),
81
+ }
@@ -0,0 +1,92 @@
1
+ """Stripe Receive — fires when StripeWebhookSource accepts a verified
2
+ forwarded event."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Callable, Dict, Literal, Optional
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field
9
+
10
+ from services.events import BaseTriggerParams, WebhookTriggerNode, WorkflowEvent
11
+
12
+ from ._credentials import StripeCredential
13
+ from ._source import StripeWebhookSource
14
+
15
+
16
+ _PREFIX = "stripe."
17
+
18
+
19
+ class StripeReceiveParams(BaseTriggerParams):
20
+ livemode_filter: Literal["all", "test", "live"] = Field(
21
+ default="all",
22
+ description="Filter by livemode flag on the event.",
23
+ )
24
+
25
+
26
+ class StripeReceiveOutput(BaseModel):
27
+ event_id: Optional[str] = None
28
+ event_type: Optional[str] = None
29
+ created: Optional[int] = None
30
+ livemode: Optional[bool] = None
31
+ api_version: Optional[str] = None
32
+ request_id: Optional[str] = None
33
+ account: Optional[str] = None
34
+ data: Optional[dict] = None
35
+
36
+ model_config = ConfigDict(extra="allow")
37
+
38
+
39
+ class StripeReceiveNode(WebhookTriggerNode):
40
+ type = "stripeReceive"
41
+ display_name = "Stripe Receive"
42
+ subtitle = "Webhook Event"
43
+ group = ("payments", "trigger")
44
+ description = "Trigger workflow when Stripe webhook event arrives"
45
+ component_kind = "trigger"
46
+ handles = (
47
+ {"name": "output-main", "kind": "output", "position": "right",
48
+ "label": "Output", "role": "main"},
49
+ )
50
+ credentials = (StripeCredential,)
51
+ webhook_source = StripeWebhookSource
52
+ event_type_prefix = _PREFIX
53
+ Params = StripeReceiveParams
54
+ Output = StripeReceiveOutput
55
+
56
+ def _extra_filter(
57
+ self, params: StripeReceiveParams,
58
+ ) -> Optional[Callable[[WorkflowEvent], bool]]:
59
+ if params.livemode_filter == "all":
60
+ return None
61
+ target_live = params.livemode_filter == "live"
62
+
63
+ def matches(ev: WorkflowEvent) -> bool:
64
+ payload = ev.data if isinstance(ev.data, dict) else {}
65
+ return bool(payload.get("livemode")) is target_live
66
+
67
+ return matches
68
+
69
+ async def _check_precondition(self) -> Optional[str]:
70
+ from ._source import get_listen_source
71
+ if not get_listen_source()._started:
72
+ return "Stripe daemon not running. Add Stripe API key in Credentials and connect."
73
+ return None
74
+
75
+ def shape_output(self, event: WorkflowEvent) -> Dict:
76
+ payload = event.data if isinstance(event.data, dict) else {}
77
+ stripe_type = event.type[len(_PREFIX):] if event.type.startswith(_PREFIX) else event.type
78
+ request = payload.get("request")
79
+ request_id = request.get("id") if isinstance(request, dict) else request
80
+ nested = payload.get("data")
81
+ return {
82
+ "event_id": event.id,
83
+ "event_type": stripe_type,
84
+ "created": payload.get("created"),
85
+ "livemode": payload.get("livemode"),
86
+ "api_version": payload.get("api_version"),
87
+ "request_id": request_id,
88
+ "account": payload.get("account") or (
89
+ event.source.split("://", 1)[1] if "://" in event.source else None
90
+ ),
91
+ "data": nested if isinstance(nested, dict) else payload,
92
+ }
@@ -5,7 +5,17 @@ Used by the two telegram plugins in this folder (telegram_send, telegram_receive
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- from services.plugin.credential import ApiKeyCredential
8
+ import httpx
9
+
10
+ from services.plugin.credential import ApiKeyCredential, ProbeResult
11
+
12
+
13
+ # Telegram embeds the bot token in the URL path (``/bot<token>/getMe``)
14
+ # rather than in a header / query / Authorization slot, so the
15
+ # declarative ``probe_url`` shape doesn't fit. We override ``_probe``
16
+ # directly but reuse :meth:`_handle_probe_response` from the base for
17
+ # the 200-with-failure-envelope case.
18
+ _TELEGRAM_API = "https://api.telegram.org"
9
19
 
10
20
 
11
21
  class TelegramCredential(ApiKeyCredential):
@@ -17,3 +27,44 @@ class TelegramCredential(ApiKeyCredential):
17
27
  key_location = "header"
18
28
  extra_fields = ("telegram_owner_chat_id",)
19
29
  docs_url = "https://core.telegram.org/bots"
30
+
31
+ @classmethod
32
+ async def _probe(cls, api_key: str) -> ProbeResult:
33
+ """Validate via ``GET /bot<token>/getMe``.
34
+
35
+ Telegram returns 401 for revoked tokens and 404 for malformed
36
+ tokens; both surface as :class:`httpx.HTTPStatusError` and the
37
+ base :meth:`Credential.validate` translates them via
38
+ :func:`classify_credential_error`. A 200 with ``{ok: false}`` is
39
+ rare but possible (legacy token shapes) and is caught in
40
+ :meth:`_handle_probe_response`.
41
+ """
42
+ url = f"{_TELEGRAM_API}/bot{api_key}/getMe"
43
+ async with httpx.AsyncClient(timeout=cls.probe_timeout_seconds) as client:
44
+ response = await client.get(url)
45
+ response.raise_for_status()
46
+ return cls._handle_probe_response(response)
47
+
48
+ @classmethod
49
+ def _handle_probe_response(cls, response: httpx.Response) -> ProbeResult:
50
+ payload = response.json()
51
+ if not payload.get("ok"):
52
+ return ProbeResult(
53
+ valid=False,
54
+ message=payload.get("description", "Telegram rejected the bot token"),
55
+ )
56
+ bot = payload.get("result") or {}
57
+ username = bot.get("username")
58
+ return ProbeResult(
59
+ valid=True,
60
+ message=(
61
+ f"Telegram bot token is valid (@{username})"
62
+ if username
63
+ else "Telegram bot token is valid"
64
+ ),
65
+ extra={
66
+ "bot_id": bot.get("id"),
67
+ "bot_username": username,
68
+ "bot_name": bot.get("first_name"),
69
+ },
70
+ )
@@ -19,6 +19,8 @@ from typing import Any, Awaitable, Callable, Dict
19
19
 
20
20
  from fastapi import WebSocket
21
21
 
22
+ from services.plugin.ws import ws_response
23
+
22
24
  from ._credentials import TelegramCredential
23
25
  from ._service import get_telegram_service
24
26
 
@@ -112,8 +114,15 @@ async def handle_telegram_status(data: Dict[str, Any], websocket: WebSocket) ->
112
114
  return {"success": True, "status": status}
113
115
 
114
116
 
117
+ @ws_response
115
118
  async def handle_telegram_send(data: Dict[str, Any], websocket: WebSocket) -> Dict[str, Any]:
116
- """Direct send via WebSocket (not via workflow node)."""
119
+ """Direct send via WebSocket (not via workflow node).
120
+
121
+ ``@ws_response`` collapses the catch-all ``try / except Exception``
122
+ block at the bottom of the function -- exceptions become
123
+ ``{success: False, error: str(e)}`` automatically. Early-return
124
+ validation stays since those are deterministic input checks.
125
+ """
117
126
  service = get_telegram_service()
118
127
  if not service.connected:
119
128
  return {"success": False, "error": "Telegram bot not connected"}
@@ -125,15 +134,11 @@ async def handle_telegram_send(data: Dict[str, Any], websocket: WebSocket) -> Di
125
134
  if dispatch is None:
126
135
  return {"success": False, "error": f"Unsupported message type: {message_type}"}
127
136
 
128
- try:
129
- coro_or_none, err = dispatch(service, data, data.get("parse_mode"))
130
- if err:
131
- return {"success": False, "error": err}
132
- result = await coro_or_none
133
- return {"success": True, "result": result}
134
- except Exception as e:
135
- logger.error(f"[Telegram] Send error: {e}")
136
- return {"success": False, "error": str(e)}
137
+ coro_or_none, err = dispatch(service, data, data.get("parse_mode"))
138
+ if err:
139
+ return {"success": False, "error": err}
140
+ result = await coro_or_none
141
+ return {"success": True, "result": result}
137
142
 
138
143
 
139
144
  async def handle_telegram_reconnect(data: Dict[str, Any], websocket: WebSocket) -> Dict[str, Any]:
@@ -155,26 +160,22 @@ async def handle_telegram_reconnect(data: Dict[str, Any], websocket: WebSocket)
155
160
  return await get_telegram_service().connect(secrets["api_key"])
156
161
 
157
162
 
163
+ @ws_response
158
164
  async def handle_telegram_get_me(data: Dict[str, Any], websocket: WebSocket) -> Dict[str, Any]:
159
165
  service = get_telegram_service()
160
166
  if not service.connected:
161
167
  return {"success": False, "error": "Telegram bot not connected"}
162
- try:
163
- return {"success": True, "result": await service.get_me()}
164
- except Exception as e:
165
- return {"success": False, "error": str(e)}
168
+ return {"success": True, "result": await service.get_me()}
166
169
 
167
170
 
171
+ @ws_response
168
172
  async def handle_telegram_get_chat(data: Dict[str, Any], websocket: WebSocket) -> Dict[str, Any]:
169
173
  service = get_telegram_service()
170
174
  if not service.connected:
171
175
  return {"success": False, "error": "Telegram bot not connected"}
172
176
  if not data.get("chat_id"):
173
177
  return {"success": False, "error": "chat_id required"}
174
- try:
175
- return {"success": True, "result": await service.get_chat(data["chat_id"])}
176
- except Exception as e:
177
- return {"success": False, "error": str(e)}
178
+ return {"success": True, "result": await service.get_chat(data["chat_id"])}
178
179
 
179
180
 
180
181
  # ---------------------------------------------------------------------------