machinaos 0.0.78 → 0.0.80

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 (743) hide show
  1. package/.env.template +74 -5
  2. package/{workflows/AI Assistant_workflow-1778504793388-ou1m1tz2x.json → .machina/workflows/AI Assistant_example_workflow-1779017037684-e2e5da7a.json } +164 -105
  3. package/{workflows/AI Employee_example_workflow-1777720598005-u4cm858dv.json → .machina/workflows/AI Employee_example_workflow-1779102911870-cbc76c82.json } +582 -328
  4. package/{workflows/Claude Assistant_workflow-1778380124051-mdibn807c.json → .machina/workflows/Claude Assistant_example_workflow-1779095939967-2369cff4.json } +152 -83
  5. package/README.md +5 -2
  6. package/bin/cli.js +2 -2
  7. package/{machina → cli}/__main__.py +11 -7
  8. package/cli/_common.py +122 -0
  9. package/cli/buildenv.py +40 -0
  10. package/cli/cli.py +204 -0
  11. package/{machina → cli}/colors.py +10 -2
  12. package/cli/commands/__init__.py +1 -0
  13. package/cli/commands/_temporal_specs.py +59 -0
  14. package/{machina → cli}/commands/build.py +35 -45
  15. package/cli/commands/clean.py +141 -0
  16. package/cli/commands/daemon/__init__.py +47 -0
  17. package/cli/commands/daemon/_state.py +97 -0
  18. package/cli/commands/daemon/restart.py +14 -0
  19. package/cli/commands/daemon/start.py +49 -0
  20. package/cli/commands/daemon/status.py +20 -0
  21. package/cli/commands/daemon/stop.py +22 -0
  22. package/{machina → cli}/commands/dev.py +32 -42
  23. package/{machina → cli}/commands/docs.py +13 -11
  24. package/{machina → cli}/commands/start.py +69 -62
  25. package/{machina → cli}/commands/stop.py +7 -10
  26. package/{machina → cli}/commands/version.py +12 -6
  27. package/cli/config.py +170 -0
  28. package/cli/platform_.py +169 -0
  29. package/{machina → cli}/ports.py +42 -3
  30. package/{machina → cli}/run.py +29 -2
  31. package/{machina → cli}/supervisor.py +29 -12
  32. package/{machina → cli}/tcp.py +6 -2
  33. package/{machina → cli}/tree.py +38 -11
  34. package/client/dist/assets/{ActionBar-Du2MSFSz.js → ActionBar-Cjr3TF7g.js} +1 -1
  35. package/client/dist/assets/{ApiKeyInput-k2LBmBjb.js → ApiKeyInput-DIJE2PVA.js} +1 -1
  36. package/client/dist/assets/{ApiKeyPanel-C_bV9U0X.js → ApiKeyPanel-CPmye7uh.js} +1 -1
  37. package/client/dist/assets/{ApiUsageSection-CmVfwZzL.js → ApiUsageSection-TF_7gH2D.js} +1 -1
  38. package/client/dist/assets/{EmailPanel-CeKIMGu-.js → EmailPanel-Bs-xvbKR.js} +1 -1
  39. package/client/dist/assets/{OAuthPanel-KA3t3Q2K.js → OAuthPanel-BDtVJhAV.js} +1 -1
  40. package/client/dist/assets/{QrPairingPanel-NgNpJNuk.js → QrPairingPanel-BwJehTuZ.js} +1 -1
  41. package/client/dist/assets/{RateLimitSection-Du5YNVIA.js → RateLimitSection-CfNOoPIS.js} +1 -1
  42. package/client/dist/assets/{StatusCard-DNLyayXc.js → StatusCard-DkwIrgdP.js} +1 -1
  43. package/client/dist/assets/index-P2FzntoL.js +165 -0
  44. package/client/dist/index.html +1 -1
  45. package/client/package.json +1 -1
  46. package/client/src/Dashboard.tsx +128 -76
  47. package/client/src/adapters/nodeSpecToDescription.ts +7 -0
  48. package/client/src/assets/icons/index.test.ts +10 -0
  49. package/client/src/assets/icons/index.ts +16 -3
  50. package/client/src/components/AIAgentNode.tsx +8 -8
  51. package/client/src/components/ParameterRenderer.tsx +6 -3
  52. package/client/src/components/SkillEditorModal.tsx +1 -0
  53. package/client/src/components/credentials/panels/EmailPanel.tsx +2 -0
  54. package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +2 -0
  55. package/client/src/components/credentials/sections/RateLimitSection.tsx +1 -0
  56. package/client/src/components/icons/AIProviderIcons.tsx +1 -0
  57. package/client/src/components/maps/GoogleMapsPicker.tsx +1 -0
  58. package/client/src/components/parameterPanel/InputSection.tsx +1 -0
  59. package/client/src/components/parameterPanel/MasterSkillEditor.tsx +1 -0
  60. package/client/src/components/parameterPanel/OutputSection.tsx +1 -0
  61. package/client/src/components/ui/ComponentPalette.tsx +1 -0
  62. package/client/src/components/ui/MapSelector.tsx +1 -0
  63. package/client/src/components/ui/NodeContextMenu.tsx +3 -3
  64. package/client/src/components/ui/SettingsPanel.tsx +1 -0
  65. package/client/src/components/ui/action-button.tsx +1 -0
  66. package/client/src/components/ui/badge.tsx +1 -0
  67. package/client/src/components/ui/button.tsx +1 -0
  68. package/client/src/components/ui/form.tsx +1 -0
  69. package/client/src/components/ui/tabs.tsx +1 -0
  70. package/client/src/contexts/AuthContext.tsx +1 -0
  71. package/client/src/contexts/ThemeContext.tsx +1 -0
  72. package/client/src/contexts/WebSocketContext.tsx +104 -34
  73. package/client/src/hooks/__tests__/useApiKeys.test.ts +2 -2
  74. package/client/src/hooks/useReactFlowNodes.ts +1 -0
  75. package/client/src/hooks/useWorkflowValidation.ts +142 -0
  76. package/client/src/lib/nodeSpec.ts +1 -0
  77. package/client/src/test/providers.tsx +1 -0
  78. package/client/src/types/__tests__/cloudEvents.test.ts +5 -2
  79. package/client/src/types/cloudEvents.ts +19 -7
  80. package/client/src/utils/nodeUtils.ts +1 -1
  81. package/client/src/utils/workflow.ts +8 -2
  82. package/client/src/utils/workflowExport.ts +60 -3
  83. package/package.json +24 -23
  84. package/scripts/install.js +16 -27
  85. package/scripts/migrate_icons.py +3 -1
  86. package/scripts/migrate_skill_icons.py +6 -7
  87. package/scripts/postinstall.js +11 -9
  88. package/server/config/ai_cli_providers.json +2 -3
  89. package/server/config/credential_providers.json +15 -15
  90. package/server/config/llm_defaults.json +1 -1
  91. package/server/config/model_registry.json +416 -611
  92. package/server/constants.py +285 -223
  93. package/server/core/__init__.py +1 -1
  94. package/server/core/cache.py +9 -29
  95. package/server/core/cleanup.py +12 -24
  96. package/server/core/config.py +148 -24
  97. package/server/core/container.py +68 -59
  98. package/server/core/credential_backends.py +5 -13
  99. package/server/core/credentials_database.py +13 -43
  100. package/server/core/database.py +292 -353
  101. package/server/core/health.py +4 -5
  102. package/server/core/logging.py +241 -87
  103. package/server/core/paths.py +285 -0
  104. package/server/core/tracing.py +2 -8
  105. package/server/gunicorn.conf.py +1 -0
  106. package/server/main.py +150 -74
  107. package/server/middleware/auth.py +18 -24
  108. package/server/models/__init__.py +1 -1
  109. package/server/models/auth.py +5 -12
  110. package/server/models/database.py +36 -68
  111. package/server/models/node_metadata.py +25 -18
  112. package/server/nodejs/dist/index.js +107 -0
  113. package/server/nodes/README.md +11 -5
  114. package/server/nodes/__init__.py +1 -1
  115. package/server/nodes/_visuals.py +146 -14
  116. package/server/nodes/agent/_events.py +124 -0
  117. package/server/nodes/agent/_handles.py +15 -29
  118. package/server/nodes/agent/_inline.py +28 -25
  119. package/server/nodes/agent/_specialized.py +30 -15
  120. package/server/nodes/agent/{ai_agent.py → ai_agent/__init__.py} +33 -17
  121. package/server/nodes/agent/ai_agent/meta.json +3 -0
  122. package/server/nodes/agent/{ai_employee.py → ai_employee/__init__.py} +5 -2
  123. package/server/nodes/agent/ai_employee/meta.json +3 -0
  124. package/server/nodes/agent/{android_agent.py → android_agent/__init__.py} +1 -1
  125. package/server/nodes/agent/android_agent/meta.json +3 -0
  126. package/server/nodes/agent/{autonomous_agent.py → autonomous_agent/__init__.py} +2 -1
  127. package/server/nodes/agent/autonomous_agent/meta.json +3 -0
  128. package/server/nodes/agent/{chat_agent.py → chat_agent/__init__.py} +29 -12
  129. package/server/nodes/agent/chat_agent/meta.json +3 -0
  130. package/server/nodes/agent/{claude_code_agent.py → claude_code_agent/__init__.py} +192 -95
  131. package/server/nodes/agent/claude_code_agent/_handlers.py +169 -0
  132. package/server/{services/claude_oauth.py → nodes/agent/claude_code_agent/_oauth.py} +26 -13
  133. package/server/nodes/agent/claude_code_agent/_pool.py +1020 -0
  134. package/server/nodes/agent/claude_code_agent/_provider.py +513 -0
  135. package/server/nodes/agent/claude_code_agent/_skills.py +245 -0
  136. package/server/nodes/agent/claude_code_agent/meta.json +3 -0
  137. package/server/nodes/agent/{codex_agent.py → codex_agent/__init__.py} +26 -35
  138. package/server/nodes/agent/codex_agent/meta.json +3 -0
  139. package/server/nodes/agent/{coding_agent.py → coding_agent/__init__.py} +1 -1
  140. package/server/nodes/agent/coding_agent/meta.json +3 -0
  141. package/server/nodes/agent/{consumer_agent.py → consumer_agent/__init__.py} +1 -1
  142. package/server/nodes/agent/consumer_agent/meta.json +3 -0
  143. package/server/nodes/agent/{orchestrator_agent.py → orchestrator_agent/__init__.py} +5 -2
  144. package/server/nodes/agent/orchestrator_agent/meta.json +3 -0
  145. package/server/nodes/agent/{payments_agent.py → payments_agent/__init__.py} +1 -1
  146. package/server/nodes/agent/payments_agent/meta.json +3 -0
  147. package/server/nodes/agent/{productivity_agent.py → productivity_agent/__init__.py} +1 -1
  148. package/server/nodes/agent/productivity_agent/meta.json +3 -0
  149. package/server/nodes/agent/{rlm_agent.py → rlm_agent/__init__.py} +18 -17
  150. package/server/nodes/agent/rlm_agent/meta.json +3 -0
  151. package/server/nodes/agent/{social_agent.py → social_agent/__init__.py} +1 -1
  152. package/server/nodes/agent/social_agent/meta.json +3 -0
  153. package/server/nodes/agent/{task_agent.py → task_agent/__init__.py} +1 -1
  154. package/server/nodes/agent/task_agent/meta.json +3 -0
  155. package/server/nodes/agent/{tool_agent.py → tool_agent/__init__.py} +1 -1
  156. package/server/nodes/agent/tool_agent/meta.json +3 -0
  157. package/server/nodes/agent/{travel_agent.py → travel_agent/__init__.py} +1 -1
  158. package/server/nodes/agent/travel_agent/meta.json +3 -0
  159. package/server/nodes/agent/{web_agent.py → web_agent/__init__.py} +1 -1
  160. package/server/nodes/agent/web_agent/meta.json +3 -0
  161. package/server/nodes/android/__init__.py +24 -0
  162. package/server/nodes/android/_base.py +93 -76
  163. package/server/nodes/android/_dispatcher.py +140 -223
  164. package/server/nodes/android/_events.py +154 -0
  165. package/server/nodes/android/_handlers.py +13 -7
  166. package/server/nodes/android/_option_loaders.py +1 -4
  167. package/server/nodes/android/_refresh.py +27 -37
  168. package/server/nodes/android/_relay/broadcaster.py +25 -41
  169. package/server/nodes/android/_relay/client.py +23 -42
  170. package/server/nodes/android/_relay/manager.py +1 -0
  171. package/server/nodes/android/_relay/protocol.py +6 -0
  172. package/server/nodes/android/_router.py +48 -133
  173. package/server/nodes/android/{airplane_mode_control.py → airplane_mode_control/__init__.py} +2 -1
  174. package/server/nodes/android/airplane_mode_control/meta.json +3 -0
  175. package/server/nodes/android/{app_launcher.py → app_launcher/__init__.py} +2 -1
  176. package/server/nodes/android/app_launcher/meta.json +3 -0
  177. package/server/nodes/android/{app_list.py → app_list/__init__.py} +2 -1
  178. package/server/nodes/android/app_list/meta.json +3 -0
  179. package/server/nodes/android/{audio_automation.py → audio_automation/__init__.py} +2 -1
  180. package/server/nodes/android/audio_automation/meta.json +3 -0
  181. package/server/nodes/android/{battery_monitor.py → battery_monitor/__init__.py} +2 -1
  182. package/server/nodes/android/battery_monitor/meta.json +3 -0
  183. package/server/nodes/android/{bluetooth_automation.py → bluetooth_automation/__init__.py} +2 -1
  184. package/server/nodes/android/bluetooth_automation/meta.json +3 -0
  185. package/server/nodes/android/{camera_control.py → camera_control/__init__.py} +2 -1
  186. package/server/nodes/android/camera_control/meta.json +3 -0
  187. package/server/nodes/android/{device_state_automation.py → device_state_automation/__init__.py} +2 -1
  188. package/server/nodes/android/device_state_automation/meta.json +3 -0
  189. package/server/nodes/android/{environmental_sensors.py → environmental_sensors/__init__.py} +2 -1
  190. package/server/nodes/android/environmental_sensors/meta.json +3 -0
  191. package/server/nodes/android/{location.py → location/__init__.py} +2 -1
  192. package/server/nodes/android/location/meta.json +3 -0
  193. package/server/nodes/android/{media_control.py → media_control/__init__.py} +2 -1
  194. package/server/nodes/android/media_control/meta.json +3 -0
  195. package/server/nodes/android/{motion_detection.py → motion_detection/__init__.py} +2 -1
  196. package/server/nodes/android/motion_detection/meta.json +3 -0
  197. package/server/nodes/android/{network_monitor.py → network_monitor/__init__.py} +2 -1
  198. package/server/nodes/android/network_monitor/meta.json +3 -0
  199. package/server/nodes/android/{screen_control_automation.py → screen_control_automation/__init__.py} +2 -1
  200. package/server/nodes/android/screen_control_automation/meta.json +3 -0
  201. package/server/nodes/android/{system_info.py → system_info/__init__.py} +2 -1
  202. package/server/nodes/android/system_info/meta.json +3 -0
  203. package/server/nodes/android/{wifi_automation.py → wifi_automation/__init__.py} +2 -1
  204. package/server/nodes/android/wifi_automation/meta.json +3 -0
  205. package/server/nodes/browser/__init__.py +22 -1
  206. package/server/nodes/browser/_install.py +63 -0
  207. package/server/nodes/browser/_service.py +21 -25
  208. package/server/nodes/browser/{browser.py → browser/__init__.py} +58 -25
  209. package/server/nodes/browser/browser/meta.json +3 -0
  210. package/server/nodes/chat/{chat_history.py → chat_history/__init__.py} +2 -4
  211. package/server/nodes/chat/chat_history/meta.json +3 -0
  212. package/server/nodes/chat/{chat_send.py → chat_send/__init__.py} +2 -4
  213. package/server/nodes/chat/chat_send/icon.svg +1 -0
  214. package/server/nodes/chat/chat_send/meta.json +3 -0
  215. package/server/nodes/code/_base.py +1 -1
  216. package/server/nodes/code/{javascript_executor.py → javascript_executor/__init__.py} +5 -5
  217. package/server/nodes/code/javascript_executor/meta.json +3 -0
  218. package/server/nodes/code/{python_executor.py → python_executor/__init__.py} +32 -14
  219. package/server/nodes/code/python_executor/meta.json +3 -0
  220. package/server/nodes/code/{typescript_executor.py → typescript_executor/__init__.py} +5 -5
  221. package/server/nodes/code/typescript_executor/meta.json +3 -0
  222. package/server/nodes/document/{document_parser.py → document_parser/__init__.py} +26 -15
  223. package/server/nodes/document/document_parser/meta.json +3 -0
  224. package/server/nodes/document/{embedding_generator.py → embedding_generator/__init__.py} +16 -9
  225. package/server/nodes/document/embedding_generator/meta.json +3 -0
  226. package/server/nodes/document/{file_downloader.py → file_downloader/__init__.py} +30 -20
  227. package/server/nodes/document/file_downloader/meta.json +3 -0
  228. package/server/nodes/document/{http_scraper.py → http_scraper/__init__.py} +31 -21
  229. package/server/nodes/document/http_scraper/meta.json +3 -0
  230. package/server/nodes/document/{text_chunker.py → text_chunker/__init__.py} +17 -12
  231. package/server/nodes/document/text_chunker/meta.json +3 -0
  232. package/server/nodes/document/{vector_store.py → vector_store/__init__.py} +88 -72
  233. package/server/nodes/document/vector_store/meta.json +3 -0
  234. package/server/nodes/email/__init__.py +9 -2
  235. package/server/nodes/email/_events.py +54 -0
  236. package/server/nodes/email/_filters.py +3 -3
  237. package/server/nodes/email/_himalaya.py +95 -50
  238. package/server/nodes/email/_service.py +23 -13
  239. package/server/nodes/email/{email_read.py → email_read/__init__.py} +23 -11
  240. package/server/nodes/email/email_read/icon.svg +6 -0
  241. package/server/nodes/email/email_read/meta.json +3 -0
  242. package/server/nodes/email/{email_receive.py → email_receive/__init__.py} +45 -23
  243. package/server/nodes/email/email_receive/meta.json +3 -0
  244. package/server/nodes/email/{email_send.py → email_send/__init__.py} +13 -7
  245. package/server/nodes/email/email_send/meta.json +3 -0
  246. package/server/nodes/filesystem/_backend.py +1 -5
  247. package/server/nodes/filesystem/{file_modify.py → file_modify/__init__.py} +10 -5
  248. package/server/nodes/filesystem/file_modify/meta.json +3 -0
  249. package/server/nodes/filesystem/{file_read.py → file_read/__init__.py} +7 -3
  250. package/server/nodes/filesystem/file_read/meta.json +3 -0
  251. package/server/nodes/filesystem/{fs_search.py → fs_search/__init__.py} +11 -3
  252. package/server/nodes/filesystem/fs_search/meta.json +3 -0
  253. package/server/nodes/filesystem/{shell.py → shell/__init__.py} +12 -5
  254. package/server/nodes/filesystem/shell/meta.json +3 -0
  255. package/server/nodes/google/__init__.py +12 -0
  256. package/server/nodes/google/_auth_helper.py +7 -13
  257. package/server/nodes/google/_base.py +14 -11
  258. package/server/nodes/google/_credentials.py +2 -1
  259. package/server/nodes/google/_events.py +47 -0
  260. package/server/nodes/google/_filters.py +3 -3
  261. package/server/nodes/google/_gmail.py +70 -47
  262. package/server/nodes/google/_handlers.py +3 -1
  263. package/server/nodes/google/_oauth.py +25 -11
  264. package/server/nodes/google/_option_loaders.py +9 -30
  265. package/server/nodes/google/_refresh.py +8 -12
  266. package/server/nodes/google/_router.py +4 -5
  267. package/server/nodes/google/{calendar.py → calendar/__init__.py} +87 -64
  268. package/server/nodes/google/calendar/meta.json +3 -0
  269. package/server/nodes/google/{contacts.py → contacts/__init__.py} +84 -72
  270. package/server/nodes/google/contacts/meta.json +3 -0
  271. package/server/nodes/google/{drive.py → drive/__init__.py} +87 -72
  272. package/server/nodes/google/drive/meta.json +3 -0
  273. package/server/nodes/google/{gmail.py → gmail/__init__.py} +73 -39
  274. package/server/nodes/google/gmail/meta.json +3 -0
  275. package/server/nodes/google/{gmail_receive.py → gmail_receive/__init__.py} +31 -24
  276. package/server/nodes/google/gmail_receive/icon.svg +7 -0
  277. package/server/nodes/google/gmail_receive/meta.json +3 -0
  278. package/server/nodes/google/google.svg +7 -0
  279. package/server/nodes/google/{sheets.py → sheets/__init__.py} +54 -42
  280. package/server/nodes/google/sheets/meta.json +3 -0
  281. package/server/nodes/google/{tasks.py → tasks/__init__.py} +56 -43
  282. package/server/nodes/google/tasks/meta.json +3 -0
  283. package/server/nodes/groups.py +28 -28
  284. package/server/nodes/location/__init__.py +31 -1
  285. package/server/nodes/location/_credentials.py +1 -6
  286. package/server/nodes/location/_service.py +88 -107
  287. package/server/nodes/location/{gmaps_create.py → gmaps_create/__init__.py} +6 -6
  288. package/server/nodes/location/gmaps_create/meta.json +3 -0
  289. package/server/nodes/location/{gmaps_locations.py → gmaps_locations/__init__.py} +8 -6
  290. package/server/nodes/location/gmaps_locations/meta.json +3 -0
  291. package/server/nodes/location/{gmaps_nearby_places.py → gmaps_nearby_places/__init__.py} +8 -6
  292. package/server/nodes/location/gmaps_nearby_places/meta.json +3 -0
  293. package/server/nodes/model/_base.py +10 -7
  294. package/server/nodes/model/_credentials.py +10 -10
  295. package/server/nodes/model/_local_validator.py +28 -24
  296. package/server/nodes/model/{anthropic_chat_model.py → anthropic_chat_model/__init__.py} +5 -3
  297. package/server/nodes/model/anthropic_chat_model/meta.json +3 -0
  298. package/server/nodes/model/{cerebras_chat_model.py → cerebras_chat_model/__init__.py} +5 -3
  299. package/server/nodes/model/cerebras_chat_model/meta.json +3 -0
  300. package/server/nodes/model/{deepseek_chat_model.py → deepseek_chat_model/__init__.py} +8 -4
  301. package/server/nodes/model/deepseek_chat_model/meta.json +3 -0
  302. package/server/nodes/model/{gemini_chat_model.py → gemini_chat_model/__init__.py} +5 -3
  303. package/server/nodes/model/gemini_chat_model/meta.json +3 -0
  304. package/server/nodes/model/{groq_chat_model.py → groq_chat_model/__init__.py} +2 -2
  305. package/server/nodes/model/groq_chat_model/meta.json +3 -0
  306. package/server/nodes/model/{kimi_chat_model.py → kimi_chat_model/__init__.py} +2 -2
  307. package/server/nodes/model/kimi_chat_model/meta.json +3 -0
  308. package/server/nodes/model/{lmstudio_chat_model.py → lmstudio_chat_model/__init__.py} +2 -2
  309. package/server/nodes/model/lmstudio_chat_model/meta.json +3 -0
  310. package/server/nodes/model/{mistral_chat_model.py → mistral_chat_model/__init__.py} +2 -2
  311. package/server/nodes/model/mistral_chat_model/meta.json +3 -0
  312. package/server/nodes/model/{ollama_chat_model.py → ollama_chat_model/__init__.py} +2 -2
  313. package/server/nodes/model/ollama_chat_model/meta.json +3 -0
  314. package/server/nodes/model/{openai_chat_model.py → openai_chat_model/__init__.py} +8 -4
  315. package/server/nodes/model/openai_chat_model/meta.json +3 -0
  316. package/server/nodes/model/{openrouter_chat_model.py → openrouter_chat_model/__init__.py} +8 -4
  317. package/server/nodes/model/openrouter_chat_model/meta.json +3 -0
  318. package/server/nodes/proxy/_usage.py +14 -15
  319. package/server/nodes/proxy/{proxy_config.py → proxy_config/__init__.py} +39 -30
  320. package/server/nodes/proxy/proxy_config/meta.json +3 -0
  321. package/server/nodes/proxy/{proxy_request.py → proxy_request/__init__.py} +30 -16
  322. package/server/nodes/proxy/proxy_request/meta.json +3 -0
  323. package/server/nodes/proxy/{proxy_status.py → proxy_status/__init__.py} +2 -0
  324. package/server/nodes/proxy/proxy_status/meta.json +3 -0
  325. package/server/nodes/scheduler/{cron_scheduler.py → cron_scheduler/__init__.py} +96 -23
  326. package/server/nodes/scheduler/cron_scheduler/_workflow.py +155 -0
  327. package/server/nodes/scheduler/cron_scheduler/meta.json +3 -0
  328. package/server/nodes/scheduler/{timer.py → timer/__init__.py} +6 -5
  329. package/server/nodes/scheduler/timer/meta.json +3 -0
  330. package/server/nodes/scraper/_credentials.py +0 -1
  331. package/server/nodes/scraper/{apify_actor.py → apify_actor/__init__.py} +44 -35
  332. package/server/nodes/scraper/apify_actor/icon.svg +5 -0
  333. package/server/nodes/scraper/apify_actor/meta.json +3 -0
  334. package/server/nodes/scraper/{crawlee_scraper.py → crawlee_scraper/__init__.py} +96 -57
  335. package/server/nodes/scraper/crawlee_scraper/meta.json +3 -0
  336. package/server/nodes/search/{brave_search.py → brave_search/__init__.py} +6 -5
  337. package/server/nodes/search/brave_search/icon.svg +3 -0
  338. package/server/nodes/search/brave_search/meta.json +3 -0
  339. package/server/nodes/search/{duckduckgo_search.py → duckduckgo_search/__init__.py} +17 -6
  340. package/server/nodes/search/duckduckgo_search/meta.json +3 -0
  341. package/server/nodes/search/{perplexity_search.py → perplexity_search/__init__.py} +4 -5
  342. package/server/nodes/search/perplexity_search/icon.svg +3 -0
  343. package/server/nodes/search/perplexity_search/meta.json +3 -0
  344. package/server/nodes/search/{serper_search.py → serper_search/__init__.py} +32 -25
  345. package/server/nodes/search/serper_search/icon.svg +3 -0
  346. package/server/nodes/search/serper_search/meta.json +3 -0
  347. package/server/nodes/skill/__init__.py +21 -1
  348. package/server/nodes/skill/_expander.py +75 -0
  349. package/server/nodes/skill/{master_skill.py → master_skill/__init__.py} +2 -8
  350. package/server/nodes/skill/master_skill/_events.py +84 -0
  351. package/server/nodes/skill/master_skill/meta.json +3 -0
  352. package/server/nodes/skill/{simple_memory.py → simple_memory/__init__.py} +8 -16
  353. package/server/nodes/skill/simple_memory/meta.json +3 -0
  354. package/server/nodes/social/_base.py +223 -231
  355. package/server/nodes/social/{social_receive.py → social_receive/__init__.py} +38 -13
  356. package/server/nodes/social/social_receive/meta.json +3 -0
  357. package/server/nodes/social/{social_send.py → social_send/__init__.py} +71 -29
  358. package/server/nodes/social/social_send/icon.svg +1 -0
  359. package/server/nodes/social/social_send/meta.json +3 -0
  360. package/server/nodes/stripe/__init__.py +7 -3
  361. package/server/nodes/stripe/_credentials.py +0 -1
  362. package/server/nodes/stripe/_handlers.py +18 -7
  363. package/server/nodes/stripe/_install.py +14 -15
  364. package/server/nodes/stripe/_source.py +5 -5
  365. package/server/nodes/stripe/icon.svg +1 -0
  366. package/server/nodes/stripe/meta.json +3 -0
  367. package/server/nodes/stripe/stripe_action.py +4 -4
  368. package/server/nodes/stripe/stripe_receive.py +6 -9
  369. package/server/nodes/telegram/__init__.py +13 -0
  370. package/server/nodes/telegram/_credentials.py +2 -7
  371. package/server/nodes/telegram/_events.py +167 -0
  372. package/server/nodes/telegram/_filters.py +3 -11
  373. package/server/nodes/telegram/_handlers.py +17 -7
  374. package/server/nodes/telegram/_refresh.py +24 -34
  375. package/server/nodes/telegram/_service.py +29 -45
  376. package/server/nodes/telegram/meta.json +3 -0
  377. package/server/nodes/telegram/telegram.svg +3 -0
  378. package/server/nodes/telegram/telegram_receive.py +38 -18
  379. package/server/nodes/telegram/telegram_send.py +21 -19
  380. package/server/nodes/text/{file_handler.py → file_handler/__init__.py} +7 -1
  381. package/server/nodes/text/file_handler/meta.json +3 -0
  382. package/server/nodes/text/{text_generator.py → text_generator/__init__.py} +2 -1
  383. package/server/nodes/text/text_generator/meta.json +3 -0
  384. package/server/nodes/tool/{agent_builder.py → agent_builder/__init__.py} +105 -100
  385. package/server/nodes/tool/agent_builder/_events.py +91 -0
  386. package/server/nodes/tool/agent_builder/meta.json +3 -0
  387. package/server/nodes/tool/{calculator_tool.py → calculator_tool/__init__.py} +19 -7
  388. package/server/nodes/tool/calculator_tool/meta.json +3 -0
  389. package/server/nodes/tool/{current_time_tool.py → current_time_tool/__init__.py} +6 -4
  390. package/server/nodes/tool/current_time_tool/meta.json +3 -0
  391. package/server/nodes/tool/{task_manager.py → task_manager/__init__.py} +17 -18
  392. package/server/nodes/tool/task_manager/meta.json +3 -0
  393. package/server/nodes/tool/{write_todos.py → write_todos/__init__.py} +20 -6
  394. package/server/nodes/tool/write_todos/meta.json +3 -0
  395. package/server/nodes/trigger/{chat_trigger.py → chat_trigger/__init__.py} +11 -7
  396. package/server/nodes/trigger/chat_trigger/_events.py +53 -0
  397. package/server/nodes/trigger/chat_trigger/meta.json +3 -0
  398. package/server/nodes/trigger/{task_trigger.py → task_trigger/__init__.py} +10 -7
  399. package/server/nodes/trigger/task_trigger/meta.json +3 -0
  400. package/server/nodes/trigger/{webhook_trigger.py → webhook_trigger/__init__.py} +10 -7
  401. package/server/nodes/trigger/webhook_trigger/_events.py +54 -0
  402. package/server/nodes/trigger/webhook_trigger/meta.json +3 -0
  403. package/server/nodes/twitter/__init__.py +7 -1
  404. package/server/nodes/twitter/_base.py +86 -61
  405. package/server/nodes/twitter/_credentials.py +7 -5
  406. package/server/nodes/twitter/_events.py +101 -0
  407. package/server/nodes/twitter/_filters.py +9 -9
  408. package/server/nodes/twitter/_handlers.py +3 -1
  409. package/server/nodes/twitter/_oauth.py +1 -2
  410. package/server/nodes/twitter/_refresh.py +8 -12
  411. package/server/nodes/twitter/{twitter_receive.py → twitter_receive/__init__.py} +7 -7
  412. package/server/nodes/twitter/twitter_receive/icon.svg +1 -0
  413. package/server/nodes/twitter/twitter_receive/meta.json +3 -0
  414. package/server/nodes/twitter/{twitter_search.py → twitter_search/__init__.py} +16 -11
  415. package/server/nodes/twitter/twitter_search/icon.svg +1 -0
  416. package/server/nodes/twitter/twitter_search/meta.json +3 -0
  417. package/server/nodes/twitter/{twitter_send.py → twitter_send/__init__.py} +60 -27
  418. package/server/nodes/twitter/twitter_send/icon.svg +1 -0
  419. package/server/nodes/twitter/twitter_send/meta.json +3 -0
  420. package/server/nodes/twitter/{twitter_user.py → twitter_user/__init__.py} +34 -19
  421. package/server/nodes/twitter/twitter_user/icon.svg +1 -0
  422. package/server/nodes/twitter/twitter_user/meta.json +3 -0
  423. package/server/nodes/utility/{console.py → console/__init__.py} +17 -22
  424. package/server/nodes/utility/console/meta.json +3 -0
  425. package/server/nodes/utility/{http_request.py → http_request/__init__.py} +9 -6
  426. package/server/nodes/utility/http_request/meta.json +3 -0
  427. package/server/nodes/utility/{process_manager.py → process_manager/__init__.py} +10 -6
  428. package/server/nodes/utility/process_manager/meta.json +3 -0
  429. package/server/nodes/utility/team_monitor/meta.json +3 -0
  430. package/server/nodes/utility/{webhook_response.py → webhook_response/__init__.py} +12 -7
  431. package/server/nodes/utility/webhook_response/meta.json +3 -0
  432. package/server/nodes/visuals.json +69 -251
  433. package/server/nodes/whatsapp/__init__.py +24 -0
  434. package/server/nodes/whatsapp/_base.py +283 -338
  435. package/server/nodes/whatsapp/_credentials.py +44 -0
  436. package/server/nodes/whatsapp/_events.py +277 -0
  437. package/server/nodes/whatsapp/_filters.py +36 -37
  438. package/server/nodes/whatsapp/_handlers.py +2 -0
  439. package/server/nodes/whatsapp/_option_loaders.py +1 -3
  440. package/server/nodes/whatsapp/_refresh.py +13 -18
  441. package/server/nodes/whatsapp/_runtime.py +9 -6
  442. package/server/nodes/whatsapp/_service.py +89 -152
  443. package/server/nodes/whatsapp/meta.json +3 -0
  444. package/server/nodes/whatsapp/whatsapp_db.py +116 -54
  445. package/server/nodes/whatsapp/whatsapp_receive.py +30 -13
  446. package/server/nodes/whatsapp/whatsapp_send.py +60 -37
  447. package/server/nodes/workflow/{start.py → start/__init__.py} +1 -4
  448. package/server/nodes/workflow/start/meta.json +3 -0
  449. package/server/package-lock.json +3 -3
  450. package/server/package.json +3 -0
  451. package/server/pyproject.toml +39 -10
  452. package/server/requirements.txt +3 -5
  453. package/server/routers/__init__.py +1 -1
  454. package/server/routers/auth.py +16 -56
  455. package/server/routers/database.py +27 -50
  456. package/server/routers/nodejs_compat.py +25 -87
  457. package/server/routers/schemas.py +66 -2
  458. package/server/routers/webhook.py +12 -12
  459. package/server/routers/websocket.py +312 -1716
  460. package/server/routers/workflow.py +28 -53
  461. package/server/scripts/smoke_test_skills.py +178 -0
  462. package/server/services/__init__.py +1 -1
  463. package/server/services/_supervisor/process.py +9 -3
  464. package/server/services/_supervisor/registry.py +3 -3
  465. package/server/services/_supervisor/util.py +1 -1
  466. package/server/services/agent_team.py +15 -43
  467. package/server/services/agent_teams/__init__.py +17 -0
  468. package/server/services/agent_teams/handlers.py +195 -0
  469. package/server/services/ai.py +853 -1108
  470. package/server/services/auth.py +10 -34
  471. package/server/services/chat_client.py +5 -34
  472. package/server/services/circuit_breaker.py +2 -6
  473. package/server/services/cli_agent/__init__.py +28 -4
  474. package/server/services/cli_agent/_cli_auth.py +61 -0
  475. package/server/services/cli_agent/_handlers.py +24 -183
  476. package/server/services/cli_agent/config.py +5 -8
  477. package/server/services/cli_agent/factory.py +168 -22
  478. package/server/services/cli_agent/jsonl_watcher.py +380 -0
  479. package/server/services/cli_agent/lockfile.py +9 -2
  480. package/server/services/cli_agent/mcp_server.py +110 -34
  481. package/server/services/cli_agent/protocol.py +37 -19
  482. package/server/services/cli_agent/providers/__init__.py +8 -4
  483. package/server/services/cli_agent/providers/google_gemini.py +11 -5
  484. package/server/services/cli_agent/providers/openai_codex.py +34 -34
  485. package/server/services/cli_agent/service.py +245 -83
  486. package/server/services/cli_agent/session.py +409 -229
  487. package/server/services/cli_agent/transports/__init__.py +47 -0
  488. package/server/services/cli_agent/transports/base.py +111 -0
  489. package/server/services/cli_agent/transports/posix.py +196 -0
  490. package/server/services/cli_agent/transports/windows.py +189 -0
  491. package/server/services/cli_agent/types.py +45 -18
  492. package/server/services/cli_agent/workflow_tools.py +28 -15
  493. package/server/services/compaction.py +68 -52
  494. package/server/services/credential_registry.py +6 -20
  495. package/server/services/credentials/__init__.py +18 -0
  496. package/server/services/credentials/handlers.py +196 -0
  497. package/server/services/deployment/__init__.py +12 -1
  498. package/server/services/deployment/canary_registry.py +137 -0
  499. package/server/services/deployment/handlers.py +382 -0
  500. package/server/services/deployment/manager.py +653 -163
  501. package/server/services/deployment/poll_registry.py +2 -6
  502. package/server/services/deployment/state.py +2 -0
  503. package/server/services/deployment/triggers.py +87 -93
  504. package/server/services/event_waiter.py +47 -54
  505. package/server/services/events/__init__.py +11 -0
  506. package/server/services/events/admin_handlers.py +368 -0
  507. package/server/services/events/daemon.py +3 -1
  508. package/server/services/events/dispatch.py +188 -0
  509. package/server/services/events/envelope.py +264 -45
  510. package/server/services/events/oauth_lifecycle.py +98 -42
  511. package/server/services/events/triggers.py +3 -13
  512. package/server/services/events/verifiers/hmac_basic.py +1 -1
  513. package/server/services/events/verifiers/standard_webhooks.py +2 -4
  514. package/server/services/events/webhook.py +2 -3
  515. package/server/services/example_loader.py +73 -15
  516. package/server/services/execution/cache.py +36 -76
  517. package/server/services/execution/conditions.py +7 -20
  518. package/server/services/execution/dlq.py +20 -24
  519. package/server/services/execution/executor.py +234 -265
  520. package/server/services/execution/models.py +40 -46
  521. package/server/services/execution/recovery.py +23 -46
  522. package/server/services/handlers/__init__.py +12 -16
  523. package/server/services/handlers/todo.py +3 -6
  524. package/server/services/handlers/tools.py +143 -194
  525. package/server/services/handlers/triggers.py +24 -23
  526. package/server/services/llm/config.py +10 -1
  527. package/server/services/llm/factory.py +16 -4
  528. package/server/services/llm/messages.py +1 -5
  529. package/server/services/llm/protocol.py +9 -1
  530. package/server/services/llm/providers/anthropic.py +23 -12
  531. package/server/services/llm/providers/gemini.py +43 -22
  532. package/server/services/llm/providers/openai.py +14 -6
  533. package/server/services/llm/providers/openrouter.py +6 -1
  534. package/server/services/markdown_formatter.py +1 -2
  535. package/server/services/memory/__init__.py +2 -2
  536. package/server/services/memory/jsonl.py +6 -2
  537. package/server/services/memory/markdown.py +6 -6
  538. package/server/services/memory/state.py +6 -5
  539. package/server/services/memory_store.py +8 -12
  540. package/server/services/model_registry.py +22 -20
  541. package/server/services/node_executor.py +85 -80
  542. package/server/services/node_output_schemas.py +4 -7
  543. package/server/services/node_registry.py +40 -4
  544. package/server/services/node_spec.py +3 -7
  545. package/server/services/nodejs_client.py +4 -14
  546. package/server/services/oauth_utils.py +11 -7
  547. package/server/services/parameter_resolver.py +30 -36
  548. package/server/services/plugin/base.py +321 -38
  549. package/server/services/plugin/connection.py +12 -7
  550. package/server/services/plugin/credential.py +80 -22
  551. package/server/services/plugin/edge_walker.py +128 -105
  552. package/server/services/plugin/identifiers.py +48 -0
  553. package/server/services/plugin/interceptor.py +1 -1
  554. package/server/services/plugin/oauth.py +25 -21
  555. package/server/services/plugin/operation.py +1 -1
  556. package/server/services/plugin/polling.py +151 -26
  557. package/server/services/plugin/registry.py +52 -4
  558. package/server/services/plugin/routing.py +6 -9
  559. package/server/services/plugin/scaling.py +36 -18
  560. package/server/services/plugin/service_factories.py +95 -0
  561. package/server/services/plugin/shutdown_hooks.py +103 -0
  562. package/server/services/plugin/social_provider_registry.py +80 -0
  563. package/server/services/plugin/ws.py +2 -1
  564. package/server/services/pricing.py +26 -40
  565. package/server/services/pricing_handlers.py +90 -0
  566. package/server/services/process_service.py +33 -32
  567. package/server/services/proxy/models.py +15 -9
  568. package/server/services/proxy/service.py +26 -40
  569. package/server/services/rlm/adapters.py +43 -40
  570. package/server/services/rlm/constants.py +9 -9
  571. package/server/services/rlm/service.py +57 -45
  572. package/server/services/scheduler.py +8 -39
  573. package/server/services/settings/__init__.py +16 -0
  574. package/server/services/settings/handlers.py +275 -0
  575. package/server/services/skill_loader.py +53 -45
  576. package/server/services/skill_prompt.py +8 -6
  577. package/server/services/skills/__init__.py +23 -0
  578. package/server/services/skills/handlers.py +479 -0
  579. package/server/services/status_broadcaster.py +314 -291
  580. package/server/services/temporal/__init__.py +22 -1
  581. package/server/services/temporal/_handlers.py +65 -0
  582. package/server/services/temporal/_install.py +158 -0
  583. package/server/services/temporal/_refresh.py +57 -0
  584. package/server/services/temporal/_retry_policies.py +85 -0
  585. package/server/services/temporal/_runtime.py +181 -0
  586. package/server/services/temporal/_supervised_runtime.py +102 -0
  587. package/server/services/temporal/activities.py +168 -11
  588. package/server/services/temporal/agent_activities.py +683 -0
  589. package/server/services/temporal/agent_workflow.py +601 -0
  590. package/server/services/temporal/client.py +58 -13
  591. package/server/services/temporal/executor.py +2 -3
  592. package/server/services/temporal/plugin_activities.py +37 -2
  593. package/server/services/temporal/plugin_registry.py +82 -0
  594. package/server/services/temporal/polling_trigger_workflow.py +267 -0
  595. package/server/services/temporal/schedules.py +220 -0
  596. package/server/services/temporal/search_attributes.py +177 -0
  597. package/server/services/temporal/trigger_listener_workflow.py +378 -0
  598. package/server/services/temporal/worker.py +111 -18
  599. package/server/services/temporal/workflow.py +259 -40
  600. package/server/services/temporal/ws_client.py +22 -11
  601. package/server/services/text.py +14 -28
  602. package/server/services/tracked_http.py +29 -49
  603. package/server/services/user_auth.py +7 -21
  604. package/server/services/workflow.py +28 -20
  605. package/server/services/workflow_import.py +351 -0
  606. package/server/services/workflow_ops.py +4 -0
  607. package/server/services/workflow_storage/__init__.py +18 -0
  608. package/server/services/workflow_storage/handlers.py +132 -0
  609. package/server/services/workflow_validator.py +209 -0
  610. package/server/services/ws_handler_registry.py +80 -9
  611. package/server/skills/assistant/agent-builder-skill/SKILL.md +6 -6
  612. package/server/tests/conftest.py +54 -3
  613. package/server/tests/credentials/test_auth_service.py +9 -21
  614. package/server/tests/credentials/test_credential_broadcasts.py +116 -22
  615. package/server/tests/credentials/test_credentials_database.py +12 -38
  616. package/server/tests/credentials/test_encryption.py +3 -9
  617. package/server/tests/credentials/test_google_oauth.py +1 -3
  618. package/server/tests/credentials/test_oauth_utils.py +31 -38
  619. package/server/tests/credentials/test_twitter_oauth.py +1 -3
  620. package/server/tests/credentials/test_websocket_handlers.py +37 -72
  621. package/server/tests/fixtures/tool_names_snapshot.json +78 -0
  622. package/server/tests/llm/test_factory.py +12 -4
  623. package/server/tests/llm/test_providers.py +25 -32
  624. package/server/tests/llm/test_wiring.py +27 -22
  625. package/server/tests/nodes/_compat.py +4 -5
  626. package/server/tests/nodes/_harness.py +31 -24
  627. package/server/tests/nodes/_mocks.py +2 -6
  628. package/server/tests/nodes/test_agent_builder.py +43 -35
  629. package/server/tests/nodes/test_ai_agents.py +29 -24
  630. package/server/tests/nodes/test_ai_chat_models.py +3 -9
  631. package/server/tests/nodes/test_ai_tools.py +29 -24
  632. package/server/tests/nodes/test_android.py +34 -64
  633. package/server/tests/nodes/test_chat_utility.py +2 -2
  634. package/server/tests/nodes/test_code_fs_process.py +26 -84
  635. package/server/tests/nodes/test_document.py +23 -47
  636. package/server/tests/nodes/test_email.py +88 -51
  637. package/server/tests/nodes/test_google_workspace.py +26 -20
  638. package/server/tests/nodes/test_http_proxy.py +43 -89
  639. package/server/tests/nodes/test_search.py +3 -9
  640. package/server/tests/nodes/test_specialized_agents.py +58 -162
  641. package/server/tests/nodes/test_stripe_plugin.py +25 -5
  642. package/server/tests/nodes/test_telegram_social.py +33 -37
  643. package/server/tests/nodes/test_twitter.py +59 -150
  644. package/server/tests/nodes/test_web_automation.py +21 -51
  645. package/server/tests/nodes/test_whatsapp.py +13 -19
  646. package/server/tests/nodes/test_workflow_triggers.py +16 -45
  647. package/server/tests/services/cli_agent/test_claude_session_events.py +201 -0
  648. package/server/tests/services/cli_agent/test_jsonl_watcher.py +190 -0
  649. package/server/tests/services/cli_agent/test_mcp_server.py +67 -29
  650. package/server/tests/services/cli_agent/test_providers.py +236 -47
  651. package/server/tests/services/cli_agent/test_service.py +9 -7
  652. package/server/tests/services/memory/test_jsonl.py +30 -25
  653. package/server/tests/services/test_events.py +26 -7
  654. package/server/tests/services/test_identifiers.py +122 -0
  655. package/server/tests/services/test_process_lifecycle.py +129 -0
  656. package/server/tests/services/test_supervisor.py +0 -1
  657. package/server/tests/temporal/__init__.py +0 -0
  658. package/server/tests/temporal/test_agent_workflow.py +215 -0
  659. package/server/tests/temporal/test_dispatch.py +231 -0
  660. package/server/tests/test_admin_handlers.py +394 -0
  661. package/server/tests/test_auto_skill.py +4 -2
  662. package/server/tests/test_canary_registry.py +310 -0
  663. package/server/tests/test_chat_trigger_canary_producer.py +101 -0
  664. package/server/tests/test_cloudevents_node_parameters.py +129 -0
  665. package/server/tests/test_credential_icon.py +115 -0
  666. package/server/tests/test_cron_canary.py +511 -0
  667. package/server/tests/test_deployment_canary_listener.py +692 -0
  668. package/server/tests/test_event_framework_phase_a.py +537 -0
  669. package/server/tests/test_no_raw_prints.py +131 -0
  670. package/server/tests/test_node_spec.py +196 -103
  671. package/server/tests/test_parameter_resolver.py +20 -20
  672. package/server/tests/test_plugin_contract.py +76 -49
  673. package/server/tests/test_plugin_helpers.py +0 -1
  674. package/server/tests/test_plugin_self_containment.py +40 -47
  675. package/server/tests/test_polling_trigger_workflow.py +572 -0
  676. package/server/tests/test_retry_policies.py +146 -0
  677. package/server/tests/test_service_factories.py +168 -0
  678. package/server/tests/test_shutdown_hooks.py +199 -0
  679. package/server/tests/test_social_provider_registry.py +177 -0
  680. package/server/tests/test_status_broadcasts.py +214 -63
  681. package/server/tests/test_task_trigger_canary_producer.py +131 -0
  682. package/server/tests/test_telegram_trigger_canary_producer.py +113 -0
  683. package/server/tests/test_tool_registry.py +110 -0
  684. package/server/tests/test_trigger_listener_workflow.py +365 -0
  685. package/server/tests/test_whatsapp_trigger_canary_producer.py +164 -0
  686. package/server/tests/test_workflow_ops.py +1 -3
  687. package/server/tests/test_workflow_validator.py +791 -0
  688. package/server/uv.lock +3539 -0
  689. package/client/dist/assets/index-DQ0nwhec.js +0 -257
  690. package/client/src/assets/icons/apify/index.ts +0 -19
  691. package/client/src/assets/icons/browser/index.ts +0 -17
  692. package/client/src/assets/icons/email/index.ts +0 -22
  693. package/client/src/assets/icons/google/index.ts +0 -34
  694. package/client/src/assets/icons/llm/deepseek.svg +0 -1
  695. package/client/src/assets/icons/llm/index.ts +0 -18
  696. package/client/src/assets/icons/llm/kimi.svg +0 -1
  697. package/client/src/assets/icons/llm/mistral.svg +0 -1
  698. package/client/src/assets/icons/search/index.ts +0 -28
  699. package/client/src/assets/icons/telegram/index.ts +0 -19
  700. package/machina/buildenv.py +0 -44
  701. package/machina/cli.py +0 -55
  702. package/machina/commands/__init__.py +0 -1
  703. package/machina/commands/clean.py +0 -80
  704. package/machina/commands/daemon.py +0 -150
  705. package/machina/config.py +0 -93
  706. package/machina/platform_.py +0 -37
  707. package/machina/pyproject.toml +0 -33
  708. package/server/nodes/agent/deep_agent.py +0 -103
  709. package/server/services/agents/__init__.py +0 -9
  710. package/server/services/agents/adapters.py +0 -199
  711. package/server/services/agents/constants.py +0 -10
  712. package/server/services/agents/service.py +0 -297
  713. package/server/services/cli_agent/providers/anthropic_claude.py +0 -419
  714. /package/{machina → cli}/README.md +0 -0
  715. /package/{machina → cli}/__init__.py +0 -0
  716. /package/{client/src/assets/icons/apify → server/credentials/icons}/apify.svg +0 -0
  717. /package/{client/src/assets/icons/search/brave.svg → server/credentials/icons/brave_search.svg} +0 -0
  718. /package/{client/src/assets/icons/email/read.svg → server/credentials/icons/email_himalaya.svg} +0 -0
  719. /package/{client/src/assets/icons/search → server/credentials/icons}/perplexity.svg +0 -0
  720. /package/{client/src/assets/icons/search/google.svg → server/credentials/icons/serper.svg} +0 -0
  721. /package/{client/src/assets → server/credentials}/icons/stripe.svg +0 -0
  722. /package/{client/src/assets/icons/twitter/x.svg → server/credentials/icons/twitter.svg} +0 -0
  723. /package/{client/src/assets/icons/browser/chrome.svg → server/nodes/browser/browser/icon.svg} +0 -0
  724. /package/{client/src/assets/icons/chat/chat.svg → server/nodes/chat/chat_history/icon.svg} +0 -0
  725. /package/{client/src/assets/icons/code/javascript.svg → server/nodes/code/javascript_executor/icon.svg} +0 -0
  726. /package/{client/src/assets/icons/code/python.svg → server/nodes/code/python_executor/icon.svg} +0 -0
  727. /package/{client/src/assets/icons/code/typescript.svg → server/nodes/code/typescript_executor/icon.svg} +0 -0
  728. /package/{client/src/assets/icons/email/receive.svg → server/nodes/email/email_receive/icon.svg} +0 -0
  729. /package/{client/src/assets/icons/email/send.svg → server/nodes/email/email_send/icon.svg} +0 -0
  730. /package/{client/src/assets/icons/google/calendar.svg → server/nodes/google/calendar/icon.svg} +0 -0
  731. /package/{client/src/assets/icons/google/contacts.svg → server/nodes/google/contacts/icon.svg} +0 -0
  732. /package/{client/src/assets/icons/google/drive.svg → server/nodes/google/drive/icon.svg} +0 -0
  733. /package/{client/src/assets/icons/google/gmail.svg → server/nodes/google/gmail/icon.svg} +0 -0
  734. /package/{client/src/assets/icons/google/sheets.svg → server/nodes/google/sheets/icon.svg} +0 -0
  735. /package/{client/src/assets/icons/google/tasks.svg → server/nodes/google/tasks/icon.svg} +0 -0
  736. /package/{client/src/assets/icons/search/duckduckgo.svg → server/nodes/search/duckduckgo_search/icon.svg} +0 -0
  737. /package/{client/src/assets/icons/social/social.svg → server/nodes/social/social_receive/icon.svg} +0 -0
  738. /package/{client/src/assets/icons/telegram/telegram.svg → server/nodes/telegram/icon.svg} +0 -0
  739. /package/server/nodes/utility/{team_monitor.py → team_monitor/__init__.py} +0 -0
  740. /package/{client/src/assets/icons/whatsapp/whatsapp-db.svg → server/nodes/whatsapp/icon_whatsappDb.svg} +0 -0
  741. /package/{client/src/assets/icons/whatsapp/whatsapp-receive.svg → server/nodes/whatsapp/icon_whatsappReceive.svg} +0 -0
  742. /package/{client/src/assets/icons/whatsapp/whatsapp-send.svg → server/nodes/whatsapp/icon_whatsappSend.svg} +0 -0
  743. /package/{client/src/assets/icons → server/nodes}/whatsapp/whatsapp.svg +0 -0
