@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,483 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolParams Component (T028)
|
|
3
|
+
*
|
|
4
|
+
* Renders tool parameters as a collapsible JSON tree structure with
|
|
5
|
+
* syntax highlighting for different value types and special formatting
|
|
6
|
+
* for file paths and shell commands.
|
|
7
|
+
*
|
|
8
|
+
* @module tui/components/Tools/ToolParams
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Box, Text } from "ink";
|
|
12
|
+
import type React from "react";
|
|
13
|
+
import { useTheme } from "../../theme/index.js";
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Props for the ToolParams component.
|
|
21
|
+
*/
|
|
22
|
+
export interface ToolParamsProps {
|
|
23
|
+
/** The parameters object to render */
|
|
24
|
+
readonly params: Record<string, unknown>;
|
|
25
|
+
/** Whether to show collapsed view (default: false) */
|
|
26
|
+
readonly collapsed?: boolean;
|
|
27
|
+
/** Maximum depth to render nested objects (default: 10) */
|
|
28
|
+
readonly maxDepth?: number;
|
|
29
|
+
/** Highlight file paths with special styling (default: false) */
|
|
30
|
+
readonly highlightPaths?: boolean;
|
|
31
|
+
/** Highlight shell commands with special styling (default: false) */
|
|
32
|
+
readonly highlightCommands?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Internal props for recursive value rendering.
|
|
37
|
+
*/
|
|
38
|
+
interface ValueRenderProps {
|
|
39
|
+
/** The value to render */
|
|
40
|
+
readonly value: unknown;
|
|
41
|
+
/** The key name (for detecting command keys) */
|
|
42
|
+
readonly keyName?: string;
|
|
43
|
+
/** Current depth in the tree */
|
|
44
|
+
readonly depth: number;
|
|
45
|
+
/** Maximum depth to render */
|
|
46
|
+
readonly maxDepth: number;
|
|
47
|
+
/** Whether to highlight file paths */
|
|
48
|
+
readonly highlightPaths: boolean;
|
|
49
|
+
/** Whether to highlight commands */
|
|
50
|
+
readonly highlightCommands: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// Constants
|
|
55
|
+
// =============================================================================
|
|
56
|
+
|
|
57
|
+
/** Base indentation per depth level */
|
|
58
|
+
const INDENT_SPACES = 2;
|
|
59
|
+
|
|
60
|
+
/** Keys that typically contain shell commands */
|
|
61
|
+
const COMMAND_KEYS = new Set(["command", "cmd", "shell", "script", "exec", "run", "execute"]);
|
|
62
|
+
|
|
63
|
+
/** File path patterns to detect */
|
|
64
|
+
const PATH_PATTERNS = [
|
|
65
|
+
// Unix-style absolute paths
|
|
66
|
+
/^\/[\w\-./]+$/,
|
|
67
|
+
// Windows-style paths
|
|
68
|
+
/^[A-Za-z]:[\\/][\w\-.\\/]+$/,
|
|
69
|
+
// Relative paths starting with ./ or ../
|
|
70
|
+
/^\.\.?\/[\w\-./]+$/,
|
|
71
|
+
// Common file extensions
|
|
72
|
+
/\.(ts|tsx|js|jsx|json|md|py|rb|go|rs|java|c|cpp|h|hpp|css|scss|html|xml|yaml|yml|toml|sh|bash|zsh|ps1|cmd|bat)$/i,
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
// =============================================================================
|
|
76
|
+
// Helper Functions
|
|
77
|
+
// =============================================================================
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if a string looks like a file path.
|
|
81
|
+
*
|
|
82
|
+
* @param value - The string to check
|
|
83
|
+
* @returns true if the string appears to be a file path
|
|
84
|
+
*/
|
|
85
|
+
function isFilePath(value: string): boolean {
|
|
86
|
+
return PATH_PATTERNS.some((pattern) => pattern.test(value));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if a key name indicates a command.
|
|
91
|
+
*
|
|
92
|
+
* @param key - The key name to check
|
|
93
|
+
* @returns true if the key likely contains a command
|
|
94
|
+
*/
|
|
95
|
+
function isCommandKey(key: string): boolean {
|
|
96
|
+
return COMMAND_KEYS.has(key.toLowerCase());
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get the type name of a value for display.
|
|
101
|
+
*
|
|
102
|
+
* @param value - The value to check
|
|
103
|
+
* @returns The type name string
|
|
104
|
+
*/
|
|
105
|
+
function getTypeName(value: unknown): string {
|
|
106
|
+
if (value === null) return "null";
|
|
107
|
+
if (Array.isArray(value)) return "array";
|
|
108
|
+
return typeof value;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Create indentation string for a given depth.
|
|
113
|
+
*
|
|
114
|
+
* @param depth - The current depth level
|
|
115
|
+
* @returns Indentation string
|
|
116
|
+
*/
|
|
117
|
+
function indent(depth: number): string {
|
|
118
|
+
return " ".repeat(depth * INDENT_SPACES);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// =============================================================================
|
|
122
|
+
// Value Renderer Components
|
|
123
|
+
// =============================================================================
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Renders a null value.
|
|
127
|
+
*/
|
|
128
|
+
function NullValue(): React.JSX.Element {
|
|
129
|
+
const { theme } = useTheme();
|
|
130
|
+
return <Text color={theme.semantic.text.muted}>null</Text>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Renders a boolean value.
|
|
135
|
+
*/
|
|
136
|
+
function BooleanValue({ value }: { readonly value: boolean }): React.JSX.Element {
|
|
137
|
+
const { theme } = useTheme();
|
|
138
|
+
return <Text color={theme.colors.warning}>{String(value)}</Text>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Renders a number value.
|
|
143
|
+
*/
|
|
144
|
+
function NumberValue({ value }: { readonly value: number }): React.JSX.Element {
|
|
145
|
+
const { theme } = useTheme();
|
|
146
|
+
return <Text color={theme.colors.info}>{String(value)}</Text>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Renders a string value with optional path/command highlighting.
|
|
151
|
+
*/
|
|
152
|
+
function StringValue({
|
|
153
|
+
value,
|
|
154
|
+
keyName,
|
|
155
|
+
highlightPaths,
|
|
156
|
+
highlightCommands,
|
|
157
|
+
}: {
|
|
158
|
+
readonly value: string;
|
|
159
|
+
readonly keyName?: string;
|
|
160
|
+
readonly highlightPaths: boolean;
|
|
161
|
+
readonly highlightCommands: boolean;
|
|
162
|
+
}): React.JSX.Element {
|
|
163
|
+
const { theme } = useTheme();
|
|
164
|
+
|
|
165
|
+
// Check for command highlighting
|
|
166
|
+
if (highlightCommands && keyName && isCommandKey(keyName)) {
|
|
167
|
+
return (
|
|
168
|
+
<Text color={theme.colors.accent} italic>
|
|
169
|
+
"{value}"
|
|
170
|
+
</Text>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check for path highlighting
|
|
175
|
+
if (highlightPaths && isFilePath(value)) {
|
|
176
|
+
return (
|
|
177
|
+
<Text color={theme.semantic.syntax.function} underline>
|
|
178
|
+
"{value}"
|
|
179
|
+
</Text>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Default string rendering
|
|
184
|
+
return <Text color={theme.colors.success}>"{value}"</Text>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Renders an array value with proper formatting.
|
|
189
|
+
*/
|
|
190
|
+
function ArrayValue({
|
|
191
|
+
value,
|
|
192
|
+
depth,
|
|
193
|
+
maxDepth,
|
|
194
|
+
highlightPaths,
|
|
195
|
+
highlightCommands,
|
|
196
|
+
}: {
|
|
197
|
+
readonly value: unknown[];
|
|
198
|
+
readonly depth: number;
|
|
199
|
+
readonly maxDepth: number;
|
|
200
|
+
readonly highlightPaths: boolean;
|
|
201
|
+
readonly highlightCommands: boolean;
|
|
202
|
+
}): React.JSX.Element {
|
|
203
|
+
const { theme } = useTheme();
|
|
204
|
+
const mutedColor = theme.semantic.text.muted;
|
|
205
|
+
|
|
206
|
+
// Max depth reached - show collapsed
|
|
207
|
+
if (depth >= maxDepth) {
|
|
208
|
+
return <Text color={mutedColor}>[{value.length} items...]</Text>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Empty array
|
|
212
|
+
if (value.length === 0) {
|
|
213
|
+
return <Text color={mutedColor}>[]</Text>;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const childIndent = indent(depth + 1);
|
|
217
|
+
const closeIndent = indent(depth);
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<Box flexDirection="column">
|
|
221
|
+
<Text color={mutedColor}>[</Text>
|
|
222
|
+
{value.map((item, index) => (
|
|
223
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: Array order is stable in JSON params
|
|
224
|
+
<Box key={index}>
|
|
225
|
+
<Text>{childIndent}</Text>
|
|
226
|
+
<ValueRenderer
|
|
227
|
+
value={item}
|
|
228
|
+
depth={depth + 1}
|
|
229
|
+
maxDepth={maxDepth}
|
|
230
|
+
highlightPaths={highlightPaths}
|
|
231
|
+
highlightCommands={highlightCommands}
|
|
232
|
+
/>
|
|
233
|
+
{index < value.length - 1 && <Text color={mutedColor}>,</Text>}
|
|
234
|
+
</Box>
|
|
235
|
+
))}
|
|
236
|
+
<Text color={mutedColor}>{closeIndent}]</Text>
|
|
237
|
+
</Box>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Renders an object value with proper formatting.
|
|
243
|
+
*/
|
|
244
|
+
function ObjectValue({
|
|
245
|
+
value,
|
|
246
|
+
depth,
|
|
247
|
+
maxDepth,
|
|
248
|
+
highlightPaths,
|
|
249
|
+
highlightCommands,
|
|
250
|
+
}: {
|
|
251
|
+
readonly value: Record<string, unknown>;
|
|
252
|
+
readonly depth: number;
|
|
253
|
+
readonly maxDepth: number;
|
|
254
|
+
readonly highlightPaths: boolean;
|
|
255
|
+
readonly highlightCommands: boolean;
|
|
256
|
+
}): React.JSX.Element {
|
|
257
|
+
const { theme } = useTheme();
|
|
258
|
+
const mutedColor = theme.semantic.text.muted;
|
|
259
|
+
const keyColor = theme.semantic.text.primary;
|
|
260
|
+
|
|
261
|
+
const entries = Object.entries(value);
|
|
262
|
+
|
|
263
|
+
// Max depth reached - show collapsed
|
|
264
|
+
if (depth >= maxDepth) {
|
|
265
|
+
return (
|
|
266
|
+
<Text color={mutedColor}>
|
|
267
|
+
{"{"}...{entries.length} keys{"}"}
|
|
268
|
+
</Text>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Empty object
|
|
273
|
+
if (entries.length === 0) {
|
|
274
|
+
return <Text color={mutedColor}>{"{}"}</Text>;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const childIndent = indent(depth + 1);
|
|
278
|
+
const closeIndent = indent(depth);
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<Box flexDirection="column">
|
|
282
|
+
<Text color={mutedColor}>{"{"}</Text>
|
|
283
|
+
{entries.map(([key, val], index) => (
|
|
284
|
+
<Box key={key}>
|
|
285
|
+
<Text>{childIndent}</Text>
|
|
286
|
+
<Text bold color={keyColor}>
|
|
287
|
+
{key}
|
|
288
|
+
</Text>
|
|
289
|
+
<Text color={mutedColor}>: </Text>
|
|
290
|
+
<ValueRenderer
|
|
291
|
+
value={val}
|
|
292
|
+
keyName={key}
|
|
293
|
+
depth={depth + 1}
|
|
294
|
+
maxDepth={maxDepth}
|
|
295
|
+
highlightPaths={highlightPaths}
|
|
296
|
+
highlightCommands={highlightCommands}
|
|
297
|
+
/>
|
|
298
|
+
{index < entries.length - 1 && <Text color={mutedColor}>,</Text>}
|
|
299
|
+
</Box>
|
|
300
|
+
))}
|
|
301
|
+
<Text color={mutedColor}>
|
|
302
|
+
{closeIndent}
|
|
303
|
+
{"}"}
|
|
304
|
+
</Text>
|
|
305
|
+
</Box>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Main value renderer that dispatches to type-specific renderers.
|
|
311
|
+
*/
|
|
312
|
+
function ValueRenderer({
|
|
313
|
+
value,
|
|
314
|
+
keyName,
|
|
315
|
+
depth,
|
|
316
|
+
maxDepth,
|
|
317
|
+
highlightPaths,
|
|
318
|
+
highlightCommands,
|
|
319
|
+
}: ValueRenderProps): React.JSX.Element {
|
|
320
|
+
const { theme } = useTheme();
|
|
321
|
+
|
|
322
|
+
// Handle null
|
|
323
|
+
if (value === null) {
|
|
324
|
+
return <NullValue />;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Handle undefined (treat as null)
|
|
328
|
+
if (value === undefined) {
|
|
329
|
+
return <Text color={theme.semantic.text.muted}>undefined</Text>;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Handle primitive types
|
|
333
|
+
const type = getTypeName(value);
|
|
334
|
+
|
|
335
|
+
switch (type) {
|
|
336
|
+
case "boolean":
|
|
337
|
+
return <BooleanValue value={value as boolean} />;
|
|
338
|
+
|
|
339
|
+
case "number":
|
|
340
|
+
return <NumberValue value={value as number} />;
|
|
341
|
+
|
|
342
|
+
case "string":
|
|
343
|
+
return (
|
|
344
|
+
<StringValue
|
|
345
|
+
value={value as string}
|
|
346
|
+
keyName={keyName}
|
|
347
|
+
highlightPaths={highlightPaths}
|
|
348
|
+
highlightCommands={highlightCommands}
|
|
349
|
+
/>
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
case "array":
|
|
353
|
+
return (
|
|
354
|
+
<ArrayValue
|
|
355
|
+
value={value as unknown[]}
|
|
356
|
+
depth={depth}
|
|
357
|
+
maxDepth={maxDepth}
|
|
358
|
+
highlightPaths={highlightPaths}
|
|
359
|
+
highlightCommands={highlightCommands}
|
|
360
|
+
/>
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
case "object":
|
|
364
|
+
return (
|
|
365
|
+
<ObjectValue
|
|
366
|
+
value={value as Record<string, unknown>}
|
|
367
|
+
depth={depth}
|
|
368
|
+
maxDepth={maxDepth}
|
|
369
|
+
highlightPaths={highlightPaths}
|
|
370
|
+
highlightCommands={highlightCommands}
|
|
371
|
+
/>
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
default:
|
|
375
|
+
// For functions, symbols, etc.
|
|
376
|
+
return <Text color={theme.semantic.text.muted}>[{type}]</Text>;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// =============================================================================
|
|
381
|
+
// Collapsed View
|
|
382
|
+
// =============================================================================
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Renders a collapsed summary of the params object.
|
|
386
|
+
*/
|
|
387
|
+
function CollapsedView({
|
|
388
|
+
params,
|
|
389
|
+
}: {
|
|
390
|
+
readonly params: Record<string, unknown>;
|
|
391
|
+
}): React.JSX.Element {
|
|
392
|
+
const { theme } = useTheme();
|
|
393
|
+
const keys = Object.keys(params);
|
|
394
|
+
const keyCount = keys.length;
|
|
395
|
+
|
|
396
|
+
if (keyCount === 0) {
|
|
397
|
+
return <Text color={theme.semantic.text.muted}>{"{}"}</Text>;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Show first few keys as preview
|
|
401
|
+
const previewKeys = keys.slice(0, 3);
|
|
402
|
+
const hasMore = keyCount > 3;
|
|
403
|
+
|
|
404
|
+
return (
|
|
405
|
+
<Box>
|
|
406
|
+
<Text color={theme.semantic.text.muted}>{"{ "}</Text>
|
|
407
|
+
{previewKeys.map((key, index) => (
|
|
408
|
+
<Box key={key}>
|
|
409
|
+
<Text bold color={theme.semantic.text.primary}>
|
|
410
|
+
{key}
|
|
411
|
+
</Text>
|
|
412
|
+
{index < previewKeys.length - 1 && <Text color={theme.semantic.text.muted}>, </Text>}
|
|
413
|
+
</Box>
|
|
414
|
+
))}
|
|
415
|
+
{hasMore && <Text color={theme.semantic.text.muted}>, ...+{keyCount - 3}</Text>}
|
|
416
|
+
<Text color={theme.semantic.text.muted}>{" }"}</Text>
|
|
417
|
+
</Box>
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// =============================================================================
|
|
422
|
+
// Main Component
|
|
423
|
+
// =============================================================================
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* ToolParams displays tool parameters as a formatted JSON tree.
|
|
427
|
+
*
|
|
428
|
+
* Features:
|
|
429
|
+
* - Collapsible tree structure for nested objects/arrays
|
|
430
|
+
* - Type-specific color coding:
|
|
431
|
+
* - Keys: bold primary text
|
|
432
|
+
* - Strings: green
|
|
433
|
+
* - Numbers: cyan/info
|
|
434
|
+
* - Booleans: yellow/warning
|
|
435
|
+
* - Null: muted/dim
|
|
436
|
+
* - Optional file path highlighting (underlined)
|
|
437
|
+
* - Optional command highlighting (italic accent)
|
|
438
|
+
* - Proper indentation for nested structures
|
|
439
|
+
* - Collapsed mode shows key preview
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```tsx
|
|
443
|
+
* // Basic usage
|
|
444
|
+
* <ToolParams params={{ name: "test", count: 42 }} />
|
|
445
|
+
*
|
|
446
|
+
* // With path highlighting
|
|
447
|
+
* <ToolParams
|
|
448
|
+
* params={{ filePath: "/src/index.ts" }}
|
|
449
|
+
* highlightPaths
|
|
450
|
+
* />
|
|
451
|
+
*
|
|
452
|
+
* // Collapsed view
|
|
453
|
+
* <ToolParams params={largeObject} collapsed />
|
|
454
|
+
*
|
|
455
|
+
* // Limited depth
|
|
456
|
+
* <ToolParams params={deepObject} maxDepth={3} />
|
|
457
|
+
* ```
|
|
458
|
+
*/
|
|
459
|
+
export function ToolParams({
|
|
460
|
+
params,
|
|
461
|
+
collapsed = false,
|
|
462
|
+
maxDepth = 10,
|
|
463
|
+
highlightPaths = false,
|
|
464
|
+
highlightCommands = false,
|
|
465
|
+
}: ToolParamsProps): React.JSX.Element {
|
|
466
|
+
// Collapsed mode - show summary
|
|
467
|
+
if (collapsed) {
|
|
468
|
+
return <CollapsedView params={params} />;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Full tree rendering
|
|
472
|
+
return (
|
|
473
|
+
<ObjectValue
|
|
474
|
+
value={params}
|
|
475
|
+
depth={0}
|
|
476
|
+
maxDepth={maxDepth}
|
|
477
|
+
highlightPaths={highlightPaths}
|
|
478
|
+
highlightCommands={highlightCommands}
|
|
479
|
+
/>
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export default ToolParams;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolsPanel Component
|
|
3
|
+
*
|
|
4
|
+
* Minimal sidebar panel that renders recent tool executions.
|
|
5
|
+
* Designed for narrow widths (20-40 cols) inside Layout sidebar.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Box, Text } from "ink";
|
|
9
|
+
import type React from "react";
|
|
10
|
+
import { useMemo } from "react";
|
|
11
|
+
import { useTools } from "../../context/ToolsContext.js";
|
|
12
|
+
import { useTheme } from "../../theme/index.js";
|
|
13
|
+
import { HotkeyHints } from "../common/HotkeyHints.js";
|
|
14
|
+
import { ToolParams } from "./ToolParams.js";
|
|
15
|
+
|
|
16
|
+
/** Shell tool names that support streaming output */
|
|
17
|
+
const SHELL_TOOLS = new Set(["shell", "bash"]);
|
|
18
|
+
|
|
19
|
+
export interface ToolsPanelProps {
|
|
20
|
+
/** Whether this panel is currently focused (reserved for future key handling). */
|
|
21
|
+
readonly isFocused?: boolean;
|
|
22
|
+
/** Max number of executions to show (default: 10). */
|
|
23
|
+
readonly maxItems?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function statusLabel(status: string): string {
|
|
27
|
+
switch (status) {
|
|
28
|
+
case "pending":
|
|
29
|
+
return "pending";
|
|
30
|
+
case "approved":
|
|
31
|
+
return "approved";
|
|
32
|
+
case "rejected":
|
|
33
|
+
return "rejected";
|
|
34
|
+
case "running":
|
|
35
|
+
return "running";
|
|
36
|
+
case "complete":
|
|
37
|
+
return "done";
|
|
38
|
+
case "error":
|
|
39
|
+
return "error";
|
|
40
|
+
default:
|
|
41
|
+
return status;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function statusGlyph(status: string): string {
|
|
46
|
+
switch (status) {
|
|
47
|
+
case "pending":
|
|
48
|
+
return "?";
|
|
49
|
+
case "approved":
|
|
50
|
+
return "✓";
|
|
51
|
+
case "running":
|
|
52
|
+
return "…";
|
|
53
|
+
case "complete":
|
|
54
|
+
return "✓";
|
|
55
|
+
case "rejected":
|
|
56
|
+
return "✗";
|
|
57
|
+
case "error":
|
|
58
|
+
return "!";
|
|
59
|
+
default:
|
|
60
|
+
return "·";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function ToolsPanel({ maxItems = 10 }: ToolsPanelProps): React.JSX.Element {
|
|
65
|
+
const { theme } = useTheme();
|
|
66
|
+
const { executions, pendingApproval } = useTools();
|
|
67
|
+
|
|
68
|
+
const hints = useMemo(
|
|
69
|
+
() => [
|
|
70
|
+
{ keys: "Alt+K", label: "Sidebar" },
|
|
71
|
+
{ keys: "Alt+G", label: "Tools" },
|
|
72
|
+
{ keys: "Alt+O", label: "MCP" },
|
|
73
|
+
{ keys: "Alt+P", label: "Memory" },
|
|
74
|
+
{ keys: "Alt+T", label: "Todo" },
|
|
75
|
+
{ keys: "Ctrl+S", label: "Sessions" },
|
|
76
|
+
{ keys: "Ctrl+Z", label: "Undo" },
|
|
77
|
+
{ keys: "Ctrl+Y", label: "Redo" },
|
|
78
|
+
],
|
|
79
|
+
[]
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const recent = useMemo(() => {
|
|
83
|
+
if (executions.length <= maxItems) {
|
|
84
|
+
return executions;
|
|
85
|
+
}
|
|
86
|
+
return executions.slice(executions.length - maxItems);
|
|
87
|
+
}, [executions, maxItems]);
|
|
88
|
+
|
|
89
|
+
const latest = recent.length > 0 ? recent[recent.length - 1] : undefined;
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Box flexDirection="column">
|
|
93
|
+
<Text color={theme.colors.primary} bold>
|
|
94
|
+
Tools
|
|
95
|
+
</Text>
|
|
96
|
+
|
|
97
|
+
<Text dimColor>
|
|
98
|
+
Pending: {pendingApproval.length} Total: {executions.length}
|
|
99
|
+
</Text>
|
|
100
|
+
|
|
101
|
+
{recent.length === 0 ? (
|
|
102
|
+
<Text dimColor>No tool activity yet</Text>
|
|
103
|
+
) : (
|
|
104
|
+
<Box flexDirection="column" marginTop={1}>
|
|
105
|
+
{recent.map((execution) => (
|
|
106
|
+
<Text key={execution.id}>
|
|
107
|
+
{statusGlyph(execution.status)} {execution.toolName} ({statusLabel(execution.status)})
|
|
108
|
+
</Text>
|
|
109
|
+
))}
|
|
110
|
+
</Box>
|
|
111
|
+
)}
|
|
112
|
+
|
|
113
|
+
{/* Minimal details view (most recent execution) */}
|
|
114
|
+
{latest && (
|
|
115
|
+
<Box flexDirection="column" marginTop={1}>
|
|
116
|
+
<Text color={theme.colors.primary} bold>
|
|
117
|
+
Details
|
|
118
|
+
</Text>
|
|
119
|
+
<Text dimColor>
|
|
120
|
+
{latest.toolName} ({statusLabel(latest.status)})
|
|
121
|
+
</Text>
|
|
122
|
+
|
|
123
|
+
{Object.keys(latest.params).length > 0 && (
|
|
124
|
+
<Box marginTop={1} flexDirection="column">
|
|
125
|
+
<Text dimColor>Params:</Text>
|
|
126
|
+
<ToolParams params={latest.params} collapsed highlightPaths highlightCommands />
|
|
127
|
+
</Box>
|
|
128
|
+
)}
|
|
129
|
+
|
|
130
|
+
{/* Shell output streaming preview */}
|
|
131
|
+
{SHELL_TOOLS.has(latest.toolName) &&
|
|
132
|
+
latest.status === "running" &&
|
|
133
|
+
latest.shellOutput &&
|
|
134
|
+
latest.shellOutput.length > 0 && (
|
|
135
|
+
<Box marginTop={1} flexDirection="column">
|
|
136
|
+
<Text color={theme.colors.primary} dimColor>
|
|
137
|
+
Output:
|
|
138
|
+
</Text>
|
|
139
|
+
<Box
|
|
140
|
+
flexDirection="column"
|
|
141
|
+
borderStyle="single"
|
|
142
|
+
borderColor={theme.colors.secondary}
|
|
143
|
+
paddingX={1}
|
|
144
|
+
>
|
|
145
|
+
{latest.shellOutput.slice(-5).map((line, idx) => (
|
|
146
|
+
<Text key={`shell-output-${idx}-${line.slice(0, 20)}`} wrap="truncate">
|
|
147
|
+
{line}
|
|
148
|
+
</Text>
|
|
149
|
+
))}
|
|
150
|
+
</Box>
|
|
151
|
+
</Box>
|
|
152
|
+
)}
|
|
153
|
+
|
|
154
|
+
{latest.status === "error" && latest.error && (
|
|
155
|
+
<Box marginTop={1}>
|
|
156
|
+
<Text color={theme.colors.error}>Error: {latest.error.message}</Text>
|
|
157
|
+
</Box>
|
|
158
|
+
)}
|
|
159
|
+
|
|
160
|
+
{latest.status === "complete" && latest.result !== undefined && (
|
|
161
|
+
<Box marginTop={1} flexDirection="column">
|
|
162
|
+
<Text dimColor>Result:</Text>
|
|
163
|
+
<Text>
|
|
164
|
+
{typeof latest.result === "string"
|
|
165
|
+
? latest.result
|
|
166
|
+
: JSON.stringify(latest.result, null, 2)}
|
|
167
|
+
</Text>
|
|
168
|
+
</Box>
|
|
169
|
+
)}
|
|
170
|
+
</Box>
|
|
171
|
+
)}
|
|
172
|
+
|
|
173
|
+
<Box marginTop={1}>
|
|
174
|
+
<HotkeyHints hints={hints} />
|
|
175
|
+
</Box>
|
|
176
|
+
</Box>
|
|
177
|
+
);
|
|
178
|
+
}
|