/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

// --------------------------------------------------------------------------
// IMPORTANT: After adding or updating settings, run `npm run docs:settings`
// to regenerate the settings reference in `docs/get-started/configuration.md`.
// --------------------------------------------------------------------------

import {
  DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD,
  DEFAULT_MODEL_CONFIGS,
  EDITOR_OPTIONS,
  AuthProviderType,
  type MCPServerConfig,
  type RequiredMcpServerConfig,
  type BugCommandSettings,
  type TelemetrySettings,
  type AuthType,
  type AgentOverride,
  type CustomTheme,
  type SandboxConfig,
  type VertexAiRoutingConfig,
} from '@google/gemini-cli-core';
import type { SessionRetentionSettings } from './settings.js';
import { DEFAULT_MIN_RETENTION } from '../utils/sessionCleanup.js';

export type SettingsType =
  | 'boolean'
  | 'string'
  | 'number'
  | 'array'
  | 'object'
  | 'enum';

export type SettingsValue =
  | boolean
  | string
  | number
  | string[]
  | object
  | undefined;

/**
 * Setting datatypes that "toggle" through a fixed list of options
 * (e.g. an enum or true/false) rather than allowing for free form input
 * (like a number or string).
 */
export const TOGGLE_TYPES: ReadonlySet<SettingsType | undefined> = new Set([
  'boolean',
  'enum',
]);

export interface SettingEnumOption {
  value: string | number;
  label: string;
}

function oneLine(strings: TemplateStringsArray, ...values: unknown[]): string {
  let result = '';
  for (let i = 0; i < strings.length; i++) {
    result += strings[i];
    if (i < values.length) {
      result += String(values[i]);
    }
  }
  return result.replace(/\s+/g, ' ').trim();
}

export interface SettingCollectionDefinition {
  type: SettingsType;
  description?: string;
  properties?: SettingsSchema;
  /** Enum type options  */
  options?: readonly SettingEnumOption[];
  /**
   * Optional reference identifier for generators that emit a `$ref`.
   * For example, a JSON schema generator can use this to point to a shared definition.
   */
  ref?: string;
  /**
   * Optional merge strategy for dynamically added properties.
   * Used when this collection definition is referenced via additionalProperties.
   */
  mergeStrategy?: MergeStrategy;
}

export enum MergeStrategy {
  // Replace the old value with the new value. This is the default.
  REPLACE = 'replace',
  // Concatenate arrays.
  CONCAT = 'concat',
  // Merge arrays, ensuring unique values.
  UNION = 'union',
  // Shallow merge objects.
  SHALLOW_MERGE = 'shallow_merge',
}

export interface SettingDefinition {
  type: SettingsType;
  label: string;
  category: string;
  requiresRestart: boolean;
  default: SettingsValue;
  description?: string;
  parentKey?: string;
  childKey?: string;
  key?: string;
  properties?: SettingsSchema;
  showInDialog?: boolean;
  ignoreInDocs?: boolean;
  mergeStrategy?: MergeStrategy;
  /** Enum type options  */
  options?: readonly SettingEnumOption[];
  /**
   * For collection types (e.g. arrays), describes the shape of each item.
   */
  items?: SettingCollectionDefinition;
  /**
   * For map-like objects without explicit `properties`, describes the shape of the values.
   */
  additionalProperties?: SettingCollectionDefinition;
  /**
   * Optional unit to display after the value (e.g. '%').
   */
  unit?: string;
  /**
   * Optional reference identifier for generators that emit a `$ref`.
   */
  ref?: string;
}

export interface SettingsSchema {
  [key: string]: SettingDefinition;
}

export type MemoryImportFormat = 'tree' | 'flat';
export type DnsResolutionOrder = 'ipv4first' | 'verbatim';

const pathArraySetting = (label: string, description: string) => ({
  type: 'array' as const,
  label,
  category: 'Advanced' as const,
  requiresRestart: true as const,
  default: [] as string[],
  description,
  showInDialog: false as const,
  items: { type: 'string' as const },
  mergeStrategy: MergeStrategy.UNION,
});

/**
 * 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.
 */
