@vibgrate/cli 2026.727.2 → 2026.727.4

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.
Files changed (101) hide show
  1. package/DOCS.md +21 -1
  2. package/README.md +2 -1
  3. package/dist/baseline-ENCOSJYQ.js +8 -0
  4. package/dist/{baseline-TG4ATZGZ.js.map → baseline-ENCOSJYQ.js.map} +1 -1
  5. package/dist/chunk-3SDV6ADQ.js +78 -0
  6. package/dist/chunk-3SDV6ADQ.js.map +1 -0
  7. package/dist/{chunk-LKVMI67M.js → chunk-6AXHLQBV.js} +220 -23
  8. package/dist/chunk-6AXHLQBV.js.map +1 -0
  9. package/dist/{chunk-6ABXHZRN.js → chunk-6UK6QPTR.js} +69 -70
  10. package/dist/chunk-6UK6QPTR.js.map +1 -0
  11. package/dist/{chunk-TCDAZZNP.js → chunk-77LYGXBI.js} +5 -5
  12. package/dist/{chunk-TCDAZZNP.js.map → chunk-77LYGXBI.js.map} +1 -1
  13. package/dist/{chunk-2XQDMLKB.js → chunk-B3YUO3NW.js} +7 -3
  14. package/dist/chunk-B3YUO3NW.js.map +1 -0
  15. package/dist/{chunk-RNP3SMTV.js → chunk-FPEOIS7K.js} +61 -26
  16. package/dist/chunk-FPEOIS7K.js.map +1 -0
  17. package/dist/{chunk-OOIG3RUM.js → chunk-GYSOQH5C.js} +18 -79
  18. package/dist/chunk-GYSOQH5C.js.map +1 -0
  19. package/dist/{chunk-6AYDFFP5.js → chunk-HK3AWUXH.js} +3 -3
  20. package/dist/{chunk-6AYDFFP5.js.map → chunk-HK3AWUXH.js.map} +1 -1
  21. package/dist/{chunk-EX4PQT6W.js → chunk-HYRAILGM.js} +4 -4
  22. package/dist/{chunk-EX4PQT6W.js.map → chunk-HYRAILGM.js.map} +1 -1
  23. package/dist/{chunk-NDMDSPFX.js → chunk-KKRSQQ3A.js} +4 -3
  24. package/dist/chunk-KKRSQQ3A.js.map +1 -0
  25. package/dist/chunk-KUIBP3LU.js +101 -0
  26. package/dist/chunk-KUIBP3LU.js.map +1 -0
  27. package/dist/{chunk-OFUC6RYN.js → chunk-KXSKFQMI.js} +6 -99
  28. package/dist/chunk-KXSKFQMI.js.map +1 -0
  29. package/dist/{chunk-KCKYKDMS.js → chunk-LJP2EPKM.js} +20 -17
  30. package/dist/chunk-LJP2EPKM.js.map +1 -0
  31. package/dist/{chunk-J4RFRKZH.js → chunk-MAUJTPQW.js} +8 -8
  32. package/dist/{chunk-J4RFRKZH.js.map → chunk-MAUJTPQW.js.map} +1 -1
  33. package/dist/{chunk-3Q7QBWFW.js → chunk-ON25BX6T.js} +9 -3
  34. package/dist/chunk-ON25BX6T.js.map +1 -0
  35. package/dist/{chunk-3V24O47U.js → chunk-PVZBYZZR.js} +19 -9
  36. package/dist/chunk-PVZBYZZR.js.map +1 -0
  37. package/dist/{chunk-CY4WKXB2.js → chunk-R6ZRVVZT.js} +4 -4
  38. package/dist/{chunk-CY4WKXB2.js.map → chunk-R6ZRVVZT.js.map} +1 -1
  39. package/dist/{chunk-WGUL45AV.js → chunk-T3AYRS7J.js} +14 -7
  40. package/dist/chunk-T3AYRS7J.js.map +1 -0
  41. package/dist/{chunk-2MBL43EJ.js → chunk-XPJZTSY7.js} +3 -3
  42. package/dist/{chunk-2MBL43EJ.js.map → chunk-XPJZTSY7.js.map} +1 -1
  43. package/dist/chunk-YCJIIGLP.js +356 -0
  44. package/dist/chunk-YCJIIGLP.js.map +1 -0
  45. package/dist/{chunk-KNELIQJO.js → chunk-YKVH2PGF.js} +640 -208
  46. package/dist/chunk-YKVH2PGF.js.map +1 -0
  47. package/dist/{chunk-KSBHGWRV.js → chunk-ZBTY6VV4.js} +4 -4
  48. package/dist/{chunk-KSBHGWRV.js.map → chunk-ZBTY6VV4.js.map} +1 -1
  49. package/dist/{chunk-K3MZIVZW.js → chunk-ZKNB4YH4.js} +19 -5
  50. package/dist/chunk-ZKNB4YH4.js.map +1 -0
  51. package/dist/cli.js +476 -393
  52. package/dist/cli.js.map +1 -1
  53. package/dist/{graph-backend-73URGTFY.js → graph-backend-UTOL3SHE.js} +5 -5
  54. package/dist/{graph-backend-73URGTFY.js.map → graph-backend-UTOL3SHE.js.map} +1 -1
  55. package/dist/index.d.ts +12 -5
  56. package/dist/index.js +12 -11
  57. package/dist/index.js.map +1 -1
  58. package/dist/{interactive-372NLI5C.js → interactive-SMHVURYK.js} +54 -24
  59. package/dist/interactive-SMHVURYK.js.map +1 -0
  60. package/dist/load-QPOWQD7C.js +8 -0
  61. package/dist/{load-I333TGNI.js.map → load-QPOWQD7C.js.map} +1 -1
  62. package/dist/model-manager-PN7HEDXD.js +9 -0
  63. package/dist/{model-orchestrator-TVONAUPS.js.map → model-manager-PN7HEDXD.js.map} +1 -1
  64. package/dist/{model-orchestrator-TVONAUPS.js → model-orchestrator-4VSYP4J4.js} +3 -3
  65. package/dist/model-orchestrator-4VSYP4J4.js.map +1 -0
  66. package/dist/parse-worker.d.ts +1 -1
  67. package/dist/parse-worker.js +1 -1
  68. package/dist/resolve-gguf-Y6FH3CNB.js +9 -0
  69. package/dist/{resolve-gguf-VPL4YQ6J.js.map → resolve-gguf-Y6FH3CNB.js.map} +1 -1
  70. package/dist/{runtime-session-JRKCQUHY.js → runtime-session-4AMZIAAG.js} +7 -7
  71. package/dist/{runtime-session-JRKCQUHY.js.map → runtime-session-4AMZIAAG.js.map} +1 -1
  72. package/dist/session-W3646AOV.js +12 -0
  73. package/dist/{session-ITPYQ5XI.js.map → session-W3646AOV.js.map} +1 -1
  74. package/dist/sql-extract-JELDZA6W.js +81 -0
  75. package/dist/sql-extract-JELDZA6W.js.map +1 -0
  76. package/dist/{stream-json-SLMDKLXP.js → stream-json-X7UQFB4T.js} +11 -10
  77. package/dist/stream-json-X7UQFB4T.js.map +1 -0
  78. package/dist/{types-7AHBUbFm.d.ts → types-DLH-Ritr.d.ts} +18 -1
  79. package/dist/{vgd-7JV5KCNJ.js → vgd-CVLKBS7K.js} +6 -6
  80. package/dist/vgd-CVLKBS7K.js.map +1 -0
  81. package/package.json +1 -1
  82. package/dist/baseline-TG4ATZGZ.js +0 -8
  83. package/dist/chunk-2XQDMLKB.js.map +0 -1
  84. package/dist/chunk-3Q7QBWFW.js.map +0 -1
  85. package/dist/chunk-3V24O47U.js.map +0 -1
  86. package/dist/chunk-6ABXHZRN.js.map +0 -1
  87. package/dist/chunk-K3MZIVZW.js.map +0 -1
  88. package/dist/chunk-KCKYKDMS.js.map +0 -1
  89. package/dist/chunk-KNELIQJO.js.map +0 -1
  90. package/dist/chunk-LKVMI67M.js.map +0 -1
  91. package/dist/chunk-NDMDSPFX.js.map +0 -1
  92. package/dist/chunk-OFUC6RYN.js.map +0 -1
  93. package/dist/chunk-OOIG3RUM.js.map +0 -1
  94. package/dist/chunk-RNP3SMTV.js.map +0 -1
  95. package/dist/chunk-WGUL45AV.js.map +0 -1
  96. package/dist/interactive-372NLI5C.js.map +0 -1
  97. package/dist/load-I333TGNI.js +0 -8
  98. package/dist/resolve-gguf-VPL4YQ6J.js +0 -8
  99. package/dist/session-ITPYQ5XI.js +0 -11
  100. package/dist/stream-json-SLMDKLXP.js.map +0 -1
  101. package/dist/vgd-7JV5KCNJ.js.map +0 -1
