sigmap 2.9.1 → 3.0.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "2.9.1",
3
+ "version": "3.0.0",
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": {
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Claude adapter — appends to CLAUDE.md under a marker line.
5
+ * Never overwrites human-written content above the marker.
6
+ *
7
+ * Contract:
8
+ * format(context, opts?) → string
9
+ * outputPath(cwd) → string
10
+ * write(context, cwd, opts?) → void (handles append logic)
11
+ */
12
+
13
+ const path = require('path');
14
+ const fs = require('fs');
15
+
16
+ const name = 'claude';
17
+
18
+ const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
19
+
20
+ /**
21
+ * Format context suited for CLAUDE.md.
22
+ * @param {string} context - Raw signature context string
23
+ * @param {object} [opts]
24
+ * @param {string} [opts.version] - SigMap version string
25
+ * @returns {string}
26
+ */
27
+ function format(context, opts = {}) {
28
+ if (!context || typeof context !== 'string') return '';
29
+ const version = opts.version || 'unknown';
30
+ const timestamp = new Date().toISOString();
31
+ return [
32
+ `<!-- Generated by SigMap v${version} — ${timestamp} -->`,
33
+ '',
34
+ context,
35
+ ].join('\n');
36
+ }
37
+
38
+ /**
39
+ * Return the output file path for this adapter.
40
+ * @param {string} cwd - Project root
41
+ * @returns {string}
42
+ */
43
+ function outputPath(cwd) {
44
+ return path.join(cwd, 'CLAUDE.md');
45
+ }
46
+
47
+ /**
48
+ * Write signatures into CLAUDE.md using the append-under-marker strategy.
49
+ * Human content above the marker is never touched.
50
+ * @param {string} context - Raw signature context string
51
+ * @param {string} cwd - Project root
52
+ * @param {object} [opts]
53
+ */
54
+ function write(context, cwd, opts = {}) {
55
+ const filePath = outputPath(cwd);
56
+ let existing = '';
57
+ if (fs.existsSync(filePath)) {
58
+ existing = fs.readFileSync(filePath, 'utf8');
59
+ }
60
+ const formatted = format(context, opts);
61
+ const markerIdx = existing.indexOf('## Auto-generated signatures');
62
+ let newContent;
63
+ if (markerIdx !== -1) {
64
+ newContent = existing.slice(0, markerIdx) + MARKER.trimStart() + formatted;
65
+ } else {
66
+ newContent = existing + MARKER + formatted;
67
+ }
68
+ fs.writeFileSync(filePath, newContent, 'utf8');
69
+ }
70
+
71
+ module.exports = { name, format, outputPath, write };
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Copilot adapter — writes to .github/copilot-instructions.md
5
+ * GitHub Copilot reads this file automatically in every workspace.
6
+ *
7
+ * Contract:
8
+ * format(context, opts?) → string
9
+ * outputPath(cwd) → string
10
+ */
11
+
12
+ const path = require('path');
13
+
14
+ const name = 'copilot';
15
+
16
+ /**
17
+ * Format context for GitHub Copilot instructions.
18
+ * @param {string} context - Raw signature context string
19
+ * @param {object} [opts]
20
+ * @param {string} [opts.version] - SigMap version string
21
+ * @returns {string}
22
+ */
23
+ function format(context, opts = {}) {
24
+ if (!context || typeof context !== 'string') return '';
25
+ const version = opts.version || 'unknown';
26
+ const timestamp = new Date().toISOString();
27
+ const header = [
28
+ `<!-- Generated by SigMap gen-context.js v${version} -->`,
29
+ `<!-- Updated: ${timestamp} -->`,
30
+ `<!-- Do not edit below — regenerate with: node gen-context.js -->`,
31
+ '',
32
+ '# Code signatures',
33
+ '',
34
+ ].join('\n');
35
+ return header + context;
36
+ }
37
+
38
+ /**
39
+ * Return the output file path for this adapter.
40
+ * @param {string} cwd - Project root
41
+ * @returns {string}
42
+ */
43
+ function outputPath(cwd) {
44
+ return path.join(cwd, '.github', 'copilot-instructions.md');
45
+ }
46
+
47
+ module.exports = { name, format, outputPath };
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Cursor adapter — writes to .cursorrules
5
+ * Cursor reads .cursorrules automatically in every workspace.
6
+ *
7
+ * Contract:
8
+ * format(context, opts?) → string
9
+ * outputPath(cwd) → string
10
+ */
11
+
12
+ const path = require('path');
13
+
14
+ const name = 'cursor';
15
+
16
+ /**
17
+ * Format context for Cursor rules file.
18
+ * @param {string} context - Raw signature context string
19
+ * @param {object} [opts]
20
+ * @param {string} [opts.version] - SigMap version string
21
+ * @returns {string}
22
+ */
23
+ function format(context, opts = {}) {
24
+ if (!context || typeof context !== 'string') return '';
25
+ const version = opts.version || 'unknown';
26
+ const timestamp = new Date().toISOString();
27
+ const header = [
28
+ `# Code signatures — generated by SigMap v${version}`,
29
+ `# Updated: ${timestamp}`,
30
+ `# Regenerate: node gen-context.js`,
31
+ '',
32
+ ].join('\n');
33
+ return header + context;
34
+ }
35
+
36
+ /**
37
+ * Return the output file path for this adapter.
38
+ * @param {string} cwd - Project root
39
+ * @returns {string}
40
+ */
41
+ function outputPath(cwd) {
42
+ return path.join(cwd, '.cursorrules');
43
+ }
44
+
45
+ module.exports = { name, format, outputPath };
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Gemini adapter — formats context as a Gemini system instruction.
5
+ * Use the output as the `system_instruction` field in a Gemini API request.
6
+ *
7
+ * Example usage:
8
+ * const { format } = require('sigmap/adapters/gemini');
9
+ * const instruction = format(context);
10
+ * // Pass to: genAI.getGenerativeModel({ model: 'gemini-pro', systemInstruction: instruction })
11
+ *
12
+ * Contract:
13
+ * format(context, opts?) → string
14
+ * outputPath(cwd) → string
15
+ */
16
+
17
+ const path = require('path');
18
+
19
+ const name = 'gemini';
20
+
21
+ /**
22
+ * Format context as a Gemini system instruction.
23
+ * @param {string} context - Raw signature context string
24
+ * @param {object} [opts]
25
+ * @param {string} [opts.version] - SigMap version string
26
+ * @param {string} [opts.projectName] - Optional project name
27
+ * @returns {string}
28
+ */
29
+ function format(context, opts = {}) {
30
+ if (!context || typeof context !== 'string') return '';
31
+ const version = opts.version || 'unknown';
32
+ const timestamp = new Date().toISOString();
33
+ const projectLine = opts.projectName
34
+ ? `Project: ${opts.projectName}\n`
35
+ : '';
36
+
37
+ return [
38
+ `You are a coding assistant with complete knowledge of this codebase.`,
39
+ `The following code signatures were extracted by SigMap v${version} on ${timestamp}.`,
40
+ projectLine,
41
+ `These signatures represent every public function, class, and type in the project.`,
42
+ `Refer to them when answering questions about code structure, APIs, and implementation.`,
43
+ ``,
44
+ `## Code Signatures`,
45
+ ``,
46
+ context,
47
+ ].join('\n');
48
+ }
49
+
50
+ /**
51
+ * Return the output file path for this adapter.
52
+ * @param {string} cwd - Project root
53
+ * @returns {string}
54
+ */
55
+ function outputPath(cwd) {
56
+ return path.join(cwd, '.github', 'gemini-context.md');
57
+ }
58
+
59
+ module.exports = { name, format, outputPath };
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * packages/adapters/index.js
5
+ * Central registry for all SigMap output adapters.
6
+ *
7
+ * Usage:
8
+ * const { getAdapter, listAdapters, adapt } = require('sigmap/adapters');
9
+ * const output = adapt(context, 'copilot', { version: '3.0.0' });
10
+ */
11
+
12
+ const path = require('path');
13
+
14
+ const ADAPTER_NAMES = ['copilot', 'claude', 'cursor', 'windsurf', 'openai', 'gemini'];
15
+
16
+ // Lazy-load adapters so unused ones don't pay any require() cost
17
+ const _cache = {};
18
+
19
+ /**
20
+ * Load and return an adapter module by name.
21
+ * @param {string} name - Adapter name (copilot|claude|cursor|windsurf|openai|gemini)
22
+ * @returns {{ name: string, format: Function, outputPath: Function }|null}
23
+ */
24
+ function getAdapter(name) {
25
+ if (!name || typeof name !== 'string') return null;
26
+ const key = name.toLowerCase();
27
+ if (!ADAPTER_NAMES.includes(key)) return null;
28
+ if (!_cache[key]) {
29
+ try {
30
+ _cache[key] = require(path.join(__dirname, key + '.js'));
31
+ } catch (_) {
32
+ return null;
33
+ }
34
+ }
35
+ return _cache[key];
36
+ }
37
+
38
+ /**
39
+ * List all available adapter names.
40
+ * @returns {string[]}
41
+ */
42
+ function listAdapters() {
43
+ return ADAPTER_NAMES.slice();
44
+ }
45
+
46
+ /**
47
+ * Format context using the named adapter.
48
+ * @param {string} context - Raw signature context string
49
+ * @param {string} adapterName - Adapter name
50
+ * @param {object} [opts] - Options passed to adapter.format()
51
+ * @returns {string} Formatted output string (empty string if adapter not found or context empty)
52
+ */
53
+ function adapt(context, adapterName, opts = {}) {
54
+ if (!context || typeof context !== 'string') return '';
55
+ const adapter = getAdapter(adapterName);
56
+ if (!adapter || typeof adapter.format !== 'function') return '';
57
+ try {
58
+ return adapter.format(context, opts);
59
+ } catch (_) {
60
+ return '';
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Map old `outputs` config values to new `adapters` names.
66
+ * Provides backward compatibility for existing configurations.
67
+ * @param {string[]} outputs - Legacy outputs array
68
+ * @returns {string[]} Equivalent adapters array
69
+ */
70
+ function outputsToAdapters(outputs) {
71
+ if (!Array.isArray(outputs)) return ['copilot'];
72
+ return outputs.map((o) => {
73
+ // All current output names already match adapter names
74
+ if (ADAPTER_NAMES.includes(o)) return o;
75
+ return o; // pass through unknowns — getAdapter() will handle gracefully
76
+ });
77
+ }
78
+
79
+ module.exports = { getAdapter, listAdapters, adapt, outputsToAdapters };
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * OpenAI adapter — formats context as an OpenAI system message.
5
+ * Use the output as the `content` field of a system role message.
6
+ *
7
+ * Example usage in code:
8
+ * const { format } = require('sigmap/adapters/openai');
9
+ * const systemPrompt = format(context);
10
+ * // Pass to: openai.chat.completions.create({ messages: [{ role: 'system', content: systemPrompt }] })
11
+ *
12
+ * Contract:
13
+ * format(context, opts?) → string
14
+ * outputPath(cwd) → string
15
+ */
16
+
17
+ const path = require('path');
18
+
19
+ const name = 'openai';
20
+
21
+ /**
22
+ * Format context as an OpenAI system prompt.
23
+ * @param {string} context - Raw signature context string
24
+ * @param {object} [opts]
25
+ * @param {string} [opts.version] - SigMap version string
26
+ * @param {string} [opts.projectName] - Optional project name
27
+ * @returns {string}
28
+ */
29
+ function format(context, opts = {}) {
30
+ if (!context || typeof context !== 'string') return '';
31
+ const version = opts.version || 'unknown';
32
+ const timestamp = new Date().toISOString();
33
+ const projectLine = opts.projectName
34
+ ? `Project: ${opts.projectName}\n`
35
+ : '';
36
+
37
+ return [
38
+ `You are a coding assistant with full knowledge of this codebase.`,
39
+ `Below are the code signatures extracted by SigMap v${version} on ${timestamp}.`,
40
+ projectLine,
41
+ `Use these signatures to answer questions about the code accurately.`,
42
+ `When the user asks about a specific file or function, refer to the signatures below.`,
43
+ ``,
44
+ `## Code Signatures`,
45
+ ``,
46
+ context,
47
+ ].join('\n');
48
+ }
49
+
50
+ /**
51
+ * Return the output file path for this adapter.
52
+ * Writes a .openai-context.md file that can be loaded at runtime.
53
+ * @param {string} cwd - Project root
54
+ * @returns {string}
55
+ */
56
+ function outputPath(cwd) {
57
+ return path.join(cwd, '.github', 'openai-context.md');
58
+ }
59
+
60
+ module.exports = { name, format, outputPath };
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Windsurf adapter — writes to .windsurfrules
5
+ * Windsurf reads .windsurfrules automatically in every workspace.
6
+ *
7
+ * Contract:
8
+ * format(context, opts?) → string
9
+ * outputPath(cwd) → string
10
+ */
11
+
12
+ const path = require('path');
13
+
14
+ const name = 'windsurf';
15
+
16
+ /**
17
+ * Format context for Windsurf rules file.
18
+ * @param {string} context - Raw signature context string
19
+ * @param {object} [opts]
20
+ * @param {string} [opts.version] - SigMap version string
21
+ * @returns {string}
22
+ */
23
+ function format(context, opts = {}) {
24
+ if (!context || typeof context !== 'string') return '';
25
+ const version = opts.version || 'unknown';
26
+ const timestamp = new Date().toISOString();
27
+ const header = [
28
+ `# Code signatures — generated by SigMap v${version}`,
29
+ `# Updated: ${timestamp}`,
30
+ `# Regenerate: node gen-context.js`,
31
+ '',
32
+ ].join('\n');
33
+ return header + context;
34
+ }
35
+
36
+ /**
37
+ * Return the output file path for this adapter.
38
+ * @param {string} cwd - Project root
39
+ * @returns {string}
40
+ */
41
+ function outputPath(cwd) {
42
+ return path.join(cwd, '.windsurfrules');
43
+ }
44
+
45
+ module.exports = { name, format, outputPath };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-cli",
3
- "version": "2.9.1",
3
+ "version": "3.0.0",
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
  # sigmap-core
2
2
 
3
- Programmatic API for [SigMap](https://manojmallick.github.io/sigmap/) — zero-dependency code signature extraction, ranked retrieval, secret scanning, and project health scoring.
3
+ Programmatic API for [SigMap](https://manojmallick.github.io/sigmap/) — zero-dependency code signature extraction, ranked retrieval, secret scanning, project health scoring, and multi-adapter output formatting (v3.0+).
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,7 +13,7 @@ npm install sigmap # installs the full package (CLI + core)
13
13
  ## Quick start
14
14
 
15
15
  ```js
16
- const { extract, rank, buildSigIndex, scan, score } = require('sigmap');
16
+ const { extract, rank, buildSigIndex, scan, score, adapt } = require('sigmap');
17
17
 
18
18
  // 1. Extract signatures from any source file
19
19
  const sigs = extract('function hello() { return "world"; }', 'javascript');
@@ -128,9 +128,21 @@ const health = score('/path/to/project');
128
128
 
129
129
  All existing CLI flags (`--generate`, `--watch`, `--mcp`, `--query`, `--analyze`, `--benchmark`, `--health`, …) are unchanged.
130
130
 
131
- ## What's next v2.9
131
+ ## v3.0Multi-Adapter Architecture (released)
132
132
 
133
- v2.9 adds JetBrains plugin support install SigMap natively in IntelliJ IDEA, WebStorm, PyCharm, GoLand, RubyMine. Includes toolbar actions, settings panel, file watcher integration, and automated JetBrains Marketplace publishing. See [issue #23](https://github.com/manojmallick/sigmap/issues/23).
133
+ v3.0 adds the `adapt()` function to `packages/core`, making the API **semver-stable**. Breaking changes now require v4.0.
134
+
135
+ ```js
136
+ const { adapt } = require('sigmap');
137
+
138
+ // Format context as an OpenAI system prompt
139
+ const systemPrompt = adapt(context, 'openai', { version: '3.0.0' });
140
+
141
+ // Format context as a Gemini system instruction
142
+ const geminiInstruction = adapt(context, 'gemini');
143
+
144
+ // All 6 adapters: copilot | claude | cursor | windsurf | openai | gemini
145
+ ```
134
146
 
135
147
  See the full [roadmap](https://manojmallick.github.io/sigmap/roadmap.html).
136
148
 
@@ -198,6 +198,33 @@ function score(cwd) {
198
198
  }
199
199
  }
200
200
 
201
+ // ---------------------------------------------------------------------------
202
+ // adapt(context, adapterName, opts?) → string (v3.0+)
203
+ // ---------------------------------------------------------------------------
204
+ /**
205
+ * Format a context string using the named output adapter.
206
+ *
207
+ * @param {string} context - Raw signature context string
208
+ * @param {string} adapterName - One of: 'copilot'|'claude'|'cursor'|'windsurf'|'openai'|'gemini'
209
+ * @param {object} [opts] - Passed through to adapter.format()
210
+ * @returns {string} Formatted output string (empty string if adapter not found)
211
+ *
212
+ * @example
213
+ * const { adapt } = require('sigmap');
214
+ * const systemPrompt = adapt(context, 'openai', { version: '3.0.0' });
215
+ *
216
+ * const copilotMd = adapt(context, 'copilot');
217
+ */
218
+ function adapt(context, adapterName, opts = {}) {
219
+ try {
220
+ const adaptersPath = path.resolve(__dirname, '..', 'adapters', 'index.js');
221
+ const { adapt: _adapt } = require(adaptersPath);
222
+ return _adapt(context, adapterName, opts);
223
+ } catch (_) {
224
+ return '';
225
+ }
226
+ }
227
+
201
228
  // ---------------------------------------------------------------------------
202
229
  // Exports
203
230
  // ---------------------------------------------------------------------------
@@ -212,4 +239,6 @@ module.exports = {
212
239
  scan,
213
240
  /** Compute project health score */
214
241
  score,
242
+ /** Format context using a named output adapter (v3.0+) */
243
+ adapt,
215
244
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-core",
3
- "version": "2.9.1",
3
+ "version": "3.0.0",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -11,6 +11,10 @@ const DEFAULTS = {
11
11
  // Output targets: 'copilot' | 'claude' | 'cursor' | 'windsurf'
12
12
  outputs: ['copilot'],
13
13
 
14
+ // Adapter targets (v3.0+): replaces 'outputs'. Same names, adds 'openai' | 'gemini'.
15
+ // Old 'outputs' config key is still accepted and silently maps to 'adapters'.
16
+ adapters: null,
17
+
14
18
  // Directories to scan (relative to project root)
15
19
  srcDirs: [
16
20
  'src', 'app', 'lib', 'packages', 'services', 'api',
@@ -50,6 +50,13 @@ function loadConfig(cwd) {
50
50
  merged[key] = val;
51
51
  }
52
52
  }
53
+ // Backward compat (v3.0+): mirror outputs ↔ adapters
54
+ if (merged.adapters && !Array.isArray(merged.adapters)) merged.adapters = null;
55
+ if (!merged.adapters && Array.isArray(merged.outputs)) {
56
+ merged.adapters = merged.outputs.slice();
57
+ } else if (Array.isArray(merged.adapters) && !userConfig.outputs) {
58
+ merged.outputs = merged.adapters.filter((a) => ['copilot','claude','cursor','windsurf'].includes(a));
59
+ }
53
60
  return merged;
54
61
  }
55
62