Skip to content

Commit 7b35024

Browse files
fix: scan project-local .claw/sessions/ as well as global root
The previous implementation only scanned ~/.claw/sessions/ for the global fallback, but sessions are actually stored in the project-local <cwd>/.claw/sessions/<fingerprint>/ by SessionStore::from_cwd(). Now scans both the global root and the project-local parent directory (checking all fingerprint subdirs) so /resume latest finds sessions regardless of where they're stored. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9b1593c commit 7b35024

1 file changed

Lines changed: 35 additions & 20 deletions

File tree

rust/crates/runtime/src/session_control.rs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl SessionStore {
164164
}
165165
// Fallback: scan all workspace namespaces under ~/.claw/sessions/
166166
// so that /resume latest can find sessions from other workspaces
167-
if let Some(latest) = Self::scan_global_sessions()?.into_iter().next() {
167+
if let Some(latest) = self.scan_global_sessions()?.into_iter().next() {
168168
return Ok(latest);
169169
}
170170
Err(SessionControlError::Format(format_no_managed_sessions(
@@ -251,28 +251,43 @@ impl SessionStore {
251251
.map(Path::to_path_buf)
252252
}
253253

254-
/// Scan all workspace namespaces under the global sessions root
255-
/// (`~/.claw/sessions/`) to find sessions from any workspace.
256-
/// Used as a fallback when the current workspace has no sessions.
257-
fn scan_global_sessions() -> Result<Vec<ManagedSessionSummary>, SessionControlError> {
258-
let global_root = global_sessions_root();
259-
let entries = match fs::read_dir(&global_root) {
260-
Ok(entries) => entries,
261-
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()),
262-
Err(err) => return Err(err.into()),
263-
};
254+
/// Scan all known session storage locations for sessions from any workspace.
255+
/// Checks both the global root (~/.claw/sessions/) and the project-local
256+
/// .claw/sessions/ parent directory. Used as a fallback when the current
257+
/// workspace has no sessions.
258+
#[allow(clippy::unnecessary_wraps)]
259+
fn scan_global_sessions(&self) -> Result<Vec<ManagedSessionSummary>, SessionControlError> {
264260
let mut sessions = Vec::new();
265-
for entry in entries {
266-
let Ok(entry) = entry else {
267-
continue;
268-
};
269-
let path = entry.path();
270-
if !path.is_dir() {
271-
continue;
261+
262+
// Scan global root: ~/.claw/sessions/<fingerprint>/
263+
let global_root = global_sessions_root();
264+
if let Ok(entries) = fs::read_dir(&global_root) {
265+
for entry in entries.flatten() {
266+
let path = entry.path();
267+
if path.is_dir() {
268+
let _ = Self::collect_sessions_from_dir_unvalidated(&path, &mut sessions);
269+
}
272270
}
273-
// Silently ignore errors reading individual workspace dirs
274-
let _ = Self::collect_sessions_from_dir_unvalidated(&path, &mut sessions);
275271
}
272+
273+
// Scan project-local parent: <cwd>/.claw/sessions/<fingerprint>/
274+
// Sessions are stored here by from_cwd(), so we must check all
275+
// fingerprint subdirs, not just the current workspace's.
276+
if let Some(local_parent) = self.legacy_sessions_root() {
277+
if let Ok(entries) = fs::read_dir(&local_parent) {
278+
for entry in entries.flatten() {
279+
let path = entry.path();
280+
if path.is_dir() && path != self.sessions_root {
281+
let _ = Self::collect_sessions_from_dir_unvalidated(&path, &mut sessions);
282+
} else if path == self.sessions_root {
283+
// Already searched in list_sessions(), but include here
284+
// in case this is called standalone
285+
let _ = Self::collect_sessions_from_dir_unvalidated(&path, &mut sessions);
286+
}
287+
}
288+
}
289+
}
290+
276291
sort_managed_sessions(&mut sessions);
277292
Ok(sessions)
278293
}

0 commit comments

Comments
 (0)