use std::time::Duration;
use kiromi_ai_memory::GcOpts;
use crate::cli::{GcArgs, GlobalArgs};
use crate::error::{CliError, ExitCode};
use crate::runtime::Runtime;
pub(crate) async fn run(args: GcArgs, globals: &GlobalArgs) -> Result<(), CliError> {
let rt = Runtime::open(globals).await?;
let dur = parse_duration(&args.retain_for)?;
let opts = GcOpts::default()
.with_retain_for(dur)
.with_dry_run(args.dry_run);
let report = rt.mem.gc(opts).await?;
if rt.json {
println!(
"{}",
serde_json::json!({
"data_blobs_removed": report.data_blobs_removed,
"summary_blobs_removed": report.summary_blobs_removed,
"manifest_blobs_removed": report.manifest_blobs_removed,
"bytes_freed": report.bytes_freed,
"dry_run": args.dry_run,
})
);
} else {
println!(
"data={} summaries={} manifests={} bytes_freed={} dry_run={}",
report.data_blobs_removed,
report.summary_blobs_removed,
report.manifest_blobs_removed,
report.bytes_freed,
args.dry_run,
);
}
rt.mem.close().await?;
Ok(())
}
fn parse_duration(s: &str) -> Result<Duration, CliError> {
let s = s.trim();
if s == "0" {
return Ok(Duration::ZERO);
}
let (num, unit) = match s.find(|c: char| !c.is_ascii_digit()) {
Some(idx) => (&s[..idx], &s[idx..]),
None => (s, "s"),
};
let n: u64 = num.parse().map_err(|e| CliError {
kind: ExitCode::Config,
source: anyhow::anyhow!("retain-for: {e}"),
})?;
let mult = match unit {
"s" => 1,
"m" => 60,
"h" => 3600,
"d" => 86_400,
other => {
return Err(CliError {
kind: ExitCode::Config,
source: anyhow::anyhow!("unknown retain-for unit: {other}"),
});
}
};
Ok(Duration::from_secs(n * mult))
}