feat(desktop): the Inbox reads one item at a time beside a list grouped by plan or newest first, and a settled item shows what it offered with the pick marked

Merged
DA
6d ago
+1900-759

Why

Dean, after the polish pass: the Inbox cards weren't clear about when a press opens the agent and when it expands the card, and it was hard to tell how an item got resolved and what the resolution was. He also disliked the Waiting/Settled icons and the toolbar's Open plan, and said the Inbox as a whole needed work. He picked this design from the Conductor show (rounds A to E, then this combination of D and E: https://stage-w2084.conductor.show/).

What

The window's Inbox (desktop-inbox.tsx) is now a list of items beside a reading pane:

  • List (inbox-list.tsx): every item of every plan holding one, not one row per plan. Rows are sidebar rows (agent mark, title, time), bold while waiting, newest first.
    • The head keeps All | Waiting and adds one View options button. Its menu offers Group by plan (the default) or Newest first, with the current choice checked.
    • Group by plan uses the sidebar's own SidebarGroupHeader: the same chevron, the count shown only on hover while folded, and the folded state remembered.
    • The filter, the grouping, and each plan's fold are kept in localStorage like the sidebar's folds.
  • Pane (inbox-pane.tsx, renamed from inbox-board.tsx, whose block, option, form, and composer parts it keeps) shows the chosen item as a thread built from the agent tab's Message components:
    • The agent's question with everything it offered.
    • Once settled, nothing it offered disappears. The pick wears the existing pressed-option look plus "✓ Your pick", and the other options fade to an outline. An approval or task keeps its Decline/Approve (Can't do this/Done) pair with the pressed one marked.
    • The developer's reply is their own bubble, with a line under it: "You chose … · 38m · Sent to ", or "Saved for the agent to read" when needsReply is false.
    • A withdrawn item shows the agent's own message with its reason.
    • While the item waits, the answer box is docked at the bottom, as under an agent's transcript.
  • Breadcrumbs plan › agent replace Open plan, the card head that opened the agent, and the old Go to agent idea. Each crumb is clickable: the plan crumb opens the plan, and the agent crumb opens that agent's tab. They use the File tab's breadcrumb styles and the app's hover cards (PlanCard, AgentTabCard).

Data (use-inbox-items.ts): main's account read lists the plans holding items but carries only open items in brief. So each listed plan is read once from the start (the service answers at once), and read again only when main says that plan's latest item moved. That avoids a held read per plan. The chosen plan's own held read (usePlanInbox) stands in for its list entry, so an answer shows at once.

The plan page's Inbox tab gets the same list and pane, scoped to the plan with no head. The old board, with its Waiting/Settled headers and two click targets per row, is gone everywhere.

Removed: SidebarPlan's Inbox mode (the waiting count and the Open plan menu entry), useWaitingFold, settledWords, and the board's card and settled-row CSS.

New CSS (only where nothing existing fits)

  • .inbox-option[data-picked="false"]: a settled option that wasn't picked, outlined and muted. The picked one shares the existing [aria-pressed="true"] rule, and .inbox-option:hover is now limited to button.inbox-option, so read-only options don't light up.
  • .inbox-picked: the "✓ Your pick" label.
  • .inbox-row .sidebar-plan-line: centres the agent mark on a sidebar row, as .sidebar-pinned-tab does, without the room that class reserves for Unpin.
  • .inbox-indent: the message body under the byline starts past the agent mark.
  • .inbox-crumb-agent: the agent crumb leads with its mark.
  • Extended existing selector lists: .desktop-inbox .agent-composer, for reading-width padding like .desktop-agent .agent-composer, and .desktop-toolbar .file-breadcrumbs, which is no-drag like .desktop-toolbar-actions.

Everything else reuses existing classes: sidebar-repository, sidebar-plan*, sidebar-pinned-tab-glyph, file-breadcrumb*, desktop-toolbar*, settings-segments, icon-button, plan-menu via ActionMenu, inbox-option, agent-composer, agent-note, plan-card, tab-card, plus Tailwind utilities.

Screenshots

These are rendered from the real components with fixtures in Chrome, using the app's compiled stylesheet. They are not a Mac capture.

Group by plan · All: a waiting choice, Audit log export folded

Group by plan · All: a waiting choice, Audit log export folded

Newest first · All: a resolved choice, the pick marked, the note in the developer's bubble (dark)

Newest first · All: a resolved choice, the pick marked, the note in the developer's bubble (dark)

Group by plan · Waiting: a waiting approval

Group by plan · Waiting: a waiting approval

Newest first · Waiting: a waiting task that doesn't message the agent (dark)

Newest first · Waiting: a waiting task that doesn't message the agent (dark)

A resolved approval: Approve marked, with the note

A resolved approval: Approve marked, with the note

Answered in the developer's own words: no option marked

Answered in the developer's own words: no option marked

Withdrawn by the agent, with its reason (dark)

Withdrawn by the agent, with its reason (dark)

The plan page's Inbox tab: the same list and pane, scoped to the plan

The plan page's Inbox tab: the same list and pane, scoped to the plan

Tests

  • inbox-model.test.ts: the list (each grouping, the Waiting filter keeping the chosen item, plan order), the first choice, proposedOptions (pick marked, own words marking none, approval presses, nothing for words, forms, or open items), and settlementOf. The superseded settledWords test was replaced.
  • desktop-inbox.test.ts (new; #2420 deleted the old one):
    • The list groups items under each plan, the first waiting item is chosen, and Newest first from the View options menu lists them in one run and survives a relaunch.
    • A settled choice keeps its options with the pick marked, plus the reply bubble and the "Sent to" line.
    • The crumbs open the plan and the agent's tab, and the bar has no other button.
    • A plan main reports as changed is read again, and Waiting then lists only what still waits.
    • Added after Devin's review: a selected item whose plan is archived elsewhere gives way to the next one; once the selected plan's live read fails, the list's read of that plan takes over again; a read that a newer one overtook changes nothing.
  • desktop-plans.test.ts: a plan's Inbox tab with no items says nothing is waiting.

Verification

  • ./scripts/check.sh exits 0 on Linux.
  • CI could not verify the Mac UI, and ./scripts/verify.sh was not run (this is a Linux VM). LUKE-159 is the manual Mac pass, and the next release rehearsal on a v* tag is the Mac gate. The screenshots above come from jsdom-rendered DOM in Chrome on Linux with the compiled CSS. Drag regions, the menu's position, and the hover cards' placement need a look on the Mac.

🤖 Generated with Claude Code