@@ -1,17 +1,17 @@
1
- import { loadConfig, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem, VERSION } from './chunk-WGUL45AV.js';
2
- import { resolveVersion, resolveLib, loadCatalog, driftFor, localPackageDocs, readDoc, inventory, localApiSurface, edgeId, buildModuleResolver, resolve, applyStaticTestLinkage, nodeId } from './chunk-LKVMI67M.js';
1
+ import { resolveVersion, resolveLib, loadCatalog, driftFor, localPackageDocs, readDoc, inventory, localApiSurface, edgeId, buildModuleResolver, resolve, applyStaticTestLinkage, nodeId } from './chunk-6AXHLQBV.js';
2
+ import { loadConfig, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem, VERSION } from './chunk-T3AYRS7J.js';
3
+ import { writeTextFile, pathExists, readJsonFile } from './chunk-CRAMOEBE.js';
3
4
  import { resolveOne, findNodes } from './chunk-J7LKEB2R.js';
4
- import { discoverModels } from './chunk-OOIG3RUM.js';
5
- import { impactOf, indexFor, withTimeout, getNodeEmbeddings, queryGraphSemantic, queryGraph, loadEmbedder, isModelReady, acquireLock, releaseLock } from './chunk-6ABXHZRN.js';
6
- import { langById, grammarSetVersion, langForExtension, setGrammarsOverride, parseSource } from './chunk-3Q7QBWFW.js';
5
+ import { impactOf, indexFor, withTimeout, getNodeEmbeddings, queryGraphSemantic, queryGraph, loadEmbedder, isModelReady, acquireLock, releaseLock } from './chunk-6UK6QPTR.js';
6
+ import { discoverModels } from './chunk-3SDV6ADQ.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-2XQDMLKB.js';
9
- import { cacheDir, loadCache, serializeGraph, stableStringify } from './chunk-K3MZIVZW.js';
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 { writeTextFile, pathExists, readJsonFile } from './chunk-CRAMOEBE.js';
12
- import * as fs16 from 'fs';
12
+ import * as fs18 from 'fs';
13
13
  import { spawnSync, execFileSync } from 'child_process';
14
- import * as path18 from 'path';
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 = fs16.realpathSync(binPath);
50
+ const real = fs18.realpathSync(binPath);
50
51
  if (/[\\/]@vibgrate[\\/]cli[\\/]/.test(real)) return true;
51
- const head = fs16.readFileSync(real, { encoding: "utf8" }).slice(0, 2048);
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(fs16.realpathSync(binPath));
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(path18.sep).join("/");
239
+ return p.split(path19.sep).join("/");
239
240
  }
