Repository navigation
Make Cloud VM SSH sessions show reconnect state - #3899
austinywang wants to merge 29 commits into
Conversation
The startup wrapper already retries transient SSH exits, but no regression coverage proves that the foreground transport reports retry and recovery transitions back to the app-owned workspace state. This test captures the sleep/network-drop path by making SSH exit 255 once, then requiring reconnecting and connected lifecycle helper calls before final session end. Constraint: Local tests are intentionally not run for this repo; CI owns execution. Rejected: Assert only terminal stderr reconnect text | acceptance requires the Cloud VM pane/app state to surface reconnecting, not just shell output. Confidence: medium Scope-risk: narrow Tested: Not run locally per instruction; expected to fail before the fix because the lifecycle helper commands do not exist yet. Not-tested: CI execution pending after fix commit.
The foreground SSH wrapper is the only process that can observe an interactive transport drop, while Workspace owns the visible remote state. The fix adds explicit terminal lifecycle helpers for reconnecting and connected transitions, routes them through TerminalController RPCs, and lets Workspace translate them into the existing remote connection state model. Constraint: Do not infer foreground SSH health from daemon/proxy failures; the terminal process owns foreground transport observations. Constraint: No local test runs for this repo; CI owns test execution. Rejected: Reuse ssh-session-end for retries | final-session cleanup would demote or clear state instead of preserving the active remote terminal during retry. Rejected: Poll the remote controller for foreground drops | proxy/daemon state is a different lifecycle and misses Cloud VM SSH-only fallback sessions. Confidence: medium Scope-risk: moderate Tested: git diff --check; python3 -m json.tool Resources/Localizable.xcstrings Not-tested: Local test suite per instruction; CI pending.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds SSH session reconnecting/connected lifecycle end-to-end: CLI emits lifecycle commands, new IPC subcommands parse and forward validated params, TerminalController exposes V2 RPCs and applies unified lifecycle payloads, Workspace updates remote connection state, tests and localized strings/docs added. ChangesRemote Terminal Reconnect Lifecycle
Sequence DiagramsequenceDiagram
participant CLI as CLI/cmux
participant TerminalController as Sources/TerminalController
participant Workspace as Sources/Workspace
CLI->>TerminalController: invoke `ssh-session-reconnecting` / `ssh-session-connected` (validated args)
TerminalController->>Workspace: v2ApplyWorkspaceRemoteTerminalLifecycle(apply reconnect/connected/session-end)
Workspace->>Workspace: validate surface/relay & update remoteConnectionState
Workspace-->>TerminalController: success payload (window/workspace/surface/relay_port/status)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (2 errors, 1 warning, 1 inconclusive)
✅ Passed checks (13 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR closes #3776 by adding transient SSH terminal lifecycle events —
Confidence Score: 5/5Safe to merge; the new lifecycle paths are well-guarded and thoroughly tested, with the only remaining open item being a localization typography issue. The core reconnect logic, sequence-guarding, and terminal settle paths are correct and covered by six new unit tests plus a shell integration test. The localization issue (missing diacritics in fr/es/nb/it/pt-BR) is user-visible but does not affect reconnect correctness. Pre-existing actor isolation gaps on two private helpers are already tracked from previous review rounds. Resources/Localizable.xcstrings — the three new strings need diacritics corrected for fr, es, nb, it, and pt-BR before shipping to users in those locales. Important Files Changed
Sequence DiagramsequenceDiagram
participant Shell as SSH Wrapper (sh)
participant CLI as cmux CLI
participant TC as TerminalController
participant WS as Workspace
Shell->>Shell: "sequence++ to 1, export CMUX_SSH_LIFECYCLE_SEQUENCE=1"
Shell->>Shell: launch ssh attempt 1
Shell->>Shell: ssh exits 255 transient drop
Shell->>Shell: "sequence++ to 2, export CMUX_SSH_LIFECYCLE_SEQUENCE=2"
Shell->>CLI: ssh-session-reconnecting --sequence 2 --attempt 1
CLI->>TC: "workspace.remote.terminal_reconnecting sequence=2"
TC->>WS: "markRemoteTerminalSessionReconnecting(sequence=2)"
WS->>WS: acceptSequence 2 gt 0 ok, state to reconnecting
Shell->>Shell: "sequence++ to 3, export CMUX_SSH_LIFECYCLE_SEQUENCE=3"
Shell->>Shell: launch ssh attempt 2
Note over Shell: SSH connects, LocalCommand fires
Shell->>CLI: ssh-session-connected --sequence 3
CLI->>TC: "workspace.remote.terminal_connected sequence=3"
TC->>WS: "markRemoteTerminalSessionConnected(sequence=3)"
WS->>WS: acceptSequence 3 gt 2 ok, state to connected
Shell->>Shell: ssh exits 0, wrapper exits
Shell->>CLI: ssh-session-end
CLI->>TC: workspace.remote.terminal_session_end
TC->>WS: markRemoteTerminalSessionEnded()
WS->>WS: untrackRemoteTerminalSurface, settle final state
Reviews (20): Last reviewed commit: "fix: localize ssh lifecycle fallback str..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/remote-daemon-spec.md`:
- Line 217: Add a blank line before the heading "### 10.4 Manual Cloud VM
Sleep/Network Smoke" in docs/remote-daemon-spec.md so the heading is preceded by
an empty line for consistent Markdown formatting; locate the heading text and
insert a single newline above it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: d824d734-a9d8-47a6-8242-d8abe3860533
📒 Files selected for processing (8)
CLI/cmux.swiftResources/Localizable.xcstringsSources/TerminalController.swiftSources/Workspace.swiftcmuxTests/SSHStartupSignalLifecycleTests.swiftcmuxTests/WorkspaceRemoteConnectionTests.swiftdocs/cli-contract.mddocs/remote-daemon-spec.md
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="Sources/Workspace.swift">
<violation number="1" location="Sources/Workspace.swift:9588">
P2: This new reconnecting guard forces a disconnect transition even when proxy/daemon readiness indicates the workspace should settle back to Connected.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Stale CodeRabbit changes-requested summary. The only actionable inline comment was fixed in df02c26, CodeRabbit acknowledged it, the thread is resolved, and the current CodeRabbit check is passing.
…-3776-cloud-vm-ssh-resilience
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Sources/Workspace.swift (1)
9727-9728:⚠️ Potential issue | 🟠 Major | ⚡ Quick winClear pending child-exit surface IDs once the panel is truly gone.
remoteTerminalLifecycleMatchesnow treatspendingRemoteTerminalChildExitSurfaceIdsas live, but in this file those IDs are only inserted here and removed again ontrackRemoteTerminalSurface(_). After a terminal has actually closed, delayed lifecycle callbacks for that dead surface will still match and can mutate the workspace state long after the pane is gone. Clear the pending entry during panel/disconnect cleanup, or stop matching against the pending set here.Also applies to: 9780-9788
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Sources/Workspace.swift` around lines 9727 - 9728, The pendingRemoteTerminalChildExitSurfaceIds set is left containing surfaceId entries that are treated as live by remoteTerminalLifecycleMatches, allowing delayed lifecycle callbacks to mutate state after a terminal pane is gone; when you call untrackRemoteTerminalSurface(surfaceId) (or during the panel/disconnect cleanup path) also remove that surfaceId from pendingRemoteTerminalChildExitSurfaceIds so it no longer matches, or alternatively stop consulting pendingRemoteTerminalChildExitSurfaceIds inside remoteTerminalLifecycleMatches — update the cleanup code that runs when a panel disconnects/actually closes (the same area that calls untrackRemoteTerminalSurface and the panel/disconnect cleanup around the 9780–9788 changes) to clear pendingRemoteTerminalChildExitSurfaceIds.remove(surfaceId).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/remote-daemon-spec.md`:
- Line 224: Update the reconnect smoke test expectation so it no longer requires
the raw SSH exit status to be visible: change the step that currently reads
"Verify the terminal pane and remote status payload enter `reconnecting`, with
detail that includes the SSH retry attempt and exit status" to assert only that
the terminal pane and remote status payload enter `reconnecting` and that the
detail includes SSH retry attempt/context (e.g., attempt number and retry
reason) but does not assert or display raw SSH exit codes; update any references
to "exit status" in the same step to instead refer to "retry context" or "retry
reason" to match the reconnect copy behavior.
In `@Resources/Localizable.xcstrings`:
- Around line 111979-112029: The three new localization keys
remote.state.reconnecting.terminal, remote.state.disconnected.terminalEnded, and
remote.state.targetFallback only include en and ja; add entries for all
supported locales (ar, bs, da, de, en, es, fr, it, ja, ko, nb, pl, pt-BR, ru,
th, tr, uk, zh-Hans, zh-Hant) under each key’s localizations block; for
lower-confidence locales (ar, bs, da, pl, th, tr) use English fallback values
but set stringUnit.state to "translated", and for the remaining locales provide
proper translations or English fallbacks as required so every locale present in
the catalog is included for each of the three keys.
In `@Sources/Workspace.swift`:
- Around line 9732-9750: The reconnect handler
markRemoteTerminalSessionReconnecting currently only validates
surfaceId/relayPort via remoteTerminalLifecycleMatches and can apply stale
updates; update it to reject stale events by comparing a stored lifecycle
generation or last-applied sequence/timestamp before applying .reconnecting.
Concretely: extend remoteTerminalLifecycleMatches (or add a new check) to accept
the incoming event's generation/sequence/timestamp (which the retry logic should
supply) and compare it against the lifecycle's current
generation/lastAppliedPhase stored on the Workspace; only call
applyRemoteConnectionStateUpdate(.reconnecting, ...) when the incoming
generation is strictly newer than the stored one (mirror the same freshness
check used by markRemoteTerminalSessionConnected), so out-of-order/delayed
reconnect callbacks cannot regress the state.
---
Outside diff comments:
In `@Sources/Workspace.swift`:
- Around line 9727-9728: The pendingRemoteTerminalChildExitSurfaceIds set is
left containing surfaceId entries that are treated as live by
remoteTerminalLifecycleMatches, allowing delayed lifecycle callbacks to mutate
state after a terminal pane is gone; when you call
untrackRemoteTerminalSurface(surfaceId) (or during the panel/disconnect cleanup
path) also remove that surfaceId from pendingRemoteTerminalChildExitSurfaceIds
so it no longer matches, or alternatively stop consulting
pendingRemoteTerminalChildExitSurfaceIds inside remoteTerminalLifecycleMatches —
update the cleanup code that runs when a panel disconnects/actually closes (the
same area that calls untrackRemoteTerminalSurface and the panel/disconnect
cleanup around the 9780–9788 changes) to clear
pendingRemoteTerminalChildExitSurfaceIds.remove(surfaceId).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: cba5c117-8b69-4faa-9a2c-8b965091fd34
📒 Files selected for processing (8)
CLI/cmux.swiftResources/Localizable.xcstringsSources/TerminalController.swiftSources/Workspace.swiftcmuxTests/SSHStartupSignalLifecycleTests.swiftcmuxTests/WorkspaceRemoteConnectionTests.swiftdocs/cli-contract.mddocs/remote-daemon-spec.md
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a3026dd. Configure here.
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Stale CodeRabbit changes-requested review for 4f9bad6. All inline findings have been addressed/resolved, and the latest CodeRabbit status check is passing on the current head.
There was a problem hiding this comment.
7 issues found across 8 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="Resources/Localizable.xcstrings">
<violation number="1" location="Resources/Localizable.xcstrings:112021">
P2: French (fr) translation uses 'a' (has) instead of 'à' (to/at). 'Reconnexion a' would be read as 'Reconnection has' rather than 'Reconnection to'. The grave accent on 'à' is required for correctness.</violation>
<violation number="2" location="Resources/Localizable.xcstrings:112045">
P2: Norwegian Bokmål (nb) translation uses 'pa' and 'forsok' instead of the correct 'på' and 'forsøk'. The Norwegian letters 'å' and 'ø' must be used for the text to be correct and readable.</violation>
<violation number="3" location="Resources/Localizable.xcstrings:112134">
P2: Spanish (es) translation is missing required accents: 'sesion' should be 'sesión' and 'termino' should be 'terminó'. The missing accents change the meaning - 'termino' reads as 'term' (noun) instead of 'ended' (verb).</violation>
<violation number="4" location="Resources/Localizable.xcstrings:112140">
P2: French (fr) translation uses 'terminee' instead of 'terminée'. Required accents on the final 'e' are missing.</violation>
<violation number="5" location="Resources/Localizable.xcstrings:112164">
P2: Norwegian Bokmål (nb) translation uses 'okten' without the required 'ø'. Should be 'økten' (the session).</violation>
<violation number="6" location="Resources/Localizable.xcstrings:112176">
P2: Portuguese (pt-BR) translation uses 'sessao' instead of 'sessão'. The required tilde on 'a' is missing.</violation>
<violation number="7" location="Resources/Localizable.xcstrings:112259">
P2: French (fr) translation uses 'hote' instead of 'hôte'. The required circumflex on 'ô' is missing.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| "pt-BR": { | ||
| "stringUnit": { | ||
| "state": "translated", | ||
| "value": "A sessao SSH com %@ terminou." |
There was a problem hiding this comment.
P2: Portuguese (pt-BR) translation uses 'sessao' instead of 'sessão'. The required tilde on 'a' is missing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/Localizable.xcstrings, line 112176:
<comment>Portuguese (pt-BR) translation uses 'sessao' instead of 'sessão'. The required tilde on 'a' is missing.</comment>
<file context>
@@ -111979,51 +111979,357 @@
+ "pt-BR": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "A sessao SSH com %@ terminou."
+ }
+ },
</file context>
| "value": "A sessao SSH com %@ terminou." | |
| "value": "A sessão SSH com %@ terminou." |
| "fr": { | ||
| "stringUnit": { | ||
| "state": "translated", | ||
| "value": "hote distant" |
There was a problem hiding this comment.
P2: French (fr) translation uses 'hote' instead of 'hôte'. The required circumflex on 'ô' is missing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/Localizable.xcstrings, line 112259:
<comment>French (fr) translation uses 'hote' instead of 'hôte'. The required circumflex on 'ô' is missing.</comment>
<file context>
@@ -111979,51 +111979,357 @@
+ "fr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "hote distant"
+ }
+ },
</file context>
| "value": "hote distant" | |
| "value": "hôte distant" |
| "fr": { | ||
| "stringUnit": { | ||
| "state": "translated", | ||
| "value": "La session SSH vers %@ est terminee." |
There was a problem hiding this comment.
P2: French (fr) translation uses 'terminee' instead of 'terminée'. Required accents on the final 'e' are missing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/Localizable.xcstrings, line 112140:
<comment>French (fr) translation uses 'terminee' instead of 'terminée'. Required accents on the final 'e' are missing.</comment>
<file context>
@@ -111979,51 +111979,357 @@
+ "fr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "La session SSH vers %@ est terminee."
+ }
+ },
</file context>
| "value": "La session SSH vers %@ est terminee." | |
| "value": "La session SSH vers %@ est terminée." |
| "nb": { | ||
| "stringUnit": { | ||
| "state": "translated", | ||
| "value": "SSH-okten til %@ er avsluttet." |
There was a problem hiding this comment.
P2: Norwegian Bokmål (nb) translation uses 'okten' without the required 'ø'. Should be 'økten' (the session).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/Localizable.xcstrings, line 112164:
<comment>Norwegian Bokmål (nb) translation uses 'okten' without the required 'ø'. Should be 'økten' (the session).</comment>
<file context>
@@ -111979,51 +111979,357 @@
+ "nb": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "SSH-okten til %@ er avsluttet."
+ }
+ },
</file context>
| "value": "SSH-okten til %@ er avsluttet." | |
| "value": "SSH-økten til %@ er avsluttet." |
| "nb": { | ||
| "stringUnit": { | ||
| "state": "translated", | ||
| "value": "Kobler til %@ pa nytt (forsok %lld/%lld)" |
There was a problem hiding this comment.
P2: Norwegian Bokmål (nb) translation uses 'pa' and 'forsok' instead of the correct 'på' and 'forsøk'. The Norwegian letters 'å' and 'ø' must be used for the text to be correct and readable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/Localizable.xcstrings, line 112045:
<comment>Norwegian Bokmål (nb) translation uses 'pa' and 'forsok' instead of the correct 'på' and 'forsøk'. The Norwegian letters 'å' and 'ø' must be used for the text to be correct and readable.</comment>
<file context>
@@ -111979,51 +111979,357 @@
+ "nb": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Kobler til %@ pa nytt (forsok %lld/%lld)"
+ }
+ },
</file context>
| "value": "Kobler til %@ pa nytt (forsok %lld/%lld)" | |
| "value": "Kobler til %@ på nytt (forsøk %lld/%lld)" |
| "es": { | ||
| "stringUnit": { | ||
| "state": "translated", | ||
| "value": "La sesion SSH con %@ termino." |
There was a problem hiding this comment.
P2: Spanish (es) translation is missing required accents: 'sesion' should be 'sesión' and 'termino' should be 'terminó'. The missing accents change the meaning - 'termino' reads as 'term' (noun) instead of 'ended' (verb).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/Localizable.xcstrings, line 112134:
<comment>Spanish (es) translation is missing required accents: 'sesion' should be 'sesión' and 'termino' should be 'terminó'. The missing accents change the meaning - 'termino' reads as 'term' (noun) instead of 'ended' (verb).</comment>
<file context>
@@ -111979,51 +111979,357 @@
+ "es": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "La sesion SSH con %@ termino."
+ }
+ },
</file context>
| "value": "La sesion SSH con %@ termino." | |
| "value": "La sesión SSH con %@ terminó." |
| "fr": { | ||
| "stringUnit": { | ||
| "state": "translated", | ||
| "value": "Reconnexion a %@ (tentative %lld/%lld)" |
There was a problem hiding this comment.
P2: French (fr) translation uses 'a' (has) instead of 'à' (to/at). 'Reconnexion a' would be read as 'Reconnection has' rather than 'Reconnection to'. The grave accent on 'à' is required for correctness.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/Localizable.xcstrings, line 112021:
<comment>French (fr) translation uses 'a' (has) instead of 'à' (to/at). 'Reconnexion a' would be read as 'Reconnection has' rather than 'Reconnection to'. The grave accent on 'à' is required for correctness.</comment>
<file context>
@@ -111979,51 +111979,357 @@
+ "fr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Reconnexion a %@ (tentative %lld/%lld)"
+ }
+ },
</file context>
| "value": "Reconnexion a %@ (tentative %lld/%lld)" | |
| "value": "Reconnexion à %@ (tentative %lld/%lld)" |
Resolve the obsolete SSH-wrapper status patch against the current native Cloud session owner. CloudTuiManualMirrorSession already publishes reconnecting attempt/reason, attached and ended states and fences stale attachments; its presentation policy intentionally keeps transient recovery silent and offers Reconnect after persistent failure. Current SSH terminal lifecycle and attempt IDs also replace the old per-surface sequence helpers. Preserve main's behavior and existing recovery tests rather than reinstall duplicate status RPCs.
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
All contributors have signed the CLA ✍️ ✅ |
|
cmux-reconcile: close-candidate Proposed action: Close this empty PR without merging; preserve the branch. Evidence checked September 18, 2026: GitHub reports 0 changed files, 0 additions, and 0 deletions. I independently fetched the PR diff and it is empty. Head: There is no remaining patch in this PR against its target branch. This does not establish that the original feature shipped to Recheck the head/diff before acting in case new work arrives. Search |
|
Fleet instruction update for head |
|
Closing as already on main: merging this branch into main at 8421357 produces main's own tree, so there's nothing left to land. The branch is kept; reopen if something here is still missing. Part of the backlog cleanup in manaflow-ai/cmuxterm-hq#563. |

