@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 @@
|
|
|
1
|
+
# Placeholder to track empty directory in Git
|
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agents Command Group Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for the agents command group (T042, T047):
|
|
5
|
+
* - Command registration and help display
|
|
6
|
+
* - Subcommand routing
|
|
7
|
+
* - Options parsing
|
|
8
|
+
* - Integration tests with temp directories
|
|
9
|
+
*
|
|
10
|
+
* @module cli/commands/__tests__/agents
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { readFile } from "node:fs/promises";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
|
|
18
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
19
|
+
import { handleAgentsGenerate } from "../agents/generate.js";
|
|
20
|
+
import { agentsCommand, executeAgents, getAgentsHelp } from "../agents/index.js";
|
|
21
|
+
import { handleAgentsShow } from "../agents/show.js";
|
|
22
|
+
import { handleAgentsValidate } from "../agents/validate.js";
|
|
23
|
+
import type { CommandContext, ParsedArgs } from "../types.js";
|
|
24
|
+
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Test Fixtures
|
|
27
|
+
// =============================================================================
|
|
28
|
+
|
|
29
|
+
const TEST_DIR = join(tmpdir(), "vellum-agents-test");
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Valid AGENTS.md content for testing
|
|
33
|
+
*/
|
|
34
|
+
const VALID_AGENTS_MD = `---
|
|
35
|
+
name: "test-project"
|
|
36
|
+
version: "1.0.0"
|
|
37
|
+
description: "Test project for agents command"
|
|
38
|
+
priority: 100
|
|
39
|
+
merge:
|
|
40
|
+
strategy: extend
|
|
41
|
+
arrays: append
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# Instructions
|
|
45
|
+
|
|
46
|
+
You are an AI coding assistant.
|
|
47
|
+
|
|
48
|
+
## Allowed Tools
|
|
49
|
+
|
|
50
|
+
allowed-tools:
|
|
51
|
+
- "@readonly"
|
|
52
|
+
- "@edit"
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Invalid AGENTS.md content for testing (malformed YAML)
|
|
57
|
+
*/
|
|
58
|
+
const INVALID_AGENTS_MD = `---
|
|
59
|
+
name: test-project
|
|
60
|
+
version: "1.0.0
|
|
61
|
+
missing end quote and bad indent
|
|
62
|
+
- this will break
|
|
63
|
+
priority: [invalid yaml
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
# Instructions
|
|
67
|
+
|
|
68
|
+
This file has malformed YAML frontmatter.
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create a mock CommandContext for testing
|
|
73
|
+
*/
|
|
74
|
+
function createMockContext(overrides: Partial<ParsedArgs> = {}): CommandContext {
|
|
75
|
+
return {
|
|
76
|
+
session: {
|
|
77
|
+
id: "test-session",
|
|
78
|
+
provider: "anthropic",
|
|
79
|
+
cwd: TEST_DIR,
|
|
80
|
+
},
|
|
81
|
+
credentials: {
|
|
82
|
+
resolve: vi.fn(),
|
|
83
|
+
store: vi.fn(),
|
|
84
|
+
delete: vi.fn(),
|
|
85
|
+
list: vi.fn(),
|
|
86
|
+
} as unknown as CommandContext["credentials"],
|
|
87
|
+
toolRegistry: {
|
|
88
|
+
get: vi.fn(),
|
|
89
|
+
list: vi.fn(),
|
|
90
|
+
} as unknown as CommandContext["toolRegistry"],
|
|
91
|
+
parsedArgs: {
|
|
92
|
+
command: overrides.command ?? "agents",
|
|
93
|
+
positional: overrides.positional ?? [],
|
|
94
|
+
named: overrides.named ?? {},
|
|
95
|
+
raw: overrides.raw ?? "/agents",
|
|
96
|
+
},
|
|
97
|
+
emit: vi.fn(),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// =============================================================================
|
|
102
|
+
// Setup/Teardown for Integration Tests
|
|
103
|
+
// =============================================================================
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
// Create temp directory
|
|
107
|
+
if (!existsSync(TEST_DIR)) {
|
|
108
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
// Change to test directory for tests
|
|
111
|
+
vi.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
afterEach(() => {
|
|
115
|
+
// Clean up temp directory
|
|
116
|
+
if (existsSync(TEST_DIR)) {
|
|
117
|
+
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
118
|
+
}
|
|
119
|
+
vi.restoreAllMocks();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// =============================================================================
|
|
123
|
+
// T042: Agents Command Group Tests
|
|
124
|
+
// =============================================================================
|
|
125
|
+
|
|
126
|
+
describe("agentsCommand", () => {
|
|
127
|
+
describe("command definition", () => {
|
|
128
|
+
it("should have correct name and aliases", () => {
|
|
129
|
+
expect(agentsCommand.name).toBe("agents");
|
|
130
|
+
expect(agentsCommand.aliases).toContain("agent");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should be a builtin config command", () => {
|
|
134
|
+
expect(agentsCommand.kind).toBe("builtin");
|
|
135
|
+
expect(agentsCommand.category).toBe("config");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should define subcommand positional argument", () => {
|
|
139
|
+
const subArg = agentsCommand.positionalArgs?.find((a) => a.name === "subcommand");
|
|
140
|
+
expect(subArg).toBeDefined();
|
|
141
|
+
expect(subArg?.required).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should define named arguments for options", () => {
|
|
145
|
+
const namedArgs = agentsCommand.namedArgs ?? [];
|
|
146
|
+
expect(namedArgs.some((a) => a.name === "json")).toBe(true);
|
|
147
|
+
expect(namedArgs.some((a) => a.name === "verbose")).toBe(true);
|
|
148
|
+
expect(namedArgs.some((a) => a.name === "scope")).toBe(true);
|
|
149
|
+
expect(namedArgs.some((a) => a.name === "output")).toBe(true);
|
|
150
|
+
expect(namedArgs.some((a) => a.name === "merge")).toBe(true);
|
|
151
|
+
expect(namedArgs.some((a) => a.name === "dry-run")).toBe(true);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should have examples", () => {
|
|
155
|
+
expect(agentsCommand.examples).toBeDefined();
|
|
156
|
+
expect(agentsCommand.examples?.length).toBeGreaterThan(0);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("getAgentsHelp", () => {
|
|
162
|
+
it("should return help text with subcommands", () => {
|
|
163
|
+
const help = getAgentsHelp();
|
|
164
|
+
|
|
165
|
+
expect(help).toContain("Agents Commands");
|
|
166
|
+
expect(help).toContain("show");
|
|
167
|
+
expect(help).toContain("validate");
|
|
168
|
+
expect(help).toContain("generate");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("should include usage examples", () => {
|
|
172
|
+
const help = getAgentsHelp();
|
|
173
|
+
|
|
174
|
+
expect(help).toContain("/agents show");
|
|
175
|
+
expect(help).toContain("/agents validate");
|
|
176
|
+
expect(help).toContain("/agents generate");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("should reference init command", () => {
|
|
180
|
+
const help = getAgentsHelp();
|
|
181
|
+
expect(help).toContain("/init");
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe("executeAgents", () => {
|
|
186
|
+
describe("help (no subcommand)", () => {
|
|
187
|
+
it("should return help text when no subcommand provided", async () => {
|
|
188
|
+
const ctx = createMockContext({ positional: [] });
|
|
189
|
+
const result = await executeAgents(ctx);
|
|
190
|
+
|
|
191
|
+
expect(result.kind).toBe("success");
|
|
192
|
+
if (result.kind === "success") {
|
|
193
|
+
expect(result.message).toContain("Agents Commands");
|
|
194
|
+
expect(result.message).toContain("show");
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("should return help for unknown subcommand", async () => {
|
|
199
|
+
const ctx = createMockContext({ positional: ["unknown"] });
|
|
200
|
+
const result = await executeAgents(ctx);
|
|
201
|
+
|
|
202
|
+
expect(result.kind).toBe("success");
|
|
203
|
+
if (result.kind === "success") {
|
|
204
|
+
expect(result.message).toContain("Agents Commands");
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe("show subcommand", () => {
|
|
210
|
+
it("should route to show handler", async () => {
|
|
211
|
+
const ctx = createMockContext({ positional: ["show"] });
|
|
212
|
+
const result = await executeAgents(ctx);
|
|
213
|
+
|
|
214
|
+
// Command is now implemented - returns success with config or "no config found" message
|
|
215
|
+
expect(result.kind).toBe("success");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should parse show options", async () => {
|
|
219
|
+
const ctx = createMockContext({
|
|
220
|
+
positional: ["show"],
|
|
221
|
+
named: { json: true, verbose: true },
|
|
222
|
+
});
|
|
223
|
+
const result = await executeAgents(ctx);
|
|
224
|
+
|
|
225
|
+
// With --json flag, should return JSON output
|
|
226
|
+
expect(result.kind).toBe("success");
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("validate subcommand", () => {
|
|
231
|
+
it("should route to validate handler", async () => {
|
|
232
|
+
const ctx = createMockContext({ positional: ["validate"] });
|
|
233
|
+
const result = await executeAgents(ctx);
|
|
234
|
+
|
|
235
|
+
// Validate returns success if no invalid files found (or no files at all)
|
|
236
|
+
expect(["success", "error"]).toContain(result.kind);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("should accept file path argument", async () => {
|
|
240
|
+
const ctx = createMockContext({
|
|
241
|
+
positional: ["validate", "./AGENTS.md"],
|
|
242
|
+
});
|
|
243
|
+
const result = await executeAgents(ctx);
|
|
244
|
+
|
|
245
|
+
// Validate with specific file - may succeed or error depending on file existence
|
|
246
|
+
expect(["success", "error"]).toContain(result.kind);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
describe("generate subcommand", () => {
|
|
251
|
+
it("should route to generate handler", async () => {
|
|
252
|
+
const ctx = createMockContext({ positional: ["generate"] });
|
|
253
|
+
const result = await executeAgents(ctx);
|
|
254
|
+
|
|
255
|
+
// Generate may fail if AGENTS.md already exists, or succeed with dry-run
|
|
256
|
+
expect(["success", "error"]).toContain(result.kind);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("should parse generate options", async () => {
|
|
260
|
+
const ctx = createMockContext({
|
|
261
|
+
positional: ["generate"],
|
|
262
|
+
named: { output: "./AGENTS.md", merge: true, "dry-run": true },
|
|
263
|
+
});
|
|
264
|
+
const result = await executeAgents(ctx);
|
|
265
|
+
|
|
266
|
+
// With --dry-run, should succeed with preview output
|
|
267
|
+
expect(result.kind).toBe("success");
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe("case insensitivity", () => {
|
|
272
|
+
it("should handle uppercase subcommands", async () => {
|
|
273
|
+
const ctx = createMockContext({ positional: ["SHOW"] });
|
|
274
|
+
const result = await executeAgents(ctx);
|
|
275
|
+
|
|
276
|
+
// Should route correctly regardless of case
|
|
277
|
+
expect(result.kind).toBe("success");
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it("should handle mixed case subcommands", async () => {
|
|
281
|
+
const ctx = createMockContext({ positional: ["Validate"] });
|
|
282
|
+
const result = await executeAgents(ctx);
|
|
283
|
+
|
|
284
|
+
// Should route correctly regardless of case
|
|
285
|
+
expect(["success", "error"]).toContain(result.kind);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// =============================================================================
|
|
291
|
+
// T047: Integration Tests - agents show
|
|
292
|
+
// =============================================================================
|
|
293
|
+
|
|
294
|
+
describe("agents show integration", () => {
|
|
295
|
+
describe("with valid AGENTS.md", () => {
|
|
296
|
+
beforeEach(() => {
|
|
297
|
+
writeFileSync(join(TEST_DIR, "AGENTS.md"), VALID_AGENTS_MD);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("should display config correctly", async () => {
|
|
301
|
+
const result = await handleAgentsShow({});
|
|
302
|
+
|
|
303
|
+
expect(result.kind).toBe("success");
|
|
304
|
+
if (result.kind === "success") {
|
|
305
|
+
expect(result.message).toContain("test-project");
|
|
306
|
+
expect(result.message).toContain("Instructions");
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("should output valid JSON with --json flag", async () => {
|
|
311
|
+
const result = await handleAgentsShow({ json: true });
|
|
312
|
+
|
|
313
|
+
expect(result.kind).toBe("success");
|
|
314
|
+
if (result.kind === "success" && result.message) {
|
|
315
|
+
// Parse JSON to verify it's valid
|
|
316
|
+
const jsonData = JSON.parse(result.message);
|
|
317
|
+
expect(jsonData.success).toBe(true);
|
|
318
|
+
expect(jsonData.config).toBeDefined();
|
|
319
|
+
expect(jsonData.config.name).toBe("test-project");
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("should show verbose details with --verbose flag", async () => {
|
|
324
|
+
const result = await handleAgentsShow({ verbose: true });
|
|
325
|
+
|
|
326
|
+
expect(result.kind).toBe("success");
|
|
327
|
+
if (result.kind === "success") {
|
|
328
|
+
expect(result.message).toContain("Merge Configuration");
|
|
329
|
+
expect(result.message).toContain("Strategy");
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
describe("without AGENTS.md", () => {
|
|
335
|
+
it("should indicate no config found", async () => {
|
|
336
|
+
const result = await handleAgentsShow({});
|
|
337
|
+
|
|
338
|
+
expect(result.kind).toBe("success");
|
|
339
|
+
if (result.kind === "success") {
|
|
340
|
+
expect(result.message).toContain("No AGENTS.md");
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("should return valid JSON indicating no config", async () => {
|
|
345
|
+
const result = await handleAgentsShow({ json: true });
|
|
346
|
+
|
|
347
|
+
expect(result.kind).toBe("success");
|
|
348
|
+
if (result.kind === "success" && result.message) {
|
|
349
|
+
const jsonData = JSON.parse(result.message);
|
|
350
|
+
expect(jsonData.success).toBe(false);
|
|
351
|
+
expect(jsonData.config).toBeNull();
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// =============================================================================
|
|
358
|
+
// T047: Integration Tests - agents validate
|
|
359
|
+
// =============================================================================
|
|
360
|
+
|
|
361
|
+
describe("agents validate integration", () => {
|
|
362
|
+
describe("with valid AGENTS.md", () => {
|
|
363
|
+
beforeEach(() => {
|
|
364
|
+
writeFileSync(join(TEST_DIR, "AGENTS.md"), VALID_AGENTS_MD);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it("should return exit code 0 (success) for valid files", async () => {
|
|
368
|
+
// Validate specific file to avoid discovery of other files
|
|
369
|
+
const result = await handleAgentsValidate({
|
|
370
|
+
file: join(TEST_DIR, "AGENTS.md"),
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
expect(result.kind).toBe("success");
|
|
374
|
+
if (result.kind === "success") {
|
|
375
|
+
expect(result.message).toContain("Valid");
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it("should validate specific file path", async () => {
|
|
380
|
+
const result = await handleAgentsValidate({
|
|
381
|
+
file: join(TEST_DIR, "AGENTS.md"),
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
expect(result.kind).toBe("success");
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it("should return valid JSON for valid files", async () => {
|
|
388
|
+
// Validate specific file for consistent count
|
|
389
|
+
const result = await handleAgentsValidate({
|
|
390
|
+
file: join(TEST_DIR, "AGENTS.md"),
|
|
391
|
+
json: true,
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
expect(result.kind).toBe("success");
|
|
395
|
+
if (result.kind === "success" && result.message) {
|
|
396
|
+
const jsonData = JSON.parse(result.message);
|
|
397
|
+
expect(jsonData.success).toBe(true);
|
|
398
|
+
expect(jsonData.valid).toBe(1);
|
|
399
|
+
expect(jsonData.invalid).toBe(0);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
describe("with invalid AGENTS.md", () => {
|
|
405
|
+
beforeEach(() => {
|
|
406
|
+
writeFileSync(join(TEST_DIR, "AGENTS.md"), INVALID_AGENTS_MD);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("should return exit code 1 (error) for invalid files", async () => {
|
|
410
|
+
// Validate specific file to ensure we test the invalid one
|
|
411
|
+
const result = await handleAgentsValidate({
|
|
412
|
+
file: join(TEST_DIR, "AGENTS.md"),
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
expect(result.kind).toBe("error");
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it("should include error details in output", async () => {
|
|
419
|
+
const result = await handleAgentsValidate({
|
|
420
|
+
file: join(TEST_DIR, "AGENTS.md"),
|
|
421
|
+
verbose: true,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
expect(result.kind).toBe("error");
|
|
425
|
+
if (result.kind === "error") {
|
|
426
|
+
expect(result.message).toContain("Invalid");
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("should return JSON with invalid count", async () => {
|
|
431
|
+
const result = await handleAgentsValidate({
|
|
432
|
+
file: join(TEST_DIR, "AGENTS.md"),
|
|
433
|
+
json: true,
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
expect(result.kind).toBe("error");
|
|
437
|
+
if (result.kind === "error") {
|
|
438
|
+
const jsonData = JSON.parse(result.message);
|
|
439
|
+
expect(jsonData.success).toBe(false);
|
|
440
|
+
expect(jsonData.invalid).toBeGreaterThan(0);
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
describe("with nonexistent file", () => {
|
|
446
|
+
it("should return error for missing file", async () => {
|
|
447
|
+
const result = await handleAgentsValidate({
|
|
448
|
+
file: join(TEST_DIR, "nonexistent.md"),
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
expect(result.kind).toBe("error");
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
describe("with no AGENTS.md files", () => {
|
|
456
|
+
it("should handle empty project gracefully", async () => {
|
|
457
|
+
const result = await handleAgentsValidate({});
|
|
458
|
+
|
|
459
|
+
// No files to validate - should succeed with message
|
|
460
|
+
expect(result.kind).toBe("success");
|
|
461
|
+
if (result.kind === "success") {
|
|
462
|
+
expect(result.message).toContain("No AGENTS.md files found");
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
// =============================================================================
|
|
469
|
+
// T047: Integration Tests - agents generate
|
|
470
|
+
// =============================================================================
|
|
471
|
+
|
|
472
|
+
describe("agents generate integration", () => {
|
|
473
|
+
describe("dry-run mode", () => {
|
|
474
|
+
it("should show content without writing file", async () => {
|
|
475
|
+
const result = await handleAgentsGenerate({ dryRun: true });
|
|
476
|
+
|
|
477
|
+
expect(result.kind).toBe("success");
|
|
478
|
+
if (result.kind === "success") {
|
|
479
|
+
// Should contain preview content
|
|
480
|
+
expect(result.message).toContain("Preview");
|
|
481
|
+
expect(result.message).toContain("Would write to");
|
|
482
|
+
// File should NOT be created
|
|
483
|
+
expect(existsSync(join(TEST_DIR, "AGENTS.md"))).toBe(false);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it("should show detected project info in dry-run", async () => {
|
|
488
|
+
// Create package.json for detection
|
|
489
|
+
writeFileSync(
|
|
490
|
+
join(TEST_DIR, "package.json"),
|
|
491
|
+
JSON.stringify({
|
|
492
|
+
name: "my-test-project",
|
|
493
|
+
description: "A test project",
|
|
494
|
+
devDependencies: { typescript: "^5.0.0" },
|
|
495
|
+
})
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
const result = await handleAgentsGenerate({ dryRun: true });
|
|
499
|
+
|
|
500
|
+
expect(result.kind).toBe("success");
|
|
501
|
+
if (result.kind === "success") {
|
|
502
|
+
expect(result.message).toContain("my-test-project");
|
|
503
|
+
expect(result.message).toContain("TypeScript");
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
describe("file creation", () => {
|
|
509
|
+
it("should create AGENTS.md when none exists", async () => {
|
|
510
|
+
// Create package.json for detection
|
|
511
|
+
writeFileSync(join(TEST_DIR, "package.json"), JSON.stringify({ name: "new-project" }));
|
|
512
|
+
|
|
513
|
+
const result = await handleAgentsGenerate({});
|
|
514
|
+
|
|
515
|
+
expect(result.kind).toBe("success");
|
|
516
|
+
expect(existsSync(join(TEST_DIR, "AGENTS.md"))).toBe(true);
|
|
517
|
+
|
|
518
|
+
const content = await readFile(join(TEST_DIR, "AGENTS.md"), "utf-8");
|
|
519
|
+
expect(content).toContain("new-project");
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it("should fail when AGENTS.md already exists without merge", async () => {
|
|
523
|
+
writeFileSync(join(TEST_DIR, "AGENTS.md"), "existing content");
|
|
524
|
+
|
|
525
|
+
const result = await handleAgentsGenerate({});
|
|
526
|
+
|
|
527
|
+
expect(result.kind).toBe("error");
|
|
528
|
+
if (result.kind === "error") {
|
|
529
|
+
expect(result.message).toContain("already exists");
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it("should write to custom output path", async () => {
|
|
534
|
+
writeFileSync(join(TEST_DIR, "package.json"), JSON.stringify({ name: "custom-output" }));
|
|
535
|
+
const customPath = join(TEST_DIR, "custom-agents.md");
|
|
536
|
+
|
|
537
|
+
const result = await handleAgentsGenerate({ output: customPath });
|
|
538
|
+
|
|
539
|
+
expect(result.kind).toBe("success");
|
|
540
|
+
expect(existsSync(customPath)).toBe(true);
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
describe("merge mode", () => {
|
|
545
|
+
it("should merge with existing file when --merge flag is set", async () => {
|
|
546
|
+
writeFileSync(join(TEST_DIR, "AGENTS.md"), "# Existing content\n");
|
|
547
|
+
writeFileSync(join(TEST_DIR, "package.json"), JSON.stringify({ name: "merge-test" }));
|
|
548
|
+
|
|
549
|
+
const result = await handleAgentsGenerate({ merge: true });
|
|
550
|
+
|
|
551
|
+
expect(result.kind).toBe("success");
|
|
552
|
+
|
|
553
|
+
const content = await readFile(join(TEST_DIR, "AGENTS.md"), "utf-8");
|
|
554
|
+
expect(content).toContain("Existing content");
|
|
555
|
+
expect(content).toContain("merge-test");
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
describe("project detection", () => {
|
|
560
|
+
it("should detect TypeScript projects", async () => {
|
|
561
|
+
writeFileSync(join(TEST_DIR, "tsconfig.json"), "{}");
|
|
562
|
+
writeFileSync(join(TEST_DIR, "package.json"), JSON.stringify({ name: "ts-project" }));
|
|
563
|
+
|
|
564
|
+
const result = await handleAgentsGenerate({ dryRun: true });
|
|
565
|
+
|
|
566
|
+
expect(result.kind).toBe("success");
|
|
567
|
+
if (result.kind === "success") {
|
|
568
|
+
expect(result.message).toContain("TypeScript");
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it("should detect React framework", async () => {
|
|
573
|
+
writeFileSync(
|
|
574
|
+
join(TEST_DIR, "package.json"),
|
|
575
|
+
JSON.stringify({
|
|
576
|
+
name: "react-app",
|
|
577
|
+
dependencies: { react: "^18.0.0" },
|
|
578
|
+
})
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
const result = await handleAgentsGenerate({ dryRun: true });
|
|
582
|
+
|
|
583
|
+
expect(result.kind).toBe("success");
|
|
584
|
+
if (result.kind === "success") {
|
|
585
|
+
expect(result.message).toContain("React");
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it("should detect test framework", async () => {
|
|
590
|
+
writeFileSync(
|
|
591
|
+
join(TEST_DIR, "package.json"),
|
|
592
|
+
JSON.stringify({
|
|
593
|
+
name: "tested-app",
|
|
594
|
+
devDependencies: { vitest: "^1.0.0" },
|
|
595
|
+
})
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
const result = await handleAgentsGenerate({ dryRun: true });
|
|
599
|
+
|
|
600
|
+
expect(result.kind).toBe("success");
|
|
601
|
+
if (result.kind === "success") {
|
|
602
|
+
expect(result.message).toContain("Vitest");
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
});
|