@tacrine_f/oh-my-dsh-omo-fork-chs 0.1.0 → 0.2.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 CHANGED
@@ -4,6 +4,185 @@ All notable changes to this project are documented in this file.
4
4
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ **What this is for.** `A5` checks that `files[]` *contains* every entry in `REQUIRED_FILES`, but no
10
+ assertion checked that those entries *resolve to anything*. **`A19`** closes that gap: for every
11
+ `files[]` entry that names a directory, the tool now requires at least one path under it that is
12
+ both tracked and present on disk.
13
+
14
+ **The hole, measured rather than argued.** With `"test/"` still listed in `files[]`, `git rm -r test`
15
+ was the silent state: the old tool exited **0** with verdict OK, `prepack` passed, `npm pack` yielded
16
+ **28** entries instead of 34, and `node --test` reported **0 tests at exit 0** — the package shipped
17
+ without its test suite and nothing went red. A plain `rm -r test` that leaves the index intact was
18
+ **already** red before this change, reached through `A14`'s machine-path scan reading a tracked path
19
+ that is no longer on disk (`cannot read test/check-package-negative.test.mjs: ENOENT`); that state
20
+ was never green. So in that second state `A19`'s contribution is not that it turns a green gate red,
21
+ but that the failure is now **about the missing directory** rather than about a missing file, and
22
+ that it keeps working if `A14`'s list of files it reads by name ever changes.
23
+
24
+ **What it does not prove.** It proves that at least one path under a `files[]`-named directory is
25
+ both tracked and present on disk. It does not prove the directory is non-empty beyond that, nor that
26
+ its contents match what `files[]` implies, and it does not cover a `files[]` entry naming a missing
27
+ **file** — the known files are covered elsewhere (`A4`/`A6` for the personas, `A17` for the two
28
+ copied modules, `A9`/`A12`/`A13`/`A15` for the licence documents and the patch).
29
+
30
+ **Counts.** The tool now runs **22** structural and license assertions rather than 21, and the test
31
+ suite totals **56** tests rather than 55.
32
+
33
+ ## [0.2.0] — 2026-10-30
34
+
35
+ **What this release is for.** The 9 subagent rows are migrated from the old
36
+ `persona: !!js readFileSync(...)` + `toolFilter` pattern to 9
37
+ `dsh-agent-preset` sub-presets (`omo-explore` through `omo-multimodal-looker`)
38
+ using `agentPreset`, which is the supported mechanism in cordis `^4.0.1`.
39
+ The duplicate `list-agents` subpath was removed, and atlas gained a
40
+ transport-failure reuse rule. The bundle is now verified on two 0.2.x builds
41
+ rather than one — `0.2.1-alpha.1` with the 0.1.x patch, `0.2.2-alpha.2` with
42
+ this patch.
43
+
44
+ **Requires DSH ≥ 0.2.2.** The 9 subagent rows now select their preset with
45
+ `agentPreset`, a field that only the 0.2.2 `dsh-tool-subagent` reads; 0.2.2 also
46
+ removed the `persona` and `toolFilter` fields the old rows used. On DSH 0.2.1 and
47
+ earlier the rows still mount, but `agentPreset` is accepted and then never read
48
+ (the schema merges unknown keys instead of rejecting them), so the child gets
49
+ **no persona and no tool restriction** and inherits the parent's full toolset: a
50
+ read-only child such as explore or oracle would silently gain write and
51
+ subagent-spawning tools. That is a silent privilege escalation, not a mount
52
+ failure. The declared peer range still admits older 0.2.x builds, so this is a
53
+ functional requirement documented here rather than a semver constraint.
54
+
55
+ No persona prose or orchestration doctrine changes. What changes is how each
56
+ subagent's tool set is expressed: the `toolFilter` deny lists are replaced by
57
+ per-preset plugin lists, and the patch grows from 540 to 946 lines because each
58
+ sub-preset repeats its `!!js readFileSync(...)` expression from the old
59
+ `persona:` field.
60
+
61
+ ### Changed
62
+
63
+ - **Cordis migration — `persona`/`toolFilter` → `agentPreset`.** The 9 subagent
64
+ rows (`tool-subagent-explore` through `tool-subagent-multimodal-looker`)
65
+ no longer carry a `persona:` field or a `toolFilter:` list. Instead, 9 new
66
+ `dsh-agent-preset` blocks are appended to the patch (`omo-explore` order 100
67
+ through `omo-multimodal-looker` order 108), each setting `dsh-persona`
68
+ `prefix:` to the same `!!js readFileSync(...)` expression. The `toolFilter`
69
+ was dropped: a preset's plugin list *is* its tool catalog, so the deny list
70
+ becomes structural. Three template groups (read-only A, writable B, vision C)
71
+ follow the same pattern as `preset-tri-*`. The `persona:` field is removed
72
+ from the 9 rows, and `agentPreset` on each row references the corresponding
73
+ sub-preset id. See Todo 2 in `notepads/handover-v0.2.0-upgrade/learnings.md`.
74
+ - **atlas.md: transport-failure reuse rule added.** A new section
75
+ `### 网络/提供商波动 → 复用同一 child,不冷启(MUST)` was inserted before the
76
+ existing `### 禁止静默冷启` ban, so atlas reuses the same child on provider
77
+ or network fluctuations instead of starting a cold replacement.
78
+
79
+ ### Fixed
80
+
81
+ - **Removed duplicate `dsh-tool-subagent-control/list-agents` row.** The root
82
+ `dsh-tool-subagent-control` entry already calls `registerListAgents(ctx)`, so
83
+ the second row would double-register `list_agents`/`send_message`/`interrupt_agent`.
84
+ Deleting it matches the upstream reference (`tri-agent`'s patch has exactly one
85
+ `tool-subagent-control` row).
86
+
87
+ ### The package check tool was updated for the new patch shape
88
+
89
+ `tools/check-package.mjs` A16 now expects 946 patch lines and 173 `- id:` rows
90
+ (instead of 540 and 40), and the `EXPECTED.version` moved to `0.2.0`.
91
+ `baseline/cordis.patch.yml` was re-derived, so `node tools/verify-patch.mjs`
92
+ reports `verdict: "IDENTICAL"` again.
93
+
94
+ ### Verification extended to dsh 0.2.2-alpha.2
95
+
96
+ 0.1.1 was verified on `0.2.1-alpha.1` — one 0.2.x build. This release was also
97
+ verified on `0.2.2-alpha.2` (the published DSH 0.2.2 alpha build) by a real
98
+ `--dump-config` run against a profile that registers this package as a bundle:
99
+ with no exemption present, the run exits 0, writes 0 bytes to stderr, and the
100
+ dump carries the preset with all 9 persona anchors and all 9 sub-presets. That
101
+ is still a claim about mount and anchor paths, not about persona bytes or preset
102
+ behaviour — no agent was invoked.
103
+
104
+ ## [0.1.1] — 2026-10-14
105
+
106
+ **What this release is for.** 0.1.0 declared peer ranges that stopped below dsh 0.2, so a dsh 0.2.x
107
+ host reported the bundle as incompatible, skipped it, and still exited 0 — a failure visible only on
108
+ stderr. **0.1.1 widens those ranges so the bundle mounts on dsh 0.2.x with no exemption**, which is
109
+ the change most consumers will care about. It also adds two checks to the package tool and corrects
110
+ several documentation statements. Nothing in the preset's behaviour changes: the preset id, its
111
+ `order`, the personas and the patch are the same as 0.1.0.
112
+
113
+ Two gates were added to `tools/check-package.mjs` after 0.1.0 was released. They close
114
+ gaps that the existing assertions could not see, and they change what the tool reports:
115
+ it now runs **21** structural and license assertions rather than 19. The test suite is
116
+ unchanged at 55 tests, because the new gates are asserted by the tool itself and by the
117
+ existing negative-path cases rather than by new test files.
118
+
119
+ ### Added
120
+
121
+ - A content-hash gate on `index.js` and `plan-aware-persona.mjs`: the tool asserts the
122
+ SHA256 of each against a frozen value. A byte count is not enough for these two,
123
+ because it is sensitive to length only — a swapped character, a changed identifier or
124
+ a reordered token leaves the length identical and the file different, which is exactly
125
+ the class of edit a formatter makes to a `.mjs`. Measured: flipping one byte of
126
+ `plan-aware-persona.mjs` leaves it at 3685 bytes and changes its hash.
127
+ - An anchor-resolution gate: every internal markdown anchor — a link whose target begins
128
+ with a `#` — in `README.md`, `README.zh.md`, `CHANGELOG.md` and `NOTICE.md` must
129
+ resolve to a heading slug in the same document,
130
+ using GitHub's own slug rule (lowercase; strip everything that is not a word
131
+ character, a hyphen or whitespace; keep CJK; spaces to hyphens; repeated headings
132
+ deduplicated with `-1`, `-2`). The rule was verified against `github-slugger` 2.0.0 on
133
+ all 38 headings of the four documents with 0 disagreements.
134
+
135
+ ### Fixed
136
+
137
+ - `README.zh.md`'s two badge links pointed at `#license` and `#peer-model` while the
138
+ document's headings are `## 许可` and `## Peer 模型`, so both links landed nowhere.
139
+ The links now match the headings. The headings were not renamed: they are the
140
+ document's structure, and the English document's equivalent links were already
141
+ correct.
142
+ - The `.gitattributes` scope entry was named in `NOTICE.md`'s mit-scope block and in the
143
+ tool's expected scope set, but missing from the anchor list that resolves each entry
144
+ against the block claiming it. It is now anchored like its ten siblings.
145
+ - `check-package.mjs`'s untracked-file failure message named the same directory once per
146
+ spelling when `files[]` listed one directory under two spellings, so a reader saw
147
+ `test/, test/` and had to work out that these are one directory and not two. Each
148
+ offending directory is now named exactly once.
149
+
150
+ ### The peer range now covers dsh 0.2.x — verified on one 0.2.x build
151
+
152
+ The 24 `@deepseek-ai/dsh-*` peer ranges were widened from `>=0.1.7-rc.2 <0.2.0` to:
153
+
154
+ ```
155
+ >=0.1.7-rc.2 <0.2.0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0
156
+ ```
157
+
158
+ The first clause is the range inherited from the upstream fork, so the previously supported line is
159
+ unchanged; the second and third add the 0.2 line. `@deepseek-ai/cordis` stays at `^4.0.1`. The
160
+ package `version` moves from `0.1.0` to `0.1.1` in this release, which is what carries the widened
161
+ ranges to consumers.
162
+
163
+ **Why the change.** The host decides whether a profile bundle loads with a semver range check over
164
+ the peers named `@deepseek-ai/dsh` or `@deepseek-ai/dsh-*`, evaluated with prereleases included
165
+ (`{ includePrerelease: true }`). The old range rejects `0.2.1-alpha.1`, so on that runtime the host
166
+ reported the plugin as incompatible, skipped the bundle, and still exited 0 — a silent failure
167
+ visible only on stderr. The widened range accepts that runtime, so no exemption is needed for it.
168
+
169
+ **What was verified, by experiment rather than by reading the range back.** On `0.2.1-alpha.1` —
170
+ the only 0.2.x build available, so this is one build and not a general claim — with the working tree
171
+ mounted as a local bundle and **no exemption present in the profile**, a `--dump-config` run exits
172
+ 0, writes **0 bytes to stderr**, and carries the preset with `order: 11` and all **nine** persona
173
+ anchors, each resolving to a real file inside the mounted package. The same package with the old
174
+ ranges produces 1884 bytes of stderr and no anchors, so the widening is what removed the skip.
175
+
176
+ **What that does not prove.** It proves the anchor *paths* resolve, not that a persona's *bytes* are
177
+ intact — a persona that still existed but had been truncated would pass the same check. It proves
178
+ structural facts, not that the preset does anything, because no agent is invoked. And it is one
179
+ build.
180
+
181
+ **The re-entry condition is `0.3.0-alpha.1`.** The widened range rejects it, so a future runtime in
182
+ that line is skipped again, with the same incompatibility warning on stderr and the same exit 0.
183
+ The exemption remains documented and remains needed for that case and for the published `0.1.0`,
184
+ whose manifest still carries the old narrower range.
185
+
7
186
  ## [0.1.0] — 2026-10-11
