@vibgrate/cli 2026.728.3 → 2026.728.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 (131) hide show
  1. package/dist/baseline-QD4HVNVJ.js +8 -0
  2. package/dist/{baseline-PPZJBYAJ.js.map → baseline-QD4HVNVJ.js.map} +1 -1
  3. package/dist/{chunk-A2IYFNCQ.js → chunk-2ZHWF7C6.js} +227 -19
  4. package/dist/chunk-2ZHWF7C6.js.map +1 -0
  5. package/dist/{chunk-UZJS7GMK.js → chunk-3LSG7Z4I.js} +10 -6
  6. package/dist/chunk-3LSG7Z4I.js.map +1 -0
  7. package/dist/{chunk-R2QNFXE5.js → chunk-DBOT2ELH.js} +3 -3
  8. package/dist/{chunk-R2QNFXE5.js.map → chunk-DBOT2ELH.js.map} +1 -1
  9. package/dist/{chunk-6UK6QPTR.js → chunk-EETK7S43.js} +137 -34
  10. package/dist/chunk-EETK7S43.js.map +1 -0
  11. package/dist/{chunk-JRAGO6OB.js → chunk-EVWW3BPM.js} +4 -4
  12. package/dist/{chunk-JRAGO6OB.js.map → chunk-EVWW3BPM.js.map} +1 -1
  13. package/dist/chunk-G4HTI4ZM.js +1537 -0
  14. package/dist/chunk-G4HTI4ZM.js.map +1 -0
  15. package/dist/{chunk-VYGEOOLY.js → chunk-HY2RVURA.js} +3 -3
  16. package/dist/{chunk-VYGEOOLY.js.map → chunk-HY2RVURA.js.map} +1 -1
  17. package/dist/chunk-IPICO2RV.js +789 -0
  18. package/dist/chunk-IPICO2RV.js.map +1 -0
  19. package/dist/{chunk-6GRLZ4Z2.js → chunk-LYDH2PHN.js} +8 -8
  20. package/dist/{chunk-6GRLZ4Z2.js.map → chunk-LYDH2PHN.js.map} +1 -1
  21. package/dist/{chunk-6UQMXIAG.js → chunk-OWSFZQOP.js} +62 -12
  22. package/dist/chunk-OWSFZQOP.js.map +1 -0
  23. package/dist/{chunk-WH2N22S3.js → chunk-PRGCCW7D.js} +4 -4
  24. package/dist/{chunk-WH2N22S3.js.map → chunk-PRGCCW7D.js.map} +1 -1
  25. package/dist/{chunk-3BIRGSRS.js → chunk-RCBMY7CR.js} +11 -11
  26. package/dist/{chunk-3BIRGSRS.js.map → chunk-RCBMY7CR.js.map} +1 -1
  27. package/dist/{chunk-OSD546W7.js → chunk-REIGWTTH.js} +5 -3
  28. package/dist/chunk-REIGWTTH.js.map +1 -0
  29. package/dist/{chunk-B3YUO3NW.js → chunk-RYNAK4LK.js} +3 -3
  30. package/dist/{chunk-B3YUO3NW.js.map → chunk-RYNAK4LK.js.map} +1 -1
  31. package/dist/{chunk-YF43FOPP.js → chunk-RZEXHDCF.js} +33 -14
  32. package/dist/chunk-RZEXHDCF.js.map +1 -0
  33. package/dist/chunk-SA4BMEU6.js +2184 -0
  34. package/dist/chunk-SA4BMEU6.js.map +1 -0
  35. package/dist/{chunk-HK3AWUXH.js → chunk-TCJTQGAO.js} +3 -3
  36. package/dist/{chunk-HK3AWUXH.js.map → chunk-TCJTQGAO.js.map} +1 -1
  37. package/dist/{chunk-ZBTY6VV4.js → chunk-US2DAKCM.js} +15 -5
  38. package/dist/chunk-US2DAKCM.js.map +1 -0
  39. package/dist/{chunk-ON25BX6T.js → chunk-UTNNGKKX.js} +3 -3
  40. package/dist/{chunk-ON25BX6T.js.map → chunk-UTNNGKKX.js.map} +1 -1
  41. package/dist/chunk-WDJNUC6V.js +3059 -0
  42. package/dist/chunk-WDJNUC6V.js.map +1 -0
  43. package/dist/{chunk-SZSNPXSW.js → chunk-WHJMS7XC.js} +3 -3
  44. package/dist/{chunk-SZSNPXSW.js.map → chunk-WHJMS7XC.js.map} +1 -1
  45. package/dist/chunk-Z6ZWNWWR.js +30 -0
  46. package/dist/{chunk-DGUM43GV.js.map → chunk-Z6ZWNWWR.js.map} +1 -1
  47. package/dist/{chunk-VI4ITXHQ.js → chunk-ZU7VD4QL.js} +7 -6
  48. package/dist/chunk-ZU7VD4QL.js.map +1 -0
  49. package/dist/cli.js +158 -71
  50. package/dist/cli.js.map +1 -1
  51. package/dist/{execution-env-ZU45JZ4G.js → execution-env-4MS5AYAN.js} +3 -3
  52. package/dist/{execution-env-ZU45JZ4G.js.map → execution-env-4MS5AYAN.js.map} +1 -1
  53. package/dist/{federation-SZWZIFZ7.js → federation-MDQPO3PW.js} +3 -3
  54. package/dist/{federation-SZWZIFZ7.js.map → federation-MDQPO3PW.js.map} +1 -1
  55. package/dist/{fs-O5IQYXHO.js → fs-4G5A65KS.js} +3 -3
  56. package/dist/fs-4G5A65KS.js.map +1 -0
  57. package/dist/{fs-B5HZ2MIU.js → fs-6JKZNQ3U.js} +3 -3
  58. package/dist/fs-6JKZNQ3U.js.map +1 -0
  59. package/dist/{git-ref-XDXB6JP5.js → git-ref-RSRAN4OH.js} +3 -3
  60. package/dist/{git-ref-XDXB6JP5.js.map → git-ref-RSRAN4OH.js.map} +1 -1
  61. package/dist/{graph-backend-UTOL3SHE.js → graph-backend-GBL33GMW.js} +5 -5
  62. package/dist/{graph-backend-UTOL3SHE.js.map → graph-backend-GBL33GMW.js.map} +1 -1
  63. package/dist/index.d.ts +3 -2
  64. package/dist/index.js +12 -10
  65. package/dist/index.js.map +1 -1
  66. package/dist/{interactive-OCWQ326U.js → interactive-32LSIBRG.js} +45 -24
  67. package/dist/interactive-32LSIBRG.js.map +1 -0
  68. package/dist/{llm-host-XYBT4267.js → llm-host-5RE34322.js} +3 -3
  69. package/dist/{llm-host-XYBT4267.js.map → llm-host-5RE34322.js.map} +1 -1
  70. package/dist/load-SEFJA3M5.js +8 -0
  71. package/dist/{load-QPOWQD7C.js.map → load-SEFJA3M5.js.map} +1 -1
  72. package/dist/local-runtime-2ED33KK6.js +6 -0
  73. package/dist/{local-runtime-5O2NN3GA.js.map → local-runtime-2ED33KK6.js.map} +1 -1
  74. package/dist/mcp-tools-KAJS34TN.js +4 -0
  75. package/dist/{mcp-tools-I7JK3S2M.js.map → mcp-tools-KAJS34TN.js.map} +1 -1
  76. package/dist/{model-execution-profile-TFBKCNJG.js → model-execution-profile-ELWF3Z6H.js} +3 -3
  77. package/dist/{model-execution-profile-TFBKCNJG.js.map → model-execution-profile-ELWF3Z6H.js.map} +1 -1
  78. package/dist/model-manager-GJ2YSTSK.js +10 -0
  79. package/dist/{model-manager-LB54VSV7.js.map → model-manager-GJ2YSTSK.js.map} +1 -1
  80. package/dist/{model-orchestrator-4M5FG6MN.js → model-orchestrator-LHYPJBFH.js} +3 -3
  81. package/dist/{model-orchestrator-4M5FG6MN.js.map → model-orchestrator-LHYPJBFH.js.map} +1 -1
  82. package/dist/parse-worker.js +2 -2
  83. package/dist/{paths-2RAH3GME.js → paths-62AKTFSR.js} +3 -3
  84. package/dist/{paths-2RAH3GME.js.map → paths-62AKTFSR.js.map} +1 -1
  85. package/dist/{resolve-gguf-4AFRN4CP.js → resolve-gguf-SDIYGGI6.js} +3 -3
  86. package/dist/{resolve-gguf-4AFRN4CP.js.map → resolve-gguf-SDIYGGI6.js.map} +1 -1
  87. package/dist/{runtime-session-EJQZXANB.js → runtime-session-4IACVDSY.js} +7 -7
  88. package/dist/{runtime-session-EJQZXANB.js.map → runtime-session-4IACVDSY.js.map} +1 -1
  89. package/dist/session-2JT4AUZT.js +13 -0
  90. package/dist/{session-ZJGENHKX.js.map → session-2JT4AUZT.js.map} +1 -1
  91. package/dist/session-store-O4XPXKOV.js +4 -0
  92. package/dist/{session-store-WFBX7HXL.js.map → session-store-O4XPXKOV.js.map} +1 -1
  93. package/dist/{sql-extract-JELDZA6W.js → sql-extract-6UJOLJDL.js} +3 -3
  94. package/dist/{sql-extract-JELDZA6W.js.map → sql-extract-6UJOLJDL.js.map} +1 -1
  95. package/dist/stream-json-Y45JBNYP.js +112 -0
  96. package/dist/stream-json-Y45JBNYP.js.map +1 -0
  97. package/dist/ui-K7D3BCHD.js +5 -0
  98. package/dist/ui-K7D3BCHD.js.map +1 -0
  99. package/dist/vg-mcp-bridge-E4SJFL7Q.js +75 -0
  100. package/dist/vg-mcp-bridge-E4SJFL7Q.js.map +1 -0
  101. package/dist/{vgd-3MHSB4KA.js → vgd-KDQFS33M.js} +6 -6
  102. package/dist/vgd-KDQFS33M.js.map +1 -0
  103. package/package.json +1 -1
  104. package/dist/baseline-PPZJBYAJ.js +0 -8
  105. package/dist/chunk-57QU36P6.js +0 -5645
  106. package/dist/chunk-57QU36P6.js.map +0 -1
  107. package/dist/chunk-6AXHLQBV.js +0 -1892
  108. package/dist/chunk-6AXHLQBV.js.map +0 -1
  109. package/dist/chunk-6UK6QPTR.js.map +0 -1
  110. package/dist/chunk-6UQMXIAG.js.map +0 -1
  111. package/dist/chunk-A2IYFNCQ.js.map +0 -1
  112. package/dist/chunk-DGUM43GV.js +0 -10
  113. package/dist/chunk-OSD546W7.js.map +0 -1
  114. package/dist/chunk-UZJS7GMK.js.map +0 -1
  115. package/dist/chunk-VI4ITXHQ.js.map +0 -1
  116. package/dist/chunk-YF43FOPP.js.map +0 -1
  117. package/dist/chunk-ZBTY6VV4.js.map +0 -1
  118. package/dist/fs-B5HZ2MIU.js.map +0 -1
  119. package/dist/fs-O5IQYXHO.js.map +0 -1
  120. package/dist/interactive-OCWQ326U.js.map +0 -1
  121. package/dist/load-QPOWQD7C.js +0 -8
  122. package/dist/local-runtime-5O2NN3GA.js +0 -5
  123. package/dist/mcp-tools-I7JK3S2M.js +0 -4
  124. package/dist/model-manager-LB54VSV7.js +0 -10
  125. package/dist/session-ZJGENHKX.js +0 -13
  126. package/dist/session-store-WFBX7HXL.js +0 -4
  127. package/dist/stream-json-Z5KC2DM3.js +0 -78
  128. package/dist/stream-json-Z5KC2DM3.js.map +0 -1
  129. package/dist/ui-Q6DJ3GCU.js +0 -5
  130. package/dist/ui-Q6DJ3GCU.js.map +0 -1
  131. package/dist/vgd-3MHSB4KA.js.map +0 -1
