dsh-plugin-wsl-env 0.15.0 → 0.16.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 +87 -14
- package/CONTRIBUTING.md +25 -33
- package/README.md +10 -10
- package/SECURITY.md +6 -4
- package/SUPPORT.md +8 -8
- package/agent/native/linux-aarch64/dsh-wsl-agent +0 -0
- package/agent/native/linux-x86_64/dsh-wsl-agent +0 -0
- package/agent/wsl-agent.sh +4 -5
- package/cordis.patch.yml +8 -1
- package/docs/ARCHITECTURE.md +42 -35
- package/docs/COMPATIBILITY.md +121 -0
- package/docs/CONFIGURATION.md +254 -273
- package/docs/LIMITATIONS.md +61 -26
- package/docs/MIGRATION.md +16 -13
- package/docs/PARITY.md +4 -3
- package/docs/PERFORMANCE.md +11 -9
- package/docs/QUICKSTART.md +46 -21
- package/docs/README.zh.md +7 -7
- package/docs/RELEASING.md +257 -0
- package/docs/REQUIREMENTS.zh.md +77 -0
- package/docs/ROADMAP-1.0.md +105 -61
- package/docs/ROADMAP.md +15 -9
- package/docs/UPSTREAM-FILE-REFERENCE-SEAM.md +3 -3
- package/docs/UPSTREAM-FSIO-EXPORT.md +7 -7
- package/docs/UPSTREAM-OPEN-IN-APP.md +57 -0
- package/docs/UPSTREAM-SESSION-NOTICE.md +4 -4
- package/docs/VALUE.zh.md +144 -0
- package/docs/adr/0002-native-agent.md +348 -0
- package/docs/root-fs-routing.md +186 -0
- package/docs/screenshots/picker.png +0 -0
- package/docs/screenshots/preview.png +0 -0
- package/docs/screenshots/sandbox.png +0 -0
- package/docs/screenshots/terminal.png +0 -0
- package/lib/agent-exec.d.ts +2 -3
- package/lib/agent-shared.js +1 -0
- package/lib/agent.d.ts +19 -8
- package/lib/agent.js +73 -13
- package/lib/fs-routing.d.ts +2 -1
- package/lib/fs-routing.js +13 -1
- package/lib/fs-substrate.d.ts +11 -9
- package/lib/fs-substrate.js +6 -9
- package/lib/fsio-agent.d.ts +2 -3
- package/lib/fsio-agent.js +2 -3
- package/lib/index.d.ts +20 -13
- package/lib/index.js +18 -11
- package/lib/session-runtime.d.ts +5 -3
- package/lib/session-runtime.js +5 -4
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +13 -4
- package/scripts/diagnose.sh +1 -1
- package/scripts/doctor.mjs +3 -3
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
This is the checklist this project follows. The last section records facts that
|
|
4
|
+
cost time to learn.
|
|
5
|
+
|
|
6
|
+
## 1. Decide the version
|
|
7
|
+
|
|
8
|
+
| Change | Version bump |
|
|
9
|
+
|---|---|
|
|
10
|
+
| Documentation, comments, the changelog itself | patch: 0.1.2 becomes 0.1.3 |
|
|
11
|
+
| A fix that does not change behaviour | patch |
|
|
12
|
+
| A behaviour change, a new configuration key, a new provider | minor |
|
|
13
|
+
| Anything that breaks an existing configuration | major |
|
|
14
|
+
|
|
15
|
+
The package is below 1.0.0, so the peer pins and the on-disk layer format may still
|
|
16
|
+
move in a minor release.
|
|
17
|
+
|
|
18
|
+
## 2. Cut the changelog and bump the version
|
|
19
|
+
|
|
20
|
+
1. Move the entries under `## [Unreleased]` in [`CHANGELOG.md`](../CHANGELOG.md)
|
|
21
|
+
into a new dated section, `## [x.y.z] - YYYY-MM-DD`.
|
|
22
|
+
2. Leave the `## [Unreleased]` heading in place, empty.
|
|
23
|
+
3. Add a one-line introduction to the new section when the release has one theme.
|
|
24
|
+
4. Bump `version` in [`package.json`](../package.json) to the same number.
|
|
25
|
+
|
|
26
|
+
## 3. Run the gates
|
|
27
|
+
|
|
28
|
+
The configuration-stability rules and the full gate table (including the manual
|
|
29
|
+
legs a CI run cannot execute) are in [MIGRATION.md](MIGRATION.md#gates-a-release-must-clear).
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pnpm test
|
|
33
|
+
pnpm run test:coverage
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The release workflow runs both of these before it publishes.
|
|
37
|
+
|
|
38
|
+
`pnpm test` includes the build-freshness gate: modules whose source lives in
|
|
39
|
+
`src/*.ts` must be rebuilt (`pnpm run build`) and the result committed under
|
|
40
|
+
`lib/`, so the tarball always ships exactly what the sources say without any
|
|
41
|
+
build step at pack time.
|
|
42
|
+
|
|
43
|
+
The coverage thresholds are 85 lines / 84 branches / 70 functions. The
|
|
44
|
+
branch threshold is one point under the others deliberately: the
|
|
45
|
+
integration layer is now measured, and part of what it leaves uncovered
|
|
46
|
+
needs a live `wsl.exe` — the distro-bound paths in `lib/index.js` (the
|
|
47
|
+
resolved home, the distro home, arming the watcher), the `wsl.exe` calls
|
|
48
|
+
in `lib/wsl.js` (`defaultDistro`'s no-distro throw, `linuxHomePath`,
|
|
49
|
+
`runInDistro`, and the other distro calls), and the real spawn internals
|
|
50
|
+
in `lib/watcher.js`. The real-machine probes cover that tail, not CI.
|
|
51
|
+
The rest of the uncovered branches — the host-path arm of
|
|
52
|
+
`wslWritableRoots`, the sandbox-error and rethrow arms, the
|
|
53
|
+
unrestricted-path result, all in `lib/index.js` — is ordinary
|
|
54
|
+
CI-coverable code. Do not raise the branch number without either covering
|
|
55
|
+
the `wsl.exe` tail on the Windows CI legs or moving the coverage job to
|
|
56
|
+
`windows-latest`.
|
|
57
|
+
|
|
58
|
+
Run the full real-machine suite when behaviour changed, and keep its output for
|
|
59
|
+
the pull request or the release notes. The harness application must be closed;
|
|
60
|
+
the runner waits until it exits:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
bash test/probe/run-all-when-closed.sh --include-fs
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
See [CONTRIBUTING.md](../CONTRIBUTING.md) for individual probes, prerequisites,
|
|
67
|
+
and optional performance probes not included in the suite.
|
|
68
|
+
|
|
69
|
+
`npm publish` runs the `prepublishOnly` script, which is `pnpm test`. The local
|
|
70
|
+
gates therefore run again during the release step.
|
|
71
|
+
|
|
72
|
+
## 4. Commit and tag
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git add package.json CHANGELOG.md
|
|
76
|
+
git commit -m "Release x.y.z: <what the release is>"
|
|
77
|
+
git tag -a vx.y.z -m "dsh-plugin-wsl-env x.y.z"
|
|
78
|
+
git push origin main vx.y.z
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The version in `package.json` and `CHANGELOG.md` carries no `v`. The tag and the
|
|
82
|
+
GitHub Release do. The tag push starts the release workflow described in step 5.
|
|
83
|
+
|
|
84
|
+
## 5. Publish
|
|
85
|
+
|
|
86
|
+
### The tag-triggered workflow
|
|
87
|
+
|
|
88
|
+
Pushing the tag starts `.github/workflows/release.yml`. It does five things, in
|
|
89
|
+
this order:
|
|
90
|
+
|
|
91
|
+
1. Checks that the tag matches `version` in `package.json`, using
|
|
92
|
+
`scripts/check-release-tag.mjs`.
|
|
93
|
+
2. Runs `pnpm test`, `pnpm run test:coverage`, and the shipped x86_64 and
|
|
94
|
+
aarch64 native-agent tests (the latter under QEMU).
|
|
95
|
+
3. Asks the registry whether this version is already published, and skips the
|
|
96
|
+
upload when it is. Re-pushing the same tag therefore does not publish again —
|
|
97
|
+
it only gets you as far as the GitHub Release.
|
|
98
|
+
4. Publishes with `npm publish --provenance --access public`. That attaches a
|
|
99
|
+
signed attestation tying the tarball to this workflow run and this commit.
|
|
100
|
+
5. Creates the GitHub Release, with notes taken from the changelog section by
|
|
101
|
+
`scripts/changelog-section.mjs`.
|
|
102
|
+
|
|
103
|
+
The workflow requires a trusted publisher configured on npmjs.com for this
|
|
104
|
+
repository, this workflow file, and the `npm-publish` environment. That is what
|
|
105
|
+
lets npm exchange the run's OIDC token (`id-token: write`) for a short-lived
|
|
106
|
+
publish credential, so no npm token is stored in the repository.
|
|
107
|
+
|
|
108
|
+
If trusted publishing is not configured, add an `NPM_TOKEN` repository secret and
|
|
109
|
+
hand it to the Publish step in `.github/workflows/release.yml` — the step does not
|
|
110
|
+
read it on its own, so add `env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}` to it.
|
|
111
|
+
Configure required reviewers on the `npm-publish` environment to put a second
|
|
112
|
+
person in front of every publish.
|
|
113
|
+
|
|
114
|
+
### Manual fallback
|
|
115
|
+
|
|
116
|
+
Use this when the workflow cannot run. On a trusted machine, authenticate with
|
|
117
|
+
`npm login --registry=https://registry.npmjs.org/` and complete the interactive
|
|
118
|
+
authentication and publishing challenges required by the npm account and package.
|
|
119
|
+
See [npm's two-factor authentication guidance](https://docs.npmjs.com/requiring-2fa-for-package-publishing-and-settings-modification/).
|
|
120
|
+
Keep credentials outside the repository and never put them in command arguments
|
|
121
|
+
or shell history. If a granular token is used instead, follow npm's package policy
|
|
122
|
+
and revoke the token after the release.
|
|
123
|
+
|
|
124
|
+
Run the same tag check the workflow runs, against the tag you are about to push,
|
|
125
|
+
then publish:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
node scripts/check-release-tag.mjs vx.y.z
|
|
129
|
+
|
|
130
|
+
npm publish --registry=https://registry.npmjs.org/ --access public
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Set `--registry` explicitly. A local `~/.npmrc` may point at a mirror, and a
|
|
134
|
+
release published to a mirror is not a release.
|
|
135
|
+
|
|
136
|
+
A manual publish does not create the GitHub Release, so do step 7 by hand.
|
|
137
|
+
|
|
138
|
+
## 6. Verify on the registry
|
|
139
|
+
|
|
140
|
+
`npm publish` prints `+ dsh-plugin-wsl-env@x.y.z` when the upload is accepted. That
|
|
141
|
+
is not the same as the version being visible. The version and the `dist-tags`
|
|
142
|
+
appear in the registry a minute or two later, so poll instead of checking once:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# expect 200, not 404
|
|
146
|
+
curl -sS -o /dev/null -w '%{http_code}\n' \
|
|
147
|
+
https://registry.npmjs.org/dsh-plugin-wsl-env/x.y.z
|
|
148
|
+
|
|
149
|
+
curl -sS https://registry.npmjs.org/-/package/dsh-plugin-wsl-env/dist-tags
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Then check the metadata:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm view dsh-plugin-wsl-env version dist-tags dist.fileCount \
|
|
156
|
+
--registry=https://registry.npmjs.org/ --prefer-online
|
|
157
|
+
|
|
158
|
+
npm view dsh-plugin-wsl-env readmeFilename \
|
|
159
|
+
--registry=https://registry.npmjs.org/ --prefer-online
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`readmeFilename` must be `README.md`. Compare the file count with what
|
|
163
|
+
`npm pack --dry-run` reports from the same commit: a difference means the `files`
|
|
164
|
+
list in `package.json` changed since the release.
|
|
165
|
+
|
|
166
|
+
Use `--prefer-online`, or a fresh cache directory, while verifying. A cached
|
|
167
|
+
packument shows the previous release and looks like a failed publish.
|
|
168
|
+
|
|
169
|
+
## 7. Create the GitHub Release
|
|
170
|
+
|
|
171
|
+
The tag-triggered workflow creates the Release for you, with notes from the
|
|
172
|
+
changelog section. Do it by hand only after a manual publish:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
node scripts/changelog-section.mjs > notes.md
|
|
176
|
+
|
|
177
|
+
gh release create vx.y.z --repo Big-Dao/dsh-plugin-wsl-env \
|
|
178
|
+
--title "vx.y.z - <short title>" --notes-file notes.md --verify-tag
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The notes summarise the changelog section. Mention anything a user must do, such as
|
|
182
|
+
a new required configuration key.
|
|
183
|
+
|
|
184
|
+
## 8. Refresh the runtime mirror
|
|
185
|
+
|
|
186
|
+
The Windows copy of the checkout is what the app loads. Sync it to the tagged
|
|
187
|
+
state:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
pnpm run sync:windows
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Then confirm that the two trees match:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
diff -rq --exclude=.git --exclude=node_modules --exclude=.scratch \
|
|
197
|
+
. /mnt/c/Users/<you>/Documents/deepseek-harness/default-workspace/dsh-plugin-wsl
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Read this as "no unexpected differences", not "no output". `test/probe/.scratch`
|
|
201
|
+
is never copied, and the sync is additive on purpose — it never deletes — so the
|
|
202
|
+
mirror legitimately keeps files this checkout no longer has.
|
|
203
|
+
`test/probe/sync-to-windows.sh` reports that same residual set as a note rather
|
|
204
|
+
than a failure. What matters is the other direction: a file this checkout has and
|
|
205
|
+
the mirror does not, or one that differs.
|
|
206
|
+
|
|
207
|
+
That destination is outside a session workspace, so a confined agent session is
|
|
208
|
+
refused there and has to approve a wider permission for the one command.
|
|
209
|
+
|
|
210
|
+
## 8.5. Announce on the upstream discussion
|
|
211
|
+
|
|
212
|
+
Every release appends an update comment to the plugin's upstream thread,
|
|
213
|
+
[deepseek-ai/deepseek-harness discussion #8644](https://github.com/deepseek-ai/deepseek-harness/discussions/8644)
|
|
214
|
+
(node id `D_kwDOT3T1g84AptnQ`), so followers of that thread see each version
|
|
215
|
+
without watching this repository:
|
|
216
|
+
|
|
217
|
+
- One comment per release, in Chinese (the thread's established language for
|
|
218
|
+
updates; the English original stays as the top post, refreshed on notable
|
|
219
|
+
releases).
|
|
220
|
+
- Content: the version, the two or three headline changes, the current
|
|
221
|
+
verification snapshot in one line (unit tests, matrix, container and qemu
|
|
222
|
+
legs, nightly probes), and the release link.
|
|
223
|
+
- Post it with the same GraphQL mutation the 2026-10-27 update used
|
|
224
|
+
(`addDiscussionComment` on the discussion's node id) from a session that
|
|
225
|
+
holds the maintainer's GitHub credentials — the release workflow's
|
|
226
|
+
`GITHUB_TOKEN` is scoped to this repository and cannot write there.
|
|
227
|
+
|
|
228
|
+
This is a hard checklist item, not a nicety: the thread is where the DSH
|
|
229
|
+
community found the plugin, and a stale thread reads as an abandoned one.
|
|
230
|
+
|
|
231
|
+
## 9. If a version turns out to be bad
|
|
232
|
+
|
|
233
|
+
npm does not let a published version be replaced, so the fix goes forward:
|
|
234
|
+
|
|
235
|
+
1. Deprecate the bad version, so anyone who installs it sees the warning:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npm deprecate dsh-plugin-wsl-env@x.y.z "<what is wrong>; use x.y.(z+1)" \
|
|
239
|
+
--registry=https://registry.npmjs.org/
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
2. Cut the fix as the next patch version, following this document from step 2.
|
|
243
|
+
Prefer that to `npm unpublish`, which is not a rollback: it removes the
|
|
244
|
+
tarball for every consumer that already resolved it.
|
|
245
|
+
|
|
246
|
+
3. Correct the GitHub Release for the bad tag, or point its notes at the patch
|
|
247
|
+
release. The release notes stay the first thing a reader finds.
|
|
248
|
+
|
|
249
|
+
## Operational facts worth remembering
|
|
250
|
+
|
|
251
|
+
| Fact | What it means in practice |
|
|
252
|
+
|---|---|
|
|
253
|
+
| `npm publish` prints success at upload time | The version may still return 404 for a minute or two. Poll the registry, and do not conclude that the publish failed. |
|
|
254
|
+
| A repeated publish of the same version is refused | npm checks the registry first and stops with `You cannot publish over the previously published versions: x.y.z.`; a registry-side conflict surfaces as `EPUBLISHCONFLICT` ("Cannot publish over existing version."). Either one means the first publish landed. Verify it instead of publishing again — the release workflow's already-published check exists for the same reason. |
|
|
255
|
+
| The npm readme is chosen from the candidate files at the package root, and the rule is not fully explained. With `README.md` and `README.zh.md` side by side, version 0.1.1 published as `readmeFilename: README.zh.md`, so its npm page rendered Chinese — even though the tarball listed `README.md` first. Both names match the npm CLI's own selection code (`@npmcli/package-json/lib/normalize.js` globs `{README,README.*}` and accepts `/\.m?a?r?k?d?o?w?n?$/i`, which does match `.md`), so neither name is screened out. | Do not rely on the rule. Keep exactly one readme candidate at the package root, which `pnpm run lint:style` checks. The Chinese README lives in `docs/` for this reason. |
|
|
256
|
+
| A local `~/.npmrc` may point at a mirror | Pass `--registry=https://registry.npmjs.org/` on every publish and every verification. |
|
|
257
|
+
| The npm token is a credential | Keep it out of command arguments and the repository; revoke a temporary token after the release. |
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# 需求登记表与追溯矩阵
|
|
2
|
+
|
|
3
|
+
本文是维护者治理文档,不随包发布(不在 `files` 清单)。它把分散在 README 与
|
|
4
|
+
docs/ 各篇里的行为承诺登记成带编号的需求条目,并给每条配上验证途径。它不是
|
|
5
|
+
第二份「当前状态陈述」——每条需求的权威正文仍在所指向的文档里,本文只回答
|
|
6
|
+
三个问题:**有哪些需求、在哪里规定、靠什么验证**。
|
|
7
|
+
|
|
8
|
+
**基线**:本文核对于 `main` 2026-10-19(基线 0.12.0)。每次发版,或 CI 配置、
|
|
9
|
+
覆盖率阈值等可核验项变更后,本表须重新核验;一切以仓库现状为准。
|
|
10
|
+
|
|
11
|
+
维护规则与 [PARITY.md](PARITY.md) 的纪律一致:需求变更与登记表改动进同一笔
|
|
12
|
+
变更;新增行为承诺先入表再实现;「验证」列与测试同改。登记表的唯一判定
|
|
13
|
+
来源是文档与代码的现状,不是意图。
|
|
14
|
+
|
|
15
|
+
## 判尺
|
|
16
|
+
|
|
17
|
+
一条需求登记为「完备」,需同时具备六个维度,逐条在「依据」列标注:
|
|
18
|
+
|
|
19
|
+
1. **行为定义**:触发条件 → 行为 → 结果;
|
|
20
|
+
2. **异常与拒绝语义**:失败路径、错误码、什么能解除、什么不能;
|
|
21
|
+
3. **边界与非目标**:明示不做什么、已知极限写在哪里;
|
|
22
|
+
4. **可验证性**:单测 / 真机探针 / parity 方法;
|
|
23
|
+
5. **配置面**:默认值与覆盖方式;
|
|
24
|
+
6. **环境约束**:支持矩阵与版本钉。
|
|
25
|
+
|
|
26
|
+
## 登记表
|
|
27
|
+
|
|
28
|
+
| ID | 需求(一句话) | 权威规格 | 依据 | 验证 | 残差 |
|
|
29
|
+
|---|---|---|---|---|---|
|
|
30
|
+
| R1 | 命令在发行版内执行:`wsl.exe -d <distro> --cd <linux dir> --exec <login shell> -lc <cmd>`,登录 shell 不硬编码 | README「Using it」;ARCHITECTURE「The three service providers」「Failure mode」 | ①②④⑤⑥:命令形态与 `-lc` 语义成文;`WSL_E_*`(stdout/UTF-16/exit 255)与 cwd 回退 exit-0 两类陷阱显式转报错;agent/one-shot 双路径定义 | `shell.test.mjs`、`wsl.test.mjs`、`agent-exec.test.mjs`;probe:sandbox-shell;probe:agent 三条 on/off 对比腿 | — |
|
|
31
|
+
| R2 | 文件工具读写真实发行版文件:单一 agent 基座(ext4),share 基座不复存在 | ARCHITECTURE「The filesystem substrate」;LIMITATIONS 首节 | ①②③⑤:读/写/身份在 ext4、原生符号链接与 mode 位;`createIfAbsent` no-replace 关闭 TOCTOU、版本随写 op 下发并在 rename 前复核(`FS_STALE_VERSION`);新文件 0600、agent 失联 fail-closed 均为明文;0600 与反斜杠文件名为已声明极限 | `fs-substrate.test.mjs`、`fsio-agent.test.mjs`、`agent-fs-script.test.mjs`、`provider.test.mjs`(守卫链)、`fs.boot.test.mjs`;probe:substrate 8/8 | rename 后无目录 fsync(OI-5,已入 LIMITATIONS) |
|
|
32
|
+
| R3 | 会话级环境绑定:distro 目录自动绑 `wsl` preset,Windows 目录保持原生 | ARCHITECTURE「How the pieces are mounted」;README「Architecture」 | ①②④:触发条件与 isolate realms 机制成文;registry/agent-loop 两棵树不相交的设计约束可复核 | `preset-choice.test.mjs` | 猴补上游 `ensureSession` 的接缝风险已转 promotion-map 跟踪(非本仓可独立修) |
|
|
33
|
+
| R4 | GUI 终端按会话路由:WSL 目录会话得发行版 shell,Windows 目录会话得 PowerShell(`hostSessions`) | ARCHITECTURE「Why the terminal provider is app-level」;LIMITATIONS 终端诸条 | ①②③⑤:路由判定、无目录启动落发行版、idle/busy/unknown 三态回收(`unknown` 必须暂停回收)逐项规定;tab 标题极限给出根因、上游提案与用户缓解 | `terminal.test.mjs`(terminalRoute 判定)、`terminal-activity.test.mjs`;probe:terminal | tab 标题读 `WSL`(UPSTREAM-TERMINAL-TITLE);host 终端 unknown 不回收——均为已声明边界 |
|
|
34
|
+
| R5 | 目录选择器列出已装发行版及其层级 | README「Install」;CONFIGURATION `directory-picker-wsl` 行 | ①②③⑤:根级列表、`includeHostHome`/`maxEntries`/`preferredDistro`、常驻 out 时 one-shot 回退;换行符文件名极限的边界论证闭合(`/` 不可能出现在名字里) | `listing.test.mjs`(`maxEntries` 封顶、行解析);probe:picker | `preferredDistro` 决定的根级 `path`/`home` 领位、`includeHostHome` 的排序姿态:单测与探针都没有断言(探针只查成员构成与截断旗标) |
|
|
35
|
+
| R6 | 端口可见性:`DSH_WSL_PORTS` 按节奏经常驻 agent 刷新 | README「Using it」;CONFIGURATION「`wsl-shell-env`」表 | ①⑤:机制(`/proc/net/tcp{,6}` 扫描)、`portsRefreshMs` 默认 10s、与 WSL2 localhost 转发的关系(平台行为)成文 | `ports.test.mjs`(解析层) | 轮询使常驻 agent 永不闲置回收(OI-4,已入 LIMITATIONS) |
|
|
36
|
+
| R7 | 模型可见的发行版事实与 WSLENV 政策:受管 `DSH_*` 前缀准入,`PATH` 刻意不转发 | README「Using it」「Recipes」 | ①②③:两个 Windows 路径变量带 `/p` 翻译、`PATH` 不转发的理由成文;传输环境钉死 essentials+`DSH_*`+过滤后 WSLENV;shell 解析失败则省略事实而非报假值(宁可缺报不误报) | `terminal.test.mjs`(`/p` 翻译)、`agent.test.mjs`(传输环境 WSLENV 钉死为受管项)、`provider.test.mjs`(探针失败重试、不钉占位符) | `lib/shell-env.js`(事实生成)无单测,覆盖率报告不含该模块 |
|
|
37
|
+
| R8 | 权限三档(read-only / workspace-write / danger-full-access)与提权提议流 | README「Sandbox」表;ARCHITECTURE「Error codes」 | ①②:三档行为逐档成表;模型可见两行前缀逐字给出;`FS_SANDBOX_DENIED` 可提权而 `FS_OUTSIDE_DISTRO` 不可,且区分理由明文(宽权限开不出另一个发行版) | `fs-decisions.test.mjs`、`provider.test.mjs`、`fsio-agent.test.mjs`(分类) | — |
|
|
38
|
+
| R9 | bubblewrap 沙箱:与 Linux runner 同参数、fail-closed、`enforcement: partial` 诚实上报 | ARCHITECTURE「Sandbox」全节;SECURITY「Sandbox enforcement is `partial` by design」 | ①②③⑤⑥:选型依据(ACL 令牌触不到 WSL)、探针失败不缓存、interop 洞 + `maskWindowsDrive` 收窄及其自身极限(binfmt 按内容分发)、完全关闭唯一路径(`wsl.conf`)、`sandbox: false` 退出——行为到边界到逃生门完整成链 | `sandbox.test.mjs`、`probe-cache.test.mjs`;probe:sandbox、probe:sandbox-off | interop 使 enforcement 恒为 partial——已声明的设计边界 |
|
|
39
|
+
| R10 | 文件搜索跑发行版自身的 rg,绝不跨 9p share | PARITY「Contract audit」第 2 条;LIMITATIONS「glob 和 grep」条 | ①②③:拦截点与参数逐字转发成文;缺 rg 浮出 exit 127 附 bootstrap 指引;grep 回退被拒绝且理由明文(不读 `.gitignore`,非 rg 替身) | `search-route.test.mjs`、`search-exec.test.mjs` | — |
|
|
40
|
+
| R11 | watch():inotify 优先(无界目录),轮询回退;粗粒度失效 | PARITY「Contract audit」第 1 条;LIMITATIONS watch 两条 | ①②③:契约向上追溯到宿主接缝(`changed()` 无载荷 → 粗粒度失效即可);inotify 递归且 0.5s 合并、文件/限深/无 inotify-tools 回退轮询;更旧 mtime 盲区只属轮询路径、`watchMaxDepth` 旋钮、目标消失响亮报错成文 | `watcher.test.mjs`;probe:watch(无 inotify 时 7/7;装 inotify-tools 后盲区检查改为期望事件) | 轮询回退的 mtime 盲区已声明;inotify 路径依赖发行版的 inotify-tools |
|
|
41
|
+
| R12 | share 基座退役:携带 `substrate: "share"` 的 profile 在 boot 被拒并附迁移 | README/CONFIGURATION/LIMITATIONS 三处一致 | ①②⑤:旧值处置与用户所见成文,迁移指引内嵌 | `fs-decisions.test.mjs`(拒绝消息与迁移指引文案) | boot 期拒绝分支无测试(构造器调 `shareSubstrateRefusal`,`src/index.ts:1056`):`fs.boot.test.mjs` 只以 `sandbox: true` 启动该行,仓内没有构造 `substrate: "share"` profile 的测试 |
|
|
42
|
+
| R14 | 会话级 systemd scope:命令共享后台进程/真实 `/tmp`/`ps`,scope 随会话结束停止;systemd + linger 缺失时预检带修复拒绝 | ADR 0001;README/CONFIGURATION/LIMITATIONS 的 `sessionSandbox` 条 | ①②③⑤:scope 生命周期(agent 为主进程、refcount、dispose stop)、`sessionSandbox: false` 退出、systemd/linger/systemd-run 四项预检与缓存策略成文;`/tmp` 与后台进程的保真边界限定在 runtime 开时 | `session-scope.test.mjs`、`session-runtime.test.mjs`、`provider.test.mjs`;真机会话验证(active scope、跨命令后台/`/tmp`、会话结束 0 units) | 硬崩溃可能留下 stale scope(启动清扫未随发,入 LIMITATIONS);受限写入已共享 runtime,读仍走无约束共享 agent,根级 fs-routing 不持有 session runtime |
|
|
43
|
+
| R13 | bootstrap:bwrap/ripgrep 等的就地体检与安装 | README「Install」「Troubleshooting」;CONFIGURATION | ①②⑤:`--install` 与只读体检两式、体检对象、错误消息补救指引成文 | 0.7.4 起脚本随包(`files` 收录,补救指引在 npm 安装下可用) | 脚本本身无 CI 腿(真机排错路径覆盖) |
|
|
44
|
+
| R14 | 安装/卸载/升级流:四步安装、幂等陷阱及补救、ES 模块重启须知 | README「Install」「Troubleshooting」 | ①③:每步预期输出、`add` 幂等性陷阱的补救(先 remove 再 add)、pnpm UNC 链接极限成文 | 人工步骤,无自动化(依赖真实 dsh CLI + Windows) | 无自动化守护 |
|
|
45
|
+
| R15 | 错误码方言:每个 `FS_*` 码给出抛出者、含义、解除条件;`wsl.exe` 自身失败显式收编 | ARCHITECTURE「Error codes」表 | ①②:逐码三列成表;两类历史隐形失败(UTF-16 stdout、cwd 回退 exit 0)收编;`FS_OUTSIDE_DISTRO` 独立成码的理由明文 | `fs-decisions.test.mjs`、`fsio-agent.test.mjs`、`fs-substrate.test.mjs`、`provider.test.mjs`(断言码与消息) | — |
|
|
46
|
+
| R16 | 对端 parity 合同:fsio 文本机制逐字节复刻钉死的对端版本 | PEER-PARITY 全文 | ①④⑥:钉版、验证方法(npm pack 逐函数比对)、验证日期、刻意分歧逐条声明、bump 钉版即重跑的维护规则 | `fsio-agent.test.mjs`(distro 内半区 canary);对端比对为手动方法 | 钉版升级后需重跑比对(维护规则) |
|
|
47
|
+
| R17 | 常驻 agent 协议:ACK 计时看门狗、只读帧才重放、逐流输出上限、sha256 部署校验、租约存活、进程组两段杀 | CHANGELOG 0.3.0/0.6.0/0.7.3;PARITY Phase 1/Phase 3 | ①②④:每条健壮性属性有规格出处与实证记录;「EXEC/变异 FS 帧禁止盲重发」是写明的不变量 | `agent-protocol.test.mjs`(HELLO 版本+摘要)、`agent.test.mjs`、`agent-exec.test.mjs`(truncated 旗标)、`agent-fs-script.test.mjs`;probe:agent、probe:exec | — |
|
|
48
|
+
| R18 | 配置面:每键默认值成文;层组合语义(整行替换、不深合并、后层胜) | CONFIGURATION;`cordis.patch.yml` 头注 | ⑤:随发键成表、未列表键点名;覆盖方式的正确心智模型(整行替换)成文 | `composition.test.mjs`(层组合);`style.mjs`(`files` 契约) | — |
|
|
49
|
+
| R19 | 非目标集:不做什么与为什么 | LIMITATIONS 开篇原则;PARITY「Not applicable」 | ③:已知极限入册;不适用项「记下来免得像遗漏」 | —(文档性) | — |
|
|
50
|
+
| R20 | 验证策略:三层(fake → 真脚本过真线 → 真机探针)+ CI 矩阵 + 覆盖率阈值 | ARCHITECTURE「Test layers」;README「Development」 | ④:CI 在 Node 22/24 × Linux/Windows 上跑 `pnpm test`,`pnpm run test:coverage` 只在 Node 24 上跑(门槛旗标需 Node 22.8);Node 20 有意排除(`engines` 下限);覆盖率阈值 85/84/70(行/分支/函数),测量集合覆盖 `test/` 下 40 个测试文件 | `pnpm test`、`pnpm run test:coverage`;CI(ci.yml) | 真机验证依赖 Windows 和可用的 WSL 发行版;非功能无量化目标(OI-1) |
|
|
51
|
+
| R21 | 安全过程:范围内外、响应时限、partial 属设计边界、凭据政策 | SECURITY 全文 | ②③⑥:范围、3/10/30 个工作日时限(标注「目标非合同」)、partial 定性、凭据零容忍成文 | —(过程性) | — |
|
|
52
|
+
| R22 | 支持矩阵:Windows 10/11 + WSL2 + Node `^22.19.0 \|\| >=24.0.0` + peer 版本范围 | SUPPORT 全文 | ⑥:支持与不受支持清单、peer 范围及精确开发依赖成文;Node 20 在范围外(理由见 SUPPORT,`engines` 为准) | `peerDependencies`、`devDependencies` 与 `engines`(`package.json`);CI 矩阵(ci.yml) | 新 peer 版本仍需验证 |
|
|
53
|
+
| R23 | 根平面 `ctx.fs` 按坐标路由:发行版 UNC 由发行版内 agent 服务(inotify 或轮询 watch),盘符路径留在宿主;接替随发的 `fs-sandbox` 行 | README「Architecture」;ARCHITECTURE「The root-plane filesystem takeover」;CONFIGURATION `fs-routing` 行;root-fs-routing.md(设计) | ①②③⑤:路由判定与接替理由(写围栏在根平面无消费者)成文;`distro` 的 `auto`/`default`/pin 三态、每个 UNC 目标由自身 distro 服务、pin 下拒外来路径,以及 `distroCwd`/`restrictToDistro`/`sandbox`/`maskWindowsDrive`/`watchMaxDepth` 逐键成表,且自成一行、不与会话级行联动;`sandbox` 失败关闭成文 | `fs-routing.test.mjs`(纯谓词与路径助手)、`provider.test.mjs`(per-distro substrate/worldPath) | 类本体无单测(需 DSH peers 与实机);由组合测试与真机探针覆盖 |
|
|
54
|
+
| R24 | GUI 文件树与预览在发行版内服务:沿用随包 `workspace-files` 行(server/client 成对),经根级 `fs-routing` 读写 distro UNC;盘符 scope 交宿主 | README「Architecture」;ARCHITECTURE「The root-plane filesystem takeover」;CONFIGURATION `workspace-files` 行 | ①②③⑤:沿用官方 server/client,浏览器 `file` provider 不丢,预览可用;路由与宿主/发行版 scope 成文;容量键由官方行承载、可覆盖;较直连多 4–6 次往返及其取舍在 LIMITATIONS 成文 | `fs-routing.test.mjs`、组合测试(`workspace-files` 保持启用、接管行不存在) | — |
|
|
55
|
+
|
|
56
|
+
登记覆盖面:上表登记 README 与 docs/ 中对外成文的行为承诺(含随发的服务面)。
|
|
57
|
+
**有意未接线**的模块不设条目——`lib/file-reference-wsl.js`(`@` 补全的发行版侧
|
|
58
|
+
遍历)按 ARCHITECTURE 的说明 built but deliberately unwired,没有对外承诺可登记;
|
|
59
|
+
其单测仍留在 `test:unit` 与 `test:coverage` 清单内。
|
|
60
|
+
|
|
61
|
+
## 开放事项
|
|
62
|
+
|
|
63
|
+
登记时发现的、尚未构成需求条目的缺口。编号 OI-*,解决后在本表记归属。
|
|
64
|
+
|
|
65
|
+
| # | 事项 | 性质 | 出处 |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| OI-1 | 非功能无量化目标:冷启动上界、常驻 agent 内存上界、watch 通知延迟上界均无规定 | 决策待定(开发工具语境可辩护,企业语境缺口) | 本表 R20 残差 |
|
|
68
|
+
| OI-2 | 真机回归(协议/基座/沙箱的最高风险面)仅手动探针;CI runner 无 WSL distro | 环境受限决策,已如实记录 | ARCHITECTURE「Test layers」 |
|
|
69
|
+
| OI-3 | 默认翻转(substrate、协议 v3→v4)无灰度、无遥测;迁移安全押在 boot 拒绝与响亮错误上 | OSS 取舍,企业语境缺口 | CHANGELOG 0.3.0 / 0.7.3 |
|
|
70
|
+
| OI-4 | 端口轮询经共享 agent 使常驻进程永不闲置回收(LIMITATIONS 已记);工程修复=移出共享 agent 或改 one-shot | 工程项 | `lib/shell-env.js:79` |
|
|
71
|
+
| OI-5 | 发布后无目录 fsync,shell agent 忽略 `sync -f` 失败;机器崩溃可能丢失数据或目录项(见 LIMITATIONS) | 工程项 | `agent/wsl-agent.sh`、`agent/native/spike/src/main.rs` |
|
|
72
|
+
|
|
73
|
+
OI-7 已解决(2026-10-19):`test/fs-routing.test.mjs` 已进入 `test:unit` 与
|
|
74
|
+
`test:coverage` 两个清单;新增的 `test/distro-route.test.mjs` 也同步加入。
|
|
75
|
+
|
|
76
|
+
OI-1 至 OI-3 属流程决策而非文档补课;OI-4/OI-5 是可独立处置的工程项。
|
|
77
|
+
OI-6(工作区未提交三件套)已随 `6e6128a`(0.8.0)解决,自本表移除。
|