#!/usr/bin/env node // Phase 2A: Build the knowledge graph from the live UMP store and persist // it to GRAPH_FILE (default /root/ump-recall/state/graph.json). // // Usage: // node scripts/build_graph.js # default UMP file // UMP_FILE=/path/to/x.json node scripts/build_graph.js // GRAPH_FILE=/tmp/x.json node scripts/build_graph.js // // Output: prints stats, top-10 entities by frequency, and top-10 edges by // weight. Exits 0 on success. Reads the UMP file as JSON once; suitable // for cron / shell triggers. import { promises as fs } from "node:fs"; import { Graph } from "../src/graph.js"; const UMP_FILE = process.env.UMP_FILE || "/root/.openclaw/agents/main/workspace/state/ump-local/memory.ump.json"; async function loadRecords() { const t0 = Date.now(); const raw = await fs.readFile(UMP_FILE, "utf8"); const records = JSON.parse(raw); if (!Array.isArray(records)) { throw new Error(`UMP file root must be an array, got ${typeof records}`); } const dt = Date.now() - t0; return { records, parseMs: dt }; } async function main() { const startedAt = Date.now(); const { records, parseMs } = await loadRecords(); console.log( `loaded ${records.length} records from ${UMP_FILE} in ${parseMs} ms` ); const g = new Graph(); const buildT0 = Date.now(); g.buildFromRecords(records); const buildMs = Date.now() - buildT0; const saveRes = await g.save(); console.log( `built graph in ${buildMs} ms; saved -> ${saveRes.file} ` + `(nodes=${saveRes.nodes}, edges=${saveRes.edges}, urns=${saveRes.urns})` ); const total = Date.now() - startedAt; console.log(`\ntotal: ${total} ms\n`); // Reporting. console.log("---- Top 10 entities by frequency ----"); for (const e of g.topEntities(10)) { console.log( ` ${String(e.frequency).padStart(4)}x ${e.kind.padEnd(14)} ${e.entity}` + ` (in ${e.urns} urns)` ); } console.log("\n---- Top 10 edges by weight ----"); for (const e of g.topEdges(10)) { console.log( ` ${String(e.weight).padStart(3)}x ${e.src} ${arrow(e.type)} ${e.tgt}` + ` (${e.type}, in ${e.urns} urns)` ); } console.log("\n---- Stats ----"); console.log(JSON.stringify(g.stats(), null, 2)); } function arrow(type) { if (type === "relates-to") return "─▶"; // matches the relation convention return "──"; } main().catch((e) => { console.error("FATAL:", e?.stack || e?.message || e); process.exit(1); });