@@ -0,0 +1,1537 @@
1
+ import { findNodes } from './chunk-J7LKEB2R.js';
2
+ import { extractLiteralNeedles, residualForSymbolSearch } from './chunk-EETK7S43.js';
3
+ import { stableStringify } from './chunk-ZKNB4YH4.js';
4
+ import { hashString } from './chunk-JFGYT6BI.js';
5
+ import * as fs3 from 'fs';
6
+ import * as path3 from 'path';
7
+ import * as os from 'os';
8
+ import { execFileSync, spawnSync } from 'child_process';
9
+ import { Worker } from 'worker_threads';
10
+
11
+ var ECOSYSTEMS = ["npm", "pypi", "go", "rust", "ruby", "php", "dotnet", "swift", "dart", "java"];
12
+ function inventory(root) {
13
+ const manifests = findManifests(root);
14
+ const records = [];
15
+ records.push(...npmDeps(manifests.npm));
16
+ records.push(...pypiDeps(manifests.pypi));
17
+ records.push(...goDeps(manifests.go));
18
+ records.push(...cargoDeps(manifests.rust));
19
+ records.push(...rubyDeps(manifests.ruby));
20
+ records.push(...phpDeps(manifests.php));
21
+ records.push(...dotnetDeps(manifests.dotnet));
22
+ records.push(...swiftDeps(manifests.swift));
23
+ records.push(...dartDeps(manifests.dart));
24
+ records.push(...javaDeps(manifests.java));
25
+ const seen = /* @__PURE__ */ new Set();
26
+ const deduped = records.filter((r) => {
27
+ const key = `${r.ecosystem}\0${r.name}`;
28
+ if (seen.has(key)) return false;
29
+ seen.add(key);
30
+ return true;
31
+ });
32
+ deduped.sort((a, b) => a.ecosystem.localeCompare(b.ecosystem) || a.name.localeCompare(b.name));
33
+ const counts = { total: deduped.length };
34
+ for (const e of ECOSYSTEMS) counts[e] = 0;
35
+ for (const r of deduped) counts[r.ecosystem]++;
36
+ return { records: deduped, counts };
37
+ }
38
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
39
+ "node_modules",
40
+ ".git",
41
+ "dist",
42
+ "build",
43
+ "out",
44
+ ".vibgrate",
45
+ "vendor",
46
+ ".venv",
47
+ "venv",
48
+ "env",
49
+ "__pycache__",
50
+ "target",
51
+ ".next",
52
+ ".nuxt",
53
+ "coverage",
54
+ ".cache"
55
+ ]);
56
+ var MANIFEST_BY_FILE = {
57
+ "package.json": "npm",
58
+ "requirements.txt": "pypi",
59
+ "pyproject.toml": "pypi",
60
+ "go.mod": "go",
61
+ "Cargo.toml": "rust",
62
+ Gemfile: "ruby",
63
+ "composer.json": "php",
64
+ "Package.swift": "swift",
65
+ "pubspec.yaml": "dart",
66
+ "pom.xml": "java",
67
+ "build.gradle": "java",
68
+ "build.gradle.kts": "java"
69
+ };
70
+ function findManifests(root) {
71
+ const set = Object.fromEntries(ECOSYSTEMS.map((e) => [e, []]));
72
+ const MAX_ENTRIES = 2e4;
73
+ let scanned = 0;
74
+ const walk = (dir, depth) => {
75
+ if (depth > 8 || scanned > MAX_ENTRIES) return;
76
+ let entries;
77
+ try {
78
+ entries = fs3.readdirSync(dir, { withFileTypes: true });
79
+ } catch {
80
+ return;
81
+ }
82
+ for (const e of entries) {
83
+ scanned++;
84
+ if (scanned > MAX_ENTRIES) break;
85
+ if (e.isDirectory()) {
86
+ if (!SKIP_DIRS.has(e.name) && !e.name.startsWith(".")) walk(path3.join(dir, e.name), depth + 1);
87
+ continue;
88
+ }
89
+ const eco = MANIFEST_BY_FILE[e.name] ?? (/\.(cs|fs)proj$/i.test(e.name) ? "dotnet" : void 0);
90
+ if (eco) set[eco].push(path3.join(dir, e.name));
91
+ }
92
+ };
93
+ walk(root, 0);
94
+ for (const e of ECOSYSTEMS) set[e].sort();
95
+ return set;
96
+ }
97
+ function npmDeps(files) {
98
+ const out = [];
99
+ for (const file of files) {
100
+ let pkg;
101
+ try {
102
+ pkg = JSON.parse(fs3.readFileSync(file, "utf8"));
103
+ } catch {
104
+ continue;
105
+ }
106
+ const dir = path3.dirname(file);
107
+ const all = { ...pkg.dependencies, ...pkg.devDependencies };
108
+ for (const [name, declared] of Object.entries(all)) {
109
+ out.push({ name, ecosystem: "npm", declared, installed: installedNpmVersion(dir, name) });
110
+ }
111
+ }
112
+ return out;
113
+ }
114
+ function installedNpmVersion(dir, name) {
115
+ let cur = dir;
116
+ for (let i = 0; i < 12; i++) {
117
+ const p = path3.join(cur, "node_modules", name, "package.json");
118
+ try {
119
+ return JSON.parse(fs3.readFileSync(p, "utf8")).version;
120
+ } catch {
121
+ }
122
+ const parent = path3.dirname(cur);
123
+ if (parent === cur) break;
124
+ cur = parent;
125
+ }
126
+ return void 0;
127
+ }
128
+ function installedTreeVersion(root, ecosystem, name) {
129
+ if (ecosystem === "pypi") return installedPypiVersion(root, name);
130
+ if (ecosystem === "php") return installedPhpVersion(root, name);
131
+ return void 0;
132
+ }
133
+ function normalizePep503(name) {
134
+ return name.trim().toLowerCase().replace(/[-_.]+/g, "-");
135
+ }
136
+ function sitePackagesDirs(base) {
137
+ const out = [];
138
+ try {
139
+ for (const d of fs3.readdirSync(path3.join(base, "lib"))) {
140
+ if (d.startsWith("python")) out.push(path3.join(base, "lib", d, "site-packages"));
141
+ }
142
+ } catch {
143
+ }
144
+ out.push(path3.join(base, "Lib", "site-packages"));
145
+ return out;
146
+ }
147
+ function installedPypiVersion(root, name) {
148
+ const target = normalizePep503(name);
149
+ for (const venv of [".venv", "venv", "env", ".tox"]) {
150
+ for (const sp of sitePackagesDirs(path3.join(root, venv))) {
151
+ let entries;
152
+ try {
153
+ entries = fs3.readdirSync(sp);
154
+ } catch {
155
+ continue;
156
+ }
157
+ for (const entry of entries) {
158
+ const m = /^(.+?)-(\d[^-]*)\.dist-info$/.exec(entry);
159
+ if (m && normalizePep503(m[1]) === target) return m[2];
160
+ }
161
+ }
162
+ }
163
+ return void 0;
164
+ }
165
+ function installedPhpVersion(root, name) {
166
+ let data;
167
+ try {
168
+ data = JSON.parse(fs3.readFileSync(path3.join(root, "vendor", "composer", "installed.json"), "utf8"));
169
+ } catch {
170
+ return void 0;
171
+ }
172
+ const pkgs = Array.isArray(data) ? data : data.packages;
173
+ if (!Array.isArray(pkgs)) return void 0;
174
+ const p = pkgs.find((x) => x && typeof x === "object" && x.name === name);
175
+ return typeof p?.version === "string" ? p.version.replace(/^v/, "") : void 0;
176
+ }
177
+ function pypiDeps(files) {
178
+ const byName = /* @__PURE__ */ new Map();
179
+ const add = (name, declared) => {
180
+ const clean = name.trim().replace(/\[.*\]$/, "");
181
+ if (!clean || clean.toLowerCase() === "python") return;
182
+ if (!byName.has(clean)) byName.set(clean, { name: clean, ecosystem: "pypi", declared: declared.trim() || "*" });
183
+ };
184
+ for (const file of files) {
185
+ let text;
186
+ try {
187
+ text = fs3.readFileSync(file, "utf8");
188
+ } catch {
189
+ continue;
190
+ }
191
+ if (path3.basename(file) === "requirements.txt") {
192
+ for (const line of text.split("\n")) {
193
+ const t = line.trim();
194
+ if (!t || t.startsWith("#") || t.startsWith("-")) continue;
195
+ const m = /^([A-Za-z0-9._-]+(?:\[[^\]]*\])?)\s*([<>=!~).*]+.*)?$/.exec(t);
196
+ if (m) add(m[1], m[2] ?? "*");
197
+ }
198
+ } else {
199
+ for (const dep of pep621Dependencies(text)) {
200
+ const m = /^([A-Za-z0-9._-]+(?:\[[^\]]*\])?)\s*(.*)$/.exec(dep.trim());
201
+ if (m) add(m[1], m[2] ?? "*");
202
+ }
203
+ for (const [name, spec] of poetryDependencies(text)) add(name, spec);
204
+ }
205
+ }
206
+ return [...byName.values()];
207
+ }
208
+ function pep621Dependencies(text) {
209
+ const section = sectionBody(text, "project");
210
+ if (!section) return [];
211
+ const start = /dependencies\s*=\s*\[/.exec(section);
212
+ if (!start) return [];
213
+ let depth = 0;
214
+ let inStr = false;
215
+ let strCh = "";
216
+ const out = [];
217
+ let cur = "";
218
+ for (let i = start.index + start[0].length - 1; i < section.length; i++) {
219
+ const ch = section[i];
220
+ if (inStr) {
221
+ if (ch === strCh) {
222
+ out.push(cur);
223
+ inStr = false;
224
+ } else cur += ch;
225
+ continue;
226
+ }
227
+ if (ch === '"' || ch === "'") {
228
+ inStr = true;
229
+ strCh = ch;
230
+ cur = "";
231
+ } else if (ch === "[") depth++;
232
+ else if (ch === "]") {
233
+ depth--;
234
+ if (depth === 0) break;
235
+ }
236
+ }
237
+ return out;
238
+ }
239
+ function poetryDependencies(text) {
240
+ const out = [];
241
+ const lines = text.split("\n");
242
+ let inDeps = false;
243
+ for (const raw of lines) {
244
+ const line = raw.trim();
245
+ if (line.startsWith("[")) {
246
+ inDeps = /^\[tool\.poetry(\.group\.[^.\]]+)?\.dependencies\]$/.test(line);
247
+ continue;
248
+ }
249
+ if (!inDeps || !line || line.startsWith("#")) continue;
250
+ const m = /^([A-Za-z0-9._-]+)\s*=\s*["']([^"']*)["']/.exec(line);
251
+ if (m) out.push([m[1], m[2] || "*"]);
252
+ }
253
+ return out;
254
+ }
255
+ function sectionBody(text, name) {
256
+ const lines = text.split("\n");
257
+ let capturing = false;
258
+ const body = [];
259
+ for (const raw of lines) {
260
+ const line = raw.trim();
261
+ if (/^\[/.test(line)) {
262
+ if (capturing) break;
263
+ capturing = line === `[${name}]`;
264
+ continue;
265
+ }
266
+ if (capturing) body.push(raw);
267
+ }
268
+ return capturing || body.length ? body.join("\n") : null;
269
+ }
270
+ function goDeps(files) {
271
+ const out = [];
272
+ for (const mod of files) {
273
+ let text;
274
+ try {
275
+ text = fs3.readFileSync(mod, "utf8");
276
+ } catch {
277
+ continue;
278
+ }
279
+ const re = /^\s*(?:require\s+)?([\w./-]+)\s+v(\S+)/gm;
280
+ let m;
281
+ while (m = re.exec(text)) {
282
+ if (m[1] === "go" || m[1] === "require" || m[1].startsWith("module")) continue;
283
+ out.push({ name: m[1], ecosystem: "go", declared: `v${m[2]}` });
284
+ }
285
+ }
286
+ return out;
287
+ }
288
+ function cargoDeps(files) {
289
+ const out = [];
290
+ for (const file of files) {
291
+ let text;
292
+ try {
293
+ text = fs3.readFileSync(file, "utf8");
294
+ } catch {
295
+ continue;
296
+ }
297
+ for (const table of ["dependencies", "dev-dependencies", "build-dependencies"]) {
298
+ const body = sectionBody(text, table);
299
+ if (!body) continue;
300
+ for (const raw of body.split("\n")) {
301
+ const line = raw.trim();
302
+ if (!line || line.startsWith("#")) continue;
303
+ const m = /^([A-Za-z0-9._-]+)\s*=\s*(.+)$/.exec(line);
304
+ if (!m) continue;
305
+ const rhs = m[2].trim();
306
+ let declared = "*";
307
+ if (rhs.startsWith('"')) {
308
+ const sm = /^"([^"]+)"/.exec(rhs);
309
+ if (sm) declared = sm[1];
310
+ } else if (rhs.startsWith("{")) {
311
+ const vm = /version\s*=\s*"([^"]+)"/.exec(rhs);
312
+ if (vm) declared = vm[1];
313
+ }
314
+ out.push({ name: m[1], ecosystem: "rust", declared });
315
+ }
316
+ }
317
+ }
318
+ return out;
319
+ }
320
+ function rubyDeps(files) {
321
+ const out = [];
322
+ for (const file of files) {
323
+ let text;
324
+ try {
325
+ text = fs3.readFileSync(file, "utf8");
326
+ } catch {
327
+ continue;
328
+ }
329
+ const re = /^\s*gem\s+["']([^"']+)["']\s*(?:,\s*["']([^"']+)["'])?/gm;
330
+ let m;
331
+ while (m = re.exec(text)) out.push({ name: m[1], ecosystem: "ruby", declared: m[2] ?? "*" });
332
+ }
333
+ return out;
334
+ }
335
+ function phpDeps(files) {
336
+ const out = [];
337
+ for (const file of files) {
338
+ let pkg;
339
+ try {
340
+ pkg = JSON.parse(fs3.readFileSync(file, "utf8"));
341
+ } catch {
342
+ continue;
343
+ }
344
+ const all = { ...pkg.require, ...pkg["require-dev"] };
345
+ for (const [name, declared] of Object.entries(all)) {
346
+ if (!name.includes("/")) continue;
347
+ out.push({ name, ecosystem: "php", declared });
348
+ }
349
+ }
350
+ return out;
351
+ }
352
+ function dotnetDeps(files) {
353
+ const out = [];
354
+ for (const file of files) {
355
+ let text;
356
+ try {
357
+ text = fs3.readFileSync(file, "utf8");
358
+ } catch {
359
+ continue;
360
+ }
361
+ const tagRe = /<PackageReference\b[^>]*>/gi;
362
+ let m;
363
+ while (m = tagRe.exec(text)) {
364
+ const inc = /Include\s*=\s*"([^"]+)"/i.exec(m[0]);
365
+ if (!inc) continue;
366
+ const ver = /Version\s*=\s*"([^"]+)"/i.exec(m[0]);
367
+ out.push({ name: inc[1], ecosystem: "dotnet", declared: ver?.[1] ?? "*" });
368
+ }
369
+ }
370
+ return out;
371
+ }
372
+ function swiftDeps(files) {
373
+ const out = [];
374
+ for (const file of files) {
375
+ let text;
376
+ try {
377
+ text = fs3.readFileSync(file, "utf8");
378
+ } catch {
379
+ continue;
380
+ }
381
+ const re = /\.package\(/g;
382
+ let m;
383
+ while (m = re.exec(text)) {
384
+ const win = text.slice(m.index, m.index + 200);
385
+ const urlM = /url:\s*"([^"]+)"/.exec(win);
386
+ if (!urlM) continue;
387
+ const name = (urlM[1].replace(/\.git$/, "").split("/").filter(Boolean).pop() ?? urlM[1]).toLowerCase();
388
+ const verM = /"(\d+\.\d+(?:\.\d+)?)"/.exec(win.slice(urlM.index + urlM[0].length));
389
+ out.push({ name, ecosystem: "swift", declared: verM?.[1] ?? "*" });
390
+ }
391
+ }
392
+ return out;
393
+ }
394
+ function dartDeps(files) {
395
+ const out = [];
396
+ for (const file of files) {
397
+ let text;
398
+ try {
399
+ text = fs3.readFileSync(file, "utf8");
400
+ } catch {
401
+ continue;
402
+ }
403
+ let section = "";
404
+ for (const raw of text.split("\n")) {
405
+ const top = /^([a-z_]+):\s*$/.exec(raw);
406
+ if (top) {
407
+ section = top[1];
408
+ continue;
409
+ }
410
+ if (section !== "dependencies" && section !== "dev_dependencies") continue;
411
+ const m = /^ ([A-Za-z0-9_.]+):\s*(\S.*)?$/.exec(raw);
412
+ if (!m || m[1] === "flutter" || m[1] === "sdk") continue;
413
+ const declared = (m[2] ?? "").replace(/^["']|["']$/g, "").trim() || "*";
414
+ out.push({ name: m[1], ecosystem: "dart", declared });
415
+ }
416
+ }
417
+ return out;
418
+ }
419
+ function javaDeps(files) {
420
+ const out = [];
421
+ for (const file of files) {
422
+ let text;
423
+ try {
424
+ text = fs3.readFileSync(file, "utf8");
425
+ } catch {
426
+ continue;
427
+ }
428
+ if (path3.basename(file) === "pom.xml") {
429
+ for (const block of text.match(/<dependency>[\s\S]*?<\/dependency>/g) ?? []) {
430
+ const g = /<groupId>([^<]+)<\/groupId>/.exec(block);
431
+ const a = /<artifactId>([^<]+)<\/artifactId>/.exec(block);
432
+ if (!g || !a) continue;
433
+ const v = /<version>([^<]+)<\/version>/.exec(block);
434
+ const declared = v ? v[1].trim().startsWith("${") ? "*" : v[1].trim() : "*";
435
+ out.push({ name: `${g[1].trim()}:${a[1].trim()}`, ecosystem: "java", declared });
436
+ }
437
+ } else {
438
+ const re = /(?:implementation|api|compileOnly|runtimeOnly|testImplementation|testRuntimeOnly|annotationProcessor)\s*[(]?\s*["']([\w.-]+):([\w.-]+):([^"']+)["']/g;
439
+ let m;
440
+ while (m = re.exec(text)) out.push({ name: `${m[1]}:${m[2]}`, ecosystem: "java", declared: m[3] });
441
+ }
442
+ }
443
+ return out;
444
+ }
445
+ async function enrichOnline(records, fetchImpl = globalThis.fetch) {
446
+ for (const r of records) {
447
+ if (r.ecosystem !== "npm" || !r.installed) continue;
448
+ try {
449
+ const res = await fetchImpl(`https://registry.npmjs.org/${encodeURIComponent(r.name)}/latest`);
450
+ if (!res.ok) continue;
451
+ const data = await res.json();
452
+ r.latest = data.version;
453
+ r.drift = classify(r.installed, r.latest);
454
+ } catch {
455
+ r.drift = "unknown";
456
+ }
457
+ }
458
+ }
459
+ function classify(installed, latest) {
460
+ if (!latest) return "unknown";
461
+ const a = installed.split(".").map(Number);
462
+ const b = latest.split(".").map(Number);
463
+ if (a[0] !== b[0]) return "major";
464
+ if (a[1] !== b[1]) return "minor";
465
+ if (a[2] !== b[2]) return "patch";
466
+ return "current";
467
+ }
468
+ function lockfileVersion(root, ecosystem, name) {
469
+ if (ecosystem === "npm") return packageLockVersion(root, name) ?? yarnLockVersion(root, name);
470
+ if (ecosystem === "pypi") return pypiLockVersion(root, name);
471
+ if (ecosystem === "rust") return tomlPackageLock(root, "Cargo.lock", name, rustName);
472
+ if (ecosystem === "ruby") return gemfileLock(root, name);
473
+ if (ecosystem === "php") return composerLock(root, name);
474
+ if (ecosystem === "dotnet") return packagesLock(root, name);
475
+ if (ecosystem === "swift") return packageResolved(root, name);
476
+ if (ecosystem === "dart") return pubspecLock(root, name);
477
+ if (ecosystem === "java") return gradleLock(root, name);
478
+ return void 0;
479
+ }
480
+ function gradleLock(root, name) {
481
+ let text;
482
+ try {
483
+ text = fs3.readFileSync(path3.join(root, "gradle.lockfile"), "utf8");
484
+ } catch {
485
+ return void 0;
486
+ }
487
+ const m = new RegExp(`^${escapeRegExp(name)}:([^=\\s]+)=`, "m").exec(text);
488
+ return m ? m[1] : void 0;
489
+ }
490
+ function packageResolved(root, name) {
491
+ let data;
492
+ try {
493
+ data = JSON.parse(fs3.readFileSync(path3.join(root, "Package.resolved"), "utf8"));
494
+ } catch {
495
+ return void 0;
496
+ }
497
+ const pins = data.pins ?? data.object?.pins;
498
+ if (!Array.isArray(pins)) return void 0;
499
+ const target = name.toLowerCase();
500
+ for (const p of pins) {
501
+ const id = (p.identity ?? p.package ?? "").toLowerCase();
502
+ if (id === target && p.state?.version) return p.state.version;
503
+ }
504
+ return void 0;
505
+ }
506
+ function pubspecLock(root, name) {
507
+ let text;
508
+ try {
509
+ text = fs3.readFileSync(path3.join(root, "pubspec.lock"), "utf8");
510
+ } catch {
511
+ return void 0;
512
+ }
513
+ let inPkg = false;
514
+ for (const line of text.split("\n")) {
515
+ const key = /^ ([A-Za-z0-9_.]+):\s*$/.exec(line);
516
+ if (key) {
517
+ inPkg = key[1] === name;
518
+ continue;
519
+ }
520
+ if (inPkg) {
521
+ const vm = /^\s+version:\s*"?([^"\s]+)"?/.exec(line);
522
+ if (vm) return vm[1];
523
+ }
524
+ }
525
+ return void 0;
526
+ }
527
+ function escapeRegExp(s) {
528
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
529
+ }
530
+ function gemfileLock(root, name) {
531
+ let text;
532
+ try {
533
+ text = fs3.readFileSync(path3.join(root, "Gemfile.lock"), "utf8");
534
+ } catch {
535
+ return void 0;
536
+ }
537
+ const m = new RegExp(`^ ${escapeRegExp(name)} \\((\\d[^)]*)\\)`, "m").exec(text);
538
+ return m ? m[1] : void 0;
539
+ }
540
+ function composerLock(root, name) {
541
+ let data;
542
+ try {
543
+ data = JSON.parse(fs3.readFileSync(path3.join(root, "composer.lock"), "utf8"));
544
+ } catch {
545
+ return void 0;
546
+ }
547
+ for (const section of ["packages", "packages-dev"]) {
548
+ const arr = data[section];
549
+ if (!Array.isArray(arr)) continue;
550
+ const p = arr.find((x) => x && x.name === name);
551
+ if (p && typeof p.version === "string") return p.version.replace(/^v/, "");
552
+ }
553
+ return void 0;
554
+ }
555
+ function packagesLock(root, name) {
556
+ let data;
557
+ try {
558
+ data = JSON.parse(fs3.readFileSync(path3.join(root, "packages.lock.json"), "utf8"));
559
+ } catch {
560
+ return void 0;
561
+ }
562
+ const target = name.toLowerCase();
563
+ for (const fw of Object.values(data.dependencies ?? {})) {
564
+ if (!fw || typeof fw !== "object") continue;
565
+ for (const [id, v] of Object.entries(fw)) {
566
+ if (id.toLowerCase() === target && v && typeof v.resolved === "string") return v.resolved;
567
+ }
568
+ }
569
+ return void 0;
570
+ }
571
+ function pep503(name) {
572
+ return name.trim().toLowerCase().replace(/[-_.]+/g, "-");
573
+ }
574
+ function rustName(name) {
575
+ return name.trim().toLowerCase();
576
+ }
577
+ function pypiLockVersion(root, name) {
578
+ return tomlPackageLock(root, "poetry.lock", name, pep503) ?? tomlPackageLock(root, "uv.lock", name, pep503) ?? pipfileLock(root, name);
579
+ }
580
+ function tomlPackageLock(root, file, name, normalize) {
581
+ let text;
582
+ try {
583
+ text = fs3.readFileSync(path3.join(root, file), "utf8");
584
+ } catch {
585
+ return void 0;
586
+ }
587
+ const target = normalize(name);
588
+ for (const block of text.split(/\[\[package\]\]/)) {
589
+ const nm = /(?:^|\n)\s*name\s*=\s*"([^"]+)"/.exec(block);
590
+ if (nm && normalize(nm[1]) === target) {
591
+ const ver = /(?:^|\n)\s*version\s*=\s*"([^"]+)"/.exec(block);
592
+ if (ver) return ver[1];
593
+ }
594
+ }
595
+ return void 0;
596
+ }
597
+ function pipfileLock(root, name) {
598
+ let data;
599
+ try {
600
+ data = JSON.parse(fs3.readFileSync(path3.join(root, "Pipfile.lock"), "utf8"));
601
+ } catch {
602
+ return void 0;
603
+ }
604
+ const target = pep503(name);
605
+ for (const section of ["default", "develop"]) {
606
+ const deps = data[section];
607
+ if (!deps || typeof deps !== "object") continue;
608
+ for (const [k, v] of Object.entries(deps)) {
609
+ if (pep503(k) === target && v && typeof v.version === "string") {
610
+ return v.version.replace(/^==/, "");
611
+ }
612
+ }
613
+ }
614
+ return void 0;
615
+ }
616
+ function packageLockVersion(root, name) {
617
+ let data;
618
+ try {
619
+ data = JSON.parse(fs3.readFileSync(path3.join(root, "package-lock.json"), "utf8"));
620
+ } catch {
621
+ return void 0;
622
+ }
623
+ const top = data.packages?.[`node_modules/${name}`]?.version;
624
+ if (typeof top === "string") return top;
625
+ const v1 = data.dependencies?.[name]?.version;
626
+ return typeof v1 === "string" ? v1 : void 0;
627
+ }
628
+ function yarnLockVersion(root, name) {
629
+ let text;
630
+ try {
631
+ text = fs3.readFileSync(path3.join(root, "yarn.lock"), "utf8");
632
+ } catch {
633
+ return void 0;
634
+ }
635
+ let inBlock = false;
636
+ for (const line of text.split("\n")) {
637
+ if (line && !/^\s/.test(line) && !line.startsWith("#")) {
638
+ inBlock = headerNamesPackage(line, name);
639
+ } else if (inBlock) {
640
+ const m = /^\s+version:?\s+"?([^"\s]+)"?/.exec(line);
641
+ if (m) return m[1];
642
+ }
643
+ }
644
+ return void 0;
645
+ }
646
+ function headerNamesPackage(header, name) {
647
+ return header.replace(/:\s*$/, "").split(",").some((spec) => {
648
+ const s = spec.trim().replace(/^"|"$/g, "");
649
+ const at = s.lastIndexOf("@");
650
+ if (at <= 0) return false;
651
+ const specName = s.slice(0, at);
652
+ return specName === name;
653
+ });
654
+ }
655
+
656
+ // src/engine/lib.ts
657
+ var LIB_SCHEMA = "vg-lib/1.0";
658
+ function catalogPath(root) {
659
+ return path3.join(root, "vibgrate.lib.json");
660
+ }
661
+ function libDir(root) {
662
+ return path3.join(root, ".vibgrate", "lib");
663
+ }
664
+ function libId(name) {
665
+ return name.trim().toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
666
+ }
667
+ function loadCatalog(root) {
668
+ const file = catalogPath(root);
669
+ if (fs3.existsSync(file)) {
670
+ try {
671
+ const data = JSON.parse(fs3.readFileSync(file, "utf8"));
672
+ if (data.schemaVersion === LIB_SCHEMA && data.libraries) return data;
673
+ } catch {
674
+ }
675
+ }
676
+ return { schemaVersion: LIB_SCHEMA, libraries: {} };
677
+ }
678
+ function saveCatalog(root, catalog) {
679
+ fs3.writeFileSync(catalogPath(root), `${stableStringify(catalog, 2)}
680
+ `);
681
+ }
682
+ function resolveLib(catalog, name) {
683
+ const id = libId(name);
684
+ if (catalog.libraries[id]) return catalog.libraries[id];
685
+ const lower = name.toLowerCase();
686
+ const all = Object.values(catalog.libraries);
687
+ return all.find((e) => e.name.toLowerCase() === lower) ?? all.find((e) => e.id.includes(id) || e.name.toLowerCase().includes(lower));
688
+ }
689
+ function installedVersion(root, name) {
690
+ const rec = inventory(root).records.find((r) => r.name === name);
691
+ return rec?.installed ?? rec?.declared;
692
+ }
693
+ var stripRange = (v) => v?.replace(/^[v^~>=<\s]+/, "");
694
+ function resolveVersion(root, name) {
695
+ const rec = inventory(root).records.find((r) => r.name === name);
696
+ const declared = rec?.declared;
697
+ const installed = rec?.installed ?? (rec ? installedTreeVersion(root, rec.ecosystem, name) : void 0);
698
+ const lockfile = rec ? lockfileVersion(root, rec.ecosystem, name) : void 0;
699
+ let mismatch;
700
+ if (lockfile && installed && stripRange(lockfile) !== stripRange(installed)) {
701
+ mismatch = {
702
+ lockfile,
703
+ installed,
704
+ note: `lockfile pins ${lockfile} but the installed tree has ${installed} \u2014 your install is out of sync with the lockfile (re-install or commit the lock)`
705
+ };
706
+ }
707
+ const served = lockfile ?? installed ?? declared;
708
+ const source = lockfile ? "lockfile" : installed ? "installed" : declared ? "declared" : "unknown";
709
+ return { served, source, lockfile, installed, declared, mismatch };
710
+ }
711
+ function driftFor(root, entry) {
712
+ const installed = installedVersion(root, entry.name);
713
+ if (!installed || entry.version === "*") return { cataloged: entry.version, installed, drift: "unknown" };
714
+ const norm = (v) => v.replace(/^[v^~>=<\s]+/, "");
715
+ const a = norm(entry.version);
716
+ const b = norm(installed);
717
+ if (a === b) return { cataloged: entry.version, installed, drift: "current" };
718
+ return { cataloged: entry.version, installed, drift: cmp(a, b) < 0 ? "behind" : "ahead" };
719
+ }
720
+ function cmp(a, b) {
721
+ const pa = a.split(".").map(Number);
722
+ const pb = b.split(".").map(Number);
723
+ for (let i = 0; i < 3; i++) {
724
+ const d = (pa[i] || 0) - (pb[i] || 0);
725
+ if (d) return d;
726
+ }
727
+ return 0;
728
+ }
729
+ function parseGitSource(source) {
730
+ if (source.startsWith("git+")) return source.slice(4);
731
+ if (/^git@[^:]+:/.test(source)) return source;
732
+ if (/\.git\/?$/.test(source)) return source;
733
+ return null;
734
+ }
735
+ async function addLibrary(source, opts) {
736
+ const { root } = opts;
737
+ let content;
738
+ let type = "local";
739
+ const gitUrl = parseGitSource(source);
740
+ if (gitUrl) {
741
+ if (!opts.allowNetwork) {
742
+ throw new Error(`refusing to clone ${source} without --online (offline by default)`);
743
+ }
744
+ content = cloneAndReadGit(gitUrl);
745
+ type = "git";
746
+ } else if (/^https?:\/\//.test(source)) {
747
+ if (!opts.allowNetwork) {
748
+ throw new Error(`refusing to fetch ${source} without --online (offline by default)`);
749
+ }
750
+ const res = await (opts.fetchImpl ?? globalThis.fetch)(source);
751
+ if (!res.ok) throw new Error(`fetch failed (${res.status}) for ${source}`);
752
+ content = await res.text();
753
+ type = source.endsWith("llms.txt") ? "llms.txt" : source.endsWith(".json") ? "openapi" : "website";
754
+ } else {
755
+ const abs = path3.resolve(root, source);
756
+ if (!fs3.existsSync(abs)) throw new Error(`source not found: ${source}`);
757
+ content = readLocal(abs);
758
+ type = "local";
759
+ }
760
+ const name = opts.name ?? inferName(source);
761
+ const id = libId(name);
762
+ const version = opts.version ?? installedVersion(root, name) ?? "*";
763
+ fs3.mkdirSync(libDir(root), { recursive: true });
764
+ const docFileAbs = path3.join(libDir(root), `${id}.md`);
765
+ fs3.writeFileSync(docFileAbs, content);
766
+ const entry = {
767
+ id,
768
+ name,
769
+ version,
770
+ source: { type, location: source },
771
+ docFile: path3.relative(root, docFileAbs).split(path3.sep).join("/"),
772
+ docHash: hashString(content),
773
+ bytes: Buffer.byteLength(content, "utf8")
774
+ };
775
+ const catalog = loadCatalog(root);
776
+ catalog.libraries[id] = entry;
777
+ saveCatalog(root, catalog);
778
+ return entry;
779
+ }
780
+ function readDoc(root, entry) {
781
+ const abs = path3.resolve(root, entry.docFile);
782
+ return fs3.existsSync(abs) ? fs3.readFileSync(abs, "utf8") : "";
783
+ }
784
+ function npmPackageDir(root, name) {
785
+ let cur = root;
786
+ for (let i = 0; i < 12; i++) {
787
+ const dir = path3.join(cur, "node_modules", name);
788
+ if (fs3.existsSync(path3.join(dir, "package.json"))) return dir;
789
+ const parent = path3.dirname(cur);
790
+ if (parent === cur) break;
791
+ cur = parent;
792
+ }
793
+ return void 0;
794
+ }
795
+ var README_CANDIDATES = ["llms.txt", "README.md", "README.mdx", "README", "readme.md"];
796
+ function packageDocsMarkdown(dir, query) {
797
+ const docsDir = path3.join(dir, "docs");
798
+ if (!fs3.existsSync(docsDir) || !fs3.statSync(docsDir).isDirectory()) return void 0;
799
+ const files = [];
800
+ const walk = (d, depth) => {
801
+ if (depth > 3 || files.length >= 40) return;
802
+ let entries;
803
+ try {
804
+ entries = fs3.readdirSync(d, { withFileTypes: true });
805
+ } catch {
806
+ return;
807
+ }
808
+ entries.sort((a, b) => a.name.localeCompare(b.name));
809
+ for (const e of entries) {
810
+ if (files.length >= 40) return;
811
+ const full = path3.join(d, e.name);
812
+ if (e.isDirectory()) {
813
+ if (e.name.startsWith(".") || e.name === "node_modules") continue;
814
+ walk(full, depth + 1);
815
+ } else if (e.isFile() && /\.(md|mdx)$/i.test(e.name)) {
816
+ files.push(full);
817
+ }
818
+ }
819
+ };
820
+ walk(docsDir, 0);
821
+ if (!files.length) return void 0;
822
+ const terms = (query ?? "").toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length > 2);
823
+ const scored = files.map((f) => {
824
+ let body = "";
825
+ try {
826
+ body = fs3.readFileSync(f, "utf8");
827
+ } catch {
828
+ return { f, body: "", score: -1 };
829
+ }
830
+ const lc = `${path3.basename(f)}
831
+ ${body}`.toLowerCase();
832
+ const score = terms.length ? terms.filter((t) => lc.includes(t)).length : 1;
833
+ return { f, body, score };
834
+ });
835
+ const picked = (terms.length ? scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score || a.f.localeCompare(b.f)) : scored).filter((s) => s.body.trim()).slice(0, terms.length ? 8 : 5);
836
+ if (!picked.length) return void 0;
837
+ const text = picked.map((s) => `<!-- ${path3.relative(dir, s.f).split(path3.sep).join("/")} -->
838
+ ${s.body.trim()}`).join("\n\n");
839
+ return {
840
+ text,
841
+ files: picked.map((s) => path3.relative(dir, s.f).split(path3.sep).join("/"))
842
+ };
843
+ }
844
+ function localPackageDocs(root, name, opts) {
845
+ const dir = npmPackageDir(root, name);
846
+ if (!dir) return void 0;
847
+ const version = resolveVersion(root, name).served;
848
+ let primary;
849
+ for (const f of README_CANDIDATES) {
850
+ const p = path3.join(dir, f);
851
+ try {
852
+ const docs = fs3.readFileSync(p, "utf8");
853
+ if (docs.trim()) {
854
+ primary = { docs, source: path3.relative(root, p).split(path3.sep).join("/") };
855
+ break;
856
+ }
857
+ } catch {
858
+ }
859
+ }
860
+ const extra = packageDocsMarkdown(dir, opts?.query);
861
+ if (primary && extra) {
862
+ return {
863
+ docs: `${primary.docs.trim()}
864
+
865
+ ## Package docs
866
+
867
+ ${extra.text}`,
868
+ version,
869
+ source: `${primary.source}+docs/`,
870
+ readmeOnly: false
871
+ };
872
+ }
873
+ if (primary) {
874
+ return { ...primary, version, readmeOnly: true };
875
+ }
876
+ if (extra) {
877
+ return {
878
+ docs: extra.text,
879
+ version,
880
+ source: path3.relative(root, path3.join(dir, "docs")).split(path3.sep).join("/") + "/",
881
+ readmeOnly: false
882
+ };
883
+ }
884
+ try {
885
+ const pkg = JSON.parse(fs3.readFileSync(path3.join(dir, "package.json"), "utf8"));
886
+ if (pkg.description?.trim()) {
887
+ return {
888
+ docs: `# ${name}
889
+
890
+ ${pkg.description}`,
891
+ version: version ?? pkg.version,
892
+ source: path3.relative(root, path3.join(dir, "package.json")).split(path3.sep).join("/"),
893
+ readmeOnly: true
894
+ };
895
+ }
896
+ } catch {
897
+ }
898
+ return void 0;
899
+ }
900
+ function typesFromPkg(dir, pkg) {
901
+ const tryRel = (rel) => {
902
+ if (typeof rel !== "string") return void 0;
903
+ const p = path3.join(dir, rel);
904
+ return fs3.existsSync(p) ? p : void 0;
905
+ };
906
+ const top = tryRel(pkg.types) ?? tryRel(pkg.typings);
907
+ if (top) return top;
908
+ const exp = pkg.exports;
909
+ if (!exp || typeof exp !== "object") return void 0;
910
+ const roots = [];
911
+ if ("." in exp) roots.push(exp["."]);
912
+ else roots.push(...Object.values(exp));
913
+ for (const entry of roots) {
914
+ if (typeof entry === "string") {
915
+ const hit = tryRel(entry.endsWith(".d.ts") ? entry : void 0);
916
+ if (hit) return hit;
917
+ continue;
918
+ }
919
+ if (entry && typeof entry === "object") {
920
+ const o = entry;
921
+ for (const key of ["types", "typings", "import", "require", "default"]) {
922
+ const v = o[key];
923
+ if (typeof v === "string") {
924
+ const hit = tryRel(v.endsWith(".ts") || v.endsWith(".d.ts") || v.endsWith(".mts") || v.endsWith(".cts") ? v : void 0);
925
+ if (hit) return hit;
926
+ } else if (v && typeof v === "object" && typeof v.types === "string") {
927
+ const hit = tryRel(v.types);
928
+ if (hit) return hit;
929
+ }
930
+ }
931
+ }
932
+ }
933
+ return void 0;
934
+ }
935
+ function dtsEntry(dir) {
936
+ try {
937
+ const pkg = JSON.parse(fs3.readFileSync(path3.join(dir, "package.json"), "utf8"));
938
+ const fromPkg = typesFromPkg(dir, pkg);
939
+ if (fromPkg) return fromPkg;
940
+ } catch {
941
+ }
942
+ for (const c of [
943
+ "index.d.ts",
944
+ "dist/index.d.ts",
945
+ "dist/types/index.d.ts",
946
+ "lib/index.d.ts",
947
+ "types/index.d.ts",
948
+ "build/index.d.ts"
949
+ ]) {
950
+ const p = path3.join(dir, c);
951
+ if (fs3.existsSync(p)) return p;
952
+ }
953
+ return void 0;
954
+ }
955
+ var MAX_DTS_FILES = 30;
956
+ var MAX_DTS_BYTES = 512e3;
957
+ function collectDtsFiles(dir) {
958
+ const out = [];
959
+ const walk = (d, depth) => {
960
+ if (depth > 4 || out.length >= MAX_DTS_FILES) return;
961
+ let entries;
962
+ try {
963
+ entries = fs3.readdirSync(d, { withFileTypes: true });
964
+ } catch {
965
+ return;
966
+ }
967
+ entries.sort((a, b) => a.name.localeCompare(b.name));
968
+ for (const e of entries) {
969
+ if (out.length >= MAX_DTS_FILES) return;
970
+ if (e.name === "node_modules" || e.name.startsWith(".")) continue;
971
+ const full = path3.join(d, e.name);
972
+ if (e.isDirectory()) walk(full, depth + 1);
973
+ else if (e.isFile() && /\.d\.(ts|mts|cts)$/.test(e.name)) out.push(full);
974
+ }
975
+ };
976
+ walk(dir, 0);
977
+ return out;
978
+ }
979
+ function extractDtsApi(src, maxDecls = 200) {
980
+ const out = [];
981
+ let depth = 0;
982
+ let capture = null;
983
+ for (const raw of src.split("\n")) {
984
+ const line = raw.trim();
985
+ if (capture === null && depth === 0 && /^export\s+\{[^}]+\}/.test(line)) {
986
+ out.push(raw.trim());
987
+ if (out.length >= maxDecls) break;
988
+ continue;
989
+ }
990
+ if (capture === null && depth === 0 && /^export\b/.test(line) && !/^export\s+(\{|\*|default\b|type\s+\{)/.test(line)) {
991
+ capture = [];
992
+ }
993
+ if (capture) capture.push(raw);
994
+ for (const ch of raw) {
995
+ if (ch === "{") depth++;
996
+ else if (ch === "}") depth = Math.max(0, depth - 1);
997
+ }
998
+ if (capture && depth === 0 && /[;}]\s*$/.test(line)) {
999
+ out.push(capture.join("\n").trim());
1000
+ capture = null;
1001
+ if (out.length >= maxDecls) break;
1002
+ }
1003
+ }
1004
+ return out;
1005
+ }
1006
+ function reExportNames(decl) {
1007
+ const m = /^export\s*\{([^}]+)\}/.exec(decl.trim());
1008
+ if (!m) return [];
1009
+ const names = [];
1010
+ for (const part of m[1].split(",")) {
1011
+ const n = part.trim().split(/\s+as\s+/i).pop()?.trim();
1012
+ if (n && /^[A-Za-z_$][\w$]*$/.test(n)) names.push(n);
1013
+ }
1014
+ return names;
1015
+ }
1016
+ function localApiSurface(root, name, query) {
1017
+ const dir = npmPackageDir(root, name);
1018
+ if (!dir) return void 0;
1019
+ const entry = dtsEntry(dir);
1020
+ const files = entry ? [entry, ...collectDtsFiles(dir).filter((f) => f !== entry)] : collectDtsFiles(dir);
1021
+ if (!files.length) return void 0;
1022
+ const allDecls = [];
1023
+ const seen = /* @__PURE__ */ new Set();
1024
+ for (const f of files) {
1025
+ let src;
1026
+ try {
1027
+ const st = fs3.statSync(f);
1028
+ if (st.size > MAX_DTS_BYTES) continue;
1029
+ src = fs3.readFileSync(f, "utf8");
1030
+ } catch {
1031
+ continue;
1032
+ }
1033
+ for (const d of extractDtsApi(src)) {
1034
+ if (seen.has(d)) continue;
1035
+ seen.add(d);
1036
+ allDecls.push(d);
1037
+ if (allDecls.length >= 400) break;
1038
+ }
1039
+ if (allDecls.length >= 400) break;
1040
+ }
1041
+ if (!allDecls.length) return void 0;
1042
+ const terms = (query ?? "").split(/[^A-Za-z0-9_$]+/).filter((w) => w.length > 2);
1043
+ if (terms.length) {
1044
+ const lcTerms = terms.map((t) => t.toLowerCase());
1045
+ const matched = allDecls.filter((d) => {
1046
+ const lc = d.toLowerCase();
1047
+ return lcTerms.some((t) => lc.includes(t));
1048
+ });
1049
+ const expanded = [];
1050
+ const expandedSeen = /* @__PURE__ */ new Set();
1051
+ for (const d of matched) {
1052
+ const names = reExportNames(d);
1053
+ if (names.length) {
1054
+ for (const n of names) {
1055
+ const fuller = allDecls.find(
1056
+ (x) => !/^export\s*\{/.test(x) && new RegExp(`\\b${n}\\b`).test(x)
1057
+ );
1058
+ const pick = fuller ?? d;
1059
+ if (!expandedSeen.has(pick)) {
1060
+ expandedSeen.add(pick);
1061
+ expanded.push(pick);
1062
+ }
1063
+ }
1064
+ } else if (!expandedSeen.has(d)) {
1065
+ expandedSeen.add(d);
1066
+ expanded.push(d);
1067
+ }
1068
+ }
1069
+ if (expanded.length) return expanded.slice(0, 40).join("\n\n");
1070
+ }
1071
+ return allDecls.slice(0, 80).join("\n\n");
1072
+ }
1073
+ function cloneAndReadGit(url) {
1074
+ const dir = fs3.mkdtempSync(path3.join(os.tmpdir(), "vg-lib-git-"));
1075
+ try {
1076
+ execFileSync("git", ["clone", "--depth", "1", "--quiet", url, dir], {
1077
+ stdio: ["ignore", "ignore", "pipe"]
1078
+ });
1079
+ } catch (err) {
1080
+ fs3.rmSync(dir, { recursive: true, force: true });
1081
+ const detail = err instanceof Error && err.message ? `: ${err.message.split("\n")[0]}` : "";
1082
+ throw new Error(`git clone failed for ${url}${detail}`);
1083
+ }
1084
+ try {
1085
+ return readGitDocs(dir);
1086
+ } finally {
1087
+ fs3.rmSync(dir, { recursive: true, force: true });
1088
+ }
1089
+ }
1090
+ function readGitDocs(dir) {
1091
+ const docsDir = path3.join(dir, "docs");
1092
+ if (fs3.existsSync(docsDir) && fs3.statSync(docsDir).isDirectory()) return readLocal(docsDir);
1093
+ const readme = ["README.md", "README.mdx", "README.txt", "README.rst", "readme.md"].map((f) => path3.join(dir, f)).find((p) => fs3.existsSync(p));
1094
+ if (readme) return fs3.readFileSync(readme, "utf8");
1095
+ return readLocal(dir);
1096
+ }
1097
+ function readLocal(abs) {
1098
+ const stat = fs3.statSync(abs);
1099
+ if (stat.isFile()) return fs3.readFileSync(abs, "utf8");
1100
+ const parts = [];
1101
+ const files = fs3.readdirSync(abs, { withFileTypes: true }).filter((e) => e.isFile() && /\.(md|mdx|txt|rst)$/i.test(e.name)).map((e) => e.name).sort();
1102
+ for (const f of files) parts.push(`<!-- ${f} -->
1103
+ ${fs3.readFileSync(path3.join(abs, f), "utf8")}`);
1104
+ return parts.join("\n\n");
1105
+ }
1106
+ function inferName(source) {
1107
+ const cleaned = source.replace(/^git\+/, "").replace(/\.git\/?$/i, "");
1108
+ const base = cleaned.replace(/\/+$/, "").split(/[/:]/).pop() ?? cleaned;
1109
+ return base.replace(/\.(md|mdx|txt|rst|json)$/i, "").replace(/^llms$/, "docs");
1110
+ }
1111
+ var MAX_FILE_BYTES = 1e6;
1112
+ var PREVIEW_CHARS = 120;
1113
+ var NUL = "\0";
1114
+ var PARALLEL_MIN_BYTES = 64e6;
1115
+ var PARALLEL_MIN_FILES = 2e3;
1116
+ var ROW_CAP = 1e4;
1117
+ async function scanCandidates(root, files, needle, opts) {
1118
+ const needleLower = needle.toLowerCase();
1119
+ if (!needleLower || files.length === 0) return { hits: [], total: 0, truncated: false };
1120
+ if (files.length < PARALLEL_MIN_FILES && !process.env.VG_PARALLEL_MIN_BYTES) {
1121
+ return opts.collectAll ? scanInline(root, files, needleLower, ROW_CAP, false, void 0) : scanInline(root, files, needleLower, opts.budget, true, void 0);
1122
+ }
1123
+ const { over, sizes } = measure(root, files);
1124
+ if (!over) {
1125
+ return opts.collectAll ? scanInline(root, files, needleLower, ROW_CAP, false, sizes) : scanInline(root, files, needleLower, opts.budget, true, sizes);
1126
+ }
1127
+ const out = await scanParallel(root, files, needleLower);
1128
+ if (!opts.collectAll && out.hits.length > opts.budget) {
1129
+ out.hits.length = opts.budget;
1130
+ out.truncated = true;
1131
+ }
1132
+ return out;
1133
+ }
1134
+ function parallelMinBytes() {
1135
+ const v = Number(process.env.VG_PARALLEL_MIN_BYTES);
1136
+ return Number.isFinite(v) && v >= 0 ? v : PARALLEL_MIN_BYTES;
1137
+ }
1138
+ function measure(root, files) {
1139
+ const threshold = parallelMinBytes();
1140
+ const sizes = /* @__PURE__ */ new Map();
1141
+ let total = 0;
1142
+ for (const rel of files) {
1143
+ let size;
1144
+ try {
1145
+ size = fs3.statSync(path3.join(root, rel)).size;
1146
+ } catch {
1147
+ continue;
1148
+ }
1149
+ sizes.set(rel, size);
1150
+ if (size <= MAX_FILE_BYTES) total += size;
1151
+ if (total >= threshold) return { over: true, sizes };
1152
+ }
1153
+ return { over: false, sizes };
1154
+ }
1155
+ function matchLines(text, needleLower) {
1156
+ const low = text.toLowerCase();
1157
+ if (!low.includes(needleLower)) return [];
1158
+ const lowLines = low.split("\n");
1159
+ const rawLines = text.split("\n");
1160
+ const hits = [];
1161
+ for (let i = 0; i < lowLines.length; i++) {
1162
+ if (lowLines[i].includes(needleLower)) hits.push({ line: i + 1, preview: rawLines[i].trim().slice(0, PREVIEW_CHARS) });
1163
+ }
1164
+ return hits;
1165
+ }
1166
+ function readCandidate(abs, knownSize) {
1167
+ try {
1168
+ const size = knownSize ?? fs3.statSync(abs).size;
1169
+ if (size > MAX_FILE_BYTES) return null;
1170
+ const text = fs3.readFileSync(abs, "utf8");
1171
+ return text.includes(NUL) ? null : text;
1172
+ } catch {
1173
+ return null;
1174
+ }
1175
+ }
1176
+ function scanInline(root, files, needleLower, cap, stopAtCap, sizes) {
1177
+ const hits = [];
1178
+ let total = 0;
1179
+ let truncated = false;
1180
+ for (const rel of files) {
1181
+ const text = readCandidate(path3.join(root, rel), sizes?.get(rel));
1182
+ if (text === null) continue;
1183
+ for (const h of matchLines(text, needleLower)) {
1184
+ total++;
1185
+ if (hits.length < cap) hits.push({ file: rel, line: h.line, preview: h.preview });
1186
+ else {
1187
+ truncated = true;
1188
+ if (stopAtCap) return { hits, total, truncated };
1189
+ }
1190
+ }
1191
+ }
1192
+ return { hits, total, truncated };
1193
+ }
1194
+ async function scanParallel(root, files, needleLower) {
1195
+ const n = Math.min(files.length, Math.max(2, Math.min(8, os.cpus().length - 1)));
1196
+ const shards = Array.from({ length: n }, () => []);
1197
+ files.forEach((f, i) => shards[i % n].push(f));
1198
+ let results;
1199
+ try {
1200
+ results = await Promise.all(shards.map((shard) => runWorker(root, shard, needleLower)));
1201
+ } catch {
1202
+ return scanInline(root, files, needleLower, ROW_CAP, false, void 0);
1203
+ }
1204
+ const hits = [];
1205
+ let total = 0;
1206
+ let truncated = false;
1207
+ for (const r of results) {
1208
+ total += r.total;
1209
+ truncated = truncated || r.truncated;
1210
+ for (const h of r.hits) hits.push(h);
1211
+ }
1212
+ hits.sort((a, b) => a.file < b.file ? -1 : a.file > b.file ? 1 : a.line - b.line);
1213
+ if (hits.length > ROW_CAP) {
1214
+ hits.length = ROW_CAP;
1215
+ truncated = true;
1216
+ }
1217
+ return { hits, total, truncated };
1218
+ }
1219
+ var WORKER_SOURCE = [
1220
+ "const { parentPort, workerData } = require('worker_threads');",
1221
+ "const fs = require('fs');",
1222
+ "const path = require('path');",
1223
+ `const MAX = ${MAX_FILE_BYTES};`,
1224
+ `const PREVIEW = ${PREVIEW_CHARS};`,
1225
+ `const CAP = ${ROW_CAP};`,
1226
+ "const NUL = String.fromCharCode(0);",
1227
+ "const NL = String.fromCharCode(10);",
1228
+ "const { root, files, needleLower } = workerData;",
1229
+ "const hits = []; let total = 0, truncated = false;",
1230
+ "for (const rel of files) {",
1231
+ " const abs = path.join(root, rel);",
1232
+ " let text;",
1233
+ ' try { if (fs.statSync(abs).size > MAX) continue; text = fs.readFileSync(abs, "utf8"); } catch { continue; }',
1234
+ " if (text.includes(NUL)) continue;",
1235
+ " const low = text.toLowerCase();",
1236
+ " if (!low.includes(needleLower)) continue;",
1237
+ " const lowLines = low.split(NL); const rawLines = text.split(NL);",
1238
+ " for (let i = 0; i < lowLines.length; i++) {",
1239
+ " if (!lowLines[i].includes(needleLower)) continue;",
1240
+ " total++;",
1241
+ " if (hits.length < CAP) hits.push({ file: rel, line: i + 1, preview: rawLines[i].trim().slice(0, PREVIEW) });",
1242
+ " else truncated = true;",
1243
+ " }",
1244
+ "}",
1245
+ "parentPort.postMessage({ hits, total, truncated });"
1246
+ ].join("\n");
1247
+ function runWorker(root, files, needleLower) {
1248
+ return new Promise((resolve2, reject) => {
1249
+ const w = new Worker(WORKER_SOURCE, { eval: true, workerData: { root, files, needleLower } });
1250
+ let settled = false;
1251
+ w.once("message", (m) => {
1252
+ settled = true;
1253
+ resolve2(m);
1254
+ });
1255
+ w.once("error", reject);
1256
+ w.once("exit", (code) => {
1257
+ if (!settled && code !== 0) reject(new Error(`literal-scan worker exited with code ${code}`));
1258
+ });
1259
+ });
1260
+ }
1261
+
1262
+ // src/engine/search.ts
1263
+ var IGNORE_DIRS = /* @__PURE__ */ new Set([
1264
+ ".git",
1265
+ ".vibgrate",
1266
+ "node_modules",
1267
+ "dist",
1268
+ "build",
1269
+ "out",
1270
+ "target",
1271
+ "vendor",
1272
+ "__pycache__",
1273
+ // .NET intermediate output and coverage reports: purely generated trees that a
1274
+ // C#/coverage-heavy repo pays for on every literal sweep. `bin` is deliberately
1275
+ // NOT here — plenty of repos keep real scripts in bin/ (rails, node CLIs), and
1276
+ // completeness beats speed; the binary-extension skip below keeps a .NET bin/
1277
+ // cheap anyway.
1278
+ "obj",
1279
+ "coverage"
1280
+ ]);
1281
+ var MAX_FILES_SCANNED = 2e4;
1282
+ var BINARY_EXTS = /* @__PURE__ */ new Set([
1283
+ ".dll",
1284
+ ".pdb",
1285
+ ".exe",
1286
+ ".so",
1287
+ ".dylib",
1288
+ ".a",
1289
+ ".lib",
1290
+ ".o",
1291
+ ".class",
1292
+ ".jar",
1293
+ ".wasm",
1294
+ ".node",
1295
+ ".png",
1296
+ ".jpg",
1297
+ ".jpeg",
1298
+ ".gif",
1299
+ ".webp",
1300
+ ".ico",
1301
+ ".icns",
1302
+ ".bmp",
1303
+ ".zip",
1304
+ ".gz",
1305
+ ".tgz",
1306
+ ".bz2",
1307
+ ".xz",
1308
+ ".7z",
1309
+ ".rar",
1310
+ ".woff",
1311
+ ".woff2",
1312
+ ".ttf",
1313
+ ".otf",
1314
+ ".eot",
1315
+ ".mp3",
1316
+ ".mp4",
1317
+ ".mov",
1318
+ ".avi",
1319
+ ".pdf"
1320
+ ]);
1321
+ function hasBinaryExt(rel) {
1322
+ return BINARY_EXTS.has(path3.extname(rel).toLowerCase());
1323
+ }
1324
+ function toPosix(rel) {
1325
+ return path3.sep === "\\" ? rel.replaceAll("\\", "/") : rel;
1326
+ }
1327
+ async function searchSymbols(graph, root, query, limit) {
1328
+ let q = query.trim();
1329
+ if (!q) return { matches: [], moreAvailable: false, hint: "query is required" };
1330
+ const quoted = /^(["'`])(.+)\1$/.exec(q);
1331
+ if (quoted && quoted[2].trim()) q = quoted[2].trim();
1332
+ const embeddedNeedles = extractLiteralNeedles(q);
1333
+ const scanNeedle = embeddedNeedles.length === 0 ? q : embeddedNeedles.length === 1 && embeddedNeedles[0] === q ? q : [...embeddedNeedles].sort((a, b) => b.length - a.length)[0];
1334
+ const symbolQuery = embeddedNeedles.length > 0 ? residualForSymbolSearch(q) : q;
1335
+ const isUrl = /^https?:\/\//i.test(scanNeedle) || embeddedNeedles.some((n) => /^https?:\/\//i.test(n));
1336
+ const isPhrase = Boolean(quoted) || isUrl || embeddedNeedles.length > 0 || /\s/.test(q) || /[/\\]/.test(q) && !q.includes(":") && !/[*?]/.test(q);
1337
+ let nodes = [];
1338
+ if (symbolQuery.trim()) {
1339
+ nodes = findNodes(graph, symbolQuery).filter((n) => n.kind !== "file");
1340
+ if (nodes.length === 0) {
1341
+ nodes = fileSymbolNodes(graph, symbolQuery);
1342
+ }
1343
+ if (nodes.length === 0 && isPhrase) {
1344
+ nodes = reconstructedIdentifierNodes(graph, symbolQuery);
1345
+ }
1346
+ if (nodes.length === 0) {
1347
+ const tokens = queryTokens(symbolQuery);
1348
+ if (tokens.length >= 2) nodes = multiTokenNodes(graph, tokens);
1349
+ }
1350
+ }
1351
+ const symbolCap = isPhrase ? Math.max(1, Math.floor(limit / 3)) : limit;
1352
+ const symbolHits = nodes.slice(0, symbolCap).map((n, i) => ({
1353
+ kind: n.kind,
1354
+ name: n.qualifiedName,
1355
+ file: n.file,
1356
+ line: n.span.start,
1357
+ score: Math.round((1 - i / Math.max(nodes.length, 1)) * 100) / 100
1358
+ }));
1359
+ const spare = limit - symbolHits.length;
1360
+ const textHits = [];
1361
+ let truncatedScan = false;
1362
+ let totalTextMatches;
1363
+ const skipScan = !isPhrase && hasExactSymbolMatch(nodes, symbolQuery || q);
1364
+ if (spare > 0 && !skipScan) {
1365
+ const seen = new Set(symbolHits.map((h) => `${h.file}:${h.line}`));
1366
+ const scan = await scanFiles(root, scanNeedle, spare, seen, textHits, isPhrase);
1367
+ truncatedScan = scan.truncated;
1368
+ if (isPhrase) totalTextMatches = scan.total;
1369
+ }
1370
+ const matches = isPhrase ? [...textHits, ...symbolHits] : [...symbolHits, ...textHits];
1371
+ if (matches.length === 0) {
1372
+ const empty = {
1373
+ matches,
1374
+ moreAvailable: false,
1375
+ hint: "no symbol or text match \u2014 for meaning-level questions (symptoms, relationships, what-breaks-if) use query_graph"
1376
+ };
1377
+ if (totalTextMatches !== void 0) empty.totalTextMatches = totalTextMatches;
1378
+ return empty;
1379
+ }
1380
+ const literalTruncated = totalTextMatches !== void 0 && totalTextMatches > textHits.length;
1381
+ const moreAvailable = isPhrase ? literalTruncated || truncatedScan : nodes.length > symbolHits.length || truncatedScan;
1382
+ const result = { matches, moreAvailable };
1383
+ if (totalTextMatches !== void 0) result.totalTextMatches = totalTextMatches;
1384
+ if (literalTruncated) {
1385
+ result.hint = `showing ${textHits.length} of ${totalTextMatches}${truncatedScan ? "+" : ""} literal matches \u2014 raise limit or narrow the query to get them all`;
1386
+ }
1387
+ return result;
1388
+ }
1389
+ function fileSymbolNodes(graph, q) {
1390
+ if (!/[/\\]/.test(q) && !/\.\w+$/.test(q)) return [];
1391
+ const norm = q.replaceAll("\\", "/").replace(/^\.\//, "");
1392
+ const inFile = graph.nodes.filter(
1393
+ (n) => n.kind !== "file" && (n.file === norm || n.file.endsWith(`/${norm}`))
1394
+ );
1395
+ return [...inFile].sort((a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName));
1396
+ }
1397
+ function hasExactSymbolMatch(nodes, q) {
1398
+ if (nodes.length === 0) return false;
1399
+ if (/^(.*):(\d+)$/.test(q)) return true;
1400
+ const lower = q.toLowerCase();
1401
+ return nodes.some((n) => n.id === q || n.qualifiedName.toLowerCase() === lower || n.name.toLowerCase() === lower);
1402
+ }
1403
+ function queryTokens(q) {
1404
+ return [...new Set(q.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 2))];
1405
+ }
1406
+ function reconstructedIdentifierNodes(graph, q) {
1407
+ const words = q.trim().split(/\s+/).filter(Boolean);
1408
+ if (words.length < 2) return [];
1409
+ const concat = findNodes(graph, words.join(""));
1410
+ if (concat.length) return concat.filter((n) => n.kind !== "file");
1411
+ const snake = findNodes(graph, words.join("_"));
1412
+ return snake.filter((n) => n.kind !== "file");
1413
+ }
1414
+ function multiTokenNodes(graph, tokens) {
1415
+ const scored = [];
1416
+ for (const n of graph.nodes) {
1417
+ if (n.kind === "file") continue;
1418
+ const name = n.name.toLowerCase();
1419
+ const qn = n.qualifiedName.toLowerCase();
1420
+ let hits = 0;
1421
+ let exact = false;
1422
+ for (const t of tokens) {
1423
+ if (name === t || qn === t) {
1424
+ hits++;
1425
+ exact = true;
1426
+ } else if (qn.includes(t)) hits++;
1427
+ }
1428
+ if (exact || hits >= 2) scored.push({ node: n, hits, exact });
1429
+ }
1430
+ return scored.sort((a, b) => Number(b.exact) - Number(a.exact) || b.hits - a.hits || b.node.importance - a.node.importance || a.node.qualifiedName.localeCompare(b.node.qualifiedName)).map((e) => e.node);
1431
+ }
1432
+ async function scanFiles(root, needle, budget, seen, out, countAll) {
1433
+ const listing = listCandidateFiles(root, needle);
1434
+ const outcome = await scanCandidates(root, listing.files, needle, { collectAll: countAll, budget });
1435
+ let overlap = 0;
1436
+ for (const h of outcome.hits) {
1437
+ if (seen.has(`${h.file}:${h.line}`)) {
1438
+ overlap++;
1439
+ continue;
1440
+ }
1441
+ seen.add(`${h.file}:${h.line}`);
1442
+ if (out.length < budget) out.push({ kind: "text", file: h.file, line: h.line, preview: h.preview });
1443
+ }
1444
+ return { total: outcome.total - overlap, truncated: listing.truncated || outcome.truncated };
1445
+ }
1446
+ function listCandidateFiles(root, needle) {
1447
+ return ripgrepCandidates(root, needle) ?? walkCandidatesCached(root);
1448
+ }
1449
+ var LISTING_TTL_MS = 2e3;
1450
+ var listingCache = /* @__PURE__ */ new Map();
1451
+ function listingTtlMs() {
1452
+ const v = Number(process.env.VG_LISTING_TTL_MS);
1453
+ return Number.isFinite(v) && v >= 0 ? v : LISTING_TTL_MS;
1454
+ }
1455
+ function walkCandidatesCached(root) {
1456
+ const ttl = listingTtlMs();
1457
+ if (ttl > 0) {
1458
+ const hit = listingCache.get(root);
1459
+ if (hit && Date.now() - hit.at < ttl) return hit.listing;
1460
+ }
1461
+ const listing = walkCandidates(root);
1462
+ if (ttl > 0) listingCache.set(root, { listing, at: Date.now() });
1463
+ return listing;
1464
+ }
1465
+ function walkCandidates(root) {
1466
+ const files = [];
1467
+ let truncated = false;
1468
+ const stack = [root];
1469
+ while (stack.length) {
1470
+ const dir = stack.pop();
1471
+ let entries;
1472
+ try {
1473
+ entries = fs3.readdirSync(dir, { withFileTypes: true });
1474
+ } catch {
1475
+ continue;
1476
+ }
1477
+ for (const e of entries) {
1478
+ if (e.name.startsWith(".") || IGNORE_DIRS.has(e.name)) continue;
1479
+ const abs = path3.join(dir, e.name);
1480
+ if (e.isDirectory()) {
1481
+ stack.push(abs);
1482
+ continue;
1483
+ }
1484
+ if (hasBinaryExt(e.name)) continue;
1485
+ if (files.length >= MAX_FILES_SCANNED) {
1486
+ truncated = true;
1487
+ continue;
1488
+ }
1489
+ files.push(toPosix(path3.relative(root, abs)));
1490
+ }
1491
+ }
1492
+ files.sort();
1493
+ return { files, truncated };
1494
+ }
1495
+ var rgAvailable;
1496
+ function hasRipgrep() {
1497
+ if (process.env.VG_DISABLE_RIPGREP) return false;
1498
+ if (rgAvailable === void 0) {
1499
+ try {
1500
+ rgAvailable = spawnSync("rg", ["--version"], { stdio: "ignore", timeout: 3e3 }).status === 0;
1501
+ } catch {
1502
+ rgAvailable = false;
1503
+ }
1504
+ }
1505
+ return rgAvailable;
1506
+ }
1507
+ function ripgrepCandidates(root, needle) {
1508
+ if (!hasRipgrep()) return null;
1509
+ const globs = [...IGNORE_DIRS].flatMap((d) => ["--glob", `!**/${d}/**`, "--glob", `!${d}/**`]);
1510
+ const res = spawnSync(
1511
+ "rg",
1512
+ ["--files-with-matches", "--fixed-strings", "--ignore-case", "--no-ignore", "--no-messages", ...globs, "--", needle, "."],
1513
+ { cwd: root, encoding: "utf8", timeout: 15e3, maxBuffer: 32 * 1024 * 1024 }
1514
+ );
1515
+ if (res.error || res.status !== 0 && res.status !== 1 || res.signal) return null;
1516
+ const files = parseRgFileList(res.stdout);
1517
+ if (files.length > MAX_FILES_SCANNED) return { files: files.slice(0, MAX_FILES_SCANNED), truncated: true };
1518
+ return { files, truncated: false };
1519
+ }
1520
+ function parseRgFileList(stdout, sep3 = path3.sep) {
1521
+ const seen = /* @__PURE__ */ new Set();
1522
+ for (const raw of stdout.split("\n")) {
1523
+ if (!raw) continue;
1524
+ const posix = sep3 === "\\" ? raw.replaceAll("\\", "/") : raw;
1525
+ const rel = posix.startsWith("./") ? posix.slice(2) : posix;
1526
+ if (!rel) continue;
1527
+ const segs = rel.split("/");
1528
+ if (segs.some((s) => s.startsWith(".") || IGNORE_DIRS.has(s))) continue;
1529
+ if (hasBinaryExt(rel)) continue;
1530
+ seen.add(rel);
1531
+ }
1532
+ return [...seen].sort();
1533
+ }
1534
+
1535
+ export { ECOSYSTEMS, addLibrary, catalogPath, driftFor, enrichOnline, inventory, libDir, libId, loadCatalog, localApiSurface, localPackageDocs, readDoc, resolveLib, resolveVersion, saveCatalog, searchSymbols };
1536
+ //# sourceMappingURL=chunk-G4HTI4ZM.js.map
1537
+ //# sourceMappingURL=chunk-G4HTI4ZM.js.map