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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
- **Settings**: `%config%/CodexBar/settings.json` via `Settings::load` / `save` and `secure_file` (DPAPI-capable on Windows). Frontend `updateSettings` patch → save → `codexbar:settings-updated` / float-bar config events.
- **Tray**: `tray_bridge` + `tray_menu`. Icon pixels from shared `codexbar::tray::{render_bar_icon_rgba, render_percent_icon_rgba}`.
- **Float bar**: `floatbar/` owns the auxiliary always-on-top window. The builder must pin `.theme(Some(tauri::Theme::Dark))` — WebView2 resolves `prefers-color-scheme` on a shared process profile; an unpinned window flips other webviews under theme `auto`.
- **Proof harness**: env `CODEXBAR_PROOF_MODE` (e.g. `settings:menu`) opens a target surface and suppresses blur-dismiss for automation / CUA capture.
- **Proof harness**: env `CODEXBAR_PROOF_MODE` (e.g. `settings:menu`) opens a target surface and suppresses blur-dismiss for automation / CUA capture. `CODEXBAR_SEED_USAGE_JSON=<abs-path>` seeds one synthetic bridge-shaped Codex `ProviderUsageSnapshot` into the provider cache at launch (pinned against refresh eviction; malformed files are warned about and skipped).

## Key Directories

Expand Down
86 changes: 77 additions & 9 deletions apps/desktop-tauri/src-tauri/src/commands/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,39 @@ use super::*;

// ── Bridge snapshot types ────────────────────────────────────────────

#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RateWindowSnapshot {
pub used_percent: f64,
/// Defaults to `100.0` when absent in JSON (e.g. proof-seed files).
#[serde(default = "default_full_remaining")]
pub remaining_percent: f64,
#[serde(default)]
pub window_minutes: Option<u32>,
#[serde(default)]
pub resets_at: Option<String>,
#[serde(default)]
pub reset_description: Option<String>,
#[serde(default)]
pub is_exhausted: bool,
#[serde(default)]
pub is_informational: bool,
#[serde(default)]
pub reserve_percent: Option<f64>,
#[serde(default)]
pub reserve_description: Option<String>,
#[serde(default)]
pub reserve_will_last_to_reset: bool,
#[serde(default)]
pub reserve_eta_seconds: Option<f64>,
}

/// Serde default for [`RateWindowSnapshot::remaining_percent`] — the common
/// case for a fresh window (0 %% used → 100 %% remaining).
fn default_full_remaining() -> f64 {
100.0
}

