dsh-plugin-wsl-env 0.7.4 → 0.7.5

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 CHANGED
@@ -12,6 +12,26 @@ reference below points at that record's numbering.
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [0.7.5] - 2026-10-05
16
+
17
+ One theme: a failed environment probe retries instead of being trusted
18
+ forever - the shell placeholder that used to pin bash onto every later
19
+ command, and the hardcoded distro name that minted UNC identities.
20
+
21
+ ### Fixed
22
+
23
+ - **A failed shell probe no longer pins `bash` for the executor's
24
+ lifetime.** `defaultShell` reported the literal `"bash"` when both probes
25
+ failed - a cold distro, a flaky first `wsl.exe` call - and the executor
26
+ cached that placeholder permanently: every later command ran bash on a
27
+ zsh distro, and the shell tool introduced itself as bash. The probes now
28
+ answer `undefined`; the executor caches only a real resolution and falls
29
+ back to bash per call, so the next command retries. `shell-env` follows:
30
+ an unresolved shell simply omits the `DSH_WSL_SHELL` fact instead of
31
+ presenting a guess as the distro's login shell. Alongside, `toWorldPath`
32
+ no longer mints UNC identities under the hardcoded `"Ubuntu"` fallback -
33
+ the pinned distro is a required option now, and every caller passes it.
34
+
15
35
  ## [0.7.4] - 2026-10-05
16
36
 
17
37
  One theme: the 0.2.0 review's engineering debt closes out - the five
package/lib/index.js CHANGED
@@ -270,7 +270,13 @@ export class WslShellExecutor extends LocalBashExecutor {
270
270
  async shell() {
271
271
  if (this.resolvedShell.length === 0) {
272
272
  const distro = await this.distro();
273
- this.resolvedShell = await defaultShell(distro, { wslPath: this.config.wslPath });
273
+ // An unresolvable shell is a retry, not a pin: a failed probe (a cold
274
+ // distro, a flaky first wsl.exe call) used to cache the "bash"
275
+ // placeholder for this executor's lifetime. The runtime fallback below
276
+ // keeps the command running; a later call resolves the real shell.
277
+ const resolved = await defaultShell(distro, { wslPath: this.config.wslPath });
278
+ if (resolved) this.resolvedShell = resolved;
279
+ return resolved ?? "bash";
274
280
  }
275
281
  return this.resolvedShell;
276
282
  }
package/lib/paths.js CHANGED
@@ -221,14 +221,20 @@ export function toLinuxPath(value, options) {
221
221
  * Windows paths from the host all have to land somewhere real.
222
222
  *
223
223
  * @param value - the path to translate.
224
- * @param options - the pinned distro and the fallback directory for relative input.
224
+ * @param options - the PINNED DISTRO (required: a POSIX-absolute input mints
225
+ * its UNC identity) and the fallback directory for relative input.
225
226
  * @returns an absolute host path (UNC for anything inside the distro).
226
227
  */
227
228
  export function toWorldPath(value, options) {
228
229
  const text = String(value ?? "");
229
230
  if (text.length === 0) return text;
230
231
  if (isWslUnc(text)) return toWindowsSlashes(text);
231
- if (isPosixAbsolute(text)) return posixToUnc(options?.distro ?? "Ubuntu", text);
232
+ // No distro fallback: an identity minted under a guessed distro name would
233
+ // address a filesystem that does not exist.
234
+ if (isPosixAbsolute(text)) {
235
+ if (!options?.distro) return text;
236
+ return posixToUnc(options.distro, text);
237
+ }
232
238
  if (DRIVE_RE.test(text)) return toWindowsSlashes(text);
233
239
  // Any other UNC share is already a world path in its own right — the host
234
240
  // can open it directly, and joining it onto a base would name a file that
package/lib/shell-env.js CHANGED
@@ -45,6 +45,9 @@ export async function apply(ctx, config = {}) {
45
45
  // result), so every fact has to be resolved up front, not per call.
46
46
  const configured = config.distro ?? "";
47
47
  const distro = configured.length > 0 ? configured : await defaultDistro();
48
+ // undefined when both probes failed (a cold distro): the fact is then
49
+ // simply absent, which beats presenting the "bash" placeholder as the
50
+ // distro's login shell for this process's lifetime.
48
51
  const shell = await defaultShell(distro);
49
52
  // The consumer is a shell running INSIDE the distro, so the fact is the POSIX
50
53
  // path, not the host-side world path.
@@ -87,12 +90,13 @@ export async function apply(ctx, config = {}) {
87
90
  // cross-distro guard) — so the honest resolution is no facts at all,
88
91
  // not another distro's home and shell presented as this session's.
89
92
  if (isAnotherDistrosUnc(cwd, distro)) return {};
90
- return {
93
+ const facts = {
91
94
  DSH_WSL_DISTRO: distro,
92
- DSH_WSL_SHELL: shell,
93
95
  DSH_WSL_HOME: home,
94
96
  DSH_WSL_PORTS: ports.join(","),
95
97
  };
98
+ if (shell !== undefined) facts.DSH_WSL_SHELL = shell;
99
+ return facts;
96
100
  },
97
101
  });
98
102
 
package/lib/wsl.js CHANGED
@@ -325,10 +325,14 @@ export async function defaultShell(distro, options = {}) {
325
325
  return undefined;
326
326
  }
327
327
  };
328
+ // No "bash" placeholder: a failed probe (a cold distro, a flaky first
329
+ // `wsl.exe` call) used to be pinned as the literal shell for the
330
+ // executor's lifetime. `undefined` tells the caller both answers failed;
331
+ // it may retry later or fall back itself.
328
332
  return (
329
333
  (await ask('getent passwd "$(id -u)" | cut -d: -f7')) ??
330
334
  (await ask('printf %s "$SHELL"')) ??
331
- "bash"
335
+ undefined
332
336
  );
333
337
  }
334
338
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-wsl-env",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "description": "让 DeepSeek Harness 以 WSL 子系统作为会话的执行环境:shell、文件读写与命令执行均在子系统内完成,目录选择器与 GUI 终端同样定位到子系统路径,并通过子系统内的 bubblewrap 对命令进行沙箱隔离",
5
5
  "keywords": [
6
6
  "deepseek-harness",