1use crate::cache::CacheManager;
2use crate::cache::store;
3use crate::git::GitRepo;
4use anyhow::Result;
5
6#[derive(Debug, clap::Args)]
7pub struct CacheArgs {
8 #[command(subcommand)]
9 pub command: CacheCommand,
10}
11
12#[derive(Debug, clap::Subcommand)]
13pub enum CacheCommand {
14 Status,
16 Clear {
18 #[arg(long)]
20 all: bool,
21 },
22}
23
24pub fn run(args: &CacheArgs) -> Result<()> {
25 match &args.command {
26 CacheCommand::Status => status(),
27 CacheCommand::Clear { all } => clear(*all),
28 }
29}
30
31fn status() -> Result<()> {
32 let repo = GitRepo::discover()?;
33 let repo_root = repo.root();
34
35 let Some(dir) = store::cache_dir(repo_root) else {
36 println!("Cache directory could not be resolved.");
37 return Ok(());
38 };
39
40 let entries = store::list_entries(&dir)?;
41
42 if entries.is_empty() {
43 println!("No cached entries for this repository.");
44 return Ok(());
45 }
46
47 let now = store::now_secs();
48
49 println!("Cached commit plans ({} entries):", entries.len());
50 println!();
51 for entry in &entries {
52 let age_secs = now.saturating_sub(entry.created_at);
53 let age = format_age(age_secs);
54 let file_count: usize = entry.plan.commits.iter().map(|c| c.files.len()).sum();
55 let commit_count = entry.plan.commits.len();
56 println!(
57 " {} — {} commit(s), {} file(s), backend={}, model={}, age={}",
58 &entry.state_key[..12],
59 commit_count,
60 file_count,
61 entry.backend,
62 entry.model,
63 age,
64 );
65 }
66
67 println!();
68 println!("Cache dir: {}", dir.display());
69
70 Ok(())
71}
72
73fn clear(all: bool) -> Result<()> {
74 if all {
75 let count = store::clear_all()?;
76 println!("Cleared {count} cached entries across all repositories.");
77 } else {
78 let repo = GitRepo::discover()?;
79 let cm = CacheManager::new(repo.root(), false, None, "", "");
80 match cm {
81 Some(cm) => {
82 let count = cm.clear()?;
83 println!("Cleared {count} cached entries for this repository.");
84 }
85 None => {
86 println!("Cache directory could not be resolved.");
87 }
88 }
89 }
90 Ok(())
91}
92
93fn format_age(secs: u64) -> String {
94 if secs < 60 {
95 format!("{secs}s")
96 } else if secs < 3600 {
97 format!("{}m", secs / 60)
98 } else {
99 format!("{}h", secs / 3600)
100 }
101}