@@ -59,6 +59,7 @@ import { calculateApiCost } from "../utils/cost"
5959import { fileExistsAtPath } from "../utils/fs"
6060import { arePathsEqual , getReadablePath } from "../utils/path"
6161import { parseMentions } from "./mentions"
62+ import { RooIgnoreController , LOCK_TEXT_SYMBOL } from "./ignore/RooIgnoreController"
6263import { AssistantMessageContent , parseAssistantMessage , ToolParamName , ToolUseName } from "./assistant-message"
6364import { formatResponse } from "./prompts/responses"
6465import { SYSTEM_PROMPT } from "./prompts/system"
@@ -118,6 +119,7 @@ export class Cline {
118119
119120 apiConversationHistory : ( Anthropic . MessageParam & { ts ?: number } ) [ ] = [ ]
120121 clineMessages : ClineMessage [ ] = [ ]
122+ rooIgnoreController ?: RooIgnoreController
121123 private askResponse ?: ClineAskResponse
122124 private askResponseText ?: string
123125 private askResponseImages ?: string [ ]
@@ -168,6 +170,11 @@ export class Cline {
168170 throw new Error ( "Either historyItem or task/images must be provided" )
169171 }
170172
173+ this . rooIgnoreController = new RooIgnoreController ( cwd )
174+ this . rooIgnoreController . initialize ( ) . catch ( ( error ) => {
175+ console . error ( "Failed to initialize RooIgnoreController:" , error )
176+ } )
177+
171178 this . taskId = historyItem ? historyItem . id : crypto . randomUUID ( )
172179 this . taskNumber = - 1
173180 this . apiConfiguration = apiConfiguration
@@ -893,6 +900,7 @@ export class Cline {
893900 this . terminalManager . disposeAll ( )
894901 this . urlContentFetcher . closeBrowser ( )
895902 this . browserSession . closeBrowser ( )
903+ this . rooIgnoreController ?. dispose ( )
896904
897905 // If we're not streaming then `abortStream` (which reverts the diff
898906 // view changes) won't be called, so we need to revert the changes here.
@@ -1044,6 +1052,8 @@ export class Cline {
10441052 } )
10451053 }
10461054
1055+ const rooIgnoreInstructions = this . rooIgnoreController ?. getInstructions ( )
1056+
10471057 const {
10481058 browserViewportSize,
10491059 mode,
@@ -1074,6 +1084,7 @@ export class Cline {
10741084 this . diffEnabled ,
10751085 experiments ,
10761086 enableMcpServerCreation ,
1087+ rooIgnoreInstructions ,
10771088 )
10781089 } ) ( )
10791090
@@ -1448,6 +1459,15 @@ export class Cline {
14481459 // wait so we can determine if it's a new file or editing an existing file
14491460 break
14501461 }
1462+
1463+ const accessAllowed = this . rooIgnoreController ?. validateAccess ( relPath )
1464+ if ( ! accessAllowed ) {
1465+ await this . say ( "rooignore_error" , relPath )
1466+ pushToolResult ( formatResponse . toolError ( formatResponse . rooIgnoreError ( relPath ) ) )
1467+
1468+ break
1469+ }
1470+
14511471 // Check if file exists using cached map or fs.access
14521472 let fileExists : boolean
14531473 if ( this . diffViewProvider . editType !== undefined ) {
@@ -1657,6 +1677,14 @@ export class Cline {
16571677 break
16581678 }
16591679
1680+ const accessAllowed = this . rooIgnoreController ?. validateAccess ( relPath )
1681+ if ( ! accessAllowed ) {
1682+ await this . say ( "rooignore_error" , relPath )
1683+ pushToolResult ( formatResponse . toolError ( formatResponse . rooIgnoreError ( relPath ) ) )
1684+
1685+ break
1686+ }
1687+
16601688 const absolutePath = path . resolve ( cwd , relPath )
16611689 const fileExists = await fileExistsAtPath ( absolutePath )
16621690
@@ -2115,6 +2143,15 @@ export class Cline {
21152143 pushToolResult ( await this . sayAndCreateMissingParamError ( "read_file" , "path" ) )
21162144 break
21172145 }
2146+
2147+ const accessAllowed = this . rooIgnoreController ?. validateAccess ( relPath )
2148+ if ( ! accessAllowed ) {
2149+ await this . say ( "rooignore_error" , relPath )
2150+ pushToolResult ( formatResponse . toolError ( formatResponse . rooIgnoreError ( relPath ) ) )
2151+
2152+ break
2153+ }
2154+
21182155 this . consecutiveMistakeCount = 0
21192156 const absolutePath = path . resolve ( cwd , relPath )
21202157 const completeMessage = JSON . stringify ( {
@@ -2160,7 +2197,12 @@ export class Cline {
21602197 this . consecutiveMistakeCount = 0
21612198 const absolutePath = path . resolve ( cwd , relDirPath )
21622199 const [ files , didHitLimit ] = await listFiles ( absolutePath , recursive , 200 )
2163- const result = formatResponse . formatFilesList ( absolutePath , files , didHitLimit )
2200+ const result = formatResponse . formatFilesList (
2201+ absolutePath ,
2202+ files ,
2203+ didHitLimit ,
2204+ this . rooIgnoreController ,
2205+ )
21642206 const completeMessage = JSON . stringify ( {
21652207 ...sharedMessageProps ,
21662208 content : result ,
@@ -2201,7 +2243,10 @@ export class Cline {
22012243 }
22022244 this . consecutiveMistakeCount = 0
22032245 const absolutePath = path . resolve ( cwd , relDirPath )
2204- const result = await parseSourceCodeForDefinitionsTopLevel ( absolutePath )
2246+ const result = await parseSourceCodeForDefinitionsTopLevel (
2247+ absolutePath ,
2248+ this . rooIgnoreController ,
2249+ )
22052250 const completeMessage = JSON . stringify ( {
22062251 ...sharedMessageProps ,
22072252 content : result ,
@@ -2249,7 +2294,13 @@ export class Cline {
22492294 }
22502295 this . consecutiveMistakeCount = 0
22512296 const absolutePath = path . resolve ( cwd , relDirPath )
2252- const results = await regexSearchFiles ( cwd , absolutePath , regex , filePattern )
2297+ const results = await regexSearchFiles (
2298+ cwd ,
2299+ absolutePath ,
2300+ regex ,
2301+ filePattern ,
2302+ this . rooIgnoreController ,
2303+ )
22532304 const completeMessage = JSON . stringify ( {
22542305 ...sharedMessageProps ,
22552306 content : results ,
@@ -2428,6 +2479,19 @@ export class Cline {
24282479 )
24292480 break
24302481 }
2482+
2483+ const ignoredFileAttemptedToAccess = this . rooIgnoreController ?. validateCommand ( command )
2484+ if ( ignoredFileAttemptedToAccess ) {
2485+ await this . say ( "rooignore_error" , ignoredFileAttemptedToAccess )
2486+ pushToolResult (
2487+ formatResponse . toolError (
2488+ formatResponse . rooIgnoreError ( ignoredFileAttemptedToAccess ) ,
2489+ ) ,
2490+ )
2491+
2492+ break
2493+ }
2494+
24312495 this . consecutiveMistakeCount = 0
24322496
24332497 const didApprove = await askApproval ( "command" , command )
@@ -3349,29 +3413,39 @@ export class Cline {
33493413
33503414 // It could be useful for cline to know if the user went from one or no file to another between messages, so we always include this context
33513415 details += "\n\n# VSCode Visible Files"
3352- const visibleFiles = vscode . window . visibleTextEditors
3416+ const visibleFilePaths = vscode . window . visibleTextEditors
33533417 ?. map ( ( editor ) => editor . document ?. uri ?. fsPath )
33543418 . filter ( Boolean )
3355- . map ( ( absolutePath ) => path . relative ( cwd , absolutePath ) . toPosix ( ) )
3356- . join ( "\n" )
3357- if ( visibleFiles ) {
3358- details += `\n${ visibleFiles } `
3419+ . map ( ( absolutePath ) => path . relative ( cwd , absolutePath ) )
3420+
3421+ // Filter paths through rooIgnoreController
3422+ const allowedVisibleFiles = this . rooIgnoreController
3423+ ? this . rooIgnoreController . filterPaths ( visibleFilePaths )
3424+ : visibleFilePaths . map ( ( p ) => p . toPosix ( ) ) . join ( "\n" )
3425+
3426+ if ( allowedVisibleFiles ) {
3427+ details += `\n${ allowedVisibleFiles } `
33593428 } else {
33603429 details += "\n(No visible files)"
33613430 }
33623431
33633432 details += "\n\n# VSCode Open Tabs"
33643433 const { maxOpenTabsContext } = ( await this . providerRef . deref ( ) ?. getState ( ) ) ?? { }
33653434 const maxTabs = maxOpenTabsContext ?? 20
3366- const openTabs = vscode . window . tabGroups . all
3435+ const openTabPaths = vscode . window . tabGroups . all
33673436 . flatMap ( ( group ) => group . tabs )
33683437 . map ( ( tab ) => ( tab . input as vscode . TabInputText ) ?. uri ?. fsPath )
33693438 . filter ( Boolean )
33703439 . map ( ( absolutePath ) => path . relative ( cwd , absolutePath ) . toPosix ( ) )
33713440 . slice ( 0 , maxTabs )
3372- . join ( "\n" )
3373- if ( openTabs ) {
3374- details += `\n${ openTabs } `
3441+
3442+ // Filter paths through rooIgnoreController
3443+ const allowedOpenTabs = this . rooIgnoreController
3444+ ? this . rooIgnoreController . filterPaths ( openTabPaths )
3445+ : openTabPaths . map ( ( p ) => p . toPosix ( ) ) . join ( "\n" )
3446+
3447+ if ( allowedOpenTabs ) {
3448+ details += `\n${ allowedOpenTabs } `
33753449 } else {
33763450 details += "\n(No open tabs)"
33773451 }
@@ -3530,7 +3604,7 @@ export class Cline {
35303604 details += "(Desktop files not shown automatically. Use list_files to explore if needed.)"
35313605 } else {
35323606 const [ files , didHitLimit ] = await listFiles ( cwd , true , 200 )
3533- const result = formatResponse . formatFilesList ( cwd , files , didHitLimit )
3607+ const result = formatResponse . formatFilesList ( cwd , files , didHitLimit , this . rooIgnoreController )
35343608 details += result
35353609 }
35363610 }
0 commit comments