240
241
  function buildRootIgnore(root, exclude) {
241
242
  const ig = ignore();
242
- const gitignorePath = path18.join(root, ".gitignore");
243
- if (fs16.existsSync(gitignorePath)) {
244
- ig.add(fs16.readFileSync(gitignorePath, "utf8"));
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 = path18.resolve(options.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) => path18.resolve(root, p)) : [root]).filter((p) => fs16.existsSync(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(path18.relative(root, abs));
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(path18.basename(abs).toLowerCase())) return;
266
- const lang = langForExtension(path18.extname(abs));
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 = fs16.readdirSync(dir, { withFileTypes: true });
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 = path18.join(dir, entry.name);
279
- const rel2 = toPosix(path18.relative(root, abs));
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 = fs16.statSync(scope);
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) => path18.resolve(root, p)
773
+ (p) => path19.resolve(root, p)
773
774
  );
774
- const found = candidates.filter((p) => fs16.existsSync(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 = fs16.readFileSync(file, "utf8");
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 = path18.isAbsolute(p) ? p : path18.resolve(root, p);
789
- return path18.relative(root, abs).split(path18.sep).join("/");
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 = fs16.readFileSync(file.abs, "utf8");
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 = path18.dirname(fileURLToPath(import.meta.url));
1152
- const candidate = path18.join(here, "parse-worker.js");
1153
- return fs16.existsSync(candidate) ? candidate : null;
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 path18.resolve(p).split(path18.sep).join("/");
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(path18.sep).join("/");
1646
+ return p.split(path19.sep).join("/");
1646
1647
  }
1647
1648
  function buildRootIgnore2(root, exclude) {
1648
1649
  const ig = ignore();
1649
- const gitignorePath = path18.join(root, ".gitignore");
1650
- if (fs16.existsSync(gitignorePath)) {
1650
+ const gitignorePath = path19.join(root, ".gitignore");
1651
+ if (fs18.existsSync(gitignorePath)) {
1651
1652
  try {
1652
- ig.add(fs16.readFileSync(gitignorePath, "utf8"));
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 = path18.basename(rel2);
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 = path18.extname(baseLower);
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 = path18.resolve(options.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) => path18.resolve(root, p)) : [root]).filter(
1696
- (p) => fs16.existsSync(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(path18.relative(root, abs));
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 = path18.basename(abs);
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 = fs16.statSync(abs);
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 = fs16.readdirSync(dir, { withFileTypes: true });
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 = path18.join(dir, entry.name);
1728
- const rel2 = toPosix2(path18.relative(root, abs));
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 = fs16.statSync(scope);
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" && path18.basename(rel2).toLowerCase() === "package.json") {
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 = fs16.readFileSync(d.abs, "utf8");
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 = path18.basename(d.rel);
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 = path18.dirname(f.abs);
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 = path18.resolve(root);
1854
+ const rootAbs = path19.resolve(root);
1854
1855
  while (true) {
1855
- if (fs16.existsSync(path18.join(dir, "tsconfig.json")) || fs16.existsSync(path18.join(dir, "tsconfig.base.json")) || fs16.existsSync(path18.join(dir, "package.json"))) {
1856
- const key = toPosix3(path18.relative(rootAbs, dir)) || ".";
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 || path18.dirname(dir) === dir) {
1861
+ if (dir === rootAbs || path19.dirname(dir) === dir) {
1861
1862
  cache.set(startDir, ".");
1862
1863
  return ".";
1863
1864
  }
1864
- dir = path18.dirname(dir);
1865
+ dir = path19.dirname(dir);
1865
1866
  }
1866
1867
  }
1867
1868
  function toPosix3(p) {
1868
- return p.split(path18.sep).join("/");
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 = path18.resolve(options.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 = fs16.statSync(file.abs);
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
- let hash = "";
1970
- try {
1971
- hash = hashBytes(fs16.readFileSync(file.abs));
1972
- } catch {
1973
- continue;
1974
- }
1975
- hashes.set(file.rel, hash);
1976
- fileStats.push({ rel: file.rel, size: stat.size, mtimeMs: stat.mtimeMs, hash });
1977
- const cached2 = cache.get(file.rel, hash);
1978
- if (cached2) {
1979
- reused.push(cached2);
1980
- cache.set(file.rel, cached2, { mtimeMs: stat.mtimeMs, size: stat.size });
1981
- } else {
1982
- toParse.push(file);
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 = fs16.statSync(d.abs);
2083
- const hash = hashBytes(fs16.readFileSync(d.abs));
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: path18.basename(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
- if (options.deep) {
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
- path18.join(root, "index.scip"),
2183
- path18.join(root, ".vibgrate", "index.scip")
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 = path18.isAbsolute(file) ? file : path18.resolve(root, file);
2187
- if (!fs16.existsSync(abs)) continue;
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(fs16.readFileSync(abs)));
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 path18.join(cacheDir(root), "freshness.json");
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
- fs16.mkdirSync(cacheDir(root), { recursive: true });
2312
- fs16.writeFileSync(snapshotPath(root), stableStringify(snapshot, 0));
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(fs16.readFileSync(snapshotPath(root), "utf8"));
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
- discovered = discover({ root, only: scope.only, exclude: scope.exclude, paths: scope.paths });
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 = fs16.statSync(file.abs);
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(fs16.readFileSync(file.abs));
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
- fs16.writeFileSync(snapshotPath(root), stableStringify(snapshot, 0));
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 = path18.join(root, "package.json");
2461
- if (fs16.existsSync(pkgPath)) {
2810
+ const pkgPath = path19.join(root, "package.json");
2811
+ if (fs18.existsSync(pkgPath)) {
2462
2812
  try {
2463
- const pkg = JSON.parse(fs16.readFileSync(pkgPath, "utf8"));
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" || fs16.existsSync(path18.join(root, "pyproject.toml")) || fs16.existsSync(path18.join(root, "pytest.ini"))) {
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" || fs16.existsSync(path18.join(root, "go.mod"))) {
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 fs16.readdirSync(root).some((f) => re.test(f));
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 = path18.resolve(startDir);
2841
+ let dir = path19.resolve(startDir);
2492
2842
  for (; ; ) {
2493
- if (fs16.existsSync(path18.join(dir, ".git"))) return dir;
2494
- const parent = path18.dirname(dir);
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 = path18.join(root, ".gitignore");
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 = fs16.readFileSync(gitignorePath, "utf8");
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
- fs16.appendFileSync(gitignorePath, `${needsLeadingNewline ? "\n" : ""}${entry}
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 = path18.resolve(opts.write);
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(path18.dirname(writePath));
2676
- const rel2 = root ? path18.relative(root, writePath).split(path18.sep).join("/") : "";
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, path18.dirname(writePath));
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 path18.join(os.homedir(), STORE_DIRNAME, STORE_FILENAME);
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 path18.join(root, STORE_DIRNAME, STORE_FILENAME);
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 path18.resolve(override);
3054
+ if (override) return path19.resolve(override);
2705
3055
  const local = projectCredentialsPath(opts.cwd);
2706
3056
  if (opts.local) return local;
2707
- if (fs16.existsSync(local)) return local;
3057
+ if (fs18.existsSync(local)) return local;
2708
3058
  return homeCredentialsPath();
2709
3059
  }
2710
3060
  function gitignoreEntryForCredentials(repoRoot, credsFile = credentialsPath()) {
2711
- const rel2 = path18.relative(repoRoot, credsFile);
2712
- if (rel2 && !rel2.startsWith("..") && !path18.isAbsolute(rel2)) {
2713
- return rel2.split(path18.sep).join("/");
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 = fs16.readFileSync(credentialsPath(opts), "utf8");
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
- fs16.mkdirSync(path18.dirname(file), { recursive: true });
2729
- fs16.writeFileSync(file, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf8", mode: 384 });
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
- fs16.chmodSync(file, 384);
3081
+ fs18.chmodSync(file, 384);
2732
3082
  } catch {
2733
3083
  }
2734
3084
  }
2735
3085
  function clearStoredCredentials(opts = {}) {
2736
3086
  try {
2737
- fs16.rmSync(credentialsPath(opts));
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 = path18.resolve(opts.file);
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 = fs16.statSync(path18.join(root, rel2)).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 ?? fs16.statSync(abs).size;
3576
+ const size = knownSize ?? fs18.statSync(abs).size;
3227
3577
  if (size > MAX_FILE_BYTES) return null;
3228
- const text = fs16.readFileSync(abs, "utf8");
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(path18.join(root, rel2), sizes?.get(rel2));
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((resolve12, reject) => {
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
- resolve12(m);
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(path18.extname(rel2).toLowerCase());
3730
+ return BINARY_EXTS.has(path19.extname(rel2).toLowerCase());
3381
3731
  }
3382
3732
  function toPosix4(rel2) {
3383
- return path18.sep === "\\" ? rel2.replaceAll("\\", "/") : rel2;
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 = fs16.readdirSync(dir, { withFileTypes: true });
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 = path18.join(dir, e.name);
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(path18.relative(root, abs)));
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, sep9 = path18.sep) {
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 posix = sep9 === "\\" ? raw.replaceAll("\\", "/") : raw;
3574
- const rel2 = posix.startsWith("./") ? posix.slice(2) : posix;
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 = path18.join(root, ".vibgrate", "scan_result.json");
3586
- return JSON.parse(fs16.readFileSync(file, "utf8"));
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
  }
@@ -3839,6 +4189,12 @@ ${chunk2}`);
3839
4189
  }
3840
4190
 
3841
4191
  // src/engine/quality.ts
4192
+ var IDENT_RE = /^(?:[A-Za-z][a-z0-9]*[A-Z][A-Za-z0-9]*|[a-z][a-z0-9]*(?:_[a-z0-9]+)+|[a-z][a-z0-9]*(?:-[a-z0-9]+)+)$/;
4193
+ function identifierTerms(query) {
4194
+ if (!query) return [];
4195
+ const raw = [...new Set(query.split(/[^A-Za-z0-9_-]+/).filter((w) => w.length > 2))];
4196
+ return raw.filter((t) => IDENT_RE.test(t) || t.length >= 6 && /[A-Z]/.test(t) && /[a-z]/.test(t));
4197
+ }
3842
4198
  function assessDocQuality(content, opts = {}) {
3843
4199
  const minTokens = opts.minTokens ?? 60;
3844
4200
  const lc = content.toLowerCase();
@@ -3856,20 +4212,36 @@ function assessDocQuality(content, opts = {}) {
3856
4212
  else reasons.push("library name absent");
3857
4213
  }
3858
4214
  const qt = tokenizeQuery(opts.query);
4215
+ const idents = identifierTerms(opts.query);
3859
4216
  let onTopic = qt.length === 0;
3860
4217
  if (qt.length) {
3861
- const hits = qt.filter((t) => lc.includes(t)).length;
3862
- if (hits) {
3863
- score += Math.min(hits, 2);
3864
- onTopic = true;
4218
+ const missingIdents = idents.filter((id) => !lc.includes(id.toLowerCase()));
4219
+ if (missingIdents.length) {
4220
+ reasons.push(`API symbol(s) absent: ${missingIdents.join(", ")}`);
4221
+ onTopic = false;
3865
4222
  } else {
3866
- reasons.push("query terms absent");
4223
+ const hits = qt.filter((t) => lc.includes(t)).length;
4224
+ const need = Math.max(1, Math.floor(qt.length / 2) + 1);
4225
+ if (hits >= need) {
4226
+ score += Math.min(hits, 2);
4227
+ onTopic = true;
4228
+ } else {
4229
+ reasons.push(hits === 0 ? "query terms absent" : `query terms weak (${hits}/${qt.length})`);
4230
+ onTopic = false;
4231
+ }
3867
4232
  }
3868
4233
  }
3869
4234
  if (opts.symbols?.length) {
3870
4235
  if (opts.symbols.some((s) => s.length > 2 && lc.includes(s.toLowerCase()))) score += 1;
3871
4236
  else reasons.push("no API symbols present");
3872
4237
  }
4238
+ if (opts.readmeOnly && (idents.length > 0 || qt.length >= 2)) {
4239
+ onTopic = false;
4240
+ if (!reasons.includes("README-only source cannot answer a focused API query")) {
4241
+ reasons.push("README-only source cannot answer a focused API query");
4242
+ }
4243
+ score = Math.min(score, 4);
4244
+ }
3873
4245
  const sufficient = hasCode && tokens >= minTokens && onTopic;
3874
4246
  return { score, sufficient, reasons };
3875
4247
  }
@@ -3973,7 +4345,7 @@ var CACHE_VERSION = "vg-hosted-docs/1";
3973
4345
  var HOSTED_DOCS_TTL_MS = 24 * 60 * 60 * 1e3;
3974
4346
  var MAX_ENTRIES = 64;
3975
4347
  function cachePath(root) {
3976
- return path18.join(cacheDir(root), "hosted-docs.json");
4348
+ return path19.join(cacheDir(root), "hosted-docs.json");
3977
4349
  }
3978
4350
  function hostedDocsCacheKey(req, opts = {}) {
3979
4351
  const material = JSON.stringify([
@@ -3989,7 +4361,7 @@ function hostedDocsCacheKey(req, opts = {}) {
3989
4361
  }
3990
4362
  function loadFile(root) {
3991
4363
  try {
3992
- const parsed = JSON.parse(fs16.readFileSync(cachePath(root), "utf8"));
4364
+ const parsed = JSON.parse(fs18.readFileSync(cachePath(root), "utf8"));
3993
4365
  if (parsed && parsed.version === CACHE_VERSION && parsed.entries && typeof parsed.entries === "object") return parsed;
3994
4366
  } catch {
3995
4367
  }
@@ -4003,8 +4375,8 @@ function saveFile(root, file) {
4003
4375
  delete file.entries[k];
4004
4376
  }
4005
4377
  }
4006
- fs16.mkdirSync(cacheDir(root), { recursive: true });
4007
- fs16.writeFileSync(cachePath(root), JSON.stringify(file));
4378
+ fs18.mkdirSync(cacheDir(root), { recursive: true });
4379
+ fs18.writeFileSync(cachePath(root), JSON.stringify(file));
4008
4380
  } catch {
4009
4381
  }
4010
4382
  }
@@ -4292,11 +4664,11 @@ var TOOLS = [
4292
4664
  area: node.area
4293
4665
  };
4294
4666
  if (ctx?.dedup && ctx.seen?.has(node.id)) {
4295
- return { ...base, repeat: true, callsTotal: uniqueNames(calleeRecs.map((x) => x.node.qualifiedName)).length, calledByTotal: uniqueNames(callerRecs.map((x) => x.node.qualifiedName)).length };
4667
+ return { ...base, repeat: true, callsTotal: uniqueNames2(calleeRecs.map((x) => x.node.qualifiedName)).length, calledByTotal: uniqueNames2(callerRecs.map((x) => x.node.qualifiedName)).length };
4296
4668
  }
4297
4669
  const edgeCap = isDetailed(args) ? NODE_EDGE_CAP : CONCISE_MATCHES;
4298
- const calls = boundList(uniqueNames(calleeRecs.map((x) => x.node.qualifiedName)), edgeCap);
4299
- const calledBy = boundList(uniqueNames(callerRecs.map((x) => x.node.qualifiedName)), edgeCap);
4670
+ const calls = boundList(uniqueNames2(calleeRecs.map((x) => x.node.qualifiedName)), edgeCap);
4671
+ const calledBy = boundList(uniqueNames2(callerRecs.map((x) => x.node.qualifiedName)), edgeCap);
4300
4672
  ctx?.seen?.add(node.id);
4301
4673
  return {
4302
4674
  ...base,
@@ -4325,7 +4697,7 @@ var TOOLS = [
4325
4697
  if (!ra.node) return { endpoint: "a", ...unresolved(ra.candidates) };
4326
4698
  if (!rb.node) return { endpoint: "b", ...unresolved(rb.candidates) };
4327
4699
  const result = shortestPath(graph, ra.node.id, rb.node.id);
4328
- if (!result) return { connected: false };
4700
+ if (!result) return pathDisconnect(graph, ra.node.id, rb.node.id);
4329
4701
  const byId = new Map(graph.nodes.map((n) => [n.id, n]));
4330
4702
  return { connected: true, direction: result.direction, path: result.ids.map((id) => byId.get(id)?.qualifiedName ?? id) };
4331
4703
  }
@@ -4418,27 +4790,68 @@ var TOOLS = [
4418
4790
  },
4419
4791
  {
4420
4792
  name: "list_hubs",
4421
- description: "Most-depended-on symbols.",
4793
+ description: "Most-depended-on symbols (includes precomputed blast-radius counts when available).",
4422
4794
  inputSchema: obj({ limit: { type: "number" } }),
4423
- handler: (graph, args) => graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance).slice(0, numOr(args.limit, 20)).map((n) => ({ name: n.qualifiedName, kind: n.kind, file: n.file, line: n.span.start, importance: n.importance, isHub: n.isHub }))
4795
+ handler: (graph, args) => {
4796
+ const limit = numOr(args.limit, 20);
4797
+ if (graph.summaries?.hubs?.length) {
4798
+ return graph.summaries.hubs.slice(0, limit).map((h) => ({
4799
+ name: h.name,
4800
+ kind: h.kind,
4801
+ file: h.file,
4802
+ importance: h.importance,
4803
+ isHub: true,
4804
+ directDependents: h.direct,
4805
+ depth2Dependents: h.depth2,
4806
+ filesAffected: h.files,
4807
+ tested: h.tested
4808
+ }));
4809
+ }
4810
+ return graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance).slice(0, limit).map((n) => ({
4811
+ name: n.qualifiedName,
4812
+ kind: n.kind,
4813
+ file: n.file,
4814
+ line: n.span.start,
4815
+ importance: n.importance,
4816
+ isHub: n.isHub
4817
+ }));
4818
+ }
4424
4819
  },
4425
4820
  {
4426
4821
  name: "get_facts",
4427
- description: "Deterministic facts for a node (contract/invariant); needs a --deep build.",
4428
- inputSchema: obj({ name: { type: "string" } }, ["name"]),
4822
+ description: "Deterministic facts for a node (contract / invariant / characterization).",
4823
+ inputSchema: obj(
4824
+ {
4825
+ name: { type: "string" },
4826
+ pick: { type: "number", description: "nth candidate if ambiguous" }
4827
+ },
4828
+ ["name"]
4829
+ ),
4429
4830
  handler: (graph, args) => {
4430
- const { node, candidates } = resolveOne(graph, String(args.name ?? ""));
4831
+ const { node, candidates } = resolveOne(graph, String(args.name ?? ""), numOrU(args.pick));
4431
4832
  if (!node) return unresolved(candidates);
4432
- if (!graph.facts) return { node: node.qualifiedName, facts: [], note: "facts require a --deep build" };
4833
+ if (!graph.facts) {
4834
+ return {
4835
+ node: node.qualifiedName,
4836
+ facts: [],
4837
+ note: "map has no facts \u2014 rebuild with a current vg (facts ship on every build)"
4838
+ };
4839
+ }
4433
4840
  return { node: node.qualifiedName, facts: graph.facts.filter((f) => f.subjectIds.includes(node.id)) };
4434
4841
  }
4435
4842
  },
4436
4843
  {
4437
4844
  name: "guide_node",
4438
4845
  description: "Cited standards/practices for a node (OWASP/CWE).",
4439
- inputSchema: obj({ name: { type: "string" } }, ["name"]),
4846
+ inputSchema: obj(
4847
+ {
4848
+ name: { type: "string" },
4849
+ pick: { type: "number", description: "nth candidate if ambiguous" }
4850
+ },
4851
+ ["name"]
4852
+ ),
4440
4853
  handler: (graph, args) => {
4441
- const { node, candidates } = resolveOne(graph, String(args.name ?? ""));
4854
+ const { node, candidates } = resolveOne(graph, String(args.name ?? ""), numOrU(args.pick));
4442
4855
  if (!node) return unresolved(candidates);
4443
4856
  const entries = new Map(FREE_PACK.entries.map((e) => [e.id, e]));
4444
4857
  return {
@@ -4632,13 +5045,24 @@ var TOOLS = [
4632
5045
  const verbosity = ["concise", "balanced", "exhaustive"].includes(String(args.verbosity)) ? String(args.verbosity) : query ? "concise" : "balanced";
4633
5046
  const budget = numOrU(args.max_tokens) ?? numOrU(args.tokens) ?? VERBOSITY_BUDGET[verbosity];
4634
5047
  const ver = resolveVersion(ctx.root, id);
4635
- const render = (readme, libName) => {
4636
- const apiSurface = localApiSurface(ctx.root, libName);
4637
- const sel = selectForBudget({ readme, query, apiSurface, budget });
4638
- const quality = assessDocQuality([readme, apiSurface].filter(Boolean).join("\n\n"), {
5048
+ const focusQuery = (() => {
5049
+ const q = query.trim();
5050
+ if (!q) return q;
5051
+ const bare = id.replace(/^@[^/]+\//, "").toLowerCase();
5052
+ const parts = q.split(/\s+/);
5053
+ if (parts.length > 1 && parts[0].toLowerCase().replace(/^@[^/]+\//, "") === bare) {
5054
+ return parts.slice(1).join(" ");
5055
+ }
5056
+ return q;
5057
+ })();
5058
+ const render = (readme, libName, readmeOnly) => {
5059
+ const apiSurface = localApiSurface(ctx.root, libName, focusQuery || void 0);
5060
+ const sel = selectForBudget({ readme, query: focusQuery || query, apiSurface, budget });
5061
+ const quality = assessDocQuality(sel.text, {
4639
5062
  name: libName,
4640
- query,
4641
- symbols: symbolsFromApi(apiSurface)
5063
+ query: focusQuery || query || void 0,
5064
+ symbols: symbolsFromApi(apiSurface),
5065
+ readmeOnly: readmeOnly === true && !apiSurface
4642
5066
  });
4643
5067
  return {
4644
5068
  content: sel.text,
@@ -4655,7 +5079,7 @@ var TOOLS = [
4655
5079
  let answer = null;
4656
5080
  let sufficient = false;
4657
5081
  if (entry) {
4658
- const r = render(readDoc(ctx.root, entry), entry.name);
5082
+ const r = render(readDoc(ctx.root, entry), entry.name, false);
4659
5083
  sufficient = r.metadata.quality.sufficient;
4660
5084
  answer = {
4661
5085
  targetId: entry.id,
@@ -4670,9 +5094,9 @@ var TOOLS = [
4670
5094
  metadata: r.metadata
4671
5095
  };
4672
5096
  } else {
4673
- const local = localPackageDocs(ctx.root, id);
5097
+ const local = localPackageDocs(ctx.root, id, { query: focusQuery || query || void 0 });
4674
5098
  if (local) {
4675
- const r = render(local.docs, id);
5099
+ const r = render(local.docs, id, local.readmeOnly);
4676
5100
  sufficient = r.metadata.quality.sufficient;
4677
5101
  answer = {
4678
5102
  targetId: id,
@@ -4721,14 +5145,22 @@ function conciseSummary(graph) {
4721
5145
  return { counts: graph.meta.counts, languages: graph.meta.languages };
4722
5146
  }
4723
5147
  function summarize(graph, top = 10) {
5148
+ const topHubs = graph.summaries?.hubs?.length ? graph.summaries.hubs.slice(0, top).map((h) => ({
5149
+ name: h.name,
5150
+ file: h.file,
5151
+ importance: h.importance,
5152
+ directDependents: h.direct,
5153
+ depth2Dependents: h.depth2
5154
+ })) : 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
5155
  return {
4725
5156
  counts: graph.meta.counts,
4726
5157
  languages: graph.meta.languages,
4727
5158
  cluster: graph.meta.cluster,
5159
+ analysisTier: graph.meta.analysisTier ?? "full",
4728
5160
  resolver: graph.provenance.resolver,
4729
5161
  generatedAt: graph.generatedAt,
4730
5162
  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: 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 }))
5163
+ topHubs
4732
5164
  };
4733
5165
  }
4734
5166
  function stripId(item) {
@@ -4756,7 +5188,7 @@ function numOrU(v) {
4756
5188
  const n = Number(v);
4757
5189
  return Number.isFinite(n) ? n : void 0;
4758
5190
  }
4759
- function uniqueNames(xs) {
5191
+ function uniqueNames2(xs) {
4760
5192
  return [...new Set(xs)];
4761
5193
  }
4762
5194
  var HOT_TOOLS = ["orient", "search_symbols", "query_graph", "get_node"];
@@ -4979,12 +5411,12 @@ function detectAssistants(root, opts = {}) {
4979
5411
  const which = opts.which ?? whichOnPath;
4980
5412
  const found = [];
4981
5413
  for (const assistant of ASSISTANTS) {
4982
- const repoHit = (assistant.markers ?? []).find((m) => fs16.existsSync(path18.join(root, m)));
5414
+ const repoHit = (assistant.markers ?? []).find((m) => fs18.existsSync(path19.join(root, m)));
4983
5415
  if (repoHit) {
4984
5416
  found.push({ assistant, via: "repo", marker: repoHit });
4985
5417
  continue;
4986
5418
  }
4987
- const homeHit = (assistant.homeMarkers ?? []).find((m) => fs16.existsSync(path18.join(home, m)));
5419
+ const homeHit = (assistant.homeMarkers ?? []).find((m) => fs18.existsSync(path19.join(home, m)));
4988
5420
  if (homeHit) {
4989
5421
  found.push({ assistant, via: "home", marker: homeHit });
4990
5422
  continue;
@@ -5016,19 +5448,19 @@ function installAssistant(a, opts) {
5016
5448
  const skipped = [];
5017
5449
  let note;
5018
5450
  if (a.skill) {
5019
- writeFileEnsured(path18.join(opts.root, a.skill), skillMarkdown(a.id));
5451
+ writeFileEnsured(path19.join(opts.root, a.skill), skillMarkdown(a.id));
5020
5452
  wrote.push(a.skill);
5021
5453
  }
5022
5454
  if (a.mcp) {
5023
5455
  const launch = opts.launch ?? detectServeLaunch();
5024
- upsertMcp(path18.join(opts.root, a.mcp.file), a.mcp, launch);
5456
+ upsertMcp(path19.join(opts.root, a.mcp.file), a.mcp, launch);
5025
5457
  wrote.push(a.mcp.file);
5026
5458
  note = launch.note;
5027
5459
  } else {
5028
5460
  skipped.push("mcp (host-specific setup)");
5029
5461
  }
5030
5462
  if (a.nudge && opts.hook !== false) {
5031
- writeNudge(path18.join(opts.root, a.nudge.file), a.nudge, opts.smallRepo, a.id);
5463
+ writeNudge(path19.join(opts.root, a.nudge.file), a.nudge, opts.smallRepo, a.id);
5032
5464
  wrote.push(a.nudge.file);
5033
5465
  } else if (a.nudge) {
5034
5466
  skipped.push("nudge (--no-hook)");
@@ -5038,41 +5470,41 @@ function installAssistant(a, opts) {
5038
5470
  function uninstallAssistant(a, root, purge) {
5039
5471
  const removed = [];
5040
5472
  if (a.mcp) {
5041
- const file = path18.join(root, a.mcp.file);
5473
+ const file = path19.join(root, a.mcp.file);
5042
5474
  if (removeMcp(file, a.mcp)) removed.push(a.mcp.file);
5043
5475
  }
5044
5476
  if (a.nudge) {
5045
- const file = path18.join(root, a.nudge.file);
5477
+ const file = path19.join(root, a.nudge.file);
5046
5478
  if (a.nudge.kind === "block") {
5047
5479
  if (removeBlock(file)) removed.push(a.nudge.file);
5048
- } else if (fs16.existsSync(file)) {
5049
- fs16.rmSync(file);
5480
+ } else if (fs18.existsSync(file)) {
5481
+ fs18.rmSync(file);
5050
5482
  removed.push(a.nudge.file);
5051
5483
  }
5052
5484
  }
5053
5485
  if (purge && a.skill) {
5054
- const file = path18.join(root, a.skill);
5055
- if (fs16.existsSync(file)) {
5056
- fs16.rmSync(file);
5486
+ const file = path19.join(root, a.skill);
5487
+ if (fs18.existsSync(file)) {
5488
+ fs18.rmSync(file);
5057
5489
  removed.push(a.skill);
5058
5490
  }
5059
5491
  }
5060
5492
  return removed;
5061
5493
  }
5062
5494
  function writeFileEnsured(file, content) {
5063
- fs16.mkdirSync(path18.dirname(file), { recursive: true });
5064
- fs16.writeFileSync(file, content);
5495
+ fs18.mkdirSync(path19.dirname(file), { recursive: true });
5496
+ fs18.writeFileSync(file, content);
5065
5497
  }
5066
5498
  function writeNavigationConfig(root) {
5067
5499
  ensureVibgrateGitignore(root);
5068
- const rel2 = path18.join(".vibgrate", "mcp-navigation.json");
5500
+ const rel2 = path19.join(".vibgrate", "mcp-navigation.json");
5069
5501
  const doc = {
5070
5502
  _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
5503
  hot_core: [...HOT_TOOLS],
5072
5504
  deferred: deferredToolNames(),
5073
5505
  toolset: navigationToolsetConfig()
5074
5506
  };
5075
- writeFileEnsured(path18.join(root, rel2), `${JSON.stringify(doc, null, 2)}
5507
+ writeFileEnsured(path19.join(root, rel2), `${JSON.stringify(doc, null, 2)}
5076
5508
  `);
5077
5509
  return rel2;
5078
5510
  }
@@ -5087,7 +5519,7 @@ function upsertMcp(file, target, launch) {
5087
5519
  `);
5088
5520
  }
5089
5521
  function removeMcp(file, target) {
5090
- if (!fs16.existsSync(file)) return false;
5522
+ if (!fs18.existsSync(file)) return false;
5091
5523
  const config = readJson(file);
5092
5524
  const bag = config[target.key];
5093
5525
  if (!bag || !(bag.vg !== void 0)) return false;
@@ -5106,8 +5538,8 @@ function refreshInstalledInstructions(root, smallRepo) {
5106
5538
  };
5107
5539
  for (const a of ASSISTANTS) {
5108
5540
  if (a.skill) {
5109
- const file = path18.join(root, a.skill);
5110
- if (fs16.existsSync(file)) {
5541
+ const file = path19.join(root, a.skill);
5542
+ if (fs18.existsSync(file)) {
5111
5543
  const text = readTextSafe(file);
5112
5544
  const from = text === null ? null : staleVersion(text, "# vg \u2014 the code map");
5113
5545
  if (from !== null) {
@@ -5117,8 +5549,8 @@ function refreshInstalledInstructions(root, smallRepo) {
5117
5549
  }
5118
5550
  }
5119
5551
  if (a.nudge) {
5120
- const file = path18.join(root, a.nudge.file);
5121
- if (!fs16.existsSync(file)) continue;
5552
+ const file = path19.join(root, a.nudge.file);
5553
+ if (!fs18.existsSync(file)) continue;
5122
5554
  const text = readTextSafe(file);
5123
5555
  if (text === null) continue;
5124
5556
  if (a.nudge.kind === "block") {
@@ -5142,7 +5574,7 @@ function refreshInstalledInstructions(root, smallRepo) {
5142
5574
  }
5143
5575
  function readTextSafe(file) {
5144
5576
  try {
5145
- return fs16.readFileSync(file, "utf8");
5577
+ return fs18.readFileSync(file, "utf8");
5146
5578
  } catch {
5147
5579
  return null;
5148
5580
  }
@@ -5161,8 +5593,8 @@ ${stripMarkers(nudgeMarkdown(smallRepo, client))}` : stripMarkers(nudgeMarkdown(
5161
5593
  upsertBlock(file, nudgeMarkdown(smallRepo, client));
5162
5594
  }
5163
5595
  function upsertBlock(file, block) {
5164
- fs16.mkdirSync(path18.dirname(file), { recursive: true });
5165
- let existing = fs16.existsSync(file) ? fs16.readFileSync(file, "utf8") : "";
5596
+ fs18.mkdirSync(path19.dirname(file), { recursive: true });
5597
+ let existing = fs18.existsSync(file) ? fs18.readFileSync(file, "utf8") : "";
5166
5598
  const re = new RegExp(`${escapeRe(NUDGE_BEGIN)}[\\s\\S]*?${escapeRe(NUDGE_END)}`);
5167
5599
  if (re.test(existing)) existing = existing.replace(re, block);
5168
5600
  else existing = existing.length ? `${existing.replace(/\s*$/, "")}
@@ -5170,20 +5602,20 @@ function upsertBlock(file, block) {
5170
5602
  ${block}
5171
5603
  ` : `${block}
5172
5604
  `;
5173
- fs16.writeFileSync(file, existing);
5605
+ fs18.writeFileSync(file, existing);
5174
5606
  }
5175
5607
  function removeBlock(file) {
5176
- if (!fs16.existsSync(file)) return false;
5177
- const existing = fs16.readFileSync(file, "utf8");
5608
+ if (!fs18.existsSync(file)) return false;
5609
+ const existing = fs18.readFileSync(file, "utf8");
5178
5610
  const re = new RegExp(`\\n*${escapeRe(NUDGE_BEGIN)}[\\s\\S]*?${escapeRe(NUDGE_END)}\\n*`);
5179
5611
  if (!re.test(existing)) return false;
5180
- fs16.writeFileSync(file, existing.replace(re, "\n"));
5612
+ fs18.writeFileSync(file, existing.replace(re, "\n"));
5181
5613
  return true;
5182
5614
  }
5183
5615
  function readJson(file) {
5184
- if (!fs16.existsSync(file)) return {};
5616
+ if (!fs18.existsSync(file)) return {};
5185
5617
  try {
5186
- const parsed = JSON.parse(fs16.readFileSync(file, "utf8"));
5618
+ const parsed = JSON.parse(fs18.readFileSync(file, "utf8"));
5187
5619
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
5188
5620
  return parsed;
5189
5621
  }
@@ -5203,7 +5635,7 @@ function escapeRe(s) {
5203
5635
  }
5204
5636
  var REFRESH_LOCK_STALE_MS = 10 * 60 * 1e3;
5205
5637
  function refreshLockPath(root) {
5206
- return path18.join(cacheDir(root), "refresh.lock");
5638
+ return path19.join(cacheDir(root), "refresh.lock");
5207
5639
  }
5208
5640
  async function refreshIfStale(root, opts = {}) {
5209
5641
  const probe = probeFreshness(root);
@@ -5235,8 +5667,8 @@ async function refreshIfStale(root, opts = {}) {
5235
5667
  writeArtifacts(result.graph, {
5236
5668
  root,
5237
5669
  graphPath: opts.graphPath,
5238
- report: fs16.existsSync(path18.join(dir, "GRAPH_REPORT.md")),
5239
- html: fs16.existsSync(path18.join(dir, "graph.html"))
5670
+ report: fs18.existsSync(path19.join(dir, "GRAPH_REPORT.md")),
5671
+ html: fs18.existsSync(path19.join(dir, "graph.html"))
5240
5672
  });
5241
5673
  }
5242
5674
  writeSnapshot(root, result.graph.provenance.corpusHash, result.fileStats, scope);
@@ -5256,6 +5688,6 @@ async function refreshIfStale(root, opts = {}) {
5256
5688
  }
5257
5689
  }
5258
5690
 
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-KNELIQJO.js.map
5261
- //# sourceMappingURL=chunk-KNELIQJO.js.map
5691
+ 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 };
5692
+ //# sourceMappingURL=chunk-YKVH2PGF.js.map
5693
+ //# sourceMappingURL=chunk-YKVH2PGF.js.map