sigmap 8.16.1 → 8.17.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 +139 -140
- package/CHANGELOG.md +9 -0
- package/README.md +2 -2
- package/gen-context.js +98 -31
- package/llms-full.txt +2 -2
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/extractors/csharp.js +17 -5
- package/src/extractors/go.js +25 -9
- package/src/extractors/java.js +16 -5
- package/src/extractors/rust.js +38 -10
- package/src/mcp/server.js +1 -1
package/AGENTS.md
CHANGED
|
@@ -33,17 +33,16 @@ Always run `sigmap ask` (or `sigmap --query`) before searching for files relevan
|
|
|
33
33
|
src/extractors/python_ast.py ← ast
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
## changes (last 5 commits —
|
|
36
|
+
## changes (last 5 commits — 1 second ago)
|
|
37
37
|
```
|
|
38
|
+
src/extractors/csharp.js ~extract ~extractMembers
|
|
39
|
+
src/extractors/go.js ~extract ~extractInterfaceMethods
|
|
40
|
+
src/extractors/java.js ~extract ~extractMembers
|
|
41
|
+
src/extractors/rust.js ~extract ~extractMethods ~extractReturnType
|
|
38
42
|
src/evidence/pack.js +riskFactorsFor ~parseAnchor ~buildEvidencePack ~formatMarkdown
|
|
39
|
-
src/graph/call-graph.js +
|
|
40
|
-
src/mcp/handlers.js
|
|
41
|
-
src/mcp/server.js ~dispatch
|
|
42
|
-
src/mcp/tools.js +it
|
|
43
|
+
src/graph/call-graph.js +buildCallFileGraph ~buildCallGraph ~formatCallGraphJSON ~_resolveSymbol
|
|
44
|
+
src/mcp/handlers.js ~queryContext
|
|
43
45
|
src/retrieval/ranker.js ~scoreFile ~rank
|
|
44
|
-
src/graph/blast-radius.js +tierFor +_normRel +_bfs +methodBlastRadius
|
|
45
|
-
src/review/pr-evidence.js ~buildPrEvidence ~formatPrEvidenceMarkdown
|
|
46
|
-
src/review/review-pr.js ~isSource ~reviewPr
|
|
47
46
|
```
|
|
48
47
|
|
|
49
48
|
## packages
|
|
@@ -175,86 +174,43 @@ code-fence ---
|
|
|
175
174
|
|
|
176
175
|
## src
|
|
177
176
|
|
|
178
|
-
### src/
|
|
177
|
+
### src/extractors/csharp.js
|
|
179
178
|
```
|
|
180
|
-
module.exports = {
|
|
179
|
+
module.exports = { extract } :71-71
|
|
180
|
+
function extract(src) → string[] :12-71
|
|
181
|
+
function extractBlock(src, startIndex) :35-44
|
|
182
|
+
function extractMembers(block) :46-59
|
|
183
|
+
function normalizeParams(params) :61-64
|
|
184
|
+
function normalizeType(type) :66-69
|
|
181
185
|
```
|
|
182
186
|
|
|
183
|
-
### src/
|
|
187
|
+
### src/extractors/go.js
|
|
184
188
|
```
|
|
185
|
-
module.exports = {
|
|
186
|
-
function
|
|
187
|
-
function
|
|
188
|
-
function
|
|
189
|
-
function
|
|
190
|
-
function testTargetStem(relPath) → string :126-132
|
|
191
|
-
function findRelatedTests(relPath, allFiles) → string[] :143-154
|
|
192
|
-
function reasonFor(signals) :157-168
|
|
193
|
-
function sigTokens(sigs) :171-173
|
|
194
|
-
function canonicalize(value) → string :180-182
|
|
195
|
-
function sortKeys(value) :184-192
|
|
196
|
-
function buildEvidencePack(query, cwd, opts = {}) → object :205-281
|
|
197
|
-
function ranked0Empty(query) :284-286
|
|
198
|
-
function formatJSON(pack) :289-291
|
|
199
|
-
function formatMarkdown(pack) :294-324
|
|
189
|
+
module.exports = { extract } :81-81
|
|
190
|
+
function extract(src) → string[] :12-81
|
|
191
|
+
function extractBlock(src, startIndex) :51-60
|
|
192
|
+
function extractInterfaceMethods(block) :62-74
|
|
193
|
+
function normalizeParams(params) :76-79
|
|
200
194
|
```
|
|
201
195
|
|
|
202
|
-
### src/
|
|
196
|
+
### src/extractors/java.js
|
|
203
197
|
```
|
|
204
|
-
module.exports = {
|
|
205
|
-
function
|
|
206
|
-
function
|
|
207
|
-
function
|
|
208
|
-
function
|
|
209
|
-
function
|
|
210
|
-
function maskPy(src) :93-110
|
|
211
|
-
function matchDelim(masked, openIdx, open, close) :113-120
|
|
212
|
-
function lineAt(src, idx) :122-127
|
|
213
|
-
function jsDefs(masked) :132-237
|
|
214
|
-
function pyDefs(masked) :200-220
|
|
215
|
-
function goDefs(masked) :224-344
|
|
216
|
-
function javaDefs(masked) :250-367
|
|
217
|
-
function rustDefs(masked) :278-401
|
|
218
|
-
function maskFor(filePath, src) :300-305
|
|
219
|
-
function extractDefs(filePath, src) :307-315
|
|
220
|
-
function callsInRange(masked, start, end) :318-330
|
|
221
|
-
function _walk(dir, excludeSet, out, depth) :334-347
|
|
222
|
-
function buildCallGraph(cwd, opts = {}) → { * forward: Map<string,s :363-446
|
|
223
|
-
function buildCallFileGraph(cwd, opts = {}) → { forward: Map<string,str :459-482
|
|
224
|
-
function _resolveSymbol(symbol, defs) :485-490
|
|
225
|
-
function _bfs(seedIds, graph, maxDepth) :493-506
|
|
226
|
-
function methodImpact(symbol, cwd, opts = {}) → { symbol:string, resolved :516-522
|
|
227
|
-
function methodCallees(symbol, cwd, opts = {}) → { symbol:string, resolved :528-534
|
|
228
|
-
function formatCallGraph(result, kind) :537-549
|
|
229
|
-
… +1 more signatures
|
|
198
|
+
module.exports = { extract } :71-71
|
|
199
|
+
function extract(src) → string[] :12-71
|
|
200
|
+
function extractBlock(src, startIndex) :34-44
|
|
201
|
+
function extractMembers(block) :46-59
|
|
202
|
+
function normalizeParams(params) :61-64
|
|
203
|
+
function normalizeType(type) :66-69
|
|
230
204
|
```
|
|
231
205
|
|
|
232
|
-
### src/
|
|
206
|
+
### src/extractors/rust.js
|
|
233
207
|
```
|
|
234
|
-
module.exports = {
|
|
235
|
-
function
|
|
236
|
-
function
|
|
237
|
-
function
|
|
238
|
-
function
|
|
239
|
-
function
|
|
240
|
-
function getRouting(args, cwd) :224-261
|
|
241
|
-
function explainFile(args, cwd) :269-356
|
|
242
|
-
function listModules(args, cwd) :364-403
|
|
243
|
-
function queryContext(args, cwd) :411-438
|
|
244
|
-
function getMethodImpact(args, cwd) :446-460
|
|
245
|
-
function getImpact(args, cwd) :468-480
|
|
246
|
-
function getLines(args, cwd) :489-537
|
|
247
|
-
function readMemory(args, cwd) :545-580
|
|
248
|
-
function getCalleeSignatures(args, cwd) :589-634
|
|
249
|
-
function _pkgVersion(cwd) :641-644
|
|
250
|
-
function notifyFileCreated(args, cwd) :648-670
|
|
251
|
-
function notifySymbolAdded(args, cwd) :673-693
|
|
252
|
-
function notifyFileDeleted(args, cwd) :696-710
|
|
253
|
-
function _changedFiles(cwd, args) :716-728
|
|
254
|
-
function getDiffContext(args, cwd) :737-808
|
|
255
|
-
function getArchitectureOverview(args, cwd) :817-885
|
|
256
|
-
function verifySuggestion(args, cwd) :895-930
|
|
257
|
-
function squeezeOutput(args, cwd) :940-973
|
|
208
|
+
module.exports = { extract } :110-110
|
|
209
|
+
function extract(src) → string[] :12-110
|
|
210
|
+
function extractBlock(src, startIndex) :72-81
|
|
211
|
+
function extractMethods(block) :83-110
|
|
212
|
+
function normalizeParams(params) :97-100
|
|
213
|
+
function extractReturnType(afterParen) :102-110
|
|
258
214
|
```
|
|
259
215
|
|
|
260
216
|
### src/mcp/server.js
|
|
@@ -266,29 +222,6 @@ function dispatch(msg, cwd) :41-108
|
|
|
266
222
|
function start(cwd) :113-139
|
|
267
223
|
```
|
|
268
224
|
|
|
269
|
-
### src/mcp/tools.js
|
|
270
|
-
```
|
|
271
|
-
module.exports = { TOOLS } :392-392
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### src/retrieval/ranker.js
|
|
275
|
-
```
|
|
276
|
-
module.exports = { rank, buildSigIndex, scoreFile, formatRankTable, formatRankJSON, DEFAULT_WEIGHTS, GRAPH_BOOST_AMOUNTS, detectIntent } :598-598
|
|
277
|
-
function _computePenalty(filePath) :63-70
|
|
278
|
-
function _computeHubs(graph) :73-84
|
|
279
|
-
function _isHub(filePath) :87-91
|
|
280
|
-
function scoreFile(filePath, sigs, queryTokens, weights) → { score: number, signals: :102-159
|
|
281
|
-
function rank(query, sigIndex, opts) → { file: string, score: nu :177-302
|
|
282
|
-
function _parseContextFile(contextPath) → Map<string, string[]> :372-404
|
|
283
|
-
function _mergeSigIndex(target, source) :407-415
|
|
284
|
-
function _buildSigIndexFromCache(cwd) → Map<string, string[]> :422-442
|
|
285
|
-
function _enrichSigIndexFromStrategy(cwd, index) → Map<string, string[]> :450-456
|
|
286
|
-
function buildSigIndex(cwd, opts) → Map<string, string[]> :473-506
|
|
287
|
-
function formatRankTable(results, query) → string :515-551
|
|
288
|
-
function formatRankJSON(results, query) → object :560-575
|
|
289
|
-
function detectIntent(query) :590-596
|
|
290
|
-
```
|
|
291
|
-
|
|
292
225
|
### src/analysis/coverage-score.js
|
|
293
226
|
```
|
|
294
227
|
module.exports = { coverageScore, CODE_EXTS } :105-105
|
|
@@ -326,6 +259,11 @@ function getChangedFiles(files, cache) → { changed: string[], unch :71-88
|
|
|
326
259
|
function updateCacheEntries(cache, extracted) :96-103
|
|
327
260
|
```
|
|
328
261
|
|
|
262
|
+
### src/config/defaults.js
|
|
263
|
+
```
|
|
264
|
+
module.exports = { DEFAULTS } :163-163
|
|
265
|
+
```
|
|
266
|
+
|
|
329
267
|
### src/config/loader.js
|
|
330
268
|
```
|
|
331
269
|
module.exports = { loadConfig, loadBaseConfig } :313-313
|
|
@@ -539,6 +477,25 @@ function scoreUsefulness(taskResult, rankingScore) :11-38
|
|
|
539
477
|
function computeUsefulnessStats(taskResults) :40-66
|
|
540
478
|
```
|
|
541
479
|
|
|
480
|
+
### src/evidence/pack.js
|
|
481
|
+
```
|
|
482
|
+
module.exports = { buildEvidencePack, formatJSON, formatMarkdown, parseAnchor, riskLabelFor, riskFactorsFor, findRelatedTests, SCHEMA_VERSION, SCHEMA_URL, TEST_DISCOVERY } :326-337
|
|
483
|
+
function parseAnchor(sig) → { symbol: string, start: :64-72
|
|
484
|
+
function riskLabelFor(relPath) → 'generated'|'test'|'migra :84-86
|
|
485
|
+
function riskFactorsFor(relPath) → string[] :96-108
|
|
486
|
+
function stemOf(relPath) :111-114
|
|
487
|
+
function testTargetStem(relPath) → string :126-132
|
|
488
|
+
function findRelatedTests(relPath, allFiles) → string[] :143-154
|
|
489
|
+
function reasonFor(signals) :157-168
|
|
490
|
+
function sigTokens(sigs) :171-173
|
|
491
|
+
function canonicalize(value) → string :180-182
|
|
492
|
+
function sortKeys(value) :184-192
|
|
493
|
+
function buildEvidencePack(query, cwd, opts = {}) → object :205-281
|
|
494
|
+
function ranked0Empty(query) :284-286
|
|
495
|
+
function formatJSON(pack) :289-291
|
|
496
|
+
function formatMarkdown(pack) :294-324
|
|
497
|
+
```
|
|
498
|
+
|
|
542
499
|
### src/extractors/coverage.js
|
|
543
500
|
```
|
|
544
501
|
module.exports = { buildTestIndex, isTested } :79-79
|
|
@@ -557,16 +514,6 @@ function normalizeParams(params) :59-62
|
|
|
557
514
|
function normalizeType(type) :64-67
|
|
558
515
|
```
|
|
559
516
|
|
|
560
|
-
### src/extractors/csharp.js
|
|
561
|
-
```
|
|
562
|
-
module.exports = { extract } :59-59
|
|
563
|
-
function extract(src) → string[] :8-59
|
|
564
|
-
function extractBlock(src, startIndex) :27-36
|
|
565
|
-
function extractMembers(block) :38-47
|
|
566
|
-
function normalizeParams(params) :49-52
|
|
567
|
-
function normalizeType(type) :54-57
|
|
568
|
-
```
|
|
569
|
-
|
|
570
517
|
### src/extractors/css.js
|
|
571
518
|
```
|
|
572
519
|
module.exports = { extract } :69-69
|
|
@@ -618,15 +565,6 @@ module.exports = { extract } :2-2
|
|
|
618
565
|
function extract(src) :14-26
|
|
619
566
|
```
|
|
620
567
|
|
|
621
|
-
### src/extractors/go.js
|
|
622
|
-
```
|
|
623
|
-
module.exports = { extract } :65-65
|
|
624
|
-
function extract(src) → string[] :8-65
|
|
625
|
-
function extractBlock(src, startIndex) :39-48
|
|
626
|
-
function extractInterfaceMethods(block) :50-58
|
|
627
|
-
function normalizeParams(params) :60-63
|
|
628
|
-
```
|
|
629
|
-
|
|
630
568
|
### src/extractors/graphql.js
|
|
631
569
|
```
|
|
632
570
|
module.exports = { extract } :66-66
|
|
@@ -639,16 +577,6 @@ module.exports = { extract } :39-39
|
|
|
639
577
|
function extract(src) → string[] :9-37
|
|
640
578
|
```
|
|
641
579
|
|
|
642
|
-
### src/extractors/java.js
|
|
643
|
-
```
|
|
644
|
-
module.exports = { extract } :60-60
|
|
645
|
-
function extract(src) → string[] :8-60
|
|
646
|
-
function extractBlock(src, startIndex) :27-37
|
|
647
|
-
function extractMembers(block) :39-48
|
|
648
|
-
function normalizeParams(params) :50-53
|
|
649
|
-
function normalizeType(type) :55-58
|
|
650
|
-
```
|
|
651
|
-
|
|
652
580
|
### src/extractors/javascript.js
|
|
653
581
|
```
|
|
654
582
|
module.exports = { extract } :147-147
|
|
@@ -781,16 +709,6 @@ function normalizeParams(params) :40-43
|
|
|
781
709
|
function extractReturnHint(stripped, index) :45-52
|
|
782
710
|
```
|
|
783
711
|
|
|
784
|
-
### src/extractors/rust.js
|
|
785
|
-
```
|
|
786
|
-
module.exports = { extract } :82-82
|
|
787
|
-
function extract(src) → string[] :8-82
|
|
788
|
-
function extractBlock(src, startIndex) :48-57
|
|
789
|
-
function extractMethods(block) :59-82
|
|
790
|
-
function normalizeParams(params) :69-72
|
|
791
|
-
function extractReturnType(afterParen) :74-82
|
|
792
|
-
```
|
|
793
|
-
|
|
794
712
|
### src/extractors/scala.js
|
|
795
713
|
```
|
|
796
714
|
module.exports = { extract } :76-76
|
|
@@ -1033,6 +951,36 @@ function build(files, cwd, ctx) → { forward: Map<string,str :387-426
|
|
|
1033
951
|
function buildFromCwd(cwd, opts) → { forward: Map<string,str :438-492
|
|
1034
952
|
```
|
|
1035
953
|
|
|
954
|
+
### src/graph/call-graph.js
|
|
955
|
+
```
|
|
956
|
+
module.exports = { buildCallGraph, buildCallFileGraph, methodImpact, methodCallees, formatCallGraph, formatCallGraphJSON, extractDefs, maskJs, maskPy, maskRust } :563-567
|
|
957
|
+
function normalizePath(p) :41-41
|
|
958
|
+
function toRel(cwd, f) :42-42
|
|
959
|
+
function symId(cwd, absFile, name) :43-43
|
|
960
|
+
function maskJs(src) :49-65
|
|
961
|
+
function maskRust(src) :70-91
|
|
962
|
+
function maskPy(src) :93-110
|
|
963
|
+
function matchDelim(masked, openIdx, open, close) :113-120
|
|
964
|
+
function lineAt(src, idx) :122-127
|
|
965
|
+
function jsDefs(masked) :132-237
|
|
966
|
+
function pyDefs(masked) :200-220
|
|
967
|
+
function goDefs(masked) :224-344
|
|
968
|
+
function javaDefs(masked) :250-367
|
|
969
|
+
function rustDefs(masked) :278-401
|
|
970
|
+
function maskFor(filePath, src) :300-305
|
|
971
|
+
function extractDefs(filePath, src) :307-315
|
|
972
|
+
function callsInRange(masked, start, end) :318-330
|
|
973
|
+
function _walk(dir, excludeSet, out, depth) :334-347
|
|
974
|
+
function buildCallGraph(cwd, opts = {}) → { * forward: Map<string,s :363-446
|
|
975
|
+
function buildCallFileGraph(cwd, opts = {}) → { forward: Map<string,str :459-482
|
|
976
|
+
function _resolveSymbol(symbol, defs) :485-490
|
|
977
|
+
function _bfs(seedIds, graph, maxDepth) :493-506
|
|
978
|
+
function methodImpact(symbol, cwd, opts = {}) → { symbol:string, resolved :516-522
|
|
979
|
+
function methodCallees(symbol, cwd, opts = {}) → { symbol:string, resolved :528-534
|
|
980
|
+
function formatCallGraph(result, kind) :537-549
|
|
981
|
+
… +1 more signatures
|
|
982
|
+
```
|
|
983
|
+
|
|
1036
984
|
### src/graph/impact.js
|
|
1037
985
|
```
|
|
1038
986
|
module.exports = { getImpact, analyzeImpact, formatImpact, formatImpactJSON } :240-240
|
|
@@ -1147,6 +1095,34 @@ function shouldSkipFile(rel) :18-21
|
|
|
1147
1095
|
function analyze(files, cwd) :23-125
|
|
1148
1096
|
```
|
|
1149
1097
|
|
|
1098
|
+
### src/mcp/handlers.js
|
|
1099
|
+
```
|
|
1100
|
+
module.exports = { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getMethodImpact, getImpact, getLines, readMemory, getCalleeSignatures, notifyFileCreated, notifySymbolAdded, notifyFileDeleted, getDiffContext, getArchitectureOverview, verifySuggestion, squeezeOutput } :975-975
|
|
1101
|
+
function _readContextFiles(cwd) :10-17
|
|
1102
|
+
function readContext(args, cwd) :36-66
|
|
1103
|
+
function searchSignatures(args, cwd) :74-100
|
|
1104
|
+
function getMap(args, cwd) :108-131
|
|
1105
|
+
function createCheckpoint(args, cwd) :143-215
|
|
1106
|
+
function getRouting(args, cwd) :224-261
|
|
1107
|
+
function explainFile(args, cwd) :269-356
|
|
1108
|
+
function listModules(args, cwd) :364-403
|
|
1109
|
+
function queryContext(args, cwd) :411-438
|
|
1110
|
+
function getMethodImpact(args, cwd) :446-460
|
|
1111
|
+
function getImpact(args, cwd) :468-480
|
|
1112
|
+
function getLines(args, cwd) :489-537
|
|
1113
|
+
function readMemory(args, cwd) :545-580
|
|
1114
|
+
function getCalleeSignatures(args, cwd) :589-634
|
|
1115
|
+
function _pkgVersion(cwd) :641-644
|
|
1116
|
+
function notifyFileCreated(args, cwd) :648-670
|
|
1117
|
+
function notifySymbolAdded(args, cwd) :673-693
|
|
1118
|
+
function notifyFileDeleted(args, cwd) :696-710
|
|
1119
|
+
function _changedFiles(cwd, args) :716-728
|
|
1120
|
+
function getDiffContext(args, cwd) :737-808
|
|
1121
|
+
function getArchitectureOverview(args, cwd) :817-885
|
|
1122
|
+
function verifySuggestion(args, cwd) :895-930
|
|
1123
|
+
function squeezeOutput(args, cwd) :940-973
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1150
1126
|
### src/mcp/install.js
|
|
1151
1127
|
```
|
|
1152
1128
|
module.exports = { CLIENTS, listClients, installClient, resolveTarget } :142-142
|
|
@@ -1159,6 +1135,11 @@ function _installYaml(filePath, scriptPath) :99-117
|
|
|
1159
1135
|
function installClient(client, opts = {}) → client, label, path, stat :124-140
|
|
1160
1136
|
```
|
|
1161
1137
|
|
|
1138
|
+
### src/mcp/tools.js
|
|
1139
|
+
```
|
|
1140
|
+
module.exports = { TOOLS } :392-392
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1162
1143
|
### src/nudge.js
|
|
1163
1144
|
```
|
|
1164
1145
|
module.exports = { checkStarNudge, readUsage, usagePath, showStarNudge, RUN_THRESHOLD, SUCCESS_THRESHOLD } :92-92
|
|
@@ -1192,6 +1173,24 @@ function expandQuery(qToks) → Map<string, number> :132-141
|
|
|
1192
1173
|
function bm25rank(query, candidates) → Array<object & { score: n :154-193
|
|
1193
1174
|
```
|
|
1194
1175
|
|
|
1176
|
+
### src/retrieval/ranker.js
|
|
1177
|
+
```
|
|
1178
|
+
module.exports = { rank, buildSigIndex, scoreFile, formatRankTable, formatRankJSON, DEFAULT_WEIGHTS, GRAPH_BOOST_AMOUNTS, detectIntent } :598-598
|
|
1179
|
+
function _computePenalty(filePath) :63-70
|
|
1180
|
+
function _computeHubs(graph) :73-84
|
|
1181
|
+
function _isHub(filePath) :87-91
|
|
1182
|
+
function scoreFile(filePath, sigs, queryTokens, weights) → { score: number, signals: :102-159
|
|
1183
|
+
function rank(query, sigIndex, opts) → { file: string, score: nu :177-302
|
|
1184
|
+
function _parseContextFile(contextPath) → Map<string, string[]> :372-404
|
|
1185
|
+
function _mergeSigIndex(target, source) :407-415
|
|
1186
|
+
function _buildSigIndexFromCache(cwd) → Map<string, string[]> :422-442
|
|
1187
|
+
function _enrichSigIndexFromStrategy(cwd, index) → Map<string, string[]> :450-456
|
|
1188
|
+
function buildSigIndex(cwd, opts) → Map<string, string[]> :473-506
|
|
1189
|
+
function formatRankTable(results, query) → string :515-551
|
|
1190
|
+
function formatRankJSON(results, query) → object :560-575
|
|
1191
|
+
function detectIntent(query) :590-596
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1195
1194
|
### src/retrieval/tokenizer.js
|
|
1196
1195
|
```
|
|
1197
1196
|
module.exports = { tokenize, STOP_WORDS } :54-54
|
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,15 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [8.17.0] — 2026-07-12
|
|
14
|
+
|
|
15
|
+
Minor release — **line anchors for Java, Go, Rust, and C#** (§7.4 Lang ceiling, the roadmap's long-named "anchors for the remaining extractors" item).
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Extractor line anchors for Java/Go/Rust/C# (#483, PR #484):** signatures from these languages now carry `:start-end` anchors — types/functions with bodies get real brace-matched ranges, single-line members get `:n-n`, Rust bodyless items (unit structs, trait declarations) get single-line anchors. Prerequisite fix folded in: the four extractors' comment strips are now **newline-preserving** (block comments previously collapsed outright, making true line numbers impossible — regression-tested with a multi-line license header above declarations). Downstream, verified: Evidence Pack `anchorCoverage` goes **0 → 1.0** on Go/Java fixtures with populated `sourceLines`, and `get_lines` (Surgical Context) works on all four languages. Expected extractor fixtures regenerated; `parseAnchor` round-trips every emitted anchor.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
13
22
|
## [8.16.1] — 2026-07-12
|
|
14
23
|
|
|
15
24
|
Patch release — **benchmark hygiene**; the published package is unchanged (scripts + tests only).
|
package/README.md
CHANGED
|
@@ -122,8 +122,8 @@ Ask → Rank → Context → Validate → Judge → Learn
|
|
|
122
122
|
|
|
123
123
|
<!--SM:benchmarkBlock-->
|
|
124
124
|
```
|
|
125
|
-
Benchmark : sigmap-v8.
|
|
126
|
-
Date : 2026-07-
|
|
125
|
+
Benchmark : sigmap-v8.17-main (21 repositories, including R language)
|
|
126
|
+
Date : 2026-07-12
|
|
127
127
|
|
|
128
128
|
Hit@5 : 87.8% (baseline 13.6% — 6.5× lift)
|
|
129
129
|
Token reduction: 97.0% (across 21 repos)
|
package/gen-context.js
CHANGED
|
@@ -5229,8 +5229,12 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
|
|
|
5229
5229
|
// ── ./src/extractors/csharp ──
|
|
5230
5230
|
__factories["./src/extractors/csharp"] = function(module, exports) {
|
|
5231
5231
|
|
|
5232
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
5233
|
+
|
|
5232
5234
|
/**
|
|
5233
5235
|
* Extract signatures from C# source code.
|
|
5236
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
5237
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5234
5238
|
* @param {string} src - Raw file content
|
|
5235
5239
|
* @returns {string[]} Array of signature strings
|
|
5236
5240
|
*/
|
|
@@ -5240,14 +5244,18 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
|
|
|
5240
5244
|
|
|
5241
5245
|
const stripped = src
|
|
5242
5246
|
.replace(/\/\/.*$/gm, '')
|
|
5243
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
5247
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
5244
5248
|
|
|
5245
5249
|
// Classes and interfaces
|
|
5246
5250
|
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
5251
|
for (const m of stripped.matchAll(typeRe)) {
|
|
5248
|
-
|
|
5249
|
-
const
|
|
5250
|
-
|
|
5252
|
+
const declIdx = m.index + (m[0].length - m[0].trimStart().length);
|
|
5253
|
+
const bodyStart = m.index + m[0].length;
|
|
5254
|
+
const block = extractBlock(stripped, bodyStart);
|
|
5255
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, declIdx), lineAt(stripped, bodyStart + block.length)));
|
|
5256
|
+
for (const meth of extractMembers(block)) {
|
|
5257
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
5258
|
+
}
|
|
5251
5259
|
}
|
|
5252
5260
|
|
|
5253
5261
|
return sigs.slice(0, 25);
|
|
@@ -5270,7 +5278,11 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
|
|
|
5270
5278
|
for (const m of block.matchAll(methodRe)) {
|
|
5271
5279
|
const ret = normalizeType(m[1]);
|
|
5272
5280
|
const retStr = ret ? ` → ${ret}` : '';
|
|
5273
|
-
members.push(
|
|
5281
|
+
members.push({
|
|
5282
|
+
text: `${m[2]}(${normalizeParams(m[3])})${retStr}`,
|
|
5283
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
5284
|
+
endIdx: m.index + m[0].length,
|
|
5285
|
+
});
|
|
5274
5286
|
}
|
|
5275
5287
|
return members.slice(0, 8);
|
|
5276
5288
|
}
|
|
@@ -5878,8 +5890,12 @@ __factories["./src/extractors/generic"] = function(module, exports) {
|
|
|
5878
5890
|
// ── ./src/extractors/go ──
|
|
5879
5891
|
__factories["./src/extractors/go"] = function(module, exports) {
|
|
5880
5892
|
|
|
5893
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
5894
|
+
|
|
5881
5895
|
/**
|
|
5882
5896
|
* Extract signatures from Go source code.
|
|
5897
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
5898
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5883
5899
|
* @param {string} src - Raw file content
|
|
5884
5900
|
* @returns {string[]} Array of signature strings
|
|
5885
5901
|
*/
|
|
@@ -5889,26 +5905,34 @@ __factories["./src/extractors/go"] = function(module, exports) {
|
|
|
5889
5905
|
|
|
5890
5906
|
const stripped = src
|
|
5891
5907
|
.replace(/\/\/.*$/gm, '')
|
|
5892
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
5908
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
5909
|
+
|
|
5910
|
+
// Index of the closing brace for a block opened just before startIndex.
|
|
5911
|
+
const blockEndIdx = (startIndex) => startIndex + extractBlock(stripped, startIndex).length;
|
|
5893
5912
|
|
|
5894
5913
|
// Structs
|
|
5895
5914
|
for (const m of stripped.matchAll(/^type\s+(\w+)\s+struct\s*\{/gm)) {
|
|
5896
|
-
|
|
5915
|
+
const end = blockEndIdx(m.index + m[0].length);
|
|
5916
|
+
sigs.push(withAnchor(`type ${m[1]} struct`, lineAt(stripped, m.index), lineAt(stripped, end)));
|
|
5897
5917
|
}
|
|
5898
5918
|
|
|
5899
5919
|
// Interfaces
|
|
5900
5920
|
for (const m of stripped.matchAll(/^type\s+(\w+)\s+interface\s*\{/gm)) {
|
|
5901
|
-
|
|
5902
|
-
const block = extractBlock(stripped,
|
|
5903
|
-
|
|
5921
|
+
const bodyStart = m.index + m[0].length;
|
|
5922
|
+
const block = extractBlock(stripped, bodyStart);
|
|
5923
|
+
sigs.push(withAnchor(`type ${m[1]} interface`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
5924
|
+
for (const meth of extractInterfaceMethods(block)) {
|
|
5925
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
5926
|
+
}
|
|
5904
5927
|
}
|
|
5905
5928
|
|
|
5906
5929
|
// Functions and methods — capture return type between ) and {
|
|
5907
5930
|
for (const m of stripped.matchAll(/^func\s+(?:\((\w+)\s+[\w*]+\)\s+)?(\w+)\s*\(([^)]*)\)([^{]*)\{/gm)) {
|
|
5908
5931
|
const receiver = m[1] ? `(${m[1]}) ` : '';
|
|
5909
5932
|
const retType = m[4] ? m[4].trim().replace(/\s+/g, ' ') : '';
|
|
5910
|
-
const retStr = retType ? `
|
|
5911
|
-
|
|
5933
|
+
const retStr = retType ? ` → ${retType.slice(0, 30)}` : '';
|
|
5934
|
+
const end = blockEndIdx(m.index + m[0].length);
|
|
5935
|
+
sigs.push(withAnchor(`func ${receiver}${m[2]}(${normalizeParams(m[3])})${retStr}`, lineAt(stripped, m.index), lineAt(stripped, end)));
|
|
5912
5936
|
}
|
|
5913
5937
|
|
|
5914
5938
|
return sigs.slice(0, 25);
|
|
@@ -5929,8 +5953,12 @@ __factories["./src/extractors/go"] = function(module, exports) {
|
|
|
5929
5953
|
const methods = [];
|
|
5930
5954
|
for (const m of block.matchAll(/^\s+(\w+)\s*\(([^)]*)\)([^\n]*)/gm)) {
|
|
5931
5955
|
const retType = m[3] ? m[3].trim().replace(/\s+/g, ' ') : '';
|
|
5932
|
-
const retStr = retType ? `
|
|
5933
|
-
methods.push(
|
|
5956
|
+
const retStr = retType ? ` → ${retType.slice(0, 30)}` : '';
|
|
5957
|
+
methods.push({
|
|
5958
|
+
text: `${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
5959
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
5960
|
+
endIdx: m.index + m[0].length,
|
|
5961
|
+
});
|
|
5934
5962
|
}
|
|
5935
5963
|
return methods.slice(0, 8);
|
|
5936
5964
|
}
|
|
@@ -6060,8 +6088,12 @@ __factories["./src/extractors/html"] = function(module, exports) {
|
|
|
6060
6088
|
// ── ./src/extractors/java ──
|
|
6061
6089
|
__factories["./src/extractors/java"] = function(module, exports) {
|
|
6062
6090
|
|
|
6091
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
6092
|
+
|
|
6063
6093
|
/**
|
|
6064
6094
|
* Extract signatures from Java source code.
|
|
6095
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
6096
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
6065
6097
|
* @param {string} src - Raw file content
|
|
6066
6098
|
* @returns {string[]} Array of signature strings
|
|
6067
6099
|
*/
|
|
@@ -6071,14 +6103,17 @@ __factories["./src/extractors/java"] = function(module, exports) {
|
|
|
6071
6103
|
|
|
6072
6104
|
const stripped = src
|
|
6073
6105
|
.replace(/\/\/.*$/gm, '')
|
|
6074
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
6106
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
6075
6107
|
|
|
6076
6108
|
// Classes and interfaces
|
|
6077
6109
|
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
6110
|
for (const m of stripped.matchAll(typeRegex)) {
|
|
6079
|
-
|
|
6080
|
-
const block = extractBlock(stripped,
|
|
6081
|
-
|
|
6111
|
+
const bodyStart = m.index + m[0].length;
|
|
6112
|
+
const block = extractBlock(stripped, bodyStart);
|
|
6113
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
6114
|
+
for (const meth of extractMembers(block)) {
|
|
6115
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
6116
|
+
}
|
|
6082
6117
|
}
|
|
6083
6118
|
|
|
6084
6119
|
return sigs.slice(0, 25);
|
|
@@ -6102,7 +6137,11 @@ __factories["./src/extractors/java"] = function(module, exports) {
|
|
|
6102
6137
|
for (const m of block.matchAll(methodRe)) {
|
|
6103
6138
|
const ret = normalizeType(m[1]);
|
|
6104
6139
|
const retStr = ret ? ` → ${ret}` : '';
|
|
6105
|
-
members.push(
|
|
6140
|
+
members.push({
|
|
6141
|
+
text: `${m[2]}(${normalizeParams(m[3])})${retStr}`,
|
|
6142
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
6143
|
+
endIdx: m.index + m[0].length,
|
|
6144
|
+
});
|
|
6106
6145
|
}
|
|
6107
6146
|
return members.slice(0, 8);
|
|
6108
6147
|
}
|
|
@@ -7513,8 +7552,12 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
|
|
|
7513
7552
|
// ── ./src/extractors/rust ──
|
|
7514
7553
|
__factories["./src/extractors/rust"] = function(module, exports) {
|
|
7515
7554
|
|
|
7555
|
+
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
7556
|
+
|
|
7516
7557
|
/**
|
|
7517
7558
|
* Extract signatures from Rust source code.
|
|
7559
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
7560
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
7518
7561
|
* @param {string} src - Raw file content
|
|
7519
7562
|
* @returns {string[]} Array of signature strings
|
|
7520
7563
|
*/
|
|
@@ -7524,35 +7567,55 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
7524
7567
|
|
|
7525
7568
|
const stripped = src
|
|
7526
7569
|
.replace(/\/\/.*$/gm, '')
|
|
7527
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
7570
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
7571
|
+
|
|
7572
|
+
// Anchor range for a declaration at declIdx whose header ends at afterIdx:
|
|
7573
|
+
// if a `{` body follows, range to its closing brace; else single-line.
|
|
7574
|
+
const rangeFor = (declIdx, afterIdx) => {
|
|
7575
|
+
let k = afterIdx;
|
|
7576
|
+
while (k < stripped.length && /[ \t]/.test(stripped[k])) k++;
|
|
7577
|
+
if (stripped[k] === '{') {
|
|
7578
|
+
const end = k + 1 + extractBlock(stripped, k + 1).length;
|
|
7579
|
+
return [lineAt(stripped, declIdx), lineAt(stripped, end)];
|
|
7580
|
+
}
|
|
7581
|
+
const line = lineAt(stripped, declIdx);
|
|
7582
|
+
return [line, line];
|
|
7583
|
+
};
|
|
7528
7584
|
|
|
7529
7585
|
// Structs
|
|
7530
7586
|
for (const m of stripped.matchAll(/^pub\s+struct\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
7531
|
-
|
|
7587
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7588
|
+
sigs.push(withAnchor(`pub struct ${m[1]}`, s, e));
|
|
7532
7589
|
}
|
|
7533
7590
|
|
|
7534
7591
|
// Enums
|
|
7535
7592
|
for (const m of stripped.matchAll(/^pub\s+enum\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
7536
|
-
|
|
7593
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7594
|
+
sigs.push(withAnchor(`pub enum ${m[1]}`, s, e));
|
|
7537
7595
|
}
|
|
7538
7596
|
|
|
7539
7597
|
// Traits
|
|
7540
7598
|
for (const m of stripped.matchAll(/^pub\s+trait\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
7541
|
-
|
|
7599
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7600
|
+
sigs.push(withAnchor(`pub trait ${m[1]}`, s, e));
|
|
7542
7601
|
}
|
|
7543
7602
|
|
|
7544
7603
|
// impl blocks
|
|
7545
7604
|
for (const m of stripped.matchAll(/^impl(?:<[^>]*>)?\s+(?:[\w:]+\s+for\s+)?(\w+)(?:<[^{]*>)?\s*\{/gm)) {
|
|
7546
|
-
|
|
7547
|
-
const block = extractBlock(stripped,
|
|
7548
|
-
|
|
7605
|
+
const bodyStart = m.index + m[0].length;
|
|
7606
|
+
const block = extractBlock(stripped, bodyStart);
|
|
7607
|
+
sigs.push(withAnchor(`impl ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
7608
|
+
for (const fn of extractMethods(block)) {
|
|
7609
|
+
sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)));
|
|
7610
|
+
}
|
|
7549
7611
|
}
|
|
7550
7612
|
|
|
7551
7613
|
// Top-level pub fns — capture everything after ) up to { or ; for return type
|
|
7552
7614
|
for (const m of stripped.matchAll(/^pub(?:\s+async)?\s+fn\s+(\w+)(?:<[^(]*>)?\s*\(([^)]*)\)([^{;]*)/gm)) {
|
|
7553
7615
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
7554
7616
|
const retStr = extractReturnType(m[3]);
|
|
7555
|
-
|
|
7617
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
7618
|
+
sigs.push(withAnchor(`pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
7556
7619
|
}
|
|
7557
7620
|
|
|
7558
7621
|
return sigs.slice(0, 25);
|
|
@@ -7574,7 +7637,11 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
7574
7637
|
for (const m of block.matchAll(/^\s+pub(?:\s+async)?\s+fn\s+(\w+)(?:<[^(]*>)?\s*\(([^)]*)\)([^{;]*)/gm)) {
|
|
7575
7638
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
7576
7639
|
const retStr = extractReturnType(m[3]);
|
|
7577
|
-
methods.push(
|
|
7640
|
+
methods.push({
|
|
7641
|
+
text: `pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
7642
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
7643
|
+
endIdx: m.index + m[0].length,
|
|
7644
|
+
});
|
|
7578
7645
|
}
|
|
7579
7646
|
return methods.slice(0, 8);
|
|
7580
7647
|
}
|
|
@@ -7589,7 +7656,7 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
7589
7656
|
const m = afterParen.match(/->\s*([^{;]+)/);
|
|
7590
7657
|
if (!m) return '';
|
|
7591
7658
|
const rt = m[1].trim().replace(/\s+/g, ' ');
|
|
7592
|
-
return `
|
|
7659
|
+
return ` → ${rt.length > 30 ? rt.slice(0, 27) + '...' : rt}`;
|
|
7593
7660
|
}
|
|
7594
7661
|
|
|
7595
7662
|
module.exports = { extract };
|
|
@@ -14414,7 +14481,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
14414
14481
|
|
|
14415
14482
|
const SERVER_INFO = {
|
|
14416
14483
|
name: 'sigmap',
|
|
14417
|
-
version: '8.
|
|
14484
|
+
version: '8.17.0',
|
|
14418
14485
|
description: 'SigMap MCP server — code signatures on demand',
|
|
14419
14486
|
};
|
|
14420
14487
|
|
|
@@ -19455,7 +19522,7 @@ function __tryGit(args, opts = {}) {
|
|
|
19455
19522
|
catch (_) { return ''; }
|
|
19456
19523
|
}
|
|
19457
19524
|
|
|
19458
|
-
const VERSION = '8.
|
|
19525
|
+
const VERSION = '8.17.0';
|
|
19459
19526
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
19460
19527
|
|
|
19461
19528
|
function requireSourceOrBundled(key) {
|
package/llms-full.txt
CHANGED
|
@@ -11,13 +11,13 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.17.0 | Benchmark: sigmap-v8.17-main (2026-07-12)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
20
|
+
## Core metrics (benchmark: sigmap-v8.17-main, 2026-07-12)
|
|
21
21
|
|
|
22
22
|
| Metric | Without SigMap | With SigMap |
|
|
23
23
|
|--------|----------------|-------------|
|
package/llms.txt
CHANGED
|
@@ -11,7 +11,7 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.17.0 | Benchmark: sigmap-v8.17-main (2026-07-12)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
@@ -23,7 +23,7 @@ Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
|
23
23
|
- No blast-radius awareness before editing a hub file — `--impact` shows every file a change touches.
|
|
24
24
|
- Pasted stack traces, CI logs, and JSON bloat the prompt — `squeeze` minimizes them and enriches the top frame from the symbol index.
|
|
25
25
|
|
|
26
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
26
|
+
## Core metrics (benchmark: sigmap-v8.17-main, 2026-07-12)
|
|
27
27
|
|
|
28
28
|
- hit@5 retrieval: 87.8% vs 13.6% random baseline (6.5× lift)
|
|
29
29
|
- Token reduction: 97.0% average across benchmark repos
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigmap",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.17.0",
|
|
4
4
|
"description": "The deterministic, verifiable grounding layer for AI code work — a zero-dependency signature-and-evidence map that grounds Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP agents against your real code (repo + installed libraries) so they stop hallucinating files, imports & APIs. Runs offline via npx; byte-stable output; ~97% token reduction as proof.",
|
|
5
5
|
"main": "packages/core/index.js",
|
|
6
6
|
"exports": {
|
package/src/extractors/csharp.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { lineAt, withAnchor } = require('./line-anchor');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Extract signatures from C# source code.
|
|
7
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
8
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5
9
|
* @param {string} src - Raw file content
|
|
6
10
|
* @returns {string[]} Array of signature strings
|
|
7
11
|
*/
|
|
@@ -11,14 +15,18 @@ function extract(src) {
|
|
|
11
15
|
|
|
12
16
|
const stripped = src
|
|
13
17
|
.replace(/\/\/.*$/gm, '')
|
|
14
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
18
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
15
19
|
|
|
16
20
|
// Classes and interfaces
|
|
17
21
|
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;
|
|
18
22
|
for (const m of stripped.matchAll(typeRe)) {
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
23
|
+
const declIdx = m.index + (m[0].length - m[0].trimStart().length);
|
|
24
|
+
const bodyStart = m.index + m[0].length;
|
|
25
|
+
const block = extractBlock(stripped, bodyStart);
|
|
26
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, declIdx), lineAt(stripped, bodyStart + block.length)));
|
|
27
|
+
for (const meth of extractMembers(block)) {
|
|
28
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
29
|
+
}
|
|
22
30
|
}
|
|
23
31
|
|
|
24
32
|
return sigs.slice(0, 25);
|
|
@@ -41,7 +49,11 @@ function extractMembers(block) {
|
|
|
41
49
|
for (const m of block.matchAll(methodRe)) {
|
|
42
50
|
const ret = normalizeType(m[1]);
|
|
43
51
|
const retStr = ret ? ` → ${ret}` : '';
|
|
44
|
-
members.push(
|
|
52
|
+
members.push({
|
|
53
|
+
text: `${m[2]}(${normalizeParams(m[3])})${retStr}`,
|
|
54
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
55
|
+
endIdx: m.index + m[0].length,
|
|
56
|
+
});
|
|
45
57
|
}
|
|
46
58
|
return members.slice(0, 8);
|
|
47
59
|
}
|
package/src/extractors/go.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { lineAt, withAnchor } = require('./line-anchor');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Extract signatures from Go source code.
|
|
7
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
8
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5
9
|
* @param {string} src - Raw file content
|
|
6
10
|
* @returns {string[]} Array of signature strings
|
|
7
11
|
*/
|
|
@@ -11,26 +15,34 @@ function extract(src) {
|
|
|
11
15
|
|
|
12
16
|
const stripped = src
|
|
13
17
|
.replace(/\/\/.*$/gm, '')
|
|
14
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
18
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
19
|
+
|
|
20
|
+
// Index of the closing brace for a block opened just before startIndex.
|
|
21
|
+
const blockEndIdx = (startIndex) => startIndex + extractBlock(stripped, startIndex).length;
|
|
15
22
|
|
|
16
23
|
// Structs
|
|
17
24
|
for (const m of stripped.matchAll(/^type\s+(\w+)\s+struct\s*\{/gm)) {
|
|
18
|
-
|
|
25
|
+
const end = blockEndIdx(m.index + m[0].length);
|
|
26
|
+
sigs.push(withAnchor(`type ${m[1]} struct`, lineAt(stripped, m.index), lineAt(stripped, end)));
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
// Interfaces
|
|
22
30
|
for (const m of stripped.matchAll(/^type\s+(\w+)\s+interface\s*\{/gm)) {
|
|
23
|
-
|
|
24
|
-
const block = extractBlock(stripped,
|
|
25
|
-
|
|
31
|
+
const bodyStart = m.index + m[0].length;
|
|
32
|
+
const block = extractBlock(stripped, bodyStart);
|
|
33
|
+
sigs.push(withAnchor(`type ${m[1]} interface`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
34
|
+
for (const meth of extractInterfaceMethods(block)) {
|
|
35
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
36
|
+
}
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
// Functions and methods — capture return type between ) and {
|
|
29
40
|
for (const m of stripped.matchAll(/^func\s+(?:\((\w+)\s+[\w*]+\)\s+)?(\w+)\s*\(([^)]*)\)([^{]*)\{/gm)) {
|
|
30
41
|
const receiver = m[1] ? `(${m[1]}) ` : '';
|
|
31
42
|
const retType = m[4] ? m[4].trim().replace(/\s+/g, ' ') : '';
|
|
32
|
-
const retStr = retType ? `
|
|
33
|
-
|
|
43
|
+
const retStr = retType ? ` → ${retType.slice(0, 30)}` : '';
|
|
44
|
+
const end = blockEndIdx(m.index + m[0].length);
|
|
45
|
+
sigs.push(withAnchor(`func ${receiver}${m[2]}(${normalizeParams(m[3])})${retStr}`, lineAt(stripped, m.index), lineAt(stripped, end)));
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
return sigs.slice(0, 25);
|
|
@@ -51,8 +63,12 @@ function extractInterfaceMethods(block) {
|
|
|
51
63
|
const methods = [];
|
|
52
64
|
for (const m of block.matchAll(/^\s+(\w+)\s*\(([^)]*)\)([^\n]*)/gm)) {
|
|
53
65
|
const retType = m[3] ? m[3].trim().replace(/\s+/g, ' ') : '';
|
|
54
|
-
const retStr = retType ? `
|
|
55
|
-
methods.push(
|
|
66
|
+
const retStr = retType ? ` → ${retType.slice(0, 30)}` : '';
|
|
67
|
+
methods.push({
|
|
68
|
+
text: `${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
69
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
70
|
+
endIdx: m.index + m[0].length,
|
|
71
|
+
});
|
|
56
72
|
}
|
|
57
73
|
return methods.slice(0, 8);
|
|
58
74
|
}
|
package/src/extractors/java.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { lineAt, withAnchor } = require('./line-anchor');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Extract signatures from Java source code.
|
|
7
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
8
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5
9
|
* @param {string} src - Raw file content
|
|
6
10
|
* @returns {string[]} Array of signature strings
|
|
7
11
|
*/
|
|
@@ -11,14 +15,17 @@ function extract(src) {
|
|
|
11
15
|
|
|
12
16
|
const stripped = src
|
|
13
17
|
.replace(/\/\/.*$/gm, '')
|
|
14
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
18
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
15
19
|
|
|
16
20
|
// Classes and interfaces
|
|
17
21
|
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;
|
|
18
22
|
for (const m of stripped.matchAll(typeRegex)) {
|
|
19
|
-
|
|
20
|
-
const block = extractBlock(stripped,
|
|
21
|
-
|
|
23
|
+
const bodyStart = m.index + m[0].length;
|
|
24
|
+
const block = extractBlock(stripped, bodyStart);
|
|
25
|
+
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
26
|
+
for (const meth of extractMembers(block)) {
|
|
27
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
28
|
+
}
|
|
22
29
|
}
|
|
23
30
|
|
|
24
31
|
return sigs.slice(0, 25);
|
|
@@ -42,7 +49,11 @@ function extractMembers(block) {
|
|
|
42
49
|
for (const m of block.matchAll(methodRe)) {
|
|
43
50
|
const ret = normalizeType(m[1]);
|
|
44
51
|
const retStr = ret ? ` → ${ret}` : '';
|
|
45
|
-
members.push(
|
|
52
|
+
members.push({
|
|
53
|
+
text: `${m[2]}(${normalizeParams(m[3])})${retStr}`,
|
|
54
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
55
|
+
endIdx: m.index + m[0].length,
|
|
56
|
+
});
|
|
46
57
|
}
|
|
47
58
|
return members.slice(0, 8);
|
|
48
59
|
}
|
package/src/extractors/rust.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { lineAt, withAnchor } = require('./line-anchor');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Extract signatures from Rust source code.
|
|
7
|
+
* Signatures carry `:start-end` line anchors (Surgical Context); the comment
|
|
8
|
+
* strip below is newline-preserving so anchor lines match the original file.
|
|
5
9
|
* @param {string} src - Raw file content
|
|
6
10
|
* @returns {string[]} Array of signature strings
|
|
7
11
|
*/
|
|
@@ -11,35 +15,55 @@ function extract(src) {
|
|
|
11
15
|
|
|
12
16
|
const stripped = src
|
|
13
17
|
.replace(/\/\/.*$/gm, '')
|
|
14
|
-
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
18
|
+
.replace(/\/\*[\s\S]*?\*\//g, (s) => s.replace(/[^\n]/g, ' '));
|
|
19
|
+
|
|
20
|
+
// Anchor range for a declaration at declIdx whose header ends at afterIdx:
|
|
21
|
+
// if a `{` body follows, range to its closing brace; else single-line.
|
|
22
|
+
const rangeFor = (declIdx, afterIdx) => {
|
|
23
|
+
let k = afterIdx;
|
|
24
|
+
while (k < stripped.length && /[ \t]/.test(stripped[k])) k++;
|
|
25
|
+
if (stripped[k] === '{') {
|
|
26
|
+
const end = k + 1 + extractBlock(stripped, k + 1).length;
|
|
27
|
+
return [lineAt(stripped, declIdx), lineAt(stripped, end)];
|
|
28
|
+
}
|
|
29
|
+
const line = lineAt(stripped, declIdx);
|
|
30
|
+
return [line, line];
|
|
31
|
+
};
|
|
15
32
|
|
|
16
33
|
// Structs
|
|
17
34
|
for (const m of stripped.matchAll(/^pub\s+struct\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
18
|
-
|
|
35
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
36
|
+
sigs.push(withAnchor(`pub struct ${m[1]}`, s, e));
|
|
19
37
|
}
|
|
20
38
|
|
|
21
39
|
// Enums
|
|
22
40
|
for (const m of stripped.matchAll(/^pub\s+enum\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
23
|
-
|
|
41
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
42
|
+
sigs.push(withAnchor(`pub enum ${m[1]}`, s, e));
|
|
24
43
|
}
|
|
25
44
|
|
|
26
45
|
// Traits
|
|
27
46
|
for (const m of stripped.matchAll(/^pub\s+trait\s+(\w+)(?:<[^{]*>)?/gm)) {
|
|
28
|
-
|
|
47
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
48
|
+
sigs.push(withAnchor(`pub trait ${m[1]}`, s, e));
|
|
29
49
|
}
|
|
30
50
|
|
|
31
51
|
// impl blocks
|
|
32
52
|
for (const m of stripped.matchAll(/^impl(?:<[^>]*>)?\s+(?:[\w:]+\s+for\s+)?(\w+)(?:<[^{]*>)?\s*\{/gm)) {
|
|
33
|
-
|
|
34
|
-
const block = extractBlock(stripped,
|
|
35
|
-
|
|
53
|
+
const bodyStart = m.index + m[0].length;
|
|
54
|
+
const block = extractBlock(stripped, bodyStart);
|
|
55
|
+
sigs.push(withAnchor(`impl ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
56
|
+
for (const fn of extractMethods(block)) {
|
|
57
|
+
sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)));
|
|
58
|
+
}
|
|
36
59
|
}
|
|
37
60
|
|
|
38
61
|
// Top-level pub fns — capture everything after ) up to { or ; for return type
|
|
39
62
|
for (const m of stripped.matchAll(/^pub(?:\s+async)?\s+fn\s+(\w+)(?:<[^(]*>)?\s*\(([^)]*)\)([^{;]*)/gm)) {
|
|
40
63
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
41
64
|
const retStr = extractReturnType(m[3]);
|
|
42
|
-
|
|
65
|
+
const [s, e] = rangeFor(m.index, m.index + m[0].length);
|
|
66
|
+
sigs.push(withAnchor(`pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
return sigs.slice(0, 25);
|
|
@@ -61,7 +85,11 @@ function extractMethods(block) {
|
|
|
61
85
|
for (const m of block.matchAll(/^\s+pub(?:\s+async)?\s+fn\s+(\w+)(?:<[^(]*>)?\s*\(([^)]*)\)([^{;]*)/gm)) {
|
|
62
86
|
const asyncKw = m[0].includes('async') ? 'async ' : '';
|
|
63
87
|
const retStr = extractReturnType(m[3]);
|
|
64
|
-
methods.push(
|
|
88
|
+
methods.push({
|
|
89
|
+
text: `pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`,
|
|
90
|
+
declIdx: m.index + (m[0].length - m[0].trimStart().length),
|
|
91
|
+
endIdx: m.index + m[0].length,
|
|
92
|
+
});
|
|
65
93
|
}
|
|
66
94
|
return methods.slice(0, 8);
|
|
67
95
|
}
|
|
@@ -76,7 +104,7 @@ function extractReturnType(afterParen) {
|
|
|
76
104
|
const m = afterParen.match(/->\s*([^{;]+)/);
|
|
77
105
|
if (!m) return '';
|
|
78
106
|
const rt = m[1].trim().replace(/\s+/g, ' ');
|
|
79
|
-
return `
|
|
107
|
+
return ` → ${rt.length > 30 ? rt.slice(0, 27) + '...' : rt}`;
|
|
80
108
|
}
|
|
81
109
|
|
|
82
110
|
module.exports = { extract };
|
package/src/mcp/server.js
CHANGED