agent_trace/commands/
log.rs1use 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}