dsh-plugin-doctor:DSH 插件行失败检测与自动禁用

前言

在 DeepSeek Harness(DSH)里,插件通过 Cordis Loader 挂载成一行一行配置。某一行的 apply 抛错、服务重复注册或依赖缺失时,宿主会把该行标成 failed 并让它停摆,其余部分仍可继续跑。问题是:failed 行会一直占着启用状态,下次启动或热重组仍可能反复撞墙,排查也要自己在 Loader 树里翻。

dsh-plugin-doctor(维护者 hollowfyh,GitHub hollowfyh/dsh-plugin-doctor)做的是周期体检:发现 failed 行后,用官方 API 持久化禁用,并留下可查的报告与事件日志;需要时还可以用 /doctor 手动触发一次扫描。下面介绍它的定位、能力与配置方式。

这是什么

一句话:面向 DSH 的「插件医生」——扫描 Loader 树里的失败行,在策略允许时自动禁用并写 patch 备份,同时输出诊断报告。

分类上属于工作流类插件;当前版本为 0.1.0(MIT 许可证,package.json 声明 Node >= 22,与 DSH 0.2.1-rc.2 标为 compatible)。社区目录页:SkillHub · hollowfyh/dsh-plugin-doctor(独立社区站点,与 DeepSeek / 幻方无官方从属关系)。

核心功能

失败行与自动修复

当插件行在加载时发生冲突,DSH 标记为 failed 后,本插件会:

  1. 周期扫描 Loader 树(也可通过 /doctor 手动体检)。
  2. 对 failed 行调用 pluginManager.setPluginEnabled(id, false),持久化禁用(写入 profile 的 cordis.patch.yml 并触发热重组),让其余插件照常工作。
  3. 每次修复追加写入 $DSH_HOME/plugin-doctor/incidents.jsonl;整份扫描结果每次重写 $DSH_HOME/plugin-doctor/report.json。

斜杠命令

注册 /doctor,可在运行期随时发起一次体检,与后台定时扫描互补。

休眠行(dormant)仅报告

启用但没有任何存活 fiber 的行(常见于模块导入失败)会出现在报告的 dormant 字段里,只记录、不自动处理。导入失败往往不产生 failed fiber,这类情况需要人工核对模块名与依赖。

安全边界(README 明示)

  • 只禁用,不卸载、不改 package.json 依赖。
  • 不处理自身、dsh-plugin-manager、插件清单模块,以及带 readOnlyReason 的只读行。
  • 单次启动自动修复行数有上限(见配置 maxFixesPerBoot)。
  • 临时冲突(如 HMR transactions cannot be nested)会自动重试,最多 6 次。
  • 被禁用的行仍可在「插件」页手动重新启用;修复记录可查。

安装与启用

README 与社区目录页均未给出单独的 dsh plugin … 安装命令原文。实际分发形式是带 cordis.patch.yml 的 DSH bundle(见仓库 package.json 的 dsh.bundle.patch)。安装方式以你在 SkillHub 或 DSH 文档里选用的插件安装流程为准;安装前请自行阅读仓库源码与 MIT 许可证,插件以当前 DSH 进程权限运行。

启用后,在 profile 的 cordis.patch.yml 里为本插件行补充 config(节选自 README):

- id: plugin-doctor
  name: 'dsh-plugin-doctor'
  config:
    autoFix: true        # 默认 true:自动禁用加载失败的行
    scanDelayMs: 3000    # 启动后延迟首次扫描的毫秒数
    watchIntervalMs: 12000  # 运行期扫描间隔(0 = 只在启动时扫描一次)
    maxFixesPerBoot: 3   # 单次启动最多自动修复的行数

典型用法与报告

自动扫描节奏

默认启动约 3 秒后首次扫描,之后每 12 秒扫描一次;将 watchIntervalMs 设为 0 则只在启动时扫描一次。若希望只看不改,将 autoFix 设为 false。

查看 report.json

每次扫描会重写 report.json,结构如下(字段含义见 README):

{
  "at": "…",
  "total": 199,
  "active": 174,
  "failed": [{ "entryId": "…", "moduleName": "…", "readOnlyReason": null }],
  "dormant": [],
  "fixed": [{ "entryId": "…", "result": { "application": "applied", "changed": true } }],
  "skipped": [{ "entryId": "…", "reason": "…" }],
  "errors": []
}

手动体检

在 DSH 对话或命令入口执行 /doctor,触发与周期扫描相同的检测逻辑(是否自动修复仍由 autoFix 等配置决定)。

仓库内自测(维护者提供)

在克隆仓库后的开发环境中(非 DSH 安装步骤)可运行:

node test/smoke.mjs

覆盖正常禁用、临时冲突重试、autoFix 关闭、修复上限等场景。端到端故障注入见 test/broken-plugin.mjs(README 记载:失败行被禁用并写入 disabled: true)。

实现要点与局限

失败检测:优先 pluginManager.listPlugins()(含 readOnlyReason、fiberPhase);拿不到时直读 ctx.loader.entries() 并按 fiber.state 映射阶段。

修复与 HMR:修复走官方 setPluginEnabled 写 patch 并 HMR。若本插件在一次热重组事务的 apply 里创建定时器,直接调用修复可能被 runExclusive 以 “HMR transactions cannot be nested” 拒绝;实现里在可用时将修复包在 hmr.executing.exit(callback) 中退出事务上下文后再调用。

不在范围内:

  • 浏览器端模块加载失败、slot 层 UI 重叠。
  • 宿主极早期 Loader 树起不来时,本插件也无法启动,需人工介入。
  • dormant 记录的导入问题需人工查模块与依赖。

结尾

dsh-plugin-doctor 适合已经装了不少 DSH 插件、偶尔会遇到单行 failed 却不想整机停摆的开发者:用可配置的自动禁用把冲突行从热路径上摘掉,用 incidents.jsonl 与 report.json 留痕,用 /doctor 做即时体检。细节与更新以仓库 README 为准。

  • 社区目录:https://www.skillhub.cn/plugins/hollowfyh/dsh-plugin-doctor
  • 源码与文档:https://github.com/hollowfyh/dsh-plugin-doctor
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