跳到主要内容

dsh-bundle-dedup-guard

已验证

dsh-bundle-dedup-guard · v0.1.0 · MIT

DSH plugin guard: checks profile bundle lists for duplicate loader entries on every plugin load, preventing the 'duplicate loader entry id' boot crash caused by listing an aggregate bundle and its sub-plugins together — and the `dsh plugin` reconcile recu

安装

dsh plugin add dsh-bundle-dedup-guard

dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南

源码

标签

作者

说明文档

dsh-bundle-dedup-guard

CI npm version node License

DeepSeek Harness 插件守卫:每次装载插件时检查 profile 的 bundles 列表是否存在重复 loader 条目。

当 profile 的 dsh.profile.bundles 同时列出聚合包(其 patch 一次性插入全部子插件条目, 如 @linxin666/dsh-web-ui-all和它的子插件时,loader 会对同一 loader 条目 id 收到两次 insert。EntryGroup.update 在任何插件条目创建之前就抛 duplicate loader entry id: <id>,整个 profile 启动失败。本插件让这类问题不再无声发生。


为什么存在

2026-08-18 事故:web profile 同时列出了 @linxin666/dsh-web-ui-all(聚合 13 个子插件 为一个 patch)和全部 13 个子插件。每个子插件 id 被 insert 两次,第一个被撞上的是 duplicate loader entry id: ui-dsh-aionui-panel。只修 bundles 列表还不够—— dsh pluginreconcilePlugins 会在每次 pnpm 操作后把 dependencies 里所有声明了 dsh.bundle 的包按依赖顺序追加回 bundles,一小时后子插件被重新写回,下次启动又崩。

完整事故记录:docs/KNOWN-ISSUE-bundle-duplicate.md

工作原理

loader 的故障链路是:cordis-plugin-includeapplyEntryPatches 平铺累加各 bundle 的 insert 条目不去重,随后 cordis-plugin-loaderEntryGroup.update 按 id 去重、 碰到第一个重复就抛错——此时任何插件条目都还没创建。本插件用纯 Node 复刻这套 「平铺累加 + 按 id 去重」语义,报告违规 id、来源(哪个 bundle/patch 插入的)与修复指引。

每次装载插件都检查

时机 触发 说明
启动装载 插件 apply 每次启动体检一次
loader 事件 loader/entry-init / loader/partial-dispose 运行时热装载/新增插件,800ms 防抖复查
清单文件变化 fs.watch 监听 profile 目录 dsh plugin add、插件市场安装、手改 package.json / cordis.patch.yml 的瞬间立刻警告,无需等重启

报告内容

  • 重复 loader 条目 id——每个被多个来源插入的 id 及完整来源链(如 ui-dsh-aionui-panel: @linxin666/dsh-web-ui-all ← @linxin666/dsh-client-ui-aionui-panel)。
  • 未解析 bundle——列在 bundles 里但解析不到(loader 同样会 loud fail)。
  • 无 patch 的包——列了但没有 dsh.bundle.patch 段(按 loader 契约属配置错误)。
  • reconcile 预测警告——dependencies 里声明了 dsh.bundle 但不在 bundles 列表的包。 dsh plugin 的 reconcile 会在下次装/更新插件时把它追加进 bundles;若它是聚合包已覆盖的 子插件,将重新造成崩溃。警告会点名已被覆盖的 id。处理:把这些包移入 devDependencies (reconcile 只读 dependencies)。

报告落盘 $DSH_HOME/dsh-bundle-dedup-guard/reports/<profile>-<时间戳>.json<profile>.latest.json

已知限制

loader 在创建任何插件条目之前就去重,所以「启动即崩溃」的场景下进程内检查无法运行 (插件树根本没装载)。此时请用下面的独立 CLI:纯读盘,崩溃状态下也能跑。

安装

作为 profile bundle(开发期推荐):

  1. 在 profile 的 package.json dependencies 加:
    "dsh-bundle-dedup-guard": "link:F:/path/to/dsh-bundle-dedup-guard"
    
  2. dsh.profile.bundles"dsh-bundle-dedup-guard"(放最前面即可)。
  3. 在 profile 的 node_modules 建立链接(dsh plugin add 会自动做)。

从 npm:

dsh plugin --profile web add dsh-bundle-dedup-guard

用法

插件自动检查,无需交互。手动诊断(含启动已崩溃时):

# 检查全部 profile(DSH_HOME 缺省 ~/.dsh)
node bin/check.mjs

# 指定 profile
node bin/check.mjs --profile web

# 指定清单文件(如修复前的备份,测试用)
node bin/check.mjs --manifest <path-to-package.json>

# 机器可读 JSON、不落盘报告
node bin/check.mjs --profile web --json --no-write

退出码:0 = 健康;1 = 发现重复 / 未解析 bundle / 无 patch bundle(可做 CI 门禁)。

修复重复

编辑 dsh.profile.bundles,每个 id 只保留一个来源。最常见的形态是「聚合包 + 子包」:

  • 保留聚合包(如 @linxin666/dsh-web-ui-all
  • 删除单独列出的子包条目
  • 同时把子插件从 dependencies 移入 devDependencies——否则 dsh plugin 的 reconcile 会在下次装/更新插件时把它们重新追加回 bundles(2026-08-18 复发的根因)

然后重跑 node bin/check.mjs --profile <name> 直到绿灯,再重启。

开发

npm test          # node --test,零依赖
npm run check     # 对本机 profile 运行守卫
  • lib/check.mjs — 检查核心(纯 Node,无第三方依赖)
  • index.mjs — Cordis 插件入口(apply + 监听器)
  • bin/check.mjs — 独立 CLI(无需装载插件树)
  • test/ — 带 fixture profile 的单元测试

License

MIT