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 +24 -76
- package/README.md +24 -6
- package/gen-context.config.json.example +1 -7
- package/gen-context.js +80 -9
- package/package.json +1 -1
- package/src/config/defaults.js +0 -6
- package/src/extractors/coverage.js +3 -6
- package/src/extractors/python.js +15 -1
- package/src/extractors/typescript.js +19 -1
- package/src/mcp/server.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,88 +6,37 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## [2.0.0
|
|
9
|
+
## [2.0.0] — 2026-04-04
|
|
10
10
|
|
|
11
|
-
###
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
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
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
47
|
-
|
|
48
|
-
- TypeScript
|
|
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
|
-
-
|
|
58
|
-
-
|
|
59
|
-
- `node
|
|
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
|
[](https://www.npmjs.com/package/sigmap)
|
|
14
|
-
[](https://github.com/manojmallick/sigmap/tree/main/test)
|
|
15
15
|
[](package.json)
|
|
16
16
|
[](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** | `
|
|
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": "
|
|
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/ ←
|
|
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
|
-
│ └──
|
|
510
|
+
│ └── release.sh ← version bump + npm publish helper
|
|
494
511
|
│
|
|
495
512
|
├── examples/
|
|
496
513
|
│ ├── self-healing-github-action.yml
|
|
497
|
-
│
|
|
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": "
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
package/src/config/defaults.js
CHANGED
|
@@ -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
|
|
package/src/extractors/python.js
CHANGED
|
@@ -63,7 +63,21 @@ function extract(src) {
|
|
|
63
63
|
sigs.push(`${asyncKw}def ${m[2]}(${params})${retStr}${hintStr}`);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
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
|
-
|
|
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