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:
Br1an
2026-05-08 06:41:12 +08:00
committed by GitHub
parent 16e345831b
commit c52acebaa2
2 changed files with 45 additions and 8 deletions
@@ -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({
+10 -6
View File
@@ -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) {