diff --git a/src/core/ignore/RooIgnoreController.ts b/src/core/ignore/RooIgnoreController.ts index fda6c37175..90654983b9 100644 --- a/src/core/ignore/RooIgnoreController.ts +++ b/src/core/ignore/RooIgnoreController.ts @@ -60,7 +60,7 @@ export class RooIgnoreController { /** * Load custom patterns from .rooignore if it exists */ - private async loadRooIgnore(): Promise { + public async loadRooIgnore(): Promise { try { // Reset ignore instance to prevent duplicate patterns this.ignoreInstance = ignore() @@ -183,7 +183,7 @@ export class RooIgnoreController { * Clean up resources when the controller is no longer needed */ dispose(): void { - this.disposables.forEach((d) => d.dispose()) + this.disposables.forEach((d) => d?.dispose?.()) this.disposables = [] } diff --git a/src/services/code-index/__tests__/ignore-integration.spec.ts b/src/services/code-index/__tests__/ignore-integration.spec.ts new file mode 100644 index 0000000000..f63e0de4f2 --- /dev/null +++ b/src/services/code-index/__tests__/ignore-integration.spec.ts @@ -0,0 +1,492 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import { CodeIndexManager } from "../manager" +import { CodeIndexServiceFactory } from "../service-factory" +import type { MockedClass } from "vitest" +import fs from "fs/promises" +import path from "path" + +// Mock vscode module +vi.mock("vscode", () => ({ + workspace: { + workspaceFolders: [ + { + uri: { fsPath: "/test/workspace" }, + name: "test", + index: 0, + }, + ], + createFileSystemWatcher: vi.fn(() => ({ + onDidCreate: vi.fn(), + onDidChange: vi.fn(), + onDidDelete: vi.fn(), + dispose: vi.fn(), + })), + }, + RelativePattern: vi.fn().mockImplementation((base, pattern) => ({ + base, + pattern, + })), +})) + +// Mock path utilities +vi.mock("../../../utils/path", () => ({ + getWorkspacePath: vi.fn(() => "/test/workspace"), +})) + +// Mock fs operations +vi.mock("fs/promises") +const mockFs = fs as any + +// Mock file existence check +vi.mock("../../../utils/fs", () => ({ + fileExistsAtPath: vi.fn(), +})) + +// Mock glob utilities +vi.mock("../../glob/list-files", () => ({ + findGitignoreFiles: vi.fn(), +})) + +// Mock state manager +vi.mock("../state-manager", () => ({ + CodeIndexStateManager: vi.fn().mockImplementation(() => ({ + onProgressUpdate: vi.fn(), + getCurrentStatus: vi.fn(), + dispose: vi.fn(), + setSystemState: vi.fn(), + })), +})) + +// Mock telemetry +vi.mock("@roo-code/telemetry", () => ({ + TelemetryService: { + instance: { + captureEvent: vi.fn(), + }, + }, +})) + +// Mock service factory +vi.mock("../service-factory") +const MockedCodeIndexServiceFactory = CodeIndexServiceFactory as MockedClass + +describe("CodeIndexManager - Ignore Integration Tests", () => { + let mockContext: any + let manager: CodeIndexManager + + beforeEach(() => { + // Clear all instances before each test + CodeIndexManager.disposeAll() + + mockContext = { + subscriptions: [], + workspaceState: {} as any, + globalState: {} as any, + extensionUri: {} as any, + extensionPath: "/test/extension", + asAbsolutePath: vi.fn(), + storageUri: {} as any, + storagePath: "/test/storage", + globalStorageUri: {} as any, + globalStoragePath: "/test/global-storage", + logUri: {} as any, + logPath: "/test/log", + extensionMode: 3, // vscode.ExtensionMode.Test + secrets: {} as any, + environmentVariableCollection: {} as any, + extension: {} as any, + languageModelAccessInformation: {} as any, + } + + manager = CodeIndexManager.getInstance(mockContext)! + }) + + afterEach(() => { + CodeIndexManager.disposeAll() + vi.clearAllMocks() + }) + + describe("gitignore integration", () => { + it("should load and apply .gitignore patterns during service recreation", async () => { + // Mock .gitignore file discovery and content + const { findGitignoreFiles } = await import("../../glob/list-files") + const mockFindGitignoreFiles = findGitignoreFiles as any + mockFindGitignoreFiles.mockResolvedValue(["/test/workspace/.gitignore"]) + + // Mock .gitignore content + mockFs.readFile.mockResolvedValue("node_modules/\n*.log\n.env") + + // Mock config manager + const mockConfigManager = { + loadConfiguration: vi.fn().mockResolvedValue({ requiresRestart: false }), + isFeatureConfigured: true, + isFeatureEnabled: true, + getConfig: vi.fn().mockReturnValue({ + isConfigured: true, + embedderProvider: "openai", + modelId: "text-embedding-3-small", + openAiOptions: { openAiNativeApiKey: "test-key" }, + qdrantUrl: "http://localhost:6333", + qdrantApiKey: "test-key", + searchMinScore: 0.4, + }), + } + ;(manager as any)._configManager = mockConfigManager + + // Mock cache manager + const mockCacheManager = { + initialize: vi.fn(), + clearCacheFile: vi.fn(), + } + ;(manager as any)._cacheManager = mockCacheManager + + // Mock service factory + const mockServiceFactoryInstance = { + createServices: vi.fn().mockReturnValue({ + embedder: { embedderInfo: { name: "openai" } }, + vectorStore: {}, + scanner: {}, + fileWatcher: { + onDidStartBatchProcessing: vi.fn(), + onBatchProgressUpdate: vi.fn(), + watch: vi.fn(), + stopWatcher: vi.fn(), + dispose: vi.fn(), + }, + }), + validateEmbedder: vi.fn().mockResolvedValue({ valid: true }), + } + MockedCodeIndexServiceFactory.mockImplementation(() => mockServiceFactoryInstance as any) + + // Act - call _recreateServices which should load .gitignore + await (manager as any)._recreateServices() + + // Assert + expect(mockFindGitignoreFiles).toHaveBeenCalledWith("/test/workspace") + expect(mockFs.readFile).toHaveBeenCalledWith("/test/workspace/.gitignore", "utf8") + expect(mockServiceFactoryInstance.createServices).toHaveBeenCalled() + + // Verify that the ignore instance was passed to createServices with .gitignore patterns + const createServicesCall = mockServiceFactoryInstance.createServices.mock.calls[0] + const ignoreInstance = createServicesCall[2] // Third parameter is the ignore instance + + // Test that the ignore instance has the expected patterns + expect(ignoreInstance.ignores("node_modules/package.json")).toBe(true) + expect(ignoreInstance.ignores("debug.log")).toBe(true) + expect(ignoreInstance.ignores(".env")).toBe(true) + expect(ignoreInstance.ignores(".gitignore")).toBe(true) // Should always ignore .gitignore files + expect(ignoreInstance.ignores("src/main.ts")).toBe(false) + }) + + it("should handle missing .gitignore files gracefully", async () => { + // Mock no .gitignore files found + const { findGitignoreFiles } = await import("../../glob/list-files") + const mockFindGitignoreFiles = findGitignoreFiles as any + mockFindGitignoreFiles.mockResolvedValue([]) + + // Mock config manager + const mockConfigManager = { + loadConfiguration: vi.fn().mockResolvedValue({ requiresRestart: false }), + isFeatureConfigured: true, + isFeatureEnabled: true, + getConfig: vi.fn().mockReturnValue({ + isConfigured: true, + embedderProvider: "openai", + modelId: "text-embedding-3-small", + openAiOptions: { openAiNativeApiKey: "test-key" }, + qdrantUrl: "http://localhost:6333", + qdrantApiKey: "test-key", + searchMinScore: 0.4, + }), + } + ;(manager as any)._configManager = mockConfigManager + + // Mock cache manager + const mockCacheManager = { + initialize: vi.fn(), + clearCacheFile: vi.fn(), + } + ;(manager as any)._cacheManager = mockCacheManager + + // Mock service factory + const mockServiceFactoryInstance = { + createServices: vi.fn().mockReturnValue({ + embedder: { embedderInfo: { name: "openai" } }, + vectorStore: {}, + scanner: {}, + fileWatcher: { + onDidStartBatchProcessing: vi.fn(), + onBatchProgressUpdate: vi.fn(), + watch: vi.fn(), + stopWatcher: vi.fn(), + dispose: vi.fn(), + }, + }), + validateEmbedder: vi.fn().mockResolvedValue({ valid: true }), + } + MockedCodeIndexServiceFactory.mockImplementation(() => mockServiceFactoryInstance as any) + + // Act - should not throw even with no .gitignore files + await expect((manager as any)._recreateServices()).resolves.not.toThrow() + + // Assert + expect(mockFindGitignoreFiles).toHaveBeenCalledWith("/test/workspace") + expect(mockFs.readFile).not.toHaveBeenCalled() + expect(mockServiceFactoryInstance.createServices).toHaveBeenCalled() + + // Verify that an ignore instance was still created (even if empty) + const createServicesCall = mockServiceFactoryInstance.createServices.mock.calls[0] + const ignoreInstance = createServicesCall[2] + + // Should still ignore .gitignore files themselves + expect(ignoreInstance.ignores(".gitignore")).toBe(true) + expect(ignoreInstance.ignores("src/main.ts")).toBe(false) + }) + }) + + describe("rooignore integration", () => { + it("should preserve RooIgnoreController instance across service recreations", async () => { + // Mock file existence check + const { fileExistsAtPath } = await import("../../../utils/fs") + const mockFileExistsAtPath = fileExistsAtPath as any + mockFileExistsAtPath.mockResolvedValue(true) + + // Mock .rooignore content + mockFs.readFile.mockResolvedValue("*.secret\ntemp/") + + // Mock config manager + const mockConfigManager = { + loadConfiguration: vi.fn().mockResolvedValue({ requiresRestart: false }), + isFeatureConfigured: true, + isFeatureEnabled: true, + getConfig: vi.fn().mockReturnValue({ + isConfigured: true, + embedderProvider: "openai", + modelId: "text-embedding-3-small", + openAiOptions: { openAiNativeApiKey: "test-key" }, + qdrantUrl: "http://localhost:6333", + qdrantApiKey: "test-key", + searchMinScore: 0.4, + }), + } + ;(manager as any)._configManager = mockConfigManager + + // Mock cache manager + const mockCacheManager = { + initialize: vi.fn(), + clearCacheFile: vi.fn(), + } + ;(manager as any)._cacheManager = mockCacheManager + + // Mock .gitignore discovery + const { findGitignoreFiles } = await import("../../glob/list-files") + const mockFindGitignoreFiles = findGitignoreFiles as any + mockFindGitignoreFiles.mockResolvedValue([]) + + // Mock service factory + const mockServiceFactoryInstance = { + createServices: vi.fn().mockReturnValue({ + embedder: { embedderInfo: { name: "openai" } }, + vectorStore: {}, + scanner: {}, + fileWatcher: { + onDidStartBatchProcessing: vi.fn(), + onBatchProgressUpdate: vi.fn(), + watch: vi.fn(), + stopWatcher: vi.fn(), + dispose: vi.fn(), + }, + }), + validateEmbedder: vi.fn().mockResolvedValue({ valid: true }), + } + MockedCodeIndexServiceFactory.mockImplementation(() => mockServiceFactoryInstance as any) + + // Act - call _recreateServices twice to simulate "Clear Index Data" scenario + await (manager as any)._recreateServices() + const firstRooIgnoreController = (manager as any)._rooIgnoreController + + await (manager as any)._recreateServices() + const secondRooIgnoreController = (manager as any)._rooIgnoreController + + // Assert - should be the same instance (preserved across recreations) + expect(firstRooIgnoreController).toBe(secondRooIgnoreController) + expect(firstRooIgnoreController).toBeDefined() + + // Verify that loadRooIgnore was called on both recreations + expect(mockFileExistsAtPath).toHaveBeenCalledWith("/test/workspace/.rooignore") + expect(mockFs.readFile).toHaveBeenCalledWith("/test/workspace/.rooignore", "utf8") + + // Verify that the RooIgnoreController was passed to createServices + expect(mockServiceFactoryInstance.createServices).toHaveBeenCalledTimes(2) + const firstCall = mockServiceFactoryInstance.createServices.mock.calls[0] + const secondCall = mockServiceFactoryInstance.createServices.mock.calls[1] + + // Fourth parameter should be the RooIgnoreController + expect(firstCall[3]).toBe(firstRooIgnoreController) + expect(secondCall[3]).toBe(secondRooIgnoreController) + expect(firstCall[3]).toBe(secondCall[3]) // Same instance + }) + + it("should reload .rooignore patterns on each service recreation", async () => { + // Mock file existence check + const { fileExistsAtPath } = await import("../../../utils/fs") + const mockFileExistsAtPath = fileExistsAtPath as any + mockFileExistsAtPath.mockResolvedValue(true) + + // Mock .rooignore content + mockFs.readFile.mockResolvedValue("*.secret\ntemp/") + + // Create a spy on the RooIgnoreController's loadRooIgnore method + const mockLoadRooIgnore = vi.fn().mockResolvedValue(undefined) + + // Mock config manager + const mockConfigManager = { + loadConfiguration: vi.fn().mockResolvedValue({ requiresRestart: false }), + isFeatureConfigured: true, + isFeatureEnabled: true, + getConfig: vi.fn().mockReturnValue({ + isConfigured: true, + embedderProvider: "openai", + modelId: "text-embedding-3-small", + openAiOptions: { openAiNativeApiKey: "test-key" }, + qdrantUrl: "http://localhost:6333", + qdrantApiKey: "test-key", + searchMinScore: 0.4, + }), + } + ;(manager as any)._configManager = mockConfigManager + + // Mock cache manager + const mockCacheManager = { + initialize: vi.fn(), + clearCacheFile: vi.fn(), + } + ;(manager as any)._cacheManager = mockCacheManager + + // Mock .gitignore discovery + const { findGitignoreFiles } = await import("../../glob/list-files") + const mockFindGitignoreFiles = findGitignoreFiles as any + mockFindGitignoreFiles.mockResolvedValue([]) + + // Pre-set a mock RooIgnoreController to test reloading + ;(manager as any)._rooIgnoreController = { + loadRooIgnore: mockLoadRooIgnore, + dispose: vi.fn(), + } + + // Mock service factory + const mockServiceFactoryInstance = { + createServices: vi.fn().mockReturnValue({ + embedder: { embedderInfo: { name: "openai" } }, + vectorStore: {}, + scanner: {}, + fileWatcher: { + onDidStartBatchProcessing: vi.fn(), + onBatchProgressUpdate: vi.fn(), + watch: vi.fn(), + stopWatcher: vi.fn(), + dispose: vi.fn(), + }, + }), + validateEmbedder: vi.fn().mockResolvedValue({ valid: true }), + } + MockedCodeIndexServiceFactory.mockImplementation(() => mockServiceFactoryInstance as any) + + // Act - call _recreateServices + await (manager as any)._recreateServices() + + // Assert - loadRooIgnore should have been called to reload patterns + expect(mockLoadRooIgnore).toHaveBeenCalledTimes(1) + }) + }) + + describe("integration with service factory", () => { + it("should pass both gitignore and rooignore controllers to service factory", async () => { + // Mock .gitignore discovery + const { findGitignoreFiles } = await import("../../glob/list-files") + const mockFindGitignoreFiles = findGitignoreFiles as any + mockFindGitignoreFiles.mockResolvedValue(["/test/workspace/.gitignore"]) + + // Mock .gitignore content + mockFs.readFile.mockImplementation((filePath: string) => { + if (filePath === "/test/workspace/.gitignore") { + return Promise.resolve("node_modules/\n*.log") + } + if (filePath === "/test/workspace/.rooignore") { + return Promise.resolve("*.secret\ntemp/") + } + return Promise.reject(new Error("File not found")) + }) + + // Mock file existence for .rooignore + const { fileExistsAtPath } = await import("../../../utils/fs") + const mockFileExistsAtPath = fileExistsAtPath as any + mockFileExistsAtPath.mockResolvedValue(true) + + // Mock config manager + const mockConfigManager = { + loadConfiguration: vi.fn().mockResolvedValue({ requiresRestart: false }), + isFeatureConfigured: true, + isFeatureEnabled: true, + getConfig: vi.fn().mockReturnValue({ + isConfigured: true, + embedderProvider: "openai", + modelId: "text-embedding-3-small", + openAiOptions: { openAiNativeApiKey: "test-key" }, + qdrantUrl: "http://localhost:6333", + qdrantApiKey: "test-key", + searchMinScore: 0.4, + }), + } + ;(manager as any)._configManager = mockConfigManager + + // Mock cache manager + const mockCacheManager = { + initialize: vi.fn(), + clearCacheFile: vi.fn(), + } + ;(manager as any)._cacheManager = mockCacheManager + + // Mock service factory + const mockServiceFactoryInstance = { + createServices: vi.fn().mockReturnValue({ + embedder: { embedderInfo: { name: "openai" } }, + vectorStore: {}, + scanner: {}, + fileWatcher: { + onDidStartBatchProcessing: vi.fn(), + onBatchProgressUpdate: vi.fn(), + watch: vi.fn(), + stopWatcher: vi.fn(), + dispose: vi.fn(), + }, + }), + validateEmbedder: vi.fn().mockResolvedValue({ valid: true }), + } + MockedCodeIndexServiceFactory.mockImplementation(() => mockServiceFactoryInstance as any) + + // Act + await (manager as any)._recreateServices() + + // Assert + expect(mockServiceFactoryInstance.createServices).toHaveBeenCalledTimes(1) + const createServicesCall = mockServiceFactoryInstance.createServices.mock.calls[0] + + // Verify parameters: context, cacheManager, ignoreInstance, rooIgnoreController + expect(createServicesCall).toHaveLength(4) + expect(createServicesCall[0]).toBe(mockContext) // context + expect(createServicesCall[1]).toBe(mockCacheManager) // cacheManager + + // Third parameter should be ignore instance with .gitignore patterns + const ignoreInstance = createServicesCall[2] + expect(ignoreInstance.ignores("node_modules/package.json")).toBe(true) + expect(ignoreInstance.ignores("debug.log")).toBe(true) + expect(ignoreInstance.ignores(".gitignore")).toBe(true) + + // Fourth parameter should be RooIgnoreController + const rooIgnoreController = createServicesCall[3] + expect(rooIgnoreController).toBeDefined() + expect(rooIgnoreController).toBe((manager as any)._rooIgnoreController) + }) + }) +}) diff --git a/src/services/code-index/__tests__/manager.spec.ts b/src/services/code-index/__tests__/manager.spec.ts index 8c64c2fdc6..b86afc6a61 100644 --- a/src/services/code-index/__tests__/manager.spec.ts +++ b/src/services/code-index/__tests__/manager.spec.ts @@ -12,7 +12,17 @@ vi.mock("vscode", () => ({ index: 0, }, ], + createFileSystemWatcher: vi.fn(() => ({ + onDidCreate: vi.fn(), + onDidChange: vi.fn(), + onDidDelete: vi.fn(), + dispose: vi.fn(), + })), }, + RelativePattern: vi.fn().mockImplementation((base, pattern) => ({ + base, + pattern, + })), })) // Mock only the essential dependencies @@ -178,6 +188,10 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { // Simulate an initialized manager by setting the required properties ;(manager as any)._orchestrator = { stopWatcher: vi.fn() } ;(manager as any)._searchService = {} + ;(manager as any)._rooIgnoreController = { + dispose: vi.fn(), + loadRooIgnore: vi.fn().mockResolvedValue(undefined), + } // Verify manager is considered initialized expect(manager.isInitialized).toBe(true) diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index 18e0752c34..f84209c80d 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -12,9 +12,11 @@ import { CacheManager } from "./cache-manager" import fs from "fs/promises" import ignore from "ignore" import path from "path" +import { findGitignoreFiles } from "../glob/list-files" import { t } from "../../i18n" import { TelemetryService } from "@roo-code/telemetry" import { TelemetryEventName } from "@roo-code/types" +import { RooIgnoreController } from "../../core/ignore/RooIgnoreController" export class CodeIndexManager { // --- Singleton Implementation --- @@ -27,6 +29,7 @@ export class CodeIndexManager { private _orchestrator: CodeIndexOrchestrator | undefined private _searchService: CodeIndexSearchService | undefined private _cacheManager: CacheManager | undefined + private _rooIgnoreController: RooIgnoreController | undefined public static getInstance(context: vscode.ExtensionContext): CodeIndexManager | undefined { // Use first workspace folder consistently @@ -70,7 +73,13 @@ export class CodeIndexManager { } private assertInitialized() { - if (!this._configManager || !this._orchestrator || !this._searchService || !this._cacheManager) { + if ( + !this._configManager || + !this._orchestrator || + !this._searchService || + !this._cacheManager || + !this._rooIgnoreController + ) { throw new Error("CodeIndexManager not initialized. Call initialize() first.") } } @@ -100,6 +109,13 @@ export class CodeIndexManager { } } + /** + * Get the global RooIgnoreController instance + */ + public get rooIgnoreController(): RooIgnoreController | undefined { + return this._rooIgnoreController + } + /** * Initializes the manager with configuration and dependent services. * Must be called before using any other methods. @@ -186,6 +202,9 @@ export class CodeIndexManager { if (this._orchestrator) { this.stopWatcher() } + if (this._rooIgnoreController) { + this._rooIgnoreController.dispose() + } this._stateManager.dispose() } @@ -228,6 +247,7 @@ export class CodeIndexManager { // Clear existing services to ensure clean state this._orchestrator = undefined this._searchService = undefined + // Note: Keep _rooIgnoreController to preserve file watchers unless it doesn't exist // (Re)Initialize service factory this._serviceFactory = new CodeIndexServiceFactory( @@ -244,26 +264,41 @@ export class CodeIndexManager { return } - const ignorePath = path.join(workspacePath, ".gitignore") + // Load all .gitignore files from workspace root up to parent directories try { - const content = await fs.readFile(ignorePath, "utf8") - ignoreInstance.add(content) + const gitignoreFiles = await findGitignoreFiles(workspacePath) + for (const gitignoreFile of gitignoreFiles) { + try { + const content = await fs.readFile(gitignoreFile, "utf8") + ignoreInstance.add(content) + } catch (error) { + console.warn(`Failed to read .gitignore file at ${gitignoreFile}:`, error) + } + } + // Always ignore .gitignore files themselves ignoreInstance.add(".gitignore") } catch (error) { - // Should never happen: reading file failed even though it exists - console.error("Unexpected error loading .gitignore:", error) + console.error("Error finding .gitignore files:", error) TelemetryService.instance.captureEvent(TelemetryEventName.CODE_INDEX_ERROR, { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, - location: "_recreateServices", + location: "_recreateServices.gitignore", }) } + // Initialize or reuse RooIgnoreController with file watchers + if (!this._rooIgnoreController) { + this._rooIgnoreController = new RooIgnoreController(workspacePath) + } + // Always reload .rooignore patterns to ensure they're up to date + await this._rooIgnoreController.loadRooIgnore() + // (Re)Create shared service instances const { embedder, vectorStore, scanner, fileWatcher } = this._serviceFactory.createServices( this.context, this._cacheManager!, ignoreInstance, + this._rooIgnoreController, ) // Validate embedder configuration before proceeding diff --git a/src/services/code-index/processors/scanner.ts b/src/services/code-index/processors/scanner.ts index 538a1252d7..508a9b42a6 100644 --- a/src/services/code-index/processors/scanner.ts +++ b/src/services/code-index/processors/scanner.ts @@ -36,6 +36,7 @@ export class DirectoryScanner implements IDirectoryScanner { private readonly codeParser: ICodeParser, private readonly cacheManager: CacheManager, private readonly ignoreInstance: Ignore, + private readonly rooIgnoreController?: RooIgnoreController, ) {} /** @@ -62,10 +63,15 @@ export class DirectoryScanner implements IDirectoryScanner { // Filter out directories (marked with trailing '/') const filePaths = allPaths.filter((p) => !p.endsWith("/")) - // Initialize RooIgnoreController if not provided - const ignoreController = new RooIgnoreController(directoryPath) - - await ignoreController.initialize() + // Use injected RooIgnoreController or create a fallback + let ignoreController: RooIgnoreController + if (this.rooIgnoreController) { + ignoreController = this.rooIgnoreController + } else { + // Fallback for backward compatibility + ignoreController = new RooIgnoreController(directoryPath) + await ignoreController.initialize() + } // Filter paths using .rooignore const allowedPaths = ignoreController.filterPaths(filePaths) diff --git a/src/services/code-index/service-factory.ts b/src/services/code-index/service-factory.ts index a741aaf72a..256c9db66b 100644 --- a/src/services/code-index/service-factory.ts +++ b/src/services/code-index/service-factory.ts @@ -10,6 +10,7 @@ import { ICodeParser, IEmbedder, IFileWatcher, IVectorStore } from "./interfaces import { CodeIndexConfigManager } from "./config-manager" import { CacheManager } from "./cache-manager" import { Ignore } from "ignore" +import { RooIgnoreController } from "../../core/ignore/RooIgnoreController" import { t } from "../../i18n" import { TelemetryService } from "@roo-code/telemetry" import { TelemetryEventName } from "@roo-code/types" @@ -145,8 +146,16 @@ export class CodeIndexServiceFactory { vectorStore: IVectorStore, parser: ICodeParser, ignoreInstance: Ignore, + rooIgnoreController?: RooIgnoreController, ): DirectoryScanner { - return new DirectoryScanner(embedder, vectorStore, parser, this.cacheManager, ignoreInstance) + return new DirectoryScanner( + embedder, + vectorStore, + parser, + this.cacheManager, + ignoreInstance, + rooIgnoreController, + ) } /** @@ -158,8 +167,17 @@ export class CodeIndexServiceFactory { vectorStore: IVectorStore, cacheManager: CacheManager, ignoreInstance: Ignore, + rooIgnoreController?: RooIgnoreController, ): IFileWatcher { - return new FileWatcher(this.workspacePath, context, cacheManager, embedder, vectorStore, ignoreInstance) + return new FileWatcher( + this.workspacePath, + context, + cacheManager, + embedder, + vectorStore, + ignoreInstance, + rooIgnoreController, + ) } /** @@ -170,6 +188,7 @@ export class CodeIndexServiceFactory { context: vscode.ExtensionContext, cacheManager: CacheManager, ignoreInstance: Ignore, + rooIgnoreController?: RooIgnoreController, ): { embedder: IEmbedder vectorStore: IVectorStore @@ -184,8 +203,15 @@ export class CodeIndexServiceFactory { const embedder = this.createEmbedder() const vectorStore = this.createVectorStore() const parser = codeParser - const scanner = this.createDirectoryScanner(embedder, vectorStore, parser, ignoreInstance) - const fileWatcher = this.createFileWatcher(context, embedder, vectorStore, cacheManager, ignoreInstance) + const scanner = this.createDirectoryScanner(embedder, vectorStore, parser, ignoreInstance, rooIgnoreController) + const fileWatcher = this.createFileWatcher( + context, + embedder, + vectorStore, + cacheManager, + ignoreInstance, + rooIgnoreController, + ) return { embedder, diff --git a/src/services/glob/list-files.ts b/src/services/glob/list-files.ts index 3164ed1eb0..dee99780d4 100644 --- a/src/services/glob/list-files.ts +++ b/src/services/glob/list-files.ts @@ -184,7 +184,7 @@ async function createIgnoreInstance(dirPath: string): Promise { +export async function findGitignoreFiles(startPath: string): Promise { const gitignoreFiles: string[] = [] let currentPath = startPath @@ -312,7 +312,6 @@ function isDirectoryExplicitlyIgnored(dirName: string): boolean { return false } - /** * Combine file and directory results and format them properly */