sigmap 6.11.0 → 6.11.1
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/CHANGELOG.md +8 -0
- package/README.md +9 -9
- package/gen-context.js +125 -85
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/mcp/server.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,14 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [6.11.1] — 2026-06-04
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **MCP hot-cold cold signatures in bundled server** — the bundled MCP server now includes the hot-cold "cold" signatures, so context lookups return complete results under the hot-cold strategy (closes #201, PR #216). Thanks @rudi193-cmd.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
13
21
|
## [6.11.0] — 2026-06-03
|
|
14
22
|
|
|
15
23
|
### Added
|
package/README.md
CHANGED
|
@@ -47,10 +47,10 @@ SigMap extracts function and class signatures from your codebase and feeds the r
|
|
|
47
47
|
|
|
48
48
|
## Why SigMap?
|
|
49
49
|
|
|
50
|
-
- **
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **1.66 prompts per task** — down from 2.84 (
|
|
50
|
+
- **81.1% hit@5** — right file found in top 5 results (vs 13.6% baseline)
|
|
51
|
+
- **96.5% token reduction** — average across 21 real repos
|
|
52
|
+
- **53.3% task success rate** — up from 10% without context
|
|
53
|
+
- **1.66 prompts per task** — down from 2.84 (41.8% fewer retries)
|
|
54
54
|
- **31 languages supported** — TypeScript, Python, Go, Rust, Java, R, and 25 others
|
|
55
55
|
- **No vendor lock-in** — works with any AI assistant or local LLM
|
|
56
56
|
- **No API costs** — use local models (Ollama, llama.cpp, vLLM) with zero token fees
|
|
@@ -63,7 +63,7 @@ SigMap extracts function and class signatures from your codebase and feeds the r
|
|
|
63
63
|
|
|
64
64
|
| Without SigMap | With SigMap |
|
|
65
65
|
|---|---|
|
|
66
|
-
| ❌ Guessing which files are relevant | ✅ Right file in context —
|
|
66
|
+
| ❌ Guessing which files are relevant | ✅ Right file in context — 81% of the time |
|
|
67
67
|
| ❌ Sending the full repo to your AI | ✅ Minimal context — only what matters |
|
|
68
68
|
| ❌ Embeddings / vector DB required | ✅ Grounded answers, no infra needed |
|
|
69
69
|
|
|
@@ -87,12 +87,12 @@ Ask → Rank → Context → Validate → Judge → Learn
|
|
|
87
87
|
## Benchmark
|
|
88
88
|
|
|
89
89
|
```
|
|
90
|
-
Benchmark : sigmap-v6.
|
|
91
|
-
Date : 2026-
|
|
90
|
+
Benchmark : sigmap-v6.11-main (21 repositories, including R language)
|
|
91
|
+
Date : 2026-06-04
|
|
92
92
|
|
|
93
|
-
Hit@5 :
|
|
93
|
+
Hit@5 : 81.1% (baseline 13.6% — 6.0× lift)
|
|
94
94
|
Token reduction: 96.5% (across 21 repos)
|
|
95
|
-
Prompt reduction : 41.
|
|
95
|
+
Prompt reduction : 41.8% (2.84 → 1.66 prompts per task)
|
|
96
96
|
Task success : 53.3% (baseline 10%)
|
|
97
97
|
Repos tested : 21 (JavaScript, Python, Go, Rust, Java, R, C++, C#, Dart, Swift, Ruby, PHP, Scala, Kotlin, and more)
|
|
98
98
|
```
|
package/gen-context.js
CHANGED
|
@@ -1174,6 +1174,30 @@ __factories["./src/extractors/php"] = function(module, exports) {
|
|
|
1174
1174
|
|
|
1175
1175
|
};
|
|
1176
1176
|
|
|
1177
|
+
// ── ./src/extractors/line-anchor ──
|
|
1178
|
+
__factories["./src/extractors/line-anchor"] = function(module, exports) {
|
|
1179
|
+
|
|
1180
|
+
function lineAt(src, idx) {
|
|
1181
|
+
let line = 1;
|
|
1182
|
+
const end = Math.min(idx, src.length);
|
|
1183
|
+
for (let i = 0; i < end; i++) {
|
|
1184
|
+
if (src.charCodeAt(i) === 10) line++;
|
|
1185
|
+
}
|
|
1186
|
+
return line;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
function anchor(start, end) {
|
|
1190
|
+
return ` :${start}-${end}`;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
function withAnchor(sig, start, end) {
|
|
1194
|
+
return `${sig}${anchor(start, end)}`;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
module.exports = { lineAt, anchor, withAnchor };
|
|
1198
|
+
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1177
1201
|
// ── ./src/extractors/python ──
|
|
1178
1202
|
__factories["./src/extractors/python"] = function(module, exports) {
|
|
1179
1203
|
|
|
@@ -5339,42 +5363,29 @@ __factories["./src/mcp/handlers"] = function(module, exports) {
|
|
|
5339
5363
|
*/
|
|
5340
5364
|
function searchSignatures(args, cwd) {
|
|
5341
5365
|
if (!args || !args.query) return 'Missing required argument: query';
|
|
5342
|
-
|
|
5343
|
-
const contextPath = path.join(cwd, CONTEXT_FILE);
|
|
5344
|
-
if (!fs.existsSync(contextPath)) {
|
|
5345
|
-
return 'No context file found. Run: node gen-context.js';
|
|
5346
|
-
}
|
|
5347
|
-
|
|
5348
|
-
const content = fs.readFileSync(contextPath, 'utf8');
|
|
5349
5366
|
const query = args.query.toLowerCase();
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
for (const line of lines) {
|
|
5357
|
-
if (line.startsWith('### ')) {
|
|
5358
|
-
currentFile = line.slice(4).trim();
|
|
5359
|
-
fileHeaderAdded = false;
|
|
5360
|
-
continue;
|
|
5361
|
-
}
|
|
5362
|
-
// Skip markdown fences and top-level headers
|
|
5363
|
-
if (line.startsWith('```') || line.startsWith('## ') || line.startsWith('# ') || line.startsWith('<!--')) {
|
|
5364
|
-
continue;
|
|
5367
|
+
|
|
5368
|
+
try {
|
|
5369
|
+
const { buildSigIndex } = __require('./src/retrieval/ranker');
|
|
5370
|
+
const index = buildSigIndex(cwd);
|
|
5371
|
+
if (index.size === 0) {
|
|
5372
|
+
return 'No context file found. Run: node gen-context.js';
|
|
5365
5373
|
}
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
result.push(
|
|
5374
|
+
|
|
5375
|
+
const result = [];
|
|
5376
|
+
for (const [file, sigs] of index.entries()) {
|
|
5377
|
+
const hits = sigs.filter((s) => s.toLowerCase().includes(query));
|
|
5378
|
+
if (hits.length === 0) continue;
|
|
5379
|
+
if (result.length > 0) result.push('');
|
|
5380
|
+
result.push(`### ${file}`);
|
|
5381
|
+
result.push(...hits);
|
|
5373
5382
|
}
|
|
5383
|
+
|
|
5384
|
+
if (result.length === 0) return `No signatures found matching: ${args.query}`;
|
|
5385
|
+
return result.join('\n');
|
|
5386
|
+
} catch (err) {
|
|
5387
|
+
return `_search_signatures failed: ${err.message}_`;
|
|
5374
5388
|
}
|
|
5375
|
-
|
|
5376
|
-
if (result.length === 0) return `No signatures found matching: ${args.query}`;
|
|
5377
|
-
return result.join('\n');
|
|
5378
5389
|
}
|
|
5379
5390
|
|
|
5380
5391
|
/**
|
|
@@ -5640,56 +5651,44 @@ __factories["./src/mcp/handlers"] = function(module, exports) {
|
|
|
5640
5651
|
}
|
|
5641
5652
|
|
|
5642
5653
|
function listModules(args, cwd) {
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
let blockBuf = [];
|
|
5653
|
-
|
|
5654
|
-
function flushBlock() {
|
|
5655
|
-
if (currentGroup === null || blockBuf.length === 0) return;
|
|
5656
|
-
if (!groups[currentGroup]) groups[currentGroup] = { fileCount: 0, tokenCount: 0 };
|
|
5657
|
-
groups[currentGroup].fileCount++;
|
|
5658
|
-
groups[currentGroup].tokenCount += Math.ceil(blockBuf.join('\n').length / 4);
|
|
5659
|
-
blockBuf = [];
|
|
5660
|
-
}
|
|
5661
|
-
|
|
5662
|
-
for (const line of ctxLines) {
|
|
5663
|
-
if (line.startsWith('### ')) {
|
|
5664
|
-
flushBlock();
|
|
5665
|
-
const rel = line.slice(4).trim().replace(/\\/g, '/');
|
|
5654
|
+
try {
|
|
5655
|
+
const { buildSigIndex } = __require('./src/retrieval/ranker');
|
|
5656
|
+
const index = buildSigIndex(cwd);
|
|
5657
|
+
if (index.size === 0) {
|
|
5658
|
+
return 'No context file found. Run: node gen-context.js';
|
|
5659
|
+
}
|
|
5660
|
+
|
|
5661
|
+
const groups = {};
|
|
5662
|
+
for (const [rel, sigs] of index.entries()) {
|
|
5666
5663
|
const parts = rel.split('/');
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5664
|
+
const mod = parts.length > 1 ? parts[0] : '.';
|
|
5665
|
+
if (!groups[mod]) groups[mod] = { fileCount: 0, tokenCount: 0 };
|
|
5666
|
+
groups[mod].fileCount++;
|
|
5667
|
+
groups[mod].tokenCount += Math.ceil(sigs.join('\n').length / 4);
|
|
5670
5668
|
}
|
|
5669
|
+
|
|
5670
|
+
const sorted = Object.entries(groups)
|
|
5671
|
+
.map(([mod, data]) => ({ module: mod, fileCount: data.fileCount, tokenCount: data.tokenCount }))
|
|
5672
|
+
.sort((a, b) => b.tokenCount - a.tokenCount);
|
|
5673
|
+
|
|
5674
|
+
if (sorted.length === 0) return 'No modules found in context file.';
|
|
5675
|
+
|
|
5676
|
+
const total = sorted.reduce((s, m) => s + m.tokenCount, 0);
|
|
5677
|
+
|
|
5678
|
+
return [
|
|
5679
|
+
'# Modules',
|
|
5680
|
+
'',
|
|
5681
|
+
'| Module | Files | Tokens |',
|
|
5682
|
+
'|--------|-------|--------|',
|
|
5683
|
+
...sorted.map((m) => `| ${m.module} | ${m.fileCount} | ~${m.tokenCount} |`),
|
|
5684
|
+
'',
|
|
5685
|
+
`**Total context tokens: ~${total}**`,
|
|
5686
|
+
'',
|
|
5687
|
+
'_Use `read_context({ module: "name" })` to get signatures for a specific module._',
|
|
5688
|
+
].join('\n');
|
|
5689
|
+
} catch (err) {
|
|
5690
|
+
return `_list_modules failed: ${err.message}_`;
|
|
5671
5691
|
}
|
|
5672
|
-
flushBlock();
|
|
5673
|
-
|
|
5674
|
-
const sorted = Object.entries(groups)
|
|
5675
|
-
.map(([mod, data]) => ({ module: mod, fileCount: data.fileCount, tokenCount: data.tokenCount }))
|
|
5676
|
-
.sort((a, b) => b.tokenCount - a.tokenCount);
|
|
5677
|
-
|
|
5678
|
-
if (sorted.length === 0) return 'No modules found in context file.';
|
|
5679
|
-
|
|
5680
|
-
const total = sorted.reduce((s, m) => s + m.tokenCount, 0);
|
|
5681
|
-
|
|
5682
|
-
return [
|
|
5683
|
-
'# Modules',
|
|
5684
|
-
'',
|
|
5685
|
-
'| Module | Files | Tokens |',
|
|
5686
|
-
'|--------|-------|--------|',
|
|
5687
|
-
...sorted.map((m) => `| ${m.module} | ${m.fileCount} | ~${m.tokenCount} |`),
|
|
5688
|
-
'',
|
|
5689
|
-
`**Total context tokens: ~${total}**`,
|
|
5690
|
-
'',
|
|
5691
|
-
'_Use `read_context({ module: "name" })` to get signatures for a specific module._',
|
|
5692
|
-
].join('\n');
|
|
5693
5692
|
}
|
|
5694
5693
|
|
|
5695
5694
|
function queryContext(args, cwd) {
|
|
@@ -5901,7 +5900,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
5901
5900
|
|
|
5902
5901
|
const SERVER_INFO = {
|
|
5903
5902
|
name: 'sigmap',
|
|
5904
|
-
version: '6.11.
|
|
5903
|
+
version: '6.11.1',
|
|
5905
5904
|
description: 'SigMap MCP server — code signatures on demand',
|
|
5906
5905
|
};
|
|
5907
5906
|
|
|
@@ -6968,9 +6967,50 @@ __factories["./src/retrieval/ranker"] = function(module, exports) {
|
|
|
6968
6967
|
if (currentFile !== null) index.set(currentFile, sigs);
|
|
6969
6968
|
return index;
|
|
6970
6969
|
}
|
|
6970
|
+
|
|
6971
|
+
function _mergeSigIndex(target, source) {
|
|
6972
|
+
for (const [file, sigs] of source.entries()) {
|
|
6973
|
+
if (!sigs || sigs.length === 0) continue;
|
|
6974
|
+
if (!target.has(file) || target.get(file).length < sigs.length) {
|
|
6975
|
+
target.set(file, sigs);
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
return target;
|
|
6979
|
+
}
|
|
6980
|
+
|
|
6981
|
+
function _buildSigIndexFromCache(cwd) {
|
|
6982
|
+
const fs = require('fs');
|
|
6983
|
+
const path = require('path');
|
|
6984
|
+
const index = new Map();
|
|
6985
|
+
try {
|
|
6986
|
+
const { loadCache } = require('../cache/sig-cache');
|
|
6987
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
6988
|
+
let version = '0.0.0';
|
|
6989
|
+
if (fs.existsSync(pkgPath)) {
|
|
6990
|
+
version = JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version || version;
|
|
6991
|
+
}
|
|
6992
|
+
const cache = loadCache(cwd, version);
|
|
6993
|
+
for (const [absPath, entry] of cache.entries()) {
|
|
6994
|
+
if (!entry || !entry.sigs || entry.sigs.length === 0) continue;
|
|
6995
|
+
const rel = path.relative(cwd, absPath).replace(/\\/g, '/');
|
|
6996
|
+
if (!rel || rel.startsWith('..')) continue;
|
|
6997
|
+
index.set(rel, entry.sigs);
|
|
6998
|
+
}
|
|
6999
|
+
} catch (_) {}
|
|
7000
|
+
return index;
|
|
7001
|
+
}
|
|
7002
|
+
|
|
7003
|
+
function _enrichSigIndexFromStrategy(cwd, index) {
|
|
7004
|
+
const path = require('path');
|
|
7005
|
+
const coldPath = path.join(cwd, '.github', 'context-cold.md');
|
|
7006
|
+
_mergeSigIndex(index, _parseContextFile(coldPath));
|
|
7007
|
+
_mergeSigIndex(index, _buildSigIndexFromCache(cwd));
|
|
7008
|
+
return index;
|
|
7009
|
+
}
|
|
7010
|
+
|
|
6971
7011
|
function buildSigIndex(cwd, opts) {
|
|
6972
7012
|
const fs = require('fs'); const path = require('path');
|
|
6973
|
-
if (opts && opts.contextPath) return _parseContextFile(opts.contextPath);
|
|
7013
|
+
if (opts && opts.contextPath) return _enrichSigIndexFromStrategy(cwd, _parseContextFile(opts.contextPath));
|
|
6974
7014
|
// Check gen-context.config.json for a persisted customOutput path.
|
|
6975
7015
|
try {
|
|
6976
7016
|
const cfgPath = path.join(cwd, 'gen-context.config.json');
|
|
@@ -6978,16 +7018,16 @@ __factories["./src/retrieval/ranker"] = function(module, exports) {
|
|
|
6978
7018
|
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
6979
7019
|
if (cfg.customOutput) {
|
|
6980
7020
|
const idx = _parseContextFile(path.resolve(cwd, cfg.customOutput));
|
|
6981
|
-
if (idx.size > 0) return idx;
|
|
7021
|
+
if (idx.size > 0) return _enrichSigIndexFromStrategy(cwd, idx);
|
|
6982
7022
|
}
|
|
6983
7023
|
}
|
|
6984
7024
|
} catch (_) {}
|
|
6985
7025
|
for (const parts of ADAPTER_OUTPUT_PATHS) {
|
|
6986
7026
|
const contextPath = path.join(cwd, ...parts);
|
|
6987
7027
|
const index = _parseContextFile(contextPath);
|
|
6988
|
-
if (index.size > 0) return index;
|
|
7028
|
+
if (index.size > 0) return _enrichSigIndexFromStrategy(cwd, index);
|
|
6989
7029
|
}
|
|
6990
|
-
return new Map();
|
|
7030
|
+
return _enrichSigIndexFromStrategy(cwd, new Map());
|
|
6991
7031
|
}
|
|
6992
7032
|
function formatRankTable(results, query) {
|
|
6993
7033
|
if (!results || results.length === 0) return `No matching files found for query: "${query}"\n`;
|
|
@@ -8655,7 +8695,7 @@ const path = require('path');
|
|
|
8655
8695
|
const os = require('os');
|
|
8656
8696
|
const { execSync } = require('child_process');
|
|
8657
8697
|
|
|
8658
|
-
const VERSION = '6.11.
|
|
8698
|
+
const VERSION = '6.11.1';
|
|
8659
8699
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
8660
8700
|
|
|
8661
8701
|
function requireSourceOrBundled(key) {
|
package/package.json
CHANGED
package/src/mcp/server.js
CHANGED