dsh-plugin-rea 2.0.7 → 2.0.9
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 +78 -0
- package/README.md +14 -5
- package/README.zh-CN.md +12 -4
- package/bin/rea-shim.mjs +331 -95
- package/check-updates.ps1 +33 -5
- package/docs/bundle-design.md +24 -1
- package/package.json +1 -1
- package/scripts/setup.mjs +43 -3
- package/scripts/setup.test.mjs +327 -2
- package/scripts/verify-branch.ps1 +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
本插件遵循语义化版本。版本号变化说明「配置组合」这层的变化,与 REA 自身的版本无关。
|
|
4
4
|
|
|
5
|
+
## 2.0.9 — 2026-10-18
|
|
6
|
+
|
|
7
|
+
**2.0.8 的两处发布前问题(假回退、乱码)与若干文档缺口;不改正常路径,只让失败路径说真话。**
|
|
8
|
+
|
|
9
|
+
### 修复
|
|
10
|
+
|
|
11
|
+
- **`reexecFromCheckout` 的「回退」是假话**:spawn 失败时只打印「继续用镜像副本」,函数却返回了,`main()` 已经
|
|
12
|
+
return —— 没有 `exit` 事件、事件循环排空、进程以 **exit 0 静默退出**,行看起来启动成功却没有任何工具。现在这个
|
|
13
|
+
Promise **只在没接管时才 resolve**:子进程活着时本进程等待、由子进程的退出码决定;失败则 `main()` 继续用本地副本
|
|
14
|
+
启动,并如实说明在回退。
|
|
15
|
+
- **回退覆盖了升级竞态的主形态**:`spawn` 的目标是 `process.execPath`,spawn 级失败几乎只剩资源耗尽;真正常见的是
|
|
16
|
+
「哈希比对通过 → node 启动 → 文件已被换掉」→ node 以 `MODULE_NOT_FOUND` 退 1。现在**退出码非 0 且源文件已不存在**
|
|
17
|
+
时同样回退到本地副本(窗口毫秒级,代价是一次 `stat`),不再把竞态变成一行死掉的 MCP。
|
|
18
|
+
- **乱码 `鈥?` 混进用户可见输出**:2.0.7 在 GBK 编辑器里碰过 `bin/rea-shim.mjs`,16 处破折号被写成 `鈥?`,其中两条是
|
|
19
|
+
stderr 消息(首次自动供给、上次供给失败)—— 每个用户都会看到。全部还原为 `— `(含被吃掉的空格)。
|
|
20
|
+
- **开发时可能测到「已安装插件」而不是自己的改动**:checkout 副本会顺着 bundle 的 `mirror.json` 转发到插件目录。
|
|
21
|
+
现在 checkout(带 `cordis.patch.yml`)永不转发,只有镜像副本会;注释也改成与行为一致。
|
|
22
|
+
- **带 BOM 的 `mirror.json` / `bundle.json` 被当成「没有记录」**:`JSON.parse` 拒绝前导 BOM,而每个调用方都把解析失败
|
|
23
|
+
读成「无记录」。Windows 编辑器保存的 JSON 就会带 BOM,表现是镜像自愈静默不生效、bundle 被当成未供给。`bin/rea-shim.mjs`
|
|
24
|
+
与 `scripts/setup.mjs` 现在都经各自的 `readJson()` 去掉 `U+FEFF` 再解析。**两个文件读的是同一份记录,所以缺一不可**:
|
|
25
|
+
此前只有 shim 剥了 BOM,带 BOM 的 `mirror.json` 在 setup 眼里仍是「没有 checkout」,镜像 layout 下的 setup 于是把上一版
|
|
26
|
+
manifest 又镜了一遍并从它供给;`bundle.json` 同理被读成未供给。`verify-branch.ps1` 与 CI 都加了守卫:这两个文件里
|
|
27
|
+
出现裸的 `JSON.parse(readFileSync(...))` 即失败。
|
|
28
|
+
|
|
29
|
+
### 文档 / CI
|
|
30
|
+
|
|
31
|
+
- 两份 README 的钉版本示例改为**当前版本** `#v2.0.9`(2.0.8 那一轮已从 `#v2.0.0` 提到 `#v2.0.8`,版本号一动就得跟上,
|
|
32
|
+
否则读者拿到的 ref 不存在);README 的「机器上已有 REA」一节补上 Windows 限制:**强制结束 shim 不会带走被委派的 REA**。
|
|
33
|
+
- `docs/bundle-design.md`(随包发布)补上 2.0.7 的 launch mode 与 2.0.8 的镜像自愈,含 `mirror.json` 的
|
|
34
|
+
`shimSha256` / `pluginVersion` / `dshHome` 三个字段与控制流图。
|
|
35
|
+
- CI 新增两条:README 必须逐字引用 `engines.dsh`;README 的钉版本示例必须等于 `package.json` 的 version(`verify-branch.ps1`
|
|
36
|
+
同步加了第二条,避免同一个漂移第三次发生)。
|
|
37
|
+
- `systemReaCandidates` 的去重键改用传入的 `platform` 参数(测试缝一致,生产无变化)。
|
|
38
|
+
|
|
39
|
+
### 验证
|
|
40
|
+
|
|
41
|
+
- 单测 **71 条**(68 过 + 3 平台跳过;新增「checkout 副本不转发」「文件中途消失 → 回退」「带 BOM 的 `mirror.json`」
|
|
42
|
+
「带 BOM 的 `bundle.json`」四条);镜像转发测试改为真的运行镜像副本。
|
|
43
|
+
- `verify-branch.ps1` 44 项全绿;`audit-manifest` clean;`host-compat` 10 covered / 5 outside。
|
|
44
|
+
|
|
45
|
+
## 2.0.8 — 2026-10-18
|
|
46
|
+
|
|
47
|
+
**2.0.7 的启动检测在两种边界上会失控:一个包着本 shim 的 `rea` 会让探针递归成进程链;超时探针会漏掉一个孙进程。两条都已修,并补了复现测试。**
|
|
48
|
+
|
|
49
|
+
### 修复
|
|
50
|
+
|
|
51
|
+
- **重复注册检测在自定义 `DSH_HOME` 下失效**:harness 会从 MCP 子进程里抹掉所有 `DSH_*`,镜像副本因此读
|
|
52
|
+
`~/.dsh` —— 那是错的文件,上游写进真实 home 的第二条 `serverName: rea` 永远报不出来。`setup.mjs` 现在把运行时
|
|
53
|
+
的 home 记进 `mirror.json` 的 `dshHome`,shim 优先读环境、其次读这条记录。`check-updates.ps1` 的 profile 段也
|
|
54
|
+
改用同一条 home 规则(此前硬编码 `$env:USERPROFILE`,自定义 home 时报「找不到 profile」)。
|
|
55
|
+
- **镜像启动器不会自己更新**:行执行的是 `<DSH_HOME>/plugins/rea-bundle/bin/rea-shim.mjs` 这份**副本**,而市场升级
|
|
56
|
+
只换包、不跑 setup —— 副本会一直跑它被复制时的代码,于是新版本里的修复对老用户静默失效(旧副本照常工作,最难发现)。
|
|
57
|
+
现在镜像启动时会与 `mirror.json` 记录的插件目录比对哈希,不同就转发执行插件里的那一份(一跳,带
|
|
58
|
+
`REA_BUNDLE_SHIM_REEXEC` 守卫,且只从镜像指向插件,不会反向)。`--shim-status` 新增 `mirror.stale`,
|
|
59
|
+
`check-updates.ps1` 也会报「镜像落后,重跑 setup」;`mirror.json` 增加 `shimSha256` 与 `pluginVersion` 便于追溯。
|
|
60
|
+
**2.0.8 之前的版本自身无法完成这一步**(副本里没有这段代码),从那些版本升级仍需手动跑一次 setup。
|
|
61
|
+
- **探针递归**:`probeRea` 派生候选时没带 `REA_BUNDLE_DELEGATED=1`,而防自委派的守卫只在**委派**前生效。若 PATH 上是「调用本 shim 的 wrapper」,
|
|
62
|
+
探针 → wrapper → 新 shim → 再探针……实测并发 node 峰值 83+、杀掉后仍自我再生。现在探针环境同时带 `REA_BUNDLE_DELEGATED=1` 与
|
|
63
|
+
`REA_BUNDLE_AUTO_PROVISION=0`:嵌套运行直接走 bundle 并返回,实测 0.2 秒、零额外进程。
|
|
64
|
+
- **超时探针泄漏孙进程**:`spawnSync` 的超时只杀它自己启动的 cmd.exe,而 `taskkill /T` 在 `spawnSync` 回收之后调用已找不到父进程 ——
|
|
65
|
+
每次超时留一个 REA/ping 在跑。探针改为异步 `spawn` + 自己的计时器:超时发生在父进程仍存活时,`taskkill /T /F` 能真正清掉整棵树。
|
|
66
|
+
实测 8.3 秒放弃、`rejected=["timeout"]`、无残留进程。
|
|
67
|
+
- **Windows 信号处理器是死代码**:`child.kill("SIGTERM")` 在 Windows 上是 TerminateProcess,不可捕获;控制台的 Ctrl+C 又直达子进程。
|
|
68
|
+
该分支已删除,并如实写明限制:**在 Windows 上强制结束 shim 不会带走被委派的 REA**(Node 没有 job object 可用)。
|
|
69
|
+
- **`comspec()` 不校验**:`ComSpec` 指向不存在的文件时,正常的 `.cmd` REA 被判 `spawn-failed`(`auto` 静默退回 bundle,`system` 直接 78)。
|
|
70
|
+
现在校验为常规文件,否则回落到 `%SystemRoot%\System32\cmd.exe`;实测 `ComSpec` 指向不存在路径仍能识别 6.9.0。
|
|
71
|
+
- **文案**:显式路径是目录时报「does not exist」,改为「is not a file」。
|
|
72
|
+
|
|
73
|
+
### 验证
|
|
74
|
+
|
|
75
|
+
- 单测 **67 条**(2.0.7 是 60 条,本轮 +7:wrapper 递归必须被判为 `exit 78` 且 20 秒内收敛;`ComSpec` 失效仍识别 `.cmd` REA;
|
|
76
|
+
镜像自愈的转发/守卫/`stale` 上报/同内容不转发;`DSH_HOME` 被抹时从 `mirror.json` 找到真实 home 并报出重复注册):
|
|
77
|
+
Windows 64 过 + 3 平台跳过。
|
|
78
|
+
- `verify-branch.ps1` 全绿(39 项),含「两份 README 必须写出 package.json 里的 `engines.dsh` 原文」;`audit-manifest` clean;
|
|
79
|
+
`host-compat` 10 covered / 5 correctly outside。
|
|
80
|
+
- 手工复现三例:wrapper 递归 0.2 秒收敛、0 残留进程;挂起候选 8.3 秒放弃且无 `PING` 残留;`ComSpec` 指向空路径仍识别系统 REA。
|
|
81
|
+
|
|
82
|
+
|
|
5
83
|
## 2.0.7 — 2026-10-18
|
|
6
84
|
|
|
7
85
|
**机器上已有可用的 REA 时,2.x 直接按 1.x 的方式跑它(环境检测 + 委派),不再供给;同时把 2.0.6 的宿主声明收紧到真的能证明的范围。**
|
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@ releases, checksum-verified). Then install the plugin for your profile:
|
|
|
100
100
|
```
|
|
101
101
|
dsh plugin --profile <profile> add dsh-plugin-rea
|
|
102
102
|
# or pin this release instead of tracking npm latest:
|
|
103
|
-
dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea#v2.0.
|
|
103
|
+
dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea#v2.0.9
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
> **On an Electron host (the DeepSeek Harness desktop app) the profile is owned by the application.**
|
|
@@ -127,7 +127,7 @@ by the shim itself, which provisions in the background.
|
|
|
127
127
|
|
|
128
128
|
### Which DSH versions
|
|
129
129
|
|
|
130
|
-
`package.json` declares `engines.dsh: ">=0.1.7-rc.2 <0.3.0"`, and that declaration is the answer the plugin market
|
|
130
|
+
`package.json` declares `engines.dsh: ">=0.1.7-rc.2 <0.3.0-0"`, and that declaration is the answer the plugin market
|
|
131
131
|
reads: with it the card says **compatible**; without it the market can only say *unknown*. The range is not a guess —
|
|
132
132
|
it is the dsh release list this plugin is checked against, and `node scripts/host-compat.mjs` fails the build when the
|
|
133
133
|
two disagree:
|
|
@@ -161,6 +161,9 @@ runs **that**, exactly as the 1.x line did, and nothing is provisioned:
|
|
|
161
161
|
list says why a candidate was skipped (`"exit 7"`, `"inside the bundle"`, `"timeout"`).
|
|
162
162
|
- A delegated child carries `REA_BUNDLE_DELEGATED=1`, so a wrapper that calls this shim cannot make it delegate to
|
|
163
163
|
itself forever.
|
|
164
|
+
- **On Windows a forced kill of the shim does not reap the delegated REA.** There is no job object here: Task Manager
|
|
165
|
+
or a supervisor terminating the shim leaves your `rea` running with the row's pipes (a console Ctrl+C reaches the
|
|
166
|
+
whole process group and does stop it). On POSIX the child is in the same group and dies with the terminal.
|
|
164
167
|
|
|
165
168
|
## Configure — nothing
|
|
166
169
|
|
|
@@ -230,9 +233,9 @@ Which one? Upstream's is the configuration-only route: it expects Node on REA's
|
|
|
230
233
|
zero-dependency route: it fetches Node, REA, JDK and Ghidra on first run. The patch shape and the
|
|
231
234
|
`mcp__rea__*` surface are the same either way.
|
|
232
235
|
|
|
233
|
-
The shim reports the conflict on startup
|
|
234
|
-
|
|
235
|
-
lists it under `duplicateRegistration`.
|
|
236
|
+
The shim reports the conflict on startup — `setup.mjs` records the DSH home it ran under in
|
|
237
|
+
`mirror.json`, and the mirrored copy reads that when the harness has stripped `DSH_*` from its
|
|
238
|
+
environment; `node bin/rea-shim.mjs --shim-status` lists it under `duplicateRegistration`.
|
|
236
239
|
|
|
237
240
|
## Verify
|
|
238
241
|
|
|
@@ -337,6 +340,12 @@ back on the next start.
|
|
|
337
340
|
|
|
338
341
|
- **This plugin** never updates itself. Installed from a market? Update it there. Installed from a `file:`
|
|
339
342
|
checkout? Overwrite the directory and reinstall.
|
|
343
|
+
- **The row runs a COPY of this plugin's launcher.** `<DSH_HOME>/plugins/rea-bundle/bin/rea-shim.mjs` is a mirror
|
|
344
|
+
made by setup, so a market upgrade replaces the package but not the file the row executes — until setup runs
|
|
345
|
+
again. From **2.0.8** the mirror notices that the installed plugin ships a different launcher and re-execs it
|
|
346
|
+
(one hop, guarded by `REA_BUNDLE_SHIM_REEXEC`), so upgrades carry. On an older version the mirror stays behind
|
|
347
|
+
silently; `--shim-status` now reports `mirror.stale`, and `check-updates.ps1` says to re-run setup. If you are
|
|
348
|
+
upgrading from 2.0.0–2.0.7, run `node scripts/setup.mjs` once after the upgrade.
|
|
340
349
|
- **Upgrading from `2.0.0-bundle.1`**: that release mirrored the shim and `setup.mjs` but not the manifest,
|
|
341
350
|
and recorded nothing about the plugin checkout, so a bundle it provisioned cannot repair itself — its
|
|
342
351
|
background provisioning dies on the missing manifest, invisibly, and its own lock suppresses retries for
|
package/README.zh-CN.md
CHANGED
|
@@ -94,7 +94,7 @@ profile 安装插件:
|
|
|
94
94
|
```
|
|
95
95
|
dsh plugin --profile <profile> add dsh-plugin-rea
|
|
96
96
|
# 或钉住这个版本,而不是跟着 npm latest 走:
|
|
97
|
-
dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea#v2.0.
|
|
97
|
+
dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea#v2.0.9
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
> **Electron 宿主(DeepSeek Harness 桌面版)的 profile 由应用独占。** 那种机器上 `dsh plugin --profile desktop …`
|
|
@@ -118,7 +118,7 @@ node scripts/setup.mjs --reuse # 或先 --dry-run 看计划
|
|
|
118
118
|
|
|
119
119
|
### 支持哪些 DSH 版本
|
|
120
120
|
|
|
121
|
-
`package.json` 里声明了 `engines.dsh: ">=0.1.7-rc.2 <0.3.0"`,这就是插件市场读的那句话:有它,卡片显示
|
|
121
|
+
`package.json` 里声明了 `engines.dsh: ">=0.1.7-rc.2 <0.3.0-0"`,这就是插件市场读的那句话:有它,卡片显示
|
|
122
122
|
**兼容**;没有它,市场只能说*未声明*。这个范围不是猜的——它对应本插件实际核对过的 dsh 发布列表,
|
|
123
123
|
`node scripts/host-compat.mjs` 会在两者不一致时让构建失败:
|
|
124
124
|
|
|
@@ -149,6 +149,9 @@ node scripts/setup.mjs --reuse # 或先 --dry-run 看计划
|
|
|
149
149
|
- `--shim-status` 会把判断结果打出来 —— `launch.mode`、`launch.reason`、`launch.systemRea`,`launch.rejected` 里
|
|
150
150
|
写的是每个候选被跳过的原因(`"exit 7"`、`"inside the bundle"`、`"timeout"`)。
|
|
151
151
|
- 被委派的子进程带着 `REA_BUNDLE_DELEGATED=1`,所以一个调用本 shim 的 wrapper 不会让它无限委派给自己。
|
|
152
|
+
- **Windows 上强制结束 shim 不会带走被委派的 REA**:这里没有 job object,任务管理器或 supervisor 终止 shim 时,
|
|
153
|
+
你自己的 `rea` 会继续占着这一行的管道(控制台 Ctrl+C 会发给整个进程组,那种情况下会一起停)。POSIX 上子进程
|
|
154
|
+
在同一进程组,随终端一起退出。
|
|
152
155
|
|
|
153
156
|
## 配置 —— 不需要
|
|
154
157
|
|
|
@@ -216,8 +219,8 @@ duplicate server name 报错并加载失败,最终留下哪一行取决于加
|
|
|
216
219
|
自己准备。本包是零依赖路线:首次运行自动取 Node、REA、JDK、Ghidra。两者的 patch 形态与
|
|
217
220
|
`mcp__rea__*` 工具面相同。
|
|
218
221
|
|
|
219
|
-
shim
|
|
220
|
-
|
|
222
|
+
shim 会在启动时提示冲突 —— `setup.mjs` 会把运行时的 DSH home 记进 `mirror.json`,镜像副本在 harness 抹掉
|
|
223
|
+
`DSH_*` 之后就用这条记录去找那份文件;`node bin/rea-shim.mjs --shim-status` 会把冲突列在 `duplicateRegistration` 下。
|
|
221
224
|
|
|
222
225
|
## 验证
|
|
223
226
|
|
|
@@ -314,6 +317,11 @@ node scripts/setup.mjs # 或:powershell -File scripts\rea-bundle-boot
|
|
|
314
317
|
工具就回来了。
|
|
315
318
|
|
|
316
319
|
- **本插件**从不自更新。从市场装的就在市场更新;从 `file:` 检出的就覆盖目录重装。
|
|
320
|
+
- **行跑的是本插件启动器的「镜像副本」**:`<DSH_HOME>/plugins/rea-bundle/bin/rea-shim.mjs` 是 setup 复制过去的,
|
|
321
|
+
所以市场升级只换包、不换行执行的那个文件 —— 直到再跑一次 setup。从 **2.0.8** 起,镜像会发现自己落后于已安装的
|
|
322
|
+
插件,并转发执行插件里的那一份(一跳,带 `REA_BUNDLE_SHIM_REEXEC` 守卫),升级因此能生效。更早的版本里镜像会
|
|
323
|
+
静默地停在旧代码;`--shim-status` 现在会报 `mirror.stale`,`check-updates.ps1` 也会提示重跑 setup。**从
|
|
324
|
+
2.0.0–2.0.7 升级的话,升级后跑一次 `node scripts/setup.mjs`。**
|
|
317
325
|
- **从 `2.0.0-bundle.1` 升级**:那一版镜像了 shim 与 `setup.mjs`,却漏了 manifest,也没有留下插件 checkout
|
|
318
326
|
的记录,所以它供给出来的 bundle **无法自愈** —— 后台供给会因缺 manifest 而崩溃且完全不可见,而它自己写下的
|
|
319
327
|
lock 又会让重试被抑制六小时。请**从插件目录**重跑一次 `node scripts/setup.mjs`:它会重新镜像三个文件,
|