@vibgrate/cli 2026.704.3 → 2026.708.1
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/DOCS.md +90 -4
- package/README.md +1 -1
- package/dist/baseline-RRO4NNNF.js +6 -0
- package/dist/{baseline-64EUPWUH.js.map → baseline-RRO4NNNF.js.map} +1 -1
- package/dist/{chunk-JL7FIC6W.js → chunk-2J7DPIAL.js} +380 -214
- package/dist/chunk-2J7DPIAL.js.map +1 -0
- package/dist/{chunk-WHQRV66O.js → chunk-FMCI3MXH.js} +3 -3
- package/dist/{chunk-WHQRV66O.js.map → chunk-FMCI3MXH.js.map} +1 -1
- package/dist/{chunk-YN5OGRWU.js → chunk-SRWMZBLG.js} +54 -21
- package/dist/chunk-SRWMZBLG.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +1576 -324
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +20 -4
- package/dist/index.js +2 -2
- package/dist/parse-worker.d.ts +1 -1
- package/dist/{types-C6ZyQpa9.d.ts → types-CXnp1uGj.d.ts} +33 -1
- package/package.json +3 -3
- package/dist/baseline-64EUPWUH.js +0 -6
- package/dist/chunk-JL7FIC6W.js.map +0 -1
- package/dist/chunk-YN5OGRWU.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hashString, langById, shortId, canonicalize, grammarSetVersion, hashBytes, langForExtension, setGrammarsOverride, parseSource } from './chunk-X5YT263H.js';
|
|
2
|
-
import { writeTextFile, pathExists, readJsonFile, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem, VERSION } from './chunk-
|
|
2
|
+
import { writeTextFile, pathExists, readJsonFile, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem, VERSION } from './chunk-SRWMZBLG.js';
|
|
3
3
|
import * as fs18 from 'fs';
|
|
4
4
|
import { execFileSync } from 'child_process';
|
|
5
5
|
import * as path18 from 'path';
|
|
@@ -1624,6 +1624,7 @@ function resolve4(parses, resolver) {
|
|
|
1624
1624
|
}
|
|
1625
1625
|
}
|
|
1626
1626
|
const edges = new EdgeSet();
|
|
1627
|
+
const unresolved2 = /* @__PURE__ */ new Map();
|
|
1627
1628
|
const stats = {
|
|
1628
1629
|
callsResolved: 0,
|
|
1629
1630
|
callsUnresolved: 0,
|
|
@@ -1672,6 +1673,7 @@ function resolve4(parses, resolver) {
|
|
|
1672
1673
|
stats.callsResolved++;
|
|
1673
1674
|
} else {
|
|
1674
1675
|
stats.callsUnresolved++;
|
|
1676
|
+
bumpUnresolved(unresolved2, srcId, call.callee, "call", p.rel);
|
|
1675
1677
|
}
|
|
1676
1678
|
}
|
|
1677
1679
|
}
|
|
@@ -1683,6 +1685,7 @@ function resolve4(parses, resolver) {
|
|
|
1683
1685
|
if (!srcId) continue;
|
|
1684
1686
|
const target = resolveType(h.superName, p.rel, p.lang, imported, defsByName);
|
|
1685
1687
|
if (target) edges.add(h.kind, srcId, target.id, "heuristic", 0.85);
|
|
1688
|
+
else bumpUnresolved(unresolved2, srcId, h.superName, h.kind, p.rel);
|
|
1686
1689
|
}
|
|
1687
1690
|
}
|
|
1688
1691
|
const nodes = [...baseNodes.values()].map((n) => ({
|
|
@@ -1693,7 +1696,16 @@ function resolve4(parses, resolver) {
|
|
|
1693
1696
|
isHub: false,
|
|
1694
1697
|
tested: null
|
|
1695
1698
|
}));
|
|
1696
|
-
|
|
1699
|
+
const unresolvedList = [...unresolved2.values()].sort(
|
|
1700
|
+
(a, b) => a.from.localeCompare(b.from) || a.kind.localeCompare(b.kind) || a.name.localeCompare(b.name)
|
|
1701
|
+
);
|
|
1702
|
+
return { nodes, edges: edges.toArray(), unresolved: unresolvedList, stats };
|
|
1703
|
+
}
|
|
1704
|
+
function bumpUnresolved(map, from, name, kind, fromRel) {
|
|
1705
|
+
const key = `${from}\0${kind}\0${name}`;
|
|
1706
|
+
const existing = map.get(key);
|
|
1707
|
+
if (existing) existing.count++;
|
|
1708
|
+
else map.set(key, { from, name, kind, count: 1, fromRel });
|
|
1697
1709
|
}
|
|
1698
1710
|
function addNode(map, n) {
|
|
1699
1711
|
if (!map.has(n.id)) map.set(n.id, n);
|
|
@@ -2036,6 +2048,30 @@ function loadCache(root, opts) {
|
|
|
2036
2048
|
};
|
|
2037
2049
|
}
|
|
2038
2050
|
|
|
2051
|
+
// src/engine/epistemic.ts
|
|
2052
|
+
var SEMANTIC_RESOLVERS = /* @__PURE__ */ new Set(["scip", "stackgraph", "tsc"]);
|
|
2053
|
+
function classifyEpistemic(edge, dstKind) {
|
|
2054
|
+
if (SEMANTIC_RESOLVERS.has(edge.resolution)) return "observed";
|
|
2055
|
+
switch (edge.kind) {
|
|
2056
|
+
case "contains":
|
|
2057
|
+
return "observed";
|
|
2058
|
+
case "import":
|
|
2059
|
+
return dstKind === "external" || dstKind === void 0 ? "declared" : "observed";
|
|
2060
|
+
case "test":
|
|
2061
|
+
case "coverage":
|
|
2062
|
+
return "declared";
|
|
2063
|
+
default:
|
|
2064
|
+
return "name-matched";
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
function epistemicBreakdown(edges) {
|
|
2068
|
+
const out = { observed: 0, "name-matched": 0, declared: 0 };
|
|
2069
|
+
for (const e of edges) {
|
|
2070
|
+
if (e.epistemic) out[e.epistemic]++;
|
|
2071
|
+
}
|
|
2072
|
+
return out;
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2039
2075
|
// src/engine/build.ts
|
|
2040
2076
|
async function buildGraph(options) {
|
|
2041
2077
|
const start = nowMs();
|
|
@@ -2117,6 +2153,7 @@ async function buildGraph(options) {
|
|
|
2117
2153
|
const nodeFileById = new Map(resolved.nodes.map((n) => [n.id, n.file]));
|
|
2118
2154
|
let edges = resolved.edges;
|
|
2119
2155
|
const resolvers = [...resolved.stats.resolvers];
|
|
2156
|
+
const preciseCoveredFiles = /* @__PURE__ */ new Set();
|
|
2120
2157
|
let tscStats;
|
|
2121
2158
|
let tsFiles = options.noTsc ? [] : files.filter((f) => (f.lang.id === "ts" || f.lang.id === "tsx" || f.lang.id === "js") && hashes.has(f.rel)).map((f) => ({ rel: f.rel, abs: f.abs }));
|
|
2122
2159
|
if (limits.tscMaxFiles > 0 && tsFiles.length > limits.tscMaxFiles) {
|
|
@@ -2129,6 +2166,7 @@ async function buildGraph(options) {
|
|
|
2129
2166
|
const res = tsResolveEdges(root, tsFiles, resolved.nodes);
|
|
2130
2167
|
if (res.stats.files > 0) {
|
|
2131
2168
|
edges = mergePreciseEdges(edges, res.edges, res.coveredFiles, nodeFileById);
|
|
2169
|
+
for (const f of res.coveredFiles) preciseCoveredFiles.add(f);
|
|
2132
2170
|
if (!resolvers.includes("tsc")) resolvers.unshift("tsc");
|
|
2133
2171
|
tscStats = res.stats;
|
|
2134
2172
|
}
|
|
@@ -2139,6 +2177,7 @@ async function buildGraph(options) {
|
|
|
2139
2177
|
if (scip) {
|
|
2140
2178
|
const res = scipEdges(scip.index, resolved.nodes, toRepoRel);
|
|
2141
2179
|
edges = mergePreciseEdges(edges, res.edges, res.coveredFiles, nodeFileById);
|
|
2180
|
+
for (const f of res.coveredFiles) preciseCoveredFiles.add(f);
|
|
2142
2181
|
if (!resolvers.includes("scip")) resolvers.unshift("scip");
|
|
2143
2182
|
scipStats = { ...res.stats, tool: scip.tool };
|
|
2144
2183
|
}
|
|
@@ -2151,6 +2190,11 @@ async function buildGraph(options) {
|
|
|
2151
2190
|
const languages = [...new Set(parses.map((p) => p.lang))].sort();
|
|
2152
2191
|
const edgeKinds = [...new Set(analysis.edges.map((e) => e.kind))].sort();
|
|
2153
2192
|
const corpusHash = computeCorpusHash(parses, hashes);
|
|
2193
|
+
const nodeKindById = new Map(analysis.nodes.map((n) => [n.id, n.kind]));
|
|
2194
|
+
for (const e of analysis.edges) {
|
|
2195
|
+
e.epistemic = classifyEpistemic(e, nodeKindById.get(e.dst));
|
|
2196
|
+
}
|
|
2197
|
+
const toolchain = computeToolchain(grammars, resolvers);
|
|
2154
2198
|
const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2155
2199
|
const testsCount = linked.testFiles.length;
|
|
2156
2200
|
const untestedCount = analysis.nodes.filter(
|
|
@@ -2165,7 +2209,8 @@ async function buildGraph(options) {
|
|
|
2165
2209
|
grammars: Object.fromEntries(languages.map((l) => [l, grammars])),
|
|
2166
2210
|
resolver: resolvers,
|
|
2167
2211
|
deep: options.deep ?? false,
|
|
2168
|
-
corpusHash
|
|
2212
|
+
corpusHash,
|
|
2213
|
+
toolchain
|
|
2169
2214
|
},
|
|
2170
2215
|
meta: {
|
|
2171
2216
|
root: path18.basename(root) === "" ? "." : ".",
|
|
@@ -2184,6 +2229,9 @@ async function buildGraph(options) {
|
|
|
2184
2229
|
edges: analysis.edges,
|
|
2185
2230
|
areas: analysis.areas
|
|
2186
2231
|
};
|
|
2232
|
+
const survivingIds = new Set(analysis.nodes.map((n) => n.id));
|
|
2233
|
+
const unknowns = resolved.unresolved.filter((u) => !preciseCoveredFiles.has(u.fromRel) && survivingIds.has(u.from)).map((u) => ({ from: u.from, name: u.name, kind: u.kind, count: u.count }));
|
|
2234
|
+
if (unknowns.length) graph.unknowns = unknowns;
|
|
2187
2235
|
if (options.deep) {
|
|
2188
2236
|
const facts = buildFacts(parses, analysis.nodes, analysis.edges);
|
|
2189
2237
|
if (facts.length) graph.facts = facts;
|
|
@@ -2242,6 +2290,23 @@ function mergePreciseEdges(base, precise, coveredFiles, nodeFileById) {
|
|
|
2242
2290
|
(a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
|
|
2243
2291
|
);
|
|
2244
2292
|
}
|
|
2293
|
+
function computeToolchain(grammars, resolvers) {
|
|
2294
|
+
const sortedResolvers = [...new Set(resolvers)].sort();
|
|
2295
|
+
return {
|
|
2296
|
+
schema: SCHEMA_VERSION,
|
|
2297
|
+
tool: VERSION,
|
|
2298
|
+
grammars,
|
|
2299
|
+
resolvers: sortedResolvers,
|
|
2300
|
+
fingerprint: shortId(
|
|
2301
|
+
canonicalize({
|
|
2302
|
+
schema: SCHEMA_VERSION,
|
|
2303
|
+
tool: VERSION,
|
|
2304
|
+
grammars,
|
|
2305
|
+
resolvers: sortedResolvers
|
|
2306
|
+
})
|
|
2307
|
+
)
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
2245
2310
|
function computeCorpusHash(parses, hashes) {
|
|
2246
2311
|
const list = parses.map((p) => [p.rel, hashes.get(p.rel) ?? p.hash]).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
2247
2312
|
return hashString(canonicalize(list));
|
|
@@ -2249,6 +2314,224 @@ function computeCorpusHash(parses, hashes) {
|
|
|
2249
2314
|
function nowMs() {
|
|
2250
2315
|
return Number(process.hrtime.bigint() / 1000n) / 1e3;
|
|
2251
2316
|
}
|
|
2317
|
+
|
|
2318
|
+
// src/engine/report.ts
|
|
2319
|
+
function renderReport(graph) {
|
|
2320
|
+
const { meta, provenance, nodes, edges } = graph;
|
|
2321
|
+
const lines = [];
|
|
2322
|
+
lines.push("# Code Graph Report");
|
|
2323
|
+
lines.push("");
|
|
2324
|
+
lines.push(`Generated by \`vg\` ${provenance.version} \xB7 schema \`${graph.schemaVersion}\``);
|
|
2325
|
+
lines.push("");
|
|
2326
|
+
lines.push("## Summary");
|
|
2327
|
+
lines.push("");
|
|
2328
|
+
lines.push(`- **Nodes:** ${meta.counts.nodes.toLocaleString("en-US")}`);
|
|
2329
|
+
lines.push(`- **Edges:** ${meta.counts.edges.toLocaleString("en-US")}`);
|
|
2330
|
+
lines.push(`- **Areas:** ${meta.counts.areas.toLocaleString("en-US")}`);
|
|
2331
|
+
lines.push(`- **Languages:** ${meta.languages.join(", ") || "\u2014"}`);
|
|
2332
|
+
lines.push(`- **Clustering:** ${meta.cluster}`);
|
|
2333
|
+
lines.push(`- **Resolvers:** ${provenance.resolver.join(", ")}`);
|
|
2334
|
+
lines.push(`- **Edge kinds:** ${meta.edgeKinds.join(", ") || "\u2014"}`);
|
|
2335
|
+
lines.push("");
|
|
2336
|
+
const fileNodes = nodes.filter((n) => n.kind === "file");
|
|
2337
|
+
const defsByFile = /* @__PURE__ */ new Map();
|
|
2338
|
+
for (const n of nodes) {
|
|
2339
|
+
if (n.kind === "file" || n.kind === "external") continue;
|
|
2340
|
+
defsByFile.set(n.file, (defsByFile.get(n.file) ?? 0) + 1);
|
|
2341
|
+
}
|
|
2342
|
+
const topFiles = [...defsByFile.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, 15);
|
|
2343
|
+
if (topFiles.length) {
|
|
2344
|
+
lines.push("## Largest files (by definitions)");
|
|
2345
|
+
lines.push("");
|
|
2346
|
+
lines.push("| File | Definitions |");
|
|
2347
|
+
lines.push("| --- | ---: |");
|
|
2348
|
+
for (const [file, count] of topFiles) lines.push(`| \`${file}\` | ${count} |`);
|
|
2349
|
+
lines.push("");
|
|
2350
|
+
}
|
|
2351
|
+
const topNodes = nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName)).slice(0, 15);
|
|
2352
|
+
if (topNodes.length) {
|
|
2353
|
+
lines.push("## Most-connected definitions");
|
|
2354
|
+
lines.push("");
|
|
2355
|
+
lines.push("| Symbol | Kind | File | Importance |");
|
|
2356
|
+
lines.push("| --- | --- | --- | ---: |");
|
|
2357
|
+
for (const n of topNodes) {
|
|
2358
|
+
lines.push(
|
|
2359
|
+
`| \`${n.qualifiedName}\` | ${n.kind} | \`${n.file}\`:${n.span.start} | ${n.importance.toFixed(3)} |`
|
|
2360
|
+
);
|
|
2361
|
+
}
|
|
2362
|
+
lines.push("");
|
|
2363
|
+
}
|
|
2364
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
2365
|
+
for (const e of edges) byKind.set(e.kind, (byKind.get(e.kind) ?? 0) + 1);
|
|
2366
|
+
if (byKind.size) {
|
|
2367
|
+
lines.push("## Edges by kind");
|
|
2368
|
+
lines.push("");
|
|
2369
|
+
lines.push("| Kind | Count |");
|
|
2370
|
+
lines.push("| --- | ---: |");
|
|
2371
|
+
for (const [kind, count] of [...byKind.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
2372
|
+
lines.push(`| ${kind} | ${count} |`);
|
|
2373
|
+
}
|
|
2374
|
+
lines.push("");
|
|
2375
|
+
}
|
|
2376
|
+
lines.push("---");
|
|
2377
|
+
lines.push("");
|
|
2378
|
+
lines.push(`_Files: ${fileNodes.length} \xB7 Corpus: \`${provenance.corpusHash.slice(0, 16)}\u2026\`_`);
|
|
2379
|
+
lines.push("");
|
|
2380
|
+
return lines.join("\n");
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
// src/engine/html.ts
|
|
2384
|
+
function renderHtml(graph) {
|
|
2385
|
+
const top = graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName)).slice(0, 50);
|
|
2386
|
+
const rows = top.map(
|
|
2387
|
+
(n) => `<tr><td><code>${esc(n.qualifiedName)}</code></td><td>${esc(n.kind)}</td><td><code>${esc(n.file)}</code>:${n.span.start}</td><td>${n.importance.toFixed(3)}</td></tr>`
|
|
2388
|
+
).join("\n");
|
|
2389
|
+
const embedded = stableStringify(graph, 0);
|
|
2390
|
+
return `<!doctype html>
|
|
2391
|
+
<html lang="en">
|
|
2392
|
+
<head>
|
|
2393
|
+
<meta charset="utf-8">
|
|
2394
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
2395
|
+
<title>vg \xB7 code graph</title>
|
|
2396
|
+
<style>
|
|
2397
|
+
:root { color-scheme: light dark; }
|
|
2398
|
+
body { font: 14px/1.5 system-ui, sans-serif; margin: 2rem auto; max-width: 60rem; padding: 0 1rem; }
|
|
2399
|
+
h1 { font-size: 1.4rem; } h2 { font-size: 1.1rem; margin-top: 2rem; }
|
|
2400
|
+
table { border-collapse: collapse; width: 100%; }
|
|
2401
|
+
th, td { text-align: left; padding: 4px 8px; border-bottom: 1px solid #8884; }
|
|
2402
|
+
td:last-child, th:last-child { text-align: right; }
|
|
2403
|
+
.meta { color: #888; } code { font-size: 0.9em; }
|
|
2404
|
+
</style>
|
|
2405
|
+
</head>
|
|
2406
|
+
<body>
|
|
2407
|
+
<h1>vg \xB7 code graph</h1>
|
|
2408
|
+
<p class="meta">${graph.meta.counts.nodes} nodes \xB7 ${graph.meta.counts.edges} edges \xB7
|
|
2409
|
+
${graph.meta.counts.areas} areas \xB7 ${esc(graph.meta.languages.join(", ") || "\u2014")} \xB7
|
|
2410
|
+
clustering: ${esc(graph.meta.cluster)} \xB7 vg ${esc(graph.provenance.version)}</p>
|
|
2411
|
+
<h2>Most-connected definitions</h2>
|
|
2412
|
+
<table>
|
|
2413
|
+
<thead><tr><th>Symbol</th><th>Kind</th><th>Location</th><th>Importance</th></tr></thead>
|
|
2414
|
+
<tbody>
|
|
2415
|
+
${rows}
|
|
2416
|
+
</tbody>
|
|
2417
|
+
</table>
|
|
2418
|
+
<p class="meta">Interactive WebGL view arrives in Phase 1. The full graph is embedded below for tooling.</p>
|
|
2419
|
+
<script type="application/json" id="vg-graph">
|
|
2420
|
+
${embedded}
|
|
2421
|
+
</script>
|
|
2422
|
+
</body>
|
|
2423
|
+
</html>
|
|
2424
|
+
`;
|
|
2425
|
+
}
|
|
2426
|
+
function esc(s) {
|
|
2427
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
2428
|
+
}
|
|
2429
|
+
function vibgrateDir(root) {
|
|
2430
|
+
return path18.join(root, ".vibgrate");
|
|
2431
|
+
}
|
|
2432
|
+
function defaultGraphPath(root) {
|
|
2433
|
+
return path18.join(vibgrateDir(root), "graph.json");
|
|
2434
|
+
}
|
|
2435
|
+
function writeArtifacts(graph, options) {
|
|
2436
|
+
const dir = vibgrateDir(options.root);
|
|
2437
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
2438
|
+
const graphPath = options.graphPath ?? defaultGraphPath(options.root);
|
|
2439
|
+
fs18.mkdirSync(path18.dirname(graphPath), { recursive: true });
|
|
2440
|
+
const tmp = `${graphPath}.${process.pid}.tmp`;
|
|
2441
|
+
try {
|
|
2442
|
+
fs18.writeFileSync(tmp, serializeGraph(graph));
|
|
2443
|
+
fs18.renameSync(tmp, graphPath);
|
|
2444
|
+
} catch (err) {
|
|
2445
|
+
fs18.rmSync(tmp, { force: true });
|
|
2446
|
+
throw err;
|
|
2447
|
+
}
|
|
2448
|
+
const written = { graphPath };
|
|
2449
|
+
if (options.report !== false) {
|
|
2450
|
+
const reportPath = path18.join(dir, "GRAPH_REPORT.md");
|
|
2451
|
+
fs18.writeFileSync(reportPath, renderReport(graph));
|
|
2452
|
+
written.reportPath = reportPath;
|
|
2453
|
+
}
|
|
2454
|
+
if (options.html !== false) {
|
|
2455
|
+
const htmlPath = path18.join(dir, "graph.html");
|
|
2456
|
+
fs18.writeFileSync(htmlPath, renderHtml(graph));
|
|
2457
|
+
written.htmlPath = htmlPath;
|
|
2458
|
+
}
|
|
2459
|
+
if (graph.facts && graph.facts.length) {
|
|
2460
|
+
const factsPath = path18.join(dir, "facts.jsonl");
|
|
2461
|
+
fs18.writeFileSync(factsPath, graph.facts.map((f) => JSON.stringify(f)).join("\n") + "\n");
|
|
2462
|
+
written.factsPath = factsPath;
|
|
2463
|
+
}
|
|
2464
|
+
return written;
|
|
2465
|
+
}
|
|
2466
|
+
function loadGraph(root, graphPath) {
|
|
2467
|
+
const file = graphPath ?? defaultGraphPath(root);
|
|
2468
|
+
if (!fs18.existsSync(file)) return null;
|
|
2469
|
+
return parseGraph(fs18.readFileSync(file, "utf8"));
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
// src/engine/verify.ts
|
|
2473
|
+
var PINNED = "1970-01-01T00:00:00.000Z";
|
|
2474
|
+
async function verifyDeterminism(opts) {
|
|
2475
|
+
const base = { root: opts.root, only: opts.only, exclude: opts.exclude, generatedAt: PINNED };
|
|
2476
|
+
const buildA = await buildGraph({ ...base, noCache: true, jobs: opts.jobs });
|
|
2477
|
+
const a = serializeGraph(buildA.graph);
|
|
2478
|
+
const b = serializeGraph((await buildGraph({ ...base, noCache: true, jobs: 1 })).graph);
|
|
2479
|
+
const cached2 = serializeGraph((await buildGraph({ ...base, noCache: false })).graph);
|
|
2480
|
+
const checks = [
|
|
2481
|
+
{ name: "run-to-run determinism", ok: a === b, detail: diffHint(a, b) },
|
|
2482
|
+
{ name: "cache safety (incremental == full)", ok: a === cached2, detail: diffHint(a, cached2) }
|
|
2483
|
+
];
|
|
2484
|
+
const scoped = Boolean(opts.only?.length || opts.exclude?.length);
|
|
2485
|
+
const committed = scoped ? null : loadGraph(opts.root);
|
|
2486
|
+
const committedFp = committed?.provenance.toolchain?.fingerprint;
|
|
2487
|
+
const currentFp = buildA.graph.provenance.toolchain?.fingerprint;
|
|
2488
|
+
if (committedFp && currentFp) {
|
|
2489
|
+
const ok = committedFp === currentFp;
|
|
2490
|
+
checks.push({
|
|
2491
|
+
name: "toolchain fingerprint matches committed graph",
|
|
2492
|
+
ok,
|
|
2493
|
+
detail: ok ? void 0 : `committed toolchain ${committedFp} != current ${currentFp} (grammar/resolver versions differ \u2014 rebuild or align the toolchain)`
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
return {
|
|
2497
|
+
ok: checks.every((c) => c.ok),
|
|
2498
|
+
checks,
|
|
2499
|
+
digest: hashString(a)
|
|
2500
|
+
};
|
|
2501
|
+
}
|
|
2502
|
+
function diffHint(x, y) {
|
|
2503
|
+
if (x === y) return void 0;
|
|
2504
|
+
const xl = x.split("\n");
|
|
2505
|
+
const yl = y.split("\n");
|
|
2506
|
+
const n = Math.max(xl.length, yl.length);
|
|
2507
|
+
for (let i = 0; i < n; i++) {
|
|
2508
|
+
if (xl[i] !== yl[i]) {
|
|
2509
|
+
return `first divergence at line ${i + 1}`;
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
return "outputs differ in length";
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
// src/util/exit.ts
|
|
2516
|
+
var ExitCode = {
|
|
2517
|
+
OK: 0,
|
|
2518
|
+
ERROR: 1,
|
|
2519
|
+
GATE_FAILED: 2,
|
|
2520
|
+
NOT_FOUND: 3,
|
|
2521
|
+
NON_DETERMINISTIC: 4,
|
|
2522
|
+
USAGE_ERROR: 5
|
|
2523
|
+
};
|
|
2524
|
+
var CliError = class extends Error {
|
|
2525
|
+
code;
|
|
2526
|
+
constructor(message, code = ExitCode.ERROR) {
|
|
2527
|
+
super(message);
|
|
2528
|
+
this.name = "CliError";
|
|
2529
|
+
this.code = code;
|
|
2530
|
+
}
|
|
2531
|
+
};
|
|
2532
|
+
function usageError(message) {
|
|
2533
|
+
return new CliError(message, ExitCode.USAGE_ERROR);
|
|
2534
|
+
}
|
|
2252
2535
|
var DEFAULT_LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
2253
2536
|
function isProcessAlive(pid) {
|
|
2254
2537
|
try {
|
|
@@ -2574,155 +2857,6 @@ async function getNodeEmbeddings(graph, embedder, root, onProgress) {
|
|
|
2574
2857
|
function safe(id) {
|
|
2575
2858
|
return id.replace(/[^a-z0-9.-]+/gi, "_");
|
|
2576
2859
|
}
|
|
2577
|
-
|
|
2578
|
-
// src/engine/report.ts
|
|
2579
|
-
function renderReport(graph) {
|
|
2580
|
-
const { meta, provenance, nodes, edges } = graph;
|
|
2581
|
-
const lines = [];
|
|
2582
|
-
lines.push("# Code Graph Report");
|
|
2583
|
-
lines.push("");
|
|
2584
|
-
lines.push(`Generated by \`vg\` ${provenance.version} \xB7 schema \`${graph.schemaVersion}\``);
|
|
2585
|
-
lines.push("");
|
|
2586
|
-
lines.push("## Summary");
|
|
2587
|
-
lines.push("");
|
|
2588
|
-
lines.push(`- **Nodes:** ${meta.counts.nodes.toLocaleString("en-US")}`);
|
|
2589
|
-
lines.push(`- **Edges:** ${meta.counts.edges.toLocaleString("en-US")}`);
|
|
2590
|
-
lines.push(`- **Areas:** ${meta.counts.areas.toLocaleString("en-US")}`);
|
|
2591
|
-
lines.push(`- **Languages:** ${meta.languages.join(", ") || "\u2014"}`);
|
|
2592
|
-
lines.push(`- **Clustering:** ${meta.cluster}`);
|
|
2593
|
-
lines.push(`- **Resolvers:** ${provenance.resolver.join(", ")}`);
|
|
2594
|
-
lines.push(`- **Edge kinds:** ${meta.edgeKinds.join(", ") || "\u2014"}`);
|
|
2595
|
-
lines.push("");
|
|
2596
|
-
const fileNodes = nodes.filter((n) => n.kind === "file");
|
|
2597
|
-
const defsByFile = /* @__PURE__ */ new Map();
|
|
2598
|
-
for (const n of nodes) {
|
|
2599
|
-
if (n.kind === "file" || n.kind === "external") continue;
|
|
2600
|
-
defsByFile.set(n.file, (defsByFile.get(n.file) ?? 0) + 1);
|
|
2601
|
-
}
|
|
2602
|
-
const topFiles = [...defsByFile.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, 15);
|
|
2603
|
-
if (topFiles.length) {
|
|
2604
|
-
lines.push("## Largest files (by definitions)");
|
|
2605
|
-
lines.push("");
|
|
2606
|
-
lines.push("| File | Definitions |");
|
|
2607
|
-
lines.push("| --- | ---: |");
|
|
2608
|
-
for (const [file, count] of topFiles) lines.push(`| \`${file}\` | ${count} |`);
|
|
2609
|
-
lines.push("");
|
|
2610
|
-
}
|
|
2611
|
-
const topNodes = nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName)).slice(0, 15);
|
|
2612
|
-
if (topNodes.length) {
|
|
2613
|
-
lines.push("## Most-connected definitions");
|
|
2614
|
-
lines.push("");
|
|
2615
|
-
lines.push("| Symbol | Kind | File | Importance |");
|
|
2616
|
-
lines.push("| --- | --- | --- | ---: |");
|
|
2617
|
-
for (const n of topNodes) {
|
|
2618
|
-
lines.push(
|
|
2619
|
-
`| \`${n.qualifiedName}\` | ${n.kind} | \`${n.file}\`:${n.span.start} | ${n.importance.toFixed(3)} |`
|
|
2620
|
-
);
|
|
2621
|
-
}
|
|
2622
|
-
lines.push("");
|
|
2623
|
-
}
|
|
2624
|
-
const byKind = /* @__PURE__ */ new Map();
|
|
2625
|
-
for (const e of edges) byKind.set(e.kind, (byKind.get(e.kind) ?? 0) + 1);
|
|
2626
|
-
if (byKind.size) {
|
|
2627
|
-
lines.push("## Edges by kind");
|
|
2628
|
-
lines.push("");
|
|
2629
|
-
lines.push("| Kind | Count |");
|
|
2630
|
-
lines.push("| --- | ---: |");
|
|
2631
|
-
for (const [kind, count] of [...byKind.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
2632
|
-
lines.push(`| ${kind} | ${count} |`);
|
|
2633
|
-
}
|
|
2634
|
-
lines.push("");
|
|
2635
|
-
}
|
|
2636
|
-
lines.push("---");
|
|
2637
|
-
lines.push("");
|
|
2638
|
-
lines.push(`_Files: ${fileNodes.length} \xB7 Corpus: \`${provenance.corpusHash.slice(0, 16)}\u2026\`_`);
|
|
2639
|
-
lines.push("");
|
|
2640
|
-
return lines.join("\n");
|
|
2641
|
-
}
|
|
2642
|
-
|
|
2643
|
-
// src/engine/html.ts
|
|
2644
|
-
function renderHtml(graph) {
|
|
2645
|
-
const top = graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName)).slice(0, 50);
|
|
2646
|
-
const rows = top.map(
|
|
2647
|
-
(n) => `<tr><td><code>${esc(n.qualifiedName)}</code></td><td>${esc(n.kind)}</td><td><code>${esc(n.file)}</code>:${n.span.start}</td><td>${n.importance.toFixed(3)}</td></tr>`
|
|
2648
|
-
).join("\n");
|
|
2649
|
-
const embedded = stableStringify(graph, 0);
|
|
2650
|
-
return `<!doctype html>
|
|
2651
|
-
<html lang="en">
|
|
2652
|
-
<head>
|
|
2653
|
-
<meta charset="utf-8">
|
|
2654
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
2655
|
-
<title>vg \xB7 code graph</title>
|
|
2656
|
-
<style>
|
|
2657
|
-
:root { color-scheme: light dark; }
|
|
2658
|
-
body { font: 14px/1.5 system-ui, sans-serif; margin: 2rem auto; max-width: 60rem; padding: 0 1rem; }
|
|
2659
|
-
h1 { font-size: 1.4rem; } h2 { font-size: 1.1rem; margin-top: 2rem; }
|
|
2660
|
-
table { border-collapse: collapse; width: 100%; }
|
|
2661
|
-
th, td { text-align: left; padding: 4px 8px; border-bottom: 1px solid #8884; }
|
|
2662
|
-
td:last-child, th:last-child { text-align: right; }
|
|
2663
|
-
.meta { color: #888; } code { font-size: 0.9em; }
|
|
2664
|
-
</style>
|
|
2665
|
-
</head>
|
|
2666
|
-
<body>
|
|
2667
|
-
<h1>vg \xB7 code graph</h1>
|
|
2668
|
-
<p class="meta">${graph.meta.counts.nodes} nodes \xB7 ${graph.meta.counts.edges} edges \xB7
|
|
2669
|
-
${graph.meta.counts.areas} areas \xB7 ${esc(graph.meta.languages.join(", ") || "\u2014")} \xB7
|
|
2670
|
-
clustering: ${esc(graph.meta.cluster)} \xB7 vg ${esc(graph.provenance.version)}</p>
|
|
2671
|
-
<h2>Most-connected definitions</h2>
|
|
2672
|
-
<table>
|
|
2673
|
-
<thead><tr><th>Symbol</th><th>Kind</th><th>Location</th><th>Importance</th></tr></thead>
|
|
2674
|
-
<tbody>
|
|
2675
|
-
${rows}
|
|
2676
|
-
</tbody>
|
|
2677
|
-
</table>
|
|
2678
|
-
<p class="meta">Interactive WebGL view arrives in Phase 1. The full graph is embedded below for tooling.</p>
|
|
2679
|
-
<script type="application/json" id="vg-graph">
|
|
2680
|
-
${embedded}
|
|
2681
|
-
</script>
|
|
2682
|
-
</body>
|
|
2683
|
-
</html>
|
|
2684
|
-
`;
|
|
2685
|
-
}
|
|
2686
|
-
function esc(s) {
|
|
2687
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
2688
|
-
}
|
|
2689
|
-
function vibgrateDir(root) {
|
|
2690
|
-
return path18.join(root, ".vibgrate");
|
|
2691
|
-
}
|
|
2692
|
-
function defaultGraphPath(root) {
|
|
2693
|
-
return path18.join(vibgrateDir(root), "graph.json");
|
|
2694
|
-
}
|
|
2695
|
-
function writeArtifacts(graph, options) {
|
|
2696
|
-
const dir = vibgrateDir(options.root);
|
|
2697
|
-
fs18.mkdirSync(dir, { recursive: true });
|
|
2698
|
-
const graphPath = options.graphPath ?? defaultGraphPath(options.root);
|
|
2699
|
-
fs18.mkdirSync(path18.dirname(graphPath), { recursive: true });
|
|
2700
|
-
const tmp = `${graphPath}.${process.pid}.tmp`;
|
|
2701
|
-
try {
|
|
2702
|
-
fs18.writeFileSync(tmp, serializeGraph(graph));
|
|
2703
|
-
fs18.renameSync(tmp, graphPath);
|
|
2704
|
-
} catch (err) {
|
|
2705
|
-
fs18.rmSync(tmp, { force: true });
|
|
2706
|
-
throw err;
|
|
2707
|
-
}
|
|
2708
|
-
const written = { graphPath };
|
|
2709
|
-
if (options.report !== false) {
|
|
2710
|
-
const reportPath = path18.join(dir, "GRAPH_REPORT.md");
|
|
2711
|
-
fs18.writeFileSync(reportPath, renderReport(graph));
|
|
2712
|
-
written.reportPath = reportPath;
|
|
2713
|
-
}
|
|
2714
|
-
if (options.html !== false) {
|
|
2715
|
-
const htmlPath = path18.join(dir, "graph.html");
|
|
2716
|
-
fs18.writeFileSync(htmlPath, renderHtml(graph));
|
|
2717
|
-
written.htmlPath = htmlPath;
|
|
2718
|
-
}
|
|
2719
|
-
if (graph.facts && graph.facts.length) {
|
|
2720
|
-
const factsPath = path18.join(dir, "facts.jsonl");
|
|
2721
|
-
fs18.writeFileSync(factsPath, graph.facts.map((f) => JSON.stringify(f)).join("\n") + "\n");
|
|
2722
|
-
written.factsPath = factsPath;
|
|
2723
|
-
}
|
|
2724
|
-
return written;
|
|
2725
|
-
}
|
|
2726
2860
|
var SNAPSHOT_VERSION = "vg-freshness/1";
|
|
2727
2861
|
function snapshotPath(root) {
|
|
2728
2862
|
return path18.join(cacheDir(root), "freshness.json");
|
|
@@ -2824,62 +2958,6 @@ function pruneScope(scope) {
|
|
|
2824
2958
|
return out;
|
|
2825
2959
|
}
|
|
2826
2960
|
|
|
2827
|
-
// src/util/exit.ts
|
|
2828
|
-
var ExitCode = {
|
|
2829
|
-
OK: 0,
|
|
2830
|
-
ERROR: 1,
|
|
2831
|
-
GATE_FAILED: 2,
|
|
2832
|
-
NOT_FOUND: 3,
|
|
2833
|
-
NON_DETERMINISTIC: 4,
|
|
2834
|
-
USAGE_ERROR: 5
|
|
2835
|
-
};
|
|
2836
|
-
var CliError = class extends Error {
|
|
2837
|
-
code;
|
|
2838
|
-
constructor(message, code = ExitCode.ERROR) {
|
|
2839
|
-
super(message);
|
|
2840
|
-
this.name = "CliError";
|
|
2841
|
-
this.code = code;
|
|
2842
|
-
}
|
|
2843
|
-
};
|
|
2844
|
-
function usageError(message) {
|
|
2845
|
-
return new CliError(message, ExitCode.USAGE_ERROR);
|
|
2846
|
-
}
|
|
2847
|
-
function loadGraph(root, graphPath) {
|
|
2848
|
-
const file = graphPath ?? defaultGraphPath(root);
|
|
2849
|
-
if (!fs18.existsSync(file)) return null;
|
|
2850
|
-
return parseGraph(fs18.readFileSync(file, "utf8"));
|
|
2851
|
-
}
|
|
2852
|
-
|
|
2853
|
-
// src/engine/verify.ts
|
|
2854
|
-
var PINNED = "1970-01-01T00:00:00.000Z";
|
|
2855
|
-
async function verifyDeterminism(opts) {
|
|
2856
|
-
const base = { root: opts.root, only: opts.only, exclude: opts.exclude, generatedAt: PINNED };
|
|
2857
|
-
const a = serializeGraph((await buildGraph({ ...base, noCache: true, jobs: opts.jobs })).graph);
|
|
2858
|
-
const b = serializeGraph((await buildGraph({ ...base, noCache: true, jobs: 1 })).graph);
|
|
2859
|
-
const cached2 = serializeGraph((await buildGraph({ ...base, noCache: false })).graph);
|
|
2860
|
-
const checks = [
|
|
2861
|
-
{ name: "run-to-run determinism", ok: a === b, detail: diffHint(a, b) },
|
|
2862
|
-
{ name: "cache safety (incremental == full)", ok: a === cached2, detail: diffHint(a, cached2) }
|
|
2863
|
-
];
|
|
2864
|
-
return {
|
|
2865
|
-
ok: checks.every((c) => c.ok),
|
|
2866
|
-
checks,
|
|
2867
|
-
digest: hashString(a)
|
|
2868
|
-
};
|
|
2869
|
-
}
|
|
2870
|
-
function diffHint(x, y) {
|
|
2871
|
-
if (x === y) return void 0;
|
|
2872
|
-
const xl = x.split("\n");
|
|
2873
|
-
const yl = y.split("\n");
|
|
2874
|
-
const n = Math.max(xl.length, yl.length);
|
|
2875
|
-
for (let i = 0; i < n; i++) {
|
|
2876
|
-
if (xl[i] !== yl[i]) {
|
|
2877
|
-
return `first divergence at line ${i + 1}`;
|
|
2878
|
-
}
|
|
2879
|
-
}
|
|
2880
|
-
return "outputs differ in length";
|
|
2881
|
-
}
|
|
2882
|
-
|
|
2883
2961
|
// src/engine/relations.ts
|
|
2884
2962
|
var GraphIndex = class {
|
|
2885
2963
|
constructor(graph) {
|
|
@@ -5537,6 +5615,17 @@ var obj = (properties, required = []) => ({
|
|
|
5537
5615
|
var RESPONSE_FORMAT = { type: "string", enum: ["concise", "detailed"] };
|
|
5538
5616
|
var isDetailed = (args) => args.response_format === "detailed";
|
|
5539
5617
|
var CONCISE_MATCHES = 5;
|
|
5618
|
+
var EPISTEMIC_TIERS = ["observed", "name-matched", "declared"];
|
|
5619
|
+
var EDGE_FILTER_SCHEMA = {
|
|
5620
|
+
min_edge_confidence: { type: "number", description: "0..1 \u2014 drop edges below this confidence" },
|
|
5621
|
+
epistemic: { type: "string", enum: EPISTEMIC_TIERS, description: "keep only edges of this evidence tier" }
|
|
5622
|
+
};
|
|
5623
|
+
function edgeRecordFilter(args) {
|
|
5624
|
+
const min = numOrU(args.min_edge_confidence);
|
|
5625
|
+
const tier = EPISTEMIC_TIERS.includes(String(args.epistemic)) ? String(args.epistemic) : void 0;
|
|
5626
|
+
if (min == null && !tier) return () => true;
|
|
5627
|
+
return (x) => (min == null || x.edge.confidence >= min) && (!tier || x.edge.epistemic === tier);
|
|
5628
|
+
}
|
|
5540
5629
|
var TOOLS = [
|
|
5541
5630
|
{
|
|
5542
5631
|
name: "orient",
|
|
@@ -5639,6 +5728,7 @@ var TOOLS = [
|
|
|
5639
5728
|
{
|
|
5640
5729
|
name: { type: "string" },
|
|
5641
5730
|
pick: { type: "number", description: "nth candidate if ambiguous" },
|
|
5731
|
+
...EDGE_FILTER_SCHEMA,
|
|
5642
5732
|
response_format: RESPONSE_FORMAT
|
|
5643
5733
|
},
|
|
5644
5734
|
["name"]
|
|
@@ -5647,6 +5737,9 @@ var TOOLS = [
|
|
|
5647
5737
|
const { node, candidates } = resolveOne(graph, String(args.name ?? ""), numOrU(args.pick));
|
|
5648
5738
|
if (!node) return unresolved(candidates);
|
|
5649
5739
|
const index = new GraphIndex(graph);
|
|
5740
|
+
const edgeOk = edgeRecordFilter(args);
|
|
5741
|
+
const calleeRecs = index.callees(node.id).filter(edgeOk);
|
|
5742
|
+
const callerRecs = index.callers(node.id).filter(edgeOk);
|
|
5650
5743
|
const base = {
|
|
5651
5744
|
name: node.qualifiedName,
|
|
5652
5745
|
kind: node.kind,
|
|
@@ -5658,11 +5751,11 @@ var TOOLS = [
|
|
|
5658
5751
|
area: node.area
|
|
5659
5752
|
};
|
|
5660
5753
|
if (ctx?.dedup && ctx.seen?.has(node.id)) {
|
|
5661
|
-
return { ...base, repeat: true, callsTotal: uniqueNames(
|
|
5754
|
+
return { ...base, repeat: true, callsTotal: uniqueNames(calleeRecs.map((x) => x.node.qualifiedName)).length, calledByTotal: uniqueNames(callerRecs.map((x) => x.node.qualifiedName)).length };
|
|
5662
5755
|
}
|
|
5663
5756
|
const edgeCap = isDetailed(args) ? NODE_EDGE_CAP : CONCISE_MATCHES;
|
|
5664
|
-
const calls = boundList(uniqueNames(
|
|
5665
|
-
const calledBy = boundList(uniqueNames(
|
|
5757
|
+
const calls = boundList(uniqueNames(calleeRecs.map((x) => x.node.qualifiedName)), edgeCap);
|
|
5758
|
+
const calledBy = boundList(uniqueNames(callerRecs.map((x) => x.node.qualifiedName)), edgeCap);
|
|
5666
5759
|
ctx?.seen?.add(node.id);
|
|
5667
5760
|
return {
|
|
5668
5761
|
...base,
|
|
@@ -5705,6 +5798,7 @@ var TOOLS = [
|
|
|
5705
5798
|
change_type: { type: "string", enum: ["modify", "delete", "rename", "add_dependency"] },
|
|
5706
5799
|
depth: { type: "number", description: "default 4" },
|
|
5707
5800
|
pick: { type: "number", description: "nth candidate if ambiguous" },
|
|
5801
|
+
min_edge_confidence: { type: "number", description: "0..1 \u2014 drop dependents below this (decayed) confidence" },
|
|
5708
5802
|
response_format: RESPONSE_FORMAT
|
|
5709
5803
|
},
|
|
5710
5804
|
["name"]
|
|
@@ -5714,6 +5808,14 @@ var TOOLS = [
|
|
|
5714
5808
|
if (!node) return unresolved(candidates);
|
|
5715
5809
|
const changeType = ["modify", "delete", "rename", "add_dependency"].includes(String(args.change_type)) ? String(args.change_type) : "modify";
|
|
5716
5810
|
const r = impactOf(graph, node.id, { depth: numOr(args.depth, 4) });
|
|
5811
|
+
const minConf = numOrU(args.min_edge_confidence);
|
|
5812
|
+
if (minConf != null) {
|
|
5813
|
+
const kept = r.affected.filter((a) => a.confidence >= minConf);
|
|
5814
|
+
r.affected = kept;
|
|
5815
|
+
r.direct = kept.filter((i) => i.depth === 1).length;
|
|
5816
|
+
r.transitive = kept.filter((i) => i.depth > 1).length;
|
|
5817
|
+
r.minEdgeConfidence = kept.length ? Math.min(...kept.map((i) => i.confidence)) : 1;
|
|
5818
|
+
}
|
|
5717
5819
|
const tests = coveringTests(graph, node);
|
|
5718
5820
|
const filesAffected = [...new Set(r.affected.map((a) => a.file))];
|
|
5719
5821
|
const heavyChange = changeType === "delete" || changeType === "rename";
|
|
@@ -6610,6 +6712,8 @@ function formatForExt(ext) {
|
|
|
6610
6712
|
return "dot";
|
|
6611
6713
|
case ".cypher":
|
|
6612
6714
|
return "cypher";
|
|
6715
|
+
case ".sql":
|
|
6716
|
+
return "sql";
|
|
6613
6717
|
case ".md":
|
|
6614
6718
|
return "md";
|
|
6615
6719
|
case ".html":
|
|
@@ -6634,6 +6738,8 @@ function exportGraph(format, ctx) {
|
|
|
6634
6738
|
return dot(ctx.graph);
|
|
6635
6739
|
case "cypher":
|
|
6636
6740
|
return cypher(ctx.graph);
|
|
6741
|
+
case "sql":
|
|
6742
|
+
return sql(ctx);
|
|
6637
6743
|
case "cyclonedx":
|
|
6638
6744
|
return cyclonedx(ctx);
|
|
6639
6745
|
case "spdx":
|
|
@@ -6696,6 +6802,66 @@ function cypherLabel(s) {
|
|
|
6696
6802
|
function q(s) {
|
|
6697
6803
|
return JSON.stringify(s);
|
|
6698
6804
|
}
|
|
6805
|
+
function sql(ctx) {
|
|
6806
|
+
const graph = ctx.graph;
|
|
6807
|
+
const lines = [];
|
|
6808
|
+
lines.push("BEGIN;");
|
|
6809
|
+
lines.push("CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);");
|
|
6810
|
+
const meta = [
|
|
6811
|
+
["schemaVersion", graph.schemaVersion],
|
|
6812
|
+
["generatedAt", ctx.generatedAt],
|
|
6813
|
+
["corpusHash", graph.provenance.corpusHash],
|
|
6814
|
+
["tool", graph.provenance.tool],
|
|
6815
|
+
["toolVersion", graph.provenance.version],
|
|
6816
|
+
["resolver", graph.provenance.resolver.join(",")],
|
|
6817
|
+
["fingerprint", graph.provenance.toolchain?.fingerprint ?? null]
|
|
6818
|
+
];
|
|
6819
|
+
for (const [k, v] of meta) lines.push(`INSERT INTO meta VALUES (${sqlStr(k)}, ${sqlStr(v)});`);
|
|
6820
|
+
lines.push(
|
|
6821
|
+
"CREATE TABLE IF NOT EXISTS nodes (id TEXT PRIMARY KEY, kind TEXT, name TEXT, qualified_name TEXT, file TEXT, span_start INTEGER, span_end INTEGER, lang TEXT, visibility TEXT, signature TEXT, importance REAL, area INTEGER, is_hub INTEGER, tested INTEGER, coverage REAL);"
|
|
6822
|
+
);
|
|
6823
|
+
for (const n of graph.nodes) {
|
|
6824
|
+
lines.push(
|
|
6825
|
+
`INSERT INTO nodes VALUES (${sqlStr(n.id)}, ${sqlStr(n.kind)}, ${sqlStr(n.name)}, ${sqlStr(n.qualifiedName)}, ${sqlStr(n.file)}, ${sqlNum(n.span.start)}, ${sqlNum(n.span.end)}, ${sqlStr(n.lang)}, ${sqlStr(n.visibility)}, ${sqlStr(n.signature)}, ${sqlNum(n.importance)}, ${sqlNum(n.area)}, ${sqlBool(n.isHub)}, ${sqlBool(n.tested)}, ${sqlNum(n.coverage)});`
|
|
6826
|
+
);
|
|
6827
|
+
}
|
|
6828
|
+
lines.push(
|
|
6829
|
+
'CREATE TABLE IF NOT EXISTS edges (id TEXT PRIMARY KEY, kind TEXT, src TEXT, dst TEXT, resolution TEXT, confidence REAL, epistemic TEXT, surprise REAL, "count" INTEGER);'
|
|
6830
|
+
);
|
|
6831
|
+
for (const e of graph.edges) {
|
|
6832
|
+
lines.push(
|
|
6833
|
+
`INSERT INTO edges VALUES (${sqlStr(e.id)}, ${sqlStr(e.kind)}, ${sqlStr(e.src)}, ${sqlStr(e.dst)}, ${sqlStr(e.resolution)}, ${sqlNum(e.confidence)}, ${sqlStr(e.epistemic)}, ${sqlNum(e.surprise)}, ${sqlNum(e.count)});`
|
|
6834
|
+
);
|
|
6835
|
+
}
|
|
6836
|
+
lines.push("CREATE TABLE IF NOT EXISTS areas (id INTEGER PRIMARY KEY, label TEXT, size INTEGER, cohesion REAL, external_edges INTEGER);");
|
|
6837
|
+
lines.push("CREATE TABLE IF NOT EXISTS area_members (area_id INTEGER, node_id TEXT);");
|
|
6838
|
+
for (const a of graph.areas) {
|
|
6839
|
+
lines.push(`INSERT INTO areas VALUES (${sqlNum(a.id)}, ${sqlStr(a.label)}, ${sqlNum(a.size)}, ${sqlNum(a.cohesion)}, ${sqlNum(a.externalEdges)});`);
|
|
6840
|
+
for (const m of a.members) lines.push(`INSERT INTO area_members VALUES (${sqlNum(a.id)}, ${sqlStr(m)});`);
|
|
6841
|
+
}
|
|
6842
|
+
if (graph.facts && graph.facts.length) {
|
|
6843
|
+
lines.push("CREATE TABLE IF NOT EXISTS facts (id TEXT PRIMARY KEY, kind TEXT, predicate_json TEXT, derived_by TEXT, confidence TEXT);");
|
|
6844
|
+
lines.push("CREATE TABLE IF NOT EXISTS fact_subjects (fact_id TEXT, node_id TEXT);");
|
|
6845
|
+
lines.push("CREATE TABLE IF NOT EXISTS fact_evidence (fact_id TEXT, file TEXT, span_start INTEGER, span_end INTEGER);");
|
|
6846
|
+
for (const f of graph.facts) {
|
|
6847
|
+
lines.push(`INSERT INTO facts VALUES (${sqlStr(f.id)}, ${sqlStr(f.kind)}, ${sqlStr(JSON.stringify(f.predicate))}, ${sqlStr(f.derivedBy)}, ${sqlStr(f.confidence)});`);
|
|
6848
|
+
for (const s of f.subjectIds) lines.push(`INSERT INTO fact_subjects VALUES (${sqlStr(f.id)}, ${sqlStr(s)});`);
|
|
6849
|
+
for (const ev of f.evidence) lines.push(`INSERT INTO fact_evidence VALUES (${sqlStr(f.id)}, ${sqlStr(ev.file)}, ${sqlNum(ev.span.start)}, ${sqlNum(ev.span.end)});`);
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
lines.push("COMMIT;");
|
|
6853
|
+
return lines.join("\n") + "\n";
|
|
6854
|
+
}
|
|
6855
|
+
function sqlStr(v) {
|
|
6856
|
+
if (v == null) return "NULL";
|
|
6857
|
+
return `'${v.replace(/'/g, "''")}'`;
|
|
6858
|
+
}
|
|
6859
|
+
function sqlNum(v) {
|
|
6860
|
+
return v == null || !Number.isFinite(v) ? "NULL" : String(v);
|
|
6861
|
+
}
|
|
6862
|
+
function sqlBool(v) {
|
|
6863
|
+
return v == null ? "NULL" : v ? "1" : "0";
|
|
6864
|
+
}
|
|
6699
6865
|
function cyclonedx(ctx) {
|
|
6700
6866
|
const components = [];
|
|
6701
6867
|
for (const d of ctx.deps ?? []) {
|
|
@@ -6735,6 +6901,6 @@ function spdx(ctx) {
|
|
|
6735
6901
|
return JSON.stringify(doc, null, 2) + "\n";
|
|
6736
6902
|
}
|
|
6737
6903
|
|
|
6738
|
-
export { ASSISTANTS, CliError, ECOSYSTEMS, ExitCode, FREE_PACK, GraphIndex, GraphSource, NPX_INVOCATION, ResourceLimitError, SCHEMA_VERSION, SKIP_DIRS, SKIP_FILES, TOOLS, UsageError, addLibrary, analyze, applyCoverage, applyStaticTestLinkage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, buildModuleResolver, cacheDir, catalogPath, clearModelCache, clearStoredCredentials, cosine, countPending, coveringTests, createServer, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, defaultGraphPath, detectRunner, detectServeLaunch, discover, discoverModels, driftCount, driftFor, dsnCommand, embeddingsCached, enrichOnline, ensureGitignored, exportGraph, fetchHostedDocs, findGitRoot, findNodes, formatForExt, getNodeEmbeddings, gitignoreEntryForCredentials, groundGraph, hasDrift, identifierParts, impactOf, installAssistant, inventory, isModelReady, isTestFile, libDir, libId, loadCatalog, loadCoverage, loadEmbedder, loadGraph, loadSnapshot, localApiSurface, localPackageDocs, modelCacheInfo, nodeById, nodeEmbedText, parseDsn, parseGraph, parseJsonc, probeFreshness, publishPrivateLibrary, pushCommand, queryGraph, queryGraphSemantic, readDoc, readSavings, readScanArtifact, recordSaving, refreshIfStale, relativeResolver, renderHtml, renderReport, resolveCliInvocation, resolveDsn, resolveEmbedModel, resolveIngestHost, resolveLib, resolveLimits, resolveOne, resolveVersion, saveCatalog, savingsRecorded, scipEdges, selectForBudget, serializeGraph, serveStdio, shortestPath, stableStringify, symbolsFromApi, testsToRun, unavailableMessage, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, vibgrateDir, writeArtifacts, writeNavigationConfig, writeSnapshot, writeStoredCredentials };
|
|
6739
|
-
//# sourceMappingURL=chunk-
|
|
6740
|
-
//# sourceMappingURL=chunk-
|
|
6904
|
+
export { ASSISTANTS, CliError, ECOSYSTEMS, ExitCode, FREE_PACK, GraphIndex, GraphSource, NPX_INVOCATION, ResourceLimitError, SCHEMA_VERSION, SKIP_DIRS, SKIP_FILES, TOOLS, UsageError, addLibrary, analyze, applyCoverage, applyStaticTestLinkage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, buildModuleResolver, cacheDir, catalogPath, clearModelCache, clearStoredCredentials, cosine, countPending, coveringTests, createServer, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, defaultGraphPath, detectRunner, detectServeLaunch, discover, discoverModels, driftCount, driftFor, dsnCommand, embeddingsCached, enrichOnline, ensureGitignored, epistemicBreakdown, exportGraph, fetchHostedDocs, findGitRoot, findNodes, formatForExt, getNodeEmbeddings, gitignoreEntryForCredentials, groundGraph, hasDrift, identifierParts, impactOf, ingestHostForRegionId, installAssistant, inventory, isModelReady, isTestFile, libDir, libId, loadCatalog, loadCoverage, loadEmbedder, loadGraph, loadSnapshot, localApiSurface, localPackageDocs, modelCacheInfo, nodeById, nodeEmbedText, parseDsn, parseGraph, parseJsonc, probeFreshness, publishPrivateLibrary, pushCommand, queryGraph, queryGraphSemantic, readDoc, readSavings, readScanArtifact, recordSaving, refreshIfStale, relativeResolver, renderHtml, renderReport, resolveCliInvocation, resolveDsn, resolveEmbedModel, resolveIngestHost, resolveLib, resolveLimits, resolveOne, resolveVersion, saveCatalog, savingsRecorded, scipEdges, selectForBudget, serializeGraph, serveStdio, shortestPath, stableStringify, symbolsFromApi, testsToRun, unavailableMessage, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, vibgrateDir, writeArtifacts, writeNavigationConfig, writeSnapshot, writeStoredCredentials };
|
|
6905
|
+
//# sourceMappingURL=chunk-2J7DPIAL.js.map
|
|
6906
|
+
//# sourceMappingURL=chunk-2J7DPIAL.js.map
|