mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-02-01 22:48:03 +00:00
feat(ui): reduce home directory warning noise and add opt-out setting (#16229)
This commit is contained in:
@@ -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`
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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<string | null>;
|
||||
check: (workspaceRoot: string, settings: Settings) => Promise<string | null>;
|
||||
};
|
||||
|
||||
// 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<string[]> {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user