fix(cli): show the real credit balance on the CLI connect pages - #83
Merged
ralyodio merged 1 commit intoJul 30, 2026
Merged
Conversation
The app bar renders a "◆ <n> cr" chip for every signed-in visitor, and every other signed-in page passes the account's real balance into it. The two CLI-connect pages passed a literal 0, so a funded account is told it has no credits on the exact page where it is deciding whether to authorize the CLI or connect a device. Pass await balance(req.user.id) instead, the same way the dashboard and the approvals page already do. balance() was already imported here for GET /api/me. Adds apps/pwa/test/cli-pages-balance.test.mjs: 2 tests that fail on main and pass with the fix, plus 2 controls that pass both ways.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
appBar(user, balance, csrf)renders a◆ <n> crchip for every signed-in visitor. Every other signed-in page passes the account's real balance into it, so the chip reads as a live credit readout:routes/pages.mjs:56,133→appBar(req.user, bal, ...)routes/approvals.mjs:119→appBar(req.user, await balance(req.user.id), ...)The two CLI-connect pages pass a literal
0:apps/pwa/src/routes/cli.mjs:41—GET /cli/authorizeapps/pwa/src/routes/cli.mjs:132—GET /deviceBoth sit behind
requireAuth, so the visitor is always a real signed-in account. A user with 4,321 credits is told◆ 0 cron the exact page where they are deciding whether to authorize the CLI or connect a device — the pages that unlock thenotify()/ask()calls those credits pay for.Repro
On unmodified
main(df9d1e0), realcliRouter+pagesRouteragainst a throwaway libsql database, one user seeded with 4,321 credits incredit_ledger:GET /cli/authorizeGET /deviceGET /dashboard(control)No fault injection, no stubs — the dashboard reads the same seeded ledger through the same helper and gets it right.
The fix
Pass
await balance(req.user.id), whichcli.mjsalready imports forGET /api/me, and make the two handlersasync. The file's other handlers in this router are alreadyasync, so this does not introduce a new failure mode for the router. 7 insertions, 4 deletions — 3 of the insertions are the comment.Tests
New
apps/pwa/test/cli-pages-balance.test.mjs, 4 tests, built on the existinglogout-csrf.test.mjsharness (skip-guard when PWA deps are missing, throwaway libsql file db).Fail-before verified by restoring the pristine
cli.mjsand re-running:The two controls (
/dashboardreads the ledger;/cli/authorizestill renders the approve form with its CSRF field) pass both ways by design. That is what makes the two failures meaningful rather than a broken parser: the same regex reads 4321 off the dashboard in the unpatched run.Suites:
apps/pwa30 → 34, rootnpm test204 → 208, 0 failures before and after.