You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Spec #761 (merged in PR #762) made the Tower dashboard multi-architect-aware: /api/state now exposes the full architects[] collection, and the dashboard renders one tab per architect when N > 1. #761 deliberately sliced the VS Code extension out of scope to keep the 3.0.6 hotfix small ("No VS Code extension changes in this PR. Deferred — see 'Deferred to follow-up issues'"). This issue is that deferred follow-up.
Predecessor: #755 / PR #757 shipped the routing primitive (a builder's afx send architect is affinity-routed back to its spawning architect). #761 surfaced architects in the browser. The VS Code Workspace sidebar still shows a single static "Open Architect" row that can only ever open main / the first registered architect.
The gap
In a workspace with main + <other>:
Browser dashboard: one clickable tab per architect.
VS Code sidebar: a single "Open Architect" row that only reaches main/first. There is no way to open a sibling architect's terminal from VS Code.
The feature is asymmetric across surfaces. The data needed (/api/state.architects[]) already ships as of #761, and TowerClient.getWorkspaceState() already returns it. This is presentation-only — no API, schema, or routing changes.
Scope of changes
A. WorkspaceProvider.getChildren() — make async, enumerate architects
packages/vscode/src/views/workspace.ts:32-117
Currently synchronous, returns a static TreeItem('Open Architect') (lines 35–43).
Make it async (TreeDataProvider.getChildren supports a Thenable) and await client.getWorkspaceState(workspacePath).
N = 1 → emit exactly one row, label unchanged ("Open Architect"). Visually identical to today.
N > 1 → emit one row per architect from state.architects[], each carrying that architect's name + terminalId as command arguments. (Label form is a design call: bare name to mirror the web strip, or Architect: <name> to disambiguate within the flat tree that also holds "Open Web Interface", "Spawn Builder", etc. Decide at implementation.)
Refresh is already wired via connectionManager.onStateChange → changeEmitter.fire() (line 21). Ensure the async fetch degrades gracefully when Tower is not connected — fall back to the single static row, never throw out of getChildren.
B. codev.openArchitectTerminal — parameterize
packages/vscode/src/extension.ts:270-287
Currently reads the scalar state.architect?.terminalId.
Accept the architect terminalId (+ name) from the tree item's command.arguments instead of always resolving the scalar. Keep a no-arg path (resolve the scalar) so the command stays usable from the command palette for the N = 1 case.
C. terminalManager.openArchitect — fix the map-key collision (blocker)
packages/vscode/src/terminal-manager.ts:95-102
All terminals share one this.terminals Map (line 23). The architect is keyed by the literal string 'architect' (line 96).
Consequence today: calling openArchitect for a second architect finds the first one's entry and silently .show()s the wrong terminal.
Fix: key by architect-${name} (mirroring the builder-${builderId} scheme at line 117). Signature → openArchitect(terminalId, name, focus).
Tab title: Codev: <name> (architect) for N > 1; keep Codev: Architect for the N = 1 case (see D).
Opening a non-first architect yields a distinct terminal, not a silent re-focus of the first (the collision regression test for C).
Tab-title format per N.
Acceptance criteria
In a main-only workspace, the Workspace sidebar is visually identical to pre-change: one "Open Architect" row, "Codev: Architect" terminal tab.
In a main + <other> workspace, the sidebar shows one row per architect; clicking each opens/reveals that architect's own terminal.
Clicking a non-first architect does not re-focus the first architect's terminal (map-key collision fixed).
getChildren() degrades gracefully when Tower is not connected (single static row, no thrown error).
No /api/state, schema, or routing changes.
Tests cover N=1 / N>1 / collision / label.
Out of scope
Grouping or badging builders by spawning architect in the Builders view — requires the deferred spawnedByArchitect-on-/api/state change; tracked with the afx status --architect follow-up, not here.
Context
Spec #761 (merged in PR #762) made the Tower dashboard multi-architect-aware:
/api/statenow exposes the fullarchitects[]collection, and the dashboard renders one tab per architect when N > 1. #761 deliberately sliced the VS Code extension out of scope to keep the 3.0.6 hotfix small ("No VS Code extension changes in this PR. Deferred — see 'Deferred to follow-up issues'"). This issue is that deferred follow-up.Predecessor: #755 / PR #757 shipped the routing primitive (a builder's
afx send architectis affinity-routed back to its spawning architect). #761 surfaced architects in the browser. The VS Code Workspace sidebar still shows a single static "Open Architect" row that can only ever openmain/ the first registered architect.The gap
In a workspace with
main+<other>:main/first. There is no way to open a sibling architect's terminal from VS Code.The feature is asymmetric across surfaces. The data needed (
/api/state.architects[]) already ships as of #761, andTowerClient.getWorkspaceState()already returns it. This is presentation-only — no API, schema, or routing changes.Scope of changes
A.
WorkspaceProvider.getChildren()— make async, enumerate architectspackages/vscode/src/views/workspace.ts:32-117TreeItem('Open Architect')(lines 35–43).TreeDataProvider.getChildrensupports aThenable) andawait client.getWorkspaceState(workspacePath).state.architects[], each carrying that architect'sname+terminalIdas command arguments. (Label form is a design call: bare name to mirror the web strip, orArchitect: <name>to disambiguate within the flat tree that also holds "Open Web Interface", "Spawn Builder", etc. Decide at implementation.)connectionManager.onStateChange→changeEmitter.fire()(line 21). Ensure the async fetch degrades gracefully when Tower is not connected — fall back to the single static row, never throw out ofgetChildren.B.
codev.openArchitectTerminal— parameterizepackages/vscode/src/extension.ts:270-287state.architect?.terminalId.terminalId(+name) from the tree item'scommand.argumentsinstead of always resolving the scalar. Keep a no-arg path (resolve the scalar) so the command stays usable from the command palette for the N = 1 case.C.
terminalManager.openArchitect— fix the map-key collision (blocker)packages/vscode/src/terminal-manager.ts:95-102this.terminalsMap (line 23). The architect is keyed by the literal string'architect'(line 96).openArchitectfor a second architect finds the first one's entry and silently.show()s the wrong terminal.architect-${name}(mirroring thebuilder-${builderId}scheme at line 117). Signature →openArchitect(terminalId, name, focus).Codev: <name> (architect)for N > 1; keepCodev: Architectfor the N = 1 case (see D).D. N = 1 label-regression guard
main.E. Tests
Mirror #761's dashboard test families:
Acceptance criteria
main-only workspace, the Workspace sidebar is visually identical to pre-change: one "Open Architect" row, "Codev: Architect" terminal tab.main+<other>workspace, the sidebar shows one row per architect; clicking each opens/reveals that architect's own terminal.getChildren()degrades gracefully when Tower is not connected (single static row, no thrown error)./api/state, schema, or routing changes.Out of scope
spawnedByArchitect-on-/api/statechange; tracked with theafx status --architectfollow-up, not here.afx statusCLI changes (architect-names header /--architect <name>filter) — separate deferred follow-up from Surface multiple architects in Tower dashboard + VS Code extension + afx status #761./api/state/ DB changes.References
codev/specs/761-surface-multiple-architects-in.md— see "Deferred to follow-up issues" and "Call sites NOT touched in v1 (deferred)".packages/vscode/src/views/workspace.ts:32-117,packages/vscode/src/extension.ts:270-287,packages/vscode/src/terminal-manager.ts:95-102,117.