use crate::model::{Agent, Session, Status};
use crate::sessions::{LiveAgentRef, SessionsResult};
use std::collections::HashMap;
use std::fs;
use std::path::Path;
const SKIP_LABELS: &[&str] = &["claude", "claude-code", "codex", "openai-codex"];
pub fn summarise(agents: &[Agent], live_agents: &[LiveAgentRef], _now_ms: u64) -> SessionsResult {
let mut by_pid: HashMap<u32, Session> = HashMap::new();
for a in agents {
if SKIP_LABELS.contains(&a.label.as_str()) { continue; }
if !live_agents.iter().any(|l| l.pid == a.pid) { continue; }
let recent = most_recent_writable(a);
let last_task = recent.as_ref().map(|p| {
let s = p.to_string_lossy();
if let Some(rest) = s.strip_prefix(a.cwd.as_str()) {
let r = rest.trim_start_matches('/');
if r.is_empty() { s.into_owned() } else { r.to_string() }
} else {
s.into_owned()
}
});
if last_task.is_some() {
by_pid.insert(a.pid, Session {
id: format!("{}", a.pid),
project: a.cwd.clone(),
project_short: a.project.clone(),
file: String::new(),
size_bytes: 0,
mtime_ms: 0,
age_ms: 0,
status: classify(a),
stop_reason: None,
last_task,
last_tool: None,
current_tool: None,
in_flight_tasks: 0,
in_flight_subagents: Vec::new(),
recent_activity: a.writing_files.iter().take(6)
.map(|f| format!("→ writing: {}", f)).collect(),
live_pid: Some(a.pid),
is_most_recent: true,
tokens_input: 0,
tokens_output: 0,
tokens_total: 0,
tokens_cache_read: 0,
tokens_cache_write: 0,
cost_usd: 0.0,
context_used: 0,
session_started_ms: 0,
tool_counts: Vec::new(),
model: None,
});
}
}
SessionsResult { sessions: crate::model::Sessions::default(), by_pid }
}
fn classify(a: &Agent) -> Status {
if a.cpu >= 20.0 { Status::Busy }
else if a.cpu >= 1.0 { Status::Active }
else { Status::Idle }
}
fn most_recent_writable(a: &Agent) -> Option<std::path::PathBuf> {
let mut best: Option<(std::path::PathBuf, std::time::SystemTime)> = None;
for f in &a.writing_files {
if f.is_empty() { continue; }
let p = Path::new(f);
if let Ok(md) = fs::metadata(p) {
if let Ok(mt) = md.modified() {
let take = best.as_ref().map(|(_, t)| mt > *t).unwrap_or(true);
if take {
best = Some((p.to_path_buf(), mt));
}
}
}
}
best.map(|(p, _)| p)
}