sigmap 6.10.6 → 6.10.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -3
- package/CHANGELOG.md +38 -0
- package/README.md +2 -2
- package/gen-context.js +105 -5
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/graph/builder.js +18 -0
- package/src/mcp/server.js +1 -1
package/AGENTS.md
CHANGED
|
@@ -61,10 +61,9 @@ Always run `sigmap ask` or `sigmap --query` before searching for files relevant
|
|
|
61
61
|
src/extractors/python_ast.py ← ast
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
## changes (last 5 commits —
|
|
64
|
+
## changes (last 5 commits — 7 minutes ago)
|
|
65
65
|
```
|
|
66
|
-
src/
|
|
67
|
-
src/map/import-graph.js +buildReverseGraph ~extractImports ~resolveJsPath ~detectCycles
|
|
66
|
+
src/graph/builder.js ~extractFileDeps
|
|
68
67
|
```
|
|
69
68
|
|
|
70
69
|
## packages
|
|
@@ -625,6 +624,15 @@ function buildReverseGraph(graph)
|
|
|
625
624
|
function analyze(files, cwd)
|
|
626
625
|
```
|
|
627
626
|
|
|
627
|
+
### src/graph/builder.js
|
|
628
|
+
```
|
|
629
|
+
module.exports = { build, buildFromCwd, extractFileDeps }
|
|
630
|
+
function resolveJsPath(dir, importStr, fileSet) → string|null
|
|
631
|
+
function extractFileDeps(filePath, content, fileSet) → string[]
|
|
632
|
+
function build(files, cwd) → { forward: Map<string,str
|
|
633
|
+
function buildFromCwd(cwd, opts) → { forward: Map<string,str
|
|
634
|
+
```
|
|
635
|
+
|
|
628
636
|
### src/mcp/server.js
|
|
629
637
|
```
|
|
630
638
|
module.exports = { start }
|
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,44 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [6.10.9] — 2026-05-12
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Documentation updates** — Updated roadmap to reflect v6.10.8 completion with Python import detection in builder.js for get_impact MCP tool.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## [6.10.8] — 2026-05-12
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **Python absolute imports in builder.js for get_impact** — Added Python absolute import detection to `src/graph/builder.js` used by the `get_impact` MCP tool. Previously only `import-graph.js` had this support, causing `get_impact` to return empty blast radius for Python monorepos. Now both tools correctly detect `from package.module import X` patterns (closes #187).
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## [6.10.7] — 2026-05-12
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **Python absolute imports in bundled gen-context.js** — Added Python absolute import detection (`from package.module import X`) to bundled extractImports function. The source code had this support but it was missing from the bundle, causing MCP tools to show empty import graphs for Python monorepos. Now matches source behavior correctly.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [6.10.6] — 2026-05-11
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **Python absolute import detection** — Detects `from package.module import X` patterns in Python files, fixing empty import graphs for monorepos. Handles nested imports like `from services.auth.oauth import get_token` correctly (closes #181).
|
|
42
|
+
- **Comprehensive import graph diagnostics** — New `sigmap-diagnostics.js` tool and `src/analysis/diagnostics.js` module provide per-file metrics and budget decision explanations. Helps debug why files are included/excluded and why import graphs may be empty (closes #182).
|
|
43
|
+
- **Regression tests for MCP tools** — Added 8 comprehensive tests covering simple projects, monorepos, circular imports, and Python absolute imports. All tests passing to prevent regressions in `explain_file`, `get_impact`, and related tools.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **Import graph edge resolution** — Improved `resolveJsPath` to handle additional extensions (.mjs, .cjs, .tsx) and better fileSet path handling. Import graph now correctly detects cross-file dependencies in complex project structures.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
13
51
|
## [6.10.5] — 2026-05-11
|
|
14
52
|
|
|
15
53
|
### Added
|
package/README.md
CHANGED
|
@@ -87,10 +87,10 @@ Ask → Rank → Context → Validate → Judge → Learn
|
|
|
87
87
|
|
|
88
88
|
```
|
|
89
89
|
Benchmark : sigmap-v6.10-main
|
|
90
|
-
Date : 2026-05-
|
|
90
|
+
Date : 2026-05-12
|
|
91
91
|
|
|
92
92
|
Hit@5 : 80.0% (baseline 13.6% — 5.9× lift)
|
|
93
|
-
Prompt reduction : 41.
|
|
93
|
+
Prompt reduction : 41.4%
|
|
94
94
|
Task success : 52.2% (baseline 10%)
|
|
95
95
|
Prompts / task : 1.68 (baseline 2.84)
|
|
96
96
|
Token reduction: 40–98% (avg 96.8% across 18 real repos)
|
package/gen-context.js
CHANGED
|
@@ -4091,6 +4091,88 @@ module.exports = { coverageScore };
|
|
|
4091
4091
|
|
|
4092
4092
|
};
|
|
4093
4093
|
|
|
4094
|
+
__factories["./src/analysis/diagnostics"] = function(module, exports) {
|
|
4095
|
+
|
|
4096
|
+
'use strict';
|
|
4097
|
+
|
|
4098
|
+
const path = require('path');
|
|
4099
|
+
|
|
4100
|
+
function estimateTokens(text) {
|
|
4101
|
+
return Math.ceil(text.length / 4);
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
function formatFileDecision(entry, decision, reason, score = null) {
|
|
4105
|
+
const rel = path.relative(process.cwd(), entry.filePath);
|
|
4106
|
+
const tokens = estimateTokens(entry.sigs.join('\n'));
|
|
4107
|
+
let line = `${decision === 'included' ? '✓' : '✗'} ${rel}`;
|
|
4108
|
+
line += ` [${tokens} tokens]`;
|
|
4109
|
+
if (score !== null) line += ` [score: ${score.toFixed(2)}]`;
|
|
4110
|
+
if (reason) line += ` — ${reason}`;
|
|
4111
|
+
return line;
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
function computeFileMetrics(entry) {
|
|
4115
|
+
const loc = entry.content ? entry.content.split('\n').length : 1;
|
|
4116
|
+
const sigCount = entry.sigs ? entry.sigs.length : 0;
|
|
4117
|
+
const signalQuality = loc > 0 ? sigCount / loc : 0;
|
|
4118
|
+
const tokens = estimateTokens(entry.sigs.join('\n'));
|
|
4119
|
+
|
|
4120
|
+
return {
|
|
4121
|
+
lineOfCode: loc,
|
|
4122
|
+
sigCount: sigCount,
|
|
4123
|
+
signalQuality: signalQuality.toFixed(3),
|
|
4124
|
+
tokens: tokens,
|
|
4125
|
+
relevance: (sigCount / Math.max(loc, 1)).toFixed(3),
|
|
4126
|
+
};
|
|
4127
|
+
}
|
|
4128
|
+
|
|
4129
|
+
function explainInclusion(fileEntries, budgetLimit) {
|
|
4130
|
+
const lines = [];
|
|
4131
|
+
|
|
4132
|
+
lines.push('## File Inclusion Diagnostics\n');
|
|
4133
|
+
lines.push(`Budget: ${budgetLimit} tokens`);
|
|
4134
|
+
lines.push(`Files: ${fileEntries.length} scanned\n`);
|
|
4135
|
+
|
|
4136
|
+
let totalTokens = 0;
|
|
4137
|
+
const withMetrics = fileEntries.map((e) => {
|
|
4138
|
+
const metrics = computeFileMetrics(e);
|
|
4139
|
+
totalTokens += metrics.tokens;
|
|
4140
|
+
return { entry: e, metrics };
|
|
4141
|
+
});
|
|
4142
|
+
|
|
4143
|
+
lines.push(`Total token requirement: ${totalTokens} tokens`);
|
|
4144
|
+
lines.push(`Budget headroom: ${budgetLimit * 0.9} tokens (90% of ${budgetLimit})\n`);
|
|
4145
|
+
|
|
4146
|
+
if (totalTokens > budgetLimit * 0.9) {
|
|
4147
|
+
lines.push('⚠ Over budget — files will be dropped\n');
|
|
4148
|
+
lines.push('### Per-file metrics:');
|
|
4149
|
+
for (const { entry, metrics } of withMetrics) {
|
|
4150
|
+
const rel = path.relative(process.cwd(), entry.filePath);
|
|
4151
|
+
lines.push(`- ${rel}`);
|
|
4152
|
+
lines.push(` - Size: ${metrics.tokens} tokens, ${metrics.lineOfCode} lines`);
|
|
4153
|
+
lines.push(` - Sigs: ${metrics.sigCount}, quality: ${metrics.signalQuality}`);
|
|
4154
|
+
}
|
|
4155
|
+
} else {
|
|
4156
|
+
lines.push('✓ All files fit within budget\n');
|
|
4157
|
+
}
|
|
4158
|
+
|
|
4159
|
+
return lines.join('\n');
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4162
|
+
function explainExclusion(dropped, reason) {
|
|
4163
|
+
return `Excluded ${dropped.length} files: ${reason}`;
|
|
4164
|
+
}
|
|
4165
|
+
|
|
4166
|
+
module.exports = {
|
|
4167
|
+
formatFileDecision,
|
|
4168
|
+
computeFileMetrics,
|
|
4169
|
+
explainInclusion,
|
|
4170
|
+
explainExclusion,
|
|
4171
|
+
estimateTokens,
|
|
4172
|
+
};
|
|
4173
|
+
|
|
4174
|
+
};
|
|
4175
|
+
|
|
4094
4176
|
__factories["./src/health/scorer"] = function(module, exports) {
|
|
4095
4177
|
|
|
4096
4178
|
/**
|
|
@@ -4507,10 +4589,10 @@ __factories["./src/map/import-graph"] = function(module, exports) {
|
|
|
4507
4589
|
}
|
|
4508
4590
|
|
|
4509
4591
|
if (PY_EXTS.has(ext)) {
|
|
4510
|
-
// from .module import ... / from ..pkg import ...
|
|
4511
|
-
const
|
|
4592
|
+
// Relative imports: from .module import ... / from ..pkg import ...
|
|
4593
|
+
const reRel = /^[ \t]*from\s+(\.+[\w.]*)\s+import/gm;
|
|
4512
4594
|
let m;
|
|
4513
|
-
while ((m =
|
|
4595
|
+
while ((m = reRel.exec(content)) !== null) {
|
|
4514
4596
|
const dotCount = (m[1].match(/^\.+/) || [''])[0].length;
|
|
4515
4597
|
const modPart = m[1].slice(dotCount).replace(/\./g, '/');
|
|
4516
4598
|
let base = dir;
|
|
@@ -4518,6 +4600,24 @@ __factories["./src/map/import-graph"] = function(module, exports) {
|
|
|
4518
4600
|
const candidate = modPart ? path.join(base, modPart + '.py') : null;
|
|
4519
4601
|
if (candidate && fileSet.has(candidate)) found.push(candidate);
|
|
4520
4602
|
}
|
|
4603
|
+
|
|
4604
|
+
// Absolute imports: from package.module import ... (infer from project structure)
|
|
4605
|
+
const reAbs = /^[ \t]*from\s+([\w.]+)\s+import/gm;
|
|
4606
|
+
while ((m = reAbs.exec(content)) !== null) {
|
|
4607
|
+
const modulePath = m[1].replace(/\./g, '/');
|
|
4608
|
+
const candidates = [
|
|
4609
|
+
path.join(dir, modulePath + '.py'),
|
|
4610
|
+
path.join(dir, modulePath, '__init__.py'),
|
|
4611
|
+
path.resolve(dir, '..', modulePath + '.py'),
|
|
4612
|
+
path.resolve(dir, '..', modulePath, '__init__.py'),
|
|
4613
|
+
];
|
|
4614
|
+
for (const c of candidates) {
|
|
4615
|
+
if (fileSet.has(c)) {
|
|
4616
|
+
found.push(c);
|
|
4617
|
+
break;
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4521
4621
|
}
|
|
4522
4622
|
|
|
4523
4623
|
return [...new Set(found)];
|
|
@@ -5607,7 +5707,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
5607
5707
|
|
|
5608
5708
|
const SERVER_INFO = {
|
|
5609
5709
|
name: 'sigmap',
|
|
5610
|
-
version: '6.10.
|
|
5710
|
+
version: '6.10.9',
|
|
5611
5711
|
description: 'SigMap MCP server — code signatures on demand',
|
|
5612
5712
|
};
|
|
5613
5713
|
|
|
@@ -8234,7 +8334,7 @@ const path = require('path');
|
|
|
8234
8334
|
const os = require('os');
|
|
8235
8335
|
const { execSync } = require('child_process');
|
|
8236
8336
|
|
|
8237
|
-
const VERSION = '6.10.
|
|
8337
|
+
const VERSION = '6.10.9';
|
|
8238
8338
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
8239
8339
|
|
|
8240
8340
|
function requireSourceOrBundled(key) {
|
package/package.json
CHANGED
package/src/graph/builder.js
CHANGED
|
@@ -93,6 +93,24 @@ function extractFileDeps(filePath, content, fileSet) {
|
|
|
93
93
|
: null;
|
|
94
94
|
if (candidate && fileSet.has(candidate)) found.push(candidate);
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
// Absolute imports: from package.module import ... (infer from project structure)
|
|
98
|
+
const reAbs = /^[ \t]*from\s+([\w.]+)\s+import/gm;
|
|
99
|
+
while ((m = reAbs.exec(content)) !== null) {
|
|
100
|
+
const modulePath = m[1].replace(/\./g, '/');
|
|
101
|
+
const candidates = [
|
|
102
|
+
path.join(dir, modulePath + '.py'),
|
|
103
|
+
path.join(dir, modulePath, '__init__.py'),
|
|
104
|
+
path.resolve(dir, '..', modulePath + '.py'),
|
|
105
|
+
path.resolve(dir, '..', modulePath, '__init__.py'),
|
|
106
|
+
];
|
|
107
|
+
for (const c of candidates) {
|
|
108
|
+
if (fileSet.has(c)) {
|
|
109
|
+
found.push(c);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
96
114
|
}
|
|
97
115
|
|
|
98
116
|
// ── Go ────────────────────────────────────────────────────────────────────
|
package/src/mcp/server.js
CHANGED