8
187
 
9
188
  0.1.0 is the first release of this repository; no earlier version was published. It carries the
@@ -103,7 +282,10 @@ SUL-1.0 is not an SPDX identifier and this package is dual-licensed. `files[]` s
103
282
  with `dsh plugin allow-version "<pkg>@<version>" --dsh-version <version> --accept-risk`, which is
104
283
  the host's own escape hatch and carries the risk the host warns about. On a runtime inside the
105
284
  declared range the preset mounts and composes correctly, including all nine persona anchors. This
106
- is inherited from the upstream fork and is not specific to this localization.
285
+ is inherited from the upstream fork and is not specific to this localization. **Superseded — see
286
+ the Unreleased section "The peer range now covers dsh 0.2.x": the 24 peer ranges were widened
287
+ after this section was released, so the sentence above describes 0.1.0 as published and no longer
288
+ describes the current manifest.**
107
289
  - `exports` keeps `"./package.json"`, because the nine persona anchors locate the package directory
108
290
  through `createRequire(baseUrl).resolve('<pkg>/package.json')`. Without that export they fail with
109
291
  `ERR_PACKAGE_PATH_NOT_EXPORTED` at mount time.
@@ -118,4 +300,7 @@ SUL-1.0 is not an SPDX identifier and this package is dual-licensed. `files[]` s
118
300
  repositories with separate packages, preset ids and scope mappings, and neither affects the other.
