@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,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command System Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared utility functions for the command system.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/utils
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// T034B: isSlashCommand
|
|
11
|
+
// =============================================================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if input is a slash command
|
|
15
|
+
*
|
|
16
|
+
* Returns true if the input starts with a forward slash after trimming.
|
|
17
|
+
* Handles edge cases:
|
|
18
|
+
* - Empty string → false
|
|
19
|
+
* - Whitespace only → false
|
|
20
|
+
* - Just "/" → false (no command name)
|
|
21
|
+
* - "/command" → true
|
|
22
|
+
* - " /command" → true (leading whitespace allowed)
|
|
23
|
+
*
|
|
24
|
+
* @param input - User input string to check
|
|
25
|
+
* @returns True if input is a slash command
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* isSlashCommand('/help') // true
|
|
30
|
+
* isSlashCommand(' /login') // true
|
|
31
|
+
* isSlashCommand('/a') // true
|
|
32
|
+
* isSlashCommand('/') // false (no command name)
|
|
33
|
+
* isSlashCommand('') // false
|
|
34
|
+
* isSlashCommand(' ') // false
|
|
35
|
+
* isSlashCommand('hello') // false
|
|
36
|
+
* isSlashCommand('//comment') // true (starts with /)
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function isSlashCommand(input: string): boolean {
|
|
40
|
+
// Handle empty or whitespace-only
|
|
41
|
+
if (!input || typeof input !== "string") {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const trimmed = input.trim();
|
|
46
|
+
|
|
47
|
+
// Must have at least 2 chars: "/" + command char
|
|
48
|
+
if (trimmed.length < 2) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Must start with "/"
|
|
53
|
+
if (trimmed[0] !== "/") {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Second character must not be whitespace (ensures command name exists)
|
|
58
|
+
const secondChar = trimmed[1];
|
|
59
|
+
if (secondChar === " " || secondChar === "\t" || secondChar === "\n") {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// Additional Utilities
|
|
68
|
+
// =============================================================================
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Extract command name from slash command input
|
|
72
|
+
*
|
|
73
|
+
* @param input - Slash command input (e.g., "/help topic")
|
|
74
|
+
* @returns Command name without slash, or null if not a valid command
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* extractCommandName('/help topic') // 'help'
|
|
79
|
+
* extractCommandName('/login') // 'login'
|
|
80
|
+
* extractCommandName('hello') // null
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function extractCommandName(input: string): string | null {
|
|
84
|
+
if (!isSlashCommand(input)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const trimmed = input.trim();
|
|
89
|
+
// Remove leading slash and split by whitespace
|
|
90
|
+
const parts = trimmed.slice(1).split(/\s+/);
|
|
91
|
+
return parts[0]?.toLowerCase() ?? null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Split command input into command name and arguments
|
|
96
|
+
*
|
|
97
|
+
* @param input - Slash command input
|
|
98
|
+
* @returns Object with command name and args array, or null if invalid
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* parseCommandInput('/login anthropic --store keychain')
|
|
103
|
+
* // { command: 'login', args: ['anthropic', '--store', 'keychain'] }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export function parseCommandInput(input: string): { command: string; args: string[] } | null {
|
|
107
|
+
if (!isSlashCommand(input)) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const trimmed = input.trim();
|
|
112
|
+
const parts = trimmed.slice(1).split(/\s+/);
|
|
113
|
+
const command = parts[0]?.toLowerCase() ?? "";
|
|
114
|
+
const args = parts.slice(1);
|
|
115
|
+
|
|
116
|
+
return { command, args };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Mask a sensitive value for display
|
|
121
|
+
*
|
|
122
|
+
* Shows first and last few characters with dots in between.
|
|
123
|
+
*
|
|
124
|
+
* @param value - Value to mask
|
|
125
|
+
* @param visibleChars - Number of visible chars at start and end (default: 4)
|
|
126
|
+
* @returns Masked string
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* maskValue('sk-1234567890abcdef') // 'sk-1...cdef'
|
|
131
|
+
* maskValue('short') // '****'
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export function maskValue(value: string, visibleChars = 4): string {
|
|
135
|
+
if (value.length <= visibleChars * 2) {
|
|
136
|
+
return "*".repeat(Math.max(4, value.length));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const start = value.slice(0, visibleChars);
|
|
140
|
+
const end = value.slice(-visibleChars);
|
|
141
|
+
return `${start}...${end}`;
|
|
142
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vim Mode Slash Command (T041)
|
|
3
|
+
*
|
|
4
|
+
* Provides the /vim command for toggling Vim editing mode.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/vim
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
|
|
10
|
+
import { success } from "./types.js";
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Module State
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Callback to toggle vim mode.
|
|
18
|
+
* Set by the App component when initialized.
|
|
19
|
+
*/
|
|
20
|
+
let vimToggleCallback: (() => void) | null = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Callback to check if vim mode is enabled.
|
|
24
|
+
* Set by the App component when initialized.
|
|
25
|
+
*/
|
|
26
|
+
let vimEnabledCallback: (() => boolean) | null = null;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set the vim mode callbacks for the /vim command.
|
|
30
|
+
* Called by the App component during initialization.
|
|
31
|
+
*
|
|
32
|
+
* @param toggle - Callback to toggle vim mode on/off
|
|
33
|
+
* @param isEnabled - Callback to check if vim mode is currently enabled
|
|
34
|
+
*/
|
|
35
|
+
export function setVimCallbacks(toggle: () => void, isEnabled: () => boolean): void {
|
|
36
|
+
vimToggleCallback = toggle;
|
|
37
|
+
vimEnabledCallback = isEnabled;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Clear vim mode callbacks.
|
|
42
|
+
* Called during cleanup.
|
|
43
|
+
*/
|
|
44
|
+
export function clearVimCallbacks(): void {
|
|
45
|
+
vimToggleCallback = null;
|
|
46
|
+
vimEnabledCallback = null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// /vim Command
|
|
51
|
+
// =============================================================================
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* /vim command - Toggle Vim editing mode.
|
|
55
|
+
*
|
|
56
|
+
* When enabled:
|
|
57
|
+
* - Input field uses Vim-style modal editing
|
|
58
|
+
* - NORMAL mode: navigation and commands
|
|
59
|
+
* - INSERT mode: text entry (i, a, I, A, o, O)
|
|
60
|
+
* - VISUAL mode: text selection (v, V)
|
|
61
|
+
* - COMMAND mode: command line (:)
|
|
62
|
+
* - Press Escape to return to NORMAL mode
|
|
63
|
+
* - Press Ctrl+V to toggle vim mode on/off
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```
|
|
67
|
+
* /vim - Toggle vim mode on/off
|
|
68
|
+
* /vim on - Enable vim mode
|
|
69
|
+
* /vim off - Disable vim mode
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export const vimCommand: SlashCommand = {
|
|
73
|
+
name: "vim",
|
|
74
|
+
description: "Toggle Vim editing mode for input",
|
|
75
|
+
kind: "builtin",
|
|
76
|
+
category: "config",
|
|
77
|
+
aliases: ["vi"],
|
|
78
|
+
positionalArgs: [
|
|
79
|
+
{
|
|
80
|
+
name: "state",
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "Explicitly set state: 'on' or 'off'",
|
|
83
|
+
required: false,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
examples: [
|
|
87
|
+
"/vim - Toggle vim mode on/off",
|
|
88
|
+
"/vim on - Enable vim mode",
|
|
89
|
+
"/vim off - Disable vim mode",
|
|
90
|
+
],
|
|
91
|
+
|
|
92
|
+
execute: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
93
|
+
const state = ctx.parsedArgs.positional[0] as string | undefined;
|
|
94
|
+
|
|
95
|
+
// Check if callbacks are available
|
|
96
|
+
if (!vimToggleCallback || !vimEnabledCallback) {
|
|
97
|
+
return success("Vim mode system not initialized.");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const currentlyEnabled = vimEnabledCallback();
|
|
101
|
+
|
|
102
|
+
// Handle explicit on/off
|
|
103
|
+
if (state === "on") {
|
|
104
|
+
if (currentlyEnabled) {
|
|
105
|
+
return success(
|
|
106
|
+
"Vim mode is already enabled.\n\nUse 'i' to enter INSERT mode, Escape to return to NORMAL mode."
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
vimToggleCallback();
|
|
110
|
+
return success(
|
|
111
|
+
"🟢 Vim mode enabled.\n\nYou are now in NORMAL mode. Press 'i' to enter INSERT mode for typing."
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (state === "off") {
|
|
116
|
+
if (!currentlyEnabled) {
|
|
117
|
+
return success("Vim mode is already disabled.");
|
|
118
|
+
}
|
|
119
|
+
vimToggleCallback();
|
|
120
|
+
return success("⚫ Vim mode disabled.\n\nReturned to standard input mode.");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Toggle
|
|
124
|
+
vimToggleCallback();
|
|
125
|
+
const newState = vimEnabledCallback();
|
|
126
|
+
|
|
127
|
+
if (newState) {
|
|
128
|
+
return success(
|
|
129
|
+
"🟢 Vim mode enabled.\n\n" +
|
|
130
|
+
"You are now in NORMAL mode. Key bindings:\n" +
|
|
131
|
+
" • i, a, I, A, o, O - Enter INSERT mode\n" +
|
|
132
|
+
" • v, V - Enter VISUAL mode\n" +
|
|
133
|
+
" • : - Enter COMMAND mode\n" +
|
|
134
|
+
" • h, j, k, l - Navigation\n" +
|
|
135
|
+
" • Escape - Return to NORMAL mode\n" +
|
|
136
|
+
" • Ctrl+V - Toggle vim mode off\n\n" +
|
|
137
|
+
"Press 'i' to start typing."
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return success("⚫ Vim mode disabled.\n\nReturned to standard input mode.");
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// =============================================================================
|
|
146
|
+
// Export
|
|
147
|
+
// =============================================================================
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* All vim-related slash commands for registration.
|
|
151
|
+
*/
|
|
152
|
+
export const vimSlashCommands: SlashCommand[] = [vimCommand];
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Slash Commands (T035)
|
|
3
|
+
*
|
|
4
|
+
* Provides slash commands for workflow management:
|
|
5
|
+
* - /workflow - List available workflows
|
|
6
|
+
* - /workflow {name} - Inject workflow instructions
|
|
7
|
+
*
|
|
8
|
+
* Workflows are loaded from .vellum/workflows/*.md files.
|
|
9
|
+
*
|
|
10
|
+
* @module cli/commands/workflow
|
|
11
|
+
* @see REQ-011
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createWorkflowLoader, type Workflow, type WorkflowLoader } from "@vellum/core";
|
|
15
|
+
import { ICONS } from "../utils/icons.js";
|
|
16
|
+
import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
|
|
17
|
+
import { error, pending, success } from "./types.js";
|
|
18
|
+
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Module State
|
|
21
|
+
// =============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Cached WorkflowLoader instance.
|
|
25
|
+
* Initialized lazily on first use.
|
|
26
|
+
*/
|
|
27
|
+
let cachedLoader: WorkflowLoader | null = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Last workspace path used to create the loader.
|
|
31
|
+
*/
|
|
32
|
+
let lastWorkspacePath: string | null = null;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get or create WorkflowLoader for the given workspace.
|
|
36
|
+
*
|
|
37
|
+
* @param cwd - Current working directory (workspace root)
|
|
38
|
+
* @returns WorkflowLoader instance
|
|
39
|
+
*/
|
|
40
|
+
function getLoader(cwd: string): WorkflowLoader {
|
|
41
|
+
// Create new loader if workspace changed
|
|
42
|
+
if (cachedLoader === null || lastWorkspacePath !== cwd) {
|
|
43
|
+
cachedLoader = createWorkflowLoader({ cwd });
|
|
44
|
+
lastWorkspacePath = cwd;
|
|
45
|
+
}
|
|
46
|
+
return cachedLoader;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Clear the cached loader (for testing).
|
|
51
|
+
*/
|
|
52
|
+
export function clearWorkflowLoaderCache(): void {
|
|
53
|
+
cachedLoader = null;
|
|
54
|
+
lastWorkspacePath = null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// =============================================================================
|
|
58
|
+
// Helper Functions
|
|
59
|
+
// =============================================================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Format workflow list for display.
|
|
63
|
+
*
|
|
64
|
+
* @param workflows - Array of loaded workflows
|
|
65
|
+
* @returns Formatted string for TUI display
|
|
66
|
+
*/
|
|
67
|
+
function formatWorkflowList(workflows: Workflow[]): string {
|
|
68
|
+
if (workflows.length === 0) {
|
|
69
|
+
return `📂 No workflows found.
|
|
70
|
+
|
|
71
|
+
Create workflows in .vellum/workflows/*.md with YAML frontmatter:
|
|
72
|
+
|
|
73
|
+
\`\`\`yaml
|
|
74
|
+
---
|
|
75
|
+
id: deploy
|
|
76
|
+
name: Deploy to Production
|
|
77
|
+
description: Step-by-step deployment workflow
|
|
78
|
+
steps:
|
|
79
|
+
- id: build
|
|
80
|
+
prompt: "Build the project for production"
|
|
81
|
+
- id: test
|
|
82
|
+
prompt: "Run all tests"
|
|
83
|
+
- id: deploy
|
|
84
|
+
prompt: "Deploy to production server"
|
|
85
|
+
---
|
|
86
|
+
\`\`\`
|
|
87
|
+
|
|
88
|
+
Then run: /workflow deploy`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const lines = [`${ICONS.workflow} Available Workflows:\n`];
|
|
92
|
+
|
|
93
|
+
for (const wf of workflows) {
|
|
94
|
+
const stepCount = wf.steps.length;
|
|
95
|
+
const source = wf.source === "project" ? "[project]" : "[user]";
|
|
96
|
+
lines.push(` ${ICONS.bullet} ${wf.id} - ${wf.name || wf.description || "No description"}`);
|
|
97
|
+
lines.push(` ${stepCount} step${stepCount !== 1 ? "s" : ""} ${source}\n`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
lines.push("\nUsage: /workflow <name> [--var=value ...]");
|
|
101
|
+
|
|
102
|
+
return lines.join("\n");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Format workflow instructions for injection.
|
|
107
|
+
*
|
|
108
|
+
* @param workflow - The workflow to format
|
|
109
|
+
* @param variables - Variable values for interpolation
|
|
110
|
+
* @returns Formatted workflow instructions
|
|
111
|
+
*/
|
|
112
|
+
function formatWorkflowInstructions(workflow: Workflow, variables: Record<string, string>): string {
|
|
113
|
+
const loader = getLoader(lastWorkspacePath ?? process.cwd());
|
|
114
|
+
return loader.getWorkflowInstructions(workflow, variables);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Parse variable arguments from command args.
|
|
119
|
+
* Format: --var=value or --var value
|
|
120
|
+
*
|
|
121
|
+
* @param args - Raw argument string
|
|
122
|
+
* @returns Parsed variables object
|
|
123
|
+
*/
|
|
124
|
+
function parseVariables(args: string): { name: string; variables: Record<string, string> } {
|
|
125
|
+
const parts = args.trim().split(/\s+/);
|
|
126
|
+
const name = parts[0] ?? "";
|
|
127
|
+
const variables: Record<string, string> = {};
|
|
128
|
+
|
|
129
|
+
for (let i = 1; i < parts.length; i++) {
|
|
130
|
+
const part = parts[i];
|
|
131
|
+
if (part?.startsWith("--")) {
|
|
132
|
+
const eqIndex = part.indexOf("=");
|
|
133
|
+
if (eqIndex > 2) {
|
|
134
|
+
// --key=value format
|
|
135
|
+
const key = part.slice(2, eqIndex);
|
|
136
|
+
const value = part.slice(eqIndex + 1);
|
|
137
|
+
variables[key] = value;
|
|
138
|
+
} else {
|
|
139
|
+
const nextPart = parts[i + 1];
|
|
140
|
+
if (nextPart && !nextPart.startsWith("--")) {
|
|
141
|
+
// --key value format
|
|
142
|
+
const key = part.slice(2);
|
|
143
|
+
variables[key] = nextPart;
|
|
144
|
+
i++;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { name, variables };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// =============================================================================
|
|
154
|
+
// /workflow Command - List and Execute Workflows
|
|
155
|
+
// =============================================================================
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* /workflow command handler.
|
|
159
|
+
*
|
|
160
|
+
* Without arguments: Lists all available workflows
|
|
161
|
+
* With workflow name: Loads and injects workflow instructions
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```
|
|
165
|
+
* /workflow # List all workflows
|
|
166
|
+
* /workflow deploy # Inject deploy workflow
|
|
167
|
+
* /workflow deploy --env=prod --branch=main
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
async function executeWorkflow(ctx: CommandContext): Promise<CommandResult> {
|
|
171
|
+
const args = ctx.parsedArgs.raw.trim();
|
|
172
|
+
const loader = getLoader(ctx.session.cwd);
|
|
173
|
+
|
|
174
|
+
// No arguments - list workflows
|
|
175
|
+
if (!args) {
|
|
176
|
+
try {
|
|
177
|
+
const workflows = await loader.loadAll();
|
|
178
|
+
return success(formatWorkflowList(workflows));
|
|
179
|
+
} catch (err) {
|
|
180
|
+
return error(
|
|
181
|
+
"INTERNAL_ERROR",
|
|
182
|
+
`Failed to load workflows: ${err instanceof Error ? err.message : String(err)}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Parse workflow name and variables
|
|
188
|
+
const { name, variables } = parseVariables(args);
|
|
189
|
+
|
|
190
|
+
if (!name) {
|
|
191
|
+
return error(
|
|
192
|
+
"INVALID_ARGUMENT",
|
|
193
|
+
"Please specify a workflow name. Use /workflow to list available workflows."
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
// Try to load the specific workflow
|
|
199
|
+
const workflow = await loader.load(name);
|
|
200
|
+
|
|
201
|
+
if (!workflow) {
|
|
202
|
+
// Workflow not found - show helpful message
|
|
203
|
+
const workflows = await loader.loadAll();
|
|
204
|
+
const names = workflows.map((w: Workflow) => w.id);
|
|
205
|
+
const suggestion =
|
|
206
|
+
names.length > 0
|
|
207
|
+
? `\n\nAvailable workflows: ${names.join(", ")}`
|
|
208
|
+
: "\n\nNo workflows found. Create one in .vellum/workflows/";
|
|
209
|
+
|
|
210
|
+
return error("RESOURCE_NOT_FOUND", `Workflow "${name}" not found.${suggestion}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Format workflow instructions for injection
|
|
214
|
+
const instructions = formatWorkflowInstructions(workflow, variables);
|
|
215
|
+
|
|
216
|
+
// Return pending result to inject instructions into context
|
|
217
|
+
return pending({
|
|
218
|
+
message: `${ICONS.workflow} Loading workflow: ${workflow.name || workflow.id}`,
|
|
219
|
+
promise: Promise.resolve(success(instructions)),
|
|
220
|
+
});
|
|
221
|
+
} catch (err) {
|
|
222
|
+
return error(
|
|
223
|
+
"INTERNAL_ERROR",
|
|
224
|
+
`Failed to load workflow "${name}": ${err instanceof Error ? err.message : String(err)}`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* /workflow slash command definition.
|
|
231
|
+
*/
|
|
232
|
+
export const workflowCommand: SlashCommand = {
|
|
233
|
+
name: "workflow",
|
|
234
|
+
description: "List or execute workflows from .vellum/workflows/",
|
|
235
|
+
kind: "builtin",
|
|
236
|
+
category: "workflow",
|
|
237
|
+
aliases: ["wf"],
|
|
238
|
+
positionalArgs: [
|
|
239
|
+
{
|
|
240
|
+
name: "name",
|
|
241
|
+
type: "string",
|
|
242
|
+
description: "Workflow name to execute (optional)",
|
|
243
|
+
required: false,
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
subcommands: [
|
|
247
|
+
{ name: "list", description: "List available workflows", aliases: ["ls"] },
|
|
248
|
+
{ name: "run", description: "Run a workflow by name" },
|
|
249
|
+
{ name: "validate", description: "Validate workflow file syntax" },
|
|
250
|
+
],
|
|
251
|
+
execute: executeWorkflow,
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* All workflow-related slash commands.
|
|
256
|
+
*/
|
|
257
|
+
export const workflowCommands: SlashCommand[] = [workflowCommand];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header Component
|
|
3
|
+
* @module cli/components/header
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Box, Text } from "ink";
|
|
7
|
+
import type { FC } from "react";
|
|
8
|
+
|
|
9
|
+
export interface HeaderProps {
|
|
10
|
+
title?: string;
|
|
11
|
+
model?: string;
|
|
12
|
+
provider?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const Header: FC<HeaderProps> = ({ title = "Vellum", model, provider }) => {
|
|
16
|
+
return (
|
|
17
|
+
<Box borderStyle="single" paddingX={1}>
|
|
18
|
+
<Text bold color="blue">
|
|
19
|
+
{title}
|
|
20
|
+
</Text>
|
|
21
|
+
{model && <Text> | Model: {model}</Text>}
|
|
22
|
+
{provider && <Text> | Provider: {provider}</Text>}
|
|
23
|
+
</Box>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Component
|
|
3
|
+
* @module cli/components/input
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Box, Text } from "ink";
|
|
7
|
+
import type { FC } from "react";
|
|
8
|
+
|
|
9
|
+
export interface InputProps {
|
|
10
|
+
value?: string;
|
|
11
|
+
onChange?: (value: string) => void;
|
|
12
|
+
onSubmit?: (value: string) => void;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const Input: FC<InputProps> = ({ value = "", placeholder = ">" }) => {
|
|
18
|
+
return (
|
|
19
|
+
<Box>
|
|
20
|
+
<Text>
|
|
21
|
+
{placeholder} {value}
|
|
22
|
+
</Text>
|
|
23
|
+
</Box>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message List Component
|
|
3
|
+
* @module cli/components/message-list
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Box, Text } from "ink";
|
|
7
|
+
import type { FC } from "react";
|
|
8
|
+
|
|
9
|
+
export interface Message {
|
|
10
|
+
role: "user" | "assistant";
|
|
11
|
+
content: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface MessageListProps {
|
|
15
|
+
messages?: Message[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const MessageList: FC<MessageListProps> = ({ messages = [] }) => {
|
|
19
|
+
return (
|
|
20
|
+
<Box flexDirection="column">
|
|
21
|
+
{messages.map((msg, i) => (
|
|
22
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: Messages don't have stable IDs
|
|
23
|
+
<Box key={i} marginBottom={1}>
|
|
24
|
+
<Text color={msg.role === "user" ? "green" : "blue"}>
|
|
25
|
+
{msg.role === "user" ? "You: " : "Assistant: "}
|
|
26
|
+
</Text>
|
|
27
|
+
<Text>{msg.content}</Text>
|
|
28
|
+
</Box>
|
|
29
|
+
))}
|
|
30
|
+
</Box>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Bar Component
|
|
3
|
+
* @module cli/components/status-bar
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Box, Text } from "ink";
|
|
7
|
+
import type { FC } from "react";
|
|
8
|
+
|
|
9
|
+
export interface StatusBarProps {
|
|
10
|
+
status?: string;
|
|
11
|
+
model?: string;
|
|
12
|
+
tokens?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const StatusBar: FC<StatusBarProps> = ({ status = "Ready", model, tokens }) => {
|
|
16
|
+
return (
|
|
17
|
+
<Box borderStyle="single" paddingX={1}>
|
|
18
|
+
<Text color="gray">{status}</Text>
|
|
19
|
+
{model && <Text> | {model}</Text>}
|
|
20
|
+
{tokens !== undefined && <Text> | Tokens: {tokens}</Text>}
|
|
21
|
+
</Box>
|
|
22
|
+
);
|
|
23
|
+
};
|