Summary
Verification
Not run
Note
Medium Risk
Touches SSH startup wrapper scripting and remote-workspace state transitions; mistakes could cause incorrect connection state in the UI or missed/dropped lifecycle events during reconnects.
Overview
Cloud VM SSH panes now emit explicit lifecycle events during transient SSH drops: the startup wrapper reports
reconnecting(with attempt/limit) on exit-255 retries andconnectedafter a successful redial, while keeping the finalssh-session-endcleanup separate.This adds internal CLI commands
ssh-session-reconnecting/ssh-session-connected, new RPC handlers (workspace.remote.terminal_reconnecting/terminal_connected), and Workspace logic to apply these updates per-surface using a monotonicsequenceto ignore stale/out-of-order signals and to settle the workspace state correctly after the last terminal ends (including browser-panel and VM no-proxy cases). Localization strings, CLI contract docs, and targeted regression tests were added/updated accordingly.Reviewed by Cursor Bugbot for commit e4a4009. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Cloud VM SSH sessions now correctly reflect reconnect state through the native
CloudTuiManualMirrorSessionlifecycle (reconnecting/attached/ended) instead of the earlier custom status RPCs; transient drops stay silent and persistent failures surface a Reconnect action.ssh-session-reconnecting,ssh-session-connected,workspace.remote.terminal_reconnecting, andworkspace.remote.terminal_connected.Written for commit 983f338. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests