@butlerw/vellum 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/LICENSE +21 -0
- package/README.md +411 -0
- package/__fixtures__/responses/code-generation.json +42 -0
- package/__fixtures__/responses/error-response.json +20 -0
- package/__fixtures__/responses/hello-world.json +32 -0
- package/dist/auth-6MCXESOH.js +26 -0
- package/dist/chunk-SECXJGWA.js +597 -0
- package/dist/index.js +34023 -0
- package/package.json +67 -0
- package/src/__tests__/commands.e2e.test.ts +728 -0
- package/src/__tests__/credentials.test.ts +713 -0
- package/src/__tests__/mode-e2e.test.ts +391 -0
- package/src/__tests__/tui-integration.test.tsx +1271 -0
- package/src/agents/__tests__/task-persistence.test.ts +235 -0
- package/src/agents/commands/delegate.ts +240 -0
- package/src/agents/commands/index.ts +10 -0
- package/src/agents/commands/resume.ts +335 -0
- package/src/agents/index.ts +29 -0
- package/src/agents/task-persistence.ts +272 -0
- package/src/agents/task-resumption.ts +242 -0
- package/src/app.tsx +4737 -0
- package/src/commands/__tests__/.gitkeep +1 -0
- package/src/commands/__tests__/agents.test.ts +606 -0
- package/src/commands/__tests__/auth.test.ts +626 -0
- package/src/commands/__tests__/autocomplete.test.ts +683 -0
- package/src/commands/__tests__/batch.test.ts +287 -0
- package/src/commands/__tests__/chain-pipe-parser.test.ts +654 -0
- package/src/commands/__tests__/completion.test.ts +238 -0
- package/src/commands/__tests__/core.test.ts +363 -0
- package/src/commands/__tests__/executor.test.ts +496 -0
- package/src/commands/__tests__/exit-codes.test.ts +220 -0
- package/src/commands/__tests__/init.test.ts +243 -0
- package/src/commands/__tests__/language.test.ts +353 -0
- package/src/commands/__tests__/mode-cli.test.ts +667 -0
- package/src/commands/__tests__/model.test.ts +277 -0
- package/src/commands/__tests__/parser.test.ts +493 -0
- package/src/commands/__tests__/performance.bench.ts +380 -0
- package/src/commands/__tests__/registry.test.ts +534 -0
- package/src/commands/__tests__/resume.test.ts +449 -0
- package/src/commands/__tests__/security.test.ts +845 -0
- package/src/commands/__tests__/stream-json.test.ts +372 -0
- package/src/commands/__tests__/user-commands.test.ts +597 -0
- package/src/commands/adapters.ts +267 -0
- package/src/commands/agent.ts +395 -0
- package/src/commands/agents/generate.ts +506 -0
- package/src/commands/agents/index.ts +272 -0
- package/src/commands/agents/show.ts +271 -0
- package/src/commands/agents/validate.ts +387 -0
- package/src/commands/auth.ts +883 -0
- package/src/commands/autocomplete.ts +480 -0
- package/src/commands/batch/command.ts +388 -0
- package/src/commands/batch/executor.ts +361 -0
- package/src/commands/batch/index.ts +12 -0
- package/src/commands/commit.ts +235 -0
- package/src/commands/completion/index.ts +371 -0
- package/src/commands/condense.ts +191 -0
- package/src/commands/config.ts +344 -0
- package/src/commands/context-provider.ts +173 -0
- package/src/commands/copy.ts +329 -0
- package/src/commands/core/clear.ts +38 -0
- package/src/commands/core/exit.ts +43 -0
- package/src/commands/core/help.ts +354 -0
- package/src/commands/core/index.ts +15 -0
- package/src/commands/cost.ts +179 -0
- package/src/commands/credentials.tsx +618 -0
- package/src/commands/custom-agents/__tests__/custom-agents.test.ts +709 -0
- package/src/commands/custom-agents/create.ts +377 -0
- package/src/commands/custom-agents/export.ts +135 -0
- package/src/commands/custom-agents/import.ts +199 -0
- package/src/commands/custom-agents/index.ts +372 -0
- package/src/commands/custom-agents/info.ts +318 -0
- package/src/commands/custom-agents/list.ts +267 -0
- package/src/commands/custom-agents/validate.ts +388 -0
- package/src/commands/diff-mode.ts +241 -0
- package/src/commands/env.ts +53 -0
- package/src/commands/executor.ts +579 -0
- package/src/commands/exit-codes.ts +202 -0
- package/src/commands/index.ts +701 -0
- package/src/commands/init/index.ts +15 -0
- package/src/commands/init/prompts.ts +366 -0
- package/src/commands/init/templates/commands-readme.md +80 -0
- package/src/commands/init/templates/example-command.md +79 -0
- package/src/commands/init/templates/example-skill.md +168 -0
- package/src/commands/init/templates/example-workflow.md +101 -0
- package/src/commands/init/templates/prompts-readme.md +52 -0
- package/src/commands/init/templates/rules-readme.md +63 -0
- package/src/commands/init/templates/skills-readme.md +83 -0
- package/src/commands/init/templates/workflows-readme.md +94 -0
- package/src/commands/init.ts +391 -0
- package/src/commands/install.ts +90 -0
- package/src/commands/language.ts +191 -0
- package/src/commands/loaders/.gitkeep +1 -0
- package/src/commands/lsp.ts +199 -0
- package/src/commands/markdown-commands.ts +253 -0
- package/src/commands/mcp.ts +588 -0
- package/src/commands/memory/export.ts +341 -0
- package/src/commands/memory/index.ts +148 -0
- package/src/commands/memory/list.ts +261 -0
- package/src/commands/memory/search.ts +346 -0
- package/src/commands/memory/utils.ts +15 -0
- package/src/commands/metrics.ts +75 -0
- package/src/commands/migrate/index.ts +16 -0
- package/src/commands/migrate/prompts.ts +477 -0
- package/src/commands/mode.ts +331 -0
- package/src/commands/model.ts +298 -0
- package/src/commands/onboard.ts +205 -0
- package/src/commands/open.ts +169 -0
- package/src/commands/output/stream-json.ts +373 -0
- package/src/commands/parser/chain-parser.ts +370 -0
- package/src/commands/parser/index.ts +29 -0
- package/src/commands/parser/pipe-parser.ts +480 -0
- package/src/commands/parser.ts +588 -0
- package/src/commands/persistence.ts +355 -0
- package/src/commands/progress.ts +18 -0
- package/src/commands/prompt/index.ts +17 -0
- package/src/commands/prompt/validate.ts +621 -0
- package/src/commands/prompt-priority.ts +401 -0
- package/src/commands/registry.ts +374 -0
- package/src/commands/sandbox/index.ts +131 -0
- package/src/commands/security/index.ts +21 -0
- package/src/commands/security/input-sanitizer.ts +168 -0
- package/src/commands/security/permission-checker.ts +456 -0
- package/src/commands/security/sensitive-data.ts +350 -0
- package/src/commands/session/delete.ts +38 -0
- package/src/commands/session/export.ts +39 -0
- package/src/commands/session/index.ts +26 -0
- package/src/commands/session/list.ts +26 -0
- package/src/commands/session/resume.ts +562 -0
- package/src/commands/session/search.ts +434 -0
- package/src/commands/session/show.ts +26 -0
- package/src/commands/settings.ts +368 -0
- package/src/commands/setup.ts +23 -0
- package/src/commands/shell/index.ts +16 -0
- package/src/commands/shell/setup.ts +422 -0
- package/src/commands/shell-init.ts +50 -0
- package/src/commands/shell-integration/index.ts +194 -0
- package/src/commands/skill.ts +1220 -0
- package/src/commands/spec.ts +558 -0
- package/src/commands/status.ts +246 -0
- package/src/commands/theme.ts +211 -0
- package/src/commands/think.ts +551 -0
- package/src/commands/trust.ts +211 -0
- package/src/commands/tutorial.ts +522 -0
- package/src/commands/types.ts +512 -0
- package/src/commands/update.ts +274 -0
- package/src/commands/usage.ts +213 -0
- package/src/commands/user-commands.ts +630 -0
- package/src/commands/utils.ts +142 -0
- package/src/commands/vim.ts +152 -0
- package/src/commands/workflow.ts +257 -0
- package/src/components/header.tsx +25 -0
- package/src/components/input.tsx +25 -0
- package/src/components/message-list.tsx +32 -0
- package/src/components/status-bar.tsx +23 -0
- package/src/index.tsx +614 -0
- package/src/onboarding/__tests__/tutorial.test.ts +740 -0
- package/src/onboarding/index.ts +69 -0
- package/src/onboarding/tips/index.ts +9 -0
- package/src/onboarding/tips/tip-engine.ts +459 -0
- package/src/onboarding/tutorial/index.ts +88 -0
- package/src/onboarding/tutorial/lessons/basics.ts +151 -0
- package/src/onboarding/tutorial/lessons/index.ts +151 -0
- package/src/onboarding/tutorial/lessons/modes.ts +230 -0
- package/src/onboarding/tutorial/lessons/tools.ts +172 -0
- package/src/onboarding/tutorial/progress-tracker.ts +350 -0
- package/src/onboarding/tutorial/storage.ts +249 -0
- package/src/onboarding/tutorial/tutorial-system.ts +462 -0
- package/src/onboarding/tutorial/types.ts +310 -0
- package/src/orchestrator-singleton.ts +129 -0
- package/src/shutdown.ts +33 -0
- package/src/test/e2e/assertions.ts +267 -0
- package/src/test/e2e/fixtures.ts +204 -0
- package/src/test/e2e/harness.ts +575 -0
- package/src/test/e2e/index.ts +57 -0
- package/src/test/e2e/types.ts +228 -0
- package/src/test/fixtures/__tests__/fake-response-loader.test.ts +314 -0
- package/src/test/fixtures/fake-response-loader.ts +314 -0
- package/src/test/fixtures/index.ts +20 -0
- package/src/tui/__tests__/mcp-panel.test.tsx +82 -0
- package/src/tui/__tests__/mcp-wiring.test.tsx +78 -0
- package/src/tui/__tests__/mode-components.test.tsx +395 -0
- package/src/tui/__tests__/permission-ask-flow.test.tsx +138 -0
- package/src/tui/__tests__/sidebar-panel-data.test.tsx +148 -0
- package/src/tui/__tests__/tools-panel-hotkeys.test.tsx +41 -0
- package/src/tui/adapters/agent-adapter.ts +1008 -0
- package/src/tui/adapters/index.ts +48 -0
- package/src/tui/adapters/message-adapter.ts +315 -0
- package/src/tui/adapters/persistence-bridge.ts +331 -0
- package/src/tui/adapters/session-adapter.ts +419 -0
- package/src/tui/buffered-stdout.ts +223 -0
- package/src/tui/components/AgentProgress.tsx +424 -0
- package/src/tui/components/Banner/AsciiArt.ts +160 -0
- package/src/tui/components/Banner/Banner.tsx +355 -0
- package/src/tui/components/Banner/ShimmerContext.tsx +131 -0
- package/src/tui/components/Banner/ShimmerText.tsx +193 -0
- package/src/tui/components/Banner/TypeWriterGradient.tsx +321 -0
- package/src/tui/components/Banner/index.ts +61 -0
- package/src/tui/components/Banner/useShimmer.ts +241 -0
- package/src/tui/components/ChatView.tsx +11 -0
- package/src/tui/components/Checkpoint/CheckpointDiffView.tsx +371 -0
- package/src/tui/components/Checkpoint/SnapshotCheckpointPanel.tsx +440 -0
- package/src/tui/components/Checkpoint/index.ts +19 -0
- package/src/tui/components/CostDisplay.tsx +226 -0
- package/src/tui/components/InitErrorBanner.tsx +122 -0
- package/src/tui/components/Input/Autocomplete.tsx +603 -0
- package/src/tui/components/Input/EnhancedCommandInput.tsx +471 -0
- package/src/tui/components/Input/HighlightedText.tsx +236 -0
- package/src/tui/components/Input/MentionAutocomplete.tsx +375 -0
- package/src/tui/components/Input/TextInput.tsx +1002 -0
- package/src/tui/components/Input/__tests__/Autocomplete.test.tsx +374 -0
- package/src/tui/components/Input/__tests__/TextInput.test.tsx +241 -0
- package/src/tui/components/Input/__tests__/highlight.test.ts +219 -0
- package/src/tui/components/Input/__tests__/slash-command-utils.test.ts +104 -0
- package/src/tui/components/Input/highlight.ts +362 -0
- package/src/tui/components/Input/index.ts +36 -0
- package/src/tui/components/Input/slash-command-utils.ts +135 -0
- package/src/tui/components/Layout.tsx +432 -0
- package/src/tui/components/McpPanel.tsx +137 -0
- package/src/tui/components/MemoryPanel.tsx +448 -0
- package/src/tui/components/Messages/CodeBlock.tsx +527 -0
- package/src/tui/components/Messages/DiffView.tsx +679 -0
- package/src/tui/components/Messages/ImageReference.tsx +89 -0
- package/src/tui/components/Messages/MarkdownBlock.tsx +228 -0
- package/src/tui/components/Messages/MarkdownRenderer.tsx +498 -0
- package/src/tui/components/Messages/MessageBubble.tsx +270 -0
- package/src/tui/components/Messages/MessageList.tsx +1719 -0
- package/src/tui/components/Messages/StreamingText.tsx +216 -0
- package/src/tui/components/Messages/ThinkingBlock.tsx +408 -0
- package/src/tui/components/Messages/ToolResultPreview.tsx +243 -0
- package/src/tui/components/Messages/__tests__/CodeBlock.test.tsx +296 -0
- package/src/tui/components/Messages/__tests__/DiffView.test.tsx +239 -0
- package/src/tui/components/Messages/__tests__/MarkdownRenderer.test.tsx +303 -0
- package/src/tui/components/Messages/__tests__/MessageBubble.test.tsx +268 -0
- package/src/tui/components/Messages/__tests__/MessageList.test.tsx +324 -0
- package/src/tui/components/Messages/__tests__/StreamingText.test.tsx +215 -0
- package/src/tui/components/Messages/index.ts +25 -0
- package/src/tui/components/ModeIndicator.tsx +177 -0
- package/src/tui/components/ModeSelector.tsx +216 -0
- package/src/tui/components/ModelSelector.tsx +339 -0
- package/src/tui/components/OnboardingWizard.tsx +670 -0
- package/src/tui/components/PhaseProgressIndicator.tsx +270 -0
- package/src/tui/components/RateLimitIndicator.tsx +82 -0
- package/src/tui/components/ScreenReaderLayout.tsx +295 -0
- package/src/tui/components/SettingsPanel.tsx +643 -0
- package/src/tui/components/Sidebar/SystemStatusPanel.tsx +284 -0
- package/src/tui/components/Sidebar/index.ts +9 -0
- package/src/tui/components/Status/ModelStatusBar.tsx +270 -0
- package/src/tui/components/Status/index.ts +12 -0
- package/src/tui/components/StatusBar/AgentModeIndicator.tsx +257 -0
- package/src/tui/components/StatusBar/ContextProgress.tsx +167 -0
- package/src/tui/components/StatusBar/FileChangesIndicator.tsx +62 -0
- package/src/tui/components/StatusBar/GitIndicator.tsx +89 -0
- package/src/tui/components/StatusBar/HeaderBar.tsx +126 -0
- package/src/tui/components/StatusBar/ModelIndicator.tsx +157 -0
- package/src/tui/components/StatusBar/PersistenceStatusIndicator.tsx +210 -0
- package/src/tui/components/StatusBar/ResilienceIndicator.tsx +106 -0
- package/src/tui/components/StatusBar/SandboxIndicator.tsx +167 -0
- package/src/tui/components/StatusBar/StatusBar.tsx +368 -0
- package/src/tui/components/StatusBar/ThinkingModeIndicator.tsx +170 -0
- package/src/tui/components/StatusBar/TokenBreakdown.tsx +246 -0
- package/src/tui/components/StatusBar/TokenCounter.tsx +135 -0
- package/src/tui/components/StatusBar/TrustModeIndicator.tsx +130 -0
- package/src/tui/components/StatusBar/WorkspaceIndicator.tsx +86 -0
- package/src/tui/components/StatusBar/__tests__/AgentModeIndicator.test.tsx +193 -0
- package/src/tui/components/StatusBar/__tests__/StatusBar.test.tsx +729 -0
- package/src/tui/components/StatusBar/index.ts +60 -0
- package/src/tui/components/TipBanner.tsx +115 -0
- package/src/tui/components/TodoItem.tsx +208 -0
- package/src/tui/components/TodoPanel.tsx +455 -0
- package/src/tui/components/Tools/ApprovalQueue.tsx +407 -0
- package/src/tui/components/Tools/OptionSelector.tsx +160 -0
- package/src/tui/components/Tools/PermissionDialog.tsx +286 -0
- package/src/tui/components/Tools/ToolParams.tsx +483 -0
- package/src/tui/components/Tools/ToolsPanel.tsx +178 -0
- package/src/tui/components/Tools/__tests__/PermissionDialog.test.tsx +510 -0
- package/src/tui/components/Tools/__tests__/ToolParams.test.tsx +432 -0
- package/src/tui/components/Tools/index.ts +21 -0
- package/src/tui/components/TrustPrompt.tsx +279 -0
- package/src/tui/components/UpdateBanner.tsx +166 -0
- package/src/tui/components/VimModeIndicator.tsx +112 -0
- package/src/tui/components/backtrack/BacktrackControls.tsx +402 -0
- package/src/tui/components/backtrack/index.ts +13 -0
- package/src/tui/components/common/AutoApprovalStatus.tsx +251 -0
- package/src/tui/components/common/CostWarning.tsx +294 -0
- package/src/tui/components/common/DynamicShortcutHints.tsx +209 -0
- package/src/tui/components/common/EnhancedLoadingIndicator.tsx +305 -0
- package/src/tui/components/common/ErrorBoundary.tsx +140 -0
- package/src/tui/components/common/GradientText.tsx +224 -0
- package/src/tui/components/common/HotkeyHelpModal.tsx +193 -0
- package/src/tui/components/common/HotkeyHints.tsx +70 -0
- package/src/tui/components/common/MaxSizedBox.tsx +354 -0
- package/src/tui/components/common/NewMessagesBadge.tsx +65 -0
- package/src/tui/components/common/ProtectedFileLegend.tsx +89 -0
- package/src/tui/components/common/ScrollIndicator.tsx +160 -0
- package/src/tui/components/common/Spinner.tsx +342 -0
- package/src/tui/components/common/StreamingIndicator.tsx +316 -0
- package/src/tui/components/common/VirtualizedList/VirtualizedList.tsx +428 -0
- package/src/tui/components/common/VirtualizedList/hooks/index.ts +19 -0
- package/src/tui/components/common/VirtualizedList/hooks/useBatchedScroll.ts +64 -0
- package/src/tui/components/common/VirtualizedList/hooks/useScrollAnchor.ts +290 -0
- package/src/tui/components/common/VirtualizedList/hooks/useVirtualization.ts +340 -0
- package/src/tui/components/common/VirtualizedList/index.ts +30 -0
- package/src/tui/components/common/VirtualizedList/types.ts +107 -0
- package/src/tui/components/common/__tests__/NewMessagesBadge.test.tsx +74 -0
- package/src/tui/components/common/__tests__/ScrollIndicator.test.tsx +193 -0
- package/src/tui/components/common/index.ts +110 -0
- package/src/tui/components/index.ts +79 -0
- package/src/tui/components/session/CheckpointPanel.tsx +323 -0
- package/src/tui/components/session/RollbackDialog.tsx +169 -0
- package/src/tui/components/session/SessionItem.tsx +136 -0
- package/src/tui/components/session/SessionListPanel.tsx +252 -0
- package/src/tui/components/session/SessionPicker.tsx +449 -0
- package/src/tui/components/session/SessionPreview.tsx +240 -0
- package/src/tui/components/session/__tests__/session.test.tsx +408 -0
- package/src/tui/components/session/index.ts +28 -0
- package/src/tui/components/session/types.ts +116 -0
- package/src/tui/components/theme/__tests__/tokens.test.ts +471 -0
- package/src/tui/components/theme/index.ts +227 -0
- package/src/tui/components/theme/tokens.ts +484 -0
- package/src/tui/config/defaults.ts +134 -0
- package/src/tui/config/index.ts +17 -0
- package/src/tui/context/AnimationContext.tsx +284 -0
- package/src/tui/context/AppContext.tsx +349 -0
- package/src/tui/context/BracketedPasteContext.tsx +372 -0
- package/src/tui/context/LspContext.tsx +192 -0
- package/src/tui/context/McpContext.tsx +325 -0
- package/src/tui/context/MessagesContext.tsx +870 -0
- package/src/tui/context/OverflowContext.tsx +213 -0
- package/src/tui/context/RateLimitContext.tsx +108 -0
- package/src/tui/context/ResilienceContext.tsx +275 -0
- package/src/tui/context/RootProvider.tsx +136 -0
- package/src/tui/context/ScrollContext.tsx +331 -0
- package/src/tui/context/ToolsContext.tsx +702 -0
- package/src/tui/context/__tests__/BracketedPasteContext.test.tsx +416 -0
- package/src/tui/context/index.ts +140 -0
- package/src/tui/enterprise-integration.ts +282 -0
- package/src/tui/hooks/__tests__/useBacktrack.test.tsx +138 -0
- package/src/tui/hooks/__tests__/useBracketedPaste.test.tsx +222 -0
- package/src/tui/hooks/__tests__/useCopyMode.test.tsx +336 -0
- package/src/tui/hooks/__tests__/useHotkeys.ctrl-input.test.tsx +96 -0
- package/src/tui/hooks/__tests__/useHotkeys.test.tsx +454 -0
- package/src/tui/hooks/__tests__/useInputHistory.test.tsx +660 -0
- package/src/tui/hooks/__tests__/useLineBuffer.test.ts +295 -0
- package/src/tui/hooks/__tests__/useModeController.test.ts +137 -0
- package/src/tui/hooks/__tests__/useModeShortcuts.test.tsx +142 -0
- package/src/tui/hooks/__tests__/useScrollController.test.ts +464 -0
- package/src/tui/hooks/__tests__/useVim.test.tsx +531 -0
- package/src/tui/hooks/index.ts +252 -0
- package/src/tui/hooks/useAgentLoop.ts +712 -0
- package/src/tui/hooks/useAlternateBuffer.ts +398 -0
- package/src/tui/hooks/useAnimatedScrollbar.ts +241 -0
- package/src/tui/hooks/useBacktrack.ts +443 -0
- package/src/tui/hooks/useBracketedPaste.ts +104 -0
- package/src/tui/hooks/useCollapsible.ts +240 -0
- package/src/tui/hooks/useCopyMode.ts +382 -0
- package/src/tui/hooks/useCostSummary.ts +75 -0
- package/src/tui/hooks/useDesktopNotification.ts +414 -0
- package/src/tui/hooks/useDiffMode.ts +44 -0
- package/src/tui/hooks/useFileChangeStats.ts +110 -0
- package/src/tui/hooks/useFileSuggestions.ts +284 -0
- package/src/tui/hooks/useFlickerDetector.ts +250 -0
- package/src/tui/hooks/useGitStatus.ts +200 -0
- package/src/tui/hooks/useHotkeys.ts +579 -0
- package/src/tui/hooks/useImagePaste.ts +114 -0
- package/src/tui/hooks/useInputHighlight.ts +145 -0
- package/src/tui/hooks/useInputHistory.ts +246 -0
- package/src/tui/hooks/useKeyboardScroll.ts +209 -0
- package/src/tui/hooks/useLineBuffer.ts +356 -0
- package/src/tui/hooks/useMentionAutocomplete.ts +235 -0
- package/src/tui/hooks/useModeController.ts +167 -0
- package/src/tui/hooks/useModeShortcuts.ts +196 -0
- package/src/tui/hooks/usePermissionHandler.ts +146 -0
- package/src/tui/hooks/usePersistence.ts +480 -0
- package/src/tui/hooks/usePersistenceShortcuts.ts +225 -0
- package/src/tui/hooks/usePlaceholderRotation.ts +143 -0
- package/src/tui/hooks/useProviderStatus.ts +270 -0
- package/src/tui/hooks/useRateLimitStatus.ts +90 -0
- package/src/tui/hooks/useScreenReader.ts +315 -0
- package/src/tui/hooks/useScrollController.ts +450 -0
- package/src/tui/hooks/useScrollEventBatcher.ts +185 -0
- package/src/tui/hooks/useSidebarPanelData.ts +115 -0
- package/src/tui/hooks/useSmoothScroll.ts +202 -0
- package/src/tui/hooks/useSnapshots.ts +300 -0
- package/src/tui/hooks/useStateAndRef.ts +50 -0
- package/src/tui/hooks/useTerminalSize.ts +206 -0
- package/src/tui/hooks/useToolApprovalController.ts +91 -0
- package/src/tui/hooks/useVim.ts +334 -0
- package/src/tui/hooks/useWorkspace.ts +56 -0
- package/src/tui/i18n/__tests__/init.test.ts +278 -0
- package/src/tui/i18n/__tests__/language-config.test.ts +199 -0
- package/src/tui/i18n/__tests__/locale-detection.test.ts +250 -0
- package/src/tui/i18n/__tests__/settings-integration.test.ts +262 -0
- package/src/tui/i18n/index.ts +72 -0
- package/src/tui/i18n/init.ts +131 -0
- package/src/tui/i18n/language-config.ts +106 -0
- package/src/tui/i18n/locale-detection.ts +173 -0
- package/src/tui/i18n/settings-integration.ts +557 -0
- package/src/tui/i18n/tui-namespace.ts +538 -0
- package/src/tui/i18n/types.ts +312 -0
- package/src/tui/index.ts +43 -0
- package/src/tui/lsp-integration.ts +409 -0
- package/src/tui/metrics-integration.ts +366 -0
- package/src/tui/plugins.ts +383 -0
- package/src/tui/resilience.ts +342 -0
- package/src/tui/sandbox-integration.ts +317 -0
- package/src/tui/services/clipboard.ts +348 -0
- package/src/tui/services/fuzzy-search.ts +441 -0
- package/src/tui/services/index.ts +72 -0
- package/src/tui/services/markdown-renderer.ts +565 -0
- package/src/tui/services/open-external.ts +247 -0
- package/src/tui/services/syntax-highlighter.ts +483 -0
- package/src/tui/slash-commands.ts +12 -0
- package/src/tui/theme/index.ts +15 -0
- package/src/tui/theme/provider.tsx +206 -0
- package/src/tui/tip-integration.ts +300 -0
- package/src/tui/types/__tests__/ink-extended.test.ts +121 -0
- package/src/tui/types/ink-extended.ts +87 -0
- package/src/tui/utils/__tests__/bracketedPaste.test.ts +231 -0
- package/src/tui/utils/__tests__/heightEstimator.test.ts +157 -0
- package/src/tui/utils/__tests__/text-width.test.ts +158 -0
- package/src/tui/utils/__tests__/textSanitizer.test.ts +266 -0
- package/src/tui/utils/__tests__/ui-sizing.test.ts +169 -0
- package/src/tui/utils/bracketedPaste.ts +107 -0
- package/src/tui/utils/cursor-manager.ts +131 -0
- package/src/tui/utils/detectTerminal.ts +596 -0
- package/src/tui/utils/findLastSafeSplitPoint.ts +92 -0
- package/src/tui/utils/heightEstimator.ts +198 -0
- package/src/tui/utils/index.ts +91 -0
- package/src/tui/utils/isNarrowWidth.ts +52 -0
- package/src/tui/utils/stdoutGuard.ts +90 -0
- package/src/tui/utils/synchronized-update.ts +70 -0
- package/src/tui/utils/text-width.ts +225 -0
- package/src/tui/utils/textSanitizer.ts +225 -0
- package/src/tui/utils/textUtils.ts +114 -0
- package/src/tui/utils/ui-sizing.ts +192 -0
- package/src/tui-blessed/app.ts +160 -0
- package/src/tui-blessed/index.ts +2 -0
- package/src/tui-blessed/neo-blessed.d.ts +6 -0
- package/src/tui-blessed/test.ts +21 -0
- package/src/tui-blessed/types.ts +14 -0
- package/src/utils/icons.ts +130 -0
- package/src/utils/index.ts +33 -0
- package/src/utils/resume-hint.ts +86 -0
- package/src/version.ts +1 -0
- package/tsconfig.json +8 -0
- package/vitest.config.ts +35 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Slash Commands (Phase 40)
|
|
3
|
+
*
|
|
4
|
+
* Provides slash commands for MCP (Model Context Protocol) server management:
|
|
5
|
+
* - /mcp list - List configured MCP servers
|
|
6
|
+
* - /mcp status - Show connection status and tool count
|
|
7
|
+
* - /mcp add - Add a new MCP server (interactive)
|
|
8
|
+
* - /mcp remove - Remove an MCP server
|
|
9
|
+
* - /mcp tools - List available tools from MCP servers
|
|
10
|
+
*
|
|
11
|
+
* @module cli/commands/mcp
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as fs from "node:fs/promises";
|
|
15
|
+
import * as os from "node:os";
|
|
16
|
+
import * as path from "node:path";
|
|
17
|
+
import type { McpHub, McpServer, McpSettings, McpStdioConfig } from "@vellum/mcp";
|
|
18
|
+
import { ICONS } from "../utils/icons.js";
|
|
19
|
+
import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
|
|
20
|
+
import { error, interactive, success } from "./types.js";
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Module State
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reference to the active McpHub instance.
|
|
28
|
+
* Set by the App component when initialized.
|
|
29
|
+
*/
|
|
30
|
+
let mcpHub: McpHub | null = null;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Set the McpHub instance for MCP commands.
|
|
34
|
+
* Called by the App component during initialization.
|
|
35
|
+
*
|
|
36
|
+
* @param hub - The McpHub instance to use
|
|
37
|
+
*/
|
|
38
|
+
export function setMcpCommandsHub(hub: McpHub | null): void {
|
|
39
|
+
mcpHub = hub;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the current McpHub instance.
|
|
44
|
+
* Returns null if not yet initialized.
|
|
45
|
+
*/
|
|
46
|
+
export function getMcpCommandsHub(): McpHub | null {
|
|
47
|
+
return mcpHub;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// Status Helpers
|
|
52
|
+
// =============================================================================
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get text indicator for a server connection status.
|
|
56
|
+
*/
|
|
57
|
+
function getStatusIndicator(status: string): string {
|
|
58
|
+
switch (status) {
|
|
59
|
+
case "connected":
|
|
60
|
+
return "[ON]";
|
|
61
|
+
case "connecting":
|
|
62
|
+
return "[...]";
|
|
63
|
+
case "disconnected":
|
|
64
|
+
return "[OFF]";
|
|
65
|
+
case "disabled":
|
|
66
|
+
return "[DIS]";
|
|
67
|
+
case "failed":
|
|
68
|
+
return ICONS.error;
|
|
69
|
+
case "needs_auth":
|
|
70
|
+
return "[Auth]";
|
|
71
|
+
case "needs_client_registration":
|
|
72
|
+
return "[Reg]";
|
|
73
|
+
default:
|
|
74
|
+
return "[?]";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Format server info for list display.
|
|
80
|
+
*/
|
|
81
|
+
function formatServerListItem(server: McpServer): string {
|
|
82
|
+
const indicator = getStatusIndicator(server.statusInfo.status);
|
|
83
|
+
const disabledTag = server.disabled ? " [disabled]" : "";
|
|
84
|
+
return ` ${indicator} ${server.name}${disabledTag}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Format detailed server status.
|
|
89
|
+
*/
|
|
90
|
+
function formatServerStatus(server: McpServer): string {
|
|
91
|
+
const indicator = getStatusIndicator(server.statusInfo.status);
|
|
92
|
+
const toolCount = server.tools?.length ?? 0;
|
|
93
|
+
const resourceCount = server.resources?.length ?? 0;
|
|
94
|
+
|
|
95
|
+
const lines = [`${indicator} ${server.name}`, ` Status: ${server.statusInfo.status}`];
|
|
96
|
+
|
|
97
|
+
if (server.statusInfo.status === "failed" && "error" in server.statusInfo) {
|
|
98
|
+
lines.push(` Error: ${server.statusInfo.error}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (server.statusInfo.status === "connected") {
|
|
102
|
+
lines.push(` Tools: ${toolCount}`);
|
|
103
|
+
lines.push(` Resources: ${resourceCount}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (server.disabled) {
|
|
107
|
+
lines.push(" Note: Server is disabled in config");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (server.uid) {
|
|
111
|
+
lines.push(` UID: ${server.uid}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return lines.join("\n");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// =============================================================================
|
|
118
|
+
// Subcommand Handlers
|
|
119
|
+
// =============================================================================
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Handle /mcp list - List configured MCP servers
|
|
123
|
+
*/
|
|
124
|
+
async function handleList(_ctx: CommandContext): Promise<CommandResult> {
|
|
125
|
+
if (!mcpHub) {
|
|
126
|
+
return error("OPERATION_NOT_ALLOWED", "MCP hub not initialized. No MCP servers available.", [
|
|
127
|
+
"/help mcp",
|
|
128
|
+
]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const servers = mcpHub.getServers();
|
|
132
|
+
|
|
133
|
+
if (servers.length === 0) {
|
|
134
|
+
return success(
|
|
135
|
+
"📡 No MCP servers configured.\n\n" + "Add servers to ~/.vellum/mcp.json or use /mcp add"
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const lines = [
|
|
140
|
+
"📡 Configured MCP Servers",
|
|
141
|
+
"",
|
|
142
|
+
...servers.map(formatServerListItem),
|
|
143
|
+
"",
|
|
144
|
+
`Total: ${servers.length} server(s)`,
|
|
145
|
+
"",
|
|
146
|
+
"Use /mcp status for detailed information.",
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
return success(lines.join("\n"));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Handle /mcp status - Show connection status and tool count
|
|
154
|
+
*/
|
|
155
|
+
async function handleStatus(ctx: CommandContext): Promise<CommandResult> {
|
|
156
|
+
if (!mcpHub) {
|
|
157
|
+
return error("OPERATION_NOT_ALLOWED", "MCP hub not initialized. No MCP servers available.", [
|
|
158
|
+
"/help mcp",
|
|
159
|
+
]);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const serverName = ctx.parsedArgs.positional[1] as string | undefined;
|
|
163
|
+
const servers = mcpHub.getServers();
|
|
164
|
+
|
|
165
|
+
if (servers.length === 0) {
|
|
166
|
+
return success("📡 No MCP servers configured.");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// If specific server requested
|
|
170
|
+
if (serverName) {
|
|
171
|
+
const server = servers.find((s) => s.name === serverName);
|
|
172
|
+
if (!server) {
|
|
173
|
+
return error("RESOURCE_NOT_FOUND", `Server "${serverName}" not found.`, [
|
|
174
|
+
`Available servers: ${servers.map((s) => s.name).join(", ")}`,
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
return success(formatServerStatus(server));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Show all servers
|
|
181
|
+
const connectedCount = servers.filter((s) => s.statusInfo.status === "connected").length;
|
|
182
|
+
const totalTools = servers.reduce((sum, s) => sum + (s.tools?.length ?? 0), 0);
|
|
183
|
+
|
|
184
|
+
const lines = [
|
|
185
|
+
"📡 MCP Server Status",
|
|
186
|
+
"",
|
|
187
|
+
...servers.map(formatServerStatus),
|
|
188
|
+
"",
|
|
189
|
+
"─".repeat(40),
|
|
190
|
+
`Connected: ${connectedCount}/${servers.length}`,
|
|
191
|
+
`Total Tools: ${totalTools}`,
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
return success(lines.join("\n"));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// =============================================================================
|
|
198
|
+
// Config File Helpers
|
|
199
|
+
// =============================================================================
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Get the global MCP config file path.
|
|
203
|
+
* Uses ~/.vellum/mcp.json on all platforms.
|
|
204
|
+
*/
|
|
205
|
+
function getGlobalMcpConfigPath(): string {
|
|
206
|
+
return path.join(os.homedir(), ".vellum", "mcp.json");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get the project-level MCP config file path.
|
|
211
|
+
*/
|
|
212
|
+
function getProjectMcpConfigPath(): string {
|
|
213
|
+
return path.join(process.cwd(), ".vellum", "mcp.json");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Read existing MCP config file or return empty config.
|
|
218
|
+
*/
|
|
219
|
+
async function readMcpConfig(configPath: string): Promise<McpSettings> {
|
|
220
|
+
try {
|
|
221
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
222
|
+
return JSON.parse(content) as McpSettings;
|
|
223
|
+
} catch {
|
|
224
|
+
// File doesn't exist or invalid JSON - return empty config
|
|
225
|
+
return { mcpServers: {} };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Write MCP config to file, creating directories if needed.
|
|
231
|
+
*/
|
|
232
|
+
async function writeMcpConfig(configPath: string, config: McpSettings): Promise<void> {
|
|
233
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
234
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Handle /mcp add - Add a new MCP server (interactive)
|
|
239
|
+
*/
|
|
240
|
+
async function handleAdd(_ctx: CommandContext): Promise<CommandResult> {
|
|
241
|
+
if (!mcpHub) {
|
|
242
|
+
return error("OPERATION_NOT_ALLOWED", "MCP hub not initialized.", ["/help mcp"]);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Interactive flow: collect server name
|
|
246
|
+
return interactive({
|
|
247
|
+
inputType: "text",
|
|
248
|
+
message: "[MCP] Enter server name:",
|
|
249
|
+
placeholder: "my-mcp-server",
|
|
250
|
+
handler: async (serverName: string): Promise<CommandResult> => {
|
|
251
|
+
if (!serverName.trim()) {
|
|
252
|
+
return error("INVALID_ARGUMENT", "Server name cannot be empty.", []);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Check if server already exists
|
|
256
|
+
const existing = mcpHub?.getServer(serverName);
|
|
257
|
+
if (existing) {
|
|
258
|
+
return error("INVALID_ARGUMENT", `Server "${serverName}" already exists.`, [
|
|
259
|
+
`/mcp remove ${serverName}`,
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Collect command
|
|
264
|
+
return interactive({
|
|
265
|
+
inputType: "text",
|
|
266
|
+
message: `${ICONS.package} Enter command to run:`,
|
|
267
|
+
placeholder: "npx -y @my-org/mcp-server",
|
|
268
|
+
handler: async (command: string): Promise<CommandResult> => {
|
|
269
|
+
if (!command.trim()) {
|
|
270
|
+
return error("INVALID_ARGUMENT", "Command cannot be empty.", []);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Parse command into parts
|
|
274
|
+
const parts = command.trim().split(/\s+/);
|
|
275
|
+
const cmd = parts[0] ?? "";
|
|
276
|
+
const args = parts.slice(1);
|
|
277
|
+
|
|
278
|
+
const serverConfig: McpStdioConfig = {
|
|
279
|
+
command: cmd,
|
|
280
|
+
args: args.length > 0 ? args : undefined,
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// Ask where to save
|
|
284
|
+
return interactive({
|
|
285
|
+
inputType: "select",
|
|
286
|
+
message: "Where do you want to save this configuration?",
|
|
287
|
+
options: [
|
|
288
|
+
"Save to global config (~/.vellum/mcp.json)",
|
|
289
|
+
"Save to project config (.vellum/mcp.json)",
|
|
290
|
+
"Just show me the JSON (manual)",
|
|
291
|
+
],
|
|
292
|
+
handler: async (choice: string): Promise<CommandResult> => {
|
|
293
|
+
// Determine save location based on selection
|
|
294
|
+
const isGlobal = choice.includes("global");
|
|
295
|
+
const isProject = choice.includes("project");
|
|
296
|
+
const isManual = choice.includes("manual") || choice.includes("JSON");
|
|
297
|
+
|
|
298
|
+
// Manual mode - just output JSON (backward compatible)
|
|
299
|
+
if (isManual) {
|
|
300
|
+
const configDisplay = {
|
|
301
|
+
[serverName]: serverConfig,
|
|
302
|
+
};
|
|
303
|
+
const configJson = JSON.stringify(configDisplay, null, 2);
|
|
304
|
+
|
|
305
|
+
return success(
|
|
306
|
+
`${ICONS.success} Server configuration ready!\n\n` +
|
|
307
|
+
"Add this to your ~/.vellum/mcp.json:\n\n" +
|
|
308
|
+
"```json\n" +
|
|
309
|
+
`"mcpServers": ${configJson}\n` +
|
|
310
|
+
"```\n\n" +
|
|
311
|
+
"After adding, the server will be auto-detected.\n" +
|
|
312
|
+
"Or restart Vellum to connect."
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Determine config path
|
|
317
|
+
const configPath = isGlobal
|
|
318
|
+
? getGlobalMcpConfigPath()
|
|
319
|
+
: isProject
|
|
320
|
+
? getProjectMcpConfigPath()
|
|
321
|
+
: getGlobalMcpConfigPath(); // Default to global
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
// Read existing config
|
|
325
|
+
const existingConfig = await readMcpConfig(configPath);
|
|
326
|
+
|
|
327
|
+
// Merge new server
|
|
328
|
+
existingConfig.mcpServers = {
|
|
329
|
+
...existingConfig.mcpServers,
|
|
330
|
+
[serverName]: serverConfig,
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// Write back
|
|
334
|
+
await writeMcpConfig(configPath, existingConfig);
|
|
335
|
+
|
|
336
|
+
return success(
|
|
337
|
+
`${ICONS.success} Server "${serverName}" added to ${configPath}\n\n` +
|
|
338
|
+
"The server will be auto-detected.\n" +
|
|
339
|
+
"Use /mcp status to check connection status."
|
|
340
|
+
);
|
|
341
|
+
} catch (err) {
|
|
342
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
343
|
+
return error("INTERNAL_ERROR", `Failed to write config file: ${message}`, [
|
|
344
|
+
"Check file permissions",
|
|
345
|
+
"Try the manual option instead",
|
|
346
|
+
]);
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
onCancel: () => success("Server addition cancelled."),
|
|
350
|
+
});
|
|
351
|
+
},
|
|
352
|
+
onCancel: () => success("Server addition cancelled."),
|
|
353
|
+
});
|
|
354
|
+
},
|
|
355
|
+
onCancel: () => success("Server addition cancelled."),
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Handle /mcp remove - Remove an MCP server
|
|
361
|
+
*/
|
|
362
|
+
async function handleRemove(ctx: CommandContext): Promise<CommandResult> {
|
|
363
|
+
if (!mcpHub) {
|
|
364
|
+
return error("OPERATION_NOT_ALLOWED", "MCP hub not initialized.", ["/help mcp"]);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const serverName = ctx.parsedArgs.positional[1] as string | undefined;
|
|
368
|
+
|
|
369
|
+
if (!serverName) {
|
|
370
|
+
const servers = mcpHub.getServers();
|
|
371
|
+
if (servers.length === 0) {
|
|
372
|
+
return error("RESOURCE_NOT_FOUND", "No MCP servers configured.", []);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return error("MISSING_ARGUMENT", "Please specify a server name to remove.", [
|
|
376
|
+
`Usage: /mcp remove <server-name>`,
|
|
377
|
+
`Available: ${servers.map((s) => s.name).join(", ")}`,
|
|
378
|
+
]);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const server = mcpHub.getServer(serverName);
|
|
382
|
+
if (!server) {
|
|
383
|
+
return error("RESOURCE_NOT_FOUND", `Server "${serverName}" not found.`, [
|
|
384
|
+
`Use /mcp list to see available servers.`,
|
|
385
|
+
]);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Confirm removal
|
|
389
|
+
return interactive({
|
|
390
|
+
inputType: "confirm",
|
|
391
|
+
message: `${ICONS.warning} Remove server "${serverName}"? This will disconnect it.`,
|
|
392
|
+
defaultValue: "n",
|
|
393
|
+
handler: async (value: string): Promise<CommandResult> => {
|
|
394
|
+
const confirmed = value.toLowerCase() === "y" || value.toLowerCase() === "yes";
|
|
395
|
+
if (!confirmed) {
|
|
396
|
+
return success("Removal cancelled.");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Note: We can't actually delete from config file here.
|
|
400
|
+
// User needs to manually edit mcp.json
|
|
401
|
+
return success(
|
|
402
|
+
`ℹ️ To remove "${serverName}", delete its entry from ~/.vellum/mcp.json\n\n` +
|
|
403
|
+
"The server will be disconnected automatically after config change."
|
|
404
|
+
);
|
|
405
|
+
},
|
|
406
|
+
onCancel: () => success("Removal cancelled."),
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Handle /mcp tools - List available tools from MCP servers
|
|
412
|
+
*/
|
|
413
|
+
async function handleTools(ctx: CommandContext): Promise<CommandResult> {
|
|
414
|
+
if (!mcpHub) {
|
|
415
|
+
return error("OPERATION_NOT_ALLOWED", "MCP hub not initialized.", ["/help mcp"]);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const serverName = ctx.parsedArgs.positional[1] as string | undefined;
|
|
419
|
+
const servers = mcpHub.getServers();
|
|
420
|
+
|
|
421
|
+
if (servers.length === 0) {
|
|
422
|
+
return success("📡 No MCP servers configured. No tools available.");
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// If specific server requested
|
|
426
|
+
if (serverName) {
|
|
427
|
+
const server = servers.find((s) => s.name === serverName);
|
|
428
|
+
if (!server) {
|
|
429
|
+
return error("RESOURCE_NOT_FOUND", `Server "${serverName}" not found.`, [
|
|
430
|
+
`Available servers: ${servers.map((s) => s.name).join(", ")}`,
|
|
431
|
+
]);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (server.statusInfo.status !== "connected") {
|
|
435
|
+
return error(
|
|
436
|
+
"OPERATION_NOT_ALLOWED",
|
|
437
|
+
`Server "${serverName}" is not connected (status: ${server.statusInfo.status}).`,
|
|
438
|
+
["/mcp status"]
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const tools = server.tools ?? [];
|
|
443
|
+
if (tools.length === 0) {
|
|
444
|
+
return success(`[MCP] ${serverName} - No tools available.`);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const lines = [
|
|
448
|
+
`${ICONS.tools} Tools from ${serverName}`,
|
|
449
|
+
"",
|
|
450
|
+
...tools.map((t) => ` - ${t.name}${t.description ? ` - ${t.description}` : ""}`),
|
|
451
|
+
"",
|
|
452
|
+
`Total: ${tools.length} tool(s)`,
|
|
453
|
+
];
|
|
454
|
+
|
|
455
|
+
return success(lines.join("\n"));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Show tools from all connected servers
|
|
459
|
+
const allTools = mcpHub.getAllTools();
|
|
460
|
+
|
|
461
|
+
if (allTools.length === 0) {
|
|
462
|
+
return success(`${ICONS.tools} No tools available from connected MCP servers.`);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Group by server
|
|
466
|
+
const toolsByServer = new Map<string, typeof allTools>();
|
|
467
|
+
for (const tool of allTools) {
|
|
468
|
+
const existing = toolsByServer.get(tool.serverName) ?? [];
|
|
469
|
+
existing.push(tool);
|
|
470
|
+
toolsByServer.set(tool.serverName, existing);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const lines = [`${ICONS.tools} Available MCP Tools`, ""];
|
|
474
|
+
|
|
475
|
+
for (const [server, tools] of toolsByServer) {
|
|
476
|
+
lines.push(`[MCP] ${server}:`);
|
|
477
|
+
for (const tool of tools) {
|
|
478
|
+
lines.push(` - ${tool.name}${tool.description ? ` - ${tool.description}` : ""}`);
|
|
479
|
+
}
|
|
480
|
+
lines.push("");
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
lines.push(`Total: ${allTools.length} tool(s) from ${toolsByServer.size} server(s)`);
|
|
484
|
+
|
|
485
|
+
return success(lines.join("\n"));
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Show help for /mcp command
|
|
490
|
+
*/
|
|
491
|
+
function showHelp(): CommandResult {
|
|
492
|
+
const lines = [
|
|
493
|
+
"[MCP] Server Management",
|
|
494
|
+
"",
|
|
495
|
+
"Subcommands:",
|
|
496
|
+
" list - List configured MCP servers",
|
|
497
|
+
" status - Show connection status and tool count",
|
|
498
|
+
" add - Add a new MCP server (interactive)",
|
|
499
|
+
" remove - Remove an MCP server",
|
|
500
|
+
" tools - List available tools from MCP servers",
|
|
501
|
+
"",
|
|
502
|
+
"Examples:",
|
|
503
|
+
" /mcp list",
|
|
504
|
+
" /mcp status",
|
|
505
|
+
" /mcp status my-server",
|
|
506
|
+
" /mcp tools",
|
|
507
|
+
" /mcp tools my-server",
|
|
508
|
+
" /mcp add",
|
|
509
|
+
" /mcp remove my-server",
|
|
510
|
+
];
|
|
511
|
+
|
|
512
|
+
return success(lines.join("\n"));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// =============================================================================
|
|
516
|
+
// /mcp Command - MCP Server Management
|
|
517
|
+
// =============================================================================
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* /mcp command - Manage MCP (Model Context Protocol) servers.
|
|
521
|
+
*
|
|
522
|
+
* Provides subcommands for listing, inspecting, adding, and removing
|
|
523
|
+
* MCP servers configured in ~/.vellum/mcp.json.
|
|
524
|
+
*/
|
|
525
|
+
export const mcpCommand: SlashCommand = {
|
|
526
|
+
name: "mcp",
|
|
527
|
+
description: "Manage MCP (Model Context Protocol) servers",
|
|
528
|
+
kind: "builtin",
|
|
529
|
+
category: "tools",
|
|
530
|
+
aliases: [],
|
|
531
|
+
positionalArgs: [
|
|
532
|
+
{
|
|
533
|
+
name: "subcommand",
|
|
534
|
+
type: "string",
|
|
535
|
+
description: "Subcommand (list, status, add, remove, tools)",
|
|
536
|
+
required: false,
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
name: "server",
|
|
540
|
+
type: "string",
|
|
541
|
+
description: "Server name (for status, remove, tools)",
|
|
542
|
+
required: false,
|
|
543
|
+
},
|
|
544
|
+
],
|
|
545
|
+
examples: [
|
|
546
|
+
"/mcp - Show help",
|
|
547
|
+
"/mcp list - List configured servers",
|
|
548
|
+
"/mcp status - Show all server status",
|
|
549
|
+
"/mcp tools - List all available tools",
|
|
550
|
+
"/mcp add - Add a new server",
|
|
551
|
+
"/mcp remove X - Remove server X",
|
|
552
|
+
],
|
|
553
|
+
subcommands: [
|
|
554
|
+
{ name: "list", description: "List configured MCP servers" },
|
|
555
|
+
{ name: "status", description: "Show connection status and tool count" },
|
|
556
|
+
{ name: "add", description: "Add a new MCP server" },
|
|
557
|
+
{ name: "remove", description: "Remove an MCP server" },
|
|
558
|
+
{ name: "tools", description: "List available tools from MCP servers" },
|
|
559
|
+
],
|
|
560
|
+
|
|
561
|
+
execute: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
562
|
+
const subcommand = ctx.parsedArgs.positional[0] as string | undefined;
|
|
563
|
+
|
|
564
|
+
switch (subcommand) {
|
|
565
|
+
case "list":
|
|
566
|
+
return handleList(ctx);
|
|
567
|
+
case "status":
|
|
568
|
+
return handleStatus(ctx);
|
|
569
|
+
case "add":
|
|
570
|
+
return handleAdd(ctx);
|
|
571
|
+
case "remove":
|
|
572
|
+
return handleRemove(ctx);
|
|
573
|
+
case "tools":
|
|
574
|
+
return handleTools(ctx);
|
|
575
|
+
default:
|
|
576
|
+
return showHelp();
|
|
577
|
+
}
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
// =============================================================================
|
|
582
|
+
// Export All MCP Commands
|
|
583
|
+
// =============================================================================
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* All MCP-related slash commands for registration.
|
|
587
|
+
*/
|
|
588
|
+
export const mcpSlashCommands: SlashCommand[] = [mcpCommand];
|