@@ -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"
@@ -107,6 +108,7 @@ export class Cline {
107108
108109 apiConversationHistory : ( Anthropic . MessageParam & { ts ?: number } ) [ ] = [ ]
109110 clineMessages : ClineMessage [ ] = [ ]
111+ rooIgnoreController ?: RooIgnoreController
110112 private askResponse ?: ClineAskResponse
111113 private askResponseText ?: string
112114 private askResponseImages ?: string [ ]
@@ -157,6 +159,11 @@ export class Cline {
157159 throw new Error ( "Either historyItem or task/images must be provided" )
158160 }
159161
162+ this . rooIgnoreController = new RooIgnoreController ( cwd )
163+ this . rooIgnoreController . initialize ( ) . catch ( ( error ) => {
164+ console . error ( "Failed to initialize RooIgnoreController:" , error )
165+ } )
166+
160167 this . taskId = historyItem ? historyItem . id : crypto . randomUUID ( )
161168
162169 this . apiConfiguration = apiConfiguration
@@ -802,6 +809,7 @@ export class Cline {
802809 this . terminalManager . disposeAll ( )
803810 this . urlContentFetcher . closeBrowser ( )
804811 this . browserSession . closeBrowser ( )
812+ this . rooIgnoreController ?. dispose ( )
805813
806814 // If we're not streaming then `abortStream` (which reverts the diff
807815 // view changes) won't be called, so we need to revert the changes here.
@@ -953,6 +961,8 @@ export class Cline {
953961 } )
954962 }
955963
964+ const rooIgnoreInstructions = this . rooIgnoreController ?. getInstructions ( )
965+
956966 const {
957967 browserViewportSize,
958968 mode,
@@ -983,6 +993,7 @@ export class Cline {
983993 this . diffEnabled ,
984994 experiments ,
985995 enableMcpServerCreation ,
996+ rooIgnoreInstructions ,
986997 )
987998 } ) ( )
988999
@@ -1357,6 +1368,15 @@ export class Cline {
13571368 // wait so we can determine if it's a new file or editing an existing file
13581369 break
13591370 }
1371+
1372+ const accessAllowed = this . rooIgnoreController ?. validateAccess ( relPath )
1373+ if ( ! accessAllowed ) {
1374+ await this . say ( "rooignore_error" , relPath )
1375+ pushToolResult ( formatResponse . toolError ( formatResponse . rooIgnoreError ( relPath ) ) )
1376+
1377+ break
1378+ }
1379+
13601380 // Check if file exists using cached map or fs.access
13611381 let fileExists : boolean
13621382 if ( this . diffViewProvider . editType !== undefined ) {
@@ -1566,6 +1586,14 @@ export class Cline {
15661586 break
15671587 }
15681588
1589+ const accessAllowed = this . rooIgnoreController ?. validateAccess ( relPath )
1590+ if ( ! accessAllowed ) {
1591+ await this . say ( "rooignore_error" , relPath )
1592+ pushToolResult ( formatResponse . toolError ( formatResponse . rooIgnoreError ( relPath ) ) )
1593+
1594+ break
1595+ }
1596+
15691597 const absolutePath = path . resolve ( cwd , relPath )
15701598 const fileExists = await fileExistsAtPath ( absolutePath )
15711599
@@ -1999,6 +2027,15 @@ export class Cline {
19992027 pushToolResult ( await this . sayAndCreateMissingParamError ( "read_file" , "path" ) )
20002028 break
20012029 }
2030+
2031+ const accessAllowed = this . rooIgnoreController ?. validateAccess ( relPath )
2032+ if ( ! accessAllowed ) {
2033+ await this . say ( "rooignore_error" , relPath )
2034+ pushToolResult ( formatResponse . toolError ( formatResponse . rooIgnoreError ( relPath ) ) )
2035+
2036+ break
2037+ }
2038+
20022039 this . consecutiveMistakeCount = 0
20032040 const absolutePath = path . resolve ( cwd , relPath )
20042041 const completeMessage = JSON . stringify ( {
@@ -2044,7 +2081,12 @@ export class Cline {
20442081 this . consecutiveMistakeCount = 0
20452082 const absolutePath = path . resolve ( cwd , relDirPath )
20462083 const [ files , didHitLimit ] = await listFiles ( absolutePath , recursive , 200 )
2047- const result = formatResponse . formatFilesList ( absolutePath , files , didHitLimit )
2084+ const result = formatResponse . formatFilesList (
2085+ absolutePath ,
2086+ files ,
2087+ didHitLimit ,
2088+ this . rooIgnoreController ,
2089+ )
20482090 const completeMessage = JSON . stringify ( {
20492091 ...sharedMessageProps ,
20502092 content : result ,
@@ -2085,7 +2127,10 @@ export class Cline {
20852127 }
20862128 this . consecutiveMistakeCount = 0
20872129 const absolutePath = path . resolve ( cwd , relDirPath )
2088- const result = await parseSourceCodeForDefinitionsTopLevel ( absolutePath )
2130+ const result = await parseSourceCodeForDefinitionsTopLevel (
2131+ absolutePath ,
2132+ this . rooIgnoreController ,
2133+ )
20892134 const completeMessage = JSON . stringify ( {
20902135 ...sharedMessageProps ,
20912136 content : result ,
@@ -2133,7 +2178,13 @@ export class Cline {
21332178 }
21342179 this . consecutiveMistakeCount = 0
21352180 const absolutePath = path . resolve ( cwd , relDirPath )
2136- const results = await regexSearchFiles ( cwd , absolutePath , regex , filePattern )
2181+ const results = await regexSearchFiles (
2182+ cwd ,
2183+ absolutePath ,
2184+ regex ,
2185+ filePattern ,
2186+ this . rooIgnoreController ,
2187+ )
21372188 const completeMessage = JSON . stringify ( {
21382189 ...sharedMessageProps ,
21392190 content : results ,
@@ -2312,6 +2363,19 @@ export class Cline {
23122363 )
23132364 break
23142365 }
2366+
2367+ const ignoredFileAttemptedToAccess = this . rooIgnoreController ?. validateCommand ( command )
2368+ if ( ignoredFileAttemptedToAccess ) {
2369+ await this . say ( "rooignore_error" , ignoredFileAttemptedToAccess )
2370+ pushToolResult (
2371+ formatResponse . toolError (
2372+ formatResponse . rooIgnoreError ( ignoredFileAttemptedToAccess ) ,
2373+ ) ,
2374+ )
2375+
2376+ break
2377+ }
2378+
23152379 this . consecutiveMistakeCount = 0
23162380
23172381 const didApprove = await askApproval ( "command" , command )
@@ -3172,29 +3236,39 @@ export class Cline {
31723236
31733237 // 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
31743238 details += "\n\n# VSCode Visible Files"
3175- const visibleFiles = vscode . window . visibleTextEditors
3239+ const visibleFilePaths = vscode . window . visibleTextEditors
31763240 ?. map ( ( editor ) => editor . document ?. uri ?. fsPath )
31773241 . filter ( Boolean )
3178- . map ( ( absolutePath ) => path . relative ( cwd , absolutePath ) . toPosix ( ) )
3179- . join ( "\n" )
3180- if ( visibleFiles ) {
3181- details += `\n${ visibleFiles } `
3242+ . map ( ( absolutePath ) => path . relative ( cwd , absolutePath ) )
3243+
3244+ // Filter paths through rooIgnoreController
3245+ const allowedVisibleFiles = this . rooIgnoreController
3246+ ? this . rooIgnoreController . filterPaths ( visibleFilePaths )
3247+ : visibleFilePaths . map ( ( p ) => p . toPosix ( ) ) . join ( "\n" )
3248+
3249+ if ( allowedVisibleFiles ) {
3250+ details += `\n${ allowedVisibleFiles } `
31823251 } else {
31833252 details += "\n(No visible files)"
31843253 }
31853254
31863255 details += "\n\n# VSCode Open Tabs"
31873256 const { maxOpenTabsContext } = ( await this . providerRef . deref ( ) ?. getState ( ) ) ?? { }
31883257 const maxTabs = maxOpenTabsContext ?? 20
3189- const openTabs = vscode . window . tabGroups . all
3258+ const openTabPaths = vscode . window . tabGroups . all
31903259 . flatMap ( ( group ) => group . tabs )
31913260 . map ( ( tab ) => ( tab . input as vscode . TabInputText ) ?. uri ?. fsPath )
31923261 . filter ( Boolean )
31933262 . map ( ( absolutePath ) => path . relative ( cwd , absolutePath ) . toPosix ( ) )
31943263 . slice ( 0 , maxTabs )
3195- . join ( "\n" )
3196- if ( openTabs ) {
3197- details += `\n${ openTabs } `
3264+
3265+ // Filter paths through rooIgnoreController
3266+ const allowedOpenTabs = this . rooIgnoreController
3267+ ? this . rooIgnoreController . filterPaths ( openTabPaths )
3268+ : openTabPaths . map ( ( p ) => p . toPosix ( ) ) . join ( "\n" )
3269+
3270+ if ( allowedOpenTabs ) {
3271+ details += `\n${ allowedOpenTabs } `
31983272 } else {
31993273 details += "\n(No open tabs)"
32003274 }
@@ -3353,7 +3427,7 @@ export class Cline {
33533427 details += "(Desktop files not shown automatically. Use list_files to explore if needed.)"
33543428 } else {
33553429 const [ files , didHitLimit ] = await listFiles ( cwd , true , 200 )
3356- const result = formatResponse . formatFilesList ( cwd , files , didHitLimit )
3430+ const result = formatResponse . formatFilesList ( cwd , files , didHitLimit , this . rooIgnoreController )
33573431 details += result
33583432 }
33593433 }
0 commit comments