const SETTINGS_SCHEMA = {
  // Maintained for compatibility/criticality
  mcpServers: {
    type: 'object',
    label: 'MCP Servers',
    category: 'Advanced',
    requiresRestart: true,
    default: {} as Record<string, MCPServerConfig>,
    description: 'Configuration for MCP servers.',
    showInDialog: false,
    mergeStrategy: MergeStrategy.SHALLOW_MERGE,
    additionalProperties: {
      type: 'object',
      ref: 'MCPServerConfig',
    },
  },

  policyPaths: pathArraySetting(
    'Policy Paths',
    'Additional policy files or directories to load.',
  ),

  adminPolicyPaths: pathArraySetting(
    'Admin Policy Paths',
    'Additional admin policy files or directories to load.',
  ),

  general: {
    type: 'object',
    label: 'General',
    category: 'General',
    requiresRestart: false,
    default: {},
    description: 'General application settings.',
    showInDialog: false,
    properties: {
      preferredEditor: {
        type: 'enum',
        label: 'Preferred Editor',
        category: 'General',
        requiresRestart: false,
        default: undefined as string | undefined,
        description: oneLine`
          The preferred editor to open files in. Must be one of the built-in
          supported identifiers. Use /editor in the CLI to pick interactively,
          or leave unset to use $VISUAL/$EDITOR.
        `,
        showInDialog: false,
        options: EDITOR_OPTIONS,
      },
      openEditorInNewWindow: {
        type: 'boolean',
        label: 'Open Editor in New Window',
        category: 'General',
        requiresRestart: false,
        default: false,
        description:
          'Open VS Code-family editors in a new window when editing files.',
        showInDialog: false,
      },
      vimMode: {
        type: 'boolean',
        label: 'Vim Mode',
        category: 'General',
        requiresRestart: false,
        default: false,
        description: 'Enable Vim keybindings',
        showInDialog: true,
      },
      defaultApprovalMode: {
        type: 'enum',
        label: 'Default Approval Mode',
        category: 'General',
        requiresRestart: false,
        default: 'default',
        description: oneLine`
          The default approval mode for tool execution.
          'default' prompts for approval, 'auto_edit' auto-approves edit tools,
          and 'plan' is read-only mode. YOLO mode (auto-approve all actions) can
          only be enabled via command line (--yolo or --approval-mode=yolo).
        `,
        showInDialog: true,
        options: [
          { value: 'default', label: 'Default' },
          { value: 'auto_edit', label: 'Auto Edit' },
          { value: 'plan', label: 'Plan' },
        ],
      },
      devtools: {
        type: 'boolean',
        label: 'DevTools',
        category: 'General',
        requiresRestart: false,
        default: false,
        description: 'Enable DevTools inspector on launch.',
        showInDialog: false,
      },
      enableAutoUpdate: {
        type: 'boolean',
        label: 'Enable Auto Update',
        category: 'General',
        requiresRestart: false,
        default: true,
        description: 'Enable automatic updates.',
        showInDialog: true,
      },
      enableAutoUpdateNotification: {
        type: 'boolean',
        label: 'Enable Auto Update Notification',
        category: 'General',
        requiresRestart: false,
        default: true,
        description: 'Enable update notification prompts.',
        showInDialog: false,
      },
      enableNotifications: {
        type: 'boolean',
        label: 'Enable Terminal Notifications',
        category: 'General',
        requiresRestart: false,
        default: false,
        description:
          'Enable terminal run-event notifications for action-required prompts and session completion.',
        showInDialog: true,
      },
      notificationMethod: {
        type: 'enum',
        label: 'Terminal Notification Method',
        category: 'General',
        requiresRestart: false,
        default: 'auto',
        description: 'How to send terminal notifications.',
        showInDialog: true,
        options: [
          { value: 'auto', label: 'Auto' },
          { value: 'osc9', label: 'OSC 9' },
          { value: 'osc777', label: 'OSC 777' },
          { value: 'bell', label: 'Bell' },
        ],
      },
      checkpointing: {
        type: 'object',
        label: 'Checkpointing',
        category: 'General',
        requiresRestart: true,
        default: {},
        description: 'Session checkpointing settings.',
        showInDialog: false,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'Enable Checkpointing',
            category: 'General',
            requiresRestart: true,
            default: false,
            description: 'Enable session checkpointing for recovery',
            showInDialog: false,
          },
        },
      },
      plan: {
        type: 'object',
        label: 'Plan',
        category: 'General',
        requiresRestart: true,
        default: {},
        description: 'Planning features configuration.',
        showInDialog: false,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'Enable Plan Mode',
            category: 'General',
            requiresRestart: true,
            default: true,
            description:
              'Enable Plan Mode for read-only safety during planning.',
            showInDialog: true,
          },
          directory: {
            type: 'string',
            label: 'Plan Directory',
            category: 'General',
            requiresRestart: true,
            default: undefined as string | undefined,
            description:
              'The directory where planning artifacts are stored. If not specified, defaults to the system temporary directory. A custom directory requires a policy to allow write access in Plan Mode.',
            showInDialog: true,
          },
          modelRouting: {
            type: 'boolean',
            label: 'Plan Model Routing',
            category: 'General',
            requiresRestart: false,
            default: true,
            description:
              'Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pro for the planning phase and Flash for the implementation phase.',
            showInDialog: true,
          },
        },
      },
      retryFetchErrors: {
        type: 'boolean',
        label: 'Retry Fetch Errors',
        category: 'General',
        requiresRestart: false,
        default: true,
        description:
          'Retry on "exception TypeError: fetch failed sending request" errors.',
        showInDialog: true,
      },
      maxAttempts: {
        type: 'number',
        label: 'Max Chat Model Attempts',
        category: 'General',
        requiresRestart: false,
        default: 10,
        description:
          'Maximum number of attempts for requests to the main chat model. Cannot exceed 10.',
        showInDialog: true,
      },
      debugKeystrokeLogging: {
        type: 'boolean',
        label: 'Debug Keystroke Logging',
        category: 'General',
        requiresRestart: false,
        default: false,
        description: 'Enable debug logging of keystrokes to the console.',
        showInDialog: true,
      },
      sessionRetention: {
        type: 'object',
        label: 'Session Retention',
        category: 'General',
        requiresRestart: false,
        default: undefined as SessionRetentionSettings | undefined,
        showInDialog: false,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'Enable Session Cleanup',
            category: 'General',
            requiresRestart: false,
            default: true as boolean,
            description: 'Enable automatic session cleanup',
            showInDialog: true,
          },
          maxAge: {
            type: 'string',
            label: 'Keep chat history',
            category: 'General',
            requiresRestart: false,
            default: '30d' as string,
            description:
              'Automatically delete chats older than this time period (e.g., "30d", "7d", "24h", "1w")',
            showInDialog: true,
          },
          maxCount: {
            type: 'number',
            label: 'Max Session Count',
            category: 'General',
            requiresRestart: false,
            default: undefined as number | undefined,
            description:
              'Alternative: Maximum number of sessions to keep (most recent)',
            showInDialog: false,
          },
          minRetention: {
            type: 'string',
            label: 'Min Retention Period',
            category: 'General',
            requiresRestart: false,
            default: DEFAULT_MIN_RETENTION,
            description: `Minimum retention period (safety limit, defaults to "${DEFAULT_MIN_RETENTION}")`,
            showInDialog: false,
          },
        },
        description: 'Settings for automatic session cleanup.',
      },
      topicUpdateNarration: {
        type: 'boolean',
        label: 'Topic & Update Narration',
        category: 'General',
        requiresRestart: false,
        default: true,
        description:
          'Enable the Topic & Update communication model for reduced chattiness and structured progress reporting.',
        showInDialog: true,
      },
      logRagSnippets: {
        type: 'boolean',
        label: 'Log RAG Snippets',
        category: 'General',
        requiresRestart: false,
        default: false,
        description:
          'Log full Code Customization (RAG) retrieved snippets to a local file for debugging.',
        showInDialog: true,
      },
    },
  },
  output: {
    type: 'object',
    label: 'Output',
    category: 'General',
    requiresRestart: false,
    default: {},
    description: 'Settings for the CLI output.',
    showInDialog: false,
    properties: {
      format: {
        type: 'enum',
        label: 'Output Format',
        category: 'General',
        requiresRestart: false,
        default: 'text',
        description: 'The format of the CLI output. Can be `text` or `json`.',
        showInDialog: true,
        options: [
          { value: 'text', label: 'Text' },
          { value: 'json', label: 'JSON' },
        ],
      },
    },
  },

  ui: {
    type: 'object',
    label: 'UI',
    category: 'UI',
    requiresRestart: false,
    default: {},
    description: 'User interface settings.',
    showInDialog: false,
    properties: {
      debugRainbow: {
        type: 'boolean',
        label: 'Debug Rainbow',
        category: 'UI',
        requiresRestart: true,
        default: false,
        description:
          'Enable debug rainbow rendering. Only useful for debugging rendering bugs and performance issues.',
        showInDialog: false,
      },
      theme: {
        type: 'string',
        label: 'Theme',
        category: 'UI',
        requiresRestart: false,
        default: undefined as string | undefined,
        description:
          'The color theme for the UI. See the CLI themes guide for available options.',
        showInDialog: false,
      },
      autoThemeSwitching: {
        type: 'boolean',
        label: 'Auto Theme Switching',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description:
          'Automatically switch between default light and dark themes based on terminal background color.',
        showInDialog: true,
      },
      terminalBackgroundPollingInterval: {
        type: 'number',
        label: 'Terminal Background Polling Interval',
        category: 'UI',
        requiresRestart: false,
        default: 60,
        description:
          'Interval in seconds to poll the terminal background color.',
        showInDialog: true,
      },
      customThemes: {
        type: 'object',
        label: 'Custom Themes',
        category: 'UI',
        requiresRestart: false,
        default: {} as Record<string, CustomTheme>,
        description: 'Custom theme definitions.',
        showInDialog: false,
        additionalProperties: {
          type: 'object',
          ref: 'CustomTheme',
        },
      },
      hideWindowTitle: {
        type: 'boolean',
        label: 'Hide Window Title',
        category: 'UI',
        requiresRestart: true,
        default: false,
        description: 'Hide the window title bar',
        showInDialog: true,
      },
      inlineThinkingMode: {
        type: 'enum',
        label: 'Inline Thinking',
        category: 'UI',
        requiresRestart: false,
        default: 'off',
        description: 'Display model thinking inline: off or full.',
        showInDialog: true,
        options: [
          { value: 'off', label: 'Off' },
          { value: 'full', label: 'Full' },
        ],
      },
      showStatusInTitle: {
        type: 'boolean',
        label: 'Show Thoughts in Title',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description:
          'Show Gemini CLI model thoughts in the terminal window title during the working phase',
        showInDialog: true,
      },
      dynamicWindowTitle: {
        type: 'boolean',
        label: 'Dynamic Window Title',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description:
          'Update the terminal window title with current status icons (Ready: ◇, Action Required: ✋, Working: ✦)',
        showInDialog: true,
      },
      showHomeDirectoryWarning: {
        type: 'boolean',
        label: 'Show Home Directory Warning',
        category: 'UI',
        requiresRestart: true,
        default: true,
        description:
          'Show a warning when running Gemini CLI in the home directory.',
        showInDialog: true,
      },
      showCompatibilityWarnings: {
        type: 'boolean',
        label: 'Show Compatibility Warnings',
        category: 'UI',
        requiresRestart: true,
        default: true,
        description: 'Show warnings about terminal or OS compatibility issues.',
        showInDialog: true,
      },
      hideTips: {
        type: 'boolean',
        label: 'Hide Tips',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description: 'Hide helpful tips in the UI',
        showInDialog: true,
      },
      escapePastedAtSymbols: {
        type: 'boolean',
        label: 'Escape Pasted @ Symbols',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description:
          'When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion.',
        showInDialog: true,
      },
      showShortcutsHint: {
        type: 'boolean',
        label: 'Show Shortcuts Hint',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description: 'Show the "? for shortcuts" hint above the input.',
        showInDialog: true,
      },
      compactToolOutput: {
        type: 'boolean',
        label: 'Compact Tool Output',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description:
          'Display tool outputs (like directory listings and file reads) in a compact, structured format.',
        showInDialog: true,
      },
      hideBanner: {
        type: 'boolean',
        label: 'Hide Banner',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description: 'Hide the application banner',
        showInDialog: true,
      },
      hideContextSummary: {
        type: 'boolean',
        label: 'Hide Context Summary',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description:
          'Hide the context summary (GEMINI.md, MCP servers) above the input.',
        showInDialog: true,
      },
      footer: {
        type: 'object',
        label: 'Footer',
        category: 'UI',
        requiresRestart: false,
        default: {},
        description: 'Settings for the footer.',
        showInDialog: false,
        properties: {
          items: {
            type: 'array',
            label: 'Footer Items',
            category: 'UI',
            requiresRestart: false,
            default: undefined as string[] | undefined,
            description:
              'List of item IDs to display in the footer. Rendered in order',
            showInDialog: false,
            items: { type: 'string' },
          },
          showLabels: {
            type: 'boolean',
            label: 'Show Footer Labels',
            category: 'UI',
            requiresRestart: false,
            default: true,
            description:
              'Display a second line above the footer items with descriptive headers (e.g., /model).',
            showInDialog: false,
          },
          hideCWD: {
            type: 'boolean',
            label: 'Hide CWD',
            category: 'UI',
            requiresRestart: false,
            default: false,
            description: 'Hide the current working directory in the footer.',
            showInDialog: true,
          },
          hideSandboxStatus: {
            type: 'boolean',
            label: 'Hide Sandbox Status',
            category: 'UI',
            requiresRestart: false,
            default: false,
            description: 'Hide the sandbox status indicator in the footer.',
            showInDialog: true,
          },
          hideModelInfo: {
            type: 'boolean',
            label: 'Hide Model Info',
            category: 'UI',
            requiresRestart: false,
            default: false,
            description: 'Hide the model name and context usage in the footer.',
            showInDialog: true,
          },
          hideContextPercentage: {
            type: 'boolean',
            label: 'Hide Context Window Percentage',
            category: 'UI',
            requiresRestart: false,
            default: true,
            description: 'Hides the context window usage percentage.',
            showInDialog: true,
          },
        },
      },
      hideFooter: {
        type: 'boolean',
        label: 'Hide Footer',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description: 'Hide the footer from the UI',
        showInDialog: true,
      },
      collapseDrawerDuringApproval: {
        type: 'boolean',
        label: 'Collapse Drawer During Approval',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description:
          'Whether to collapse the UI drawer when a tool is awaiting confirmation.',
        showInDialog: false,
      },
      showMemoryUsage: {
        type: 'boolean',
        label: 'Show Memory Usage',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description: 'Display memory usage information in the UI',
        showInDialog: true,
      },
      showLineNumbers: {
        type: 'boolean',
        label: 'Show Line Numbers',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description: 'Show line numbers in the chat.',
        showInDialog: true,
      },
      showCitations: {
        type: 'boolean',
        label: 'Show Citations',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description: 'Show citations for generated text in the chat.',
        showInDialog: true,
      },
      showModelInfoInChat: {
        type: 'boolean',
        label: 'Show Model Info In Chat',
        category: 'UI',
        requiresRestart: false,
        default: false,
        description: 'Show the model name in the chat for each model turn.',
        showInDialog: true,
      },
      showUserIdentity: {
        type: 'boolean',
        label: 'Show User Identity',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description:
          "Show the signed-in user's identity (e.g. email) in the UI.",
        showInDialog: true,
      },
      useAlternateBuffer: {
        type: 'boolean',
        label: 'Use Alternate Screen Buffer',
        category: 'UI',
        requiresRestart: true,
        default: false,
        description:
          'Use an alternate screen buffer for the UI, preserving shell history.',
        showInDialog: true,
      },
      renderProcess: {
        type: 'boolean',
        label: 'Render Process',
        category: 'UI',
        requiresRestart: true,
        default: true,
        description: 'Enable Ink render process for the UI.',
        showInDialog: true,
      },
      terminalBuffer: {
        type: 'boolean',
        label: 'Terminal Buffer',
        category: 'UI',
        requiresRestart: true,
        default: false,
        description: 'Use the new terminal buffer architecture for rendering.',
        showInDialog: true,
      },
      useBackgroundColor: {
        type: 'boolean',
        label: 'Use Background Color',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description: 'Whether to use background colors in the UI.',
        showInDialog: true,
      },
      incrementalRendering: {
        type: 'boolean',
        label: 'Incremental Rendering',
        category: 'UI',
        requiresRestart: true,
        default: true,
        description:
          'Enable incremental rendering for the UI. This option will reduce flickering but may cause rendering artifacts. Only supported when useAlternateBuffer is enabled.',
        showInDialog: true,
      },
      showSpinner: {
        type: 'boolean',
        label: 'Show Spinner',
        category: 'UI',
        requiresRestart: false,
        default: true,
        description: 'Show the spinner during operations.',
        showInDialog: true,
      },
      loadingPhrases: {
        type: 'enum',
        label: 'Loading Phrases',
        category: 'UI',
        requiresRestart: false,
        default: 'off',
        description:
          'What to show while the model is working: tips, witty comments, all, or off.',
        showInDialog: true,
        options: [
          { value: 'tips', label: 'Tips' },
          { value: 'witty', label: 'Witty' },
          { value: 'all', label: 'All' },
          { value: 'off', label: 'Off' },
        ],
      },
      errorVerbosity: {
        type: 'enum',
        label: 'Error Verbosity',
        category: 'UI',
        requiresRestart: false,
        default: 'low',
        description:
          'Controls whether recoverable errors are hidden (low) or fully shown (full).',
        showInDialog: true,
        options: [
          { value: 'low', label: 'Low' },
          { value: 'full', label: 'Full' },
        ],
      },
      customWittyPhrases: {
        type: 'array',
        label: 'Custom Witty Phrases',
        category: 'UI',
        requiresRestart: false,
        default: [] as string[],
        description: oneLine`
          Custom witty phrases to display during loading.
          When provided, the CLI cycles through these instead of the defaults.
        `,
        showInDialog: false,
        items: { type: 'string' },
      },
      accessibility: {
        type: 'object',
        label: 'Accessibility',
        category: 'UI',
        requiresRestart: true,
        default: {},
        description: 'Accessibility settings.',
        showInDialog: false,
        properties: {
          enableLoadingPhrases: {
            type: 'boolean',
            label: 'Enable Loading Phrases',
            category: 'UI',
            requiresRestart: true,
            default: true,
            description:
              '@deprecated Use ui.loadingPhrases instead. Enable loading phrases during operations.',
            showInDialog: false,
          },
          screenReader: {
            type: 'boolean',
            label: 'Screen Reader Mode',
            category: 'UI',
            requiresRestart: true,
            default: false,
            description:
              'Render output in plain-text to be more screen reader accessible',
            showInDialog: true,
          },
        },
      },
    },
  },

  ide: {
    type: 'object',
    label: 'IDE',
    category: 'IDE',
    requiresRestart: true,
    default: {},
    description: 'IDE integration settings.',
    showInDialog: false,
    properties: {
      enabled: {
        type: 'boolean',
        label: 'IDE Mode',
        category: 'IDE',
        requiresRestart: true,
        default: false,
        description: 'Enable IDE integration mode.',
        showInDialog: true,
      },
      hasSeenNudge: {
        type: 'boolean',
        label: 'Has Seen IDE Integration Nudge',
        category: 'IDE',
        requiresRestart: false,
        default: false,
        description: 'Whether the user has seen the IDE integration nudge.',
        showInDialog: false,
      },
    },
  },

  privacy: {
    type: 'object',
    label: 'Privacy',
    category: 'Privacy',
    requiresRestart: true,
    default: {},
    description: 'Privacy-related settings.',
    showInDialog: false,
    properties: {
      usageStatisticsEnabled: {
        type: 'boolean',
        label: 'Enable Usage Statistics',
        category: 'Privacy',
        requiresRestart: true,
        default: true,
        description: 'Enable collection of usage statistics',
        showInDialog: false,
      },
    },
  },

  telemetry: {
    type: 'object',
    label: 'Telemetry',
    category: 'Advanced',
    requiresRestart: true,
    default: undefined as TelemetrySettings | undefined,
    description: 'Telemetry configuration.',
    showInDialog: false,
    ref: 'TelemetrySettings',
  },

  billing: {
    type: 'object',
    label: 'Billing',
    category: 'Advanced',
    requiresRestart: false,
    default: {},
    description: 'Billing and AI credits settings.',
    showInDialog: false,
    properties: {
      overageStrategy: {
        type: 'enum',
        label: 'Overage Strategy',
        category: 'Advanced',
        requiresRestart: false,
        default: 'ask',
        description: oneLine`
          How to handle quota exhaustion when AI credits are available.
          'ask' prompts each time, 'always' automatically uses credits,
          'never' disables credit usage.
        `,
        showInDialog: true,
        options: [
          { value: 'ask', label: 'Ask each time' },
          { value: 'always', label: 'Always use credits' },
          { value: 'never', label: 'Never use credits' },
        ],
      },
      vertexAi: {
        type: 'object',
        label: 'Vertex AI',
        category: 'Advanced',
        requiresRestart: true,
        default: undefined as VertexAiRoutingConfig | undefined,
        description: 'Vertex AI request routing settings.',
        showInDialog: false,
        properties: {
          requestType: {
            type: 'enum',
            label: 'Vertex AI Request Type',
            category: 'Advanced',
            requiresRestart: true,
            default: undefined as VertexAiRoutingConfig['requestType'],
            description:
              'Sets the X-Vertex-AI-LLM-Request-Type header for Vertex AI requests.',
            showInDialog: false,
            options: [
              { value: 'dedicated', label: 'Dedicated' },
              { value: 'shared', label: 'Shared' },
            ],
          },
          sharedRequestType: {
            type: 'enum',
            label: 'Vertex AI Shared Request Type',
            category: 'Advanced',
            requiresRestart: true,
            default: undefined as VertexAiRoutingConfig['sharedRequestType'],
            description:
              'Sets the X-Vertex-AI-LLM-Shared-Request-Type header for Vertex AI requests.',
            showInDialog: false,
            options: [
              { value: 'priority', label: 'Priority' },
              { value: 'flex', label: 'Flex' },
            ],
          },
        },
      },
    },
  },

  model: {
    type: 'object',
    label: 'Model',
    category: 'Model',
    requiresRestart: false,
    default: {},
    description: 'Settings related to the generative model.',
    showInDialog: false,
    properties: {
      name: {
        type: 'string',
        label: 'Model',
        category: 'Model',
        requiresRestart: false,
        default: undefined as string | undefined,
        description: 'The Gemini model to use for conversations.',
        showInDialog: true,
      },
      maxSessionTurns: {
        type: 'number',
        label: 'Max Session Turns',
        category: 'Model',
        requiresRestart: false,
        default: -1,
        description:
          'Maximum number of user/model/tool turns to keep in a session. -1 means unlimited.',
        showInDialog: true,
      },
      summarizeToolOutput: {
        type: 'object',
        label: 'Summarize Tool Output',
        category: 'Model',
        requiresRestart: false,
        default: undefined as
          | Record<string, { tokenBudget?: number }>
          | undefined,
        description: oneLine`
          Enables or disables summarization of tool output.
          Configure per-tool token budgets (for example {"run_shell_command": {"tokenBudget": 2000}}).
          Currently only the run_shell_command tool supports summarization.
        `,
        showInDialog: false,
        additionalProperties: {
          type: 'object',
          description:
            'Per-tool summarization settings with an optional tokenBudget.',
          ref: 'SummarizeToolOutputSettings',
        },
      },
      compressionThreshold: {
        type: 'number',
        label: 'Context Compression Threshold',
        category: 'Model',
        requiresRestart: true,
        default: 0.5 as number,
        description:
          'The fraction of context usage at which to trigger context compression (e.g. 0.2, 0.3).',
        showInDialog: true,
        unit: '%',
      },
      disableLoopDetection: {
        type: 'boolean',
        label: 'Disable Loop Detection',
        category: 'Model',
        requiresRestart: true,
        default: false,
        description:
          'Disable automatic detection and prevention of infinite loops.',
        showInDialog: true,
      },
      skipNextSpeakerCheck: {
        type: 'boolean',
        label: 'Skip Next Speaker Check',
        category: 'Model',
        requiresRestart: false,
        default: true,
        description: 'Skip the next speaker check.',
        showInDialog: true,
      },
    },
  },

  modelConfigs: {
    type: 'object',
    label: 'Model Configs',
    category: 'Model',
    requiresRestart: false,
    default: DEFAULT_MODEL_CONFIGS,
    description: 'Model configurations.',
    showInDialog: false,
    properties: {
      aliases: {
        type: 'object',
        label: 'Model Config Aliases',
        category: 'Model',
        requiresRestart: false,
        default: DEFAULT_MODEL_CONFIGS.aliases,
        description:
          'Named presets for model configs. Can be used in place of a model name and can inherit from other aliases using an `extends` property.',
        showInDialog: false,
      },
      customAliases: {
        type: 'object',
        label: 'Custom Model Config Aliases',
        category: 'Model',
        requiresRestart: false,
        default: {},
        description:
          'Custom named presets for model configs. These are merged with (and override) the built-in aliases.',
        showInDialog: false,
      },
      customOverrides: {
        type: 'array',
        label: 'Custom Model Config Overrides',
        category: 'Model',
        requiresRestart: false,
        default: [],
        description:
          'Custom model config overrides. These are merged with (and added to) the built-in overrides.',
        showInDialog: false,
      },
      overrides: {
        type: 'array',
        label: 'Model Config Overrides',
        category: 'Model',
        requiresRestart: false,
        default: [],
        description:
          'Apply specific configuration overrides based on matches, with a primary key of model (or alias). The most specific match will be used.',
        showInDialog: false,
      },
      modelDefinitions: {
        type: 'object',
        label: 'Model Definitions',
        category: 'Model',
        requiresRestart: true,
        default: DEFAULT_MODEL_CONFIGS.modelDefinitions,
        description:
          'Registry of model metadata, including tier, family, and features.',
        showInDialog: false,
        additionalProperties: {
          type: 'object',
          ref: 'ModelDefinition',
        },
      },
      modelIdResolutions: {
        type: 'object',
        label: 'Model ID Resolutions',
        category: 'Model',
        requiresRestart: true,
        default: DEFAULT_MODEL_CONFIGS.modelIdResolutions,
        description:
          'Rules for resolving requested model names to concrete model IDs based on context.',
        showInDialog: false,
        additionalProperties: {
          type: 'object',
          ref: 'ModelResolution',
        },
      },
      classifierIdResolutions: {
        type: 'object',
        label: 'Classifier ID Resolutions',
        category: 'Model',
        requiresRestart: true,
        default: DEFAULT_MODEL_CONFIGS.classifierIdResolutions,
        description:
          'Rules for resolving classifier tiers (flash, pro) to concrete model IDs.',
        showInDialog: false,
        additionalProperties: {
          type: 'object',
          ref: 'ModelResolution',
        },
      },
      modelChains: {
        type: 'object',
        label: 'Model Chains',
        category: 'Model',
        requiresRestart: true,
        default: DEFAULT_MODEL_CONFIGS.modelChains,
        description:
          'Availability policy chains defining fallback behavior for models.',
        showInDialog: false,
        additionalProperties: {
          type: 'array',
          ref: 'ModelPolicyChain',
        },
      },
    },
  },

  agents: {
    type: 'object',
    label: 'Agents',
    category: 'Advanced',
    requiresRestart: true,
    default: {},
    description: 'Settings for subagents.',
    showInDialog: false,
    properties: {
      overrides: {
        type: 'object',
        label: 'Agent Overrides',
        category: 'Advanced',
        requiresRestart: true,
        default: {} as Record<string, AgentOverride>,
        description:
          'Override settings for specific agents, e.g. to disable the agent, set a custom model config, or run config.',
        showInDialog: false,
        additionalProperties: {
          type: 'object',
          ref: 'AgentOverride',
        },
      },
      browser: {
        type: 'object',
        label: 'Browser Agent',
        category: 'Advanced',
        requiresRestart: true,
        default: {},
        description: 'Settings specific to the browser agent.',
        showInDialog: false,
        properties: {
          sessionMode: {
            type: 'enum',
            label: 'Browser Session Mode',
            category: 'Advanced',
            requiresRestart: true,
            default: 'persistent',
            description:
              "Session mode: 'persistent', 'isolated', or 'existing'.",
            showInDialog: false,
            options: [
              { value: 'persistent', label: 'Persistent' },
              { value: 'isolated', label: 'Isolated' },
              { value: 'existing', label: 'Existing' },
            ],
          },
          headless: {
            type: 'boolean',
            label: 'Browser Headless',
            category: 'Advanced',
            requiresRestart: true,
            default: false,
            description: 'Run browser in headless mode.',
            showInDialog: false,
          },
          profilePath: {
            type: 'string',
            label: 'Browser Profile Path',
            category: 'Advanced',
            requiresRestart: true,
            default: undefined as string | undefined,
            description:
              'Path to browser profile directory for session persistence.',
            showInDialog: false,
          },
          visualModel: {
            type: 'string',
            label: 'Browser Visual Model',
            category: 'Advanced',
            requiresRestart: true,
            default: undefined as string | undefined,
            description:
              "Model for the visual agent's analyze_screenshot tool. When set, enables the tool.",
            showInDialog: false,
          },
          allowedDomains: {
            type: 'array',
            label: 'Allowed Domains',
            category: 'Advanced',
            requiresRestart: true,
            default: ['github.com', '*.google.com', 'localhost'] as string[],
            description: oneLine`
              A list of allowed domains for the browser agent
              (e.g., ["github.com", "*.google.com"]).
            `,
            showInDialog: false,
            items: { type: 'string' },
          },
          disableUserInput: {
            type: 'boolean',
            label: 'Disable User Input',
            category: 'Advanced',
            requiresRestart: false,
            default: true,
            description:
              'Disable user input on browser window during automation.',
            showInDialog: false,
          },
          maxActionsPerTask: {
            type: 'number',
            label: 'Max Actions Per Task',
            category: 'Advanced',
            requiresRestart: false,
            default: 100,
            description:
              'The maximum number of tool calls allowed per browser task. Enforcement is hard: the agent will be terminated when the limit is reached.',
            showInDialog: false,
          },
          confirmSensitiveActions: {
            type: 'boolean',
            label: 'Confirm Sensitive Actions',
            category: 'Advanced',
            requiresRestart: true,
            default: false,
            description:
              'Require manual confirmation for sensitive browser actions (e.g., fill_form, evaluate_script).',
            showInDialog: true,
          },
          blockFileUploads: {
            type: 'boolean',
            label: 'Block File Uploads',
            category: 'Advanced',
            requiresRestart: true,
            default: false,
            description:
              'Hard-block file upload requests from the browser agent.',
            showInDialog: true,
          },
        },
      },
    },
  },

  context: {
    type: 'object',
    label: 'Context',
    category: 'Context',
    requiresRestart: false,
    default: {},
    description: 'Settings for managing context provided to the model.',
    showInDialog: false,
    properties: {
      fileName: {
        type: 'string',
        label: 'Context File Name',
        category: 'Context',
        requiresRestart: false,
        default: undefined as string | string[] | undefined,
        ref: 'StringOrStringArray',
        description:
          'The name of the context file or files to load into memory. Accepts either a single string or an array of strings.',
        showInDialog: false,
      },
      importFormat: {
        type: 'string',
        label: 'Memory Import Format',
        category: 'Context',
        requiresRestart: false,
        default: undefined as MemoryImportFormat | undefined,
        description: 'The format to use when importing memory.',
        showInDialog: false,
      },
      includeDirectoryTree: {
        type: 'boolean',
        label: 'Include Directory Tree',
        category: 'Context',
        requiresRestart: false,
        default: true,
        description:
          'Whether to include the directory tree of the current working directory in the initial request to the model.',
        showInDialog: false,
      },
      discoveryMaxDirs: {
        type: 'number',
        label: 'Memory Discovery Max Dirs',
        category: 'Context',
        requiresRestart: false,
        default: 200,
        description: 'Maximum number of directories to search for memory.',
        showInDialog: true,
      },
      memoryBoundaryMarkers: {
        type: 'array',
        label: 'Memory Boundary Markers',
        category: 'Context',
        requiresRestart: true,
        default: ['.git'] as string[],
        description:
          'File or directory names that mark the boundary for GEMINI.md discovery. ' +
          'The upward traversal stops at the first directory containing any of these markers. ' +
          'An empty array disables parent traversal.',
        showInDialog: false,
        items: { type: 'string' },
      },
      includeDirectories: {
        type: 'array',
        label: 'Include Directories',
        category: 'Context',
        requiresRestart: false,
        default: [] as string[],
        description: oneLine`
          Additional directories to include in the workspace context.
          Missing directories will be skipped with a warning.
        `,
        showInDialog: false,
        items: { type: 'string' },
        mergeStrategy: MergeStrategy.CONCAT,
      },
      loadMemoryFromIncludeDirectories: {
        type: 'boolean',
        label: 'Load Memory From Include Directories',
        category: 'Context',
        requiresRestart: false,
        default: false,
        description: oneLine`
          Controls how /memory reload loads GEMINI.md files.
          When true, include directories are scanned; when false, only the current directory is used.
        `,
        showInDialog: true,
      },
      fileFiltering: {
        type: 'object',
        label: 'File Filtering',
        category: 'Context',
        requiresRestart: true,
        default: {},
        description: 'Settings for git-aware file filtering.',
        showInDialog: false,
        properties: {
          respectGitIgnore: {
            type: 'boolean',
            label: 'Respect .gitignore',
            category: 'Context',
            requiresRestart: true,
            default: true,
            description: 'Respect .gitignore files when searching.',
            showInDialog: true,
          },
          respectGeminiIgnore: {
            type: 'boolean',
            label: 'Respect .geminiignore',
            category: 'Context',
            requiresRestart: true,
            default: true,
            description: 'Respect .geminiignore files when searching.',
            showInDialog: true,
          },
          enableFileWatcher: {
            type: 'boolean',
            label: 'Enable File Watcher',
            category: 'Context',
            requiresRestart: true,
            default: false,
            description: oneLine`
              Enable file watcher updates for @ file suggestions (experimental).
            `,
            showInDialog: false,
          },
          enableRecursiveFileSearch: {
            type: 'boolean',
            label: 'Enable Recursive File Search',
            category: 'Context',
            requiresRestart: true,
            default: true,
            description: oneLine`
              Enable recursive file search functionality when completing @ references in the prompt.
            `,
            showInDialog: true,
          },
          enableFuzzySearch: {
            type: 'boolean',
            label: 'Enable Fuzzy Search',
            category: 'Context',
            requiresRestart: true,
            default: true,
            description: 'Enable fuzzy search when searching for files.',
            showInDialog: true,
          },
          customIgnoreFilePaths: {
            type: 'array',
            label: 'Custom Ignore File Paths',
            category: 'Context',
            requiresRestart: true,
            default: [] as string[],
            description:
              'Additional ignore file paths to respect. These files take precedence over .geminiignore and .gitignore. Files earlier in the array take precedence over files later in the array, e.g. the first file takes precedence over the second one.',
            showInDialog: true,
            items: { type: 'string' },
            mergeStrategy: MergeStrategy.UNION,
          },
        },
      },
    },
  },

  tools: {
    type: 'object',
    label: 'Tools',
    category: 'Tools',
    requiresRestart: true,
    default: {},
    description: 'Settings for built-in and custom tools.',
    showInDialog: false,
    properties: {
      sandbox: {
        type: 'string',
        label: 'Sandbox',
        category: 'Tools',
        requiresRestart: true,
        default: undefined as boolean | string | SandboxConfig | undefined,
        ref: 'BooleanOrStringOrObject',
        description: oneLine`
          Legacy full-process sandbox execution environment.
          Set to a boolean to enable or disable the sandbox, provide a string path to a sandbox profile,
          or specify an explicit sandbox command (e.g., "docker", "podman", "lxc", "windows-native").
        `,
        showInDialog: false,
      },
      sandboxAllowedPaths: {
        type: 'array',
        label: 'Sandbox Allowed Paths',
        category: 'Tools',
        requiresRestart: true,
        default: [] as string[],
        description:
          'List of additional paths that the sandbox is allowed to access.',
        showInDialog: true,
        items: { type: 'string' },
      },
      sandboxNetworkAccess: {
        type: 'boolean',
        label: 'Sandbox Network Access',
        category: 'Tools',
        requiresRestart: true,
        default: false,
        description: 'Whether the sandbox is allowed to access the network.',
        showInDialog: true,
      },
      shell: {
        type: 'object',
        label: 'Shell',
        category: 'Tools',
        requiresRestart: false,
        default: {},
        description: 'Settings for shell execution.',
        showInDialog: false,
        properties: {
          enableInteractiveShell: {
            type: 'boolean',
            label: 'Enable Interactive Shell',
            category: 'Tools',
            requiresRestart: true,
            default: true,
            description: oneLine`
              Use node-pty for an interactive shell experience.
              Fallback to child_process still applies.
            `,
            showInDialog: true,
          },
          backgroundCompletionBehavior: {
            type: 'enum',
            label: 'Background Completion Behavior',
            category: 'Tools',
            requiresRestart: false,
            default: 'silent',
            description:
              "Controls what happens when a background shell command finishes. 'silent' (default): quietly exits in background. 'inject': automatically returns output to agent. 'notify': shows brief message in chat.",
            showInDialog: false,
            options: [
              { label: 'Silent', value: 'silent' },
              { label: 'Inject', value: 'inject' },
              { label: 'Notify', value: 'notify' },
            ],
          },
          pager: {
            type: 'string',
            label: 'Pager',
            category: 'Tools',
            requiresRestart: false,
            default: 'cat' as string | undefined,
            description:
              'The pager command to use for shell output. Defaults to `cat`.',
            showInDialog: false,
          },
          showColor: {
            type: 'boolean',
            label: 'Show Color',
            category: 'Tools',
            requiresRestart: false,
            default: true,
            description: 'Show color in shell output.',
            showInDialog: true,
          },
          inactivityTimeout: {
            type: 'number',
            label: 'Inactivity Timeout',
            category: 'Tools',
            requiresRestart: false,
            default: 300,
            description:
              'The maximum time in seconds allowed without output from the shell command. Defaults to 5 minutes.',
            showInDialog: false,
          },
          enableShellOutputEfficiency: {
            type: 'boolean',
            label: 'Enable Shell Output Efficiency',
            category: 'Tools',
            requiresRestart: false,
            default: true,
            description:
              'Enable shell output efficiency optimizations for better performance.',
            showInDialog: false,
          },
        },
      },

      core: {
        type: 'array',
        label: 'Core Tools',
        category: 'Tools',
        requiresRestart: true,
        default: undefined as string[] | undefined,
        description: oneLine`
          Restrict the set of built-in tools with an allowlist.
          Match semantics mirror tools.allowed; see the built-in tools documentation for available names.
        `,
        showInDialog: false,
        items: { type: 'string' },
      },
      allowed: {
        type: 'array',
        label: 'Allowed Tools',
        category: 'Advanced',
        requiresRestart: true,
        default: undefined as string[] | undefined,
        description: oneLine`
          Tool names that bypass the confirmation dialog.
          Useful for trusted commands (for example ["run_shell_command(git)", "run_shell_command(npm test)"]).
          See shell tool command restrictions for matching details.
        `,
        showInDialog: false,
        items: { type: 'string' },
      },
      confirmationRequired: {
        type: 'array',
        label: 'Confirmation Required',
        category: 'Advanced',
        requiresRestart: true,
        default: undefined as string[] | undefined,
        description: oneLine`
          Tool names that always require user confirmation.
          Takes precedence over allowed tools and core tool allowlists.
        `,
        showInDialog: false,
        items: { type: 'string' },
      },
      exclude: {
        type: 'array',
        label: 'Exclude Tools',
        category: 'Tools',
        requiresRestart: true,
        default: undefined as string[] | undefined,
        description: 'Tool names to exclude from discovery.',
        showInDialog: false,
        items: { type: 'string' },
        mergeStrategy: MergeStrategy.UNION,
      },
      discoveryCommand: {
        type: 'string',
        label: 'Tool Discovery Command',
        category: 'Tools',
        requiresRestart: true,
        default: undefined as string | undefined,
        description: 'Command to run for tool discovery.',
        showInDialog: false,
      },
      callCommand: {
        type: 'string',
        label: 'Tool Call Command',
        category: 'Tools',
        requiresRestart: true,
        default: undefined as string | undefined,
        description: oneLine`
          Defines a custom shell command for invoking discovered tools.
          The command must take the tool name as the first argument, read JSON arguments from stdin, and emit JSON results on stdout.
        `,
        showInDialog: false,
      },
      useRipgrep: {
        type: 'boolean',
        label: 'Use Ripgrep',
        category: 'Tools',
        requiresRestart: false,
        default: true,
        description:
          'Use ripgrep for file content search instead of the fallback implementation. Provides faster search performance.',
        showInDialog: true,
      },
      truncateToolOutputThreshold: {
        type: 'number',
        label: 'Tool Output Truncation Threshold',
        category: 'General',
        requiresRestart: true,
        default: DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD,
        description:
          'Maximum characters to show when truncating large tool outputs. Set to 0 or negative to disable truncation.',
        showInDialog: true,
      },
      disableLLMCorrection: {
        type: 'boolean',
        label: 'Disable LLM Correction',
        category: 'Tools',
        requiresRestart: true,
        default: true,
        description: oneLine`
          Disable LLM-based error correction for edit tools.
          When enabled, tools will fail immediately if exact string matches are not found, instead of attempting to self-correct.
        `,
        showInDialog: true,
      },
    },
  },

  mcp: {
    type: 'object',
    label: 'MCP',
    category: 'MCP',
    requiresRestart: true,
    default: {},
    description: 'Settings for Model Context Protocol (MCP) servers.',
    showInDialog: false,
    properties: {
      serverCommand: {
        type: 'string',
        label: 'MCP Server Command',
        category: 'MCP',
        requiresRestart: true,
        default: undefined as string | undefined,
        description: 'Command to start an MCP server.',
        showInDialog: false,
      },
      allowed: {
        type: 'array',
        label: 'Allow MCP Servers',
        category: 'MCP',
        requiresRestart: true,
        default: undefined as string[] | undefined,
        description: 'A list of MCP servers to allow.',
        showInDialog: false,
        items: { type: 'string' },
      },
      excluded: {
        type: 'array',
        label: 'Exclude MCP Servers',
        category: 'MCP',
        requiresRestart: true,
        default: undefined as string[] | undefined,
        description: 'A list of MCP servers to exclude.',
        showInDialog: false,
        items: { type: 'string' },
      },
    },
  },

  useWriteTodos: {
    type: 'boolean',
    label: 'Use WriteTodos',
    category: 'Advanced',
    requiresRestart: false,
    default: true,
    description: 'Enable the write_todos tool.',
    showInDialog: false,
  },
  security: {
    type: 'object',
    label: 'Security',
    category: 'Security',
    requiresRestart: true,
    default: {},
    description: 'Security-related settings.',
    showInDialog: false,
    properties: {
      toolSandboxing: {
        type: 'boolean',
        label: 'Tool Sandboxing',
        category: 'Security',
        requiresRestart: true,
        default: false,
        description:
          'Tool-level sandboxing. Isolates individual tools instead of the entire CLI process.',
        showInDialog: true,
      },
      disableYoloMode: {
        type: 'boolean',
        label: 'Disable YOLO Mode',
        category: 'Security',
        requiresRestart: true,
        default: false,
        description: 'Disable YOLO mode, even if enabled by a flag.',
        showInDialog: true,
      },
      disableAlwaysAllow: {
        type: 'boolean',
        label: 'Disable Always Allow',
        category: 'Security',
        requiresRestart: true,
        default: false,
        description:
          'Disable "Always allow" options in tool confirmation dialogs.',
        showInDialog: true,
      },
      enablePermanentToolApproval: {
        type: 'boolean',
        label: 'Allow Permanent Tool Approval',
        category: 'Security',
        requiresRestart: false,
        default: false,
        description:
          'Enable the "Allow for all future sessions" option in tool confirmation dialogs.',
        showInDialog: true,
      },
      autoAddToPolicyByDefault: {
        type: 'boolean',
        label: 'Auto-add to Policy by Default',
        category: 'Security',
        requiresRestart: false,
        default: false,
        description: oneLine`
          When enabled, the "Allow for all future sessions" option becomes the
          default choice for low-risk tools in trusted workspaces.
        `,
        showInDialog: true,
      },
      blockGitExtensions: {
        type: 'boolean',
        label: 'Blocks extensions from Git',
        category: 'Security',
        requiresRestart: true,
        default: false,
        description: 'Blocks installing and loading extensions from Git.',
        showInDialog: true,
      },
      allowedExtensions: {
        type: 'array',
        label: 'Extension Source Regex Allowlist',
        category: 'Security',
        requiresRestart: true,
        default: [] as string[],
        description:
          'List of Regex patterns for allowed extensions. If nonempty, only extensions that match the patterns in this list are allowed. Overrides the blockGitExtensions setting.',
        showInDialog: true,
        items: { type: 'string' },
      },
      folderTrust: {
        type: 'object',
        label: 'Folder Trust',
        category: 'Security',
        requiresRestart: false,
        default: {},
        description: 'Settings for folder trust.',
        showInDialog: false,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'Folder Trust',
            category: 'Security',
            requiresRestart: true,
            default: true,
            description: 'Setting to track whether Folder trust is enabled.',
            showInDialog: true,
          },
        },
      },
      environmentVariableRedaction: {
        type: 'object',
        label: 'Environment Variable Redaction',
        category: 'Security',
        requiresRestart: false,
        default: {},
        description: 'Settings for environment variable redaction.',
        showInDialog: false,
        properties: {
          allowed: {
            type: 'array',
            label: 'Allowed Environment Variables',
            category: 'Security',
            requiresRestart: true,
            default: [] as string[],
            description:
              'Environment variables to always allow (bypass redaction).',
            showInDialog: false,
            items: { type: 'string' },
          },
          blocked: {
            type: 'array',
            label: 'Blocked Environment Variables',
            category: 'Security',
            requiresRestart: true,
            default: [] as string[],
            description: 'Environment variables to always redact.',
            showInDialog: false,
            items: { type: 'string' },
          },
          enabled: {
            type: 'boolean',
            label: 'Enable Environment Variable Redaction',
            category: 'Security',
            requiresRestart: true,
            default: false,
            description:
              'Enable redaction of environment variables that may contain secrets.',
            showInDialog: true,
          },
        },
      },
      auth: {
        type: 'object',
        label: 'Authentication',
        category: 'Security',
        requiresRestart: true,
        default: {},
        description: 'Authentication settings.',
        showInDialog: false,
        properties: {
          selectedType: {
            type: 'string',
            label: 'Selected Auth Type',
            category: 'Security',
            requiresRestart: true,
            default: undefined as AuthType | undefined,
            description: 'The currently selected authentication type.',
            showInDialog: false,
          },
          enforcedType: {
            type: 'string',
            label: 'Enforced Auth Type',
            category: 'Advanced',
            requiresRestart: true,
            default: undefined as AuthType | undefined,
            description:
              'The required auth type. If this does not match the selected auth type, the user will be prompted to re-authenticate.',
            showInDialog: false,
          },
          useExternal: {
            type: 'boolean',
            label: 'Use External Auth',
            category: 'Security',
            requiresRestart: true,
            default: undefined as boolean | undefined,
            description: 'Whether to use an external authentication flow.',
            showInDialog: false,
          },
        },
      },
      enableConseca: {
        type: 'boolean',
        label: 'Enable Context-Aware Security',
        category: 'Security',
        requiresRestart: true,
        default: false,
        description:
          'Enable the context-aware security checker. This feature uses an LLM to dynamically generate and enforce security policies for tool use based on your prompt, providing an additional layer of protection against unintended actions.',
        showInDialog: true,
      },
    },
  },

  advanced: {
    type: 'object',
    label: 'Advanced',
    category: 'Advanced',
    requiresRestart: true,
    default: {},
    description: 'Advanced settings for power users.',
    showInDialog: false,
    properties: {
      autoConfigureMemory: {
        type: 'boolean',
        label: 'Auto Configure Max Old Space Size',
        category: 'Advanced',
        requiresRestart: true,
        default: true,
        description:
          'Automatically configure Node.js memory limits. Note: Because memory is allocated during the initial process boot, this setting is only read from the global user settings file and ignores workspace-level overrides.',
        showInDialog: true,
      },
      dnsResolutionOrder: {
        type: 'string',
        label: 'DNS Resolution Order',
        category: 'Advanced',
        requiresRestart: true,
        default: undefined as DnsResolutionOrder | undefined,
        description: 'The DNS resolution order.',
        showInDialog: false,
      },
      excludedEnvVars: {
        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,
        items: { type: 'string' },
        mergeStrategy: MergeStrategy.UNION,
      },
      ignoreLocalEnv: {
        type: 'boolean',
        label: 'Ignore Local .env',
        category: 'Advanced',
        requiresRestart: true,
        default: false,
        description:
          'Whether to ignore generic .env files in the project directory.',
        showInDialog: true,
      },
      bugCommand: {
        type: 'object',
        label: 'Bug Command',
        category: 'Advanced',
        requiresRestart: false,
        default: undefined as BugCommandSettings | undefined,
        description: 'Configuration for the bug report command.',
        showInDialog: false,
        ref: 'BugCommandSettings',
      },
    },
  },

  experimental: {
    type: 'object',
    label: 'Experimental',
    category: 'Experimental',
    requiresRestart: true,
    default: {},
    description: 'Setting to enable experimental features',
    showInDialog: false,
    properties: {
      gemma: {
        type: 'boolean',
        label: 'Gemma Models',
        category: 'Experimental',
        requiresRestart: true,
        default: true,
        description: 'Enable access to Gemma 4 models via Gemini API.',
        showInDialog: true,
      },
      voiceMode: {
        type: 'boolean',
        label: 'Voice Mode',
        category: 'Experimental',
        requiresRestart: false,
        default: false,
        description:
          'Enable experimental voice dictation and commands (/voice, /voice model).',
        showInDialog: true,
      },
      voice: {
        type: 'object',
        label: 'Voice',
        category: 'Experimental',
        requiresRestart: false,
        default: {},
        description: 'Settings for voice mode and transcription.',
        showInDialog: false,
        properties: {
          activationMode: {
            type: 'enum',
            label: 'Voice Activation Mode',
            category: 'Experimental',
            requiresRestart: false,
            default: 'push-to-talk',
            description: 'How to trigger voice recording with the Space key.',
            showInDialog: true,
            options: [
              { value: 'push-to-talk', label: 'Push-To-Talk (Hold Space)' },
              { value: 'toggle', label: 'Toggle (Press Space to start/stop)' },
            ],
          },
          backend: {
            type: 'enum',
            label: 'Voice Transcription Backend',
            category: 'Experimental',
            requiresRestart: false,
            default: 'gemini-live',
            description: oneLine`
              The backend to use for voice transcription. Note: When using the
              Gemini Live backend, voice recordings are sent to Google Cloud for
              transcription.
            `,
            showInDialog: true,
            options: [
              { value: 'gemini-live', label: 'Gemini Live API (Cloud)' },
              { value: 'whisper', label: 'Whisper (Local)' },
            ],
          },
          whisperModel: {
            type: 'enum',
            label: 'Whisper Model',
            category: 'Experimental',
            requiresRestart: false,
            default: 'ggml-base.en.bin',
            description: 'The Whisper model to use for local transcription.',
            showInDialog: true,
            options: [
              { value: 'ggml-tiny.en.bin', label: 'Tiny (EN) - Fast (~75MB)' },
              {
                value: 'ggml-base.en.bin',
                label: 'Base (EN) - Balanced (~142MB)',
              },
              {
                value: 'ggml-large-v3-turbo-q5_0.bin',
                label: 'Large v3 Turbo (Q5_0) - High Accuracy (~547MB)',
              },
              {
                value: 'ggml-large-v3-turbo-q8_0.bin',
                label: 'Large v3 Turbo (Q8_0) - Max Accuracy (~834MB)',
              },
            ],
          },
          stopGracePeriodMs: {
            type: 'number',
            label: 'Voice Stop Grace Period (ms)',
            category: 'Experimental',
            requiresRestart: false,
            default: 4000,
            description:
              'How long to wait for final transcription after stopping recording.',
            showInDialog: true,
          },
        },
      },
      adk: {
        type: 'object',
        label: 'ADK',
        category: 'Experimental',
        requiresRestart: true,
        default: {},
        description: 'Settings for the Agent Development Kit (ADK).',
        showInDialog: false,
        properties: {
          agentSessionNoninteractiveEnabled: {
            type: 'boolean',
            label: 'Agent Session Non-interactive Enabled',
            category: 'Experimental',
            requiresRestart: true,
            default: false,
            description: 'Enable non-interactive agent sessions.',
            showInDialog: false,
          },
          agentSessionInteractiveEnabled: {
            type: 'boolean',
            label: 'Interactive Agent Session Enabled',
            category: 'Experimental',
            requiresRestart: true,
            default: false,
            description:
              'Enable the agent session implementation for the interactive CLI.',
            showInDialog: false,
          },
          agentSessionSubagentEnabled: {
            type: 'boolean',
            label: 'Agent Session Subagent Enabled',
            category: 'Experimental',
            requiresRestart: true,
            default: false,
            description:
              'Route subagent invocations through the AgentSession protocol instead of legacy executors.',
            showInDialog: false,
          },
        },
      },
      enableAgents: {
        type: 'boolean',
        label: 'Enable Agents',
        category: 'Experimental',
        requiresRestart: true,
        default: true,
        description: 'Enable local and remote subagents.',
        showInDialog: false,
      },
      worktrees: {
        type: 'boolean',
        label: 'Enable Git Worktrees',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description:
          'Enable automated Git worktree management for parallel work.',
        showInDialog: true,
      },
      extensionManagement: {
        type: 'boolean',
        label: 'Extension Management',
        category: 'Experimental',
        requiresRestart: true,
        default: true,
        description: 'Enable extension management features.',
        showInDialog: false,
      },
      extensionConfig: {
        type: 'boolean',
        label: 'Extension Configuration',
        category: 'Experimental',
        requiresRestart: true,
        default: true,
        description: 'Enable requesting and fetching of extension settings.',
        showInDialog: false,
      },
      extensionRegistry: {
        type: 'boolean',
        label: 'Extension Registry Explore UI',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description: 'Enable extension registry explore UI.',
        showInDialog: false,
      },
      extensionRegistryURI: {
        type: 'string',
        label: 'Extension Registry URI',
        category: 'Experimental',
        requiresRestart: true,
        default: 'https://geminicli.com/extensions.json',
        description:
          'The URI (web URL or local file path) of the extension registry.',
        showInDialog: false,
      },
      extensionReloading: {
        type: 'boolean',
        label: 'Extension Reloading',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description:
          'Enables extension loading/unloading within the CLI session.',
        showInDialog: false,
      },
      useOSC52Paste: {
        type: 'boolean',
        label: 'Use OSC 52 Paste',
        category: 'Experimental',
        requiresRestart: false,
        default: false,
        description:
          'Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it).',
        showInDialog: true,
      },
      useOSC52Copy: {
        type: 'boolean',
        label: 'Use OSC 52 Copy',
        category: 'Experimental',
        requiresRestart: false,
        default: false,
        description:
          'Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it).',
        showInDialog: true,
      },
      taskTracker: {
        type: 'boolean',
        label: 'Task Tracker',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description: 'Enable task tracker tools.',
        showInDialog: false,
      },
      modelSteering: {
        type: 'boolean',
        label: 'Model Steering',
        category: 'Experimental',
        requiresRestart: false,
        default: false,
        description:
          'Enable model steering (user hints) to guide the model during tool execution.',
        showInDialog: true,
      },
      directWebFetch: {
        type: 'boolean',
        label: 'Direct Web Fetch',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description:
          'Enable web fetch behavior that bypasses LLM summarization.',
        showInDialog: true,
      },
      dynamicModelConfiguration: {
        type: 'boolean',
        label: 'Dynamic Model Configuration',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description:
          'Enable dynamic model configuration (definitions, resolutions, and chains) via settings.',
        showInDialog: false,
      },
      gemmaModelRouter: {
        type: 'object',
        label: 'Gemma Model Router',
        category: 'Experimental',
        requiresRestart: true,
        default: {},
        description: 'Enable Gemma model router (experimental).',
        showInDialog: false,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'Enable Gemma Model Router',
            category: 'Experimental',
            requiresRestart: true,
            default: false,
            description:
              'Enable the Gemma Model Router (experimental). Requires a local endpoint serving Gemma via the Gemini API using LiteRT-LM shim.',
            showInDialog: true,
          },
          autoStartServer: {
            type: 'boolean',
            label: 'Auto-start LiteRT Server',
            category: 'Experimental',
            requiresRestart: true,
            default: false,
            description:
              'Automatically start the LiteRT-LM server when Gemini CLI starts and the Gemma router is enabled.',
            showInDialog: true,
          },
          binaryPath: {
            type: 'string',
            label: 'LiteRT Binary Path',
            category: 'Experimental',
            requiresRestart: true,
            default: '',
            description:
              'Custom path to the LiteRT-LM binary. Leave empty to use the default location (~/.gemini/bin/litert/).',
            showInDialog: false,
          },
          classifier: {
            type: 'object',
            label: 'Classifier',
            category: 'Experimental',
            requiresRestart: true,
            default: {},
            description: 'Classifier configuration.',
            showInDialog: false,
            properties: {
              host: {
                type: 'string',
                label: 'Host',
                category: 'Experimental',
                requiresRestart: true,
                default: 'http://localhost:9379',
                description: 'The host of the classifier.',
                showInDialog: false,
              },
              model: {
                type: 'string',
                label: 'Model',
                category: 'Experimental',
                requiresRestart: true,
                default: 'gemma3-1b-gpu-custom',
                description:
                  'The model to use for the classifier. Only tested on `gemma3-1b-gpu-custom`.',
                showInDialog: false,
              },
            },
          },
        },
      },
      stressTestProfile: {
        type: 'boolean',
        label:
          'Use the stress test profile to aggressively trigger context management.',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description:
          'Significantly lowers token limits to force early garbage collection and distillation for testing purposes.',
        showInDialog: false,
      },
      autoMemory: {
        type: 'boolean',
        label: 'Auto Memory',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description:
          'Automatically extract memory patches and skills from past sessions in the background. Every change is written as a unified diff `.patch` file under `<projectMemoryDir>/.inbox/<kind>/` and held for review in /memory inbox; nothing is applied until you approve it.',
        showInDialog: true,
      },
      generalistProfile: {
        type: 'boolean',
        label: 'Use the generalist profile to manage agent contexts.',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description:
          'Suitable for general coding and software development tasks.',
        showInDialog: true,
      },
      powerUserProfile: {
        type: 'boolean',
        label: 'Use the power user profile to manage agent contexts.',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description: 'Less cache friendly version of the generalist profile.',
        showInDialog: false,
      },
      contextManagement: {
        type: 'boolean',
        label: 'Enable Context Management',
        category: 'Experimental',
        requiresRestart: true,
        default: false,
        description: 'Enable logic for context management.',
        showInDialog: true,
      },
      topicUpdateNarration: {
        type: 'boolean',
        label: 'Topic & Update Narration',
        category: 'Experimental',
        requiresRestart: false,
        default: false,
        description: 'Deprecated: Use general.topicUpdateNarration instead.',
        showInDialog: false,
      },
    },
  },
  extensions: {
    type: 'object',
    label: 'Extensions',
    category: 'Extensions',
    requiresRestart: true,
    default: {},
    description: 'Settings for extensions.',
    showInDialog: false,
    properties: {
      disabled: {
        type: 'array',
        label: 'Disabled Extensions',
        category: 'Extensions',
        requiresRestart: true,
        default: [] as string[],
        description: 'List of disabled extensions.',
        showInDialog: false,
        items: { type: 'string' },
        mergeStrategy: MergeStrategy.UNION,
      },
      workspacesWithMigrationNudge: {
        type: 'array',
        label: 'Workspaces with Migration Nudge',
        category: 'Extensions',
        requiresRestart: false,
        default: [] as string[],
        description:
          'List of workspaces for which the migration nudge has been shown.',
        showInDialog: false,
        items: { type: 'string' },
        mergeStrategy: MergeStrategy.UNION,
      },
    },
  },

  skills: {
    type: 'object',
    label: 'Skills',
    category: 'Advanced',
    requiresRestart: true,
    default: {},
    description: 'Settings for agent skills.',
    showInDialog: false,
    properties: {
      enabled: {
        type: 'boolean',
        label: 'Enable Agent Skills',
        category: 'Advanced',
        requiresRestart: true,
        default: true,
        description: 'Enable Agent Skills.',
        showInDialog: true,
      },
      disabled: {
        type: 'array',
        label: 'Disabled Skills',
        category: 'Advanced',
        requiresRestart: true,
        default: [] as string[],
        description: 'List of disabled skills.',
        showInDialog: false,
        items: { type: 'string' },
        mergeStrategy: MergeStrategy.UNION,
      },
    },
  },

  hooksConfig: {
    type: 'object',
    label: 'HooksConfig',
    category: 'Advanced',
    requiresRestart: false,
    default: {},
    description:
      'Hook configurations for intercepting and customizing agent behavior.',
    showInDialog: false,
    properties: {
      enabled: {
        type: 'boolean',
        label: 'Enable Hooks',
        category: 'Advanced',
        requiresRestart: true,
        default: true,
        description:
          'Canonical toggle for the hooks system. When disabled, no hooks will be executed.',
        showInDialog: true,
      },
      disabled: {
        type: 'array',
        label: 'Disabled Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [] as string[],
        description:
          'List of hook names (commands) that should be disabled. Hooks in this list will not execute even if configured.',
        showInDialog: false,
        items: {
          type: 'string',
          description: 'Hook command name',
        },
        mergeStrategy: MergeStrategy.UNION,
      },
      notifications: {
        type: 'boolean',
        label: 'Hook Notifications',
        category: 'Advanced',
        requiresRestart: false,
        default: true,
        description: 'Show visual indicators when hooks are executing.',
        showInDialog: true,
      },
    },
  },

  hooks: {
    type: 'object',
    label: 'Hook Events',
    category: 'Advanced',
    requiresRestart: false,
    default: {},
    description: 'Event-specific hook configurations.',
    showInDialog: false,
    properties: {
      BeforeTool: {
        type: 'array',
        label: 'Before Tool Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute before tool execution. Can intercept, validate, or modify tool calls.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      AfterTool: {
        type: 'array',
        label: 'After Tool Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute after tool execution. Can process results, log outputs, or trigger follow-up actions.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      BeforeAgent: {
        type: 'array',
        label: 'Before Agent Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute before agent loop starts. Can set up context or initialize resources.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      AfterAgent: {
        type: 'array',
        label: 'After Agent Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute after agent loop completes. Can perform cleanup or summarize results.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      Notification: {
        type: 'array',
        label: 'Notification Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute on notification events (errors, warnings, info). Can log or alert on specific conditions.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      SessionStart: {
        type: 'array',
        label: 'Session Start Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute when a session starts. Can initialize session-specific resources or state.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      SessionEnd: {
        type: 'array',
        label: 'Session End Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute when a session ends. Can perform cleanup or persist session data.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      PreCompress: {
        type: 'array',
        label: 'Pre-Compress Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute before chat history compression. Can back up or analyze conversation before compression.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      BeforeModel: {
        type: 'array',
        label: 'Before Model Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute before LLM requests. Can modify prompts, inject context, or control model parameters.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      AfterModel: {
        type: 'array',
        label: 'After Model Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute after LLM responses. Can process outputs, extract information, or log interactions.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
      BeforeToolSelection: {
        type: 'array',
        label: 'Before Tool Selection Hooks',
        category: 'Advanced',
        requiresRestart: false,
        default: [],
        description:
          'Hooks that execute before tool selection. Can filter or prioritize available tools dynamically.',
        showInDialog: false,
        ref: 'HookDefinitionArray',
        mergeStrategy: MergeStrategy.CONCAT,
      },
    },
    additionalProperties: {
      type: 'array',
      description:
        'Custom hook event arrays that contain hook definitions for user-defined events',
      mergeStrategy: MergeStrategy.CONCAT,
    },
  },

  contextManagement: {
    type: 'object',
    label: 'Context Management',
    category: 'Experimental',
    requiresRestart: true,
    default: {},
    description:
      'Settings for agent history and tool distillation context management.',
    showInDialog: false,
    properties: {
      historyWindow: {
        type: 'object',
        label: 'History Window Settings',
        category: 'Context Management',
        requiresRestart: true,
        default: {},
        showInDialog: false,
        properties: {
          maxTokens: {
            type: 'number',
            label: 'Max Tokens',
            category: 'Context Management',
            requiresRestart: true,
            default: 150_000,
            description:
              'The number of tokens to allow before triggering compression.',
            showInDialog: false,
          },
          retainedTokens: {
            type: 'number',
            label: 'Retained Tokens',
            category: 'Context Management',
            requiresRestart: true,
            default: 40_000,
            description: 'The number of tokens to always retain.',
            showInDialog: false,
          },
        },
      },
      messageLimits: {
        type: 'object',
        label: 'Message Limits',
        category: 'Context Management',
        requiresRestart: true,
        default: {},
        showInDialog: false,
        properties: {
          normalMaxTokens: {
            type: 'number',
            label: 'Normal Maximum Tokens',
            category: 'Context Management',
            requiresRestart: true,
            default: 2500,
            description:
              'The target number of tokens to budget for a normal conversation turn.',
            showInDialog: false,
          },
          retainedMaxTokens: {
            type: 'number',
            label: 'Retained Maximum Tokens',
            category: 'Context Management',
            requiresRestart: true,
            default: 12000,
            description:
              'The maximum number of tokens a single conversation turn can consume before truncation.',
            showInDialog: false,
          },
          normalizationHeadRatio: {
            type: 'number',
            label: 'Normalization Head Ratio',
            category: 'Context Management',
            requiresRestart: true,
            default: 0.25,
            description:
              'The ratio of tokens to retain from the beginning of a truncated message (0.0 to 1.0).',
            showInDialog: false,
          },
        },
      },
      tools: {
        type: 'object',
        label: 'Context Management Tools',
        category: 'Context Management',
        requiresRestart: true,
        default: {},
        showInDialog: false,
        properties: {
          distillation: {
            type: 'object',
            label: 'Tool Distillation',
            category: 'Context Management',
            requiresRestart: true,
            default: {},
            showInDialog: false,
            properties: {
              maxOutputTokens: {
                type: 'number',
                label: 'Max Output Tokens',
                category: 'Context Management',
                requiresRestart: true,
                default: 10_000,
                description:
                  'Maximum tokens to show to the model when truncating large tool outputs.',
                showInDialog: false,
              },
              summarizationThresholdTokens: {
                type: 'number',
                label: 'Tool Summarization Threshold',
                category: 'Context Management',
                requiresRestart: true,
                default: 20_000,
                description:
                  'Threshold above which truncated tool outputs will be summarized by an LLM.',
                showInDialog: false,
              },
            },
          },
          outputMasking: {
            type: 'object',
            label: 'Tool Output Masking',
            category: 'Context Management',
            requiresRestart: true,
            ignoreInDocs: false,
            default: {},
            description:
              'Advanced settings for tool output masking to manage context window efficiency.',
            showInDialog: false,
            properties: {
              protectionThresholdTokens: {
                type: 'number',
                label: 'Tool Protection Threshold (Tokens)',
                category: 'Context Management',
                requiresRestart: true,
                default: 50_000,
                description:
                  'Minimum number of tokens to protect from masking (most recent tool outputs).',
                showInDialog: false,
              },
              minPrunableThresholdTokens: {
                type: 'number',
                label: 'Min Prunable Tokens Threshold',
                category: 'Context Management',
                requiresRestart: true,
                default: 30_000,
                description:
                  'Minimum prunable tokens required to trigger a masking pass.',
                showInDialog: false,
              },
              protectLatestTurn: {
                type: 'boolean',
                label: 'Protect Latest Turn',
                category: 'Context Management',
                requiresRestart: true,
                default: true,
                description:
                  'Ensures the absolute latest turn is never masked, regardless of token count.',
                showInDialog: false,
              },
            },
          },
        },
      },
    },
  },

  admin: {
    type: 'object',
    label: 'Admin',
    category: 'Admin',
    requiresRestart: false,
    default: {},
    description: 'Settings configured remotely by enterprise admins.',
    showInDialog: false,
    mergeStrategy: MergeStrategy.REPLACE,
    properties: {
      secureModeEnabled: {
        type: 'boolean',
        label: 'Secure Mode Enabled',
        category: 'Admin',
        requiresRestart: false,
        default: false,
        description:
          'If true, disallows YOLO mode and "Always allow" options from being used.',
        showInDialog: false,
        mergeStrategy: MergeStrategy.REPLACE,
      },
      extensions: {
        type: 'object',
        label: 'Extensions Settings',
        category: 'Admin',
        requiresRestart: false,
        default: {},
        description: 'Extensions-specific admin settings.',
        showInDialog: false,
        mergeStrategy: MergeStrategy.REPLACE,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'Extensions Enabled',
            category: 'Admin',
            requiresRestart: false,
            default: true,
            description:
              'If false, disallows extensions from being installed or used.',
            showInDialog: false,
            mergeStrategy: MergeStrategy.REPLACE,
          },
        },
      },
      mcp: {
        type: 'object',
        label: 'MCP Settings',
        category: 'Admin',
        requiresRestart: false,
        default: {},
        description: 'MCP-specific admin settings.',
        showInDialog: false,
        mergeStrategy: MergeStrategy.REPLACE,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'MCP Enabled',
            category: 'Admin',
            requiresRestart: false,
            default: true,
            description: 'If false, disallows MCP servers from being used.',
            showInDialog: false,
            mergeStrategy: MergeStrategy.REPLACE,
          },
          config: {
            type: 'object',
            label: 'MCP Config',
            category: 'Admin',
            requiresRestart: false,
            default: {} as Record<string, MCPServerConfig>,
            description: 'Admin-configured MCP servers (allowlist).',
            showInDialog: false,
            mergeStrategy: MergeStrategy.REPLACE,
            additionalProperties: {
              type: 'object',
              ref: 'MCPServerConfig',
            },
          },
          requiredConfig: {
            type: 'object',
            label: 'Required MCP Config',
            category: 'Admin',
            requiresRestart: false,
            default: {} as Record<string, RequiredMcpServerConfig>,
            description: 'Admin-required MCP servers that are always injected.',
            showInDialog: false,
            mergeStrategy: MergeStrategy.REPLACE,
            additionalProperties: {
              type: 'object',
              ref: 'RequiredMcpServerConfig',
            },
          },
        },
      },
      skills: {
        type: 'object',
        label: 'Skills Settings',
        category: 'Admin',
        requiresRestart: false,
        default: {},
        description: 'Agent Skills-specific admin settings.',
        showInDialog: false,
        mergeStrategy: MergeStrategy.REPLACE,
        properties: {
          enabled: {
            type: 'boolean',
            label: 'Skills Enabled',
            category: 'Admin',
            requiresRestart: false,
            default: true,
            description: 'If false, disallows agent skills from being used.',
            showInDialog: false,
            mergeStrategy: MergeStrategy.REPLACE,
          },
        },
      },
    },
  },
} as const satisfies SettingsSchema;

