@machina.ai/cell-cli-core 1.0.13-rc9 → 1.0.21-rc1
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/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/package.json +12 -4
- package/dist/src/code_assist/converter.d.ts +6 -3
- package/dist/src/code_assist/converter.js +4 -2
- package/dist/src/code_assist/converter.js.map +1 -1
- package/dist/src/code_assist/converter.test.js +61 -11
- package/dist/src/code_assist/converter.test.js.map +1 -1
- package/dist/src/code_assist/oauth2.d.ts +1 -0
- package/dist/src/code_assist/oauth2.js +43 -18
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +142 -9
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/code_assist/server.d.ts +2 -2
- package/dist/src/code_assist/server.js +5 -5
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +13 -10
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/code_assist/setup.js +49 -18
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/code_assist/setup.test.js +115 -9
- package/dist/src/code_assist/setup.test.js.map +1 -1
- package/dist/src/config/config.d.ts +71 -13
- package/dist/src/config/config.js +154 -41
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +206 -21
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/flashFallback.test.js +19 -47
- package/dist/src/config/flashFallback.test.js.map +1 -1
- package/dist/src/config/models.d.ts +1 -0
- package/dist/src/config/models.js +1 -0
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/core/client.d.ts +15 -16
- package/dist/src/core/client.js +247 -104
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +798 -49
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +2 -2
- package/dist/src/core/contentGenerator.js +23 -21
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +30 -126
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +23 -10
- package/dist/src/core/coreToolScheduler.js +201 -77
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +322 -94
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +8 -6
- package/dist/src/core/geminiChat.js +49 -51
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +2 -2
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/geminiRequest.js +2 -37
- package/dist/src/core/geminiRequest.js.map +1 -1
- package/dist/src/core/logger.d.ts +24 -1
- package/dist/src/core/logger.js +128 -4
- package/dist/src/core/logger.js.map +1 -1
- package/dist/src/core/logger.test.js +157 -11
- package/dist/src/core/logger.test.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.d.ts +25 -0
- package/dist/src/core/loggingContentGenerator.js +95 -0
- package/dist/src/core/loggingContentGenerator.js.map +1 -0
- package/dist/src/core/nonInteractiveToolExecutor.js +39 -4
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +85 -62
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
- package/dist/src/core/prompts.js +43 -19
- package/dist/src/core/prompts.js.map +1 -1
- package/dist/src/core/prompts.test.js +118 -1
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/core/subagent.d.ts +230 -0
- package/dist/src/core/subagent.js +447 -0
- package/dist/src/core/subagent.js.map +1 -0
- package/dist/src/core/subagent.test.js +515 -0
- package/dist/src/core/subagent.test.js.map +1 -0
- package/dist/src/core/tokenLimits.js +1 -0
- package/dist/src/core/tokenLimits.js.map +1 -1
- package/dist/src/core/turn.d.ts +3 -0
- package/dist/src/core/turn.js +4 -0
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/core/turn.test.js +4 -0
- package/dist/src/core/turn.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +7 -0
- package/dist/src/generated/git-commit.js +10 -0
- package/dist/src/generated/git-commit.js.map +1 -0
- package/dist/src/ide/constants.d.ts +6 -0
- package/dist/src/ide/constants.js +7 -0
- package/dist/src/ide/constants.js.map +1 -0
- package/dist/src/ide/detect-ide.d.ts +20 -0
- package/dist/src/ide/detect-ide.js +86 -0
- package/dist/src/ide/detect-ide.js.map +1 -0
- package/dist/src/ide/detect-ide.test.js +65 -0
- package/dist/src/ide/detect-ide.test.js.map +1 -0
- package/dist/src/ide/ide-client.d.ts +63 -0
- package/dist/src/ide/ide-client.js +320 -0
- package/dist/src/ide/ide-client.js.map +1 -0
- package/dist/src/ide/ide-client.test.d.ts +6 -0
- package/dist/src/ide/ide-client.test.js +43 -0
- package/dist/src/ide/ide-client.test.js.map +1 -0
- package/dist/src/ide/ide-installer.d.ts +14 -0
- package/dist/src/ide/ide-installer.js +98 -0
- package/dist/src/ide/ide-installer.js.map +1 -0
- package/dist/src/ide/ide-installer.test.d.ts +6 -0
- package/dist/src/ide/ide-installer.test.js +53 -0
- package/dist/src/ide/ide-installer.test.js.map +1 -0
- package/dist/src/ide/ideContext.d.ts +374 -0
- package/dist/src/ide/ideContext.js +147 -0
- package/dist/src/ide/ideContext.js.map +1 -0
- package/dist/src/ide/ideContext.test.d.ts +6 -0
- package/dist/src/ide/ideContext.test.js +265 -0
- package/dist/src/ide/ideContext.test.js.map +1 -0
- package/dist/src/ide/process-utils.d.ts +14 -0
- package/dist/src/ide/process-utils.js +57 -0
- package/dist/src/ide/process-utils.js.map +1 -0
- package/dist/src/index.d.ts +17 -1
- package/dist/src/index.js +20 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.d.ts +23 -0
- package/dist/src/mcp/google-auth-provider.js +72 -0
- package/dist/src/mcp/google-auth-provider.js.map +1 -0
- package/dist/src/mcp/google-auth-provider.test.d.ts +6 -0
- package/dist/src/mcp/google-auth-provider.test.js +89 -0
- package/dist/src/mcp/google-auth-provider.test.js.map +1 -0
- package/dist/src/mcp/oauth-provider.d.ts +6 -2
- package/dist/src/mcp/oauth-provider.js +208 -53
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-provider.test.js +222 -70
- package/dist/src/mcp/oauth-provider.test.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.d.ts +3 -1
- package/dist/src/mcp/oauth-token-storage.js +3 -1
- package/dist/src/mcp/oauth-token-storage.js.map +1 -1
- package/dist/src/mcp/oauth-utils.d.ts +3 -1
- package/dist/src/mcp/oauth-utils.js +52 -14
- package/dist/src/mcp/oauth-utils.js.map +1 -1
- package/dist/src/mcp/oauth-utils.test.js +18 -3
- package/dist/src/mcp/oauth-utils.test.js.map +1 -1
- package/dist/src/mocks/msw.d.ts +6 -0
- package/dist/src/mocks/msw.js +8 -0
- package/dist/src/mocks/msw.js.map +1 -0
- package/dist/src/prompts/mcp-prompts.d.ts +8 -0
- package/dist/src/prompts/mcp-prompts.js +13 -0
- package/dist/src/prompts/mcp-prompts.js.map +1 -0
- package/dist/src/prompts/prompt-registry.d.ts +34 -0
- package/dist/src/prompts/prompt-registry.js +63 -0
- package/dist/src/prompts/prompt-registry.js.map +1 -0
- package/dist/src/services/chatRecordingService.d.ts +150 -0
- package/dist/src/services/chatRecordingService.js +318 -0
- package/dist/src/services/chatRecordingService.js.map +1 -0
- package/dist/src/services/chatRecordingService.test.d.ts +6 -0
- package/dist/src/services/chatRecordingService.test.js +288 -0
- package/dist/src/services/chatRecordingService.test.js.map +1 -0
- package/dist/src/services/fileDiscoveryService.test.js +101 -60
- package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
- package/dist/src/services/fileSystemService.d.ts +31 -0
- package/dist/src/services/fileSystemService.js +18 -0
- package/dist/src/services/fileSystemService.js.map +1 -0
- package/dist/src/services/fileSystemService.test.d.ts +6 -0
- package/dist/src/services/fileSystemService.test.js +41 -0
- package/dist/src/services/fileSystemService.test.js.map +1 -0
- package/dist/src/services/gitService.test.js +67 -86
- package/dist/src/services/gitService.test.js.map +1 -1
- package/dist/src/services/loopDetectionService.d.ts +51 -5
- package/dist/src/services/loopDetectionService.js +152 -45
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/loopDetectionService.test.js +286 -89
- package/dist/src/services/loopDetectionService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.d.ts +70 -0
- package/dist/src/services/shellExecutionService.js +175 -0
- package/dist/src/services/shellExecutionService.js.map +1 -0
- package/dist/src/services/shellExecutionService.test.d.ts +6 -0
- package/dist/src/services/shellExecutionService.test.js +282 -0
- package/dist/src/services/shellExecutionService.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +81 -9
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +356 -182
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +17 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +342 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +19 -2
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +51 -9
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/constants.d.ts +4 -0
- package/dist/src/telemetry/constants.js +4 -0
- package/dist/src/telemetry/constants.js.map +1 -1
- package/dist/src/telemetry/file-exporters.d.ts +28 -0
- package/dist/src/telemetry/file-exporters.js +62 -0
- package/dist/src/telemetry/file-exporters.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +2 -2
- package/dist/src/telemetry/index.js +2 -2
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/integration.test.circular.js +1 -0
- package/dist/src/telemetry/integration.test.circular.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +6 -1
- package/dist/src/telemetry/loggers.js +87 -6
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.circular.js +9 -2
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +51 -11
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +7 -2
- package/dist/src/telemetry/metrics.js +26 -6
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/metrics.test.js +81 -1
- package/dist/src/telemetry/metrics.test.js.map +1 -1
- package/dist/src/telemetry/sdk.d.ts +1 -1
- package/dist/src/telemetry/sdk.js +77 -30
- package/dist/src/telemetry/sdk.js.map +1 -1
- package/dist/src/telemetry/sdk.test.d.ts +6 -0
- package/dist/src/telemetry/sdk.test.js +82 -0
- package/dist/src/telemetry/sdk.test.js.map +1 -0
- package/dist/src/telemetry/telemetry.test.js +2 -2
- package/dist/src/telemetry/telemetry.test.js.map +1 -1
- package/dist/src/telemetry/tool-call-decision.d.ts +13 -0
- package/dist/src/telemetry/tool-call-decision.js +29 -0
- package/dist/src/telemetry/tool-call-decision.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +74 -18
- package/dist/src/telemetry/types.js +110 -32
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.d.ts +8 -1
- package/dist/src/telemetry/uiTelemetry.js +17 -2
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +60 -10
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/test-utils/config.d.ts +16 -0
- package/dist/src/test-utils/config.js +32 -0
- package/dist/src/test-utils/config.js.map +1 -0
- package/dist/src/test-utils/mockWorkspaceContext.d.ts +13 -0
- package/dist/src/test-utils/mockWorkspaceContext.js +24 -0
- package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -0
- package/dist/src/test-utils/tools.d.ts +44 -0
- package/dist/src/test-utils/tools.js +105 -0
- package/dist/src/test-utils/tools.js.map +1 -0
- package/dist/src/tools/diffOptions.d.ts +2 -0
- package/dist/src/tools/diffOptions.js +28 -0
- package/dist/src/tools/diffOptions.js.map +1 -1
- package/dist/src/tools/diffOptions.test.d.ts +6 -0
- package/dist/src/tools/diffOptions.test.js +119 -0
- package/dist/src/tools/diffOptions.test.js.map +1 -0
- package/dist/src/tools/edit.d.ts +10 -34
- package/dist/src/tools/edit.js +171 -131
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +220 -43
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/glob.d.ts +4 -11
- package/dist/src/tools/glob.js +129 -97
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +73 -17
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/grep.d.ts +5 -37
- package/dist/src/tools/grep.js +175 -100
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +112 -28
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.d.ts +4 -23
- package/dist/src/tools/ls.js +77 -78
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/ls.test.d.ts +6 -0
- package/dist/src/tools/ls.test.js +384 -0
- package/dist/src/tools/ls.test.js.map +1 -0
- package/dist/src/tools/mcp-client-manager.d.ts +38 -0
- package/dist/src/tools/mcp-client-manager.js +74 -0
- package/dist/src/tools/mcp-client-manager.js.map +1 -0
- package/dist/src/tools/mcp-client-manager.test.d.ts +6 -0
- package/dist/src/tools/mcp-client-manager.test.js +39 -0
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -0
- package/dist/src/tools/mcp-client.d.ts +86 -4
- package/dist/src/tools/mcp-client.js +730 -59
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +295 -22
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +6 -13
- package/dist/src/tools/mcp-tool.js +163 -76
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/mcp-tool.test.js +400 -29
- package/dist/src/tools/mcp-tool.test.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +14 -3
- package/dist/src/tools/memoryTool.js +159 -40
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/memoryTool.test.js +116 -11
- package/dist/src/tools/memoryTool.test.js.map +1 -1
- package/dist/src/tools/modifiable-tool.d.ts +9 -6
- package/dist/src/tools/modifiable-tool.js +6 -3
- package/dist/src/tools/modifiable-tool.js.map +1 -1
- package/dist/src/tools/modifiable-tool.test.js +63 -74
- package/dist/src/tools/modifiable-tool.test.js.map +1 -1
- package/dist/src/tools/read-file.d.ts +4 -6
- package/dist/src/tools/read-file.js +100 -53
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-file.test.js +238 -111
- package/dist/src/tools/read-file.test.js.map +1 -1
- package/dist/src/tools/read-many-files.d.ts +3 -6
- package/dist/src/tools/read-many-files.js +232 -157
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +231 -34
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/shell.d.ts +6 -28
- package/dist/src/tools/shell.js +249 -366
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +305 -384
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +27 -0
- package/dist/src/tools/tool-error.js +32 -0
- package/dist/src/tools/tool-error.js.map +1 -0
- package/dist/src/tools/tool-registry.d.ts +38 -23
- package/dist/src/tools/tool-registry.js +127 -99
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +37 -212
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +145 -92
- package/dist/src/tools/tools.js +188 -61
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/tools.test.d.ts +6 -0
- package/dist/src/tools/tools.test.js +206 -0
- package/dist/src/tools/tools.test.js.map +1 -0
- package/dist/src/tools/web-fetch.d.ts +4 -7
- package/dist/src/tools/web-fetch.js +58 -64
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-fetch.test.js +8 -4
- package/dist/src/tools/web-fetch.test.js.map +1 -1
- package/dist/src/tools/web-search.d.ts +4 -5
- package/dist/src/tools/web-search.js +47 -51
- package/dist/src/tools/web-search.js.map +1 -1
- package/dist/src/tools/web-search.test.d.ts +6 -0
- package/dist/src/tools/web-search.test.js +139 -0
- package/dist/src/tools/web-search.test.js.map +1 -0
- package/dist/src/tools/write-file.d.ts +20 -11
- package/dist/src/tools/write-file.js +198 -141
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +190 -76
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/utils/bfsFileSearch.js +51 -27
- package/dist/src/utils/bfsFileSearch.js.map +1 -1
- package/dist/src/utils/bfsFileSearch.test.js +137 -136
- package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
- package/dist/src/utils/browser.js +4 -3
- package/dist/src/utils/browser.js.map +1 -1
- package/dist/src/utils/editCorrector.js +23 -24
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/editor.d.ts +2 -2
- package/dist/src/utils/editor.js +23 -6
- package/dist/src/utils/editor.js.map +1 -1
- package/dist/src/utils/editor.test.js +67 -15
- package/dist/src/utils/editor.test.js.map +1 -1
- package/dist/src/utils/environmentContext.d.ts +21 -0
- package/dist/src/utils/environmentContext.js +90 -0
- package/dist/src/utils/environmentContext.js.map +1 -0
- package/dist/src/utils/environmentContext.test.d.ts +6 -0
- package/dist/src/utils/environmentContext.test.js +140 -0
- package/dist/src/utils/environmentContext.test.js.map +1 -0
- package/dist/src/utils/errorParsing.d.ts +8 -0
- package/dist/src/utils/errorParsing.js +93 -0
- package/dist/src/utils/errorParsing.js.map +1 -0
- package/dist/src/utils/errorParsing.test.d.ts +6 -0
- package/dist/src/utils/errorParsing.test.js +172 -0
- package/dist/src/utils/errorParsing.test.js.map +1 -0
- package/dist/src/utils/errorReporting.d.ts +1 -1
- package/dist/src/utils/errorReporting.js +2 -2
- package/dist/src/utils/errorReporting.js.map +1 -1
- package/dist/src/utils/errorReporting.test.js +44 -38
- package/dist/src/utils/errorReporting.test.js.map +1 -1
- package/dist/src/utils/fileUtils.d.ts +9 -1
- package/dist/src/utils/fileUtils.js +27 -13
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +61 -18
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/filesearch/crawlCache.d.ts +25 -0
- package/dist/src/utils/filesearch/crawlCache.js +57 -0
- package/dist/src/utils/filesearch/crawlCache.js.map +1 -0
- package/dist/src/utils/filesearch/crawlCache.test.d.ts +6 -0
- package/dist/src/utils/filesearch/crawlCache.test.js +103 -0
- package/dist/src/utils/filesearch/crawlCache.test.js.map +1 -0
- package/dist/src/utils/filesearch/crawler.d.ts +15 -0
- package/dist/src/utils/filesearch/crawler.js +50 -0
- package/dist/src/utils/filesearch/crawler.js.map +1 -0
- package/dist/src/utils/filesearch/crawler.test.d.ts +6 -0
- package/dist/src/utils/filesearch/crawler.test.js +468 -0
- package/dist/src/utils/filesearch/crawler.test.js.map +1 -0
- package/dist/src/utils/filesearch/fileSearch.d.ts +37 -0
- package/dist/src/utils/filesearch/fileSearch.js +186 -0
- package/dist/src/utils/filesearch/fileSearch.js.map +1 -0
- package/dist/src/utils/filesearch/fileSearch.test.d.ts +6 -0
- package/dist/src/utils/filesearch/fileSearch.test.js +552 -0
- package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -0
- package/dist/src/utils/filesearch/ignore.d.ts +42 -0
- package/dist/src/utils/filesearch/ignore.js +106 -0
- package/dist/src/utils/filesearch/ignore.js.map +1 -0
- package/dist/src/utils/filesearch/ignore.test.d.ts +6 -0
- package/dist/src/utils/filesearch/ignore.test.js +144 -0
- package/dist/src/utils/filesearch/ignore.test.js.map +1 -0
- package/dist/src/utils/filesearch/result-cache.d.ts +33 -0
- package/dist/src/utils/filesearch/result-cache.js +59 -0
- package/dist/src/utils/filesearch/result-cache.js.map +1 -0
- package/dist/src/utils/filesearch/result-cache.test.d.ts +6 -0
- package/dist/src/utils/filesearch/result-cache.test.js +46 -0
- package/dist/src/utils/filesearch/result-cache.test.js.map +1 -0
- package/dist/src/utils/flashFallback.integration.test.js +6 -0
- package/dist/src/utils/flashFallback.integration.test.js.map +1 -1
- package/dist/src/utils/formatters.d.ts +6 -0
- package/dist/src/utils/formatters.js +16 -0
- package/dist/src/utils/formatters.js.map +1 -0
- package/dist/src/utils/getFolderStructure.test.js +11 -13
- package/dist/src/utils/getFolderStructure.test.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.js +5 -11
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.test.js +58 -61
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.d.ts +1 -1
- package/dist/src/utils/memoryDiscovery.js +76 -83
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +122 -372
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.d.ts +19 -12
- package/dist/src/utils/memoryImportProcessor.js +240 -85
- package/dist/src/utils/memoryImportProcessor.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.test.js +593 -51
- package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.js +4 -25
- package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
- package/dist/src/utils/partUtils.d.ts +14 -0
- package/dist/src/utils/partUtils.js +65 -0
- package/dist/src/utils/partUtils.js.map +1 -0
- package/dist/src/utils/partUtils.test.d.ts +6 -0
- package/dist/src/utils/partUtils.test.js +130 -0
- package/dist/src/utils/partUtils.test.js.map +1 -0
- package/dist/src/utils/paths.d.ts +18 -2
- package/dist/src/utils/paths.js +39 -7
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/paths.test.d.ts +6 -0
- package/dist/src/utils/paths.test.js +225 -0
- package/dist/src/utils/paths.test.js.map +1 -0
- package/dist/src/utils/quotaErrorDetection.d.ts +1 -5
- package/dist/src/utils/quotaErrorDetection.js.map +1 -1
- package/dist/src/utils/retry.d.ts +3 -0
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/schemaValidator.d.ts +1 -8
- package/dist/src/utils/schemaValidator.js +1 -32
- package/dist/src/utils/schemaValidator.js.map +1 -1
- package/dist/src/utils/secure-browser-launcher.d.ts +23 -0
- package/dist/src/utils/secure-browser-launcher.js +165 -0
- package/dist/src/utils/secure-browser-launcher.js.map +1 -0
- package/dist/src/utils/secure-browser-launcher.test.d.ts +6 -0
- package/dist/src/utils/secure-browser-launcher.test.js +149 -0
- package/dist/src/utils/secure-browser-launcher.test.js.map +1 -0
- package/dist/src/utils/shell-utils.d.ts +117 -0
- package/dist/src/utils/shell-utils.js +376 -0
- package/dist/src/utils/shell-utils.js.map +1 -0
- package/dist/src/utils/shell-utils.test.d.ts +6 -0
- package/dist/src/utils/shell-utils.test.js +328 -0
- package/dist/src/utils/shell-utils.test.js.map +1 -0
- package/dist/src/utils/summarizer.js +3 -32
- package/dist/src/utils/summarizer.js.map +1 -1
- package/dist/src/utils/systemEncoding.js +1 -1
- package/dist/src/utils/systemEncoding.js.map +1 -1
- package/dist/src/utils/systemEncoding.test.js +23 -23
- package/dist/src/utils/systemEncoding.test.js.map +1 -1
- package/dist/src/utils/textUtils.d.ts +13 -0
- package/dist/src/utils/textUtils.js +28 -0
- package/dist/src/utils/textUtils.js.map +1 -0
- package/dist/src/utils/user_account.js +58 -48
- package/dist/src/utils/user_account.js.map +1 -1
- package/dist/src/utils/user_account.test.js +76 -9
- package/dist/src/utils/user_account.test.js.map +1 -1
- package/dist/src/utils/workspaceContext.d.ts +66 -0
- package/dist/src/utils/workspaceContext.js +165 -0
- package/dist/src/utils/workspaceContext.js.map +1 -0
- package/dist/src/utils/workspaceContext.test.d.ts +6 -0
- package/dist/src/utils/workspaceContext.test.js +293 -0
- package/dist/src/utils/workspaceContext.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -3
- package/dist/src/core/geminiRequest.test.js +0 -72
- package/dist/src/core/geminiRequest.test.js.map +0 -1
- package/dist/src/core/modelCheck.d.ts +0 -14
- package/dist/src/core/modelCheck.js +0 -62
- package/dist/src/core/modelCheck.js.map +0 -1
- package/dist/src/services/ideContext.d.ts +0 -178
- package/dist/src/services/ideContext.js +0 -105
- package/dist/src/services/ideContext.js.map +0 -1
- package/dist/src/services/ideContext.test.js +0 -111
- package/dist/src/services/ideContext.test.js.map +0 -1
- /package/dist/src/core/{geminiRequest.test.d.ts → subagent.test.d.ts} +0 -0
- /package/dist/src/{services/ideContext.test.d.ts → ide/detect-ide.test.d.ts} +0 -0
package/dist/src/tools/shell.js
CHANGED
|
@@ -7,227 +7,57 @@ import fs from 'fs';
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import os from 'os';
|
|
9
9
|
import crypto from 'crypto';
|
|
10
|
-
import {
|
|
11
|
-
import { Type } from '@google/genai';
|
|
12
|
-
import { SchemaValidator } from '../utils/schemaValidator.js';
|
|
10
|
+
import { BaseDeclarativeTool, BaseToolInvocation, ToolConfirmationOutcome, Kind, } from './tools.js';
|
|
13
11
|
import { getErrorMessage } from '../utils/errors.js';
|
|
14
|
-
import stripAnsi from 'strip-ansi';
|
|
15
|
-
import { spawn } from 'child_process';
|
|
16
12
|
import { summarizeToolOutput } from '../utils/summarizer.js';
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
import { ShellExecutionService, } from '../services/shellExecutionService.js';
|
|
14
|
+
import { formatMemoryUsage } from '../utils/formatters.js';
|
|
15
|
+
import { getCommandRoots, isCommandAllowed, stripShellWrapper, } from '../utils/shell-utils.js';
|
|
16
|
+
export const OUTPUT_UPDATE_INTERVAL_MS = 1000;
|
|
17
|
+
class ShellToolInvocation extends BaseToolInvocation {
|
|
19
18
|
config;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
super(ShellTool.Name, 'Shell', `This tool executes a given shell command as \`bash -c <command>\`. Command can start background processes using \`&\`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as \`kill -- -PGID\` or signaled as \`kill -s SIGNAL -- -PGID\`.
|
|
24
|
-
|
|
25
|
-
The following information is returned:
|
|
26
|
-
|
|
27
|
-
Command: Executed command.
|
|
28
|
-
Directory: Directory (relative to project root) where command was executed, or \`(root)\`.
|
|
29
|
-
Stdout: Output on stdout stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
|
|
30
|
-
Stderr: Output on stderr stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
|
|
31
|
-
Error: Error or \`(none)\` if no error was reported for the subprocess.
|
|
32
|
-
Exit Code: Exit code or \`(none)\` if terminated by signal.
|
|
33
|
-
Signal: Signal number or \`(none)\` if no signal was received.
|
|
34
|
-
Background PIDs: List of background processes started or \`(none)\`.
|
|
35
|
-
Process Group PGID: Process group started or \`(none)\``, Icon.Terminal, {
|
|
36
|
-
type: Type.OBJECT,
|
|
37
|
-
properties: {
|
|
38
|
-
command: {
|
|
39
|
-
type: Type.STRING,
|
|
40
|
-
description: 'Exact bash command to execute as `bash -c <command>`',
|
|
41
|
-
},
|
|
42
|
-
description: {
|
|
43
|
-
type: Type.STRING,
|
|
44
|
-
description: 'Brief description of the command for the user. Be specific and concise. Ideally a single sentence. Can be up to 3 sentences for clarity. No line breaks.',
|
|
45
|
-
},
|
|
46
|
-
directory: {
|
|
47
|
-
type: Type.STRING,
|
|
48
|
-
description: '(OPTIONAL) Directory to run the command in, if not the project root directory. Must be relative to the project root directory and must already exist.',
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
required: ['command'],
|
|
52
|
-
}, false, // output is not markdown
|
|
53
|
-
true);
|
|
19
|
+
allowlist;
|
|
20
|
+
constructor(config, params, allowlist) {
|
|
21
|
+
super(params);
|
|
54
22
|
this.config = config;
|
|
23
|
+
this.allowlist = allowlist;
|
|
55
24
|
}
|
|
56
|
-
getDescription(
|
|
57
|
-
let description = `${params.command}`;
|
|
25
|
+
getDescription() {
|
|
26
|
+
let description = `${this.params.command}`;
|
|
58
27
|
// append optional [in directory]
|
|
59
28
|
// note description is needed even if validation fails due to absolute path
|
|
60
|
-
if (params.directory) {
|
|
61
|
-
description += ` [in ${params.directory}]`;
|
|
29
|
+
if (this.params.directory) {
|
|
30
|
+
description += ` [in ${this.params.directory}]`;
|
|
62
31
|
}
|
|
63
32
|
// append optional (description), replacing any line breaks with spaces
|
|
64
|
-
if (params.description) {
|
|
65
|
-
description += ` (${params.description.replace(/\n/g, ' ')})`;
|
|
33
|
+
if (this.params.description) {
|
|
34
|
+
description += ` (${this.params.description.replace(/\n/g, ' ')})`;
|
|
66
35
|
}
|
|
67
36
|
return description;
|
|
68
37
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
* @returns The root command name, or undefined if it cannot be determined
|
|
75
|
-
* @example getCommandRoot("ls -la /tmp") returns "ls"
|
|
76
|
-
* @example getCommandRoot("git status && npm test") returns "git"
|
|
77
|
-
*/
|
|
78
|
-
getCommandRoot(command) {
|
|
79
|
-
return command
|
|
80
|
-
.trim() // remove leading and trailing whitespace
|
|
81
|
-
.replace(/[{}()]/g, '') // remove all grouping operators
|
|
82
|
-
.split(/[\s;&|]+/)[0] // split on any whitespace or separator or chaining operators and take first part
|
|
83
|
-
?.split(/[/\\]/) // split on any path separators (or return undefined if previous line was undefined)
|
|
84
|
-
.pop(); // take last part and return command root (or undefined if previous line was empty)
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Determines whether a given shell command is allowed to execute based on
|
|
88
|
-
* the tool's configuration including allowlists and blocklists.
|
|
89
|
-
*
|
|
90
|
-
* @param command The shell command string to validate
|
|
91
|
-
* @returns An object with 'allowed' boolean and optional 'reason' string if not allowed
|
|
92
|
-
*/
|
|
93
|
-
isCommandAllowed(command) {
|
|
94
|
-
// 0. Disallow command substitution
|
|
95
|
-
if (command.includes('$(')) {
|
|
96
|
-
return {
|
|
97
|
-
allowed: false,
|
|
98
|
-
reason: 'Command substitution using $() is not allowed for security reasons',
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
const SHELL_TOOL_NAMES = [ShellTool.name, ShellTool.Name];
|
|
102
|
-
const normalize = (cmd) => cmd.trim().replace(/\s+/g, ' ');
|
|
103
|
-
/**
|
|
104
|
-
* Checks if a command string starts with a given prefix, ensuring it's a
|
|
105
|
-
* whole word match (i.e., followed by a space or it's an exact match).
|
|
106
|
-
* e.g., `isPrefixedBy('npm install', 'npm')` -> true
|
|
107
|
-
* e.g., `isPrefixedBy('npm', 'npm')` -> true
|
|
108
|
-
* e.g., `isPrefixedBy('npminstall', 'npm')` -> false
|
|
109
|
-
*/
|
|
110
|
-
const isPrefixedBy = (cmd, prefix) => {
|
|
111
|
-
if (!cmd.startsWith(prefix)) {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
return cmd.length === prefix.length || cmd[prefix.length] === ' ';
|
|
115
|
-
};
|
|
116
|
-
/**
|
|
117
|
-
* Extracts and normalizes shell commands from a list of tool strings.
|
|
118
|
-
* e.g., 'ShellTool("ls -l")' becomes 'ls -l'
|
|
119
|
-
*/
|
|
120
|
-
const extractCommands = (tools) => tools.flatMap((tool) => {
|
|
121
|
-
for (const toolName of SHELL_TOOL_NAMES) {
|
|
122
|
-
if (tool.startsWith(`${toolName}(`) && tool.endsWith(')')) {
|
|
123
|
-
return [normalize(tool.slice(toolName.length + 1, -1))];
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return [];
|
|
127
|
-
});
|
|
128
|
-
const coreTools = this.config.getCoreTools() || [];
|
|
129
|
-
const excludeTools = this.config.getExcludeTools() || [];
|
|
130
|
-
// 1. Check if the shell tool is globally disabled.
|
|
131
|
-
if (SHELL_TOOL_NAMES.some((name) => excludeTools.includes(name))) {
|
|
132
|
-
return {
|
|
133
|
-
allowed: false,
|
|
134
|
-
reason: 'Shell tool is globally disabled in configuration',
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
const blockedCommands = new Set(extractCommands(excludeTools));
|
|
138
|
-
const allowedCommands = new Set(extractCommands(coreTools));
|
|
139
|
-
const hasSpecificAllowedCommands = allowedCommands.size > 0;
|
|
140
|
-
const isWildcardAllowed = SHELL_TOOL_NAMES.some((name) => coreTools.includes(name));
|
|
141
|
-
const commandsToValidate = command.split(/&&|\|\||\||;/).map(normalize);
|
|
142
|
-
const blockedCommandsArr = [...blockedCommands];
|
|
143
|
-
for (const cmd of commandsToValidate) {
|
|
144
|
-
// 2. Check if the command is on the blocklist.
|
|
145
|
-
const isBlocked = blockedCommandsArr.some((blocked) => isPrefixedBy(cmd, blocked));
|
|
146
|
-
if (isBlocked) {
|
|
147
|
-
return {
|
|
148
|
-
allowed: false,
|
|
149
|
-
reason: `Command '${cmd}' is blocked by configuration`,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
// 3. If in strict allow-list mode, check if the command is permitted.
|
|
153
|
-
const isStrictAllowlist = hasSpecificAllowedCommands && !isWildcardAllowed;
|
|
154
|
-
const allowedCommandsArr = [...allowedCommands];
|
|
155
|
-
if (isStrictAllowlist) {
|
|
156
|
-
const isAllowed = allowedCommandsArr.some((allowed) => isPrefixedBy(cmd, allowed));
|
|
157
|
-
if (!isAllowed) {
|
|
158
|
-
return {
|
|
159
|
-
allowed: false,
|
|
160
|
-
reason: `Command '${cmd}' is not in the allowed commands list`,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
// 4. If all checks pass, the command is allowed.
|
|
166
|
-
return { allowed: true };
|
|
167
|
-
}
|
|
168
|
-
validateToolParams(params) {
|
|
169
|
-
const commandCheck = this.isCommandAllowed(params.command);
|
|
170
|
-
if (!commandCheck.allowed) {
|
|
171
|
-
if (!commandCheck.reason) {
|
|
172
|
-
console.error('Unexpected: isCommandAllowed returned false without a reason');
|
|
173
|
-
return `Command is not allowed: ${params.command}`;
|
|
174
|
-
}
|
|
175
|
-
return commandCheck.reason;
|
|
176
|
-
}
|
|
177
|
-
const errors = SchemaValidator.validate(this.schema.parameters, params);
|
|
178
|
-
if (errors) {
|
|
179
|
-
return errors;
|
|
180
|
-
}
|
|
181
|
-
if (!params.command.trim()) {
|
|
182
|
-
return 'Command cannot be empty.';
|
|
183
|
-
}
|
|
184
|
-
if (!this.getCommandRoot(params.command)) {
|
|
185
|
-
return 'Could not identify command root to obtain permission from user.';
|
|
186
|
-
}
|
|
187
|
-
if (params.directory) {
|
|
188
|
-
if (path.isAbsolute(params.directory)) {
|
|
189
|
-
return 'Directory cannot be absolute. Must be relative to the project root directory.';
|
|
190
|
-
}
|
|
191
|
-
const directory = path.resolve(this.config.getTargetDir(), params.directory);
|
|
192
|
-
if (!fs.existsSync(directory)) {
|
|
193
|
-
return 'Directory must exist.';
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
async shouldConfirmExecute(params, _abortSignal) {
|
|
199
|
-
if (this.validateToolParams(params)) {
|
|
200
|
-
return false; // skip confirmation, execute call will fail immediately
|
|
201
|
-
}
|
|
202
|
-
const rootCommand = this.getCommandRoot(params.command); // must be non-empty string post-validation
|
|
203
|
-
if (this.whitelist.has(rootCommand)) {
|
|
38
|
+
async shouldConfirmExecute(_abortSignal) {
|
|
39
|
+
const command = stripShellWrapper(this.params.command);
|
|
40
|
+
const rootCommands = [...new Set(getCommandRoots(command))];
|
|
41
|
+
const commandsToConfirm = rootCommands.filter((command) => !this.allowlist.has(command));
|
|
42
|
+
if (commandsToConfirm.length === 0) {
|
|
204
43
|
return false; // already approved and whitelisted
|
|
205
44
|
}
|
|
206
45
|
const confirmationDetails = {
|
|
207
46
|
type: 'exec',
|
|
208
47
|
title: 'Confirm Shell Command',
|
|
209
|
-
command: params.command,
|
|
210
|
-
rootCommand,
|
|
48
|
+
command: this.params.command,
|
|
49
|
+
rootCommand: commandsToConfirm.join(', '),
|
|
211
50
|
onConfirm: async (outcome) => {
|
|
212
51
|
if (outcome === ToolConfirmationOutcome.ProceedAlways) {
|
|
213
|
-
this.
|
|
52
|
+
commandsToConfirm.forEach((command) => this.allowlist.add(command));
|
|
214
53
|
}
|
|
215
54
|
},
|
|
216
55
|
};
|
|
217
56
|
return confirmationDetails;
|
|
218
57
|
}
|
|
219
|
-
async execute(
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
-
return {
|
|
223
|
-
llmContent: [
|
|
224
|
-
`Command rejected: ${params.command}`,
|
|
225
|
-
`Reason: ${validationError}`,
|
|
226
|
-
].join('\n'),
|
|
227
|
-
returnDisplay: `Error: ${validationError}`,
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
if (abortSignal.aborted) {
|
|
58
|
+
async execute(signal, updateOutput) {
|
|
59
|
+
const strippedCommand = stripShellWrapper(this.params.command);
|
|
60
|
+
if (signal.aborted) {
|
|
231
61
|
return {
|
|
232
62
|
llmContent: 'Command was cancelled by user before it could start.',
|
|
233
63
|
returnDisplay: 'Command cancelled by user.',
|
|
@@ -238,198 +68,251 @@ Process Group PGID: Process group started or \`(none)\``, Icon.Terminal, {
|
|
|
238
68
|
.randomBytes(6)
|
|
239
69
|
.toString('hex')}.tmp`;
|
|
240
70
|
const tempFilePath = path.join(os.tmpdir(), tempFileName);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
command
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
detached: true, // ensure subprocess starts its own process group (esp. in Linux)
|
|
261
|
-
cwd: path.resolve(this.config.getTargetDir(), params.directory || ''),
|
|
262
|
-
});
|
|
263
|
-
let exited = false;
|
|
264
|
-
let stdout = '';
|
|
265
|
-
let output = '';
|
|
266
|
-
let lastUpdateTime = Date.now();
|
|
267
|
-
const appendOutput = (str) => {
|
|
268
|
-
output += str;
|
|
269
|
-
if (updateOutput &&
|
|
270
|
-
Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
|
|
271
|
-
updateOutput(output);
|
|
272
|
-
lastUpdateTime = Date.now();
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
shell.stdout.on('data', (data) => {
|
|
276
|
-
// continue to consume post-exit for background processes
|
|
277
|
-
// removing listeners can overflow OS buffer and block subprocesses
|
|
278
|
-
// destroying (e.g. shell.stdout.destroy()) can terminate subprocesses via SIGPIPE
|
|
279
|
-
if (!exited) {
|
|
280
|
-
const str = stripAnsi(data.toString());
|
|
281
|
-
stdout += str;
|
|
282
|
-
appendOutput(str);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
let stderr = '';
|
|
286
|
-
shell.stderr.on('data', (data) => {
|
|
287
|
-
if (!exited) {
|
|
288
|
-
const str = stripAnsi(data.toString());
|
|
289
|
-
stderr += str;
|
|
290
|
-
appendOutput(str);
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
let error = null;
|
|
294
|
-
shell.on('error', (err) => {
|
|
295
|
-
error = err;
|
|
296
|
-
// remove wrapper from user's command in error message
|
|
297
|
-
error.message = error.message.replace(command, params.command);
|
|
298
|
-
});
|
|
299
|
-
let code = null;
|
|
300
|
-
let processSignal = null;
|
|
301
|
-
const exitHandler = (_code, _signal) => {
|
|
302
|
-
exited = true;
|
|
303
|
-
code = _code;
|
|
304
|
-
processSignal = _signal;
|
|
305
|
-
};
|
|
306
|
-
shell.on('exit', exitHandler);
|
|
307
|
-
const abortHandler = async () => {
|
|
308
|
-
if (shell.pid && !exited) {
|
|
309
|
-
if (os.platform() === 'win32') {
|
|
310
|
-
// For Windows, use taskkill to kill the process tree
|
|
311
|
-
spawn('taskkill', ['/pid', shell.pid.toString(), '/f', '/t']);
|
|
71
|
+
try {
|
|
72
|
+
// pgrep is not available on Windows, so we can't get background PIDs
|
|
73
|
+
const commandToExecute = isWindows
|
|
74
|
+
? strippedCommand
|
|
75
|
+
: (() => {
|
|
76
|
+
// wrap command to append subprocess pids (via pgrep) to temporary file
|
|
77
|
+
let command = strippedCommand.trim();
|
|
78
|
+
if (!command.endsWith('&'))
|
|
79
|
+
command += ';';
|
|
80
|
+
return `{ ${command} }; __code=$?; pgrep -g 0 >${tempFilePath} 2>&1; exit $__code;`;
|
|
81
|
+
})();
|
|
82
|
+
const cwd = path.resolve(this.config.getTargetDir(), this.params.directory || '');
|
|
83
|
+
let cumulativeStdout = '';
|
|
84
|
+
let cumulativeStderr = '';
|
|
85
|
+
let lastUpdateTime = Date.now();
|
|
86
|
+
let isBinaryStream = false;
|
|
87
|
+
const { result: resultPromise } = ShellExecutionService.execute(commandToExecute, cwd, (event) => {
|
|
88
|
+
if (!updateOutput) {
|
|
89
|
+
return;
|
|
312
90
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (
|
|
320
|
-
|
|
91
|
+
let currentDisplayOutput = '';
|
|
92
|
+
let shouldUpdate = false;
|
|
93
|
+
switch (event.type) {
|
|
94
|
+
case 'data':
|
|
95
|
+
if (isBinaryStream)
|
|
96
|
+
break; // Don't process text if we are in binary mode
|
|
97
|
+
if (event.stream === 'stdout') {
|
|
98
|
+
cumulativeStdout += event.chunk;
|
|
321
99
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
100
|
+
else {
|
|
101
|
+
cumulativeStderr += event.chunk;
|
|
102
|
+
}
|
|
103
|
+
currentDisplayOutput =
|
|
104
|
+
cumulativeStdout +
|
|
105
|
+
(cumulativeStderr ? `\n${cumulativeStderr}` : '');
|
|
106
|
+
if (Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
|
|
107
|
+
shouldUpdate = true;
|
|
329
108
|
}
|
|
330
|
-
|
|
331
|
-
|
|
109
|
+
break;
|
|
110
|
+
case 'binary_detected':
|
|
111
|
+
isBinaryStream = true;
|
|
112
|
+
currentDisplayOutput =
|
|
113
|
+
'[Binary output detected. Halting stream...]';
|
|
114
|
+
shouldUpdate = true;
|
|
115
|
+
break;
|
|
116
|
+
case 'binary_progress':
|
|
117
|
+
isBinaryStream = true;
|
|
118
|
+
currentDisplayOutput = `[Receiving binary output... ${formatMemoryUsage(event.bytesReceived)} received]`;
|
|
119
|
+
if (Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
|
|
120
|
+
shouldUpdate = true;
|
|
332
121
|
}
|
|
122
|
+
break;
|
|
123
|
+
default: {
|
|
124
|
+
throw new Error('An unhandled ShellOutputEvent was found.');
|
|
333
125
|
}
|
|
334
126
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
127
|
+
if (shouldUpdate) {
|
|
128
|
+
updateOutput(currentDisplayOutput);
|
|
129
|
+
lastUpdateTime = Date.now();
|
|
130
|
+
}
|
|
131
|
+
}, signal);
|
|
132
|
+
const result = await resultPromise;
|
|
133
|
+
const backgroundPIDs = [];
|
|
134
|
+
if (os.platform() !== 'win32') {
|
|
135
|
+
if (fs.existsSync(tempFilePath)) {
|
|
136
|
+
const pgrepLines = fs
|
|
137
|
+
.readFileSync(tempFilePath, 'utf8')
|
|
138
|
+
.split('\n')
|
|
139
|
+
.filter(Boolean);
|
|
140
|
+
for (const line of pgrepLines) {
|
|
141
|
+
if (!/^\d+$/.test(line)) {
|
|
142
|
+
console.error(`pgrep: ${line}`);
|
|
143
|
+
}
|
|
144
|
+
const pid = Number(line);
|
|
145
|
+
if (pid !== result.pid) {
|
|
146
|
+
backgroundPIDs.push(pid);
|
|
147
|
+
}
|
|
356
148
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (
|
|
360
|
-
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
if (!signal.aborted) {
|
|
152
|
+
console.error('missing pgrep output');
|
|
361
153
|
}
|
|
362
154
|
}
|
|
363
|
-
fs.unlinkSync(tempFilePath);
|
|
364
155
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
156
|
+
let llmContent = '';
|
|
157
|
+
if (result.aborted) {
|
|
158
|
+
llmContent = 'Command was cancelled by user before it could complete.';
|
|
159
|
+
if (result.output.trim()) {
|
|
160
|
+
llmContent += ` Below is the output (on stdout and stderr) before it was cancelled:\n${result.output}`;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
llmContent += ' There was no output before it was cancelled.';
|
|
368
164
|
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
let llmContent = '';
|
|
372
|
-
if (abortSignal.aborted) {
|
|
373
|
-
llmContent = 'Command was cancelled by user before it could complete.';
|
|
374
|
-
if (output.trim()) {
|
|
375
|
-
llmContent += ` Below is the output (on stdout and stderr) before it was cancelled:\n${output}`;
|
|
376
165
|
}
|
|
377
166
|
else {
|
|
378
|
-
|
|
167
|
+
// Create a formatted error string for display, replacing the wrapper command
|
|
168
|
+
// with the user-facing command.
|
|
169
|
+
const finalError = result.error
|
|
170
|
+
? result.error.message.replace(commandToExecute, this.params.command)
|
|
171
|
+
: '(none)';
|
|
172
|
+
llmContent = [
|
|
173
|
+
`Command: ${this.params.command}`,
|
|
174
|
+
`Directory: ${this.params.directory || '(root)'}`,
|
|
175
|
+
`Stdout: ${result.stdout || '(empty)'}`,
|
|
176
|
+
`Stderr: ${result.stderr || '(empty)'}`,
|
|
177
|
+
`Error: ${finalError}`, // Use the cleaned error string.
|
|
178
|
+
`Exit Code: ${result.exitCode ?? '(none)'}`,
|
|
179
|
+
`Signal: ${result.signal ?? '(none)'}`,
|
|
180
|
+
`Background PIDs: ${backgroundPIDs.length ? backgroundPIDs.join(', ') : '(none)'}`,
|
|
181
|
+
`Process Group PGID: ${result.pid ?? '(none)'}`,
|
|
182
|
+
].join('\n');
|
|
379
183
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
`Command: ${params.command}`,
|
|
384
|
-
`Directory: ${params.directory || '(root)'}`,
|
|
385
|
-
`Stdout: ${stdout || '(empty)'}`,
|
|
386
|
-
`Stderr: ${stderr || '(empty)'}`,
|
|
387
|
-
`Error: ${error ?? '(none)'}`,
|
|
388
|
-
`Exit Code: ${code ?? '(none)'}`,
|
|
389
|
-
`Signal: ${processSignal ?? '(none)'}`,
|
|
390
|
-
`Background PIDs: ${backgroundPIDs.length ? backgroundPIDs.join(', ') : '(none)'}`,
|
|
391
|
-
`Process Group PGID: ${shell.pid ?? '(none)'}`,
|
|
392
|
-
].join('\n');
|
|
393
|
-
}
|
|
394
|
-
let returnDisplayMessage = '';
|
|
395
|
-
if (this.config.getDebugMode()) {
|
|
396
|
-
returnDisplayMessage = llmContent;
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
if (output.trim()) {
|
|
400
|
-
returnDisplayMessage = output;
|
|
184
|
+
let returnDisplayMessage = '';
|
|
185
|
+
if (this.config.getDebugMode()) {
|
|
186
|
+
returnDisplayMessage = llmContent;
|
|
401
187
|
}
|
|
402
188
|
else {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
returnDisplayMessage = 'Command cancelled by user.';
|
|
406
|
-
}
|
|
407
|
-
else if (processSignal) {
|
|
408
|
-
returnDisplayMessage = `Command terminated by signal: ${processSignal}`;
|
|
189
|
+
if (result.output.trim()) {
|
|
190
|
+
returnDisplayMessage = result.output;
|
|
409
191
|
}
|
|
410
|
-
else
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
192
|
+
else {
|
|
193
|
+
if (result.aborted) {
|
|
194
|
+
returnDisplayMessage = 'Command cancelled by user.';
|
|
195
|
+
}
|
|
196
|
+
else if (result.signal) {
|
|
197
|
+
returnDisplayMessage = `Command terminated by signal: ${result.signal}`;
|
|
198
|
+
}
|
|
199
|
+
else if (result.error) {
|
|
200
|
+
returnDisplayMessage = `Command failed: ${getErrorMessage(result.error)}`;
|
|
201
|
+
}
|
|
202
|
+
else if (result.exitCode !== null && result.exitCode !== 0) {
|
|
203
|
+
returnDisplayMessage = `Command exited with code: ${result.exitCode}`;
|
|
204
|
+
}
|
|
205
|
+
// If output is empty and command succeeded (code 0, no error/signal/abort),
|
|
206
|
+
// returnDisplayMessage will remain empty, which is fine.
|
|
416
207
|
}
|
|
417
|
-
// If output is empty and command succeeded (code 0, no error/signal/abort),
|
|
418
|
-
// returnDisplayMessage will remain empty, which is fine.
|
|
419
208
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
209
|
+
const summarizeConfig = this.config.getSummarizeToolOutputConfig();
|
|
210
|
+
if (summarizeConfig && summarizeConfig[ShellTool.Name]) {
|
|
211
|
+
const summary = await summarizeToolOutput(llmContent, this.config.getGeminiClient(), signal, summarizeConfig[ShellTool.Name].tokenBudget);
|
|
212
|
+
return {
|
|
213
|
+
llmContent: summary,
|
|
214
|
+
returnDisplay: returnDisplayMessage,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
424
217
|
return {
|
|
425
|
-
llmContent
|
|
218
|
+
llmContent,
|
|
426
219
|
returnDisplay: returnDisplayMessage,
|
|
427
220
|
};
|
|
428
221
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
222
|
+
finally {
|
|
223
|
+
if (fs.existsSync(tempFilePath)) {
|
|
224
|
+
fs.unlinkSync(tempFilePath);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function getShellToolDescription() {
|
|
230
|
+
const returnedInfo = `
|
|
231
|
+
|
|
232
|
+
The following information is returned:
|
|
233
|
+
|
|
234
|
+
Command: Executed command.
|
|
235
|
+
Directory: Directory (relative to project root) where command was executed, or \`(root)\`.
|
|
236
|
+
Stdout: Output on stdout stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
|
|
237
|
+
Stderr: Output on stderr stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
|
|
238
|
+
Error: Error or \`(none)\` if no error was reported for the subprocess.
|
|
239
|
+
Exit Code: Exit code or \`(none)\` if terminated by signal.
|
|
240
|
+
Signal: Signal number or \`(none)\` if no signal was received.
|
|
241
|
+
Background PIDs: List of background processes started or \`(none)\`.
|
|
242
|
+
Process Group PGID: Process group started or \`(none)\``;
|
|
243
|
+
if (os.platform() === 'win32') {
|
|
244
|
+
return `This tool executes a given shell command as \`cmd.exe /c <command>\`. Command can start background processes using \`start /b\`.${returnedInfo}`;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
return `This tool executes a given shell command as \`bash -c <command>\`. Command can start background processes using \`&\`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as \`kill -- -PGID\` or signaled as \`kill -s SIGNAL -- -PGID\`.${returnedInfo}`;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function getCommandDescription() {
|
|
251
|
+
if (os.platform() === 'win32') {
|
|
252
|
+
return 'Exact command to execute as `cmd.exe /c <command>`';
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
return 'Exact bash command to execute as `bash -c <command>`';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
export class ShellTool extends BaseDeclarativeTool {
|
|
259
|
+
config;
|
|
260
|
+
static Name = 'run_shell_command';
|
|
261
|
+
allowlist = new Set();
|
|
262
|
+
constructor(config) {
|
|
263
|
+
super(ShellTool.Name, 'Shell', getShellToolDescription(), Kind.Execute, {
|
|
264
|
+
type: 'object',
|
|
265
|
+
properties: {
|
|
266
|
+
command: {
|
|
267
|
+
type: 'string',
|
|
268
|
+
description: getCommandDescription(),
|
|
269
|
+
},
|
|
270
|
+
description: {
|
|
271
|
+
type: 'string',
|
|
272
|
+
description: 'Brief description of the command for the user. Be specific and concise. Ideally a single sentence. Can be up to 3 sentences for clarity. No line breaks.',
|
|
273
|
+
},
|
|
274
|
+
directory: {
|
|
275
|
+
type: 'string',
|
|
276
|
+
description: '(OPTIONAL) Directory to run the command in, if not the project root directory. Must be relative to the project root directory and must already exist.',
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
required: ['command'],
|
|
280
|
+
}, false, // output is not markdown
|
|
281
|
+
true);
|
|
282
|
+
this.config = config;
|
|
283
|
+
}
|
|
284
|
+
validateToolParamValues(params) {
|
|
285
|
+
const commandCheck = isCommandAllowed(params.command, this.config);
|
|
286
|
+
if (!commandCheck.allowed) {
|
|
287
|
+
if (!commandCheck.reason) {
|
|
288
|
+
console.error('Unexpected: isCommandAllowed returned false without a reason');
|
|
289
|
+
return `Command is not allowed: ${params.command}`;
|
|
290
|
+
}
|
|
291
|
+
return commandCheck.reason;
|
|
292
|
+
}
|
|
293
|
+
if (!params.command.trim()) {
|
|
294
|
+
return 'Command cannot be empty.';
|
|
295
|
+
}
|
|
296
|
+
if (getCommandRoots(params.command).length === 0) {
|
|
297
|
+
return 'Could not identify command root to obtain permission from user.';
|
|
298
|
+
}
|
|
299
|
+
if (params.directory) {
|
|
300
|
+
if (path.isAbsolute(params.directory)) {
|
|
301
|
+
return 'Directory cannot be absolute. Please refer to workspace directories by their name.';
|
|
302
|
+
}
|
|
303
|
+
const workspaceDirs = this.config.getWorkspaceContext().getDirectories();
|
|
304
|
+
const matchingDirs = workspaceDirs.filter((dir) => path.basename(dir) === params.directory);
|
|
305
|
+
if (matchingDirs.length === 0) {
|
|
306
|
+
return `Directory '${params.directory}' is not a registered workspace directory.`;
|
|
307
|
+
}
|
|
308
|
+
if (matchingDirs.length > 1) {
|
|
309
|
+
return `Directory name '${params.directory}' is ambiguous as it matches multiple workspace directories.`;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
createInvocation(params) {
|
|
315
|
+
return new ShellToolInvocation(this.config, params, this.allowlist);
|
|
433
316
|
}
|
|
434
317
|
}
|
|
435
318
|
//# sourceMappingURL=shell.js.map
|