1use crate::engine::cooldown;
8use std::sync::Arc;
9
10pub async fn list() -> anyhow::Result<()> {
12 let store = Arc::new(crate::cli::init_store().await?);
13 cooldown::init_cooldown_store(store).await;
15
16 let entries = cooldown::list_all_cooldowns();
17 if entries.is_empty() {
18 println!("No active cooldowns.");
19 return Ok(());
20 }
21
22 let now = chrono::Utc::now().timestamp();
23 println!("{:<30} {:<12} REASON", "KEY", "REMAINING");
24 println!("{}", "-".repeat(72_usize));
25 for (key, until, reason) in entries {
26 let remaining_secs = until - now;
27 let remaining = format_remaining(remaining_secs);
28 println!("{:<30} {:<12} {}", key, remaining, reason);
29 }
30 Ok(())
31}
32
33pub async fn clear(key: Option<String>, all: bool) -> anyhow::Result<()> {
35 let store = Arc::new(crate::cli::init_store().await?);
36 cooldown::init_cooldown_store(store.clone()).await;
38
39 if all {
40 cooldown::clear_cooldown("*", &store).await;
41 println!("Cleared all cooldowns.");
42 } else if let Some(k) = key {
43 cooldown::clear_cooldown(&k, &store).await;
44 println!("Cleared cooldown: {k}");
45 } else {
46 anyhow::bail!("specify a key (e.g. 'claude' or 'claude:sonnet') or use --all");
47 }
48 Ok(())
49}
50
51fn format_remaining(secs: i64) -> String {
52 if secs <= 0 {
53 return "expired".to_string();
54 }
55 if secs < 3600 {
56 format!("{}m", secs / 60)
57 } else if secs < 86400 {
58 let h = secs / 3600;
59 let m = (secs % 3600) / 60;
60 if m == 0 {
61 format!("{h}h")
62 } else {
63 format!("{h}h{m}m")
64 }
65 } else {
66 let d = secs / 86400;
67 let h = (secs % 86400) / 3600;
68 if h == 0 {
69 format!("{d}d")
70 } else {
71 format!("{d}d{h}h")
72 }
73 }
74}