feat(desktop): add API-billed usage profiles

Merged
KI
2mo ago
+1292-406

What & why

Supersedes #6967 (thanks @iamgadmarconi) — that branch was 141 commits behind main and on the retired explicit-ID i18n scheme, so this re-applies it on main and reworks the UI. Fixes #6966.

The Usage page can already discover several Claude Code and Codex subscription profiles and switch the default with one click. API-billed profiles (Anthropic Console, codex login --with-api-key) could not take part. Now:

  • Add account gets a Billing row: Subscription or API key. The generated command runs the provider's own API login and then writes a marker file into the profile dir; the key never passes through Superset.
  • API-billed profiles get an API badge and, instead of quota bars, a "Billed per token" line with a View usage link to the provider's usage page.
  • Switch sign-in on an API profile stays on API billing (re-runs the API login, rewrites the marker); Remove works as for any profile.
  • Sections render before the first quota read lands, so Add account is reachable immediately.

Changes vs #6967

  • Marker is agent-tagged. The marker now holds claude or codex. A presence-only marker made every marked ~/.codex-* home also show up as a Claude API profile, because Claude discovery scans all ~ dot-dirs (reproduced in the running app).
  • Codex command is one line with read -rs instead of the stty/trap subshell, and the marker step precedes unset so it follows the login's exit status. A multi-line paste would feed the next line to read as the key, so it stays single-line on purpose.
  • Login poll survives an unfocused window. useHostUsageLogins sets refetchIntervalInBackground: true. The app ties react-query's focusManager to window focus, so the poll paused exactly while the user was off in a terminal signing in, and the dialog never noticed the new profile.
  • Inline RadioGroup instead of Tabs; dialog copy trimmed; catalogs for all 17 locales.

How I tested it

  • bun test on packages/host-service/src/trpc/router/usage (97 pass) and the desktop usage folder (39 pass): agent-tagged marker classification, fingerprint changes on re-login, other agent's marker ignored, unmarked API auth.json ignored, generated commands for both agents and both billing kinds.
  • typecheck for desktop and host-service, biome clean, bun run check:i18n clean.
  • Real dev app over CDP, window unfocused:
    • Ran the generated Codex command verbatim with a throwaway key: codex login --with-api-key accepted it from stdin and the marker was written; the profile appeared under Codex only.
    • Claude add flow with API billing: simulated the Console login finishing by writing the marker; the dialog detected it in ~1.5s.
    • Switch sign-in on an API profile shows the API login command; Remove deleted both test dirs.
  • Not exercised: a real Anthropic Console OAuth login.

Screenshots

Cards under Claude Code and Codex, the dialog in API mode for both providers, the detected state, and Switch sign-in are in the session link below.

https://claude.ai/code/session_01Qy1bWiGW9qq8V3zZ64v2r3

Summary by CodeRabbit

  • New Features

    • Added support for API-key billing profiles for Claude and Codex.
    • API-billed accounts now show billing status and a link to provider usage pages instead of quota windows.
    • Added terminal-based sign-in guidance, including secure API-key entry for Codex.
    • Account switching preserves billing type.
  • Improvements

    • Usage sections now appear immediately with per-agent “Reading usage…” states.
    • Login discovery continues while the app is unfocused.
    • Updated translations across supported languages for billing, sign-in, usage, and zoom controls.