centaurus-cli 3.0.0 → 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 -5037
- 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 +1513 -973
- 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 +605 -537
- 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 -400
- 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 -3249
- 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 -511
- 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 -167
- 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,529 +1,544 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { logError, logWarning } from
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
* @param cwd Optional working directory - if provided, command will be prefixed with 'cd <cwd> &&' for remote contexts
|
|
196
|
-
*/
|
|
197
|
-
async executeCommand(command, timeoutMs = 30000, cwd) {
|
|
198
|
-
const context = this.getCurrentContext();
|
|
199
|
-
const startTime = Date.now();
|
|
200
|
-
try {
|
|
201
|
-
let result;
|
|
202
|
-
if (context.type === 'local') {
|
|
203
|
-
// Execute locally using Node.js child_process
|
|
204
|
-
// Use provided cwd or fall back to context's working directory
|
|
205
|
-
const workingDir = cwd || context.metadata.workingDirectory;
|
|
206
|
-
result = await this.executeWithTimeout(() => this.executeLocalCommand(command, workingDir), timeoutMs, 'Command execution');
|
|
207
|
-
// Update context cwd if execution was successful and cwd was provided
|
|
208
|
-
if (cwd && result.exitCode === 0 && cwd !== context.metadata.workingDirectory) {
|
|
209
|
-
context.metadata.workingDirectory = cwd;
|
|
210
|
-
this.notifyContextChange();
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
// Execute in subshell
|
|
215
|
-
if (!context.handler) {
|
|
216
|
-
throw new SubshellExecutionError(command, 'No handler available for current context', 1);
|
|
217
|
-
}
|
|
218
|
-
// For remote contexts, prefix command with 'cd <cwd> &&' if cwd is provided and valid
|
|
219
|
-
let fullCommand = command;
|
|
220
|
-
if (cwd && cwd !== '~' && cwd !== context.metadata.workingDirectory) {
|
|
221
|
-
// Prefix with cd to ensure command runs in the correct directory
|
|
222
|
-
fullCommand = `cd "${cwd}" && ${command}`;
|
|
223
|
-
}
|
|
224
|
-
result = await this.executeWithTimeout(() => context.handler.executeCommand(fullCommand), timeoutMs, 'Command execution');
|
|
225
|
-
// Update working directory after command execution
|
|
226
|
-
try {
|
|
227
|
-
const newCwd = await context.handler.getCurrentWorkingDirectory();
|
|
228
|
-
// Only update if we got a valid path (not ~ which is the fallback)
|
|
229
|
-
if (newCwd && newCwd !== '~' && newCwd !== context.metadata.workingDirectory) {
|
|
230
|
-
context.metadata.workingDirectory = newCwd;
|
|
231
|
-
this.notifyContextChange();
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
catch (cwdError) {
|
|
235
|
-
// Ignore cwd detection errors - don't change the stored CWD
|
|
236
|
-
// The previous CWD should remain valid
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
// Check for latency warning
|
|
240
|
-
const executionTime = Date.now() - startTime;
|
|
241
|
-
if (executionTime > 2000) {
|
|
242
|
-
this.notifyUser(`Command took ${(executionTime / 1000).toFixed(1)}s to execute (high latency detected)`, 'warning');
|
|
243
|
-
}
|
|
244
|
-
return result;
|
|
245
|
-
}
|
|
246
|
-
catch (error) {
|
|
247
|
-
if (error instanceof Error && error.message.includes('timed out')) {
|
|
248
|
-
this.notifyUser(`Command timed out after ${timeoutMs / 1000}s`, 'error');
|
|
249
|
-
throw new SubshellExecutionError(command, `Command timed out after ${timeoutMs / 1000}s`, 124 // Standard timeout exit code
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
throw new SubshellExecutionError(command, error instanceof Error ? error.message : String(error), 1);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Execute a command locally
|
|
257
|
-
*/
|
|
258
|
-
async executeLocalCommand(command, cwd) {
|
|
259
|
-
const { exec } = await import('child_process');
|
|
260
|
-
const { promisify } = await import('util');
|
|
261
|
-
const execAsync = promisify(exec);
|
|
262
|
-
try {
|
|
263
|
-
const { stdout, stderr } = await execAsync(command, { cwd });
|
|
264
|
-
return {
|
|
265
|
-
stdout: stdout || '',
|
|
266
|
-
stderr: stderr || '',
|
|
267
|
-
exitCode: 0,
|
|
268
|
-
};
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import {
|
|
3
|
+
SubshellConnectionError,
|
|
4
|
+
SubshellExecutionError
|
|
5
|
+
} from "./types.js";
|
|
6
|
+
import { logError, logWarning } from "../utils/logger.js";
|
|
7
|
+
class ContextManager {
|
|
8
|
+
constructor(initialCwd, platform) {
|
|
9
|
+
this.initialCwd = initialCwd;
|
|
10
|
+
this.platform = platform;
|
|
11
|
+
this.contextStack.push(this.createLocalContext(initialCwd));
|
|
12
|
+
}
|
|
13
|
+
contextStack = [];
|
|
14
|
+
handlers = /* @__PURE__ */ new Map();
|
|
15
|
+
contextChangeCallbacks = [];
|
|
16
|
+
userNotificationCallbacks = [];
|
|
17
|
+
/**
|
|
18
|
+
* Create a local context
|
|
19
|
+
*/
|
|
20
|
+
createLocalContext(cwd) {
|
|
21
|
+
return {
|
|
22
|
+
type: "local",
|
|
23
|
+
metadata: {
|
|
24
|
+
workingDirectory: cwd,
|
|
25
|
+
shell: this.detectLocalShell(),
|
|
26
|
+
os: this.detectLocalOS()
|
|
27
|
+
},
|
|
28
|
+
connectionState: "connected",
|
|
29
|
+
sessionId: randomUUID()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Detect the local shell type
|
|
34
|
+
*/
|
|
35
|
+
detectLocalShell() {
|
|
36
|
+
const shell = process.env.SHELL || process.env.ComSpec || "unknown";
|
|
37
|
+
if (shell.includes("bash")) return "bash";
|
|
38
|
+
if (shell.includes("zsh")) return "zsh";
|
|
39
|
+
if (shell.includes("fish")) return "fish";
|
|
40
|
+
if (shell.includes("cmd")) return "cmd";
|
|
41
|
+
if (shell.includes("powershell") || shell.includes("pwsh")) return "powershell";
|
|
42
|
+
return "unknown";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Detect the local operating system
|
|
46
|
+
*/
|
|
47
|
+
detectLocalOS() {
|
|
48
|
+
switch (this.platform) {
|
|
49
|
+
case "win32":
|
|
50
|
+
return "windows";
|
|
51
|
+
case "darwin":
|
|
52
|
+
return "macos";
|
|
53
|
+
default:
|
|
54
|
+
return "linux";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the current execution context
|
|
59
|
+
*/
|
|
60
|
+
getCurrentContext() {
|
|
61
|
+
return this.contextStack[this.contextStack.length - 1];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the parent context (one level up in the stack)
|
|
65
|
+
* Returns null if at local context or only one context exists.
|
|
66
|
+
* Useful for detecting nested sessions (e.g., Docker inside SSH).
|
|
67
|
+
*/
|
|
68
|
+
getParentContext() {
|
|
69
|
+
if (this.contextStack.length <= 1) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return this.contextStack[this.contextStack.length - 2];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Push a new context onto the stack
|
|
76
|
+
*/
|
|
77
|
+
pushContext(context) {
|
|
78
|
+
this.contextStack.push(context);
|
|
79
|
+
this.notifyContextChange();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the full context stack
|
|
83
|
+
*/
|
|
84
|
+
getContextStack() {
|
|
85
|
+
return [...this.contextStack];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Pop the current context from the stack
|
|
89
|
+
* @returns The popped context, or null if only local context remains
|
|
90
|
+
*/
|
|
91
|
+
popContext() {
|
|
92
|
+
if (this.contextStack.length <= 1) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const popped = this.contextStack.pop();
|
|
96
|
+
this.notifyContextChange();
|
|
97
|
+
return popped;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Register a subshell handler
|
|
101
|
+
*/
|
|
102
|
+
registerHandler(type, handler) {
|
|
103
|
+
this.handlers.set(type, handler);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get a registered handler by type
|
|
107
|
+
*/
|
|
108
|
+
getHandler(type) {
|
|
109
|
+
return this.handlers.get(type);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get all registered handlers
|
|
113
|
+
*/
|
|
114
|
+
getAllHandlers() {
|
|
115
|
+
return Array.from(this.handlers.values());
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Update the working directory of the current context
|
|
119
|
+
*/
|
|
120
|
+
updateWorkingDirectory(path) {
|
|
121
|
+
const current = this.getCurrentContext();
|
|
122
|
+
current.metadata.workingDirectory = path;
|
|
123
|
+
this.notifyContextChange();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Update the connection state of the current context
|
|
127
|
+
*/
|
|
128
|
+
updateConnectionState(state) {
|
|
129
|
+
const current = this.getCurrentContext();
|
|
130
|
+
current.connectionState = state;
|
|
131
|
+
this.notifyContextChange();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Register a callback for context changes
|
|
135
|
+
*/
|
|
136
|
+
onContextChange(callback) {
|
|
137
|
+
this.contextChangeCallbacks.push(callback);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Register a callback for user notifications
|
|
141
|
+
*/
|
|
142
|
+
onUserNotification(callback) {
|
|
143
|
+
this.userNotificationCallbacks.push(callback);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Notify all registered callbacks of a context change
|
|
147
|
+
*/
|
|
148
|
+
notifyContextChange() {
|
|
149
|
+
const current = this.getCurrentContext();
|
|
150
|
+
const stack = [...this.contextStack];
|
|
151
|
+
this.contextChangeCallbacks.forEach((callback) => {
|
|
152
|
+
try {
|
|
153
|
+
callback(current, stack);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
logError("Error in context change callback", error);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Notify user with a message
|
|
161
|
+
*/
|
|
162
|
+
notifyUser(message, type = "info") {
|
|
163
|
+
this.userNotificationCallbacks.forEach((callback) => {
|
|
164
|
+
try {
|
|
165
|
+
callback(message, type);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
logError("Error in user notification callback", error);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
if (this.userNotificationCallbacks.length === 0) {
|
|
171
|
+
logWarning(`${type.toUpperCase()}: ${message}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Execute a command in the current context with timeout
|
|
176
|
+
* @param command The command to execute
|
|
177
|
+
* @param timeoutMs Timeout in milliseconds (default 30000)
|
|
178
|
+
* @param cwd Optional working directory - if provided, command will be prefixed with 'cd <cwd> &&' for remote contexts
|
|
179
|
+
*/
|
|
180
|
+
async executeCommand(command, timeoutMs = 3e4, cwd) {
|
|
181
|
+
const context = this.getCurrentContext();
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
try {
|
|
184
|
+
let result;
|
|
185
|
+
if (context.type === "local") {
|
|
186
|
+
const workingDir = cwd || context.metadata.workingDirectory;
|
|
187
|
+
result = await this.executeWithTimeout(
|
|
188
|
+
() => this.executeLocalCommand(command, workingDir),
|
|
189
|
+
timeoutMs,
|
|
190
|
+
"Command execution"
|
|
191
|
+
);
|
|
192
|
+
if (cwd && result.exitCode === 0 && cwd !== context.metadata.workingDirectory) {
|
|
193
|
+
context.metadata.workingDirectory = cwd;
|
|
194
|
+
this.notifyContextChange();
|
|
269
195
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
196
|
+
} else {
|
|
197
|
+
if (!context.handler) {
|
|
198
|
+
throw new SubshellExecutionError(
|
|
199
|
+
command,
|
|
200
|
+
"No handler available for current context",
|
|
201
|
+
1
|
|
202
|
+
);
|
|
276
203
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
*/
|
|
281
|
-
async readFile(path, timeoutMs = 10000) {
|
|
282
|
-
const context = this.getCurrentContext();
|
|
283
|
-
try {
|
|
284
|
-
if (context.type === 'local') {
|
|
285
|
-
const fs = await import('fs/promises');
|
|
286
|
-
return await this.executeWithTimeout(() => fs.readFile(path, 'utf-8'), timeoutMs, 'File read');
|
|
287
|
-
}
|
|
288
|
-
if (!context.handler) {
|
|
289
|
-
throw new Error('No handler available for current context');
|
|
290
|
-
}
|
|
291
|
-
return await this.executeWithTimeout(() => context.handler.readFile(path), timeoutMs, 'File read');
|
|
292
|
-
}
|
|
293
|
-
catch (error) {
|
|
294
|
-
if (error instanceof Error && error.message.includes('timed out')) {
|
|
295
|
-
this.notifyUser(`File read timed out after ${timeoutMs / 1000}s`, 'error');
|
|
296
|
-
}
|
|
297
|
-
throw error;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Write a file in the current context with timeout
|
|
302
|
-
*/
|
|
303
|
-
async writeFile(path, content, timeoutMs = 10000) {
|
|
304
|
-
const context = this.getCurrentContext();
|
|
305
|
-
try {
|
|
306
|
-
if (context.type === 'local') {
|
|
307
|
-
const fs = await import('fs/promises');
|
|
308
|
-
await this.executeWithTimeout(() => fs.writeFile(path, content, 'utf-8'), timeoutMs, 'File write');
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
if (!context.handler) {
|
|
312
|
-
throw new Error('No handler available for current context');
|
|
313
|
-
}
|
|
314
|
-
await this.executeWithTimeout(() => context.handler.writeFile(path, content), timeoutMs, 'File write');
|
|
204
|
+
let fullCommand = command;
|
|
205
|
+
if (cwd && cwd !== "~" && cwd !== context.metadata.workingDirectory) {
|
|
206
|
+
fullCommand = `cd "${cwd}" && ${command}`;
|
|
315
207
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* List directory contents in the current context with timeout
|
|
325
|
-
*/
|
|
326
|
-
async listDirectory(path, timeoutMs = 10000) {
|
|
327
|
-
const context = this.getCurrentContext();
|
|
208
|
+
result = await this.executeWithTimeout(
|
|
209
|
+
() => context.handler.executeCommand(fullCommand),
|
|
210
|
+
timeoutMs,
|
|
211
|
+
"Command execution"
|
|
212
|
+
);
|
|
328
213
|
try {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
type: entry.isDirectory() ? 'directory' : 'file',
|
|
336
|
-
}));
|
|
337
|
-
}, timeoutMs, 'Directory listing');
|
|
338
|
-
}
|
|
339
|
-
if (!context.handler) {
|
|
340
|
-
throw new Error('No handler available for current context');
|
|
341
|
-
}
|
|
342
|
-
return await this.executeWithTimeout(() => context.handler.listDirectory(path), timeoutMs, 'Directory listing');
|
|
343
|
-
}
|
|
344
|
-
catch (error) {
|
|
345
|
-
if (error instanceof Error && error.message.includes('timed out')) {
|
|
346
|
-
this.notifyUser(`Directory listing timed out after ${timeoutMs / 1000}s`, 'error');
|
|
347
|
-
}
|
|
348
|
-
throw error;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Search for files in the current context with timeout
|
|
353
|
-
*/
|
|
354
|
-
async searchFiles(pattern, directory, timeoutMs = 30000) {
|
|
355
|
-
const context = this.getCurrentContext();
|
|
356
|
-
try {
|
|
357
|
-
if (context.type === 'local') {
|
|
358
|
-
// For local, we'll use grep via command execution
|
|
359
|
-
const result = await this.executeWithTimeout(() => this.executeLocalCommand(`grep -rn "${pattern}" "${directory}" 2>/dev/null || true`, context.metadata.workingDirectory), timeoutMs, 'File search');
|
|
360
|
-
return this.parseGrepOutput(result.stdout);
|
|
361
|
-
}
|
|
362
|
-
if (!context.handler) {
|
|
363
|
-
throw new Error('No handler available for current context');
|
|
364
|
-
}
|
|
365
|
-
return await this.executeWithTimeout(() => context.handler.searchFiles(pattern, directory), timeoutMs, 'File search');
|
|
366
|
-
}
|
|
367
|
-
catch (error) {
|
|
368
|
-
if (error instanceof Error && error.message.includes('timed out')) {
|
|
369
|
-
this.notifyUser(`File search timed out after ${timeoutMs / 1000}s`, 'error');
|
|
370
|
-
}
|
|
371
|
-
throw error;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Parse grep output into SearchResult array
|
|
376
|
-
*/
|
|
377
|
-
parseGrepOutput(output) {
|
|
378
|
-
const results = [];
|
|
379
|
-
const lines = output.split('\n').filter(line => line.trim());
|
|
380
|
-
for (const line of lines) {
|
|
381
|
-
const match = line.match(/^([^:]+):(\d+):(.*)$/);
|
|
382
|
-
if (match) {
|
|
383
|
-
results.push({
|
|
384
|
-
file: match[1],
|
|
385
|
-
line: parseInt(match[2], 10),
|
|
386
|
-
content: match[3],
|
|
387
|
-
});
|
|
388
|
-
}
|
|
214
|
+
const newCwd = await context.handler.getCurrentWorkingDirectory();
|
|
215
|
+
if (newCwd && newCwd !== "~" && newCwd !== context.metadata.workingDirectory) {
|
|
216
|
+
context.metadata.workingDirectory = newCwd;
|
|
217
|
+
this.notifyContextChange();
|
|
218
|
+
}
|
|
219
|
+
} catch (cwdError) {
|
|
389
220
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
221
|
+
}
|
|
222
|
+
const executionTime = Date.now() - startTime;
|
|
223
|
+
if (executionTime > 2e3) {
|
|
224
|
+
this.notifyUser(
|
|
225
|
+
`Command took ${(executionTime / 1e3).toFixed(1)}s to execute (high latency detected)`,
|
|
226
|
+
"warning"
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return result;
|
|
230
|
+
} catch (error) {
|
|
231
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
232
|
+
this.notifyUser(`Command timed out after ${timeoutMs / 1e3}s`, "error");
|
|
233
|
+
throw new SubshellExecutionError(
|
|
234
|
+
command,
|
|
235
|
+
`Command timed out after ${timeoutMs / 1e3}s`,
|
|
236
|
+
124
|
|
237
|
+
// Standard timeout exit code
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
throw new SubshellExecutionError(
|
|
241
|
+
command,
|
|
242
|
+
error instanceof Error ? error.message : String(error),
|
|
243
|
+
1
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Execute a command locally
|
|
249
|
+
*/
|
|
250
|
+
async executeLocalCommand(command, cwd) {
|
|
251
|
+
const { exec } = await import("child_process");
|
|
252
|
+
const { promisify } = await import("util");
|
|
253
|
+
const execAsync = promisify(exec);
|
|
254
|
+
try {
|
|
255
|
+
const { stdout, stderr } = await execAsync(command, { cwd });
|
|
256
|
+
return {
|
|
257
|
+
stdout: stdout || "",
|
|
258
|
+
stderr: stderr || "",
|
|
259
|
+
exitCode: 0
|
|
260
|
+
};
|
|
261
|
+
} catch (error) {
|
|
262
|
+
return {
|
|
263
|
+
stdout: error.stdout || "",
|
|
264
|
+
stderr: error.stderr || error.message || "",
|
|
265
|
+
exitCode: error.code || 1
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Read a file in the current context with timeout
|
|
271
|
+
*/
|
|
272
|
+
async readFile(path, timeoutMs = 1e4) {
|
|
273
|
+
const context = this.getCurrentContext();
|
|
274
|
+
try {
|
|
275
|
+
if (context.type === "local") {
|
|
276
|
+
const fs = await import("fs/promises");
|
|
277
|
+
return await this.executeWithTimeout(
|
|
278
|
+
() => fs.readFile(path, "utf-8"),
|
|
279
|
+
timeoutMs,
|
|
280
|
+
"File read"
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
if (!context.handler) {
|
|
284
|
+
throw new Error("No handler available for current context");
|
|
285
|
+
}
|
|
286
|
+
return await this.executeWithTimeout(
|
|
287
|
+
() => context.handler.readFile(path),
|
|
288
|
+
timeoutMs,
|
|
289
|
+
"File read"
|
|
290
|
+
);
|
|
291
|
+
} catch (error) {
|
|
292
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
293
|
+
this.notifyUser(`File read timed out after ${timeoutMs / 1e3}s`, "error");
|
|
294
|
+
}
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Write a file in the current context with timeout
|
|
300
|
+
*/
|
|
301
|
+
async writeFile(path, content, timeoutMs = 1e4) {
|
|
302
|
+
const context = this.getCurrentContext();
|
|
303
|
+
try {
|
|
304
|
+
if (context.type === "local") {
|
|
305
|
+
const fs = await import("fs/promises");
|
|
306
|
+
await this.executeWithTimeout(
|
|
307
|
+
() => fs.writeFile(path, content, "utf-8"),
|
|
308
|
+
timeoutMs,
|
|
309
|
+
"File write"
|
|
310
|
+
);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (!context.handler) {
|
|
314
|
+
throw new Error("No handler available for current context");
|
|
315
|
+
}
|
|
316
|
+
await this.executeWithTimeout(
|
|
317
|
+
() => context.handler.writeFile(path, content),
|
|
318
|
+
timeoutMs,
|
|
319
|
+
"File write"
|
|
320
|
+
);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
323
|
+
this.notifyUser(`File write timed out after ${timeoutMs / 1e3}s`, "error");
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* List directory contents in the current context with timeout
|
|
330
|
+
*/
|
|
331
|
+
async listDirectory(path, timeoutMs = 1e4) {
|
|
332
|
+
const context = this.getCurrentContext();
|
|
333
|
+
try {
|
|
334
|
+
if (context.type === "local") {
|
|
335
|
+
const fs = await import("fs/promises");
|
|
336
|
+
return await this.executeWithTimeout(
|
|
337
|
+
async () => {
|
|
338
|
+
const entries = await fs.readdir(path, { withFileTypes: true });
|
|
339
|
+
return entries.map((entry) => ({
|
|
340
|
+
name: entry.name,
|
|
341
|
+
type: entry.isDirectory() ? "directory" : "file"
|
|
342
|
+
}));
|
|
343
|
+
},
|
|
344
|
+
timeoutMs,
|
|
345
|
+
"Directory listing"
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
if (!context.handler) {
|
|
349
|
+
throw new Error("No handler available for current context");
|
|
350
|
+
}
|
|
351
|
+
return await this.executeWithTimeout(
|
|
352
|
+
() => context.handler.listDirectory(path),
|
|
353
|
+
timeoutMs,
|
|
354
|
+
"Directory listing"
|
|
355
|
+
);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
358
|
+
this.notifyUser(`Directory listing timed out after ${timeoutMs / 1e3}s`, "error");
|
|
359
|
+
}
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Search for files in the current context with timeout
|
|
365
|
+
*/
|
|
366
|
+
async searchFiles(pattern, directory, timeoutMs = 3e4) {
|
|
367
|
+
const context = this.getCurrentContext();
|
|
368
|
+
try {
|
|
369
|
+
if (context.type === "local") {
|
|
370
|
+
const result = await this.executeWithTimeout(
|
|
371
|
+
() => this.executeLocalCommand(
|
|
372
|
+
`grep -rn "${pattern}" "${directory}" 2>/dev/null || true`,
|
|
373
|
+
context.metadata.workingDirectory
|
|
374
|
+
),
|
|
375
|
+
timeoutMs,
|
|
376
|
+
"File search"
|
|
377
|
+
);
|
|
378
|
+
return this.parseGrepOutput(result.stdout);
|
|
379
|
+
}
|
|
380
|
+
if (!context.handler) {
|
|
381
|
+
throw new Error("No handler available for current context");
|
|
382
|
+
}
|
|
383
|
+
return await this.executeWithTimeout(
|
|
384
|
+
() => context.handler.searchFiles(pattern, directory),
|
|
385
|
+
timeoutMs,
|
|
386
|
+
"File search"
|
|
387
|
+
);
|
|
388
|
+
} catch (error) {
|
|
389
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
390
|
+
this.notifyUser(`File search timed out after ${timeoutMs / 1e3}s`, "error");
|
|
391
|
+
}
|
|
392
|
+
throw error;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Parse grep output into SearchResult array
|
|
397
|
+
*/
|
|
398
|
+
parseGrepOutput(output) {
|
|
399
|
+
const results = [];
|
|
400
|
+
const lines = output.split("\n").filter((line) => line.trim());
|
|
401
|
+
for (const line of lines) {
|
|
402
|
+
const match = line.match(/^([^:]+):(\d+):(.*)$/);
|
|
403
|
+
if (match) {
|
|
404
|
+
results.push({
|
|
405
|
+
file: match[1],
|
|
406
|
+
line: parseInt(match[2], 10),
|
|
407
|
+
content: match[3]
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return results;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Connect to a subshell with error handling
|
|
415
|
+
*/
|
|
416
|
+
async connectToSubshell(handler, command) {
|
|
417
|
+
try {
|
|
418
|
+
this.updateConnectionState("connecting");
|
|
419
|
+
this.notifyUser(`Connecting to ${handler.type}...`, "info");
|
|
420
|
+
const cwd = this.getCurrentContext().metadata.workingDirectory;
|
|
421
|
+
const context = await handler.connect(command, cwd);
|
|
422
|
+
this.pushContext(context);
|
|
423
|
+
this.updateConnectionState("connected");
|
|
424
|
+
this.notifyUser(`Connected to ${handler.type} successfully`, "info");
|
|
425
|
+
} catch (error) {
|
|
426
|
+
this.updateConnectionState("error");
|
|
427
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
428
|
+
this.notifyUser(`Failed to connect: ${errorMessage}`, "error");
|
|
429
|
+
if (error instanceof SubshellConnectionError && error.recoverable) {
|
|
430
|
+
this.notifyUser("Attempting to reconnect...", "info");
|
|
396
431
|
try {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
this.updateConnectionState('connected');
|
|
403
|
-
this.notifyUser(`Connected to ${handler.type} successfully`, 'info');
|
|
404
|
-
}
|
|
405
|
-
catch (error) {
|
|
406
|
-
this.updateConnectionState('error');
|
|
407
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
408
|
-
this.notifyUser(`Failed to connect: ${errorMessage}`, 'error');
|
|
409
|
-
// Check if error is recoverable
|
|
410
|
-
if (error instanceof SubshellConnectionError && error.recoverable) {
|
|
411
|
-
this.notifyUser('Attempting to reconnect...', 'info');
|
|
412
|
-
try {
|
|
413
|
-
await this.attemptReconnection(handler, command);
|
|
414
|
-
}
|
|
415
|
-
catch (reconnectError) {
|
|
416
|
-
const reconnectMsg = reconnectError instanceof Error ? reconnectError.message : String(reconnectError);
|
|
417
|
-
this.notifyUser(`Reconnection failed: ${reconnectMsg}`, 'error');
|
|
418
|
-
this.restoreLocalContext();
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
// Non-recoverable error, restore local context
|
|
423
|
-
this.restoreLocalContext();
|
|
424
|
-
}
|
|
425
|
-
throw error;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Restore local context after connection failure
|
|
430
|
-
*/
|
|
431
|
-
restoreLocalContext() {
|
|
432
|
-
// Pop all subshell contexts and return to local
|
|
433
|
-
while (this.contextStack.length > 1) {
|
|
434
|
-
const context = this.contextStack.pop();
|
|
435
|
-
if (context?.handler) {
|
|
436
|
-
context.handler.disconnect().catch((err) => {
|
|
437
|
-
logError('Error disconnecting handler', err);
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
this.updateConnectionState('connected');
|
|
442
|
-
this.notifyUser('Restored local context', 'info');
|
|
443
|
-
}
|
|
444
|
-
/**
|
|
445
|
-
* Attempt to reconnect to a subshell
|
|
446
|
-
*/
|
|
447
|
-
async attemptReconnection(handler, command, maxAttempts = 3) {
|
|
448
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
449
|
-
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 8000);
|
|
450
|
-
this.notifyUser(`Reconnection attempt ${attempt}/${maxAttempts}...`, 'info');
|
|
451
|
-
await this.sleep(delay);
|
|
452
|
-
try {
|
|
453
|
-
const cwd = this.getCurrentContext().metadata.workingDirectory;
|
|
454
|
-
const context = await handler.connect(command, cwd);
|
|
455
|
-
this.pushContext(context);
|
|
456
|
-
this.updateConnectionState('connected');
|
|
457
|
-
this.notifyUser('Reconnected successfully', 'info');
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
catch (error) {
|
|
461
|
-
if (attempt === maxAttempts) {
|
|
462
|
-
throw new SubshellConnectionError(handler.type, 'Reconnection failed after maximum attempts', false);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
432
|
+
await this.attemptReconnection(handler, command);
|
|
433
|
+
} catch (reconnectError) {
|
|
434
|
+
const reconnectMsg = reconnectError instanceof Error ? reconnectError.message : String(reconnectError);
|
|
435
|
+
this.notifyUser(`Reconnection failed: ${reconnectMsg}`, "error");
|
|
436
|
+
this.restoreLocalContext();
|
|
465
437
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Reset to local context (for error recovery)
|
|
484
|
-
*/
|
|
485
|
-
resetToLocal() {
|
|
486
|
-
// Disconnect all subshells
|
|
487
|
-
const handlers = this.contextStack
|
|
488
|
-
.filter(ctx => ctx.handler)
|
|
489
|
-
.map(ctx => ctx.handler);
|
|
490
|
-
// Clear stack except local context
|
|
491
|
-
this.contextStack = [this.contextStack[0]];
|
|
492
|
-
// Disconnect handlers asynchronously
|
|
493
|
-
handlers.forEach(handler => {
|
|
494
|
-
handler.disconnect().catch((err) => {
|
|
495
|
-
logError('Error disconnecting handler', err);
|
|
496
|
-
});
|
|
438
|
+
} else {
|
|
439
|
+
this.restoreLocalContext();
|
|
440
|
+
}
|
|
441
|
+
throw error;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Restore local context after connection failure
|
|
446
|
+
*/
|
|
447
|
+
restoreLocalContext() {
|
|
448
|
+
while (this.contextStack.length > 1) {
|
|
449
|
+
const context = this.contextStack.pop();
|
|
450
|
+
if (context?.handler) {
|
|
451
|
+
context.handler.disconnect().catch((err) => {
|
|
452
|
+
logError("Error disconnecting handler", err);
|
|
497
453
|
});
|
|
498
|
-
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
this.updateConnectionState("connected");
|
|
457
|
+
this.notifyUser("Restored local context", "info");
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Attempt to reconnect to a subshell
|
|
461
|
+
*/
|
|
462
|
+
async attemptReconnection(handler, command, maxAttempts = 3) {
|
|
463
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
464
|
+
const delay = Math.min(1e3 * Math.pow(2, attempt - 1), 8e3);
|
|
465
|
+
this.notifyUser(`Reconnection attempt ${attempt}/${maxAttempts}...`, "info");
|
|
466
|
+
await this.sleep(delay);
|
|
467
|
+
try {
|
|
468
|
+
const cwd = this.getCurrentContext().metadata.workingDirectory;
|
|
469
|
+
const context = await handler.connect(command, cwd);
|
|
470
|
+
this.pushContext(context);
|
|
471
|
+
this.updateConnectionState("connected");
|
|
472
|
+
this.notifyUser("Reconnected successfully", "info");
|
|
473
|
+
return;
|
|
474
|
+
} catch (error) {
|
|
475
|
+
if (attempt === maxAttempts) {
|
|
476
|
+
throw new SubshellConnectionError(
|
|
477
|
+
handler.type,
|
|
478
|
+
"Reconnection failed after maximum attempts",
|
|
479
|
+
false
|
|
480
|
+
);
|
|
508
481
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Utility method to sleep for a specified duration
|
|
487
|
+
*/
|
|
488
|
+
sleep(ms) {
|
|
489
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Execute an operation with a timeout
|
|
493
|
+
*/
|
|
494
|
+
async executeWithTimeout(operation, timeoutMs, operationName) {
|
|
495
|
+
return Promise.race([
|
|
496
|
+
operation(),
|
|
497
|
+
new Promise(
|
|
498
|
+
(_, reject) => setTimeout(
|
|
499
|
+
() => reject(new Error(`${operationName} timed out after ${timeoutMs}ms`)),
|
|
500
|
+
timeoutMs
|
|
501
|
+
)
|
|
502
|
+
)
|
|
503
|
+
]);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Reset to local context (for error recovery)
|
|
507
|
+
*/
|
|
508
|
+
resetToLocal() {
|
|
509
|
+
const handlers = this.contextStack.filter((ctx) => ctx.handler).map((ctx) => ctx.handler);
|
|
510
|
+
this.contextStack = [this.contextStack[0]];
|
|
511
|
+
handlers.forEach((handler) => {
|
|
512
|
+
handler.disconnect().catch((err) => {
|
|
513
|
+
logError("Error disconnecting handler", err);
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
this.notifyContextChange();
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Handle connection loss and attempt recovery
|
|
520
|
+
*/
|
|
521
|
+
async handleConnectionLoss(error) {
|
|
522
|
+
const context = this.getCurrentContext();
|
|
523
|
+
if (context.type === "local") {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
this.updateConnectionState("error");
|
|
527
|
+
this.notifyUser(`Connection lost: ${error.message}`, "error");
|
|
528
|
+
if (context.handler) {
|
|
529
|
+
try {
|
|
530
|
+
this.notifyUser("Attempting to reconnect...", "info");
|
|
531
|
+
this.restoreLocalContext();
|
|
532
|
+
} catch (reconnectError) {
|
|
533
|
+
this.notifyUser("Reconnection failed, restoring local context", "error");
|
|
534
|
+
this.restoreLocalContext();
|
|
535
|
+
}
|
|
536
|
+
} else {
|
|
537
|
+
this.restoreLocalContext();
|
|
538
|
+
}
|
|
539
|
+
}
|
|
528
540
|
}
|
|
541
|
+
export {
|
|
542
|
+
ContextManager
|
|
543
|
+
};
|
|
529
544
|
//# sourceMappingURL=context-manager.js.map
|