From 14f0cb45389deff7b0293dfe58e04fea11ee151c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 9 Jan 2026 11:56:22 -0800 Subject: [PATCH] feat(ui): reduce home directory warning noise and add opt-out setting (#16229) --- docs/get-started/configuration.md | 6 +++ packages/cli/src/config/settingsSchema.ts | 10 ++++ packages/cli/src/gemini.tsx | 2 +- .../cli/src/utils/userStartupWarnings.test.ts | 54 ++++++++++++++++--- packages/cli/src/utils/userStartupWarnings.ts | 28 ++++++++-- schemas/settings.schema.json | 7 +++ 6 files changed, 95 insertions(+), 12 deletions(-) diff --git a/docs/get-started/configuration.md b/docs/get-started/configuration.md index 1777d22f5f..8d7b95e24d 100644 --- a/docs/get-started/configuration.md +++ b/docs/get-started/configuration.md @@ -184,6 +184,12 @@ their corresponding top-level category object in your `settings.json` file. title - **Default:** `false` +- **`ui.showHomeDirectoryWarning`** (boolean): + - **Description:** Show a warning when running Gemini CLI in the home + directory. + - **Default:** `true` + - **Requires restart:** Yes + - **`ui.hideTips`** (boolean): - **Description:** Hide helpful tips in the UI - **Default:** `false` diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index 4dea5d0a99..b69d8f7fe6 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -384,6 +384,16 @@ const SETTINGS_SCHEMA = { 'Show Gemini CLI status and thoughts in the terminal window title', 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, + }, hideTips: { type: 'boolean', label: 'Hide Tips', diff --git a/packages/cli/src/gemini.tsx b/packages/cli/src/gemini.tsx index b3ce41f7fe..d75f509dd2 100644 --- a/packages/cli/src/gemini.tsx +++ b/packages/cli/src/gemini.tsx @@ -588,7 +588,7 @@ export async function main() { let input = config.getQuestion(); const startupWarnings = [ ...(await getStartupWarnings()), - ...(await getUserStartupWarnings()), + ...(await getUserStartupWarnings(settings.merged)), ]; // Handle --resume flag diff --git a/packages/cli/src/utils/userStartupWarnings.test.ts b/packages/cli/src/utils/userStartupWarnings.test.ts index 0a9f957617..c3746ad0a1 100644 --- a/packages/cli/src/utils/userStartupWarnings.test.ts +++ b/packages/cli/src/utils/userStartupWarnings.test.ts @@ -9,6 +9,10 @@ import { getUserStartupWarnings } from './userStartupWarnings.js'; import * as os from 'node:os'; import fs from 'node:fs/promises'; import path from 'node:path'; +import { + isFolderTrustEnabled, + isWorkspaceTrusted, +} from '../config/trustedFolders.js'; // Mock os.homedir to control the home directory in tests vi.mock('os', async (importOriginal) => { @@ -28,6 +32,11 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => { }; }); +vi.mock('../config/trustedFolders.js', () => ({ + isFolderTrustEnabled: vi.fn(), + isWorkspaceTrusted: vi.fn(), +})); + describe('getUserStartupWarnings', () => { let testRootDir: string; let homeDir: string; @@ -37,6 +46,11 @@ describe('getUserStartupWarnings', () => { homeDir = path.join(testRootDir, 'home'); await fs.mkdir(homeDir, { recursive: true }); vi.mocked(os.homedir).mockReturnValue(homeDir); + vi.mocked(isFolderTrustEnabled).mockReturnValue(false); + vi.mocked(isWorkspaceTrusted).mockReturnValue({ + isTrusted: false, + source: undefined, + }); }); afterEach(async () => { @@ -46,16 +60,44 @@ describe('getUserStartupWarnings', () => { describe('home directory check', () => { it('should return a warning when running in home directory', async () => { - const warnings = await getUserStartupWarnings(homeDir); + const warnings = await getUserStartupWarnings({}, homeDir); expect(warnings).toContainEqual( - expect.stringContaining('home directory'), + expect.stringContaining( + 'Warning you are running Gemini CLI in your home directory', + ), + ); + expect(warnings).toContainEqual( + expect.stringContaining('warning can be disabled in /settings'), ); }); it('should not return a warning when running in a project directory', async () => { const projectDir = path.join(testRootDir, 'project'); await fs.mkdir(projectDir); - const warnings = await getUserStartupWarnings(projectDir); + const warnings = await getUserStartupWarnings({}, projectDir); + expect(warnings).not.toContainEqual( + expect.stringContaining('home directory'), + ); + }); + + it('should not return a warning when showHomeDirectoryWarning is false', async () => { + const warnings = await getUserStartupWarnings( + { ui: { showHomeDirectoryWarning: false } }, + homeDir, + ); + expect(warnings).not.toContainEqual( + expect.stringContaining('home directory'), + ); + }); + + it('should not return a warning when folder trust is enabled and workspace is trusted', async () => { + vi.mocked(isFolderTrustEnabled).mockReturnValue(true); + vi.mocked(isWorkspaceTrusted).mockReturnValue({ + isTrusted: true, + source: 'file', + }); + + const warnings = await getUserStartupWarnings({}, homeDir); expect(warnings).not.toContainEqual( expect.stringContaining('home directory'), ); @@ -65,7 +107,7 @@ describe('getUserStartupWarnings', () => { describe('root directory check', () => { it('should return a warning when running in a root directory', async () => { const rootDir = path.parse(testRootDir).root; - const warnings = await getUserStartupWarnings(rootDir); + const warnings = await getUserStartupWarnings({}, rootDir); expect(warnings).toContainEqual( expect.stringContaining('root directory'), ); @@ -77,7 +119,7 @@ describe('getUserStartupWarnings', () => { it('should not return a warning when running in a non-root directory', async () => { const projectDir = path.join(testRootDir, 'project'); await fs.mkdir(projectDir); - const warnings = await getUserStartupWarnings(projectDir); + const warnings = await getUserStartupWarnings({}, projectDir); expect(warnings).not.toContainEqual( expect.stringContaining('root directory'), ); @@ -87,7 +129,7 @@ describe('getUserStartupWarnings', () => { describe('error handling', () => { it('should handle errors when checking directory', async () => { const nonExistentPath = path.join(testRootDir, 'non-existent'); - const warnings = await getUserStartupWarnings(nonExistentPath); + const warnings = await getUserStartupWarnings({}, nonExistentPath); const expectedWarning = 'Could not verify the current directory due to a file system error.'; expect(warnings).toEqual([expectedWarning, expectedWarning]); diff --git a/packages/cli/src/utils/userStartupWarnings.ts b/packages/cli/src/utils/userStartupWarnings.ts index 37a5dd49cd..8a0c0b0d3a 100644 --- a/packages/cli/src/utils/userStartupWarnings.ts +++ b/packages/cli/src/utils/userStartupWarnings.ts @@ -8,16 +8,25 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import process from 'node:process'; import { homedir } from '@google/gemini-cli-core'; +import type { Settings } from '../config/settingsSchema.js'; +import { + isFolderTrustEnabled, + isWorkspaceTrusted, +} from '../config/trustedFolders.js'; type WarningCheck = { id: string; - check: (workspaceRoot: string) => Promise; + check: (workspaceRoot: string, settings: Settings) => Promise; }; // Individual warning checks const homeDirectoryCheck: WarningCheck = { id: 'home-directory', - check: async (workspaceRoot: string) => { + check: async (workspaceRoot: string, settings: Settings) => { + if (settings.ui?.showHomeDirectoryWarning === false) { + return null; + } + try { const [workspaceRealPath, homeRealPath] = await Promise.all([ fs.realpath(workspaceRoot), @@ -25,7 +34,15 @@ const homeDirectoryCheck: WarningCheck = { ]); if (workspaceRealPath === homeRealPath) { - return 'You are running Gemini CLI in your home directory. It is recommended to run in a project-specific directory.'; + // If folder trust is enabled and the user trusts the home directory, don't show the warning. + if ( + isFolderTrustEnabled(settings) && + isWorkspaceTrusted(settings).isTrusted + ) { + return null; + } + + return 'Warning you are running Gemini CLI in your home directory.\nThis warning can be disabled in /settings'; } return null; } catch (_err: unknown) { @@ -36,7 +53,7 @@ const homeDirectoryCheck: WarningCheck = { const rootDirectoryCheck: WarningCheck = { id: 'root-directory', - check: async (workspaceRoot: string) => { + check: async (workspaceRoot: string, _settings: Settings) => { try { const workspaceRealPath = await fs.realpath(workspaceRoot); const errorMessage = @@ -61,10 +78,11 @@ const WARNING_CHECKS: readonly WarningCheck[] = [ ]; export async function getUserStartupWarnings( + settings: Settings, workspaceRoot: string = process.cwd(), ): Promise { const results = await Promise.all( - WARNING_CHECKS.map((check) => check.check(workspaceRoot)), + WARNING_CHECKS.map((check) => check.check(workspaceRoot, settings)), ); return results.filter((msg) => msg !== null); } diff --git a/schemas/settings.schema.json b/schemas/settings.schema.json index 83429aecca..2cfbcb5056 100644 --- a/schemas/settings.schema.json +++ b/schemas/settings.schema.json @@ -194,6 +194,13 @@ "default": false, "type": "boolean" }, + "showHomeDirectoryWarning": { + "title": "Show Home Directory Warning", + "description": "Show a warning when running Gemini CLI in the home directory.", + "markdownDescription": "Show a warning when running Gemini CLI in the home directory.\n\n- Category: `UI`\n- Requires restart: `yes`\n- Default: `true`", + "default": true, + "type": "boolean" + }, "hideTips": { "title": "Hide Tips", "description": "Hide helpful tips in the UI",