定位插件静默失效原因并给出修复补丁
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/14 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add ven314/dsh-conflict-doctor该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · dev
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 19 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 31 处,展示前 31 条)
- 写入本地文件lib/cli.js:231
writeFileSync(options.out, rendered, 'utf8'); - 读取本地文件lib/static.js:102
const parsed = JSON.parse(readFileSync(file, 'utf8')); - 读取本地文件lib/static.js:114
return readFileSync(file, 'utf8'); - 读取本地文件lib/static.js:125
if (existsSync(join(dir, 'package.json'))) - 读取本地文件lib/apply.js:57
if (!existsSync(target)) { - 读取本地文件lib/apply.js:60
const stat = statSync(target); - 写入本地文件lib/apply.js:93
copyFileSync(target, backupPath); - 写入本地文件lib/apply.js:105
renameSync(tempPath, target); - 删除本地文件lib/apply.js:111
rmSync(tempPath, { force: true }); - 读取本地文件lib/apply.js:132
if (!existsSync(backupPath)) { - 读取本地文件lib/apply.js:135
const text = readFileSync(backupPath, 'utf8'); - 写入本地文件lib/apply.js:155
mkdirSync(outDir, { recursive: true }); - 写入本地文件lib/apply.js:182
writeFileSync(target, `${header}${fix.snippet}\n`, 'utf8'); - 写入本地文件lib/apply.js:203
writeFileSync(join(outDir, 'README.md'), manifest, 'utf8'); - 读取本地文件lib/dryrun.js:67
if (!existsSync(patchFile)) { - 读取本地文件lib/dryrun.js:70
const original = readFileSync(patchFile, 'utf8'); - 读取本地文件lib/source.js:30
stat = statSync(dir); - 读取本地文件lib/source.js:39
entries = readdirSync(dir, { withFileTypes: true }); - 读取本地文件lib/source.js:61
return readFileSync(file, 'utf8'); - 读取本地文件lib/source.js:70
if (statSync(file).size > MAX_FILE_BYTES) - 读取本地文件lib/source.js:206
return existsSync(join(dir, 'package.json')); - 读取本地文件lib/hostroot.js:30
return statSync(path).isDirectory(); - 读取本地文件lib/hostroot.js:39
return statSync(path).isFile(); - 读取本地文件lib/hostroot.js:203
return existsSync(join(dirname(process.execPath), 'resources')) || process.env.DSH_HOST_ROOT !== undefined; - 读取本地文件release.mjs:53
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')) - 执行外部命令来自配置/变量release.mjs:96
return execFileSync(file, args, { - 读取本地文件release.mjs:116
if (candidate && existsSync(candidate)) return candidate - 执行外部命令固定命令release.mjs:165
const out = execFileSync('git', ['credential', 'fill'], { - 请求外部主机api.github.comrelease.mjs:179
const res = await fetch(`https://api.github.com${path}`, { - 发起网络请求release.mjs:179
const res = await fetch(`https://api.github.com${path}`, { - 写入本地文件release.mjs:326
writeFileSync(ENTRY_PATH, ENTRY_BODY)
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
涉及外部主机:api.github.com
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-tools给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DSH 插件冲突治理:诊断 DeepSeek Harness 里悄无声息的插件冲突,并给出修复每个冲突的确切补丁。DSH 插件冲突诊断与修复建议。
README
由 DeepSeek 最新模型翻译生成dsh-conflict-doctor
插件冲突治理:把「装上了但没生效」变成一条可执行的结论。
DSH 有大量手段告诉你插件装上了;没有任何手段告诉你插件没在工作。三类真实故障全部是静默的:
| 现象 | 实际发生的事 | 现有工具为什么看不见 |
| 装完插件,功能不出现 | fiber 停在 PENDING,等一个没人提供的服务,不报错、不打日志 | 没有报错就没有信号 |
| 装第二个插件后整个功能没了 | tool id 重复 → 后注册者抛错 → 整行加载失败,错误信息不指出另一个 owner | 错误只说「already registered」 |
| 「我明明关了它,怎么还生效」 | 后一层 patch 把前一层的 disabled/config 盖掉了 | 层语义是整段替换、最后一层胜出 |
本插件把运行期图谱与磁盘上的 patch 层对齐,给出谁和谁撞了 + 改哪一行。
展开完整文档(README 剩余 1 节)
dsh-conflict-doctor
插件冲突治理:把「装上了但没生效」变成一条可执行的结论。
DSH 有大量手段告诉你插件装上了;没有任何手段告诉你插件没在工作。三类真实故障全部是静默的:
| 现象 | 实际发生的事 | 现有工具为什么看不见 |
| 装完插件,功能不出现 | fiber 停在 PENDING,等一个没人提供的服务,不报错、不打日志 | 没有报错就没有信号 |
| 装第二个插件后整个功能没了 | tool id 重复 → 后注册者抛错 → 整行加载失败,错误信息不指出另一个 owner | 错误只说「already registered」 |
| 「我明明关了它,怎么还生效」 | 后一层 patch 把前一层的 disabled/config 盖掉了 | 层语义是整段替换、最后一层胜出 |
本插件把运行期图谱与磁盘上的 patch 层对齐,给出谁和谁撞了 + 改哪一行。
它检测什么
运行期(live)
| code | 严重度 | 含义 |
| live/tool-id-conflict | critical | 两个插件注册同一个 tool id;从失败 fiber 的错误里认出冲突名,并确认它已在注册表中 |
| live/failed-fiber | critical | 任何启动失败的 fiber,带原始错误首行 |
| live/pending-missing-service | critical | fiber 停在 PENDING 且 inject 的服务无人提供——静默失败的根源 |
| live/duplicate-entry-id | critical | 两个模块占用同一个 Loader entry id(整树启动失败) |
| live/unprovided-inject | warning | 声明依赖的服务在整个进程里都不存在(下次重载就会挂) |
磁盘组合(profile)
| code | 严重度 | 含义 |
| profile/duplicate-row-in-layer | critical | 同一 patch 层里 row id 重复 |
| profile/module-under-multiple-ids | critical / info | 同一模块挂两次。config 不同 → info(dsh-tool-subagent 用 toolName: subagent / subagent_fork 刻意挂两次);config 相同或为空 → critical(真的挂重了) |
| profile/disable-then-reinsert | critical | 某层停用、后面的层又插进来 |
| profile/missing-patch-file | critical | bundle 声明的 dsh.bundle.patch 在磁盘上不存在 |
| profile/tool-id-collision | critical | 两个包在编译产物里声明了同一个 tool id。这是静态版本比对永远覆盖不到的能力级冲突 |
| profile/peer-range-unsatisfied | warning / info | 按包分组。已装版本低于声明最小值 → warning(宿主比插件旧,真会坏);只是声明更旧 → info。仅在版本权威性已确认时运行(见下) |
| profile/host-import-unsatisfied | warning | 插件从宿主包里 import 了一个当前宿主并不导出的符号。这是「peer 版本字符串匹配 ≠ API 存在」的具体形态。仅在版本权威性已确认时运行 |
| profile/service-collision | warning | 两个包注册同名服务。按 realm 过滤:浏览器侧包(dsh.client)不与宿主共享服务表,不参与比对 |
| profile/row-config-replaced | info | 多层依次替换同一 row 的 config(DSH 的层语义,符合预期时无需处理,所以只作提示) |
| profile/dangling-override | warning | patch 里的 - id: X 不对应任何已插入的 row(空操作,不报错) |
| profile/node-engine-unsatisfied | warning | engines.node 不满足当前 Node。仅在版本权威性已确认时运行 |
| profile/bundle-unresolved | info | dsh.profile.bundles 里的名字在 node_modules 里解析不到 |
运行期还有两条需要跨两半才能看出的:
| code | 严重度 | 含义 |
| live/pending-self-dependent | critical | fiber 等的服务正是它自己要提供的——自锁,永远不会激活。修复不是「装 provider」 |
| live/outbound-tool-collision | warning | 两个已加载的插件都声明了同一 tool id,而该 id 还没进注册表:冲突是确定的,只是被时序掩盖 |
版本权威性:一次真实的误报与修正
这是本工具最重要的一条设计约束,来自一次被实测证伪的错误。
打包的桌面应用从自己的 archive 提供 profile bundle(@deepseek-ai/dsh-base@0.2.0-rc.2),而 profiles/node_modules 里可能是另一代(0.1.0-rc.6)。早期版本直接拿磁盘副本当基准,于是产出了 7 条并不存在的冲突:声称社区插件 import 了宿主没有的符号、peer 范围不满足。实测把那些符号在运行宿主的 archive 里数出来——IconBranchOutlineRegular 7 处、resolveImageAttachmentAccess 13 处,全都在。
所以现在:插件启动时先向 pluginManager 问运行中的真实版本,再决定要不要做版本敏感的判断。
- 两边一致 → authoritative,正常比对;
- 不一致 → stale-disk,跳过 peer / import / engines 三类检查,并在报告里说明原因;
- 读不到运行版本 → unknown,同样跳过。
宁可不报,也不拿错误的基准报。结构类检查(重复 row、双挂载、层覆盖、配置被替换)不依赖版本,任何时候都照常运行。
每条 finding 都带 refs(涉及对象)、evidence(证据,不是猜测)、impact(会怎么坏)和至少一条 fix;能用 patch 修的直接给出可粘贴的 YAML。
安装
从插件市场(Settings → Plugin Market)搜索安装,或直接:
dsh plugin --profile web add dsh-conflict-doctor
然后把包名加进该 profile package.json 的 dsh.profile.bundles:
{
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-conflict-doctor"] } }
}
或者不安装,直接用 overlay 验证组合层:
dsh --profile web --patch <path-to>/conflict-doctor/cordis.patch.yml --dump-config
关于名字。 npm 上的 dsh-plugin-doctor 是另一个作者的工具,做的是「兼容性 / 安全性 / 隔离安装 / 回滚」。本插件做的是冲突诊断与修复——谁和谁撞了、为什么静默失效、改哪一行。定位不同但名字几乎相同,会在市场上造成安装歧义,因此本包定名为 dsh-conflict-doctor。
使用
模型侧工具:
conflict_doctor { scope: "all" | "live" | "profile", profilePath?: string, format?: "markdown" | "json" }
用户侧命令:
/conflict-doctor
- scope: "live" — 只看运行中的进程(Loader 树、fiber 状态、服务、tool 注册表)
- scope: "profile" — 只读磁盘(bundle 清单 → 每层 patch → row ledger)
- scope: "all"(默认)— 两者都有
设计取向
1. 只读。 不注册服务、不改配置、不碰注册表,只读 + 报告。一个「治理」插件自己成为故障源是荒谬的。
2. 只有一个硬依赖 tools。 loader/commands/systemPrompt/pluginManager 全部在用时 ctx.get——一个诊断插件如果自己停在 PENDING 就是个笑话。注册全部包在 ctx.effect() 里,卸载时干净撤销。
3. 宁缺毋滥。 每条检测器都在真实 profile 上跑过并调过阈值。真实数据把第一版的 23 条噪音收敛到可执行的少数几条;宁可不报,也不拿错误基准报。
4. 纯函数内核。 采集(live.ts / static.ts / source.ts)→ 检测(detect.ts)→ 渲染(render.ts)都是纯函数,可以用 fixture 单测,不需要启动 harness。38 项检查覆盖每个检测器的正例+反例、真实 profile 扫描、以及 Cordis 集成。
主动播报
有 critical 冲突时,插件会把它写进系统提示(systemPrompt.context,order 50),而不是等你来问。没有冲突时贡献空字符串——健康的组合为此付出 0 token。内容只报结论与第一条修复,并明确要求模型在用户提出相关问题前不要擅自改配置。
能力边界(老实说)
- tool id 归属无法 100% 归因。 dsh 的 tool 注册表不记录注册者,公开 API 也拿不到调用方 fiber。所以运行期只报告「冲突名 + 失败行」,跨插件的冲突归属由静态扫描(defineTool({ name: '...' }) 字面量)补上。动态拼出的 tool 名不在静态视野内。
- 静默覆盖只能报症状。 profile/row-config-replaced 里无法判断被丢掉的那层 config 是否必需——因为语义上就是整段替换。
- 版本敏感的检查会主动弃权。 当磁盘副本不是运行中的宿主时,peer / import / engines 三类检查直接跳过并说明原因(见上)。这是刻意的:一次被实测证伪的误报,比十次「可能有问题」更伤信任。
- 名称类静态提取只认字面量。 super(ctx, 'name')、provide('name')、defineTool({ name: '...' }) 能认;拼接出来的名字不能。所以报告措辞是「声明于编译产物」而不是「运行期已注册」。
- engines / peer 是证据不是因果。 范围不满足不等于一定坏,但它是「插件调了宿主里不存在的 API」的第一嫌疑人。
- !!js 不求值。 审计按原样记录 profile 提供的表达式——求值等于在审计里执行用户代码。因此 disabled: !!js ... 这类条件停用无法判定真假,相关行按「未停用」处理。
- fiber 错误文本读的是运行时记录的错误对象(fiber._error,非公开字段),取不到时降级为「无错误文本」而不是抛错。
开发
pnpm install
pnpm build # tsc -> lib/
pnpm test # 38 项检查:fixture 检测器 + 真实 profile 扫描 + Cordis 集成
node test/check-metadata.mjs # 发布元数据:name / engines.dsh / files / peer 声明
test/run.mjs 分三段:Part A 每个检测器的正例/反例 fixture(含版本权威性闸门);Part B 对 $DSH_PROFILE_DIR 真实 profile 做静态扫描;Part C 把 apply() 装进真实 Cordis 容器,验证工具/命令/告警注册、execute 输出契约、以及卸载后 ctx.effect 干净撤销。
test/emit-report.mjs 用真实数据写出仓库根目录的 conflict-doctor-report.md。
路线图
- 把 findings 主动播报进系统提示 ✅ 已实现(systemPrompt.context,无冲突时 0 token)
- 服务级冲突:两个插件提供同一个服务名 ✅ 已实现(realm 感知)
- 对「属性级 API 缺失」做真实比对 ✅ 已实现(import ↔ 导出面),并在实测中修正了基准错误
- slot / 客户端侧冲突(需要 Client Provider 配合)
- 把版本权威性做彻底:直接从运行宿主的 archive / 解析器拿导出面,而不是拿到版本号就弃权——这样 stale-disk 也能给出可信的 API 比对
- live/outbound-tool-collision 的时序预测:结合 fiber 的 inject 等待状态,预告「这一行一旦激活就会撞」
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
ven314/dsh-conflict-doctor
定位插件静默失效原因并给出修复补丁
相关插件 · 开发 / 工程
隐私简历生成器reactive-resume/reactive-resume
Reactive Resume 已迁至 GitHub 上的…
★ 45,125已汉化MCP
71.7
AI 架构文档生成器sopaco/deepwiki-rs
🚀 Litho 已进化为 Terrain —— 给你的 AI 智能体一张会呼吸的代码库地图。
★ 3,157已汉化DSH
70.8
长时任务执行闭环AMAP-ML/LongHorizon-Harness
面向 Computer-Use Agent 的 Loop Engineering
★ 1,764已汉化DSH
70.5
AI 编程纪律方法包GanyuanRan/Aegis
让 AI 编程 agent 变得可信:少返工、更安全、说“完成”前先给证据。
★ 1,384已汉化DSH
69.6
多代理编排运行时Enderfga/claw-orchestrator
面向编程智能体的运行时。把 Claude Code、Codex、Antigravity、Grok…
★ 586已汉化MCP
69.4
记忆进化插件csyangwen/dsh-memory-evolve
dsh-memory-evolve 使用场景指南
★ 461已汉化DSH
67.9