dsh-recency-guard 0.11.4 → 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/README.md +314 -382
- package/assets/icon-256.png +0 -0
- package/bin/rescue.mjs +269 -9
- package/dist/client.js +2504 -500
- package/dist/index.js +4706 -2218
- package/dsh-plugin.json +142 -0
- package/locale/en.json +145 -9
- package/locale/zh.json +145 -9
- package/package.json +34 -20
- package/screenshots.json +3 -0
package/README.md
CHANGED
|
@@ -1,350 +1,303 @@
|
|
|
1
|
-
## v0.10 新增(可观测性数学增强 + 洞察卡 + 插件信息/反馈入口)
|
|
2
|
-
|
|
3
|
-
- **转移矩阵卡(马尔可夫链)**:阶段行为的「去向分布」——monitoring 是健康值守
|
|
4
|
-
(80% 留在自己)还是高危巡逻(40% 掉进 crashed)一眼可见;幂法迭代求平稳分布
|
|
5
|
-
(ε=1e-9,L∞ 判敛),回答「长期来看守护停在哪个阶段」。样本不足时诚实显示
|
|
6
|
-
「不可判定」,白名单外迁移被丢弃且如实计数。
|
|
7
|
-
- **控制带(休哈特单值-MR)**:崩溃间隔的 x̄±3σ̂(σ̂=MR̄/1.128)控制带,
|
|
8
|
-
区分「偶然波动」与「特殊原因」——哪一次间隔越界(崩溃变密)被点名到序号;
|
|
9
|
-
与 CUSUM 变点、回归斜率、生存分析互为视角(趋势看方向,控制带看单点越界)。
|
|
10
|
-
- **数据流卡**:journal 原文 → 事件投影 → 语义流动 → 面板渲染的四环链路白盒,
|
|
11
|
-
每环带说明与计数 —— 「画面上的事实从哪来、经过什么变换」不再靠猜。
|
|
12
|
-
- **系统诊断卡 + 插件信息面板 + 反馈入口(R18)**:插件版本 / 宿主版本 / 运行环境 /
|
|
13
|
-
**分区键** / 数据面状态 / 快照耗时一卡尽览;仓库链接来自 package.json 的
|
|
14
|
-
`repository`/`bugs`,「问题反馈」按钮直达 GitHub Issues(未登记时隐藏按钮,
|
|
15
|
-
绝不放死链);工具 `status` 的命令窗口输出同步携带这两条。
|
|
16
|
-
- **命令窗口显示修复(R10)**:`rescue.mjs` 的 status/history 输出按 CJK 显示宽
|
|
17
|
-
(全角 2 列)对齐 —— 中文标签与英文值混排不再错位(rescue 零依赖纪律不变,
|
|
18
|
-
宽度判定内联实现)。
|
|
19
|
-
|
|
20
|
-
## v0.9.1 新增(判定可视化)
|
|
21
|
-
|
|
22
|
-
- **恢复判定条**:崩溃后的分级判定现在到达用户可见面 —— 面板生命周期卡片顶部
|
|
23
|
-
显示「观察中 / 已行动」标签 + 完整判定理由 + 进度(第 N/M 轮,act=false 虚线中性色,
|
|
24
|
-
「观察中」不是错误);工具 `status` 的 facts 同步携带。undefined(从未崩溃过)
|
|
25
|
-
不渲染假判定。
|
|
26
|
-
- **事件流高亮两阶段**:观察轮/恢复判定/两阶段对账的 journal note 在事件流卡片
|
|
27
|
-
用 warn/success 徽标区分(识别 detail 前缀派生语义,存储词汇不变)。
|
|
28
|
-
|
|
29
|
-
## v0.9 新增(恢复置信分级 + 两阶段提交 + CLI 逃生通道 + 卡片限高)
|
|
30
|
-
|
|
31
|
-
- **恢复置信分级**:唯一嫌疑是确定性证据(第 1 轮即关闭);多嫌疑是概率性证据,
|
|
32
|
-
同一头号嫌疑连续 N 轮(默认 2,可配 `confirmRounds`)复现才自动关闭。
|
|
33
|
-
偶发崩溃不再误伤无辜插件 —— 观察轮的崩溃证据链完整保留,供下次判定。
|
|
34
|
-
- **两阶段提交 + 重启对账**:关闭动作分 prepared(记录待执行)→ quarantined
|
|
35
|
-
(已生效)两阶段;崩溃打断时下次启动按磁盘现状对账(confirmed/reverted),
|
|
36
|
-
不留半成品状态。
|
|
37
|
-
- **CLI 逃生通道**:`node bin/rescue.mjs status|history|decision|archives
|
|
38
|
-
--profile-dir <dir>` —— 宿主起不来时离线读取守护产物(零依赖、只读、
|
|
39
|
-
语义化退出码 2 = 有未恢复崩溃,供脚本联动)。
|
|
40
|
-
- **面板备份策略卡片**:时间线备份开关/保留份数/备份根/配置编辑服务可用性
|
|
41
|
-
一目了然(只读投影;改配置走宿主设置页)。
|
|
42
|
-
- **卡片固定高度 + 扩大**:每张展开卡片内容区限高 240px 内部滚动(窄侧栏
|
|
43
|
-
180px),视口密度均匀;卡片头部 ⤢ 按钮临时解除限高摊开阅读,与折叠态独立。
|
|
44
|
-
|
|
45
|
-
## v0.8 新增(备份增强 + 官方实验插件观测 + 事件驱动)
|
|
46
|
-
|
|
47
|
-
- **时间线备份**:插件更新时自动把「更新前」的配置快照存为 `<版本>@<时刻>.json`,
|
|
48
|
-
每插件默认保留 5 份(可配),更新前后的配置可逐版对账 —— 回答「升级后行为变了,
|
|
49
|
-
是配置变了还是 bug」。工具 `action=backups` 同时报告最近备份与每插件时间线。
|
|
50
|
-
- **自定义备份目录**:配置 `backupRoot` 或环境变量 `RECENCY_GUARD_BACKUP_ROOT`;
|
|
51
|
-
自定义根下仍按分区键分层,多项目隔离不因集中存放而失效。
|
|
52
|
-
- **官方实验插件观测**:`@deepseek-ai/dsh-experimental-*` 只记录不关闭
|
|
53
|
-
(journal `official-observe` 事件 + 整组状态的时间线备份)。它们是官方的
|
|
54
|
-
实验场,崩溃概率最高,但自动关闭官方组件的风险不可接受 —— 现在崩溃归因时
|
|
55
|
-
能回答「当时装了哪些实验组件、什么版本、什么状态」。
|
|
56
|
-
- **事件驱动变更检测**:订阅宿主 `plugin-manager/changed` 事件(500ms 防抖),
|
|
57
|
-
GUI/工具路径的安装更新**立即**进时间线与嫌疑面,不用等重启。CLI/手工编辑
|
|
58
|
-
不发此事件,仍由每次启动的同步 diff 兑底 —— 事件是加速器,不是唯一真相。
|
|
59
|
-
- **嫌疑排名显示修复**:数据层不再截断(曾 slice(0,10) 且渲染又 limit 5,
|
|
60
|
-
「报 N 只列 5」);命令窗口列 15 条带省略计数,面板默认 15 条 + 「展开其余 N 个」。
|
|
61
|
-
|
|
62
1
|
# dsh-recency-guard
|
|
63
2
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
当某个插件把 DSH 拖垮时,本插件会在崩溃的那一刻记录下"谁最可疑",并在**下一次启动时、在崩溃插件的代码被加载之前**把它挡在门外。反复崩溃时,关闭的插件会逐个增加(第 1 次关最近更新的 1 个,仍崩溃则关最近更新的 2 个)。稳定之后,除首要嫌疑外,其余被关闭的配置会自动恢复。
|
|
67
|
-
|
|
68
|
-
## v0.11.4 触屏双指缩放(图谱交互补齐)
|
|
69
|
-
|
|
70
|
-
- **双指捏合缩放**:两指同时按下即进入捏合 —— 中点下的世界点在缩放中保持
|
|
71
|
-
不动(与单指缩放同一不变式),同时中点位移会带动画布平移;捏合期间取消
|
|
72
|
-
画布平移拖拽,抬指后清空取样。退化输入(两指重合/非有限)返回原视口,
|
|
73
|
-
绝不产生 Infinity。
|
|
74
|
-
- 回归:viewport 新增 4 条捏合断言(翻倍缩放/锚点不动/跟随平移/退化与上界)。
|
|
75
|
-
|
|
76
|
-
## v0.11.3 图谱交互补齐(边可交互 + 布局过渡)
|
|
77
|
-
|
|
78
|
-
- **边可交互(审计 P0 收尾)**:此前边完全不可点击、`edge.label` 是死数据。
|
|
79
|
-
现在每条边叠加透明宽描边热区:悬停高亮 + 指针变化、点击显示**边详情侧栏**
|
|
80
|
-
(生产方 → 消费方 · 语义 · 边自带 label);选中边的语义标签与数据标签
|
|
81
|
-
分别绘制。选中态与节点详情**互斥**(单一真相),Esc / 空白处点击 /
|
|
82
|
-
「重置」都会清空。
|
|
83
|
-
- **布局切换过渡**:节点坐标改用 CSS transform,布局切换与拖拽回弹有
|
|
84
|
-
过渡动画;拖动中的节点禁用过渡(否则「追不上指针」);
|
|
85
|
-
`prefers-reduced-motion` 由全局规则降级。
|
|
86
|
-
- 回归:`edgeDetailOf` 纯函数新增 3 条断言(端点解析/字段带出/幽灵端点 null)。
|
|
87
|
-
|
|
88
|
-
## v0.11.2 紧急修复(恢复诚实性 + 启动恢复时序)
|
|
89
|
-
|
|
90
|
-
- **恢复结果白盒化(P0 假绿修复)**:`reenable` 此前**无条件**返回
|
|
91
|
-
`reenabled: true` 并从 `autoDisabled` 移除 —— 实测管理器返回
|
|
92
|
-
`application: 'failed'`(HMR 嵌套事务)时,state 仍记「已恢复」,面板/工具
|
|
93
|
-
显示成功而插件实际仍关闭。现在只有**真的 applied** 才算成功;失败者保留在
|
|
94
|
-
自动关闭名单待下轮重试,journal/note 如实列出「未启用(管理器拒绝)」。
|
|
95
|
-
- **启动恢复延后到 HMR 事务之外**:boot 阶段 Loader 自身可能正处在事务中,
|
|
96
|
-
恢复调用会报 `HMR transactions cannot be nested`。自动恢复改为 boot 后
|
|
97
|
-
1.5s 执行(定时器 unref,不拖住宿主退出),失败由诚实结果兜底。
|
|
98
|
-
- 回归:host 工具测试新增「管理器拒绝 ⇒ reenable 报失败」断言;14/14 全绿。
|
|
99
|
-
|
|
100
|
-
## v0.11.1 紧急修复(宿主兼容 + 启动崩溃 · 2026-11-08)
|
|
101
|
-
|
|
102
|
-
**事故背景**:桌面端 DSH 自动升级到 `dsh 0.2.2-rc.1` 后连续崩溃(5 次/3 分钟),
|
|
103
|
-
守护插件被兼容闸门移出 profile、不再保护;重新挂载后又因遗留写锁把宿主拖进
|
|
104
|
-
`fatal load failure`。本版本修复三处,全部是「守护不能拖垮宿主」的底线问题。
|
|
105
|
-
|
|
106
|
-
- **宿主预发布版本兼容(P0)**:`engines.dsh` 与全部 `@deepseek-ai/dsh-*`
|
|
107
|
-
peer 范围改为显式预发布分支
|
|
108
|
-
`>=0.2.1-rc.5 <0.2.2-0 || >=0.2.2-rc.1 <0.2.3-0 || >=0.2.3-rc.1 <0.3.0-0`。
|
|
109
|
-
原因:node-semver 只放行「与范围中某个比较符 **major.minor.patch 元组相同**
|
|
110
|
-
且自身带预发布标签」的预发布版本 —— 旧范围 `>=0.2.1-rc.5 <0.3.0-0` 会
|
|
111
|
-
静默排除 `0.2.2-rc.1`,插件被兼容闸门判为不兼容并从 profile 移除。
|
|
112
|
-
已在 `dsh 0.2.2-rc.1` 干净沙箱(sb-rg-v0111)实测安装 + 启动 + 守护激活通过。
|
|
113
|
-
- **启动绝不抛出(P0)**:`boot()` 失败改为**降级留痕**(步骤记失败 + 警告
|
|
114
|
-
日志),不再 rethrow。此前一个可恢复的写锁超时会把宿主变成
|
|
115
|
-
`dsh: fatal load failure`(退出码 1)—— 观测/恢复设施不能拖垮主流程。
|
|
116
|
-
- **失效写锁自愈(P0)**:新增 `cleanStaleLocks`(Store.init 启动时清理 +
|
|
117
|
-
`updateState` 超时后清理重试一次)。判据:锁内容为空/非正整数 PID(不完整
|
|
118
|
-
记录,atomic-write 永远无法接管)/ PID 对应进程已死,且文件年龄 > 5s
|
|
119
|
-
(避开锁创建与写 PID 之间的零字节窗口,绝不抢活锁)。
|
|
120
|
-
真机事故:崩溃恰好发生在锁创建与写 PID 之间,遗留 0 字节
|
|
121
|
-
`state.json.lock`,此后每次启动都等满超时并致命。
|
|
122
|
-
- **连续崩溃兜底升级(P0)**:`assessConfidence` 新增安全网 —— 累计崩溃
|
|
123
|
-
`crashSeq ≥ 3` 时即使概率计数未达 `confirmRounds` 也强制行动;同时
|
|
124
|
-
`readCrashHistory` 跳过启动时的「无嫌疑 crash-detected」记录。实测该记录
|
|
125
|
-
每轮打断连续计数,导致 crashSeq 涨到 3 仍停在「观察中 1/2 轮」,崩溃循环
|
|
126
|
-
永远无法自愈。
|
|
127
|
-
- 测试:新增 `tests/unit/store-lock.test.ts`(锁自愈 11 断言)与契约层
|
|
128
|
-
预发布范围守卫;14/14 全绿(Core 7 / Host 2 / Client 4 / Contract 1)。
|
|
129
|
-
|
|
130
|
-
## v0.11 新增(数据面安全 + 图谱图例一致性 + 马尔可夫去向可见 + 市场准备)
|
|
131
|
-
|
|
132
|
-
- **动作路由方法守卫(P0 安全修复)**:`/action/archive|reenable|restore|recover`
|
|
133
|
-
此前不检查 HTTP 方法 —— `GET /recency-guard/api/action/archive` 也会执行归档重置
|
|
134
|
-
(浏览器预取/爬虫/误点链接都可能触发)。现在非 POST 一律 405 + `allow: POST`。
|
|
135
|
-
- **`?partition=` 真正生效(P0)**:客户端一直拼分区查询参数,但数据面此前从不读它
|
|
136
|
-
—— 跨分区查看永远静默返回当前分区。现在快照路由在宿主侧实现分区感知:
|
|
137
|
-
请求其它分区返回**只读磁盘投影**(状态/日志/决策/备份),运行时字段如实标注
|
|
138
|
-
归属,未知分区返回 `available:false`(绝不假绿)。
|
|
139
|
-
- **面板动作面补齐**:新增 `/action/restore` 路由 + 面板「恢复非嫌疑插件」按钮
|
|
140
|
-
(工具早有此动作,路由此前缺失);暂停轮询时 footer 显示「数据已停留 N 分钟」。
|
|
141
|
-
- **图谱图例一致性(P0)**:图例颜色此前固定语义色调色板,切到「按类型」口径时
|
|
142
|
-
与节点实际颜色不一致;现在图例色**跟随当前着色口径**(legendColorOf),并直接
|
|
143
|
-
绘制节点形状(形状=第二编码通道,图例不展示它就只对知道映射的人可读)。
|
|
144
|
-
- **搜索循环跳转**:多匹配时回车依次遍历(第 n/m 指示可见),不再永远停在第一个;
|
|
145
|
-
「重置」按钮现在同时清掉拖拽偏移(此前节点拖飞后只能刷新页面)。
|
|
146
|
-
- **马尔可夫跨阶段去向(P0)**:矩阵卡此前只渲染自环概率条 —— `monitoring → 崩溃
|
|
147
|
-
40%` 这类核心去向分布(README 宣称的)在界面上根本看不到。现在每行带 top-2
|
|
148
|
-
跨阶段去向徽标。
|
|
149
|
-
- **事件流展开**:默认 12 条 + 「展开其余 N 条」显式计数(与嫌疑排名同款纪律,
|
|
150
|
-
数据层给全量、显示层管截断)。
|
|
151
|
-
- **测试盲区补齐**:新增 `tests/client/graph-model.test.ts`(过滤共源/布局确定性/
|
|
152
|
-
图例同源/平行边曲率)与 `tests/host/routes.test.ts`(方法守卫/partition/参数
|
|
153
|
-
校验/请假语义)—— 文件头「已由测试钉死」的注释如今成真。13/13 全绿。
|
|
154
|
-
- **参考插件取长补短**:系统研究 dsh-ops(输出 notice 三要素)、dsh-compat-guardian
|
|
155
|
-
(reconcile 自愈/原子写/乐观锁)、dsh-context(工作预算/资源自适应)、
|
|
156
|
-
dsh-cookie-guard(独立救援 CLI)后按审计清单采纳落地;研究报告见
|
|
157
|
-
`.cycles/cycles/cycle-6/参考插件研究报告.md`。
|
|
158
|
-
- **插件市场准备**:仓库 topics(dsh-plugin 等)补齐、256px 图标、screenshots.json
|
|
159
|
-
声明、投稿 YAML 按 awesome-dsh-plugin contributing.md 形态定稿。
|
|
160
|
-
|
|
161
|
-
## v0.7 新增(崩溃级修复 + 可交互图谱 + 可观测性白盒化)
|
|
162
|
-
|
|
163
|
-
**先说最要紧的一条:v0.6 会把 profile 写崩。**
|
|
164
|
-
|
|
165
|
-
- **崩溃级修复:守护行 YAML 注入**。v0.6 写入守护行时 `name:` 没有加引号,
|
|
166
|
-
而 YAML 把 `@` 列为保留指示符 —— 于是任意 scoped 包(`@linxin666/...`)
|
|
167
|
-
都会让**整份 `cordis.patch.yml` 不可解析**,DSH 起不来。真机桌面 profile
|
|
168
|
-
已中招(第 185/189/193 行)。v0.7 改为「永远引号 + 写前校验 + 原子回滚 +
|
|
169
|
-
pristine 备份」三层防线,并提供 `npm run repair-patch` 修复既有污染。
|
|
170
|
-
- **静默失效修复**:`apply` 里直接读未 `inject` 的 `ctx.configEditor` 会抛错,
|
|
171
|
-
表现为「端口在听、UI 能开,但插件根本没激活」(日志只有一行
|
|
172
|
-
`warning: 1 entry did not activate`)。改走 `tryReadService` 后消失。
|
|
173
|
-
- **可交互图谱**:hover 高亮 + tooltip、点击选中联动详情、搜索过滤、
|
|
174
|
-
布局切换、缩放平移钳制;**fit 只做一次**,数据轮询不重置用户缩放
|
|
175
|
-
(实测 7 秒轮询零变化)。滚轮改用原生非 passive 监听,
|
|
176
|
-
修掉「缩放时页面跟着滚」。
|
|
177
|
-
- **面板自己滚动(v0.7.1)**:宿主槽位是 `overflow:hidden` 且整页不滚,
|
|
178
|
-
面板内容约 4000px 被裁到一屏 —— 下方指标/能力清单/归档根本看不到。
|
|
179
|
-
面板改为自带滚动容器(`height:100%` + `min-height:0` + `overflow-y:auto`
|
|
180
|
-
+ `overscroll-behavior:contain`),实测可滚到 `scrollTop=3361` 并看到底部归档区。
|
|
181
|
-
滚轮分工同步调整:**普通滚轮滚动面板,Ctrl/⌘ + 滚轮缩放图谱**
|
|
182
|
-
(缩放入口仍在工具栏三个按钮上)。
|
|
183
|
-
- **可观测性白盒化**:每个指标都带 `formula` / `inputs` / `sampleSize` /
|
|
184
|
-
`confidence`;不可判定时 `defined=false` 且**给原因**("没有崩溃样本"),
|
|
185
|
-
绝不把无数据当 0。CUSUM 变点按**相邻崩溃间隔**回归(不是时间戳、不是累计计数)。
|
|
186
|
-
- **能力闭环**:能力清单与注册处双向比对;`consumes`/`consumedBy` 方向修正;
|
|
187
|
-
21 项能力、对外暴露 12、连通率 100%、孤立 0(面板可见)。
|
|
188
|
-
- **8 条数据面路由全部可用**(曾出现 `isolation` / `lifecycle` 500,
|
|
189
|
-
根因是 RouteContext 缺 provider)。
|
|
190
|
-
- **模块拆分降复杂度**:`patch.ts` 142 → `patch-scalar.ts`(87) + `patch-yaml.ts`
|
|
191
|
-
+ `patch.ts` 门面,band-detector `Status: OK`。
|
|
192
|
-
|
|
193
|
-
## v0.6 新增
|
|
194
|
-
|
|
195
|
-
- **崩溃压力(EWMA)**:新增 KPI「崩溃压力」——EWMA 平滑的近期崩溃密度
|
|
196
|
-
(半衰期 5 次启动)。同样 1/3 的崩溃率,崩溃集中在最近时压力更高,
|
|
197
|
-
这是整体崩溃率给不出的时间局部性。无观测样本时诚实显示「不可判定」。
|
|
198
|
-
- **归档摘要**:归档清单(工具 `archives` / 面板归档卡片)现在带 manifest
|
|
199
|
-
摘要——那次归档时的崩溃次数、事件数、被关插件。「举他对照」时能看到
|
|
200
|
-
基线事实,而不只是「归过档」。
|
|
201
|
-
- **隔离可见性**:工具 `status` 输出新增「工作区 · 分区」行,命令窗口可
|
|
202
|
-
对账「这次守护是哪个项目的事实」;面板 header 显示可读项目名 +
|
|
203
|
-
完整工作区路径(悬停全文),哈希前缀退居兜底。
|
|
204
|
-
- **图谱邻居导航**:节点详情侧栏新增上游(生产方)/下游(消费方)邻居
|
|
205
|
-
列表,点击即跳转定位——度数回答「有几条边」,邻居回答「连到谁」。
|
|
206
|
-
|
|
207
|
-
## v0.5 新增
|
|
208
|
-
|
|
209
|
-
- **图谱交互二次增强**:节点拖拽重排(布局偏移跨轮询保持)、搜索定位(id/标签/引用三级优先匹配,回车跳第一个)、节点详情侧栏(完整 id + 度数 + 定位按钮)、双击节点视口居中、贝塞尔曲线边(同一对端点的平行边奇偶交替弯曲,方向可辨)、高亮边带生产/消费语义标签。
|
|
210
|
-
- **面板现代化**:KPI 摘要条置顶(稳定性 SVG 圆环、当前阶段、崩溃率、趋势判定、CUSUM 变点一览);崩溃间隔统计(中位/CV)与 CUSUM 变点接入指标卡片;轮询暂停/恢复开关(调试截图时画面不再跳动);卡片可折叠(折叠态记入 localStorage,跨会话保持)。
|
|
211
|
-
- **性能债清理**:图谱 id→node 索引由「每条边重建一次」改为「每个节点数组建一次」(O(E·V) → O(V)),节点上百时轮询不再卡顿。
|
|
212
|
-
|
|
213
|
-
## v0.3 新增
|
|
214
|
-
|
|
215
|
-
- **能力闭环可证**:能力清单(注册/生产/消费)与实际注册面双向比对(契约测试 100% 层),三类缺口(消费断链/过度生产/孤立)可检出。
|
|
216
|
-
- **生命周期状态机**:六阶段白名单迁移(idle/monitoring/crashed/deciding/stabilizing/recovered),非法迁移被拒且不改状态,迁移历史带原因与时刻。
|
|
217
|
-
- **可量化可观测**:崩溃率/平均恢复耗时/检出率/隔离纯度/稳定性评分/风险评分/崩溃趋势七个读数,**不可判定时为 null 而非 0**。
|
|
218
|
-
- **管理面板 + 可交互图谱**:`main` 与侧栏双席位,滚轮缩放以指针为锚、拖拽平移、点击高亮追溯(BFS)、Esc 一次退出;响应式(窄屏单列)、主题变量驱动。
|
|
219
|
-
- **多项目隔离**:状态按**项目目录**分区(哈希键),A 项目崩溃不影响 B;守护行经指针文件搭桥。
|
|
220
|
-
- **归档重置 + 举他**:归档 = 搬走 + 留档(manifest 先读后搬),重置后不继承旧结论、按最新 node_modules 事实重推嫌疑;另一工作区可只读清单作对照。
|
|
221
|
-
- **质量评审体系**:Core/Host/Client/Contract 四层测试 + 类型/lint/构建/依赖审计全零门禁(npm audit high:0 critical:0)。
|
|
222
|
-
|
|
223
|
-
---
|
|
3
|
+
**v0.16.0** · [GitHub](https://github.com/xuanyuanchumo/dsh-recency-guard) · [问题反馈](https://github.com/xuanyuanchumo/dsh-recency-guard/issues) · MIT
|
|
224
4
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
- [工具](#工具recency_guard)
|
|
232
|
-
- [数据文件](#数据文件)
|
|
233
|
-
- [恢复流程](#恢复流程)
|
|
234
|
-
- [安全边界](#安全边界)
|
|
235
|
-
- [开发与测试](#开发与测试)
|
|
5
|
+
> DeepSeek Harness 的**插件崩溃恢复守护**:记录第三方 / 实验性插件的安装与更新时序并备份配置;
|
|
6
|
+
> 崩溃后的**下一次启动之前**,把最近更新的嫌疑插件挡在门外;稳定启动后,再把非首要嫌疑放回来。
|
|
7
|
+
>
|
|
8
|
+
> 版本基线(2026-11-11,北京时间):**0.16.0**。版本四锚点(`package.json` / 本 README /
|
|
9
|
+
> `docs/agents/` / [`dsh-plugin.json`](dsh-plugin.json))一致。
|
|
10
|
+
> 测试分四层,当前 **68/68 全绿**(Core 29 / Host 10 / Client 20 / Contract 7)。
|
|
236
11
|
|
|
237
12
|
---
|
|
238
13
|
|
|
239
14
|
## 它解决什么问题
|
|
240
15
|
|
|
241
|
-
在 DSH
|
|
16
|
+
在 DSH 里安装或更新一个第三方 / 实验性插件后,宿主可能直接退出:
|
|
242
17
|
|
|
243
18
|
```
|
|
244
19
|
dsh: fatal uncaught exception: Error: ...
|
|
245
20
|
```
|
|
246
21
|
|
|
247
|
-
|
|
22
|
+
崩溃发生在插件加载阶段,**插件自己已经来不及运行** —— 它的恢复逻辑、工具、面板都不可达。
|
|
23
|
+
手动流程是:禁用所有插件 → 重启 → 逐个加回 → 每次重启验证。慢,而且容易再踩一次。
|
|
248
24
|
|
|
249
|
-
|
|
25
|
+
本插件把这件事自动化成三步:
|
|
250
26
|
|
|
251
|
-
| 步骤 |
|
|
27
|
+
| 步骤 | 手动做法 | 本插件 |
|
|
252
28
|
| --- | --- | --- |
|
|
253
|
-
|
|
|
254
|
-
|
|
|
255
|
-
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
29
|
+
| 记录 | 靠记忆 | 安装 / 更新事件写进 `journal.jsonl`(崩溃也不丢) |
|
|
30
|
+
| 拦截 | 手动改配置 | 崩溃瞬间**同步**写决策文件;Loader 在 import 嫌疑插件**之前**求值守护行 |
|
|
31
|
+
| 恢复 | 逐个加回 | 稳定启动后恢复非首要嫌疑;首要嫌疑留给你确认 |
|
|
32
|
+
|
|
33
|
+
**它不做什么**:不修复宿主自身缺陷、不处理依赖版本不兼容、不阻止 entry 级 `apply` 抛错
|
|
34
|
+
(那是宿主的自隔离 warning,不是进程崩溃)。见下文「诚实边界」。
|
|
259
35
|
|
|
260
36
|
---
|
|
261
37
|
|
|
262
|
-
##
|
|
38
|
+
## 安装
|
|
263
39
|
|
|
264
|
-
###
|
|
40
|
+
### npm(推荐)
|
|
265
41
|
|
|
266
|
-
|
|
42
|
+
```bash
|
|
43
|
+
dsh plugin --profile <profile名> add dsh-recency-guard
|
|
44
|
+
```
|
|
267
45
|
|
|
268
|
-
|
|
46
|
+
安装后**重启 dsh**。启动时本插件会自动:
|
|
269
47
|
|
|
270
|
-
|
|
48
|
+
- 在 profile 的 `cordis.patch.yml` 中为每个第三方插件写入守护行;
|
|
49
|
+
- 开始记录安装 / 更新事件与配置备份。
|
|
271
50
|
|
|
272
|
-
|
|
51
|
+
锁定版本:
|
|
273
52
|
|
|
274
|
-
|
|
53
|
+
```bash
|
|
54
|
+
dsh plugin --profile <profile名> add dsh-recency-guard@0.16.0
|
|
55
|
+
```
|
|
275
56
|
|
|
276
|
-
|
|
277
|
-
|
|
57
|
+
> 版本对应:本 README 描述本仓库 **0.16.0** 源码。npm 上实际可安装的版本以
|
|
58
|
+
> `npm view dsh-recency-guard version` 为准;若 `latest` 落后于本文版本,请按下面的源码方式安装,
|
|
59
|
+
> 或等待对应版本发布。发布顺序见 [`docs/agents/conventions.md`](docs/agents/conventions.md) §6。
|
|
278
60
|
|
|
279
|
-
###
|
|
61
|
+
### 插件市场
|
|
280
62
|
|
|
281
|
-
|
|
63
|
+
投稿材料已按 [awesome-dsh-plugin contributing.md](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/blob/main/contributing.md)
|
|
64
|
+
备好([`docs/market-submission.md`](docs/market-submission.md)):一个条目文件、`category: security`。
|
|
65
|
+
上架后可在 dsh 的 **Plugins → Discover** 或 dsh-market 中搜索 `recency-guard` 安装。
|
|
66
|
+
**当前状态:材料已备、PR 未提交** —— 本文不声称已在市场中可搜到。
|
|
282
67
|
|
|
283
|
-
|
|
68
|
+
### 手动 / 本地源码(开发)
|
|
284
69
|
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/xuanyuanchumo/dsh-recency-guard.git
|
|
72
|
+
cd dsh-recency-guard
|
|
73
|
+
npm install
|
|
74
|
+
npm run build # 必跑:dsh plugin add file: 只拷贝 files 声明的产物,不执行构建
|
|
75
|
+
dsh plugin --profile <profile名> add file:/绝对路径/dsh-recency-guard
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
开发期反复改代码时用 `link:`(Windows 落 Junction),改完 `npm run build` 重启即生效:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
dsh plugin --profile <profile名> add link:/绝对路径/dsh-recency-guard
|
|
289
82
|
```
|
|
290
83
|
|
|
291
|
-
|
|
84
|
+
### 安装顺序
|
|
85
|
+
|
|
86
|
+
本插件必须排在被守护插件**之前**,才能在启动阶段完成守护行安装。确认 profile 的 `package.json`:
|
|
292
87
|
|
|
293
|
-
|
|
88
|
+
```json
|
|
89
|
+
"dsh": {
|
|
90
|
+
"profile": {
|
|
91
|
+
"bundles": [
|
|
92
|
+
"@deepseek-ai/dsh-base",
|
|
93
|
+
"dsh-recency-guard",
|
|
94
|
+
"dsh-你的插件"
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
294
99
|
|
|
295
|
-
|
|
100
|
+
---
|
|
296
101
|
|
|
297
|
-
|
|
102
|
+
## 三分钟上手
|
|
298
103
|
|
|
299
|
-
|
|
104
|
+
1. **重启 dsh 后打开面板**:侧栏图标「插件守护」→ 中央面板。首屏三块:生命周期、崩溃决策、能力清单。
|
|
105
|
+
2. **用工具看状态**(会话里让模型调用,或直接看命令窗口):
|
|
300
106
|
|
|
301
|
-
|
|
107
|
+
```json
|
|
108
|
+
{ "action": "status" }
|
|
109
|
+
```
|
|
302
110
|
|
|
303
|
-
|
|
111
|
+
输出包含崩溃次数、嫌疑排名(全量)、自动关闭名单、声明式冲突(每条带
|
|
112
|
+
`文件:行号` 与声明原文)、上次隔离后仍治不了的 `unresolved`、隔离分区与量化指标;
|
|
113
|
+
不可判定的指标显示**原因**,不显示 0。
|
|
114
|
+
3. **看磁盘事实**:`<profile>/.recency-guard/projects/<分区键>/` 下的
|
|
115
|
+
`journal.jsonl` / `state.json` / `decision.json` 是全部真相,面板只是它们的投影。
|
|
116
|
+
4. **想验证拦截**:不要在主 profile 做。用独立沙箱 profile 装一个**故意抛异常**的插件,
|
|
117
|
+
启动 → 崩溃 → 再启动,观察决策文件与日志。步骤见
|
|
118
|
+
[`docs/agents/verification.md`](docs/agents/verification.md) §5.3。
|
|
304
119
|
|
|
305
|
-
|
|
306
|
-
2. `node_modules` 的 mtime(首次运行时兜底)
|
|
120
|
+
---
|
|
307
121
|
|
|
308
|
-
|
|
122
|
+
## 能力表
|
|
123
|
+
|
|
124
|
+
每条能力的代码位置与验证入口都可点击核对。能力清单本身是**投影**,真相在注册处
|
|
125
|
+
(工具注册、路由注册、事件发射),由契约测试双向比对。
|
|
126
|
+
|
|
127
|
+
| 能力 | 你能看到什么 | 代码 | 验证 |
|
|
128
|
+
| --- | --- | --- | --- |
|
|
129
|
+
| 安装 / 更新时间线 | `history`、`journal.jsonl` | [`store.ts`](src/host/data/store.ts) | [`core.test.ts`](tests/unit/core.test.ts) |
|
|
130
|
+
| 嫌疑排序(最近更新 + 实验性标记 + 变更频率) | `status.suspectRanking`(全量) | [`recency.ts`](src/host/risk/recency.ts) | [`risk-frequency.test.ts`](tests/unit/risk-frequency.test.ts)、[`official-experimental.test.ts`](tests/unit/official-experimental.test.ts) |
|
|
131
|
+
| 风险评分与误伤校准(并行读数) | 面板「决策因子」卡 | [`risk-bayes.ts`](src/host/risk/risk-bayes.ts)、[`risk-calibration.ts`](src/host/risk/risk-calibration.ts) | [`risk-bayes.test.ts`](tests/unit/risk-bayes.test.ts)、[`risk-calibration.test.ts`](tests/unit/risk-calibration.test.ts) |
|
|
132
|
+
| **确定性冲突证据** | status / 面板「声明式冲突」(带 文件:行号) | [`conflict-declarations.ts`](src/host/guard/conflict-declarations.ts)、[`conflict-findings.ts`](src/host/guard/conflict-findings.ts)([`conflict-metadata.ts`](src/host/guard/conflict-metadata.ts) 转发) | [`conflict-findings.test.ts`](tests/unit/conflict-findings.test.ts)、[`deterministic-evidence.test.ts`](tests/unit/deterministic-evidence.test.ts) |
|
|
133
|
+
| **贪心最小隔离 + 依赖联动** | `recover` 关闭整组、残余 `unresolved` 上屏 | [`quarantine-plan.ts`](src/host/guard/quarantine-plan.ts)、[`crash-decision.ts`](src/host/guard/crash-decision.ts) | [`quarantine-plan.test.ts`](tests/unit/quarantine-plan.test.ts)、[`crash-decision.test.ts`](tests/unit/crash-decision.test.ts) |
|
|
134
|
+
| 崩溃决策 + 守护行 | 下次启动前拦截 | [`crash-decision.ts`](src/host/guard/crash-decision.ts)、[`decision.ts`](src/host/guard/decision.ts)、[`guarded-rows.ts`](src/host/guard/guarded-rows.ts)、[`patch.ts`](src/host/profile/patch.ts) | [`patch-safety.test.ts`](tests/unit/patch-safety.test.ts)、[`core.test.ts`](tests/unit/core.test.ts)、[`revision-source.test.ts`](tests/host/revision-source.test.ts) |
|
|
135
|
+
| 双通道崩溃检测(哨兵 + 残留标记) | 强杀 / 断电也能被发现 | [`sentinel.ts`](src/host/guard/sentinel.ts)、[`abnormal-boot.ts`](src/host/guard/abnormal-boot.ts) | [`fault-injection.test.ts`](tests/fault-injection/fault-injection.test.ts)、[`reload-journey.test.ts`](tests/host/reload-journey.test.ts) |
|
|
136
|
+
| 降级留痕与状态对账 | 重启后仍可查;「关了但 crashSeq=0」会被补账 | [`boot-orchestration.ts`](src/host/guard/boot-orchestration.ts)、[`state-reconcile.ts`](src/host/guard/state-reconcile.ts)、[`store.ts`](src/host/data/store.ts) | [`boot-degradation.test.ts`](tests/unit/boot-degradation.test.ts)、[`state-reconcile.test.ts`](tests/unit/state-reconcile.test.ts)、[`journal-append-race.test.ts`](tests/unit/journal-append-race.test.ts)、[`boot-crashseq-race.test.ts`](tests/unit/boot-crashseq-race.test.ts) |
|
|
137
|
+
| 恢复与配置备份 | `restore` / `backups` | [`recovery-actions.ts`](src/host/guard/recovery-actions.ts)、[`recovery-policy.ts`](src/host/guard/recovery-policy.ts) | [`core.test.ts`](tests/unit/core.test.ts)、[`versioned-backup.test.ts`](tests/unit/versioned-backup.test.ts) |
|
|
138
|
+
| 生命周期状态机 | 生命周期卡 + 迁移史 | [`lifecycle.ts`](src/host/core/lifecycle.ts) | [`lifecycle-steps.test.ts`](tests/unit/lifecycle-steps.test.ts) |
|
|
139
|
+
| 量化指标与数学模型 | 指标卡 / 控制带 / 转移矩阵 | [`observability.ts`](src/host/observe/observability.ts)、[`markov.ts`](src/host/observe/markov.ts)、[`control-band.ts`](src/host/observe/control-band.ts) | [`observability-math.test.ts`](tests/unit/observability-math.test.ts)、[`hazard-threshold.test.ts`](tests/unit/hazard-threshold.test.ts) |
|
|
140
|
+
| 管理面板 | 中央面板 + 侧栏图标 | [`GuardPanel.tsx`](src/client/panel/GuardPanel.tsx)、[`snapshot-view.ts`](src/client/panel/snapshot-view.ts)、[`PanelShell.tsx`](src/client/panel/PanelShell.tsx) | [`panel-v014.test.ts`](tests/client/panel-v014.test.ts)、[`panel-scroll.test.ts`](tests/client/panel-scroll.test.ts)、[`panel-null-snapshot.test.ts`](tests/client/panel-null-snapshot.test.ts) |
|
|
141
|
+
| 可交互能力图谱 | 节点 / 边 / 缺口 / 小地图 | [`GuardGraph.tsx`](src/client/graph/GuardGraph.tsx)、[`graph-interaction.ts`](src/client/graph/graph-interaction.ts) | [`graph-model.test.ts`](tests/client/graph-model.test.ts)、[`graph-focus.test.ts`](tests/client/graph-focus.test.ts)、[`graph-keyboard.test.ts`](tests/client/graph-keyboard.test.ts) |
|
|
142
|
+
| 项目隔离 | 隔离卡 + `?partition=<key>` | [`isolation.ts`](src/host/core/isolation.ts) | [`isolation-journey.test.ts`](tests/host/isolation-journey.test.ts)、[`isolation-parallel.test.ts`](tests/host/isolation-parallel.test.ts) |
|
|
143
|
+
| 归档与重置 | `archive` / `archives` | [`archive.ts`](src/host/data/archive.ts) | [`core.test.ts`](tests/unit/core.test.ts)、[`resilience-fallback.test.ts`](tests/unit/resilience-fallback.test.ts) |
|
|
144
|
+
| 工具 `recency_guard`(8 个 action) | 命令窗口卡片与文本 | [`tool-registration.ts`](src/host/surface/tool-registration.ts)、[`tool-dispatch.ts`](src/host/surface/tool-dispatch.ts)、[`tool-render.ts`](src/host/surface/tool-render.ts) | [`tool.test.ts`](tests/host/tool.test.ts)、[`display-truncation.test.ts`](tests/host/display-truncation.test.ts) |
|
|
145
|
+
| 写动作乐观并发(409 不执行) | 面板冲突提示 | [`change-guard.ts`](src/host/core/change-guard.ts)、[`routes.ts`](src/host/surface/routes.ts) | [`change-guard.test.ts`](tests/unit/change-guard.test.ts)、[`routes.test.ts`](tests/host/routes.test.ts)、[`api-conflict.test.ts`](tests/client/api-conflict.test.ts) |
|
|
146
|
+
| 能力清单双向比对 | 能力缺口卡 | [`capability-specs.ts`](src/host/capability/capability-specs.ts) | [`capability.test.ts`](tests/contract/capability.test.ts) |
|
|
147
|
+
| 离线逃生 CLI | 宿主起不来时查现场 / 止血 / 回插 | [`rescue.mjs`](bin/rescue.mjs) | [`rescue-cli.test.ts`](tests/unit/rescue-cli.test.ts) |
|
|
309
148
|
|
|
310
149
|
---
|
|
311
150
|
|
|
312
|
-
##
|
|
151
|
+
## 面板与图谱
|
|
152
|
+
|
|
153
|
+
### 管理面板
|
|
154
|
+
|
|
155
|
+
- **数据面**:`GET /recency-guard/api/snapshot`,5 秒轮询一次;暂停按钮按下后**不再发请求**
|
|
156
|
+
(画面停在暂停时刻,而不是继续跳)。
|
|
157
|
+
- **卡片**:稳定性 / 阶段 / 崩溃率 / 崩溃压力 / CUSUM 变点、崩溃决策与因子分解、
|
|
158
|
+
**声明式冲突**(每条带 `文件:行号` 与声明原文)、**未解决冲突**(上次隔离后仍治不了的部分,
|
|
159
|
+
与「现在有冲突」分开显示)、量化指标(不可判定显示原因)、能力清单与缺口、项目隔离、归档、事件流。
|
|
160
|
+
- **可空契约**:宿主在跨分区只读视图会发 `null` / 整段省略的字段,由
|
|
161
|
+
[`snapshot-view.ts`](src/client/panel/snapshot-view.ts) 的 `PanelSnapshotView` 显式放宽,
|
|
162
|
+
渲染层诚实降级,不把面板整块打进错误边界(契约测试
|
|
163
|
+
[`panel-snapshot-nullability.test.ts`](tests/contract/panel-snapshot-nullability.test.ts) 守护)。
|
|
164
|
+
- **折叠记忆**:折叠态存 `localStorage` 的 `recency-guard-collapsed`,读取失败退化为全展开,不抛异常。
|
|
165
|
+
- **动作**:恢复非嫌疑插件、重新启用某个插件、归档重置 —— 都携带快照的 `revision`;
|
|
166
|
+
过期返回 **409 且动作不执行**,面板提示重读后再决定。
|
|
167
|
+
- **滚动**:面板自己滚(`height:100% + min-height:0 + overflow-y:auto`),页面不被撑高。
|
|
168
|
+
- **真机视觉验收**:卡片标题单行;数据流 4 步完整;面板已无渲染崩溃 ——
|
|
169
|
+
此前 `intervals.cv=null` 会让整块白屏,现由客户端可空视图 + 契约测试钉住(见上)。
|
|
170
|
+
|
|
171
|
+
### 可交互图谱
|
|
172
|
+
|
|
173
|
+
- **缩放**:`Ctrl/⌘ + 滚轮`(指针为锚),或工具栏 `+` / `-`;普通滚轮滚面板,不吞手势。
|
|
174
|
+
- **默认 fit-all**:首帧优先铺满全图;内容多时文字会偏小,可点工具栏「放大视图」。
|
|
175
|
+
22 节点规模下首帧会自动放大到可读比例。
|
|
176
|
+
- **放大视图**:高度按**像素**(不是 `vh`),窗口变化不挤压图形;收起后**保留缩放**,
|
|
177
|
+
不把用户视角打回默认。
|
|
178
|
+
- **平移 / 拖拽**:拖画布平移;拖节点做**用户叠加层**位移,数据轮询不会重置它。
|
|
179
|
+
- **选择**:单击节点高亮上下游;双击节点居中;点击边看边详情(可与节点详情互斥收起)。
|
|
180
|
+
- **搜索**:输入定位;`Enter` 在匹配项间循环并显示第 n / m 个。
|
|
181
|
+
- **图例**:按着色口径自动跟色(改配色图例跟着变),形状通道同样入图例。
|
|
182
|
+
- **小地图**:显示全图范围与当前视口,可点击 / 拖拽跳转。
|
|
183
|
+
- **键盘**:方向键在节点/边之间二维导航,`+` / `-` / `0` 缩放与复位,`Esc` 一次清空全部观察态,
|
|
184
|
+
`Enter` 循环搜索结果(以 [`GuardGraph.tsx`](src/client/graph/GuardGraph.tsx) 的 `aria-keyshortcuts` 为准)。
|
|
185
|
+
- **轮询不重置视口**:fit 只跑一次(有守卫),数据刷新不会把用户缩放打回默认。
|
|
186
|
+
|
|
187
|
+
> 本文**不贴截图**:仓库的 [`screenshots.json`](screenshots.json) 目前只声明了市场图标,
|
|
188
|
+
> 没有面板 / 图谱截图。宁可写清交互,也不放一张不存在的图。
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 工具:`recency_guard`
|
|
193
|
+
|
|
194
|
+
`execute` 返回**规范 JSON**(业务数据摊平在顶层),人读文本由 `output.render` 投影,
|
|
195
|
+
命令窗口另接 `presentCall` / `presentResult` / `presentationMeta` 三条卡片通道。
|
|
196
|
+
|
|
197
|
+
| action | 参数 | 行为 |
|
|
198
|
+
| --- | --- | --- |
|
|
199
|
+
| `status` | — | 崩溃状态、嫌疑排名(全量)、自动关闭、**声明式冲突(带出处)**、**未解决冲突**、指标、工作区 / 分区归因 |
|
|
200
|
+
| `history` | `limit?=40` | 安装 / 更新 / 崩溃 / 恢复事件时间线 |
|
|
201
|
+
| `recover` | — | 按确定性冲突与依赖联动做**贪心最小隔离**;未命中声明时退回「按最近更新关闭」;残余 `unresolved` 上屏 |
|
|
202
|
+
| `restore` | — | 重新启用非首要嫌疑,首要嫌疑保持关闭 |
|
|
203
|
+
| `reenable` | `bundle` | 手动重新启用指定插件 |
|
|
204
|
+
| `backups` | — | 配置备份清单(含版本时间线) |
|
|
205
|
+
| `archive` | `reason?` | 归档当前产物并重置(先写审计行,再执行) |
|
|
206
|
+
| `archives` | — | 历史归档清单(带 manifest 摘要) |
|
|
207
|
+
|
|
208
|
+
所有写 action 在执行**之前**先落一条审计行(`kind: note` + 结构化 `audit{actor,action,justification}`);
|
|
209
|
+
审计写失败不阻塞动作。读 action 不写日志。
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## CLI 逃生通道
|
|
214
|
+
|
|
215
|
+
宿主起不来时,面板、工具、路由全都不可达 —— 这时用零依赖的 rescue CLI 直接读磁盘。
|
|
216
|
+
**默认只读**;写操作必须显式 `--yes`,且是两阶段、可精确回插的。
|
|
313
217
|
|
|
314
|
-
###
|
|
218
|
+
### 只读命令(默认绝不写盘)
|
|
315
219
|
|
|
316
220
|
```bash
|
|
317
|
-
|
|
221
|
+
node bin/rescue.mjs status --profile-dir "<profile目录>" [--project <key|label>]
|
|
222
|
+
node bin/rescue.mjs history --profile-dir "<profile目录>" [--limit 40]
|
|
223
|
+
node bin/rescue.mjs decision --profile-dir "<profile目录>"
|
|
224
|
+
node bin/rescue.mjs archives --profile-dir "<profile目录>"
|
|
225
|
+
node bin/rescue.mjs rescues --profile-dir "<profile目录>"
|
|
318
226
|
```
|
|
319
227
|
|
|
320
|
-
|
|
228
|
+
### 可写命令(崩溃救火,默认 dry-run)
|
|
321
229
|
|
|
322
|
-
|
|
323
|
-
|
|
230
|
+
```bash
|
|
231
|
+
# 1) 先看计划:把 decision.json 的 disable 名单(或 --bundle)从 profile bundles 摘掉
|
|
232
|
+
node bin/rescue.mjs apply --profile-dir "<profile目录>" [--bundle a,b] [--reason "事故说明"]
|
|
324
233
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
> "dsh-你的插件"
|
|
332
|
-
> ] } }
|
|
333
|
-
> ```
|
|
234
|
+
# 2) 确认后真正落盘
|
|
235
|
+
node bin/rescue.mjs apply --profile-dir "<profile目录>" --yes
|
|
236
|
+
|
|
237
|
+
# 3) 回插:默认取最新一条可回插记录;中断后用 --resume
|
|
238
|
+
node bin/rescue.mjs restore --profile-dir "<profile目录>" [--id <uuid>] [--resume] --yes
|
|
239
|
+
```
|
|
334
240
|
|
|
335
|
-
|
|
241
|
+
- **两阶段**:先写 `prepared` 记录(含 `beforeHash` / `afterHash` / 每个 bundle 的原 index),
|
|
242
|
+
再原子改 profile 的 `package.json`,最后标 `applied`;记录在
|
|
243
|
+
`<profile>/.recency-guard/rescue/<uuid>.json`。
|
|
244
|
+
- **中断恢复**:`restore --resume` 读 `prepared` 记录,用哈希判定第二步是否已生效 ——
|
|
245
|
+
`afterHash` 相符 ⇒ 按已生效回插;`beforeHash` 相符 ⇒ 第 2 步没发生,记录作废、不动 profile。
|
|
246
|
+
回插按**原 index 升序**执行,不会互相挤位。
|
|
247
|
+
- **拒绝而不是硬改**:现场哈希不符 / 记录被篡改 ⇒ 退出码 `3`,不覆盖。
|
|
248
|
+
- **退出码**:`0` 正常;`1` 参数错误;`2` 发现未恢复的崩溃状态;`3` 拒绝(现场已变)。
|
|
249
|
+
- npm 安装后也可用 bin 名:`recency-guard-rescue status --profile-dir ...`。
|
|
250
|
+
|
|
251
|
+
Windows 示例:
|
|
336
252
|
|
|
337
253
|
```bash
|
|
338
|
-
|
|
254
|
+
node bin/rescue.mjs status --profile-dir "%USERPROFILE%\.dsh\profiles\desktop"
|
|
339
255
|
```
|
|
340
256
|
|
|
341
|
-
|
|
257
|
+
---
|
|
342
258
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
259
|
+
## 诚实边界
|
|
260
|
+
|
|
261
|
+
**概率性判定(会观察、可能不立刻行动)**
|
|
262
|
+
|
|
263
|
+
- 第二条崩溃通道(残留 bootMarker + 该 pid 已不在)是**概率性证据**:
|
|
264
|
+
人为强杀也会产生同样形状。因此第 1 轮只观察,同一头号嫌疑累计到 `confirmRounds`(默认 2)才动手;
|
|
265
|
+
**唯一嫌疑**走确定性证据,第 1 轮即行动。
|
|
266
|
+
- 幻影「另一个实例」已单独归类为 `self-reload`(同 pid 热重载),不按并发实例处理。
|
|
267
|
+
|
|
268
|
+
**写安全与对账(真机竞态修复)**
|
|
269
|
+
|
|
270
|
+
- **journal 是 append-only**:崩溃路径同步追加、绝不整文件回写;行数裁剪只在异步、
|
|
271
|
+
加锁的安全时机做。并发写不会再用旧快照覆盖 `crash-detected`(此前真机约 1/9 复现)。
|
|
272
|
+
- **以决策文件为真相补账**:哨兵在场且决策文件有非空 `disable` 时,state 缺失的
|
|
273
|
+
`autoDisabled` / 被清零的 `crashSeq` 会在下次启动补回;无哨兵 / 非崩溃决策 / 空名单
|
|
274
|
+
一律不补(不猜)。
|
|
275
|
+
- **清零是 CAS**:干净启动只归零「本轮启动后没被崩溃改过」的计数,晚到的异步写
|
|
276
|
+
不会抹掉崩溃路径刚写下的 `crashSeq`。
|
|
277
|
+
- **降级可查**:启动编排的分区索引提交 / 变更记录 / 官方实验观测失败,都会落一条
|
|
278
|
+
journal `note` 并带 `degraded: true` —— 不只写 logger,重启后仍可查。
|
|
279
|
+
|
|
280
|
+
**明确不拦 / 不修的**
|
|
281
|
+
|
|
282
|
+
- **entry 级 `apply` 抛错**:宿主只 warning 并自隔离该 entry,进程不崩 —— 不属于本插件的拦截面。
|
|
283
|
+
真崩溃来自进程级未捕获异常 / rejection。评估守护能力时别用 entry 级失败当夹具。
|
|
284
|
+
- **官方组件**:`@deepseek-ai/*` 永远不是嫌疑;官方实验包(`@deepseek-ai/dsh-experimental-*`)
|
|
285
|
+
只观测、**绝不自动关闭**(关官方组件等于卸宿主半边)。
|
|
286
|
+
- **宿主自身缺陷 / 依赖版本不兼容**:本插件不修,也不假装能修。按
|
|
287
|
+
[`docs/agents/update-guide.md`](docs/agents/update-guide.md) 的紧急流程处理。
|
|
288
|
+
- **指标不可判定时为 `null`,不是 0**:没有真实崩溃样本时,贝叶斯后验、预防性预警不编数字;
|
|
289
|
+
研究文档里的「Top-1 命中率提升 ≥5%」「预警提前量 ≥1 轮」两条效果判据**尚未声称达成**
|
|
290
|
+
(机制已就位,效果待真机样本)。
|
|
291
|
+
- **跨分区只读视图**:`GET /snapshot?partition=<key>` 的运行时字段(stage / metrics / markov)
|
|
292
|
+
如实降级为 `null` / `idle`,不替别的分区编造状态;`revision` 恒为 `null`。
|
|
293
|
+
- **声明式冲突只在有声明时产生**:插件没写 `dshCompat` / `dsh-plugin.json`、版本范围不可判定、
|
|
294
|
+
对手不在场 ⇒ **不产生 finding**(不猜)。`conflicts` 空数组 = 扫过且没有,不是没扫。
|
|
295
|
+
- **`unresolved` 不静默**:受保护组件(官方 / 本插件)/ 无候选 / 配额不足导致治不了的冲突会单独上屏;
|
|
296
|
+
不会用 recency 嫌疑人顶替确定性目标来「装作解决」。
|
|
297
|
+
- **`maxAutoDisable` 是整组上限**:依赖联动可能一次关一组;整组放不进配额则**一个都不动**
|
|
298
|
+
(不让依赖者半关着在下一次启动时再崩一次)。
|
|
299
|
+
- **rescue 写模式不是自动的**:默认 dry-run,不带 `--yes` 绝不写;两阶段 + 哈希校验,
|
|
300
|
+
现场已变时退出码 `3` 拒绝而不是硬改 profile。
|
|
348
301
|
|
|
349
302
|
---
|
|
350
303
|
|
|
@@ -357,127 +310,106 @@ npm 发布后市场索引会自动携带 npm 版本;GitHub-only 期间用上
|
|
|
357
310
|
name: dsh-recency-guard
|
|
358
311
|
config:
|
|
359
312
|
enabled: true # 总开关;false 时只记录,绝不自动关闭
|
|
360
|
-
includeExperimental: true #
|
|
361
|
-
maxAutoDisable: 2 #
|
|
362
|
-
autoRestore: true #
|
|
313
|
+
includeExperimental: true # 实验性 / beta 命名是否算嫌疑
|
|
314
|
+
maxAutoDisable: 2 # 单次恢复最多停用几个(整组上限,含依赖联动)
|
|
315
|
+
autoRestore: true # 稳定后自动恢复非首要嫌疑
|
|
363
316
|
confirmRounds: 2 # 概率性证据的行动阈值(唯一嫌疑不受限)
|
|
364
|
-
versionedBackups: true #
|
|
365
|
-
backupRetain: 5 #
|
|
366
|
-
backupRoot: '' #
|
|
317
|
+
versionedBackups: true # 更新时写带版本的时间线备份
|
|
318
|
+
backupRetain: 5 # 每插件保留几份
|
|
319
|
+
backupRoot: '' # 备份自定义目录(环境变量 RECENCY_GUARD_BACKUP_ROOT 优先)
|
|
367
320
|
```
|
|
368
321
|
|
|
369
322
|
| 配置 | 默认 | 说明 |
|
|
370
323
|
| --- | --- | --- |
|
|
371
|
-
| `enabled` | `true` |
|
|
372
|
-
| `includeExperimental` | `true` |
|
|
373
|
-
| `maxAutoDisable` | `2` |
|
|
374
|
-
| `autoRestore` | `true` |
|
|
375
|
-
| `confirmRounds` | `2` | 多嫌疑时同一头号嫌疑连续 N
|
|
376
|
-
| `versionedBackups` | `true` |
|
|
324
|
+
| `enabled` | `true` | 总开关。关闭后只记录,永不自动禁用 |
|
|
325
|
+
| `includeExperimental` | `true` | 实验性 / beta 命名的包是否算嫌疑 |
|
|
326
|
+
| `maxAutoDisable` | `2` | 单次恢复最多停用数,**整组上限**(依赖联动可能一次关多个;整组放不进则不动) |
|
|
327
|
+
| `autoRestore` | `true` | 稳定启动后自动恢复非首要嫌疑 |
|
|
328
|
+
| `confirmRounds` | `2` | 多嫌疑时同一头号嫌疑连续 N 轮才自动关闭(唯一嫌疑第 1 轮行动) |
|
|
329
|
+
| `versionedBackups` | `true` | 写「带版本的时间线备份」,可逐版对账 |
|
|
377
330
|
| `backupRetain` | `5` | 每个插件保留的备份份数(超出删最旧) |
|
|
378
|
-
| `backupRoot` | `''` |
|
|
331
|
+
| `backupRoot` | `''` | 自定义备份目录;`RECENCY_GUARD_BACKUP_ROOT` 优先 |
|
|
379
332
|
|
|
380
333
|
---
|
|
381
334
|
|
|
382
|
-
##
|
|
335
|
+
## 兼容范围
|
|
383
336
|
|
|
384
|
-
|
|
|
385
|
-
| --- | --- |
|
|
386
|
-
| `
|
|
387
|
-
|
|
|
388
|
-
| `
|
|
389
|
-
| `
|
|
390
|
-
| `
|
|
391
|
-
| `
|
|
392
|
-
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
```json
|
|
398
|
-
{ "action": "status" }
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
---
|
|
337
|
+
| 项 | 范围 | 依据 |
|
|
338
|
+
| --- | --- | --- |
|
|
339
|
+
| dsh 宿主 | `>=0.2.1-rc.5 <0.2.2-0 \|\| >=0.2.2-rc.1 <0.2.3-0 \|\| >=0.2.3-rc.1 <0.3.0-0` | [`package.json`](package.json) 的 `engines.dsh` |
|
|
340
|
+
| 开发 / 测试代际 | `0.2.2-rc.1` | `devDependencies` 与 `peerDependencies` 对齐 |
|
|
341
|
+
| `@deepseek-ai/cordis` | `>=4.0.5 <5.0.0` | 宿主实际 `4.1.0`;旧 `~4.0.5` 会被兼容闸门整体拒绝 |
|
|
342
|
+
| 官方包 | 全部 `peerDependencies` + `optional: true` | 缺 `dsh-tools` / `schemastery` 时降级加载,不 require 崩 |
|
|
343
|
+
| 社区 manifest | draft **v0.15**([`dsh-plugin.json`](dsh-plugin.json)) | 与 dsh 安装契约(`package.json`)并存,不是替换 |
|
|
344
|
+
| Node | 开发与测试环境 `v24.14.0`;`package.json` 未声明 `engines.node` | 不声称未验证的 Node 版本 |
|
|
345
|
+
| 平台 | Windows 真机实测(桌面端 dsh) | Linux / macOS 未做真机崩溃注入验证 —— 未声称 |
|
|
346
|
+
|
|
347
|
+
> 预发布分支为什么要写显式 `||`:node-semver 只允许「范围里某个比较符与该版本的
|
|
348
|
+
> `major.minor.patch` 元组一致、且自身带预发布标签」时才放行预发布版本。
|
|
349
|
+
> 写成 `>=0.2.1-rc.5 <0.3.0-0` 会**静默排除** `0.2.2-rc.1`,用户安装直接撞 `ERESOLVE`。
|
|
402
350
|
|
|
403
351
|
## 数据文件
|
|
404
352
|
|
|
405
|
-
|
|
353
|
+
全部在 profile 目录下,按工作区分区(项目 A 的崩溃不影响项目 B):
|
|
406
354
|
|
|
407
355
|
```
|
|
408
356
|
<profile>/.recency-guard/
|
|
409
|
-
├── current.json
|
|
410
|
-
├── partitions.json
|
|
411
|
-
├──
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
└──
|
|
357
|
+
├── current.json # 指针:当前分区键(守护行表达式经它搭桥)
|
|
358
|
+
├── partitions.json # 分区索引:项目 → 分区键
|
|
359
|
+
├── rescue/<uuid>.json # 两阶段 rescue 记录(profile 级;apply/restore 用)
|
|
360
|
+
└── projects/<分区键>/
|
|
361
|
+
├── journal.jsonl # 只追加:install / update / crash-detected / disable / restore / note
|
|
362
|
+
├── snapshot.json # 上次观测到的 { 插件名: 版本 }
|
|
363
|
+
├── state.json # 崩溃计数、自动关闭 / 已恢复名单
|
|
364
|
+
├── decision.json # 本轮要拦截的插件 + unresolved 残余(守护行表达式读 disable)
|
|
365
|
+
├── crashed # 崩溃哨兵(非零退出码时写下)
|
|
366
|
+
├── observation-*.json # 观测快照(指标数据源)
|
|
367
|
+
├── archive/ # 历史归档(搬走 + 留档)
|
|
368
|
+
└── backups/ # 关闭前备份的配置(versionedBackups 时带版本)
|
|
421
369
|
```
|
|
422
370
|
|
|
423
371
|
---
|
|
424
372
|
|
|
425
|
-
## 恢复流程
|
|
426
|
-
|
|
427
|
-
```
|
|
428
|
-
第 1 次崩溃
|
|
429
|
-
└─ 退出码非 0 → 写哨兵 + 决策(关闭最近更新的 1 个嫌疑)
|
|
430
|
-
第 2 次启动
|
|
431
|
-
└─ 决策文件已就位 → 嫌疑插件的模块不被加载
|
|
432
|
-
├─ 仍然崩溃 → 关闭数 +1(最近更新的 2 个)
|
|
433
|
-
└─ 启动成功 → 视为恢复
|
|
434
|
-
第 3 次启动(稳定)
|
|
435
|
-
└─ 自动重新启用除首要嫌疑外的插件
|
|
436
|
-
└─ 首要嫌疑保持关闭,等你确认后用 reenable 手动开启
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
**首要嫌疑**(最后被关闭的那个)会一直保持关闭,直到你明确用 `reenable` 开启它 —— 避免刚恢复就再次崩溃。
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
## 安全边界
|
|
444
|
-
|
|
445
|
-
本插件在设计上刻意保守:
|
|
446
|
-
|
|
447
|
-
- **只碰第三方插件**:`@deepseek-ai/*` 官方包永远不是嫌疑,harness 核心不会被关掉。
|
|
448
|
-
- **不碰自己**:`dsh-recency-guard` 永远不在嫌疑名单里。
|
|
449
|
-
- **决策文件缺失 / 损坏时一律放行**:表达式在任何异常下都返回 `false`,插件照常加载。守护机制**永远不会**把 profile 锁死在插件之外。
|
|
450
|
-
- **无法读取时不影响启动**:所有文件操作都包在 `try/catch` 中,失败只记录日志。
|
|
451
|
-
- **官方包与 harness 组件不受影响**:崩溃检测只影响"用户自己加的插件"这一层。
|
|
452
|
-
|
|
453
|
-
---
|
|
454
|
-
|
|
455
373
|
## 开发与测试
|
|
456
374
|
|
|
457
375
|
```bash
|
|
458
376
|
npm install
|
|
459
|
-
npm run build
|
|
460
|
-
|
|
461
|
-
npm
|
|
377
|
+
npm run build # esbuild 双产物:dist/index.js(宿主)+ dist/client.js(客户端)
|
|
378
|
+
npx tsc --noEmit # 类型
|
|
379
|
+
npm run lint # 类型 + 未使用符号
|
|
380
|
+
npm test # 分层运行器:Core 29 / Host 10 / Client 20 / Contract 7 = 68
|
|
381
|
+
npm run extract-runtime # Host 层测试前置(runtime/ 缺失时先解出)
|
|
462
382
|
```
|
|
463
383
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
```
|
|
384
|
+
- 当前基线:`npm test` **68/68 通过**、`npx tsc --noEmit` 0 错误(2026-11-11 实测)。
|
|
385
|
+
- 验证顺序固定:**build → typecheck → lint → test**,全部零错误才算完成。
|
|
386
|
+
- 文档体系与写码纪律见 [`docs/agents/`](docs/agents/README.md);
|
|
387
|
+
发布 / 升级 / 热重载见 [`docs/agents/update-guide.md`](docs/agents/update-guide.md)。
|
|
469
388
|
|
|
470
|
-
|
|
389
|
+
---
|
|
471
390
|
|
|
472
|
-
|
|
391
|
+
## 版本记录
|
|
473
392
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
393
|
+
| 版本 | 一句话 |
|
|
394
|
+
| --- | --- |
|
|
395
|
+
| **0.16.0**(2026-11-11) | 确定性冲突证据(4 类 finding + 出处)、贪心最小隔离与依赖联动、可写两阶段 rescue、常态路径锁卫生、PanelSnapshotView 可空契约;新增社区 manifest [`dsh-plugin.json`](dsh-plugin.json),README 面向用户重构,版本四锚点统一 |
|
|
396
|
+
| 0.15.0 | 架构重构:`host/` + `client/` + `shared/` 分层,client→host 越界与值依赖环写成契约测试 |
|
|
397
|
+
| 0.14.0 | 误伤反馈闭环、贝叶斯风险并行读数、预防性健康指标(EWMA / CUSUM)、自动化变异测试 |
|
|
398
|
+
| 0.13.0 | 决策因子快照、决策与展示排序口径统一、可选 peer 惰性解析(修安装即崩)、图谱结构洞察 |
|
|
399
|
+
| 0.12.1 | 崩溃信号第二条通道:哨兵盲区(SIGKILL / 断电)与 self-reload 判别 |
|
|
400
|
+
| 0.12.0 | 命令窗口显示接线、动作路由乐观并发(409)、L4 审计线、依赖代际对齐 |
|
|
401
|
+
| 0.11.x | 数据面安全(动作路由方法守卫)、跨分区只读快照、图谱交互补齐(边 / 小地图 / 触屏) |
|
|
402
|
+
| 0.10.0 | 马尔可夫转移矩阵、休哈特控制带、诊断投影与反馈入口 |
|
|
403
|
+
| 0.9.0 | 恢复置信分级(`confirmRounds`)、两阶段提交、离线 rescue CLI |
|
|
404
|
+
| 0.8.0 | 备份增强(版本时间线)、官方实验插件只观测、事件驱动变更检测 |
|
|
405
|
+
| 0.7.0 | 崩溃级修复(守护行 YAML 写入管线)、可交互图谱、可观测性白盒化 |
|
|
406
|
+
| 0.3–0.6 | 能力闭环双向比对、生命周期状态机、量化指标、多项目隔离、面板与图谱基础 |
|
|
407
|
+
|
|
408
|
+
长设计论证(为什么这样决策、数学模型、踩过的坑)已迁到
|
|
409
|
+
[`docs/agents/design.md`](docs/agents/design.md),不再堆在 README。
|
|
478
410
|
|
|
479
411
|
---
|
|
480
412
|
|
|
481
|
-
##
|
|
413
|
+
## 许可
|
|
482
414
|
|
|
483
|
-
MIT
|
|
415
|
+
MIT。见 [`LICENSE`](LICENSE)。
|