@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,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy Slash Command
|
|
3
|
+
*
|
|
4
|
+
* Provides clipboard functionality for the CLI:
|
|
5
|
+
* - /copy last - Copy the last assistant message
|
|
6
|
+
* - /copy code - Copy the last code block
|
|
7
|
+
* - /copy file <path> - Copy file contents
|
|
8
|
+
*
|
|
9
|
+
* @module cli/commands/copy
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from "node:fs/promises";
|
|
13
|
+
import * as path from "node:path";
|
|
14
|
+
|
|
15
|
+
import type { AgentLoop, SessionMessage } from "@vellum/core";
|
|
16
|
+
import { copy, isSupported } from "../tui/services/clipboard.js";
|
|
17
|
+
import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
|
|
18
|
+
import { error, success } from "./types.js";
|
|
19
|
+
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// Module State
|
|
22
|
+
// =============================================================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Reference to the active AgentLoop instance.
|
|
26
|
+
* Set by the App component when an agent session is active.
|
|
27
|
+
*/
|
|
28
|
+
let agentLoopRef: AgentLoop | null = null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Set the AgentLoop instance for copy commands.
|
|
32
|
+
* Called by the App component when an agent session starts/ends.
|
|
33
|
+
*
|
|
34
|
+
* @param loop - The AgentLoop instance to use, or null when session ends
|
|
35
|
+
*/
|
|
36
|
+
export function setCopyCommandLoop(loop: AgentLoop | null): void {
|
|
37
|
+
agentLoopRef = loop;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the current AgentLoop instance.
|
|
42
|
+
* Returns null if no agent session is active.
|
|
43
|
+
*/
|
|
44
|
+
export function getCopyCommandLoop(): AgentLoop | null {
|
|
45
|
+
return agentLoopRef;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// =============================================================================
|
|
49
|
+
// Helper Functions
|
|
50
|
+
// =============================================================================
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Extract text content from a SessionMessage's parts.
|
|
54
|
+
*/
|
|
55
|
+
function extractTextFromMessage(msg: SessionMessage): string {
|
|
56
|
+
return msg.parts
|
|
57
|
+
.filter((part): part is { type: "text"; text: string } => part.type === "text")
|
|
58
|
+
.map((part) => part.text)
|
|
59
|
+
.join("\n");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Extract the last assistant message from session messages.
|
|
64
|
+
*/
|
|
65
|
+
function getLastAssistantMessage(messages: SessionMessage[]): string | undefined {
|
|
66
|
+
// Iterate from end to find last assistant message
|
|
67
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
68
|
+
const msg = messages[i];
|
|
69
|
+
if (msg?.role === "assistant") {
|
|
70
|
+
const text = extractTextFromMessage(msg);
|
|
71
|
+
if (text) {
|
|
72
|
+
return text;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Extract code blocks from text content.
|
|
81
|
+
* Returns array of { language, code } objects.
|
|
82
|
+
*/
|
|
83
|
+
function extractCodeBlocks(text: string): Array<{ language: string; code: string }> {
|
|
84
|
+
const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
|
|
85
|
+
const blocks: Array<{ language: string; code: string }> = [];
|
|
86
|
+
|
|
87
|
+
for (const match of text.matchAll(codeBlockRegex)) {
|
|
88
|
+
blocks.push({
|
|
89
|
+
language: match[1] || "text",
|
|
90
|
+
code: match[2]?.trim() || "",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return blocks;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get the last code block from session messages.
|
|
99
|
+
*/
|
|
100
|
+
function getLastCodeBlock(
|
|
101
|
+
messages: SessionMessage[]
|
|
102
|
+
): { language: string; code: string } | undefined {
|
|
103
|
+
// Search from most recent message backwards
|
|
104
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
105
|
+
const msg = messages[i];
|
|
106
|
+
if (msg?.role !== "assistant") continue;
|
|
107
|
+
|
|
108
|
+
const content = extractTextFromMessage(msg);
|
|
109
|
+
const blocks = extractCodeBlocks(content);
|
|
110
|
+
if (blocks.length > 0) {
|
|
111
|
+
// Return the last block in this message
|
|
112
|
+
return blocks[blocks.length - 1];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Read file content with size limit check.
|
|
121
|
+
*/
|
|
122
|
+
async function readFileContent(
|
|
123
|
+
filePath: string,
|
|
124
|
+
cwd: string
|
|
125
|
+
): Promise<{ content: string } | { error: string }> {
|
|
126
|
+
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const stat = await fs.stat(resolvedPath);
|
|
130
|
+
|
|
131
|
+
// 1MB size limit for clipboard
|
|
132
|
+
const MAX_SIZE = 1024 * 1024;
|
|
133
|
+
if (stat.size > MAX_SIZE) {
|
|
134
|
+
return {
|
|
135
|
+
error: `File too large (${Math.round(stat.size / 1024)}KB). Maximum is 1MB.`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const content = await fs.readFile(resolvedPath, "utf-8");
|
|
140
|
+
return { content };
|
|
141
|
+
} catch (err) {
|
|
142
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
143
|
+
return { error: `File not found: ${filePath}` };
|
|
144
|
+
}
|
|
145
|
+
if ((err as NodeJS.ErrnoException).code === "EACCES") {
|
|
146
|
+
return { error: `Permission denied: ${filePath}` };
|
|
147
|
+
}
|
|
148
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
149
|
+
return { error: `Failed to read file: ${message}` };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// =============================================================================
|
|
154
|
+
// Command Implementation
|
|
155
|
+
// =============================================================================
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* /copy command - Copy content to clipboard
|
|
159
|
+
*
|
|
160
|
+
* Subcommands:
|
|
161
|
+
* - last: Copy the last assistant message
|
|
162
|
+
* - code: Copy the last code block
|
|
163
|
+
* - file <path>: Copy file contents
|
|
164
|
+
*/
|
|
165
|
+
export const copyCommand: SlashCommand = {
|
|
166
|
+
name: "copy",
|
|
167
|
+
description: "Copy content to clipboard",
|
|
168
|
+
kind: "builtin",
|
|
169
|
+
category: "tools",
|
|
170
|
+
aliases: ["cp", "yank"],
|
|
171
|
+
positionalArgs: [
|
|
172
|
+
{
|
|
173
|
+
name: "target",
|
|
174
|
+
type: "string",
|
|
175
|
+
description: "What to copy: last, code, or file",
|
|
176
|
+
required: false,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: "path",
|
|
180
|
+
type: "path",
|
|
181
|
+
description: "File path (when target is 'file')",
|
|
182
|
+
required: false,
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
subcommands: [
|
|
186
|
+
{ name: "last", description: "Copy the last assistant message" },
|
|
187
|
+
{ name: "code", description: "Copy the last code block" },
|
|
188
|
+
{ name: "file", description: "Copy file contents" },
|
|
189
|
+
],
|
|
190
|
+
examples: [
|
|
191
|
+
"/copy last - Copy last message",
|
|
192
|
+
"/copy code - Copy last code block",
|
|
193
|
+
"/copy file src/index.ts",
|
|
194
|
+
],
|
|
195
|
+
|
|
196
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Command handler requires comprehensive target validation
|
|
197
|
+
async execute(ctx: CommandContext): Promise<CommandResult> {
|
|
198
|
+
const { parsedArgs, session } = ctx;
|
|
199
|
+
const target = parsedArgs.positional[0] as string | undefined;
|
|
200
|
+
const filePath = parsedArgs.positional[1] as string | undefined;
|
|
201
|
+
|
|
202
|
+
// Check clipboard support
|
|
203
|
+
if (!isSupported()) {
|
|
204
|
+
return error("OPERATION_NOT_ALLOWED", "Clipboard not supported in this environment", [
|
|
205
|
+
"Clipboard access requires a display server or Windows/macOS.",
|
|
206
|
+
"",
|
|
207
|
+
"On Linux, try installing: sudo apt install xclip",
|
|
208
|
+
"In WSL, ensure Windows clipboard integration is enabled.",
|
|
209
|
+
]);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Default to showing help if no target
|
|
213
|
+
if (!target) {
|
|
214
|
+
return success(
|
|
215
|
+
[
|
|
216
|
+
"📋 Copy Command",
|
|
217
|
+
"",
|
|
218
|
+
"Usage:",
|
|
219
|
+
" /copy last Copy the last assistant message",
|
|
220
|
+
" /copy code Copy the last code block",
|
|
221
|
+
" /copy file <path> Copy file contents",
|
|
222
|
+
"",
|
|
223
|
+
"Aliases: /cp, /yank",
|
|
224
|
+
].join("\n")
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Handle file copy (doesn't require agent loop)
|
|
229
|
+
if (target === "file") {
|
|
230
|
+
if (!filePath) {
|
|
231
|
+
return error("MISSING_ARGUMENT", "File path required", [
|
|
232
|
+
"Usage: /copy file <path>",
|
|
233
|
+
"Example: /copy file src/index.ts",
|
|
234
|
+
]);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const result = await readFileContent(filePath, session.cwd);
|
|
238
|
+
if ("error" in result) {
|
|
239
|
+
return error("FILE_NOT_FOUND", result.error);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const copyResult = await copy(result.content, `file: ${filePath}`);
|
|
243
|
+
if (!copyResult.success) {
|
|
244
|
+
return error("INTERNAL_ERROR", copyResult.error);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const lines = result.content.split("\n").length;
|
|
248
|
+
return success(`📋 Copied ${path.basename(filePath)} (${lines} lines)`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Check agent loop for message-based operations
|
|
252
|
+
if (!agentLoopRef) {
|
|
253
|
+
return error("OPERATION_NOT_ALLOWED", "No active conversation", [
|
|
254
|
+
"Start a conversation first, then use /copy to copy messages.",
|
|
255
|
+
]);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const messages = agentLoopRef.getMessages();
|
|
259
|
+
|
|
260
|
+
if (messages.length === 0) {
|
|
261
|
+
return error("RESOURCE_NOT_FOUND", "No messages in conversation", [
|
|
262
|
+
"The conversation is empty. Send a message first.",
|
|
263
|
+
]);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Handle 'last' - copy last assistant message
|
|
267
|
+
if (target === "last") {
|
|
268
|
+
const lastMessage = getLastAssistantMessage(messages);
|
|
269
|
+
|
|
270
|
+
if (!lastMessage) {
|
|
271
|
+
return error("RESOURCE_NOT_FOUND", "No assistant message found", [
|
|
272
|
+
"No assistant messages in the current conversation.",
|
|
273
|
+
]);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const copyResult = await copy(lastMessage, "last message");
|
|
277
|
+
if (!copyResult.success) {
|
|
278
|
+
return error("INTERNAL_ERROR", copyResult.error);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const preview =
|
|
282
|
+
lastMessage.length > 60
|
|
283
|
+
? `${lastMessage.slice(0, 57)}...`
|
|
284
|
+
: lastMessage.replace(/\n/g, "↵");
|
|
285
|
+
|
|
286
|
+
return success(
|
|
287
|
+
`📋 Copied last message (${lastMessage.length} chars)\n Preview: ${preview}`
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Handle 'code' - copy last code block
|
|
292
|
+
if (target === "code") {
|
|
293
|
+
const codeBlock = getLastCodeBlock(messages);
|
|
294
|
+
|
|
295
|
+
if (!codeBlock) {
|
|
296
|
+
return error("RESOURCE_NOT_FOUND", "No code block found", [
|
|
297
|
+
"No code blocks found in the conversation.",
|
|
298
|
+
"Code blocks are detected by ``` fences.",
|
|
299
|
+
]);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const copyResult = await copy(codeBlock.code, `code: ${codeBlock.language}`);
|
|
303
|
+
if (!copyResult.success) {
|
|
304
|
+
return error("INTERNAL_ERROR", copyResult.error);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const lines = codeBlock.code.split("\n").length;
|
|
308
|
+
const lang = codeBlock.language || "text";
|
|
309
|
+
|
|
310
|
+
return success(`📋 Copied ${lang} code block (${lines} lines)`);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Unknown target
|
|
314
|
+
return error("INVALID_ARGUMENT", `Unknown copy target: ${target}`, [
|
|
315
|
+
"Valid targets: last, code, file",
|
|
316
|
+
"",
|
|
317
|
+
"Examples:",
|
|
318
|
+
" /copy last Copy last assistant message",
|
|
319
|
+
" /copy code Copy last code block",
|
|
320
|
+
" /copy file <path> Copy file contents",
|
|
321
|
+
]);
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// =============================================================================
|
|
326
|
+
// Exports
|
|
327
|
+
// =============================================================================
|
|
328
|
+
|
|
329
|
+
export default copyCommand;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clear Command
|
|
3
|
+
*
|
|
4
|
+
* Clears the terminal screen.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/core/clear
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CommandContext, CommandResult, SlashCommand } from "../types.js";
|
|
10
|
+
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// T028: Clear Command Definition
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Clear command - clears the terminal screen
|
|
17
|
+
*
|
|
18
|
+
* Usage: /clear
|
|
19
|
+
*
|
|
20
|
+
* Returns a success result with `clearScreen: true` flag,
|
|
21
|
+
* which instructs the TUI to clear the display.
|
|
22
|
+
*/
|
|
23
|
+
export const clearCommand: SlashCommand = {
|
|
24
|
+
name: "clear",
|
|
25
|
+
description: "Clear the terminal screen",
|
|
26
|
+
kind: "builtin",
|
|
27
|
+
category: "system",
|
|
28
|
+
aliases: ["cls"],
|
|
29
|
+
examples: ["/clear - Clear the screen"],
|
|
30
|
+
|
|
31
|
+
execute: async (_ctx: CommandContext): Promise<CommandResult> => {
|
|
32
|
+
return {
|
|
33
|
+
kind: "success",
|
|
34
|
+
message: "Screen cleared",
|
|
35
|
+
clearScreen: true,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit Command
|
|
3
|
+
*
|
|
4
|
+
* Exits the application immediately.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/core/exit
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CommandContext, CommandResult, SlashCommand } from "../types.js";
|
|
10
|
+
import { success } from "../types.js";
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// T029: Exit Command Definition
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Exit command - exits the application
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* - /exit - Exit immediately
|
|
21
|
+
* - /quit - Exit immediately (alias)
|
|
22
|
+
* - /q - Exit immediately (alias)
|
|
23
|
+
*
|
|
24
|
+
* Emits 'app:exit' event and returns success.
|
|
25
|
+
*/
|
|
26
|
+
export const exitCommand: SlashCommand = {
|
|
27
|
+
name: "exit(quit)",
|
|
28
|
+
description: "Exit the application",
|
|
29
|
+
kind: "builtin",
|
|
30
|
+
category: "system",
|
|
31
|
+
aliases: ["exit", "quit", "q"],
|
|
32
|
+
examples: [
|
|
33
|
+
"/exit - Exit the application",
|
|
34
|
+
"/quit - Exit the application",
|
|
35
|
+
"/q - Exit the application",
|
|
36
|
+
],
|
|
37
|
+
|
|
38
|
+
execute: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
39
|
+
ctx.emit("app:exit", { reason: "user-command" });
|
|
40
|
+
// Message is handled by the app:exit event handler
|
|
41
|
+
return success(undefined, { exit: true });
|
|
42
|
+
},
|
|
43
|
+
};
|