Skip to content

vscode + tower: 'No active terminal for X' warning is unactionable — Tower's session registry and overview disagree, no in-extension recovery path #982

@amrmelsayed

Description

@amrmelsayed

Symptom

Clicking a builder row in the Codev sidebar produces a warning toast:

Codev: No active terminal for <builder-id>

…then nothing else happens. The builder row stays in the sidebar (looking normal), but you can't open its terminal from the click. The user is left with a dead-end UX: no indication of what's wrong, no in-extension affordance to recover.

The warning fires at packages/vscode/src/terminal-manager.ts:201 inside openBuilderByRoleOrId:

if (!builder?.terminalId) {
  vscode.window.showWarningMessage(`Codev: No active terminal for ${roleOrId}`);
  return;
}

So Tower's getWorkspaceState returns a builder record matching the clicked row, but that record's terminalId is null or empty. The overview (which the sidebar renders from) and the workspace-state (which the terminal opener queries) disagree on whether this builder has a live terminal session.

Why the disagreement happens

Three known triggers, in order of likelihood:

  1. Tower restarted. Tower's PTY session registry is in-memory; the disk-persisted builder records survive restarts but the session IDs that bind a builder to a live PTY don't. Sidebar still shows the builder (filesystem-sourced); clicking fails because terminalId is gone.
  2. Terminal session died without the builder being cleaned up. PTY child crashed, WebSocket disconnected past the GC timeout, network blip dropped the session and Tower forgot it. Builder record persists; terminal record vanishes.
  3. Race window during spawn or recover. Briefly between "builder registered" and "terminal session created" the overview may report the builder without a terminalId. Self-corrects on the next overview tick.

(1) and (2) are persistent and require user action. (3) is transient and self-heals.

Why it matters

The warning is correct (something IS wrong) but the UX is unactionable. The user has to know that:

  • afx workspace recover exists and is the right tool
  • They have to run it from the workspace root, not inside a worktree
  • It only works if the builder process itself is still alive somewhere

A first-time user (or any user mid-flow) hits the toast and has no obvious next step. The sidebar row remains looking healthy, which compounds the confusion. The bug-class is silent state divergence with a downstream "polite" failure — exactly the shape the v3.1.7 #916 fix was designed to head off for the overview case, but the same divergence in the opposite direction (overview populated, individual fields stale) wasn't covered there.

Proposed improvements (plan-approval picks the layer)

Five plausible directions, ranged from "polish the dead-end" to "fix the underlying divergence":

  1. Better error message + recovery suggestion. Replace the bare toast with something like "Builder #X's terminal session is gone (likely Tower restart). Run afx workspace recover from the workspace root to revive it, or cleanup if it's no longer needed." Cheap; pure vscode.
  2. In-extension recover affordance. Add a Recover button on the toast that invokes afx workspace recover for that specific builder (or the whole workspace). One-click instead of "go look up the right command". Pure vscode plus a small CLI integration.
  3. Sidebar visual signal. Builders without a live terminalId render with a distinct icon (e.g., unlink or circle-slash) so the user can see before clicking that the session is dropped. Pure vscode.
  4. Auto-recover on extension activation. Detect on load that there are builders without terminalIds and either run recovery or prompt the user. Stronger UX but a behavior decision (auto-runs vs prompts) that needs plan-gate.
  5. Root-cause fix: persist Tower's session registry. Survive restarts so the disk record and the runtime record don't diverge in the first place. Largest scope; addresses cause (1) but not (2) or (3).

(1) and (2) compose cleanly and could ship together as a v1; (3) is independent and can layer on; (4) and (5) are bigger investments worth deferring.

Acceptance (loose, pending plan-gate)

  • When terminalId is missing on a clicked builder row, the user gets a clear signal of what's wrong and what to do next, not just a bare warning.
  • At least one of the recovery paths (suggested command, one-click button, auto-recover) is in-extension and doesn't require terminal-flipping or doc-lookup.
  • The sidebar surface either visually flags the dropped-session state (option 3) or the toast self-recovers gracefully on the next overview tick when cause was transient.
  • No regression to the happy-path click behavior (terminalId present → terminal opens) or to existing afx workspace recover semantics.

What this isn't

Related

  • #915afx workspace recover semantics for previously-cleaned-up builders.
  • #916 — sidebar last-known-good fix (shipped in v3.1.7). Adjacent state-divergence class, opposite direction.
  • packages/vscode/src/terminal-manager.ts:180-208openBuilderByRoleOrId (where the warning lives).

Metadata

Metadata

Assignees

Labels

area/cross-cuttingTouches multiple areas — needs coordinated handling

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