Skip to content

feat(shell): multi-account quick-switch UI (slice 3, PR 3/3)#117

Merged
stuffbucket merged 1 commit into
mainfrom
feat/account-switch-ui
Jun 11, 2026
Merged

feat(shell): multi-account quick-switch UI (slice 3, PR 3/3)#117
stuffbucket merged 1 commit into
mainfrom
feat/account-switch-ui

Conversation

@stuffbucket

Copy link
Copy Markdown
Owner

What

PR 3 of 3 — the user-facing finale of slice 3 (multi-account persistence + quick-switch), on top of #115 (store) and #116 (routes). Shell UI for the account roster.

  • Authenticated card gains a "Switch to" list of the other saved accounts (the active one stays the hero), each with Switch + Remove. Switch sets the active account and reboots the sidecar into it (via a new rebootAndAwaitAuth helper — the write-then-reboot poll loop extracted from useGhAccount per /simplify, now shared by gh-reuse and switch). A 422 (token no longer valid for Copilot) is caught before the reboot and shown inline. Remove forgets maximal's own copy (gh untouched), no reboot.
  • Unauthenticated screen shows "Switch to a remembered account" when other accounts remain (e.g. after signing out of one) — above the gh-reuse list.
  • Reuses the .gh-account list rows, status dots, btn--sm, and the ambient busy bar; new CSS is just .account-roster, .gh-account__actions, and a quiet destructive .btn--ghost-destructive. Built to a design-skill spec against .design-context.md (list-not-cards, destructive token for Remove, reduced-motion = no new transitions).
  • api.ts: accounts-list/switch/remove request kinds + AccountsListResponse.

Lifecycle decision (flag for veto)

Sign out FORGETS the active account's credential (the secure default for a credential store; matches PR 1's backend, no change). Switch is the bounce-between-accounts path (no re-auth); Remove is the explicit per-account forget. This supersedes the earlier "sign-out keeps the copy" design rec — for a credential manager, sign-out not forgetting the token is surprising. Easy to flip if you'd rather keep-on-signout.

Verification (per the goal's UX-inspection directive)

  • Playwright + vision check (headless Chromium, mocked /settings/api/**): DOM logic 7/7 PASS (roster excludes the active account, 2 rows with Switch+Remove, hero correct; unauthenticated remembered-list shows all 3). Vision PASS at both real window widths — 900px (default) and 600px (the window's hard min_inner_size): no wrap, host on its own line, clean two-button alignment, Remove reads as the quieter destructive action. (An initial 520px "overflow" finding was a false positive — 520px is below the 600px window minimum and unreachable in production; the flex: 1 1 0 tweak is kept as a defensive correctness improvement.)
  • Documented the registry's read-modify-write concurrency model in a code comment (a dedicated subagent verdict: document-and-defer — Bun's event loop serializes the single sidecar; the only race needs a manual maximal auth CLI run alongside the sidecar and loses a recoverable account entry, not credentials).
  • bun test 850 pass / 0 fail; check:fast clean; shell tsc clean.

Stacked on #116 (merged); branched from main.

The user-facing payoff for slice 3. The Account section now surfaces the
persisted account roster:
- Authenticated card gains a "Switch to" list of the OTHER saved accounts
  (active one stays the hero), each with Switch + Remove. Switch sets the
  active account and reboots the sidecar into it (same write-then-reboot
  poll as gh-reuse); a 422 (token no longer valid) is caught pre-reboot and
  shown inline. Remove forgets maximal's own copy (gh untouched), no reboot.
- Unauthenticated screen shows "Switch to a remembered account" when other
  accounts remain (e.g. after signing out of one) — above the gh-reuse list.
- Reuses the .gh-account list rows, status dots, btn--sm, and the ambient
  busy bar; new CSS is just .account-roster, .gh-account__actions, and a
  quiet .btn--ghost-destructive (built to .design-context.md via a
  design-skill spec — list-not-cards, destructive token for Remove,
  reduced-motion: no new transitions).
- api.ts: accounts-list/switch/remove endpoints + AccountsListResponse.

LIFECYCLE DECISION (supersedes the earlier "sign-out keeps the copy" rec):
Sign out FORGETS the active account's credential (PR1 behaviour, the secure
default for a credential store); Switch is the bounce-between-accounts path
(no re-auth); Remove is the explicit per-account forget. No backend change.

Shell tsc clean.
@stuffbucket stuffbucket merged commit 937818c into main Jun 11, 2026
4 checks passed
@stuffbucket stuffbucket deleted the feat/account-switch-ui branch June 11, 2026 21:52
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.

1 participant