Skip to main content
1

dsh-rescue-guard

1250589385/dsh-rescue-guard

Standalone rescue for a broken DeepSeek Harness profile: a CLI that runs without DSH diagnoses the crash logs (six classified causes, from real incidents), pre-flights the profile for command-name collisions and files plugins read at construction time, arms a safe mode that loads only official bundles until a healthy boot restores them, and keeps manifest snapshots for rollback. A resident watcher watches the crash-log directories via OS file events — idle costs nothing, and when the loader dies the report is written within seconds, one file overwritten per crash. Windows only: crash logs are read from %APPDATA% and the watcher autostarts from the Windows Startup folder.

Install

dsh plugin --profile web add github:1250589385/dsh-rescue-guard

README

dsh-rescue-guard · 启动救援与自我修复

DSH 起不来的时候,能救回来。

本插件由这台机器上的 21 份真实崩溃日志反推而来,不是凭空设计。每一条防护都对应一次 真实事故。


先说清楚一个矛盾(这决定了两半的分工)

插件是被启动过程加载的。所以:

如果崩溃发生在插件加载阶段,救援插件自己也加载不了。

这不是推测。实测 21 份日志里,12 份的崩溃点就在插件加载中:

崩溃原因次数崩在哪
ENOENT 读缺失文件(插件构造时抛出)8插件加载中
command "rules" is already registered2插件加载中
1 entry did not activate2插件加载中
desktop welcome: Web authentication failed8启动握手
renderer exited: killed1运行中

所以本插件分成两半,职责不同:

组件何时工作干什么
独立 CLI dsh-rescueDSH 起不来时真救援:不依赖 DSH,禁用可疑 bundle、回滚清单、布防安全模式
启动前预检DSH 正常时预防:在启动前就发现命令名冲突、缺失文件
面板 UIDSH 正常时看诊断、一键布防、管理快照

独立 CLI(核心)

DSH 起不来时用这个。它只用 Node 内置模块,不需要 DSH。

:: 方式一:双击 bin\rescue-console.cmd(菜单式,最省事)
:: 方式二:从命令行跑,路径取决于你装在哪
%USERPROFILE%\.dsh\profiles\desktop\node_modules\dsh-rescue-guard\bin\dsh-rescue.cmd diagnose

路径不是固定的,按你的实际安装位置换:

装法bin 目录在哪
dsh plugin add dsh-rescue-guard(默认 profile)%USERPROFILE%\.dsh\profiles\desktop\node_modules\dsh-rescue-guard\bin
指定了别的 profile%USERPROFILE%\.dsh\profiles\<profile名>\node_modules\dsh-rescue-guard\bin
从源码目录跑(开发时)<你 clone 的位置>\bin

不确定装在哪?任选一条:

:: ① 直接找(Windows)
dir /s /b %USERPROFILE%\.dsh\*dsh-rescue-guard\bin\dsh-rescue.cmd

:: ② 让桌面入口自己带路径(跑一次),之后双击桌面那个文件
cd <插件目录> && node bin\install-desktop.mjs

bin\dsh-rescue.cmd 与 bin\rescue-console.cmd 都会自己探测 Node 运行时 (很多机器上 Node 不在 PATH,但 DSH 自带一份),所以不需要你配环境变量。

dsh-rescue diagnose                 看崩溃原因 + 预检 + 给建议(先跑这个)
dsh-rescue crashes [--limit N]      只列归类后的崩溃历史
dsh-rescue scan                     只跑启动前静态预检
dsh-rescue safe-mode status|on|off  安全模式
dsh-rescue snapshot create|list|restore <id>
dsh-rescue cookies                  量 Cookie 头体积(「认证失败」多半是它)
dsh-rescue cookies --prune          清理陈旧 dsh-auth 令牌(先退出 DSH)
dsh-rescue cookies --prune --keep 3 只保留最新 3 条
dsh-rescue cookies --from-backup    DSH 在跑时读上次备份估算
dsh-rescue cookies --install-task   只打印每日自动清理的命令,不执行
dsh-rescue cookies --policy          查看自动清理策略(与设置面板同一份)
dsh-rescue cookies --auto on|off     开关自动清理
dsh-rescue cookies --keep-set N      持久化保留数
dsh-rescue cookies --auto-run        按策略执行一次(计划任务用)
dsh-rescue menu                     交互式救援菜单(桌面入口调用的就是它)
dsh-rescue install-desktop          在桌面创建双击即开的入口
dsh-rescue disable <bundle>         把某个 bundle 移出启动列表
dsh-rescue enable <bundle>          加回启动列表

