dsh-dupguard 1.1.4 → 1.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 +27 -0
- package/README.md +50 -32
- package/cordis.patch.yml +6 -0
- package/lib/index.js +3 -3
- package/package.json +9 -2
- package/plugin/host.js +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
本文件遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [1.2.0] - 2026-09-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- 适配 DSH 0.1.2 的 bundle 约定:本包自带补丁层 `cordis.patch.yml` 并声明
|
|
10
|
+
`dsh.bundle.patch`,安装只需一条命令 `dsh plugin --profile web add dsh-dupguard`
|
|
11
|
+
(`dsh plugin` 会自动把声明了 `dsh.bundle` 的依赖加入 `dsh.profile.bundles`,
|
|
12
|
+
DSH 按层应用补丁插入宿主行 `{ id: dupguard, name: dsh-dupguard }`,无需手改 YAML);
|
|
13
|
+
- package.json 增加 `dsh.compatibility`(`dsh >= 0.1.1-rc.1`)。
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- 与 DSH 0.1.2-rc.1 逐项核对:`llm/stream` 瀑布事件与 `StreamChunk` 协议、`settings.register`
|
|
18
|
+
(`base` 选项)、客户端 `settingsScope.bind` / `decode(view.value)` / `describe`、
|
|
19
|
+
`settings.section` 槽位契约、`--dsw-*` 主题变量均未变化,插件行为无需改动;
|
|
20
|
+
- standing-mount 缺陷在 0.1.2-rc.1 仍未修复(上游保留 reclaim 代际的 TODO),
|
|
21
|
+
兼容补丁继续默认开启;
|
|
22
|
+
- README 安装章节改为以 bundle 方式为主、手工补丁层为辅,并说明两者不可同时使用
|
|
23
|
+
(重复 entry id 会抛 `duplicate loader entry id: dupguard`)。
|
|
24
|
+
|
|
25
|
+
## [1.1.5] - 2026-09-02
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- 明确不支持 Node 18(与 DSH 一致):`engines` 提升为 `>=20`,CI 矩阵调整为
|
|
30
|
+
Node 20/22/24,README 同步说明。
|
|
31
|
+
|
|
5
32
|
## [1.1.4] - 2026-09-02
|
|
6
33
|
|
|
7
34
|
### Fixed
|
package/README.md
CHANGED
|
@@ -49,13 +49,24 @@ Paste the entire content of [`plugin/host.js`](plugin/host.js) as `code.host` in
|
|
|
49
49
|
|
|
50
50
|
插件已发布到 npm:[`dsh-dupguard`](https://www.npmjs.com/package/dsh-dupguard)。
|
|
51
51
|
|
|
52
|
-
**1.
|
|
52
|
+
**1. 安装(DSH ≥ 0.1.2-rc.1,一条命令)**:
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
|
|
55
|
+
dsh plugin --profile web add dsh-dupguard
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
本包自带 bundle 补丁层(`dsh.bundle.patch` → [`cordis.patch.yml`](cordis.patch.yml)):
|
|
59
|
+
`dsh plugin` 把参数转发给 profile 目录下的 pnpm,安装后自动把声明了 `dsh.bundle` 的依赖
|
|
60
|
+
加入 `dsh.profile.bundles`;DSH 按 bundles 顺序应用各层补丁,本插件的层插入宿主行
|
|
61
|
+
`{ id: dupguard, name: dsh-dupguard }`。**无需手改任何 YAML。**
|
|
62
|
+
|
|
63
|
+
- 验证:`dsh --profile web --dump-config` 末尾应出现 `dupguard` 行;loader 日志出现
|
|
64
|
+
`apply plugin dupguard`。
|
|
65
|
+
- 升级:`dsh plugin --profile web update dsh-dupguard`;
|
|
66
|
+
卸载:`dsh plugin --profile web remove dsh-dupguard`(依赖与 bundles 层一并移除)。
|
|
67
|
+
|
|
68
|
+
**2. 手工补丁层(旧版 DSH 或不想加入 bundles 时仍受支持)**:在 profile 的用户补丁层
|
|
69
|
+
`cordis.patch.yml` 自行插入同一行:
|
|
59
70
|
|
|
60
71
|
```yaml
|
|
61
72
|
# $DSH_HOME/profiles/web/cordis.patch.yml
|
|
@@ -64,33 +75,36 @@ pnpm add dsh-dupguard # 或 npm install dsh-dupguard
|
|
|
64
75
|
name: dsh-dupguard
|
|
65
76
|
```
|
|
66
77
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- 验证:`dsh --profile web --dump-config` 末尾应出现 `dupguard` 行;loader 日志会出现
|
|
70
|
-
`apply plugin dupguard`。
|
|
71
|
-
- **撤销**:删掉该 `insert` 项即可热卸载。
|
|
78
|
+
用户补丁层在 bundle 层之后应用;运行中的 DSH 通过 `watchUserPatches` **热重载**它——
|
|
79
|
+
保存即生效,无需重启,加载失败会事务性回滚。
|
|
72
80
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
`pnpm add dsh-dupguard`,再把 `cordis.patch.yml` 中该行的 `name` 改为 `dsh-dupguard`。
|
|
81
|
+
⚠️ 两种方式**不要同时使用**:loader 对重复 entry id 直接抛
|
|
82
|
+
`duplicate loader entry id: dupguard`。从手工方式切换到 bundle 方式时,请删除手工 `insert` 项。
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
**本地开发**:未发布/调试时,`name` 也可直接用 `file:` URL 指向仓库内的
|
|
78
85
|
[`lib/index.js`](lib/index.js)(CJS 导出 `{ name, apply }`,与 loader 的
|
|
79
86
|
`unwrapExports` 兼容,零构建)。
|
|
80
87
|
|
|
81
|
-
The plugin is published on npm as [`dsh-dupguard`](https://www.npmjs.com/package/dsh-dupguard)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
`
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
The plugin is published on npm as [`dsh-dupguard`](https://www.npmjs.com/package/dsh-dupguard)
|
|
89
|
+
and ships its own bundle patch layer (`dsh.bundle.patch` → [`cordis.patch.yml`](cordis.patch.yml)).
|
|
90
|
+
Install it with one command (DSH ≥ 0.1.2-rc.1):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
dsh plugin --profile web add dsh-dupguard
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`dsh plugin` forwards its arguments to pnpm in the profile directory and appends any dependency
|
|
97
|
+
declaring `dsh.bundle` to `dsh.profile.bundles`; DSH then applies each bundle layer's patch in
|
|
98
|
+
order, and this plugin's layer inserts the host row `{ id: dupguard, name: dsh-dupguard }`. No YAML
|
|
99
|
+
editing needed. Verify with `dsh --profile web --dump-config` or the loader log line
|
|
100
|
+
`apply plugin dupguard`; upgrade with `dsh plugin --profile web update dsh-dupguard` and uninstall
|
|
101
|
+
with `dsh plugin --profile web remove dsh-dupguard`.
|
|
102
|
+
|
|
103
|
+
**Manual layer (still supported)**: without a bundles entry, insert the same row into the profile's
|
|
104
|
+
user patch layer `cordis.patch.yml`; the running DSH hot-reloads that file (`watchUserPatches`) with
|
|
105
|
+
a transactional rollback on failure. Do **not** combine both — the loader throws
|
|
106
|
+
`duplicate loader entry id: dupguard`. The `file:` URL form also remains handy for local development
|
|
107
|
+
against [`lib/index.js`](lib/index.js) (CJS, `module.exports = { name, apply }`, compatible with the
|
|
94
108
|
loader's `unwrapExports`, no build step).
|
|
95
109
|
|
|
96
110
|
---
|
|
@@ -184,7 +198,8 @@ default), Markdown table separator rows and horizontal rules (whitelisted by def
|
|
|
184
198
|
├── tests/
|
|
185
199
|
│ ├── detector.test.js # 端到端测试:双入口防漂移 + reasoning 开关 + settings 集成
|
|
186
200
|
│ └── experiment-cancel.mjs # 诊断实验(不进 CI):验证截停不阻塞于底层流取消
|
|
187
|
-
├── .github/workflows/ci.yml # GitHub Actions:Node
|
|
201
|
+
├── .github/workflows/ci.yml # GitHub Actions:Node 20/22/24
|
|
202
|
+
├── cordis.patch.yml # bundle 补丁层(dsh.bundle.patch:插入宿主行)
|
|
188
203
|
├── package.json
|
|
189
204
|
├── CHANGELOG.md
|
|
190
205
|
├── LICENSE # MIT
|
|
@@ -199,11 +214,11 @@ node tests/detector.test.js # 或 npm test
|
|
|
199
214
|
|
|
200
215
|
同一套 15 项用例分别驱动两个入口(`plugin/host.js` 经 `new Function` 求值、`lib/index.js` 经
|
|
201
216
|
`require` 加载),覆盖:透传完整性、各类复读形态、阈值边界、协议闭合、上游 `return()` 调用、
|
|
202
|
-
默认不检测 reasoning/工具参数、未闭合工具调用块的闭合、多次调用状态隔离等。CI 在 Node
|
|
203
|
-
|
|
217
|
+
默认不检测 reasoning/工具参数、未闭合工具调用块的闭合、多次调用状态隔离等。CI 在 Node 20/22/24
|
|
218
|
+
上运行(与 DSH 一致,不支持 Node 18)。
|
|
204
219
|
|
|
205
220
|
The same 15-test suite drives both entries, guarding against drift between the two forms. CI runs on
|
|
206
|
-
Node
|
|
221
|
+
Node 20/22/24 (matching DSH; Node 18 is not supported).
|
|
207
222
|
|
|
208
223
|
---
|
|
209
224
|
|
|
@@ -213,7 +228,7 @@ Node 18/20/22.
|
|
|
213
228
|
- 服务端停止依赖适配器在流关闭时中止底层请求的语义(已验证 `dsh-llm-deepseek`;自定义适配器需自查)。
|
|
214
229
|
- 阈值语义为 `>= threshold`:第 10 次重复出现时即停止。
|
|
215
230
|
|
|
216
|
-
### DSH 运行期间编辑 preset 后的 standing-mount 冲突(DSH ≤ 0.1.
|
|
231
|
+
### DSH 运行期间编辑 preset 后的 standing-mount 冲突(DSH ≤ 0.1.2-rc.1 缺陷,本插件已内置补丁)
|
|
217
232
|
|
|
218
233
|
**现象**:对某个会话执行模型选择等操作时报
|
|
219
234
|
`resume failed ... preset ... failed to mount ... Host Cordis inspect provider "Service" is already registered`,
|
|
@@ -229,7 +244,9 @@ while the process lives")。`tool-cordis` 在每次挂载时向**进程全局*
|
|
|
229
244
|
**本插件的修复(默认开启)**:`apply` 时把 `cordisInspect.register` **幂等化**——同 id 已有注册时
|
|
230
245
|
共享既有注册并返回 no-op disposer,多代并存不再冲突。补丁进程内常驻(卸载本插件后仍生效,
|
|
231
246
|
重启后由本插件重新安装;HMR 重载不会叠加)。依赖 `cordisInspect.providers` 为可读 Map
|
|
232
|
-
(rc.6 / rc.7 / 0.1.1-rc.1
|
|
247
|
+
(rc.6 / rc.7 / 0.1.1-rc.1 / 0.1.2-rc.1 实测如此);0.1.2-rc.1 上游仍留有
|
|
248
|
+
"reclaim the superseded generation" 的 TODO,缺陷未修复,故默认开启。
|
|
249
|
+
DSH 升级修复后可将 `CONFIG.fixStandingMountConflict` 置为 `false` 关闭。
|
|
233
250
|
|
|
234
251
|
**仍建议的操作纪律**:运行期间编辑已挂载 preset 后重启 DSH(补丁消除的是报错,旧代残留的
|
|
235
252
|
组合仍占用资源,这是 DSH 的既有行为);根治仍待上游修复。
|
|
@@ -242,7 +259,8 @@ its process-global Host inspect providers (`Service` …) twice and every retry
|
|
|
242
259
|
patches it by default**: `cordisInspect.register` is made idempotent (a same-id registration shares
|
|
243
260
|
the existing one and gets a no-op disposer), so coexisting generations no longer collide. The patch
|
|
244
261
|
is process-resident (survives plugin unload, reinstalled on restart; HMR reload does not stack it);
|
|
245
|
-
set `CONFIG.fixStandingMountConflict` to `false` once a fixed DSH ships.
|
|
262
|
+
set `CONFIG.fixStandingMountConflict` to `false` once a fixed DSH ships. Still open in 0.1.2-rc.1:
|
|
263
|
+
upstream carries a TODO to reclaim superseded generations.
|
|
246
264
|
|
|
247
265
|
## License
|
|
248
266
|
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# dsh-dupguard bundle layer: insert the plugin row when this bundle is active.
|
|
2
|
+
# The row name resolves from the profile's own node_modules, where
|
|
3
|
+
# `dsh plugin --profile <name> add dsh-dupguard` installed this package.
|
|
4
|
+
- insert:
|
|
5
|
+
- id: dupguard
|
|
6
|
+
name: dsh-dupguard
|
package/lib/index.js
CHANGED
|
@@ -66,7 +66,7 @@ const CONFIG = {
|
|
|
66
66
|
monitorReasoning: true,
|
|
67
67
|
// 是否同时检测工具调用参数(JSON 片段)。默认关闭:JSON / base64 中重复字符很常见。
|
|
68
68
|
monitorToolArguments: false,
|
|
69
|
-
// DSH ≤ 0.1.
|
|
69
|
+
// DSH ≤ 0.1.2-rc.1 兼容补丁(默认开启;实测 0.1.1-rc.1 / 0.1.2-rc.1 仍未修复):preset 的 standing mount
|
|
70
70
|
// 在 composition 文件变化后
|
|
71
71
|
// 会新建一代而旧代永不销毁,tool-cordis 每次挂载都向进程全局的 cordisInspect 注册表
|
|
72
72
|
// 注册 Service/Event/Builtin/Tool provider,两代并存即抛
|
|
@@ -271,7 +271,7 @@ function createStreamGuard(options, runtime) {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
/**
|
|
274
|
-
* DSH ≤ 0.1.
|
|
274
|
+
* DSH ≤ 0.1.2-rc.1 standing-mount 兼容补丁:把 cordisInspect.register 幂等化。
|
|
275
275
|
*
|
|
276
276
|
* 背景:preset 的 standing mount 在 composition 文件变化后新建一代、旧代永不销毁;
|
|
277
277
|
* tool-cordis 每次挂载都向进程全局的 cordisInspect 注册 Service/Event/Builtin/Tool
|
|
@@ -279,7 +279,7 @@ function createStreamGuard(options, runtime) {
|
|
|
279
279
|
* 注册(返回 no-op disposer),多代并存不再冲突。
|
|
280
280
|
*
|
|
281
281
|
* 说明:补丁有意不做撤销(常驻进程,重启后由本插件重新安装);依赖
|
|
282
|
-
* cordisInspect.providers 为可读 Map(实测 rc.6 / rc.7 / 0.1.1-rc.1 如此)。
|
|
282
|
+
* cordisInspect.providers 为可读 Map(实测 rc.6 / rc.7 / 0.1.1-rc.1 / 0.1.2-rc.1 如此)。
|
|
283
283
|
* DSH 升级修复后可将 CONFIG.fixStandingMountConflict 置为 false。
|
|
284
284
|
*/
|
|
285
285
|
function installStandingMountPatch(ctx) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-dupguard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Real-time repetition guard for DeepSeek Harness (DSH): stops model generation when the same string repeats >=10 times in the streamed output. 实时检测 DSH 大模型流式输出中的重复内容,同一字符串重复十次以上立即停止生成。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -23,19 +23,26 @@
|
|
|
23
23
|
"./package.json": "./package.json"
|
|
24
24
|
},
|
|
25
25
|
"dsh": {
|
|
26
|
+
"bundle": {
|
|
27
|
+
"patch": "./cordis.patch.yml"
|
|
28
|
+
},
|
|
26
29
|
"client": {
|
|
27
30
|
"platform": "web"
|
|
31
|
+
},
|
|
32
|
+
"compatibility": {
|
|
33
|
+
"dsh": ">=0.1.1-rc.1"
|
|
28
34
|
}
|
|
29
35
|
},
|
|
30
36
|
"files": [
|
|
31
37
|
"lib",
|
|
32
38
|
"plugin",
|
|
39
|
+
"cordis.patch.yml",
|
|
33
40
|
"README.md",
|
|
34
41
|
"LICENSE",
|
|
35
42
|
"CHANGELOG.md"
|
|
36
43
|
],
|
|
37
44
|
"engines": {
|
|
38
|
-
"node": ">=
|
|
45
|
+
"node": ">=20"
|
|
39
46
|
},
|
|
40
47
|
"scripts": {
|
|
41
48
|
"test": "node tests/detector.test.js"
|
package/plugin/host.js
CHANGED
|
@@ -40,7 +40,7 @@ const CONFIG = {
|
|
|
40
40
|
monitorReasoning: true,
|
|
41
41
|
// 是否同时检测工具调用参数(JSON 片段)。默认关闭:JSON / base64 中重复字符很常见。
|
|
42
42
|
monitorToolArguments: false,
|
|
43
|
-
// DSH ≤ 0.1.
|
|
43
|
+
// DSH ≤ 0.1.2-rc.1 兼容补丁(默认开启;实测 0.1.1-rc.1 / 0.1.2-rc.1 仍未修复):preset 的 standing mount
|
|
44
44
|
// 在 composition 文件变化后
|
|
45
45
|
// 会新建一代而旧代永不销毁,tool-cordis 每次挂载都向进程全局的 cordisInspect 注册表
|
|
46
46
|
// 注册 Service/Event/Builtin/Tool provider,两代并存即抛
|
|
@@ -243,7 +243,7 @@ function createStreamGuard(options) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
/**
|
|
246
|
-
* DSH ≤ 0.1.
|
|
246
|
+
* DSH ≤ 0.1.2-rc.1 standing-mount 兼容补丁:把 cordisInspect.register 幂等化。
|
|
247
247
|
*
|
|
248
248
|
* 背景:preset 的 standing mount 在 composition 文件变化后新建一代、旧代永不销毁;
|
|
249
249
|
* tool-cordis 每次挂载都向进程全局的 cordisInspect 注册 Service/Event/Builtin/Tool
|
|
@@ -251,7 +251,7 @@ function createStreamGuard(options) {
|
|
|
251
251
|
* 注册(返回 no-op disposer),多代并存不再冲突。
|
|
252
252
|
*
|
|
253
253
|
* 说明:补丁有意不做撤销(常驻进程,重启后由本插件重新安装);依赖
|
|
254
|
-
* cordisInspect.providers 为可读 Map(实测 rc.6 / rc.7 / 0.1.1-rc.1 如此)。
|
|
254
|
+
* cordisInspect.providers 为可读 Map(实测 rc.6 / rc.7 / 0.1.1-rc.1 / 0.1.2-rc.1 如此)。
|
|
255
255
|
* DSH 升级修复后可将 CONFIG.fixStandingMountConflict 置为 false。
|
|
256
256
|
*/
|
|
257
257
|
function installStandingMountPatch(ctx) {
|