sigmap 8.7.0 → 8.8.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/CHANGELOG.md +21 -0
- package/README.md +8 -8
- package/gen-context.js +114 -17
- package/llms-full.txt +15 -6
- package/llms.txt +5 -5
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/discovery/source-root-resolver.js +12 -5
- package/src/mcp/handlers.js +44 -1
- package/src/mcp/server.js +4 -3
- package/src/mcp/tools.js +24 -2
- package/src/tracking/pricing.js +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,27 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [8.8.0] — 2026-07-05
|
|
14
|
+
|
|
15
|
+
Minor release — **the squeeze engine, exposed mid-session (D6).** The always-on squeeze engine (`src/squeeze/`) that powers `sigmap squeeze` was reachable only from the CLI on pasted input. This release exposes it as an MCP tool an agent can call *mid-session*, and adds a named CLI entry point for compressing an agent/tool *response*. Zero-dependency, offline, deterministic — the last A+ ceiling item (Machine 9→10): the engine already shipped, this just exposes it.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **`squeeze_output` MCP tool (#437, PR #438):** the 19th MCP tool (18 → 19) wraps the existing `squeeze()` engine so an agent can compress noisy tool/command output — a stack trace, CI/build log, or JSON payload — before it enters context. Keeps the signal (error frames, failing steps, JSON shape), strips the noise, and enriches the top stack frame with its signature; returns the squeezed text plus token-reduction stats. Passes the input through unchanged when no squeezable structure is detected, and returns usage on empty input. No LLM, no network. New handler `squeezeOutput` in `src/mcp/handlers.js`, wired through `src/mcp/tools.js` and `src/mcp/server.js`.
|
|
19
|
+
- **`sigmap squeeze --response <file|->` (#437, PR #438):** names the agent/tool response input explicitly (mirroring the existing `sigmap judge --response` convention), routing it through the same squeeze engine. Supports `--json`. Documented in `--help`.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Deterministic context output — three nondeterminism sources (#440, PR #441):** `gen-context`'s signature output was not byte-stable across runs on some repos, making the retrieval benchmark's hit@5 non-reproducible. Fixes: (1) the token-budget drop-order now has a final `filePath` tie-break, so which files survive the budget no longer falls through to filesystem `readdir` order (test files sharing a git-checkout mtime tied on every prior key); (2) the source-file walk sorts `readdir` entries by name for stable section order; (3) auto source-root detection sorts its candidate enumeration and adds tie-breaks to the score sorts, so the `MAX_ROOTS` cutoff admits a deterministic directory set. Adds a resolver determinism regression guard. A residual affecting a few large repos remains tracked in #440.
|
|
23
|
+
|
|
24
|
+
## [8.7.1] — 2026-07-05
|
|
25
|
+
|
|
26
|
+
Patch release — **multi-model cost savings + verified pricing.** The quality benchmark reported API input-cost savings for GPT-4o only; it now reports GPT-4o, Claude Sonnet, and Claude Haiku, and the hardcoded Claude rates were corrected to current published pricing.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **Multi-model cost savings (#433, PR #434):** `scripts/run-quality-benchmark.mjs` adds Claude Haiku to the pricing model and emits a per-model "cost savings by model" table (GPT-4o · Claude Sonnet · Claude Haiku). `docs-vp/guide/quality-benchmark.md` now shows all three models in the cost table, headline, and frontmatter. Pricing verified 2026-07 (per 1M input tokens): GPT-4o $2.50, Claude Sonnet 5/4.6 $3.00, Claude Haiku 4.5 $1.00.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- **Stale Claude pricing (#433, PR #434):** `src/tracking/pricing.js` (the `sigmap gain` dashboard's cost assumptions) corrected to current published rates — Claude Haiku $0.80→$1.00 and Claude Opus $15.00→$5.00 (Opus 4.8). GPT-4o ($2.50) and Sonnet ($3.00) were already correct.
|
|
33
|
+
|
|
13
34
|
## [8.7.0] — 2026-07-05
|
|
14
35
|
|
|
15
36
|
Minor release — **method/caller-level call-graph (D4 v1): the graph goes from files to functions.** SigMap's dependency graph was file-level only (imports → `--impact`/`get_impact`). This adds **symbol-level** edges — *which function calls which function* — and the **method-level blast radius** of changing a single symbol. Deterministic, zero-dependency, JS/TS + Python. This is the plan's single hardest unbuilt gap and the biggest remaining lever on graph intelligence (v9.5 GR1).
|
package/README.md
CHANGED
|
@@ -59,8 +59,8 @@ That map is exactly what agentic grep is worst at: reproducible, auditable conte
|
|
|
59
59
|
<!--SM:whyMetrics-->
|
|
60
60
|
- **87.8% hit@5** — right file found in top 5 results (vs 13.6% baseline)
|
|
61
61
|
- **97.0% token reduction** — average across 21 real repos
|
|
62
|
-
- **
|
|
63
|
-
- **1.
|
|
62
|
+
- **67.8% task success rate** — up from 10% without context
|
|
63
|
+
- **1.44 prompts per task** — down from 2.84 (49.2% fewer retries)
|
|
64
64
|
<!--/SM:whyMetrics-->
|
|
65
65
|
- **<!--SM:languages-->33<!--/SM:languages--> languages supported** — TypeScript, Python, Go, Rust, Java, R, and more
|
|
66
66
|
- **No vendor lock-in** — works with any AI assistant or local LLM
|
|
@@ -120,13 +120,13 @@ Ask → Rank → Context → Validate → Judge → Learn
|
|
|
120
120
|
|
|
121
121
|
<!--SM:benchmarkBlock-->
|
|
122
122
|
```
|
|
123
|
-
Benchmark : sigmap-v8.
|
|
123
|
+
Benchmark : sigmap-v8.8-main (21 repositories, including R language)
|
|
124
124
|
Date : 2026-07-05
|
|
125
125
|
|
|
126
126
|
Hit@5 : 87.8% (baseline 13.6% — 6.5× lift)
|
|
127
127
|
Token reduction: 97.0% (across 21 repos)
|
|
128
|
-
Prompt reduction : 49.
|
|
129
|
-
Task success :
|
|
128
|
+
Prompt reduction : 49.2% (2.84 → 1.44 prompts per task)
|
|
129
|
+
Task success : 67.8% (baseline 10%)
|
|
130
130
|
Repos tested : 21 (JavaScript, Python, Go, Rust, Java, R, C++, C#, Dart, Swift, Ruby, PHP, Scala, Kotlin, and more)
|
|
131
131
|
```
|
|
132
132
|
<!--/SM:benchmarkBlock-->
|
|
@@ -220,13 +220,13 @@ Use SigMap with open-source tools and fully self-hosted setups:
|
|
|
220
220
|
| **JetBrains** | [Marketplace](https://plugins.jetbrains.com/plugin/31109-sigmap--ai-context-engine/) | [github.com/manojmallick/sigmap-jetbrains](https://github.com/manojmallick/sigmap-jetbrains) | IntelliJ IDEA, WebStorm, PyCharm, GoLand — tool window + actions |
|
|
221
221
|
| **Neovim** | lazy.nvim / packer / vim-plug | [github.com/manojmallick/sigmap.nvim](https://github.com/manojmallick/sigmap.nvim) | `:SigMap`, `:SigMapQuery` float window, statusline widget |
|
|
222
222
|
|
|
223
|
-
**MCP server** —
|
|
223
|
+
**MCP server** — 19 on-demand tools for Claude Code and Cursor:
|
|
224
224
|
|
|
225
225
|
```bash
|
|
226
226
|
sigmap --mcp
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
-
Tools: `read_context`, `search_signatures`, `get_map`, `create_checkpoint`, `get_routing`, `explain_file`, `list_modules`, `query_context`, `get_impact`, `get_lines`, `read_memory`, `get_callee_signatures`, `get_diff_context` (changed files + signatures + blast radius), `get_architecture_overview` (modules, hub files, cycles), plus the live-index notifications `sigmap_notify_file_created`, `sigmap_notify_symbol_added`, and `sigmap_notify_file_deleted`. Full reference: [llms-full.txt](llms-full.txt).
|
|
229
|
+
Tools: `read_context`, `search_signatures`, `get_map`, `create_checkpoint`, `get_routing`, `explain_file`, `list_modules`, `query_context`, `get_impact`, `get_lines`, `read_memory`, `get_callee_signatures`, `get_diff_context` (changed files + signatures + blast radius), `get_architecture_overview` (modules, hub files, cycles), `verify_suggestion` (ground AI code against repo + installed libraries), `squeeze_output` (compress noisy tool/log/JSON output mid-session), plus the live-index notifications `sigmap_notify_file_created`, `sigmap_notify_symbol_added`, and `sigmap_notify_file_deleted`. Full reference: [llms-full.txt](llms-full.txt).
|
|
230
230
|
|
|
231
231
|
---
|
|
232
232
|
|
|
@@ -265,7 +265,7 @@ SigMap treats coding agents as **consumers, not competitors**: it hands them a d
|
|
|
265
265
|
|
|
266
266
|
| Agent | One-time setup | How it consumes SigMap |
|
|
267
267
|
|---|---|---|
|
|
268
|
-
| **Claude Code** | `sigmap mcp install claude` |
|
|
268
|
+
| **Claude Code** | `sigmap mcp install claude` | 19 MCP tools (`search_signatures`, `get_lines`, `get_diff_context`, `squeeze_output`…) |
|
|
269
269
|
| **Cursor** | `sigmap mcp install cursor` | MCP tools, plus the `cursor` adapter writes `.cursorrules` |
|
|
270
270
|
| **Cline** | `sigmap mcp install cursor` | Reads `.cursorrules`; same MCP server |
|
|
271
271
|
| **Continue** | `sigmap mcp install vscode` | MCP tools inside the Continue extension |
|
package/gen-context.js
CHANGED
|
@@ -3202,7 +3202,11 @@ __factories["./src/discovery/source-root-resolver"] = function(module, exports)
|
|
|
3202
3202
|
score: scoreCandidate(name, full, context),
|
|
3203
3203
|
}))
|
|
3204
3204
|
.filter(c => c.score > 0)
|
|
3205
|
-
|
|
3205
|
+
// Final tie-break on dir keeps selection deterministic when scores tie — the
|
|
3206
|
+
// top-MAX_ROOTS slice below would otherwise admit different dirs run to run
|
|
3207
|
+
// (candidate order comes from filesystem readdir), changing which files are
|
|
3208
|
+
// collected and making the generated context non-reproducible.
|
|
3209
|
+
.sort((a, b) => b.score - a.score || a.dir.localeCompare(b.dir));
|
|
3206
3210
|
|
|
3207
3211
|
// Handle special rules
|
|
3208
3212
|
let roots = _applySpecialRules(scored, cwd, primaryFw, fwEntry, frameworks);
|
|
@@ -3245,9 +3249,12 @@ __factories["./src/discovery/source-root-resolver"] = function(module, exports)
|
|
|
3245
3249
|
const candidates = [];
|
|
3246
3250
|
const excSet = new Set(excludeList);
|
|
3247
3251
|
|
|
3248
|
-
// Root-level dirs
|
|
3252
|
+
// Root-level dirs (sorted so candidate order — and downstream dedupe/selection
|
|
3253
|
+
// — is deterministic regardless of filesystem readdir order)
|
|
3249
3254
|
try {
|
|
3250
|
-
|
|
3255
|
+
const rootEntries = fs.readdirSync(cwd, { withFileTypes: true })
|
|
3256
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
3257
|
+
for (const e of rootEntries) {
|
|
3251
3258
|
if (!e.isDirectory()) continue;
|
|
3252
3259
|
if (excSet.has(e.name)) continue;
|
|
3253
3260
|
if (matchesIgnorePattern(e.name, ignorePatterns)) continue;
|
|
@@ -3316,7 +3323,7 @@ __factories["./src/discovery/source-root-resolver"] = function(module, exports)
|
|
|
3316
3323
|
}
|
|
3317
3324
|
}
|
|
3318
3325
|
} catch (_) {}
|
|
3319
|
-
roots.sort((a, b) => b.score - a.score);
|
|
3326
|
+
roots.sort((a, b) => b.score - a.score || a.dir.localeCompare(b.dir));
|
|
3320
3327
|
}
|
|
3321
3328
|
|
|
3322
3329
|
// Swift project dir: dirs with ≥3 .swift files
|
|
@@ -3331,7 +3338,7 @@ __factories["./src/discovery/source-root-resolver"] = function(module, exports)
|
|
|
3331
3338
|
}
|
|
3332
3339
|
}
|
|
3333
3340
|
} catch (_) {}
|
|
3334
|
-
roots.sort((a, b) => b.score - a.score);
|
|
3341
|
+
roots.sort((a, b) => b.score - a.score || a.dir.localeCompare(b.dir));
|
|
3335
3342
|
}
|
|
3336
3343
|
|
|
3337
3344
|
return roots;
|
|
@@ -13345,7 +13352,50 @@ __factories["./src/mcp/handlers"] = function(module, exports) {
|
|
|
13345
13352
|
return out.join('\n');
|
|
13346
13353
|
}
|
|
13347
13354
|
|
|
13348
|
-
|
|
13355
|
+
/**
|
|
13356
|
+
* squeeze_output({ content }) → string
|
|
13357
|
+
*
|
|
13358
|
+
* Compress noisy tool/command/agent output (stack trace, CI/build log, or JSON
|
|
13359
|
+
* payload) through the deterministic squeeze engine. Enriches the top stack
|
|
13360
|
+
* frame with its signature when the symbol index is available. Passes the input
|
|
13361
|
+
* through unchanged when no squeezable structure is detected.
|
|
13362
|
+
*/
|
|
13363
|
+
function squeezeOutput(args, cwd) {
|
|
13364
|
+
const content = args && typeof args.content === 'string' ? args.content : '';
|
|
13365
|
+
if (!content.trim()) {
|
|
13366
|
+
return 'Usage: squeeze_output({ content: "<raw tool/log/JSON output>" }) — provide the output to compress.';
|
|
13367
|
+
}
|
|
13368
|
+
|
|
13369
|
+
let sq;
|
|
13370
|
+
try {
|
|
13371
|
+
const { squeeze } = __require('./src/squeeze/index');
|
|
13372
|
+
let srcDirs;
|
|
13373
|
+
let symbolIndex = null;
|
|
13374
|
+
try {
|
|
13375
|
+
const { loadConfig } = __require('./src/config/loader');
|
|
13376
|
+
srcDirs = loadConfig(cwd).srcDirs;
|
|
13377
|
+
} catch (_) {}
|
|
13378
|
+
try {
|
|
13379
|
+
const { buildSigIndex } = __require('./src/retrieval/ranker');
|
|
13380
|
+
symbolIndex = buildSigIndex(cwd);
|
|
13381
|
+
} catch (_) {}
|
|
13382
|
+
sq = squeeze(content, { srcDirs, symbolIndex });
|
|
13383
|
+
} catch (err) {
|
|
13384
|
+
return `_squeeze_output failed: ${err.message}_`;
|
|
13385
|
+
}
|
|
13386
|
+
|
|
13387
|
+
if (!sq.category || !sq.applies) {
|
|
13388
|
+
return `No squeezable structure detected — content unchanged (${sq.rawTokens} tokens).\n\n${content}`;
|
|
13389
|
+
}
|
|
13390
|
+
|
|
13391
|
+
const pct = Math.round(sq.reduction * 100);
|
|
13392
|
+
const header =
|
|
13393
|
+
`Squeezed ${sq.category} — ${sq.rawTokens} → ${sq.squeezedTokens} tokens ` +
|
|
13394
|
+
`(${pct}% smaller)${sq.enriched ? ' · signature-enriched' : ''}\n\n`;
|
|
13395
|
+
return header + sq.squeezed;
|
|
13396
|
+
}
|
|
13397
|
+
|
|
13398
|
+
module.exports = { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getImpact, getLines, readMemory, getCalleeSignatures, notifyFileCreated, notifySymbolAdded, notifyFileDeleted, getDiffContext, getArchitectureOverview, verifySuggestion, squeezeOutput };
|
|
13349
13399
|
|
|
13350
13400
|
};
|
|
13351
13401
|
|
|
@@ -13506,17 +13556,17 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
13506
13556
|
*
|
|
13507
13557
|
* Supported methods:
|
|
13508
13558
|
* initialize → serverInfo + capabilities
|
|
13509
|
-
* tools/list →
|
|
13559
|
+
* tools/list → 19 tool definitions
|
|
13510
13560
|
* tools/call → dispatch to handler, return result
|
|
13511
13561
|
*/
|
|
13512
13562
|
|
|
13513
13563
|
const readline = require('readline');
|
|
13514
13564
|
const { TOOLS } = __require('./src/mcp/tools');
|
|
13515
|
-
const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getImpact, getLines, readMemory, getCalleeSignatures, notifyFileCreated, notifySymbolAdded, notifyFileDeleted, getDiffContext, getArchitectureOverview, verifySuggestion } = __require('./src/mcp/handlers');
|
|
13565
|
+
const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getImpact, getLines, readMemory, getCalleeSignatures, notifyFileCreated, notifySymbolAdded, notifyFileDeleted, getDiffContext, getArchitectureOverview, verifySuggestion, squeezeOutput } = __require('./src/mcp/handlers');
|
|
13516
13566
|
|
|
13517
13567
|
const SERVER_INFO = {
|
|
13518
13568
|
name: 'sigmap',
|
|
13519
|
-
version: '8.
|
|
13569
|
+
version: '8.8.0',
|
|
13520
13570
|
description: 'SigMap MCP server — code signatures on demand',
|
|
13521
13571
|
};
|
|
13522
13572
|
|
|
@@ -13582,6 +13632,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
13582
13632
|
else if (name === 'get_diff_context') text = getDiffContext(args, cwd);
|
|
13583
13633
|
else if (name === 'get_architecture_overview') text = getArchitectureOverview(args, cwd);
|
|
13584
13634
|
else if (name === 'verify_suggestion') text = verifySuggestion(args, cwd);
|
|
13635
|
+
else if (name === 'squeeze_output') text = squeezeOutput(args, cwd);
|
|
13585
13636
|
else {
|
|
13586
13637
|
respondError(id, -32601, `Unknown tool: ${name}`);
|
|
13587
13638
|
return;
|
|
@@ -13642,11 +13693,12 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
13642
13693
|
__factories["./src/mcp/tools"] = function(module, exports) {
|
|
13643
13694
|
|
|
13644
13695
|
/**
|
|
13645
|
-
* MCP tool definitions for SigMap (
|
|
13696
|
+
* MCP tool definitions for SigMap (19 tools).
|
|
13646
13697
|
* read_context, search_signatures, get_map, create_checkpoint, get_routing,
|
|
13647
13698
|
* explain_file, list_modules, query_context, get_impact, get_lines, read_memory,
|
|
13648
13699
|
* get_callee_signatures, sigmap_notify_file_created, sigmap_notify_symbol_added,
|
|
13649
|
-
* sigmap_notify_file_deleted, get_diff_context, get_architecture_overview
|
|
13700
|
+
* sigmap_notify_file_deleted, get_diff_context, get_architecture_overview,
|
|
13701
|
+
* verify_suggestion, squeeze_output.
|
|
13650
13702
|
*/
|
|
13651
13703
|
|
|
13652
13704
|
const TOOLS = [
|
|
@@ -13977,6 +14029,27 @@ __factories["./src/mcp/tools"] = function(module, exports) {
|
|
|
13977
14029
|
required: ['code'],
|
|
13978
14030
|
},
|
|
13979
14031
|
},
|
|
14032
|
+
{
|
|
14033
|
+
name: 'squeeze_output',
|
|
14034
|
+
description:
|
|
14035
|
+
'Compress noisy tool, command, or agent output before it enters context — a stack ' +
|
|
14036
|
+
'trace, CI/build log, or JSON payload. Same deterministic, offline engine as ' +
|
|
14037
|
+
'`sigmap squeeze`: keeps the signal (error frames, failing steps, JSON shape), strips ' +
|
|
14038
|
+
'the noise, and enriches the top stack frame with its signature. Returns the squeezed ' +
|
|
14039
|
+
'text plus token-reduction stats; passes the input through unchanged when no squeezable ' +
|
|
14040
|
+
'structure is detected. No LLM, no network.',
|
|
14041
|
+
inputSchema: {
|
|
14042
|
+
type: 'object',
|
|
14043
|
+
properties: {
|
|
14044
|
+
content: {
|
|
14045
|
+
type: 'string',
|
|
14046
|
+
description:
|
|
14047
|
+
'The raw output to compress (a stack trace, CI/build log, or JSON payload).',
|
|
14048
|
+
},
|
|
14049
|
+
},
|
|
14050
|
+
required: ['content'],
|
|
14051
|
+
},
|
|
14052
|
+
},
|
|
13980
14053
|
];
|
|
13981
14054
|
|
|
13982
14055
|
module.exports = { TOOLS };
|
|
@@ -16851,11 +16924,12 @@ __factories["./src/tracking/pricing"] = function(module, exports) {
|
|
|
16851
16924
|
* presented as exact. Zero npm dependencies.
|
|
16852
16925
|
*/
|
|
16853
16926
|
|
|
16854
|
-
// USD per 1,000,000 input tokens.
|
|
16927
|
+
// USD per 1,000,000 input tokens. Claude rates verified 2026-07 against
|
|
16928
|
+
// platform.claude.com (Opus 4.8 $5, Sonnet 5/4.6 $3, Haiku 4.5 $1); GPT-4o $2.50.
|
|
16855
16929
|
const PRICES = {
|
|
16856
16930
|
'claude-sonnet': 3.0,
|
|
16857
|
-
'claude-opus':
|
|
16858
|
-
'claude-haiku': 0
|
|
16931
|
+
'claude-opus': 5.0,
|
|
16932
|
+
'claude-haiku': 1.0,
|
|
16859
16933
|
'gpt-4o': 2.5,
|
|
16860
16934
|
'gpt-4o-mini': 0.15,
|
|
16861
16935
|
'gemini-1.5-pro': 1.25,
|
|
@@ -18084,7 +18158,7 @@ function __tryGit(args, opts = {}) {
|
|
|
18084
18158
|
catch (_) { return ''; }
|
|
18085
18159
|
}
|
|
18086
18160
|
|
|
18087
|
-
const VERSION = '8.
|
|
18161
|
+
const VERSION = '8.8.0';
|
|
18088
18162
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
18089
18163
|
|
|
18090
18164
|
function requireSourceOrBundled(key) {
|
|
@@ -18197,6 +18271,10 @@ function walkDir(dir, exclude, maxDepth, depth = 0) {
|
|
|
18197
18271
|
} catch (_) {
|
|
18198
18272
|
return [];
|
|
18199
18273
|
}
|
|
18274
|
+
// Sort by name so the collected file list — and therefore the output section
|
|
18275
|
+
// order — is deterministic. Raw readdir order is filesystem-dependent and can
|
|
18276
|
+
// vary run to run, making the generated context non-byte-stable.
|
|
18277
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
18200
18278
|
for (const entry of entries) {
|
|
18201
18279
|
if (exclude.includes(entry.name)) continue;
|
|
18202
18280
|
const full = path.join(dir, entry.name);
|
|
@@ -18408,10 +18486,15 @@ function applyTokenBudget(fileEntries, maxTokens) {
|
|
|
18408
18486
|
});
|
|
18409
18487
|
|
|
18410
18488
|
// Best-first order: lowest drop-priority, then most-recent, then most-informative.
|
|
18489
|
+
// Final tie-break on filePath keeps the selection deterministic when priority,
|
|
18490
|
+
// mtime, and signalQuality all tie (common for test files sharing a git-checkout
|
|
18491
|
+
// mtime) — otherwise the choice fell through to filesystem readdir order, making
|
|
18492
|
+
// which files are kept vs dropped non-reproducible run to run.
|
|
18411
18493
|
const bestFirst = withPriority.slice().sort((a, b) => {
|
|
18412
18494
|
if (a.priority !== b.priority) return a.priority - b.priority;
|
|
18413
18495
|
if ((b.mtime || 0) !== (a.mtime || 0)) return (b.mtime || 0) - (a.mtime || 0);
|
|
18414
|
-
return (b.signalQuality || 0) - (a.signalQuality || 0);
|
|
18496
|
+
if ((b.signalQuality || 0) !== (a.signalQuality || 0)) return (b.signalQuality || 0) - (a.signalQuality || 0);
|
|
18497
|
+
return a.filePath.localeCompare(b.filePath);
|
|
18415
18498
|
});
|
|
18416
18499
|
|
|
18417
18500
|
const entryCost = (e) => estimateTokens(e.sigs.join('\n')) + sectionOverhead(e);
|
|
@@ -19910,6 +19993,7 @@ Usage:
|
|
|
19910
19993
|
${cmd} review-pr --markdown PR Evidence Report — branded Markdown (signatures + blast radius + tests) to post as a PR comment
|
|
19911
19994
|
${cmd} create "<task>" Grounded-creation pipeline: scaffold → verify-plan → verify-ai-output → review-pr (--staged)
|
|
19912
19995
|
${cmd} squeeze <file|-> Minimize a pasted stacktrace/CI-log/JSON blob (--json for stats)
|
|
19996
|
+
${cmd} squeeze --response <file|-> Minimize an agent/tool response (same engine; also exposed as the squeeze_output MCP tool)
|
|
19913
19997
|
${cmd} ask "<query>" --squeeze Auto-accept input minimization (no prompt; for scripts/CI)
|
|
19914
19998
|
${cmd} ask "<query>" --no-squeeze Disable input minimization entirely
|
|
19915
19999
|
${cmd} ask "<query>" --squeeze-threshold N Min reduction %% to prompt (default 30)
|
|
@@ -21680,7 +21764,20 @@ function main() {
|
|
|
21680
21764
|
// v7.0.0: `sigmap squeeze <file|->` — minimize a pasted stacktrace / CI-log / JSON blob
|
|
21681
21765
|
if (args[0] === 'squeeze') {
|
|
21682
21766
|
const jsonOut = args.includes('--json');
|
|
21683
|
-
|
|
21767
|
+
// `--response <file|->` names the agent/tool response to squeeze explicitly
|
|
21768
|
+
// (mirrors `sigmap judge --response`); otherwise fall back to the positional arg.
|
|
21769
|
+
const respIdx = args.indexOf('--response');
|
|
21770
|
+
let target;
|
|
21771
|
+
if (respIdx !== -1) {
|
|
21772
|
+
const val = args[respIdx + 1];
|
|
21773
|
+
if (!val || val.startsWith('--')) {
|
|
21774
|
+
console.error('[sigmap] Usage: sigmap squeeze --response <file|-> [--json]');
|
|
21775
|
+
process.exit(1);
|
|
21776
|
+
}
|
|
21777
|
+
target = val;
|
|
21778
|
+
} else {
|
|
21779
|
+
target = args[1] && !args[1].startsWith('--') ? args[1] : '-';
|
|
21780
|
+
}
|
|
21684
21781
|
let input = '';
|
|
21685
21782
|
try {
|
|
21686
21783
|
input = fs.readFileSync(target === '-' ? 0 : path.resolve(cwd, target), 'utf8');
|
package/llms-full.txt
CHANGED
|
@@ -11,22 +11,22 @@ 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.8.0 | Benchmark: sigmap-v8.8-main (2026-07-05)
|
|
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.8-main, 2026-07-05)
|
|
21
21
|
|
|
22
22
|
| Metric | Without SigMap | With SigMap |
|
|
23
23
|
|--------|----------------|-------------|
|
|
24
24
|
| Retrieval hit@5 | 13.6% (random) | 87.8% (6.5× lift) |
|
|
25
25
|
| Token reduction | — | 97.0% average |
|
|
26
|
-
| Task success proxy | 10% |
|
|
27
|
-
| Prompts per task | 2.84 | 1.
|
|
26
|
+
| Task success proxy | 10% | 67.8% |
|
|
27
|
+
| Prompts per task | 2.84 | 1.44 (49.2% fewer) |
|
|
28
28
|
| Supported languages | — | 33 |
|
|
29
|
-
| MCP tools | — |
|
|
29
|
+
| MCP tools | — | 19 |
|
|
30
30
|
| npm runtime dependencies | — | 0 |
|
|
31
31
|
|
|
32
32
|
---
|
|
@@ -113,6 +113,7 @@ sigmap review-pr Audit a diff — scope drift, god-node
|
|
|
113
113
|
sigmap review-pr --markdown PR Evidence Report — branded Markdown (signatures + blast radius + tests) to post as a PR comment
|
|
114
114
|
sigmap create "<task>" Grounded-creation pipeline: scaffold → verify-plan → verify-ai-output → review-pr (--staged)
|
|
115
115
|
sigmap squeeze <file|-> Minimize a pasted stacktrace/CI-log/JSON blob (--json for stats)
|
|
116
|
+
sigmap squeeze --response <file|-> Minimize an agent/tool response (same engine; also exposed as the squeeze_output MCP tool)
|
|
116
117
|
sigmap ask "<query>" --squeeze Auto-accept input minimization (no prompt; for scripts/CI)
|
|
117
118
|
sigmap ask "<query>" --no-squeeze Disable input minimization entirely
|
|
118
119
|
sigmap ask "<query>" --squeeze-threshold N Min reduction %% to prompt (default 30)
|
|
@@ -132,7 +133,7 @@ sigmap --version Show version
|
|
|
132
133
|
|
|
133
134
|
---
|
|
134
135
|
|
|
135
|
-
## MCP server —
|
|
136
|
+
## MCP server — 19 tools
|
|
136
137
|
|
|
137
138
|
Start with `sigmap --mcp` (stdio JSON-RPC). Configure once:
|
|
138
139
|
|
|
@@ -284,6 +285,14 @@ Ground an AI code suggestion before writing it: verify a snippet or answer again
|
|
|
284
285
|
Input: { code: string }
|
|
285
286
|
```
|
|
286
287
|
|
|
288
|
+
### squeeze_output
|
|
289
|
+
|
|
290
|
+
Compress noisy tool, command, or agent output before it enters context — a stack trace, CI/build log, or JSON payload. Same deterministic, offline engine as `sigmap squeeze`: keeps the signal (error frames, failing steps, JSON shape), strips the noise, and enriches the top stack frame with its signature. Returns the squeezed text plus token-reduction stats; passes the input through unchanged when no squeezable structure is detected. No LLM, no network.
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
Input: { content: string }
|
|
294
|
+
```
|
|
295
|
+
|
|
287
296
|
---
|
|
288
297
|
|
|
289
298
|
## Configuration (gen-context.config.json)
|
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.8.0 | Benchmark: sigmap-v8.8-main (2026-07-05)
|
|
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,13 +23,13 @@ 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.8-main, 2026-07-05)
|
|
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
|
|
30
|
-
- Task success:
|
|
31
|
-
- Prompts per task: 1.
|
|
32
|
-
- Languages: 33 supported · MCP tools:
|
|
30
|
+
- Task success: 67.8% vs 10% without SigMap
|
|
31
|
+
- Prompts per task: 1.44 vs 2.84 baseline (49.2% fewer)
|
|
32
|
+
- Languages: 33 supported · MCP tools: 19
|
|
33
33
|
- Dependencies: zero npm runtime dependencies · fully offline
|
|
34
34
|
|
|
35
35
|
## Quick start
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigmap",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.8.0",
|
|
4
4
|
"description": "97% token reduction for AI coding. Extracts function & class signatures with TF-IDF ranking to feed only the right files to Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP. Zero dependencies, runs offline via npx.",
|
|
5
5
|
"main": "packages/core/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -43,7 +43,11 @@ function resolveSourceRoots(cwd, opts = {}) {
|
|
|
43
43
|
score: scoreCandidate(name, full, context),
|
|
44
44
|
}))
|
|
45
45
|
.filter(c => c.score > 0)
|
|
46
|
-
|
|
46
|
+
// Final tie-break on dir keeps selection deterministic when scores tie — the
|
|
47
|
+
// top-MAX_ROOTS slice below would otherwise admit different dirs run to run
|
|
48
|
+
// (candidate order comes from filesystem readdir), changing which files are
|
|
49
|
+
// collected and making the generated context non-reproducible.
|
|
50
|
+
.sort((a, b) => b.score - a.score || a.dir.localeCompare(b.dir));
|
|
47
51
|
|
|
48
52
|
// Handle special rules
|
|
49
53
|
let roots = _applySpecialRules(scored, cwd, primaryFw, fwEntry, frameworks);
|
|
@@ -86,9 +90,12 @@ function _enumerateCandidates(cwd, isMonorepo, ignorePatterns, excludeList) {
|
|
|
86
90
|
const candidates = [];
|
|
87
91
|
const excSet = new Set(excludeList);
|
|
88
92
|
|
|
89
|
-
// Root-level dirs
|
|
93
|
+
// Root-level dirs (sorted so candidate order — and downstream dedupe/selection
|
|
94
|
+
// — is deterministic regardless of filesystem readdir order)
|
|
90
95
|
try {
|
|
91
|
-
|
|
96
|
+
const rootEntries = fs.readdirSync(cwd, { withFileTypes: true })
|
|
97
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
98
|
+
for (const e of rootEntries) {
|
|
92
99
|
if (!e.isDirectory()) continue;
|
|
93
100
|
if (excSet.has(e.name)) continue;
|
|
94
101
|
if (matchesIgnorePattern(e.name, ignorePatterns)) continue;
|
|
@@ -157,7 +164,7 @@ function _applySpecialRules(scored, cwd, primaryFw, fwEntry, frameworks) {
|
|
|
157
164
|
}
|
|
158
165
|
}
|
|
159
166
|
} catch (_) {}
|
|
160
|
-
roots.sort((a, b) => b.score - a.score);
|
|
167
|
+
roots.sort((a, b) => b.score - a.score || a.dir.localeCompare(b.dir));
|
|
161
168
|
}
|
|
162
169
|
|
|
163
170
|
// Swift project dir: dirs with ≥3 .swift files
|
|
@@ -172,7 +179,7 @@ function _applySpecialRules(scored, cwd, primaryFw, fwEntry, frameworks) {
|
|
|
172
179
|
}
|
|
173
180
|
}
|
|
174
181
|
} catch (_) {}
|
|
175
|
-
roots.sort((a, b) => b.score - a.score);
|
|
182
|
+
roots.sort((a, b) => b.score - a.score || a.dir.localeCompare(b.dir));
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
return roots;
|
package/src/mcp/handlers.js
CHANGED
|
@@ -898,4 +898,47 @@ function verifySuggestion(args, cwd) {
|
|
|
898
898
|
return out.join('\n');
|
|
899
899
|
}
|
|
900
900
|
|
|
901
|
-
|
|
901
|
+
/**
|
|
902
|
+
* squeeze_output({ content }) → string
|
|
903
|
+
*
|
|
904
|
+
* Compress noisy tool/command/agent output (stack trace, CI/build log, or JSON
|
|
905
|
+
* payload) through the deterministic squeeze engine. Enriches the top stack
|
|
906
|
+
* frame with its signature when the symbol index is available. Passes the input
|
|
907
|
+
* through unchanged when no squeezable structure is detected.
|
|
908
|
+
*/
|
|
909
|
+
function squeezeOutput(args, cwd) {
|
|
910
|
+
const content = args && typeof args.content === 'string' ? args.content : '';
|
|
911
|
+
if (!content.trim()) {
|
|
912
|
+
return 'Usage: squeeze_output({ content: "<raw tool/log/JSON output>" }) — provide the output to compress.';
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
let sq;
|
|
916
|
+
try {
|
|
917
|
+
const { squeeze } = require('../squeeze/index');
|
|
918
|
+
let srcDirs;
|
|
919
|
+
let symbolIndex = null;
|
|
920
|
+
try {
|
|
921
|
+
const { loadConfig } = require('../config/loader');
|
|
922
|
+
srcDirs = loadConfig(cwd).srcDirs;
|
|
923
|
+
} catch (_) {}
|
|
924
|
+
try {
|
|
925
|
+
const { buildSigIndex } = require('../retrieval/ranker');
|
|
926
|
+
symbolIndex = buildSigIndex(cwd);
|
|
927
|
+
} catch (_) {}
|
|
928
|
+
sq = squeeze(content, { srcDirs, symbolIndex });
|
|
929
|
+
} catch (err) {
|
|
930
|
+
return `_squeeze_output failed: ${err.message}_`;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
if (!sq.category || !sq.applies) {
|
|
934
|
+
return `No squeezable structure detected — content unchanged (${sq.rawTokens} tokens).\n\n${content}`;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const pct = Math.round(sq.reduction * 100);
|
|
938
|
+
const header =
|
|
939
|
+
`Squeezed ${sq.category} — ${sq.rawTokens} → ${sq.squeezedTokens} tokens ` +
|
|
940
|
+
`(${pct}% smaller)${sq.enriched ? ' · signature-enriched' : ''}\n\n`;
|
|
941
|
+
return header + sq.squeezed;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
module.exports = { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getImpact, getLines, readMemory, getCalleeSignatures, notifyFileCreated, notifySymbolAdded, notifyFileDeleted, getDiffContext, getArchitectureOverview, verifySuggestion, squeezeOutput };
|
package/src/mcp/server.js
CHANGED
|
@@ -8,17 +8,17 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Supported methods:
|
|
10
10
|
* initialize → serverInfo + capabilities
|
|
11
|
-
* tools/list →
|
|
11
|
+
* tools/list → 19 tool definitions
|
|
12
12
|
* tools/call → dispatch to handler, return result
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
const readline = require('readline');
|
|
16
16
|
const { TOOLS } = require('./tools');
|
|
17
|
-
const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getImpact, getLines, readMemory, getCalleeSignatures, notifyFileCreated, notifySymbolAdded, notifyFileDeleted, getDiffContext, getArchitectureOverview, verifySuggestion } = require('./handlers');
|
|
17
|
+
const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getImpact, getLines, readMemory, getCalleeSignatures, notifyFileCreated, notifySymbolAdded, notifyFileDeleted, getDiffContext, getArchitectureOverview, verifySuggestion, squeezeOutput } = require('./handlers');
|
|
18
18
|
|
|
19
19
|
const SERVER_INFO = {
|
|
20
20
|
name: 'sigmap',
|
|
21
|
-
version: '8.
|
|
21
|
+
version: '8.8.0',
|
|
22
22
|
description: 'SigMap MCP server — code signatures on demand',
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -84,6 +84,7 @@ function dispatch(msg, cwd) {
|
|
|
84
84
|
else if (name === 'get_diff_context') text = getDiffContext(args, cwd);
|
|
85
85
|
else if (name === 'get_architecture_overview') text = getArchitectureOverview(args, cwd);
|
|
86
86
|
else if (name === 'verify_suggestion') text = verifySuggestion(args, cwd);
|
|
87
|
+
else if (name === 'squeeze_output') text = squeezeOutput(args, cwd);
|
|
87
88
|
else {
|
|
88
89
|
respondError(id, -32601, `Unknown tool: ${name}`);
|
|
89
90
|
return;
|
package/src/mcp/tools.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* MCP tool definitions for SigMap (
|
|
4
|
+
* MCP tool definitions for SigMap (19 tools).
|
|
5
5
|
* read_context, search_signatures, get_map, create_checkpoint, get_routing,
|
|
6
6
|
* explain_file, list_modules, query_context, get_impact, get_lines, read_memory,
|
|
7
7
|
* get_callee_signatures, sigmap_notify_file_created, sigmap_notify_symbol_added,
|
|
8
|
-
* sigmap_notify_file_deleted, get_diff_context, get_architecture_overview
|
|
8
|
+
* sigmap_notify_file_deleted, get_diff_context, get_architecture_overview,
|
|
9
|
+
* verify_suggestion, squeeze_output.
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
const TOOLS = [
|
|
@@ -336,6 +337,27 @@ const TOOLS = [
|
|
|
336
337
|
required: ['code'],
|
|
337
338
|
},
|
|
338
339
|
},
|
|
340
|
+
{
|
|
341
|
+
name: 'squeeze_output',
|
|
342
|
+
description:
|
|
343
|
+
'Compress noisy tool, command, or agent output before it enters context — a stack ' +
|
|
344
|
+
'trace, CI/build log, or JSON payload. Same deterministic, offline engine as ' +
|
|
345
|
+
'`sigmap squeeze`: keeps the signal (error frames, failing steps, JSON shape), strips ' +
|
|
346
|
+
'the noise, and enriches the top stack frame with its signature. Returns the squeezed ' +
|
|
347
|
+
'text plus token-reduction stats; passes the input through unchanged when no squeezable ' +
|
|
348
|
+
'structure is detected. No LLM, no network.',
|
|
349
|
+
inputSchema: {
|
|
350
|
+
type: 'object',
|
|
351
|
+
properties: {
|
|
352
|
+
content: {
|
|
353
|
+
type: 'string',
|
|
354
|
+
description:
|
|
355
|
+
'The raw output to compress (a stack trace, CI/build log, or JSON payload).',
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
required: ['content'],
|
|
359
|
+
},
|
|
360
|
+
},
|
|
339
361
|
];
|
|
340
362
|
|
|
341
363
|
module.exports = { TOOLS };
|
package/src/tracking/pricing.js
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
* presented as exact. Zero npm dependencies.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
// USD per 1,000,000 input tokens.
|
|
13
|
+
// USD per 1,000,000 input tokens. Claude rates verified 2026-07 against
|
|
14
|
+
// platform.claude.com (Opus 4.8 $5, Sonnet 5/4.6 $3, Haiku 4.5 $1); GPT-4o $2.50.
|
|
14
15
|
const PRICES = {
|
|
15
16
|
'claude-sonnet': 3.0,
|
|
16
|
-
'claude-opus':
|
|
17
|
-
'claude-haiku': 0
|
|
17
|
+
'claude-opus': 5.0,
|
|
18
|
+
'claude-haiku': 1.0,
|
|
18
19
|
'gpt-4o': 2.5,
|
|
19
20
|
'gpt-4o-mini': 0.15,
|
|
20
21
|
'gemini-1.5-pro': 1.25,
|