@vibgrate/cli 2026.711.1 → 2026.715.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- import { hashString, langById, shortId, canonicalize, grammarSetVersion, hashBytes, langForExtension, setGrammarsOverride, parseSource } from './chunk-X5YT263H.js';
2
- import { writeTextFile, pathExists, readJsonFile, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem, VERSION } from './chunk-2PCL4ZME.js';
1
+ import { hashString, langById, shortId, canonicalize, grammarSetVersion, hashBytes, langForExtension, setGrammarsOverride, parseSource } from './chunk-VFO5UDAT.js';
2
+ import { writeTextFile, pathExists, readJsonFile, loadConfig, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem, VERSION } from './chunk-C5AVF7PT.js';
3
3
  import * as fs19 from 'fs';
4
4
  import { spawnSync, execFileSync } from 'child_process';
5
5
  import * as path19 from 'path';
@@ -15,6 +15,7 @@ import { fileURLToPath } from 'url';
15
15
  import ts from 'typescript';
16
16
  import { bidirectional } from 'graphology-shortest-path/unweighted.js';
17
17
  import * as crypto from 'crypto';
18
+ import { createHash } from 'crypto';
18
19
  import { Command } from 'commander';
19
20
  import chalk from 'chalk';
20
21
  import * as zlib from 'zlib';
@@ -702,6 +703,73 @@ function edgeId(kind, src, dst) {
702
703
  return shortId(canonicalize({ t: "edge", kind, src, dst }));
703
704
  }
704
705
 
