diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 5b83218c14..f6ae751837 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -1601,6 +1601,7 @@ export class Cline { if (!accessAllowed) { await this.say("clineignore_error", relPath) pushToolResult(formatResponse.clineIgnoreError(relPath)) + await this.saveCheckpoint() break } @@ -1878,6 +1879,7 @@ export class Cline { if (!accessAllowed) { await this.say("clineignore_error", relPath) pushToolResult(formatResponse.clineIgnoreError(relPath)) + await this.saveCheckpoint() break } @@ -2333,6 +2335,14 @@ export class Cline { } this.consecutiveMistakeCount = 0 + const ignoredFileAttemptedToAccess = this.clineIgnoreController.validateCommand(command) + if (ignoredFileAttemptedToAccess) { + await this.say("clineignore_error", ignoredFileAttemptedToAccess) + pushToolResult(formatResponse.clineIgnoreError(ignoredFileAttemptedToAccess)) + await this.saveCheckpoint() + break + } + let didAutoApprove = false if (!requiresApproval && this.shouldAutoApproveTool(block.name)) { diff --git a/src/core/ignore/ClineIgnoreController.ts b/src/core/ignore/ClineIgnoreController.ts index 925dcd189a..d3637caa76 100644 --- a/src/core/ignore/ClineIgnoreController.ts +++ b/src/core/ignore/ClineIgnoreController.ts @@ -102,6 +102,62 @@ export class ClineIgnoreController { } } + /** + * Check if a terminal command should be allowed to execute based on file access patterns + * @param command - Terminal command to validate + * @returns path of file that is being accessed if it is being accessed, undefined if command is allowed + */ + validateCommand(command: string): string | undefined { + // Always allow if no .clineignore exists + if (!this.clineIgnoreContent) { + return undefined + } + + // Split command into parts and get the base command + const parts = command.trim().split(/\s+/) + const baseCommand = parts[0].toLowerCase() + + // Commands that read file contents + const fileReadingCommands = [ + // Unix commands + "cat", + "less", + "more", + "head", + "tail", + "grep", + "awk", + "sed", + // PowerShell commands and aliases + "get-content", + "gc", + "type", + "select-string", + "sls", + ] + + if (fileReadingCommands.includes(baseCommand)) { + // Check each argument that could be a file path + for (let i = 1; i < parts.length; i++) { + const arg = parts[i] + // Skip command flags/options (both Unix and PowerShell style) + if (arg.startsWith("-") || arg.startsWith("/")) { + continue + } + // Ignore PowerShell parameter names + if (arg.includes(":")) { + continue + } + // Validate file access + if (!this.validateAccess(arg)) { + return arg + } + } + } + + return undefined + } + /** * Filter an array of paths, removing those that should be ignored * @param paths - Array of paths to filter (relative to cwd)