Files
buzz/desktop/tests
ss-dev-00 6c9b0e2fe7 feat(desktop): cover the channel with the agent activity drawer
Slice A of the focus-mode agent conversation. Agent activity gets the same
full-cover presentation threads already had in focus mode, because its
transcript is tool calls, diffs, and command output — content a 380px side
pane cannot show usefully. It deliberately offers no split/focus toggle: at
any viewport wide enough for two panes it always covers.

The drawer surface is extracted from `FocusThreadDrawer` into a
presentation-only `CoverDrawer` that knows nothing about what it covers, so
the thread drawer and the activity drawer are one surface with two contents.
Motion, scrim, Escape ownership, and focus capture/restore all live there.

"Which panel" and "which presentation" now resolve together in
`channelAuxiliarySurface`, which is what makes the two cover drawers mutually
exclusive: there is one covered slot and the resolved surface owns it.

Two ordering hazards the surface has to handle, both covered by tests:

- Escape during a replacement. `AnimatePresence` keeps the outgoing drawer
  mounted through its exit, capture-phase listeners fire in registration
  order, and the outgoing one registered first — so it would swallow the press
  via `stopImmediatePropagation` and the user would have to press Escape
  twice. The drawer stands down for its whole exit, gated on presence rather
  than the focus slot: a successor whose content takes focus never claims the
  slot, which would leave the outgoing claim current for exactly the drawer
  that should stand down.
- `StrictMode` replaying the focus-capture effect. By the replayed setup the
  drawer has already focused itself, so an unconditional
  `document.activeElement` read records the drawer as its own opener and a
  real close focuses a detached node, stranding the keyboard on `<body>`. A
  one-shot ref captures the opener exactly once.

Reconciled against main, where the idle auxiliary panel gained its own
full-cover presentation (#6590):

- `FocusThreadDrawer` keeps main's `label` prop and passes it through as
  `CoverDrawer`'s `ariaLabel`; the idle panel reuses the presentation with its
  own name, which is why the label is a prop and not the thread's constant.
- `outline-hidden` carries onto the extracted surface with the reason it
  exists recorded — the drawer is `tabIndex={-1}` and focuses itself, so the
  ring is noise.
- `useFocusIdleDrawer` sits outside `auxiliarySurface` on purpose: the idle
  panel is caller-owned, is not in the last-opened-wins set, and
  `idleAuxiliaryOverridesThread` lets it render ahead of a thread. It still
  cannot contend for the covered slot, because `shouldUseFocusIdleDrawer`
  requires every other candidate to be absent.
- main's `mode="wait"` on the presence boundary is kept. It closes the window
  where two drawers are mounted together, but the drawer's presence and
  focus-slot guards stay: they protect the surface, not this host's choice of
  mode.

Squashed from ss-dev-00/agent-activity-cover (#6542) at 105a3654d.

Co-authored-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz>
2026-08-26 15:25:39 -07:00
..