lens-engine 0.1.20 → 0.1.21
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/cli.js +76 -2
- package/daemon.js +1257 -233
- package/dashboard/assets/{index-D5Z-3_m6.js → index-ojhLsux_.js} +16 -16
- package/dashboard/index.html +1 -1
- package/package.json +14 -3
package/daemon.js
CHANGED
|
@@ -7605,6 +7605,7 @@ var init_esm2 = __esm({
|
|
|
7605
7605
|
var dist_exports = {};
|
|
7606
7606
|
__export(dist_exports, {
|
|
7607
7607
|
DEFAULT_CHUNKING_PARAMS: () => DEFAULT_CHUNKING_PARAMS,
|
|
7608
|
+
GOLD_DATASET: () => GOLD_DATASET,
|
|
7608
7609
|
RequestTrace: () => RequestTrace,
|
|
7609
7610
|
agglomerativeCluster: () => agglomerativeCluster,
|
|
7610
7611
|
analyzeGitHistory: () => analyzeGitHistory,
|
|
@@ -7616,10 +7617,12 @@ __export(dist_exports, {
|
|
|
7616
7617
|
closeDb: () => closeDb,
|
|
7617
7618
|
cochangeQueries: () => cochangeQueries,
|
|
7618
7619
|
computeMaxImportDepth: () => computeMaxImportDepth,
|
|
7620
|
+
computeMetrics: () => computeMetrics,
|
|
7619
7621
|
cosine: () => cosine2,
|
|
7620
7622
|
deriveIdentityKey: () => deriveIdentityKey,
|
|
7621
7623
|
detectLanguage: () => detectLanguage,
|
|
7622
7624
|
diffScan: () => diffScan,
|
|
7625
|
+
discoverTestFiles: () => discoverTestFiles,
|
|
7623
7626
|
enrichPurpose: () => enrichPurpose,
|
|
7624
7627
|
ensureEmbedded: () => ensureEmbedded,
|
|
7625
7628
|
ensureIndexed: () => ensureIndexed,
|
|
@@ -7654,10 +7657,13 @@ __export(dist_exports, {
|
|
|
7654
7657
|
metadataQueries: () => metadataQueries,
|
|
7655
7658
|
openDb: () => openDb,
|
|
7656
7659
|
parseGitLog: () => parseGitLog,
|
|
7660
|
+
parseQuery: () => parseQuery,
|
|
7657
7661
|
registerRepo: () => registerRepo,
|
|
7658
7662
|
removeRepo: () => removeRepo,
|
|
7659
7663
|
repoQueries: () => repoQueries,
|
|
7660
7664
|
resolveImport: () => resolveImport,
|
|
7665
|
+
resolveSnippets: () => resolveSnippets,
|
|
7666
|
+
runEval: () => runEval,
|
|
7661
7667
|
runIndex: () => runIndex,
|
|
7662
7668
|
setTelemetryEnabled: () => setTelemetryEnabled,
|
|
7663
7669
|
settingsQueries: () => settingsQueries,
|
|
@@ -7704,6 +7710,49 @@ function fromEmbeddingBlob(blob2) {
|
|
|
7704
7710
|
const buf = blob2 instanceof Buffer ? blob2 : Buffer.from(blob2);
|
|
7705
7711
|
return new Float32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4);
|
|
7706
7712
|
}
|
|
7713
|
+
function extractSlice(chunks2, targetLine) {
|
|
7714
|
+
const chunk = chunks2.find((c) => c.start_line <= targetLine && targetLine <= c.end_line);
|
|
7715
|
+
if (!chunk) return null;
|
|
7716
|
+
const lines = chunk.content.split("\n");
|
|
7717
|
+
const offset = targetLine - chunk.start_line;
|
|
7718
|
+
const from = Math.max(0, offset - RADIUS);
|
|
7719
|
+
const to = Math.min(lines.length, offset + RADIUS + 1);
|
|
7720
|
+
const sliced = lines.slice(from, to);
|
|
7721
|
+
if (!sliced.length) return null;
|
|
7722
|
+
return {
|
|
7723
|
+
startLine: chunk.start_line + from,
|
|
7724
|
+
endLine: chunk.start_line + to - 1,
|
|
7725
|
+
code: sliced.join("\n")
|
|
7726
|
+
};
|
|
7727
|
+
}
|
|
7728
|
+
function sliceContext(db, repoId, snippets, queryKind) {
|
|
7729
|
+
const result = /* @__PURE__ */ new Map();
|
|
7730
|
+
const limit = MAX_SLICES[queryKind] ?? 3;
|
|
7731
|
+
const candidates = [...snippets.values()].filter((s) => s.line !== null).slice(0, limit);
|
|
7732
|
+
if (!candidates.length) return result;
|
|
7733
|
+
const paths = candidates.map((c) => c.path);
|
|
7734
|
+
const allChunks = chunkQueries.getByRepoPaths(db, repoId, paths);
|
|
7735
|
+
const chunksByPath = /* @__PURE__ */ new Map();
|
|
7736
|
+
for (const c of allChunks) {
|
|
7737
|
+
const arr = chunksByPath.get(c.path) ?? [];
|
|
7738
|
+
arr.push({ start_line: c.start_line, end_line: c.end_line, content: c.content });
|
|
7739
|
+
chunksByPath.set(c.path, arr);
|
|
7740
|
+
}
|
|
7741
|
+
for (const snip of candidates) {
|
|
7742
|
+
const chunks2 = chunksByPath.get(snip.path);
|
|
7743
|
+
if (!chunks2) continue;
|
|
7744
|
+
const slice = extractSlice(chunks2, snip.line);
|
|
7745
|
+
if (!slice) continue;
|
|
7746
|
+
result.set(snip.path, {
|
|
7747
|
+
path: snip.path,
|
|
7748
|
+
startLine: slice.startLine,
|
|
7749
|
+
endLine: slice.endLine,
|
|
7750
|
+
code: slice.code,
|
|
7751
|
+
symbol: snip.symbol
|
|
7752
|
+
});
|
|
7753
|
+
}
|
|
7754
|
+
return result;
|
|
7755
|
+
}
|
|
7707
7756
|
function setTelemetryEnabled(enabled) {
|
|
7708
7757
|
_enabled = enabled;
|
|
7709
7758
|
}
|
|
@@ -8445,101 +8494,372 @@ async function ensureIndexed(db, repoId, caps) {
|
|
|
8445
8494
|
if (repo.last_indexed_commit === head) return null;
|
|
8446
8495
|
return runIndex(db, repoId, caps);
|
|
8447
8496
|
}
|
|
8497
|
+
function estimateTokens(s) {
|
|
8498
|
+
return Math.ceil(s.length / 4);
|
|
8499
|
+
}
|
|
8448
8500
|
function basename3(p) {
|
|
8449
8501
|
const i = p.lastIndexOf("/");
|
|
8450
8502
|
return i >= 0 ? p.substring(i + 1) : p;
|
|
8451
8503
|
}
|
|
8452
|
-
function
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
if (days === 1) return "1d ago";
|
|
8457
|
-
return `${days}d ago`;
|
|
8504
|
+
function guessLang(path) {
|
|
8505
|
+
const dot = path.lastIndexOf(".");
|
|
8506
|
+
if (dot < 0) return "";
|
|
8507
|
+
return LANG_EXT[path.substring(dot + 1)] ?? "";
|
|
8458
8508
|
}
|
|
8459
|
-
function
|
|
8460
|
-
const L = [];
|
|
8461
|
-
const files = data.files.slice(0, 15);
|
|
8462
|
-
const exportsMap = /* @__PURE__ */ new Map();
|
|
8509
|
+
function getPurpose(path, data) {
|
|
8463
8510
|
for (const m of data.metadata) {
|
|
8464
|
-
if (m.
|
|
8511
|
+
if (m.path === path && m.purpose) return m.purpose;
|
|
8465
8512
|
}
|
|
8513
|
+
return "";
|
|
8514
|
+
}
|
|
8515
|
+
function renderImports(path, data) {
|
|
8516
|
+
const fwd = data.forwardImports.get(path)?.slice(0, 3) ?? [];
|
|
8517
|
+
const rev = data.reverseImports.get(path)?.slice(0, 3) ?? [];
|
|
8518
|
+
const parts = [];
|
|
8519
|
+
if (rev.length) parts.push(`\u2190 ${rev.join(", ")}`);
|
|
8520
|
+
if (fwd.length) parts.push(`\u2192 ${fwd.join(", ")}`);
|
|
8521
|
+
return parts.join(" | ");
|
|
8522
|
+
}
|
|
8523
|
+
function renderCochanges(path, cochanges, limit = 2) {
|
|
8524
|
+
const partners = [];
|
|
8525
|
+
for (const cc of cochanges) {
|
|
8526
|
+
if (cc.path === path) partners.push({ name: basename3(cc.partner), count: cc.count });
|
|
8527
|
+
else if (cc.partner === path) partners.push({ name: basename3(cc.path), count: cc.count });
|
|
8528
|
+
}
|
|
8529
|
+
partners.sort((a, b) => b.count - a.count);
|
|
8530
|
+
return partners.slice(0, limit).map((p) => `${p.name} (${p.count}x)`).join(", ");
|
|
8531
|
+
}
|
|
8532
|
+
function getExports(path, data) {
|
|
8533
|
+
for (const m of data.metadata) {
|
|
8534
|
+
if (m.path === path) return m.exports ?? [];
|
|
8535
|
+
}
|
|
8536
|
+
return [];
|
|
8537
|
+
}
|
|
8538
|
+
function fileLabel(path, snippet) {
|
|
8539
|
+
const line = snippet?.line ? `:${snippet.line}` : "";
|
|
8540
|
+
return `${path}${line}`;
|
|
8541
|
+
}
|
|
8542
|
+
function renderSlice(path, data) {
|
|
8543
|
+
const slice = data.slices?.get(path);
|
|
8544
|
+
if (!slice) return null;
|
|
8545
|
+
const lang = guessLang(path);
|
|
8546
|
+
return ` \`\`\`${lang}
|
|
8547
|
+
${slice.code}
|
|
8548
|
+
\`\`\``;
|
|
8549
|
+
}
|
|
8550
|
+
function formatNatural(data) {
|
|
8551
|
+
const L = [];
|
|
8552
|
+
const files = data.files.slice(0, 7);
|
|
8553
|
+
const snippets = data.snippets ?? /* @__PURE__ */ new Map();
|
|
8466
8554
|
L.push(`# ${data.goal}`);
|
|
8467
8555
|
L.push("");
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8556
|
+
L.push("## Key Files");
|
|
8557
|
+
for (let i = 0; i < files.length; i++) {
|
|
8558
|
+
const f = files[i];
|
|
8559
|
+
const snip = snippets.get(f.path);
|
|
8560
|
+
const purpose = getPurpose(f.path, data);
|
|
8561
|
+
const label = fileLabel(f.path, snip);
|
|
8562
|
+
L.push(`${i + 1}. **${label}**${purpose ? ` \u2014 ${purpose}` : ""}`);
|
|
8563
|
+
const exports = getExports(f.path, data);
|
|
8564
|
+
if (exports.length) L.push(` Exports: ${exports.slice(0, 5).join(", ")}`);
|
|
8565
|
+
const imports = renderImports(f.path, data);
|
|
8566
|
+
if (imports) L.push(` ${imports}`);
|
|
8567
|
+
const cochangeStr = renderCochanges(f.path, data.cochanges);
|
|
8568
|
+
if (cochangeStr) L.push(` Co-changes: ${cochangeStr}`);
|
|
8569
|
+
const sliceStr = renderSlice(f.path, data);
|
|
8570
|
+
if (sliceStr) L.push(sliceStr);
|
|
8571
|
+
}
|
|
8572
|
+
const testLines = [];
|
|
8573
|
+
const testFiles = data.testFiles;
|
|
8574
|
+
if (testFiles) {
|
|
8575
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8576
|
+
for (const f of files.slice(0, 5)) {
|
|
8577
|
+
const tests = testFiles.get(f.path);
|
|
8578
|
+
if (tests) {
|
|
8579
|
+
for (const t of tests) {
|
|
8580
|
+
if (!seen.has(t)) {
|
|
8581
|
+
seen.add(t);
|
|
8582
|
+
testLines.push(`- ${t}`);
|
|
8583
|
+
}
|
|
8584
|
+
}
|
|
8585
|
+
}
|
|
8586
|
+
}
|
|
8587
|
+
}
|
|
8588
|
+
if (testLines.length) {
|
|
8589
|
+
L.push("");
|
|
8590
|
+
L.push("## Tests");
|
|
8591
|
+
for (const t of testLines) L.push(t);
|
|
8592
|
+
}
|
|
8593
|
+
return L.join("\n");
|
|
8594
|
+
}
|
|
8595
|
+
function formatSymbol(data) {
|
|
8596
|
+
const L = [];
|
|
8597
|
+
const files = data.files;
|
|
8598
|
+
const snippets = data.snippets ?? /* @__PURE__ */ new Map();
|
|
8599
|
+
const top = files[0];
|
|
8600
|
+
if (!top) return `# ${data.goal}
|
|
8601
|
+
|
|
8602
|
+
No files found.`;
|
|
8603
|
+
const snip = snippets.get(top.path);
|
|
8604
|
+
const purpose = getPurpose(top.path, data);
|
|
8605
|
+
L.push(`# Symbol: ${data.goal}`);
|
|
8606
|
+
L.push("");
|
|
8607
|
+
L.push("## Definition");
|
|
8608
|
+
L.push(`**${fileLabel(top.path, snip)}**${purpose ? ` \u2014 ${purpose}` : ""}`);
|
|
8609
|
+
if (snip?.symbol) {
|
|
8610
|
+
L.push(` \`${snip.symbol}\``);
|
|
8611
|
+
} else {
|
|
8612
|
+
const exports = getExports(top.path, data);
|
|
8613
|
+
if (exports.length) L.push(` Exports: ${exports.slice(0, 5).join(", ")}`);
|
|
8614
|
+
}
|
|
8615
|
+
const sliceStr = renderSlice(top.path, data);
|
|
8616
|
+
if (sliceStr) L.push(sliceStr);
|
|
8617
|
+
const rev = data.reverseImports.get(top.path);
|
|
8618
|
+
if (rev?.length) {
|
|
8619
|
+
L.push("");
|
|
8620
|
+
L.push("## Dependents");
|
|
8621
|
+
L.push(`\u2190 ${rev.slice(0, 5).join(", ")}`);
|
|
8622
|
+
}
|
|
8623
|
+
const cochangeStr = renderCochanges(top.path, data.cochanges, 3);
|
|
8624
|
+
if (cochangeStr) {
|
|
8625
|
+
L.push("");
|
|
8626
|
+
L.push("## Co-changes");
|
|
8627
|
+
L.push(cochangeStr);
|
|
8628
|
+
}
|
|
8629
|
+
if (files.length > 1) {
|
|
8630
|
+
L.push("");
|
|
8631
|
+
L.push("## Also relevant");
|
|
8632
|
+
for (let i = 1; i < Math.min(files.length, 5); i++) {
|
|
8471
8633
|
const f = files[i];
|
|
8472
|
-
const
|
|
8473
|
-
|
|
8474
|
-
L.push(`${i + 1}. ${f.path}${exportStr}`);
|
|
8634
|
+
const p = getPurpose(f.path, data);
|
|
8635
|
+
L.push(`${i + 1}. ${f.path}${p ? ` \u2014 ${p}` : ""}`);
|
|
8475
8636
|
}
|
|
8637
|
+
}
|
|
8638
|
+
return L.join("\n");
|
|
8639
|
+
}
|
|
8640
|
+
function formatError(data) {
|
|
8641
|
+
const L = [];
|
|
8642
|
+
const files = data.files;
|
|
8643
|
+
const snippets = data.snippets ?? /* @__PURE__ */ new Map();
|
|
8644
|
+
L.push(`# Error: ${data.goal}`);
|
|
8645
|
+
L.push("");
|
|
8646
|
+
if (files.length === 0) {
|
|
8647
|
+
L.push("No matching files found.");
|
|
8648
|
+
return L.join("\n");
|
|
8649
|
+
}
|
|
8650
|
+
const top = files[0];
|
|
8651
|
+
const snip = snippets.get(top.path);
|
|
8652
|
+
const purpose = getPurpose(top.path, data);
|
|
8653
|
+
L.push("## Error Source");
|
|
8654
|
+
L.push(`1. **${fileLabel(top.path, snip)}**${purpose ? ` \u2014 ${purpose}` : ""}`);
|
|
8655
|
+
const exports = getExports(top.path, data);
|
|
8656
|
+
if (exports.length) L.push(` Exports: ${exports.slice(0, 5).join(", ")}`);
|
|
8657
|
+
const imports = renderImports(top.path, data);
|
|
8658
|
+
if (imports) L.push(` ${imports}`);
|
|
8659
|
+
const sliceStr = renderSlice(top.path, data);
|
|
8660
|
+
if (sliceStr) L.push(sliceStr);
|
|
8661
|
+
if (files.length > 1) {
|
|
8476
8662
|
L.push("");
|
|
8663
|
+
L.push("## Also References");
|
|
8664
|
+
for (let i = 1; i < Math.min(files.length, 5); i++) {
|
|
8665
|
+
const f = files[i];
|
|
8666
|
+
const s = snippets.get(f.path);
|
|
8667
|
+
const p = getPurpose(f.path, data);
|
|
8668
|
+
L.push(`${i + 1}. **${fileLabel(f.path, s)}**${p ? ` \u2014 ${p}` : ""}`);
|
|
8669
|
+
}
|
|
8477
8670
|
}
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8671
|
+
return L.join("\n");
|
|
8672
|
+
}
|
|
8673
|
+
function formatStackTrace(data) {
|
|
8674
|
+
const L = [];
|
|
8675
|
+
const files = data.files;
|
|
8676
|
+
const snippets = data.snippets ?? /* @__PURE__ */ new Map();
|
|
8677
|
+
L.push("# Stack Trace");
|
|
8678
|
+
L.push("");
|
|
8679
|
+
if (files.length === 0) {
|
|
8680
|
+
L.push("No matching files found.");
|
|
8681
|
+
return L.join("\n");
|
|
8682
|
+
}
|
|
8683
|
+
const top = files[0];
|
|
8684
|
+
const snip = snippets.get(top.path);
|
|
8685
|
+
const purpose = getPurpose(top.path, data);
|
|
8686
|
+
L.push("## Crash Point");
|
|
8687
|
+
L.push(`**${fileLabel(top.path, snip)}**${purpose ? ` \u2014 ${purpose}` : ""}`);
|
|
8688
|
+
if (snip?.symbol) {
|
|
8689
|
+
L.push(` \`${snip.symbol}\``);
|
|
8690
|
+
}
|
|
8691
|
+
const sliceStr = renderSlice(top.path, data);
|
|
8692
|
+
if (sliceStr) L.push(sliceStr);
|
|
8693
|
+
const chain = [];
|
|
8694
|
+
const fwd = data.forwardImports.get(top.path);
|
|
8695
|
+
const rev = data.reverseImports.get(top.path);
|
|
8696
|
+
if (rev?.length || fwd?.length) {
|
|
8697
|
+
const callers = rev?.slice(0, 2) ?? [];
|
|
8698
|
+
const deps = fwd?.slice(0, 2) ?? [];
|
|
8699
|
+
if (callers.length || deps.length) {
|
|
8700
|
+
const parts = [...callers.map((c) => `${c} \u2192`), top.path, ...deps.map((d) => `\u2192 ${d}`)];
|
|
8701
|
+
chain.push(parts.join(" "));
|
|
8702
|
+
}
|
|
8703
|
+
}
|
|
8704
|
+
if (chain.length) {
|
|
8705
|
+
L.push("");
|
|
8706
|
+
L.push("## Call Chain");
|
|
8707
|
+
for (const c of chain) L.push(c);
|
|
8708
|
+
}
|
|
8709
|
+
if (files.length > 1) {
|
|
8710
|
+
L.push("");
|
|
8711
|
+
L.push("## Related");
|
|
8712
|
+
for (let i = 1; i < Math.min(files.length, 5); i++) {
|
|
8713
|
+
const f = files[i];
|
|
8714
|
+
const p = getPurpose(f.path, data);
|
|
8715
|
+
const cochangeStr = renderCochanges(f.path, data.cochanges, 1);
|
|
8716
|
+
L.push(`- ${f.path}${p ? ` \u2014 ${p}` : ""}${cochangeStr ? ` (${cochangeStr})` : ""}`);
|
|
8717
|
+
const relSlice = renderSlice(f.path, data);
|
|
8718
|
+
if (relSlice) L.push(relSlice);
|
|
8719
|
+
}
|
|
8720
|
+
}
|
|
8721
|
+
return L.join("\n");
|
|
8722
|
+
}
|
|
8723
|
+
function stripCodeSlices(lines) {
|
|
8724
|
+
const result = [];
|
|
8725
|
+
let inFence = false;
|
|
8726
|
+
for (const line of lines) {
|
|
8727
|
+
if (line.trimStart().startsWith("```") && !inFence) {
|
|
8728
|
+
inFence = true;
|
|
8729
|
+
continue;
|
|
8487
8730
|
}
|
|
8488
|
-
if (
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8731
|
+
if (inFence && line.trimStart().startsWith("```")) {
|
|
8732
|
+
inFence = false;
|
|
8733
|
+
continue;
|
|
8734
|
+
}
|
|
8735
|
+
if (!inFence) result.push(line);
|
|
8736
|
+
}
|
|
8737
|
+
return result;
|
|
8738
|
+
}
|
|
8739
|
+
function progressiveStrip(output, _data) {
|
|
8740
|
+
let lines = output.split("\n");
|
|
8741
|
+
if (estimateTokens(lines.join("\n")) > TOKEN_CAP) {
|
|
8742
|
+
lines = stripCodeSlices(lines);
|
|
8743
|
+
}
|
|
8744
|
+
if (estimateTokens(lines.join("\n")) > TOKEN_CAP) {
|
|
8745
|
+
lines = lines.map((l) => {
|
|
8746
|
+
if (l.trimStart().startsWith("Co-changes:")) {
|
|
8747
|
+
const match2 = l.match(/Co-changes:\s*([^,]+)/);
|
|
8748
|
+
if (match2) return `${l.substring(0, l.indexOf("Co-changes:"))}Co-changes: ${match2[1].trim()}`;
|
|
8492
8749
|
}
|
|
8493
|
-
|
|
8750
|
+
return l;
|
|
8751
|
+
});
|
|
8752
|
+
}
|
|
8753
|
+
if (estimateTokens(lines.join("\n")) > TOKEN_CAP) {
|
|
8754
|
+
const testIdx = lines.findIndex((l) => l.startsWith("## Tests"));
|
|
8755
|
+
if (testIdx >= 0) {
|
|
8756
|
+
let endIdx = lines.findIndex((l, i) => i > testIdx && l.startsWith("## "));
|
|
8757
|
+
if (endIdx < 0) endIdx = lines.length;
|
|
8758
|
+
lines.splice(testIdx, endIdx - testIdx);
|
|
8494
8759
|
}
|
|
8495
8760
|
}
|
|
8496
|
-
if (
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8761
|
+
if (estimateTokens(lines.join("\n")) > TOKEN_CAP) {
|
|
8762
|
+
lines = lines.filter((l) => {
|
|
8763
|
+
const trimmed = l.trimStart();
|
|
8764
|
+
return !(trimmed.startsWith("\u2190") || trimmed.startsWith("\u2192")) || !trimmed.includes("|");
|
|
8765
|
+
});
|
|
8500
8766
|
}
|
|
8501
|
-
if (
|
|
8502
|
-
const
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8767
|
+
if (estimateTokens(lines.join("\n")) > TOKEN_CAP) {
|
|
8768
|
+
const reduced = [];
|
|
8769
|
+
let fileCount = 0;
|
|
8770
|
+
for (const line of lines) {
|
|
8771
|
+
if (/^\d+\./.test(line.trimStart())) {
|
|
8772
|
+
fileCount++;
|
|
8773
|
+
if (fileCount > 5) continue;
|
|
8507
8774
|
}
|
|
8508
|
-
|
|
8775
|
+
reduced.push(line);
|
|
8509
8776
|
}
|
|
8777
|
+
lines = reduced;
|
|
8510
8778
|
}
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8779
|
+
if (estimateTokens(lines.join("\n")) > TOKEN_CAP) {
|
|
8780
|
+
lines = lines.map((l) => {
|
|
8781
|
+
const dashIdx = l.indexOf(" \u2014 ");
|
|
8782
|
+
if (dashIdx > 0 && (l.includes("**") || /^\d+\./.test(l.trimStart()))) {
|
|
8783
|
+
return l.substring(0, dashIdx);
|
|
8784
|
+
}
|
|
8785
|
+
return l;
|
|
8786
|
+
});
|
|
8787
|
+
}
|
|
8788
|
+
return lines.join("\n");
|
|
8789
|
+
}
|
|
8790
|
+
function filterByScoreRelevance(data) {
|
|
8791
|
+
if (!data.scores || data.scores.size === 0) return data;
|
|
8792
|
+
const topScore = Math.max(...data.scores.values());
|
|
8793
|
+
if (topScore <= 0) return data;
|
|
8794
|
+
const threshold = topScore * 0.15;
|
|
8795
|
+
const filtered = data.files.filter((f) => {
|
|
8796
|
+
const score = data.scores?.get(f.path);
|
|
8797
|
+
if (score === void 0) return data.files.indexOf(f) < 5;
|
|
8798
|
+
return score >= threshold;
|
|
8799
|
+
});
|
|
8800
|
+
return { ...data, files: filtered };
|
|
8801
|
+
}
|
|
8802
|
+
function formatContextPack(data) {
|
|
8803
|
+
const filtered = filterByScoreRelevance(data);
|
|
8804
|
+
let output;
|
|
8805
|
+
switch (filtered.queryKind) {
|
|
8806
|
+
case "symbol":
|
|
8807
|
+
output = formatSymbol(filtered);
|
|
8808
|
+
break;
|
|
8809
|
+
case "error_message":
|
|
8810
|
+
output = formatError(filtered);
|
|
8811
|
+
break;
|
|
8812
|
+
case "stack_trace":
|
|
8813
|
+
output = formatStackTrace(filtered);
|
|
8814
|
+
break;
|
|
8815
|
+
default:
|
|
8816
|
+
output = formatNatural(filtered);
|
|
8817
|
+
break;
|
|
8518
8818
|
}
|
|
8519
|
-
if (
|
|
8520
|
-
|
|
8521
|
-
for (const line of activityLines) L.push(line);
|
|
8819
|
+
if (estimateTokens(output) > TOKEN_CAP) {
|
|
8820
|
+
output = progressiveStrip(output, filtered);
|
|
8522
8821
|
}
|
|
8523
|
-
return
|
|
8822
|
+
return output;
|
|
8524
8823
|
}
|
|
8525
|
-
function
|
|
8526
|
-
const
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8824
|
+
function extractFrames(query) {
|
|
8825
|
+
const frames = [];
|
|
8826
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8827
|
+
for (const pattern of FRAME_PATTERNS) {
|
|
8828
|
+
pattern.lastIndex = 0;
|
|
8829
|
+
let m;
|
|
8830
|
+
while (m = pattern.exec(query)) {
|
|
8831
|
+
const raw2 = m[1].replace(/^\.\//, "").replace(/^\/+/, "");
|
|
8832
|
+
const line = Number.parseInt(m[2], 10);
|
|
8833
|
+
const key = `${raw2}:${line}`;
|
|
8834
|
+
if (!seen.has(key)) {
|
|
8835
|
+
seen.add(key);
|
|
8836
|
+
frames.push({ path: raw2, line });
|
|
8536
8837
|
}
|
|
8537
8838
|
}
|
|
8538
|
-
if (!merged) {
|
|
8539
|
-
clusters.push({ members: [cc.path, cc.partner], count: cc.count });
|
|
8540
|
-
}
|
|
8541
8839
|
}
|
|
8542
|
-
return
|
|
8840
|
+
return frames;
|
|
8841
|
+
}
|
|
8842
|
+
function tokenize(query) {
|
|
8843
|
+
return query.toLowerCase().replace(/[^a-z0-9\s_-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w));
|
|
8844
|
+
}
|
|
8845
|
+
function parseQuery(query) {
|
|
8846
|
+
const naturalTokens = tokenize(query);
|
|
8847
|
+
const frames = extractFrames(query);
|
|
8848
|
+
if (frames.length >= 2) {
|
|
8849
|
+
return { kind: "stack_trace", raw: query, frames, symbol: null, errorToken: null, naturalTokens };
|
|
8850
|
+
}
|
|
8851
|
+
const trimmed = query.trim();
|
|
8852
|
+
if (SYMBOL_RE.test(trimmed) && trimmed.length >= 4 && CASING_BOUNDARY.test(trimmed)) {
|
|
8853
|
+
return { kind: "symbol", raw: query, frames: [], symbol: trimmed, errorToken: null, naturalTokens };
|
|
8854
|
+
}
|
|
8855
|
+
const errorCode = query.match(ERROR_CODE_RE)?.[0];
|
|
8856
|
+
const errorSuffix = query.match(ERROR_SUFFIX_RE)?.[0];
|
|
8857
|
+
const errorPrefix = query.match(ERROR_PREFIX_RE)?.[1];
|
|
8858
|
+
const errorToken = errorCode || errorSuffix || errorPrefix || null;
|
|
8859
|
+
if (errorToken) {
|
|
8860
|
+
return { kind: "error_message", raw: query, frames, symbol: null, errorToken, naturalTokens };
|
|
8861
|
+
}
|
|
8862
|
+
return { kind: "natural", raw: query, frames, symbol: null, errorToken: null, naturalTokens };
|
|
8543
8863
|
}
|
|
8544
8864
|
function stem(word) {
|
|
8545
8865
|
if (word.length <= 4) return word;
|
|
@@ -8547,6 +8867,7 @@ function stem(word) {
|
|
|
8547
8867
|
}
|
|
8548
8868
|
function expandKeywords(words, clusters) {
|
|
8549
8869
|
const exact = /* @__PURE__ */ new Set();
|
|
8870
|
+
const expanded = /* @__PURE__ */ new Set();
|
|
8550
8871
|
const stemmed = /* @__PURE__ */ new Set();
|
|
8551
8872
|
const clusterFiles = /* @__PURE__ */ new Set();
|
|
8552
8873
|
for (const w of words) {
|
|
@@ -8555,7 +8876,7 @@ function expandKeywords(words, clusters) {
|
|
|
8555
8876
|
if (s.length >= 3 && s !== w) stemmed.add(s);
|
|
8556
8877
|
if (w.includes("-")) {
|
|
8557
8878
|
for (const part of w.split("-")) {
|
|
8558
|
-
if (part.length > 2 && !
|
|
8879
|
+
if (part.length > 2 && !STOPWORDS2.has(part)) {
|
|
8559
8880
|
exact.add(part);
|
|
8560
8881
|
const ps = stem(part);
|
|
8561
8882
|
if (ps.length >= 3 && ps !== part) stemmed.add(ps);
|
|
@@ -8566,21 +8887,26 @@ function expandKeywords(words, clusters) {
|
|
|
8566
8887
|
for (const w of words) {
|
|
8567
8888
|
const synonyms = CONCEPT_SYNONYMS[w];
|
|
8568
8889
|
if (synonyms) {
|
|
8569
|
-
for (const syn of synonyms)
|
|
8890
|
+
for (const syn of synonyms) {
|
|
8891
|
+
if (!exact.has(syn)) expanded.add(syn);
|
|
8892
|
+
}
|
|
8570
8893
|
}
|
|
8571
8894
|
}
|
|
8572
8895
|
if (clusters) {
|
|
8573
8896
|
for (const w of words) {
|
|
8574
8897
|
for (const cluster of clusters) {
|
|
8575
8898
|
if (cluster.terms.includes(w) || cluster.terms.some((t) => stem(t) === stem(w))) {
|
|
8576
|
-
for (const t of cluster.terms)
|
|
8899
|
+
for (const t of cluster.terms) {
|
|
8900
|
+
if (!exact.has(t)) expanded.add(t);
|
|
8901
|
+
}
|
|
8577
8902
|
for (const f of cluster.files) clusterFiles.add(f);
|
|
8578
8903
|
}
|
|
8579
8904
|
}
|
|
8580
8905
|
}
|
|
8581
8906
|
}
|
|
8582
8907
|
for (const e of exact) stemmed.delete(e);
|
|
8583
|
-
|
|
8908
|
+
for (const e of expanded) stemmed.delete(e);
|
|
8909
|
+
return { exact: [...exact], expanded, stemmed: [...stemmed], clusterFiles };
|
|
8584
8910
|
}
|
|
8585
8911
|
function isNoisePath(path) {
|
|
8586
8912
|
const lower = path.toLowerCase();
|
|
@@ -8604,17 +8930,17 @@ function buildTermWeights(words, metadata) {
|
|
|
8604
8930
|
}
|
|
8605
8931
|
return weights;
|
|
8606
8932
|
}
|
|
8607
|
-
function interpretQuery(query, metadata, fileStats2, vocabClusters, indegrees, maxImportDepth) {
|
|
8608
|
-
const rawWords = query.toLowerCase().replace(/[^a-z0-9\s_-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !
|
|
8609
|
-
const { exact, stemmed, clusterFiles } = expandKeywords(rawWords, vocabClusters ?? null);
|
|
8610
|
-
const allTerms = [...exact, ...stemmed];
|
|
8933
|
+
function interpretQuery(query, metadata, fileStats2, vocabClusters, indegrees, maxImportDepth, parsed) {
|
|
8934
|
+
const rawWords = query.toLowerCase().replace(/[^a-z0-9\s_-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS2.has(w));
|
|
8935
|
+
const { exact, expanded, stemmed, clusterFiles } = expandKeywords(rawWords, vocabClusters ?? null);
|
|
8936
|
+
const allTerms = [...exact, ...expanded, ...stemmed];
|
|
8611
8937
|
const termWeights = buildTermWeights(allTerms, metadata);
|
|
8612
8938
|
const exportTokensMap = /* @__PURE__ */ new Map();
|
|
8613
8939
|
for (const f of metadata) {
|
|
8614
8940
|
const tokens = /* @__PURE__ */ new Set();
|
|
8615
8941
|
for (const exp of f.exports ?? []) {
|
|
8616
8942
|
for (const part of exp.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(/[\s_-]+/)) {
|
|
8617
|
-
if (part.length >= 3 && !
|
|
8943
|
+
if (part.length >= 3 && !STOPWORDS2.has(part)) tokens.add(part);
|
|
8618
8944
|
}
|
|
8619
8945
|
}
|
|
8620
8946
|
exportTokensMap.set(f.path, tokens);
|
|
@@ -8634,6 +8960,32 @@ function interpretQuery(query, metadata, fileStats2, vocabClusters, indegrees, m
|
|
|
8634
8960
|
const dirTokens = pathSegments.slice(-4, -1).flatMap((s) => s.replace(/\./g, " ").split(/\s+/)).filter((t) => t.length >= 2);
|
|
8635
8961
|
const pathTokenSet = /* @__PURE__ */ new Set([...fileTokens, ...dirTokens]);
|
|
8636
8962
|
const expTokens = exportTokensMap.get(f.path);
|
|
8963
|
+
if (parsed) {
|
|
8964
|
+
if (parsed.kind === "stack_trace") {
|
|
8965
|
+
for (const frame of parsed.frames) {
|
|
8966
|
+
if (f.path.endsWith(frame.path) || frame.path.endsWith(f.path)) {
|
|
8967
|
+
score += 50;
|
|
8968
|
+
}
|
|
8969
|
+
}
|
|
8970
|
+
} else if (parsed.kind === "symbol" && parsed.symbol) {
|
|
8971
|
+
const sym = parsed.symbol;
|
|
8972
|
+
if ((f.exports ?? []).includes(sym)) score += 100;
|
|
8973
|
+
else if ((f.internals ?? []).includes(sym)) score += 80;
|
|
8974
|
+
} else if (parsed.kind === "error_message") {
|
|
8975
|
+
if (parsed.errorToken) {
|
|
8976
|
+
const token = parsed.errorToken.toLowerCase();
|
|
8977
|
+
if (exportsLower.includes(token) || internalsLower.includes(token) || pathLower.includes(token)) {
|
|
8978
|
+
score += 30;
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8981
|
+
const rawError = parsed.raw.replace(/^(Error|TypeError|ReferenceError|SyntaxError|RangeError|FATAL|WARN|ERR):\s*/i, "").toLowerCase().trim();
|
|
8982
|
+
if (rawError.length >= 5) {
|
|
8983
|
+
if (docLower.includes(rawError) || sectionsLower.includes(rawError) || internalsLower.includes(rawError) || purposeLower.includes(rawError)) {
|
|
8984
|
+
score += 40;
|
|
8985
|
+
}
|
|
8986
|
+
}
|
|
8987
|
+
}
|
|
8988
|
+
}
|
|
8637
8989
|
for (const w of exact) {
|
|
8638
8990
|
const weight = termWeights.get(w) ?? 1;
|
|
8639
8991
|
let termScore = 0;
|
|
@@ -8647,6 +8999,16 @@ function interpretQuery(query, metadata, fileStats2, vocabClusters, indegrees, m
|
|
|
8647
8999
|
if (termScore > 0) matchedTerms++;
|
|
8648
9000
|
score += termScore;
|
|
8649
9001
|
}
|
|
9002
|
+
for (const w of expanded) {
|
|
9003
|
+
const weight = (termWeights.get(w) ?? 1) * 0.5;
|
|
9004
|
+
let termScore = 0;
|
|
9005
|
+
if (expTokens?.has(w)) termScore += 2 * weight;
|
|
9006
|
+
else if (exportsLower.includes(w)) termScore += 1.5 * weight;
|
|
9007
|
+
if (docLower.includes(w) || purposeLower.includes(w)) termScore += 1 * weight;
|
|
9008
|
+
if (internalsLower.includes(w)) termScore += 1 * weight;
|
|
9009
|
+
if (termScore > 0) matchedTerms++;
|
|
9010
|
+
score += termScore;
|
|
9011
|
+
}
|
|
8650
9012
|
for (const w of stemmed) {
|
|
8651
9013
|
const weight = termWeights.get(w) ?? 1;
|
|
8652
9014
|
let termScore = 0;
|
|
@@ -8662,7 +9024,7 @@ function interpretQuery(query, metadata, fileStats2, vocabClusters, indegrees, m
|
|
|
8662
9024
|
score *= 1 + coverage * coverage;
|
|
8663
9025
|
}
|
|
8664
9026
|
if (score > 0 && isNoisePath(f.path)) {
|
|
8665
|
-
score
|
|
9027
|
+
score = 0;
|
|
8666
9028
|
}
|
|
8667
9029
|
const exportCount = (f.exports ?? []).length;
|
|
8668
9030
|
if (exportCount > 5 && score > 0) {
|
|
@@ -8696,14 +9058,27 @@ function interpretQuery(query, metadata, fileStats2, vocabClusters, indegrees, m
|
|
|
8696
9058
|
deduped.push(f);
|
|
8697
9059
|
if (deduped.length >= fileCap) break;
|
|
8698
9060
|
}
|
|
9061
|
+
const scores = /* @__PURE__ */ new Map();
|
|
9062
|
+
for (const f of deduped) scores.set(f.path, f.score);
|
|
8699
9063
|
return {
|
|
8700
9064
|
fileCap,
|
|
9065
|
+
scores,
|
|
8701
9066
|
files: deduped.map((f) => {
|
|
8702
|
-
const reason = f.docstring
|
|
9067
|
+
const reason = truncateAtWord(f.docstring, 80) || formatExports(f.exports) || f.path.split("/").pop() || "";
|
|
8703
9068
|
return { path: f.path, reason };
|
|
8704
9069
|
})
|
|
8705
9070
|
};
|
|
8706
9071
|
}
|
|
9072
|
+
function truncateAtWord(s, max) {
|
|
9073
|
+
if (!s) return "";
|
|
9074
|
+
if (s.length <= max) return s;
|
|
9075
|
+
const cut = s.lastIndexOf(" ", max);
|
|
9076
|
+
return cut > max * 0.5 ? `${s.slice(0, cut)}...` : `${s.slice(0, max)}...`;
|
|
9077
|
+
}
|
|
9078
|
+
function formatExports(exports) {
|
|
9079
|
+
if (!exports?.length) return "";
|
|
9080
|
+
return `exports: ${exports.slice(0, 4).join(", ")}`;
|
|
9081
|
+
}
|
|
8707
9082
|
function siblingKey(path) {
|
|
8708
9083
|
const lastSlash = path.lastIndexOf("/");
|
|
8709
9084
|
const dir = lastSlash >= 0 ? path.substring(0, lastSlash) : "";
|
|
@@ -8712,6 +9087,99 @@ function siblingKey(path) {
|
|
|
8712
9087
|
const tokens = stem2.split(/[-.]/).slice(0, 3).join("-");
|
|
8713
9088
|
return `${dir}/${tokens}`;
|
|
8714
9089
|
}
|
|
9090
|
+
function findSymbolLine(symbol, chunkRows) {
|
|
9091
|
+
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9092
|
+
const re = new RegExp(`\\b${escaped}\\b`);
|
|
9093
|
+
for (const chunk of chunkRows) {
|
|
9094
|
+
const lines = chunk.content.split("\n");
|
|
9095
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9096
|
+
if (re.test(lines[i]) && SYMBOL_DEF_RE.test(lines[i])) {
|
|
9097
|
+
return chunk.start_line + i;
|
|
9098
|
+
}
|
|
9099
|
+
}
|
|
9100
|
+
}
|
|
9101
|
+
for (const chunk of chunkRows) {
|
|
9102
|
+
const lines = chunk.content.split("\n");
|
|
9103
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9104
|
+
if (re.test(lines[i])) {
|
|
9105
|
+
return chunk.start_line + i;
|
|
9106
|
+
}
|
|
9107
|
+
}
|
|
9108
|
+
}
|
|
9109
|
+
return null;
|
|
9110
|
+
}
|
|
9111
|
+
function pickBestExport(exports, queryTokens) {
|
|
9112
|
+
if (exports.length <= 1 || !queryTokens.length) return exports[0];
|
|
9113
|
+
let best = exports[0];
|
|
9114
|
+
let bestScore = 0;
|
|
9115
|
+
for (const exp of exports) {
|
|
9116
|
+
const lower = exp.toLowerCase();
|
|
9117
|
+
const expTokens = lower.replace(/([a-z])([A-Z])/g, "$1 $2").split(/[\s_-]+/);
|
|
9118
|
+
let score = 0;
|
|
9119
|
+
for (const qt of queryTokens) {
|
|
9120
|
+
if (lower.includes(qt)) score += 2;
|
|
9121
|
+
else if (expTokens.some((t) => t.includes(qt) || qt.includes(t))) score++;
|
|
9122
|
+
}
|
|
9123
|
+
if (score > bestScore) {
|
|
9124
|
+
bestScore = score;
|
|
9125
|
+
best = exp;
|
|
9126
|
+
}
|
|
9127
|
+
}
|
|
9128
|
+
return best;
|
|
9129
|
+
}
|
|
9130
|
+
function resolveSnippets(db, repoId, files, metadata, parsed, limit = 5) {
|
|
9131
|
+
const result = /* @__PURE__ */ new Map();
|
|
9132
|
+
const topFiles = files.slice(0, limit);
|
|
9133
|
+
const topPaths = topFiles.map((f) => f.path);
|
|
9134
|
+
const allChunks = chunkQueries.getByRepoPaths(db, repoId, topPaths);
|
|
9135
|
+
const chunksByPath = /* @__PURE__ */ new Map();
|
|
9136
|
+
for (const c of allChunks) {
|
|
9137
|
+
const arr = chunksByPath.get(c.path) ?? [];
|
|
9138
|
+
arr.push({ start_line: c.start_line, content: c.content });
|
|
9139
|
+
chunksByPath.set(c.path, arr);
|
|
9140
|
+
}
|
|
9141
|
+
const metaMap = /* @__PURE__ */ new Map();
|
|
9142
|
+
for (const m of metadata) metaMap.set(m.path, m);
|
|
9143
|
+
const frameByPath = /* @__PURE__ */ new Map();
|
|
9144
|
+
for (const frame of parsed.frames) {
|
|
9145
|
+
for (const p of topPaths) {
|
|
9146
|
+
if (p.endsWith(frame.path) || frame.path.endsWith(p)) {
|
|
9147
|
+
frameByPath.set(p, frame.line);
|
|
9148
|
+
}
|
|
9149
|
+
}
|
|
9150
|
+
}
|
|
9151
|
+
for (const f of topFiles) {
|
|
9152
|
+
const chunks2 = chunksByPath.get(f.path) ?? [];
|
|
9153
|
+
const meta = metaMap.get(f.path);
|
|
9154
|
+
const frameLine = frameByPath.get(f.path);
|
|
9155
|
+
if (frameLine !== void 0) {
|
|
9156
|
+
result.set(f.path, { path: f.path, symbol: null, line: frameLine, matchKind: "frame" });
|
|
9157
|
+
continue;
|
|
9158
|
+
}
|
|
9159
|
+
if (parsed.symbol) {
|
|
9160
|
+
const exports = meta?.exports ?? [];
|
|
9161
|
+
const internals = meta?.internals ?? [];
|
|
9162
|
+
if (exports.includes(parsed.symbol)) {
|
|
9163
|
+
const line = findSymbolLine(parsed.symbol, chunks2);
|
|
9164
|
+
result.set(f.path, { path: f.path, symbol: parsed.symbol, line, matchKind: "export" });
|
|
9165
|
+
continue;
|
|
9166
|
+
}
|
|
9167
|
+
if (internals.includes(parsed.symbol)) {
|
|
9168
|
+
const line = findSymbolLine(parsed.symbol, chunks2);
|
|
9169
|
+
result.set(f.path, { path: f.path, symbol: parsed.symbol, line, matchKind: "internal" });
|
|
9170
|
+
continue;
|
|
9171
|
+
}
|
|
9172
|
+
}
|
|
9173
|
+
if (meta?.exports?.length) {
|
|
9174
|
+
const bestExport = pickBestExport(meta.exports, parsed.naturalTokens);
|
|
9175
|
+
const line = findSymbolLine(bestExport, chunks2);
|
|
9176
|
+
result.set(f.path, { path: f.path, symbol: bestExport, line, matchKind: "export" });
|
|
9177
|
+
continue;
|
|
9178
|
+
}
|
|
9179
|
+
result.set(f.path, { path: f.path, symbol: null, line: null, matchKind: null });
|
|
9180
|
+
}
|
|
9181
|
+
return result;
|
|
9182
|
+
}
|
|
8715
9183
|
function loadFileMetadata(db, repoId) {
|
|
8716
9184
|
return metadataQueries.getByRepo(db, repoId);
|
|
8717
9185
|
}
|
|
@@ -8774,6 +9242,37 @@ function getIndegrees(db, repoId) {
|
|
|
8774
9242
|
function getCochangePartners(db, repoId, paths, minCount = 5, limit = 10) {
|
|
8775
9243
|
return cochangeQueries.getPartners(db, repoId, paths, minCount, limit);
|
|
8776
9244
|
}
|
|
9245
|
+
function discoverTestFiles(reverseImports, cochanges, metadataPaths, sourcePaths) {
|
|
9246
|
+
const result = /* @__PURE__ */ new Map();
|
|
9247
|
+
for (const src of sourcePaths) {
|
|
9248
|
+
const tests = /* @__PURE__ */ new Set();
|
|
9249
|
+
const importers = reverseImports.get(src) ?? [];
|
|
9250
|
+
for (const imp of importers) {
|
|
9251
|
+
if (TEST_PATTERN.test(imp)) tests.add(imp);
|
|
9252
|
+
}
|
|
9253
|
+
for (const cc of cochanges) {
|
|
9254
|
+
const partner = cc.path === src ? cc.partner : cc.partner === src ? cc.path : null;
|
|
9255
|
+
if (partner && TEST_PATTERN.test(partner)) tests.add(partner);
|
|
9256
|
+
}
|
|
9257
|
+
const ext = src.slice(src.lastIndexOf("."));
|
|
9258
|
+
const base = src.slice(0, src.lastIndexOf("."));
|
|
9259
|
+
const dir = src.slice(0, src.lastIndexOf("/"));
|
|
9260
|
+
const name = src.slice(src.lastIndexOf("/") + 1, src.lastIndexOf("."));
|
|
9261
|
+
const candidates = [
|
|
9262
|
+
`${base}.test${ext}`,
|
|
9263
|
+
`${base}.spec${ext}`,
|
|
9264
|
+
`${dir}/__tests__/${name}${ext}`,
|
|
9265
|
+
`${dir}/__tests__/${name}.test${ext}`
|
|
9266
|
+
];
|
|
9267
|
+
for (const c of candidates) {
|
|
9268
|
+
if (metadataPaths.has(c)) tests.add(c);
|
|
9269
|
+
}
|
|
9270
|
+
if (tests.size > 0) {
|
|
9271
|
+
result.set(src, [...tests].slice(0, 3));
|
|
9272
|
+
}
|
|
9273
|
+
}
|
|
9274
|
+
return result;
|
|
9275
|
+
}
|
|
8777
9276
|
function loadVocabClusters(db, repoId) {
|
|
8778
9277
|
const repo = repoQueries.getById(db, repoId);
|
|
8779
9278
|
if (!repo?.vocab_clusters) return null;
|
|
@@ -8834,18 +9333,21 @@ async function buildContext(db, repoId, goal, caps, trace, options) {
|
|
|
8834
9333
|
const repo = repoQueries.getById(db, repoId);
|
|
8835
9334
|
const commit = repo?.last_indexed_commit ?? null;
|
|
8836
9335
|
const useEmb = options?.useEmbeddings !== false;
|
|
8837
|
-
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
9336
|
+
if (!options?.skipCache) {
|
|
9337
|
+
const key = cacheKey(repoId, goal, commit, useEmb);
|
|
9338
|
+
const cached2 = cacheGet(key);
|
|
9339
|
+
if (cached2) {
|
|
9340
|
+
trace?.add("cache", 0, "HIT");
|
|
9341
|
+
track(db, "context", {
|
|
9342
|
+
duration_ms: Date.now() - start,
|
|
9343
|
+
result_count: cached2.stats.files_in_context,
|
|
9344
|
+
cache_hit: true
|
|
9345
|
+
});
|
|
9346
|
+
return { ...cached2, stats: { ...cached2.stats, cached: true, duration_ms: Date.now() - start } };
|
|
9347
|
+
}
|
|
8847
9348
|
}
|
|
8848
9349
|
const embAvailable = useEmb && (await Promise.resolve().then(() => (init_queries(), queries_exports))).chunkQueries.hasEmbeddings(db, repoId);
|
|
9350
|
+
const parsed = parseQuery(goal);
|
|
8849
9351
|
trace?.step("loadStructural");
|
|
8850
9352
|
const metadata = loadFileMetadata(db, repoId);
|
|
8851
9353
|
const allStats = getAllFileStats(db, repoId);
|
|
@@ -8861,11 +9363,44 @@ async function buildContext(db, repoId, goal, caps, trace, options) {
|
|
|
8861
9363
|
statsForInterpreter.set(path, { commit_count: stat32.commit_count, recent_count: stat32.recent_count });
|
|
8862
9364
|
}
|
|
8863
9365
|
trace?.step("interpretQuery");
|
|
8864
|
-
const interpreted = interpretQuery(
|
|
8865
|
-
|
|
9366
|
+
const interpreted = interpretQuery(
|
|
9367
|
+
goal,
|
|
9368
|
+
metadata,
|
|
9369
|
+
statsForInterpreter,
|
|
9370
|
+
vocabClusters,
|
|
9371
|
+
indegreeMap,
|
|
9372
|
+
maxImportDepth,
|
|
9373
|
+
parsed
|
|
9374
|
+
);
|
|
9375
|
+
trace?.end("interpretQuery", `${interpreted.files.length} files (${parsed.kind})`);
|
|
9376
|
+
if (parsed.kind === "error_message") {
|
|
9377
|
+
trace?.step("errorContentSearch");
|
|
9378
|
+
const rawError = parsed.raw.replace(/^(Error|TypeError|ReferenceError|SyntaxError|RangeError|FATAL|WARN|ERR):\s*/i, "").trim();
|
|
9379
|
+
if (rawError.length >= 5) {
|
|
9380
|
+
const contentHits = chunkQueries.searchContent(db, repoId, rawError).filter((p) => !isNoisePath(p));
|
|
9381
|
+
const scored = contentHits.filter((p) => (interpreted.scores.get(p) ?? 0) > 0);
|
|
9382
|
+
const unscored = contentHits.filter((p) => (interpreted.scores.get(p) ?? 0) === 0);
|
|
9383
|
+
const capped = [...scored.slice(0, 3), ...unscored.slice(0, Math.max(0, 3 - scored.length))];
|
|
9384
|
+
const existingSet = new Set(interpreted.files.map((f) => f.path));
|
|
9385
|
+
for (const p of capped) {
|
|
9386
|
+
const currentScore = interpreted.scores.get(p) ?? 0;
|
|
9387
|
+
interpreted.scores.set(p, currentScore + 40);
|
|
9388
|
+
if (!existingSet.has(p)) {
|
|
9389
|
+
const meta = metadata.find((m) => m.path === p);
|
|
9390
|
+
interpreted.files.push({
|
|
9391
|
+
path: p,
|
|
9392
|
+
reason: meta?.docstring?.slice(0, 80) || `contains "${rawError.slice(0, 30)}"`
|
|
9393
|
+
});
|
|
9394
|
+
existingSet.add(p);
|
|
9395
|
+
}
|
|
9396
|
+
}
|
|
9397
|
+
interpreted.files.sort((a, b) => (interpreted.scores.get(b.path) ?? 0) - (interpreted.scores.get(a.path) ?? 0));
|
|
9398
|
+
}
|
|
9399
|
+
trace?.end("errorContentSearch");
|
|
9400
|
+
}
|
|
8866
9401
|
trace?.step("cochangePromotion");
|
|
8867
9402
|
const topForCochange = interpreted.files.slice(0, 5).map((f) => f.path);
|
|
8868
|
-
const cochangePartners = getCochangePartners(db, repoId, topForCochange,
|
|
9403
|
+
const cochangePartners = getCochangePartners(db, repoId, topForCochange, 5, 15);
|
|
8869
9404
|
const existingPathSet = new Set(interpreted.files.map((f) => f.path));
|
|
8870
9405
|
let promoted = 0;
|
|
8871
9406
|
for (const cp of cochangePartners) {
|
|
@@ -8945,6 +9480,20 @@ async function buildContext(db, repoId, goal, caps, trace, options) {
|
|
|
8945
9480
|
}
|
|
8946
9481
|
}
|
|
8947
9482
|
trace?.end("structuralEnrichment");
|
|
9483
|
+
trace?.step("resolveSnippets");
|
|
9484
|
+
const snippets = resolveSnippets(db, repoId, interpreted.files, metadata, parsed, 5);
|
|
9485
|
+
const metadataPaths = new Set(metadata.map((m) => m.path));
|
|
9486
|
+
const testFiles = discoverTestFiles(
|
|
9487
|
+
reverseImports,
|
|
9488
|
+
cochanges,
|
|
9489
|
+
metadataPaths,
|
|
9490
|
+
interpreted.files.slice(0, 5).map((f) => f.path)
|
|
9491
|
+
);
|
|
9492
|
+
trace?.end("resolveSnippets", `${snippets.size} snippets, ${testFiles.size} test maps`);
|
|
9493
|
+
trace?.step("sliceContext");
|
|
9494
|
+
const { sliceContext: sliceCtx } = await Promise.resolve().then(() => (init_slicer(), slicer_exports));
|
|
9495
|
+
const slices = sliceCtx(db, repoId, snippets, parsed.kind);
|
|
9496
|
+
trace?.end("sliceContext", `${slices.size} slices`);
|
|
8948
9497
|
trace?.step("formatContextPack");
|
|
8949
9498
|
const data = {
|
|
8950
9499
|
goal,
|
|
@@ -8954,7 +9503,12 @@ async function buildContext(db, repoId, goal, caps, trace, options) {
|
|
|
8954
9503
|
forwardImports,
|
|
8955
9504
|
hop2Deps,
|
|
8956
9505
|
cochanges,
|
|
8957
|
-
fileStats: allStats
|
|
9506
|
+
fileStats: allStats,
|
|
9507
|
+
scores: interpreted.scores,
|
|
9508
|
+
snippets,
|
|
9509
|
+
slices,
|
|
9510
|
+
testFiles,
|
|
9511
|
+
queryKind: parsed.kind
|
|
8958
9512
|
};
|
|
8959
9513
|
const contextPack = formatContextPack(data);
|
|
8960
9514
|
trace?.end("formatContextPack");
|
|
@@ -8967,7 +9521,18 @@ async function buildContext(db, repoId, goal, caps, trace, options) {
|
|
|
8967
9521
|
cached: false
|
|
8968
9522
|
}
|
|
8969
9523
|
};
|
|
8970
|
-
|
|
9524
|
+
if (options?.includeRankedFiles) {
|
|
9525
|
+
response.ranked_files = interpreted.files.map((f) => ({
|
|
9526
|
+
path: f.path,
|
|
9527
|
+
reason: f.reason,
|
|
9528
|
+
score: interpreted.scores.get(f.path) ?? 0
|
|
9529
|
+
}));
|
|
9530
|
+
response.query_kind = parsed.kind;
|
|
9531
|
+
}
|
|
9532
|
+
if (!options?.skipCache) {
|
|
9533
|
+
const key = cacheKey(repoId, goal, commit, useEmb);
|
|
9534
|
+
cacheSet(key, response);
|
|
9535
|
+
}
|
|
8971
9536
|
track(db, "context", {
|
|
8972
9537
|
duration_ms: response.stats.duration_ms,
|
|
8973
9538
|
result_count: response.stats.files_in_context,
|
|
@@ -9166,7 +9731,102 @@ function createTablesSql() {
|
|
|
9166
9731
|
CREATE INDEX IF NOT EXISTS idx_telemetry_events_synced ON telemetry_events(synced_at);
|
|
9167
9732
|
`;
|
|
9168
9733
|
}
|
|
9169
|
-
function
|
|
9734
|
+
function hitAtN(expected, returned, n) {
|
|
9735
|
+
const top = returned.slice(0, n);
|
|
9736
|
+
return expected.some((e) => top.includes(e));
|
|
9737
|
+
}
|
|
9738
|
+
function entryHitAtN(entry, returned, n) {
|
|
9739
|
+
if (!entry) return false;
|
|
9740
|
+
return returned.slice(0, n).includes(entry);
|
|
9741
|
+
}
|
|
9742
|
+
function recallAtK(expected, returned, k) {
|
|
9743
|
+
if (expected.length === 0) return 1;
|
|
9744
|
+
const top = new Set(returned.slice(0, k));
|
|
9745
|
+
const hits = expected.filter((e) => top.has(e)).length;
|
|
9746
|
+
return hits / expected.length;
|
|
9747
|
+
}
|
|
9748
|
+
function computeMetrics(results) {
|
|
9749
|
+
const total = results.length;
|
|
9750
|
+
if (total === 0) {
|
|
9751
|
+
return {
|
|
9752
|
+
total: 0,
|
|
9753
|
+
hit_at_1: 0,
|
|
9754
|
+
hit_at_3: 0,
|
|
9755
|
+
entry_hit_at_1: 0,
|
|
9756
|
+
entry_hit_at_3: 0,
|
|
9757
|
+
avg_recall_at_5: 0,
|
|
9758
|
+
avg_duration_ms: 0,
|
|
9759
|
+
by_kind: [],
|
|
9760
|
+
results
|
|
9761
|
+
};
|
|
9762
|
+
}
|
|
9763
|
+
const hit1 = results.filter((r) => r.hit_at_1).length;
|
|
9764
|
+
const hit3 = results.filter((r) => r.hit_at_3).length;
|
|
9765
|
+
const entryHit1 = results.filter((r) => r.entry_hit_at_1).length;
|
|
9766
|
+
const entryHit3 = results.filter((r) => r.entry_hit_at_3).length;
|
|
9767
|
+
const sumRecall = results.reduce((s, r) => s + r.recall_at_5, 0);
|
|
9768
|
+
const sumDuration = results.reduce((s, r) => s + r.duration_ms, 0);
|
|
9769
|
+
const kinds = [...new Set(results.map((r) => r.kind))];
|
|
9770
|
+
const by_kind = kinds.map((kind) => {
|
|
9771
|
+
const group = results.filter((r) => r.kind === kind);
|
|
9772
|
+
const n = group.length;
|
|
9773
|
+
return {
|
|
9774
|
+
kind,
|
|
9775
|
+
count: n,
|
|
9776
|
+
hit_at_1: group.filter((r) => r.hit_at_1).length / n,
|
|
9777
|
+
hit_at_3: group.filter((r) => r.hit_at_3).length / n,
|
|
9778
|
+
entry_hit_at_1: group.filter((r) => r.entry_hit_at_1).length / n,
|
|
9779
|
+
entry_hit_at_3: group.filter((r) => r.entry_hit_at_3).length / n,
|
|
9780
|
+
avg_recall_at_5: group.reduce((s, r) => s + r.recall_at_5, 0) / n,
|
|
9781
|
+
avg_duration_ms: Math.round(group.reduce((s, r) => s + r.duration_ms, 0) / n)
|
|
9782
|
+
};
|
|
9783
|
+
});
|
|
9784
|
+
return {
|
|
9785
|
+
total,
|
|
9786
|
+
hit_at_1: hit1 / total,
|
|
9787
|
+
hit_at_3: hit3 / total,
|
|
9788
|
+
entry_hit_at_1: entryHit1 / total,
|
|
9789
|
+
entry_hit_at_3: entryHit3 / total,
|
|
9790
|
+
avg_recall_at_5: sumRecall / total,
|
|
9791
|
+
avg_duration_ms: Math.round(sumDuration / total),
|
|
9792
|
+
by_kind,
|
|
9793
|
+
results
|
|
9794
|
+
};
|
|
9795
|
+
}
|
|
9796
|
+
async function runEval(db, repoId, options) {
|
|
9797
|
+
let queries = GOLD_DATASET;
|
|
9798
|
+
if (options?.filterKind) {
|
|
9799
|
+
queries = queries.filter((q) => q.kind === options.filterKind);
|
|
9800
|
+
}
|
|
9801
|
+
const results = [];
|
|
9802
|
+
for (const gold of queries) {
|
|
9803
|
+
const start = Date.now();
|
|
9804
|
+
const response = await buildContext(db, repoId, gold.query, void 0, void 0, {
|
|
9805
|
+
useEmbeddings: false,
|
|
9806
|
+
includeRankedFiles: true,
|
|
9807
|
+
skipCache: true
|
|
9808
|
+
});
|
|
9809
|
+
const duration3 = Date.now() - start;
|
|
9810
|
+
const returned = (response.ranked_files ?? []).map((f) => f.path);
|
|
9811
|
+
results.push({
|
|
9812
|
+
id: gold.id,
|
|
9813
|
+
query: gold.query,
|
|
9814
|
+
kind: gold.kind,
|
|
9815
|
+
expected_files: gold.expected_files,
|
|
9816
|
+
expected_entry: gold.expected_entry,
|
|
9817
|
+
returned_files: returned,
|
|
9818
|
+
hit_at_1: hitAtN(gold.expected_files, returned, 1),
|
|
9819
|
+
hit_at_3: hitAtN(gold.expected_files, returned, 3),
|
|
9820
|
+
entry_hit_at_1: entryHitAtN(gold.expected_entry, returned, 1),
|
|
9821
|
+
entry_hit_at_3: entryHitAtN(gold.expected_entry, returned, 3),
|
|
9822
|
+
recall_at_5: recallAtK(gold.expected_files, returned, 5),
|
|
9823
|
+
duration_ms: duration3,
|
|
9824
|
+
file_count: returned.length
|
|
9825
|
+
});
|
|
9826
|
+
}
|
|
9827
|
+
return computeMetrics(results);
|
|
9828
|
+
}
|
|
9829
|
+
function estimateTokens2(text22) {
|
|
9170
9830
|
return Math.ceil(text22.length / CHARS_PER_TOKEN);
|
|
9171
9831
|
}
|
|
9172
9832
|
async function ensureEmbedded(db, repoId, caps) {
|
|
@@ -9192,7 +9852,7 @@ async function ensureEmbedded(db, repoId, caps) {
|
|
|
9192
9852
|
const batch = [];
|
|
9193
9853
|
let batchTokens = 0;
|
|
9194
9854
|
while (offset < validRows.length) {
|
|
9195
|
-
const est =
|
|
9855
|
+
const est = estimateTokens2(validRows[offset].content);
|
|
9196
9856
|
if (batch.length > 0 && batchTokens + est > MAX_BATCH_TOKENS) break;
|
|
9197
9857
|
batch.push(validRows[offset]);
|
|
9198
9858
|
batchTokens += est;
|
|
@@ -9255,7 +9915,7 @@ async function enrichPurpose(db, repoId, caps, fullRun = false) {
|
|
|
9255
9915
|
return { enriched: totalEnriched, skipped: totalSkipped, duration_ms: Date.now() - start };
|
|
9256
9916
|
}
|
|
9257
9917
|
function splitIdentifier(name) {
|
|
9258
|
-
return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[_\-./\\]/g, " ").toLowerCase().split(/\s+/).filter((w) => w.length >= 3 && !
|
|
9918
|
+
return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[_\-./\\]/g, " ").toLowerCase().split(/\s+/).filter((w) => w.length >= 3 && !STOPWORDS3.has(w));
|
|
9259
9919
|
}
|
|
9260
9920
|
function extractVocab(files) {
|
|
9261
9921
|
const termToFiles = /* @__PURE__ */ new Map();
|
|
@@ -9596,7 +10256,7 @@ async function getRepoStatus(db, id) {
|
|
|
9596
10256
|
vocab_cluster_count: Array.isArray(vocabClusters) ? vocabClusters.length : 0
|
|
9597
10257
|
};
|
|
9598
10258
|
}
|
|
9599
|
-
var __defProp2, __getOwnPropNames2, __esm2, __export2, schema_exports, uuid, now, updatedAt, repos, chunks, fileMetadata, fileImports, fileStats, fileCochanges, usageCounters, requestLogs, settings, telemetryEvents, init_schema, queries_exports, repoQueries, chunkQueries, metadataQueries, importQueries, statsQueries, cochangeQueries, logQueries, usageQueries, telemetryQueries, settingsQueries, init_queries, _enabled, DEFAULT_CHUNKING_PARAMS, execFileAsync, MAX_FILE_SIZE, BINARY_EXTENSIONS, DOCS_EXTENSIONS, LANG_MAP, TS_IMPORT_RE, PY_IMPORT_RE, GO_IMPORT_RE, RUST_USE_RE, TS_EXTENSIONS, PY_EXTENSIONS, TS_EXPORT_RE, PY_EXPORT_RE, GO_EXPORT_RE, RUST_EXPORT_RE, CSHARP_EXPORT_RE, CSHARP_EXPORT_METHOD_RE, JAVA_EXPORT_RE, JSDOC_RE, PY_DOCSTRING_RE, CSHARP_DOC_RE, GO_PKG_RE, RUST_DOC_RE, SECTION_SINGLE_RE, SECTION_BLOCK_RE, UNIVERSAL_DECL_RES, EXPORT_LINE_RE, SKIP_NAMES, execFileAsync2, MAX_COMMITS, MAX_FILES_PER_COMMIT, RECENT_DAYS, MAX_CHUNKS_PER_REPO, locks, STOPWORDS, NOISE_EXTENSIONS, NOISE_PATHS, CONCEPT_SYNONYMS, CACHE_TTL, CACHE_MAX, cache, _db, _raw, MAX_API_CALLS, POOL_SIZE, MAX_BATCH_TOKENS, CHARS_PER_TOKEN, PURPOSE_BATCH_LIMIT, PURPOSE_CONCURRENCY, TERM_BATCH_SIZE, SIMILARITY_THRESHOLD, MAX_TERMS, MAX_CLUSTERS, MAX_CLUSTER_SIZE,
|
|
10259
|
+
var __defProp2, __getOwnPropNames2, __esm2, __export2, schema_exports, uuid, now, updatedAt, repos, chunks, fileMetadata, fileImports, fileStats, fileCochanges, usageCounters, requestLogs, settings, telemetryEvents, init_schema, queries_exports, repoQueries, chunkQueries, metadataQueries, importQueries, statsQueries, cochangeQueries, logQueries, usageQueries, telemetryQueries, settingsQueries, init_queries, slicer_exports, RADIUS, MAX_SLICES, init_slicer, _enabled, DEFAULT_CHUNKING_PARAMS, execFileAsync, MAX_FILE_SIZE, BINARY_EXTENSIONS, DOCS_EXTENSIONS, LANG_MAP, TS_IMPORT_RE, PY_IMPORT_RE, GO_IMPORT_RE, RUST_USE_RE, TS_EXTENSIONS, PY_EXTENSIONS, TS_EXPORT_RE, PY_EXPORT_RE, GO_EXPORT_RE, RUST_EXPORT_RE, CSHARP_EXPORT_RE, CSHARP_EXPORT_METHOD_RE, JAVA_EXPORT_RE, JSDOC_RE, PY_DOCSTRING_RE, CSHARP_DOC_RE, GO_PKG_RE, RUST_DOC_RE, SECTION_SINGLE_RE, SECTION_BLOCK_RE, UNIVERSAL_DECL_RES, EXPORT_LINE_RE, SKIP_NAMES, execFileAsync2, MAX_COMMITS, MAX_FILES_PER_COMMIT, RECENT_DAYS, MAX_CHUNKS_PER_REPO, locks, TOKEN_CAP, LANG_EXT, FRAME_PATTERNS, CASING_BOUNDARY, SYMBOL_RE, ERROR_CODE_RE, ERROR_SUFFIX_RE, ERROR_PREFIX_RE, STOPWORDS, STOPWORDS2, NOISE_EXTENSIONS, NOISE_PATHS, CONCEPT_SYNONYMS, SYMBOL_DEF_RE, TEST_PATTERN, CACHE_TTL, CACHE_MAX, cache, _db, _raw, GOLD_DATASET, MAX_API_CALLS, POOL_SIZE, MAX_BATCH_TOKENS, CHARS_PER_TOKEN, PURPOSE_BATCH_LIMIT, PURPOSE_CONCURRENCY, TERM_BATCH_SIZE, SIMILARITY_THRESHOLD, MAX_TERMS, MAX_CLUSTERS, MAX_CLUSTER_SIZE, STOPWORDS3, watchers, debounceTimers, IGNORED, DEBOUNCE_MS, RequestTrace;
|
|
9600
10260
|
var init_dist = __esm({
|
|
9601
10261
|
"packages/engine/dist/index.js"() {
|
|
9602
10262
|
"use strict";
|
|
@@ -9982,6 +10642,21 @@ var init_dist = __esm({
|
|
|
9982
10642
|
const row = db.select({ id: chunks.id }).from(chunks).where(and(eq(chunks.repo_id, repoId), sql`embedding IS NOT NULL`)).limit(1).get();
|
|
9983
10643
|
return !!row;
|
|
9984
10644
|
},
|
|
10645
|
+
getByRepoPaths(db, repoId, paths) {
|
|
10646
|
+
if (!paths.length) return [];
|
|
10647
|
+
return db.select({
|
|
10648
|
+
path: chunks.path,
|
|
10649
|
+
chunk_index: chunks.chunk_index,
|
|
10650
|
+
start_line: chunks.start_line,
|
|
10651
|
+
end_line: chunks.end_line,
|
|
10652
|
+
content: chunks.content
|
|
10653
|
+
}).from(chunks).where(and(eq(chunks.repo_id, repoId), inArray(chunks.path, paths))).orderBy(chunks.path, chunks.chunk_index).all();
|
|
10654
|
+
},
|
|
10655
|
+
searchContent(db, repoId, searchString) {
|
|
10656
|
+
if (!searchString || searchString.length < 4) return [];
|
|
10657
|
+
const rows = db.select({ path: chunks.path }).from(chunks).where(and(eq(chunks.repo_id, repoId), sql`INSTR(LOWER(${chunks.content}), ${searchString.toLowerCase()}) > 0`)).groupBy(chunks.path).all();
|
|
10658
|
+
return rows.map((r) => r.path);
|
|
10659
|
+
},
|
|
9985
10660
|
getStats(db, repoId) {
|
|
9986
10661
|
const row = db.select({
|
|
9987
10662
|
chunk_count: sql`count(*)`,
|
|
@@ -10328,6 +11003,23 @@ var init_dist = __esm({
|
|
|
10328
11003
|
};
|
|
10329
11004
|
}
|
|
10330
11005
|
});
|
|
11006
|
+
slicer_exports = {};
|
|
11007
|
+
__export2(slicer_exports, {
|
|
11008
|
+
sliceContext: () => sliceContext
|
|
11009
|
+
});
|
|
11010
|
+
init_slicer = __esm2({
|
|
11011
|
+
"src/context/slicer.ts"() {
|
|
11012
|
+
"use strict";
|
|
11013
|
+
init_queries();
|
|
11014
|
+
RADIUS = 10;
|
|
11015
|
+
MAX_SLICES = {
|
|
11016
|
+
symbol: 1,
|
|
11017
|
+
error_message: 1,
|
|
11018
|
+
stack_trace: 2,
|
|
11019
|
+
natural: 3
|
|
11020
|
+
};
|
|
11021
|
+
}
|
|
11022
|
+
});
|
|
10331
11023
|
init_queries();
|
|
10332
11024
|
init_queries();
|
|
10333
11025
|
init_queries();
|
|
@@ -10476,6 +11168,40 @@ var init_dist = __esm({
|
|
|
10476
11168
|
init_queries();
|
|
10477
11169
|
MAX_CHUNKS_PER_REPO = 1e5;
|
|
10478
11170
|
locks = /* @__PURE__ */ new Map();
|
|
11171
|
+
TOKEN_CAP = 2e3;
|
|
11172
|
+
LANG_EXT = {
|
|
11173
|
+
ts: "typescript",
|
|
11174
|
+
tsx: "typescript",
|
|
11175
|
+
js: "javascript",
|
|
11176
|
+
jsx: "javascript",
|
|
11177
|
+
py: "python",
|
|
11178
|
+
rb: "ruby",
|
|
11179
|
+
go: "go",
|
|
11180
|
+
rs: "rust",
|
|
11181
|
+
java: "java",
|
|
11182
|
+
kt: "kotlin",
|
|
11183
|
+
cs: "csharp",
|
|
11184
|
+
cpp: "cpp",
|
|
11185
|
+
c: "c",
|
|
11186
|
+
h: "c",
|
|
11187
|
+
swift: "swift",
|
|
11188
|
+
php: "php",
|
|
11189
|
+
sql: "sql",
|
|
11190
|
+
sh: "shell"
|
|
11191
|
+
};
|
|
11192
|
+
FRAME_PATTERNS = [
|
|
11193
|
+
// JS/TS: at fn (path:line:col) or at path:line:col
|
|
11194
|
+
/at\s+(?:\S+\s+\()?([^():]+):(\d+):\d+\)?/g,
|
|
11195
|
+
// Python: File "path", line N
|
|
11196
|
+
/File\s+"([^"]+)",\s+line\s+(\d+)/g,
|
|
11197
|
+
// C#/Java: at namespace(path:line)
|
|
11198
|
+
/at\s+\S+\(([^():]+):(\d+)\)/g
|
|
11199
|
+
];
|
|
11200
|
+
CASING_BOUNDARY = /[a-z][A-Z]|_/;
|
|
11201
|
+
SYMBOL_RE = /^[a-zA-Z_]\w+$/;
|
|
11202
|
+
ERROR_CODE_RE = /\b[A-Z][A-Z0-9_]{2,}\b/;
|
|
11203
|
+
ERROR_SUFFIX_RE = /\w+(Exception|Error)\b/;
|
|
11204
|
+
ERROR_PREFIX_RE = /\b(TypeError|ReferenceError|SyntaxError|RangeError|Error|panic|FATAL|WARN|ERR):/;
|
|
10479
11205
|
STOPWORDS = /* @__PURE__ */ new Set([
|
|
10480
11206
|
"the",
|
|
10481
11207
|
"a",
|
|
@@ -10577,6 +11303,139 @@ var init_dist = __esm({
|
|
|
10577
11303
|
"mock",
|
|
10578
11304
|
"module"
|
|
10579
11305
|
]);
|
|
11306
|
+
STOPWORDS2 = /* @__PURE__ */ new Set([
|
|
11307
|
+
"the",
|
|
11308
|
+
"a",
|
|
11309
|
+
"an",
|
|
11310
|
+
"is",
|
|
11311
|
+
"are",
|
|
11312
|
+
"was",
|
|
11313
|
+
"were",
|
|
11314
|
+
"be",
|
|
11315
|
+
"been",
|
|
11316
|
+
"being",
|
|
11317
|
+
"have",
|
|
11318
|
+
"has",
|
|
11319
|
+
"had",
|
|
11320
|
+
"do",
|
|
11321
|
+
"does",
|
|
11322
|
+
"did",
|
|
11323
|
+
"will",
|
|
11324
|
+
"would",
|
|
11325
|
+
"could",
|
|
11326
|
+
"should",
|
|
11327
|
+
"may",
|
|
11328
|
+
"might",
|
|
11329
|
+
"can",
|
|
11330
|
+
"need",
|
|
11331
|
+
"must",
|
|
11332
|
+
"to",
|
|
11333
|
+
"of",
|
|
11334
|
+
"in",
|
|
11335
|
+
"for",
|
|
11336
|
+
"on",
|
|
11337
|
+
"with",
|
|
11338
|
+
"at",
|
|
11339
|
+
"by",
|
|
11340
|
+
"from",
|
|
11341
|
+
"as",
|
|
11342
|
+
"into",
|
|
11343
|
+
"through",
|
|
11344
|
+
"and",
|
|
11345
|
+
"but",
|
|
11346
|
+
"or",
|
|
11347
|
+
"not",
|
|
11348
|
+
"no",
|
|
11349
|
+
"so",
|
|
11350
|
+
"if",
|
|
11351
|
+
"then",
|
|
11352
|
+
"than",
|
|
11353
|
+
"that",
|
|
11354
|
+
"this",
|
|
11355
|
+
"it",
|
|
11356
|
+
"its",
|
|
11357
|
+
"all",
|
|
11358
|
+
"each",
|
|
11359
|
+
"every",
|
|
11360
|
+
"any",
|
|
11361
|
+
"some",
|
|
11362
|
+
"how",
|
|
11363
|
+
"what",
|
|
11364
|
+
"which",
|
|
11365
|
+
"who",
|
|
11366
|
+
"when",
|
|
11367
|
+
"where",
|
|
11368
|
+
"why",
|
|
11369
|
+
"get",
|
|
11370
|
+
"set",
|
|
11371
|
+
"new",
|
|
11372
|
+
"null",
|
|
11373
|
+
"true",
|
|
11374
|
+
"false",
|
|
11375
|
+
"void",
|
|
11376
|
+
"type",
|
|
11377
|
+
"var",
|
|
11378
|
+
"let",
|
|
11379
|
+
"const",
|
|
11380
|
+
"return",
|
|
11381
|
+
"import",
|
|
11382
|
+
"export",
|
|
11383
|
+
"default",
|
|
11384
|
+
"class",
|
|
11385
|
+
"function",
|
|
11386
|
+
"string",
|
|
11387
|
+
"number",
|
|
11388
|
+
"boolean",
|
|
11389
|
+
"object",
|
|
11390
|
+
"array",
|
|
11391
|
+
"index",
|
|
11392
|
+
"data",
|
|
11393
|
+
"value",
|
|
11394
|
+
"result",
|
|
11395
|
+
"item",
|
|
11396
|
+
"list",
|
|
11397
|
+
"name",
|
|
11398
|
+
"id",
|
|
11399
|
+
"key",
|
|
11400
|
+
"src",
|
|
11401
|
+
"lib",
|
|
11402
|
+
"app",
|
|
11403
|
+
"spec",
|
|
11404
|
+
"mock",
|
|
11405
|
+
"module",
|
|
11406
|
+
"work",
|
|
11407
|
+
"works",
|
|
11408
|
+
"working",
|
|
11409
|
+
"make",
|
|
11410
|
+
"makes",
|
|
11411
|
+
"use",
|
|
11412
|
+
"uses",
|
|
11413
|
+
"used",
|
|
11414
|
+
"using",
|
|
11415
|
+
"find",
|
|
11416
|
+
"run",
|
|
11417
|
+
"runs",
|
|
11418
|
+
"call",
|
|
11419
|
+
"calls",
|
|
11420
|
+
"look",
|
|
11421
|
+
"like",
|
|
11422
|
+
"just",
|
|
11423
|
+
"also",
|
|
11424
|
+
"about",
|
|
11425
|
+
"there",
|
|
11426
|
+
"here",
|
|
11427
|
+
"define",
|
|
11428
|
+
"defined",
|
|
11429
|
+
"handle",
|
|
11430
|
+
"handles",
|
|
11431
|
+
"add",
|
|
11432
|
+
"adds",
|
|
11433
|
+
"create",
|
|
11434
|
+
"serve",
|
|
11435
|
+
"does",
|
|
11436
|
+
"file",
|
|
11437
|
+
"files"
|
|
11438
|
+
]);
|
|
10580
11439
|
NOISE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
10581
11440
|
".md",
|
|
10582
11441
|
".json",
|
|
@@ -10611,6 +11470,7 @@ var init_dist = __esm({
|
|
|
10611
11470
|
"node_modules/",
|
|
10612
11471
|
"dist/",
|
|
10613
11472
|
"build/",
|
|
11473
|
+
"publish/",
|
|
10614
11474
|
"vendor/",
|
|
10615
11475
|
"vendors/",
|
|
10616
11476
|
"/scripts/",
|
|
@@ -10649,6 +11509,9 @@ var init_dist = __esm({
|
|
|
10649
11509
|
api: ["controller", "endpoint", "route", "middleware", "interceptor"]
|
|
10650
11510
|
};
|
|
10651
11511
|
init_queries();
|
|
11512
|
+
SYMBOL_DEF_RE = /^.*?\b(?:function|def|fn|class|const|let|var|type|interface|struct|enum|export\s+(?:function|class|const|type|interface|default))\s+/;
|
|
11513
|
+
init_queries();
|
|
11514
|
+
TEST_PATTERN = /\.(?:test|spec)\.|__tests__\/|_test\./;
|
|
10652
11515
|
init_queries();
|
|
10653
11516
|
CACHE_TTL = 12e4;
|
|
10654
11517
|
CACHE_MAX = 20;
|
|
@@ -10657,6 +11520,159 @@ var init_dist = __esm({
|
|
|
10657
11520
|
_db = null;
|
|
10658
11521
|
_raw = null;
|
|
10659
11522
|
init_queries();
|
|
11523
|
+
GOLD_DATASET = [
|
|
11524
|
+
// --- natural (12) ---
|
|
11525
|
+
{
|
|
11526
|
+
id: "nat-01",
|
|
11527
|
+
query: "How does the context pack pipeline work?",
|
|
11528
|
+
kind: "natural",
|
|
11529
|
+
expected_files: [
|
|
11530
|
+
"packages/engine/src/context/context.ts",
|
|
11531
|
+
"packages/engine/src/context/formatter.ts",
|
|
11532
|
+
"packages/engine/src/context/query-interpreter.ts"
|
|
11533
|
+
],
|
|
11534
|
+
expected_entry: "packages/engine/src/context/context.ts"
|
|
11535
|
+
},
|
|
11536
|
+
{
|
|
11537
|
+
id: "nat-02",
|
|
11538
|
+
query: "How does file indexing work?",
|
|
11539
|
+
kind: "natural",
|
|
11540
|
+
expected_files: [
|
|
11541
|
+
"packages/engine/src/index/engine.ts",
|
|
11542
|
+
"packages/engine/src/index/chunker.ts",
|
|
11543
|
+
"packages/engine/src/index/discovery.ts"
|
|
11544
|
+
],
|
|
11545
|
+
expected_entry: "packages/engine/src/index/engine.ts"
|
|
11546
|
+
},
|
|
11547
|
+
{
|
|
11548
|
+
id: "nat-03",
|
|
11549
|
+
query: "How are imports resolved and the import graph built?",
|
|
11550
|
+
kind: "natural",
|
|
11551
|
+
expected_files: ["packages/engine/src/index/import-graph.ts", "packages/engine/src/index/imports.ts"],
|
|
11552
|
+
expected_entry: "packages/engine/src/index/import-graph.ts"
|
|
11553
|
+
},
|
|
11554
|
+
{
|
|
11555
|
+
id: "nat-04",
|
|
11556
|
+
query: "How does the daemon HTTP server handle requests?",
|
|
11557
|
+
kind: "natural",
|
|
11558
|
+
expected_files: ["apps/daemon/src/server.ts", "apps/daemon/src/index.ts"],
|
|
11559
|
+
expected_entry: "apps/daemon/src/server.ts"
|
|
11560
|
+
},
|
|
11561
|
+
{
|
|
11562
|
+
id: "nat-05",
|
|
11563
|
+
query: "How does the CLI register a repo?",
|
|
11564
|
+
kind: "natural",
|
|
11565
|
+
expected_files: ["packages/cli/src/commands/register.ts", "packages/engine/src/repo/repo.ts"],
|
|
11566
|
+
expected_entry: "packages/cli/src/commands/register.ts"
|
|
11567
|
+
},
|
|
11568
|
+
{
|
|
11569
|
+
id: "nat-06",
|
|
11570
|
+
query: "How does git history analysis and co-change detection work?",
|
|
11571
|
+
kind: "natural",
|
|
11572
|
+
expected_files: ["packages/engine/src/index/git-analysis.ts"],
|
|
11573
|
+
expected_entry: "packages/engine/src/index/git-analysis.ts"
|
|
11574
|
+
},
|
|
11575
|
+
{
|
|
11576
|
+
id: "nat-07",
|
|
11577
|
+
query: "How does the MCP stdio server work?",
|
|
11578
|
+
kind: "natural",
|
|
11579
|
+
expected_files: ["apps/daemon/src/mcp.ts"],
|
|
11580
|
+
expected_entry: "apps/daemon/src/mcp.ts"
|
|
11581
|
+
},
|
|
11582
|
+
{
|
|
11583
|
+
id: "nat-08",
|
|
11584
|
+
query: "How does TF-IDF scoring work in the query interpreter?",
|
|
11585
|
+
kind: "natural",
|
|
11586
|
+
expected_files: ["packages/engine/src/context/query-interpreter.ts"],
|
|
11587
|
+
expected_entry: "packages/engine/src/context/query-interpreter.ts"
|
|
11588
|
+
},
|
|
11589
|
+
{
|
|
11590
|
+
id: "nat-09",
|
|
11591
|
+
query: "How are file metadata (exports, docstrings, sections) extracted?",
|
|
11592
|
+
kind: "natural",
|
|
11593
|
+
expected_files: ["packages/engine/src/index/extract-metadata.ts"],
|
|
11594
|
+
expected_entry: "packages/engine/src/index/extract-metadata.ts"
|
|
11595
|
+
},
|
|
11596
|
+
{
|
|
11597
|
+
id: "nat-10",
|
|
11598
|
+
query: "How does vector/semantic search work?",
|
|
11599
|
+
kind: "natural",
|
|
11600
|
+
expected_files: ["packages/engine/src/context/vector.ts", "packages/engine/src/index/embed.ts"],
|
|
11601
|
+
expected_entry: "packages/engine/src/context/vector.ts"
|
|
11602
|
+
},
|
|
11603
|
+
{
|
|
11604
|
+
id: "nat-11",
|
|
11605
|
+
query: "How does the file watcher detect changes?",
|
|
11606
|
+
kind: "natural",
|
|
11607
|
+
expected_files: ["packages/engine/src/index/watcher.ts"],
|
|
11608
|
+
expected_entry: "packages/engine/src/index/watcher.ts"
|
|
11609
|
+
},
|
|
11610
|
+
{
|
|
11611
|
+
id: "nat-12",
|
|
11612
|
+
query: "How is the database schema defined?",
|
|
11613
|
+
kind: "natural",
|
|
11614
|
+
expected_files: ["packages/engine/src/db/schema.ts", "packages/engine/src/db/connection.ts"],
|
|
11615
|
+
expected_entry: "packages/engine/src/db/schema.ts"
|
|
11616
|
+
},
|
|
11617
|
+
// --- symbol (5) ---
|
|
11618
|
+
{
|
|
11619
|
+
id: "sym-01",
|
|
11620
|
+
query: "buildContext",
|
|
11621
|
+
kind: "symbol",
|
|
11622
|
+
expected_files: ["packages/engine/src/context/context.ts"],
|
|
11623
|
+
expected_entry: "packages/engine/src/context/context.ts"
|
|
11624
|
+
},
|
|
11625
|
+
{
|
|
11626
|
+
id: "sym-02",
|
|
11627
|
+
query: "interpretQuery",
|
|
11628
|
+
kind: "symbol",
|
|
11629
|
+
expected_files: ["packages/engine/src/context/query-interpreter.ts"],
|
|
11630
|
+
expected_entry: "packages/engine/src/context/query-interpreter.ts"
|
|
11631
|
+
},
|
|
11632
|
+
{
|
|
11633
|
+
id: "sym-03",
|
|
11634
|
+
query: "runIndex",
|
|
11635
|
+
kind: "symbol",
|
|
11636
|
+
expected_files: ["packages/engine/src/index/engine.ts"],
|
|
11637
|
+
expected_entry: "packages/engine/src/index/engine.ts"
|
|
11638
|
+
},
|
|
11639
|
+
{
|
|
11640
|
+
id: "sym-04",
|
|
11641
|
+
query: "extractFileMetadata",
|
|
11642
|
+
kind: "symbol",
|
|
11643
|
+
expected_files: ["packages/engine/src/index/extract-metadata.ts"],
|
|
11644
|
+
expected_entry: "packages/engine/src/index/extract-metadata.ts"
|
|
11645
|
+
},
|
|
11646
|
+
{
|
|
11647
|
+
id: "sym-05",
|
|
11648
|
+
query: "formatContextPack",
|
|
11649
|
+
kind: "symbol",
|
|
11650
|
+
expected_files: ["packages/engine/src/context/formatter.ts"],
|
|
11651
|
+
expected_entry: "packages/engine/src/context/formatter.ts"
|
|
11652
|
+
},
|
|
11653
|
+
// --- error_message (3) ---
|
|
11654
|
+
{
|
|
11655
|
+
id: "err-01",
|
|
11656
|
+
query: "Error: repo not found",
|
|
11657
|
+
kind: "error_message",
|
|
11658
|
+
expected_files: ["packages/engine/src/repo/repo.ts", "apps/daemon/src/server.ts"],
|
|
11659
|
+
expected_entry: "packages/engine/src/repo/repo.ts"
|
|
11660
|
+
},
|
|
11661
|
+
{
|
|
11662
|
+
id: "err-02",
|
|
11663
|
+
query: "LENS daemon is not running",
|
|
11664
|
+
kind: "error_message",
|
|
11665
|
+
expected_files: ["packages/cli/src/util/client.ts"],
|
|
11666
|
+
expected_entry: "packages/cli/src/util/client.ts"
|
|
11667
|
+
},
|
|
11668
|
+
{
|
|
11669
|
+
id: "err-03",
|
|
11670
|
+
query: "Context generation failed",
|
|
11671
|
+
kind: "error_message",
|
|
11672
|
+
expected_files: ["packages/engine/src/context/context.ts"],
|
|
11673
|
+
expected_entry: "packages/engine/src/context/context.ts"
|
|
11674
|
+
}
|
|
11675
|
+
];
|
|
10660
11676
|
init_queries();
|
|
10661
11677
|
MAX_API_CALLS = 2e3;
|
|
10662
11678
|
POOL_SIZE = 32;
|
|
@@ -10671,7 +11687,7 @@ var init_dist = __esm({
|
|
|
10671
11687
|
MAX_TERMS = 1500;
|
|
10672
11688
|
MAX_CLUSTERS = 200;
|
|
10673
11689
|
MAX_CLUSTER_SIZE = 12;
|
|
10674
|
-
|
|
11690
|
+
STOPWORDS3 = /* @__PURE__ */ new Set([
|
|
10675
11691
|
"the",
|
|
10676
11692
|
"a",
|
|
10677
11693
|
"an",
|
|
@@ -10888,31 +11904,45 @@ var cloud_capabilities_exports = {};
|
|
|
10888
11904
|
__export(cloud_capabilities_exports, {
|
|
10889
11905
|
createCloudCapabilities: () => createCloudCapabilities
|
|
10890
11906
|
});
|
|
10891
|
-
function createCloudCapabilities(
|
|
11907
|
+
function createCloudCapabilities(getKey, refreshKey, trackUsage, logRequest) {
|
|
10892
11908
|
const CLOUD_API_URL = getCloudUrl();
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
"
|
|
10896
|
-
|
|
11909
|
+
async function cloudFetch(path, reqBody) {
|
|
11910
|
+
const apiKey = await getKey();
|
|
11911
|
+
if (!apiKey) throw new Error("No API key available");
|
|
11912
|
+
const start = performance.now();
|
|
11913
|
+
let res = await fetch(`${CLOUD_API_URL}${path}`, {
|
|
11914
|
+
method: "POST",
|
|
11915
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
11916
|
+
body: reqBody
|
|
11917
|
+
});
|
|
11918
|
+
let resText = await res.text();
|
|
11919
|
+
let duration3 = Math.round(performance.now() - start);
|
|
11920
|
+
logRequest?.("POST", path, res.status, duration3, "cloud", reqBody, resText);
|
|
11921
|
+
if (res.status === 401) {
|
|
11922
|
+
const newKey = await refreshKey();
|
|
11923
|
+
if (newKey) {
|
|
11924
|
+
const retryStart = performance.now();
|
|
11925
|
+
res = await fetch(`${CLOUD_API_URL}${path}`, {
|
|
11926
|
+
method: "POST",
|
|
11927
|
+
headers: { Authorization: `Bearer ${newKey}`, "Content-Type": "application/json" },
|
|
11928
|
+
body: reqBody
|
|
11929
|
+
});
|
|
11930
|
+
resText = await res.text();
|
|
11931
|
+
duration3 = Math.round(performance.now() - retryStart);
|
|
11932
|
+
logRequest?.("POST", path, res.status, duration3, "cloud-retry", reqBody, resText);
|
|
11933
|
+
}
|
|
11934
|
+
}
|
|
11935
|
+
return { res, resText };
|
|
11936
|
+
}
|
|
10897
11937
|
return {
|
|
10898
11938
|
async embedTexts(texts, isQuery) {
|
|
10899
|
-
const start = performance.now();
|
|
10900
11939
|
const reqBody = JSON.stringify({
|
|
10901
11940
|
input: texts,
|
|
10902
11941
|
model: "voyage-code-3",
|
|
10903
11942
|
input_type: isQuery ? "query" : "document"
|
|
10904
11943
|
});
|
|
10905
|
-
const res = await
|
|
10906
|
-
|
|
10907
|
-
headers,
|
|
10908
|
-
body: reqBody
|
|
10909
|
-
});
|
|
10910
|
-
const resText = await res.text();
|
|
10911
|
-
const duration3 = Math.round(performance.now() - start);
|
|
10912
|
-
logRequest?.("POST", "/api/proxy/embed", res.status, duration3, "cloud", reqBody, resText);
|
|
10913
|
-
if (!res.ok) {
|
|
10914
|
-
throw new Error(`Cloud embed failed (${res.status}): ${resText}`);
|
|
10915
|
-
}
|
|
11944
|
+
const { res, resText } = await cloudFetch("/api/proxy/embed", reqBody);
|
|
11945
|
+
if (!res.ok) throw new Error(`Cloud embed failed (${res.status}): ${resText}`);
|
|
10916
11946
|
const data = JSON.parse(resText);
|
|
10917
11947
|
trackUsage?.("embedding_requests");
|
|
10918
11948
|
trackUsage?.("embedding_chunks", texts.length);
|
|
@@ -10926,7 +11956,6 @@ function createCloudCapabilities(apiKey, trackUsage, logRequest) {
|
|
|
10926
11956
|
"",
|
|
10927
11957
|
content.slice(0, 2e3)
|
|
10928
11958
|
].filter(Boolean).join("\n");
|
|
10929
|
-
const start = performance.now();
|
|
10930
11959
|
const reqBody = JSON.stringify({
|
|
10931
11960
|
messages: [
|
|
10932
11961
|
{
|
|
@@ -10937,17 +11966,8 @@ function createCloudCapabilities(apiKey, trackUsage, logRequest) {
|
|
|
10937
11966
|
],
|
|
10938
11967
|
max_tokens: 128
|
|
10939
11968
|
});
|
|
10940
|
-
const res = await
|
|
10941
|
-
|
|
10942
|
-
headers,
|
|
10943
|
-
body: reqBody
|
|
10944
|
-
});
|
|
10945
|
-
const resText = await res.text();
|
|
10946
|
-
const duration3 = Math.round(performance.now() - start);
|
|
10947
|
-
logRequest?.("POST", "/api/proxy/chat", res.status, duration3, "cloud", reqBody, resText);
|
|
10948
|
-
if (!res.ok) {
|
|
10949
|
-
throw new Error(`Cloud purpose failed (${res.status}): ${resText}`);
|
|
10950
|
-
}
|
|
11969
|
+
const { res, resText } = await cloudFetch("/api/proxy/chat", reqBody);
|
|
11970
|
+
if (!res.ok) throw new Error(`Cloud purpose failed (${res.status}): ${resText}`);
|
|
10951
11971
|
const data = JSON.parse(resText);
|
|
10952
11972
|
trackUsage?.("purpose_requests");
|
|
10953
11973
|
return data.choices?.[0]?.message?.content?.trim() ?? "";
|
|
@@ -15670,7 +16690,7 @@ function flattenError(error3, mapper = (issue2) => issue2.message) {
|
|
|
15670
16690
|
}
|
|
15671
16691
|
return { formErrors, fieldErrors };
|
|
15672
16692
|
}
|
|
15673
|
-
function
|
|
16693
|
+
function formatError2(error3, _mapper) {
|
|
15674
16694
|
const mapper = _mapper || function(issue2) {
|
|
15675
16695
|
return issue2.message;
|
|
15676
16696
|
};
|
|
@@ -19316,7 +20336,7 @@ var init_errors4 = __esm({
|
|
|
19316
20336
|
inst.name = "ZodError";
|
|
19317
20337
|
Object.defineProperties(inst, {
|
|
19318
20338
|
format: {
|
|
19319
|
-
value: (mapper) =>
|
|
20339
|
+
value: (mapper) => formatError2(inst, mapper)
|
|
19320
20340
|
// enumerable: false,
|
|
19321
20341
|
},
|
|
19322
20342
|
flatten: {
|
|
@@ -32426,7 +33446,7 @@ function createMcpServer(db, caps) {
|
|
|
32426
33446
|
server.registerTool(
|
|
32427
33447
|
"get_context",
|
|
32428
33448
|
{
|
|
32429
|
-
description: "
|
|
33449
|
+
description: "Returns ranked files with import dependency chains and git co-change clusters for a development goal. Surfaces structural relationships (imports, co-changes, exports) that keyword search alone won't find. Use when exploring architecture, tracing data flow, assessing change impact, or navigating an unfamiliar codebase. Skip for simple lookups where you already know the file path.",
|
|
32430
33450
|
inputSchema: { repo_path: external_exports.string(), goal: external_exports.string() }
|
|
32431
33451
|
},
|
|
32432
33452
|
async ({ repo_path, goal }) => {
|
|
@@ -34986,21 +36006,6 @@ function createApp(db, dashboardDist, initialCaps, initialPlanData) {
|
|
|
34986
36006
|
const trace = c.get("trace");
|
|
34987
36007
|
const { root_path, name, remote_url } = await c.req.json();
|
|
34988
36008
|
if (!root_path) return c.json({ error: "root_path required" }, 400);
|
|
34989
|
-
trace.step("quotaCheck");
|
|
34990
|
-
const currentRepos = listRepos(db).length;
|
|
34991
|
-
const maxRepos = quotaCache?.quota?.maxRepos ?? 50;
|
|
34992
|
-
trace.end("quotaCheck", `${currentRepos}/${maxRepos}`);
|
|
34993
|
-
if (currentRepos >= maxRepos) {
|
|
34994
|
-
return c.json(
|
|
34995
|
-
{
|
|
34996
|
-
error: "Repo limit reached",
|
|
34997
|
-
current: currentRepos,
|
|
34998
|
-
limit: maxRepos,
|
|
34999
|
-
plan: quotaCache?.plan ?? "unknown"
|
|
35000
|
-
},
|
|
35001
|
-
429
|
|
35002
|
-
);
|
|
35003
|
-
}
|
|
35004
36009
|
trace.step("registerRepo");
|
|
35005
36010
|
const result = registerRepo(db, root_path, name, remote_url);
|
|
35006
36011
|
trace.end("registerRepo", result.created ? "created" : "existing");
|
|
@@ -35190,6 +36195,20 @@ function createApp(db, dashboardDist, initialCaps, initialPlanData) {
|
|
|
35190
36195
|
return c.json({ error: e.message }, 500);
|
|
35191
36196
|
}
|
|
35192
36197
|
});
|
|
36198
|
+
trackRoute("POST", "/eval/run");
|
|
36199
|
+
app.post("/eval/run", async (c) => {
|
|
36200
|
+
try {
|
|
36201
|
+
const trace = c.get("trace");
|
|
36202
|
+
const { repo_id, filter_kind } = await c.req.json();
|
|
36203
|
+
if (!repo_id) return c.json({ error: "repo_id required" }, 400);
|
|
36204
|
+
trace.step("runEval");
|
|
36205
|
+
const summary = await runEval(db, repo_id, { filterKind: filter_kind });
|
|
36206
|
+
trace.end("runEval", `${summary.total} queries`);
|
|
36207
|
+
return c.json(summary);
|
|
36208
|
+
} catch (e) {
|
|
36209
|
+
return c.json({ error: e.message }, 500);
|
|
36210
|
+
}
|
|
36211
|
+
});
|
|
35193
36212
|
trackRoute("POST", "/index/run");
|
|
35194
36213
|
app.post("/index/run", async (c) => {
|
|
35195
36214
|
try {
|
|
@@ -35396,24 +36415,34 @@ function createApp(db, dashboardDist, initialCaps, initialPlanData) {
|
|
|
35396
36415
|
expires_at: Math.floor(Date.now() / 1e3) + (data.expires_in ?? 3600)
|
|
35397
36416
|
};
|
|
35398
36417
|
}
|
|
35399
|
-
const
|
|
36418
|
+
const sseClients = /* @__PURE__ */ new Set();
|
|
35400
36419
|
const encoder = new TextEncoder();
|
|
35401
|
-
function
|
|
35402
|
-
|
|
36420
|
+
function emitSSE(type) {
|
|
36421
|
+
const payload = encoder.encode(`data: ${JSON.stringify({ type })}
|
|
36422
|
+
|
|
36423
|
+
`);
|
|
36424
|
+
for (const ctrl of sseClients) {
|
|
35403
36425
|
try {
|
|
35404
|
-
ctrl.enqueue(
|
|
36426
|
+
ctrl.enqueue(payload);
|
|
35405
36427
|
} catch {
|
|
35406
|
-
|
|
36428
|
+
sseClients.delete(ctrl);
|
|
35407
36429
|
}
|
|
35408
36430
|
}
|
|
35409
36431
|
}
|
|
35410
|
-
|
|
35411
|
-
|
|
36432
|
+
function emitRepoEvent() {
|
|
36433
|
+
emitSSE("repo");
|
|
36434
|
+
}
|
|
36435
|
+
function emitAuthEvent() {
|
|
36436
|
+
emitSSE("auth");
|
|
36437
|
+
}
|
|
36438
|
+
trackRoute("GET", "/api/events");
|
|
36439
|
+
app.get("/api/events", (_c) => {
|
|
35412
36440
|
const stream = new ReadableStream({
|
|
35413
36441
|
start(ctrl) {
|
|
35414
|
-
|
|
36442
|
+
sseClients.add(ctrl);
|
|
35415
36443
|
},
|
|
35416
|
-
cancel() {
|
|
36444
|
+
cancel(ctrl) {
|
|
36445
|
+
sseClients.delete(ctrl);
|
|
35417
36446
|
}
|
|
35418
36447
|
});
|
|
35419
36448
|
return new Response(stream, {
|
|
@@ -35424,17 +36453,7 @@ function createApp(db, dashboardDist, initialCaps, initialPlanData) {
|
|
|
35424
36453
|
}
|
|
35425
36454
|
});
|
|
35426
36455
|
});
|
|
35427
|
-
const authClients = /* @__PURE__ */ new Set();
|
|
35428
36456
|
const authDir = join5(homedir3(), ".lens");
|
|
35429
|
-
function emitAuthEvent() {
|
|
35430
|
-
for (const ctrl of authClients) {
|
|
35431
|
-
try {
|
|
35432
|
-
ctrl.enqueue(encoder.encode("data: auth-changed\n\n"));
|
|
35433
|
-
} catch {
|
|
35434
|
-
authClients.delete(ctrl);
|
|
35435
|
-
}
|
|
35436
|
-
}
|
|
35437
|
-
}
|
|
35438
36457
|
try {
|
|
35439
36458
|
watch2(authDir, (_, filename) => {
|
|
35440
36459
|
if (filename && filename !== "auth.json") return;
|
|
@@ -35442,23 +36461,6 @@ function createApp(db, dashboardDist, initialCaps, initialPlanData) {
|
|
|
35442
36461
|
});
|
|
35443
36462
|
} catch {
|
|
35444
36463
|
}
|
|
35445
|
-
trackRoute("GET", "/api/auth/events");
|
|
35446
|
-
app.get("/api/auth/events", (_c) => {
|
|
35447
|
-
const stream = new ReadableStream({
|
|
35448
|
-
start(ctrl) {
|
|
35449
|
-
authClients.add(ctrl);
|
|
35450
|
-
},
|
|
35451
|
-
cancel() {
|
|
35452
|
-
}
|
|
35453
|
-
});
|
|
35454
|
-
return new Response(stream, {
|
|
35455
|
-
headers: {
|
|
35456
|
-
"Content-Type": "text/event-stream",
|
|
35457
|
-
"Cache-Control": "no-cache",
|
|
35458
|
-
Connection: "keep-alive"
|
|
35459
|
-
}
|
|
35460
|
-
});
|
|
35461
|
-
});
|
|
35462
36464
|
trackRoute("POST", "/api/auth/notify");
|
|
35463
36465
|
app.post("/api/auth/notify", async (c) => {
|
|
35464
36466
|
await refreshQuotaCache();
|
|
@@ -35995,7 +36997,8 @@ function createApp(db, dashboardDist, initialCaps, initialPlanData) {
|
|
|
35995
36997
|
if (apiKey) {
|
|
35996
36998
|
const { createCloudCapabilities: createCloudCapabilities2 } = await Promise.resolve().then(() => (init_cloud_capabilities(), cloud_capabilities_exports));
|
|
35997
36999
|
caps = createCloudCapabilities2(
|
|
35998
|
-
|
|
37000
|
+
() => readApiKey(),
|
|
37001
|
+
provisionApiKey,
|
|
35999
37002
|
(counter, amount) => {
|
|
36000
37003
|
try {
|
|
36001
37004
|
usageQueries.increment(db, counter, amount);
|
|
@@ -36082,10 +37085,9 @@ var init_server3 = __esm({
|
|
|
36082
37085
|
TEMPLATE = `<!-- LENS \u2014 Repo Context Daemon -->
|
|
36083
37086
|
## LENS Context
|
|
36084
37087
|
|
|
36085
|
-
This repo is indexed by LENS.
|
|
36086
|
-
|
|
36087
|
-
lens context "<your goal>"
|
|
36088
|
-
\`\`\``;
|
|
37088
|
+
This repo is indexed by LENS. When exploring architecture, tracing data flow, or assessing change impact, call \`mcp__lens__get_context\` \u2014 it returns ranked files with import chains and co-change clusters that keyword search alone won't surface.
|
|
37089
|
+
|
|
37090
|
+
CLI alternative: \`lens context "<your goal>"\``;
|
|
36089
37091
|
startedAt = Date.now();
|
|
36090
37092
|
MIME_TYPES = {
|
|
36091
37093
|
".html": "text/html",
|
|
@@ -36678,6 +37680,7 @@ import { join as join6 } from "path";
|
|
|
36678
37680
|
var LENS_DIR = join6(homedir4(), ".lens");
|
|
36679
37681
|
var PID_FILE = join6(LENS_DIR, "daemon.pid");
|
|
36680
37682
|
var LOG_FILE = join6(LENS_DIR, "daemon.log");
|
|
37683
|
+
var AUTH_FILE = join6(LENS_DIR, "auth.json");
|
|
36681
37684
|
function writePid() {
|
|
36682
37685
|
writeFileSync3(PID_FILE, String(process.pid));
|
|
36683
37686
|
}
|
|
@@ -36687,76 +37690,97 @@ function removePid() {
|
|
|
36687
37690
|
} catch {
|
|
36688
37691
|
}
|
|
36689
37692
|
}
|
|
36690
|
-
|
|
36691
|
-
if (data.api_key) return data.api_key;
|
|
36692
|
-
if (!data.access_token) return void 0;
|
|
36693
|
-
const cloudUrl = getCloudUrl();
|
|
37693
|
+
function readApiKeyFromDisk() {
|
|
36694
37694
|
try {
|
|
37695
|
+
const data = JSON.parse(readFileSync3(AUTH_FILE, "utf-8"));
|
|
37696
|
+
return data.api_key || null;
|
|
37697
|
+
} catch {
|
|
37698
|
+
return null;
|
|
37699
|
+
}
|
|
37700
|
+
}
|
|
37701
|
+
async function provisionNewKey() {
|
|
37702
|
+
try {
|
|
37703
|
+
const data = JSON.parse(readFileSync3(AUTH_FILE, "utf-8"));
|
|
37704
|
+
if (!data.access_token) return null;
|
|
37705
|
+
const cloudUrl = getCloudUrl();
|
|
36695
37706
|
const res = await fetch(`${cloudUrl}/auth/key`, {
|
|
36696
37707
|
headers: { Authorization: `Bearer ${data.access_token}` }
|
|
36697
37708
|
});
|
|
36698
|
-
if (!res.ok)
|
|
36699
|
-
console.error(`[LENS] API key provisioning failed (${res.status})`);
|
|
36700
|
-
return void 0;
|
|
36701
|
-
}
|
|
37709
|
+
if (!res.ok) return null;
|
|
36702
37710
|
const { api_key } = await res.json();
|
|
36703
37711
|
data.api_key = api_key;
|
|
36704
|
-
|
|
36705
|
-
|
|
36706
|
-
console.error("[LENS] API key auto-provisioned");
|
|
37712
|
+
writeFileSync3(AUTH_FILE, JSON.stringify(data, null, 2), { mode: 384 });
|
|
37713
|
+
console.error("[LENS] API key re-provisioned");
|
|
36707
37714
|
return api_key;
|
|
36708
|
-
} catch
|
|
36709
|
-
|
|
36710
|
-
return void 0;
|
|
37715
|
+
} catch {
|
|
37716
|
+
return null;
|
|
36711
37717
|
}
|
|
36712
37718
|
}
|
|
36713
37719
|
async function loadCapabilities(db) {
|
|
36714
37720
|
try {
|
|
36715
|
-
|
|
36716
|
-
|
|
36717
|
-
|
|
36718
|
-
|
|
37721
|
+
let apiKey = readApiKeyFromDisk();
|
|
37722
|
+
if (!apiKey) {
|
|
37723
|
+
apiKey = await provisionNewKey();
|
|
37724
|
+
if (!apiKey) return {};
|
|
37725
|
+
}
|
|
36719
37726
|
const cloudUrl = getCloudUrl();
|
|
36720
37727
|
const res = await fetch(`${cloudUrl}/api/usage/current`, {
|
|
36721
37728
|
headers: { Authorization: `Bearer ${apiKey}` }
|
|
36722
37729
|
});
|
|
37730
|
+
if (res.status === 401) {
|
|
37731
|
+
apiKey = await provisionNewKey();
|
|
37732
|
+
if (!apiKey) return {};
|
|
37733
|
+
const retry = await fetch(`${cloudUrl}/api/usage/current`, {
|
|
37734
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
37735
|
+
});
|
|
37736
|
+
if (!retry.ok) {
|
|
37737
|
+
console.error(`[LENS] Plan check failed after re-provision (${retry.status})`);
|
|
37738
|
+
return {};
|
|
37739
|
+
}
|
|
37740
|
+
const usageData2 = await retry.json();
|
|
37741
|
+
return buildCapsResult(db, usageData2);
|
|
37742
|
+
}
|
|
36723
37743
|
if (!res.ok) {
|
|
36724
37744
|
console.error(`[LENS] Plan check failed (${res.status}), capabilities disabled`);
|
|
36725
37745
|
return {};
|
|
36726
37746
|
}
|
|
36727
37747
|
const usageData = await res.json();
|
|
36728
|
-
|
|
36729
|
-
plan: usageData.plan ?? "free",
|
|
36730
|
-
usage: usageData.usage ?? {},
|
|
36731
|
-
quota: usageData.quota ?? {}
|
|
36732
|
-
};
|
|
36733
|
-
if (usageData.plan !== "pro") {
|
|
36734
|
-
console.error(`[LENS] Plan: ${usageData.plan ?? "free"} \u2014 Pro features disabled`);
|
|
36735
|
-
return { planData };
|
|
36736
|
-
}
|
|
36737
|
-
const { createCloudCapabilities: createCloudCapabilities2 } = await Promise.resolve().then(() => (init_cloud_capabilities(), cloud_capabilities_exports));
|
|
36738
|
-
const { usageQueries: usageQueries2, logQueries: logQueries2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
36739
|
-
const caps = createCloudCapabilities2(
|
|
36740
|
-
apiKey,
|
|
36741
|
-
(counter, amount) => {
|
|
36742
|
-
try {
|
|
36743
|
-
usageQueries2.increment(db, counter, amount);
|
|
36744
|
-
} catch {
|
|
36745
|
-
}
|
|
36746
|
-
},
|
|
36747
|
-
(method, path, status, duration3, source, reqBody, resBody) => {
|
|
36748
|
-
try {
|
|
36749
|
-
logQueries2.insert(db, method, path, status, duration3, source, reqBody, resBody?.length, resBody);
|
|
36750
|
-
} catch {
|
|
36751
|
-
}
|
|
36752
|
-
}
|
|
36753
|
-
);
|
|
36754
|
-
console.error("[LENS] Cloud capabilities enabled (Pro plan)");
|
|
36755
|
-
return { caps, planData };
|
|
37748
|
+
return buildCapsResult(db, usageData);
|
|
36756
37749
|
} catch {
|
|
36757
37750
|
return {};
|
|
36758
37751
|
}
|
|
36759
37752
|
}
|
|
37753
|
+
async function buildCapsResult(db, usageData) {
|
|
37754
|
+
const planData = {
|
|
37755
|
+
plan: usageData.plan ?? "free",
|
|
37756
|
+
usage: usageData.usage ?? {},
|
|
37757
|
+
quota: usageData.quota ?? {}
|
|
37758
|
+
};
|
|
37759
|
+
if (usageData.plan !== "pro") {
|
|
37760
|
+
console.error(`[LENS] Plan: ${usageData.plan ?? "free"} \u2014 Pro features disabled`);
|
|
37761
|
+
return { planData };
|
|
37762
|
+
}
|
|
37763
|
+
const { createCloudCapabilities: createCloudCapabilities2 } = await Promise.resolve().then(() => (init_cloud_capabilities(), cloud_capabilities_exports));
|
|
37764
|
+
const { usageQueries: usageQueries2, logQueries: logQueries2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
37765
|
+
const caps = createCloudCapabilities2(
|
|
37766
|
+
() => Promise.resolve(readApiKeyFromDisk()),
|
|
37767
|
+
provisionNewKey,
|
|
37768
|
+
(counter, amount) => {
|
|
37769
|
+
try {
|
|
37770
|
+
usageQueries2.increment(db, counter, amount);
|
|
37771
|
+
} catch {
|
|
37772
|
+
}
|
|
37773
|
+
},
|
|
37774
|
+
(method, path, status, duration3, source, reqBody, resBody) => {
|
|
37775
|
+
try {
|
|
37776
|
+
logQueries2.insert(db, method, path, status, duration3, source, reqBody, resBody?.length, resBody);
|
|
37777
|
+
} catch {
|
|
37778
|
+
}
|
|
37779
|
+
}
|
|
37780
|
+
);
|
|
37781
|
+
console.error("[LENS] Cloud capabilities enabled (Pro plan)");
|
|
37782
|
+
return { caps, planData };
|
|
37783
|
+
}
|
|
36760
37784
|
async function main() {
|
|
36761
37785
|
const db = openDb();
|
|
36762
37786
|
const { caps, planData } = await loadCapabilities(db);
|