🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

插件体检医生 moonquake2004/dsh-doctor

DeepSeek Harnessv0.8.5
moonquake200415 天前有提交已提供中文文档扫描:含敏感能力

已针对 DSH 0.1.5-rc.1 验证会话格式 v3;dsh-session 定位覆盖 npx / 全局 /…

31.9/100
综合分
3
GitHub 星标
341
npm 周下载
—/5
用户评分

数据截至 2026/10/22 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add @moonquake2004/dsh-doctor
npm 源 · @moonquake2004/dsh-doctor 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · other
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功(非静态推断);本次验证针对插件 v0.8.9,当前版本为 v0.8.5
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 15 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过

安装清单取自 plugin/package.json

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包@moonquake2004/dsh-doctor @ 0.8.5
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/11 22:10:33

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 223 处,展示前 28 条)
  • 执行外部命令来自配置/变量
    lib/index.js:41
    const child = spawn(process.execPath, [SCRIPT, ...args], {
  • 发起网络请求
    client/client.js:84
    const res = await fetch('/dsh-doctor/run', { cache: 'no-store' })
  • 读取本地文件
    dsh-doctor.mjs:101
    if (!p || !existsSync(join(p, 'dsh'))) continue;
  • 读取本地文件
    dsh-doctor.mjs:117
    if (existsSync(profiles)) {
  • 读取本地文件
    dsh-doctor.mjs:118
    for (const name of readdirSync(profiles)) {
  • 读取本地文件
    dsh-doctor.mjs:122
    if (existsSync(store)) {
  • 读取本地文件
    dsh-doctor.mjs:123
    for (const d of readdirSync(store)) {
  • 读取本地文件
    dsh-doctor.mjs:129
    return [...new Set(cands.filter((c) => existsSync(c)))];
  • 执行外部命令来自配置/变量
    dsh-doctor.mjs:436
    const find = (cmd) => { for (const w of process.platform === 'win32' ? ['where'] : ['which']) { const r = spawnSync(w, [cmd]); if (r.status === 0) { c
  • 执行外部命令固定命令
    dsh-doctor.mjs:446
    const nv = spawnSync('node', ['-e', 'console.log(process.version)']);
  • 执行外部命令来自配置/变量
    dsh-doctor.mjs:479
    const found = (() => { const r = spawnSync(whichCmd, ['dsh'], { encoding: 'utf8' }); return r.status === 0 ? String(r.stdout).split(/ ? /)[0].trim()
  • 执行外部命令来自配置/变量
    dsh-doctor.mjs:483
    const r = spawnSync(process.platform === 'win32' ? 'dsh.cmd' : 'dsh', ['--version'], { encoding: 'utf8', timeout: 15000, shell: process.platform === '
  • 执行外部命令来自配置/变量
    dsh-doctor.mjs:519
    const r = spawnSync(process.execPath, ['-e', 'require("node:zlib").zstdDecompressSync(require("node:zlib").zstdCompressSync(Buffer.from("x")))'], { en
  • 执行外部命令固定命令
    dsh-doctor.mjs:633
    const r = execFileSync('netstat', ['-ano'], { encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 });
  • 写入本地文件
    dsh-doctor.mjs:2349
    try { mkdirSync(dirname(cachePath), { recursive: true }); writeFileSync(cachePath, JSON.stringify(data, null, 2)); } catch { }
  • 写入本地文件
    dsh-doctor.mjs:2349
    try { mkdirSync(dirname(cachePath), { recursive: true }); writeFileSync(cachePath, JSON.stringify(data, null, 2)); } catch { }
  • 写入本地文件
    dsh-doctor.mjs:2598
    try { mkdirSync(dirname(cachePath), { recursive: true }); writeFileSync(cachePath, JSON.stringify({ latest, checkedAt: new Date().toISOString() })); }
  • 写入本地文件
    dsh-doctor.mjs:2598
    try { mkdirSync(dirname(cachePath), { recursive: true }); writeFileSync(cachePath, JSON.stringify({ latest, checkedAt: new Date().toISOString() })); }
  • 写入本地文件
    dsh-doctor.mjs:3039
    try { writeFileSync(join(profileDir, SNAPSHOT_FILE), JSON.stringify(snap, null, 2) + '\n'); } catch { }
  • 写入本地文件
    dsh-doctor.mjs:3054
    writeFileSync(`${manifestPath}.dsh-doctor.pre-add.${Date.now()}`, before);
  • 读取本地文件
    observer.mjs:273
    const st = statSync(p);
  • 读取本地文件
    observer.mjs:276
    for (const f of readdirSync(p)) {
  • 读取本地文件
    observer.mjs:278
    try { out.push(JSON.parse(readFileSync(join(p, f), 'utf8'))); } catch { }
  • 读取本地文件
    observer.mjs:282
    return JSON.parse(readFileSync(p, 'utf8'));
  • 执行外部命令来自配置/变量
    observer.mjs:287
    const r = spawnSync(cmd, { input: prompt, encoding: 'utf8', shell: true, timeout: 30_000, maxBuffer: 4 * 1024 * 1024 });
  • 写入本地文件
    observer.mjs:311
    mkdirSync(dirname(filePath), { recursive: true });
  • 写入本地文件
    observer.mjs:312
    writeFileSync(filePath, JSON.stringify(catalog, null, 2) + '\n', 'utf8');
  • 读取本地文件
    observer.mjs:318
    const d = JSON.parse(readFileSync(filePath, 'utf8'));
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 扫描插件树
  • 发现配置故障

README

由 DeepSeek 最新模型翻译生成
dsh-doctor 已针对 DSH 0.1.5-rc.1 验证(会话格式 v3;dsh-session 定位覆盖 npx / 全局 / profile 三种布局;v0 旧事件按已装 dsh-session-format- 迁移链读取)。 DeepSeek Harness 的离线诊断工具——在启动前或安装插件前跑一次,它会告诉你社区反复报告的哪几类故障会在你机器上咬人。 零 npm 依赖。单文件。任何有 node 的环境都能跑(zstd 只在扫 .zstd 会话日志时需要,E1 会检查它)。 为什么 dsh 的插件树"装出来就是脆的":一个悬空引用、一个断掉的 file: 链接、一个重复的 entry id、一段损坏的会话日志,都能让 profile 在启动时直接挂掉或拖垮整个 web 服务器——而 --dump-config 从不挂载 loader,所以在坏配置上也"一切正常"。这类故障被汇总在 dsh discussion #1496(Advisory:插件安装路径需要护栏)。dsh-doctor 就是这个护栏——26 项内置检查(env 7 / profile 11 / session 8)映射到 18 个社区报告,每一项都用合成负样例验证过;外加一个自更新的远程检查目录(声明式规则,v0.2.0 起)。
展开完整文档(README 剩余 1 节)
dsh-doctor

已针对 DSH 0.1.5-rc.1 验证(会话格式 v3;dsh-session 定位覆盖 npx / 全局 / profile 三种布局;v0 旧事件按已装 dsh-session-format- 迁移链读取)。

DeepSeek Harness 的离线诊断工具——在启动前或安装插件前跑一次,它会告诉你社区反复报告的哪几类故障会在你机器上咬人。

零 npm 依赖。单文件。任何有 node 的环境都能跑(zstd 只在扫 .zstd 会话日志时需要,E1 会检查它)。

为什么

dsh 的插件树"装出来就是脆的":一个悬空引用、一个断掉的 file: 链接、一个重复的 entry id、一段损坏的会话日志,都能让 profile 在启动时直接挂掉或拖垮整个 web 服务器——而 --dump-config 从不挂载 loader,所以在坏配置上也"一切正常"。这类故障被汇总在 dsh discussion #1496(Advisory:插件安装路径需要护栏)。dsh-doctor 就是这个护栏——26 项内置检查(env 7 / profile 11 / session 8)映射到 18 个社区报告,每一项都用合成负样例验证过;外加一个自更新的远程检查目录(声明式规则,v0.2.0 起)。

用法

node dsh-doctor.mjs # 全部检查(env + profile + session)
node dsh-doctor.mjs --profile web # 仅 profile 检查
node dsh-doctor.mjs --session <path> # 仅会话检查(默认自动找最新会话)
node dsh-doctor.mjs --env # 仅环境检查
node dsh-doctor.mjs --json # 机器可读输出
node dsh-doctor.mjs --no-catalog # 不拉远程目录(只用内置副本)

退出码:0 = 全部通过 · 1 = 发现问题(内置检查 + 目录中 severity: error 的项)· warn 级目录失败不改退出码。

检查项(28 内置 + 5 目录)

env

| ID | 检查 | 对应讨论 |
| E1 | node/pnpm/zstd 在 PATH | #1270 |
| E2 | .env 是文件而非目录 | #71 |
| E3 | node 版本 / --expose-internals 可及性 | #113, #1313 |
| E4 | node-pty 原生二进制在位(prebuilds/<platform>-<arch>/pty.node) | #1219 |
| E5 | 存储 JSON 文件合法(严格 UTF-8 + 可解析) | #1357 |
| E6 | 锚点 tripwire:S6/S7/S10 依赖的契约仍在当前版本存放它的位置(npx / 全局 / profile 三布局;dsh-session 或 dsh-session-format- 迁移链) | anti-rot idea |
| E10 | 启动前 Web 端口 3080 可用性(dsh web 自身占用=正常;其他进程=FAIL;DSH_DOCTOR_PORT 可覆盖) | #1719 |

profile

| ID | 检查 | 对应讨论 |
| P2 | bundle 层与用户 patch 的 insert id 冲突(启动必崩) | #1404 |
| P3 | 用户 patch 的 insert name: 能从 profile 锚点解析 | #1197, #880 |
| P4 | file: 依赖完整 | #1197 |
| P5 | 顶层无 @deepseek-ai/ 重复(双模块实例) | #1486, #1697 |
| P7 | cordis.patch.yml 结构 lint(~ insert: null 字面量、tab 缩进、缺冒号、顶层映射+序列混排 → UI 打不开) | #1724 |
| P12 | profile 内 bundle 版本 vs 运行 CLI(发词汇名 installed_bundle,#1719 v1.1:未声明=skip / manifest 撒谎或分歧=warn / 一致=pass;web「诊断」面板 / /dsh-doctor/run API 跑的是 bundle) | #1719 |
| P13 | client 半 provide 服务名抢注核心客户端服务(chatFileMentions 等 @deepseek-ai/dsh-client-,warn)或跨 bundle 同名(浏览器端 service already registered → UI 白屏、服务端日志无感知) | #2752 |
| P14 | 声明 bin 可执行性(目标文件在位 + 文本 bin 必须带 shebang;仅可执行位不识别解释器 → 直接执行 ENOEXEC,#1846) | #1846 |
| P16 | 插件导入了已装包未提供的命名导出(warn;单条坏 entry 即 boot 硬失败) | #5864 |
| P17 | client 端 require() 的模块宿主模块表无法服务(平台种子 ∪ 已装图行 ∪ 声明的 external)——warn 级;抓浏览器 Failed to load plugins 白屏 | #5719 |

session

| ID | 检查 | 对应讨论 |
| S1 | 孤儿 tool_call(无对应 tool result) | #1363, #1544 |
| S2 | 未闭合 turn(会话卡"运行中") | #466, #1265 |
| S6 | seq == index 连续性(官方语义,chunk 行按 expandRow 展开) | #1333, #1452, #1469 |
| S7 | end-seed 后重放(重放已提交尾部) | #1497 |
| S8 | 未知事件类型且无 ignorable(整包拒绝)——可读集 = 当前表 ∪ 已装 dsh-session-format- 迁移包认的旧类型 | #1538 |
| S9 | zstd 容器帧数(单帧日志 → session.list 整体 500) | #1043 |
| S10 | sourceEventSeqs 引用非更早事件 | #1469 |
| S11 | 全会话扫描:损坏 → 隔离建议;超大 / 工作区估算物化堆(max(事件×600B, 字节×6),默认 1GiB,DSH_DOCTOR_HEAP_MB)→ 冷启动卡顿风险 | #1550 |
| S12 | 迁移拒载预检:会被已装 dsh-session-format- 迁移链拒绝的会话日志(v0 subagent/descriptor 版本门;v2→v3 source.kind 白名单)——列表里看着在、点开却打不开 | #6045, #6328, #6311 |

备注

- S 类检查复刻了 harness 自身的校验(如 SessionLogScanner 的 seq == events.length + expandRow chunk 展开),所以离线结论与 boot/resume 实际行为一致。
- 尊重 $DSH_HOME(默认 ~/.dsh),可以用临时 home 干跑,不碰真实数据。
- 当前活跃 turn 的尾部 in-flight 工具调用按警告而非错误处理,扫活会话不会误报。
- 同生态位兄弟实现:boyin111-1/dsh-doctor —— 两工具用同一批坏 fixture 交叉验证过。

相关社区工具

dsh-doctor/v1 词汇表 r5 兼容,v1.1 installed_bundle 待认领 —— 起草 @ciceroyang(ciceroyang/dsh-doctor),审阅 @sjh9714(dsh-win32)与 @moonquake2004(#1719)。我们的 node/pnpm 检查按 r5 语义输出词汇名(pass/warn/fail/skip;summary.skip 常驻);P12 直接发 v1.1 词汇名 installed_bundle(四态 skip/warn/pass/warn,r6 表待发)。

- zoahdev/dsh-plugin-doctor —— 发布前插件 bundle 健康检查(manifest/patch/entry/files/build/pack+全新 profile 安装)+ 宿主遮蔽 profile-shadow 哨兵(作者/CI 侧)。与本工具的用户侧 profile/session/env 诊断互补;它的 profile-shadow 与我们的 P5 从两个方向标记同一个宿主遮蔽前置条件。
- boyin111-1/dsh-doctor —— 同生态位离线诊断兄弟实现,用同一批坏 fixture 交叉验证。

Symptom → check quick-start (dsh-diagnose alignment)

If you're coming from a symptom (rather than from the machine), these are the checks to run first. Coverage is honest: ✅ = direct offline coverage, ⚠️ = partial (we see the log/profile effects, not the runtime internals), ❌ = gap (runtime-only, no offline probe today).

| Symptom family | dsh-doctor checks | What they catch |
| session log corruption / can't resume | S1, S2, S6, S7, S8, S9, S10 | orphan tool calls, unclosed turns, seq gaps, end-seed replay, unknown event types, zstd single-frame, sourceEventSeqs drift |
| oversized / cold-start stall | S11 | estimated materialization heap, corrupt-session quarantine |
| boot failure (UI won't open) | P1–P10, E10 | dangling bundles, id collisions, patch syntax, host shadowing, adapter conflicts, client-service injects, port 3080 |
| tool registry gaps (tools missing) | P1, P2, P8, P10, P9 | unresolved/conflicting/duplicated tool registrations, client-only service injects |
| compaction / history unavailable | S10, S6, S8 | sourceEventSeqs not remapped after compaction |
| agent-loop lifecycle (session stuck "running") | S2, S1, S6 | unclosed turns, orphan tool calls, broken seq |
| llm retry storms | S6, S11, S2 | retry traffic effects on log integrity/size |
| token metering off | S11, S1, S2 | metering derives from the event stream |
| workflow script failures | P7, S6, S8, S1 | patch syntax (boot), workflow event integrity |
| approval policy pending | S2, S1 | open turns / orphan calls from pending or rejected approvals |
| credentials resolution | E2, E5, P4 | .env shape, storage JSON, file: links |
| web internals | E10, P10, E5 | port, client half, workspace storage |
| subagent depth | S11, S8 | session size, subagent event types |
| sandbox denials | E4 | node-pty binary (infra only) — ❌ runtime policy not offline-checkable |
| approval internals | S2 | ⚠️ runtime policy; only the turn-level effect |
| credentials internals | E2, E5 | ⚠️ file-level only |

The dsh-doctor/v1 envelope (--json --envelope) is the machine-readable form of any of these runs, so a symptom tool can consume the verdict directly. --remediation(配合 --json --envelope)输出 v1.1 可选 remediation 数组——失败项的有序 [检查名] 修复 行;不带该 flag 时字段不存在,r5 消费者字节稳定。

自更新检查(v0.2.1,层 B)

工具也会盯着自己的 npm 版本:每次运行对比已装版本与 dist-tags.latest(与目录同样的 6h TTL 缓存 + 离线回退)。有新版时打印提示、JSON 里报 update: { current, latest, available }——未经你要求绝不改动你的安装。

- --update —— 立即执行更新:在宿主 profile 里跑 pnpm install(可用 DSH_DOCTOR_UPDATE_CMD 覆盖),然后提示重启 dsh web。
- DSH_DOCTOR_AUTO_UPDATE=1 —— 有新版时自动更新。
- 诚实边界:cordis 启动时加载插件,新引擎要重启才生效——层 B 是"换文件 + 提醒重启",不做热替换。
- --no-catalog 同时禁用更新检查(纯离线模式)。

远程检查目录(v0.2.0,层 A)

内置 26 项检查编译在工具里。目录是第二层、自更新的:本仓库的 plugin/checks.json 放声明式规则(规则是数据,不是代码),所有已装实例自动获取新规则——无需重装。

- 工作机制:每次运行尝试从 GitHub 拉 plugin/checks.json(3s 超时)→ 成功后缓存到 $DSH_HOME/.cache/dsh-doctor/checks.json(TTL 6h)→ 失败回退 last-known-good 缓存 → 再回退内置副本。新检查因此在上游提交后 ≤6h 内自动到达。
- 安全性:规则是只读探测原语,由内置引擎执行(command-exists、path-*、json-valid、text-contains / text-not-contains、file-size-above、glob-count)。远程内容永远无法执行代码——只能新增模式检查。
- 严重级别:error(默认,改退出码)或 warn(只报告,不影响退出码)。--no-catalog 关闭远程拉取。
- 加一条检查(这就是重点——无需发版):往 plugin/checks.json 追加一条并提交即可。目前已随目录发布的检查:

| ID | 探测 | 检查 | 对应讨论 |
| E7 | command-exists | dsh 在 PATH | #1270 家族 |
| E8 | text-contains(warn) | profile .npmrc 含 ignore-workspace-root-check=true | dsh-market #20 |
| E9 | json-valid | config/workspace.json 可解析 | #1357 家族 |
| P6 | text-not-contains | patch insert name: 含空格(Windows spawn lint) | #1420 |

目录检查的结果在 JSON 输出中标 src: "catalog",CLI 输出标 [目录]。

LLM 观察者(v0.3.0,层 C)

第三层把"现场信号 → 目录条目"的回路半自动化:从诊断运行产出候选检查提案,人做最后把关(认证门禁不变)。设计与细节见 docs/layer-c-observer.md。

- dsh-doctor --observe run.json —— 聚类诊断运行的 fail/warn 信号(--json / --envelope 输出,或含 JSON 的目录),按目录 schema 起草候选检查(确定性,默认 severity: warn)。
- --observe-llm "<cmd>"(或 DSH_DOCTOR_LLM_CMD)—— 用 LLM 富化草稿:cmd 从 stdin 收 prompt,stdout 回 JSON。回复被封闭探测词表约束,任何解析/词表违规静默回退草稿。
- --observe-apply proposals.json —— 把校验通过的提案并入本地覆盖层 plugin/checks.local.json(幂等)。覆盖层参与本地诊断直到你认证该检查,但永不随包分发——认证后的检查应进 plugin/checks.json。

安全不变量:封闭探测词表(LLM 输出永远是数据、不是代码)、提案默认 warn、不自动上目录、不依赖任何外部服务(不带 --observe-llm 即确定性模式)。

也可作为 dsh 插件安装

工具以标准 dsh bundle 形态发布(plugin/),可以在 web UI 里跑同样的检查(28 内置 + 5 目录规则):

装进 profile(checkout 或已发布路径均可)
dsh plugin --profile web add file:/path/to/dsh-doctor/plugin

装完你会得到:

- 设置 → 诊断面板:一键跑全部检查,按 env / profile / session 分组渲染结果,带逐项修复建议与隔离建议(只展示建议,绝不自动执行);
- HTTP API:GET /dsh-doctor/run 返回同样的 JSON(可选 ?profile= / ?session= 收窄范围)。

架构:插件的服务端路由 shell 出 plugin/dsh-doctor.mjs --json——与 CLI 同一份真相源(检查按设计是离线/文件系统导向的,不需要 harness 内部接口)。仓库根目录的 dsh-doctor.mjs 是兼容 node dsh-doctor.mjs 的薄封装。

License

MIT
预览分享卡片长什么样 ↓moonquake2004/dsh-doctor
分享 · DeepSeek Harness Hub
moonquake2004/dsh-doctor

已针对 DSH 0.1.5-rc.1 验证会话格式 v3;dsh-session 定位覆盖 npx / 全局 /…

这是你的仓库?认领条目

回到顶部