sigmap 6.10.6 → 6.10.7

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 CHANGED
@@ -10,6 +10,28 @@ Format: [Semantic Versioning](https://semver.org/)
10
10
 
11
11
  ---
12
12
 
13
+ ## [6.10.7] — 2026-05-12
14
+
15
+ ### Fixed
16
+
17
+ - **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.
18
+
19
+ ---
20
+
21
+ ## [6.10.6] — 2026-05-11
22
+
23
+ ### Added
24
+
25
+ - **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).
26
+ - **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).
27
+ - **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.
28
+
29
+ ### Fixed
30
+
31
+ - **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.
32
+
33
+ ---
34
+
13
35
  ## [6.10.5] — 2026-05-11
14
36
 
15
37
  ### 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-05
90
+ Date : 2026-05-12
91
91
 
92
92
  Hit@5 : 80.0% (baseline 13.6% — 5.9× lift)
93
- Prompt reduction : 41.0%
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 re = /^[ \t]*from\s+(\.+[\w.]*)\s+import/gm;
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 = re.exec(content)) !== null) {
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)];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "6.10.6",
3
+ "version": "6.10.7",
4
4
  "description": "Zero-dependency AI context engine — 97% token reduction. No npm install. Runs on Node 18+.",
5
5
  "main": "gen-context.js",
6
6
  "exports": {