From 747cdcc54467392a0263ab50e847033df07c4cc6 Mon Sep 17 00:00:00 2001 From: Paul Anduschus <157472224+DreamyTalesPAN@users.noreply.github.com> Date: Tue, 10 Nov 2026 18:43:08 +0100 Subject: [PATCH 1/2] claude: test that a weekly-only /usage panel keeps Session empty (VibeTV-shop/vibetv#614) Co-Authored-By: Claude Sonnet 5.5 --- rust/src/providers/claude/tests.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) 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#" From 4624340a7f79dfbd0079eacab9512b350a952a88 Mon Sep 17 00:00:00 2001 From: Paul Anduschus <157472224+DreamyTalesPAN@users.noreply.github.com> Date: Tue, 10 Nov 2026 18:43:08 +0100 Subject: [PATCH 2/2] claude: no Current session row means no session window, not a copy of Weekly Port of steipete/CodexBar#4914 to the Claude Code CLI path: without a Current session row the first percentage is no longer read as session. Session becomes the informational no-active-session window, like the OAuth and Web paths. Refs VibeTV-shop/vibetv#614. Co-Authored-By: Claude Sonnet 5.5 --- rust/src/providers/claude/mod.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) 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);