Skip to content

feat: VS Code Workspace sidebar — list all architects (multi-architect follow-up to #761) #770

@amrmelsayed

Description

@amrmelsayed

Context

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.onStateChangechangeEmitter.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).

D. N = 1 label-regression guard

E. Tests

Mirror #761's dashboard test families:

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.
  • Any afx status CLI changes (architect-names header / --architect <name> filter) — separate deferred follow-up from Surface multiple architects in Tower dashboard + VS Code extension + afx status #761.
  • Any routing / /api/state / DB changes.

References

Metadata

Metadata

Assignees

Labels

projectNew project or feature

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions