From efff8b91d7a53bb97bb81c87d2b9da937b494931 Mon Sep 17 00:00:00 2001 From: NessZerra <90105158+Finesssee@users.noreply.github.com> Date: Sun, 6 Sep 2026 11:22:20 +0700 Subject: [PATCH 1/6] Port upstream CodexBar 0.56.0 (#421) * Port upstream 0.55.1: align provider usage surfaces * Port upstream 0.55.1: prefer Bailian CLI token plan * Port upstream 0.55.1: scan OpenCodex logs incrementally * Port upstream 0.55.1: preserve Codex reset and catch-up state * Port upstream 0.55.1: isolate OpenCodex cache state * Port upstream 0.55.1: update Turkish translations * Port upstream 0.55.1: generalize usage source settings * Port upstream 0.55.1: rename generic usage source component * Fix upstream 0.55.1 Rust compile regressions * Fix OpenCodex Windows file identity * Fix OpenCodex cache report test call * Restore scanner source encoding * Fix upstream 0.55.1 Clippy findings * Fix OpenCodex newline test lint * Update Turkish locale regression expectation * Port upstream 0.56.0: honor Codex token expiry * Port upstream 0.56.0: read Antigravity SQLite history * Port upstream 0.56.0: honor Codex token expiry * Port upstream 0.56.0: finish Antigravity history and quota cadence * Port upstream 0.56.0: estimate Cursor API-rate costs * Port upstream 0.56.0: isolate Grok browser identity * Port upstream 0.56.0: clarify OpenRouter key caps * Port upstream 0.56.0: narrow cached Codex status reads * Fix Antigravity epoch conversion lint * Fix 0.56.0 review findings * Fix reset inventory regression test * Localize API spend label * Keep Antigravity cadence labels provider-owned * Fix Antigravity cadence label test --------- Co-authored-by: NessZerra Co-authored-by: Mohamed Mohsen --- .../src-tauri/src/commands/bridge.rs | 13 +- .../src/commands/provider_settings.rs | 3 +- .../src-tauri/src/commands/usage_spend.rs | 21 +- .../src-tauri/src/tray_bridge.rs | 1 + .../src/components/MenuCard.test.tsx | 28 + .../src/components/MenuCardDetails.tsx | 14 +- apps/desktop-tauri/src/i18n/keys.ts | 1 + .../settings/providers/ProviderDetailPane.tsx | 20 +- .../sections/MenuBarMetricSection.test.tsx | 30 + .../sections/UsageSourceSection.test.tsx | 44 + ...urceSection.tsx => UsageSourceSection.tsx} | 32 +- apps/desktop-tauri/src/types/bridge.ts | 2 + rust/Cargo.toml | 1 + rust/src/cli/usage.rs | 22 +- rust/src/core/jsonl_scanner.rs | 227 +++++- rust/src/core/usage_snapshot.rs | 24 + rust/src/host/command_runner.rs | 42 +- rust/src/locale.rs | 1 + rust/src/locale/en-US.ftl | 1 + rust/src/locale/es-MX.ftl | 1 + rust/src/locale/ja-JP.ftl | 1 + rust/src/locale/ko-KR.ftl | 1 + rust/src/locale/ru-RU.ftl | 1 + rust/src/locale/tests.rs | 2 +- rust/src/locale/tr-TR.ftl | 73 +- rust/src/locale/zh-CN.ftl | 1 + rust/src/locale/zh-TW.ftl | 1 + rust/src/providers/alibabatokenplan/cli.rs | 277 +++++++ rust/src/providers/alibabatokenplan/mod.rs | 56 +- rust/src/providers/alibabatokenplan/region.rs | 7 + rust/src/providers/amp/mod.rs | 21 + rust/src/providers/antigravity/local_proto.rs | 267 ++++++ .../providers/antigravity/local_sessions.rs | 209 ++++- .../src/providers/antigravity/local_sqlite.rs | 570 +++++++++++++ rust/src/providers/antigravity/mod.rs | 223 ++++-- .../providers/antigravity/quota_summary.rs | 317 ++++++++ rust/src/providers/antigravity/tests.rs | 9 + rust/src/providers/codex/api.rs | 263 +++++- rust/src/providers/codex/mod.rs | 1 + rust/src/providers/codex/weekly_reset.rs | 758 ++++++++++++++++++ rust/src/providers/cursor/token_cost.rs | 515 +++++++++--- rust/src/providers/fireworks/mod.rs | 2 +- rust/src/providers/grok/mod.rs | 34 +- rust/src/providers/openrouter/activity.rs | 57 +- rust/src/providers/openrouter/mod.rs | 36 +- rust/src/spend_contract/opencodex.rs | 210 +++-- rust/src/spend_contract/opencodex/cache.rs | 423 ++++++++++ 47 files changed, 4419 insertions(+), 444 deletions(-) create mode 100644 apps/desktop-tauri/src/surfaces/settings/providers/sections/UsageSourceSection.test.tsx rename apps/desktop-tauri/src/surfaces/settings/providers/sections/{GrokUsageSourceSection.tsx => UsageSourceSection.tsx} (74%) create mode 100644 rust/src/providers/alibabatokenplan/cli.rs create mode 100644 rust/src/providers/antigravity/local_proto.rs create mode 100644 rust/src/providers/antigravity/local_sqlite.rs create mode 100644 rust/src/providers/antigravity/quota_summary.rs create mode 100644 rust/src/providers/codex/weekly_reset.rs create mode 100644 rust/src/spend_contract/opencodex/cache.rs diff --git a/apps/desktop-tauri/src-tauri/src/commands/bridge.rs b/apps/desktop-tauri/src-tauri/src/commands/bridge.rs index 841756b9b1..2edf24acd4 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/bridge.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/bridge.rs @@ -102,6 +102,8 @@ pub struct CostSnapshotBridge { pub formatted_balance: Option, #[serde(default)] pub daily: Vec, + #[serde(default)] + pub always_visible: bool, } fn default_currency() -> String { @@ -333,10 +335,12 @@ impl ProviderUsageSnapshot { .unwrap_or_else(|| metadata.session_label.to_string()), ), secondary: secondary_snap, - secondary_label: usage - .secondary - .as_ref() - .map(|_| metadata.weekly_label.to_string()), + secondary_label: usage.secondary.as_ref().map(|_| { + usage + .secondary_label + .clone() + .unwrap_or_else(|| metadata.weekly_label.to_string()) + }), model_specific: usage .model_specific .as_ref() @@ -385,6 +389,7 @@ impl ProviderUsageSnapshot { amount: point.amount, }) .collect(), + always_visible: c.always_visible, }), plan_name: usage.login_method.clone(), account_email: usage.account_email.clone(), diff --git a/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs b/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs index 3fff45473d..ddf94f30dd 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs @@ -137,6 +137,7 @@ fn cookie_source_provider(provider_id: &str) -> Option ProviderId::OpenCode, "factory" => ProviderId::Factory, "alibaba" => ProviderId::Alibaba, + "alibabatokenplan" => ProviderId::AlibabaTokenPlan, "kimi" | "kimik2" => ProviderId::Kimi, "minimax" => ProviderId::MiniMax, "augment" => ProviderId::Augment, @@ -547,7 +548,7 @@ pub fn cookie_source_options_for(provider_id: &str, lang: Language) -> Vec vec![ + "alibaba" | "alibabatokenplan" => vec![ cookie_option( lang, "auto", diff --git a/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs b/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs index 23384b5aae..28c74bab5b 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs @@ -179,15 +179,15 @@ fn build_usage_spend_summary( let include_opencodex = settings.open_codex_usage_logs_enabled; let hide_native = settings.hide_native_codex_cost_when_open_codex_present; - 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_cache_status = + codexbar::core::JsonlScanner::load_cache_status(codexbar::core::ProviderId::Codex, None); + let codex_stale = codex_cache_status.has_days && codex_cache_status.previous_report.is_some(); let codex_stale_updated_at = codex_stale .then(|| { - codex_cache + codex_cache_status .previous_report .as_ref() - .and_then(|r| r.updated_at.clone()) + .and_then(|report| report.updated_at.clone()) }) .flatten(); @@ -351,13 +351,16 @@ fn build_usage_spend_summary( spend } "antigravity" => { + use codexbar::providers::antigravity::local_sessions::LocalHistoryCoverage; let seven = codexbar::providers::antigravity::local_sessions::summarize(7); let thirty = codexbar::providers::antigravity::local_sessions::summarize(30); let mut spend = cached_spend(cached_snapshot); - spend.seven_day_tokens = (seven.session_count > 0).then_some(seven.total_tokens); - spend.thirty_day_tokens = (thirty.session_count > 0).then_some(thirty.total_tokens); - if thirty.session_count > 0 { - spend.source = "local Antigravity sessions".to_string(); + spend.seven_day_tokens = matches!(seven.coverage, LocalHistoryCoverage::Complete) + .then_some(seven.total_tokens); + spend.thirty_day_tokens = matches!(thirty.coverage, LocalHistoryCoverage::Complete) + .then_some(thirty.total_tokens); + if matches!(thirty.coverage, LocalHistoryCoverage::Complete) { + spend.source = "local Antigravity history".to_string(); } spend } diff --git a/apps/desktop-tauri/src-tauri/src/tray_bridge.rs b/apps/desktop-tauri/src-tauri/src/tray_bridge.rs index 53580a36cf..e0b38d55cf 100644 --- a/apps/desktop-tauri/src-tauri/src/tray_bridge.rs +++ b/apps/desktop-tauri/src-tauri/src/tray_bridge.rs @@ -1079,6 +1079,7 @@ mod tests { balance: None, formatted_balance: None, daily: Vec::new(), + always_visible: false, }), plan_name: None, account_email: None, diff --git a/apps/desktop-tauri/src/components/MenuCard.test.tsx b/apps/desktop-tauri/src/components/MenuCard.test.tsx index c7838cf8e6..bed4d2ca6f 100644 --- a/apps/desktop-tauri/src/components/MenuCard.test.tsx +++ b/apps/desktop-tauri/src/components/MenuCard.test.tsx @@ -86,6 +86,7 @@ function renderCard( showResetWhenExhausted?: boolean; showPace?: boolean; onLayoutChange?: () => void; + costSummaryDisplayStyle?: "compact" | "detailed" | "hidden"; } = {}, ) { return render( @@ -98,6 +99,7 @@ function renderCard( showAsUsed: opts.showAsUsed, showResetWhenExhausted: opts.showResetWhenExhausted, showPace: opts.showPace, + costSummaryDisplayStyle: opts.costSummaryDisplayStyle, }} onLayoutChange={opts.onLayoutChange} /> @@ -111,6 +113,7 @@ describe("MenuCard", () => { tauriMocks.getLocaleStrings.mockResolvedValue( buildBundle({ ActionCopyError: "Copy error", + ApiSpendTitle: "API spend", DetailPaceRunsOutIn: "Runs out in", PanelEstimatedFromLocalLogs: "Estimated from local logs", PanelLeftSuffix: "left", @@ -167,6 +170,31 @@ describe("MenuCard", () => { eventMocks.listen.mockResolvedValue(() => {}); }); + it("keeps Fireworks vendor API spend visible when local cost summaries are hidden", async () => { + const snapshot = provider(null, 0); + snapshot.providerId = "fireworks"; + snapshot.displayName = "Fireworks"; + snapshot.cost = { + used: 12.34, + limit: null, + remaining: null, + currencyCode: "USD", + currencySymbol: "$", + period: "30 days", + resetsAt: null, + formattedUsed: "$12.34", + formattedLimit: null, + balance: null, + formattedBalance: null, + daily: [], + alwaysVisible: true, + }; + + renderCard(snapshot, { costSummaryDisplayStyle: "hidden" }); + + expect(await screen.findByText("API spend")).toBeInTheDocument(); + expect(document.querySelector(".menu-card__cost-line")).toHaveTextContent("$12.34"); + }); it("does not mix stale local usage into an error card", async () => { const { container } = renderCard( provider("OAuth error: Claude OAuth credentials not found."), diff --git a/apps/desktop-tauri/src/components/MenuCardDetails.tsx b/apps/desktop-tauri/src/components/MenuCardDetails.tsx index 4ef58e3d1c..0e1ed9f738 100644 --- a/apps/desktop-tauri/src/components/MenuCardDetails.tsx +++ b/apps/desktop-tauri/src/components/MenuCardDetails.tsx @@ -453,7 +453,9 @@ export function describeCard( const localUsage = provider.error ? null : chartData?.localUsage ?? null; const wayfinderUsage = isWayfinder ? provider.wayfinderUsage : null; const hasMetrics = visibleMetrics.length > 0; - const hasCost = !!provider.cost && costSummaryDisplayStyle !== "hidden"; + const hasCost = + !!provider.cost && + (costSummaryDisplayStyle !== "hidden" || provider.cost.alwaysVisible === true); const hasPace = showPace && !!provider.pace; const hasDetails = !provider.error && @@ -538,13 +540,15 @@ export default function MenuCardDetails({ /> )} - {hasMetrics && hasCost && costStyle !== "hidden" &&
} + {hasMetrics && hasCost &&
} - {provider.cost && costStyle !== "hidden" && ( + {hasCost && provider.cost && (
- {provider.cost.balance != null && provider.cost.limit == null - ? provider.cost.period || t("CreditsLabel") + {provider.cost.alwaysVisible === true && (provider.cost.limit ?? 0) <= 0 + ? t("ApiSpendTitle") + : provider.cost.balance != null && provider.cost.limit == null + ? provider.cost.period || t("CreditsLabel") : `${t("DetailCostTitle")} — ${provider.cost.period}`}
{provider.cost.balance != null && provider.cost.limit == null ? ( diff --git a/apps/desktop-tauri/src/i18n/keys.ts b/apps/desktop-tauri/src/i18n/keys.ts index ac2b06c784..2da4c36537 100644 --- a/apps/desktop-tauri/src/i18n/keys.ts +++ b/apps/desktop-tauri/src/i18n/keys.ts @@ -570,6 +570,7 @@ export const ALL_LOCALE_KEYS = [ "DetailPaceRunsOutIn", "DetailPaceWillLastToReset", "DetailCostTitle", + "ApiSpendTitle", "DetailCostUsed", "DetailCostLimit", "DetailCostRemaining", diff --git a/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx b/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx index 29ff8c4d50..b630d859ec 100644 --- a/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx +++ b/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx @@ -28,7 +28,7 @@ import { CostSection } from "./sections/CostSection"; import { QuickActionsSection } from "./sections/QuickActionsSection"; import { ChartsSection } from "./sections/charts/ChartsSection"; import { CookieSourceSection } from "./sections/CookieSourceSection"; -import { GrokUsageSourceSection } from "./sections/GrokUsageSourceSection"; +import { UsageSourceSection } from "./sections/UsageSourceSection"; import { RegionSection } from "./sections/RegionSection"; import { CodexUsageOptions } from "./sections/credentials/CodexUsageOptions"; import { CodexAccountsSection } from "./sections/credentials/CodexAccountsSection"; @@ -302,19 +302,21 @@ export function ProviderDetailPane({ - - + {!(detail.id === "alibabatokenplan" && detail.usageSource === "cli") && ( + + )} { + it("offers Monthly for OpenCode Go only after a tertiary window is observed", () => { + const base = provider(false); + base.id = "opencodego"; + base.displayName = "OpenCode Go"; + base.tertiary = null; + const { rerender } = render( + key} + onChange={vi.fn()} + />, + ); + + expect(screen.queryByRole("option", { name: "DetailWindowTertiary" })).not.toBeInTheDocument(); + + const observed = { ...base, tertiary: rateWindow(37) }; + rerender( + key} + onChange={vi.fn()} + />, + ); + + expect(screen.getByRole("option", { name: "DetailWindowTertiary" })).toBeInTheDocument(); + }); it("offers extra usage when a provider has extra rate windows", () => { const onChange = vi.fn(); render( diff --git a/apps/desktop-tauri/src/surfaces/settings/providers/sections/UsageSourceSection.test.tsx b/apps/desktop-tauri/src/surfaces/settings/providers/sections/UsageSourceSection.test.tsx new file mode 100644 index 0000000000..cfbe9ac2c8 --- /dev/null +++ b/apps/desktop-tauri/src/surfaces/settings/providers/sections/UsageSourceSection.test.tsx @@ -0,0 +1,44 @@ +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +const tauriMocks = vi.hoisted(() => ({ + setProviderUsageSource: vi.fn(), +})); + +vi.mock("../../../../lib/tauri", () => tauriMocks); + +import { UsageSourceSection } from "./UsageSourceSection"; + +describe("UsageSourceSection", () => { + it("offers Bailian Auto, CLI, and Web and persists explicit CLI selection", async () => { + const onChanged = vi.fn(); + tauriMocks.setProviderUsageSource.mockResolvedValue(undefined); + + render( + key} + onChanged={onChanged} + />, + ); + + expect(screen.getByRole("radio", { name: "Auto" })).toHaveAttribute("aria-checked", "true"); + expect(screen.getByRole("radio", { name: "Bailian CLI" })).toBeInTheDocument(); + expect(screen.getByRole("radio", { name: "Browser cookies" })).toBeInTheDocument(); + + fireEvent.click(screen.getByRole("radio", { name: "Bailian CLI" })); + + await waitFor(() => { + expect(tauriMocks.setProviderUsageSource).toHaveBeenCalledWith("alibabatokenplan", "cli"); + expect(onChanged).toHaveBeenCalledTimes(1); + }); + }); + + it("does not render for unrelated providers", () => { + const { container } = render( + key} onChanged={vi.fn()} />, + ); + expect(container).toBeEmptyDOMElement(); + }); +}); diff --git a/apps/desktop-tauri/src/surfaces/settings/providers/sections/GrokUsageSourceSection.tsx b/apps/desktop-tauri/src/surfaces/settings/providers/sections/UsageSourceSection.tsx similarity index 74% rename from apps/desktop-tauri/src/surfaces/settings/providers/sections/GrokUsageSourceSection.tsx rename to apps/desktop-tauri/src/surfaces/settings/providers/sections/UsageSourceSection.tsx index 27233928b0..2c11622521 100644 --- a/apps/desktop-tauri/src/surfaces/settings/providers/sections/GrokUsageSourceSection.tsx +++ b/apps/desktop-tauri/src/surfaces/settings/providers/sections/UsageSourceSection.tsx @@ -31,8 +31,26 @@ const GROK_OPTIONS = [ description: "Uses the configured grok.com browser session only.", }, ] as const; +const ALIBABA_TOKEN_PLAN_OPTIONS = [ + { + value: "auto", + label: "Auto", + description: "Tries the signed-in Bailian CLI first, then browser cookies.", + }, + { + value: "cli", + label: "Bailian CLI", + description: "Uses the locally signed-in Bailian CLI only.", + }, + { + value: "web", + label: "Browser cookies", + description: "Uses the configured Model Studio / Bailian browser session only.", + }, +] as const; + -export function GrokUsageSourceSection({ +export function UsageSourceSection({ providerId, currentValue, t, @@ -41,10 +59,16 @@ export function GrokUsageSourceSection({ const [busy, setBusy] = useState(false); const [error, setError] = useState(null); - if (providerId !== "grok") return null; + const options = + providerId === "grok" + ? GROK_OPTIONS + : providerId === "alibabatokenplan" + ? ALIBABA_TOKEN_PLAN_OPTIONS + : null; + if (!options) return null; const selected = currentValue ?? "auto"; - const selectedOption = GROK_OPTIONS.find((option) => option.value === selected) ?? GROK_OPTIONS[0]; + const selectedOption = options.find((option) => option.value === selected) ?? options[0]; const handleSelect = async (value: string) => { if (value === selected || busy) return; @@ -64,7 +88,7 @@ export function GrokUsageSourceSection({

{t("UsageSource")}

- {GROK_OPTIONS.map((option) => { + {options.map((option) => { const isActive = option.value === selected; return (