@pellux/goodvibes-agent 0.1.0
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/.goodvibes/GOODVIBES.md +35 -0
- package/.goodvibes/agents/reviewer.md +48 -0
- package/.goodvibes/skills/add-provider/SKILL.md +199 -0
- package/CHANGELOG.md +25 -0
- package/README.md +74 -0
- package/bin/goodvibes-agent.ts +2 -0
- package/docs/README.md +23 -0
- package/docs/deployment-and-services.md +57 -0
- package/docs/getting-started.md +53 -0
- package/docs/release-and-publishing.md +46 -0
- package/package.json +134 -0
- package/scripts/check-bun.sh +20 -0
- package/src/audio/player.ts +156 -0
- package/src/audio/spoken-turn-controller.ts +203 -0
- package/src/audio/spoken-turn-model-routing.ts +117 -0
- package/src/audio/spoken-turn-wiring.ts +44 -0
- package/src/audio/text-chunker.ts +110 -0
- package/src/cli/bundle-command.ts +227 -0
- package/src/cli/completion.ts +90 -0
- package/src/cli/config-overrides.ts +159 -0
- package/src/cli/endpoints.ts +63 -0
- package/src/cli/entrypoint.ts +172 -0
- package/src/cli/help.ts +299 -0
- package/src/cli/index.ts +11 -0
- package/src/cli/management-commands.ts +426 -0
- package/src/cli/management.ts +744 -0
- package/src/cli/network-posture.ts +46 -0
- package/src/cli/package-verification.ts +123 -0
- package/src/cli/parser.ts +369 -0
- package/src/cli/provider-auth-routes.ts +22 -0
- package/src/cli/provider-classification.ts +107 -0
- package/src/cli/redaction.ts +105 -0
- package/src/cli/service-command.ts +26 -0
- package/src/cli/service-posture.ts +482 -0
- package/src/cli/status.ts +383 -0
- package/src/cli/surface-command.ts +247 -0
- package/src/cli/tui-startup.ts +32 -0
- package/src/cli/types.ts +69 -0
- package/src/cli-flags.ts +21 -0
- package/src/config/goodvibes-home-audit.ts +465 -0
- package/src/config/index.ts +57 -0
- package/src/config/provider-model.ts +23 -0
- package/src/config/secret-config.ts +119 -0
- package/src/config/secrets.ts +71 -0
- package/src/config/surface.ts +1 -0
- package/src/core/composer-state.ts +61 -0
- package/src/core/conversation-rendering.ts +359 -0
- package/src/core/conversation.ts +551 -0
- package/src/core/history.ts +45 -0
- package/src/core/orchestrator.ts +7 -0
- package/src/core/system-message-router.ts +171 -0
- package/src/daemon/cli.ts +55 -0
- package/src/daemon/safe-serve.ts +61 -0
- package/src/input/agent-workspace.ts +428 -0
- package/src/input/autocomplete.ts +96 -0
- package/src/input/bookmark-modal.ts +115 -0
- package/src/input/command-args-hint.ts +36 -0
- package/src/input/command-registry.ts +329 -0
- package/src/input/commands/agent-externalized-tui.ts +73 -0
- package/src/input/commands/agent-workspace-runtime.ts +17 -0
- package/src/input/commands/branch-runtime.ts +72 -0
- package/src/input/commands/cloudflare-runtime.ts +370 -0
- package/src/input/commands/config.ts +18 -0
- package/src/input/commands/control-room-runtime.ts +255 -0
- package/src/input/commands/conversation-runtime.ts +207 -0
- package/src/input/commands/discovery-runtime.ts +52 -0
- package/src/input/commands/eval.ts +204 -0
- package/src/input/commands/experience-runtime.ts +278 -0
- package/src/input/commands/guidance-runtime.ts +106 -0
- package/src/input/commands/health-runtime.ts +434 -0
- package/src/input/commands/hooks-runtime.ts +148 -0
- package/src/input/commands/incident-runtime.ts +95 -0
- package/src/input/commands/integration-runtime.ts +394 -0
- package/src/input/commands/intelligence-runtime.ts +223 -0
- package/src/input/commands/knowledge.ts +531 -0
- package/src/input/commands/local-auth-runtime.ts +105 -0
- package/src/input/commands/local-provider-runtime.ts +170 -0
- package/src/input/commands/local-runtime.ts +392 -0
- package/src/input/commands/local-setup-review.ts +199 -0
- package/src/input/commands/local-setup-transfer.ts +135 -0
- package/src/input/commands/local-setup.ts +282 -0
- package/src/input/commands/managed-runtime.ts +209 -0
- package/src/input/commands/marketplace-runtime.ts +290 -0
- package/src/input/commands/mcp-runtime.ts +432 -0
- package/src/input/commands/memory-product-runtime.ts +111 -0
- package/src/input/commands/memory.ts +151 -0
- package/src/input/commands/notify-runtime.ts +83 -0
- package/src/input/commands/onboarding-runtime.ts +14 -0
- package/src/input/commands/operator-panel-runtime.ts +146 -0
- package/src/input/commands/operator-runtime.ts +392 -0
- package/src/input/commands/planning-runtime.ts +205 -0
- package/src/input/commands/platform-access-runtime.ts +422 -0
- package/src/input/commands/platform-services-runtime.ts +246 -0
- package/src/input/commands/policy-dispatch.ts +339 -0
- package/src/input/commands/policy.ts +17 -0
- package/src/input/commands/product-runtime.ts +351 -0
- package/src/input/commands/profile-sync-runtime.ts +99 -0
- package/src/input/commands/provider-accounts-runtime.ts +113 -0
- package/src/input/commands/provider.ts +363 -0
- package/src/input/commands/qrcode-runtime.ts +20 -0
- package/src/input/commands/quit-shared.ts +162 -0
- package/src/input/commands/recall-bundle.ts +132 -0
- package/src/input/commands/recall-capture.ts +152 -0
- package/src/input/commands/recall-query.ts +229 -0
- package/src/input/commands/recall-review.ts +98 -0
- package/src/input/commands/recall-shared.ts +22 -0
- package/src/input/commands/remote-runtime-pool.ts +106 -0
- package/src/input/commands/remote-runtime-setup.ts +199 -0
- package/src/input/commands/remote-runtime.ts +431 -0
- package/src/input/commands/replay-runtime.ts +18 -0
- package/src/input/commands/runtime-services.ts +291 -0
- package/src/input/commands/schedule-runtime.ts +91 -0
- package/src/input/commands/services-runtime.ts +209 -0
- package/src/input/commands/session-content.ts +408 -0
- package/src/input/commands/session-workflow.ts +464 -0
- package/src/input/commands/session.ts +375 -0
- package/src/input/commands/settings-sync-runtime.ts +174 -0
- package/src/input/commands/share-runtime.ts +119 -0
- package/src/input/commands/shell-core.ts +307 -0
- package/src/input/commands/skills-runtime.ts +221 -0
- package/src/input/commands/subscription-runtime.ts +434 -0
- package/src/input/commands/tasks-runtime.ts +230 -0
- package/src/input/commands/teamwork-runtime.ts +339 -0
- package/src/input/commands/teleport-runtime.ts +57 -0
- package/src/input/commands/tts-runtime.ts +29 -0
- package/src/input/commands/work-plan-runtime.ts +169 -0
- package/src/input/commands.ts +131 -0
- package/src/input/feed-context-factory.ts +254 -0
- package/src/input/file-picker.ts +192 -0
- package/src/input/handler-command-route.ts +180 -0
- package/src/input/handler-content-actions.ts +497 -0
- package/src/input/handler-feed-routes.ts +648 -0
- package/src/input/handler-feed.ts +452 -0
- package/src/input/handler-interactions.ts +281 -0
- package/src/input/handler-modal-routes.ts +418 -0
- package/src/input/handler-modal-stack.ts +263 -0
- package/src/input/handler-modal-token-routes.ts +329 -0
- package/src/input/handler-onboarding-cloudflare.ts +391 -0
- package/src/input/handler-onboarding.ts +620 -0
- package/src/input/handler-picker-routes.ts +472 -0
- package/src/input/handler-prompt-buffer.ts +320 -0
- package/src/input/handler-shortcuts.ts +213 -0
- package/src/input/handler-ui-state.ts +372 -0
- package/src/input/handler.ts +729 -0
- package/src/input/input-history.ts +297 -0
- package/src/input/keybindings.ts +292 -0
- package/src/input/mcp-workspace.ts +554 -0
- package/src/input/model-picker-provider-filter.ts +28 -0
- package/src/input/model-picker-types.ts +137 -0
- package/src/input/model-picker.ts +797 -0
- package/src/input/onboarding/handler-onboarding-routes.ts +125 -0
- package/src/input/onboarding/onboarding-runtime-status.ts +87 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +277 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +494 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +204 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +158 -0
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +130 -0
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +762 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +167 -0
- package/src/input/onboarding/onboarding-wizard-rules.ts +256 -0
- package/src/input/onboarding/onboarding-wizard-state.ts +365 -0
- package/src/input/onboarding/onboarding-wizard-steps.ts +798 -0
- package/src/input/onboarding/onboarding-wizard-types.ts +195 -0
- package/src/input/onboarding/onboarding-wizard.ts +711 -0
- package/src/input/panel-integration-actions.ts +78 -0
- package/src/input/profile-picker-modal.ts +222 -0
- package/src/input/search.ts +100 -0
- package/src/input/selection-modal.ts +163 -0
- package/src/input/selection.ts +135 -0
- package/src/input/session-picker-modal.ts +136 -0
- package/src/input/settings-modal-behavior.ts +37 -0
- package/src/input/settings-modal-secrets.ts +41 -0
- package/src/input/settings-modal-subscriptions.ts +95 -0
- package/src/input/settings-modal-types.ts +91 -0
- package/src/input/settings-modal.ts +793 -0
- package/src/input/submission-intent.ts +17 -0
- package/src/input/submission-router.ts +59 -0
- package/src/input/tts-settings-actions.ts +100 -0
- package/src/main.ts +792 -0
- package/src/mcp/runtime-reload.ts +81 -0
- package/src/panels/agent-inspector-panel.ts +521 -0
- package/src/panels/agent-inspector-shared.ts +94 -0
- package/src/panels/agent-logs-panel.ts +559 -0
- package/src/panels/agent-logs-shared.ts +129 -0
- package/src/panels/approval-panel.ts +150 -0
- package/src/panels/automation-control-panel.ts +212 -0
- package/src/panels/base-panel.ts +254 -0
- package/src/panels/builtin/agent.ts +117 -0
- package/src/panels/builtin/development.ts +31 -0
- package/src/panels/builtin/knowledge.ts +26 -0
- package/src/panels/builtin/operations.ts +349 -0
- package/src/panels/builtin/session.ts +129 -0
- package/src/panels/builtin/shared.ts +274 -0
- package/src/panels/builtin-panels.ts +23 -0
- package/src/panels/cockpit-panel.ts +183 -0
- package/src/panels/communication-panel.ts +153 -0
- package/src/panels/confirm-state.ts +61 -0
- package/src/panels/context-visualizer-panel.ts +204 -0
- package/src/panels/control-plane-panel.ts +211 -0
- package/src/panels/cost-tracker-panel.ts +444 -0
- package/src/panels/debug-panel.ts +432 -0
- package/src/panels/diff-panel.ts +520 -0
- package/src/panels/docs-panel.ts +283 -0
- package/src/panels/eval-panel.ts +399 -0
- package/src/panels/file-explorer-panel.ts +584 -0
- package/src/panels/file-preview-panel.ts +434 -0
- package/src/panels/forensics-panel.ts +364 -0
- package/src/panels/git-panel.ts +638 -0
- package/src/panels/hooks-panel.ts +239 -0
- package/src/panels/incident-review-panel.ts +197 -0
- package/src/panels/index.ts +46 -0
- package/src/panels/intelligence-panel.ts +176 -0
- package/src/panels/knowledge-panel.ts +345 -0
- package/src/panels/local-auth-panel.ts +130 -0
- package/src/panels/marketplace-panel.ts +212 -0
- package/src/panels/memory-panel.ts +225 -0
- package/src/panels/ops-control-panel.ts +150 -0
- package/src/panels/ops-strategy-panel.ts +235 -0
- package/src/panels/orchestration-panel.ts +273 -0
- package/src/panels/panel-list-panel.ts +509 -0
- package/src/panels/panel-manager.ts +570 -0
- package/src/panels/panel-picker.ts +106 -0
- package/src/panels/plan-dashboard-panel.ts +274 -0
- package/src/panels/plugins-panel.ts +178 -0
- package/src/panels/policy-panel.ts +308 -0
- package/src/panels/polish.ts +717 -0
- package/src/panels/project-planning-panel.ts +711 -0
- package/src/panels/provider-account-snapshot.ts +259 -0
- package/src/panels/provider-accounts-panel.ts +218 -0
- package/src/panels/provider-health-domains.ts +215 -0
- package/src/panels/provider-health-panel.ts +727 -0
- package/src/panels/provider-health-tracker.ts +115 -0
- package/src/panels/provider-stats-panel.ts +366 -0
- package/src/panels/qr-panel.ts +182 -0
- package/src/panels/remote-panel.ts +449 -0
- package/src/panels/routes-panel.ts +178 -0
- package/src/panels/sandbox-panel.ts +283 -0
- package/src/panels/schedule-panel.ts +329 -0
- package/src/panels/scrollable-list-panel.ts +491 -0
- package/src/panels/search-focus.ts +32 -0
- package/src/panels/security-panel.ts +295 -0
- package/src/panels/services-panel.ts +231 -0
- package/src/panels/session-browser-panel.ts +400 -0
- package/src/panels/session-maintenance.ts +125 -0
- package/src/panels/settings-sync-panel.ts +120 -0
- package/src/panels/skills-panel.ts +431 -0
- package/src/panels/subscription-panel.ts +263 -0
- package/src/panels/symbol-outline-panel.ts +486 -0
- package/src/panels/system-messages-panel.ts +230 -0
- package/src/panels/tasks-panel.ts +399 -0
- package/src/panels/thinking-panel.ts +304 -0
- package/src/panels/token-budget-panel.ts +475 -0
- package/src/panels/tool-inspector-panel.ts +429 -0
- package/src/panels/types.ts +54 -0
- package/src/panels/watchers-panel.ts +193 -0
- package/src/panels/work-plan-panel.ts +175 -0
- package/src/panels/worktree-panel.ts +182 -0
- package/src/panels/wrfc-panel.ts +609 -0
- package/src/permissions/prompt.ts +165 -0
- package/src/planning/project-planning-coordinator.ts +543 -0
- package/src/plugins/loader.ts +15 -0
- package/src/renderer/agent-detail-modal.ts +331 -0
- package/src/renderer/agent-workspace.ts +238 -0
- package/src/renderer/ansi-sanitize.ts +76 -0
- package/src/renderer/autocomplete-overlay.ts +154 -0
- package/src/renderer/block-actions.ts +76 -0
- package/src/renderer/bookmark-modal.ts +101 -0
- package/src/renderer/bottom-bar.ts +58 -0
- package/src/renderer/buffer.ts +113 -0
- package/src/renderer/code-block.ts +373 -0
- package/src/renderer/compositor.ts +283 -0
- package/src/renderer/context-inspector.ts +219 -0
- package/src/renderer/conversation-layout.ts +67 -0
- package/src/renderer/conversation-overlays.ts +140 -0
- package/src/renderer/conversation-surface.ts +260 -0
- package/src/renderer/diff-view.ts +132 -0
- package/src/renderer/diff.ts +130 -0
- package/src/renderer/file-picker-overlay.ts +101 -0
- package/src/renderer/file-tree.ts +153 -0
- package/src/renderer/fullscreen-primitives.ts +130 -0
- package/src/renderer/fullscreen-workspace.ts +199 -0
- package/src/renderer/git-status.ts +89 -0
- package/src/renderer/help-overlay.ts +267 -0
- package/src/renderer/history-search-overlay.ts +73 -0
- package/src/renderer/layout-engine.ts +97 -0
- package/src/renderer/layout.ts +32 -0
- package/src/renderer/live-tail-modal.ts +156 -0
- package/src/renderer/markdown.ts +635 -0
- package/src/renderer/mcp-workspace.ts +237 -0
- package/src/renderer/modal-factory.ts +467 -0
- package/src/renderer/modal-utils.ts +24 -0
- package/src/renderer/model-picker-overlay.ts +473 -0
- package/src/renderer/model-workspace.ts +488 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +615 -0
- package/src/renderer/overlay-box.ts +146 -0
- package/src/renderer/overlay-viewport.ts +104 -0
- package/src/renderer/panel-composite.ts +158 -0
- package/src/renderer/panel-picker-overlay.ts +202 -0
- package/src/renderer/panel-tab-bar.ts +69 -0
- package/src/renderer/panel-workspace-bar.ts +42 -0
- package/src/renderer/process-indicator.ts +96 -0
- package/src/renderer/process-modal.ts +656 -0
- package/src/renderer/process-summary.ts +67 -0
- package/src/renderer/profile-picker-modal.ts +129 -0
- package/src/renderer/progress.ts +98 -0
- package/src/renderer/qr-renderer.ts +120 -0
- package/src/renderer/search-overlay.ts +54 -0
- package/src/renderer/selection-modal-overlay.ts +214 -0
- package/src/renderer/semantic-diff.ts +369 -0
- package/src/renderer/session-picker-modal.ts +127 -0
- package/src/renderer/settings-modal-helpers.ts +193 -0
- package/src/renderer/settings-modal.ts +537 -0
- package/src/renderer/shell-surface.ts +88 -0
- package/src/renderer/status-glyphs.ts +21 -0
- package/src/renderer/status-token.ts +67 -0
- package/src/renderer/surface-layout.ts +101 -0
- package/src/renderer/syntax-highlighter.ts +542 -0
- package/src/renderer/system-message.ts +83 -0
- package/src/renderer/tab-strip.ts +108 -0
- package/src/renderer/text-layout.ts +31 -0
- package/src/renderer/thinking.ts +17 -0
- package/src/renderer/tool-call.ts +234 -0
- package/src/renderer/ui-factory.ts +524 -0
- package/src/renderer/ui-primitives.ts +96 -0
- package/src/runtime/bootstrap-command-context.ts +278 -0
- package/src/runtime/bootstrap-command-parts.ts +386 -0
- package/src/runtime/bootstrap-core.ts +540 -0
- package/src/runtime/bootstrap-hook-bridge.ts +112 -0
- package/src/runtime/bootstrap-shell.ts +283 -0
- package/src/runtime/bootstrap.ts +575 -0
- package/src/runtime/cloudflare-control-plane.ts +349 -0
- package/src/runtime/context.ts +142 -0
- package/src/runtime/diagnostics/panels/index.ts +24 -0
- package/src/runtime/diagnostics/panels/ops.ts +156 -0
- package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
- package/src/runtime/diagnostics/panels/policy.ts +177 -0
- package/src/runtime/index.ts +662 -0
- package/src/runtime/onboarding/apply.ts +642 -0
- package/src/runtime/onboarding/derivation.ts +534 -0
- package/src/runtime/onboarding/index.ts +7 -0
- package/src/runtime/onboarding/markers.ts +148 -0
- package/src/runtime/onboarding/snapshot.ts +406 -0
- package/src/runtime/onboarding/state.ts +141 -0
- package/src/runtime/onboarding/types.ts +404 -0
- package/src/runtime/onboarding/verify.ts +171 -0
- package/src/runtime/operator-token-cleanup.ts +27 -0
- package/src/runtime/perf/panel-contracts.ts +32 -0
- package/src/runtime/perf/panel-health-monitor.ts +18 -0
- package/src/runtime/sandbox-public-gaps.ts +358 -0
- package/src/runtime/services.ts +670 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +15 -0
- package/src/runtime/store/domains/index.ts +222 -0
- package/src/runtime/store/domains/panels.ts +117 -0
- package/src/runtime/store/domains/ui-perf.ts +103 -0
- package/src/runtime/store/index.ts +305 -0
- package/src/runtime/store/selectors/index.ts +359 -0
- package/src/runtime/store/state.ts +145 -0
- package/src/runtime/surface-feature-flags.ts +65 -0
- package/src/runtime/terminal-output-guard.ts +228 -0
- package/src/runtime/ui/index.ts +39 -0
- package/src/runtime/ui/model-picker/data-provider.ts +182 -0
- package/src/runtime/ui/model-picker/health-enrichment.ts +228 -0
- package/src/runtime/ui/model-picker/index.ts +59 -0
- package/src/runtime/ui/model-picker/types.ts +149 -0
- package/src/runtime/ui/provider-health/data-provider.ts +244 -0
- package/src/runtime/ui/provider-health/fallback-visualizer.ts +71 -0
- package/src/runtime/ui/provider-health/index.ts +46 -0
- package/src/runtime/ui/provider-health/types.ts +146 -0
- package/src/runtime/ui-events.ts +1 -0
- package/src/runtime/ui-read-model-helpers.ts +1 -0
- package/src/runtime/ui-read-models-observability-maintenance.ts +1 -0
- package/src/runtime/ui-read-models-observability-options.ts +1 -0
- package/src/runtime/ui-read-models-observability-remote.ts +1 -0
- package/src/runtime/ui-read-models-observability-security.ts +1 -0
- package/src/runtime/ui-read-models-observability-system.ts +1 -0
- package/src/runtime/ui-read-models-observability.ts +1 -0
- package/src/runtime/ui-read-models.ts +61 -0
- package/src/runtime/ui-service-queries.ts +1 -0
- package/src/runtime/ui-services.ts +190 -0
- package/src/scripts/process-messages.ts +42 -0
- package/src/shell/blocking-input.ts +98 -0
- package/src/shell/service-settings-sync.ts +273 -0
- package/src/shell/ui-openers.ts +352 -0
- package/src/tools/index.ts +1 -0
- package/src/tools/wrfc-agent-guard.ts +49 -0
- package/src/types/grid.ts +48 -0
- package/src/types/sql-js.d.ts +15 -0
- package/src/utils/clipboard.ts +22 -0
- package/src/utils/splash-lines.ts +46 -0
- package/src/utils/terminal-width.ts +185 -0
- package/src/verification/live-verifier.ts +430 -0
- package/src/verification/verification-ledger.ts +242 -0
- package/src/version.ts +17 -0
- package/src/widget/index.ts +2 -0
- package/src/widget/types.ts +9 -0
- package/src/widget/widget.ts +8 -0
- package/src/work-plans/work-plan-store.ts +374 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import type { CommandContext, CommandRegistry } from '../command-registry.ts';
|
|
2
|
+
import type { McpConfigScope, McpReloadResult, McpServerConfig } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
3
|
+
import { requireMcpApi, requireShellPaths } from './runtime-services.ts';
|
|
4
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
5
|
+
|
|
6
|
+
const MCP_ROLES = ['general', 'docs', 'filesystem', 'git', 'database', 'browser', 'automation', 'ops', 'remote'] as const;
|
|
7
|
+
const MCP_TRUST_MODES = ['constrained', 'ask-on-risk', 'allow-all', 'blocked'] as const;
|
|
8
|
+
|
|
9
|
+
interface ParsedMcpAddArgs {
|
|
10
|
+
readonly scope: McpConfigScope;
|
|
11
|
+
readonly server: McpServerConfig;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isMcpRole(value: string): value is NonNullable<McpServerConfig['role']> {
|
|
15
|
+
return MCP_ROLES.includes(value as NonNullable<McpServerConfig['role']>);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isMcpTrustMode(value: string): value is NonNullable<McpServerConfig['trustMode']> {
|
|
19
|
+
return MCP_TRUST_MODES.includes(value as NonNullable<McpServerConfig['trustMode']>);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isMcpScope(value: string): value is McpConfigScope {
|
|
23
|
+
return value === 'project' || value === 'global';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function validateServerName(name: string): string | null {
|
|
27
|
+
if (!name.trim()) return 'MCP server name is required.';
|
|
28
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(name)) {
|
|
29
|
+
return 'MCP server names may contain letters, numbers, dot, underscore, and dash only.';
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function readFlagValue(tokens: string[], index: number, flag: string): string {
|
|
35
|
+
const value = tokens[index + 1];
|
|
36
|
+
if (!value) {
|
|
37
|
+
throw new Error(`Missing value after ${flag}.`);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseAddServerArgs(args: string[]): ParsedMcpAddArgs {
|
|
43
|
+
const name = args[1]?.trim();
|
|
44
|
+
const command = args[2]?.trim();
|
|
45
|
+
if (!name || !command) {
|
|
46
|
+
throw new Error('Usage: /mcp add <name> <command> [args...] [--scope project|global] [--role <role>] [--trust <mode>] [--env KEY=VALUE] [--path <path>] [--host <host>]');
|
|
47
|
+
}
|
|
48
|
+
const nameError = validateServerName(name);
|
|
49
|
+
if (nameError) throw new Error(nameError);
|
|
50
|
+
|
|
51
|
+
const serverArgs: string[] = [];
|
|
52
|
+
const env: Record<string, string> = {};
|
|
53
|
+
const allowedPaths: string[] = [];
|
|
54
|
+
const allowedHosts: string[] = [];
|
|
55
|
+
let role: McpServerConfig['role'];
|
|
56
|
+
let trustMode: McpServerConfig['trustMode'];
|
|
57
|
+
let scope: McpConfigScope = 'project';
|
|
58
|
+
let passthrough = false;
|
|
59
|
+
const tokens = args.slice(3);
|
|
60
|
+
|
|
61
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
62
|
+
const token = tokens[index]!;
|
|
63
|
+
if (passthrough) {
|
|
64
|
+
serverArgs.push(token);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (token === '--') {
|
|
68
|
+
passthrough = true;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (token === '--role') {
|
|
72
|
+
const value = readFlagValue(tokens, index, token);
|
|
73
|
+
if (!isMcpRole(value)) throw new Error(`Invalid MCP role "${value}". Expected one of: ${MCP_ROLES.join(', ')}`);
|
|
74
|
+
role = value;
|
|
75
|
+
index += 1;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (token === '--scope') {
|
|
79
|
+
const value = readFlagValue(tokens, index, token);
|
|
80
|
+
if (!isMcpScope(value)) throw new Error(`Invalid MCP scope "${value}". Expected project or global.`);
|
|
81
|
+
scope = value;
|
|
82
|
+
index += 1;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (token === '--trust') {
|
|
86
|
+
const value = readFlagValue(tokens, index, token);
|
|
87
|
+
if (!isMcpTrustMode(value)) throw new Error(`Invalid MCP trust mode "${value}". Expected one of: ${MCP_TRUST_MODES.join(', ')}`);
|
|
88
|
+
trustMode = value;
|
|
89
|
+
index += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (token === '--env') {
|
|
93
|
+
const value = readFlagValue(tokens, index, token);
|
|
94
|
+
const eq = value.indexOf('=');
|
|
95
|
+
if (eq <= 0) throw new Error('MCP env entries must use KEY=VALUE.');
|
|
96
|
+
env[value.slice(0, eq)] = value.slice(eq + 1);
|
|
97
|
+
index += 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (token === '--path') {
|
|
101
|
+
allowedPaths.push(readFlagValue(tokens, index, token));
|
|
102
|
+
index += 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (token === '--host') {
|
|
106
|
+
allowedHosts.push(readFlagValue(tokens, index, token));
|
|
107
|
+
index += 1;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
serverArgs.push(token);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
scope,
|
|
115
|
+
server: {
|
|
116
|
+
name,
|
|
117
|
+
command,
|
|
118
|
+
...(serverArgs.length > 0 ? { args: serverArgs } : {}),
|
|
119
|
+
...(Object.keys(env).length > 0 ? { env } : {}),
|
|
120
|
+
...(role ? { role } : {}),
|
|
121
|
+
...(trustMode ? { trustMode } : {}),
|
|
122
|
+
...(allowedPaths.length > 0 ? { allowedPaths } : {}),
|
|
123
|
+
...(allowedHosts.length > 0 ? { allowedHosts } : {}),
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function reloadMcpRuntime(ctx: CommandContext): Promise<McpReloadResult> {
|
|
129
|
+
const result = await requireMcpApi(ctx).reload(requireShellPaths(ctx));
|
|
130
|
+
ctx.renderRequest();
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function registerMcpRuntimeCommands(registry: CommandRegistry): void {
|
|
135
|
+
registry.register({
|
|
136
|
+
name: 'mcp',
|
|
137
|
+
aliases: [],
|
|
138
|
+
description: 'Manage MCP servers and their tools',
|
|
139
|
+
usage: '[add|remove|reload|config|review|tools [<server>]|auth-review|repair [server]]',
|
|
140
|
+
argsHint: '[add|remove|reload|config|review|tools [server]]',
|
|
141
|
+
async handler(args, ctx) {
|
|
142
|
+
const mcpApi = requireMcpApi(ctx);
|
|
143
|
+
const listServerSecurity = () => mcpApi.listServerSecurity();
|
|
144
|
+
const subcommand = args[0];
|
|
145
|
+
if (!subcommand && ctx.openMcpWorkspace) {
|
|
146
|
+
ctx.openMcpWorkspace();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (subcommand === 'review') {
|
|
150
|
+
const servers = listServerSecurity();
|
|
151
|
+
const authRequired = servers.filter((server) => !server.connected || server.schemaFreshness === 'quarantined');
|
|
152
|
+
ctx.print([
|
|
153
|
+
'MCP Review',
|
|
154
|
+
` servers: ${servers.length}`,
|
|
155
|
+
` connected: ${servers.filter((server) => server.connected).length}`,
|
|
156
|
+
` auth or repair attention: ${authRequired.length}`,
|
|
157
|
+
...servers.map((server) => ` ${server.name} trust=${server.trustMode} role=${server.role} freshness=${server.schemaFreshness} connected=${server.connected ? 'yes' : 'no'}`),
|
|
158
|
+
' next: /mcp auth-review',
|
|
159
|
+
' next: /mcp repair <server>',
|
|
160
|
+
].join('\n'));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (subcommand === 'tools') {
|
|
164
|
+
const filterServer = args[1];
|
|
165
|
+
ctx.print('Fetching MCP tool list...');
|
|
166
|
+
let allTools;
|
|
167
|
+
try {
|
|
168
|
+
allTools = await mcpApi.listAllTools();
|
|
169
|
+
} catch (e) {
|
|
170
|
+
ctx.print(`Error listing tools: ${summarizeError(e)}`);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const tools = filterServer ? allTools.filter(t => t.serverName === filterServer) : allTools;
|
|
174
|
+
if (tools.length === 0) {
|
|
175
|
+
ctx.print(filterServer
|
|
176
|
+
? `No tools found for server "${filterServer}". Is it connected? Run /mcp to see server status.`
|
|
177
|
+
: 'No MCP tools available. Configure servers in .goodvibes/mcp.json or ~/.config/mcp/mcp.json.');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const lines: string[] = [`MCP Tools (${tools.length} total):`];
|
|
181
|
+
let lastServer = '';
|
|
182
|
+
for (const tool of tools) {
|
|
183
|
+
if (tool.serverName !== lastServer) {
|
|
184
|
+
lines.push(`\n [${tool.serverName}]`);
|
|
185
|
+
lastServer = tool.serverName;
|
|
186
|
+
}
|
|
187
|
+
lines.push(` ${tool.toolName}${tool.description ? ` — ${tool.description}` : ''}`);
|
|
188
|
+
}
|
|
189
|
+
ctx.print(lines.join('\n'));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (subcommand === 'auth-review') {
|
|
194
|
+
const servers = listServerSecurity();
|
|
195
|
+
const needingAttention = servers.filter((server) => !server.connected || server.schemaFreshness === 'quarantined');
|
|
196
|
+
ctx.print(needingAttention.length > 0
|
|
197
|
+
? [
|
|
198
|
+
'MCP Auth Review',
|
|
199
|
+
...needingAttention.map((server) => (
|
|
200
|
+
` ${server.name} connected=${server.connected ? 'yes' : 'no'} freshness=${server.schemaFreshness} trust=${server.trustMode}`
|
|
201
|
+
)),
|
|
202
|
+
' next: /services auth-review',
|
|
203
|
+
' next: /mcp repair <server>',
|
|
204
|
+
].join('\n')
|
|
205
|
+
: 'MCP Auth Review\n No MCP servers currently need auth or quarantine recovery.');
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (subcommand === 'repair') {
|
|
210
|
+
const serverName = args[1];
|
|
211
|
+
const servers = listServerSecurity();
|
|
212
|
+
const selected = serverName ? servers.find((server) => server.name === serverName) : servers.find((server) => !server.connected || server.schemaFreshness === 'quarantined');
|
|
213
|
+
if (!selected) {
|
|
214
|
+
ctx.print(serverName
|
|
215
|
+
? `Unknown MCP server: ${serverName}`
|
|
216
|
+
: 'MCP Repair\n No MCP server currently needs repair.');
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const nextSteps = [
|
|
220
|
+
selected.schemaFreshness === 'quarantined'
|
|
221
|
+
? `/mcp quarantine ${selected.name} approve operator`
|
|
222
|
+
: null,
|
|
223
|
+
!selected.connected ? '/services auth-review' : null,
|
|
224
|
+
'/mcp review',
|
|
225
|
+
'/health review',
|
|
226
|
+
].filter((entry): entry is string => entry !== null);
|
|
227
|
+
ctx.print([
|
|
228
|
+
`MCP Repair: ${selected.name}`,
|
|
229
|
+
` connected: ${selected.connected ? 'yes' : 'no'}`,
|
|
230
|
+
` trust: ${selected.trustMode}`,
|
|
231
|
+
` role: ${selected.role}`,
|
|
232
|
+
` freshness: ${selected.schemaFreshness}`,
|
|
233
|
+
...(selected.quarantineReason ? [` quarantine: ${selected.quarantineReason}`] : []),
|
|
234
|
+
...(selected.quarantineDetail ? [` detail: ${selected.quarantineDetail}`] : []),
|
|
235
|
+
' next:',
|
|
236
|
+
...nextSteps.map((step) => ` ${step}`),
|
|
237
|
+
].join('\n'));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (subcommand === 'trust') {
|
|
242
|
+
const serverName = args[1];
|
|
243
|
+
const mode = args[2] as 'constrained' | 'ask-on-risk' | 'allow-all' | 'blocked' | undefined;
|
|
244
|
+
if (serverName && mode) {
|
|
245
|
+
if (mode === 'allow-all') {
|
|
246
|
+
ctx.print(`Use /settings → MCP to explicitly enable allow-all for ${serverName}. Direct CLI escalation is blocked.`);
|
|
247
|
+
ctx.openSettingsModal?.();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
mcpApi.setServerTrustMode(serverName, mode);
|
|
251
|
+
ctx.print(`Updated MCP trust mode for ${serverName} to ${mode}.`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (serverName || mode) {
|
|
255
|
+
ctx.print('Usage: /mcp trust <server> <constrained|ask-on-risk|blocked>\nUse /settings → MCP to explicitly enable allow-all.');
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (subcommand === 'role') {
|
|
261
|
+
const serverName = args[1];
|
|
262
|
+
const role = args[2] as 'general' | 'docs' | 'filesystem' | 'git' | 'database' | 'browser' | 'automation' | 'ops' | 'remote' | undefined;
|
|
263
|
+
if (serverName && role) {
|
|
264
|
+
mcpApi.setServerRole(serverName, role);
|
|
265
|
+
ctx.print(`Updated MCP role for ${serverName} to ${role}.`);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (serverName || role) {
|
|
269
|
+
ctx.print('Usage: /mcp role <server> <general|docs|filesystem|git|database|browser|automation|ops|remote>');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (subcommand === 'add') {
|
|
275
|
+
let parsed: ParsedMcpAddArgs;
|
|
276
|
+
try {
|
|
277
|
+
parsed = parseAddServerArgs(args);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
ctx.print(summarizeError(error));
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const shellPaths = requireShellPaths(ctx);
|
|
283
|
+
try {
|
|
284
|
+
const result = await mcpApi.upsertServerConfig(shellPaths, parsed.scope, parsed.server);
|
|
285
|
+
const connected = listServerSecurity().find((entry) => entry.name === parsed.server.name)?.connected ?? false;
|
|
286
|
+
ctx.print([
|
|
287
|
+
`MCP server "${parsed.server.name}" saved to ${parsed.scope} config: ${result.path}.`,
|
|
288
|
+
`Runtime reload: ${connected ? 'connected' : 'server saved; connection needs attention'} (+${result.reload.added} ~${result.reload.changed} -${result.reload.removed}, unchanged ${result.reload.unchanged}).`,
|
|
289
|
+
`Command: ${parsed.server.command}${parsed.server.args?.length ? ` ${parsed.server.args.join(' ')}` : ''}`,
|
|
290
|
+
'Next: /mcp tools',
|
|
291
|
+
].join('\n'));
|
|
292
|
+
} catch (error) {
|
|
293
|
+
ctx.print(`MCP add failed: ${summarizeError(error)}`);
|
|
294
|
+
}
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (subcommand === 'remove') {
|
|
299
|
+
const serverName = args[1]?.trim();
|
|
300
|
+
if (!serverName) {
|
|
301
|
+
ctx.print('Usage: /mcp remove <server> [--scope project|global]');
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
let scope: McpConfigScope = 'project';
|
|
305
|
+
try {
|
|
306
|
+
for (let index = 2; index < args.length; index += 1) {
|
|
307
|
+
if (args[index] === '--scope') {
|
|
308
|
+
const value = readFlagValue(args, index, '--scope');
|
|
309
|
+
if (!isMcpScope(value)) {
|
|
310
|
+
ctx.print(`Invalid MCP scope "${value}". Expected project or global.`);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
scope = value;
|
|
314
|
+
index += 1;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
} catch (error) {
|
|
318
|
+
ctx.print(summarizeError(error));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const shellPaths = requireShellPaths(ctx);
|
|
322
|
+
try {
|
|
323
|
+
const result = await mcpApi.removeServerConfig(shellPaths, scope, serverName);
|
|
324
|
+
ctx.print(result.removed
|
|
325
|
+
? `Removed MCP server "${serverName}" from ${scope} config ${result.path}. Reload: +${result.reload.added} ~${result.reload.changed} -${result.reload.removed}, unchanged ${result.reload.unchanged}.`
|
|
326
|
+
: `No ${scope} MCP server named "${serverName}" exists in ${result.path}.\nIf it still appears, it is coming from another config scope or external MCP config.`);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
ctx.print(`MCP remove failed: ${summarizeError(error)}`);
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (subcommand === 'reload') {
|
|
334
|
+
try {
|
|
335
|
+
const result = await reloadMcpRuntime(ctx);
|
|
336
|
+
const servers = listServerSecurity();
|
|
337
|
+
ctx.print(`Reloaded MCP runtime from config. ${servers.filter((server) => server.connected).length}/${servers.length} server(s) connected. Result: +${result.added} ~${result.changed} -${result.removed}, unchanged ${result.unchanged}.`);
|
|
338
|
+
} catch (error) {
|
|
339
|
+
ctx.print(`MCP reload failed: ${summarizeError(error)}`);
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (subcommand === 'config') {
|
|
345
|
+
const shellPaths = requireShellPaths(ctx);
|
|
346
|
+
try {
|
|
347
|
+
const effective = mcpApi.getEffectiveConfig(shellPaths);
|
|
348
|
+
ctx.print([
|
|
349
|
+
'MCP Config',
|
|
350
|
+
' locations:',
|
|
351
|
+
...effective.locations.map((location) => ` ${location.scope}/${location.kind}${location.writable ? ' writable' : ' read-only'} ${location.path}`),
|
|
352
|
+
` effective servers: ${effective.servers.length}`,
|
|
353
|
+
...effective.servers.map((entry) => {
|
|
354
|
+
const server = entry.server;
|
|
355
|
+
const envKeys = Object.keys(server.env ?? {});
|
|
356
|
+
return ` - ${server.name}: ${server.command}${server.args?.length ? ` ${server.args.join(' ')}` : ''} source=${entry.source.scope}/${entry.source.kind}${envKeys.length ? ` envKeys=${envKeys.join(',')}` : ''}`;
|
|
357
|
+
}),
|
|
358
|
+
'',
|
|
359
|
+
'Add or update from inside the TUI:',
|
|
360
|
+
' /mcp add <name> <command> [args...] [--scope project|global] [--role <role>] [--trust <mode>]',
|
|
361
|
+
'Example:',
|
|
362
|
+
' /mcp add filesystem npx -y @modelcontextprotocol/server-filesystem . --scope project --role filesystem --trust constrained',
|
|
363
|
+
].join('\n'));
|
|
364
|
+
} catch (error) {
|
|
365
|
+
ctx.print(`MCP config read failed: ${summarizeError(error)}`);
|
|
366
|
+
}
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (subcommand === 'quarantine') {
|
|
371
|
+
const serverName = args[1];
|
|
372
|
+
const action = args[2];
|
|
373
|
+
if (!serverName) {
|
|
374
|
+
ctx.print('Usage: /mcp quarantine <server> [detail]\n /mcp quarantine <server> approve [operatorId]');
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (action === 'approve') {
|
|
378
|
+
const operatorId = args[3] || 'operator';
|
|
379
|
+
mcpApi.approveSchemaQuarantine(serverName, operatorId);
|
|
380
|
+
ctx.print(`Approved MCP schema quarantine override for ${serverName} as ${operatorId}. Refresh is still recommended.`);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const detail = args.slice(2).join(' ') || 'quarantined by operator';
|
|
384
|
+
mcpApi.quarantineSchema(serverName, 'operator_flagged', detail);
|
|
385
|
+
ctx.print(`Quarantined MCP schema for ${serverName}.\nReason: ${detail}`);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const servers = listServerSecurity();
|
|
390
|
+
if (servers.length === 0) {
|
|
391
|
+
ctx.print(
|
|
392
|
+
'No MCP servers configured.\n'
|
|
393
|
+
+ 'Add servers to one of these locations (scanned in order):\n'
|
|
394
|
+
+ ' ~/.config/mcp/mcp.json (global XDG)\n'
|
|
395
|
+
+ ' ~/.mcp/mcp.json (global dotdir)\n'
|
|
396
|
+
+ ' ~/.config/claude/claude_desktop_config.json (Claude Desktop)\n'
|
|
397
|
+
+ ' .mcp/mcp.json (project-local)\n'
|
|
398
|
+
+ ' .goodvibes/mcp.json (goodvibes project)\n'
|
|
399
|
+
+ '\nAdd one from inside the TUI:\n'
|
|
400
|
+
+ ' /mcp add filesystem npx -y @modelcontextprotocol/server-filesystem . --scope project --role filesystem\n'
|
|
401
|
+
+ '\nFormat: { "servers": [{ "name": "my-server", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }] }'
|
|
402
|
+
);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const connected = servers.filter(s => s.connected);
|
|
407
|
+
const disconnected = servers.filter(s => !s.connected);
|
|
408
|
+
const lines: string[] = [`MCP Servers (${connected.length}/${servers.length} connected):`];
|
|
409
|
+
for (const s of servers) {
|
|
410
|
+
const pathScope = s.allowedPaths.length > 0 ? ` paths=${s.allowedPaths.length}` : '';
|
|
411
|
+
const hostScope = s.allowedHosts.length > 0 ? ` hosts=${s.allowedHosts.length}` : '';
|
|
412
|
+
const freshness = ` freshness=${s.schemaFreshness}`;
|
|
413
|
+
const quarantine = s.schemaFreshness === 'quarantined' ? ` quarantine=${s.quarantineReason ?? 'unknown'}` : '';
|
|
414
|
+
lines.push(` ${s.connected ? '[connected] ' : '[disconnected]'} ${s.name} trust=${s.trustMode} role=${s.role}${freshness}${quarantine}${pathScope}${hostScope}`);
|
|
415
|
+
}
|
|
416
|
+
if (connected.length > 0) {
|
|
417
|
+
lines.push('');
|
|
418
|
+
lines.push('Run "/mcp tools" to list all tools, or "/mcp tools <server>" for a specific server.');
|
|
419
|
+
lines.push('Run "/mcp" to open the fullscreen MCP workspace, or "/mcp add <name> <command> [args...] [--scope project|global]" to add/update without restarting.');
|
|
420
|
+
lines.push('Run "/mcp reload" after editing MCP config outside the TUI.');
|
|
421
|
+
lines.push('Run "/mcp trust <server> <mode>" to change trust mode, or "/mcp role <server> <role>" to change its coherence role.');
|
|
422
|
+
lines.push('Run "/mcp quarantine <server> [detail]" to block a server, or "/mcp quarantine <server> approve [operatorId]" to approve a temporary override.');
|
|
423
|
+
lines.push('Use /settings → MCP to explicitly enable allow-all for a server.');
|
|
424
|
+
}
|
|
425
|
+
if (disconnected.length > 0) {
|
|
426
|
+
lines.push('');
|
|
427
|
+
lines.push(`${disconnected.length} server(s) failed to connect. Check server command and args in your config.`);
|
|
428
|
+
}
|
|
429
|
+
ctx.print(lines.join('\n'));
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
+
|
|
3
|
+
export function registerMemoryProductRuntimeCommands(registry: CommandRegistry): void {
|
|
4
|
+
registry.register({
|
|
5
|
+
name: 'memory-sync',
|
|
6
|
+
aliases: ['memsync'],
|
|
7
|
+
description: 'Dedicated front-door for durable memory export/import and bundle exchange',
|
|
8
|
+
usage: '[export <path> [scope] | import <path>]',
|
|
9
|
+
async handler(args, ctx) {
|
|
10
|
+
const sub = (args[0] ?? '').toLowerCase();
|
|
11
|
+
if (!ctx.executeCommand) {
|
|
12
|
+
ctx.print('Memory sync controls are not available in this runtime.');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (sub === 'export' && args[1]) {
|
|
16
|
+
const scope = args[2];
|
|
17
|
+
const recallArgs = ['export', args[1], ...(scope ? ['--scope', scope] : [])];
|
|
18
|
+
await ctx.executeCommand('recall', recallArgs);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (sub === 'import' && args[1]) {
|
|
22
|
+
await ctx.executeCommand('recall', ['import', args[1]]);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
ctx.print('Usage: /memory-sync [export <path> [scope] | import <path>]');
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
registry.register({
|
|
30
|
+
name: 'handoff',
|
|
31
|
+
description: 'Dedicated front-door for reviewable memory handoff bundles',
|
|
32
|
+
usage: '[export <path> [scope] | inspect <path> | import <path>]',
|
|
33
|
+
async handler(args, ctx) {
|
|
34
|
+
const sub = (args[0] ?? '').toLowerCase();
|
|
35
|
+
if (!ctx.executeCommand) {
|
|
36
|
+
ctx.print('Handoff controls are not available in this runtime.');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (sub === 'export' && args[1]) {
|
|
40
|
+
const scope = args[2];
|
|
41
|
+
await ctx.executeCommand('recall', ['handoff-export', args[1], ...(scope ? ['--scope', scope] : [])]);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (sub === 'inspect' && args[1]) {
|
|
45
|
+
await ctx.executeCommand('recall', ['handoff-inspect', args[1]]);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (sub === 'import' && args[1]) {
|
|
49
|
+
await ctx.executeCommand('recall', ['handoff-import', args[1]]);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
ctx.print('Usage: /handoff [export <path> [scope] | inspect <path> | import <path>]');
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
registry.register({
|
|
57
|
+
name: 'session-memory',
|
|
58
|
+
description: 'Dedicated front-door for session-scoped memory capture and review',
|
|
59
|
+
usage: '[queue [limit] | export <path> | add <class> <summary...>]',
|
|
60
|
+
async handler(args, ctx) {
|
|
61
|
+
const sub = (args[0] ?? 'queue').toLowerCase();
|
|
62
|
+
if (!ctx.executeCommand) {
|
|
63
|
+
ctx.print('Session memory controls are not available in this runtime.');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (sub === 'queue') {
|
|
67
|
+
await ctx.executeCommand('recall', ['queue', ...(args[1] ? [args[1]] : [])]);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (sub === 'export' && args[1]) {
|
|
71
|
+
await ctx.executeCommand('recall', ['export', args[1], '--scope', 'session']);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (sub === 'add' && args.length >= 3) {
|
|
75
|
+
await ctx.executeCommand('recall', ['add', args[1], ...args.slice(2), '--scope', 'session']);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
ctx.print('Usage: /session-memory [queue [limit] | export <path> | add <class> <summary...>]');
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
registry.register({
|
|
83
|
+
name: 'team-memory',
|
|
84
|
+
description: 'Dedicated front-door for team/shared memory review and exchange',
|
|
85
|
+
usage: '[queue [limit] | export <path> | import <path> | capture policy]',
|
|
86
|
+
async handler(args, ctx) {
|
|
87
|
+
const sub = (args[0] ?? 'queue').toLowerCase();
|
|
88
|
+
if (!ctx.executeCommand) {
|
|
89
|
+
ctx.print('Team memory controls are not available in this runtime.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (sub === 'queue') {
|
|
93
|
+
await ctx.executeCommand('recall', ['queue', ...(args[1] ? [args[1]] : [])]);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (sub === 'export' && args[1]) {
|
|
97
|
+
await ctx.executeCommand('recall', ['handoff-export', args[1], '--scope', 'team']);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (sub === 'import' && args[1]) {
|
|
101
|
+
await ctx.executeCommand('recall', ['handoff-import', args[1]]);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (sub === 'capture' && args[1]?.toLowerCase() === 'policy') {
|
|
105
|
+
await ctx.executeCommand('recall', ['capture', 'policy']);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
ctx.print('Usage: /team-memory [queue [limit] | export <path> | import <path> | capture policy]');
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|