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.
- package/.env.template +74 -5
- package/{workflows/AI Assistant_workflow-1778504793388-ou1m1tz2x.json → .machina/workflows/AI Assistant_example_workflow-1779017037684-e2e5da7a.json } +164 -105
- package/{workflows/AI Employee_example_workflow-1777720598005-u4cm858dv.json → .machina/workflows/AI Employee_example_workflow-1779102911870-cbc76c82.json } +582 -328
- package/{workflows/Claude Assistant_workflow-1778380124051-mdibn807c.json → .machina/workflows/Claude Assistant_example_workflow-1779095939967-2369cff4.json } +152 -83
- package/README.md +5 -2
- package/bin/cli.js +2 -2
- package/{machina → cli}/__main__.py +11 -7
- package/cli/_common.py +122 -0
- package/cli/buildenv.py +40 -0
- package/cli/cli.py +204 -0
- package/{machina → cli}/colors.py +10 -2
- package/cli/commands/__init__.py +1 -0
- package/cli/commands/_temporal_specs.py +59 -0
- package/{machina → cli}/commands/build.py +35 -45
- package/cli/commands/clean.py +141 -0
- package/cli/commands/daemon/__init__.py +47 -0
- package/cli/commands/daemon/_state.py +97 -0
- package/cli/commands/daemon/restart.py +14 -0
- package/cli/commands/daemon/start.py +49 -0
- package/cli/commands/daemon/status.py +20 -0
- package/cli/commands/daemon/stop.py +22 -0
- package/{machina → cli}/commands/dev.py +32 -42
- package/{machina → cli}/commands/docs.py +13 -11
- package/{machina → cli}/commands/start.py +69 -62
- package/{machina → cli}/commands/stop.py +7 -10
- package/{machina → cli}/commands/version.py +12 -6
- package/cli/config.py +170 -0
- package/cli/platform_.py +169 -0
- package/{machina → cli}/ports.py +42 -3
- package/{machina → cli}/run.py +29 -2
- package/{machina → cli}/supervisor.py +29 -12
- package/{machina → cli}/tcp.py +6 -2
- package/{machina → cli}/tree.py +38 -11
- package/client/dist/assets/{ActionBar-Du2MSFSz.js → ActionBar-Cjr3TF7g.js} +1 -1
- package/client/dist/assets/{ApiKeyInput-k2LBmBjb.js → ApiKeyInput-DIJE2PVA.js} +1 -1
- package/client/dist/assets/{ApiKeyPanel-C_bV9U0X.js → ApiKeyPanel-CPmye7uh.js} +1 -1
- package/client/dist/assets/{ApiUsageSection-CmVfwZzL.js → ApiUsageSection-TF_7gH2D.js} +1 -1
- package/client/dist/assets/{EmailPanel-CeKIMGu-.js → EmailPanel-Bs-xvbKR.js} +1 -1
- package/client/dist/assets/{OAuthPanel-KA3t3Q2K.js → OAuthPanel-BDtVJhAV.js} +1 -1
- package/client/dist/assets/{QrPairingPanel-NgNpJNuk.js → QrPairingPanel-BwJehTuZ.js} +1 -1
- package/client/dist/assets/{RateLimitSection-Du5YNVIA.js → RateLimitSection-CfNOoPIS.js} +1 -1
- package/client/dist/assets/{StatusCard-DNLyayXc.js → StatusCard-DkwIrgdP.js} +1 -1
- package/client/dist/assets/index-P2FzntoL.js +165 -0
- package/client/dist/index.html +1 -1
- package/client/package.json +1 -1
- package/client/src/Dashboard.tsx +128 -76
- package/client/src/adapters/nodeSpecToDescription.ts +7 -0
- package/client/src/assets/icons/index.test.ts +10 -0
- package/client/src/assets/icons/index.ts +16 -3
- package/client/src/components/AIAgentNode.tsx +8 -8
- package/client/src/components/ParameterRenderer.tsx +6 -3
- package/client/src/components/SkillEditorModal.tsx +1 -0
- package/client/src/components/credentials/panels/EmailPanel.tsx +2 -0
- package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +2 -0
- package/client/src/components/credentials/sections/RateLimitSection.tsx +1 -0
- package/client/src/components/icons/AIProviderIcons.tsx +1 -0
- package/client/src/components/maps/GoogleMapsPicker.tsx +1 -0
- package/client/src/components/parameterPanel/InputSection.tsx +1 -0
- package/client/src/components/parameterPanel/MasterSkillEditor.tsx +1 -0
- package/client/src/components/parameterPanel/OutputSection.tsx +1 -0
- package/client/src/components/ui/ComponentPalette.tsx +1 -0
- package/client/src/components/ui/MapSelector.tsx +1 -0
- package/client/src/components/ui/NodeContextMenu.tsx +3 -3
- package/client/src/components/ui/SettingsPanel.tsx +1 -0
- package/client/src/components/ui/action-button.tsx +1 -0
- package/client/src/components/ui/badge.tsx +1 -0
- package/client/src/components/ui/button.tsx +1 -0
- package/client/src/components/ui/form.tsx +1 -0
- package/client/src/components/ui/tabs.tsx +1 -0
- package/client/src/contexts/AuthContext.tsx +1 -0
- package/client/src/contexts/ThemeContext.tsx +1 -0
- package/client/src/contexts/WebSocketContext.tsx +104 -34
- package/client/src/hooks/__tests__/useApiKeys.test.ts +2 -2
- package/client/src/hooks/useReactFlowNodes.ts +1 -0
- package/client/src/hooks/useWorkflowValidation.ts +142 -0
- package/client/src/lib/nodeSpec.ts +1 -0
- package/client/src/test/providers.tsx +1 -0
- package/client/src/types/__tests__/cloudEvents.test.ts +5 -2
- package/client/src/types/cloudEvents.ts +19 -7
- package/client/src/utils/nodeUtils.ts +1 -1
- package/client/src/utils/workflow.ts +8 -2
- package/client/src/utils/workflowExport.ts +60 -3
- package/package.json +24 -23
- package/scripts/install.js +16 -27
- package/scripts/migrate_icons.py +3 -1
- package/scripts/migrate_skill_icons.py +6 -7
- package/scripts/postinstall.js +11 -9
- package/server/config/ai_cli_providers.json +2 -3
- package/server/config/credential_providers.json +15 -15
- package/server/config/llm_defaults.json +1 -1
- package/server/config/model_registry.json +416 -611
- package/server/constants.py +285 -223
- package/server/core/__init__.py +1 -1
- package/server/core/cache.py +9 -29
- package/server/core/cleanup.py +12 -24
- package/server/core/config.py +148 -24
- package/server/core/container.py +68 -59
- package/server/core/credential_backends.py +5 -13
- package/server/core/credentials_database.py +13 -43
- package/server/core/database.py +292 -353
- package/server/core/health.py +4 -5
- package/server/core/logging.py +241 -87
- package/server/core/paths.py +285 -0
- package/server/core/tracing.py +2 -8
- package/server/gunicorn.conf.py +1 -0
- package/server/main.py +150 -74
- package/server/middleware/auth.py +18 -24
- package/server/models/__init__.py +1 -1
- package/server/models/auth.py +5 -12
- package/server/models/database.py +36 -68
- package/server/models/node_metadata.py +25 -18
- package/server/nodejs/dist/index.js +107 -0
- package/server/nodes/README.md +11 -5
- package/server/nodes/__init__.py +1 -1
- package/server/nodes/_visuals.py +146 -14
- package/server/nodes/agent/_events.py +124 -0
- package/server/nodes/agent/_handles.py +15 -29
- package/server/nodes/agent/_inline.py +28 -25
- package/server/nodes/agent/_specialized.py +30 -15
- package/server/nodes/agent/{ai_agent.py → ai_agent/__init__.py} +33 -17
- package/server/nodes/agent/ai_agent/meta.json +3 -0
- package/server/nodes/agent/{ai_employee.py → ai_employee/__init__.py} +5 -2
- package/server/nodes/agent/ai_employee/meta.json +3 -0
- package/server/nodes/agent/{android_agent.py → android_agent/__init__.py} +1 -1
- package/server/nodes/agent/android_agent/meta.json +3 -0
- package/server/nodes/agent/{autonomous_agent.py → autonomous_agent/__init__.py} +2 -1
- package/server/nodes/agent/autonomous_agent/meta.json +3 -0
- package/server/nodes/agent/{chat_agent.py → chat_agent/__init__.py} +29 -12
- package/server/nodes/agent/chat_agent/meta.json +3 -0
- package/server/nodes/agent/{claude_code_agent.py → claude_code_agent/__init__.py} +192 -95
- package/server/nodes/agent/claude_code_agent/_handlers.py +169 -0
- package/server/{services/claude_oauth.py → nodes/agent/claude_code_agent/_oauth.py} +26 -13
- package/server/nodes/agent/claude_code_agent/_pool.py +1020 -0
- package/server/nodes/agent/claude_code_agent/_provider.py +513 -0
- package/server/nodes/agent/claude_code_agent/_skills.py +245 -0
- package/server/nodes/agent/claude_code_agent/meta.json +3 -0
- package/server/nodes/agent/{codex_agent.py → codex_agent/__init__.py} +26 -35
- package/server/nodes/agent/codex_agent/meta.json +3 -0
- package/server/nodes/agent/{coding_agent.py → coding_agent/__init__.py} +1 -1
- package/server/nodes/agent/coding_agent/meta.json +3 -0
- package/server/nodes/agent/{consumer_agent.py → consumer_agent/__init__.py} +1 -1
- package/server/nodes/agent/consumer_agent/meta.json +3 -0
- package/server/nodes/agent/{orchestrator_agent.py → orchestrator_agent/__init__.py} +5 -2
- package/server/nodes/agent/orchestrator_agent/meta.json +3 -0
- package/server/nodes/agent/{payments_agent.py → payments_agent/__init__.py} +1 -1
- package/server/nodes/agent/payments_agent/meta.json +3 -0
- package/server/nodes/agent/{productivity_agent.py → productivity_agent/__init__.py} +1 -1
- package/server/nodes/agent/productivity_agent/meta.json +3 -0
- package/server/nodes/agent/{rlm_agent.py → rlm_agent/__init__.py} +18 -17
- package/server/nodes/agent/rlm_agent/meta.json +3 -0
- package/server/nodes/agent/{social_agent.py → social_agent/__init__.py} +1 -1
- package/server/nodes/agent/social_agent/meta.json +3 -0
- package/server/nodes/agent/{task_agent.py → task_agent/__init__.py} +1 -1
- package/server/nodes/agent/task_agent/meta.json +3 -0
- package/server/nodes/agent/{tool_agent.py → tool_agent/__init__.py} +1 -1
- package/server/nodes/agent/tool_agent/meta.json +3 -0
- package/server/nodes/agent/{travel_agent.py → travel_agent/__init__.py} +1 -1
- package/server/nodes/agent/travel_agent/meta.json +3 -0
- package/server/nodes/agent/{web_agent.py → web_agent/__init__.py} +1 -1
- package/server/nodes/agent/web_agent/meta.json +3 -0
- package/server/nodes/android/__init__.py +24 -0
- package/server/nodes/android/_base.py +93 -76
- package/server/nodes/android/_dispatcher.py +140 -223
- package/server/nodes/android/_events.py +154 -0
- package/server/nodes/android/_handlers.py +13 -7
- package/server/nodes/android/_option_loaders.py +1 -4
- package/server/nodes/android/_refresh.py +27 -37
- package/server/nodes/android/_relay/broadcaster.py +25 -41
- package/server/nodes/android/_relay/client.py +23 -42
- package/server/nodes/android/_relay/manager.py +1 -0
- package/server/nodes/android/_relay/protocol.py +6 -0
- package/server/nodes/android/_router.py +48 -133
- package/server/nodes/android/{airplane_mode_control.py → airplane_mode_control/__init__.py} +2 -1
- package/server/nodes/android/airplane_mode_control/meta.json +3 -0
- package/server/nodes/android/{app_launcher.py → app_launcher/__init__.py} +2 -1
- package/server/nodes/android/app_launcher/meta.json +3 -0
- package/server/nodes/android/{app_list.py → app_list/__init__.py} +2 -1
- package/server/nodes/android/app_list/meta.json +3 -0
- package/server/nodes/android/{audio_automation.py → audio_automation/__init__.py} +2 -1
- package/server/nodes/android/audio_automation/meta.json +3 -0
- package/server/nodes/android/{battery_monitor.py → battery_monitor/__init__.py} +2 -1
- package/server/nodes/android/battery_monitor/meta.json +3 -0
- package/server/nodes/android/{bluetooth_automation.py → bluetooth_automation/__init__.py} +2 -1
- package/server/nodes/android/bluetooth_automation/meta.json +3 -0
- package/server/nodes/android/{camera_control.py → camera_control/__init__.py} +2 -1
- package/server/nodes/android/camera_control/meta.json +3 -0
- package/server/nodes/android/{device_state_automation.py → device_state_automation/__init__.py} +2 -1
- package/server/nodes/android/device_state_automation/meta.json +3 -0
- package/server/nodes/android/{environmental_sensors.py → environmental_sensors/__init__.py} +2 -1
- package/server/nodes/android/environmental_sensors/meta.json +3 -0
- package/server/nodes/android/{location.py → location/__init__.py} +2 -1
- package/server/nodes/android/location/meta.json +3 -0
- package/server/nodes/android/{media_control.py → media_control/__init__.py} +2 -1
- package/server/nodes/android/media_control/meta.json +3 -0
- package/server/nodes/android/{motion_detection.py → motion_detection/__init__.py} +2 -1
- package/server/nodes/android/motion_detection/meta.json +3 -0
- package/server/nodes/android/{network_monitor.py → network_monitor/__init__.py} +2 -1
- package/server/nodes/android/network_monitor/meta.json +3 -0
- package/server/nodes/android/{screen_control_automation.py → screen_control_automation/__init__.py} +2 -1
- package/server/nodes/android/screen_control_automation/meta.json +3 -0
- package/server/nodes/android/{system_info.py → system_info/__init__.py} +2 -1
- package/server/nodes/android/system_info/meta.json +3 -0
- package/server/nodes/android/{wifi_automation.py → wifi_automation/__init__.py} +2 -1
- package/server/nodes/android/wifi_automation/meta.json +3 -0
- package/server/nodes/browser/__init__.py +22 -1
- package/server/nodes/browser/_install.py +63 -0
- package/server/nodes/browser/_service.py +21 -25
- package/server/nodes/browser/{browser.py → browser/__init__.py} +58 -25
- package/server/nodes/browser/browser/meta.json +3 -0
- package/server/nodes/chat/{chat_history.py → chat_history/__init__.py} +2 -4
- package/server/nodes/chat/chat_history/meta.json +3 -0
- package/server/nodes/chat/{chat_send.py → chat_send/__init__.py} +2 -4
- package/server/nodes/chat/chat_send/icon.svg +1 -0
- package/server/nodes/chat/chat_send/meta.json +3 -0
- package/server/nodes/code/_base.py +1 -1
- package/server/nodes/code/{javascript_executor.py → javascript_executor/__init__.py} +5 -5
- package/server/nodes/code/javascript_executor/meta.json +3 -0
- package/server/nodes/code/{python_executor.py → python_executor/__init__.py} +32 -14
- package/server/nodes/code/python_executor/meta.json +3 -0
- package/server/nodes/code/{typescript_executor.py → typescript_executor/__init__.py} +5 -5
- package/server/nodes/code/typescript_executor/meta.json +3 -0
- package/server/nodes/document/{document_parser.py → document_parser/__init__.py} +26 -15
- package/server/nodes/document/document_parser/meta.json +3 -0
- package/server/nodes/document/{embedding_generator.py → embedding_generator/__init__.py} +16 -9
- package/server/nodes/document/embedding_generator/meta.json +3 -0
- package/server/nodes/document/{file_downloader.py → file_downloader/__init__.py} +30 -20
- package/server/nodes/document/file_downloader/meta.json +3 -0
- package/server/nodes/document/{http_scraper.py → http_scraper/__init__.py} +31 -21
- package/server/nodes/document/http_scraper/meta.json +3 -0
- package/server/nodes/document/{text_chunker.py → text_chunker/__init__.py} +17 -12
- package/server/nodes/document/text_chunker/meta.json +3 -0
- package/server/nodes/document/{vector_store.py → vector_store/__init__.py} +88 -72
- package/server/nodes/document/vector_store/meta.json +3 -0
- package/server/nodes/email/__init__.py +9 -2
- package/server/nodes/email/_events.py +54 -0
- package/server/nodes/email/_filters.py +3 -3
- package/server/nodes/email/_himalaya.py +95 -50
- package/server/nodes/email/_service.py +23 -13
- package/server/nodes/email/{email_read.py → email_read/__init__.py} +23 -11
- package/server/nodes/email/email_read/icon.svg +6 -0
- package/server/nodes/email/email_read/meta.json +3 -0
- package/server/nodes/email/{email_receive.py → email_receive/__init__.py} +45 -23
- package/server/nodes/email/email_receive/meta.json +3 -0
- package/server/nodes/email/{email_send.py → email_send/__init__.py} +13 -7
- package/server/nodes/email/email_send/meta.json +3 -0
- package/server/nodes/filesystem/_backend.py +1 -5
- package/server/nodes/filesystem/{file_modify.py → file_modify/__init__.py} +10 -5
- package/server/nodes/filesystem/file_modify/meta.json +3 -0
- package/server/nodes/filesystem/{file_read.py → file_read/__init__.py} +7 -3
- package/server/nodes/filesystem/file_read/meta.json +3 -0
- package/server/nodes/filesystem/{fs_search.py → fs_search/__init__.py} +11 -3
- package/server/nodes/filesystem/fs_search/meta.json +3 -0
- package/server/nodes/filesystem/{shell.py → shell/__init__.py} +12 -5
- package/server/nodes/filesystem/shell/meta.json +3 -0
- package/server/nodes/google/__init__.py +12 -0
- package/server/nodes/google/_auth_helper.py +7 -13
- package/server/nodes/google/_base.py +14 -11
- package/server/nodes/google/_credentials.py +2 -1
- package/server/nodes/google/_events.py +47 -0
- package/server/nodes/google/_filters.py +3 -3
- package/server/nodes/google/_gmail.py +70 -47
- package/server/nodes/google/_handlers.py +3 -1
- package/server/nodes/google/_oauth.py +25 -11
- package/server/nodes/google/_option_loaders.py +9 -30
- package/server/nodes/google/_refresh.py +8 -12
- package/server/nodes/google/_router.py +4 -5
- package/server/nodes/google/{calendar.py → calendar/__init__.py} +87 -64
- package/server/nodes/google/calendar/meta.json +3 -0
- package/server/nodes/google/{contacts.py → contacts/__init__.py} +84 -72
- package/server/nodes/google/contacts/meta.json +3 -0
- package/server/nodes/google/{drive.py → drive/__init__.py} +87 -72
- package/server/nodes/google/drive/meta.json +3 -0
- package/server/nodes/google/{gmail.py → gmail/__init__.py} +73 -39
- package/server/nodes/google/gmail/meta.json +3 -0
- package/server/nodes/google/{gmail_receive.py → gmail_receive/__init__.py} +31 -24
- package/server/nodes/google/gmail_receive/icon.svg +7 -0
- package/server/nodes/google/gmail_receive/meta.json +3 -0
- package/server/nodes/google/google.svg +7 -0
- package/server/nodes/google/{sheets.py → sheets/__init__.py} +54 -42
- package/server/nodes/google/sheets/meta.json +3 -0
- package/server/nodes/google/{tasks.py → tasks/__init__.py} +56 -43
- package/server/nodes/google/tasks/meta.json +3 -0
- package/server/nodes/groups.py +28 -28
- package/server/nodes/location/__init__.py +31 -1
- package/server/nodes/location/_credentials.py +1 -6
- package/server/nodes/location/_service.py +88 -107
- package/server/nodes/location/{gmaps_create.py → gmaps_create/__init__.py} +6 -6
- package/server/nodes/location/gmaps_create/meta.json +3 -0
- package/server/nodes/location/{gmaps_locations.py → gmaps_locations/__init__.py} +8 -6
- package/server/nodes/location/gmaps_locations/meta.json +3 -0
- package/server/nodes/location/{gmaps_nearby_places.py → gmaps_nearby_places/__init__.py} +8 -6
- package/server/nodes/location/gmaps_nearby_places/meta.json +3 -0
- package/server/nodes/model/_base.py +10 -7
- package/server/nodes/model/_credentials.py +10 -10
- package/server/nodes/model/_local_validator.py +28 -24
- package/server/nodes/model/{anthropic_chat_model.py → anthropic_chat_model/__init__.py} +5 -3
- package/server/nodes/model/anthropic_chat_model/meta.json +3 -0
- package/server/nodes/model/{cerebras_chat_model.py → cerebras_chat_model/__init__.py} +5 -3
- package/server/nodes/model/cerebras_chat_model/meta.json +3 -0
- package/server/nodes/model/{deepseek_chat_model.py → deepseek_chat_model/__init__.py} +8 -4
- package/server/nodes/model/deepseek_chat_model/meta.json +3 -0
- package/server/nodes/model/{gemini_chat_model.py → gemini_chat_model/__init__.py} +5 -3
- package/server/nodes/model/gemini_chat_model/meta.json +3 -0
- package/server/nodes/model/{groq_chat_model.py → groq_chat_model/__init__.py} +2 -2
- package/server/nodes/model/groq_chat_model/meta.json +3 -0
- package/server/nodes/model/{kimi_chat_model.py → kimi_chat_model/__init__.py} +2 -2
- package/server/nodes/model/kimi_chat_model/meta.json +3 -0
- package/server/nodes/model/{lmstudio_chat_model.py → lmstudio_chat_model/__init__.py} +2 -2
- package/server/nodes/model/lmstudio_chat_model/meta.json +3 -0
- package/server/nodes/model/{mistral_chat_model.py → mistral_chat_model/__init__.py} +2 -2
- package/server/nodes/model/mistral_chat_model/meta.json +3 -0
- package/server/nodes/model/{ollama_chat_model.py → ollama_chat_model/__init__.py} +2 -2
- package/server/nodes/model/ollama_chat_model/meta.json +3 -0
- package/server/nodes/model/{openai_chat_model.py → openai_chat_model/__init__.py} +8 -4
- package/server/nodes/model/openai_chat_model/meta.json +3 -0
- package/server/nodes/model/{openrouter_chat_model.py → openrouter_chat_model/__init__.py} +8 -4
- package/server/nodes/model/openrouter_chat_model/meta.json +3 -0
- package/server/nodes/proxy/_usage.py +14 -15
- package/server/nodes/proxy/{proxy_config.py → proxy_config/__init__.py} +39 -30
- package/server/nodes/proxy/proxy_config/meta.json +3 -0
- package/server/nodes/proxy/{proxy_request.py → proxy_request/__init__.py} +30 -16
- package/server/nodes/proxy/proxy_request/meta.json +3 -0
- package/server/nodes/proxy/{proxy_status.py → proxy_status/__init__.py} +2 -0
- package/server/nodes/proxy/proxy_status/meta.json +3 -0
- package/server/nodes/scheduler/{cron_scheduler.py → cron_scheduler/__init__.py} +96 -23
- package/server/nodes/scheduler/cron_scheduler/_workflow.py +155 -0
- package/server/nodes/scheduler/cron_scheduler/meta.json +3 -0
- package/server/nodes/scheduler/{timer.py → timer/__init__.py} +6 -5
- package/server/nodes/scheduler/timer/meta.json +3 -0
- package/server/nodes/scraper/_credentials.py +0 -1
- package/server/nodes/scraper/{apify_actor.py → apify_actor/__init__.py} +44 -35
- package/server/nodes/scraper/apify_actor/icon.svg +5 -0
- package/server/nodes/scraper/apify_actor/meta.json +3 -0
- package/server/nodes/scraper/{crawlee_scraper.py → crawlee_scraper/__init__.py} +96 -57
- package/server/nodes/scraper/crawlee_scraper/meta.json +3 -0
- package/server/nodes/search/{brave_search.py → brave_search/__init__.py} +6 -5
- package/server/nodes/search/brave_search/icon.svg +3 -0
- package/server/nodes/search/brave_search/meta.json +3 -0
- package/server/nodes/search/{duckduckgo_search.py → duckduckgo_search/__init__.py} +17 -6
- package/server/nodes/search/duckduckgo_search/meta.json +3 -0
- package/server/nodes/search/{perplexity_search.py → perplexity_search/__init__.py} +4 -5
- package/server/nodes/search/perplexity_search/icon.svg +3 -0
- package/server/nodes/search/perplexity_search/meta.json +3 -0
- package/server/nodes/search/{serper_search.py → serper_search/__init__.py} +32 -25
- package/server/nodes/search/serper_search/icon.svg +3 -0
- package/server/nodes/search/serper_search/meta.json +3 -0
- package/server/nodes/skill/__init__.py +21 -1
- package/server/nodes/skill/_expander.py +75 -0
- package/server/nodes/skill/{master_skill.py → master_skill/__init__.py} +2 -8
- package/server/nodes/skill/master_skill/_events.py +84 -0
- package/server/nodes/skill/master_skill/meta.json +3 -0
- package/server/nodes/skill/{simple_memory.py → simple_memory/__init__.py} +8 -16
- package/server/nodes/skill/simple_memory/meta.json +3 -0
- package/server/nodes/social/_base.py +223 -231
- package/server/nodes/social/{social_receive.py → social_receive/__init__.py} +38 -13
- package/server/nodes/social/social_receive/meta.json +3 -0
- package/server/nodes/social/{social_send.py → social_send/__init__.py} +71 -29
- package/server/nodes/social/social_send/icon.svg +1 -0
- package/server/nodes/social/social_send/meta.json +3 -0
- package/server/nodes/stripe/__init__.py +7 -3
- package/server/nodes/stripe/_credentials.py +0 -1
- package/server/nodes/stripe/_handlers.py +18 -7
- package/server/nodes/stripe/_install.py +14 -15
- package/server/nodes/stripe/_source.py +5 -5
- package/server/nodes/stripe/icon.svg +1 -0
- package/server/nodes/stripe/meta.json +3 -0
- package/server/nodes/stripe/stripe_action.py +4 -4
- package/server/nodes/stripe/stripe_receive.py +6 -9
- package/server/nodes/telegram/__init__.py +13 -0
- package/server/nodes/telegram/_credentials.py +2 -7
- package/server/nodes/telegram/_events.py +167 -0
- package/server/nodes/telegram/_filters.py +3 -11
- package/server/nodes/telegram/_handlers.py +17 -7
- package/server/nodes/telegram/_refresh.py +24 -34
- package/server/nodes/telegram/_service.py +29 -45
- package/server/nodes/telegram/meta.json +3 -0
- package/server/nodes/telegram/telegram.svg +3 -0
- package/server/nodes/telegram/telegram_receive.py +38 -18
- package/server/nodes/telegram/telegram_send.py +21 -19
- package/server/nodes/text/{file_handler.py → file_handler/__init__.py} +7 -1
- package/server/nodes/text/file_handler/meta.json +3 -0
- package/server/nodes/text/{text_generator.py → text_generator/__init__.py} +2 -1
- package/server/nodes/text/text_generator/meta.json +3 -0
- package/server/nodes/tool/{agent_builder.py → agent_builder/__init__.py} +105 -100
- package/server/nodes/tool/agent_builder/_events.py +91 -0
- package/server/nodes/tool/agent_builder/meta.json +3 -0
- package/server/nodes/tool/{calculator_tool.py → calculator_tool/__init__.py} +19 -7
- package/server/nodes/tool/calculator_tool/meta.json +3 -0
- package/server/nodes/tool/{current_time_tool.py → current_time_tool/__init__.py} +6 -4
- package/server/nodes/tool/current_time_tool/meta.json +3 -0
- package/server/nodes/tool/{task_manager.py → task_manager/__init__.py} +17 -18
- package/server/nodes/tool/task_manager/meta.json +3 -0
- package/server/nodes/tool/{write_todos.py → write_todos/__init__.py} +20 -6
- package/server/nodes/tool/write_todos/meta.json +3 -0
- package/server/nodes/trigger/{chat_trigger.py → chat_trigger/__init__.py} +11 -7
- package/server/nodes/trigger/chat_trigger/_events.py +53 -0
- package/server/nodes/trigger/chat_trigger/meta.json +3 -0
- package/server/nodes/trigger/{task_trigger.py → task_trigger/__init__.py} +10 -7
- package/server/nodes/trigger/task_trigger/meta.json +3 -0
- package/server/nodes/trigger/{webhook_trigger.py → webhook_trigger/__init__.py} +10 -7
- package/server/nodes/trigger/webhook_trigger/_events.py +54 -0
- package/server/nodes/trigger/webhook_trigger/meta.json +3 -0
- package/server/nodes/twitter/__init__.py +7 -1
- package/server/nodes/twitter/_base.py +86 -61
- package/server/nodes/twitter/_credentials.py +7 -5
- package/server/nodes/twitter/_events.py +101 -0
- package/server/nodes/twitter/_filters.py +9 -9
- package/server/nodes/twitter/_handlers.py +3 -1
- package/server/nodes/twitter/_oauth.py +1 -2
- package/server/nodes/twitter/_refresh.py +8 -12
- package/server/nodes/twitter/{twitter_receive.py → twitter_receive/__init__.py} +7 -7
- package/server/nodes/twitter/twitter_receive/icon.svg +1 -0
- package/server/nodes/twitter/twitter_receive/meta.json +3 -0
- package/server/nodes/twitter/{twitter_search.py → twitter_search/__init__.py} +16 -11
- package/server/nodes/twitter/twitter_search/icon.svg +1 -0
- package/server/nodes/twitter/twitter_search/meta.json +3 -0
- package/server/nodes/twitter/{twitter_send.py → twitter_send/__init__.py} +60 -27
- package/server/nodes/twitter/twitter_send/icon.svg +1 -0
- package/server/nodes/twitter/twitter_send/meta.json +3 -0
- package/server/nodes/twitter/{twitter_user.py → twitter_user/__init__.py} +34 -19
- package/server/nodes/twitter/twitter_user/icon.svg +1 -0
- package/server/nodes/twitter/twitter_user/meta.json +3 -0
- package/server/nodes/utility/{console.py → console/__init__.py} +17 -22
- package/server/nodes/utility/console/meta.json +3 -0
- package/server/nodes/utility/{http_request.py → http_request/__init__.py} +9 -6
- package/server/nodes/utility/http_request/meta.json +3 -0
- package/server/nodes/utility/{process_manager.py → process_manager/__init__.py} +10 -6
- package/server/nodes/utility/process_manager/meta.json +3 -0
- package/server/nodes/utility/team_monitor/meta.json +3 -0
- package/server/nodes/utility/{webhook_response.py → webhook_response/__init__.py} +12 -7
- package/server/nodes/utility/webhook_response/meta.json +3 -0
- package/server/nodes/visuals.json +69 -251
- package/server/nodes/whatsapp/__init__.py +24 -0
- package/server/nodes/whatsapp/_base.py +283 -338
- package/server/nodes/whatsapp/_credentials.py +44 -0
- package/server/nodes/whatsapp/_events.py +277 -0
- package/server/nodes/whatsapp/_filters.py +36 -37
- package/server/nodes/whatsapp/_handlers.py +2 -0
- package/server/nodes/whatsapp/_option_loaders.py +1 -3
- package/server/nodes/whatsapp/_refresh.py +13 -18
- package/server/nodes/whatsapp/_runtime.py +9 -6
- package/server/nodes/whatsapp/_service.py +89 -152
- package/server/nodes/whatsapp/meta.json +3 -0
- package/server/nodes/whatsapp/whatsapp_db.py +116 -54
- package/server/nodes/whatsapp/whatsapp_receive.py +30 -13
- package/server/nodes/whatsapp/whatsapp_send.py +60 -37
- package/server/nodes/workflow/{start.py → start/__init__.py} +1 -4
- package/server/nodes/workflow/start/meta.json +3 -0
- package/server/package-lock.json +3 -3
- package/server/package.json +3 -0
- package/server/pyproject.toml +39 -10
- package/server/requirements.txt +3 -5
- package/server/routers/__init__.py +1 -1
- package/server/routers/auth.py +16 -56
- package/server/routers/database.py +27 -50
- package/server/routers/nodejs_compat.py +25 -87
- package/server/routers/schemas.py +66 -2
- package/server/routers/webhook.py +12 -12
- package/server/routers/websocket.py +312 -1716
- package/server/routers/workflow.py +28 -53
- package/server/scripts/smoke_test_skills.py +178 -0
- package/server/services/__init__.py +1 -1
- package/server/services/_supervisor/process.py +9 -3
- package/server/services/_supervisor/registry.py +3 -3
- package/server/services/_supervisor/util.py +1 -1
- package/server/services/agent_team.py +15 -43
- package/server/services/agent_teams/__init__.py +17 -0
- package/server/services/agent_teams/handlers.py +195 -0
- package/server/services/ai.py +853 -1108
- package/server/services/auth.py +10 -34
- package/server/services/chat_client.py +5 -34
- package/server/services/circuit_breaker.py +2 -6
- package/server/services/cli_agent/__init__.py +28 -4
- package/server/services/cli_agent/_cli_auth.py +61 -0
- package/server/services/cli_agent/_handlers.py +24 -183
- package/server/services/cli_agent/config.py +5 -8
- package/server/services/cli_agent/factory.py +168 -22
- package/server/services/cli_agent/jsonl_watcher.py +380 -0
- package/server/services/cli_agent/lockfile.py +9 -2
- package/server/services/cli_agent/mcp_server.py +110 -34
- package/server/services/cli_agent/protocol.py +37 -19
- package/server/services/cli_agent/providers/__init__.py +8 -4
- package/server/services/cli_agent/providers/google_gemini.py +11 -5
- package/server/services/cli_agent/providers/openai_codex.py +34 -34
- package/server/services/cli_agent/service.py +245 -83
- package/server/services/cli_agent/session.py +409 -229
- package/server/services/cli_agent/transports/__init__.py +47 -0
- package/server/services/cli_agent/transports/base.py +111 -0
- package/server/services/cli_agent/transports/posix.py +196 -0
- package/server/services/cli_agent/transports/windows.py +189 -0
- package/server/services/cli_agent/types.py +45 -18
- package/server/services/cli_agent/workflow_tools.py +28 -15
- package/server/services/compaction.py +68 -52
- package/server/services/credential_registry.py +6 -20
- package/server/services/credentials/__init__.py +18 -0
- package/server/services/credentials/handlers.py +196 -0
- package/server/services/deployment/__init__.py +12 -1
- package/server/services/deployment/canary_registry.py +137 -0
- package/server/services/deployment/handlers.py +382 -0
- package/server/services/deployment/manager.py +653 -163
- package/server/services/deployment/poll_registry.py +2 -6
- package/server/services/deployment/state.py +2 -0
- package/server/services/deployment/triggers.py +87 -93
- package/server/services/event_waiter.py +47 -54
- package/server/services/events/__init__.py +11 -0
- package/server/services/events/admin_handlers.py +368 -0
- package/server/services/events/daemon.py +3 -1
- package/server/services/events/dispatch.py +188 -0
- package/server/services/events/envelope.py +264 -45
- package/server/services/events/oauth_lifecycle.py +98 -42
- package/server/services/events/triggers.py +3 -13
- package/server/services/events/verifiers/hmac_basic.py +1 -1
- package/server/services/events/verifiers/standard_webhooks.py +2 -4
- package/server/services/events/webhook.py +2 -3
- package/server/services/example_loader.py +73 -15
- package/server/services/execution/cache.py +36 -76
- package/server/services/execution/conditions.py +7 -20
- package/server/services/execution/dlq.py +20 -24
- package/server/services/execution/executor.py +234 -265
- package/server/services/execution/models.py +40 -46
- package/server/services/execution/recovery.py +23 -46
- package/server/services/handlers/__init__.py +12 -16
- package/server/services/handlers/todo.py +3 -6
- package/server/services/handlers/tools.py +143 -194
- package/server/services/handlers/triggers.py +24 -23
- package/server/services/llm/config.py +10 -1
- package/server/services/llm/factory.py +16 -4
- package/server/services/llm/messages.py +1 -5
- package/server/services/llm/protocol.py +9 -1
- package/server/services/llm/providers/anthropic.py +23 -12
- package/server/services/llm/providers/gemini.py +43 -22
- package/server/services/llm/providers/openai.py +14 -6
- package/server/services/llm/providers/openrouter.py +6 -1
- package/server/services/markdown_formatter.py +1 -2
- package/server/services/memory/__init__.py +2 -2
- package/server/services/memory/jsonl.py +6 -2
- package/server/services/memory/markdown.py +6 -6
- package/server/services/memory/state.py +6 -5
- package/server/services/memory_store.py +8 -12
- package/server/services/model_registry.py +22 -20
- package/server/services/node_executor.py +85 -80
- package/server/services/node_output_schemas.py +4 -7
- package/server/services/node_registry.py +40 -4
- package/server/services/node_spec.py +3 -7
- package/server/services/nodejs_client.py +4 -14
- package/server/services/oauth_utils.py +11 -7
- package/server/services/parameter_resolver.py +30 -36
- package/server/services/plugin/base.py +321 -38
- package/server/services/plugin/connection.py +12 -7
- package/server/services/plugin/credential.py +80 -22
- package/server/services/plugin/edge_walker.py +128 -105
- package/server/services/plugin/identifiers.py +48 -0
- package/server/services/plugin/interceptor.py +1 -1
- package/server/services/plugin/oauth.py +25 -21
- package/server/services/plugin/operation.py +1 -1
- package/server/services/plugin/polling.py +151 -26
- package/server/services/plugin/registry.py +52 -4
- package/server/services/plugin/routing.py +6 -9
- package/server/services/plugin/scaling.py +36 -18
- package/server/services/plugin/service_factories.py +95 -0
- package/server/services/plugin/shutdown_hooks.py +103 -0
- package/server/services/plugin/social_provider_registry.py +80 -0
- package/server/services/plugin/ws.py +2 -1
- package/server/services/pricing.py +26 -40
- package/server/services/pricing_handlers.py +90 -0
- package/server/services/process_service.py +33 -32
- package/server/services/proxy/models.py +15 -9
- package/server/services/proxy/service.py +26 -40
- package/server/services/rlm/adapters.py +43 -40
- package/server/services/rlm/constants.py +9 -9
- package/server/services/rlm/service.py +57 -45
- package/server/services/scheduler.py +8 -39
- package/server/services/settings/__init__.py +16 -0
- package/server/services/settings/handlers.py +275 -0
- package/server/services/skill_loader.py +53 -45
- package/server/services/skill_prompt.py +8 -6
- package/server/services/skills/__init__.py +23 -0
- package/server/services/skills/handlers.py +479 -0
- package/server/services/status_broadcaster.py +314 -291
- package/server/services/temporal/__init__.py +22 -1
- package/server/services/temporal/_handlers.py +65 -0
- package/server/services/temporal/_install.py +158 -0
- package/server/services/temporal/_refresh.py +57 -0
- package/server/services/temporal/_retry_policies.py +85 -0
- package/server/services/temporal/_runtime.py +181 -0
- package/server/services/temporal/_supervised_runtime.py +102 -0
- package/server/services/temporal/activities.py +168 -11
- package/server/services/temporal/agent_activities.py +683 -0
- package/server/services/temporal/agent_workflow.py +601 -0
- package/server/services/temporal/client.py +58 -13
- package/server/services/temporal/executor.py +2 -3
- package/server/services/temporal/plugin_activities.py +37 -2
- package/server/services/temporal/plugin_registry.py +82 -0
- package/server/services/temporal/polling_trigger_workflow.py +267 -0
- package/server/services/temporal/schedules.py +220 -0
- package/server/services/temporal/search_attributes.py +177 -0
- package/server/services/temporal/trigger_listener_workflow.py +378 -0
- package/server/services/temporal/worker.py +111 -18
- package/server/services/temporal/workflow.py +259 -40
- package/server/services/temporal/ws_client.py +22 -11
- package/server/services/text.py +14 -28
- package/server/services/tracked_http.py +29 -49
- package/server/services/user_auth.py +7 -21
- package/server/services/workflow.py +28 -20
- package/server/services/workflow_import.py +351 -0
- package/server/services/workflow_ops.py +4 -0
- package/server/services/workflow_storage/__init__.py +18 -0
- package/server/services/workflow_storage/handlers.py +132 -0
- package/server/services/workflow_validator.py +209 -0
- package/server/services/ws_handler_registry.py +80 -9
- package/server/skills/assistant/agent-builder-skill/SKILL.md +6 -6
- package/server/tests/conftest.py +54 -3
- package/server/tests/credentials/test_auth_service.py +9 -21
- package/server/tests/credentials/test_credential_broadcasts.py +116 -22
- package/server/tests/credentials/test_credentials_database.py +12 -38
- package/server/tests/credentials/test_encryption.py +3 -9
- package/server/tests/credentials/test_google_oauth.py +1 -3
- package/server/tests/credentials/test_oauth_utils.py +31 -38
- package/server/tests/credentials/test_twitter_oauth.py +1 -3
- package/server/tests/credentials/test_websocket_handlers.py +37 -72
- package/server/tests/fixtures/tool_names_snapshot.json +78 -0
- package/server/tests/llm/test_factory.py +12 -4
- package/server/tests/llm/test_providers.py +25 -32
- package/server/tests/llm/test_wiring.py +27 -22
- package/server/tests/nodes/_compat.py +4 -5
- package/server/tests/nodes/_harness.py +31 -24
- package/server/tests/nodes/_mocks.py +2 -6
- package/server/tests/nodes/test_agent_builder.py +43 -35
- package/server/tests/nodes/test_ai_agents.py +29 -24
- package/server/tests/nodes/test_ai_chat_models.py +3 -9
- package/server/tests/nodes/test_ai_tools.py +29 -24
- package/server/tests/nodes/test_android.py +34 -64
- package/server/tests/nodes/test_chat_utility.py +2 -2
- package/server/tests/nodes/test_code_fs_process.py +26 -84
- package/server/tests/nodes/test_document.py +23 -47
- package/server/tests/nodes/test_email.py +88 -51
- package/server/tests/nodes/test_google_workspace.py +26 -20
- package/server/tests/nodes/test_http_proxy.py +43 -89
- package/server/tests/nodes/test_search.py +3 -9
- package/server/tests/nodes/test_specialized_agents.py +58 -162
- package/server/tests/nodes/test_stripe_plugin.py +25 -5
- package/server/tests/nodes/test_telegram_social.py +33 -37
- package/server/tests/nodes/test_twitter.py +59 -150
- package/server/tests/nodes/test_web_automation.py +21 -51
- package/server/tests/nodes/test_whatsapp.py +13 -19
- package/server/tests/nodes/test_workflow_triggers.py +16 -45
- package/server/tests/services/cli_agent/test_claude_session_events.py +201 -0
- package/server/tests/services/cli_agent/test_jsonl_watcher.py +190 -0
- package/server/tests/services/cli_agent/test_mcp_server.py +67 -29
- package/server/tests/services/cli_agent/test_providers.py +236 -47
- package/server/tests/services/cli_agent/test_service.py +9 -7
- package/server/tests/services/memory/test_jsonl.py +30 -25
- package/server/tests/services/test_events.py +26 -7
- package/server/tests/services/test_identifiers.py +122 -0
- package/server/tests/services/test_process_lifecycle.py +129 -0
- package/server/tests/services/test_supervisor.py +0 -1
- package/server/tests/temporal/__init__.py +0 -0
- package/server/tests/temporal/test_agent_workflow.py +215 -0
- package/server/tests/temporal/test_dispatch.py +231 -0
- package/server/tests/test_admin_handlers.py +394 -0
- package/server/tests/test_auto_skill.py +4 -2
- package/server/tests/test_canary_registry.py +310 -0
- package/server/tests/test_chat_trigger_canary_producer.py +101 -0
- package/server/tests/test_cloudevents_node_parameters.py +129 -0
- package/server/tests/test_credential_icon.py +115 -0
- package/server/tests/test_cron_canary.py +511 -0
- package/server/tests/test_deployment_canary_listener.py +692 -0
- package/server/tests/test_event_framework_phase_a.py +537 -0
- package/server/tests/test_no_raw_prints.py +131 -0
- package/server/tests/test_node_spec.py +196 -103
- package/server/tests/test_parameter_resolver.py +20 -20
- package/server/tests/test_plugin_contract.py +76 -49
- package/server/tests/test_plugin_helpers.py +0 -1
- package/server/tests/test_plugin_self_containment.py +40 -47
- package/server/tests/test_polling_trigger_workflow.py +572 -0
- package/server/tests/test_retry_policies.py +146 -0
- package/server/tests/test_service_factories.py +168 -0
- package/server/tests/test_shutdown_hooks.py +199 -0
- package/server/tests/test_social_provider_registry.py +177 -0
- package/server/tests/test_status_broadcasts.py +214 -63
- package/server/tests/test_task_trigger_canary_producer.py +131 -0
- package/server/tests/test_telegram_trigger_canary_producer.py +113 -0
- package/server/tests/test_tool_registry.py +110 -0
- package/server/tests/test_trigger_listener_workflow.py +365 -0
- package/server/tests/test_whatsapp_trigger_canary_producer.py +164 -0
- package/server/tests/test_workflow_ops.py +1 -3
- package/server/tests/test_workflow_validator.py +791 -0
- package/server/uv.lock +3539 -0
- package/client/dist/assets/index-DQ0nwhec.js +0 -257
- package/client/src/assets/icons/apify/index.ts +0 -19
- package/client/src/assets/icons/browser/index.ts +0 -17
- package/client/src/assets/icons/email/index.ts +0 -22
- package/client/src/assets/icons/google/index.ts +0 -34
- package/client/src/assets/icons/llm/deepseek.svg +0 -1
- package/client/src/assets/icons/llm/index.ts +0 -18
- package/client/src/assets/icons/llm/kimi.svg +0 -1
- package/client/src/assets/icons/llm/mistral.svg +0 -1
- package/client/src/assets/icons/search/index.ts +0 -28
- package/client/src/assets/icons/telegram/index.ts +0 -19
- package/machina/buildenv.py +0 -44
- package/machina/cli.py +0 -55
- package/machina/commands/__init__.py +0 -1
- package/machina/commands/clean.py +0 -80
- package/machina/commands/daemon.py +0 -150
- package/machina/config.py +0 -93
- package/machina/platform_.py +0 -37
- package/machina/pyproject.toml +0 -33
- package/server/nodes/agent/deep_agent.py +0 -103
- package/server/services/agents/__init__.py +0 -9
- package/server/services/agents/adapters.py +0 -199
- package/server/services/agents/constants.py +0 -10
- package/server/services/agents/service.py +0 -297
- package/server/services/cli_agent/providers/anthropic_claude.py +0 -419
- /package/{machina → cli}/README.md +0 -0
- /package/{machina → cli}/__init__.py +0 -0
- /package/{client/src/assets/icons/apify → server/credentials/icons}/apify.svg +0 -0
- /package/{client/src/assets/icons/search/brave.svg → server/credentials/icons/brave_search.svg} +0 -0
- /package/{client/src/assets/icons/email/read.svg → server/credentials/icons/email_himalaya.svg} +0 -0
- /package/{client/src/assets/icons/search → server/credentials/icons}/perplexity.svg +0 -0
- /package/{client/src/assets/icons/search/google.svg → server/credentials/icons/serper.svg} +0 -0
- /package/{client/src/assets → server/credentials}/icons/stripe.svg +0 -0
- /package/{client/src/assets/icons/twitter/x.svg → server/credentials/icons/twitter.svg} +0 -0
- /package/{client/src/assets/icons/browser/chrome.svg → server/nodes/browser/browser/icon.svg} +0 -0
- /package/{client/src/assets/icons/chat/chat.svg → server/nodes/chat/chat_history/icon.svg} +0 -0
- /package/{client/src/assets/icons/code/javascript.svg → server/nodes/code/javascript_executor/icon.svg} +0 -0
- /package/{client/src/assets/icons/code/python.svg → server/nodes/code/python_executor/icon.svg} +0 -0
- /package/{client/src/assets/icons/code/typescript.svg → server/nodes/code/typescript_executor/icon.svg} +0 -0
- /package/{client/src/assets/icons/email/receive.svg → server/nodes/email/email_receive/icon.svg} +0 -0
- /package/{client/src/assets/icons/email/send.svg → server/nodes/email/email_send/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/calendar.svg → server/nodes/google/calendar/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/contacts.svg → server/nodes/google/contacts/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/drive.svg → server/nodes/google/drive/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/gmail.svg → server/nodes/google/gmail/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/sheets.svg → server/nodes/google/sheets/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/tasks.svg → server/nodes/google/tasks/icon.svg} +0 -0
- /package/{client/src/assets/icons/search/duckduckgo.svg → server/nodes/search/duckduckgo_search/icon.svg} +0 -0
- /package/{client/src/assets/icons/social/social.svg → server/nodes/social/social_receive/icon.svg} +0 -0
- /package/{client/src/assets/icons/telegram/telegram.svg → server/nodes/telegram/icon.svg} +0 -0
- /package/server/nodes/utility/{team_monitor.py → team_monitor/__init__.py} +0 -0
- /package/{client/src/assets/icons/whatsapp/whatsapp-db.svg → server/nodes/whatsapp/icon_whatsappDb.svg} +0 -0
- /package/{client/src/assets/icons/whatsapp/whatsapp-receive.svg → server/nodes/whatsapp/icon_whatsappReceive.svg} +0 -0
- /package/{client/src/assets/icons/whatsapp/whatsapp-send.svg → server/nodes/whatsapp/icon_whatsappSend.svg} +0 -0
- /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
|
|
25
|
-
from
|
|
26
|
-
from
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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(
|
|
133
|
+
argv=["node", str(static_client_script(root))],
|
|
113
134
|
cwd=root,
|
|
114
135
|
ready_port=cfg.client_port,
|
|
115
136
|
),
|
|
116
|
-
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
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 =
|
|
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(
|
|
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
|
|
17
|
-
from
|
|
18
|
-
from
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
+
)
|
package/cli/platform_.py
ADDED
|
@@ -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)
|