sigmap 6.0.1 → 6.0.3

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 CHANGED
@@ -11,19 +11,9 @@ Use this marker block for all appendable context files:
11
11
  ```
12
12
  ## Auto-generated signatures
13
13
  <!-- Updated by gen-context.js -->
14
- You are a coding assistant with full knowledge of this codebase.
15
- Below are the code signatures extracted by SigMap v6.0.1 on 2026-04-21T10:54:32.005Z.
16
-
17
- Use these signatures to answer questions about the code accurately.
18
-
19
- ## Code Signatures
20
-
21
- <!-- Generated by SigMap gen-context.js v6.0.1 -->
22
- <!-- DO NOT EDIT below the marker line — run gen-context.js to regenerate -->
23
-
24
14
  # Code signatures
25
15
 
26
- ## changes (last 5 commits — 11 minutes ago)
16
+ ## changes (last 5 commits — 3 minutes ago)
27
17
  ```
28
18
  src/extractors/typescript.js ~extractInterfaceMembers ~extractClassMembers
29
19
  packages/adapters/codex.js ~format
@@ -610,14 +600,6 @@ function coverageScore(cwd, fileEntries, config)
610
600
  function _walk(dir, excludeSet, out)
611
601
  ```
612
602
 
613
- ### src/tracking/logger.js
614
- ```
615
- module.exports = { logRun, readLog, summarize }
616
- function logRun(entry, cwd)
617
- function readLog(cwd) → object[]
618
- function summarize(entries) → object
619
- ```
620
-
621
603
  ### src/cache/sig-cache.js
622
604
  ```
623
605
  module.exports = { loadCache, saveCache, getChangedFiles, updateCacheEntries }
