sigmap 8.16.1 → 8.18.0
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/AGENTS.md +164 -192
- package/CHANGELOG.md +24 -0
- package/README.md +12 -10
- package/gen-context.js +333 -70
- package/llms-full.txt +6 -6
- package/llms.txt +5 -5
- package/package.json +2 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/config/defaults.js +2 -0
- package/src/extractors/csharp.js +17 -5
- package/src/extractors/dart.js +32 -8
- package/src/extractors/go.js +25 -9
- package/src/extractors/java.js +16 -5
- package/src/extractors/kotlin.js +32 -8
- package/src/extractors/php.js +31 -6
- package/src/extractors/rust.js +38 -10
- package/src/extractors/scala.js +18 -6
- package/src/extractors/swift.js +31 -7
- package/src/map/route-table.js +14 -2
- package/src/mcp/handlers.js +4 -1
- package/src/mcp/server.js +1 -1
- package/src/retrieval/bm25.js +4 -1
- package/src/retrieval/enrich-from-maps.js +55 -0
package/gen-context.js
CHANGED
|
@@ -1533,6 +1533,8 @@ __factories["./src/config/defaults"] = function(module, exports) {
|
|
|
1533
1533
|
recencyBoost: 1.5,
|
|
1534
1534
|
// Boost files call-graph-connected to query matches (opt-in, measure-gated)
|
|
1535
1535
|
callGraphBoost: false,
|
|
1536
|
+
// Append route pseudo-signatures to the rankable index (opt-in, measure-gated)
|
|
1537
|
+
surfaceEnrichment: false,
|
|
1536
1538
|
},
|
|
1537
1539
|
|
|
1538
1540
|
// Impact layer settings (v2.5)
|
|
@@ -5229,8 +5231,12 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
|
|
|
5229
5231
|
// ── ./src/extractors/csharp ──
|
|
5230
5232
|
__factories["./src/extractors/csharp"] = function(module, exports) {
|
|
5231
5233
|
|
|
5234
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
5235
|
+
|
|
5232
5236
|
/**
|
|
5233
5237
|
* Extract signatures from C# source code.
|
|
5238
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
5239
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5234
5240
|
* @param {string} src - Raw file content
|
|
5235
5241
|
* @returns {string[]} Array of signature strings
|
|
5236
5242
|
*/
|
|
@@ -5240,14 +5246,18 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
|
|
|
5240
5246
|
|
|
5241
5247
|
const stripped = src
|
|
5242
5248
|
.replace(/\/\/.*$/gm, '')
|
|
5243
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
5249
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
5244
5250
|
|
|
5245
5251
|
// Classes and interfaces
|
|
5246
5252
|
const typeRe = /^\s*(?:public\s+|internal\s+|protected\s+)?(?:abstract\s+|sealed\s+|static\s+)?(class|interface|enum|record|struct)\s+(\w+)(?:<[^{]*>)?(?:\s*:\s*[\w<>, .]+)?\s*\{/gm;
|
|
5247
5253
|
for (const m of stripped.matchAll(typeRe)) {
|
|
5248
|
-
|
|
5249
|
-
const
|
|
5250
|
-
|
|
5254
|
+
const declIdx = m.index + (m[0].length - m[0].trimStart().length);
|
|
5255
|
+
const bodyStart = m.index + m[0].length;
|
|
5256
|
+
const block = extractBlock(stripped, bodyStart);
|
|
5257
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, declIdx), lineAt(stripped, bodyStart + block.length)));
|
|
5258
|
+
for (const meth of extractMembers(block)) {
|
|
5259
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
5260
|
+
}
|
|
5251
5261
|
}
|
|
5252
5262
|
|
|
5253
5263
|
return sigs.slice(0, 25);
|
|
@@ -5270,7 +5280,11 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
|
|
|
5270
5280
|
for (const m of block.matchAll(methodRe)) {
|
|
5271
5281
|
const ret = normalizeType(m[1]);
|
|
5272
5282
|
const retStr = ret ? ` → ${ret}` : '';
|
|
5273
|
-
members.push(
|
|
5283
|
+
members.push({
|
|
5284
|
+
text: `${m[2]}(${normalizeParams(m[3])})${retStr}`,
|
|
5285
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
5286
|
+
endIdx: m.index + m[0].length,
|
|
5287
|
+
});
|
|
5274
5288
|
}
|
|
5275
5289
|
return members.slice(0, 8);
|
|
5276
5290
|
}
|
|
@@ -5365,8 +5379,12 @@ __factories["./src/extractors/css"] = function(module, exports) {
|
|
|
5365
5379
|
// ── ./src/extractors/dart ──
|
|
5366
5380
|
__factories["./src/extractors/dart"] = function(module, exports) {
|
|
5367
5381
|
|
|
5382
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
5383
|
+
|
|
5368
5384
|
/**
|
|
5369
5385
|
* Extract signatures from Dart source code.
|
|
5386
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
5387
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5370
5388
|
* @param {string} src - Raw file content
|
|
5371
5389
|
* @returns {string[]} Array of signature strings
|
|
5372
5390
|
*/
|
|
@@ -5376,21 +5394,37 @@ __factories["./src/extractors/dart"] = function(module, exports) {
|
|
|
5376
5394
|
|
|
5377
5395
|
const stripped = src
|
|
5378
5396
|
.replace(/\/\/.*$/gm, '')
|
|
5379
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
5397
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
5398
|
+
|
|
5399
|
+
// Anchor range: scan past same-line trivia (`async`, `=>` stops) to a body `{`.
|
|
5400
|
+
const rangeFor = (declIdx, afterIdx) => {
|
|
5401
|
+
let k = afterIdx;
|
|
5402
|
+
while (k < stripped.length && /[ \tA-Za-z0-9_]/.test(stripped[k])) k++;
|
|
5403
|
+
if (stripped[k] === '{') {
|
|
5404
|
+
const end = k + 1 + extractBlock(stripped, k + 1).length;
|
|
5405
|
+
return [lineAt(stripped, declIdx), lineAt(stripped, end)];
|
|
5406
|
+
}
|
|
5407
|
+
const line = lineAt(stripped, declIdx);
|
|
5408
|
+
return [line, line];
|
|
5409
|
+
};
|
|
5380
5410
|
|
|
5381
5411
|
// Classes and abstract classes
|
|
5382
5412
|
for (const m of stripped.matchAll(/^(?:abstract\s+)?class\s+(\w+)(?:<[^{]*>)?(?:\s+extends\s+[\w<>, ]+)?(?:\s+(?:implements|with|on)\s+[\w<>, ]+)?\s*\{/gm)) {
|
|
5383
5413
|
const abs = m[0].trimStart().startsWith('abstract') ? 'abstract ' : '';
|
|
5384
|
-
|
|
5385
|
-
const block = extractBlock(stripped,
|
|
5386
|
-
|
|
5414
|
+
const bodyStart = m.index + m[0].length;
|
|
5415
|
+
const block = extractBlock(stripped, bodyStart);
|
|
5416
|
+
sigs.push(withAnchor(`${abs}class ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
5417
|
+
for (const meth of extractMembers(block)) {
|
|
5418
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
5419
|
+
}
|
|
5387
5420
|
}
|
|
5388
5421
|
|
|
5389
5422
|
// Top-level functions — capture return type (prefix before name) and show as suffix
|
|
5390
5423
|
for (const m of stripped.matchAll(/^((?:Future<[\w<>?,\s]*>|[\w<>?]+))\s+(\w+)\s*\(([^)]*)\)/gm)) {
|
|
5391
5424
|
if (m[2].startsWith('_')) continue;
|
|
5392
|
-
const retStr = (m[1] && m[1] !== 'void') ? `
|
|
5393
|
-
|
|
5425
|
+
const retStr = (m[1] && m[1] !== 'void') ? ` → ${m[1].replace(/\s+/g, '').slice(0, 25)}` : '';
|
|
5426
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
5427
|
+
sigs.push(withAnchor(`${m[2]}(${normalizeParams(m[3])})${retStr}`, s, e));
|
|
5394
5428
|
}
|
|
5395
5429
|
|
|
5396
5430
|
return sigs.slice(0, 25);
|
|
@@ -5411,8 +5445,12 @@ __factories["./src/extractors/dart"] = function(module, exports) {
|
|
|
5411
5445
|
const members = [];
|
|
5412
5446
|
for (const m of block.matchAll(/^\s+(?:@override\s+)?(?:@\w+\s+)*((?:Future<[\w<>?,\s]*>|[\w<>?]+))\s+(\w+)\s*\(([^)]*)\)/gm)) {
|
|
5413
5447
|
if (m[2].startsWith('_')) continue;
|
|
5414
|
-
const retStr = (m[1] && m[1] !== 'void') ? `
|
|
5415
|
-
members.push(
|
|
5448
|
+
const retStr = (m[1] && m[1] !== 'void') ? ` → ${m[1].replace(/\s+/g, '').slice(0, 25)}` : '';
|
|
5449
|
+
members.push({
|
|
5450
|
+
text: `${m[2]}(${normalizeParams(m[3])})${retStr}`,
|
|
5451
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
5452
|
+
endIdx: m.index + m[0].length,
|
|
5453
|
+
});
|
|
5416
5454
|
}
|
|
5417
5455
|
return members.slice(0, 8);
|
|
5418
5456
|
}
|
|
@@ -5878,8 +5916,12 @@ __factories["./src/extractors/generic"] = function(module, exports) {
|
|
|
5878
5916
|
// ── ./src/extractors/go ──
|
|
5879
5917
|
__factories["./src/extractors/go"] = function(module, exports) {
|
|
5880
5918
|
|
|
5919
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
5920
|
+
|
|
5881
5921
|
/**
|
|
5882
5922
|
* Extract signatures from Go source code.
|
|
5923
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
5924
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5883
5925
|
* @param {string} src - Raw file content
|
|
5884
5926
|
* @returns {string[]} Array of signature strings
|
|
5885
5927
|
*/
|
|
@@ -5889,26 +5931,34 @@ __factories["./src/extractors/go"] = function(module, exports) {
|
|
|
5889
5931
|
|
|
5890
5932
|
const stripped = src
|
|
5891
5933
|
.replace(/\/\/.*$/gm, '')
|
|
5892
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
5934
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
5935
|
+
|
|
5936
|
+
// Index of the closing brace for a block opened just before startIndex.
|
|
5937
|
+
const blockEndIdx = (startIndex) => startIndex + extractBlock(stripped, startIndex).length;
|
|
5893
5938
|
|
|
5894
5939
|
// Structs
|
|
5895
5940
|
for (const m of stripped.matchAll(/^type\s+(\w+)\s+struct\s*\{/gm)) {
|
|
5896
|
-
|
|
5941
|
+
const end = blockEndIdx(m.index + m[0].length);
|
|
5942
|
+
sigs.push(withAnchor(`type ${m[1]} struct`, lineAt(stripped, m.index), lineAt(stripped, end)));
|
|
5897
5943
|
}
|
|
5898
5944
|
|
|
5899
5945
|
// Interfaces
|
|
5900
5946
|
for (const m of stripped.matchAll(/^type\s+(\w+)\s+interface\s*\{/gm)) {
|
|
5901
|
-
|
|
5902
|
-
const block = extractBlock(stripped,
|
|
5903
|
-
|
|
5947
|
+
const bodyStart = m.index + m[0].length;
|
|
5948
|
+
const block = extractBlock(stripped, bodyStart);
|
|
5949
|
+
sigs.push(withAnchor(`type ${m[1]} interface`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
5950
|
+
for (const meth of extractInterfaceMethods(block)) {
|
|
5951
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
5952
|
+
}
|
|
5904
5953
|
}
|
|
5905
5954
|
|
|
5906
5955
|
// Functions and methods — capture return type between ) and {
|
|
5907
5956
|
for (const m of stripped.matchAll(/^func\s+(?:\((\w+)\s+[\w*]+\)\s+)?(\w+)\s*\(([^)]*)\)([^{]*)\{/gm)) {
|
|
5908
5957
|
const receiver = m[1] ? `(${m[1]}) ` : '';
|
|
5909
5958
|
const retType = m[4] ? m[4].trim().replace(/\s+/g, ' ') : '';
|
|
5910
|
-
const retStr = retType ? `
|
|
5911
|
-
|
|
5959
|
+
const retStr = retType ? ` → ${retType.slice(0, 30)}` : '';
|
|
5960
|
+
const end = blockEndIdx(m.index + m[0].length);
|
|
5961
|
+
sigs.push(withAnchor(`func ${receiver}${m[2]}(${normalizeParams(m[3])})${retStr}`, lineAt(stripped, m.index), lineAt(stripped, end)));
|
|
5912
5962
|
}
|
|
5913
5963
|
|
|
5914
5964
|
return sigs.slice(0, 25);
|
|
@@ -5929,8 +5979,12 @@ __factories["./src/extractors/go"] = function(module, exports) {
|
|
|
5929
5979
|
const methods = [];
|
|
5930
5980
|
for (const m of block.matchAll(/^\s+(\w+)\s*\(([^)]*)\)([^\n]*)/gm)) {
|
|
5931
5981
|
const retType = m[3] ? m[3].trim().replace(/\s+/g, ' ') : '';
|
|
5932
|
-
const retStr = retType ? `
|
|
5933
|
-
methods.push(
|
|
5982
|
+
const retStr = retType ? ` → ${retType.slice(0, 30)}` : '';
|
|
5983
|
+
methods.push({
|
|
5984
|
+
text: `${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
5985
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
5986
|
+
endIdx: m.index + m[0].length,
|
|
5987
|
+
});
|
|
5934
5988
|
}
|
|
5935
5989
|
return methods.slice(0, 8);
|
|
5936
5990
|
}
|
|
@@ -6060,8 +6114,12 @@ __factories["./src/extractors/html"] = function(module, exports) {
|
|
|
6060
6114
|
// ── ./src/extractors/java ──
|
|
6061
6115
|
__factories["./src/extractors/java"] = function(module, exports) {
|
|
6062
6116
|
|
|
6117
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
6118
|
+
|
|
6063
6119
|
/**
|
|
6064
6120
|
* Extract signatures from Java source code.
|
|
6121
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
6122
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
6065
6123
|
* @param {string} src - Raw file content
|
|
6066
6124
|
* @returns {string[]} Array of signature strings
|
|
6067
6125
|
*/
|
|
@@ -6071,14 +6129,17 @@ __factories["./src/extractors/java"] = function(module, exports) {
|
|
|
6071
6129
|
|
|
6072
6130
|
const stripped = src
|
|
6073
6131
|
.replace(/\/\/.*$/gm, '')
|
|
6074
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
6132
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
6075
6133
|
|
|
6076
6134
|
// Classes and interfaces
|
|
6077
6135
|
const typeRegex = /^(?:public\s+|protected\s+)?(?:abstract\s+|final\s+)?(class|interface|enum)\s+(\w+)(?:\s+extends\s+[\w<>, .]+)?(?:\s+implements\s+[\w<>, .]+)?\s*\{/gm;
|
|
6078
6136
|
for (const m of stripped.matchAll(typeRegex)) {
|
|
6079
|
-
|
|
6080
|
-
const block = extractBlock(stripped,
|
|
6081
|
-
|
|
6137
|
+
const bodyStart = m.index + m[0].length;
|
|
6138
|
+
const block = extractBlock(stripped, bodyStart);
|
|
6139
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
6140
|
+
for (const meth of extractMembers(block)) {
|
|
6141
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
6142
|
+
}
|
|
6082
6143
|
}
|
|
6083
6144
|
|
|
6084
6145
|
return sigs.slice(0, 25);
|
|
@@ -6102,7 +6163,11 @@ __factories["./src/extractors/java"] = function(module, exports) {
|
|
|
6102
6163
|
for (const m of block.matchAll(methodRe)) {
|
|
6103
6164
|
const ret = normalizeType(m[1]);
|
|
6104
6165
|
const retStr = ret ? ` → ${ret}` : '';
|
|
6105
|
-
members.push(
|
|
6166
|
+
members.push({
|
|
6167
|
+
text: `${m[2]}(${normalizeParams(m[3])})${retStr}`,
|
|
6168
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
6169
|
+
endIdx: m.index + m[0].length,
|
|
6170
|
+
});
|
|
6106
6171
|
}
|
|
6107
6172
|
return members.slice(0, 8);
|
|
6108
6173
|
}
|
|
@@ -6275,8 +6340,12 @@ __factories["./src/extractors/javascript"] = function(module, exports) {
|
|
|
6275
6340
|
// ── ./src/extractors/kotlin ──
|
|
6276
6341
|
__factories["./src/extractors/kotlin"] = function(module, exports) {
|
|
6277
6342
|
|
|
6343
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
6344
|
+
|
|
6278
6345
|
/**
|
|
6279
6346
|
* Extract signatures from Kotlin source code.
|
|
6347
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
6348
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
6280
6349
|
* @param {string} src - Raw file content
|
|
6281
6350
|
* @returns {string[]} Array of signature strings
|
|
6282
6351
|
*/
|
|
@@ -6286,21 +6355,37 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
|
|
|
6286
6355
|
|
|
6287
6356
|
const stripped = src
|
|
6288
6357
|
.replace(/\/\/.*$/gm, '')
|
|
6289
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
6358
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
6359
|
+
|
|
6360
|
+
// Anchor range: scan past same-line modifiers to a body `{` (range) else single line.
|
|
6361
|
+
const rangeFor = (declIdx, afterIdx) => {
|
|
6362
|
+
let k = afterIdx;
|
|
6363
|
+
while (k < stripped.length && /[ \tA-Za-z0-9_]/.test(stripped[k])) k++;
|
|
6364
|
+
if (stripped[k] === '{') {
|
|
6365
|
+
const end = k + 1 + extractBlock(stripped, k + 1).length;
|
|
6366
|
+
return [lineAt(stripped, declIdx), lineAt(stripped, end)];
|
|
6367
|
+
}
|
|
6368
|
+
const line = lineAt(stripped, declIdx);
|
|
6369
|
+
return [line, line];
|
|
6370
|
+
};
|
|
6290
6371
|
|
|
6291
6372
|
// Classes, objects, interfaces
|
|
6292
6373
|
for (const m of stripped.matchAll(/^(?:public\s+|internal\s+)?(?:data\s+|sealed\s+|abstract\s+|open\s+)?(class|object|interface)\s+(\w+)(?:[^{]*)\{/gm)) {
|
|
6293
|
-
|
|
6294
|
-
const block = extractBlock(stripped,
|
|
6295
|
-
|
|
6374
|
+
const bodyStart = m.index + m[0].length;
|
|
6375
|
+
const block = extractBlock(stripped, bodyStart);
|
|
6376
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
6377
|
+
for (const meth of extractMembers(block)) {
|
|
6378
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
6379
|
+
}
|
|
6296
6380
|
}
|
|
6297
6381
|
|
|
6298
6382
|
// Top-level functions — capture `: RetType` after params
|
|
6299
6383
|
for (const m of stripped.matchAll(/^(?:public\s+|internal\s+)?(?:suspend\s+)?fun\s+(\w+)\s*(?:<[^(]*>)?\s*\(([^)]*)\)(?:\s*:\s*([^\n{=]+))?/gm)) {
|
|
6300
6384
|
const suspend = m[0].includes('suspend') ? 'suspend ' : '';
|
|
6301
6385
|
const retType = m[3] ? m[3].trim().replace(/\s+/g, ' ') : '';
|
|
6302
|
-
const retStr = retType ? `
|
|
6303
|
-
|
|
6386
|
+
const retStr = retType ? ` → ${retType.slice(0, 25)}` : '';
|
|
6387
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
6388
|
+
sigs.push(withAnchor(`${suspend}fun ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
6304
6389
|
}
|
|
6305
6390
|
|
|
6306
6391
|
return sigs.slice(0, 25);
|
|
@@ -6323,8 +6408,12 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
|
|
|
6323
6408
|
if (m[1].startsWith('_')) continue;
|
|
6324
6409
|
const suspend = m[0].includes('suspend') ? 'suspend ' : '';
|
|
6325
6410
|
const retType = m[3] ? m[3].trim().replace(/\s+/g, ' ') : '';
|
|
6326
|
-
const retStr = retType ? `
|
|
6327
|
-
members.push(
|
|
6411
|
+
const retStr = retType ? ` → ${retType.slice(0, 25)}` : '';
|
|
6412
|
+
members.push({
|
|
6413
|
+
text: `${suspend}fun ${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
6414
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
6415
|
+
endIdx: m.index + m[0].length,
|
|
6416
|
+
});
|
|
6328
6417
|
}
|
|
6329
6418
|
return members.slice(0, 8);
|
|
6330
6419
|
}
|
|
@@ -6574,8 +6663,12 @@ __factories["./src/extractors/patterns"] = function(module, exports) {
|
|
|
6574
6663
|
// ── ./src/extractors/php ──
|
|
6575
6664
|
__factories["./src/extractors/php"] = function(module, exports) {
|
|
6576
6665
|
|
|
6666
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
6667
|
+
|
|
6577
6668
|
/**
|
|
6578
6669
|
* Extract signatures from PHP source code.
|
|
6670
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
6671
|
+
* strips below are newline-preserving so anchor lines match the original file.
|
|
6579
6672
|
* @param {string} src - Raw file content
|
|
6580
6673
|
* @returns {string[]} Array of signature strings
|
|
6581
6674
|
*/
|
|
@@ -6586,23 +6679,40 @@ __factories["./src/extractors/php"] = function(module, exports) {
|
|
|
6586
6679
|
const stripped = src
|
|
6587
6680
|
.replace(/\/\/.*$/gm, '')
|
|
6588
6681
|
.replace(/#.*$/gm, '')
|
|
6589
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
6682
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
6683
|
+
|
|
6684
|
+
// Anchor range: scan past same-line trivia to a body `{` (range) else single line.
|
|
6685
|
+
const rangeFor = (declIdx, afterIdx) => {
|
|
6686
|
+
let k = afterIdx;
|
|
6687
|
+
while (k < stripped.length && /[ \tA-Za-z0-9_:?\\]/.test(stripped[k])) k++;
|
|
6688
|
+
if (stripped[k] === '{' || (stripped[k] === '\n' && stripped[k + 1] === '{')) {
|
|
6689
|
+
const open = stripped[k] === '{' ? k : k + 1;
|
|
6690
|
+
const end = open + 1 + extractBlock(stripped, open + 1).length;
|
|
6691
|
+
return [lineAt(stripped, declIdx), lineAt(stripped, end)];
|
|
6692
|
+
}
|
|
6693
|
+
const line = lineAt(stripped, declIdx);
|
|
6694
|
+
return [line, line];
|
|
6695
|
+
};
|
|
6590
6696
|
|
|
6591
6697
|
// Classes and interfaces
|
|
6592
6698
|
const typeRe = /^(?:abstract\s+)?(?:class|interface|trait)\s+(\w+)(?:\s+extends\s+\w+)?(?:\s+implements\s+[\w, ]+)?\s*\{/gm;
|
|
6593
6699
|
for (const m of stripped.matchAll(typeRe)) {
|
|
6594
6700
|
const kind = m[0].trimStart().startsWith('interface') ? 'interface' :
|
|
6595
6701
|
m[0].trimStart().startsWith('trait') ? 'trait' : 'class';
|
|
6596
|
-
|
|
6597
|
-
const block = extractBlock(stripped,
|
|
6598
|
-
|
|
6702
|
+
const bodyStart = m.index + m[0].length;
|
|
6703
|
+
const block = extractBlock(stripped, bodyStart);
|
|
6704
|
+
sigs.push(withAnchor(`${kind} ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
6705
|
+
for (const meth of extractMembers(block)) {
|
|
6706
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
6707
|
+
}
|
|
6599
6708
|
}
|
|
6600
6709
|
|
|
6601
6710
|
// Top-level functions
|
|
6602
6711
|
for (const m of stripped.matchAll(/^function\s+(\w+)\s*\(([^)]*)\)\s*(?::\s*([^\n{]+))?/gm)) {
|
|
6603
6712
|
const ret = normalizeType(m[3]);
|
|
6604
6713
|
const retStr = ret ? ` → ${ret}` : '';
|
|
6605
|
-
|
|
6714
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
6715
|
+
sigs.push(withAnchor(`function ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
6606
6716
|
}
|
|
6607
6717
|
|
|
6608
6718
|
return sigs.slice(0, 25);
|
|
@@ -6627,7 +6737,11 @@ __factories["./src/extractors/php"] = function(module, exports) {
|
|
|
6627
6737
|
const isStatic = m[0].includes('static ') ? 'static ' : '';
|
|
6628
6738
|
const ret = normalizeType(m[3]);
|
|
6629
6739
|
const retStr = ret ? ` → ${ret}` : '';
|
|
6630
|
-
members.push(
|
|
6740
|
+
members.push({
|
|
6741
|
+
text: `${isStatic}function ${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
6742
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
6743
|
+
endIdx: m.index + m[0].length,
|
|
6744
|
+
});
|
|
6631
6745
|
}
|
|
6632
6746
|
return members.slice(0, 8);
|
|
6633
6747
|
}
|
|
@@ -7513,8 +7627,12 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
|
|
|
7513
7627
|
// ── ./src/extractors/rust ──
|
|
7514
7628
|
__factories["./src/extractors/rust"] = function(module, exports) {
|
|
7515
7629
|
|
|
7630
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
7631
|
+
|
|
7516
7632
|
/**
|
|
7517
7633
|
* Extract signatures from Rust source code.
|
|
7634
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
7635
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
7518
7636
|
* @param {string} src - Raw file content
|
|
7519
7637
|
* @returns {string[]} Array of signature strings
|
|
7520
7638
|
*/
|
|
@@ -7524,35 +7642,55 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
7524
7642
|
|
|
7525
7643
|
const stripped = src
|
|
7526
7644
|
.replace(/\/\/.*$/gm, '')
|
|
7527
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
7645
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
7646
|
+
|
|
7647
|
+
// Anchor range for a declaration at declIdx whose header ends at afterIdx:
|
|
7648
|
+
// if a `{` body follows, range to its closing brace; else single-line.
|
|
7649
|
+
const rangeFor = (declIdx, afterIdx) => {
|
|
7650
|
+
let k = afterIdx;
|
|
7651
|
+
while (k < stripped.length && /[ \t]/.test(stripped[k])) k++;
|
|
7652
|
+
if (stripped[k] === '{') {
|
|
7653
|
+
const end = k + 1 + extractBlock(stripped, k + 1).length;
|
|
7654
|
+
return [lineAt(stripped, declIdx), lineAt(stripped, end)];
|
|
7655
|
+
}
|
|
7656
|
+
const line = lineAt(stripped, declIdx);
|
|
7657
|
+
return [line, line];
|
|
7658
|
+
};
|
|
7528
7659
|
|
|
7529
7660
|
// Structs
|
|
7530
7661
|
for (const m of stripped.matchAll(/^pub\s+struct\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
7531
|
-
|
|
7662
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7663
|
+
sigs.push(withAnchor(`pub struct ${m[1]}`, s, e));
|
|
7532
7664
|
}
|
|
7533
7665
|
|
|
7534
7666
|
// Enums
|
|
7535
7667
|
for (const m of stripped.matchAll(/^pub\s+enum\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
7536
|
-
|
|
7668
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7669
|
+
sigs.push(withAnchor(`pub enum ${m[1]}`, s, e));
|
|
7537
7670
|
}
|
|
7538
7671
|
|
|
7539
7672
|
// Traits
|
|
7540
7673
|
for (const m of stripped.matchAll(/^pub\s+trait\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
7541
|
-
|
|
7674
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7675
|
+
sigs.push(withAnchor(`pub trait ${m[1]}`, s, e));
|
|
7542
7676
|
}
|
|
7543
7677
|
|
|
7544
7678
|
// impl blocks
|
|
7545
7679
|
for (const m of stripped.matchAll(/^impl(?:<[^>]*>)?\s+(?:[\w:]+\s+for\s+)?(\w+)(?:<[^{]*>)?\s*\{/gm)) {
|
|
7546
|
-
|
|
7547
|
-
const block = extractBlock(stripped,
|
|
7548
|
-
|
|
7680
|
+
const bodyStart = m.index + m[0].length;
|
|
7681
|
+
const block = extractBlock(stripped, bodyStart);
|
|
7682
|
+
sigs.push(withAnchor(`impl ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
7683
|
+
for (const fn of extractMethods(block)) {
|
|
7684
|
+
sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)));
|
|
7685
|
+
}
|
|
7549
7686
|
}
|
|
7550
7687
|
|
|
7551
7688
|
// Top-level pub fns — capture everything after ) up to { or ; for return type
|
|
7552
7689
|
for (const m of stripped.matchAll(/^pub(?:\s+async)?\s+fn\s+(\w+)(?:<[^(]*>)?\s*\(([^)]*)\)([^{;]*)/gm)) {
|
|
7553
7690
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
7554
7691
|
const retStr = extractReturnType(m[3]);
|
|
7555
|
-
|
|
7692
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7693
|
+
sigs.push(withAnchor(`pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
7556
7694
|
}
|
|
7557
7695
|
|
|
7558
7696
|
return sigs.slice(0, 25);
|
|
@@ -7574,7 +7712,11 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
7574
7712
|
for (const m of block.matchAll(/^\s+pub(?:\s+async)?\s+fn\s+(\w+)(?:<[^(]*>)?\s*\(([^)]*)\)([^{;]*)/gm)) {
|
|
7575
7713
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
7576
7714
|
const retStr = extractReturnType(m[3]);
|
|
7577
|
-
methods.push(
|
|
7715
|
+
methods.push({
|
|
7716
|
+
text: `pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
7717
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
7718
|
+
endIdx: m.index + m[0].length,
|
|
7719
|
+
});
|
|
7578
7720
|
}
|
|
7579
7721
|
return methods.slice(0, 8);
|
|
7580
7722
|
}
|
|
@@ -7589,7 +7731,7 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
7589
7731
|
const m = afterParen.match(/->\s*([^{;]+)/);
|
|
7590
7732
|
if (!m) return '';
|
|
7591
7733
|
const rt = m[1].trim().replace(/\s+/g, ' ');
|
|
7592
|
-
return `
|
|
7734
|
+
return ` → ${rt.length > 30 ? rt.slice(0, 27) + '...' : rt}`;
|
|
7593
7735
|
}
|
|
7594
7736
|
|
|
7595
7737
|
module.exports = { extract };
|
|
@@ -7599,8 +7741,12 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
7599
7741
|
// ── ./src/extractors/scala ──
|
|
7600
7742
|
__factories["./src/extractors/scala"] = function(module, exports) {
|
|
7601
7743
|
|
|
7744
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
7745
|
+
|
|
7602
7746
|
/**
|
|
7603
7747
|
* Extract signatures from Scala source code.
|
|
7748
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
7749
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
7604
7750
|
* @param {string} src - Raw file content
|
|
7605
7751
|
* @returns {string[]} Array of signature strings
|
|
7606
7752
|
*/
|
|
@@ -7610,7 +7756,7 @@ __factories["./src/extractors/scala"] = function(module, exports) {
|
|
|
7610
7756
|
|
|
7611
7757
|
const stripped = src
|
|
7612
7758
|
.replace(/\/\/.*$/gm, '')
|
|
7613
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
7759
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
7614
7760
|
|
|
7615
7761
|
// Classes, traits, objects
|
|
7616
7762
|
const typeRe = /^(?:case\s+)?(?:class|trait|object)\s+(\w+)(?:\[[\w, ]+\])?(?:[^{]*)\{/gm;
|
|
@@ -7618,9 +7764,12 @@ __factories["./src/extractors/scala"] = function(module, exports) {
|
|
|
7618
7764
|
const kind = m[0].trimStart().startsWith('case class') ? 'case class' :
|
|
7619
7765
|
m[0].trimStart().startsWith('trait') ? 'trait' :
|
|
7620
7766
|
m[0].trimStart().startsWith('object') ? 'object' : 'class';
|
|
7621
|
-
|
|
7622
|
-
const block = extractBlock(stripped,
|
|
7623
|
-
|
|
7767
|
+
const bodyStart = m.index + m[0].length;
|
|
7768
|
+
const block = extractBlock(stripped, bodyStart);
|
|
7769
|
+
sigs.push(withAnchor(`${kind} ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
7770
|
+
for (const fn of extractMembers(block)) {
|
|
7771
|
+
sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)));
|
|
7772
|
+
}
|
|
7624
7773
|
}
|
|
7625
7774
|
|
|
7626
7775
|
// Top-level defs
|
|
@@ -7629,7 +7778,8 @@ __factories["./src/extractors/scala"] = function(module, exports) {
|
|
|
7629
7778
|
const params = m[2] ? `(${normalizeParams(m[2])})` : '';
|
|
7630
7779
|
const ret = normalizeType(m[3]);
|
|
7631
7780
|
const retStr = ret ? ` → ${ret}` : '';
|
|
7632
|
-
|
|
7781
|
+
const line = lineAt(stripped, m.index);
|
|
7782
|
+
sigs.push(withAnchor(`def ${m[1]}${params}${retStr}`, line, line));
|
|
7633
7783
|
}
|
|
7634
7784
|
|
|
7635
7785
|
return sigs.slice(0, 25);
|
|
@@ -7653,7 +7803,11 @@ __factories["./src/extractors/scala"] = function(module, exports) {
|
|
|
7653
7803
|
const params = m[2] ? `(${normalizeParams(m[2])})` : '';
|
|
7654
7804
|
const ret = normalizeType(m[3]);
|
|
7655
7805
|
const retStr = ret ? ` → ${ret}` : '';
|
|
7656
|
-
members.push(
|
|
7806
|
+
members.push({
|
|
7807
|
+
text: `def ${m[1]}${params}${retStr}`,
|
|
7808
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
7809
|
+
endIdx: m.index + m[0].length,
|
|
7810
|
+
});
|
|
7657
7811
|
}
|
|
7658
7812
|
return members.slice(0, 8);
|
|
7659
7813
|
}
|
|
@@ -7885,8 +8039,12 @@ __factories["./src/extractors/svelte"] = function(module, exports) {
|
|
|
7885
8039
|
// ── ./src/extractors/swift ──
|
|
7886
8040
|
__factories["./src/extractors/swift"] = function(module, exports) {
|
|
7887
8041
|
|
|
8042
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
8043
|
+
|
|
7888
8044
|
/**
|
|
7889
8045
|
* Extract signatures from Swift source code.
|
|
8046
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
8047
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
7890
8048
|
* @param {string} src - Raw file content
|
|
7891
8049
|
* @returns {string[]} Array of signature strings
|
|
7892
8050
|
*/
|
|
@@ -7896,21 +8054,37 @@ __factories["./src/extractors/swift"] = function(module, exports) {
|
|
|
7896
8054
|
|
|
7897
8055
|
const stripped = src
|
|
7898
8056
|
.replace(/\/\/.*$/gm, '')
|
|
7899
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
8057
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
8058
|
+
|
|
8059
|
+
// Anchor range: scan past same-line modifiers to a body `{` (range) else single line.
|
|
8060
|
+
const rangeFor = (declIdx, afterIdx) => {
|
|
8061
|
+
let k = afterIdx;
|
|
8062
|
+
while (k < stripped.length && /[ \tA-Za-z0-9_>-]/.test(stripped[k])) k++;
|
|
8063
|
+
if (stripped[k] === '{') {
|
|
8064
|
+
const end = k + 1 + extractBlock(stripped, k + 1).length;
|
|
8065
|
+
return [lineAt(stripped, declIdx), lineAt(stripped, end)];
|
|
8066
|
+
}
|
|
8067
|
+
const line = lineAt(stripped, declIdx);
|
|
8068
|
+
return [line, line];
|
|
8069
|
+
};
|
|
7900
8070
|
|
|
7901
8071
|
// Classes, structs, protocols, enums
|
|
7902
8072
|
const typeRe = /^(?:public\s+|internal\s+|open\s+)?(?:final\s+)?(class|struct|protocol|enum|actor)\s+(\w+)(?:<[^{]*>)?(?:\s*:\s*[\w, <>.]+)?\s*\{/gm;
|
|
7903
8073
|
for (const m of stripped.matchAll(typeRe)) {
|
|
7904
|
-
|
|
7905
|
-
const block = extractBlock(stripped,
|
|
7906
|
-
|
|
8074
|
+
const bodyStart = m.index + m[0].length;
|
|
8075
|
+
const block = extractBlock(stripped, bodyStart);
|
|
8076
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
8077
|
+
for (const fn of extractMembers(block)) {
|
|
8078
|
+
sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)));
|
|
8079
|
+
}
|
|
7907
8080
|
}
|
|
7908
8081
|
|
|
7909
8082
|
// Top-level public functions — capture everything after ) to end of line for arrow type
|
|
7910
8083
|
for (const m of stripped.matchAll(/^(?:public\s+|internal\s+)?(?:static\s+)?(?:async\s+)?func\s+(\w+)(?:<[^(]*>)?\s*\(([^)]*)\)([^{\n]*)/gm)) {
|
|
7911
8084
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
7912
8085
|
const retStr = extractArrowType(m[3]);
|
|
7913
|
-
|
|
8086
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
8087
|
+
sigs.push(withAnchor(`${asyncKw}func ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
7914
8088
|
}
|
|
7915
8089
|
|
|
7916
8090
|
return sigs.slice(0, 25);
|
|
@@ -7933,7 +8107,11 @@ __factories["./src/extractors/swift"] = function(module, exports) {
|
|
|
7933
8107
|
if (m[1].startsWith('_')) continue;
|
|
7934
8108
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
7935
8109
|
const retStr = extractArrowType(m[3]);
|
|
7936
|
-
members.push(
|
|
8110
|
+
members.push({
|
|
8111
|
+
text: `${asyncKw}func ${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
8112
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
8113
|
+
endIdx: m.index + m[0].length,
|
|
8114
|
+
});
|
|
7937
8115
|
}
|
|
7938
8116
|
return members.slice(0, 8);
|
|
7939
8117
|
}
|
|
@@ -7952,7 +8130,7 @@ __factories["./src/extractors/swift"] = function(module, exports) {
|
|
|
7952
8130
|
const m = str.match(/->\s*([^\n{]+)/);
|
|
7953
8131
|
if (!m) return '';
|
|
7954
8132
|
const rt = m[1].trim().replace(/\s+/g, ' ');
|
|
7955
|
-
return `
|
|
8133
|
+
return ` → ${rt.length > 25 ? rt.slice(0, 22) + '...' : rt}`;
|
|
7956
8134
|
}
|
|
7957
8135
|
|
|
7958
8136
|
module.exports = { extract };
|
|
@@ -13160,7 +13338,14 @@ __factories["./src/map/route-table"] = function(module, exports) {
|
|
|
13160
13338
|
return /(^|\/)(gen-context|gen-project-map)\.js$/.test(normalized);
|
|
13161
13339
|
}
|
|
13162
13340
|
|
|
13163
|
-
|
|
13341
|
+
/**
|
|
13342
|
+
* Structured route rows across the supported frameworks — the data behind
|
|
13343
|
+
* `analyze`, exposed for retrieval surface-enrichment (#488).
|
|
13344
|
+
* @param {string[]} files absolute paths
|
|
13345
|
+
* @param {string} cwd
|
|
13346
|
+
* @returns {{ method:string, path:string, file:string }[]} file is cwd-relative
|
|
13347
|
+
*/
|
|
13348
|
+
function collectRoutes(files, cwd) {
|
|
13164
13349
|
const routes = [];
|
|
13165
13350
|
|
|
13166
13351
|
for (const filePath of files) {
|
|
@@ -13252,6 +13437,11 @@ __factories["./src/map/route-table"] = function(module, exports) {
|
|
|
13252
13437
|
}
|
|
13253
13438
|
}
|
|
13254
13439
|
|
|
13440
|
+
return routes;
|
|
13441
|
+
}
|
|
13442
|
+
|
|
13443
|
+
function analyze(files, cwd) {
|
|
13444
|
+
const routes = collectRoutes(files, cwd);
|
|
13255
13445
|
if (routes.length === 0) return '';
|
|
13256
13446
|
|
|
13257
13447
|
const lines = [
|
|
@@ -13264,7 +13454,7 @@ __factories["./src/map/route-table"] = function(module, exports) {
|
|
|
13264
13454
|
return lines.join('\n');
|
|
13265
13455
|
}
|
|
13266
13456
|
|
|
13267
|
-
module.exports = { analyze };
|
|
13457
|
+
module.exports = { analyze, collectRoutes };
|
|
13268
13458
|
|
|
13269
13459
|
};
|
|
13270
13460
|
|
|
@@ -13692,7 +13882,7 @@ __factories["./src/mcp/handlers"] = function(module, exports) {
|
|
|
13692
13882
|
// Build dependency graph for neighbor boost — non-fatal if it fails
|
|
13693
13883
|
let graph = null;
|
|
13694
13884
|
try { graph = buildFromCwd(cwd); } catch (_) {}
|
|
13695
|
-
// Opt-in call-graph neighbor boost
|
|
13885
|
+
// Opt-in call-graph neighbor boost + surface enrichment — non-fatal
|
|
13696
13886
|
let callGraph = null;
|
|
13697
13887
|
try {
|
|
13698
13888
|
const { loadConfig } = __require('./src/config/loader');
|
|
@@ -13700,6 +13890,9 @@ __factories["./src/mcp/handlers"] = function(module, exports) {
|
|
|
13700
13890
|
if (retrieval && retrieval.callGraphBoost) {
|
|
13701
13891
|
callGraph = __require('./src/graph/call-graph').buildCallFileGraph(cwd);
|
|
13702
13892
|
}
|
|
13893
|
+
if (retrieval && retrieval.surfaceEnrichment) {
|
|
13894
|
+
__require('./src/retrieval/enrich-from-maps').enrichWithSurfaces(index, cwd);
|
|
13895
|
+
}
|
|
13703
13896
|
} catch (_) {}
|
|
13704
13897
|
const results = rank(args.query, index, { topK, cwd, graph, callGraph });
|
|
13705
13898
|
return formatRankTable(results, args.query);
|
|
@@ -14414,7 +14607,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
14414
14607
|
|
|
14415
14608
|
const SERVER_INFO = {
|
|
14416
14609
|
name: 'sigmap',
|
|
14417
|
-
version: '8.
|
|
14610
|
+
version: '8.18.0',
|
|
14418
14611
|
description: 'SigMap MCP server — code signatures on demand',
|
|
14419
14612
|
};
|
|
14420
14613
|
|
|
@@ -15402,7 +15595,10 @@ __factories["./src/retrieval/bm25"] = function(module, exports) {
|
|
|
15402
15595
|
|
|
15403
15596
|
const docs = candidates.map((c) => {
|
|
15404
15597
|
const pathToks = tokenize(c.file || '');
|
|
15405
|
-
|
|
15598
|
+
// Ranking is anchor-invariant: `:start-end` line anchors are metadata,
|
|
15599
|
+
// not content — strip them before tokenizing so adding anchors to an
|
|
15600
|
+
// extractor never shifts BM25 length normalization or token counts.
|
|
15601
|
+
const toks = tokenize((c.sigs || []).map((s) => String(s).replace(/\s*:\d+(?:-\d+)?\s*$/, '')).join(' '));
|
|
15406
15602
|
for (let i = 0; i < PATH_BOOST; i++) toks.push(...pathToks);
|
|
15407
15603
|
const tf = new Map();
|
|
15408
15604
|
for (const t of toks) tf.set(t, (tf.get(t) || 0) + 1);
|
|
@@ -15439,6 +15635,65 @@ __factories["./src/retrieval/bm25"] = function(module, exports) {
|
|
|
15439
15635
|
|
|
15440
15636
|
};
|
|
15441
15637
|
|
|
15638
|
+
// ── ./src/retrieval/enrich-from-maps ──
|
|
15639
|
+
__factories["./src/retrieval/enrich-from-maps"] = function(module, exports) {
|
|
15640
|
+
|
|
15641
|
+
/**
|
|
15642
|
+
* Retrieval surface-enrichment (#488, §7.4 Retrieval ceiling — opt-in via
|
|
15643
|
+
* `retrieval.surfaceEnrichment`, measure-gated).
|
|
15644
|
+
*
|
|
15645
|
+
* The map analyzers extract surfaces (routes) that never reach the rankable
|
|
15646
|
+
* signature index — a query like "payment webhook route" cannot match a
|
|
15647
|
+
* controller whose signatures never mention the route path. This module
|
|
15648
|
+
* appends deterministic pseudo-signatures (`route GET /api/users`) to the
|
|
15649
|
+
* defining file's signature list so the ranker's tokenizer can see them.
|
|
15650
|
+
*
|
|
15651
|
+
* Deterministic: rows are deduped and sorted; entries are copy-on-write so
|
|
15652
|
+
* arrays shared with the signature cache are never mutated.
|
|
15653
|
+
*/
|
|
15654
|
+
|
|
15655
|
+
const path = require('path');
|
|
15656
|
+
|
|
15657
|
+
/**
|
|
15658
|
+
* Enrich a signature index with route pseudo-signatures.
|
|
15659
|
+
* @param {Map<string,string[]>} index cwd-relative file → sigs (mutated: enriched entries are replaced with fresh arrays)
|
|
15660
|
+
* @param {string} cwd
|
|
15661
|
+
* @returns {number} pseudo-signatures added
|
|
15662
|
+
*/
|
|
15663
|
+
function enrichWithSurfaces(index, cwd) {
|
|
15664
|
+
if (!(index instanceof Map) || index.size === 0) return 0;
|
|
15665
|
+
|
|
15666
|
+
let collectRoutes;
|
|
15667
|
+
try { ({ collectRoutes } = __require('./src/map/route-table')); } catch (_) { return 0; }
|
|
15668
|
+
|
|
15669
|
+
const rels = [...index.keys()];
|
|
15670
|
+
const files = rels.map((rel) => path.join(cwd, rel));
|
|
15671
|
+
let routes = [];
|
|
15672
|
+
try { routes = collectRoutes(files, cwd) || []; } catch (_) { return 0; }
|
|
15673
|
+
|
|
15674
|
+
const byFile = new Map();
|
|
15675
|
+
for (const r of routes) {
|
|
15676
|
+
const rel = String(r.file).replace(/\\/g, '/');
|
|
15677
|
+
if (!byFile.has(rel)) byFile.set(rel, new Set());
|
|
15678
|
+
byFile.get(rel).add(`route ${r.method} ${r.path}`);
|
|
15679
|
+
}
|
|
15680
|
+
|
|
15681
|
+
let added = 0;
|
|
15682
|
+
for (const [rel, extras] of [...byFile.entries()].sort()) {
|
|
15683
|
+
const sigs = index.get(rel);
|
|
15684
|
+
if (!sigs) continue;
|
|
15685
|
+
const fresh = [...extras].sort().filter((x) => !sigs.includes(x));
|
|
15686
|
+
if (!fresh.length) continue;
|
|
15687
|
+
index.set(rel, [...sigs, ...fresh]); // copy-on-write: never mutate cached arrays
|
|
15688
|
+
added += fresh.length;
|
|
15689
|
+
}
|
|
15690
|
+
return added;
|
|
15691
|
+
}
|
|
15692
|
+
|
|
15693
|
+
module.exports = { enrichWithSurfaces };
|
|
15694
|
+
|
|
15695
|
+
};
|
|
15696
|
+
|
|
15442
15697
|
// ── ./src/retrieval/ranker ──
|
|
15443
15698
|
__factories["./src/retrieval/ranker"] = function(module, exports) {
|
|
15444
15699
|
|
|
@@ -19455,7 +19710,7 @@ function __tryGit(args, opts = {}) {
|
|
|
19455
19710
|
catch (_) { return ''; }
|
|
19456
19711
|
}
|
|
19457
19712
|
|
|
19458
|
-
const VERSION = '8.
|
|
19713
|
+
const VERSION = '8.18.0';
|
|
19459
19714
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
19460
19715
|
|
|
19461
19716
|
function requireSourceOrBundled(key) {
|
|
@@ -21783,6 +22038,10 @@ function main() {
|
|
|
21783
22038
|
if (config && config.retrieval && config.retrieval.callGraphBoost) {
|
|
21784
22039
|
try { askCallGraph = requireSourceOrBundled('./src/graph/call-graph').buildCallFileGraph(cwd); } catch (_) {}
|
|
21785
22040
|
}
|
|
22041
|
+
// Opt-in route surface-enrichment (retrieval.surfaceEnrichment) — non-fatal
|
|
22042
|
+
if (config && config.retrieval && config.retrieval.surfaceEnrichment) {
|
|
22043
|
+
try { requireSourceOrBundled('./src/retrieval/enrich-from-maps').enrichWithSurfaces(sigIndex, cwd); } catch (_) {}
|
|
22044
|
+
}
|
|
21786
22045
|
|
|
21787
22046
|
let ranked = rank(query, sigIndex, { topK: 5, weights: intentWeights, cwd, callGraph: askCallGraph });
|
|
21788
22047
|
|
|
@@ -23961,6 +24220,10 @@ function main() {
|
|
|
23961
24220
|
if (config && config.retrieval && config.retrieval.callGraphBoost) {
|
|
23962
24221
|
try { queryCallGraph = requireSourceOrBundled('./src/graph/call-graph').buildCallFileGraph(cwd); } catch (_) {}
|
|
23963
24222
|
}
|
|
24223
|
+
// Opt-in route surface-enrichment (retrieval.surfaceEnrichment) — non-fatal
|
|
24224
|
+
if (config && config.retrieval && config.retrieval.surfaceEnrichment) {
|
|
24225
|
+
try { requireSourceOrBundled('./src/retrieval/enrich-from-maps').enrichWithSurfaces(index, cwd); } catch (_) {}
|
|
24226
|
+
}
|
|
23964
24227
|
const results = rank(query, index, { topK, recencyBoost, cwd, callGraph: queryCallGraph });
|
|
23965
24228
|
if (args.includes('--context')) {
|
|
23966
24229
|
const miniCtx = buildMiniContext(results, cwd);
|