Discover all transcript files across the modern projects layout and the legacy flat `transcripts/` directory. - ` /projects/ /*.jsonl` (top-level sessions) - ` /projects/ / /subagents/*.jsonl` (subagents) - ` /transcripts/*.jsonl` (legacy)
(config: &Config)
| 26 | /// - `<data_dir>/projects/<slug>/<sessionId>/subagents/*.jsonl` (subagents) |
| 27 | /// - `<data_dir>/transcripts/*.jsonl` (legacy) |
| 28 | pub fn discover_transcript_files(config: &Config) -> Vec<TranscriptFile> { |
| 29 | let mut files = Vec::new(); |
| 30 | |
| 31 | let projects_dir = config.projects_dir(); |
| 32 | if projects_dir.exists() { |
| 33 | for entry in WalkDir::new(&projects_dir) |
| 34 | .into_iter() |
| 35 | .filter_map(|e| e.ok()) |
| 36 | { |
| 37 | let path = entry.path(); |
| 38 | if path.extension().is_none_or(|e| e != "jsonl") { |
| 39 | continue; |
| 40 | } |
| 41 | if let Some(file) = classify_project_file(path, &projects_dir) { |
| 42 | files.push(file); |
| 43 | } |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | let legacy_dir = config.transcripts_dir(); |
| 48 | if legacy_dir.exists() { |
| 49 | for entry in WalkDir::new(&legacy_dir) |
| 50 | .max_depth(1) |
| 51 | .into_iter() |
| 52 | .filter_map(|e| e.ok()) |
| 53 | { |
| 54 | let path = entry.path(); |
| 55 | if path.extension().is_none_or(|e| e != "jsonl") { |
| 56 | continue; |
| 57 | } |
| 58 | let source_file = file_name_string(path); |
| 59 | let session_id = source_file |
| 60 | .strip_prefix("ses_") |
| 61 | .and_then(|s| s.strip_suffix(".jsonl")) |
| 62 | .unwrap_or(&source_file) |
| 63 | .to_string(); |
| 64 | files.push(TranscriptFile { |
| 65 | path: path.to_path_buf(), |
| 66 | source_file, |
| 67 | session_id, |
| 68 | project: None, |
| 69 | agent_id: None, |
| 70 | }); |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | files |
| 75 | } |
| 76 | |
| 77 | fn file_name_string(path: &Path) -> String { |
| 78 | path.file_name() |
no test coverage detected