@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,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory List Command
|
|
3
|
+
*
|
|
4
|
+
* Lists all saved project memories with filtering options.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/memory/list
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { MemoryEntry, MemoryEntryType } from "@vellum/core";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
|
|
12
|
+
import type { CommandContext, CommandResult, SlashCommand } from "../types.js";
|
|
13
|
+
import { error, success } from "../types.js";
|
|
14
|
+
import { withMemoryService } from "./utils.js";
|
|
15
|
+
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Types
|
|
18
|
+
// =============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for the memory list command.
|
|
22
|
+
*/
|
|
23
|
+
export interface MemoryListOptions {
|
|
24
|
+
/** Filter by tag */
|
|
25
|
+
tag?: string;
|
|
26
|
+
/** Filter by type */
|
|
27
|
+
type?: MemoryEntryType;
|
|
28
|
+
/** Filter entries since this date */
|
|
29
|
+
since?: Date;
|
|
30
|
+
/** Maximum number of entries to return */
|
|
31
|
+
limit?: number;
|
|
32
|
+
/** Output as JSON */
|
|
33
|
+
json?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* JSON output for memory list.
|
|
38
|
+
*/
|
|
39
|
+
interface MemoryListJson {
|
|
40
|
+
success: boolean;
|
|
41
|
+
entries: Array<{
|
|
42
|
+
key: string;
|
|
43
|
+
type: MemoryEntryType;
|
|
44
|
+
content: string;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
updatedAt: string;
|
|
47
|
+
tags: string[];
|
|
48
|
+
importance: number;
|
|
49
|
+
}>;
|
|
50
|
+
total: number;
|
|
51
|
+
filtered: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// =============================================================================
|
|
55
|
+
// Helper Functions
|
|
56
|
+
// =============================================================================
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Filter entries by options.
|
|
60
|
+
*/
|
|
61
|
+
function filterEntries(entries: MemoryEntry[], options: MemoryListOptions): MemoryEntry[] {
|
|
62
|
+
let filtered = entries;
|
|
63
|
+
|
|
64
|
+
// Filter by type
|
|
65
|
+
if (options.type) {
|
|
66
|
+
filtered = filtered.filter((e) => e.type === options.type);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Filter by tag
|
|
70
|
+
if (options.tag) {
|
|
71
|
+
const tag = options.tag.toLowerCase();
|
|
72
|
+
filtered = filtered.filter((e) => e.metadata.tags.some((t) => t.toLowerCase().includes(tag)));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Filter by date
|
|
76
|
+
if (options.since) {
|
|
77
|
+
const sinceDate = options.since;
|
|
78
|
+
filtered = filtered.filter((e) => e.updatedAt >= sinceDate);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Apply limit
|
|
82
|
+
if (options.limit && options.limit > 0) {
|
|
83
|
+
filtered = filtered.slice(0, options.limit);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return filtered;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Format a date for display.
|
|
91
|
+
*/
|
|
92
|
+
function formatDate(date: Date): string {
|
|
93
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
94
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
95
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
96
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
97
|
+
return `${month}/${day} ${hours}:${minutes}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get type badge color.
|
|
102
|
+
*/
|
|
103
|
+
function getTypeBadge(type: MemoryEntryType): string {
|
|
104
|
+
const colors: Record<MemoryEntryType, (s: string) => string> = {
|
|
105
|
+
context: chalk.cyan,
|
|
106
|
+
preference: chalk.magenta,
|
|
107
|
+
decision: chalk.yellow,
|
|
108
|
+
summary: chalk.green,
|
|
109
|
+
};
|
|
110
|
+
return colors[type](`[${type}]`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Format entries for console output.
|
|
115
|
+
*/
|
|
116
|
+
function formatEntriesOutput(entries: MemoryEntry[], total: number): string {
|
|
117
|
+
if (entries.length === 0) {
|
|
118
|
+
return chalk.dim("No memories found.");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const lines: string[] = [
|
|
122
|
+
chalk.bold.blue("📚 Project Memories"),
|
|
123
|
+
chalk.dim(`Showing ${entries.length} of ${total} entries`),
|
|
124
|
+
"",
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
const badge = getTypeBadge(entry.type);
|
|
129
|
+
const date = chalk.dim(formatDate(entry.updatedAt));
|
|
130
|
+
const key = chalk.bold(entry.key);
|
|
131
|
+
const preview = entry.content.slice(0, 60).replace(/\n/g, " ");
|
|
132
|
+
const truncated = entry.content.length > 60 ? "…" : "";
|
|
133
|
+
|
|
134
|
+
lines.push(`${badge} ${key} ${date}`);
|
|
135
|
+
lines.push(chalk.dim(` ${preview}${truncated}`));
|
|
136
|
+
|
|
137
|
+
if (entry.metadata.tags.length > 0) {
|
|
138
|
+
const tags = entry.metadata.tags.map((t) => chalk.cyan(`#${t}`)).join(" ");
|
|
139
|
+
lines.push(chalk.dim(` Tags: ${tags}`));
|
|
140
|
+
}
|
|
141
|
+
lines.push("");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return lines.join("\n");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Format entries as JSON.
|
|
149
|
+
*/
|
|
150
|
+
function formatEntriesJson(entries: MemoryEntry[], total: number): MemoryListJson {
|
|
151
|
+
return {
|
|
152
|
+
success: true,
|
|
153
|
+
entries: entries.map((e) => ({
|
|
154
|
+
key: e.key,
|
|
155
|
+
type: e.type,
|
|
156
|
+
content: e.content,
|
|
157
|
+
createdAt: e.createdAt.toISOString(),
|
|
158
|
+
updatedAt: e.updatedAt.toISOString(),
|
|
159
|
+
tags: e.metadata.tags,
|
|
160
|
+
importance: e.metadata.importance,
|
|
161
|
+
})),
|
|
162
|
+
total,
|
|
163
|
+
filtered: entries.length,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// =============================================================================
|
|
168
|
+
// Command Execution
|
|
169
|
+
// =============================================================================
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Execute the memory list command.
|
|
173
|
+
*/
|
|
174
|
+
export async function executeMemoryList(
|
|
175
|
+
projectPath: string,
|
|
176
|
+
options: MemoryListOptions = {}
|
|
177
|
+
): Promise<CommandResult> {
|
|
178
|
+
try {
|
|
179
|
+
return await withMemoryService(projectPath, async (service) => {
|
|
180
|
+
const allEntries = await service.listEntries(options.type);
|
|
181
|
+
const filtered = filterEntries(allEntries, options);
|
|
182
|
+
|
|
183
|
+
if (options.json) {
|
|
184
|
+
const json = formatEntriesJson(filtered, allEntries.length);
|
|
185
|
+
return success(JSON.stringify(json, null, 2));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const output = formatEntriesOutput(filtered, allEntries.length);
|
|
189
|
+
return success(output);
|
|
190
|
+
});
|
|
191
|
+
} catch (err) {
|
|
192
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
193
|
+
return error("INTERNAL_ERROR", `Failed to list memories: ${message}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// =============================================================================
|
|
198
|
+
// Slash Command Definition
|
|
199
|
+
// =============================================================================
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Parse list command arguments.
|
|
203
|
+
*/
|
|
204
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Argument parsing requires handling many flag combinations
|
|
205
|
+
function parseListArgs(args: string[]): MemoryListOptions {
|
|
206
|
+
const options: MemoryListOptions = {};
|
|
207
|
+
|
|
208
|
+
for (let i = 0; i < args.length; i++) {
|
|
209
|
+
const arg = args[i];
|
|
210
|
+
const nextArg = args[i + 1];
|
|
211
|
+
|
|
212
|
+
if (arg === "--tag" && nextArg) {
|
|
213
|
+
options.tag = nextArg;
|
|
214
|
+
i++;
|
|
215
|
+
} else if (arg === "--type" && nextArg) {
|
|
216
|
+
if (["context", "preference", "decision", "summary"].includes(nextArg)) {
|
|
217
|
+
options.type = nextArg as MemoryEntryType;
|
|
218
|
+
}
|
|
219
|
+
i++;
|
|
220
|
+
} else if (arg === "--since" && nextArg) {
|
|
221
|
+
const date = new Date(nextArg);
|
|
222
|
+
if (!Number.isNaN(date.getTime())) {
|
|
223
|
+
options.since = date;
|
|
224
|
+
}
|
|
225
|
+
i++;
|
|
226
|
+
} else if (arg === "--limit" && nextArg) {
|
|
227
|
+
const limit = Number.parseInt(nextArg, 10);
|
|
228
|
+
if (!Number.isNaN(limit) && limit > 0) {
|
|
229
|
+
options.limit = limit;
|
|
230
|
+
}
|
|
231
|
+
i++;
|
|
232
|
+
} else if (arg === "--json") {
|
|
233
|
+
options.json = true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return options;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Memory list slash command handler.
|
|
242
|
+
*/
|
|
243
|
+
async function handleMemoryList(context: CommandContext): Promise<CommandResult> {
|
|
244
|
+
const args = context.parsedArgs.positional as string[];
|
|
245
|
+
const options = parseListArgs(args);
|
|
246
|
+
const projectPath = context.session.cwd;
|
|
247
|
+
|
|
248
|
+
return executeMemoryList(projectPath, options);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Memory list slash command definition.
|
|
253
|
+
*/
|
|
254
|
+
export const memoryListCommand: SlashCommand = {
|
|
255
|
+
name: "memory list",
|
|
256
|
+
description: "List all saved project memories",
|
|
257
|
+
kind: "builtin",
|
|
258
|
+
category: "session",
|
|
259
|
+
aliases: ["memory ls"],
|
|
260
|
+
execute: handleMemoryList,
|
|
261
|
+
};
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Search Command
|
|
3
|
+
*
|
|
4
|
+
* Search project memories by query with full-text search support.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/memory/search
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { MemoryEntry, MemoryEntryType } from "@vellum/core";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
|
|
12
|
+
import type { CommandContext, CommandResult, SlashCommand } from "../types.js";
|
|
13
|
+
import { error, success } from "../types.js";
|
|
14
|
+
import { withMemoryService } from "./utils.js";
|
|
15
|
+
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Types
|
|
18
|
+
// =============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for the memory search command.
|
|
22
|
+
*/
|
|
23
|
+
export interface MemorySearchOptions {
|
|
24
|
+
/** Search query string */
|
|
25
|
+
query: string;
|
|
26
|
+
/** Filter by type */
|
|
27
|
+
type?: MemoryEntryType;
|
|
28
|
+
/** Case-sensitive search */
|
|
29
|
+
caseSensitive?: boolean;
|
|
30
|
+
/** Maximum results to return */
|
|
31
|
+
limit?: number;
|
|
32
|
+
/** Output as JSON */
|
|
33
|
+
json?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Search result with relevance score.
|
|
38
|
+
*/
|
|
39
|
+
interface SearchResult {
|
|
40
|
+
entry: MemoryEntry;
|
|
41
|
+
score: number;
|
|
42
|
+
matches: {
|
|
43
|
+
inKey: boolean;
|
|
44
|
+
inContent: boolean;
|
|
45
|
+
inTags: boolean;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* JSON output for memory search.
|
|
51
|
+
*/
|
|
52
|
+
interface MemorySearchJson {
|
|
53
|
+
success: boolean;
|
|
54
|
+
query: string;
|
|
55
|
+
results: Array<{
|
|
56
|
+
key: string;
|
|
57
|
+
type: MemoryEntryType;
|
|
58
|
+
content: string;
|
|
59
|
+
score: number;
|
|
60
|
+
matches: {
|
|
61
|
+
inKey: boolean;
|
|
62
|
+
inContent: boolean;
|
|
63
|
+
inTags: boolean;
|
|
64
|
+
};
|
|
65
|
+
}>;
|
|
66
|
+
total: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// Search Functions
|
|
71
|
+
// =============================================================================
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Calculate relevance score for an entry.
|
|
75
|
+
*/
|
|
76
|
+
function calculateScore(
|
|
77
|
+
entry: MemoryEntry,
|
|
78
|
+
query: string,
|
|
79
|
+
caseSensitive: boolean
|
|
80
|
+
): SearchResult | null {
|
|
81
|
+
const q = caseSensitive ? query : query.toLowerCase();
|
|
82
|
+
const key = caseSensitive ? entry.key : entry.key.toLowerCase();
|
|
83
|
+
const content = caseSensitive ? entry.content : entry.content.toLowerCase();
|
|
84
|
+
const tags = entry.metadata.tags.map((t) => (caseSensitive ? t : t.toLowerCase()));
|
|
85
|
+
|
|
86
|
+
const inKey = key.includes(q);
|
|
87
|
+
const inContent = content.includes(q);
|
|
88
|
+
const inTags = tags.some((t) => t.includes(q));
|
|
89
|
+
|
|
90
|
+
if (!inKey && !inContent && !inTags) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Score weighting: key matches > tag matches > content matches
|
|
95
|
+
let score = 0;
|
|
96
|
+
if (inKey) score += 10;
|
|
97
|
+
if (inTags) score += 5;
|
|
98
|
+
if (inContent) score += 1;
|
|
99
|
+
|
|
100
|
+
// Boost for exact key match
|
|
101
|
+
if (key === q) score += 20;
|
|
102
|
+
|
|
103
|
+
// Boost by importance
|
|
104
|
+
score *= 1 + entry.metadata.importance;
|
|
105
|
+
|
|
106
|
+
// Boost recent entries slightly
|
|
107
|
+
const ageInDays = (Date.now() - entry.updatedAt.getTime()) / (1000 * 60 * 60 * 24);
|
|
108
|
+
if (ageInDays < 7) score *= 1.1;
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
entry,
|
|
112
|
+
score,
|
|
113
|
+
matches: { inKey, inContent, inTags },
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Search entries and return ranked results.
|
|
119
|
+
*/
|
|
120
|
+
function searchEntries(entries: MemoryEntry[], options: MemorySearchOptions): SearchResult[] {
|
|
121
|
+
const results: SearchResult[] = [];
|
|
122
|
+
|
|
123
|
+
for (const entry of entries) {
|
|
124
|
+
// Filter by type if specified
|
|
125
|
+
if (options.type && entry.type !== options.type) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const result = calculateScore(entry, options.query, options.caseSensitive ?? false);
|
|
130
|
+
if (result) {
|
|
131
|
+
results.push(result);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Sort by score descending
|
|
136
|
+
results.sort((a, b) => b.score - a.score);
|
|
137
|
+
|
|
138
|
+
// Apply limit
|
|
139
|
+
if (options.limit && options.limit > 0) {
|
|
140
|
+
return results.slice(0, options.limit);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return results;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Highlight query matches in text.
|
|
148
|
+
*/
|
|
149
|
+
function highlightMatch(text: string, query: string): string {
|
|
150
|
+
const regex = new RegExp(`(${escapeRegex(query)})`, "gi");
|
|
151
|
+
return text.replace(regex, chalk.bold.yellow("$1"));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Escape special regex characters.
|
|
156
|
+
*/
|
|
157
|
+
function escapeRegex(str: string): string {
|
|
158
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Format date for display.
|
|
163
|
+
*/
|
|
164
|
+
function formatDate(date: Date): string {
|
|
165
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
166
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
167
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
168
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
169
|
+
return `${month}/${day} ${hours}:${minutes}`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get type badge color.
|
|
174
|
+
*/
|
|
175
|
+
function getTypeBadge(type: MemoryEntryType): string {
|
|
176
|
+
const colors: Record<MemoryEntryType, (s: string) => string> = {
|
|
177
|
+
context: chalk.cyan,
|
|
178
|
+
preference: chalk.magenta,
|
|
179
|
+
decision: chalk.yellow,
|
|
180
|
+
summary: chalk.green,
|
|
181
|
+
};
|
|
182
|
+
return colors[type](`[${type}]`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Format search results for console output.
|
|
187
|
+
*/
|
|
188
|
+
function formatSearchOutput(results: SearchResult[], query: string): string {
|
|
189
|
+
if (results.length === 0) {
|
|
190
|
+
return chalk.dim(`No memories found matching "${query}".`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const lines: string[] = [
|
|
194
|
+
chalk.bold.blue(`🔍 Search Results for "${query}"`),
|
|
195
|
+
chalk.dim(`Found ${results.length} matching ${results.length === 1 ? "entry" : "entries"}`),
|
|
196
|
+
"",
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
for (const { entry, score, matches } of results) {
|
|
200
|
+
const badge = getTypeBadge(entry.type);
|
|
201
|
+
const date = chalk.dim(formatDate(entry.updatedAt));
|
|
202
|
+
const key = matches.inKey ? highlightMatch(entry.key, query) : chalk.bold(entry.key);
|
|
203
|
+
const scoreStr = chalk.dim(`(score: ${score.toFixed(1)})`);
|
|
204
|
+
|
|
205
|
+
lines.push(`${badge} ${key} ${date} ${scoreStr}`);
|
|
206
|
+
|
|
207
|
+
// Show content preview with highlighting
|
|
208
|
+
let preview = entry.content.slice(0, 80).replace(/\n/g, " ");
|
|
209
|
+
if (matches.inContent) {
|
|
210
|
+
preview = highlightMatch(preview, query);
|
|
211
|
+
}
|
|
212
|
+
const truncated = entry.content.length > 80 ? "…" : "";
|
|
213
|
+
lines.push(chalk.dim(` ${preview}${truncated}`));
|
|
214
|
+
|
|
215
|
+
// Show matching tags
|
|
216
|
+
if (matches.inTags && entry.metadata.tags.length > 0) {
|
|
217
|
+
const tags = entry.metadata.tags
|
|
218
|
+
.map((t) =>
|
|
219
|
+
t.toLowerCase().includes(query.toLowerCase())
|
|
220
|
+
? chalk.bold.yellow(`#${t}`)
|
|
221
|
+
: chalk.cyan(`#${t}`)
|
|
222
|
+
)
|
|
223
|
+
.join(" ");
|
|
224
|
+
lines.push(chalk.dim(` Tags: ${tags}`));
|
|
225
|
+
}
|
|
226
|
+
lines.push("");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return lines.join("\n");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Format search results as JSON.
|
|
234
|
+
*/
|
|
235
|
+
function formatSearchJson(results: SearchResult[], query: string): MemorySearchJson {
|
|
236
|
+
return {
|
|
237
|
+
success: true,
|
|
238
|
+
query,
|
|
239
|
+
results: results.map(({ entry, score, matches }) => ({
|
|
240
|
+
key: entry.key,
|
|
241
|
+
type: entry.type,
|
|
242
|
+
content: entry.content,
|
|
243
|
+
score,
|
|
244
|
+
matches,
|
|
245
|
+
})),
|
|
246
|
+
total: results.length,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// =============================================================================
|
|
251
|
+
// Command Execution
|
|
252
|
+
// =============================================================================
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Execute the memory search command.
|
|
256
|
+
*/
|
|
257
|
+
export async function executeMemorySearch(
|
|
258
|
+
projectPath: string,
|
|
259
|
+
options: MemorySearchOptions
|
|
260
|
+
): Promise<CommandResult> {
|
|
261
|
+
if (!options.query || options.query.trim().length === 0) {
|
|
262
|
+
return error("MISSING_ARGUMENT", "Search query is required. Usage: /memory search <query>");
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
return await withMemoryService(projectPath, async (service) => {
|
|
267
|
+
const allEntries = await service.listEntries();
|
|
268
|
+
const results = searchEntries(allEntries, options);
|
|
269
|
+
|
|
270
|
+
if (options.json) {
|
|
271
|
+
const json = formatSearchJson(results, options.query);
|
|
272
|
+
return success(JSON.stringify(json, null, 2));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const output = formatSearchOutput(results, options.query);
|
|
276
|
+
return success(output);
|
|
277
|
+
});
|
|
278
|
+
} catch (err) {
|
|
279
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
280
|
+
return error("INTERNAL_ERROR", `Failed to search memories: ${message}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// =============================================================================
|
|
285
|
+
// Slash Command Definition
|
|
286
|
+
// =============================================================================
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Parse search command arguments.
|
|
290
|
+
*/
|
|
291
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Argument parsing requires handling many flag combinations
|
|
292
|
+
function parseSearchArgs(args: string[]): MemorySearchOptions {
|
|
293
|
+
const options: MemorySearchOptions = { query: "" };
|
|
294
|
+
const queryParts: string[] = [];
|
|
295
|
+
|
|
296
|
+
for (let i = 0; i < args.length; i++) {
|
|
297
|
+
const arg = args[i];
|
|
298
|
+
if (!arg) continue;
|
|
299
|
+
const nextArg = args[i + 1] ?? "";
|
|
300
|
+
|
|
301
|
+
if (arg === "--type" && nextArg) {
|
|
302
|
+
if (["context", "preference", "decision", "summary"].includes(nextArg)) {
|
|
303
|
+
options.type = nextArg as MemoryEntryType;
|
|
304
|
+
}
|
|
305
|
+
i++;
|
|
306
|
+
} else if (arg === "--limit" && nextArg) {
|
|
307
|
+
const limit = Number.parseInt(nextArg, 10);
|
|
308
|
+
if (!Number.isNaN(limit) && limit > 0) {
|
|
309
|
+
options.limit = limit;
|
|
310
|
+
}
|
|
311
|
+
i++;
|
|
312
|
+
} else if (arg === "--case-sensitive" || arg === "-c") {
|
|
313
|
+
options.caseSensitive = true;
|
|
314
|
+
} else if (arg === "--json") {
|
|
315
|
+
options.json = true;
|
|
316
|
+
} else if (!arg.startsWith("--")) {
|
|
317
|
+
queryParts.push(arg);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
options.query = queryParts.join(" ");
|
|
322
|
+
return options;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Memory search slash command handler.
|
|
327
|
+
*/
|
|
328
|
+
async function handleMemorySearch(context: CommandContext): Promise<CommandResult> {
|
|
329
|
+
const args = context.parsedArgs.positional as string[];
|
|
330
|
+
const options = parseSearchArgs(args);
|
|
331
|
+
const projectPath = context.session.cwd;
|
|
332
|
+
|
|
333
|
+
return executeMemorySearch(projectPath, options);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Memory search slash command definition.
|
|
338
|
+
*/
|
|
339
|
+
export const memorySearchCommand: SlashCommand = {
|
|
340
|
+
name: "memory search",
|
|
341
|
+
description: "Search project memories by query",
|
|
342
|
+
kind: "builtin",
|
|
343
|
+
category: "session",
|
|
344
|
+
aliases: ["memory find"],
|
|
345
|
+
execute: handleMemorySearch,
|
|
346
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ProjectMemoryService } from "@vellum/core";
|
|
2
|
+
|
|
3
|
+
export async function withMemoryService<T>(
|
|
4
|
+
projectPath: string,
|
|
5
|
+
action: (service: ProjectMemoryService) => Promise<T>
|
|
6
|
+
): Promise<T> {
|
|
7
|
+
const service = new ProjectMemoryService();
|
|
8
|
+
await service.initialize(projectPath);
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
return await action(service);
|
|
12
|
+
} finally {
|
|
13
|
+
await service.close();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Command
|
|
3
|
+
*
|
|
4
|
+
* Display application metrics and statistics.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/metrics
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { getMetricsManager } from "../tui/metrics-integration.js";
|
|
10
|
+
import type { CommandContext, CommandResult, SlashCommand as SlashCommandDef } from "./types.js";
|
|
11
|
+
import { success } from "./types.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* /metrics command - Display current metrics
|
|
15
|
+
*/
|
|
16
|
+
export const metricsCommand: SlashCommandDef = {
|
|
17
|
+
name: "metrics",
|
|
18
|
+
description: "Display application metrics and statistics",
|
|
19
|
+
kind: "builtin",
|
|
20
|
+
category: "debug",
|
|
21
|
+
positionalArgs: [],
|
|
22
|
+
namedArgs: [
|
|
23
|
+
{
|
|
24
|
+
name: "format",
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Output format (text, json)",
|
|
27
|
+
required: false,
|
|
28
|
+
default: "text",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
subcommands: [
|
|
32
|
+
{ name: "show", description: "Display current metrics" },
|
|
33
|
+
{ name: "reset", description: "Reset all metrics counters" },
|
|
34
|
+
{ name: "export", description: "Export metrics to file" },
|
|
35
|
+
],
|
|
36
|
+
aliases: ["stats"],
|
|
37
|
+
|
|
38
|
+
execute: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
39
|
+
const manager = getMetricsManager();
|
|
40
|
+
const snapshot = manager.getSnapshot();
|
|
41
|
+
const format = (ctx.parsedArgs?.named?.format as string) ?? "text";
|
|
42
|
+
|
|
43
|
+
if (format === "json") {
|
|
44
|
+
return success(JSON.stringify(snapshot, null, 2));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Format as text
|
|
48
|
+
const output = manager.formatSnapshot(snapshot);
|
|
49
|
+
return success(output);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* /metrics reset command - Reset all metrics
|
|
55
|
+
*/
|
|
56
|
+
export const metricsResetCommand: SlashCommandDef = {
|
|
57
|
+
name: "metrics:reset",
|
|
58
|
+
description: "Reset all metrics counters",
|
|
59
|
+
kind: "builtin",
|
|
60
|
+
category: "debug",
|
|
61
|
+
positionalArgs: [],
|
|
62
|
+
namedArgs: [],
|
|
63
|
+
aliases: [],
|
|
64
|
+
|
|
65
|
+
execute: async (_ctx: CommandContext): Promise<CommandResult> => {
|
|
66
|
+
const manager = getMetricsManager();
|
|
67
|
+
manager.reset();
|
|
68
|
+
return success("✅ Metrics reset successfully");
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* All metrics commands
|
|
74
|
+
*/
|
|
75
|
+
export const metricsCommands: SlashCommandDef[] = [metricsCommand, metricsResetCommand];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migrate Commands Index
|
|
3
|
+
*
|
|
4
|
+
* Barrel exports for migration commands.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/migrate
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
executeMigratePrompts,
|
|
11
|
+
type MigratePromptsOptions,
|
|
12
|
+
type MigratePromptsResult,
|
|
13
|
+
type MigrationAction,
|
|
14
|
+
migratePromptsCommand,
|
|
15
|
+
runMigratePromptsCli,
|
|
16
|
+
} from "./prompts.js";
|