sigmap 8.7.1 → 8.8.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 +23 -0
- package/README.md +9 -9
- package/gen-context.js +136 -17
- package/llms-full.txt +15 -6
- package/llms.txt +5 -5
- package/package.json +2 -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/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,29 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [8.8.1] — 2026-07-05
|
|
14
|
+
|
|
15
|
+
Patch release — **byte-stable context, reproducible benchmark.** Closes the determinism residual tracked in #440: `gen-context` output is now byte-identical run-to-run across all 43 benchmark repos, and the retrieval benchmark reproduces a single hit@5 (87.8%) instead of flapping 85.6–87.8%. Plus a test-count derivation fix, docs/CI serving fixes, and repo hygiene.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **gen-context determinism residual — token-budget recency boost (#440, PR #444):** the recency boost stamped `mtime = Date.now()` on every recently-committed file. On repos where nearly every file is "recently changed", consecutive files often landed on the *same millisecond* — so which equal-priority files shared a millisecond (and thus fell through to the `filePath` tie-break instead of sorting by a distinct mtime) shifted run to run, swapping which files survived at the budget cutoff and making the output non-byte-stable. The `Date.now()` value wasn't just a boost: it encoded the alphabetical walk order that the budget's best-first sort relied on; the nondeterminism was only the millisecond *collisions*. Replaced it with a deterministic monotonic counter (`nextRecentMtime`) that reproduces the exact same processing-order ranking without collisions. Result: all 43 benchmark repos are byte-identical across two clean runs (excluding the `Updated:` timestamp), and retrieval hit@5 reproduces at **87.8%** with identical per-repo results. Adds an integration regression guard (`test/integration/gen-context-determinism.test.js`) that runs gen-context twice on a committed fixture and asserts byte-equality — verified to fail on the old `Date.now()` behaviour.
|
|
19
|
+
- **Derived test count after test relocation (503a6e5):** the test-count derivation globbed `tests/**/*.py`; after relocating `test_python_ast_extractor.py` into `test/` it matched neither pattern and dropped the count, failing `check:metrics` in CI. Now counts `test/**/test_*.py` (unittest-named), which matches the relocated test and excludes the fixture.
|
|
20
|
+
- **Docs / CI serving (b236e08):** serve the OG banner image and the Google Search Console verification file; run the Python extractor tests in CI.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **Repo hygiene (a49e9c5):** dropped orphaned demo GIFs and a dead script; relocated a stray test from `tests/` into `test/`.
|
|
24
|
+
|
|
25
|
+
## [8.8.0] — 2026-07-05
|
|
26
|
+
|
|
27
|
+
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.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **`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`.
|
|
31
|
+
- **`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`.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- **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.
|
|
35
|
+
|
|
13
36
|
## [8.7.1] — 2026-07-05
|
|
14
37
|
|
|
15
38
|
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.
|
package/README.md
CHANGED
|
@@ -57,10 +57,10 @@ That map is exactly what agentic grep is worst at: reproducible, auditable conte
|
|
|
57
57
|
|
|
58
58
|
**Proof it pays off** (full benchmark below):
|
|
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
62
|
- **67.8% task success rate** — up from 10% without context
|
|
63
|
-
- **1.
|
|
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
|
|
@@ -96,7 +96,7 @@ sigmap verify answer.md --report # standalone red/amber/green HTML report
|
|
|
96
96
|
| Without SigMap | With SigMap |
|
|
97
97
|
|---|---|
|
|
98
98
|
| ❌ Non-reproducible agent guesses | ✅ Deterministic map — same input, same output, every time |
|
|
99
|
-
| ❌ "Trust me" AI answers | ✅ Grounded — right file in context <!--SM:hitWhole-->
|
|
99
|
+
| ❌ "Trust me" AI answers | ✅ Grounded — right file in context <!--SM:hitWhole-->88%<!--/SM:hitWhole--> of the time, every symbol on a real line anchor |
|
|
100
100
|
| ❌ Embeddings / vector DB required | ✅ Zero deps, no infra, fully offline |
|
|
101
101
|
|
|
102
102
|
---
|
|
@@ -120,12 +120,12 @@ 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
|
-
Hit@5 :
|
|
126
|
+
Hit@5 : 87.8% (baseline 13.6% — 6.5× lift)
|
|
127
127
|
Token reduction: 97.0% (across 21 repos)
|
|
128
|
-
Prompt reduction :
|
|
128
|
+
Prompt reduction : 49.2% (2.84 → 1.44 prompts per task)
|
|
129
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
|
```
|
|
@@ -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.1',
|
|
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 };
|
|
@@ -18085,7 +18158,7 @@ function __tryGit(args, opts = {}) {
|
|
|
18085
18158
|
catch (_) { return ''; }
|
|
18086
18159
|
}
|
|
18087
18160
|
|
|
18088
|
-
const VERSION = '8.
|
|
18161
|
+
const VERSION = '8.8.1';
|
|
18089
18162
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
18090
18163
|
|
|
18091
18164
|
function requireSourceOrBundled(key) {
|
|
@@ -18198,6 +18271,10 @@ function walkDir(dir, exclude, maxDepth, depth = 0) {
|
|
|
18198
18271
|
} catch (_) {
|
|
18199
18272
|
return [];
|
|
18200
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));
|
|
18201
18278
|
for (const entry of entries) {
|
|
18202
18279
|
if (exclude.includes(entry.name)) continue;
|
|
18203
18280
|
const full = path.join(dir, entry.name);
|
|
@@ -18291,6 +18368,26 @@ function annotateCoverage(sigs, testIndex, enabled) {
|
|
|
18291
18368
|
// ---------------------------------------------------------------------------
|
|
18292
18369
|
// Token budget enforcement
|
|
18293
18370
|
// ---------------------------------------------------------------------------
|
|
18371
|
+
// Deterministic recency boost for recently-committed files so the token budget
|
|
18372
|
+
// doesn't drop them first. Previously this used `Date.now()`, which encoded the
|
|
18373
|
+
// (alphabetical) processing order as a monotonically increasing mtime — but on
|
|
18374
|
+
// repos where nearly every file is "recently changed", consecutive files often
|
|
18375
|
+
// landed on the *same* millisecond. Which files shared a millisecond (and so
|
|
18376
|
+
// fell through to the filePath tie-break instead of sorting by a distinct
|
|
18377
|
+
// mtime) shifted run to run, swapping which files survived at the budget cutoff
|
|
18378
|
+
// and making the output non-byte-stable. A monotonic integer counter preserves
|
|
18379
|
+
// the exact processing-order ranking Date.now() produced — recent files stay
|
|
18380
|
+
// ahead of non-recent ones, ordered among themselves by walk order — but is
|
|
18381
|
+
// collision-free and reproducible. RECENT_MTIME_BASE sits far above any real
|
|
18382
|
+
// filesystem mtime (ms since epoch ≈ 1.7e12) so boosted files always out-rank
|
|
18383
|
+
// non-boosted ones, and far below MAX_SAFE_INTEGER so the counter never
|
|
18384
|
+
// overflows. Call nextRecentMtime() once per boosted file, in walk order. (#440)
|
|
18385
|
+
const RECENT_MTIME_BASE = 1e15;
|
|
18386
|
+
let _recentMtimeSeq = 0;
|
|
18387
|
+
function nextRecentMtime() {
|
|
18388
|
+
return RECENT_MTIME_BASE + (_recentMtimeSeq++);
|
|
18389
|
+
}
|
|
18390
|
+
|
|
18294
18391
|
function estimateTokens(str) {
|
|
18295
18392
|
return Math.ceil(str.length / 4);
|
|
18296
18393
|
}
|
|
@@ -18409,10 +18506,15 @@ function applyTokenBudget(fileEntries, maxTokens) {
|
|
|
18409
18506
|
});
|
|
18410
18507
|
|
|
18411
18508
|
// Best-first order: lowest drop-priority, then most-recent, then most-informative.
|
|
18509
|
+
// Final tie-break on filePath keeps the selection deterministic when priority,
|
|
18510
|
+
// mtime, and signalQuality all tie (common for test files sharing a git-checkout
|
|
18511
|
+
// mtime) — otherwise the choice fell through to filesystem readdir order, making
|
|
18512
|
+
// which files are kept vs dropped non-reproducible run to run.
|
|
18412
18513
|
const bestFirst = withPriority.slice().sort((a, b) => {
|
|
18413
18514
|
if (a.priority !== b.priority) return a.priority - b.priority;
|
|
18414
18515
|
if ((b.mtime || 0) !== (a.mtime || 0)) return (b.mtime || 0) - (a.mtime || 0);
|
|
18415
|
-
return (b.signalQuality || 0) - (a.signalQuality || 0);
|
|
18516
|
+
if ((b.signalQuality || 0) !== (a.signalQuality || 0)) return (b.signalQuality || 0) - (a.signalQuality || 0);
|
|
18517
|
+
return a.filePath.localeCompare(b.filePath);
|
|
18416
18518
|
});
|
|
18417
18519
|
|
|
18418
18520
|
const entryCost = (e) => estimateTokens(e.sigs.join('\n')) + sectionOverhead(e);
|
|
@@ -19266,7 +19368,7 @@ function runDiff(cwd, config, stagedOnly, baseRef) {
|
|
|
19266
19368
|
|
|
19267
19369
|
sigs = annotateCoverage(sigs, testIndex, !!config.testCoverage);
|
|
19268
19370
|
|
|
19269
|
-
fileEntries.push({ filePath, sigs, deps: extractFileDeps(filePath, content, config), content, mtime:
|
|
19371
|
+
fileEntries.push({ filePath, sigs, deps: extractFileDeps(filePath, content, config), content, mtime: nextRecentMtime() });
|
|
19270
19372
|
}
|
|
19271
19373
|
|
|
19272
19374
|
if (fileEntries.length === 0) {
|
|
@@ -19414,8 +19516,11 @@ function runGenerate(cwd, config, reportMode, reportJson = false) {
|
|
|
19414
19516
|
mtime = fs.statSync(filePath).mtimeMs;
|
|
19415
19517
|
} catch (_) {}
|
|
19416
19518
|
|
|
19417
|
-
// Boost recently committed files (give them max mtime so they aren't
|
|
19418
|
-
|
|
19519
|
+
// Boost recently committed files (give them a max mtime so they aren't
|
|
19520
|
+
// dropped first). A deterministic monotonic counter — not Date.now() — keeps
|
|
19521
|
+
// the budget selection byte-stable when many files are recent, while
|
|
19522
|
+
// preserving the original processing-order ranking (see nextRecentMtime, #440).
|
|
19523
|
+
if (recentFiles.has(filePath)) mtime = nextRecentMtime();
|
|
19419
19524
|
|
|
19420
19525
|
fileEntries.push({ filePath, sigs, deps: extractFileDeps(filePath, content, config), content, mtime });
|
|
19421
19526
|
}
|
|
@@ -19911,6 +20016,7 @@ Usage:
|
|
|
19911
20016
|
${cmd} review-pr --markdown PR Evidence Report — branded Markdown (signatures + blast radius + tests) to post as a PR comment
|
|
19912
20017
|
${cmd} create "<task>" Grounded-creation pipeline: scaffold → verify-plan → verify-ai-output → review-pr (--staged)
|
|
19913
20018
|
${cmd} squeeze <file|-> Minimize a pasted stacktrace/CI-log/JSON blob (--json for stats)
|
|
20019
|
+
${cmd} squeeze --response <file|-> Minimize an agent/tool response (same engine; also exposed as the squeeze_output MCP tool)
|
|
19914
20020
|
${cmd} ask "<query>" --squeeze Auto-accept input minimization (no prompt; for scripts/CI)
|
|
19915
20021
|
${cmd} ask "<query>" --no-squeeze Disable input minimization entirely
|
|
19916
20022
|
${cmd} ask "<query>" --squeeze-threshold N Min reduction %% to prompt (default 30)
|
|
@@ -21681,7 +21787,20 @@ function main() {
|
|
|
21681
21787
|
// v7.0.0: `sigmap squeeze <file|->` — minimize a pasted stacktrace / CI-log / JSON blob
|
|
21682
21788
|
if (args[0] === 'squeeze') {
|
|
21683
21789
|
const jsonOut = args.includes('--json');
|
|
21684
|
-
|
|
21790
|
+
// `--response <file|->` names the agent/tool response to squeeze explicitly
|
|
21791
|
+
// (mirrors `sigmap judge --response`); otherwise fall back to the positional arg.
|
|
21792
|
+
const respIdx = args.indexOf('--response');
|
|
21793
|
+
let target;
|
|
21794
|
+
if (respIdx !== -1) {
|
|
21795
|
+
const val = args[respIdx + 1];
|
|
21796
|
+
if (!val || val.startsWith('--')) {
|
|
21797
|
+
console.error('[sigmap] Usage: sigmap squeeze --response <file|-> [--json]');
|
|
21798
|
+
process.exit(1);
|
|
21799
|
+
}
|
|
21800
|
+
target = val;
|
|
21801
|
+
} else {
|
|
21802
|
+
target = args[1] && !args[1].startsWith('--') ? args[1] : '-';
|
|
21803
|
+
}
|
|
21685
21804
|
let input = '';
|
|
21686
21805
|
try {
|
|
21687
21806
|
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.1 | 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
|
-
| Retrieval hit@5 | 13.6% (random) |
|
|
24
|
+
| Retrieval hit@5 | 13.6% (random) | 87.8% (6.5× lift) |
|
|
25
25
|
| Token reduction | — | 97.0% average |
|
|
26
26
|
| Task success proxy | 10% | 67.8% |
|
|
27
|
-
| Prompts per task | 2.84 | 1.
|
|
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.1 | 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
|
-
- hit@5 retrieval:
|
|
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
30
|
- Task success: 67.8% vs 10% without SigMap
|
|
31
|
-
- Prompts per task: 1.
|
|
32
|
-
- Languages: 33 supported · MCP tools:
|
|
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.1",
|
|
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": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"test": "node test/run.js && node test/r-language.test.js",
|
|
18
18
|
"test:integration": "node test/integration/strategy.test.js && node test/integration/secret-scan.test.js && node test/integration/token-budget.test.js && node test/integration/auto-budget.test.js && node test/integration/mcp/server.test.js && node test/integration/verify-ai-output.test.js && node test/integration/memory-tools.test.js && node test/integration/squeeze.test.js && node test/integration/context-consistency.test.js && node test/integration/features/llms-current.test.js",
|
|
19
19
|
"test:integration:all": "node test/integration/all.js",
|
|
20
|
+
"test:python": "python3 test/test_python_ast_extractor.py",
|
|
20
21
|
"test:all": "node test/run.js && node test/r-language.test.js && node test/integration/strategy.test.js && node test/integration/secret-scan.test.js",
|
|
21
22
|
"generate": "node gen-context.js",
|
|
22
23
|
"watch": "node gen-context.js --watch",
|
|
@@ -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.1',
|
|
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 };
|