use anyhow::Result;
use crate::cache::Cache;
pub fn print_stats(db_path: &str) -> Result<()> {
let s = Cache::new(db_path)?.stats(db_path)?;
let saved = s.tokens_saved();
let rate = s.hit_rate();
let db_mb = s.db_bytes as f64 / (1024.0 * 1024.0);
let reduction = if s.tokens_original > 0 {
(1.0 - s.tokens_returned as f64 / s.tokens_original as f64) * 100.0
} else {
0.0
};
eprintln!();
eprintln!(" ┌─────────────────────────────────────────┐");
eprintln!(" │ mcpkill cache stats │");
eprintln!(" ├─────────────────────────────────────────┤");
eprintln!(" │ Cache entries {:<22} │", s.entries);
eprintln!(" │ Stored chunks {:<22} │", s.total_chunks);
eprintln!(" │ Cache hits {:<22} │", s.cache_hits);
eprintln!(" │ Hit rate {:<22} │", format!("{rate:.1}%"));
eprintln!(" ├─────────────────────────────────────────┤");
eprintln!(" │ Tokens (original){:<22} │", s.tokens_original);
eprintln!(" │ Tokens (returned){:<22} │", s.tokens_returned);
eprintln!(
" │ Tokens saved {:<22} │",
format!("~{saved} ({reduction:.0}%)")
);
eprintln!(" ├─────────────────────────────────────────┤");
eprintln!(" │ DB size {:<22} │", format!("{db_mb:.2} MB"));
eprintln!(" │ DB path {:<22} │", truncate(db_path, 22));
eprintln!(" └─────────────────────────────────────────┘");
eprintln!();
Ok(())
}
pub fn print_stats_json(db_path: &str) -> Result<()> {
let s = Cache::new(db_path)?.stats(db_path)?;
let json = serde_json::json!({
"entries": s.entries,
"chunks": s.total_chunks,
"cache_hits": s.cache_hits,
"hit_rate_pct": format!("{:.1}", s.hit_rate()),
"tokens_original": s.tokens_original,
"tokens_returned": s.tokens_returned,
"tokens_saved": s.tokens_saved(),
"db_bytes": s.db_bytes,
"db_path": db_path,
});
println!("{}", serde_json::to_string_pretty(&json)?);
Ok(())
}
fn truncate(s: &str, max: usize) -> String {
if s.len() <= max {
s.to_string()
} else {
format!("…{}", &s[s.len().saturating_sub(max - 1)..])
}
}