@@ -15,19 +15,25 @@ import asyncio
15
15
  import json
16
16
  import os
17
17
  import subprocess
18
- import sys
19
18
  import time
20
19
  from pathlib import Path
21
20
 
22
21
  import typer
23
22
 
24
- from machina.colors import console
25
- from machina.config import load_config
26
- from machina.platform_ import IS_WINDOWS, IS_WSL, platform_name, project_root
27
- from machina.buildenv import validate_build, venv_python
28
- from machina.ports import kill_port
29
- from machina.run import which_argv
30
- from machina.supervisor import Manager, RestartPolicy, ServiceSpec
23
+ from cli._common import build_backend_spec, error_block, free_all_ports, preflight
24
+ from cli.colors import console
25
+ from cli.platform_ import (
26
+ IS_WINDOWS,
27
+ IS_WSL,
28
+ platform_name,
29
+ server_dir,
30
+ server_venv,
31
+ static_client_script,
32
+ )
33
+ from cli.buildenv import validate_build
34
+ from cli.run import uv_run
35
+ from cli.supervisor import Manager, ServiceSpec
36
+ from cli.commands._temporal_specs import temporal_specs
31
37
 
32
38
 
33
39
  def _sqlalchemy_preflight(root: Path) -> None:
@@ -38,28 +44,55 @@ def _sqlalchemy_preflight(root: Path) -> None:
38
44
  calls even after exclusions are added. Catching it here gives a
