diff --git a/src/core/ignore/ClineIgnoreController.ts b/src/core/ignore/ClineIgnoreController.ts index c1eb037d8d..0fb882e121 100644 --- a/src/core/ignore/ClineIgnoreController.ts +++ b/src/core/ignore/ClineIgnoreController.ts @@ -12,20 +12,13 @@ import * as vscode from "vscode" export class ClineIgnoreController { private cwd: string private ignoreInstance: Ignore - private fileWatcher: vscode.FileSystemWatcher | null private disposables: vscode.Disposable[] = [] - - /** - * Default patterns that are always ignored - */ - private static readonly DEFAULT_PATTERNS = [".clineignore"] + clineIgnoreExists: boolean constructor(cwd: string) { this.cwd = cwd this.ignoreInstance = ignore() - this.ignoreInstance.add(ClineIgnoreController.DEFAULT_PATTERNS) - this.fileWatcher = null - + this.clineIgnoreExists = false // Set up file watcher for .clineignore this.setupFileWatcher() } @@ -35,7 +28,7 @@ export class ClineIgnoreController { * Must be called after construction and before using the controller */ async initialize(): Promise { - await this.loadCustomPatterns() + await this.loadClineIgnore() } /** @@ -43,60 +36,56 @@ export class ClineIgnoreController { */ private setupFileWatcher(): void { const clineignorePattern = new vscode.RelativePattern(this.cwd, ".clineignore") - this.fileWatcher = vscode.workspace.createFileSystemWatcher(clineignorePattern) + const fileWatcher = vscode.workspace.createFileSystemWatcher(clineignorePattern) // Watch for changes and updates this.disposables.push( - this.fileWatcher.onDidChange(() => { - this.loadCustomPatterns().catch((error) => { - console.error("Failed to load updated .clineignore patterns:", error) - }) + fileWatcher.onDidChange(() => { + this.loadClineIgnore() }), - this.fileWatcher.onDidCreate(() => { - this.loadCustomPatterns().catch((error) => { - console.error("Failed to load new .clineignore patterns:", error) - }) + fileWatcher.onDidCreate(() => { + this.loadClineIgnore() }), - this.fileWatcher.onDidDelete(() => { - this.resetToDefaultPatterns() + fileWatcher.onDidDelete(() => { + this.loadClineIgnore() }), ) // Add fileWatcher itself to disposables - this.disposables.push(this.fileWatcher) + this.disposables.push(fileWatcher) } /** * Load custom patterns from .clineignore if it exists */ - private async loadCustomPatterns(): Promise { + private async loadClineIgnore(): Promise { try { + // Reset ignore instance to prevent duplicate patterns + this.ignoreInstance = ignore() const ignorePath = path.join(this.cwd, ".clineignore") if (await fileExistsAtPath(ignorePath)) { - // Reset ignore instance to prevent duplicate patterns - this.resetToDefaultPatterns() + this.clineIgnoreExists = true const content = await fs.readFile(ignorePath, "utf8") this.ignoreInstance.add(content) + } else { + this.clineIgnoreExists = false } } catch (error) { - // Continue with default patterns + // Should never happen: reading file failed even though it exists + console.error("Unexpected error loading .clineignore:", error) } } - /** - * Reset ignore patterns to defaults - */ - private resetToDefaultPatterns(): void { - this.ignoreInstance = ignore() - this.ignoreInstance.add(ClineIgnoreController.DEFAULT_PATTERNS) - } - /** * Check if a file should be accessible to the LLM * @param filePath - Path to check (relative to cwd) * @returns true if file is accessible, false if ignored */ validateAccess(filePath: string): boolean { + // Always allow access if .clineignore does not exist + if (!this.clineIgnoreExists) { + return true + } try { // Normalize path to be relative to cwd and use forward slashes const absolutePath = path.resolve(this.cwd, filePath) @@ -137,6 +126,5 @@ export class ClineIgnoreController { dispose(): void { this.disposables.forEach((d) => d.dispose()) this.disposables = [] - this.fileWatcher = null } } diff --git a/src/core/prompts/responses.ts b/src/core/prompts/responses.ts index 5cce47e9e4..090667d3ff 100644 --- a/src/core/prompts/responses.ts +++ b/src/core/prompts/responses.ts @@ -54,7 +54,7 @@ Otherwise, if you have not completed the task and do not need additional informa absolutePath: string, files: string[], didHitLimit: boolean, - clineIgnoreController: ClineIgnoreController, + clineIgnoreController?: ClineIgnoreController, ): string => { const sorted = files .map((file) => { @@ -87,7 +87,7 @@ Otherwise, if you have not completed the task and do not need additional informa return aParts.length - bParts.length }) - const accessControlledSortedFiles = clineIgnoreController + const clineIgnoreParsed = clineIgnoreController ? sorted.map((filePath) => { // path is relative to absolute path, not cwd // validateAccess expects either path relative to cwd or absolute path @@ -103,16 +103,13 @@ Otherwise, if you have not completed the task and do not need additional informa : sorted if (didHitLimit) { - return `${accessControlledSortedFiles.join( + return `${clineIgnoreParsed.join( "\n", )}\n\n(File list truncated. Use list_files on specific subdirectories if you need to explore further.)` - } else if ( - accessControlledSortedFiles.length === 0 || - (accessControlledSortedFiles.length === 1 && accessControlledSortedFiles[0] === "") - ) { + } else if (clineIgnoreParsed.length === 0 || (clineIgnoreParsed.length === 1 && clineIgnoreParsed[0] === "")) { return "No files found." } else { - return accessControlledSortedFiles.join("\n") + return clineIgnoreParsed.join("\n") } },