export type SettingsSchemaType = typeof SETTINGS_SCHEMA;

export type SettingsJsonSchemaDefinition = Record<string, unknown>;

export const SETTINGS_SCHEMA_DEFINITIONS: Record<
  string,
  SettingsJsonSchemaDefinition
> = {
  MCPServerConfig: {
    type: 'object',
    description:
      'Definition of a Model Context Protocol (MCP) server configuration.',
    additionalProperties: false,
    properties: {
      command: {
        type: 'string',
        description: 'Executable invoked for stdio transport.',
      },
      args: {
        type: 'array',
        description: 'Command-line arguments for the stdio transport command.',
        items: { type: 'string' },
      },
      env: {
        type: 'object',
        description: 'Environment variables to set for the server process.',
        additionalProperties: { type: 'string' },
      },
      cwd: {
        type: 'string',
        description: 'Working directory for the server process.',
      },
      url: {
        type: 'string',
        description:
          'URL for SSE or HTTP transport. Use with "type" field to specify transport type.',
      },
      httpUrl: {
        type: 'string',
        description: 'Streaming HTTP transport URL.',
      },
      headers: {
        type: 'object',
        description: 'Additional HTTP headers sent to the server.',
        additionalProperties: { type: 'string' },
      },
      tcp: {
        type: 'string',
        description: 'TCP address for websocket transport.',
      },
      type: {
        type: 'string',
        description:
          'Transport type. Use "stdio" for local command, "sse" for Server-Sent Events, or "http" for Streamable HTTP.',
        enum: ['stdio', 'sse', 'http'],
      },
      timeout: {
        type: 'number',
        description: 'Timeout in milliseconds for MCP requests.',
      },
      trust: {
        type: 'boolean',
        description:
          'Marks the server as trusted. Trusted servers may gain additional capabilities.',
      },
      description: {
        type: 'string',
        description: 'Human-readable description of the server.',
      },
      includeTools: {
        type: 'array',
        description:
          'Subset of tools that should be enabled for this server. When omitted all tools are enabled.',
        items: { type: 'string' },
      },
      excludeTools: {
        type: 'array',
        description:
          'Tools that should be disabled for this server even if exposed.',
        items: { type: 'string' },
      },
      extension: {
        type: 'object',
        description:
          'Metadata describing the Gemini CLI extension that owns this MCP server.',
        additionalProperties: { type: ['string', 'boolean', 'number'] },
      },
      oauth: {
        type: 'object',
        description: 'OAuth configuration for authenticating with the server.',
        additionalProperties: true,
      },
      authProviderType: {
        type: 'string',
        description:
          'Authentication provider used for acquiring credentials (for example `dynamic_discovery`).',
        enum: Object.values(AuthProviderType),
      },
      targetAudience: {
        type: 'string',
        description:
          'OAuth target audience (CLIENT_ID.apps.googleusercontent.com).',
      },
      targetServiceAccount: {
        type: 'string',
        description:
          'Service account email to impersonate (name@project.iam.gserviceaccount.com).',
      },
    },
  },
  RequiredMcpServerConfig: {
    type: 'object',
    description:
      'Admin-required MCP server configuration (remote transports only).',
    additionalProperties: false,
    properties: {
      url: {
        type: 'string',
        description: 'URL for the required MCP server.',
      },
      type: {
        type: 'string',
        description: 'Transport type for the required server.',
        enum: ['sse', 'http'],
      },
      headers: {
        type: 'object',
        description: 'Additional HTTP headers sent to the server.',
        additionalProperties: { type: 'string' },
      },
      timeout: {
        type: 'number',
        description: 'Timeout in milliseconds for MCP requests.',
      },
      trust: {
        type: 'boolean',
        description:
          'Marks the server as trusted. Defaults to true for admin-required servers.',
      },
      description: {
        type: 'string',
        description: 'Human-readable description of the server.',
      },
      includeTools: {
        type: 'array',
        description: 'Subset of tools enabled for this server.',
        items: { type: 'string' },
      },
      excludeTools: {
        type: 'array',
        description: 'Tools disabled for this server.',
        items: { type: 'string' },
      },
      oauth: {
        type: 'object',
        description: 'OAuth configuration for authenticating with the server.',
        additionalProperties: true,
      },
      authProviderType: {
        type: 'string',
        description: 'Authentication provider used for acquiring credentials.',
        enum: Object.values(AuthProviderType),
      },
      targetAudience: {
        type: 'string',
        description:
          'OAuth target audience (CLIENT_ID.apps.googleusercontent.com).',
      },
      targetServiceAccount: {
        type: 'string',
        description:
          'Service account email to impersonate (name@project.iam.gserviceaccount.com).',
      },
    },
  },
  TelemetrySettings: {
    type: 'object',
    description: 'Telemetry configuration for Gemini CLI.',
    additionalProperties: false,
    properties: {
      enabled: {
        type: 'boolean',
        description: 'Enables telemetry emission.',
      },
      target: {
        type: 'string',
        description:
          'Telemetry destination (for example `stderr`, `stdout`, or `otlp`).',
      },
      otlpEndpoint: {
        type: 'string',
        description: 'Endpoint for OTLP exporters.',
      },
      otlpProtocol: {
        type: 'string',
        description: 'Protocol for OTLP exporters.',
        enum: ['grpc', 'http'],
      },
      traces: {
        type: 'boolean',
        description:
          'Whether detailed traces with large attributes are captured.',
      },
      logPrompts: {
        type: 'boolean',
        description: 'Whether prompts are logged in telemetry payloads.',
      },
      outfile: {
        type: 'string',
        description: 'File path for writing telemetry output.',
      },
      useCollector: {
        type: 'boolean',
        description: 'Whether to forward telemetry to an OTLP collector.',
      },
      useCliAuth: {
        type: 'boolean',
        description:
          'Whether to use CLI authentication for telemetry (only for in-process exporters).',
      },
    },
  },
  BugCommandSettings: {
    type: 'object',
    description: 'Configuration for the bug report helper command.',
    additionalProperties: false,
    properties: {
      urlTemplate: {
        type: 'string',
        description:
          'Template used to open a bug report URL. Variables in the template are populated at runtime.',
      },
    },
    required: ['urlTemplate'],
  },
  SummarizeToolOutputSettings: {
    type: 'object',
    description:
      'Controls summarization behavior for individual tools. All properties are optional.',
    additionalProperties: false,
    properties: {
      tokenBudget: {
        type: 'number',
        description:
          'Maximum number of tokens used when summarizing tool output.',
      },
    },
  },
  AgentOverride: {
    type: 'object',
    description: 'Override settings for a specific agent.',
    additionalProperties: false,
    properties: {
      modelConfig: {
        type: 'object',
        additionalProperties: true,
      },
      runConfig: {
        type: 'object',
        description: 'Run configuration for an agent.',
        additionalProperties: false,
        properties: {
          maxTimeMinutes: {
            type: 'number',
            description: 'The maximum execution time for the agent in minutes.',
          },
          maxTurns: {
            type: 'number',
            description: 'The maximum number of conversational turns.',
          },
        },
      },
      enabled: {
        type: 'boolean',
        description: 'Whether to enable the agent.',
      },
    },
  },
  CustomTheme: {
    type: 'object',
    description:
      'Custom theme definition used for styling Gemini CLI output. Colors are provided as hex strings or named ANSI colors.',
    additionalProperties: false,
    properties: {
      type: {
        type: 'string',
        enum: ['custom'],
        default: 'custom',
      },
      name: {
        type: 'string',
        description: 'Theme display name.',
      },
      text: {
        type: 'object',
        additionalProperties: false,
        properties: {
          primary: { type: 'string' },
          secondary: { type: 'string' },
          link: { type: 'string' },
          accent: { type: 'string' },
          response: { type: 'string' },
        },
      },
      background: {
        type: 'object',
        additionalProperties: false,
        properties: {
          primary: { type: 'string' },
          diff: {
            type: 'object',
            additionalProperties: false,
            properties: {
              added: { type: 'string' },
              removed: { type: 'string' },
            },
          },
        },
      },
      border: {
        type: 'object',
        additionalProperties: false,
        properties: {
          default: { type: 'string' },
          focused: { type: 'string' },
        },
      },
      ui: {
        type: 'object',
        additionalProperties: false,
        properties: {
          comment: { type: 'string' },
          symbol: { type: 'string' },
          gradient: {
            type: 'array',
            items: { type: 'string' },
          },
        },
      },
      status: {
        type: 'object',
        additionalProperties: false,
        properties: {
          error: { type: 'string' },
          success: { type: 'string' },
          warning: { type: 'string' },
        },
      },
      Background: { type: 'string' },
      Foreground: { type: 'string' },
      LightBlue: { type: 'string' },
      AccentBlue: { type: 'string' },
      AccentPurple: { type: 'string' },
      AccentCyan: { type: 'string' },
      AccentGreen: { type: 'string' },
      AccentYellow: { type: 'string' },
      AccentRed: { type: 'string' },
      DiffAdded: { type: 'string' },
      DiffRemoved: { type: 'string' },
      Comment: { type: 'string' },
      Gray: { type: 'string' },
      DarkGray: { type: 'string' },
      GradientColors: {
        type: 'array',
        items: { type: 'string' },
      },
    },
    required: ['type', 'name'],
  },
  StringOrStringArray: {
    description: 'Accepts either a single string or an array of strings.',
    anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
  },
  BooleanOrStringOrObject: {
    description:
      'Accepts either a boolean flag, a string command name, or a configuration object.',
    anyOf: [
      { type: 'boolean' },
      { type: 'string' },
      {
        type: 'object',
        description: 'Sandbox configuration object.',
        additionalProperties: false,
        properties: {
          enabled: {
            type: 'boolean',
            description: 'Enables or disables the sandbox.',
          },
          command: {
            type: 'string',
            description:
              'The sandbox command to use (docker, podman, sandbox-exec, runsc, lxc).',
            enum: ['docker', 'podman', 'sandbox-exec', 'runsc', 'lxc'],
          },
          image: {
            type: 'string',
            description: 'The sandbox image to use.',
          },
          allowedPaths: {
            type: 'array',
            description:
              'A list of absolute host paths that should be accessible within the sandbox.',
            items: { type: 'string' },
          },
          networkAccess: {
            type: 'boolean',
            description: 'Whether the sandbox should have internet access.',
          },
        },
      },
    ],
  },
  HookDefinitionArray: {
    type: 'array',
    description: 'Array of hook definition objects for a specific event.',
    items: {
      type: 'object',
      description:
        'Hook definition specifying matcher pattern and hook configurations.',
      properties: {
        matcher: {
          type: 'string',
          description:
            'Pattern to match against the event context (tool name, notification type, etc.). Supports exact match, regex (/pattern/), and wildcards (*).',
        },
        hooks: {
          type: 'array',
          description: 'Hooks to execute when the matcher matches.',
          items: {
            type: 'object',
            description: 'Individual hook configuration.',
            properties: {
              name: {
                type: 'string',
                description: 'Unique identifier for the hook.',
              },
              type: {
                type: 'string',
                description:
                  'Type of hook (currently only "command" supported).',
              },
              command: {
                type: 'string',
                description:
                  'Shell command to execute. Receives JSON input via stdin and returns JSON output via stdout.',
              },
              description: {
                type: 'string',
                description: 'A description of the hook.',
              },
              timeout: {
                type: 'number',
                description: 'Timeout in milliseconds for hook execution.',
              },
            },
          },
        },
      },
    },
  },
  ModelDefinition: {
    type: 'object',
    description: 'Model metadata registry entry.',
    properties: {
      displayName: { type: 'string' },
      tier: { enum: ['pro', 'flash', 'flash-lite', 'custom', 'auto'] },
      family: { type: 'string' },
      isPreview: { type: 'boolean' },
      isVisible: { type: 'boolean' },
      dialogDescription: {
        type: 'string',
        description:
          "A description of the model to display in the model selection dialog. For the 'auto' alias, this value is dynamically generated and any value provided here will be ignored.",
      },
      features: {
        type: 'object',
        properties: {
          thinking: { type: 'boolean' },
          multimodalToolUse: { type: 'boolean' },
        },
      },
    },
  },
  ModelResolution: {
    type: 'object',
    description: 'Model resolution rule.',
    properties: {
      default: { type: 'string' },
      contexts: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            condition: {
              type: 'object',
              properties: {
                useGemini3_1: { type: 'boolean' },
                useGemini3_1FlashLite: { type: 'boolean' },
                useCustomTools: { type: 'boolean' },
                hasAccessToPreview: { type: 'boolean' },
                requestedModels: {
                  type: 'array',
                  items: { type: 'string' },
                },
              },
            },
            target: { type: 'string' },
          },
        },
      },
    },
  },
  ModelPolicyChain: {
    type: 'array',
    description: 'A chain of model policies for fallback behavior.',
    items: {
      type: 'object',
      ref: 'ModelPolicy',
    },
  },
  ModelPolicy: {
    type: 'object',
    description:
      'Defines the policy for a single model in the availability chain.',
    properties: {
      model: { type: 'string' },
      isLastResort: { type: 'boolean' },
      actions: {
        type: 'object',
        properties: {
          terminal: { type: 'string', enum: ['silent', 'prompt'] },
          transient: { type: 'string', enum: ['silent', 'prompt'] },
          not_found: { type: 'string', enum: ['silent', 'prompt'] },
          unknown: { type: 'string', enum: ['silent', 'prompt'] },
        },
      },
      stateTransitions: {
        type: 'object',
        properties: {
          terminal: { type: 'string', enum: ['terminal', 'sticky_retry'] },
          transient: { type: 'string', enum: ['terminal', 'sticky_retry'] },
          not_found: { type: 'string', enum: ['terminal', 'sticky_retry'] },
          unknown: { type: 'string', enum: ['terminal', 'sticky_retry'] },
        },
      },
    },
    required: ['model'],
  },
};

