chore: Extract '.gemini' to GEMINI_DIR constant (#10540)

Co-authored-by: Richie Foreman <richie.foreman@gmail.com>
This commit is contained in:
Dongin Kim(Terry)
2025-10-14 02:31:39 +09:00
committed by GitHub
parent 7beaa368a9
commit 518caae62e
36 changed files with 181 additions and 157 deletions

View File

@@ -32,7 +32,7 @@ vi.mock('@google/gemini-cli-core', () => ({
getWorkspaceSettingsPath: () => '/tmp/gemini/workspace-settings.json',
getProjectTempDir: () => '/test/home/.gemini/tmp/mocked_hash',
})),
GEMINI_CONFIG_DIR: '.gemini',
GEMINI_DIR: '.gemini',
getErrorMessage: (e: unknown) => (e instanceof Error ? e.message : String(e)),
}));
vi.mock('@modelcontextprotocol/sdk/client/index.js');

View File

@@ -11,6 +11,7 @@ import { removeCommand } from './remove.js';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
import { GEMINI_DIR } from '@google/gemini-cli-core';
vi.mock('fs/promises', () => ({
readFile: vi.fn(),
@@ -80,7 +81,7 @@ describe('mcp remove command', () => {
vi.restoreAllMocks();
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-remove-test-'));
settingsDir = path.join(tempDir, '.gemini');
settingsDir = path.join(tempDir, GEMINI_DIR);
settingsPath = path.join(settingsDir, 'settings.json');
fs.mkdirSync(settingsDir, { recursive: true });

View File

@@ -1171,7 +1171,10 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
// 3. Spies on console functions (for logger output) are correctly set up if needed.
// Example of a previously failing test structure:
it.skip('should correctly use mocked homedir for global path', async () => {
const MOCK_GEMINI_DIR_LOCAL = path.join('/mock/home/user', '.gemini');
const MOCK_GEMINI_DIR_LOCAL = path.join(
'/mock/home/user',
ServerConfig.GEMINI_DIR,
);
const MOCK_GLOBAL_PATH_LOCAL = path.join(
MOCK_GEMINI_DIR_LOCAL,
'GEMINI.md',

View File

@@ -9,7 +9,8 @@ import fs from 'node:fs';
import os from 'node:os';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { ExtensionEnablementManager, Override } from './extensionEnablement.js';
import type { GeminiCLIExtension } from '@google/gemini-cli-core';
import { GEMINI_DIR, type GeminiCLIExtension } from '@google/gemini-cli-core';
// Helper to create a temporary directory for testing
function createTestDir() {
@@ -27,7 +28,7 @@ let manager: ExtensionEnablementManager;
describe('ExtensionEnablementManager', () => {
beforeEach(() => {
testDir = createTestDir();
configDir = path.join(testDir.path, '.gemini');
configDir = path.join(testDir.path, GEMINI_DIR);
manager = new ExtensionEnablementManager(configDir);
});

View File

@@ -59,7 +59,6 @@ import {
USER_SETTINGS_PATH, // This IS the mocked path.
getSystemSettingsPath,
getSystemDefaultsPath,
SETTINGS_DIRECTORY_NAME, // This is from the original module, but used by the mock.
migrateSettingsToV1,
needsMigration,
type Settings,
@@ -70,10 +69,10 @@ import {
import { FatalConfigError, GEMINI_DIR } from '@google/gemini-cli-core';
const MOCK_WORKSPACE_DIR = '/mock/workspace';
// Use the (mocked) SETTINGS_DIRECTORY_NAME for consistency
// Use the (mocked) GEMINI_DIR for consistency
const MOCK_WORKSPACE_SETTINGS_PATH = pathActual.join(
MOCK_WORKSPACE_DIR,
SETTINGS_DIRECTORY_NAME,
GEMINI_DIR,
'settings.json',
);

View File

@@ -11,7 +11,7 @@ import * as dotenv from 'dotenv';
import process from 'node:process';
import {
FatalConfigError,
GEMINI_CONFIG_DIR as GEMINI_DIR,
GEMINI_DIR,
getErrorMessage,
Storage,
} from '@google/gemini-cli-core';
@@ -49,8 +49,6 @@ function getMergeStrategyForPath(path: string[]): MergeStrategy | undefined {
export type { Settings, MemoryImportFormat };
export const SETTINGS_DIRECTORY_NAME = '.gemini';
export const USER_SETTINGS_PATH = Storage.getGlobalSettingsPath();
export const USER_SETTINGS_DIR = path.dirname(USER_SETTINGS_PATH);
export const DEFAULT_EXCLUDED_ENV_VARS = ['DEBUG', 'DEBUG_MODE'];

View File

@@ -12,13 +12,13 @@ import {
getErrorMessage,
isWithinRoot,
ideContextStore,
GEMINI_DIR,
} from '@google/gemini-cli-core';
import type { Settings } from './settings.js';
import stripJsonComments from 'strip-json-comments';
export const TRUSTED_FOLDERS_FILENAME = 'trustedFolders.json';
export const SETTINGS_DIRECTORY_NAME = '.gemini';
export const USER_SETTINGS_DIR = path.join(homedir(), SETTINGS_DIRECTORY_NAME);
export const USER_SETTINGS_DIR = path.join(homedir(), GEMINI_DIR);
export function getTrustedFoldersPath(): string {
if (process.env['GEMINI_CLI_TRUSTED_FOLDERS_PATH']) {

View File

@@ -6,7 +6,7 @@
import * as path from 'node:path';
import type { Config } from '@google/gemini-cli-core';
import { Storage } from '@google/gemini-cli-core';
import { GEMINI_DIR, Storage } from '@google/gemini-cli-core';
import mock from 'mock-fs';
import { FileCommandLoader } from './FileCommandLoader.js';
import { assert, vi } from 'vitest';
@@ -529,7 +529,9 @@ describe('FileCommandLoader', () => {
).getProjectCommandsDir();
const extensionDir = path.join(
process.cwd(),
'.gemini/extensions/test-ext',
GEMINI_DIR,
'extensions',
'test-ext',
);
mock({
@@ -582,7 +584,9 @@ describe('FileCommandLoader', () => {
).getProjectCommandsDir();
const extensionDir = path.join(
process.cwd(),
'.gemini/extensions/test-ext',
GEMINI_DIR,
'extensions',
'test-ext',
);
mock({
@@ -678,11 +682,15 @@ describe('FileCommandLoader', () => {
it('only loads commands from active extensions', async () => {
const extensionDir1 = path.join(
process.cwd(),
'.gemini/extensions/active-ext',
GEMINI_DIR,
'extensions',
'active-ext',
);
const extensionDir2 = path.join(
process.cwd(),
'.gemini/extensions/inactive-ext',
GEMINI_DIR,
'extensions',
'inactive-ext',
);
mock({
@@ -737,7 +745,9 @@ describe('FileCommandLoader', () => {
it('handles missing extension commands directory gracefully', async () => {
const extensionDir = path.join(
process.cwd(),
'.gemini/extensions/no-commands',
GEMINI_DIR,
'extensions',
'no-commands',
);
mock({
@@ -769,7 +779,12 @@ describe('FileCommandLoader', () => {
});
it('handles nested command structure in extensions', async () => {
const extensionDir = path.join(process.cwd(), '.gemini/extensions/a');
const extensionDir = path.join(
process.cwd(),
GEMINI_DIR,
'extensions',
'a',
);
mock({
[extensionDir]: {

View File

@@ -11,7 +11,11 @@ import * as path from 'node:path';
import { restoreCommand } from './restoreCommand.js';
import { type CommandContext } from './types.js';
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
import type { Config, GitService } from '@google/gemini-cli-core';
import {
GEMINI_DIR,
type Config,
type GitService,
} from '@google/gemini-cli-core';
describe('restoreCommand', () => {
let mockContext: CommandContext;
@@ -26,7 +30,7 @@ describe('restoreCommand', () => {
testRootDir = await fs.mkdtemp(
path.join(os.tmpdir(), 'restore-command-test-'),
);
geminiTempDir = path.join(testRootDir, '.gemini');
geminiTempDir = path.join(testRootDir, GEMINI_DIR);
checkpointsDir = path.join(geminiTempDir, 'checkpoints');
// The command itself creates this, but for tests it's easier to have it ready.
// Some tests might remove it to test error paths.

View File

@@ -11,10 +11,11 @@ import { theme } from '../semantic-colors.js';
import { StreamingState } from '../types.js';
import { UpdateNotification } from './UpdateNotification.js';
import { GEMINI_DIR } from '@google/gemini-cli-core';
import { homedir } from 'node:os';
import path from 'node:path';
const settingsPath = path.join(homedir(), '.gemini', 'settings.json');
const settingsPath = path.join(homedir(), GEMINI_DIR, 'settings.json');
export const Notifications = () => {
const { startupWarnings } = useAppContext();

View File

@@ -19,6 +19,7 @@ vi.mock('../contexts/ConfigContext.js');
vi.mock('../contexts/UIStateContext.js');
vi.mock('@google/gemini-cli-core', () => ({
recordFlickerFrame: vi.fn(),
GEMINI_DIR: '.gemini',
}));
vi.mock('ink', async (importOriginal) => {
const original = await importOriginal<typeof import('ink')>();

View File

@@ -10,30 +10,34 @@ import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import * as os from 'node:os';
import * as crypto from 'node:crypto';
import { GEMINI_DIR } from '@google/gemini-cli-core';
vi.mock('fs/promises', () => ({
vi.mock('node:fs/promises', () => ({
readFile: vi.fn(),
writeFile: vi.fn(),
mkdir: vi.fn(),
}));
vi.mock('os');
vi.mock('crypto');
vi.mock('fs', async (importOriginal) => {
const actualFs = await importOriginal<typeof import('fs')>();
vi.mock('node:os');
vi.mock('node:crypto');
vi.mock('node:fs', async (importOriginal) => {
const actualFs = await importOriginal<typeof import('node:fs')>();
return {
...actualFs,
mkdirSync: vi.fn(),
};
});
vi.mock('@google/gemini-cli-core', () => {
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
const actual =
await importOriginal<typeof import('@google/gemini-cli-core')>();
const path = await import('node:path');
class Storage {
getProjectTempDir(): string {
return path.join('/test/home/', '.gemini', 'tmp', 'mocked_hash');
return path.join('/test/home/', actual.GEMINI_DIR, 'tmp', 'mocked_hash');
}
getHistoryFilePath(): string {
return path.join(
'/test/home/',
'.gemini',
actual.GEMINI_DIR,
'tmp',
'mocked_hash',
'shell_history',
@@ -41,6 +45,7 @@ vi.mock('@google/gemini-cli-core', () => {
}
}
return {
...actual,
isNodeError: (err: unknown): err is NodeJS.ErrnoException =>
typeof err === 'object' && err !== null && 'code' in err,
Storage,
@@ -53,7 +58,7 @@ const MOCKED_PROJECT_HASH = 'mocked_hash';
const MOCKED_HISTORY_DIR = path.join(
MOCKED_HOME_DIR,
'.gemini',
GEMINI_DIR,
'tmp',
MOCKED_PROJECT_HASH,
);

View File

@@ -11,13 +11,10 @@ import fs from 'node:fs';
import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { quote, parse } from 'shell-quote';
import {
USER_SETTINGS_DIR,
SETTINGS_DIRECTORY_NAME,
} from '../config/settings.js';
import { USER_SETTINGS_DIR } from '../config/settings.js';
import { promisify } from 'node:util';
import type { Config, SandboxConfig } from '@google/gemini-cli-core';
import { FatalSandboxError } from '@google/gemini-cli-core';
import { FatalSandboxError, GEMINI_DIR } from '@google/gemini-cli-core';
import { ConsolePatcher } from '../ui/utils/ConsolePatcher.js';
import { randomBytes } from 'node:crypto';
@@ -156,10 +153,7 @@ function entrypoint(workdir: string, cliArgs: string[]): string[] {
shellCmds.push(`export PYTHONPATH="$PYTHONPATH${pythonPathSuffix}";`);
}
const projectSandboxBashrc = path.join(
SETTINGS_DIRECTORY_NAME,
'sandbox.bashrc',
);
const projectSandboxBashrc = path.join(GEMINI_DIR, 'sandbox.bashrc');
if (fs.existsSync(projectSandboxBashrc)) {
shellCmds.push(`source ${getContainerPath(projectSandboxBashrc)};`);
}
@@ -211,10 +205,7 @@ export async function start_sandbox(
);
// if profile name is not recognized, then look for file under project settings directory
if (!BUILTIN_SEATBELT_PROFILES.includes(profile)) {
profileFile = path.join(
SETTINGS_DIRECTORY_NAME,
`sandbox-macos-${profile}.sb`,
);
profileFile = path.join(GEMINI_DIR, `sandbox-macos-${profile}.sb`);
}
if (!fs.existsSync(profileFile)) {
throw new FatalSandboxError(
@@ -359,7 +350,7 @@ export async function start_sandbox(
const gcPath = fs.realpathSync(process.argv[1]);
const projectSandboxDockerfile = path.join(
SETTINGS_DIRECTORY_NAME,
GEMINI_DIR,
'sandbox.Dockerfile',
);
const isCustomProjectSandbox = fs.existsSync(projectSandboxDockerfile);
@@ -383,7 +374,7 @@ export async function start_sandbox(
// if project folder has sandbox.Dockerfile under project settings folder, use that
let buildArgs = '';
const projectSandboxDockerfile = path.join(
SETTINGS_DIRECTORY_NAME,
GEMINI_DIR,
'sandbox.Dockerfile',
);
if (isCustomProjectSandbox) {
@@ -441,7 +432,7 @@ export async function start_sandbox(
// note user/home changes inside sandbox and we mount at BOTH paths for consistency
const userSettingsDirOnHost = USER_SETTINGS_DIR;
const userSettingsDirInSandbox = getContainerPath(
`/home/node/${SETTINGS_DIRECTORY_NAME}`,
`/home/node/${GEMINI_DIR}`,
);
if (!fs.existsSync(userSettingsDirOnHost)) {
fs.mkdirSync(userSettingsDirOnHost);
@@ -665,10 +656,7 @@ export async function start_sandbox(
?.toLowerCase()
.startsWith(workdir.toLowerCase())
) {
const sandboxVenvPath = path.resolve(
SETTINGS_DIRECTORY_NAME,
'sandbox.venv',
);
const sandboxVenvPath = path.resolve(GEMINI_DIR, 'sandbox.venv');
if (!fs.existsSync(sandboxVenvPath)) {
fs.mkdirSync(sandboxVenvPath, { recursive: true });
}