@vibgrate/cli 2026.727.2 → 2026.727.3
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 +21 -1
- package/README.md +2 -1
- package/dist/baseline-ATM5MXBZ.js +8 -0
- package/dist/{baseline-TG4ATZGZ.js.map → baseline-ATM5MXBZ.js.map} +1 -1
- package/dist/{chunk-CY4WKXB2.js → chunk-2VFWXNS5.js} +3 -3
- package/dist/{chunk-CY4WKXB2.js.map → chunk-2VFWXNS5.js.map} +1 -1
- package/dist/{chunk-LKVMI67M.js → chunk-6JIKUDWM.js} +3 -3
- package/dist/{chunk-LKVMI67M.js.map → chunk-6JIKUDWM.js.map} +1 -1
- package/dist/{chunk-6ABXHZRN.js → chunk-6UK6QPTR.js} +69 -70
- package/dist/chunk-6UK6QPTR.js.map +1 -0
- package/dist/{chunk-TCDAZZNP.js → chunk-77LYGXBI.js} +5 -5
- package/dist/{chunk-TCDAZZNP.js.map → chunk-77LYGXBI.js.map} +1 -1
- package/dist/{chunk-KCKYKDMS.js → chunk-AVQSHIJ5.js} +20 -17
- package/dist/chunk-AVQSHIJ5.js.map +1 -0
- package/dist/{chunk-2XQDMLKB.js → chunk-B3YUO3NW.js} +7 -3
- package/dist/chunk-B3YUO3NW.js.map +1 -0
- package/dist/{chunk-RNP3SMTV.js → chunk-C66GOHYB.js} +8 -8
- package/dist/{chunk-RNP3SMTV.js.map → chunk-C66GOHYB.js.map} +1 -1
- package/dist/{chunk-EX4PQT6W.js → chunk-FFWGT55D.js} +4 -4
- package/dist/{chunk-EX4PQT6W.js.map → chunk-FFWGT55D.js.map} +1 -1
- package/dist/{chunk-6AYDFFP5.js → chunk-HK3AWUXH.js} +3 -3
- package/dist/{chunk-6AYDFFP5.js.map → chunk-HK3AWUXH.js.map} +1 -1
- package/dist/{chunk-KNELIQJO.js → chunk-MAY5HLDH.js} +576 -189
- package/dist/chunk-MAY5HLDH.js.map +1 -0
- package/dist/{chunk-3Q7QBWFW.js → chunk-ON25BX6T.js} +9 -3
- package/dist/chunk-ON25BX6T.js.map +1 -0
- package/dist/{chunk-2MBL43EJ.js → chunk-XPJZTSY7.js} +3 -3
- package/dist/{chunk-2MBL43EJ.js.map → chunk-XPJZTSY7.js.map} +1 -1
- package/dist/{chunk-WGUL45AV.js → chunk-Y23HMSWU.js} +3 -3
- package/dist/{chunk-WGUL45AV.js.map → chunk-Y23HMSWU.js.map} +1 -1
- package/dist/{chunk-J4RFRKZH.js → chunk-Z7GP7XTJ.js} +7 -7
- package/dist/{chunk-J4RFRKZH.js.map → chunk-Z7GP7XTJ.js.map} +1 -1
- package/dist/{chunk-KSBHGWRV.js → chunk-ZBTY6VV4.js} +4 -4
- package/dist/{chunk-KSBHGWRV.js.map → chunk-ZBTY6VV4.js.map} +1 -1
- package/dist/{chunk-K3MZIVZW.js → chunk-ZKNB4YH4.js} +19 -5
- package/dist/chunk-ZKNB4YH4.js.map +1 -0
- package/dist/cli.js +424 -210
- package/dist/cli.js.map +1 -1
- package/dist/{graph-backend-73URGTFY.js → graph-backend-UTOL3SHE.js} +5 -5
- package/dist/{graph-backend-73URGTFY.js.map → graph-backend-UTOL3SHE.js.map} +1 -1
- package/dist/index.d.ts +12 -5
- package/dist/index.js +10 -10
- package/dist/{interactive-372NLI5C.js → interactive-INGJNSON.js} +19 -19
- package/dist/{interactive-372NLI5C.js.map → interactive-INGJNSON.js.map} +1 -1
- package/dist/load-QPOWQD7C.js +8 -0
- package/dist/{load-I333TGNI.js.map → load-QPOWQD7C.js.map} +1 -1
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +1 -1
- package/dist/{runtime-session-JRKCQUHY.js → runtime-session-4AMZIAAG.js} +7 -7
- package/dist/{runtime-session-JRKCQUHY.js.map → runtime-session-4AMZIAAG.js.map} +1 -1
- package/dist/{session-ITPYQ5XI.js → session-M72522AP.js} +6 -6
- package/dist/{session-ITPYQ5XI.js.map → session-M72522AP.js.map} +1 -1
- package/dist/sql-extract-JELDZA6W.js +81 -0
- package/dist/sql-extract-JELDZA6W.js.map +1 -0
- package/dist/{stream-json-SLMDKLXP.js → stream-json-6ZBUA2L3.js} +9 -9
- package/dist/{stream-json-SLMDKLXP.js.map → stream-json-6ZBUA2L3.js.map} +1 -1
- package/dist/{types-7AHBUbFm.d.ts → types-DLH-Ritr.d.ts} +18 -1
- package/dist/{vgd-7JV5KCNJ.js → vgd-CVLKBS7K.js} +6 -6
- package/dist/vgd-CVLKBS7K.js.map +1 -0
- package/package.json +1 -1
- package/dist/baseline-TG4ATZGZ.js +0 -8
- package/dist/chunk-2XQDMLKB.js.map +0 -1
- package/dist/chunk-3Q7QBWFW.js.map +0 -1
- package/dist/chunk-6ABXHZRN.js.map +0 -1
- package/dist/chunk-K3MZIVZW.js.map +0 -1
- package/dist/chunk-KCKYKDMS.js.map +0 -1
- package/dist/chunk-KNELIQJO.js.map +0 -1
- package/dist/load-I333TGNI.js +0 -8
- package/dist/vgd-7JV5KCNJ.js.map +0 -1
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { resolveVersion, resolveLib, loadCatalog, driftFor, localPackageDocs, readDoc, inventory, localApiSurface, edgeId, buildModuleResolver, resolve, applyStaticTestLinkage, nodeId } from './chunk-6JIKUDWM.js';
|
|
2
|
+
import { loadConfig, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem, VERSION } from './chunk-Y23HMSWU.js';
|
|
3
|
+
import { writeTextFile, pathExists, readJsonFile } from './chunk-CRAMOEBE.js';
|
|
3
4
|
import { resolveOne, findNodes } from './chunk-J7LKEB2R.js';
|
|
4
5
|
import { discoverModels } from './chunk-OOIG3RUM.js';
|
|
5
|
-
import { impactOf, indexFor, withTimeout, getNodeEmbeddings, queryGraphSemantic, queryGraph, loadEmbedder, isModelReady, acquireLock, releaseLock } from './chunk-
|
|
6
|
-
import { langById, grammarSetVersion, langForExtension, setGrammarsOverride, parseSource } from './chunk-
|
|
6
|
+
import { impactOf, indexFor, withTimeout, getNodeEmbeddings, queryGraphSemantic, queryGraph, loadEmbedder, isModelReady, acquireLock, releaseLock } from './chunk-6UK6QPTR.js';
|
|
7
|
+
import { langById, grammarSetVersion, langForExtension, setGrammarsOverride, parseSource } from './chunk-ON25BX6T.js';
|
|
7
8
|
import { redactSecrets } from './chunk-RXP66R2E.js';
|
|
8
|
-
import { writeGraphIndex, SCHEMA_VERSION, loadGraph, ensureVibgrateGitignore, vibgrateDir, writeArtifacts } from './chunk-
|
|
9
|
-
import { cacheDir, loadCache, serializeGraph, stableStringify } from './chunk-
|
|
9
|
+
import { writeGraphIndex, SCHEMA_VERSION, loadGraph, ensureVibgrateGitignore, vibgrateDir, writeArtifacts } from './chunk-B3YUO3NW.js';
|
|
10
|
+
import { cacheDir, loadCache, serializeGraph, stableStringify } from './chunk-ZKNB4YH4.js';
|
|
10
11
|
import { shortId, canonicalize, hashString, hashBytes } from './chunk-JFGYT6BI.js';
|
|
11
|
-
import
|
|
12
|
-
import * as fs16 from 'fs';
|
|
12
|
+
import * as fs18 from 'fs';
|
|
13
13
|
import { spawnSync, execFileSync } from 'child_process';
|
|
14
|
-
import * as
|
|
14
|
+
import * as path19 from 'path';
|
|
15
15
|
import ignore from 'ignore';
|
|
16
16
|
import * as v8 from 'v8';
|
|
17
17
|
import Graph from 'graphology';
|
|
@@ -22,6 +22,7 @@ import louvain from 'graphology-communities-louvain';
|
|
|
22
22
|
import * as os from 'os';
|
|
23
23
|
import { fileURLToPath } from 'url';
|
|
24
24
|
import ts from 'typescript';
|
|
25
|
+
import * as fs8 from 'fs/promises';
|
|
25
26
|
import { bidirectional } from 'graphology-shortest-path/unweighted.js';
|
|
26
27
|
import * as crypto from 'crypto';
|
|
27
28
|
import { createHash } from 'crypto';
|
|
@@ -46,9 +47,9 @@ function whichOnPath(cmd) {
|
|
|
46
47
|
}
|
|
47
48
|
function isOwnBinary(binPath) {
|
|
48
49
|
try {
|
|
49
|
-
const real =
|
|
50
|
+
const real = fs18.realpathSync(binPath);
|
|
50
51
|
if (/[\\/]@vibgrate[\\/]cli[\\/]/.test(real)) return true;
|
|
51
|
-
const head =
|
|
52
|
+
const head = fs18.readFileSync(real, { encoding: "utf8" }).slice(0, 2048);
|
|
52
53
|
return head.includes("@vibgrate/cli") || head.includes("vibgrate");
|
|
53
54
|
} catch {
|
|
54
55
|
return false;
|
|
@@ -58,7 +59,7 @@ function isEphemeralNpxBinary(binPath) {
|
|
|
58
59
|
const NPX_SEGMENT = /[\\/]_npx[\\/]/;
|
|
59
60
|
if (NPX_SEGMENT.test(binPath)) return true;
|
|
60
61
|
try {
|
|
61
|
-
return NPX_SEGMENT.test(
|
|
62
|
+
return NPX_SEGMENT.test(fs18.realpathSync(binPath));
|
|
62
63
|
} catch {
|
|
63
64
|
return false;
|
|
64
65
|
}
|
|
@@ -235,19 +236,19 @@ var SKIP_FILES = /* @__PURE__ */ new Set([
|
|
|
235
236
|
"flake.lock"
|
|
236
237
|
]);
|
|
237
238
|
function toPosix(p) {
|
|
238
|
-
return p.split(
|
|
239
|
+
return p.split(path19.sep).join("/");
|
|
239
240
|
}
|
|
240
241
|
function buildRootIgnore(root, exclude) {
|
|
241
242
|
const ig = ignore();
|
|
242
|
-
const gitignorePath =
|
|
243
|
-
if (
|
|
244
|
-
ig.add(
|
|
243
|
+
const gitignorePath = path19.join(root, ".gitignore");
|
|
244
|
+
if (fs18.existsSync(gitignorePath)) {
|
|
245
|
+
ig.add(fs18.readFileSync(gitignorePath, "utf8"));
|
|
245
246
|
}
|
|
246
247
|
if (exclude.length) ig.add(exclude);
|
|
247
248
|
return ig;
|
|
248
249
|
}
|
|
249
250
|
function discover(options) {
|
|
250
|
-
const root =
|
|
251
|
+
const root = path19.resolve(options.root);
|
|
251
252
|
const onlyLangs = (options.only ?? []).filter(Boolean);
|
|
252
253
|
const allowLang = (lang) => onlyLangs.length === 0 || onlyLangs.includes(lang.id);
|
|
253
254
|
for (const id of onlyLangs) {
|
|
@@ -256,27 +257,27 @@ function discover(options) {
|
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
const rootIg = buildRootIgnore(root, options.exclude ?? []);
|
|
259
|
-
const scopeAbs = (options.paths && options.paths.length ? options.paths.map((p) =>
|
|
260
|
+
const scopeAbs = (options.paths && options.paths.length ? options.paths.map((p) => path19.resolve(root, p)) : [root]).filter((p) => fs18.existsSync(p));
|
|
260
261
|
const found = /* @__PURE__ */ new Map();
|
|
261
262
|
const considerFile = (abs) => {
|
|
262
|
-
const rel2 = toPosix(
|
|
263
|
+
const rel2 = toPosix(path19.relative(root, abs));
|
|
263
264
|
if (rel2.startsWith("..")) return;
|
|
264
265
|
if (rel2 === "" || rootIg.ignores(rel2)) return;
|
|
265
|
-
if (SKIP_FILES.has(
|
|
266
|
-
const lang = langForExtension(
|
|
266
|
+
if (SKIP_FILES.has(path19.basename(abs).toLowerCase())) return;
|
|
267
|
+
const lang = langForExtension(path19.extname(abs));
|
|
267
268
|
if (!lang || !allowLang(lang)) return;
|
|
268
269
|
found.set(rel2, { rel: rel2, abs, lang });
|
|
269
270
|
};
|
|
270
271
|
const walk = (dir) => {
|
|
271
272
|
let entries;
|
|
272
273
|
try {
|
|
273
|
-
entries =
|
|
274
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
274
275
|
} catch {
|
|
275
276
|
return;
|
|
276
277
|
}
|
|
277
278
|
for (const entry of entries) {
|
|
278
|
-
const abs =
|
|
279
|
-
const rel2 = toPosix(
|
|
279
|
+
const abs = path19.join(dir, entry.name);
|
|
280
|
+
const rel2 = toPosix(path19.relative(root, abs));
|
|
280
281
|
if (entry.isDirectory()) {
|
|
281
282
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
282
283
|
if (rel2 && rootIg.ignores(`${rel2}/`)) continue;
|
|
@@ -287,7 +288,7 @@ function discover(options) {
|
|
|
287
288
|
}
|
|
288
289
|
};
|
|
289
290
|
for (const scope of scopeAbs) {
|
|
290
|
-
const stat =
|
|
291
|
+
const stat = fs18.statSync(scope);
|
|
291
292
|
if (stat.isDirectory()) walk(scope);
|
|
292
293
|
else if (stat.isFile()) considerFile(scope);
|
|
293
294
|
}
|
|
@@ -769,14 +770,14 @@ var DEFAULT_PATHS = [
|
|
|
769
770
|
];
|
|
770
771
|
function loadCoverage(root, explicit) {
|
|
771
772
|
const candidates = (explicit && explicit.length ? explicit : DEFAULT_PATHS).map(
|
|
772
|
-
(p) =>
|
|
773
|
+
(p) => path19.resolve(root, p)
|
|
773
774
|
);
|
|
774
|
-
const found = candidates.filter((p) =>
|
|
775
|
+
const found = candidates.filter((p) => fs18.existsSync(p));
|
|
775
776
|
if (found.length === 0) return null;
|
|
776
777
|
const map = /* @__PURE__ */ new Map();
|
|
777
778
|
for (const file of found) {
|
|
778
779
|
try {
|
|
779
|
-
const text =
|
|
780
|
+
const text = fs18.readFileSync(file, "utf8");
|
|
780
781
|
if (file.endsWith(".json")) mergeIstanbul(map, text, root);
|
|
781
782
|
else mergeLcov(map, text, root);
|
|
782
783
|
} catch {
|
|
@@ -785,8 +786,8 @@ function loadCoverage(root, explicit) {
|
|
|
785
786
|
return map.size ? map : null;
|
|
786
787
|
}
|
|
787
788
|
function rel(root, p) {
|
|
788
|
-
const abs =
|
|
789
|
-
return
|
|
789
|
+
const abs = path19.isAbsolute(p) ? p : path19.resolve(root, p);
|
|
790
|
+
return path19.relative(root, abs).split(path19.sep).join("/");
|
|
790
791
|
}
|
|
791
792
|
function bump(map, file, line, hits) {
|
|
792
793
|
let lh = map.get(file);
|
|
@@ -1093,7 +1094,7 @@ async function parseInline(files, options) {
|
|
|
1093
1094
|
onProgress?.(0, files.length);
|
|
1094
1095
|
for (const file of files) {
|
|
1095
1096
|
try {
|
|
1096
|
-
const source =
|
|
1097
|
+
const source = fs18.readFileSync(file.abs, "utf8");
|
|
1097
1098
|
out.push(await parseSource(file.rel, file.lang.id, source));
|
|
1098
1099
|
} catch (err) {
|
|
1099
1100
|
out.push(emptyParse(file, `parse failed: ${err.message}`));
|
|
@@ -1148,9 +1149,9 @@ function isWorkerOom(err) {
|
|
|
1148
1149
|
return e?.code === "ERR_WORKER_OUT_OF_MEMORY" || /out of memory/i.test(e?.message ?? "");
|
|
1149
1150
|
}
|
|
1150
1151
|
function resolveWorkerFile() {
|
|
1151
|
-
const here =
|
|
1152
|
-
const candidate =
|
|
1153
|
-
return
|
|
1152
|
+
const here = path19.dirname(fileURLToPath(import.meta.url));
|
|
1153
|
+
const candidate = path19.join(here, "parse-worker.js");
|
|
1154
|
+
return fs18.existsSync(candidate) ? candidate : null;
|
|
1154
1155
|
}
|
|
1155
1156
|
function chunk(items, buckets) {
|
|
1156
1157
|
const out = Array.from({ length: Math.min(buckets, items.length || 1) }, () => []);
|
|
@@ -1399,7 +1400,7 @@ function enclosing3(nodes, line) {
|
|
|
1399
1400
|
return best;
|
|
1400
1401
|
}
|
|
1401
1402
|
function normalize2(p) {
|
|
1402
|
-
return
|
|
1403
|
+
return path19.resolve(p).split(path19.sep).join("/");
|
|
1403
1404
|
}
|
|
1404
1405
|
|
|
1405
1406
|
// src/engine/epistemic.ts
|
|
@@ -1642,14 +1643,14 @@ var IMPORTANCE = {
|
|
|
1642
1643
|
"other-config": 0.08
|
|
1643
1644
|
};
|
|
1644
1645
|
function toPosix2(p) {
|
|
1645
|
-
return p.split(
|
|
1646
|
+
return p.split(path19.sep).join("/");
|
|
1646
1647
|
}
|
|
1647
1648
|
function buildRootIgnore2(root, exclude) {
|
|
1648
1649
|
const ig = ignore();
|
|
1649
|
-
const gitignorePath =
|
|
1650
|
-
if (
|
|
1650
|
+
const gitignorePath = path19.join(root, ".gitignore");
|
|
1651
|
+
if (fs18.existsSync(gitignorePath)) {
|
|
1651
1652
|
try {
|
|
1652
|
-
ig.add(
|
|
1653
|
+
ig.add(fs18.readFileSync(gitignorePath, "utf8"));
|
|
1653
1654
|
} catch {
|
|
1654
1655
|
}
|
|
1655
1656
|
}
|
|
@@ -1658,7 +1659,7 @@ function buildRootIgnore2(root, exclude) {
|
|
|
1658
1659
|
}
|
|
1659
1660
|
function classifyProjectContext(relOrName) {
|
|
1660
1661
|
const rel2 = relOrName.replace(/\\/g, "/");
|
|
1661
|
-
const base =
|
|
1662
|
+
const base = path19.basename(rel2);
|
|
1662
1663
|
const baseLower = base.toLowerCase();
|
|
1663
1664
|
if (/^\.env($|\.)/i.test(base) && !isEnvExampleName(baseLower)) return null;
|
|
1664
1665
|
if (SKIP_FILES.has(baseLower)) return null;
|
|
@@ -1671,7 +1672,7 @@ function classifyProjectContext(relOrName) {
|
|
|
1671
1672
|
for (const { re, category } of PATH_PATTERNS) {
|
|
1672
1673
|
if (re.test(rel2)) return category;
|
|
1673
1674
|
}
|
|
1674
|
-
const ext =
|
|
1675
|
+
const ext = path19.extname(baseLower);
|
|
1675
1676
|
if (DOC_EXTENSIONS.has(ext)) return ext === ".txt" ? "text" : "markdown";
|
|
1676
1677
|
if (API_EXTENSIONS.has(ext)) return "api-contract";
|
|
1677
1678
|
if ((ext === ".yaml" || ext === ".yml" || ext === ".json") && /openapi|swagger|asyncapi/i.test(base)) {
|
|
@@ -1689,24 +1690,24 @@ function isEnvExampleName(baseLower) {
|
|
|
1689
1690
|
return false;
|
|
1690
1691
|
}
|
|
1691
1692
|
function discoverDocs(options) {
|
|
1692
|
-
const root =
|
|
1693
|
+
const root = path19.resolve(options.root);
|
|
1693
1694
|
const maxFiles = options.maxFiles ?? DOC_MAX_FILES;
|
|
1694
1695
|
const rootIg = buildRootIgnore2(root, options.exclude ?? []);
|
|
1695
|
-
const scopeAbs = (options.paths?.length ? options.paths.map((p) =>
|
|
1696
|
-
(p) =>
|
|
1696
|
+
const scopeAbs = (options.paths?.length ? options.paths.map((p) => path19.resolve(root, p)) : [root]).filter(
|
|
1697
|
+
(p) => fs18.existsSync(p)
|
|
1697
1698
|
);
|
|
1698
1699
|
const found = /* @__PURE__ */ new Map();
|
|
1699
1700
|
const consider = (abs) => {
|
|
1700
1701
|
if (found.size >= maxFiles) return;
|
|
1701
|
-
const rel2 = toPosix2(
|
|
1702
|
+
const rel2 = toPosix2(path19.relative(root, abs));
|
|
1702
1703
|
if (!rel2 || rel2.startsWith("..")) return;
|
|
1703
1704
|
if (rootIg.ignores(rel2)) return;
|
|
1704
|
-
const base =
|
|
1705
|
+
const base = path19.basename(abs);
|
|
1705
1706
|
if (SKIP_FILES.has(base.toLowerCase())) return;
|
|
1706
1707
|
const category = classifyProjectContext(rel2);
|
|
1707
1708
|
if (!category) return;
|
|
1708
1709
|
try {
|
|
1709
|
-
const st =
|
|
1710
|
+
const st = fs18.statSync(abs);
|
|
1710
1711
|
if (!st.isFile() || st.size > DOC_FILE_MAX_BYTES) return;
|
|
1711
1712
|
if (st.size === 0) return;
|
|
1712
1713
|
} catch {
|
|
@@ -1718,14 +1719,14 @@ function discoverDocs(options) {
|
|
|
1718
1719
|
if (found.size >= maxFiles || depth > 12) return;
|
|
1719
1720
|
let entries;
|
|
1720
1721
|
try {
|
|
1721
|
-
entries =
|
|
1722
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
1722
1723
|
} catch {
|
|
1723
1724
|
return;
|
|
1724
1725
|
}
|
|
1725
1726
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
1726
1727
|
if (found.size >= maxFiles) return;
|
|
1727
|
-
const abs =
|
|
1728
|
-
const rel2 = toPosix2(
|
|
1728
|
+
const abs = path19.join(dir, entry.name);
|
|
1729
|
+
const rel2 = toPosix2(path19.relative(root, abs));
|
|
1729
1730
|
if (entry.isDirectory()) {
|
|
1730
1731
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
1731
1732
|
if (rel2 && rootIg.ignores(`${rel2}/`) && !rel2.startsWith(".github")) continue;
|
|
@@ -1737,7 +1738,7 @@ function discoverDocs(options) {
|
|
|
1737
1738
|
};
|
|
1738
1739
|
for (const scope of scopeAbs) {
|
|
1739
1740
|
try {
|
|
1740
|
-
const st =
|
|
1741
|
+
const st = fs18.statSync(scope);
|
|
1741
1742
|
if (st.isDirectory()) walk(scope, 0);
|
|
1742
1743
|
else if (st.isFile()) consider(scope);
|
|
1743
1744
|
} catch {
|
|
@@ -1748,7 +1749,7 @@ function discoverDocs(options) {
|
|
|
1748
1749
|
function prepareDocBody(rel2, raw, category) {
|
|
1749
1750
|
const scrubbed = redactSecrets(raw);
|
|
1750
1751
|
if (scrubbed.length <= DOC_BODY_MAX_CHARS) return scrubbed;
|
|
1751
|
-
if (category === "manifest" &&
|
|
1752
|
+
if (category === "manifest" && path19.basename(rel2).toLowerCase() === "package.json") {
|
|
1752
1753
|
return summarizePackageJson(scrubbed);
|
|
1753
1754
|
}
|
|
1754
1755
|
if (category === "api-contract" && /\.(ya?ml|json)$/i.test(rel2)) {
|
|
@@ -1794,14 +1795,14 @@ function documentNodesFromDocs(docs) {
|
|
|
1794
1795
|
for (const d of docs) {
|
|
1795
1796
|
let raw = "";
|
|
1796
1797
|
try {
|
|
1797
|
-
raw =
|
|
1798
|
+
raw = fs18.readFileSync(d.abs, "utf8");
|
|
1798
1799
|
} catch {
|
|
1799
1800
|
continue;
|
|
1800
1801
|
}
|
|
1801
1802
|
const category = d.category ?? d.kind;
|
|
1802
1803
|
const scrubbed = prepareDocBody(d.rel, raw, category);
|
|
1803
1804
|
if (!scrubbed.trim()) continue;
|
|
1804
|
-
const name =
|
|
1805
|
+
const name = path19.basename(d.rel);
|
|
1805
1806
|
const qualifiedName = d.rel.replace(/\\/g, "/");
|
|
1806
1807
|
const id = nodeId({
|
|
1807
1808
|
kind: "document",
|
|
@@ -1835,7 +1836,7 @@ function shardTsProjects(root, files) {
|
|
|
1835
1836
|
const cache = /* @__PURE__ */ new Map();
|
|
1836
1837
|
const byKey = /* @__PURE__ */ new Map();
|
|
1837
1838
|
for (const f of files) {
|
|
1838
|
-
const dir =
|
|
1839
|
+
const dir = path19.dirname(f.abs);
|
|
1839
1840
|
const key = nearestProjectKey(root, dir, cache);
|
|
1840
1841
|
const list = byKey.get(key);
|
|
1841
1842
|
if (list) list.push(f);
|
|
@@ -1850,22 +1851,22 @@ function nearestProjectKey(root, startDir, cache) {
|
|
|
1850
1851
|
const hit = cache.get(startDir);
|
|
1851
1852
|
if (hit !== void 0) return hit;
|
|
1852
1853
|
let dir = startDir;
|
|
1853
|
-
const rootAbs =
|
|
1854
|
+
const rootAbs = path19.resolve(root);
|
|
1854
1855
|
while (true) {
|
|
1855
|
-
if (
|
|
1856
|
-
const key = toPosix3(
|
|
1856
|
+
if (fs18.existsSync(path19.join(dir, "tsconfig.json")) || fs18.existsSync(path19.join(dir, "tsconfig.base.json")) || fs18.existsSync(path19.join(dir, "package.json"))) {
|
|
1857
|
+
const key = toPosix3(path19.relative(rootAbs, dir)) || ".";
|
|
1857
1858
|
cache.set(startDir, key);
|
|
1858
1859
|
return key;
|
|
1859
1860
|
}
|
|
1860
|
-
if (dir === rootAbs ||
|
|
1861
|
+
if (dir === rootAbs || path19.dirname(dir) === dir) {
|
|
1861
1862
|
cache.set(startDir, ".");
|
|
1862
1863
|
return ".";
|
|
1863
1864
|
}
|
|
1864
|
-
dir =
|
|
1865
|
+
dir = path19.dirname(dir);
|
|
1865
1866
|
}
|
|
1866
1867
|
}
|
|
1867
1868
|
function toPosix3(p) {
|
|
1868
|
-
return p.split(
|
|
1869
|
+
return p.split(path19.sep).join("/");
|
|
1869
1870
|
}
|
|
1870
1871
|
|
|
1871
1872
|
// src/engine/timing.ts
|
|
@@ -1900,11 +1901,284 @@ function nowMs() {
|
|
|
1900
1901
|
return Number(process.hrtime.bigint() / 1000n) / 1e3;
|
|
1901
1902
|
}
|
|
1902
1903
|
|
|
1904
|
+
// src/engine/summaries.ts
|
|
1905
|
+
var DEPEND_EDGES = /* @__PURE__ */ new Set(["call", "import", "extends", "implements", "references"]);
|
|
1906
|
+
var HUB_LIMIT = 40;
|
|
1907
|
+
function buildSummaries(graph) {
|
|
1908
|
+
const index = indexFor(graph);
|
|
1909
|
+
const candidates = graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external" && n.kind !== "document").sort((a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName)).slice(0, HUB_LIMIT);
|
|
1910
|
+
const hubs = candidates.map((n) => {
|
|
1911
|
+
const d1 = reverseDependents(index, n.id, 1);
|
|
1912
|
+
const d2 = reverseDependents(index, n.id, 2);
|
|
1913
|
+
const files = /* @__PURE__ */ new Set();
|
|
1914
|
+
for (const id of d2) {
|
|
1915
|
+
const node = index.node(id);
|
|
1916
|
+
if (node?.file) files.add(node.file);
|
|
1917
|
+
}
|
|
1918
|
+
return {
|
|
1919
|
+
id: n.id,
|
|
1920
|
+
name: n.qualifiedName,
|
|
1921
|
+
kind: n.kind,
|
|
1922
|
+
file: n.file,
|
|
1923
|
+
importance: n.importance,
|
|
1924
|
+
direct: d1.size,
|
|
1925
|
+
depth2: d2.size,
|
|
1926
|
+
files: files.size,
|
|
1927
|
+
tested: n.tested
|
|
1928
|
+
};
|
|
1929
|
+
});
|
|
1930
|
+
hubs.sort((a, b) => b.importance - a.importance || a.name.localeCompare(b.name));
|
|
1931
|
+
return { hubs };
|
|
1932
|
+
}
|
|
1933
|
+
function reverseDependents(index, rootId, maxDepth) {
|
|
1934
|
+
const affected = /* @__PURE__ */ new Set();
|
|
1935
|
+
let frontier = [rootId];
|
|
1936
|
+
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
1937
|
+
const next = [];
|
|
1938
|
+
for (const id of frontier) {
|
|
1939
|
+
for (const e of index.in(id)) {
|
|
1940
|
+
if (!DEPEND_EDGES.has(e.kind)) continue;
|
|
1941
|
+
if (e.src === rootId || affected.has(e.src)) continue;
|
|
1942
|
+
affected.add(e.src);
|
|
1943
|
+
next.push(e.src);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
frontier = next;
|
|
1947
|
+
if (frontier.length === 0) break;
|
|
1948
|
+
}
|
|
1949
|
+
return affected;
|
|
1950
|
+
}
|
|
1951
|
+
var emptyNode = (partial) => ({
|
|
1952
|
+
...partial,
|
|
1953
|
+
span: partial.span ?? { start: 1, end: 1 },
|
|
1954
|
+
importance: 0,
|
|
1955
|
+
centrality: { degree: 0, pagerank: 0, betweenness: 0, eigenvector: 0 },
|
|
1956
|
+
area: -1,
|
|
1957
|
+
isHub: false,
|
|
1958
|
+
tested: null
|
|
1959
|
+
});
|
|
1960
|
+
function extractManifests(root, opts = {}) {
|
|
1961
|
+
const absRoot = path19.resolve(root);
|
|
1962
|
+
const ig = buildRootIgnore3(absRoot, opts.exclude ?? []);
|
|
1963
|
+
const scopes = (opts.paths?.length ? opts.paths : ["."]).map((p) => path19.resolve(absRoot, p)).filter((p) => fs18.existsSync(p));
|
|
1964
|
+
const found = /* @__PURE__ */ new Map();
|
|
1965
|
+
for (const scope of scopes) {
|
|
1966
|
+
walkManifests(absRoot, scope, ig, found);
|
|
1967
|
+
}
|
|
1968
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
1969
|
+
const edges = /* @__PURE__ */ new Map();
|
|
1970
|
+
let deps = 0;
|
|
1971
|
+
for (const rel2 of [...found.keys()].sort()) {
|
|
1972
|
+
const abs = found.get(rel2);
|
|
1973
|
+
const base = path19.posix.basename(rel2);
|
|
1974
|
+
try {
|
|
1975
|
+
if (base === "package.json") {
|
|
1976
|
+
deps += ingestPackageJson(rel2, abs, nodes, edges);
|
|
1977
|
+
} else if (base === "go.mod") {
|
|
1978
|
+
deps += ingestGoMod(rel2, abs, nodes, edges);
|
|
1979
|
+
}
|
|
1980
|
+
} catch {
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
return {
|
|
1984
|
+
nodes: [...nodes.values()].sort((a, b) => a.id.localeCompare(b.id)),
|
|
1985
|
+
edges: [...edges.values()].sort(
|
|
1986
|
+
(a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
|
|
1987
|
+
),
|
|
1988
|
+
files: found.size,
|
|
1989
|
+
deps
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
function ingestPackageJson(rel2, abs, nodes, edges) {
|
|
1993
|
+
const raw = JSON.parse(fs18.readFileSync(abs, "utf8"));
|
|
1994
|
+
const pkgName = raw.name && String(raw.name).trim() || path19.posix.dirname(rel2) || ".";
|
|
1995
|
+
const localId = nodeId({ kind: "package", qualifiedName: pkgName, file: rel2 });
|
|
1996
|
+
nodes.set(
|
|
1997
|
+
localId,
|
|
1998
|
+
emptyNode({
|
|
1999
|
+
id: localId,
|
|
2000
|
+
kind: "package",
|
|
2001
|
+
name: pkgName.includes("/") ? pkgName.split("/").pop() : pkgName,
|
|
2002
|
+
qualifiedName: pkgName,
|
|
2003
|
+
file: rel2,
|
|
2004
|
+
lang: "json"
|
|
2005
|
+
})
|
|
2006
|
+
);
|
|
2007
|
+
const fileId = nodeId({ kind: "file", qualifiedName: rel2, file: rel2 });
|
|
2008
|
+
nodes.set(
|
|
2009
|
+
fileId,
|
|
2010
|
+
emptyNode({
|
|
2011
|
+
id: fileId,
|
|
2012
|
+
kind: "file",
|
|
2013
|
+
name: path19.posix.basename(rel2),
|
|
2014
|
+
qualifiedName: rel2,
|
|
2015
|
+
file: rel2,
|
|
2016
|
+
lang: "json"
|
|
2017
|
+
})
|
|
2018
|
+
);
|
|
2019
|
+
addEdge(edges, "contains", fileId, localId, 1);
|
|
2020
|
+
let n = 0;
|
|
2021
|
+
const depMaps = [raw.dependencies, raw.peerDependencies, raw.optionalDependencies];
|
|
2022
|
+
const names = /* @__PURE__ */ new Set();
|
|
2023
|
+
for (const m of depMaps) {
|
|
2024
|
+
if (!m || typeof m !== "object") continue;
|
|
2025
|
+
for (const name of Object.keys(m)) {
|
|
2026
|
+
if (name) names.add(name);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
for (const name of [...names].sort()) {
|
|
2030
|
+
const extId = ensureExternal(nodes, name);
|
|
2031
|
+
addEdge(edges, "import", localId, extId, 1);
|
|
2032
|
+
n++;
|
|
2033
|
+
}
|
|
2034
|
+
return n;
|
|
2035
|
+
}
|
|
2036
|
+
function ingestGoMod(rel2, abs, nodes, edges) {
|
|
2037
|
+
const text = fs18.readFileSync(abs, "utf8");
|
|
2038
|
+
let moduleName = path19.posix.dirname(rel2) || ".";
|
|
2039
|
+
const moduleMatch = /^\s*module\s+(\S+)/m.exec(text);
|
|
2040
|
+
if (moduleMatch) moduleName = moduleMatch[1];
|
|
2041
|
+
const localId = nodeId({ kind: "package", qualifiedName: moduleName, file: rel2 });
|
|
2042
|
+
nodes.set(
|
|
2043
|
+
localId,
|
|
2044
|
+
emptyNode({
|
|
2045
|
+
id: localId,
|
|
2046
|
+
kind: "package",
|
|
2047
|
+
name: moduleName.split("/").pop() ?? moduleName,
|
|
2048
|
+
qualifiedName: moduleName,
|
|
2049
|
+
file: rel2,
|
|
2050
|
+
lang: "go"
|
|
2051
|
+
})
|
|
2052
|
+
);
|
|
2053
|
+
const fileId = nodeId({ kind: "file", qualifiedName: rel2, file: rel2 });
|
|
2054
|
+
nodes.set(
|
|
2055
|
+
fileId,
|
|
2056
|
+
emptyNode({
|
|
2057
|
+
id: fileId,
|
|
2058
|
+
kind: "file",
|
|
2059
|
+
name: path19.posix.basename(rel2),
|
|
2060
|
+
qualifiedName: rel2,
|
|
2061
|
+
file: rel2,
|
|
2062
|
+
lang: "go"
|
|
2063
|
+
})
|
|
2064
|
+
);
|
|
2065
|
+
addEdge(edges, "contains", fileId, localId, 1);
|
|
2066
|
+
const reqNames = /* @__PURE__ */ new Set();
|
|
2067
|
+
const block = /require\s*\(([\s\S]*?)\)/g;
|
|
2068
|
+
let bm;
|
|
2069
|
+
while ((bm = block.exec(text)) !== null) {
|
|
2070
|
+
for (const line of bm[1].split("\n")) {
|
|
2071
|
+
const m = /^\s*(\S+)\s+v\S+/.exec(line);
|
|
2072
|
+
if (m && !line.trim().startsWith("//")) reqNames.add(m[1]);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
const single = /^\s*require\s+(\S+)\s+v\S+/gm;
|
|
2076
|
+
let sm;
|
|
2077
|
+
while ((sm = single.exec(text)) !== null) reqNames.add(sm[1]);
|
|
2078
|
+
let n = 0;
|
|
2079
|
+
for (const name of [...reqNames].sort()) {
|
|
2080
|
+
const extId = ensureExternal(nodes, name);
|
|
2081
|
+
addEdge(edges, "import", localId, extId, 1);
|
|
2082
|
+
n++;
|
|
2083
|
+
}
|
|
2084
|
+
return n;
|
|
2085
|
+
}
|
|
2086
|
+
function ensureExternal(nodes, name) {
|
|
2087
|
+
const id = nodeId({ kind: "external", qualifiedName: name, file: "" });
|
|
2088
|
+
if (!nodes.has(id)) {
|
|
2089
|
+
nodes.set(
|
|
2090
|
+
id,
|
|
2091
|
+
emptyNode({
|
|
2092
|
+
id,
|
|
2093
|
+
kind: "external",
|
|
2094
|
+
name,
|
|
2095
|
+
qualifiedName: name,
|
|
2096
|
+
file: "",
|
|
2097
|
+
lang: "external"
|
|
2098
|
+
})
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
return id;
|
|
2102
|
+
}
|
|
2103
|
+
function addEdge(edges, kind, src, dst, confidence) {
|
|
2104
|
+
if (src === dst) return;
|
|
2105
|
+
const id = edgeId(kind, src, dst);
|
|
2106
|
+
if (edges.has(id)) return;
|
|
2107
|
+
edges.set(id, {
|
|
2108
|
+
id,
|
|
2109
|
+
kind,
|
|
2110
|
+
src,
|
|
2111
|
+
dst,
|
|
2112
|
+
resolution: "heuristic",
|
|
2113
|
+
confidence,
|
|
2114
|
+
epistemic: "declared",
|
|
2115
|
+
count: 1
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
function buildRootIgnore3(root, exclude) {
|
|
2119
|
+
const ig = ignore();
|
|
2120
|
+
const gitignorePath = path19.join(root, ".gitignore");
|
|
2121
|
+
if (fs18.existsSync(gitignorePath)) {
|
|
2122
|
+
try {
|
|
2123
|
+
ig.add(fs18.readFileSync(gitignorePath, "utf8"));
|
|
2124
|
+
} catch {
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
if (exclude.length) ig.add(exclude);
|
|
2128
|
+
return ig;
|
|
2129
|
+
}
|
|
2130
|
+
function walkManifests(root, dir, ig, found) {
|
|
2131
|
+
let entries;
|
|
2132
|
+
try {
|
|
2133
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
2134
|
+
} catch {
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
for (const entry of entries) {
|
|
2138
|
+
const abs = path19.join(dir, entry.name);
|
|
2139
|
+
const rel2 = path19.relative(root, abs).split(path19.sep).join("/");
|
|
2140
|
+
if (entry.isDirectory()) {
|
|
2141
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
2142
|
+
if (rel2 && ig.ignores(`${rel2}/`)) continue;
|
|
2143
|
+
walkManifests(root, abs, ig, found);
|
|
2144
|
+
} else if (entry.isFile()) {
|
|
2145
|
+
const base = entry.name;
|
|
2146
|
+
if (base !== "package.json" && base !== "go.mod") continue;
|
|
2147
|
+
if (rel2 && ig.ignores(rel2)) continue;
|
|
2148
|
+
found.set(rel2, abs);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
async function hashFilesParallel(jobs, concurrency) {
|
|
2153
|
+
if (jobs.length === 0) return [];
|
|
2154
|
+
const limit = Math.max(
|
|
2155
|
+
1,
|
|
2156
|
+
Math.min(concurrency ?? Math.max(1, (os.cpus()?.length ?? 4) * 2), jobs.length)
|
|
2157
|
+
);
|
|
2158
|
+
const out = new Array(jobs.length);
|
|
2159
|
+
let next = 0;
|
|
2160
|
+
async function worker() {
|
|
2161
|
+
for (; ; ) {
|
|
2162
|
+
const i = next++;
|
|
2163
|
+
if (i >= jobs.length) return;
|
|
2164
|
+
const job = jobs[i];
|
|
2165
|
+
try {
|
|
2166
|
+
const buf = await fs8.readFile(job.abs);
|
|
2167
|
+
out[i] = { rel: job.rel, hash: hashBytes(buf), ok: true };
|
|
2168
|
+
} catch {
|
|
2169
|
+
out[i] = { rel: job.rel, hash: "", ok: false };
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
2174
|
+
return out;
|
|
2175
|
+
}
|
|
2176
|
+
|
|
1903
2177
|
// src/engine/build.ts
|
|
1904
2178
|
async function buildGraph(options) {
|
|
1905
2179
|
const timer = new StageTimer();
|
|
1906
2180
|
timer.start("total");
|
|
1907
|
-
const root =
|
|
2181
|
+
const root = path19.resolve(options.root);
|
|
1908
2182
|
timer.start("discover");
|
|
1909
2183
|
const files = discover({
|
|
1910
2184
|
root,
|
|
@@ -1933,10 +2207,11 @@ async function buildGraph(options) {
|
|
|
1933
2207
|
const reused = [];
|
|
1934
2208
|
const buildWarnings = [];
|
|
1935
2209
|
let statHits = 0;
|
|
2210
|
+
const pendingHash = [];
|
|
1936
2211
|
for (const file of files) {
|
|
1937
2212
|
let stat;
|
|
1938
2213
|
try {
|
|
1939
|
-
stat =
|
|
2214
|
+
stat = fs18.statSync(file.abs);
|
|
1940
2215
|
} catch {
|
|
1941
2216
|
continue;
|
|
1942
2217
|
}
|
|
@@ -1966,20 +2241,29 @@ async function buildGraph(options) {
|
|
|
1966
2241
|
statHits++;
|
|
1967
2242
|
continue;
|
|
1968
2243
|
}
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
2244
|
+
pendingHash.push({ file, size: stat.size, mtimeMs: stat.mtimeMs });
|
|
2245
|
+
}
|
|
2246
|
+
if (pendingHash.length) {
|
|
2247
|
+
const jobs = pendingHash.map((p) => ({ rel: p.file.rel, abs: p.file.abs }));
|
|
2248
|
+
const results = await hashFilesParallel(jobs, options.jobs);
|
|
2249
|
+
const byRel = new Map(results.map((r) => [r.rel, r]));
|
|
2250
|
+
for (const p of pendingHash) {
|
|
2251
|
+
const r = byRel.get(p.file.rel);
|
|
2252
|
+
if (!r || !r.ok) continue;
|
|
2253
|
+
hashes.set(p.file.rel, r.hash);
|
|
2254
|
+
fileStats.push({
|
|
2255
|
+
rel: p.file.rel,
|
|
2256
|
+
size: p.size,
|
|
2257
|
+
mtimeMs: p.mtimeMs,
|
|
2258
|
+
hash: r.hash
|
|
2259
|
+
});
|
|
2260
|
+
const cached2 = cache.get(p.file.rel, r.hash);
|
|
2261
|
+
if (cached2) {
|
|
2262
|
+
reused.push(cached2);
|
|
2263
|
+
cache.set(p.file.rel, cached2, { mtimeMs: p.mtimeMs, size: p.size });
|
|
2264
|
+
} else {
|
|
2265
|
+
toParse.push(p.file);
|
|
2266
|
+
}
|
|
1983
2267
|
}
|
|
1984
2268
|
}
|
|
1985
2269
|
timer.end("hash");
|
|
@@ -2009,6 +2293,30 @@ async function buildGraph(options) {
|
|
|
2009
2293
|
const resolved = resolve(parses, moduleResolver);
|
|
2010
2294
|
timer.end("resolve");
|
|
2011
2295
|
checkMemoryBudget("resolve", limits.memoryBudgetMb);
|
|
2296
|
+
const manifests = extractManifests(root, {
|
|
2297
|
+
exclude: options.exclude,
|
|
2298
|
+
paths: options.paths
|
|
2299
|
+
});
|
|
2300
|
+
if (manifests.files > 0) {
|
|
2301
|
+
const byId = new Map(resolved.nodes.map((n) => [n.id, n]));
|
|
2302
|
+
for (const n of manifests.nodes) {
|
|
2303
|
+
if (!byId.has(n.id)) {
|
|
2304
|
+
byId.set(n.id, n);
|
|
2305
|
+
resolved.nodes.push(n);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
const edgeById = new Map(resolved.edges.map((e) => [e.id, e]));
|
|
2309
|
+
for (const e of manifests.edges) {
|
|
2310
|
+
if (!edgeById.has(e.id)) {
|
|
2311
|
+
edgeById.set(e.id, e);
|
|
2312
|
+
resolved.edges.push(e);
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
resolved.nodes.sort((a, b) => a.id.localeCompare(b.id));
|
|
2316
|
+
resolved.edges.sort(
|
|
2317
|
+
(a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
|
|
2318
|
+
);
|
|
2319
|
+
}
|
|
2012
2320
|
const nodeFileById = new Map(resolved.nodes.map((n) => [n.id, n.file]));
|
|
2013
2321
|
let edges = resolved.edges;
|
|
2014
2322
|
const resolvers = [...resolved.stats.resolvers];
|
|
@@ -2079,8 +2387,8 @@ async function buildGraph(options) {
|
|
|
2079
2387
|
});
|
|
2080
2388
|
for (const d of docs) {
|
|
2081
2389
|
try {
|
|
2082
|
-
const st =
|
|
2083
|
-
const hash = hashBytes(
|
|
2390
|
+
const st = fs18.statSync(d.abs);
|
|
2391
|
+
const hash = hashBytes(fs18.readFileSync(d.abs));
|
|
2084
2392
|
hashes.set(d.rel, hash);
|
|
2085
2393
|
fileStats.push({ rel: d.rel, size: st.size, mtimeMs: st.mtimeMs, hash });
|
|
2086
2394
|
} catch {
|
|
@@ -2121,7 +2429,7 @@ async function buildGraph(options) {
|
|
|
2121
2429
|
toolchain
|
|
2122
2430
|
},
|
|
2123
2431
|
meta: {
|
|
2124
|
-
root:
|
|
2432
|
+
root: path19.basename(root) === "" ? "." : ".",
|
|
2125
2433
|
languages,
|
|
2126
2434
|
analysisTier: analysis.tier,
|
|
2127
2435
|
counts: {
|
|
@@ -2141,7 +2449,8 @@ async function buildGraph(options) {
|
|
|
2141
2449
|
const survivingIds = new Set(analysis.nodes.map((n) => n.id));
|
|
2142
2450
|
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 }));
|
|
2143
2451
|
if (unknowns.length) graph.unknowns = unknowns;
|
|
2144
|
-
|
|
2452
|
+
graph.summaries = buildSummaries(graph);
|
|
2453
|
+
{
|
|
2145
2454
|
const facts = buildFacts(parses, analysis.nodes, analysis.edges);
|
|
2146
2455
|
if (facts.length) graph.facts = facts;
|
|
2147
2456
|
}
|
|
@@ -2179,14 +2488,14 @@ function toRepoRel(p) {
|
|
|
2179
2488
|
function loadScipIndex(root, explicit) {
|
|
2180
2489
|
const candidates = [
|
|
2181
2490
|
explicit,
|
|
2182
|
-
|
|
2183
|
-
|
|
2491
|
+
path19.join(root, "index.scip"),
|
|
2492
|
+
path19.join(root, ".vibgrate", "index.scip")
|
|
2184
2493
|
].filter((p) => Boolean(p));
|
|
2185
2494
|
for (const file of candidates) {
|
|
2186
|
-
const abs =
|
|
2187
|
-
if (!
|
|
2495
|
+
const abs = path19.isAbsolute(file) ? file : path19.resolve(root, file);
|
|
2496
|
+
if (!fs18.existsSync(abs)) continue;
|
|
2188
2497
|
try {
|
|
2189
|
-
const index = decodeScipIndex(new Uint8Array(
|
|
2498
|
+
const index = decodeScipIndex(new Uint8Array(fs18.readFileSync(abs)));
|
|
2190
2499
|
if (index.documents.length) {
|
|
2191
2500
|
return { index, tool: index.toolVersion ? `${index.toolName} ${index.toolVersion}` : index.toolName };
|
|
2192
2501
|
}
|
|
@@ -2301,21 +2610,21 @@ function usageError(message) {
|
|
|
2301
2610
|
}
|
|
2302
2611
|
var SNAPSHOT_VERSION = "vg-freshness/1";
|
|
2303
2612
|
function snapshotPath(root) {
|
|
2304
|
-
return
|
|
2613
|
+
return path19.join(cacheDir(root), "freshness.json");
|
|
2305
2614
|
}
|
|
2306
2615
|
function writeSnapshot(root, corpusHash, fileStats, scope = {}) {
|
|
2307
2616
|
const files = {};
|
|
2308
2617
|
for (const f of fileStats) files[f.rel] = { size: f.size, mtimeMs: f.mtimeMs, hash: f.hash };
|
|
2309
2618
|
const snapshot = { version: SNAPSHOT_VERSION, corpusHash, scope: pruneScope(scope), files };
|
|
2310
2619
|
try {
|
|
2311
|
-
|
|
2312
|
-
|
|
2620
|
+
fs18.mkdirSync(cacheDir(root), { recursive: true });
|
|
2621
|
+
fs18.writeFileSync(snapshotPath(root), stableStringify(snapshot, 0));
|
|
2313
2622
|
} catch {
|
|
2314
2623
|
}
|
|
2315
2624
|
}
|
|
2316
2625
|
function loadSnapshot(root) {
|
|
2317
2626
|
try {
|
|
2318
|
-
const loaded = JSON.parse(
|
|
2627
|
+
const loaded = JSON.parse(fs18.readFileSync(snapshotPath(root), "utf8"));
|
|
2319
2628
|
if (loaded.version === SNAPSHOT_VERSION && loaded.files && typeof loaded.corpusHash === "string") {
|
|
2320
2629
|
return { ...loaded, scope: loaded.scope ?? {} };
|
|
2321
2630
|
}
|
|
@@ -2335,7 +2644,14 @@ function probeFreshness(root) {
|
|
|
2335
2644
|
const { scope } = snapshot;
|
|
2336
2645
|
let discovered;
|
|
2337
2646
|
try {
|
|
2338
|
-
|
|
2647
|
+
const code = discover({ root, only: scope.only, exclude: scope.exclude, paths: scope.paths });
|
|
2648
|
+
const docs = discoverDocs({ root, exclude: scope.exclude, paths: scope.paths });
|
|
2649
|
+
const byRel = /* @__PURE__ */ new Map();
|
|
2650
|
+
for (const f of code) byRel.set(f.rel, f.abs);
|
|
2651
|
+
for (const d of docs) {
|
|
2652
|
+
if (!byRel.has(d.rel)) byRel.set(d.rel, d.abs);
|
|
2653
|
+
}
|
|
2654
|
+
discovered = [...byRel.entries()].map(([rel2, abs]) => ({ rel: rel2, abs })).sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
|
|
2339
2655
|
} catch {
|
|
2340
2656
|
return null;
|
|
2341
2657
|
}
|
|
@@ -2351,15 +2667,25 @@ function probeFreshness(root) {
|
|
|
2351
2667
|
}
|
|
2352
2668
|
let stat;
|
|
2353
2669
|
try {
|
|
2354
|
-
stat =
|
|
2670
|
+
stat = fs18.statSync(file.abs);
|
|
2355
2671
|
} catch {
|
|
2356
2672
|
drift.removed.push(file.rel);
|
|
2357
2673
|
continue;
|
|
2358
2674
|
}
|
|
2359
2675
|
if (stat.size === entry.size && stat.mtimeMs === entry.mtimeMs) continue;
|
|
2676
|
+
if (entry.hash.startsWith("vg:oversize:")) {
|
|
2677
|
+
const expected = `vg:oversize:${stat.size}`;
|
|
2678
|
+
if (entry.hash === expected) {
|
|
2679
|
+
snapshot.files[file.rel] = { size: stat.size, mtimeMs: stat.mtimeMs, hash: entry.hash };
|
|
2680
|
+
absorbed = true;
|
|
2681
|
+
} else {
|
|
2682
|
+
drift.changed.push(file.rel);
|
|
2683
|
+
}
|
|
2684
|
+
continue;
|
|
2685
|
+
}
|
|
2360
2686
|
let hash = "";
|
|
2361
2687
|
try {
|
|
2362
|
-
hash = hashBytes(
|
|
2688
|
+
hash = hashBytes(fs18.readFileSync(file.abs));
|
|
2363
2689
|
} catch {
|
|
2364
2690
|
drift.removed.push(file.rel);
|
|
2365
2691
|
continue;
|
|
@@ -2376,7 +2702,7 @@ function probeFreshness(root) {
|
|
|
2376
2702
|
}
|
|
2377
2703
|
if (absorbed && !hasDrift(drift)) {
|
|
2378
2704
|
try {
|
|
2379
|
-
|
|
2705
|
+
fs18.writeFileSync(snapshotPath(root), stableStringify(snapshot, 0));
|
|
2380
2706
|
} catch {
|
|
2381
2707
|
}
|
|
2382
2708
|
}
|
|
@@ -2422,6 +2748,30 @@ function shortestPath(graph, srcId, dstId) {
|
|
|
2422
2748
|
if (reverse) return { ids: reverse.slice().reverse(), direction: "reverse" };
|
|
2423
2749
|
return null;
|
|
2424
2750
|
}
|
|
2751
|
+
var NEIGHBOR_CAP = 6;
|
|
2752
|
+
function pathDisconnect(graph, srcId, dstId) {
|
|
2753
|
+
const idx = indexFor(graph);
|
|
2754
|
+
const from = neighborhood(idx, srcId);
|
|
2755
|
+
const to = neighborhood(idx, dstId);
|
|
2756
|
+
const hint = from.calls.length || from.calledBy.length || to.calls.length || to.calledBy.length ? "No direct call/import chain links these symbols. Try `vg show` / `vg impact` on each end, or path via a shared hub." : "Neither endpoint has call/import neighbors in the map \u2014 they may be isolated docs/externals, or the link needs a more precise build.";
|
|
2757
|
+
return { connected: false, from, to, hint };
|
|
2758
|
+
}
|
|
2759
|
+
function neighborhood(idx, id) {
|
|
2760
|
+
const node = idx.node(id);
|
|
2761
|
+
const name = node?.qualifiedName ?? id;
|
|
2762
|
+
const calls = uniqueNames(idx.callees(id).map((x) => x.node.qualifiedName));
|
|
2763
|
+
const calledBy = uniqueNames(idx.callers(id).map((x) => x.node.qualifiedName));
|
|
2764
|
+
const imports = uniqueNames(
|
|
2765
|
+
idx.out(id, "import").map((e) => idx.node(e.dst)?.qualifiedName).filter((n) => !!n)
|
|
2766
|
+
);
|
|
2767
|
+
const importedBy = uniqueNames(
|
|
2768
|
+
idx.in(id, "import").map((e) => idx.node(e.src)?.qualifiedName).filter((n) => !!n)
|
|
2769
|
+
);
|
|
2770
|
+
return { name, calls, calledBy, imports, importedBy };
|
|
2771
|
+
}
|
|
2772
|
+
function uniqueNames(names) {
|
|
2773
|
+
return [...new Set(names)].sort((a, b) => a.localeCompare(b)).slice(0, NEIGHBOR_CAP);
|
|
2774
|
+
}
|
|
2425
2775
|
function coveringTests(graph, node, index) {
|
|
2426
2776
|
const idx = index ?? indexFor(graph);
|
|
2427
2777
|
const byId = idx.nodeById;
|
|
@@ -2457,10 +2807,10 @@ function testsToRun(graph, rootId, depth = 4) {
|
|
|
2457
2807
|
};
|
|
2458
2808
|
}
|
|
2459
2809
|
function detectRunner(root, lang) {
|
|
2460
|
-
const pkgPath =
|
|
2461
|
-
if (
|
|
2810
|
+
const pkgPath = path19.join(root, "package.json");
|
|
2811
|
+
if (fs18.existsSync(pkgPath)) {
|
|
2462
2812
|
try {
|
|
2463
|
-
const pkg = JSON.parse(
|
|
2813
|
+
const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf8"));
|
|
2464
2814
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2465
2815
|
if (deps.vitest) return { name: "vitest", command: (f) => `npx vitest run ${f.join(" ")}`.trim() };
|
|
2466
2816
|
if (deps.jest) return { name: "jest", command: (f) => `npx jest ${f.join(" ")}`.trim() };
|
|
@@ -2468,10 +2818,10 @@ function detectRunner(root, lang) {
|
|
|
2468
2818
|
} catch {
|
|
2469
2819
|
}
|
|
2470
2820
|
}
|
|
2471
|
-
if (lang === "py" ||
|
|
2821
|
+
if (lang === "py" || fs18.existsSync(path19.join(root, "pyproject.toml")) || fs18.existsSync(path19.join(root, "pytest.ini"))) {
|
|
2472
2822
|
return { name: "pytest", command: (f) => `pytest ${f.join(" ")}`.trim() };
|
|
2473
2823
|
}
|
|
2474
|
-
if (lang === "go" ||
|
|
2824
|
+
if (lang === "go" || fs18.existsSync(path19.join(root, "go.mod"))) {
|
|
2475
2825
|
return { name: "go test", command: () => "go test ./..." };
|
|
2476
2826
|
}
|
|
2477
2827
|
if (lang === "cs" || hasFile(root, /\.csproj$/) || hasFile(root, /\.sln$/)) {
|
|
@@ -2482,16 +2832,16 @@ function detectRunner(root, lang) {
|
|
|
2482
2832
|
}
|
|
2483
2833
|
function hasFile(root, re) {
|
|
2484
2834
|
try {
|
|
2485
|
-
return
|
|
2835
|
+
return fs18.readdirSync(root).some((f) => re.test(f));
|
|
2486
2836
|
} catch {
|
|
2487
2837
|
return false;
|
|
2488
2838
|
}
|
|
2489
2839
|
}
|
|
2490
2840
|
function findGitRoot(startDir = process.cwd()) {
|
|
2491
|
-
let dir =
|
|
2841
|
+
let dir = path19.resolve(startDir);
|
|
2492
2842
|
for (; ; ) {
|
|
2493
|
-
if (
|
|
2494
|
-
const parent =
|
|
2843
|
+
if (fs18.existsSync(path19.join(dir, ".git"))) return dir;
|
|
2844
|
+
const parent = path19.dirname(dir);
|
|
2495
2845
|
if (parent === dir) return null;
|
|
2496
2846
|
dir = parent;
|
|
2497
2847
|
}
|
|
@@ -2502,19 +2852,19 @@ function normalizeEntry(line) {
|
|
|
2502
2852
|
function ensureGitignored(entry, startDir = process.cwd()) {
|
|
2503
2853
|
const root = findGitRoot(startDir);
|
|
2504
2854
|
if (!root) return { status: "not-a-repo", entry };
|
|
2505
|
-
const gitignorePath =
|
|
2855
|
+
const gitignorePath = path19.join(root, ".gitignore");
|
|
2506
2856
|
const target = normalizeEntry(entry);
|
|
2507
2857
|
let existing = "";
|
|
2508
2858
|
let fileExisted = true;
|
|
2509
2859
|
try {
|
|
2510
|
-
existing =
|
|
2860
|
+
existing = fs18.readFileSync(gitignorePath, "utf8");
|
|
2511
2861
|
} catch {
|
|
2512
2862
|
fileExisted = false;
|
|
2513
2863
|
}
|
|
2514
2864
|
const alreadyPresent = existing.split(/\r?\n/).some((line) => normalizeEntry(line) === target);
|
|
2515
2865
|
if (alreadyPresent) return { status: "present", entry, gitignorePath };
|
|
2516
2866
|
const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
2517
|
-
|
|
2867
|
+
fs18.appendFileSync(gitignorePath, `${needsLeadingNewline ? "\n" : ""}${entry}
|
|
2518
2868
|
`, "utf8");
|
|
2519
2869
|
return { status: fileExisted ? "added" : "created", entry, gitignorePath };
|
|
2520
2870
|
}
|
|
@@ -2668,14 +3018,14 @@ dsnCommand.command("create").description("Create a new DSN token").option("--ing
|
|
|
2668
3018
|
console.log(chalk.dim("The secret must be registered on your Vibgrate ingest API."));
|
|
2669
3019
|
}
|
|
2670
3020
|
if (opts.write) {
|
|
2671
|
-
const writePath =
|
|
3021
|
+
const writePath = path19.resolve(opts.write);
|
|
2672
3022
|
await writeTextFile(writePath, dsn + "\n");
|
|
2673
3023
|
console.log("");
|
|
2674
3024
|
console.log(chalk.green("\u2714") + ` DSN written to ${opts.write}`);
|
|
2675
|
-
const root = findGitRoot(
|
|
2676
|
-
const rel2 = root ?
|
|
3025
|
+
const root = findGitRoot(path19.dirname(writePath));
|
|
3026
|
+
const rel2 = root ? path19.relative(root, writePath).split(path19.sep).join("/") : "";
|
|
2677
3027
|
if (root && rel2 && !rel2.startsWith("..")) {
|
|
2678
|
-
const res = ensureGitignored(rel2,
|
|
3028
|
+
const res = ensureGitignored(rel2, path19.dirname(writePath));
|
|
2679
3029
|
if (res.status === "created") {
|
|
2680
3030
|
console.log(chalk.green("\u2714") + ` Created .gitignore and ignored ${rel2}`);
|
|
2681
3031
|
} else if (res.status === "added") {
|
|
@@ -2693,30 +3043,30 @@ dsnCommand.command("create").description("Create a new DSN token").option("--ing
|
|
|
2693
3043
|
var STORE_DIRNAME = ".vibgrate";
|
|
2694
3044
|
var STORE_FILENAME = "credentials.json";
|
|
2695
3045
|
function homeCredentialsPath() {
|
|
2696
|
-
return
|
|
3046
|
+
return path19.join(os.homedir(), STORE_DIRNAME, STORE_FILENAME);
|
|
2697
3047
|
}
|
|
2698
3048
|
function projectCredentialsPath(cwd = process.cwd()) {
|
|
2699
3049
|
const root = findGitRoot(cwd) ?? cwd;
|
|
2700
|
-
return
|
|
3050
|
+
return path19.join(root, STORE_DIRNAME, STORE_FILENAME);
|
|
2701
3051
|
}
|
|
2702
3052
|
function credentialsPath(opts = {}) {
|
|
2703
3053
|
const override = process.env.VIBGRATE_CREDENTIALS?.trim();
|
|
2704
|
-
if (override) return
|
|
3054
|
+
if (override) return path19.resolve(override);
|
|
2705
3055
|
const local = projectCredentialsPath(opts.cwd);
|
|
2706
3056
|
if (opts.local) return local;
|
|
2707
|
-
if (
|
|
3057
|
+
if (fs18.existsSync(local)) return local;
|
|
2708
3058
|
return homeCredentialsPath();
|
|
2709
3059
|
}
|
|
2710
3060
|
function gitignoreEntryForCredentials(repoRoot, credsFile = credentialsPath()) {
|
|
2711
|
-
const rel2 =
|
|
2712
|
-
if (rel2 && !rel2.startsWith("..") && !
|
|
2713
|
-
return rel2.split(
|
|
3061
|
+
const rel2 = path19.relative(repoRoot, credsFile);
|
|
3062
|
+
if (rel2 && !rel2.startsWith("..") && !path19.isAbsolute(rel2)) {
|
|
3063
|
+
return rel2.split(path19.sep).join("/");
|
|
2714
3064
|
}
|
|
2715
3065
|
return `${STORE_DIRNAME}/${STORE_FILENAME}`;
|
|
2716
3066
|
}
|
|
2717
3067
|
function readStoredCredentials(opts = {}) {
|
|
2718
3068
|
try {
|
|
2719
|
-
const raw =
|
|
3069
|
+
const raw = fs18.readFileSync(credentialsPath(opts), "utf8");
|
|
2720
3070
|
const parsed = JSON.parse(raw);
|
|
2721
3071
|
return parsed && typeof parsed.dsn === "string" && parsed.dsn ? parsed : null;
|
|
2722
3072
|
} catch {
|
|
@@ -2725,16 +3075,16 @@ function readStoredCredentials(opts = {}) {
|
|
|
2725
3075
|
}
|
|
2726
3076
|
function writeStoredCredentials(creds, opts = {}) {
|
|
2727
3077
|
const file = credentialsPath(opts);
|
|
2728
|
-
|
|
2729
|
-
|
|
3078
|
+
fs18.mkdirSync(path19.dirname(file), { recursive: true });
|
|
3079
|
+
fs18.writeFileSync(file, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
2730
3080
|
try {
|
|
2731
|
-
|
|
3081
|
+
fs18.chmodSync(file, 384);
|
|
2732
3082
|
} catch {
|
|
2733
3083
|
}
|
|
2734
3084
|
}
|
|
2735
3085
|
function clearStoredCredentials(opts = {}) {
|
|
2736
3086
|
try {
|
|
2737
|
-
|
|
3087
|
+
fs18.rmSync(credentialsPath(opts));
|
|
2738
3088
|
return true;
|
|
2739
3089
|
} catch {
|
|
2740
3090
|
return false;
|
|
@@ -3105,7 +3455,7 @@ var pushCommand = new Command("push").description("Push scan results to Vibgrate
|
|
|
3105
3455
|
if (opts.strict) process.exit(1);
|
|
3106
3456
|
return;
|
|
3107
3457
|
}
|
|
3108
|
-
const filePath =
|
|
3458
|
+
const filePath = path19.resolve(opts.file);
|
|
3109
3459
|
if (!await pathExists(filePath)) {
|
|
3110
3460
|
console.error(chalk.red(`Scan artifact not found: ${filePath}`));
|
|
3111
3461
|
console.error(chalk.dim('Run "vibgrate scan" first.'));
|
|
@@ -3200,7 +3550,7 @@ function measure(root, files) {
|
|
|
3200
3550
|
for (const rel2 of files) {
|
|
3201
3551
|
let size;
|
|
3202
3552
|
try {
|
|
3203
|
-
size =
|
|
3553
|
+
size = fs18.statSync(path19.join(root, rel2)).size;
|
|
3204
3554
|
} catch {
|
|
3205
3555
|
continue;
|
|
3206
3556
|
}
|
|
@@ -3223,9 +3573,9 @@ function matchLines(text, needleLower) {
|
|
|
3223
3573
|
}
|
|
3224
3574
|
function readCandidate(abs, knownSize) {
|
|
3225
3575
|
try {
|
|
3226
|
-
const size = knownSize ??
|
|
3576
|
+
const size = knownSize ?? fs18.statSync(abs).size;
|
|
3227
3577
|
if (size > MAX_FILE_BYTES) return null;
|
|
3228
|
-
const text =
|
|
3578
|
+
const text = fs18.readFileSync(abs, "utf8");
|
|
3229
3579
|
return text.includes(NUL) ? null : text;
|
|
3230
3580
|
} catch {
|
|
3231
3581
|
return null;
|
|
@@ -3236,7 +3586,7 @@ function scanInline(root, files, needleLower, cap, stopAtCap, sizes) {
|
|
|
3236
3586
|
let total = 0;
|
|
3237
3587
|
let truncated = false;
|
|
3238
3588
|
for (const rel2 of files) {
|
|
3239
|
-
const text = readCandidate(
|
|
3589
|
+
const text = readCandidate(path19.join(root, rel2), sizes?.get(rel2));
|
|
3240
3590
|
if (text === null) continue;
|
|
3241
3591
|
for (const h of matchLines(text, needleLower)) {
|
|
3242
3592
|
total++;
|
|
@@ -3303,12 +3653,12 @@ var WORKER_SOURCE = [
|
|
|
3303
3653
|
"parentPort.postMessage({ hits, total, truncated });"
|
|
3304
3654
|
].join("\n");
|
|
3305
3655
|
function runWorker(root, files, needleLower) {
|
|
3306
|
-
return new Promise((
|
|
3656
|
+
return new Promise((resolve13, reject) => {
|
|
3307
3657
|
const w = new Worker(WORKER_SOURCE, { eval: true, workerData: { root, files, needleLower } });
|
|
3308
3658
|
let settled = false;
|
|
3309
3659
|
w.once("message", (m) => {
|
|
3310
3660
|
settled = true;
|
|
3311
|
-
|
|
3661
|
+
resolve13(m);
|
|
3312
3662
|
});
|
|
3313
3663
|
w.once("error", reject);
|
|
3314
3664
|
w.once("exit", (code) => {
|
|
@@ -3377,10 +3727,10 @@ var BINARY_EXTS = /* @__PURE__ */ new Set([
|
|
|
3377
3727
|
".pdf"
|
|
3378
3728
|
]);
|
|
3379
3729
|
function hasBinaryExt(rel2) {
|
|
3380
|
-
return BINARY_EXTS.has(
|
|
3730
|
+
return BINARY_EXTS.has(path19.extname(rel2).toLowerCase());
|
|
3381
3731
|
}
|
|
3382
3732
|
function toPosix4(rel2) {
|
|
3383
|
-
return
|
|
3733
|
+
return path19.sep === "\\" ? rel2.replaceAll("\\", "/") : rel2;
|
|
3384
3734
|
}
|
|
3385
3735
|
async function searchSymbols(graph, root, query, limit) {
|
|
3386
3736
|
let q = query.trim();
|
|
@@ -3519,13 +3869,13 @@ function walkCandidates(root) {
|
|
|
3519
3869
|
const dir = stack.pop();
|
|
3520
3870
|
let entries;
|
|
3521
3871
|
try {
|
|
3522
|
-
entries =
|
|
3872
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
3523
3873
|
} catch {
|
|
3524
3874
|
continue;
|
|
3525
3875
|
}
|
|
3526
3876
|
for (const e of entries) {
|
|
3527
3877
|
if (e.name.startsWith(".") || IGNORE_DIRS.has(e.name)) continue;
|
|
3528
|
-
const abs =
|
|
3878
|
+
const abs = path19.join(dir, e.name);
|
|
3529
3879
|
if (e.isDirectory()) {
|
|
3530
3880
|
stack.push(abs);
|
|
3531
3881
|
continue;
|
|
@@ -3535,7 +3885,7 @@ function walkCandidates(root) {
|
|
|
3535
3885
|
truncated = true;
|
|
3536
3886
|
continue;
|
|
3537
3887
|
}
|
|
3538
|
-
files.push(toPosix4(
|
|
3888
|
+
files.push(toPosix4(path19.relative(root, abs)));
|
|
3539
3889
|
}
|
|
3540
3890
|
}
|
|
3541
3891
|
files.sort();
|
|
@@ -3566,12 +3916,12 @@ function ripgrepCandidates(root, needle) {
|
|
|
3566
3916
|
if (files.length > MAX_FILES_SCANNED) return { files: files.slice(0, MAX_FILES_SCANNED), truncated: true };
|
|
3567
3917
|
return { files, truncated: false };
|
|
3568
3918
|
}
|
|
3569
|
-
function parseRgFileList(stdout,
|
|
3919
|
+
function parseRgFileList(stdout, sep10 = path19.sep) {
|
|
3570
3920
|
const seen = /* @__PURE__ */ new Set();
|
|
3571
3921
|
for (const raw of stdout.split("\n")) {
|
|
3572
3922
|
if (!raw) continue;
|
|
3573
|
-
const
|
|
3574
|
-
const rel2 =
|
|
3923
|
+
const posix2 = sep10 === "\\" ? raw.replaceAll("\\", "/") : raw;
|
|
3924
|
+
const rel2 = posix2.startsWith("./") ? posix2.slice(2) : posix2;
|
|
3575
3925
|
if (!rel2) continue;
|
|
3576
3926
|
const segs = rel2.split("/");
|
|
3577
3927
|
if (segs.some((s) => s.startsWith(".") || IGNORE_DIRS.has(s))) continue;
|
|
@@ -3582,8 +3932,8 @@ function parseRgFileList(stdout, sep9 = path18.sep) {
|
|
|
3582
3932
|
}
|
|
3583
3933
|
function readScanArtifact(root) {
|
|
3584
3934
|
try {
|
|
3585
|
-
const file =
|
|
3586
|
-
return JSON.parse(
|
|
3935
|
+
const file = path19.join(root, ".vibgrate", "scan_result.json");
|
|
3936
|
+
return JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
3587
3937
|
} catch {
|
|
3588
3938
|
return null;
|
|
3589
3939
|
}
|
|
@@ -3973,7 +4323,7 @@ var CACHE_VERSION = "vg-hosted-docs/1";
|
|
|
3973
4323
|
var HOSTED_DOCS_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3974
4324
|
var MAX_ENTRIES = 64;
|
|
3975
4325
|
function cachePath(root) {
|
|
3976
|
-
return
|
|
4326
|
+
return path19.join(cacheDir(root), "hosted-docs.json");
|
|
3977
4327
|
}
|
|
3978
4328
|
function hostedDocsCacheKey(req, opts = {}) {
|
|
3979
4329
|
const material = JSON.stringify([
|
|
@@ -3989,7 +4339,7 @@ function hostedDocsCacheKey(req, opts = {}) {
|
|
|
3989
4339
|
}
|
|
3990
4340
|
function loadFile(root) {
|
|
3991
4341
|
try {
|
|
3992
|
-
const parsed = JSON.parse(
|
|
4342
|
+
const parsed = JSON.parse(fs18.readFileSync(cachePath(root), "utf8"));
|
|
3993
4343
|
if (parsed && parsed.version === CACHE_VERSION && parsed.entries && typeof parsed.entries === "object") return parsed;
|
|
3994
4344
|
} catch {
|
|
3995
4345
|
}
|
|
@@ -4003,8 +4353,8 @@ function saveFile(root, file) {
|
|
|
4003
4353
|
delete file.entries[k];
|
|
4004
4354
|
}
|
|
4005
4355
|
}
|
|
4006
|
-
|
|
4007
|
-
|
|
4356
|
+
fs18.mkdirSync(cacheDir(root), { recursive: true });
|
|
4357
|
+
fs18.writeFileSync(cachePath(root), JSON.stringify(file));
|
|
4008
4358
|
} catch {
|
|
4009
4359
|
}
|
|
4010
4360
|
}
|
|
@@ -4292,11 +4642,11 @@ var TOOLS = [
|
|
|
4292
4642
|
area: node.area
|
|
4293
4643
|
};
|
|
4294
4644
|
if (ctx?.dedup && ctx.seen?.has(node.id)) {
|
|
4295
|
-
return { ...base, repeat: true, callsTotal:
|
|
4645
|
+
return { ...base, repeat: true, callsTotal: uniqueNames2(calleeRecs.map((x) => x.node.qualifiedName)).length, calledByTotal: uniqueNames2(callerRecs.map((x) => x.node.qualifiedName)).length };
|
|
4296
4646
|
}
|
|
4297
4647
|
const edgeCap = isDetailed(args) ? NODE_EDGE_CAP : CONCISE_MATCHES;
|
|
4298
|
-
const calls = boundList(
|
|
4299
|
-
const calledBy = boundList(
|
|
4648
|
+
const calls = boundList(uniqueNames2(calleeRecs.map((x) => x.node.qualifiedName)), edgeCap);
|
|
4649
|
+
const calledBy = boundList(uniqueNames2(callerRecs.map((x) => x.node.qualifiedName)), edgeCap);
|
|
4300
4650
|
ctx?.seen?.add(node.id);
|
|
4301
4651
|
return {
|
|
4302
4652
|
...base,
|
|
@@ -4325,7 +4675,7 @@ var TOOLS = [
|
|
|
4325
4675
|
if (!ra.node) return { endpoint: "a", ...unresolved(ra.candidates) };
|
|
4326
4676
|
if (!rb.node) return { endpoint: "b", ...unresolved(rb.candidates) };
|
|
4327
4677
|
const result = shortestPath(graph, ra.node.id, rb.node.id);
|
|
4328
|
-
if (!result) return
|
|
4678
|
+
if (!result) return pathDisconnect(graph, ra.node.id, rb.node.id);
|
|
4329
4679
|
const byId = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
4330
4680
|
return { connected: true, direction: result.direction, path: result.ids.map((id) => byId.get(id)?.qualifiedName ?? id) };
|
|
4331
4681
|
}
|
|
@@ -4418,18 +4768,47 @@ var TOOLS = [
|
|
|
4418
4768
|
},
|
|
4419
4769
|
{
|
|
4420
4770
|
name: "list_hubs",
|
|
4421
|
-
description: "Most-depended-on symbols.",
|
|
4771
|
+
description: "Most-depended-on symbols (includes precomputed blast-radius counts when available).",
|
|
4422
4772
|
inputSchema: obj({ limit: { type: "number" } }),
|
|
4423
|
-
handler: (graph, args) =>
|
|
4773
|
+
handler: (graph, args) => {
|
|
4774
|
+
const limit = numOr(args.limit, 20);
|
|
4775
|
+
if (graph.summaries?.hubs?.length) {
|
|
4776
|
+
return graph.summaries.hubs.slice(0, limit).map((h) => ({
|
|
4777
|
+
name: h.name,
|
|
4778
|
+
kind: h.kind,
|
|
4779
|
+
file: h.file,
|
|
4780
|
+
importance: h.importance,
|
|
4781
|
+
isHub: true,
|
|
4782
|
+
directDependents: h.direct,
|
|
4783
|
+
depth2Dependents: h.depth2,
|
|
4784
|
+
filesAffected: h.files,
|
|
4785
|
+
tested: h.tested
|
|
4786
|
+
}));
|
|
4787
|
+
}
|
|
4788
|
+
return graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance).slice(0, limit).map((n) => ({
|
|
4789
|
+
name: n.qualifiedName,
|
|
4790
|
+
kind: n.kind,
|
|
4791
|
+
file: n.file,
|
|
4792
|
+
line: n.span.start,
|
|
4793
|
+
importance: n.importance,
|
|
4794
|
+
isHub: n.isHub
|
|
4795
|
+
}));
|
|
4796
|
+
}
|
|
4424
4797
|
},
|
|
4425
4798
|
{
|
|
4426
4799
|
name: "get_facts",
|
|
4427
|
-
description: "Deterministic facts for a node (contract/invariant
|
|
4800
|
+
description: "Deterministic facts for a node (contract / invariant / characterization).",
|
|
4428
4801
|
inputSchema: obj({ name: { type: "string" } }, ["name"]),
|
|
4429
4802
|
handler: (graph, args) => {
|
|
4430
4803
|
const { node, candidates } = resolveOne(graph, String(args.name ?? ""));
|
|
4431
4804
|
if (!node) return unresolved(candidates);
|
|
4432
|
-
if (!graph.facts)
|
|
4805
|
+
if (!graph.facts) {
|
|
4806
|
+
return {
|
|
4807
|
+
node: node.qualifiedName,
|
|
4808
|
+
facts: [],
|
|
4809
|
+
note: "map has no facts \u2014 rebuild with a current vg (facts ship on every build)"
|
|
4810
|
+
};
|
|
4811
|
+
}
|
|
4433
4812
|
return { node: node.qualifiedName, facts: graph.facts.filter((f) => f.subjectIds.includes(node.id)) };
|
|
4434
4813
|
}
|
|
4435
4814
|
},
|
|
@@ -4721,14 +5100,22 @@ function conciseSummary(graph) {
|
|
|
4721
5100
|
return { counts: graph.meta.counts, languages: graph.meta.languages };
|
|
4722
5101
|
}
|
|
4723
5102
|
function summarize(graph, top = 10) {
|
|
5103
|
+
const topHubs = graph.summaries?.hubs?.length ? graph.summaries.hubs.slice(0, top).map((h) => ({
|
|
5104
|
+
name: h.name,
|
|
5105
|
+
file: h.file,
|
|
5106
|
+
importance: h.importance,
|
|
5107
|
+
directDependents: h.direct,
|
|
5108
|
+
depth2Dependents: h.depth2
|
|
5109
|
+
})) : graph.nodes.filter((n) => n.isHub).sort((a, b) => b.importance - a.importance).slice(0, top).map((n) => ({ name: n.qualifiedName, file: n.file, importance: n.importance }));
|
|
4724
5110
|
return {
|
|
4725
5111
|
counts: graph.meta.counts,
|
|
4726
5112
|
languages: graph.meta.languages,
|
|
4727
5113
|
cluster: graph.meta.cluster,
|
|
5114
|
+
analysisTier: graph.meta.analysisTier ?? "full",
|
|
4728
5115
|
resolver: graph.provenance.resolver,
|
|
4729
5116
|
generatedAt: graph.generatedAt,
|
|
4730
5117
|
topAreas: [...graph.areas].sort((a, b) => b.size - a.size).slice(0, top).map((a) => ({ id: a.id, label: a.label, size: a.size })),
|
|
4731
|
-
topHubs
|
|
5118
|
+
topHubs
|
|
4732
5119
|
};
|
|
4733
5120
|
}
|
|
4734
5121
|
function stripId(item) {
|
|
@@ -4756,7 +5143,7 @@ function numOrU(v) {
|
|
|
4756
5143
|
const n = Number(v);
|
|
4757
5144
|
return Number.isFinite(n) ? n : void 0;
|
|
4758
5145
|
}
|
|
4759
|
-
function
|
|
5146
|
+
function uniqueNames2(xs) {
|
|
4760
5147
|
return [...new Set(xs)];
|
|
4761
5148
|
}
|
|
4762
5149
|
var HOT_TOOLS = ["orient", "search_symbols", "query_graph", "get_node"];
|
|
@@ -4979,12 +5366,12 @@ function detectAssistants(root, opts = {}) {
|
|
|
4979
5366
|
const which = opts.which ?? whichOnPath;
|
|
4980
5367
|
const found = [];
|
|
4981
5368
|
for (const assistant of ASSISTANTS) {
|
|
4982
|
-
const repoHit = (assistant.markers ?? []).find((m) =>
|
|
5369
|
+
const repoHit = (assistant.markers ?? []).find((m) => fs18.existsSync(path19.join(root, m)));
|
|
4983
5370
|
if (repoHit) {
|
|
4984
5371
|
found.push({ assistant, via: "repo", marker: repoHit });
|
|
4985
5372
|
continue;
|
|
4986
5373
|
}
|
|
4987
|
-
const homeHit = (assistant.homeMarkers ?? []).find((m) =>
|
|
5374
|
+
const homeHit = (assistant.homeMarkers ?? []).find((m) => fs18.existsSync(path19.join(home, m)));
|
|
4988
5375
|
if (homeHit) {
|
|
4989
5376
|
found.push({ assistant, via: "home", marker: homeHit });
|
|
4990
5377
|
continue;
|
|
@@ -5016,19 +5403,19 @@ function installAssistant(a, opts) {
|
|
|
5016
5403
|
const skipped = [];
|
|
5017
5404
|
let note;
|
|
5018
5405
|
if (a.skill) {
|
|
5019
|
-
writeFileEnsured(
|
|
5406
|
+
writeFileEnsured(path19.join(opts.root, a.skill), skillMarkdown(a.id));
|
|
5020
5407
|
wrote.push(a.skill);
|
|
5021
5408
|
}
|
|
5022
5409
|
if (a.mcp) {
|
|
5023
5410
|
const launch = opts.launch ?? detectServeLaunch();
|
|
5024
|
-
upsertMcp(
|
|
5411
|
+
upsertMcp(path19.join(opts.root, a.mcp.file), a.mcp, launch);
|
|
5025
5412
|
wrote.push(a.mcp.file);
|
|
5026
5413
|
note = launch.note;
|
|
5027
5414
|
} else {
|
|
5028
5415
|
skipped.push("mcp (host-specific setup)");
|
|
5029
5416
|
}
|
|
5030
5417
|
if (a.nudge && opts.hook !== false) {
|
|
5031
|
-
writeNudge(
|
|
5418
|
+
writeNudge(path19.join(opts.root, a.nudge.file), a.nudge, opts.smallRepo, a.id);
|
|
5032
5419
|
wrote.push(a.nudge.file);
|
|
5033
5420
|
} else if (a.nudge) {
|
|
5034
5421
|
skipped.push("nudge (--no-hook)");
|
|
@@ -5038,41 +5425,41 @@ function installAssistant(a, opts) {
|
|
|
5038
5425
|
function uninstallAssistant(a, root, purge) {
|
|
5039
5426
|
const removed = [];
|
|
5040
5427
|
if (a.mcp) {
|
|
5041
|
-
const file =
|
|
5428
|
+
const file = path19.join(root, a.mcp.file);
|
|
5042
5429
|
if (removeMcp(file, a.mcp)) removed.push(a.mcp.file);
|
|
5043
5430
|
}
|
|
5044
5431
|
if (a.nudge) {
|
|
5045
|
-
const file =
|
|
5432
|
+
const file = path19.join(root, a.nudge.file);
|
|
5046
5433
|
if (a.nudge.kind === "block") {
|
|
5047
5434
|
if (removeBlock(file)) removed.push(a.nudge.file);
|
|
5048
|
-
} else if (
|
|
5049
|
-
|
|
5435
|
+
} else if (fs18.existsSync(file)) {
|
|
5436
|
+
fs18.rmSync(file);
|
|
5050
5437
|
removed.push(a.nudge.file);
|
|
5051
5438
|
}
|
|
5052
5439
|
}
|
|
5053
5440
|
if (purge && a.skill) {
|
|
5054
|
-
const file =
|
|
5055
|
-
if (
|
|
5056
|
-
|
|
5441
|
+
const file = path19.join(root, a.skill);
|
|
5442
|
+
if (fs18.existsSync(file)) {
|
|
5443
|
+
fs18.rmSync(file);
|
|
5057
5444
|
removed.push(a.skill);
|
|
5058
5445
|
}
|
|
5059
5446
|
}
|
|
5060
5447
|
return removed;
|
|
5061
5448
|
}
|
|
5062
5449
|
function writeFileEnsured(file, content) {
|
|
5063
|
-
|
|
5064
|
-
|
|
5450
|
+
fs18.mkdirSync(path19.dirname(file), { recursive: true });
|
|
5451
|
+
fs18.writeFileSync(file, content);
|
|
5065
5452
|
}
|
|
5066
5453
|
function writeNavigationConfig(root) {
|
|
5067
5454
|
ensureVibgrateGitignore(root);
|
|
5068
|
-
const rel2 =
|
|
5455
|
+
const rel2 = path19.join(".vibgrate", "mcp-navigation.json");
|
|
5069
5456
|
const doc = {
|
|
5070
5457
|
_readme: "Deferred-loading config for agents embedding `vg serve` via the Claude API (defer_loading + tool-search). The hot navigation core stays in context; the rest load on demand \u2014 ~350-450 schema tokens/step vs ~1,881 for the full set. Hosts without defer_loading ignore this and serve the whole (already optimized) tool set. See docs/graph/VG-NAVIGATION-PROFILE.md.",
|
|
5071
5458
|
hot_core: [...HOT_TOOLS],
|
|
5072
5459
|
deferred: deferredToolNames(),
|
|
5073
5460
|
toolset: navigationToolsetConfig()
|
|
5074
5461
|
};
|
|
5075
|
-
writeFileEnsured(
|
|
5462
|
+
writeFileEnsured(path19.join(root, rel2), `${JSON.stringify(doc, null, 2)}
|
|
5076
5463
|
`);
|
|
5077
5464
|
return rel2;
|
|
5078
5465
|
}
|
|
@@ -5087,7 +5474,7 @@ function upsertMcp(file, target, launch) {
|
|
|
5087
5474
|
`);
|
|
5088
5475
|
}
|
|
5089
5476
|
function removeMcp(file, target) {
|
|
5090
|
-
if (!
|
|
5477
|
+
if (!fs18.existsSync(file)) return false;
|
|
5091
5478
|
const config = readJson(file);
|
|
5092
5479
|
const bag = config[target.key];
|
|
5093
5480
|
if (!bag || !(bag.vg !== void 0)) return false;
|
|
@@ -5106,8 +5493,8 @@ function refreshInstalledInstructions(root, smallRepo) {
|
|
|
5106
5493
|
};
|
|
5107
5494
|
for (const a of ASSISTANTS) {
|
|
5108
5495
|
if (a.skill) {
|
|
5109
|
-
const file =
|
|
5110
|
-
if (
|
|
5496
|
+
const file = path19.join(root, a.skill);
|
|
5497
|
+
if (fs18.existsSync(file)) {
|
|
5111
5498
|
const text = readTextSafe(file);
|
|
5112
5499
|
const from = text === null ? null : staleVersion(text, "# vg \u2014 the code map");
|
|
5113
5500
|
if (from !== null) {
|
|
@@ -5117,8 +5504,8 @@ function refreshInstalledInstructions(root, smallRepo) {
|
|
|
5117
5504
|
}
|
|
5118
5505
|
}
|
|
5119
5506
|
if (a.nudge) {
|
|
5120
|
-
const file =
|
|
5121
|
-
if (!
|
|
5507
|
+
const file = path19.join(root, a.nudge.file);
|
|
5508
|
+
if (!fs18.existsSync(file)) continue;
|
|
5122
5509
|
const text = readTextSafe(file);
|
|
5123
5510
|
if (text === null) continue;
|
|
5124
5511
|
if (a.nudge.kind === "block") {
|
|
@@ -5142,7 +5529,7 @@ function refreshInstalledInstructions(root, smallRepo) {
|
|
|
5142
5529
|
}
|
|
5143
5530
|
function readTextSafe(file) {
|
|
5144
5531
|
try {
|
|
5145
|
-
return
|
|
5532
|
+
return fs18.readFileSync(file, "utf8");
|
|
5146
5533
|
} catch {
|
|
5147
5534
|
return null;
|
|
5148
5535
|
}
|
|
@@ -5161,8 +5548,8 @@ ${stripMarkers(nudgeMarkdown(smallRepo, client))}` : stripMarkers(nudgeMarkdown(
|
|
|
5161
5548
|
upsertBlock(file, nudgeMarkdown(smallRepo, client));
|
|
5162
5549
|
}
|
|
5163
5550
|
function upsertBlock(file, block) {
|
|
5164
|
-
|
|
5165
|
-
let existing =
|
|
5551
|
+
fs18.mkdirSync(path19.dirname(file), { recursive: true });
|
|
5552
|
+
let existing = fs18.existsSync(file) ? fs18.readFileSync(file, "utf8") : "";
|
|
5166
5553
|
const re = new RegExp(`${escapeRe(NUDGE_BEGIN)}[\\s\\S]*?${escapeRe(NUDGE_END)}`);
|
|
5167
5554
|
if (re.test(existing)) existing = existing.replace(re, block);
|
|
5168
5555
|
else existing = existing.length ? `${existing.replace(/\s*$/, "")}
|
|
@@ -5170,20 +5557,20 @@ function upsertBlock(file, block) {
|
|
|
5170
5557
|
${block}
|
|
5171
5558
|
` : `${block}
|
|
5172
5559
|
`;
|
|
5173
|
-
|
|
5560
|
+
fs18.writeFileSync(file, existing);
|
|
5174
5561
|
}
|
|
5175
5562
|
function removeBlock(file) {
|
|
5176
|
-
if (!
|
|
5177
|
-
const existing =
|
|
5563
|
+
if (!fs18.existsSync(file)) return false;
|
|
5564
|
+
const existing = fs18.readFileSync(file, "utf8");
|
|
5178
5565
|
const re = new RegExp(`\\n*${escapeRe(NUDGE_BEGIN)}[\\s\\S]*?${escapeRe(NUDGE_END)}\\n*`);
|
|
5179
5566
|
if (!re.test(existing)) return false;
|
|
5180
|
-
|
|
5567
|
+
fs18.writeFileSync(file, existing.replace(re, "\n"));
|
|
5181
5568
|
return true;
|
|
5182
5569
|
}
|
|
5183
5570
|
function readJson(file) {
|
|
5184
|
-
if (!
|
|
5571
|
+
if (!fs18.existsSync(file)) return {};
|
|
5185
5572
|
try {
|
|
5186
|
-
const parsed = JSON.parse(
|
|
5573
|
+
const parsed = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
5187
5574
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
5188
5575
|
return parsed;
|
|
5189
5576
|
}
|
|
@@ -5203,7 +5590,7 @@ function escapeRe(s) {
|
|
|
5203
5590
|
}
|
|
5204
5591
|
var REFRESH_LOCK_STALE_MS = 10 * 60 * 1e3;
|
|
5205
5592
|
function refreshLockPath(root) {
|
|
5206
|
-
return
|
|
5593
|
+
return path19.join(cacheDir(root), "refresh.lock");
|
|
5207
5594
|
}
|
|
5208
5595
|
async function refreshIfStale(root, opts = {}) {
|
|
5209
5596
|
const probe = probeFreshness(root);
|
|
@@ -5235,8 +5622,8 @@ async function refreshIfStale(root, opts = {}) {
|
|
|
5235
5622
|
writeArtifacts(result.graph, {
|
|
5236
5623
|
root,
|
|
5237
5624
|
graphPath: opts.graphPath,
|
|
5238
|
-
report:
|
|
5239
|
-
html:
|
|
5625
|
+
report: fs18.existsSync(path19.join(dir, "GRAPH_REPORT.md")),
|
|
5626
|
+
html: fs18.existsSync(path19.join(dir, "graph.html"))
|
|
5240
5627
|
});
|
|
5241
5628
|
}
|
|
5242
5629
|
writeSnapshot(root, result.graph.provenance.corpusHash, result.fileStats, scope);
|
|
@@ -5256,6 +5643,6 @@ async function refreshIfStale(root, opts = {}) {
|
|
|
5256
5643
|
}
|
|
5257
5644
|
}
|
|
5258
5645
|
|
|
5259
|
-
export { ASSISTANTS, CliError, ExitCode, FREE_PACK, NPX_INVOCATION, ResourceLimitError, SKIP_DIRS, SKIP_FILES, SMALL_REPO_FILES, TOOLS, UsageError, analyze, applyCoverage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, clearStoredCredentials, countTokens, coveringTests, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, detectAssistants, detectRunner, detectServeLaunch, discover, driftCount, dsnCommand, ensureGitignored, epistemicBreakdown, fetchHostedDocsCached, findGitRoot, gitignoreEntryForCredentials, groundGraph, hasDrift, homeCredentialsPath, hostedBase, ingestHostForRegionId, installAssistant, loadCoverage, loadSnapshot, parseDsn, probeFreshness, projectCredentialsPath, publishPrivateLibrary, pushCommand, readScanArtifact, readStoredCredentials, refreshIfStale, refreshInstalledInstructions, renderToolResult, resolveCliInvocation, resolveDsn, resolveIngestHost, resolveLimits, scipEdges, searchSymbols, selectForBudget, shortestPath, symbolsFromApi, testsToRun, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, warmEmbedderInBackground, writeNavigationConfig, writeSnapshot, writeStoredCredentials };
|
|
5260
|
-
//# sourceMappingURL=chunk-
|
|
5261
|
-
//# sourceMappingURL=chunk-
|
|
5646
|
+
export { ASSISTANTS, CliError, ExitCode, FREE_PACK, NPX_INVOCATION, ResourceLimitError, SKIP_DIRS, SKIP_FILES, SMALL_REPO_FILES, TOOLS, UsageError, analyze, applyCoverage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, clearStoredCredentials, countTokens, coveringTests, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, detectAssistants, detectRunner, detectServeLaunch, discover, driftCount, dsnCommand, ensureGitignored, epistemicBreakdown, fetchHostedDocsCached, findGitRoot, gitignoreEntryForCredentials, groundGraph, hasDrift, homeCredentialsPath, hostedBase, ingestHostForRegionId, installAssistant, loadCoverage, loadSnapshot, parseDsn, pathDisconnect, probeFreshness, projectCredentialsPath, publishPrivateLibrary, pushCommand, readScanArtifact, readStoredCredentials, refreshIfStale, refreshInstalledInstructions, renderToolResult, resolveCliInvocation, resolveDsn, resolveIngestHost, resolveLimits, scipEdges, searchSymbols, selectForBudget, shortestPath, symbolsFromApi, testsToRun, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, warmEmbedderInBackground, writeNavigationConfig, writeSnapshot, writeStoredCredentials };
|
|
5647
|
+
//# sourceMappingURL=chunk-MAY5HLDH.js.map
|
|
5648
|
+
//# sourceMappingURL=chunk-MAY5HLDH.js.map
|