@@ -121,15 +121,19 @@ fn append_omp_profile_roots(roots: &mut Vec<PathBuf>, profiles_dir: &Path, xdg:
121121 let Ok ( entries) = fs:: read_dir ( profiles_dir) else {
122122 return ;
123123 } ;
124- for entry in entries. flatten ( ) {
125- if entry. file_type ( ) . is_ok_and ( |kind| kind. is_dir ( ) ) {
126- roots. push ( if xdg {
124+ let mut discovered = entries
125+ . flatten ( )
126+ . filter ( |entry| entry. file_type ( ) . is_ok_and ( |kind| kind. is_dir ( ) ) )
127+ . map ( |entry| {
128+ if xdg {
127129 entry. path ( ) . join ( "sessions" )
128130 } else {
129131 entry. path ( ) . join ( "agent/sessions" )
130- } ) ;
131- }
132- }
132+ }
133+ } )
134+ . collect :: < Vec < _ > > ( ) ;
135+ discovered. sort ( ) ;
136+ roots. extend ( discovered) ;
133137}
134138
135139fn pi_compatible_session_roots ( ) -> Vec < PathBuf > {
@@ -181,18 +185,42 @@ fn pi_compatible_session_roots() -> Vec<PathBuf> {
181185 roots
182186}
183187
188+ fn deduplicate_pi_sessions ( mut sessions : Vec < PiSessionMeta > ) -> Vec < PiSessionMeta > {
189+ sessions. sort_by ( |left, right| {
190+ right
191+ . modified
192+ . cmp ( & left. modified )
193+ . then_with ( || left. jsonl_path . cmp ( & right. jsonl_path ) )
194+ } ) ;
195+ let mut seen_paths = HashSet :: new ( ) ;
196+ let mut seen_ids = HashSet :: new ( ) ;
197+ sessions. retain ( |session| {
198+ let canonical_path =
199+ fs:: canonicalize ( & session. jsonl_path ) . unwrap_or_else ( |_| session. jsonl_path . clone ( ) ) ;
200+ if !seen_paths. insert ( canonical_path) {
201+ return false ;
202+ }
203+ session. session_id . is_empty ( ) || seen_ids. insert ( session. session_id . clone ( ) )
204+ } ) ;
205+ sessions
206+ }
207+
184208pub fn scan_pi_session_dir ( ) -> Vec < PiSessionMeta > {
185- pi_compatible_session_roots ( )
186- . into_iter ( )
187- . flat_map ( |root| scan_pi_session_dir_at ( & root) )
188- . collect ( )
209+ deduplicate_pi_sessions (
210+ pi_compatible_session_roots ( )
211+ . into_iter ( )
212+ . flat_map ( |root| scan_pi_session_dir_at ( & root) )
213+ . collect ( ) ,
214+ )
189215}
190216
191217pub fn scan_pi_cache_session_dir ( ) -> Vec < PiSessionMeta > {
192- pi_compatible_session_roots ( )
193- . into_iter ( )
194- . flat_map ( |root| scan_pi_cache_session_dir_at ( & root) )
195- . collect ( )
218+ deduplicate_pi_sessions (
219+ pi_compatible_session_roots ( )
220+ . into_iter ( )
221+ . flat_map ( |root| scan_pi_cache_session_dir_at ( & root) )
222+ . collect ( ) ,
223+ )
196224}
197225
198226fn scan_pi_cache_session_dir_at ( root : & Path ) -> Vec < PiSessionMeta > {
@@ -771,6 +799,28 @@ mod tests {
771799 assert ! ( scan_pi_cache_session_dir_at( dir. path( ) ) . is_empty( ) ) ;
772800 }
773801
802+ #[ test]
803+ fn multi_root_discovery_deduplicates_logical_sessions ( ) {
804+ clear_caches_for_tests ( ) ;
805+ let first = tempfile:: tempdir ( ) . unwrap ( ) ;
806+ let second = tempfile:: tempdir ( ) . unwrap ( ) ;
807+ let content = r#"{"type":"session","id":"same-session","timestamp":"2026-01-01T00:00:00.000Z","cwd":"/tmp/proj"}"# ;
808+ fixture_path ( & first, content) ;
809+ fixture_path ( & second, content) ;
810+
811+ let mut first_sessions = scan_pi_session_dir_at ( first. path ( ) ) ;
812+ first_sessions[ 0 ] . modified = 100 ;
813+ let mut second_sessions = scan_pi_session_dir_at ( second. path ( ) ) ;
814+ second_sessions[ 0 ] . modified = 200 ;
815+ let newest_path = second_sessions[ 0 ] . jsonl_path . clone ( ) ;
816+ let sessions =
817+ deduplicate_pi_sessions ( first_sessions. into_iter ( ) . chain ( second_sessions) . collect ( ) ) ;
818+
819+ assert_eq ! ( sessions. len( ) , 1 ) ;
820+ assert_eq ! ( sessions[ 0 ] . session_id, "same-session" ) ;
821+ assert_eq ! ( sessions[ 0 ] . jsonl_path, newest_path) ;
822+ }
823+
774824 #[ test]
775825 fn compaction_entry_handling ( ) {
776826 clear_caches_for_tests ( ) ;
0 commit comments