From da50a1eefbd0751aaf137882595d500e6b6b4179 Mon Sep 17 00:00:00 2001 From: christine betts Date: Wed, 9 Jul 2025 21:16:42 +0000 Subject: Add system-wide settings config for administrators (#3498) Co-authored-by: Jack Wotherspoon --- packages/cli/src/config/settings.ts | 42 ++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'packages/cli/src/config/settings.ts') diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts index c2d03167..133701f5 100644 --- a/packages/cli/src/config/settings.ts +++ b/packages/cli/src/config/settings.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { homedir } from 'os'; +import { homedir, platform } from 'os'; import * as dotenv from 'dotenv'; import { MCPServerConfig, @@ -24,9 +24,22 @@ export const SETTINGS_DIRECTORY_NAME = '.gemini'; export const USER_SETTINGS_DIR = path.join(homedir(), SETTINGS_DIRECTORY_NAME); export const USER_SETTINGS_PATH = path.join(USER_SETTINGS_DIR, 'settings.json'); +function getSystemSettingsPath(): string { + if (platform() === 'darwin') { + return '/Library/Application Support/GeminiCli/settings.json'; + } else if (platform() === 'win32') { + return 'C:\\ProgramData\\gemini-cli\\settings.json'; + } else { + return '/etc/gemini-cli/settings.json'; + } +} + +export const SYSTEM_SETTINGS_PATH = getSystemSettingsPath(); + export enum SettingScope { User = 'User', Workspace = 'Workspace', + System = 'System', } export interface CheckpointingSettings { @@ -81,16 +94,19 @@ export interface SettingsFile { } export class LoadedSettings { constructor( + system: SettingsFile, user: SettingsFile, workspace: SettingsFile, errors: SettingsError[], ) { + this.system = system; this.user = user; this.workspace = workspace; this.errors = errors; this._merged = this.computeMergedSettings(); } + readonly system: SettingsFile; readonly user: SettingsFile; readonly workspace: SettingsFile; readonly errors: SettingsError[]; @@ -105,6 +121,7 @@ export class LoadedSettings { return { ...this.user.settings, ...this.workspace.settings, + ...this.system.settings, }; } @@ -114,6 +131,8 @@ export class LoadedSettings { return this.user; case SettingScope.Workspace: return this.workspace; + case SettingScope.System: + return this.system; default: throw new Error(`Invalid scope: ${scope}`); } @@ -243,10 +262,27 @@ export function loadEnvironment(): void { */ export function loadSettings(workspaceDir: string): LoadedSettings { loadEnvironment(); + let systemSettings: Settings = {}; let userSettings: Settings = {}; let workspaceSettings: Settings = {}; const settingsErrors: SettingsError[] = []; + // Load system settings + try { + if (fs.existsSync(SYSTEM_SETTINGS_PATH)) { + const systemContent = fs.readFileSync(SYSTEM_SETTINGS_PATH, 'utf-8'); + const parsedSystemSettings = JSON.parse( + stripJsonComments(systemContent), + ) as Settings; + systemSettings = resolveEnvVarsInObject(parsedSystemSettings); + } + } catch (error: unknown) { + settingsErrors.push({ + message: getErrorMessage(error), + path: SYSTEM_SETTINGS_PATH, + }); + } + // Load user settings try { if (fs.existsSync(USER_SETTINGS_PATH)) { @@ -300,6 +336,10 @@ export function loadSettings(workspaceDir: string): LoadedSettings { } return new LoadedSettings( + { + path: SYSTEM_SETTINGS_PATH, + settings: systemSettings, + }, { path: USER_SETTINGS_PATH, settings: userSettings, -- cgit v1.2.3