@google/gemini-cli-core 0.39.0-preview.2 → 0.40.0-preview.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/docs/changelogs/index.md +21 -0
- package/dist/docs/changelogs/latest.md +253 -407
- package/dist/docs/changelogs/preview.md +236 -247
- package/dist/docs/cli/auto-memory.md +143 -0
- package/dist/docs/cli/enterprise.md +1 -1
- package/dist/docs/cli/plan-mode.md +3 -1
- package/dist/docs/cli/settings.md +29 -25
- package/dist/docs/cli/system-prompt.md +6 -6
- package/dist/docs/cli/telemetry.md +18 -11
- package/dist/docs/cli/tutorials/memory-management.md +2 -0
- package/dist/docs/get-started/{authentication.md → authentication.mdx} +139 -93
- package/dist/docs/get-started/index.md +3 -2
- package/dist/docs/get-started/installation.mdx +201 -0
- package/dist/docs/index.md +2 -2
- package/dist/docs/reference/configuration.md +88 -12
- package/dist/docs/reference/policy-engine.md +18 -12
- package/dist/docs/reference/tools.md +22 -0
- package/dist/docs/sidebar.json +13 -1
- package/dist/docs/tools/mcp-resources.md +44 -0
- package/dist/docs/tools/mcp-server.md +2 -1
- package/dist/docs/tools/tracker.md +61 -0
- package/dist/src/agents/agent-tool.js +1 -0
- package/dist/src/agents/agent-tool.js.map +1 -1
- package/dist/src/agents/agentLoader.d.ts +4 -4
- package/dist/src/agents/generalist-agent.js +3 -2
- package/dist/src/agents/generalist-agent.js.map +1 -1
- package/dist/src/agents/local-executor.js +4 -1
- package/dist/src/agents/local-executor.js.map +1 -1
- package/dist/src/agents/registry.js +0 -8
- package/dist/src/agents/registry.js.map +1 -1
- package/dist/src/agents/skill-extraction-agent.d.ts +3 -2
- package/dist/src/agents/skill-extraction-agent.js +72 -67
- package/dist/src/agents/skill-extraction-agent.js.map +1 -1
- package/dist/src/agents/skill-extraction-agent.test.js +54 -0
- package/dist/src/agents/skill-extraction-agent.test.js.map +1 -0
- package/dist/src/config/config.d.ts +21 -6
- package/dist/src/config/config.js +103 -19
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +262 -6
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/constants.d.ts +1 -0
- package/dist/src/config/constants.js +2 -0
- package/dist/src/config/constants.js.map +1 -1
- package/dist/src/config/memory.js +1 -1
- package/dist/src/config/memory.js.map +1 -1
- package/dist/src/config/path-validation.test.js +15 -6
- package/dist/src/config/path-validation.test.js.map +1 -1
- package/dist/src/config/projectRegistry.js +113 -32
- package/dist/src/config/projectRegistry.js.map +1 -1
- package/dist/src/config/projectRegistry.test.js +51 -0
- package/dist/src/config/projectRegistry.test.js.map +1 -1
- package/dist/src/config/storage.d.ts +3 -1
- package/dist/src/config/storage.js +6 -0
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/config/storage.test.js +12 -0
- package/dist/src/config/storage.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +8 -1
- package/dist/src/core/contentGenerator.js +46 -4
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +174 -8
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +1 -0
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/geminiChat_network_retry.test.js +42 -0
- package/dist/src/core/geminiChat_network_retry.test.js.map +1 -1
- package/dist/src/core/localLiteRtLmClient.js +2 -0
- package/dist/src/core/localLiteRtLmClient.js.map +1 -1
- package/dist/src/core/localLiteRtLmClient.test.js +7 -0
- package/dist/src/core/localLiteRtLmClient.test.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.js +3 -0
- package/dist/src/core/loggingContentGenerator.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.test.js +1 -0
- package/dist/src/core/loggingContentGenerator.test.js.map +1 -1
- package/dist/src/core/prompts.d.ts +1 -1
- package/dist/src/core/prompts.js +2 -2
- package/dist/src/core/prompts.js.map +1 -1
- package/dist/src/core/prompts.test.js +2 -2
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/ide/ide-client.js +3 -4
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/policy/policies/read-only.toml +4 -1
- package/dist/src/policy/policy-engine.js +4 -0
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/policy/policy-engine.test.js +25 -0
- package/dist/src/policy/policy-engine.test.js.map +1 -1
- package/dist/src/policy/toml-loader.test.js +5 -0
- package/dist/src/policy/toml-loader.test.js.map +1 -1
- package/dist/src/prompts/promptProvider.d.ts +1 -1
- package/dist/src/prompts/promptProvider.js +15 -7
- package/dist/src/prompts/promptProvider.js.map +1 -1
- package/dist/src/prompts/promptProvider.test.js +31 -1
- package/dist/src/prompts/promptProvider.test.js.map +1 -1
- package/dist/src/prompts/snippets-memory-v2.test.js +94 -0
- package/dist/src/prompts/snippets-memory-v2.test.js.map +1 -0
- package/dist/src/prompts/snippets.d.ts +19 -1
- package/dist/src/prompts/snippets.js +24 -3
- package/dist/src/prompts/snippets.js.map +1 -1
- package/dist/src/prompts/snippets.legacy.d.ts +6 -1
- package/dist/src/prompts/snippets.legacy.js +10 -3
- package/dist/src/prompts/snippets.legacy.js.map +1 -1
- package/dist/src/sandbox/linux/LinuxSandboxManager.js +16 -2
- package/dist/src/sandbox/linux/LinuxSandboxManager.js.map +1 -1
- package/dist/src/sandbox/linux/bwrapArgsBuilder.js +64 -36
- package/dist/src/sandbox/linux/bwrapArgsBuilder.js.map +1 -1
- package/dist/src/sandbox/linux/bwrapArgsBuilder.test.js +3 -3
- package/dist/src/sandbox/linux/bwrapArgsBuilder.test.js.map +1 -1
- package/dist/src/sandbox/macos/MacOsSandboxManager.js +13 -1
- package/dist/src/sandbox/macos/MacOsSandboxManager.js.map +1 -1
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.js +61 -42
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.js.map +1 -1
- package/dist/src/sandbox/windows/WindowsSandboxManager.js +12 -1
- package/dist/src/sandbox/windows/WindowsSandboxManager.js.map +1 -1
- package/dist/src/scheduler/policy.js +1 -2
- package/dist/src/scheduler/policy.js.map +1 -1
- package/dist/src/scheduler/policy.test.js +35 -2
- package/dist/src/scheduler/policy.test.js.map +1 -1
- package/dist/src/scheduler/scheduler.js +1 -0
- package/dist/src/scheduler/scheduler.js.map +1 -1
- package/dist/src/scheduler/scheduler.test.js +2 -0
- package/dist/src/scheduler/scheduler.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_hooks.test.js +1 -0
- package/dist/src/scheduler/scheduler_hooks.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_parallel.test.js +1 -0
- package/dist/src/scheduler/scheduler_parallel.test.js.map +1 -1
- package/dist/src/scheduler/tool-executor.js +1 -0
- package/dist/src/scheduler/tool-executor.js.map +1 -1
- package/dist/src/services/chatRecordingService.d.ts +1 -0
- package/dist/src/services/chatRecordingService.js +48 -19
- package/dist/src/services/chatRecordingService.js.map +1 -1
- package/dist/src/services/memoryService.d.ts +15 -1
- package/dist/src/services/memoryService.js +276 -57
- package/dist/src/services/memoryService.js.map +1 -1
- package/dist/src/services/memoryService.test.js +296 -2
- package/dist/src/services/memoryService.test.js.map +1 -1
- package/dist/src/services/sandboxManager.integration.test.js +204 -0
- package/dist/src/services/sandboxManager.integration.test.js.map +1 -1
- package/dist/src/services/sandboxManager.js +16 -0
- package/dist/src/services/sandboxManager.js.map +1 -1
- package/dist/src/services/sessionSummaryUtils.d.ts +1 -1
- package/dist/src/services/sessionSummaryUtils.js +111 -38
- package/dist/src/services/sessionSummaryUtils.js.map +1 -1
- package/dist/src/services/sessionSummaryUtils.test.js +204 -51
- package/dist/src/services/sessionSummaryUtils.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.js +7 -1
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/telemetry/config.js +3 -0
- package/dist/src/telemetry/config.js.map +1 -1
- package/dist/src/telemetry/conseca-logger.test.js +1 -0
- package/dist/src/telemetry/conseca-logger.test.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +72 -4
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/memory-monitor.d.ts +1 -0
- package/dist/src/telemetry/memory-monitor.js +8 -1
- package/dist/src/telemetry/memory-monitor.js.map +1 -1
- package/dist/src/telemetry/memory-monitor.test.js +6 -1
- package/dist/src/telemetry/memory-monitor.test.js.map +1 -1
- package/dist/src/telemetry/trace.d.ts +1 -0
- package/dist/src/telemetry/trace.js +33 -13
- package/dist/src/telemetry/trace.js.map +1 -1
- package/dist/src/telemetry/trace.test.js +50 -10
- package/dist/src/telemetry/trace.test.js.map +1 -1
- package/dist/src/telemetry/types.js +11 -4
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/tools/definitions/base-declarations.d.ts +2 -0
- package/dist/src/tools/definitions/base-declarations.js +3 -0
- package/dist/src/tools/definitions/base-declarations.js.map +1 -1
- package/dist/src/tools/definitions/coreTools.d.ts +3 -1
- package/dist/src/tools/definitions/coreTools.js +13 -1
- package/dist/src/tools/definitions/coreTools.js.map +1 -1
- package/dist/src/tools/definitions/model-family-sets/default-legacy.js +29 -1
- package/dist/src/tools/definitions/model-family-sets/default-legacy.js.map +1 -1
- package/dist/src/tools/definitions/model-family-sets/gemini-3.js +29 -1
- package/dist/src/tools/definitions/model-family-sets/gemini-3.js.map +1 -1
- package/dist/src/tools/definitions/types.d.ts +2 -0
- package/dist/src/tools/get-internal-docs.js +5 -2
- package/dist/src/tools/get-internal-docs.js.map +1 -1
- package/dist/src/tools/list-mcp-resources.d.ts +24 -0
- package/dist/src/tools/list-mcp-resources.js +74 -0
- package/dist/src/tools/list-mcp-resources.js.map +1 -0
- package/dist/src/tools/list-mcp-resources.test.d.ts +6 -0
- package/dist/src/tools/list-mcp-resources.test.js +79 -0
- package/dist/src/tools/list-mcp-resources.test.js.map +1 -0
- package/dist/src/tools/mcp-client-manager.d.ts +3 -1
- package/dist/src/tools/mcp-client-manager.js +24 -1
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.test.js +43 -0
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +2 -1
- package/dist/src/tools/memoryTool.js +42 -13
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/memoryTool.test.js +23 -3
- package/dist/src/tools/memoryTool.test.js.map +1 -1
- package/dist/src/tools/read-mcp-resource.d.ts +25 -0
- package/dist/src/tools/read-mcp-resource.js +120 -0
- package/dist/src/tools/read-mcp-resource.js.map +1 -0
- package/dist/src/tools/read-mcp-resource.test.d.ts +6 -0
- package/dist/src/tools/read-mcp-resource.test.js +110 -0
- package/dist/src/tools/read-mcp-resource.test.js.map +1 -0
- package/dist/src/tools/ripGrep.d.ts +3 -2
- package/dist/src/tools/ripGrep.js +25 -54
- package/dist/src/tools/ripGrep.js.map +1 -1
- package/dist/src/tools/ripGrep.test.js +73 -131
- package/dist/src/tools/ripGrep.test.js.map +1 -1
- package/dist/src/tools/shell.js +38 -12
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +410 -25
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +1 -0
- package/dist/src/tools/tool-error.js +1 -0
- package/dist/src/tools/tool-error.js.map +1 -1
- package/dist/src/tools/tool-names.d.ts +4 -4
- package/dist/src/tools/tool-names.js +6 -2
- package/dist/src/tools/tool-names.js.map +1 -1
- package/dist/src/tools/tool-registry.js +8 -1
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/utils/filesearch/fileSearch.d.ts +2 -0
- package/dist/src/utils/filesearch/fileSearch.js +97 -6
- package/dist/src/utils/filesearch/fileSearch.js.map +1 -1
- package/dist/src/utils/filesearch/fileSearch.test.js +54 -0
- package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -1
- package/dist/src/utils/filesearch/fileWatcher.d.ts +25 -0
- package/dist/src/utils/filesearch/fileWatcher.js +86 -0
- package/dist/src/utils/filesearch/fileWatcher.js.map +1 -0
- package/dist/src/utils/filesearch/fileWatcher.test.d.ts +6 -0
- package/dist/src/utils/filesearch/fileWatcher.test.js +142 -0
- package/dist/src/utils/filesearch/fileWatcher.test.js.map +1 -0
- package/dist/src/utils/gitIgnoreParser.js +1 -1
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/ignoreFileParser.js +1 -1
- package/dist/src/utils/ignoreFileParser.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.js +15 -5
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/retry.js +18 -6
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js +30 -0
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/shell-utils.d.ts +1 -0
- package/dist/src/utils/shell-utils.js +106 -0
- package/dist/src/utils/shell-utils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -3
- package/vendor/ripgrep/rg-darwin-arm64 +0 -0
- package/vendor/ripgrep/rg-darwin-x64 +0 -0
- package/vendor/ripgrep/rg-linux-arm64 +0 -0
- package/vendor/ripgrep/rg-linux-x64 +0 -0
- package/vendor/ripgrep/rg-win32-x64.exe +0 -0
- package/dist/docs/get-started/installation.md +0 -181
- package/dist/google-gemini-cli-core-0.39.0-preview.1.tgz +0 -0
- package/dist/src/agents/memory-manager-agent.d.ts +0 -25
- package/dist/src/agents/memory-manager-agent.js +0 -138
- package/dist/src/agents/memory-manager-agent.js.map +0 -1
- package/dist/src/agents/memory-manager-agent.test.js +0 -123
- package/dist/src/agents/memory-manager-agent.test.js.map +0 -1
- package/dist/src/prompts/snippets-memory-manager.test.js +0 -31
- package/dist/src/prompts/snippets-memory-manager.test.js.map +0 -1
- /package/dist/src/agents/{memory-manager-agent.test.d.ts → skill-extraction-agent.test.d.ts} +0 -0
- /package/dist/src/prompts/{snippets-memory-manager.test.d.ts → snippets-memory-v2.test.d.ts} +0 -0
|
@@ -61,6 +61,7 @@ describe('ShellTool', () => {
|
|
|
61
61
|
let mockShellOutputCallback;
|
|
62
62
|
let resolveExecutionPromise;
|
|
63
63
|
let tempRootDir;
|
|
64
|
+
let extractedTmpFile;
|
|
64
65
|
beforeEach(() => {
|
|
65
66
|
vi.clearAllMocks();
|
|
66
67
|
tempRootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'shell-test-'));
|
|
@@ -146,9 +147,14 @@ describe('ShellTool', () => {
|
|
|
146
147
|
vi.mocked(crypto.randomBytes).mockReturnValue(Buffer.from('abcdef', 'hex'));
|
|
147
148
|
process.env['ComSpec'] =
|
|
148
149
|
'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
|
|
150
|
+
extractedTmpFile = '';
|
|
149
151
|
// Capture the output callback to simulate streaming events from the service
|
|
150
|
-
mockShellExecutionService.mockImplementation((
|
|
152
|
+
mockShellExecutionService.mockImplementation((cmd, _cwd, callback) => {
|
|
151
153
|
mockShellOutputCallback = callback;
|
|
154
|
+
const match = cmd.match(/pgrep -g 0 >([^ ]+)/);
|
|
155
|
+
if (match) {
|
|
156
|
+
extractedTmpFile = match[1].replace(/['"]/g, '');
|
|
157
|
+
}
|
|
152
158
|
return {
|
|
153
159
|
pid: 12345,
|
|
154
160
|
result: new Promise((resolve) => {
|
|
@@ -227,38 +233,32 @@ describe('ShellTool', () => {
|
|
|
227
233
|
it('should wrap command on linux and parse pgrep output', async () => {
|
|
228
234
|
const invocation = shellTool.build({ command: 'my-command &' });
|
|
229
235
|
const promise = invocation.execute({ abortSignal: mockAbortSignal });
|
|
230
|
-
resolveShellExecution({ pid: 54321 });
|
|
231
236
|
// Simulate pgrep output file creation by the shell command
|
|
232
|
-
|
|
233
|
-
|
|
237
|
+
fs.writeFileSync(extractedTmpFile, `54321${os.EOL}54322${os.EOL}`);
|
|
238
|
+
resolveShellExecution({ pid: 54321 });
|
|
234
239
|
const result = await promise;
|
|
235
|
-
|
|
236
|
-
expect(mockShellExecutionService).toHaveBeenCalledWith(wrappedCommand, tempRootDir, expect.any(Function), expect.any(AbortSignal), false, expect.objectContaining({
|
|
240
|
+
expect(mockShellExecutionService).toHaveBeenCalledWith(expect.stringMatching(/pgrep -g 0 >.*gemini-shell-.*[/\\]pgrep\.tmp/), tempRootDir, expect.any(Function), expect.any(AbortSignal), false, expect.objectContaining({
|
|
237
241
|
pager: 'cat',
|
|
238
242
|
sanitizationConfig: {},
|
|
239
243
|
sandboxManager: expect.any(Object),
|
|
240
244
|
}));
|
|
241
245
|
expect(result.llmContent).toContain('Background PIDs: 54322');
|
|
242
246
|
// The file should be deleted by the tool
|
|
243
|
-
expect(fs.existsSync(
|
|
247
|
+
expect(fs.existsSync(extractedTmpFile)).toBe(false);
|
|
244
248
|
});
|
|
245
249
|
it('should add a space when command ends with a backslash to prevent escaping newline', async () => {
|
|
246
250
|
const invocation = shellTool.build({ command: 'ls\\' });
|
|
247
251
|
const promise = invocation.execute({ abortSignal: mockAbortSignal });
|
|
248
252
|
resolveShellExecution();
|
|
249
253
|
await promise;
|
|
250
|
-
|
|
251
|
-
const wrappedCommand = `(\nls\\ \n); __code=$?; pgrep -g 0 >${tmpFile} 2>&1; exit $__code;`;
|
|
252
|
-
expect(mockShellExecutionService).toHaveBeenCalledWith(wrappedCommand, tempRootDir, expect.any(Function), expect.any(AbortSignal), false, expect.any(Object));
|
|
254
|
+
expect(mockShellExecutionService).toHaveBeenCalledWith(expect.stringMatching(/pgrep -g 0 >.*gemini-shell-.*[/\\]pgrep\.tmp/), tempRootDir, expect.any(Function), expect.any(AbortSignal), false, expect.any(Object));
|
|
253
255
|
});
|
|
254
256
|
it('should handle trailing comments correctly by placing them on their own line', async () => {
|
|
255
257
|
const invocation = shellTool.build({ command: 'ls # comment' });
|
|
256
258
|
const promise = invocation.execute({ abortSignal: mockAbortSignal });
|
|
257
259
|
resolveShellExecution();
|
|
258
260
|
await promise;
|
|
259
|
-
|
|
260
|
-
const wrappedCommand = `(\nls # comment\n); __code=$?; pgrep -g 0 >${tmpFile} 2>&1; exit $__code;`;
|
|
261
|
-
expect(mockShellExecutionService).toHaveBeenCalledWith(wrappedCommand, tempRootDir, expect.any(Function), expect.any(AbortSignal), false, expect.any(Object));
|
|
261
|
+
expect(mockShellExecutionService).toHaveBeenCalledWith(expect.stringMatching(/pgrep -g 0 >.*gemini-shell-.*[/\\]pgrep\.tmp/), tempRootDir, expect.any(Function), expect.any(AbortSignal), false, expect.any(Object));
|
|
262
262
|
});
|
|
263
263
|
it('should use the provided absolute directory as cwd', async () => {
|
|
264
264
|
const subdir = path.join(tempRootDir, 'subdir');
|
|
@@ -269,9 +269,7 @@ describe('ShellTool', () => {
|
|
|
269
269
|
const promise = invocation.execute({ abortSignal: mockAbortSignal });
|
|
270
270
|
resolveShellExecution();
|
|
271
271
|
await promise;
|
|
272
|
-
|
|
273
|
-
const wrappedCommand = `(\n${'ls'}\n); __code=$?; pgrep -g 0 >${tmpFile} 2>&1; exit $__code;`;
|
|
274
|
-
expect(mockShellExecutionService).toHaveBeenCalledWith(wrappedCommand, subdir, expect.any(Function), expect.any(AbortSignal), false, expect.objectContaining({
|
|
272
|
+
expect(mockShellExecutionService).toHaveBeenCalledWith(expect.stringMatching(/pgrep -g 0 >.*gemini-shell-.*[/\\]pgrep\.tmp/), subdir, expect.any(Function), expect.any(AbortSignal), false, expect.objectContaining({
|
|
275
273
|
pager: 'cat',
|
|
276
274
|
sanitizationConfig: {},
|
|
277
275
|
sandboxManager: expect.any(Object),
|
|
@@ -285,9 +283,7 @@ describe('ShellTool', () => {
|
|
|
285
283
|
const promise = invocation.execute({ abortSignal: mockAbortSignal });
|
|
286
284
|
resolveShellExecution();
|
|
287
285
|
await promise;
|
|
288
|
-
|
|
289
|
-
const wrappedCommand = `(\n${'ls'}\n); __code=$?; pgrep -g 0 >${tmpFile} 2>&1; exit $__code;`;
|
|
290
|
-
expect(mockShellExecutionService).toHaveBeenCalledWith(wrappedCommand, path.join(tempRootDir, 'subdir'), expect.any(Function), expect.any(AbortSignal), false, expect.objectContaining({
|
|
286
|
+
expect(mockShellExecutionService).toHaveBeenCalledWith(expect.stringMatching(/pgrep -g 0 >.*gemini-shell-.*[/\\]pgrep\.tmp/), path.join(tempRootDir, 'subdir'), expect.any(Function), expect.any(AbortSignal), false, expect.objectContaining({
|
|
291
287
|
pager: 'cat',
|
|
292
288
|
sanitizationConfig: {},
|
|
293
289
|
sandboxManager: expect.any(Object),
|
|
@@ -328,6 +324,17 @@ describe('ShellTool', () => {
|
|
|
328
324
|
sandboxManager: expect.any(NoopSandboxManager),
|
|
329
325
|
}));
|
|
330
326
|
}, 20000);
|
|
327
|
+
it('should correctly wrap heredoc commands', async () => {
|
|
328
|
+
const command = `cat << 'EOF'
|
|
329
|
+
hello world
|
|
330
|
+
EOF`;
|
|
331
|
+
const invocation = shellTool.build({ command });
|
|
332
|
+
const promise = invocation.execute({ abortSignal: mockAbortSignal });
|
|
333
|
+
resolveShellExecution();
|
|
334
|
+
await promise;
|
|
335
|
+
expect(mockShellExecutionService).toHaveBeenCalledWith(expect.stringMatching(/pgrep -g 0 >.*gemini-shell-.*[/\\]pgrep\.tmp/), tempRootDir, expect.any(Function), expect.any(AbortSignal), false, expect.any(Object));
|
|
336
|
+
expect(mockShellExecutionService.mock.calls[0][0]).toMatch(/\nEOF\n\)\n/);
|
|
337
|
+
});
|
|
331
338
|
it('should format error messages correctly', async () => {
|
|
332
339
|
const error = new Error('wrapped command failed');
|
|
333
340
|
const invocation = shellTool.build({ command: 'user-command' });
|
|
@@ -403,16 +410,18 @@ describe('ShellTool', () => {
|
|
|
403
410
|
});
|
|
404
411
|
it('should clean up the temp file on synchronous execution error', async () => {
|
|
405
412
|
const error = new Error('sync spawn error');
|
|
406
|
-
mockShellExecutionService.mockImplementation(() => {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
413
|
+
mockShellExecutionService.mockImplementation((cmd) => {
|
|
414
|
+
const match = cmd.match(/pgrep -g 0 >([^ ]+)/);
|
|
415
|
+
if (match) {
|
|
416
|
+
extractedTmpFile = match[1].replace(/['"]/g, ''); // remove any quotes if present
|
|
417
|
+
// Create the temp file before throwing to simulate it being left behind
|
|
418
|
+
fs.writeFileSync(extractedTmpFile, '');
|
|
419
|
+
}
|
|
410
420
|
throw error;
|
|
411
421
|
});
|
|
412
422
|
const invocation = shellTool.build({ command: 'a-command' });
|
|
413
423
|
await expect(invocation.execute({ abortSignal: mockAbortSignal })).rejects.toThrow(error);
|
|
414
|
-
|
|
415
|
-
expect(fs.existsSync(tmpFile)).toBe(false);
|
|
424
|
+
expect(fs.existsSync(extractedTmpFile)).toBe(false);
|
|
416
425
|
});
|
|
417
426
|
it('should not log "missing pgrep output" when process is backgrounded', async () => {
|
|
418
427
|
vi.useFakeTimers();
|
|
@@ -881,5 +890,381 @@ describe('ShellTool', () => {
|
|
|
881
890
|
expect(schema.description).toMatchSnapshot();
|
|
882
891
|
});
|
|
883
892
|
});
|
|
893
|
+
describe('command injection detection', () => {
|
|
894
|
+
it('should block $() command substitution', async () => {
|
|
895
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
896
|
+
const invocation = tool.build({ command: 'echo $(whoami)' });
|
|
897
|
+
const result = await invocation.execute({
|
|
898
|
+
abortSignal: new AbortController().signal,
|
|
899
|
+
});
|
|
900
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
901
|
+
});
|
|
902
|
+
it('should block backtick command substitution', async () => {
|
|
903
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
904
|
+
const invocation = tool.build({ command: 'echo `whoami`' });
|
|
905
|
+
const result = await invocation.execute({
|
|
906
|
+
abortSignal: new AbortController().signal,
|
|
907
|
+
});
|
|
908
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
909
|
+
});
|
|
910
|
+
it('should allow normal commands without substitution', async () => {
|
|
911
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
912
|
+
pid: 12345,
|
|
913
|
+
result: Promise.resolve({
|
|
914
|
+
output: 'hello',
|
|
915
|
+
rawOutput: Buffer.from('hello'),
|
|
916
|
+
exitCode: 0,
|
|
917
|
+
signal: null,
|
|
918
|
+
error: null,
|
|
919
|
+
aborted: false,
|
|
920
|
+
pid: 12345,
|
|
921
|
+
executionMethod: 'child_process',
|
|
922
|
+
backgrounded: false,
|
|
923
|
+
}),
|
|
924
|
+
}));
|
|
925
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
926
|
+
const invocation = tool.build({ command: 'echo hello' });
|
|
927
|
+
const result = await invocation.execute({
|
|
928
|
+
abortSignal: new AbortController().signal,
|
|
929
|
+
});
|
|
930
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
931
|
+
});
|
|
932
|
+
it('should allow single quoted strings with special chars', async () => {
|
|
933
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
934
|
+
pid: 12345,
|
|
935
|
+
result: Promise.resolve({
|
|
936
|
+
output: '$(not substituted)',
|
|
937
|
+
rawOutput: Buffer.from('$(not substituted)'),
|
|
938
|
+
exitCode: 0,
|
|
939
|
+
signal: null,
|
|
940
|
+
error: null,
|
|
941
|
+
aborted: false,
|
|
942
|
+
pid: 12345,
|
|
943
|
+
executionMethod: 'child_process',
|
|
944
|
+
backgrounded: false,
|
|
945
|
+
}),
|
|
946
|
+
}));
|
|
947
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
948
|
+
const invocation = tool.build({
|
|
949
|
+
command: "echo '$(not substituted)'",
|
|
950
|
+
});
|
|
951
|
+
const result = await invocation.execute({
|
|
952
|
+
abortSignal: new AbortController().signal,
|
|
953
|
+
});
|
|
954
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
955
|
+
});
|
|
956
|
+
it('should allow escaped backtick outside double quotes', async () => {
|
|
957
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
958
|
+
pid: 12345,
|
|
959
|
+
result: Promise.resolve({
|
|
960
|
+
output: 'hello',
|
|
961
|
+
rawOutput: Buffer.from('hello'),
|
|
962
|
+
exitCode: 0,
|
|
963
|
+
signal: null,
|
|
964
|
+
error: null,
|
|
965
|
+
aborted: false,
|
|
966
|
+
pid: 12345,
|
|
967
|
+
executionMethod: 'child_process',
|
|
968
|
+
backgrounded: false,
|
|
969
|
+
}),
|
|
970
|
+
}));
|
|
971
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
972
|
+
const invocation = tool.build({ command: 'echo \\`hello\\`' });
|
|
973
|
+
const result = await invocation.execute({
|
|
974
|
+
abortSignal: new AbortController().signal,
|
|
975
|
+
});
|
|
976
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
977
|
+
});
|
|
978
|
+
it('should block $() inside double quotes', async () => {
|
|
979
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
980
|
+
const invocation = tool.build({ command: 'echo "$(whoami)"' });
|
|
981
|
+
const result = await invocation.execute({
|
|
982
|
+
abortSignal: new AbortController().signal,
|
|
983
|
+
});
|
|
984
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
985
|
+
});
|
|
986
|
+
it('should block >() process substitution', async () => {
|
|
987
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
988
|
+
const invocation = tool.build({ command: 'echo >(whoami)' });
|
|
989
|
+
const result = await invocation.execute({
|
|
990
|
+
abortSignal: new AbortController().signal,
|
|
991
|
+
});
|
|
992
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
993
|
+
});
|
|
994
|
+
it('should allow $() inside single quotes', async () => {
|
|
995
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
996
|
+
pid: 12345,
|
|
997
|
+
result: Promise.resolve({
|
|
998
|
+
output: '$(whoami)',
|
|
999
|
+
rawOutput: Buffer.from('$(whoami)'),
|
|
1000
|
+
exitCode: 0,
|
|
1001
|
+
signal: null,
|
|
1002
|
+
error: null,
|
|
1003
|
+
aborted: false,
|
|
1004
|
+
pid: 12345,
|
|
1005
|
+
executionMethod: 'child_process',
|
|
1006
|
+
backgrounded: false,
|
|
1007
|
+
}),
|
|
1008
|
+
}));
|
|
1009
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1010
|
+
const invocation = tool.build({
|
|
1011
|
+
command: "echo '$(whoami)'",
|
|
1012
|
+
});
|
|
1013
|
+
const result = await invocation.execute({
|
|
1014
|
+
abortSignal: new AbortController().signal,
|
|
1015
|
+
});
|
|
1016
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1017
|
+
});
|
|
1018
|
+
it('should block PowerShell @() array subexpression', async () => {
|
|
1019
|
+
mockPlatform.mockReturnValue('win32');
|
|
1020
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1021
|
+
const invocation = tool.build({ command: 'echo @(whoami)' });
|
|
1022
|
+
const result = await invocation.execute({
|
|
1023
|
+
abortSignal: new AbortController().signal,
|
|
1024
|
+
});
|
|
1025
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
1026
|
+
});
|
|
1027
|
+
it('should block PowerShell $() subexpression', async () => {
|
|
1028
|
+
mockPlatform.mockReturnValue('win32');
|
|
1029
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1030
|
+
const invocation = tool.build({ command: 'echo $(whoami)' });
|
|
1031
|
+
const result = await invocation.execute({
|
|
1032
|
+
abortSignal: new AbortController().signal,
|
|
1033
|
+
});
|
|
1034
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
1035
|
+
});
|
|
1036
|
+
it('should allow PowerShell single quoted strings', async () => {
|
|
1037
|
+
mockPlatform.mockReturnValue('win32');
|
|
1038
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1039
|
+
pid: 12345,
|
|
1040
|
+
result: Promise.resolve({
|
|
1041
|
+
output: '$(whoami)',
|
|
1042
|
+
rawOutput: Buffer.from('$(whoami)'),
|
|
1043
|
+
exitCode: 0,
|
|
1044
|
+
signal: null,
|
|
1045
|
+
error: null,
|
|
1046
|
+
aborted: false,
|
|
1047
|
+
pid: 12345,
|
|
1048
|
+
executionMethod: 'child_process',
|
|
1049
|
+
backgrounded: false,
|
|
1050
|
+
}),
|
|
1051
|
+
}));
|
|
1052
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1053
|
+
const invocation = tool.build({
|
|
1054
|
+
command: "echo '$(whoami)'",
|
|
1055
|
+
});
|
|
1056
|
+
const result = await invocation.execute({
|
|
1057
|
+
abortSignal: new AbortController().signal,
|
|
1058
|
+
});
|
|
1059
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1060
|
+
});
|
|
1061
|
+
it('should allow escaped substitution outside quotes', async () => {
|
|
1062
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1063
|
+
pid: 12345,
|
|
1064
|
+
result: Promise.resolve({
|
|
1065
|
+
output: '$(whoami)',
|
|
1066
|
+
rawOutput: Buffer.from('$(whoami)'),
|
|
1067
|
+
exitCode: 0,
|
|
1068
|
+
signal: null,
|
|
1069
|
+
error: null,
|
|
1070
|
+
aborted: false,
|
|
1071
|
+
pid: 12345,
|
|
1072
|
+
executionMethod: 'child_process',
|
|
1073
|
+
backgrounded: false,
|
|
1074
|
+
}),
|
|
1075
|
+
}));
|
|
1076
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1077
|
+
const invocation = tool.build({ command: 'echo \\$(whoami)' });
|
|
1078
|
+
const result = await invocation.execute({
|
|
1079
|
+
abortSignal: new AbortController().signal,
|
|
1080
|
+
});
|
|
1081
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1082
|
+
});
|
|
1083
|
+
it('should allow process substitution inside double quotes', async () => {
|
|
1084
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1085
|
+
pid: 12345,
|
|
1086
|
+
result: Promise.resolve({
|
|
1087
|
+
output: '<(whoami)',
|
|
1088
|
+
rawOutput: Buffer.from('<(whoami)'),
|
|
1089
|
+
exitCode: 0,
|
|
1090
|
+
signal: null,
|
|
1091
|
+
error: null,
|
|
1092
|
+
aborted: false,
|
|
1093
|
+
pid: 12345,
|
|
1094
|
+
executionMethod: 'child_process',
|
|
1095
|
+
backgrounded: false,
|
|
1096
|
+
}),
|
|
1097
|
+
}));
|
|
1098
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1099
|
+
const invocation = tool.build({ command: 'echo "<(whoami)"' });
|
|
1100
|
+
const result = await invocation.execute({
|
|
1101
|
+
abortSignal: new AbortController().signal,
|
|
1102
|
+
});
|
|
1103
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1104
|
+
});
|
|
1105
|
+
it('should block process substitution without quotes', async () => {
|
|
1106
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1107
|
+
const invocation = tool.build({ command: 'echo <(whoami)' });
|
|
1108
|
+
const result = await invocation.execute({
|
|
1109
|
+
abortSignal: new AbortController().signal,
|
|
1110
|
+
});
|
|
1111
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
1112
|
+
});
|
|
1113
|
+
it('should allow escaped $() outside double quotes', async () => {
|
|
1114
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1115
|
+
pid: 12345,
|
|
1116
|
+
result: Promise.resolve({
|
|
1117
|
+
output: '$(whoami)',
|
|
1118
|
+
rawOutput: Buffer.from('$(whoami)'),
|
|
1119
|
+
exitCode: 0,
|
|
1120
|
+
signal: null,
|
|
1121
|
+
error: null,
|
|
1122
|
+
aborted: false,
|
|
1123
|
+
pid: 12345,
|
|
1124
|
+
executionMethod: 'child_process',
|
|
1125
|
+
backgrounded: false,
|
|
1126
|
+
}),
|
|
1127
|
+
}));
|
|
1128
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1129
|
+
const invocation = tool.build({ command: 'echo \\$(whoami)' });
|
|
1130
|
+
const result = await invocation.execute({
|
|
1131
|
+
abortSignal: new AbortController().signal,
|
|
1132
|
+
});
|
|
1133
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1134
|
+
});
|
|
1135
|
+
it('should allow output process substitution inside double quotes', async () => {
|
|
1136
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1137
|
+
pid: 12345,
|
|
1138
|
+
result: Promise.resolve({
|
|
1139
|
+
output: '<(whoami)',
|
|
1140
|
+
rawOutput: Buffer.from('<(whoami)'),
|
|
1141
|
+
exitCode: 0,
|
|
1142
|
+
signal: null,
|
|
1143
|
+
error: null,
|
|
1144
|
+
aborted: false,
|
|
1145
|
+
pid: 12345,
|
|
1146
|
+
executionMethod: 'child_process',
|
|
1147
|
+
backgrounded: false,
|
|
1148
|
+
}),
|
|
1149
|
+
}));
|
|
1150
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1151
|
+
const invocation = tool.build({ command: 'echo "<(whoami)"' });
|
|
1152
|
+
const result = await invocation.execute({
|
|
1153
|
+
abortSignal: new AbortController().signal,
|
|
1154
|
+
});
|
|
1155
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1156
|
+
});
|
|
1157
|
+
it('should block <() process substitution without quotes', async () => {
|
|
1158
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1159
|
+
const invocation = tool.build({ command: 'echo <(whoami)' });
|
|
1160
|
+
const result = await invocation.execute({
|
|
1161
|
+
abortSignal: new AbortController().signal,
|
|
1162
|
+
});
|
|
1163
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
1164
|
+
});
|
|
1165
|
+
it('should block PowerShell bare () grouping operator', async () => {
|
|
1166
|
+
mockPlatform.mockReturnValue('win32');
|
|
1167
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1168
|
+
const invocation = tool.build({ command: 'echo (whoami)' });
|
|
1169
|
+
const result = await invocation.execute({
|
|
1170
|
+
abortSignal: new AbortController().signal,
|
|
1171
|
+
});
|
|
1172
|
+
expect(result.returnDisplay).toContain('Blocked');
|
|
1173
|
+
});
|
|
1174
|
+
it('should allow escaped $() inside double quotes', async () => {
|
|
1175
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1176
|
+
pid: 12345,
|
|
1177
|
+
result: Promise.resolve({
|
|
1178
|
+
output: '$(whoami)',
|
|
1179
|
+
rawOutput: Buffer.from('$(whoami)'),
|
|
1180
|
+
exitCode: 0,
|
|
1181
|
+
signal: null,
|
|
1182
|
+
error: null,
|
|
1183
|
+
aborted: false,
|
|
1184
|
+
pid: 12345,
|
|
1185
|
+
executionMethod: 'child_process',
|
|
1186
|
+
backgrounded: false,
|
|
1187
|
+
}),
|
|
1188
|
+
}));
|
|
1189
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1190
|
+
const invocation = tool.build({ command: 'echo "\\$(whoami)"' });
|
|
1191
|
+
const result = await invocation.execute({
|
|
1192
|
+
abortSignal: new AbortController().signal,
|
|
1193
|
+
});
|
|
1194
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1195
|
+
});
|
|
1196
|
+
it('should allow escaped substitution inside double quotes', async () => {
|
|
1197
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1198
|
+
pid: 12345,
|
|
1199
|
+
result: Promise.resolve({
|
|
1200
|
+
output: '$(whoami)',
|
|
1201
|
+
rawOutput: Buffer.from('$(whoami)'),
|
|
1202
|
+
exitCode: 0,
|
|
1203
|
+
signal: null,
|
|
1204
|
+
error: null,
|
|
1205
|
+
aborted: false,
|
|
1206
|
+
pid: 12345,
|
|
1207
|
+
executionMethod: 'child_process',
|
|
1208
|
+
backgrounded: false,
|
|
1209
|
+
}),
|
|
1210
|
+
}));
|
|
1211
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1212
|
+
const invocation = tool.build({ command: 'echo "\\$(whoami)"' });
|
|
1213
|
+
const result = await invocation.execute({
|
|
1214
|
+
abortSignal: new AbortController().signal,
|
|
1215
|
+
});
|
|
1216
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1217
|
+
});
|
|
1218
|
+
it('should allow PowerShell keyword with flag e.g. switch -regex ($x)', async () => {
|
|
1219
|
+
mockPlatform.mockReturnValue('win32');
|
|
1220
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1221
|
+
pid: 12345,
|
|
1222
|
+
result: Promise.resolve({
|
|
1223
|
+
output: 'result',
|
|
1224
|
+
rawOutput: Buffer.from('result'),
|
|
1225
|
+
exitCode: 0,
|
|
1226
|
+
signal: null,
|
|
1227
|
+
error: null,
|
|
1228
|
+
aborted: false,
|
|
1229
|
+
pid: 12345,
|
|
1230
|
+
executionMethod: 'child_process',
|
|
1231
|
+
backgrounded: false,
|
|
1232
|
+
}),
|
|
1233
|
+
}));
|
|
1234
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1235
|
+
const invocation = tool.build({
|
|
1236
|
+
command: 'switch -regex ($x) { "a" { 1 } }',
|
|
1237
|
+
});
|
|
1238
|
+
const result = await invocation.execute({
|
|
1239
|
+
abortSignal: new AbortController().signal,
|
|
1240
|
+
});
|
|
1241
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1242
|
+
});
|
|
1243
|
+
it('should allow PowerShell nested parentheses e.g. if ((condition))', async () => {
|
|
1244
|
+
mockPlatform.mockReturnValue('win32');
|
|
1245
|
+
mockShellExecutionService.mockImplementation((_cmd, _cwd, _callback) => ({
|
|
1246
|
+
pid: 12345,
|
|
1247
|
+
result: Promise.resolve({
|
|
1248
|
+
output: 'result',
|
|
1249
|
+
rawOutput: Buffer.from('result'),
|
|
1250
|
+
exitCode: 0,
|
|
1251
|
+
signal: null,
|
|
1252
|
+
error: null,
|
|
1253
|
+
aborted: false,
|
|
1254
|
+
pid: 12345,
|
|
1255
|
+
executionMethod: 'child_process',
|
|
1256
|
+
backgrounded: false,
|
|
1257
|
+
}),
|
|
1258
|
+
}));
|
|
1259
|
+
const tool = new ShellTool(mockConfig, createMockMessageBus());
|
|
1260
|
+
const invocation = tool.build({
|
|
1261
|
+
command: 'if ((condition)) { Write-Host ok }',
|
|
1262
|
+
});
|
|
1263
|
+
const result = await invocation.execute({
|
|
1264
|
+
abortSignal: new AbortController().signal,
|
|
1265
|
+
});
|
|
1266
|
+
expect(result.returnDisplay).not.toContain('Blocked');
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
884
1269
|
});
|
|
885
1270
|
//# sourceMappingURL=shell.test.js.map
|