Skip to content
dsh.fish
Bundle

dsh-nuke-plugin

强力卸载 DSH 插件 — 策略分级 · 批量原子 · 指纹快照 · 健康检查 · 并发锁 · 先知问责 · 报告导出

Source
beijingwahw
stars
3 stars
License
MIT
Updated
Updated 5 days ago

Readme

# dsh-nuke-plugin

> DeepSeek Harness 的工业级 Nuke 环境清理引擎 — 事务回滚 · 崩溃自恢复 · 审计链 · 先知推演 · 混沌演习 · 贝叶斯自学习 · 预测存证问责 · 自我校准 · Thompson 探索

[![Release](https://img.shields.io/github/v/release/beijingwahw/dsh-nuke-plugin?color=blue&label=release)](https://github.com/beijingwahw/dsh-nuke-plugin/releases)
[![Tests](https://img.shields.io/badge/tests-758%2F758-brightgreen)](https://github.com/beijingwahw/dsh-nuke-plugin/actions)
[![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)](./tsconfig.json)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)

把"删除插件并清理残留"这件危险的事,做成一套**可验证、可撤销、可审计**的事务系统。


## 为什么需要它

dsh 的一切皆插件 —— 但插件的装卸会在 `.dsh/`、Nuke 目录、系统 TEMP 等处留下残留。手工清理容易误删,脚本清理不可逆,出了事无从追溯。本插件用数据库级的纪律来做这件事:

| 痛点 | 解法 |
|---|---|
| 删错无法挽回 | 每个动作自带 `validate / preview / execute / undo`,目录删除 = 原子改名进回收区 |
| 清理途中崩溃 | WAL 预写日志 + 备份区,`nuke_recover` 重放并反向补偿;`nuke_drill` 随时实战验证这条退路 |
| 出事无从追责 | hash chain 审计日志,任何篡改可被 `nuke_verify` 检出 |
| 并发清理打架 | 跨进程读写锁(O_EXCL + bootToken 归属核验 + guard 目录互斥) |
| 不知道能删多少 | 五因子评分 + 趋势回归 + 磁盘写满预测,先预演后执行 |
| 不知道"删了会怎样" | `nuke_oracle` 先知推演:基于历史执行数据预测事务成功率、期望回收、最脆弱步骤 |

## 安装

```bash
dsh plugin add beijingwahw/dsh-nuke-plugin --profile web
```

安装后直接对话即可,例如:

> 帮我扫描一下 web profile 的插件残留,先预演不要真删

## 安全纪律(设计原则)

1. **fail-closed** — 校验器/健康检查自身失败时同样拒绝操作,绝不"查不到就放行"
2. **路径 Containment** — 所有路径操作限制在授权目录内;txId 白名单 `[A-Za-z0-9_-]{1,64}` 防穿越注入
3. **TOCTOU 复验** — 分析与执行是两个时刻,执行前重验指纹(size + SHA-256 + mtime)
4. **诚实记账** — bytesSaved 只计真正释放的空间(nlink>1 的硬链接替换不虚增)
5. **保护名单 + 限额 + 黑窗** — 作为引擎 pre-hook veto,超限即拒绝(纵深防御,不依赖单层检查)
6. **回收区代替物理删除** — commit 后才允许 purge;restore 失败或存在孤儿产物时绝不 purge

## 工具速查(25 个)

所有工具注册为 dsh Agent 工具,安装后直接让 Agent 调用即可。

### 感知 — 先看清现状

| 工具 | 说明 |
|---|---|
| `nuke_list` | 列出 profile 下已安装的第三方插件 |
| `nuke_scan` | 残留扫描(配置引用/目录/TEMP),五因子评分 + 可回收空间统计;省略插件名进入全局模式 |
| `nuke_deps` | 依赖关系检测:谁引用了目标插件(删除前必查) |
| `nuke_orphans` | 全局孤儿扫描:node_modules 未声明包 / 无主附件 / TEMP 过期条目 |
| `nuke_health` | 健康检查:config/dependency/runtime/residue 四组,critical 失败自动阻断清理 |

### 决策 — 评估风险与收益

| 工具 | 说明 |
|---|---|
| `nuke_blastradius` | 爆炸半径沙盘推演(what-if,零副作用):删除会损坏谁、可级联谁、风险几级 |
| `nuke_strategies` | 查看三级策略(safe / balanced / aggressive)的动作集 |
| `nuke_policy` | 查看守卫配置:保护名单 / 批量上限 / 回收上限 / 磁盘下限 / 时间黑窗 |
| `nuke_trend` | 历史趋势:字节/天变化率、30 天外推、3σ̂ 异常检测(失控写盘早期信号) |
| `nuke_forecast` | 磁盘写满预测:趋势 × 实时余量 → 倒计时与分级建议 |
| `nuke_oracle` | **先知推演**:概率化后果预测——事务成功率、期望回收(校准分布修正)、最脆弱步骤、爆炸半径、磁盘倒计时延长、预计耗时(p50 与悲观 p90)、下行风险 CVaR₁₀、Thompson 探索口径与信息价值排序(建议先执行哪步以最快积累证据);基于历史执行数据贝叶斯自学习 + 从战绩自我校准,零副作用不拿锁 |
| `nuke_failures` | **失败档案**:每类动作的历史失败模式诊断(EBUSY 锁定/超时/权限/校验拒绝…)、瞬态份额与处方;⚡瞬态引擎自动重试、🔒永久需人工介入 |
| `nuke_scorecard` | **先知战绩对账单**:执行前已存证进 hash chain 的预测(成功率/耗时)vs 实际结局——Brier 技能分(对照无技能基线)、逐步命中明细、耗时偏差分布、重试疗效学习值、系统性偏差诊断与自我校准位移;回答"先知的数字到底可不可信、偏在哪、纠了没有" |

### 执行 — 事务化清理

| 工具 | 说明 |
|---|---|
| `nuke_clean` | 事务化强力卸载:健康闸门 → 独占锁 → 计划 → 预演/提交;失败自动 Saga 回滚 |
| `nuke_dedup` | 内容寻址去重:三级瀑布(尺寸 → 采样指纹 → SHA-256)分析,`apply=true` 时硬链接实收 |
| `nuke_restorepoint` | 配置还原点:list / create / restore / prune |

### 恢复与审计 — 出事有退路

| 工具 | 说明 |
|---|---|
| `nuke_status` | 查询事务状态:带 tx_id 返回步骤明细与回收统计;省略 tx_id 列出活跃事务与崩溃残留的未终结事务 |
| `nuke_locks` | 锁诊断(零副作用):全部锁文件的持有者现场 —— 进程存活 / TTL 状态 / PID 复用甄别 / 自动回收倒计时;E_LOCK_HELD 排障第一工具 |
| `nuke_recover` | 崩溃恢复:扫描未终结事务的 WAL,反向补偿恢复到执行前状态 |
| `nuke_verify` | 审计链完整性校验(hash chain 任何篡改均可定位) |

### 运维 — 日常保养

| 工具 | 说明 |
|---|---|
| `nuke_doctor` | 一键全科体检:健康 + 残留 + 孤儿 + 评分 → P1/P2/P3 优先级处方 |
| `nuke_guardian` | 守卫者巡检:磁盘倒计时 / 趋势异常 / 未终结事务 → 带建议的分级告警 |
| `nuke_gc` | 备份 GC:按宽限期(默认 14 天)+ 空间配额清理已终结事务的备份区,未终结事务永不淘汰;dir-move 隔离量结算为真实物理回收(台账 pending→freed) |
| `nuke_ledger` | 空间台账:每字节回收可溯源,按动作/profile/日聚合,freed/pending 双轨 |
| `nuke_drill` | **混沌演习**:沙箱中执行真实事务 → 第 N 步后模拟"断电"(不回滚、锁悬挂)→ 走真实恢复路径 → 逐项验证数据字节级还原 / 审计链完整 / WAL 终结 → 签发崩溃安全证书 |

## 典型工作流

### 第一次清理(推荐路径)

```
1. nuke_scan                    # 看清残留与可回收空间
2. nuke_oracle                  # 先知推演:做了会怎样(成功率/期望回收/最脆弱步骤)
3. nuke_blastradius [插件]       # 零副作用推演:会不会误伤
4. nuke_clean --dry_run true    # 预演:只出计划,不动文件
5. nuke_clean                   # 执行:失败自动回滚,全程审计
```

### aggressive 策略(需要确认令牌)

```
nuke_clean --strategy aggressive \
           --confirmation_token "CONFIRM:web:<plugin-a>,<plugin-b>"
```

### 崩溃后恢复

```
1. nuke_status                  # 查看未终结事务(省略 tx_id = 清单模式)
2. nuke_recover                 # WAL 重放 + 反向补偿
3. nuke_verify                  # 校验审计链完整性
```

### 日常保养

```
nuke_guardian                   # 一键巡检,输出带建议的告警
nuke_forecast                   # 磁盘还能撑几天
nuke_drill                      # 定期混沌演习,确认崩溃退路始终有效
```

## 核心创新:会自我学习的清理引擎

传统工具的"预演"只能告诉你"我打算做什么"。本插件更进一步——用历史执行数据回答"**做了会怎样**",并用真实崩溃验证"**出了事能否退回**"。

### 先知引擎(nuke_oracle)— 概率化后果推演

dry-run 是确定性预演,先知是概率化推演。每次清理的每个步骤都会入审计链,先知从中学习:

- **贝叶斯可靠性模型**(经验贝叶斯收缩):每个动作的成败率向全局均值收缩——
  `p̂ = (s + κ·μ) / (n + κ)`。执行过 100 次的动作自信报数,只跑过 1 次的动作自动向全局均值靠拢,不会被单次运气带偏
- **设计先验冷启动**(V5.1.1 修复):零历史时全局均值向设计先验 0.95 收缩而非硬币 0.5 ——
  事务引擎 validate 前置 + 快照备份 + 回滚保护,步骤失败是设计上的例外。旧硬币先验在 Saga 连乘下指数塌缩(4 步 6%),把"零信息"误渲染成"高故障";现在零历史 3 步事务报 85.7%,且置信度诚实标 low、逐步明细标 🧭(纯先验)、CI 仍宽开(Wilson 不假装知道)。约 20 次全局观测后历史数据权重过半,先验自动让位
- **校准分布**:追踪"预估回收 vs 实际回收"的比率历史,用中位数修正乐观估计——预演说能回收 1GB,历史上实际只有 90%,先知就按 90% 报
- **事务成功率**:各步骤成功概率连乘,一眼看出整条链的把握有多大
- **期望回收**:`Σ(步骤回收量 × 校准系数) × 事务成功率`——不是"最多能回收多少",是"预期能回收多少"
- **最脆弱步骤**:成功率贡献最小的一环,建议先修它(比如先解依赖再清理)
- 零副作用:影子上下文执行 preview,不拿锁、不落盘

### 混沌演习(nuke_drill)— 崩溃安全证书

"有恢复机制"和"恢复机制真的有效"是两回事。演习不承诺,只验证:

```
沙箱搭建 → 真实事务执行 → 第 N 步成功落盘后模拟进程死亡
       (跳过回滚、跳过锁释放——最恶劣的崩溃现场)
→ 模拟重启 → 走真实 nuke_recover 路径 → 逐项验证:
   ✓ 崩溃注入生效          ✓ 事务完整回滚
   ✓ 数据字节级还原         ✓ 审计链完整(hash chain)
   ✓ 新事务畅通无阻塞       ✓ WAL 正确终结
→ 通过则签发崩溃安全证书(含耗时与验证明细)
```

随时可跑、不触碰真实环境。升级、改配置、怀疑人生时,跑一次就知道退路还在不在。

### 数据闭环

```
执行(审计链记录每步成败与预估/实际)
   → 可靠性模型(贝叶斯学习:动作成功率 + 校准分布)
      → 先知引擎(预测下次:成功率 / 期望回收 / 最脆弱步骤)
         → 决策(先修最弱步骤,或换 safe 策略)
            → 再执行 → 数据更准 → ...
```

## V5.6 探索智能:从纯利用到知情探索,从期望值到下行风险

V5.5 之前的学习系统有一个结构性死锁:**所有预测取后验均值,决策永远偏向历史证据充分的动作**——新动作/新尺寸桶收缩向先验,在均值口径下永远竞争不过"老将",于是永远不被执行、永远没有数据、先验永远不被修正(多臂老虎机的"富者愈富")。V5.6 用两个世界级机制补全决策智能的最后两块:

### Thompson 受控探索(后验采样决策)

```
纯利用(旧):决策 = argmax 后验均值      → 富者愈富,新动作饿死
Thompson(新):决策 = argmax 后验抽样 p̃  → 后验宽(数据少)的动作
                                          偶尔被抽得很高 → 获得执行机会
                                          → 产生数据 → 后验收窄
                                          → 探索/利用比例由不确定性自动调节
```

- `sampleBeta`:Marsaglia-Tsang Gamma + Box-Muller 的种子化 Beta 采样(零依赖,逐位可复现)
- 可靠性模型暴露最终层 Beta 后验参数(与均值点估计同源,桶调制后即桶层后验)
- `nuke_oracle` 输出**探索口径**(采样成功率 vs 均值成功率并列)与**信息价值排序**:`不确定敞口 = 后验 σ × 失败敞口`——"这步的不确定度值多少字节",数据最少、牵扯最大的步骤最先被建议执行
- 探索是**建议不是行为**:执行决策权仍在用户/Agent,种子固定可复现

### CVaR₁₀ 下行风险(最差 10% 情形能剩多少)

蒙特卡洛分布不止报 P10/P90 悲观-乐观带,新增**条件风险值**:最差 10% 抽样的平均回收。Saga 全或无语义下成功率 > 90% 时尾部由失败回滚(=0)过渡到最小的成功抽样——诚实回答"最坏情形我能接受吗",而不是只给让人舒服的期望值。

## V5.5 自我校准:对账不止打分,还驱动再学习

V5.4 让预测可问责(存证 + Brier 对账),但问责本身不改善预测——先知报 95% 实际只有 60%,计分器只是把这件尴尬的事写下来。V5.5 闭环最后一段:**从已对账的 (预测, 结局) 对学习系统性偏差,动态修正未来预测**:

```
预测 → 存证(hash chain)→ 执行 → 对账(Brier/技能分)
   ↑                                      ↓
   └──── 校准位移 δ 修正未来预测 ←── 从残差学习 δ
              (过自信 → δ<0 拉低;过保守 → δ>0 拉高;
                残差消失 → δ→0,迭代收敛的终点)
```

### 学什么:Platt 截距式校准

对账侧(`nuke_scorecard` 同源逻辑)从步骤级 (预测, 结局) 对学习:

```
meanPred = 存证均值          actualRate = 实际率(Laplace +1/+2 收缩)
δ_raw = logit(actualRate) − logit(meanPred)     ← 系统性偏差的 logit 口径
δ     = δ_raw · w,  w = n/(n+K)                 ← 证据权重收缩(K=8)
```

- **证据纪律**:已对账步骤 < 5 → 不修正(没有统计力就不动,诚实留白)
- **钳制**:δ ∈ [−5, +5];修正后 p ∈ [0.001, 0.999]
- **耗时同理**:中位耗时比(实际/预测)向 1 收缩为修正因子,钳制 [0.25, 4]——预测系统性偏乐观 3× 就放大 3×(按证据权重打折)

### 用在哪:写侧与读侧同源

- **引擎存证(写侧)**:commit 前的预测存证直接落校准后口径,`detail` 记录 `calibrationDelta` / `calibrationEvidence`——存证与推演同一套修正,对账才有收敛意义
- **先知推演(读侧)**:`nuke_oracle` 逐步与事务成功率给出校准后口径,叙事直白交代病史:`自我校准后成功率 74%(历史预测过自信:存证均值 90% vs 实际 55%,12 步证据 → logit 位移 −0.75)`
- **故障纪律**:校准器抛错 → 恒等存证/恒等推演(学习失败绝不阻断真实清理);未注入 → V5.4 语义完全兼容

### 为什么这样设计

- **logit 空间线性**——概率靠近 0/1 时偏差被天然放大(0.99→0.95 与 0.6→0.56 的"严重性"不可同日而语),logit 位移对此无偏
- **证据收缩而非全信**——6 步证据只信 43%(w=6/14),50 步信 86%;小样本的极端战绩不会把预测甩飞
- **存证口径 = 推演口径**——若存证用原始值、推演用校正值,对账永远学不到真残差,闭环退化成摆设

## V5.4 先知问责制:预测若不可证伪,就与巫术无异

V5.3 之前,先知在事务执行前报出"成功率 87%",但没有任何机制核对这句话:预测过了就过了,说 60% 报 95% 无人知晓。V5.4 给预测装上**存证 + 对账**两翼,先知从"预测者"升格为"可问责的决策顾问":

```
commit 前(写侧):预测存证
   逐步预测(predictedP / estimatedBytes / predictedDurationMs)
      + 事务级成功率 → 写入 hash chain 审计链
   ✓ 预测先于结局(时间戳为证)   ✓ 事后不可篡改(链哈希)
   ✓ 统计增强能力:构建/存证失败只记日志,绝不阻断真实清理

执行后(读侧):nuke_scorecard 对账
   预测存证 × 步骤结局 × 事务终结 → 三方证据对账
      → Brier 分(预测校准度的事实标准)
      → 技能分 SS = 1 − Brier/Brier_baseline(对照"无技能基线":
        总是预测平均成功率的家伙 —— 跑赢他才算有本事)
      → 耗时偏差分布(预测 p50 / 实际耗时 的比率中位数)
      → 逐步命中明细(预测 0.87 的那步,究竟成了没有)
```

### 耗时模型:从"会不会成"到"要等多久"

- 每动作学习耗时分布(时间加权 p50/p90,半衰期 30 天,墙钟口径含重试退避等待 —— 用户等的就是这个数);成败双向计入(失败步骤的耗时同样是"这步要多久"的证据)
- `nuke_oracle` 报告新增**预计耗时**(各步 p50 之和)与**悲观上界**(各步 p90 之和,"每步都跑在最慢 10%");任一步零历史 → 整体 null **诚实留白**(不用先验冒充耗时证据)

### 重试疗效学习:常数 0.5 退役

V5.3 假设"单次重试对瞬态失败的成功率是 0.5"——一个没有证据的常数。V5.4 用引擎自己的历史成绩说话:

```
营救池 = 审计链中所有 retries ≥ 1 的步骤
   → 营救率 r̂ = (rescued + a·r₀)/(pool + a)(向先验收缩,a=4)
   → 反解单次疗效 ê = 1−(1−r̂)^(1/R)(R=引擎重试上限)
   → 投影 p_adj = p + (1−p)·t·(1−(1−ê)^R)
```

疗效观测惨淡(比如 EBUSY 常驻锁 8 次重试 0 次救回)→ 学习值自动拉低投影,先知不再对无效重试抱有幻想;零观测时退回 0.75 总营救率先验(与 V5.3 默认一致)。严格往返保证:`r̂=0.64, R=2 → ê=0.4 → 复合回 1−(1−0.4)²=0.64`。

## V5.3 失败模式智能:从"会挂"到"为什么挂、怎么办"

V5.2 之前,系统学习"这步会挂"(概率),但不学习"以什么方式挂、挂了怎么办"。失败被回滚后,下一次清理迎面撞上同一个失败。V5.3 闭环了**预测 → 诊断 → 处方 → 自愈 → 再学习**:

```
失败分类学(契约层单一事实源)
   ├── 分类器:错误文本 → 10 种规范模式(locked/timeout/resource/space/
   │   vanished/permission/validation/dependency/io/unknown)
   ├── 瞬态性:transient(EBUSY/超时/句柄…重试有救)vs permanent(校验/权限/依赖…重试纯浪费)
   └── 处方:每个模式一条人类可读的修复指引
        ↓ 写方(引擎)与读方(模型)共享 —— 分类规则永不漂移
   ├── 引擎:步骤级模式感知重试(瞬态 → 有界指数退避自动重试;永久 → 立即失败快速回滚)
   ├── 模型:从审计链学习每动作的失败模式分布 + 瞬态份额
   │         → 重试调整成功率 p_adj = p + (1-p)·t·(1-(1-e)^R)
   └── 先知:重试感知事务成功率(两档口径并列)+ 最脆弱步骤的模式诊断与处方
             + 计划合成候选取重试调整口径(预测与引擎真实行为对齐)
```

三个关键设计:

- **模式感知重试,不是盲目重试**——EBUSY(文件被占用)稍后自愈概率高,指数退避后重试(默认 2 次、退避 150ms 起步、单次等待上限 2s);`E_VALIDATION`(策略拒绝)重试一万次结果相同,立即回滚省时间。命令级重试(exec-ops 的 spawn 错误)之上补齐了步骤级(fs/edit 操作失败同样覆盖)
- **投影不双重计息**——基础 p 取经验值(历史若已含重试自愈效果则一并计入),重试调整投影建立在经验之上:`p_adj = p + (1-p)·t·(1-(1-e)^R)`(t=瞬态份额,R=重试上限,e=单次重试成功率默认 0.5)。引擎一直开着重试时投影收敛于经验值,永不发散
- **审计即学习数据**——引擎把 `retries` 与 `failureMode` 写进步骤审计 detail;可靠性模型优先读显式 failureMode(新条目),缺失时从 error 文本现场分类(旧条目兼容)—— 迁移零成本

`nuke_oracle` 输出升级:**♻️ 重试感知成功率**(两档口径并列)、逐步推演附**模式画像**(`locked⚡80%` = 80% 的历史失败是锁定、瞬态可自愈)、最脆弱步骤附**🩺 主导失败模式 + 💊 处方**。新工具 `nuke_failures` 给出全部动作的失败档案。

## V5.2 决策智能:帕累托计划合成(先知从"预测者"到"决策顾问")

先知此前只回答"这个事务多危险";V5.2 让它回答"那我该怎么办"。

### 计划合成器(Optimizer)

在成功率 × 回收量的双目标上合成**帕累托最优**的动作子集(Saga 语义:`P(S)=∏p_i`,`E(S)=P·Σw_i`):

```
求解(世界级惯例:小规模精确、大规模启发式):
  n ≤ 16 → 2^n 精确枚举(65,536 子集,毫秒级)→ 数学最优前沿
  n > 16 → 贪心剔除序列(按 bytes/pct 性价比)+ 2-swap 局部改善

三种问法(同一前沿):
  max-reclaim {minSuccess}  → 成功率达标下回收最大(概率背包)
  max-success {minReclaim}  → 回收达标下成功率最大
  pareto                    → 全前沿 + 拐点推荐(边际收益崩塌处)
```

两个数学事实贯穿设计:

- **全集不一定帕累托最优**:`E=∏p·Σw` 下,剔除"低成功率大动作"可能同时提升两目标(成功率大涨、回收微降)——推荐计划可能优于"全都要"
- **空集不是解**:不清理就无需跑事务,解空间从首个非空子集开始

**可解释性**:每个被剔除动作附带账单——`+2.1pct 成功率 / 代价 340MB(162MB/pct)`,推荐不是黑箱。

### 操作级成功率:大小分桶(三层收缩)

"remove-node-modules 的成功率"是动作级粗粒度——**删 2GB 和删 5MB 的失败模式完全不同**(EBUSY/长路径/超时集中于大目录)。V5.2 引入协变量调制:

```
四层收缩:桶 → 动作 → 全局 → 设计先验
  桶边界:<1MB(small)/ 1MB~100MB(medium)/ ≥100MB(large)
  桶层:α_b = p_action·κ_b + s_b(κ_b=5,桶样本被三桶摊薄 → 更快向动作层让位)
  失败样本同样归桶(审计失败事件已带 estimated)→ 双向归桶无偏
  桶内零样本 → 调制不生效(诚实返回动作层估计,sizeBucket.selfWeight=0)
```

`nuke_oracle` 的逐步推演与计划合成全部使用操作级成功率,`nuke_oracle` 输出新增**帕累托前沿阶梯**(激进端→保守端,★ 标推荐点)与剔除理由清单。

## V5.1 长期方案:外部工具治理(单一事实源)

真实故障复盘:dsh CLI 经 nvm 安装,用户 shell 的 rc 文件注入 PATH 而宿主进程不加载 rc → 宿主 PATH 缺口 → `spawnSync('dsh')` ENOENT。此时系统中有**三处独立探测**(健康检查 / standard-remove / pnpm-prune)各自解释"什么算可用",一处误报 critical 即阻断全部清理 —— 即便 dsh 实际就装在 `~/.nvm/versions/node/v24/bin/dsh`。

长期方案把外部工具解析收敛为**一份实现、一个事实源**:

### 工具注册表(ToolRegistry)

```
解析链(顺序固定,全系统只此一份):
  ① 显式环境变量 DSH_BIN / PNPM_BIN
     → 用户显式指定的路径失效时响亮报错,绝不静默降级
  ② 裸名探测(PATH 语义)
     → exit 0 = ok;exit 非 0 但进程已执行 = ok(旗标差异不算缺失)
  ③ spawn ENOENT → 全局 bin 候选目录救援(nvm/volta/asdf/npm 前缀)
     → 救援命中 = rescued(附宿主 PATH 修复提示);全落空 = missing
```

治理原则:

- **语义漂移在结构上不可能** —— 健康检查、standard-remove、pnpm-prune、doctor 全部委托同一注册表,"什么算可用"只存在一份定义
- **能力映射降级** —— 每个工具声明 `affects`(依赖它的动作清单);缺失时只降级这些动作并给出 `fixHint`,**永不全局阻断清理**
- **TTL 缓存(60s)** —— 一次事务内多次探测共享结果;环境变化后可 `invalidate()` 强制重解析
- **逃生通道** —— `DSH_BIN` / `PNPM_BIN` 环境变量显式指定路径,绕过 PATH 缺口

### doctor 环境矩阵

`nuke_doctor` 报告新增**环境矩阵**:全部已注册外部工具的解析结果(状态 + 来源 + 路径 + 版本 + 影响面 + 修复建议),与 runtime 健康检查同源(共享注册表缓存)—— 两处输出永远一致,排查环境问题一次到位。

```
─ 环境矩阵(外部工具)─
  ✅ dsh: 版本: 0.1.0-rc.6
  🟡 pnpm: 可用: 9.12.0(救援路径 /home/t/.nvm/.../bin/pnpm;宿主 PATH 未含该目录,建议修复)
  ❌ node: node 命令未找到(宿主 PATH 与常见全局 bin 目录均无 node)
     🔧 安装 node 或将其所在目录加入 PATH
```

## V5 全模块升级总览

V5 聚焦 V4 未覆盖的模块与一处真实整合缺口,全部向后兼容,零新增运行时依赖。

### 关键修复:V4 整合缺口(真实缺陷)

V4 在契约中定义了 `freezeWindows`/`maxFilesPerTx`,但守卫从未执行(`hitFreezeWindow` 零调用、`fileCount` 无人供给)。V5 补全完整链条:

- **FREEZE_WINDOW**:`hitFreezeWindow` 纯函数(跨零点/多窗支持)接入 policy-guard 首查
- **TOO_MANY_FILES**:`dirStats`(一次遍历产出字节+文件数)→ fs-ops/edit-ops preview 填充 `OperationPlan.fileCount` → commit 前预飞 dry-run 汇总 → 守卫第二道闸门
- **commit 前预飞复查**:执行前零副作用预演拿真实文件数再过策略(预演结果同时预热 estimates,零额外成本)

### infra 剩余模块

| 模块 | 升级 |
|---|---|
| policy-guard | 冻结窗/文件数上限真正执行;策略文件加载校验(非法配置 fail-closed 忽略并定位到字段级 issue);全部违规附带人类可读修复建议 |
| path-resolver | NFC Unicode 归一(杜绝同形异码绕过白名单);控制字符路径拒绝;darwin/win32 大小写不敏感白名单匹配 |
| validator | `validateAll` 批量校验一次返回全部错误;profile 字符集与插件名对齐 |
| logger | 结构化 JSONL 模式(机器可读);`child(bindings)` 上下文子日志器 |
| reporter | Markdown/JSON 报告汇总统计区(按动作分组回收量、成功率、总量) |

### engine 剩余模块

| 模块 | 升级 |
|---|---|
| transaction-engine | dry-run 预览有界并发(默认 4,输出顺序稳定);commit 每步耗时进审计 detail |
| hook-registry | 钩子优先级排序;单钩子错误隔离(veto 仍立即短路);注册级超时 |
| blast-radius | 直接/传递依赖方分层(1 跳 vs 2+ 跳);按 profile 影响计数 |
| orphan-detector | 多 profile 检测并行化(输出稳定排序) |
| restore-point | `maxPoints` 保留策略(在用还原点宁可多留不误删);创建后读回 hash 校验(fail-closed) |
| health-inspector | 四组检查并行执行(组序稳定);inode 压力检查(探测不到标记 skipped) |

## V4 全模块升级总览

V4 对五层架构的每个模块做了系统性升级,全部向后兼容(API 只增不改),零新增运行时依赖。

### infra 基建层

| 模块 | 升级 |
|---|---|
| 审计链 | `appendMany` 批量追加共享一次 fdatasync;`verifyIncremental` 从可信锚点增量校验(锚点失配/截断攻击均 fail-closed) |
| WAL | 已终结事务归档至 `archive/`(replay 仍可读,扫描只扫活跃区);尾部半行自动截断修复(中间行损坏拒绝修复);父目录 fsync |
| 锁 | 等待重试升级指数退避 + 等值抖动(防惊群);`autoRenewMs` 后台心跳自动续期 |
| 备份区 | `restoreAll` 依赖分层并行恢复(同层并发、层间串行);恢复后 size/hash 指纹复验 |
| fs-utils | 统一 `walk()` 流式遍历原语(AbortSignal/深度限制/不走 symlink);`withTransientRetry` 瞬态错误退避重试(EMFILE/ENFILE/EBUSY) |
| 扫描缓存 | 命中刷新 LRU 热度(热条目不因 TTL 被逐);容量上限驱逐 |
| 可靠性模型 | Wilson score 可信区间(小样本天然有界);校准分位数指数时间加权(近期样本权重更高) |

### engine 引擎层

| 模块 | 升级 |
|---|---|
| 先知引擎 | 蒙特卡洛模拟(带种子可复现,2000 次抽样)输出回收 P10/P50/P90 分布;最脆弱步骤附带"修复收益"量化 |
| 趋势追踪 | 时间加权 Theil-Sen(近期样本权重更高);CUSUM 变点检测识别增长率突变;30 天预测区间 |
| 磁盘预测 | 写满倒计时 95% 置信区间(不确定性传播),分级按区间悲观侧判定 |
| 评分器 | 五因子权重可配置,输出各因子贡献度明细(解释性) |
| 依赖图 | 文件指纹缓存(mtime+size),未变文件解析结果增量复用 |
| 残留扫描 | 迁移至流式 walk(可中断);进度事件限频防风暴 |
| 去重 | 采样指纹升级头+中+尾三段(大文件中部参与指纹,降低碰撞误判) |
| 混沌演习 | `matrix=true` 崩溃注入点矩阵(plan 后/第 1 步后/第 2 步后),每点独立验证签发证书 |
| 守卫者 | 告警去重键 + 抑制窗口;"全部被抑制"不再谎报"一切正常" |

### operations / contracts 层

| 模块 | 升级 |
|---|---|
| exec-ops | 外部命令瞬态重试(指数退避)+ 超时硬上限 fail-closed;stdout/stderr/exitCode/durationMs 结构化捕获进审计 |
| fs-ops | preview 附带目录 top-N 大文件/子目录影响面明细 |
| edit-ops | 幂等化(引用不存在 → skipped 语义,不报错不产生空操作);YAML 摘除字节级保持(注释/顺序/CRLF 原样透传) |
| 策略编译 | 动作集元数据化(riskLevel + 描述,表驱动);`makeOperationPlan` 零副作用计划预览 |
| 契约增量 | `freezeWindows` 多重时间黑窗、`maxFilesPerTx` 文件数上限、`DryRunReport.actions` 动作级明细(含风险分级与跳过标记) |

### 事务引擎与工具接线

- dry-run 报告填充动作级明细:`nuke_clean --dry_run` 直接输出风险分级的动作清单(🟢/🟡/🔴)与幂等跳过标记
- `nuke_oracle` 输出蒙特卡洛分位数;`nuke_trend` 输出变点与预测区间;`nuke_forecast` 输出置信区间;`nuke_drill` 支持 `matrix` 参数

### 独立 CLI

- **锁协议对齐 V4**(关键安全修复):此前 CLI 的 `.nuke.lock`(V3)与插件 `.nuke/locks/`(V4)互不感知,并发清理可能交叉写;现在 CLI 与插件共享同一锁目录、文件格式与破锁纪律(O_EXCL + bootToken 归属 + 死亡且过期才破锁)
- `--json` 机器可读输出(scan/deps/health/sweep,CI 友好);`--version`;崩溃兜底(未捕获异常 fail-closed 退出并引导提 issue)
- 遍历 symlink 防护 + 深度限制(防目录环/逃逸);瞬态 IO 退避重试;修复 `strategies` 输出 undefined 的缺陷

## 事务生命周期

```
nuke_clean
   │
   ├─ 健康检查闸门(critical 失败 → 拒绝;检查本身失败 → 同样拒绝)
   │
   ├─ begin: 独占锁 + 事务 ID + WAL 开档
   │
   ├─ plan: 依赖校验 / 令牌校验 / 策略守卫(保护名单/上限/黑窗 veto)
   │
   ├─ dry_run? ── 是 ── 输出计划明细 → rollback 释放(零副作用)
   │
   ├─ commit(每步均经 WAL):
   │     step-intent → 备份/stage → 副作用 → 事后断言
   │        │ 成功 → 下一步
   │        │ 失败 → Saga 反向补偿(undo 逆序)→ rollback
   │
   └─ finalize: 摘要缓存 → 释放锁 → 审计入链(hash-linked)

崩溃窗口(任意时刻断电/被杀):
   下次 nuke_recover → WAL 重放 → 备份区逆序 restore → 全部成功才 purge
   restore 有失败或孤儿产物 → 保留备份,保持"未终结",等待人工/重试
```

## 架构

```
src/
├── contracts/   # 契约层:先定义接口再实现;Result 类型消灭异常控制流
├── infra/       # 基建:WAL / 读写锁 / 备份区 / hash-chain 审计 / 台账 / 校验器 / 贝叶斯可靠性
├── engine/      # 引擎:事务 / 扫描 / 评分 / 依赖图 / 去重 / 趋势 / 守卫 / 还原点 / 先知 / 混沌演习
├── operations/  # 命令模式:每个动作自带 validate/preview/execute/undo
├── runtime.ts   # 运行时组装:全量依赖注入的唯一场所
├── tools/       # 工具注册层:感知 / 决策 / 执行 / 恢复保障四域 23 工具
└── index.ts     # 插件入口(纯组装,零业务逻辑)
```

数据落盘位置:`<dshHome>/.nuke/`(wal/ backups/ audit/ ledger/ history/ policy.json restore-points/)

## 开发

```bash
git clone https://github.com/beijingwahw/dsh-nuke-plugin
cd dsh-nuke-plugin
npm install
npm run typecheck    # tsc --noEmit(零错误)
npm run lint         # eslint 严格基线(strictTypeChecked,零告警门禁)
npm test             # vitest(758 用例 / 47 文件)
npm run build        # tsdown 构建
npm run dev          # 开发期热更新进程(见下)
```

### 热更新(HMR)

| 层 | 方法 | 生效范围 |
|---|---|---|
| 运行配置 | 编辑 dsh 用户层 `cordis.patch.yml`(`~/.dsh/profiles/<name>/` 或 `~/.dsh/`),保存即生效 | dsh 原生监视用户层,事务性重载该行(bundle 层默认值已全量列出,照抄整行覆盖即可) |
| 开发期代码 | `npm run dev` 起独立 cordis + HMR 进程 | 保存 `src/` 下任意文件或 `cordis.yml` → 旧实例卸载(effect 回卷)→ 新代码挂载,无需重启 |
| 安装产物 | 改代码 → `npm run build` → 重新 `dsh plugin add` → 重启 dsh | 更新已安装的插件 |

`npm run dev` 的组成:仓库根 `cordis.yml` 依次挂 logger / timer / hmr / 宿主桩 / 本插件(直接加载 `src/index.ts`);
`dev/host-stubs.ts` 提供 dsh 宿主 `tools` 服务的最小桩(本插件 inject `['tools']`,缺桩会永远 PENDING)。

> 注意:开发基线为 Node ≥ 24.11(已在 `package.json` 的 `engines` 声明,npm 安装时自动校验)。早期 24.x(如 24.1.0)的 Node 内部接口与 cordis-plugin-loader 1.0.2 不兼容(表现为 HMR 编辑文件不触发重载),且不满足 tsdown 0.22 的引擎要求。

## FAQ

**Q: 清理会物理删除我的文件吗?**
目录删除是原子改名进备份区(`rename`,跨设备回退 copy),commit 后 purge 前可 `nuke_recover`。restore 未全部成功或存在孤儿产物时,引擎拒绝 purge —— 这些产物可能是数据唯一副本。

**Q: 去重的硬链接安全吗?**
verify-then-link:canonical 与 victim 执行前重算 SHA-256 复验;跨文件系统(st_dev 不同)、符号链接、mtime 变化的 canonical 一律跳过。替换是 `link→tmp→rename` 原子操作,无空窗;journal 记录每一步,可 `undo` 复制回独立文件。

**Q: 趋势预测为什么用 Theil-Sen 而不是最小二乘?**
最小二乘 breakdown point 为 0% —— 单个离群点(一次异常写盘)就能把斜率拉偏,污染写满倒计时。Theil-Sen(成对斜率中位数)breakdown point 29.3%,配合 MAD×1.4826 稳健 σ,近三分之一数据被污染时预测仍然正确。

**Q: 多个 dsh 实例同时清理会怎样?**
`nuke_clean` 持有跨进程独占锁(O_EXCL 原子获取 + bootToken 归属核验 + 固定名 guard 目录互斥),后到者等待或失败,绝不会交叉写。

**Q: 先知的成功率预测为什么用贝叶斯收缩,而不是直接用历史频率?**
只跑过 1 次且恰好成功的动作,频率是 100%——但没人敢信。经验贝叶斯收缩 `p̂ = (s + κ·μ) / (n + κ)` 把小样本拉向全局均值:数据越多越自信,数据越少越保守。这与保险精算、A/B 测试平滑是同一套方法论。

**Q: 刚装好还没清理过,先知报的事务成功率可信吗?**
可信,且要看懂它的口径。零历史时每个动作的成功率收缩向**设计先验 0.95**(V5.1.1 起)——依据是引擎本身的设计:validate 前置把失败拦在 commit 之前、编辑前快照备份、目录改名进回收区、Saga 回滚。所以"没跑过"≠"五五开",3 步事务报 0.95³≈85.7% 而不是 0.5³=12.5%。同时它诚实标注:置信度 low、纯先验步骤标 🧭、CI 宽开。跑过约 20 次清理后历史数据权重过半,预测由你的真实历史主导。若你的环境确实更脆弱,可在可靠性模型注入 `priorSuccessProbability` 调低锚点。

**Q: nuke_scorecard 的技能分是什么口径?负分说明先知在瞎猜吗?**
Brier 分 = (预测概率 − 实际结局)² 的均值(0 完美、0.25 硬币水平)。但绝对值没有参照系,所以战绩单以**无技能基线**为对照:一个总是预测"历史平均成功率"的傻瓜预测器的 Brier 分。技能分 SS = 1 − Brier/Brier_baseline:1 = 完美校准,0 = 不比傻瓜强,负 = 比傻瓜还差。样本 < 2 时诚实显示 n/a —— 对账没有统计力时绝不给出误导性结论。

**Q: nuke_oracle 和 nuke_clean --dry_run 有什么区别?**
dry-run 回答"我打算做什么"(确定性计划明细);先知回答"做了会怎样"(概率化后果:成功率、期望回收、最脆弱步骤)。两者互补:先知看趋势,dry-run 看细节。

**Q: 混沌演习会在我的真实环境里制造崩溃吗?**
不会。演习在 `<nukeRoot>/drill/<runId>/` 沙箱内进行——用一份合成的插件布局(含受保护文件)执行真实事务代码路径,崩溃、恢复、验证全部发生在沙箱里,真实环境零接触。

**Q: 健康检查提示 dsh CLI 不可用,但我明明装了(shell 里 `dsh --version` 正常)?**
这是宿主进程 PATH 与用户 shell PATH 不一致的经典场景(dsh 经 nvm/npm 安装,rc 文件注入的 PATH 宿主进程看不到)。V5.1 起注册表会自动走全局 bin 救援(nvm/volta/asdf/npm 前缀目录),命中则以 `rescued` 状态继续工作;也可设 `DSH_BIN=/完整/路径/dsh` 显式指定。CLI 缺失只是 warning(附 `skip_standard` 降级建议),不会阻断清理事务。

**Q: 我想让清理彻底绕过 dsh CLI,怎么做?**
`nuke_clean` 传 `skip_standard: true` 跳过标准卸载步骤;其余配置摘除与目录回收动作不依赖任何外部 CLI。

## License

[MIT](./LICENSE) © 2026 beijingwahw

Install

dsh plugin --profile web add github:beijingwahw/dsh-nuke-plugin

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source