@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,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usePlaceholderRotation Hook
|
|
3
|
+
*
|
|
4
|
+
* Rotates through example placeholder texts to help users discover capabilities.
|
|
5
|
+
* Inspired by OpenCode's prompt-input pattern.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/hooks/usePlaceholderRotation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Types
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Options for the usePlaceholderRotation hook.
|
|
18
|
+
*/
|
|
19
|
+
export interface UsePlaceholderRotationOptions {
|
|
20
|
+
/** Rotation interval in milliseconds (default: 5000) */
|
|
21
|
+
readonly interval?: number;
|
|
22
|
+
/** Whether rotation is enabled (default: true) */
|
|
23
|
+
readonly enabled?: boolean;
|
|
24
|
+
/** Custom placeholder examples (uses defaults if not provided) */
|
|
25
|
+
readonly examples?: readonly string[];
|
|
26
|
+
/** Static placeholder to use when input has content */
|
|
27
|
+
readonly staticPlaceholder?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Return value of usePlaceholderRotation hook.
|
|
32
|
+
*/
|
|
33
|
+
export interface UsePlaceholderRotationReturn {
|
|
34
|
+
/** Current placeholder text to display */
|
|
35
|
+
readonly placeholder: string;
|
|
36
|
+
/** Index of current placeholder in examples array */
|
|
37
|
+
readonly currentIndex: number;
|
|
38
|
+
/** Manually advance to next placeholder */
|
|
39
|
+
readonly next: () => void;
|
|
40
|
+
/** Reset to first placeholder */
|
|
41
|
+
readonly reset: () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// Constants
|
|
46
|
+
// =============================================================================
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Default placeholder examples showcasing Vellum capabilities.
|
|
50
|
+
* Each demonstrates a different type of task users can request.
|
|
51
|
+
*/
|
|
52
|
+
export const DEFAULT_PLACEHOLDER_EXAMPLES: readonly string[] = [
|
|
53
|
+
"Implement a user authentication feature...",
|
|
54
|
+
"Fix the bug in the payment service...",
|
|
55
|
+
"Refactor this function to be more readable...",
|
|
56
|
+
"Add unit tests for the API endpoints...",
|
|
57
|
+
"Explain how this code works...",
|
|
58
|
+
"Create a React component for...",
|
|
59
|
+
"Optimize this database query...",
|
|
60
|
+
"Review this code for security issues...",
|
|
61
|
+
"Generate TypeScript types for this API...",
|
|
62
|
+
"Help me debug this error...",
|
|
63
|
+
] as const;
|
|
64
|
+
|
|
65
|
+
/** Default rotation interval: 5 seconds */
|
|
66
|
+
const DEFAULT_INTERVAL_MS = 5000;
|
|
67
|
+
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// Hook Implementation
|
|
70
|
+
// =============================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Hook that rotates through placeholder examples.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```tsx
|
|
77
|
+
* const { placeholder } = usePlaceholderRotation({
|
|
78
|
+
* interval: 5000,
|
|
79
|
+
* enabled: inputValue.length === 0,
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* return <TextInput placeholder={placeholder} />;
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export function usePlaceholderRotation({
|
|
86
|
+
interval = DEFAULT_INTERVAL_MS,
|
|
87
|
+
enabled = true,
|
|
88
|
+
examples = DEFAULT_PLACEHOLDER_EXAMPLES,
|
|
89
|
+
staticPlaceholder = "Type a message, /command, or @mention...",
|
|
90
|
+
}: UsePlaceholderRotationOptions = {}): UsePlaceholderRotationReturn {
|
|
91
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
92
|
+
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
|
93
|
+
|
|
94
|
+
// Memoize examples array to prevent unnecessary effect triggers
|
|
95
|
+
const memoizedExamples = useMemo(() => examples, [examples]);
|
|
96
|
+
|
|
97
|
+
// Cleanup interval on unmount or when dependencies change
|
|
98
|
+
const clearRotationInterval = useCallback(() => {
|
|
99
|
+
if (intervalRef.current !== null) {
|
|
100
|
+
clearInterval(intervalRef.current);
|
|
101
|
+
intervalRef.current = null;
|
|
102
|
+
}
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
// Advance to next placeholder
|
|
106
|
+
const next = useCallback(() => {
|
|
107
|
+
setCurrentIndex((prev) => (prev + 1) % memoizedExamples.length);
|
|
108
|
+
}, [memoizedExamples.length]);
|
|
109
|
+
|
|
110
|
+
// Reset to first placeholder
|
|
111
|
+
const reset = useCallback(() => {
|
|
112
|
+
setCurrentIndex(0);
|
|
113
|
+
}, []);
|
|
114
|
+
|
|
115
|
+
// Set up rotation interval
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!enabled || memoizedExamples.length <= 1) {
|
|
118
|
+
clearRotationInterval();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
intervalRef.current = setInterval(() => {
|
|
123
|
+
setCurrentIndex((prev) => (prev + 1) % memoizedExamples.length);
|
|
124
|
+
}, interval);
|
|
125
|
+
|
|
126
|
+
return clearRotationInterval;
|
|
127
|
+
}, [enabled, interval, memoizedExamples.length, clearRotationInterval]);
|
|
128
|
+
|
|
129
|
+
// Get current placeholder
|
|
130
|
+
const placeholder = useMemo(() => {
|
|
131
|
+
if (!enabled || memoizedExamples.length === 0) {
|
|
132
|
+
return staticPlaceholder;
|
|
133
|
+
}
|
|
134
|
+
return memoizedExamples[currentIndex] ?? staticPlaceholder;
|
|
135
|
+
}, [enabled, memoizedExamples, currentIndex, staticPlaceholder]);
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
placeholder,
|
|
139
|
+
currentIndex,
|
|
140
|
+
next,
|
|
141
|
+
reset,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useProviderStatus Hook
|
|
3
|
+
*
|
|
4
|
+
* Tracks provider status including circuit breaker states for the TUI.
|
|
5
|
+
* Provides real-time status updates for model status bar display.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/hooks/useProviderStatus
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useCallback, useEffect, useState } from "react";
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Types
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Circuit breaker state following standard pattern.
|
|
18
|
+
* - CLOSED: Normal operation, requests pass through
|
|
19
|
+
* - OPEN: Failure threshold exceeded, requests rejected
|
|
20
|
+
* - HALF_OPEN: Testing if service has recovered
|
|
21
|
+
*/
|
|
22
|
+
export type CircuitState = "CLOSED" | "OPEN" | "HALF_OPEN";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Individual provider status entry.
|
|
26
|
+
*/
|
|
27
|
+
export interface ProviderStatusEntry {
|
|
28
|
+
/** Provider identifier (e.g., 'anthropic', 'openai', 'google') */
|
|
29
|
+
readonly id: string;
|
|
30
|
+
/** Display name for the provider */
|
|
31
|
+
readonly name: string;
|
|
32
|
+
/** Current circuit breaker state */
|
|
33
|
+
readonly circuitState: CircuitState;
|
|
34
|
+
/** Whether this is the currently active provider */
|
|
35
|
+
readonly isActive: boolean;
|
|
36
|
+
/** Number of failures in current window */
|
|
37
|
+
readonly failureCount: number;
|
|
38
|
+
/** Time until circuit may reset (ms), 0 if not in OPEN state */
|
|
39
|
+
readonly timeUntilReset: number;
|
|
40
|
+
/** Last error message if any */
|
|
41
|
+
readonly lastError?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Return type for useProviderStatus hook.
|
|
46
|
+
*/
|
|
47
|
+
export interface UseProviderStatusReturn {
|
|
48
|
+
/** Array of all tracked provider statuses */
|
|
49
|
+
readonly providers: readonly ProviderStatusEntry[];
|
|
50
|
+
/** Currently active provider ID */
|
|
51
|
+
readonly activeProviderId: string | undefined;
|
|
52
|
+
/** Set the active provider */
|
|
53
|
+
readonly setActiveProvider: (providerId: string) => void;
|
|
54
|
+
/** Update a provider's circuit state */
|
|
55
|
+
readonly updateProviderState: (
|
|
56
|
+
providerId: string,
|
|
57
|
+
state: CircuitState,
|
|
58
|
+
failureCount?: number,
|
|
59
|
+
lastError?: string
|
|
60
|
+
) => void;
|
|
61
|
+
/** Register a new provider */
|
|
62
|
+
readonly registerProvider: (id: string, name: string) => void;
|
|
63
|
+
/** Unregister a provider */
|
|
64
|
+
readonly unregisterProvider: (id: string) => void;
|
|
65
|
+
/** Get status for a specific provider */
|
|
66
|
+
readonly getProviderStatus: (providerId: string) => ProviderStatusEntry | undefined;
|
|
67
|
+
/** Count of healthy (CLOSED state) providers */
|
|
68
|
+
readonly healthyCount: number;
|
|
69
|
+
/** Count of unhealthy (OPEN state) providers */
|
|
70
|
+
readonly unhealthyCount: number;
|
|
71
|
+
/** Count of half-open providers */
|
|
72
|
+
readonly halfOpenCount: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Options for useProviderStatus hook.
|
|
77
|
+
*/
|
|
78
|
+
export interface UseProviderStatusOptions {
|
|
79
|
+
/** Initial providers to track */
|
|
80
|
+
readonly initialProviders?: ReadonlyArray<{
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly isActive?: boolean;
|
|
84
|
+
}>;
|
|
85
|
+
/** Interval to update time-until-reset values (ms) */
|
|
86
|
+
readonly updateInterval?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// Constants
|
|
91
|
+
// =============================================================================
|
|
92
|
+
|
|
93
|
+
/** Default update interval for time-based state changes */
|
|
94
|
+
const DEFAULT_UPDATE_INTERVAL = 1000;
|
|
95
|
+
|
|
96
|
+
// =============================================================================
|
|
97
|
+
// Hook Implementation
|
|
98
|
+
// =============================================================================
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Hook for tracking provider status including circuit breaker states.
|
|
102
|
+
*
|
|
103
|
+
* @param options - Configuration options
|
|
104
|
+
* @returns Provider status state and actions
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* const { providers, activeProviderId, setActiveProvider } = useProviderStatus({
|
|
109
|
+
* initialProviders: [
|
|
110
|
+
* { id: 'anthropic', name: 'Claude', isActive: true },
|
|
111
|
+
* { id: 'openai', name: 'GPT-4' },
|
|
112
|
+
* { id: 'google', name: 'Gemini' },
|
|
113
|
+
* ],
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export function useProviderStatus(options: UseProviderStatusOptions = {}): UseProviderStatusReturn {
|
|
118
|
+
const { initialProviders = [], updateInterval = DEFAULT_UPDATE_INTERVAL } = options;
|
|
119
|
+
|
|
120
|
+
// State: Map of provider ID to status entry
|
|
121
|
+
const [providerMap, setProviderMap] = useState<Map<string, ProviderStatusEntry>>(() => {
|
|
122
|
+
const map = new Map<string, ProviderStatusEntry>();
|
|
123
|
+
for (const provider of initialProviders) {
|
|
124
|
+
map.set(provider.id, {
|
|
125
|
+
id: provider.id,
|
|
126
|
+
name: provider.name,
|
|
127
|
+
circuitState: "CLOSED",
|
|
128
|
+
isActive: provider.isActive ?? false,
|
|
129
|
+
failureCount: 0,
|
|
130
|
+
timeUntilReset: 0,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return map;
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Derived: Active provider ID
|
|
137
|
+
const activeProviderId = Array.from(providerMap.values()).find((p) => p.isActive)?.id;
|
|
138
|
+
|
|
139
|
+
// Set active provider
|
|
140
|
+
const setActiveProvider = useCallback((providerId: string) => {
|
|
141
|
+
setProviderMap((prev) => {
|
|
142
|
+
const next = new Map(prev);
|
|
143
|
+
for (const [id, entry] of next) {
|
|
144
|
+
next.set(id, {
|
|
145
|
+
...entry,
|
|
146
|
+
isActive: id === providerId,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return next;
|
|
150
|
+
});
|
|
151
|
+
}, []);
|
|
152
|
+
|
|
153
|
+
// Update provider circuit state
|
|
154
|
+
const updateProviderState = useCallback(
|
|
155
|
+
(providerId: string, state: CircuitState, failureCount?: number, lastError?: string) => {
|
|
156
|
+
setProviderMap((prev) => {
|
|
157
|
+
const entry = prev.get(providerId);
|
|
158
|
+
if (!entry) return prev;
|
|
159
|
+
|
|
160
|
+
const next = new Map(prev);
|
|
161
|
+
next.set(providerId, {
|
|
162
|
+
...entry,
|
|
163
|
+
circuitState: state,
|
|
164
|
+
failureCount: failureCount ?? entry.failureCount,
|
|
165
|
+
lastError: lastError ?? entry.lastError,
|
|
166
|
+
// Reset timeUntilReset based on state
|
|
167
|
+
timeUntilReset: state === "OPEN" ? 30000 : 0, // Default 30s reset timeout
|
|
168
|
+
});
|
|
169
|
+
return next;
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
[]
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// Register new provider
|
|
176
|
+
const registerProvider = useCallback((id: string, name: string) => {
|
|
177
|
+
setProviderMap((prev) => {
|
|
178
|
+
if (prev.has(id)) return prev;
|
|
179
|
+
|
|
180
|
+
const next = new Map(prev);
|
|
181
|
+
next.set(id, {
|
|
182
|
+
id,
|
|
183
|
+
name,
|
|
184
|
+
circuitState: "CLOSED",
|
|
185
|
+
isActive: next.size === 0, // First provider is active by default
|
|
186
|
+
failureCount: 0,
|
|
187
|
+
timeUntilReset: 0,
|
|
188
|
+
});
|
|
189
|
+
return next;
|
|
190
|
+
});
|
|
191
|
+
}, []);
|
|
192
|
+
|
|
193
|
+
// Unregister provider
|
|
194
|
+
const unregisterProvider = useCallback((id: string) => {
|
|
195
|
+
setProviderMap((prev) => {
|
|
196
|
+
if (!prev.has(id)) return prev;
|
|
197
|
+
|
|
198
|
+
const next = new Map(prev);
|
|
199
|
+
const wasActive = next.get(id)?.isActive;
|
|
200
|
+
next.delete(id);
|
|
201
|
+
|
|
202
|
+
// If removed provider was active, activate first remaining provider
|
|
203
|
+
if (wasActive && next.size > 0) {
|
|
204
|
+
const firstId = next.keys().next().value;
|
|
205
|
+
if (firstId !== undefined) {
|
|
206
|
+
const firstEntry = next.get(firstId);
|
|
207
|
+
if (firstEntry) {
|
|
208
|
+
next.set(firstId, { ...firstEntry, isActive: true });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return next;
|
|
214
|
+
});
|
|
215
|
+
}, []);
|
|
216
|
+
|
|
217
|
+
// Get status for specific provider
|
|
218
|
+
const getProviderStatus = useCallback(
|
|
219
|
+
(providerId: string): ProviderStatusEntry | undefined => {
|
|
220
|
+
return providerMap.get(providerId);
|
|
221
|
+
},
|
|
222
|
+
[providerMap]
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
// Timer to decrement timeUntilReset for OPEN circuits
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
const timer = setInterval(() => {
|
|
228
|
+
setProviderMap((prev) => {
|
|
229
|
+
let hasChanges = false;
|
|
230
|
+
const next = new Map(prev);
|
|
231
|
+
|
|
232
|
+
for (const [id, entry] of next) {
|
|
233
|
+
if (entry.circuitState === "OPEN" && entry.timeUntilReset > 0) {
|
|
234
|
+
hasChanges = true;
|
|
235
|
+
const newTime = Math.max(0, entry.timeUntilReset - updateInterval);
|
|
236
|
+
next.set(id, {
|
|
237
|
+
...entry,
|
|
238
|
+
timeUntilReset: newTime,
|
|
239
|
+
// Auto-transition to HALF_OPEN when timer expires
|
|
240
|
+
circuitState: newTime === 0 ? "HALF_OPEN" : "OPEN",
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return hasChanges ? next : prev;
|
|
246
|
+
});
|
|
247
|
+
}, updateInterval);
|
|
248
|
+
|
|
249
|
+
return () => clearInterval(timer);
|
|
250
|
+
}, [updateInterval]);
|
|
251
|
+
|
|
252
|
+
// Compute counts
|
|
253
|
+
const providers = Array.from(providerMap.values());
|
|
254
|
+
const healthyCount = providers.filter((p) => p.circuitState === "CLOSED").length;
|
|
255
|
+
const unhealthyCount = providers.filter((p) => p.circuitState === "OPEN").length;
|
|
256
|
+
const halfOpenCount = providers.filter((p) => p.circuitState === "HALF_OPEN").length;
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
providers,
|
|
260
|
+
activeProviderId,
|
|
261
|
+
setActiveProvider,
|
|
262
|
+
updateProviderState,
|
|
263
|
+
registerProvider,
|
|
264
|
+
unregisterProvider,
|
|
265
|
+
getProviderStatus,
|
|
266
|
+
healthyCount,
|
|
267
|
+
unhealthyCount,
|
|
268
|
+
halfOpenCount,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limit Status Hook
|
|
3
|
+
*
|
|
4
|
+
* Provides rate limit status information for API providers.
|
|
5
|
+
* Placeholder implementation - to be expanded.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/hooks/useRateLimitStatus
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useCallback, useEffect, useState } from "react";
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Types
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
export interface RateLimitStatus {
|
|
17
|
+
/** Whether currently rate limited */
|
|
18
|
+
isLimited: boolean;
|
|
19
|
+
/** Remaining requests in current window */
|
|
20
|
+
remaining?: number;
|
|
21
|
+
/** Total limit for the window */
|
|
22
|
+
limit?: number;
|
|
23
|
+
/** Time until limit resets (seconds) */
|
|
24
|
+
resetIn?: number;
|
|
25
|
+
/** Provider name */
|
|
26
|
+
provider?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface UseRateLimitStatusOptions {
|
|
30
|
+
/** Provider to track */
|
|
31
|
+
provider?: string;
|
|
32
|
+
/** Polling interval in ms */
|
|
33
|
+
pollInterval?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface UseRateLimitStatusResult {
|
|
37
|
+
/** Current rate limit status */
|
|
38
|
+
status: RateLimitStatus;
|
|
39
|
+
/** Whether data is loading */
|
|
40
|
+
isLoading: boolean;
|
|
41
|
+
/** Any error that occurred */
|
|
42
|
+
error: Error | null;
|
|
43
|
+
/** Refresh the status */
|
|
44
|
+
refresh: () => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// =============================================================================
|
|
48
|
+
// Hook
|
|
49
|
+
// =============================================================================
|
|
50
|
+
|
|
51
|
+
const defaultStatus: RateLimitStatus = {
|
|
52
|
+
isLimited: false,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Hook to track rate limit status
|
|
57
|
+
*/
|
|
58
|
+
export function useRateLimitStatus(
|
|
59
|
+
options: UseRateLimitStatusOptions = {}
|
|
60
|
+
): UseRateLimitStatusResult {
|
|
61
|
+
const { provider, pollInterval } = options;
|
|
62
|
+
const [status, setStatus] = useState<RateLimitStatus>(defaultStatus);
|
|
63
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
64
|
+
const [error, _setError] = useState<Error | null>(null);
|
|
65
|
+
|
|
66
|
+
const refresh = useCallback(() => {
|
|
67
|
+
setIsLoading(true);
|
|
68
|
+
// Placeholder: In real implementation, fetch status from provider
|
|
69
|
+
setStatus({ ...defaultStatus, provider });
|
|
70
|
+
setIsLoading(false);
|
|
71
|
+
}, [provider]);
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
refresh();
|
|
75
|
+
|
|
76
|
+
if (pollInterval && pollInterval > 0) {
|
|
77
|
+
const interval = setInterval(refresh, pollInterval);
|
|
78
|
+
return () => clearInterval(interval);
|
|
79
|
+
}
|
|
80
|
+
}, [pollInterval, refresh]);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
status,
|
|
84
|
+
isLoading,
|
|
85
|
+
error,
|
|
86
|
+
refresh,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default useRateLimitStatus;
|