openmoat 0.12.0

Policy checks for AI coding agents: decides allow, defer, ask or deny for every tool call from Claude Code, Codex, Cursor, OpenClaw, GitHub Copilot CLI, pi and Gemini CLI, configures Claude Code's, Codex's and Cursor's own OS sandboxes from the same policy, and keeps a local audit log.
//! `moat replay`: what each agent session did, as a timeline.

use anyhow::{Result, bail};
use openmoat_audit::SessionSummary;
use openmoat_hosts::Host;

use crate::cli::{Format, ReplayArgs};
use crate::exit::Code;
use crate::home::Home;
use crate::render;
use crate::time;

pub fn run(args: &ReplayArgs) -> Result<Code> {
    let store = Home::locate()?.open_audit()?;
    let host = args.host.map(Host::id);

    let sessions: Vec<SessionSummary> = if let Some(id) = &args.session {
        let events = store.session(id)?;
        if events.is_empty() {
            bail!("no session `{id}`");
        }
        let first = &events[0];
        vec![SessionSummary {
            session_id: first.session_id.clone(),
            host: first.host.clone(),
            cwd: first.cwd.clone(),
            first_ms: first.ts_ms,
            last_ms: events.last().map_or(first.ts_ms, |e| e.ts_ms),
            events,
        }]
    } else {
        let since = time::parse_since(&args.since, time::now_ms())?;
        store.sessions_since(since, host)?
    };

    match args.format {
        Format::Json => render::json(&sessions)?,
        Format::Text => render::replay(&sessions)?,
    }
    Ok(Code::Ok)
}