fix(worktree): recognise the Windows profile through WSL's drvfs view

`/mnt/<letter>` under a WSL UNC alias is the distro's drvfs mount of a Windows
volume, so `\\wsl.localhost\Ubuntu\mnt\c\Users\bob` is `C:\Users\bob` wearing a
Linux spelling. The Windows-profile rule excludes every WSL UNC path by design
(the aliases normally front a Linux filesystem) and the POSIX shapes never match
a `/mnt/...` tail, so that path fell through both and read back as deletable.

The spelling is producible by the product: `resolveWslRepoWorktreeBasePath` maps a
`/mnt/c/...` worktree base against a WSL repo into exactly this UNC form, and
`getWslFilesystemBoundaryDistro` already treats it as the drvfs crossing.

A drvfs tail now takes the Windows rule on its drive form, via the existing
`toWindowsWslDrivePath`. Scoped to the UNC branch, where `parseWslUncPath` has
proven the path is a WSL alias — a plain Linux host's `/mnt/c/...` is untouched.
The lowercase-only `/mnt` match is deliberate: `/MNT` is an ordinary
case-sensitive Linux directory, never the automount.
This commit is contained in:
Neil
2026-09-18 23:39:57 -07:00
parent 7063c2cbdd
commit 2ca2b008fc
2 changed files with 29 additions and 2 deletions
@@ -87,6 +87,20 @@ describe('path-shape home detection', () => {
])('WSL UNC %s -> %s', (worktreePath, expected) => {
expect(isHome(worktreePath, CLIENT_REMOVAL_HOME)).toBe(expected)
})
it.each([
// `/mnt/<letter>` is the distro's drvfs view of a Windows volume, so this is
// `C:\Users\bob` wearing a Linux spelling, not a directory in the distro.
['\\\\wsl.localhost\\Ubuntu\\mnt\\c\\Users\\bob', true],
['\\\\wsl$\\Ubuntu\\mnt\\c\\Users', true],
['\\\\wsl.localhost\\Ubuntu\\mnt\\c\\Users\\bob\\ws\\wt', false],
// `/MNT` is an ordinary case-sensitive Linux directory, never the automount.
['\\\\wsl.localhost\\Ubuntu\\MNT\\c\\Users\\bob', false]
])('WSL drvfs %s -> %s', (worktreePath, expected) => {
expect(withProcessPlatform('darwin', () => isHome(worktreePath, CLIENT_REMOVAL_HOME))).toBe(
expected
)
})
})
describe('whose home the guard consults', () => {
+15 -2
View File
@@ -17,7 +17,7 @@
import { homedir } from 'node:os'
import { posix, win32 } from 'node:path'
import { isWindowsAbsolutePathLike } from '../shared/cross-platform-path'
import { parseWslUncPath } from '../shared/wsl-paths'
import { parseWslUncPath, toWindowsWslDrivePath } from '../shared/wsl-paths'
export type PathOps = typeof posix
@@ -172,13 +172,26 @@ function isLikelyWindowsUserProfileDirectory(
/**
* WSL UNC aliases front a Linux filesystem, so POSIX home shapes — not
* `<root>\Users` — are what protect `\\wsl.localhost\Ubuntu\home\alice`.
*
* Except under `/mnt/<letter>`: that tail is the distro's drvfs view of a Windows
* volume, so `\\wsl.localhost\Ubuntu\mnt\c\Users\bob` is the Windows profile with
* a Linux spelling. It takes the Windows rule on its drive form, which the UNC
* exclusion above would otherwise skip.
*/
function isLikelyWslDistroHomeDirectory(resolvedWorktreePath: string, pathOps: PathOps): boolean {
if (pathOps !== win32) {
return false
}
const wsl = parseWslUncPath(resolvedWorktreePath)
return !!wsl && (wsl.linuxPath === '/' || isPosixHomeRoot(trimTrailingSlash(wsl.linuxPath)))
if (!wsl) {
return false
}
const linuxPath = trimTrailingSlash(wsl.linuxPath)
const drivePath = toWindowsWslDrivePath(linuxPath)
if (drivePath) {
return isLikelyWindowsUserProfileDirectory(win32.resolve(drivePath), win32)
}
return wsl.linuxPath === '/' || isPosixHomeRoot(linuxPath)
}
function isWslUncRemovalPath(resolvedWorktreePath: string): boolean {