sigmap 2.0.0-beta.5 → 2.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/CHANGELOG.md CHANGED
@@ -6,88 +6,37 @@ Format: [Semantic Versioning](https://semver.org/)
6
6
 
7
7
  ---
8
8
 
9
- ## [2.0.0-beta.5] — 2026-04-03
9
+ ## [2.0.0] — 2026-04-04
10
10
 
11
- ### Changed
12
- - Prerelease version bumped from `2.0.0-beta.4` to `2.0.0-beta.5` across CLI, MCP server info, root package metadata, and VS Code extension metadata.
13
-
14
- ### Validation gate
15
- - 21/21 extractor tests passed
16
- - 17/17 integration suites passed (including v2plus 3/3)
17
-
18
- ---
19
-
20
- ## [2.0.0-beta.4]2026-04-03
21
-
22
- ### Changed
23
- - Prerelease version bumped from `2.0.0-beta.3` to `2.0.0-beta.4` across CLI, MCP server info, root package metadata, and VS Code extension metadata.
24
-
25
- ### Validation gate
26
- - 21/21 extractor tests passed
27
- - 17/17 integration suites passed (including v2plus 3/3)
28
-
29
- ---
30
-
31
- ## [2.0.0-beta.3] — 2026-04-03
11
+ ### Added
12
+ - **v2 output enrichment pipeline** — compact `deps`, `todos`, `changes` sections auto-generated in context output.
13
+ - **Structural diff mode** — `--diff <base-ref>` writes a signature-level diff section comparing current signatures against a base branch.
14
+ - **Test coverage markers** — opt-in per-function `✓`/`✗` hints by scanning test directories (`testCoverage: true`).
15
+ - **Impact radius hints** — opt-in reverse dependency annotations (`impactRadius: true`).
16
+ - **New helper extractors**:
17
+ - `src/extractors/deps.js` — Python and TS/JS dependency extraction + reverse dep map.
18
+ - `src/extractors/todos.js` — TODO/FIXME/HACK/XXX harvesting (max 20 entries).
19
+ - `src/extractors/coverage.js` — lightweight function/test correlation.
20
+ - `src/extractors/prdiff.js`signature-level base-ref diffs.
21
+ - **New config keys**: `enrichSignatures`, `depMap`, `schemaFields`, `todos`, `changes`, `changesCommits`, `testCoverage`, `testDirs`, `impactRadius`.
22
+ - `test/integration/v2plus.test.js` — 3 integration tests for todos, coverage markers, and structural diff.
23
+ - `test/integration/all.js` unified integration runner and `test:integration:all` npm script.
32
24
 
33
25
  ### Changed
34
- - Prerelease version bumped from `2.0.0-beta.2` to `2.0.0-beta.3` across CLI, MCP server info, root package metadata, and VS Code extension metadata.
35
- - Version drift in [gen-context.js](gen-context.js) was corrected so runtime reporting matches published package metadata.
36
-
37
- ### Validation gate
38
- - `node scripts/bundle.js`
39
- - `node test/run.js`
40
- - `node test/integration/all.js`
41
- - `node gen-context.js --report`
42
-
43
- ## [2.0.0-beta.2] — 2026-04-03
26
+ - **Enriched multi-language extractors** return-type hints (`→ Type`) and richer signatures across C++, C#, Dart, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, Rust, Scala, Svelte, Swift, TypeScript, and Vue.
27
+ - **Python extractor** dataclass/BaseModel field collapse, top-level docstring hints, fixed field bleed across class boundaries.
28
+ - **TypeScript extractor** — interface property types, class method return hints, compact hook return shapes for `export function useX()`, union type truncation extended to 35 chars.
29
+ - Removed stale development files: `TIMELINE.md`, `scripts/bundle.js`, `scripts/make-icon.py`, `scripts/inject-search.py`, `scripts/backfill-npm.sh`, `examples/slack-context-bot.js`, `examples/copilot-prompts.code-snippets`.
44
30
 
45
31
  ### Fixed
46
- - Python BaseModel field extraction no longer bleeds into subsequent classes when class bodies are separated by blank lines.
47
- - Updated [src/extractors/python.js](src/extractors/python.js) `tryExtractBaseModelFields` to stop scanning at the next top-level block.
48
- - TypeScript interface member type previews now preserve longer union strings.
49
- - Updated [src/extractors/typescript.js](src/extractors/typescript.js) to extend interface type truncation from 20 to 35 characters.
50
- - TypeScript function-style hooks (`export function useX`) now include compact return object shapes, matching existing arrow-hook behavior.
51
- - Updated [src/extractors/typescript.js](src/extractors/typescript.js) export-function extraction path.
52
-
53
- ### Changed
54
- - Prerelease version bumped from `2.0.0-beta.1` to `2.0.0-beta.2` across CLI, MCP server info, root package metadata, and VS Code extension metadata.
32
+ - Python `tryExtractBaseModelFields` no longer bleeds fields into subsequent classes.
33
+ - TypeScript interface member type previews preserve longer union strings (20 → 35 chars).
34
+ - TypeScript function-style hooks (`export function useX`) now include compact return object shapes.
55
35
 
56
36
  ### Validation gate
57
- - `node scripts/bundle.js`
58
- - `node test/run.js`
59
- - `node test/integration/all.js`
60
- - `node gen-context.js --report`
61
- - `node /Users/manojmallick/context-forge/gen-context.js --report` on arbi-platform
62
-
63
- ## [2.0.0-beta.1] — 2026-04-03
64
-
65
- ### Added
66
- - v2 output enrichment pipeline in [gen-context.js](gen-context.js): compact `deps`, `todos`, `changes`, optional structural `diff (vs <base>)`, optional test coverage markers, and optional impact-radius hints.
67
- - New helper extractors:
68
- - [src/extractors/deps.js](src/extractors/deps.js) for Python and TS/JS dependency extraction
69
- - [src/extractors/todos.js](src/extractors/todos.js) for TODO/FIXME/HACK/XXX harvesting
70
- - [src/extractors/coverage.js](src/extractors/coverage.js) for lightweight function/test correlation
71
- - [src/extractors/prdiff.js](src/extractors/prdiff.js) for signature-level base-ref diffs
72
- - New integration coverage in [test/integration/v2plus.test.js](test/integration/v2plus.test.js) for todos, changes, test coverage markers, and `--diff <base-ref>`.
73
- - New unified integration runner in [test/integration/all.js](test/integration/all.js) and npm script `test:integration:all` in [package.json](package.json).
74
-
75
- ### Changed
76
- - Expanded multi-language extractors to surface compact return-type hints and richer signatures across C++, C#, Dart, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, Rust, Scala, Svelte, Swift, TypeScript, and Vue.
77
- - Python extractor now supports dataclass/BaseModel field collapse and top-level docstring hints.
78
- - TypeScript extractor now exposes interface property types, class method return hints, and compact hook return shapes for `use*` exports.
79
- - Source config defaults in [src/config/defaults.js](src/config/defaults.js) now include strategy keys and v2 output toggles so source-loaded config matches bundled behavior.
80
- - Compatibility tests were updated to current `sigmap.*` command/config naming and broader MCP tool lists.
81
-
82
- ### Validation gate
83
- - `node test/run.js` → 21/21 pass
84
- - `node test/integration/all.js` → 17/17 integration suites pass
85
- - `node gen-context.js --report` on this repo → ~93.6% reduction
86
- - `node /Users/manojmallick/context-forge/gen-context.js --report` on arbi-platform → ~85.7% reduction, 3987 output tokens
87
-
88
- ### Notes
89
- - This is a prerelease build intended for final release hardening before stable `2.0.0`.
90
- - Publish with the `beta` dist-tag to avoid upgrading stable consumers automatically.
37
+ - 21/21 extractor tests passed
38
+ - 17/17 integration suites passed (262 individual tests)
39
+ - `node gen-context.js --report` → ~93.5% reduction
91
40
 
92
41
 
93
42
  ## [1.5.0] — 2026-04-04
@@ -116,7 +65,6 @@ Format: [Semantic Versioning](https://semver.org/)
116
65
 
117
66
  ### Notes
118
67
  - The VS Code extension requires the `vscode` peer dependency at runtime (provided by the editor). It has no npm runtime dependencies of its own.
119
- - `scripts/inject-search.py` is the one-time migration script used to add search to existing HTML pages; it is idempotent (skip if already patched).
120
68
 
121
69
  ### Validation gate
122
70
  - `node gen-context.js --version` → `1.5.0` ✔ *(note: version bumped separately if desired)*
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  <!-- Status -->
13
13
  [![npm version](https://img.shields.io/npm/v/sigmap?color=7c6af7&label=latest&logo=npm)](https://www.npmjs.com/package/sigmap)
14
- [![Tests](https://img.shields.io/badge/tests-274%20passing-22c55e)](https://github.com/manojmallick/sigmap/tree/main/test)
14
+ [![Tests](https://img.shields.io/badge/tests-262%20passing-22c55e)](https://github.com/manojmallick/sigmap/tree/main/test)
15
15
  [![Zero deps](https://img.shields.io/badge/dependencies-zero-22c55e)](package.json)
16
16
  [![Last commit](https://img.shields.io/github/last-commit/manojmallick/sigmap?color=7c6af7)](https://github.com/manojmallick/sigmap/commits/main)
17
17
 
@@ -82,6 +82,23 @@ AI agent session starts with full context
82
82
 
83
83
  ---
84
84
 
85
+ ## 🆕 What's new in 2.0
86
+
87
+ | Feature | Description |
88
+ |---|---|
89
+ | **Enriched signatures** | Return types, type hints, and schema field collapse (Python `@dataclass` / `BaseModel`) |
90
+ | **Dependency map** | Compact import dependency section at the top of output (~50–100 extra tokens) |
91
+ | **TODO/FIXME section** | Auto-harvested TODO/FIXME/HACK/XXX comments (max 20 entries) |
92
+ | **Recent changes section** | Git-based recent changes summary in output |
93
+ | **Test coverage markers** | Per-function `✓`/`✗` hints by scanning test directories |
94
+ | **Structural diff mode** | `--diff <base-ref>` writes a signature-level diff section |
95
+ | **Impact radius hints** | Reverse dependency annotations (used by: ...) |
96
+ | **New helper extractors** | `deps.js`, `todos.js`, `coverage.js`, `prdiff.js` |
97
+
98
+ Several v2 enhancements (deps map, TODOs, recent changes) are enabled by default. All v2 sections can be tuned or disabled via `gen-context.config.json`.
99
+
100
+ ---
101
+
85
102
  ## 🚀 Quick start
86
103
 
87
104
  **No install required — just Node.js 18+.**
@@ -147,7 +164,7 @@ The `vscode-extension/` directory contains a first-party VS Code extension that
147
164
  | **Stale notification** | Warns when `copilot-instructions.md` is > 24 h old; one-click regeneration |
148
165
  | **Regenerate command** | `SigMap: Regenerate Context` — runs `node gen-context.js` in the integrated terminal |
149
166
  | **Open context command** | `SigMap: Open Context File` — opens `.github/copilot-instructions.md` |
150
- | **Script path setting** | `contextforge.scriptPath` — override when `gen-context.js` is not at the project root |
167
+ | **Script path setting** | `sigmap.scriptPath` — override when `gen-context.js` is not at the project root |
151
168
 
152
169
  Activate on startup (`onStartupFinished`) — loads within 3 s, never blocks editor startup.
153
170
 
@@ -380,7 +397,7 @@ node gen-context.js --track
380
397
 
381
398
  # Structured JSON report for CI (exits 1 if over budget)
382
399
  node gen-context.js --report --json
383
- # { "version": "1.5.0", "finalTokens": 3200, "reductionPct": 92.4, "overBudget": false }
400
+ # { "version": "2.0.0", "finalTokens": 3200, "reductionPct": 92.4, "overBudget": false }
384
401
 
385
402
  # Composite health score
386
403
  node gen-context.js --health
@@ -478,7 +495,7 @@ sigmap/
478
495
  │ ├── fixtures/ ← one source file per language
479
496
  │ ├── expected/ ← expected extractor output
480
497
  │ ├── run.js ← zero-dep test runner
481
- │ └── integration/ ← 16 integration test files (253 tests)
498
+ │ └── integration/ ← 17 integration test files (241 tests)
482
499
 
483
500
  ├── docs/ ← documentation site (GitHub Pages)
484
501
  │ ├── index.html ← homepage
@@ -490,11 +507,12 @@ sigmap/
490
507
 
491
508
  ├── scripts/
492
509
  │ ├── ci-update.sh ← CI pipeline helper
493
- │ └── inject-search.py one-time: add search to docs HTML pages
510
+ │ └── release.sh version bump + npm publish helper
494
511
 
495
512
  ├── examples/
496
513
  │ ├── self-healing-github-action.yml
497
- └── gen-context.config.json full annotated config
514
+ ├── github-action.yml ready-to-use CI workflow
515
+ │ └── claude-code-settings.json ← MCP server config example
498
516
 
499
517
  ├── .npmignore ← excludes docs/, test/, vscode-extension/ from publish
500
518
  ├── .contextignore.example ← exclusion template
@@ -1,5 +1,5 @@
1
1
  {
2
- "_comment": "ContextForge configuration — all keys are optional (defaults shown)",
2
+ "_comment": "SigMap configuration — all keys are optional (defaults shown)",
3
3
 
4
4
  "output": ".github/copilot-instructions.md",
5
5
 
@@ -38,15 +38,9 @@
38
38
  "_hotCommits_comment": "Only used by hot-cold strategy: how many recent commits count as 'hot'",
39
39
  "hotCommits": 10,
40
40
 
41
- "_enrichSignatures_comment": "Enrich signatures with return types, type hints, and schema field collapse (Python @dataclass / BaseModel)",
42
- "enrichSignatures": true,
43
-
44
41
  "_depMap_comment": "Include a compact import dependency map at the top of the output (~50-100 extra tokens)",
45
42
  "depMap": true,
46
43
 
47
- "_schemaFields_comment": "Collapse Pydantic BaseModel / @dataclass class bodies to a single field-list line",
48
- "schemaFields": true,
49
-
50
44
  "_todos_comment": "Include compact TODO/FIXME/HACK/XXX section (max 20 entries)",
51
45
  "todos": true,
52
46
 
package/gen-context.js CHANGED
@@ -983,8 +983,26 @@ __factories["./src/extractors/python"] = function(module, exports) {
983
983
  const retStr = retType ? ` \u2192 ${retType}` : '';
984
984
  sigs.push(`${asyncKw}def ${m[2]}(${params})${retStr}`);
985
985
  }
986
+
987
+ // FastAPI router endpoints: @router.METHOD("path") + async def name(...)
988
+ const lines = noComments.split('\n');
989
+ for (let i = 0; i < lines.length - 1; i++) {
990
+ const decLine = lines[i].trim();
991
+ const rm = decLine.match(/^@\w+\.(get|post|put|patch|delete|head)\s*\(\s*['"]([^'"]+)['"]/);
992
+ if (!rm) continue;
993
+ // Find the next non-empty, non-decorator line that starts the function
994
+ for (let j = i + 1; j < Math.min(i + 6, lines.length); j++) {
995
+ const fl = lines[j].trim();
996
+ const fm = fl.match(/^(?:async\s+)?def\s+(\w+)/);
997
+ if (fm) {
998
+ sigs.push(`${rm[1].toUpperCase()} ${rm[2]} → ${fm[1]}()`);
999
+ break;
1000
+ }
1001
+ if (fl && !fl.startsWith('@') && !fl.startsWith('#')) break;
1002
+ }
1003
+ }
986
1004
 
987
- return sigs.slice(0, 25);
1005
+ return sigs.slice(0, 30);
988
1006
  }
989
1007
 
990
1008
  function extractClassMethods(stripped, startIndex) {
@@ -1027,8 +1045,12 @@ __factories["./src/extractors/python"] = function(module, exports) {
1027
1045
  function tryExtractBaseModelFields(stripped, bodyStart) {
1028
1046
  const lines = stripped.slice(bodyStart, bodyStart + 800).split('\n');
1029
1047
  const fields = [];
1048
+ let foundFirst = false;
1030
1049
  for (const line of lines) {
1050
+ if (line.trim() === '') continue;
1051
+ if (foundFirst && !/^\s/.test(line)) break;
1031
1052
  if (!line.match(/^\s{4}\w/)) continue;
1053
+ foundFirst = true;
1032
1054
  const f = line.match(/^\s{4}(\w+)\s*(?::\s*([^=\n]+?))?(?:\s*=\s*(.*))?$/);
1033
1055
  if (!f || f[1].startsWith('_') || f[1] === 'class' || f[1] === 'def') continue;
1034
1056
  const isOptional = (f[2] || '').includes('Optional') || f[3] !== undefined;
@@ -1562,8 +1584,36 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
1562
1584
  const params = normalizeParams(m[2]);
1563
1585
  sigs.push(`export const ${m[1]} = ${asyncKw}(${params}) =>`);
1564
1586
  }
1587
+
1588
+ // Zustand stores: export const useXxxStore = create<State>()(...)
1589
+ for (const m of stripped.matchAll(/^export\s+const\s+(use\w+Store)\s*=\s*create(?:<[^>]*>)?\s*\(/gm)) {
1590
+ // Extract the State interface name from create<StateName>
1591
+ const stateType = m[0].match(/create<([\w]+)>/)?.[1] || '';
1592
+ sigs.push(`export const ${m[1]} = create<${stateType}>(...)`);
1593
+ // Extract action/state keys from the embedded interface in same file
1594
+ const ifaceRe = new RegExp(`interface\\s+${stateType}\\s*\\{([\\s\\S]*?)\\}`);
1595
+ const ifm = stripped.match(ifaceRe);
1596
+ if (ifm) {
1597
+ for (const fm of ifm[1].matchAll(/^\s+(\w+)\s*(?:\([^)]*\))?\s*:/gm)) {
1598
+ sigs.push(` ${fm[1]}`);
1599
+ }
1600
+ }
1601
+ }
1602
+
1603
+ // API client objects: export default { method: async (...) => ... }
1604
+ // Pattern: const xxxApi = { methodName: async ... }
1605
+ for (const m of stripped.matchAll(/^(?:export\s+default\s+|const\s+)(\w*[Aa]pi\w*)\s*=\s*\{/gm)) {
1606
+ const apiName = m[1];
1607
+ const start = m.index + m[0].length;
1608
+ const block = extractBlock(stripped, start);
1609
+ const methods = [];
1610
+ for (const mm of block.matchAll(/^\s+(\w+)\s*:\s*(?:async\s+)?(?:\([^)]*\)|\w+)\s*=>/gm)) {
1611
+ methods.push(mm[1]);
1612
+ }
1613
+ if (methods.length) sigs.push(`${apiName}: { ${methods.join(', ')} }`);
1614
+ }
1565
1615
 
1566
- return sigs.slice(0, 25);
1616
+ return sigs.slice(0, 35);
1567
1617
  }
1568
1618
 
1569
1619
  function extractBlock(src, startIndex) {
@@ -1583,7 +1633,7 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
1583
1633
  for (const m of block.matchAll(/^\s+(readonly\s+)?(\w+)(\??):\s*([^;]+);/gm)) {
1584
1634
  const readonly = m[1] ? 'readonly ' : '';
1585
1635
  const optional = m[3] ? '?' : '';
1586
- const typeStr = m[4].trim().replace(/\s+/g, ' ').slice(0, 20);
1636
+ const typeStr = m[4].trim().replace(/\s+/g, ' ').slice(0, 35);
1587
1637
  members.push(`${readonly}${m[2]}${optional}: ${typeStr}`);
1588
1638
  }
1589
1639
  for (const m of block.matchAll(/^\s+(\w+)\s*(?:<[^(]*>)?\s*\(([^)]*)\)\s*:/gm)) {
@@ -1666,7 +1716,20 @@ __factories["./src/extractors/deps"] = function(module, exports) {
1666
1716
  return [...deps].slice(0, 5);
1667
1717
  }
1668
1718
 
1669
- module.exports = { extractPythonDeps, extractTSDeps };
1719
+ function buildReverseDepMap(forwardMap) {
1720
+ const reverse = new Map();
1721
+ if (!forwardMap || typeof forwardMap.entries !== 'function') return reverse;
1722
+ for (const [file, deps] of forwardMap.entries()) {
1723
+ if (!Array.isArray(deps)) continue;
1724
+ for (const dep of deps) {
1725
+ if (!reverse.has(dep)) reverse.set(dep, []);
1726
+ reverse.get(dep).push(file);
1727
+ }
1728
+ }
1729
+ return reverse;
1730
+ }
1731
+
1732
+ module.exports = { extractPythonDeps, extractTSDeps, buildReverseDepMap };
1670
1733
 
1671
1734
  };
1672
1735
 
@@ -3520,7 +3583,7 @@ const path = require('path');
3520
3583
  const os = require('os');
3521
3584
  const { execSync } = require('child_process');
3522
3585
 
3523
- const VERSION = '2.0.0-beta.5';
3586
+ const VERSION = '2.0.0';
3524
3587
  const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
3525
3588
 
3526
3589
  function requireSourceOrBundled(key) {
@@ -3794,8 +3857,13 @@ function getDiffFiles(cwd, stagedOnly) {
3794
3857
  }
3795
3858
 
3796
3859
  function getFilesChangedSinceBase(cwd, baseRef) {
3860
+ if (!/^[A-Za-z0-9._/\-~^]+$/.test(baseRef)) {
3861
+ console.warn(`[sigmap] --diff: invalid base ref '${baseRef}'`);
3862
+ return new Set();
3863
+ }
3797
3864
  try {
3798
- const out = execSync(`git diff ${baseRef}..HEAD --name-only`, {
3865
+ const { execFileSync } = require('child_process');
3866
+ const out = execFileSync('git', ['diff', `${baseRef}..HEAD`, '--name-only'], {
3799
3867
  cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
3800
3868
  });
3801
3869
  return new Set(out.split('\n').map((f) => f.trim()).filter(Boolean).map((f) => path.resolve(cwd, f)));
@@ -3812,7 +3880,8 @@ function buildDiffSectionFromBase(cwd, baseRef, currentEntries, config) {
3812
3880
  const rel = path.relative(cwd, entry.filePath);
3813
3881
  let baseSrc = '';
3814
3882
  try {
3815
- baseSrc = execSync(`git show ${baseRef}:"${rel}" 2>/dev/null`, {
3883
+ const { execFileSync } = require('child_process');
3884
+ baseSrc = execFileSync('git', ['show', `${baseRef}:${rel}`], {
3816
3885
  cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
3817
3886
  });
3818
3887
  } catch (_) {
@@ -3919,9 +3988,11 @@ function buildChangesSection(cwd, config, fileEntries) {
3919
3988
  }
3920
3989
  const plus = [...diff.matchAll(/^\+.*(?:def\s+|function\s+|class\s+|func\s+)(\w+)/gm)].map((m) => `+${m[1]}`);
3921
3990
  const modDef = [...diff.matchAll(/^-.*(?:def\s+|function\s+|class\s+|func\s+)(\w+)/gm)].map((m) => `~${m[1]}`);
3922
- // Also extract function names from @@ hunk headers (catches body-only changes like added comments/lines)
3991
+ // Hunk headers (Python/Go/Java: git shows enclosing func in @@ ... @@ context)
3923
3992
  const modCtx = [...diff.matchAll(/^@@[^@]*@@\s+(?:(?:async|export|public|private|static)\s+)*(?:def|function|class|func)\s+(\w+)/gm)].map((m) => `~${m[1]}`);
3924
- const delta = [...new Set([...plus, ...modDef, ...modCtx])].slice(0, 4).join(' ');
3993
+ // Context lines (TS/JS: git doesn't detect funcname, so scan the unchanged lines adjacent to hunks)
3994
+ const ctxFn = [...diff.matchAll(/^ +(?:export\s+)?(?:async\s+)?(?:default\s+)?(?:function\s+(\w+)|class\s+(\w+))/gm)].map((m) => `~${m[1] || m[2]}`);
3995
+ const delta = [...new Set([...plus, ...modDef, ...modCtx, ...ctxFn])].slice(0, 4).join(' ');
3925
3996
  if (delta) {
3926
3997
  hasDelta = true;
3927
3998
  lines.push(`${rel.padEnd(45)} ${delta}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.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
  "bin": {
@@ -72,15 +72,9 @@ const DEFAULTS = {
72
72
  autoRegister: true,
73
73
  },
74
74
 
75
- // Enrich signatures with return types, type hints, and schema field collapse
76
- enrichSignatures: true,
77
-
78
75
  // Include a compact import dependency map at top of output
79
76
  depMap: true,
80
77
 
81
- // Collapse Pydantic BaseModel / @dataclass fields to a single line
82
- schemaFields: true,
83
-
84
78
  // Include TODO/FIXME/HACK/XXX comments as compact section
85
79
  todos: true,
86
80
 
@@ -35,11 +35,11 @@ function buildTestIndex(cwd, testDirs) {
35
35
  }
36
36
 
37
37
  for (const m of src.matchAll(/\b(?:test_|it\(|test\(|describe\()\s*['"`]?([\w_]+)/g)) {
38
- if (m[1]) names.add(m[1].toLowerCase());
38
+ if (m[1] && m[1].length >= 3) names.add(m[1].toLowerCase());
39
39
  }
40
40
 
41
41
  for (const m of src.matchAll(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g)) {
42
- if (m[1]) names.add(m[1].toLowerCase());
42
+ if (m[1] && m[1].length >= 4) names.add(m[1].toLowerCase());
43
43
  }
44
44
  }
45
45
  }
@@ -48,12 +48,9 @@ function buildTestIndex(cwd, testDirs) {
48
48
  }
49
49
 
50
50
  function isTested(funcName, testIndex) {
51
- if (!funcName || !testIndex || testIndex.size === 0) return false;
51
+ if (!funcName || funcName.length < 3 || !testIndex || testIndex.size === 0) return false;
52
52
  const lower = funcName.toLowerCase();
53
53
  if (testIndex.has(lower) || testIndex.has(`test_${lower}`)) return true;
54
- for (const token of testIndex) {
55
- if (token.includes(lower)) return true;
56
- }
57
54
  return false;
58
55
  }
59
56
 
@@ -63,7 +63,21 @@ function extract(src) {
63
63
  sigs.push(`${asyncKw}def ${m[2]}(${params})${retStr}${hintStr}`);
64
64
  }
65
65
 
66
- return sigs.slice(0, 25);
66
+ // FastAPI router endpoints: @router.METHOD("path") + async def name(...)
67
+ const lines = noComments.split('\n');
68
+ for (let i = 0; i < lines.length - 1; i++) {
69
+ const decLine = lines[i].trim();
70
+ const rm = decLine.match(/^@\w+\.(get|post|put|patch|delete|head)\s*\(\s*['"]([^'"]+)['"]/);
71
+ if (!rm) continue;
72
+ for (let j = i + 1; j < Math.min(i + 6, lines.length); j++) {
73
+ const fl = lines[j].trim();
74
+ const fm = fl.match(/^(?:async\s+)?def\s+(\w+)/);
75
+ if (fm) { sigs.push(`${rm[1].toUpperCase()} ${rm[2]} → ${fm[1]}()`); break; }
76
+ if (fl && !fl.startsWith('@') && !fl.startsWith('#')) break;
77
+ }
78
+ }
79
+
80
+ return sigs.slice(0, 30);
67
81
  }
68
82
 
69
83
  function extractClassMethods(stripped, startIndex) {
@@ -99,7 +99,25 @@ function extract(src) {
99
99
  }
100
100
  }
101
101
 
102
- return sigs.slice(0, 25);
102
+ // Zustand stores: export const useXxxStore = create<State>()(...)
103
+ for (const m of stripped.matchAll(/^export\s+const\s+(use\w+Store)\s*=\s*create(?:<[^>]*>)?\s*\(/gm)) {
104
+ const stateType = m[0].match(/create<([\w]+)>/)?.[1] || '';
105
+ sigs.push(`export const ${m[1]} = create<${stateType}>(...)`);
106
+ const ifaceRe = new RegExp(`interface\\s+${stateType}\\s*\\{([\\s\\S]*?)\\}`);
107
+ const ifm = stripped.match(ifaceRe);
108
+ if (ifm) {
109
+ for (const fm of ifm[1].matchAll(/^\s+(\w+)\s*(?:\([^)]*\))?\s*:/gm)) sigs.push(` ${fm[1]}`);
110
+ }
111
+ }
112
+
113
+ // API client objects: const xxxApi = { method: async () => {} }
114
+ for (const m of stripped.matchAll(/^(?:export\s+default\s+|const\s+)(\w*[Aa]pi\w*)\s*=\s*\{/gm)) {
115
+ const block = extractBlock(stripped, m.index + m[0].length);
116
+ const methods = [...block.matchAll(/^\s+(\w+)\s*:\s*(?:async\s+)?(?:\([^)]*\)|\w+)\s*=>/gm)].map(mm => mm[1]);
117
+ if (methods.length) sigs.push(`${m[1]}: { ${methods.join(', ')} }`);
118
+ }
119
+
120
+ return sigs.slice(0, 35);
103
121
  }
104
122
 
105
123
  function extractBlock(src, startIndex) {
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: '2.0.0-beta.5',
21
+ version: '2.0.0',
22
22
  description: 'SigMap MCP server — code signatures on demand',
23
23
  };
24
24