sigmap 5.0.0 → 5.1.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 CHANGED
@@ -12,20 +12,23 @@ Use this marker block for all appendable context files:
12
12
  ## Auto-generated signatures
13
13
  <!-- Updated by gen-context.js -->
14
14
  You are a coding assistant with full knowledge of this codebase.
15
- Below are the code signatures extracted by SigMap v4.1.2 on 2026-04-16T17:45:07.132Z.
15
+ Below are the code signatures extracted by SigMap v5.1.0 on 2026-04-16T21:33:38.411Z.
16
16
 
17
17
  Use these signatures to answer questions about the code accurately.
18
18
 
19
19
  ## Code Signatures
20
20
 
21
- <!-- Generated by SigMap gen-context.js v4.1.2 -->
21
+ <!-- Generated by SigMap gen-context.js v5.1.0 -->
22
22
  <!-- DO NOT EDIT below the marker line — run gen-context.js to regenerate -->
23
23
 
24
24
  # Code signatures
25
25
 
26
- ## changes (last 5 commits — 53 minutes ago)
26
+ ## changes (last 5 commits — 16 minutes ago)
27
27
  ```
28
- src/retrieval/ranker.js +_parseContextFile +buildSigIndex ~buildSigIndex ~rank
28
+ src/config/loader.js +loadBaseConfig ~loadConfig ~deepClone
29
+ src/format/dashboard.js ~computeExtractorCoverage ~readBenchmarkTrend
30
+ src/judge/judge-engine.js +tokenize +groundedness +judge
31
+ src/retrieval/ranker.js +detectIntent ~formatRankJSON
29
32
  ```
30
33
 
31
34
  ## packages
@@ -146,9 +149,41 @@ function adapt(context, adapterName, opts = {}) → string
146
149
 
147
150
  ## src
148
151
 
149
- ### src/config/defaults.js
152
+ ### src/config/loader.js
150
153
  ```
151
- module.exports = { DEFAULTS }
154
+ module.exports = { loadConfig, loadBaseConfig }
155
+ function loadBaseConfig(extendsVal, cwd)
156
+ function detectAutoSrcDirs(cwd, excludeList) → string[]
157
+ function loadConfig(cwd) → object
158
+ function deepClone(obj)
159
+ ```
160
+
161
+ ### src/format/dashboard.js
162
+ ```
163
+ module.exports = { generateDashboardHtml, renderHistoryCharts, computeExtractorCoverage, percentile, overBudgetStreak }
164
+ function toNumber(v)
165
+ function percentile(values, p)
166
+ function overBudgetStreak(entries)
167
+ function loadConfig(cwd)
168
+ function shouldExclude(rel, excludeSet)
169
+ function detectLanguage(filePath)
170
+ function walkFiles(dir, maxDepth, depth, out, excludeSet)
171
+ function computeExtractorCoverage(cwd)
172
+ function readBenchmarkTrend(cwd)
173
+ function lineChartSvg(values, title, ySuffix)
174
+ function barChartSvg(perLanguage)
175
+ function sparkline(values)
176
+ function buildDashboardData(cwd, health)
177
+ function generateDashboardHtml(cwd, health)
178
+ function renderHistoryCharts(cwd, health)
179
+ ```
180
+
181
+ ### src/judge/judge-engine.js
182
+ ```
183
+ module.exports = { groundedness, judge }
184
+ function tokenize(text)
185
+ function groundedness(response, context)
186
+ function judge(response, context, opts = {})
152
187
  ```
153
188
 
154
189
  ### src/mcp/server.js
@@ -162,13 +197,14 @@ function start(cwd)
162
197
 
163
198
  ### src/retrieval/ranker.js