--profile <dir>  配置目录(默认 ~/.dsh/profiles/desktop)
--home <dir>     DSH_HOME
--json           以 JSON 输出

典型救援流程

:: 1. 先看是什么原因
dsh-rescue diagnose

:: 2. 布防安全模式:下次启动只加载官方 bundle
dsh-rescue safe-mode on

:: 3. 启动 DSH。能起来了 -> 面板会自动还原第三方 bundle
::    还起不来 -> 说明不是第三方插件的问题,看诊断里的 web_auth 建议

:: 4. 想定位到具体是哪个插件:逐个加回
dsh-rescue enable dsh-ops

启动前预检(预防)

在 DSH 还正常的时候跑,提前发现会让下次启动崩掉的问题。

检查对应真实事故
命令名冲突dsh-permission-rules 与 dsh-purge 都注册 /rules,重复注册抛错 → apply() 中断 → 宿主停止(发生 2 次)
构造期读取的文件缺失插件 apply() 里 readFileSync 一个更新尚未落地的文件 → 抛出 → 启动即死(发生 8 次)
可能遮蔽根路由的注册prefix 路由挂在 / 会拦掉桌面端握手,导致 Web authentication failed(发生 8 次)

预检是启发式静态分析,不是证明。命中的问题值得查;没命中不代表没问题。 UI 与 CLI 都会把这句话显示出来。


安全模式

