feat(panel): a stage-cli style merge control, a status chip, one direct press, and Queued in the pill
Built on #4156 (header polish), now merged; this PR targets main.
Summary
The developer said: "I don't love the merge button. Can we make it more like the stage/stage-cli merge button?" This replaces #3957's single button and popover (GitHub's sentence, method radios and a press) with stage-cli's merge-status shape (merge-status.tsx, merge-action.ts, merge-status-summary.ts), built from Luke's parts.
A status chip (@luke/ui Badge, the 20px status size from #4101): a glyph and a word in the tone of where the merge stands.
- Checking (spinner), Conflicts, Behind, Review required, Changes requested, Checks failing, Checks running, Blocked, Ready, Auto-merge on.
- GitHub's fuller sentence ("A required review is missing", "#2 in the merge queue. GitHub is still checking whether it merges") is the chip's tooltip, and is read to screen readers.
- No chip when the PR is ready and the press is Merge or Merge when ready (the press says it), for a draft (the pill says Draft), or in the merge queue (the pill says Queued #N).
- Below a 520px header the chip drops its word (glyph only, word still read), so the press keeps its words and nothing overflows the title row.
One direct press, chosen by mergeActionOf (unchanged):
- Ready: a primary
SplitButtonwhose words are the chosen method: "Squash and merge", "Merge pull request" or "Rebase and merge". The chevron opens the allowed methods ("Create a merge commit" etc.) with a check on the current one. One allowed method gives a plain primary button.- A click merges at once, as stage-cli's does (the developer's call): the press shows a spinner, named "Merging", until GitHub answers, and GitHub's refusal shows in its own words on the tab's write note.
- Checks running, auto-merge allowed: an outline "Enable auto-merge" split button by the chosen method, its chevron choosing the method too.
- Merge-queue base: primary "Merge when ready". It enqueues once ready, as before.
- Auto-merge on: outline "Disable auto-merge".
- Queued: outline "Remove from queue", asked first in the danger tone ("could impact other pull requests in the queue").
Queued #N in the state pill (the developer's choice, as stage-cli does it): while GitHub holds an open PR in its merge queue, the PR tab's state pill reads Queued #N, or "Queued" if the position is unknown. It's in the attention (amber) tone with the merge glyph, at the same 20px compact size. Its menu offers Close but not Convert to draft, as on GitHub. The merge control then shows only Remove from queue. Only the PR tab's pill changes; the PR chips on agents and in the sidebar keep their marks.
Unchanged underneath:
mergeActionOf, the method kept per repository, and the head pinned at press.- Writes as the member, with refusals in GitHub's words on the tab's write note, and sign-in-required.
- The busy press while a change is out ("Merging", "Turning on auto-merge", …).
- The popover, its radios and its CSS are removed.
Screenshots
From the same harness as #4156 (the real tab with fixture reads over the built styles.css; Geist instead of SF on Linux).
Ready (method chosen)
| Light | Dark | |
|---|---|---|
| 900px | ![]() | ![]() |
| 600px | ![]() | ![]() |
Checks running (Auto-merge plus chip)
| Light | Dark | |
|---|---|---|
| 900px | ![]() | ![]() |
| 600px | ![]() | ![]() |
Queued (Queued #2 in the pill, Remove from queue)
| Light | Dark | |
|---|---|---|
| 900px | ![]() | ![]() |
| 600px | ![]() | ![]() |
Conflicts (chip only)
| Light | Dark | |
|---|---|---|
| 900px | ![]() | ![]() |
| 600px | ![]() | ![]() |
Blocked (Review required)
| Light | Dark | |
|---|---|---|
| 900px | ![]() | ![]() |
| 600px | ![]() | ![]() |
Method dropdown open
| Light | Dark | |
|---|---|---|
| 900px | ![]() | ![]() |
| 600px | ![]() | ![]() |
Evidence
- Per-package
tscfor@luke/panel: pass.vitest run --project panel: 265 files, 2723 tests pass../scripts/oxlint.sh: 0 errors.pnpm knip: clean.cd apps/desktop && node scripts/build.mjs: within the bundle budget. (check:affectedruns out of memory on the panel typecheck in the sandbox.) - Tests (
agent-pull-request-tab.test.ts), rewritten for the new shape:- Each state's chip (word, tone, GitHub's sentence) and press (words, look, chevron or not): ready, ready by one method, checks running, merge-queue base, queued, auto-merge on, conflicts, behind, checking, review required, checks failing, changes requested, blocked, and a draft (nothing).
- Choosing a method from the chevron's menu (checked items), kept per repository across a remount, and the press merging at once, with no question, at the head it read.
- Enable/Disable auto-merge and Merge when ready go straight to the service; Remove from queue asks first.
- Pending and refusal: "Squash and merge" stands busy as "Merging", then the tab says GitHub's refusal.
- "The question goes with its panel" now covers Remove from queue's question.
- The queued pill: "Queued #2" in the attention tone, its menu offering only Close (no Convert to draft), no merge chip and only Remove from queue; out of the queue the pill says Open and offers Convert to draft again.
- Remove from queue's question goes once a read finds the PR out of the queue, and GitHub's refusal stands in the question for another try (from Devin's review).
- Removed: the popover's Escape/outside-press test (there's no popover), and "a merge asked about merges the head it was asked about" (there's no question now). The ready-to-merge test covers the head pinned at press.
Notes
- Desktop/panel only, no service change, so no Preview run.