39
45
  clear remediation message instead of letting uvicorn hang silently.
40
46
  See ``docs-internal/errors.md`` #1 / #1a.
47
+
48
+ Runs the probe inside the server ``.venv`` through ``uv run`` with
49
+ ``cwd=server/`` so uv discovers ``server/pyproject.toml`` (the only
50
+ place uv-managed Python deps live -- root ``pyproject.toml`` is the
51
+ standalone CLI package). Same environment the supervised services
52
+ will use, no path-to-interpreter logic on this side.
41
53
  """
42
- py = venv_python(root)
43
- if py is None:
44
- return
45
54
  started = time.monotonic()
46
55
  try:
47
56
  subprocess.run(
48
- [str(py), "-c", "import sqlalchemy"],
57
+ uv_run("python", "-c", "import sqlalchemy"),
58
+ cwd=str(server_dir(root)),
49
59
  timeout=15,
50
60
  check=True,
51
61
  capture_output=True,
52
62
  )
53
- except (subprocess.TimeoutExpired, subprocess.CalledProcessError):
63
+ except (subprocess.TimeoutExpired, subprocess.CalledProcessError) as exc:
54
64
  elapsed = time.monotonic() - started
55
- console.print(f"[red]Error: Python venv health check failed ({elapsed:.1f}s).[/]")
56
- console.print(" sqlalchemy import hung or crashed.")
57
- console.print(" Likely cause: Windows Defender scan cache or stale kernel state.")
58
- console.print(" Fix options:")
59
- console.print(" 1. Restart-Service WinDefend (admin PowerShell)")
60
- console.print(" 2. Reboot the machine")
61
- console.print(f" 3. Add {root / 'server' / '.venv'} to Defender exclusions")
62
- console.print(" See docs-internal/errors.md #1 / #1a for details.")
65
+ stderr_tail = ""
66
+ if isinstance(exc, subprocess.CalledProcessError) and exc.stderr:
67
+ stderr_bytes = (
68
+ exc.stderr if isinstance(exc.stderr, bytes) else exc.stderr.encode()
69
+ )
70
+ stderr_tail = stderr_bytes.decode(errors="replace").strip()
71
+ details: list[str] = ["sqlalchemy import hung or crashed."]
72
+ if stderr_tail:
73
+ details.append(f"subprocess stderr: {stderr_tail}")
74
+ if IS_WINDOWS:
75
+ details.extend(
76
+ [
77
+ "Likely cause on Windows: Defender scan cache or stale kernel state.",
78
+ "Fix options:",
79
+ " 1. Restart-Service WinDefend (admin PowerShell)",
80
+ " 2. Reboot the machine",
81
+ f" 3. Add {server_venv(root)} to Defender exclusions",
82
+ ]
83
+ )
84
+ else:
85
+ details.extend(
86
+ [
87
+ f"Check that {server_venv(root)} exists and is populated.",
88
+ "Run `machina build` to recreate the server venv.",
89
+ ]
90
+ )
91
+ details.append("See docs-internal/errors.md #1 / #1a for details.")
92
+ error_block(
93
+ f"Python venv health check failed ({elapsed:.1f}s).",
94
+ details,
95
+ )
63
96
  raise typer.Exit(code=1)
64
97
  elapsed = time.monotonic() - started
65
98
  if elapsed > 5.0:
@@ -69,18 +102,15 @@ def _sqlalchemy_preflight(root: Path) -> None:
69
102
  )
70
103
 
71
104
 
72
- def _temporal_running() -> bool:
73
- """Check whether the temporal server is already up via the ``temporal`` CLI."""
74
- try:
75
- out = subprocess.run(
76
- which_argv(["temporal", "status"]),
77
- capture_output=True,
78
- text=True,
79
- timeout=5,
80
- )
81
- return any(token in out.stdout for token in ("running", "UP", "up"))
82
- except (FileNotFoundError, subprocess.TimeoutExpired):
83
- return False
105
+ def _temporal_running(cfg) -> bool:
106
+ """Check whether a Temporal frontend is already listening on the
107
+ configured gRPC port. TCP probe instead of spawning a CLI -- works
108
+ without the legacy ``temporal-server`` npm wrapper (we install our
109
+ own binary via pooch at first boot of the supervised
110
+ ``TemporalServerRuntime``)."""
111
+ from cli.tcp import probe_tcp_port_sync
112
+
113
+ return probe_tcp_port_sync(cfg.temporal_port)
84
114
 
85
115
 
86
116
  def _read_version(root: Path) -> str:
@@ -92,61 +122,38 @@ def _read_version(root: Path) -> str:
92
122
 
93
123
 
94
124
  def _build_specs(root: Path, cfg, *, temporal_running: bool) -> list[ServiceSpec]:
95
- static_client = root / "scripts" / "serve-client.js"
96
- server_dir = root / "server"
97
-
98
125
  # Match the existing behaviour: production uses python:start
99
126
  # (bind 127.0.0.1) on Windows/WSL, python:daemon (bind 0.0.0.0)
100
127
  # on POSIX.
101
128
  backend_host = "127.0.0.1" if (IS_WINDOWS or IS_WSL) else "0.0.0.0"
102
- backend_argv = [
103
- "uv", "run", "uvicorn", "main:app",
104
- "--host", backend_host,
105
- "--port", str(cfg.backend_port),
106
- "--log-level", "warning",
107
- ]
108
129
 
109
130
  specs: list[ServiceSpec] = [
110
131
  ServiceSpec(
111
132
  name="client",
112
- argv=["node", str(static_client)],
133
+ argv=["node", str(static_client_script(root))],
113
134
  cwd=root,
114
135
  ready_port=cfg.client_port,
115
136
  ),
116
- ServiceSpec(
117
- name="server",
118
- argv=backend_argv,
119
- cwd=server_dir,
120
- ready_port=cfg.backend_port,
121
- ),
137
+ build_backend_spec(cfg, host=backend_host, root=root),
122
138
  ]
123
139
  if not temporal_running:
124
- specs.append(
125
- ServiceSpec(
126
- name="temporal",
127
- argv=["temporal", "api"],
128
- cwd=root,
129
- ready_port=cfg.temporal_port,
130
- )
131
- )
140
+ specs.extend(temporal_specs(root, cfg))
132
141
  return specs
133
142
 
134
143
 
135
144
  def start_command() -> None:
136
- root = project_root()
137
- cfg = load_config()
145
+ cfg, root = preflight()
138
146
  os.environ.setdefault("PYTHONUTF8", "1")
139
147
 
140
148
  validate_build(root, require_client_dist=True)
141
149
  _sqlalchemy_preflight(root)
142
150
 
143
- temporal_running = _temporal_running()
151
+ temporal_running = _temporal_running(cfg)
144
152
  if temporal_running:
145
153
  console.print("[dim]Temporal already running, skipping[/]")
146
154
 
147
155
  console.log("Freeing ports...")
148
- for port in cfg.all_ports:
149
- kill_port(port)
156
+ free_all_ports(cfg)
150
157
  console.log("Ports ready")
151
158
 
152
159
  version = _read_version(root)
@@ -11,30 +11,27 @@ import time
11
11
 
12
12
  import typer
13
13
 
14
- from machina.colors import console
15
- from machina.config import load_config
16
- from machina.platform_ import platform_name, project_root
17
- from machina.ports import (
14
+ from cli._common import free_all_ports, preflight
15
+ from cli.colors import console
16
+ from cli.platform_ import platform_name
17
+ from cli.ports import (
18
18
  kill_by_pattern,
19
19
  kill_orphaned_machina_processes,
20
- kill_port,
21
20
  )
22
21
 
23
22
 
24
23
  def stop_command() -> None:
25
- cfg = load_config()
26
- root = project_root()
24
+ cfg, root = preflight()
27
25
 
28
26
  console.print()
29
27
  console.print("[bold]Stopping MachinaOS services...[/]")
30
28
  console.print(f"Platform: {platform_name()}")
31
29
  console.print(f"Ports: {', '.join(str(p) for p in cfg.all_ports)}")
32
- console.print(f"Temporal: enabled" if cfg.temporal_enabled else "Temporal: disabled")
30
+ console.print("Temporal: enabled" if cfg.temporal_enabled else "Temporal: disabled")
33
31
  console.print()
34
32
 
35
33
  all_stopped = True
36
- for port in cfg.all_ports:
37
- result = kill_port(port)
34
+ for port, result in zip(cfg.all_ports, free_all_ports(cfg)):
38
35
  status = "[green]\\[OK][/]" if result.port_free else "[red]\\[!!][/]"
39
36
  if result.port_free:
40
37
  if result.killed_pids:
@@ -13,9 +13,9 @@ from pathlib import Path
13
13
 
14
14
  import typer
15
15
 
16
- from machina.colors import console
17
- from machina.platform_ import project_root
18
- from machina.run import capture
16
+ from cli.colors import console
17
+ from cli.platform_ import project_root
18
+ from cli.run import capture
19
19
 
20
20
 
21
21
  app = typer.Typer(
@@ -36,7 +36,9 @@ def _git_describe(root: Path) -> str | None:
36
36
  return described
37
37
  listed = capture(["git", "tag", "-l", "--sort=-version:refname"], cwd=root)
38
38
  if listed:
39
- return next((line.strip() for line in listed.splitlines() if line.strip()), None)
39
+ return next(
40
+ (line.strip() for line in listed.splitlines() if line.strip()), None
41
+ )
40
42
  return None
41
43
 
42
44
 
@@ -58,7 +60,9 @@ def _update_package_json(path: Path, new_version: str) -> bool:
58
60
 
59
61
 
60
62
  @app.command("sync", help="Sync package.json versions from latest git tag.")
61
- def sync(tag: str | None = typer.Argument(None, help="Git tag to use (defaults to latest).")) -> None:
63
+ def sync(
64
+ tag: str | None = typer.Argument(None, help="Git tag to use (defaults to latest)."),
65
+ ) -> None:
62
66
  root = project_root()
63
67
  resolved_tag = tag or _git_describe(root)
64
68
  if not resolved_tag:
@@ -67,7 +71,9 @@ def sync(tag: str | None = typer.Argument(None, help="Git tag to use (defaults t
67
71
 
68
72
  version = _tag_to_version(resolved_tag)
69
73
  if not _VALID_VERSION.match(version):
70
- console.print(f"[red]Error: Invalid version from tag {resolved_tag!r}: {version!r}[/]")
74
+ console.print(
75
+ f"[red]Error: Invalid version from tag {resolved_tag!r}: {version!r}[/]"
76
+ )
71
77
  console.print("Expected semver format (e.g. v0.0.11 or 0.0.11).")
72
78
  raise typer.Exit(code=1)
73
79
 
package/cli/config.py ADDED
@@ -0,0 +1,170 @@
1
+ """Project configuration -- typed view over ``.env.dev`` / ``.env`` / ``.env.template``.
2
+
3
+ Stdlib-only env-var loader. Three env files, lowest precedence first:
4
+
5
+ 1. ``.env.template`` — canonical production defaults. Ships with every
6
+ install. ``DATA_DIR=~/.machina`` (user home) is the daemon
7
+ behaviour: ``machina start`` / ``machina daemon`` use these.
8
+ 2. ``.env`` — user overrides (created by ``scripts/postinstall.js`` on
9
+ ``npm install -g machinaos``). Gitignored.
10
+ 3. ``.env.dev`` — dev-mode overrides. Loaded ONLY by ``machina dev``
11
+ via :func:`load_dev_overrides`. Pins ``DATA_DIR=.machina`` so
12
+ per-checkout dev state lives at ``<repo>/.machina/`` instead of
13
+ ``~/.machina/``. Committed to git.
14
+
15
+ Process env (``os.environ``) wins over all three. Merged file values
16
+ are pushed into ``os.environ`` via ``setdefault`` so downstream
17
+ consumers that read ``os.environ`` directly see the same view as this
18
+ module.
19
+
20
+ No Python-side hardcoded defaults: env files are the single source of
21
+ truth. If ``.env.template`` is missing (broken install), we error out
22
+ loudly with a remediation hint rather than silently substituting
23
+ duplicate hardcoded values that drift from the shipped template.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import os
29
+ from dataclasses import dataclass
30
+ from functools import lru_cache
31
+ from pathlib import Path
32
+
33
+ from cli.platform_ import project_root
34
+
35
+
36
+ def _load_env_file(path: Path) -> dict[str, str]:
37
+ out: dict[str, str] = {}
38
+ if not path.exists():
39
+ return out
40
+ for raw in path.read_text(encoding="utf-8").splitlines():
41
+ line = raw.strip()
42
+ if not line or line.startswith("#") or "=" not in line:
43
+ continue
44
+ key, _, value = line.partition("=")
45
+ value = value.strip()
46
+ if len(value) >= 2 and value[0] == value[-1] and value[0] in ("'", '"'):
47
+ value = value[1:-1]
48
+ out[key.strip()] = value
49
+ return out
50
+
51
+
52
+ def _require(env: dict[str, str], key: str) -> str:
53
+ raw = env.get(key)
54
+ if raw is None:
55
+ raise KeyError(
56
+ f"{key} missing from .env / .env.template -- "
57
+ "reinstall (``npm install -g machinaos``) or restore the template."
58
+ )
59
+ return raw
60
+
61
+
62
+ def _int(env: dict[str, str], key: str) -> int:
63
+ return int(_require(env, key))
64
+
65
+
66
+ def _bool(env: dict[str, str], key: str) -> bool:
67
+ return _require(env, key).strip().lower() in ("1", "true", "yes", "on")
68
+
69
+
70
+ @dataclass(frozen=True)
71
+ class Config:
72
+ """Typed view over the merged ``.env.template`` + ``.env`` + process
73
+ env. No field defaults -- every value originates in the env files so
74
+ the published shape matches what users see (and can edit) in their
75
+ ``.env``."""
76
+
77
+ client_port: int
78
+ backend_port: int
79
+ whatsapp_port: int
80
+ nodejs_port: int
81
+ temporal_address: str
82
+ temporal_enabled: bool
83
+ temporal_ui_port: int
84
+
85
+ @property
86
+ def temporal_port(self) -> int:
87
+ return int(self.temporal_address.rsplit(":", 1)[-1])
88
+
89
+ @property
90
+ def all_ports(self) -> list[int]:
91
+ # Ports the supervisor frees pre-spawn and verifies are released
92
+ # on ``machina stop``. ``temporal_port`` (gRPC) and
93
+ # ``temporal_ui_port`` are bound by the same ``temporal server
94
+ # start-dev`` process, so killing one kills both — listing both
95
+ # only matters when cleaning up stale orphans on either port.
96
+ return [
97
+ self.client_port,
98
+ self.backend_port,
99
+ self.whatsapp_port,
100
+ self.nodejs_port,
101
+ self.temporal_port,
102
+ self.temporal_ui_port,
103
+ ]
104
+
105
+
106
+ def load_dev_overrides(root: Path | None = None) -> None:
107
+ """Layer ``.env.dev`` on top of ``.env.template`` + ``.env``.
108
+
109
+ Called by ``machina dev`` BEFORE :func:`load_config` so dev-only env
110
+ vars (notably ``DATA_DIR=.machina``, the per-checkout dev state
111
+ root) land in ``os.environ`` first. ``load_config`` then sees them
112
+ via its own ``setdefault`` pass and skips its template fallbacks.
113
+
114
+ Uses ``setdefault`` so an explicit shell override
115
+ (``DATA_DIR=/foo machina dev``) still wins. Missing ``.env.dev``
116
+ file is a no-op — production-style invocations never trigger this.
117
+
118
+ The daemon path (``machina start`` / ``machina daemon``) does not
119
+ call this, so daemon installs keep the ``.env.template`` default
120
+ of ``DATA_DIR=~/.machina``.
121
+ """
122
+ root = root or project_root()
123
+ for key, value in _load_env_file(root / ".env.dev").items():
124
+ os.environ.setdefault(key, value)
125
+
126
+
127
+ @lru_cache(maxsize=1)
128
+ def load_config(root: Path | None = None) -> Config:
129
+ """Load + merge ``.env.template`` (baseline) and ``.env`` (overrides).
130
+
131
+ Precedence (low -> high): ``.env.template`` < ``.env`` < ``os.environ``.
132
+
133
+ Merged file values are pushed into ``os.environ`` so any downstream
134
+ ``os.environ.get(...)`` lookup sees the same view -- without
135
+ overwriting existing process env vars (matches python-dotenv's
136
+ default ``override=False`` semantics).
137
+ """
138
+ root = root or project_root()
139
+ template = root / ".env.template"
140
+ user = root / ".env"
141
+
142
+ if not template.exists():
143
+ raise FileNotFoundError(
144
+ f".env.template not found at {template}. "
145
+ "Reinstall (``npm install -g machinaos``) or restore the template "
146
+ "from the source tree."
147
+ )
148
+
149
+ # Layer: .env.template (canonical defaults) <- .env (user override)
150
+ merged: dict[str, str] = _load_env_file(template)
151
+ merged.update(_load_env_file(user))
152
+
153
+ # Push file values into the process environment so downstream
154
+ # ``os.environ.get(...)`` reads see them. Process env still wins --
155
+ # only keys missing from the process environment are inserted.
156
+ for key, value in merged.items():
157
+ os.environ.setdefault(key, value)
158
+
159
+ # Final view layers process env on top of file env.
160
+ env = {**merged, **os.environ}
161
+
162
+ return Config(
163
+ client_port=_int(env, "VITE_CLIENT_PORT"),
164
+ backend_port=_int(env, "PYTHON_BACKEND_PORT"),
165
+ whatsapp_port=_int(env, "WHATSAPP_RPC_PORT"),
166
+ nodejs_port=_int(env, "NODEJS_EXECUTOR_PORT"),
167
+ temporal_address=_require(env, "TEMPORAL_SERVER_ADDRESS"),
168
+ temporal_enabled=_bool(env, "TEMPORAL_ENABLED"),
169
+ temporal_ui_port=_int(env, "TEMPORAL_UI_PORT"),
170
+ )
@@ -0,0 +1,169 @@
1
+ """Platform / shell / venv detection + canonical path-prefix helpers.
2
+
3
+ All on-disk locations the CLI needs (server tree, the server's uv venv,
4
+ client static script, build-output index, OS-native user dirs) are
5
+ derived from one prefix -- :func:`project_root` -- via the helpers
6
+ below. No callsite composes ``root / "server"`` / ``root / ".venv"``
7
+ inline; every consumer imports the named helper. This keeps layout
8
+ knowledge centralised so a future repo rename / directory relocation
9
+ is a single-file edit.
10
+
11
+ The CLI is **independent of the server's uv environment**: ``machina``
12
+ is installable via pipx / system Python without involving uv, and
13
+ shells out to ``uv run --no-sync ...`` (via :func:`cli.run.uv_run`)
14
+ for any server-side command. :func:`server_venv` exists so build /
15
+ clean / preflight code can check or report that venv's location
16
+ without composing it inline.
17
+
18
+ ``server_venv`` respects uv's documented ``UV_PROJECT_ENVIRONMENT``
19
+ override (https://docs.astral.sh/uv/concepts/projects/config/) so
20
+ power users with non-default venv locations still work.
21
+
22
+ OS-native user dirs (data, cache, config, log) are derived through
23
+ ``platformdirs`` (https://pypi.org/project/platformdirs/) -- the same
24
+ library the server uses for its pooch binary cache -- so the two halves
25
+ of the project agree on per-OS conventions.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import os
31
+ import sys
32
+ from pathlib import Path
33
+
34
+
35
+ IS_WINDOWS = sys.platform == "win32"
36
+ IS_MACOS = sys.platform == "darwin"
37
+ IS_LINUX = sys.platform.startswith("linux")
38
+ IS_WSL = IS_LINUX and ("WSL_DISTRO_NAME" in os.environ or "WSLENV" in os.environ)
39
+ IS_GIT_BASH = IS_WINDOWS and bool(
40
+ os.environ.get("MSYSTEM") or "bash" in (os.environ.get("SHELL") or "")
41
+ )
42
+
43
+
44
+ def platform_name() -> str:
45
+ """Human-readable platform label."""
46
+ if IS_GIT_BASH:
47
+ return "Git Bash"
48
+ if IS_WSL:
49
+ return "WSL"
50
+ if IS_WINDOWS:
51
+ return "Windows"
52
+ if IS_MACOS:
53
+ return "macOS"
54
+ return "Linux"
55
+
56
+
57
+ def project_root() -> Path:
58
+ """Resolve the project root from a module under ``cli/``.
59
+
60
+ Layout: ``<project_root>/cli/<this_file>`` -> parents[1].
61
+ """
62
+ return Path(__file__).resolve().parents[1]
63
+
64
+
65
+ # ---------------------------------------------------------------------------
66
+ # Path-prefix helpers -- canonical layout derived from ``project_root``.
67
+ # ---------------------------------------------------------------------------
68
+
69
+
70
+ def _root(root: Path | None) -> Path:
71
+ return root if root is not None else project_root()
72
+
73
+
74
+ def server_dir(root: Path | None = None) -> Path:
75
+ """The ``server/`` directory -- the Python backend + plugin tree.
76
+ ``server/`` is its own standalone uv project (its ``pyproject.toml``
77
+ declares the dependency closure ``uv sync`` resolves)."""
78
+ return _root(root) / "server"
79
+
80
+
81
+ def server_venv(root: Path | None = None) -> Path:
82
+ """The server's uv-managed project environment directory.
83
+
84
+ ``server/`` is a standalone uv project, so uv places its venv at
85
+ ``server/.venv`` by default per https://docs.astral.sh/uv/concepts/
86
+ projects/layout/. The ``UV_PROJECT_ENVIRONMENT`` env var overrides
87
+ this -- relative overrides resolve against ``server/`` (matching
88
+ uv's own behaviour), absolute paths are used verbatim.
89
+
90
+ The CLI itself does NOT live in this venv; ``machina`` is
91
+ independently installable (pipx / system python). This helper
92
+ exists so build / clean / preflight code can check or report the
93
+ server venv's location without anyone composing the path inline.
94
+ """
95
+ base = server_dir(root)
96
+ override = os.environ.get("UV_PROJECT_ENVIRONMENT")
97
+ if override:
98
+ path = Path(override)
99
+ return path if path.is_absolute() else base / path
100
+ return base / ".venv"
101
+
102
+
103
+ def node_modules_dir(root: Path | None = None) -> Path:
104
+ """The pnpm/npm-installed dependency tree at the workspace root."""
105
+ return _root(root) / "node_modules"
106
+
107
+
108
+ def client_dist_entry(root: Path | None = None) -> Path:
109
+ """The Vite-built client entrypoint -- proof that the client side
110
+ of ``machina build`` completed."""
111
+ return _root(root) / "client" / "dist" / "index.html"
112
+
113
+
114
+ def static_client_script(root: Path | None = None) -> Path:
115
+ """The Node.js static-server script that serves the built client
116
+ (used by ``machina start``)."""
117
+ return _root(root) / "scripts" / "serve-client.js"
118
+
119
+
120
+ # ---------------------------------------------------------------------------
121
+ # OS-native user directories via ``platformdirs``
122
+ # (https://pypi.org/project/platformdirs/). ``platformdirs`` is imported
123
+ # inside each helper, NOT at module level, so the rest of
124
+ # ``cli.platform_`` (path-prefix helpers, project_root, the platform
125
+ # booleans) keeps loading even when the wheel hasn't been installed
126
+ # yet -- the recovery-verb scenario (``machina clean`` against a
127
+ # half-broken env). Callers that actually need a user dir trigger the
128
+ # import on first call; if missing, the natural ``ModuleNotFoundError``
129
+ # surfaces at that callsite, not at every CLI import.
130
+ # ---------------------------------------------------------------------------
131
+
132
+ _APP_NAME = "MachinaOs"
133
+
134
+
135
+ def user_data_dir() -> Path:
136
+ """User data directory.
137
+
138
+ Honours the project's ``DATA_DIR`` env override (see
139
+ ``.env.template``) -- the convention shared with the server's
140
+ ``core.paths.machina_root``. Otherwise delegates to platformdirs.
141
+ """
142
+ override = os.environ.get("DATA_DIR")
143
+ if override:
144
+ return Path(override).expanduser()
145
+ import platformdirs
146
+
147
+ return platformdirs.user_data_path(_APP_NAME, appauthor=_APP_NAME)
148
+
149
+
150
+ def user_cache_dir() -> Path:
151
+ """User cache directory (downloaded binaries / pooch caches).
152
+ Matches ``server/core/paths.py::packages_dir``."""
153
+ import platformdirs
154
+
155
+ return platformdirs.user_cache_path(_APP_NAME, appauthor=_APP_NAME)
156
+
157
+
158
+ def user_config_dir() -> Path:
159
+ """User config directory."""
160
+ import platformdirs
161
+
162
+ return platformdirs.user_config_path(_APP_NAME, appauthor=_APP_NAME)
163
+
164
+
165
+ def user_log_dir() -> Path:
166
+ """User log directory."""
167
+ import platformdirs
168
+
169
+ return platformdirs.user_log_path(_APP_NAME, appauthor=_APP_NAME)