centaurus-cli 3.0.1 → 3.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/dist/ai/types.js +0 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/cli-adapter.js +5047 -5158
- package/dist/cli-adapter.js.map +1 -1
- package/dist/commands/CommandParser.js +372 -315
- package/dist/commands/CommandParser.js.map +1 -1
- package/dist/config/build-config.js +11 -42
- package/dist/config/build-config.js.map +1 -1
- package/dist/config/defaultConfig.js +94 -82
- package/dist/config/defaultConfig.js.map +1 -1
- package/dist/config/manager.js +144 -160
- package/dist/config/manager.js.map +1 -1
- package/dist/config/mcp-config-manager.js +411 -364
- package/dist/config/mcp-config-manager.js.map +1 -1
- package/dist/config/models.js +118 -185
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.js +186 -184
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.js +33 -26
- package/dist/config/types.js.map +1 -1
- package/dist/context/command-detector.js +63 -67
- package/dist/context/command-detector.js.map +1 -1
- package/dist/context/context-manager.js +533 -518
- package/dist/context/context-manager.js.map +1 -1
- package/dist/context/handlers/docker-handler.js +518 -576
- package/dist/context/handlers/docker-handler.js.map +1 -1
- package/dist/context/handlers/ssh-handler.js +1050 -1109
- package/dist/context/handlers/ssh-handler.js.map +1 -1
- package/dist/context/handlers/wsl-handler.js +558 -630
- package/dist/context/handlers/wsl-handler.js.map +1 -1
- package/dist/context/index.js +42 -6
- package/dist/context/index.js.map +1 -1
- package/dist/context/subshell-handler.js +0 -4
- package/dist/context/subshell-handler.js.map +1 -1
- package/dist/context/types.js +20 -31
- package/dist/context/types.js.map +1 -1
- package/dist/hooks/useConnectivity.js +13 -10
- package/dist/hooks/useConnectivity.js.map +1 -1
- package/dist/hooks/useTerminalDimensions.js +67 -79
- package/dist/hooks/useTerminalDimensions.js.map +1 -1
- package/dist/index.js +228 -251
- package/dist/index.js.map +1 -1
- package/dist/mcp/mcp-command-handler.js +297 -260
- package/dist/mcp/mcp-command-handler.js.map +1 -1
- package/dist/mcp/mcp-server-manager.js +139 -155
- package/dist/mcp/mcp-server-manager.js.map +1 -1
- package/dist/mcp/mcp-tool-wrapper.js +74 -94
- package/dist/mcp/mcp-tool-wrapper.js.map +1 -1
- package/dist/services/ai-autocomplete-agent.js +169 -181
- package/dist/services/ai-autocomplete-agent.js.map +1 -1
- package/dist/services/ai-context-injector.js +180 -93
- package/dist/services/ai-context-injector.js.map +1 -1
- package/dist/services/ai-service-client.js +513 -456
- package/dist/services/ai-service-client.js.map +1 -1
- package/dist/services/api-client.js +443 -441
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/auth-handler.js +162 -198
- package/dist/services/auth-handler.js.map +1 -1
- package/dist/services/background-task-manager.js +258 -282
- package/dist/services/background-task-manager.js.map +1 -1
- package/dist/services/checkpoint-manager.js +1526 -1512
- package/dist/services/checkpoint-manager.js.map +1 -1
- package/dist/services/clipboard-service.js +151 -200
- package/dist/services/clipboard-service.js.map +1 -1
- package/dist/services/connectivity-manager.js +63 -65
- package/dist/services/connectivity-manager.js.map +1 -1
- package/dist/services/conversation-manager.js +118 -121
- package/dist/services/conversation-manager.js.map +1 -1
- package/dist/services/environment-context-injector.js +160 -187
- package/dist/services/environment-context-injector.js.map +1 -1
- package/dist/services/fast-context-agent.js +203 -243
- package/dist/services/fast-context-agent.js.map +1 -1
- package/dist/services/input-detection-agent.js +190 -202
- package/dist/services/input-detection-agent.js.map +1 -1
- package/dist/services/input-requirement-detector.js +155 -189
- package/dist/services/input-requirement-detector.js.map +1 -1
- package/dist/services/local-chat-storage.js +342 -365
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/monitored-shell-manager.js +225 -233
- package/dist/services/monitored-shell-manager.js.map +1 -1
- package/dist/services/ollama-service.js +293 -310
- package/dist/services/ollama-service.js.map +1 -1
- package/dist/services/rules-storage.js +142 -0
- package/dist/services/rules-storage.js.map +1 -0
- package/dist/services/session-quota-manager.js +219 -235
- package/dist/services/session-quota-manager.js.map +1 -1
- package/dist/services/shell-input-agent.js +299 -334
- package/dist/services/shell-input-agent.js.map +1 -1
- package/dist/services/sub-agent-manager.js +459 -501
- package/dist/services/sub-agent-manager.js.map +1 -1
- package/dist/services/warpify-detector.js +133 -183
- package/dist/services/warpify-detector.js.map +1 -1
- package/dist/services/workflow-storage.js +202 -217
- package/dist/services/workflow-storage.js.map +1 -1
- package/dist/test-ssh-handler.js +148 -193
- package/dist/test-ssh-handler.js.map +1 -1
- package/dist/tools/add-mcp.js +161 -0
- package/dist/tools/add-mcp.js.map +1 -0
- package/dist/tools/background-command.js +240 -273
- package/dist/tools/background-command.js.map +1 -1
- package/dist/tools/command.js +447 -440
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/create-image.js +172 -202
- package/dist/tools/create-image.js.map +1 -1
- package/dist/tools/enter-remote-session.js +169 -215
- package/dist/tools/enter-remote-session.js.map +1 -1
- package/dist/tools/fast-context.js +60 -67
- package/dist/tools/fast-context.js.map +1 -1
- package/dist/tools/file-ops.js +601 -572
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/find-files.js +262 -303
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/get-diff.js +423 -406
- package/dist/tools/get-diff.js.map +1 -1
- package/dist/tools/grep-search.js +966 -948
- package/dist/tools/grep-search.js.map +1 -1
- package/dist/tools/inspect-symbol.js +308 -323
- package/dist/tools/inspect-symbol.js.map +1 -1
- package/dist/tools/plan-mode.js +459 -503
- package/dist/tools/plan-mode.js.map +1 -1
- package/dist/tools/read-binary-file.js +160 -190
- package/dist/tools/read-binary-file.js.map +1 -1
- package/dist/tools/registry.js +100 -84
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/reproduce_issue.js +170 -151
- package/dist/tools/reproduce_issue.js.map +1 -1
- package/dist/tools/sub-agent.js +223 -228
- package/dist/tools/sub-agent.js.map +1 -1
- package/dist/tools/task-complete.js +28 -27
- package/dist/tools/task-complete.js.map +1 -1
- package/dist/tools/types.js +0 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/validation.js +96 -118
- package/dist/tools/validation.js.map +1 -1
- package/dist/tools/web-search.js +194 -194
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools/workflow-tool.js +77 -82
- package/dist/tools/workflow-tool.js.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/rule.js +1 -0
- package/dist/types/rule.js.map +1 -0
- package/dist/types/workflow.js +0 -7
- package/dist/types/workflow.js.map +1 -1
- package/dist/ui/components/AgentTimer.js +24 -25
- package/dist/ui/components/AgentTimer.js.map +1 -1
- package/dist/ui/components/App.js +3266 -3263
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/AuthScreen.js +22 -34
- package/dist/ui/components/AuthScreen.js.map +1 -1
- package/dist/ui/components/AuthWelcomeScreen.js +30 -24
- package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
- package/dist/ui/components/Breadcrumbs.js +53 -82
- package/dist/ui/components/Breadcrumbs.js.map +1 -1
- package/dist/ui/components/CircularSelectInput.js +59 -67
- package/dist/ui/components/CircularSelectInput.js.map +1 -1
- package/dist/ui/components/ClipboardFileAutocomplete.js +78 -39
- package/dist/ui/components/ClipboardFileAutocomplete.js.map +1 -1
- package/dist/ui/components/CodeBlock.js +24 -42
- package/dist/ui/components/CodeBlock.js.map +1 -1
- package/dist/ui/components/ConfigViewer.js +18 -25
- package/dist/ui/components/ConfigViewer.js.map +1 -1
- package/dist/ui/components/ConfirmPrompt.js +49 -71
- package/dist/ui/components/ConfirmPrompt.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +32 -83
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/ContextWindowIndicator.js +34 -49
- package/dist/ui/components/ContextWindowIndicator.js.map +1 -1
- package/dist/ui/components/DetailedPlanReviewScreen.js +104 -106
- package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
- package/dist/ui/components/DiffViewer.js +68 -121
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/ErrorBoundary.js +40 -48
- package/dist/ui/components/ErrorBoundary.js.map +1 -1
- package/dist/ui/components/FileCreationPreview.js +29 -60
- package/dist/ui/components/FileCreationPreview.js.map +1 -1
- package/dist/ui/components/FileOperation.js +34 -29
- package/dist/ui/components/FileOperation.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.js +55 -25
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
- package/dist/ui/components/FontRecommendation.js.map +1 -1
- package/dist/ui/components/GitDiffBreadcrumb.js +29 -0
- package/dist/ui/components/GitDiffBreadcrumb.js.map +1 -0
- package/dist/ui/components/InputBox.js +1620 -2150
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.js +234 -352
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/KeyboardHelp.js +34 -35
- package/dist/ui/components/KeyboardHelp.js.map +1 -1
- package/dist/ui/components/LoadingIndicator.js +22 -25
- package/dist/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/ui/components/MCPAddScreen.js +40 -51
- package/dist/ui/components/MCPAddScreen.js.map +1 -1
- package/dist/ui/components/MCPListScreen.js +40 -48
- package/dist/ui/components/MCPListScreen.js.map +1 -1
- package/dist/ui/components/MCPServerListScreen.js +49 -56
- package/dist/ui/components/MCPServerListScreen.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +69 -96
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageBox.js +66 -48
- package/dist/ui/components/MessageBox.js.map +1 -1
- package/dist/ui/components/MessageDisplay.js +150 -142
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/MonitorModeAIPanel.js +46 -65
- package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
- package/dist/ui/components/MultiLineInput.js +243 -277
- package/dist/ui/components/MultiLineInput.js.map +1 -1
- package/dist/ui/components/PasswordPrompt.js +37 -18
- package/dist/ui/components/PasswordPrompt.js.map +1 -1
- package/dist/ui/components/PlanAcceptedMessage.js +27 -38
- package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
- package/dist/ui/components/PlanReviewScreen.js +46 -50
- package/dist/ui/components/PlanReviewScreen.js.map +1 -1
- package/dist/ui/components/RulesEditorScreen.js +81 -0
- package/dist/ui/components/RulesEditorScreen.js.map +1 -0
- package/dist/ui/components/SelectPrompt.js +19 -8
- package/dist/ui/components/SelectPrompt.js.map +1 -1
- package/dist/ui/components/ShimmerText.js +44 -0
- package/dist/ui/components/ShimmerText.js.map +1 -0
- package/dist/ui/components/SlashCommandAutocomplete.js +49 -22
- package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
- package/dist/ui/components/StatusBar.js +56 -87
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +116 -99
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/TaskCompletedMessage.js +28 -23
- package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
- package/dist/ui/components/TaskProgressIndicator.js +44 -70
- package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
- package/dist/ui/components/ThinkingDisplay.js +44 -41
- package/dist/ui/components/ThinkingDisplay.js.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.js +772 -1326
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/ToolExecutionStatus.js +53 -84
- package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
- package/dist/ui/components/ToolResult.js +22 -15
- package/dist/ui/components/ToolResult.js.map +1 -1
- package/dist/ui/components/VersionUpdatePrompt.js +88 -120
- package/dist/ui/components/VersionUpdatePrompt.js.map +1 -1
- package/dist/ui/components/WelcomeBanner.js +176 -26
- package/dist/ui/components/WelcomeBanner.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.js +94 -161
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
- package/dist/utils/ansi-encoder.js +30 -61
- package/dist/utils/ansi-encoder.js.map +1 -1
- package/dist/utils/chat-formatter.js +327 -305
- package/dist/utils/chat-formatter.js.map +1 -1
- package/dist/utils/command-history.js +152 -174
- package/dist/utils/command-history.js.map +1 -1
- package/dist/utils/context-sanitizer.js +49 -112
- package/dist/utils/context-sanitizer.js.map +1 -1
- package/dist/utils/conversation-logger.js +292 -324
- package/dist/utils/conversation-logger.js.map +1 -1
- package/dist/utils/custom-commands-manager.js +126 -131
- package/dist/utils/custom-commands-manager.js.map +1 -1
- package/dist/utils/editor-utils.js +732 -837
- package/dist/utils/editor-utils.js.map +1 -1
- package/dist/utils/file.js +174 -213
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/git-stats.js +169 -0
- package/dist/utils/git-stats.js.map +1 -0
- package/dist/utils/input-classifier.js +960 -482
- package/dist/utils/input-classifier.js.map +1 -1
- package/dist/utils/logger.js +48 -73
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/markdown-parser.js +277 -310
- package/dist/utils/markdown-parser.js.map +1 -1
- package/dist/utils/rule-reference-resolver.js +54 -0
- package/dist/utils/rule-reference-resolver.js.map +1 -0
- package/dist/utils/shell.js +144 -156
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/state.js +23 -22
- package/dist/utils/state.js.map +1 -1
- package/dist/utils/syntax-checker.js +279 -327
- package/dist/utils/syntax-checker.js.map +1 -1
- package/dist/utils/terminal-output.js +199 -302
- package/dist/utils/terminal-output.js.map +1 -1
- package/dist/utils/text-clipboard.js +47 -70
- package/dist/utils/text-clipboard.js.map +1 -1
- package/dist/utils/unicode-sanitizer.js +134 -197
- package/dist/utils/unicode-sanitizer.js.map +1 -1
- package/dist/utils/version-checker.js +46 -56
- package/dist/utils/version-checker.js.map +1 -1
- package/package.json +6 -4
- package/dist/ai/types.d.ts +0 -20
- package/dist/ai/types.d.ts.map +0 -1
- package/dist/cli-adapter.d.ts +0 -514
- package/dist/cli-adapter.d.ts.map +0 -1
- package/dist/commands/CommandParser.d.ts +0 -27
- package/dist/commands/CommandParser.d.ts.map +0 -1
- package/dist/config/build-config.d.ts +0 -42
- package/dist/config/build-config.d.ts.map +0 -1
- package/dist/config/defaultConfig.d.ts +0 -79
- package/dist/config/defaultConfig.d.ts.map +0 -1
- package/dist/config/manager.d.ts +0 -62
- package/dist/config/manager.d.ts.map +0 -1
- package/dist/config/mcp-config-manager.d.ts +0 -79
- package/dist/config/mcp-config-manager.d.ts.map +0 -1
- package/dist/config/models.d.ts +0 -83
- package/dist/config/models.d.ts.map +0 -1
- package/dist/config/slash-commands.d.ts +0 -23
- package/dist/config/slash-commands.d.ts.map +0 -1
- package/dist/config/types.d.ts +0 -35
- package/dist/config/types.d.ts.map +0 -1
- package/dist/context/command-detector.d.ts +0 -50
- package/dist/context/command-detector.d.ts.map +0 -1
- package/dist/context/context-manager.d.ts +0 -157
- package/dist/context/context-manager.d.ts.map +0 -1
- package/dist/context/handlers/docker-handler.d.ts +0 -130
- package/dist/context/handlers/docker-handler.d.ts.map +0 -1
- package/dist/context/handlers/ssh-handler.d.ts +0 -201
- package/dist/context/handlers/ssh-handler.d.ts.map +0 -1
- package/dist/context/handlers/wsl-handler.d.ts +0 -146
- package/dist/context/handlers/wsl-handler.d.ts.map +0 -1
- package/dist/context/index.d.ts +0 -8
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/subshell-handler.d.ts +0 -165
- package/dist/context/subshell-handler.d.ts.map +0 -1
- package/dist/context/types.d.ts +0 -70
- package/dist/context/types.d.ts.map +0 -1
- package/dist/hooks/useConnectivity.d.ts +0 -2
- package/dist/hooks/useConnectivity.d.ts.map +0 -1
- package/dist/hooks/useTerminalDimensions.d.ts +0 -41
- package/dist/hooks/useTerminalDimensions.d.ts.map +0 -1
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +0 -1
- package/dist/mcp/mcp-command-handler.d.ts +0 -47
- package/dist/mcp/mcp-command-handler.d.ts.map +0 -1
- package/dist/mcp/mcp-server-manager.d.ts +0 -30
- package/dist/mcp/mcp-server-manager.d.ts.map +0 -1
- package/dist/mcp/mcp-tool-wrapper.d.ts +0 -12
- package/dist/mcp/mcp-tool-wrapper.d.ts.map +0 -1
- package/dist/services/ai-autocomplete-agent.d.ts +0 -39
- package/dist/services/ai-autocomplete-agent.d.ts.map +0 -1
- package/dist/services/ai-context-injector.d.ts +0 -41
- package/dist/services/ai-context-injector.d.ts.map +0 -1
- package/dist/services/ai-service-client.d.ts +0 -128
- package/dist/services/ai-service-client.d.ts.map +0 -1
- package/dist/services/api-client.d.ts +0 -353
- package/dist/services/api-client.d.ts.map +0 -1
- package/dist/services/auth-handler.d.ts +0 -30
- package/dist/services/auth-handler.d.ts.map +0 -1
- package/dist/services/background-task-manager.d.ts +0 -114
- package/dist/services/background-task-manager.d.ts.map +0 -1
- package/dist/services/checkpoint-manager.d.ts +0 -204
- package/dist/services/checkpoint-manager.d.ts.map +0 -1
- package/dist/services/clipboard-service.d.ts +0 -37
- package/dist/services/clipboard-service.d.ts.map +0 -1
- package/dist/services/connectivity-manager.d.ts +0 -18
- package/dist/services/connectivity-manager.d.ts.map +0 -1
- package/dist/services/conversation-manager.d.ts +0 -73
- package/dist/services/conversation-manager.d.ts.map +0 -1
- package/dist/services/environment-context-injector.d.ts +0 -69
- package/dist/services/environment-context-injector.d.ts.map +0 -1
- package/dist/services/fast-context-agent.d.ts +0 -12
- package/dist/services/fast-context-agent.d.ts.map +0 -1
- package/dist/services/input-detection-agent.d.ts +0 -40
- package/dist/services/input-detection-agent.d.ts.map +0 -1
- package/dist/services/input-requirement-detector.d.ts +0 -28
- package/dist/services/input-requirement-detector.d.ts.map +0 -1
- package/dist/services/local-chat-storage.d.ts +0 -182
- package/dist/services/local-chat-storage.d.ts.map +0 -1
- package/dist/services/monitored-shell-manager.d.ts +0 -120
- package/dist/services/monitored-shell-manager.d.ts.map +0 -1
- package/dist/services/ollama-service.d.ts +0 -197
- package/dist/services/ollama-service.d.ts.map +0 -1
- package/dist/services/session-quota-manager.d.ts +0 -101
- package/dist/services/session-quota-manager.d.ts.map +0 -1
- package/dist/services/shell-input-agent.d.ts +0 -89
- package/dist/services/shell-input-agent.d.ts.map +0 -1
- package/dist/services/sub-agent-manager.d.ts +0 -140
- package/dist/services/sub-agent-manager.d.ts.map +0 -1
- package/dist/services/warpify-detector.d.ts +0 -43
- package/dist/services/warpify-detector.d.ts.map +0 -1
- package/dist/services/workflow-storage.d.ts +0 -72
- package/dist/services/workflow-storage.d.ts.map +0 -1
- package/dist/test-ssh-handler.d.ts +0 -8
- package/dist/test-ssh-handler.d.ts.map +0 -1
- package/dist/tools/background-command.d.ts +0 -11
- package/dist/tools/background-command.d.ts.map +0 -1
- package/dist/tools/command.d.ts +0 -3
- package/dist/tools/command.d.ts.map +0 -1
- package/dist/tools/create-image.d.ts +0 -10
- package/dist/tools/create-image.d.ts.map +0 -1
- package/dist/tools/enter-remote-session.d.ts +0 -48
- package/dist/tools/enter-remote-session.d.ts.map +0 -1
- package/dist/tools/fast-context.d.ts +0 -3
- package/dist/tools/fast-context.d.ts.map +0 -1
- package/dist/tools/file-ops.d.ts +0 -7
- package/dist/tools/file-ops.d.ts.map +0 -1
- package/dist/tools/find-files.d.ts +0 -49
- package/dist/tools/find-files.d.ts.map +0 -1
- package/dist/tools/get-diff.d.ts +0 -14
- package/dist/tools/get-diff.d.ts.map +0 -1
- package/dist/tools/grep-search.d.ts +0 -155
- package/dist/tools/grep-search.d.ts.map +0 -1
- package/dist/tools/inspect-symbol.d.ts +0 -32
- package/dist/tools/inspect-symbol.d.ts.map +0 -1
- package/dist/tools/plan-mode.d.ts +0 -140
- package/dist/tools/plan-mode.d.ts.map +0 -1
- package/dist/tools/read-binary-file.d.ts +0 -10
- package/dist/tools/read-binary-file.d.ts.map +0 -1
- package/dist/tools/registry.d.ts +0 -31
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/reproduce_issue.d.ts +0 -2
- package/dist/tools/reproduce_issue.d.ts.map +0 -1
- package/dist/tools/sub-agent.d.ts +0 -9
- package/dist/tools/sub-agent.d.ts.map +0 -1
- package/dist/tools/task-complete.d.ts +0 -3
- package/dist/tools/task-complete.d.ts.map +0 -1
- package/dist/tools/types.d.ts +0 -40
- package/dist/tools/types.d.ts.map +0 -1
- package/dist/tools/validation.d.ts +0 -47
- package/dist/tools/validation.d.ts.map +0 -1
- package/dist/tools/web-search.d.ts +0 -24
- package/dist/tools/web-search.d.ts.map +0 -1
- package/dist/tools/workflow-tool.d.ts +0 -11
- package/dist/tools/workflow-tool.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -123
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/workflow.d.ts +0 -110
- package/dist/types/workflow.d.ts.map +0 -1
- package/dist/ui/components/AgentTimer.d.ts +0 -7
- package/dist/ui/components/AgentTimer.d.ts.map +0 -1
- package/dist/ui/components/App.d.ts +0 -197
- package/dist/ui/components/App.d.ts.map +0 -1
- package/dist/ui/components/AuthScreen.d.ts +0 -8
- package/dist/ui/components/AuthScreen.d.ts.map +0 -1
- package/dist/ui/components/AuthWelcomeScreen.d.ts +0 -8
- package/dist/ui/components/AuthWelcomeScreen.d.ts.map +0 -1
- package/dist/ui/components/Breadcrumbs.d.ts +0 -13
- package/dist/ui/components/Breadcrumbs.d.ts.map +0 -1
- package/dist/ui/components/CircularSelectInput.d.ts +0 -24
- package/dist/ui/components/CircularSelectInput.d.ts.map +0 -1
- package/dist/ui/components/ClipboardFileAutocomplete.d.ts +0 -10
- package/dist/ui/components/ClipboardFileAutocomplete.d.ts.map +0 -1
- package/dist/ui/components/CodeBlock.d.ts +0 -9
- package/dist/ui/components/CodeBlock.d.ts.map +0 -1
- package/dist/ui/components/ConfigViewer.d.ts +0 -11
- package/dist/ui/components/ConfigViewer.d.ts.map +0 -1
- package/dist/ui/components/ConfirmPrompt.d.ts +0 -13
- package/dist/ui/components/ConfirmPrompt.d.ts.map +0 -1
- package/dist/ui/components/ConnectionStatusMessage.d.ts +0 -17
- package/dist/ui/components/ConnectionStatusMessage.d.ts.map +0 -1
- package/dist/ui/components/ContextWindowIndicator.d.ts +0 -8
- package/dist/ui/components/ContextWindowIndicator.d.ts.map +0 -1
- package/dist/ui/components/DetailedPlanReviewScreen.d.ts +0 -17
- package/dist/ui/components/DetailedPlanReviewScreen.d.ts.map +0 -1
- package/dist/ui/components/DiffViewer.d.ts +0 -9
- package/dist/ui/components/DiffViewer.d.ts.map +0 -1
- package/dist/ui/components/ErrorBoundary.d.ts +0 -17
- package/dist/ui/components/ErrorBoundary.d.ts.map +0 -1
- package/dist/ui/components/FileCreationPreview.d.ts +0 -8
- package/dist/ui/components/FileCreationPreview.d.ts.map +0 -1
- package/dist/ui/components/FileOperation.d.ts +0 -10
- package/dist/ui/components/FileOperation.d.ts.map +0 -1
- package/dist/ui/components/FileTagAutocomplete.d.ts +0 -11
- package/dist/ui/components/FileTagAutocomplete.d.ts.map +0 -1
- package/dist/ui/components/FontRecommendation.d.ts +0 -1
- package/dist/ui/components/FontRecommendation.d.ts.map +0 -1
- package/dist/ui/components/InputBox.d.ts +0 -42
- package/dist/ui/components/InputBox.d.ts.map +0 -1
- package/dist/ui/components/InteractiveShell.d.ts +0 -30
- package/dist/ui/components/InteractiveShell.d.ts.map +0 -1
- package/dist/ui/components/KeyboardHelp.d.ts +0 -7
- package/dist/ui/components/KeyboardHelp.d.ts.map +0 -1
- package/dist/ui/components/LoadingIndicator.d.ts +0 -3
- package/dist/ui/components/LoadingIndicator.d.ts.map +0 -1
- package/dist/ui/components/MCPAddScreen.d.ts +0 -13
- package/dist/ui/components/MCPAddScreen.d.ts.map +0 -1
- package/dist/ui/components/MCPListScreen.d.ts +0 -17
- package/dist/ui/components/MCPListScreen.d.ts.map +0 -1
- package/dist/ui/components/MCPServerListScreen.d.ts +0 -16
- package/dist/ui/components/MCPServerListScreen.d.ts.map +0 -1
- package/dist/ui/components/MarkdownRenderer.d.ts +0 -8
- package/dist/ui/components/MarkdownRenderer.d.ts.map +0 -1
- package/dist/ui/components/MessageBox.d.ts +0 -10
- package/dist/ui/components/MessageBox.d.ts.map +0 -1
- package/dist/ui/components/MessageDisplay.d.ts +0 -14
- package/dist/ui/components/MessageDisplay.d.ts.map +0 -1
- package/dist/ui/components/MonitorModeAIPanel.d.ts +0 -23
- package/dist/ui/components/MonitorModeAIPanel.d.ts.map +0 -1
- package/dist/ui/components/MultiLineInput.d.ts +0 -13
- package/dist/ui/components/MultiLineInput.d.ts.map +0 -1
- package/dist/ui/components/PasswordPrompt.d.ts +0 -9
- package/dist/ui/components/PasswordPrompt.d.ts.map +0 -1
- package/dist/ui/components/PlanAcceptedMessage.d.ts +0 -20
- package/dist/ui/components/PlanAcceptedMessage.d.ts.map +0 -1
- package/dist/ui/components/PlanReviewScreen.d.ts +0 -14
- package/dist/ui/components/PlanReviewScreen.d.ts.map +0 -1
- package/dist/ui/components/SelectPrompt.d.ts +0 -12
- package/dist/ui/components/SelectPrompt.d.ts.map +0 -1
- package/dist/ui/components/SlashCommandAutocomplete.d.ts +0 -13
- package/dist/ui/components/SlashCommandAutocomplete.d.ts.map +0 -1
- package/dist/ui/components/StatusBar.d.ts +0 -14
- package/dist/ui/components/StatusBar.d.ts.map +0 -1
- package/dist/ui/components/StreamingMessageDisplay.d.ts +0 -15
- package/dist/ui/components/StreamingMessageDisplay.d.ts.map +0 -1
- package/dist/ui/components/TaskCompletedMessage.d.ts +0 -14
- package/dist/ui/components/TaskCompletedMessage.d.ts.map +0 -1
- package/dist/ui/components/TaskProgressIndicator.d.ts +0 -18
- package/dist/ui/components/TaskProgressIndicator.d.ts.map +0 -1
- package/dist/ui/components/ThinkingDisplay.d.ts +0 -15
- package/dist/ui/components/ThinkingDisplay.d.ts.map +0 -1
- package/dist/ui/components/ToolExecutionMessage.d.ts +0 -8
- package/dist/ui/components/ToolExecutionMessage.d.ts.map +0 -1
- package/dist/ui/components/ToolExecutionStatus.d.ts +0 -10
- package/dist/ui/components/ToolExecutionStatus.d.ts.map +0 -1
- package/dist/ui/components/ToolResult.d.ts +0 -10
- package/dist/ui/components/ToolResult.d.ts.map +0 -1
- package/dist/ui/components/VersionUpdatePrompt.d.ts +0 -9
- package/dist/ui/components/VersionUpdatePrompt.d.ts.map +0 -1
- package/dist/ui/components/WelcomeBanner.d.ts +0 -3
- package/dist/ui/components/WelcomeBanner.d.ts.map +0 -1
- package/dist/ui/components/WorkflowCreatorScreen.d.ts +0 -25
- package/dist/ui/components/WorkflowCreatorScreen.d.ts.map +0 -1
- package/dist/utils/ansi-encoder.d.ts +0 -7
- package/dist/utils/ansi-encoder.d.ts.map +0 -1
- package/dist/utils/chat-formatter.d.ts +0 -12
- package/dist/utils/chat-formatter.d.ts.map +0 -1
- package/dist/utils/command-history.d.ts +0 -24
- package/dist/utils/command-history.d.ts.map +0 -1
- package/dist/utils/context-sanitizer.d.ts +0 -50
- package/dist/utils/context-sanitizer.d.ts.map +0 -1
- package/dist/utils/conversation-logger.d.ts +0 -142
- package/dist/utils/conversation-logger.d.ts.map +0 -1
- package/dist/utils/custom-commands-manager.d.ts +0 -59
- package/dist/utils/custom-commands-manager.d.ts.map +0 -1
- package/dist/utils/editor-utils.d.ts +0 -101
- package/dist/utils/editor-utils.d.ts.map +0 -1
- package/dist/utils/file.d.ts +0 -61
- package/dist/utils/file.d.ts.map +0 -1
- package/dist/utils/input-classifier.d.ts +0 -25
- package/dist/utils/input-classifier.d.ts.map +0 -1
- package/dist/utils/logger.d.ts +0 -17
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/markdown-parser.d.ts +0 -60
- package/dist/utils/markdown-parser.d.ts.map +0 -1
- package/dist/utils/shell.d.ts +0 -47
- package/dist/utils/shell.d.ts.map +0 -1
- package/dist/utils/state.d.ts +0 -13
- package/dist/utils/state.d.ts.map +0 -1
- package/dist/utils/syntax-checker.d.ts +0 -24
- package/dist/utils/syntax-checker.d.ts.map +0 -1
- package/dist/utils/terminal-output.d.ts +0 -25
- package/dist/utils/terminal-output.d.ts.map +0 -1
- package/dist/utils/text-clipboard.d.ts +0 -12
- package/dist/utils/text-clipboard.d.ts.map +0 -1
- package/dist/utils/unicode-sanitizer.d.ts +0 -44
- package/dist/utils/unicode-sanitizer.d.ts.map +0 -1
- package/dist/utils/version-checker.d.ts +0 -14
- package/dist/utils/version-checker.d.ts.map +0 -1
|
@@ -1,649 +1,577 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import { SubshellConnectionError, SubshellExecutionError } from '../types.js';
|
|
7
|
-
import { randomBytes } from 'crypto';
|
|
8
|
-
import * as os from 'os';
|
|
1
|
+
import { exec, spawn } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import { SubshellConnectionError, SubshellExecutionError } from "../types.js";
|
|
4
|
+
import { randomBytes } from "crypto";
|
|
5
|
+
import * as os from "os";
|
|
9
6
|
const execAsync = promisify(exec);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (this.shellProcess && this.shellProcess.stdin && !this.shellProcess.stdin.destroyed) {
|
|
42
|
-
this.shellProcess.stdin.write(data);
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Detect if a command should trigger this handler
|
|
49
|
-
*/
|
|
50
|
-
detect(command) {
|
|
51
|
-
return this.detectionPatterns.some(pattern => pattern.test(command));
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Connect to the WSL environment
|
|
55
|
-
*/
|
|
56
|
-
async connect(command, cwd) {
|
|
57
|
-
this.sessionId = randomBytes(16).toString('hex');
|
|
58
|
-
try {
|
|
59
|
-
// Verify WSL is available (Windows only)
|
|
60
|
-
this.verifyWSLAvailable();
|
|
61
|
-
// Parse WSL command to extract distribution
|
|
62
|
-
this.config = await this.parseWSLCommand(command);
|
|
63
|
-
// Spawn interactive shell
|
|
64
|
-
await this.spawnInteractiveShell();
|
|
65
|
-
// Detect shell type
|
|
66
|
-
this.shellType = await this.detectShellType();
|
|
67
|
-
// Get initial working directory
|
|
68
|
-
this.currentWorkingDirectory = await this.getCurrentWorkingDirectory();
|
|
69
|
-
return {
|
|
70
|
-
type: 'wsl',
|
|
71
|
-
handler: this,
|
|
72
|
-
metadata: {
|
|
73
|
-
workingDirectory: this.currentWorkingDirectory,
|
|
74
|
-
shell: this.shellType,
|
|
75
|
-
os: 'linux',
|
|
76
|
-
distroName: this.config.distribution,
|
|
77
|
-
},
|
|
78
|
-
connectionState: 'connected',
|
|
79
|
-
sessionId: this.sessionId,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
throw new SubshellConnectionError('wsl', error instanceof Error ? error.message : 'Unknown error', false);
|
|
84
|
-
}
|
|
7
|
+
class WSLHandler {
|
|
8
|
+
type = "wsl";
|
|
9
|
+
detectionPatterns = [
|
|
10
|
+
/^wsl$/,
|
|
11
|
+
/^wsl\s+/,
|
|
12
|
+
/^wsl\.exe\s+/
|
|
13
|
+
];
|
|
14
|
+
config = null;
|
|
15
|
+
currentWorkingDirectory = "~";
|
|
16
|
+
shellType = "bash";
|
|
17
|
+
sessionId = "";
|
|
18
|
+
shellProcess = null;
|
|
19
|
+
commandQueue = [];
|
|
20
|
+
currentOutput = "";
|
|
21
|
+
currentError = "";
|
|
22
|
+
// Streaming output callback for real-time display
|
|
23
|
+
onOutputCallback = null;
|
|
24
|
+
/**
|
|
25
|
+
* Set a callback to receive real-time output from commands
|
|
26
|
+
* This is essential for interactive commands like sudo that need user input
|
|
27
|
+
*/
|
|
28
|
+
setOutputCallback(callback) {
|
|
29
|
+
this.onOutputCallback = callback;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Write data to the shell's stdin (for user input like passwords)
|
|
33
|
+
*/
|
|
34
|
+
writeToStdin(data) {
|
|
35
|
+
if (this.shellProcess && this.shellProcess.stdin && !this.shellProcess.stdin.destroyed) {
|
|
36
|
+
this.shellProcess.stdin.write(data);
|
|
37
|
+
return true;
|
|
85
38
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
this.currentError += text;
|
|
124
|
-
errorOutput += text;
|
|
125
|
-
// Stream to callback if registered (for real-time UI display)
|
|
126
|
-
if (this.onOutputCallback) {
|
|
127
|
-
this.onOutputCallback(text, 'stderr');
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
this.shellProcess.on('exit', (code) => {
|
|
131
|
-
if (!hasResolved) {
|
|
132
|
-
hasResolved = true;
|
|
133
|
-
// Check for common WSL errors
|
|
134
|
-
if (errorOutput.includes('HCS_E_SERVICE_NOT_AVAILABLE')) {
|
|
135
|
-
reject(new Error('WSL service is not running. Try running "wsl --shutdown" and then try again, or restart your computer.'));
|
|
136
|
-
}
|
|
137
|
-
else if (errorOutput.includes('required feature is not installed')) {
|
|
138
|
-
reject(new Error('WSL is not properly installed or enabled. Please ensure WSL 2 is installed and the Virtual Machine Platform feature is enabled.'));
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
reject(new Error(`WSL process exited with code ${code}. Error: ${errorOutput || 'No error output'}`));
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
this.shellProcess = null;
|
|
145
|
-
});
|
|
146
|
-
this.shellProcess.on('error', (error) => {
|
|
147
|
-
if (!hasResolved) {
|
|
148
|
-
hasResolved = true;
|
|
149
|
-
reject(new Error(`Failed to spawn WSL process: ${error.message}`));
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
// Wait for stdin to be ready, then send initialization command
|
|
153
|
-
const sendInitCommand = () => {
|
|
154
|
-
if (!initCommandSent && this.shellProcess && this.shellProcess.stdin && !this.shellProcess.stdin.destroyed) {
|
|
155
|
-
initCommandSent = true;
|
|
156
|
-
this.shellProcess.stdin.write('echo "CENTAURUS_READY"\n');
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
// Try to send command immediately if stdin is already writable
|
|
160
|
-
if (this.shellProcess.stdin.writable) {
|
|
161
|
-
sendInitCommand();
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
// Otherwise wait for the 'ready' event on stdin
|
|
165
|
-
this.shellProcess.stdin.once('ready', sendInitCommand);
|
|
166
|
-
}
|
|
167
|
-
// Fallback: also try after a small delay in case ready event doesn't fire
|
|
168
|
-
setTimeout(() => {
|
|
169
|
-
sendInitCommand();
|
|
170
|
-
}, 200);
|
|
171
|
-
// Timeout if we don't get a response
|
|
172
|
-
// WSL cold-start can take 10+ seconds on first run
|
|
173
|
-
setTimeout(() => {
|
|
174
|
-
if (!hasResolved) {
|
|
175
|
-
hasResolved = true;
|
|
176
|
-
reject(new Error(`WSL shell initialization timed out. Error: ${errorOutput || 'No error output'}`));
|
|
177
|
-
}
|
|
178
|
-
}, 15000);
|
|
179
|
-
});
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Detect if a command should trigger this handler
|
|
43
|
+
*/
|
|
44
|
+
detect(command) {
|
|
45
|
+
return this.detectionPatterns.some((pattern) => pattern.test(command));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Connect to the WSL environment
|
|
49
|
+
*/
|
|
50
|
+
async connect(command, cwd) {
|
|
51
|
+
this.sessionId = randomBytes(16).toString("hex");
|
|
52
|
+
try {
|
|
53
|
+
this.verifyWSLAvailable();
|
|
54
|
+
this.config = await this.parseWSLCommand(command);
|
|
55
|
+
await this.spawnInteractiveShell();
|
|
56
|
+
this.shellType = await this.detectShellType();
|
|
57
|
+
this.currentWorkingDirectory = await this.getCurrentWorkingDirectory();
|
|
58
|
+
return {
|
|
59
|
+
type: "wsl",
|
|
60
|
+
handler: this,
|
|
61
|
+
metadata: {
|
|
62
|
+
workingDirectory: this.currentWorkingDirectory,
|
|
63
|
+
shell: this.shellType,
|
|
64
|
+
os: "linux",
|
|
65
|
+
distroName: this.config.distribution
|
|
66
|
+
},
|
|
67
|
+
connectionState: "connected",
|
|
68
|
+
sessionId: this.sessionId
|
|
69
|
+
};
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw new SubshellConnectionError(
|
|
72
|
+
"wsl",
|
|
73
|
+
error instanceof Error ? error.message : "Unknown error",
|
|
74
|
+
false
|
|
75
|
+
);
|
|
180
76
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (!this.shellProcess.stdin) {
|
|
208
|
-
throw new SubshellExecutionError(command, 'Not connected to WSL - stdin is null');
|
|
209
|
-
}
|
|
210
|
-
if (this.shellProcess.killed || this.shellProcess.exitCode !== null) {
|
|
211
|
-
throw new SubshellExecutionError(command, 'Not connected to WSL - shell process has exited');
|
|
212
|
-
}
|
|
213
|
-
try {
|
|
214
|
-
// Clear previous output
|
|
215
|
-
this.currentOutput = '';
|
|
216
|
-
this.currentError = '';
|
|
217
|
-
// Unique PWD tag for this session
|
|
218
|
-
const pwdTag = `__CENTAURUS_PWD_${this.sessionId}__`;
|
|
219
|
-
// Build command with pwd tracking
|
|
220
|
-
let commandWithPwd;
|
|
221
|
-
const trimmedCommand = command.trim();
|
|
222
|
-
// Check if this is a cd command
|
|
223
|
-
if (trimmedCommand.startsWith('cd ') || trimmedCommand === 'cd') {
|
|
224
|
-
// For cd commands, execute directly without prepending current directory
|
|
225
|
-
// The shell maintains its own state
|
|
226
|
-
commandWithPwd = `${command}; echo "${pwdTag}:$(pwd)"\n`;
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
// For other commands, ensure we're in the right directory first
|
|
230
|
-
commandWithPwd = `cd ${this.currentWorkingDirectory} && ${command}; echo "${pwdTag}:$(pwd)"\n`;
|
|
231
|
-
}
|
|
232
|
-
// Send command to shell
|
|
233
|
-
this.shellProcess.stdin.write(commandWithPwd);
|
|
234
|
-
// Wait for command to complete (look for the pwd marker)
|
|
235
|
-
const result = await this.waitForCommandCompletion(30000);
|
|
236
|
-
return result;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Spawn an interactive shell process
|
|
80
|
+
*/
|
|
81
|
+
async spawnInteractiveShell() {
|
|
82
|
+
if (!this.config) {
|
|
83
|
+
throw new Error("Config not initialized");
|
|
84
|
+
}
|
|
85
|
+
const distro = this.config.distribution.trim().replace(/\0/g, "");
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
this.shellProcess = spawn("wsl.exe", ["-d", distro], {
|
|
88
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
89
|
+
shell: false
|
|
90
|
+
});
|
|
91
|
+
if (!this.shellProcess.stdout || !this.shellProcess.stderr || !this.shellProcess.stdin) {
|
|
92
|
+
reject(new Error("Failed to create shell process streams"));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
let hasResolved = false;
|
|
96
|
+
let errorOutput = "";
|
|
97
|
+
let initCommandSent = false;
|
|
98
|
+
this.shellProcess.stdout.on("data", (data) => {
|
|
99
|
+
const text = data.toString();
|
|
100
|
+
this.currentOutput += text;
|
|
101
|
+
if (this.onOutputCallback) {
|
|
102
|
+
this.onOutputCallback(text, "stdout");
|
|
237
103
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
stderr: error.message || 'Command execution failed',
|
|
242
|
-
exitCode: 1,
|
|
243
|
-
};
|
|
104
|
+
if (!hasResolved) {
|
|
105
|
+
hasResolved = true;
|
|
106
|
+
resolve();
|
|
244
107
|
}
|
|
108
|
+
});
|
|
109
|
+
this.shellProcess.stderr.on("data", (data) => {
|
|
110
|
+
const text = data.toString();
|
|
111
|
+
this.currentError += text;
|
|
112
|
+
errorOutput += text;
|
|
113
|
+
if (this.onOutputCallback) {
|
|
114
|
+
this.onOutputCallback(text, "stderr");
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
this.shellProcess.on("exit", (code) => {
|
|
118
|
+
if (!hasResolved) {
|
|
119
|
+
hasResolved = true;
|
|
120
|
+
if (errorOutput.includes("HCS_E_SERVICE_NOT_AVAILABLE")) {
|
|
121
|
+
reject(new Error('WSL service is not running. Try running "wsl --shutdown" and then try again, or restart your computer.'));
|
|
122
|
+
} else if (errorOutput.includes("required feature is not installed")) {
|
|
123
|
+
reject(new Error("WSL is not properly installed or enabled. Please ensure WSL 2 is installed and the Virtual Machine Platform feature is enabled."));
|
|
124
|
+
} else {
|
|
125
|
+
reject(new Error(`WSL process exited with code ${code}. Error: ${errorOutput || "No error output"}`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
this.shellProcess = null;
|
|
129
|
+
});
|
|
130
|
+
this.shellProcess.on("error", (error) => {
|
|
131
|
+
if (!hasResolved) {
|
|
132
|
+
hasResolved = true;
|
|
133
|
+
reject(new Error(`Failed to spawn WSL process: ${error.message}`));
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
const sendInitCommand = () => {
|
|
137
|
+
if (!initCommandSent && this.shellProcess && this.shellProcess.stdin && !this.shellProcess.stdin.destroyed) {
|
|
138
|
+
initCommandSent = true;
|
|
139
|
+
this.shellProcess.stdin.write('echo "CENTAURUS_READY"\n');
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
if (this.shellProcess.stdin.writable) {
|
|
143
|
+
sendInitCommand();
|
|
144
|
+
} else {
|
|
145
|
+
this.shellProcess.stdin.once("ready", sendInitCommand);
|
|
146
|
+
}
|
|
147
|
+
setTimeout(() => {
|
|
148
|
+
sendInitCommand();
|
|
149
|
+
}, 200);
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
if (!hasResolved) {
|
|
152
|
+
hasResolved = true;
|
|
153
|
+
reject(new Error(`WSL shell initialization timed out. Error: ${errorOutput || "No error output"}`));
|
|
154
|
+
}
|
|
155
|
+
}, 15e3);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Disconnect from the WSL environment
|
|
160
|
+
*/
|
|
161
|
+
async disconnect() {
|
|
162
|
+
if (this.shellProcess) {
|
|
163
|
+
this.shellProcess.kill();
|
|
164
|
+
this.shellProcess = null;
|
|
245
165
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
const pwdMatch = this.currentOutput.match(pwdRegex);
|
|
262
|
-
if (pwdMatch) {
|
|
263
|
-
clearInterval(checkInterval);
|
|
264
|
-
// Extract working directory
|
|
265
|
-
const newCwd = pwdMatch[1].trim();
|
|
266
|
-
this.currentWorkingDirectory = newCwd;
|
|
267
|
-
// Clean output
|
|
268
|
-
const cleanStdout = this.currentOutput
|
|
269
|
-
.replace(removeRegex, '')
|
|
270
|
-
.trim();
|
|
271
|
-
resolve({
|
|
272
|
-
stdout: cleanStdout,
|
|
273
|
-
stderr: this.currentError,
|
|
274
|
-
exitCode: 0,
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
}, 100);
|
|
278
|
-
});
|
|
166
|
+
this.config = null;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Check if this handler is currently connected to a WSL environment
|
|
170
|
+
*/
|
|
171
|
+
isConnected() {
|
|
172
|
+
return this.config !== null && this.shellProcess !== null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Execute a command in the WSL environment
|
|
176
|
+
*/
|
|
177
|
+
async executeCommand(command) {
|
|
178
|
+
if (!this.config) {
|
|
179
|
+
throw new SubshellExecutionError(command, "Not connected to WSL - config is null");
|
|
279
180
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
*/
|
|
283
|
-
async readFile(path) {
|
|
284
|
-
if (!this.config) {
|
|
285
|
-
throw new Error('Not connected to WSL');
|
|
286
|
-
}
|
|
287
|
-
const distro = this.config.distribution.trim().replace(/\0/g, '');
|
|
288
|
-
const wslPath = this.resolveWSLPath(path);
|
|
289
|
-
// Use base64 to avoid encoding issues and binary-safe transfer
|
|
290
|
-
const command = `wsl.exe -d ${distro} -- bash -c "base64 '${wslPath}' 2>/dev/null || cat '${wslPath}' | base64"`;
|
|
291
|
-
try {
|
|
292
|
-
const { stdout } = await execAsync(command);
|
|
293
|
-
const b64 = stdout.replace(/\s+/g, '');
|
|
294
|
-
return Buffer.from(b64, 'base64').toString('utf-8');
|
|
295
|
-
}
|
|
296
|
-
catch (error) {
|
|
297
|
-
throw new Error(`Failed to read file ${path}: ${error.message}`);
|
|
298
|
-
}
|
|
181
|
+
if (!this.shellProcess) {
|
|
182
|
+
throw new SubshellExecutionError(command, "Not connected to WSL - shell process is null");
|
|
299
183
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
*/
|
|
303
|
-
async writeFile(path, content) {
|
|
304
|
-
if (!this.config) {
|
|
305
|
-
throw new Error('Not connected to WSL');
|
|
306
|
-
}
|
|
307
|
-
const distro = this.config.distribution.trim().replace(/\0/g, '');
|
|
308
|
-
const wslPath = this.resolveWSLPath(path);
|
|
309
|
-
// Use base64-encoded, chunked writes to avoid shell arg/command length limits
|
|
310
|
-
const inputBuffer = Buffer.isBuffer(content) ? content : Buffer.from(content, 'utf8');
|
|
311
|
-
const base64Content = inputBuffer.toString('base64');
|
|
312
|
-
const CHUNK_SIZE = 32000; // conservative size per command
|
|
313
|
-
try {
|
|
314
|
-
// Truncate/initialize file
|
|
315
|
-
const truncateCmd = `wsl.exe -d ${distro} -- bash -c ": > '${wslPath}'"`;
|
|
316
|
-
await execAsync(truncateCmd);
|
|
317
|
-
// Write in chunks
|
|
318
|
-
for (let i = 0; i < base64Content.length; i += CHUNK_SIZE) {
|
|
319
|
-
const chunk = base64Content.slice(i, i + CHUNK_SIZE);
|
|
320
|
-
const writeCmd = `wsl.exe -d ${distro} -- bash -c "echo '${chunk}' | base64 -d >> '${wslPath}'"`;
|
|
321
|
-
await execAsync(writeCmd);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
catch (error) {
|
|
325
|
-
throw new Error(`Failed to write file ${path}: ${error.message}`);
|
|
326
|
-
}
|
|
184
|
+
if (!this.shellProcess.stdin) {
|
|
185
|
+
throw new SubshellExecutionError(command, "Not connected to WSL - stdin is null");
|
|
327
186
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
*/
|
|
331
|
-
async listDirectory(path) {
|
|
332
|
-
if (!this.config) {
|
|
333
|
-
throw new Error('Not connected to WSL');
|
|
334
|
-
}
|
|
335
|
-
const distro = this.config.distribution.trim().replace(/\0/g, '');
|
|
336
|
-
const wslPath = this.resolveWSLPath(path);
|
|
337
|
-
const command = `wsl.exe -d ${distro} -- ls -la "${wslPath}"`;
|
|
338
|
-
try {
|
|
339
|
-
const { stdout } = await execAsync(command);
|
|
340
|
-
return this.parseDirectoryListing(stdout);
|
|
341
|
-
}
|
|
342
|
-
catch (error) {
|
|
343
|
-
throw new Error(`Failed to list directory ${path}: ${error.message}`);
|
|
344
|
-
}
|
|
187
|
+
if (this.shellProcess.killed || this.shellProcess.exitCode !== null) {
|
|
188
|
+
throw new SubshellExecutionError(command, "Not connected to WSL - shell process has exited");
|
|
345
189
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
190
|
+
try {
|
|
191
|
+
this.currentOutput = "";
|
|
192
|
+
this.currentError = "";
|
|
193
|
+
const pwdTag = `__CENTAURUS_PWD_${this.sessionId}__`;
|
|
194
|
+
let commandWithPwd;
|
|
195
|
+
const trimmedCommand = command.trim();
|
|
196
|
+
if (trimmedCommand.startsWith("cd ") || trimmedCommand === "cd") {
|
|
197
|
+
commandWithPwd = `${command}; echo "${pwdTag}:$(pwd)"
|
|
198
|
+
`;
|
|
199
|
+
} else {
|
|
200
|
+
commandWithPwd = `cd ${this.currentWorkingDirectory} && ${command}; echo "${pwdTag}:$(pwd)"
|
|
201
|
+
`;
|
|
202
|
+
}
|
|
203
|
+
this.shellProcess.stdin.write(commandWithPwd);
|
|
204
|
+
const result = await this.waitForCommandCompletion(3e4);
|
|
205
|
+
return result;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
return {
|
|
208
|
+
stdout: "",
|
|
209
|
+
stderr: error.message || "Command execution failed",
|
|
210
|
+
exitCode: 1
|
|
211
|
+
};
|
|
365
212
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Wait for command completion by monitoring output
|
|
216
|
+
*/
|
|
217
|
+
async waitForCommandCompletion(timeoutMs = 3e4) {
|
|
218
|
+
const pwdTag = `__CENTAURUS_PWD_${this.sessionId}__`;
|
|
219
|
+
const pwdRegex = new RegExp(`${pwdTag}:(.+)$`, "m");
|
|
220
|
+
const removeRegex = new RegExp(`${pwdTag}:.+$`, "m");
|
|
221
|
+
return new Promise((resolve, reject) => {
|
|
222
|
+
const startTime = Date.now();
|
|
223
|
+
const checkInterval = setInterval(() => {
|
|
224
|
+
if (timeoutMs > 0 && Date.now() - startTime >= timeoutMs) {
|
|
225
|
+
clearInterval(checkInterval);
|
|
226
|
+
reject(new Error(`Command execution timed out after ${timeoutMs}ms`));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const pwdMatch = this.currentOutput.match(pwdRegex);
|
|
230
|
+
if (pwdMatch) {
|
|
231
|
+
clearInterval(checkInterval);
|
|
232
|
+
const newCwd = pwdMatch[1].trim();
|
|
233
|
+
this.currentWorkingDirectory = newCwd;
|
|
234
|
+
const cleanStdout = this.currentOutput.replace(removeRegex, "").trim();
|
|
235
|
+
resolve({
|
|
236
|
+
stdout: cleanStdout,
|
|
237
|
+
stderr: this.currentError,
|
|
238
|
+
exitCode: 0
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}, 100);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Read a file from the WSL filesystem
|
|
246
|
+
*/
|
|
247
|
+
async readFile(path) {
|
|
248
|
+
if (!this.config) {
|
|
249
|
+
throw new Error("Not connected to WSL");
|
|
387
250
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
async getOSType() {
|
|
398
|
-
return 'linux';
|
|
399
|
-
}
|
|
400
|
-
/**
|
|
401
|
-
* Get breadcrumb information for the UI
|
|
402
|
-
*/
|
|
403
|
-
getBreadcrumbs() {
|
|
404
|
-
if (!this.config) {
|
|
405
|
-
return [];
|
|
406
|
-
}
|
|
407
|
-
return [
|
|
408
|
-
{
|
|
409
|
-
label: 'wsl',
|
|
410
|
-
color: 'yellow',
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
label: this.config.distribution,
|
|
414
|
-
color: 'yellow',
|
|
415
|
-
},
|
|
416
|
-
];
|
|
417
|
-
}
|
|
418
|
-
// Private helper methods
|
|
419
|
-
/**
|
|
420
|
-
* Verify that WSL is available on the system
|
|
421
|
-
*/
|
|
422
|
-
verifyWSLAvailable() {
|
|
423
|
-
if (os.platform() !== 'win32') {
|
|
424
|
-
throw new Error('WSL is only available on Windows');
|
|
425
|
-
}
|
|
251
|
+
const distro = this.config.distribution.trim().replace(/\0/g, "");
|
|
252
|
+
const wslPath = this.resolveWSLPath(path);
|
|
253
|
+
const command = `wsl.exe -d ${distro} -- bash -c "base64 '${wslPath}' 2>/dev/null || cat '${wslPath}' | base64"`;
|
|
254
|
+
try {
|
|
255
|
+
const { stdout } = await execAsync(command);
|
|
256
|
+
const b64 = stdout.replace(/\s+/g, "");
|
|
257
|
+
return Buffer.from(b64, "base64").toString("utf-8");
|
|
258
|
+
} catch (error) {
|
|
259
|
+
throw new Error(`Failed to read file ${path}: ${error.message}`);
|
|
426
260
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
for (let i = 1; i < parts.length; i++) {
|
|
435
|
-
const part = parts[i];
|
|
436
|
-
if ((part === '-d' || part === '--distribution') && i + 1 < parts.length) {
|
|
437
|
-
distribution = parts[i + 1];
|
|
438
|
-
break;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
// If no distribution specified, get the default
|
|
442
|
-
if (!distribution) {
|
|
443
|
-
distribution = await this.getDefaultDistribution();
|
|
444
|
-
}
|
|
445
|
-
return {
|
|
446
|
-
distribution,
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
/**
|
|
450
|
-
* Get the default WSL distribution
|
|
451
|
-
*/
|
|
452
|
-
async getDefaultDistribution() {
|
|
453
|
-
try {
|
|
454
|
-
const { stdout } = await execAsync('wsl.exe --list --verbose');
|
|
455
|
-
// Remove BOM and null bytes from output
|
|
456
|
-
const cleanOutput = stdout.replace(/^\uFEFF/, '').replace(/\0/g, '');
|
|
457
|
-
const lines = cleanOutput.split('\n');
|
|
458
|
-
// Find the line with * (default distribution)
|
|
459
|
-
for (const line of lines) {
|
|
460
|
-
if (line.includes('*')) {
|
|
461
|
-
const match = line.match(/\*\s+(\S+)/);
|
|
462
|
-
if (match) {
|
|
463
|
-
const distro = match[1].trim().replace(/\0/g, '');
|
|
464
|
-
if (distro) {
|
|
465
|
-
return distro;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
// If no default found, return the first distribution
|
|
471
|
-
for (const line of lines) {
|
|
472
|
-
const match = line.match(/^\s+(\S+)/);
|
|
473
|
-
if (match && !match[1].includes('NAME')) {
|
|
474
|
-
const distro = match[1].trim().replace(/\0/g, '');
|
|
475
|
-
if (distro) {
|
|
476
|
-
return distro;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
throw new Error('No WSL distributions found');
|
|
481
|
-
}
|
|
482
|
-
catch (error) {
|
|
483
|
-
throw new Error('Failed to detect WSL distribution');
|
|
484
|
-
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Write a file to the WSL filesystem
|
|
264
|
+
*/
|
|
265
|
+
async writeFile(path, content) {
|
|
266
|
+
if (!this.config) {
|
|
267
|
+
throw new Error("Not connected to WSL");
|
|
485
268
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
if (shellPath.includes('bash'))
|
|
502
|
-
return 'bash';
|
|
503
|
-
if (shellPath.includes('zsh'))
|
|
504
|
-
return 'zsh';
|
|
505
|
-
if (shellPath.includes('fish'))
|
|
506
|
-
return 'fish';
|
|
507
|
-
return 'bash';
|
|
508
|
-
}
|
|
509
|
-
catch {
|
|
510
|
-
return 'bash';
|
|
511
|
-
}
|
|
269
|
+
const distro = this.config.distribution.trim().replace(/\0/g, "");
|
|
270
|
+
const wslPath = this.resolveWSLPath(path);
|
|
271
|
+
const inputBuffer = Buffer.isBuffer(content) ? content : Buffer.from(content, "utf8");
|
|
272
|
+
const base64Content = inputBuffer.toString("base64");
|
|
273
|
+
const CHUNK_SIZE = 32e3;
|
|
274
|
+
try {
|
|
275
|
+
const truncateCmd = `wsl.exe -d ${distro} -- bash -c ": > '${wslPath}'"`;
|
|
276
|
+
await execAsync(truncateCmd);
|
|
277
|
+
for (let i = 0; i < base64Content.length; i += CHUNK_SIZE) {
|
|
278
|
+
const chunk = base64Content.slice(i, i + CHUNK_SIZE);
|
|
279
|
+
const writeCmd = `wsl.exe -d ${distro} -- bash -c "echo '${chunk}' | base64 -d >> '${wslPath}'"`;
|
|
280
|
+
await execAsync(writeCmd);
|
|
281
|
+
}
|
|
282
|
+
} catch (error) {
|
|
283
|
+
throw new Error(`Failed to write file ${path}: ${error.message}`);
|
|
512
284
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* List directory contents in WSL
|
|
288
|
+
*/
|
|
289
|
+
async listDirectory(path) {
|
|
290
|
+
if (!this.config) {
|
|
291
|
+
throw new Error("Not connected to WSL");
|
|
292
|
+
}
|
|
293
|
+
const distro = this.config.distribution.trim().replace(/\0/g, "");
|
|
294
|
+
const wslPath = this.resolveWSLPath(path);
|
|
295
|
+
const command = `wsl.exe -d ${distro} -- ls -la "${wslPath}"`;
|
|
296
|
+
try {
|
|
297
|
+
const { stdout } = await execAsync(command);
|
|
298
|
+
return this.parseDirectoryListing(stdout);
|
|
299
|
+
} catch (error) {
|
|
300
|
+
throw new Error(`Failed to list directory ${path}: ${error.message}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Search for files matching a pattern in WSL
|
|
305
|
+
*/
|
|
306
|
+
async searchFiles(pattern, directory) {
|
|
307
|
+
if (!this.config) {
|
|
308
|
+
throw new Error("Not connected to WSL");
|
|
309
|
+
}
|
|
310
|
+
const distro = this.config.distribution.trim().replace(/\0/g, "");
|
|
311
|
+
const wslPath = this.resolveWSLPath(directory);
|
|
312
|
+
const escapedPattern = pattern.replace(/'/g, "'\\''");
|
|
313
|
+
const command = `wsl.exe -d ${distro} -- bash -c "grep -rn '${escapedPattern}' '${wslPath}' 2>/dev/null || true"`;
|
|
314
|
+
try {
|
|
315
|
+
const { stdout } = await execAsync(command);
|
|
316
|
+
return this.parseSearchResults(stdout);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
return [];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get the current working directory in WSL
|
|
323
|
+
*/
|
|
324
|
+
async getCurrentWorkingDirectory() {
|
|
325
|
+
if (!this.config || !this.shellProcess || !this.shellProcess.stdin) {
|
|
326
|
+
return "~";
|
|
327
|
+
}
|
|
328
|
+
try {
|
|
329
|
+
this.currentOutput = "";
|
|
330
|
+
this.shellProcess.stdin.write("pwd\n");
|
|
331
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
332
|
+
const lines = this.currentOutput.trim().split("\n");
|
|
333
|
+
const path = lines[lines.length - 1].trim();
|
|
334
|
+
return path || "~";
|
|
335
|
+
} catch {
|
|
336
|
+
return "~";
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Get the shell type
|
|
341
|
+
*/
|
|
342
|
+
async getShellType() {
|
|
343
|
+
return this.shellType;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get the operating system type (always linux for WSL)
|
|
347
|
+
*/
|
|
348
|
+
async getOSType() {
|
|
349
|
+
return "linux";
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Get breadcrumb information for the UI
|
|
353
|
+
*/
|
|
354
|
+
getBreadcrumbs() {
|
|
355
|
+
if (!this.config) {
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
return [
|
|
359
|
+
{
|
|
360
|
+
label: "wsl",
|
|
361
|
+
color: "yellow"
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
label: this.config.distribution,
|
|
365
|
+
color: "yellow"
|
|
366
|
+
}
|
|
367
|
+
];
|
|
368
|
+
}
|
|
369
|
+
// Private helper methods
|
|
370
|
+
/**
|
|
371
|
+
* Verify that WSL is available on the system
|
|
372
|
+
*/
|
|
373
|
+
verifyWSLAvailable() {
|
|
374
|
+
if (os.platform() !== "win32") {
|
|
375
|
+
throw new Error("WSL is only available on Windows");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Parse WSL command to extract distribution name
|
|
380
|
+
*/
|
|
381
|
+
async parseWSLCommand(command) {
|
|
382
|
+
const parts = command.trim().split(/\s+/);
|
|
383
|
+
let distribution = "";
|
|
384
|
+
for (let i = 1; i < parts.length; i++) {
|
|
385
|
+
const part = parts[i];
|
|
386
|
+
if ((part === "-d" || part === "--distribution") && i + 1 < parts.length) {
|
|
387
|
+
distribution = parts[i + 1];
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (!distribution) {
|
|
392
|
+
distribution = await this.getDefaultDistribution();
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
distribution
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Get the default WSL distribution
|
|
400
|
+
*/
|
|
401
|
+
async getDefaultDistribution() {
|
|
402
|
+
try {
|
|
403
|
+
const { stdout } = await execAsync("wsl.exe --list --verbose");
|
|
404
|
+
const cleanOutput = stdout.replace(/^\uFEFF/, "").replace(/\0/g, "");
|
|
405
|
+
const lines = cleanOutput.split("\n");
|
|
406
|
+
for (const line of lines) {
|
|
407
|
+
if (line.includes("*")) {
|
|
408
|
+
const match = line.match(/\*\s+(\S+)/);
|
|
409
|
+
if (match) {
|
|
410
|
+
const distro = match[1].trim().replace(/\0/g, "");
|
|
411
|
+
if (distro) {
|
|
412
|
+
return distro;
|
|
625
413
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
for (const line of lines) {
|
|
418
|
+
const match = line.match(/^\s+(\S+)/);
|
|
419
|
+
if (match && !match[1].includes("NAME")) {
|
|
420
|
+
const distro = match[1].trim().replace(/\0/g, "");
|
|
421
|
+
if (distro) {
|
|
422
|
+
return distro;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
throw new Error("No WSL distributions found");
|
|
427
|
+
} catch (error) {
|
|
428
|
+
throw new Error("Failed to detect WSL distribution");
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Detect the shell type in WSL
|
|
433
|
+
*/
|
|
434
|
+
async detectShellType() {
|
|
435
|
+
if (!this.config || !this.shellProcess || !this.shellProcess.stdin) {
|
|
436
|
+
return "bash";
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
this.currentOutput = "";
|
|
440
|
+
this.shellProcess.stdin.write("echo $SHELL\n");
|
|
441
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
442
|
+
const shellPath = this.currentOutput.trim();
|
|
443
|
+
if (shellPath.includes("bash")) return "bash";
|
|
444
|
+
if (shellPath.includes("zsh")) return "zsh";
|
|
445
|
+
if (shellPath.includes("fish")) return "fish";
|
|
446
|
+
return "bash";
|
|
447
|
+
} catch {
|
|
448
|
+
return "bash";
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Build a WSL command with working directory context
|
|
453
|
+
*/
|
|
454
|
+
buildWSLCommand(command) {
|
|
455
|
+
if (!this.config) {
|
|
456
|
+
throw new Error("Not connected to WSL");
|
|
457
|
+
}
|
|
458
|
+
const distro = this.config.distribution.trim().replace(/\0/g, "");
|
|
459
|
+
if (!distro) {
|
|
460
|
+
throw new Error("Invalid WSL distribution name");
|
|
461
|
+
}
|
|
462
|
+
const targetDir = this.currentWorkingDirectory === "~" || this.currentWorkingDirectory === "" ? "~" : this.currentWorkingDirectory;
|
|
463
|
+
const pwdTag = `__CENTAURUS_PWD_${this.sessionId}__`;
|
|
464
|
+
const bashScript = `cd ${targetDir} && ${command}; echo "${pwdTag}:$(pwd)"`;
|
|
465
|
+
return `wsl.exe -d ${distro} -- bash -c '${bashScript.replace(/'/g, "'\\''")}'`;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Convert Windows path to WSL path
|
|
469
|
+
*/
|
|
470
|
+
static windowsToWSLPath(windowsPath) {
|
|
471
|
+
const match = windowsPath.match(/^([A-Za-z]):(\\|\/)/);
|
|
472
|
+
if (match) {
|
|
473
|
+
const drive = match[1].toLowerCase();
|
|
474
|
+
const rest = windowsPath.substring(2).replace(/\\/g, "/");
|
|
475
|
+
return `/mnt/${drive}${rest}`;
|
|
476
|
+
}
|
|
477
|
+
return windowsPath.replace(/\\/g, "/");
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Convert WSL path to Windows path
|
|
481
|
+
*/
|
|
482
|
+
static wslToWindowsPath(wslPath) {
|
|
483
|
+
const match = wslPath.match(/^\/mnt\/([a-z])(\/.*)?$/);
|
|
484
|
+
if (match) {
|
|
485
|
+
const drive = match[1].toUpperCase();
|
|
486
|
+
const rest = (match[2] || "").replace(/\//g, "\\");
|
|
487
|
+
return `${drive}:${rest}`;
|
|
488
|
+
}
|
|
489
|
+
return wslPath;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Resolve a path to a WSL path
|
|
493
|
+
*/
|
|
494
|
+
resolveWSLPath(path) {
|
|
495
|
+
if (path.startsWith("/")) {
|
|
496
|
+
return path;
|
|
497
|
+
}
|
|
498
|
+
if (path.startsWith("~")) {
|
|
499
|
+
return path;
|
|
500
|
+
}
|
|
501
|
+
if (path.match(/^[A-Za-z]:/)) {
|
|
502
|
+
return WSLHandler.windowsToWSLPath(path);
|
|
503
|
+
}
|
|
504
|
+
return `${this.currentWorkingDirectory}/${path}`;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Parse directory listing output
|
|
508
|
+
*/
|
|
509
|
+
parseDirectoryListing(output) {
|
|
510
|
+
const entries = [];
|
|
511
|
+
const lines = output.split("\n").filter((line) => line.trim());
|
|
512
|
+
for (const line of lines) {
|
|
513
|
+
if (line.startsWith("total") || line.endsWith(" .") || line.endsWith(" ..")) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
const match = line.match(/^([drwx-]+)\s+\d+\s+\S+\s+\S+\s+(\d+)\s+\S+\s+\S+\s+\S+\s+(.+)$/);
|
|
517
|
+
if (match) {
|
|
518
|
+
const permissions = match[1];
|
|
519
|
+
const size = parseInt(match[2], 10);
|
|
520
|
+
const name = match[3];
|
|
521
|
+
entries.push({
|
|
522
|
+
name,
|
|
523
|
+
type: permissions.startsWith("d") ? "directory" : "file",
|
|
524
|
+
size,
|
|
525
|
+
permissions
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return entries;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Parse search results from grep output
|
|
533
|
+
*/
|
|
534
|
+
parseSearchResults(output) {
|
|
535
|
+
const results = [];
|
|
536
|
+
const lines = output.split("\n").filter((line) => line.trim());
|
|
537
|
+
for (const line of lines) {
|
|
538
|
+
const match = line.match(/^(.+?):(\d+):(.+)$/);
|
|
539
|
+
if (match) {
|
|
540
|
+
results.push({
|
|
541
|
+
file: match[1],
|
|
542
|
+
line: parseInt(match[2], 10),
|
|
543
|
+
content: match[3]
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return results;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Execute a promise with a timeout
|
|
551
|
+
*/
|
|
552
|
+
async executeWithTimeout(operation, timeoutMs, operationName) {
|
|
553
|
+
return Promise.race([
|
|
554
|
+
operation(),
|
|
555
|
+
new Promise(
|
|
556
|
+
(_, reject) => setTimeout(
|
|
557
|
+
() => reject(new Error(`${operationName} timed out after ${timeoutMs}ms`)),
|
|
558
|
+
timeoutMs
|
|
559
|
+
)
|
|
560
|
+
)
|
|
561
|
+
]);
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Create a new instance of this handler
|
|
565
|
+
*/
|
|
566
|
+
createNew() {
|
|
567
|
+
const newHandler = new WSLHandler();
|
|
568
|
+
if (this.onOutputCallback) {
|
|
569
|
+
newHandler.setOutputCallback(this.onOutputCallback);
|
|
647
570
|
}
|
|
571
|
+
return newHandler;
|
|
572
|
+
}
|
|
648
573
|
}
|
|
574
|
+
export {
|
|
575
|
+
WSLHandler
|
|
576
|
+
};
|
|
649
577
|
//# sourceMappingURL=wsl-handler.js.map
|