Repository navigation
feat(wsl): convert UNC Windows-drive projects to drive paths across a restart (D1c-4c) - #33135
Conversation
f450baa to
ae0edfe
Compare
d4156d0 to
56c1025
Compare
ae0edfe to
2195374
Compare
56c1025 to
cf3d9bc
Compare
2195374 to
b34a214
Compare
cf3d9bc to
f0a703e
Compare
b34a214 to
58e5339
Compare
f0a703e to
d34f97f
Compare
58e5339 to
54befbd
Compare
d34f97f to
5783d45
Compare
54befbd to
a53538e
Compare
5783d45 to
0a32b80
Compare
a53538e to
9f1192c
Compare
0a32b80 to
f87d599
Compare
9f1192c to
c728220
Compare
f87d599 to
9eae9cd
Compare
c728220 to
c3e6842
Compare
9eae9cd to
9f518c3
Compare
c3e6842 to
914b6c2
Compare
9f518c3 to
b96ac8b
Compare
914b6c2 to
05fef6a
Compare
b96ac8b to
33734d6
Compare
05fef6a to
2112bdc
Compare
33734d6 to
a482987
Compare
2112bdc to
38da560
Compare
a482987 to
dcc2604
Compare
| } catch (error) { | ||
| removeWslDriveUncConversion(deps.userDataPath, migrationId) | ||
| return { migrationId, outcome: 'rolled-back', detail: describe(error) } |
There was a problem hiding this comment.
Uncertain commits lose their journal
rewriteProfile throwing does not prove the profile rolled back. The profile writer can throw ProfileStateIndeterminateWriteError when COMMIT ends without a confirmed rollback. This catch still deletes the conversion journal.
If the commit took effect, the profile uses drive paths, but terminal history, chats, and the other stores keep their old IDs with no journal left to retry them. Keep the journal when the write result is uncertain and check the saved profile before deciding to roll back.
Knowledge Base Used: Desktop persistence and lifecycle
| if (existsSync(from) && !existsSync(to)) { | ||
| renameSync(from, to) | ||
| renamed = true | ||
| } | ||
| // The history sweep keeps a folder whose meta names a live worktree. | ||
| rewriteShellHistoryMeta(to, oldId, newId) |
There was a problem hiding this comment.
Retries abandon old shell history
If shell-history fails after the profile commits, startup continues and the project can open new terminals. A new terminal creates the history folder for the new worktree ID. On the next start, this check skips the old folder because the destination exists, then marks the store complete without copying its history.
The old folder still names the old worktree and can be deleted by history cleanup. Keep affected terminals blocked until their history moves, or merge both folders safely before recording completion. The same skip-existing check also appears in renameTerminalSessions.
Knowledge Base Used: Desktop persistence and lifecycle
2f0aeb3 to
c3f6175
Compare
b9ca555 to
74d1a1b
Compare
…al: it waits for the window, and finishes on any platform once the gate is open
c3f6175 to
7ab29a6
Compare
74d1a1b to
8e4c006
Compare
…al: it waits for the window, and finishes on any platform once the gate is open
|
Warning Review limit reachedYou'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 15 minutes. View limit details
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 |
8e4c006 to
7fb0b5b
Compare
…al: it waits for the window, and finishes on any platform once the gate is open
… restart (D1c-4c)
…nce WSL denies UNC drive folders WSL 2.7.11 answers EPERM for \\wsl.localhost\<distro>\mnt\c\... from Windows. Pin that the preflight's Git runs and worktree-link reads use C:\... by making every UNC access throw EPERM.
A refusal over saved state now says whether a project also holds an unconverted repo, or a drive key already holds different data (and which key), instead of a bare collision code. The fields are optional, so the window's copy still reads an older host's refusal. The seeded shape (a saved UNC worktree with tabs beside the bare drive row startup discovery wrote) now converts.
…on, as #34059's mover now requires Co-Authored-By: Claude <noreply@anthropic.com> (cherry picked from commit bfeb4fe3ae7f278ac452e376d426315dbf7b985c)
…and check its profile; refuse paths off a Windows drive mount - The journal's post-commit phase write sat inside the rollback catch, so a failure there dropped the journal and reported rolled-back for a profile already rewritten. The write now follows the commit outside the catch: a failure leaves the journal 'prepared', whose rewrite is idempotent, and reports resuming. - The journal records the profile it rewrites, and startup runs only the active profile's. - The run reads the distro's Windows-drive mounts and passes them to the scope. Co-Authored-By: Claude <noreply@anthropic.com>
…t is written atomically, and only a prepared conversion blocks a new one
7fb0b5b to
c675fa9
Compare
| return wslMoveFenceFromCutovers(scanWslMoveCutovers(userDataPath)) | ||
| return withWslDriveUncConversions( | ||
| wslMoveFenceFromCutovers(scanWslMoveCutovers(userDataPath)), | ||
| listWslDriveUncConversions(userDataPath) |
There was a problem hiding this comment.
Other profiles lose terminal access
resolveWslMoveFence loads every profile's conversion journal, but startup only finishes the active profile's conversions. If an interrupted conversion leaves profile A's journal prepared, switching to profile B still blocks A's project IDs and folders. A project shared by both profiles can no longer open terminals in B, even though B has no pending conversion.
Filter conversion journals by the active profile when building the fence, matching startup.
…al: it waits for the window, and finishes on any platform once the gate is open
…al: it waits for the window, and finishes on any platform once the gate is open
…onvert the window's stores (D1c-4d) (#33143) * feat(wsl): offer the drive-path conversion in project settings, and convert the window's stores (D1c-4d) * fix(wsl): tell the user why saved state blocked the drive-path conversion A refusal over saved state now names the cause: a folder with different details under both its WSL path and its drive path, or a project that also holds a repository that isn't converting. An older host's refusal without a cause keeps the general message. * fix(wsl): explain a conversion refused because the distro's /mnt/<letter> is not that Windows drive Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl): give the renderer-rewrite journal fixture the profile the journal now records * test(wsl): give the e2e conversion journal the profile field the journal now requires * test(wsl): carry the #33135 startup tests onto the window-store journal: it waits for the window, and finishes on any platform once the gate is open * test(wsl): off Windows the conversion IPC still reports startup's outcomes, as the journal can finish on any platform --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
ELI5
This PR does the conversion that #33128 only computed. When someone converts a project that Orca has open through WSL's view of a Windows drive (
\\wsl.localhost\Ubuntu\mnt\c\src\app), Orca:On the way back up, before the window opens, Orca renames everything to
C:\src\app: tabs, layouts, worktree settings, sleeping agents, chats, orchestration history, and each slept terminal's saved history. Panes then wake into their old scrollback and folder, and Git runs on Windows. A crash at any point either finishes the conversion at the next start or leaves everything as it was.What Changed
wslDriveUnc:convertconverts them. The settings button and the renderer-side stores come in the next PR.src/main/wsl/wsl-drive-unc-conversion-run.ts):It refuses when:
The last two reuse feat(wsl): run Git for Windows for a WSL project on a Windows drive (D1c-2) #33090's checks, run on the drive path.
It then runs the WSL mover's pause,
pauseWslMoveScope. That runs the terminal gate, then Sleep, keeping each shell's folder.It writes a
preparedjournal entry with the old→new worktree ids, then restarts with quit (not exit), so the window and the store save the slept panes first.wsl-drive-unc-conversion-journal.ts): built on the mover'screateMigrationJournalDirectory(durable, owner-only, fails closed), in its ownwsl-drive-unc-conversions/directory.prepared, the mover's fence keeps the projects read-only, with no new terminals (withWslDriveUncConversionsinwsl-move-fence.ts). A terminal started in that gap would keep the old id.wsl-drive-unc-conversion-startup.ts): runs inmain-process-ready-foundation.tsbefore the profile store opens.writeProfileProjectDomainChanges), and only the fields the rewrite changed are written.rolled-back).resuming).wsl-drive-unc-conversion-stores.ts):terminal-history/<session id>is renamed to the new id. A slept pane reattaches by its id, so it wakes with its scrollback and folder. The folder holds no id of its own.terminal-history*/<hash(worktree id)>move to the new hash, and theirmeta.jsonis updated.rewriteWslMoveOrchestrationHistory, now exported as a file-level function.journal_sessions.workspace_idand each record'slocation.workspaceId, in one transaction. A record this build can't read stays byte-identical.Why
Owner decision: these projects become Windows projects with WSL terminals.
Why a restart instead of rewriting live. This touches every saved id at once. Doing it before anything opens means:
Profile transfer already restarts the same way.
No undo, on purpose. Once the profile write commits, the conversion is one-way, like the decision not to build a reverse mover. Going back would mean re-keying every id to a UNC path that WSL 2.7.11 no longer lets Windows open. A failure before the commit leaves everything as it was.
Why not reuse the mover's commit and desktop-rewrite pipeline. It is built around a destination host: a manifest, staging, a host commit, and a re-seeded host partition. Here nothing leaves this computer. So this reuses the mover's pieces (pause, fence, journal directory, orchestration rewrite) and the profile-transfer write, rather than a second copy of the pipeline.
Linked Issue
Part of the WSL re-write, step D1c-4 (risk rows R36, R6). Stacked on #33128.
Visual Proof
N/A: the IPC has no UI yet (next PR).
Testing
wsl-drive-unc-conversion-startup.test.ts, against a real profile SQLite database, terminal history folders and a chat journal database. It covers:wsl-drive-unc-conversion-run.test.tscovers:\\wsl.localhost\<distro>\mnt\c\…to Windows): the checks only touch theC:\side;pnpm tc:node, plus the mover, IPC, profile and startup suites (7.5k tests), pass locally.Review
Self-reviewed.
Agent skill upstream boundary
Notes
wsl-drive-unc-conversion-startup.ts), and the new IPC refuses while the gate is closed. The one ungated addition is the mover fence'sexistsSyncon the conversion-journal folder, which only the gated convert handler can create, so it returns nothing. Everything else is a refactor or a type. Themeta.jsonhandling and the narrower pending check run only inside the gated conversion. Edge case, internal testers only: a journal leftpreparedby a run with the gate open keeps fencing its projects after the gate closes, because the startup step that finishes it is skipped. That fails safe.C:\project on WSL. It ignores the journal directory.Status
74d1a1b05bc: rebased onto main64344142fa0, which has feat(wsl): run Git for Windows for a WSL project on a Windows drive (D1c-2) #33090 squash-merged (fix(wsl-host): tell users how to fix a distro Orca can't host (D1c-1) #33085 earlier) and fix(wsl-mover): hold an app update install while a moved project comes back #35357; feat(wsl): offer Git for Windows in a Windows-drive WSL project's settings (D1c-3) #33097 now targets main. Every commit is kept. CI: running on this head.meta.jsonthat a crash left torn is skipped instead of throwing, so a conversion can no longer stall before re-keying chats. The file is now written atomically (temp file, fsync, rename viawriteFileDurableSync). A new conversion is refused only while this profile has apreparedjournal. Tests cover a tornmeta.json, the startup step leaving a journal untouched with the gate closed or off Windows, aprofile-rewrittenjournal not blocking a new conversion, and the IPC handlers (refused with the gate closed or off Windows, parsed for the active profile, invalid arguments rejected). The optional Low item (a failed history rename on the failure path) is not done.preparedand reportsresuming, never a falserolled-back(test throws on that write). The journal recordsprofileId, and startup runs only the active profile's conversions. The run reads the distro's drive mounts for the scope check.pnpm tc,pnpm run typecheck:ci, the PR's tests,check:code-quality:changed, the anti-slop oxlint, repo oxlint and ast-grep (including the no-real-time-sleep test rules) and the e2e typecheck ratchet all pass locally on this head, run one branch at a time.