feat(opencode): add rolling/weekly/monthly quota display via console scraping - #250
feat(opencode): add rolling/weekly/monthly quota display via console scraping#250achappell wants to merge 9 commits into
Conversation
1fbe312 to
595d12e
Compare
|
Thanks for this, and sorry for the long silence. Could you rebase onto main? This now conflicts on One request to make review easier: this bundles several changes that aren't really about OpenCode quota display — the cross-account session-clobbering fix, the claude_code Keychain key-name fix, and the |
|
Yep, can do! |
|
Good call — split out the two cleanly-separable pieces:
Both are self-contained diffs against current On the third item — the Once #299 and #300 merge, I'll rebase this branch — since this PR already contains the identical fix commits, git will dedupe them against the merged |
|
Reviewed. The substance here is good, and the cross-account bugs you found are real — I confirmed the telemetry provider-scope leak independently while reviewing #300. The blocker is overlap, not quality. This branch contains the same fixes as two of your own smaller PRs:
Splitting those out was the right call, and it means the review order should be #299 → #300 → this one. Both of those are now green and queued to merge (I resolved a Once they land, this branch's remaining unique content is the part I actually want to review on its own merits:
What I'd like from you: after #299 and #300 merge, rebase this on One reviewable note for when it comes back: the scrape of the Go usage page (HTML + embedded Seroval) is inherently fragile against a console redesign. The RPC fallback helps, but I'd want the failure mode to be an explicit degraded status rather than a silent zero — which is exactly the class of bug you already fixed here for the auth case, so I think we agree on the principle. Worth a test that a shape change surfaces as Thanks for splitting out the small fixes — that's what made them mergeable this week. |
…isplay - Add workspace discovery via workspaces RPC (def39973...) - Add subscription.get RPC (7abeebee...) for rolling 5h and weekly usage % - Fetch billing + subscription concurrently in enrichFromConsole - New metrics: rolling_usage, weekly_usage with reset timestamps - Dashboard widget: blue theme, gauge priority for quota metrics - Regex fallback parsing matching CodexBar's strategy - 8 new tests covering round-trips, fallbacks, and workspace parsing
The individual RPC endpoints (subscription.get, billing.get) have
content-hash IDs that rotate on every backend deploy. The Go usage
page at /workspace/{id}/go embeds both billing.get and
lite.subscription.get data in a Seroval script blob that's stable
across deploys.
- Add FetchGoUsagePage() that scrapes the HTML page
- Parse embedded Seroval script for billing + subscription data
- Extract rolling 5h, weekly, and monthly usage percentages
- Fallback to individual RPC calls if page scraping fails
- Add monthly_usage_pct metric (49% on test account)
- Update dashboard widget with monthly gauge
Accounts configured with only browser_session auth were showing AUTH_REQUIRED because RequireAPIKey() returned before trying the console enrichment path. Now: - Skip Zen API probe when no key but browser cookie is configured - Fall through to enrichFromConsole for quota/billing data - Message shows 'Auth OK' when browser session succeeds without API key
…nsole failure - Fetch() no longer defaults to StatusOK when an account has neither a validated Zen API key nor a working console/browser session — it now surfaces the underlying auth-required status instead. - enrichFromConsole no longer swallows errors when both the HTML usage-page scrape and the billing-RPC fallback fail; it returns the error instead of writing zero-valued billing metrics into the snapshot as if they were real. - Rolling/weekly/monthly usage percentages now use presence flags (RollingUsageOK etc.) instead of a `> 0` check, so a legitimate 0% reading is no longer indistinguishable from "field not found" and dropped. - loadStoredSession is now a stubbable var (matching the existing loadBrowserSession/newConsoleClient seams), and the console-enrichment test now stubs the seam actually on the call path — it was previously stubbing the now-unused loadBrowserSession, so it passed only by accident against whatever real credentials.json happened to exist.
DefaultDashboard caps gauge rendering to 2 lines unless a widget opts into more. OpenCode's gauge priority lists three usage-window percentages (rolling_usage, weekly_usage, monthly_usage_pct), so the 2-line default meant monthly_usage_pct was always bumped by the two shorter windows even though it was already being fetched and had real data. Raise GaugeMaxLines to 3, matching the existing ollama precedent.
The "resets Xh Ym · Y% by reset" annotation claude_code's tiles show was silently never rendering for opencode, for two stacked reasons: - gaugeWindowDuration only recognized "5h"/"7d"/"30d"/etc., not the "rolling-5h"/"month" window strings core.Metric's own doc comment documents as valid — opencode uses exactly those. - tileGaugeProjectionAnnotation only checked snap.Resets[key] (the bare metric key, matching claude_code's convention), never the "<key>_reset" suffixed convention copilot and opencode already use. Also fixes an inconsistency in opencode's own reset-key naming: monthly_usage_pct's reset was stored as "monthly_usage_reset" instead of "monthly_usage_pct_reset", unlike rolling_usage/weekly_usage which correctly followed the "<metric key>_reset" pattern.
computeDisplayInfoRaw only recognized claude_code's metric naming (usage_five_hour/usage_seven_day) for the "Usage" tag. opencode's differently-named quota metrics (rolling_usage/weekly_usage/ monthly_usage_pct) fell through to the cost-based today_api_cost branch whenever local telemetry data was also present, tagging the tile "Credits" instead of "Usage" even though real quota-window data was available.
fff7480 to
5284191
Compare
|
Thanks for the feedback. I’ve addressed the comments While reviewing this more closely, I found a larger I have a broader fix locally, but haven’t pushed it yet. Since that expands the scope considerably, my preference |
Summary
Adds OpenCode Zen quota display (rolling 5h / weekly / monthly usage percentages, console balance, billing info) to the dashboard, sourced from the OpenCode console (browser-session auth), plus a handful of correctness fixes found while getting this working with multiple OpenCode accounts on the same machine.
Provider/subsystem touched:
internal/providers/opencode,internal/providers/perplexity,internal/providers/claude_code,internal/telemetry.What's included
internal/providers/opencode: newconsole_rpc.goclient that scrapes the OpenCode Go usage page (HTML + embedded Seroval script) for billing and rolling/weekly/monthly usage-percent data, with an RPC-based fallback. Adds amonthly_usage_pctmetric and a blue-themed dashboard widget.Fetch()no longer requires an API key when a browser cookie is configured.loadStoredSessionreads directly fromcredentials.jsoninstead of refreshing from whichever browser polled last).internal/telemetry/usage_view.go) no longer leaks one account's local usage/message/token data onto a sibling account that shares the same provider ID but has no local telemetry of its own.internal/providers/perplexity— it had the identical bug (same fixed cookie domain, multiple accounts, different browsers).$0.00 balance— it now surfaces as a real auth error.OKstatus.internal/providers/claude_code— the Keychain lookup for Claude Desktop's Chromium Safe Storage password used a stale account name ("Claude") that no longer matches current Claude Desktop builds ("Claude Key"), which silently broke the 5h/7d usage-percent metrics for Claude Code. Now tries both.DefaultDashboardcaps gauge rendering to 2 lines unless a widget opts into more. OpenCode's gauge priority lists three usage-window percentages (5h / 7d / monthly), so the 2-line default meantmonthly_usage_pctwas always bumped by the two shorter windows even though it was already being fetched correctly. RaisedGaugeMaxLinesto 3 (matches the existingollamaprovider's precedent) so all three render.User-visible changes
rolling_usage,weekly_usage,monthly_usage_pct,console_balance,monthly_limit, plus billing attributes (subscription plan, payment method) — all three usage-window gauges (5h/7d/monthly) are now visible on the tile, not just the first two.OPENCODE_API_KEY) now work end-to-end instead of requiring a key.browser_cookieaccount config is reused as-is.Testing
make fmt vet testrun locally. All green except three pre-existing, environment-dependent failures unrelated to this PR (hermes/zedTestProvider_Fetch_MissingDB, which pick up real local DB files, and anopencodeauth_scopeassertion that depends on real local credentials rather than a proper test double) — confirmed viagit stashthat all three exist onmainbefore this branch's changes.console_rpc_test.go(Seroval/HTML parsing, including a 0%-usage regression test),provider_test.go(browser-session-only auth flow, double-failure error propagation, status fallback),usage_view_test.go(cross-account telemetry leak regression).GaugeMaxLineschange is a widget-config constant, not new logic — the underlyingmonthly_usage_pctdata path was already covered by existing/added tests; verified the rendering fix visually viamake demo-style TUI capture rather than a new unit test.No docs changes — no new config keys were introduced.