mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 12:54:07 -07:00
chore: Extract '.gemini' to GEMINI_DIR constant (#10540)
Co-authored-by: Richie Foreman <richie.foreman@gmail.com>
This commit is contained in:
committed by
GitHub
parent
7beaa368a9
commit
518caae62e
@@ -19,23 +19,14 @@ import {
|
||||
} from 'node:fs/promises';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as os from 'node:os';
|
||||
|
||||
import {
|
||||
GEMINI_CONFIG_DIR,
|
||||
DEFAULT_CONTEXT_FILENAME,
|
||||
} from '../packages/core/src/tools/memoryTool.js';
|
||||
import { getGlobalMemoryFilePath } from '../packages/core/src/tools/memoryTool.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = join(__dirname, '..');
|
||||
const integrationTestsDir = join(rootDir, '.integration-tests');
|
||||
let runDir = ''; // Make runDir accessible in teardown
|
||||
|
||||
const memoryFilePath = join(
|
||||
os.homedir(),
|
||||
GEMINI_CONFIG_DIR,
|
||||
DEFAULT_CONTEXT_FILENAME,
|
||||
);
|
||||
const memoryFilePath = getGlobalMemoryFilePath();
|
||||
let originalMemoryContent: string | null = null;
|
||||
|
||||
export async function setup() {
|
||||
|
||||
@@ -15,6 +15,7 @@ import fs from 'node:fs';
|
||||
import * as pty from '@lydell/node-pty';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import * as os from 'node:os';
|
||||
import { GEMINI_DIR } from '../packages/core/src/utils/paths.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
@@ -244,7 +245,7 @@ export class TestRig {
|
||||
mkdirSync(this.testDir, { recursive: true });
|
||||
|
||||
// Create a settings file to point the CLI to the local collector
|
||||
const geminiDir = join(this.testDir, '.gemini');
|
||||
const geminiDir = join(this.testDir, GEMINI_DIR);
|
||||
mkdirSync(geminiDir, { recursive: true });
|
||||
// In sandbox mode, use an absolute path for telemetry inside the container
|
||||
// The container mounts the test directory at the same path as the host
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
FileDiscoveryService,
|
||||
ApprovalMode,
|
||||
loadServerHierarchicalMemory,
|
||||
GEMINI_CONFIG_DIR,
|
||||
GEMINI_DIR,
|
||||
DEFAULT_GEMINI_EMBEDDING_MODEL,
|
||||
DEFAULT_GEMINI_MODEL,
|
||||
type GeminiCLIExtension,
|
||||
@@ -176,7 +176,7 @@ function findEnvFile(startDir: string): string | null {
|
||||
let currentDir = path.resolve(startDir);
|
||||
while (true) {
|
||||
// prefer gemini-specific .env under GEMINI_DIR
|
||||
const geminiEnvPath = path.join(currentDir, GEMINI_CONFIG_DIR, '.env');
|
||||
const geminiEnvPath = path.join(currentDir, GEMINI_DIR, '.env');
|
||||
if (fs.existsSync(geminiEnvPath)) {
|
||||
return geminiEnvPath;
|
||||
}
|
||||
@@ -187,11 +187,7 @@ function findEnvFile(startDir: string): string | null {
|
||||
const parentDir = path.dirname(currentDir);
|
||||
if (parentDir === currentDir || !parentDir) {
|
||||
// check .env under home as fallback, again preferring gemini-specific .env
|
||||
const homeGeminiEnvPath = path.join(
|
||||
process.cwd(),
|
||||
GEMINI_CONFIG_DIR,
|
||||
'.env',
|
||||
);
|
||||
const homeGeminiEnvPath = path.join(process.cwd(), GEMINI_DIR, '.env');
|
||||
if (fs.existsSync(homeGeminiEnvPath)) {
|
||||
return homeGeminiEnvPath;
|
||||
}
|
||||
|
||||
@@ -6,17 +6,18 @@
|
||||
|
||||
// Copied exactly from packages/cli/src/config/extension.ts, last PR #1026
|
||||
|
||||
import type {
|
||||
MCPServerConfig,
|
||||
ExtensionInstallMetadata,
|
||||
GeminiCLIExtension,
|
||||
import {
|
||||
GEMINI_DIR,
|
||||
type MCPServerConfig,
|
||||
type ExtensionInstallMetadata,
|
||||
type GeminiCLIExtension,
|
||||
} from '@google/gemini-cli-core';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
export const EXTENSIONS_DIRECTORY_NAME = path.join('.gemini', 'extensions');
|
||||
export const EXTENSIONS_DIRECTORY_NAME = path.join(GEMINI_DIR, 'extensions');
|
||||
export const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json';
|
||||
export const INSTALL_METADATA_FILENAME = '.gemini-extension-install.json';
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import { homedir } from 'node:os';
|
||||
|
||||
import type { MCPServerConfig } from '@google/gemini-cli-core';
|
||||
import {
|
||||
GEMINI_DIR,
|
||||
getErrorMessage,
|
||||
type TelemetrySettings,
|
||||
} from '@google/gemini-cli-core';
|
||||
import stripJsonComments from 'strip-json-comments';
|
||||
|
||||
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 const USER_SETTINGS_PATH = path.join(USER_SETTINGS_DIR, 'settings.json');
|
||||
|
||||
// Reconcile with https://github.com/google-gemini/gemini-cli/blob/b09bc6656080d4d12e1d06734aae2ec33af5c1ed/packages/cli/src/config/settings.ts#L53
|
||||
@@ -76,7 +76,7 @@ export function loadSettings(workspaceDir: string): Settings {
|
||||
|
||||
const workspaceSettingsPath = path.join(
|
||||
workspaceDir,
|
||||
SETTINGS_DIRECTORY_NAME,
|
||||
GEMINI_DIR,
|
||||
'settings.json',
|
||||
);
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -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']) {
|
||||
|
||||
@@ -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]: {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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')>();
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import type { OAuthCredentials } from '../mcp/token-storage/types.js';
|
||||
import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import { promises as fs } from 'node:fs';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
const GEMINI_DIR = '.gemini';
|
||||
const KEYCHAIN_SERVICE_NAME = 'gemini-cli-oauth';
|
||||
const MAIN_ACCOUNT_KEY = 'main-account';
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import { AuthType } from '../core/contentGenerator.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import readline from 'node:readline';
|
||||
import { FORCE_ENCRYPTED_FILE_ENV_VAR } from '../mcp/token-storage/index.js';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
vi.mock('os', async (importOriginal) => {
|
||||
const os = await importOriginal<typeof import('os')>();
|
||||
@@ -182,7 +183,7 @@ describe('oauth2', () => {
|
||||
// Verify Google Account was cached
|
||||
const googleAccountPath = path.join(
|
||||
tempHomeDir,
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
'google_accounts.json',
|
||||
);
|
||||
expect(fs.existsSync(googleAccountPath)).toBe(true);
|
||||
@@ -290,7 +291,11 @@ describe('oauth2', () => {
|
||||
|
||||
it('should attempt to load cached credentials first', async () => {
|
||||
const cachedCreds = { refresh_token: 'cached-token' };
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(
|
||||
tempHomeDir,
|
||||
GEMINI_DIR,
|
||||
'oauth_creds.json',
|
||||
);
|
||||
await fs.promises.mkdir(path.dirname(credsPath), { recursive: true });
|
||||
await fs.promises.writeFile(credsPath, JSON.stringify(cachedCreds));
|
||||
|
||||
@@ -328,7 +333,11 @@ describe('oauth2', () => {
|
||||
|
||||
await getOauthClient(AuthType.CLOUD_SHELL, mockConfig);
|
||||
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(
|
||||
tempHomeDir,
|
||||
GEMINI_DIR,
|
||||
'oauth_creds.json',
|
||||
);
|
||||
expect(fs.existsSync(credsPath)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -355,7 +364,7 @@ describe('oauth2', () => {
|
||||
const defaultCreds = { refresh_token: 'default-cached-token' };
|
||||
const defaultCredsPath = path.join(
|
||||
tempHomeDir,
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
'oauth_creds.json',
|
||||
);
|
||||
await fs.promises.mkdir(path.dirname(defaultCredsPath), {
|
||||
@@ -463,7 +472,7 @@ describe('oauth2', () => {
|
||||
// Verify Google Account was cached
|
||||
const googleAccountPath = path.join(
|
||||
tempHomeDir,
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
'google_accounts.json',
|
||||
);
|
||||
const cachedContent = fs.readFileSync(googleAccountPath, 'utf-8');
|
||||
@@ -493,7 +502,11 @@ describe('oauth2', () => {
|
||||
|
||||
// Make it fall through to cached credentials path
|
||||
const cachedCreds = { refresh_token: 'cached-token' };
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(
|
||||
tempHomeDir,
|
||||
GEMINI_DIR,
|
||||
'oauth_creds.json',
|
||||
);
|
||||
await fs.promises.mkdir(path.dirname(credsPath), { recursive: true });
|
||||
await fs.promises.writeFile(credsPath, JSON.stringify(cachedCreds));
|
||||
|
||||
@@ -524,7 +537,11 @@ describe('oauth2', () => {
|
||||
|
||||
// Make it fall through to cached credentials path
|
||||
const cachedCreds = { refresh_token: 'cached-token' };
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(
|
||||
tempHomeDir,
|
||||
GEMINI_DIR,
|
||||
'oauth_creds.json',
|
||||
);
|
||||
await fs.promises.mkdir(path.dirname(credsPath), { recursive: true });
|
||||
await fs.promises.writeFile(credsPath, JSON.stringify(cachedCreds));
|
||||
|
||||
@@ -916,13 +933,17 @@ describe('oauth2', () => {
|
||||
describe('clearCachedCredentialFile', () => {
|
||||
it('should clear cached credentials and Google account', async () => {
|
||||
const cachedCreds = { refresh_token: 'test-token' };
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(
|
||||
tempHomeDir,
|
||||
GEMINI_DIR,
|
||||
'oauth_creds.json',
|
||||
);
|
||||
await fs.promises.mkdir(path.dirname(credsPath), { recursive: true });
|
||||
await fs.promises.writeFile(credsPath, JSON.stringify(cachedCreds));
|
||||
|
||||
const googleAccountPath = path.join(
|
||||
tempHomeDir,
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
'google_accounts.json',
|
||||
);
|
||||
const accountData = { active: 'test@example.com', old: [] };
|
||||
@@ -965,7 +986,11 @@ describe('oauth2', () => {
|
||||
);
|
||||
|
||||
// Pre-populate credentials to make getOauthClient resolve quickly
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(
|
||||
tempHomeDir,
|
||||
GEMINI_DIR,
|
||||
'oauth_creds.json',
|
||||
);
|
||||
await fs.promises.mkdir(path.dirname(credsPath), { recursive: true });
|
||||
await fs.promises.writeFile(
|
||||
credsPath,
|
||||
@@ -1104,7 +1129,7 @@ describe('oauth2', () => {
|
||||
expect(
|
||||
OAuthCredentialStorage.saveCredentials as Mock,
|
||||
).toHaveBeenCalledWith(mockTokens);
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(tempHomeDir, GEMINI_DIR, 'oauth_creds.json');
|
||||
expect(fs.existsSync(credsPath)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -1120,7 +1145,7 @@ describe('oauth2', () => {
|
||||
// Create a dummy unencrypted credential file.
|
||||
// If the logic is correct, this file should be ignored.
|
||||
const unencryptedCreds = { refresh_token: 'unencrypted-token' };
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(tempHomeDir, GEMINI_DIR, 'oauth_creds.json');
|
||||
await fs.promises.mkdir(path.dirname(credsPath), { recursive: true });
|
||||
await fs.promises.writeFile(credsPath, JSON.stringify(unencryptedCreds));
|
||||
|
||||
@@ -1150,7 +1175,7 @@ describe('oauth2', () => {
|
||||
);
|
||||
|
||||
// Create a dummy unencrypted credential file. It should not be deleted.
|
||||
const credsPath = path.join(tempHomeDir, '.gemini', 'oauth_creds.json');
|
||||
const credsPath = path.join(tempHomeDir, GEMINI_DIR, 'oauth_creds.json');
|
||||
await fs.promises.mkdir(path.dirname(credsPath), { recursive: true });
|
||||
await fs.promises.writeFile(credsPath, '{}');
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ vi.mock('../tools/memoryTool', () => ({
|
||||
setGeminiMdFilename: vi.fn(),
|
||||
getCurrentGeminiMdFilename: vi.fn(() => 'GEMINI.md'), // Mock the original filename
|
||||
DEFAULT_CONTEXT_FILENAME: 'GEMINI.md',
|
||||
GEMINI_CONFIG_DIR: '.gemini',
|
||||
GEMINI_DIR: '.gemini',
|
||||
}));
|
||||
|
||||
vi.mock('../core/contentGenerator.js');
|
||||
|
||||
@@ -17,10 +17,11 @@ vi.mock('fs', async (importOriginal) => {
|
||||
});
|
||||
|
||||
import { Storage } from './storage.js';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
describe('Storage – getGlobalSettingsPath', () => {
|
||||
it('returns path to ~/.gemini/settings.json', () => {
|
||||
const expected = path.join(os.homedir(), '.gemini', 'settings.json');
|
||||
const expected = path.join(os.homedir(), GEMINI_DIR, 'settings.json');
|
||||
expect(Storage.getGlobalSettingsPath()).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -30,31 +31,31 @@ describe('Storage – additional helpers', () => {
|
||||
const storage = new Storage(projectRoot);
|
||||
|
||||
it('getWorkspaceSettingsPath returns project/.gemini/settings.json', () => {
|
||||
const expected = path.join(projectRoot, '.gemini', 'settings.json');
|
||||
const expected = path.join(projectRoot, GEMINI_DIR, 'settings.json');
|
||||
expect(storage.getWorkspaceSettingsPath()).toBe(expected);
|
||||
});
|
||||
|
||||
it('getUserCommandsDir returns ~/.gemini/commands', () => {
|
||||
const expected = path.join(os.homedir(), '.gemini', 'commands');
|
||||
const expected = path.join(os.homedir(), GEMINI_DIR, 'commands');
|
||||
expect(Storage.getUserCommandsDir()).toBe(expected);
|
||||
});
|
||||
|
||||
it('getProjectCommandsDir returns project/.gemini/commands', () => {
|
||||
const expected = path.join(projectRoot, '.gemini', 'commands');
|
||||
const expected = path.join(projectRoot, GEMINI_DIR, 'commands');
|
||||
expect(storage.getProjectCommandsDir()).toBe(expected);
|
||||
});
|
||||
|
||||
it('getMcpOAuthTokensPath returns ~/.gemini/mcp-oauth-tokens.json', () => {
|
||||
const expected = path.join(
|
||||
os.homedir(),
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
'mcp-oauth-tokens.json',
|
||||
);
|
||||
expect(Storage.getMcpOAuthTokensPath()).toBe(expected);
|
||||
});
|
||||
|
||||
it('getGlobalBinDir returns ~/.gemini/tmp/bin', () => {
|
||||
const expected = path.join(os.homedir(), '.gemini', 'tmp', 'bin');
|
||||
const expected = path.join(os.homedir(), GEMINI_DIR, 'tmp', 'bin');
|
||||
expect(Storage.getGlobalBinDir()).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,8 +8,8 @@ import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import * as crypto from 'node:crypto';
|
||||
import * as fs from 'node:fs';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
export const GEMINI_DIR = '.gemini';
|
||||
export const GOOGLE_ACCOUNTS_FILENAME = 'google_accounts.json';
|
||||
export const OAUTH_FILE = 'oauth_creds.json';
|
||||
const TMP_DIR_NAME = 'tmp';
|
||||
@@ -25,7 +25,7 @@ export class Storage {
|
||||
static getGlobalGeminiDir(): string {
|
||||
const homeDir = os.homedir();
|
||||
if (!homeDir) {
|
||||
return path.join(os.tmpdir(), '.gemini');
|
||||
return path.join(os.tmpdir(), GEMINI_DIR);
|
||||
}
|
||||
return path.join(homeDir, GEMINI_DIR);
|
||||
}
|
||||
|
||||
@@ -27,20 +27,15 @@ import type { Content } from '@google/genai';
|
||||
|
||||
import crypto from 'node:crypto';
|
||||
import os from 'node:os';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
const GEMINI_DIR_NAME = '.gemini';
|
||||
const TMP_DIR_NAME = 'tmp';
|
||||
const LOG_FILE_NAME = 'logs.json';
|
||||
const CHECKPOINT_FILE_NAME = 'checkpoint.json';
|
||||
|
||||
const projectDir = process.cwd();
|
||||
const hash = crypto.createHash('sha256').update(projectDir).digest('hex');
|
||||
const TEST_GEMINI_DIR = path.join(
|
||||
os.homedir(),
|
||||
GEMINI_DIR_NAME,
|
||||
TMP_DIR_NAME,
|
||||
hash,
|
||||
);
|
||||
const TEST_GEMINI_DIR = path.join(os.homedir(), GEMINI_DIR, TMP_DIR_NAME, hash);
|
||||
|
||||
const TEST_LOG_FILE_PATH = path.join(TEST_GEMINI_DIR, LOG_FILE_NAME);
|
||||
const TEST_CHECKPOINT_FILE_PATH = path.join(
|
||||
|
||||
@@ -10,9 +10,9 @@ import { isGitRepository } from '../utils/gitUtils.js';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { GEMINI_CONFIG_DIR } from '../tools/memoryTool.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { CodebaseInvestigatorAgent } from '../agents/codebase-investigator.js';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
// Mock tool names if they are dynamically generated or complex
|
||||
vi.mock('../tools/ls', () => ({ LSTool: { Name: 'list_directory' } }));
|
||||
@@ -223,9 +223,7 @@ describe('Core System Prompt (prompts.ts)', () => {
|
||||
});
|
||||
|
||||
it('should read from default path when GEMINI_SYSTEM_MD is "true"', () => {
|
||||
const defaultPath = path.resolve(
|
||||
path.join(GEMINI_CONFIG_DIR, 'system.md'),
|
||||
);
|
||||
const defaultPath = path.resolve(path.join(GEMINI_DIR, 'system.md'));
|
||||
vi.stubEnv('GEMINI_SYSTEM_MD', 'true');
|
||||
vi.mocked(fs.existsSync).mockReturnValue(true);
|
||||
vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt');
|
||||
@@ -236,9 +234,7 @@ describe('Core System Prompt (prompts.ts)', () => {
|
||||
});
|
||||
|
||||
it('should read from default path when GEMINI_SYSTEM_MD is "1"', () => {
|
||||
const defaultPath = path.resolve(
|
||||
path.join(GEMINI_CONFIG_DIR, 'system.md'),
|
||||
);
|
||||
const defaultPath = path.resolve(path.join(GEMINI_DIR, 'system.md'));
|
||||
vi.stubEnv('GEMINI_SYSTEM_MD', '1');
|
||||
vi.mocked(fs.existsSync).mockReturnValue(true);
|
||||
vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt');
|
||||
@@ -291,9 +287,7 @@ describe('Core System Prompt (prompts.ts)', () => {
|
||||
});
|
||||
|
||||
it('should write to default path when GEMINI_WRITE_SYSTEM_MD is "true"', () => {
|
||||
const defaultPath = path.resolve(
|
||||
path.join(GEMINI_CONFIG_DIR, 'system.md'),
|
||||
);
|
||||
const defaultPath = path.resolve(path.join(GEMINI_DIR, 'system.md'));
|
||||
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', 'true');
|
||||
getCoreSystemPrompt(mockConfig);
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
@@ -303,9 +297,7 @@ describe('Core System Prompt (prompts.ts)', () => {
|
||||
});
|
||||
|
||||
it('should write to default path when GEMINI_WRITE_SYSTEM_MD is "1"', () => {
|
||||
const defaultPath = path.resolve(
|
||||
path.join(GEMINI_CONFIG_DIR, 'system.md'),
|
||||
);
|
||||
const defaultPath = path.resolve(path.join(GEMINI_DIR, 'system.md'));
|
||||
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', '1');
|
||||
getCoreSystemPrompt(mockConfig);
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
|
||||
@@ -17,9 +17,10 @@ import { ShellTool } from '../tools/shell.js';
|
||||
import { WRITE_FILE_TOOL_NAME } from '../tools/tool-names.js';
|
||||
import process from 'node:process';
|
||||
import { isGitRepository } from '../utils/gitUtils.js';
|
||||
import { MemoryTool, GEMINI_CONFIG_DIR } from '../tools/memoryTool.js';
|
||||
import { MemoryTool } from '../tools/memoryTool.js';
|
||||
import { CodebaseInvestigatorAgent } from '../agents/codebase-investigator.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
export function resolvePathFromEnv(envVar?: string): {
|
||||
isSwitch: boolean;
|
||||
@@ -78,7 +79,7 @@ export function getCoreSystemPrompt(
|
||||
// A flag to indicate whether the system prompt override is active.
|
||||
let systemMdEnabled = false;
|
||||
// The default path for the system prompt file. This can be overridden.
|
||||
let systemMdPath = path.resolve(path.join(GEMINI_CONFIG_DIR, 'system.md'));
|
||||
let systemMdPath = path.resolve(path.join(GEMINI_DIR, 'system.md'));
|
||||
// Resolve the environment variable to get either a path or a switch value.
|
||||
const systemMdResolution = resolvePathFromEnv(
|
||||
process.env['GEMINI_SYSTEM_MD'],
|
||||
|
||||
@@ -9,6 +9,7 @@ import { promises as fs } from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { FileTokenStorage } from './file-token-storage.js';
|
||||
import type { OAuthCredentials } from './types.js';
|
||||
import { GEMINI_DIR } from '../../utils/paths.js';
|
||||
|
||||
vi.mock('node:fs', () => ({
|
||||
promises: {
|
||||
@@ -135,7 +136,7 @@ describe('FileTokenStorage', () => {
|
||||
await storage.setCredentials(credentials);
|
||||
|
||||
expect(mockFs.mkdir).toHaveBeenCalledWith(
|
||||
path.join('/home/test', '.gemini'),
|
||||
path.join('/home/test', GEMINI_DIR),
|
||||
{ recursive: true, mode: 0o700 },
|
||||
);
|
||||
expect(mockFs.writeFile).toHaveBeenCalled();
|
||||
@@ -201,7 +202,7 @@ describe('FileTokenStorage', () => {
|
||||
await storage.deleteCredentials('test-server');
|
||||
|
||||
expect(mockFs.unlink).toHaveBeenCalledWith(
|
||||
path.join('/home/test', '.gemini', 'mcp-oauth-tokens-v2.json'),
|
||||
path.join('/home/test', GEMINI_DIR, 'mcp-oauth-tokens-v2.json'),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -282,7 +283,7 @@ describe('FileTokenStorage', () => {
|
||||
await storage.clearAll();
|
||||
|
||||
expect(mockFs.unlink).toHaveBeenCalledWith(
|
||||
path.join('/home/test', '.gemini', 'mcp-oauth-tokens-v2.json'),
|
||||
path.join('/home/test', GEMINI_DIR, 'mcp-oauth-tokens-v2.json'),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import * as os from 'node:os';
|
||||
import * as crypto from 'node:crypto';
|
||||
import { BaseTokenStorage } from './base-token-storage.js';
|
||||
import type { OAuthCredentials } from './types.js';
|
||||
import { GEMINI_DIR } from '../../utils/paths.js';
|
||||
|
||||
export class FileTokenStorage extends BaseTokenStorage {
|
||||
private readonly tokenFilePath: string;
|
||||
@@ -17,7 +18,7 @@ export class FileTokenStorage extends BaseTokenStorage {
|
||||
|
||||
constructor(serviceName: string) {
|
||||
super(serviceName);
|
||||
const configDir = path.join(os.homedir(), '.gemini');
|
||||
const configDir = path.join(os.homedir(), GEMINI_DIR);
|
||||
this.tokenFilePath = path.join(configDir, 'mcp-oauth-tokens-v2.json');
|
||||
this.encryptionKey = this.deriveEncryptionKey();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import { ToolConfirmationOutcome } from './tools.js';
|
||||
import { ToolErrorType } from './tool-error.js';
|
||||
import { GEMINI_DIR } from '../utils/paths.js';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock(import('node:fs/promises'), async (importOriginal) => {
|
||||
@@ -105,7 +106,7 @@ describe('MemoryTool', () => {
|
||||
beforeEach(() => {
|
||||
testFilePath = path.join(
|
||||
os.homedir(),
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
DEFAULT_CONTEXT_FILENAME,
|
||||
);
|
||||
});
|
||||
@@ -237,7 +238,7 @@ describe('MemoryTool', () => {
|
||||
// Use getCurrentGeminiMdFilename for the default expectation before any setGeminiMdFilename calls in a test
|
||||
const expectedFilePath = path.join(
|
||||
os.homedir(),
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
getCurrentGeminiMdFilename(), // This will be DEFAULT_CONTEXT_FILENAME unless changed by a test
|
||||
);
|
||||
|
||||
@@ -317,9 +318,11 @@ describe('MemoryTool', () => {
|
||||
expect(result).not.toBe(false);
|
||||
|
||||
if (result && result.type === 'edit') {
|
||||
const expectedPath = path.join('~', '.gemini', 'GEMINI.md');
|
||||
const expectedPath = path.join('~', GEMINI_DIR, 'GEMINI.md');
|
||||
expect(result.title).toBe(`Confirm Memory Save: ${expectedPath}`);
|
||||
expect(result.fileName).toContain(path.join('mock', 'home', '.gemini'));
|
||||
expect(result.fileName).toContain(
|
||||
path.join('mock', 'home', GEMINI_DIR),
|
||||
);
|
||||
expect(result.fileName).toContain('GEMINI.md');
|
||||
expect(result.fileDiff).toContain('Index: GEMINI.md');
|
||||
expect(result.fileDiff).toContain('+## Gemini Added Memories');
|
||||
@@ -334,7 +337,7 @@ describe('MemoryTool', () => {
|
||||
const params = { fact: 'Test fact' };
|
||||
const memoryFilePath = path.join(
|
||||
os.homedir(),
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
getCurrentGeminiMdFilename(),
|
||||
);
|
||||
|
||||
@@ -352,7 +355,7 @@ describe('MemoryTool', () => {
|
||||
const params = { fact: 'Test fact' };
|
||||
const memoryFilePath = path.join(
|
||||
os.homedir(),
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
getCurrentGeminiMdFilename(),
|
||||
);
|
||||
|
||||
@@ -378,7 +381,7 @@ describe('MemoryTool', () => {
|
||||
const params = { fact: 'Test fact' };
|
||||
const memoryFilePath = path.join(
|
||||
os.homedir(),
|
||||
'.gemini',
|
||||
GEMINI_DIR,
|
||||
getCurrentGeminiMdFilename(),
|
||||
);
|
||||
|
||||
@@ -415,7 +418,7 @@ describe('MemoryTool', () => {
|
||||
expect(result).not.toBe(false);
|
||||
|
||||
if (result && result.type === 'edit') {
|
||||
const expectedPath = path.join('~', '.gemini', 'GEMINI.md');
|
||||
const expectedPath = path.join('~', GEMINI_DIR, 'GEMINI.md');
|
||||
expect(result.title).toBe(`Confirm Memory Save: ${expectedPath}`);
|
||||
expect(result.fileDiff).toContain('Index: GEMINI.md');
|
||||
expect(result.fileDiff).toContain('+- New fact');
|
||||
|
||||
@@ -60,7 +60,6 @@ Do NOT use this tool:
|
||||
- \`fact\` (string, required): The specific fact or piece of information to remember. This should be a clear, self-contained statement. For example, if the user says "My favorite color is blue", the fact would be "My favorite color is blue".
|
||||
`;
|
||||
|
||||
export const GEMINI_CONFIG_DIR = '.gemini';
|
||||
export const DEFAULT_CONTEXT_FILENAME = 'GEMINI.md';
|
||||
export const MEMORY_SECTION_HEADER = '## Gemini Added Memories';
|
||||
|
||||
@@ -98,7 +97,7 @@ interface SaveMemoryParams {
|
||||
modified_content?: string;
|
||||
}
|
||||
|
||||
function getGlobalMemoryFilePath(): string {
|
||||
export function getGlobalMemoryFilePath(): string {
|
||||
return path.join(Storage.getGlobalGeminiDir(), getCurrentGeminiMdFilename());
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as os from 'node:os';
|
||||
import { getFolderStructure } from './getFolderStructure.js';
|
||||
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
||||
import * as path from 'node:path';
|
||||
import { GEMINI_DIR } from './paths.js';
|
||||
|
||||
describe('getFolderStructure', () => {
|
||||
let testRootDir: string;
|
||||
@@ -255,8 +256,8 @@ ${testRootDir}${path.sep}
|
||||
await createTestFile('file1.txt');
|
||||
await createTestFile('node_modules', 'some-package', 'index.js');
|
||||
await createTestFile('ignored.txt');
|
||||
await createTestFile('.gemini', 'config.yaml');
|
||||
await createTestFile('.gemini', 'logs.json');
|
||||
await createTestFile(GEMINI_DIR, 'config.yaml');
|
||||
await createTestFile(GEMINI_DIR, 'logs.json');
|
||||
|
||||
const fileService = new FileDiscoveryService(testRootDir);
|
||||
const structure = await getFolderStructure(testRootDir, {
|
||||
@@ -301,8 +302,8 @@ ${testRootDir}${path.sep}
|
||||
await createTestFile('file1.txt');
|
||||
await createTestFile('node_modules', 'some-package', 'index.js');
|
||||
await createTestFile('ignored.txt');
|
||||
await createTestFile('.gemini', 'config.yaml');
|
||||
await createTestFile('.gemini', 'logs.json');
|
||||
await createTestFile(GEMINI_DIR, 'config.yaml');
|
||||
await createTestFile(GEMINI_DIR, 'logs.json');
|
||||
|
||||
const fileService = new FileDiscoveryService(testRootDir);
|
||||
const structure = await getFolderStructure(testRootDir, {
|
||||
@@ -321,8 +322,8 @@ ${testRootDir}${path.sep}
|
||||
await createTestFile('file1.txt');
|
||||
await createTestFile('node_modules', 'some-package', 'index.js');
|
||||
await createTestFile('ignored.txt');
|
||||
await createTestFile('.gemini', 'config.yaml');
|
||||
await createTestFile('.gemini', 'logs.json');
|
||||
await createTestFile(GEMINI_DIR, 'config.yaml');
|
||||
await createTestFile(GEMINI_DIR, 'logs.json');
|
||||
|
||||
const fileService = new FileDiscoveryService(testRootDir);
|
||||
const structure = await getFolderStructure(testRootDir, {
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { GEMINI_DIR } from './paths.js';
|
||||
|
||||
vi.mock('node:fs', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('node:fs')>();
|
||||
@@ -41,7 +42,7 @@ describe('InstallationManager', () => {
|
||||
let tempHomeDir: string;
|
||||
let installationManager: InstallationManager;
|
||||
const installationIdFile = () =>
|
||||
path.join(tempHomeDir, '.gemini', 'installation_id');
|
||||
path.join(tempHomeDir, GEMINI_DIR, 'installation_id');
|
||||
|
||||
beforeEach(() => {
|
||||
tempHomeDir = fs.mkdtempSync(
|
||||
|
||||
@@ -10,6 +10,7 @@ import { UserAccountManager } from './userAccountManager.js';
|
||||
import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { GEMINI_DIR } from './paths.js';
|
||||
|
||||
vi.mock('os', async (importOriginal) => {
|
||||
const os = await importOriginal<typeof import('os')>();
|
||||
@@ -30,7 +31,7 @@ describe('UserAccountManager', () => {
|
||||
);
|
||||
(os.homedir as Mock).mockReturnValue(tempHomeDir);
|
||||
accountsFile = () =>
|
||||
path.join(tempHomeDir, '.gemini', 'google_accounts.json');
|
||||
path.join(tempHomeDir, GEMINI_DIR, 'google_accounts.json');
|
||||
userAccountManager = new UserAccountManager();
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import os from 'node:os';
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import dotenv from 'dotenv';
|
||||
import { GEMINI_DIR } from '@google/gemini-cli-core';
|
||||
|
||||
const argv = yargs(hideBin(process.argv)).option('q', {
|
||||
alias: 'quiet',
|
||||
@@ -35,7 +36,7 @@ const argv = yargs(hideBin(process.argv)).option('q', {
|
||||
let geminiSandbox = process.env.GEMINI_SANDBOX;
|
||||
|
||||
if (!geminiSandbox) {
|
||||
const userSettingsFile = join(os.homedir(), '.gemini', 'settings.json');
|
||||
const userSettingsFile = join(os.homedir(), GEMINI_DIR, 'settings.json');
|
||||
if (existsSync(userSettingsFile)) {
|
||||
const settings = JSON.parse(
|
||||
stripJsonComments(readFileSync(userSettingsFile, 'utf-8')),
|
||||
@@ -49,7 +50,7 @@ if (!geminiSandbox) {
|
||||
if (!geminiSandbox) {
|
||||
let currentDir = process.cwd();
|
||||
while (true) {
|
||||
const geminiEnv = join(currentDir, '.gemini', '.env');
|
||||
const geminiEnv = join(currentDir, GEMINI_DIR, '.env');
|
||||
const regularEnv = join(currentDir, '.env');
|
||||
if (existsSync(geminiEnv)) {
|
||||
dotenv.config({ path: geminiEnv, quiet: true });
|
||||
|
||||
@@ -9,20 +9,16 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
import { join } from 'node:path';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { GEMINI_DIR } from '@google/gemini-cli-core';
|
||||
|
||||
const projectRoot = join(import.meta.dirname, '..');
|
||||
|
||||
const SETTINGS_DIRECTORY_NAME = '.gemini';
|
||||
const USER_SETTINGS_DIR = join(
|
||||
process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH || '',
|
||||
SETTINGS_DIRECTORY_NAME,
|
||||
GEMINI_DIR,
|
||||
);
|
||||
const USER_SETTINGS_PATH = join(USER_SETTINGS_DIR, 'settings.json');
|
||||
const WORKSPACE_SETTINGS_PATH = join(
|
||||
projectRoot,
|
||||
SETTINGS_DIRECTORY_NAME,
|
||||
'settings.json',
|
||||
);
|
||||
const WORKSPACE_SETTINGS_PATH = join(projectRoot, GEMINI_DIR, 'settings.json');
|
||||
|
||||
let settingsTarget = undefined;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import os from 'node:os';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import crypto from 'node:crypto';
|
||||
import { GEMINI_DIR } from '@google/gemini-cli-core';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -24,9 +25,9 @@ const projectHash = crypto
|
||||
.digest('hex');
|
||||
|
||||
// User-level .gemini directory in home
|
||||
const USER_GEMINI_DIR = path.join(os.homedir(), '.gemini');
|
||||
const USER_GEMINI_DIR = path.join(os.homedir(), GEMINI_DIR);
|
||||
// Project-level .gemini directory in the workspace
|
||||
const WORKSPACE_GEMINI_DIR = path.join(projectRoot, '.gemini');
|
||||
const WORKSPACE_GEMINI_DIR = path.join(projectRoot, GEMINI_DIR);
|
||||
|
||||
// Telemetry artifacts are stored in a hashed directory under the user's ~/.gemini/tmp
|
||||
export const OTEL_DIR = path.join(USER_GEMINI_DIR, 'tmp', projectHash, 'otel');
|
||||
|
||||
Reference in New Issue
Block a user