164
199
  ```
165
- module.exports = { rank, buildSigIndex, scoreFile, formatRankTable, formatRankJSON, DEFAULT_WEIGHTS }
200
+ module.exports = { rank, buildSigIndex, scoreFile, formatRankTable, formatRankJSON, DEFAULT_WEIGHTS, detectIntent }
166
201
  function scoreFile(filePath, sigs, queryTokens, weights) → number
167
202
  function rank(query, sigIndex, opts) → { file: string, score: nu
168
203
  function _parseContextFile(contextPath) → Map<string, string[]>
169
204
  function buildSigIndex(cwd, opts) → Map<string, string[]>
170
205
  function formatRankTable(results, query) → string
171
206
  function formatRankJSON(results, query) → object
207
+ function detectIntent(query)
172
208
  ```
173
209
 
174
210
  ### src/analysis/coverage-score.js
@@ -178,12 +214,9 @@ function coverageScore(cwd, fileEntries, config) → { * score: number, * grad
178
214
  function _walk(dir, excludeSet, out)
179
215
  ```
180
216
 
181
- ### src/config/loader.js
217
+ ### src/config/defaults.js
182
218
  ```
183
- module.exports = { loadConfig }
184
- function detectAutoSrcDirs(cwd, excludeList) → string[]
185
- function loadConfig(cwd) → object
186
- function deepClone(obj)
219
+ module.exports = { DEFAULTS }
187
220
  ```
188
221
 
189
222
  ### src/eval/analyzer.js
@@ -527,26 +560,6 @@ function formatCache(content) → string
527
560
  function formatCachePayload(content, model) → string
528
561
  ```
529
562
 
530
- ### src/format/dashboard.js
531
- ```
532
- module.exports = { generateDashboardHtml, renderHistoryCharts, computeExtractorCoverage, percentile, overBudgetStreak }
533
- function toNumber(v)
534
- function percentile(values, p)
535
- function overBudgetStreak(entries)
536
- function loadConfig(cwd)
537
- function shouldExclude(rel, excludeSet)
538
- function detectLanguage(filePath)
539
- function walkFiles(dir, maxDepth, depth, out, excludeSet)
540
- function computeExtractorCoverage(cwd)
541
- function readBenchmarkTrend(cwd)
542
- function lineChartSvg(values, title, ySuffix)
543
- function barChartSvg(perLanguage)
544
- function sparkline(values)
545
- function buildDashboardData(cwd, health)
546
- function generateDashboardHtml(cwd, health)
547
- function renderHistoryCharts(cwd, health)
548
- ```
549
-
550
563
  ### src/format/llm-txt.js
551
564
  ```
552
565
  module.exports = { format, outputPath }
package/CHANGELOG.md CHANGED
@@ -10,6 +10,16 @@ Format: [Semantic Versioning](https://semver.org/)
10
10
 
11
11
  ---
12
12
 
13
+ ## [5.1.0] — 2026-04-16
14
+
15
+ ### Added
16
+
17
+ - **Benchmark history tracking** — all three benchmark scripts (`run-retrieval-benchmark.mjs`, `run-benchmark.mjs`, `run-task-benchmark.mjs`) now append a structured NDJSON entry to `.context/benchmark-history.ndjson` after each run (`type: "retrieval" | "token-reduction" | "task"`).
18
+ - **`sigmap history` benchmark trend rows** — when `.context/benchmark-history.ndjson` exists, `sigmap history` prints a retrieval `hit@5` sparkline row and a token-reduction sparkline row below the usage table. The command no longer exits early when the usage log is empty.
19
+ - **Dashboard `readBenchmarkTrend` uses local history** — `src/format/dashboard.js` now prefers `.context/benchmark-history.ndjson` over the CI-only `benchmarks/results/` directory, so the dashboard hit@5 trend chart populates for all users after running any benchmark locally.
20
+
21
+ ---
22
+
13
23
  ## [5.0.0] — 2026-04-16
14
24
 
15
25
  ### Added
package/gen-context.js CHANGED
@@ -3152,6 +3152,25 @@ __factories["./src/format/cache"] = function(module, exports) {
3152
3152
  }
3153
3153
 
3154
3154
  function readBenchmarkTrend(cwd) {
3155
+ // Prefer per-user history file written by benchmark scripts
3156
+ const histPath = path.join(cwd, '.context', 'benchmark-history.ndjson');
3157
+ if (fs.existsSync(histPath)) {
3158
+ const histValues = [];
3159
+ try {
3160
+ for (const line of fs.readFileSync(histPath, 'utf8').trim().split('\n').filter(Boolean)) {
3161
+ try {
3162
+ const obj = JSON.parse(line);
3163
+ if (obj.type === 'retrieval') {
3164
+ const v = toNumber(obj.hitAt5Pct);
3165
+ if (v !== null) histValues.push(v);
3166
+ }
3167
+ } catch (_) {}
3168
+ }
3169
+ } catch (_) {}
3170
+ if (histValues.length > 0) return histValues.slice(-30);
3171
+ }
3172
+
3173
+ // Fallback: legacy benchmarks/results directory (CI artifacts)
3155
3174
  const resultDir = path.join(cwd, 'benchmarks', 'results');
3156
3175
  if (!fs.existsSync(resultDir)) return [];
3157
3176
  const files = [];
@@ -4708,7 +4727,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
4708
4727
 
4709
4728
  const SERVER_INFO = {
4710
4729
  name: 'sigmap',
4711
- version: '5.0.0',
4730
+ version: '5.1.0',
4712
4731
  description: 'SigMap MCP server — code signatures on demand',
4713
4732
  };
4714
4733
 
@@ -6371,7 +6390,7 @@ const path = require('path');
6371
6390
  const os = require('os');
6372
6391
  const { execSync } = require('child_process');
6373
6392
 
6374
- const VERSION = '5.0.0';
6393
+ const VERSION = '5.1.0';
6375
6394
  const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
6376
6395
 
6377
6396
  function requireSourceOrBundled(key) {
@@ -8482,11 +8501,6 @@ function main() {
8482
8501
  process.exit(0);
8483
8502
  }
8484
8503
 
8485
- if (last.length === 0) {
8486
- console.log('[sigmap] No history found. Run sigmap to generate entries (enable tracking: true in config).');
8487
- process.exit(0);
8488
- }
8489
-
8490
8504
  const SPARK_CHARS = '▁▂▃▄▅▆▇█';
8491
8505
  function sparkline(values) {
8492
8506
  if (values.length === 0) return '';
@@ -8499,25 +8513,48 @@ function main() {
8499
8513
  }).join('');
8500
8514
  }
8501
8515
 
8502
- const tokens = last.map((e) => e.finalTokens || 0);
8503
- const spark = sparkline(tokens);
8504
-
8505
8516
  const bar = '─'.repeat(62);
8506
8517
  console.log(bar);
8507
- console.log(` sigmap history (last ${last.length} runs)`);
8518
+ console.log(` sigmap history (last ${Math.max(last.length, 1)} runs)`);
8508
8519
  console.log(bar);
8509
- console.log(` ${'Date'.padEnd(24)} ${'Files'.padStart(5)} ${'Tokens'.padStart(7)} ${'Reduction'.padStart(9)} ${'Budget?'.padStart(7)}`);
8510
- console.log(` ${'─'.repeat(24)} ${'─'.repeat(5)} ${'─'.repeat(7)} ${'─'.repeat(9)} ${'─'.repeat(7)}`);
8511
- for (const e of last) {
8512
- const date = (e.ts || '').slice(0, 19).replace('T', ' ');
8513
- const files = String(e.fileCount || 0).padStart(5);
8514
- const tok = String(e.finalTokens || 0).padStart(7);
8515
- const red = `${e.reductionPct || 0}%`.padStart(9);
8516
- const over = (e.overBudget ? ' yes' : ' no').padStart(7);
8517
- console.log(` ${date.padEnd(24)} ${files} ${tok} ${red} ${over}`);
8520
+
8521
+ if (last.length === 0) {
8522
+ console.log(' No usage log entries. Enable tracking: true in config to start recording runs.');
8523
+ } else {
8524
+ console.log(` ${'Date'.padEnd(24)} ${'Files'.padStart(5)} ${'Tokens'.padStart(7)} ${'Reduction'.padStart(9)} ${'Budget?'.padStart(7)}`);
8525
+ console.log(` ${'─'.repeat(24)} ${'─'.repeat(5)} ${'─'.repeat(7)} ${'─'.repeat(9)} ${'─'.repeat(7)}`);
8526
+ for (const e of last) {
8527
+ const date = (e.ts || '').slice(0, 19).replace('T', ' ');
8528
+ const files = String(e.fileCount || 0).padStart(5);
8529
+ const tok = String(e.finalTokens || 0).padStart(7);
8530
+ const red = `${e.reductionPct || 0}%`.padStart(9);
8531
+ const over = (e.overBudget ? ' ⚠ yes' : ' no').padStart(7);
8532
+ console.log(` ${date.padEnd(24)} ${files} ${tok} ${red} ${over}`);
8533
+ }
8534
+ console.log(bar);
8535
+ const tokens = last.map((e) => e.finalTokens || 0);
8536
+ console.log(` Token trend: ${sparkline(tokens)}`);
8537
+ }
8538
+
8539
+ // Show benchmark trend row if .context/benchmark-history.ndjson exists
8540
+ const benchHistPath = path.join(cwd, '.context', 'benchmark-history.ndjson');
8541
+ if (fs.existsSync(benchHistPath)) {
8542
+ try {
8543
+ const benchEntries = fs.readFileSync(benchHistPath, 'utf8').trim().split('\n')
8544
+ .map((l) => { try { return JSON.parse(l); } catch (_) { return null; } }).filter(Boolean);
8545
+ const retrieval = benchEntries.filter((e) => e.type === 'retrieval').slice(-n);
8546
+ if (retrieval.length > 0) {
8547
+ const hits = retrieval.map((e) => e.hitAt5Pct || 0);
8548
+ console.log(` hit@5 trend: ${sparkline(hits)} ${hits.at(-1)}% (latest)`);
8549
+ }
8550
+ const tokenBench = benchEntries.filter((e) => e.type === 'token-reduction').slice(-n);
8551
+ if (tokenBench.length > 0) {
8552
+ const reds = tokenBench.map((e) => e.reduction || e.avgReductionPct || 0);
8553
+ console.log(` tok reduce : ${sparkline(reds)} ${reds.at(-1)}% (latest)`);
8554
+ }
8555
+ } catch (_) {}
8518
8556
  }
8519
- console.log(bar);
8520
- console.log(` Token trend: ${spark}`);
8557
+
8521
8558
  console.log(bar);
8522
8559
  process.exit(0);
8523
8560
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
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": "5.0.0",
3
+ "version": "5.1.0",
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": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -140,6 +140,26 @@ function computeExtractorCoverage(cwd) {
140
140
  }
141
141
 
142
142
  function readBenchmarkTrend(cwd) {
143
+ // Prefer per-user history file written by benchmark scripts
144
+ const histPath = path.join(cwd, '.context', 'benchmark-history.ndjson');
145
+ if (fs.existsSync(histPath)) {
146
+ const values = [];
147
+ try {
148
+ const lines = fs.readFileSync(histPath, 'utf8').trim().split('\n').filter(Boolean);
149
+ for (const line of lines) {
150
+ try {
151
+ const obj = JSON.parse(line);
152
+ if (obj.type === 'retrieval') {
153
+ const v = toNumber(obj.hitAt5Pct);
154
+ if (v !== null) values.push(v);
155
+ }
156
+ } catch (_) {}
157
+ }
158
+ } catch (_) {}
159
+ if (values.length > 0) return values.slice(-30);
160
+ }
161
+
162
+ // Fallback: legacy benchmarks/results directory (CI artifacts)
143
163
  const resultDir = path.join(cwd, 'benchmarks', 'results');
144
164
  if (!fs.existsSync(resultDir)) return [];
145
165
 
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: '5.0.0',
21
+ version: '5.1.0',
22
22
  description: 'SigMap MCP server — code signatures on demand',
23
23
  };
24
24