Skip to content

fix(wsl-host): a terminal on a stopped distro offers Start, and New Terminal starts it - #35168

Merged
nwparker merged 6 commits into
mainfrom
nwparker/wsl-terminal-start-stopped-host
Oct 28, 2026
Merged

nwparker merged 6 commits into
mainfrom
nwparker/wsl-terminal-start-stopped-host

Conversation

@nwparker

@nwparker nwparker commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 12 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​834 $\color{#cf222e}{\Huge{\mathbf{−}}}$​291 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​543
Prod 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​242 $\color{#cf222e}{\Huge{\mathbf{−}}}$​48 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​194

Flag-off: Only WSL hosts are affected, so nothing changes with the experimental WSL host setting off. The new card and the start-before-New-Terminal step only act when a WSL host's last status is "distro stopped". SSH servers, paired servers and local workspaces never reach them.
User-risk: WSL host users only. Clicking Start on a pane, or opening a New Terminal, now boots a stopped distro, the same as the chat's Start. Nothing automatic boots it. A host whose Remove is still pending refuses with the existing "removal pending" message rather than starting.

ELI5

If you stop a WSL distro (for example with wsl --terminate Ubuntu), its terminals in Orca used to say "Reconnecting… retrying automatically" forever, and New Terminal didn't help. Orca correctly never starts a stopped distro by itself, but that left no way back. Now the terminal says "Ubuntu is stopped" with a Start button, and opening a New Terminal on that project starts the distro too.

What Changed

  • Before:
    • After the distro stopped, every terminal on it showed the server-wide "Reconnecting to Ubuntu (WSL)… Down for N min… retrying automatically" notice indefinitely.
    • New Terminal on the project failed with "Ubuntu was stopped…".
    • Only Settings → Remote Orca Servers → Connect, or switching away from the project and back, brought it back.
  • After:
    • Each terminal on that host shows "Ubuntu is stopped" with a Start button instead of the "retrying automatically" notice. The wording is the chat's, from feat(wsl-host): a chat on a stopped WSL distro says so and offers Start #34681.
    • Start boots the distro, reconnects the host and resumes the pane.
    • New Terminal (tab bar, the tab group's "+" menu, Cmd+J's New Terminal, "Open in terminal" from the file explorer, and the "new terminal with this shell" option) starts a stopped host first, then opens the terminal.
    • Background retries still never boot the distro.

Mechanism

  • Shared start helper: src/renderer/src/lib/wsl-host-user-start.ts holds the Start that the chat used privately. wsl-host-stopped-status.ts holds the store selector the panes read. The reconnect helper is loaded lazily, so terminal creation's module graph doesn't grow.
    • It calls wslHosts.connect({ environmentId, withdrawPendingRemoval: false }) (the user-mode connect that may boot), then reconnects the host and reloads its projects.
    • Repeated clicks while it boots share one start.
    • The chat's Start now uses this helper.
  • Pane card: TerminalPaneRecoveryPortals reads the host's WSL status. When the workspace's host is a stopped distro, each pane on it gets the new WslHostStoppedCard in place of the reconnect banner, and the server-wide "retrying automatically" notice stays silent.
    • The card shows whether or not the pane is mid-recovery, because a stopped distro's terminal is dead either way.
    • It also shows on a pane whose create failed before it reached the host.
    • It stays behind the existing "WSL hosts are turned off" card, which takes precedence.
    • Where the card shows, the pane's raw "Ubuntu was stopped…" error toast is hidden (use-wsl-host-stopped-pane.ts, using the same paneShowsWslHostStoppedCard condition as the card), as it already is for SSH recovery. Otherwise the toast sat over the Start button. A pane on another server, or a host that can't run, keeps its real error.
  • New Terminal: createWebRuntimeSessionTerminal takes a userAct option. It's a client-side option and never goes over the wire.
    • With it set, a stopped WSL host is started before the create. If the start is refused, nothing is created and the user sees why.
    • Only the explicit New Terminal paths pass it. The initial-terminal bootstrap, session-tab sync and wake-time terminal creation don't, so they can't boot a distro.
  • Main is unchanged: runtime calls still go through ensureForRuntimeCall, which never boots.

Why

  • Renderer-side, at the user's act. Main can't tell a user's create from a background one, because both are the same runtime call. Marking the act where the click happens keeps E9 intact, with no "maybe boot" path in main.
  • Reusing feat(wsl-host): a chat on a stopped WSL distro says so and offers Start #34681's connect path, copy and refusal. Chat and terminal now behave the same way, including refusing a host whose Remove is still pending (E11).
  • A per-pane card rather than changing the server notice. It mirrors how the existing "WSL hosts are turned off" card already replaces the reconnect UI for a host that can't run, and it needs no new strings.

Linked Issue

Internal WSL rewrite: flag-on blocker from the Windows real-host check.

Visual Proof

From the e2e run below (hidden window, CDP screenshot): the terminal pane on a stopped distro shows "Ubuntu is stopped" with a Start button at the bottom of the pane. I kept the screenshots out of the PR because the terminal prompt shows the test machine's hostname.

Testing

  • wsl-host-terminal-start.spec.ts (new e2e, fake WSL transport; hidden; passed 4 times locally, about 1 min each):

    • New Terminal on a running host opens a terminal.
    • After the distro stops, the pane shows the stopped card. For 10 s the fake records no boot, and the distro stays stopped.
    • Start boots it and the card goes away.
    • Stopping again, then New Terminal, boots the distro and opens another terminal.
  • wsl-host-chat.spec.ts still passes. Its launch helpers moved to tests/e2e/helpers/wsl-host-fake-desktop.ts, as its own comment asked, and the new spec reuses them.

  • Unit tests:

    • WslHostStoppedCard.test.tsx: the card names the distro and offers Start, and showing it boots nothing. A click boots with withdrawPendingRemoval: false and then resumes the pane. A refused start toasts and leaves the pane. Repeated clicks start once.
    • TerminalPaneRecoveryPortals.test.tsx: every pane of a stopped distro gets the card, with no server notice and no reconnect banner. That includes a pane whose create failed before it knew its host.
    • web-runtime-terminal-creation.wsl-host-start.test.ts:
      • a user's New Terminal starts the host before creating;
      • a background create never boots it;
      • running and non-WSL hosts are untouched;
      • a refused start creates nothing.
  • The broad renderer suites pass: terminal-pane, native-chat, runtime, store, tab-group, terminal and lib (2,532 files).

  • createNewTerminalTab tests moved to terminal-tab-create.test.ts (the module they test), because the old file hit the line cap. Expectations now include { userAct: true }.

  • Load rule: pnpm tc, typecheck:ci, oxlint, the anti-slop lint, oxfmt, check:code-quality:changed, and the five localization checks. No new strings.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • SSH: the card and the start only apply to WSL hosts. A stopped status exists only for them; SSH servers keep their existing Reconnect and sign-in flows.
  • Windows: the real-host check should be re-run on a Windows machine: wsl --terminate, then Start, then New Terminal.
  • Mobile and paired web client: they keep their existing behaviour, because wslHosts is desktop-only and the helper does nothing without it.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 17 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 43bb5a28-eb2c-473d-aeca-91c81b87435f
Commits

Reviewing files that changed from the base of the PR and between e274e97 and a6d25ff.

Files selected for processing: 1
  • tests/e2e/wsl-host-terminal-start.spec.ts

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 68dac687-40b7-431c-a69b-19cc7ae5a158
Commits

Reviewing files that changed from the base of the PR and between 6108bf6 and e274e97.

Files selected for processing: 6
  • src/renderer/src/components/terminal-pane/TerminalPaneRecoveryPortals.tsx
  • src/renderer/src/components/terminal-pane/TerminalPaneSurface.tsx
  • src/renderer/src/components/terminal-pane/use-wsl-host-stopped-pane.test.ts
  • src/renderer/src/components/terminal-pane/use-wsl-host-stopped-pane.ts
  • src/renderer/src/lib/wsl-host-stopped-status.test.ts
  • src/renderer/src/lib/wsl-host-stopped-status.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

Walkthrough

The changes add a stopped-WSL recovery card to terminal panes and add host startup before user-requested terminal creation. Shared startup helpers connect to the stopped host and reload its projects. Pane recovery suppresses the remote-outage notice and active-pane error toast for stopped hosts. Terminal-creation and pane-recovery tests cover these paths. Shared fake-WSL test helpers support a new end-to-end test and the existing WSL chat test.

Priority: Normal

Merge Risk: Moderate · previous review e274e

Some bridged panes may show the wrong recovery card, and two test checks can block CI. Address these before merging.

Pre-merge checks: Passed 3 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Description check Warning The description is detailed and covers the user impact, mechanism, rationale, testing, and scope. However, it does not provide an actual linked issue and does not attach the required visual proof or s… Add the actual issue reference under Linked Issue. Attach before-and-after screenshots or a video, or write N/A with a brief reason if visual proof is genuinely not applicable. Update the testing and checklist items to reflect whether the…
Docstring Coverage Warning Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main user-facing WSL recovery changes: offering Start for stopped distros and starting them before New Terminal.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is detailed and covers the user impact, mechanism, rationale, testing, and scope. However, it does not provide an actual linked issue and does not attach the required visual proof or state N/A exactly for this UI change. Several required validation checklist items also remain unchecked.

Resolution

Add the actual issue reference under Linked Issue. Attach before-and-after screenshots or a video, or write N/A with a brief reason if visual proof is genuinely not applicable. Update the testing and checklist items to reflect whether the required commands passed locally or will be covered by CI.

Full details: Docstring Coverage

Explanation

Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 17 functions across 24 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fe446906-4838-4f30-8823-f3e49ed1ce03
Commits

Reviewing files that changed from the base of the PR and between 6981f34 and 6108bf6.

Files selected for processing: 22
  • src/renderer/src/components/native-chat/use-native-chat-host-outage-notice.ts
  • src/renderer/src/components/tab-group/useTabGroupCreationCommands.ts
  • src/renderer/src/components/terminal-pane/RemoteRuntimeRecoveryCard.tsx
  • src/renderer/src/components/terminal-pane/TerminalPaneRecoveryPortals.test.tsx
  • src/renderer/src/components/terminal-pane/TerminalPaneRecoveryPortals.tsx
  • src/renderer/src/components/terminal-pane/TerminalPaneSurface.tsx
  • src/renderer/src/components/terminal-pane/WslHostStoppedCard.test.tsx
  • src/renderer/src/components/terminal-pane/WslHostStoppedCard.tsx
  • src/renderer/src/components/terminal/terminal-tab-actions.test.ts
  • src/renderer/src/components/terminal/terminal-tab-create.test.ts
  • src/renderer/src/components/terminal/terminal-tab-create.ts
  • src/renderer/src/components/use-terminal-create-actions.ts
  • src/renderer/src/lib/wsl-host-stopped-status.ts
  • src/renderer/src/lib/wsl-host-user-start.test.ts
  • src/renderer/src/lib/wsl-host-user-start.ts
  • src/renderer/src/runtime/web-runtime-terminal-creation.ts
  • src/renderer/src/runtime/web-runtime-terminal-creation.wsl-host-start.test.ts
  • src/renderer/src/store/slices/cmd-j-create-actions.test.ts
  • src/renderer/src/store/terminals/terminal-active-workspace-creation.ts
  • tests/e2e/helpers/wsl-host-fake-desktop.ts
  • tests/e2e/wsl-host-chat.spec.ts
  • tests/e2e/wsl-host-terminal-start.spec.ts
Files with no reviewable changes: 1
  • src/renderer/src/components/terminal/terminal-tab-actions.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

!wslHostUnavailable &&
stoppedWslDistro !== null &&
ownerEnvironmentId !== null &&
(paneEnvironmentId === null || paneEnvironmentId === ownerEnvironmentId)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major · Functional Correctness · Heavy lift

Supported by static analysis

Script executed:

sed -n '55,175p' src/renderer/src/components/terminal-pane/TerminalPaneRecoveryPortals.tsx

Repository: stablyai/orca

Length of output: 5414


Script executed:

set -o pipefail
rg -n -F --glob '*.ts' --glob '*.tsx' \
  -e 'getRuntimeEnvironmentId' \
  -e 'paneTransportsRef' \
  -e 'bridg' \
  -e 'create failed' \
  src/renderer/src/components/terminal-pane src/renderer/src | head -n 240

Repository: stablyai/orca

Length of output: 35010


Script executed:

set -o pipefail
rg -n -F --glob '*.ts' --glob '*.tsx' \
  -e 'getRuntimeEnvironmentId' \
  -e 'paneTransportsRef' \
  -e 'bridg' \
  -e 'create failed' \
  src/renderer/src/components/terminal-pane src/renderer/src | head -n 260

Repository: stablyai/orca

Length of output: 38679


Do not treat every null pane environment as the WSL owner.

legacy-relay-bridge-transport.ts returns null for an established bridge, not only for a failed create. The current condition maps that value to the owner’s WslHostStoppedCard, replacing the bridged pane’s reconnect banner. Distinguish the established bridge state from a create failure before showing the stopped-distro card.

{/* Let SSH recovery own its strip instead of covering it with the raw connection-error toast. */}
{visibleTerminalError && isActive && !showSshReconnectOverlay && activePane
{/* Let SSH recovery and a stopped WSL distro's Start own the pane instead of the raw error toast. */}
{visibleTerminalError && isActive && !showSshReconnectOverlay && !wslHostStopped && activePane

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major · Functional Correctness · Heavy lift

Suppress errors only for panes covered by the stopped-host card.

If the active pane belongs to another environment, a stopped WSL workspace owner still sets wslHostStopped. This condition then hides that pane's TerminalErrorToast, including its Retry or Close action, although the stopped-host card need not apply to the pane. Match the toast guard to the same pane eligibility used for the stopped-host card.

…can't land in the no-boot window

CI saw 2 extra fake connects right after the first stop. Instrumented runs traced
every boot after a stop to the Start flow's two calls (wslHosts:connect, then the
runtimeEnvironments connect, logged as a pair) and the renderer stack of the
second pair to openNewTerminalTabInActiveWorkspace. In CI the spec clicked New
Terminal, then waited only for the first .xterm. That was the auto-created
terminal, so it wrote the stop while its own New Terminal was still in flight.
That terminal then started the distro as the user act it is. No background path
booted anything.

The spec now runs the tab bar's New Terminal action and awaits it before the
stop. The no-boot assertion is unchanged.
@greptile-apps

greptile-apps Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes affect recovery and terminal creation for desktop users of WSL hosts.

The PR still needs the previously reported fix so Start can reconnect a pane whose first connection failed.

Findings

  1. P1 Start leaves the pane disconnected ▶

Summary

Adds a Start card for terminals on stopped WSL distros and starts the distro before an explicit New Terminal request.

  • Stopped WSL terminals show a Start button and reconnect on request.
  • New Terminal starts a stopped WSL distro before opening a terminal.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Stopped WSL distro] --> B[Pane offers Start]
  B --> C[User clicks Start]
  D[User requests New Terminal] --> E[Start stopped host]
  C --> E
  E --> F[Reconnect host and reload projects]
  F --> G[Retry pane or create terminal]
Loading

Reviews (2) · Last reviewed commit: "test(wsl-host): narrow the tab group id ..." · Reviewed by Greptile

<WslHostStoppedCard
environmentId={ownerEnvironmentId}
distro={stoppedWslDistro}
onStarted={onReconnect}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Start leaves the pane disconnected

When a pane fails to attach with “Ubuntu was stopped,” connectPane calls recovery.cancel() and leaves recovery idle. After booting the distro, this callback only calls retryRecovery(), which refuses an idle transport. The card disappears, but the pane still cannot accept input.

Add a retry path for this failed-attach state. Test that the pane accepts input after Start, not just that the card disappears.

Knowledge Base Used: PTY streaming and recovery

@nwparker
nwparker merged commit f7a114a into main Oct 28, 2026
48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant