diff options
| author | Ali Al Jufairi <[email protected]> | 2025-08-10 09:04:52 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-10 00:04:52 +0000 |
| commit | 8a9a9275440e3681e9be73d741a5aba429ae501f (patch) | |
| tree | cc2c17101c57d0c34049a6ee390d0f1b9bf38018 /packages/cli/src/config | |
| parent | c632ec8b03ac5b459da9ccb041b9fca19252f69b (diff) | |
feat(ui): add /settings command and UI panel (#4738)
Co-authored-by: Jacob Richman <[email protected]>
Diffstat (limited to 'packages/cli/src/config')
| -rw-r--r-- | packages/cli/src/config/settings.ts | 91 | ||||
| -rw-r--r-- | packages/cli/src/config/settingsSchema.test.ts | 253 | ||||
| -rw-r--r-- | packages/cli/src/config/settingsSchema.ts | 516 |
3 files changed, 773 insertions, 87 deletions
diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts index 3c4270d7..36fd50f1 100644 --- a/packages/cli/src/config/settings.ts +++ b/packages/cli/src/config/settings.ts @@ -9,18 +9,15 @@ import * as path from 'path'; import { homedir, platform } from 'os'; import * as dotenv from 'dotenv'; import { - MCPServerConfig, GEMINI_CONFIG_DIR as GEMINI_DIR, getErrorMessage, - BugCommandSettings, - ChatCompressionSettings, - TelemetrySettings, - AuthType, } from '@google/gemini-cli-core'; import stripJsonComments from 'strip-json-comments'; import { DefaultLight } from '../ui/themes/default-light.js'; import { DefaultDark } from '../ui/themes/default.js'; -import { CustomTheme } from '../ui/themes/theme.js'; +import { Settings, MemoryImportFormat } from './settingsSchema.js'; + +export type { Settings, MemoryImportFormat }; export const SETTINGS_DIRECTORY_NAME = '.gemini'; export const USER_SETTINGS_DIR = path.join(homedir(), SETTINGS_DIRECTORY_NAME); @@ -44,7 +41,7 @@ export function getWorkspaceSettingsPath(workspaceDir: string): string { return path.join(workspaceDir, SETTINGS_DIRECTORY_NAME, 'settings.json'); } -export type DnsResolutionOrder = 'ipv4first' | 'verbatim'; +export type { DnsResolutionOrder } from './settingsSchema.js'; export enum SettingScope { User = 'User', @@ -64,86 +61,6 @@ export interface AccessibilitySettings { disableLoadingPhrases?: boolean; } -export interface Settings { - theme?: string; - customThemes?: Record<string, CustomTheme>; - selectedAuthType?: AuthType; - useExternalAuth?: boolean; - sandbox?: boolean | string; - coreTools?: string[]; - excludeTools?: string[]; - toolDiscoveryCommand?: string; - toolCallCommand?: string; - mcpServerCommand?: string; - mcpServers?: Record<string, MCPServerConfig>; - allowMCPServers?: string[]; - excludeMCPServers?: string[]; - showMemoryUsage?: boolean; - contextFileName?: string | string[]; - accessibility?: AccessibilitySettings; - telemetry?: TelemetrySettings; - usageStatisticsEnabled?: boolean; - preferredEditor?: string; - bugCommand?: BugCommandSettings; - checkpointing?: CheckpointingSettings; - autoConfigureMaxOldSpaceSize?: boolean; - /** The model name to use (e.g 'gemini-9.0-pro') */ - model?: string; - - // Git-aware file filtering settings - fileFiltering?: { - respectGitIgnore?: boolean; - respectGeminiIgnore?: boolean; - enableRecursiveFileSearch?: boolean; - }; - - hideWindowTitle?: boolean; - - hideTips?: boolean; - hideBanner?: boolean; - - // Setting for setting maximum number of user/model/tool turns in a session. - maxSessionTurns?: number; - - // A map of tool names to their summarization settings. - summarizeToolOutput?: Record<string, SummarizeToolOutputSettings>; - - vimMode?: boolean; - memoryImportFormat?: 'tree' | 'flat'; - - // Flag to be removed post-launch. - ideModeFeature?: boolean; - /// IDE mode setting configured via slash command toggle. - ideMode?: boolean; - - // Flag to be removed post-launch. - folderTrustFeature?: boolean; - // Setting to track whether Folder trust is enabled. - folderTrust?: boolean; - - // Setting to track if the user has seen the IDE integration nudge. - hasSeenIdeIntegrationNudge?: boolean; - - // Setting for disabling auto-update. - disableAutoUpdate?: boolean; - - // Setting for disabling the update nag message. - disableUpdateNag?: boolean; - - memoryDiscoveryMaxDirs?: number; - - // Environment variables to exclude from project .env files - excludedProjectEnvVars?: string[]; - dnsResolutionOrder?: DnsResolutionOrder; - - includeDirectories?: string[]; - - loadMemoryFromIncludeDirectories?: boolean; - - chatCompression?: ChatCompressionSettings; - showLineNumbers?: boolean; -} - export interface SettingsError { message: string; path: string; diff --git a/packages/cli/src/config/settingsSchema.test.ts b/packages/cli/src/config/settingsSchema.test.ts new file mode 100644 index 00000000..ab820ee1 --- /dev/null +++ b/packages/cli/src/config/settingsSchema.test.ts @@ -0,0 +1,253 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect } from 'vitest'; +import { SETTINGS_SCHEMA, Settings } from './settingsSchema.js'; + +describe('SettingsSchema', () => { + describe('SETTINGS_SCHEMA', () => { + it('should contain all expected top-level settings', () => { + const expectedSettings = [ + 'theme', + 'customThemes', + 'showMemoryUsage', + 'usageStatisticsEnabled', + 'autoConfigureMaxOldSpaceSize', + 'preferredEditor', + 'maxSessionTurns', + 'memoryImportFormat', + 'memoryDiscoveryMaxDirs', + 'contextFileName', + 'vimMode', + 'ideMode', + 'accessibility', + 'checkpointing', + 'fileFiltering', + 'disableAutoUpdate', + 'hideWindowTitle', + 'hideTips', + 'hideBanner', + 'selectedAuthType', + 'useExternalAuth', + 'sandbox', + 'coreTools', + 'excludeTools', + 'toolDiscoveryCommand', + 'toolCallCommand', + 'mcpServerCommand', + 'mcpServers', + 'allowMCPServers', + 'excludeMCPServers', + 'telemetry', + 'bugCommand', + 'summarizeToolOutput', + 'ideModeFeature', + 'dnsResolutionOrder', + 'excludedProjectEnvVars', + 'disableUpdateNag', + 'includeDirectories', + 'loadMemoryFromIncludeDirectories', + 'model', + 'hasSeenIdeIntegrationNudge', + 'folderTrustFeature', + ]; + + expectedSettings.forEach((setting) => { + expect( + SETTINGS_SCHEMA[setting as keyof typeof SETTINGS_SCHEMA], + ).toBeDefined(); + }); + }); + + it('should have correct structure for each setting', () => { + Object.entries(SETTINGS_SCHEMA).forEach(([_key, definition]) => { + expect(definition).toHaveProperty('type'); + expect(definition).toHaveProperty('label'); + expect(definition).toHaveProperty('category'); + expect(definition).toHaveProperty('requiresRestart'); + expect(definition).toHaveProperty('default'); + expect(typeof definition.type).toBe('string'); + expect(typeof definition.label).toBe('string'); + expect(typeof definition.category).toBe('string'); + expect(typeof definition.requiresRestart).toBe('boolean'); + }); + }); + + it('should have correct nested setting structure', () => { + const nestedSettings = [ + 'accessibility', + 'checkpointing', + 'fileFiltering', + ]; + + nestedSettings.forEach((setting) => { + const definition = SETTINGS_SCHEMA[ + setting as keyof typeof SETTINGS_SCHEMA + ] as (typeof SETTINGS_SCHEMA)[keyof typeof SETTINGS_SCHEMA] & { + properties: unknown; + }; + expect(definition.type).toBe('object'); + expect(definition.properties).toBeDefined(); + expect(typeof definition.properties).toBe('object'); + }); + }); + + it('should have accessibility nested properties', () => { + expect( + SETTINGS_SCHEMA.accessibility.properties?.disableLoadingPhrases, + ).toBeDefined(); + expect( + SETTINGS_SCHEMA.accessibility.properties?.disableLoadingPhrases.type, + ).toBe('boolean'); + }); + + it('should have checkpointing nested properties', () => { + expect(SETTINGS_SCHEMA.checkpointing.properties?.enabled).toBeDefined(); + expect(SETTINGS_SCHEMA.checkpointing.properties?.enabled.type).toBe( + 'boolean', + ); + }); + + it('should have fileFiltering nested properties', () => { + expect( + SETTINGS_SCHEMA.fileFiltering.properties?.respectGitIgnore, + ).toBeDefined(); + expect( + SETTINGS_SCHEMA.fileFiltering.properties?.respectGeminiIgnore, + ).toBeDefined(); + expect( + SETTINGS_SCHEMA.fileFiltering.properties?.enableRecursiveFileSearch, + ).toBeDefined(); + }); + + it('should have unique categories', () => { + const categories = new Set(); + + // Collect categories from top-level settings + Object.values(SETTINGS_SCHEMA).forEach((definition) => { + categories.add(definition.category); + // Also collect from nested properties + const defWithProps = definition as typeof definition & { + properties?: Record<string, unknown>; + }; + if (defWithProps.properties) { + Object.values(defWithProps.properties).forEach( + (nestedDef: unknown) => { + const nestedDefTyped = nestedDef as { category?: string }; + if (nestedDefTyped.category) { + categories.add(nestedDefTyped.category); + } + }, + ); + } + }); + + expect(categories.size).toBeGreaterThan(0); + expect(categories).toContain('General'); + expect(categories).toContain('UI'); + expect(categories).toContain('Mode'); + expect(categories).toContain('Updates'); + expect(categories).toContain('Accessibility'); + expect(categories).toContain('Checkpointing'); + expect(categories).toContain('File Filtering'); + expect(categories).toContain('Advanced'); + }); + + it('should have consistent default values for boolean settings', () => { + const checkBooleanDefaults = (schema: Record<string, unknown>) => { + Object.entries(schema).forEach( + ([_key, definition]: [string, unknown]) => { + const def = definition as { + type?: string; + default?: unknown; + properties?: Record<string, unknown>; + }; + if (def.type === 'boolean') { + // Boolean settings can have boolean or undefined defaults (for optional settings) + expect(['boolean', 'undefined']).toContain(typeof def.default); + } + if (def.properties) { + checkBooleanDefaults(def.properties); + } + }, + ); + }; + + checkBooleanDefaults(SETTINGS_SCHEMA as Record<string, unknown>); + }); + + it('should have showInDialog property configured', () => { + // Check that user-facing settings are marked for dialog display + expect(SETTINGS_SCHEMA.showMemoryUsage.showInDialog).toBe(true); + expect(SETTINGS_SCHEMA.vimMode.showInDialog).toBe(true); + expect(SETTINGS_SCHEMA.ideMode.showInDialog).toBe(true); + expect(SETTINGS_SCHEMA.disableAutoUpdate.showInDialog).toBe(true); + expect(SETTINGS_SCHEMA.hideWindowTitle.showInDialog).toBe(true); + expect(SETTINGS_SCHEMA.hideTips.showInDialog).toBe(true); + expect(SETTINGS_SCHEMA.hideBanner.showInDialog).toBe(true); + expect(SETTINGS_SCHEMA.usageStatisticsEnabled.showInDialog).toBe(true); + + // Check that advanced settings are hidden from dialog + expect(SETTINGS_SCHEMA.selectedAuthType.showInDialog).toBe(false); + expect(SETTINGS_SCHEMA.coreTools.showInDialog).toBe(false); + expect(SETTINGS_SCHEMA.mcpServers.showInDialog).toBe(false); + expect(SETTINGS_SCHEMA.telemetry.showInDialog).toBe(false); + + // Check that some settings are appropriately hidden + expect(SETTINGS_SCHEMA.theme.showInDialog).toBe(false); // Changed to false + expect(SETTINGS_SCHEMA.customThemes.showInDialog).toBe(false); // Managed via theme editor + expect(SETTINGS_SCHEMA.checkpointing.showInDialog).toBe(false); // Experimental feature + expect(SETTINGS_SCHEMA.accessibility.showInDialog).toBe(false); // Changed to false + expect(SETTINGS_SCHEMA.fileFiltering.showInDialog).toBe(false); // Changed to false + expect(SETTINGS_SCHEMA.preferredEditor.showInDialog).toBe(false); // Changed to false + expect(SETTINGS_SCHEMA.autoConfigureMaxOldSpaceSize.showInDialog).toBe( + true, + ); + }); + + it('should infer Settings type correctly', () => { + // This test ensures that the Settings type is properly inferred from the schema + const settings: Settings = { + theme: 'dark', + includeDirectories: ['/path/to/dir'], + loadMemoryFromIncludeDirectories: true, + }; + + // TypeScript should not complain about these properties + expect(settings.theme).toBe('dark'); + expect(settings.includeDirectories).toEqual(['/path/to/dir']); + expect(settings.loadMemoryFromIncludeDirectories).toBe(true); + }); + + it('should have includeDirectories setting in schema', () => { + expect(SETTINGS_SCHEMA.includeDirectories).toBeDefined(); + expect(SETTINGS_SCHEMA.includeDirectories.type).toBe('array'); + expect(SETTINGS_SCHEMA.includeDirectories.category).toBe('General'); + expect(SETTINGS_SCHEMA.includeDirectories.default).toEqual([]); + }); + + it('should have loadMemoryFromIncludeDirectories setting in schema', () => { + expect(SETTINGS_SCHEMA.loadMemoryFromIncludeDirectories).toBeDefined(); + expect(SETTINGS_SCHEMA.loadMemoryFromIncludeDirectories.type).toBe( + 'boolean', + ); + expect(SETTINGS_SCHEMA.loadMemoryFromIncludeDirectories.category).toBe( + 'General', + ); + expect(SETTINGS_SCHEMA.loadMemoryFromIncludeDirectories.default).toBe( + false, + ); + }); + + it('should have folderTrustFeature setting in schema', () => { + expect(SETTINGS_SCHEMA.folderTrustFeature).toBeDefined(); + expect(SETTINGS_SCHEMA.folderTrustFeature.type).toBe('boolean'); + expect(SETTINGS_SCHEMA.folderTrustFeature.category).toBe('General'); + expect(SETTINGS_SCHEMA.folderTrustFeature.default).toBe(false); + expect(SETTINGS_SCHEMA.folderTrustFeature.showInDialog).toBe(true); + }); + }); +}); diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts new file mode 100644 index 00000000..dc2582ec --- /dev/null +++ b/packages/cli/src/config/settingsSchema.ts @@ -0,0 +1,516 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + MCPServerConfig, + BugCommandSettings, + TelemetrySettings, + AuthType, + ChatCompressionSettings, +} from '@google/gemini-cli-core'; +import { CustomTheme } from '../ui/themes/theme.js'; + +export interface SettingDefinition { + type: 'boolean' | 'string' | 'number' | 'array' | 'object'; + label: string; + category: string; + requiresRestart: boolean; + default: boolean | string | number | string[] | object | undefined; + description?: string; + parentKey?: string; + childKey?: string; + key?: string; + properties?: SettingsSchema; + showInDialog?: boolean; +} + +export interface SettingsSchema { + [key: string]: SettingDefinition; +} + +export type MemoryImportFormat = 'tree' | 'flat'; +export type DnsResolutionOrder = 'ipv4first' | 'verbatim'; + +/** + * The canonical schema for all settings. + * The structure of this object defines the structure of the `Settings` type. + * `as const` is crucial for TypeScript to infer the most specific types possible. + */ +export const SETTINGS_SCHEMA = { + // UI Settings + theme: { + type: 'string', + label: 'Theme', + category: 'UI', + requiresRestart: false, + default: undefined as string | undefined, + description: 'The color theme for the UI.', + showInDialog: false, + }, + customThemes: { + type: 'object', + label: 'Custom Themes', + category: 'UI', + requiresRestart: false, + default: {} as Record<string, CustomTheme>, + description: 'Custom theme definitions.', + showInDialog: false, + }, + hideWindowTitle: { + type: 'boolean', + label: 'Hide Window Title', + category: 'UI', + requiresRestart: true, + default: false, + description: 'Hide the window title bar', + showInDialog: true, + }, + hideTips: { + type: 'boolean', + label: 'Hide Tips', + category: 'UI', + requiresRestart: false, + default: false, + description: 'Hide helpful tips in the UI', + showInDialog: true, + }, + hideBanner: { + type: 'boolean', + label: 'Hide Banner', + category: 'UI', + requiresRestart: false, + default: false, + description: 'Hide the application banner', + showInDialog: true, + }, + showMemoryUsage: { + type: 'boolean', + label: 'Show Memory Usage', + category: 'UI', + requiresRestart: false, + default: false, + description: 'Display memory usage information in the UI', + showInDialog: true, + }, + + usageStatisticsEnabled: { + type: 'boolean', + label: 'Enable Usage Statistics', + category: 'General', + requiresRestart: true, + default: false, + description: 'Enable collection of usage statistics', + showInDialog: true, + }, + autoConfigureMaxOldSpaceSize: { + type: 'boolean', + label: 'Auto Configure Max Old Space Size', + category: 'General', + requiresRestart: true, + default: false, + description: 'Automatically configure Node.js memory limits', + showInDialog: true, + }, + preferredEditor: { + type: 'string', + label: 'Preferred Editor', + category: 'General', + requiresRestart: false, + default: undefined as string | undefined, + description: 'The preferred editor to open files in.', + showInDialog: false, + }, + maxSessionTurns: { + type: 'number', + label: 'Max Session Turns', + category: 'General', + requiresRestart: false, + default: undefined as number | undefined, + description: + 'Maximum number of user/model/tool turns to keep in a session.', + showInDialog: false, + }, + memoryImportFormat: { + type: 'string', + label: 'Memory Import Format', + category: 'General', + requiresRestart: false, + default: undefined as MemoryImportFormat | undefined, + description: 'The format to use when importing memory.', + showInDialog: false, + }, + memoryDiscoveryMaxDirs: { + type: 'number', + label: 'Memory Discovery Max Dirs', + category: 'General', + requiresRestart: false, + default: undefined as number | undefined, + description: 'Maximum number of directories to search for memory.', + showInDialog: false, + }, + contextFileName: { + type: 'object', + label: 'Context File Name', + category: 'General', + requiresRestart: false, + default: undefined as string | string[] | undefined, + description: 'The name of the context file.', + showInDialog: false, + }, + vimMode: { + type: 'boolean', + label: 'Vim Mode', + category: 'Mode', + requiresRestart: false, + default: false, + description: 'Enable Vim keybindings', + showInDialog: true, + }, + ideMode: { + type: 'boolean', + label: 'IDE Mode', + category: 'Mode', + requiresRestart: true, + default: false, + description: 'Enable IDE integration mode', + showInDialog: true, + }, + + accessibility: { + type: 'object', + label: 'Accessibility', + category: 'Accessibility', + requiresRestart: true, + default: {}, + description: 'Accessibility settings.', + showInDialog: false, + properties: { + disableLoadingPhrases: { + type: 'boolean', + label: 'Disable Loading Phrases', + category: 'Accessibility', + requiresRestart: true, + default: false, + description: 'Disable loading phrases for accessibility', + showInDialog: true, + }, + }, + }, + checkpointing: { + type: 'object', + label: 'Checkpointing', + category: 'Checkpointing', + requiresRestart: true, + default: {}, + description: 'Session checkpointing settings.', + showInDialog: false, + properties: { + enabled: { + type: 'boolean', + label: 'Enable Checkpointing', + category: 'Checkpointing', + requiresRestart: true, + default: false, + description: 'Enable session checkpointing for recovery', + showInDialog: false, + }, + }, + }, + fileFiltering: { + type: 'object', + label: 'File Filtering', + category: 'File Filtering', + requiresRestart: true, + default: {}, + description: 'Settings for git-aware file filtering.', + showInDialog: false, + properties: { + respectGitIgnore: { + type: 'boolean', + label: 'Respect .gitignore', + category: 'File Filtering', + requiresRestart: true, + default: true, + description: 'Respect .gitignore files when searching', + showInDialog: true, + }, + respectGeminiIgnore: { + type: 'boolean', + label: 'Respect .geminiignore', + category: 'File Filtering', + requiresRestart: true, + default: true, + description: 'Respect .geminiignore files when searching', + showInDialog: true, + }, + enableRecursiveFileSearch: { + type: 'boolean', + label: 'Enable Recursive File Search', + category: 'File Filtering', + requiresRestart: true, + default: true, + description: 'Enable recursive file search functionality', + showInDialog: true, + }, + }, + }, + + disableAutoUpdate: { + type: 'boolean', + label: 'Disable Auto Update', + category: 'Updates', + requiresRestart: false, + default: false, + description: 'Disable automatic updates', + showInDialog: true, + }, + + selectedAuthType: { + type: 'string', + label: 'Selected Auth Type', + category: 'Advanced', + requiresRestart: true, + default: undefined as AuthType | undefined, + description: 'The currently selected authentication type.', + showInDialog: false, + }, + useExternalAuth: { + type: 'boolean', + label: 'Use External Auth', + category: 'Advanced', + requiresRestart: true, + default: undefined as boolean | undefined, + description: 'Whether to use an external authentication flow.', + showInDialog: false, + }, + sandbox: { + type: 'object', + label: 'Sandbox', + category: 'Advanced', + requiresRestart: true, + default: undefined as boolean | string | undefined, + description: + 'Sandbox execution environment (can be a boolean or a path string).', + showInDialog: false, + }, + coreTools: { + type: 'array', + label: 'Core Tools', + category: 'Advanced', + requiresRestart: true, + default: undefined as string[] | undefined, + description: 'Paths to core tool definitions.', + showInDialog: false, + }, + excludeTools: { + type: 'array', + label: 'Exclude Tools', + category: 'Advanced', + requiresRestart: true, + default: undefined as string[] | undefined, + description: 'Tool names to exclude from discovery.', + showInDialog: false, + }, + toolDiscoveryCommand: { + type: 'string', + label: 'Tool Discovery Command', + category: 'Advanced', + requiresRestart: true, + default: undefined as string | undefined, + description: 'Command to run for tool discovery.', + showInDialog: false, + }, + toolCallCommand: { + type: 'string', + label: 'Tool Call Command', + category: 'Advanced', + requiresRestart: true, + default: undefined as string | undefined, + description: 'Command to run for tool calls.', + showInDialog: false, + }, + mcpServerCommand: { + type: 'string', + label: 'MCP Server Command', + category: 'Advanced', + requiresRestart: true, + default: undefined as string | undefined, + description: 'Command to start an MCP server.', + showInDialog: false, + }, + mcpServers: { + type: 'object', + label: 'MCP Servers', + category: 'Advanced', + requiresRestart: true, + default: {} as Record<string, MCPServerConfig>, + description: 'Configuration for MCP servers.', + showInDialog: false, + }, + allowMCPServers: { + type: 'array', + label: 'Allow MCP Servers', + category: 'Advanced', + requiresRestart: true, + default: undefined as string[] | undefined, + description: 'A whitelist of MCP servers to allow.', + showInDialog: false, + }, + excludeMCPServers: { + type: 'array', + label: 'Exclude MCP Servers', + category: 'Advanced', + requiresRestart: true, + default: undefined as string[] | undefined, + description: 'A blacklist of MCP servers to exclude.', + showInDialog: false, + }, + telemetry: { + type: 'object', + label: 'Telemetry', + category: 'Advanced', + requiresRestart: true, + default: undefined as TelemetrySettings | undefined, + description: 'Telemetry configuration.', + showInDialog: false, + }, + bugCommand: { + type: 'object', + label: 'Bug Command', + category: 'Advanced', + requiresRestart: false, + default: undefined as BugCommandSettings | undefined, + description: 'Configuration for the bug report command.', + showInDialog: false, + }, + summarizeToolOutput: { + type: 'object', + label: 'Summarize Tool Output', + category: 'Advanced', + requiresRestart: false, + default: undefined as Record<string, { tokenBudget?: number }> | undefined, + description: 'Settings for summarizing tool output.', + showInDialog: false, + }, + ideModeFeature: { + type: 'boolean', + label: 'IDE Mode Feature Flag', + category: 'Advanced', + requiresRestart: true, + default: undefined as boolean | undefined, + description: 'Internal feature flag for IDE mode.', + showInDialog: false, + }, + dnsResolutionOrder: { + type: 'string', + label: 'DNS Resolution Order', + category: 'Advanced', + requiresRestart: true, + default: undefined as DnsResolutionOrder | undefined, + description: 'The DNS resolution order.', + showInDialog: false, + }, + excludedProjectEnvVars: { + type: 'array', + label: 'Excluded Project Environment Variables', + category: 'Advanced', + requiresRestart: false, + default: ['DEBUG', 'DEBUG_MODE'] as string[], + description: 'Environment variables to exclude from project context.', + showInDialog: false, + }, + disableUpdateNag: { + type: 'boolean', + label: 'Disable Update Nag', + category: 'Updates', + requiresRestart: false, + default: false, + description: 'Disable update notification prompts.', + showInDialog: false, + }, + includeDirectories: { + type: 'array', + label: 'Include Directories', + category: 'General', + requiresRestart: false, + default: [] as string[], + description: 'Additional directories to include in the workspace context.', + showInDialog: false, + }, + loadMemoryFromIncludeDirectories: { + type: 'boolean', + label: 'Load Memory From Include Directories', + category: 'General', + requiresRestart: false, + default: false, + description: 'Whether to load memory files from include directories.', + showInDialog: true, + }, + model: { + type: 'string', + label: 'Model', + category: 'General', + requiresRestart: false, + default: undefined as string | undefined, + description: 'The Gemini model to use for conversations.', + showInDialog: false, + }, + hasSeenIdeIntegrationNudge: { + type: 'boolean', + label: 'Has Seen IDE Integration Nudge', + category: 'General', + requiresRestart: false, + default: false, + description: 'Whether the user has seen the IDE integration nudge.', + showInDialog: false, + }, + folderTrustFeature: { + type: 'boolean', + label: 'Folder Trust Feature', + category: 'General', + requiresRestart: false, + default: false, + description: 'Enable folder trust feature for enhanced security.', + showInDialog: true, + }, + folderTrust: { + type: 'boolean', + label: 'Folder Trust', + category: 'General', + requiresRestart: false, + default: false, + description: 'Setting to track whether Folder trust is enabled.', + showInDialog: true, + }, + chatCompression: { + type: 'object', + label: 'Chat Compression', + category: 'General', + requiresRestart: false, + default: undefined as ChatCompressionSettings | undefined, + description: 'Chat compression settings.', + showInDialog: false, + }, + showLineNumbers: { + type: 'boolean', + label: 'Show Line Numbers', + category: 'General', + requiresRestart: false, + default: false, + description: 'Show line numbers in the chat.', + showInDialog: true, + }, +} as const; + +type InferSettings<T extends SettingsSchema> = { + -readonly [K in keyof T]?: T[K] extends { properties: SettingsSchema } + ? InferSettings<T[K]['properties']> + : T[K]['default'] extends boolean + ? boolean + : T[K]['default']; +}; + +export type Settings = InferSettings<typeof SETTINGS_SCHEMA>; |
