@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,480 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Pipe Parser Module
|
|
3
|
+
*
|
|
4
|
+
* Parses command pipes and redirections with shell-like operators:
|
|
5
|
+
* - | (PIPE): Pass output as input to next command
|
|
6
|
+
* - > (WRITE): Write output to file (overwrite)
|
|
7
|
+
* - >> (APPEND): Write output to file (append)
|
|
8
|
+
*
|
|
9
|
+
* @module cli/commands/parser/pipe-parser
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { CommandErrorCode, CommandResult } from "../types.js";
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// T054: Pipe Operator Types
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Pipe operator discriminator
|
|
20
|
+
*
|
|
21
|
+
* - | (PIPE): Pass stdout of left command to stdin of right command
|
|
22
|
+
* - > (WRITE): Write stdout to file, overwriting existing content
|
|
23
|
+
* - >> (APPEND): Write stdout to file, appending to existing content
|
|
24
|
+
*/
|
|
25
|
+
export type PipeOperator = "|" | ">" | ">>";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Segment type discriminator
|
|
29
|
+
*/
|
|
30
|
+
export type PipeSegmentType = "command" | "file";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Single segment of a piped command
|
|
34
|
+
*/
|
|
35
|
+
export interface PipeSegment {
|
|
36
|
+
/** Segment type: command to execute or file target */
|
|
37
|
+
readonly type: PipeSegmentType;
|
|
38
|
+
/** Command string or file path */
|
|
39
|
+
readonly value: string;
|
|
40
|
+
/** Operator connecting to the NEXT segment (undefined for last) */
|
|
41
|
+
readonly operator?: PipeOperator;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Result of parsing a piped command string
|
|
46
|
+
*/
|
|
47
|
+
export interface PipeParseResult {
|
|
48
|
+
/** Whether the input contains pipe operators */
|
|
49
|
+
readonly isPiped: boolean;
|
|
50
|
+
/** Array of command/file segments with their operators */
|
|
51
|
+
readonly segments: readonly PipeSegment[];
|
|
52
|
+
/** Original raw input */
|
|
53
|
+
readonly raw: string;
|
|
54
|
+
/** Whether output redirects to a file */
|
|
55
|
+
readonly hasRedirect: boolean;
|
|
56
|
+
/** Redirect mode if hasRedirect is true */
|
|
57
|
+
readonly redirectMode?: "overwrite" | "append";
|
|
58
|
+
/** Target file if hasRedirect is true */
|
|
59
|
+
readonly redirectTarget?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Result of pipe execution
|
|
64
|
+
*/
|
|
65
|
+
export interface PipeExecutionResult {
|
|
66
|
+
/** Final result from the pipe chain */
|
|
67
|
+
readonly result: CommandResult;
|
|
68
|
+
/** Accumulated output data */
|
|
69
|
+
readonly output: string;
|
|
70
|
+
/** Number of commands executed */
|
|
71
|
+
readonly executedCount: number;
|
|
72
|
+
/** Total segments in pipe */
|
|
73
|
+
readonly totalCount: number;
|
|
74
|
+
/** Whether pipe completed fully */
|
|
75
|
+
readonly completed: boolean;
|
|
76
|
+
/** File written to (if redirected) */
|
|
77
|
+
readonly writtenFile?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// =============================================================================
|
|
81
|
+
// T054: Pipe Parser Implementation
|
|
82
|
+
// =============================================================================
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check if a position is inside quotes
|
|
86
|
+
*/
|
|
87
|
+
function isInsideQuotes(input: string, position: number): boolean {
|
|
88
|
+
let inDouble = false;
|
|
89
|
+
let inSingle = false;
|
|
90
|
+
|
|
91
|
+
for (let i = 0; i < position && i < input.length; i++) {
|
|
92
|
+
const char = input[i];
|
|
93
|
+
const prevChar = i > 0 ? input[i - 1] : "";
|
|
94
|
+
|
|
95
|
+
if (char === '"' && !inSingle && prevChar !== "\\") {
|
|
96
|
+
inDouble = !inDouble;
|
|
97
|
+
} else if (char === "'" && !inDouble) {
|
|
98
|
+
inSingle = !inSingle;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return inDouble || inSingle;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Find all pipe operators with their positions
|
|
107
|
+
*/
|
|
108
|
+
function findPipeOperators(
|
|
109
|
+
input: string
|
|
110
|
+
): Array<{ operator: PipeOperator; start: number; end: number }> {
|
|
111
|
+
const operators: Array<{ operator: PipeOperator; start: number; end: number }> = [];
|
|
112
|
+
|
|
113
|
+
let i = 0;
|
|
114
|
+
while (i < input.length) {
|
|
115
|
+
// Skip if inside quotes
|
|
116
|
+
if (isInsideQuotes(input, i)) {
|
|
117
|
+
i++;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Check for >> (must check before single >)
|
|
122
|
+
if (input[i] === ">" && input[i + 1] === ">") {
|
|
123
|
+
operators.push({ operator: ">>", start: i, end: i + 2 });
|
|
124
|
+
i += 2;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check for > (single, not part of >>)
|
|
129
|
+
if (input[i] === ">" && input[i + 1] !== ">") {
|
|
130
|
+
operators.push({ operator: ">", start: i, end: i + 1 });
|
|
131
|
+
i++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check for | (but not || - check both next AND previous char)
|
|
136
|
+
if (input[i] === "|" && input[i + 1] !== "|" && input[i - 1] !== "|") {
|
|
137
|
+
operators.push({ operator: "|", start: i, end: i + 1 });
|
|
138
|
+
i++;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
i++;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return operators;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Pipe Parser
|
|
150
|
+
*
|
|
151
|
+
* Parses command strings containing pipe/redirect operators into segments.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const result = PipeParser.parse('/list | /filter pattern > output.txt');
|
|
156
|
+
* // {
|
|
157
|
+
* // isPiped: true,
|
|
158
|
+
* // segments: [
|
|
159
|
+
* // { type: 'command', value: '/list', operator: '|' },
|
|
160
|
+
* // { type: 'command', value: '/filter pattern', operator: '>' },
|
|
161
|
+
* // { type: 'file', value: 'output.txt' }
|
|
162
|
+
* // ],
|
|
163
|
+
* // raw: '/list | /filter pattern > output.txt',
|
|
164
|
+
* // hasRedirect: true,
|
|
165
|
+
* // redirectMode: 'overwrite',
|
|
166
|
+
* // redirectTarget: 'output.txt'
|
|
167
|
+
* // }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
// biome-ignore lint/complexity/noStaticOnlyClass: PipeParser provides logical grouping
|
|
171
|
+
export class PipeParser {
|
|
172
|
+
/**
|
|
173
|
+
* Parse a command string for pipe operators
|
|
174
|
+
*
|
|
175
|
+
* @param input - Raw command string
|
|
176
|
+
* @returns PipeParseResult with parsed segments
|
|
177
|
+
*/
|
|
178
|
+
static parse(input: string): PipeParseResult {
|
|
179
|
+
const trimmed = input.trim();
|
|
180
|
+
|
|
181
|
+
if (!trimmed) {
|
|
182
|
+
return {
|
|
183
|
+
isPiped: false,
|
|
184
|
+
segments: [],
|
|
185
|
+
raw: input,
|
|
186
|
+
hasRedirect: false,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const operators = findPipeOperators(trimmed);
|
|
191
|
+
|
|
192
|
+
// No pipe operators found
|
|
193
|
+
if (operators.length === 0) {
|
|
194
|
+
return {
|
|
195
|
+
isPiped: false,
|
|
196
|
+
segments: [{ type: "command", value: trimmed }],
|
|
197
|
+
raw: input,
|
|
198
|
+
hasRedirect: false,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Split into segments
|
|
203
|
+
const segments: PipeSegment[] = [];
|
|
204
|
+
let lastEnd = 0;
|
|
205
|
+
|
|
206
|
+
for (let i = 0; i < operators.length; i++) {
|
|
207
|
+
const op = operators[i];
|
|
208
|
+
if (!op) continue;
|
|
209
|
+
|
|
210
|
+
const value = trimmed.slice(lastEnd, op.start).trim();
|
|
211
|
+
if (value) {
|
|
212
|
+
// Determine segment type based on what comes before
|
|
213
|
+
const type: PipeSegmentType = "command";
|
|
214
|
+
segments.push({ type, value, operator: op.operator });
|
|
215
|
+
}
|
|
216
|
+
lastEnd = op.end;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Add final segment (after last operator)
|
|
220
|
+
const finalValue = trimmed.slice(lastEnd).trim();
|
|
221
|
+
if (finalValue) {
|
|
222
|
+
// Determine if final segment is a file (after > or >>)
|
|
223
|
+
const lastOp = operators[operators.length - 1];
|
|
224
|
+
const isFile = lastOp?.operator === ">" || lastOp?.operator === ">>";
|
|
225
|
+
segments.push({
|
|
226
|
+
type: isFile ? "file" : "command",
|
|
227
|
+
value: finalValue,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Determine redirect info
|
|
232
|
+
const lastOp = operators[operators.length - 1];
|
|
233
|
+
const hasRedirect = lastOp?.operator === ">" || lastOp?.operator === ">>";
|
|
234
|
+
const redirectMode = hasRedirect
|
|
235
|
+
? lastOp?.operator === ">>"
|
|
236
|
+
? "append"
|
|
237
|
+
: "overwrite"
|
|
238
|
+
: undefined;
|
|
239
|
+
const redirectTarget = hasRedirect ? finalValue : undefined;
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
isPiped: segments.length > 1 || hasRedirect,
|
|
243
|
+
segments,
|
|
244
|
+
raw: input,
|
|
245
|
+
hasRedirect,
|
|
246
|
+
redirectMode,
|
|
247
|
+
redirectTarget,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Check if input contains pipe operators
|
|
253
|
+
*
|
|
254
|
+
* @param input - Raw command string
|
|
255
|
+
* @returns true if pipe operators are present
|
|
256
|
+
*/
|
|
257
|
+
static hasPipeOperators(input: string): boolean {
|
|
258
|
+
const operators = findPipeOperators(input);
|
|
259
|
+
return operators.length > 0;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Check if input has file redirection
|
|
264
|
+
*
|
|
265
|
+
* @param input - Raw command string
|
|
266
|
+
* @returns true if > or >> is present
|
|
267
|
+
*/
|
|
268
|
+
static hasRedirection(input: string): boolean {
|
|
269
|
+
const operators = findPipeOperators(input);
|
|
270
|
+
return operators.some((op) => op.operator === ">" || op.operator === ">>");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// =============================================================================
|
|
275
|
+
// T054: Piped Command Executor
|
|
276
|
+
// =============================================================================
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Executor function type for piped commands
|
|
280
|
+
* Returns output string for piping to next command
|
|
281
|
+
*/
|
|
282
|
+
export type PipeCommandExecutorFn = (
|
|
283
|
+
command: string,
|
|
284
|
+
input?: string,
|
|
285
|
+
signal?: AbortSignal
|
|
286
|
+
) => Promise<{ result: CommandResult; output: string }>;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* File writer function type for redirections
|
|
290
|
+
*/
|
|
291
|
+
export type FileWriterFn = (
|
|
292
|
+
path: string,
|
|
293
|
+
content: string,
|
|
294
|
+
mode: "overwrite" | "append"
|
|
295
|
+
) => Promise<void>;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Piped Command Executor
|
|
299
|
+
*
|
|
300
|
+
* Executes a pipe of commands according to shell semantics:
|
|
301
|
+
* - | : Pass output of left as input to right
|
|
302
|
+
* - > : Write final output to file (overwrite)
|
|
303
|
+
* - >> : Write final output to file (append)
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const executor = new PipedCommandExecutor(
|
|
308
|
+
* async (cmd, input) => ({
|
|
309
|
+
* result: { type: 'success', message: `Processed: ${cmd}` },
|
|
310
|
+
* output: `Output from ${cmd} with input: ${input ?? 'none'}`
|
|
311
|
+
* }),
|
|
312
|
+
* async (path, content, mode) => {
|
|
313
|
+
* // Write to file
|
|
314
|
+
* }
|
|
315
|
+
* );
|
|
316
|
+
*
|
|
317
|
+
* const result = await executor.execute('/list | /filter > output.txt');
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
export class PipedCommandExecutor {
|
|
321
|
+
private readonly executeFn: PipeCommandExecutorFn;
|
|
322
|
+
private readonly writeFileFn?: FileWriterFn;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Create a PipedCommandExecutor
|
|
326
|
+
*
|
|
327
|
+
* @param executeFn - Function to execute individual commands
|
|
328
|
+
* @param writeFileFn - Optional function to write output to files
|
|
329
|
+
*/
|
|
330
|
+
constructor(executeFn: PipeCommandExecutorFn, writeFileFn?: FileWriterFn) {
|
|
331
|
+
this.executeFn = executeFn;
|
|
332
|
+
this.writeFileFn = writeFileFn;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Create an error result for pipe execution */
|
|
336
|
+
private createErrorResult(
|
|
337
|
+
code: CommandErrorCode,
|
|
338
|
+
message: string,
|
|
339
|
+
output: string,
|
|
340
|
+
executedCount: number,
|
|
341
|
+
totalCount: number
|
|
342
|
+
): PipeExecutionResult {
|
|
343
|
+
return {
|
|
344
|
+
result: { kind: "error", code, message },
|
|
345
|
+
output,
|
|
346
|
+
executedCount,
|
|
347
|
+
totalCount,
|
|
348
|
+
completed: false,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Execute command segments in sequence */
|
|
353
|
+
private async executeCommandSequence(
|
|
354
|
+
commandSegments: PipeSegment[],
|
|
355
|
+
signal?: AbortSignal
|
|
356
|
+
): Promise<{ result: CommandResult; output: string; executedCount: number; aborted: boolean }> {
|
|
357
|
+
let currentOutput = "";
|
|
358
|
+
let lastResult: CommandResult = { kind: "success", message: "" };
|
|
359
|
+
let executedCount = 0;
|
|
360
|
+
|
|
361
|
+
for (let i = 0; i < commandSegments.length; i++) {
|
|
362
|
+
if (signal?.aborted) {
|
|
363
|
+
return {
|
|
364
|
+
result: {
|
|
365
|
+
kind: "error",
|
|
366
|
+
code: "COMMAND_ABORTED",
|
|
367
|
+
message: "Pipe execution was cancelled",
|
|
368
|
+
},
|
|
369
|
+
output: currentOutput,
|
|
370
|
+
executedCount,
|
|
371
|
+
aborted: true,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const segment = commandSegments[i];
|
|
376
|
+
if (!segment) continue;
|
|
377
|
+
|
|
378
|
+
const pipeInput = i > 0 ? currentOutput : undefined;
|
|
379
|
+
const { result, output } = await this.executeFn(segment.value, pipeInput, signal);
|
|
380
|
+
|
|
381
|
+
lastResult = result;
|
|
382
|
+
currentOutput = output;
|
|
383
|
+
executedCount++;
|
|
384
|
+
|
|
385
|
+
if (result.kind === "error") {
|
|
386
|
+
return { result, output: currentOutput, executedCount, aborted: false };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return { result: lastResult, output: currentOutput, executedCount, aborted: false };
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** Handle file redirection after command execution */
|
|
394
|
+
private async handleFileRedirection(
|
|
395
|
+
parsed: PipeParseResult,
|
|
396
|
+
output: string,
|
|
397
|
+
executedCount: number
|
|
398
|
+
): Promise<{ success: boolean; writtenFile?: string; error?: PipeExecutionResult }> {
|
|
399
|
+
if (!parsed.hasRedirect || !parsed.redirectTarget || !parsed.redirectMode) {
|
|
400
|
+
return { success: true };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (!this.writeFileFn) {
|
|
404
|
+
return {
|
|
405
|
+
success: false,
|
|
406
|
+
error: this.createErrorResult(
|
|
407
|
+
"INTERNAL_ERROR",
|
|
408
|
+
"File redirection not supported: no file writer configured",
|
|
409
|
+
output,
|
|
410
|
+
executedCount,
|
|
411
|
+
parsed.segments.length
|
|
412
|
+
),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
try {
|
|
417
|
+
await this.writeFileFn(parsed.redirectTarget, output, parsed.redirectMode);
|
|
418
|
+
return { success: true, writtenFile: parsed.redirectTarget };
|
|
419
|
+
} catch (err) {
|
|
420
|
+
return {
|
|
421
|
+
success: false,
|
|
422
|
+
error: this.createErrorResult(
|
|
423
|
+
"INTERNAL_ERROR",
|
|
424
|
+
`Failed to write to file '${parsed.redirectTarget}': ${err instanceof Error ? err.message : String(err)}`,
|
|
425
|
+
output,
|
|
426
|
+
executedCount,
|
|
427
|
+
parsed.segments.length
|
|
428
|
+
),
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Execute a piped command string
|
|
435
|
+
*
|
|
436
|
+
* @param input - Command string (may contain pipe operators)
|
|
437
|
+
* @param signal - Optional abort signal for cancellation
|
|
438
|
+
* @returns PipeExecutionResult with execution details
|
|
439
|
+
*/
|
|
440
|
+
async execute(input: string, signal?: AbortSignal): Promise<PipeExecutionResult> {
|
|
441
|
+
const parsed = PipeParser.parse(input);
|
|
442
|
+
|
|
443
|
+
if (!parsed.isPiped || parsed.segments.length === 0) {
|
|
444
|
+
const command = parsed.segments[0]?.value ?? input;
|
|
445
|
+
const { result, output } = await this.executeFn(command, undefined, signal);
|
|
446
|
+
return { result, output, executedCount: 1, totalCount: 1, completed: true };
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const commandSegments = parsed.segments.filter((s) => s.type === "command");
|
|
450
|
+
const seqResult = await this.executeCommandSequence(commandSegments, signal);
|
|
451
|
+
|
|
452
|
+
if (seqResult.aborted || seqResult.result.kind === "error") {
|
|
453
|
+
return {
|
|
454
|
+
result: seqResult.result,
|
|
455
|
+
output: seqResult.output,
|
|
456
|
+
executedCount: seqResult.executedCount,
|
|
457
|
+
totalCount: parsed.segments.length,
|
|
458
|
+
completed: false,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const redirectResult = await this.handleFileRedirection(
|
|
463
|
+
parsed,
|
|
464
|
+
seqResult.output,
|
|
465
|
+
seqResult.executedCount
|
|
466
|
+
);
|
|
467
|
+
if (!redirectResult.success && redirectResult.error) {
|
|
468
|
+
return redirectResult.error;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
result: seqResult.result,
|
|
473
|
+
output: seqResult.output,
|
|
474
|
+
executedCount: seqResult.executedCount,
|
|
475
|
+
totalCount: parsed.segments.length,
|
|
476
|
+
completed: true,
|
|
477
|
+
writtenFile: redirectResult.writtenFile,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
}
|