From 8eb505fbba664d32c4f5ed94485cc219f2db3e20 Mon Sep 17 00:00:00 2001 From: "Anas H. Sulaiman" Date: Fri, 13 Jun 2025 20:25:59 -0400 Subject: [PATCH] initialize `FileDiscoveryService` once (#1029) --- packages/cli/src/config/config.test.ts | 12 +++++++----- packages/cli/src/config/config.ts | 9 +++++++++ packages/cli/src/ui/App.tsx | 1 + packages/core/src/config/config.ts | 2 ++ packages/core/src/utils/gitIgnoreParser.ts | 11 +++++++---- packages/core/src/utils/memoryDiscovery.test.ts | 14 +++++++++++++- packages/core/src/utils/memoryDiscovery.ts | 5 +++-- 7 files changed, 42 insertions(+), 12 deletions(-) diff --git a/packages/cli/src/config/config.test.ts b/packages/cli/src/config/config.test.ts index 313deedf..1d8c486a 100644 --- a/packages/cli/src/config/config.test.ts +++ b/packages/cli/src/config/config.test.ts @@ -33,11 +33,12 @@ vi.mock('@gemini-cli/core', async () => { return { ...actualServer, loadEnvironment: vi.fn(), - loadServerHierarchicalMemory: vi.fn((cwd, debug, extensionPaths) => - Promise.resolve({ - memoryContent: extensionPaths?.join(',') || '', - fileCount: extensionPaths?.length || 0, - }), + loadServerHierarchicalMemory: vi.fn( + (cwd, debug, fileService, extensionPaths) => + Promise.resolve({ + memoryContent: extensionPaths?.join(',') || '', + fileCount: extensionPaths?.length || 0, + }), ), }; }); @@ -239,6 +240,7 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => { expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith( expect.any(String), false, + expect.any(Object), [ '/path/to/ext1/GEMINI.md', '/path/to/ext3/context1.md', diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 9534f403..eef3c0f3 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -17,6 +17,7 @@ import { GEMINI_CONFIG_DIR as GEMINI_DIR, DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_EMBEDDING_MODEL, + FileDiscoveryService, } from '@gemini-cli/core'; import { Settings } from './settings.js'; import { getEffectiveModel } from '../utils/modelCheck.js'; @@ -114,6 +115,7 @@ async function parseArguments(): Promise { export async function loadHierarchicalGeminiMemory( currentWorkingDirectory: string, debugMode: boolean, + fileService: FileDiscoveryService, extensionContextFilePaths: string[] = [], ): Promise<{ memoryContent: string; fileCount: number }> { if (debugMode) { @@ -126,6 +128,7 @@ export async function loadHierarchicalGeminiMemory( return loadServerHierarchicalMemory( currentWorkingDirectory, debugMode, + fileService, extensionContextFilePaths, ); } @@ -154,10 +157,15 @@ export async function loadCliConfig( const extensionContextFilePaths = extensions.flatMap((e) => e.contextFiles); + const fileService = new FileDiscoveryService(process.cwd()); + await fileService.initialize({ + respectGitIgnore: settings.fileFiltering?.respectGitIgnore, + }); // Call the (now wrapper) loadHierarchicalGeminiMemory which calls the server's version const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory( process.cwd(), debugMode, + fileService, extensionContextFilePaths, ); @@ -201,6 +209,7 @@ export async function loadCliConfig( process.env.http_proxy, cwd: process.cwd(), telemetryOtlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT, + fileDiscoveryService: fileService, }); } diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index c022fb31..7d8ef463 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -139,6 +139,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory( process.cwd(), config.getDebugMode(), + await config.getFileService(), ); config.setUserMemory(memoryContent); config.setGeminiMdFileCount(fileCount); diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 4bc5d08b..ac0fabb0 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -86,6 +86,7 @@ export interface ConfigParameters { checkpoint?: boolean; proxy?: string; cwd: string; + fileDiscoveryService?: FileDiscoveryService; } export class Config { @@ -152,6 +153,7 @@ export class Config { this.checkpoint = params.checkpoint ?? false; this.proxy = params.proxy; this.cwd = params.cwd ?? process.cwd(); + this.fileDiscoveryService = params.fileDiscoveryService ?? null; if (params.contextFileName) { setGeminiMdFilename(params.contextFileName); diff --git a/packages/core/src/utils/gitIgnoreParser.ts b/packages/core/src/utils/gitIgnoreParser.ts index eeee9f48..16367a4a 100644 --- a/packages/core/src/utils/gitIgnoreParser.ts +++ b/packages/core/src/utils/gitIgnoreParser.ts @@ -47,14 +47,17 @@ export class GitIgnoreParser implements GitIgnoreFilter { } async loadPatterns(patternsFileName: string): Promise { - const content = await fs.readFile( - path.join(this.projectRoot, patternsFileName), - 'utf-8', - ); + const patternsFilePath = path.join(this.projectRoot, patternsFileName); + const content = await fs.readFile(patternsFilePath, 'utf-8'); const patterns = content .split('\n') .map((p) => p.trim()) .filter((p) => p !== '' && !p.startsWith('#')); + if (patterns.length > 0) { + console.log( + `Loaded ${patterns.length} patterns from ${patternsFilePath}`, + ); + } this.addPatterns(patterns); } diff --git a/packages/core/src/utils/memoryDiscovery.test.ts b/packages/core/src/utils/memoryDiscovery.test.ts index 05d274f5..1e38d972 100644 --- a/packages/core/src/utils/memoryDiscovery.test.ts +++ b/packages/core/src/utils/memoryDiscovery.test.ts @@ -17,6 +17,7 @@ import { getCurrentGeminiMdFilename, DEFAULT_CONTEXT_FILENAME, } from '../tools/memoryTool.js'; +import { FileDiscoveryService } from '../services/fileDiscoveryService.js'; const ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST = DEFAULT_CONTEXT_FILENAME; @@ -43,6 +44,7 @@ describe('loadServerHierarchicalMemory', () => { let GLOBAL_GEMINI_DIR: string; let GLOBAL_GEMINI_FILE: string; // Defined in beforeEach + const fileService = new FileDiscoveryService(PROJECT_ROOT); beforeEach(() => { vi.resetAllMocks(); // Set environment variables to indicate test environment @@ -69,6 +71,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); expect(memoryContent).toBe(''); expect(fileCount).toBe(0); @@ -95,6 +98,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); expect(memoryContent).toBe( @@ -125,6 +129,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); expect(memoryContent).toBe( @@ -167,6 +172,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); const expectedContent = `--- Context from: ${path.relative(CWD, projectRootCustomFile)} ---\nProject root custom memory\n--- End of Context from: ${path.relative(CWD, projectRootCustomFile)} ---\n\n` + @@ -231,6 +237,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); const expectedContent = `--- Context from: ${customFilename} ---\nCWD custom memory\n--- End of Context from: ${customFilename} ---\n\n` + @@ -277,6 +284,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); const expectedContent = `--- Context from: ${path.relative(CWD, projectRootGeminiFile)} ---\nProject root memory\n--- End of Context from: ${path.relative(CWD, projectRootGeminiFile)} ---\n\n` + @@ -345,6 +353,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); const expectedContent = `--- Context from: ${ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST} ---\nCWD memory\n--- End of Context from: ${ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST} ---\n\n` + @@ -438,6 +447,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); const relPathGlobal = path.relative(CWD, GLOBAL_GEMINI_FILE); @@ -520,6 +530,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, ); const expectedContent = `--- Context from: ${path.join('my_code', ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST)} ---\nMy code memory\n--- End of Context from: ${path.join('my_code', ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST)} ---`; @@ -556,7 +567,7 @@ describe('loadServerHierarchicalMemory', () => { }) as unknown as typeof fsPromises.readdir); mockFs.access.mockRejectedValue(new Error('not found')); - await loadServerHierarchicalMemory(CWD, true); + await loadServerHierarchicalMemory(CWD, true, fileService); expect(consoleDebugSpy).toHaveBeenCalledWith( expect.stringContaining('[DEBUG] [BfsFileSearch]'), @@ -583,6 +594,7 @@ describe('loadServerHierarchicalMemory', () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, + fileService, [extensionFilePath], ); diff --git a/packages/core/src/utils/memoryDiscovery.ts b/packages/core/src/utils/memoryDiscovery.ts index 66f7f5ac..47d9f9a1 100644 --- a/packages/core/src/utils/memoryDiscovery.ts +++ b/packages/core/src/utils/memoryDiscovery.ts @@ -82,6 +82,7 @@ async function getGeminiMdFilePathsInternal( currentWorkingDirectory: string, userHomePath: string, debugMode: boolean, + fileService: FileDiscoveryService, extensionContextFilePaths: string[] = [], ): Promise { const allPaths = new Set(); @@ -179,8 +180,6 @@ async function getGeminiMdFilePathsInternal( } upwardPaths.forEach((p) => allPaths.add(p)); - const fileService = new FileDiscoveryService(projectRoot || resolvedCwd); - await fileService.initialize(); const downwardPaths = await bfsFileSearch(resolvedCwd, { fileName: geminiMdFilename, maxDirs: MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY, @@ -272,6 +271,7 @@ function concatenateInstructions( export async function loadServerHierarchicalMemory( currentWorkingDirectory: string, debugMode: boolean, + fileService: FileDiscoveryService, extensionContextFilePaths: string[] = [], ): Promise<{ memoryContent: string; fileCount: number }> { if (debugMode) @@ -285,6 +285,7 @@ export async function loadServerHierarchicalMemory( currentWorkingDirectory, userHomePath, debugMode, + fileService, extensionContextFilePaths, ); if (filePaths.length === 0) {