feat(shortcuts): mod+↑/↓ relative agent navigation + neighbor hint chips - #306
Merged
Conversation
…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
nox-0x
reviewed
Aug 4, 2026
nox-0x
reviewed
Aug 4, 2026
nox-0x
approved these changes
Aug 4, 2026
nox-0x
left a comment
Collaborator
There was a problem hiding this comment.
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
focusAgentDeltamirrorsfocusAgentByIndexexactly (switchPane, then focusTerminal, then clear unread), clamps withMath.max/mininstead of wrapping, and thetarget === activeIdearly-return keeps a clamped press from re-firingswitchPane/markNotificationsReadon the row you are already on.- The
index < 0guard inarrowForRowis the right call, and the comment names the exact failure it prevents (a row transiently absent from the published order matchingactiveIndex - 1when row 0 is active). Unit tests cover that case, the no-anchor case, and both edges. - The anchor is
activePanein both the action andSessionRow, 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+arrowdownnormalize cleanly througheventChord(e.key.toLowerCase(), no Digit path involved),mod+shift+arrow*deliberately does not match, andisReservedChordpicks them up so xterm declines them — consistent with both registry enforcement points.NON_MAC_COSTentries 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)
displayChordrenders the new chords as⌘ARROWUP/⌘ARROWDOWNin the mod+/ help overlay — cosmetic, but that overlay is the one surface where a user learns the chord. One line in thekeyLabelmap.- 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-freeboundary this would use.
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 publishedsidebarRowOrder— 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.NON_MAC_COSTtable. ⌘↑/↓ (page top/bottom) is interceptable in Chrome.Testing
arrowForRowunit tests — including a test-caught real bug: a row id transiently absent from the published order (indexOf= -1) would have matchedactiveIndex - 1whenever the first row was active and wrongly shown ↑; now guarded.make check,AUTONOMOS_INTEGRATION=1 make check, 351 unit, 20 e2e.🤖 Generated with Claude Code
https://claude.ai/code/session_01CwEqcpy5nXYCCqL2V6wf6k