@moonquake2004/dsh-doctor 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -47,6 +47,7 @@ With `--envelope` (doctor-contract mode): `0` = all pass · `1` = any WARN · `2
47
47
  | P4 | `file:` dependencies intact | [#1197](https://github.com/deepseek-ai/deepseek-harness/discussions/1197) |
48
48
  | P5 | no top-level `@deepseek-ai/*` duplication (dual module instances) | [#1486](https://github.com/deepseek-ai/deepseek-harness/discussions/1486), [#1697](https://github.com/deepseek-ai/deepseek-harness/discussions/1697) |
49
49
  | P7 | `cordis.patch.yml` structural lint (`~ insert:` null-literal typo, tab indentation, missing colon → UI won't boot) | [#1724](https://github.com/deepseek-ai/deepseek-harness/discussions/1724) |
50
+ | P12 | profile-installed bundle version vs running CLI (warn on divergence; the web "Doctor" panel / `/dsh-doctor/run` API runs the bundle) | [#1719](https://github.com/deepseek-ai/deepseek-harness/discussions/1719) v1.1 `installed_bundle` |
50
51
 
51
52
  ### session
52
53
  | ID | Checks | Discussion |
@@ -69,6 +70,8 @@ With `--envelope` (doctor-contract mode): `0` = all pass · `1` = any WARN · `2
69
70
 
70
71
  ## Related community tools
71
72
 
73
+ > **dsh-doctor/v1 vocabulary r5 compatible** — drafted by [@ciceroyang](https://github.com/ciceroyang) (ciceroyang/dsh-doctor), reviewed by [@sjh9714](https://github.com/sjh9714) (dsh-win32) and [@moonquake2004](https://github.com/moonquake2004) ([#1719](https://github.com/deepseek-ai/deepseek-harness/discussions/1719)). Our `node`/`pnpm` checks emit the vocabulary names with r5 semantics (pass/warn/fail/skip; `summary.skip` always present).
74
+
72
75
  - [zoahdev/dsh-plugin-doctor](https://github.com/zoahdev/dsh-plugin-doctor) — pre-publish plugin bundle health checks (manifest/patch/entry/files/build/pack+fresh-profile install) plus a `profile-shadow` tripwire for host-shadowing (author/CI side). Complementary to this tool's user-side profile/session/env diagnostics; its `profile-shadow` and our P5 flag the same host-shadowing precondition from two sides.
73
76
  - [boyin111-1/dsh-doctor](https://github.com/boyin111-1/dsh-doctor) — sibling offline diagnostic, cross-verified against the same broken fixtures.
74
77
 
package/README.zh.md CHANGED
@@ -42,6 +42,7 @@ node dsh-doctor.mjs --no-catalog # 不拉远程目录(只用内置副
42
42
  | P4 | `file:` 依赖完整 | [#1197](https://github.com/deepseek-ai/deepseek-harness/discussions/1197) |
43
43
  | P5 | 顶层无 `@deepseek-ai/*` 重复(双模块实例) | [#1486](https://github.com/deepseek-ai/deepseek-harness/discussions/1486), [#1697](https://github.com/deepseek-ai/deepseek-harness/discussions/1697) |
44
44
  | P7 | `cordis.patch.yml` 结构 lint(`~ insert:` null 字面量、tab 缩进、缺冒号、顶层映射+序列混排 → UI 打不开) | [#1724](https://github.com/deepseek-ai/deepseek-harness/discussions/1724) |
45
+ | P12 | profile 内 bundle 版本 vs 运行 CLI(分歧 warn;web「诊断」面板 / `/dsh-doctor/run` API 跑的是 bundle) | [#1719](https://github.com/deepseek-ai/deepseek-harness/discussions/1719) v1.1 `installed_bundle` |
45
46
 
46
47
  ### session
47
48
  | ID | 检查 | 对应讨论 |
@@ -64,6 +65,8 @@ node dsh-doctor.mjs --no-catalog # 不拉远程目录(只用内置副
64
65
 
65
66
  ## 相关社区工具
66
67
 
68
+ > **dsh-doctor/v1 词汇表 r5 兼容** —— 起草 [@ciceroyang](https://github.com/ciceroyang)(ciceroyang/dsh-doctor),审阅 [@sjh9714](https://github.com/sjh9714)(dsh-win32)与 [@moonquake2004](https://github.com/moonquake2004)([#1719](https://github.com/deepseek-ai/deepseek-harness/discussions/1719))。我们的 `node`/`pnpm` 检查按 r5 语义输出词汇名(pass/warn/fail/skip;`summary.skip` 常驻)。
69
+
67
70
  - [zoahdev/dsh-plugin-doctor](https://github.com/zoahdev/dsh-plugin-doctor) —— 发布前插件 bundle 健康检查(manifest/patch/entry/files/build/pack+全新 profile 安装)+ 宿主遮蔽 `profile-shadow` 哨兵(作者/CI 侧)。与本工具的用户侧 profile/session/env 诊断互补;它的 `profile-shadow` 与我们的 P5 从两个方向标记同一个宿主遮蔽前置条件。
68
71
  - [boyin111-1/dsh-doctor](https://github.com/boyin111-1/dsh-doctor) —— 同生态位离线诊断兄弟实现,用同一批坏 fixture 交叉验证。
69
72
 
package/dsh-doctor.mjs CHANGED
@@ -14,6 +14,7 @@
14
14
  * P9 ctx.settings 未声明 inject: ['settings'](#1904⑤:先于 settings 就绪激活 → namespace not registered)
15
15
  * P10 inject 引用客户端专属服务(#1947:@deepseek-ai/dsh-client-* 服务端永不提供 → Fiber 永久 PENDING → web boot 失败)
16
16
  * P11 已装 bundle 的 main 入口产物缺失(#1965:市场装未构建源码树 → ERR_MODULE_NOT_FOUND → boot 崩)
17
+ * P12 profile 内 bundle 版本 vs 运行 CLI 版本(#1719 v1.1 `installed_bundle` 候选:web 面板/API 跑的是 profile 里装的 bundle,可与独立 CLI 版本不一致)
17
18
  * [session]
18
19
  * S1 孤儿 tool_call(#1363:assistant tool_calls 无对应 tool 结果 → INVALID_REQUEST)
19
20
  * S2 未闭合 turn(#466/#1265:turn/start 无 turn/end → 会话永久"运行中")
@@ -108,12 +109,19 @@ function resolveProfile(name) {
108
109
  }
109
110
 
110
111
  /* ================= env ================= */
