Skip to content

feat(usage-queue): at-limit toggle button + timed simulation demo mode - #239

Merged
aterrylu merged 1 commit into
mainfrom
terry/usage-queue-button-ux
Jun 21, 2026
Merged

feat(usage-queue): at-limit toggle button + timed simulation demo mode#239
aterrylu merged 1 commit into
mainfrom
terry/usage-queue-button-ux

Conversation

@aterrylu

Copy link
Copy Markdown
Owner

What

Follow-up to the usage-queue feature (#232) — refines the overlay control based on live UX review, and adds a timed simulation mode so the auto-Enter can be watched firing on its own.

Button → at-limit toggle

  • Appears only when you're at the usage cap. At normal usage there's no button; it surfaces as a timely call-to-action exactly when you've run out. Driven by a new capped field on GET /api/usage-queue, computed fresh from usage (via exported evaluateCap) so the control can show before anything is armed — independent of the watcher's armed-only blocked.
  • Clear on/off switch — yellow border when off, green when on, sliding toggle. Solid background in both states (no translucency), constant 1.5px border.
  • Intent copyAuto-Enter when limit resets + Type in the terminal to queue (off) / Sends in ~2h13m (on). Spells out both halves: it auto-presses Enter at reset, and you queue by typing in the terminal yourself.
  • Hardcoded width so the differing on/off subtitle never resizes the bar; role="switch" for accessibility.

Dev simulation: timed reset

  • POST /api/usage-queue/_simulate?state=capped&resetInSec=N caps now and auto-clears after N seconds, firing any armed pane via the server's own countdown — so you can arm a pane and watch the auto-Enter fire with no second call. Extracted applySimulatedClear() keeps the timed transition testable. Still gated behind AUTONOMOS_ENABLE_USAGE_SIMULATION.

Testing

  • Button: visibility gating (nothing rendered when not capped), off/on switch states, ETA copy, toggle click.
  • Hook: capped wiring, optimistic toggle + rollback.
  • Server: resetInSec parsing (set / ignored-for-non-capped / ignored-invalid), applySimulatedClear flips to cleared.
  • Real-spawn integration (CI-gated): arms a pane over the API, sets capped&resetInSec=2, and asserts a real claude auto-submits when the countdown elapses. ✅ Verified passing locally.
  • Full suite green: server + 253 dashboard, Biome + tsc clean.

Notes

  • All UX iterated live with Terry on a dev server (final: at-limit toggle, yellow/green, 270px width).
  • No ADR — this refines the already-recorded ADR-042 (usage queue) without changing its architecture.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UpGRD3fxgWmCKyp9nZtrQs

Button: now appears only when at the usage cap (new 'capped' field on
/api/usage-queue, computed fresh from usage so the control surfaces before
anything is armed). Rendered as an on/off switch — yellow border off, green on —
with intent copy clarifying it auto-presses Enter at reset and you queue by
typing in the terminal. Hardcoded width so the on/off subtitle never resizes it.

Server: export evaluateCap() for the stateless at-cap read; GET /api/usage-queue
returns capped + nearest reset. Dev /_simulate gains resetInSec — caps now and
auto-clears after N seconds (extracted applySimulatedClear), so you can arm a
pane and watch the auto-Enter fire on its own.

Tests: button visibility/switch states, hook capped wiring, resetInSec parsing +
applySimulatedClear, and a real-spawn integration test that arms a pane, sets
capped&resetInSec=2, and asserts a real CC auto-submits when the timer elapses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpGRD3fxgWmCKyp9nZtrQs
@aterrylu
aterrylu enabled auto-merge (squash) June 21, 2026 00:22

@nox-0x nox-0x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — the at-limit visibility gate, the toggle UX rework, and the timed-reset simulation control all hang together cleanly, with the new evaluateCap correctly separating stateless visibility from the watcher's hysteresis-smoothed blocked.

Notes worth a follow-up (none blocking):

  • GET /api/usage-queue is now async and awaits getRateLimits() on every poll. The scanner's 60s cache absorbs most of it, but a slow claude.ai call can now stall a status response that used to be sync.
  • applySimulatedClear() builds its 'cleared' override with DEFAULT_RESET_SEC (2h13m) in the future — harmless because util=2 makes evaluateCap return capped:false, but the stale reset hint is mildly weird.
  • Minor comment rot in UsageQueueButton.tsx: the Switch comment says 'amber track' (it's GREEN), and the border comment says '2px' (it's 1.5px).

@aterrylu
aterrylu merged commit 67c440d into main Jun 21, 2026
10 checks passed
@aterrylu
aterrylu deleted the terry/usage-queue-button-ux branch June 21, 2026 00:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants