fix(cost): reconcile usage estimates and billing labels#520
fix(cost): reconcile usage estimates and billing labels#520willytop8 wants to merge 5 commits intosteipete:mainfrom
Conversation
Transform CodexBar into a focused 5-provider app targeting Claude Code, OpenAI Codex, Google Gemini, Google Antigravity, and Perplexity. Provider strategy upgrades: - Claude: OAuth-only via api.anthropic.com/api/oauth/usage (no CLI/web fallback) - Codex: CLI RPC only (remove web dashboard scrape) - Gemini: OAuth API + FSEvents watcher on ~/.gemini/ for instant updates - Antigravity: local probe + FSEvents watcher on ~/.codeium/ + 3x retry backoff - Perplexity: new provider — web API with session cookie stored in Keychain Adaptive refresh scheduler: - Active (>50% utilisation): 15s; moderate: 60s; idle: 600s - 120s hysteresis before dropping out of active rate - 429 rate-limit backoff: 300s cooldown, auto-resume Staleness indicators in menu cards: - ✅ green (<30s),⚠️ yellow (30s–5m), ❌ red (>5m or error) - Menu bar dot triggers when any provider is >5m stale - isStale(provider:) now time-based, not error-only Non-target providers: left intact, defaultEnabled: false Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AdaptiveRefreshScheduler now tracks lastRefreshedAt per provider and exposes shouldRefresh()/recordRefresh() so each provider is gated on its own effective interval, not just the global timer tick. Fast local providers (Codex 15 s) no longer drag remote API providers (Claude, Gemini, Perplexity) along at the same cadence. - During a 429 backoff, effectiveInterval returns the remaining backoff time (not a fixed 600 s), so the provider is skipped entirely until the window expires. - Rate-limit backoff (1800 s) and hard remote-API floor (300 s) are now persisted across relaunches via UserDefaults. - ClaudeOAuthFetchStrategy gains isAlwaysAvailable flag; set to true in auto mode so the pipeline always runs fetch() and surfaces real errors instead of the opaque "no available fetch strategy" message. - User-initiated refreshes pass forceAllProviders: true to bypass the per-provider gate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The /api/oauth/usage endpoint is a private beta endpoint built for on-demand queries, not continuous polling. 5-minute polling (12×/hr) was too aggressive. 15 minutes (4×/hr) keeps usage data reasonably fresh while staying well within rate limits. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Raise Claude's minimum polling floor, preserve cached Claude data during 429 backoff, and keep forced refreshes from bypassing active rate-limit cooldowns. Refresh the README fork description, remove internal fork-admin documents, sanitize hard-coded local paths and personal contact details, and delete local junk artifacts before pushing.
|
Closing this in favor of #522, which contains the same fix rebuilt cleanly on top of upstream main as a single commit. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be163eb5ff
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| var request = URLRequest( | ||
| url: URL(string: "https://www.perplexity.ai/rest/user/settings")!, | ||
| timeoutInterval: context.webTimeout) | ||
| request.setValue(cookie, forHTTPHeaderField: "Cookie") |
There was a problem hiding this comment.
Prefix Perplexity cookie name before sending request
The settings UI asks users to paste the __Secure-next-auth.session-token value, but this request sends that raw value directly as the Cookie header. A valid cookie header must be name=value, so users who follow the UI instructions will send an invalid cookie and get unauthenticated responses from https://www.perplexity.ai/rest/user/settings, effectively breaking Perplexity usage fetching unless they manually add the cookie name themselves.
Useful? React with 👍 / 👎.
| let due = self.shouldRefreshProvider( | ||
| provider, | ||
| forceAllProviders: forceAllProviders, | ||
| now: now) |
There was a problem hiding this comment.
Update adaptive scheduler state for token-account refresh path
This new per-provider due gate depends on AdaptiveRefreshScheduler, but providers that go through refreshTokenAccounts (when showAllTokenAccountsInMenu is enabled with multiple accounts) return early in refreshProvider and never call recordRefresh/recordRateLimit. In that mode, the scheduler never advances for that provider, so shouldRefreshProvider keeps it due on every cycle and Claude multi-account setups can still be hammered despite the new long minimum interval and 429 backoff logic.
Useful? React with 👍 / 👎.
Summary
Testing
Notes