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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/vscodeArea: VS Code extension

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions