Back to home@limochaishang

crash-guard-dsh

No description

Stars
1
Language
JavaScript
Created
Sep 7, 2026
Updated
Sep 7, 2026
GitHub repo

Introduction

crash-guard-dsh

DeepSeek Harness / PawWork 插件崩溃保护插件:当某个插件导致启动崩溃或卡死时,自动隔离该插件,避免反复崩溃(crash loop)。

License: MIT Platform DSH

功能特性

  • 崩溃自动隔离:加载期崩溃后,下次启动自动禁用导致崩溃的插件
  • 卡死自动恢复:独立看门狗进程检测完全卡死(hang),自动杀进程、禁用可疑插件、重启
  • 三层自愈架构:同进程监控 → 独立看门狗 → 手动恢复,层层兜底
  • 零配置:安装即用,无需额外配置
  • 安全护栏:不误伤正常插件、不隔离自身和核心包、防重入误判

工作原理

三层自愈架构

┌─────────────────────────────────────────────────┐
│  第一层:同进程监控(index.mjs)                  │
│  - 每 50ms 跟踪正在加载的插件                      │
│  - 15 秒 hang 超时检测                            │
│  - 状态机:booting → ready → clean               │
│  - 崩溃后下次启动自动隔离                          │
├─────────────────────────────────────────────────┤
│  第二层:独立看门狗(watchdog.mjs)                │
│  - detached 独立进程,不加载任何插件               │
│  - 每 5 秒检查心跳文件                             │
│  - 30 秒无心跳判定完全卡死                         │
│  - 自动:禁用可疑插件 → 杀进程 → 重启             │
├─────────────────────────────────────────────────┤
│  第三层:手动恢复                                  │
│  - 删除 cordis.patch.yml 中的禁用条目             │
│  - 重启即可恢复                                    │
└─────────────────────────────────────────────────┘

崩溃检测流程

类似 Chrome 扩展的安全启动(safe mode):

阶段动作
每次启动crash-guard 作为 profile bundles 第一位加载,最先执行 apply
启动中每 50ms 跟踪正在加载的插件,同步写盘记录 lastLoading
加载完成状态标记 ready;正常退出标记 clean
检测崩溃下次启动发现上次状态停在 booting(没走完也没正常退出)→ 判定加载期崩溃
自动隔离把崩溃前正在加载的那个插件写进用户层 cordis.patch.ymldisabled: true),不再加载

独立看门狗机制

同进程监控有一个根本局限:如果插件导致完全阻塞事件循环(如无限循环、同步阻塞),crash-guard 自身的 50ms 轮询也会被冻住,无法检测卡死。

独立看门狗解决这个问题:

  1. crash-guard 启动时用 child_process.spawn 启动 watchdog.mjsdetached: true
  2. 主进程每 2 秒写心跳文件 heartbeat.json
  3. 看门狗每 5 秒检查心跳文件的修改时间
  4. 超过 30 秒没更新 → 判定完全卡死
  5. 自动执行:禁用可疑插件 → 杀掉所有 PawWork 进程(排除自己)→ 重启 PawWork

