Skip to content

vscode: Recoverable Builders section in Workspace sidebar + on-activation notification #1168

Description

@amrmelsayed

Problem

After a machine restart or Tower crash, builders don't auto-recover — only architects do. Users have to know to run afx workspace recover --apply from the CLI to revive them, and most users don't discover this until their in-flight work goes missing. The command works (issue #829), but discoverability is the real gap.

Design context: the asymmetry between architect auto-recovery and manual builder recovery is intentional (see packages/codev/src/agent-farm/commands/workspace-recover.ts for the safety gates: eligibility filtering, dry-run default, per-protocol revivability). This issue does not change the recovery discipline. It only surfaces the CLI's dry-run result in the VS Code sidebar so users can recover from a click instead of a command they didn't know existed.

Scope

Placement — Workspace view, standalone section

A new collapsible section in the Codev sidebar's WORKSPACE view, sibling to Architects:

WORKSPACE
├─ Architects
│  ├─ MAIN
│  ├─ REVIEWER
│  └─ + Add Architect
├─ Recoverable Builders (3)         [Recover All]  header context menu
│  ├─ pir-1149 · Claude crash-loop fix · 2h ago      [Recover] [Cleanup]
│  ├─ pir-1150 · Sibling resurrect · 2h ago          [Recover] [Cleanup]
│  └─ pir-1151 · ... · 2h ago                        [Recover] [Cleanup]
├─ Spawn Builder
└─ New Shell

Visibility: section is hidden entirely when the recoverable set is empty. Appears when non-empty.

Row shape: <builder-id> · <issue title if resolvable> · <age since last activity> plus per-row Recover and Cleanup actions (context-menu items).

Ineligible builders are NOT displayed. Only builders that would appear in afx workspace recover --apply's eligible set. Ineligible (terminal phase, unsupported protocol, too old) are omitted entirely to keep the section focused.

Header actions:

  • Recover All — bulk-revive every row in the section. Same underlying operation as per-row, batched.

Refresh model — one-shot check on extension activation only

Rationale: recoverable builders only appear after Tower had to cold-boot from an outage. During normal operation (Tower alive), the recoverable set is empty. Fresh recoverables only accumulate when a machine restart happens, at which point VS Code and the extension are re-launching too.

Implementation:

  • Extension activation → single GET /api/recover-preview fetch → renders section if non-empty
  • No SSE subscription for builders-recoverable-changed (out of scope; unnecessary for the intended failure mode)
  • After user takes an action (Recover / Cleanup), the section refreshes via a follow-up preview fetch
  • Not re-checked on Tower disconnect/reconnect within a session — reduces noise and matches the "restart-triggered" use case

Out of scope: any auto-refresh mechanism. If Tower crashes mid-session and rebuilds recoverable state without a VS Code restart, the sidebar will not show it until the extension is reactivated. Acceptable trade-off for the common case.

Notification — once per session, on activation

If the initial GET /api/recover-preview returns a non-empty set:

  • Show a VS Code information notification: "N builders are stopped from your workspace after a Tower restart. Recover them?"
  • Actions: Recover All, View, Dismiss
  • View reveals + expands the Workspace view's Recoverable Builders section
  • Recover All runs the bulk revive
  • Dismiss closes without another notification this session
  • Notification fires at most once per extension activation (a globalState-tracked session flag)

Backend — Tower HTTP endpoints

Two new endpoints, both scoped to the current workspace:

  1. GET /api/recover-preview?workspace=<path> — returns the recoverable set in JSON, using the same eligibility logic as afx workspace recover dry-run.
    • Response shape: { recoverable: [{ id, issueId?, issueTitle?, protocol, worktreePath, ageDays }] }
    • Ineligible builders excluded server-side
  2. POST /api/recover?workspace=<path> — triggers revival. Body: { ids: string[] } (single or bulk). Response: per-id success/error map.
  3. POST /api/cleanup-builder?workspace=<path> — removes a builder from state without revival. Body: { id: string }.

Refactor: workspace-recover.ts currently tangles eligibility with dry-run rendering + CLI shell-out. Extract the eligibility predicate into a shared module (workspace-recover-eligibility.ts or similar) so the endpoint and CLI both consume it. No behavior change to the CLI itself.

Auth posture: no change. Tower's model is localhost-only. Standard warning: don't enable BRIDGE_MODE=1 — these endpoints do real destructive work and Tower has no application-layer auth.

Prerequisites and coordination

Acceptance

  • After a Tower restart with 3 builders in the workspace, WORKSPACE > Recoverable Builders (3) renders on the next VS Code activation
  • Section is hidden entirely when the recoverable set is empty
  • Notification fires exactly once on activation with a non-empty set; suppressed on re-activation the same session after Dismiss
  • Recover All from the header revives every row; per-row Recover revives one
  • Cleanup removes a builder from state without spawning
  • Ineligible builders (terminal phase, unsupported protocol, too old) never appear
  • After any action, the section re-fetches its state via the preview endpoint
  • CLI afx workspace recover output is unchanged (uses the same shared eligibility module)

Out of scope

  • SSE-based real-time refresh of the section
  • Cross-workspace recoverable view (only current workspace)
  • Any change to the auto-revive discipline (architects continue to auto-recover, builders remain user-triggered)
  • Any change to the CLI's dry-run / --apply / max-age / --include-stale semantics
  • Any change to Tower's HTTP auth model

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/vscodeArea: VS Code extension

    Type

    No type

    Fields

    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