112
+ /** v1 词汇表 r5(#1719)node 语义:pass = 满足 ^22.19.0 || >=24.0.0(root package.json engines),其余 warn——无民间 fail 阈值。 */
113
+ function nodeInSupportedRange(v) {
114
+ const m = /^v?(\d+)\.(\d+)\.(\d+)/.exec(String(v));
115
+ if (!m) return false;
116
+ const major = Number(m[1]); const minor = Number(m[2]);
117
+ return (major === 22 && minor >= 19) || major >= 24;
118
+ }
111
119
  function checkEnv() {
112
120
  if (!wants('env')) return;
113
121
  const find = (cmd) => { for (const w of process.platform === 'win32' ? ['where'] : ['which']) { const r = spawnSync(w, [cmd]); if (r.status === 0) { const p = String(r.stdout).split(/\r?\n/)[0].trim(); if (p) return p; } } return null; };
114
122
  for (const cmd of ['node', 'pnpm', 'zstd']) {
115
123
  const p = find(cmd);
116
- report('env', `E1-${cmd}`, !!p, p ? `${cmd}: ${p}` : `${cmd} 不在 PATH(${cmd === 'node' ? '创建会话会失败 #1270' : cmd === 'pnpm' ? 'dsh plugin 不可用' : '会话日志解压不可用'})`, p ? undefined : `安装 ${cmd} 或加入 PATH`);
124
+ report('env', `E1-${cmd}`, !!p, p ? `${cmd}: ${p}` : `${cmd} 不在 PATH(${cmd === 'node' ? '创建会话会失败 #1270' : cmd === 'pnpm' ? 'dsh plugin 不可用(corepack 可恢复:corepack enable pnpm)' : '会话日志解压不可用'})`, p ? undefined : (cmd === 'pnpm' ? 'corepack enable pnpm 或安装 pnpm 后加入 PATH' : `安装 ${cmd} 或加入 PATH`));
117
125
  }
118
126
  const envFile = join(HOME, '.env');
119
127
  if (existsSync(envFile)) {
@@ -121,7 +129,13 @@ function checkEnv() {
121
129
  report('env', 'E2-env', !isDir, isDir ? `${envFile} 是目录,dsh 启动会报 failed to load .env: EISDIR(#71)` : `${envFile} 正常`, isDir ? '删除或改名该目录' : undefined);
122
130
  }
123
131
  const nv = spawnSync('node', ['-e', 'console.log(process.version)']);
124
- if (nv.status === 0) report('env', 'E3-node', true, `node ${String(nv.stdout).trim()}`, undefined);
132
+ if (nv.status === 0) {
133
+ const version = String(nv.stdout).trim();
134
+ const supported = nodeInSupportedRange(version);
135
+ report('env', 'E3-node', supported,
136
+ supported ? `node ${version}(满足 ^22.19.0 || >=24.0.0,root package.json engines)` : `node ${version} 不在支持范围(^22.19.0 || >=24.0.0)——会话日志读取等能力受限`,
137
+ supported ? undefined : '升级 node 到 ^22.19.0 或 >=24.0.0(root package.json engines,见 #2259)');
138
+ }
125
139
 
126
140
  // E4:node-pty 原生模块完整性(#1219:pty.node 缺失 → dsh web 启动失败)
127
141
  const ptyDirs = [];
@@ -517,6 +531,32 @@ function checkProfile(name) {
517
531
  }
518
532
  if (entryIssues.length) report('profile', 'P11', false, `已装 bundle 的 main 入口缺失(#1965:市场装源码不跑构建 → ERR_MODULE_NOT_FOUND → dsh web boot 崩溃): ${entryIssues.join('; ')}`, '在插件目录跑构建(pnpm install && pnpm run build 产出 main 指向的文件),或改用打包好的 npm 包安装;monorepo 插件需装子包(dsh-market #18 同族)');
519
533
  else report('profile', 'P11', true, '已装 bundle 的 main 入口产物均在', undefined);
534
+
535
+ // P12:profile 内 bundle 版本 vs 运行 CLI 版本(#1719 v1.1 `installed_bundle` 候选)
536
+ // web 设置「诊断」面板与 /dsh-doctor/run API 跑的是 profile 里装的 bundle;独立 CLI(checkout/npx)是另一个副本——
537
+ // Layer-B 自更新只比 npm latest vs 运行模块,profile 内 bundle 落后/超前都不报警(dsh-win32/bundle 同坑,sjh9714 先发现的)。
538
+ // 语义(#1719 提名):ok = 版本一致;warn = 分歧。profile 未装本插件 = 无对比对象,放行。
539
+ try {
540
+ const selfName = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')).name ?? '@moonquake2004/dsh-doctor';
541
+ // 安装形态两种都找:npm scoped 名(@moonquake2004/dsh-doctor)与 file: 依赖的裸名(dsh-doctor)
542
+ let bundlePkg = null;
543
+ for (const cand of [selfName, 'dsh-doctor']) {
544
+ const p = join(dir, 'node_modules', cand, 'package.json');
545
+ if (existsSync(p)) { bundlePkg = p; break; }
546
+ }
547
+ if (!bundlePkg) {
548
+ report('profile', 'P12-bundle-version', true, 'profile 未安装 dsh-doctor bundle,跳过版本对比(CLI 独立运行)', undefined);
549
+ } else {
550
+ const bundleVersion = JSON.parse(readFileSync(bundlePkg, 'utf8')).version;
551
+ const cliVersion = localVersion();
552
+ const same = bundleVersion === cliVersion;
553
+ report('profile', 'P12-bundle-version', same,
554
+ same ? `profile 内 bundle 版本 ${bundleVersion} 与运行 CLI ${cliVersion} 一致` : `profile 内 bundle 版本 ${bundleVersion} ≠ 运行 CLI ${cliVersion}(web 面板/API 跑的是 bundle,两边行为可能不一致)`,
555
+ same ? undefined : `同步安装版本:dsh plugin --profile ${name} update ${selfName}(或让 CLI 与 bundle 走同一安装方式)`);
556
+ }
557
+ } catch (e) {
558
+ report('profile', 'P12-bundle-version', false, `bundle 版本对比异常: ${e.message.slice(0, 60)}`, undefined);
559
+ }
520
560
  }
521
561
 
522
562
  /* ================= session ================= */
@@ -749,6 +789,10 @@ function scanAllSessions() {
749
789
  const REMOTE_CATALOG_URL = 'https://raw.githubusercontent.com/moonquake2004/dsh-doctor/main/plugin/checks.json';
750
790
  const CATALOG_TTL_MS = 6 * 60 * 60 * 1000; // 6h:新检查最长 6h 内自动生效
751
791
  const catalogSeverity = new Map(); // catalog 检查 id → severity('error' | 'warn')
792
+ // v1 词汇表 r5 对齐(#1719):E1-pnpm 缺失=warn(corepack 可恢复)、E3-node 越界=warn(EBADENGINE 语义)、P12 bundle 版本分歧=warn(v1.1 `installed_bundle` 候选)——均不翻退出码
793
+ catalogSeverity.set('E1-pnpm', 'warn');
794
+ catalogSeverity.set('E3-node', 'warn');
795
+ catalogSeverity.set('P12-bundle-version', 'warn');
752
796
 
753
797
  function bundledCatalog() {
754
798
  const p = new URL('./checks.json', import.meta.url);
@@ -1102,7 +1146,7 @@ async function run() {
1102
1146
  if (jsonOut && process.argv.includes('--envelope')) {
1103
1147
  // v1 契约信封(dsh doctor 规格,zoahdev/doctor 对齐):status 小写 + 退出码 0/1/2
1104
1148
  const st = (r) => (!r.ok ? (catalogSeverity.get(r.id) === 'warn' ? 'warn' : 'fail') : 'pass');
1105
- const summary = { pass: 0, warn: 0, fail: 0 };
1149
+ const summary = { pass: 0, warn: 0, fail: 0, skip: 0 }; // skip 常驻(v1 词汇表 r5:#1719),当前无平台作用域检查所以恒为 0
1106
1150
  const checks = results.map((r) => { summary[st(r)]++; return { name: r.id, status: st(r), detail: r.detail }; });
1107
1151
  const exitCode = summary.fail > 0 ? 2 : summary.warn > 0 ? 1 : 0;
1108
1152
  console.log(JSON.stringify({
@@ -1142,4 +1186,4 @@ async function run() {
1142
1186
  // 直接执行(CLI:根目录薄封装、plugin 本体、npm bin 均可);被 import(测试/宿主)时不自动运行
1143
1187
  if (process.argv[1] && /^dsh-doctor(\.mjs)?$/.test(basename(process.argv[1]))) run();
1144
1188
 
1145
- export { loadCatalog, bundledCatalog, validCatalog, expandPath, globCount, checkCatalog };
1189
+ export { loadCatalog, bundledCatalog, validCatalog, expandPath, globCount, checkCatalog, nodeInSupportedRange };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moonquake2004/dsh-doctor",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Offline diagnostic for DeepSeek Harness — 25 built-in + 5 catalog checks across env/profile/session (Layer A checks-as-data), self-update (Layer B), and a semi-automatic LLM observer (Layer C, --observe); Doctor panel in web UI settings.",
5
5
  "main": "lib/index.js",
6
6
  "files": [