sigmap 3.3.4 → 3.4.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/CHANGELOG.md CHANGED
@@ -10,16 +10,20 @@ Format: [Semantic Versioning](https://semver.org/)
10
10
 
11
11
  ---
12
12
 
13
- ## [3.3.4] — 2026-04-14 — Binary Bundle Fix
13
+ ## [3.4.0] — 2026-04-14 — Phase A/B Coverage Expansion
14
14
 
15
- ### Fixed
16
- - **Standalone binary pre-flight now passes for new P1 extractors**
17
- - Added missing bundled `__factories` entries in `gen-context.js` for:
18
- - `./src/extractors/graphql`
19
- - `./src/extractors/protobuf`
20
- - `./src/extractors/sql`
21
- - `./src/extractors/terraform`
22
- - Resolves CI/build failure in `scripts/build-binary.mjs` reporting missing `src/` modules in bundle.
15
+ ### Added
16
+ - **Phase A extractor support** for high-value config and docs formats:
17
+ - TOML: `.toml`
18
+ - Java/INI properties: `.properties`
19
+ - XML: `.xml`
20
+ - Markdown technical docs: `.md`
21
+ - **Bundled runtime factory wiring** for new extractors so standalone/binary execution resolves the same modules as source mode.
22
+
23
+ ### Changed
24
+ - **Framework-aware source discovery** defaults expanded for Next/React, Angular, Rails, Laravel, and Flask/Python-style layouts.
25
+ - **Strategy audit coverage rules** updated to treat Phase A formats as supported instead of important unsupported baselines.
26
+ - **Default srcDirs** broadened to improve first-run context quality on framework-heavy repositories.
23
27
 
24
28
  ---
25
29
 
package/README.md CHANGED
@@ -19,8 +19,6 @@
19
19
  npx sigmap # 10 seconds. zero config. your AI never reads the wrong file again.
20
20
  ```
21
21
 
22
- > Latest: **v3.3.4** includes a standalone binary bundle fix for newly added P1 extractors.
23
-
24
22
  <div align="center">
25
23
  <img src="demo.gif" alt="SigMap demo — reducing 80K tokens to 4K in under 10 seconds" width="760" />
26
24
  </div>
@@ -471,6 +469,8 @@ Compatible with **IntelliJ IDEA 2024.1+** (Community & Ultimate), **WebStorm**,
471
469
  ## 🌐 Languages supported
472
470
 
473
471
  > 25 languages. All implemented with zero external dependencies — pure regex + Node built-ins.
472
+ >
473
+ > Also includes lightweight config/doc extraction for `.toml`, `.properties`, `.xml`, and `.md` to improve real-repo coverage beyond source-code files.
474
474
 
475
475
  <details>
476
476
  <summary><strong>Show all 25 languages</strong></summary>
package/gen-context.js CHANGED
@@ -2000,6 +2000,185 @@ __factories["./src/extractors/terraform"] = function(module, exports) {
2000
2000
 
2001
2001
  };
2002
2002
 
2003
+ // ── ./src/extractors/toml ──
2004
+ __factories["./src/extractors/toml"] = function(module, exports) {
2005
+
2006
+ 'use strict';
2007
+
2008
+ /**
2009
+ * Extract signatures from TOML configuration files.
2010
+ * Focuses on section/table names and high-value keys.
2011
+ *
2012
+ * @param {string} src - Raw TOML content
2013
+ * @returns {string[]} Array of signature strings
2014
+ */
2015
+ function extract(src) {
2016
+ if (!src || typeof src !== 'string') return [];
2017
+ const sigs = [];
2018
+
2019
+ // Remove # comments while preserving values before comment markers.
2020
+ const stripped = src.replace(/\s+#.*$/gm, '');
2021
+
2022
+ // [section] and [[array.section]]
2023
+ for (const m of stripped.matchAll(/^\s*(\[\[?[^\]]+\]\]?)\s*$/gm)) {
2024
+ sigs.push(`table ${m[1].trim()}`);
2025
+ }
2026
+
2027
+ // Key-value lines (top-level and nested) — keep key names only.
2028
+ for (const m of stripped.matchAll(/^\s*([A-Za-z0-9_.-]+)\s*=\s*(.+)$/gm)) {
2029
+ const key = m[1].trim();
2030
+ const value = m[2].trim();
2031
+
2032
+ // Prefer common metadata/config keys for compact, useful output.
2033
+ if (/^(name|version|description|authors|license|requires-python|dependencies|optional-dependencies|scripts|tool\.|build-system\.|project\.)/.test(key)) {
2034
+ sigs.push(`key ${key}`);
2035
+ continue;
2036
+ }
2037
+
2038
+ // Include booleans and simple scalar keys as generic config signal.
2039
+ if (/^(true|false|"[^"]*"|'[^']*'|[0-9._-]+)$/.test(value)) {
2040
+ sigs.push(`key ${key}`);
2041
+ }
2042
+ }
2043
+
2044
+ return Array.from(new Set(sigs)).slice(0, 40);
2045
+ }
2046
+
2047
+ module.exports = { extract };
2048
+
2049
+ };
2050
+
2051
+ // ── ./src/extractors/properties ──
2052
+ __factories["./src/extractors/properties"] = function(module, exports) {
2053
+
2054
+ 'use strict';
2055
+
2056
+ /**
2057
+ * Extract signatures from .properties configuration files.
2058
+ * Captures key names, grouped by prefixes where possible.
2059
+ *
2060
+ * @param {string} src - Raw properties content
2061
+ * @returns {string[]} Array of signature strings
2062
+ */
2063
+ function extract(src) {
2064
+ if (!src || typeof src !== 'string') return [];
2065
+ const sigs = [];
2066
+
2067
+ const lines = src.split(/\r?\n/);
2068
+ for (const line of lines) {
2069
+ const trimmed = line.trim();
2070
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('!')) continue;
2071
+
2072
+ const idxEq = trimmed.indexOf('=');
2073
+ const idxColon = trimmed.indexOf(':');
2074
+ const idx = idxEq >= 0 && idxColon >= 0 ? Math.min(idxEq, idxColon) : Math.max(idxEq, idxColon);
2075
+ if (idx <= 0) continue;
2076
+
2077
+ const key = trimmed.slice(0, idx).trim();
2078
+ if (!key) continue;
2079
+
2080
+ const parts = key.split('.').filter(Boolean);
2081
+ if (parts.length >= 2) {
2082
+ sigs.push(`group ${parts[0]}.${parts[1]}`);
2083
+ }
2084
+ sigs.push(`key ${key}`);
2085
+ }
2086
+
2087
+ return Array.from(new Set(sigs)).slice(0, 50);
2088
+ }
2089
+
2090
+ module.exports = { extract };
2091
+
2092
+ };
2093
+
2094
+ // ── ./src/extractors/xml ──
2095
+ __factories["./src/extractors/xml"] = function(module, exports) {
2096
+
2097
+ 'use strict';
2098
+
2099
+ /**
2100
+ * Lightweight XML config extractor.
2101
+ * Captures root tags, key config tags, and id/name/class attributes.
2102
+ *
2103
+ * @param {string} src - Raw XML content
2104
+ * @returns {string[]} Array of signature strings
2105
+ */
2106
+ function extract(src) {
2107
+ if (!src || typeof src !== 'string') return [];
2108
+ const sigs = [];
2109
+
2110
+ // Remove comments and XML declaration for simpler scanning.
2111
+ const stripped = src
2112
+ .replace(/<!--[\s\S]*?-->/g, '')
2113
+ .replace(/<\?xml[\s\S]*?\?>/gi, '');
2114
+
2115
+ // Root element (first opening tag).
2116
+ const root = stripped.match(/<\s*([A-Za-z_][\w:.-]*)\b[^>]*>/);
2117
+ if (root) sigs.push(`root ${root[1]}`);
2118
+
2119
+ // High-value config-like tags.
2120
+ const tagRe = /<\s*([A-Za-z_][\w:.-]*)\b([^>]*)>/g;
2121
+ for (const m of stripped.matchAll(tagRe)) {
2122
+ const tag = m[1];
2123
+ const attrs = m[2] || '';
2124
+
2125
+ if (/^(bean|beans|route|routes|property|properties|dependency|dependencies|plugin|plugins|configuration|settings|profile|profiles|module|modules)$/i.test(tag)) {
2126
+ sigs.push(`tag ${tag}`);
2127
+ }
2128
+
2129
+ const id = attrs.match(/\bid\s*=\s*"([^"]+)"/i);
2130
+ if (id) sigs.push(`${tag}#${id[1]}`);
2131
+
2132
+ const name = attrs.match(/\bname\s*=\s*"([^"]+)"/i);
2133
+ if (name) sigs.push(`${tag}[name=${name[1]}]`);
2134
+
2135
+ const cls = attrs.match(/\bclass\s*=\s*"([^"]+)"/i);
2136
+ if (cls) sigs.push(`${tag} -> ${cls[1]}`);
2137
+ }
2138
+
2139
+ return Array.from(new Set(sigs)).slice(0, 50);
2140
+ }
2141
+
2142
+ module.exports = { extract };
2143
+
2144
+ };
2145
+
2146
+ // ── ./src/extractors/markdown ──
2147
+ __factories["./src/extractors/markdown"] = function(module, exports) {
2148
+
2149
+ 'use strict';
2150
+
2151
+ /**
2152
+ * Lightweight markdown technical indexer.
2153
+ * Captures headings and fenced code block language hints only.
2154
+ *
2155
+ * @param {string} src - Raw markdown content
2156
+ * @returns {string[]} Array of signature strings
2157
+ */
2158
+ function extract(src) {
2159
+ if (!src || typeof src !== 'string') return [];
2160
+ const sigs = [];
2161
+
2162
+ // Headings: # .. ######
2163
+ for (const m of src.matchAll(/^(#{1,6})\s+(.+)$/gm)) {
2164
+ const level = m[1].length;
2165
+ const title = m[2].trim().replace(/\s+/g, ' ');
2166
+ if (title) sigs.push(`h${level} ${title}`);
2167
+ }
2168
+
2169
+ // Fenced code blocks: ```lang
2170
+ for (const m of src.matchAll(/^```\s*([A-Za-z0-9_+-]*)\s*$/gm)) {
2171
+ const lang = m[1] ? m[1].toLowerCase() : 'plain';
2172
+ sigs.push(`code-fence ${lang}`);
2173
+ }
2174
+
2175
+ return Array.from(new Set(sigs)).slice(0, 40);
2176
+ }
2177
+
2178
+ module.exports = { extract };
2179
+
2180
+ };
2181
+
2003
2182
  // ── ./src/extractors/deps ──
2004
2183
  __factories["./src/extractors/deps"] = function(module, exports) {
2005
2184
 
@@ -4020,7 +4199,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
4020
4199
 
4021
4200
  const SERVER_INFO = {
4022
4201
  name: 'sigmap',
4023
- version: '3.3.4',
4202
+ version: '3.4.0',
4024
4203
  description: 'SigMap MCP server — code signatures on demand',
4025
4204
  };
4026
4205
 
@@ -4944,6 +5123,11 @@ __factories["./src/eval/analyzer"] = function(module, exports) {
4944
5123
  '.graphql': 'graphql', '.gql': 'graphql',
4945
5124
  '.tf': 'terraform', '.tfvars': 'terraform',
4946
5125
  '.proto': 'protobuf',
5126
+ // Phase A formats
5127
+ '.toml': 'toml',
5128
+ '.properties': 'properties',
5129
+ '.xml': 'xml',
5130
+ '.md': 'markdown',
4947
5131
  };
4948
5132
 
4949
5133
  function isDockerfile(name) { return name === 'Dockerfile' || name.startsWith('Dockerfile.'); }
@@ -5430,7 +5614,7 @@ const path = require('path');
5430
5614
  const os = require('os');
5431
5615
  const { execSync } = require('child_process');
5432
5616
 
5433
- const VERSION = '3.3.4';
5617
+ const VERSION = '3.4.0';
5434
5618
  const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
5435
5619
 
5436
5620
  function requireSourceOrBundled(key) {
@@ -5477,6 +5661,11 @@ const EXT_MAP = {
5477
5661
  '.graphql': 'graphql', '.gql': 'graphql',
5478
5662
  '.tf': 'terraform', '.tfvars': 'terraform',
5479
5663
  '.proto': 'protobuf',
5664
+ // Phase A formats
5665
+ '.toml': 'toml',
5666
+ '.properties': 'properties',
5667
+ '.xml': 'xml',
5668
+ '.md': 'markdown',
5480
5669
  };
5481
5670
 
5482
5671
  // Dockerfile handled separately (no extension)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "3.3.4",
3
+ "version": "3.4.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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-cli",
3
- "version": "3.3.4",
3
+ "version": "3.4.0",
4
4
  "description": "SigMap CLI wrapper — thin adapter for programmatic CLI invocation",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -40,6 +40,11 @@ const EXT_MAP = {
40
40
  '.graphql': 'graphql', '.gql': 'graphql',
41
41
  '.tf': 'terraform', '.tfvars': 'terraform',
42
42
  '.proto': 'protobuf',
43
+ // Phase A formats
44
+ '.toml': 'toml',
45
+ '.properties': 'properties',
46
+ '.xml': 'xml',
47
+ '.md': 'markdown',
43
48
  };
44
49
 
45
50
  const SRC_ROOT = path.resolve(__dirname, '..', '..', 'src');
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-core",
3
- "version": "3.3.4",
3
+ "version": "3.4.0",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -22,6 +22,10 @@ const DEFAULTS = {
22
22
  'server', 'client', 'web', 'frontend', 'backend',
23
23
  'desktop', 'mobile', 'shared', 'common', 'core',
24
24
  'workers', 'functions', 'lambda', 'cmd',
25
+ // framework convention folders
26
+ 'pages', 'components', 'hooks', 'routes', 'controllers',
27
+ 'models', 'views', 'resources', 'config', 'db',
28
+ 'projects', 'apps', 'libs', 'instance', 'blueprints',
25
29
  ],
26
30
 
27
31
  // Directory/file names to exclude entirely
@@ -26,6 +26,7 @@ const SUPPORTED_CODE_EXTS = new Set([
26
26
  '.html', '.htm', '.css', '.scss', '.sass', '.less',
27
27
  '.yml', '.yaml', '.sh', '.bash', '.zsh', '.fish',
28
28
  '.sql', '.graphql', '.gql', '.tf', '.tfvars', '.proto',
29
+ '.toml', '.properties', '.xml', '.md',
29
30
  ]);
30
31
 
31
32
  /**
@@ -71,7 +72,7 @@ function detectAutoSrcDirs(cwd, excludeList) {
71
72
  const hasRequirements = fs.existsSync(path.join(cwd, 'requirements.txt'));
72
73
  const hasSetupPy = fs.existsSync(path.join(cwd, 'setup.py'));
73
74
  if (hasPyproject || hasRequirements || hasSetupPy) {
74
- for (const d of ['src', 'app', 'tests', 'examples']) candidates.add(d);
75
+ for (const d of ['src', 'app', 'apps', 'tests', 'examples', 'instance', 'blueprints']) candidates.add(d);
75
76
  }
76
77
 
77
78
  if (fs.existsSync(path.join(cwd, 'Gemfile'))) {
@@ -35,6 +35,10 @@ const EXT_MAP = {
35
35
  '.css': 'css', '.scss': 'css', '.sass': 'css', '.less': 'css',
36
36
  '.yml': 'yaml', '.yaml': 'yaml',
37
37
  '.sh': 'shell', '.bash': 'shell', '.zsh': 'shell', '.fish': 'shell',
38
+ '.toml': 'toml',
39
+ '.properties': 'properties',
40
+ '.xml': 'xml',
41
+ '.md': 'markdown',
38
42
  };
39
43
 
40
44
  function isDockerfile(name) {
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Lightweight markdown technical indexer.
5
+ * Captures headings and fenced code block language hints only.
6
+ *
7
+ * @param {string} src - Raw markdown content
8
+ * @returns {string[]} Array of signature strings
9
+ */
10
+ function extract(src) {
11
+ if (!src || typeof src !== 'string') return [];
12
+ const sigs = [];
13
+
14
+ // Headings: # .. ######
15
+ for (const m of src.matchAll(/^(#{1,6})\s+(.+)$/gm)) {
16
+ const level = m[1].length;
17
+ const title = m[2].trim().replace(/\s+/g, ' ');
18
+ if (title) sigs.push(`h${level} ${title}`);
19
+ }
20
+
21
+ // Fenced code blocks: ```lang
22
+ for (const m of src.matchAll(/^```\s*([A-Za-z0-9_+-]*)\s*$/gm)) {
23
+ const lang = m[1] ? m[1].toLowerCase() : 'plain';
24
+ sigs.push(`code-fence ${lang}`);
25
+ }
26
+
27
+ return Array.from(new Set(sigs)).slice(0, 40);
28
+ }
29
+
30
+ module.exports = { extract };
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Extract signatures from .properties configuration files.
5
+ * Captures key names, grouped by prefixes where possible.
6
+ *
7
+ * @param {string} src - Raw properties content
8
+ * @returns {string[]} Array of signature strings
9
+ */
10
+ function extract(src) {
11
+ if (!src || typeof src !== 'string') return [];
12
+ const sigs = [];
13
+
14
+ const lines = src.split(/\r?\n/);
15
+ for (const line of lines) {
16
+ const trimmed = line.trim();
17
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('!')) continue;
18
+
19
+ const idxEq = trimmed.indexOf('=');
20
+ const idxColon = trimmed.indexOf(':');
21
+ const idx = idxEq >= 0 && idxColon >= 0 ? Math.min(idxEq, idxColon) : Math.max(idxEq, idxColon);
22
+ if (idx <= 0) continue;
23
+
24
+ const key = trimmed.slice(0, idx).trim();
25
+ if (!key) continue;
26
+
27
+ const parts = key.split('.').filter(Boolean);
28
+ if (parts.length >= 2) {
29
+ sigs.push(`group ${parts[0]}.${parts[1]}`);
30
+ }
31
+ sigs.push(`key ${key}`);
32
+ }
33
+
34
+ return Array.from(new Set(sigs)).slice(0, 50);
35
+ }
36
+
37
+ module.exports = { extract };
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Extract signatures from TOML configuration files.
5
+ * Focuses on section/table names and high-value keys.
6
+ *
7
+ * @param {string} src - Raw TOML content
8
+ * @returns {string[]} Array of signature strings
9
+ */
10
+ function extract(src) {
11
+ if (!src || typeof src !== 'string') return [];
12
+ const sigs = [];
13
+
14
+ // Remove # comments while preserving values before comment markers.
15
+ const stripped = src.replace(/\s+#.*$/gm, '');
16
+
17
+ // [section] and [[array.section]]
18
+ for (const m of stripped.matchAll(/^\s*(\[\[?[^\]]+\]\]?)\s*$/gm)) {
19
+ sigs.push(`table ${m[1].trim()}`);
20
+ }
21
+
22
+ // Key-value lines (top-level and nested) — keep key names only.
23
+ for (const m of stripped.matchAll(/^\s*([A-Za-z0-9_.-]+)\s*=\s*(.+)$/gm)) {
24
+ const key = m[1].trim();
25
+ const value = m[2].trim();
26
+
27
+ // Prefer common metadata/config keys for compact, useful output.
28
+ if (/^(name|version|description|authors|license|requires-python|dependencies|optional-dependencies|scripts|tool\.|build-system\.|project\.)/.test(key)) {
29
+ sigs.push(`key ${key}`);
30
+ continue;
31
+ }
32
+
33
+ // Include booleans and simple scalar keys as generic config signal.
34
+ if (/^(true|false|"[^"]*"|'[^']*'|[0-9._-]+)$/.test(value)) {
35
+ sigs.push(`key ${key}`);
36
+ }
37
+ }
38
+
39
+ return Array.from(new Set(sigs)).slice(0, 40);
40
+ }
41
+
42
+ module.exports = { extract };
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Lightweight XML config extractor.
5
+ * Captures root tags, key config tags, and id/name/class attributes.
6
+ *
7
+ * @param {string} src - Raw XML content
8
+ * @returns {string[]} Array of signature strings
9
+ */
10
+ function extract(src) {
11
+ if (!src || typeof src !== 'string') return [];
12
+ const sigs = [];
13
+
14
+ // Remove comments and XML declaration for simpler scanning.
15
+ const stripped = src
16
+ .replace(/<!--[\s\S]*?-->/g, '')
17
+ .replace(/<\?xml[\s\S]*?\?>/gi, '');
18
+
19
+ // Root element (first opening tag).
20
+ const root = stripped.match(/<\s*([A-Za-z_][\w:.-]*)\b[^>]*>/);
21
+ if (root) sigs.push(`root ${root[1]}`);
22
+
23
+ // High-value config-like tags.
24
+ const tagRe = /<\s*([A-Za-z_][\w:.-]*)\b([^>]*)>/g;
25
+ for (const m of stripped.matchAll(tagRe)) {
26
+ const tag = m[1];
27
+ const attrs = m[2] || '';
28
+
29
+ if (/^(bean|beans|route|routes|property|properties|dependency|dependencies|plugin|plugins|configuration|settings|profile|profiles|module|modules)$/i.test(tag)) {
30
+ sigs.push(`tag ${tag}`);
31
+ }
32
+
33
+ const id = attrs.match(/\bid\s*=\s*"([^"]+)"/i);
34
+ if (id) sigs.push(`${tag}#${id[1]}`);
35
+
36
+ const name = attrs.match(/\bname\s*=\s*"([^"]+)"/i);
37
+ if (name) sigs.push(`${tag}[name=${name[1]}]`);
38
+
39
+ const cls = attrs.match(/\bclass\s*=\s*"([^"]+)"/i);
40
+ if (cls) sigs.push(`${tag} -> ${cls[1]}`);
41
+ }
42
+
43
+ return Array.from(new Set(sigs)).slice(0, 50);
44
+ }
45
+
46
+ module.exports = { extract };
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: '3.3.2',
21
+ version: '3.4.0',
22
22
  description: 'SigMap MCP server — code signatures on demand',
23
23
  };
24
24