119
301
  - A missing or empty persona file fails the mount by design, naming the file in the error.
120
302
 
303
+ [Unreleased]: https://github.com/Tacrine/oh-my-dsh-omo-fork-chs/compare/v0.2.0...HEAD
304
+ [0.2.0]: https://github.com/Tacrine/oh-my-dsh-omo-fork-chs/releases/tag/v0.2.0
305
+ [0.1.1]: https://github.com/Tacrine/oh-my-dsh-omo-fork-chs/releases/tag/v0.1.1
121
306
  [0.1.0]: https://github.com/Tacrine/oh-my-dsh-omo-fork-chs/releases/tag/v0.1.0
package/README.md CHANGED
@@ -165,7 +165,8 @@ error that names the file is far easier to act on than an agent that quietly los
165
165
 
166
166
  Every `@deepseek-ai/*` package the patch mounts is declared as a **`peerDependency`**, never as a
167
167
  regular `dependency`. DSH provides them; the bundle must not install its own copies. Peer ranges are
168
- pinned as `>=0.1.7-rc.2 <0.2.0` (and `@deepseek-ai/cordis` as `^4.0.1`). The package declares 25
168
+ declared as `>=0.1.7-rc.2 <0.2.0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`, which keeps the
169
+ 0.1.7 line and adds the 0.2 line (and `@deepseek-ai/cordis` as `^4.0.1`). The package declares 25
169
170
  peers and **no** runtime dependencies and **no** dev dependencies, so nothing has to be installed
