mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-15 06:12:50 -07:00
fix(core): handle EISDIR on virtual drives in memory discovery (#26985)
This commit is contained in:
@@ -46,6 +46,15 @@ import { Config, type GeminiCLIExtension } from '../config/config.js';
|
||||
import { Storage } from '../config/storage.js';
|
||||
import { SimpleExtensionLoader } from './extensionLoader.js';
|
||||
import { CoreEvent, coreEvents } from './events.js';
|
||||
import * as fs from 'node:fs';
|
||||
|
||||
vi.mock('node:fs', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('node:fs')>();
|
||||
return {
|
||||
...actual,
|
||||
realpathSync: vi.fn(actual.realpathSync),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('os', async (importOriginal) => {
|
||||
const actualOs = await importOriginal<typeof os>();
|
||||
@@ -743,6 +752,40 @@ included directory memory
|
||||
expect(result.filePaths).toContain(projectContextFile);
|
||||
});
|
||||
|
||||
it('should not crash when fs.realpathSync throws EISDIR on virtual drive roots', async () => {
|
||||
// Mock realpathSync to throw EISDIR for a specific path, simulating
|
||||
// the Windows virtual drive issue (#25216).
|
||||
vi.mocked(fs.realpathSync).mockImplementation((p: fs.PathLike) => {
|
||||
const pathStr = p.toString();
|
||||
if (pathStr.includes('virtual-drive')) {
|
||||
const error = new Error(
|
||||
"EISDIR: illegal operation on a directory, realpath 'A:\\a'",
|
||||
);
|
||||
|
||||
(error as NodeJS.ErrnoException).code = 'EISDIR';
|
||||
throw error;
|
||||
}
|
||||
// For other paths, we need to return something sensible.
|
||||
// Since it's a mock, we can just return the path string itself.
|
||||
return pathStr;
|
||||
});
|
||||
|
||||
const virtualDriveCwd = path.join(testRootDir, 'virtual-drive');
|
||||
await fsPromises.mkdir(virtualDriveCwd, { recursive: true });
|
||||
|
||||
// This should now succeed instead of throwing
|
||||
const result = await loadServerHierarchicalMemory(
|
||||
virtualDriveCwd,
|
||||
[],
|
||||
new FileDiscoveryService(projectRoot),
|
||||
new SimpleExtensionLoader([]),
|
||||
DEFAULT_FOLDER_TRUST,
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.fileCount).toBe(0);
|
||||
});
|
||||
|
||||
it('silently skips a GEMINI.md symlink that points to a directory', async () => {
|
||||
// Create a real directory elsewhere and symlink GEMINI.md to it.
|
||||
const realDir = await createEmptyDir(path.join(cwd, '.geminimd-target'));
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
isSubpath,
|
||||
normalizePath,
|
||||
toAbsolutePath,
|
||||
resolveToRealPath,
|
||||
} from './paths.js';
|
||||
import type { ExtensionLoader } from './extensionLoader.js';
|
||||
import { debugLogger } from './debugLogger.js';
|
||||
@@ -702,10 +703,8 @@ export async function loadServerHierarchicalMemory(
|
||||
boundaryMarkers: readonly string[] = ['.git'],
|
||||
): Promise<LoadServerHierarchicalMemoryResponse> {
|
||||
// FIX: Use real, canonical paths for a reliable comparison to handle symlinks.
|
||||
const realCwd = normalizePath(
|
||||
await fs.realpath(path.resolve(currentWorkingDirectory)),
|
||||
);
|
||||
const realHome = normalizePath(await fs.realpath(path.resolve(homedir())));
|
||||
const realCwd = normalizePath(resolveToRealPath(currentWorkingDirectory));
|
||||
const realHome = normalizePath(resolveToRealPath(homedir()));
|
||||
const isHomeDirectory = realCwd === realHome;
|
||||
|
||||
// If it is the home directory, pass an empty string to the core memory
|
||||
|
||||
Reference in New Issue
Block a user