Repository navigation
fix(remote): restore offline workspaces and reconnect in place - #890
Merged
xintaofei merged 5 commits intoOct 9, 2026
Merged
Conversation
This was referenced Oct 8, 2026
There was a problem hiding this comment.
🔵 Needs a closer look
It changes cross-runtime restoration and connection lifecycle behavior while validation still reports an unresolved draft-loss case and an unexplained Rust test failure.
0 open findings
What changed in this PR
Restores remote desktop workspaces during outages and adds in-place connection recovery while preserving workspace state and drafts.
Changes:
- Restores saved remote windows without health preflight.
- Tracks connection state and supports manual reconnection.
- Prevents failed folder reads from pruning offline drafts.
| File | Description |
|---|---|
src/stores/app-workspace-store.ts |
Marks folders hydrated only after successful reads. |
src/stores/app-workspace-store.test.ts |
Tests folder hydration failure and recovery. |
src/stores/app-workspace-store-offline.test.tsx |
Tests offline draft preservation. |
src/lib/transport/types.ts |
Clarifies reconnect and authorization contracts. |
src/lib/transport/remote-desktop-transport.ts |
Adds connection state, recovery, and in-place retry. |
src/lib/transport/remote-desktop-transport.test.ts |
Covers transport lifecycle and recovery behavior. |
src/contexts/remote-connection-gate.test.tsx |
Tests mounted-workspace recovery behavior. |
src/contexts/remote-connection-context.tsx |
Integrates remote connection status handling. |
src/components/connection/remote-connection-status.tsx |
Adds reconnect status and action UI. |
src/components/connection/remote-connection-status.test.tsx |
Tests status transitions and cleanup. |
src-tauri/src/commands/workspace_windows.rs |
Restores offline windows and preserves explicit closes. |
src-tauri/src/commands/remote_workspace.rs |
Documents probe-free saved-window restoration. |
src-tauri/src/commands/remote_proxy.rs |
Removes stopped proxy tasks before retry notification. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
The event socket proxy cannot tell a handshake the server refused with HTTP 401 from a server that is down: every failure was a string, and after three of them the task sent `__unauthorized__`. The frontend in this branch reads that signal as "retries stopped", so a revoked or rotated token was shown as "Connection lost / Reconnect now", and each retry failed three more times without ever reaching the expired screen, unless some HTTP call happened to run. PRs spacering-net#840 and spacering-net#887 also give `__unauthorized__` exactly the meaning "refused token", which this frontend would have shown as retryable. Classify the handshake instead. A 401 ends the task at once with `__unauthorized__`, which reaches `onUnauthorized()` and the expired screen, the same as a 401 on an HTTP call. The three-failure cutoff now sends its own `__retries_exhausted__`, which keeps the workspace mounted and offers the in-place retry. `onUnauthorized` goes back to meaning only a refused token, so the gate no longer filters by source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Reconnect now" moves the transport to "reconnecting" synchronously, and the status pill hides every "reconnecting" period for its 4 s grace. So the click made the pill vanish, and against a server that still refuses, the proxy gives up after about 3 s (fail, 1 s, fail, 2 s, fail): the pill came back with the same button and no progress was ever shown. A retry the user asked for now skips the grace, for as long as that retry runs. The flag is armed only when the transport actually started a retry, and cleared as soon as the retry ends, so a later outage still gets its grace window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nothing Four retry tests passed with `reconnectNow()` replaced by a no-op: the synthetic `__ready__` they inject resolves the waiters and reattaches the stream whether or not the retry resubscribed, and in the destroy case `destroy()` itself consumed the pending unsubscribe the test meant for the retry. Assert that the retry reached its commands: the failing one before it gave up, a fresh subscribe before the ready, and the unsubscribe the retry, not `destroy()`, is waiting on. All six retry tests now fail when `reconnectNow()` is a no-op. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
|
codeg work task |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Saved remote windows depended on server health during startup, so an outage could remove them from the next saved session. This restores their local shells while offline and allows connection recovery without remounting the workspace.
Validation
action_requiredwith zero jobs executed; CI validation is pending.Known issues
Related work
Complements #840, which proposes automatic heartbeat, wake probes, continued retries and sleep/wake transcript recovery.
Related to #887, a broader draft combining workspace activation, restoration, heartbeats and continued retries. This change includes a manual retry fallback after the existing retry cutoff.
The separate Dock activation PR adds adjacent session methods and tests in
workspace_windows.rs. Rebasing after either change merges needs a text-conflict resolution that retains both sets. The combined resolution was checked against the native-validated source tree.The local-workspace entry is proposed separately in #891.