Cycle agent terminals from keyboard and Stream Deck - #1676
Merged
Conversation
…keys in default profile
…t/PreviousAgentTerminal)
…rev-agent relay verbs
…spaces + skip unopenable agents
… an idle architect
… walk, dial progress bar, doc fixes
amrmelsayed
added a commit
that referenced
this pull request
Sep 11, 2026
amrmelsayed
added a commit
that referenced
this pull request
Sep 11, 2026
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.
PIR Review: Cycle agent terminals from keyboard and Stream Deck
Fixes #1563
Summary
Adds two VS Code commands —
codev.focusNextAgentTerminal/codev.focusPreviousAgentTerminal— that cycle focus across agent terminals in the exact rendered order of the sidebar Agents view (grouping-aware, wrap-around, opening a terminal if it isn't open), bound toctrl/cmd+alt+n/ctrl/cmd+alt+pas a hold-to-repeat motion. The same motion is exposed on the Stream Deck through the established command-relay path: twofocus-next/prev-agentverbs driving a Next/Prev Agent key pair (every deck model) and an Agent Navigator dial (Stream Deck +). The cycle roster is derived from the sameorderForDisplay+ grouping the tree renders — one source of truth, no parallel ordering.Files Changed
Scoped to this branch (merge-base
origin/main):apps/vscode/src/views/builders.ts(+180) —AgentTargettype; purepartitionArchitectGroups(shared with the renderer);agentCycleOrder();agentTargetIsFocused();revealTargetForAgent();getParentroutes idle-sibling architects to the Idle-Architects containerapps/vscode/src/extension.ts(+64) —cycleAgentTerminal(direction)+ the two commands; open +reveal({select})apps/vscode/src/terminal-manager.ts(+21) —getActiveArchitectName()apps/vscode/package.json(+20) — command contributions + keybindings (when: codev.hasWorkspace)apps/vscode/src/command-relay.ts(+4) —focus-next-agent/focus-prev-agentallowlist entriesapps/streamdeck/src/actions.ts(+80) —FocusNextAgentKey/FocusPrevAgentKey+AgentNavdialapps/streamdeck/src/plugin.ts(+6) — register the three actionsapps/streamdeck/com.cluesmith.codev.sdPlugin/manifest.json(+51) — 2 Keypad + 1 Encoder actionapps/streamdeck/README.md(+15) — document the keys + dialapps/vscode/src/__tests__/agent-cycle-order.test.ts(+357, new),command-relay.test.ts(+12),terminal-manager.test.ts(±6, brittle-test scoping fix),apps/streamdeck/src/__tests__/actions.test.ts(+58)codev/resources/lessons-learned.md— the two-id-space seam lesson (below)codev/plans/1563-*.md,codev/reviews/1563-*.md,codev/state/pir-1563_thread.md— protocol artifactsCommits
git log origin/main..HEAD --oneline(implementation, excluding porch/plan/thread bookkeeping):ab1db5ce1VS Code: cycle agent terminals in sidebar orderdbbdf0ddbStream Deck: key pair + dial via focus-next/prev-agent relay verbs705278f45Fix agent cycle collapsing to index 0: bridge builder id spaces + skip unopenable agents027feabb7Select the agent's sidebar row when cycling (reveal with select)68976603fExpand the Idle Architects container when cycling selects an idle architect5a84ce060Simplify agentCycleOrder: fold the idle-sibling pass into the main loopc017d68f5Extract architectOrder for readabilityTest Results
npm run build: ✓ passnpm test: ✓ pass (core suite 6053 pass / 48 skip)check-types+lint+test:unit(1004 pass) ✓; streamdeckcheck-types+ manifestvalidate+test(257 pass) ✓app, its builder, and the idle architects; the sidebar selection follows the cycle and expands the Idle-Architects container. Stream Deck not hardware-tested this round.Architecture Updates
No module-boundary changes — this feature adds two commands and three deck actions over existing seams (the Agents tree provider,
TerminalManager, the command relay). The one system-shape fact worth recording is the two builder id spaces (OverviewBuilder.idvs Tower-canonical terminal id) and the rule to bridge them withresolveAgentName; per the architect's direction it is captured as a lesson (below) rather than an arch-doc entry, since it is a matching-discipline rule, not a new boundary. HOTarch-critical.mduntouched (at cap; nothing here displaces an entry).Lessons Learned Updates
Routed to COLD
codev/resources/lessons-learned.md→ Architecture (a spec-narrow recipe, not a top-10 always-injected rule, so HOTlessons-critical.mdis untouched):Things to Look At During PR Review
agentCycleOrder()axis-dependence (builders.ts) — the roster is builders-only on stage/area and interleaves architect headers on the architect axis. This is the deliberate "mirror the sidebar exactly" reading (owner-confirmed): architects only cycle in Architect grouping. The anti-drift test pins that the architect order equals whatarchitectRootChildrenrenders (the vscode: group builders in the tree by area (area/* label namespace, identical to backlog) #818 shared-function discipline).agentTargetIsFocused) — the bug found at dev-approval. It usesresolveAgentNameboth directions and is covered by regression tests keyed on the exact3816vsbugfix-3816collapse. This is the highest-value spot to scrutinize.agentCycleAttemptOrder+cycleAgentTerminal) — the walk is a pureagentCycleAttemptOrder(order, currentIndex, direction)(unit-tested for wrap-around, ≤1 no-op, and the nothing-focused start) whose entries the command opens in order, taking the first that succeeds. The builder open runsquiet(new param onopenBuilderByRoleOrId) so a stale roster row is skipped silently rather than stalling behind the sticky "no terminal" recovery prompt; a rare non-live architect still shows a transient warning as it is skipped (its roster is the live-session set, so this is uncommon).getParentchange for idle architects (builders.ts) — now returns the Idle-Architects container for a folded idle sibling sorevealexpands it. Verify it still returnsundefined(root) for stage/area headers,main, populated siblings, and a lone idle sibling (tests cover these).AgentNav) face shows the current builder (id + progress bar), following VS Code focus via the builder-onlybuilder-activeactivity hook; the keys carry staticNext Agent/Prev Agentlabels. Neither shows an architect name (deferred; plan decision point 3).How to Test Locally
pir-1563→ Review Diffcd apps/vscode && pnpm package && pnpm vsix), install via "Extensions: Install from VSIX…", reloadn/p— focus walks the Agents order, wraps; a closed agent's terminal opensConsultation (3-way, single advisory pass)
Gemini APPROVE, Claude COMMENT, Codex REQUEST_CHANGES — the two non-approvals converged on a consistent, fair set, all addressed in this branch before the pr gate:
openBuilderByRoleOrIdawaited a sticky recovery prompt on a stale row. Fixed by a newquietparam that skips the prompt/warning on the cycle path; the review claim above is corrected. (Architect skips still show a rare transient warning — noted honestly.)agentCycleAttemptOrderand added wrap-around / ≤1-no-op / nothing-focused-start / skip-order tests.revealTargetForAgentcontradicting the container-expand fix (Claude): updated.agentTargetIsFocused(Claude, minor): documented with a comment.ctrl+alt+*family — no change.Per PIR's single-pass rule the correctness backstop is these fixes + their regression tests + this pr-gate review; there is no automated re-review.
Notes for the Record
apps/vscode/CHANGELOG.md) and release notes (docs/releases/UNRELEASED.md) are accumulated on thedocs/vscode-changelogbranch post-merge (referencing the PR#), perUNRELEASED.md's own template; the plan's mention of in-PR changelog edits was stale against that convention. This deviation was ratified by the architect at the dev-approval gate. Stream Deck marketplace collateral (marketplace/description.md,release-notes.md) is likewise synced at the next plugin submission, not per-PR.