布防后,下次启动只加载 @deepseek-ai/* 官方 bundle,第三方全部暂时移出;启动成功后 自动还原。

几条硬约束:

  • 绝不触碰 @deepseek-ai/*(有专门测试)
  • 改写清单前先自动快照,回滚也可回滚
  • 原子写(.tmp + rename),不会留下半截文件
  • 幂等:重复布防/应用/还原都不会损坏清单

快照

每次启动保留一份配置快照(package.json / pnpm-workspace.yaml / rules.yaml), 存于 <profile>/.rescue/snapshots/,默认保留最近 10 份。

清单被写坏时:

dsh-rescue snapshot list
dsh-rescue snapshot restore 2026-11-07T13-35-29.164Z

面板

DSH 正常时,面板显示:上次启动是否正常、崩溃历史归类、预检结果、安全模式开关、 快照管理与回滚。底部固定给出一行可复制的救援命令。


与已有插件的关系(避免装重复)

生态里这个方向已经有不少插件。以下是对照,装之前可以先看看:

插件它做什么与本插件的关系
dsh-plugin-ops10 条完全静态的预检规则 + 面板:bundle 声明完整性、依赖漂移、peer 缺口、patch 行解析、结构完整性、版本兼容、minimumReleaseAgeExclude 语法、重复物理副本互补。它不检测命令名注册冲突 —— 而那正是本机真实导致 2 次宿主崩溃的原因
dsh-fix独立(不依赖 DSH)的启动故障诊断与修复工具重叠:独立 CLI + 修复启动故障。差别在本插件把「命令名冲突预检」和「崩溃日志六类归类」做成了明确能力
@perrylink/dsh-plugin-doctor面向插件作者的包结构与沙箱冒烟检测不同受众:它校验一个插件包是否合格,本插件诊断一个坏掉的 profile
dsh-checkpoint-rewind / dsh-time-machine / @xiaoyuyu6420/dsh-backup配置与会话快照、备份、回滚重叠:快照能力。本插件的快照只服务于救援(清单级、每次启动一份)
@noob-stupid/dsh-plugin-console升级门控:旧插件不适配自动禁用相邻:它管升级后禁用,本插件管启动崩溃后禁用

本插件真正独有的两点

  1. 命令名注册冲突的静态预检。生态里没有其它插件做这件事,而它在本机真实发生过 2 次: dsh-permission-rules 与 dsh-purge 都注册 /rules,重复注册抛错 → dsh-purge 的 apply() 中断 → 宿主停止。本插件的预检能在启动前就报出来。
  2. 崩溃日志的六类归因,并把「缺失文件路径」「冲突的命令名」抽出来。 归类本身不出奇,但它是从本机 21 份真实日志反推的,能直接对上历史事故。

如果你的需求是依赖/peer/版本兼容类预检,dsh-plugin-ops 比本插件成熟得多,建议装它; 本插件的价值集中在命令冲突与独立救援 CLI这两点上。


它不能做什么

  • 不能救插件加载期就死掉的启动(那是 12/21 的情况)——这正是必须有独立 CLI 的原因
  • 不做安全审计
  • 不自动删任何东西:只禁用(可还原),不删除
  • 修复不了 DSH 应用本身的问题(如 renderer exited: killed 这类进程被杀)

预检的已知盲区(如实声明)

  • 命令冲突的检出以 package.json 声明为准(bundles + dependencies)。一个插件若被从 声明里删掉、只剩 node_modules 里的物理残留,扫描会漏报——彻底扫 node_modules 会引入 卸载残留的噪声,这是取舍后的选择。命中项带 active 字段,可区分「已启用 bundle」与 「仅安装未启用」。
  • 动态构造的 readFileSync 路径无法静态解析(按 bundle 聚合为附注,不计入缺失清单)。
  • 栈帧解析只能指出「哪个第三方包」,不能证明它就是根因:跨包调用里,第三方帧可能是 被官方 API 误用的受害者。判定逻辑是「第一个非 @deepseek-ai/* 的帧」,遇到链式调用时 仍需人工确认——它把范围从 27 个插件缩到 1 个,但不是判决书。
  • 私有事件订阅只是 warning,不是阻断:订阅 internal/* 不等于一定崩,取决于宿主该版本 是否仍提供相同的回调约定。它的价值是"升级宿主前先看这一眼"。

桌面救援台(DSH 起不来时双击它)

DSH 拒绝启动的那一刻,图形界面正是坏掉的东西——这时候用户唯一能做的动作是 在桌面上双击一个东西。所以本插件自带一个菜单式救援台:

dsh-rescue-desktop          # 或 node bin/install-desktop.mjs

会在桌面创建 DSH 救援台.cmd(Windows;macOS/Linux 为 .sh),双击后是编号菜单:

  [1] 一键诊断        崩溃原因 + 预检 + 该做什么(推荐先点这个)
  [2] 查 Cookie 体积   「Web authentication failed」多半是它
  [3] 清理 Cookie 令牌  修 431 头超限(需先退出 DSH)
  [4] 看崩溃历史      只列归类后的崩溃
  [5] 启动前预检      命令冲突 / 缺失文件 / 私有事件
  [6] 安全模式        下次只加载官方插件
  [7] 快照            备份 / 列出 / 回滚 profile 配置
  [8] 禁用/启用插件    把可疑插件从启动列表摘掉

它自己探测 Node 运行时(优先用 DSH 自带的那份,macOS/Linux 上优先 PATH), 不依赖 PATH、不依赖 DSH 能启动、不改注册表、不加开机自启。 删掉桌面那个文件就完全还原。

自动清理策略(设置面板 / 控制台 / 配置文件,同一份真源)

Cookie 清理的策略存在 ~/.dsh/rescue-guard/config.json,不是宿主的 settings 命名空间。 理由很实际:这个策略的全部价值是「下次 DSH 起不来时已经生效」,而那时宿主 settings 读不到, CLI 必须能读到——所以它必须是一个不依赖宿主的文件。

三个入口改的都是这一份:

① 设置面板

设置 → 启动救援(和「Our Free Model」「wb400修复」「记忆」同一列):

  • 自动清理开关
  • 保留最新令牌数(0 = 全删)
  • 「立即清理」按钮(DSH 在跑时会明确告诉你被占用)

② 控制台 CLI

dsh-rescue cookies --policy        # 查看当前策略
dsh-rescue cookies --auto on       # 打开自动清理
dsh-rescue cookies --auto off      # 关闭
dsh-rescue cookies --keep-set 3    # 持久化「保留最新 3 条」
dsh-rescue cookies --auto-run      # 按策略执行一次(给计划任务用)

③ 救援台菜单

双击 bin\rescue-console.cmd:[9] 看策略、[a] 开、[b] 关。

配置项

字段默认含义
cookies.autoCleanfalse超阈值时自动清理(下次干净启动生效)
cookies.keepNewest0保留最新 N 条令牌,0 = 全删
cookies.warnRatio0.6达到上限的百分之多少开始预警
cookies.confirmBeforeCleantrue清理前是否要确认

文件缺失或损坏时自动回落默认值(不报错、不阻塞救援);写入是深合并 + 原子落盘, 不会因为只改了一个字段就把其它字段重置。

想定时自动清理

dsh-rescue cookies --install-task 会打印(不执行)一条 schtasks 命令, 内容是把 --auto-run 挂到每天一次。它会先读策略:没开自动清理就直接跳过。

2026-11-10 的真实事故:弹窗说 desktop welcome: Web authentication failed,看起来像账号或 凭据出了问题,实际坏的是请求头体积。

机制是这样的:

  1. 每次 Desktop 端启动,都会把 launch URL 换成一个新的 dsh-auth-<32字节随机> cookie, 绑在 127.0.0.1、有效期 30 天;
  2. Chromium 不会删除旧的(它们没到期,只是不再被用);
  3. 于是每天涨约 3 条,三周后累积到 71 条 / Cookie 头 16117 字节,加上其它请求头 共约 16600 字节,越过 Node 默认 maxHeaderSize = 16 KiB;
  4. Host 回 HTTP/1.1 431 Request Header Fields Too Large, connectDesktopWelcome 看到 !response.ok 就抛「认证失败」——文案完全没提体积;
  5. 失败后客户端重试,每次重试再加一条 cookie,形成恶化闭环。

cookies 子命令把这个不可见的量量出来:

$ dsh-rescue cookies --from-backup
Cookie 体积(决定能否启动握手)
  上限:Node 默认 maxHeaderSize = 16384 字节(Cookie 头还要加上其它请求头)
  ✗ 71 条 cookie(dsh-auth-* 71 条) → Cookie 头约 16117 字节(98%),加其它头约 16717 字节
      dsh-auth 令牌龄期:2026-10-19T02:02:45 → 2026-11-10T03:08:52

  ✗ Cookie 头加上其它请求头已超过 16KB:Host 返回 431,桌面端只会显示「Web authentication failed」。
      → 这就是「认证失败」却查不出账号问题的原因:坏的是请求头体积,不是凭据。

清理:

dsh-rescue cookies --prune --dry-run   # 先看会删多少
dsh-rescue cookies --prune             # 全删陈旧令牌(会先备份)
dsh-rescue cookies --prune --keep 3    # 只保留最新 3 条

几个必须知道的边界:

  • 必须先完全退出 DSH(含托盘图标)。Chromium 独占打开 cookie 库,就地清理会 EBUSY 失败或写进去被覆盖。CLI 会检测进程并拒绝执行。
  • 每次清理前都会把库备份到 ~/.dsh/backups/dsh-cookies-<时间戳>.db。
  • 清理只删 dsh-auth-*,不动其它 cookie(登录态等)。
  • DSH 正在跑时读不了实时库,用 --from-backup 读上次备份来估算"上次有多严重"。
  • 想自动化:dsh-rescue cookies --install-task 会打印(不执行)一条 schtasks 命令。

崩溃定位:从栈里认人

崩溃日志的 --- error --- 段第一行是被脱敏过的散文("4 required plugins did not activate"), 但下面的栈是原文。0.3.0 起直接解析栈里的第三方帧:

$ dsh-rescue diagnose
  ✗ 肇事插件(从崩溃栈里抽出的第三方帧):
      dsh-ops/lib/session-pwsh.js:19  ×3  (在 loaderCtx.on.global)
      → 这个包与当前宿主版本不兼容的可能性最高;先禁用它可以最快恢复启动。

建议
  ✗ 有 3 次「entry did not activate」,崩溃栈指向 dsh-ops。先用 dsh-rescue disable dsh-ops 再启动
    ——这是最短的恢复路径,不必二分。

2026-11-09 的真实事故就是这条路径:dsh-ops@0.3.0 在 internal/config 钩子里读 this.entry, 而 cordis 4.1.0 不再给 hook 绑 this,于是每个插件的配置解析都抛错,24 个插件失败、宿主拒绝启动。 旧版诊断只说"某个 bundle 未能激活",建议是跑 5 次安全模式二分;有了栈帧解析,第一句话就点名。

启动指纹:知道自己上次是怎么跑起来的

每次启动记一份指纹(宿主版本 + 每个插件的解析版本),启动成功时存为 lastGood。 下次启动失败时自动比对,把变化写进日志、CLI 和面板:

WARN [dsh-rescue] 相对上次成功启动的变化:
  版本变化:dsh-ops 0.5.2 → 0.3.0

指纹落在 boot.json 的 fingerprint / lastGood 里,不额外维护文件。 有了它,"27 个插件失败"这类结论才能收敛到"其中一个版本变了"。

预检第 4 条规则:私有事件订阅

scan 除了命令名冲突、缺失文件、路由遮蔽,现在还检测插件对宿主私有事件(internal/*)的订阅:

! 订阅了宿主私有事件的插件 1 处(宿主升级时可能直接崩):
      dsh-ops → internal/config  (lib/session-pwsh.js:19)

internal/* 是 Loader 内部事件,没有版本兼容承诺。这条规则锚定在订阅调用本身 (.on('internal/…')),对「普通类里恰好有个 this.entry 字段」的写法零误报(已用 11 个 真实已装插件 + 两个夹具验证)。

崩溃守护(平时零占用,出事即自检)

面板里可一键安装开机自启的守护进程(写入用户「启动」文件夹,卸载即删)。

工作方式(事件驱动,不是轮询):

  • 主触发是操作系统推送的目录变更事件(Windows 上是内核级的 ReadDirectoryChangesW):进程平时睡眠,空闲零 CPU、零唤醒,不耗电
  • 出现新崩溃日志 → 系统通知进程 → 2 秒防抖合并同一次崩溃的多个写入事件 → 生成报告
  • 一条 10 分钟一次的兜底扫描只防两类极端丢事件(目录在挂接后才创建/被整体替换), 平时不是它干活
  • 报告 <profile>/.rescue/last-crash-report.txt:本次错误原文、历史归类、启动前预检 结果(命令冲突/缺失文件)、「立即可做的事」
  • 报告每次覆盖,不累积历史 —— 崩溃一千次也只有一份文件 + 一个状态 JSON

单实例锁保证不会出现两个守护进程;守护进程自身崩溃也不影响手动 CLI。


安装与生效

安装后需要重启宿主,路由与面板才会出现(插件在启动时加载;装完不重启,/dsh-rescue/*.json 会是 404 —— 这是本机实测过的正常行为,不是故障)。

安装

dsh plugin add dsh-rescue-guard

CLI 在插件安装目录的 bin/dsh-rescue.cmd(不是本项目目录,因为在别处 clone 的位置与此无关)。 想知道确切路径就运行下面这条,它会打印并帮你放到桌面:

node bin/install-desktop.mjs

自检(本包内含测试)

test/ 随包发布,因为本插件的判断逻辑(崩溃归类、栈帧归因、安全模式、快照轮换)出错时 代价很高——它给你的建议是要照做的。无任何依赖,跑一条命令即可:

node test/regression.mjs     # 期望:全部通过(44 项)

覆盖的是真实事故反推的行为,不是构造的用例,例如:

  • 作用域包在 Windows 反斜杠路径下的包名解析(曾错成 C:/Users)
  • 多插件调用链应指认最内层第三方帧(曾指认外层调用方)
  • previousCrashes 计数、confirmBoot 清除 pending、快照按时间轮换
  • 私有事件订阅(internal/*)的检出与零误报

许可

MIT

Related plugins