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.clone()).await;
15
16 let router = crate::engine::router::Router::from_config();
19 router.refresh_health(&store).await;
20
21 let entries = cooldown::list_all_cooldowns();
22 let degraded = cooldown::list_degraded_agents();
23 if entries.is_empty() && degraded.is_empty() {
24 println!("No active cooldowns.");
25 return Ok(());
26 }
27
28 let now = chrono::Utc::now().timestamp();
29 println!("{:<30} {:<12} REASON", "KEY", "REMAINING");
30 println!("{}", "-".repeat(72_usize));
31 for (key, until, reason) in &entries {
32 let remaining_secs = until - now;
33 let remaining = format_remaining(remaining_secs);
34 println!("{:<30} {:<12} {}", key, remaining, reason);
35 }
36 for (agent, reason) in degraded {
37 if entries.iter().any(|(key, ..)| key == &agent) {
38 continue;
39 }
40 println!("{:<30} {:<12} {}", agent, "degraded", reason);
41 }
42 Ok(())
43}
44
45pub async fn clear(key: Option<String>, all: bool) -> anyhow::Result<()> {
47 let store = Arc::new(crate::cli::init_store().await?);
48 cooldown::init_cooldown_store(store.clone()).await;
50
51 if all {
52 let agents = crate::engine::router::Router::from_config().available_agents;
53 cooldown::clear_cooldown("*", &store).await;
54 cooldown::mark_rate_limits_cleared(&store, &agents).await;
55 println!("Cleared all cooldowns.");
56 } else if let Some(k) = key {
57 cooldown::clear_cooldown(&k, &store).await;
58 println!("Cleared cooldown: {k}");
59 } else {
60 anyhow::bail!("specify a key (e.g. 'claude' or 'claude:sonnet') or use --all");
61 }
62 Ok(())
63}
64
65fn format_remaining(secs: i64) -> String {
66 if secs <= 0 {
67 return "expired".to_string();
68 }
69 if secs < 3600 {
70 format!("{}m", secs / 60)
71 } else if secs < 86400 {
72 let h = secs / 3600;
73 let m = (secs % 3600) / 60;
74 if m == 0 {
75 format!("{h}h")
76 } else {
77 format!("{h}h{m}m")
78 }
79 } else {
80 let d = secs / 86400;
81 let h = (secs % 86400) / 3600;
82 if h == 0 {
83 format!("{d}d")
84 } else {
85 format!("{d}d{h}h")
86 }
87 }
88}