@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,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output Assertions for CLI E2E Tests
|
|
3
|
+
*
|
|
4
|
+
* @module cli/test/e2e/assertions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { AssertionFailure, CLIResult, OutputMatcher } from "./types.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Assert CLI output against expected matchers
|
|
11
|
+
*/
|
|
12
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Assertion function needs to check multiple output conditions
|
|
13
|
+
export function assertOutput(result: CLIResult, expected: OutputMatcher): AssertionFailure[] {
|
|
14
|
+
const failures: AssertionFailure[] = [];
|
|
15
|
+
|
|
16
|
+
// Check exit code
|
|
17
|
+
if (expected.exitCode !== undefined && result.exitCode !== expected.exitCode) {
|
|
18
|
+
failures.push({
|
|
19
|
+
type: "exitCode",
|
|
20
|
+
expected: expected.exitCode,
|
|
21
|
+
actual: result.exitCode,
|
|
22
|
+
message: `Expected exit code ${expected.exitCode}, got ${result.exitCode}`,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check stdout
|
|
27
|
+
if (expected.stdout !== undefined) {
|
|
28
|
+
if (typeof expected.stdout === "string") {
|
|
29
|
+
if (!result.stdout.includes(expected.stdout)) {
|
|
30
|
+
failures.push({
|
|
31
|
+
type: "stdout",
|
|
32
|
+
expected: expected.stdout,
|
|
33
|
+
actual: result.stdout,
|
|
34
|
+
message: `stdout does not contain expected string: "${expected.stdout}"`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
} else if (!expected.stdout.test(result.stdout)) {
|
|
38
|
+
failures.push({
|
|
39
|
+
type: "stdout",
|
|
40
|
+
expected: expected.stdout.toString(),
|
|
41
|
+
actual: result.stdout,
|
|
42
|
+
message: `stdout does not match pattern: ${expected.stdout.toString()}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check stderr
|
|
48
|
+
if (expected.stderr !== undefined) {
|
|
49
|
+
if (typeof expected.stderr === "string") {
|
|
50
|
+
if (!result.stderr.includes(expected.stderr)) {
|
|
51
|
+
failures.push({
|
|
52
|
+
type: "stderr",
|
|
53
|
+
expected: expected.stderr,
|
|
54
|
+
actual: result.stderr,
|
|
55
|
+
message: `stderr does not contain expected string: "${expected.stderr}"`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
} else if (!expected.stderr.test(result.stderr)) {
|
|
59
|
+
failures.push({
|
|
60
|
+
type: "stderr",
|
|
61
|
+
expected: expected.stderr.toString(),
|
|
62
|
+
actual: result.stderr,
|
|
63
|
+
message: `stderr does not match pattern: ${expected.stderr.toString()}`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check contains (stdout + stderr combined)
|
|
69
|
+
if (expected.contains) {
|
|
70
|
+
const combined = result.stdout + result.stderr;
|
|
71
|
+
for (const text of expected.contains) {
|
|
72
|
+
if (!combined.includes(text)) {
|
|
73
|
+
failures.push({
|
|
74
|
+
type: "contains",
|
|
75
|
+
expected: text,
|
|
76
|
+
actual: combined,
|
|
77
|
+
message: `Output does not contain: "${text}"`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check excludes (stdout + stderr combined)
|
|
84
|
+
if (expected.excludes) {
|
|
85
|
+
const combined = result.stdout + result.stderr;
|
|
86
|
+
for (const text of expected.excludes) {
|
|
87
|
+
if (combined.includes(text)) {
|
|
88
|
+
failures.push({
|
|
89
|
+
type: "excludes",
|
|
90
|
+
expected: `not "${text}"`,
|
|
91
|
+
actual: combined,
|
|
92
|
+
message: `Output should NOT contain: "${text}"`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check timeout
|
|
99
|
+
if (result.timedOut) {
|
|
100
|
+
failures.push({
|
|
101
|
+
type: "timeout",
|
|
102
|
+
expected: "no timeout",
|
|
103
|
+
actual: "timed out",
|
|
104
|
+
message: `Process timed out after ${result.duration}ms`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return failures;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Assert that output contains a string
|
|
113
|
+
*/
|
|
114
|
+
export function assertContains(result: CLIResult, text: string): void {
|
|
115
|
+
const combined = result.stdout + result.stderr;
|
|
116
|
+
if (!combined.includes(text)) {
|
|
117
|
+
throw new Error(`Expected output to contain "${text}"\nActual:\n${combined}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Assert that output does not contain a string
|
|
123
|
+
*/
|
|
124
|
+
export function assertNotContains(result: CLIResult, text: string): void {
|
|
125
|
+
const combined = result.stdout + result.stderr;
|
|
126
|
+
if (combined.includes(text)) {
|
|
127
|
+
throw new Error(`Expected output NOT to contain "${text}"\nActual:\n${combined}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Assert stdout matches exactly
|
|
133
|
+
*/
|
|
134
|
+
export function assertStdout(result: CLIResult, expected: string | RegExp): void {
|
|
135
|
+
if (typeof expected === "string") {
|
|
136
|
+
if (result.stdout !== expected) {
|
|
137
|
+
throw new Error(`Expected stdout:\n${expected}\nActual:\n${result.stdout}`);
|
|
138
|
+
}
|
|
139
|
+
} else if (!expected.test(result.stdout)) {
|
|
140
|
+
throw new Error(`Expected stdout to match ${expected.toString()}\nActual:\n${result.stdout}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Assert stderr matches exactly
|
|
146
|
+
*/
|
|
147
|
+
export function assertStderr(result: CLIResult, expected: string | RegExp): void {
|
|
148
|
+
if (typeof expected === "string") {
|
|
149
|
+
if (result.stderr !== expected) {
|
|
150
|
+
throw new Error(`Expected stderr:\n${expected}\nActual:\n${result.stderr}`);
|
|
151
|
+
}
|
|
152
|
+
} else if (!expected.test(result.stderr)) {
|
|
153
|
+
throw new Error(`Expected stderr to match ${expected.toString()}\nActual:\n${result.stderr}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Assert exit code
|
|
159
|
+
*/
|
|
160
|
+
export function assertExitCode(result: CLIResult, expected: number): void {
|
|
161
|
+
if (result.exitCode !== expected) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Expected exit code ${expected}, got ${result.exitCode}\nstdout: ${result.stdout}\nstderr: ${result.stderr}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Assert process did not timeout
|
|
170
|
+
*/
|
|
171
|
+
export function assertNoTimeout(result: CLIResult): void {
|
|
172
|
+
if (result.timedOut) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`Process timed out after ${result.duration}ms\nstdout: ${result.stdout}\nstderr: ${result.stderr}`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Assert success (exit code 0, no timeout)
|
|
181
|
+
*/
|
|
182
|
+
export function assertSuccess(result: CLIResult): void {
|
|
183
|
+
assertNoTimeout(result);
|
|
184
|
+
assertExitCode(result, 0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Assert failure (non-zero exit code)
|
|
189
|
+
*/
|
|
190
|
+
export function assertFailure(result: CLIResult, expectedCode?: number): void {
|
|
191
|
+
assertNoTimeout(result);
|
|
192
|
+
if (expectedCode !== undefined) {
|
|
193
|
+
assertExitCode(result, expectedCode);
|
|
194
|
+
} else if (result.exitCode === 0) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Expected non-zero exit code, got 0\nstdout: ${result.stdout}\nstderr: ${result.stderr}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Assert output contains JSON
|
|
203
|
+
*/
|
|
204
|
+
export function assertJSON(result: CLIResult): unknown {
|
|
205
|
+
try {
|
|
206
|
+
return JSON.parse(result.stdout) as unknown;
|
|
207
|
+
} catch {
|
|
208
|
+
throw new Error(`Expected stdout to be valid JSON\nActual:\n${result.stdout}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Assert output contains lines in order
|
|
214
|
+
*/
|
|
215
|
+
export function assertLinesInOrder(result: CLIResult, lines: string[]): void {
|
|
216
|
+
const combined = result.stdout + result.stderr;
|
|
217
|
+
let lastIndex = -1;
|
|
218
|
+
|
|
219
|
+
for (const line of lines) {
|
|
220
|
+
const index = combined.indexOf(line, lastIndex + 1);
|
|
221
|
+
if (index === -1) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`Expected to find "${line}" after position ${lastIndex + 1}\nActual:\n${combined}`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
lastIndex = index;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Create matcher for use with vitest expect
|
|
232
|
+
*/
|
|
233
|
+
export const cliMatchers = {
|
|
234
|
+
toContainOutput(result: CLIResult, expected: string) {
|
|
235
|
+
const combined = result.stdout + result.stderr;
|
|
236
|
+
const pass = combined.includes(expected);
|
|
237
|
+
return {
|
|
238
|
+
pass,
|
|
239
|
+
message: () =>
|
|
240
|
+
pass
|
|
241
|
+
? `Expected output NOT to contain "${expected}"`
|
|
242
|
+
: `Expected output to contain "${expected}"\nActual:\n${combined}`,
|
|
243
|
+
};
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
toExitWith(result: CLIResult, expected: number) {
|
|
247
|
+
const pass = result.exitCode === expected;
|
|
248
|
+
return {
|
|
249
|
+
pass,
|
|
250
|
+
message: () =>
|
|
251
|
+
pass
|
|
252
|
+
? `Expected exit code NOT to be ${expected}`
|
|
253
|
+
: `Expected exit code ${expected}, got ${result.exitCode}`,
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
toSucceed(result: CLIResult) {
|
|
258
|
+
const pass = result.exitCode === 0 && !result.timedOut;
|
|
259
|
+
return {
|
|
260
|
+
pass,
|
|
261
|
+
message: () =>
|
|
262
|
+
pass
|
|
263
|
+
? `Expected command NOT to succeed`
|
|
264
|
+
: `Expected command to succeed\nexit code: ${result.exitCode}\ntimedOut: ${result.timedOut}\nstdout: ${result.stdout}\nstderr: ${result.stderr}`,
|
|
265
|
+
};
|
|
266
|
+
},
|
|
267
|
+
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Fixtures - Temporary Directory Management
|
|
3
|
+
*
|
|
4
|
+
* @module cli/test/e2e/fixtures
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Options for temp directory creation
|
|
13
|
+
*/
|
|
14
|
+
export interface TempDirOptions {
|
|
15
|
+
/** Prefix for temp directory name */
|
|
16
|
+
prefix?: string;
|
|
17
|
+
|
|
18
|
+
/** Initial files to create */
|
|
19
|
+
files?: Record<string, string>;
|
|
20
|
+
|
|
21
|
+
/** Cleanup on process exit */
|
|
22
|
+
autoCleanup?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Temporary directory manager
|
|
27
|
+
*/
|
|
28
|
+
export class TempDir {
|
|
29
|
+
private readonly path: string;
|
|
30
|
+
private cleaned = false;
|
|
31
|
+
|
|
32
|
+
private constructor(path: string) {
|
|
33
|
+
this.path = path;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the temp directory path
|
|
38
|
+
*/
|
|
39
|
+
get dir(): string {
|
|
40
|
+
return this.path;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Create a new temp directory
|
|
45
|
+
*/
|
|
46
|
+
static async create(options: TempDirOptions = {}): Promise<TempDir> {
|
|
47
|
+
const prefix = options.prefix ?? "vellum-e2e-";
|
|
48
|
+
const path = await mkdtemp(join(tmpdir(), prefix));
|
|
49
|
+
const tempDir = new TempDir(path);
|
|
50
|
+
|
|
51
|
+
// Create initial files
|
|
52
|
+
if (options.files) {
|
|
53
|
+
for (const [name, content] of Object.entries(options.files)) {
|
|
54
|
+
await tempDir.writeFile(name, content);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Register cleanup on exit
|
|
59
|
+
if (options.autoCleanup) {
|
|
60
|
+
process.on("exit", () => {
|
|
61
|
+
void tempDir.cleanup();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return tempDir;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Write a file to the temp directory
|
|
70
|
+
*/
|
|
71
|
+
async writeFile(relativePath: string, content: string): Promise<string> {
|
|
72
|
+
const fullPath = join(this.path, relativePath);
|
|
73
|
+
const dir = join(fullPath, "..");
|
|
74
|
+
await mkdir(dir, { recursive: true });
|
|
75
|
+
await writeFile(fullPath, content, "utf-8");
|
|
76
|
+
return fullPath;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Read a file from the temp directory
|
|
81
|
+
*/
|
|
82
|
+
async readFile(relativePath: string): Promise<string> {
|
|
83
|
+
const fullPath = join(this.path, relativePath);
|
|
84
|
+
return readFile(fullPath, "utf-8");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Check if a file exists
|
|
89
|
+
*/
|
|
90
|
+
async exists(relativePath: string): Promise<boolean> {
|
|
91
|
+
const fullPath = join(this.path, relativePath);
|
|
92
|
+
try {
|
|
93
|
+
await stat(fullPath);
|
|
94
|
+
return true;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Create a subdirectory
|
|
102
|
+
*/
|
|
103
|
+
async mkdir(relativePath: string): Promise<string> {
|
|
104
|
+
const fullPath = join(this.path, relativePath);
|
|
105
|
+
await mkdir(fullPath, { recursive: true });
|
|
106
|
+
return fullPath;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get full path for a relative path
|
|
111
|
+
*/
|
|
112
|
+
resolve(relativePath: string): string {
|
|
113
|
+
return join(this.path, relativePath);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Clean up the temp directory
|
|
118
|
+
*/
|
|
119
|
+
async cleanup(): Promise<void> {
|
|
120
|
+
if (this.cleaned) return;
|
|
121
|
+
this.cleaned = true;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
await rm(this.path, { recursive: true, force: true });
|
|
125
|
+
} catch {
|
|
126
|
+
// Ignore cleanup errors
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Fixture manager for managing multiple fixtures
|
|
133
|
+
*/
|
|
134
|
+
export class FixtureManager {
|
|
135
|
+
private readonly fixtures: TempDir[] = [];
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Create a new temp directory
|
|
139
|
+
*/
|
|
140
|
+
async createTempDir(options?: TempDirOptions): Promise<TempDir> {
|
|
141
|
+
const tempDir = await TempDir.create(options);
|
|
142
|
+
this.fixtures.push(tempDir);
|
|
143
|
+
return tempDir;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Clean up all managed fixtures
|
|
148
|
+
*/
|
|
149
|
+
async cleanup(): Promise<void> {
|
|
150
|
+
await Promise.all(this.fixtures.map((f) => f.cleanup()));
|
|
151
|
+
this.fixtures.length = 0;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create a fixture with a vellum project structure
|
|
157
|
+
*/
|
|
158
|
+
export async function createProjectFixture(): Promise<TempDir> {
|
|
159
|
+
return TempDir.create({
|
|
160
|
+
prefix: "vellum-project-",
|
|
161
|
+
files: {
|
|
162
|
+
"package.json": JSON.stringify(
|
|
163
|
+
{
|
|
164
|
+
name: "test-project",
|
|
165
|
+
version: "1.0.0",
|
|
166
|
+
type: "module",
|
|
167
|
+
},
|
|
168
|
+
null,
|
|
169
|
+
2
|
|
170
|
+
),
|
|
171
|
+
".vellum/config.json": JSON.stringify(
|
|
172
|
+
{
|
|
173
|
+
version: "1.0",
|
|
174
|
+
},
|
|
175
|
+
null,
|
|
176
|
+
2
|
|
177
|
+
),
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Create fixture with git repository
|
|
184
|
+
*/
|
|
185
|
+
export async function createGitFixture(): Promise<TempDir> {
|
|
186
|
+
const tempDir = await createProjectFixture();
|
|
187
|
+
await tempDir.mkdir(".git");
|
|
188
|
+
await tempDir.writeFile(".git/config", "[core]\n\trepositoryformatversion = 0\n");
|
|
189
|
+
await tempDir.writeFile(".git/HEAD", "ref: refs/heads/main\n");
|
|
190
|
+
return tempDir;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Vitest-compatible fixture helpers
|
|
195
|
+
*/
|
|
196
|
+
export function useFixtures() {
|
|
197
|
+
const manager = new FixtureManager();
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
manager,
|
|
201
|
+
createTempDir: (options?: TempDirOptions) => manager.createTempDir(options),
|
|
202
|
+
cleanup: () => manager.cleanup(),
|
|
203
|
+
};
|
|
204
|
+
}
|