machinaos 0.0.76 → 0.0.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -107
- package/client/dist/assets/ActionBar-Du2MSFSz.js +1 -0
- package/client/dist/assets/ApiKeyInput-k2LBmBjb.js +1 -0
- package/client/dist/assets/ApiKeyPanel-C_bV9U0X.js +1 -0
- package/client/dist/assets/ApiUsageSection-CmVfwZzL.js +1 -0
- package/client/dist/assets/EmailPanel-CeKIMGu-.js +1 -0
- package/client/dist/assets/OAuthPanel-KA3t3Q2K.js +1 -0
- package/client/dist/assets/QrPairingPanel-NgNpJNuk.js +1 -0
- package/client/dist/assets/RateLimitSection-Du5YNVIA.js +1 -0
- package/client/dist/assets/StatusCard-DNLyayXc.js +1 -0
- package/client/dist/assets/index-DQ0nwhec.js +257 -0
- package/client/dist/assets/index-DxmbVskS.css +1 -0
- package/client/dist/assets/vendor-flow-CZmBvHRo.js +1 -0
- package/client/dist/assets/vendor-icons-CVrPjN2Q.js +22 -0
- package/client/dist/assets/vendor-markdown-CRou3yQ5.js +62 -0
- package/client/dist/assets/vendor-misc-C4VxKHs5.js +1 -0
- package/client/dist/assets/vendor-query-SzWcOU0G.js +1 -0
- package/client/dist/assets/vendor-radix-Dnos29jG.js +56 -0
- package/client/dist/assets/vendor-react-DvWIbVx0.js +1 -0
- package/client/dist/index.html +37 -3
- package/client/index.html +28 -1
- package/client/package.json +44 -40
- package/client/src/App.tsx +2 -0
- package/client/src/Dashboard.tsx +157 -45
- package/client/src/ParameterPanel.tsx +3 -5
- package/client/src/adapters/nodeSpecToDescription.ts +1 -0
- package/client/src/assets/icons/NodeIcon.tsx +32 -0
- package/client/src/assets/icons/index.ts +4 -0
- package/client/src/assets/icons/stripe.svg +1 -0
- package/client/src/assets/icons/themedGlyphs.ts +404 -0
- package/client/src/components/AIAgentNode.tsx +77 -53
- package/client/src/components/GenericNode.tsx +34 -52
- package/client/src/components/OutputPanel.tsx +64 -147
- package/client/src/components/ParameterRenderer.tsx +5 -3
- package/client/src/components/SkillEditorModal.tsx +9 -18
- package/client/src/components/SquareNode.tsx +97 -115
- package/client/src/components/StartNode.tsx +32 -42
- package/client/src/components/SvgFilterDefs.tsx +54 -0
- package/client/src/components/TeamMonitorNode.tsx +12 -14
- package/client/src/components/ToolkitNode.tsx +35 -60
- package/client/src/components/TriggerNode.tsx +43 -77
- package/client/src/components/__tests__/CredentialsModal.test.tsx +49 -45
- package/client/src/components/credentials/CredentialsModal.tsx +98 -30
- package/client/src/components/credentials/CredentialsPalette.tsx +73 -5
- package/client/src/components/credentials/catalogueAdapter.ts +17 -1
- package/client/src/components/credentials/panels/ApiKeyPanel.tsx +102 -37
- package/client/src/components/credentials/panels/EmailPanel.tsx +7 -19
- package/client/src/components/credentials/panels/OAuthPanel.tsx +5 -1
- package/client/src/components/credentials/panels/QrPairingPanel.tsx +1 -3
- package/client/src/components/credentials/primitives/ActionBar.tsx +7 -11
- package/client/src/components/credentials/primitives/OAuthConnect.tsx +19 -28
- package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +24 -3
- package/client/src/components/credentials/types.ts +12 -2
- package/client/src/components/credentials/useCredentialPanel.ts +43 -19
- package/client/src/components/icons/AIProviderIcons.tsx +16 -0
- package/client/src/components/onboarding/OnboardingWizard.tsx +23 -63
- package/client/src/components/onboarding/nodeRoleClasses.ts +23 -0
- package/client/src/components/onboarding/steps/CanvasStep.tsx +15 -21
- package/client/src/components/onboarding/steps/ConceptsStep.tsx +2 -11
- package/client/src/components/onboarding/steps/GetStartedStep.tsx +2 -10
- package/client/src/components/parameterPanel/InputSection.tsx +9 -7
- package/client/src/components/parameterPanel/MasterSkillEditor.tsx +84 -198
- package/client/src/components/parameterPanel/MiddleSection.tsx +57 -80
- package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +31 -25
- package/client/src/components/parameterPanel/__tests__/InputSection.test.tsx +7 -2
- package/client/src/components/ui/AIResultModal.tsx +1 -1
- package/client/src/components/ui/CollapsibleSection.tsx +9 -5
- package/client/src/components/ui/CommandPalette.tsx +147 -0
- package/client/src/components/ui/CommandPaletteHost.tsx +189 -0
- package/client/src/components/ui/ComponentItem.tsx +13 -7
- package/client/src/components/ui/ComponentPalette.tsx +24 -13
- package/client/src/components/ui/ConsolePanel.tsx +19 -11
- package/client/src/components/ui/DropCap.tsx +28 -0
- package/client/src/components/ui/EditableNodeLabel.tsx +10 -2
- package/client/src/components/ui/InputNodesPanel.tsx +1 -1
- package/client/src/components/ui/Modal.tsx +38 -6
- package/client/src/components/ui/OutputDisplayPanel.tsx +1 -1
- package/client/src/components/ui/SettingsPanel.tsx +42 -13
- package/client/src/components/ui/StatusBar.tsx +108 -0
- package/client/src/components/ui/ThemeSwitcher.tsx +109 -0
- package/client/src/components/ui/TopToolbar.tsx +42 -25
- package/client/src/components/ui/WorkflowSidebar.tsx +32 -16
- package/client/src/components/ui/action-button.tsx +40 -15
- package/client/src/components/ui/button.tsx +24 -1
- package/client/src/components/ui/dropdown-menu.tsx +24 -2
- package/client/src/components/ui/input.tsx +19 -2
- package/client/src/components/ui/select.tsx +15 -0
- package/client/src/components/ui/textarea.tsx +15 -2
- package/client/src/contexts/AuthContext.tsx +148 -109
- package/client/src/contexts/ThemeContext.tsx +93 -17
- package/client/src/contexts/WebSocketContext.tsx +373 -206
- package/client/src/contexts/__tests__/AuthContext.test.tsx +221 -0
- package/client/src/hooks/__tests__/useDragVariable.test.ts +7 -1
- package/client/src/hooks/__tests__/useWorkflowOpsListener.test.ts +142 -0
- package/client/src/hooks/useAppTheme.ts +209 -7
- package/client/src/hooks/useAutoSkillEdges.ts +7 -2
- package/client/src/hooks/useCatalogueQuery.ts +67 -1
- package/client/src/hooks/useDragVariable.ts +1 -1
- package/client/src/hooks/useNodeAllowlist.ts +115 -8
- package/client/src/hooks/useOnboarding.ts +20 -8
- package/client/src/hooks/useParameterPanel.ts +2 -1
- package/client/src/hooks/useReactFlowNodes.ts +2 -1
- package/client/src/hooks/useSound.ts +185 -0
- package/client/src/hooks/useWorkflowManagement.ts +6 -8
- package/client/src/hooks/useWorkflowOpsListener.ts +90 -0
- package/client/src/index.css +65 -3
- package/client/src/lib/__tests__/connectionConfig.test.ts +91 -0
- package/client/src/lib/aiModelProviders.ts +8 -0
- package/client/src/lib/connectionConfig.ts +107 -0
- package/client/src/lib/queryPersist.ts +13 -5
- package/client/src/lib/sound.ts +393 -0
- package/client/src/main.tsx +20 -0
- package/client/src/store/useAppStore.ts +26 -0
- package/client/src/styles/canvasAnimations.ts +37 -36
- package/client/src/styles/theme.ts +36 -20
- package/client/src/test/setup.ts +1 -0
- package/client/src/themes/atomic.css +253 -0
- package/client/src/themes/base.css +373 -0
- package/client/src/themes/cyber.css +890 -0
- package/client/src/themes/dark.css +70 -0
- package/client/src/themes/edo.css +246 -0
- package/client/src/themes/greek.css +293 -0
- package/client/src/themes/light.css +78 -0
- package/client/src/themes/plague.css +253 -0
- package/client/src/themes/renaissance.css +727 -0
- package/client/src/themes/rot.css +249 -0
- package/client/src/themes/steampunk.css +272 -0
- package/client/src/themes/surveillance.css +289 -0
- package/client/src/themes/wasteland.css +250 -0
- package/client/src/types/INodeProperties.ts +5 -0
- package/client/src/types/NodeTypes.ts +11 -1
- package/client/src/types/__tests__/cloudEvents.test.ts +99 -0
- package/client/src/types/cloudEvents.ts +78 -0
- package/client/src/vite-env.d.ts +7 -0
- package/client/tsconfig.json +1 -1
- package/client/vite.config.js +62 -2
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/machina/commands/build.py +51 -7
- package/machina/pyproject.toml +4 -0
- package/machina/supervisor.py +12 -2
- package/machina/tree.py +71 -21
- package/package.json +4 -4
- package/scripts/install.js +16 -1
- package/server/config/ai_cli_providers.json +54 -0
- package/server/config/credential_providers.json +109 -2
- package/server/config/llm_defaults.json +24 -0
- package/server/config/model_registry.json +338 -499
- package/server/config/node_allowlist.json +16 -1
- package/server/config/pricing.json +8 -0
- package/server/constants.py +38 -15
- package/server/core/container.py +2 -2
- package/server/core/credentials_database.py +35 -2
- package/server/core/logging.py +4 -3
- package/server/main.py +99 -13
- package/server/models/node_metadata.py +1 -0
- package/server/nodejs/package.json +8 -6
- package/server/nodejs/src/index.ts +22 -5
- package/server/nodes/README.md +31 -4
- package/server/nodes/agent/_inline.py +2 -0
- package/server/nodes/agent/_specialized.py +6 -3
- package/server/nodes/agent/ai_agent.py +13 -3
- package/server/nodes/agent/chat_agent.py +6 -3
- package/server/nodes/agent/claude_code_agent.py +287 -75
- package/server/nodes/agent/codex_agent.py +239 -0
- package/server/nodes/agent/deep_agent.py +3 -3
- package/server/nodes/agent/rlm_agent.py +3 -3
- package/server/nodes/android/__init__.py +31 -1
- package/server/nodes/android/_base.py +9 -5
- package/server/{services/android_service.py → nodes/android/_dispatcher.py} +2 -2
- package/server/nodes/android/_handlers.py +154 -0
- package/server/nodes/android/_option_loaders.py +44 -0
- package/server/nodes/android/_refresh.py +127 -0
- package/server/{services/android → nodes/android/_relay}/client.py +4 -4
- package/server/{routers/android.py → nodes/android/_router.py} +27 -8
- package/server/nodes/browser/browser.py +2 -2
- package/server/nodes/code/_base.py +6 -2
- package/server/nodes/code/_claude_code.py +134 -0
- package/server/nodes/document/embedding_generator.py +3 -3
- package/server/nodes/document/http_scraper.py +3 -3
- package/server/nodes/document/vector_store.py +5 -5
- package/server/nodes/email/__init__.py +11 -1
- package/server/nodes/email/_filters.py +21 -0
- package/server/{services/himalaya_service.py → nodes/email/_himalaya.py} +6 -10
- package/server/{services/email_service.py → nodes/email/_service.py} +9 -13
- package/server/nodes/email/email_read.py +1 -1
- package/server/nodes/email/email_receive.py +54 -5
- package/server/nodes/email/email_send.py +1 -1
- package/server/nodes/filesystem/shell.py +24 -1
- package/server/nodes/google/__init__.py +55 -1
- package/server/{services/handlers/google_auth.py → nodes/google/_auth_helper.py} +8 -5
- package/server/nodes/google/_base.py +2 -2
- package/server/nodes/google/_credentials.py +5 -5
- package/server/nodes/google/_filters.py +25 -0
- package/server/nodes/google/_handlers.py +57 -0
- package/server/{services/google_oauth.py → nodes/google/_oauth.py} +195 -162
- package/server/nodes/google/_option_loaders.py +107 -0
- package/server/nodes/google/_refresh.py +66 -0
- package/server/nodes/google/_router.py +131 -0
- package/server/nodes/google/gmail_receive.py +41 -4
- package/server/nodes/groups.py +1 -0
- package/server/nodes/location/_credentials.py +45 -1
- package/server/{services/maps.py → nodes/location/_service.py} +18 -3
- package/server/nodes/location/gmaps_create.py +4 -4
- package/server/nodes/location/gmaps_locations.py +4 -4
- package/server/nodes/location/gmaps_nearby_places.py +4 -4
- package/server/nodes/model/_base.py +8 -3
- package/server/nodes/model/_credentials.py +96 -8
- package/server/nodes/model/_local_validator.py +345 -0
- package/server/nodes/model/lmstudio_chat_model.py +23 -0
- package/server/nodes/model/ollama_chat_model.py +25 -0
- package/server/nodes/proxy/_usage.py +2 -2
- package/server/nodes/proxy/proxy_config.py +14 -14
- package/server/nodes/proxy/proxy_request.py +4 -4
- package/server/nodes/scraper/_credentials.py +29 -1
- package/server/nodes/scraper/apify_actor.py +9 -9
- package/server/nodes/scraper/crawlee_scraper.py +5 -5
- package/server/nodes/search/brave_search.py +4 -0
- package/server/nodes/search/perplexity_search.py +9 -0
- package/server/nodes/search/serper_search.py +3 -0
- package/server/nodes/skill/simple_memory.py +12 -0
- package/server/nodes/social/_base.py +2 -2
- package/server/nodes/stripe/__init__.py +46 -0
- package/server/nodes/stripe/_credentials.py +33 -0
- package/server/nodes/stripe/_handlers.py +270 -0
- package/server/nodes/stripe/_install.py +127 -0
- package/server/nodes/stripe/_source.py +174 -0
- package/server/nodes/stripe/stripe_action.py +81 -0
- package/server/nodes/stripe/stripe_receive.py +92 -0
- package/server/nodes/telegram/_credentials.py +52 -1
- package/server/nodes/telegram/_handlers.py +19 -18
- package/server/nodes/telegram/_service.py +134 -32
- package/server/nodes/telegram/telegram_send.py +5 -6
- package/server/nodes/text/file_handler.py +2 -2
- package/server/nodes/text/text_generator.py +2 -2
- package/server/nodes/tool/agent_builder.py +630 -0
- package/server/nodes/tool/task_manager.py +144 -2
- package/server/nodes/twitter/__init__.py +38 -1
- package/server/nodes/twitter/_base.py +7 -7
- package/server/nodes/twitter/_credentials.py +1 -1
- package/server/nodes/twitter/_filters.py +37 -0
- package/server/nodes/twitter/_handlers.py +77 -0
- package/server/nodes/twitter/_oauth.py +124 -0
- package/server/nodes/twitter/_refresh.py +78 -0
- package/server/nodes/twitter/_router.py +29 -0
- package/server/nodes/twitter/twitter_receive.py +4 -0
- package/server/nodes/visuals.json +64 -19
- package/server/nodes/whatsapp/__init__.py +45 -5
- package/server/nodes/whatsapp/_base.py +3 -3
- package/server/nodes/whatsapp/_filters.py +137 -0
- package/server/nodes/whatsapp/_handlers.py +167 -0
- package/server/nodes/whatsapp/_option_loaders.py +68 -0
- package/server/nodes/whatsapp/_refresh.py +62 -0
- package/server/nodes/whatsapp/_runtime.py +1 -1
- package/server/pyproject.toml +29 -7
- package/server/routers/schemas.py +2 -2
- package/server/routers/webhook.py +26 -9
- package/server/routers/websocket.py +149 -810
- package/server/services/ai.py +89 -8
- package/server/services/auth.py +220 -43
- package/server/services/claude_oauth.py +126 -100
- package/server/services/cli_agent/__init__.py +78 -0
- package/server/services/cli_agent/_handlers.py +237 -0
- package/server/services/cli_agent/config.py +112 -0
- package/server/services/cli_agent/factory.py +48 -0
- package/server/services/cli_agent/lockfile.py +141 -0
- package/server/services/cli_agent/mcp_server.py +482 -0
- package/server/services/cli_agent/protocol.py +173 -0
- package/server/services/cli_agent/providers/__init__.py +9 -0
- package/server/services/cli_agent/providers/anthropic_claude.py +419 -0
- package/server/services/cli_agent/providers/google_gemini.py +80 -0
- package/server/services/cli_agent/providers/openai_codex.py +310 -0
- package/server/services/cli_agent/service.py +607 -0
- package/server/services/cli_agent/session.py +618 -0
- package/server/services/cli_agent/types.py +227 -0
- package/server/services/cli_agent/workflow_tools.py +233 -0
- package/server/services/credential_registry.py +26 -1
- package/server/services/deployment/manager.py +26 -145
- package/server/services/deployment/poll_registry.py +59 -0
- package/server/services/event_waiter.py +76 -246
- package/server/services/events/__init__.py +54 -0
- package/server/services/events/cli.py +78 -0
- package/server/services/events/daemon.py +163 -0
- package/server/services/events/envelope.py +281 -0
- package/server/services/events/lifecycle.py +99 -0
- package/server/services/events/oauth_lifecycle.py +534 -0
- package/server/services/events/polling.py +60 -0
- package/server/services/events/push.py +36 -0
- package/server/services/events/source.py +63 -0
- package/server/services/events/triggers.py +118 -0
- package/server/services/events/verifiers/__init__.py +25 -0
- package/server/services/events/verifiers/base.py +28 -0
- package/server/services/events/verifiers/github.py +25 -0
- package/server/services/events/verifiers/hmac_basic.py +32 -0
- package/server/services/events/verifiers/standard_webhooks.py +47 -0
- package/server/services/events/verifiers/stripe.py +42 -0
- package/server/services/events/webhook.py +105 -0
- package/server/services/handlers/tools.py +28 -186
- package/server/services/llm/config.py +7 -0
- package/server/services/llm/factory.py +8 -2
- package/server/services/memory/__init__.py +52 -0
- package/server/services/memory/jsonl.py +80 -0
- package/server/services/memory/markdown.py +65 -0
- package/server/services/memory/state.py +112 -0
- package/server/services/memory/vector_store.py +40 -0
- package/server/services/model_registry.py +76 -0
- package/server/services/node_allowlist.py +71 -15
- package/server/services/node_executor.py +2 -2
- package/server/services/node_output_schemas.py +21 -10
- package/server/services/node_spec.py +1 -1
- package/server/services/oauth_utils.py +1 -1
- package/server/services/plugin/__init__.py +2 -0
- package/server/services/plugin/base.py +44 -2
- package/server/services/plugin/credential.py +288 -1
- package/server/services/plugin/deps.py +105 -0
- package/server/services/plugin/edge_walker.py +12 -4
- package/server/services/plugin/oauth.py +381 -0
- package/server/services/plugin/polling.py +247 -0
- package/server/services/plugin/registry.py +145 -0
- package/server/services/plugin/singleton.py +65 -0
- package/server/services/plugin/ws.py +81 -0
- package/server/services/process_service.py +31 -2
- package/server/services/status_broadcaster.py +155 -238
- package/server/services/temporal/workflow.py +7 -7
- package/server/services/workflow.py +21 -3
- package/server/services/ws_handler_registry.py +111 -28
- package/server/skills/GUIDE.md +16 -1
- package/server/skills/assistant/agent-builder-skill/SKILL.md +166 -0
- package/server/skills/payments_agent/stripe-skill/SKILL.md +306 -0
- package/server/tests/credentials/test_auth_service.py +16 -9
- package/server/tests/credentials/test_credential_broadcasts.py +219 -0
- package/server/tests/credentials/test_google_oauth.py +6 -6
- package/server/tests/credentials/test_oauth_utils.py +1 -1
- package/server/tests/credentials/test_twitter_oauth.py +2 -2
- package/server/tests/credentials/test_websocket_handlers.py +44 -20
- package/server/tests/llm/test_factory.py +1 -0
- package/server/tests/llm/test_wiring.py +5 -1
- package/server/tests/nodes/_compat.py +24 -24
- package/server/tests/nodes/test_agent_builder.py +439 -0
- package/server/tests/nodes/test_ai_tools.py +18 -14
- package/server/tests/nodes/test_code_fs_process.py +17 -8
- package/server/tests/nodes/test_email.py +10 -9
- package/server/tests/nodes/test_google_workspace.py +2 -2
- package/server/tests/nodes/test_specialized_agents.py +100 -53
- package/server/tests/nodes/test_stripe_plugin.py +293 -0
- package/server/tests/nodes/test_telegram_social.py +4 -4
- package/server/tests/nodes/test_twitter.py +1 -1
- package/server/tests/nodes/test_web_automation.py +2 -2
- package/server/tests/nodes/test_whatsapp.py +9 -9
- package/server/tests/services/cli_agent/__init__.py +0 -0
- package/server/tests/services/cli_agent/test_mcp_server.py +432 -0
- package/server/tests/services/cli_agent/test_providers.py +358 -0
- package/server/tests/services/cli_agent/test_service.py +298 -0
- package/server/tests/services/memory/__init__.py +0 -0
- package/server/tests/services/memory/test_jsonl.py +188 -0
- package/server/tests/services/test_events.py +333 -0
- package/server/tests/test_node_spec.py +56 -16
- package/server/tests/test_plugin_helpers.py +116 -0
- package/server/tests/test_plugin_self_containment.py +486 -0
- package/server/tests/test_status_broadcasts.py +425 -0
- package/workflows/{AI Assistant_workflow-1777421105154-0m4snkzjf.json → AI Assistant_workflow-1778504793388-ou1m1tz2x.json } +70 -266
- package/workflows/{AI Employee_workflow-1777720598005-u4cm858dv.json → AI Employee_example_workflow-1777720598005-u4cm858dv.json } +112 -112
- package/workflows/Claude Assistant_workflow-1778380124051-mdibn807c.json +709 -0
- package/client/dist/assets/ActionBar-vzPpSR77.js +0 -1
- package/client/dist/assets/ApiKeyInput-Ds7AKFe8.js +0 -1
- package/client/dist/assets/ApiKeyPanel-gfblELep.js +0 -1
- package/client/dist/assets/ApiUsageSection-BMNWTe2r.js +0 -1
- package/client/dist/assets/EmailPanel-B1Om64p5.js +0 -1
- package/client/dist/assets/OAuthPanel-CXyQYGBz.js +0 -1
- package/client/dist/assets/QrPairingPanel-BgNuI1we.js +0 -1
- package/client/dist/assets/RateLimitSection-YYK8sx1T.js +0 -1
- package/client/dist/assets/StatusCard-DuYA5hJR.js +0 -1
- package/client/dist/assets/index-D9tZfgvi.js +0 -363
- package/client/dist/assets/index-al7snTkG.css +0 -1
- package/client/src/components/credentials/providers.tsx +0 -177
- package/server/routers/google.py +0 -277
- package/server/routers/maps.py +0 -142
- package/server/routers/twitter.py +0 -365
- package/server/services/claude_code_service.py +0 -106
- package/server/services/memory.py +0 -159
- package/server/services/node_option_loaders/__init__.py +0 -77
- package/server/services/node_option_loaders/android_loaders.py +0 -55
- package/server/services/node_option_loaders/google_loaders.py +0 -97
- package/server/services/node_option_loaders/whatsapp_loaders.py +0 -69
- package/server/services/twitter_oauth.py +0 -411
- package/server/services/websocket_client.py +0 -29
- /package/server/{services/android → nodes/android/_relay}/__init__.py +0 -0
- /package/server/{services/android → nodes/android/_relay}/broadcaster.py +0 -0
- /package/server/{services/android → nodes/android/_relay}/manager.py +0 -0
- /package/server/{services/android → nodes/android/_relay}/protocol.py +0 -0
- /package/server/{services/browser_service.py → nodes/browser/_service.py} +0 -0
- /package/server/{services/whatsapp_service.py → nodes/whatsapp/_service.py} +0 -0
- /package/server/skills/{task_agent → assistant}/write-todos-skill/SKILL.md +0 -0
|
@@ -3,7 +3,6 @@ import { Loader2, Save } from 'lucide-react';
|
|
|
3
3
|
import { toast } from 'sonner';
|
|
4
4
|
import { useMutation, useQueries, useQuery } from '@tanstack/react-query';
|
|
5
5
|
|
|
6
|
-
import { Button } from '@/components/ui/button';
|
|
7
6
|
import { Input } from '@/components/ui/input';
|
|
8
7
|
import { Progress } from '@/components/ui/progress';
|
|
9
8
|
import { Checkbox } from '@/components/ui/checkbox';
|
|
@@ -30,7 +29,6 @@ import { ActionButton } from '@/components/ui/action-button';
|
|
|
30
29
|
import ParameterRenderer from '../ParameterRenderer';
|
|
31
30
|
import ToolSchemaEditor from './ToolSchemaEditor';
|
|
32
31
|
import MasterSkillEditor from './MasterSkillEditor';
|
|
33
|
-
import { useAppTheme } from '../../hooks/useAppTheme';
|
|
34
32
|
import { useAppStore } from '../../store/useAppStore';
|
|
35
33
|
import { useWebSocket, CompactionStats } from '../../contexts/WebSocketContext';
|
|
36
34
|
import { useUserSettingsQuery } from '../../hooks/useUserSettingsQuery';
|
|
@@ -44,7 +42,12 @@ import { ExecutionResult } from '../../services/executionService';
|
|
|
44
42
|
import { Edge } from 'reactflow';
|
|
45
43
|
import { shouldShowParameter } from '../../utils/parameterVisibility';
|
|
46
44
|
|
|
47
|
-
import { resolveNodeDescription } from '../../lib/nodeSpec';
|
|
45
|
+
import { resolveNodeDescription, getCachedNodeSpec } from '../../lib/nodeSpec';
|
|
46
|
+
|
|
47
|
+
const isMasterSkillNodeType = (nodeType: string | undefined): boolean => {
|
|
48
|
+
if (!nodeType) return false;
|
|
49
|
+
return (getCachedNodeSpec(nodeType)?.uiHints as any)?.isMasterSkillEditor === true;
|
|
50
|
+
};
|
|
48
51
|
// Wave 10.G.3: retired the three tribal arrays `SKILL_NODE_TYPES`,
|
|
49
52
|
// `TOOL_NODE_TYPES`, and `AGENT_WITH_SKILLS_TYPES`. The parameter panel
|
|
50
53
|
// now reads `uiHints.hasSkills` / `uiHints.isToolPanel` /
|
|
@@ -87,8 +90,7 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
87
90
|
isLoadingParameters = false,
|
|
88
91
|
executionResults = []
|
|
89
92
|
}) => {
|
|
90
|
-
const
|
|
91
|
-
const { currentWorkflow } = useAppStore();
|
|
93
|
+
const currentWorkflow = useAppStore((s) => s.currentWorkflow);
|
|
92
94
|
const { clearMemory, resetSkill, sendRequest, getNodeParameters, compactionStats: contextCompactionStats, updateCompactionStats } = useWebSocket();
|
|
93
95
|
|
|
94
96
|
const [showClearMemoryDialog, setShowClearMemoryDialog] = useState(false);
|
|
@@ -297,7 +299,7 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
297
299
|
const masterSkillEdgeSources = useMemo<string[]>(() => {
|
|
298
300
|
const nodes = currentWorkflow?.nodes || [];
|
|
299
301
|
return skillEdges
|
|
300
|
-
.filter((edge) => nodes.find((n: any) => n.id === edge.source)?.type
|
|
302
|
+
.filter((edge) => isMasterSkillNodeType(nodes.find((n: any) => n.id === edge.source)?.type))
|
|
301
303
|
.map((edge) => edge.source);
|
|
302
304
|
}, [skillEdges, currentWorkflow?.nodes]);
|
|
303
305
|
|
|
@@ -425,7 +427,7 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
425
427
|
for (const edge of skillEdges) {
|
|
426
428
|
const sourceNode = nodes.find((n: any) => n.id === edge.source);
|
|
427
429
|
const nodeType = sourceNode?.type || '';
|
|
428
|
-
if (nodeType
|
|
430
|
+
if (isMasterSkillNodeType(nodeType)) continue;
|
|
429
431
|
const def = resolveNodeDescription(nodeType);
|
|
430
432
|
skills.push({
|
|
431
433
|
id: edge.source,
|
|
@@ -452,7 +454,7 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
452
454
|
|
|
453
455
|
for (const edge of skillEdges) {
|
|
454
456
|
const sourceNode = nodes.find((n: any) => n.id === edge.source);
|
|
455
|
-
if (sourceNode?.type
|
|
457
|
+
if (isMasterSkillNodeType(sourceNode?.type)) {
|
|
456
458
|
const params = masterSkillParams[edge.source];
|
|
457
459
|
const skillsConfig = params?.skills_config || {};
|
|
458
460
|
|
|
@@ -510,38 +512,21 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
510
512
|
const consoleOutput = isCodeExecutorNode ? getConsoleOutput() : '';
|
|
511
513
|
|
|
512
514
|
return (
|
|
513
|
-
<div
|
|
514
|
-
flex: 1,
|
|
515
|
-
display: 'flex',
|
|
516
|
-
flexDirection: 'column',
|
|
517
|
-
height: '100%',
|
|
518
|
-
overflow: 'hidden',
|
|
519
|
-
position: 'relative'
|
|
520
|
-
}}>
|
|
515
|
+
<div className="relative flex h-full flex-1 flex-col overflow-hidden">
|
|
521
516
|
{/* Description - hide for code editor nodes (Python, Skill) and masterSkill */}
|
|
522
517
|
{!needsCodeEditorLayout && !isMasterSkillNode && (
|
|
523
|
-
<div
|
|
524
|
-
|
|
525
|
-
borderBottom: `1px solid ${theme.colors.border}`,
|
|
526
|
-
backgroundColor: theme.colors.backgroundAlt,
|
|
527
|
-
flexShrink: 0
|
|
528
|
-
}}>
|
|
529
|
-
<p style={{
|
|
530
|
-
margin: 0,
|
|
531
|
-
fontSize: theme.fontSize.base,
|
|
532
|
-
color: theme.colors.textSecondary,
|
|
533
|
-
lineHeight: '1.5',
|
|
534
|
-
}}>
|
|
518
|
+
<div className="shrink-0 border-b border-border-default bg-bg-panel px-6 pt-4 pb-2">
|
|
519
|
+
<p className="m-0 text-base leading-[1.5] text-fg-muted">
|
|
535
520
|
{nodeDefinition.description}
|
|
536
521
|
</p>
|
|
537
522
|
</div>
|
|
538
523
|
)}
|
|
539
524
|
|
|
540
525
|
{/* Main Content Area - Flexible */}
|
|
541
|
-
<div
|
|
526
|
+
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
|
|
542
527
|
{/* Master Skill Editor - Full panel for masterSkill nodes */}
|
|
543
528
|
{isMasterSkillNode ? (
|
|
544
|
-
<div
|
|
529
|
+
<div className="flex flex-1 flex-col overflow-hidden p-4">
|
|
545
530
|
<MasterSkillEditor
|
|
546
531
|
skillsConfig={parameters.skills_config || {}}
|
|
547
532
|
onConfigChange={(config) => onParameterChange('skills_config', config)}
|
|
@@ -553,45 +538,34 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
553
538
|
) : (
|
|
554
539
|
<>
|
|
555
540
|
{/* Parameters */}
|
|
556
|
-
<div
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
display: needsCodeEditorLayout ? 'flex' : 'block',
|
|
565
|
-
flexDirection: 'column'
|
|
566
|
-
}}>
|
|
541
|
+
<div
|
|
542
|
+
className={cn(
|
|
543
|
+
'box-border min-h-0 w-full overflow-x-hidden p-6',
|
|
544
|
+
needsCodeEditorLayout
|
|
545
|
+
? 'flex flex-[3] flex-col overflow-y-hidden'
|
|
546
|
+
: 'block flex-1 overflow-y-auto',
|
|
547
|
+
)}
|
|
548
|
+
>
|
|
567
549
|
{/* Parameters Container */}
|
|
568
|
-
<div
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
height: needsCodeEditorLayout ? '100%' : 'auto',
|
|
575
|
-
display: needsCodeEditorLayout ? 'flex' : 'block',
|
|
576
|
-
flexDirection: 'column',
|
|
577
|
-
boxSizing: 'border-box'
|
|
578
|
-
}}>
|
|
550
|
+
<div
|
|
551
|
+
className={cn(
|
|
552
|
+
'box-border rounded-md border border-border-default bg-bg-elevated p-4 shadow-sm',
|
|
553
|
+
needsCodeEditorLayout ? 'flex h-full flex-col' : 'block h-auto',
|
|
554
|
+
)}
|
|
555
|
+
>
|
|
579
556
|
{/* All Parameters - standard n8n style */}
|
|
580
557
|
{visibleParams.map((param: INodeProperties, index: number) => {
|
|
581
558
|
// Check if this parameter is a code editor - give it more flex space
|
|
582
559
|
const isCodeParam = (param as any).typeOptions?.editor === 'code';
|
|
560
|
+
const isLast = index === visibleParams.length - 1;
|
|
583
561
|
return (
|
|
584
562
|
<div
|
|
585
563
|
key={param.name}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
display: needsCodeEditorLayout ? 'flex' : 'block',
|
|
592
|
-
flexDirection: 'column',
|
|
593
|
-
minHeight: needsCodeEditorLayout && isCodeParam ? '300px' : 0
|
|
594
|
-
}}
|
|
564
|
+
className={cn(
|
|
565
|
+
needsCodeEditorLayout ? 'flex flex-col' : 'block',
|
|
566
|
+
!isLast && 'mb-3 border-b border-border-default pb-3',
|
|
567
|
+
needsCodeEditorLayout && isCodeParam ? 'min-h-[300px] flex-1' : 'min-h-0 flex-none',
|
|
568
|
+
)}
|
|
595
569
|
>
|
|
596
570
|
<ParameterRenderer
|
|
597
571
|
parameter={param}
|
|
@@ -618,21 +592,21 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
618
592
|
|
|
619
593
|
{/* Clear Memory Button - Only for memory nodes */}
|
|
620
594
|
{isMemoryNode && (
|
|
621
|
-
<div className="mt-3 flex justify-end border-t border-border pt-3">
|
|
622
|
-
<
|
|
623
|
-
|
|
624
|
-
size="sm"
|
|
595
|
+
<div className="mt-3 flex justify-end border-t border-border-default pt-3">
|
|
596
|
+
<ActionButton
|
|
597
|
+
intent="stop"
|
|
625
598
|
onClick={() => setShowClearMemoryDialog(true)}
|
|
599
|
+
className="h-8"
|
|
626
600
|
>
|
|
627
601
|
<Trash2 className="h-3.5 w-3.5" />
|
|
628
602
|
Clear Memory
|
|
629
|
-
</
|
|
603
|
+
</ActionButton>
|
|
630
604
|
</div>
|
|
631
605
|
)}
|
|
632
606
|
|
|
633
607
|
{/* Reset Skill Button - Only for built-in skill nodes */}
|
|
634
608
|
{isSkillNode && (
|
|
635
|
-
<div className="mt-3 flex justify-end border-t border-border pt-3">
|
|
609
|
+
<div className="mt-3 flex justify-end border-t border-border-default pt-3">
|
|
636
610
|
<ActionButton
|
|
637
611
|
intent="config"
|
|
638
612
|
onClick={() => setShowResetSkillDialog(true)}
|
|
@@ -710,18 +684,18 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
710
684
|
|
|
711
685
|
{/* Token Usage Section - Only for agent nodes with memory connected */}
|
|
712
686
|
{isAgentWithSkills && connectedMemorySessionId && (
|
|
713
|
-
<Accordion type="single" collapsible defaultValue="tokens"
|
|
687
|
+
<Accordion type="single" collapsible defaultValue="tokens" className="mt-4">
|
|
714
688
|
<AccordionItem value="tokens">
|
|
715
689
|
<AccordionTrigger>
|
|
716
690
|
{(() => {
|
|
717
691
|
const ctxLen = compactionStats?.context_length || 0;
|
|
718
692
|
const displayMax = ctxLen > 0 ? ctxLen : compactionStats?.threshold || 0;
|
|
719
693
|
return (
|
|
720
|
-
<span className="flex flex-1 items-center gap-2">
|
|
694
|
+
<span className="font-display tracking-[var(--type-tracking-display)] [text-transform:var(--type-uppercase)] text-fg-default flex flex-1 items-center gap-2">
|
|
721
695
|
<Zap className="h-4 w-4" />
|
|
722
696
|
Token Usage
|
|
723
697
|
{compactionStats && displayMax > 0 && (
|
|
724
|
-
<span className="ml-auto text-xs text-muted-
|
|
698
|
+
<span className="ml-auto text-xs text-fg-muted normal-case tracking-normal">
|
|
725
699
|
{Math.round(compactionStats.total / 1000)}K / {Math.round(displayMax / 1000)}K{ctxLen > 0 ? ' context' : ''}
|
|
726
700
|
</span>
|
|
727
701
|
)}
|
|
@@ -769,8 +743,9 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
769
743
|
step={10000}
|
|
770
744
|
className="h-7 w-28 text-xs"
|
|
771
745
|
/>
|
|
772
|
-
<
|
|
773
|
-
|
|
746
|
+
<ActionButton
|
|
747
|
+
intent="save"
|
|
748
|
+
className="h-7 w-7 px-0"
|
|
774
749
|
disabled={savingThreshold || !connectedMemorySessionId}
|
|
775
750
|
onClick={() => {
|
|
776
751
|
if (!connectedMemorySessionId) return;
|
|
@@ -781,7 +756,7 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
781
756
|
}}
|
|
782
757
|
>
|
|
783
758
|
{savingThreshold ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Save className="h-3.5 w-3.5" />}
|
|
784
|
-
</
|
|
759
|
+
</ActionButton>
|
|
785
760
|
</div>
|
|
786
761
|
</div>
|
|
787
762
|
) : (
|
|
@@ -829,12 +804,12 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
829
804
|
>
|
|
830
805
|
<AccordionItem value="skills">
|
|
831
806
|
<AccordionTrigger>
|
|
832
|
-
<span className="flex flex-1 items-center gap-2">
|
|
807
|
+
<span className="font-display tracking-[var(--type-tracking-display)] [text-transform:var(--type-uppercase)] text-fg-default flex flex-1 items-center gap-2">
|
|
833
808
|
<Sparkles className="h-4 w-4" />
|
|
834
809
|
Connected Skills
|
|
835
810
|
<Badge
|
|
836
811
|
variant={expandedConnectedSkills.length > 0 ? 'default' : 'outline'}
|
|
837
|
-
className="ml-auto"
|
|
812
|
+
className="ml-auto normal-case tracking-normal"
|
|
838
813
|
>
|
|
839
814
|
{expandedConnectedSkills.length}
|
|
840
815
|
</Badge>
|
|
@@ -894,20 +869,22 @@ const MiddleSection: React.FC<MiddleSectionProps> = ({
|
|
|
894
869
|
<Accordion type="single" collapsible defaultValue="console" className="flex min-h-0 flex-1 flex-col">
|
|
895
870
|
<AccordionItem value="console" className="flex min-h-0 flex-1 flex-col">
|
|
896
871
|
<AccordionTrigger>
|
|
897
|
-
<span className="flex flex-1 items-center gap-2">
|
|
872
|
+
<span className="font-display tracking-[var(--type-tracking-display)] [text-transform:var(--type-uppercase)] text-fg-default flex flex-1 items-center gap-2">
|
|
898
873
|
<TerminalSquare className="h-4 w-4" />
|
|
899
874
|
Console
|
|
900
875
|
{consoleOutput && (
|
|
901
|
-
<Badge variant="success" className="ml-auto">Output</Badge>
|
|
876
|
+
<Badge variant="success" className="ml-auto normal-case tracking-normal">Output</Badge>
|
|
902
877
|
)}
|
|
903
878
|
</span>
|
|
904
879
|
</AccordionTrigger>
|
|
905
880
|
<AccordionContent className="flex min-h-0 flex-1 flex-col">
|
|
906
|
-
<div className="min-h-0 flex-1 overflow-y-auto rounded-md bg-
|
|
881
|
+
<div className="min-h-0 flex-1 overflow-y-auto rounded-md bg-bg-app p-2 font-mono text-sm leading-relaxed">
|
|
907
882
|
{consoleOutput ? (
|
|
908
883
|
<pre
|
|
909
|
-
className=
|
|
910
|
-
|
|
884
|
+
className={cn(
|
|
885
|
+
'm-0 whitespace-pre-wrap break-words',
|
|
886
|
+
consoleOutput.startsWith('Error') ? 'text-destructive' : 'text-success',
|
|
887
|
+
)}
|
|
911
888
|
>
|
|
912
889
|
{consoleOutput}
|
|
913
890
|
</pre>
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
SelectTrigger,
|
|
34
34
|
SelectValue,
|
|
35
35
|
} from '@/components/ui/select';
|
|
36
|
-
import {
|
|
36
|
+
import { ActionButton } from '@/components/ui/action-button';
|
|
37
37
|
import { Checkbox } from '@/components/ui/checkbox';
|
|
38
38
|
|
|
39
39
|
import { resolveNodeDescription } from '../../lib/nodeSpec';
|
|
@@ -122,10 +122,12 @@ function formValuesToConfig(values: ToolSchemaFormValues): ToolSchemaConfig {
|
|
|
122
122
|
// Editor
|
|
123
123
|
// ---------------------------------------------------------------------------
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
// Outer component is the gate: it only calls the hooks needed to decide
|
|
126
|
+
// whether the editor should render at all. The full hook surface (form,
|
|
127
|
+
// effects, field array) lives in <ToolSchemaEditorBody/> so React's
|
|
128
|
+
// rules-of-hooks invariants hold whether the gate is open or closed.
|
|
129
|
+
const ToolSchemaEditor: React.FC<ToolSchemaEditorProps> = ({ nodeId, toolName, toolDescription }) => {
|
|
130
|
+
const currentWorkflow = useAppStore((s) => s.currentWorkflow);
|
|
129
131
|
|
|
130
132
|
const currentNode = useMemo(() => {
|
|
131
133
|
if (!currentWorkflow?.nodes) return null;
|
|
@@ -139,6 +141,14 @@ const ToolSchemaEditor: React.FC<ToolSchemaEditorProps> = ({ nodeId }) => {
|
|
|
139
141
|
const isAndroidTool = (currentNodeDef?.uiHints as any)?.isAndroidToolkit === true;
|
|
140
142
|
if (!isAndroidTool) return null;
|
|
141
143
|
|
|
144
|
+
return <ToolSchemaEditorBody nodeId={nodeId} toolName={toolName} toolDescription={toolDescription} />;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const ToolSchemaEditorBody: React.FC<ToolSchemaEditorProps> = ({ nodeId }) => {
|
|
148
|
+
const { getToolSchema, saveToolSchema, deleteToolSchema, isLoading } = useToolSchema();
|
|
149
|
+
const { isConnected } = useWebSocket();
|
|
150
|
+
const currentWorkflow = useAppStore((s) => s.currentWorkflow);
|
|
151
|
+
|
|
142
152
|
const connectedServices = useMemo(() => {
|
|
143
153
|
if (!currentWorkflow?.edges || !currentWorkflow?.nodes) return [];
|
|
144
154
|
const incomingEdges = currentWorkflow.edges.filter((edge) => edge.target === nodeId);
|
|
@@ -244,7 +254,7 @@ const ToolSchemaEditor: React.FC<ToolSchemaEditorProps> = ({ nodeId }) => {
|
|
|
244
254
|
!isExpanded && '-rotate-90'
|
|
245
255
|
)}
|
|
246
256
|
/>
|
|
247
|
-
<span className="font-semibold text-
|
|
257
|
+
<span className="font-display tracking-[var(--type-tracking-display)] [text-transform:var(--type-uppercase)] text-sm font-semibold text-fg-default">Connected Services</span>
|
|
248
258
|
</div>
|
|
249
259
|
<span className="text-sm text-muted-foreground">
|
|
250
260
|
{connectedServices.length} service(s)
|
|
@@ -279,18 +289,16 @@ const ToolSchemaEditor: React.FC<ToolSchemaEditorProps> = ({ nodeId }) => {
|
|
|
279
289
|
)}
|
|
280
290
|
</div>
|
|
281
291
|
) : (
|
|
282
|
-
<div className="mb-3 rounded border border-
|
|
292
|
+
<div className="mb-3 rounded border border-warning/30 bg-warning/10 p-2 text-sm text-warning">
|
|
283
293
|
Connect Android nodes to the input handle
|
|
284
294
|
</div>
|
|
285
295
|
)}
|
|
286
296
|
|
|
287
297
|
<div className="mb-2 flex items-center justify-between">
|
|
288
|
-
<label className="text-sm text-muted
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
size="sm"
|
|
293
|
-
className="h-7 border-dracula-cyan/40 bg-dracula-cyan/15 text-dracula-cyan hover:bg-dracula-cyan/25"
|
|
298
|
+
<label className="font-display tracking-[var(--type-tracking-display)] [text-transform:var(--type-uppercase)] text-sm text-fg-muted">Schema Fields</label>
|
|
299
|
+
<ActionButton
|
|
300
|
+
intent="tools"
|
|
301
|
+
className="h-7"
|
|
294
302
|
onClick={() =>
|
|
295
303
|
append({
|
|
296
304
|
name: `field_${fields.length + 1}`,
|
|
@@ -301,7 +309,7 @@ const ToolSchemaEditor: React.FC<ToolSchemaEditorProps> = ({ nodeId }) => {
|
|
|
301
309
|
}
|
|
302
310
|
>
|
|
303
311
|
+ Add
|
|
304
|
-
</
|
|
312
|
+
</ActionButton>
|
|
305
313
|
</div>
|
|
306
314
|
|
|
307
315
|
<div className="flex flex-col gap-1">
|
|
@@ -312,17 +320,16 @@ const ToolSchemaEditor: React.FC<ToolSchemaEditorProps> = ({ nodeId }) => {
|
|
|
312
320
|
|
|
313
321
|
{hasChanges && (
|
|
314
322
|
<div className="mt-3 flex justify-end gap-2">
|
|
315
|
-
<
|
|
323
|
+
<ActionButton intent="config" type="button" onClick={handleReset}>
|
|
316
324
|
Reset
|
|
317
|
-
</
|
|
318
|
-
<
|
|
325
|
+
</ActionButton>
|
|
326
|
+
<ActionButton
|
|
327
|
+
intent="save"
|
|
319
328
|
type="submit"
|
|
320
|
-
size="sm"
|
|
321
329
|
disabled={isLoading || saveStatus === 'saving'}
|
|
322
|
-
className="border-dracula-green/40 bg-dracula-green/15 text-dracula-green hover:bg-dracula-green/25"
|
|
323
330
|
>
|
|
324
331
|
{saveStatus === 'saving' ? 'Saving...' : saveStatus === 'saved' ? 'Saved!' : 'Save'}
|
|
325
|
-
</
|
|
332
|
+
</ActionButton>
|
|
326
333
|
</div>
|
|
327
334
|
)}
|
|
328
335
|
</form>
|
|
@@ -391,14 +398,13 @@ const FieldRow: React.FC<{ index: number; onRemove: () => void }> = ({ index, on
|
|
|
391
398
|
</FormItem>
|
|
392
399
|
)}
|
|
393
400
|
/>
|
|
394
|
-
<
|
|
395
|
-
|
|
396
|
-
size="sm"
|
|
401
|
+
<ActionButton
|
|
402
|
+
intent="stop"
|
|
397
403
|
onClick={onRemove}
|
|
398
|
-
className="h-7
|
|
404
|
+
className="h-7 px-2 text-xs"
|
|
399
405
|
>
|
|
400
406
|
X
|
|
401
|
-
</
|
|
407
|
+
</ActionButton>
|
|
402
408
|
</div>
|
|
403
409
|
<FormField
|
|
404
410
|
control={control}
|
|
@@ -11,13 +11,18 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
14
|
-
import {
|
|
14
|
+
import { screen, waitFor } from '@testing-library/react';
|
|
15
|
+
import { renderWithProviders as render } from '../../../test/providers';
|
|
15
16
|
|
|
16
17
|
// --- Mocks -----------------------------------------------------------------
|
|
17
18
|
|
|
18
19
|
const storeState: { currentWorkflow: any } = { currentWorkflow: null };
|
|
20
|
+
// Threads the slice selector so `useAppStore((s) => s.currentWorkflow)`
|
|
21
|
+
// returns the right slice. A no-arg `useAppStore()` returns the whole
|
|
22
|
+
// state for legacy whole-store consumers.
|
|
19
23
|
vi.mock('../../../store/useAppStore', () => ({
|
|
20
|
-
useAppStore: () => storeState
|
|
24
|
+
useAppStore: <T,>(selector?: (state: typeof storeState) => T): T | typeof storeState =>
|
|
25
|
+
selector ? selector(storeState) : storeState,
|
|
21
26
|
}));
|
|
22
27
|
|
|
23
28
|
const wsMock = {
|
|
@@ -51,7 +51,7 @@ const AIResultModal: React.FC<AIResultModalProps> = ({ isOpen, onClose, result }
|
|
|
51
51
|
<div className="border-b border-border bg-muted p-4">
|
|
52
52
|
<div className="mb-2 flex items-start justify-between">
|
|
53
53
|
<div>
|
|
54
|
-
<h3 className="m-0 text-base font-semibold text-
|
|
54
|
+
<h3 className="m-0 font-display text-base font-semibold tracking-[var(--type-tracking-display)] text-fg-default [text-transform:var(--type-uppercase)]">
|
|
55
55
|
{result.nodeName} Result
|
|
56
56
|
</h3>
|
|
57
57
|
<p className="mt-1 mb-0 text-sm text-muted-foreground">
|
|
@@ -23,22 +23,26 @@ const CollapsibleSection: React.FC<CollapsibleSectionProps> = ({
|
|
|
23
23
|
const open = !isCollapsed;
|
|
24
24
|
return (
|
|
25
25
|
<Collapsible open={open} onOpenChange={() => onToggle()}>
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
{/* bg-bg-app + border-default for the outer card; bg-bg-elevated
|
|
27
|
+
on the trigger so the head sits above the body — matches the
|
|
28
|
+
handoff `.cat` / `.cat-head` two-tier surface. `cat` /
|
|
29
|
+
`cat-head` co-classes activate per-theme decorations. */}
|
|
30
|
+
<div className={cn('cat overflow-hidden rounded-lg border border-border-default bg-bg-app', isCollapsed && 'collapsed')}>
|
|
31
|
+
<CollapsibleTrigger className="cat-head flex w-full cursor-pointer items-center justify-between gap-2 border-none bg-bg-elevated px-4 py-3 text-base text-fg-default transition-colors hover:bg-bg-hover">
|
|
28
32
|
{typeof title === 'string' ? (
|
|
29
|
-
<span className="font-medium">{title}</span>
|
|
33
|
+
<span className="font-display font-medium">{title}</span>
|
|
30
34
|
) : (
|
|
31
35
|
<div className="flex flex-1 items-center">{title}</div>
|
|
32
36
|
)}
|
|
33
37
|
<ChevronDown
|
|
34
38
|
className={cn(
|
|
35
|
-
'h-3 w-3 shrink-0 text-muted
|
|
39
|
+
'h-3 w-3 shrink-0 text-fg-muted transition-transform',
|
|
36
40
|
isCollapsed && '-rotate-90'
|
|
37
41
|
)}
|
|
38
42
|
/>
|
|
39
43
|
</CollapsibleTrigger>
|
|
40
44
|
|
|
41
|
-
<CollapsibleContent className={cn('transition-[padding]', open && 'p-3')}>
|
|
45
|
+
<CollapsibleContent className={cn('cat-body transition-[padding]', open && 'p-3')}>
|
|
42
46
|
{children}
|
|
43
47
|
</CollapsibleContent>
|
|
44
48
|
</div>
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CommandPalette — global ⌘K (Ctrl+K) command launcher.
|
|
3
|
+
*
|
|
4
|
+
* Lightweight shell action surface inspired by the design handoff's
|
|
5
|
+
* `.cmdk` panel. Keeps a small registered command set in state; the
|
|
6
|
+
* Dashboard wires the actual handlers (`onOpenSettings`, etc.) via the
|
|
7
|
+
* `commands` prop. Composes on top of the cmdk library that ships with
|
|
8
|
+
* the codebase (CredentialsPalette uses the same dependency).
|
|
9
|
+
*
|
|
10
|
+
* Token-driven: chrome reads bg-bg-elevated + border-border-strong;
|
|
11
|
+
* active row reads bg-bg-active + text-accent. Under Renaissance the
|
|
12
|
+
* panel becomes an "open scroll" via the per-theme background image
|
|
13
|
+
* (declared in renaissance.css `.cmdk` block — wired through here by
|
|
14
|
+
* applying the `cmdk` class on the outer wrapper). Under Cyber it
|
|
15
|
+
* becomes a "root terminal" with neon-cyan border + scanlines.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import * as React from 'react';
|
|
19
|
+
import { useEffect } from 'react';
|
|
20
|
+
import { Command } from 'cmdk';
|
|
21
|
+
import { Search } from 'lucide-react';
|
|
22
|
+
import { Dialog, DialogPortal, DialogOverlay, DialogTitle, DialogDescription } from '@/components/ui/dialog';
|
|
23
|
+
import { Dialog as DialogPrimitive } from 'radix-ui';
|
|
24
|
+
import { cn } from '@/lib/utils';
|
|
25
|
+
|
|
26
|
+
export interface CommandItem {
|
|
27
|
+
id: string;
|
|
28
|
+
label: string;
|
|
29
|
+
hint?: string;
|
|
30
|
+
shortcut?: string;
|
|
31
|
+
/** lucide-react icon component */
|
|
32
|
+
icon?: React.ComponentType<{ className?: string }>;
|
|
33
|
+
/** Group label used to bucket items in the list. */
|
|
34
|
+
group?: string;
|
|
35
|
+
/** Invoked when the user presses Enter / clicks the row. */
|
|
36
|
+
onRun: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface CommandPaletteProps {
|
|
40
|
+
open: boolean;
|
|
41
|
+
onOpenChange: (open: boolean) => void;
|
|
42
|
+
commands: CommandItem[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const CommandPalette: React.FC<CommandPaletteProps> = ({ open, onOpenChange, commands }) => {
|
|
46
|
+
// ⌘K / Ctrl+K toggles the palette globally.
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const handler = (e: KeyboardEvent) => {
|
|
49
|
+
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
onOpenChange(!open);
|
|
52
|
+
} else if (e.key === 'Escape' && open) {
|
|
53
|
+
onOpenChange(false);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
window.addEventListener('keydown', handler);
|
|
57
|
+
return () => window.removeEventListener('keydown', handler);
|
|
58
|
+
}, [open, onOpenChange]);
|
|
59
|
+
|
|
60
|
+
// Bucket commands by group so the list renders Command.Group sections.
|
|
61
|
+
const groups = React.useMemo(() => {
|
|
62
|
+
const buckets: Record<string, CommandItem[]> = {};
|
|
63
|
+
for (const cmd of commands) {
|
|
64
|
+
const key = cmd.group ?? 'Actions';
|
|
65
|
+
(buckets[key] ??= []).push(cmd);
|
|
66
|
+
}
|
|
67
|
+
return buckets;
|
|
68
|
+
}, [commands]);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
72
|
+
<DialogPortal>
|
|
73
|
+
<DialogOverlay className="bg-bg-overlay" />
|
|
74
|
+
<DialogPrimitive.Content
|
|
75
|
+
data-slot="command-palette"
|
|
76
|
+
className={cn(
|
|
77
|
+
// `cmdk` class is the per-theme decorative hook (renaissance
|
|
78
|
+
// and cyber CSS apply backgrounds + borders + scanlines via
|
|
79
|
+
// `:root[data-theme="..."] .cmdk`).
|
|
80
|
+
'cmdk fixed left-1/2 top-[14%] z-50 w-[min(560px,92vw)] -translate-x-1/2 overflow-hidden rounded-md border border-border-strong bg-bg-elevated shadow-2xl outline-none',
|
|
81
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 duration-100',
|
|
82
|
+
)}
|
|
83
|
+
>
|
|
84
|
+
<DialogTitle className="sr-only">Command palette</DialogTitle>
|
|
85
|
+
<DialogDescription className="sr-only">Run a command from the keyboard</DialogDescription>
|
|
86
|
+
|
|
87
|
+
<Command label="Command palette" className="flex flex-col" shouldFilter>
|
|
88
|
+
<div className="relative border-b border-border-default px-4">
|
|
89
|
+
<Search className="pointer-events-none absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-fg-muted" />
|
|
90
|
+
<Command.Input
|
|
91
|
+
placeholder="Type a command or search..."
|
|
92
|
+
autoFocus
|
|
93
|
+
className="h-12 w-full bg-transparent pl-7 font-display text-[15px] tracking-[var(--type-tracking-display)] text-fg-default placeholder:text-fg-faint focus:outline-none [text-transform:var(--type-uppercase)]"
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<Command.List className="max-h-[360px] overflow-y-auto p-1.5">
|
|
98
|
+
<Command.Empty className="px-3 py-6 text-center text-sm text-fg-muted">
|
|
99
|
+
No matching commands
|
|
100
|
+
</Command.Empty>
|
|
101
|
+
|
|
102
|
+
{Object.entries(groups).map(([groupName, items]) => (
|
|
103
|
+
<Command.Group
|
|
104
|
+
key={groupName}
|
|
105
|
+
heading={groupName}
|
|
106
|
+
className="px-1 py-1 text-[10px] font-semibold uppercase tracking-wider text-fg-faint"
|
|
107
|
+
>
|
|
108
|
+
{items.map((cmd) => {
|
|
109
|
+
const Icon = cmd.icon;
|
|
110
|
+
return (
|
|
111
|
+
<Command.Item
|
|
112
|
+
key={cmd.id}
|
|
113
|
+
value={`${cmd.label} ${cmd.hint ?? ''}`}
|
|
114
|
+
onSelect={() => {
|
|
115
|
+
onOpenChange(false);
|
|
116
|
+
// Defer the action one frame so the dialog
|
|
117
|
+
// closes cleanly before the handler fires
|
|
118
|
+
// (avoids focus-trap clashes when the action
|
|
119
|
+
// opens another modal).
|
|
120
|
+
requestAnimationFrame(() => cmd.onRun());
|
|
121
|
+
}}
|
|
122
|
+
className="flex cursor-pointer items-center gap-3 rounded-sm px-3 py-2 text-sm text-fg-default data-[selected=true]:bg-bg-active data-[selected=true]:text-accent"
|
|
123
|
+
>
|
|
124
|
+
{Icon && <Icon className="h-4 w-4 shrink-0" />}
|
|
125
|
+
<span className="flex-1 truncate font-display">{cmd.label}</span>
|
|
126
|
+
{cmd.hint && (
|
|
127
|
+
<span className="font-mono text-[11px] text-fg-faint">{cmd.hint}</span>
|
|
128
|
+
)}
|
|
129
|
+
{cmd.shortcut && (
|
|
130
|
+
<kbd className="ml-auto rounded-sm border border-border-default bg-bg-app px-1.5 py-0.5 font-mono text-[10px] text-fg-muted">
|
|
131
|
+
{cmd.shortcut}
|
|
132
|
+
</kbd>
|
|
133
|
+
)}
|
|
134
|
+
</Command.Item>
|
|
135
|
+
);
|
|
136
|
+
})}
|
|
137
|
+
</Command.Group>
|
|
138
|
+
))}
|
|
139
|
+
</Command.List>
|
|
140
|
+
</Command>
|
|
141
|
+
</DialogPrimitive.Content>
|
|
142
|
+
</DialogPortal>
|
|
143
|
+
</Dialog>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default CommandPalette;
|