@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,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenBreakdown Component (Token Counting Fix)
|
|
3
|
+
*
|
|
4
|
+
* Displays granular token breakdown with cumulative vs per-turn stats.
|
|
5
|
+
* Shows: input | output | cache | thinking tokens with turn/total distinction.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/TokenBreakdown
|
|
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
|
+
* Detailed token usage statistics
|
|
20
|
+
*/
|
|
21
|
+
export interface TokenStats {
|
|
22
|
+
/** Number of input tokens */
|
|
23
|
+
readonly inputTokens: number;
|
|
24
|
+
/** Number of output tokens */
|
|
25
|
+
readonly outputTokens: number;
|
|
26
|
+
/** Number of tokens used for thinking/reasoning (if applicable) */
|
|
27
|
+
readonly thinkingTokens?: number;
|
|
28
|
+
/** Number of tokens read from cache (if applicable) */
|
|
29
|
+
readonly cacheReadTokens?: number;
|
|
30
|
+
/** Number of tokens written to cache (if applicable) */
|
|
31
|
+
readonly cacheWriteTokens?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Props for the TokenBreakdown component.
|
|
36
|
+
*/
|
|
37
|
+
export interface TokenBreakdownProps {
|
|
38
|
+
/** Current turn token usage */
|
|
39
|
+
readonly turn?: TokenStats;
|
|
40
|
+
/** Cumulative session token usage */
|
|
41
|
+
readonly total: TokenStats;
|
|
42
|
+
/** Whether to show compact format (default: false) */
|
|
43
|
+
readonly compact?: boolean;
|
|
44
|
+
/** Whether to show turn stats (default: true if turn provided) */
|
|
45
|
+
readonly showTurn?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// =============================================================================
|
|
49
|
+
// Helper Functions
|
|
50
|
+
// =============================================================================
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Formats a number with K/M suffix for compact display.
|
|
54
|
+
*/
|
|
55
|
+
function formatTokenCount(count: number): string {
|
|
56
|
+
if (count < 1000) {
|
|
57
|
+
return count.toString();
|
|
58
|
+
}
|
|
59
|
+
if (count < 1000000) {
|
|
60
|
+
const k = count / 1000;
|
|
61
|
+
return k >= 10 ? `${Math.round(k)}K` : `${k.toFixed(1)}K`;
|
|
62
|
+
}
|
|
63
|
+
const m = count / 1000000;
|
|
64
|
+
return m >= 10 ? `${Math.round(m)}M` : `${m.toFixed(1)}M`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Formats a signed number (with + prefix for positive) for turn display.
|
|
69
|
+
*/
|
|
70
|
+
function formatTurnCount(count: number): string {
|
|
71
|
+
const formatted = formatTokenCount(count);
|
|
72
|
+
return count > 0 ? `+${formatted}` : formatted;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// =============================================================================
|
|
76
|
+
// Main Component
|
|
77
|
+
// =============================================================================
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* TokenBreakdown displays granular token usage with turn vs cumulative distinction.
|
|
81
|
+
*
|
|
82
|
+
* Compact format: `in: X | out: Y | cache: Z | think: W`
|
|
83
|
+
* Full format with turn: `Turn: +X in +Y out | Total: A in B out`
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* // Compact cumulative only
|
|
88
|
+
* <TokenBreakdown
|
|
89
|
+
* total={{ inputTokens: 5000, outputTokens: 2000, cacheReadTokens: 500 }}
|
|
90
|
+
* compact
|
|
91
|
+
* />
|
|
92
|
+
* // Output: in: 5K | out: 2K | cache: 500
|
|
93
|
+
*
|
|
94
|
+
* // With turn breakdown
|
|
95
|
+
* <TokenBreakdown
|
|
96
|
+
* turn={{ inputTokens: 500, outputTokens: 200 }}
|
|
97
|
+
* total={{ inputTokens: 5000, outputTokens: 2000 }}
|
|
98
|
+
* />
|
|
99
|
+
* // Output: Turn: +500 in +200 out | Total: 5K in 2K out
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function TokenBreakdown({
|
|
103
|
+
turn,
|
|
104
|
+
total,
|
|
105
|
+
compact = false,
|
|
106
|
+
showTurn = true,
|
|
107
|
+
}: TokenBreakdownProps): React.JSX.Element {
|
|
108
|
+
const { theme } = useTheme();
|
|
109
|
+
|
|
110
|
+
// Memoized formatted values for total
|
|
111
|
+
const formattedTotal = useMemo(
|
|
112
|
+
() => ({
|
|
113
|
+
input: formatTokenCount(total.inputTokens),
|
|
114
|
+
output: formatTokenCount(total.outputTokens),
|
|
115
|
+
thinking: total.thinkingTokens ? formatTokenCount(total.thinkingTokens) : null,
|
|
116
|
+
cache:
|
|
117
|
+
total.cacheReadTokens || total.cacheWriteTokens
|
|
118
|
+
? formatTokenCount((total.cacheReadTokens ?? 0) + (total.cacheWriteTokens ?? 0))
|
|
119
|
+
: null,
|
|
120
|
+
}),
|
|
121
|
+
[total]
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Memoized formatted values for turn (if provided)
|
|
125
|
+
const formattedTurn = useMemo(() => {
|
|
126
|
+
if (!turn) return null;
|
|
127
|
+
return {
|
|
128
|
+
input: formatTurnCount(turn.inputTokens),
|
|
129
|
+
output: formatTurnCount(turn.outputTokens),
|
|
130
|
+
thinking: turn.thinkingTokens ? formatTurnCount(turn.thinkingTokens) : null,
|
|
131
|
+
cache:
|
|
132
|
+
turn.cacheReadTokens || turn.cacheWriteTokens
|
|
133
|
+
? formatTurnCount((turn.cacheReadTokens ?? 0) + (turn.cacheWriteTokens ?? 0))
|
|
134
|
+
: null,
|
|
135
|
+
};
|
|
136
|
+
}, [turn]);
|
|
137
|
+
|
|
138
|
+
const hasTurn = showTurn && turn && formattedTurn;
|
|
139
|
+
|
|
140
|
+
// Compact format: `in: X | out: Y | cache: Z | think: W`
|
|
141
|
+
if (compact) {
|
|
142
|
+
const parts: React.ReactNode[] = [];
|
|
143
|
+
|
|
144
|
+
parts.push(
|
|
145
|
+
<Text key="in" color={theme.semantic.text.secondary}>
|
|
146
|
+
in: <Text color={theme.colors.info}>{formattedTotal.input}</Text>
|
|
147
|
+
</Text>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
parts.push(
|
|
151
|
+
<Text key="out" color={theme.semantic.text.secondary}>
|
|
152
|
+
out: <Text color={theme.colors.success}>{formattedTotal.output}</Text>
|
|
153
|
+
</Text>
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
if (formattedTotal.cache) {
|
|
157
|
+
parts.push(
|
|
158
|
+
<Text key="cache" color={theme.semantic.text.secondary}>
|
|
159
|
+
cache: <Text color={theme.semantic.text.muted}>{formattedTotal.cache}</Text>
|
|
160
|
+
</Text>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (formattedTotal.thinking) {
|
|
165
|
+
parts.push(
|
|
166
|
+
<Text key="think" color={theme.semantic.text.secondary}>
|
|
167
|
+
think: <Text color={theme.colors.warning}>{formattedTotal.thinking}</Text>
|
|
168
|
+
</Text>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<Box>
|
|
174
|
+
{parts.map((part, index) => (
|
|
175
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: Parts array is built locally with stable order, not reordered or filtered
|
|
176
|
+
<Text key={`wrapper-${index}`}>
|
|
177
|
+
{index > 0 && <Text color={theme.semantic.border.muted}> │ </Text>}
|
|
178
|
+
{part}
|
|
179
|
+
</Text>
|
|
180
|
+
))}
|
|
181
|
+
</Box>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Full format with turn distinction
|
|
186
|
+
if (hasTurn) {
|
|
187
|
+
return (
|
|
188
|
+
<Box>
|
|
189
|
+
{/* Turn stats */}
|
|
190
|
+
<Text color={theme.semantic.text.muted}>Turn: </Text>
|
|
191
|
+
<Text color={theme.colors.info}>{formattedTurn.input}</Text>
|
|
192
|
+
<Text color={theme.semantic.text.muted}> in </Text>
|
|
193
|
+
<Text color={theme.colors.success}>{formattedTurn.output}</Text>
|
|
194
|
+
<Text color={theme.semantic.text.muted}> out</Text>
|
|
195
|
+
{formattedTurn.thinking && (
|
|
196
|
+
<>
|
|
197
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
198
|
+
<Text color={theme.colors.warning}>{formattedTurn.thinking}</Text>
|
|
199
|
+
<Text color={theme.semantic.text.muted}> think</Text>
|
|
200
|
+
</>
|
|
201
|
+
)}
|
|
202
|
+
|
|
203
|
+
{/* Separator */}
|
|
204
|
+
<Text color={theme.semantic.border.muted}> │ </Text>
|
|
205
|
+
|
|
206
|
+
{/* Total stats */}
|
|
207
|
+
<Text color={theme.semantic.text.muted}>Total: </Text>
|
|
208
|
+
<Text color={theme.semantic.text.secondary}>{formattedTotal.input}</Text>
|
|
209
|
+
<Text color={theme.semantic.text.muted}> in </Text>
|
|
210
|
+
<Text color={theme.semantic.text.secondary}>{formattedTotal.output}</Text>
|
|
211
|
+
<Text color={theme.semantic.text.muted}> out</Text>
|
|
212
|
+
{formattedTotal.thinking && (
|
|
213
|
+
<>
|
|
214
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
215
|
+
<Text color={theme.semantic.text.secondary}>{formattedTotal.thinking}</Text>
|
|
216
|
+
<Text color={theme.semantic.text.muted}> think</Text>
|
|
217
|
+
</>
|
|
218
|
+
)}
|
|
219
|
+
</Box>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Full format without turn (total only)
|
|
224
|
+
return (
|
|
225
|
+
<Box>
|
|
226
|
+
<Text color={theme.semantic.text.secondary}>{formattedTotal.input}</Text>
|
|
227
|
+
<Text color={theme.semantic.text.muted}> in </Text>
|
|
228
|
+
<Text color={theme.semantic.text.secondary}>{formattedTotal.output}</Text>
|
|
229
|
+
<Text color={theme.semantic.text.muted}> out</Text>
|
|
230
|
+
{formattedTotal.cache && (
|
|
231
|
+
<>
|
|
232
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
233
|
+
<Text color={theme.semantic.text.muted}>{formattedTotal.cache}</Text>
|
|
234
|
+
<Text color={theme.semantic.text.muted}> cache</Text>
|
|
235
|
+
</>
|
|
236
|
+
)}
|
|
237
|
+
{formattedTotal.thinking && (
|
|
238
|
+
<>
|
|
239
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
240
|
+
<Text color={theme.colors.warning}>{formattedTotal.thinking}</Text>
|
|
241
|
+
<Text color={theme.semantic.text.muted}> think</Text>
|
|
242
|
+
</>
|
|
243
|
+
)}
|
|
244
|
+
</Box>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenCounter Component (T036)
|
|
3
|
+
*
|
|
4
|
+
* Displays token usage as a percentage with color-coded warnings.
|
|
5
|
+
* Changes color based on usage thresholds: warning at 80%, error at 95%.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/TokenCounter
|
|
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 TokenCounter component.
|
|
20
|
+
*/
|
|
21
|
+
export interface TokenCounterProps {
|
|
22
|
+
/** Current token count */
|
|
23
|
+
readonly current: number;
|
|
24
|
+
/** Maximum token limit */
|
|
25
|
+
readonly max: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Constants
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
/** Warning threshold percentage (80%) */
|
|
33
|
+
const WARNING_THRESHOLD = 80;
|
|
34
|
+
|
|
35
|
+
/** Error threshold percentage (95%) */
|
|
36
|
+
const ERROR_THRESHOLD = 95;
|
|
37
|
+
|
|
38
|
+
/** Token counter icon */
|
|
39
|
+
const TOKEN_ICON = "◊";
|
|
40
|
+
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// Helper Functions
|
|
43
|
+
// =============================================================================
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Formats a number with K/M suffix for compact display.
|
|
47
|
+
*/
|
|
48
|
+
function formatTokenCount(count: number): string {
|
|
49
|
+
if (count < 1000) {
|
|
50
|
+
return count.toString();
|
|
51
|
+
}
|
|
52
|
+
if (count < 1000000) {
|
|
53
|
+
const k = count / 1000;
|
|
54
|
+
return k >= 10 ? `${Math.round(k)}K` : `${k.toFixed(1)}K`;
|
|
55
|
+
}
|
|
56
|
+
const m = count / 1000000;
|
|
57
|
+
return m >= 10 ? `${Math.round(m)}M` : `${m.toFixed(1)}M`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Calculates the percentage of tokens used.
|
|
62
|
+
*/
|
|
63
|
+
function calculatePercentage(current: number, max: number): number {
|
|
64
|
+
if (max <= 0) return 0;
|
|
65
|
+
return Math.min(Math.round((current / max) * 100), 100);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// Main Component
|
|
70
|
+
// =============================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* TokenCounter displays token usage with color-coded warnings.
|
|
74
|
+
*
|
|
75
|
+
* Features:
|
|
76
|
+
* - Current/max token display
|
|
77
|
+
* - Percentage indicator
|
|
78
|
+
* - Color-coded thresholds:
|
|
79
|
+
* - Normal (< 80%): secondary text color
|
|
80
|
+
* - Warning (80-95%): warning color
|
|
81
|
+
* - Error (> 95%): error color
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```tsx
|
|
85
|
+
* // Normal usage
|
|
86
|
+
* <TokenCounter current={5000} max={100000} />
|
|
87
|
+
*
|
|
88
|
+
* // Warning state
|
|
89
|
+
* <TokenCounter current={85000} max={100000} />
|
|
90
|
+
*
|
|
91
|
+
* // Error state
|
|
92
|
+
* <TokenCounter current={98000} max={100000} />
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export function TokenCounter({ current, max }: TokenCounterProps): React.JSX.Element {
|
|
96
|
+
const { theme } = useTheme();
|
|
97
|
+
|
|
98
|
+
const percentage = useMemo(() => calculatePercentage(current, max), [current, max]);
|
|
99
|
+
|
|
100
|
+
const formattedCurrent = useMemo(() => formatTokenCount(current), [current]);
|
|
101
|
+
const formattedMax = useMemo(() => formatTokenCount(max), [max]);
|
|
102
|
+
|
|
103
|
+
// Determine color based on percentage thresholds
|
|
104
|
+
const color = useMemo(() => {
|
|
105
|
+
if (percentage >= ERROR_THRESHOLD) {
|
|
106
|
+
return theme.colors.error;
|
|
107
|
+
}
|
|
108
|
+
if (percentage >= WARNING_THRESHOLD) {
|
|
109
|
+
return theme.colors.warning;
|
|
110
|
+
}
|
|
111
|
+
return theme.semantic.text.secondary;
|
|
112
|
+
}, [percentage, theme.colors.error, theme.colors.warning, theme.semantic.text.secondary]);
|
|
113
|
+
|
|
114
|
+
const percentageColor = useMemo(() => {
|
|
115
|
+
if (percentage >= ERROR_THRESHOLD) {
|
|
116
|
+
return theme.colors.error;
|
|
117
|
+
}
|
|
118
|
+
if (percentage >= WARNING_THRESHOLD) {
|
|
119
|
+
return theme.colors.warning;
|
|
120
|
+
}
|
|
121
|
+
return theme.semantic.text.muted;
|
|
122
|
+
}, [percentage, theme.colors.error, theme.colors.warning, theme.semantic.text.muted]);
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<Box>
|
|
126
|
+
<Text color={theme.semantic.text.muted}>{TOKEN_ICON} </Text>
|
|
127
|
+
<Text color={color}>{formattedCurrent}</Text>
|
|
128
|
+
<Text color={theme.semantic.text.muted}>/</Text>
|
|
129
|
+
<Text color={theme.semantic.text.secondary}>{formattedMax}</Text>
|
|
130
|
+
<Text color={theme.semantic.text.muted}> (</Text>
|
|
131
|
+
<Text color={percentageColor}>{percentage}%</Text>
|
|
132
|
+
<Text color={theme.semantic.text.muted}>)</Text>
|
|
133
|
+
</Box>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TrustModeIndicator Component (T037)
|
|
3
|
+
*
|
|
4
|
+
* Displays the current trust mode with an icon and color.
|
|
5
|
+
* Trust modes control how much autonomy the AI has for tool execution.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/TrustModeIndicator
|
|
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
|
+
* Trust mode types.
|
|
20
|
+
* - ask: AI asks for approval before each action
|
|
21
|
+
* - auto: AI auto-approves safe actions, asks for dangerous ones
|
|
22
|
+
* - full: AI auto-approves all actions
|
|
23
|
+
*/
|
|
24
|
+
export type TrustMode = "ask" | "auto" | "full";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Props for the TrustModeIndicator component.
|
|
28
|
+
*/
|
|
29
|
+
export interface TrustModeIndicatorProps {
|
|
30
|
+
/** Current trust mode */
|
|
31
|
+
readonly mode: TrustMode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Constants
|
|
36
|
+
// =============================================================================
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Trust mode configuration mapping.
|
|
40
|
+
*/
|
|
41
|
+
interface TrustModeConfig {
|
|
42
|
+
readonly icon: string;
|
|
43
|
+
readonly label: string;
|
|
44
|
+
readonly description: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const TRUST_MODE_CONFIG: Record<TrustMode, TrustModeConfig> = {
|
|
48
|
+
ask: {
|
|
49
|
+
icon: "◎",
|
|
50
|
+
label: "Approval: Ask",
|
|
51
|
+
description: "Manual approval required",
|
|
52
|
+
},
|
|
53
|
+
auto: {
|
|
54
|
+
icon: "◉",
|
|
55
|
+
label: "Approval: Auto",
|
|
56
|
+
description: "Auto-approve safe actions",
|
|
57
|
+
},
|
|
58
|
+
full: {
|
|
59
|
+
icon: "●",
|
|
60
|
+
label: "Approval: Full",
|
|
61
|
+
description: "Auto-approve all actions",
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// =============================================================================
|
|
66
|
+
// Helper Functions
|
|
67
|
+
// =============================================================================
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Gets the color for a trust mode.
|
|
71
|
+
* - ask: warning (requires attention)
|
|
72
|
+
* - auto: info (semi-autonomous)
|
|
73
|
+
* - full: success (fully autonomous) but also indicates risk
|
|
74
|
+
*/
|
|
75
|
+
function getTrustModeColor(mode: TrustMode, theme: ReturnType<typeof useTheme>["theme"]): string {
|
|
76
|
+
switch (mode) {
|
|
77
|
+
case "ask":
|
|
78
|
+
return theme.colors.warning;
|
|
79
|
+
case "auto":
|
|
80
|
+
return theme.colors.info;
|
|
81
|
+
case "full":
|
|
82
|
+
return theme.colors.success;
|
|
83
|
+
default:
|
|
84
|
+
return theme.semantic.text.secondary;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// =============================================================================
|
|
89
|
+
// Main Component
|
|
90
|
+
// =============================================================================
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* TrustModeIndicator displays the current trust mode with visual cues.
|
|
94
|
+
*
|
|
95
|
+
* Features:
|
|
96
|
+
* - Mode-specific icon
|
|
97
|
+
* - Color-coded by trust level
|
|
98
|
+
* - Compact label display
|
|
99
|
+
*
|
|
100
|
+
* Trust Modes:
|
|
101
|
+
* - Ask (◎): Manual approval for all actions
|
|
102
|
+
* - Auto (◉): Auto-approve safe actions, ask for dangerous ones
|
|
103
|
+
* - Full (●): Auto-approve all actions (highest trust)
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```tsx
|
|
107
|
+
* // Ask mode (most restrictive)
|
|
108
|
+
* <TrustModeIndicator mode="ask" />
|
|
109
|
+
*
|
|
110
|
+
* // Auto mode (balanced)
|
|
111
|
+
* <TrustModeIndicator mode="auto" />
|
|
112
|
+
*
|
|
113
|
+
* // Full mode (most permissive)
|
|
114
|
+
* <TrustModeIndicator mode="full" />
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export function TrustModeIndicator({ mode }: TrustModeIndicatorProps): React.JSX.Element {
|
|
118
|
+
const { theme } = useTheme();
|
|
119
|
+
|
|
120
|
+
const config = useMemo(() => TRUST_MODE_CONFIG[mode], [mode]);
|
|
121
|
+
const color = useMemo(() => getTrustModeColor(mode, theme), [mode, theme]);
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<Box>
|
|
125
|
+
<Text color={color}>{config.icon}</Text>
|
|
126
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
127
|
+
<Text color={color}>{config.label}</Text>
|
|
128
|
+
</Box>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkspaceIndicator Component
|
|
3
|
+
*
|
|
4
|
+
* Displays the current workspace directory name with a folder icon.
|
|
5
|
+
* Uses gradient styling for visual emphasis while maintaining readability.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/WorkspaceIndicator
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { getIcons } from "@vellum/shared";
|
|
11
|
+
import { Text } from "ink";
|
|
12
|
+
import type React from "react";
|
|
13
|
+
import { useMemo } from "react";
|
|
14
|
+
import { useWorkspace } from "../../hooks/useWorkspace.js";
|
|
15
|
+
import { useTheme } from "../../theme/index.js";
|
|
16
|
+
import { truncateToDisplayWidth } from "../../utils/index.js";
|
|
17
|
+
import { GradientText } from "../common/GradientText.js";
|
|
18
|
+
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Types
|
|
21
|
+
// =============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Props for the WorkspaceIndicator component.
|
|
25
|
+
*/
|
|
26
|
+
export interface WorkspaceIndicatorProps {
|
|
27
|
+
/** Maximum width for the workspace name (truncates if exceeded) */
|
|
28
|
+
readonly maxWidth?: number;
|
|
29
|
+
/** Whether to use gradient styling (default: true) */
|
|
30
|
+
readonly useGradient?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Component
|
|
35
|
+
// =============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* WorkspaceIndicator displays the current workspace directory.
|
|
39
|
+
*
|
|
40
|
+
* Uses Nerd Font icon or Unicode/ASCII fallback.
|
|
41
|
+
* Applies gradient styling for visual emphasis (configurable).
|
|
42
|
+
* Truncates long names with ellipsis if maxWidth is specified.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* <WorkspaceIndicator maxWidth={20} />
|
|
47
|
+
* // Output: vellum (with gradient)
|
|
48
|
+
*
|
|
49
|
+
* <WorkspaceIndicator useGradient={false} />
|
|
50
|
+
* // Output: vellum (muted)
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function WorkspaceIndicator({
|
|
54
|
+
maxWidth = 20,
|
|
55
|
+
useGradient = true,
|
|
56
|
+
}: WorkspaceIndicatorProps): React.JSX.Element {
|
|
57
|
+
const { theme } = useTheme();
|
|
58
|
+
const { name } = useWorkspace();
|
|
59
|
+
const icons = getIcons();
|
|
60
|
+
|
|
61
|
+
const displayName = useMemo(() => {
|
|
62
|
+
// Truncate with ellipsis using string-width for CJK/Emoji handling
|
|
63
|
+
return truncateToDisplayWidth(name, maxWidth);
|
|
64
|
+
}, [name, maxWidth]);
|
|
65
|
+
|
|
66
|
+
// Workspace gradient: subtle gold tones
|
|
67
|
+
const workspaceGradient = useMemo(
|
|
68
|
+
() => [theme.brand.primary, theme.brand.secondary, theme.brand.mid] as const,
|
|
69
|
+
[theme.brand]
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (useGradient) {
|
|
73
|
+
return (
|
|
74
|
+
<Text>
|
|
75
|
+
<Text color={theme.brand.primary}>{icons.folder} </Text>
|
|
76
|
+
<GradientText text={displayName} colors={workspaceGradient} bold />
|
|
77
|
+
</Text>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Text color={theme.semantic.text.muted}>
|
|
83
|
+
{icons.folder} {displayName}
|
|
84
|
+
</Text>
|
|
85
|
+
);
|
|
86
|
+
}
|