dsh-plugin-wsl-env 0.7.5 → 0.9.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +345 -8
  2. package/CONTRIBUTING.md +221 -68
  3. package/README.md +50 -35
  4. package/SECURITY.md +18 -2
  5. package/SUPPORT.md +23 -7
  6. package/cordis.patch.yml +9 -0
  7. package/docs/ARCHITECTURE.md +200 -57
  8. package/docs/CONFIGURATION.md +180 -16
  9. package/docs/LIMITATIONS.md +91 -33
  10. package/docs/PARITY.md +66 -38
  11. package/docs/PEER-PARITY.md +95 -32
  12. package/docs/README.zh.md +49 -31
  13. package/docs/UPSTREAM-FSIO-EXPORT.md +159 -50
  14. package/docs/UPSTREAM-TERMINAL-TITLE.md +49 -14
  15. package/lib/agent-confined.d.ts +42 -0
  16. package/lib/agent-confined.js +25 -41
  17. package/lib/agent-errors.d.ts +31 -0
  18. package/lib/agent-errors.js +19 -16
  19. package/lib/agent-exec.d.ts +159 -0
  20. package/lib/agent-exec.js +151 -165
  21. package/lib/agent-protocol.d.ts +192 -0
  22. package/lib/agent-protocol.js +76 -100
  23. package/lib/agent-shared.d.ts +27 -0
  24. package/lib/agent-shared.js +12 -12
  25. package/lib/agent.d.ts +353 -0
  26. package/lib/agent.js +536 -552
  27. package/lib/auto-preset.d.ts +110 -0
  28. package/lib/auto-preset.js +157 -141
  29. package/lib/bwrap.d.ts +90 -0
  30. package/lib/bwrap.js +18 -18
  31. package/lib/file-reference-wsl.d.ts +160 -0
  32. package/lib/file-reference-wsl.js +192 -173
  33. package/lib/fs-decisions.d.ts +107 -0
  34. package/lib/fs-decisions.js +64 -60
  35. package/lib/fs-routing.d.ts +182 -0
  36. package/lib/fs-routing.js +173 -116
  37. package/lib/fs-substrate.d.ts +258 -0
  38. package/lib/fs-substrate.js +248 -248
  39. package/lib/fs.d.ts +10 -0
  40. package/lib/fs.js +5 -0
  41. package/lib/fsio-agent.d.ts +307 -0
  42. package/lib/fsio-agent.js +414 -410
  43. package/lib/fsio-text.d.ts +115 -0
  44. package/lib/fsio-text.js +104 -84
  45. package/lib/git-route.d.ts +100 -0
  46. package/lib/git-route.js +46 -47
  47. package/lib/index.d.ts +1003 -0
  48. package/lib/index.js +1106 -1003
  49. package/lib/listing.d.ts +114 -0
  50. package/lib/listing.js +68 -55
  51. package/lib/paths.d.ts +182 -0
  52. package/lib/paths.js +134 -109
  53. package/lib/picker.d.ts +266 -0
  54. package/lib/picker.js +371 -351
  55. package/lib/ports.d.ts +44 -0
  56. package/lib/ports.js +39 -29
  57. package/lib/preflight.d.ts +91 -0
  58. package/lib/preflight.js +94 -0
  59. package/lib/preset-choice.d.ts +33 -0
  60. package/lib/preset-choice.js +15 -7
  61. package/lib/probe-cache.d.ts +51 -0
  62. package/lib/probe-cache.js +43 -29
  63. package/lib/sandbox-core.d.ts +149 -0
  64. package/lib/sandbox-core.js +239 -87
  65. package/lib/sandbox.d.ts +48 -0
  66. package/lib/sandbox.js +4 -4
  67. package/lib/search-exec.d.ts +96 -0
  68. package/lib/search-exec.js +52 -79
  69. package/lib/search-route.d.ts +75 -0
  70. package/lib/search-route.js +30 -31
  71. package/lib/shell-env.d.ts +88 -0
  72. package/lib/shell-env.js +78 -74
  73. package/lib/shell.d.ts +10 -0
  74. package/lib/shell.js +5 -0
  75. package/lib/subprocess.d.ts +313 -0
  76. package/lib/subprocess.js +267 -262
  77. package/lib/terminal-activity.d.ts +98 -0
  78. package/lib/terminal-activity.js +29 -39
  79. package/lib/terminal-route.d.ts +27 -0
  80. package/lib/terminal-route.js +16 -8
  81. package/lib/watcher.d.ts +77 -0
  82. package/lib/watcher.js +120 -126
  83. package/lib/workspace-files-route.d.ts +132 -0
  84. package/lib/workspace-files-route.js +73 -81
  85. package/lib/workspace-files-wsl.d.ts +257 -0
  86. package/lib/workspace-files-wsl.js +311 -251
  87. package/lib/wsl.d.ts +266 -0
  88. package/lib/wsl.js +150 -155
  89. package/locale/preflight/en.json +6 -0
  90. package/locale/preflight/zh.json +6 -0
  91. package/package.json +78 -22
  92. package/scripts/diagnose.sh +92 -0
