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
|
@@ -44,6 +44,14 @@ class TreeStore {
|
|
|
44
44
|
nodeGet(treeId, keyOrId) {
|
|
45
45
|
return this.db.get("SELECT * FROM nodes WHERE tree_id=? AND (key=? OR id=?)", [treeId, keyOrId, keyOrId]);
|
|
46
46
|
}
|
|
47
|
+
/** Which OTHER trees contain this key? (Report ③: a parallel session
|
|
48
|
+
* flipped current_tree; `node can p_dates` then said just "node not
|
|
49
|
+
* found" — the key existed the whole time, in another tree. This lookup
|
|
50
|
+
* lets the error name the tree instead of forcing a blind node list.) */
|
|
51
|
+
nodeInOtherTrees(keyOrId, excludeTreeId) {
|
|
52
|
+
return this.db.all(`SELECT t.name AS tree, n.key FROM nodes n JOIN trees t ON t.id=n.tree_id
|
|
53
|
+
WHERE n.tree_id<>? AND (n.key=? OR n.id=?) LIMIT 5`, [excludeTreeId, keyOrId, keyOrId]);
|
|
54
|
+
}
|
|
47
55
|
/** Runtime state for one node (default context). Separate from nodeGet on
|
|
48
56
|
* purpose: nodeGet feeds WRITE paths, and a context join there could return
|
|
49
57
|
* one row per context — silently wrong for link/unlink/rm. */
|
|
@@ -378,6 +386,12 @@ class TreeStore {
|
|
|
378
386
|
* + unlocked set + the caller's state bag. The eval API demands a context
|
|
379
387
|
* package — bare state fell into the gray band 6/8 in the material's
|
|
380
388
|
* routing test, so we ship everything the tree knows about this node.
|
|
389
|
+
*
|
|
390
|
+
* 0.80: the rel fabric joins the package — evidence/claim/kb summaries
|
|
391
|
+
* attached to the node (either direction) land in `attachments`, so a
|
|
392
|
+
* decided-by chain is visible to the eval model without manually
|
|
393
|
+
* re-carrying facts via --state (user finding: P 0.30 → 0.92 gap).
|
|
394
|
+
* Bounded: ≤12 rows, text clipped to 120 chars.
|
|
381
395
|
*/
|
|
382
396
|
evalContext(treeId, keyOrId, stateBag, context = "default") {
|
|
383
397
|
const n = this.nodeGet(treeId, keyOrId);
|
|
@@ -390,7 +404,7 @@ class TreeStore {
|
|
|
390
404
|
name: c.name, kind: c.kind, op: c.op, value: c.value, required: !!c.required, effect: c.effect,
|
|
391
405
|
}));
|
|
392
406
|
const unlocked = [...this.unlockedSet(treeId, context)].map((id) => idToKey.get(id) || id);
|
|
393
|
-
|
|
407
|
+
const pkg = {
|
|
394
408
|
node: { key: n.key, name: n.name, kind: n.kind, tier: n.tier, cost: n.cost },
|
|
395
409
|
parents,
|
|
396
410
|
ancestors,
|
|
@@ -398,6 +412,50 @@ class TreeStore {
|
|
|
398
412
|
unlocked,
|
|
399
413
|
state: stateBag,
|
|
400
414
|
};
|
|
415
|
+
const attachments = this.relAttachments(String(n.id));
|
|
416
|
+
if (attachments.length)
|
|
417
|
+
pkg.attachments = attachments;
|
|
418
|
+
return pkg;
|
|
419
|
+
}
|
|
420
|
+
/** 0.80: rel-fabric summaries for the eval context package (both directions). */
|
|
421
|
+
relAttachments(nodeId) {
|
|
422
|
+
const rows = this.db.all(`SELECT rel, src_type, src_id, dst_type, dst_id FROM relations
|
|
423
|
+
WHERE (src_type='node' AND src_id=?) OR (dst_type='node' AND dst_id=?)
|
|
424
|
+
ORDER BY rowid LIMIT 12`, [nodeId, nodeId]);
|
|
425
|
+
const clip = (v, n = 120) => String(v ?? "").slice(0, n);
|
|
426
|
+
return rows.map((r) => {
|
|
427
|
+
const srcIsMe = r.src_type === "node" && r.src_id === nodeId;
|
|
428
|
+
const type = String(srcIsMe ? r.dst_type : r.src_type);
|
|
429
|
+
const id = String(srcIsMe ? r.dst_id : r.src_id);
|
|
430
|
+
const base = { rel: String(r.rel), type, id };
|
|
431
|
+
const q = (sql) => this.db.get(sql, [id]);
|
|
432
|
+
if (type === "claim") {
|
|
433
|
+
const c = q("SELECT text, status, confidence FROM claims WHERE id=?");
|
|
434
|
+
if (c)
|
|
435
|
+
return { ...base, text: clip(c.text), status: c.status, confidence: c.confidence };
|
|
436
|
+
}
|
|
437
|
+
else if (type === "evidence") {
|
|
438
|
+
const e = q("SELECT quote FROM evidence WHERE id=?");
|
|
439
|
+
if (e)
|
|
440
|
+
return { ...base, quote: clip(e.quote) };
|
|
441
|
+
}
|
|
442
|
+
else if (type === "kb") {
|
|
443
|
+
const k = q("SELECT title FROM kb_notes WHERE id=?");
|
|
444
|
+
if (k)
|
|
445
|
+
return { ...base, title: clip(k.title, 80) };
|
|
446
|
+
}
|
|
447
|
+
else if (type === "source") {
|
|
448
|
+
const s = q("SELECT title FROM sources WHERE id=?");
|
|
449
|
+
if (s)
|
|
450
|
+
return { ...base, title: clip(s.title, 80) };
|
|
451
|
+
}
|
|
452
|
+
else if (type === "node") {
|
|
453
|
+
const nd = q("SELECT key, name FROM nodes WHERE id=?");
|
|
454
|
+
if (nd)
|
|
455
|
+
return { ...base, key: nd.key, name: clip(nd.name, 80) };
|
|
456
|
+
}
|
|
457
|
+
return base; // query/artifact/skill or dangling ref: id only
|
|
458
|
+
});
|
|
401
459
|
}
|
|
402
460
|
/** Every node whose required gates are currently satisfied. */
|
|
403
461
|
ready(treeId, context = "default", state = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ygl-trees",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.80.0",
|
|
4
4
|
"description": "猿光 · 科技树 — database-centric CLI for research → production → knowledge reuse, built for AI agents.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/apps/cli/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"typeorm": "^1.1.2",
|
|
28
28
|
"@deepseek-ai/cordis": "~4.0.5-alpha.2",
|
|
29
29
|
"@deepseek-ai/cordis-plugin-timer": "~1.1.7-alpha.2",
|
|
30
|
-
"@deepseek-ai/
|
|
31
|
-
"@deepseek-ai/
|
|
30
|
+
"@deepseek-ai/cosmokit": "~1.8.6-alpha.2",
|
|
31
|
+
"@deepseek-ai/schemastery": "~3.18.5-alpha.2"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^20.0.0",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
],
|
|
50
50
|
"exclude": [
|
|
51
51
|
"node_modules",
|
|
52
|
-
"dist"
|
|
52
|
+
"dist",
|
|
53
|
+
"tmp"
|
|
53
54
|
],
|
|
54
55
|
"env": {
|
|
55
56
|
"YGL_TEST": "1"
|
|
@@ -60,7 +60,12 @@ ygl-trees node can gate-node --eval --json # evaluated[] 带 type 字段 + p
|
|
|
60
60
|
## 4. 上下文包(模型看到什么)
|
|
61
61
|
|
|
62
62
|
节点元数据(key/name/kind/tier/cost)+ 直接父(node_edges)+ 祖先链(node_closure)+
|
|
63
|
-
该节点全部条件 + 已解锁集 + `--state`
|
|
63
|
+
该节点全部条件 + 已解锁集 + `--state` 袋 + **rel 挂接摘要(0.80)**。**state 必带上下文包**——裸 state 大概率落灰带。
|
|
64
|
+
|
|
65
|
+
**attachments(0.80 织物并入)**:节点挂接的 rel 关系(双向 ≤12 条)自动摘录入包——
|
|
66
|
+
claim(text+status+confidence)、evidence(quote 截 120 字)、kb/source(标题)、node(key+name)、
|
|
67
|
+
其余类型 id-only。裁决链 `decided-by` 挂好后 eval 模型直接可见,不必 `--state k=v` 手动携带事实
|
|
68
|
+
(用户实测:不挂链 P=0.30,挂链后 0.92)。
|
|
64
69
|
|
|
65
70
|
## 5. 凭证与端点(优先级:config > 环境变量/文件 > 默认网关)
|
|
66
71
|
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
触发词:ygl-trees 入门、初始化、quickstart、工作区、退出码、exit code、备份、export、
|
|
10
10
|
PostgreSQL、sync、migrate、镜像、job、tick、定时、doctor、健康检查、任务、task、
|
|
11
11
|
关联、rel、插件、plugin、WebUI、webui、仪表盘、dashboard、bench、基准、bundle。
|
|
12
|
-
version: 0.
|
|
12
|
+
version: 0.79.0
|
|
13
13
|
tags: ygl-trees,quickstart,backup,postgres,schedule,doctor,plugin,webui,bench
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -56,25 +56,35 @@ ygl-trees llms --json # 结构化 JSON
|
|
|
56
56
|
## 2b. 运维命令速查
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
ygl-trees doctor #
|
|
60
|
-
ygl-trees doctor --fix #
|
|
59
|
+
ygl-trees doctor # 10 项健康检查(含锁 pid 存活、幻影写入对账)
|
|
60
|
+
ygl-trees doctor --fix # 一键安全修复(脏索引 + 死 pid 陈旧锁;活 holder 不动)
|
|
61
|
+
ygl-trees db unlock # 清残留 .ygllock(死 pid 直清;活 holder 回显其命令行并拒绝,--force 强清)
|
|
61
62
|
ygl-trees kb rm <id> # 删除笔记(与 skill rm 对称)
|
|
62
63
|
ygl-trees webui serve --host 0.0.0.0 --port 8642 # LAN/WSL 可访问
|
|
64
|
+
ygl-trees webui serve --help # 只打印用法不启服务(0.79.1 短路)
|
|
63
65
|
```
|
|
64
66
|
|
|
65
67
|
PG 迁移预检:`db migrate pg` 前自动逐表扫描 INTEGER 列类型——非整数值会**点名 table.column rowid=N** 而非迁移时才爆。
|
|
66
68
|
|
|
67
|
-
##
|
|
69
|
+
## 2b2. 多会话安全(0.79)
|
|
68
70
|
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
+
- `tree use` / `project use` 落 `tree.use` / `project.use` 事件(`YGL_SESSION` 会话标识)
|
|
72
|
+
- `agent brief` 的 `selection_changed`:最近 10 分钟选择变更;跨会话变更置顶提示带 `-t`/`-p`
|
|
73
|
+
- `kb add` 回执自检(`verified:true`)+ 工作区回显(防写错 home 的"丢笔记"事故)
|
|
74
|
+
- `research claim link <cid> <sid> --by-source`:来源下全部证据一次挂齐;误传来源 id 会列出其证据 id
|
|
75
|
+
|
|
76
|
+
## 2c. DB 锁行为(0.68 → 0.79.1)
|
|
77
|
+
|
|
78
|
+
- CLI 短命令:进程级锁(保护写窗口,退出自动释放);锁文件记录**持有者命令行**,撞锁/`db unlock`/`doctor` 都回显真实持有者身份
|
|
79
|
+
- webui serve:无锁(WAL 并发安全,与 CLI 共存;从不取写锁)
|
|
71
80
|
- 死锁自愈:下一进程探测持有者 PID,死则即时清(无需手动 rmdir)
|
|
81
|
+
- 无锁进程(serve / `db unlock` 自身)退出绝不误清并行会话的活锁(0.79.1 所有权守卫)
|
|
72
82
|
- YGL_TEST=1:全旁路(测试并行)
|
|
73
83
|
|
|
74
84
|
## 3. 健康检查与任务
|
|
75
85
|
|
|
76
86
|
```bash
|
|
77
|
-
ygl-trees doctor #
|
|
87
|
+
ygl-trees doctor # 10 项健康检查(schema/索引/FTS/重复/孤儿/config/锁存活/eval信封/插件/幻影写入)
|
|
78
88
|
ygl-trees task add "<标题>" # 建任务(todo 起步)
|
|
79
89
|
ygl-trees task list # 按状态分组
|
|
80
90
|
ygl-trees task done <id> # 勾销(全程留痕)
|
|
@@ -120,6 +130,7 @@ ygl-trees db export <file.sql> # 全部数据表 + 行数摘要
|
|
|
120
130
|
ygl-trees db sync pg <url> # 可刷新 PK-only 镜像
|
|
121
131
|
ygl-trees db migrate pg <url> [--fresh] # 一次性完整保真迁移
|
|
122
132
|
ygl-trees job add <title> -- "<cmd>" --every 60 # cron 每分钟跑 job tick
|
|
133
|
+
ygl-trees job add "闸门探针" -- "node probe.mjs" --every 30 # 树节奏化监控:任意命令皆可(0.79.1 实证)
|
|
123
134
|
```
|
|
124
135
|
|
|
125
136
|
禁止双后端同写:ygl-trees 永远只写 SQLite,PG 是单向出口。
|
|
@@ -17,6 +17,11 @@ tags: ygl-trees,methodology,relations,fabric
|
|
|
17
17
|
**两条平行流水线**:研究管线(source→evidence→claim→report)和科技树各自发育、零缝合——
|
|
18
18
|
检阅者看不出"这个节点依据什么证据、由什么断言决定、跟踪着什么任务"。`relations` 表就是缝合线。
|
|
19
19
|
|
|
20
|
+
**缝合直接喂决策模型(0.80)**:节点挂接的 rel 关系(双向 ≤12 条)自动进 eval 上下文包
|
|
21
|
+
`attachments`——claim 带 text+status+confidence、evidence 带 quote 摘要。裁决 `decided-by`
|
|
22
|
+
挂链后 `node can --eval` 不必 `--state k=v` 手动携带事实(实测 P 0.30 → 0.92)。
|
|
23
|
+
挂链纪律由此获得语义门槛层面的回报。
|
|
24
|
+
|
|
20
25
|
## 2. rel 词汇表(方向:src --rel→ dst)
|
|
21
26
|
|
|
22
27
|
| rel | 语义 | 典型挂法 |
|
|
@@ -26,9 +26,14 @@ ygl-trees research source add --title t --url https://... \
|
|
|
26
26
|
--abstract "..." --relevance 4 --query "邻接表 vs 闭包表" # 手工入库+关联检索式
|
|
27
27
|
ygl-trees research source fetch https://example.com/page # 自动抓取(title/meta/正文;
|
|
28
28
|
# 非 html 拒收零副作用;薄内容打 needs_review)
|
|
29
|
+
ygl-trees research source add --adjudication "会话内裁决:三条件已逐条核对" \
|
|
30
|
+
--tags adjudication # 会话内裁决原生载体(0.80):
|
|
31
|
+
# url 自动 session://adjudication/<时刻>,
|
|
32
|
+
# 摘要兼作标题——不再需要临时文件绕行
|
|
29
33
|
```
|
|
30
34
|
|
|
31
35
|
来源按 `(project, url_hash)` 去重;`--query` 顺带建立召回关联(query list 显示召回数)。
|
|
36
|
+
`--url` 收 http(s):// · file:// · session://(0.80)。
|
|
32
37
|
|
|
33
38
|
## 2. 摘录与断言
|
|
34
39
|
|
|
@@ -57,5 +62,7 @@ ygl-trees produce export <reportId> report.md
|
|
|
57
62
|
|
|
58
63
|
- 先 `agent brief --json` 看 next_actions(它会告诉你缺来源/缺证据/缺断言)
|
|
59
64
|
- 每条断言至少一条证据再进报告;contested 的要么补证据要么 resolve
|
|
65
|
+
- 预测断言(`[预测·N天]`)定期 `research predict audit` 回测:本地判据自动测;`--state <file|url>`
|
|
66
|
+
桥接外部计数(裸键名后缀匹配 `counts.y_imported`);已 resolve 的默认隐藏(`--all` 查看终态表)
|
|
60
67
|
- `--json` 输出可直接 parse 拿 id;列表命令字段:source(id,title,url,relevance,…)、
|
|
61
68
|
claim(id,text,status,confidence,sup,ref)、evidence(id,source,locator,quote,used_by)
|
|
@@ -38,6 +38,7 @@ ygl-trees node index && ygl-trees node validate
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
ygl-trees node can steel --state "lab_level=3,has_eng=1" # 三类失败分开列+成本系数
|
|
41
|
+
ygl-trees node can a b c --state-file bags.json # 批量:一进程测 N 节点(探针 1s×N → 1s)
|
|
41
42
|
ygl-trees node ready # 当前可解锁集合
|
|
42
43
|
ygl-trees node path steel # 解锁顺序+累计成本(目标恒最后)
|
|
43
44
|
ygl-trees node ancestors bronze # 闭包索引直查,depth=1 是直接父
|
|
@@ -46,6 +47,7 @@ ygl-trees node unlock mining && ygl-trees node lock mining
|
|
|
46
47
|
|
|
47
48
|
- 写入时环守卫:门控边(prereq/unlock)成环当场拒绝
|
|
48
49
|
- `node can` 输出:missing_required(阻塞)/ blocked_by(被排斥)/ missing_optional(不阻塞)
|
|
50
|
+
- `--state-file` 两种形状:扁平 `{"y_imported":40}` 全节点共享;按节点 `{"a":{"y_imported":40}}` 各取各袋;多键 `--json` 返回数组(0.79.1)
|
|
49
51
|
|
|
50
52
|
## 3. 迁移与保真
|
|
51
53
|
|