@@ -22,9 +22,9 @@ use serde_json::{Map, Value};
2222
2323use crate :: sessions:: SessionMessageRecord ;
2424use crate :: sessions:: shared:: {
25- StoredCursor , TranscriptLocation , TranscriptLocationMetadataKeys , append_location_metadata ,
26- append_tool_calls_metadata , append_usage_metadata , content_storage_text_and_tools ,
27- path_belongs_to_project , title_from_messages,
25+ ProjectMembership , ProjectRootMatcherCache , StoredCursor , TranscriptLocation ,
26+ TranscriptLocationMetadataKeys , append_location_metadata , append_tool_calls_metadata ,
27+ append_usage_metadata , content_storage_text_and_tools , title_from_messages,
2828} ;
2929use crate :: sessions:: source:: {
3030 ParsedTranscript , SessionDraft , TranscriptSource , read_changed_with_companion,
@@ -46,6 +46,7 @@ pub struct ClineLikeSource {
4646 provider : & ' static str ,
4747 storage_roots : Vec < PathBuf > ,
4848 user_registered_roots : Option < Vec < PathBuf > > ,
49+ project_matchers : ProjectRootMatcherCache ,
4950}
5051
5152impl ClineLikeSource {
@@ -78,6 +79,7 @@ impl ClineLikeSource {
7879 . join( "User/globalStorage/saoudrizwan.claude-dev/tasks" ) ,
7980 ] ,
8081 user_registered_roots : None ,
82+ project_matchers : ProjectRootMatcherCache :: default ( ) ,
8183 }
8284 }
8385
@@ -89,6 +91,7 @@ impl ClineLikeSource {
8991 . join( "User/globalStorage/rooveterinaryinc.roo-cline/tasks" ) ,
9092 ] ,
9193 user_registered_roots : None ,
94+ project_matchers : ProjectRootMatcherCache :: default ( ) ,
9295 }
9396 }
9497
@@ -101,6 +104,7 @@ impl ClineLikeSource {
101104 home. join( ".kilocode/cli/global/tasks" ) ,
102105 ] ,
103106 user_registered_roots : None ,
107+ project_matchers : ProjectRootMatcherCache :: default ( ) ,
104108 }
105109 }
106110
@@ -137,15 +141,15 @@ impl TranscriptSource for ClineLikeSource {
137141 let metadata = read_task_metadata ( task_dir) ?;
138142 let location_cwd = if let Some ( roots) = & self . user_registered_roots {
139143 let paths = metadata_project_paths ( & metadata) ;
140- if paths
141- . iter ( )
142- . any ( |path| roots . iter ( ) . any ( |root| path_belongs_to_project ( path , root ) ) )
143- {
144+ if paths. iter ( ) . any ( |path| {
145+ self . project_matchers . membership_against_roots ( path , roots )
146+ != ProjectMembership :: NoMatch
147+ } ) {
144148 return None ;
145149 }
146150 paths. into_iter ( ) . next ( ) ?
147151 } else {
148- metadata_project_location ( & metadata, project_root) ?
152+ metadata_project_location ( & metadata, project_root, & self . project_matchers ) ?
149153 } ;
150154
151155 let document: Value = match serde_json:: from_str ( & changed. contents ) {
@@ -310,10 +314,24 @@ fn read_task_metadata(task_dir: &Path) -> Option<Value> {
310314 None
311315}
312316
313- fn metadata_project_location ( metadata : & Value , project_root : & Path ) -> Option < PathBuf > {
314- metadata_project_paths ( metadata)
315- . into_iter ( )
316- . find ( |path| path_belongs_to_project ( path, project_root) )
317+ fn metadata_project_location (
318+ metadata : & Value ,
319+ project_root : & Path ,
320+ project_matchers : & ProjectRootMatcherCache ,
321+ ) -> Option < PathBuf > {
322+ let mut matched = None ;
323+ for path in metadata_project_paths ( metadata) {
324+ match project_matchers. membership ( & path, project_root) {
325+ ProjectMembership :: Match => {
326+ if matched. is_none ( ) {
327+ matched = Some ( path) ;
328+ }
329+ }
330+ ProjectMembership :: NoMatch => { }
331+ ProjectMembership :: Unknown => return None ,
332+ }
333+ }
334+ matched
317335}
318336
319337fn metadata_project_paths ( value : & Value ) -> Vec < PathBuf > {
0 commit comments