mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
fix: prevent false command conflicts when launching from home directory (#23069)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
This commit is contained in:
@@ -6,7 +6,12 @@
|
||||
|
||||
import * as glob from 'glob';
|
||||
import * as path from 'node:path';
|
||||
import { GEMINI_DIR, Storage, type Config } from '@google/gemini-cli-core';
|
||||
import {
|
||||
GEMINI_DIR,
|
||||
Storage,
|
||||
type Config,
|
||||
homedir,
|
||||
} from '@google/gemini-cli-core';
|
||||
import mock from 'mock-fs';
|
||||
import { FileCommandLoader } from './FileCommandLoader.js';
|
||||
import { assert, vi } from 'vitest';
|
||||
@@ -21,7 +26,7 @@ import {
|
||||
ShellProcessor,
|
||||
} from './prompt-processors/shellProcessor.js';
|
||||
import { DefaultArgumentProcessor } from './prompt-processors/argumentProcessor.js';
|
||||
import type { CommandContext } from '../ui/commands/types.js';
|
||||
import { CommandKind, type CommandContext } from '../ui/commands/types.js';
|
||||
import { AtFileProcessor } from './prompt-processors/atFileProcessor.js';
|
||||
|
||||
const mockShellProcess = vi.hoisted(() => vi.fn());
|
||||
@@ -315,6 +320,34 @@ describe('FileCommandLoader', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('does not duplicate commands when project root is the home directory', async () => {
|
||||
const homeDir = homedir();
|
||||
const userCommandsDir = Storage.getUserCommandsDir();
|
||||
mock({
|
||||
[userCommandsDir]: {
|
||||
'test.toml': 'prompt = "User prompt"',
|
||||
'another.toml': 'prompt = "Another prompt"',
|
||||
},
|
||||
});
|
||||
|
||||
const mockConfig = {
|
||||
getProjectRoot: vi.fn(() => homeDir),
|
||||
getExtensions: vi.fn(() => []),
|
||||
getFolderTrust: vi.fn(() => false),
|
||||
isTrustedFolder: vi.fn(() => false),
|
||||
} as unknown as Config;
|
||||
const loader = new FileCommandLoader(mockConfig);
|
||||
const commands = await loader.loadCommands(signal);
|
||||
|
||||
// Should load each command only once (as user commands), not twice
|
||||
expect(commands).toHaveLength(2);
|
||||
const names = commands.map((c) => c.name);
|
||||
expect(names).toContain('test');
|
||||
expect(names).toContain('another');
|
||||
// Verify they are loaded as user commands, not duplicated as workspace commands
|
||||
expect(commands.every((c) => c.kind === CommandKind.USER_FILE)).toBe(true);
|
||||
});
|
||||
|
||||
it('ignores files with TOML syntax errors', async () => {
|
||||
const userCommandsDir = Storage.getUserCommandsDir();
|
||||
mock({
|
||||
|
||||
@@ -212,16 +212,20 @@ export class FileCommandLoader implements ICommandLoader {
|
||||
const storage = this.config?.storage ?? new Storage(this.projectRoot);
|
||||
|
||||
// 1. User commands
|
||||
const userCommandsDir = Storage.getUserCommandsDir();
|
||||
dirs.push({
|
||||
path: Storage.getUserCommandsDir(),
|
||||
path: userCommandsDir,
|
||||
kind: CommandKind.USER_FILE,
|
||||
});
|
||||
|
||||
// 2. Project commands
|
||||
dirs.push({
|
||||
path: storage.getProjectCommandsDir(),
|
||||
kind: CommandKind.WORKSPACE_FILE,
|
||||
});
|
||||
// 2. Project commands (skip if same directory as user commands, e.g. when
|
||||
// cwd is the user's home directory, to avoid false conflict warnings)
|
||||
if (!storage.isWorkspaceHomeDir()) {
|
||||
dirs.push({
|
||||
path: storage.getProjectCommandsDir(),
|
||||
kind: CommandKind.WORKSPACE_FILE,
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Extension commands (processed last to detect all conflicts)
|
||||
if (this.config) {
|
||||
|
||||
Reference in New Issue
Block a user