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 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
- - **78.9% hit@5** — right file found in top 5 results (vs 13.6% baseline)
51
- - **97.9% token reduction** — 278K instead of 13.5M tokens across 21 repos
52
- - **52.2% task success rate** — up from 10% without context
53
- - **1.66 prompts per task** — down from 2.84 (40.6% fewer retries)
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 — 80% of the time |
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.10-main (21 repositories, including R language)
91
- Date : 2026-05-22
90
+ Benchmark : sigmap-v6.11-main (21 repositories, including R language)
91
+ Date : 2026-06-04
92
92
 
93
- Hit@5 : 80% (baseline 13.6% — 5.9× lift)
93
+ Hit@5 : 81.1% (baseline 13.6% — 6.0× lift)
94
94
  Token reduction: 96.5% (across 21 repos)
95
- Prompt reduction : 41.4% (2.84 → 1.67 prompts per task)
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
- const lines = content.split('\n');
5351
-
5352
- const result = [];
5353
- let currentFile = '';
5354
- let fileHeaderAdded = false;
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
- if (line.toLowerCase().includes(query)) {
5367
- if (currentFile && !fileHeaderAdded) {
5368
- if (result.length > 0) result.push('');
5369
- result.push(`### ${currentFile}`);
5370
- fileHeaderAdded = true;
5371
- }
5372
- result.push(line);
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
- const contextPath = path.join(cwd, CONTEXT_FILE);
5644
- if (!fs.existsSync(contextPath)) {
5645
- return 'No context file found. Run: node gen-context.js';
5646
- }
5647
-
5648
- const content = fs.readFileSync(contextPath, 'utf8');
5649
- const ctxLines = content.split('\n');
5650
- const groups = {};
5651
- let currentGroup = null;
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
- currentGroup = parts.length > 1 ? parts[0] : '.';
5668
- } else if (currentGroup !== null) {
5669
- blockBuf.push(line);
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.0',
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.0';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "6.11.0",
3
+ "version": "6.11.1",
4
4
  "description": "Zero-dependency AI context engine — 97% token reduction. No npm install. Runs on Node 18+.",
5
5
  "main": "gen-context.js",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-cli",
3
- "version": "6.11.0",
3
+ "version": "6.11.1",
4
4
  "description": "SigMap CLI wrapper — thin adapter for programmatic CLI invocation",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-core",
3
- "version": "6.11.0",
3
+ "version": "6.11.1",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [
package/src/mcp/server.js CHANGED
@@ -18,7 +18,7 @@ const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, exp
18
18
 
19
19
  const SERVER_INFO = {
20
20
  name: 'sigmap',
21
- version: '6.11.0',
21
+ version: '6.11.1',
22
22
  description: 'SigMap MCP server — code signatures on demand',
23
23
  };
24
24