ygl-trees 0.78.0 → 0.80.0
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/CHANGELOG.md +30 -0
- package/README.md +28 -4
- package/dist/apps/cli/src/bin.js +34 -7
- package/dist/bundle/bin.cjs +725 -110
- package/dist/packages/core/database/src/db.js +73 -5
- package/dist/packages/knowledge/skills/src/cmds.js +26 -1
- package/dist/packages/ops/tools/src/agent-cmds.js +35 -0
- package/dist/packages/ops/tools/src/db-cmds.js +70 -0
- package/dist/packages/ops/tools/src/doctor.js +79 -24
- package/dist/packages/ops/tools/src/webui.js +9 -0
- package/dist/packages/research/pipeline/src/cmds.js +120 -14
- package/dist/packages/research/pipeline/src/predict.js +82 -9
- package/dist/packages/research/produce/src/produce-cmds.js +6 -0
- package/dist/packages/research/produce/src/project-cmds.js +27 -2
- package/dist/packages/techtree/model/src/cmds.js +236 -72
- package/dist/packages/techtree/model/src/reads.js +59 -1
- package/package.json +5 -4
- package/skills/ygl-trees-eval-gates/SKILL.md +6 -1
- package/skills/ygl-trees-quickstart/SKILL.md +18 -7
- package/skills/ygl-trees-relating/SKILL.md +5 -0
- package/skills/ygl-trees-research/SKILL.md +7 -0
- package/skills/ygl-trees-techtree/SKILL.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.80.0(2026-10-17)rel 织物并入 eval 上下文 + 会话内裁决载体
|
|
4
|
+
- **eval 上下文包并入 rel 挂接摘要**(用户实测发现:裁决已 `decided-by` 挂链,P 仍 0.30,必须 `--state k=v` 手动携带事实才 0.92):`evalContext` 新增 `attachments`——节点挂接的 relations 双向查询(≤12 条),claim 摘录 text+status+confidence、evidence 摘录 quote(截 120 字)、kb/source 标题、node key+name、其余 id-only;无挂接时字段缺省(与旧形状逐字节兼容)
|
|
5
|
+
- **`research source add --adjudication "<裁决摘要>"`**:会话内裁决原生载体——url 自动 `session://adjudication/<yyyymmddhhmm>`,摘要兼作缺省标题;`--url` 校验放宽收 `session://`;裸 `--adjudication` 旗标缺值 rc=2
|
|
6
|
+
- 测试:`packages/techtree/model/tests/evalctx.spec.ts` 5 例(无挂接兼容 / decided-by 摘要 / 反向 evidenced-by / 截断与悬空退化 / 12 条上限);`scripts/readme-verify.sh` +1(--adjudication rc=0)
|
|
7
|
+
|
|
8
|
+
## 0.79.1(2026-10-17)锁身份 + serve --help 短路 + 批量判定 + 回测状态桥
|
|
9
|
+
- **异常①锁归属**:`.ygllock` 记录持有者命令行;撞锁报错、`db unlock`(含 `holder_cmd` JSON 字段)、`doctor` 三处回显真实持有者身份——CLI 撞 CLI 不再被误标为 serve(serve 从不取写锁,报错明示这一点)
|
|
10
|
+
- **异常②**:`webui serve --help` 短路打印用法即退出,不再直接启动服务(随机端口误触发实证)
|
|
11
|
+
- **异常③**:serve 写锁警告改为如实措辞(WAL 并发读写安全,批量写才建议停 serve)
|
|
12
|
+
- **回归修复**:无锁进程(serve / db unlock)退出不再误清并行会话的活锁(ownsLock 所有权守卫——自 serve 时代潜伏的 unconditional releaseLockFor);`db unlock` 改为无锁模式启动,自身诊断命令不再被诊断对象卡死,其"活 holder 拒绝/--force/死 pid 清理"三条路径首次真正可达
|
|
13
|
+
- **特性①** `node can` 批量判定 + `--state-file <json>`:多键一进程(探针冷启动 1s×N → 1s);状态袋两种形状——扁平计数共享 / 按节点 `{key: bag}` 各取各袋;多键 `--json` 返回数组;`ready --state-file` 同步支持(扁平)
|
|
14
|
+
- **特性②** `job add` 接探针实证可用(任意命令 + `--every N` 本就支持,README 补闸门探针模式)
|
|
15
|
+
- **特性③(m02806)** predict audit:已 `claim resolve` 的预测默认隐藏(回测终态 resolved),`--all` 查看全表;空表提示
|
|
16
|
+
- **特性④(m02801)** predict audit `--state <file|url>`:外部计数桥接(HTTP 3s 超时 / 本地文件),嵌套对象扁平化(`{counts:{y:12}}` → `counts.y=12`),判据裸键名后缀匹配(`y_imported≥12` ← `counts.y_imported`,实测列显示来源键);加载失败回落 manual 并警告
|
|
17
|
+
- 修复 `node can` 无 `--state-file` 时误报 usage rc=2 的回归(demo 门禁当场抓获——无标记路径此前未测)
|
|
18
|
+
- 单测 163(+7:state 桥接/后缀匹配/resolved 终态/loadStateSource)、demo 82(+8:5g 锁身份+批量+状态桥)、readme:verify 38(+4)
|
|
19
|
+
|
|
20
|
+
## 0.79.0(2026-10-17)真实用户反馈硬化(四异常 + 六特性)
|
|
21
|
+
- **报告②新命令** `db unlock`:清残留 .ygllock——pid 存活检测,死 pid 直接清;活 holder(并行会话/serve)拒绝并解释,`--force` 才强清;自持锁(boot 期间获得)自清不死锁
|
|
22
|
+
- **报告②** doctor 锁检查升级 pid 存活判定:外进程活锁=PASS(多会话正常态),死 pid 才告警;`--fix` 只清死锁(此前会误删并行会话的活锁)
|
|
23
|
+
- **报告③** 选择变更事件化:`tree use`/`project use`/`tree new`/`project new`/`node import` 全落 `tree.use`/`project.use` 事件(带 `YGL_SESSION`);`agent brief` 新增 `selection_changed`(最近 10 分钟),跨会话变更置顶提示带 `-t`/`-p`
|
|
24
|
+
- **报告③** node not found 增强:key 在其他树 → 点名树并给 `-t` 提示;不存在 → 显示当前树名(并行会话翻转 current_tree 后错误自解释)
|
|
25
|
+
- **报告①** kb add 回执自检:提交后立即 kbGet 回读,`--json` 带 `verified:true` + `workspace`;人类模式回显 `@ <home>`(防写错 home 的"丢笔记");doctor 第 10 项 write_integrity:回放近 2 天 kb/source/evidence 写事件对账基表,幻影写入点名
|
|
26
|
+
- **报告④** claim link 三 id 纲目修复:误传来源 id → 列出该来源证据 id + 建议;无证据来源 → 提示先 evidence add;`--by-source` 批量挂齐来源下全部证据
|
|
27
|
+
- **报告⑤新命令** `node timeline <tree>`:单树成长时间线(add/link/unlock 事件倒序 30 条)
|
|
28
|
+
- **报告⑤** `research evidence add --file <path>`:长摘录免 shell 转义(与 --quote 互斥,空文件 rc=2)
|
|
29
|
+
- **确认①** produce spec 拒绝 `--design-type`(rc=2 并指向 produce design)
|
|
30
|
+
- **确认②** project new 回执提示前项目不再选中 + 回切命令
|
|
31
|
+
- 单测 156(+5:pidAlive/lockHolder 语义)、demo 74(+5:5f 反馈硬化断言)、contract 86
|
|
32
|
+
|
|
3
33
|
## 0.78.0(2026-10-17)预测回测管线
|
|
4
34
|
- **新命令** `research predict audit`:扫描 [预测·N天] 断言——deadline 解析(显式日期优先,created+horizon 推导兜底)、本地可测判据自动实测(树/kb 计数,或语义 any-hit)、npm 版本数 registry 探测(3s 超时,--offline 关闭)
|
|
5
35
|
- 判定四态:hit / miss / pending(含已达标标记)/ manual(外部判据)——只报告不仲裁,给出待 resolve 命令建议
|
package/README.md
CHANGED
|
@@ -88,9 +88,11 @@ ygl-trees node link bronze steel --optional # 可选,不阻塞
|
|
|
88
88
|
ygl-trees node link bronze iron --mode OR # 任一即可
|
|
89
89
|
ygl-trees node link a b --rel excludes # 互斥分支
|
|
90
90
|
ygl-trees node can steel --state "research_lab_level=3,has_engineer=1"
|
|
91
|
+
ygl-trees node can a b c --state-file probe.json # 批量判定:一进程测 N 节点(探针冷启动 1s×N → 1s)
|
|
91
92
|
ygl-trees node ready # 当前可解锁集合
|
|
92
93
|
ygl-trees node path advanced-alloy # 到目标的最省顺序 + 累计成本
|
|
93
94
|
ygl-trees node ancestors bronze # 闭包索引,直接父 depth=1
|
|
95
|
+
ygl-trees node timeline demo # 单树成长时间线(add/link/unlock 倒序)
|
|
94
96
|
ygl-trees node export --out tree.json # 可移植 JSON
|
|
95
97
|
ygl-trees node import --file tree.json --tree copy # 严格校验、事务导入
|
|
96
98
|
```
|
|
@@ -99,7 +101,11 @@ ygl-trees node import --file tree.json --tree copy # 严格校验、事务导
|
|
|
99
101
|
|
|
100
102
|
`node can` 的输出把三类失败分开列:**必检未满足 / 被排斥 / 可选未满足(不阻塞)**,外加成本系数。
|
|
101
103
|
|
|
102
|
-
|
|
104
|
+
**批量判定 + `--state-file`(0.79.1)**:`node can k1 k2 k3` 一次进程判定多节点(多键自动进批模式,`--json` 返回数组);`--state-file <json>` 喂状态袋,两种形状——**扁平计数** `{"y_imported": 40}` 全节点共享,或**按节点** `{"a": {"y_imported": 40}, "b": {...}}` 各取各袋。探针脚本从此每树起一次进程而非每节点。
|
|
105
|
+
|
|
106
|
+
**决策模型评估门(spec R8;0.14 布尔 → 0.26 三题型 → 0.27 混批 → 0.80 织物并入)**:语义型必检条件用 eval 题型声明,`node can <key> --eval` 会把**节点元数据 + 直接父(关联)+ 祖先链(闭包索引)+ 条件组 + 已解锁集 + --state 袋 + rel 挂接摘要**组装为上下文包,交给评估模型(TypeSafe jev,经 Vercel AI Gateway)判定:
|
|
107
|
+
|
|
108
|
+
- **rel 织物并入(0.80)**:节点挂接的 evidence(quote 摘要)/ claim(text+status+confidence)/ kb/source(标题)等 rel 关系(双向,≤12 条,文本截 120 字)自动进上下文包的 `attachments`——「证据挂链」纪律从此对语义门槛可见,不必再 `--state k=v` 手动携带裁决事实(实测 P 0.30 → 0.92 的差距由挂链补平)
|
|
103
109
|
|
|
104
110
|
- **三题型**:`--op eval`(布尔 P(true))/ `--op eval-choice`(多选一,判 **P(期望答案)**,`--options "k=desc,..."` + `--answer k`)/ `--op eval-score`(等级评分 `--levels "级0,..."` 2-10 级 + `--min-score n`,判概率加权均值 ±1 灰带)
|
|
105
111
|
- P≥0.7 通过 · P≤0.4 未通过 · **灰带 pending**(过程态,禁作终态,单列不阻塞也不放行);score 的灰带是 [min−1, min)
|
|
@@ -120,12 +126,16 @@ ygl-trees node import --file tree.json --tree copy # 严格校验、事务导
|
|
|
120
126
|
query add 登记检索式
|
|
121
127
|
query attach 检索式 ↔ 来源关联(query list 显示召回数)
|
|
122
128
|
source add 收来源,按 (project, url_hash) 去重;--query 顺带关联
|
|
129
|
+
--adjudication "<裁决摘要>":会话内裁决原生载体(url 自动 session://adjudication/<时刻>,摘要兼作标题);--url 也收 session://
|
|
123
130
|
source fetch <url> 直接抓取网页入库:title/meta description/去标签正文;15s 超时、非 html 拒收、失败零副作用,正文过薄自动打 needs_review
|
|
124
|
-
evidence add 从来源摘原文片段,带 locator
|
|
131
|
+
evidence add 从来源摘原文片段,带 locator(页码/章节);长摘录用 --file <path> 免转义
|
|
125
132
|
claim add 写下断言
|
|
126
133
|
claim link 断言 ↔ 证据,自动算 supported / refuted / contested
|
|
134
|
+
--by-source:传来源 id 一次挂齐其全部证据;误传来源 id 会列出该来源的证据 id
|
|
127
135
|
claim resolve 人工仲裁出口:--as supported|refuted|contested,事件留痕;后续新证据链接会重新推导
|
|
128
136
|
predict audit 预测回测:扫描 [预测·N天] 断言,本地可测判据自动测(树/kb 计数、npm 版本数),判 hit/miss/pending/manual——只报告不仲裁,给出待 resolve 建议
|
|
137
|
+
--state <file|url>:外部计数桥接(如 DSH API 快照),判据里的裸键名后缀匹配嵌套键(y_imported≥12 ← counts.y_imported)
|
|
138
|
+
已 claim resolve 的预测默认隐藏(回测终态),--all 查看全表
|
|
129
139
|
```
|
|
130
140
|
|
|
131
141
|
**JSON 纪律**:写命令在 `--json` 下 stdout 只有一个 JSON 对象(重复时带 `duplicate: true`),Agent 可直接 `JSON.parse` 全量输出。
|
|
@@ -251,6 +261,7 @@ CJK 检索是个坑:FTS5 默认 `unicode61` 会把整句中文当成一个 tok
|
|
|
251
261
|
|
|
252
262
|
```bash
|
|
253
263
|
ygl-trees job add "nightly" -- "ygl-trees produce report" --every 1440
|
|
264
|
+
ygl-trees job add "闸门探针" -- "node ~/.local/lib/ygl-trees/tmp/dsh-tree-probe.mjs" --every 30 # 树自带节奏化监控(0.79.1 实证用法)
|
|
254
265
|
ygl-trees job tick # cron 每分钟调它,只跑到期的任务
|
|
255
266
|
ygl-trees job logs
|
|
256
267
|
```
|
|
@@ -273,7 +284,7 @@ ygl-trees agent ask "<question>" natural language interface
|
|
|
273
284
|
## 五b、开发与运维工具
|
|
274
285
|
|
|
275
286
|
```bash
|
|
276
|
-
pnpm test # 四段制回归:unit (vitest
|
|
287
|
+
pnpm test # 四段制回归:unit (vitest 163 例) + build (tsc + tsdown) + demo(82 条断言)+ contract:audit(86 项)
|
|
277
288
|
pnpm bench # 性能基准七席(startup/写路径/检索/索引),每席含 RSS 内存端点 → tmp/bench-results.json
|
|
278
289
|
node benchmarks/bench.js --quick # 缩小规模快速跑
|
|
279
290
|
pnpm pack:check # 发布就绪门禁:打包 → 隔离安装 → 驱动发布产物跑命令面 + --json 纯净性
|
|
@@ -281,11 +292,24 @@ ygl-trees --version # 打印版本号
|
|
|
281
292
|
ygl-trees llms # 结构化能力清单(LLM 参考一次性获取全部命令面)
|
|
282
293
|
pnpm contract:audit # 写路径契约体检:写命令跑两次必须 rc=0、重复回执 duplicate、坏引用点名、用法 rc=2
|
|
283
294
|
pnpm smoke:bun # Bun 运行时探针(Windows 当前受阻,见 docs/bun-compat.md)
|
|
284
|
-
ygl-trees doctor # 工作区健康检查
|
|
295
|
+
ygl-trees doctor # 工作区健康检查 10 项(--fix 一键安全修复)(schema/索引/FTS/重复/孤儿/config/锁存活/eval 信封/插件 profile/幻影写入)
|
|
296
|
+
ygl-trees db unlock # 清残留 .ygllock:查 pid 存活,死 pid 直接清;活 holder(回显其命令行)拒绝并说明,--force 才强清
|
|
297
|
+
ygl-trees node timeline <tree> # 单树成长时间线(add/link/unlock 事件倒序)
|
|
285
298
|
ygl-trees webui serve # React 富客户端(http://127.0.0.1:8642/,SSE 实时推送,Ctrl+C 停)
|
|
299
|
+
ygl-trees webui serve --help # 打印用法即退出,不启服务(0.79.1:--help 短路)
|
|
286
300
|
ygl-trees webui export --out d.html # 零依赖单文件仪表盘(离线可开)
|
|
287
301
|
```
|
|
288
302
|
|
|
303
|
+
**锁身份(0.79.1)**:`.ygllock` 里除 pid 外记录**持有者命令行**;撞锁报错、`db unlock`、`doctor`
|
|
304
|
+
三处都会回显真实持有者(如 `node bin.cjs node unlock trend-collector`),不再把 CLI 会话误标成
|
|
305
|
+
serve。serve 从不取写锁(WAL 并发读写安全),`db unlock` 也以无锁模式启动——自己的诊断命令
|
|
306
|
+
不该被诊断对象卡住。
|
|
307
|
+
|
|
308
|
+
**多会话安全(0.79)**:`tree use` / `project use` 全部落 `tree.use` / `project.use` 事件(带
|
|
309
|
+
`YGL_SESSION` 会话标识);`agent brief` 的 `selection_changed` 字段暴露最近 10 分钟的选择变更,
|
|
310
|
+
跨会话变更会置顶提示命令带 `-t/-p` 固定上下文。`kb add` 回执自带 `verified` 自检与工作区回显,
|
|
311
|
+
`doctor` 第 10 项回放近 2 天 kb/source/evidence 写事件对账基表,幻影写入当场点名。
|
|
312
|
+
|
|
289
313
|
**提交门禁(无 CI 环境的等效方案)**:`.githooks/pre-push` —— push 分支跑 `pnpm test`,
|
|
290
314
|
**push tag 追加 `pnpm pack:check`**;旁路只能显式 `YGL_SKIP_HOOKS=1`。安装一次:
|
|
291
315
|
`git config core.hooksPath .githooks`。(本仓库 Gitee Go 服务对当前账户 403 不可用,见 [docs/release.md](docs/release.md)。)
|
package/dist/apps/cli/src/bin.js
CHANGED
|
@@ -157,10 +157,11 @@ ${(0, fmt_1.paint)(fmt_1.C.bold, "research", true)} collect → screen → ex
|
|
|
157
157
|
source add --title --url [--abstract --content --relevance --confidence --query]
|
|
158
158
|
source fetch <url> fetch page, extract title/meta/text (zero side-effect on failure)
|
|
159
159
|
source list | search "<q>" | show <id> | rm <id>
|
|
160
|
-
evidence add <sourceId> --quote "..." [--note --locator]
|
|
160
|
+
evidence add <sourceId> --quote "..." | --file <path> [--note --locator]
|
|
161
161
|
evidence list
|
|
162
162
|
claim add "<text>" [--confidence A|B|C]
|
|
163
163
|
claim link <claimId> <evidenceId> [--stance supports|refutes]
|
|
164
|
+
--by-source <claimId> <sourceId>: link ALL evidence under a source
|
|
164
165
|
claim resolve <claimId> --as supported|refuted|contested [--note]
|
|
165
166
|
claim list
|
|
166
167
|
|
|
@@ -216,6 +217,7 @@ ${(0, fmt_1.paint)(fmt_1.C.bold, "tree / node", true)} tech-tree node model
|
|
|
216
217
|
node validate cycles, dangling edges, dirty index
|
|
217
218
|
node export [--out file.json] portable JSON
|
|
218
219
|
node import --file <file.json> [--tree name] [--merge] — strict, transactional
|
|
220
|
+
node timeline [tree] per-tree growth history (add/link/unlock events)
|
|
219
221
|
|
|
220
222
|
Writes are idempotent (claim/evidence/query/kb/job dedupe by content
|
|
221
223
|
hash); pass --force to keep a deliberate duplicate.
|
|
@@ -273,6 +275,13 @@ async function main(argv) {
|
|
|
273
275
|
if (group === "webui" && (action === "serve" || action === "export")) {
|
|
274
276
|
process.env.YGL_SERVE = "1";
|
|
275
277
|
}
|
|
278
|
+
// 0.79.1 (R297 user report follow-up): `db unlock` must be callable WHILE
|
|
279
|
+
// another process holds the lock — otherwise its live-holder refusal and
|
|
280
|
+
// --force paths are unreachable (boot would collide first). It only touches
|
|
281
|
+
// the lock dir on the filesystem, never the DB, so boot lock-free.
|
|
282
|
+
if (group === "db" && action === "unlock") {
|
|
283
|
+
process.env.YGL_SERVE = "1";
|
|
284
|
+
}
|
|
276
285
|
// P4 fix: --version prints the actual version number (cold-user report);
|
|
277
286
|
// the parser eats --version as a flag, so check flags not positional args.
|
|
278
287
|
if (args.flags.version === true || group === "version") {
|
|
@@ -417,8 +426,18 @@ async function main(argv) {
|
|
|
417
426
|
alive = err.code === "EPERM";
|
|
418
427
|
}
|
|
419
428
|
if (alive) {
|
|
420
|
-
|
|
421
|
-
|
|
429
|
+
// 0.79.1 (R297 user report): the old hint guessed "(serve? webui
|
|
430
|
+
// dashboard)" — serve never takes the write lock, so the guess sent
|
|
431
|
+
// users to kill the wrong process. Echo the holder's self-reported
|
|
432
|
+
// command line from the lock dir instead.
|
|
433
|
+
let holderCmd = "";
|
|
434
|
+
try {
|
|
435
|
+
holderCmd = require("node:fs").readFileSync(require("node:path").join(lock, "cmd"), "utf8").trim();
|
|
436
|
+
}
|
|
437
|
+
catch { /* */ }
|
|
438
|
+
(0, fmt_1.out)(ctx, ` lock held by live process pid ${holder}${holderCmd ? `\n holder command: ${holderCmd}` : " (parallel CLI session — serve never takes the write lock)"}`);
|
|
439
|
+
(0, fmt_1.out)(ctx, ` reads still work; the lock serializes CLI writers and self-heals when pid ${holder} exits`);
|
|
440
|
+
(0, fmt_1.out)(ctx, ` force through (know what you are doing): YGL_TEST=1 · inspect/clear: ygl-trees db unlock`);
|
|
422
441
|
}
|
|
423
442
|
else {
|
|
424
443
|
(0, fmt_1.out)(ctx, ` orphaned lock (pid ${holder} is dead) — removing: ${lock}`);
|
|
@@ -441,9 +460,16 @@ async function main(argv) {
|
|
|
441
460
|
db?.close();
|
|
442
461
|
}
|
|
443
462
|
catch { /* best effort */ }
|
|
444
|
-
// P0-2 belt-and-suspenders: force-release the lock on any exit path
|
|
463
|
+
// P0-2 belt-and-suspenders: force-release the lock on any exit path —
|
|
464
|
+
// but ONLY one this process owns. Unconditional release nuked FOREIGN
|
|
465
|
+
// locks whenever a lock-less process (serve; db unlock since 0.79.1)
|
|
466
|
+
// exited next to a live holder.
|
|
445
467
|
try {
|
|
446
|
-
require("../../../packages/core/database/src/db")
|
|
468
|
+
const { DB } = require("../../../packages/core/database/src/db");
|
|
469
|
+
if (db?.ownsLock)
|
|
470
|
+
DB.releaseLockFor(file);
|
|
471
|
+
else if (DB.lockHolder(file) === String(process.pid))
|
|
472
|
+
DB.releaseLockFor(file);
|
|
447
473
|
}
|
|
448
474
|
catch { /* */ }
|
|
449
475
|
});
|
|
@@ -700,10 +726,11 @@ function generateLlmsManifest() {
|
|
|
700
726
|
["db export <file>", "full backup"],
|
|
701
727
|
["db sync pg <url>", "one-way mirror to PostgreSQL"],
|
|
702
728
|
["db migrate pg <url> [--fresh]", "full-fidelity graduation (with type preflight)"],
|
|
729
|
+
["db unlock [--force]", "clear stale .ygllock (pid-liveness checked; refuses live holders)"],
|
|
703
730
|
["db reset", "delete database"],
|
|
704
731
|
]],
|
|
705
|
-
["doctor", "Health check (
|
|
706
|
-
["doctor [--fix]", "diagnose (+ auto-fix: dirty index, stale lock)"],
|
|
732
|
+
["doctor", "Health check (10 items)", [
|
|
733
|
+
["doctor [--fix]", "diagnose (+ auto-fix: dirty index, dead stale lock, phantom writes)"],
|
|
707
734
|
]],
|
|
708
735
|
["config", "User settings", [
|
|
709
736
|
["config list / get / set / reset", "registry-backed settings"],
|