dsh-plugin-wsl-env 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +274 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/cordis.patch.yml +306 -0
- package/examples/profile.cordis.patch.yml +36 -0
- package/lib/auto-preset.js +198 -0
- package/lib/fs.js +5 -0
- package/lib/index.js +871 -0
- package/lib/listing.js +112 -0
- package/lib/paths.js +265 -0
- package/lib/picker.js +350 -0
- package/lib/sandbox.js +162 -0
- package/lib/shell-env.js +74 -0
- package/lib/shell.js +5 -0
- package/lib/subprocess.js +230 -0
- package/lib/wsl.js +320 -0
- package/package.json +103 -0
package/lib/listing.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure listing helpers for the WSL directory picker, kept dependency-free so
|
|
3
|
+
* they can be unit-tested without installing the DSH peers the service itself
|
|
4
|
+
* imports. Ported from `@deepseek-ai/dsh-host-directory-picker-browse` so the
|
|
5
|
+
* picker behaves exactly like the shipped browse backend on ordinary paths.
|
|
6
|
+
*
|
|
7
|
+
* @module dsh-plugin-wsl/listing
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { win32 } from "node:path";
|
|
11
|
+
import { isWslUnc, uncToPosix } from "./paths.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Whether a path names one fixed filesystem location regardless of process
|
|
15
|
+
* state. On Windows only drive-qualified (`C:\…`) or complete UNC
|
|
16
|
+
* (`\\server\share…`) forms qualify — which is what lets a distro root like
|
|
17
|
+
* `\\wsl.localhost\ubuntu` be adopted as a workspace, while the bare share root
|
|
18
|
+
* `\\wsl.localhost` is correctly rejected as a directory.
|
|
19
|
+
*
|
|
20
|
+
* @param path - candidate path.
|
|
21
|
+
* @returns whether the path is fully qualified.
|
|
22
|
+
*/
|
|
23
|
+
export function fullyQualified(path) {
|
|
24
|
+
return win32.isAbsolute(path) && /^(?:[A-Za-z]:[\\/]|[\\/]{2}[^\\/]+[\\/]+[^\\/]+)/.test(path);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Ancestor chain from the filesystem root to `target` inclusive — the
|
|
29
|
+
* breadcrumb rows of a listing, every one a jump target. On a UNC path the walk
|
|
30
|
+
* terminates at the share root, whose `dirname` is itself.
|
|
31
|
+
*
|
|
32
|
+
* The `win32` flavour is explicit, not the platform default: these helpers
|
|
33
|
+
* serve Windows paths only, and the bare `node:path` functions are POSIX on
|
|
34
|
+
* Linux, where a UNC path parses as a single relative segment and the chain
|
|
35
|
+
* collapses to `['.', <whole path>]`. Walking up from inside a distro also
|
|
36
|
+
* yields the share root WITH its trailing separator (`\\wsl.localhost\ubuntu\`)
|
|
37
|
+
* — canonicalized by {@link breadcrumbs}, and asserted by the tests.
|
|
38
|
+
*
|
|
39
|
+
* `win32.basename` of a drive root (`C:\`) is empty, so the root crumb falls
|
|
40
|
+
* back to its own path rather than rendering blank.
|
|
41
|
+
*
|
|
42
|
+
* @param target - an absolute Windows path.
|
|
43
|
+
* @returns the ancestry, outermost first.
|
|
44
|
+
*/
|
|
45
|
+
export function ancestryCrumbs(target) {
|
|
46
|
+
const crumbs = [];
|
|
47
|
+
let current = target;
|
|
48
|
+
for (;;) {
|
|
49
|
+
const parent = win32.dirname(current);
|
|
50
|
+
// `basename` of a volume root is empty (`C:\`), so the root crumb falls
|
|
51
|
+
// back to its own path rather than rendering blank.
|
|
52
|
+
crumbs.unshift({ name: win32.basename(current) || current, path: current, hidden: false });
|
|
53
|
+
if (parent === current) return crumbs;
|
|
54
|
+
current = parent;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Breadcrumb rows for a level, with the WSL share head prepended for anything
|
|
60
|
+
* inside a distro.
|
|
61
|
+
*
|
|
62
|
+
* Two Windows path quirks make this more than a relabel. `win32.dirname` treats
|
|
63
|
+
* `\\server\share` as a volume root and never yields the share itself, so the
|
|
64
|
+
* WSL row has to be synthesized; and `win32.basename` of that same share root is
|
|
65
|
+
* the empty string, so the distro row is named from the parsed distro instead.
|
|
66
|
+
* Without both fixes, browsing into a distro would render a blank breadcrumb and
|
|
67
|
+
* offer no way back to the distro list.
|
|
68
|
+
*
|
|
69
|
+
* @param target - the directory being listed.
|
|
70
|
+
* @param providerRoot - the share root acting as the WSL row's jump target.
|
|
71
|
+
* @returns breadcrumb rows, outermost first.
|
|
72
|
+
*/
|
|
73
|
+
export function breadcrumbs(target, providerRoot) {
|
|
74
|
+
const crumbs = ancestryCrumbs(target);
|
|
75
|
+
const head = crumbs[0];
|
|
76
|
+
if (head === undefined) return [{ name: "WSL", path: providerRoot, hidden: false }];
|
|
77
|
+
const parsed = isWslUnc(head.path) ? uncToPosix(head.path) : undefined;
|
|
78
|
+
if (parsed !== undefined && parsed.linuxPath === "/") {
|
|
79
|
+
// `win32.dirname` reports the share root with a trailing separator
|
|
80
|
+
// (`\\wsl.localhost\ubuntu\`); rewrite the row to the canonical distro root
|
|
81
|
+
// so crumb paths match what distroRoot() and the picker produce elsewhere.
|
|
82
|
+
crumbs[0] = { name: parsed.distro, path: `${providerRoot}\\${parsed.distro}`, hidden: false };
|
|
83
|
+
crumbs.unshift({ name: "WSL", path: providerRoot, hidden: false });
|
|
84
|
+
}
|
|
85
|
+
return crumbs;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Insert a streamed candidate into the name-sorted bounded window, evicting the
|
|
90
|
+
* name-largest candidate when the window exceeds `keep`. Keeps memory O(keep)
|
|
91
|
+
* regardless of how many children a level holds, so a pathological directory
|
|
92
|
+
* cannot make the picker allocate one row per entry.
|
|
93
|
+
*
|
|
94
|
+
* @param window - the name-ascending window, mutated in place.
|
|
95
|
+
* @param candidate - the streamed candidate to place.
|
|
96
|
+
* @param keep - the window bound.
|
|
97
|
+
* @returns true when an eviction happened (the level has more candidates).
|
|
98
|
+
*/
|
|
99
|
+
export function boundedInsert(window, candidate, keep) {
|
|
100
|
+
if (window.length === keep && candidate.name.localeCompare(window[window.length - 1].name) >= 0) return true;
|
|
101
|
+
let lo = 0;
|
|
102
|
+
let hi = window.length;
|
|
103
|
+
while (lo < hi) {
|
|
104
|
+
const mid = (lo + hi) >>> 1;
|
|
105
|
+
if (candidate.name.localeCompare(window[mid].name) < 0) hi = mid;
|
|
106
|
+
else lo = mid + 1;
|
|
107
|
+
}
|
|
108
|
+
window.splice(lo, 0, candidate);
|
|
109
|
+
if (window.length <= keep) return false;
|
|
110
|
+
window.pop();
|
|
111
|
+
return true;
|
|
112
|
+
}
|
package/lib/paths.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path translation between the three coordinate systems a WSL-backed session
|
|
3
|
+
* touches:
|
|
4
|
+
*
|
|
5
|
+
* 1. Linux/POSIX paths inside the distro /home/andy/proj/src/a.ts
|
|
6
|
+
* 2. WSL's Windows UNC share \\wsl.localhost\ubuntu\home\andy\proj\src\a.ts
|
|
7
|
+
* 3. The Windows filesystem itself C:\Users\andyz\... -> /mnt/c/Users/andyz/...
|
|
8
|
+
*
|
|
9
|
+
* The harness host can reach (2) directly with Node's fs, which is what makes
|
|
10
|
+
* reads and ripgrep searches work without any in-distro helper. Commands must
|
|
11
|
+
* run inside the distro, so the shell executor speaks (1).
|
|
12
|
+
*
|
|
13
|
+
* These helpers are pure and dependency-free so they can be unit-tested without
|
|
14
|
+
* booting Cordis.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-plugin-wsl/paths
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** The WSL UNC share prefix Node can read. `\\wsl$\<distro>\...` is the legacy spelling. */
|
|
20
|
+
const UNC_RE = /^\\\\wsl(?:\.localhost|\$)\\([^\\]+)(?:\\([\s\S]*))?$/i;
|
|
21
|
+
const DRIVE_RE = /^([A-Za-z]):[\\/]([\s\S]*)$/;
|
|
22
|
+
|
|
23
|
+
/** Normalize Windows separators without touching a POSIX path. */
|
|
24
|
+
function toWindowsSlashes(value) {
|
|
25
|
+
return String(value).replace(/\//g, "\\");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether a string is the WSL UNC share rather than an ordinary Windows path.
|
|
30
|
+
* @param value - candidate path.
|
|
31
|
+
* @returns true for `\\wsl.localhost\...` and `\\wsl$\...`.
|
|
32
|
+
*/
|
|
33
|
+
export function isWslUnc(value) {
|
|
34
|
+
return UNC_RE.test(String(value));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Whether a string is POSIX-absolute. On Windows `path.isAbsolute('/home/x')`
|
|
39
|
+
* is also true, so the WSL mapper must test this before falling back to the
|
|
40
|
+
* host helpers.
|
|
41
|
+
* @param value - candidate path.
|
|
42
|
+
* @returns true when the path starts with a single forward slash.
|
|
43
|
+
*/
|
|
44
|
+
export function isPosixAbsolute(value) {
|
|
45
|
+
return /^\/(?!\/)/.test(String(value));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Whether a path is relative — the only input for which {@link toWorldPath} and
|
|
50
|
+
* {@link toLinuxPath} consult their `cwd` fallback. A provider uses this to skip
|
|
51
|
+
* resolving a default workdir for input that can never need one.
|
|
52
|
+
* @param value - candidate path.
|
|
53
|
+
* @returns true when the path names no absolute location.
|
|
54
|
+
*/
|
|
55
|
+
export function isRelativeWorldPath(value) {
|
|
56
|
+
const text = String(value ?? "");
|
|
57
|
+
if (text.length === 0) return false;
|
|
58
|
+
return !isWslUnc(text) && !isPosixAbsolute(text) && !DRIVE_RE.test(text);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Drop trailing separators, keeping a bare root (`C:\`, `\\wsl.localhost\x\`) meaningful. */
|
|
62
|
+
function trimTrailingSeparators(value) {
|
|
63
|
+
return value.replace(/[\\/]+$/, "") || value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* A UNC, drive, or (with a distro) Linux path as a comparable Windows key.
|
|
68
|
+
* Windows semantics are case-insensitive and separator-tolerant, so the key is
|
|
69
|
+
* lowercased and backslashed; a Linux path maps onto the distro's UNC share so
|
|
70
|
+
* it can be compared with a target reached through that share.
|
|
71
|
+
* @param value - the path to key.
|
|
72
|
+
* @param distro - the distro whose share a Linux path maps onto, if any.
|
|
73
|
+
* @returns the key, or undefined when the path is not in that vocabulary.
|
|
74
|
+
*/
|
|
75
|
+
function toWindowsKey(value, distro) {
|
|
76
|
+
const text = String(value ?? "");
|
|
77
|
+
if (text.length === 0) return undefined;
|
|
78
|
+
if (DRIVE_RE.test(text) || isWslUnc(text)) {
|
|
79
|
+
const key = trimTrailingSeparators(toWindowsSlashes(text)).toLowerCase();
|
|
80
|
+
// A drive root trims to `c:`; without its separator back the prefix test
|
|
81
|
+
// would accept a sibling like `C:\ish` as a child of `C:\`.
|
|
82
|
+
return /^[a-z]:$/.test(key) ? `${key}\\` : key;
|
|
83
|
+
}
|
|
84
|
+
if (distro !== undefined && distro !== "" && isPosixAbsolute(text)) {
|
|
85
|
+
return trimTrailingSeparators(toWindowsSlashes(posixToUnc(distro, text))).toLowerCase();
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** A POSIX-absolute path as a comparable key, without its trailing separators. */
|
|
91
|
+
function toPosixKey(value) {
|
|
92
|
+
const text = String(value ?? "");
|
|
93
|
+
if (!isPosixAbsolute(text)) return undefined;
|
|
94
|
+
const trimmed = text.replace(/\/+$/, "");
|
|
95
|
+
return trimmed.length === 0 ? "/" : trimmed;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Whether a world path is a granted root or lies beneath it, compared in the
|
|
100
|
+
* coordinate system the two spellings share.
|
|
101
|
+
*
|
|
102
|
+
* A grant is written in the vocabulary of the world it governs: the Windows
|
|
103
|
+
* sandbox hands out drive and UNC paths, while a distro-side grant is a Linux
|
|
104
|
+
* path such as `/tmp`. Passing the distro maps a Linux grant onto the same UNC
|
|
105
|
+
* share as the target, so `\\wsl.localhost\ubuntu\home\andy` can be compared
|
|
106
|
+
* with `/home/andy`. Mixed pairs that share no vocabulary report no containment
|
|
107
|
+
* — the conservative answer, never a textual guess.
|
|
108
|
+
*
|
|
109
|
+
* @param target - the path being tested, in any coordinate system.
|
|
110
|
+
* @param root - the granted root, in any coordinate system.
|
|
111
|
+
* @param options - the distro that maps a Linux root onto its UNC share.
|
|
112
|
+
* @returns true when target is root itself or a descendant of it.
|
|
113
|
+
*/
|
|
114
|
+
export function isWorldPathUnder(target, root, options = {}) {
|
|
115
|
+
const winTarget = toWindowsKey(target, options.distro);
|
|
116
|
+
const winRoot = toWindowsKey(root, options.distro);
|
|
117
|
+
if (winTarget !== undefined && winRoot !== undefined) {
|
|
118
|
+
// A drive root keeps its separator in the key, so the child boundary is
|
|
119
|
+
// "root already ends with one" rather than "append another".
|
|
120
|
+
const prefix = winRoot.endsWith("\\") ? winRoot : `${winRoot}\\`;
|
|
121
|
+
return winTarget === winRoot || winTarget.startsWith(prefix);
|
|
122
|
+
}
|
|
123
|
+
const posixTarget = toPosixKey(target);
|
|
124
|
+
const posixRoot = toPosixKey(root);
|
|
125
|
+
if (posixTarget !== undefined && posixRoot !== undefined) {
|
|
126
|
+
return posixRoot === "/" || posixTarget === posixRoot || posixTarget.startsWith(`${posixRoot}/`);
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Map a Linux path inside a distro onto the UNC path the host can read.
|
|
133
|
+
* @param distro - distro name, e.g. `ubuntu`.
|
|
134
|
+
* @param linuxPath - absolute Linux path, e.g. `/home/andy/proj`.
|
|
135
|
+
* @returns the equivalent `\\wsl.localhost\<distro>\...` path.
|
|
136
|
+
*/
|
|
137
|
+
export function posixToUnc(distro, linuxPath) {
|
|
138
|
+
const rest = String(linuxPath).replace(/^\/+/, "").replace(/\//g, "\\");
|
|
139
|
+
return `\\\\wsl.localhost\\${distro}\\${rest}`.replace(/\\+$/, "\\");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Map a WSL UNC path back onto the distro and Linux path it names.
|
|
144
|
+
* @param uncPath - a `\\wsl.localhost\<distro>\...` path.
|
|
145
|
+
* @returns `{ distro, linuxPath }`, or undefined for any other path.
|
|
146
|
+
*/
|
|
147
|
+
export function uncToPosix(uncPath) {
|
|
148
|
+
const match = UNC_RE.exec(String(uncPath));
|
|
149
|
+
if (!match?.[1]) return undefined;
|
|
150
|
+
const rest = (match[2] ?? "").replace(/\\/g, "/");
|
|
151
|
+
return { distro: match[1], linuxPath: rest.length > 0 ? `/${rest}` : "/" };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Whether a UNC path belongs to the named distro. Used to confine the WSL
|
|
156
|
+
* filesystem backend to one distro instead of silently serving every mounted
|
|
157
|
+
* share.
|
|
158
|
+
* @param uncPath - candidate UNC path.
|
|
159
|
+
* @param distro - the distro this session is pinned to.
|
|
160
|
+
* @returns true when the path is the same distro (case-insensitive).
|
|
161
|
+
*/
|
|
162
|
+
export function isUnderDistro(uncPath, distro) {
|
|
163
|
+
const parsed = uncToPosix(uncPath);
|
|
164
|
+
return parsed !== undefined && parsed.distro.toLowerCase() === String(distro).toLowerCase();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Translate a Windows drive path into its WSL interop mount.
|
|
169
|
+
* @param winPath - e.g. `C:\Users\andyz\Documents`.
|
|
170
|
+
* @returns e.g. `/mnt/c/Users/andyz/Documents`, or undefined for a non-drive path.
|
|
171
|
+
*/
|
|
172
|
+
export function windowsToLinuxMount(winPath) {
|
|
173
|
+
const match = DRIVE_RE.exec(String(winPath));
|
|
174
|
+
if (!match?.[1]) return undefined;
|
|
175
|
+
return `/mnt/${match[1].toLowerCase()}/${match[2].replace(/\\/g, "/")}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Resolve a caller-supplied workdir into a path `wsl.exe --cd` accepts.
|
|
180
|
+
*
|
|
181
|
+
* Accepts every coordinate system, because the tool layer passes whatever the
|
|
182
|
+
* session cwd is (a UNC path once the workspace is a WSL folder) while a human
|
|
183
|
+
* editing the profile is likely to write a plain Linux path.
|
|
184
|
+
*
|
|
185
|
+
* @param value - the path to translate.
|
|
186
|
+
* @param options - the pinned distro and the fallback directory for relative input.
|
|
187
|
+
* @returns an absolute Linux path, or the input unchanged when it cannot be mapped.
|
|
188
|
+
*/
|
|
189
|
+
export function toLinuxPath(value, options) {
|
|
190
|
+
const text = String(value ?? "");
|
|
191
|
+
if (text.length === 0) return text;
|
|
192
|
+
const parsed = uncToPosix(text);
|
|
193
|
+
if (parsed !== undefined) return parsed.linuxPath;
|
|
194
|
+
if (isPosixAbsolute(text)) return text;
|
|
195
|
+
const mounted = windowsToLinuxMount(text);
|
|
196
|
+
if (mounted !== undefined) return mounted;
|
|
197
|
+
// Relative input is resolved against the configured default workdir.
|
|
198
|
+
const base = options?.cwd ?? "/";
|
|
199
|
+
const baseLinux = toLinuxPath(base, { distro: options?.distro });
|
|
200
|
+
return `${baseLinux.replace(/\/+$/, "")}/${text.replace(/^\.\//, "")}`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Resolve a caller-supplied path into the UNC coordinate system the host's fs
|
|
205
|
+
* calls use. Linux paths from the model, UNC paths from the harness, and
|
|
206
|
+
* Windows paths from the host all have to land somewhere real.
|
|
207
|
+
*
|
|
208
|
+
* @param value - the path to translate.
|
|
209
|
+
* @param options - the pinned distro and the fallback directory for relative input.
|
|
210
|
+
* @returns an absolute host path (UNC for anything inside the distro).
|
|
211
|
+
*/
|
|
212
|
+
export function toWorldPath(value, options) {
|
|
213
|
+
const text = String(value ?? "");
|
|
214
|
+
if (text.length === 0) return text;
|
|
215
|
+
if (isWslUnc(text)) return toWindowsSlashes(text);
|
|
216
|
+
if (isPosixAbsolute(text)) return posixToUnc(options?.distro ?? "Ubuntu", text);
|
|
217
|
+
if (DRIVE_RE.test(text)) return toWindowsSlashes(text);
|
|
218
|
+
const base = options?.cwd ?? process.cwd();
|
|
219
|
+
const baseWorld = toWorldPath(base, { distro: options?.distro });
|
|
220
|
+
return `${baseWorld.replace(/[\\/]+$/, "")}\\${toWindowsSlashes(text).replace(/^\.\\/, "")}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Render a world path back into the form the model and the UI should see: a
|
|
225
|
+
* Linux path inside the distro, and the ordinary Windows path everywhere else.
|
|
226
|
+
* `FsTarget.targetKey` stays the UNC path (the contract treats it as opaque);
|
|
227
|
+
* only `displayPath` is rewritten.
|
|
228
|
+
*
|
|
229
|
+
* @param worldPath - an absolute host path.
|
|
230
|
+
* @param distro - the distro whose paths should be shown as Linux paths.
|
|
231
|
+
* @returns the display path.
|
|
232
|
+
*/
|
|
233
|
+
export function toDisplayPath(worldPath, distro) {
|
|
234
|
+
const parsed = uncToPosix(worldPath);
|
|
235
|
+
if (parsed !== undefined && parsed.distro.toLowerCase() === String(distro).toLowerCase()) return parsed.linuxPath;
|
|
236
|
+
return String(worldPath);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** The provider root of the WSL UNC share — the level that holds one entry per distro. */
|
|
240
|
+
export const UNC_PROVIDER_ROOT = "\\\\wsl.localhost";
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* The UNC root of one distro, which is the mount point of that distro's `/`.
|
|
244
|
+
* This is a complete UNC path (`\\server\share`), which is what the directory
|
|
245
|
+
* picker's fully-qualified check requires and what the workspace registry
|
|
246
|
+
* accepts as a project directory.
|
|
247
|
+
*
|
|
248
|
+
* @param distro - distro name.
|
|
249
|
+
* @returns e.g. `\\wsl.localhost\ubuntu`.
|
|
250
|
+
*/
|
|
251
|
+
export function distroRoot(distro) {
|
|
252
|
+
return `${UNC_PROVIDER_ROOT}\\${distro}`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Whether a path names the WSL share's root rather than a distro inside it.
|
|
257
|
+
* Both share spellings and a trailing separator are accepted.
|
|
258
|
+
*
|
|
259
|
+
* @param value - candidate path.
|
|
260
|
+
* @returns true for `\\wsl.localhost` and `\\wsl$` in any casing.
|
|
261
|
+
*/
|
|
262
|
+
export function isProviderRoot(value) {
|
|
263
|
+
const trimmed = String(value).replace(/[\\/]+$/, "").toLowerCase();
|
|
264
|
+
return trimmed === UNC_PROVIDER_ROOT.toLowerCase() || trimmed === "\\\\wsl$";
|
|
265
|
+
}
|