@google/gemini-cli-core 0.34.0-preview.3 → 0.35.0-nightly.20260314.3038fdce2
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 +19 -0
- package/dist/docs/changelogs/latest.md +217 -191
- package/dist/docs/changelogs/preview.md +447 -184
- package/dist/docs/cli/model-routing.md +18 -1
- package/dist/docs/cli/model-steering.md +79 -0
- package/dist/docs/cli/plan-mode.md +99 -14
- package/dist/docs/cli/settings.md +14 -12
- package/dist/docs/cli/telemetry.md +45 -0
- package/dist/docs/cli/tutorials/plan-mode-steering.md +89 -0
- package/dist/docs/core/index.md +2 -0
- package/dist/docs/core/local-model-routing.md +193 -0
- package/dist/docs/reference/configuration.md +27 -3
- package/dist/docs/reference/keyboard-shortcuts.md +168 -90
- package/dist/docs/reference/policy-engine.md +30 -6
- package/dist/docs/resources/troubleshooting.md +15 -0
- package/dist/docs/sidebar.json +10 -0
- package/dist/docs/tools/shell.md +8 -0
- package/dist/google-gemini-cli-core-0.35.0-nightly.20260311.657f19c1f.tgz +0 -0
- package/dist/src/agents/a2a-client-manager.d.ts +11 -4
- package/dist/src/agents/a2a-client-manager.js +61 -34
- package/dist/src/agents/a2a-client-manager.js.map +1 -1
- package/dist/src/agents/a2a-client-manager.test.js +178 -115
- package/dist/src/agents/a2a-client-manager.test.js.map +1 -1
- package/dist/src/agents/a2aUtils.d.ts +4 -28
- package/dist/src/agents/a2aUtils.js +20 -181
- package/dist/src/agents/a2aUtils.js.map +1 -1
- package/dist/src/agents/a2aUtils.test.js +19 -106
- package/dist/src/agents/a2aUtils.test.js.map +1 -1
- package/dist/src/agents/agent-scheduler.d.ts +2 -0
- package/dist/src/agents/agent-scheduler.js +3 -2
- package/dist/src/agents/agent-scheduler.js.map +1 -1
- package/dist/src/agents/agent-scheduler.test.js +12 -3
- package/dist/src/agents/agent-scheduler.test.js.map +1 -1
- package/dist/src/agents/agentLoader.d.ts +2 -2
- package/dist/src/agents/agentLoader.js +15 -0
- package/dist/src/agents/agentLoader.js.map +1 -1
- package/dist/src/agents/auth-provider/factory.d.ts +2 -0
- package/dist/src/agents/auth-provider/factory.js +6 -3
- package/dist/src/agents/auth-provider/factory.js.map +1 -1
- package/dist/src/agents/auth-provider/google-credentials-provider.d.ts +26 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.js +117 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.js.map +1 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.test.d.ts +6 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.test.js +126 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.test.js.map +1 -0
- package/dist/src/agents/browser/browserAgentFactory.js +11 -2
- package/dist/src/agents/browser/browserAgentFactory.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.d.ts +4 -3
- package/dist/src/agents/browser/browserAgentInvocation.js +10 -4
- package/dist/src/agents/browser/browserAgentInvocation.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.test.js +1 -0
- package/dist/src/agents/browser/browserAgentInvocation.test.js.map +1 -1
- package/dist/src/agents/browser/browserManager.d.ts +10 -0
- package/dist/src/agents/browser/browserManager.js +53 -8
- package/dist/src/agents/browser/browserManager.js.map +1 -1
- package/dist/src/agents/browser/inputBlocker.d.ts +51 -0
- package/dist/src/agents/browser/inputBlocker.js +234 -0
- package/dist/src/agents/browser/inputBlocker.js.map +1 -0
- package/dist/src/agents/browser/inputBlocker.test.d.ts +6 -0
- package/dist/src/agents/browser/inputBlocker.test.js +82 -0
- package/dist/src/agents/browser/inputBlocker.test.js.map +1 -0
- package/dist/src/agents/browser/mcpToolWrapper.d.ts +3 -2
- package/dist/src/agents/browser/mcpToolWrapper.js +49 -8
- package/dist/src/agents/browser/mcpToolWrapper.js.map +1 -1
- package/dist/src/agents/browser/mcpToolWrapper.test.js +51 -0
- package/dist/src/agents/browser/mcpToolWrapper.test.js.map +1 -1
- package/dist/src/agents/local-executor.d.ts +5 -4
- package/dist/src/agents/local-executor.js +30 -25
- package/dist/src/agents/local-executor.js.map +1 -1
- package/dist/src/agents/local-executor.test.js +269 -3
- package/dist/src/agents/local-executor.test.js.map +1 -1
- package/dist/src/agents/local-invocation.d.ts +4 -4
- package/dist/src/agents/local-invocation.js +12 -9
- package/dist/src/agents/local-invocation.js.map +1 -1
- package/dist/src/agents/local-invocation.test.js +19 -3
- package/dist/src/agents/local-invocation.test.js.map +1 -1
- package/dist/src/agents/registry.js +3 -2
- package/dist/src/agents/registry.js.map +1 -1
- package/dist/src/agents/registry.test.js +1 -0
- package/dist/src/agents/registry.test.js.map +1 -1
- package/dist/src/agents/remote-invocation.d.ts +0 -9
- package/dist/src/agents/remote-invocation.js +1 -28
- package/dist/src/agents/remote-invocation.js.map +1 -1
- package/dist/src/agents/remote-invocation.test.js +1 -0
- package/dist/src/agents/remote-invocation.test.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.d.ts +5 -4
- package/dist/src/agents/subagent-tool-wrapper.js +9 -5
- package/dist/src/agents/subagent-tool-wrapper.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.test.js +15 -1
- package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -1
- package/dist/src/agents/subagent-tool.d.ts +3 -3
- package/dist/src/agents/subagent-tool.js +16 -12
- package/dist/src/agents/subagent-tool.js.map +1 -1
- package/dist/src/agents/subagent-tool.test.js +13 -3
- package/dist/src/agents/subagent-tool.test.js.map +1 -1
- package/dist/src/code_assist/oauth2.js +0 -1
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/server.js +2 -2
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +5 -1
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/code_assist/telemetry.d.ts +2 -2
- package/dist/src/code_assist/telemetry.js +5 -3
- package/dist/src/code_assist/telemetry.js.map +1 -1
- package/dist/src/code_assist/telemetry.test.js +14 -12
- package/dist/src/code_assist/telemetry.test.js.map +1 -1
- package/dist/src/code_assist/types.d.ts +14 -12
- package/dist/src/code_assist/types.js.map +1 -1
- package/dist/src/config/agent-loop-context.d.ts +3 -0
- package/dist/src/config/config.d.ts +75 -2
- package/dist/src/config/config.js +78 -11
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +170 -10
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/models.d.ts +14 -0
- package/dist/src/config/models.js +37 -0
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/config/models.test.js +51 -1
- package/dist/src/config/models.test.js.map +1 -1
- package/dist/src/config/storage.d.ts +1 -0
- package/dist/src/config/storage.js +3 -0
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/core/baseLlmClient.js +19 -3
- package/dist/src/core/baseLlmClient.js.map +1 -1
- package/dist/src/core/baseLlmClient.test.js +2 -0
- package/dist/src/core/baseLlmClient.test.js.map +1 -1
- package/dist/src/core/client.d.ts +4 -3
- package/dist/src/core/client.js +42 -17
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +8 -0
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +1 -0
- package/dist/src/core/contentGenerator.js +35 -3
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +137 -2
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolHookTriggers.d.ts +2 -3
- package/dist/src/core/coreToolHookTriggers.js +5 -11
- package/dist/src/core/coreToolHookTriggers.js.map +1 -1
- package/dist/src/core/coreToolHookTriggers.test.js +24 -0
- package/dist/src/core/coreToolHookTriggers.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.js +1 -1
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/geminiChat.js +31 -21
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +6 -4
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/geminiChat_network_retry.test.js +21 -11
- package/dist/src/core/geminiChat_network_retry.test.js.map +1 -1
- package/dist/src/fallback/handler.js +0 -4
- package/dist/src/fallback/handler.js.map +1 -1
- package/dist/src/fallback/handler.test.js +0 -6
- package/dist/src/fallback/handler.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/generated/git-commit.js.map +1 -1
- package/dist/src/ide/detect-ide.d.ts +8 -0
- package/dist/src/ide/detect-ide.js +12 -1
- package/dist/src/ide/detect-ide.js.map +1 -1
- package/dist/src/ide/detect-ide.test.js +12 -0
- package/dist/src/ide/detect-ide.test.js.map +1 -1
- package/dist/src/ide/ide-installer.js +20 -8
- package/dist/src/ide/ide-installer.js.map +1 -1
- package/dist/src/ide/ide-installer.test.js +60 -4
- package/dist/src/ide/ide-installer.test.js.map +1 -1
- package/dist/src/mcp/oauth-provider.js +0 -2
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.test.js +6 -10
- package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
- package/dist/src/mcp/oauth-utils.js +0 -2
- package/dist/src/mcp/oauth-utils.js.map +1 -1
- package/dist/src/mcp/token-storage/file-token-storage.d.ts +24 -0
- package/dist/src/mcp/token-storage/file-token-storage.js +152 -0
- package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js +276 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.js +21 -9
- package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -1
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +59 -10
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/index.d.ts +1 -1
- package/dist/src/mcp/token-storage/index.js +1 -1
- package/dist/src/mcp/token-storage/index.js.map +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +0 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.js +0 -3
- package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -1
- package/dist/src/policy/config.d.ts +14 -2
- package/dist/src/policy/config.js +94 -49
- package/dist/src/policy/config.js.map +1 -1
- package/dist/src/policy/config.test.js +208 -488
- package/dist/src/policy/config.test.js.map +1 -1
- package/dist/src/policy/policies/plan.toml +1 -1
- package/dist/src/policy/stable-stringify.js +15 -5
- package/dist/src/policy/stable-stringify.js.map +1 -1
- package/dist/src/policy/types.d.ts +1 -0
- package/dist/src/policy/types.js.map +1 -1
- package/dist/src/policy/utils.d.ts +17 -0
- package/dist/src/policy/utils.js +27 -7
- package/dist/src/policy/utils.js.map +1 -1
- package/dist/src/prompts/snippets.js +2 -1
- package/dist/src/prompts/snippets.js.map +1 -1
- package/dist/src/prompts/utils.test.d.ts +6 -0
- package/dist/src/prompts/utils.test.js +225 -0
- package/dist/src/prompts/utils.test.js.map +1 -0
- package/dist/src/routing/modelRouterService.js +2 -2
- package/dist/src/routing/modelRouterService.js.map +1 -1
- package/dist/src/routing/modelRouterService.test.js +4 -3
- package/dist/src/routing/modelRouterService.test.js.map +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.js +6 -40
- package/dist/src/routing/strategies/numericalClassifierStrategy.js.map +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js +29 -64
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js.map +1 -1
- package/dist/src/scheduler/policy.d.ts +3 -7
- package/dist/src/scheduler/policy.js +4 -3
- package/dist/src/scheduler/policy.js.map +1 -1
- package/dist/src/scheduler/policy.test.js +51 -31
- package/dist/src/scheduler/policy.test.js.map +1 -1
- package/dist/src/scheduler/scheduler.d.ts +4 -2
- package/dist/src/scheduler/scheduler.js +19 -16
- package/dist/src/scheduler/scheduler.js.map +1 -1
- package/dist/src/scheduler/scheduler.test.js +33 -10
- package/dist/src/scheduler/scheduler.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_parallel.test.js +40 -2
- package/dist/src/scheduler/scheduler_parallel.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_waiting_callback.test.js +1 -1
- package/dist/src/scheduler/scheduler_waiting_callback.test.js.map +1 -1
- package/dist/src/scheduler/tool-executor.d.ts +3 -3
- package/dist/src/scheduler/tool-executor.js +15 -21
- package/dist/src/scheduler/tool-executor.js.map +1 -1
- package/dist/src/scheduler/tool-executor.test.js +43 -8
- package/dist/src/scheduler/tool-executor.test.js.map +1 -1
- package/dist/src/services/chatRecordingService.js +2 -1
- package/dist/src/services/chatRecordingService.js.map +1 -1
- package/dist/src/services/chatRecordingService.test.js +21 -0
- package/dist/src/services/chatRecordingService.test.js.map +1 -1
- package/dist/src/services/executionLifecycleService.d.ts +83 -0
- package/dist/src/services/executionLifecycleService.js +271 -0
- package/dist/src/services/executionLifecycleService.js.map +1 -0
- package/dist/src/services/executionLifecycleService.test.d.ts +6 -0
- package/dist/src/services/executionLifecycleService.test.js +227 -0
- package/dist/src/services/executionLifecycleService.test.js.map +1 -0
- package/dist/src/services/keychainService.d.ts +0 -5
- package/dist/src/services/keychainService.js +13 -30
- package/dist/src/services/keychainService.js.map +1 -1
- package/dist/src/services/keychainService.test.js +22 -52
- package/dist/src/services/keychainService.test.js.map +1 -1
- package/dist/src/services/sandboxManager.d.ts +54 -0
- package/dist/src/services/sandboxManager.js +30 -0
- package/dist/src/services/sandboxManager.js.map +1 -0
- package/dist/src/services/sandboxManager.test.d.ts +6 -0
- package/dist/src/services/sandboxManager.test.js +95 -0
- package/dist/src/services/sandboxManager.test.js.map +1 -0
- package/dist/src/services/shellExecutionService.d.ts +4 -52
- package/dist/src/services/shellExecutionService.js +437 -498
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +10 -21
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +13 -2
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +91 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +77 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +10 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +25 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +3 -3
- package/dist/src/telemetry/index.js +3 -3
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +2 -1
- package/dist/src/telemetry/loggers.js +32 -1
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +37 -2
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +13 -0
- package/dist/src/telemetry/metrics.js +17 -0
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/startupProfiler.js +4 -4
- package/dist/src/telemetry/startupProfiler.js.map +1 -1
- package/dist/src/telemetry/startupProfiler.test.js +19 -0
- package/dist/src/telemetry/startupProfiler.test.js.map +1 -1
- package/dist/src/telemetry/telemetry-utils.test.js +3 -3
- package/dist/src/telemetry/types.d.ts +16 -2
- package/dist/src/telemetry/types.js +34 -0
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.d.ts +7 -0
- package/dist/src/telemetry/uiTelemetry.js +78 -0
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +101 -0
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/tools/exit-plan-mode.js +10 -2
- package/dist/src/tools/exit-plan-mode.js.map +1 -1
- package/dist/src/tools/exit-plan-mode.test.js +15 -0
- package/dist/src/tools/exit-plan-mode.test.js.map +1 -1
- package/dist/src/tools/ls.js +2 -2
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/mcp-client.js +0 -1
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +4 -0
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.test.js +10 -1
- package/dist/src/tools/mcp-tool.test.js.map +1 -1
- package/dist/src/tools/read-many-files.js +2 -4
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/shell.d.ts +1 -1
- package/dist/src/tools/shell.js +3 -3
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +4 -0
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +34 -1
- package/dist/src/tools/tools.js +47 -1
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/web-fetch.d.ts +5 -0
- package/dist/src/tools/web-fetch.js +177 -100
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-fetch.test.js +130 -26
- package/dist/src/tools/web-fetch.test.js.map +1 -1
- package/dist/src/tools/web-search.test.js +2 -0
- package/dist/src/tools/web-search.test.js.map +1 -1
- package/dist/src/utils/fetch.d.ts +0 -29
- package/dist/src/utils/fetch.js +10 -123
- package/dist/src/utils/fetch.js.map +1 -1
- package/dist/src/utils/fetch.test.js +1 -103
- package/dist/src/utils/fetch.test.js.map +1 -1
- package/dist/src/utils/language-detection.js +96 -89
- package/dist/src/utils/language-detection.js.map +1 -1
- package/dist/src/utils/language-detection.test.d.ts +6 -0
- package/dist/src/utils/language-detection.test.js +39 -0
- package/dist/src/utils/language-detection.test.js.map +1 -0
- package/dist/src/utils/oauth-flow.js +0 -2
- package/dist/src/utils/oauth-flow.js.map +1 -1
- package/dist/src/utils/paths.js +5 -2
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/paths.test.js +11 -0
- package/dist/src/utils/paths.test.js.map +1 -1
- package/dist/src/utils/process-utils.js +18 -4
- package/dist/src/utils/process-utils.js.map +1 -1
- package/dist/src/utils/process-utils.test.js +32 -10
- package/dist/src/utils/process-utils.test.js.map +1 -1
- package/dist/src/utils/retry.d.ts +7 -0
- package/dist/src/utils/retry.js +40 -3
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js +13 -0
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/summarizer.test.js +5 -0
- package/dist/src/utils/summarizer.test.js.map +1 -1
- package/dist/src/utils/surface.d.ts +18 -0
- package/dist/src/utils/surface.js +46 -0
- package/dist/src/utils/surface.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/google-gemini-cli-core-0.34.0-preview.2.tgz +0 -0
- package/dist/src/services/fileKeychain.d.ts +0 -24
- package/dist/src/services/fileKeychain.js +0 -123
- package/dist/src/services/fileKeychain.js.map +0 -1
|
@@ -3,27 +3,17 @@
|
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { describe, it, expect, vi, beforeEach
|
|
6
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
7
7
|
import { KeychainService } from './keychainService.js';
|
|
8
8
|
import { coreEvents } from '../utils/events.js';
|
|
9
9
|
import { debugLogger } from '../utils/debugLogger.js';
|
|
10
|
-
import { FileKeychain } from './fileKeychain.js';
|
|
11
10
|
const mockKeytar = {
|
|
12
11
|
getPassword: vi.fn(),
|
|
13
12
|
setPassword: vi.fn(),
|
|
14
13
|
deletePassword: vi.fn(),
|
|
15
14
|
findCredentials: vi.fn(),
|
|
16
15
|
};
|
|
17
|
-
const mockFileKeychain = {
|
|
18
|
-
getPassword: vi.fn(),
|
|
19
|
-
setPassword: vi.fn(),
|
|
20
|
-
deletePassword: vi.fn(),
|
|
21
|
-
findCredentials: vi.fn(),
|
|
22
|
-
};
|
|
23
16
|
vi.mock('keytar', () => ({ default: mockKeytar }));
|
|
24
|
-
vi.mock('./fileKeychain.js', () => ({
|
|
25
|
-
FileKeychain: vi.fn(() => mockFileKeychain),
|
|
26
|
-
}));
|
|
27
17
|
vi.mock('../utils/events.js', () => ({
|
|
28
18
|
coreEvents: { emitTelemetryKeychainAvailability: vi.fn() },
|
|
29
19
|
}));
|
|
@@ -34,13 +24,11 @@ describe('KeychainService', () => {
|
|
|
34
24
|
let service;
|
|
35
25
|
const SERVICE_NAME = 'test-service';
|
|
36
26
|
let passwords = {};
|
|
37
|
-
const originalEnv = process.env;
|
|
38
27
|
beforeEach(() => {
|
|
39
28
|
vi.clearAllMocks();
|
|
40
|
-
process.env = { ...originalEnv };
|
|
41
29
|
service = new KeychainService(SERVICE_NAME);
|
|
42
30
|
passwords = {};
|
|
43
|
-
// Stateful mock implementation
|
|
31
|
+
// Stateful mock implementation to verify behavioral correctness
|
|
44
32
|
mockKeytar.setPassword?.mockImplementation((_svc, acc, val) => {
|
|
45
33
|
passwords[acc] = val;
|
|
46
34
|
return Promise.resolve();
|
|
@@ -55,65 +43,35 @@ describe('KeychainService', () => {
|
|
|
55
43
|
account,
|
|
56
44
|
password,
|
|
57
45
|
}))));
|
|
58
|
-
// Stateful mock implementation for fallback file keychain
|
|
59
|
-
mockFileKeychain.setPassword?.mockImplementation((_svc, acc, val) => {
|
|
60
|
-
passwords[acc] = val;
|
|
61
|
-
return Promise.resolve();
|
|
62
|
-
});
|
|
63
|
-
mockFileKeychain.getPassword?.mockImplementation((_svc, acc) => Promise.resolve(passwords[acc] ?? null));
|
|
64
|
-
mockFileKeychain.deletePassword?.mockImplementation((_svc, acc) => {
|
|
65
|
-
const exists = !!passwords[acc];
|
|
66
|
-
delete passwords[acc];
|
|
67
|
-
return Promise.resolve(exists);
|
|
68
|
-
});
|
|
69
|
-
mockFileKeychain.findCredentials?.mockImplementation(() => Promise.resolve(Object.entries(passwords).map(([account, password]) => ({
|
|
70
|
-
account,
|
|
71
|
-
password,
|
|
72
|
-
}))));
|
|
73
|
-
});
|
|
74
|
-
afterEach(() => {
|
|
75
|
-
process.env = originalEnv;
|
|
76
46
|
});
|
|
77
47
|
describe('isAvailable', () => {
|
|
78
|
-
it('should return true and emit telemetry on successful functional test
|
|
48
|
+
it('should return true and emit telemetry on successful functional test', async () => {
|
|
79
49
|
const available = await service.isAvailable();
|
|
80
50
|
expect(available).toBe(true);
|
|
81
51
|
expect(mockKeytar.setPassword).toHaveBeenCalled();
|
|
82
52
|
expect(coreEvents.emitTelemetryKeychainAvailability).toHaveBeenCalledWith(expect.objectContaining({ available: true }));
|
|
83
53
|
});
|
|
84
|
-
it('should return
|
|
54
|
+
it('should return false, log error, and emit telemetry on failed functional test', async () => {
|
|
85
55
|
mockKeytar.setPassword?.mockRejectedValue(new Error('locked'));
|
|
86
56
|
const available = await service.isAvailable();
|
|
87
|
-
|
|
88
|
-
expect(available).toBe(true);
|
|
57
|
+
expect(available).toBe(false);
|
|
89
58
|
expect(debugLogger.log).toHaveBeenCalledWith(expect.stringContaining('encountered an error'), 'locked');
|
|
90
59
|
expect(coreEvents.emitTelemetryKeychainAvailability).toHaveBeenCalledWith(expect.objectContaining({ available: false }));
|
|
91
|
-
expect(debugLogger.log).toHaveBeenCalledWith(expect.stringContaining('Using FileKeychain fallback'));
|
|
92
|
-
expect(FileKeychain).toHaveBeenCalled();
|
|
93
60
|
});
|
|
94
|
-
it('should return
|
|
61
|
+
it('should return false, log validation error, and emit telemetry on module load failure', async () => {
|
|
95
62
|
const originalMock = mockKeytar.getPassword;
|
|
96
63
|
mockKeytar.getPassword = undefined; // Break schema
|
|
97
64
|
const available = await service.isAvailable();
|
|
98
|
-
expect(available).toBe(
|
|
65
|
+
expect(available).toBe(false);
|
|
99
66
|
expect(debugLogger.log).toHaveBeenCalledWith(expect.stringContaining('failed structural validation'), expect.objectContaining({ getPassword: expect.any(Array) }));
|
|
100
67
|
expect(coreEvents.emitTelemetryKeychainAvailability).toHaveBeenCalledWith(expect.objectContaining({ available: false }));
|
|
101
|
-
expect(FileKeychain).toHaveBeenCalled();
|
|
102
68
|
mockKeytar.getPassword = originalMock;
|
|
103
69
|
});
|
|
104
|
-
it('should log failure if functional test cycle returns false
|
|
70
|
+
it('should log failure if functional test cycle returns false', async () => {
|
|
105
71
|
mockKeytar.getPassword?.mockResolvedValue('wrong-password');
|
|
106
72
|
const available = await service.isAvailable();
|
|
107
|
-
expect(available).toBe(
|
|
73
|
+
expect(available).toBe(false);
|
|
108
74
|
expect(debugLogger.log).toHaveBeenCalledWith(expect.stringContaining('functional verification failed'));
|
|
109
|
-
expect(FileKeychain).toHaveBeenCalled();
|
|
110
|
-
});
|
|
111
|
-
it('should fallback to FileKeychain when GEMINI_FORCE_FILE_STORAGE is true', async () => {
|
|
112
|
-
process.env['GEMINI_FORCE_FILE_STORAGE'] = 'true';
|
|
113
|
-
const available = await service.isAvailable();
|
|
114
|
-
expect(available).toBe(true);
|
|
115
|
-
expect(FileKeychain).toHaveBeenCalled();
|
|
116
|
-
expect(coreEvents.emitTelemetryKeychainAvailability).toHaveBeenCalledWith(expect.objectContaining({ available: false }));
|
|
117
75
|
});
|
|
118
76
|
it('should cache the result and handle concurrent initialization attempts once', async () => {
|
|
119
77
|
await Promise.all([
|
|
@@ -145,6 +103,18 @@ describe('KeychainService', () => {
|
|
|
145
103
|
expect(await service.getPassword('missing')).toBeNull();
|
|
146
104
|
});
|
|
147
105
|
});
|
|
148
|
-
|
|
106
|
+
describe('When Unavailable', () => {
|
|
107
|
+
beforeEach(() => {
|
|
108
|
+
mockKeytar.setPassword?.mockRejectedValue(new Error('Unavailable'));
|
|
109
|
+
});
|
|
110
|
+
it.each([
|
|
111
|
+
{ method: 'getPassword', args: ['acc'] },
|
|
112
|
+
{ method: 'setPassword', args: ['acc', 'val'] },
|
|
113
|
+
{ method: 'deletePassword', args: ['acc'] },
|
|
114
|
+
{ method: 'findCredentials', args: [] },
|
|
115
|
+
])('$method should throw a consistent error', async ({ method, args }) => {
|
|
116
|
+
await expect(service[method](...args)).rejects.toThrow('Keychain is not available');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
149
119
|
});
|
|
150
120
|
//# sourceMappingURL=keychainService.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keychainService.test.js","sourceRoot":"","sources":["../../../src/services/keychainService.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"keychainService.test.js","sourceRoot":"","sources":["../../../src/services/keychainService.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { type EnvironmentSanitizationConfig } from './environmentSanitization.js';
|
|
7
|
+
/**
|
|
8
|
+
* Request for preparing a command to run in a sandbox.
|
|
9
|
+
*/
|
|
10
|
+
export interface SandboxRequest {
|
|
11
|
+
/** The program to execute. */
|
|
12
|
+
command: string;
|
|
13
|
+
/** Arguments for the program. */
|
|
14
|
+
args: string[];
|
|
15
|
+
/** The working directory. */
|
|
16
|
+
cwd: string;
|
|
17
|
+
/** Environment variables to be passed to the program. */
|
|
18
|
+
env: NodeJS.ProcessEnv;
|
|
19
|
+
/** Optional sandbox-specific configuration. */
|
|
20
|
+
config?: {
|
|
21
|
+
sanitizationConfig?: Partial<EnvironmentSanitizationConfig>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A command that has been prepared for sandboxed execution.
|
|
26
|
+
*/
|
|
27
|
+
export interface SandboxedCommand {
|
|
28
|
+
/** The program or wrapper to execute. */
|
|
29
|
+
program: string;
|
|
30
|
+
/** Final arguments for the program. */
|
|
31
|
+
args: string[];
|
|
32
|
+
/** Sanitized environment variables. */
|
|
33
|
+
env: NodeJS.ProcessEnv;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Interface for a service that prepares commands for sandboxed execution.
|
|
37
|
+
*/
|
|
38
|
+
export interface SandboxManager {
|
|
39
|
+
/**
|
|
40
|
+
* Prepares a command to run in a sandbox, including environment sanitization.
|
|
41
|
+
*/
|
|
42
|
+
prepareCommand(req: SandboxRequest): Promise<SandboxedCommand>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A no-op implementation of SandboxManager that silently passes commands
|
|
46
|
+
* through while applying environment sanitization.
|
|
47
|
+
*/
|
|
48
|
+
export declare class NoopSandboxManager implements SandboxManager {
|
|
49
|
+
/**
|
|
50
|
+
* Prepares a command by sanitizing the environment and passing through
|
|
51
|
+
* the original program and arguments.
|
|
52
|
+
*/
|
|
53
|
+
prepareCommand(req: SandboxRequest): Promise<SandboxedCommand>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { sanitizeEnvironment, } from './environmentSanitization.js';
|
|
7
|
+
/**
|
|
8
|
+
* A no-op implementation of SandboxManager that silently passes commands
|
|
9
|
+
* through while applying environment sanitization.
|
|
10
|
+
*/
|
|
11
|
+
export class NoopSandboxManager {
|
|
12
|
+
/**
|
|
13
|
+
* Prepares a command by sanitizing the environment and passing through
|
|
14
|
+
* the original program and arguments.
|
|
15
|
+
*/
|
|
16
|
+
async prepareCommand(req) {
|
|
17
|
+
const sanitizationConfig = {
|
|
18
|
+
allowedEnvironmentVariables: req.config?.sanitizationConfig?.allowedEnvironmentVariables ?? [],
|
|
19
|
+
blockedEnvironmentVariables: req.config?.sanitizationConfig?.blockedEnvironmentVariables ?? [],
|
|
20
|
+
enableEnvironmentVariableRedaction: true, // Forced for safety
|
|
21
|
+
};
|
|
22
|
+
const sanitizedEnv = sanitizeEnvironment(req.env, sanitizationConfig);
|
|
23
|
+
return {
|
|
24
|
+
program: req.command,
|
|
25
|
+
args: req.args,
|
|
26
|
+
env: sanitizedEnv,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=sandboxManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandboxManager.js","sourceRoot":"","sources":["../../../src/services/sandboxManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,mBAAmB,GAEpB,MAAM,8BAA8B,CAAC;AA0CtC;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IAC7B;;;OAGG;IACH,KAAK,CAAC,cAAc,CAAC,GAAmB;QACtC,MAAM,kBAAkB,GAAkC;YACxD,2BAA2B,EACzB,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,2BAA2B,IAAI,EAAE;YACnE,2BAA2B,EACzB,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,2BAA2B,IAAI,EAAE;YACnE,kCAAkC,EAAE,IAAI,EAAE,oBAAoB;SAC/D,CAAC;QAEF,MAAM,YAAY,GAAG,mBAAmB,CAAC,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAEtE,OAAO;YACL,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,GAAG,EAAE,YAAY;SAClB,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it } from 'vitest';
|
|
7
|
+
import { NoopSandboxManager } from './sandboxManager.js';
|
|
8
|
+
describe('NoopSandboxManager', () => {
|
|
9
|
+
const sandboxManager = new NoopSandboxManager();
|
|
10
|
+
it('should pass through the command and arguments unchanged', async () => {
|
|
11
|
+
const req = {
|
|
12
|
+
command: 'ls',
|
|
13
|
+
args: ['-la'],
|
|
14
|
+
cwd: '/tmp',
|
|
15
|
+
env: { PATH: '/usr/bin' },
|
|
16
|
+
};
|
|
17
|
+
const result = await sandboxManager.prepareCommand(req);
|
|
18
|
+
expect(result.program).toBe('ls');
|
|
19
|
+
expect(result.args).toEqual(['-la']);
|
|
20
|
+
});
|
|
21
|
+
it('should sanitize the environment variables', async () => {
|
|
22
|
+
const req = {
|
|
23
|
+
command: 'echo',
|
|
24
|
+
args: ['hello'],
|
|
25
|
+
cwd: '/tmp',
|
|
26
|
+
env: {
|
|
27
|
+
PATH: '/usr/bin',
|
|
28
|
+
GITHUB_TOKEN: 'ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
|
29
|
+
MY_SECRET: 'super-secret',
|
|
30
|
+
SAFE_VAR: 'is-safe',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const result = await sandboxManager.prepareCommand(req);
|
|
34
|
+
expect(result.env['PATH']).toBe('/usr/bin');
|
|
35
|
+
expect(result.env['SAFE_VAR']).toBe('is-safe');
|
|
36
|
+
expect(result.env['GITHUB_TOKEN']).toBeUndefined();
|
|
37
|
+
expect(result.env['MY_SECRET']).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
it('should force environment variable redaction even if not requested in config', async () => {
|
|
40
|
+
const req = {
|
|
41
|
+
command: 'echo',
|
|
42
|
+
args: ['hello'],
|
|
43
|
+
cwd: '/tmp',
|
|
44
|
+
env: {
|
|
45
|
+
API_KEY: 'sensitive-key',
|
|
46
|
+
},
|
|
47
|
+
config: {
|
|
48
|
+
sanitizationConfig: {
|
|
49
|
+
enableEnvironmentVariableRedaction: false,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const result = await sandboxManager.prepareCommand(req);
|
|
54
|
+
expect(result.env['API_KEY']).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
it('should respect allowedEnvironmentVariables in config', async () => {
|
|
57
|
+
const req = {
|
|
58
|
+
command: 'echo',
|
|
59
|
+
args: ['hello'],
|
|
60
|
+
cwd: '/tmp',
|
|
61
|
+
env: {
|
|
62
|
+
MY_TOKEN: 'secret-token',
|
|
63
|
+
OTHER_SECRET: 'another-secret',
|
|
64
|
+
},
|
|
65
|
+
config: {
|
|
66
|
+
sanitizationConfig: {
|
|
67
|
+
allowedEnvironmentVariables: ['MY_TOKEN'],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
const result = await sandboxManager.prepareCommand(req);
|
|
72
|
+
expect(result.env['MY_TOKEN']).toBe('secret-token');
|
|
73
|
+
expect(result.env['OTHER_SECRET']).toBeUndefined();
|
|
74
|
+
});
|
|
75
|
+
it('should respect blockedEnvironmentVariables in config', async () => {
|
|
76
|
+
const req = {
|
|
77
|
+
command: 'echo',
|
|
78
|
+
args: ['hello'],
|
|
79
|
+
cwd: '/tmp',
|
|
80
|
+
env: {
|
|
81
|
+
SAFE_VAR: 'safe-value',
|
|
82
|
+
BLOCKED_VAR: 'blocked-value',
|
|
83
|
+
},
|
|
84
|
+
config: {
|
|
85
|
+
sanitizationConfig: {
|
|
86
|
+
blockedEnvironmentVariables: ['BLOCKED_VAR'],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const result = await sandboxManager.prepareCommand(req);
|
|
91
|
+
expect(result.env['SAFE_VAR']).toBe('safe-value');
|
|
92
|
+
expect(result.env['BLOCKED_VAR']).toBeUndefined();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=sandboxManager.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandboxManager.test.js","sourceRoot":"","sources":["../../../src/services/sandboxManager.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { type AnsiOutput } from '../utils/terminalSerializer.js';
|
|
7
6
|
import { type EnvironmentSanitizationConfig } from './environmentSanitization.js';
|
|
7
|
+
import { type ExecutionHandle, type ExecutionOutputEvent, type ExecutionResult } from './executionLifecycleService.js';
|
|
8
8
|
/**
|
|
9
9
|
* An environment variable that is set for shell executions. This can be used
|
|
10
10
|
* by downstream executables and scripts to identify that they were executed
|
|
@@ -17,33 +17,9 @@ export declare const GEMINI_CLI_IDENTIFICATION_ENV_VAR = "GEMINI_CLI";
|
|
|
17
17
|
export declare const GEMINI_CLI_IDENTIFICATION_ENV_VAR_VALUE = "1";
|
|
18
18
|
export declare const SCROLLBACK_LIMIT = 300000;
|
|
19
19
|
/** A structured result from a shell command execution. */
|
|
20
|
-
export
|
|
21
|
-
/** The raw, unprocessed output buffer. */
|
|
22
|
-
rawOutput: Buffer;
|
|
23
|
-
/** The combined, decoded output as a string. */
|
|
24
|
-
output: string;
|
|
25
|
-
/** The process exit code, or null if terminated by a signal. */
|
|
26
|
-
exitCode: number | null;
|
|
27
|
-
/** The signal that terminated the process, if any. */
|
|
28
|
-
signal: number | null;
|
|
29
|
-
/** An error object if the process failed to spawn. */
|
|
30
|
-
error: Error | null;
|
|
31
|
-
/** A boolean indicating if the command was aborted by the user. */
|
|
32
|
-
aborted: boolean;
|
|
33
|
-
/** The process ID of the spawned shell. */
|
|
34
|
-
pid: number | undefined;
|
|
35
|
-
/** The method used to execute the shell command. */
|
|
36
|
-
executionMethod: 'lydell-node-pty' | 'node-pty' | 'child_process' | 'none';
|
|
37
|
-
/** Whether the command was moved to the background. */
|
|
38
|
-
backgrounded?: boolean;
|
|
39
|
-
}
|
|
20
|
+
export type ShellExecutionResult = ExecutionResult;
|
|
40
21
|
/** A handle for an ongoing shell execution. */
|
|
41
|
-
export
|
|
42
|
-
/** The process ID of the spawned shell. */
|
|
43
|
-
pid: number | undefined;
|
|
44
|
-
/** A promise that resolves with the complete execution result. */
|
|
45
|
-
result: Promise<ShellExecutionResult>;
|
|
46
|
-
}
|
|
22
|
+
export type ShellExecutionHandle = ExecutionHandle;
|
|
47
23
|
export interface ShellExecutionConfig {
|
|
48
24
|
terminalWidth?: number;
|
|
49
25
|
terminalHeight?: number;
|
|
@@ -59,27 +35,7 @@ export interface ShellExecutionConfig {
|
|
|
59
35
|
/**
|
|
60
36
|
* Describes a structured event emitted during shell command execution.
|
|
61
37
|
*/
|
|
62
|
-
export type ShellOutputEvent =
|
|
63
|
-
/** The event contains a chunk of output data. */
|
|
64
|
-
type: 'data';
|
|
65
|
-
/** The decoded string chunk. */
|
|
66
|
-
chunk: string | AnsiOutput;
|
|
67
|
-
} | {
|
|
68
|
-
/** Signals that the output stream has been identified as binary. */
|
|
69
|
-
type: 'binary_detected';
|
|
70
|
-
} | {
|
|
71
|
-
/** Provides progress updates for a binary stream. */
|
|
72
|
-
type: 'binary_progress';
|
|
73
|
-
/** The total number of bytes received so far. */
|
|
74
|
-
bytesReceived: number;
|
|
75
|
-
} | {
|
|
76
|
-
/** Signals that the process has exited. */
|
|
77
|
-
type: 'exit';
|
|
78
|
-
/** The exit code of the process, if any. */
|
|
79
|
-
exitCode: number | null;
|
|
80
|
-
/** The signal that terminated the process, if any. */
|
|
81
|
-
signal: number | null;
|
|
82
|
-
};
|
|
38
|
+
export type ShellOutputEvent = ExecutionOutputEvent;
|
|
83
39
|
/**
|
|
84
40
|
* A centralized service for executing shell commands with robust process
|
|
85
41
|
* management, cross-platform compatibility, and streaming output capabilities.
|
|
@@ -90,13 +46,10 @@ export declare class ShellExecutionService {
|
|
|
90
46
|
private static activeChildProcesses;
|
|
91
47
|
private static backgroundLogPids;
|
|
92
48
|
private static backgroundLogStreams;
|
|
93
|
-
private static exitedPtyInfo;
|
|
94
49
|
static getLogDir(): string;
|
|
95
50
|
static getLogFilePath(pid: number): string;
|
|
96
51
|
private static syncBackgroundLog;
|
|
97
52
|
private static cleanupLogStream;
|
|
98
|
-
private static activeResolvers;
|
|
99
|
-
private static activeListeners;
|
|
100
53
|
/**
|
|
101
54
|
* Executes a shell command using `node-pty`, capturing all output and lifecycle events.
|
|
102
55
|
*
|
|
@@ -109,7 +62,6 @@ export declare class ShellExecutionService {
|
|
|
109
62
|
*/
|
|
110
63
|
static execute(commandToExecute: string, cwd: string, onOutputEvent: (event: ShellOutputEvent) => void, abortSignal: AbortSignal, shouldUseNodePty: boolean, shellExecutionConfig: ShellExecutionConfig): Promise<ShellExecutionHandle>;
|
|
111
64
|
private static appendAndTruncate;
|
|
112
|
-
private static emitEvent;
|
|
113
65
|
private static childProcessFallback;
|
|
114
66
|
private static executeWithPty;
|
|
115
67
|
/**
|