Context
Follows on from #936 (terminal-adapter reconnect-loop fix). Once that work lands, the terminal will give up after N failed reconnect attempts and print a red "max reconnect attempts reached" message. At that point the terminal is dead — the user has to close the tab and re-open via the sidebar / command palette to recover. Three clicks across two UI surfaces, with the user needing to know where each control lives.
This issue tracks adding a manual-reconnect affordance: a one-click recovery control surfaced where the user just saw the failure, so they don't have to do the close+reopen dance.
Why split from #936
#936's original scope bundled the spam-loop fix (adapter-level resilience: backoff, max-retries, state reset, identity-checked close-events) with the recovery-after-give-up UX. They're orthogonal concerns:
Splitting lets #936's PR land cleanly without dragging in UX work, and lets this issue go through PIR (where the design calls and visual verification belong) without being gated on the defect fix.
Three shape options
Each works; the plan-approval gate picks one (or composes).
Shape 1 — Terminal link (cheapest, ~15-20 LOC)
The give-up message itself becomes a clickable token:
[Codev: Connection lost — max reconnect attempts reached. Click Reconnect to try again]
^^^^^^^^^
clickable
Mechanism: vscode.window.registerTerminalLinkProvider — extensions can register link providers that detect specific patterns in terminal text and surface them as clickable links. Click → run command → adapter.reconnect().
Pros: localized to the terminal pane where the user just saw the failure; no cross-surface jump; one click to recover; minimal new surface area.
Cons: discoverable only if the user reads the failure message; the link styling depends on the user's theme's terminal.foreground vs link-decoration tokens.
Shape 2 — Toast notification with button
After N failed attempts, fire a vscode.window.showWarningMessage with [Reconnect] [Dismiss] actions. Same mechanism the existing gate-toast uses (packages/vscode/src/notifications/gate-toast.ts).
Pros: high visibility — the user sees the recovery option even if they weren't watching the terminal at the give-up moment; toast affordances are a familiar pattern in the extension.
Cons: more intrusive (toast slides in over other UI); harder to dismiss if the user wants to acknowledge the failure but not act on it; doesn't preserve the failure context the way the in-terminal message does.
Shape 3 — Status-bar action
When any terminal hits the give-up state, flip the Codev status-bar chip from Codev: Connected to Codev: Reconnect Terminal (with a click action calling the appropriate adapter.reconnect()).
Pros: persistent, always-visible (no time-out like toast); doesn't require the user to be looking at the terminal.
Cons: ambiguous when multiple terminals are in give-up state (which one does "Reconnect" target?); status-bar is shared real-estate with other indicators; less localized than Shape 1.
Recommended default for the plan
Shape 1 (terminal link). Justification: lowest cost, most contextually appropriate (recovery affordance lives where the failure was shown), no ambiguity with multi-terminal scenarios, no contention for status-bar real estate, doesn't add a toast to the user's notification stream.
Shapes 2 and 3 are optional follow-ons if usage shows Shape 1 is insufficient.
Design calls for plan-approval
- Affordance shape: Shape 1 / 2 / 3 / combination (see above; recommended default: Shape 1).
- Reconnect attempts counter on retry: does clicking "Reconnect" reset the attempt counter to 0 (full fresh retry chain), or restart from the last attempt (1 more retry, then give up again)? Recommended default: full reset — the user is signaling intent, so honor it with a full retry budget.
- Visual styling of the terminal link (Shape 1 only): use VSCode's default link color tokens, or a Codev-specific accent? Recommended default: VSCode's default link styling so it auto-themes against dark/light/high-contrast.
- Repeated give-up cycles: if the user clicks "Reconnect", retries fail again, gives up again — does the new link still work, or do we transition to a different state (e.g. "persistent failure — restart Tower")? Recommended default: link still works every time; trust the user to know when to escalate to a Tower restart.
Acceptance
Out of scope
Why PIR
Real design surface (three shape choices with tradeoffs documented above) and the result is user-visible UI behavior that needs running-app verification across themes — both gates of PIR earn their keep here. AIR would technically fit if Shape 1 is locked in pre-spawn, but the plan-approval gate is worth having for the four design-call defaults to land deliberately.
Context
Follows on from #936 (terminal-adapter reconnect-loop fix). Once that work lands, the terminal will give up after N failed reconnect attempts and print a red "max reconnect attempts reached" message. At that point the terminal is dead — the user has to close the tab and re-open via the sidebar / command palette to recover. Three clicks across two UI surfaces, with the user needing to know where each control lives.
This issue tracks adding a manual-reconnect affordance: a one-click recovery control surfaced where the user just saw the failure, so they don't have to do the close+reopen dance.
Why split from #936
#936's original scope bundled the spam-loop fix (adapter-level resilience: backoff, max-retries, state reset, identity-checked close-events) with the recovery-after-give-up UX. They're orthogonal concerns:
terminal-adapter.ts— bounded change, mechanical, no real design surface beyond the retry-curve constants.Splitting lets #936's PR land cleanly without dragging in UX work, and lets this issue go through PIR (where the design calls and visual verification belong) without being gated on the defect fix.
Three shape options
Each works; the plan-approval gate picks one (or composes).
Shape 1 — Terminal link (cheapest, ~15-20 LOC)
The give-up message itself becomes a clickable token:
Mechanism:
vscode.window.registerTerminalLinkProvider— extensions can register link providers that detect specific patterns in terminal text and surface them as clickable links. Click → run command →adapter.reconnect().Pros: localized to the terminal pane where the user just saw the failure; no cross-surface jump; one click to recover; minimal new surface area.
Cons: discoverable only if the user reads the failure message; the link styling depends on the user's theme's
terminal.foregroundvs link-decoration tokens.Shape 2 — Toast notification with button
After N failed attempts, fire a
vscode.window.showWarningMessagewith[Reconnect] [Dismiss]actions. Same mechanism the existing gate-toast uses (packages/vscode/src/notifications/gate-toast.ts).Pros: high visibility — the user sees the recovery option even if they weren't watching the terminal at the give-up moment; toast affordances are a familiar pattern in the extension.
Cons: more intrusive (toast slides in over other UI); harder to dismiss if the user wants to acknowledge the failure but not act on it; doesn't preserve the failure context the way the in-terminal message does.
Shape 3 — Status-bar action
When any terminal hits the give-up state, flip the Codev status-bar chip from
Codev: ConnectedtoCodev: Reconnect Terminal(with a click action calling the appropriateadapter.reconnect()).Pros: persistent, always-visible (no time-out like toast); doesn't require the user to be looking at the terminal.
Cons: ambiguous when multiple terminals are in give-up state (which one does "Reconnect" target?); status-bar is shared real-estate with other indicators; less localized than Shape 1.
Recommended default for the plan
Shape 1 (terminal link). Justification: lowest cost, most contextually appropriate (recovery affordance lives where the failure was shown), no ambiguity with multi-terminal scenarios, no contention for status-bar real estate, doesn't add a toast to the user's notification stream.
Shapes 2 and 3 are optional follow-ons if usage shows Shape 1 is insufficient.
Design calls for plan-approval
Acceptance
adapter.reconnect()and starts a fresh retry chain.dev-approvalgate).Out of scope
Why PIR
Real design surface (three shape choices with tradeoffs documented above) and the result is user-visible UI behavior that needs running-app verification across themes — both gates of PIR earn their keep here. AIR would technically fit if Shape 1 is locked in pre-spawn, but the plan-approval gate is worth having for the four design-call defaults to land deliberately.