export type WslUncPathInfo = { distro: string linuxPath: string } export function parseWslUncPath(path: string): WslUncPathInfo | null { const normalized = path.replace(/\\/g, '/') const match = normalized.match(/^\/\/(wsl\.localhost|wsl\$)\/([^/]+)(\/.*)?$/i) if (!match) { return null } return { distro: match[2], linuxPath: match[3] || '/' } } export function isWslUncPath(path: string): boolean { return parseWslUncPath(path) !== null } /** Convert an absolute Linux path in a known WSL distro to its Windows form. */ export function toWindowsWslPath(linuxPath: string, distro: string): string { const mntMatch = linuxPath.match(/^\/mnt\/([a-z])(\/.*)?$/) if (mntMatch) { const rest = (mntMatch[2] || '').replace(/\//g, '\\') return `${mntMatch[1].toUpperCase()}:${rest || '\\'}` } return `\\\\wsl.localhost\\${distro}${linuxPath.replace(/\//g, '\\')}` } // Why: Windows folds the share (\\wsl$ aliases \\wsl.localhost), the distro, and // drvfs /mnt/ tails case-insensitively; the rest of the Linux path is not. export function foldWslUncPathCaseInsensitiveParts(path: string): string | null { const parsed = parseWslUncPath(path) if (!parsed) { return null } // Why: the drvfs automount is literally lowercase /mnt — a case-variant like // /MNT is an ordinary case-sensitive Linux dir and must not be folded. const linuxPath = /^\/mnt\/[a-zA-Z](?:\/|$)/.test(parsed.linuxPath) ? parsed.linuxPath.toLowerCase() : parsed.linuxPath return `//wsl.localhost/${parsed.distro.toLowerCase()}${linuxPath === '/' ? '' : linuxPath}` }