@vibgrate/cli 2026.803.1 → 2026.803.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.
- package/dist/agent-WYBWUBCC.js +26 -0
- package/dist/{agent-HNV2VUCO.js.map → agent-WYBWUBCC.js.map} +1 -1
- package/dist/baseline-3HECX4Q6.js +9 -0
- package/dist/{baseline-6WTULHM5.js.map → baseline-3HECX4Q6.js.map} +1 -1
- package/dist/{chunk-FKFRASAB.js → chunk-23UPIFRU.js} +8 -8
- package/dist/{chunk-FKFRASAB.js.map → chunk-23UPIFRU.js.map} +1 -1
- package/dist/chunk-2A7XCANX.js +375 -0
- package/dist/chunk-2A7XCANX.js.map +1 -0
- package/dist/{chunk-AJ2KE3NT.js → chunk-4LGDQBYK.js} +14 -102
- package/dist/chunk-4LGDQBYK.js.map +1 -0
- package/dist/{chunk-B2KLJPFY.js → chunk-4ZMJKR74.js} +451 -22
- package/dist/chunk-4ZMJKR74.js.map +1 -0
- package/dist/{chunk-DIU3MXB3.js → chunk-537JBQVB.js} +4 -4
- package/dist/{chunk-DIU3MXB3.js.map → chunk-537JBQVB.js.map} +1 -1
- package/dist/{chunk-4HFSUIIN.js → chunk-5TS7N7J2.js} +59 -9
- package/dist/chunk-5TS7N7J2.js.map +1 -0
- package/dist/{chunk-BWMMR5XA.js → chunk-5WMFX7TY.js} +4 -4
- package/dist/{chunk-BWMMR5XA.js.map → chunk-5WMFX7TY.js.map} +1 -1
- package/dist/{chunk-SNKTD23L.js → chunk-66B4ZQA3.js} +9 -8
- package/dist/chunk-66B4ZQA3.js.map +1 -0
- package/dist/{chunk-536J6HUR.js → chunk-7BU7CWXC.js} +39 -12
- package/dist/chunk-7BU7CWXC.js.map +1 -0
- package/dist/{chunk-N4IDP2M2.js → chunk-7TOIESUT.js} +5 -4
- package/dist/chunk-7TOIESUT.js.map +1 -0
- package/dist/{chunk-CE45STY5.js → chunk-BRUMBQV7.js} +4 -4
- package/dist/{chunk-CE45STY5.js.map → chunk-BRUMBQV7.js.map} +1 -1
- package/dist/{chunk-CC6F75GI.js → chunk-BUCNKYTW.js} +5 -5
- package/dist/{chunk-CC6F75GI.js.map → chunk-BUCNKYTW.js.map} +1 -1
- package/dist/{chunk-2TLQDF6C.js → chunk-FAA7RBIG.js} +9 -9
- package/dist/{chunk-2TLQDF6C.js.map → chunk-FAA7RBIG.js.map} +1 -1
- package/dist/chunk-FZ5Y4KEI.js +6 -0
- package/dist/{chunk-QT2PMGN3.js.map → chunk-FZ5Y4KEI.js.map} +1 -1
- package/dist/{chunk-S4NSF5AZ.js → chunk-HBQC4XQJ.js} +6 -6
- package/dist/{chunk-S4NSF5AZ.js.map → chunk-HBQC4XQJ.js.map} +1 -1
- package/dist/{chunk-O7MTBC52.js → chunk-HVHCXM2E.js} +9 -9
- package/dist/{chunk-O7MTBC52.js.map → chunk-HVHCXM2E.js.map} +1 -1
- package/dist/{chunk-NJFQCDGA.js → chunk-INIULQEP.js} +3 -3
- package/dist/{chunk-NJFQCDGA.js.map → chunk-INIULQEP.js.map} +1 -1
- package/dist/{chunk-Y7YKUZ3T.js → chunk-JZGVUH57.js} +30 -10
- package/dist/chunk-JZGVUH57.js.map +1 -0
- package/dist/{chunk-JUSXLCSE.js → chunk-KFK7KCAH.js} +3 -3
- package/dist/{chunk-JUSXLCSE.js.map → chunk-KFK7KCAH.js.map} +1 -1
- package/dist/{chunk-6I4TXAI6.js → chunk-OVDL76LB.js} +3 -3
- package/dist/{chunk-6I4TXAI6.js.map → chunk-OVDL76LB.js.map} +1 -1
- package/dist/{chunk-SJFBXCII.js → chunk-QUI3E3TQ.js} +54 -9
- package/dist/chunk-QUI3E3TQ.js.map +1 -0
- package/dist/chunk-RBMKBYGV.js +102 -0
- package/dist/chunk-RBMKBYGV.js.map +1 -0
- package/dist/{chunk-5VH3Y4QC.js → chunk-TVRM57CE.js} +78 -381
- package/dist/chunk-TVRM57CE.js.map +1 -0
- package/dist/{chunk-BBFQZ7CA.js → chunk-UWVFLVZX.js} +4 -4
- package/dist/{chunk-BBFQZ7CA.js.map → chunk-UWVFLVZX.js.map} +1 -1
- package/dist/{chunk-6JP7HGIF.js → chunk-Y4JO6LYP.js} +3 -3
- package/dist/{chunk-6JP7HGIF.js.map → chunk-Y4JO6LYP.js.map} +1 -1
- package/dist/cli.js +555 -351
- package/dist/cli.js.map +1 -1
- package/dist/embed-worker-main.d.ts +2 -0
- package/dist/embed-worker-main.js +64 -0
- package/dist/embed-worker-main.js.map +1 -0
- package/dist/ensure-map-DZ53QXRT.js +31 -0
- package/dist/{ensure-map-5YEI7R7V.js.map → ensure-map-DZ53QXRT.js.map} +1 -1
- package/dist/graph-backend-3A2M22QN.js +13 -0
- package/dist/{graph-backend-CPHLUKUC.js.map → graph-backend-3A2M22QN.js.map} +1 -1
- package/dist/index.d.ts +27 -2
- package/dist/index.js +16 -14
- package/dist/index.js.map +1 -1
- package/dist/{interactive-TNRE4OEK.js → interactive-DB7IC3BL.js} +35 -29
- package/dist/interactive-DB7IC3BL.js.map +1 -0
- package/dist/load-6KVGUQMU.js +11 -0
- package/dist/{load-MWG6WZTK.js.map → load-6KVGUQMU.js.map} +1 -1
- package/dist/{run-outcome-375HMSQG.js → run-outcome-YOYRC32U.js} +7 -6
- package/dist/run-outcome-YOYRC32U.js.map +1 -0
- package/dist/runtime-session-XEP7IPGP.js +22 -0
- package/dist/{runtime-session-3MPWXNRL.js.map → runtime-session-XEP7IPGP.js.map} +1 -1
- package/dist/session-5WKEACIF.js +17 -0
- package/dist/{session-2NGJLI5Y.js.map → session-5WKEACIF.js.map} +1 -1
- package/dist/{stream-json-AUMU3NLV.js → stream-json-3OJCPBWY.js} +13 -11
- package/dist/stream-json-3OJCPBWY.js.map +1 -0
- package/dist/{vg-mcp-bridge-D463EHQI.js → vg-mcp-bridge-PM3C4FQL.js} +12 -10
- package/dist/vg-mcp-bridge-PM3C4FQL.js.map +1 -0
- package/dist/{vgd-Z23PXSP4.js → vgd-UTLMMPIZ.js} +12 -10
- package/dist/vgd-UTLMMPIZ.js.map +1 -0
- package/package.json +1 -1
- package/scripts/postinstall.mjs +22 -1
- package/dist/agent-HNV2VUCO.js +0 -24
- package/dist/baseline-6WTULHM5.js +0 -9
- package/dist/chunk-4HFSUIIN.js.map +0 -1
- package/dist/chunk-536J6HUR.js.map +0 -1
- package/dist/chunk-5VH3Y4QC.js.map +0 -1
- package/dist/chunk-AJ2KE3NT.js.map +0 -1
- package/dist/chunk-B2KLJPFY.js.map +0 -1
- package/dist/chunk-N4IDP2M2.js.map +0 -1
- package/dist/chunk-QT2PMGN3.js +0 -6
- package/dist/chunk-SJFBXCII.js.map +0 -1
- package/dist/chunk-SNKTD23L.js.map +0 -1
- package/dist/chunk-Y7YKUZ3T.js.map +0 -1
- package/dist/ensure-map-5YEI7R7V.js +0 -29
- package/dist/graph-backend-CPHLUKUC.js +0 -11
- package/dist/interactive-TNRE4OEK.js.map +0 -1
- package/dist/load-MWG6WZTK.js +0 -10
- package/dist/run-outcome-375HMSQG.js.map +0 -1
- package/dist/runtime-session-3MPWXNRL.js +0 -20
- package/dist/session-2NGJLI5Y.js +0 -15
- package/dist/stream-json-AUMU3NLV.js.map +0 -1
- package/dist/vg-mcp-bridge-D463EHQI.js.map +0 -1
- package/dist/vgd-Z23PXSP4.js.map +0 -1
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import * as fs2 from 'fs';
|
|
4
|
-
import { createRequire } from 'module';
|
|
5
|
-
import * as os from 'os';
|
|
6
|
-
import * as path2 from 'path';
|
|
7
|
-
import { pathToFileURL } from 'url';
|
|
1
|
+
import { cosine } from './chunk-2A7XCANX.js';
|
|
2
|
+
import { bigramConsumedTokens, WEAK_TERMS, expandConcepts } from './chunk-4LGDQBYK.js';
|
|
8
3
|
|
|
9
4
|
// src/engine/relations.ts
|
|
10
5
|
var GraphIndex = class {
|
|
@@ -72,369 +67,6 @@ function indexFor(graph) {
|
|
|
72
67
|
}
|
|
73
68
|
return idx;
|
|
74
69
|
}
|
|
75
|
-
var DEFAULT_LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
76
|
-
function isProcessAlive(pid) {
|
|
77
|
-
try {
|
|
78
|
-
process.kill(pid, 0);
|
|
79
|
-
return true;
|
|
80
|
-
} catch (e) {
|
|
81
|
-
return e.code === "EPERM";
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function lockIsStale(file, staleMs) {
|
|
85
|
-
try {
|
|
86
|
-
const { pid, at } = JSON.parse(fs2.readFileSync(file, "utf8"));
|
|
87
|
-
if (typeof at === "number" && Date.now() - at > staleMs) return true;
|
|
88
|
-
if (typeof pid === "number" && !isProcessAlive(pid)) return true;
|
|
89
|
-
return false;
|
|
90
|
-
} catch {
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
function acquireLock(file, staleMs = DEFAULT_LOCK_STALE_MS) {
|
|
95
|
-
const write = () => {
|
|
96
|
-
try {
|
|
97
|
-
fs2.mkdirSync(path2.dirname(file), { recursive: true });
|
|
98
|
-
const fd = fs2.openSync(file, "wx");
|
|
99
|
-
fs2.writeFileSync(fd, JSON.stringify({ pid: process.pid, at: Date.now() }));
|
|
100
|
-
fs2.closeSync(fd);
|
|
101
|
-
return true;
|
|
102
|
-
} catch {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
if (write()) return true;
|
|
107
|
-
if (lockIsStale(file, staleMs)) {
|
|
108
|
-
try {
|
|
109
|
-
fs2.rmSync(file, { force: true });
|
|
110
|
-
} catch {
|
|
111
|
-
}
|
|
112
|
-
return write();
|
|
113
|
-
}
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
function releaseLock(file) {
|
|
117
|
-
try {
|
|
118
|
-
fs2.rmSync(file, { force: true });
|
|
119
|
-
} catch {
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// src/engine/embeddings.ts
|
|
124
|
-
function resolveEmbedModel(model) {
|
|
125
|
-
return model ?? "bge-small-en-v1.5";
|
|
126
|
-
}
|
|
127
|
-
function modelCacheDir() {
|
|
128
|
-
const base = process.env.XDG_CACHE_HOME || path2.join(os.homedir(), ".cache");
|
|
129
|
-
return path2.join(base, "vibgrate", "models");
|
|
130
|
-
}
|
|
131
|
-
function modelReadyMarker(modelId) {
|
|
132
|
-
return path2.join(modelCacheDir(), `.ready-${safe(modelId)}`);
|
|
133
|
-
}
|
|
134
|
-
function isModelReady(modelId = resolveEmbedModel()) {
|
|
135
|
-
return fs2.existsSync(modelReadyMarker(modelId));
|
|
136
|
-
}
|
|
137
|
-
function unavailableMessage(reason) {
|
|
138
|
-
switch (reason) {
|
|
139
|
-
case "no-permission":
|
|
140
|
-
return `semantic search couldn't write its model cache at ${modelCacheDir()} \u2014 using fast lexical search instead. Relocate it with the standard XDG_CACHE_HOME, or run with --local to stay lexical quietly. (No admin/sudo is ever needed \u2014 the cache lives in your home folder.)`;
|
|
141
|
-
case "download-failed":
|
|
142
|
-
return `the semantic model isn't downloaded yet and couldn't be fetched (offline?) \u2014 using fast lexical search. It'll try again next time; run with --local to keep lexical without retrying.`;
|
|
143
|
-
case "not-installed":
|
|
144
|
-
return `the optional semantic backend isn't available here \u2014 using fast lexical search.`;
|
|
145
|
-
case "init-failed":
|
|
146
|
-
default:
|
|
147
|
-
return `the semantic model couldn't load \u2014 using fast lexical search.`;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
function modelCacheInfo(modelId = resolveEmbedModel()) {
|
|
151
|
-
const dir = modelCacheDir();
|
|
152
|
-
return { dir, present: isModelReady(modelId) || fs2.existsSync(dir), bytes: dirSize(dir) };
|
|
153
|
-
}
|
|
154
|
-
function clearModelCache() {
|
|
155
|
-
const dir = modelCacheDir();
|
|
156
|
-
const bytes = dirSize(dir);
|
|
157
|
-
try {
|
|
158
|
-
fs2.rmSync(dir, { recursive: true, force: true });
|
|
159
|
-
} catch {
|
|
160
|
-
}
|
|
161
|
-
return bytes;
|
|
162
|
-
}
|
|
163
|
-
function dirSize(dir) {
|
|
164
|
-
let total = 0;
|
|
165
|
-
let entries;
|
|
166
|
-
try {
|
|
167
|
-
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
168
|
-
} catch {
|
|
169
|
-
return 0;
|
|
170
|
-
}
|
|
171
|
-
for (const e of entries) {
|
|
172
|
-
const p = path2.join(dir, e.name);
|
|
173
|
-
if (e.isDirectory()) total += dirSize(p);
|
|
174
|
-
else {
|
|
175
|
-
try {
|
|
176
|
-
total += fs2.statSync(p).size;
|
|
177
|
-
} catch {
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return total;
|
|
182
|
-
}
|
|
183
|
-
function isPermissionError(e) {
|
|
184
|
-
const code = e?.code;
|
|
185
|
-
return code === "EACCES" || code === "EPERM" || code === "EROFS";
|
|
186
|
-
}
|
|
187
|
-
function embeddingsCached(root, modelId) {
|
|
188
|
-
return fs2.existsSync(path2.join(cacheDir(root), `embeddings-${safe(modelId)}.json`));
|
|
189
|
-
}
|
|
190
|
-
async function loadEmbedder(options = {}) {
|
|
191
|
-
if (options.local) return null;
|
|
192
|
-
const modelId = resolveEmbedModel(options.model);
|
|
193
|
-
if (options.noDownload && !isModelReady(modelId)) return null;
|
|
194
|
-
const fail = (reason) => {
|
|
195
|
-
options.onUnavailable?.(reason);
|
|
196
|
-
return null;
|
|
197
|
-
};
|
|
198
|
-
const mod = await importEmbedBackend();
|
|
199
|
-
if (!mod?.FlagEmbedding) return fail("not-installed");
|
|
200
|
-
const cache = modelCacheDir();
|
|
201
|
-
try {
|
|
202
|
-
fs2.mkdirSync(cache, { recursive: true });
|
|
203
|
-
} catch (e) {
|
|
204
|
-
return fail(isPermissionError(e) ? "no-permission" : "init-failed");
|
|
205
|
-
}
|
|
206
|
-
try {
|
|
207
|
-
const model = await withTimeout(
|
|
208
|
-
mod.FlagEmbedding.init({
|
|
209
|
-
model: mapModel(mod, modelId),
|
|
210
|
-
cacheDir: cache,
|
|
211
|
-
showDownloadProgress: options.showDownloadProgress ?? false
|
|
212
|
-
}),
|
|
213
|
-
embedInitTimeoutMs(),
|
|
214
|
-
"embedding model init timed out"
|
|
215
|
-
);
|
|
216
|
-
try {
|
|
217
|
-
fs2.writeFileSync(modelReadyMarker(modelId), (/* @__PURE__ */ new Date(0)).toISOString());
|
|
218
|
-
} catch {
|
|
219
|
-
}
|
|
220
|
-
return {
|
|
221
|
-
id: modelId,
|
|
222
|
-
async embed(texts) {
|
|
223
|
-
const out = [];
|
|
224
|
-
for await (const batch of model.embed(texts, 64)) {
|
|
225
|
-
for (const v of batch) out.push(Array.from(v));
|
|
226
|
-
}
|
|
227
|
-
return out;
|
|
228
|
-
},
|
|
229
|
-
async embedQuery(text) {
|
|
230
|
-
const v = await model.queryEmbed(text);
|
|
231
|
-
return Array.from(v);
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
} catch (e) {
|
|
235
|
-
return fail(isPermissionError(e) ? "no-permission" : "download-failed");
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
async function importEmbedBackend() {
|
|
239
|
-
const hostDir = process.env.VIBGRATE_EMBEDDER_PATH;
|
|
240
|
-
if (hostDir) {
|
|
241
|
-
try {
|
|
242
|
-
const req = createRequire(path2.join(hostDir, "package.json"));
|
|
243
|
-
const mod = await import(pathToFileURL(req.resolve("fastembed")).href);
|
|
244
|
-
const resolved = mod?.FlagEmbedding ? mod : mod?.default;
|
|
245
|
-
if (resolved?.FlagEmbedding) return resolved;
|
|
246
|
-
} catch {
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return await import('fastembed').catch(() => null);
|
|
250
|
-
}
|
|
251
|
-
function embedInitTimeoutMs() {
|
|
252
|
-
const n = Number(process.env.VG_EMBED_TIMEOUT_MS);
|
|
253
|
-
return Number.isFinite(n) && n > 0 ? n : 6e4;
|
|
254
|
-
}
|
|
255
|
-
async function withTimeout(promise, ms, message) {
|
|
256
|
-
let timer;
|
|
257
|
-
try {
|
|
258
|
-
return await Promise.race([
|
|
259
|
-
promise,
|
|
260
|
-
new Promise((_, reject) => {
|
|
261
|
-
timer = setTimeout(() => reject(new Error(message)), ms);
|
|
262
|
-
timer.unref?.();
|
|
263
|
-
})
|
|
264
|
-
]);
|
|
265
|
-
} finally {
|
|
266
|
-
clearTimeout(timer);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
function mapModel(mod, id) {
|
|
270
|
-
const m = mod.EmbeddingModel ?? {};
|
|
271
|
-
if (/bge-small/i.test(id)) return m.BGESmallENV15 ?? m.BGESmallEN ?? id;
|
|
272
|
-
if (/bge-base/i.test(id)) return m.BGEBaseENV15 ?? id;
|
|
273
|
-
if (/all-minilm/i.test(id)) return m.AllMiniLML6V2 ?? id;
|
|
274
|
-
return id;
|
|
275
|
-
}
|
|
276
|
-
var PATH_NOISE = /* @__PURE__ */ new Set([
|
|
277
|
-
"src",
|
|
278
|
-
"app",
|
|
279
|
-
"apps",
|
|
280
|
-
"lib",
|
|
281
|
-
"libs",
|
|
282
|
-
"dist",
|
|
283
|
-
"build",
|
|
284
|
-
"out",
|
|
285
|
-
"index",
|
|
286
|
-
"main",
|
|
287
|
-
"packages",
|
|
288
|
-
"pkg",
|
|
289
|
-
"test",
|
|
290
|
-
"tests",
|
|
291
|
-
"__tests__",
|
|
292
|
-
"spec",
|
|
293
|
-
"node_modules",
|
|
294
|
-
"internal",
|
|
295
|
-
"com",
|
|
296
|
-
"example",
|
|
297
|
-
"demo",
|
|
298
|
-
"java",
|
|
299
|
-
"net",
|
|
300
|
-
"org",
|
|
301
|
-
"www"
|
|
302
|
-
]);
|
|
303
|
-
function pathContext(file) {
|
|
304
|
-
const parts = file.split("/");
|
|
305
|
-
const stem = (parts.pop() ?? "").replace(/\.[^.]+$/, "");
|
|
306
|
-
const dirs = parts.filter((p) => p && !PATH_NOISE.has(p.toLowerCase()));
|
|
307
|
-
return [...dirs.slice(-2), stem].filter(Boolean).join(" ");
|
|
308
|
-
}
|
|
309
|
-
function nodeEmbedText(node, areaLabel) {
|
|
310
|
-
if (node.kind === "document") {
|
|
311
|
-
const category = (node.signature ?? "document").replace(/^document:/, "");
|
|
312
|
-
const categoryHints = {
|
|
313
|
-
manifest: "package dependencies scripts install dependencies versions",
|
|
314
|
-
docker: "dockerfile container image build runtime",
|
|
315
|
-
compose: "docker-compose services containers networking volumes",
|
|
316
|
-
ci: "continuous integration github actions workflow pipeline test build deploy",
|
|
317
|
-
"build-config": "typescript tsconfig bundler vite webpack eslint prettier test",
|
|
318
|
-
"api-contract": "openapi swagger graphql protobuf api schema endpoints",
|
|
319
|
-
"task-runner": "makefile justfile tasks build test run commands",
|
|
320
|
-
workspace: "monorepo workspace packages pnpm turbo nx",
|
|
321
|
-
infra: "deploy infrastructure kubernetes kubernetes terraform helm kubernetes",
|
|
322
|
-
"env-example": "environment variables configuration secrets template",
|
|
323
|
-
markdown: "documentation readme guide"
|
|
324
|
-
};
|
|
325
|
-
const hint = categoryHints[category] ?? category;
|
|
326
|
-
return [
|
|
327
|
-
node.qualifiedName,
|
|
328
|
-
"document",
|
|
329
|
-
category,
|
|
330
|
-
hint,
|
|
331
|
-
pathContext(node.file),
|
|
332
|
-
(node.doc ?? "").slice(0, 5e3)
|
|
333
|
-
].filter(Boolean).join("\n");
|
|
334
|
-
}
|
|
335
|
-
return [node.qualifiedName, node.kind, node.signature ?? "", node.doc ?? "", pathContext(node.file), areaLabel ?? ""].filter(Boolean).join(" ");
|
|
336
|
-
}
|
|
337
|
-
function cosine(a, b) {
|
|
338
|
-
let dot = 0;
|
|
339
|
-
let na = 0;
|
|
340
|
-
let nb = 0;
|
|
341
|
-
const n = Math.min(a.length, b.length);
|
|
342
|
-
for (let i = 0; i < n; i++) {
|
|
343
|
-
dot += a[i] * b[i];
|
|
344
|
-
na += a[i] * a[i];
|
|
345
|
-
nb += b[i] * b[i];
|
|
346
|
-
}
|
|
347
|
-
if (na === 0 || nb === 0) return 0;
|
|
348
|
-
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
349
|
-
}
|
|
350
|
-
var EMBED_CHUNK = 256;
|
|
351
|
-
var CACHE_WRITE_INTERVAL_MS = 1500;
|
|
352
|
-
function vectorCachePath(root, modelId) {
|
|
353
|
-
return path2.join(cacheDir(root), `embeddings-${safe(modelId)}.json`);
|
|
354
|
-
}
|
|
355
|
-
function countPending(graph, root, modelId) {
|
|
356
|
-
const entries = readCacheEntries(vectorCachePath(root, modelId), modelId);
|
|
357
|
-
const areaLabel = new Map(graph.areas.map((a) => [a.id, a.label]));
|
|
358
|
-
let pending = 0;
|
|
359
|
-
for (const n of graph.nodes) {
|
|
360
|
-
if (n.kind === "file" || n.kind === "external") continue;
|
|
361
|
-
const h = hashString(nodeEmbedText(n, areaLabel.get(n.area)));
|
|
362
|
-
const cached = entries[n.id];
|
|
363
|
-
if (!cached || cached.hash !== h) pending++;
|
|
364
|
-
}
|
|
365
|
-
return pending;
|
|
366
|
-
}
|
|
367
|
-
function readCacheEntries(file, modelId) {
|
|
368
|
-
if (!fs2.existsSync(file)) return {};
|
|
369
|
-
try {
|
|
370
|
-
const loaded = JSON.parse(fs2.readFileSync(file, "utf8"));
|
|
371
|
-
if (loaded.model === modelId && loaded.entries) return loaded.entries;
|
|
372
|
-
} catch {
|
|
373
|
-
}
|
|
374
|
-
return {};
|
|
375
|
-
}
|
|
376
|
-
async function getNodeEmbeddings(graph, embedder, root, onProgress) {
|
|
377
|
-
const file = vectorCachePath(root, embedder.id);
|
|
378
|
-
let cache = { model: embedder.id, entries: {} };
|
|
379
|
-
if (fs2.existsSync(file)) {
|
|
380
|
-
try {
|
|
381
|
-
const loaded = JSON.parse(fs2.readFileSync(file, "utf8"));
|
|
382
|
-
if (loaded.model === embedder.id && loaded.entries) cache = loaded;
|
|
383
|
-
} catch {
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
const areaLabel = new Map(graph.areas.map((a) => [a.id, a.label]));
|
|
387
|
-
const targets = graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external");
|
|
388
|
-
const toEmbed = [];
|
|
389
|
-
const vectors = /* @__PURE__ */ new Map();
|
|
390
|
-
for (const n of targets) {
|
|
391
|
-
const text = nodeEmbedText(n, areaLabel.get(n.area));
|
|
392
|
-
const h = hashString(text);
|
|
393
|
-
const cached = cache.entries[n.id];
|
|
394
|
-
if (cached && cached.hash === h) vectors.set(n.id, cached.vec);
|
|
395
|
-
else toEmbed.push({ id: n.id, text, hash: h });
|
|
396
|
-
}
|
|
397
|
-
const persist = () => {
|
|
398
|
-
try {
|
|
399
|
-
fs2.mkdirSync(cacheDir(root), { recursive: true });
|
|
400
|
-
const tmp = `${file}.tmp.${process.pid}`;
|
|
401
|
-
fs2.writeFileSync(tmp, JSON.stringify(cache));
|
|
402
|
-
fs2.renameSync(tmp, file);
|
|
403
|
-
} catch {
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
if (toEmbed.length) {
|
|
407
|
-
const lock = `${file}.lock`;
|
|
408
|
-
if (!acquireLock(lock)) return vectors;
|
|
409
|
-
try {
|
|
410
|
-
onProgress?.(0, toEmbed.length);
|
|
411
|
-
let lastWrite = Date.now();
|
|
412
|
-
for (let i = 0; i < toEmbed.length; i += EMBED_CHUNK) {
|
|
413
|
-
const slice = toEmbed.slice(i, i + EMBED_CHUNK);
|
|
414
|
-
const vecs = await embedder.embed(slice.map((t) => t.text));
|
|
415
|
-
slice.forEach((t, j) => {
|
|
416
|
-
const vec = vecs[j] ?? [];
|
|
417
|
-
vectors.set(t.id, vec);
|
|
418
|
-
cache.entries[t.id] = { hash: t.hash, vec };
|
|
419
|
-
});
|
|
420
|
-
onProgress?.(Math.min(i + EMBED_CHUNK, toEmbed.length), toEmbed.length);
|
|
421
|
-
if (Date.now() - lastWrite >= CACHE_WRITE_INTERVAL_MS) {
|
|
422
|
-
persist();
|
|
423
|
-
lastWrite = Date.now();
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
const live = new Set(targets.map((n) => n.id));
|
|
427
|
-
for (const id of Object.keys(cache.entries)) if (!live.has(id)) delete cache.entries[id];
|
|
428
|
-
persist();
|
|
429
|
-
} finally {
|
|
430
|
-
releaseLock(lock);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
return vectors;
|
|
434
|
-
}
|
|
435
|
-
function safe(id) {
|
|
436
|
-
return id.replace(/[^a-z0-9.-]+/gi, "_");
|
|
437
|
-
}
|
|
438
70
|
|
|
439
71
|
// src/engine/query.ts
|
|
440
72
|
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
@@ -587,7 +219,7 @@ function queryGraph(graph, question, options = {}) {
|
|
|
587
219
|
const limit = options.limit ?? 12;
|
|
588
220
|
const literals = extractLiteralNeedles(question);
|
|
589
221
|
const forTokens = literals.length > 0 ? stripLiteralNeedles(question) : question;
|
|
590
|
-
const prep = prepareTerms(forTokens, options.relevance);
|
|
222
|
+
const prep = prepareTerms(forTokens, options.relevance, priorResidual(options.priorQuestion));
|
|
591
223
|
const weightOf = termWeights(graph, prep.terms.map((t) => t.term));
|
|
592
224
|
const index = indexFor(graph);
|
|
593
225
|
const scored = [];
|
|
@@ -620,7 +252,7 @@ async function queryGraphSemantic(graph, question, options) {
|
|
|
620
252
|
const limit = options.limit ?? 12;
|
|
621
253
|
const literals = extractLiteralNeedles(question);
|
|
622
254
|
const forTokens = literals.length > 0 ? stripLiteralNeedles(question) : question;
|
|
623
|
-
const prep = prepareTerms(forTokens, options.relevance);
|
|
255
|
+
const prep = prepareTerms(forTokens, options.relevance, priorResidual(options.priorQuestion));
|
|
624
256
|
const terms = prep.terms.map((t) => t.term);
|
|
625
257
|
const weightOf = termWeights(graph, terms);
|
|
626
258
|
const index = indexFor(graph);
|
|
@@ -679,11 +311,13 @@ function tokenizeOrdered(q) {
|
|
|
679
311
|
var WEAK_TERM_WEIGHT = 0.25;
|
|
680
312
|
var EXPANSION_WEIGHT = 0.7;
|
|
681
313
|
var COVERAGE_BONUS = 0.35;
|
|
682
|
-
|
|
314
|
+
var CARRY_WEIGHT = 0.5;
|
|
315
|
+
function prepareTerms(forTokens, relevance, prior) {
|
|
683
316
|
const base = tokenize(forTokens);
|
|
684
317
|
const ordered = tokenizeOrdered(forTokens);
|
|
685
318
|
const baseSet = new Set(base);
|
|
686
|
-
const
|
|
319
|
+
const consumed = bigramConsumedTokens(ordered);
|
|
320
|
+
const terms = base.map((t) => ({ term: t, weak: WEAK_TERMS.has(t) || consumed.has(t) }));
|
|
687
321
|
const have = new Set(base);
|
|
688
322
|
for (const e of expandConcepts(ordered)) {
|
|
689
323
|
if (baseSet.has(e.term)) continue;
|
|
@@ -695,9 +329,72 @@ function prepareTerms(forTokens, relevance) {
|
|
|
695
329
|
terms.push({ term: e.term, weak: false, from: e.from, providerWeight: e.weight });
|
|
696
330
|
have.add(e.term);
|
|
697
331
|
}
|
|
332
|
+
if (prior?.trim()) {
|
|
333
|
+
const priorOrdered = tokenizeOrdered(prior);
|
|
334
|
+
const priorConsumed = bigramConsumedTokens(priorOrdered);
|
|
335
|
+
for (const t of tokenize(prior)) {
|
|
336
|
+
if (have.has(t) || WEAK_TERMS.has(t) || priorConsumed.has(t)) continue;
|
|
337
|
+
terms.push({ term: t, weak: false, carried: true });
|
|
338
|
+
have.add(t);
|
|
339
|
+
}
|
|
340
|
+
for (const e of expandConcepts(priorOrdered)) {
|
|
341
|
+
if (have.has(e.term)) continue;
|
|
342
|
+
terms.push({ term: e.term, weak: false, from: e.from, carried: true });
|
|
343
|
+
have.add(e.term);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
698
346
|
const hasContent = terms.some((t) => !t.weak);
|
|
699
347
|
return { terms, hasContent };
|
|
700
348
|
}
|
|
349
|
+
function priorResidual(prior) {
|
|
350
|
+
const raw = prior?.trim();
|
|
351
|
+
if (!raw) return null;
|
|
352
|
+
return extractLiteralNeedles(raw).length > 0 ? stripLiteralNeedles(raw) : raw;
|
|
353
|
+
}
|
|
354
|
+
function conceptMapLines(question, relevance, priorQuestion) {
|
|
355
|
+
const cap = (xs) => [...new Set(xs)].slice(0, 8).join(", ");
|
|
356
|
+
const literals = extractLiteralNeedles(question);
|
|
357
|
+
const residual = literals.length > 0 ? stripLiteralNeedles(question) : question;
|
|
358
|
+
const lines = [];
|
|
359
|
+
const byFrom = /* @__PURE__ */ new Map();
|
|
360
|
+
for (const e of expandConcepts(tokenizeOrdered(residual))) {
|
|
361
|
+
const list = byFrom.get(e.from) ?? [];
|
|
362
|
+
list.push(e.term);
|
|
363
|
+
byFrom.set(e.from, list);
|
|
364
|
+
}
|
|
365
|
+
for (const [from, terms] of byFrom) {
|
|
366
|
+
lines.push(`- "${from}" in the ask implies these codebase identifiers: ${cap(terms)}.`);
|
|
367
|
+
}
|
|
368
|
+
if (relevance?.topics?.length) {
|
|
369
|
+
const topicVocab = /* @__PURE__ */ new Map();
|
|
370
|
+
for (const e of relevance.expansions ?? []) {
|
|
371
|
+
const list = topicVocab.get(e.from) ?? [];
|
|
372
|
+
list.push(e.term);
|
|
373
|
+
topicVocab.set(e.from, list);
|
|
374
|
+
}
|
|
375
|
+
for (const t of relevance.topics.slice(0, 3)) {
|
|
376
|
+
const vocab = topicVocab.get(t.id);
|
|
377
|
+
lines.push(
|
|
378
|
+
vocab?.length ? `- The ask is about the "${t.id}" domain; code for it typically uses: ${cap(vocab)}.` : `- The ask is about the "${t.id}" domain.`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const priorText = priorResidual(priorQuestion);
|
|
383
|
+
if (priorText) {
|
|
384
|
+
const current = new Set(tokenize(residual));
|
|
385
|
+
const consumed = bigramConsumedTokens(tokenizeOrdered(priorText));
|
|
386
|
+
const carried = tokenize(priorText).filter((t) => !current.has(t) && !WEAK_TERMS.has(t) && !consumed.has(t));
|
|
387
|
+
if (carried.length) {
|
|
388
|
+
lines.push(`- This is a follow-up; topic words carried from the previous ask: ${cap(carried)}.`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (lines.length) {
|
|
392
|
+
lines.push(
|
|
393
|
+
'- Seed notation below: `a\u2192b` = ask term "a" implied identifier "b"; `~t` = word-form match; `\u21A9t` = carried from the previous ask.'
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
return lines;
|
|
397
|
+
}
|
|
701
398
|
function scoreNode(node, terms, weightOf = () => 1) {
|
|
702
399
|
let score = 0;
|
|
703
400
|
let contentHits = 0;
|
|
@@ -707,10 +404,10 @@ function scoreNode(node, terms, weightOf = () => 1) {
|
|
|
707
404
|
const file = node.file.toLowerCase();
|
|
708
405
|
const dirSegments = new Set(file.split("/").slice(0, -1));
|
|
709
406
|
const nameParts = identifierParts(node.name);
|
|
710
|
-
for (const { term: t, weak, from, providerWeight } of terms) {
|
|
407
|
+
for (const { term: t, weak, from, providerWeight, carried } of terms) {
|
|
711
408
|
const expansionW = providerWeight !== void 0 ? Math.min(providerWeight, EXPANSION_WEIGHT) : from ? EXPANSION_WEIGHT : 1;
|
|
712
|
-
const w = weightOf(t) * (weak ? WEAK_TERM_WEIGHT : 1) * expansionW;
|
|
713
|
-
const label = from ? `${from}\u2192${t}` : t;
|
|
409
|
+
const w = weightOf(t) * (weak ? WEAK_TERM_WEIGHT : 1) * expansionW * (carried ? CARRY_WEIGHT : 1);
|
|
410
|
+
const label = (carried ? "\u21A9" : "") + (from ? `${from}\u2192${t}` : t);
|
|
714
411
|
let contribution = 0;
|
|
715
412
|
if (name === t) {
|
|
716
413
|
contribution = 10 * w;
|
|
@@ -726,7 +423,7 @@ function scoreNode(node, terms, weightOf = () => 1) {
|
|
|
726
423
|
hits.push(label);
|
|
727
424
|
} else if (fuzzyPartMatch(t, nameParts)) {
|
|
728
425
|
contribution = 2 * w;
|
|
729
|
-
hits.push(from ? `~${from}\u2192${t}` : `~${t}`);
|
|
426
|
+
hits.push((carried ? "\u21A9" : "") + (from ? `~${from}\u2192${t}` : `~${t}`));
|
|
730
427
|
} else if (dirSegments.has(t)) {
|
|
731
428
|
contribution = 2 * w;
|
|
732
429
|
hits.push(label);
|
|
@@ -895,6 +592,6 @@ function round2(x) {
|
|
|
895
592
|
return Math.round(x * 1e6) / 1e6;
|
|
896
593
|
}
|
|
897
594
|
|
|
898
|
-
export { GraphIndex,
|
|
899
|
-
//# sourceMappingURL=chunk-
|
|
900
|
-
//# sourceMappingURL=chunk-
|
|
595
|
+
export { GraphIndex, conceptMapLines, extractLiteralNeedles, identifierParts, impactOf, indexFor, isLocateOnlyInstruction, queryGraph, queryGraphSemantic, residualForSymbolSearch };
|
|
596
|
+
//# sourceMappingURL=chunk-TVRM57CE.js.map
|
|
597
|
+
//# sourceMappingURL=chunk-TVRM57CE.js.map
|