@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,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DiffView Component Tests (T022)
|
|
3
|
+
*
|
|
4
|
+
* @module tui/components/Messages/__tests__/DiffView.test
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { render } from "ink-testing-library";
|
|
8
|
+
import { describe, expect, it } from "vitest";
|
|
9
|
+
import { ThemeProvider } from "../../../theme/index.js";
|
|
10
|
+
import { DiffView } from "../DiffView.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Wrap component with ThemeProvider for testing.
|
|
14
|
+
*/
|
|
15
|
+
function renderWithTheme(ui: React.ReactElement) {
|
|
16
|
+
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Sample unified diff for testing
|
|
20
|
+
const sampleDiff = `--- a/src/index.ts
|
|
21
|
+
+++ b/src/index.ts
|
|
22
|
+
@@ -1,5 +1,6 @@
|
|
23
|
+
import { foo } from './foo';
|
|
24
|
+
+import { bar } from './bar';
|
|
25
|
+
|
|
26
|
+
function main() {
|
|
27
|
+
- console.log('hello');
|
|
28
|
+
+ console.log('hello world');
|
|
29
|
+
}`;
|
|
30
|
+
|
|
31
|
+
const simpleAddition = `@@ -1,3 +1,4 @@
|
|
32
|
+
line 1
|
|
33
|
+
+new line
|
|
34
|
+
line 2
|
|
35
|
+
line 3`;
|
|
36
|
+
|
|
37
|
+
const simpleDeletion = `@@ -1,4 +1,3 @@
|
|
38
|
+
line 1
|
|
39
|
+
-deleted line
|
|
40
|
+
line 2
|
|
41
|
+
line 3`;
|
|
42
|
+
|
|
43
|
+
describe("DiffView", () => {
|
|
44
|
+
describe("basic rendering", () => {
|
|
45
|
+
it("renders diff content", () => {
|
|
46
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
47
|
+
|
|
48
|
+
expect(lastFrame()).toContain("foo");
|
|
49
|
+
expect(lastFrame()).toContain("main");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("renders empty diff", () => {
|
|
53
|
+
const { lastFrame } = renderWithTheme(<DiffView diff="" />);
|
|
54
|
+
|
|
55
|
+
// Should render borders at minimum
|
|
56
|
+
expect(lastFrame()).toBeTruthy();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("renders with borders", () => {
|
|
60
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
61
|
+
|
|
62
|
+
// Check for box-drawing characters (borders)
|
|
63
|
+
expect(lastFrame()).toMatch(/[─│┌┐└┘┬┴├┤┼╭╮╯╰]/);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("file header", () => {
|
|
68
|
+
it("displays custom fileName when provided", () => {
|
|
69
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} fileName="src/index.ts" />);
|
|
70
|
+
|
|
71
|
+
expect(lastFrame()).toContain("src/index.ts");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("shows file icon with fileName", () => {
|
|
75
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} fileName="test.ts" />);
|
|
76
|
+
|
|
77
|
+
expect(lastFrame()).toContain("📄");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("hides built-in diff headers when fileName provided", () => {
|
|
81
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} fileName="custom.ts" />);
|
|
82
|
+
|
|
83
|
+
// Should not show the original --- and +++ headers
|
|
84
|
+
expect(lastFrame()).not.toContain("---");
|
|
85
|
+
expect(lastFrame()).not.toContain("+++");
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("added lines", () => {
|
|
90
|
+
it("displays + prefix for added lines", () => {
|
|
91
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={simpleAddition} />);
|
|
92
|
+
|
|
93
|
+
expect(lastFrame()).toContain("+");
|
|
94
|
+
expect(lastFrame()).toContain("new line");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("renders added line content correctly", () => {
|
|
98
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
99
|
+
|
|
100
|
+
expect(lastFrame()).toContain("bar");
|
|
101
|
+
expect(lastFrame()).toContain("hello world");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("removed lines", () => {
|
|
106
|
+
it("displays - prefix for removed lines", () => {
|
|
107
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={simpleDeletion} />);
|
|
108
|
+
|
|
109
|
+
expect(lastFrame()).toContain("-");
|
|
110
|
+
expect(lastFrame()).toContain("deleted line");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("renders removed line content correctly", () => {
|
|
114
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
115
|
+
|
|
116
|
+
// The original line before modification
|
|
117
|
+
expect(lastFrame()).toContain("hello");
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("context lines", () => {
|
|
122
|
+
it("renders unchanged context lines", () => {
|
|
123
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
124
|
+
|
|
125
|
+
expect(lastFrame()).toContain("import { foo }");
|
|
126
|
+
expect(lastFrame()).toContain("function main");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("hunk headers", () => {
|
|
131
|
+
it("renders hunk headers", () => {
|
|
132
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
133
|
+
|
|
134
|
+
expect(lastFrame()).toContain("@@");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("line numbers", () => {
|
|
139
|
+
it("shows line numbers when enabled", () => {
|
|
140
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={simpleAddition} showLineNumbers />);
|
|
141
|
+
|
|
142
|
+
// Should show line numbers
|
|
143
|
+
expect(lastFrame()).toContain("1");
|
|
144
|
+
expect(lastFrame()).toContain("2");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("hides line numbers when disabled", () => {
|
|
148
|
+
const { lastFrame } = renderWithTheme(
|
|
149
|
+
<DiffView diff={simpleAddition} showLineNumbers={false} />
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Line numbers separator pattern should not appear in diff content area
|
|
153
|
+
// Context lines should just have the content
|
|
154
|
+
expect(lastFrame()).toContain("line 1");
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("compact mode", () => {
|
|
159
|
+
it("renders in compact mode without errors", () => {
|
|
160
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} compact />);
|
|
161
|
+
|
|
162
|
+
expect(lastFrame()).toContain("foo");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("reduces padding in compact mode", () => {
|
|
166
|
+
const normalRender = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
167
|
+
const compactRender = renderWithTheme(<DiffView diff={sampleDiff} compact />);
|
|
168
|
+
|
|
169
|
+
// Both should render successfully
|
|
170
|
+
expect(normalRender.lastFrame()).toBeTruthy();
|
|
171
|
+
expect(compactRender.lastFrame()).toBeTruthy();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe("unified diff format parsing", () => {
|
|
176
|
+
it("parses file headers correctly", () => {
|
|
177
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={sampleDiff} />);
|
|
178
|
+
|
|
179
|
+
// Without fileName prop, should show the original headers
|
|
180
|
+
expect(lastFrame()).toContain("---");
|
|
181
|
+
expect(lastFrame()).toContain("+++");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("handles multiple hunks", () => {
|
|
185
|
+
const multiHunkDiff = `@@ -1,3 +1,4 @@
|
|
186
|
+
first
|
|
187
|
+
+added first
|
|
188
|
+
second
|
|
189
|
+
@@ -10,3 +11,4 @@
|
|
190
|
+
tenth
|
|
191
|
+
+added tenth
|
|
192
|
+
eleventh`;
|
|
193
|
+
|
|
194
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={multiHunkDiff} />);
|
|
195
|
+
|
|
196
|
+
expect(lastFrame()).toContain("first");
|
|
197
|
+
expect(lastFrame()).toContain("tenth");
|
|
198
|
+
expect(lastFrame()).toContain("added first");
|
|
199
|
+
expect(lastFrame()).toContain("added tenth");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("handles diff with only additions", () => {
|
|
203
|
+
const additionsOnly = `@@ -0,0 +1,3 @@
|
|
204
|
+
+new file
|
|
205
|
+
+line 2
|
|
206
|
+
+line 3`;
|
|
207
|
+
|
|
208
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={additionsOnly} />);
|
|
209
|
+
|
|
210
|
+
expect(lastFrame()).toContain("new file");
|
|
211
|
+
expect(lastFrame()).toContain("line 2");
|
|
212
|
+
expect(lastFrame()).toContain("line 3");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("handles diff with only deletions", () => {
|
|
216
|
+
const deletionsOnly = `@@ -1,3 +0,0 @@
|
|
217
|
+
-deleted 1
|
|
218
|
+
-deleted 2
|
|
219
|
+
-deleted 3`;
|
|
220
|
+
|
|
221
|
+
const { lastFrame } = renderWithTheme(<DiffView diff={deletionsOnly} />);
|
|
222
|
+
|
|
223
|
+
expect(lastFrame()).toContain("deleted 1");
|
|
224
|
+
expect(lastFrame()).toContain("deleted 2");
|
|
225
|
+
expect(lastFrame()).toContain("deleted 3");
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("combined props", () => {
|
|
230
|
+
it("works with all props enabled", () => {
|
|
231
|
+
const { lastFrame } = renderWithTheme(
|
|
232
|
+
<DiffView diff={sampleDiff} fileName="src/index.ts" showLineNumbers compact />
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
expect(lastFrame()).toContain("src/index.ts");
|
|
236
|
+
expect(lastFrame()).toContain("foo");
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MarkdownRenderer Component Tests (T020)
|
|
3
|
+
*
|
|
4
|
+
* @module tui/components/Messages/__tests__/MarkdownRenderer.test
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { render } from "ink-testing-library";
|
|
8
|
+
import { describe, expect, it } from "vitest";
|
|
9
|
+
import { ThemeProvider } from "../../../theme/index.js";
|
|
10
|
+
import { MarkdownRenderer } from "../MarkdownRenderer.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Wrap component with ThemeProvider for testing.
|
|
14
|
+
*/
|
|
15
|
+
function renderWithTheme(ui: React.ReactElement) {
|
|
16
|
+
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("MarkdownRenderer", () => {
|
|
20
|
+
describe("headers", () => {
|
|
21
|
+
it("renders h1 headers with bold styling", () => {
|
|
22
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="# Hello World" />);
|
|
23
|
+
|
|
24
|
+
expect(lastFrame()).toContain("Hello World");
|
|
25
|
+
// Header should be present (visual prefix varies)
|
|
26
|
+
expect(lastFrame()).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("renders h2 headers", () => {
|
|
30
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="## Section Title" />);
|
|
31
|
+
|
|
32
|
+
expect(lastFrame()).toContain("Section Title");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("renders h3 headers", () => {
|
|
36
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="### Subsection" />);
|
|
37
|
+
|
|
38
|
+
expect(lastFrame()).toContain("Subsection");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("renders multiple header levels", () => {
|
|
42
|
+
const content = `# Main Title
|
|
43
|
+
## Section
|
|
44
|
+
### Subsection`;
|
|
45
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
46
|
+
|
|
47
|
+
expect(lastFrame()).toContain("Main Title");
|
|
48
|
+
expect(lastFrame()).toContain("Section");
|
|
49
|
+
expect(lastFrame()).toContain("Subsection");
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("bold text", () => {
|
|
54
|
+
it("renders **bold** text", () => {
|
|
55
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="This is **bold** text" />);
|
|
56
|
+
|
|
57
|
+
expect(lastFrame()).toContain("bold");
|
|
58
|
+
expect(lastFrame()).toContain("This is");
|
|
59
|
+
expect(lastFrame()).toContain("text");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("renders __bold__ text with underscores", () => {
|
|
63
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="This is __bold__ text" />);
|
|
64
|
+
|
|
65
|
+
expect(lastFrame()).toContain("bold");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("renders multiple bold sections", () => {
|
|
69
|
+
const { lastFrame } = renderWithTheme(
|
|
70
|
+
<MarkdownRenderer content="**First** and **second** bold" />
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(lastFrame()).toContain("First");
|
|
74
|
+
expect(lastFrame()).toContain("second");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("italic text", () => {
|
|
79
|
+
it("renders *italic* text with asterisk", () => {
|
|
80
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="This is *italic* text" />);
|
|
81
|
+
|
|
82
|
+
expect(lastFrame()).toContain("italic");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("renders _italic_ text with underscore", () => {
|
|
86
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="This is _italic_ text" />);
|
|
87
|
+
|
|
88
|
+
expect(lastFrame()).toContain("italic");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("inline code", () => {
|
|
93
|
+
it("renders `inline code` with backticks", () => {
|
|
94
|
+
const { lastFrame } = renderWithTheme(
|
|
95
|
+
<MarkdownRenderer content="Use `console.log()` for debugging" />
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(lastFrame()).toContain("console.log()");
|
|
99
|
+
expect(lastFrame()).toContain("Use");
|
|
100
|
+
expect(lastFrame()).toContain("debugging");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("renders multiple inline code sections", () => {
|
|
104
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="Compare `foo` and `bar`" />);
|
|
105
|
+
|
|
106
|
+
expect(lastFrame()).toContain("foo");
|
|
107
|
+
expect(lastFrame()).toContain("bar");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("code blocks", () => {
|
|
112
|
+
it("renders code blocks with triple backticks", () => {
|
|
113
|
+
const content = `Here is code:
|
|
114
|
+
\`\`\`
|
|
115
|
+
const x = 1;
|
|
116
|
+
\`\`\``;
|
|
117
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
118
|
+
|
|
119
|
+
expect(lastFrame()).toContain("const x = 1;");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("renders code blocks with language identifier", () => {
|
|
123
|
+
const content = `\`\`\`typescript
|
|
124
|
+
function hello(): void {
|
|
125
|
+
console.log("hi");
|
|
126
|
+
}
|
|
127
|
+
\`\`\``;
|
|
128
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
129
|
+
|
|
130
|
+
expect(lastFrame()).toContain("typescript");
|
|
131
|
+
expect(lastFrame()).toContain("function hello()");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("handles multiline code blocks", () => {
|
|
135
|
+
const content = `\`\`\`
|
|
136
|
+
line 1
|
|
137
|
+
line 2
|
|
138
|
+
line 3
|
|
139
|
+
\`\`\``;
|
|
140
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
141
|
+
|
|
142
|
+
expect(lastFrame()).toContain("line 1");
|
|
143
|
+
expect(lastFrame()).toContain("line 2");
|
|
144
|
+
expect(lastFrame()).toContain("line 3");
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe("lists", () => {
|
|
149
|
+
it("renders unordered lists with dash", () => {
|
|
150
|
+
const content = `- Item 1
|
|
151
|
+
- Item 2
|
|
152
|
+
- Item 3`;
|
|
153
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
154
|
+
|
|
155
|
+
expect(lastFrame()).toContain("Item 1");
|
|
156
|
+
expect(lastFrame()).toContain("Item 2");
|
|
157
|
+
expect(lastFrame()).toContain("Item 3");
|
|
158
|
+
expect(lastFrame()).toContain("•");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("renders unordered lists with asterisk", () => {
|
|
162
|
+
const content = `* First
|
|
163
|
+
* Second`;
|
|
164
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
165
|
+
|
|
166
|
+
expect(lastFrame()).toContain("First");
|
|
167
|
+
expect(lastFrame()).toContain("Second");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("renders ordered lists", () => {
|
|
171
|
+
const content = `1. First item
|
|
172
|
+
2. Second item
|
|
173
|
+
3. Third item`;
|
|
174
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
175
|
+
|
|
176
|
+
expect(lastFrame()).toContain("1.");
|
|
177
|
+
expect(lastFrame()).toContain("First item");
|
|
178
|
+
expect(lastFrame()).toContain("2.");
|
|
179
|
+
expect(lastFrame()).toContain("Second item");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("renders nested list items", () => {
|
|
183
|
+
const content = `- Parent
|
|
184
|
+
- Child`;
|
|
185
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
186
|
+
|
|
187
|
+
expect(lastFrame()).toContain("Parent");
|
|
188
|
+
expect(lastFrame()).toContain("Child");
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("links", () => {
|
|
193
|
+
it("renders links with text and URL", () => {
|
|
194
|
+
const { lastFrame } = renderWithTheme(
|
|
195
|
+
<MarkdownRenderer content="Visit [GitHub](https://github.com) for code" />
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
expect(lastFrame()).toContain("GitHub");
|
|
199
|
+
expect(lastFrame()).toContain("https://github.com");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("renders multiple links", () => {
|
|
203
|
+
const { lastFrame } = renderWithTheme(
|
|
204
|
+
<MarkdownRenderer content="[Link 1](url1) and [Link 2](url2)" />
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
expect(lastFrame()).toContain("Link 1");
|
|
208
|
+
expect(lastFrame()).toContain("Link 2");
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe("mixed content", () => {
|
|
213
|
+
it("renders complex markdown with multiple elements", () => {
|
|
214
|
+
const content = `# Title
|
|
215
|
+
|
|
216
|
+
This is **bold** and *italic* text with \`code\`.
|
|
217
|
+
|
|
218
|
+
## List Section
|
|
219
|
+
|
|
220
|
+
- Item with **bold**
|
|
221
|
+
- Item with \`code\`
|
|
222
|
+
|
|
223
|
+
\`\`\`javascript
|
|
224
|
+
const hello = "world";
|
|
225
|
+
\`\`\`
|
|
226
|
+
|
|
227
|
+
Check [docs](https://example.com)`;
|
|
228
|
+
|
|
229
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
230
|
+
|
|
231
|
+
expect(lastFrame()).toContain("Title");
|
|
232
|
+
expect(lastFrame()).toContain("bold");
|
|
233
|
+
expect(lastFrame()).toContain("italic");
|
|
234
|
+
expect(lastFrame()).toContain("code");
|
|
235
|
+
expect(lastFrame()).toContain("List Section");
|
|
236
|
+
expect(lastFrame()).toContain("•");
|
|
237
|
+
expect(lastFrame()).toContain("javascript");
|
|
238
|
+
expect(lastFrame()).toContain("hello");
|
|
239
|
+
expect(lastFrame()).toContain("docs");
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe("compact mode", () => {
|
|
244
|
+
it("renders with reduced spacing in compact mode", () => {
|
|
245
|
+
const content = `# Header
|
|
246
|
+
|
|
247
|
+
Paragraph 1
|
|
248
|
+
|
|
249
|
+
Paragraph 2`;
|
|
250
|
+
|
|
251
|
+
const { lastFrame: normalFrame } = renderWithTheme(
|
|
252
|
+
<MarkdownRenderer content={content} compact={false} />
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const { lastFrame: compactFrame } = renderWithTheme(
|
|
256
|
+
<MarkdownRenderer content={content} compact={true} />
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
// Both should contain content
|
|
260
|
+
expect(normalFrame()).toContain("Header");
|
|
261
|
+
expect(compactFrame()).toContain("Header");
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe("edge cases", () => {
|
|
266
|
+
it("handles empty content", () => {
|
|
267
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content="" />);
|
|
268
|
+
|
|
269
|
+
// Should not crash, may render empty
|
|
270
|
+
expect(lastFrame()).toBeDefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("handles content with only whitespace", () => {
|
|
274
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content=" \n \n " />);
|
|
275
|
+
|
|
276
|
+
expect(lastFrame()).toBeDefined();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("handles unclosed code blocks gracefully", () => {
|
|
280
|
+
const content = `\`\`\`
|
|
281
|
+
code without closing`;
|
|
282
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={content} />);
|
|
283
|
+
|
|
284
|
+
expect(lastFrame()).toContain("code without closing");
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it("handles special characters in content", () => {
|
|
288
|
+
const specialContent = "Special chars: < > &";
|
|
289
|
+
const { lastFrame } = renderWithTheme(<MarkdownRenderer content={specialContent} />);
|
|
290
|
+
|
|
291
|
+
expect(lastFrame()).toContain("Special chars");
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it("handles consecutive formatting", () => {
|
|
295
|
+
const { lastFrame } = renderWithTheme(
|
|
296
|
+
<MarkdownRenderer content="***bold italic*** should work" />
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// Verify component renders without crashing
|
|
300
|
+
expect(lastFrame()).toBeDefined();
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
});
|