@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,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox Configuration Defaults
|
|
3
|
+
*
|
|
4
|
+
* Centralized configuration constants for sandbox execution.
|
|
5
|
+
* All values can be overridden via function parameters or environment variables.
|
|
6
|
+
*
|
|
7
|
+
* @module cli/tui/config/defaults
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Environment Variable Helpers
|
|
12
|
+
// =============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse numeric environment variable with fallback.
|
|
16
|
+
*/
|
|
17
|
+
function parseEnvNumber(key: string, fallback: number): number {
|
|
18
|
+
const value = process.env[key];
|
|
19
|
+
if (value === undefined) return fallback;
|
|
20
|
+
const parsed = Number.parseInt(value, 10);
|
|
21
|
+
return Number.isNaN(parsed) ? fallback : parsed;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse boolean environment variable with fallback.
|
|
26
|
+
*/
|
|
27
|
+
function parseEnvBoolean(key: string, fallback: boolean): boolean {
|
|
28
|
+
const value = process.env[key];
|
|
29
|
+
if (value === undefined) return fallback;
|
|
30
|
+
return value === "true" || value === "1";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Size Constants (in bytes)
|
|
35
|
+
// =============================================================================
|
|
36
|
+
|
|
37
|
+
/** 1 Megabyte in bytes */
|
|
38
|
+
const MB = 1024 * 1024;
|
|
39
|
+
|
|
40
|
+
// =============================================================================
|
|
41
|
+
// Sandbox Resource Defaults
|
|
42
|
+
// =============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Default sandbox resource limits.
|
|
46
|
+
*/
|
|
47
|
+
export const SANDBOX_RESOURCES = {
|
|
48
|
+
/** Default execution timeout in milliseconds (30s) */
|
|
49
|
+
TIMEOUT_MS: parseEnvNumber("VELLUM_SANDBOX_TIMEOUT_MS", 30_000),
|
|
50
|
+
|
|
51
|
+
/** Additional wall time buffer beyond CPU timeout (5s) */
|
|
52
|
+
WALL_TIME_BUFFER_MS: parseEnvNumber("VELLUM_SANDBOX_WALL_TIME_BUFFER_MS", 5_000),
|
|
53
|
+
|
|
54
|
+
/** Maximum memory limit in bytes (512MB) */
|
|
55
|
+
MEMORY_BYTES: parseEnvNumber("VELLUM_SANDBOX_MEMORY_BYTES", 512 * MB),
|
|
56
|
+
|
|
57
|
+
/** Maximum output size in bytes (1MB) */
|
|
58
|
+
MAX_OUTPUT_BYTES: parseEnvNumber("VELLUM_SANDBOX_MAX_OUTPUT_BYTES", 1 * MB),
|
|
59
|
+
|
|
60
|
+
/** Maximum single file size in bytes (50MB) */
|
|
61
|
+
MAX_FILE_SIZE_BYTES: parseEnvNumber("VELLUM_SANDBOX_MAX_FILE_SIZE_BYTES", 50 * MB),
|
|
62
|
+
|
|
63
|
+
/** Maximum disk usage in bytes (100MB) */
|
|
64
|
+
MAX_DISK_USAGE_BYTES: parseEnvNumber("VELLUM_SANDBOX_MAX_DISK_USAGE_BYTES", 100 * MB),
|
|
65
|
+
|
|
66
|
+
/** Maximum number of file descriptors */
|
|
67
|
+
MAX_FILE_DESCRIPTORS: parseEnvNumber("VELLUM_SANDBOX_MAX_FILE_DESCRIPTORS", 100),
|
|
68
|
+
|
|
69
|
+
/** Maximum number of spawned processes */
|
|
70
|
+
MAX_PROCESSES: parseEnvNumber("VELLUM_SANDBOX_MAX_PROCESSES", 10),
|
|
71
|
+
} as const;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Default sandbox permission settings.
|
|
75
|
+
*/
|
|
76
|
+
export const SANDBOX_PERMISSIONS = {
|
|
77
|
+
/** Allow network access by default */
|
|
78
|
+
ALLOW_NETWORK: parseEnvBoolean("VELLUM_SANDBOX_ALLOW_NETWORK", false),
|
|
79
|
+
|
|
80
|
+
/** Allow file system access by default */
|
|
81
|
+
ALLOW_FILE_SYSTEM: parseEnvBoolean("VELLUM_SANDBOX_ALLOW_FILE_SYSTEM", true),
|
|
82
|
+
|
|
83
|
+
/** Use overlay filesystem */
|
|
84
|
+
USE_OVERLAY: parseEnvBoolean("VELLUM_SANDBOX_USE_OVERLAY", false),
|
|
85
|
+
|
|
86
|
+
/** Enable audit logging */
|
|
87
|
+
ENABLE_AUDIT: parseEnvBoolean("VELLUM_SANDBOX_ENABLE_AUDIT", false),
|
|
88
|
+
} as const;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Default security paths to deny access.
|
|
92
|
+
* These paths are blocked for security reasons.
|
|
93
|
+
*/
|
|
94
|
+
export const SANDBOX_DENIED_PATHS = ["/etc/passwd", "/etc/shadow"] as const;
|
|
95
|
+
|
|
96
|
+
// =============================================================================
|
|
97
|
+
// Aggregated Defaults
|
|
98
|
+
// =============================================================================
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Complete sandbox defaults configuration.
|
|
102
|
+
* Import and spread to apply all defaults with optional overrides.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* import { SANDBOX_DEFAULTS } from './config/defaults';
|
|
107
|
+
*
|
|
108
|
+
* const config = {
|
|
109
|
+
* ...SANDBOX_DEFAULTS.resources,
|
|
110
|
+
* timeoutMs: 60_000, // Override timeout
|
|
111
|
+
* };
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export const SANDBOX_DEFAULTS = {
|
|
115
|
+
/** Resource limits */
|
|
116
|
+
resources: SANDBOX_RESOURCES,
|
|
117
|
+
/** Permission settings */
|
|
118
|
+
permissions: SANDBOX_PERMISSIONS,
|
|
119
|
+
/** Denied filesystem paths */
|
|
120
|
+
deniedPaths: SANDBOX_DENIED_PATHS,
|
|
121
|
+
} as const;
|
|
122
|
+
|
|
123
|
+
// =============================================================================
|
|
124
|
+
// Type Exports
|
|
125
|
+
// =============================================================================
|
|
126
|
+
|
|
127
|
+
/** Type for sandbox resource configuration */
|
|
128
|
+
export type SandboxResourceConfig = typeof SANDBOX_RESOURCES;
|
|
129
|
+
|
|
130
|
+
/** Type for sandbox permission configuration */
|
|
131
|
+
export type SandboxPermissionConfig = typeof SANDBOX_PERMISSIONS;
|
|
132
|
+
|
|
133
|
+
/** Type for complete sandbox defaults */
|
|
134
|
+
export type SandboxDefaultsConfig = typeof SANDBOX_DEFAULTS;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI Configuration Module
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all configuration constants and types.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/tui/config
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
SANDBOX_DEFAULTS,
|
|
11
|
+
SANDBOX_DENIED_PATHS,
|
|
12
|
+
SANDBOX_PERMISSIONS,
|
|
13
|
+
SANDBOX_RESOURCES,
|
|
14
|
+
type SandboxDefaultsConfig,
|
|
15
|
+
type SandboxPermissionConfig,
|
|
16
|
+
type SandboxResourceConfig,
|
|
17
|
+
} from "./defaults.js";
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation Context
|
|
3
|
+
*
|
|
4
|
+
* Global animation context that provides:
|
|
5
|
+
* 1. A centralized animation frame counter
|
|
6
|
+
* 2. FPS limiting to prevent excessive re-renders (60 FPS max)
|
|
7
|
+
* 3. VS Code terminal detection for adaptive timing
|
|
8
|
+
*
|
|
9
|
+
* All animated components should subscribe to this instead of individual timers
|
|
10
|
+
* to reduce flickering and improve performance.
|
|
11
|
+
*
|
|
12
|
+
* @module tui/context/AnimationContext
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type React from "react";
|
|
16
|
+
import type { ReactNode } from "react";
|
|
17
|
+
import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
18
|
+
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Constants
|
|
21
|
+
// =============================================================================
|
|
22
|
+
|
|
23
|
+
/** Minimum frame interval (~60 FPS) to prevent excessive re-renders */
|
|
24
|
+
const MIN_FRAME_INTERVAL_MS = 16;
|
|
25
|
+
|
|
26
|
+
/** Base animation tick interval */
|
|
27
|
+
const BASE_ANIMATION_TICK_MS = 120;
|
|
28
|
+
|
|
29
|
+
/** Extended animation tick for VS Code terminal (more conservative) */
|
|
30
|
+
const VSCODE_ANIMATION_TICK_MS = 200;
|
|
31
|
+
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// Environment Detection
|
|
34
|
+
// =============================================================================
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Detects if running inside VS Code integrated terminal.
|
|
38
|
+
* VS Code terminals benefit from slightly longer intervals to reduce flickering.
|
|
39
|
+
*/
|
|
40
|
+
function isVSCodeTerminal(): boolean {
|
|
41
|
+
return (
|
|
42
|
+
process.env.TERM_PROGRAM === "vscode" ||
|
|
43
|
+
process.env.VSCODE_INJECTION === "1" ||
|
|
44
|
+
!!process.env.VSCODE_GIT_IPC_HANDLE
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Gets the optimal animation tick interval based on terminal environment.
|
|
50
|
+
* VS Code terminals use a longer interval to reduce flickering.
|
|
51
|
+
*/
|
|
52
|
+
function getAnimationTick(): number {
|
|
53
|
+
// Allow environment override for debugging
|
|
54
|
+
const envTick = Number(process.env.VELLUM_ANIMATION_TICK);
|
|
55
|
+
if (Number.isFinite(envTick) && envTick > 0) {
|
|
56
|
+
return envTick;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return isVSCodeTerminal() ? VSCODE_ANIMATION_TICK_MS : BASE_ANIMATION_TICK_MS;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// Types
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Animation context state
|
|
68
|
+
*/
|
|
69
|
+
export interface AnimationState {
|
|
70
|
+
/** Current animation frame counter (monotonically increasing) */
|
|
71
|
+
readonly frame: number;
|
|
72
|
+
/** Current timestamp in milliseconds */
|
|
73
|
+
readonly timestamp: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Animation context value
|
|
78
|
+
*/
|
|
79
|
+
export interface AnimationContextValue extends AnimationState {
|
|
80
|
+
/** Whether running in VS Code terminal */
|
|
81
|
+
readonly isVSCode: boolean;
|
|
82
|
+
/** Current animation tick interval in ms */
|
|
83
|
+
readonly tickInterval: number;
|
|
84
|
+
/** Whether animations are currently paused */
|
|
85
|
+
readonly isPaused: boolean;
|
|
86
|
+
/** Pause all animations (useful during text input to reduce flickering) */
|
|
87
|
+
readonly pauseAnimations: () => void;
|
|
88
|
+
/** Resume animations after pausing */
|
|
89
|
+
readonly resumeAnimations: () => void;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Props for the AnimationProvider component
|
|
94
|
+
*/
|
|
95
|
+
export interface AnimationProviderProps {
|
|
96
|
+
/** Children to render */
|
|
97
|
+
readonly children: ReactNode;
|
|
98
|
+
/** Override the animation tick interval (for testing) */
|
|
99
|
+
readonly tickInterval?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// =============================================================================
|
|
103
|
+
// Context
|
|
104
|
+
// =============================================================================
|
|
105
|
+
|
|
106
|
+
const initialState: AnimationContextValue = {
|
|
107
|
+
frame: 0,
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
isVSCode: isVSCodeTerminal(),
|
|
110
|
+
tickInterval: getAnimationTick(),
|
|
111
|
+
isPaused: false,
|
|
112
|
+
pauseAnimations: () => {},
|
|
113
|
+
resumeAnimations: () => {},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Animation context - provides global animation frame and timing
|
|
118
|
+
*/
|
|
119
|
+
export const AnimationContext = createContext<AnimationContextValue>(initialState);
|
|
120
|
+
|
|
121
|
+
// =============================================================================
|
|
122
|
+
// Provider Component
|
|
123
|
+
// =============================================================================
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Animation provider that manages a global animation loop.
|
|
127
|
+
*
|
|
128
|
+
* Features:
|
|
129
|
+
* - Single timer for all animated components
|
|
130
|
+
* - FPS limiting to prevent excessive renders
|
|
131
|
+
* - VS Code terminal detection for adaptive timing
|
|
132
|
+
* - Environment variable override for debugging
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```tsx
|
|
136
|
+
* // In root provider
|
|
137
|
+
* <AnimationProvider>
|
|
138
|
+
* <App />
|
|
139
|
+
* </AnimationProvider>
|
|
140
|
+
*
|
|
141
|
+
* // Override tick for testing
|
|
142
|
+
* <AnimationProvider tickInterval={200}>
|
|
143
|
+
* <SlowAnimatedComponent />
|
|
144
|
+
* </AnimationProvider>
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export function AnimationProvider({
|
|
148
|
+
children,
|
|
149
|
+
tickInterval: tickOverride,
|
|
150
|
+
}: AnimationProviderProps): React.JSX.Element {
|
|
151
|
+
const tickInterval = tickOverride ?? getAnimationTick();
|
|
152
|
+
const isVSCode = isVSCodeTerminal();
|
|
153
|
+
|
|
154
|
+
const [state, setState] = useState<AnimationState>({
|
|
155
|
+
frame: 0,
|
|
156
|
+
timestamp: Date.now(),
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const [isPaused, setIsPaused] = useState(false);
|
|
160
|
+
const isPausedRef = useRef(false);
|
|
161
|
+
const lastRenderRef = useRef(Date.now());
|
|
162
|
+
|
|
163
|
+
// Stable pause/resume callbacks
|
|
164
|
+
const pauseAnimations = useCallback(() => {
|
|
165
|
+
isPausedRef.current = true;
|
|
166
|
+
setIsPaused(true);
|
|
167
|
+
}, []);
|
|
168
|
+
|
|
169
|
+
const resumeAnimations = useCallback(() => {
|
|
170
|
+
isPausedRef.current = false;
|
|
171
|
+
setIsPaused(false);
|
|
172
|
+
}, []);
|
|
173
|
+
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
// Don't start timer when paused - completely stops animation overhead
|
|
176
|
+
if (isPaused) return;
|
|
177
|
+
|
|
178
|
+
let mounted = true;
|
|
179
|
+
|
|
180
|
+
const tick = () => {
|
|
181
|
+
if (!mounted) return;
|
|
182
|
+
|
|
183
|
+
const now = Date.now();
|
|
184
|
+
const sinceLastRender = now - lastRenderRef.current;
|
|
185
|
+
|
|
186
|
+
// FPS limiter: ensure minimum interval since last render
|
|
187
|
+
if (sinceLastRender >= MIN_FRAME_INTERVAL_MS) {
|
|
188
|
+
lastRenderRef.current = now;
|
|
189
|
+
setState((prev) => ({
|
|
190
|
+
frame: prev.frame + 1,
|
|
191
|
+
timestamp: now,
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// Use setInterval for consistent timing in terminal environments
|
|
197
|
+
// requestAnimationFrame is designed for visual rendering, not terminal output
|
|
198
|
+
const timer = setInterval(tick, tickInterval);
|
|
199
|
+
|
|
200
|
+
return () => {
|
|
201
|
+
mounted = false;
|
|
202
|
+
clearInterval(timer);
|
|
203
|
+
};
|
|
204
|
+
}, [tickInterval, isPaused]);
|
|
205
|
+
|
|
206
|
+
const contextValue: AnimationContextValue = {
|
|
207
|
+
...state,
|
|
208
|
+
isVSCode,
|
|
209
|
+
tickInterval,
|
|
210
|
+
isPaused,
|
|
211
|
+
pauseAnimations,
|
|
212
|
+
resumeAnimations,
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return <AnimationContext.Provider value={contextValue}>{children}</AnimationContext.Provider>;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// =============================================================================
|
|
219
|
+
// Hooks
|
|
220
|
+
// =============================================================================
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Hook to access the full animation context.
|
|
224
|
+
*
|
|
225
|
+
* Returns safe defaults if context is not available (e.g., when rendered
|
|
226
|
+
* outside AnimationProvider). This prevents "Rendered more hooks than
|
|
227
|
+
* during the previous render" errors.
|
|
228
|
+
*
|
|
229
|
+
* @returns Animation context value with frame, timestamp, and metadata
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```tsx
|
|
233
|
+
* function AnimatedComponent() {
|
|
234
|
+
* const { frame, timestamp, isVSCode } = useAnimation();
|
|
235
|
+
* // Use frame/timestamp for animations
|
|
236
|
+
* }
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
export function useAnimation(): AnimationContextValue {
|
|
240
|
+
const context = useContext(AnimationContext);
|
|
241
|
+
// Return safe defaults if context is not available
|
|
242
|
+
// This prevents hook count errors when rendered outside AnimationProvider
|
|
243
|
+
if (!context) {
|
|
244
|
+
return initialState;
|
|
245
|
+
}
|
|
246
|
+
return context;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Hook to get the current animation frame index for a set of frames.
|
|
251
|
+
*
|
|
252
|
+
* This is the recommended way to animate through a sequence of frames
|
|
253
|
+
* (like spinner characters) without managing your own state or timer.
|
|
254
|
+
*
|
|
255
|
+
* @param frames - Array of frames or number of total frames
|
|
256
|
+
* @returns Current frame index (0 to frames.length-1 or 0 to frames-1)
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```tsx
|
|
260
|
+
* // With array of frames
|
|
261
|
+
* const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
262
|
+
* function Spinner() {
|
|
263
|
+
* const frameIndex = useAnimationFrame(SPINNER_FRAMES);
|
|
264
|
+
* return <Text>{SPINNER_FRAMES[frameIndex]}</Text>;
|
|
265
|
+
* }
|
|
266
|
+
*
|
|
267
|
+
* // With frame count
|
|
268
|
+
* function FourPhaseAnimation() {
|
|
269
|
+
* const phase = useAnimationFrame(4);
|
|
270
|
+
* return <Text>Phase {phase + 1}</Text>;
|
|
271
|
+
* }
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
export function useAnimationFrame(frames: readonly unknown[] | number): number {
|
|
275
|
+
const { frame } = useAnimation();
|
|
276
|
+
const frameCount = typeof frames === "number" ? frames : frames.length;
|
|
277
|
+
return frameCount > 0 ? frame % frameCount : 0;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// =============================================================================
|
|
281
|
+
// Exports
|
|
282
|
+
// =============================================================================
|
|
283
|
+
|
|
284
|
+
export default AnimationProvider;
|