# KNOWN ISSUE — duplicate loader entry id(聚合包 + 单独子包重复列出) > 记录于 2026-08-18,由本插件(dsh-bundle-dedup-guard)守护。症状、根因、证据、修复、 > 预防全记录在此,避免再次踩坑。 ## 症状 - 启动 `dsh web` / `dsh --profile web` 即失败,日志报: `plugin tree failed to load: duplicate loader entry id: ui-dsh-aionui-panel`(退出码 1)。 - 报错 id 是「第一个被撞上的」,修掉它还会继续报下一个——同一批还有 12 个。 ## 根因 profile 的 `dsh.profile.bundles` 里,**聚合包与它的全部子插件被同时列出**: - `@linxin666/dsh-web-ui-all` 是聚合包:它的 `dependencies` 包含 13 个子插件, 自带一份**自动生成**的 `cordis.patch.yml`,一次性 insert 全部子插件条目 (`ui-dsh-aionui-panel`、`ui-task-board`、`ui-git-graph`、`pet`、`ssh`、 `describe-image`、`liangshen`、`live-stats`、`remote-web-ui`、 `ui-community-plugins`、`ui-web-ui-settings`、`ui-skin-center`、`ui-web-ui-compat`)。 - 每个子插件**自己**也带 `cordis.patch.yml`,再 insert 一遍自己的 id。 - `bundles` 列表把聚合包和 13 个子插件各列了一次 → 每个 id 收到两次 insert。 机制链路(loader 侧,已对照源码确认): 1. `cordis-plugin-include` 的 `applyEntryPatches`:把各 bundle patch 的 insert **平铺累加**,不去重。 2. `cordis-plugin-loader` 的 `EntryGroup.update`:对组合后的 config 按 id 去重, `if (seen.has(id)) throw new TypeError(\`duplicate loader entry id: ${id}\`)` (`src/config/group.ts` 第 64 行)——在创建任何插件条目**之前**就抛,整个插件树起不来。 ## 证据(本机) | 文件 | 内容 | | --- | --- | | `/profiles/web/package.json.bak-20260818` | 事故前状态:bundles 里聚合包 + 13 个子包各列一遍 | | `/profiles/web/package.json` | 修复后:只保留聚合包 | | `plugins/dsh-web-ui-all/package/cordis.patch.yml` | 聚合 patch,13 个 insert id(文件头注明 AUTO-GENERATED by scripts/aggregate.mjs) | | `plugins/dsh-web-ui-all/package/node_modules/@linxin666/dsh-client-ui-aionui-panel/package.json` | 子插件自带 `dsh.bundle.patch: ./cordis.patch.yml` | | `plugins/dsh-web-ui-all/package/node_modules/@linxin666/dsh-skins/cordis.patch.yml` | dsh-skins 自带小聚合 patch,再插一遍 `ui-skin-center`(三源重复) | | `resources/vendor/dsh/node_modules/@deepseek-ai/cordis-plugin-loader/src/config/group.ts` | 去重抛错点(第 64 行) | | `resources/vendor/dsh/node_modules/@deepseek-ai/cordis-plugin-include/src/index.ts` | `applyEntryPatches` 平铺累加(第 58 行) | ## 修复 `dsh.profile.bundles` 只保留聚合包,删除重复的单独子包条目。本机修复后: - `dsh --dump-config` 插件树组合成功,`ui-dsh-aionui-panel` 只出现一次,退出码 0; - 实际启动 `dsh web`,服务正常起来,HTTP 200; - 皮肤功能未受影响:`dsh-skins` 没有自己的 bundle patch(`ui-skin-center` 由聚合 patch 插入), 皮肤注册是 skin-center 运行时直接扫描 `dsh-skins` 包目录(该包仍是 web-ui-all 的依赖)。 备份:`package.json.bak-20260818`。 ## 复发记录(2026-08-18 14:00)——根因在 dependencies,不是 bundles 初次修复只删了 `bundles` 列表,**13 个子插件仍留在 `dependencies`(link: 条目)**。随后: 1. GUI 插件市场执行了一次 `dsh plugin --profile web ...`(同时安装了新插件 `dsh-checkpoint-rewind`,pnpm 顺带跑了 playwright 的 chromium 安装)。 2. `dsh plugin` 的 `reconcilePlugins`(vendor `@deepseek-ai/dsh/lib/plugin-*.js`) 在 pnpm 成功后把 **每个解析到 `dsh.bundle` 声明的 dependencies 条目按依赖顺序 追加进 `dsh.profile.bundles`**(设计意图:让更新后新增 bundle 声明的包自动激活)。 3. 13 个子插件全是 `dsh.bundle` 声明者 → 被重新写回 bundles → 与 web-ui-all 聚合 patch 重复 → 下次启动又抛 `duplicate loader entry id: ui-dsh-aionui-panel`。 **为什么不能直接删 dependencies**:loader 通过 profile 的 `node_modules` 解析聚合条目 的 `name`(如 `@linxin666/dsh-client-ui-aionui-panel`),这些 link: 条目就是解析通道。 **持久修复(当前生效)**:把 13 个子插件的 link: 条目从 `dependencies` 移入 `devDependencies`——`reconcilePlugins` 只读 `dependencies`,永远不会再把它们追加进 bundles;而 pnpm 默认仍安装 devDependencies,loader 解析通道不变。备份: `package.json.bak-20260818-dupe-reappeared`(复发态)、`package.json.bak-20260818-guard`(首次修复态)。 **本插件据此新增预测性检查**:扫描 `dependencies`,发现声明了 `dsh.bundle` 但不在 bundles 列表的包时警告(含其 insert id 已被哪个聚合覆盖的明细)——这正是 reconcile 复发的前置条件,在下次 `dsh plugin` 把它写回之前就报警。 ## 预防(本插件做的事) - 每次装载插件(启动 apply / loader 条目事件 / 清单文件变化)自动检查,发现重复立刻在 日志里给出「重复 id + 来源 + 修复指引」,并落盘报告到 `$DSH_HOME/dsh-bundle-dedup-guard/reports/`。 - 启动已崩溃时用独立 CLI 诊断: `node plugins/dsh-bundle-dedup-guard/package/bin/check.mjs --profile web`。 ## 复现/自查方法 任何「既装了全家桶又单独装了子插件」的路径都会再触发同款问题。自查三步: 1. `node plugins/dsh-bundle-dedup-guard/package/bin/check.mjs --profile web`(应输出 ✓ 绿灯); 2. 或 `dsh --dump-config`(应无重复条目、退出码 0); 3. 直接启动 `dsh web`(服务应正常起来)。 ## 补充知识 - 13 个单独列出的 `@linxin666/dsh-*` 条目**全部**带自有 patch(含 `@linxin666/dsh-skins`—— 它自己也是个小聚合:`dsh.bundle.patch: ./cordis.patch.yml` 是 AUTO-GENERATED 的, 插入 `ui-skin-center`,其 `dependencies` 含 `dsh-client-ui-skin-center`)。 - 12 个不同的重复 id:其中 11 个被 insert 两次,`ui-skin-center` 被 insert **三次** (`@linxin666/dsh-web-ui-all` 聚合 patch ← `dsh-client-ui-skin-center` 子包 ← `dsh-skins` 聚合 patch)。按「多出的 insert」计数共 13 个,与当初日志的计数吻合。 - `dependencies` 里的 `link:` 条目不直接参与 loader 条目,但 **`dsh plugin` 的 reconcile 会按它们重建 bundles**——所以只要它们留在 `dependencies`,聚合子包重复 就随时可能被写回。聚合覆盖的子插件应放在 `devDependencies`。