cli-jaw 2.1.1 → 2.1.3
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.ja.md +8 -6
- package/README.ko.md +8 -6
- package/README.md +18 -11
- package/README.zh-CN.md +8 -6
- package/dist/bin/cli-jaw.js +19 -3
- package/dist/bin/cli-jaw.js.map +1 -1
- package/dist/bin/commands/browser.js +1 -1
- package/dist/bin/commands/browser.js.map +1 -1
- package/dist/bin/commands/chat-search.js +71 -0
- package/dist/bin/commands/chat-search.js.map +1 -0
- package/dist/bin/commands/chat.js +98 -58
- package/dist/bin/commands/chat.js.map +1 -1
- package/dist/bin/commands/dispatch.js +130 -5
- package/dist/bin/commands/dispatch.js.map +1 -1
- package/dist/bin/commands/goal.js +66 -9
- package/dist/bin/commands/goal.js.map +1 -1
- package/dist/bin/commands/history.js +61 -0
- package/dist/bin/commands/history.js.map +1 -0
- package/dist/bin/commands/lock.js +104 -0
- package/dist/bin/commands/lock.js.map +1 -0
- package/dist/bin/commands/memory.js +23 -2
- package/dist/bin/commands/memory.js.map +1 -1
- package/dist/bin/commands/orchestrate.js.map +1 -1
- package/dist/bin/commands/project.js +4 -1
- package/dist/bin/commands/project.js.map +1 -1
- package/dist/bin/commands/tui/fullscreen-mode.js +237 -0
- package/dist/bin/commands/tui/fullscreen-mode.js.map +1 -0
- package/dist/bin/commands/tui/input-handler.js +139 -52
- package/dist/bin/commands/tui/input-handler.js.map +1 -1
- package/dist/bin/commands/tui/overlays.js +177 -70
- package/dist/bin/commands/tui/overlays.js.map +1 -1
- package/dist/bin/commands/tui/renderer.js +70 -20
- package/dist/bin/commands/tui/renderer.js.map +1 -1
- package/dist/bin/commands/tui/simple-mode.js +1 -2
- package/dist/bin/commands/tui/simple-mode.js.map +1 -1
- package/dist/bin/commands/tui/tui-io.js +8 -0
- package/dist/bin/commands/tui/tui-io.js.map +1 -0
- package/dist/bin/commands/tui/types.js +9 -0
- package/dist/bin/commands/tui/types.js.map +1 -1
- package/dist/bin/commands/tui/ws-handler.js +115 -23
- package/dist/bin/commands/tui/ws-handler.js.map +1 -1
- package/dist/bin/commands/worker.js +159 -0
- package/dist/bin/commands/worker.js.map +1 -0
- package/dist/bin/postinstall.js +0 -76
- package/dist/bin/postinstall.js.map +1 -1
- package/dist/lib/mcp/format-converters.js +21 -2
- package/dist/lib/mcp/format-converters.js.map +1 -1
- package/dist/lib/mcp/mcp-registry.js +75 -0
- package/dist/lib/mcp/mcp-registry.js.map +1 -0
- package/dist/lib/stt.js +1 -1
- package/dist/lib/stt.js.map +1 -1
- package/dist/lib/upload.js +7 -0
- package/dist/lib/upload.js.map +1 -1
- package/dist/scripts/fresh-install-smoke.js +1 -1
- package/dist/scripts/fresh-install-smoke.js.map +1 -1
- package/dist/server.js +151 -22
- package/dist/server.js.map +1 -1
- package/dist/src/agent/agy-runtime.js +1 -0
- package/dist/src/agent/agy-runtime.js.map +1 -1
- package/dist/src/agent/agy-transcript-watcher.js +78 -0
- package/dist/src/agent/agy-transcript-watcher.js.map +1 -0
- package/dist/src/agent/agy-transcript.js +158 -0
- package/dist/src/agent/agy-transcript.js.map +1 -0
- package/dist/src/agent/args.js +51 -5
- package/dist/src/agent/args.js.map +1 -1
- package/dist/src/agent/claude-e-runtime.js +1 -1
- package/dist/src/agent/claude-e-runtime.js.map +1 -1
- package/dist/src/agent/codex-app-client.js +2 -2
- package/dist/src/agent/codex-app-client.js.map +1 -1
- package/dist/src/agent/cursor-runtime.js +1 -0
- package/dist/src/agent/cursor-runtime.js.map +1 -1
- package/dist/src/agent/error-classifier.js +6 -1
- package/dist/src/agent/error-classifier.js.map +1 -1
- package/dist/src/agent/events/claude.js +1 -0
- package/dist/src/agent/events/claude.js.map +1 -1
- package/dist/src/agent/events/codex.js +0 -44
- package/dist/src/agent/events/codex.js.map +1 -1
- package/dist/src/agent/events/helpers.js +52 -5
- package/dist/src/agent/events/helpers.js.map +1 -1
- package/dist/src/agent/events/opencode.js +6 -2
- package/dist/src/agent/events/opencode.js.map +1 -1
- package/dist/src/agent/events/summary.js +3 -2
- package/dist/src/agent/events/summary.js.map +1 -1
- package/dist/src/agent/events/tool-labels.js +8 -5
- package/dist/src/agent/events/tool-labels.js.map +1 -1
- package/dist/src/agent/kiro-auth.js +213 -0
- package/dist/src/agent/kiro-auth.js.map +1 -0
- package/dist/src/agent/kiro-models.js +79 -0
- package/dist/src/agent/kiro-models.js.map +1 -0
- package/dist/src/agent/kiro-runtime.js +314 -0
- package/dist/src/agent/kiro-runtime.js.map +1 -0
- package/dist/src/agent/lifecycle-handler.js +208 -23
- package/dist/src/agent/lifecycle-handler.js.map +1 -1
- package/dist/src/agent/memory-flush-controller.js +3 -4
- package/dist/src/agent/memory-flush-controller.js.map +1 -1
- package/dist/src/agent/resume-classifier.js +18 -1
- package/dist/src/agent/resume-classifier.js.map +1 -1
- package/dist/src/agent/session-persistence.js +2 -2
- package/dist/src/agent/session-persistence.js.map +1 -1
- package/dist/src/agent/smoke-detector.js +3 -0
- package/dist/src/agent/smoke-detector.js.map +1 -1
- package/dist/src/agent/spawn/queue.js +11 -5
- package/dist/src/agent/spawn/queue.js.map +1 -1
- package/dist/src/agent/spawn/resume.js +6 -1
- package/dist/src/agent/spawn/resume.js.map +1 -1
- package/dist/src/agent/spawn-env.js +1 -1
- package/dist/src/agent/spawn-env.js.map +1 -1
- package/dist/src/agent/spawn.js +231 -43
- package/dist/src/agent/spawn.js.map +1 -1
- package/dist/src/agent/watchdog.js +1 -1
- package/dist/src/agent/watchdog.js.map +1 -1
- package/dist/src/browser/actions.js +0 -8
- package/dist/src/browser/actions.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/browser-escalation.js +5 -29
- package/dist/src/browser/adaptive-fetch/browser-escalation.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/browser-runtime.js +5 -14
- package/dist/src/browser/adaptive-fetch/browser-runtime.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/browser-session.js +14 -28
- package/dist/src/browser/adaptive-fetch/browser-session.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/challenge-detector.js +4 -26
- package/dist/src/browser/adaptive-fetch/challenge-detector.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/content-scorer.js +5 -29
- package/dist/src/browser/adaptive-fetch/content-scorer.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/endpoint-resolvers.js +0 -64
- package/dist/src/browser/adaptive-fetch/endpoint-resolvers.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/fetcher.js +4 -19
- package/dist/src/browser/adaptive-fetch/fetcher.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/human-loop.js +0 -26
- package/dist/src/browser/adaptive-fetch/human-loop.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/index.js +74 -145
- package/dist/src/browser/adaptive-fetch/index.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/metadata.js +1 -41
- package/dist/src/browser/adaptive-fetch/metadata.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/output.js +1 -18
- package/dist/src/browser/adaptive-fetch/output.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/reader-adapters.js +43 -75
- package/dist/src/browser/adaptive-fetch/reader-adapters.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/safety.js +5 -48
- package/dist/src/browser/adaptive-fetch/safety.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/third-party-readers.js +0 -11
- package/dist/src/browser/adaptive-fetch/third-party-readers.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/trace.js +3 -18
- package/dist/src/browser/adaptive-fetch/trace.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/transforms.js +0 -23
- package/dist/src/browser/adaptive-fetch/transforms.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/types.js +3 -0
- package/dist/src/browser/adaptive-fetch/types.js.map +1 -0
- package/dist/src/browser/adaptive-fetch/validators.js +0 -17
- package/dist/src/browser/adaptive-fetch/validators.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/waf-profiles.js +0 -10
- package/dist/src/browser/adaptive-fetch/waf-profiles.js.map +1 -1
- package/dist/src/browser/connection.js +1 -1
- package/dist/src/browser/connection.js.map +1 -1
- package/dist/src/browser/web-ai/chatgpt-response.js +0 -1
- package/dist/src/browser/web-ai/chatgpt-response.js.map +1 -1
- package/dist/src/browser/web-ai/chatgpt.js +0 -33
- package/dist/src/browser/web-ai/chatgpt.js.map +1 -1
- package/dist/src/browser/web-ai/diagnostics.js +0 -16
- package/dist/src/browser/web-ai/diagnostics.js.map +1 -1
- package/dist/src/browser/web-ai/doctor.js.map +1 -1
- package/dist/src/browser/web-ai/errors.js +1 -1
- package/dist/src/browser/web-ai/errors.js.map +1 -1
- package/dist/src/browser/web-ai/grok-live.js +2 -0
- package/dist/src/browser/web-ai/grok-live.js.map +1 -1
- package/dist/src/cli/claude-models.js +2 -2
- package/dist/src/cli/claude-models.js.map +1 -1
- package/dist/src/cli/command-context.js.map +1 -1
- package/dist/src/cli/commands.js +16 -4
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/compact.js +2 -1
- package/dist/src/cli/compact.js.map +1 -1
- package/dist/src/cli/handlers/session-handlers.js +34 -0
- package/dist/src/cli/handlers/session-handlers.js.map +1 -0
- package/dist/src/cli/handlers-project.js.map +1 -1
- package/dist/src/cli/handlers-runtime.js +2 -0
- package/dist/src/cli/handlers-runtime.js.map +1 -1
- package/dist/src/cli/handlers-workflows.js +85 -17
- package/dist/src/cli/handlers-workflows.js.map +1 -1
- package/dist/src/cli/handlers.js +84 -43
- package/dist/src/cli/handlers.js.map +1 -1
- package/dist/src/cli/readiness.js +17 -1
- package/dist/src/cli/readiness.js.map +1 -1
- package/dist/src/cli/registry-live.js +17 -0
- package/dist/src/cli/registry-live.js.map +1 -0
- package/dist/src/cli/registry.js +51 -10
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/cli/tui/composer.js +135 -5
- package/dist/src/cli/tui/composer.js.map +1 -1
- package/dist/src/cli/tui/diffview.js +41 -0
- package/dist/src/cli/tui/diffview.js.map +1 -0
- package/dist/src/cli/tui/editor.js +45 -0
- package/dist/src/cli/tui/editor.js.map +1 -0
- package/dist/src/cli/tui/file-mention.js +78 -0
- package/dist/src/cli/tui/file-mention.js.map +1 -0
- package/dist/src/cli/tui/highlight.js +82 -0
- package/dist/src/cli/tui/highlight.js.map +1 -0
- package/dist/src/cli/tui/keymap.js +21 -0
- package/dist/src/cli/tui/keymap.js.map +1 -1
- package/dist/src/cli/tui/markdown.js +124 -0
- package/dist/src/cli/tui/markdown.js.map +1 -0
- package/dist/src/cli/tui/mode.js +26 -0
- package/dist/src/cli/tui/mode.js.map +1 -0
- package/dist/src/cli/tui/overlay.js +121 -98
- package/dist/src/cli/tui/overlay.js.map +1 -1
- package/dist/src/cli/tui/render/frame.js +72 -0
- package/dist/src/cli/tui/render/frame.js.map +1 -0
- package/dist/src/cli/tui/render/layout.js +22 -0
- package/dist/src/cli/tui/render/layout.js.map +1 -0
- package/dist/src/cli/tui/render/mouse.js +25 -0
- package/dist/src/cli/tui/render/mouse.js.map +1 -0
- package/dist/src/cli/tui/render/scheduler.js +37 -0
- package/dist/src/cli/tui/render/scheduler.js.map +1 -0
- package/dist/src/cli/tui/render/viewport.js +82 -0
- package/dist/src/cli/tui/render/viewport.js.map +1 -0
- package/dist/src/cli/tui/renderers.js +37 -0
- package/dist/src/cli/tui/renderers.js.map +1 -1
- package/dist/src/cli/tui/stream.js +48 -0
- package/dist/src/cli/tui/stream.js.map +1 -0
- package/dist/src/cli/tui/text-buffer.js +143 -0
- package/dist/src/cli/tui/text-buffer.js.map +1 -0
- package/dist/src/cli/tui/theme.js +128 -0
- package/dist/src/cli/tui/theme.js.map +1 -0
- package/dist/src/cli/tui/transcript.js +4 -0
- package/dist/src/cli/tui/transcript.js.map +1 -1
- package/dist/src/command-contract/help-renderer.js +1 -1
- package/dist/src/command-contract/help-renderer.js.map +1 -1
- package/dist/src/core/chat-sessions.js +63 -0
- package/dist/src/core/chat-sessions.js.map +1 -0
- package/dist/src/core/cli-detection.js +14 -0
- package/dist/src/core/cli-detection.js.map +1 -1
- package/dist/src/core/compact.js +43 -11
- package/dist/src/core/compact.js.map +1 -1
- package/dist/src/core/config.js +14 -1
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/db.js +52 -12
- package/dist/src/core/db.js.map +1 -1
- package/dist/src/core/employees.js +2 -2
- package/dist/src/core/employees.js.map +1 -1
- package/dist/src/core/main-session.js +3 -2
- package/dist/src/core/main-session.js.map +1 -1
- package/dist/src/discord/bot.js.map +1 -1
- package/dist/src/discord/discord-file.js +1 -1
- package/dist/src/discord/discord-file.js.map +1 -1
- package/dist/src/discord/send-only-client.js +1 -3
- package/dist/src/discord/send-only-client.js.map +1 -1
- package/dist/src/goal/heartbeat.js +113 -7
- package/dist/src/goal/heartbeat.js.map +1 -1
- package/dist/src/goal/store.js +44 -5
- package/dist/src/goal/store.js.map +1 -1
- package/dist/src/ide/diff.js +37 -0
- package/dist/src/ide/diff.js.map +1 -1
- package/dist/src/manager/launchd-service.js +1 -1
- package/dist/src/manager/launchd-service.js.map +1 -1
- package/dist/src/manager/lifecycle-helpers.js +14 -0
- package/dist/src/manager/lifecycle-helpers.js.map +1 -1
- package/dist/src/manager/lifecycle-store.js.map +1 -1
- package/dist/src/manager/lifecycle.js +94 -5
- package/dist/src/manager/lifecycle.js.map +1 -1
- package/dist/src/manager/notes/routes.js +0 -31
- package/dist/src/manager/notes/routes.js.map +1 -1
- package/dist/src/manager/notes/ws.js.map +1 -1
- package/dist/src/manager/preview-link-policy.js +11 -4
- package/dist/src/manager/preview-link-policy.js.map +1 -1
- package/dist/src/manager/registry.js.map +1 -1
- package/dist/src/manager/routes/dashboard-memory.js.map +1 -1
- package/dist/src/manager/scan.js +36 -1
- package/dist/src/manager/scan.js.map +1 -1
- package/dist/src/manager/server.js +42 -7
- package/dist/src/manager/server.js.map +1 -1
- package/dist/src/manager/shutdown.js +8 -3
- package/dist/src/manager/shutdown.js.map +1 -1
- package/dist/src/manager/systemd-service.js +1 -1
- package/dist/src/manager/systemd-service.js.map +1 -1
- package/dist/src/memory/indexing.js +49 -1
- package/dist/src/memory/indexing.js.map +1 -1
- package/dist/src/memory/keyword-expand.js +0 -187
- package/dist/src/memory/keyword-expand.js.map +1 -1
- package/dist/src/memory/runtime.js +3 -2
- package/dist/src/memory/runtime.js.map +1 -1
- package/dist/src/memory/shared.js.map +1 -1
- package/dist/src/messaging/send.js +66 -7
- package/dist/src/messaging/send.js.map +1 -1
- package/dist/src/orchestrator/collect.js +3 -2
- package/dist/src/orchestrator/collect.js.map +1 -1
- package/dist/src/orchestrator/distribute.js +9 -3
- package/dist/src/orchestrator/distribute.js.map +1 -1
- package/dist/src/orchestrator/friction.js +59 -0
- package/dist/src/orchestrator/friction.js.map +1 -0
- package/dist/src/orchestrator/gateway.js +4 -4
- package/dist/src/orchestrator/gateway.js.map +1 -1
- package/dist/src/orchestrator/pipeline.js +89 -45
- package/dist/src/orchestrator/pipeline.js.map +1 -1
- package/dist/src/orchestrator/sanitize.js +69 -0
- package/dist/src/orchestrator/sanitize.js.map +1 -0
- package/dist/src/orchestrator/seed.js +50 -0
- package/dist/src/orchestrator/seed.js.map +1 -0
- package/dist/src/orchestrator/state-machine.js +215 -76
- package/dist/src/orchestrator/state-machine.js.map +1 -1
- package/dist/src/orchestrator/worker-monitor.js +1 -1
- package/dist/src/orchestrator/worker-monitor.js.map +1 -1
- package/dist/src/orchestrator/worker-progress.js +29 -0
- package/dist/src/orchestrator/worker-progress.js.map +1 -0
- package/dist/src/orchestrator/worker-registry.js +63 -2
- package/dist/src/orchestrator/worker-registry.js.map +1 -1
- package/dist/src/prompt/builder.js +190 -115
- package/dist/src/prompt/builder.js.map +1 -1
- package/dist/src/prompt/templates/a1-system.md +124 -61
- package/dist/src/prompt/templates/control-system.md +2 -2
- package/dist/src/prompt/templates/employee.md +41 -56
- package/dist/src/prompt/templates/orchestration.md +23 -8
- package/dist/src/prompt/templates/skills.md +6 -0
- package/dist/src/routes/browser.js +3 -3
- package/dist/src/routes/browser.js.map +1 -1
- package/dist/src/routes/employees.js +4 -4
- package/dist/src/routes/employees.js.map +1 -1
- package/dist/src/routes/goal.js +48 -4
- package/dist/src/routes/goal.js.map +1 -1
- package/dist/src/routes/heartbeat.js +1 -1
- package/dist/src/routes/heartbeat.js.map +1 -1
- package/dist/src/routes/i18n.js +1 -1
- package/dist/src/routes/i18n.js.map +1 -1
- package/dist/src/routes/jaw-memory.js +1 -1
- package/dist/src/routes/jaw-memory.js.map +1 -1
- package/dist/src/routes/memory.js.map +1 -1
- package/dist/src/routes/messaging.js +8 -3
- package/dist/src/routes/messaging.js.map +1 -1
- package/dist/src/routes/orchestrate.js +267 -117
- package/dist/src/routes/orchestrate.js.map +1 -1
- package/dist/src/routes/quota-agy-reverse.js +6 -5
- package/dist/src/routes/quota-agy-reverse.js.map +1 -1
- package/dist/src/routes/quota-kiro-reverse.js +187 -0
- package/dist/src/routes/quota-kiro-reverse.js.map +1 -0
- package/dist/src/routes/quota.js +68 -6
- package/dist/src/routes/quota.js.map +1 -1
- package/dist/src/routes/settings.js +37 -8
- package/dist/src/routes/settings.js.map +1 -1
- package/dist/src/routes/skills.js.map +1 -1
- package/dist/src/security/path-guards.js +0 -3
- package/dist/src/security/path-guards.js.map +1 -1
- package/dist/src/security/security-audit-log.js.map +1 -1
- package/dist/src/shared/shell-command-display.js +51 -0
- package/dist/src/shared/shell-command-display.js.map +1 -0
- package/dist/src/telegram/bot.js.map +1 -1
- package/dist/src/trace/store.js +32 -0
- package/dist/src/trace/store.js.map +1 -1
- package/dist/src/types/cli-engine.js +1 -0
- package/dist/src/types/cli-engine.js.map +1 -1
- package/dist/src/workflows/employee-boundary.js +7 -7
- package/dist/src/workflows/employee-boundary.js.map +1 -1
- package/dist/src/workflows/handoff.js +16 -16
- package/dist/src/workflows/handoff.js.map +1 -1
- package/dist/src/workflows/scope-sandbox.js +58 -0
- package/dist/src/workflows/scope-sandbox.js.map +1 -0
- package/package.json +1 -1
- package/public/assets/providers/kiro-color.svg +15 -0
- package/public/assets/providers/kiro.svg +14 -0
- package/public/css/chat.css +27 -0
- package/public/css/modals.css +79 -0
- package/public/css/orc-state.css +10 -6
- package/public/css/sidebar.css +85 -0
- package/public/css/variables.css +6 -2
- package/public/dist/assets/{Agent-CIUGaUVn.js → Agent-DBKNQ6tp.js} +1 -1
- package/public/dist/assets/{DocPanel-C1pGgE-S.js → DocPanel-BU16GUlB.js} +1 -1
- package/public/dist/assets/DocPanel-gU-WkgyA.css +1 -0
- package/public/dist/assets/Employees-F0ssNuO-.js +1 -0
- package/public/dist/assets/{FolderPanel-DSkanaGN.js → FolderPanel-DT0fU8f2.js} +1 -1
- package/public/dist/assets/Heartbeat-fsuLzY9c.js +1 -0
- package/public/dist/assets/Mcp-_Yq4N3Sk.js +4 -0
- package/public/dist/assets/{Memory-BgN8djV4.js → Memory-CRR8kotI.js} +1 -1
- package/public/dist/assets/{ModelProvider-DHQ1Zvw0.js → ModelProvider-DQgISbKw.js} +1 -1
- package/public/dist/assets/agent-meta-C4mauPL5.js +1 -0
- package/public/dist/assets/app-0OQhPpTG.css +1 -0
- package/public/dist/assets/app-CSqIyg9A.js +55 -0
- package/public/dist/assets/constants-BHMkzpN_.js +1 -0
- package/public/dist/assets/{employees-DiNLzEXS.js → employees-CZdWHH-r.js} +7 -7
- package/public/dist/assets/idb-cache-0LNMskFB.js +1 -0
- package/public/dist/assets/idb-cache-5H89a4l8.js +1 -0
- package/public/dist/assets/manager-CGTQ5EIm.js +12 -0
- package/public/dist/assets/manager-UBunDqMH.css +1 -0
- package/public/dist/assets/{memory-B_nn0A4v.js → memory-B3QSmj_e.js} +9 -9
- package/public/dist/assets/memory-DOBqiuPc.js +1 -0
- package/public/dist/assets/{provider-icons-XEfJPGTe.js → provider-icons-Crv6yvlG.js} +35 -6
- package/public/dist/assets/render-J11oxfnl.js +28 -0
- package/public/dist/assets/settings-BV_2Bh0_.js +1 -0
- package/public/dist/assets/settings-m_cim0ov.js +151 -0
- package/public/dist/assets/sidebar-ZBXdBgF7.js +49 -0
- package/public/dist/assets/{skills-COa4iSwL.js → skills-CjaBmIPV.js} +6 -6
- package/public/dist/assets/skills-Xm3fl1zr.js +1 -0
- package/public/dist/assets/{slash-commands-C_ePvrPi.js → slash-commands-71jc07Wf.js} +1 -1
- package/public/dist/assets/slash-commands-BO6ssnAz.js +1 -0
- package/public/dist/assets/{trace-drawer-CY4z_Ie8.js → trace-drawer-Czvf2P2o.js} +1 -1
- package/public/dist/assets/ui-CverZJnd.js +1 -0
- package/public/dist/assets/ui-qKxy-4p9.js +142 -0
- package/public/dist/index.html +113 -86
- package/public/dist/manager/index.html +2 -2
- package/public/index.html +111 -84
- package/public/js/constants.ts +34 -11
- package/public/js/features/chat-messages.ts +13 -2
- package/public/js/features/chat-search.ts +5 -1
- package/public/js/features/chat.ts +86 -44
- package/public/js/features/employees.ts +7 -2
- package/public/js/features/idb-cache.ts +4 -0
- package/public/js/features/media-lightbox.ts +40 -0
- package/public/js/features/message-history.ts +55 -7
- package/public/js/features/pending-queue.ts +28 -4
- package/public/js/features/process-block.ts +32 -17
- package/public/js/features/process-log-adapter.ts +11 -2
- package/public/js/features/settings-cli-status-render.ts +161 -0
- package/public/js/features/settings-cli-status.ts +136 -187
- package/public/js/features/settings-core.ts +5 -1
- package/public/js/features/settings-mcp.ts +513 -7
- package/public/js/features/settings-types.ts +1 -0
- package/public/js/features/settings.ts +1 -1
- package/public/js/features/tool-ui.ts +18 -4
- package/public/js/features/transport-status-row.ts +3 -0
- package/public/js/features/ui-status.ts +5 -1
- package/public/js/main.ts +5 -0
- package/public/js/preview-parent-origin.ts +14 -0
- package/public/js/provider-icons.ts +6 -1
- package/public/js/render/file-links.ts +10 -2
- package/public/js/render/markdown.ts +16 -0
- package/public/js/ui.ts +8 -1
- package/public/js/virtual-scroll.ts +19 -0
- package/public/js/ws.ts +151 -15
- package/public/locales/en.json +9 -2
- package/public/locales/ja.json +9 -2
- package/public/locales/ko.json +9 -2
- package/public/locales/zh.json +9 -2
- package/public/manager/src/App.tsx +13 -70
- package/public/manager/src/InstancePreview.tsx +56 -11
- package/public/manager/src/SidebarRailRouter.tsx +32 -4
- package/public/manager/src/components/InstanceRow.tsx +0 -1
- package/public/manager/src/components/WorkbenchHeader.tsx +17 -7
- package/public/manager/src/doc-panel/DocPanel.tsx +14 -1
- package/public/manager/src/doc-panel/doc-panel.css +16 -0
- package/public/manager/src/folder-panel/FolderPanel.tsx +13 -2
- package/public/manager/src/hooks/useElectronDroppedPaths.ts +89 -0
- package/public/manager/src/hooks/useInstanceMessageEvents.ts +4 -15
- package/public/manager/src/manager-components.css +35 -1
- package/public/manager/src/manager-polish.css +11 -1
- package/public/manager/src/manager-shortcut-runner.ts +107 -0
- package/public/manager/src/manager-shortcuts.ts +15 -0
- package/public/manager/src/panels/desktop-bridge.ts +13 -0
- package/public/manager/src/settings/SettingsSidebar.tsx +1 -1
- package/public/manager/src/settings/components/sidebar-filter.ts +2 -0
- package/public/manager/src/settings/pages/Mcp.tsx +311 -43
- package/public/manager/src/settings/pages/components/McpServerCard.tsx +89 -55
- package/public/manager/src/settings/pages/components/agent/agent-meta.ts +32 -9
- package/public/manager/src/settings/pages/components/employees-helpers.ts +1 -0
- package/public/manager/src/settings/pages/components/heartbeat-helpers.ts +1 -0
- package/public/manager/src/settings/pages/mcp-helpers.ts +54 -12
- package/public/manager/src/settings/types.ts +1 -0
- package/public/manager/src/types.ts +2 -1
- package/scripts/fresh-install-smoke.ts +1 -1
- package/scripts/smoke/agy-transcript-tail-smoke.mjs +89 -0
- package/public/dist/assets/DocPanel-CL1scIfq.css +0 -1
- package/public/dist/assets/Employees-BL9MAzzx.js +0 -1
- package/public/dist/assets/Heartbeat-D64JCg4t.js +0 -1
- package/public/dist/assets/Mcp-wYwJA_61.js +0 -3
- package/public/dist/assets/agent-meta-BhEbjy4P.js +0 -1
- package/public/dist/assets/app-2Rz848bQ.js +0 -48
- package/public/dist/assets/app-BW-Xz2p6.css +0 -1
- package/public/dist/assets/constants-ahKI_aEG.js +0 -1
- package/public/dist/assets/idb-cache-BnZfG5FD.js +0 -1
- package/public/dist/assets/idb-cache-CZ3JdK8r.js +0 -1
- package/public/dist/assets/manager-CfyZloIP.js +0 -12
- package/public/dist/assets/manager-DyrwJLZr.css +0 -1
- package/public/dist/assets/memory-CCjNFWmO.js +0 -1
- package/public/dist/assets/render-CgDEBoCX.js +0 -28
- package/public/dist/assets/settings-CY_6tGuS.js +0 -1
- package/public/dist/assets/settings-DWW4GzNc.js +0 -66
- package/public/dist/assets/sidebar-DQKE5IA1.js +0 -23
- package/public/dist/assets/skills-DYTlqoke.js +0 -1
- package/public/dist/assets/slash-commands-D7CU5oso.js +0 -1
- package/public/dist/assets/ui-Car1OUvV.js +0 -1
- package/public/dist/assets/ui-DK_9ndj0.js +0 -140
- /package/public/dist/assets/{locale-DT1WRaeJ.js → locale-BHMJIzyw.js} +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { DashboardDetailTab, DashboardInstance, DashboardShortcutAction, DashboardSidebarMode } from './types';
|
|
2
|
+
import { panelShortcutBus } from './panels/panel-shortcut-bus';
|
|
3
|
+
import { getDesktop } from './panels/desktop-bridge';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Dependencies the manager keyboard-shortcut runner needs from <App>.
|
|
7
|
+
* Extracted from App.tsx to keep the component under the dashboard line budget;
|
|
8
|
+
* behaviour is identical — App passes current render values on every call.
|
|
9
|
+
*/
|
|
10
|
+
export interface ManagerShortcutRunnerDeps {
|
|
11
|
+
selectedInstance: DashboardInstance | null;
|
|
12
|
+
filtered: DashboardInstance[];
|
|
13
|
+
activeDetailTab: DashboardDetailTab;
|
|
14
|
+
setDrawerOpen: (open: boolean) => void;
|
|
15
|
+
handleSidebarModeChange: (mode: DashboardSidebarMode) => void;
|
|
16
|
+
handlePreview: (instance: DashboardInstance) => void;
|
|
17
|
+
selectRelativeInstance: (direction: 1 | -1) => void;
|
|
18
|
+
handleTabChange: (tab: DashboardDetailTab) => void;
|
|
19
|
+
setPreviewRefreshKey: (updater: (key: number) => number) => void;
|
|
20
|
+
handleSidebarToggle: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function runManagerShortcut(action: DashboardShortcutAction, deps: ManagerShortcutRunnerDeps): void {
|
|
24
|
+
if (panelShortcutBus.dispatch(action)) return;
|
|
25
|
+
if (action === 'focusInstances') {
|
|
26
|
+
deps.handleSidebarModeChange('instances');
|
|
27
|
+
deps.setDrawerOpen(false);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (action === 'focusActiveSession') {
|
|
31
|
+
const target = deps.selectedInstance?.ok
|
|
32
|
+
? deps.selectedInstance
|
|
33
|
+
: deps.filtered.find(instance => instance.ok) || null;
|
|
34
|
+
if (target) deps.handlePreview(target);
|
|
35
|
+
else deps.handleSidebarModeChange('instances');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (action === 'focusNotes') {
|
|
39
|
+
deps.handleSidebarModeChange('notes');
|
|
40
|
+
deps.setDrawerOpen(false);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (action === 'previousInstance') {
|
|
44
|
+
deps.selectRelativeInstance(-1);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (action === 'nextInstance') {
|
|
48
|
+
deps.selectRelativeInstance(1);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (action === 'closeFocusedTab') {
|
|
52
|
+
const active = document.activeElement;
|
|
53
|
+
if (active?.closest('.browser-webview-stack, .browser-tab-strip')) {
|
|
54
|
+
document.dispatchEvent(new CustomEvent('jaw:shortcut-action', { detail: 'closeBrowserTab' }));
|
|
55
|
+
} else if (active?.closest('.terminal-panel, .xterm')) {
|
|
56
|
+
document.dispatchEvent(new CustomEvent('jaw:shortcut-action', { detail: 'closeTerminalTab' }));
|
|
57
|
+
} else if (active?.closest('.bottom-panel')) {
|
|
58
|
+
panelShortcutBus.dispatch('closeActiveBottomTab');
|
|
59
|
+
} else if (active?.closest('.right-panel')) {
|
|
60
|
+
panelShortcutBus.dispatch('toggleRightPanel');
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (action === 'switchTab1') { deps.handleTabChange('overview'); return; }
|
|
65
|
+
if (action === 'switchTab2') { deps.handleTabChange('preview'); return; }
|
|
66
|
+
if (action === 'switchTab3') { deps.handleTabChange('logs'); return; }
|
|
67
|
+
if (action === 'switchTab4') { deps.handleTabChange('settings'); return; }
|
|
68
|
+
if (action === 'previousTab' || action === 'nextTab') {
|
|
69
|
+
const tabs: DashboardDetailTab[] = ['overview', 'preview', 'logs', 'settings'];
|
|
70
|
+
const idx = tabs.indexOf(deps.activeDetailTab);
|
|
71
|
+
const dir = action === 'nextTab' ? 1 : -1;
|
|
72
|
+
deps.handleTabChange(tabs[(idx + dir + tabs.length) % tabs.length]);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (action === 'browserReload' || action === 'browserHardReload' || action === 'browserFocusUrl' || action === 'browserBack' || action === 'browserForward') {
|
|
76
|
+
const el = document.activeElement;
|
|
77
|
+
if (el?.closest('.browser-webview-stack, .browser-tab-strip, .browser-panel')) {
|
|
78
|
+
document.dispatchEvent(new CustomEvent('jaw:shortcut-action', { detail: action }));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Focus is NOT in the browser panel → reload acts on the preview or app.
|
|
82
|
+
// Preview focus refreshes the preview for both soft and hard (the iframe
|
|
83
|
+
// has no separate hard-reload concept).
|
|
84
|
+
if (action === 'browserReload' || action === 'browserHardReload') {
|
|
85
|
+
if (el?.closest('.preview-panel')) {
|
|
86
|
+
deps.setPreviewRefreshKey(key => key + 1);
|
|
87
|
+
} else if (action === 'browserReload') {
|
|
88
|
+
getDesktop()?.reloadWindow?.();
|
|
89
|
+
} else {
|
|
90
|
+
getDesktop()?.hardReloadWindow?.();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// browserFocusUrl / Back / Forward are browser-only → no-op outside the panel.
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (action === 'terminalClear' || action === 'terminalNewTab') {
|
|
97
|
+
const el = document.activeElement;
|
|
98
|
+
if (el?.closest('.terminal-panel, .xterm')) {
|
|
99
|
+
document.dispatchEvent(new CustomEvent('jaw:shortcut-action', { detail: action }));
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (action === 'toggleLeftSidebar') {
|
|
104
|
+
deps.handleSidebarToggle();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -134,12 +134,27 @@ export function shortcutMatches(event: KeyboardEvent, raw: string): boolean {
|
|
|
134
134
|
&& resolveEventKey(event) === parsed.key;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Actions whose keyboard shortcut is owned by the Electron application menu
|
|
139
|
+
* accelerator (single source of truth), so the renderer keydown matcher must
|
|
140
|
+
* NOT also match them — otherwise ⌘R fires twice (menu + keydown). The actions
|
|
141
|
+
* stay in MANAGER_SHORTCUT_ACTIONS so the menu can still dispatch them by name;
|
|
142
|
+
* only the renderer-side keyboard binding is suppressed. This also makes a
|
|
143
|
+
* persisted user keymap carrying Meta+R harmless, and preserves the browser's
|
|
144
|
+
* native ⌘R in a pure web build (no menu, no match → no preventDefault).
|
|
145
|
+
*/
|
|
146
|
+
export const RENDERER_DISABLED_SHORTCUT_ACTIONS = new Set<DashboardShortcutAction>([
|
|
147
|
+
'browserReload',
|
|
148
|
+
'browserHardReload',
|
|
149
|
+
]);
|
|
150
|
+
|
|
137
151
|
export function actionForShortcutEvent(
|
|
138
152
|
event: KeyboardEvent,
|
|
139
153
|
keymap: unknown,
|
|
140
154
|
): DashboardShortcutAction | null {
|
|
141
155
|
const shortcuts = normalizeManagerShortcutKeymap(keymap);
|
|
142
156
|
for (const action of MANAGER_SHORTCUT_ACTIONS) {
|
|
157
|
+
if (RENDERER_DISABLED_SHORTCUT_ACTIONS.has(action)) continue;
|
|
143
158
|
if (shortcutMatches(event, shortcuts[action])) return action;
|
|
144
159
|
if (MANAGER_SHORTCUT_ALIASES[action]?.some(shortcut => shortcutMatches(event, shortcut))) return action;
|
|
145
160
|
}
|
|
@@ -47,6 +47,16 @@ export type FolderBridgeApi = {
|
|
|
47
47
|
onDirChange: (cb: (dirPath: string) => void) => () => void;
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
+
export type DroppedPathEntry = {
|
|
51
|
+
name: string;
|
|
52
|
+
path: string;
|
|
53
|
+
kind: 'file' | 'directory';
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type DragDropBridgeApi = {
|
|
57
|
+
resolveDroppedItems: (files: File[]) => Promise<{ ok: boolean; entries?: DroppedPathEntry[]; rejected?: Array<{ path: string; reason: string }>; error?: string }>;
|
|
58
|
+
};
|
|
59
|
+
|
|
50
60
|
export type ShortcutBridgeApi = {
|
|
51
61
|
onAction: (cb: (action: DashboardShortcutAction) => void) => () => void;
|
|
52
62
|
};
|
|
@@ -87,10 +97,13 @@ export type CliJawDesktopApi = {
|
|
|
87
97
|
terminal?: TerminalBridgeApi | undefined;
|
|
88
98
|
diff?: DiffBridgeApi | undefined;
|
|
89
99
|
folder?: FolderBridgeApi | undefined;
|
|
100
|
+
dragDrop?: DragDropBridgeApi | undefined;
|
|
90
101
|
clipboard?: ClipboardBridgeApi | undefined;
|
|
91
102
|
permissions?: PermissionDiagnosticsBridgeApi | undefined;
|
|
92
103
|
shortcuts?: ShortcutBridgeApi | undefined;
|
|
93
104
|
browser?: BrowserBridgeApi | undefined;
|
|
105
|
+
reloadWindow?: (() => void) | undefined;
|
|
106
|
+
hardReloadWindow?: (() => void) | undefined;
|
|
94
107
|
};
|
|
95
108
|
|
|
96
109
|
export function getDesktop(): CliJawDesktopApi | null {
|
|
@@ -21,9 +21,9 @@ const CATEGORIES: SidebarEntry[] = [
|
|
|
21
21
|
{ id: 'channels-discord', label: 'Channels — Discord', group: 'channels' },
|
|
22
22
|
{ id: 'heartbeat', label: 'Heartbeat & schedules', group: 'automation' },
|
|
23
23
|
{ id: 'memory', label: 'Memory', group: 'automation' },
|
|
24
|
+
{ id: 'mcp', label: 'MCP servers', group: 'mcp' },
|
|
24
25
|
{ id: 'speech', label: 'Speech & keys', group: 'integrations' },
|
|
25
26
|
{ id: 'prompts', label: 'Prompts', group: 'integrations' },
|
|
26
|
-
{ id: 'mcp', label: 'MCP servers', group: 'integrations' },
|
|
27
27
|
{ id: 'browser', label: 'Browser / CDP', group: 'integrations' },
|
|
28
28
|
{ id: 'network', label: 'Network', group: 'network-security' },
|
|
29
29
|
{ id: 'permissions', label: 'Permissions', group: 'network-security' },
|
|
@@ -14,6 +14,7 @@ export type SidebarEntry = {
|
|
|
14
14
|
export const SIDEBAR_GROUP_ORDER: ReadonlyArray<SettingsCategoryGroup> = [
|
|
15
15
|
'runtime',
|
|
16
16
|
'identity',
|
|
17
|
+
'mcp',
|
|
17
18
|
'channels',
|
|
18
19
|
'automation',
|
|
19
20
|
'integrations',
|
|
@@ -24,6 +25,7 @@ export const SIDEBAR_GROUP_ORDER: ReadonlyArray<SettingsCategoryGroup> = [
|
|
|
24
25
|
export const SIDEBAR_GROUP_LABELS: Record<SettingsCategoryGroup, string> = {
|
|
25
26
|
runtime: 'Runtime',
|
|
26
27
|
identity: 'Identity',
|
|
28
|
+
mcp: 'MCP',
|
|
27
29
|
channels: 'Channels',
|
|
28
30
|
automation: 'Automation',
|
|
29
31
|
integrations: 'Integrations',
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
// Phase 8 — MCP page: structured editor for server cards plus an Advanced
|
|
2
|
-
// JSON view, plus action buttons for sync/install/reset against the
|
|
3
|
-
// unified MCP config (`/api/mcp`).
|
|
4
|
-
//
|
|
5
|
-
// The page owns one synthetic dirty-store key (`mcp.config`) carrying the
|
|
6
|
-
// full normalized config. Save PUTs back with `toPersistShape` to keep the
|
|
7
|
-
// on-disk JSON minimal. Render-time validation (duplicate names, missing
|
|
8
|
-
// commands, malformed env) gates the dirty entry's `valid` flag — invalid
|
|
9
|
-
// configs cannot save.
|
|
10
|
-
|
|
11
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
2
|
import type { SettingsPageProps } from '../types';
|
|
13
3
|
import { JsonEditorField } from '../fields';
|
|
@@ -21,7 +11,9 @@ import {
|
|
|
21
11
|
import { InlineWarn } from './components/InlineWarn';
|
|
22
12
|
import { McpServerCard } from './components/McpServerCard';
|
|
23
13
|
import {
|
|
14
|
+
countInstallBundleCandidates,
|
|
24
15
|
findDuplicateNames,
|
|
16
|
+
getServerTag,
|
|
25
17
|
makeEmptyServer,
|
|
26
18
|
newServerName,
|
|
27
19
|
normalizeMcpConfig,
|
|
@@ -46,6 +38,9 @@ type SyncResultsPayload = {
|
|
|
46
38
|
servers?: unknown;
|
|
47
39
|
};
|
|
48
40
|
|
|
41
|
+
type ModalTab = 'active' | 'add';
|
|
42
|
+
type AddSubTab = 'local' | 'remote';
|
|
43
|
+
|
|
49
44
|
export default function Mcp({ port, client, dirty, registerSave }: SettingsPageProps) {
|
|
50
45
|
const { state, refresh, setData } = usePageSnapshot<unknown>(client, '/api/mcp');
|
|
51
46
|
const [draft, setDraft] = useState<McpConfig>({ servers: {} });
|
|
@@ -55,6 +50,18 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
55
50
|
const [actionState, setActionState] = useState<ActionResult>({ kind: 'idle' });
|
|
56
51
|
const actionRunIdRef = useRef(0);
|
|
57
52
|
|
|
53
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
54
|
+
const [modalTab, setModalTab] = useState<ModalTab>('active');
|
|
55
|
+
const [addSubTab, setAddSubTab] = useState<AddSubTab>('local');
|
|
56
|
+
const [addName, setAddName] = useState('');
|
|
57
|
+
const [addCommand, setAddCommand] = useState('');
|
|
58
|
+
const [addArgs, setAddArgs] = useState('');
|
|
59
|
+
const [addEnv, setAddEnv] = useState('');
|
|
60
|
+
const [addUrl, setAddUrl] = useState('');
|
|
61
|
+
const [addHeaders, setAddHeaders] = useState('');
|
|
62
|
+
const [addError, setAddError] = useState<string | null>(null);
|
|
63
|
+
const [addPending, setAddPending] = useState(false);
|
|
64
|
+
|
|
58
65
|
const original = useMemo<McpConfig>(
|
|
59
66
|
() => (state.kind === 'ready' ? normalizeMcpConfig(state.data) : { servers: {} }),
|
|
60
67
|
[state],
|
|
@@ -69,9 +76,7 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
69
76
|
}, [state]);
|
|
70
77
|
|
|
71
78
|
useEffect(() => {
|
|
72
|
-
return () => {
|
|
73
|
-
dirty.remove(DIRTY_KEY);
|
|
74
|
-
};
|
|
79
|
+
return () => { dirty.remove(DIRTY_KEY); };
|
|
75
80
|
}, [dirty]);
|
|
76
81
|
|
|
77
82
|
const names = useMemo(() => Object.keys(draft.servers), [draft]);
|
|
@@ -85,6 +90,10 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
85
90
|
const hasFieldErrors = validations.some((v) => v.result.kind === 'invalid');
|
|
86
91
|
const hasDupes = duplicates.size > 0;
|
|
87
92
|
const isValid = !hasFieldErrors && !hasDupes && advancedValid;
|
|
93
|
+
const bundleCandidates = useMemo(
|
|
94
|
+
() => countInstallBundleCandidates(draft.servers),
|
|
95
|
+
[draft],
|
|
96
|
+
);
|
|
88
97
|
|
|
89
98
|
const writeDirty = useCallback(
|
|
90
99
|
(next: McpConfig, valid: boolean) => {
|
|
@@ -101,7 +110,6 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
101
110
|
(next: McpConfig, nextOrder?: string[]) => {
|
|
102
111
|
setDraft(next);
|
|
103
112
|
if (nextOrder) setOrder(nextOrder);
|
|
104
|
-
// Recompute validity on the next draft, not the stale `isValid`.
|
|
105
113
|
const ns = nextOrder ?? Object.keys(next.servers);
|
|
106
114
|
const dupes = findDuplicateNames(ns);
|
|
107
115
|
const fieldOk = ns.every(
|
|
@@ -115,8 +123,6 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
115
123
|
const onRenameServer = useCallback(
|
|
116
124
|
(oldName: string, nextName: string) => {
|
|
117
125
|
if (oldName === nextName) return;
|
|
118
|
-
// Preserve insertion order; keep the same card in place even if the
|
|
119
|
-
// new name collides with a later card (validation surfaces the dupe).
|
|
120
126
|
const nextOrder = order.map((n) => (n === oldName ? nextName : n));
|
|
121
127
|
const nextServers: Record<string, McpServer> = {};
|
|
122
128
|
for (const n of nextOrder) {
|
|
@@ -185,9 +191,6 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
185
191
|
if (!(DIRTY_KEY in bundle)) return;
|
|
186
192
|
const body = bundle[DIRTY_KEY];
|
|
187
193
|
const updated = await client.put<unknown>('/api/mcp', body);
|
|
188
|
-
// /api/mcp PUT returns `{ ok, servers: string[] }` — re-fetch to get the
|
|
189
|
-
// canonical persisted shape rather than reusing the (possibly trimmed)
|
|
190
|
-
// request body.
|
|
191
194
|
dirty.clear();
|
|
192
195
|
const fresh = await client.get<unknown>('/api/mcp').catch(() => updated);
|
|
193
196
|
const normalized = normalizeMcpConfig(fresh);
|
|
@@ -211,9 +214,7 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
211
214
|
!window.confirm(
|
|
212
215
|
`You have unsaved MCP edits. ${label} will use the on-disk config, not your unsaved changes. Continue?`,
|
|
213
216
|
)
|
|
214
|
-
) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
+
) { return; }
|
|
217
218
|
}
|
|
218
219
|
const runId = actionRunIdRef.current + 1;
|
|
219
220
|
actionRunIdRef.current = runId;
|
|
@@ -236,6 +237,94 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
236
237
|
[client, dirty],
|
|
237
238
|
);
|
|
238
239
|
|
|
240
|
+
const resetAddForm = useCallback(() => {
|
|
241
|
+
setAddName('');
|
|
242
|
+
setAddCommand('');
|
|
243
|
+
setAddArgs('');
|
|
244
|
+
setAddEnv('');
|
|
245
|
+
setAddUrl('');
|
|
246
|
+
setAddHeaders('');
|
|
247
|
+
setAddError(null);
|
|
248
|
+
setAddPending(false);
|
|
249
|
+
}, []);
|
|
250
|
+
|
|
251
|
+
const openModal = useCallback(() => {
|
|
252
|
+
setModalTab('active');
|
|
253
|
+
resetAddForm();
|
|
254
|
+
setModalOpen(true);
|
|
255
|
+
}, [resetAddForm]);
|
|
256
|
+
|
|
257
|
+
const closeModal = useCallback(() => {
|
|
258
|
+
setModalOpen(false);
|
|
259
|
+
resetAddForm();
|
|
260
|
+
}, [resetAddForm]);
|
|
261
|
+
|
|
262
|
+
const handleAddAndSync = useCallback(async () => {
|
|
263
|
+
const name = addName.trim() || newServerName(Object.keys(original.servers));
|
|
264
|
+
const server: McpServer = addSubTab === 'remote'
|
|
265
|
+
? { url: addUrl.trim(), ...(addHeaders.trim() ? { headers: parseSimpleKV(addHeaders) } : {}) }
|
|
266
|
+
: {
|
|
267
|
+
command: addCommand.trim(),
|
|
268
|
+
...(addArgs.trim() ? { args: addArgs.split(/\r?\n|,/).map(s => s.trim()).filter(Boolean) } : {}),
|
|
269
|
+
...(addEnv.trim() ? { env: parseSimpleKV(addEnv) } : {}),
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const validation = validateServer(name, server);
|
|
273
|
+
if (validation.kind === 'invalid') {
|
|
274
|
+
setAddError(validation.reason);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (original.servers[name]) {
|
|
278
|
+
setAddError(`Server "${name}" already exists.`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
setAddPending(true);
|
|
283
|
+
setAddError(null);
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
const merged: McpConfig = {
|
|
287
|
+
...original,
|
|
288
|
+
servers: { ...original.servers, [name]: server },
|
|
289
|
+
};
|
|
290
|
+
await client.put<unknown>('/api/mcp', toPersistShape(merged));
|
|
291
|
+
await client.post<unknown>('/api/mcp/sync', {});
|
|
292
|
+
dirty.clear();
|
|
293
|
+
const fresh = await client.get<unknown>('/api/mcp').catch(() => merged);
|
|
294
|
+
const normalized = normalizeMcpConfig(fresh);
|
|
295
|
+
setDraft(normalized);
|
|
296
|
+
setOrder(Object.keys(normalized.servers));
|
|
297
|
+
setData(fresh);
|
|
298
|
+
await refresh();
|
|
299
|
+
closeModal();
|
|
300
|
+
} catch (err: unknown) {
|
|
301
|
+
setAddError(err instanceof Error ? err.message : String(err));
|
|
302
|
+
setAddPending(false);
|
|
303
|
+
}
|
|
304
|
+
}, [addName, addSubTab, addUrl, addHeaders, addCommand, addArgs, addEnv, original, client, dirty, refresh, setData, closeModal]);
|
|
305
|
+
|
|
306
|
+
const handleRemoveFromModal = useCallback(async (name: string) => {
|
|
307
|
+
const nextServers = { ...original.servers };
|
|
308
|
+
delete nextServers[name];
|
|
309
|
+
const merged: McpConfig = { ...original, servers: nextServers };
|
|
310
|
+
try {
|
|
311
|
+
await client.put<unknown>('/api/mcp', toPersistShape(merged));
|
|
312
|
+
await client.post<unknown>('/api/mcp/sync', {});
|
|
313
|
+
dirty.clear();
|
|
314
|
+
const fresh = await client.get<unknown>('/api/mcp').catch(() => merged);
|
|
315
|
+
const normalized = normalizeMcpConfig(fresh);
|
|
316
|
+
setDraft(normalized);
|
|
317
|
+
setOrder(Object.keys(normalized.servers));
|
|
318
|
+
setData(fresh);
|
|
319
|
+
await refresh();
|
|
320
|
+
} catch (err: unknown) {
|
|
321
|
+
setActionState({
|
|
322
|
+
kind: 'error',
|
|
323
|
+
message: err instanceof Error ? err.message : String(err),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}, [original, client, dirty, refresh, setData]);
|
|
327
|
+
|
|
239
328
|
if (state.kind === 'loading') return <PageLoading />;
|
|
240
329
|
if (state.kind === 'offline') return <PageOffline port={port} />;
|
|
241
330
|
if (state.kind === 'error') return <PageError message={state.message} />;
|
|
@@ -277,15 +366,6 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
277
366
|
);
|
|
278
367
|
})}
|
|
279
368
|
</div>
|
|
280
|
-
<div className="mcp-servers-actions">
|
|
281
|
-
<button
|
|
282
|
-
type="button"
|
|
283
|
-
className="settings-action"
|
|
284
|
-
onClick={onAddServer}
|
|
285
|
-
>
|
|
286
|
-
Add server
|
|
287
|
-
</button>
|
|
288
|
-
</div>
|
|
289
369
|
{hasDupes && (
|
|
290
370
|
<InlineWarn role="alert">
|
|
291
371
|
Duplicate server name{dupeNames.length === 1 ? '' : 's'}: {dupeNames.join(', ')}.
|
|
@@ -294,7 +374,7 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
294
374
|
)}
|
|
295
375
|
{hasFieldErrors && !hasDupes && (
|
|
296
376
|
<InlineWarn role="alert">
|
|
297
|
-
Some servers have errors (missing command or invalid name).
|
|
377
|
+
Some servers have errors (missing command/URL or invalid name).
|
|
298
378
|
Saving is blocked until they are fixed.
|
|
299
379
|
</InlineWarn>
|
|
300
380
|
)}
|
|
@@ -305,6 +385,13 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
305
385
|
hint="These act on the saved config. Save edits first if you want them included."
|
|
306
386
|
>
|
|
307
387
|
<div className="mcp-action-buttons">
|
|
388
|
+
<button
|
|
389
|
+
type="button"
|
|
390
|
+
className="settings-action"
|
|
391
|
+
onClick={openModal}
|
|
392
|
+
>
|
|
393
|
+
+ Add, Set MCP
|
|
394
|
+
</button>
|
|
308
395
|
<button
|
|
309
396
|
type="button"
|
|
310
397
|
className="settings-action"
|
|
@@ -316,10 +403,10 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
316
403
|
<button
|
|
317
404
|
type="button"
|
|
318
405
|
className="settings-action"
|
|
319
|
-
disabled={actionState.kind === 'pending'}
|
|
406
|
+
disabled={actionState.kind === 'pending' || bundleCandidates === 0}
|
|
320
407
|
onClick={() => void runAction('Install bundle', '/api/mcp/install')}
|
|
321
408
|
>
|
|
322
|
-
Install bundle
|
|
409
|
+
Install bundle ({bundleCandidates})
|
|
323
410
|
</button>
|
|
324
411
|
<button
|
|
325
412
|
type="button"
|
|
@@ -331,9 +418,7 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
331
418
|
!window.confirm(
|
|
332
419
|
'Reset MCP config to defaults? Your custom servers will be removed.',
|
|
333
420
|
)
|
|
334
|
-
) {
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
421
|
+
) { return; }
|
|
337
422
|
void runAction('Reset to defaults', '/api/mcp/reset');
|
|
338
423
|
}}
|
|
339
424
|
>
|
|
@@ -341,14 +426,10 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
341
426
|
</button>
|
|
342
427
|
</div>
|
|
343
428
|
{actionState.kind === 'pending' && (
|
|
344
|
-
<p className="settings-section-hint" role="status">
|
|
345
|
-
{actionState.label}…
|
|
346
|
-
</p>
|
|
429
|
+
<p className="settings-section-hint" role="status">{actionState.label}…</p>
|
|
347
430
|
)}
|
|
348
431
|
{actionState.kind === 'success' && (
|
|
349
|
-
<p className="settings-section-hint" role="status">
|
|
350
|
-
✅ {actionState.message}
|
|
351
|
-
</p>
|
|
432
|
+
<p className="settings-section-hint" role="status">{actionState.message}</p>
|
|
352
433
|
)}
|
|
353
434
|
{actionState.kind === 'error' && (
|
|
354
435
|
<InlineWarn role="alert">{actionState.message}</InlineWarn>
|
|
@@ -382,6 +463,193 @@ export default function Mcp({ port, client, dirty, registerSave }: SettingsPageP
|
|
|
382
463
|
</p>
|
|
383
464
|
)}
|
|
384
465
|
</SettingsSection>
|
|
466
|
+
|
|
467
|
+
{modalOpen && (
|
|
468
|
+
<div className="mcp-modal-backdrop" onClick={closeModal}>
|
|
469
|
+
<div
|
|
470
|
+
className="mcp-modal"
|
|
471
|
+
role="dialog"
|
|
472
|
+
aria-modal="true"
|
|
473
|
+
aria-label="MCP Server Management"
|
|
474
|
+
onClick={(e) => e.stopPropagation()}
|
|
475
|
+
>
|
|
476
|
+
<div className="mcp-modal-tabs">
|
|
477
|
+
<button
|
|
478
|
+
type="button"
|
|
479
|
+
className={`mcp-modal-tab${modalTab === 'active' ? ' is-active' : ''}`}
|
|
480
|
+
onClick={() => setModalTab('active')}
|
|
481
|
+
>
|
|
482
|
+
Active Servers
|
|
483
|
+
</button>
|
|
484
|
+
<button
|
|
485
|
+
type="button"
|
|
486
|
+
className={`mcp-modal-tab${modalTab === 'add' ? ' is-active' : ''}`}
|
|
487
|
+
onClick={() => { setModalTab('add'); resetAddForm(); }}
|
|
488
|
+
>
|
|
489
|
+
Add New
|
|
490
|
+
</button>
|
|
491
|
+
</div>
|
|
492
|
+
|
|
493
|
+
<div className="mcp-modal-body">
|
|
494
|
+
{modalTab === 'active' && (
|
|
495
|
+
<div className="mcp-active-list">
|
|
496
|
+
{Object.keys(original.servers).length === 0 && (
|
|
497
|
+
<p className="settings-section-hint">No active MCP servers.</p>
|
|
498
|
+
)}
|
|
499
|
+
{Object.entries(original.servers).map(([name, srv]) => {
|
|
500
|
+
const tag = getServerTag(srv);
|
|
501
|
+
return (
|
|
502
|
+
<div key={name} className="mcp-active-row">
|
|
503
|
+
<span className="mcp-active-name">{name}</span>
|
|
504
|
+
<span className="mcp-active-detail">
|
|
505
|
+
{srv.url || [srv.command, ...(srv.args || [])].filter(Boolean).join(' ')}
|
|
506
|
+
</span>
|
|
507
|
+
{tag && <span className="mcp-server-tag" data-tag={tag}>[{tag}]</span>}
|
|
508
|
+
<button
|
|
509
|
+
type="button"
|
|
510
|
+
className="settings-action settings-action-discard mcp-active-remove"
|
|
511
|
+
onClick={() => void handleRemoveFromModal(name)}
|
|
512
|
+
>
|
|
513
|
+
Remove
|
|
514
|
+
</button>
|
|
515
|
+
</div>
|
|
516
|
+
);
|
|
517
|
+
})}
|
|
518
|
+
</div>
|
|
519
|
+
)}
|
|
520
|
+
|
|
521
|
+
{modalTab === 'add' && (
|
|
522
|
+
<div className="mcp-add-form">
|
|
523
|
+
<div className="mcp-add-subtabs">
|
|
524
|
+
<button
|
|
525
|
+
type="button"
|
|
526
|
+
className={`mcp-modal-tab${addSubTab === 'local' ? ' is-active' : ''}`}
|
|
527
|
+
onClick={() => setAddSubTab('local')}
|
|
528
|
+
>
|
|
529
|
+
Local
|
|
530
|
+
</button>
|
|
531
|
+
<button
|
|
532
|
+
type="button"
|
|
533
|
+
className={`mcp-modal-tab${addSubTab === 'remote' ? ' is-active' : ''}`}
|
|
534
|
+
onClick={() => setAddSubTab('remote')}
|
|
535
|
+
>
|
|
536
|
+
Remote
|
|
537
|
+
</button>
|
|
538
|
+
</div>
|
|
539
|
+
|
|
540
|
+
<label className="settings-field settings-field-text">
|
|
541
|
+
<span className="settings-field-label">Name</span>
|
|
542
|
+
<input
|
|
543
|
+
type="text"
|
|
544
|
+
value={addName}
|
|
545
|
+
placeholder="my-server"
|
|
546
|
+
spellCheck={false}
|
|
547
|
+
onChange={(e) => setAddName(e.target.value)}
|
|
548
|
+
/>
|
|
549
|
+
</label>
|
|
550
|
+
|
|
551
|
+
{addSubTab === 'local' ? (
|
|
552
|
+
<>
|
|
553
|
+
<label className="settings-field settings-field-text">
|
|
554
|
+
<span className="settings-field-label">Command</span>
|
|
555
|
+
<input
|
|
556
|
+
type="text"
|
|
557
|
+
value={addCommand}
|
|
558
|
+
placeholder="npx"
|
|
559
|
+
spellCheck={false}
|
|
560
|
+
onChange={(e) => setAddCommand(e.target.value)}
|
|
561
|
+
/>
|
|
562
|
+
</label>
|
|
563
|
+
<label className="settings-field settings-field-text">
|
|
564
|
+
<span className="settings-field-label">Args (one per line)</span>
|
|
565
|
+
<textarea
|
|
566
|
+
value={addArgs}
|
|
567
|
+
rows={3}
|
|
568
|
+
spellCheck={false}
|
|
569
|
+
placeholder="-y @upstash/context7-mcp"
|
|
570
|
+
onChange={(e) => setAddArgs(e.target.value)}
|
|
571
|
+
/>
|
|
572
|
+
</label>
|
|
573
|
+
<label className="settings-field settings-field-text">
|
|
574
|
+
<span className="settings-field-label">Env (KEY=value per line)</span>
|
|
575
|
+
<textarea
|
|
576
|
+
value={addEnv}
|
|
577
|
+
rows={2}
|
|
578
|
+
spellCheck={false}
|
|
579
|
+
onChange={(e) => setAddEnv(e.target.value)}
|
|
580
|
+
/>
|
|
581
|
+
</label>
|
|
582
|
+
</>
|
|
583
|
+
) : (
|
|
584
|
+
<>
|
|
585
|
+
<label className="settings-field settings-field-text">
|
|
586
|
+
<span className="settings-field-label">URL</span>
|
|
587
|
+
<input
|
|
588
|
+
type="text"
|
|
589
|
+
value={addUrl}
|
|
590
|
+
placeholder="https://mcp.example.com/sse"
|
|
591
|
+
spellCheck={false}
|
|
592
|
+
onChange={(e) => setAddUrl(e.target.value)}
|
|
593
|
+
/>
|
|
594
|
+
</label>
|
|
595
|
+
<label className="settings-field settings-field-text">
|
|
596
|
+
<span className="settings-field-label">Headers (KEY=value per line)</span>
|
|
597
|
+
<textarea
|
|
598
|
+
value={addHeaders}
|
|
599
|
+
rows={2}
|
|
600
|
+
spellCheck={false}
|
|
601
|
+
onChange={(e) => setAddHeaders(e.target.value)}
|
|
602
|
+
/>
|
|
603
|
+
</label>
|
|
604
|
+
</>
|
|
605
|
+
)}
|
|
606
|
+
|
|
607
|
+
{addError && <InlineWarn role="alert">{addError}</InlineWarn>}
|
|
608
|
+
|
|
609
|
+
<div className="mcp-add-actions">
|
|
610
|
+
<button
|
|
611
|
+
type="button"
|
|
612
|
+
className="settings-action"
|
|
613
|
+
onClick={closeModal}
|
|
614
|
+
>
|
|
615
|
+
Cancel
|
|
616
|
+
</button>
|
|
617
|
+
<button
|
|
618
|
+
type="button"
|
|
619
|
+
className="settings-action"
|
|
620
|
+
disabled={addPending}
|
|
621
|
+
onClick={() => void handleAddAndSync()}
|
|
622
|
+
>
|
|
623
|
+
{addPending ? 'Adding…' : 'Add & Sync'}
|
|
624
|
+
</button>
|
|
625
|
+
</div>
|
|
626
|
+
</div>
|
|
627
|
+
)}
|
|
628
|
+
</div>
|
|
629
|
+
|
|
630
|
+
<button
|
|
631
|
+
type="button"
|
|
632
|
+
className="mcp-modal-close"
|
|
633
|
+
aria-label="Close"
|
|
634
|
+
onClick={closeModal}
|
|
635
|
+
>
|
|
636
|
+
×
|
|
637
|
+
</button>
|
|
638
|
+
</div>
|
|
639
|
+
</div>
|
|
640
|
+
)}
|
|
385
641
|
</form>
|
|
386
642
|
);
|
|
387
643
|
}
|
|
644
|
+
|
|
645
|
+
function parseSimpleKV(text: string): Record<string, string> {
|
|
646
|
+
const out: Record<string, string> = {};
|
|
647
|
+
for (const line of text.split(/\r?\n/)) {
|
|
648
|
+
const t = line.trim();
|
|
649
|
+
if (!t || t.startsWith('#')) continue;
|
|
650
|
+
const eq = t.indexOf('=');
|
|
651
|
+
if (eq === -1) continue;
|
|
652
|
+
out[t.slice(0, eq).trim()] = t.slice(eq + 1);
|
|
653
|
+
}
|
|
654
|
+
return out;
|
|
655
|
+
}
|