claudex_cli/commands/
files.rs1use anyhow::Result;
2use chrono::DateTime;
3
4use crate::cli::ResolvedFilter;
5use crate::ui;
6use claudex::index::IndexStore;
7use claudex::providers::enabled_default;
8use claudex::store::short_name;
9
10pub fn run(
11 project: Option<&str>,
12 path: Option<&str>,
13 limit: usize,
14 json: bool,
15 filter: &ResolvedFilter,
16) -> Result<()> {
17 let providers = enabled_default()?;
18 let mut idx = IndexStore::open()?;
19 idx.ensure_fresh(&providers)?;
20
21 let rows = idx.query_file_mods(project, path, filter, limit)?;
22
23 if json {
24 let output: Vec<_> = rows
25 .iter()
26 .map(|r| {
27 let last_touched_at = r
28 .last_touched_timestamp_ms
29 .and_then(DateTime::from_timestamp_millis)
30 .map(|d| d.to_rfc3339());
31 serde_json::json!({
32 "file_path": r.file_path,
33 "modification_count": r.modification_count,
34 "distinct_session_count": r.distinct_session_count,
35 "last_touched_at": last_touched_at,
36 "top_project": r.top_project,
37 })
38 })
39 .collect();
40 println!("{}", serde_json::to_string_pretty(&output)?);
41 return Ok(());
42 }
43
44 if rows.is_empty() {
45 println!("No file modification data found.");
46 return Ok(());
47 }
48
49 let mut table = ui::table();
50 table.set_header(ui::header([
51 "File Path",
52 "Modifications",
53 "Sessions",
54 "Last Touched",
55 "Top Project",
56 ]));
57 ui::right_align(&mut table, &[1, 2]);
58 for r in &rows {
59 let last_touched = r
60 .last_touched_timestamp_ms
61 .and_then(DateTime::from_timestamp_millis)
62 .map(|d| d.format("%Y-%m-%d").to_string())
63 .unwrap_or_else(|| "-".to_string());
64 table.add_row([
65 ui::cell_project(&short_name(&r.file_path)),
66 ui::cell_count(r.modification_count as u64),
67 ui::cell_count(r.distinct_session_count as u64),
68 ui::cell_dim(&last_touched),
69 ui::cell_dim(r.top_project.as_deref().unwrap_or("-")),
70 ]);
71 }
72 println!("{table}");
73 Ok(())
74}