dsh-plugin-wsl-env 0.13.0 → 0.13.1

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
@@ -16,6 +16,47 @@ were part of the record.
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [0.13.1] - 2026-10-19
20
+
21
+ A patch release restoring `wsl-shell-env`: the component mounts again, and the
22
+ managed `DSH_*` facts it contributes now reach commands on the default
23
+ resident-agent path.
24
+
25
+ ### Changed
26
+
27
+ - **Upstream proposals filed.** The session-notice seam
28
+ ([#10263](https://github.com/deepseek-ai/deepseek-harness/discussions/10263)),
29
+ the `spawnSpec` seam (#10261), the fsio export (#10262), the UNC-workspace bug
30
+ (#10260) and the WSL-workspaces RFC (#10264) now point at their discussions;
31
+ the local drafts carry the links.
32
+
33
+ ### Fixed
34
+
35
+ - **`wsl-shell-env` no longer fails to activate.** The row sweeps the
36
+ live-agent list at mount to warm facts for sessions that opened before it,
37
+ but declared only `shellEnv` in `inject` and read `ctx.agents` as a property.
38
+ Cordis 4 refuses that read — `cannot get property "agents" without inject` —
39
+ so `apply()` rejected and the plugin manager listed the component as 异常
40
+ (`包含的组件 → 异常`), with the whole contribution missing from shell calls.
41
+ The sweep now reads the service through `ctx.get("agents")`, the sanctioned
42
+ access for a service this row does not inject: activation no longer depends
43
+ on an agent loop, and the sweep still runs when one is composed.
44
+ `wsl-preflight` carried the same property read inside a `try`/`catch`, where
45
+ the throw silently disabled its mount sweep; it gets the same fix.
46
+ `test/shell-env.test.mjs` and the real-cordis check in
47
+ `test/preflight.test.mjs` mount both rows against the guard.
48
+
49
+ - **The managed `DSH_*` namespace now reaches commands on the default
50
+ resident-agent path.** `ShellExecSpec.dshEnv` was forwarded only by the
51
+ one-shot `wsl.exe` fallback; `executeViaAgent` dropped it before
52
+ `agent.exec` — after the mount fix above, the row registered its facts but
53
+ no model shell call could see `DSH_HOME`, `DSH_SESSION_ID` or any
54
+ `DSH_WSL_*` value (`env | grep '^DSH_'` was empty). The handle now carries
55
+ the merged map (`env` first, `dshEnv` last — the same order the one-shot
56
+ path uses) into the agent's `SETENV` frames. `test/agent-exec.test.mjs` and
57
+ `test/provider.test.mjs` pin the frame, and both checks fail against the
58
+ previous build.
59
+
19
60
  ## [0.13.0] - 2026-10-19
20
61
 
21
62
  This release ships the P0/P1 hardening batch: session-scoped `auto`
@@ -339,9 +339,9 @@ command.
339
339
  - [x] The preflight checks bwrap, systemd PID 1, `systemd-run` and Linger.
340
340
  - [x] The warning is visibly attached to the session through the
341
341
  runtime-context entry (not only logs).
342
- - [ ] A GUI notice/banner renders it: upstream seam missing; the filing payload
343
- is ready at [proposal-session-notice.md](upstream/proposal-session-notice.md)
344
- and has not been submitted (a maintainer action).
342
+ - [ ] A GUI notice/banner renders it: filed upstream as
343
+ [#10263](https://github.com/deepseek-ai/deepseek-harness/discussions/10263);
344
+ until a seam lands, the advisory stays in the log and runtime context.
345
345
  - [x] The warning never installs anything and never changes fail-closed
346
346
  behavior.
347
347
  - [x] A session with a usable environment produces no warning.
@@ -1,7 +1,8 @@
1
1
  # Upstream proposal: export the fsio text helpers from `dsh-fs-local`
2
2
 
3
- Status: draft, not yet filed upstream — no discussion link yet (the filing
4
- convention is [UPSTREAM-TERMINAL-TITLE.md](UPSTREAM-TERMINAL-TITLE.md)).
3
+ Status: filed upstream as
4
+ [deepseek-ai/deepseek-harness#10262](https://github.com/deepseek-ai/deepseek-harness/discussions/10262)
5
+ (Ideas); the filing convention is [UPSTREAM-TERMINAL-TITLE.md](UPSTREAM-TERMINAL-TITLE.md).
5
6
  Targeting `deepseek-harness` @ `packages/fs/fs-local`, the `0.2.1-rc.x` line
6
7
  this plugin pins exactly (`@deepseek-ai/dsh-fs-local@0.2.1-rc.2`, in both the
7
8
  dev and peer dependency blocks of `package.json`). This is the Shape-A
@@ -129,10 +129,10 @@ export interface AgentExecutionHandle {
129
129
  * @returns the execution handle (`status`, `exitCode`, `signal`, `observed`,
130
130
  * `done`, `readOutput`, `kill`, `result`).
131
131
  */
132
- export declare function agentExecutionHandle({ agent, cwd, argv, timeoutMs, maxOutputBytes, signal, onStarted }: {
132
+ export declare function agentExecutionHandle({ agent, cwd, argv, timeoutMs, maxOutputBytes, env, signal, onStarted }: {
133
133
  /**
134
134
  * The {@link WslAgent}-like runner: `exec` accepting
135
- * `{cwd, argv, timeoutMs, signal}` and resolving `{exitCode, stdout, stderr}`;
135
+ * `{cwd, argv, timeoutMs, env, signal}` and resolving `{exitCode, stdout, stderr}`;
136
136
  * throws `AgentUnavailableError` when out.
137
137
  */
138
138
  agent: AgentExecRunner;
@@ -150,6 +150,13 @@ export declare function agentExecutionHandle({ agent, cwd, argv, timeoutMs, maxO
150
150
  * stream as `truncated: true`.
151
151
  */
152
152
  maxOutputBytes?: number;
153
+ /**
154
+ * Environment for this command: the caller's entries with the managed
155
+ * `DSH_*` snapshot merged last. The agent applies it as `SETENV` frames
156
+ * immediately before the command's `EXEC` (see `WslAgent.exec`); dropping it
157
+ * here is what kept every managed fact out of the resident-agent path.
158
+ */
159
+ env?: Record<string, string>;
153
160
  /** The caller's cancellation. */
154
161
  signal?: AbortSignal;
155
162
  /**
package/lib/agent-exec.js CHANGED
@@ -54,7 +54,7 @@ function memoryReader(buffer) {
54
54
  * @returns the execution handle (`status`, `exitCode`, `signal`, `observed`,
55
55
  * `done`, `readOutput`, `kill`, `result`).
56
56
  */
57
- export function agentExecutionHandle({ agent, cwd, argv, timeoutMs = 0, maxOutputBytes = 0, signal, onStarted }) {
57
+ export function agentExecutionHandle({ agent, cwd, argv, timeoutMs = 0, maxOutputBytes = 0, env, signal, onStarted }) {
58
58
  // Our own controller is the kill channel; the caller's signal races it.
59
59
  const controller = new AbortController();
60
60
  let timedOut = false;
@@ -72,7 +72,7 @@ export function agentExecutionHandle({ agent, cwd, argv, timeoutMs = 0, maxOutpu
72
72
  controller.abort(new Error(BASH_TIMEOUT_REASON));
73
73
  }, timeoutMs).unref?.();
74
74
  }
75
- const settle = agent.exec({ cwd, argv, timeoutMs, maxOutputBytes, signal: controller.signal }).then((result) => ({ ok: true, result }), (error) => {
75
+ const settle = agent.exec({ cwd, argv, timeoutMs, maxOutputBytes, env, signal: controller.signal }).then((result) => ({ ok: true, result }), (error) => {
76
76
  // A workdir the distro cannot enter is the command's own failure, not
77
77
  // the agent's: synthesize the relay-shaped stderr the one-shot path
78
78
  // produces, so the executor's `workdirFailure` check reports it the
package/lib/index.js CHANGED
@@ -831,6 +831,13 @@ export class WslShellExecutor extends LocalBashExecutor {
831
831
  const argv = runtime !== undefined
832
832
  ? this.distroArgv(resolved, shell)
833
833
  : confined !== undefined ? confined.argv : this.distroArgv(resolved, shell);
834
+ // The managed `DSH_*` snapshot merges last, exactly as the one-shot path's
835
+ // spawn env does (`ShellExecSpec`: `dshEnv` wins over `env`). The agent
836
+ // applies these as SETENV frames immediately before the command's EXEC, so
837
+ // the resident path now carries `DSH_HOME`, `DSH_SESSION_ID` and the
838
+ // `DSH_WSL_*` facts too — without this the whole registry was invisible on
839
+ // the default path while the one-shot fallback forwarded it.
840
+ const env = { ...resolved.env, ...resolved.dshEnv };
834
841
  const execution = agentExecutionHandle({
835
842
  agent,
836
843
  // The one-shot path converts the spec's workdir into the distro's
@@ -839,6 +846,7 @@ export class WslShellExecutor extends LocalBashExecutor {
839
846
  // reach `chdir` (that is the bug this line fixes).
840
847
  cwd: toLinuxPath(resolved.workdir, { distro }),
841
848
  argv,
849
+ env: Object.keys(env).length > 0 ? env : undefined,
842
850
  timeoutMs: resolved.timeoutMs,
843
851
  // The agent enforces the collect budget distro-side (the EXEC frame
844
852
  // carries it); `maxSpillBytes` stays one-shot-only — the agent path has
package/lib/preflight.js CHANGED
@@ -176,8 +176,14 @@ export async function apply(ctx, config = {}) {
176
176
  // Mount order is not a guarantee: a session created during startup can finish
177
177
  // before this service mounts and miss the event entirely (dsh-headless does
178
178
  // exactly that, and auto-preset sweeps for the same reason).
179
+ //
180
+ // `agents` is optional (this row injects nothing), so read it with `ctx.get`:
181
+ // a property read of an undeclared service throws in cordis 4, and the catch
182
+ // below would turn that into a silent no-op — exactly the sweep this block
183
+ // exists to perform.
179
184
  try {
180
- for (const agent of ctx.agents?.list() ?? [])
185
+ const agents = ctx.get("agents");
186
+ for (const agent of agents?.list() ?? [])
181
187
  void check(agent);
182
188
  }
183
189
  catch (error) {
package/lib/shell-env.js CHANGED
@@ -157,7 +157,14 @@ export async function apply(ctx, config = {}) {
157
157
  ensurePorts(parsed.distro);
158
158
  };
159
159
  const off = lifecycle.on?.("agent/created", (payload) => consider(payload?.agent));
160
- for (const agent of lifecycle.agents?.list?.() ?? [])
160
+ // The live-agent sweep is a convenience, not a dependency: `inject` names
161
+ // only `shellEnv`, so reading `ctx.agents` as a property makes cordis 4
162
+ // throw "cannot get property \"agents\" without inject" and marks the whole
163
+ // component failed. `ctx.get` is the sanctioned read for a service this
164
+ // plugin did not inject, and it answers undefined when no agent loop is
165
+ // composed — the row still activates and resolves facts per shell call.
166
+ const live = ctx.get("agents");
167
+ for (const agent of live?.list?.() ?? [])
161
168
  consider(agent);
162
169
  const dispose = ctx.shellEnv.register({
163
170
  name: "dsh-plugin-wsl-env",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-wsl-env",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "\u8ba9 DeepSeek Harness \u4ee5 WSL \u5b50\u7cfb\u7edf\u4f5c\u4e3a\u4f1a\u8bdd\u7684\u6267\u884c\u73af\u5883\uff1ashell\u3001\u6587\u4ef6\u8bfb\u5199\u4e0e\u547d\u4ee4\u6267\u884c\u5747\u5728\u5b50\u7cfb\u7edf\u5185\u5b8c\u6210\uff0c\u76ee\u5f55\u9009\u62e9\u5668\u4e0e GUI \u7ec8\u7aef\u540c\u6837\u5b9a\u4f4d\u5230\u5b50\u7cfb\u7edf\u8def\u5f84\uff0c\u5e76\u901a\u8fc7\u5b50\u7cfb\u7edf\u5185\u7684 bubblewrap \u5bf9\u547d\u4ee4\u8fdb\u884c\u6c99\u7bb1\u9694\u79bb",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -125,9 +125,9 @@
125
125
  "lint:types": "tsc --noEmit",
126
126
  "build": "node scripts/build.mjs",
127
127
  "lint:build": "node test/build-freshness.mjs",
128
- "test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=85 --test-coverage-branches=84 --test-coverage-functions=70 --test-coverage-exclude='scripts/**' test/agent-exec.test.mjs test/agent-fs-script.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/fs-substrate.test.mjs test/fs.boot.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/fsio-agent.test.mjs test/fsio-text.test.mjs test/git-route.test.mjs test/listing.test.mjs test/paths.test.mjs test/ports.test.mjs test/preset-choice.test.mjs test/probe-cache.test.mjs test/preflight.test.mjs test/sandbox.test.mjs test/search-exec.test.mjs test/search-route.test.mjs test/shell.test.mjs test/terminal-activity.test.mjs test/terminal.test.mjs test/watcher.test.mjs test/wsl.test.mjs test/fs-decisions.test.mjs test/session-scope.test.mjs test/session-runtime.test.mjs test/native-agent.test.mjs test/peers.test.mjs test/agent-shared.test.mjs test/distro-route.test.mjs test/fs-routing.test.mjs test/doctor.test.mjs test/profile-preset.test.mjs test/packaging.test.mjs test/peer-canary.test.mjs",
128
+ "test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=85 --test-coverage-branches=84 --test-coverage-functions=70 --test-coverage-exclude='scripts/**' test/agent-exec.test.mjs test/agent-fs-script.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/fs-substrate.test.mjs test/fs.boot.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/fsio-agent.test.mjs test/fsio-text.test.mjs test/git-route.test.mjs test/listing.test.mjs test/paths.test.mjs test/ports.test.mjs test/preset-choice.test.mjs test/probe-cache.test.mjs test/preflight.test.mjs test/sandbox.test.mjs test/search-exec.test.mjs test/search-route.test.mjs test/shell.test.mjs test/shell-env.test.mjs test/terminal-activity.test.mjs test/terminal.test.mjs test/watcher.test.mjs test/wsl.test.mjs test/fs-decisions.test.mjs test/session-scope.test.mjs test/session-runtime.test.mjs test/native-agent.test.mjs test/peers.test.mjs test/agent-shared.test.mjs test/distro-route.test.mjs test/fs-routing.test.mjs test/doctor.test.mjs test/profile-preset.test.mjs test/packaging.test.mjs test/peer-canary.test.mjs",
129
129
  "test:syntax": "node test/syntax.mjs",
130
- "test:unit": "node --test test/fs.boot.test.mjs test/fsio-text.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/paths.test.mjs test/listing.test.mjs test/shell.test.mjs test/terminal.test.mjs test/probe-cache.test.mjs test/preflight.test.mjs test/preset-choice.test.mjs test/sandbox.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/agent-fs-script.test.mjs test/fsio-agent.test.mjs test/fs-substrate.test.mjs test/agent-exec.test.mjs test/ports.test.mjs test/watcher.test.mjs test/wsl.test.mjs test/fs-decisions.test.mjs test/git-route.test.mjs test/search-route.test.mjs test/search-exec.test.mjs test/terminal-activity.test.mjs test/session-scope.test.mjs test/session-runtime.test.mjs test/native-agent.test.mjs test/peers.test.mjs test/agent-shared.test.mjs test/distro-route.test.mjs test/fs-routing.test.mjs test/doctor.test.mjs test/profile-preset.test.mjs test/packaging.test.mjs test/peer-canary.test.mjs",
130
+ "test:unit": "node --test test/fs.boot.test.mjs test/fsio-text.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/paths.test.mjs test/listing.test.mjs test/shell.test.mjs test/shell-env.test.mjs test/terminal.test.mjs test/probe-cache.test.mjs test/preflight.test.mjs test/preset-choice.test.mjs test/sandbox.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/agent-fs-script.test.mjs test/fsio-agent.test.mjs test/fs-substrate.test.mjs test/agent-exec.test.mjs test/ports.test.mjs test/watcher.test.mjs test/wsl.test.mjs test/fs-decisions.test.mjs test/git-route.test.mjs test/search-route.test.mjs test/search-exec.test.mjs test/terminal-activity.test.mjs test/session-scope.test.mjs test/session-runtime.test.mjs test/native-agent.test.mjs test/peers.test.mjs test/agent-shared.test.mjs test/distro-route.test.mjs test/fs-routing.test.mjs test/doctor.test.mjs test/profile-preset.test.mjs test/packaging.test.mjs test/peer-canary.test.mjs",
131
131
  "lint:style": "node test/style.mjs",
132
132
  "lint:links": "node scripts/check-links.mjs",
133
133
  "prepublishOnly": "pnpm test",