diff --git a/rust/src/providers/claude/mod.rs b/rust/src/providers/claude/mod.rs index d093e8b87e..bd30de5b0f 100755 --- a/rust/src/providers/claude/mod.rs +++ b/rust/src/providers/claude/mod.rs @@ -682,7 +682,11 @@ impl ClaudeProvider { // Fallback: collect all percentages in order. Activity stats carry // their own percentages, which must never be read as plan limits. - if session_percent.is_none() && !activity_stats { + // Without a "Current session" row (weekly-only plans) the first + // percentage belongs to a weekly window, so there is no fallback + // (upstream steipete/CodexBar#4914). + if session_percent.is_none() && !activity_stats && clean_lower.contains("current session") + { let all_percents: Vec = percent_matches(&clean).collect(); if !all_percents.is_empty() { session_percent = Some(all_percents[0]); @@ -727,15 +731,17 @@ impl ClaudeProvider { } // Build usage snapshot - let session_used = session_percent.unwrap_or(0.0); - let primary = RateWindow::with_details( - session_used, - Some(300), // 5 hour session window - session_reset - .as_deref() - .and_then(|reset| parse_claude_reset_date(reset, now, Some(300))), - session_reset, - ); + let primary = match session_percent { + Some(session_used) => RateWindow::with_details( + session_used, + Some(300), // 5 hour session window + session_reset + .as_deref() + .and_then(|reset| parse_claude_reset_date(reset, now, Some(300))), + session_reset, + ), + None => RateWindow::no_active_session(), + }; let mut usage = UsageSnapshot::new(primary); diff --git a/rust/src/providers/claude/tests.rs b/rust/src/providers/claude/tests.rs index 4277ce6cbd..15168974c6 100644 --- a/rust/src/providers/claude/tests.rs +++ b/rust/src/providers/claude/tests.rs @@ -326,6 +326,30 @@ fn parse_err(output: &str) -> ProviderError { .expect_err("should reject") } +/// Plans without a 5-hour limit print no "Current session" row. The first +/// percentage on the panel is then the weekly one and must not become the +/// session (VibeTV-shop/vibetv#614, upstream steipete/CodexBar#4914). +#[test] +fn weekly_only_cli_screen_keeps_session_empty() { + let usage = parse_ok( + r#" +Status Config Usage + + Current week (all models) + ████ 8% used + Resets Nov 9 at 9am (America/New_York) + + Current week (Fable only) + ▌ 0% used + Resets Nov 9 at 9am (America/New_York) +"#, + ) + .usage; + assert!(usage.primary.is_informational); + assert_eq!(usage.primary.used_percent, 0.0); + assert_eq!(usage.secondary.map(|w| w.used_percent), Some(8.0)); +} + #[test] fn parses_current_cli_usage_screen() { let output = r#"