export function getSettingsSchema(): SettingsSchemaType {
  return SETTINGS_SCHEMA;
}

type InferSettings<T extends SettingsSchema> = {
  -readonly [K in keyof T]?: T[K] extends { properties: SettingsSchema }
    ? InferSettings<T[K]['properties']>
    : T[K]['type'] extends 'enum'
      ? T[K]['options'] extends readonly SettingEnumOption[]
        ? T[K]['options'][number]['value']
        : T[K]['default']
      : T[K]['default'] extends boolean
        ? boolean
        : T[K]['default'] extends string
          ? string
          : T[K]['default'] extends ReadonlyArray<infer U>
            ? U[]
            : T[K]['default'];
};

type InferMergedSettings<T extends SettingsSchema> = {
  -readonly [K in keyof T]-?: T[K] extends { properties: SettingsSchema }
    ? InferMergedSettings<T[K]['properties']>
    : T[K]['type'] extends 'enum'
      ? T[K]['options'] extends readonly SettingEnumOption[]
        ? T[K]['options'][number]['value']
        : T[K]['default']
      : T[K]['default'] extends boolean
        ? boolean
        : T[K]['default'] extends string
          ? string
          : T[K]['default'] extends ReadonlyArray<infer U>
            ? U[]
            : T[K]['default'];
};

export type Settings = InferSettings<SettingsSchemaType>;
export type MergedSettings = InferMergedSettings<SettingsSchemaType>;
