@moonquake2004/dsh-doctor 0.4.13 → 0.4.14

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.
Files changed (2) hide show
  1. package/dsh-doctor.mjs +23 -0
  2. package/package.json +1 -1
package/dsh-doctor.mjs CHANGED
@@ -1149,6 +1149,23 @@ function checkSession(targetPath) {
1149
1149
  } else {
1150
1150
  report('session', 'S9', true, '非 zstd 输入,跳过容器检查', undefined);
1151
1151
  }
1152
+
1153
+ // S13:会话头完整性(#6651)——首行必须是 {"type":"session",...}
1154
+ // 实测:首行被写成事件时 dsh-doctor 的其余 S 检查**全部照常通过**(它们看的是事件流),
1155
+ // S11 甚至会报"均健康";而 harness 侧会 `corrupt Zstandard session log` 直接拒绝启动 `dsh web`。
1156
+ {
1157
+ const firstLine = String(text).split('\n').find((l) => l.trim());
1158
+ let header = null;
1159
+ try { header = firstLine ? JSON.parse(firstLine) : null; } catch { header = null; }
1160
+ if (!header || header.type !== 'session') {
1161
+ report('session', 'S13', false,
1162
+ `日志首行不是会话头(type=${header && header.type ? JSON.stringify(header.type) : '缺失/无法解析'})——#6651:此类损坏会让 \`dsh web\` **整体启动失败**(corrupt Zstandard session log: first frame is not exactly …),会话列表一并损坏`,
1163
+ '优先从备份恢复该日志;无备份时把整个会话目录**移出** sessions/(隔离,勿删)后重启 dsh,再用本工具复查');
1164
+ } else {
1165
+ report('session', 'S13', true,
1166
+ `会话头完整(type=session, version=${header.version ?? '?'}, id=${String(header.id ?? '').slice(0, 12)})`);
1167
+ }
1168
+ }
1152
1169
  const calls = new Map(); const results2 = new Set(); let maxSeq = -1;
1153
1170
  const turnStarts = new Set(); const turnEnds = new Set();
1154
1171
  const positions = []; const endSeedSeqs = [];
@@ -1462,11 +1479,17 @@ function scanAllSessions() {
1462
1479
  totalDS += ds;
1463
1480
  // 轻量损坏扫描:seq==index + end-seed 重放 + 未知类型
1464
1481
  const problems = [];
1482
+ let firstRowSeen = false;
1465
1483
  let evIndex = 0, lastSeed = -1, seedIdx = -1, posList = [];
1466
1484
  const lines = text.split('\n');
1467
1485
  for (let li = 0; li < lines.length; li++) {
1468
1486
  const ln = lines[li]; if (!ln.trim()) continue;
1469
1487
  let d; try { d = JSON.parse(ln); } catch { problems.push(`行 ${li + 1} 无法解析`); continue; }
1488
+ // #6651:首行必须是会话头——否则 harness 拒绝启动 dsh web,而其余检查看不出问题
1489
+ if (!firstRowSeen) {
1490
+ firstRowSeen = true;
1491
+ if (d.type !== 'session') problems.push(`首行不是会话头(#6651 启动阻断,实际 type=${d.type})`);
1492
+ }
1470
1493
  if (!STORAGE_ROW_TYPES.has(d.type) && !READABLE.has(d.type) && d.ignorable !== true) problems.push(`未知类型 ${d.type}`);
1471
1494
  if (d.type === 'session/end-seed' && typeof d.seq === 'number') { lastSeed = d.seq; seedIdx = posList.length; }
1472
1495
  const t = d.type;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moonquake2004/dsh-doctor",
3
- "version": "0.4.13",
3
+ "version": "0.4.14",
4
4
  "description": "Offline diagnostic for DeepSeek Harness — 28 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": [