@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,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelIndicator Component (T035)
|
|
3
|
+
*
|
|
4
|
+
* Displays the current AI provider icon and model name in the status bar.
|
|
5
|
+
* Uses provider-specific icons for visual identification.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/ModelIndicator
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Box, Text } from "ink";
|
|
11
|
+
import { useMemo } from "react";
|
|
12
|
+
import { useTheme } from "../../theme/index.js";
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Types
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Props for the ModelIndicator component.
|
|
20
|
+
*/
|
|
21
|
+
export interface ModelIndicatorProps {
|
|
22
|
+
/** AI provider name (e.g., 'anthropic', 'openai', 'google') */
|
|
23
|
+
readonly provider?: string;
|
|
24
|
+
/** Model name (e.g., 'claude-3-opus', 'gpt-4') */
|
|
25
|
+
readonly model: string;
|
|
26
|
+
/** Compact mode: show only model name without provider (default: false) */
|
|
27
|
+
readonly compact?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// Constants
|
|
32
|
+
// =============================================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Provider icons mapping.
|
|
36
|
+
* Uses Unicode symbols for terminal compatibility.
|
|
37
|
+
*/
|
|
38
|
+
const PROVIDER_ICONS: Record<string, string> = {
|
|
39
|
+
anthropic: "◈", // Diamond with dot
|
|
40
|
+
openai: "◉", // Circle with fill
|
|
41
|
+
google: "◎", // Circle with ring
|
|
42
|
+
azure: "◇", // Diamond outline
|
|
43
|
+
bedrock: "▣", // Square with fill
|
|
44
|
+
mistral: "◆", // Filled diamond
|
|
45
|
+
ollama: "○", // Circle outline
|
|
46
|
+
default: "●", // Filled circle
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Provider display names mapping.
|
|
51
|
+
*/
|
|
52
|
+
const PROVIDER_NAMES: Record<string, string> = {
|
|
53
|
+
anthropic: "Anthropic",
|
|
54
|
+
openai: "OpenAI",
|
|
55
|
+
google: "Google",
|
|
56
|
+
azure: "Azure",
|
|
57
|
+
bedrock: "Bedrock",
|
|
58
|
+
mistral: "Mistral",
|
|
59
|
+
ollama: "Ollama",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// Helper Functions
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gets the icon for a provider.
|
|
68
|
+
* Falls back to default icon for unknown providers.
|
|
69
|
+
*/
|
|
70
|
+
function getProviderIcon(provider: string): string {
|
|
71
|
+
const normalizedProvider = provider.toLowerCase();
|
|
72
|
+
return PROVIDER_ICONS[normalizedProvider] ?? "●";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Gets the display name for a provider.
|
|
77
|
+
* Falls back to capitalized provider name for unknown providers.
|
|
78
|
+
*/
|
|
79
|
+
function getProviderName(provider: string): string {
|
|
80
|
+
const normalizedProvider = provider.toLowerCase();
|
|
81
|
+
return PROVIDER_NAMES[normalizedProvider] ?? provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Truncates model name if too long.
|
|
86
|
+
* Preserves the version suffix if present.
|
|
87
|
+
*/
|
|
88
|
+
function formatModelName(model: string, maxLength = 25): string {
|
|
89
|
+
if (model.length <= maxLength) {
|
|
90
|
+
return model;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Try to preserve version suffix
|
|
94
|
+
const parts = model.split("-");
|
|
95
|
+
if (parts.length > 1) {
|
|
96
|
+
const suffix = parts[parts.length - 1] ?? "";
|
|
97
|
+
const truncated = model.slice(0, maxLength - suffix.length - 4);
|
|
98
|
+
return `${truncated}...${suffix}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return `${model.slice(0, maxLength - 3)}...`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// =============================================================================
|
|
105
|
+
// Main Component
|
|
106
|
+
// =============================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* ModelIndicator displays the current AI provider and model.
|
|
110
|
+
*
|
|
111
|
+
* Features:
|
|
112
|
+
* - Provider-specific icon
|
|
113
|
+
* - Provider name (optional)
|
|
114
|
+
* - Model name (truncated if too long)
|
|
115
|
+
* - Compact mode for unified footer layout
|
|
116
|
+
* - Themed styling
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* // Full display with provider
|
|
121
|
+
* <ModelIndicator provider="anthropic" model="claude-3-opus" />
|
|
122
|
+
*
|
|
123
|
+
* // Compact mode (model only)
|
|
124
|
+
* <ModelIndicator model="claude-sonnet-4" compact />
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export function ModelIndicator({
|
|
128
|
+
provider,
|
|
129
|
+
model,
|
|
130
|
+
compact = false,
|
|
131
|
+
}: ModelIndicatorProps): React.JSX.Element {
|
|
132
|
+
const { theme } = useTheme();
|
|
133
|
+
|
|
134
|
+
const icon = useMemo(() => (provider ? getProviderIcon(provider) : "●"), [provider]);
|
|
135
|
+
const providerName = useMemo(() => (provider ? getProviderName(provider) : ""), [provider]);
|
|
136
|
+
const displayModel = useMemo(() => formatModelName(model, compact ? 20 : 25), [model, compact]);
|
|
137
|
+
|
|
138
|
+
// Compact mode: model name only
|
|
139
|
+
if (compact) {
|
|
140
|
+
return (
|
|
141
|
+
<Box>
|
|
142
|
+
<Text color={theme.semantic.text.primary}>{displayModel}</Text>
|
|
143
|
+
</Box>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Full mode: icon + provider + model
|
|
148
|
+
return (
|
|
149
|
+
<Box>
|
|
150
|
+
<Text color={theme.colors.primary}>{icon}</Text>
|
|
151
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
152
|
+
<Text color={theme.semantic.text.secondary}>{providerName}</Text>
|
|
153
|
+
<Text color={theme.semantic.text.muted}>/</Text>
|
|
154
|
+
<Text color={theme.semantic.text.primary}>{displayModel}</Text>
|
|
155
|
+
</Box>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PersistenceStatusIndicator Component
|
|
3
|
+
*
|
|
4
|
+
* Status indicator for session persistence state.
|
|
5
|
+
* Displays save status, unsaved message count, and timing info.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/PersistenceStatusIndicator
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { getIcons } from "@vellum/shared";
|
|
11
|
+
import { Box, Text } from "ink";
|
|
12
|
+
import type React from "react";
|
|
13
|
+
import { useMemo } from "react";
|
|
14
|
+
import type { PersistenceStatus } from "../../hooks/usePersistence.js";
|
|
15
|
+
import { useTUITranslation } from "../../i18n/index.js";
|
|
16
|
+
import { useTheme } from "../../theme/index.js";
|
|
17
|
+
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Types
|
|
20
|
+
// =============================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Props for the PersistenceStatusIndicator component
|
|
24
|
+
*/
|
|
25
|
+
export interface PersistenceStatusIndicatorProps {
|
|
26
|
+
/** Current persistence status */
|
|
27
|
+
readonly status: PersistenceStatus;
|
|
28
|
+
/** Number of unsaved messages */
|
|
29
|
+
readonly unsavedCount?: number;
|
|
30
|
+
/** Timestamp of last successful save */
|
|
31
|
+
readonly lastSavedAt?: Date | null;
|
|
32
|
+
/** Whether to use compact display mode */
|
|
33
|
+
readonly compact?: boolean;
|
|
34
|
+
/** Whether the indicator is visible */
|
|
35
|
+
readonly visible?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// Constants
|
|
40
|
+
// =============================================================================
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get icon for a persistence status using the theme icon system.
|
|
44
|
+
*/
|
|
45
|
+
function getStatusIcon(status: PersistenceStatus): string {
|
|
46
|
+
const icons = getIcons();
|
|
47
|
+
switch (status) {
|
|
48
|
+
case "idle":
|
|
49
|
+
return icons.check; // All good, nothing to save
|
|
50
|
+
case "saving":
|
|
51
|
+
return icons.running; // In progress
|
|
52
|
+
case "saved":
|
|
53
|
+
return icons.success; // Just saved successfully
|
|
54
|
+
case "error":
|
|
55
|
+
return icons.error; // Save failed
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Icon suffix for unsaved state
|
|
61
|
+
*/
|
|
62
|
+
const UNSAVED_SUFFIX = "•";
|
|
63
|
+
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// Helper Functions
|
|
66
|
+
// =============================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Format relative time from a date.
|
|
70
|
+
*
|
|
71
|
+
* @param date - Date to format
|
|
72
|
+
* @returns Human-readable relative time string
|
|
73
|
+
*/
|
|
74
|
+
function formatRelativeTime(date: Date): string {
|
|
75
|
+
const now = new Date();
|
|
76
|
+
const diffMs = now.getTime() - date.getTime();
|
|
77
|
+
const diffSecs = Math.floor(diffMs / 1000);
|
|
78
|
+
const diffMins = Math.floor(diffSecs / 60);
|
|
79
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
80
|
+
|
|
81
|
+
if (diffSecs < 10) {
|
|
82
|
+
return "just now";
|
|
83
|
+
}
|
|
84
|
+
if (diffSecs < 60) {
|
|
85
|
+
return `${diffSecs}s ago`;
|
|
86
|
+
}
|
|
87
|
+
if (diffMins < 60) {
|
|
88
|
+
return `${diffMins}min ago`;
|
|
89
|
+
}
|
|
90
|
+
if (diffHours < 24) {
|
|
91
|
+
return `${diffHours}h ago`;
|
|
92
|
+
}
|
|
93
|
+
return date.toLocaleDateString();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// =============================================================================
|
|
97
|
+
// Main Component
|
|
98
|
+
// =============================================================================
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* PersistenceStatusIndicator displays the current session save state.
|
|
102
|
+
*
|
|
103
|
+
* Status Icons (using theme icons):
|
|
104
|
+
* - ✔/✦ (green) - Saved, no unsaved changes
|
|
105
|
+
* - ✔• (yellow) - Unsaved changes present
|
|
106
|
+
* - ⟳ (blue) - Save in progress
|
|
107
|
+
* - ✘ (red) - Save failed
|
|
108
|
+
*
|
|
109
|
+
* Display Modes:
|
|
110
|
+
* - Normal: "✔ saved 2min ago" or "✔• unsaved: 3"
|
|
111
|
+
* - Compact: "✔" or "✔•3"
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```tsx
|
|
115
|
+
* <PersistenceStatusIndicator
|
|
116
|
+
* status="idle"
|
|
117
|
+
* unsavedCount={3}
|
|
118
|
+
* lastSavedAt={new Date()}
|
|
119
|
+
* />
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export function PersistenceStatusIndicator({
|
|
123
|
+
status,
|
|
124
|
+
unsavedCount = 0,
|
|
125
|
+
lastSavedAt = null,
|
|
126
|
+
compact = false,
|
|
127
|
+
visible = true,
|
|
128
|
+
}: PersistenceStatusIndicatorProps): React.JSX.Element | null {
|
|
129
|
+
const { theme } = useTheme();
|
|
130
|
+
const { t } = useTUITranslation();
|
|
131
|
+
|
|
132
|
+
// Determine effective status based on unsaved count
|
|
133
|
+
const effectiveStatus = useMemo((): PersistenceStatus => {
|
|
134
|
+
if (status === "saving" || status === "error") {
|
|
135
|
+
return status;
|
|
136
|
+
}
|
|
137
|
+
if (unsavedCount > 0) {
|
|
138
|
+
return "idle";
|
|
139
|
+
}
|
|
140
|
+
return "saved";
|
|
141
|
+
}, [status, unsavedCount]);
|
|
142
|
+
|
|
143
|
+
// Get icon based on status
|
|
144
|
+
const icon = useMemo((): string => {
|
|
145
|
+
const baseIcon = getStatusIcon(effectiveStatus);
|
|
146
|
+
if (effectiveStatus === "idle" && unsavedCount > 0) {
|
|
147
|
+
return `${getStatusIcon("idle")}${UNSAVED_SUFFIX}`;
|
|
148
|
+
}
|
|
149
|
+
return baseIcon;
|
|
150
|
+
}, [effectiveStatus, unsavedCount]);
|
|
151
|
+
|
|
152
|
+
// Determine color based on status
|
|
153
|
+
const color = useMemo((): string => {
|
|
154
|
+
switch (effectiveStatus) {
|
|
155
|
+
case "saved":
|
|
156
|
+
return theme.colors.success;
|
|
157
|
+
case "saving":
|
|
158
|
+
return theme.colors.info;
|
|
159
|
+
case "error":
|
|
160
|
+
return theme.colors.error;
|
|
161
|
+
case "idle":
|
|
162
|
+
return unsavedCount > 0 ? theme.colors.warning : theme.semantic.text.muted;
|
|
163
|
+
}
|
|
164
|
+
}, [effectiveStatus, unsavedCount, theme]);
|
|
165
|
+
|
|
166
|
+
// Build display text
|
|
167
|
+
const displayText = useMemo((): string => {
|
|
168
|
+
if (compact) {
|
|
169
|
+
// Compact mode: just icon and count if unsaved
|
|
170
|
+
if (unsavedCount > 0 && effectiveStatus !== "saving") {
|
|
171
|
+
return `${icon}${unsavedCount}`;
|
|
172
|
+
}
|
|
173
|
+
return icon;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Full mode
|
|
177
|
+
switch (effectiveStatus) {
|
|
178
|
+
case "saving":
|
|
179
|
+
return `${icon} ${t("persistence.saving")}`;
|
|
180
|
+
case "saved":
|
|
181
|
+
if (lastSavedAt) {
|
|
182
|
+
return `${icon} ${t("persistence.saved")} ${formatRelativeTime(lastSavedAt)}`;
|
|
183
|
+
}
|
|
184
|
+
return `${icon} ${t("persistence.saved")}`;
|
|
185
|
+
case "error":
|
|
186
|
+
return `${icon} ${t("persistence.saveError")}`;
|
|
187
|
+
case "idle":
|
|
188
|
+
if (unsavedCount > 0) {
|
|
189
|
+
return `${icon} ${t("persistence.unsaved")}: ${unsavedCount}`;
|
|
190
|
+
}
|
|
191
|
+
return `${icon} ${t("persistence.saved")}`;
|
|
192
|
+
}
|
|
193
|
+
}, [compact, effectiveStatus, unsavedCount, lastSavedAt, icon, t]);
|
|
194
|
+
|
|
195
|
+
if (!visible) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return (
|
|
200
|
+
<Box>
|
|
201
|
+
<Text color={color}>{displayText}</Text>
|
|
202
|
+
</Box>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// =============================================================================
|
|
207
|
+
// Exports
|
|
208
|
+
// =============================================================================
|
|
209
|
+
|
|
210
|
+
export default PersistenceStatusIndicator;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resilience Indicator Component
|
|
3
|
+
*
|
|
4
|
+
* Displays rate limiting and retry status in the TUI.
|
|
5
|
+
*
|
|
6
|
+
* @module tui/components/StatusBar/ResilienceIndicator
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Box, Text } from "ink";
|
|
10
|
+
import type React from "react";
|
|
11
|
+
|
|
12
|
+
import { type ResilienceStatus, useResilienceOptional } from "../../context/ResilienceContext.js";
|
|
13
|
+
import { useTheme } from "../../theme/index.js";
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Props for ResilienceIndicator
|
|
21
|
+
*/
|
|
22
|
+
export interface ResilienceIndicatorProps {
|
|
23
|
+
/** Override status (for testing/storybook) */
|
|
24
|
+
readonly status?: ResilienceStatus;
|
|
25
|
+
/** Show compact version */
|
|
26
|
+
readonly compact?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Component
|
|
31
|
+
// =============================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Resilience indicator showing rate limit and retry status.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* // In StatusBar
|
|
39
|
+
* <ResilienceIndicator />
|
|
40
|
+
*
|
|
41
|
+
* // Compact version
|
|
42
|
+
* <ResilienceIndicator compact />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function ResilienceIndicator({
|
|
46
|
+
status: overrideStatus,
|
|
47
|
+
compact = false,
|
|
48
|
+
}: ResilienceIndicatorProps): React.JSX.Element | null {
|
|
49
|
+
const { theme } = useTheme();
|
|
50
|
+
const context = useResilienceOptional();
|
|
51
|
+
|
|
52
|
+
// Use override status or context status
|
|
53
|
+
const status = overrideStatus ?? context?.status;
|
|
54
|
+
|
|
55
|
+
// Don't render if no status or idle
|
|
56
|
+
if (!status || status.type === "idle") {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Select icon and color based on status type
|
|
61
|
+
const icon = status.type === "rate-limit" ? "⏳" : "🔄";
|
|
62
|
+
const color = status.type === "rate-limit" ? theme.colors.warning : theme.colors.info;
|
|
63
|
+
|
|
64
|
+
if (compact) {
|
|
65
|
+
// Compact: just icon and wait time
|
|
66
|
+
const waitText = status.waitSeconds ? `${status.waitSeconds}s` : "";
|
|
67
|
+
return (
|
|
68
|
+
<Box>
|
|
69
|
+
<Text color={color}>
|
|
70
|
+
{icon} {waitText}
|
|
71
|
+
</Text>
|
|
72
|
+
</Box>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Full: icon and message
|
|
77
|
+
return (
|
|
78
|
+
<Box>
|
|
79
|
+
<Text color={color}>
|
|
80
|
+
{icon} {status.message}
|
|
81
|
+
</Text>
|
|
82
|
+
</Box>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Resilience status bar segment for integration into StatusBar.
|
|
88
|
+
*
|
|
89
|
+
* Returns null if no active resilience event, making it safe to
|
|
90
|
+
* include in layouts unconditionally.
|
|
91
|
+
*/
|
|
92
|
+
export function ResilienceStatusSegment(): React.JSX.Element | null {
|
|
93
|
+
const context = useResilienceOptional();
|
|
94
|
+
|
|
95
|
+
// Don't render anything if context not available or feedback disabled
|
|
96
|
+
if (!context || !context.feedbackEnabled) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Don't render if idle
|
|
101
|
+
if (context.status.type === "idle") {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return <ResilienceIndicator />;
|
|
106
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SandboxIndicator Component
|
|
3
|
+
*
|
|
4
|
+
* Displays the current sandbox policy with an icon and label.
|
|
5
|
+
* Sandbox policies control file system access boundaries.
|
|
6
|
+
*
|
|
7
|
+
* Trust Mode (approval) and Sandbox (file boundaries) are SEPARATE concepts:
|
|
8
|
+
* - Trust Mode: When to ask user (ask/auto/full-auto)
|
|
9
|
+
* - Sandbox: Where agent can access (workspace/cwd/system)
|
|
10
|
+
*
|
|
11
|
+
* @module tui/components/StatusBar/SandboxIndicator
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { SandboxPolicy } from "@vellum/core";
|
|
15
|
+
import { Box, Text } from "ink";
|
|
16
|
+
import { useMemo } from "react";
|
|
17
|
+
import { useTheme } from "../../theme/index.js";
|
|
18
|
+
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Types
|
|
21
|
+
// =============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Props for the SandboxIndicator component.
|
|
25
|
+
*/
|
|
26
|
+
export interface SandboxIndicatorProps {
|
|
27
|
+
/** Current sandbox policy */
|
|
28
|
+
readonly policy: SandboxPolicy;
|
|
29
|
+
/** Whether to show compact label (default: true) */
|
|
30
|
+
readonly compact?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Constants
|
|
35
|
+
// =============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Sandbox policy display configuration.
|
|
39
|
+
*
|
|
40
|
+
* Maps technical policy names to user-friendly display:
|
|
41
|
+
* - workspace-read: Read-only within workspace
|
|
42
|
+
* - workspace-write: Read/write within workspace
|
|
43
|
+
* - cwd-read: Read-only in current directory
|
|
44
|
+
* - cwd-write: Read/write in current directory
|
|
45
|
+
* - full-access: Full system-wide access (dangerous)
|
|
46
|
+
*/
|
|
47
|
+
interface SandboxDisplayConfig {
|
|
48
|
+
readonly icon: string;
|
|
49
|
+
readonly label: string;
|
|
50
|
+
readonly compactLabel: string;
|
|
51
|
+
readonly description: string;
|
|
52
|
+
readonly severity: "safe" | "caution" | "danger";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const SANDBOX_DISPLAY: Record<SandboxPolicy, SandboxDisplayConfig> = {
|
|
56
|
+
"workspace-read": {
|
|
57
|
+
icon: "[r]",
|
|
58
|
+
label: "workspace (read)",
|
|
59
|
+
compactLabel: "ws",
|
|
60
|
+
description: "Read-only access within workspace",
|
|
61
|
+
severity: "safe",
|
|
62
|
+
},
|
|
63
|
+
"workspace-write": {
|
|
64
|
+
icon: "[w]",
|
|
65
|
+
label: "workspace",
|
|
66
|
+
compactLabel: "ws",
|
|
67
|
+
description: "Read/write access within workspace",
|
|
68
|
+
severity: "caution",
|
|
69
|
+
},
|
|
70
|
+
"cwd-read": {
|
|
71
|
+
icon: "[r]",
|
|
72
|
+
label: "cwd (read)",
|
|
73
|
+
compactLabel: "cwd",
|
|
74
|
+
description: "Read-only access in current directory",
|
|
75
|
+
severity: "safe",
|
|
76
|
+
},
|
|
77
|
+
"cwd-write": {
|
|
78
|
+
icon: "[w]",
|
|
79
|
+
label: "cwd",
|
|
80
|
+
compactLabel: "cwd",
|
|
81
|
+
description: "Read/write access in current directory",
|
|
82
|
+
severity: "caution",
|
|
83
|
+
},
|
|
84
|
+
"full-access": {
|
|
85
|
+
icon: "[*]",
|
|
86
|
+
label: "system",
|
|
87
|
+
compactLabel: "sys",
|
|
88
|
+
description: "Full system-wide access",
|
|
89
|
+
severity: "danger",
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// =============================================================================
|
|
94
|
+
// Helper Functions
|
|
95
|
+
// =============================================================================
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Gets the semantic color for a sandbox policy severity.
|
|
99
|
+
* - safe: success (green) - limited access
|
|
100
|
+
* - caution: warning (yellow) - workspace/cwd write access
|
|
101
|
+
* - danger: error (red) - full system access
|
|
102
|
+
*/
|
|
103
|
+
function getSandboxColor(
|
|
104
|
+
severity: SandboxDisplayConfig["severity"],
|
|
105
|
+
theme: ReturnType<typeof useTheme>["theme"]
|
|
106
|
+
): string {
|
|
107
|
+
switch (severity) {
|
|
108
|
+
case "safe":
|
|
109
|
+
return theme.colors.success;
|
|
110
|
+
case "caution":
|
|
111
|
+
return theme.colors.warning;
|
|
112
|
+
case "danger":
|
|
113
|
+
return theme.colors.error;
|
|
114
|
+
default:
|
|
115
|
+
return theme.semantic.text.secondary;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// Main Component
|
|
121
|
+
// =============================================================================
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* SandboxIndicator displays the current sandbox policy with visual cues.
|
|
125
|
+
*
|
|
126
|
+
* Features:
|
|
127
|
+
* - Policy-specific icon
|
|
128
|
+
* - Color-coded by access level severity
|
|
129
|
+
* - Compact or full label display
|
|
130
|
+
*
|
|
131
|
+
* Sandbox Policies:
|
|
132
|
+
* - workspace-read: [r] Read-only within workspace (safe)
|
|
133
|
+
* - workspace-write: [w] Read/write within workspace (caution)
|
|
134
|
+
* - cwd-read: [r] Read-only in current directory (safe)
|
|
135
|
+
* - cwd-write: [w] Read/write in current directory (caution)
|
|
136
|
+
* - full-access: [*] Full system access (danger)
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```tsx
|
|
140
|
+
* // Compact mode (default)
|
|
141
|
+
* <SandboxIndicator policy="workspace-write" />
|
|
142
|
+
* // Output: [w] ws
|
|
143
|
+
*
|
|
144
|
+
* // Full mode
|
|
145
|
+
* <SandboxIndicator policy="workspace-write" compact={false} />
|
|
146
|
+
* // Output: [w] workspace
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function SandboxIndicator({
|
|
150
|
+
policy,
|
|
151
|
+
compact = true,
|
|
152
|
+
}: SandboxIndicatorProps): React.JSX.Element {
|
|
153
|
+
const { theme } = useTheme();
|
|
154
|
+
|
|
155
|
+
const config = useMemo(() => SANDBOX_DISPLAY[policy], [policy]);
|
|
156
|
+
const color = useMemo(() => getSandboxColor(config.severity, theme), [config.severity, theme]);
|
|
157
|
+
|
|
158
|
+
const displayLabel = compact ? config.compactLabel : config.label;
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<Box flexDirection="row">
|
|
162
|
+
<Text color={color}>
|
|
163
|
+
{config.icon} {displayLabel}
|
|
164
|
+
</Text>
|
|
165
|
+
</Box>
|
|
166
|
+
);
|
|
167
|
+
}
|