graph-seed.js
5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env node
/**
* graph-seed.js — seeds data/graph.sqlite from the on-disk agent/company sources.
*
* 依次跑 reconcileDanglingRows()(P3B W1,28 三轮起还含孤儿 org 节点清理 + 存量本体毕业对账)
* → seedAgents()(28 批次 1 起由 T1+T2 合并而来)
* → seedCompanyAgents()(T3)→ verifyCounts()(T4,独立重新扫描目录/文件做行数交叉核对)。
* 打印按 origin 分组的汇总报告;核对不一致时以非零状态码退出。
*
* 前两步(reconcile + seedAgents)服务启动时会自动跑一遍
* (graph-seed-service.runStartupSeedSafely,见 server/index.js);本脚本比启动多跑
* seedCompanyAgents()——那一步会从 company.json 反推 org_graph_nodes,属于手动补种,
* 不放进启动流程(理由见 runStartupSeed 的注释)。
*
* 用法:
* node scripts/graph-seed.js
*/
const {
reconcileDanglingRows, seedAgents, seedCompanyAgents, verifyCounts,
} = require('../server/services/graph-seed-service');
function main() {
console.log('[graph-seed] 开始种子导入\n');
const reconciled = reconcileDanglingRows();
console.log(`[reconcile] 清理悬空 created 行: ${reconciled.agentsRemoved.length} 条${reconciled.agentsRemoved.length ? ` (${reconciled.agentsRemoved.join(', ')})` : ''}`);
console.log(` 已删公司的名册行: ${reconciled.companyAgentsRemoved} 行`);
console.log(` 已删公司的 org 节点/边: ${reconciled.orgNodesRemoved}/${reconciled.orgEdgesRemoved} 行${reconciled.ghostCompanyIds.length ? `,涉及公司 ${reconciled.ghostCompanyIds.join(', ')}` : ''}`);
console.log(` 磁盘上已无本体的 builtin 行: ${reconciled.builtinsRemoved.length} 条${reconciled.builtinsRemoved.length ? ` (${reconciled.builtinsRemoved.join(', ')})` : ''}`);
// 这两项是 28 三轮修复加的:孤儿节点会变成一个「谁也点不亮却真的会被执行」的 org 节点,
// 卡住的 training 行会让现役本体对**新公司**永远雇不到 —— 都得能在报告里一眼看见。
console.log(` 图基础设施本体的孤儿 org 节点: ${reconciled.orphanNonOrgNodesRemoved.length} 行${reconciled.orphanNonOrgNodesRemoved.length ? ` (${reconciled.orphanNonOrgNodesRemoved.join(', ')})` : ''}`);
console.log(` 🎓 定义已齐全、就地转正的存量本体: ${reconciled.graduated.length} 个${reconciled.graduated.length ? ` (${reconciled.graduated.join(', ')})` : ''}`);
if (reconciled.retained.length > 0) {
console.log(` ⚠️ 被外键引用、暂时保留 (${reconciled.retained.length}): ${reconciled.retained.map(r => `${r.id} — ${r.reason}`).join('; ')}`);
}
const agents = seedAgents();
console.log(`[builtin] 扫描 system/agents/* 目录: ${agents.scanned} 个,是本体(非 _ 开头且含 agent.md)且已导入: ${agents.seeded} 个`);
console.log(` ids: ${agents.ids.join(', ')}`);
if (agents.reclaimed.length > 0) {
console.log(` ♻️ 从悬空 created 占位接管回 builtin 的 ids (${agents.reclaimed.length}): ${agents.reclaimed.join(', ')}`);
}
console.log(` registry 匹配到 benchmark_score 的 ids (${agents.registryMatched.length}): ${agents.registryMatched.join(', ')}`);
if (agents.skipped.length > 0) {
console.log(` ⚠️ id 仍被活着的公司私有 agent 占着,已跳过写入 (${agents.skipped.length}): ${agents.skipped.map(s => `${s.id}(已属于 ${s.existingOrigin})`).join(', ')}`);
}
const companyAgents = seedCompanyAgents();
console.log(`\n[created] 扫描到 ${companyAgents.companies.length} 家有 company.json 的公司: ${companyAgents.companies.join(', ')}`);
console.log(` org_graph_nodes 本次新建: ${companyAgents.nodesCreated} 行,已存在跳过: ${companyAgents.nodesExisting} 行`);
console.log(` 引用已有 system_agents 行 (${companyAgents.reusedSystemAgents.length}): ${companyAgents.reusedSystemAgents.join(', ')}`);
console.log(` 新建 scope='company' 行 (${companyAgents.newSystemAgents.length}): ${companyAgents.newSystemAgents.join(', ')}`);
console.log('\n[verify] 行数对账(独立重新扫描目录/文件,不复用上面的计数器)');
const v = verifyCounts();
console.log(` system_agents[builtin]: 期望 ${v.expected.builtin},实际 ${v.actual.builtin}`);
console.log(` system_agents[created]: 期望 ${v.expected.created},实际 ${v.actual.created}`);
const companyIds = Object.keys({ ...v.expected.nodesPerCompany, ...v.actual.nodesPerCompany });
for (const companyId of companyIds) {
const expected = v.expected.nodesPerCompany[companyId] || 0;
const actual = v.actual.nodesPerCompany[companyId] || 0;
console.log(` org_graph_nodes[${companyId}]: 期望 ${expected},实际 ${actual}`);
}
if (!v.ok) {
console.error('\n❌ 行数对账失败,发现以下不一致:');
for (const m of v.mismatches) {
console.error(` - ${m.check}: 期望 ${m.expected},实际 ${m.actual}`);
}
process.exitCode = 1;
return;
}
console.log('\n✅ 种子导入完成,行数对账通过');
}
main();