@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,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentModeIndicator Component (T057)
|
|
3
|
+
*
|
|
4
|
+
* Displays the current agent mode for multi-agent orchestration.
|
|
5
|
+
* Shows agent name, level depth, and agent-specific icons.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/AgentModeIndicator
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { getIcons } from "@vellum/shared";
|
|
11
|
+
import { Box, Text } from "ink";
|
|
12
|
+
import { useMemo } from "react";
|
|
13
|
+
import { useTheme } from "../../theme/index.js";
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Agent level depth in the orchestration hierarchy.
|
|
21
|
+
* - 0: Master orchestrator (ouroboros)
|
|
22
|
+
* - 1: Sub-orchestrators (init, spec, implement, archive)
|
|
23
|
+
* - 2: Workers (coder, qa, writer, analyst, etc.)
|
|
24
|
+
*/
|
|
25
|
+
export type AgentLevel = 0 | 1 | 2;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Known agent types in the multi-agent system.
|
|
29
|
+
*/
|
|
30
|
+
export type AgentType =
|
|
31
|
+
| "orchestrator"
|
|
32
|
+
| "coder"
|
|
33
|
+
| "qa"
|
|
34
|
+
| "writer"
|
|
35
|
+
| "analyst"
|
|
36
|
+
| "devops"
|
|
37
|
+
| "security"
|
|
38
|
+
| "architect"
|
|
39
|
+
| "researcher"
|
|
40
|
+
| "requirements"
|
|
41
|
+
| "tasks"
|
|
42
|
+
| "validator"
|
|
43
|
+
| "init"
|
|
44
|
+
| "spec"
|
|
45
|
+
| "implement"
|
|
46
|
+
| "archive";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Props for the AgentModeIndicator component.
|
|
50
|
+
*/
|
|
51
|
+
export interface AgentModeIndicatorProps {
|
|
52
|
+
/** Current agent name (e.g., 'orchestrator', 'coder', 'qa') */
|
|
53
|
+
readonly agentName: string;
|
|
54
|
+
/** Agent level depth (0=orchestrator, 1=sub-orchestrator, 2=worker) */
|
|
55
|
+
readonly level?: AgentLevel;
|
|
56
|
+
/** Compact display mode (icon only) */
|
|
57
|
+
readonly compact?: boolean;
|
|
58
|
+
/** Whether delegation is currently active (T059) */
|
|
59
|
+
readonly isDelegating?: boolean;
|
|
60
|
+
/** Agent being delegated to (T059) */
|
|
61
|
+
readonly delegatingTo?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// Constants
|
|
66
|
+
// =============================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get agent icons mapping.
|
|
70
|
+
* Uses centralized icon system for consistent terminal display.
|
|
71
|
+
*/
|
|
72
|
+
function getAgentIcons(): Record<string, string> {
|
|
73
|
+
const icons = getIcons();
|
|
74
|
+
return {
|
|
75
|
+
orchestrator: icons.assistant, // Robot/AI icon
|
|
76
|
+
coder: "⌨", // Keyboard (Unicode)
|
|
77
|
+
qa: "⚗", // Test tube (Unicode)
|
|
78
|
+
writer: "✎", // Pencil (Unicode)
|
|
79
|
+
analyst: "⊙", // Search/target (Unicode)
|
|
80
|
+
devops: icons.tool, // Tool icon
|
|
81
|
+
security: "⊗", // Lock-like (Unicode)
|
|
82
|
+
architect: "⦿", // Diagram-like (Unicode)
|
|
83
|
+
researcher: "⊞", // Book-like (Unicode)
|
|
84
|
+
requirements: icons.plan, // Plan icon
|
|
85
|
+
tasks: icons.note, // Note icon
|
|
86
|
+
validator: icons.check, // Check icon
|
|
87
|
+
init: "▶", // Play (Unicode)
|
|
88
|
+
spec: icons.spec, // Spec icon
|
|
89
|
+
implement: icons.gear, // Gear icon
|
|
90
|
+
archive: "⊟", // Box-like (Unicode)
|
|
91
|
+
default: icons.assistant, // Default robot
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Agent display names mapping.
|
|
97
|
+
*/
|
|
98
|
+
const AGENT_NAMES: Record<string, string> = {
|
|
99
|
+
orchestrator: "Orchestrator",
|
|
100
|
+
coder: "Coder",
|
|
101
|
+
qa: "QA",
|
|
102
|
+
writer: "Writer",
|
|
103
|
+
analyst: "Analyst",
|
|
104
|
+
devops: "DevOps",
|
|
105
|
+
security: "Security",
|
|
106
|
+
architect: "Architect",
|
|
107
|
+
researcher: "Researcher",
|
|
108
|
+
requirements: "Requirements",
|
|
109
|
+
tasks: "Tasks",
|
|
110
|
+
validator: "Validator",
|
|
111
|
+
init: "Init",
|
|
112
|
+
spec: "Spec",
|
|
113
|
+
implement: "Implement",
|
|
114
|
+
archive: "Archive",
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Level indicator labels.
|
|
119
|
+
*/
|
|
120
|
+
const LEVEL_LABELS: Record<AgentLevel, string> = {
|
|
121
|
+
0: "L0",
|
|
122
|
+
1: "L1",
|
|
123
|
+
2: "L2",
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// =============================================================================
|
|
127
|
+
// Helper Functions
|
|
128
|
+
// =============================================================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Gets the icon for an agent type.
|
|
132
|
+
* Falls back to default robot icon for unknown agents.
|
|
133
|
+
*/
|
|
134
|
+
function getAgentIcon(agentName: string): string {
|
|
135
|
+
const agentIcons = getAgentIcons();
|
|
136
|
+
const normalizedName = agentName.toLowerCase();
|
|
137
|
+
return agentIcons[normalizedName] ?? agentIcons.default ?? getIcons().assistant;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Gets the display name for an agent.
|
|
142
|
+
* Falls back to capitalized agent name for unknown agents.
|
|
143
|
+
*/
|
|
144
|
+
function getAgentDisplayName(agentName: string): string {
|
|
145
|
+
const normalizedName = agentName.toLowerCase();
|
|
146
|
+
return AGENT_NAMES[normalizedName] ?? agentName.charAt(0).toUpperCase() + agentName.slice(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Gets the color for an agent level.
|
|
151
|
+
* - L0: Primary (orchestrator level)
|
|
152
|
+
* - L1: Info (sub-orchestrator level)
|
|
153
|
+
* - L2: Secondary (worker level)
|
|
154
|
+
*/
|
|
155
|
+
function getLevelColor(level: AgentLevel, theme: ReturnType<typeof useTheme>["theme"]): string {
|
|
156
|
+
switch (level) {
|
|
157
|
+
case 0:
|
|
158
|
+
return theme.colors.primary;
|
|
159
|
+
case 1:
|
|
160
|
+
return theme.colors.info;
|
|
161
|
+
case 2:
|
|
162
|
+
return theme.semantic.text.secondary;
|
|
163
|
+
default:
|
|
164
|
+
return theme.semantic.text.muted;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// Main Component
|
|
170
|
+
// =============================================================================
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* AgentModeIndicator displays the current agent in the multi-agent system.
|
|
174
|
+
*
|
|
175
|
+
* Features:
|
|
176
|
+
* - Agent-specific icon (emoji)
|
|
177
|
+
* - Agent name display
|
|
178
|
+
* - Level indicator (L0/L1/L2)
|
|
179
|
+
* - Compact mode for space-constrained layouts
|
|
180
|
+
* - Themed styling based on agent level
|
|
181
|
+
*
|
|
182
|
+
* Agent Levels:
|
|
183
|
+
* - L0: Master orchestrator (ouroboros)
|
|
184
|
+
* - L1: Sub-orchestrators (init, spec, implement, archive)
|
|
185
|
+
* - L2: Workers (coder, qa, writer, analyst, devops, security, etc.)
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```tsx
|
|
189
|
+
* // Master orchestrator
|
|
190
|
+
* <AgentModeIndicator agentName="orchestrator" level={0} />
|
|
191
|
+
*
|
|
192
|
+
* // Coder worker
|
|
193
|
+
* <AgentModeIndicator agentName="coder" level={2} />
|
|
194
|
+
*
|
|
195
|
+
* // Compact mode (icon only)
|
|
196
|
+
* <AgentModeIndicator agentName="qa" level={2} compact />
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export function AgentModeIndicator({
|
|
200
|
+
agentName,
|
|
201
|
+
level = 2,
|
|
202
|
+
compact = false,
|
|
203
|
+
isDelegating = false,
|
|
204
|
+
delegatingTo,
|
|
205
|
+
}: AgentModeIndicatorProps): React.JSX.Element {
|
|
206
|
+
const { theme } = useTheme();
|
|
207
|
+
|
|
208
|
+
const icon = useMemo(() => getAgentIcon(agentName), [agentName]);
|
|
209
|
+
const displayName = useMemo(() => getAgentDisplayName(agentName), [agentName]);
|
|
210
|
+
const levelColor = useMemo(() => getLevelColor(level, theme), [level, theme]);
|
|
211
|
+
const levelLabel = LEVEL_LABELS[level];
|
|
212
|
+
|
|
213
|
+
// Show delegation indicator when active (GAP 3 fix - T059)
|
|
214
|
+
if (isDelegating && delegatingTo) {
|
|
215
|
+
const delegateIcon = getAgentIcon(delegatingTo);
|
|
216
|
+
const delegateName = getAgentDisplayName(delegatingTo);
|
|
217
|
+
|
|
218
|
+
if (compact) {
|
|
219
|
+
return (
|
|
220
|
+
<Box>
|
|
221
|
+
<Text color={theme.colors.warning}>⋯</Text>
|
|
222
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
223
|
+
<Text>{delegateIcon}</Text>
|
|
224
|
+
</Box>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<Box>
|
|
230
|
+
<Text color={theme.colors.warning}>⋯ Delegating to </Text>
|
|
231
|
+
<Text>{delegateIcon}</Text>
|
|
232
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
233
|
+
<Text color={theme.colors.info}>{delegateName}</Text>
|
|
234
|
+
</Box>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (compact) {
|
|
239
|
+
return (
|
|
240
|
+
<Box>
|
|
241
|
+
<Text>{icon}</Text>
|
|
242
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
243
|
+
<Text color={levelColor}>{levelLabel}</Text>
|
|
244
|
+
</Box>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<Box>
|
|
250
|
+
<Text>{icon}</Text>
|
|
251
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
252
|
+
<Text color={theme.semantic.text.primary}>{displayName}</Text>
|
|
253
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
254
|
+
<Text color={levelColor}>[{levelLabel}]</Text>
|
|
255
|
+
</Box>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextProgress Component
|
|
3
|
+
*
|
|
4
|
+
* Visual context window usage indicator with progress bar.
|
|
5
|
+
* Shows token usage with color-coded thresholds:
|
|
6
|
+
* - Green (0-50%): Plenty of context
|
|
7
|
+
* - Yellow (50-80%): Moderate usage
|
|
8
|
+
* - Red (80%+): Critical usage
|
|
9
|
+
*
|
|
10
|
+
* @module tui/components/StatusBar/ContextProgress
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Box, Text } from "ink";
|
|
14
|
+
import { useMemo } from "react";
|
|
15
|
+
import { useTheme } from "../../theme/index.js";
|
|
16
|
+
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Types
|
|
19
|
+
// =============================================================================
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Props for the ContextProgress component.
|
|
23
|
+
*/
|
|
24
|
+
export interface ContextProgressProps {
|
|
25
|
+
/** Current token count */
|
|
26
|
+
readonly current: number;
|
|
27
|
+
/** Maximum token limit */
|
|
28
|
+
readonly max: number;
|
|
29
|
+
/** Whether to show the label "Context:" (default: true) */
|
|
30
|
+
readonly showLabel?: boolean;
|
|
31
|
+
/** Width of progress bar in characters (default: 10) */
|
|
32
|
+
readonly barWidth?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Constants
|
|
37
|
+
// =============================================================================
|
|
38
|
+
|
|
39
|
+
/** Progress bar characters - using half-filled block for visual progress */
|
|
40
|
+
const BAR_FILLED = "▓";
|
|
41
|
+
const BAR_EMPTY = "░";
|
|
42
|
+
|
|
43
|
+
/** Color thresholds for context usage warning */
|
|
44
|
+
const THRESHOLDS = {
|
|
45
|
+
LOW: 50, // 0-50%: green (plenty of context)
|
|
46
|
+
MEDIUM: 80, // 50-80%: yellow (moderate usage)
|
|
47
|
+
// 80%+: red (critical usage)
|
|
48
|
+
} as const;
|
|
49
|
+
|
|
50
|
+
/** Default bar width - compact for status bar usage */
|
|
51
|
+
const DEFAULT_BAR_WIDTH = 10;
|
|
52
|
+
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// Helper Functions
|
|
55
|
+
// =============================================================================
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Formats a number with K/M suffix for compact display.
|
|
59
|
+
*/
|
|
60
|
+
function formatTokenCount(count: number): string {
|
|
61
|
+
if (count < 1000) {
|
|
62
|
+
return count.toString();
|
|
63
|
+
}
|
|
64
|
+
if (count < 1000000) {
|
|
65
|
+
const k = count / 1000;
|
|
66
|
+
return k >= 10 ? `${Math.round(k)}K` : `${k.toFixed(1)}K`;
|
|
67
|
+
}
|
|
68
|
+
const m = count / 1000000;
|
|
69
|
+
return m >= 10 ? `${Math.round(m)}M` : `${m.toFixed(1)}M`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Calculates the percentage of tokens used.
|
|
74
|
+
*/
|
|
75
|
+
function calculatePercentage(current: number, max: number): number {
|
|
76
|
+
if (max <= 0) return 0;
|
|
77
|
+
return Math.min(Math.round((current / max) * 100), 100);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get the color based on usage percentage.
|
|
82
|
+
* Uses semantic status colors:
|
|
83
|
+
* - 0-50%: success (green) - plenty of context
|
|
84
|
+
* - 50-80%: warning (yellow) - moderate usage
|
|
85
|
+
* - 80-100%: error (red) - critical usage
|
|
86
|
+
*/
|
|
87
|
+
function getProgressColor(percentage: number, theme: ReturnType<typeof useTheme>["theme"]): string {
|
|
88
|
+
if (percentage >= THRESHOLDS.MEDIUM) {
|
|
89
|
+
return theme.colors.error; // Red for 80%+
|
|
90
|
+
}
|
|
91
|
+
if (percentage >= THRESHOLDS.LOW) {
|
|
92
|
+
return theme.colors.warning; // Yellow for 50-80%
|
|
93
|
+
}
|
|
94
|
+
return theme.colors.success; // Green for 0-50%
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Generates the progress bar string.
|
|
99
|
+
*/
|
|
100
|
+
function generateProgressBar(percentage: number, width: number): { filled: string; empty: string } {
|
|
101
|
+
const filledCount = Math.round((percentage / 100) * width);
|
|
102
|
+
const emptyCount = width - filledCount;
|
|
103
|
+
return {
|
|
104
|
+
filled: BAR_FILLED.repeat(filledCount),
|
|
105
|
+
empty: BAR_EMPTY.repeat(emptyCount),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// =============================================================================
|
|
110
|
+
// Main Component
|
|
111
|
+
// =============================================================================
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* ContextProgress displays context window usage with a visual progress bar.
|
|
115
|
+
*
|
|
116
|
+
* Features:
|
|
117
|
+
* - Visual progress bar using Unicode block characters
|
|
118
|
+
* - Color-coded based on usage thresholds
|
|
119
|
+
* - Compact token count display (K/M suffixes)
|
|
120
|
+
* - Optional label display
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* // Full display with label
|
|
125
|
+
* <ContextProgress current={32000} max={40000} />
|
|
126
|
+
* // Output: Context: ████████░░ 80% (32K/40K)
|
|
127
|
+
*
|
|
128
|
+
* // Compact without label
|
|
129
|
+
* <ContextProgress current={5000} max={100000} showLabel={false} />
|
|
130
|
+
* // Output: █░░░░░░░░░ 5% (5K/100K)
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function ContextProgress({
|
|
134
|
+
current,
|
|
135
|
+
max,
|
|
136
|
+
showLabel = true,
|
|
137
|
+
barWidth = DEFAULT_BAR_WIDTH,
|
|
138
|
+
}: ContextProgressProps): React.JSX.Element {
|
|
139
|
+
const { theme } = useTheme();
|
|
140
|
+
|
|
141
|
+
const percentage = useMemo(() => calculatePercentage(current, max), [current, max]);
|
|
142
|
+
|
|
143
|
+
const progressBar = useMemo(
|
|
144
|
+
() => generateProgressBar(percentage, barWidth),
|
|
145
|
+
[percentage, barWidth]
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const progressColor = useMemo(() => getProgressColor(percentage, theme), [percentage, theme]);
|
|
149
|
+
|
|
150
|
+
const formattedCurrent = useMemo(() => formatTokenCount(current), [current]);
|
|
151
|
+
const formattedMax = useMemo(() => formatTokenCount(max), [max]);
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Box>
|
|
155
|
+
{showLabel && <Text color={theme.semantic.text.muted}>Context: </Text>}
|
|
156
|
+
<Text color={progressColor}>{progressBar.filled}</Text>
|
|
157
|
+
<Text color={theme.semantic.text.muted}>{progressBar.empty}</Text>
|
|
158
|
+
<Text color={theme.semantic.text.muted}> </Text>
|
|
159
|
+
<Text color={progressColor}>{percentage}%</Text>
|
|
160
|
+
<Text color={theme.semantic.text.muted}> (</Text>
|
|
161
|
+
<Text color={theme.semantic.text.secondary}>{formattedCurrent}</Text>
|
|
162
|
+
<Text color={theme.semantic.text.muted}>/</Text>
|
|
163
|
+
<Text color={theme.semantic.text.secondary}>{formattedMax}</Text>
|
|
164
|
+
<Text color={theme.semantic.text.muted}>)</Text>
|
|
165
|
+
</Box>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileChangesIndicator Component
|
|
3
|
+
*
|
|
4
|
+
* Displays file change statistics (+additions -deletions) in the header bar.
|
|
5
|
+
* Uses success color for additions and error color for deletions.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/FileChangesIndicator
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Box, Text } from "ink";
|
|
11
|
+
import type React from "react";
|
|
12
|
+
import { useTheme } from "../../theme/index.js";
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Types
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Props for the FileChangesIndicator component.
|
|
20
|
+
*/
|
|
21
|
+
export interface FileChangesIndicatorProps {
|
|
22
|
+
/** Number of lines added */
|
|
23
|
+
readonly additions: number;
|
|
24
|
+
/** Number of lines deleted */
|
|
25
|
+
readonly deletions: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Component
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* FileChangesIndicator displays cumulative file change statistics.
|
|
34
|
+
*
|
|
35
|
+
* Format: +{additions} -{deletions}
|
|
36
|
+
* Returns null if no changes (additions and deletions both 0).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <FileChangesIndicator additions={42} deletions={15} />
|
|
41
|
+
* // Output: +42 -15
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function FileChangesIndicator({
|
|
45
|
+
additions,
|
|
46
|
+
deletions,
|
|
47
|
+
}: FileChangesIndicatorProps): React.JSX.Element | null {
|
|
48
|
+
const { theme } = useTheme();
|
|
49
|
+
|
|
50
|
+
// Don't show if no changes
|
|
51
|
+
if (additions === 0 && deletions === 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Box>
|
|
57
|
+
<Text color={theme.colors.success}>+{additions}</Text>
|
|
58
|
+
<Text> </Text>
|
|
59
|
+
<Text color={theme.colors.error}>-{deletions}</Text>
|
|
60
|
+
</Box>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitIndicator Component
|
|
3
|
+
*
|
|
4
|
+
* Displays the current git branch and dirty status.
|
|
5
|
+
* Uses dim styling to avoid competing with main content.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/components/StatusBar/GitIndicator
|
|
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 { useGitStatus } from "../../hooks/useGitStatus.js";
|
|
15
|
+
import { useTheme } from "../../theme/index.js";
|
|
16
|
+
import { truncateToDisplayWidth } from "../../utils/index.js";
|
|
17
|
+
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Types
|
|
20
|
+
// =============================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Props for the GitIndicator component.
|
|
24
|
+
*/
|
|
25
|
+
export interface GitIndicatorProps {
|
|
26
|
+
/** Maximum width for the branch name (truncates if exceeded) */
|
|
27
|
+
readonly maxWidth?: number;
|
|
28
|
+
/** Whether to show the dirty indicator (default: true) */
|
|
29
|
+
readonly showDirty?: boolean;
|
|
30
|
+
/** Whether to show the changed files count (default: false) */
|
|
31
|
+
readonly showChangedCount?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Component
|
|
36
|
+
// =============================================================================
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* GitIndicator displays the current git branch and status.
|
|
40
|
+
*
|
|
41
|
+
* Uses Nerd Font icon or Unicode/ASCII fallback.
|
|
42
|
+
* Shows dirty indicator when there are uncommitted changes.
|
|
43
|
+
*
|
|
44
|
+
* Returns null if not in a git repository.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* <GitIndicator maxWidth={15} />
|
|
49
|
+
* // Output: main (clean)
|
|
50
|
+
* // Output: main * (dirty)
|
|
51
|
+
* // Output: feature/long… * (truncated + dirty)
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export function GitIndicator({
|
|
55
|
+
maxWidth = 15,
|
|
56
|
+
showDirty = true,
|
|
57
|
+
showChangedCount = false,
|
|
58
|
+
}: GitIndicatorProps): React.JSX.Element | null {
|
|
59
|
+
const { theme } = useTheme();
|
|
60
|
+
const { branch, isDirty, changedFiles, isLoading, isGitRepo } = useGitStatus();
|
|
61
|
+
const icons = getIcons();
|
|
62
|
+
|
|
63
|
+
const displayBranch = useMemo(() => {
|
|
64
|
+
if (!branch) return null;
|
|
65
|
+
// Truncate with ellipsis using string-width for CJK/Emoji handling
|
|
66
|
+
return truncateToDisplayWidth(branch, maxWidth);
|
|
67
|
+
}, [branch, maxWidth]);
|
|
68
|
+
|
|
69
|
+
// Don't render if not in a git repo or still loading
|
|
70
|
+
if (!isGitRepo || isLoading || !displayBranch) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Build the dirty suffix
|
|
75
|
+
const dirtySuffix = showDirty && isDirty ? ` ${icons.dirty}` : "";
|
|
76
|
+
const countSuffix = showChangedCount && changedFiles > 0 ? ` (${changedFiles})` : "";
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Text color={theme.semantic.text.muted}>
|
|
80
|
+
{icons.branch} {displayBranch}
|
|
81
|
+
{isDirty && (
|
|
82
|
+
<Text color={theme.colors.warning}>
|
|
83
|
+
{dirtySuffix}
|
|
84
|
+
{countSuffix}
|
|
85
|
+
</Text>
|
|
86
|
+
)}
|
|
87
|
+
</Text>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HeaderBar Component
|
|
3
|
+
*
|
|
4
|
+
* Embedded header bar showing workspace and git status indicators.
|
|
5
|
+
* Designed to be placed at the top of the AppHeader without adding extra lines.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Workspace directory name with folder icon
|
|
9
|
+
* - Git branch with dirty indicator
|
|
10
|
+
* - Responsive: adapts to terminal width
|
|
11
|
+
* - Dim styling to not compete with main content
|
|
12
|
+
*
|
|
13
|
+
* @module tui/components/StatusBar/HeaderBar
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { Box, Text } from "ink";
|
|
17
|
+
import type React from "react";
|
|
18
|
+
import { useFileChangeStats } from "../../hooks/useFileChangeStats.js";
|
|
19
|
+
import { useTerminalDimensions } from "../../hooks/useTerminalSize.js";
|
|
20
|
+
import { useTheme } from "../../theme/index.js";
|
|
21
|
+
import { FileChangesIndicator } from "./FileChangesIndicator.js";
|
|
22
|
+
import { GitIndicator } from "./GitIndicator.js";
|
|
23
|
+
import { WorkspaceIndicator } from "./WorkspaceIndicator.js";
|
|
24
|
+
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Constants
|
|
27
|
+
// =============================================================================
|
|
28
|
+
|
|
29
|
+
/** Separator between header bar items */
|
|
30
|
+
const SEPARATOR = " │ ";
|
|
31
|
+
|
|
32
|
+
/** Minimum terminal width to show git indicator */
|
|
33
|
+
const MIN_WIDTH_FOR_GIT = 60;
|
|
34
|
+
|
|
35
|
+
/** Minimum terminal width to show both indicators with full width */
|
|
36
|
+
const COMPACT_THRESHOLD = 80;
|
|
37
|
+
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// Types
|
|
40
|
+
// =============================================================================
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Props for the HeaderBar component.
|
|
44
|
+
*/
|
|
45
|
+
export interface HeaderBarProps {
|
|
46
|
+
/** Optional session snapshot count to display */
|
|
47
|
+
readonly snapshotCount?: number;
|
|
48
|
+
/** Whether sandbox boundaries are active */
|
|
49
|
+
readonly sandboxActive?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Component
|
|
54
|
+
// =============================================================================
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* HeaderBar displays workspace and git status in a compact horizontal bar.
|
|
58
|
+
*
|
|
59
|
+
* Layout:
|
|
60
|
+
* - Wide (≥80 cols): vellum │ main *
|
|
61
|
+
* - Medium (60-79): vellum │ main
|
|
62
|
+
* - Narrow (<60): vellum (no git)
|
|
63
|
+
*
|
|
64
|
+
* Uses dim colors to stay unobtrusive while providing useful context.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```tsx
|
|
68
|
+
* <HeaderBar />
|
|
69
|
+
* // Output: vellum │ main *
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export function HeaderBar({ snapshotCount, sandboxActive }: HeaderBarProps): React.JSX.Element {
|
|
73
|
+
const { theme } = useTheme();
|
|
74
|
+
const { width: columns } = useTerminalDimensions();
|
|
75
|
+
const fileStats = useFileChangeStats();
|
|
76
|
+
|
|
77
|
+
// Responsive width calculations
|
|
78
|
+
const isCompact = columns < COMPACT_THRESHOLD;
|
|
79
|
+
const showGit = columns >= MIN_WIDTH_FOR_GIT;
|
|
80
|
+
|
|
81
|
+
// Calculate max widths based on available space
|
|
82
|
+
const workspaceMaxWidth = isCompact ? 15 : 20;
|
|
83
|
+
const gitMaxWidth = isCompact ? 10 : 15;
|
|
84
|
+
|
|
85
|
+
// Show file changes if there are any
|
|
86
|
+
const hasFileChanges = fileStats.additions > 0 || fileStats.deletions > 0;
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<Box flexDirection="row" justifyContent="flex-start">
|
|
90
|
+
{/* Workspace indicator */}
|
|
91
|
+
<WorkspaceIndicator maxWidth={workspaceMaxWidth} />
|
|
92
|
+
|
|
93
|
+
{/* Git indicator (if visible and space allows) */}
|
|
94
|
+
{showGit && (
|
|
95
|
+
<>
|
|
96
|
+
<Text color={theme.semantic.text.muted}>{SEPARATOR}</Text>
|
|
97
|
+
<GitIndicator maxWidth={gitMaxWidth} showDirty showChangedCount={!isCompact} />
|
|
98
|
+
</>
|
|
99
|
+
)}
|
|
100
|
+
|
|
101
|
+
{/* File changes indicator */}
|
|
102
|
+
{hasFileChanges && (
|
|
103
|
+
<>
|
|
104
|
+
<Text color={theme.semantic.text.muted}>{SEPARATOR}</Text>
|
|
105
|
+
<FileChangesIndicator additions={fileStats.additions} deletions={fileStats.deletions} />
|
|
106
|
+
</>
|
|
107
|
+
)}
|
|
108
|
+
|
|
109
|
+
{/* Optional snapshot count */}
|
|
110
|
+
{snapshotCount !== undefined && snapshotCount > 0 && (
|
|
111
|
+
<>
|
|
112
|
+
<Text color={theme.semantic.text.muted}>{SEPARATOR}</Text>
|
|
113
|
+
<Text color={theme.semantic.text.muted}>◉ {snapshotCount}</Text>
|
|
114
|
+
</>
|
|
115
|
+
)}
|
|
116
|
+
|
|
117
|
+
{/* Optional sandbox indicator */}
|
|
118
|
+
{sandboxActive && (
|
|
119
|
+
<>
|
|
120
|
+
<Text color={theme.semantic.text.muted}>{SEPARATOR}</Text>
|
|
121
|
+
<Text color={theme.colors.warning}>⊘ sandbox</Text>
|
|
122
|
+
</>
|
|
123
|
+
)}
|
|
124
|
+
</Box>
|
|
125
|
+
);
|
|
126
|
+
}
|