sigmap 8.28.0 → 8.28.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 +13 -0
- package/README.md +1 -1
- package/gen-context.js +37 -16
- package/llms-full.txt +2 -2
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/graph/builder.js +20 -12
- package/src/mcp/server.js +1 -1
- package/src/retrieval/ranker.js +15 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,19 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [8.28.1] — 2026-08-22
|
|
14
|
+
|
|
15
|
+
Patch release — two silent-failure bug fixes: a false "zero importers" in the Python import graph, and an empty index under the per-module strategy.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Python absolute imports resolve through any ancestor root (#532, PR #533)** — reported and precisely diagnosed by **@ruurdboeke**, thank you: `extractFileDeps` probed only the importing file's directory and one parent for `from package.module import`, so `src/`-layout projects (source root on `sys.path`) silently produced no graph edge whenever the importer sat two or more directories below the root — and `get_impact` then reported **zero importers**, exactly the signal that says a change is safe to make. Fix: an ancestor walk from the importing file up to the project root (nearest first, 16-level cap), probing `<module>.py` and `<module>/__init__.py` per level; nearest-first preserves the old first-match semantics for same-dir/one-parent cases. 4 new tests incl. the verbatim issue repro and `get_impact` end-to-end.
|
|
19
|
+
- **Per-module strategy: `ask`/`query_context` find signatures again (#534, PR #535):** the per-module strategy writes one `context-<module>.md` per top-level srcDir and leaves the primary file as a thin overview — but the sig-index strategy enrichment merged only `context-cold.md` (hot-cold) plus the cache, so `sigmap ask` failed with "no context file found" and the `query_context` MCP tool returned an empty index on every per-module repo. Fix: enumerate `.github/context-*.md` (sorted, deterministic) and merge each — the cold-file merge generalized to every strategy split. 4 new tests on a real generated two-module fixture incl. the exact reported failure; hot-cold and full strategies verified unchanged.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- 8 new integration tests (138 test files); bundle rebuilt; zero new dependencies.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
13
26
|
## [8.28.0] — 2026-08-18
|
|
14
27
|
|
|
15
28
|
Minor release — **"Arity Guard" (v8.28, D1)**: verification now checks not just *does this function exist* but *is it being called with a plausible number of arguments* — the payoff of the v8.27 balanced scanner.
|
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ Ask → Rank → Context → Validate → Judge → Learn
|
|
|
123
123
|
<!--SM:benchmarkBlock-->
|
|
124
124
|
```
|
|
125
125
|
Benchmark : sigmap-v8.28-main (21 repositories, including R language)
|
|
126
|
-
Date : 2026-08-
|
|
126
|
+
Date : 2026-08-22
|
|
127
127
|
|
|
128
128
|
Hit@5 : 81.1% (grep-agent baseline 44.0% — 1.73× lift)
|
|
129
129
|
Token reduction: 96.8% (across 21 repos)
|
package/gen-context.js
CHANGED
|
@@ -11573,23 +11573,31 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
11573
11573
|
}
|
|
11574
11574
|
}
|
|
11575
11575
|
|
|
11576
|
-
// Absolute imports: from package.module import ... (infer from project
|
|
11576
|
+
// Absolute imports: from package.module import ... (infer from project
|
|
11577
|
+
// structure). The module is resolved against EVERY ancestor of the
|
|
11578
|
+
// importing file up to the project root, nearest first — any of them can
|
|
11579
|
+
// be the source root on sys.path (src/ layouts, pytest rootdir). The old
|
|
11580
|
+
// dir + one-parent probe silently dropped edges for files nested two or
|
|
11581
|
+
// more directories below the source root (#532), and a false "zero
|
|
11582
|
+
// importers" from get_impact is exactly the signal that says a change is
|
|
11583
|
+
// safe to make.
|
|
11577
11584
|
const reAbs = /^[ \t]*from\s+([\w.]+)\s+import/gm;
|
|
11578
11585
|
while ((m = reAbs.exec(content)) !== null) {
|
|
11579
11586
|
const modulePath = m[1].replace(/\./g, '/');
|
|
11580
|
-
const
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
path.
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
const normC = normalizePath(c);
|
|
11588
|
-
if (fileSet.has(normC)) {
|
|
11589
|
-
found.push(normC);
|
|
11590
|
-
break;
|
|
11587
|
+
const normCwd = normalizePath(path.resolve(cwd));
|
|
11588
|
+
let base = dir;
|
|
11589
|
+
let hit = null;
|
|
11590
|
+
for (let depth = 0; depth < 16 && !hit; depth++) {
|
|
11591
|
+
for (const c of [path.join(base, modulePath + '.py'), path.join(base, modulePath, '__init__.py')]) {
|
|
11592
|
+
const normC = normalizePath(c);
|
|
11593
|
+
if (fileSet.has(normC)) { hit = normC; break; }
|
|
11591
11594
|
}
|
|
11595
|
+
if (normalizePath(base) === normCwd) break;
|
|
11596
|
+
const parent = path.dirname(base);
|
|
11597
|
+
if (parent === base) break;
|
|
11598
|
+
base = parent;
|
|
11592
11599
|
}
|
|
11600
|
+
if (hit) found.push(hit);
|
|
11593
11601
|
}
|
|
11594
11602
|
}
|
|
11595
11603
|
|
|
@@ -15385,7 +15393,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
15385
15393
|
|
|
15386
15394
|
const SERVER_INFO = {
|
|
15387
15395
|
name: 'sigmap',
|
|
15388
|
-
version: '8.28.
|
|
15396
|
+
version: '8.28.1',
|
|
15389
15397
|
description: 'SigMap MCP server — code signatures on demand',
|
|
15390
15398
|
};
|
|
15391
15399
|
|
|
@@ -16975,9 +16983,22 @@ __factories["./src/retrieval/ranker"] = function(module, exports) {
|
|
|
16975
16983
|
* @returns {Map<string, string[]>}
|
|
16976
16984
|
*/
|
|
16977
16985
|
function _enrichSigIndexFromStrategy(cwd, index) {
|
|
16986
|
+
const fs = require('fs');
|
|
16978
16987
|
const path = require('path');
|
|
16979
|
-
|
|
16980
|
-
|
|
16988
|
+
// Merge every strategy split file: context-cold.md (hot-cold) AND each
|
|
16989
|
+
// per-module context-<module>.md — the per-module strategy stores ALL
|
|
16990
|
+
// signatures in these, leaving the primary file as a thin overview, so
|
|
16991
|
+
// skipping them made ask/query_context see an empty index (#534).
|
|
16992
|
+
// Sorted for deterministic merge order.
|
|
16993
|
+
try {
|
|
16994
|
+
const ghDir = path.join(cwd, '.github');
|
|
16995
|
+
const splits = fs.readdirSync(ghDir)
|
|
16996
|
+
.filter((f) => /^context-[\w.-]+\.md$/.test(f))
|
|
16997
|
+
.sort();
|
|
16998
|
+
for (const f of splits) {
|
|
16999
|
+
_mergeSigIndex(index, _parseContextFile(path.join(ghDir, f)));
|
|
17000
|
+
}
|
|
17001
|
+
} catch (_) {}
|
|
16981
17002
|
_mergeSigIndex(index, _buildSigIndexFromCache(cwd));
|
|
16982
17003
|
return index;
|
|
16983
17004
|
}
|
|
@@ -21214,7 +21235,7 @@ function __tryGit(args, opts = {}) {
|
|
|
21214
21235
|
catch (_) { return ''; }
|
|
21215
21236
|
}
|
|
21216
21237
|
|
|
21217
|
-
const VERSION = '8.28.
|
|
21238
|
+
const VERSION = '8.28.1';
|
|
21218
21239
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
21219
21240
|
|
|
21220
21241
|
function requireSourceOrBundled(key) {
|
package/llms-full.txt
CHANGED
|
@@ -11,13 +11,13 @@ 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.28.
|
|
14
|
+
# Version: 8.28.1 | Benchmark: sigmap-v8.28-main (2026-08-22)
|
|
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.28-main, 2026-08-
|
|
20
|
+
## Core metrics (benchmark: sigmap-v8.28-main, 2026-08-22)
|
|
21
21
|
|
|
22
22
|
| Metric | Without SigMap | With SigMap |
|
|
23
23
|
|--------|----------------|-------------|
|
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.28.
|
|
14
|
+
# Version: 8.28.1 | Benchmark: sigmap-v8.28-main (2026-08-22)
|
|
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,7 +23,7 @@ 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.28-main, 2026-08-
|
|
26
|
+
## Core metrics (benchmark: sigmap-v8.28-main, 2026-08-22)
|
|
27
27
|
|
|
28
28
|
- hit@5 retrieval: 81.1% vs 44.0% single-shot grep baseline (1.73× lift)
|
|
29
29
|
- Token reduction: 96.8% average across benchmark repos
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigmap",
|
|
3
|
-
"version": "8.28.
|
|
3
|
+
"version": "8.28.1",
|
|
4
4
|
"description": "The deterministic, verifiable grounding layer for AI code work — a zero-dependency signature-and-evidence map that grounds Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP agents against your real code (repo + installed libraries) so they stop hallucinating files, imports & APIs. Runs offline via npx; byte-stable output; ~97% token reduction as proof.",
|
|
5
5
|
"main": "packages/core/index.js",
|
|
6
6
|
"exports": {
|
package/src/graph/builder.js
CHANGED
|
@@ -240,23 +240,31 @@ function extractFileDeps(filePath, content, fileSet, cwd, ctx) {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
// Absolute imports: from package.module import ... (infer from project
|
|
243
|
+
// Absolute imports: from package.module import ... (infer from project
|
|
244
|
+
// structure). The module is resolved against EVERY ancestor of the
|
|
245
|
+
// importing file up to the project root, nearest first — any of them can
|
|
246
|
+
// be the source root on sys.path (src/ layouts, pytest rootdir). The old
|
|
247
|
+
// dir + one-parent probe silently dropped edges for files nested two or
|
|
248
|
+
// more directories below the source root (#532), and a false "zero
|
|
249
|
+
// importers" from get_impact is exactly the signal that says a change is
|
|
250
|
+
// safe to make.
|
|
244
251
|
const reAbs = /^[ \t]*from\s+([\w.]+)\s+import/gm;
|
|
245
252
|
while ((m = reAbs.exec(content)) !== null) {
|
|
246
253
|
const modulePath = m[1].replace(/\./g, '/');
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
path.
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const normC = normalizePath(c);
|
|
255
|
-
if (fileSet.has(normC)) {
|
|
256
|
-
found.push(normC);
|
|
257
|
-
break;
|
|
254
|
+
const normCwd = normalizePath(path.resolve(cwd));
|
|
255
|
+
let base = dir;
|
|
256
|
+
let hit = null;
|
|
257
|
+
for (let depth = 0; depth < 16 && !hit; depth++) {
|
|
258
|
+
for (const c of [path.join(base, modulePath + '.py'), path.join(base, modulePath, '__init__.py')]) {
|
|
259
|
+
const normC = normalizePath(c);
|
|
260
|
+
if (fileSet.has(normC)) { hit = normC; break; }
|
|
258
261
|
}
|
|
262
|
+
if (normalizePath(base) === normCwd) break;
|
|
263
|
+
const parent = path.dirname(base);
|
|
264
|
+
if (parent === base) break;
|
|
265
|
+
base = parent;
|
|
259
266
|
}
|
|
267
|
+
if (hit) found.push(hit);
|
|
260
268
|
}
|
|
261
269
|
}
|
|
262
270
|
|
package/src/mcp/server.js
CHANGED
package/src/retrieval/ranker.js
CHANGED
|
@@ -473,9 +473,22 @@ function _buildSigIndexFromCache(cwd) {
|
|
|
473
473
|
* @returns {Map<string, string[]>}
|
|
474
474
|
*/
|
|
475
475
|
function _enrichSigIndexFromStrategy(cwd, index) {
|
|
476
|
+
const fs = require('fs');
|
|
476
477
|
const path = require('path');
|
|
477
|
-
|
|
478
|
-
|
|
478
|
+
// Merge every strategy split file: context-cold.md (hot-cold) AND each
|
|
479
|
+
// per-module context-<module>.md — the per-module strategy stores ALL
|
|
480
|
+
// signatures in these, leaving the primary file as a thin overview, so
|
|
481
|
+
// skipping them made ask/query_context see an empty index (#534).
|
|
482
|
+
// Sorted for deterministic merge order.
|
|
483
|
+
try {
|
|
484
|
+
const ghDir = path.join(cwd, '.github');
|
|
485
|
+
const splits = fs.readdirSync(ghDir)
|
|
486
|
+
.filter((f) => /^context-[\w.-]+\.md$/.test(f))
|
|
487
|
+
.sort();
|
|
488
|
+
for (const f of splits) {
|
|
489
|
+
_mergeSigIndex(index, _parseContextFile(path.join(ghDir, f)));
|
|
490
|
+
}
|
|
491
|
+
} catch (_) {}
|
|
479
492
|
_mergeSigIndex(index, _buildSigIndexFromCache(cwd));
|
|
480
493
|
return index;
|
|
481
494
|
}
|