170
171
  for the tests or for the zero-dependency part of the check chain.
171
172
 
@@ -179,7 +180,7 @@ Everything below runs from the repository root with **no install**, except `chec
179
180
  a runtime and is marked as such.
180
181
 
181
182
  ```powershell
182
- # 1. The test suite. Zero dependencies. 55 tests.
183
+ # 1. The test suite. Zero dependencies. 56 tests.
183
184
  npm run test
184
185
 
185
186
  # 2. The check chain. Zero dependencies, no runtime needed.
@@ -202,10 +203,10 @@ What each one proves:
202
203
 
203
204
  - **`npm run test`** runs the `node:test` suite: the three forward rewrites, the inverse rewrites
204
205
  and their round trip, the argument parsers, the machine-path pattern from both sides, the
205
- zero-byte guard, and the package check's negative paths. It is 55 tests and it needs nothing
206
+ zero-byte guard, and the package check's negative paths. It is 56 tests and it needs nothing
206
207
  installed.
207
208
  - **`npm run check`** is `node tools/check-package.mjs && node tools/verify-patch.mjs`. The first
208
- runs 19 structural and license assertions (manifest identity, the four `exports`, the single
209
+ runs 22 structural and license assertions (manifest identity, the four `exports`, the single
209
210
  self-reference row, the nine persona anchors and their files, the `files[]` coverage, the eleven
210
211
  persona byte counts, the license pointers, the three license documents, the paths that must never
211
212
  ship, the untracked-file check over every directory `files[]` lists and the untracked root files
@@ -213,7 +214,9 @@ What each one proves:
213
214
  when one is supplied, the modification-notice claims, the license scope mapping and the per-entry
214
215
  anchors
215
216
  that pin each scope block to the content it claims, the machine-path
216
- scan and the classes that govern where the pre-port package name may appear, and the patch's
217
+ scan and the classes that govern where the pre-port package name may appear, the SHA256 of the
218
+ two modules the package copies out of this repository, the internal markdown anchors of every
219
+ document that carries one, and the patch's
217
220
  shape). The second proves the published patch
218
221
  still equals what the three documented rewrites compute from the frozen baseline, and reports
219
222
  `verdict: "IDENTICAL"` with 11 rewrite sites. Both are **zero-dependency**, so they pass in a
@@ -248,6 +251,16 @@ What each one proves:
248
251
  > mapping check that reports success for work it never did is worse than no check at all. The
249
252
  > published package includes the tools and the test suite so the chain can be re-run from a clone.
250
253
 
254
+ > **Counting a document's lines in PowerShell: `Measure-Object -Line` counts non-empty lines
255
+ > only.** `(Get-Content README.md | Measure-Object -Line).Lines` reports **311** for this file,
256
+ > while `(Get-Content README.md).Count` reports **374** — the same file, two readings, and the
257
+ > difference is 63 blank lines that the first command never saw. Nothing in the command's name or
258
+ > output says so, so a length check built on it silently under-counts any file with blank lines in
259
+ > it. Use `.Count`, or `[IO.File]::ReadAllLines(path).Count`, when you want the raw line count. The
260
+ > same trap has already produced wrong readings of a plan file in this repository twice, from two
261
+ > separate contributors, because the two numbers look equally plausible when you have not measured
262
+ > both.
263
+
251
264
  ## License
252
265
 
253
266
  This repository is **dual-licensed**, and the two licenses are not alternatives you may choose
@@ -291,16 +304,41 @@ Upstream names and trademarks belong to their owners.
291
304
 
292
305
  ## Known issues
293
306
 
294
- - **The declared peer range excludes dsh 0.2.0 and above, and the host skips the bundle there.** The
295
- peers are declared as `>=0.1.7-rc.2 <0.2.0`, matching the upstream fork. On a dsh at 0.2.0 or
296
- above, the host reports the plugin as incompatible, **skips the bundle**, and the command **still
297
- exits 0**, so the failure is silent unless you read stderr: the preset never appears in the dump.
298
- On such a version you must either run a dsh inside the declared range, or grant the exact-version
299
- exemption with `dsh plugin allow-version "<pkg>@<version>" --dsh-version <version> --accept-risk`.
300
- That exemption is the host's own escape hatch and carries the risk the host itself warns about, so
301
- it is a deliberate acceptance of risk rather than a supported configuration. This behaviour is
302
- inherited from the upstream fork and is not specific to this localization. On a runtime inside the
303
- declared range the package mounts and composes correctly, including all nine persona anchors.
307
+ - **This version requires DSH ≥ 0.2.2.** The 0.2.0 patch selects each of the 9
308
+ subagent presets with `agentPreset`, a field that only the 0.2.2
309
+ `dsh-tool-subagent` reads; 0.2.2 also removed the `persona` and `toolFilter`
310
+ fields the old rows used. On DSH 0.2.1 and earlier the rows still mount, but
311
+ `agentPreset` is accepted and then never read (the schema merges unknown keys
312
+ instead of rejecting them), so the child gets **no persona and no tool
313
+ restriction** and inherits the parent's full toolset: a read-only child such as
314
+ explore or oracle would silently gain write and subagent-spawning tools. That is
315
+ a silent privilege escalation, not a mount failure. The declared peer range
316
+ below still admits older 0.2.x builds, so this is a functional requirement
317
+ rather than a semver constraint. Verified on `0.2.2-alpha.2`; do not run this
318
+ version on DSH older than 0.2.2.
319
+ - **The declared peer range covers the 0.1.7 line and the 0.2 line. The range check was verified on two 0.2.x builds, but `0.2.1-alpha.1` only with the 0.1.x patch.** The 24
320
+ `@deepseek-ai/dsh-*` peers are declared as
321
+ `>=0.1.7-rc.2 <0.2.0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`, which keeps the range this
322
+ fork inherited from upstream and adds the 0.2 line. The host decides compatibility with a semver
323
+ range check over those peers, evaluating prereleases, so the range accepts `0.2.0`,
324
+ `0.2.1-alpha.1` and the later prerelease `0.2.2-beta`, and rejects `0.3.0-alpha.1`.
325
+ **Verified by experiment on `0.2.1-alpha.1` (0.1.x patch only) and `0.2.2-alpha.2` (this patch)**: with
326
+ no exemption present in the profile, a config dump of this package exits 0, writes **0 bytes to
327
+ stderr**, and carries the preset with all nine persona anchors; the `0.2.2-alpha.2` run was against
328
+ a profile that registers this package as a bundle. That is a claim about the mount and the anchor
329
+ paths, not about the personas' bytes and not about the preset's behaviour: no agent was invoked,
330
+ and a persona that still existed but had been truncated would pass the same check.
331
+ **`0.3.0-alpha.1` is the re-entry condition**: a future runtime in that range is rejected again,
332
+ with the same incompatibility warning on stderr and the same exit 0, so the failure stays silent
333
+ unless you read stderr. On such a version you must either run a dsh inside the declared range, or
334
+ grant the exact-version exemption with
335
+ `dsh plugin allow-version "<pkg>@<version>" --dsh-version <version> --accept-risk`. That exemption
336
+ is the host's own escape hatch and carries the risk the host itself warns about, so it is a
337
+ deliberate acceptance of risk rather than a supported configuration. **It is still needed for cases
338
+ this widening does not cover**: the published `0.1.0` on npm carries the old narrower range, and any
339
+ future 0.3.x runtime will need it. `@deepseek-ai/cordis` is declared at `^4.0.1` as well, but the
340
+ host never tests it — it only evaluates peers named `@deepseek-ai/dsh` or `@deepseek-ai/dsh-*` —
341
+ so that entry is not a compatibility constraint the host enforces.
304
342
  - **`baseline/` proves reproducibility, not correctness.** The baseline is a frozen snapshot of the
305
343
  pre-port patch, committed so the round trip can be checked anywhere. It is byte-identical to the
306
344
  source patch, and the derivation proves the port is **reproducible**: the published patch and the
package/README.zh.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # oh-my-dsh-omo-fork-chs
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@tacrine_f/oh-my-dsh-omo-fork-chs)](https://www.npmjs.com/package/@tacrine_f/oh-my-dsh-omo-fork-chs)
4
- [![license: SUL-1.0 (content) + MIT (packaging)](https://img.shields.io/badge/license-SUL--1.0_(content)_%2B_MIT_(packaging)-orange)](#license)
5
- [![node](https://img.shields.io/badge/node-%5E22.19.0%20%7C%7C%20%3E%3D24.0.0-blue)](#peer-model)
4
+ [![license: SUL-1.0 (content) + MIT (packaging)](https://img.shields.io/badge/license-SUL--1.0_(content)_%2B_MIT_(packaging)-orange)](#许可)
5
+ [![node](https://img.shields.io/badge/node-%5E22.19.0%20%7C%7C%20%3E%3D24.0.0-blue)](#peer-模型)
6
6
 
7
7
  `tri-agent` agent preset 的**简体中文非官方 fork**,面向
8
8
  [DeepSeek Harness](https://www.npmjs.com/package/@deepseek-ai/dsh) 打包为可发布的 Cordis bundle。
@@ -153,8 +153,9 @@ plan-aware-persona: persona "file:///.../personas/atlas.md" is empty
153
153
  ## Peer 模型
154
154
 
155
155
  patch 挂载的每个 `@deepseek-ai/*` 包都声明为 **`peerDependency`**,而不是普通 `dependency`。它们由
156
- DSH 提供;bundle 不得安装自己的副本。peer 范围固定为 `>=0.1.7-rc.2 <0.2.0`(`@deepseek-ai/cordis`
157
- 为 `^4.0.1`)。本包声明 25 条 peer,且**没有**运行期依赖、**没有**开发依赖,因此测试与检查链中零依赖
156
+ DSH 提供;bundle 不得安装自己的副本。peer 范围声明为
157
+ `>=0.1.7-rc.2 <0.2.0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`,既保留 0.1.7 线,又加入
158
+ 0.2 线(`@deepseek-ai/cordis` 为 `^4.0.1`)。本包声明 25 条 peer,且**没有**运行期依赖、**没有**开发依赖,因此测试与检查链中零依赖
158
159
  的那部分都不需要安装任何东西。
159
160
 
160
161
  DSH profile 的 `.npmrc` 设置了 `auto-install-peers=false`,所以这些 peer 是**纯声明式**的:pnpm 不会
@@ -165,7 +166,7 @@ DSH profile 的 `.npmrc` 设置了 `auto-install-peers=false`,所以这些 pee
165
166
  下面全部在仓库根目录运行,且**无需安装**,只有 `check:full` 例外,它需要 runtime,并已如此标注。
166
167
 
167
168
  ```powershell
168
- # 1. 测试套件。零依赖。55 个测试。
169
+ # 1. 测试套件。零依赖。56 个测试。
169
170
  npm run test
170
171
 
171
172
  # 2. 检查链。零依赖,不需要 runtime。
@@ -187,14 +188,15 @@ npm run port -- --src <dir holding cordis.patch.yml>
187
188
  每一条各自证明什么:
188
189
 
189
190
  - **`npm run test`** 运行 `node:test` 套件:三组正向改写、反向改写及其往返、参数解析器、从两侧检验
190
- 机器路径模式、零字节守卫,以及包检查的失败路径。共 55 个测试,不需要安装任何东西。
191
- - **`npm run check`** 是 `node tools/check-package.mjs && node tools/verify-patch.mjs`。前者运行 19 条
191
+ 机器路径模式、零字节守卫,以及包检查的失败路径。共 56 个测试,不需要安装任何东西。
192
+ - **`npm run check`** 是 `node tools/check-package.mjs && node tools/verify-patch.mjs`。前者运行 22 条
192
193
  结构与许可断言(manifest 身份、四个 `exports`、唯一一条自引用 row、九条 persona 锚点及其文件、
193
194
  `files[]` 覆盖、11 个 persona 的字节数、许可指针、三份许可文档、绝不允许进入 tarball 的路径,
194
195
  对 `files[]` 所列每个目录的未跟踪文件检查,以及 npm 无论 `files[]` 如何都会自动收录的根目录文件、
195
196
  提供了上游指纹时的比对、
196
197
  修改声明的各项主张、许可范围映射及逐条把每个范围块钉到其所声明内容的锚点、机器路径扫描、
197
- 约束移植前包名出现位置的类,以及 patch 的形状)。
198
+ 约束移植前包名出现位置的类、本仓库向消费者复制的两个模块的 SHA256、
199
+ 每份带内部锚点的文档中锚点是否都能解析到标题,以及 patch 的形状)。
198
200
  后者证明已发布的 patch 仍然等于三项已记录改写从冻结 baseline 算出的结果,并报告
199
201
  `verdict: "IDENTICAL"` 与 11 处改写点。两者都**零依赖**,因此在干净克隆里、无需安装即可通过。
200
202
  - **`npm run check:full`** 就是单独运行 `node tools/verify-patch.mjs`。当 `DSH_RUNTIME` 指向一个包含
@@ -255,14 +257,33 @@ bundle patch 表达式的**逐字片段**,以便生成和校验该 patch。那
255
257
 
256
258
  ## 已知问题
257
259
 
258
- - **声明的 peer 范围不含 dsh 0.2.0 及以上,宿主会在这类版本上跳过本 bundle。** peer 声明为
259
- `>=0.1.7-rc.2 <0.2.0`,与上游 fork 一致。在 0.2.0 或更高的 dsh 上,宿主会把该插件判为不兼容、
260
- **跳过该 bundle**,而命令**仍然以 0 退出**,所以除非去看 stderr,这个失败是静默的:preset 根本不会
261
- 出现在 dump 里。在这类版本上,你必须要么使用落在声明范围内的 dsh,要么用
260
+ - **本版本要求 DSH ≥ 0.2.2。** 0.2.0 patch 用 `agentPreset` 为 9 个子代理各选一个 preset,
261
+ 而这个字段只有 0.2.2 的 `dsh-tool-subagent` 才会读取;0.2.2 同时移除了旧行使用的 `persona`
262
+ 与 `toolFilter` 字段。在 DSH 0.2.1 及更早版本上,这些行**照常挂载**,但 `agentPreset` 只是被
263
+ 接受、随后从不被读取(schema 会合并未知键而不是拒绝它),于是子代理**既没有 persona,也没有
264
+ 任何工具限制**,直接继承父代理的全部工具集:像 explore 或 oracle 这样的只读子代理会静默获得
265
+ 写文件与派生子代理的能力。这是**静默提权,不是挂载失败**。下面声明的 peer 范围仍然放行更旧的
266
+ 0.2.x 构建,所以这是一条功能性要求,而不是 semver 约束。已于 `0.2.2-alpha.2` 验证;请不要在
267
+ 低于 0.2.2 的 DSH 上运行本版本。
268
+ - **声明的 peer 范围覆盖 0.1.7 线与 0.2 线。范围检查在两个 0.2.x 构建上验证过,但 `0.2.1-alpha.1` 只验证过 0.1.x 的 patch。** 24 个
269
+ `@deepseek-ai/dsh-*` peer 声明为
270
+ `>=0.1.7-rc.2 <0.2.0 || >=0.2.0-0 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0`,既保留本 fork 从上游继承的
271
+ 范围,又加入 0.2 线。宿主用一个 semver 范围检查来判定这些 peer 是否兼容,并且会把预发布版本纳入比较,
272
+ 因此该范围接受 `0.2.0`、`0.2.1-alpha.1` 与更晚的预发布版本 `0.2.2-beta`,而拒绝 `0.3.0-alpha.1`。
273
+ **已用实验在 `0.2.1-alpha.1`(仅 0.1.x 的 patch)与 `0.2.2-alpha.2`(本 patch)上验证**:在 profile 中不存在任何
274
+ 豁免的情况下,对本包做 config dump 会以 0 退出、向 **stderr 写入 0 字节**,并在 dump 中带上该 preset 与
275
+ 全部九条 persona 锚点;其中 `0.2.2-alpha.2` 这次运行针对的是把本包注册为 bundle 的 profile。这证明的是
276
+ 挂载与锚点路径,而不是 persona 的字节内容,也不是 preset 的行为:本次验证没有调用任何 agent,
277
+ 一个仍然存在但已被截断的 persona 同样会通过这项检查。
278
+ **`0.3.0-alpha.1` 是重新触发的条件**:将来的运行时一旦落在该范围内就会再次被拒,stderr 上出现同样的
279
+ 不兼容警告,退出码同样是 0,所以除非去看 stderr,这个失败仍然是静默的。在这类版本上,你必须要么使用
280
+ 落在声明范围内的 dsh,要么用
262
281
  `dsh plugin allow-version "<pkg>@<version>" --dsh-version <version> --accept-risk` 授予精确版本
263
282
  豁免。该豁免是宿主自带的逃生舱,并带有宿主自己警告过的风险,因此它是对风险的刻意接受,而不是受支持的
264
- 配置。这一行为继承自上游 fork,并非本地化引入。在声明范围内的运行时上,本包能正确挂载并完成装配,包括
265
- 全部九条 persona 锚点。
283
+ 配置。**对于本次放宽没有覆盖的情形,它仍然是必需的**:npm 上已发布的 `0.1.0` 携带的是旧的、更窄的范围,
284
+ 而将来任何 0.3.x 运行时也都需要它。`@deepseek-ai/cordis` 同样声明为 `^4.0.1`,但宿主从不检查它——
285
+ 宿主只评估名为 `@deepseek-ai/dsh` 或以 `@deepseek-ai/dsh-` 开头的 peer——所以那一条并不是宿主会执行的
286
+ 兼容性约束。
266
287
  - **`baseline/` 证明的是可复现,而不是正确。** baseline 是移植前 patch 的冻结快照,提交它是为了让往返
267
288
  校验在任何地方都能跑。它与源 patch 逐字节一致,而这次推导证明移植是**可复现**的:已发布的 patch 与
268
289
  baseline 之间恰好由三项已记录改写相连,别无其他。它**不**证明内容正确。如果源 patch 本身是错的,
@@ -11,15 +11,16 @@ that this fork vendors from. It was captured by reversing the three port rewrite
11
11
  `node tools/derive-baseline.mjs`, which reads this repository's published `cordis.patch.yml`
12
12
  and applies the inverse of the rules in `tools/lib/rewrites.mjs`.
13
13
 
14
- - Source: the chs bundle's `cordis.patch.yml`
15
- - Source byte count: 26903
16
- - Source line count: 540
17
- - Source SHA256: `BD9619038AFB3817C4EC8599B6A67EAC559A6193FFF53C820F1895E26312514F`
18
-
19
- The baseline file in this directory is **byte-identical** to that source: same 26903 bytes,
20
- same 540 lines, same SHA256. It carries no header, no provenance comment and no added blank
21
- line, because any of those would break both the byte-identity assertion and the round trip.
22
- This sidecar exists precisely so that nothing has to be added to the file itself.
14
+ - Source: the repository's own `cordis.patch.yml` (the published agentPreset form)
15
+ - Source byte count: 42649
16
+ - Source line count: 946
17
+ - Source SHA256: `06CA0E349E975DA6C948CE823D648DA1D2F370149F61D63BE9964692ACD7E829`
18
+
19
+ The baseline file in this directory is the **pre-port** form: 41743 bytes, 946 lines,
20
+ SHA256 `E086ED15B390DF293A46B6F901103B9F84839C0F4C2B5E562537F34A2644830C`. It differs from the
21
+ source because the three port rewrites transform the package reference and persona-file paths.
22
+ Re-applying those rewrites (`node tools/port-patch.mjs --src baseline`) reproduces the published
23
+ patch byte for byte, which is what the verification chain proves.
23
24
 
24
25
  ## Upstream provenance
25
26