List all stored sessions. Returns sessions sorted by `started_at` (newest first). Skips corrupted session files with a warning log.
(&self)
| 583 | /// Returns sessions sorted by `started_at` (newest first). |
| 584 | /// Skips corrupted session files with a warning log. |
| 585 | pub fn list(&self) -> AgentResult<Vec<AgentSession>> { |
| 586 | let entries = match std::fs::read_dir(&self.sessions_dir) { |
| 587 | Ok(entries) => entries, |
| 588 | Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()), |
| 589 | Err(e) => return Err(e.into()), |
| 590 | }; |
| 591 | |
| 592 | let mut sessions = Vec::new(); |
| 593 | |
| 594 | for entry in entries { |
| 595 | let entry = entry?; |
| 596 | let name = entry.file_name(); |
| 597 | let name_str = name.to_string_lossy(); |
| 598 | |
| 599 | // Only process .json files (skip .tmp files, etc.) |
| 600 | if !name_str.ends_with(".json") || name_str.ends_with(".json.tmp") { |
| 601 | continue; |
| 602 | } |
| 603 | |
| 604 | let session_id = name_str.trim_end_matches(".json"); |
| 605 | |
| 606 | match self.load(session_id) { |
| 607 | Ok(Some(session)) => sessions.push(session), |
| 608 | Ok(None) => {} // File disappeared between readdir and load |
| 609 | Err(e) => { |
| 610 | log::warn!("Skipping corrupted session file {}: {}", name_str, e); |
| 611 | } |
| 612 | } |
| 613 | } |
| 614 | |
| 615 | // Sort by started_at, newest first |
| 616 | sessions.sort_by_key(|s| std::cmp::Reverse(s.started_at)); |
| 617 | |
| 618 | Ok(sessions) |
| 619 | } |
| 620 | |
| 621 | /// Find all active (non-ended) sessions. |
| 622 | /// |