sigmap 3.3.3 → 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 +17 -0
- package/README.md +2 -0
- package/gen-context.js +511 -2
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/index.js +5 -0
- package/packages/core/package.json +1 -1
- package/src/config/defaults.js +4 -0
- package/src/config/loader.js +2 -1
- package/src/eval/analyzer.js +4 -0
- package/src/extractors/markdown.js +30 -0
- package/src/extractors/properties.js +37 -0
- package/src/extractors/toml.js +42 -0
- package/src/extractors/xml.js +46 -0
- package/src/mcp/server.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,23 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [3.4.0] — 2026-04-14 — Phase A/B Coverage Expansion
|
|
14
|
+
|
|
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.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
13
30
|
## [3.3.3] — 2026-04-14 — Auto srcDirs + P1 Extractors
|
|
14
31
|
|
|
15
32
|
### Added
|
package/README.md
CHANGED
|
@@ -469,6 +469,8 @@ Compatible with **IntelliJ IDEA 2024.1+** (Community & Ultimate), **WebStorm**,
|
|
|
469
469
|
## 🌐 Languages supported
|
|
470
470
|
|
|
471
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.
|
|
472
474
|
|
|
473
475
|
<details>
|
|
474
476
|
<summary><strong>Show all 25 languages</strong></summary>
|
package/gen-context.js
CHANGED
|
@@ -1680,6 +1680,505 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
|
|
|
1680
1680
|
|
|
1681
1681
|
};
|
|
1682
1682
|
|
|
1683
|
+
// ── ./src/extractors/graphql ──
|
|
1684
|
+
__factories["./src/extractors/graphql"] = function(module, exports) {
|
|
1685
|
+
|
|
1686
|
+
'use strict';
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
* Extract signatures from GraphQL schema / operation files.
|
|
1690
|
+
* Captures type, interface, enum, input, union, scalar, query, mutation,
|
|
1691
|
+
* subscription, fragment definitions.
|
|
1692
|
+
*
|
|
1693
|
+
* @param {string} src - Raw GraphQL content
|
|
1694
|
+
* @returns {string[]} Array of signature strings
|
|
1695
|
+
*/
|
|
1696
|
+
function extract(src) {
|
|
1697
|
+
if (!src || typeof src !== 'string') return [];
|
|
1698
|
+
const sigs = [];
|
|
1699
|
+
|
|
1700
|
+
// Strip comments (# style)
|
|
1701
|
+
const stripped = src.replace(/#[^\n]*/g, '');
|
|
1702
|
+
|
|
1703
|
+
// Schema type definitions: type Foo [implements Bar] { ... }
|
|
1704
|
+
for (const m of stripped.matchAll(
|
|
1705
|
+
/\b(type|interface|input)\s+(\w+)(?:\s+implements\s+([\w\s&]+))?\s*\{/g
|
|
1706
|
+
)) {
|
|
1707
|
+
const implements_ = m[3] ? ` implements ${m[3].trim().replace(/\s+/g, ' ')}` : '';
|
|
1708
|
+
sigs.push(`${m[1]} ${m[2]}${implements_}`);
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// enum
|
|
1712
|
+
for (const m of stripped.matchAll(/\benum\s+(\w+)\s*\{/g)) {
|
|
1713
|
+
sigs.push(`enum ${m[1]}`);
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
// union
|
|
1717
|
+
for (const m of stripped.matchAll(/\bunion\s+(\w+)\s*=/g)) {
|
|
1718
|
+
sigs.push(`union ${m[1]}`);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// scalar
|
|
1722
|
+
for (const m of stripped.matchAll(/\bscalar\s+(\w+)/g)) {
|
|
1723
|
+
sigs.push(`scalar ${m[1]}`);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
// extend type / extend interface
|
|
1727
|
+
for (const m of stripped.matchAll(/\bextend\s+(type|interface)\s+(\w+)/g)) {
|
|
1728
|
+
sigs.push(`extend ${m[1]} ${m[2]}`);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// Query / Mutation / Subscription operations
|
|
1732
|
+
for (const m of stripped.matchAll(
|
|
1733
|
+
/\b(query|mutation|subscription)\s+(\w+)\s*(?:\([^)]*\))?\s*\{/g
|
|
1734
|
+
)) {
|
|
1735
|
+
sigs.push(`${m[1]} ${m[2]}`);
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// Named fragments
|
|
1739
|
+
for (const m of stripped.matchAll(/\bfragment\s+(\w+)\s+on\s+(\w+)/g)) {
|
|
1740
|
+
sigs.push(`fragment ${m[1]} on ${m[2]}`);
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
// Top-level schema { query: ... }
|
|
1744
|
+
if (/\bschema\s*\{/.test(stripped)) {
|
|
1745
|
+
sigs.push('schema { ... }');
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
return sigs;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
module.exports = { extract };
|
|
1752
|
+
|
|
1753
|
+
};
|
|
1754
|
+
|
|
1755
|
+
// ── ./src/extractors/protobuf ──
|
|
1756
|
+
__factories["./src/extractors/protobuf"] = function(module, exports) {
|
|
1757
|
+
|
|
1758
|
+
'use strict';
|
|
1759
|
+
|
|
1760
|
+
/**
|
|
1761
|
+
* Extract signatures from Protocol Buffer (.proto) files.
|
|
1762
|
+
* Captures message, enum, service, rpc, oneof, extend definitions.
|
|
1763
|
+
*
|
|
1764
|
+
* @param {string} src - Raw .proto content
|
|
1765
|
+
* @returns {string[]} Array of signature strings
|
|
1766
|
+
*/
|
|
1767
|
+
function extract(src) {
|
|
1768
|
+
if (!src || typeof src !== 'string') return [];
|
|
1769
|
+
const sigs = [];
|
|
1770
|
+
|
|
1771
|
+
// Strip single-line and block comments
|
|
1772
|
+
const stripped = src
|
|
1773
|
+
.replace(/\/\/[^\n]*/g, '')
|
|
1774
|
+
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
1775
|
+
|
|
1776
|
+
// syntax / package / option (top-level metadata)
|
|
1777
|
+
const syntaxM = stripped.match(/\bsyntax\s*=\s*"([^"]+)"/);
|
|
1778
|
+
if (syntaxM) sigs.push(`syntax = "${syntaxM[1]}"`);
|
|
1779
|
+
|
|
1780
|
+
const pkgM = stripped.match(/\bpackage\s+([\w.]+)\s*;/);
|
|
1781
|
+
if (pkgM) sigs.push(`package ${pkgM[1]}`);
|
|
1782
|
+
|
|
1783
|
+
// message <Name> { ... }
|
|
1784
|
+
for (const m of stripped.matchAll(/\bmessage\s+(\w+)\s*\{/g)) {
|
|
1785
|
+
sigs.push(`message ${m[1]}`);
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// enum <Name> { ... }
|
|
1789
|
+
for (const m of stripped.matchAll(/\benum\s+(\w+)\s*\{/g)) {
|
|
1790
|
+
sigs.push(`enum ${m[1]}`);
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// service <Name> { ... }
|
|
1794
|
+
for (const m of stripped.matchAll(/\bservice\s+(\w+)\s*\{/g)) {
|
|
1795
|
+
sigs.push(`service ${m[1]}`);
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
// rpc <Name>(<Request>) returns (<Response>)
|
|
1799
|
+
for (const m of stripped.matchAll(
|
|
1800
|
+
/\brpc\s+(\w+)\s*\(\s*(stream\s+)?(\w+)\s*\)\s+returns\s*\(\s*(stream\s+)?(\w+)\s*\)/g
|
|
1801
|
+
)) {
|
|
1802
|
+
const req = `${m[2] || ''}${m[3]}`.trim();
|
|
1803
|
+
const res = `${m[4] || ''}${m[5]}`.trim();
|
|
1804
|
+
sigs.push(`rpc ${m[1]}(${req}) returns (${res})`);
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
// oneof <name>
|
|
1808
|
+
for (const m of stripped.matchAll(/\boneof\s+(\w+)\s*\{/g)) {
|
|
1809
|
+
sigs.push(`oneof ${m[1]}`);
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
// extend <TypeName>
|
|
1813
|
+
for (const m of stripped.matchAll(/\bextend\s+([\w.]+)\s*\{/g)) {
|
|
1814
|
+
sigs.push(`extend ${m[1]}`);
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
return sigs;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
module.exports = { extract };
|
|
1821
|
+
|
|
1822
|
+
};
|
|
1823
|
+
|
|
1824
|
+
// ── ./src/extractors/sql ──
|
|
1825
|
+
__factories["./src/extractors/sql"] = function(module, exports) {
|
|
1826
|
+
|
|
1827
|
+
'use strict';
|
|
1828
|
+
|
|
1829
|
+
/**
|
|
1830
|
+
* Extract signatures from SQL source files.
|
|
1831
|
+
* Captures CREATE TABLE, VIEW, INDEX, FUNCTION, PROCEDURE, TRIGGER, TYPE, SEQUENCE.
|
|
1832
|
+
*
|
|
1833
|
+
* @param {string} src - Raw SQL content
|
|
1834
|
+
* @returns {string[]} Array of signature strings
|
|
1835
|
+
*/
|
|
1836
|
+
function extract(src) {
|
|
1837
|
+
if (!src || typeof src !== 'string') return [];
|
|
1838
|
+
const sigs = [];
|
|
1839
|
+
|
|
1840
|
+
// Strip single-line comments and block comments
|
|
1841
|
+
const stripped = src
|
|
1842
|
+
.replace(/--[^\n]*/g, '')
|
|
1843
|
+
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
1844
|
+
|
|
1845
|
+
// CREATE TABLE [IF NOT EXISTS] <name> / CREATE [TEMP] TABLE ...
|
|
1846
|
+
for (const m of stripped.matchAll(
|
|
1847
|
+
/CREATE\s+(?:OR\s+REPLACE\s+)?(?:TEMP(?:ORARY)?\s+)?TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([`"[\w.]+)/gi
|
|
1848
|
+
)) {
|
|
1849
|
+
sigs.push(`TABLE ${_cleanName(m[1])}`);
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// CREATE VIEW / MATERIALIZED VIEW
|
|
1853
|
+
for (const m of stripped.matchAll(
|
|
1854
|
+
/CREATE\s+(?:OR\s+REPLACE\s+)?(?:MATERIALIZED\s+)?VIEW\s+(?:IF\s+NOT\s+EXISTS\s+)?([`"[\w.]+)/gi
|
|
1855
|
+
)) {
|
|
1856
|
+
sigs.push(`VIEW ${_cleanName(m[1])}`);
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// CREATE INDEX / UNIQUE INDEX
|
|
1860
|
+
for (const m of stripped.matchAll(
|
|
1861
|
+
/CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:CONCURRENTLY\s+)?(?:IF\s+NOT\s+EXISTS\s+)?([`"[\w.]+)\s+ON\s+([`"[\w.]+)/gi
|
|
1862
|
+
)) {
|
|
1863
|
+
sigs.push(`INDEX ${_cleanName(m[1])} ON ${_cleanName(m[2])}`);
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
// CREATE FUNCTION / CREATE OR REPLACE FUNCTION
|
|
1867
|
+
for (const m of stripped.matchAll(
|
|
1868
|
+
/CREATE\s+(?:OR\s+REPLACE\s+)?FUNCTION\s+([`"[\w.]+)\s*\(([^)]*)\)/gi
|
|
1869
|
+
)) {
|
|
1870
|
+
const params = _normalizeParams(m[2]);
|
|
1871
|
+
sigs.push(`FUNCTION ${_cleanName(m[1])}(${params})`);
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
// CREATE PROCEDURE
|
|
1875
|
+
for (const m of stripped.matchAll(
|
|
1876
|
+
/CREATE\s+(?:OR\s+REPLACE\s+)?PROCEDURE\s+([`"[\w.]+)\s*\(([^)]*)\)/gi
|
|
1877
|
+
)) {
|
|
1878
|
+
const params = _normalizeParams(m[2]);
|
|
1879
|
+
sigs.push(`PROCEDURE ${_cleanName(m[1])}(${params})`);
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
// CREATE TRIGGER
|
|
1883
|
+
for (const m of stripped.matchAll(
|
|
1884
|
+
/CREATE\s+(?:OR\s+REPLACE\s+)?(?:CONSTRAINT\s+)?TRIGGER\s+([`"[\w.]+)/gi
|
|
1885
|
+
)) {
|
|
1886
|
+
sigs.push(`TRIGGER ${_cleanName(m[1])}`);
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
// CREATE TYPE (composite, enum, domain)
|
|
1890
|
+
for (const m of stripped.matchAll(
|
|
1891
|
+
/CREATE\s+(?:OR\s+REPLACE\s+)?TYPE\s+([`"[\w.]+)/gi
|
|
1892
|
+
)) {
|
|
1893
|
+
sigs.push(`TYPE ${_cleanName(m[1])}`);
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
// CREATE SEQUENCE
|
|
1897
|
+
for (const m of stripped.matchAll(
|
|
1898
|
+
/CREATE\s+(?:OR\s+REPLACE\s+)?SEQUENCE\s+(?:IF\s+NOT\s+EXISTS\s+)?([`"[\w.]+)/gi
|
|
1899
|
+
)) {
|
|
1900
|
+
sigs.push(`SEQUENCE ${_cleanName(m[1])}`);
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
return sigs;
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
function _cleanName(raw) {
|
|
1907
|
+
return raw.replace(/^[`"[]|[`"\]]+$/g, '').trim();
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
function _normalizeParams(raw) {
|
|
1911
|
+
if (!raw || !raw.trim()) return '';
|
|
1912
|
+
return raw.trim()
|
|
1913
|
+
.split(',')
|
|
1914
|
+
.map((p) => p.trim().replace(/\s+/g, ' ').split(' ').slice(0, 2).join(' '))
|
|
1915
|
+
.filter(Boolean)
|
|
1916
|
+
.join(', ');
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
module.exports = { extract };
|
|
1920
|
+
|
|
1921
|
+
};
|
|
1922
|
+
|
|
1923
|
+
// ── ./src/extractors/terraform ──
|
|
1924
|
+
__factories["./src/extractors/terraform"] = function(module, exports) {
|
|
1925
|
+
|
|
1926
|
+
'use strict';
|
|
1927
|
+
|
|
1928
|
+
/**
|
|
1929
|
+
* Extract signatures from Terraform (.tf / .tfvars) configuration files.
|
|
1930
|
+
* Captures resource, data, module, variable, output, locals, provider,
|
|
1931
|
+
* terraform blocks, and moved/import blocks.
|
|
1932
|
+
*
|
|
1933
|
+
* @param {string} src - Raw Terraform content
|
|
1934
|
+
* @returns {string[]} Array of signature strings
|
|
1935
|
+
*/
|
|
1936
|
+
function extract(src) {
|
|
1937
|
+
if (!src || typeof src !== 'string') return [];
|
|
1938
|
+
const sigs = [];
|
|
1939
|
+
|
|
1940
|
+
// Strip single-line comments
|
|
1941
|
+
const stripped = src
|
|
1942
|
+
.replace(/\/\/[^\n]*/g, '')
|
|
1943
|
+
.replace(/#[^\n]*/g, '')
|
|
1944
|
+
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
1945
|
+
|
|
1946
|
+
// resource "<type>" "<name>" { ... }
|
|
1947
|
+
for (const m of stripped.matchAll(/\bresource\s+"([^"]+)"\s+"([^"]+)"\s*\{/g)) {
|
|
1948
|
+
sigs.push(`resource "${m[1]}" "${m[2]}"`);
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
// data "<type>" "<name>" { ... }
|
|
1952
|
+
for (const m of stripped.matchAll(/\bdata\s+"([^"]+)"\s+"([^"]+)"\s*\{/g)) {
|
|
1953
|
+
sigs.push(`data "${m[1]}" "${m[2]}"`);
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
// module "<name>" { ... }
|
|
1957
|
+
for (const m of stripped.matchAll(/\bmodule\s+"([^"]+)"\s*\{/g)) {
|
|
1958
|
+
sigs.push(`module "${m[1]}"`);
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
// variable "<name>" { ... }
|
|
1962
|
+
for (const m of stripped.matchAll(/\bvariable\s+"([^"]+)"\s*\{/g)) {
|
|
1963
|
+
sigs.push(`variable "${m[1]}"`);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
// output "<name>" { ... }
|
|
1967
|
+
for (const m of stripped.matchAll(/\boutput\s+"([^"]+)"\s*\{/g)) {
|
|
1968
|
+
sigs.push(`output "${m[1]}"`);
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
// provider "<name>" { ... }
|
|
1972
|
+
for (const m of stripped.matchAll(/\bprovider\s+"([^"]+)"\s*\{/g)) {
|
|
1973
|
+
sigs.push(`provider "${m[1]}"`);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
// locals { ... } (just mark presence; key names too noisy to enumerate)
|
|
1977
|
+
if (/\blocals\s*\{/.test(stripped)) {
|
|
1978
|
+
sigs.push('locals { ... }');
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
// terraform { required_providers / backend }
|
|
1982
|
+
if (/\bterraform\s*\{/.test(stripped)) {
|
|
1983
|
+
sigs.push('terraform { ... }');
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
// moved block
|
|
1987
|
+
for (const m of stripped.matchAll(/\bmoved\s*\{[\s\S]*?from\s*=\s*([^\n]+)/g)) {
|
|
1988
|
+
sigs.push(`moved from ${m[1].trim()}`);
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
// import block (Terraform 1.5+)
|
|
1992
|
+
for (const m of stripped.matchAll(/\bimport\s*\{[\s\S]*?to\s*=\s*([^\n]+)/g)) {
|
|
1993
|
+
sigs.push(`import to ${m[1].trim()}`);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
return sigs;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
module.exports = { extract };
|
|
2000
|
+
|
|
2001
|
+
};
|
|
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
|
+
|
|
1683
2182
|
// ── ./src/extractors/deps ──
|
|
1684
2183
|
__factories["./src/extractors/deps"] = function(module, exports) {
|
|
1685
2184
|
|
|
@@ -3700,7 +4199,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
3700
4199
|
|
|
3701
4200
|
const SERVER_INFO = {
|
|
3702
4201
|
name: 'sigmap',
|
|
3703
|
-
version: '3.
|
|
4202
|
+
version: '3.4.0',
|
|
3704
4203
|
description: 'SigMap MCP server — code signatures on demand',
|
|
3705
4204
|
};
|
|
3706
4205
|
|
|
@@ -4624,6 +5123,11 @@ __factories["./src/eval/analyzer"] = function(module, exports) {
|
|
|
4624
5123
|
'.graphql': 'graphql', '.gql': 'graphql',
|
|
4625
5124
|
'.tf': 'terraform', '.tfvars': 'terraform',
|
|
4626
5125
|
'.proto': 'protobuf',
|
|
5126
|
+
// Phase A formats
|
|
5127
|
+
'.toml': 'toml',
|
|
5128
|
+
'.properties': 'properties',
|
|
5129
|
+
'.xml': 'xml',
|
|
5130
|
+
'.md': 'markdown',
|
|
4627
5131
|
};
|
|
4628
5132
|
|
|
4629
5133
|
function isDockerfile(name) { return name === 'Dockerfile' || name.startsWith('Dockerfile.'); }
|
|
@@ -5110,7 +5614,7 @@ const path = require('path');
|
|
|
5110
5614
|
const os = require('os');
|
|
5111
5615
|
const { execSync } = require('child_process');
|
|
5112
5616
|
|
|
5113
|
-
const VERSION = '3.
|
|
5617
|
+
const VERSION = '3.4.0';
|
|
5114
5618
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
5115
5619
|
|
|
5116
5620
|
function requireSourceOrBundled(key) {
|
|
@@ -5157,6 +5661,11 @@ const EXT_MAP = {
|
|
|
5157
5661
|
'.graphql': 'graphql', '.gql': 'graphql',
|
|
5158
5662
|
'.tf': 'terraform', '.tfvars': 'terraform',
|
|
5159
5663
|
'.proto': 'protobuf',
|
|
5664
|
+
// Phase A formats
|
|
5665
|
+
'.toml': 'toml',
|
|
5666
|
+
'.properties': 'properties',
|
|
5667
|
+
'.xml': 'xml',
|
|
5668
|
+
'.md': 'markdown',
|
|
5160
5669
|
};
|
|
5161
5670
|
|
|
5162
5671
|
// Dockerfile handled separately (no extension)
|
package/package.json
CHANGED
package/packages/core/index.js
CHANGED
|
@@ -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');
|
package/src/config/defaults.js
CHANGED
|
@@ -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
|
package/src/config/loader.js
CHANGED
|
@@ -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'))) {
|
package/src/eval/analyzer.js
CHANGED
|
@@ -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