706
+ // src/engine/tests.ts
707
+ function isTestFile(rel2) {
708
+ const lower = rel2.toLowerCase();
709
+ const base = rel2.split("/").pop() ?? rel2;
710
+ const lbase = base.toLowerCase();
711
+ if (/(^|\/)(__tests__|__test__)\//.test(lower)) return true;
712
+ if (/(^|\/)(tests?|spec|specs)\//.test(lower)) return true;
713
+ if (/(^|\/)src\/test\//.test(lower)) return true;
714
+ if (/\.(test|spec)\.[cm]?[jt]sx?$/.test(lbase)) return true;
715
+ if (/^test_.*\.py$/.test(lbase) || /_test\.py$/.test(lbase)) return true;
716
+ if (/_test\.go$/.test(lbase)) return true;
717
+ if (/[A-Za-z0-9](Test|Tests|IT)\.java$/.test(base)) return true;
718
+ if (/_spec\.rb$/.test(lbase) || /_test\.rb$/.test(lbase)) return true;
719
+ if (/[A-Za-z0-9](Test|Tests)\.cs$/.test(base)) return true;
720
+ if (/[A-Za-z0-9](Test|Tests)\.swift$/.test(base)) return true;
721
+ return false;
722
+ }
723
+ function applyStaticTestLinkage(nodes, edges) {
724
+ const byId = new Map(nodes.map((n) => [n.id, n]));
725
+ const testFiles = /* @__PURE__ */ new Set();
726
+ for (const n of nodes) if (n.kind === "file" && isTestFile(n.file)) testFiles.add(n.file);
727
+ const fileNodeIdByRel = /* @__PURE__ */ new Map();
728
+ for (const n of nodes) if (n.kind === "file") fileNodeIdByRel.set(n.file, n.id);
729
+ const covered = /* @__PURE__ */ new Set();
730
+ const newEdges = /* @__PURE__ */ new Map();
731
+ for (const e of edges) {
732
+ if (e.kind !== "call") continue;
733
+ const src = byId.get(e.src);
734
+ const dst = byId.get(e.dst);
735
+ if (!src || !dst) continue;
736
+ if (testFiles.has(src.file) && !testFiles.has(dst.file) && dst.kind !== "external") {
737
+ const testFileId = fileNodeIdByRel.get(src.file);
738
+ if (!testFileId) continue;
739
+ const id = edgeId("test", testFileId, dst.id);
740
+ if (!newEdges.has(id)) {
741
+ newEdges.set(id, {
742
+ id,
743
+ kind: "test",
744
+ src: testFileId,
745
+ dst: dst.id,
746
+ resolution: e.resolution,
747
+ confidence: e.confidence
748
+ });
749
+ }
750
+ covered.add(dst.id);
751
+ }
752
+ }
753
+ const outNodes = nodes.map((n) => ({ ...n, tested: testedFlag(n, covered.has(n.id), testFiles) }));
754
+ const outEdges = [...edges, ...newEdges.values()].sort(
755
+ (a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
756
+ );
757
+ return {
758
+ nodes: outNodes,
759
+ edges: outEdges,
760
+ testFiles: [...testFiles].sort(),
761
+ testEdgeCount: newEdges.size
762
+ };
763
+ }
764
+ function testedFlag(node, covered, testFiles) {
765
+ if (node.kind === "external" || node.kind === "file" || node.kind === "package" || node.kind === "module") {
766
+ return null;
767
+ }
768
+ if (testFiles.has(node.file)) return null;
769
+ if (node.kind === "function" || node.kind === "method") return covered;
770
+ return covered ? true : node.tested ?? null;
771
+ }
772
+
705
773
  // src/engine/scip.ts
706
774
  var ROLE_DEFINITION = 1;
707
775
  var Reader = class {
@@ -1064,72 +1132,6 @@ function round(x) {
1064
1132
  function pairKey(a, b) {
1065
1133
  return a < b ? `${a}|${b}` : `${b}|${a}`;
1066
1134
  }
1067
-
1068
- // src/engine/tests.ts
1069
- function isTestFile(rel2) {
1070
- const lower = rel2.toLowerCase();
1071
- const base = rel2.split("/").pop() ?? rel2;
1072
- const lbase = base.toLowerCase();
1073
- if (/(^|\/)(__tests__|__test__)\//.test(lower)) return true;
1074
- if (/(^|\/)(tests?|spec|specs)\//.test(lower)) return true;
1075
- if (/(^|\/)src\/test\//.test(lower)) return true;
1076
- if (/\.(test|spec)\.[cm]?[jt]sx?$/.test(lbase)) return true;
1077
- if (/^test_.*\.py$/.test(lbase) || /_test\.py$/.test(lbase)) return true;
1078
- if (/_test\.go$/.test(lbase)) return true;
1079
- if (/[A-Za-z0-9](Test|Tests|IT)\.java$/.test(base)) return true;
1080
- if (/_spec\.rb$/.test(lbase) || /_test\.rb$/.test(lbase)) return true;
1081
- if (/[A-Za-z0-9](Test|Tests)\.cs$/.test(base)) return true;
1082
- return false;
1083
- }
1084
- function applyStaticTestLinkage(nodes, edges) {
1085
- const byId = new Map(nodes.map((n) => [n.id, n]));
1086
- const testFiles = /* @__PURE__ */ new Set();
1087
- for (const n of nodes) if (n.kind === "file" && isTestFile(n.file)) testFiles.add(n.file);
1088
- const fileNodeIdByRel = /* @__PURE__ */ new Map();
1089
- for (const n of nodes) if (n.kind === "file") fileNodeIdByRel.set(n.file, n.id);
1090
- const covered = /* @__PURE__ */ new Set();
1091
- const newEdges = /* @__PURE__ */ new Map();
1092
- for (const e of edges) {
1093
- if (e.kind !== "call") continue;
1094
- const src = byId.get(e.src);
1095
- const dst = byId.get(e.dst);
1096
- if (!src || !dst) continue;
1097
- if (testFiles.has(src.file) && !testFiles.has(dst.file) && dst.kind !== "external") {
1098
- const testFileId = fileNodeIdByRel.get(src.file);
1099
- if (!testFileId) continue;
1100
- const id = edgeId("test", testFileId, dst.id);
1101
- if (!newEdges.has(id)) {
1102
- newEdges.set(id, {
1103
- id,
1104
- kind: "test",
1105
- src: testFileId,
1106
- dst: dst.id,
1107
- resolution: e.resolution,
1108
- confidence: e.confidence
1109
- });
1110
- }
1111
- covered.add(dst.id);
1112
- }
1113
- }
1114
- const outNodes = nodes.map((n) => ({ ...n, tested: testedFlag(n, covered.has(n.id), testFiles) }));
1115
- const outEdges = [...edges, ...newEdges.values()].sort(
1116
- (a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
1117
- );
1118
- return {
1119
- nodes: outNodes,
1120
- edges: outEdges,
1121
- testFiles: [...testFiles].sort(),
1122
- testEdgeCount: newEdges.size
1123
- };
1124
- }
1125
- function testedFlag(node, covered, testFiles) {
1126
- if (node.kind === "external" || node.kind === "file" || node.kind === "package" || node.kind === "module") {
1127
- return null;
1128
- }
1129
- if (testFiles.has(node.file)) return null;
1130
- if (node.kind === "function" || node.kind === "method") return covered;
1131
- return covered ? true : node.tested ?? null;
1132
- }
1133
1135
  var DEFAULT_PATHS = [
1134
1136
  "coverage/lcov.info",
1135
1137
  "lcov.info",
@@ -1569,6 +1571,7 @@ function emptyParse(file, warning) {
1569
1571
  calls: [],
1570
1572
  imports: [],
1571
1573
  heritage: [],
1574
+ typeRefs: [],
1572
1575
  guards: [],
1573
1576
  warnings: [warning]
1574
1577
  };
@@ -1666,9 +1669,10 @@ function resolve4(parses, resolver) {
1666
1669
  const fileId = fileNodeIdByRel.get(p.rel);
1667
1670
  const localDefs = defsByFile.get(p.rel) ?? [];
1668
1671
  const imported = importedFilesByRel.get(p.rel) ?? /* @__PURE__ */ new Set();
1672
+ const testCaller = isTestFile(p.rel);
1669
1673
  for (const call of p.calls) {
1670
1674
  const srcId = enclosingDefId(localDefs, call.byte) ?? fileId;
1671
- const resolved = resolveCall(call, p.rel, p.lang, imported, defsByName, srcId);
1675
+ const resolved = resolveCall(call, p.rel, p.lang, imported, defsByName, srcId, testCaller);
1672
1676
  if (resolved) {
1673
1677
  edges.add("call", srcId, resolved.id, "heuristic", resolved.confidence);
1674
1678
  stats.callsResolved++;
@@ -1678,13 +1682,25 @@ function resolve4(parses, resolver) {
1678
1682
  }
1679
1683
  }
1680
1684
  }
1685
+ for (const p of parses) {
1686
+ const fileId = fileNodeIdByRel.get(p.rel);
1687
+ const localDefs = defsByFile.get(p.rel) ?? [];
1688
+ const imported = importedFilesByRel.get(p.rel) ?? /* @__PURE__ */ new Set();
1689
+ const testCaller = isTestFile(p.rel);
1690
+ for (const ref of p.typeRefs) {
1691
+ const srcId = enclosingDefId(localDefs, ref.byte) ?? fileId;
1692
+ const target = resolveType(ref.name, p.rel, p.lang, imported, defsByName, testCaller);
1693
+ if (target) edges.add("references", srcId, target.id, "heuristic", 0.7);
1694
+ }
1695
+ }
1681
1696
  for (const p of parses) {
1682
1697
  const localDefs = defsByFile.get(p.rel) ?? [];
1683
1698
  const imported = importedFilesByRel.get(p.rel) ?? /* @__PURE__ */ new Set();
1699
+ const testCaller = isTestFile(p.rel);
1684
1700
  for (const h of p.heritage) {
1685
1701
  const srcId = enclosingDefId(localDefs, h.byte);
1686
1702
  if (!srcId) continue;
1687
- const target = resolveType(h.superName, p.rel, p.lang, imported, defsByName);
1703
+ const target = resolveType(h.superName, p.rel, p.lang, imported, defsByName, testCaller);
1688
1704
  if (target) edges.add(h.kind, srcId, target.id, "heuristic", 0.85);
1689
1705
  else bumpUnresolved(unresolved2, srcId, h.superName, h.kind, p.rel);
1690
1706
  }
@@ -1749,7 +1765,7 @@ function dirOf(rel2) {
1749
1765
  const i = rel2.lastIndexOf("/");
1750
1766
  return i >= 0 ? rel2.slice(0, i) : "";
1751
1767
  }
1752
- function resolveCall(call, fromRel, fromLang, importedRels, defsByName, enclosingId) {
1768
+ function resolveCall(call, fromRel, fromLang, importedRels, defsByName, enclosingId, fromIsTestFile = false) {
1753
1769
  const candidates = defsByName.get(call.callee);
1754
1770
  if (!candidates || candidates.length === 0) return null;
1755
1771
  const callable = candidates.filter((c) => c.kind === "function" || c.kind === "method");
@@ -1770,9 +1786,12 @@ function resolveCall(call, fromRel, fromLang, importedRels, defsByName, enclosin
1770
1786
  if (call.qualified && enclosingId) samePkg = samePkg.filter((c) => c.id !== enclosingId);
1771
1787
  if (samePkg.length === 1) return { id: samePkg[0].id, confidence: 0.7 };
1772
1788
  }
1789
+ if (fromLang === "swift" && fromIsTestFile && pool.length === 1) {
1790
+ return { id: pool[0].id, confidence: 0.5 };
1791
+ }
1773
1792
  return null;
1774
1793
  }
1775
- function resolveType(name, fromRel, fromLang, importedRels, defsByName) {
1794
+ function resolveType(name, fromRel, fromLang, importedRels, defsByName, fromIsTestFile = false) {
1776
1795
  const candidates = (defsByName.get(name) ?? []).filter(
1777
1796
  (c) => c.kind === "class" || c.kind === "interface"
1778
1797
  );
@@ -1787,6 +1806,9 @@ function resolveType(name, fromRel, fromLang, importedRels, defsByName) {
1787
1806
  const samePkg = candidates.filter((c) => c.lang === fromLang && dirOf(c.rel) === dir);
1788
1807
  if (samePkg.length === 1) return { id: samePkg[0].id };
1789
1808
  }
1809
+ if (fromLang === "swift" && fromIsTestFile && candidates.length === 1) {
1810
+ return { id: candidates[0].id };
1811
+ }
1790
1812
  return null;
1791
1813
  }
1792
1814
  var EdgeSet = class {
@@ -2984,13 +3006,19 @@ var GraphIndex = class {
2984
3006
  node(id) {
2985
3007
  return this.nodeById.get(id);
2986
3008
  }
2987
- /** Resolved nodes called by `id`. */
3009
+ /**
3010
+ * Resolved nodes called by `id` — invocations (`call`) plus structural
3011
+ * dependency references (`references`, e.g. a constructor-injected field's
3012
+ * type), since both represent real usage a caller/impact question cares
3013
+ * about. `references` is otherwise only emitted by the precise SCIP/tsc
3014
+ * rungs and (for Java DI wiring) the heuristic rung — never a guess.
3015
+ */
2988
3016
  callees(id) {
2989
- return this.resolveTargets(this.out(id, "call"), "dst");
3017
+ return this.resolveTargets(this.out(id).filter(isUsageEdge), "dst");
2990
3018
  }
2991
- /** Resolved nodes that call `id`. */
3019
+ /** Resolved nodes that call or structurally reference `id`. */
2992
3020
  callers(id) {
2993
- return this.resolveTargets(this.in(id, "call"), "src");
3021
+ return this.resolveTargets(this.in(id).filter(isUsageEdge), "src");
2994
3022
  }
2995
3023
  resolveTargets(edges, end) {
2996
3024
  const out = [];
@@ -3001,6 +3029,10 @@ var GraphIndex = class {
3001
3029
  return out;
3002
3030
  }
3003
3031
  };
3032
+ var USAGE_KINDS = /* @__PURE__ */ new Set(["call", "references"]);
3033
+ function isUsageEdge(e) {
3034
+ return USAGE_KINDS.has(e.kind);
3035
+ }
3004
3036
  function push2(map, key, value) {
3005
3037
  const list = map.get(key);
3006
3038
  if (list) list.push(value);
@@ -3058,7 +3090,26 @@ var STOPWORDS = /* @__PURE__ */ new Set([
3058
3090
  "from",
3059
3091
  "by",
3060
3092
  "at",
3061
- "as"
3093
+ "as",
3094
+ // Discovery-question scaffolding: words a caller uses to FRAME the ask
3095
+ // ("find the code responsible for X", "I need to modify X, where do I
3096
+ // start?", "explain how X works in this codebase") rather than to name the
3097
+ // target. Left in, these compete on equal footing with the real identifier
3098
+ // terms and can outrank it outright — e.g. "find the code responsible for
3099
+ // deleteAsync" let "find" alone drag in every FindByIdAsync/FindAll method
3100
+ // in the repo, none of them the target (VG-LOCATE-FAILURE-ANALYSIS.md).
3101
+ "find",
3102
+ "code",
3103
+ "responsible",
3104
+ "need",
3105
+ "modify",
3106
+ "me",
3107
+ "implementation",
3108
+ "explain",
3109
+ "works",
3110
+ "codebase",
3111
+ "contains",
3112
+ "file"
3062
3113
  ]);
3063
3114
  function queryGraph(graph, question, options = {}) {
3064
3115
  const budget = options.budget ?? 2e3;
@@ -3114,7 +3165,7 @@ async function queryGraphSemantic(graph, question, options) {
3114
3165
  function tokenize(q2) {
3115
3166
  return [
3116
3167
  ...new Set(
3117
- q2.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 2 && !STOPWORDS.has(t))
3168
+ q2.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 1 && !STOPWORDS.has(t))
3118
3169
  )
3119
3170
  ];
3120
3171
  }
@@ -3172,7 +3223,7 @@ function termWeights(graph, terms) {
3172
3223
  }
3173
3224
  function identifierParts(name) {
3174
3225
  return new Set(
3175
- name.split(/[^a-zA-Z0-9]+|(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/).filter(Boolean).map((s) => s.toLowerCase())
3226
+ name.split(/[^\p{L}\p{N}]+|(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/u).filter(Boolean).map((s) => s.toLowerCase())
3176
3227
  );
3177
3228
  }
3178
3229
  function fuzzyPartMatch(term, parts) {
@@ -3675,10 +3726,10 @@ var MANIFEST_BY_FILE = {
3675
3726
  };
3676
3727
  function findManifests(root) {
3677
3728
  const set = Object.fromEntries(ECOSYSTEMS.map((e) => [e, []]));
3678
- const MAX_ENTRIES = 2e4;
3729
+ const MAX_ENTRIES2 = 2e4;
3679
3730
  let scanned = 0;
3680
3731
  const walk2 = (dir, depth) => {
3681
- if (depth > 8 || scanned > MAX_ENTRIES) return;
3732
+ if (depth > 8 || scanned > MAX_ENTRIES2) return;
3682
3733
  let entries;
3683
3734
  try {
3684
3735
  entries = fs19.readdirSync(dir, { withFileTypes: true });
@@ -3687,7 +3738,7 @@ function findManifests(root) {
3687
3738
  }
3688
3739
  for (const e of entries) {
3689
3740
  scanned++;
3690
- if (scanned > MAX_ENTRIES) break;
3741
+ if (scanned > MAX_ENTRIES2) break;
3691
3742
  if (e.isDirectory()) {
3692
3743
  if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(path19.join(dir, e.name), depth + 1);
3693
3744
  continue;
@@ -4937,6 +4988,20 @@ function dedupeRoutes(routes) {
4937
4988
  // src/reporting/utils/compact-artifact.ts
4938
4989
  var gzip2 = promisify(zlib.gzip);
4939
4990
  var MAX_ITEMS = 50;
4991
+ var MAX_DB_MODELS = 300;
4992
+ var MAX_DB_FIELDS_PER_MODEL = 100;
4993
+ var MAX_DB_MODEL_FILES = 5;
4994
+ var MAX_DB_FILES_SCANNED = 500;
4995
+ var DB_UPLOAD_HARD_CEILING = {
4996
+ maxModels: 2e3,
4997
+ maxFieldsPerModel: 500,
4998
+ maxFilesPerModel: 20,
4999
+ maxFilesScanned: 5e3
5000
+ };
5001
+ function clampCap(configured, fallback, ceiling) {
5002
+ if (typeof configured !== "number" || !Number.isFinite(configured) || configured <= 0) return fallback;
5003
+ return Math.min(Math.floor(configured), ceiling);
5004
+ }
4940
5005
  function extractName(entry) {
4941
5006
  const match = entry.match(/^(.+?)\s*\(/);
4942
5007
  return match ? match[1].trim() : entry.trim();
@@ -5002,7 +5067,29 @@ function compactAssetBranding(result) {
5002
5067
  // Don't include logos
5003
5068
  };
5004
5069
  }
5005
- function prepareArtifactForUpload(artifact) {
5070
+ function compactDatabaseSchema(result, caps) {
5071
+ const maxModels = clampCap(caps?.maxModels, MAX_DB_MODELS, DB_UPLOAD_HARD_CEILING.maxModels);
5072
+ const maxFieldsPerModel = clampCap(caps?.maxFieldsPerModel, MAX_DB_FIELDS_PER_MODEL, DB_UPLOAD_HARD_CEILING.maxFieldsPerModel);
5073
+ const maxFilesPerModel = clampCap(caps?.maxFilesPerModel, MAX_DB_MODEL_FILES, DB_UPLOAD_HARD_CEILING.maxFilesPerModel);
5074
+ const maxFilesScanned = clampCap(caps?.maxFilesScanned, MAX_DB_FILES_SCANNED, DB_UPLOAD_HARD_CEILING.maxFilesScanned);
5075
+ return {
5076
+ providers: result.providers.slice(0, MAX_ITEMS),
5077
+ models: result.models.slice(0, maxModels).map((model) => ({
5078
+ ...model,
5079
+ fields: model.fields.slice(0, maxFieldsPerModel),
5080
+ files: model.files.slice(0, maxFilesPerModel)
5081
+ })),
5082
+ enums: result.enums.slice(0, MAX_ITEMS),
5083
+ filesScanned: result.filesScanned.slice(0, maxFilesScanned),
5084
+ projects: result.projects.slice(0, MAX_ITEMS).map((project) => ({
5085
+ project: project.project,
5086
+ filesScanned: project.filesScanned.slice(0, MAX_ITEMS),
5087
+ models: project.models.slice(0, MAX_ITEMS),
5088
+ enums: project.enums.slice(0, MAX_ITEMS)
5089
+ }))
5090
+ };
5091
+ }
5092
+ function prepareArtifactForUpload(artifact, opts) {
5006
5093
  const compacted = { ...artifact };
5007
5094
  if (compacted.extended) {
5008
5095
  const ext = { ...compacted.extended };
@@ -5078,6 +5165,9 @@ function prepareArtifactForUpload(artifact) {
5078
5165
  duplicatedPackages: ext.dependencyGraph.duplicatedPackages.slice(0, MAX_ITEMS)
5079
5166
  };
5080
5167
  }
5168
+ if (ext.databaseSchema) {
5169
+ ext.databaseSchema = compactDatabaseSchema(ext.databaseSchema, opts?.databaseSchemaCaps);
5170
+ }
5081
5171
  compacted.extended = ext;
5082
5172
  }
5083
5173
  return compacted;
@@ -5086,8 +5176,8 @@ async function compressArtifact(artifact) {
5086
5176
  const json = JSON.stringify(artifact);
5087
5177
  return gzip2(json, { level: 9 });
5088
5178
  }
5089
- async function prepareCompressedUpload(artifact) {
5090
- const compacted = prepareArtifactForUpload(artifact);
5179
+ async function prepareCompressedUpload(artifact, opts) {
5180
+ const compacted = prepareArtifactForUpload(artifact, opts);
5091
5181
  const compressed = await compressArtifact(compacted);
5092
5182
  return { body: compressed, contentEncoding: "gzip" };
5093
5183
  }
@@ -5100,8 +5190,9 @@ function postOnce(input, host) {
5100
5190
  "Content-Encoding": input.contentEncoding,
5101
5191
  "X-Vibgrate-Timestamp": input.timestamp,
5102
5192
  "Authorization": `VibgrateDSN ${input.keyId}:${input.secret}`,
5103
- "Connection": "close"
5193
+ "Connection": "close",
5104
5194
  // Prevent keep-alive delays on exit
5195
+ ...input.runId && input.runToken ? { "X-Vibgrate-Run-Id": input.runId, "X-Vibgrate-Run-Token": input.runToken } : {}
5105
5196
  },
5106
5197
  body: input.body
5107
5198
  });
@@ -5169,7 +5260,9 @@ var pushCommand = new Command("push").description("Push scan results to Vibgrate
5169
5260
  return;
5170
5261
  }
5171
5262
  const artifact = await readJsonFile(filePath);
5172
- const { body, contentEncoding } = await prepareCompressedUpload(artifact);
5263
+ const config = await loadConfig(process.cwd());
5264
+ const databaseSchemaCaps = config.scanners !== false ? config.scanners?.databaseSchema : void 0;
5265
+ const { body, contentEncoding } = await prepareCompressedUpload(artifact, { databaseSchemaCaps });
5173
5266
  const timestamp = String(Date.now());
5174
5267
  let host = parsed.host;
5175
5268
  if (opts.region) {
@@ -5193,7 +5286,11 @@ var pushCommand = new Command("push").description("Push scan results to Vibgrate
5193
5286
  secret: parsed.secret,
5194
5287
  body,
5195
5288
  contentEncoding,
5196
- timestamp
5289
+ timestamp,
5290
+ // Set only by an automated caller running the scan on the workspace's
5291
+ // behalf (e.g. a Vibgrate-hosted remediation run) — never a customer flag.
5292
+ runId: process.env.VIBGRATE_SCAN_RUN_ID,
5293
+ runToken: process.env.VIBGRATE_SCAN_RUN_TOKEN
5197
5294
  });
5198
5295
  host = uploadedHost;
5199
5296
  if (!response.ok) {
@@ -5604,6 +5701,65 @@ async function publishPrivateLibrary(req, opts = {}) {
5604
5701
  }
5605
5702
  }
5606
5703
 
5704
+ // src/engine/hosted-cache.ts
5705
+ var CACHE_VERSION2 = "vg-hosted-docs/1";
5706
+ var HOSTED_DOCS_TTL_MS = 24 * 60 * 60 * 1e3;
5707
+ var MAX_ENTRIES = 64;
5708
+ function cachePath2(root) {
5709
+ return path19.join(cacheDir(root), "hosted-docs.json");
5710
+ }
5711
+ function hostedDocsCacheKey(req, opts = {}) {
5712
+ const material = JSON.stringify([
5713
+ req.name ?? "",
5714
+ req.targetId ?? "",
5715
+ req.query ?? "",
5716
+ req.verbosity ?? "",
5717
+ req.maxTokens ?? 0,
5718
+ hostedBase(opts),
5719
+ opts.auth?.keyId ?? "anon"
5720
+ ]);
5721
+ return createHash("sha256").update(material).digest("hex");
5722
+ }
5723
+ function loadFile(root) {
5724
+ try {
5725
+ const parsed = JSON.parse(fs19.readFileSync(cachePath2(root), "utf8"));
5726
+ if (parsed && parsed.version === CACHE_VERSION2 && parsed.entries && typeof parsed.entries === "object") return parsed;
5727
+ } catch {
5728
+ }
5729
+ return { version: CACHE_VERSION2, entries: {} };
5730
+ }
5731
+ function saveFile(root, file) {
5732
+ try {
5733
+ const keys = Object.keys(file.entries);
5734
+ if (keys.length > MAX_ENTRIES) {
5735
+ for (const k of keys.sort((a, b) => file.entries[a].at - file.entries[b].at).slice(0, keys.length - MAX_ENTRIES)) {
5736
+ delete file.entries[k];
5737
+ }
5738
+ }
5739
+ fs19.mkdirSync(cacheDir(root), { recursive: true });
5740
+ fs19.writeFileSync(cachePath2(root), JSON.stringify(file));
5741
+ } catch {
5742
+ }
5743
+ }
5744
+ async function fetchHostedDocsCached(root, req, opts = {}) {
5745
+ const now = opts.now ?? Date.now;
5746
+ const ttl = opts.ttlMs ?? HOSTED_DOCS_TTL_MS;
5747
+ const key = hostedDocsCacheKey(req, opts);
5748
+ const file = loadFile(root);
5749
+ if (!opts.bypass) {
5750
+ const hit = file.entries[key];
5751
+ if (hit && now() - hit.at < ttl && hit.result?.content) {
5752
+ return { ...hit.result, metadata: { ...hit.result.metadata ?? {}, cached: true } };
5753
+ }
5754
+ }
5755
+ const result = await fetchHostedDocs(req, opts);
5756
+ if (result) {
5757
+ file.entries[key] = { at: now(), result };
5758
+ saveFile(root, file);
5759
+ }
5760
+ return result;
5761
+ }
5762
+
5607
5763
  // src/mcp/response.ts
5608
5764
  var MAX_RESULT_TOKENS = 25e3;
5609
5765
  function renderToolResult(result, maxTokens = MAX_RESULT_TOKENS) {
@@ -5825,6 +5981,9 @@ async function searchSymbols(graph, root, query, limit) {
5825
5981
  if (!q2) return { matches: [], moreAvailable: false, hint: "query is required" };
5826
5982
  const isPhrase = /\s/.test(q2);
5827
5983
  let nodes = findNodes(graph, q2).filter((n) => n.kind !== "file");
5984
+ if (nodes.length === 0 && isPhrase) {
5985
+ nodes = reconstructedIdentifierNodes(graph, q2);
5986
+ }
5828
5987
  if (nodes.length === 0) {
5829
5988
  const tokens = queryTokens(q2);
5830
5989
  if (tokens.length >= 2) nodes = multiTokenNodes(graph, tokens);
@@ -5867,6 +6026,14 @@ async function searchSymbols(graph, root, query, limit) {
5867
6026
  function queryTokens(q2) {
5868
6027
  return [...new Set(q2.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 2))];
5869
6028
  }
6029
+ function reconstructedIdentifierNodes(graph, q2) {
6030
+ const words = q2.trim().split(/\s+/).filter(Boolean);
6031
+ if (words.length < 2) return [];
6032
+ const concat = findNodes(graph, words.join(""));
6033
+ if (concat.length) return concat.filter((n) => n.kind !== "file");
6034
+ const snake = findNodes(graph, words.join("_"));
6035
+ return snake.filter((n) => n.kind !== "file");
6036
+ }
5870
6037
  function multiTokenNodes(graph, tokens) {
5871
6038
  const cov = /* @__PURE__ */ new Map();
5872
6039
  for (const t of tokens) {
@@ -6546,7 +6713,8 @@ var TOOLS = [
6546
6713
  return (async () => {
6547
6714
  const dsn = resolveDsn();
6548
6715
  const parsed = dsn ? parseDsn(dsn) : null;
6549
- const hosted = await fetchHostedDocs(
6716
+ const hosted = await fetchHostedDocsCached(
6717
+ ctx.root,
6550
6718
  { name: entry?.name ?? id, targetId: entry?.id, query: query || void 0, maxTokens: budget },
6551
6719
  { auth: parsed ? { keyId: parsed.keyId, secret: parsed.secret } : void 0 }
6552
6720
  );
@@ -7323,6 +7491,6 @@ function spdx(ctx) {
7323
7491
  return JSON.stringify(doc, null, 2) + "\n";
7324
7492
  }
7325
7493
 
7326
- export { ASSISTANTS, CLI_TOOL_ALIASES, CliError, ECOSYSTEMS, ExitCode, FREE_PACK, GraphIndex, GraphSource, NPX_INVOCATION, ResourceLimitError, SCHEMA_VERSION, SKIP_DIRS, SKIP_FILES, TOOLS, UsageError, addLibrary, analyze, applyCoverage, applyStaticTestLinkage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, buildModuleResolver, cacheDir, catalogPath, clearModelCache, clearStoredCredentials, cosine, countPending, countTokens, coveringTests, createServer, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, defaultGraphPath, detectRunner, detectServeLaunch, discover, discoverModels, driftCount, driftFor, dsnCommand, embeddingsCached, enrichOnline, ensureGitignored, epistemicBreakdown, exportGraph, fetchHostedDocs, findGitRoot, findNodes, formatForExt, getNodeEmbeddings, gitignoreEntryForCredentials, groundGraph, hasDrift, identifierParts, impactOf, indexFor, ingestHostForRegionId, installAssistant, inventory, isModelReady, isTestFile, libDir, libId, loadCatalog, loadCoverage, loadEmbedder, loadGraph, loadSnapshot, localApiSurface, localPackageDocs, modelCacheInfo, nodeById, nodeEmbedText, parseDsn, parseGraph, parseJsonc, probeFreshness, publishPrivateLibrary, pushCommand, queryGraph, queryGraphSemantic, readDoc, readSavings, readScanArtifact, readUsage, recordCliCall, recordSaving, refreshIfStale, relativeResolver, renderHtml, renderReport, resolveCliInvocation, resolveDsn, resolveEmbedModel, resolveIngestHost, resolveLib, resolveLimits, resolveOne, resolveVersion, saveCatalog, savingsRecorded, scipEdges, selectForBudget, serializeGraph, serveStdio, shortestPath, stableStringify, symbolsFromApi, testsToRun, unavailableMessage, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, vibgrateDir, writeArtifacts, writeNavigationConfig, writeSnapshot, writeStoredCredentials };
7327
- //# sourceMappingURL=chunk-MIJ3ZSSF.js.map
7328
- //# sourceMappingURL=chunk-MIJ3ZSSF.js.map
7494
+ export { ASSISTANTS, CLI_TOOL_ALIASES, CliError, ECOSYSTEMS, ExitCode, FREE_PACK, GraphIndex, GraphSource, NPX_INVOCATION, ResourceLimitError, SCHEMA_VERSION, SKIP_DIRS, SKIP_FILES, TOOLS, UsageError, addLibrary, analyze, applyCoverage, applyStaticTestLinkage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, buildModuleResolver, cacheDir, catalogPath, clearModelCache, clearStoredCredentials, cosine, countPending, countTokens, coveringTests, createServer, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, defaultGraphPath, detectRunner, detectServeLaunch, discover, discoverModels, driftCount, driftFor, dsnCommand, embeddingsCached, enrichOnline, ensureGitignored, epistemicBreakdown, exportGraph, fetchHostedDocsCached, findGitRoot, findNodes, formatForExt, getNodeEmbeddings, gitignoreEntryForCredentials, groundGraph, hasDrift, identifierParts, impactOf, indexFor, ingestHostForRegionId, installAssistant, inventory, isModelReady, isTestFile, libDir, libId, loadCatalog, loadCoverage, loadEmbedder, loadGraph, loadSnapshot, localApiSurface, localPackageDocs, modelCacheInfo, nodeById, nodeEmbedText, parseDsn, parseGraph, parseJsonc, probeFreshness, publishPrivateLibrary, pushCommand, queryGraph, queryGraphSemantic, readDoc, readSavings, readScanArtifact, readUsage, recordCliCall, recordSaving, refreshIfStale, relativeResolver, renderHtml, renderReport, resolveCliInvocation, resolveDsn, resolveEmbedModel, resolveIngestHost, resolveLib, resolveLimits, resolveOne, resolveVersion, saveCatalog, savingsRecorded, scipEdges, selectForBudget, serializeGraph, serveStdio, shortestPath, stableStringify, symbolsFromApi, testsToRun, unavailableMessage, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, vibgrateDir, writeArtifacts, writeNavigationConfig, writeSnapshot, writeStoredCredentials };
7495
+ //# sourceMappingURL=chunk-D4BPWARI.js.map
7496
+ //# sourceMappingURL=chunk-D4BPWARI.js.map