impl RateWindowSnapshot {
pub(super) fn from_rate_window(rw: &RateWindow) -> Self {
Self {
Expand Down Expand Up @@ -50,22 +67,41 @@ impl RateWindowSnapshot {
}
}

#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CostSnapshotBridge {
pub used: f64,
#[serde(default)]
pub limit: Option<f64>,
#[serde(default)]
pub remaining: Option<f64>,
#[serde(default = "default_currency")]
pub currency_code: String,
#[serde(default = "default_cost_period")]
pub period: String,
#[serde(default)]
pub resets_at: Option<String>,
/// Defaults to `format!("${:.2}", used)` when absent (filled by
/// [`parse_seed_usage_snapshot`](crate::proof_harness::parse_seed_usage_snapshot)).
#[serde(default)]
pub formatted_used: String,
#[serde(default)]
pub formatted_limit: Option<String>,
#[serde(default)]
pub balance: Option<f64>,
#[serde(default)]
pub formatted_balance: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
fn default_currency() -> String {
"USD".to_string()
}

fn default_cost_period() -> String {
"month".to_string()
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NamedRateWindowSnapshot {
pub id: String,
Expand All @@ -74,19 +110,23 @@ pub struct NamedRateWindowSnapshot {
}

/// Pace prediction snapshot for tray/bridge display.
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PaceSnapshot {
pub stage: &'static str,
pub stage: String,
pub delta_percent: f64,
#[serde(default)]
pub will_last_to_reset: bool,
#[serde(default)]
pub eta_seconds: Option<f64>,
#[serde(default)]
pub expected_used_percent: f64,
#[serde(default)]
pub actual_used_percent: f64,
}

/// Session-equivalent weekly forecast for Claude/Codex menu secondary line.
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SessionEquivalentForecastSnapshot {
pub estimated_windows_to_exhaust_weekly: f64,
Expand All @@ -98,34 +138,62 @@ pub struct SessionEquivalentForecastSnapshot {
}

/// A frontend-friendly snapshot of one provider's usage data.
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProviderUsageSnapshot {
#[serde(default)]
pub tertiary_label: Option<String>,
pub provider_id: String,
#[serde(default = "default_display_name")]
pub display_name: String,
pub primary: RateWindowSnapshot,
#[serde(default)]
pub primary_label: Option<String>,
#[serde(default)]
pub secondary: Option<RateWindowSnapshot>,
#[serde(default)]
pub secondary_label: Option<String>,
#[serde(default)]
pub model_specific: Option<RateWindowSnapshot>,
#[serde(default)]
pub tertiary: Option<RateWindowSnapshot>,
#[serde(default)]
pub extra_rate_windows: Vec<NamedRateWindowSnapshot>,
#[serde(default)]
pub cost: Option<CostSnapshotBridge>,
#[serde(default)]
pub plan_name: Option<String>,
#[serde(default)]
pub account_email: Option<String>,
#[serde(default = "default_source_label")]
pub source_label: String,
/// Defaults to launch time when absent so the card renders as fresh.
#[serde(default)]
pub updated_at: String,
#[serde(default)]
pub error: Option<String>,
#[serde(default)]
pub pace: Option<PaceSnapshot>,
#[serde(default)]
pub account_organization: Option<String>,
#[serde(default)]
pub tray_status_label: Option<String>,
#[serde(default)]
pub fetch_duration_ms: Option<u128>,
#[serde(default)]
pub wayfinder_usage: Option<codexbar::core::WayfinderUsageSnapshot>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(skip_serializing_if = "Option::is_none", default)]
pub session_equivalent_forecast: Option<SessionEquivalentForecastSnapshot>,
}

fn default_display_name() -> String {
"Codex".to_string()
}

fn default_source_label() -> String {
"seed".to_string()
}

/// Provider payload after applying settings-driven cross-surface presentation.
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -190,7 +258,7 @@ impl ProviderUsageSnapshot {
.and_then(|window| codexbar::core::UsagePace::weekly(window, None, 10080));

let pace = primary_pace.as_ref().map(|p| PaceSnapshot {
stage: pace_stage_str(p.stage),
stage: pace_stage_str(p.stage).to_string(),
delta_percent: p.delta_percent,
will_last_to_reset: p.will_last_to_reset,
eta_seconds: p.eta_seconds,
Expand Down
6 changes: 6 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,12 @@ fn begin_provider_refresh(
}

fn provider_cache_can_skip_refresh(guard: &AppState, force: bool) -> bool {
// Proof-harness seed: pin the synthetic snapshot for the whole run so a
// periodic auto-refresh cannot overwrite seeded capture conditions.
if !force && crate::proof_harness::seed_usage_json_active() && !guard.provider_cache.is_empty()
{
return true;
}
!force
&& !guard.provider_cache.is_empty()
&& is_provider_cache_fresh(guard.provider_cache_updated_at, PROVIDER_CACHE_STALE_AFTER)
Expand Down
12 changes: 12 additions & 0 deletions apps/desktop-tauri/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@ fn main() {

let mut initial_state = AppState::new();
initial_state.proof_config = proof_config;
// Proof-harness seed: CODEXBAR_SEED_USAGE_JSON plants one synthetic Codex
// ProviderUsageSnapshot before the event loop and any WebView read. The
// cache timestamp makes the seeded cache count as fresh so the first
// frontend refresh-if-stale call does not evict the synthetic data.
if let Some(snapshot) = proof_harness::seed_usage_snapshot_from_env() {
tracing::info!(
"proof-harness: seeded provider snapshot for '{}'",
snapshot.provider_id
);
initial_state.provider_cache.push(snapshot);
initial_state.provider_cache_updated_at = Some(std::time::Instant::now());
}

tauri::Builder::default()
.manage(Mutex::new(initial_state))
Expand Down
Loading
Loading