@quantum-ai/gemini-cli 0.45.4 → 0.45.5
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 +394 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/package.json +12 -11
- package/dist/src/config/settingsSchema.d.ts +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/ui/App.d.ts +1 -1
- package/dist/src/ui/AppContainer.d.ts +1 -1
- package/dist/src/ui/IdeIntegrationNudge.d.ts +1 -1
- package/dist/src/ui/auth/LoginRestartDialog.d.ts +1 -1
- package/dist/src/ui/components/AdminSettingsChangedDialog.d.ts +1 -1
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.d.ts +1 -1
- package/dist/src/ui/components/AppHeader.d.ts +1 -1
- package/dist/src/ui/components/BackgroundTaskDisplay.d.ts +1 -1
- package/dist/src/ui/components/Banner.d.ts +1 -1
- package/dist/src/ui/components/CliSpinner.d.ts +1 -1
- package/dist/src/ui/components/Composer.d.ts +1 -1
- package/dist/src/ui/components/ConfigInitDisplay.d.ts +1 -1
- package/dist/src/ui/components/ConsentPrompt.d.ts +1 -1
- package/dist/src/ui/components/ContextUsageDisplay.d.ts +1 -1
- package/dist/src/ui/components/DebugProfiler.d.ts +1 -1
- package/dist/src/ui/components/DialogManager.d.ts +1 -1
- package/dist/src/ui/components/IdeTrustChangeDialog.d.ts +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.d.ts +1 -1
- package/dist/src/ui/components/MainContent.d.ts +1 -1
- package/dist/src/ui/components/ModelQuotaDisplay.d.ts +1 -1
- package/dist/src/ui/components/NewAgentsNotification.d.ts +1 -1
- package/dist/src/ui/components/Notifications.d.ts +1 -1
- package/dist/src/ui/components/QueuedMessageDisplay.d.ts +1 -1
- package/dist/src/ui/components/QuittingDisplay.d.ts +1 -1
- package/dist/src/ui/components/ShowMoreLines.d.ts +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.d.ts +1 -1
- package/dist/src/ui/components/Table.d.ts +1 -1
- package/dist/src/ui/components/UpdateNotification.d.ts +1 -1
- package/dist/src/ui/components/shared/SlicingMaxSizedBox.d.ts +1 -1
- package/dist/src/ui/components/triage/TriageDuplicates.d.ts +1 -1
- package/dist/src/ui/components/triage/TriageIssues.d.ts +1 -1
- package/dist/src/ui/contexts/KeypressContext.d.ts +1 -1
- package/dist/src/ui/contexts/MouseContext.d.ts +1 -1
- package/dist/src/ui/contexts/TerminalContext.d.ts +1 -1
- package/dist/src/ui/contexts/VimModeContext.d.ts +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +2 -2
- package/dist/src/ui/hooks/useInlineEditBuffer.d.ts +1 -1
- package/dist/src/ui/hooks/useStateAndRef.d.ts +1 -1
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.d.ts +1 -1
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.d.ts +1 -1
- package/dist/src/ui/privacy/GeminiPrivacyNotice.d.ts +1 -1
- package/dist/src/ui/privacy/PrivacyNotice.d.ts +1 -1
- package/dist/src/utils/devtoolsService.js +1 -1
- package/dist/src/utils/devtoolsService.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -11
- package/dist/src/acp/acpCommandHandler.test.d.ts +0 -6
- package/dist/src/acp/acpCommandHandler.test.js +0 -28
- package/dist/src/acp/acpCommandHandler.test.js.map +0 -1
- package/dist/src/acp/acpErrors.test.d.ts +0 -6
- package/dist/src/acp/acpErrors.test.js +0 -38
- package/dist/src/acp/acpErrors.test.js.map +0 -1
- package/dist/src/acp/acpFileSystemService.test.d.ts +0 -6
- package/dist/src/acp/acpFileSystemService.test.js +0 -162
- package/dist/src/acp/acpFileSystemService.test.js.map +0 -1
- package/dist/src/acp/acpResume.test.d.ts +0 -6
- package/dist/src/acp/acpResume.test.js +0 -260
- package/dist/src/acp/acpResume.test.js.map +0 -1
- package/dist/src/acp/acpRpcDispatcher.test.d.ts +0 -6
- package/dist/src/acp/acpRpcDispatcher.test.js +0 -238
- package/dist/src/acp/acpRpcDispatcher.test.js.map +0 -1
- package/dist/src/acp/acpSession.test.d.ts +0 -6
- package/dist/src/acp/acpSession.test.js +0 -742
- package/dist/src/acp/acpSession.test.js.map +0 -1
- package/dist/src/acp/acpSessionManager.test.d.ts +0 -6
- package/dist/src/acp/acpSessionManager.test.js +0 -283
- package/dist/src/acp/acpSessionManager.test.js.map +0 -1
- package/dist/src/acp/commands/extensions.test.d.ts +0 -6
- package/dist/src/acp/commands/extensions.test.js +0 -70
- package/dist/src/acp/commands/extensions.test.js.map +0 -1
- package/dist/src/acp/commands/help.test.d.ts +0 -6
- package/dist/src/acp/commands/help.test.js +0 -40
- package/dist/src/acp/commands/help.test.js.map +0 -1
- package/dist/src/acp/commands/restore.test.d.ts +0 -6
- package/dist/src/acp/commands/restore.test.js +0 -173
- package/dist/src/acp/commands/restore.test.js.map +0 -1
- package/dist/src/commands/extensions/configure.test.d.ts +0 -1
- package/dist/src/commands/extensions/configure.test.js +0 -195
- package/dist/src/commands/extensions/configure.test.js.map +0 -1
- package/dist/src/commands/extensions/disable.test.d.ts +0 -6
- package/dist/src/commands/extensions/disable.test.js +0 -169
- package/dist/src/commands/extensions/disable.test.js.map +0 -1
- package/dist/src/commands/extensions/enable.test.d.ts +0 -6
- package/dist/src/commands/extensions/enable.test.js +0 -199
- package/dist/src/commands/extensions/enable.test.js.map +0 -1
- package/dist/src/commands/extensions/install.test.d.ts +0 -6
- package/dist/src/commands/extensions/install.test.js +0 -311
- package/dist/src/commands/extensions/install.test.js.map +0 -1
- package/dist/src/commands/extensions/link.test.d.ts +0 -6
- package/dist/src/commands/extensions/link.test.js +0 -121
- package/dist/src/commands/extensions/link.test.js.map +0 -1
- package/dist/src/commands/extensions/list.test.d.ts +0 -6
- package/dist/src/commands/extensions/list.test.js +0 -132
- package/dist/src/commands/extensions/list.test.js.map +0 -1
- package/dist/src/commands/extensions/new.test.d.ts +0 -6
- package/dist/src/commands/extensions/new.test.js +0 -62
- package/dist/src/commands/extensions/new.test.js.map +0 -1
- package/dist/src/commands/extensions/uninstall.test.d.ts +0 -6
- package/dist/src/commands/extensions/uninstall.test.js +0 -240
- package/dist/src/commands/extensions/uninstall.test.js.map +0 -1
- package/dist/src/commands/extensions/update.test.d.ts +0 -6
- package/dist/src/commands/extensions/update.test.js +0 -196
- package/dist/src/commands/extensions/update.test.js.map +0 -1
- package/dist/src/commands/extensions/validate.test.d.ts +0 -6
- package/dist/src/commands/extensions/validate.test.js +0 -96
- package/dist/src/commands/extensions/validate.test.js.map +0 -1
- package/dist/src/commands/extensions.test.d.ts +0 -6
- package/dist/src/commands/extensions.test.js +0 -67
- package/dist/src/commands/extensions.test.js.map +0 -1
- package/dist/src/commands/gemma/logs.test.d.ts +0 -6
- package/dist/src/commands/gemma/logs.test.js +0 -122
- package/dist/src/commands/gemma/logs.test.js.map +0 -1
- package/dist/src/commands/gemma/platform.test.d.ts +0 -6
- package/dist/src/commands/gemma/platform.test.js +0 -108
- package/dist/src/commands/gemma/platform.test.js.map +0 -1
- package/dist/src/commands/gemma/setup.test.d.ts +0 -6
- package/dist/src/commands/gemma/setup.test.js +0 -36
- package/dist/src/commands/gemma/setup.test.js.map +0 -1
- package/dist/src/commands/gemma/stop.test.d.ts +0 -6
- package/dist/src/commands/gemma/stop.test.js +0 -89
- package/dist/src/commands/gemma/stop.test.js.map +0 -1
- package/dist/src/commands/hooks/migrate.test.d.ts +0 -6
- package/dist/src/commands/hooks/migrate.test.js +0 -388
- package/dist/src/commands/hooks/migrate.test.js.map +0 -1
- package/dist/src/commands/mcp/add.test.d.ts +0 -6
- package/dist/src/commands/mcp/add.test.js +0 -274
- package/dist/src/commands/mcp/add.test.js.map +0 -1
- package/dist/src/commands/mcp/list.test.d.ts +0 -6
- package/dist/src/commands/mcp/list.test.js +0 -477
- package/dist/src/commands/mcp/list.test.js.map +0 -1
- package/dist/src/commands/mcp/remove.test.d.ts +0 -6
- package/dist/src/commands/mcp/remove.test.js +0 -206
- package/dist/src/commands/mcp/remove.test.js.map +0 -1
- package/dist/src/commands/mcp.test.d.ts +0 -6
- package/dist/src/commands/mcp.test.js +0 -64
- package/dist/src/commands/mcp.test.js.map +0 -1
- package/dist/src/commands/skills/disable.test.d.ts +0 -6
- package/dist/src/commands/skills/disable.test.js +0 -93
- package/dist/src/commands/skills/disable.test.js.map +0 -1
- package/dist/src/commands/skills/enable.test.d.ts +0 -6
- package/dist/src/commands/skills/enable.test.js +0 -104
- package/dist/src/commands/skills/enable.test.js.map +0 -1
- package/dist/src/commands/skills/install.test.d.ts +0 -6
- package/dist/src/commands/skills/install.test.js +0 -99
- package/dist/src/commands/skills/install.test.js.map +0 -1
- package/dist/src/commands/skills/link.test.d.ts +0 -6
- package/dist/src/commands/skills/link.test.js +0 -53
- package/dist/src/commands/skills/link.test.js.map +0 -1
- package/dist/src/commands/skills/list.test.d.ts +0 -6
- package/dist/src/commands/skills/list.test.js +0 -127
- package/dist/src/commands/skills/list.test.js.map +0 -1
- package/dist/src/commands/skills/uninstall.test.d.ts +0 -6
- package/dist/src/commands/skills/uninstall.test.js +0 -65
- package/dist/src/commands/skills/uninstall.test.js.map +0 -1
- package/dist/src/commands/skills.test.d.ts +0 -6
- package/dist/src/commands/skills.test.js +0 -49
- package/dist/src/commands/skills.test.js.map +0 -1
- package/dist/src/commands/utils.test.d.ts +0 -6
- package/dist/src/commands/utils.test.js +0 -35
- package/dist/src/commands/utils.test.js.map +0 -1
- package/dist/src/config/auth.test.d.ts +0 -6
- package/dist/src/config/auth.test.js +0 -96
- package/dist/src/config/auth.test.js.map +0 -1
- package/dist/src/config/config.integration.test.d.ts +0 -6
- package/dist/src/config/config.integration.test.js +0 -205
- package/dist/src/config/config.integration.test.js.map +0 -1
- package/dist/src/config/config.test.d.ts +0 -6
- package/dist/src/config/config.test.js +0 -3124
- package/dist/src/config/config.test.js.map +0 -1
- package/dist/src/config/extension-manager-agents.test.d.ts +0 -6
- package/dist/src/config/extension-manager-agents.test.js +0 -116
- package/dist/src/config/extension-manager-agents.test.js.map +0 -1
- package/dist/src/config/extension-manager-hydration.test.d.ts +0 -6
- package/dist/src/config/extension-manager-hydration.test.js +0 -262
- package/dist/src/config/extension-manager-hydration.test.js.map +0 -1
- package/dist/src/config/extension-manager-permissions.test.d.ts +0 -6
- package/dist/src/config/extension-manager-permissions.test.js +0 -107
- package/dist/src/config/extension-manager-permissions.test.js.map +0 -1
- package/dist/src/config/extension-manager-scope.test.d.ts +0 -6
- package/dist/src/config/extension-manager-scope.test.js +0 -158
- package/dist/src/config/extension-manager-scope.test.js.map +0 -1
- package/dist/src/config/extension-manager-skills.test.d.ts +0 -6
- package/dist/src/config/extension-manager-skills.test.js +0 -157
- package/dist/src/config/extension-manager-skills.test.js.map +0 -1
- package/dist/src/config/extension-manager.test.d.ts +0 -6
- package/dist/src/config/extension-manager.test.js +0 -430
- package/dist/src/config/extension-manager.test.js.map +0 -1
- package/dist/src/config/extension.test.d.ts +0 -6
- package/dist/src/config/extension.test.js +0 -1800
- package/dist/src/config/extension.test.js.map +0 -1
- package/dist/src/config/extensionRegistryClient.test.d.ts +0 -6
- package/dist/src/config/extensionRegistryClient.test.js +0 -261
- package/dist/src/config/extensionRegistryClient.test.js.map +0 -1
- package/dist/src/config/extensions/consent.test.d.ts +0 -6
- package/dist/src/config/extensions/consent.test.js +0 -302
- package/dist/src/config/extensions/consent.test.js.map +0 -1
- package/dist/src/config/extensions/extensionEnablement.test.d.ts +0 -6
- package/dist/src/config/extensions/extensionEnablement.test.js +0 -404
- package/dist/src/config/extensions/extensionEnablement.test.js.map +0 -1
- package/dist/src/config/extensions/extensionSettings.test.d.ts +0 -6
- package/dist/src/config/extensions/extensionSettings.test.js +0 -575
- package/dist/src/config/extensions/extensionSettings.test.js.map +0 -1
- package/dist/src/config/extensions/extensionUpdates.test.d.ts +0 -6
- package/dist/src/config/extensions/extensionUpdates.test.js +0 -265
- package/dist/src/config/extensions/extensionUpdates.test.js.map +0 -1
- package/dist/src/config/extensions/github.test.d.ts +0 -6
- package/dist/src/config/extensions/github.test.js +0 -454
- package/dist/src/config/extensions/github.test.js.map +0 -1
- package/dist/src/config/extensions/github_fetch.test.d.ts +0 -6
- package/dist/src/config/extensions/github_fetch.test.js +0 -171
- package/dist/src/config/extensions/github_fetch.test.js.map +0 -1
- package/dist/src/config/extensions/storage.test.d.ts +0 -6
- package/dist/src/config/extensions/storage.test.js +0 -64
- package/dist/src/config/extensions/storage.test.js.map +0 -1
- package/dist/src/config/extensions/update.test.d.ts +0 -6
- package/dist/src/config/extensions/update.test.js +0 -296
- package/dist/src/config/extensions/update.test.js.map +0 -1
- package/dist/src/config/extensions/variables.test.d.ts +0 -6
- package/dist/src/config/extensions/variables.test.js +0 -119
- package/dist/src/config/extensions/variables.test.js.map +0 -1
- package/dist/src/config/footerItems.test.d.ts +0 -6
- package/dist/src/config/footerItems.test.js +0 -180
- package/dist/src/config/footerItems.test.js.map +0 -1
- package/dist/src/config/mcp/mcpServerEnablement.test.d.ts +0 -6
- package/dist/src/config/mcp/mcpServerEnablement.test.js +0 -148
- package/dist/src/config/mcp/mcpServerEnablement.test.js.map +0 -1
- package/dist/src/config/mutual-exclusivity.test.d.ts +0 -6
- package/dist/src/config/mutual-exclusivity.test.js +0 -33
- package/dist/src/config/mutual-exclusivity.test.js.map +0 -1
- package/dist/src/config/policy-engine.integration.test.d.ts +0 -6
- package/dist/src/config/policy-engine.integration.test.js +0 -394
- package/dist/src/config/policy-engine.integration.test.js.map +0 -1
- package/dist/src/config/policy.test.d.ts +0 -6
- package/dist/src/config/policy.test.js +0 -199
- package/dist/src/config/policy.test.js.map +0 -1
- package/dist/src/config/sandboxConfig.test.d.ts +0 -6
- package/dist/src/config/sandboxConfig.test.js +0 -401
- package/dist/src/config/sandboxConfig.test.js.map +0 -1
- package/dist/src/config/settingPaths.test.d.ts +0 -6
- package/dist/src/config/settingPaths.test.js +0 -22
- package/dist/src/config/settingPaths.test.js.map +0 -1
- package/dist/src/config/settings-env-isolation.test.d.ts +0 -6
- package/dist/src/config/settings-env-isolation.test.js +0 -188
- package/dist/src/config/settings-env-isolation.test.js.map +0 -1
- package/dist/src/config/settings-validation.test.d.ts +0 -6
- package/dist/src/config/settings-validation.test.js +0 -464
- package/dist/src/config/settings-validation.test.js.map +0 -1
- package/dist/src/config/settings.test.d.ts +0 -6
- package/dist/src/config/settings.test.js +0 -2660
- package/dist/src/config/settings.test.js.map +0 -1
- package/dist/src/config/settingsSchema.test.d.ts +0 -6
- package/dist/src/config/settingsSchema.test.js +0 -450
- package/dist/src/config/settingsSchema.test.js.map +0 -1
- package/dist/src/config/settings_repro.test.d.ts +0 -6
- package/dist/src/config/settings_repro.test.js +0 -163
- package/dist/src/config/settings_repro.test.js.map +0 -1
- package/dist/src/config/settings_validation_warning.test.d.ts +0 -6
- package/dist/src/config/settings_validation_warning.test.js +0 -124
- package/dist/src/config/settings_validation_warning.test.js.map +0 -1
- package/dist/src/config/skipExtensions.test.d.ts +0 -6
- package/dist/src/config/skipExtensions.test.js +0 -49
- package/dist/src/config/skipExtensions.test.js.map +0 -1
- package/dist/src/config/trustedFolders.test.d.ts +0 -6
- package/dist/src/config/trustedFolders.test.js +0 -411
- package/dist/src/config/trustedFolders.test.js.map +0 -1
- package/dist/src/config/workspace-policy-cli.test.d.ts +0 -6
- package/dist/src/config/workspace-policy-cli.test.js +0 -204
- package/dist/src/config/workspace-policy-cli.test.js.map +0 -1
- package/dist/src/core/auth.test.d.ts +0 -6
- package/dist/src/core/auth.test.js +0 -93
- package/dist/src/core/auth.test.js.map +0 -1
- package/dist/src/core/initializer.test.d.ts +0 -6
- package/dist/src/core/initializer.test.js +0 -111
- package/dist/src/core/initializer.test.js.map +0 -1
- package/dist/src/core/theme.test.d.ts +0 -6
- package/dist/src/core/theme.test.js +0 -46
- package/dist/src/core/theme.test.js.map +0 -1
- package/dist/src/deferred.test.d.ts +0 -6
- package/dist/src/deferred.test.js +0 -180
- package/dist/src/deferred.test.js.map +0 -1
- package/dist/src/gemini.test.d.ts +0 -6
- package/dist/src/gemini.test.js +0 -1432
- package/dist/src/gemini.test.js.map +0 -1
- package/dist/src/gemini_cleanup.test.d.ts +0 -6
- package/dist/src/gemini_cleanup.test.js +0 -391
- package/dist/src/gemini_cleanup.test.js.map +0 -1
- package/dist/src/integration-tests/modelSteering.test.d.ts +0 -6
- package/dist/src/integration-tests/modelSteering.test.js +0 -62
- package/dist/src/integration-tests/modelSteering.test.js.map +0 -1
- package/dist/src/nonInteractiveCli.test.d.ts +0 -6
- package/dist/src/nonInteractiveCli.test.js +0 -1921
- package/dist/src/nonInteractiveCli.test.js.map +0 -1
- package/dist/src/nonInteractiveCliAgentSession.test.d.ts +0 -6
- package/dist/src/nonInteractiveCliAgentSession.test.js +0 -2015
- package/dist/src/nonInteractiveCliAgentSession.test.js.map +0 -1
- package/dist/src/output-redirection.test.d.ts +0 -6
- package/dist/src/output-redirection.test.js +0 -77
- package/dist/src/output-redirection.test.js.map +0 -1
- package/dist/src/services/BuiltinCommandLoader.test.d.ts +0 -6
- package/dist/src/services/BuiltinCommandLoader.test.js +0 -369
- package/dist/src/services/BuiltinCommandLoader.test.js.map +0 -1
- package/dist/src/services/CommandService.test.d.ts +0 -6
- package/dist/src/services/CommandService.test.js +0 -74
- package/dist/src/services/CommandService.test.js.map +0 -1
- package/dist/src/services/FileCommandLoader.test.d.ts +0 -6
- package/dist/src/services/FileCommandLoader.test.js +0 -1128
- package/dist/src/services/FileCommandLoader.test.js.map +0 -1
- package/dist/src/services/McpPromptLoader.test.d.ts +0 -6
- package/dist/src/services/McpPromptLoader.test.js +0 -411
- package/dist/src/services/McpPromptLoader.test.js.map +0 -1
- package/dist/src/services/SkillCommandLoader.test.d.ts +0 -6
- package/dist/src/services/SkillCommandLoader.test.js +0 -113
- package/dist/src/services/SkillCommandLoader.test.js.map +0 -1
- package/dist/src/services/SlashCommandConflictHandler.test.d.ts +0 -6
- package/dist/src/services/SlashCommandConflictHandler.test.js +0 -144
- package/dist/src/services/SlashCommandConflictHandler.test.js.map +0 -1
- package/dist/src/services/SlashCommandResolver.test.d.ts +0 -6
- package/dist/src/services/SlashCommandResolver.test.js +0 -186
- package/dist/src/services/SlashCommandResolver.test.js.map +0 -1
- package/dist/src/services/liteRtServerManager.test.d.ts +0 -6
- package/dist/src/services/liteRtServerManager.test.js +0 -54
- package/dist/src/services/liteRtServerManager.test.js.map +0 -1
- package/dist/src/services/prompt-processors/argumentProcessor.test.d.ts +0 -6
- package/dist/src/services/prompt-processors/argumentProcessor.test.js +0 -40
- package/dist/src/services/prompt-processors/argumentProcessor.test.js.map +0 -1
- package/dist/src/services/prompt-processors/atFileProcessor.test.d.ts +0 -6
- package/dist/src/services/prompt-processors/atFileProcessor.test.js +0 -177
- package/dist/src/services/prompt-processors/atFileProcessor.test.js.map +0 -1
- package/dist/src/services/prompt-processors/injectionParser.test.d.ts +0 -6
- package/dist/src/services/prompt-processors/injectionParser.test.js +0 -189
- package/dist/src/services/prompt-processors/injectionParser.test.js.map +0 -1
- package/dist/src/services/prompt-processors/shellProcessor.test.d.ts +0 -6
- package/dist/src/services/prompt-processors/shellProcessor.test.js +0 -525
- package/dist/src/services/prompt-processors/shellProcessor.test.js.map +0 -1
- package/dist/src/test-utils/AppRig.test.d.ts +0 -6
- package/dist/src/test-utils/AppRig.test.js +0 -60
- package/dist/src/test-utils/AppRig.test.js.map +0 -1
- package/dist/src/test-utils/mockCommandContext.test.d.ts +0 -6
- package/dist/src/test-utils/mockCommandContext.test.js +0 -51
- package/dist/src/test-utils/mockCommandContext.test.js.map +0 -1
- package/dist/src/test-utils/render.test.d.ts +0 -6
- package/dist/src/test-utils/render.test.js +0 -84
- package/dist/src/test-utils/render.test.js.map +0 -1
- package/dist/src/ui/App.test.d.ts +0 -6
- package/dist/src/ui/App.test.js +0 -244
- package/dist/src/ui/App.test.js.map +0 -1
- package/dist/src/ui/AppContainer.test.d.ts +0 -6
- package/dist/src/ui/AppContainer.test.js +0 -2824
- package/dist/src/ui/AppContainer.test.js.map +0 -1
- package/dist/src/ui/IdeIntegrationNudge.test.d.ts +0 -6
- package/dist/src/ui/IdeIntegrationNudge.test.js +0 -149
- package/dist/src/ui/IdeIntegrationNudge.test.js.map +0 -1
- package/dist/src/ui/ToolConfirmationFullFrame.test.d.ts +0 -1
- package/dist/src/ui/ToolConfirmationFullFrame.test.js +0 -153
- package/dist/src/ui/ToolConfirmationFullFrame.test.js.map +0 -1
- package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +0 -6
- package/dist/src/ui/auth/ApiAuthDialog.test.js +0 -127
- package/dist/src/ui/auth/ApiAuthDialog.test.js.map +0 -1
- package/dist/src/ui/auth/AuthDialog.test.d.ts +0 -6
- package/dist/src/ui/auth/AuthDialog.test.js +0 -350
- package/dist/src/ui/auth/AuthDialog.test.js.map +0 -1
- package/dist/src/ui/auth/AuthInProgress.test.d.ts +0 -6
- package/dist/src/ui/auth/AuthInProgress.test.js +0 -99
- package/dist/src/ui/auth/AuthInProgress.test.js.map +0 -1
- package/dist/src/ui/auth/BannedAccountDialog.test.d.ts +0 -6
- package/dist/src/ui/auth/BannedAccountDialog.test.js +0 -141
- package/dist/src/ui/auth/BannedAccountDialog.test.js.map +0 -1
- package/dist/src/ui/auth/LoginRestartDialog.test.d.ts +0 -6
- package/dist/src/ui/auth/LoginRestartDialog.test.js +0 -79
- package/dist/src/ui/auth/LoginRestartDialog.test.js.map +0 -1
- package/dist/src/ui/auth/useAuth.test.d.ts +0 -6
- package/dist/src/ui/auth/useAuth.test.js +0 -214
- package/dist/src/ui/auth/useAuth.test.js.map +0 -1
- package/dist/src/ui/commands/aboutCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/aboutCommand.test.js +0 -145
- package/dist/src/ui/commands/aboutCommand.test.js.map +0 -1
- package/dist/src/ui/commands/agentsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/agentsCommand.test.js +0 -382
- package/dist/src/ui/commands/agentsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/authCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/authCommand.test.js +0 -103
- package/dist/src/ui/commands/authCommand.test.js.map +0 -1
- package/dist/src/ui/commands/bugCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/bugCommand.test.js +0 -305
- package/dist/src/ui/commands/bugCommand.test.js.map +0 -1
- package/dist/src/ui/commands/bugMemoryCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/bugMemoryCommand.test.js +0 -100
- package/dist/src/ui/commands/bugMemoryCommand.test.js.map +0 -1
- package/dist/src/ui/commands/chatCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/chatCommand.test.js +0 -627
- package/dist/src/ui/commands/chatCommand.test.js.map +0 -1
- package/dist/src/ui/commands/clearCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/clearCommand.test.js +0 -98
- package/dist/src/ui/commands/clearCommand.test.js.map +0 -1
- package/dist/src/ui/commands/commandsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/commandsCommand.test.js +0 -115
- package/dist/src/ui/commands/commandsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/compressCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/compressCommand.test.js +0 -110
- package/dist/src/ui/commands/compressCommand.test.js.map +0 -1
- package/dist/src/ui/commands/copyCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/copyCommand.test.js +0 -244
- package/dist/src/ui/commands/copyCommand.test.js.map +0 -1
- package/dist/src/ui/commands/corgiCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/corgiCommand.test.js +0 -28
- package/dist/src/ui/commands/corgiCommand.test.js.map +0 -1
- package/dist/src/ui/commands/directoryCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/directoryCommand.test.js +0 -365
- package/dist/src/ui/commands/directoryCommand.test.js.map +0 -1
- package/dist/src/ui/commands/docsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/docsCommand.test.js +0 -72
- package/dist/src/ui/commands/docsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/editorCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/editorCommand.test.js +0 -27
- package/dist/src/ui/commands/editorCommand.test.js.map +0 -1
- package/dist/src/ui/commands/exportSessionCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/exportSessionCommand.test.js +0 -100
- package/dist/src/ui/commands/exportSessionCommand.test.js.map +0 -1
- package/dist/src/ui/commands/extensionsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/extensionsCommand.test.js +0 -947
- package/dist/src/ui/commands/extensionsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/helpCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/helpCommand.test.js +0 -94
- package/dist/src/ui/commands/helpCommand.test.js.map +0 -1
- package/dist/src/ui/commands/hooksCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/hooksCommand.test.js +0 -562
- package/dist/src/ui/commands/hooksCommand.test.js.map +0 -1
- package/dist/src/ui/commands/ideCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/ideCommand.test.js +0 -205
- package/dist/src/ui/commands/ideCommand.test.js.map +0 -1
- package/dist/src/ui/commands/initCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/initCommand.test.js +0 -86
- package/dist/src/ui/commands/initCommand.test.js.map +0 -1
- package/dist/src/ui/commands/mcpCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/mcpCommand.test.js +0 -231
- package/dist/src/ui/commands/mcpCommand.test.js.map +0 -1
- package/dist/src/ui/commands/memoryCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/memoryCommand.test.js +0 -361
- package/dist/src/ui/commands/memoryCommand.test.js.map +0 -1
- package/dist/src/ui/commands/modelCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/modelCommand.test.js +0 -135
- package/dist/src/ui/commands/modelCommand.test.js.map +0 -1
- package/dist/src/ui/commands/permissionsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/permissionsCommand.test.js +0 -86
- package/dist/src/ui/commands/permissionsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/planCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/planCommand.test.js +0 -146
- package/dist/src/ui/commands/planCommand.test.js.map +0 -1
- package/dist/src/ui/commands/policiesCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/policiesCommand.test.js +0 -133
- package/dist/src/ui/commands/policiesCommand.test.js.map +0 -1
- package/dist/src/ui/commands/privacyCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/privacyCommand.test.js +0 -32
- package/dist/src/ui/commands/privacyCommand.test.js.map +0 -1
- package/dist/src/ui/commands/quitCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/quitCommand.test.js +0 -95
- package/dist/src/ui/commands/quitCommand.test.js.map +0 -1
- package/dist/src/ui/commands/restoreCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/restoreCommand.test.js +0 -193
- package/dist/src/ui/commands/restoreCommand.test.js.map +0 -1
- package/dist/src/ui/commands/resumeCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/resumeCommand.test.js +0 -28
- package/dist/src/ui/commands/resumeCommand.test.js.map +0 -1
- package/dist/src/ui/commands/rewindCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/rewindCommand.test.js +0 -256
- package/dist/src/ui/commands/rewindCommand.test.js.map +0 -1
- package/dist/src/ui/commands/settingsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/settingsCommand.test.js +0 -30
- package/dist/src/ui/commands/settingsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/setupGithubCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/setupGithubCommand.test.js +0 -238
- package/dist/src/ui/commands/setupGithubCommand.test.js.map +0 -1
- package/dist/src/ui/commands/skillsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/skillsCommand.test.js +0 -500
- package/dist/src/ui/commands/skillsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/statsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/statsCommand.test.js +0 -122
- package/dist/src/ui/commands/statsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/tasksCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/tasksCommand.test.js +0 -30
- package/dist/src/ui/commands/tasksCommand.test.js.map +0 -1
- package/dist/src/ui/commands/terminalSetupCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/terminalSetupCommand.test.js +0 -66
- package/dist/src/ui/commands/terminalSetupCommand.test.js.map +0 -1
- package/dist/src/ui/commands/themeCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/themeCommand.test.js +0 -32
- package/dist/src/ui/commands/themeCommand.test.js.map +0 -1
- package/dist/src/ui/commands/toolsCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/toolsCommand.test.js +0 -187
- package/dist/src/ui/commands/toolsCommand.test.js.map +0 -1
- package/dist/src/ui/commands/upgradeCommand.test.d.ts +0 -6
- package/dist/src/ui/commands/upgradeCommand.test.js +0 -102
- package/dist/src/ui/commands/upgradeCommand.test.js.map +0 -1
- package/dist/src/ui/components/AboutBox.test.d.ts +0 -6
- package/dist/src/ui/components/AboutBox.test.js +0 -63
- package/dist/src/ui/components/AboutBox.test.js.map +0 -1
- package/dist/src/ui/components/AdminSettingsChangedDialog.test.d.ts +0 -6
- package/dist/src/ui/components/AdminSettingsChangedDialog.test.js +0 -43
- package/dist/src/ui/components/AdminSettingsChangedDialog.test.js.map +0 -1
- package/dist/src/ui/components/AgentConfigDialog.test.d.ts +0 -6
- package/dist/src/ui/components/AgentConfigDialog.test.js +0 -267
- package/dist/src/ui/components/AgentConfigDialog.test.js.map +0 -1
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js +0 -196
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js.map +0 -1
- package/dist/src/ui/components/AnsiOutput.test.d.ts +0 -6
- package/dist/src/ui/components/AnsiOutput.test.js +0 -142
- package/dist/src/ui/components/AnsiOutput.test.js.map +0 -1
- package/dist/src/ui/components/AppHeader.test.d.ts +0 -6
- package/dist/src/ui/components/AppHeader.test.js +0 -212
- package/dist/src/ui/components/AppHeader.test.js.map +0 -1
- package/dist/src/ui/components/AppHeaderIcon.test.d.ts +0 -6
- package/dist/src/ui/components/AppHeaderIcon.test.js +0 -39
- package/dist/src/ui/components/AppHeaderIcon.test.js.map +0 -1
- package/dist/src/ui/components/ApprovalModeIndicator.test.d.ts +0 -6
- package/dist/src/ui/components/ApprovalModeIndicator.test.js +0 -37
- package/dist/src/ui/components/ApprovalModeIndicator.test.js.map +0 -1
- package/dist/src/ui/components/AskUserDialog.test.d.ts +0 -6
- package/dist/src/ui/components/AskUserDialog.test.js +0 -1121
- package/dist/src/ui/components/AskUserDialog.test.js.map +0 -1
- package/dist/src/ui/components/BackgroundTaskDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/BackgroundTaskDisplay.test.js +0 -209
- package/dist/src/ui/components/BackgroundTaskDisplay.test.js.map +0 -1
- package/dist/src/ui/components/Banner.test.d.ts +0 -6
- package/dist/src/ui/components/Banner.test.js +0 -29
- package/dist/src/ui/components/Banner.test.js.map +0 -1
- package/dist/src/ui/components/BubblingRegression.test.d.ts +0 -6
- package/dist/src/ui/components/BubblingRegression.test.js +0 -60
- package/dist/src/ui/components/BubblingRegression.test.js.map +0 -1
- package/dist/src/ui/components/Checklist.test.d.ts +0 -6
- package/dist/src/ui/components/Checklist.test.js +0 -46
- package/dist/src/ui/components/Checklist.test.js.map +0 -1
- package/dist/src/ui/components/ChecklistItem.test.d.ts +0 -6
- package/dist/src/ui/components/ChecklistItem.test.js +0 -40
- package/dist/src/ui/components/ChecklistItem.test.js.map +0 -1
- package/dist/src/ui/components/CliSpinner.test.d.ts +0 -6
- package/dist/src/ui/components/CliSpinner.test.js +0 -32
- package/dist/src/ui/components/CliSpinner.test.js.map +0 -1
- package/dist/src/ui/components/ColorsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ColorsDisplay.test.js +0 -107
- package/dist/src/ui/components/ColorsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/Composer.test.d.ts +0 -6
- package/dist/src/ui/components/Composer.test.js +0 -853
- package/dist/src/ui/components/Composer.test.js.map +0 -1
- package/dist/src/ui/components/ConfigInitDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ConfigInitDisplay.test.js +0 -118
- package/dist/src/ui/components/ConfigInitDisplay.test.js.map +0 -1
- package/dist/src/ui/components/ConsentPrompt.test.d.ts +0 -6
- package/dist/src/ui/components/ConsentPrompt.test.js +0 -80
- package/dist/src/ui/components/ConsentPrompt.test.js.map +0 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ConsoleSummaryDisplay.test.js +0 -28
- package/dist/src/ui/components/ConsoleSummaryDisplay.test.js.map +0 -1
- package/dist/src/ui/components/ContextSummaryDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ContextSummaryDisplay.test.js +0 -81
- package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +0 -1
- package/dist/src/ui/components/ContextUsageDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ContextUsageDisplay.test.js +0 -50
- package/dist/src/ui/components/ContextUsageDisplay.test.js.map +0 -1
- package/dist/src/ui/components/CopyModeWarning.test.d.ts +0 -6
- package/dist/src/ui/components/CopyModeWarning.test.js +0 -35
- package/dist/src/ui/components/CopyModeWarning.test.js.map +0 -1
- package/dist/src/ui/components/DebugProfiler.test.d.ts +0 -6
- package/dist/src/ui/components/DebugProfiler.test.js +0 -228
- package/dist/src/ui/components/DebugProfiler.test.js.map +0 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/DetailedMessagesDisplay.test.js +0 -81
- package/dist/src/ui/components/DetailedMessagesDisplay.test.js.map +0 -1
- package/dist/src/ui/components/DialogManager.test.d.ts +0 -6
- package/dist/src/ui/components/DialogManager.test.js +0 -187
- package/dist/src/ui/components/DialogManager.test.js.map +0 -1
- package/dist/src/ui/components/EditorSettingsDialog.test.d.ts +0 -6
- package/dist/src/ui/components/EditorSettingsDialog.test.js +0 -145
- package/dist/src/ui/components/EditorSettingsDialog.test.js.map +0 -1
- package/dist/src/ui/components/EmptyWalletDialog.test.d.ts +0 -6
- package/dist/src/ui/components/EmptyWalletDialog.test.js +0 -116
- package/dist/src/ui/components/EmptyWalletDialog.test.js.map +0 -1
- package/dist/src/ui/components/ExitPlanModeDialog.test.d.ts +0 -6
- package/dist/src/ui/components/ExitPlanModeDialog.test.js +0 -443
- package/dist/src/ui/components/ExitPlanModeDialog.test.js.map +0 -1
- package/dist/src/ui/components/ExitWarning.test.d.ts +0 -6
- package/dist/src/ui/components/ExitWarning.test.js +0 -58
- package/dist/src/ui/components/ExitWarning.test.js.map +0 -1
- package/dist/src/ui/components/FolderTrustDialog.test.d.ts +0 -6
- package/dist/src/ui/components/FolderTrustDialog.test.js +0 -342
- package/dist/src/ui/components/FolderTrustDialog.test.js.map +0 -1
- package/dist/src/ui/components/Footer.test.d.ts +0 -6
- package/dist/src/ui/components/Footer.test.js +0 -806
- package/dist/src/ui/components/Footer.test.js.map +0 -1
- package/dist/src/ui/components/FooterConfigDialog.test.d.ts +0 -6
- package/dist/src/ui/components/FooterConfigDialog.test.js +0 -191
- package/dist/src/ui/components/FooterConfigDialog.test.js.map +0 -1
- package/dist/src/ui/components/GeminiRespondingSpinner.test.d.ts +0 -6
- package/dist/src/ui/components/GeminiRespondingSpinner.test.js +0 -63
- package/dist/src/ui/components/GeminiRespondingSpinner.test.js.map +0 -1
- package/dist/src/ui/components/GradientRegression.test.d.ts +0 -6
- package/dist/src/ui/components/GradientRegression.test.js +0 -116
- package/dist/src/ui/components/GradientRegression.test.js.map +0 -1
- package/dist/src/ui/components/Header.test.d.ts +0 -6
- package/dist/src/ui/components/Header.test.js +0 -131
- package/dist/src/ui/components/Header.test.js.map +0 -1
- package/dist/src/ui/components/Help.test.d.ts +0 -6
- package/dist/src/ui/components/Help.test.js +0 -67
- package/dist/src/ui/components/Help.test.js.map +0 -1
- package/dist/src/ui/components/HistoryItemDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/HistoryItemDisplay.test.js +0 -302
- package/dist/src/ui/components/HistoryItemDisplay.test.js.map +0 -1
- package/dist/src/ui/components/HookStatusDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/HookStatusDisplay.test.js +0 -77
- package/dist/src/ui/components/HookStatusDisplay.test.js.map +0 -1
- package/dist/src/ui/components/HooksDialog.test.d.ts +0 -6
- package/dist/src/ui/components/HooksDialog.test.js +0 -175
- package/dist/src/ui/components/HooksDialog.test.js.map +0 -1
- package/dist/src/ui/components/IdeTrustChangeDialog.test.d.ts +0 -6
- package/dist/src/ui/components/IdeTrustChangeDialog.test.js +0 -78
- package/dist/src/ui/components/IdeTrustChangeDialog.test.js.map +0 -1
- package/dist/src/ui/components/InboxDialog.test.d.ts +0 -6
- package/dist/src/ui/components/InboxDialog.test.js +0 -804
- package/dist/src/ui/components/InboxDialog.test.js.map +0 -1
- package/dist/src/ui/components/InputPrompt.test.d.ts +0 -17
- package/dist/src/ui/components/InputPrompt.test.js +0 -4078
- package/dist/src/ui/components/InputPrompt.test.js.map +0 -1
- package/dist/src/ui/components/LoadingIndicator.test.d.ts +0 -6
- package/dist/src/ui/components/LoadingIndicator.test.js +0 -325
- package/dist/src/ui/components/LoadingIndicator.test.js.map +0 -1
- package/dist/src/ui/components/LogoutConfirmationDialog.test.d.ts +0 -6
- package/dist/src/ui/components/LogoutConfirmationDialog.test.js +0 -74
- package/dist/src/ui/components/LogoutConfirmationDialog.test.js.map +0 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.test.d.ts +0 -6
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js +0 -27
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +0 -1
- package/dist/src/ui/components/MainContent.test.d.ts +0 -6
- package/dist/src/ui/components/MainContent.test.js +0 -750
- package/dist/src/ui/components/MainContent.test.js.map +0 -1
- package/dist/src/ui/components/MemoryUsageDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/MemoryUsageDisplay.test.js +0 -52
- package/dist/src/ui/components/MemoryUsageDisplay.test.js.map +0 -1
- package/dist/src/ui/components/ModelDialog.test.d.ts +0 -6
- package/dist/src/ui/components/ModelDialog.test.js +0 -356
- package/dist/src/ui/components/ModelDialog.test.js.map +0 -1
- package/dist/src/ui/components/ModelQuotaDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ModelQuotaDisplay.test.js +0 -62
- package/dist/src/ui/components/ModelQuotaDisplay.test.js.map +0 -1
- package/dist/src/ui/components/ModelStatsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ModelStatsDisplay.test.js +0 -651
- package/dist/src/ui/components/ModelStatsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/MultiFolderTrustDialog.test.d.ts +0 -6
- package/dist/src/ui/components/MultiFolderTrustDialog.test.js +0 -177
- package/dist/src/ui/components/MultiFolderTrustDialog.test.js.map +0 -1
- package/dist/src/ui/components/NewAgentsNotification.test.d.ts +0 -6
- package/dist/src/ui/components/NewAgentsNotification.test.js +0 -83
- package/dist/src/ui/components/NewAgentsNotification.test.js.map +0 -1
- package/dist/src/ui/components/Notifications.test.d.ts +0 -6
- package/dist/src/ui/components/Notifications.test.js +0 -285
- package/dist/src/ui/components/Notifications.test.js.map +0 -1
- package/dist/src/ui/components/OverageMenuDialog.test.d.ts +0 -6
- package/dist/src/ui/components/OverageMenuDialog.test.js +0 -118
- package/dist/src/ui/components/OverageMenuDialog.test.js.map +0 -1
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.d.ts +0 -6
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +0 -181
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +0 -1
- package/dist/src/ui/components/PolicyUpdateDialog.test.d.ts +0 -6
- package/dist/src/ui/components/PolicyUpdateDialog.test.js +0 -92
- package/dist/src/ui/components/PolicyUpdateDialog.test.js.map +0 -1
- package/dist/src/ui/components/ProQuotaDialog.test.d.ts +0 -6
- package/dist/src/ui/components/ProQuotaDialog.test.js +0 -222
- package/dist/src/ui/components/ProQuotaDialog.test.js.map +0 -1
- package/dist/src/ui/components/ProgressBar.test.d.ts +0 -6
- package/dist/src/ui/components/ProgressBar.test.js +0 -28
- package/dist/src/ui/components/ProgressBar.test.js.map +0 -1
- package/dist/src/ui/components/QueuedMessageDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/QueuedMessageDisplay.test.js +0 -65
- package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +0 -1
- package/dist/src/ui/components/QuittingDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/QuittingDisplay.test.js +0 -60
- package/dist/src/ui/components/QuittingDisplay.test.js.map +0 -1
- package/dist/src/ui/components/QuotaDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/QuotaDisplay.test.js +0 -68
- package/dist/src/ui/components/QuotaDisplay.test.js.map +0 -1
- package/dist/src/ui/components/RawMarkdownIndicator.test.d.ts +0 -6
- package/dist/src/ui/components/RawMarkdownIndicator.test.js +0 -38
- package/dist/src/ui/components/RawMarkdownIndicator.test.js.map +0 -1
- package/dist/src/ui/components/RewindConfirmation.test.d.ts +0 -6
- package/dist/src/ui/components/RewindConfirmation.test.js +0 -57
- package/dist/src/ui/components/RewindConfirmation.test.js.map +0 -1
- package/dist/src/ui/components/RewindViewer.test.d.ts +0 -6
- package/dist/src/ui/components/RewindViewer.test.js +0 -334
- package/dist/src/ui/components/RewindViewer.test.js.map +0 -1
- package/dist/src/ui/components/SessionBrowser/SessionBrowserSearchNav.test.d.ts +0 -6
- package/dist/src/ui/components/SessionBrowser/SessionBrowserSearchNav.test.js +0 -47
- package/dist/src/ui/components/SessionBrowser/SessionBrowserSearchNav.test.js.map +0 -1
- package/dist/src/ui/components/SessionBrowser/SessionBrowserStates.test.d.ts +0 -6
- package/dist/src/ui/components/SessionBrowser/SessionBrowserStates.test.js +0 -27
- package/dist/src/ui/components/SessionBrowser/SessionBrowserStates.test.js.map +0 -1
- package/dist/src/ui/components/SessionBrowser/utils.test.d.ts +0 -6
- package/dist/src/ui/components/SessionBrowser/utils.test.js +0 -108
- package/dist/src/ui/components/SessionBrowser/utils.test.js.map +0 -1
- package/dist/src/ui/components/SessionBrowser.test.d.ts +0 -6
- package/dist/src/ui/components/SessionBrowser.test.js +0 -266
- package/dist/src/ui/components/SessionBrowser.test.js.map +0 -1
- package/dist/src/ui/components/SessionSummaryDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/SessionSummaryDisplay.test.js +0 -164
- package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +0 -1
- package/dist/src/ui/components/SettingsDialog.test.d.ts +0 -6
- package/dist/src/ui/components/SettingsDialog.test.js +0 -1499
- package/dist/src/ui/components/SettingsDialog.test.js.map +0 -1
- package/dist/src/ui/components/ShellInputPrompt.test.d.ts +0 -6
- package/dist/src/ui/components/ShellInputPrompt.test.js +0 -201
- package/dist/src/ui/components/ShellInputPrompt.test.js.map +0 -1
- package/dist/src/ui/components/ShellModeIndicator.test.d.ts +0 -6
- package/dist/src/ui/components/ShellModeIndicator.test.js +0 -18
- package/dist/src/ui/components/ShellModeIndicator.test.js.map +0 -1
- package/dist/src/ui/components/ShortcutsHelp.test.d.ts +0 -6
- package/dist/src/ui/components/ShortcutsHelp.test.js +0 -45
- package/dist/src/ui/components/ShortcutsHelp.test.js.map +0 -1
- package/dist/src/ui/components/ShowMoreLines.test.d.ts +0 -6
- package/dist/src/ui/components/ShowMoreLines.test.js +0 -79
- package/dist/src/ui/components/ShowMoreLines.test.js.map +0 -1
- package/dist/src/ui/components/ShowMoreLinesLayout.test.d.ts +0 -1
- package/dist/src/ui/components/ShowMoreLinesLayout.test.js +0 -68
- package/dist/src/ui/components/ShowMoreLinesLayout.test.js.map +0 -1
- package/dist/src/ui/components/StatsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/StatsDisplay.test.js +0 -489
- package/dist/src/ui/components/StatsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/StatusDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/StatusDisplay.test.js +0 -117
- package/dist/src/ui/components/StatusDisplay.test.js.map +0 -1
- package/dist/src/ui/components/StatusRow.test.d.ts +0 -6
- package/dist/src/ui/components/StatusRow.test.js +0 -99
- package/dist/src/ui/components/StatusRow.test.js.map +0 -1
- package/dist/src/ui/components/StickyHeader.test.d.ts +0 -6
- package/dist/src/ui/components/StickyHeader.test.js +0 -19
- package/dist/src/ui/components/StickyHeader.test.js.map +0 -1
- package/dist/src/ui/components/SuggestionsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/SuggestionsDisplay.test.js +0 -82
- package/dist/src/ui/components/SuggestionsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/Table.test.d.ts +0 -6
- package/dist/src/ui/components/Table.test.js +0 -72
- package/dist/src/ui/components/Table.test.js.map +0 -1
- package/dist/src/ui/components/ThemeDialog.test.d.ts +0 -6
- package/dist/src/ui/components/ThemeDialog.test.js +0 -162
- package/dist/src/ui/components/ThemeDialog.test.js.map +0 -1
- package/dist/src/ui/components/ThemedGradient.test.d.ts +0 -6
- package/dist/src/ui/components/ThemedGradient.test.js +0 -35
- package/dist/src/ui/components/ThemedGradient.test.js.map +0 -1
- package/dist/src/ui/components/Tips.test.d.ts +0 -6
- package/dist/src/ui/components/Tips.test.js +0 -23
- package/dist/src/ui/components/Tips.test.js.map +0 -1
- package/dist/src/ui/components/ToastDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ToastDisplay.test.js +0 -167
- package/dist/src/ui/components/ToastDisplay.test.js.map +0 -1
- package/dist/src/ui/components/ToolConfirmationQueue.test.d.ts +0 -6
- package/dist/src/ui/components/ToolConfirmationQueue.test.js +0 -444
- package/dist/src/ui/components/ToolConfirmationQueue.test.js.map +0 -1
- package/dist/src/ui/components/ToolStatsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ToolStatsDisplay.test.js +0 -234
- package/dist/src/ui/components/ToolStatsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/UpdateNotification.test.d.ts +0 -6
- package/dist/src/ui/components/UpdateNotification.test.js +0 -17
- package/dist/src/ui/components/UpdateNotification.test.js.map +0 -1
- package/dist/src/ui/components/UserIdentity.test.d.ts +0 -6
- package/dist/src/ui/components/UserIdentity.test.js +0 -138
- package/dist/src/ui/components/UserIdentity.test.js.map +0 -1
- package/dist/src/ui/components/ValidationDialog.test.d.ts +0 -6
- package/dist/src/ui/components/ValidationDialog.test.js +0 -162
- package/dist/src/ui/components/ValidationDialog.test.js.map +0 -1
- package/dist/src/ui/components/VoiceModelDialog.test.d.ts +0 -6
- package/dist/src/ui/components/VoiceModelDialog.test.js +0 -68
- package/dist/src/ui/components/VoiceModelDialog.test.js.map +0 -1
- package/dist/src/ui/components/messages/CompressionMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/CompressionMessage.test.js +0 -180
- package/dist/src/ui/components/messages/CompressionMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/DenseToolMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/DenseToolMessage.test.js +0 -406
- package/dist/src/ui/components/messages/DenseToolMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.d.ts +0 -6
- package/dist/src/ui/components/messages/DiffRenderer.test.js +0 -269
- package/dist/src/ui/components/messages/DiffRenderer.test.js.map +0 -1
- package/dist/src/ui/components/messages/ErrorMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ErrorMessage.test.js +0 -25
- package/dist/src/ui/components/messages/ErrorMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/ExportSessionMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ExportSessionMessage.test.js +0 -32
- package/dist/src/ui/components/messages/ExportSessionMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/GeminiMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/GeminiMessage.test.js +0 -46
- package/dist/src/ui/components/messages/GeminiMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/HintMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/HintMessage.test.js +0 -42
- package/dist/src/ui/components/messages/HintMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/InfoMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/InfoMessage.test.js +0 -31
- package/dist/src/ui/components/messages/InfoMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/RedirectionConfirmation.test.d.ts +0 -6
- package/dist/src/ui/components/messages/RedirectionConfirmation.test.js +0 -35
- package/dist/src/ui/components/messages/RedirectionConfirmation.test.js.map +0 -1
- package/dist/src/ui/components/messages/ShellToolMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ShellToolMessage.test.js +0 -290
- package/dist/src/ui/components/messages/ShellToolMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/SubagentGroupDisplay.test.d.ts +0 -1
- package/dist/src/ui/components/messages/SubagentGroupDisplay.test.js +0 -92
- package/dist/src/ui/components/messages/SubagentGroupDisplay.test.js.map +0 -1
- package/dist/src/ui/components/messages/SubagentHistoryMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/SubagentHistoryMessage.test.js +0 -69
- package/dist/src/ui/components/messages/SubagentHistoryMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/SubagentProgressDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/messages/SubagentProgressDisplay.test.js +0 -164
- package/dist/src/ui/components/messages/SubagentProgressDisplay.test.js.map +0 -1
- package/dist/src/ui/components/messages/ThinkingMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ThinkingMessage.test.js +0 -104
- package/dist/src/ui/components/messages/ThinkingMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/Todo.test.d.ts +0 -6
- package/dist/src/ui/components/messages/Todo.test.js +0 -129
- package/dist/src/ui/components/messages/Todo.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +0 -558
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolGroupDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolGroupDisplay.test.js +0 -210
- package/dist/src/ui/components/messages/ToolGroupDisplay.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.compact.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolGroupMessage.compact.test.js +0 -147
- package/dist/src/ui/components/messages/ToolGroupMessage.compact.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +0 -828
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolGroupMessageRegression.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolGroupMessageRegression.test.js +0 -101
- package/dist/src/ui/components/messages/ToolGroupMessageRegression.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolMessage.test.js +0 -292
- package/dist/src/ui/components/messages/ToolMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolMessageFocusHint.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolMessageFocusHint.test.js +0 -96
- package/dist/src/ui/components/messages/ToolMessageFocusHint.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js +0 -72
- package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolOverflowConsistencyChecks.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolOverflowConsistencyChecks.test.js +0 -88
- package/dist/src/ui/components/messages/ToolOverflowConsistencyChecks.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolResultDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolResultDisplay.test.js +0 -333
- package/dist/src/ui/components/messages/ToolResultDisplay.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolResultDisplayOverflow.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolResultDisplayOverflow.test.js +0 -77
- package/dist/src/ui/components/messages/ToolResultDisplayOverflow.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolShared.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolShared.test.js +0 -65
- package/dist/src/ui/components/messages/ToolShared.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.js +0 -142
- package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.js.map +0 -1
- package/dist/src/ui/components/messages/TopicMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/TopicMessage.test.js +0 -77
- package/dist/src/ui/components/messages/TopicMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/UserMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/UserMessage.test.js +0 -67
- package/dist/src/ui/components/messages/UserMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/UserShellMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/UserShellMessage.test.js +0 -40
- package/dist/src/ui/components/messages/UserShellMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/WarningMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/WarningMessage.test.js +0 -25
- package/dist/src/ui/components/messages/WarningMessage.test.js.map +0 -1
- package/dist/src/ui/components/shared/BaseSelectionList.test.d.ts +0 -6
- package/dist/src/ui/components/shared/BaseSelectionList.test.js +0 -441
- package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +0 -1
- package/dist/src/ui/components/shared/BaseSettingsDialog.test.d.ts +0 -6
- package/dist/src/ui/components/shared/BaseSettingsDialog.test.js +0 -710
- package/dist/src/ui/components/shared/BaseSettingsDialog.test.js.map +0 -1
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.d.ts +0 -6
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.js +0 -89
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.js.map +0 -1
- package/dist/src/ui/components/shared/EnumSelector.test.d.ts +0 -6
- package/dist/src/ui/components/shared/EnumSelector.test.js +0 -83
- package/dist/src/ui/components/shared/EnumSelector.test.js.map +0 -1
- package/dist/src/ui/components/shared/ExpandableText.test.d.ts +0 -6
- package/dist/src/ui/components/shared/ExpandableText.test.js +0 -95
- package/dist/src/ui/components/shared/ExpandableText.test.js.map +0 -1
- package/dist/src/ui/components/shared/HalfLinePaddedBox.test.d.ts +0 -1
- package/dist/src/ui/components/shared/HalfLinePaddedBox.test.js +0 -47
- package/dist/src/ui/components/shared/HalfLinePaddedBox.test.js.map +0 -1
- package/dist/src/ui/components/shared/MaxSizedBox.test.d.ts +0 -6
- package/dist/src/ui/components/shared/MaxSizedBox.test.js +0 -161
- package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +0 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.test.d.ts +0 -6
- package/dist/src/ui/components/shared/RadioButtonSelect.test.js +0 -146
- package/dist/src/ui/components/shared/RadioButtonSelect.test.js.map +0 -1
- package/dist/src/ui/components/shared/Scrollable.test.d.ts +0 -6
- package/dist/src/ui/components/shared/Scrollable.test.js +0 -143
- package/dist/src/ui/components/shared/Scrollable.test.js.map +0 -1
- package/dist/src/ui/components/shared/ScrollableList.test.d.ts +0 -6
- package/dist/src/ui/components/shared/ScrollableList.test.js +0 -438
- package/dist/src/ui/components/shared/ScrollableList.test.js.map +0 -1
- package/dist/src/ui/components/shared/SearchableList.test.d.ts +0 -6
- package/dist/src/ui/components/shared/SearchableList.test.js +0 -169
- package/dist/src/ui/components/shared/SearchableList.test.js.map +0 -1
- package/dist/src/ui/components/shared/SectionHeader.test.d.ts +0 -6
- package/dist/src/ui/components/shared/SectionHeader.test.js +0 -42
- package/dist/src/ui/components/shared/SectionHeader.test.js.map +0 -1
- package/dist/src/ui/components/shared/SlicingMaxSizedBox.test.d.ts +0 -6
- package/dist/src/ui/components/shared/SlicingMaxSizedBox.test.js +0 -54
- package/dist/src/ui/components/shared/SlicingMaxSizedBox.test.js.map +0 -1
- package/dist/src/ui/components/shared/TabHeader.test.d.ts +0 -6
- package/dist/src/ui/components/shared/TabHeader.test.js +0 -144
- package/dist/src/ui/components/shared/TabHeader.test.js.map +0 -1
- package/dist/src/ui/components/shared/TextInput.test.d.ts +0 -6
- package/dist/src/ui/components/shared/TextInput.test.js +0 -353
- package/dist/src/ui/components/shared/TextInput.test.js.map +0 -1
- package/dist/src/ui/components/shared/VirtualizedList.test.d.ts +0 -6
- package/dist/src/ui/components/shared/VirtualizedList.test.js +0 -174
- package/dist/src/ui/components/shared/VirtualizedList.test.js.map +0 -1
- package/dist/src/ui/components/shared/performance.test.d.ts +0 -1
- package/dist/src/ui/components/shared/performance.test.js +0 -74
- package/dist/src/ui/components/shared/performance.test.js.map +0 -1
- package/dist/src/ui/components/shared/text-buffer.test.d.ts +0 -6
- package/dist/src/ui/components/shared/text-buffer.test.js +0 -2965
- package/dist/src/ui/components/shared/text-buffer.test.js.map +0 -1
- package/dist/src/ui/components/shared/vim-buffer-actions.test.d.ts +0 -6
- package/dist/src/ui/components/shared/vim-buffer-actions.test.js +0 -2272
- package/dist/src/ui/components/shared/vim-buffer-actions.test.js.map +0 -1
- package/dist/src/ui/components/views/ChatList.test.d.ts +0 -6
- package/dist/src/ui/components/views/ChatList.test.js +0 -45
- package/dist/src/ui/components/views/ChatList.test.js.map +0 -1
- package/dist/src/ui/components/views/ExtensionDetails.test.d.ts +0 -6
- package/dist/src/ui/components/views/ExtensionDetails.test.js +0 -154
- package/dist/src/ui/components/views/ExtensionDetails.test.js.map +0 -1
- package/dist/src/ui/components/views/ExtensionRegistryView.test.d.ts +0 -6
- package/dist/src/ui/components/views/ExtensionRegistryView.test.js +0 -222
- package/dist/src/ui/components/views/ExtensionRegistryView.test.js.map +0 -1
- package/dist/src/ui/components/views/ExtensionsList.test.d.ts +0 -6
- package/dist/src/ui/components/views/ExtensionsList.test.js +0 -145
- package/dist/src/ui/components/views/ExtensionsList.test.js.map +0 -1
- package/dist/src/ui/components/views/McpStatus.test.d.ts +0 -6
- package/dist/src/ui/components/views/McpStatus.test.js +0 -174
- package/dist/src/ui/components/views/McpStatus.test.js.map +0 -1
- package/dist/src/ui/components/views/SkillsList.test.d.ts +0 -6
- package/dist/src/ui/components/views/SkillsList.test.js +0 -99
- package/dist/src/ui/components/views/SkillsList.test.js.map +0 -1
- package/dist/src/ui/components/views/ToolsList.test.d.ts +0 -6
- package/dist/src/ui/components/views/ToolsList.test.js +0 -45
- package/dist/src/ui/components/views/ToolsList.test.js.map +0 -1
- package/dist/src/ui/contexts/KeypressContext.test.d.ts +0 -6
- package/dist/src/ui/contexts/KeypressContext.test.js +0 -1133
- package/dist/src/ui/contexts/KeypressContext.test.js.map +0 -1
- package/dist/src/ui/contexts/MouseContext.test.d.ts +0 -6
- package/dist/src/ui/contexts/MouseContext.test.js +0 -269
- package/dist/src/ui/contexts/MouseContext.test.js.map +0 -1
- package/dist/src/ui/contexts/ScrollProvider.drag.test.d.ts +0 -6
- package/dist/src/ui/contexts/ScrollProvider.drag.test.js +0 -320
- package/dist/src/ui/contexts/ScrollProvider.drag.test.js.map +0 -1
- package/dist/src/ui/contexts/ScrollProvider.test.d.ts +0 -6
- package/dist/src/ui/contexts/ScrollProvider.test.js +0 -478
- package/dist/src/ui/contexts/ScrollProvider.test.js.map +0 -1
- package/dist/src/ui/contexts/SessionContext.test.d.ts +0 -6
- package/dist/src/ui/contexts/SessionContext.test.js +0 -213
- package/dist/src/ui/contexts/SessionContext.test.js.map +0 -1
- package/dist/src/ui/contexts/SettingsContext.test.d.ts +0 -6
- package/dist/src/ui/contexts/SettingsContext.test.js +0 -106
- package/dist/src/ui/contexts/SettingsContext.test.js.map +0 -1
- package/dist/src/ui/contexts/TerminalContext.test.d.ts +0 -6
- package/dist/src/ui/contexts/TerminalContext.test.js +0 -75
- package/dist/src/ui/contexts/TerminalContext.test.js.map +0 -1
- package/dist/src/ui/contexts/ToolActionsContext.test.d.ts +0 -6
- package/dist/src/ui/contexts/ToolActionsContext.test.js +0 -247
- package/dist/src/ui/contexts/ToolActionsContext.test.js.map +0 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.d.ts +0 -6
- package/dist/src/ui/hooks/atCommandProcessor.test.js +0 -1265
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +0 -1
- package/dist/src/ui/hooks/atCommandProcessor_agents.test.d.ts +0 -6
- package/dist/src/ui/hooks/atCommandProcessor_agents.test.js +0 -210
- package/dist/src/ui/hooks/atCommandProcessor_agents.test.js.map +0 -1
- package/dist/src/ui/hooks/creditsFlowHandler.test.d.ts +0 -6
- package/dist/src/ui/hooks/creditsFlowHandler.test.js +0 -211
- package/dist/src/ui/hooks/creditsFlowHandler.test.js.map +0 -1
- package/dist/src/ui/hooks/shell-completions/gitProvider.test.d.ts +0 -6
- package/dist/src/ui/hooks/shell-completions/gitProvider.test.js +0 -73
- package/dist/src/ui/hooks/shell-completions/gitProvider.test.js.map +0 -1
- package/dist/src/ui/hooks/shell-completions/npmProvider.test.d.ts +0 -6
- package/dist/src/ui/hooks/shell-completions/npmProvider.test.js +0 -69
- package/dist/src/ui/hooks/shell-completions/npmProvider.test.js.map +0 -1
- package/dist/src/ui/hooks/shellReducer.test.d.ts +0 -6
- package/dist/src/ui/hooks/shellReducer.test.js +0 -341
- package/dist/src/ui/hooks/shellReducer.test.js.map +0 -1
- package/dist/src/ui/hooks/slashCommandProcessor.test.d.ts +0 -6
- package/dist/src/ui/hooks/slashCommandProcessor.test.js +0 -881
- package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +0 -1
- package/dist/src/ui/hooks/toolMapping.test.d.ts +0 -6
- package/dist/src/ui/hooks/toolMapping.test.js +0 -292
- package/dist/src/ui/hooks/toolMapping.test.js.map +0 -1
- package/dist/src/ui/hooks/useAgentStream.test.d.ts +0 -6
- package/dist/src/ui/hooks/useAgentStream.test.js +0 -161
- package/dist/src/ui/hooks/useAgentStream.test.js.map +0 -1
- package/dist/src/ui/hooks/useAlternateBuffer.test.d.ts +0 -6
- package/dist/src/ui/hooks/useAlternateBuffer.test.js +0 -62
- package/dist/src/ui/hooks/useAlternateBuffer.test.js.map +0 -1
- package/dist/src/ui/hooks/useAnimatedScrollbar.test.d.ts +0 -6
- package/dist/src/ui/hooks/useAnimatedScrollbar.test.js +0 -85
- package/dist/src/ui/hooks/useAnimatedScrollbar.test.js.map +0 -1
- package/dist/src/ui/hooks/useApprovalModeIndicator.test.d.ts +0 -6
- package/dist/src/ui/hooks/useApprovalModeIndicator.test.js +0 -477
- package/dist/src/ui/hooks/useApprovalModeIndicator.test.js.map +0 -1
- package/dist/src/ui/hooks/useAtCompletion.test.d.ts +0 -6
- package/dist/src/ui/hooks/useAtCompletion.test.js +0 -567
- package/dist/src/ui/hooks/useAtCompletion.test.js.map +0 -1
- package/dist/src/ui/hooks/useAtCompletion_agents.test.d.ts +0 -6
- package/dist/src/ui/hooks/useAtCompletion_agents.test.js +0 -87
- package/dist/src/ui/hooks/useAtCompletion_agents.test.js.map +0 -1
- package/dist/src/ui/hooks/useBackgroundTaskManager.test.d.ts +0 -6
- package/dist/src/ui/hooks/useBackgroundTaskManager.test.js +0 -168
- package/dist/src/ui/hooks/useBackgroundTaskManager.test.js.map +0 -1
- package/dist/src/ui/hooks/useBanner.test.d.ts +0 -6
- package/dist/src/ui/hooks/useBanner.test.js +0 -144
- package/dist/src/ui/hooks/useBanner.test.js.map +0 -1
- package/dist/src/ui/hooks/useBatchedScroll.test.d.ts +0 -6
- package/dist/src/ui/hooks/useBatchedScroll.test.js +0 -62
- package/dist/src/ui/hooks/useBatchedScroll.test.js.map +0 -1
- package/dist/src/ui/hooks/useCommandCompletion.test.d.ts +0 -6
- package/dist/src/ui/hooks/useCommandCompletion.test.js +0 -722
- package/dist/src/ui/hooks/useCommandCompletion.test.js.map +0 -1
- package/dist/src/ui/hooks/useConsoleMessages.test.d.ts +0 -6
- package/dist/src/ui/hooks/useConsoleMessages.test.js +0 -201
- package/dist/src/ui/hooks/useConsoleMessages.test.js.map +0 -1
- package/dist/src/ui/hooks/useEditorSettings.test.d.ts +0 -6
- package/dist/src/ui/hooks/useEditorSettings.test.js +0 -179
- package/dist/src/ui/hooks/useEditorSettings.test.js.map +0 -1
- package/dist/src/ui/hooks/useExecutionLifecycle.test.d.ts +0 -6
- package/dist/src/ui/hooks/useExecutionLifecycle.test.js +0 -903
- package/dist/src/ui/hooks/useExecutionLifecycle.test.js.map +0 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.d.ts +0 -6
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +0 -280
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +0 -1
- package/dist/src/ui/hooks/useFlickerDetector.test.d.ts +0 -6
- package/dist/src/ui/hooks/useFlickerDetector.test.js +0 -106
- package/dist/src/ui/hooks/useFlickerDetector.test.js.map +0 -1
- package/dist/src/ui/hooks/useFocus.test.d.ts +0 -6
- package/dist/src/ui/hooks/useFocus.test.js +0 -140
- package/dist/src/ui/hooks/useFocus.test.js.map +0 -1
- package/dist/src/ui/hooks/useFolderTrust.test.d.ts +0 -6
- package/dist/src/ui/hooks/useFolderTrust.test.js +0 -268
- package/dist/src/ui/hooks/useFolderTrust.test.js.map +0 -1
- package/dist/src/ui/hooks/useGeminiStream.test.d.ts +0 -6
- package/dist/src/ui/hooks/useGeminiStream.test.js +0 -2855
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +0 -1
- package/dist/src/ui/hooks/useGitBranchName.test.d.ts +0 -6
- package/dist/src/ui/hooks/useGitBranchName.test.js +0 -237
- package/dist/src/ui/hooks/useGitBranchName.test.js.map +0 -1
- package/dist/src/ui/hooks/useHistoryManager.test.d.ts +0 -6
- package/dist/src/ui/hooks/useHistoryManager.test.js +0 -259
- package/dist/src/ui/hooks/useHistoryManager.test.js.map +0 -1
- package/dist/src/ui/hooks/useHookDisplayState.test.d.ts +0 -6
- package/dist/src/ui/hooks/useHookDisplayState.test.js +0 -200
- package/dist/src/ui/hooks/useHookDisplayState.test.js.map +0 -1
- package/dist/src/ui/hooks/useIdeTrustListener.test.d.ts +0 -6
- package/dist/src/ui/hooks/useIdeTrustListener.test.js +0 -225
- package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +0 -1
- package/dist/src/ui/hooks/useIncludeDirsTrust.test.d.ts +0 -6
- package/dist/src/ui/hooks/useIncludeDirsTrust.test.js +0 -174
- package/dist/src/ui/hooks/useIncludeDirsTrust.test.js.map +0 -1
- package/dist/src/ui/hooks/useInlineEditBuffer.test.d.ts +0 -6
- package/dist/src/ui/hooks/useInlineEditBuffer.test.js +0 -112
- package/dist/src/ui/hooks/useInlineEditBuffer.test.js.map +0 -1
- package/dist/src/ui/hooks/useInputHistory.test.d.ts +0 -6
- package/dist/src/ui/hooks/useInputHistory.test.js +0 -389
- package/dist/src/ui/hooks/useInputHistory.test.js.map +0 -1
- package/dist/src/ui/hooks/useInputHistoryStore.test.d.ts +0 -6
- package/dist/src/ui/hooks/useInputHistoryStore.test.js +0 -238
- package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +0 -1
- package/dist/src/ui/hooks/useKeypress.test.d.ts +0 -6
- package/dist/src/ui/hooks/useKeypress.test.js +0 -198
- package/dist/src/ui/hooks/useKeypress.test.js.map +0 -1
- package/dist/src/ui/hooks/useLoadingIndicator.test.d.ts +0 -6
- package/dist/src/ui/hooks/useLoadingIndicator.test.js +0 -177
- package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +0 -1
- package/dist/src/ui/hooks/useLogger.test.d.ts +0 -6
- package/dist/src/ui/hooks/useLogger.test.js +0 -44
- package/dist/src/ui/hooks/useLogger.test.js.map +0 -1
- package/dist/src/ui/hooks/useMcpStatus.test.d.ts +0 -6
- package/dist/src/ui/hooks/useMcpStatus.test.js +0 -69
- package/dist/src/ui/hooks/useMcpStatus.test.js.map +0 -1
- package/dist/src/ui/hooks/useMemoryMonitor.test.d.ts +0 -6
- package/dist/src/ui/hooks/useMemoryMonitor.test.js +0 -62
- package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +0 -1
- package/dist/src/ui/hooks/useMessageQueue.test.d.ts +0 -6
- package/dist/src/ui/hooks/useMessageQueue.test.js +0 -365
- package/dist/src/ui/hooks/useMessageQueue.test.js.map +0 -1
- package/dist/src/ui/hooks/useModelCommand.test.d.ts +0 -6
- package/dist/src/ui/hooks/useModelCommand.test.js +0 -45
- package/dist/src/ui/hooks/useModelCommand.test.js.map +0 -1
- package/dist/src/ui/hooks/useMouse.test.d.ts +0 -6
- package/dist/src/ui/hooks/useMouse.test.js +0 -52
- package/dist/src/ui/hooks/useMouse.test.js.map +0 -1
- package/dist/src/ui/hooks/useMouseClick.test.d.ts +0 -6
- package/dist/src/ui/hooks/useMouseClick.test.js +0 -68
- package/dist/src/ui/hooks/useMouseClick.test.js.map +0 -1
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.d.ts +0 -6
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +0 -291
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +0 -1
- package/dist/src/ui/hooks/usePhraseCycler.test.d.ts +0 -6
- package/dist/src/ui/hooks/usePhraseCycler.test.js +0 -187
- package/dist/src/ui/hooks/usePhraseCycler.test.js.map +0 -1
- package/dist/src/ui/hooks/usePrivacySettings.test.d.ts +0 -6
- package/dist/src/ui/hooks/usePrivacySettings.test.js +0 -113
- package/dist/src/ui/hooks/usePrivacySettings.test.js.map +0 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.test.d.ts +0 -6
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js +0 -817
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +0 -1
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.d.ts +0 -6
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +0 -168
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +0 -1
- package/dist/src/ui/hooks/useRewind.test.d.ts +0 -6
- package/dist/src/ui/hooks/useRewind.test.js +0 -100
- package/dist/src/ui/hooks/useRewind.test.js.map +0 -1
- package/dist/src/ui/hooks/useSelectionList.test.d.ts +0 -6
- package/dist/src/ui/hooks/useSelectionList.test.js +0 -960
- package/dist/src/ui/hooks/useSelectionList.test.js.map +0 -1
- package/dist/src/ui/hooks/useSessionBrowser.test.d.ts +0 -6
- package/dist/src/ui/hooks/useSessionBrowser.test.js +0 -277
- package/dist/src/ui/hooks/useSessionBrowser.test.js.map +0 -1
- package/dist/src/ui/hooks/useSessionResume.test.d.ts +0 -6
- package/dist/src/ui/hooks/useSessionResume.test.js +0 -402
- package/dist/src/ui/hooks/useSessionResume.test.js.map +0 -1
- package/dist/src/ui/hooks/useSettingsNavigation.test.d.ts +0 -6
- package/dist/src/ui/hooks/useSettingsNavigation.test.js +0 -87
- package/dist/src/ui/hooks/useSettingsNavigation.test.js.map +0 -1
- package/dist/src/ui/hooks/useShellCompletion.test.d.ts +0 -6
- package/dist/src/ui/hooks/useShellCompletion.test.js +0 -354
- package/dist/src/ui/hooks/useShellCompletion.test.js.map +0 -1
- package/dist/src/ui/hooks/useShellHistory.test.d.ts +0 -6
- package/dist/src/ui/hooks/useShellHistory.test.js +0 -226
- package/dist/src/ui/hooks/useShellHistory.test.js.map +0 -1
- package/dist/src/ui/hooks/useShellInactivityStatus.test.d.ts +0 -6
- package/dist/src/ui/hooks/useShellInactivityStatus.test.js +0 -84
- package/dist/src/ui/hooks/useShellInactivityStatus.test.js.map +0 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.d.ts +0 -10
- package/dist/src/ui/hooks/useSlashCompletion.test.js +0 -977
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +0 -1
- package/dist/src/ui/hooks/useSnowfall.test.d.ts +0 -6
- package/dist/src/ui/hooks/useSnowfall.test.js +0 -92
- package/dist/src/ui/hooks/useSnowfall.test.js.map +0 -1
- package/dist/src/ui/hooks/useSuspend.test.d.ts +0 -6
- package/dist/src/ui/hooks/useSuspend.test.js +0 -136
- package/dist/src/ui/hooks/useSuspend.test.js.map +0 -1
- package/dist/src/ui/hooks/useTabbedNavigation.test.d.ts +0 -6
- package/dist/src/ui/hooks/useTabbedNavigation.test.js +0 -243
- package/dist/src/ui/hooks/useTabbedNavigation.test.js.map +0 -1
- package/dist/src/ui/hooks/useTerminalTheme.test.d.ts +0 -6
- package/dist/src/ui/hooks/useTerminalTheme.test.js +0 -169
- package/dist/src/ui/hooks/useTerminalTheme.test.js.map +0 -1
- package/dist/src/ui/hooks/useTimer.test.d.ts +0 -6
- package/dist/src/ui/hooks/useTimer.test.js +0 -119
- package/dist/src/ui/hooks/useTimer.test.js.map +0 -1
- package/dist/src/ui/hooks/useTips.test.d.ts +0 -6
- package/dist/src/ui/hooks/useTips.test.js +0 -33
- package/dist/src/ui/hooks/useTips.test.js.map +0 -1
- package/dist/src/ui/hooks/useToolScheduler.test.d.ts +0 -6
- package/dist/src/ui/hooks/useToolScheduler.test.js +0 -534
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +0 -1
- package/dist/src/ui/hooks/useTurnActivityMonitor.test.d.ts +0 -6
- package/dist/src/ui/hooks/useTurnActivityMonitor.test.js +0 -99
- package/dist/src/ui/hooks/useTurnActivityMonitor.test.js.map +0 -1
- package/dist/src/ui/hooks/vim-passthrough.test.d.ts +0 -6
- package/dist/src/ui/hooks/vim-passthrough.test.js +0 -84
- package/dist/src/ui/hooks/vim-passthrough.test.js.map +0 -1
- package/dist/src/ui/hooks/vim.test.d.ts +0 -6
- package/dist/src/ui/hooks/vim.test.js +0 -2156
- package/dist/src/ui/hooks/vim.test.js.map +0 -1
- package/dist/src/ui/key/keyBindings.test.d.ts +0 -6
- package/dist/src/ui/key/keyBindings.test.js +0 -225
- package/dist/src/ui/key/keyBindings.test.js.map +0 -1
- package/dist/src/ui/key/keyMatchers.test.d.ts +0 -6
- package/dist/src/ui/key/keyMatchers.test.js +0 -524
- package/dist/src/ui/key/keyMatchers.test.js.map +0 -1
- package/dist/src/ui/key/keybindingUtils.test.d.ts +0 -6
- package/dist/src/ui/key/keybindingUtils.test.js +0 -121
- package/dist/src/ui/key/keybindingUtils.test.js.map +0 -1
- package/dist/src/ui/layouts/DefaultAppLayout.test.d.ts +0 -6
- package/dist/src/ui/layouts/DefaultAppLayout.test.js +0 -126
- package/dist/src/ui/layouts/DefaultAppLayout.test.js.map +0 -1
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.test.d.ts +0 -6
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.test.js +0 -134
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.test.js.map +0 -1
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.test.d.ts +0 -6
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.test.js +0 -43
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.test.js.map +0 -1
- package/dist/src/ui/privacy/GeminiPrivacyNotice.test.d.ts +0 -6
- package/dist/src/ui/privacy/GeminiPrivacyNotice.test.js +0 -43
- package/dist/src/ui/privacy/GeminiPrivacyNotice.test.js.map +0 -1
- package/dist/src/ui/privacy/PrivacyNotice.test.d.ts +0 -6
- package/dist/src/ui/privacy/PrivacyNotice.test.js +0 -63
- package/dist/src/ui/privacy/PrivacyNotice.test.js.map +0 -1
- package/dist/src/ui/state/extensions.test.d.ts +0 -6
- package/dist/src/ui/state/extensions.test.js +0 -219
- package/dist/src/ui/state/extensions.test.js.map +0 -1
- package/dist/src/ui/themes/color-utils.test.d.ts +0 -6
- package/dist/src/ui/themes/color-utils.test.js +0 -326
- package/dist/src/ui/themes/color-utils.test.js.map +0 -1
- package/dist/src/ui/themes/theme-manager.test.d.ts +0 -6
- package/dist/src/ui/themes/theme-manager.test.js +0 -274
- package/dist/src/ui/themes/theme-manager.test.js.map +0 -1
- package/dist/src/ui/themes/theme.test.d.ts +0 -6
- package/dist/src/ui/themes/theme.test.js +0 -171
- package/dist/src/ui/themes/theme.test.js.map +0 -1
- package/dist/src/ui/utils/CodeColorizer.test.d.ts +0 -6
- package/dist/src/ui/utils/CodeColorizer.test.js +0 -74
- package/dist/src/ui/utils/CodeColorizer.test.js.map +0 -1
- package/dist/src/ui/utils/ConsolePatcher.test.d.ts +0 -6
- package/dist/src/ui/utils/ConsolePatcher.test.js +0 -199
- package/dist/src/ui/utils/ConsolePatcher.test.js.map +0 -1
- package/dist/src/ui/utils/MarkdownDisplay.test.d.ts +0 -6
- package/dist/src/ui/utils/MarkdownDisplay.test.js +0 -175
- package/dist/src/ui/utils/MarkdownDisplay.test.js.map +0 -1
- package/dist/src/ui/utils/TableRenderer.test.d.ts +0 -1
- package/dist/src/ui/utils/TableRenderer.test.js +0 -396
- package/dist/src/ui/utils/TableRenderer.test.js.map +0 -1
- package/dist/src/ui/utils/antigravityUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/antigravityUtils.test.js +0 -54
- package/dist/src/ui/utils/antigravityUtils.test.js.map +0 -1
- package/dist/src/ui/utils/borderStyles.test.d.ts +0 -6
- package/dist/src/ui/utils/borderStyles.test.js +0 -172
- package/dist/src/ui/utils/borderStyles.test.js.map +0 -1
- package/dist/src/ui/utils/clipboardUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/clipboardUtils.test.js +0 -442
- package/dist/src/ui/utils/clipboardUtils.test.js.map +0 -1
- package/dist/src/ui/utils/clipboardUtils.windows.test.d.ts +0 -6
- package/dist/src/ui/utils/clipboardUtils.windows.test.js +0 -56
- package/dist/src/ui/utils/clipboardUtils.windows.test.js.map +0 -1
- package/dist/src/ui/utils/commandUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/commandUtils.test.js +0 -511
- package/dist/src/ui/utils/commandUtils.test.js.map +0 -1
- package/dist/src/ui/utils/computeStats.test.d.ts +0 -6
- package/dist/src/ui/utils/computeStats.test.js +0 -279
- package/dist/src/ui/utils/computeStats.test.js.map +0 -1
- package/dist/src/ui/utils/directoryUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/directoryUtils.test.js +0 -239
- package/dist/src/ui/utils/directoryUtils.test.js.map +0 -1
- package/dist/src/ui/utils/displayUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/displayUtils.test.js +0 -61
- package/dist/src/ui/utils/displayUtils.test.js.map +0 -1
- package/dist/src/ui/utils/formatters.test.d.ts +0 -6
- package/dist/src/ui/utils/formatters.test.js +0 -152
- package/dist/src/ui/utils/formatters.test.js.map +0 -1
- package/dist/src/ui/utils/highlight.test.d.ts +0 -6
- package/dist/src/ui/utils/highlight.test.js +0 -205
- package/dist/src/ui/utils/highlight.test.js.map +0 -1
- package/dist/src/ui/utils/input.test.d.ts +0 -6
- package/dist/src/ui/utils/input.test.js +0 -44
- package/dist/src/ui/utils/input.test.js.map +0 -1
- package/dist/src/ui/utils/latexToUnicode.test.d.ts +0 -6
- package/dist/src/ui/utils/latexToUnicode.test.js +0 -222
- package/dist/src/ui/utils/latexToUnicode.test.js.map +0 -1
- package/dist/src/ui/utils/markdownParsingUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/markdownParsingUtils.test.js +0 -201
- package/dist/src/ui/utils/markdownParsingUtils.test.js.map +0 -1
- package/dist/src/ui/utils/markdownUtilities.test.d.ts +0 -6
- package/dist/src/ui/utils/markdownUtilities.test.js +0 -42
- package/dist/src/ui/utils/markdownUtilities.test.js.map +0 -1
- package/dist/src/ui/utils/memorySnapshot.test.d.ts +0 -6
- package/dist/src/ui/utils/memorySnapshot.test.js +0 -62
- package/dist/src/ui/utils/memorySnapshot.test.js.map +0 -1
- package/dist/src/ui/utils/mouse.test.d.ts +0 -6
- package/dist/src/ui/utils/mouse.test.js +0 -136
- package/dist/src/ui/utils/mouse.test.js.map +0 -1
- package/dist/src/ui/utils/pendingAttentionNotification.test.d.ts +0 -6
- package/dist/src/ui/utils/pendingAttentionNotification.test.js +0 -79
- package/dist/src/ui/utils/pendingAttentionNotification.test.js.map +0 -1
- package/dist/src/ui/utils/rewindFileOps.test.d.ts +0 -6
- package/dist/src/ui/utils/rewindFileOps.test.js +0 -375
- package/dist/src/ui/utils/rewindFileOps.test.js.map +0 -1
- package/dist/src/ui/utils/terminalCapabilityManager.test.d.ts +0 -6
- package/dist/src/ui/utils/terminalCapabilityManager.test.js +0 -400
- package/dist/src/ui/utils/terminalCapabilityManager.test.js.map +0 -1
- package/dist/src/ui/utils/terminalSetup.test.d.ts +0 -6
- package/dist/src/ui/utils/terminalSetup.test.js +0 -201
- package/dist/src/ui/utils/terminalSetup.test.js.map +0 -1
- package/dist/src/ui/utils/textOutput.test.d.ts +0 -6
- package/dist/src/ui/utils/textOutput.test.js +0 -80
- package/dist/src/ui/utils/textOutput.test.js.map +0 -1
- package/dist/src/ui/utils/textUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/textUtils.test.js +0 -430
- package/dist/src/ui/utils/textUtils.test.js.map +0 -1
- package/dist/src/ui/utils/toolLayoutUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/toolLayoutUtils.test.js +0 -187
- package/dist/src/ui/utils/toolLayoutUtils.test.js.map +0 -1
- package/dist/src/ui/utils/ui-sizing.test.d.ts +0 -6
- package/dist/src/ui/utils/ui-sizing.test.js +0 -25
- package/dist/src/ui/utils/ui-sizing.test.js.map +0 -1
- package/dist/src/ui/utils/updateCheck.test.d.ts +0 -6
- package/dist/src/ui/utils/updateCheck.test.js +0 -207
- package/dist/src/ui/utils/updateCheck.test.js.map +0 -1
- package/dist/src/ui/utils/urlSecurityUtils.test.d.ts +0 -6
- package/dist/src/ui/utils/urlSecurityUtils.test.js +0 -49
- package/dist/src/ui/utils/urlSecurityUtils.test.js.map +0 -1
- package/dist/src/utils/activityLogger.test.d.ts +0 -6
- package/dist/src/utils/activityLogger.test.js +0 -196
- package/dist/src/utils/activityLogger.test.js.map +0 -1
- package/dist/src/utils/agentSettings.test.d.ts +0 -6
- package/dist/src/utils/agentSettings.test.js +0 -111
- package/dist/src/utils/agentSettings.test.js.map +0 -1
- package/dist/src/utils/agentUtils.test.d.ts +0 -6
- package/dist/src/utils/agentUtils.test.js +0 -121
- package/dist/src/utils/agentUtils.test.js.map +0 -1
- package/dist/src/utils/cleanup.test.d.ts +0 -6
- package/dist/src/utils/cleanup.test.js +0 -256
- package/dist/src/utils/cleanup.test.js.map +0 -1
- package/dist/src/utils/commands.test.d.ts +0 -6
- package/dist/src/utils/commands.test.js +0 -194
- package/dist/src/utils/commands.test.js.map +0 -1
- package/dist/src/utils/commentJson.test.d.ts +0 -6
- package/dist/src/utils/commentJson.test.js +0 -308
- package/dist/src/utils/commentJson.test.js.map +0 -1
- package/dist/src/utils/deepMerge.test.d.ts +0 -6
- package/dist/src/utils/deepMerge.test.js +0 -211
- package/dist/src/utils/deepMerge.test.js.map +0 -1
- package/dist/src/utils/devtoolsService.test.d.ts +0 -6
- package/dist/src/utils/devtoolsService.test.js +0 -346
- package/dist/src/utils/devtoolsService.test.js.map +0 -1
- package/dist/src/utils/dialogScopeUtils.test.d.ts +0 -6
- package/dist/src/utils/dialogScopeUtils.test.js +0 -81
- package/dist/src/utils/dialogScopeUtils.test.js.map +0 -1
- package/dist/src/utils/envVarResolver.test.d.ts +0 -6
- package/dist/src/utils/envVarResolver.test.js +0 -238
- package/dist/src/utils/envVarResolver.test.js.map +0 -1
- package/dist/src/utils/errors.test.d.ts +0 -6
- package/dist/src/utils/errors.test.js +0 -420
- package/dist/src/utils/errors.test.js.map +0 -1
- package/dist/src/utils/events.test.d.ts +0 -6
- package/dist/src/utils/events.test.js +0 -24
- package/dist/src/utils/events.test.js.map +0 -1
- package/dist/src/utils/featureToggleUtils.test.d.ts +0 -6
- package/dist/src/utils/featureToggleUtils.test.js +0 -126
- package/dist/src/utils/featureToggleUtils.test.js.map +0 -1
- package/dist/src/utils/gitUtils.test.d.ts +0 -6
- package/dist/src/utils/gitUtils.test.js +0 -172
- package/dist/src/utils/gitUtils.test.js.map +0 -1
- package/dist/src/utils/handleAutoUpdate.test.d.ts +0 -6
- package/dist/src/utils/handleAutoUpdate.test.js +0 -399
- package/dist/src/utils/handleAutoUpdate.test.js.map +0 -1
- package/dist/src/utils/hookSettings.test.d.ts +0 -6
- package/dist/src/utils/hookSettings.test.js +0 -117
- package/dist/src/utils/hookSettings.test.js.map +0 -1
- package/dist/src/utils/hookUtils.test.d.ts +0 -6
- package/dist/src/utils/hookUtils.test.js +0 -113
- package/dist/src/utils/hookUtils.test.js.map +0 -1
- package/dist/src/utils/installationInfo.test.d.ts +0 -6
- package/dist/src/utils/installationInfo.test.js +0 -322
- package/dist/src/utils/installationInfo.test.js.map +0 -1
- package/dist/src/utils/jsonoutput.test.d.ts +0 -6
- package/dist/src/utils/jsonoutput.test.js +0 -74
- package/dist/src/utils/jsonoutput.test.js.map +0 -1
- package/dist/src/utils/logCleanup.test.d.ts +0 -6
- package/dist/src/utils/logCleanup.test.js +0 -87
- package/dist/src/utils/logCleanup.test.js.map +0 -1
- package/dist/src/utils/math.test.d.ts +0 -6
- package/dist/src/utils/math.test.js +0 -23
- package/dist/src/utils/math.test.js.map +0 -1
- package/dist/src/utils/persistentState.test.d.ts +0 -6
- package/dist/src/utils/persistentState.test.js +0 -68
- package/dist/src/utils/persistentState.test.js.map +0 -1
- package/dist/src/utils/processUtils.test.d.ts +0 -6
- package/dist/src/utils/processUtils.test.js +0 -150
- package/dist/src/utils/processUtils.test.js.map +0 -1
- package/dist/src/utils/readStdin.test.d.ts +0 -6
- package/dist/src/utils/readStdin.test.js +0 -149
- package/dist/src/utils/readStdin.test.js.map +0 -1
- package/dist/src/utils/readStdin_safety.test.d.ts +0 -6
- package/dist/src/utils/readStdin_safety.test.js +0 -68
- package/dist/src/utils/readStdin_safety.test.js.map +0 -1
- package/dist/src/utils/relaunch.test.d.ts +0 -6
- package/dist/src/utils/relaunch.test.js +0 -275
- package/dist/src/utils/relaunch.test.js.map +0 -1
- package/dist/src/utils/resolvePath.test.d.ts +0 -6
- package/dist/src/utils/resolvePath.test.js +0 -34
- package/dist/src/utils/resolvePath.test.js.map +0 -1
- package/dist/src/utils/sandbox.test.d.ts +0 -6
- package/dist/src/utils/sandbox.test.js +0 -725
- package/dist/src/utils/sandbox.test.js.map +0 -1
- package/dist/src/utils/sandboxUtils.test.d.ts +0 -6
- package/dist/src/utils/sandboxUtils.test.js +0 -190
- package/dist/src/utils/sandboxUtils.test.js.map +0 -1
- package/dist/src/utils/sessionCleanup.integration.test.d.ts +0 -6
- package/dist/src/utils/sessionCleanup.integration.test.js +0 -276
- package/dist/src/utils/sessionCleanup.integration.test.js.map +0 -1
- package/dist/src/utils/sessionCleanup.test.d.ts +0 -6
- package/dist/src/utils/sessionCleanup.test.js +0 -829
- package/dist/src/utils/sessionCleanup.test.js.map +0 -1
- package/dist/src/utils/sessionUtils.test.d.ts +0 -6
- package/dist/src/utils/sessionUtils.test.js +0 -815
- package/dist/src/utils/sessionUtils.test.js.map +0 -1
- package/dist/src/utils/sessions.test.d.ts +0 -6
- package/dist/src/utils/sessions.test.js +0 -580
- package/dist/src/utils/sessions.test.js.map +0 -1
- package/dist/src/utils/settingsUtils.test.d.ts +0 -6
- package/dist/src/utils/settingsUtils.test.js +0 -673
- package/dist/src/utils/settingsUtils.test.js.map +0 -1
- package/dist/src/utils/skillSettings.test.d.ts +0 -6
- package/dist/src/utils/skillSettings.test.js +0 -142
- package/dist/src/utils/skillSettings.test.js.map +0 -1
- package/dist/src/utils/skillUtils.test.d.ts +0 -6
- package/dist/src/utils/skillUtils.test.js +0 -248
- package/dist/src/utils/skillUtils.test.js.map +0 -1
- package/dist/src/utils/startupWarnings.test.d.ts +0 -6
- package/dist/src/utils/startupWarnings.test.js +0 -61
- package/dist/src/utils/startupWarnings.test.js.map +0 -1
- package/dist/src/utils/terminalNotifications.test.d.ts +0 -6
- package/dist/src/utils/terminalNotifications.test.js +0 -219
- package/dist/src/utils/terminalNotifications.test.js.map +0 -1
- package/dist/src/utils/terminalTheme.test.d.ts +0 -6
- package/dist/src/utils/terminalTheme.test.js +0 -91
- package/dist/src/utils/terminalTheme.test.js.map +0 -1
- package/dist/src/utils/tierUtils.test.d.ts +0 -6
- package/dist/src/utils/tierUtils.test.js +0 -25
- package/dist/src/utils/tierUtils.test.js.map +0 -1
- package/dist/src/utils/toolOutputCleanup.test.d.ts +0 -6
- package/dist/src/utils/toolOutputCleanup.test.js +0 -280
- package/dist/src/utils/toolOutputCleanup.test.js.map +0 -1
- package/dist/src/utils/updateEventEmitter.test.d.ts +0 -6
- package/dist/src/utils/updateEventEmitter.test.js +0 -18
- package/dist/src/utils/updateEventEmitter.test.js.map +0 -1
- package/dist/src/utils/userStartupWarnings.test.d.ts +0 -6
- package/dist/src/utils/userStartupWarnings.test.js +0 -225
- package/dist/src/utils/userStartupWarnings.test.js.map +0 -1
- package/dist/src/utils/windowTitle.test.d.ts +0 -6
- package/dist/src/utils/windowTitle.test.js +0 -216
- package/dist/src/utils/windowTitle.test.js.map +0 -1
- package/dist/src/utils/worktreeSetup.test.d.ts +0 -6
- package/dist/src/utils/worktreeSetup.test.js +0 -89
- package/dist/src/utils/worktreeSetup.test.js.map +0 -1
- package/dist/src/validateNonInterActiveAuth.test.d.ts +0 -6
- package/dist/src/validateNonInterActiveAuth.test.js +0 -319
- package/dist/src/validateNonInterActiveAuth.test.js.map +0 -1
|
@@ -1,2660 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
/// <reference types="vitest/globals" />
|
|
7
|
-
// Mock 'os' first.
|
|
8
|
-
import * as osActual from 'node:os'; // Import for type info for the mock factory
|
|
9
|
-
vi.mock('os', async (importOriginal) => {
|
|
10
|
-
const actualOs = await importOriginal();
|
|
11
|
-
return {
|
|
12
|
-
...actualOs,
|
|
13
|
-
homedir: vi.fn(() => path.resolve('/mock/home/user')),
|
|
14
|
-
platform: vi.fn(() => 'linux'),
|
|
15
|
-
};
|
|
16
|
-
});
|
|
17
|
-
// Mock './settings.js' to ensure it uses the mocked 'os.homedir()' for its internal constants.
|
|
18
|
-
vi.mock('./settings.js', async (importActual) => {
|
|
19
|
-
const originalModule = await importActual();
|
|
20
|
-
return {
|
|
21
|
-
__esModule: true, // Ensure correct module shape
|
|
22
|
-
...originalModule, // Re-export all original members
|
|
23
|
-
// We are relying on originalModule's USER_SETTINGS_PATH being constructed with mocked os.homedir()
|
|
24
|
-
};
|
|
25
|
-
});
|
|
26
|
-
// Mock trustedFolders
|
|
27
|
-
import * as trustedFolders from './trustedFolders.js';
|
|
28
|
-
vi.mock('./trustedFolders.js', () => ({
|
|
29
|
-
isWorkspaceTrusted: vi.fn(),
|
|
30
|
-
isFolderTrustEnabled: vi.fn(),
|
|
31
|
-
loadTrustedFolders: vi.fn(),
|
|
32
|
-
}));
|
|
33
|
-
vi.mock('./settingsSchema.js', async (importOriginal) => {
|
|
34
|
-
const actual = await importOriginal();
|
|
35
|
-
return {
|
|
36
|
-
...actual,
|
|
37
|
-
getSettingsSchema: vi.fn(actual.getSettingsSchema),
|
|
38
|
-
};
|
|
39
|
-
});
|
|
40
|
-
// NOW import everything else, including the (now effectively re-exported) settings.js
|
|
41
|
-
import * as path from 'node:path'; // Restored for MOCK_WORKSPACE_SETTINGS_PATH
|
|
42
|
-
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
|
|
43
|
-
import * as fs from 'node:fs'; // fs will be mocked separately
|
|
44
|
-
import stripJsonComments from 'strip-json-comments'; // Will be mocked separately
|
|
45
|
-
import { isWorkspaceTrusted } from './trustedFolders.js';
|
|
46
|
-
// These imports will get the versions from the vi.mock('./settings.js', ...) factory.
|
|
47
|
-
import { loadSettings, USER_SETTINGS_PATH, // This IS the mocked path.
|
|
48
|
-
getSystemSettingsPath, getSystemDefaultsPath, saveSettings, getDefaultsFromSchema, loadEnvironment, migrateDeprecatedSettings, SettingScope, LoadedSettings, sanitizeEnvVar, createTestMergedSettings, resetSettingsCacheForTesting, } from './settings.js';
|
|
49
|
-
import { FatalConfigError, GEMINI_DIR, Storage, AuthType, } from '@google/gemini-cli-core';
|
|
50
|
-
import { updateSettingsFilePreservingFormat } from '../utils/commentJson.js';
|
|
51
|
-
import { getSettingsSchema, MergeStrategy, } from './settingsSchema.js';
|
|
52
|
-
import { createMockSettings } from '../test-utils/settings.js';
|
|
53
|
-
const MOCK_WORKSPACE_DIR = path.resolve(path.resolve('/mock/workspace'));
|
|
54
|
-
// Use the (mocked) GEMINI_DIR for consistency
|
|
55
|
-
const MOCK_WORKSPACE_SETTINGS_PATH = path.join(MOCK_WORKSPACE_DIR, GEMINI_DIR, 'settings.json');
|
|
56
|
-
// Helper to normalize paths for test assertions, making them OS-agnostic
|
|
57
|
-
const normalizePath = (p) => path.normalize(p.toString());
|
|
58
|
-
vi.mock('fs', async (importOriginal) => {
|
|
59
|
-
// Get all the functions from the real 'fs' module
|
|
60
|
-
const actualFs = await importOriginal();
|
|
61
|
-
return {
|
|
62
|
-
...actualFs, // Keep all the real functions
|
|
63
|
-
// Now, just override the ones we need for the test
|
|
64
|
-
existsSync: vi.fn(),
|
|
65
|
-
readFileSync: vi.fn(),
|
|
66
|
-
writeFileSync: vi.fn(),
|
|
67
|
-
mkdirSync: vi.fn(),
|
|
68
|
-
realpathSync: vi.fn((p) => p),
|
|
69
|
-
};
|
|
70
|
-
});
|
|
71
|
-
vi.mock('./extension.js');
|
|
72
|
-
const mockCoreEvents = vi.hoisted(() => ({
|
|
73
|
-
emitFeedback: vi.fn(),
|
|
74
|
-
emitSettingsChanged: vi.fn(),
|
|
75
|
-
}));
|
|
76
|
-
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
|
77
|
-
const actual = await importOriginal();
|
|
78
|
-
const os = await import('node:os');
|
|
79
|
-
const pathMod = await import('node:path');
|
|
80
|
-
const fsMod = await import('node:fs');
|
|
81
|
-
// Helper to resolve paths using the test's mocked environment
|
|
82
|
-
const testResolve = (p) => {
|
|
83
|
-
if (!p)
|
|
84
|
-
return '';
|
|
85
|
-
try {
|
|
86
|
-
// Use the mocked fs.realpathSync if available, otherwise fallback
|
|
87
|
-
return fsMod.realpathSync(pathMod.resolve(p));
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
return pathMod.resolve(p);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
// Create a smarter mock for isWorkspaceHomeDir
|
|
94
|
-
vi.spyOn(actual.Storage.prototype, 'isWorkspaceHomeDir').mockImplementation(function () {
|
|
95
|
-
const target = testResolve(pathMod.dirname(this.getGeminiDir()));
|
|
96
|
-
// Pick up the mocked home directory specifically from the 'os' mock
|
|
97
|
-
const home = testResolve(os.homedir());
|
|
98
|
-
return actual.normalizePath(target) === actual.normalizePath(home);
|
|
99
|
-
});
|
|
100
|
-
return {
|
|
101
|
-
...actual,
|
|
102
|
-
coreEvents: mockCoreEvents,
|
|
103
|
-
homedir: vi.fn(() => os.homedir()),
|
|
104
|
-
};
|
|
105
|
-
});
|
|
106
|
-
vi.mock('../utils/commentJson.js', () => ({
|
|
107
|
-
updateSettingsFilePreservingFormat: vi.fn(),
|
|
108
|
-
}));
|
|
109
|
-
vi.mock('strip-json-comments', () => ({
|
|
110
|
-
default: vi.fn((content) => content),
|
|
111
|
-
}));
|
|
112
|
-
describe('Settings Loading and Merging', () => {
|
|
113
|
-
let mockFsExistsSync;
|
|
114
|
-
let mockStripJsonComments;
|
|
115
|
-
let mockFsMkdirSync;
|
|
116
|
-
beforeEach(() => {
|
|
117
|
-
vi.resetAllMocks();
|
|
118
|
-
resetSettingsCacheForTesting();
|
|
119
|
-
mockFsExistsSync = vi.mocked(fs.existsSync);
|
|
120
|
-
mockFsMkdirSync = vi.mocked(fs.mkdirSync);
|
|
121
|
-
mockStripJsonComments = vi.mocked(stripJsonComments);
|
|
122
|
-
vi.mocked(osActual.homedir).mockReturnValue(path.resolve('/mock/home/user'));
|
|
123
|
-
mockStripJsonComments.mockImplementation((jsonString) => jsonString);
|
|
124
|
-
mockFsExistsSync.mockReturnValue(false);
|
|
125
|
-
fs.readFileSync.mockReturnValue('{}'); // Return valid empty JSON
|
|
126
|
-
mockFsMkdirSync.mockImplementation(() => undefined);
|
|
127
|
-
vi.spyOn(trustedFolders, 'isWorkspaceTrusted').mockReturnValue({
|
|
128
|
-
isTrusted: true,
|
|
129
|
-
source: 'file',
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
afterEach(() => {
|
|
133
|
-
vi.restoreAllMocks();
|
|
134
|
-
vi.unstubAllEnvs();
|
|
135
|
-
});
|
|
136
|
-
describe('loadSettings', () => {
|
|
137
|
-
it.each([
|
|
138
|
-
{
|
|
139
|
-
scope: 'system',
|
|
140
|
-
path: getSystemSettingsPath(),
|
|
141
|
-
content: {
|
|
142
|
-
ui: { theme: 'system-default' },
|
|
143
|
-
tools: { sandbox: false },
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
scope: 'user',
|
|
148
|
-
path: USER_SETTINGS_PATH,
|
|
149
|
-
content: {
|
|
150
|
-
ui: { theme: 'dark' },
|
|
151
|
-
context: { fileName: 'USER_CONTEXT.md' },
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
scope: 'workspace',
|
|
156
|
-
path: MOCK_WORKSPACE_SETTINGS_PATH,
|
|
157
|
-
content: {
|
|
158
|
-
tools: { sandbox: true },
|
|
159
|
-
context: { fileName: 'WORKSPACE_CONTEXT.md' },
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
])('should load $scope settings if only $scope file exists', ({ scope, path: p, content }) => {
|
|
163
|
-
mockFsExistsSync.mockImplementation((pathLike) => path.normalize(pathLike.toString()) === path.normalize(p));
|
|
164
|
-
fs.readFileSync.mockImplementation((pathDesc) => {
|
|
165
|
-
if (path.normalize(pathDesc.toString()) === path.normalize(p))
|
|
166
|
-
return JSON.stringify(content);
|
|
167
|
-
return '{}';
|
|
168
|
-
});
|
|
169
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
170
|
-
expect(fs.readFileSync).toHaveBeenCalledWith(expect.stringContaining(path.basename(p)), 'utf-8');
|
|
171
|
-
expect(settings[scope].settings).toEqual(content);
|
|
172
|
-
expect(settings.merged).toMatchObject(content);
|
|
173
|
-
});
|
|
174
|
-
it('should merge system, user and workspace settings, with system taking precedence over workspace, and workspace over user', () => {
|
|
175
|
-
mockFsExistsSync.mockImplementation((p) => {
|
|
176
|
-
const normP = path.normalize(p.toString());
|
|
177
|
-
return (normP === path.normalize(getSystemSettingsPath()) ||
|
|
178
|
-
normP === path.normalize(USER_SETTINGS_PATH) ||
|
|
179
|
-
normP === path.normalize(MOCK_WORKSPACE_SETTINGS_PATH));
|
|
180
|
-
});
|
|
181
|
-
const systemSettingsContent = {
|
|
182
|
-
ui: {
|
|
183
|
-
theme: 'system-theme',
|
|
184
|
-
},
|
|
185
|
-
tools: {
|
|
186
|
-
sandbox: false,
|
|
187
|
-
},
|
|
188
|
-
mcp: {
|
|
189
|
-
allowed: ['server1', 'server2'],
|
|
190
|
-
},
|
|
191
|
-
telemetry: { enabled: false },
|
|
192
|
-
};
|
|
193
|
-
const userSettingsContent = {
|
|
194
|
-
ui: {
|
|
195
|
-
theme: 'dark',
|
|
196
|
-
},
|
|
197
|
-
tools: {
|
|
198
|
-
sandbox: true,
|
|
199
|
-
},
|
|
200
|
-
context: {
|
|
201
|
-
fileName: 'USER_CONTEXT.md',
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
const workspaceSettingsContent = {
|
|
205
|
-
tools: {
|
|
206
|
-
sandbox: false,
|
|
207
|
-
core: ['tool1'],
|
|
208
|
-
},
|
|
209
|
-
context: {
|
|
210
|
-
fileName: 'WORKSPACE_CONTEXT.md',
|
|
211
|
-
},
|
|
212
|
-
mcp: {
|
|
213
|
-
allowed: ['server1', 'server2', 'server3'],
|
|
214
|
-
},
|
|
215
|
-
};
|
|
216
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
217
|
-
const normP = path.normalize(p.toString());
|
|
218
|
-
if (normP === path.normalize(getSystemSettingsPath()))
|
|
219
|
-
return JSON.stringify(systemSettingsContent);
|
|
220
|
-
if (normP === path.normalize(USER_SETTINGS_PATH))
|
|
221
|
-
return JSON.stringify(userSettingsContent);
|
|
222
|
-
if (normP === path.normalize(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
223
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
224
|
-
return '';
|
|
225
|
-
});
|
|
226
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
227
|
-
expect(settings.system.settings).toEqual(systemSettingsContent);
|
|
228
|
-
expect(settings.user.settings).toEqual(userSettingsContent);
|
|
229
|
-
expect(settings.workspace.settings).toEqual(workspaceSettingsContent);
|
|
230
|
-
expect(settings.merged).toMatchObject({
|
|
231
|
-
ui: {
|
|
232
|
-
theme: 'system-theme',
|
|
233
|
-
},
|
|
234
|
-
tools: {
|
|
235
|
-
sandbox: false,
|
|
236
|
-
core: ['tool1'],
|
|
237
|
-
},
|
|
238
|
-
telemetry: { enabled: false },
|
|
239
|
-
context: {
|
|
240
|
-
fileName: 'WORKSPACE_CONTEXT.md',
|
|
241
|
-
},
|
|
242
|
-
mcp: {
|
|
243
|
-
allowed: ['server1', 'server2'],
|
|
244
|
-
},
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
it('should merge all settings files with the correct precedence', () => {
|
|
248
|
-
// Mock schema to test defaults application
|
|
249
|
-
const mockSchema = {
|
|
250
|
-
ui: { type: 'object', default: {}, properties: {} },
|
|
251
|
-
tools: { type: 'object', default: {}, properties: {} },
|
|
252
|
-
context: {
|
|
253
|
-
type: 'object',
|
|
254
|
-
default: {},
|
|
255
|
-
properties: {
|
|
256
|
-
discoveryMaxDirs: { type: 'number', default: 200 },
|
|
257
|
-
includeDirectories: {
|
|
258
|
-
type: 'array',
|
|
259
|
-
default: [],
|
|
260
|
-
mergeStrategy: MergeStrategy.CONCAT,
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
mcpServers: { type: 'object', default: {} },
|
|
265
|
-
};
|
|
266
|
-
getSettingsSchema.mockReturnValue(mockSchema);
|
|
267
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
268
|
-
const systemDefaultsContent = {
|
|
269
|
-
ui: {
|
|
270
|
-
theme: 'default-theme',
|
|
271
|
-
},
|
|
272
|
-
tools: {
|
|
273
|
-
sandbox: true,
|
|
274
|
-
},
|
|
275
|
-
telemetry: true,
|
|
276
|
-
context: {
|
|
277
|
-
includeDirectories: ['/system/defaults/dir'],
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
const userSettingsContent = {
|
|
281
|
-
ui: {
|
|
282
|
-
theme: 'user-theme',
|
|
283
|
-
},
|
|
284
|
-
context: {
|
|
285
|
-
fileName: 'USER_CONTEXT.md',
|
|
286
|
-
includeDirectories: ['/user/dir1', '/user/dir2'],
|
|
287
|
-
},
|
|
288
|
-
};
|
|
289
|
-
const workspaceSettingsContent = {
|
|
290
|
-
tools: {
|
|
291
|
-
sandbox: false,
|
|
292
|
-
},
|
|
293
|
-
context: {
|
|
294
|
-
fileName: 'WORKSPACE_CONTEXT.md',
|
|
295
|
-
includeDirectories: ['/workspace/dir'],
|
|
296
|
-
},
|
|
297
|
-
};
|
|
298
|
-
const systemSettingsContent = {
|
|
299
|
-
ui: {
|
|
300
|
-
theme: 'system-theme',
|
|
301
|
-
},
|
|
302
|
-
telemetry: false,
|
|
303
|
-
context: {
|
|
304
|
-
includeDirectories: ['/system/dir'],
|
|
305
|
-
},
|
|
306
|
-
};
|
|
307
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
308
|
-
if (normalizePath(p) === normalizePath(getSystemDefaultsPath()))
|
|
309
|
-
return JSON.stringify(systemDefaultsContent);
|
|
310
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath()))
|
|
311
|
-
return JSON.stringify(systemSettingsContent);
|
|
312
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
313
|
-
return JSON.stringify(userSettingsContent);
|
|
314
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
315
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
316
|
-
return '';
|
|
317
|
-
});
|
|
318
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
319
|
-
expect(settings.systemDefaults.settings).toEqual(systemDefaultsContent);
|
|
320
|
-
expect(settings.system.settings).toEqual(systemSettingsContent);
|
|
321
|
-
expect(settings.user.settings).toEqual(userSettingsContent);
|
|
322
|
-
expect(settings.workspace.settings).toEqual(workspaceSettingsContent);
|
|
323
|
-
expect(settings.merged).toEqual({
|
|
324
|
-
context: {
|
|
325
|
-
discoveryMaxDirs: 200,
|
|
326
|
-
includeDirectories: [
|
|
327
|
-
'/system/defaults/dir',
|
|
328
|
-
'/user/dir1',
|
|
329
|
-
'/user/dir2',
|
|
330
|
-
'/workspace/dir',
|
|
331
|
-
'/system/dir',
|
|
332
|
-
],
|
|
333
|
-
fileName: 'WORKSPACE_CONTEXT.md',
|
|
334
|
-
},
|
|
335
|
-
mcpServers: {},
|
|
336
|
-
ui: { theme: 'system-theme' },
|
|
337
|
-
tools: { sandbox: false },
|
|
338
|
-
telemetry: false,
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
it('should use folderTrust from workspace settings when trusted', () => {
|
|
342
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
343
|
-
const userSettingsContent = {
|
|
344
|
-
security: {
|
|
345
|
-
folderTrust: {
|
|
346
|
-
enabled: true,
|
|
347
|
-
},
|
|
348
|
-
},
|
|
349
|
-
};
|
|
350
|
-
const workspaceSettingsContent = {
|
|
351
|
-
security: {
|
|
352
|
-
folderTrust: {
|
|
353
|
-
enabled: false, // This should be used
|
|
354
|
-
},
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
const systemSettingsContent = {
|
|
358
|
-
// No folderTrust here
|
|
359
|
-
};
|
|
360
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
361
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath()))
|
|
362
|
-
return JSON.stringify(systemSettingsContent);
|
|
363
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
364
|
-
return JSON.stringify(userSettingsContent);
|
|
365
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
366
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
367
|
-
return '{}';
|
|
368
|
-
});
|
|
369
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
370
|
-
expect(settings.merged.security?.folderTrust?.enabled).toBe(false); // Workspace setting should be used
|
|
371
|
-
});
|
|
372
|
-
it('should resolve environment variables and cast them to correct types before validation', () => {
|
|
373
|
-
vi.stubEnv('TEST_AUTO_THEME', 'false');
|
|
374
|
-
vi.stubEnv('TEST_MAX_TURNS', '15');
|
|
375
|
-
mockFsExistsSync.mockImplementation((p) => path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH));
|
|
376
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
377
|
-
if (path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH)) {
|
|
378
|
-
return JSON.stringify({
|
|
379
|
-
ui: { autoThemeSwitching: '$TEST_AUTO_THEME' },
|
|
380
|
-
model: { maxSessionTurns: '$TEST_MAX_TURNS' },
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
return '{}';
|
|
384
|
-
});
|
|
385
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
386
|
-
expect(settings.merged.ui.autoThemeSwitching).toBe(false);
|
|
387
|
-
expect(settings.merged.model.maxSessionTurns).toBe(15);
|
|
388
|
-
expect(settings.errors).toHaveLength(0);
|
|
389
|
-
});
|
|
390
|
-
it('should use default values from environment variable placeholders', () => {
|
|
391
|
-
vi.stubEnv('TEST_AUTO_THEME', ''); // Should trigger default
|
|
392
|
-
delete process.env['TEST_AUTO_THEME'];
|
|
393
|
-
mockFsExistsSync.mockImplementation((p) => path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH));
|
|
394
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
395
|
-
if (path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH)) {
|
|
396
|
-
return JSON.stringify({
|
|
397
|
-
ui: { autoThemeSwitching: '${TEST_AUTO_THEME:-true}' },
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
return '{}';
|
|
401
|
-
});
|
|
402
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
403
|
-
expect(settings.merged.ui.autoThemeSwitching).toBe(true);
|
|
404
|
-
expect(settings.errors).toHaveLength(0);
|
|
405
|
-
});
|
|
406
|
-
it('should record validation errors if expansion result is invalid', () => {
|
|
407
|
-
vi.stubEnv('TEST_MAX_TURNS', 'not-a-number');
|
|
408
|
-
mockFsExistsSync.mockImplementation((p) => path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH));
|
|
409
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
410
|
-
if (path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH)) {
|
|
411
|
-
return JSON.stringify({
|
|
412
|
-
model: { maxSessionTurns: '$TEST_MAX_TURNS' },
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
return '{}';
|
|
416
|
-
});
|
|
417
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
418
|
-
expect(settings.errors.length).toBeGreaterThan(0);
|
|
419
|
-
expect(settings.errors[0].message).toContain('Expected number, received string');
|
|
420
|
-
// Should fall back to the expanded string value
|
|
421
|
-
expect(settings.merged.model.maxSessionTurns).toBe('not-a-number');
|
|
422
|
-
});
|
|
423
|
-
it('should preserve environment variable placeholders on save', () => {
|
|
424
|
-
vi.stubEnv('TEST_AUTO_THEME', 'true');
|
|
425
|
-
const placeholder = '${TEST_AUTO_THEME:-false}';
|
|
426
|
-
mockFsExistsSync.mockImplementation((p) => path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH));
|
|
427
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
428
|
-
if (path.normalize(p.toString()) === path.normalize(USER_SETTINGS_PATH)) {
|
|
429
|
-
return JSON.stringify({
|
|
430
|
-
ui: { autoThemeSwitching: placeholder },
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
return '{}';
|
|
434
|
-
});
|
|
435
|
-
// Load settings - this will expand the placeholder for runtime use
|
|
436
|
-
const loaded = loadSettings(MOCK_WORKSPACE_DIR);
|
|
437
|
-
expect(loaded.merged.ui.autoThemeSwitching).toBe(true);
|
|
438
|
-
// Verify that the original settings for the user scope still have the placeholder
|
|
439
|
-
const userFile = loaded.forScope(SettingScope.User);
|
|
440
|
-
expect(userFile.originalSettings.ui?.autoThemeSwitching).toBe(placeholder);
|
|
441
|
-
// Save settings - this should use the originalSettings (with placeholders)
|
|
442
|
-
const mockUpdate = vi.mocked(updateSettingsFilePreservingFormat);
|
|
443
|
-
saveSettings(userFile);
|
|
444
|
-
expect(mockUpdate).toHaveBeenCalledWith(USER_SETTINGS_PATH, expect.objectContaining({
|
|
445
|
-
ui: expect.objectContaining({
|
|
446
|
-
autoThemeSwitching: placeholder,
|
|
447
|
-
}),
|
|
448
|
-
}));
|
|
449
|
-
});
|
|
450
|
-
it('should use system folderTrust over user setting', () => {
|
|
451
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
452
|
-
const userSettingsContent = {
|
|
453
|
-
security: {
|
|
454
|
-
folderTrust: {
|
|
455
|
-
enabled: false,
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
};
|
|
459
|
-
const workspaceSettingsContent = {
|
|
460
|
-
security: {
|
|
461
|
-
folderTrust: {
|
|
462
|
-
enabled: true, // This should be ignored
|
|
463
|
-
},
|
|
464
|
-
},
|
|
465
|
-
};
|
|
466
|
-
const systemSettingsContent = {
|
|
467
|
-
security: {
|
|
468
|
-
folderTrust: {
|
|
469
|
-
enabled: true,
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
};
|
|
473
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
474
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath()))
|
|
475
|
-
return JSON.stringify(systemSettingsContent);
|
|
476
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
477
|
-
return JSON.stringify(userSettingsContent);
|
|
478
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
479
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
480
|
-
return '{}';
|
|
481
|
-
});
|
|
482
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
483
|
-
expect(settings.merged.security?.folderTrust?.enabled).toBe(true); // System setting should be used
|
|
484
|
-
});
|
|
485
|
-
it('should not allow user or workspace to override system disableYoloMode', () => {
|
|
486
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
487
|
-
const userSettingsContent = {
|
|
488
|
-
security: {
|
|
489
|
-
disableYoloMode: false,
|
|
490
|
-
disableAlwaysAllow: false,
|
|
491
|
-
},
|
|
492
|
-
};
|
|
493
|
-
const workspaceSettingsContent = {
|
|
494
|
-
security: {
|
|
495
|
-
disableYoloMode: false, // This should be ignored
|
|
496
|
-
disableAlwaysAllow: false, // This should be ignored
|
|
497
|
-
},
|
|
498
|
-
};
|
|
499
|
-
const systemSettingsContent = {
|
|
500
|
-
security: {
|
|
501
|
-
disableYoloMode: true,
|
|
502
|
-
disableAlwaysAllow: true,
|
|
503
|
-
},
|
|
504
|
-
};
|
|
505
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
506
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath()))
|
|
507
|
-
return JSON.stringify(systemSettingsContent);
|
|
508
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
509
|
-
return JSON.stringify(userSettingsContent);
|
|
510
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
511
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
512
|
-
return '{}';
|
|
513
|
-
});
|
|
514
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
515
|
-
expect(settings.merged.security?.disableYoloMode).toBe(true); // System setting should be used
|
|
516
|
-
expect(settings.merged.security?.disableAlwaysAllow).toBe(true); // System setting should be used
|
|
517
|
-
});
|
|
518
|
-
it.each([
|
|
519
|
-
{
|
|
520
|
-
description: 'contextFileName in user settings',
|
|
521
|
-
path: USER_SETTINGS_PATH,
|
|
522
|
-
content: { context: { fileName: 'CUSTOM.md' } },
|
|
523
|
-
expected: { key: 'context.fileName', value: 'CUSTOM.md' },
|
|
524
|
-
},
|
|
525
|
-
{
|
|
526
|
-
description: 'contextFileName in workspace settings',
|
|
527
|
-
path: MOCK_WORKSPACE_SETTINGS_PATH,
|
|
528
|
-
content: { context: { fileName: 'PROJECT_SPECIFIC.md' } },
|
|
529
|
-
expected: { key: 'context.fileName', value: 'PROJECT_SPECIFIC.md' },
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
description: 'excludedProjectEnvVars in user settings',
|
|
533
|
-
path: USER_SETTINGS_PATH,
|
|
534
|
-
content: {
|
|
535
|
-
advanced: { excludedEnvVars: ['DEBUG', 'NODE_ENV', 'CUSTOM_VAR'] },
|
|
536
|
-
},
|
|
537
|
-
expected: {
|
|
538
|
-
key: 'advanced.excludedEnvVars',
|
|
539
|
-
value: ['DEBUG', 'DEBUG_MODE', 'NODE_ENV', 'CUSTOM_VAR'],
|
|
540
|
-
},
|
|
541
|
-
},
|
|
542
|
-
{
|
|
543
|
-
description: 'excludedProjectEnvVars in workspace settings',
|
|
544
|
-
path: MOCK_WORKSPACE_SETTINGS_PATH,
|
|
545
|
-
content: {
|
|
546
|
-
advanced: { excludedEnvVars: ['WORKSPACE_DEBUG', 'WORKSPACE_VAR'] },
|
|
547
|
-
},
|
|
548
|
-
expected: {
|
|
549
|
-
key: 'advanced.excludedEnvVars',
|
|
550
|
-
value: ['DEBUG', 'DEBUG_MODE', 'WORKSPACE_DEBUG', 'WORKSPACE_VAR'],
|
|
551
|
-
},
|
|
552
|
-
},
|
|
553
|
-
])('should handle $description correctly', ({ path, content, expected }) => {
|
|
554
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(path));
|
|
555
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
556
|
-
if (normalizePath(p) === normalizePath(path))
|
|
557
|
-
return JSON.stringify(content);
|
|
558
|
-
return '{}';
|
|
559
|
-
});
|
|
560
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
561
|
-
const keys = expected.key.split('.');
|
|
562
|
-
let result = settings.merged;
|
|
563
|
-
for (const key of keys) {
|
|
564
|
-
result = result[key];
|
|
565
|
-
}
|
|
566
|
-
expect(result).toEqual(expected.value);
|
|
567
|
-
});
|
|
568
|
-
it('should merge excludedProjectEnvVars with workspace taking precedence over user', () => {
|
|
569
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH) ||
|
|
570
|
-
normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH));
|
|
571
|
-
const userSettingsContent = {
|
|
572
|
-
general: {},
|
|
573
|
-
advanced: { excludedEnvVars: ['DEBUG', 'NODE_ENV', 'USER_VAR'] },
|
|
574
|
-
};
|
|
575
|
-
const workspaceSettingsContent = {
|
|
576
|
-
general: {},
|
|
577
|
-
advanced: { excludedEnvVars: ['WORKSPACE_DEBUG', 'WORKSPACE_VAR'] },
|
|
578
|
-
};
|
|
579
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
580
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
581
|
-
return JSON.stringify(userSettingsContent);
|
|
582
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
583
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
584
|
-
return '';
|
|
585
|
-
});
|
|
586
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
587
|
-
expect(settings.user.settings.advanced?.excludedEnvVars).toEqual([
|
|
588
|
-
'DEBUG',
|
|
589
|
-
'NODE_ENV',
|
|
590
|
-
'USER_VAR',
|
|
591
|
-
]);
|
|
592
|
-
expect(settings.workspace.settings.advanced?.excludedEnvVars).toEqual([
|
|
593
|
-
'WORKSPACE_DEBUG',
|
|
594
|
-
'WORKSPACE_VAR',
|
|
595
|
-
]);
|
|
596
|
-
expect(settings.merged.advanced?.excludedEnvVars).toEqual([
|
|
597
|
-
'DEBUG',
|
|
598
|
-
'DEBUG_MODE',
|
|
599
|
-
'NODE_ENV',
|
|
600
|
-
'USER_VAR',
|
|
601
|
-
'WORKSPACE_DEBUG',
|
|
602
|
-
'WORKSPACE_VAR',
|
|
603
|
-
]);
|
|
604
|
-
});
|
|
605
|
-
it('should default contextFileName to undefined if not in any settings file', () => {
|
|
606
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH) ||
|
|
607
|
-
normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH));
|
|
608
|
-
const userSettingsContent = { ui: { theme: 'dark' } };
|
|
609
|
-
const workspaceSettingsContent = { tools: { sandbox: true } };
|
|
610
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
611
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
612
|
-
return JSON.stringify(userSettingsContent);
|
|
613
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
614
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
615
|
-
return '';
|
|
616
|
-
});
|
|
617
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
618
|
-
expect(settings.merged.context?.fileName).toBeUndefined();
|
|
619
|
-
});
|
|
620
|
-
it.each([
|
|
621
|
-
{
|
|
622
|
-
scope: 'user',
|
|
623
|
-
path: USER_SETTINGS_PATH,
|
|
624
|
-
content: { telemetry: { enabled: true } },
|
|
625
|
-
expected: true,
|
|
626
|
-
},
|
|
627
|
-
{
|
|
628
|
-
scope: 'workspace',
|
|
629
|
-
path: MOCK_WORKSPACE_SETTINGS_PATH,
|
|
630
|
-
content: { telemetry: { enabled: false } },
|
|
631
|
-
expected: false,
|
|
632
|
-
},
|
|
633
|
-
])('should load telemetry setting from $scope settings', ({ path, content, expected }) => {
|
|
634
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(path));
|
|
635
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
636
|
-
if (normalizePath(p) === normalizePath(path))
|
|
637
|
-
return JSON.stringify(content);
|
|
638
|
-
return '{}';
|
|
639
|
-
});
|
|
640
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
641
|
-
expect(settings.merged.telemetry?.enabled).toBe(expected);
|
|
642
|
-
});
|
|
643
|
-
it('should prioritize workspace telemetry setting over user setting', () => {
|
|
644
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
645
|
-
const userSettingsContent = { telemetry: { enabled: true } };
|
|
646
|
-
const workspaceSettingsContent = { telemetry: { enabled: false } };
|
|
647
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
648
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
649
|
-
return JSON.stringify(userSettingsContent);
|
|
650
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
651
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
652
|
-
return '{}';
|
|
653
|
-
});
|
|
654
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
655
|
-
expect(settings.merged.telemetry?.enabled).toBe(false);
|
|
656
|
-
});
|
|
657
|
-
it('should have telemetry as undefined if not in any settings file', () => {
|
|
658
|
-
mockFsExistsSync.mockReturnValue(false); // No settings files exist
|
|
659
|
-
fs.readFileSync.mockReturnValue('{}');
|
|
660
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
661
|
-
expect(settings.merged.telemetry).toBeUndefined();
|
|
662
|
-
expect(settings.merged.ui).toBeDefined();
|
|
663
|
-
expect(settings.merged.mcpServers).toEqual({});
|
|
664
|
-
});
|
|
665
|
-
it('should merge MCP servers correctly, with workspace taking precedence', () => {
|
|
666
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH) ||
|
|
667
|
-
normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH));
|
|
668
|
-
const userSettingsContent = {
|
|
669
|
-
mcpServers: {
|
|
670
|
-
'user-server': {
|
|
671
|
-
command: 'user-command',
|
|
672
|
-
args: ['--user-arg'],
|
|
673
|
-
description: 'User MCP server',
|
|
674
|
-
},
|
|
675
|
-
'shared-server': {
|
|
676
|
-
command: 'user-shared-command',
|
|
677
|
-
description: 'User shared server config',
|
|
678
|
-
},
|
|
679
|
-
},
|
|
680
|
-
};
|
|
681
|
-
const workspaceSettingsContent = {
|
|
682
|
-
mcpServers: {
|
|
683
|
-
'workspace-server': {
|
|
684
|
-
command: 'workspace-command',
|
|
685
|
-
args: ['--workspace-arg'],
|
|
686
|
-
description: 'Workspace MCP server',
|
|
687
|
-
},
|
|
688
|
-
'shared-server': {
|
|
689
|
-
command: 'workspace-shared-command',
|
|
690
|
-
description: 'Workspace shared server config',
|
|
691
|
-
},
|
|
692
|
-
},
|
|
693
|
-
};
|
|
694
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
695
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
696
|
-
return JSON.stringify(userSettingsContent);
|
|
697
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
698
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
699
|
-
return '';
|
|
700
|
-
});
|
|
701
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
702
|
-
expect(settings.user.settings).toEqual(userSettingsContent);
|
|
703
|
-
expect(settings.workspace.settings).toEqual(workspaceSettingsContent);
|
|
704
|
-
expect(settings.merged.mcpServers).toEqual({
|
|
705
|
-
'user-server': {
|
|
706
|
-
command: 'user-command',
|
|
707
|
-
args: ['--user-arg'],
|
|
708
|
-
description: 'User MCP server',
|
|
709
|
-
},
|
|
710
|
-
'workspace-server': {
|
|
711
|
-
command: 'workspace-command',
|
|
712
|
-
args: ['--workspace-arg'],
|
|
713
|
-
description: 'Workspace MCP server',
|
|
714
|
-
},
|
|
715
|
-
'shared-server': {
|
|
716
|
-
command: 'workspace-shared-command',
|
|
717
|
-
description: 'Workspace shared server config',
|
|
718
|
-
},
|
|
719
|
-
});
|
|
720
|
-
});
|
|
721
|
-
it.each([
|
|
722
|
-
{
|
|
723
|
-
scope: 'user',
|
|
724
|
-
path: USER_SETTINGS_PATH,
|
|
725
|
-
content: {
|
|
726
|
-
mcpServers: {
|
|
727
|
-
'user-only-server': {
|
|
728
|
-
command: 'user-only-command',
|
|
729
|
-
description: 'User only server',
|
|
730
|
-
},
|
|
731
|
-
},
|
|
732
|
-
},
|
|
733
|
-
expected: {
|
|
734
|
-
'user-only-server': {
|
|
735
|
-
command: 'user-only-command',
|
|
736
|
-
description: 'User only server',
|
|
737
|
-
},
|
|
738
|
-
},
|
|
739
|
-
},
|
|
740
|
-
{
|
|
741
|
-
scope: 'workspace',
|
|
742
|
-
path: MOCK_WORKSPACE_SETTINGS_PATH,
|
|
743
|
-
content: {
|
|
744
|
-
mcpServers: {
|
|
745
|
-
'workspace-only-server': {
|
|
746
|
-
command: 'workspace-only-command',
|
|
747
|
-
description: 'Workspace only server',
|
|
748
|
-
},
|
|
749
|
-
},
|
|
750
|
-
},
|
|
751
|
-
expected: {
|
|
752
|
-
'workspace-only-server': {
|
|
753
|
-
command: 'workspace-only-command',
|
|
754
|
-
description: 'Workspace only server',
|
|
755
|
-
},
|
|
756
|
-
},
|
|
757
|
-
},
|
|
758
|
-
])('should handle MCP servers when only in $scope settings', ({ path, content, expected }) => {
|
|
759
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(path));
|
|
760
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
761
|
-
if (normalizePath(p) === normalizePath(path))
|
|
762
|
-
return JSON.stringify(content);
|
|
763
|
-
return '{}';
|
|
764
|
-
});
|
|
765
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
766
|
-
expect(settings.merged.mcpServers).toEqual(expected);
|
|
767
|
-
});
|
|
768
|
-
it('should have mcpServers as undefined if not in any settings file', () => {
|
|
769
|
-
mockFsExistsSync.mockReturnValue(false); // No settings files exist
|
|
770
|
-
fs.readFileSync.mockReturnValue('{}');
|
|
771
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
772
|
-
expect(settings.merged.mcpServers).toEqual({});
|
|
773
|
-
});
|
|
774
|
-
it('should merge MCP servers from system, user, and workspace with system taking precedence', () => {
|
|
775
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
776
|
-
const systemSettingsContent = {
|
|
777
|
-
mcpServers: {
|
|
778
|
-
'shared-server': {
|
|
779
|
-
command: 'system-command',
|
|
780
|
-
args: ['--system-arg'],
|
|
781
|
-
},
|
|
782
|
-
'system-only-server': {
|
|
783
|
-
command: 'system-only-command',
|
|
784
|
-
},
|
|
785
|
-
},
|
|
786
|
-
};
|
|
787
|
-
const userSettingsContent = {
|
|
788
|
-
mcpServers: {
|
|
789
|
-
'user-server': {
|
|
790
|
-
command: 'user-command',
|
|
791
|
-
},
|
|
792
|
-
'shared-server': {
|
|
793
|
-
command: 'user-command',
|
|
794
|
-
description: 'from user',
|
|
795
|
-
},
|
|
796
|
-
},
|
|
797
|
-
};
|
|
798
|
-
const workspaceSettingsContent = {
|
|
799
|
-
mcpServers: {
|
|
800
|
-
'workspace-server': {
|
|
801
|
-
command: 'workspace-command',
|
|
802
|
-
},
|
|
803
|
-
'shared-server': {
|
|
804
|
-
command: 'workspace-command',
|
|
805
|
-
args: ['--workspace-arg'],
|
|
806
|
-
},
|
|
807
|
-
},
|
|
808
|
-
};
|
|
809
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
810
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath()))
|
|
811
|
-
return JSON.stringify(systemSettingsContent);
|
|
812
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
813
|
-
return JSON.stringify(userSettingsContent);
|
|
814
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
815
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
816
|
-
return '{}';
|
|
817
|
-
});
|
|
818
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
819
|
-
expect(settings.merged.mcpServers).toEqual({
|
|
820
|
-
'user-server': {
|
|
821
|
-
command: 'user-command',
|
|
822
|
-
},
|
|
823
|
-
'workspace-server': {
|
|
824
|
-
command: 'workspace-command',
|
|
825
|
-
},
|
|
826
|
-
'system-only-server': {
|
|
827
|
-
command: 'system-only-command',
|
|
828
|
-
},
|
|
829
|
-
'shared-server': {
|
|
830
|
-
command: 'system-command',
|
|
831
|
-
args: ['--system-arg'],
|
|
832
|
-
},
|
|
833
|
-
});
|
|
834
|
-
});
|
|
835
|
-
it('should merge mcp allowed/excluded lists with system taking precedence over workspace', () => {
|
|
836
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
837
|
-
const systemSettingsContent = {
|
|
838
|
-
mcp: {
|
|
839
|
-
allowed: ['system-allowed'],
|
|
840
|
-
},
|
|
841
|
-
};
|
|
842
|
-
const userSettingsContent = {
|
|
843
|
-
mcp: {
|
|
844
|
-
allowed: ['user-allowed'],
|
|
845
|
-
excluded: ['user-excluded'],
|
|
846
|
-
},
|
|
847
|
-
};
|
|
848
|
-
const workspaceSettingsContent = {
|
|
849
|
-
mcp: {
|
|
850
|
-
allowed: ['workspace-allowed'],
|
|
851
|
-
excluded: ['workspace-excluded'],
|
|
852
|
-
},
|
|
853
|
-
};
|
|
854
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
855
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath()))
|
|
856
|
-
return JSON.stringify(systemSettingsContent);
|
|
857
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
858
|
-
return JSON.stringify(userSettingsContent);
|
|
859
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
860
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
861
|
-
return '{}';
|
|
862
|
-
});
|
|
863
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
864
|
-
expect(settings.merged.mcp).toEqual({
|
|
865
|
-
allowed: ['system-allowed'],
|
|
866
|
-
excluded: ['workspace-excluded'],
|
|
867
|
-
});
|
|
868
|
-
});
|
|
869
|
-
describe('LoadedSettings MCP consolidation', () => {
|
|
870
|
-
it('should consolidate mcp excluded list across all scopes', () => {
|
|
871
|
-
const loaded = new LoadedSettings({
|
|
872
|
-
path: '',
|
|
873
|
-
settings: { mcp: { excluded: ['system-excluded'] } },
|
|
874
|
-
originalSettings: {},
|
|
875
|
-
}, {
|
|
876
|
-
path: '',
|
|
877
|
-
settings: { mcp: { excluded: ['defaults-excluded'] } },
|
|
878
|
-
originalSettings: {},
|
|
879
|
-
}, {
|
|
880
|
-
path: '',
|
|
881
|
-
settings: { mcp: { excluded: ['user-excluded'] } },
|
|
882
|
-
originalSettings: {},
|
|
883
|
-
}, {
|
|
884
|
-
path: '',
|
|
885
|
-
settings: { mcp: { excluded: ['workspace-excluded'] } },
|
|
886
|
-
originalSettings: {},
|
|
887
|
-
}, true);
|
|
888
|
-
expect(loaded.getConsolidatedExcludedMcpServers()).toEqual([
|
|
889
|
-
'system-excluded',
|
|
890
|
-
'defaults-excluded',
|
|
891
|
-
'user-excluded',
|
|
892
|
-
'workspace-excluded',
|
|
893
|
-
]);
|
|
894
|
-
});
|
|
895
|
-
it('should consolidate allowed mcp list via case-insensitive intersection', () => {
|
|
896
|
-
const loaded = new LoadedSettings({
|
|
897
|
-
path: '',
|
|
898
|
-
settings: { mcp: { allowed: ['Server-A', 'Server-B'] } },
|
|
899
|
-
originalSettings: {},
|
|
900
|
-
}, {
|
|
901
|
-
path: '',
|
|
902
|
-
settings: { mcp: { allowed: ['server-a', 'Server-C'] } },
|
|
903
|
-
originalSettings: {},
|
|
904
|
-
}, { path: '', settings: {}, originalSettings: {} }, // no allowlist in user
|
|
905
|
-
{
|
|
906
|
-
path: '',
|
|
907
|
-
settings: { mcp: { allowed: ['SERVER-A', 'Server-D'] } },
|
|
908
|
-
originalSettings: {},
|
|
909
|
-
}, true);
|
|
910
|
-
expect(loaded.getConsolidatedAllowedMcpServers()).toEqual(['Server-A']);
|
|
911
|
-
});
|
|
912
|
-
it('should return undefined allowed list if no scopes define one', () => {
|
|
913
|
-
const loaded = new LoadedSettings({ path: '', settings: {}, originalSettings: {} }, { path: '', settings: {}, originalSettings: {} }, { path: '', settings: {}, originalSettings: {} }, { path: '', settings: {}, originalSettings: {} }, true);
|
|
914
|
-
expect(loaded.getConsolidatedAllowedMcpServers()).toBeUndefined();
|
|
915
|
-
});
|
|
916
|
-
});
|
|
917
|
-
describe('compressionThreshold settings', () => {
|
|
918
|
-
it.each([
|
|
919
|
-
{
|
|
920
|
-
description: 'should be taken from user settings if only present there',
|
|
921
|
-
userContent: { model: { compressionThreshold: 0.5 } },
|
|
922
|
-
workspaceContent: {},
|
|
923
|
-
expected: 0.5,
|
|
924
|
-
},
|
|
925
|
-
{
|
|
926
|
-
description: 'should be taken from workspace settings if only present there',
|
|
927
|
-
userContent: {},
|
|
928
|
-
workspaceContent: { model: { compressionThreshold: 0.8 } },
|
|
929
|
-
expected: 0.8,
|
|
930
|
-
},
|
|
931
|
-
{
|
|
932
|
-
description: 'should prioritize workspace settings over user settings',
|
|
933
|
-
userContent: { model: { compressionThreshold: 0.5 } },
|
|
934
|
-
workspaceContent: { model: { compressionThreshold: 0.8 } },
|
|
935
|
-
expected: 0.8,
|
|
936
|
-
},
|
|
937
|
-
{
|
|
938
|
-
description: 'should be default if not in any settings file',
|
|
939
|
-
userContent: {},
|
|
940
|
-
workspaceContent: {},
|
|
941
|
-
expected: 0.5,
|
|
942
|
-
},
|
|
943
|
-
])('$description', ({ userContent, workspaceContent, expected }) => {
|
|
944
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
945
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
946
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
947
|
-
return JSON.stringify(userContent);
|
|
948
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
949
|
-
return JSON.stringify(workspaceContent);
|
|
950
|
-
return '{}';
|
|
951
|
-
});
|
|
952
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
953
|
-
expect(settings.merged.model?.compressionThreshold).toEqual(expected);
|
|
954
|
-
});
|
|
955
|
-
});
|
|
956
|
-
it('should use user compressionThreshold if workspace does not define it', () => {
|
|
957
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
958
|
-
const userSettingsContent = {
|
|
959
|
-
general: {},
|
|
960
|
-
model: { compressionThreshold: 0.5 },
|
|
961
|
-
};
|
|
962
|
-
const workspaceSettingsContent = {
|
|
963
|
-
general: {},
|
|
964
|
-
model: {},
|
|
965
|
-
};
|
|
966
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
967
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
968
|
-
return JSON.stringify(userSettingsContent);
|
|
969
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
970
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
971
|
-
return '{}';
|
|
972
|
-
});
|
|
973
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
974
|
-
expect(settings.merged.model?.compressionThreshold).toEqual(0.5);
|
|
975
|
-
});
|
|
976
|
-
it('should merge includeDirectories from all scopes', () => {
|
|
977
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
978
|
-
const systemSettingsContent = {
|
|
979
|
-
context: { includeDirectories: ['/system/dir'] },
|
|
980
|
-
};
|
|
981
|
-
const systemDefaultsContent = {
|
|
982
|
-
context: { includeDirectories: ['/system/defaults/dir'] },
|
|
983
|
-
};
|
|
984
|
-
const userSettingsContent = {
|
|
985
|
-
context: { includeDirectories: ['/user/dir1', '/user/dir2'] },
|
|
986
|
-
};
|
|
987
|
-
const workspaceSettingsContent = {
|
|
988
|
-
context: { includeDirectories: ['/workspace/dir'] },
|
|
989
|
-
};
|
|
990
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
991
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath()))
|
|
992
|
-
return JSON.stringify(systemSettingsContent);
|
|
993
|
-
if (normalizePath(p) === normalizePath(getSystemDefaultsPath()))
|
|
994
|
-
return JSON.stringify(systemDefaultsContent);
|
|
995
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
996
|
-
return JSON.stringify(userSettingsContent);
|
|
997
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
998
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
999
|
-
return '{}';
|
|
1000
|
-
});
|
|
1001
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1002
|
-
expect(settings.merged.context?.includeDirectories).toEqual([
|
|
1003
|
-
'/system/defaults/dir',
|
|
1004
|
-
'/user/dir1',
|
|
1005
|
-
'/user/dir2',
|
|
1006
|
-
'/workspace/dir',
|
|
1007
|
-
'/system/dir',
|
|
1008
|
-
]);
|
|
1009
|
-
});
|
|
1010
|
-
it('should handle JSON parsing errors gracefully', () => {
|
|
1011
|
-
mockFsExistsSync.mockReturnValue(true); // Both files "exist"
|
|
1012
|
-
const invalidJsonContent = 'invalid json';
|
|
1013
|
-
const userReadError = new SyntaxError("Expected ',' or '}' after property value in JSON at position 10");
|
|
1014
|
-
const workspaceReadError = new SyntaxError('Unexpected token i in JSON at position 0');
|
|
1015
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1016
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH)) {
|
|
1017
|
-
// Simulate JSON.parse throwing for user settings
|
|
1018
|
-
vi.spyOn(JSON, 'parse').mockImplementationOnce(() => {
|
|
1019
|
-
throw userReadError;
|
|
1020
|
-
});
|
|
1021
|
-
return invalidJsonContent; // Content that would cause JSON.parse to throw
|
|
1022
|
-
}
|
|
1023
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH)) {
|
|
1024
|
-
// Simulate JSON.parse throwing for workspace settings
|
|
1025
|
-
vi.spyOn(JSON, 'parse').mockImplementationOnce(() => {
|
|
1026
|
-
throw workspaceReadError;
|
|
1027
|
-
});
|
|
1028
|
-
return invalidJsonContent;
|
|
1029
|
-
}
|
|
1030
|
-
return '{}'; // Default for other reads
|
|
1031
|
-
});
|
|
1032
|
-
try {
|
|
1033
|
-
loadSettings(MOCK_WORKSPACE_DIR);
|
|
1034
|
-
throw new Error('loadSettings should have thrown a FatalConfigError');
|
|
1035
|
-
}
|
|
1036
|
-
catch (e) {
|
|
1037
|
-
expect(e).toBeInstanceOf(FatalConfigError);
|
|
1038
|
-
const error = e;
|
|
1039
|
-
expect(error.message).toContain(`Error in ${USER_SETTINGS_PATH}: ${userReadError.message}`);
|
|
1040
|
-
expect(error.message).toContain(`Error in ${MOCK_WORKSPACE_SETTINGS_PATH}: ${workspaceReadError.message}`);
|
|
1041
|
-
expect(error.message).toContain('Please fix the configuration file(s) and try again.');
|
|
1042
|
-
}
|
|
1043
|
-
// Restore JSON.parse mock if it was spied on specifically for this test
|
|
1044
|
-
vi.restoreAllMocks(); // Or more targeted restore if needed
|
|
1045
|
-
});
|
|
1046
|
-
it('should resolve environment variables in user settings', () => {
|
|
1047
|
-
process.env['TEST_API_KEY'] = 'user_api_key_from_env';
|
|
1048
|
-
const userSettingsContent = {
|
|
1049
|
-
apiKey: '$TEST_API_KEY',
|
|
1050
|
-
someUrl: 'https://test.com/${TEST_API_KEY}',
|
|
1051
|
-
};
|
|
1052
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1053
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1054
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1055
|
-
return JSON.stringify(userSettingsContent);
|
|
1056
|
-
return '{}';
|
|
1057
|
-
});
|
|
1058
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1059
|
-
expect(settings.user.settings['apiKey']).toBe('user_api_key_from_env');
|
|
1060
|
-
expect(settings.user.settings['someUrl']).toBe('https://test.com/user_api_key_from_env');
|
|
1061
|
-
expect(settings.merged['apiKey']).toBe('user_api_key_from_env');
|
|
1062
|
-
delete process.env['TEST_API_KEY'];
|
|
1063
|
-
});
|
|
1064
|
-
it('should resolve environment variables in workspace settings', () => {
|
|
1065
|
-
process.env['WORKSPACE_ENDPOINT'] = 'workspace_endpoint_from_env';
|
|
1066
|
-
const workspaceSettingsContent = {
|
|
1067
|
-
endpoint: '${WORKSPACE_ENDPOINT}/api',
|
|
1068
|
-
nested: { value: '$WORKSPACE_ENDPOINT' },
|
|
1069
|
-
};
|
|
1070
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH));
|
|
1071
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1072
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1073
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1074
|
-
return '{}';
|
|
1075
|
-
});
|
|
1076
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1077
|
-
expect(settings.workspace.settings['endpoint']).toBe('workspace_endpoint_from_env/api');
|
|
1078
|
-
const nested = settings.workspace.settings['nested'];
|
|
1079
|
-
expect(nested['value']).toBe('workspace_endpoint_from_env');
|
|
1080
|
-
expect(settings.merged['endpoint']).toBe('workspace_endpoint_from_env/api');
|
|
1081
|
-
delete process.env['WORKSPACE_ENDPOINT'];
|
|
1082
|
-
});
|
|
1083
|
-
it('should correctly resolve and merge env variables from different scopes', () => {
|
|
1084
|
-
process.env['SYSTEM_VAR'] = 'system_value';
|
|
1085
|
-
process.env['USER_VAR'] = 'user_value';
|
|
1086
|
-
process.env['WORKSPACE_VAR'] = 'workspace_value';
|
|
1087
|
-
process.env['SHARED_VAR'] = 'final_value';
|
|
1088
|
-
const systemSettingsContent = {
|
|
1089
|
-
configValue: '$SHARED_VAR',
|
|
1090
|
-
systemOnly: '$SYSTEM_VAR',
|
|
1091
|
-
};
|
|
1092
|
-
const userSettingsContent = {
|
|
1093
|
-
configValue: '$SHARED_VAR',
|
|
1094
|
-
userOnly: '$USER_VAR',
|
|
1095
|
-
ui: {
|
|
1096
|
-
theme: 'dark',
|
|
1097
|
-
},
|
|
1098
|
-
};
|
|
1099
|
-
const workspaceSettingsContent = {
|
|
1100
|
-
configValue: '$SHARED_VAR',
|
|
1101
|
-
workspaceOnly: '$WORKSPACE_VAR',
|
|
1102
|
-
ui: {
|
|
1103
|
-
theme: 'light',
|
|
1104
|
-
},
|
|
1105
|
-
};
|
|
1106
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1107
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1108
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath())) {
|
|
1109
|
-
return JSON.stringify(systemSettingsContent);
|
|
1110
|
-
}
|
|
1111
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH)) {
|
|
1112
|
-
return JSON.stringify(userSettingsContent);
|
|
1113
|
-
}
|
|
1114
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH)) {
|
|
1115
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1116
|
-
}
|
|
1117
|
-
return '{}';
|
|
1118
|
-
});
|
|
1119
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1120
|
-
// Check resolved values in individual scopes
|
|
1121
|
-
expect(settings.system.settings['configValue']).toBe('final_value');
|
|
1122
|
-
expect(settings.system.settings['systemOnly']).toBe('system_value');
|
|
1123
|
-
expect(settings.user.settings['configValue']).toBe('final_value');
|
|
1124
|
-
expect(settings.user.settings['userOnly']).toBe('user_value');
|
|
1125
|
-
expect(settings.workspace.settings['configValue']).toBe('final_value');
|
|
1126
|
-
expect(settings.workspace.settings['workspaceOnly']).toBe('workspace_value');
|
|
1127
|
-
// Check merged values (system > workspace > user)
|
|
1128
|
-
expect(settings.merged['configValue']).toBe('final_value');
|
|
1129
|
-
expect(settings.merged['systemOnly']).toBe('system_value');
|
|
1130
|
-
expect(settings.merged['userOnly']).toBe('user_value');
|
|
1131
|
-
expect(settings.merged['workspaceOnly']).toBe('workspace_value');
|
|
1132
|
-
expect(settings.merged.ui?.theme).toBe('light'); // workspace overrides user
|
|
1133
|
-
delete process.env['SYSTEM_VAR'];
|
|
1134
|
-
delete process.env['USER_VAR'];
|
|
1135
|
-
delete process.env['WORKSPACE_VAR'];
|
|
1136
|
-
delete process.env['SHARED_VAR'];
|
|
1137
|
-
});
|
|
1138
|
-
it('should correctly merge dnsResolutionOrder with workspace taking precedence', () => {
|
|
1139
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1140
|
-
const userSettingsContent = {
|
|
1141
|
-
advanced: { dnsResolutionOrder: 'ipv4first' },
|
|
1142
|
-
};
|
|
1143
|
-
const workspaceSettingsContent = {
|
|
1144
|
-
advanced: { dnsResolutionOrder: 'verbatim' },
|
|
1145
|
-
};
|
|
1146
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1147
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1148
|
-
return JSON.stringify(userSettingsContent);
|
|
1149
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1150
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1151
|
-
return '{}';
|
|
1152
|
-
});
|
|
1153
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1154
|
-
expect(settings.merged.advanced?.dnsResolutionOrder).toBe('verbatim');
|
|
1155
|
-
});
|
|
1156
|
-
it('should use user dnsResolutionOrder if workspace is not defined', () => {
|
|
1157
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1158
|
-
const userSettingsContent = {
|
|
1159
|
-
advanced: { dnsResolutionOrder: 'verbatim' },
|
|
1160
|
-
};
|
|
1161
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1162
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1163
|
-
return JSON.stringify(userSettingsContent);
|
|
1164
|
-
return '{}';
|
|
1165
|
-
});
|
|
1166
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1167
|
-
expect(settings.merged.advanced?.dnsResolutionOrder).toBe('verbatim');
|
|
1168
|
-
});
|
|
1169
|
-
it('should leave unresolved environment variables as is', () => {
|
|
1170
|
-
const userSettingsContent = { apiKey: '$UNDEFINED_VAR' };
|
|
1171
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1172
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1173
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1174
|
-
return JSON.stringify(userSettingsContent);
|
|
1175
|
-
return '{}';
|
|
1176
|
-
});
|
|
1177
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1178
|
-
expect(settings.user.settings['apiKey']).toBe('$UNDEFINED_VAR');
|
|
1179
|
-
expect(settings.merged['apiKey']).toBe('$UNDEFINED_VAR');
|
|
1180
|
-
});
|
|
1181
|
-
it('should resolve multiple environment variables in a single string', () => {
|
|
1182
|
-
process.env['VAR_A'] = 'valueA';
|
|
1183
|
-
process.env['VAR_B'] = 'valueB';
|
|
1184
|
-
const userSettingsContent = {
|
|
1185
|
-
path: '/path/$VAR_A/${VAR_B}/end',
|
|
1186
|
-
};
|
|
1187
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1188
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1189
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1190
|
-
return JSON.stringify(userSettingsContent);
|
|
1191
|
-
return '{}';
|
|
1192
|
-
});
|
|
1193
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1194
|
-
expect(settings.user.settings['path']).toBe('/path/valueA/valueB/end');
|
|
1195
|
-
delete process.env['VAR_A'];
|
|
1196
|
-
delete process.env['VAR_B'];
|
|
1197
|
-
});
|
|
1198
|
-
it('should resolve environment variables in arrays', () => {
|
|
1199
|
-
process.env['ITEM_1'] = 'item1_env';
|
|
1200
|
-
process.env['ITEM_2'] = 'item2_env';
|
|
1201
|
-
const userSettingsContent = {
|
|
1202
|
-
list: ['$ITEM_1', '${ITEM_2}', 'literal'],
|
|
1203
|
-
};
|
|
1204
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1205
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1206
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1207
|
-
return JSON.stringify(userSettingsContent);
|
|
1208
|
-
return '{}';
|
|
1209
|
-
});
|
|
1210
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1211
|
-
expect(settings.user.settings['list']).toEqual([
|
|
1212
|
-
'item1_env',
|
|
1213
|
-
'item2_env',
|
|
1214
|
-
'literal',
|
|
1215
|
-
]);
|
|
1216
|
-
delete process.env['ITEM_1'];
|
|
1217
|
-
delete process.env['ITEM_2'];
|
|
1218
|
-
});
|
|
1219
|
-
it('should correctly pass through null, boolean, and number types, and handle undefined properties', () => {
|
|
1220
|
-
process.env['MY_ENV_STRING'] = 'env_string_value';
|
|
1221
|
-
process.env['MY_ENV_STRING_NESTED'] = 'env_string_nested_value';
|
|
1222
|
-
const userSettingsContent = {
|
|
1223
|
-
nullVal: null,
|
|
1224
|
-
trueVal: true,
|
|
1225
|
-
falseVal: false,
|
|
1226
|
-
numberVal: 123.45,
|
|
1227
|
-
stringVal: '$MY_ENV_STRING',
|
|
1228
|
-
nestedObj: {
|
|
1229
|
-
nestedNull: null,
|
|
1230
|
-
nestedBool: true,
|
|
1231
|
-
nestedNum: 0,
|
|
1232
|
-
nestedString: 'literal',
|
|
1233
|
-
anotherEnv: '${MY_ENV_STRING_NESTED}',
|
|
1234
|
-
},
|
|
1235
|
-
};
|
|
1236
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1237
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1238
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1239
|
-
return JSON.stringify(userSettingsContent);
|
|
1240
|
-
return '{}';
|
|
1241
|
-
});
|
|
1242
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1243
|
-
expect(settings.user.settings['nullVal']).toBeNull();
|
|
1244
|
-
expect(settings.user.settings['trueVal']).toBe(true);
|
|
1245
|
-
expect(settings.user.settings['falseVal']).toBe(false);
|
|
1246
|
-
expect(settings.user.settings['numberVal']).toBe(123.45);
|
|
1247
|
-
expect(settings.user.settings['stringVal']).toBe('env_string_value');
|
|
1248
|
-
expect(settings.user.settings['undefinedVal']).toBeUndefined();
|
|
1249
|
-
const nestedObj = settings.user.settings['nestedObj'];
|
|
1250
|
-
expect(nestedObj['nestedNull']).toBeNull();
|
|
1251
|
-
expect(nestedObj['nestedBool']).toBe(true);
|
|
1252
|
-
expect(nestedObj['nestedNum']).toBe(0);
|
|
1253
|
-
expect(nestedObj['nestedString']).toBe('literal');
|
|
1254
|
-
expect(nestedObj['anotherEnv']).toBe('env_string_nested_value');
|
|
1255
|
-
delete process.env['MY_ENV_STRING'];
|
|
1256
|
-
delete process.env['MY_ENV_STRING_NESTED'];
|
|
1257
|
-
});
|
|
1258
|
-
it('should resolve multiple concatenated environment variables in a single string value', () => {
|
|
1259
|
-
process.env['TEST_HOST'] = 'myhost';
|
|
1260
|
-
process.env['TEST_PORT'] = '9090';
|
|
1261
|
-
const userSettingsContent = {
|
|
1262
|
-
serverAddress: '${TEST_HOST}:${TEST_PORT}/api',
|
|
1263
|
-
};
|
|
1264
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1265
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1266
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1267
|
-
return JSON.stringify(userSettingsContent);
|
|
1268
|
-
return '{}';
|
|
1269
|
-
});
|
|
1270
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1271
|
-
expect(settings.user.settings['serverAddress']).toBe('myhost:9090/api');
|
|
1272
|
-
delete process.env['TEST_HOST'];
|
|
1273
|
-
delete process.env['TEST_PORT'];
|
|
1274
|
-
});
|
|
1275
|
-
describe('when GEMINI_CLI_SYSTEM_SETTINGS_PATH is set', () => {
|
|
1276
|
-
const MOCK_ENV_SYSTEM_SETTINGS_PATH = path.resolve('/mock/env/system/settings.json');
|
|
1277
|
-
beforeEach(() => {
|
|
1278
|
-
process.env['GEMINI_CLI_SYSTEM_SETTINGS_PATH'] =
|
|
1279
|
-
MOCK_ENV_SYSTEM_SETTINGS_PATH;
|
|
1280
|
-
});
|
|
1281
|
-
afterEach(() => {
|
|
1282
|
-
delete process.env['GEMINI_CLI_SYSTEM_SETTINGS_PATH'];
|
|
1283
|
-
});
|
|
1284
|
-
it('should load system settings from the path specified in the environment variable', () => {
|
|
1285
|
-
mockFsExistsSync.mockImplementation((p) => p === MOCK_ENV_SYSTEM_SETTINGS_PATH);
|
|
1286
|
-
const systemSettingsContent = {
|
|
1287
|
-
ui: { theme: 'env-var-theme' },
|
|
1288
|
-
tools: { sandbox: true },
|
|
1289
|
-
};
|
|
1290
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1291
|
-
if (p === MOCK_ENV_SYSTEM_SETTINGS_PATH)
|
|
1292
|
-
return JSON.stringify(systemSettingsContent);
|
|
1293
|
-
return '{}';
|
|
1294
|
-
});
|
|
1295
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1296
|
-
expect(fs.readFileSync).toHaveBeenCalledWith(MOCK_ENV_SYSTEM_SETTINGS_PATH, 'utf-8');
|
|
1297
|
-
expect(settings.system.path).toBe(MOCK_ENV_SYSTEM_SETTINGS_PATH);
|
|
1298
|
-
expect(settings.system.settings).toEqual(systemSettingsContent);
|
|
1299
|
-
expect(settings.merged).toMatchObject({
|
|
1300
|
-
...systemSettingsContent,
|
|
1301
|
-
});
|
|
1302
|
-
});
|
|
1303
|
-
});
|
|
1304
|
-
it('should correctly skip workspace-level loading if workspaceDir is a symlink to home', () => {
|
|
1305
|
-
const mockHomeDir = path.resolve('/mock/home/user');
|
|
1306
|
-
const mockSymlinkDir = path.resolve('/mock/symlink/to/home');
|
|
1307
|
-
const mockWorkspaceSettingsPath = path.join(mockSymlinkDir, GEMINI_DIR, 'settings.json');
|
|
1308
|
-
vi.mocked(osActual.homedir).mockReturnValue(mockHomeDir);
|
|
1309
|
-
vi.mocked(fs.realpathSync).mockImplementation((p) => {
|
|
1310
|
-
const pStr = p.toString();
|
|
1311
|
-
const resolved = path.resolve(pStr);
|
|
1312
|
-
if (resolved === path.resolve(mockSymlinkDir) ||
|
|
1313
|
-
resolved === path.resolve(mockHomeDir)) {
|
|
1314
|
-
return mockHomeDir;
|
|
1315
|
-
}
|
|
1316
|
-
return pStr;
|
|
1317
|
-
});
|
|
1318
|
-
// Force the storage check to return true for this specific test
|
|
1319
|
-
const isWorkspaceHomeDirSpy = vi
|
|
1320
|
-
.spyOn(Storage.prototype, 'isWorkspaceHomeDir')
|
|
1321
|
-
.mockReturnValue(true);
|
|
1322
|
-
mockFsExistsSync.mockImplementation((p) =>
|
|
1323
|
-
// Only return true for workspace settings path to see if it gets loaded
|
|
1324
|
-
p === mockWorkspaceSettingsPath);
|
|
1325
|
-
try {
|
|
1326
|
-
const settings = loadSettings(mockSymlinkDir);
|
|
1327
|
-
// Verify that even though the file exists, it was NOT loaded because realpath matched home
|
|
1328
|
-
expect(fs.readFileSync).not.toHaveBeenCalledWith(mockWorkspaceSettingsPath, 'utf-8');
|
|
1329
|
-
expect(settings.workspace.settings).toEqual({});
|
|
1330
|
-
}
|
|
1331
|
-
finally {
|
|
1332
|
-
isWorkspaceHomeDirSpy.mockRestore();
|
|
1333
|
-
}
|
|
1334
|
-
});
|
|
1335
|
-
describe('caching', () => {
|
|
1336
|
-
it('should cache loadSettings results', () => {
|
|
1337
|
-
const mockedRead = vi.mocked(fs.readFileSync);
|
|
1338
|
-
mockedRead.mockClear();
|
|
1339
|
-
mockedRead.mockReturnValue('{}');
|
|
1340
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1341
|
-
const settings1 = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1342
|
-
const settings2 = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1343
|
-
expect(mockedRead).toHaveBeenCalledTimes(5); // system, systemDefaults, user, workspace, and potentially an env file
|
|
1344
|
-
expect(settings1).toBe(settings2);
|
|
1345
|
-
});
|
|
1346
|
-
it('should use separate cache for different workspace directories', () => {
|
|
1347
|
-
const mockedRead = vi.mocked(fs.readFileSync);
|
|
1348
|
-
mockedRead.mockClear();
|
|
1349
|
-
mockedRead.mockReturnValue('{}');
|
|
1350
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1351
|
-
const workspace1 = path.resolve('/mock/workspace1');
|
|
1352
|
-
const workspace2 = path.resolve('/mock/workspace2');
|
|
1353
|
-
const settings1 = loadSettings(workspace1);
|
|
1354
|
-
const settings2 = loadSettings(workspace2);
|
|
1355
|
-
expect(mockedRead).toHaveBeenCalledTimes(10); // 5 for each workspace
|
|
1356
|
-
expect(settings1).not.toBe(settings2);
|
|
1357
|
-
});
|
|
1358
|
-
it('should clear cache when saveSettings is called for user settings', () => {
|
|
1359
|
-
const mockedRead = vi.mocked(fs.readFileSync);
|
|
1360
|
-
mockedRead.mockClear();
|
|
1361
|
-
mockedRead.mockReturnValue('{}');
|
|
1362
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1363
|
-
const settings1 = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1364
|
-
expect(mockedRead).toHaveBeenCalledTimes(5);
|
|
1365
|
-
saveSettings(settings1.user);
|
|
1366
|
-
const settings2 = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1367
|
-
expect(mockedRead).toHaveBeenCalledTimes(10); // Should have re-read from disk
|
|
1368
|
-
expect(settings1).not.toBe(settings2);
|
|
1369
|
-
});
|
|
1370
|
-
it('should clear all caches when saveSettings is called for workspace settings', () => {
|
|
1371
|
-
const mockedRead = vi.mocked(fs.readFileSync);
|
|
1372
|
-
mockedRead.mockClear();
|
|
1373
|
-
mockedRead.mockReturnValue('{}');
|
|
1374
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1375
|
-
const workspace1 = path.resolve('/mock/workspace1');
|
|
1376
|
-
const workspace2 = path.resolve('/mock/workspace2');
|
|
1377
|
-
const settings1W1 = loadSettings(workspace1);
|
|
1378
|
-
const settings1W2 = loadSettings(workspace2);
|
|
1379
|
-
expect(mockedRead).toHaveBeenCalledTimes(10);
|
|
1380
|
-
// Save settings for workspace 1
|
|
1381
|
-
saveSettings(settings1W1.workspace);
|
|
1382
|
-
const settings2W1 = loadSettings(workspace1);
|
|
1383
|
-
const settings2W2 = loadSettings(workspace2);
|
|
1384
|
-
// Both workspace caches should have been cleared and re-read from disk (+10 reads)
|
|
1385
|
-
expect(mockedRead).toHaveBeenCalledTimes(20);
|
|
1386
|
-
expect(settings1W1).not.toBe(settings2W1);
|
|
1387
|
-
expect(settings1W2).not.toBe(settings2W2);
|
|
1388
|
-
});
|
|
1389
|
-
});
|
|
1390
|
-
});
|
|
1391
|
-
describe('excludedProjectEnvVars integration', () => {
|
|
1392
|
-
const originalEnv = { ...process.env };
|
|
1393
|
-
beforeEach(() => {
|
|
1394
|
-
process.env = { ...originalEnv };
|
|
1395
|
-
});
|
|
1396
|
-
afterEach(() => {
|
|
1397
|
-
process.env = originalEnv;
|
|
1398
|
-
});
|
|
1399
|
-
it('should exclude DEBUG and DEBUG_MODE from project .env files by default', () => {
|
|
1400
|
-
// Create a workspace settings file with excludedProjectEnvVars
|
|
1401
|
-
const workspaceSettingsContent = {
|
|
1402
|
-
general: {},
|
|
1403
|
-
advanced: { excludedEnvVars: ['DEBUG', 'DEBUG_MODE'] },
|
|
1404
|
-
};
|
|
1405
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH));
|
|
1406
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1407
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1408
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1409
|
-
return '{}';
|
|
1410
|
-
});
|
|
1411
|
-
// Mock findEnvFile to return a project .env file
|
|
1412
|
-
const originalFindEnvFile = loadSettings.findEnvFile;
|
|
1413
|
-
loadSettings.findEnvFile =
|
|
1414
|
-
() => path.resolve('/mock/project/.env');
|
|
1415
|
-
// Mock fs.readFileSync for .env file content
|
|
1416
|
-
const originalReadFileSync = fs.readFileSync;
|
|
1417
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1418
|
-
if (p === path.resolve('/mock/project/.env')) {
|
|
1419
|
-
return 'DEBUG=true\nDEBUG_MODE=1\nGEMINI_API_KEY=test-key';
|
|
1420
|
-
}
|
|
1421
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH)) {
|
|
1422
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1423
|
-
}
|
|
1424
|
-
return '{}';
|
|
1425
|
-
});
|
|
1426
|
-
try {
|
|
1427
|
-
// This will call loadEnvironment internally with the merged settings
|
|
1428
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1429
|
-
// Verify the settings were loaded correctly
|
|
1430
|
-
expect(settings.merged.advanced?.excludedEnvVars).toEqual([
|
|
1431
|
-
'DEBUG',
|
|
1432
|
-
'DEBUG_MODE',
|
|
1433
|
-
]);
|
|
1434
|
-
// Note: We can't directly test process.env changes here because the mocking
|
|
1435
|
-
// prevents the actual file system operations, but we can verify the settings
|
|
1436
|
-
// are correctly merged and passed to loadEnvironment
|
|
1437
|
-
}
|
|
1438
|
-
finally {
|
|
1439
|
-
loadSettings.findEnvFile =
|
|
1440
|
-
originalFindEnvFile;
|
|
1441
|
-
fs.readFileSync.mockImplementation(originalReadFileSync);
|
|
1442
|
-
}
|
|
1443
|
-
});
|
|
1444
|
-
it('should respect custom excludedProjectEnvVars from user settings', () => {
|
|
1445
|
-
const userSettingsContent = {
|
|
1446
|
-
general: {},
|
|
1447
|
-
advanced: { excludedEnvVars: ['NODE_ENV', 'DEBUG'] },
|
|
1448
|
-
};
|
|
1449
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1450
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1451
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1452
|
-
return JSON.stringify(userSettingsContent);
|
|
1453
|
-
return '{}';
|
|
1454
|
-
});
|
|
1455
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1456
|
-
expect(settings.user.settings.advanced?.excludedEnvVars).toEqual([
|
|
1457
|
-
'NODE_ENV',
|
|
1458
|
-
'DEBUG',
|
|
1459
|
-
]);
|
|
1460
|
-
expect(settings.merged.advanced?.excludedEnvVars).toEqual([
|
|
1461
|
-
'DEBUG',
|
|
1462
|
-
'DEBUG_MODE',
|
|
1463
|
-
'NODE_ENV',
|
|
1464
|
-
]);
|
|
1465
|
-
});
|
|
1466
|
-
it('should merge excludedProjectEnvVars with workspace taking precedence', () => {
|
|
1467
|
-
const userSettingsContent = {
|
|
1468
|
-
general: {},
|
|
1469
|
-
advanced: { excludedEnvVars: ['DEBUG', 'NODE_ENV', 'USER_VAR'] },
|
|
1470
|
-
};
|
|
1471
|
-
const workspaceSettingsContent = {
|
|
1472
|
-
general: {},
|
|
1473
|
-
advanced: { excludedEnvVars: ['WORKSPACE_DEBUG', 'WORKSPACE_VAR'] },
|
|
1474
|
-
};
|
|
1475
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1476
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1477
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1478
|
-
return JSON.stringify(userSettingsContent);
|
|
1479
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1480
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1481
|
-
return '{}';
|
|
1482
|
-
});
|
|
1483
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1484
|
-
expect(settings.user.settings.advanced?.excludedEnvVars).toEqual([
|
|
1485
|
-
'DEBUG',
|
|
1486
|
-
'NODE_ENV',
|
|
1487
|
-
'USER_VAR',
|
|
1488
|
-
]);
|
|
1489
|
-
expect(settings.workspace.settings.advanced?.excludedEnvVars).toEqual([
|
|
1490
|
-
'WORKSPACE_DEBUG',
|
|
1491
|
-
'WORKSPACE_VAR',
|
|
1492
|
-
]);
|
|
1493
|
-
expect(settings.merged.advanced?.excludedEnvVars).toEqual([
|
|
1494
|
-
'DEBUG',
|
|
1495
|
-
'DEBUG_MODE',
|
|
1496
|
-
'NODE_ENV',
|
|
1497
|
-
'USER_VAR',
|
|
1498
|
-
'WORKSPACE_DEBUG',
|
|
1499
|
-
'WORKSPACE_VAR',
|
|
1500
|
-
]);
|
|
1501
|
-
});
|
|
1502
|
-
});
|
|
1503
|
-
describe('with workspace trust', () => {
|
|
1504
|
-
it('should merge workspace settings when workspace is trusted', () => {
|
|
1505
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1506
|
-
const userSettingsContent = {
|
|
1507
|
-
ui: { theme: 'dark' },
|
|
1508
|
-
tools: { sandbox: false },
|
|
1509
|
-
};
|
|
1510
|
-
const workspaceSettingsContent = {
|
|
1511
|
-
tools: { sandbox: true },
|
|
1512
|
-
context: { fileName: 'WORKSPACE.md' },
|
|
1513
|
-
};
|
|
1514
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1515
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1516
|
-
return JSON.stringify(userSettingsContent);
|
|
1517
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1518
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1519
|
-
return '{}';
|
|
1520
|
-
});
|
|
1521
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1522
|
-
expect(settings.merged.tools?.sandbox).toBe(true);
|
|
1523
|
-
expect(settings.merged.context?.fileName).toBe('WORKSPACE.md');
|
|
1524
|
-
expect(settings.merged.ui?.theme).toBe('dark');
|
|
1525
|
-
});
|
|
1526
|
-
it('should NOT merge workspace settings when workspace is not trusted', () => {
|
|
1527
|
-
vi.spyOn(trustedFolders, 'isWorkspaceTrusted').mockReturnValue({
|
|
1528
|
-
isTrusted: false,
|
|
1529
|
-
source: 'file',
|
|
1530
|
-
});
|
|
1531
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1532
|
-
const userSettingsContent = {
|
|
1533
|
-
ui: { theme: 'dark' },
|
|
1534
|
-
tools: { sandbox: false },
|
|
1535
|
-
context: { fileName: 'USER.md' },
|
|
1536
|
-
};
|
|
1537
|
-
const workspaceSettingsContent = {
|
|
1538
|
-
tools: { sandbox: true },
|
|
1539
|
-
context: { fileName: 'WORKSPACE.md' },
|
|
1540
|
-
};
|
|
1541
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1542
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1543
|
-
return JSON.stringify(userSettingsContent);
|
|
1544
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1545
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1546
|
-
return '{}';
|
|
1547
|
-
});
|
|
1548
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1549
|
-
expect(settings.merged.tools?.sandbox).toBe(false); // User setting
|
|
1550
|
-
expect(settings.merged.context?.fileName).toBe('USER.md'); // User setting
|
|
1551
|
-
expect(settings.merged.ui?.theme).toBe('dark'); // User setting
|
|
1552
|
-
});
|
|
1553
|
-
it('should NOT merge workspace settings when workspace trust is undefined', () => {
|
|
1554
|
-
vi.spyOn(trustedFolders, 'isWorkspaceTrusted').mockReturnValue({
|
|
1555
|
-
isTrusted: undefined,
|
|
1556
|
-
source: undefined,
|
|
1557
|
-
});
|
|
1558
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1559
|
-
const userSettingsContent = {
|
|
1560
|
-
ui: { theme: 'dark' },
|
|
1561
|
-
tools: { sandbox: false },
|
|
1562
|
-
context: { fileName: 'USER.md' },
|
|
1563
|
-
};
|
|
1564
|
-
const workspaceSettingsContent = {
|
|
1565
|
-
tools: { sandbox: true },
|
|
1566
|
-
context: { fileName: 'WORKSPACE.md' },
|
|
1567
|
-
};
|
|
1568
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1569
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1570
|
-
return JSON.stringify(userSettingsContent);
|
|
1571
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1572
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1573
|
-
return '{}';
|
|
1574
|
-
});
|
|
1575
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1576
|
-
expect(settings.merged.tools?.sandbox).toBe(false); // User setting
|
|
1577
|
-
expect(settings.merged.context?.fileName).toBe('USER.md'); // User setting
|
|
1578
|
-
});
|
|
1579
|
-
});
|
|
1580
|
-
describe('loadEnvironment', () => {
|
|
1581
|
-
function setup({ isFolderTrustEnabled = true, isWorkspaceTrustedValue = true, }) {
|
|
1582
|
-
delete process.env['GEMINI_API_KEY']; // reset
|
|
1583
|
-
delete process.env['TESTTEST']; // reset
|
|
1584
|
-
const geminiEnvPath = path.resolve(path.join(MOCK_WORKSPACE_DIR, GEMINI_DIR, '.env'));
|
|
1585
|
-
const workspaceEnvPath = path.resolve(path.join(MOCK_WORKSPACE_DIR, '.env'));
|
|
1586
|
-
vi.spyOn(trustedFolders, 'isWorkspaceTrusted').mockReturnValue({
|
|
1587
|
-
isTrusted: isWorkspaceTrustedValue,
|
|
1588
|
-
source: 'file',
|
|
1589
|
-
});
|
|
1590
|
-
mockFsExistsSync.mockImplementation((p) => {
|
|
1591
|
-
const normalizedP = path.resolve(p.toString());
|
|
1592
|
-
return [
|
|
1593
|
-
path.resolve(USER_SETTINGS_PATH),
|
|
1594
|
-
geminiEnvPath,
|
|
1595
|
-
workspaceEnvPath,
|
|
1596
|
-
].includes(normalizedP);
|
|
1597
|
-
});
|
|
1598
|
-
const userSettingsContent = {
|
|
1599
|
-
ui: {
|
|
1600
|
-
theme: 'dark',
|
|
1601
|
-
},
|
|
1602
|
-
security: {
|
|
1603
|
-
folderTrust: {
|
|
1604
|
-
enabled: isFolderTrustEnabled,
|
|
1605
|
-
},
|
|
1606
|
-
},
|
|
1607
|
-
context: {
|
|
1608
|
-
fileName: 'USER_CONTEXT.md',
|
|
1609
|
-
},
|
|
1610
|
-
};
|
|
1611
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1612
|
-
const normalizedP = path.resolve(p.toString());
|
|
1613
|
-
if (normalizedP === path.resolve(USER_SETTINGS_PATH))
|
|
1614
|
-
return JSON.stringify(userSettingsContent);
|
|
1615
|
-
if (normalizedP === geminiEnvPath || normalizedP === workspaceEnvPath)
|
|
1616
|
-
return 'TESTTEST=1234\nGEMINI_API_KEY=test-key';
|
|
1617
|
-
return '{}';
|
|
1618
|
-
});
|
|
1619
|
-
}
|
|
1620
|
-
it('sets environment variables from .env files', () => {
|
|
1621
|
-
setup({ isFolderTrustEnabled: false, isWorkspaceTrustedValue: true });
|
|
1622
|
-
const settings = {
|
|
1623
|
-
security: { folderTrust: { enabled: false } },
|
|
1624
|
-
};
|
|
1625
|
-
loadEnvironment(settings, MOCK_WORKSPACE_DIR, isWorkspaceTrusted);
|
|
1626
|
-
expect(process.env['TESTTEST']).toEqual('1234');
|
|
1627
|
-
expect(process.env['GEMINI_API_KEY']).toEqual('test-key');
|
|
1628
|
-
});
|
|
1629
|
-
it('does not load env files from untrusted spaces when sandboxed', () => {
|
|
1630
|
-
setup({ isFolderTrustEnabled: true, isWorkspaceTrustedValue: false });
|
|
1631
|
-
const settings = {
|
|
1632
|
-
security: { folderTrust: { enabled: true } },
|
|
1633
|
-
tools: { sandbox: true },
|
|
1634
|
-
};
|
|
1635
|
-
loadEnvironment(settings, MOCK_WORKSPACE_DIR, isWorkspaceTrusted);
|
|
1636
|
-
expect(process.env['TESTTEST']).not.toEqual('1234');
|
|
1637
|
-
});
|
|
1638
|
-
it('does NOT load non-whitelisted env files from untrusted spaces even when NOT sandboxed', () => {
|
|
1639
|
-
setup({ isFolderTrustEnabled: true, isWorkspaceTrustedValue: false });
|
|
1640
|
-
const settings = {
|
|
1641
|
-
security: { folderTrust: { enabled: true } },
|
|
1642
|
-
tools: { sandbox: false },
|
|
1643
|
-
};
|
|
1644
|
-
loadEnvironment(settings, MOCK_WORKSPACE_DIR, isWorkspaceTrusted);
|
|
1645
|
-
expect(process.env['TESTTEST']).not.toEqual('1234');
|
|
1646
|
-
expect(process.env['GEMINI_API_KEY']).toEqual('test-key');
|
|
1647
|
-
});
|
|
1648
|
-
it('does not load env files when trust is undefined and sandboxed', () => {
|
|
1649
|
-
delete process.env['TESTTEST'];
|
|
1650
|
-
// isWorkspaceTrusted returns {isTrusted: undefined} for matched rules with no trust value, or no matching rules.
|
|
1651
|
-
setup({ isFolderTrustEnabled: true, isWorkspaceTrustedValue: undefined });
|
|
1652
|
-
const settings = {
|
|
1653
|
-
security: { folderTrust: { enabled: true } },
|
|
1654
|
-
tools: { sandbox: true },
|
|
1655
|
-
};
|
|
1656
|
-
const mockTrustFn = vi.fn().mockReturnValue({ isTrusted: undefined });
|
|
1657
|
-
loadEnvironment(settings, MOCK_WORKSPACE_DIR, mockTrustFn);
|
|
1658
|
-
expect(process.env['TESTTEST']).not.toEqual('1234');
|
|
1659
|
-
expect(process.env['GEMINI_API_KEY']).toEqual('test-key');
|
|
1660
|
-
});
|
|
1661
|
-
it('loads whitelisted env files from untrusted spaces if sandboxing is enabled', () => {
|
|
1662
|
-
setup({ isFolderTrustEnabled: true, isWorkspaceTrustedValue: false });
|
|
1663
|
-
const settings = createTestMergedSettings({
|
|
1664
|
-
tools: { sandbox: true },
|
|
1665
|
-
});
|
|
1666
|
-
loadEnvironment(settings, MOCK_WORKSPACE_DIR, isWorkspaceTrusted);
|
|
1667
|
-
// GEMINI_API_KEY is in the whitelist, so it should be loaded.
|
|
1668
|
-
expect(process.env['GEMINI_API_KEY']).toEqual('test-key');
|
|
1669
|
-
// TESTTEST is NOT in the whitelist, so it should be blocked.
|
|
1670
|
-
expect(process.env['TESTTEST']).not.toEqual('1234');
|
|
1671
|
-
});
|
|
1672
|
-
it('loads whitelisted env files from untrusted spaces if sandboxing is enabled via CLI flag', () => {
|
|
1673
|
-
const originalArgv = [...process.argv];
|
|
1674
|
-
process.argv.push('-s');
|
|
1675
|
-
try {
|
|
1676
|
-
setup({ isFolderTrustEnabled: true, isWorkspaceTrustedValue: false });
|
|
1677
|
-
const settings = createTestMergedSettings({
|
|
1678
|
-
tools: { sandbox: false },
|
|
1679
|
-
});
|
|
1680
|
-
loadEnvironment(settings, MOCK_WORKSPACE_DIR, isWorkspaceTrusted);
|
|
1681
|
-
expect(process.env['GEMINI_API_KEY']).toEqual('test-key');
|
|
1682
|
-
expect(process.env['TESTTEST']).not.toEqual('1234');
|
|
1683
|
-
}
|
|
1684
|
-
finally {
|
|
1685
|
-
process.argv = originalArgv;
|
|
1686
|
-
}
|
|
1687
|
-
});
|
|
1688
|
-
});
|
|
1689
|
-
describe('migrateDeprecatedSettings', () => {
|
|
1690
|
-
let mockFsExistsSync;
|
|
1691
|
-
let mockFsReadFileSync;
|
|
1692
|
-
beforeEach(() => {
|
|
1693
|
-
vi.resetAllMocks();
|
|
1694
|
-
mockFsExistsSync = vi.mocked(fs.existsSync);
|
|
1695
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
1696
|
-
mockFsReadFileSync = vi.mocked(fs.readFileSync);
|
|
1697
|
-
mockFsReadFileSync.mockReturnValue('{}');
|
|
1698
|
-
vi.spyOn(trustedFolders, 'isWorkspaceTrusted').mockReturnValue({
|
|
1699
|
-
isTrusted: true,
|
|
1700
|
-
source: undefined,
|
|
1701
|
-
});
|
|
1702
|
-
});
|
|
1703
|
-
afterEach(() => {
|
|
1704
|
-
vi.restoreAllMocks();
|
|
1705
|
-
});
|
|
1706
|
-
it('should not do anything if there are no deprecated settings', () => {
|
|
1707
|
-
const userSettingsContent = {
|
|
1708
|
-
extensions: {
|
|
1709
|
-
enabled: ['user-ext-1'],
|
|
1710
|
-
},
|
|
1711
|
-
};
|
|
1712
|
-
const workspaceSettingsContent = {
|
|
1713
|
-
someOtherSetting: 'value',
|
|
1714
|
-
};
|
|
1715
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1716
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1717
|
-
return JSON.stringify(userSettingsContent);
|
|
1718
|
-
if (normalizePath(p) === normalizePath(MOCK_WORKSPACE_SETTINGS_PATH))
|
|
1719
|
-
return JSON.stringify(workspaceSettingsContent);
|
|
1720
|
-
return '{}';
|
|
1721
|
-
});
|
|
1722
|
-
const setValueSpy = vi.spyOn(LoadedSettings.prototype, 'setValue');
|
|
1723
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1724
|
-
setValueSpy.mockClear();
|
|
1725
|
-
migrateDeprecatedSettings(loadedSettings, true);
|
|
1726
|
-
expect(setValueSpy).not.toHaveBeenCalled();
|
|
1727
|
-
});
|
|
1728
|
-
it('should migrate general.disableAutoUpdate to general.enableAutoUpdate with inverted value', () => {
|
|
1729
|
-
const userSettingsContent = {
|
|
1730
|
-
general: {
|
|
1731
|
-
disableAutoUpdate: true,
|
|
1732
|
-
},
|
|
1733
|
-
};
|
|
1734
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1735
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1736
|
-
return JSON.stringify(userSettingsContent);
|
|
1737
|
-
return '{}';
|
|
1738
|
-
});
|
|
1739
|
-
const setValueSpy = vi.spyOn(LoadedSettings.prototype, 'setValue');
|
|
1740
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1741
|
-
migrateDeprecatedSettings(loadedSettings, true);
|
|
1742
|
-
// Should set new value to false (inverted from true)
|
|
1743
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'general', expect.objectContaining({ enableAutoUpdate: false }));
|
|
1744
|
-
});
|
|
1745
|
-
it('should migrate tools.approvalMode to general.defaultApprovalMode', () => {
|
|
1746
|
-
const userSettingsContent = {
|
|
1747
|
-
tools: {
|
|
1748
|
-
approvalMode: 'plan',
|
|
1749
|
-
},
|
|
1750
|
-
};
|
|
1751
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1752
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1753
|
-
return JSON.stringify(userSettingsContent);
|
|
1754
|
-
return '{}';
|
|
1755
|
-
});
|
|
1756
|
-
const setValueSpy = vi.spyOn(LoadedSettings.prototype, 'setValue');
|
|
1757
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1758
|
-
migrateDeprecatedSettings(loadedSettings, true);
|
|
1759
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'general', expect.objectContaining({ defaultApprovalMode: 'plan' }));
|
|
1760
|
-
// Verify removal
|
|
1761
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'tools', expect.not.objectContaining({ approvalMode: 'plan' }));
|
|
1762
|
-
});
|
|
1763
|
-
it('should migrate all 4 inverted boolean settings', () => {
|
|
1764
|
-
const userSettingsContent = {
|
|
1765
|
-
general: {
|
|
1766
|
-
disableAutoUpdate: false,
|
|
1767
|
-
disableUpdateNag: true,
|
|
1768
|
-
},
|
|
1769
|
-
context: {
|
|
1770
|
-
fileFiltering: {
|
|
1771
|
-
disableFuzzySearch: false,
|
|
1772
|
-
},
|
|
1773
|
-
},
|
|
1774
|
-
ui: {
|
|
1775
|
-
accessibility: {
|
|
1776
|
-
disableLoadingPhrases: true,
|
|
1777
|
-
},
|
|
1778
|
-
},
|
|
1779
|
-
};
|
|
1780
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1781
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1782
|
-
return JSON.stringify(userSettingsContent);
|
|
1783
|
-
return '{}';
|
|
1784
|
-
});
|
|
1785
|
-
const setValueSpy = vi.spyOn(LoadedSettings.prototype, 'setValue');
|
|
1786
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1787
|
-
migrateDeprecatedSettings(loadedSettings, true);
|
|
1788
|
-
// Check that general settings were migrated with inverted values
|
|
1789
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'general', expect.objectContaining({ enableAutoUpdate: true }));
|
|
1790
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'general', expect.objectContaining({ enableAutoUpdateNotification: false }));
|
|
1791
|
-
// Check context.fileFiltering was migrated
|
|
1792
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'context', expect.objectContaining({
|
|
1793
|
-
fileFiltering: expect.objectContaining({ enableFuzzySearch: true }),
|
|
1794
|
-
}));
|
|
1795
|
-
// Check ui.accessibility was migrated
|
|
1796
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'ui', expect.objectContaining({
|
|
1797
|
-
accessibility: expect.objectContaining({
|
|
1798
|
-
enableLoadingPhrases: false,
|
|
1799
|
-
}),
|
|
1800
|
-
}));
|
|
1801
|
-
// Check that enableLoadingPhrases: false was further migrated to loadingPhrases: 'off'
|
|
1802
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'ui', expect.objectContaining({
|
|
1803
|
-
loadingPhrases: 'off',
|
|
1804
|
-
}));
|
|
1805
|
-
});
|
|
1806
|
-
it('should migrate enableLoadingPhrases: false to loadingPhrases: off', () => {
|
|
1807
|
-
const userSettingsContent = {
|
|
1808
|
-
ui: {
|
|
1809
|
-
accessibility: {
|
|
1810
|
-
enableLoadingPhrases: false,
|
|
1811
|
-
},
|
|
1812
|
-
},
|
|
1813
|
-
};
|
|
1814
|
-
const loadedSettings = createMockSettings(userSettingsContent);
|
|
1815
|
-
const setValueSpy = vi.spyOn(loadedSettings, 'setValue');
|
|
1816
|
-
migrateDeprecatedSettings(loadedSettings);
|
|
1817
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'ui', expect.objectContaining({
|
|
1818
|
-
loadingPhrases: 'off',
|
|
1819
|
-
}));
|
|
1820
|
-
});
|
|
1821
|
-
it('should not migrate enableLoadingPhrases: true to loadingPhrases', () => {
|
|
1822
|
-
const userSettingsContent = {
|
|
1823
|
-
ui: {
|
|
1824
|
-
accessibility: {
|
|
1825
|
-
enableLoadingPhrases: true,
|
|
1826
|
-
},
|
|
1827
|
-
},
|
|
1828
|
-
};
|
|
1829
|
-
const loadedSettings = createMockSettings(userSettingsContent);
|
|
1830
|
-
const setValueSpy = vi.spyOn(loadedSettings, 'setValue');
|
|
1831
|
-
migrateDeprecatedSettings(loadedSettings);
|
|
1832
|
-
// Should not set loadingPhrases when enableLoadingPhrases is true
|
|
1833
|
-
const uiCalls = setValueSpy.mock.calls.filter((call) => call[1] === 'ui');
|
|
1834
|
-
for (const call of uiCalls) {
|
|
1835
|
-
const uiValue = call[2];
|
|
1836
|
-
expect(uiValue).not.toHaveProperty('loadingPhrases');
|
|
1837
|
-
}
|
|
1838
|
-
});
|
|
1839
|
-
it('should not overwrite existing loadingPhrases during migration', () => {
|
|
1840
|
-
const userSettingsContent = {
|
|
1841
|
-
ui: {
|
|
1842
|
-
loadingPhrases: 'witty',
|
|
1843
|
-
accessibility: {
|
|
1844
|
-
enableLoadingPhrases: false,
|
|
1845
|
-
},
|
|
1846
|
-
},
|
|
1847
|
-
};
|
|
1848
|
-
const loadedSettings = createMockSettings(userSettingsContent);
|
|
1849
|
-
const setValueSpy = vi.spyOn(loadedSettings, 'setValue');
|
|
1850
|
-
migrateDeprecatedSettings(loadedSettings);
|
|
1851
|
-
// Should not overwrite existing loadingPhrases
|
|
1852
|
-
const uiCalls = setValueSpy.mock.calls.filter((call) => call[1] === 'ui');
|
|
1853
|
-
for (const call of uiCalls) {
|
|
1854
|
-
const uiValue = call[2];
|
|
1855
|
-
if (uiValue['loadingPhrases'] !== undefined) {
|
|
1856
|
-
expect(uiValue['loadingPhrases']).toBe('witty');
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
});
|
|
1860
|
-
it('should remove deprecated settings by default and prioritize new ones', () => {
|
|
1861
|
-
const userSettingsContent = {
|
|
1862
|
-
general: {
|
|
1863
|
-
disableAutoUpdate: true,
|
|
1864
|
-
enableAutoUpdate: true, // Trust this (true) over disableAutoUpdate (true -> false)
|
|
1865
|
-
},
|
|
1866
|
-
context: {
|
|
1867
|
-
fileFiltering: {
|
|
1868
|
-
disableFuzzySearch: false,
|
|
1869
|
-
enableFuzzySearch: false, // Trust this (false) over disableFuzzySearch (false -> true)
|
|
1870
|
-
},
|
|
1871
|
-
},
|
|
1872
|
-
};
|
|
1873
|
-
const loadedSettings = createMockSettings(userSettingsContent);
|
|
1874
|
-
const setValueSpy = vi.spyOn(loadedSettings, 'setValue');
|
|
1875
|
-
// Default is now removeDeprecated = true
|
|
1876
|
-
migrateDeprecatedSettings(loadedSettings);
|
|
1877
|
-
// Should remove disableAutoUpdate and trust enableAutoUpdate: true
|
|
1878
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'general', {
|
|
1879
|
-
enableAutoUpdate: true,
|
|
1880
|
-
});
|
|
1881
|
-
// Should remove disableFuzzySearch and trust enableFuzzySearch: false
|
|
1882
|
-
expect(setValueSpy).toHaveBeenCalledWith(SettingScope.User, 'context', {
|
|
1883
|
-
fileFiltering: { enableFuzzySearch: false },
|
|
1884
|
-
});
|
|
1885
|
-
});
|
|
1886
|
-
it('should preserve deprecated settings when removeDeprecated is explicitly false', () => {
|
|
1887
|
-
const userSettingsContent = {
|
|
1888
|
-
general: {
|
|
1889
|
-
disableAutoUpdate: true,
|
|
1890
|
-
enableAutoUpdate: true,
|
|
1891
|
-
},
|
|
1892
|
-
context: {
|
|
1893
|
-
fileFiltering: {
|
|
1894
|
-
disableFuzzySearch: false,
|
|
1895
|
-
enableFuzzySearch: false,
|
|
1896
|
-
},
|
|
1897
|
-
},
|
|
1898
|
-
};
|
|
1899
|
-
const loadedSettings = createMockSettings(userSettingsContent);
|
|
1900
|
-
migrateDeprecatedSettings(loadedSettings, false);
|
|
1901
|
-
// Should still have old settings since removeDeprecated = false
|
|
1902
|
-
expect(loadedSettings.forScope(SettingScope.User).settings.general).toHaveProperty('disableAutoUpdate');
|
|
1903
|
-
expect(loadedSettings.forScope(SettingScope.User).settings.context.fileFiltering).toHaveProperty('disableFuzzySearch');
|
|
1904
|
-
});
|
|
1905
|
-
it('should trigger migration automatically during loadSettings', () => {
|
|
1906
|
-
mockFsExistsSync.mockImplementation((p) => normalizePath(p) === normalizePath(USER_SETTINGS_PATH));
|
|
1907
|
-
const userSettingsContent = {
|
|
1908
|
-
general: {
|
|
1909
|
-
disableAutoUpdate: true,
|
|
1910
|
-
},
|
|
1911
|
-
};
|
|
1912
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1913
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
1914
|
-
return JSON.stringify(userSettingsContent);
|
|
1915
|
-
return '{}';
|
|
1916
|
-
});
|
|
1917
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1918
|
-
// Verify it was migrated in the merged settings
|
|
1919
|
-
expect(settings.merged.general?.enableAutoUpdate).toBe(false);
|
|
1920
|
-
// Verify it was saved back to disk (via setValue calling updateSettingsFilePreservingFormat)
|
|
1921
|
-
expect(updateSettingsFilePreservingFormat).toHaveBeenCalledWith(USER_SETTINGS_PATH, expect.objectContaining({
|
|
1922
|
-
general: expect.objectContaining({ enableAutoUpdate: false }),
|
|
1923
|
-
}));
|
|
1924
|
-
});
|
|
1925
|
-
it('should migrate disableUpdateNag to enableAutoUpdateNotification in memory but not save for system and system defaults settings', () => {
|
|
1926
|
-
const systemSettingsContent = {
|
|
1927
|
-
general: {
|
|
1928
|
-
disableUpdateNag: true,
|
|
1929
|
-
},
|
|
1930
|
-
};
|
|
1931
|
-
const systemDefaultsContent = {
|
|
1932
|
-
general: {
|
|
1933
|
-
disableUpdateNag: false,
|
|
1934
|
-
},
|
|
1935
|
-
};
|
|
1936
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
1937
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1938
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath())) {
|
|
1939
|
-
return JSON.stringify(systemSettingsContent);
|
|
1940
|
-
}
|
|
1941
|
-
if (normalizePath(p) === normalizePath(getSystemDefaultsPath())) {
|
|
1942
|
-
return JSON.stringify(systemDefaultsContent);
|
|
1943
|
-
}
|
|
1944
|
-
return '{}';
|
|
1945
|
-
});
|
|
1946
|
-
const feedbackSpy = mockCoreEvents.emitFeedback;
|
|
1947
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1948
|
-
// Verify system settings were migrated in memory
|
|
1949
|
-
expect(settings.system.settings.general).toHaveProperty('enableAutoUpdateNotification');
|
|
1950
|
-
expect(settings.system.settings.general['enableAutoUpdateNotification']).toBe(false);
|
|
1951
|
-
// Verify system defaults settings were migrated in memory
|
|
1952
|
-
expect(settings.systemDefaults.settings.general).toHaveProperty('enableAutoUpdateNotification');
|
|
1953
|
-
expect(settings.systemDefaults.settings.general['enableAutoUpdateNotification']).toBe(true);
|
|
1954
|
-
// Merged should also reflect it (system overrides defaults, but both are migrated)
|
|
1955
|
-
expect(settings.merged.general?.enableAutoUpdateNotification).toBe(false);
|
|
1956
|
-
// Verify it was NOT saved back to disk
|
|
1957
|
-
expect(updateSettingsFilePreservingFormat).not.toHaveBeenCalledWith(getSystemSettingsPath(), expect.anything());
|
|
1958
|
-
expect(updateSettingsFilePreservingFormat).not.toHaveBeenCalledWith(getSystemDefaultsPath(), expect.anything());
|
|
1959
|
-
// Verify warnings were shown
|
|
1960
|
-
expect(feedbackSpy).toHaveBeenCalledWith('warning', expect.stringContaining('The system configuration contains deprecated settings'));
|
|
1961
|
-
expect(feedbackSpy).toHaveBeenCalledWith('warning', expect.stringContaining('The system default configuration contains deprecated settings'));
|
|
1962
|
-
});
|
|
1963
|
-
it('should migrate experimental agent settings in system scope in memory but not save', () => {
|
|
1964
|
-
const systemSettingsContent = {
|
|
1965
|
-
experimental: {
|
|
1966
|
-
codebaseInvestigatorSettings: {
|
|
1967
|
-
enabled: true,
|
|
1968
|
-
},
|
|
1969
|
-
},
|
|
1970
|
-
};
|
|
1971
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
1972
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
1973
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath())) {
|
|
1974
|
-
return JSON.stringify(systemSettingsContent);
|
|
1975
|
-
}
|
|
1976
|
-
return '{}';
|
|
1977
|
-
});
|
|
1978
|
-
const feedbackSpy = mockCoreEvents.emitFeedback;
|
|
1979
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
1980
|
-
// Verify it was migrated in memory
|
|
1981
|
-
expect(settings.system.settings.agents?.overrides).toMatchObject({
|
|
1982
|
-
codebase_investigator: {
|
|
1983
|
-
enabled: true,
|
|
1984
|
-
},
|
|
1985
|
-
});
|
|
1986
|
-
// Verify it was NOT saved back to disk
|
|
1987
|
-
expect(updateSettingsFilePreservingFormat).not.toHaveBeenCalledWith(getSystemSettingsPath(), expect.anything());
|
|
1988
|
-
// Verify warnings were shown
|
|
1989
|
-
expect(feedbackSpy).toHaveBeenCalledWith('warning', expect.stringContaining('The system configuration contains deprecated settings: [experimental.codebaseInvestigatorSettings]'));
|
|
1990
|
-
});
|
|
1991
|
-
it('should migrate experimental agent settings to agents overrides', () => {
|
|
1992
|
-
const userSettingsContent = {
|
|
1993
|
-
experimental: {
|
|
1994
|
-
codebaseInvestigatorSettings: {
|
|
1995
|
-
enabled: true,
|
|
1996
|
-
maxNumTurns: 15,
|
|
1997
|
-
maxTimeMinutes: 5,
|
|
1998
|
-
thinkingBudget: 16384,
|
|
1999
|
-
model: 'gemini-1.5-pro',
|
|
2000
|
-
},
|
|
2001
|
-
cliHelpAgentSettings: {
|
|
2002
|
-
enabled: false,
|
|
2003
|
-
},
|
|
2004
|
-
},
|
|
2005
|
-
};
|
|
2006
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
2007
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
2008
|
-
if (normalizePath(p) === normalizePath(USER_SETTINGS_PATH))
|
|
2009
|
-
return JSON.stringify(userSettingsContent);
|
|
2010
|
-
return '{}';
|
|
2011
|
-
});
|
|
2012
|
-
const settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
2013
|
-
// Verify migration to agents.overrides
|
|
2014
|
-
expect(settings.user.settings.agents?.overrides).toMatchObject({
|
|
2015
|
-
codebase_investigator: {
|
|
2016
|
-
enabled: true,
|
|
2017
|
-
runConfig: {
|
|
2018
|
-
maxTurns: 15,
|
|
2019
|
-
maxTimeMinutes: 5,
|
|
2020
|
-
},
|
|
2021
|
-
modelConfig: {
|
|
2022
|
-
model: 'gemini-1.5-pro',
|
|
2023
|
-
generateContentConfig: {
|
|
2024
|
-
thinkingConfig: {
|
|
2025
|
-
thinkingBudget: 16384,
|
|
2026
|
-
},
|
|
2027
|
-
},
|
|
2028
|
-
},
|
|
2029
|
-
},
|
|
2030
|
-
cli_help: {
|
|
2031
|
-
enabled: false,
|
|
2032
|
-
},
|
|
2033
|
-
});
|
|
2034
|
-
});
|
|
2035
|
-
});
|
|
2036
|
-
describe('saveSettings', () => {
|
|
2037
|
-
it('should save settings using updateSettingsFilePreservingFormat', () => {
|
|
2038
|
-
const mockUpdateSettings = vi.mocked(updateSettingsFilePreservingFormat);
|
|
2039
|
-
const settingsFile = createMockSettings({ ui: { theme: 'dark' } }).user;
|
|
2040
|
-
settingsFile.path = path.resolve('/mock/settings.json');
|
|
2041
|
-
saveSettings(settingsFile);
|
|
2042
|
-
expect(mockUpdateSettings).toHaveBeenCalledWith(path.resolve('/mock/settings.json'), {
|
|
2043
|
-
ui: { theme: 'dark' },
|
|
2044
|
-
});
|
|
2045
|
-
});
|
|
2046
|
-
it('should create directory if it does not exist', () => {
|
|
2047
|
-
const mockFsExistsSync = vi.mocked(fs.existsSync);
|
|
2048
|
-
const mockFsMkdirSync = vi.mocked(fs.mkdirSync);
|
|
2049
|
-
mockFsExistsSync.mockReturnValue(false);
|
|
2050
|
-
const settingsFile = createMockSettings({}).user;
|
|
2051
|
-
settingsFile.path = path.resolve('/mock/new/dir/settings.json');
|
|
2052
|
-
saveSettings(settingsFile);
|
|
2053
|
-
expect(mockFsExistsSync).toHaveBeenCalledWith(path.resolve('/mock/new/dir'));
|
|
2054
|
-
expect(mockFsMkdirSync).toHaveBeenCalledWith(path.resolve('/mock/new/dir'), {
|
|
2055
|
-
recursive: true,
|
|
2056
|
-
});
|
|
2057
|
-
});
|
|
2058
|
-
it('should emit error feedback if saving fails', () => {
|
|
2059
|
-
const mockUpdateSettings = vi.mocked(updateSettingsFilePreservingFormat);
|
|
2060
|
-
const error = new Error('Write failed');
|
|
2061
|
-
mockUpdateSettings.mockImplementation(() => {
|
|
2062
|
-
throw error;
|
|
2063
|
-
});
|
|
2064
|
-
const settingsFile = createMockSettings({}).user;
|
|
2065
|
-
settingsFile.path = path.resolve('/mock/settings.json');
|
|
2066
|
-
saveSettings(settingsFile);
|
|
2067
|
-
expect(mockCoreEvents.emitFeedback).toHaveBeenCalledWith('error', 'Failed to save settings: Write failed', error);
|
|
2068
|
-
});
|
|
2069
|
-
});
|
|
2070
|
-
describe('LoadedSettings and remote admin settings', () => {
|
|
2071
|
-
it('should prioritize remote admin settings over file-based admin settings', () => {
|
|
2072
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
2073
|
-
const systemSettingsContent = {
|
|
2074
|
-
admin: {
|
|
2075
|
-
// These should be ignored
|
|
2076
|
-
secureModeEnabled: true,
|
|
2077
|
-
mcp: { enabled: false },
|
|
2078
|
-
extensions: { enabled: false },
|
|
2079
|
-
},
|
|
2080
|
-
// A non-admin setting to ensure it's still processed
|
|
2081
|
-
ui: { theme: 'system-theme' },
|
|
2082
|
-
};
|
|
2083
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
2084
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath())) {
|
|
2085
|
-
return JSON.stringify(systemSettingsContent);
|
|
2086
|
-
}
|
|
2087
|
-
return '{}';
|
|
2088
|
-
});
|
|
2089
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
2090
|
-
// 1. Verify that on initial load, file-based admin settings are ignored
|
|
2091
|
-
// and schema defaults are used instead.
|
|
2092
|
-
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false); // default: false
|
|
2093
|
-
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(true); // default: true
|
|
2094
|
-
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(true); // default: true
|
|
2095
|
-
expect(loadedSettings.merged.ui?.theme).toBe('system-theme'); // non-admin setting should be loaded
|
|
2096
|
-
// 2. Now, set remote admin settings.
|
|
2097
|
-
loadedSettings.setRemoteAdminSettings({
|
|
2098
|
-
strictModeDisabled: false,
|
|
2099
|
-
mcpSetting: { mcpEnabled: false, mcpConfig: {} },
|
|
2100
|
-
cliFeatureSetting: {
|
|
2101
|
-
extensionsSetting: { extensionsEnabled: false },
|
|
2102
|
-
unmanagedCapabilitiesEnabled: false,
|
|
2103
|
-
},
|
|
2104
|
-
});
|
|
2105
|
-
// 3. Verify that remote admin settings take precedence.
|
|
2106
|
-
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
|
|
2107
|
-
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(false);
|
|
2108
|
-
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false);
|
|
2109
|
-
// non-admin setting should remain unchanged
|
|
2110
|
-
expect(loadedSettings.merged.ui?.theme).toBe('system-theme');
|
|
2111
|
-
});
|
|
2112
|
-
it('should set remote admin settings and recompute merged settings', () => {
|
|
2113
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
2114
|
-
const systemSettingsContent = {
|
|
2115
|
-
admin: {
|
|
2116
|
-
secureModeEnabled: false,
|
|
2117
|
-
mcp: { enabled: false },
|
|
2118
|
-
extensions: { enabled: false },
|
|
2119
|
-
},
|
|
2120
|
-
ui: { theme: 'initial-theme' },
|
|
2121
|
-
};
|
|
2122
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
2123
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath())) {
|
|
2124
|
-
return JSON.stringify(systemSettingsContent);
|
|
2125
|
-
}
|
|
2126
|
-
return '{}';
|
|
2127
|
-
});
|
|
2128
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
2129
|
-
// Ensure initial state from defaults (as file-based admin settings are ignored)
|
|
2130
|
-
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
|
|
2131
|
-
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(true);
|
|
2132
|
-
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(true);
|
|
2133
|
-
expect(loadedSettings.merged.ui?.theme).toBe('initial-theme');
|
|
2134
|
-
const newRemoteSettings = {
|
|
2135
|
-
strictModeDisabled: false,
|
|
2136
|
-
mcpSetting: { mcpEnabled: false, mcpConfig: {} },
|
|
2137
|
-
cliFeatureSetting: {
|
|
2138
|
-
extensionsSetting: { extensionsEnabled: false },
|
|
2139
|
-
unmanagedCapabilitiesEnabled: false,
|
|
2140
|
-
},
|
|
2141
|
-
};
|
|
2142
|
-
loadedSettings.setRemoteAdminSettings(newRemoteSettings);
|
|
2143
|
-
// Verify that remote admin settings are applied
|
|
2144
|
-
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
|
|
2145
|
-
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(false);
|
|
2146
|
-
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false);
|
|
2147
|
-
// Non-admin settings should remain untouched
|
|
2148
|
-
expect(loadedSettings.merged.ui?.theme).toBe('initial-theme');
|
|
2149
|
-
});
|
|
2150
|
-
it('should correctly handle undefined remote admin settings', () => {
|
|
2151
|
-
mockFsExistsSync.mockReturnValue(true);
|
|
2152
|
-
const systemSettingsContent = {
|
|
2153
|
-
ui: { theme: 'initial-theme' },
|
|
2154
|
-
};
|
|
2155
|
-
fs.readFileSync.mockImplementation((p) => {
|
|
2156
|
-
if (normalizePath(p) === normalizePath(getSystemSettingsPath())) {
|
|
2157
|
-
return JSON.stringify(systemSettingsContent);
|
|
2158
|
-
}
|
|
2159
|
-
return '{}';
|
|
2160
|
-
});
|
|
2161
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
2162
|
-
// Should have default admin settings
|
|
2163
|
-
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
|
|
2164
|
-
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(true);
|
|
2165
|
-
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(true);
|
|
2166
|
-
loadedSettings.setRemoteAdminSettings({}); // Set empty remote settings
|
|
2167
|
-
// Admin settings should revert to defaults because there are no remote overrides
|
|
2168
|
-
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
|
|
2169
|
-
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(true);
|
|
2170
|
-
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(true);
|
|
2171
|
-
});
|
|
2172
|
-
it('should un-nest MCP configuration from remote settings', () => {
|
|
2173
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
2174
|
-
const mcpServers = {
|
|
2175
|
-
'admin-server': {
|
|
2176
|
-
url: 'http://admin-mcp.com',
|
|
2177
|
-
type: 'sse',
|
|
2178
|
-
trust: true,
|
|
2179
|
-
},
|
|
2180
|
-
};
|
|
2181
|
-
loadedSettings.setRemoteAdminSettings({
|
|
2182
|
-
mcpSetting: {
|
|
2183
|
-
mcpEnabled: true,
|
|
2184
|
-
mcpConfig: {
|
|
2185
|
-
mcpServers,
|
|
2186
|
-
},
|
|
2187
|
-
},
|
|
2188
|
-
});
|
|
2189
|
-
expect(loadedSettings.merged.admin?.mcp?.config).toEqual(mcpServers);
|
|
2190
|
-
});
|
|
2191
|
-
it('should map requiredMcpConfig from remote settings', () => {
|
|
2192
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
2193
|
-
const requiredMcpConfig = {
|
|
2194
|
-
'corp-tool': {
|
|
2195
|
-
url: 'https://mcp.corp/tool',
|
|
2196
|
-
type: 'http',
|
|
2197
|
-
trust: true,
|
|
2198
|
-
},
|
|
2199
|
-
};
|
|
2200
|
-
loadedSettings.setRemoteAdminSettings({
|
|
2201
|
-
mcpSetting: {
|
|
2202
|
-
mcpEnabled: true,
|
|
2203
|
-
requiredMcpConfig,
|
|
2204
|
-
},
|
|
2205
|
-
});
|
|
2206
|
-
expect(loadedSettings.merged.admin?.mcp?.requiredConfig).toEqual(requiredMcpConfig);
|
|
2207
|
-
});
|
|
2208
|
-
it('should set skills based on unmanagedCapabilitiesEnabled', () => {
|
|
2209
|
-
const loadedSettings = loadSettings();
|
|
2210
|
-
loadedSettings.setRemoteAdminSettings({
|
|
2211
|
-
cliFeatureSetting: {
|
|
2212
|
-
unmanagedCapabilitiesEnabled: true,
|
|
2213
|
-
},
|
|
2214
|
-
});
|
|
2215
|
-
expect(loadedSettings.merged.admin.skills?.enabled).toBe(true);
|
|
2216
|
-
loadedSettings.setRemoteAdminSettings({
|
|
2217
|
-
cliFeatureSetting: {
|
|
2218
|
-
unmanagedCapabilitiesEnabled: false,
|
|
2219
|
-
},
|
|
2220
|
-
});
|
|
2221
|
-
expect(loadedSettings.merged.admin.skills?.enabled).toBe(false);
|
|
2222
|
-
});
|
|
2223
|
-
it('should handle completely empty remote admin settings response', () => {
|
|
2224
|
-
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
2225
|
-
loadedSettings.setRemoteAdminSettings({});
|
|
2226
|
-
// Should default to schema defaults (standard defaults)
|
|
2227
|
-
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
|
|
2228
|
-
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(true);
|
|
2229
|
-
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(true);
|
|
2230
|
-
});
|
|
2231
|
-
});
|
|
2232
|
-
describe('getDefaultsFromSchema', () => {
|
|
2233
|
-
it('should extract defaults from a schema', () => {
|
|
2234
|
-
const mockSchema = {
|
|
2235
|
-
prop1: {
|
|
2236
|
-
type: 'string',
|
|
2237
|
-
default: 'default1',
|
|
2238
|
-
label: 'Prop 1',
|
|
2239
|
-
category: 'General',
|
|
2240
|
-
requiresRestart: false,
|
|
2241
|
-
},
|
|
2242
|
-
nested: {
|
|
2243
|
-
type: 'object',
|
|
2244
|
-
label: 'Nested',
|
|
2245
|
-
category: 'General',
|
|
2246
|
-
requiresRestart: false,
|
|
2247
|
-
default: {},
|
|
2248
|
-
properties: {
|
|
2249
|
-
prop2: {
|
|
2250
|
-
type: 'number',
|
|
2251
|
-
default: 42,
|
|
2252
|
-
label: 'Prop 2',
|
|
2253
|
-
category: 'General',
|
|
2254
|
-
requiresRestart: false,
|
|
2255
|
-
},
|
|
2256
|
-
},
|
|
2257
|
-
},
|
|
2258
|
-
};
|
|
2259
|
-
const defaults = getDefaultsFromSchema(mockSchema);
|
|
2260
|
-
expect(defaults).toEqual({
|
|
2261
|
-
prop1: 'default1',
|
|
2262
|
-
nested: {
|
|
2263
|
-
prop2: 42,
|
|
2264
|
-
},
|
|
2265
|
-
});
|
|
2266
|
-
});
|
|
2267
|
-
});
|
|
2268
|
-
describe('Reactivity & Snapshots', () => {
|
|
2269
|
-
let loadedSettings;
|
|
2270
|
-
beforeEach(() => {
|
|
2271
|
-
const emptySettingsFile = {
|
|
2272
|
-
path: path.resolve('/mock/path'),
|
|
2273
|
-
settings: {},
|
|
2274
|
-
originalSettings: {},
|
|
2275
|
-
};
|
|
2276
|
-
loadedSettings = new LoadedSettings({ ...emptySettingsFile, path: getSystemSettingsPath() }, { ...emptySettingsFile, path: getSystemDefaultsPath() }, { ...emptySettingsFile, path: USER_SETTINGS_PATH }, { ...emptySettingsFile, path: MOCK_WORKSPACE_SETTINGS_PATH }, true, // isTrusted
|
|
2277
|
-
[]);
|
|
2278
|
-
});
|
|
2279
|
-
it('getSnapshot() should return stable reference if no changes occur', () => {
|
|
2280
|
-
const snap1 = loadedSettings.getSnapshot();
|
|
2281
|
-
const snap2 = loadedSettings.getSnapshot();
|
|
2282
|
-
expect(snap1).toBe(snap2);
|
|
2283
|
-
});
|
|
2284
|
-
it('getSnapshot() should preserve readOnly metadata for each scope', () => {
|
|
2285
|
-
const readonlySettings = new LoadedSettings({
|
|
2286
|
-
path: getSystemSettingsPath(),
|
|
2287
|
-
settings: {},
|
|
2288
|
-
originalSettings: {},
|
|
2289
|
-
readOnly: true,
|
|
2290
|
-
}, {
|
|
2291
|
-
path: getSystemDefaultsPath(),
|
|
2292
|
-
settings: {},
|
|
2293
|
-
originalSettings: {},
|
|
2294
|
-
readOnly: true,
|
|
2295
|
-
}, {
|
|
2296
|
-
path: USER_SETTINGS_PATH,
|
|
2297
|
-
settings: {},
|
|
2298
|
-
originalSettings: {},
|
|
2299
|
-
readOnly: false,
|
|
2300
|
-
}, {
|
|
2301
|
-
path: MOCK_WORKSPACE_SETTINGS_PATH,
|
|
2302
|
-
settings: {},
|
|
2303
|
-
originalSettings: {},
|
|
2304
|
-
readOnly: true,
|
|
2305
|
-
}, true, []);
|
|
2306
|
-
const snapshot = readonlySettings.getSnapshot();
|
|
2307
|
-
expect(snapshot.system.readOnly).toBe(true);
|
|
2308
|
-
expect(snapshot.systemDefaults.readOnly).toBe(true);
|
|
2309
|
-
expect(snapshot.user.readOnly).toBe(false);
|
|
2310
|
-
expect(snapshot.workspace.readOnly).toBe(true);
|
|
2311
|
-
});
|
|
2312
|
-
it('setValue() should create a new snapshot reference and emit event', () => {
|
|
2313
|
-
const oldSnapshot = loadedSettings.getSnapshot();
|
|
2314
|
-
const oldUserRef = oldSnapshot.user.settings;
|
|
2315
|
-
loadedSettings.setValue(SettingScope.User, 'ui.theme', 'high-contrast');
|
|
2316
|
-
const newSnapshot = loadedSettings.getSnapshot();
|
|
2317
|
-
expect(newSnapshot).not.toBe(oldSnapshot);
|
|
2318
|
-
expect(newSnapshot.user.settings).not.toBe(oldUserRef);
|
|
2319
|
-
expect(newSnapshot.user.settings.ui?.theme).toBe('high-contrast');
|
|
2320
|
-
expect(newSnapshot.system.settings).not.toBe(oldSnapshot.system.settings);
|
|
2321
|
-
expect(mockCoreEvents.emitSettingsChanged).toHaveBeenCalled();
|
|
2322
|
-
});
|
|
2323
|
-
});
|
|
2324
|
-
describe('Security and Sandbox', () => {
|
|
2325
|
-
let originalArgv;
|
|
2326
|
-
let originalEnv;
|
|
2327
|
-
beforeEach(() => {
|
|
2328
|
-
originalArgv = [...process.argv];
|
|
2329
|
-
originalEnv = { ...process.env };
|
|
2330
|
-
// Clear relevant env vars
|
|
2331
|
-
delete process.env['GEMINI_API_KEY'];
|
|
2332
|
-
delete process.env['GOOGLE_API_KEY'];
|
|
2333
|
-
delete process.env['GOOGLE_CLOUD_PROJECT'];
|
|
2334
|
-
delete process.env['GOOGLE_CLOUD_LOCATION'];
|
|
2335
|
-
delete process.env['CLOUD_SHELL'];
|
|
2336
|
-
delete process.env['MALICIOUS_VAR'];
|
|
2337
|
-
delete process.env['FOO'];
|
|
2338
|
-
delete process.env['_GEMINI_USER_GCP_PROJECT'];
|
|
2339
|
-
vi.resetAllMocks();
|
|
2340
|
-
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
2341
|
-
});
|
|
2342
|
-
afterEach(() => {
|
|
2343
|
-
process.argv = originalArgv;
|
|
2344
|
-
process.env = originalEnv;
|
|
2345
|
-
});
|
|
2346
|
-
describe('sandbox detection', () => {
|
|
2347
|
-
it('should detect sandbox when -s is a real flag', () => {
|
|
2348
|
-
process.argv = ['node', 'gemini', '-s', 'some prompt'];
|
|
2349
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2350
|
-
isTrusted: false,
|
|
2351
|
-
source: 'file',
|
|
2352
|
-
});
|
|
2353
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
2354
|
-
vi.mocked(fs.readFileSync).mockReturnValue('FOO=bar\nGEMINI_API_KEY=secret');
|
|
2355
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2356
|
-
// If sandboxed and untrusted, FOO should NOT be loaded, but GEMINI_API_KEY should be.
|
|
2357
|
-
expect(process.env['FOO']).toBeUndefined();
|
|
2358
|
-
expect(process.env['GEMINI_API_KEY']).toBe('secret');
|
|
2359
|
-
});
|
|
2360
|
-
it('should detect sandbox when --sandbox is a real flag', () => {
|
|
2361
|
-
process.argv = ['node', 'gemini', '--sandbox', 'prompt'];
|
|
2362
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2363
|
-
isTrusted: false,
|
|
2364
|
-
source: 'file',
|
|
2365
|
-
});
|
|
2366
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
2367
|
-
vi.mocked(fs.readFileSync).mockReturnValue('GEMINI_API_KEY=secret');
|
|
2368
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2369
|
-
expect(process.env['GEMINI_API_KEY']).toBe('secret');
|
|
2370
|
-
});
|
|
2371
|
-
it('should ignore sandbox flags if they appear after --', () => {
|
|
2372
|
-
process.argv = ['node', 'gemini', '--', '-s', 'some prompt'];
|
|
2373
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2374
|
-
isTrusted: false,
|
|
2375
|
-
source: 'file',
|
|
2376
|
-
});
|
|
2377
|
-
vi.mocked(fs.existsSync).mockImplementation((path) => path.toString().endsWith('.env'));
|
|
2378
|
-
vi.mocked(fs.readFileSync).mockReturnValue('GEMINI_API_KEY=secret');
|
|
2379
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2380
|
-
expect(process.env['GEMINI_API_KEY']).toEqual('secret');
|
|
2381
|
-
});
|
|
2382
|
-
it('should NOT be tricked by positional arguments that look like flags', () => {
|
|
2383
|
-
process.argv = ['node', 'gemini', 'my -s prompt'];
|
|
2384
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2385
|
-
isTrusted: false,
|
|
2386
|
-
source: 'file',
|
|
2387
|
-
});
|
|
2388
|
-
vi.mocked(fs.existsSync).mockImplementation((path) => path.toString().endsWith('.env'));
|
|
2389
|
-
vi.mocked(fs.readFileSync).mockReturnValue('GEMINI_API_KEY=secret');
|
|
2390
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2391
|
-
expect(process.env['GEMINI_API_KEY']).toEqual('secret');
|
|
2392
|
-
});
|
|
2393
|
-
});
|
|
2394
|
-
describe('env var sanitization', () => {
|
|
2395
|
-
it('should strictly enforce whitelist in untrusted/sandboxed mode', () => {
|
|
2396
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2397
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2398
|
-
isTrusted: false,
|
|
2399
|
-
source: 'file',
|
|
2400
|
-
});
|
|
2401
|
-
vi.mocked(fs.existsSync).mockImplementation((path) => path.toString().endsWith('.env'));
|
|
2402
|
-
vi.mocked(fs.readFileSync).mockReturnValue(`
|
|
2403
|
-
GEMINI_API_KEY=secret-key
|
|
2404
|
-
MALICIOUS_VAR=should-be-ignored
|
|
2405
|
-
GOOGLE_API_KEY=another-secret
|
|
2406
|
-
`);
|
|
2407
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2408
|
-
expect(process.env['GEMINI_API_KEY']).toBe('secret-key');
|
|
2409
|
-
expect(process.env['GOOGLE_API_KEY']).toBe('another-secret');
|
|
2410
|
-
expect(process.env['MALICIOUS_VAR']).toBeUndefined();
|
|
2411
|
-
});
|
|
2412
|
-
it('should sanitize shell injection characters in whitelisted env vars in untrusted mode', () => {
|
|
2413
|
-
process.argv = ['node', 'gemini', '--sandbox', 'prompt'];
|
|
2414
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2415
|
-
isTrusted: false,
|
|
2416
|
-
source: 'file',
|
|
2417
|
-
});
|
|
2418
|
-
vi.mocked(fs.existsSync).mockImplementation((path) => path.toString().endsWith('.env'));
|
|
2419
|
-
const maliciousPayload = 'key-$(whoami)-`id`-&|;><*?[]{}';
|
|
2420
|
-
vi.mocked(fs.readFileSync).mockReturnValue(`GEMINI_API_KEY=${maliciousPayload}`);
|
|
2421
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2422
|
-
// sanitizeEnvVar: value.replace(/[^a-zA-Z0-9\-_./]/g, '')
|
|
2423
|
-
expect(process.env['GEMINI_API_KEY']).toBe('key-whoami-id-');
|
|
2424
|
-
});
|
|
2425
|
-
it('should allow . and / in whitelisted env vars but sanitize other characters in untrusted mode', () => {
|
|
2426
|
-
process.argv = ['node', 'gemini', '--sandbox', 'prompt'];
|
|
2427
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2428
|
-
isTrusted: false,
|
|
2429
|
-
source: 'file',
|
|
2430
|
-
});
|
|
2431
|
-
vi.mocked(fs.existsSync).mockImplementation((path) => path.toString().endsWith('.env'));
|
|
2432
|
-
const complexPayload = 'secret-123/path.to/somewhere;rm -rf /';
|
|
2433
|
-
vi.mocked(fs.readFileSync).mockReturnValue(`GEMINI_API_KEY=${complexPayload}`);
|
|
2434
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2435
|
-
expect(process.env['GEMINI_API_KEY']).toBe('secret-123/path.to/somewhererm-rf/');
|
|
2436
|
-
});
|
|
2437
|
-
it('should NOT sanitize variables from trusted sources', () => {
|
|
2438
|
-
process.argv = ['node', 'gemini', 'prompt'];
|
|
2439
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2440
|
-
isTrusted: true,
|
|
2441
|
-
source: 'file',
|
|
2442
|
-
});
|
|
2443
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
2444
|
-
vi.mocked(fs.readFileSync).mockReturnValue('FOO=$(bar)');
|
|
2445
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2446
|
-
// Trusted source, no sanitization
|
|
2447
|
-
expect(process.env['FOO']).toBe('$(bar)');
|
|
2448
|
-
});
|
|
2449
|
-
it('should load environment variables normally when workspace is TRUSTED even if "sandboxed"', () => {
|
|
2450
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2451
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2452
|
-
isTrusted: true,
|
|
2453
|
-
source: 'file',
|
|
2454
|
-
});
|
|
2455
|
-
vi.mocked(fs.existsSync).mockImplementation((path) => path.toString().endsWith('.env'));
|
|
2456
|
-
vi.mocked(fs.readFileSync).mockReturnValue(`
|
|
2457
|
-
GEMINI_API_KEY=un-sanitized;key!
|
|
2458
|
-
MALICIOUS_VAR=allowed-because-trusted
|
|
2459
|
-
`);
|
|
2460
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2461
|
-
expect(process.env['GEMINI_API_KEY']).toBe('un-sanitized;key!');
|
|
2462
|
-
expect(process.env['MALICIOUS_VAR']).toBe('allowed-because-trusted');
|
|
2463
|
-
});
|
|
2464
|
-
it('should sanitize value in sanitizeEnvVar helper', () => {
|
|
2465
|
-
expect(sanitizeEnvVar('$(calc)')).toBe('calc');
|
|
2466
|
-
expect(sanitizeEnvVar('`rm -rf /`')).toBe('rm-rf/');
|
|
2467
|
-
expect(sanitizeEnvVar('normal-project-123')).toBe('normal-project-123');
|
|
2468
|
-
expect(sanitizeEnvVar('us-central1')).toBe('us-central1');
|
|
2469
|
-
});
|
|
2470
|
-
});
|
|
2471
|
-
describe('Cloud Shell security', () => {
|
|
2472
|
-
it('should handle Cloud Shell special defaults securely when untrusted', () => {
|
|
2473
|
-
process.env['CLOUD_SHELL'] = 'true';
|
|
2474
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2475
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2476
|
-
isTrusted: false,
|
|
2477
|
-
source: 'file',
|
|
2478
|
-
});
|
|
2479
|
-
// No .env file
|
|
2480
|
-
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
2481
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2482
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('cloudshell-gca');
|
|
2483
|
-
});
|
|
2484
|
-
it('should not override GOOGLE_CLOUD_PROJECT in Cloud Shell when auth type is vertex-ai', () => {
|
|
2485
|
-
vi.stubEnv('CLOUD_SHELL', 'true');
|
|
2486
|
-
vi.stubEnv('GOOGLE_CLOUD_PROJECT', 'my-vertex-project');
|
|
2487
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2488
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2489
|
-
isTrusted: false,
|
|
2490
|
-
source: 'file',
|
|
2491
|
-
});
|
|
2492
|
-
// No .env file
|
|
2493
|
-
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
2494
|
-
loadEnvironment(createMockSettings({
|
|
2495
|
-
tools: { sandbox: false },
|
|
2496
|
-
security: { auth: { selectedType: AuthType.USE_VERTEX_AI } },
|
|
2497
|
-
}).merged, MOCK_WORKSPACE_DIR);
|
|
2498
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('my-vertex-project');
|
|
2499
|
-
});
|
|
2500
|
-
it('should respect .env override for GOOGLE_CLOUD_PROJECT in Cloud Shell when auth type is vertex-ai', () => {
|
|
2501
|
-
vi.stubEnv('CLOUD_SHELL', 'true');
|
|
2502
|
-
vi.stubEnv('GOOGLE_CLOUD_PROJECT', 'my-vertex-project');
|
|
2503
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2504
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2505
|
-
isTrusted: true,
|
|
2506
|
-
source: 'file',
|
|
2507
|
-
});
|
|
2508
|
-
// Mock .env file to override the shell project
|
|
2509
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
2510
|
-
vi.mocked(fs.readFileSync).mockReturnValue('GOOGLE_CLOUD_PROJECT=env-vertex-project');
|
|
2511
|
-
loadEnvironment(createMockSettings({
|
|
2512
|
-
tools: { sandbox: false },
|
|
2513
|
-
security: { auth: { selectedType: AuthType.USE_VERTEX_AI } },
|
|
2514
|
-
}).merged, MOCK_WORKSPACE_DIR);
|
|
2515
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('env-vertex-project');
|
|
2516
|
-
});
|
|
2517
|
-
it('should clear cloudshell-gca when switching to Vertex AI without an original project', () => {
|
|
2518
|
-
process.env['CLOUD_SHELL'] = 'true';
|
|
2519
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2520
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2521
|
-
isTrusted: false,
|
|
2522
|
-
source: 'file',
|
|
2523
|
-
});
|
|
2524
|
-
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
2525
|
-
// First call: normal Cloud Shell auth sets cloudshell-gca
|
|
2526
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2527
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('cloudshell-gca');
|
|
2528
|
-
// Second call: user switched to Vertex AI, should remove cloudshell-gca
|
|
2529
|
-
loadEnvironment(createMockSettings({
|
|
2530
|
-
tools: { sandbox: false },
|
|
2531
|
-
security: { auth: { selectedType: AuthType.USE_VERTEX_AI } },
|
|
2532
|
-
}).merged, MOCK_WORKSPACE_DIR);
|
|
2533
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBeUndefined();
|
|
2534
|
-
});
|
|
2535
|
-
it('should restore original project when switching to Vertex AI after Cloud Shell override', () => {
|
|
2536
|
-
process.env['CLOUD_SHELL'] = 'true';
|
|
2537
|
-
process.env['GOOGLE_CLOUD_PROJECT'] = 'my-real-project';
|
|
2538
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2539
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2540
|
-
isTrusted: false,
|
|
2541
|
-
source: 'file',
|
|
2542
|
-
});
|
|
2543
|
-
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
2544
|
-
// First call: saves original to _GEMINI_USER_GCP_PROJECT, sets cloudshell-gca
|
|
2545
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2546
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('cloudshell-gca');
|
|
2547
|
-
expect(process.env['_GEMINI_USER_GCP_PROJECT']).toBe('my-real-project');
|
|
2548
|
-
// Second call: switching to Vertex AI should restore the saved value
|
|
2549
|
-
loadEnvironment(createMockSettings({
|
|
2550
|
-
tools: { sandbox: false },
|
|
2551
|
-
security: { auth: { selectedType: AuthType.USE_VERTEX_AI } },
|
|
2552
|
-
}).merged, MOCK_WORKSPACE_DIR);
|
|
2553
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('my-real-project');
|
|
2554
|
-
});
|
|
2555
|
-
it('should restore project after restart when child inherits cloudshell-gca', () => {
|
|
2556
|
-
// Simulate child process after restart: inherits cloudshell-gca and
|
|
2557
|
-
// the saved original from the parent process.
|
|
2558
|
-
process.env['CLOUD_SHELL'] = 'true';
|
|
2559
|
-
process.env['GOOGLE_CLOUD_PROJECT'] = 'cloudshell-gca';
|
|
2560
|
-
process.env['_GEMINI_USER_GCP_PROJECT'] = 'my-real-project';
|
|
2561
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2562
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2563
|
-
isTrusted: false,
|
|
2564
|
-
source: 'file',
|
|
2565
|
-
});
|
|
2566
|
-
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
2567
|
-
loadEnvironment(createMockSettings({
|
|
2568
|
-
tools: { sandbox: false },
|
|
2569
|
-
security: { auth: { selectedType: AuthType.USE_VERTEX_AI } },
|
|
2570
|
-
}).merged, MOCK_WORKSPACE_DIR);
|
|
2571
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('my-real-project');
|
|
2572
|
-
});
|
|
2573
|
-
it('should sanitize GOOGLE_CLOUD_PROJECT in Cloud Shell when loaded from .env in untrusted mode', () => {
|
|
2574
|
-
process.env['CLOUD_SHELL'] = 'true';
|
|
2575
|
-
process.argv = ['node', 'gemini', '-s', 'prompt'];
|
|
2576
|
-
vi.mocked(isWorkspaceTrusted).mockReturnValue({
|
|
2577
|
-
isTrusted: false,
|
|
2578
|
-
source: 'file',
|
|
2579
|
-
});
|
|
2580
|
-
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
2581
|
-
vi.mocked(fs.readFileSync).mockReturnValue('GOOGLE_CLOUD_PROJECT=attacker-project;inject');
|
|
2582
|
-
loadEnvironment(createMockSettings({ tools: { sandbox: false } }).merged, MOCK_WORKSPACE_DIR);
|
|
2583
|
-
expect(process.env['GOOGLE_CLOUD_PROJECT']).toBe('attacker-projectinject');
|
|
2584
|
-
});
|
|
2585
|
-
});
|
|
2586
|
-
});
|
|
2587
|
-
});
|
|
2588
|
-
describe('LoadedSettings Isolation and Serializability', () => {
|
|
2589
|
-
let loadedSettings;
|
|
2590
|
-
beforeEach(() => {
|
|
2591
|
-
vi.resetAllMocks();
|
|
2592
|
-
// Create a minimal LoadedSettings instance
|
|
2593
|
-
const emptyScope = {
|
|
2594
|
-
path: path.resolve('/mock/settings.json'),
|
|
2595
|
-
settings: {},
|
|
2596
|
-
originalSettings: {},
|
|
2597
|
-
};
|
|
2598
|
-
loadedSettings = new LoadedSettings(emptyScope, // system
|
|
2599
|
-
emptyScope, // systemDefaults
|
|
2600
|
-
{ ...emptyScope }, // user
|
|
2601
|
-
emptyScope, // workspace
|
|
2602
|
-
true);
|
|
2603
|
-
});
|
|
2604
|
-
describe('setValue Isolation', () => {
|
|
2605
|
-
it('should isolate state between settings and originalSettings', () => {
|
|
2606
|
-
const complexValue = { a: { b: 1 } };
|
|
2607
|
-
loadedSettings.setValue(SettingScope.User, 'test', complexValue);
|
|
2608
|
-
const userSettings = loadedSettings.forScope(SettingScope.User);
|
|
2609
|
-
const settingsValue = userSettings.settings['test'];
|
|
2610
|
-
const originalValue = userSettings.originalSettings['test'];
|
|
2611
|
-
// Verify they are equal but different references
|
|
2612
|
-
expect(settingsValue).toEqual(complexValue);
|
|
2613
|
-
expect(originalValue).toEqual(complexValue);
|
|
2614
|
-
expect(settingsValue).not.toBe(complexValue);
|
|
2615
|
-
expect(originalValue).not.toBe(complexValue);
|
|
2616
|
-
expect(settingsValue).not.toBe(originalValue);
|
|
2617
|
-
// Modify the in-memory setting object
|
|
2618
|
-
settingsValue.a.b = 2;
|
|
2619
|
-
// originalSettings should NOT be affected
|
|
2620
|
-
expect(originalValue.a.b).toBe(1);
|
|
2621
|
-
});
|
|
2622
|
-
it('should not share references between settings and originalSettings (original servers test)', () => {
|
|
2623
|
-
const mcpServers = {
|
|
2624
|
-
'test-server': { command: 'echo' },
|
|
2625
|
-
};
|
|
2626
|
-
loadedSettings.setValue(SettingScope.User, 'mcpServers', mcpServers);
|
|
2627
|
-
// Modify the original object
|
|
2628
|
-
delete mcpServers['test-server'];
|
|
2629
|
-
// The settings in LoadedSettings should still have the server
|
|
2630
|
-
const userSettings = loadedSettings.forScope(SettingScope.User);
|
|
2631
|
-
expect(userSettings.settings.mcpServers['test-server']).toBeDefined();
|
|
2632
|
-
expect(userSettings.originalSettings.mcpServers['test-server']).toBeDefined();
|
|
2633
|
-
// They should also be different objects from each other
|
|
2634
|
-
expect(userSettings.settings.mcpServers).not.toBe(userSettings.originalSettings.mcpServers);
|
|
2635
|
-
});
|
|
2636
|
-
});
|
|
2637
|
-
describe('setValue Serializability', () => {
|
|
2638
|
-
it('should preserve Map/Set types (via structuredClone)', () => {
|
|
2639
|
-
const mapValue = { myMap: new Map([['key', 'value']]) };
|
|
2640
|
-
loadedSettings.setValue(SettingScope.User, 'test', mapValue);
|
|
2641
|
-
const userSettings = loadedSettings.forScope(SettingScope.User);
|
|
2642
|
-
const settingsValue = userSettings.settings['test'];
|
|
2643
|
-
// Map is preserved by structuredClone
|
|
2644
|
-
expect(settingsValue.myMap).toBeInstanceOf(Map);
|
|
2645
|
-
expect(settingsValue.myMap.get('key')).toBe('value');
|
|
2646
|
-
// But it should be a different reference
|
|
2647
|
-
expect(settingsValue.myMap).not.toBe(mapValue.myMap);
|
|
2648
|
-
});
|
|
2649
|
-
it('should handle circular references (structuredClone supports them, but deepMerge may not)', () => {
|
|
2650
|
-
const circular = { a: 1 };
|
|
2651
|
-
circular['self'] = circular;
|
|
2652
|
-
// structuredClone(circular) works, but LoadedSettings.setValue calls
|
|
2653
|
-
// computeMergedSettings() -> customDeepMerge() which blows up on circularity.
|
|
2654
|
-
expect(() => {
|
|
2655
|
-
loadedSettings.setValue(SettingScope.User, 'test', circular);
|
|
2656
|
-
}).toThrow(/Maximum call stack size exceeded/);
|
|
2657
|
-
});
|
|
2658
|
-
});
|
|
2659
|
-
});
|
|
2660
|
-
//# sourceMappingURL=settings.test.js.map
|