diff --git a/.beans/claudbg-9627--sessions-list-some-sessions-show-no-project-path.md b/.beans/claudbg-9627--sessions-list-some-sessions-show-no-project-path.md index 439e8e8..5f8b22f 100644 --- a/.beans/claudbg-9627--sessions-list-some-sessions-show-no-project-path.md +++ b/.beans/claudbg-9627--sessions-list-some-sessions-show-no-project-path.md @@ -1,10 +1,15 @@ --- # claudbg-9627 title: 'sessions list: some sessions show no project path' -status: todo +status: completed type: bug +priority: normal created_at: 2026-03-31T23:44:53Z -updated_at: 2026-03-31T23:44:53Z +updated_at: 2026-04-01T05:59:53Z --- Some entries in `claudbg sessions list` do not display a project path. Investigate why the project path is missing for certain sessions. + +## Summary of Changes + +Fixed `read_cwd_from_first_line()` in `src/parser/discovery.rs`. The old code stopped after the first non-empty line even if it contained no `cwd` field. The fix scans up to 20 non-empty lines looking for any entry with a `cwd` field. Claude Code typically writes `cwd` on a `system`-type entry which may not be the very first line in all session files. diff --git a/src/parser/discovery.rs b/src/parser/discovery.rs index 5dad6a6..1b04c91 100644 --- a/src/parser/discovery.rs +++ b/src/parser/discovery.rs @@ -44,25 +44,35 @@ fn claude_projects_dir() -> Option { Some(PathBuf::from(home).join(".claude").join("projects")) } -/// Read the first non-empty line of a file and attempt to extract `cwd` from it. +/// Scan the first few lines of a session file to find a `cwd` field. /// -/// Returns `None` if the file cannot be read or the first line cannot be parsed. +/// Reads up to 20 non-empty lines looking for any entry whose top-level `cwd` +/// field is set. The `cwd` field is written by Claude Code on `system`-type +/// entries; it may not appear on the very first line if the session file starts +/// with a user or assistant message. +/// +/// Returns `None` if the file cannot be read or no `cwd` is found within the +/// first 20 lines. fn read_cwd_from_first_line(path: &Path) -> Option { + const MAX_LINES: usize = 20; let file = std::fs::File::open(path).ok()?; let reader = BufReader::new(file); + let mut checked = 0usize; for line in reader.lines() { let line = line.ok()?; let trimmed = line.trim(); if trimmed.is_empty() { continue; } + checked += 1; if let Ok(entry) = serde_json::from_str::(trimmed) && entry.cwd.is_some() { return entry.cwd; } - // Return after first non-empty line regardless. - break; + if checked >= MAX_LINES { + break; + } } None } @@ -266,11 +276,7 @@ pub fn discover_all_agents() -> crate::error::Result> { let session_dir_entries = match std::fs::read_dir(&proj_path) { Ok(e) => e, Err(err) => { - eprintln!( - "claudbg: could not read {}: {}", - proj_path.display(), - err - ); + eprintln!("claudbg: could not read {}: {}", proj_path.display(), err); continue; } };