use rmcp::schemars;
use serde::Serialize;
use crate::coordination::inventory::fetch_status_agents_over_http;
use crate::mcp::RepoContext;
use crate::session::{self, SessionStatus};
#[derive(Debug, Clone, Serialize, schemars::JsonSchema)]
pub struct AgentRow {
pub branch: String,
pub cli: String,
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_seen_seconds: Option<u64>,
}
#[derive(Debug, Clone, Serialize, schemars::JsonSchema)]
pub struct SessionSnapshot {
pub name: String,
pub mode: String,
pub status: String,
pub paused: bool,
pub agent_count: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub broker_url: Option<String>,
pub agents: Vec<AgentRow>,
}
fn status_label(status: &SessionStatus) -> &'static str {
match status {
SessionStatus::Active => "active",
SessionStatus::Paused => "paused",
SessionStatus::Stopped => "stopped",
}
}
#[must_use]
pub fn session_status(ctx: &RepoContext) -> Option<SessionSnapshot> {
let session = session::find_session_for_repo(&ctx.root).ok().flatten()?;
let live = ctx
.broker_url
.as_deref()
.and_then(|url| fetch_status_agents_over_http(url).ok())
.unwrap_or_default();
let agents = session
.worktrees
.iter()
.map(|w| {
let row = live.iter().find(|a| a.agent_id == w.branch);
AgentRow {
branch: w.branch.clone(),
cli: w.cli.clone(),
status: row.map(|r| r.status.clone()).unwrap_or_default(),
last_seen_seconds: row.map(|r| r.last_seen_seconds),
}
})
.collect::<Vec<_>>();
let mode = match session.mode {
crate::session::SessionMode::Bare => "bare",
crate::session::SessionMode::Supervisor => "supervisor",
};
let paused = session.status == SessionStatus::Paused;
Some(SessionSnapshot {
name: session.session_name.clone(),
mode: mode.to_string(),
status: status_label(&session.status).to_string(),
paused,
agent_count: session.worktrees.len(),
broker_url: ctx.broker_url.clone(),
agents,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_session_yields_none() {
let tmp = tempfile::tempdir().unwrap();
let ctx = RepoContext {
root: tmp.path().to_path_buf(),
git_paw_dir: None,
broker_url: None,
server_name: "git-paw".to_string(),
};
assert!(session_status(&ctx).is_none());
}
}