Repository navigation
Conversation
Loongphy
force-pushed
the
wip/reset-credits-panel
branch
from
October 22, 2026 07:49
6be1d18 to
3cb072d
Compare
Adds a read-only RESET CREDITS detail block to the list --live screen: - 'c' toggles the block under the cursor row; j/k move the cursor row - lists available reset credits sorted by expires_at ascending, one line per card (title, local expiry, relative countdown), bounded to terminal width - read-only: redemption stays in codex sessions (contextual picker on rate-limit hit); no changes to the data layer from #159 Stacked on #159; draft for design review of the panel interaction. [skip ci]
- ⏎ on the expanded panel arms a two-step confirm (mirrors the upstream 'Use this reset?' UX); second ⏎ consumes the selected credit - new api/reset_credits.zig: POST wham/rate-limit-reset-credits/consume with a client-generated UUID v4 redeem_request_id (upstream semantics); per-account auth via registry.accountAuthPath - http_curl.zig: POST JSON curl runner (mirrors the GET runner) - panel: available-card collection (status==available, minus session consumed ids, sorted by expiry), cursor/detail/confirm/status lines - registry is left untouched on use: session-scoped consumed ids filter the display; the next --api refresh reconciles [skip ci]
Loongphy
force-pushed
the
wip/reset-credits-panel
branch
from
October 22, 2026 09:11
3cb072d to
36380a6
Compare
- generate the redeem idempotency key from std.Io entropy (UUID v4) and reuse it while retrying the same credit, so the backend deduplicates instead of consuming a second credit - parse the consume response code (reset / already_redeemed / nothing_to_reset / no_credit) like upstream instead of trusting any 2xx status; already_redeemed counts as success and no_credit hides the spent card from the panel - restore workflow_dispatch in CI (unrelated accidental removal)
@loongphy/codex-auth-darwin-arm64
@loongphy/codex-auth-darwin-x64
@loongphy/codex-auth-linux-arm64
@loongphy/codex-auth-linux-x64
@loongphy/codex-auth-win32-arm64
@loongphy/codex-auth-win32-x64
@loongphy/codex-auth
commit: |
Loongphy
marked this pull request as ready for review
October 22, 2026 09:28
`codex-auth reset <selector>` redeems the available reset credit with the earliest expiry for one account and prints the consumed card plus the credits that remain. It reuses the panel's card collection, the shared consume call, and the consume outcome mapping (reset / already_redeemed succeed; no_credit / nothing_to_reset fail with their own messages). Help, command docs, and README entries are included, along with scenario tests for the success and no-credit paths.
reset command
Print the consumed credit on one line (title + local expiry) and replace the per-card remaining list with a single summary line: count plus the card that expires next. Matches the two-line format requested for the command.
The RESET CREDITS cell now reads N (-) when no available credit has an expiry, and the reset command's remaining summary prints - instead of 'no expiry'. Docs updated to match.
Keep each view's visual column order while sharing one allocator. Plain list, live details, switch, and remove now hide unsupported fields and redistribute their width/separators. Use width-aware percentage cells, compact AUTH EXPIRE/RESET CREDITS headers, and leave ACCOUNT growth last. Add coverage for live-detail widths, 100% completeness, and column order.
Render the live panel as a rail: a top line with 'Remaining N', the ⏎ select hint and the esc close hint, compact card rows (title plus MM-DD HH:MM and a relative countdown, or - when no expiry), the armed hint on the selected row, and a bare bottom rail. esc now closes the panel instead of quitting the live view; collapsing with c or esc also clears the pending confirm state. Unit test covers the rendered rail.
reset command- Indent the rail to the account column so it nests under its row (ANSI-aware header scan for the column offset) - Header now reads 'Available N · ⏎ select · esc close' - After a successful redeem, refresh that account's usage immediately so the 5H/WEEKLY cells and the remaining card list reflect the reset; the success message is the compact '✓ reset credit used' - Unit test covers the indented rail and the new header
Start the rail at the column of the first '|' separator (the one next to the display number) instead of the ACCOUNT column, so the rail's left edge continues that separator line.
# Conflicts: # docs/commands/list.md # docs/table-layout.md # src/cli/list_details.zig # src/cli/table_layout.zig # src/tui/table.zig # tests/cli_picker_test.zig
- Render LAST ACTIVITY in list --live when the column is wide enough, falling back to LAST like the plain list. - Bound reset-credit rail text by display columns instead of bytes. - Add tests for shared column order and multibyte rail truncation.
The live rail cursor mixed two index spaces: it indexed rows.items while the renderer skips group header rows, so the rail could show one account while sitting under another, and the consume target followed the wrong account. renderListBody now shares one predicate with the exported data-row mapping, and the rail cursor is a rendered data-row index only. Redemption is irreversible, so the armed confirmation is bound to the exact (account_key, credit_id) pair instead of a flag: any cursor move, rail close, selection loss, or registry refresh drops it, and approve() releases the redeem exactly once. q now closes the open rail like esc, the rail status line is owned by the selection and cleared when the row changes, and the panel reuses time.timestamp.parseIso8601 instead of a weaker local parser. spliceAfterDataLine no longer emits a phantom trailing row (it inflated the viewport row count) and no longer leaks its buffer on every rendered frame.
credit_id originates at the backend and round-trips through the stored registry, so interpolating it into body text could emit a malformed request or add fields. BuildConsumeBodyAlloc encodes both fields with std.json.Stringify.
docs/tests.md requires production modules to hold no test blocks, so move the shared column order test to its own test root and export cli.table_layout as the module boundary it already is.
docs/tests.md requires production modules to hold no test blocks; relocate the remaining live_tui and text_width tests into their behaviour test root with the descriptions unchanged, so the checklist command rg '^test "' src returns nothing.
…edit The list viewport only clamped its start, so with more accounts than one screen the rail could hang on a row outside the display: pressing c looked dead, and Enter Enter still redeemed a credit the user could not see along with its result line. listViewportFollowing now scrolls the rail row into view on the body line index that renderListBodyViewport actually slices. A burst of keys read in one batch could also swallow a queued redeem: the second Enter armed the consume, then a following j moved the rail and cleared the selection before the queued redeem ran, leaving no feedback at all. The batch now stops being consumed once a redeem is committed. The re-confirm hint was driven by 'armed is not null' while it is drawn on the cursor card, with no identity link. Selection now exposes isPendingFor(identity), and the frame derives the shown credit once and uses it for the hint, the owned copies, and the armed check.
rowIndexForDisplayIndex/dataRowCount/liveViewportStartForDisplayIndex work on rows.items because the switch and remove screens render one line per row, group headers included. The live list body skips header rows and uses isRenderedLiveRow/liveDataRowCount/liveRowIndexForDataIndex. Both bases are correct for their own view; the names gave no hint, which is how a rail cursor nearly got fed to the wrong helper. Say so at each definition.
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.
Summary
list --livegains a reset-credits rail: it lists the available reset credits for the cursor row and redeems one in place.codex-auth reset <selector>command redeems the soonest-expiring reset credit for one account and prints a two-line summary.POST wham/rate-limit-reset-credits/consume, client-generated UUID v4 idempotency key, andcode-based outcomes.No registry schema change: the persisted shape is the v4 format merged in #159.
codex-auth resetswitch.status == "available"credit with the earliestexpires_at; credits without an expiry sort last and render-.0after a successful consume (includingalready_redeemed),1otherwise.list --apirefresh reconciles it.Live reset-credits rail
cexpands or collapses the rail under the cursor row; the left rail aligns with the row separator so it nests beneath its account.MM-DD HH:MMexpiry, relative countdown; missing expiry renders-.⏎selects the highlighted credit (the row shows· ⏎ again to use), the second⏎redeems it.esccloses the rail without redeeming; when the rail is collapsed,esckeeps its normal quit behavior.✓ reset credit usedand refreshes that account's usage immediately, so the5H/WEEKLYcells and the remaining list reflect the reset without waiting for the next refresh round. Failures keep their existing messages, and consumed cards are filtered for the session.Consume semantics
POST wham/rate-limit-reset-credits/consumewith{"redeem_request_id": "<uuid-v4>", "credit_id": "<id>"}and the standard bearer/account headers.std.Ioentropy and reused while retrying the same credit, so a retried request is deduplicated instead of consuming a second credit.codeis parsed like upstream:reset/already_redeemedcount as success,no_credithides the spent card and asks for a refresh,nothing_to_resetreports that usage does not need a reset, and unknown codes or non-2xx responses fail.Responsive columns
ACCOUNTgrows last.AUTH EXPIRE/RESET CREDITSheaders keep narrow terminals readable.RESET CREDITScell appends the earliest available credit expiry asN (exp MMM-DD), orN (-)when no available credit has an expiry.