@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,443 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useBacktrack Hook (T058)
|
|
3
|
+
*
|
|
4
|
+
* React hook for managing conversation backtracking and branching.
|
|
5
|
+
* Provides undo/redo functionality with support for creating alternative
|
|
6
|
+
* conversation branches (forks).
|
|
7
|
+
*
|
|
8
|
+
* @module @vellum/cli
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { useCallback, useMemo, useReducer } from "react";
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Types
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Represents a single state snapshot in the history.
|
|
19
|
+
*/
|
|
20
|
+
export interface HistorySnapshot<T> {
|
|
21
|
+
/** Unique identifier for this snapshot */
|
|
22
|
+
readonly id: string;
|
|
23
|
+
/** The state data at this point */
|
|
24
|
+
readonly state: T;
|
|
25
|
+
/** Timestamp when this snapshot was created */
|
|
26
|
+
readonly timestamp: number;
|
|
27
|
+
/** Optional description of what changed */
|
|
28
|
+
readonly description?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Represents a branch (fork) in the conversation history.
|
|
33
|
+
*/
|
|
34
|
+
export interface Branch<T> {
|
|
35
|
+
/** Unique identifier for this branch */
|
|
36
|
+
readonly id: string;
|
|
37
|
+
/** Human-readable name for the branch */
|
|
38
|
+
readonly name: string;
|
|
39
|
+
/** Index in the parent branch where this fork occurred */
|
|
40
|
+
readonly forkPoint: number;
|
|
41
|
+
/** The history snapshots in this branch */
|
|
42
|
+
readonly history: ReadonlyArray<HistorySnapshot<T>>;
|
|
43
|
+
/** ID of the parent branch (null for main branch) */
|
|
44
|
+
readonly parentBranchId: string | null;
|
|
45
|
+
/** Timestamp when this branch was created */
|
|
46
|
+
readonly createdAt: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Current backtrack state exposed to consumers.
|
|
51
|
+
*/
|
|
52
|
+
export interface BacktrackState {
|
|
53
|
+
/** Whether undo is available */
|
|
54
|
+
readonly canUndo: boolean;
|
|
55
|
+
/** Whether redo is available */
|
|
56
|
+
readonly canRedo: boolean;
|
|
57
|
+
/** Total number of forks/branches */
|
|
58
|
+
readonly forkCount: number;
|
|
59
|
+
/** Current branch identifier */
|
|
60
|
+
readonly currentBranch: string;
|
|
61
|
+
/** Current position in history */
|
|
62
|
+
readonly currentIndex: number;
|
|
63
|
+
/** Total history length in current branch */
|
|
64
|
+
readonly historyLength: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Options for the useBacktrack hook.
|
|
69
|
+
*/
|
|
70
|
+
export interface UseBacktrackOptions<T> {
|
|
71
|
+
/** Initial state */
|
|
72
|
+
readonly initialState: T;
|
|
73
|
+
/** Maximum history length per branch (default: 100) */
|
|
74
|
+
readonly maxHistory?: number;
|
|
75
|
+
/** Whether to enable branching (default: true) */
|
|
76
|
+
readonly enableBranching?: boolean;
|
|
77
|
+
/** Callback when state changes */
|
|
78
|
+
readonly onStateChange?: (state: T, action: "undo" | "redo" | "push" | "branch") => void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Return value of useBacktrack hook.
|
|
83
|
+
*/
|
|
84
|
+
export interface UseBacktrackReturn<T> {
|
|
85
|
+
/** Current state */
|
|
86
|
+
readonly currentState: T;
|
|
87
|
+
/** Backtrack state information */
|
|
88
|
+
readonly backtrackState: BacktrackState;
|
|
89
|
+
/** All available branches */
|
|
90
|
+
readonly branches: ReadonlyArray<Branch<T>>;
|
|
91
|
+
/** Push a new state to history */
|
|
92
|
+
readonly push: (state: T, description?: string) => void;
|
|
93
|
+
/** Undo to previous state */
|
|
94
|
+
readonly undo: () => void;
|
|
95
|
+
/** Redo to next state */
|
|
96
|
+
readonly redo: () => void;
|
|
97
|
+
/** Create a new branch from current position */
|
|
98
|
+
readonly createBranch: (name?: string) => string;
|
|
99
|
+
/** Switch to a different branch */
|
|
100
|
+
readonly switchBranch: (branchId: string) => void;
|
|
101
|
+
/** Get branch by ID */
|
|
102
|
+
readonly getBranch: (branchId: string) => Branch<T> | undefined;
|
|
103
|
+
/** Reset to initial state */
|
|
104
|
+
readonly reset: () => void;
|
|
105
|
+
/** Go to specific point in history */
|
|
106
|
+
readonly goTo: (index: number) => void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// =============================================================================
|
|
110
|
+
// Constants
|
|
111
|
+
// =============================================================================
|
|
112
|
+
|
|
113
|
+
/** Default maximum history length */
|
|
114
|
+
const DEFAULT_MAX_HISTORY = 100;
|
|
115
|
+
|
|
116
|
+
/** Main branch identifier */
|
|
117
|
+
const MAIN_BRANCH_ID = "main";
|
|
118
|
+
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// Internal State Types
|
|
121
|
+
// =============================================================================
|
|
122
|
+
|
|
123
|
+
interface InternalState<T> {
|
|
124
|
+
readonly branches: Record<string, Branch<T>>;
|
|
125
|
+
readonly currentBranchId: string;
|
|
126
|
+
readonly currentIndex: number;
|
|
127
|
+
readonly maxHistory: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
type Action<T> =
|
|
131
|
+
| { type: "PUSH"; state: T; description?: string }
|
|
132
|
+
| { type: "UNDO" }
|
|
133
|
+
| { type: "REDO" }
|
|
134
|
+
| { type: "GO_TO"; index: number }
|
|
135
|
+
| { type: "CREATE_BRANCH"; name?: string; newBranchId: string }
|
|
136
|
+
| { type: "SWITCH_BRANCH"; branchId: string }
|
|
137
|
+
| { type: "RESET"; initialState: T };
|
|
138
|
+
|
|
139
|
+
// =============================================================================
|
|
140
|
+
// Utility Functions
|
|
141
|
+
// =============================================================================
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Generate a unique ID for snapshots and branches.
|
|
145
|
+
*/
|
|
146
|
+
function generateId(): string {
|
|
147
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Create a new snapshot.
|
|
152
|
+
*/
|
|
153
|
+
function createSnapshot<T>(state: T, description?: string): HistorySnapshot<T> {
|
|
154
|
+
return {
|
|
155
|
+
id: generateId(),
|
|
156
|
+
state,
|
|
157
|
+
timestamp: Date.now(),
|
|
158
|
+
description,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Create initial branch with initial state.
|
|
164
|
+
*/
|
|
165
|
+
function createInitialBranch<T>(initialState: T): Branch<T> {
|
|
166
|
+
return {
|
|
167
|
+
id: MAIN_BRANCH_ID,
|
|
168
|
+
name: "Main",
|
|
169
|
+
forkPoint: 0,
|
|
170
|
+
history: [createSnapshot(initialState, "Initial state")],
|
|
171
|
+
parentBranchId: null,
|
|
172
|
+
createdAt: Date.now(),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// =============================================================================
|
|
177
|
+
// Reducer
|
|
178
|
+
// =============================================================================
|
|
179
|
+
|
|
180
|
+
function reducer<T>(state: InternalState<T>, action: Action<T>): InternalState<T> {
|
|
181
|
+
const currentBranch = state.branches[state.currentBranchId];
|
|
182
|
+
if (!currentBranch) {
|
|
183
|
+
return state;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
switch (action.type) {
|
|
187
|
+
case "PUSH": {
|
|
188
|
+
const newSnapshot = createSnapshot(action.state, action.description);
|
|
189
|
+
|
|
190
|
+
// If we're not at the end, truncate future history
|
|
191
|
+
const truncatedHistory = currentBranch.history.slice(0, state.currentIndex + 1);
|
|
192
|
+
|
|
193
|
+
// Add new snapshot
|
|
194
|
+
let newHistory = [...truncatedHistory, newSnapshot];
|
|
195
|
+
|
|
196
|
+
// Enforce max history limit
|
|
197
|
+
if (newHistory.length > state.maxHistory) {
|
|
198
|
+
newHistory = newHistory.slice(newHistory.length - state.maxHistory);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const updatedBranch: Branch<T> = {
|
|
202
|
+
...currentBranch,
|
|
203
|
+
history: newHistory,
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
...state,
|
|
208
|
+
branches: {
|
|
209
|
+
...state.branches,
|
|
210
|
+
[state.currentBranchId]: updatedBranch,
|
|
211
|
+
},
|
|
212
|
+
currentIndex: newHistory.length - 1,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
case "UNDO": {
|
|
217
|
+
if (state.currentIndex <= 0) {
|
|
218
|
+
return state;
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
...state,
|
|
222
|
+
currentIndex: state.currentIndex - 1,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
case "REDO": {
|
|
227
|
+
if (state.currentIndex >= currentBranch.history.length - 1) {
|
|
228
|
+
return state;
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
...state,
|
|
232
|
+
currentIndex: state.currentIndex + 1,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
case "GO_TO": {
|
|
237
|
+
const targetIndex = Math.max(0, Math.min(action.index, currentBranch.history.length - 1));
|
|
238
|
+
if (targetIndex === state.currentIndex) {
|
|
239
|
+
return state;
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
...state,
|
|
243
|
+
currentIndex: targetIndex,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case "CREATE_BRANCH": {
|
|
248
|
+
const branchName = action.name ?? `Branch ${Object.keys(state.branches).length}`;
|
|
249
|
+
|
|
250
|
+
// Copy history up to current point
|
|
251
|
+
const forkedHistory = currentBranch.history.slice(0, state.currentIndex + 1);
|
|
252
|
+
|
|
253
|
+
const newBranch: Branch<T> = {
|
|
254
|
+
id: action.newBranchId,
|
|
255
|
+
name: branchName,
|
|
256
|
+
forkPoint: state.currentIndex,
|
|
257
|
+
history: forkedHistory,
|
|
258
|
+
parentBranchId: state.currentBranchId,
|
|
259
|
+
createdAt: Date.now(),
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
...state,
|
|
264
|
+
branches: {
|
|
265
|
+
...state.branches,
|
|
266
|
+
[action.newBranchId]: newBranch,
|
|
267
|
+
},
|
|
268
|
+
currentBranchId: action.newBranchId,
|
|
269
|
+
currentIndex: forkedHistory.length - 1,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
case "SWITCH_BRANCH": {
|
|
274
|
+
const targetBranch = state.branches[action.branchId];
|
|
275
|
+
if (!targetBranch) {
|
|
276
|
+
return state;
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
...state,
|
|
280
|
+
currentBranchId: action.branchId,
|
|
281
|
+
currentIndex: targetBranch.history.length - 1,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
case "RESET": {
|
|
286
|
+
const initialBranch = createInitialBranch(action.initialState);
|
|
287
|
+
return {
|
|
288
|
+
...state,
|
|
289
|
+
branches: { [MAIN_BRANCH_ID]: initialBranch },
|
|
290
|
+
currentBranchId: MAIN_BRANCH_ID,
|
|
291
|
+
currentIndex: 0,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// =============================================================================
|
|
298
|
+
// Hook Implementation
|
|
299
|
+
// =============================================================================
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Hook for managing conversation backtracking and branching.
|
|
303
|
+
*
|
|
304
|
+
* Provides undo/redo functionality with support for creating alternative
|
|
305
|
+
* conversation branches (forks) from any point in history.
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```tsx
|
|
309
|
+
* function ConversationView() {
|
|
310
|
+
* const {
|
|
311
|
+
* currentState,
|
|
312
|
+
* backtrackState,
|
|
313
|
+
* push,
|
|
314
|
+
* undo,
|
|
315
|
+
* redo,
|
|
316
|
+
* createBranch,
|
|
317
|
+
* } = useBacktrack({
|
|
318
|
+
* initialState: { messages: [] },
|
|
319
|
+
* });
|
|
320
|
+
*
|
|
321
|
+
* // Ctrl+Z to undo
|
|
322
|
+
* useHotkeys([
|
|
323
|
+
* { key: 'z', ctrl: true, handler: undo },
|
|
324
|
+
* { key: 'y', ctrl: true, handler: redo },
|
|
325
|
+
* { key: 'b', ctrl: true, handler: () => createBranch() },
|
|
326
|
+
* ]);
|
|
327
|
+
*
|
|
328
|
+
* return (
|
|
329
|
+
* <Box>
|
|
330
|
+
* <Text>Can Undo: {backtrackState.canUndo ? 'Yes' : 'No'}</Text>
|
|
331
|
+
* <Text>Branch: {backtrackState.currentBranch}</Text>
|
|
332
|
+
* </Box>
|
|
333
|
+
* );
|
|
334
|
+
* }
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
export function useBacktrack<T>(options: UseBacktrackOptions<T>): UseBacktrackReturn<T> {
|
|
338
|
+
const { initialState, maxHistory = DEFAULT_MAX_HISTORY, onStateChange } = options;
|
|
339
|
+
|
|
340
|
+
// Initialize state
|
|
341
|
+
const [state, dispatch] = useReducer(reducer<T>, {
|
|
342
|
+
branches: { [MAIN_BRANCH_ID]: createInitialBranch(initialState) },
|
|
343
|
+
currentBranchId: MAIN_BRANCH_ID,
|
|
344
|
+
currentIndex: 0,
|
|
345
|
+
maxHistory,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Get current branch and state
|
|
349
|
+
const currentBranch = state.branches[state.currentBranchId];
|
|
350
|
+
const currentSnapshot = currentBranch?.history[state.currentIndex];
|
|
351
|
+
const currentState = currentSnapshot?.state ?? initialState;
|
|
352
|
+
|
|
353
|
+
// Compute backtrack state
|
|
354
|
+
const backtrackState = useMemo<BacktrackState>(
|
|
355
|
+
() => ({
|
|
356
|
+
canUndo: state.currentIndex > 0,
|
|
357
|
+
canRedo: currentBranch ? state.currentIndex < currentBranch.history.length - 1 : false,
|
|
358
|
+
forkCount: Object.keys(state.branches).length - 1, // Exclude main branch
|
|
359
|
+
currentBranch: currentBranch?.name ?? "Main",
|
|
360
|
+
currentIndex: state.currentIndex,
|
|
361
|
+
historyLength: currentBranch?.history.length ?? 0,
|
|
362
|
+
}),
|
|
363
|
+
[state.currentIndex, currentBranch, state.branches]
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
// Get all branches as array
|
|
367
|
+
const branches = useMemo<ReadonlyArray<Branch<T>>>(
|
|
368
|
+
() => Object.values(state.branches) as ReadonlyArray<Branch<T>>,
|
|
369
|
+
[state.branches]
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// Action handlers
|
|
373
|
+
const push = useCallback(
|
|
374
|
+
(newState: T, description?: string) => {
|
|
375
|
+
dispatch({ type: "PUSH", state: newState, description });
|
|
376
|
+
onStateChange?.(newState, "push");
|
|
377
|
+
},
|
|
378
|
+
[onStateChange]
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
const undo = useCallback(() => {
|
|
382
|
+
if (state.currentIndex > 0) {
|
|
383
|
+
dispatch({ type: "UNDO" });
|
|
384
|
+
const prevState = currentBranch?.history[state.currentIndex - 1]?.state;
|
|
385
|
+
if (prevState) {
|
|
386
|
+
onStateChange?.(prevState, "undo");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}, [state.currentIndex, currentBranch?.history, onStateChange]);
|
|
390
|
+
|
|
391
|
+
const redo = useCallback(() => {
|
|
392
|
+
if (currentBranch && state.currentIndex < currentBranch.history.length - 1) {
|
|
393
|
+
dispatch({ type: "REDO" });
|
|
394
|
+
const nextState = currentBranch.history[state.currentIndex + 1]?.state;
|
|
395
|
+
if (nextState) {
|
|
396
|
+
onStateChange?.(nextState, "redo");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}, [state.currentIndex, currentBranch, onStateChange]);
|
|
400
|
+
|
|
401
|
+
const createBranch = useCallback(
|
|
402
|
+
(name?: string): string => {
|
|
403
|
+
const newBranchId = generateId();
|
|
404
|
+
dispatch({ type: "CREATE_BRANCH", name, newBranchId });
|
|
405
|
+
onStateChange?.(currentState, "branch");
|
|
406
|
+
return newBranchId;
|
|
407
|
+
},
|
|
408
|
+
[currentState, onStateChange]
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
const switchBranch = useCallback((branchId: string) => {
|
|
412
|
+
dispatch({ type: "SWITCH_BRANCH", branchId });
|
|
413
|
+
}, []);
|
|
414
|
+
|
|
415
|
+
const getBranch = useCallback(
|
|
416
|
+
(branchId: string): Branch<T> | undefined => {
|
|
417
|
+
return state.branches[branchId] as Branch<T> | undefined;
|
|
418
|
+
},
|
|
419
|
+
[state.branches]
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
const reset = useCallback(() => {
|
|
423
|
+
dispatch({ type: "RESET", initialState });
|
|
424
|
+
}, [initialState]);
|
|
425
|
+
|
|
426
|
+
const goTo = useCallback((index: number) => {
|
|
427
|
+
dispatch({ type: "GO_TO", index });
|
|
428
|
+
}, []);
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
currentState,
|
|
432
|
+
backtrackState,
|
|
433
|
+
branches,
|
|
434
|
+
push,
|
|
435
|
+
undo,
|
|
436
|
+
redo,
|
|
437
|
+
createBranch,
|
|
438
|
+
switchBranch,
|
|
439
|
+
getBranch,
|
|
440
|
+
reset,
|
|
441
|
+
goTo,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bracketed Paste Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook that enables bracketed paste mode when mounted and ensures
|
|
5
|
+
* proper cleanup on unmount or process exit.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/hooks/useBracketedPaste
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useEffect } from "react";
|
|
11
|
+
import { disableBracketedPaste, enableBracketedPaste } from "../utils/bracketedPaste.js";
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Types
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Options for the useBracketedPaste hook
|
|
19
|
+
*/
|
|
20
|
+
export interface UseBracketedPasteOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Whether bracketed paste mode should be enabled.
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
readonly enabled?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Hook
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Hook to manage bracketed paste mode lifecycle.
|
|
34
|
+
*
|
|
35
|
+
* Enables bracketed paste mode when the component mounts and disables it
|
|
36
|
+
* on unmount. Also handles process signals (SIGINT, SIGTERM) and beforeExit
|
|
37
|
+
* to ensure the terminal state is properly restored.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* function App() {
|
|
42
|
+
* // Enable bracketed paste for the entire app
|
|
43
|
+
* useBracketedPaste();
|
|
44
|
+
*
|
|
45
|
+
* return <MyComponents />;
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```tsx
|
|
51
|
+
* function ConditionalPaste() {
|
|
52
|
+
* const [pasteEnabled, setPasteEnabled] = useState(true);
|
|
53
|
+
*
|
|
54
|
+
* // Conditionally enable/disable
|
|
55
|
+
* useBracketedPaste({ enabled: pasteEnabled });
|
|
56
|
+
*
|
|
57
|
+
* return <MyComponents />;
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function useBracketedPaste(options: UseBracketedPasteOptions = {}): void {
|
|
62
|
+
const { enabled = true } = options;
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!enabled) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Enable bracketed paste mode
|
|
70
|
+
enableBracketedPaste();
|
|
71
|
+
|
|
72
|
+
// Cleanup function for graceful shutdown
|
|
73
|
+
const cleanup = () => {
|
|
74
|
+
disableBracketedPaste();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Handle various exit scenarios
|
|
78
|
+
const handleSignal = () => {
|
|
79
|
+
cleanup();
|
|
80
|
+
// Let the signal propagate
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const handleExit = () => {
|
|
84
|
+
cleanup();
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Register cleanup handlers
|
|
88
|
+
process.on("SIGINT", handleSignal);
|
|
89
|
+
process.on("SIGTERM", handleSignal);
|
|
90
|
+
process.on("beforeExit", handleExit);
|
|
91
|
+
process.on("exit", handleExit);
|
|
92
|
+
|
|
93
|
+
// Cleanup on unmount or when disabled
|
|
94
|
+
return () => {
|
|
95
|
+
cleanup();
|
|
96
|
+
|
|
97
|
+
// Remove event listeners
|
|
98
|
+
process.off("SIGINT", handleSignal);
|
|
99
|
+
process.off("SIGTERM", handleSignal);
|
|
100
|
+
process.off("beforeExit", handleExit);
|
|
101
|
+
process.off("exit", handleExit);
|
|
102
|
+
};
|
|
103
|
+
}, [enabled]);
|
|
104
|
+
}
|