@google/gemini-cli-core 0.35.0-preview.2 → 0.36.0-nightly.20260321.fc03891a1
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/README.md +0 -1
- package/dist/docs/CONTRIBUTING.md +0 -15
- package/dist/docs/admin/enterprise-controls.md +61 -0
- package/dist/docs/changelogs/index.md +11 -0
- package/dist/docs/changelogs/latest.md +459 -209
- package/dist/docs/changelogs/preview.md +355 -454
- package/dist/docs/cli/checkpointing.md +3 -1
- package/dist/docs/cli/cli-reference.md +1 -0
- package/dist/docs/cli/custom-commands.md +7 -5
- package/dist/docs/cli/enterprise.md +15 -9
- package/dist/docs/cli/git-worktrees.md +107 -0
- package/dist/docs/cli/model-steering.md +4 -3
- package/dist/docs/cli/model.md +3 -1
- package/dist/docs/cli/notifications.md +4 -3
- package/dist/docs/cli/plan-mode.md +28 -8
- package/dist/docs/cli/sandbox.md +24 -4
- package/dist/docs/cli/session-management.md +6 -0
- package/dist/docs/cli/settings.md +14 -1
- package/dist/docs/cli/skills.md +4 -2
- package/dist/docs/cli/system-prompt.md +3 -1
- package/dist/docs/cli/telemetry.md +6 -3
- package/dist/docs/cli/themes.md +12 -8
- package/dist/docs/cli/tutorials/file-management.md +8 -6
- package/dist/docs/cli/tutorials/mcp-setup.md +5 -3
- package/dist/docs/cli/tutorials/memory-management.md +6 -6
- package/dist/docs/cli/tutorials/plan-mode-steering.md +4 -3
- package/dist/docs/cli/tutorials/shell-commands.md +3 -3
- package/dist/docs/core/remote-agents.md +8 -3
- package/dist/docs/core/subagents.md +21 -13
- package/dist/docs/extensions/reference.md +8 -3
- package/dist/docs/get-started/authentication.md +60 -50
- package/dist/docs/get-started/examples.md +3 -1
- package/dist/docs/get-started/gemini-3.md +11 -5
- package/dist/docs/hooks/index.md +3 -1
- package/dist/docs/hooks/writing-hooks.md +2 -2
- package/dist/docs/ide-integration/ide-companion-spec.md +5 -3
- package/dist/docs/ide-integration/index.md +8 -4
- package/dist/docs/issue-and-pr-automation.md +3 -1
- package/dist/docs/local-development.md +3 -1
- package/dist/docs/reference/commands.md +2 -2
- package/dist/docs/reference/configuration.md +410 -16
- package/dist/docs/reference/policy-engine.md +47 -19
- package/dist/docs/reference/tools.md +3 -1
- package/dist/docs/release-confidence.md +7 -3
- package/dist/docs/releases.md +11 -7
- package/dist/docs/resources/faq.md +13 -0
- package/dist/docs/resources/tos-privacy.md +4 -2
- package/dist/docs/resources/troubleshooting.md +3 -1
- package/dist/docs/sidebar.json +5 -0
- package/dist/docs/tools/mcp-server.md +17 -9
- package/dist/docs/tools/planning.md +3 -1
- package/dist/docs/tools/shell.md +4 -4
- package/dist/docs/tools/todos.md +2 -1
- package/dist/{google-gemini-cli-core-0.35.0-preview.1.tgz → google-gemini-cli-core-0.36.0-nightly.20260317.2f90b4653.tgz} +0 -0
- package/dist/src/agent/agent-session.d.ts +37 -0
- package/dist/src/agent/agent-session.js +168 -0
- package/dist/src/agent/agent-session.js.map +1 -0
- package/dist/src/agent/agent-session.test.d.ts +6 -0
- package/dist/src/agent/agent-session.test.js +217 -0
- package/dist/src/agent/agent-session.test.js.map +1 -0
- package/dist/src/agent/content-utils.d.ts +33 -0
- package/dist/src/agent/content-utils.js +135 -0
- package/dist/src/agent/content-utils.js.map +1 -0
- package/dist/src/agent/content-utils.test.d.ts +6 -0
- package/dist/src/agent/content-utils.test.js +223 -0
- package/dist/src/agent/content-utils.test.js.map +1 -0
- package/dist/src/agent/mock.d.ts +9 -12
- package/dist/src/agent/mock.js +88 -129
- package/dist/src/agent/mock.js.map +1 -1
- package/dist/src/agent/mock.test.js +114 -144
- package/dist/src/agent/mock.test.js.map +1 -1
- package/dist/src/agent/types.d.ts +21 -21
- package/dist/src/agents/a2a-client-manager.d.ts +2 -11
- package/dist/src/agents/a2a-client-manager.js +3 -19
- package/dist/src/agents/a2a-client-manager.js.map +1 -1
- package/dist/src/agents/a2a-client-manager.test.js +6 -10
- package/dist/src/agents/a2a-client-manager.test.js.map +1 -1
- package/dist/src/agents/agent-scheduler.d.ts +6 -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 +6 -0
- package/dist/src/agents/agent-scheduler.test.js.map +1 -1
- package/dist/src/agents/browser/browserAgentDefinition.js +10 -1
- package/dist/src/agents/browser/browserAgentDefinition.js.map +1 -1
- package/dist/src/agents/browser/browserAgentFactory.js +62 -1
- package/dist/src/agents/browser/browserAgentFactory.js.map +1 -1
- package/dist/src/agents/browser/browserAgentFactory.test.js +73 -0
- package/dist/src/agents/browser/browserAgentFactory.test.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.js +2 -97
- package/dist/src/agents/browser/browserAgentInvocation.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.test.js +30 -0
- package/dist/src/agents/browser/browserAgentInvocation.test.js.map +1 -1
- package/dist/src/agents/browser/browserManager.js +11 -0
- package/dist/src/agents/browser/browserManager.js.map +1 -1
- package/dist/src/agents/browser/browserManager.test.js +37 -0
- package/dist/src/agents/browser/browserManager.test.js.map +1 -1
- package/dist/src/agents/browser/mcpToolWrapper.d.ts +4 -2
- package/dist/src/agents/browser/mcpToolWrapper.js +30 -8
- package/dist/src/agents/browser/mcpToolWrapper.js.map +1 -1
- package/dist/src/agents/browser/mcpToolWrapper.test.js +30 -0
- package/dist/src/agents/browser/mcpToolWrapper.test.js.map +1 -1
- package/dist/src/agents/browser/mcpToolWrapperConfirmation.test.js +3 -3
- package/dist/src/agents/codebase-investigator.js +3 -3
- package/dist/src/agents/codebase-investigator.js.map +1 -1
- package/dist/src/agents/local-executor.d.ts +3 -1
- package/dist/src/agents/local-executor.js +138 -39
- package/dist/src/agents/local-executor.js.map +1 -1
- package/dist/src/agents/local-executor.test.js +305 -12
- package/dist/src/agents/local-executor.test.js.map +1 -1
- package/dist/src/agents/local-invocation.js +43 -24
- package/dist/src/agents/local-invocation.js.map +1 -1
- package/dist/src/agents/local-invocation.test.js +89 -14
- package/dist/src/agents/local-invocation.test.js.map +1 -1
- package/dist/src/agents/memory-manager-agent.d.ts +25 -0
- package/dist/src/agents/memory-manager-agent.js +137 -0
- package/dist/src/agents/memory-manager-agent.js.map +1 -0
- package/dist/src/agents/memory-manager-agent.test.d.ts +6 -0
- package/dist/src/agents/memory-manager-agent.test.js +117 -0
- package/dist/src/agents/memory-manager-agent.test.js.map +1 -0
- package/dist/src/agents/registry.js +21 -3
- package/dist/src/agents/registry.js.map +1 -1
- package/dist/src/agents/registry.test.js +23 -24
- package/dist/src/agents/registry.test.js.map +1 -1
- package/dist/src/agents/remote-invocation.d.ts +3 -1
- package/dist/src/agents/remote-invocation.js +10 -5
- package/dist/src/agents/remote-invocation.js.map +1 -1
- package/dist/src/agents/remote-invocation.test.js +64 -41
- package/dist/src/agents/remote-invocation.test.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.js +1 -1
- package/dist/src/agents/subagent-tool-wrapper.js.map +1 -1
- package/dist/src/agents/types.d.ts +12 -0
- package/dist/src/agents/types.js +14 -0
- package/dist/src/agents/types.js.map +1 -1
- package/dist/src/availability/policyHelpers.js +41 -1
- package/dist/src/availability/policyHelpers.js.map +1 -1
- package/dist/src/availability/policyHelpers.test.js +47 -0
- package/dist/src/availability/policyHelpers.test.js.map +1 -1
- package/dist/src/code_assist/admin/admin_controls.js +11 -0
- package/dist/src/code_assist/admin/admin_controls.js.map +1 -1
- package/dist/src/code_assist/admin/admin_controls.test.js +68 -0
- package/dist/src/code_assist/admin/admin_controls.test.js.map +1 -1
- package/dist/src/code_assist/admin/mcpUtils.d.ts +16 -1
- package/dist/src/code_assist/admin/mcpUtils.js +43 -0
- package/dist/src/code_assist/admin/mcpUtils.js.map +1 -1
- package/dist/src/code_assist/admin/mcpUtils.test.js +130 -1
- package/dist/src/code_assist/admin/mcpUtils.test.js.map +1 -1
- package/dist/src/code_assist/types.d.ts +458 -0
- package/dist/src/code_assist/types.js +26 -0
- package/dist/src/code_assist/types.js.map +1 -1
- package/dist/src/config/agent-loop-context.d.ts +6 -0
- package/dist/src/config/config.d.ts +41 -10
- package/dist/src/config/config.js +96 -19
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +29 -1
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/defaultModelConfigs.js +265 -9
- package/dist/src/config/defaultModelConfigs.js.map +1 -1
- package/dist/src/config/models.d.ts +13 -2
- package/dist/src/config/models.js +31 -3
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/config/models.test.js +52 -7
- package/dist/src/config/models.test.js.map +1 -1
- package/dist/src/config/path-validation.test.d.ts +6 -0
- package/dist/src/config/path-validation.test.js +59 -0
- package/dist/src/config/path-validation.test.js.map +1 -0
- package/dist/src/core/client.d.ts +1 -0
- package/dist/src/core/client.js +6 -1
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +9 -1
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.js +36 -6
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +97 -3
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/geminiChat.js +2 -2
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/prompts.test.js +10 -0
- 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/generated/git-commit.js.map +1 -1
- package/dist/src/ide/ide-connection-utils.js +2 -7
- package/dist/src/ide/ide-connection-utils.js.map +1 -1
- package/dist/src/ide/ide-connection-utils.test.js +7 -0
- package/dist/src/ide/ide-connection-utils.test.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/policy/config.js +2 -0
- package/dist/src/policy/config.js.map +1 -1
- package/dist/src/policy/config.test.js +15 -0
- package/dist/src/policy/config.test.js.map +1 -1
- package/dist/src/policy/memory-manager-policy.test.d.ts +6 -0
- package/dist/src/policy/memory-manager-policy.test.js +80 -0
- package/dist/src/policy/memory-manager-policy.test.js.map +1 -0
- package/dist/src/policy/policies/memory-manager.toml +10 -0
- package/dist/src/policy/policies/plan.toml +14 -0
- package/dist/src/policy/policies/yolo.toml +1 -0
- package/dist/src/policy/policy-engine.js +33 -6
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/policy/policy-engine.test.js +85 -3
- package/dist/src/policy/policy-engine.test.js.map +1 -1
- package/dist/src/policy/policy-updater.test.js +44 -0
- package/dist/src/policy/policy-updater.test.js.map +1 -1
- package/dist/src/policy/toml-loader.js +2 -0
- package/dist/src/policy/toml-loader.js.map +1 -1
- package/dist/src/policy/types.d.ts +11 -0
- package/dist/src/policy/types.js +5 -0
- package/dist/src/policy/types.js.map +1 -1
- package/dist/src/prompts/promptProvider.js +5 -3
- package/dist/src/prompts/promptProvider.js.map +1 -1
- package/dist/src/prompts/promptProvider.test.js +1 -0
- package/dist/src/prompts/promptProvider.test.js.map +1 -1
- package/dist/src/prompts/snippets-memory-manager.test.d.ts +6 -0
- package/dist/src/prompts/snippets-memory-manager.test.js +31 -0
- package/dist/src/prompts/snippets-memory-manager.test.js.map +1 -0
- package/dist/src/prompts/snippets.d.ts +2 -0
- package/dist/src/prompts/snippets.js +7 -3
- package/dist/src/prompts/snippets.js.map +1 -1
- package/dist/src/prompts/snippets.legacy.d.ts +5 -0
- package/dist/src/prompts/snippets.legacy.js +30 -2
- package/dist/src/prompts/snippets.legacy.js.map +1 -1
- package/dist/src/routing/strategies/classifierStrategy.js +1 -1
- package/dist/src/routing/strategies/classifierStrategy.js.map +1 -1
- package/dist/src/routing/strategies/defaultStrategy.js +1 -1
- package/dist/src/routing/strategies/defaultStrategy.js.map +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.js +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.js +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.js.map +1 -1
- package/dist/src/routing/strategies/overrideStrategy.js +1 -1
- package/dist/src/routing/strategies/overrideStrategy.js.map +1 -1
- package/dist/src/sandbox/macos/MacOsSandboxManager.d.ts +28 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.integration.test.d.ts +1 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.integration.test.js +160 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.integration.test.js.map +1 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.js +33 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.js.map +1 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.test.d.ts +1 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.test.js +87 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.test.js.map +1 -0
- package/dist/src/sandbox/macos/baseProfile.d.ts +20 -0
- package/dist/src/sandbox/macos/baseProfile.js +93 -0
- package/dist/src/sandbox/macos/baseProfile.js.map +1 -0
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.d.ts +25 -0
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.js +58 -0
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.js.map +1 -0
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.d.ts +1 -0
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js +80 -0
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js.map +1 -0
- package/dist/src/scheduler/scheduler.js +2 -0
- package/dist/src/scheduler/scheduler.js.map +1 -1
- package/dist/src/services/contextManager.js +2 -3
- package/dist/src/services/contextManager.js.map +1 -1
- package/dist/src/services/contextManager.test.js +1 -1
- package/dist/src/services/contextManager.test.js.map +1 -1
- package/dist/src/services/modelConfigService.d.ts +36 -1
- package/dist/src/services/modelConfigService.js +66 -0
- package/dist/src/services/modelConfigService.js.map +1 -1
- package/dist/src/services/sandboxManager.d.ts +3 -4
- package/dist/src/services/sandboxManager.js +1 -14
- package/dist/src/services/sandboxManager.js.map +1 -1
- package/dist/src/services/sandboxManager.test.js +13 -16
- package/dist/src/services/sandboxManager.test.js.map +1 -1
- package/dist/src/services/sandboxManagerFactory.d.ts +11 -0
- package/dist/src/services/sandboxManagerFactory.js +31 -0
- package/dist/src/services/sandboxManagerFactory.js.map +1 -0
- package/dist/src/services/sandboxedFileSystemService.d.ts +17 -0
- package/dist/src/services/sandboxedFileSystemService.js +95 -0
- package/dist/src/services/sandboxedFileSystemService.js.map +1 -0
- package/dist/src/services/sandboxedFileSystemService.test.d.ts +6 -0
- package/dist/src/services/sandboxedFileSystemService.test.js +87 -0
- package/dist/src/services/sandboxedFileSystemService.test.js.map +1 -0
- package/dist/src/services/scripts/GeminiSandbox.cs +370 -0
- package/dist/src/services/shellExecutionService.d.ts +2 -0
- package/dist/src/services/shellExecutionService.js +79 -75
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/trackerTypes.d.ts +1 -0
- package/dist/src/services/trackerTypes.js +1 -0
- package/dist/src/services/trackerTypes.js.map +1 -1
- package/dist/src/services/windowsSandboxManager.d.ts +27 -0
- package/dist/src/services/windowsSandboxManager.js +148 -0
- package/dist/src/services/windowsSandboxManager.js.map +1 -0
- package/dist/src/services/windowsSandboxManager.test.d.ts +6 -0
- package/dist/src/services/windowsSandboxManager.test.js +59 -0
- package/dist/src/services/windowsSandboxManager.test.js.map +1 -0
- package/dist/src/services/worktreeService.d.ts +33 -0
- package/dist/src/services/worktreeService.js +174 -0
- package/dist/src/services/worktreeService.js.map +1 -0
- package/dist/src/services/worktreeService.test.d.ts +6 -0
- package/dist/src/services/worktreeService.test.js +200 -0
- package/dist/src/services/worktreeService.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +4 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +1 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +2 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +62 -40
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +1 -0
- package/dist/src/telemetry/types.js +3 -0
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/tools/definitions/model-family-sets/default-legacy.js +8 -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 +8 -1
- package/dist/src/tools/definitions/model-family-sets/gemini-3.js.map +1 -1
- package/dist/src/tools/exit-plan-mode.d.ts +6 -1
- package/dist/src/tools/exit-plan-mode.js +17 -6
- package/dist/src/tools/exit-plan-mode.js.map +1 -1
- package/dist/src/tools/exit-plan-mode.test.js +22 -1
- package/dist/src/tools/exit-plan-mode.test.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.d.ts +22 -3
- package/dist/src/tools/mcp-client-manager.js +84 -32
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.test.js +76 -56
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +15 -6
- package/dist/src/tools/mcp-client.js +85 -71
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +195 -88
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +2 -1
- package/dist/src/tools/tool-registry.js +12 -1
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +15 -0
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +1 -1
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/trackerTools.js +6 -1
- package/dist/src/tools/trackerTools.js.map +1 -1
- package/dist/src/tools/trackerTools.test.js +9 -1
- package/dist/src/tools/trackerTools.test.js.map +1 -1
- package/dist/src/tools/write-todos.js +1 -0
- package/dist/src/tools/write-todos.js.map +1 -1
- package/dist/src/tools/write-todos.test.js +4 -1
- package/dist/src/tools/write-todos.test.js.map +1 -1
- package/dist/src/utils/agent-sanitization-utils.d.ts +23 -0
- package/dist/src/utils/agent-sanitization-utils.js +123 -0
- package/dist/src/utils/agent-sanitization-utils.js.map +1 -0
- package/dist/src/utils/agent-sanitization-utils.test.d.ts +6 -0
- package/dist/src/utils/agent-sanitization-utils.test.js +83 -0
- package/dist/src/utils/agent-sanitization-utils.test.js.map +1 -0
- package/dist/src/utils/browserConsent.d.ts +17 -0
- package/dist/src/utils/browserConsent.js +78 -0
- package/dist/src/utils/browserConsent.js.map +1 -0
- package/dist/src/utils/browserConsent.test.d.ts +6 -0
- package/dist/src/utils/browserConsent.test.js +93 -0
- package/dist/src/utils/browserConsent.test.js.map +1 -0
- package/dist/src/utils/compatibility.d.ts +16 -0
- package/dist/src/utils/compatibility.js +58 -9
- package/dist/src/utils/compatibility.js.map +1 -1
- package/dist/src/utils/compatibility.test.js +127 -29
- package/dist/src/utils/compatibility.test.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.d.ts +2 -2
- package/dist/src/utils/memoryDiscovery.js +5 -10
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +37 -37
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.js +5 -5
- package/dist/src/utils/memoryImportProcessor.js.map +1 -1
- package/dist/src/utils/surface.js +4 -3
- package/dist/src/utils/surface.js.map +1 -1
- package/dist/src/utils/toolCallContext.d.ts +2 -0
- package/dist/src/utils/toolCallContext.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import { sanitizeErrorMessage, sanitizeToolArgs, sanitizeThoughtContent, } from './agent-sanitization-utils.js';
|
|
8
|
+
describe('agent-sanitization-utils', () => {
|
|
9
|
+
describe('sanitizeErrorMessage', () => {
|
|
10
|
+
it('should redact standard inline PEM content', () => {
|
|
11
|
+
const input = 'Here is my key: -----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA12345\n-----END RSA PRIVATE KEY----- do not share.';
|
|
12
|
+
const expected = 'Here is my key: [REDACTED_PEM] do not share.';
|
|
13
|
+
expect(sanitizeErrorMessage(input)).toBe(expected);
|
|
14
|
+
});
|
|
15
|
+
it('should redact non-standard inline PEM content (with punctuation)', () => {
|
|
16
|
+
const input = '-----BEGIN X.509 CERTIFICATE-----\nMIIEowIBAAKCAQEA12345\n-----END X.509 CERTIFICATE-----';
|
|
17
|
+
const expected = '[REDACTED_PEM]';
|
|
18
|
+
expect(sanitizeErrorMessage(input)).toBe(expected);
|
|
19
|
+
});
|
|
20
|
+
it('should not hang on ReDoS attack string for PEM redaction', () => {
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
// A string that starts with -----BEGIN but has no ending, with many spaces
|
|
23
|
+
// In the vulnerable regex, this would cause catastrophic backtracking.
|
|
24
|
+
const maliciousInput = '-----BEGIN ' + ' '.repeat(50000) + 'A';
|
|
25
|
+
const result = sanitizeErrorMessage(maliciousInput);
|
|
26
|
+
const duration = Date.now() - start;
|
|
27
|
+
// Should process very quickly (e.g. < 50ms)
|
|
28
|
+
expect(duration).toBeLessThan(50);
|
|
29
|
+
// Since it doesn't match the full PEM block pattern, it should return the input unaltered
|
|
30
|
+
expect(result).toBe(maliciousInput);
|
|
31
|
+
});
|
|
32
|
+
it('should redact key-value pairs with sensitive keys', () => {
|
|
33
|
+
const input = 'Error: connection failed. --api-key="secret123"';
|
|
34
|
+
const result = sanitizeErrorMessage(input);
|
|
35
|
+
expect(result).toContain('[REDACTED]');
|
|
36
|
+
expect(result).not.toContain('secret123');
|
|
37
|
+
});
|
|
38
|
+
it('should redact space-separated sensitive keywords', () => {
|
|
39
|
+
// The keyword regex requires tokens to be 8+ chars
|
|
40
|
+
const input = 'Using password mySuperSecretPassword123';
|
|
41
|
+
const result = sanitizeErrorMessage(input);
|
|
42
|
+
expect(result).toContain('[REDACTED]');
|
|
43
|
+
expect(result).not.toContain('mySuperSecretPassword123');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('sanitizeToolArgs', () => {
|
|
47
|
+
it('should redact sensitive fields in an object', () => {
|
|
48
|
+
const input = {
|
|
49
|
+
username: 'admin',
|
|
50
|
+
password: 'superSecretPassword',
|
|
51
|
+
nested: {
|
|
52
|
+
api_key: 'abc123xyz',
|
|
53
|
+
normal_field: 'hello',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const result = sanitizeToolArgs(input);
|
|
57
|
+
expect(result).toEqual({
|
|
58
|
+
username: 'admin',
|
|
59
|
+
password: '[REDACTED]',
|
|
60
|
+
nested: {
|
|
61
|
+
api_key: '[REDACTED]',
|
|
62
|
+
normal_field: 'hello',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
it('should handle arrays and strings correctly', () => {
|
|
67
|
+
const input = ['normal string', '--api-key="secret123"'];
|
|
68
|
+
const result = sanitizeToolArgs(input);
|
|
69
|
+
expect(result[0]).toBe('normal string');
|
|
70
|
+
expect(result[1]).toContain('[REDACTED]');
|
|
71
|
+
expect(result[1]).not.toContain('secret123');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('sanitizeThoughtContent', () => {
|
|
75
|
+
it('should redact sensitive patterns from thought content', () => {
|
|
76
|
+
const input = 'I will now authenticate using token 1234567890abcdef.';
|
|
77
|
+
const result = sanitizeThoughtContent(input);
|
|
78
|
+
expect(result).toContain('[REDACTED]');
|
|
79
|
+
expect(result).not.toContain('1234567890abcdef');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=agent-sanitization-utils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-sanitization-utils.test.js","sourceRoot":"","sources":["../../../src/utils/agent-sanitization-utils.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Ensures the user has acknowledged the browser agent privacy notice.
|
|
8
|
+
*
|
|
9
|
+
* On first invocation (per profile), an interactive consent dialog is shown
|
|
10
|
+
* describing chrome-devtools-mcp's data collection and the fact that browser
|
|
11
|
+
* content is exposed to the AI model. A sentinel file is written to the
|
|
12
|
+
* browser profile directory once the user accepts.
|
|
13
|
+
*
|
|
14
|
+
* @returns `true` if consent was already given or the user accepted,
|
|
15
|
+
* `false` if the user declined.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getBrowserConsentIfNeeded(): Promise<boolean>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { CoreEvent, coreEvents } from './events.js';
|
|
7
|
+
import { Storage } from '../config/storage.js';
|
|
8
|
+
import * as fs from 'node:fs/promises';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
/** Sentinel file written after the user acknowledges the browser privacy notice. */
|
|
11
|
+
const BROWSER_CONSENT_FLAG_FILE = 'browser-consent-acknowledged.txt';
|
|
12
|
+
/** Default browser profile directory name within ~/.gemini/ */
|
|
13
|
+
const BROWSER_PROFILE_DIR = 'cli-browser-profile';
|
|
14
|
+
/**
|
|
15
|
+
* Ensures the user has acknowledged the browser agent privacy notice.
|
|
16
|
+
*
|
|
17
|
+
* On first invocation (per profile), an interactive consent dialog is shown
|
|
18
|
+
* describing chrome-devtools-mcp's data collection and the fact that browser
|
|
19
|
+
* content is exposed to the AI model. A sentinel file is written to the
|
|
20
|
+
* browser profile directory once the user accepts.
|
|
21
|
+
*
|
|
22
|
+
* @returns `true` if consent was already given or the user accepted,
|
|
23
|
+
* `false` if the user declined.
|
|
24
|
+
*/
|
|
25
|
+
export async function getBrowserConsentIfNeeded() {
|
|
26
|
+
const consentFilePath = path.join(Storage.getGlobalGeminiDir(), BROWSER_PROFILE_DIR, BROWSER_CONSENT_FLAG_FILE);
|
|
27
|
+
// Fast path: consent already persisted.
|
|
28
|
+
try {
|
|
29
|
+
await fs.access(consentFilePath);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// File doesn't exist — need to request consent.
|
|
34
|
+
void 0;
|
|
35
|
+
}
|
|
36
|
+
// Non-interactive mode (no UI listeners): skip the dialog for this session
|
|
37
|
+
// only. Do NOT persist the sentinel file — an interactive user on the same
|
|
38
|
+
// machine should still see the consent dialog the first time they use the
|
|
39
|
+
// browser agent.
|
|
40
|
+
if (coreEvents.listenerCount(CoreEvent.ConsentRequest) === 0) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
const prompt = '🔒 Browser Agent Privacy Notice\n\n' +
|
|
44
|
+
'The Browser Agent uses chrome-devtools-mcp to control your browser. ' +
|
|
45
|
+
'Please note:\n\n' +
|
|
46
|
+
'• Chrome DevTools MCP collects usage statistics by default ' +
|
|
47
|
+
'(can be disabled via privacy settings)\n' +
|
|
48
|
+
'• Performance tools may send trace URLs to Google CrUX API\n' +
|
|
49
|
+
'• Browser content will be exposed to the AI model for analysis\n' +
|
|
50
|
+
'• All data is handled per the Google Privacy Policy ' +
|
|
51
|
+
'(https://policies.google.com/privacy)\n\n' +
|
|
52
|
+
'Do you understand and consent to proceed?';
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
coreEvents.emitConsentRequest({
|
|
55
|
+
prompt,
|
|
56
|
+
onConfirm: async (confirmed) => {
|
|
57
|
+
if (confirmed) {
|
|
58
|
+
await markConsentAsAcknowledged(consentFilePath);
|
|
59
|
+
}
|
|
60
|
+
resolve(confirmed);
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Persists a sentinel file so consent is not requested again.
|
|
67
|
+
*/
|
|
68
|
+
async function markConsentAsAcknowledged(consentFilePath) {
|
|
69
|
+
try {
|
|
70
|
+
await fs.mkdir(path.dirname(consentFilePath), { recursive: true });
|
|
71
|
+
await fs.writeFile(consentFilePath, `Browser privacy consent acknowledged at ${new Date().toISOString()}\n`);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Best-effort: if we can't persist, the dialog will appear again next time.
|
|
75
|
+
void 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=browserConsent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserConsent.js","sourceRoot":"","sources":["../../../src/utils/browserConsent.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,oFAAoF;AACpF,MAAM,yBAAyB,GAAG,kCAAkC,CAAC;AAErE,+DAA+D;AAC/D,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AAElD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB;IAC7C,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAC/B,OAAO,CAAC,kBAAkB,EAAE,EAC5B,mBAAmB,EACnB,yBAAyB,CAC1B,CAAC;IAEF,wCAAwC;IACxC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;QAChD,KAAK,CAAC,CAAC;IACT,CAAC;IAED,2EAA2E;IAC3E,2EAA2E;IAC3E,0EAA0E;IAC1E,iBAAiB;IACjB,IAAI,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GACV,qCAAqC;QACrC,sEAAsE;QACtE,kBAAkB;QAClB,6DAA6D;QAC7D,0CAA0C;QAC1C,8DAA8D;QAC9D,kEAAkE;QAClE,sDAAsD;QACtD,2CAA2C;QAC3C,2CAA2C,CAAC;IAE9C,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACtC,UAAU,CAAC,kBAAkB,CAAC;YAC5B,MAAM;YACN,SAAS,EAAE,KAAK,EAAE,SAAkB,EAAE,EAAE;gBACtC,IAAI,SAAS,EAAE,CAAC;oBACd,MAAM,yBAAyB,CAAC,eAAe,CAAC,CAAC;gBACnD,CAAC;gBACD,OAAO,CAAC,SAAS,CAAC,CAAC;YACrB,CAAC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,yBAAyB,CACtC,eAAuB;IAEvB,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,MAAM,EAAE,CAAC,SAAS,CAChB,eAAe,EACf,2CAA2C,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CACxE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,KAAK,CAAC,CAAC;IACT,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import * as fs from 'node:fs/promises';
|
|
8
|
+
import { coreEvents } from './events.js';
|
|
9
|
+
import { Storage } from '../config/storage.js';
|
|
10
|
+
// Mock fs/promises before importing the module under test
|
|
11
|
+
vi.mock('node:fs/promises', () => ({
|
|
12
|
+
access: vi.fn(),
|
|
13
|
+
mkdir: vi.fn().mockResolvedValue(undefined),
|
|
14
|
+
writeFile: vi.fn().mockResolvedValue(undefined),
|
|
15
|
+
}));
|
|
16
|
+
// Mock Storage to return a predictable directory
|
|
17
|
+
vi.mock('../config/storage.js', () => ({
|
|
18
|
+
Storage: {
|
|
19
|
+
getGlobalGeminiDir: vi.fn(),
|
|
20
|
+
},
|
|
21
|
+
}));
|
|
22
|
+
import { getBrowserConsentIfNeeded } from './browserConsent.js';
|
|
23
|
+
describe('browserConsent', () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.resetAllMocks();
|
|
26
|
+
vi.mocked(Storage.getGlobalGeminiDir).mockReturnValue('/mock/.gemini');
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
vi.restoreAllMocks();
|
|
30
|
+
});
|
|
31
|
+
it('should return true if consent file already exists', async () => {
|
|
32
|
+
// Consent file exists — fs.access resolves
|
|
33
|
+
vi.mocked(fs.access).mockResolvedValue(undefined);
|
|
34
|
+
const result = await getBrowserConsentIfNeeded();
|
|
35
|
+
expect(result).toBe(true);
|
|
36
|
+
// Should not emit a consent request
|
|
37
|
+
const emitSpy = vi.spyOn(coreEvents, 'emitConsentRequest');
|
|
38
|
+
expect(emitSpy).not.toHaveBeenCalled();
|
|
39
|
+
});
|
|
40
|
+
it('should auto-accept in non-interactive mode (no listeners) without persisting consent', async () => {
|
|
41
|
+
// Consent file does not exist
|
|
42
|
+
vi.mocked(fs.access).mockRejectedValue(new Error('ENOENT'));
|
|
43
|
+
// No listeners registered
|
|
44
|
+
vi.spyOn(coreEvents, 'listenerCount').mockReturnValue(0);
|
|
45
|
+
const result = await getBrowserConsentIfNeeded();
|
|
46
|
+
expect(result).toBe(true);
|
|
47
|
+
// Should NOT persist the consent — an interactive user on the same machine
|
|
48
|
+
// must still see the dialog the first time they use the browser agent.
|
|
49
|
+
expect(fs.writeFile).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
it('should request consent interactively and return true when accepted', async () => {
|
|
52
|
+
// Consent file does not exist
|
|
53
|
+
vi.mocked(fs.access).mockRejectedValue(new Error('ENOENT'));
|
|
54
|
+
// Simulate interactive mode: there is at least one listener
|
|
55
|
+
vi.spyOn(coreEvents, 'listenerCount').mockReturnValue(1);
|
|
56
|
+
// Mock emitConsentRequest to auto-confirm
|
|
57
|
+
vi.spyOn(coreEvents, 'emitConsentRequest').mockImplementation((payload) => {
|
|
58
|
+
payload.onConfirm(true);
|
|
59
|
+
});
|
|
60
|
+
const result = await getBrowserConsentIfNeeded();
|
|
61
|
+
expect(result).toBe(true);
|
|
62
|
+
expect(coreEvents.emitConsentRequest).toHaveBeenCalledWith(expect.objectContaining({
|
|
63
|
+
prompt: expect.stringContaining('Privacy Notice'),
|
|
64
|
+
}));
|
|
65
|
+
expect(fs.writeFile).toHaveBeenCalled();
|
|
66
|
+
});
|
|
67
|
+
it('should return false when user declines consent', async () => {
|
|
68
|
+
// Consent file does not exist
|
|
69
|
+
vi.mocked(fs.access).mockRejectedValue(new Error('ENOENT'));
|
|
70
|
+
// Simulate interactive mode
|
|
71
|
+
vi.spyOn(coreEvents, 'listenerCount').mockReturnValue(1);
|
|
72
|
+
// Mock emitConsentRequest to decline
|
|
73
|
+
vi.spyOn(coreEvents, 'emitConsentRequest').mockImplementation((payload) => {
|
|
74
|
+
payload.onConfirm(false);
|
|
75
|
+
});
|
|
76
|
+
const result = await getBrowserConsentIfNeeded();
|
|
77
|
+
expect(result).toBe(false);
|
|
78
|
+
// Should NOT persist consent
|
|
79
|
+
expect(fs.writeFile).not.toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
it('should include privacy policy link in the prompt', async () => {
|
|
82
|
+
vi.mocked(fs.access).mockRejectedValue(new Error('ENOENT'));
|
|
83
|
+
vi.spyOn(coreEvents, 'listenerCount').mockReturnValue(1);
|
|
84
|
+
vi.spyOn(coreEvents, 'emitConsentRequest').mockImplementation((payload) => {
|
|
85
|
+
payload.onConfirm(true);
|
|
86
|
+
});
|
|
87
|
+
await getBrowserConsentIfNeeded();
|
|
88
|
+
expect(coreEvents.emitConsentRequest).toHaveBeenCalledWith(expect.objectContaining({
|
|
89
|
+
prompt: expect.stringContaining('policies.google.com/privacy'),
|
|
90
|
+
}));
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=browserConsent.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserConsent.test.js","sourceRoot":"","sources":["../../../src/utils/browserConsent.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,22 @@ export declare function isWindows10(): boolean;
|
|
|
12
12
|
* Detects if the current terminal is a JetBrains-based IDE terminal.
|
|
13
13
|
*/
|
|
14
14
|
export declare function isJetBrainsTerminal(): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Detects if the current terminal is running inside tmux.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isTmux(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Detects if the current terminal is running inside GNU screen.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isGnuScreen(): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Detects if the terminal is low-color mode (TERM=screen* with no COLORTERM).
|
|
25
|
+
*/
|
|
26
|
+
export declare function isLowColorTmux(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Detects if the terminal is a "dumb" terminal.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isDumbTerminal(): boolean;
|
|
15
31
|
/**
|
|
16
32
|
* Detects if the current terminal is the default Apple Terminal.app.
|
|
17
33
|
*/
|
|
@@ -24,7 +24,34 @@ export function isWindows10() {
|
|
|
24
24
|
* Detects if the current terminal is a JetBrains-based IDE terminal.
|
|
25
25
|
*/
|
|
26
26
|
export function isJetBrainsTerminal() {
|
|
27
|
-
|
|
27
|
+
const env = process.env;
|
|
28
|
+
return !!(env['TERMINAL_EMULATOR']?.startsWith('JetBrains') || env['JETBRAINS_IDE']);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Detects if the current terminal is running inside tmux.
|
|
32
|
+
*/
|
|
33
|
+
export function isTmux() {
|
|
34
|
+
return !!process.env['TMUX'];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Detects if the current terminal is running inside GNU screen.
|
|
38
|
+
*/
|
|
39
|
+
export function isGnuScreen() {
|
|
40
|
+
return !!process.env['STY'];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Detects if the terminal is low-color mode (TERM=screen* with no COLORTERM).
|
|
44
|
+
*/
|
|
45
|
+
export function isLowColorTmux() {
|
|
46
|
+
const term = process.env['TERM'] || '';
|
|
47
|
+
return isTmux() && term.startsWith('screen') && !process.env['COLORTERM'];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Detects if the terminal is a "dumb" terminal.
|
|
51
|
+
*/
|
|
52
|
+
export function isDumbTerminal() {
|
|
53
|
+
const term = process.env['TERM'] || '';
|
|
54
|
+
return term === 'dumb' || term === 'vt100';
|
|
28
55
|
}
|
|
29
56
|
/**
|
|
30
57
|
* Detects if the current terminal is the default Apple Terminal.app.
|
|
@@ -80,16 +107,38 @@ export function getCompatibilityWarnings(options) {
|
|
|
80
107
|
});
|
|
81
108
|
}
|
|
82
109
|
if (isJetBrainsTerminal() && options?.isAlternateBuffer) {
|
|
83
|
-
const platformTerminals = {
|
|
84
|
-
win32: 'Windows Terminal',
|
|
85
|
-
darwin: 'iTerm2 or Ghostty',
|
|
86
|
-
linux: 'Ghostty',
|
|
87
|
-
};
|
|
88
|
-
const suggestion = platformTerminals[os.platform()];
|
|
89
|
-
const suggestedTerminals = suggestion ? ` (e.g., ${suggestion})` : '';
|
|
90
110
|
warnings.push({
|
|
91
111
|
id: 'jetbrains-terminal',
|
|
92
|
-
message:
|
|
112
|
+
message: 'Warning: JetBrains terminal detected — alternate buffer mode may cause scroll wheel issues and rendering artifacts. If you experience problems, disable it in /settings → "Use Alternate Screen Buffer".',
|
|
113
|
+
priority: WarningPriority.High,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (isTmux() && options?.isAlternateBuffer) {
|
|
117
|
+
warnings.push({
|
|
118
|
+
id: 'tmux-alternate-buffer',
|
|
119
|
+
message: 'Warning: tmux detected — alternate buffer mode may cause unexpected scrollback loss and flickering. If you experience issues, disable it in /settings → "Use Alternate Screen Buffer".\n Tip: Use Ctrl-b [ to access tmux copy mode for scrolling history.',
|
|
120
|
+
priority: WarningPriority.High,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (isLowColorTmux()) {
|
|
124
|
+
warnings.push({
|
|
125
|
+
id: 'low-color-tmux',
|
|
126
|
+
message: 'Warning: Limited color support detected (TERM=screen). Some visual elements may not render correctly. For better color support in tmux, add to ~/.tmux.conf:\n set -g default-terminal "tmux-256color"\n set -ga terminal-overrides ",*256col*:Tc"',
|
|
127
|
+
priority: WarningPriority.High,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (isGnuScreen()) {
|
|
131
|
+
warnings.push({
|
|
132
|
+
id: 'gnu-screen',
|
|
133
|
+
message: 'Warning: GNU screen detected. Some keyboard shortcuts and visual features may behave unexpectedly. For the best experience, consider using tmux or running Gemini CLI directly in your terminal.',
|
|
134
|
+
priority: WarningPriority.Low,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (isDumbTerminal()) {
|
|
138
|
+
const term = process.env['TERM'] || 'dumb';
|
|
139
|
+
warnings.push({
|
|
140
|
+
id: 'dumb-terminal',
|
|
141
|
+
message: `Warning: Basic terminal detected (TERM=${term}). Visual rendering will be limited. For the best experience, use a terminal emulator with truecolor support.`,
|
|
93
142
|
priority: WarningPriority.High,
|
|
94
143
|
});
|
|
95
144
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../../../src/utils/compatibility.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,OAAO,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../../../src/utils/compatibility.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
7
7
|
import os from 'node:os';
|
|
8
|
-
import { isWindows10, isJetBrainsTerminal, supports256Colors, supportsTrueColor, getCompatibilityWarnings, WarningPriority, } from './compatibility.js';
|
|
8
|
+
import { isWindows10, isJetBrainsTerminal, isTmux, isGnuScreen, isLowColorTmux, isDumbTerminal, supports256Colors, supportsTrueColor, getCompatibilityWarnings, WarningPriority, } from './compatibility.js';
|
|
9
9
|
vi.mock('node:os', () => ({
|
|
10
10
|
default: {
|
|
11
11
|
platform: vi.fn(),
|
|
@@ -46,19 +46,89 @@ describe('compatibility', () => {
|
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
48
|
describe('isJetBrainsTerminal', () => {
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
vi.stubEnv('TERMINAL_EMULATOR', '');
|
|
51
|
+
vi.stubEnv('JETBRAINS_IDE', '');
|
|
52
|
+
});
|
|
49
53
|
it.each([
|
|
50
54
|
{
|
|
51
|
-
env: 'JetBrains-JediTerm',
|
|
55
|
+
env: { TERMINAL_EMULATOR: 'JetBrains-JediTerm' },
|
|
52
56
|
expected: true,
|
|
53
|
-
desc: 'TERMINAL_EMULATOR
|
|
57
|
+
desc: 'TERMINAL_EMULATOR starts with JetBrains',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
env: { JETBRAINS_IDE: 'IntelliJ' },
|
|
61
|
+
expected: true,
|
|
62
|
+
desc: 'JETBRAINS_IDE is set',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
env: { TERMINAL_EMULATOR: 'xterm' },
|
|
66
|
+
expected: false,
|
|
67
|
+
desc: 'other terminals',
|
|
54
68
|
},
|
|
55
|
-
{ env:
|
|
56
|
-
{ env: '', expected: false, desc: 'TERMINAL_EMULATOR is not set' },
|
|
69
|
+
{ env: {}, expected: false, desc: 'no env vars set' },
|
|
57
70
|
])('should return $expected when $desc', ({ env, expected }) => {
|
|
58
|
-
vi.stubEnv('TERMINAL_EMULATOR',
|
|
71
|
+
vi.stubEnv('TERMINAL_EMULATOR', '');
|
|
72
|
+
vi.stubEnv('JETBRAINS_IDE', '');
|
|
73
|
+
for (const [key, value] of Object.entries(env)) {
|
|
74
|
+
vi.stubEnv(key, value);
|
|
75
|
+
}
|
|
59
76
|
expect(isJetBrainsTerminal()).toBe(expected);
|
|
60
77
|
});
|
|
61
78
|
});
|
|
79
|
+
describe('isTmux', () => {
|
|
80
|
+
it('should return true when TMUX is set', () => {
|
|
81
|
+
vi.stubEnv('TMUX', '/tmp/tmux-1001/default,1425,0');
|
|
82
|
+
expect(isTmux()).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
it('should return false when TMUX is not set', () => {
|
|
85
|
+
vi.stubEnv('TMUX', '');
|
|
86
|
+
expect(isTmux()).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('isGnuScreen', () => {
|
|
90
|
+
it('should return true when STY is set', () => {
|
|
91
|
+
vi.stubEnv('STY', '1234.pts-0.host');
|
|
92
|
+
expect(isGnuScreen()).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
it('should return false when STY is not set', () => {
|
|
95
|
+
vi.stubEnv('STY', '');
|
|
96
|
+
expect(isGnuScreen()).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('isLowColorTmux', () => {
|
|
100
|
+
it('should return true when TERM=screen and COLORTERM is not set', () => {
|
|
101
|
+
vi.stubEnv('TERM', 'screen');
|
|
102
|
+
vi.stubEnv('TMUX', '1');
|
|
103
|
+
vi.stubEnv('COLORTERM', '');
|
|
104
|
+
expect(isLowColorTmux()).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it('should return false when TERM=screen and COLORTERM is set', () => {
|
|
107
|
+
vi.stubEnv('TERM', 'screen');
|
|
108
|
+
vi.stubEnv('TMUX', '1');
|
|
109
|
+
vi.stubEnv('COLORTERM', 'truecolor');
|
|
110
|
+
expect(isLowColorTmux()).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
it('should return false when TERM=xterm-256color', () => {
|
|
113
|
+
vi.stubEnv('TERM', 'xterm-256color');
|
|
114
|
+
vi.stubEnv('COLORTERM', '');
|
|
115
|
+
expect(isLowColorTmux()).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe('isDumbTerminal', () => {
|
|
119
|
+
it('should return true when TERM=dumb', () => {
|
|
120
|
+
vi.stubEnv('TERM', 'dumb');
|
|
121
|
+
expect(isDumbTerminal()).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
it('should return true when TERM=vt100', () => {
|
|
124
|
+
vi.stubEnv('TERM', 'vt100');
|
|
125
|
+
expect(isDumbTerminal()).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
it('should return false when TERM=xterm', () => {
|
|
128
|
+
vi.stubEnv('TERM', 'xterm');
|
|
129
|
+
expect(isDumbTerminal()).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
62
132
|
describe('supports256Colors', () => {
|
|
63
133
|
it.each([
|
|
64
134
|
{
|
|
@@ -84,6 +154,9 @@ describe('compatibility', () => {
|
|
|
84
154
|
if (term !== undefined) {
|
|
85
155
|
vi.stubEnv('TERM', term);
|
|
86
156
|
}
|
|
157
|
+
else {
|
|
158
|
+
vi.stubEnv('TERM', '');
|
|
159
|
+
}
|
|
87
160
|
expect(supports256Colors()).toBe(expected);
|
|
88
161
|
});
|
|
89
162
|
});
|
|
@@ -121,6 +194,13 @@ describe('compatibility', () => {
|
|
|
121
194
|
});
|
|
122
195
|
describe('getCompatibilityWarnings', () => {
|
|
123
196
|
beforeEach(() => {
|
|
197
|
+
// Clear out potential local environment variables that might trigger warnings
|
|
198
|
+
vi.stubEnv('TERMINAL_EMULATOR', '');
|
|
199
|
+
vi.stubEnv('JETBRAINS_IDE', '');
|
|
200
|
+
vi.stubEnv('TMUX', '');
|
|
201
|
+
vi.stubEnv('STY', '');
|
|
202
|
+
vi.stubEnv('TERM', 'xterm-256color'); // Prevent dumb terminal warning
|
|
203
|
+
vi.stubEnv('TERM_PROGRAM', '');
|
|
124
204
|
// Default to supporting true color to keep existing tests simple
|
|
125
205
|
vi.stubEnv('COLORTERM', 'truecolor');
|
|
126
206
|
process.stdout.getColorDepth = vi.fn().mockReturnValue(24);
|
|
@@ -135,33 +215,51 @@ describe('compatibility', () => {
|
|
|
135
215
|
message: expect.stringContaining('Windows 10 detected'),
|
|
136
216
|
}));
|
|
137
217
|
});
|
|
138
|
-
it
|
|
139
|
-
|
|
140
|
-
platform: 'darwin',
|
|
141
|
-
release: '20.6.0',
|
|
142
|
-
externalTerminal: 'iTerm2 or Ghostty',
|
|
143
|
-
desc: 'macOS',
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
platform: 'win32',
|
|
147
|
-
release: '10.0.22000',
|
|
148
|
-
externalTerminal: 'Windows Terminal',
|
|
149
|
-
desc: 'Windows',
|
|
150
|
-
}, // Valid Windows 11 release to not trigger the Windows 10 warning
|
|
151
|
-
{
|
|
152
|
-
platform: 'linux',
|
|
153
|
-
release: '5.10.0',
|
|
154
|
-
externalTerminal: 'Ghostty',
|
|
155
|
-
desc: 'Linux',
|
|
156
|
-
},
|
|
157
|
-
])('should return JetBrains warning when detected and in alternate buffer ($desc)', ({ platform, release, externalTerminal }) => {
|
|
158
|
-
vi.mocked(os.platform).mockReturnValue(platform);
|
|
159
|
-
vi.mocked(os.release).mockReturnValue(release);
|
|
218
|
+
it('should return JetBrains warning when detected and in alternate buffer', () => {
|
|
219
|
+
vi.mocked(os.platform).mockReturnValue('darwin');
|
|
160
220
|
vi.stubEnv('TERMINAL_EMULATOR', 'JetBrains-JediTerm');
|
|
161
221
|
const warnings = getCompatibilityWarnings({ isAlternateBuffer: true });
|
|
162
222
|
expect(warnings).toContainEqual(expect.objectContaining({
|
|
163
223
|
id: 'jetbrains-terminal',
|
|
164
|
-
message: expect.stringContaining(
|
|
224
|
+
message: expect.stringContaining('JetBrains terminal detected'),
|
|
225
|
+
priority: WarningPriority.High,
|
|
226
|
+
}));
|
|
227
|
+
});
|
|
228
|
+
it('should return tmux warning when detected and in alternate buffer', () => {
|
|
229
|
+
vi.stubEnv('TMUX', '/tmp/tmux-1001/default,1,0');
|
|
230
|
+
const warnings = getCompatibilityWarnings({ isAlternateBuffer: true });
|
|
231
|
+
expect(warnings).toContainEqual(expect.objectContaining({
|
|
232
|
+
id: 'tmux-alternate-buffer',
|
|
233
|
+
message: expect.stringContaining('tmux detected'),
|
|
234
|
+
priority: WarningPriority.High,
|
|
235
|
+
}));
|
|
236
|
+
});
|
|
237
|
+
it('should return low-color tmux warning when detected', () => {
|
|
238
|
+
vi.stubEnv('TERM', 'screen');
|
|
239
|
+
vi.stubEnv('TMUX', '1');
|
|
240
|
+
vi.stubEnv('COLORTERM', '');
|
|
241
|
+
const warnings = getCompatibilityWarnings();
|
|
242
|
+
expect(warnings).toContainEqual(expect.objectContaining({
|
|
243
|
+
id: 'low-color-tmux',
|
|
244
|
+
message: expect.stringContaining('Limited color support detected'),
|
|
245
|
+
priority: WarningPriority.High,
|
|
246
|
+
}));
|
|
247
|
+
});
|
|
248
|
+
it('should return GNU screen warning when detected', () => {
|
|
249
|
+
vi.stubEnv('STY', '1234.pts-0.host');
|
|
250
|
+
const warnings = getCompatibilityWarnings();
|
|
251
|
+
expect(warnings).toContainEqual(expect.objectContaining({
|
|
252
|
+
id: 'gnu-screen',
|
|
253
|
+
message: expect.stringContaining('GNU screen detected'),
|
|
254
|
+
priority: WarningPriority.Low,
|
|
255
|
+
}));
|
|
256
|
+
});
|
|
257
|
+
it.each(['dumb', 'vt100'])('should return dumb terminal warning when TERM=%s', (term) => {
|
|
258
|
+
vi.stubEnv('TERM', term);
|
|
259
|
+
const warnings = getCompatibilityWarnings();
|
|
260
|
+
expect(warnings).toContainEqual(expect.objectContaining({
|
|
261
|
+
id: 'dumb-terminal',
|
|
262
|
+
message: `Warning: Basic terminal detected (TERM=${term}). Visual rendering will be limited. For the best experience, use a terminal emulator with truecolor support.`,
|
|
165
263
|
priority: WarningPriority.High,
|
|
166
264
|
}));
|
|
167
265
|
});
|