安全护栏(不误伤)

  • 只处理加载期崩溃/卡死:运行期崩溃/强杀只记日志不自动禁用——无法可靠归因
  • 永不隔离 guard 自身和核心包id: crash-guard@deepseek-ai/* 永远不会被禁用
  • 每次只禁一个:每次崩溃只禁用最后一个被跟踪的插件,其余保持原样
  • 防重入锁:模块顶层全局锁,live-reload 热重载时清理上一个实例,避免残留积累
  • 新鲜度校验:60 秒状态文件新鲜度窗口 + 进程标记双重保险,防 live-reload 误判
  • 看门狗锁文件:防止多个看门狗实例同时运行

文件布局

crash-guard-dsh/
├── index.mjs          # 插件主体(崩溃检测 + hang 检测 + 看门狗启动 + 心跳写入)
├── watchdog.mjs       # 独立看门狗进程(detached,监控心跳、自动恢复)
├── cordis.patch.yml   # bundle 补丁:以第一位插入 crash-guard 条目
├── package.json       # 插件声明
├── install.ps1        # Windows 安装脚本
├── uninstall.ps1      # Windows 卸载脚本
├── README.md          # 本文档
├── LICENSE            # MIT 许可证
└── test/
    ├── simulate.mjs        # 崩溃恢复流程模拟测试
    └── verify-install.mjs  # 安装验证测试

运行时状态目录(默认):

  • 状态:$DSH_HOME/crash-guard/state.json
  • 心跳:$DSH_HOME/crash-guard/heartbeat.json
  • 看门狗锁:$DSH_HOME/crash-guard/watchdog.lock
  • 看门狗日志:$DSH_HOME/crash-guard/watchdog.log
  • 隔离日志:$DSH_HOME/crash-guard/quarantine.log(JSONL,含每次禁用记录)

$DSH_HOME 默认为 ~/.pawwork/dsh,可用 DSH_HOME 环境变量覆盖。

安装

前置要求

  • DeepSeek Harness / PawWork 已安装
  • Node.js 18+(DSH 自带运行时即可)

Windows(PowerShell)

# 克隆或下载本仓库
git clone https://github.com/limochaishang/crash-guard-dsh.git
cd crash-guard-dsh

# 运行安装脚本
.\install.ps1

脚本会:

  1. 复制 crash-guard-dsh 到目标 profile 的 node_modules/
  2. crash-guard-dsh 插入目标 profile package.jsondsh.profile.bundles 第一位
  3. 加入 dependencies
  4. 备份被修改的文件为 .crash-guard.bak

安装后重启 DSH / PawWork 生效。

手动安装

  1. 复制本目录到 profile 的 node_modules/crash-guard-dsh/
  2. 在 profile 的 package.json 中,把 crash-guard-dsh 加入 dsh.profile.bundles 第一位
  3. 加入 dependencies
  4. 重启 DSH / PawWork

卸载

.\uninstall.ps1

从 bundles / dependencies 移除并删除 node_modules 里的包目录;state.jsonheartbeat.jsonquarantine.log 会保留(可选删除)。

使用方法

安装后无需任何操作,crash-guard 自动工作:

  • 正常启动:crash-guard 跟踪加载过程,记录状态,启动完成后进入 ready 状态
  • 插件崩溃:下次启动自动隔离导致崩溃的插件,PawWork 可以正常启动
  • 插件卡死:看门狗检测到无心跳,自动杀进程、禁用可疑插件、重启
  • 查看日志:检查 $DSH_HOME/crash-guard/quarantine.log 查看被禁用的插件记录

手动恢复被禁用的插件

崩溃/卡死后 crash-guard 会在用户层 cordis.patch.yml(如 profiles/web/cordis.patch.yml)追加类似内容:

# [crash-guard] 自动禁用:插件 "xxx" (yyy) 在最近一次启动时导致崩溃。
# 如需恢复,删除下面两行即可。
- id: yyy
  disabled: true

删除这两行并重启即可重新启用该插件。

配置选项

crash-guard 零配置即可使用。如需自定义,可通过 patch 配置以下参数:

参数默认值说明
stateDir$DSH_HOME/crash-guard状态文件目录
patchFileprofile 下的 cordis.patch.yml禁用插件写入的补丁文件
freshWindowMs60000状态文件新鲜度窗口(毫秒)
readyTimeoutMs30000启动超时时间(毫秒)
hangTimeoutMs15000单插件加载 hang 超时(毫秒)
heartbeatIntervalMs2000心跳写入间隔(毫秒)
watchdogCheckIntervalMs5000看门狗检查间隔(毫秒)
watchdogTimeoutMs30000看门狗心跳超时(毫秒)

测试

模拟崩溃测试

node test/simulate.mjs

测试覆盖:

  • 正常启动 → clean 状态
  • 崩溃残留 → 下次自动禁用
  • 幂等不重复禁用

真实环境测试

  1. 安装一个会导致崩溃的插件(如已知不兼容的插件)
  2. 重启 PawWork,观察是否崩溃
  3. 再次重启,观察 crash-guard 是否自动隔离该插件
  4. 检查 quarantine.log 确认禁用记录

看门狗测试

  1. 安装一个会导致完全卡死的插件(如无限循环、同步阻塞)
  2. 重启 PawWork,观察是否卡死
  3. 等待约 30 秒,观察看门狗是否自动杀进程、禁用插件、重启
  4. 检查 watchdog.log 确认看门狗动作记录

常见问题(FAQ)

Q: crash-guard 会影响正常插件的加载吗?

A: 不会。crash-guard 只在启动时跟踪加载过程,不修改其他插件的代码或配置。正常启动后,crash-guard 进入 ready 状态,不再干预。

Q: 为什么是"下次启动"才生效?

A: 崩溃发生在加载过程中,guard 自身来不及写禁用指令;只有等下一次启动、由 guard 首先执行检测并落盘禁用,才能阻止坏插件再次加载。这与 Chrome 安全启动的设计一致。

Q: 看门狗会不会误杀正常进程?

A: 概率极低。看门狗只在心跳超过 30 秒没更新时才触发,而正常运行时主进程每 2 秒写一次心跳。只有完全卡死(事件循环被阻塞)才会导致心跳停止。

Q: 两个进程(主进程 + 看门狗)会不会都崩溃?

A: 理论上可能但概率极低。看门狗代码极简(约 100 行),不加载任何插件,不依赖 DSH 运行时,作为 detached 独立进程运行。主要风险来自系统级故障(如操作系统崩溃、断电)。

Q: 归因不准确怎么办?

A: 当前归因是启发式的——记录崩溃前正在加载的插件。在某些情况下(如插件 A 阻塞导致 loader 认为插件 B 还在加载),可能归因到错误的插件。这是已知局限,已列为未来工作方向。如果发现误禁,手动删除 cordis.patch.yml 中的禁用条目即可恢复。

Q: crash-guard 自身崩溃了怎么办?

A: crash-guard 有防重入锁和异常处理。如果 crash-guard 自身崩溃,它不会写入崩溃状态(因为还没完成 booting→ready 的转换),下次启动会重新尝试。crash-guard 代码经过严格测试,自身崩溃概率极低。

局限性

  • 崩溃发生在 crash-guard 加载之前(如 base bundle 自身问题)时无法归因——设计边界,与主流 safe-mode 一致
  • 只针对「加载期崩溃/卡死」;运行期崩溃不自动禁用
  • 归因是启发式的,极端情况下可能不准确
  • 本插件不参与 UI,无配置项(如需自定义可通过 patch 配置)

未来工作

  • 精确归因:通过插件加载时序分析更准确地定位崩溃元凶
  • 三层监控架构:同进程 → 独立看门狗 → 操作系统级服务监控
  • 崩溃报告:收集崩溃堆栈,生成更详细的诊断报告
  • 插件兼容性评分:基于历史崩溃数据评估插件稳定性
  • 批量测试工具:自动化测试插件市场中插件的兼容性

贡献

欢迎提交 Issue 和 Pull Request!

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 开启 Pull Request

许可证

本项目采用 MIT 许可证 开源。

致谢

  • DeepSeek Harness 团队提供的插件架构
  • Chrome 扩展安全启动机制的设计灵感
  • 所有贡献者和用户的反馈

如果你觉得这个插件有用,欢迎给个 Star ⭐