chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
+ ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
This commit is contained in:
1 parent
c70d5d860e
commit
5ad755116e
173 files changed
+27632
No files matched your search
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 会话取证 · schema 探测:解压多帧 zstd → 事件类型直方图 + 每类样本键结构(先摸清格式)
|
||||
* 会话 schema 探测(只读):输出事件类型直方图 + 少量样本键结构
|
||||
* 用法:node probe-schema.mjs <session.jsonl.zstd>
|
||||
*/
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { zstdDecompressSync } from 'node:zlib'
|
||||
|
||||
const raw = readFileSync(process.argv[2])
|
||||
const MAGIC = Buffer.from([0x28, 0xb5, 0x2f, 0xfd])
|
||||
const offs = []
|
||||
for (let i = 0; i + 4 <= raw.length; i++) if (raw.compare(MAGIC, 0, 4, i, i + 4) === 0) offs.push(i)
|
||||
let text = ''
|
||||
const frames = offs.length ? offs : [0]
|
||||
for (let f = 0; f < frames.length; f++) {
|
||||
const s = frames[f], e = f + 1 < frames.length ? frames[f + 1] : raw.length
|
||||
try { text += zstdDecompressSync(raw.subarray(s, e)).toString('utf8') } catch {}
|
||||
}
|
||||
const lines = text.split('\n').filter((l) => l.trim())
|
||||
console.log('解压后 %d 行 / %d 字符 / zstd 帧 %d', lines.length, text.length, frames.length)
|
||||
|
||||
const types = new Map()
|
||||
const samples = new Map()
|
||||
for (const l of lines) {
|
||||
let o
|
||||
try { o = JSON.parse(l) } catch { continue }
|
||||
const t = o.type ?? o.event ?? o.kind ?? '(no-type)'
|
||||
types.set(t, (types.get(t) ?? 0) + 1)
|
||||
if (!samples.has(t)) samples.set(t, o)
|
||||
}
|
||||
console.log('\n=== 事件类型直方图 ===')
|
||||
for (const [t, n] of [...types].sort((a, b) => b[1] - a[1])) console.log(' %-28s %d', t, n)
|
||||
|
||||
console.log('\n=== 每类样本(键 + 截断值) ===')
|
||||
for (const [t, o] of samples) {
|
||||
console.log('--- %s ---', t)
|
||||
const dump = (v, depth = 0) => {
|
||||
if (v === null) return 'null'
|
||||
if (Array.isArray(v)) return `[${v.length} items${v.length ? ': ' + dump(v[0], depth + 1) : ''}]`
|
||||
if (typeof v === 'object') {
|
||||
if (depth > 1) return '{…}'
|
||||
return '{' + Object.entries(v).slice(0, 10).map(([k, x]) => `${k}: ${dump(x, depth + 1)}`).join(', ') + '}'
|
||||
}
|
||||
const s = String(v)
|
||||
return JSON.stringify(s.length > 90 ? s.slice(0, 90) + '…' : s)
|
||||
}
|
||||
console.log(' ' + dump(o).slice(0, 1200))
|
||||
}
|
||||
Reference in new issue
Block a user