@@ -628,16 +610,6 @@ function getChangedFiles(files, cache) → { changed: string[], unch
628
610
  function updateCacheEntries(cache, extracted)
629
611
  ```
630
612
 
631
- ### src/extractors/typescript.js
632
- ```
633
- module.exports = { extract }
634
- function extract(src) → string[]
635
- function extractBlock(src, startIndex)
636
- function extractInterfaceMembers(block)
637
- function extractClassMembers(block)
638
- function normalizeParams(params)
639
- ```
640
-
641
613
  ### src/mcp/handlers.js
642
614
  ```
643
615
  module.exports = { readContext, searchSignatures, getMap, createCheckpoint, getRouting, explainFile, listModules, queryContext, getImpact }
@@ -664,6 +636,24 @@ function formatRankJSON(results, query) → object
664
636
  function detectIntent(query)
665
637
  ```
666
638
 
639
+ ### src/tracking/logger.js
640
+ ```
641
+ module.exports = { logRun, readLog, summarize }
642
+ function logRun(entry, cwd)
643
+ function readLog(cwd) → object[]
644
+ function summarize(entries) → object
645
+ ```
646
+
647
+ ### src/extractors/typescript.js
648
+ ```
649
+ module.exports = { extract }
650
+ function extract(src) → string[]
651
+ function extractBlock(src, startIndex)
652
+ function extractInterfaceMembers(block)
653
+ function extractClassMembers(block)
654
+ function normalizeParams(params)
655
+ ```
656
+
667
657
  ### src/mcp/server.js
668
658
  ```
669
659
  module.exports = { start }
package/CHANGELOG.md CHANGED
@@ -10,6 +10,25 @@ Format: [Semantic Versioning](https://semver.org/)
10
10
 
11
11
  ---
12
12
 
13
+ ## [6.0.3] — 2026-04-21
14
+
15
+ ### Added
16
+
17
+ - **`--coverage` CLI flag** — enables test coverage annotation (`✓`/`✗` per function) at runtime without editing config; sets `testCoverage: true` on the loaded config before any run path.
18
+ - **`sigmap weights --export [file]`** — writes learned weights JSON to a file path, or prints to stdout if no path given (pipe-friendly for CI and team sharing).
19
+ - **`sigmap weights --import <file> [--replace]`** — merges imported weights into the local `.context/weights.json`; `--replace` discards existing weights and takes the imported set entirely. Incoming values are sanitized and clamped.
20
+
21
+ ---
22
+
23
+ ## [6.0.2] — 2026-04-21
24
+
25
+ ### Fixed
26
+
27
+ - **Duplicate adapter headers (#104, #96)** — `writeOutputs()` now strips the `formatOutput()` preamble (`<!-- Generated... -->` + `# Code signatures`) before passing content to adapters, preventing double headers on every run. Introduces `stripFormatHeader()` helper applied to all adapter paths including `writeClaude()`.
28
+ - **Bundled codex factory (#96)** — the inline `__factories["./packages/adapters/codex"]` in `gen-context.js` was still delegating to `openai.format()` after the source-file fix in v6.0.1. Now uses clean `# Code signatures\n\n` + context, matching the source adapter.
29
+
30
+ ---
31
+
13
32
  ## [6.0.1] — 2026-04-21
14
33
 
15
34
  ### Fixed
package/README.md CHANGED
@@ -147,7 +147,7 @@ volta install sigmap
147
147
  | `windsurf` | `.windsurfrules` | Windsurf |
148
148
  | `openai` | `.github/openai-context.md` | OpenAI models |
149
149
  | `gemini` | `.github/gemini-context.md` | Google Gemini |
150
- | `codex` | `AGENTS.md` | OpenAI Codex |
150
+ | `codex` | `AGENTS.md` | OpenAI Codex · OpenCode |
151
151
 
152
152
  ```bash
153
153
  sigmap --adapter copilot # default
package/gen-context.js CHANGED
@@ -5327,11 +5327,42 @@ __factories["./src/learning/weights"] = function(module, exports) {
5327
5327
  if (fs.existsSync(outPath)) fs.unlinkSync(outPath);
5328
5328
  }
5329
5329
 
5330
+ function exportWeights(cwd, outputPath) {
5331
+ const weights = loadWeights(cwd);
5332
+ const json = JSON.stringify(weights, null, 2) + '\n';
5333
+ if (outputPath) {
5334
+ fs.mkdirSync(path.dirname(path.resolve(outputPath)), { recursive: true });
5335
+ fs.writeFileSync(outputPath, json, 'utf8');
5336
+ } else {
5337
+ process.stdout.write(json);
5338
+ }
5339
+ return weights;
5340
+ }
5341
+
5342
+ function importWeights(cwd, importPath, replace) {
5343
+ let incoming;
5344
+ try {
5345
+ incoming = JSON.parse(fs.readFileSync(importPath, 'utf8'));
5346
+ } catch (err) {
5347
+ throw new Error('Cannot read weights file: ' + err.message);
5348
+ }
5349
+ const sanitized = sanitizeWeights(cwd, incoming);
5350
+ if (replace) {
5351
+ saveWeights(cwd, sanitized);
5352
+ return sanitized;
5353
+ }
5354
+ const existing = loadWeights(cwd);
5355
+ const merged = Object.assign({}, existing, sanitized);
5356
+ saveWeights(cwd, merged);
5357
+ return merged;
5358
+ }
5359
+
5330
5360
  module.exports = {
5331
5361
  BASELINE, DECAY, MAX_MULT, MIN_MULT,
5332
5362
  weightsPath, clampMultiplier, normalizeFile,
5333
5363
  loadWeights, saveWeights, updateWeights,
5334
5364
  boostFiles, penalizeFiles, resetWeights,
5365
+ exportWeights, importWeights,
5335
5366
  };
5336
5367
  };
5337
5368
 
@@ -5356,7 +5387,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
5356
5387
 
5357
5388
  const SERVER_INFO = {
5358
5389
  name: 'sigmap',
5359
- version: '6.0.1',
5390
+ version: '6.0.3',
5360
5391
  description: 'SigMap MCP server — code signatures on demand',
5361
5392
  };
5362
5393
 
@@ -6866,11 +6897,11 @@ __factories["./packages/adapters/gemini"] = function(module, exports) {
6866
6897
  __factories["./packages/adapters/codex"] = function(module, exports) {
6867
6898
  const path = require('path');
6868
6899
  const fs = require('fs');
6869
- const openai = __require('./packages/adapters/openai');
6870
6900
  const name = 'codex';
6871
6901
  const CODEX_MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
6872
6902
  function format(context, opts = {}) {
6873
- return openai.format(context, opts);
6903
+ if (!context || typeof context !== 'string' || !context.trim()) return '';
6904
+ return '# Code signatures\n\n' + context;
6874
6905
  }
6875
6906
  function outputPath(cwd) { return path.join(cwd, 'AGENTS.md'); }
6876
6907
  function write(context, cwd, opts = {}) {
@@ -7074,7 +7105,7 @@ const path = require('path');
7074
7105
  const os = require('os');
7075
7106
  const { execSync } = require('child_process');
7076
7107
 
7077
- const VERSION = '6.0.1';
7108
+ const VERSION = '6.0.3';
7078
7109
  const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
7079
7110
 
7080
7111
  function requireSourceOrBundled(key) {
@@ -7762,13 +7793,17 @@ function writeOutputs(content, targets, cwd, config) {
7762
7793
  if (ADAPTER_TARGETS.has(target)) {
7763
7794
  try {
7764
7795
  const adapterMod = __require('./packages/adapters/' + target);
7796
+ // Adapters add their own header via format() — strip the formatOutput() header
7797
+ // so the content body (## src, ## deps, etc.) is passed without a pre-existing
7798
+ // header, preventing duplicate "# Code signatures" blocks on every run.
7799
+ const adapterContent = stripFormatHeader(content);
7765
7800
  // copilot: honour config.output custom path (redirects away from default .github/copilot-instructions.md)
7766
7801
  if (target === 'copilot') {
7767
7802
  const outPath = resolveAdapterPath('copilot', cwd, config);
7768
7803
  const defaultPath = path.join(cwd, '.github', 'copilot-instructions.md');
7769
7804
  if (outPath !== defaultPath) {
7770
7805
  // custom path: format and write directly (no append logic)
7771
- const formatted = adapterMod.format(content, { version: VERSION });
7806
+ const formatted = adapterMod.format(adapterContent, { version: VERSION });
7772
7807
  ensureDir(outPath);
7773
7808
  fs.writeFileSync(outPath, formatted, 'utf8');
7774
7809
  console.warn(`[sigmap] wrote ${path.relative(cwd, outPath)}`);
@@ -7776,11 +7811,11 @@ function writeOutputs(content, targets, cwd, config) {
7776
7811
  }
7777
7812
  }
7778
7813
  if (typeof adapterMod.write === 'function') {
7779
- adapterMod.write(content, cwd, { version: VERSION });
7814
+ adapterMod.write(adapterContent, cwd, { version: VERSION });
7780
7815
  const outPath = adapterMod.outputPath(cwd);
7781
7816
  console.warn(`[sigmap] wrote ${path.relative(cwd, outPath)} (appended signatures)`);
7782
7817
  } else {
7783
- const formatted = adapterMod.format(content, { version: VERSION });
7818
+ const formatted = adapterMod.format(adapterContent, { version: VERSION });
7784
7819
  const outPath = adapterMod.outputPath(cwd);
7785
7820
  ensureDir(outPath);
7786
7821
  fs.writeFileSync(outPath, formatted, 'utf8');
@@ -7802,18 +7837,36 @@ function writeOutputs(content, targets, cwd, config) {
7802
7837
  }
7803
7838
  }
7804
7839
 
7840
+ // Strip the formatOutput() header block before passing content to adapters.
7841
+ // formatOutput() prepends "<!-- Generated... -->\n\n# Code signatures\n\n" which
7842
+ // is the raw-file header. Adapters add their own header via format(), so passing
7843
+ // pre-headered content produces duplicate headers on every run.
7844
+ function stripFormatHeader(content) {
7845
+ if (!content || typeof content !== 'string') return content;
7846
+ // Header ends after "# Code signatures\n\n" (with blank line)
7847
+ const marker = '\n# Code signatures\n';
7848
+ const idx = content.indexOf(marker);
7849
+ if (idx === -1) return content;
7850
+ // Skip past the marker line and one blank line
7851
+ const afterMarker = content.slice(idx + marker.length);
7852
+ return afterMarker.startsWith('\n') ? afterMarker.slice(1) : afterMarker;
7853
+ }
7854
+
7805
7855
  function writeClaude(content, cwd) {
7806
7856
  const claudePath = path.join(cwd, 'CLAUDE.md');
7807
7857
  let existing = '';
7808
7858
  if (fs.existsSync(claudePath)) {
7809
7859
  existing = fs.readFileSync(claudePath, 'utf8');
7810
7860
  }
7861
+ // Strip the formatOutput() header — CLAUDE.md gets its own header via the MARKER
7862
+ const body = stripFormatHeader(content);
7863
+ const sigHeader = '# Code signatures\n\n';
7811
7864
  const markerIdx = existing.indexOf('## Auto-generated signatures');
7812
7865
  let newContent;
7813
7866
  if (markerIdx !== -1) {
7814
- newContent = existing.slice(0, markerIdx) + MARKER.trimStart() + content;
7867
+ newContent = existing.slice(0, markerIdx) + MARKER.trimStart() + sigHeader + body;
7815
7868
  } else {
7816
- newContent = existing + MARKER + content;
7869
+ newContent = existing + MARKER + sigHeader + body;
7817
7870
  }
7818
7871
  fs.writeFileSync(claudePath, newContent, 'utf8');
7819
7872
  console.warn(`[sigmap] wrote CLAUDE.md (appended signatures)`);
@@ -8960,6 +9013,11 @@ function main() {
8960
9013
  config.srcDirs = ['.'];
8961
9014
  }
8962
9015
 
9016
+ // --coverage: enable test coverage annotation without editing config
9017
+ if (args.includes('--coverage')) {
9018
+ config.testCoverage = true;
9019
+ }
9020
+
8963
9021
  // ── --output <file> — parse early so every subsequent block can use it ─────
8964
9022
  // Resolves the custom output path and merges it into config.customOutput.
8965
9023
  // Also persists the resolved relative path to gen-context.config.json so
@@ -9282,7 +9340,36 @@ function main() {
9282
9340
 
9283
9341
  // v5.2: `sigmap weights` — explain learned ranking multipliers
9284
9342
  if (args[0] === 'weights') {
9285
- const { loadWeights } = requireSourceOrBundled('./src/learning/weights');
9343
+ const { loadWeights, exportWeights, importWeights } = requireSourceOrBundled('./src/learning/weights');
9344
+
9345
+ if (args.includes('--export')) {
9346
+ const exportIdx = args.indexOf('--export');
9347
+ const maybeFile = args[exportIdx + 1];
9348
+ const exportFile = (maybeFile && !maybeFile.startsWith('--')) ? maybeFile : null;
9349
+ exportWeights(cwd, exportFile);
9350
+ if (exportFile) console.warn(`[sigmap] weights exported to ${exportFile}`);
9351
+ process.exit(0);
9352
+ }
9353
+
9354
+ if (args.includes('--import')) {
9355
+ const importIdx = args.indexOf('--import');
9356
+ const importFile = args[importIdx + 1];
9357
+ if (!importFile || importFile.startsWith('--')) {
9358
+ console.error('[sigmap] --import requires a file path');
9359
+ process.exit(1);
9360
+ }
9361
+ const replace = args.includes('--replace');
9362
+ try {
9363
+ const result = importWeights(cwd, importFile, replace);
9364
+ const count = Object.keys(result).length;
9365
+ console.warn(`[sigmap] weights ${replace ? 'replaced' : 'merged'} from ${importFile} — ${count} file(s) with non-baseline weights`);
9366
+ } catch (err) {
9367
+ console.error(`[sigmap] weights import failed: ${err.message}`);
9368
+ process.exit(1);
9369
+ }
9370
+ process.exit(0);
9371
+ }
9372
+
9286
9373
  const weights = loadWeights(cwd);
9287
9374
  const entries = Object.entries(weights).sort(([, a], [, b]) => b - a || 0);
9288
9375
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "6.0.1",
3
+ "version": "6.0.3",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-cli",
3
- "version": "6.0.1",
3
+ "version": "6.0.3",
4
4
  "description": "SigMap CLI wrapper — thin adapter for programmatic CLI invocation",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-core",
3
- "version": "6.0.1",
3
+ "version": "6.0.3",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -121,6 +121,36 @@ function resetWeights(cwd) {
121
121
  if (fs.existsSync(outPath)) fs.unlinkSync(outPath);
122
122
  }
123
123
 
124
+ function exportWeights(cwd, outputPath) {
125
+ const weights = loadWeights(cwd);
126
+ const json = JSON.stringify(weights, null, 2) + '\n';
127
+ if (outputPath) {
128
+ fs.mkdirSync(path.dirname(path.resolve(outputPath)), { recursive: true });
129
+ fs.writeFileSync(outputPath, json, 'utf8');
130
+ } else {
131
+ process.stdout.write(json);
132
+ }
133
+ return weights;
134
+ }
135
+
136
+ function importWeights(cwd, importPath, replace) {
137
+ let incoming;
138
+ try {
139
+ incoming = JSON.parse(fs.readFileSync(importPath, 'utf8'));
140
+ } catch (err) {
141
+ throw new Error(`Cannot read weights file: ${err.message}`);
142
+ }
143
+ const sanitized = sanitizeWeights(cwd, incoming);
144
+ if (replace) {
145
+ saveWeights(cwd, sanitized);
146
+ return sanitized;
147
+ }
148
+ const existing = loadWeights(cwd);
149
+ const merged = Object.assign({}, existing, sanitized);
150
+ saveWeights(cwd, merged);
151
+ return merged;
152
+ }
153
+
124
154
  module.exports = {
125
155
  BASELINE,
126
156
  DECAY,
@@ -135,4 +165,6 @@ module.exports = {
135
165
  boostFiles,
136
166
  penalizeFiles,
137
167
  resetWeights,
168
+ exportWeights,
169
+ importWeights,
138
170
  };
package/src/mcp/server.js CHANGED
@@ -18,7 +18,7 @@ const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, exp
18
18
 
19
19
  const SERVER_INFO = {
20
20
  name: 'sigmap',
21
- version: '6.0.1',
21
+ version: '6.0.3',
22
22
  description: 'SigMap MCP server — code signatures on demand',
23
23
  };
24
24