Skip to main content

agent_trace/commands/
log.rs

1use crate::observability::CliOutput;
2use crate::store::Store;
3use crate::types::{Actor, DocType};
4use anyhow::Result;
5use std::path::Path;
6
7pub fn run(
8    store_root: &Path,
9    file: Option<&Path>,
10    limit: Option<usize>,
11    actor_filter: Option<&str>,
12    type_filter: Option<&DocType>,
13    output: &dyn CliOutput,
14) -> Result<()> {
15    let store = Store::open(store_root)?;
16    let limit = limit.unwrap_or(50);
17
18    let entries = if let Some(f) = file {
19        store.git.log_file(f, limit)?
20    } else {
21        store.git.log(limit)?
22    };
23
24    let entries: Vec<_> = entries
25        .into_iter()
26        .filter(|e| match actor_filter {
27            Some("user") => matches!(e.actor, Actor::User),
28            Some("agent") => e.actor.is_agent(),
29            Some("system") => matches!(e.actor, Actor::System),
30            _ => true,
31        })
32        .filter(|e| match type_filter {
33            Some(tf) => e.files.iter().any(|(_, _, dt)| dt == tf),
34            None => true,
35        })
36        .collect();
37
38    if entries.is_empty() {
39        output.line("No log entries.")?;
40        return Ok(());
41    }
42
43    for entry in &entries {
44        let time = entry.timestamp.format("%Y-%m-%d %H:%M:%S");
45        let files_str = entry
46            .files
47            .iter()
48            .map(|(p, _, _)| p.display().to_string())
49            .collect::<Vec<_>>()
50            .join(", ");
51        output.line(&format!(
52            "{} [{}] {} {} — {}",
53            time, entry.action, entry.actor, files_str, entry.summary
54        ))?;
55    }
56
57    Ok(())
58}