feat(cli): add built-in web dashboard to codexbar serve - #2715
Conversation
GET / now serves a self-contained HTML page that polls /dashboard/v1/snapshot and renders provider cards with usage windows, credits, and cost. The static UI stays unauthenticated (it carries no account data); tokens are entered in-browser, kept in localStorage, and sent as a bearer header. No visibility gating on polling so embedded panes that report document.hidden permanently still refresh.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2ddf754f66
ℹ️ 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".
| const windows = node("div", "windows"); | ||
| for (const window of provider.windows || []) windows.append(renderWindow(window)); | ||
| card.append(windows); |
There was a problem hiding this comment.
When the snapshot includes multi-account data (providers[].accounts, e.g. claude-swap), this renderer only walks provider.windows and then returns the provider card without ever visiting provider.accounts or accountsError. In that context the new web dashboard hides every account's windows/errors/active state even though the dashboard API supplies them, so Claude multi-account users see an incomplete dashboard.
Useful? React with 👍 / 👎.
…-fireworks-provider
The serve dashboard PRs (#2715-#2723) merged during the GitHub Actions outage without CI lint validation. Mechanical, behavior-preserving fixes: - CLIServeProviderIcons.swift: generator now emits scoped swiftlint:disable/enable line_length around the base64 data (icon payload is byte-identical after regeneration) - CLIServeWebUI.swift: moved the html template constant to CLIServeWebUI+HTML.swift (enum body 1093 -> under 800 lines); the string literal content is verbatim-identical - Data->String conversions switched to failable String(bytes:encoding:) with fallbacks, matching repo convention - Long @option help strings wrapped via adjacent + concatenation
Summary
codexbar servenow ships a built-in web dashboard:GET /returns a single self-contained HTML page (inline CSS/JS, zero external requests) that polls the existing/dashboard/v1/snapshotroute and renders provider cards — usage windows as progress bars with reset countdowns, credits, today/30-day cost, status dots, per-provider accent colors, light/dark viaprefers-color-scheme.Auth model is unchanged and matches the documented threat model:
/health, it carries no account data).401the page shows an inline token prompt; the token lives inlocalStorage(codexbar.dashboardToken) and is sent as a bearer header, never in the URL.textContent; the snapshot's identity redaction is preserved as-is.Design note: polling is intentionally not gated on
document.hidden— embedded panes and sidebars often reporthiddenpermanently (verified during development), and browsers already throttle background-tab timers.Docs (
docs/dashboard-api.md,docs/cli.md),servehelp text, and the changelog are updated.Commands run
swift buildswift test --filter CLIServe— 92 tests, 4 suites, all passingmake test— full sharded suitemake check— 0 violationsserveon a tokened bind: initial401→ token prompt → cards render with real provider data;504error state and retry verified.Screenshots
Omitted deliberately: the dashboard renders live personal account and spend data, and a sanitized capture was not available at land time. To see it:
codexbar servethen openhttp://127.0.0.1:8080/.