Skip to content

feat(shortcuts): mod+↑/↓ relative agent navigation + neighbor hint chips - #306

Merged
aterrylu merged 3 commits into
mainfrom
terry/shortcuts-arrow-nav
Aug 4, 2026
Merged

feat(shortcuts): mod+↑/↓ relative agent navigation + neighbor hint chips#306
aterrylu merged 3 commits into
mainfrom
terry/shortcuts-arrow-nav

Conversation

@aterrylu

@aterrylu aterrylu commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Problem

mod+1–9 (#305) only reaches the first nine sidebar rows; Terry runs fleets past ten agents. Requested: mod+↑/↓ to walk the agent list vertically, with the row above the active agent showing ↑ and the row below showing ↓ during the hold-reveal.

Solution

  • mod+↑ / mod+↓ switch to the previous/next agent row in the published sidebarRowOrder — same list, same click-mirroring action as the digits (ADR-066 model unchanged). Clamped at the ends (no wrap); with no active-session anchor, ↓ enters at the top, ↑ at the bottom.
  • Neighbor hint chips: while holding the modifier, the rows adjacent to the active agent show ↑/↓ chips next to the digit badges — rows beyond 9 (no digit) still get an arrow when adjacent, which is exactly the >10-agent case.
  • Boundary cost recorded: Ctrl+↑/↓ on non-Mac carries a real xterm encoding (CSI 1;5A/B); the reservation is documented in the test-enforced NON_MAC_COST table. ⌘↑/↓ (page top/bottom) is interceptable in Chrome.

Testing

  • arrowForRow unit tests — including a test-caught real bug: a row id transiently absent from the published order (indexOf = -1) would have matched activeIndex - 1 whenever the first row was active and wrongly shown ↑; now guarded.
  • Dispatcher tests: walk down/up, clamp at both ends, no-anchor entry (↓→first, ↑→last, incl. from a singleton pane).
  • e2e (real Chromium): mod+↓/↑ walk with clamping; hold shows exactly one ↓ chip on the active agent's down-neighbor; release clears.
  • Exact CI green: biome, make check, AUTONOMOS_INTEGRATION=1 make check, 351 unit, 20 e2e.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CwEqcpy5nXYCCqL2V6wf6k

…chips

mod+ArrowUp/ArrowDown walk the sidebar agent list relative to the active
agent — the complement to mod+1-9 for fleets past nine agents (digits only
reach rows 1-9; arrows reach everything). Clamped at the ends; with no
active-session anchor, Down enters at the top and Up at the bottom. Action
reads the same published sidebarRowOrder as the digits and mirrors a row
click.

During the mod hold, the rows directly above/below the active agent show
small up/down chips alongside the digit badges (arrowForRow, same published
order). A test-caught edge is guarded: a row id transiently missing from the
published order (indexOf -1) must not match activeIndex-1 when the first row
is active.

Non-Mac cost recorded in NON_MAC_COST (test-enforced): Ctrl+Up/Down carry
xterm encodings (CSI 1;5A/B), now app-reserved — same accepted-steal class as
the digits (ADR-066 model unchanged).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CwEqcpy5nXYCCqL2V6wf6k
Comment thread packages/dashboard/src/shortcuts/registry.ts
Comment thread packages/dashboard/src/shortcuts/actions.ts

@nox-0x nox-0x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — the navigation logic is correct, well-clamped, and reads from the same published sidebarRowOrder as the digits, so the hint chips cannot lie; the two things I found are follow-up polish, not blockers.

What I verified

  • focusAgentDelta mirrors focusAgentByIndex exactly (switchPane, then focusTerminal, then clear unread), clamps with Math.max/min instead of wrapping, and the target === activeId early-return keeps a clamped press from re-firing switchPane / markNotificationsRead on the row you are already on.
  • The index < 0 guard in arrowForRow is the right call, and the comment names the exact failure it prevents (a row transiently absent from the published order matching activeIndex - 1 when row 0 is active). Unit tests cover that case, the no-anchor case, and both edges.
  • The anchor is activePane in both the action and SessionRow, so chip and shortcut agree by construction — including the beyond-nine-agents case where a row gets an arrow but no digit.
  • mod+arrowup / mod+arrowdown normalize cleanly through eventChord (e.key.toLowerCase(), no Digit path involved), mod+shift+arrow* deliberately does not match, and isReservedChord picks them up so xterm declines them — consistent with both registry enforcement points.
  • NON_MAC_COST entries are present, so the test-enforced steal documentation holds. e2e covers walk, clamp, exactly one chip on hold, and clearing on release.

Follow-ups (non-blocking)

  1. displayChord renders the new chords as ⌘ARROWUP / ⌘ARROWDOWN in the mod+/ help overlay — cosmetic, but that overlay is the one surface where a user learns the chord. One line in the keyLabel map.
  2. Plain ⌘↑/⌘↓ (and Ctrl+↑/↓ on Linux) are real caret-movement keys inside editable fields, and the dispatcher has no editable-target gate, so they now switch agents and pull focus out of e.g. the Templates System Prompt textarea. The registry header already names the app-when-free boundary this would use.

aterrylu and others added 2 commits August 4, 2026 01:12
…ugh for mod+arrows (review)

Two review catches. (1) displayChord rendered the new chords as ⌘ARROWUP in
the help overlay — the one surface users go to LEARN the chord. Now ↑/↓.
(2) mod+arrows are native caret motions (start/end of text on mac,
paragraph-move elsewhere) and the dispatcher had no editable-target gate —
typing in a textarea, ⌘↓ switched agents and yanked focus out of the field.
New per-entry skipWhenEditing flag: the chord passes through UN-consumed
while a real editable field has focus, but still wins over xterm's helper
textarea (which is the terminal — the whole point of the boundary). Digits
keep firing everywhere (no caret semantics).

Both pinned: displayChord glyph assertions; dispatcher test covering
field-passthrough, terminal-override, and digits-still-fire-in-fields.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CwEqcpy5nXYCCqL2V6wf6k
@aterrylu
aterrylu merged commit e79aa84 into main Aug 4, 2026
5 checks passed
@aterrylu
aterrylu deleted the terry/shortcuts-arrow-nav branch August 4, 2026 08:21
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.

2 participants