@vibgrate/cli 2026.711.2 → 2026.717.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-NNU2PW2H.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-M62BGJMK.js';
3
3
  import * as fs19 from 'fs';
4
4
  import { spawnSync, execFileSync } from 'child_process';
5
5
  import * as path19 from 'path';
@@ -11,8 +11,9 @@ import betweenness from 'graphology-metrics/centrality/betweenness.js';
11
11
  import eigenvector from 'graphology-metrics/centrality/eigenvector.js';
12
12
  import louvain from 'graphology-communities-louvain';
13
13
  import * as os from 'os';
14
- import { fileURLToPath } from 'url';
14
+ import { pathToFileURL, fileURLToPath } from 'url';
15
15
  import ts from 'typescript';
16
+ import { createRequire } from 'module';
16
17
  import { bidirectional } from 'graphology-shortest-path/unweighted.js';
17
18
  import * as crypto from 'crypto';
18
19
  import { createHash } from 'crypto';
@@ -703,6 +704,73 @@ function edgeId(kind, src, dst) {
703
704
  return shortId(canonicalize({ t: "edge", kind, src, dst }));
704
705
  }
705
706
 
707
+ // src/engine/tests.ts
708
+ function isTestFile(rel2) {
709
+ const lower = rel2.toLowerCase();
710
+ const base = rel2.split("/").pop() ?? rel2;
711
+ const lbase = base.toLowerCase();
712
+ if (/(^|\/)(__tests__|__test__)\//.test(lower)) return true;
713
+ if (/(^|\/)(tests?|spec|specs)\//.test(lower)) return true;
714
+ if (/(^|\/)src\/test\//.test(lower)) return true;
715
+ if (/\.(test|spec)\.[cm]?[jt]sx?$/.test(lbase)) return true;
716
+ if (/^test_.*\.py$/.test(lbase) || /_test\.py$/.test(lbase)) return true;
717
+ if (/_test\.go$/.test(lbase)) return true;
718
+ if (/[A-Za-z0-9](Test|Tests|IT)\.java$/.test(base)) return true;
719
+ if (/_spec\.rb$/.test(lbase) || /_test\.rb$/.test(lbase)) return true;
720
+ if (/[A-Za-z0-9](Test|Tests)\.cs$/.test(base)) return true;
721
+ if (/[A-Za-z0-9](Test|Tests)\.swift$/.test(base)) return true;
722
+ return false;
723
+ }
724
+ function applyStaticTestLinkage(nodes, edges) {
725
+ const byId = new Map(nodes.map((n) => [n.id, n]));
726
+ const testFiles = /* @__PURE__ */ new Set();
727
+ for (const n of nodes) if (n.kind === "file" && isTestFile(n.file)) testFiles.add(n.file);
728
+ const fileNodeIdByRel = /* @__PURE__ */ new Map();
729
+ for (const n of nodes) if (n.kind === "file") fileNodeIdByRel.set(n.file, n.id);
730
+ const covered = /* @__PURE__ */ new Set();
731
+ const newEdges = /* @__PURE__ */ new Map();
732
+ for (const e of edges) {
733
+ if (e.kind !== "call") continue;
734
+ const src = byId.get(e.src);
735
+ const dst = byId.get(e.dst);
736
+ if (!src || !dst) continue;
737
+ if (testFiles.has(src.file) && !testFiles.has(dst.file) && dst.kind !== "external") {
738
+ const testFileId = fileNodeIdByRel.get(src.file);
739
+ if (!testFileId) continue;
740
+ const id = edgeId("test", testFileId, dst.id);
741
+ if (!newEdges.has(id)) {
742
+ newEdges.set(id, {
743
+ id,
744
+ kind: "test",
745
+ src: testFileId,
746
+ dst: dst.id,
747
+ resolution: e.resolution,
748
+ confidence: e.confidence
749
+ });
750
+ }
751
+ covered.add(dst.id);
752
+ }
753
+ }
754
+ const outNodes = nodes.map((n) => ({ ...n, tested: testedFlag(n, covered.has(n.id), testFiles) }));
755
+ const outEdges = [...edges, ...newEdges.values()].sort(
756
+ (a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
757
+ );
758
+ return {
759
+ nodes: outNodes,
760
+ edges: outEdges,
761
+ testFiles: [...testFiles].sort(),
762
+ testEdgeCount: newEdges.size
763
+ };
764
+ }
765
+ function testedFlag(node, covered, testFiles) {
766
+ if (node.kind === "external" || node.kind === "file" || node.kind === "package" || node.kind === "module") {
767
+ return null;
768
+ }
769
+ if (testFiles.has(node.file)) return null;
770
+ if (node.kind === "function" || node.kind === "method") return covered;
771
+ return covered ? true : node.tested ?? null;
772
+ }
773
+
706
774
  // src/engine/scip.ts
707
775
  var ROLE_DEFINITION = 1;
708
776
  var Reader = class {
@@ -1065,72 +1133,6 @@ function round(x) {
1065
1133
  function pairKey(a, b) {
1066
1134
  return a < b ? `${a}|${b}` : `${b}|${a}`;
1067
1135
  }
1068
-
1069
- // src/engine/tests.ts
1070
- function isTestFile(rel2) {
1071
- const lower = rel2.toLowerCase();
1072
- const base = rel2.split("/").pop() ?? rel2;
1073
- const lbase = base.toLowerCase();
1074
- if (/(^|\/)(__tests__|__test__)\//.test(lower)) return true;
1075
- if (/(^|\/)(tests?|spec|specs)\//.test(lower)) return true;
1076
- if (/(^|\/)src\/test\//.test(lower)) return true;
1077
- if (/\.(test|spec)\.[cm]?[jt]sx?$/.test(lbase)) return true;
1078
- if (/^test_.*\.py$/.test(lbase) || /_test\.py$/.test(lbase)) return true;
1079
- if (/_test\.go$/.test(lbase)) return true;
1080
- if (/[A-Za-z0-9](Test|Tests|IT)\.java$/.test(base)) return true;
1081
- if (/_spec\.rb$/.test(lbase) || /_test\.rb$/.test(lbase)) return true;
1082
- if (/[A-Za-z0-9](Test|Tests)\.cs$/.test(base)) return true;
1083
- return false;
1084
- }
1085
- function applyStaticTestLinkage(nodes, edges) {
1086
- const byId = new Map(nodes.map((n) => [n.id, n]));
1087
- const testFiles = /* @__PURE__ */ new Set();
1088
- for (const n of nodes) if (n.kind === "file" && isTestFile(n.file)) testFiles.add(n.file);
1089
- const fileNodeIdByRel = /* @__PURE__ */ new Map();
1090
- for (const n of nodes) if (n.kind === "file") fileNodeIdByRel.set(n.file, n.id);
1091
- const covered = /* @__PURE__ */ new Set();
1092
- const newEdges = /* @__PURE__ */ new Map();
1093
- for (const e of edges) {
1094
- if (e.kind !== "call") continue;
1095
- const src = byId.get(e.src);
1096
- const dst = byId.get(e.dst);
1097
- if (!src || !dst) continue;
1098
- if (testFiles.has(src.file) && !testFiles.has(dst.file) && dst.kind !== "external") {
1099
- const testFileId = fileNodeIdByRel.get(src.file);
1100
- if (!testFileId) continue;
1101
- const id = edgeId("test", testFileId, dst.id);
1102
- if (!newEdges.has(id)) {
1103
- newEdges.set(id, {
1104
- id,
1105
- kind: "test",
1106
- src: testFileId,
1107
- dst: dst.id,
1108
- resolution: e.resolution,
1109
- confidence: e.confidence
1110
- });
1111
- }
1112
- covered.add(dst.id);
1113
- }
1114
- }
1115
- const outNodes = nodes.map((n) => ({ ...n, tested: testedFlag(n, covered.has(n.id), testFiles) }));
1116
- const outEdges = [...edges, ...newEdges.values()].sort(
1117
- (a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
1118
- );
1119
- return {
1120
- nodes: outNodes,
1121
- edges: outEdges,
1122
- testFiles: [...testFiles].sort(),
1123
- testEdgeCount: newEdges.size
1124
- };
1125
- }
1126
- function testedFlag(node, covered, testFiles) {
1127
- if (node.kind === "external" || node.kind === "file" || node.kind === "package" || node.kind === "module") {
1128
- return null;
1129
- }
1130
- if (testFiles.has(node.file)) return null;
1131
- if (node.kind === "function" || node.kind === "method") return covered;
1132
- return covered ? true : node.tested ?? null;
1133
- }
1134
1136
  var DEFAULT_PATHS = [
1135
1137
  "coverage/lcov.info",
1136
1138
  "lcov.info",
@@ -1570,6 +1572,7 @@ function emptyParse(file, warning) {
1570
1572
  calls: [],
1571
1573
  imports: [],
1572
1574
  heritage: [],
1575
+ typeRefs: [],
1573
1576
  guards: [],
1574
1577
  warnings: [warning]
1575
1578
  };
@@ -1667,9 +1670,10 @@ function resolve4(parses, resolver) {
1667
1670
  const fileId = fileNodeIdByRel.get(p.rel);
1668
1671
  const localDefs = defsByFile.get(p.rel) ?? [];
1669
1672
  const imported = importedFilesByRel.get(p.rel) ?? /* @__PURE__ */ new Set();
1673
+ const testCaller = isTestFile(p.rel);
1670
1674
  for (const call of p.calls) {
1671
1675
  const srcId = enclosingDefId(localDefs, call.byte) ?? fileId;
1672
- const resolved = resolveCall(call, p.rel, p.lang, imported, defsByName, srcId);
1676
+ const resolved = resolveCall(call, p.rel, p.lang, imported, defsByName, srcId, testCaller);
1673
1677
  if (resolved) {
1674
1678
  edges.add("call", srcId, resolved.id, "heuristic", resolved.confidence);
1675
1679
  stats.callsResolved++;
@@ -1679,13 +1683,25 @@ function resolve4(parses, resolver) {
1679
1683
  }
1680
1684
  }
1681
1685
  }
1686
+ for (const p of parses) {
1687
+ const fileId = fileNodeIdByRel.get(p.rel);
1688
+ const localDefs = defsByFile.get(p.rel) ?? [];
1689
+ const imported = importedFilesByRel.get(p.rel) ?? /* @__PURE__ */ new Set();
1690
+ const testCaller = isTestFile(p.rel);
1691
+ for (const ref of p.typeRefs) {
1692
+ const srcId = enclosingDefId(localDefs, ref.byte) ?? fileId;
1693
+ const target = resolveType(ref.name, p.rel, p.lang, imported, defsByName, testCaller);
1694
+ if (target) edges.add("references", srcId, target.id, "heuristic", 0.7);
1695
+ }
1696
+ }
1682
1697
  for (const p of parses) {
1683
1698
  const localDefs = defsByFile.get(p.rel) ?? [];
1684
1699
  const imported = importedFilesByRel.get(p.rel) ?? /* @__PURE__ */ new Set();
1700
+ const testCaller = isTestFile(p.rel);
1685
1701
  for (const h of p.heritage) {
1686
1702
  const srcId = enclosingDefId(localDefs, h.byte);
1687
1703
  if (!srcId) continue;
1688
- const target = resolveType(h.superName, p.rel, p.lang, imported, defsByName);
1704
+ const target = resolveType(h.superName, p.rel, p.lang, imported, defsByName, testCaller);
1689
1705
  if (target) edges.add(h.kind, srcId, target.id, "heuristic", 0.85);
1690
1706
  else bumpUnresolved(unresolved2, srcId, h.superName, h.kind, p.rel);
1691
1707
  }
@@ -1750,7 +1766,7 @@ function dirOf(rel2) {
1750
1766
  const i = rel2.lastIndexOf("/");
1751
1767
  return i >= 0 ? rel2.slice(0, i) : "";
1752
1768
  }
1753
- function resolveCall(call, fromRel, fromLang, importedRels, defsByName, enclosingId) {
1769
+ function resolveCall(call, fromRel, fromLang, importedRels, defsByName, enclosingId, fromIsTestFile = false) {
1754
1770
  const candidates = defsByName.get(call.callee);
1755
1771
  if (!candidates || candidates.length === 0) return null;
1756
1772
  const callable = candidates.filter((c) => c.kind === "function" || c.kind === "method");
@@ -1771,9 +1787,12 @@ function resolveCall(call, fromRel, fromLang, importedRels, defsByName, enclosin
1771
1787
  if (call.qualified && enclosingId) samePkg = samePkg.filter((c) => c.id !== enclosingId);
1772
1788
  if (samePkg.length === 1) return { id: samePkg[0].id, confidence: 0.7 };
1773
1789
  }
1790
+ if (fromLang === "swift" && fromIsTestFile && pool.length === 1) {
1791
+ return { id: pool[0].id, confidence: 0.5 };
1792
+ }
1774
1793
  return null;
1775
1794
  }
1776
- function resolveType(name, fromRel, fromLang, importedRels, defsByName) {
1795
+ function resolveType(name, fromRel, fromLang, importedRels, defsByName, fromIsTestFile = false) {
1777
1796
  const candidates = (defsByName.get(name) ?? []).filter(
1778
1797
  (c) => c.kind === "class" || c.kind === "interface"
1779
1798
  );
@@ -1788,6 +1807,9 @@ function resolveType(name, fromRel, fromLang, importedRels, defsByName) {
1788
1807
  const samePkg = candidates.filter((c) => c.lang === fromLang && dirOf(c.rel) === dir);
1789
1808
  if (samePkg.length === 1) return { id: samePkg[0].id };
1790
1809
  }
1810
+ if (fromLang === "swift" && fromIsTestFile && candidates.length === 1) {
1811
+ return { id: candidates[0].id };
1812
+ }
1791
1813
  return null;
1792
1814
  }
1793
1815
  var EdgeSet = class {
@@ -2657,7 +2679,7 @@ async function loadEmbedder(options = {}) {
2657
2679
  options.onUnavailable?.(reason);
2658
2680
  return null;
2659
2681
  };
2660
- const mod = await import('fastembed').catch(() => null);
2682
+ const mod = await importEmbedBackend();
2661
2683
  if (!mod?.FlagEmbedding) return fail("not-installed");
2662
2684
  const cache = modelCacheDir();
2663
2685
  try {
@@ -2697,6 +2719,19 @@ async function loadEmbedder(options = {}) {
2697
2719
  return fail(isPermissionError(e) ? "no-permission" : "download-failed");
2698
2720
  }
2699
2721
  }
2722
+ async function importEmbedBackend() {
2723
+ const hostDir = process.env.VIBGRATE_EMBEDDER_PATH;
2724
+ if (hostDir) {
2725
+ try {
2726
+ const req = createRequire(path19.join(hostDir, "package.json"));
2727
+ const mod = await import(pathToFileURL(req.resolve("fastembed")).href);
2728
+ const resolved = mod?.FlagEmbedding ? mod : mod?.default;
2729
+ if (resolved?.FlagEmbedding) return resolved;
2730
+ } catch {
2731
+ }
2732
+ }
2733
+ return await import('fastembed').catch(() => null);
2734
+ }
2700
2735
  function embedInitTimeoutMs() {
2701
2736
  const n = Number(process.env.VG_EMBED_TIMEOUT_MS);
2702
2737
  return Number.isFinite(n) && n > 0 ? n : 6e4;
@@ -2985,13 +3020,19 @@ var GraphIndex = class {
2985
3020
  node(id) {
2986
3021
  return this.nodeById.get(id);
2987
3022
  }
2988
- /** Resolved nodes called by `id`. */
3023
+ /**
3024
+ * Resolved nodes called by `id` — invocations (`call`) plus structural
3025
+ * dependency references (`references`, e.g. a constructor-injected field's
3026
+ * type), since both represent real usage a caller/impact question cares
3027
+ * about. `references` is otherwise only emitted by the precise SCIP/tsc
3028
+ * rungs and (for Java DI wiring) the heuristic rung — never a guess.
3029
+ */
2989
3030
  callees(id) {
2990
- return this.resolveTargets(this.out(id, "call"), "dst");
3031
+ return this.resolveTargets(this.out(id).filter(isUsageEdge), "dst");
2991
3032
  }
2992
- /** Resolved nodes that call `id`. */
3033
+ /** Resolved nodes that call or structurally reference `id`. */
2993
3034
  callers(id) {
2994
- return this.resolveTargets(this.in(id, "call"), "src");
3035
+ return this.resolveTargets(this.in(id).filter(isUsageEdge), "src");
2995
3036
  }
2996
3037
  resolveTargets(edges, end) {
2997
3038
  const out = [];
@@ -3002,6 +3043,10 @@ var GraphIndex = class {
3002
3043
  return out;
3003
3044
  }
3004
3045
  };
3046
+ var USAGE_KINDS = /* @__PURE__ */ new Set(["call", "references"]);
3047
+ function isUsageEdge(e) {
3048
+ return USAGE_KINDS.has(e.kind);
3049
+ }
3005
3050
  function push2(map, key, value) {
3006
3051
  const list = map.get(key);
3007
3052
  if (list) list.push(value);
@@ -3059,7 +3104,26 @@ var STOPWORDS = /* @__PURE__ */ new Set([
3059
3104
  "from",
3060
3105
  "by",
3061
3106
  "at",
3062
- "as"
3107
+ "as",
3108
+ // Discovery-question scaffolding: words a caller uses to FRAME the ask
3109
+ // ("find the code responsible for X", "I need to modify X, where do I
3110
+ // start?", "explain how X works in this codebase") rather than to name the
3111
+ // target. Left in, these compete on equal footing with the real identifier
3112
+ // terms and can outrank it outright — e.g. "find the code responsible for
3113
+ // deleteAsync" let "find" alone drag in every FindByIdAsync/FindAll method
3114
+ // in the repo, none of them the target (VG-LOCATE-FAILURE-ANALYSIS.md).
3115
+ "find",
3116
+ "code",
3117
+ "responsible",
3118
+ "need",
3119
+ "modify",
3120
+ "me",
3121
+ "implementation",
3122
+ "explain",
3123
+ "works",
3124
+ "codebase",
3125
+ "contains",
3126
+ "file"
3063
3127
  ]);
3064
3128
  function queryGraph(graph, question, options = {}) {
3065
3129
  const budget = options.budget ?? 2e3;
@@ -3115,7 +3179,7 @@ async function queryGraphSemantic(graph, question, options) {
3115
3179
  function tokenize(q2) {
3116
3180
  return [
3117
3181
  ...new Set(
3118
- q2.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 2 && !STOPWORDS.has(t))
3182
+ q2.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 1 && !STOPWORDS.has(t))
3119
3183
  )
3120
3184
  ];
3121
3185
  }
@@ -3173,7 +3237,7 @@ function termWeights(graph, terms) {
3173
3237
  }
3174
3238
  function identifierParts(name) {
3175
3239
  return new Set(
3176
- name.split(/[^a-zA-Z0-9]+|(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/).filter(Boolean).map((s) => s.toLowerCase())
3240
+ name.split(/[^\p{L}\p{N}]+|(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/u).filter(Boolean).map((s) => s.toLowerCase())
3177
3241
  );
3178
3242
  }
3179
3243
  function fuzzyPartMatch(term, parts) {
@@ -4938,6 +5002,20 @@ function dedupeRoutes(routes) {
4938
5002
  // src/reporting/utils/compact-artifact.ts
4939
5003
  var gzip2 = promisify(zlib.gzip);
4940
5004
  var MAX_ITEMS = 50;
5005
+ var MAX_DB_MODELS = 300;
5006
+ var MAX_DB_FIELDS_PER_MODEL = 100;
5007
+ var MAX_DB_MODEL_FILES = 5;
5008
+ var MAX_DB_FILES_SCANNED = 500;
5009
+ var DB_UPLOAD_HARD_CEILING = {
5010
+ maxModels: 2e3,
5011
+ maxFieldsPerModel: 500,
5012
+ maxFilesPerModel: 20,
5013
+ maxFilesScanned: 5e3
5014
+ };
5015
+ function clampCap(configured, fallback, ceiling) {
5016
+ if (typeof configured !== "number" || !Number.isFinite(configured) || configured <= 0) return fallback;
5017
+ return Math.min(Math.floor(configured), ceiling);
5018
+ }
4941
5019
  function extractName(entry) {
4942
5020
  const match = entry.match(/^(.+?)\s*\(/);
4943
5021
  return match ? match[1].trim() : entry.trim();
@@ -5003,7 +5081,29 @@ function compactAssetBranding(result) {
5003
5081
  // Don't include logos
5004
5082
  };
5005
5083
  }
5006
- function prepareArtifactForUpload(artifact) {
5084
+ function compactDatabaseSchema(result, caps) {
5085
+ const maxModels = clampCap(caps?.maxModels, MAX_DB_MODELS, DB_UPLOAD_HARD_CEILING.maxModels);
5086
+ const maxFieldsPerModel = clampCap(caps?.maxFieldsPerModel, MAX_DB_FIELDS_PER_MODEL, DB_UPLOAD_HARD_CEILING.maxFieldsPerModel);
5087
+ const maxFilesPerModel = clampCap(caps?.maxFilesPerModel, MAX_DB_MODEL_FILES, DB_UPLOAD_HARD_CEILING.maxFilesPerModel);
5088
+ const maxFilesScanned = clampCap(caps?.maxFilesScanned, MAX_DB_FILES_SCANNED, DB_UPLOAD_HARD_CEILING.maxFilesScanned);
5089
+ return {
5090
+ providers: result.providers.slice(0, MAX_ITEMS),
5091
+ models: result.models.slice(0, maxModels).map((model) => ({
5092
+ ...model,
5093
+ fields: model.fields.slice(0, maxFieldsPerModel),
5094
+ files: model.files.slice(0, maxFilesPerModel)
5095
+ })),
5096
+ enums: result.enums.slice(0, MAX_ITEMS),
5097
+ filesScanned: result.filesScanned.slice(0, maxFilesScanned),
5098
+ projects: result.projects.slice(0, MAX_ITEMS).map((project) => ({
5099
+ project: project.project,
5100
+ filesScanned: project.filesScanned.slice(0, MAX_ITEMS),
5101
+ models: project.models.slice(0, MAX_ITEMS),
5102
+ enums: project.enums.slice(0, MAX_ITEMS)
5103
+ }))
5104
+ };
5105
+ }
5106
+ function prepareArtifactForUpload(artifact, opts) {
5007
5107
  const compacted = { ...artifact };
5008
5108
  if (compacted.extended) {
5009
5109
  const ext = { ...compacted.extended };
@@ -5079,6 +5179,9 @@ function prepareArtifactForUpload(artifact) {
5079
5179
  duplicatedPackages: ext.dependencyGraph.duplicatedPackages.slice(0, MAX_ITEMS)
5080
5180
  };
5081
5181
  }
5182
+ if (ext.databaseSchema) {
5183
+ ext.databaseSchema = compactDatabaseSchema(ext.databaseSchema, opts?.databaseSchemaCaps);
5184
+ }
5082
5185
  compacted.extended = ext;
5083
5186
  }
5084
5187
  return compacted;
@@ -5087,8 +5190,8 @@ async function compressArtifact(artifact) {
5087
5190
  const json = JSON.stringify(artifact);
5088
5191
  return gzip2(json, { level: 9 });
5089
5192
  }
5090
- async function prepareCompressedUpload(artifact) {
5091
- const compacted = prepareArtifactForUpload(artifact);
5193
+ async function prepareCompressedUpload(artifact, opts) {
5194
+ const compacted = prepareArtifactForUpload(artifact, opts);
5092
5195
  const compressed = await compressArtifact(compacted);
5093
5196
  return { body: compressed, contentEncoding: "gzip" };
5094
5197
  }
@@ -5101,8 +5204,9 @@ function postOnce(input, host) {
5101
5204
  "Content-Encoding": input.contentEncoding,
5102
5205
  "X-Vibgrate-Timestamp": input.timestamp,
5103
5206
  "Authorization": `VibgrateDSN ${input.keyId}:${input.secret}`,
5104
- "Connection": "close"
5207
+ "Connection": "close",
5105
5208
  // Prevent keep-alive delays on exit
5209
+ ...input.runId && input.runToken ? { "X-Vibgrate-Run-Id": input.runId, "X-Vibgrate-Run-Token": input.runToken } : {}
5106
5210
  },
5107
5211
  body: input.body
5108
5212
  });
@@ -5170,7 +5274,9 @@ var pushCommand = new Command("push").description("Push scan results to Vibgrate
5170
5274
  return;
5171
5275
  }
5172
5276
  const artifact = await readJsonFile(filePath);
5173
- const { body, contentEncoding } = await prepareCompressedUpload(artifact);
5277
+ const config = await loadConfig(process.cwd());
5278
+ const databaseSchemaCaps = config.scanners !== false ? config.scanners?.databaseSchema : void 0;
5279
+ const { body, contentEncoding } = await prepareCompressedUpload(artifact, { databaseSchemaCaps });
5174
5280
  const timestamp = String(Date.now());
5175
5281
  let host = parsed.host;
5176
5282
  if (opts.region) {
@@ -5194,7 +5300,11 @@ var pushCommand = new Command("push").description("Push scan results to Vibgrate
5194
5300
  secret: parsed.secret,
5195
5301
  body,
5196
5302
  contentEncoding,
5197
- timestamp
5303
+ timestamp,
5304
+ // Set only by an automated caller running the scan on the workspace's
5305
+ // behalf (e.g. a Vibgrate-hosted remediation run) — never a customer flag.
5306
+ runId: process.env.VIBGRATE_SCAN_RUN_ID,
5307
+ runToken: process.env.VIBGRATE_SCAN_RUN_TOKEN
5198
5308
  });
5199
5309
  host = uploadedHost;
5200
5310
  if (!response.ok) {
@@ -5885,6 +5995,9 @@ async function searchSymbols(graph, root, query, limit) {
5885
5995
  if (!q2) return { matches: [], moreAvailable: false, hint: "query is required" };
5886
5996
  const isPhrase = /\s/.test(q2);
5887
5997
  let nodes = findNodes(graph, q2).filter((n) => n.kind !== "file");
5998
+ if (nodes.length === 0 && isPhrase) {
5999
+ nodes = reconstructedIdentifierNodes(graph, q2);
6000
+ }
5888
6001
  if (nodes.length === 0) {
5889
6002
  const tokens = queryTokens(q2);
5890
6003
  if (tokens.length >= 2) nodes = multiTokenNodes(graph, tokens);
@@ -5927,6 +6040,14 @@ async function searchSymbols(graph, root, query, limit) {
5927
6040
  function queryTokens(q2) {
5928
6041
  return [...new Set(q2.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 2))];
5929
6042
  }
6043
+ function reconstructedIdentifierNodes(graph, q2) {
6044
+ const words = q2.trim().split(/\s+/).filter(Boolean);
6045
+ if (words.length < 2) return [];
6046
+ const concat = findNodes(graph, words.join(""));
6047
+ if (concat.length) return concat.filter((n) => n.kind !== "file");
6048
+ const snake = findNodes(graph, words.join("_"));
6049
+ return snake.filter((n) => n.kind !== "file");
6050
+ }
5930
6051
  function multiTokenNodes(graph, tokens) {
5931
6052
  const cov = /* @__PURE__ */ new Map();
5932
6053
  for (const t of tokens) {
@@ -6971,60 +7092,96 @@ var ASSISTANTS = [
6971
7092
  label: "Claude Code",
6972
7093
  skill: ".claude/skills/vg/SKILL.md",
6973
7094
  mcp: { file: ".mcp.json", key: "mcpServers" },
6974
- nudge: { file: "CLAUDE.md", kind: "block" }
7095
+ nudge: { file: "CLAUDE.md", kind: "block" },
7096
+ markers: ["CLAUDE.md", ".claude"],
7097
+ homeMarkers: [".claude", ".claude.json"],
7098
+ bin: ["claude"]
6975
7099
  },
6976
7100
  {
6977
7101
  id: "cursor",
6978
7102
  label: "Cursor",
6979
7103
  mcp: { file: ".cursor/mcp.json", key: "mcpServers" },
6980
- nudge: { file: ".cursor/rules/vg.mdc", kind: "file" }
7104
+ nudge: { file: ".cursor/rules/vg.mdc", kind: "file" },
7105
+ markers: [".cursor", ".cursorrules"],
7106
+ homeMarkers: [".cursor"],
7107
+ bin: ["cursor-agent"]
6981
7108
  },
6982
7109
  {
6983
7110
  id: "windsurf",
6984
7111
  label: "Windsurf",
6985
7112
  mcp: { file: ".windsurf/mcp.json", key: "mcpServers" },
6986
- nudge: { file: ".windsurf/rules/vg.md", kind: "file" }
7113
+ nudge: { file: ".windsurf/rules/vg.md", kind: "file" },
7114
+ markers: [".windsurf", ".windsurfrules"],
7115
+ homeMarkers: [".codeium/windsurf"]
6987
7116
  },
6988
7117
  {
6989
7118
  id: "vscode",
6990
7119
  label: "VS Code (Copilot Chat)",
6991
7120
  mcp: { file: ".vscode/mcp.json", key: "servers", vscode: true },
6992
- nudge: { file: ".github/copilot-instructions.md", kind: "block" }
7121
+ nudge: { file: ".github/copilot-instructions.md", kind: "block" },
7122
+ markers: [".github/copilot-instructions.md"]
6993
7123
  },
6994
7124
  {
6995
7125
  id: "codex",
6996
7126
  label: "Codex",
6997
7127
  skill: ".codex/skills/vg/SKILL.md",
6998
- nudge: { file: "AGENTS.md", kind: "block" }
7128
+ nudge: { file: "AGENTS.md", kind: "block" },
7129
+ markers: [".codex"],
7130
+ homeMarkers: [".codex"],
7131
+ bin: ["codex"]
6999
7132
  },
7000
7133
  {
7001
7134
  id: "gemini",
7002
7135
  label: "Gemini CLI",
7003
7136
  skill: ".gemini/skills/vg/SKILL.md",
7004
- nudge: { file: "GEMINI.md", kind: "block" }
7137
+ nudge: { file: "GEMINI.md", kind: "block" },
7138
+ markers: ["GEMINI.md", ".gemini"],
7139
+ homeMarkers: [".gemini"],
7140
+ bin: ["gemini"]
7005
7141
  },
7006
7142
  // Skill + advisory AGENTS.md nudge (the broad-reach common denominator). MCP
7007
7143
  // registration for these hosts is host-specific and added as their formats
7008
7144
  // stabilise; the skill + nudge work today.
7009
- { id: "opencode", label: "OpenCode", skill: ".opencode/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7010
- { id: "kilo", label: "Kilo Code", skill: ".kilo/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7011
- { id: "aider", label: "Aider", skill: ".aider/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7012
- { id: "factory", label: "Factory Droid", skill: ".factory/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7013
- { id: "trae", label: "Trae", skill: ".trae/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7014
- { id: "kiro", label: "Kiro", skill: ".kiro/skills/vg/SKILL.md", nudge: { file: ".kiro/steering/vg.md", kind: "file" } },
7015
- { id: "amp", label: "Amp", skill: ".agents/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7016
- { id: "kimi", label: "Kimi Code", skill: ".kimi/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7017
- { id: "codebuddy", label: "CodeBuddy", skill: ".codebuddy/skills/vg/SKILL.md", nudge: { file: "CODEBUDDY.md", kind: "block" } },
7018
- { id: "copilot-cli", label: "GitHub Copilot CLI", skill: ".copilot/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7019
- { id: "pi", label: "Pi", skill: ".pi/agent/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7020
- { id: "devin", label: "Devin CLI", skill: ".devin/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7021
- { id: "hermes", label: "Hermes", skill: ".hermes/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7022
- { id: "openclaw", label: "OpenClaw", skill: ".openclaw/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } },
7023
- { id: "agents", label: "Agent-Skills (generic)", skill: ".agents/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" } }
7145
+ { id: "grok", label: "Grok CLI", skill: ".grok/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".grok", "GROK.md"], homeMarkers: [".grok"], bin: ["grok"] },
7146
+ { id: "opencode", label: "OpenCode", skill: ".opencode/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".opencode", "opencode.json"], homeMarkers: [".config/opencode"], bin: ["opencode"] },
7147
+ { id: "kilo", label: "Kilo Code", skill: ".kilo/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".kilo", ".kilocode"], homeMarkers: [".kilocode"] },
7148
+ { id: "aider", label: "Aider", skill: ".aider/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".aider", ".aider.conf.yml"], homeMarkers: [".aider.conf.yml"], bin: ["aider"] },
7149
+ { id: "factory", label: "Factory Droid", skill: ".factory/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".factory"], homeMarkers: [".factory"], bin: ["droid"] },
7150
+ { id: "trae", label: "Trae", skill: ".trae/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".trae"], homeMarkers: [".trae"] },
7151
+ { id: "kiro", label: "Kiro", skill: ".kiro/skills/vg/SKILL.md", nudge: { file: ".kiro/steering/vg.md", kind: "file" }, markers: [".kiro"], homeMarkers: [".kiro"] },
7152
+ { id: "amp", label: "Amp", skill: ".agents/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, homeMarkers: [".config/amp"], bin: ["amp"] },
7153
+ { id: "kimi", label: "Kimi Code", skill: ".kimi/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".kimi"], homeMarkers: [".kimi"] },
7154
+ { id: "codebuddy", label: "CodeBuddy", skill: ".codebuddy/skills/vg/SKILL.md", nudge: { file: "CODEBUDDY.md", kind: "block" }, markers: ["CODEBUDDY.md", ".codebuddy"], homeMarkers: [".codebuddy"] },
7155
+ { id: "copilot-cli", label: "GitHub Copilot CLI", skill: ".copilot/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".copilot"], homeMarkers: [".copilot"], bin: ["copilot"] },
7156
+ { id: "pi", label: "Pi", skill: ".pi/agent/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".pi"], homeMarkers: [".pi"] },
7157
+ { id: "devin", label: "Devin CLI", skill: ".devin/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".devin"], homeMarkers: [".devin"] },
7158
+ { id: "hermes", label: "Hermes", skill: ".hermes/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".hermes"], homeMarkers: [".hermes"] },
7159
+ { id: "openclaw", label: "OpenClaw", skill: ".openclaw/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: [".openclaw"], homeMarkers: [".openclaw"], bin: ["openclaw"] },
7160
+ { id: "agents", label: "Agent-Skills (generic)", skill: ".agents/skills/vg/SKILL.md", nudge: { file: "AGENTS.md", kind: "block" }, markers: ["AGENTS.md", ".agents"] }
7024
7161
  ];
7025
7162
  function assistantById(id) {
7026
7163
  return ASSISTANTS.find((a) => a.id === id);
7027
7164
  }
7165
+ function detectAssistants(root, opts = {}) {
7166
+ const home = opts.home ?? os.homedir();
7167
+ const which = opts.which ?? whichOnPath;
7168
+ const found = [];
7169
+ for (const assistant of ASSISTANTS) {
7170
+ const repoHit = (assistant.markers ?? []).find((m) => fs19.existsSync(path19.join(root, m)));
7171
+ if (repoHit) {
7172
+ found.push({ assistant, via: "repo", marker: repoHit });
7173
+ continue;
7174
+ }
7175
+ const homeHit = (assistant.homeMarkers ?? []).find((m) => fs19.existsSync(path19.join(home, m)));
7176
+ if (homeHit) {
7177
+ found.push({ assistant, via: "home", marker: homeHit });
7178
+ continue;
7179
+ }
7180
+ const binHit = (assistant.bin ?? []).find((b) => which(b) !== null);
7181
+ if (binHit) found.push({ assistant, via: "path", marker: binHit });
7182
+ }
7183
+ return found;
7184
+ }
7028
7185
  function detectServeLaunch(which = whichOnPath) {
7029
7186
  const vg = which("vg");
7030
7187
  if (vg && isInstalledOwnBinary(vg)) return { command: "vg", args: ["serve"] };
@@ -7384,6 +7541,6 @@ function spdx(ctx) {
7384
7541
  return JSON.stringify(doc, null, 2) + "\n";
7385
7542
  }
7386
7543
 
7387
- 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 };
7388
- //# sourceMappingURL=chunk-75ZJYYJE.js.map
7389
- //# sourceMappingURL=chunk-75ZJYYJE.js.map
7544
+ 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, detectAssistants, 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 };
7545
+ //# sourceMappingURL=chunk-L42NVMD6.js.map
7546
+ //# sourceMappingURL=chunk-L42NVMD6.js.map