Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f86a1e0
Port upstream 0.48.0: bound serve request heads
Finesssee Aug 8, 2026
b37c37b
Test serve deadline-driven connection recovery
Finesssee Aug 8, 2026
f8db152
Port upstream 0.48.0: serve dashboard + snapshot contract
Finesssee Aug 8, 2026
10cea4f
Port upstream 0.48.0: codexbar dashboard command
Finesssee Aug 8, 2026
87ff071
fix(dashboard): coordinator lost-wakeup/cancellation, daily totalCost…
Finesssee Aug 8, 2026
10f2f18
Port upstream 0.48.0: OpenCode Go per-model daily cost breakdown
Finesssee Aug 8, 2026
edb396f
Port upstream 0.48.0: parse CommandCode rolling windows + GOAT plan
Finesssee Aug 8, 2026
1a73c62
Port upstream 0.48.0: derive OpenRouter key meter from server remaining
Finesssee Aug 8, 2026
2a242af
Port upstream 0.48.0: preserve ZoomMate browser cookie scope
Finesssee Aug 8, 2026
79ff599
Port upstream 0.48.0: decode Copilot AI credits counter
Finesssee Aug 8, 2026
dc8c8b1
Port upstream 0.48.0: classify Claude OAuth refresh failures, termina…
Finesssee Aug 8, 2026
58026df
Port upstream 0.48.0: bounded Zen balance wait in OpenCode Go usage r…
Finesssee Aug 8, 2026
7ffa03e
Port upstream 0.48.0: Claude OAuth refresh gate + serve/opencodego fi…
Finesssee Aug 8, 2026
7f016d3
Port upstream 0.48.0: Kimi/GLM/z.ai China routing (WS5)
Finesssee Aug 8, 2026
d2a63eb
Port upstream 0.48.0: unify Pi-family (pi + OMP) agent sessions (WS6)
Finesssee Aug 8, 2026
762bcd3
fix(dashboard): enable waiter notification under the decision guard (F1)
Finesssee Aug 8, 2026
2fdd01c
Port upstream 0.48.0: Codex cost-scanner robustness (F1,F2,F18,F19)
Finesssee Aug 8, 2026
dbcb583
Port upstream 0.48.0: Codex windows/pricing (F5,F6,C4)
Finesssee Aug 8, 2026
ab217f1
Port upstream 0.48.0: complete WS2+WS3 follow-up (A16,F6,F8,F5)
Finesssee Aug 8, 2026
319a19e
Port upstream 0.48.0: fix fmt/clippy integration issues
Finesssee Aug 8, 2026
d4725f8
Port upstream 0.48.0: C4 centralize fast suffix stripping (audit fix)
Finesssee Aug 8, 2026
e93524c
Port upstream 0.48.0: F8 clear previous_report after full scan (audit…
Finesssee Aug 8, 2026
ee2004e
Port upstream 0.48.0: A16/F18 expose coverage+completeness in CLI JSO…
Finesssee Aug 8, 2026
3937576
Port upstream 0.48.0: F19 refuse oversized cache + fix trim double-su…
Finesssee Aug 8, 2026
ed45e91
Port upstream 0.48.0: F2 boundary helper + scan-level negative regres…
Finesssee Aug 8, 2026
13cecda
Port upstream 0.48.0: F5 cadence/routing/headline regression tests (a…
Finesssee Aug 8, 2026
e35090a
Port upstream 0.48.0: F6 reset-backfill regression tests (audit fix)
Finesssee Aug 8, 2026
985b224
Port upstream 0.48.0: fix clippy lint in audit-followup test code (au…
Finesssee Aug 8, 2026
6286ce9
Port upstream 0.48.0: F19 refusal removes preexisting destination art…
Finesssee Aug 8, 2026
bee54cf
fix: fan out dashboard build errors
Finesssee Aug 8, 2026
979f4a5
fix: pin Windows globalization timezone module
Finesssee Aug 8, 2026
a7ca726
test: make globalization pin test host-independent
Finesssee Aug 8, 2026
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
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
Sources/** linguist-vendored
Tests/** linguist-vendored
Package.swift linguist-vendored

# Pi-family session fixtures are byte-exact copies of upstream wire shapes;
# never EOL-convert them (parsers split on LF).
rust/src/agent_sessions/fixtures/** -text
13 changes: 13 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ pub struct SessionEquivalentForecastSnapshot {
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ProviderUsageSnapshot {
pub tertiary_label: Option<String>,
pub provider_id: String,
pub display_name: String,
pub primary: RateWindowSnapshot,
Expand Down Expand Up @@ -214,6 +215,17 @@ impl ProviderUsageSnapshot {
.tertiary
.as_ref()
.map(RateWindowSnapshot::from_rate_window),
// F5 (upstream 0.48.0): label the tertiary lane by its duration cadence
// so surfaces (MenuCard, CLI, tray) can show "Monthly" instead of the
// generic "DetailWindowTertiary" slot key.
tertiary_label: usage.tertiary.as_ref().map(|w| {
match codexbar::core::RateWindowCadence::from_minutes(w.window_minutes.unwrap_or(0))
.label_key()
{
"monthly" => "monthly".to_string(),
other => other.to_string(),
}
}),
extra_rate_windows: usage
.extra_rate_windows
.iter()
Expand Down Expand Up @@ -272,6 +284,7 @@ impl ProviderUsageSnapshot {
secondary_label: None,
model_specific: None,
tertiary: None,
tertiary_label: None,
extra_rate_windows: Vec::new(),
cost: None,
plan_name: None,
Expand Down
1 change: 1 addition & 0 deletions apps/desktop-tauri/src-tauri/src/commands/chart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ fn scan_local_cost(
match provider_id {
"codex" => Some(scanner.scan_codex_with_cancel(cancel)),
"claude" => Some(scanner.scan_claude_with_cancel(cancel)),
"opencodego" => Some(scanner.scan_opencodego_with_cancel(cancel)),
_ => None,
}
}
Expand Down
172 changes: 172 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,15 @@ async fn refresh_provider(
None
} else {
let snapshot = preserve_last_good_transient_failure(&mut guard, id, snapshot);
// F6 (upstream 0.48.0): backfill missing reset timestamps from the
// cached snapshot before persisting and publishing.
let cached = guard
.provider_cache
.iter()
.find(|c| c.provider_id == snapshot.provider_id && c.error.is_none())
.cloned();
let mut snapshot = snapshot;
codex_reset_backfill(&mut snapshot, cached.as_ref());
upsert_provider_cache(&mut guard.provider_cache, snapshot.clone());
Some(snapshot)
}
Expand All @@ -400,6 +409,66 @@ async fn refresh_provider(
}
}

/// F6 (upstream 0.48.0 UsageStore+CodexResetBackfill): backfill missing
/// `resets_at` / `reset_description` on fresh Codex windows from the cached
/// lane data when the cached reset is still future. Fresh `used_percent` is
/// untouched; only the reset timestamp/description are backfilled.
///
/// This is Codex-scoped by design (upstream: "Provider-specific by design"):
/// other providers do not carry bounded resume state.
///
/// Applies to the bridge snapshot before publishing so every surface (tray,
/// CLI, frontend) sees the backfilled reset instead of a missing one.
pub(super) fn codex_reset_backfill(
snapshot: &mut ProviderUsageSnapshot,
cached: Option<&ProviderUsageSnapshot>,
) {
let Some(cached) = cached else { return };
if snapshot.provider_id != "codex" {
return;
}

// Backfill each slot from the corresponding cached slot.
backfill_slot_window(&mut snapshot.primary, &cached.primary);
if let (Some(fresh), Some(cached_sec)) = (&mut snapshot.secondary, &cached.secondary) {
backfill_slot_window(fresh, cached_sec);
}
// Tertiary (monthly/other): the Codex bridge doesn't normally populate this,
// but the slot exists for forward-compat. Backfill when available.
if let (Some(fresh), Some(cached_ter)) = (&mut snapshot.tertiary, &cached.tertiary) {
backfill_slot_window(fresh, cached_ter);
}
}

/// Backfill `resets_at` and `reset_description` on a fresh window from the
/// cached window whose reset is still in the future. `used_percent` is never
/// overwritten (upstream: "fresh used_percent untouched").
fn backfill_slot_window(
fresh: &mut bridge::RateWindowSnapshot,
cached: &bridge::RateWindowSnapshot,
) {
if fresh.resets_at.is_some() {
return;
}
let Some(cached_reset) = &cached.resets_at else {
return;
};
// Only backfill when the cached reset is still future — a stale reset is
// worse than a missing one.
if let Ok(cached_dt) = chrono::DateTime::parse_from_rfc3339(cached_reset) {
if cached_dt <= chrono::Utc::now() {
return;
}
} else {
return;
}
fresh.resets_at = Some(cached_reset.clone());
fresh.reset_description = fresh
.reset_description
.clone()
.or_else(|| cached.reset_description.clone());
}

pub(super) fn preserve_last_good_transient_failure(
guard: &mut AppState,
id: ProviderId,
Expand Down Expand Up @@ -938,3 +1007,106 @@ mod predictive_warning_tests {
assert_eq!(quota_notification_account_identity(&snapshot, None), "");
}
}

#[cfg(test)]
mod reset_backfill_tests {
use super::*;
use crate::commands::bridge::{ProviderUsageSnapshot, RateWindowSnapshot};

fn win(used: f64, resets_at: Option<&str>) -> RateWindowSnapshot {
RateWindowSnapshot {
used_percent: used,
remaining_percent: 100.0 - used,
window_minutes: Some(300),
resets_at: resets_at.map(String::from),
reset_description: None,
is_exhausted: false,
is_informational: false,
reserve_percent: None,
reserve_description: None,
reserve_will_last_to_reset: false,
reserve_eta_seconds: None,
}
}

fn codex_snapshot(primary: RateWindowSnapshot) -> ProviderUsageSnapshot {
ProviderUsageSnapshot {
provider_id: "codex".into(),
display_name: "Codex".into(),
primary,
primary_label: None,
secondary: None,
secondary_label: None,
model_specific: None,
tertiary: None,
tertiary_label: None,
extra_rate_windows: Vec::new(),
cost: None,
plan_name: None,
account_email: None,
source_label: String::new(),
updated_at: "2026-01-01T00:00:00Z".into(),
error: None,
pace: None,
account_organization: None,
tray_status_label: None,
fetch_duration_ms: None,
wayfinder_usage: None,
session_equivalent_forecast: None,
}
}

#[test]
fn f6_backfills_future_cached_reset() {
// Cached has a future resets_at; fresh has none → backfilled.
let future = (chrono::Utc::now() + chrono::Duration::hours(2)).to_rfc3339();
let cached = codex_snapshot(win(50.0, Some(&future)));
let mut fresh = codex_snapshot(win(30.0, None));
codex_reset_backfill(&mut fresh, Some(&cached));
assert_eq!(fresh.primary.resets_at.as_deref(), Some(future.as_str()));
// used_percent is NOT overwritten.
assert!((fresh.primary.used_percent - 30.0).abs() < f64::EPSILON);
}

#[test]
fn f6_does_not_backfill_stale_cached_reset() {
// Cached reset is in the past → not backfilled.
let past = (chrono::Utc::now() - chrono::Duration::hours(2)).to_rfc3339();
let cached = codex_snapshot(win(50.0, Some(&past)));
let mut fresh = codex_snapshot(win(30.0, None));
codex_reset_backfill(&mut fresh, Some(&cached));
assert!(
fresh.primary.resets_at.is_none(),
"stale reset not backfilled"
);
}

#[test]
fn f6_does_not_overwrite_existing_resets_at() {
// Fresh already has resets_at → cached not applied.
let future1 = (chrono::Utc::now() + chrono::Duration::hours(3)).to_rfc3339();
let future2 = (chrono::Utc::now() + chrono::Duration::hours(5)).to_rfc3339();
let cached = codex_snapshot(win(50.0, Some(&future2)));
let mut fresh = codex_snapshot(win(30.0, Some(&future1)));
codex_reset_backfill(&mut fresh, Some(&cached));
assert_eq!(fresh.primary.resets_at.as_deref(), Some(future1.as_str()));
}

#[test]
fn f6_skips_non_codex_provider() {
let future = (chrono::Utc::now() + chrono::Duration::hours(2)).to_rfc3339();
let mut cached = codex_snapshot(win(50.0, Some(&future)));
cached.provider_id = "claude".into();
let mut fresh = codex_snapshot(win(30.0, None));
fresh.provider_id = "claude".into();
codex_reset_backfill(&mut fresh, Some(&cached));
assert!(fresh.primary.resets_at.is_none(), "non-codex skip");
}

#[test]
fn f6_skips_when_no_cached_snapshot() {
let mut fresh = codex_snapshot(win(30.0, None));
codex_reset_backfill(&mut fresh, None);
assert!(fresh.primary.resets_at.is_none());
}
}
29 changes: 29 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ pub struct UsageSpendRow {
pub thirty_day: Option<f64>,
pub currency: String,
pub source: String,
/// F8 (upstream 0.48.0): true when the totals are served from a stale cache
/// while a background re-scan rebuilds the artifact. Frontend shows a
/// "refreshing" indicator.
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub refreshing: bool,
/// ISO 8601 timestamp of the stale snapshot (when `refreshing` is true).
#[serde(skip_serializing_if = "Option::is_none")]
pub stale_updated_at: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
Expand All @@ -42,6 +50,21 @@ pub async fn get_usage_spend_summary(
fn build_usage_spend_summary(cached: &[ProviderUsageSnapshot]) -> UsageSpendSummary {
let mut rows = Vec::new();

// F8 (upstream 0.48.0): check codex cache staleness before scanning. When the
// debounce has expired, the scan below will rebuild the cache — mark the row
// as refreshing and include the stale timestamp so the UI shows the indicator.
let codex_cache =
codexbar::core::JsonlScanner::load_cache(codexbar::core::ProviderId::Codex, None);
let codex_stale = !codex_cache.days.is_empty() && codex_cache.previous_report.is_some();
let codex_stale_updated_at = if codex_stale {
codex_cache
.previous_report
.as_ref()
.and_then(|r| r.updated_at.clone())
} else {
None
};

// Local JSONL scanners for Codex / Claude (primary spend sources).
let codex_7 = CostScanner::new(7).scan_codex().total_cost_usd;
let codex_30 = CostScanner::new(30).scan_codex().total_cost_usd;
Expand All @@ -52,6 +75,8 @@ fn build_usage_spend_summary(cached: &[ProviderUsageSnapshot]) -> UsageSpendSumm
thirty_day: Some(codex_30),
currency: "USD".into(),
source: "local logs".into(),
refreshing: codex_stale,
stale_updated_at: codex_stale_updated_at,
});

let claude_7 = CostScanner::new(7).scan_claude().total_cost_usd;
Expand All @@ -63,6 +88,8 @@ fn build_usage_spend_summary(cached: &[ProviderUsageSnapshot]) -> UsageSpendSumm
thirty_day: Some(claude_30),
currency: "USD".into(),
source: "local logs".into(),
refreshing: false,
stale_updated_at: None,
});

// Surface any other provider cost snapshots from the last refresh (period
Expand All @@ -81,6 +108,8 @@ fn build_usage_spend_summary(cached: &[ProviderUsageSnapshot]) -> UsageSpendSumm
} else {
snapshot.display_name.clone()
},
refreshing: false,
stale_updated_at: None,
seven_day: None,
thirty_day: Some(cost.used),
currency: cost.currency_code.clone(),
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop-tauri/src-tauri/src/powertoys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ mod tests {
secondary_label: None,
model_specific: None,
tertiary: None,
tertiary_label: None,
extra_rate_windows: Vec::new(),
cost: None,
plan_name: Some("Team".to_string()),
Expand Down Expand Up @@ -237,6 +238,7 @@ mod tests {
secondary_label: None,
model_specific: None,
tertiary: None,
tertiary_label: None,
extra_rate_windows: Vec::new(),
cost: None,
plan_name: None,
Expand Down
Loading
Loading