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