Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions src/parsers/claude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! Claude Code CLI authenticates against. Both return the same shape.

use crate::model::UsageWindow;
use crate::time::{DAY, HOUR, format_countdown};
use crate::time::{DAY, HOUR, format_countdown, format_duration};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
Expand All @@ -22,8 +22,15 @@ struct Bucket {
impl Bucket {
fn into_window(self, label: &str, seconds: i64) -> UsageWindow {
let countdown = match self.resets_at.as_deref().map(str::trim) {
None | Some("") => "Unknown".to_string(),
Some(at) => format_countdown(at),
None | Some("") => format_duration(seconds),
Some(at) => {
let parsed = format_countdown(at);
if parsed == "Unknown" {
format_duration(seconds)
} else {
parsed
}
}
};
UsageWindow::new(label, self.utilization.unwrap_or(0.0))
.reset(countdown)
Expand Down Expand Up @@ -98,18 +105,20 @@ mod tests {
}

#[test]
fn a_missing_reset_time_is_reported_as_unknown() {
fn a_missing_reset_time_falls_back_to_window_duration() {
let windows = parse(r#"{"five_hour":{"utilization":10.0}}"#);
assert_eq!(windows[0].reset_countdown, "Unknown");
assert_eq!(windows[0].reset_countdown, "5h 0m");
}

#[test]
fn null_fields_in_bucket_survive_deserialization() {
let windows = parse(r#"{"five_hour":{"utilization":0.0,"resets_at":null},"seven_day":{"utilization":99.0,"resets_at":"2026-08-18T10:59:59.644698+00:00"}}"#);
let windows = parse(
r#"{"five_hour":{"utilization":0.0,"resets_at":null},"seven_day":{"utilization":99.0,"resets_at":"2026-08-18T10:59:59.644698+00:00"}}"#,
);
assert_eq!(windows.len(), 2);
assert_eq!(windows[0].label, "Session");
assert_eq!(windows[0].used_percent, 0.0);
assert_eq!(windows[0].reset_countdown, "Unknown");
assert_eq!(windows[0].reset_countdown, "5h 0m");
assert_eq!(windows[1].label, "Weekly");
assert_eq!(windows[1].used_percent, 99.0);
}
Expand Down
5 changes: 5 additions & 0 deletions src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ pub fn format_countdown(timestamp: &str) -> String {
}
}

/// Format a duration in seconds as a countdown string (e.g. `5h 0m`, `7d 0h`, `45m`).
pub fn format_duration(seconds: i64) -> String {
countdown_between(seconds, 0)
}

/// Turn a countdown string back into seconds.
///
/// Used only for ordering exhausted providers by who frees up first, so an
Expand Down
Loading