package/CHANGELOG.md CHANGED
@@ -7,11 +7,340 @@ All notable changes to this project are documented here. The format follows
7
7
  The reasoning and the measurements behind each entry are in the archived
8
8
  engineering record,
9
9
  [docs/archive/engineering-record.zh.md](docs/archive/engineering-record.zh.md)
10
- (Chinese, repository only — it is history, never a second README). Every `§`
11
- reference below points at that record's numbering.
10
+ (Chinese, repository only — it is history, never a second README). A `§`
11
+ reference below points at that record's numbering unless it names another
12
+ document: the 0.1.0 entry's `design-history §` references are to
13
+ [docs/archive/design-history.zh.md](docs/archive/design-history.zh.md), which
14
+ keeps the superseded designs under the section numbers they had while they
15
+ were part of the record.
12
16
 
13
17
  ## [Unreleased]
14
18
 
19
+ ## [0.9.0] - 2026-10-06
20
+
21
+ A usability round over the sandbox failure path: the failure stops being a
22
+ wall the first command walks into, and becomes a message that arrives early
23
+ and says how to fix it.
24
+
25
+ The bwrap refusal now classifies its cause — missing versus
26
+ present-but-failing — and prints the direct install command in the distro's
27
+ own package family (apt/dnf/pacman/zypper) instead of a hardcoded `apt-get`
28
+ line; every consumer composes it from one place. A new `wsl-preflight`
29
+ service runs the same shared probe when a distro session opens and surfaces
30
+ an unusable bwrap as a warning with the full remedy, moving the discovery
31
+ moment ahead of the first failed command — advisory only, never installing.
32
+ `pnpm run diagnose` collects a read-only, paste-ready diagnostic report for
33
+ issues, and the three bare wsl-probe failures (no distro, no `$HOME`, no
34
+ shell) now carry their next steps. The agent probe's parity legs classify
35
+ the nested-interop service timeout (`Wsl/Service/WSAETIMEDOUT`, observed on
36
+ WSL 3.0.1.0) as SKIP with the evidence attached, so an environment failure
37
+ that prevents the comparison reads as what it is instead of a parity
38
+ violation.
39
+
40
+ ## [0.8.0] - 2026-10-06
41
+
42
+ The toolchain's TypeScript story completes (pnpm, a checkJs gate, and 36 of 36
43
+ modules with their declarations shipped), and with it three behaviour fixes
44
+ land: the byte-window cap is enforced, the agent path's EXEC capture budget is
45
+ honoured, and the filesystem's host-path mapping speaks its synchronous
46
+ contract.
47
+
48
+ One theme: the toolchain moves from npm to pnpm. `pnpm-lock.yaml` replaces
49
+ `package-lock.json`, CI installs through corepack with
50
+ `pnpm install --frozen-lockfile` (the `packageManager` field pins pnpm 11.7.0,
51
+ matching the harness repository), and the three dependencies with install
52
+ scripts (`@deepseek-ai/dsh-subprocess-local`, `koffi`, `node-pty`) are
53
+ allow-listed in `pnpm-workspace.yaml` — pnpm 11 blocks dependency build
54
+ scripts by default. With it: `engines` and the CI matrix align with the harness
55
+ host's own floor (`^22.19.0 || >=24.0.0`), so the Node 20 legs are gone, and
56
+ the per-target lock test drops its unused `withResolvers` gate, a Node 22+ API
57
+ that hung those legs on every push.
58
+
59
+ The unit suite also takes on the integration layer. `test/provider.test.mjs`
60
+ boots the REAL `WslShellExecutor` and `WslFileSystem` with substitutes only at
61
+ the seams that would reach `wsl.exe` — the agent, the substrate, the
62
+ confinement — so the guard chain, the mutation routing, the agent execution
63
+ path with its result decoration, the one-shot fallback and the runner-failure
64
+ remap are measured: `lib/index.js` goes from 60% lines / 9% functions covered
65
+ to 97%/90% when it joins, and measures 97.49% lines / 95.16% functions in the
66
+ released tree. The coverage gate's branch threshold moves with it, 85 to 84 —
67
+ the newly measured layer's uncovered tail is the distro-resolution branches
68
+ (`defaultDistro`'s no-distro throw, `linuxHomePath`'s refusals, the watcher's
69
+ real spawn internals) that need a live `wsl.exe`, and RELEASING.md records
70
+ the bar for raising it again: cover that tail on the Windows CI legs, or move
71
+ the coverage job to `windows-latest`. And the probes join CI: a
72
+ `workflow_dispatch` job — named for the self-hosted Windows runner, though it
73
+ carries the hosted `windows-latest` label — runs five of them: `sandbox`
74
+ unconditionally, since it needs only bubblewrap in the default distro, then
75
+ `mode`, `terminal`, `picker` and `missing-wsl` where the harness app is
76
+ present. The `sandbox` leg fails, not skips, where bubblewrap is absent, so a
77
+ dispatch to a hosted runner is no green no-op. Separately,
78
+ `test/probe/run-all-when-closed.sh`'s suite gains the four probes it was
79
+ missing — `agent`, `watch`, `substrate`, `exec`.
80
+
81
+ One more theme: the whole repository comes under a TypeScript check gate.
82
+ `tsc --noEmit` under `strict`/`checkJs` now runs as part of `pnpm test` over
83
+ `lib/**`, `test/**` and the probe scripts — a scope that narrows to what is
84
+ NOT generated once the migration completes, `lib/**` leaving the gate for the
85
+ build program below — with the types taken from the peer packages' own
86
+ declarations and the service augmentations loaded through
87
+ `types/dsh-services.d.ts`. The gate's first pass surfaced the seam work this
88
+ package already carries: the private `spawnSpec` the WSL spawn directory needs
89
+ (`docs/UPSTREAM-SPAWN-SEAM.md` bridges it) and a synchronous-contract violation
90
+ in `processPathFromHostPath`, pending a design decision.
91
+
92
+ Extending the gate to the tests found real defects the untyped corners had
93
+ been hiding: `distroReadBytes` accepted the byte-window cap (both call sites
94
+ pass it) but neither documented nor enforced it, so a ranged `readBytes`
95
+ asking past the page cap was served instead of refused — upstream refuses a
96
+ window the same way it refuses a page. Fixed against the upstream wording and
97
+ arithmetic (`lib/workspace-files-wsl.js`), with an absent length now
98
+ defaulting to the window cap rather than the whole-file cap, as upstream's
99
+ `resolveWindow` defaults it; the refusal is pinned in
100
+ `test/workspace-files-wsl.test.mjs`. Two hand-written JSDoc contracts wider
101
+ than their code (`gitSpawnRewrite`'s `argv`/`cwd`, `wslErrorCode`'s
102
+ `stdout`/`stderr` — both tolerate absence at runtime) and one narrower than
103
+ its caller (`uncToPosix`'s path) were corrected to what the functions actually
104
+ take. Test doubles are typed as the slice of the seam they script, reaching
105
+ the seam's declared type through one documented cast at the injection point —
106
+ no `any` and no new `@ts-expect-error` anywhere in the suite.
107
+
108
+ And the migration's third step opens: `src/agent-protocol.ts` is the first
109
+ module whose source is TypeScript. `pnpm run build` (`tsconfig.build.json`)
110
+ emits `lib/agent-protocol.js` plus `lib/agent-protocol.d.ts` under the same
111
+ export paths, and the artifacts stay committed so a bare checkout remains
112
+ loadable and the tarball needs no build step; the new `lint:build` gate
113
+ (`test/build-freshness.mjs`) makes `pnpm test` fail the moment a committed
114
+ artifact drifts from its source. Generated files are excluded from the
115
+ `checkJs` gate — their TypeScript sources are type-checked with
116
+ `noEmitOnError` instead, which is strictly stronger. The protocol message
117
+ union now has one home: `lib/agent.js` and the script-driven tests import
118
+ `AgentMessage` and friends from the protocol module's declarations instead of
119
+ restating them.
120
+
121
+ And the declarations land for every module. A second, declaration-only pass
122
+ (`tsconfig.dts.json`, driven by `scripts/build.mjs`) emits `.d.ts` for the
123
+ hand-written, JSDoc-typed JavaScript, and every export subpath now carries its
124
+ `types` condition — downstream finally sees this plugin's types, verified end
125
+ to end (a consumer's wrong call is rejected with the precise signature). The
126
+ declaration pass must run against a clean tree: a stale `.d.ts` is resolved as
127
+ an input exactly where `./x.js` would be, and re-emitting through it silently
128
+ degrades the result — a precise type in `index.d.ts` collapsed to `any` that
129
+ way during the migration — so the build deletes the declarations its first
130
+ pass does not own before re-emitting, and `lint:build` snapshots the
131
+ artifacts, runs the real build, byte-compares and restores the tree.
132
+ `lint:style` gained the invariant that keeps the surface from rotting: a
133
+ JavaScript export without its `types` sibling fails the gate.
134
+
135
+ `lib/paths.js` follows as the second migrated module — the path algebra every
136
+ other module imports, plus `DistroPath`/`WorldPathOptions`, which consumers
137
+ reference through `import("./paths.js").DistroPath`; the TypeScript source
138
+ keeps those names, so nothing downstream changes except that they now come
139
+ from a checked source. CONTRIBUTING records the per-module checklist this
140
+ settled into: write `src/<name>.ts`, add the generated JavaScript to the two
141
+ `exclude` lists, build, and let the suite verify the artifact is
142
+ behaviourally identical — the `exclude` step lasts only while the tree is
143
+ mixed; the finished checklist ends at write, build and test, with no list to
144
+ maintain.
145
+
146
+ Three leaf modules then follow in one pass — `agent-errors` (the two error
147
+ classes the executor switches on), `probe-cache` (the verdict policy that
148
+ remembers successes and re-probes failures) and `listing` (the picker's pure
149
+ helpers, `boundedInsert`'s generic included). Each was verified export-for-
150
+ export against its predecessor, and the whitespace-normalized code diff is
151
+ tsc's statement reflow and nothing else; every source keeps its module doc
152
+ plus a note naming the generated artifact.
153
+
154
+ The next four carry the decision layer: `fsio-text` (the byte-for-byte
155
+ replication of the peer's text mechanics — `FsCodedError` gained a declared
156
+ `code` field, and the stream decoder is typed through `node:util`, since
157
+ Node's global `TextDecoder` is a value, not a type), `fs-decisions` (the
158
+ refusal descriptors, with `Refusal` as an exported interface and `isCoded` as
159
+ a real type predicate), and `git-route`/`search-route` (the two spawn
160
+ rewrites; their generated artifacts are byte-identical modulo whitespace).
161
+ Nine of the thirty-six modules now have TypeScript sources.
162
+
163
+ Six more follow — `terminal-route`, `preset-choice`, `ports`, `bwrap`,
164
+ `agent-confined` and `agent-shared` — and they cross a structural line: a
165
+ source may now import a module that is not migrated yet. `rootDirs` merges
166
+ `src/` and `lib/` for resolution, so `./agent.js` resolves through the
167
+ generated `lib/agent.d.ts` while the emitted specifier stays `./agent.js`;
168
+ because that merge also pulls declarations in as program inputs, pass 1 now
169
+ emits into a scratch directory the build script copies from, keeping inputs
170
+ and outputs disjoint (TS5055 otherwise). `agent-shared`'s generated artifact
171
+ is byte-identical even after whitespace normalization; the rest differ only
172
+ by tsc's statement reflow. Fifteen of the thirty-six modules are TypeScript.
173
+
174
+ The mid-size tier follows: `wsl` (the `wsl.exe` interop primitives — its four
175
+ option shapes are exported interfaces now), `agent-exec` (the agent-backed
176
+ execution handle, whose request/result/runner/handle typedefs the tests and
177
+ `search-exec` already imported by name) and `shell-env` (the `DSH_*` fact
178
+ contributor, typing the harness registry it contributes through structurally,
179
+ as its JSDoc always did). `agent-exec` surfaced one Node typing fact worth
180
+ knowing: `Buffer.alloc(0)` infers `Buffer<ArrayBuffer>` while an incoming
181
+ `Buffer` is `Buffer<ArrayBufferLike>`, so the accumulators are annotated
182
+ `Buffer`. Eighteen of the thirty-six modules are TypeScript now.
183
+
184
+ Seven small modules follow — `watcher` (the in-distro mtime watch loop and its
185
+ protocol, `ChildProcess` and options typed), `sandbox-core`/`sandbox` (the
186
+ bwrap probe-and-confine pair; `WslConfined`/`WslSandboxCoreInstance` are
187
+ exported interfaces and the two class fields are `declare` so the emitted
188
+ JavaScript stays byte-identical), `terminal-activity`, `search-exec`, and the
189
+ two entry re-exports `shell`/`fs` (whose artifacts are byte-identical). At
190
+ twenty-five of thirty-six, the remaining modules are the large ones: `agent`,
191
+ `fs-substrate`, `fsio-agent`, `picker`, `subprocess`, `auto-preset`,
192
+ `workspace-files-*`, `file-reference-wsl`, `fs-routing`, and finally `index`.
193
+
194
+ The route layer follows — `workspace-files-route` (the pure build/parse pairs
195
+ for the distro-routed file service), `file-reference-wsl` (the `@`-completion
196
+ traversal strategy, with `TraversalDirent`/`FileReferenceTraversal` as
197
+ exported interfaces) and `fs-routing` (the root-plane coordinate router).
198
+ `fs-routing` is where the compiler re-met the documented upstream seam:
199
+ `WslFileSystem.processPathFromHostPath` is async against the `FileSystem`
200
+ interface's synchronous contract, so the router's lazy backend is typed as the
201
+ concrete class rather than casting the mismatch away — the seam keeps its one
202
+ visible `@ts-expect-error` in `index.js`. The port also dropped two dead
203
+ imports `fs-routing` had carried since a refactor (`windowsToLinuxMount`,
204
+ `linuxJoin`), which the emitted artifact no longer contains. The orphaned
205
+ `linuxJoin` doc block above the class — a leftover of that same refactor — is
206
+ gone too. Twenty-eight of the thirty-six modules are TypeScript.
207
+
208
+ `fs-substrate` and `auto-preset` follow — the agent-backed filesystem face
209
+ (`ResolvedTarget` exported as an interface, its six instance fields declared
210
+ with `declare` so the emitted JavaScript stays byte-identical) and the
211
+ preset-adoption plugin (whose harness service slices stay spelled
212
+ structurally, and whose `ensureSession` patch carries the `this: unknown`
213
+ parameter the JSDoc already documented). Thirty of the thirty-six modules
214
+ are TypeScript; the remaining six are `agent`, `fsio-agent`, `picker`,
215
+ `subprocess`, `workspace-files-wsl` and `index`.
216
+
217
+ `picker` follows — the biggest single module migrated so far after the
218
+ protocol file itself (494 lines). Its config, the cached distro listing and
219
+ the per-distro home map are `declare`d so the emitted JavaScript stays
220
+ byte-identical, and the browse capability object stays an inline class field,
221
+ which is how the original script wrote it. Thirty-one of the thirty-six
222
+ modules are TypeScript.
223
+
224
+ `subprocess` follows — the composition-level provider behind the GUI's
225
+ terminal window, and the last module that overrides a shipped peer class for
226
+ the terminal/search routing. Its `spawnTerminal`/`spawn` overrides are checked
227
+ against the peer's declared signatures (they pass without a new assertion),
228
+ and the two JSDoc casts the script carried (`env`, the stdout collect budget)
229
+ are absorbed into the types. Thirty-two of the thirty-six modules are
230
+ TypeScript; the last four are `agent`, `fsio-agent`, `workspace-files-wsl`
231
+ and `index`.
232
+
233
+ `agent` follows — the resident in-distro agent's whole lifecycle (756 lines).
234
+ Its seven internal methods stay `private`, which surfaced the migration's one
235
+ structural seam: a class with private members is nominal, so the declaration
236
+ generated for the still-un-migrated `fsio-agent` and the one this source emits
237
+ are not interchangeable even though the runtime object is the same class. The
238
+ one boundary (`fs-substrate` handing agents to `DistroFs`) crosses it through a
239
+ single documented assertion naming the lib-side type; it disappears when
240
+ `fsio-agent` migrates. Thirty-three of the thirty-six modules are TypeScript.
241
+
242
+ `fsio-agent` follows, and with it that seam closes: the lib-side declaration
243
+ it used to drag in is gone, so the boundary assertion in `fs-substrate` is
244
+ deleted in the same commit — the class is declared once now, and the private
245
+ members it keeps are nominal against nothing else. Thirty-four of the
246
+ thirty-six modules are TypeScript; `workspace-files-wsl` and `index` remain.
247
+
248
+ `workspace-files-wsl` follows — the distro-routed GUI file service, with
249
+ `WorkspaceFilesWslConfig`/`DistroListing` exported, the row-config read kept
250
+ as its one documented double cast (the base class keeps `config` private), and
251
+ the `readByteRange` expect-error left exactly where it was: that one is an
252
+ open design decision, not a migration artifact. Thirty-five of the thirty-six
253
+ modules are TypeScript; `index` is the last one.
254
+
255
+ `index` closes the migration — the integration layer's two providers, 1400
256
+ lines, with both documented upstream seams intact: the private `spawnSpec` a
257
+ `wsl.exe` spawn needs, and the `processPathFromHostPath` contract violation,
258
+ keep their `@ts-expect-error` carrying the reason. The generated artifact is
259
+ proven structurally identical to the hand-written module: an AST comparison
260
+ that treats the erased type wrappers (`as`, `@type` casts, parentheses) as
261
+ transparent reports only the imports the source no longer needs — a never-used
262
+ `fileURLToPath`, the dead `isUnderDistro`, and the type-only `WslAgent` (which
263
+ tsc elides; the module still loads through its other edges) — plus tsc's
264
+ reflow and one internal rename in `decorateResult`, whose result row now
265
+ derives from the handle type instead of a second type parameter. `resolve()`
266
+ returns the precise `WslExecSpec` where the JSDoc declared the wider
267
+ `ShellExecSpec`. Thirty-six of thirty-six modules are TypeScript.
268
+
269
+ The transitional scaffolding then retires, nothing left for it to do:
270
+ `rootDirs` and the scratch declaration emission existed for a mixed tree
271
+ (`src/` sources importing un-migrated `lib/*.js` neighbours), and the
272
+ declaration-only second pass (`tsconfig.dts.json`) existed to give the
273
+ hand-written JavaScript its `.d.ts`. `pnpm run build` is one `tsc` pass
274
+ emitting JavaScript and declarations straight into `lib/`, pruning
275
+ declarations no source owns; the `checkJs` gate drops its 35-entry exclude
276
+ list and states what is NOT generated — `test/**` and the ambient service
277
+ types, with `src/` checked by the build program (`noEmitOnError`); and
278
+ `lint:build` enforces the closed corpus (every `lib/*.js` has its
279
+ `src/<name>.ts`, every source has both artifacts), so "`lib/` is entirely
280
+ generated" is a checked property rather than a convention.
281
+
282
+ The real-machine probes then re-ran green on the migrated tree — 12 of 12, the
283
+ one verification face CI cannot cover (its self-hosted leg is skipped):
284
+ filesystem mutation through the throwaway wslfs profile, terminal, mode,
285
+ missing-wsl, bwrap, the shell confinement wiring, sandbox-off, picker, agent
286
+ protocol, watch, substrate and exec. The run surfaced two defects in the probe
287
+ harness itself. `ELECTRON_RUN_AS_NODE` — the flag that boots the harness CLI in
288
+ node mode — never crossed the WSL interop boundary: interop hands a Windows
289
+ process only the variables `WSLENV` lists, so the inline assignment was dropped
290
+ and the app booted as its GUI self, leaving the probe waiting on a process that
291
+ would never run; `test/probe/env.sh` lists the flag now, composed with any
292
+ `WSLENV` the caller had. And the kill-cleanup check counted every `sleep` in
293
+ the distro, which the resident agent's lease watchdog — introduced after the
294
+ probes last ran — makes non-zero by construction, alongside in-flight timeout
295
+ watchers; the check counts its own command line now, so a kill that really
296
+ leaked still fails it. And the suite's live log sits inside the checkout,
297
+ where the mirror sync's `tar` read it while it grew — `file changed as we read
298
+ it`, exit 1, `set -e` failing the probe before it ran; the sync excludes
299
+ `test/probe/.scratch` now, which is run scratch nothing at runtime reads.
300
+
301
+ One real defect fell out of the type gate's migration notes and closes here:
302
+ the agent execution path handed the EXEC frame the volatile wrapper object
303
+ where a byte budget belongs. `encodeExecFrame`'s `> 0` test was false on an
304
+ object, the frame carried 0, and 0 is the agent's "uncapped" — so the cut at
305
+ the caller's per-stream budget that `agent-exec` documents never ran, and a
306
+ chatty command cost unbounded distro memory. `src/index.ts` now reads
307
+ `config.maxOutputBytes.get()` like every other volatile field, and
308
+ `test/provider.test.mjs` pins the resolved number in the frame (the check
309
+ fails against the previous artifact). The one-shot path was always correct —
310
+ it reads the same field through the upstream executor's own `.get()`.
311
+
312
+ The second pending seam closes the same way — with an implementation instead
313
+ of a note. `WslFileSystem.processPathFromHostPath` was `async` against the
314
+ peer interface's synchronous contract, so the consumers that read it without
315
+ awaiting (spill-policy's attachment mapping, the session controller's and the
316
+ UI's path verification) received a Promise — always truthy, never the
317
+ `undefined` they test for — and mapped nothing. It is synchronous now, built
318
+ from what is already known: the distro once `distro()` has resolved it (the
319
+ pinned config, or the default `wsl.exe` answered by an earlier operation) and
320
+ the configured `cwd`, or the resolved home for a relative path. A call that
321
+ would have to ask `wsl.exe` — a cold default distro, a relative path before
322
+ the home is known — answers `undefined`, the same "no mapping" the ssh
323
+ provider gives, so the consumers take their documented refusal path instead of
324
+ receiving a bogus value. The value keeps the world spelling the backend keys
325
+ on, so their map → resolve → processPath round trip closes exactly as it does
326
+ for the host backend. `test/provider.test.mjs` pins the sync value, the round
327
+ trip, and both `undefined` cases (the checks fail against the previous
328
+ artifact). The `@ts-expect-error` count drops to three: the two remaining
329
+ design decisions and the upstream spawn seam.
330
+
331
+ The last in-code seam note closes by deletion rather than repair. The GUI file
332
+ service's `readByteRange` — a method older than the migration, which the type
333
+ gate flagged with an expect-error because its host-workspace branch called a
334
+ base method that does not exist — turned out to be unreachable: the remote
335
+ layer registers exactly the methods a decorated class declares (typert writes
336
+ its markers per instance, from the class that carries the decorators), the
337
+ base service has no such method, and nothing in the plugin or in the harness
338
+ calls it. Ranged reads already go through the wire op they always did —
339
+ `readBytes` with `options.range`, which the distro branch serves and the host
340
+ branch delegates. The method and its one test line are gone (the range case
341
+ stays covered through `readBytes`), and one more expect-error goes with it:
342
+ two remain, the exit-4 kind and the upstream spawn seam.
343
+
15
344
  ## [0.7.5] - 2026-10-05
16
345
 
17
346
  One theme: a failed environment probe retries instead of being trusted
@@ -717,6 +1046,17 @@ overwrite guard that stopped at the host.
717
1046
  app's own runtime, both entries import; `test/syntax.mjs` now checks every
718
1047
  `z.<member>` in `lib/` against the pinned peer's surface, which fails on
719
1048
  `z.enum` and passes on `z.union`.
1049
+
1050
+ ## [0.2.0] - 2026-10-03
1051
+
1052
+ One theme: the Remote-WSL parity plan (`docs/PARITY.md`) lands, Phases 0–7 —
1053
+ a resident in-distro agent plus the shell-execution, watch, publication,
1054
+ ports, terminal-routing and bootstrap work that migrates the seams onto it.
1055
+ The release closes with the two agent-path breaks that took down every GUI
1056
+ shell call, both surfacing only through the GUI's wire protocol.
1057
+
1058
+ ### Fixed
1059
+
720
1060
  - **`truncated` missing from the agent path's output streams** — the bash tool's
721
1061
  canonical result copies the field unconditionally (`canonicalBashResult`), so an
722
1062
  `undefined` failed the wire's lossless-JSON snapshot and EVERY shell tool call
@@ -799,9 +1139,6 @@ overwrite guard that stopped at the host.
799
1139
  Probed end-to-end against a real distro: `test/probe/agent.sh` (8 checks, including
800
1140
  binary-safe payloads, an in-distro timeout kill, and a 2 MB single-line response).
801
1141
  Unit tests cover the codecs and the lifecycle state machine with a fake transport.
802
-
803
- ### Added
804
-
805
1142
  - `docs/PARITY.md`: the plan to reach VS Code Remote-WSL-grade experience — a resident
806
1143
  in-distro agent as the core, with the `fs` and `shell` seams migrated onto it and the
807
1144
  current 9p/one-shot paths kept as the documented fallback — plus the Phase-0 contract
@@ -1343,9 +1680,9 @@ freshly created files.
1343
1680
  - Three peer declarations this plugin neither imports nor injects:
1344
1681
  `@deepseek-ai/dsh-sandbox`, `@deepseek-ai/dsh-shell` and
1345
1682
  `@deepseek-ai/dsh-tools`. They were required by the abandoned tool-renaming
1346
- designs (archive §15/§18), which could only stub the sandbox symbols locally
1347
- (archive §15.5). The remaining set is checkable in one command —
1348
- `grep -rho 'from "@deepseek-ai/[^"]*"' lib/ | sort -u` — plus
1683
+ designs (design-history §15/§18), which could only stub the sandbox symbols
1684
+ locally (design-history §15.5). The remaining set is checkable in one
1685
+ command — `grep -rho 'from "@deepseek-ai/[^"]*"' lib/ | sort -u` — plus
1349
1686
  `@deepseek-ai/dsh-subprocess` (the service `static inject` requires) and
1350
1687
  `@deepseek-ai/cordis`, which every DSH plugin declares.
1351
1688
  (`@deepseek-ai/dsh-sandbox` came back in this same release: the distro-side