Web command bar: overlay shell, session results, Enter attaches #149

Closed
opened 2026-09-03 13:26:50 +01:00 by naps62-yolo · 1 comment
Collaborator

Build the web command bar itself: the overlay, the query input, the result
list, and the session half of the results.

  • ctrl-k opens it while the sidebar has focus. (Opening it over a focused
    terminal is #I — this issue does not have to win that fight yet.)
  • Empty query lists sessions most-recently-focused first, using the daemon's
    last-focused field from #145.
  • Typing fuzzy-matches sessions through the matcher from #146, with matched
    ranges highlighted; results are grouped under a kind header, since commands
    and directories join the same list in #G.
  • Enter opens the highlighted session — the same path the sidebar's click and
    the hash router already share, so a split or a drag can't leave it
    inconsistent.
  • Escape closes. Up/down and ctrl-p/ctrl-n move the highlight.
  • It is a registry command (#148) like everything else, so it shows up in the ?
    help overlay without being listed twice.

Follow docs/COMMAND-BAR.md for the key model and the empty-query ordering,
and DESIGN.md's existing overlay tokens for the visuals — this is the same
family of surface as the spawn modal and the help overlay, not a new one.

Non-goals: no sigils (#G), no session action page (#H), no terminal-focus
interception or leader escape hatch (#I), no touch entry point (#N).

Depends on: #145, #146, #148


Handoff from #148. The registry is in web/src/commands.ts:
COMMAND_SPECS is the list to feed the > sigil (each entry has id,
label, group, keys, scope), publishedCommands() returns the bound
subset in registry order, and keyCaps(chord) turns a chord into the keycaps a
row renders. Chord resolution already works, so ctrl-a ctrl-k is a spec entry
plus a run() — no dispatcher work.

The global key listener is still bubble phase. docs/COMMAND-BAR.md
requires ctrl-k to be intercepted ahead of xterm, so this issue has to move
that listener to capture phase
. #148 left it alone deliberately, because
switching phases would have changed existing behaviour.

Build the web command bar itself: the overlay, the query input, the result list, and the session half of the results. - `ctrl-k` opens it while the sidebar has focus. (Opening it over a focused terminal is #I — this issue does not have to win that fight yet.) - Empty query lists sessions most-recently-focused first, using the daemon's last-focused field from #145. - Typing fuzzy-matches sessions through the matcher from #146, with matched ranges highlighted; results are grouped under a kind header, since commands and directories join the same list in #G. - Enter opens the highlighted session — the same path the sidebar's click and the hash router already share, so a split or a drag can't leave it inconsistent. - Escape closes. Up/down and `ctrl-p`/`ctrl-n` move the highlight. - It is a registry command (#148) like everything else, so it shows up in the `?` help overlay without being listed twice. Follow `docs/COMMAND-BAR.md` for the key model and the empty-query ordering, and `DESIGN.md`'s existing overlay tokens for the visuals — this is the same family of surface as the spawn modal and the help overlay, not a new one. Non-goals: no sigils (#G), no session action page (#H), no terminal-focus interception or leader escape hatch (#I), no touch entry point (#N). Depends on: #145, #146, #148 --- **Handoff from #148.** The registry is in `web/src/commands.ts`: `COMMAND_SPECS` is the list to feed the `>` sigil (each entry has `id`, `label`, `group`, `keys`, `scope`), `publishedCommands()` returns the bound subset in registry order, and `keyCaps(chord)` turns a chord into the keycaps a row renders. Chord resolution already works, so `ctrl-a ctrl-k` is a spec entry plus a `run()` — no dispatcher work. **The global key listener is still bubble phase.** `docs/COMMAND-BAR.md` requires `ctrl-k` to be intercepted ahead of xterm, so **this issue has to move that listener to capture phase**. #148 left it alone deliberately, because switching phases would have changed existing behaviour.
naps62-yolo added this to the Command bar milestone 2026-09-03 13:26:50 +01:00
naps62-yolo added the difficulty/hardarea/webtype/feat labels 2026-09-03 13:26:51 +01:00
naps62-yolo added a new dependency 2026-09-03 13:26:51 +01:00
naps62-yolo added a new dependency 2026-09-03 13:26:52 +01:00
naps62-yolo added a new dependency 2026-09-03 13:26:52 +01:00
naps62-yolo added a new dependency 2026-09-03 13:26:52 +01:00
Author
Collaborator

Merged into blitz/command-bar. Suite re-run on the integration branch: 356
tests across 40 files, green, typecheck clean.

orderSessionsForBar implements the empty-query ordering the way the contract
states it — dead after live regardless of recency, never-focused after focused,
created-descending as the last tie-break — and it doubles as the input order a
non-empty query inherits, which is what the matcher's stable last tie-break was
specified for. The two halves fit.

The capture-phase move is in, and it correctly stops short of the pane: the
listener still defers to isTypingTarget, leaving Ctrl-K reaching xterm until
#152 takes that over. Deferring rather than half-implementing it was the right
call.

Merged into `blitz/command-bar`. Suite re-run on the integration branch: 356 tests across 40 files, green, typecheck clean. `orderSessionsForBar` implements the empty-query ordering the way the contract states it — dead after live regardless of recency, never-focused after focused, created-descending as the last tie-break — and it doubles as the input order a non-empty query inherits, which is what the matcher's stable last tie-break was specified for. The two halves fit. The capture-phase move is in, and it correctly stops short of the pane: the listener still defers to `isTypingTarget`, leaving Ctrl-K reaching xterm until #152 takes that over. Deferring rather than half-implementing it was the right call.
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Reference: naps62/maestro#149