sigmap 3.5.0 → 3.6.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/AGENTS.md +81 -55
- package/README.md +21 -15
- package/gen-context.js +383 -13
- package/package.json +2 -1
- package/packages/adapters/llm-full.js +25 -0
- package/src/extractors/generic.js +26 -0
- package/src/format/llm-txt.js +28 -0
- package/src/format/llms-txt.js +70 -0
package/AGENTS.md
CHANGED
|
@@ -12,46 +12,19 @@ Use this marker block for all appendable context files:
|
|
|
12
12
|
## Auto-generated signatures
|
|
13
13
|
<!-- Updated by gen-context.js -->
|
|
14
14
|
You are a coding assistant with full knowledge of this codebase.
|
|
15
|
-
Below are the code signatures extracted by SigMap v3.
|
|
15
|
+
Below are the code signatures extracted by SigMap v3.5.1 on 2026-04-14T23:05:11.451Z.
|
|
16
16
|
|
|
17
17
|
Use these signatures to answer questions about the code accurately.
|
|
18
18
|
|
|
19
19
|
## Code Signatures
|
|
20
20
|
|
|
21
|
-
<!-- Generated by SigMap gen-context.js v3.
|
|
21
|
+
<!-- Generated by SigMap gen-context.js v3.5.1 -->
|
|
22
22
|
<!-- DO NOT EDIT below the marker line — run gen-context.js to regenerate -->
|
|
23
23
|
|
|
24
24
|
# Code signatures
|
|
25
25
|
|
|
26
|
-
## changes (last 5 commits — 11 minutes ago)
|
|
27
|
-
```
|
|
28
|
-
src/config/loader.js ~detectAutoSrcDirs
|
|
29
|
-
src/eval/analyzer.js ~isDockerfile
|
|
30
|
-
src/extractors/markdown.js +extract
|
|
31
|
-
src/extractors/properties.js +extract
|
|
32
|
-
src/extractors/toml.js +extract
|
|
33
|
-
src/extractors/xml.js +attributes +extract
|
|
34
|
-
```
|
|
35
|
-
|
|
36
26
|
## packages
|
|
37
27
|
|
|
38
|
-
### packages/adapters/codex.js
|
|
39
|
-
```
|
|
40
|
-
module.exports = { name, format, outputPath, write }
|
|
41
|
-
function format(context, opts = {}) → string
|
|
42
|
-
function outputPath(cwd) → string
|
|
43
|
-
function write(context, cwd, opts = {})
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### packages/adapters/index.js
|
|
47
|
-
```
|
|
48
|
-
module.exports = { getAdapter, listAdapters, adapt, outputsToAdapters }
|
|
49
|
-
function getAdapter(name) → { name: string, format: F
|
|
50
|
-
function listAdapters() → string[]
|
|
51
|
-
function adapt(context, adapterName, opts = {}) → string
|
|
52
|
-
function outputsToAdapters(outputs) → string[]
|
|
53
|
-
```
|
|
54
|
-
|
|
55
28
|
### packages/core/index.js
|
|
56
29
|
```
|
|
57
30
|
module.exports = { extract, rank, buildSigIndex, scan, score, adapt }
|
|
@@ -72,6 +45,14 @@ function outputPath(cwd) → string
|
|
|
72
45
|
function write(context, cwd, opts = {})
|
|
73
46
|
```
|
|
74
47
|
|
|
48
|
+
### packages/adapters/codex.js
|
|
49
|
+
```
|
|
50
|
+
module.exports = { name, format, outputPath, write }
|
|
51
|
+
function format(context, opts = {}) → string
|
|
52
|
+
function outputPath(cwd) → string
|
|
53
|
+
function write(context, cwd, opts = {})
|
|
54
|
+
```
|
|
55
|
+
|
|
75
56
|
### packages/adapters/copilot.js
|
|
76
57
|
```
|
|
77
58
|
module.exports = { name, format, outputPath, write }
|
|
@@ -95,6 +76,23 @@ function outputPath(cwd) → string
|
|
|
95
76
|
function write(context, cwd, opts = {})
|
|
96
77
|
```
|
|
97
78
|
|
|
79
|
+
### packages/adapters/index.js
|
|
80
|
+
```
|
|
81
|
+
module.exports = { getAdapter, listAdapters, adapt, outputsToAdapters }
|
|
82
|
+
function getAdapter(name) → { name: string, format: F
|
|
83
|
+
function listAdapters() → string[]
|
|
84
|
+
function adapt(context, adapterName, opts = {}) → string
|
|
85
|
+
function outputsToAdapters(outputs) → string[]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### packages/adapters/llm-full.js
|
|
89
|
+
```
|
|
90
|
+
module.exports = { name: 'llm-full', format, outputPath, write }
|
|
91
|
+
function outputPath(cwd)
|
|
92
|
+
function format(context, opts)
|
|
93
|
+
function write(context, cwd, opts)
|
|
94
|
+
```
|
|
95
|
+
|
|
98
96
|
### packages/adapters/openai.js
|
|
99
97
|
```
|
|
100
98
|
module.exports = { name, format, outputPath }
|
|
@@ -163,13 +161,13 @@ function formatAnalysisTable(stats, showSlow) → string
|
|
|
163
161
|
function formatAnalysisJSON(stats) → object
|
|
164
162
|
```
|
|
165
163
|
|
|
166
|
-
### src/extractors/
|
|
164
|
+
### src/extractors/markdown.js
|
|
167
165
|
```
|
|
168
166
|
module.exports = { extract }
|
|
169
167
|
function extract(src) → string[]
|
|
170
168
|
```
|
|
171
169
|
|
|
172
|
-
### src/extractors/
|
|
170
|
+
### src/extractors/patterns.js
|
|
173
171
|
```
|
|
174
172
|
module.exports = { extract }
|
|
175
173
|
function extract(src) → string[]
|
|
@@ -181,27 +179,25 @@ module.exports = { extract }
|
|
|
181
179
|
function extract(src) → string[]
|
|
182
180
|
```
|
|
183
181
|
|
|
184
|
-
### src/extractors/
|
|
182
|
+
### src/extractors/python_dataclass.js
|
|
185
183
|
```
|
|
186
184
|
module.exports = { extract }
|
|
187
185
|
function extract(src) → string[]
|
|
188
186
|
```
|
|
189
187
|
|
|
190
|
-
### src/extractors/
|
|
188
|
+
### src/extractors/toml.js
|
|
191
189
|
```
|
|
192
190
|
module.exports = { extract }
|
|
193
191
|
function extract(src) → string[]
|
|
194
|
-
function _cleanName(raw)
|
|
195
|
-
function _normalizeParams(raw)
|
|
196
192
|
```
|
|
197
193
|
|
|
198
|
-
### src/extractors/
|
|
194
|
+
### src/extractors/typescript_react.js
|
|
199
195
|
```
|
|
200
196
|
module.exports = { extract }
|
|
201
197
|
function extract(src) → string[]
|
|
202
198
|
```
|
|
203
199
|
|
|
204
|
-
### src/extractors/
|
|
200
|
+
### src/extractors/vue_sfc.js
|
|
205
201
|
```
|
|
206
202
|
module.exports = { extract }
|
|
207
203
|
function extract(src) → string[]
|
|
@@ -305,6 +301,12 @@ module.exports = { extract }
|
|
|
305
301
|
function extract(src) → string[]
|
|
306
302
|
```
|
|
307
303
|
|
|
304
|
+
### src/extractors/generic.js
|
|
305
|
+
```
|
|
306
|
+
module.exports = { extract }
|
|
307
|
+
function extract(src)
|
|
308
|
+
```
|
|
309
|
+
|
|
308
310
|
### src/extractors/go.js
|
|
309
311
|
```
|
|
310
312
|
module.exports = { extract }
|
|
@@ -314,6 +316,12 @@ function extractInterfaceMethods(block)
|
|
|
314
316
|
function normalizeParams(params)
|
|
315
317
|
```
|
|
316
318
|
|
|
319
|
+
### src/extractors/graphql.js
|
|
320
|
+
```
|
|
321
|
+
module.exports = { extract }
|
|
322
|
+
function extract(src) → string[]
|
|
323
|
+
```
|
|
324
|
+
|
|
317
325
|
### src/extractors/html.js
|
|
318
326
|
```
|
|
319
327
|
module.exports = { extract }
|
|
@@ -368,6 +376,12 @@ function diffSignatures(baseSigs, currentSigs) → {added:string[], removed:
|
|
|
368
376
|
function extractName(sig)
|
|
369
377
|
```
|
|
370
378
|
|
|
379
|
+
### src/extractors/protobuf.js
|
|
380
|
+
```
|
|
381
|
+
module.exports = { extract }
|
|
382
|
+
function extract(src) → string[]
|
|
383
|
+
```
|
|
384
|
+
|
|
371
385
|
### src/extractors/python.js
|
|
372
386
|
```
|
|
373
387
|
module.exports = { extract }
|
|
@@ -381,12 +395,6 @@ function normalizeParams(params)
|
|
|
381
395
|
function extractDocHint(src, fnName, fnSigLine)
|
|
382
396
|
```
|
|
383
397
|
|
|
384
|
-
### src/extractors/python_dataclass.js
|
|
385
|
-
```
|
|
386
|
-
module.exports = { extract }
|
|
387
|
-
function extract(src) → string[]
|
|
388
|
-
```
|
|
389
|
-
|
|
390
398
|
### src/extractors/ruby.js
|
|
391
399
|
```
|
|
392
400
|
module.exports = { extract }
|
|
@@ -421,6 +429,14 @@ module.exports = { extract }
|
|
|
421
429
|
function extract(src) → string[]
|
|
422
430
|
```
|
|
423
431
|
|
|
432
|
+
### src/extractors/sql.js
|
|
433
|
+
```
|
|
434
|
+
module.exports = { extract }
|
|
435
|
+
function extract(src) → string[]
|
|
436
|
+
function _cleanName(raw)
|
|
437
|
+
function _normalizeParams(raw)
|
|
438
|
+
```
|
|
439
|
+
|
|
424
440
|
### src/extractors/svelte.js
|
|
425
441
|
```
|
|
426
442
|
module.exports = { extract }
|
|
@@ -439,6 +455,12 @@ function normalizeParams(params)
|
|
|
439
455
|
function extractArrowType(str)
|
|
440
456
|
```
|
|
441
457
|
|
|
458
|
+
### src/extractors/terraform.js
|
|
459
|
+
```
|
|
460
|
+
module.exports = { extract }
|
|
461
|
+
function extract(src) → string[]
|
|
462
|
+
```
|
|
463
|
+
|
|
442
464
|
### src/extractors/todos.js
|
|
443
465
|
```
|
|
444
466
|
module.exports = { extractTodos }
|
|
@@ -455,12 +477,6 @@ function extractClassMembers(block)
|
|
|
455
477
|
function normalizeParams(params)
|
|
456
478
|
```
|
|
457
479
|
|
|
458
|
-
### src/extractors/typescript_react.js
|
|
459
|
-
```
|
|
460
|
-
module.exports = { extract }
|
|
461
|
-
function extract(src) → string[]
|
|
462
|
-
```
|
|
463
|
-
|
|
464
480
|
### src/extractors/vue.js
|
|
465
481
|
```
|
|
466
482
|
module.exports = { extract }
|
|
@@ -469,12 +485,6 @@ function normalizeParams(params)
|
|
|
469
485
|
function normalizeType(type)
|
|
470
486
|
```
|
|
471
487
|
|
|
472
|
-
### src/extractors/vue_sfc.js
|
|
473
|
-
```
|
|
474
|
-
module.exports = { extract }
|
|
475
|
-
function extract(src) → string[]
|
|
476
|
-
```
|
|
477
|
-
|
|
478
488
|
### src/extractors/yaml.js
|
|
479
489
|
```
|
|
480
490
|
module.exports = { extract }
|
|
@@ -508,6 +518,22 @@ function generateDashboardHtml(cwd, health)
|
|
|
508
518
|
function renderHistoryCharts(cwd, health)
|
|
509
519
|
```
|
|
510
520
|
|
|
521
|
+
### src/format/llm-txt.js
|
|
522
|
+
```
|
|
523
|
+
module.exports = { format, outputPath }
|
|
524
|
+
function outputPath(cwd)
|
|
525
|
+
function format(context, cwd, version)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### src/format/llms-txt.js
|
|
529
|
+
```
|
|
530
|
+
module.exports = { format, outputPath }
|
|
531
|
+
function outputPath(cwd)
|
|
532
|
+
function getShortCommit(cwd)
|
|
533
|
+
function detectVersion(cwd)
|
|
534
|
+
function format(context, cwd, writtenFiles, sigmapVersion)
|
|
535
|
+
```
|
|
536
|
+
|
|
511
537
|
### src/graph/builder.js
|
|
512
538
|
```
|
|
513
539
|
module.exports = { build, buildFromCwd, extractFileDeps }
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="
|
|
3
|
+
<img src="assets/logo.png" alt="SigMap logo" width="80" height="80" />
|
|
4
4
|
|
|
5
5
|
<h1>⚡ SigMap</h1>
|
|
6
6
|
|
|
@@ -50,15 +50,15 @@ npx sigmap # 10 seconds. zero config. your AI never reads the wrong file again
|
|
|
50
50
|
|
|
51
51
|
<div align="center">
|
|
52
52
|
<img src="docs/comparison-chart.svg" alt="SigMap benchmark — before vs after across 3 RAG quality metrics" width="700" />
|
|
53
|
-
<br/><sub><a href="https://manojmallick.github.io/sigmap/guide/task-benchmark.html">
|
|
53
|
+
<br/><sub><a href="https://manojmallick.github.io/sigmap/guide/task-benchmark.html">90 tasks · 18 real repos · no LLM API · <strong>full methodology →</strong></a></sub>
|
|
54
54
|
</div>
|
|
55
55
|
|
|
56
56
|
| | Without SigMap | With SigMap |
|
|
57
57
|
|---|:---:|:---:|
|
|
58
58
|
| Task success | 10% | **59%** |
|
|
59
|
-
| Prompts per task | 2.84 | **1.
|
|
59
|
+
| Prompts per task | 2.84 | **1.78** |
|
|
60
60
|
| Tokens per session | ~80,000 | **~2,000** |
|
|
61
|
-
| Right file found | 13.
|
|
61
|
+
| Right file found | 13.6% | **84.4%** |
|
|
62
62
|
| Hallucination risk | 92% | **0%** |
|
|
63
63
|
|
|
64
64
|
</details>
|
|
@@ -126,24 +126,26 @@ Reproduced with `node scripts/run-benchmark.mjs` on public repos:
|
|
|
126
126
|
|
|
127
127
|
| Repo | Language | Raw tokens | After SigMap | Reduction |
|
|
128
128
|
|------|----------|------------|--------------|-----------|
|
|
129
|
-
| express | JavaScript |
|
|
130
|
-
| flask | Python |
|
|
131
|
-
| gin | Go |
|
|
132
|
-
| spring-petclinic | Java |
|
|
129
|
+
| express | JavaScript | 70.6K | 911 | **98.7%** |
|
|
130
|
+
| flask | Python | 147.9K | 6.7K | **95.4%** |
|
|
131
|
+
| gin | Go | 216.4K | 6.0K | **97.2%** |
|
|
132
|
+
| spring-petclinic | Java | 97.9K | 3.4K | **96.5%** |
|
|
133
133
|
| rails | Ruby | 1.5M | 7.1K | **99.5%** |
|
|
134
|
-
| axios | TypeScript |
|
|
135
|
-
| rust-analyzer | Rust | 3.5M |
|
|
134
|
+
| axios | TypeScript | 105.7K | 6.1K | **94.3%** |
|
|
135
|
+
| rust-analyzer | Rust | 3.5M | 6.3K | **99.8%** |
|
|
136
136
|
| abseil-cpp | C++ | 2.3M | 6.3K | **99.7%** |
|
|
137
|
-
| serilog | C# |
|
|
138
|
-
| riverpod | Dart |
|
|
137
|
+
| serilog | C# | 195.5K | 6.9K | **96.4%** |
|
|
138
|
+
| riverpod | Dart | 747.2K | 6.5K | **99.1%** |
|
|
139
139
|
| okhttp | Kotlin | 31.3K | 1.4K | **95.5%** |
|
|
140
140
|
| laravel | PHP | 1.7M | 7.2K | **99.6%** |
|
|
141
141
|
| akka | Scala | 790.5K | 7.1K | **99.1%** |
|
|
142
|
-
| vapor | Swift | 171.
|
|
143
|
-
| vue-core | Vue |
|
|
142
|
+
| vapor | Swift | 171.4K | 6.4K | **96.2%** |
|
|
143
|
+
| vue-core | Vue | 414.4K | 8.6K | **97.9%** |
|
|
144
144
|
| svelte | Svelte | 438.2K | 8.0K | **98.2%** |
|
|
145
|
+
| fastify | JavaScript | 54.4K | 2.6K | **95.3%** |
|
|
146
|
+
| fastapi | Python | 178.4K | 5.2K | **97.1%** |
|
|
145
147
|
|
|
146
|
-
**Average:
|
|
148
|
+
**Average: 97.5% reduction across 18 repos (16 languages).** See [`benchmarks/reports/token-reduction.md`](benchmarks/reports/token-reduction.md) or reproduce with `node scripts/run-benchmark.mjs`.
|
|
147
149
|
|
|
148
150
|
---
|
|
149
151
|
|
|
@@ -454,6 +456,10 @@ Activates on startup (`onStartupFinished`) — loads within 3 s, never blocks ed
|
|
|
454
456
|
|
|
455
457
|
The official SigMap JetBrains plugin brings the same features to IntelliJ-based IDEs. Install it from the JetBrains Marketplace and it works identically to the VS Code extension.
|
|
456
458
|
|
|
459
|
+
<div align="center">
|
|
460
|
+
<img src="assets/intelij.gif" alt="SigMap JetBrains plugin — status bar health grade, regenerate action, and context auto-refresh in IntelliJ IDEA" width="700" />
|
|
461
|
+
</div>
|
|
462
|
+
|
|
457
463
|
| Feature | Detail |
|
|
458
464
|
|---|---|
|
|
459
465
|
| **Status bar widget** | Shows health grade (`A`-`F`) + time since last regen; updates every 60 s |
|
package/gen-context.js
CHANGED
|
@@ -5881,6 +5881,153 @@ __factories["./packages/adapters/index"] = function(module, exports) {
|
|
|
5881
5881
|
module.exports = { getAdapter, listAdapters, adapt, outputsToAdapters };
|
|
5882
5882
|
};
|
|
5883
5883
|
|
|
5884
|
+
// ── ./src/extractors/generic ──
|
|
5885
|
+
__factories["./src/extractors/generic"] = function(module, exports) {
|
|
5886
|
+
'use strict';
|
|
5887
|
+
const PATTERNS = [
|
|
5888
|
+
/^(?:pub\s+)?(?:async\s+)?function\s+\w+\s*\(/,
|
|
5889
|
+
/^(?:pub\s+)?(?:async\s+)?fn\s+\w+[\s(<]/,
|
|
5890
|
+
/^def\s+\w+[\s(|:]/,
|
|
5891
|
+
/^(?:pub\s+)?func\s+\w+\s*\(/,
|
|
5892
|
+
/^(?:let|let\s+rec)\s+\w+\s*[=(]/,
|
|
5893
|
+
/^class\s+\w+/,
|
|
5894
|
+
/^(?:proc|sub|method)\s+\w+\s*\(/,
|
|
5895
|
+
];
|
|
5896
|
+
function extract(src) {
|
|
5897
|
+
if (!src || typeof src !== 'string') return [];
|
|
5898
|
+
const results = [];
|
|
5899
|
+
for (const raw of src.split('\n')) {
|
|
5900
|
+
const line = raw.trim();
|
|
5901
|
+
if (!line || /^[#\-]/.test(line) || /^\/\//.test(line) || line.includes('\0')) continue;
|
|
5902
|
+
for (const pat of PATTERNS) {
|
|
5903
|
+
if (pat.test(line)) { results.push(line.slice(0, 120)); break; }
|
|
5904
|
+
}
|
|
5905
|
+
if (results.length >= 15) break;
|
|
5906
|
+
}
|
|
5907
|
+
return results;
|
|
5908
|
+
}
|
|
5909
|
+
module.exports = { extract };
|
|
5910
|
+
};
|
|
5911
|
+
|
|
5912
|
+
// ── ./src/format/llm-txt ──
|
|
5913
|
+
__factories["./src/format/llm-txt"] = function(module, exports) {
|
|
5914
|
+
'use strict';
|
|
5915
|
+
const path = require('path');
|
|
5916
|
+
function outputPath(cwd) { return path.join(cwd, 'llm.txt'); }
|
|
5917
|
+
function format(context, cwd, version) {
|
|
5918
|
+
const name = context.projectName || path.basename(cwd);
|
|
5919
|
+
const langs = [...new Set((context.fileEntries || []).map(f => f.language).filter(Boolean))];
|
|
5920
|
+
const mods = context.srcDirs || [];
|
|
5921
|
+
return [
|
|
5922
|
+
`# Project: ${name}`,
|
|
5923
|
+
`Languages: ${langs.join(', ') || 'unknown'}`,
|
|
5924
|
+
`Root: ${mods[0] || 'src/'}`,
|
|
5925
|
+
'',
|
|
5926
|
+
'## Modules',
|
|
5927
|
+
...mods.map(m => `- ${m}/`),
|
|
5928
|
+
'',
|
|
5929
|
+
'## Key flows',
|
|
5930
|
+
'- <!-- describe your main user flows here -->',
|
|
5931
|
+
'',
|
|
5932
|
+
'## Rules',
|
|
5933
|
+
'- <!-- describe your team conventions here -->',
|
|
5934
|
+
'',
|
|
5935
|
+
`Generated: ${new Date().toISOString()} | SigMap v${version}`,
|
|
5936
|
+
].join('\n');
|
|
5937
|
+
}
|
|
5938
|
+
module.exports = { format, outputPath };
|
|
5939
|
+
};
|
|
5940
|
+
|
|
5941
|
+
// ── ./src/format/llms-txt ──
|
|
5942
|
+
__factories["./src/format/llms-txt"] = function(module, exports) {
|
|
5943
|
+
'use strict';
|
|
5944
|
+
const path = require('path');
|
|
5945
|
+
const fs = require('fs');
|
|
5946
|
+
const { execSync } = require('child_process');
|
|
5947
|
+
function outputPath(cwd) { return path.join(cwd, 'llms.txt'); }
|
|
5948
|
+
function getShortCommit(cwd) {
|
|
5949
|
+
try { return execSync('git rev-parse --short HEAD', { cwd, timeout: 2000 }).toString().trim(); }
|
|
5950
|
+
catch (_) { return ''; }
|
|
5951
|
+
}
|
|
5952
|
+
function detectVersion(cwd) {
|
|
5953
|
+
try {
|
|
5954
|
+
const pkg = path.join(cwd, 'package.json');
|
|
5955
|
+
if (fs.existsSync(pkg)) return JSON.parse(fs.readFileSync(pkg, 'utf8')).version || '';
|
|
5956
|
+
} catch (_) {}
|
|
5957
|
+
return '';
|
|
5958
|
+
}
|
|
5959
|
+
function format(context, cwd, writtenFiles, sigmapVersion) {
|
|
5960
|
+
writtenFiles = writtenFiles || [];
|
|
5961
|
+
sigmapVersion = sigmapVersion || '';
|
|
5962
|
+
const name = context.projectName || path.basename(cwd);
|
|
5963
|
+
const ver = detectVersion(cwd);
|
|
5964
|
+
const commit = getShortCommit(cwd);
|
|
5965
|
+
const langs = [...new Set((context.fileEntries || []).map(f => f.language).filter(Boolean))];
|
|
5966
|
+
const lines = [
|
|
5967
|
+
'# SigMap Context Index',
|
|
5968
|
+
`> Generated by SigMap v${sigmapVersion} — zero-dependency AI context engine`,
|
|
5969
|
+
'',
|
|
5970
|
+
'## Project',
|
|
5971
|
+
`- Name: ${name}`,
|
|
5972
|
+
];
|
|
5973
|
+
if (ver) lines.push(`- Version: ${ver}`);
|
|
5974
|
+
if (langs.length) lines.push(`- Language: ${langs.join(', ')}`);
|
|
5975
|
+
if (commit) lines.push(`- Commit: ${commit}`);
|
|
5976
|
+
if (writtenFiles.length) {
|
|
5977
|
+
lines.push('', '## Context Files');
|
|
5978
|
+
for (const f of writtenFiles) {
|
|
5979
|
+
const rel = path.relative(cwd, f.path);
|
|
5980
|
+
const extra = f.tokens ? `: ${f.tokens} tokens` : '';
|
|
5981
|
+
lines.push(`- [${f.label || rel}](${rel})${extra}`);
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
5984
|
+
const mods = context.srcDirs || [];
|
|
5985
|
+
if (mods.length) {
|
|
5986
|
+
lines.push('', '## Source Modules');
|
|
5987
|
+
for (const m of mods) lines.push(`- [${m}/](${m}/)`);
|
|
5988
|
+
}
|
|
5989
|
+
const top5 = (context.fileEntries || [])
|
|
5990
|
+
.sort((a, b) => (b.sigs || []).length - (a.sigs || []).length)
|
|
5991
|
+
.slice(0, 5);
|
|
5992
|
+
if (top5.length) {
|
|
5993
|
+
lines.push('', '## Key Files');
|
|
5994
|
+
for (const f of top5) {
|
|
5995
|
+
const rel = path.relative(cwd, f.filePath);
|
|
5996
|
+
const preview = (f.sigs || []).slice(0, 3).join(', ');
|
|
5997
|
+
lines.push(`- ${rel}: ${preview}`);
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
6000
|
+
return lines.join('\n');
|
|
6001
|
+
}
|
|
6002
|
+
module.exports = { format, outputPath };
|
|
6003
|
+
};
|
|
6004
|
+
|
|
6005
|
+
// ── ./packages/adapters/llm-full ──
|
|
6006
|
+
__factories["./packages/adapters/llm-full"] = function(module, exports) {
|
|
6007
|
+
'use strict';
|
|
6008
|
+
const path = require('path');
|
|
6009
|
+
const fs = require('fs');
|
|
6010
|
+
function outputPath(cwd) { return path.join(cwd, 'llm-full.txt'); }
|
|
6011
|
+
function format(context, opts) {
|
|
6012
|
+
opts = opts || {};
|
|
6013
|
+
const lines = [
|
|
6014
|
+
`# ${context.projectName || 'Project'} — SigMap Context`,
|
|
6015
|
+
`Generated: ${new Date().toISOString()} | SigMap v${opts.version || ''}`,
|
|
6016
|
+
'',
|
|
6017
|
+
];
|
|
6018
|
+
for (const entry of (context.fileEntries || [])) {
|
|
6019
|
+
const rel = path.relative(opts.cwd || '', entry.filePath);
|
|
6020
|
+
lines.push(`## ${rel}`, '```', ...(entry.sigs || []), '```', '');
|
|
6021
|
+
}
|
|
6022
|
+
return lines.join('\n');
|
|
6023
|
+
}
|
|
6024
|
+
function write(context, cwd, opts) {
|
|
6025
|
+
opts = opts || {};
|
|
6026
|
+
fs.writeFileSync(outputPath(cwd), format(context, { ...opts, cwd }));
|
|
6027
|
+
}
|
|
6028
|
+
module.exports = { name: 'llm-full', format, outputPath, write };
|
|
6029
|
+
};
|
|
6030
|
+
|
|
5884
6031
|
/**
|
|
5885
6032
|
* SigMap — gen-context.js v1.2.0
|
|
5886
6033
|
* Zero-dependency AI context engine.
|
|
@@ -5893,7 +6040,7 @@ const path = require('path');
|
|
|
5893
6040
|
const os = require('os');
|
|
5894
6041
|
const { execSync } = require('child_process');
|
|
5895
6042
|
|
|
5896
|
-
const VERSION = '3.
|
|
6043
|
+
const VERSION = '3.6.0';
|
|
5897
6044
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
5898
6045
|
|
|
5899
6046
|
function requireSourceOrBundled(key) {
|
|
@@ -6042,7 +6189,8 @@ function detectAndExtract(filePath, content, maxSigsPerFile) {
|
|
|
6042
6189
|
const ext = path.extname(base).toLowerCase();
|
|
6043
6190
|
let extractorName = EXT_MAP[ext] || null;
|
|
6044
6191
|
if (!extractorName && isDockerfile(base)) extractorName = 'dockerfile';
|
|
6045
|
-
|
|
6192
|
+
// Feature 7: generic fallback — catches Nix, Elixir, Gleam, Zig, Go templates, etc.
|
|
6193
|
+
if (!extractorName) extractorName = 'generic';
|
|
6046
6194
|
|
|
6047
6195
|
const extractor = getExtractor(extractorName);
|
|
6048
6196
|
if (!extractor) return [];
|
|
@@ -6122,12 +6270,13 @@ function applyTokenBudget(fileEntries, maxTokens) {
|
|
|
6122
6270
|
// Sort by drop priority (drop first = index 0)
|
|
6123
6271
|
const withPriority = fileEntries.map((e) => {
|
|
6124
6272
|
let priority = 0;
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
else if (
|
|
6128
|
-
else if (
|
|
6273
|
+
let dropReason = 'budget: low recency';
|
|
6274
|
+
if (isGeneratedFile(e.filePath)) { priority = 10; dropReason = 'budget: generated file'; }
|
|
6275
|
+
else if (isMockFile(e.filePath)) { priority = 9; dropReason = 'budget: mock file'; }
|
|
6276
|
+
else if (isTestFile(e.filePath)) { priority = 8; dropReason = 'budget: test file'; }
|
|
6277
|
+
else if (isConfigFile(e.filePath)) { priority = 6; dropReason = 'budget: config file'; }
|
|
6129
6278
|
else priority = 4;
|
|
6130
|
-
return { ...e, priority };
|
|
6279
|
+
return { ...e, priority, dropReason };
|
|
6131
6280
|
});
|
|
6132
6281
|
|
|
6133
6282
|
// Within same priority, sort by mtime ascending (oldest first = drop first)
|
|
@@ -6137,20 +6286,27 @@ function applyTokenBudget(fileEntries, maxTokens) {
|
|
|
6137
6286
|
});
|
|
6138
6287
|
|
|
6139
6288
|
const kept = [];
|
|
6140
|
-
|
|
6289
|
+
const verboseDropped = [];
|
|
6141
6290
|
// Iterate forward: highest drop-priority files (generated=10, mock=9, test=8) are at index 0
|
|
6142
6291
|
// Drop those first until we're under budget, then keep everything else
|
|
6143
6292
|
for (const entry of withPriority) {
|
|
6144
6293
|
const entryTokens = estimateTokens(entry.sigs.join('\n'));
|
|
6145
6294
|
if (total > effectiveBudget) {
|
|
6146
6295
|
total -= entryTokens;
|
|
6147
|
-
|
|
6296
|
+
verboseDropped.push({ filePath: entry.filePath, reason: entry.dropReason });
|
|
6148
6297
|
} else {
|
|
6149
6298
|
kept.push(entry);
|
|
6150
6299
|
}
|
|
6151
6300
|
}
|
|
6152
|
-
if (
|
|
6153
|
-
console.warn(`[sigmap] budget: dropped ${
|
|
6301
|
+
if (verboseDropped.length > 0) {
|
|
6302
|
+
console.warn(`[sigmap] budget: dropped ${verboseDropped.length} files to stay under ${maxTokens} tokens`);
|
|
6303
|
+
// Feature 7: --verbose — print per-file drop reason
|
|
6304
|
+
if (process.argv.includes('--verbose')) {
|
|
6305
|
+
for (const { filePath, reason } of verboseDropped) {
|
|
6306
|
+
console.warn(`[sigmap] dropped: ${path.relative(process.cwd(), filePath)} — ${reason}`);
|
|
6307
|
+
}
|
|
6308
|
+
console.warn(`[sigmap] included: ${kept.length} files, dropped: ${verboseDropped.length}`);
|
|
6309
|
+
}
|
|
6154
6310
|
}
|
|
6155
6311
|
return kept;
|
|
6156
6312
|
}
|
|
@@ -6980,7 +7136,37 @@ function runGenerate(cwd, config, reportMode, reportJson = false) {
|
|
|
6980
7136
|
const finalTokens = estimateTokens(content);
|
|
6981
7137
|
const formatIdx = process.argv.indexOf('--format');
|
|
6982
7138
|
const formatValue = formatIdx >= 0 ? process.argv[formatIdx + 1] : (config.format || 'default');
|
|
6983
|
-
|
|
7139
|
+
// Feature 2: --mode write matrix
|
|
7140
|
+
const activeMode = process.argv.indexOf('--mode') >= 0
|
|
7141
|
+
? process.argv[process.argv.indexOf('--mode') + 1]
|
|
7142
|
+
: (config.mode || 'default');
|
|
7143
|
+
if (activeMode === 'fast') {
|
|
7144
|
+
const llmTxtMod = requireSourceOrBundled('./src/format/llm-txt');
|
|
7145
|
+
const syncContext = { projectName: path.basename(cwd), fileEntries, srcDirs: config.srcDirs || [] };
|
|
7146
|
+
fs.writeFileSync(llmTxtMod.outputPath(cwd), llmTxtMod.format(syncContext, cwd, VERSION));
|
|
7147
|
+
console.warn(`[sigmap] --mode fast → llm.txt`);
|
|
7148
|
+
} else if (activeMode === 'full') {
|
|
7149
|
+
const llmFullMod = requireSourceOrBundled('./packages/adapters/llm-full');
|
|
7150
|
+
const syncContext = { projectName: path.basename(cwd), fileEntries, srcDirs: config.srcDirs || [] };
|
|
7151
|
+
llmFullMod.write(syncContext, cwd, { version: VERSION });
|
|
7152
|
+
console.warn(`[sigmap] --mode full → llm-full.txt`);
|
|
7153
|
+
} else if (activeMode === 'both') {
|
|
7154
|
+
const llmTxtMod = requireSourceOrBundled('./src/format/llm-txt');
|
|
7155
|
+
const llmFullMod = requireSourceOrBundled('./packages/adapters/llm-full');
|
|
7156
|
+
const llmsMod = requireSourceOrBundled('./src/format/llms-txt');
|
|
7157
|
+
const syncContext = { projectName: path.basename(cwd), fileEntries, srcDirs: config.srcDirs || [] };
|
|
7158
|
+
fs.writeFileSync(llmTxtMod.outputPath(cwd), llmTxtMod.format(syncContext, cwd, VERSION));
|
|
7159
|
+
llmFullMod.write(syncContext, cwd, { version: VERSION });
|
|
7160
|
+
writeOutputs(content, config.outputs, cwd, config);
|
|
7161
|
+
const llmsContent = llmsMod.format(syncContext, cwd, [
|
|
7162
|
+
{ path: llmTxtMod.outputPath(cwd), label: 'llm.txt' },
|
|
7163
|
+
{ path: llmFullMod.outputPath(cwd), label: 'llm-full.txt' },
|
|
7164
|
+
], VERSION);
|
|
7165
|
+
fs.writeFileSync(llmsMod.outputPath(cwd), llmsContent);
|
|
7166
|
+
console.warn(`[sigmap] --mode both → copilot-instructions.md + llm.txt + llm-full.txt + llms.txt`);
|
|
7167
|
+
} else {
|
|
7168
|
+
writeOutputs(content, config.outputs, cwd, config);
|
|
7169
|
+
}
|
|
6984
7170
|
if (formatValue === 'cache') writeCacheOutput(content, cwd);
|
|
6985
7171
|
result = { inputTokenTotal, finalTokens, fileCount: beforeCount, droppedCount };
|
|
6986
7172
|
}
|
|
@@ -7016,6 +7202,29 @@ function runGenerate(cwd, config, reportMode, reportJson = false) {
|
|
|
7016
7202
|
}
|
|
7017
7203
|
}
|
|
7018
7204
|
|
|
7205
|
+
// Feature 8: post-run summary — 6-line stdout after every normal run
|
|
7206
|
+
if (!reportMode
|
|
7207
|
+
&& !process.argv.includes('--json')
|
|
7208
|
+
&& !process.argv.includes('--report')
|
|
7209
|
+
&& !process.argv.includes('--quiet')) {
|
|
7210
|
+
const bar = '\u2500'.repeat(43);
|
|
7211
|
+
const syms = fileEntries.reduce((n, f) => n + (f.sigs ? f.sigs.length : 0), 0);
|
|
7212
|
+
const pct = result.inputTokenTotal > 0
|
|
7213
|
+
? Math.round((1 - result.finalTokens / result.inputTokenTotal) * 100)
|
|
7214
|
+
: 0;
|
|
7215
|
+
process.stderr.write([
|
|
7216
|
+
bar,
|
|
7217
|
+
` SigMap v${VERSION}`,
|
|
7218
|
+
` Files scanned : ${result.fileCount}`,
|
|
7219
|
+
` Symbols found : ${syms.toLocaleString()}`,
|
|
7220
|
+
` Token reduction: ${pct}% (${result.inputTokenTotal.toLocaleString()} \u2192 ${result.finalTokens.toLocaleString()})`,
|
|
7221
|
+
` Output : .github/copilot-instructions.md`,
|
|
7222
|
+
bar,
|
|
7223
|
+
` Try: "explain the architecture" \u00b7 "find the auth module"`,
|
|
7224
|
+
bar, '',
|
|
7225
|
+
].join('\n'));
|
|
7226
|
+
}
|
|
7227
|
+
|
|
7019
7228
|
return result;
|
|
7020
7229
|
}
|
|
7021
7230
|
|
|
@@ -7327,6 +7536,12 @@ function registerMcp(cwd, scriptPath) {
|
|
|
7327
7536
|
|
|
7328
7537
|
function main() {
|
|
7329
7538
|
const args = process.argv.slice(2);
|
|
7539
|
+
|
|
7540
|
+
// Feature 1: `sigmap run` alias — strip positional 'run' so existing logic handles it
|
|
7541
|
+
if (args[0] === 'run' && !args[0].startsWith('--')) {
|
|
7542
|
+
args.shift();
|
|
7543
|
+
}
|
|
7544
|
+
|
|
7330
7545
|
const invokedFrom = process.cwd();
|
|
7331
7546
|
const cwd = resolveProjectRoot(invokedFrom);
|
|
7332
7547
|
const scriptPath = process.argv[1] || path.join(invokedFrom, 'gen-context.js');
|
|
@@ -7354,6 +7569,154 @@ function main() {
|
|
|
7354
7569
|
|
|
7355
7570
|
const config = loadConfig(cwd);
|
|
7356
7571
|
|
|
7572
|
+
// Feature 2: `--mode fast|full|both`
|
|
7573
|
+
const modeIdx = args.indexOf('--mode');
|
|
7574
|
+
const mode = modeIdx !== -1
|
|
7575
|
+
? args[modeIdx + 1]
|
|
7576
|
+
: (config.mode || 'default');
|
|
7577
|
+
const VALID_MODES = ['default', 'fast', 'full', 'both'];
|
|
7578
|
+
if (mode && !VALID_MODES.includes(mode)) {
|
|
7579
|
+
console.error(`[sigmap] unknown --mode "${mode}". Valid: ${VALID_MODES.join(', ')}`);
|
|
7580
|
+
process.exit(1);
|
|
7581
|
+
}
|
|
7582
|
+
|
|
7583
|
+
// Feature 6: `sigmap sync` — write all outputs + llms.txt + print compact diff
|
|
7584
|
+
if (args[0] === 'sync') {
|
|
7585
|
+
try {
|
|
7586
|
+
// Generate copilot-instructions.md first (existing output)
|
|
7587
|
+
runGenerate(cwd, config, false);
|
|
7588
|
+
const llmTxt = requireSourceOrBundled('./src/format/llm-txt');
|
|
7589
|
+
const llmsGen = requireSourceOrBundled('./src/format/llms-txt');
|
|
7590
|
+
const llmFullMod = requireSourceOrBundled('./packages/adapters/llm-full');
|
|
7591
|
+
|
|
7592
|
+
// Gather file entries for llm.txt / llm-full.txt
|
|
7593
|
+
const ignorePatterns = loadIgnorePatterns(cwd);
|
|
7594
|
+
let syncFiles = buildFileList(cwd, config).filter((f) => {
|
|
7595
|
+
const rel = path.relative(cwd, f).replace(/\\/g, '/');
|
|
7596
|
+
return !matchesIgnore(rel, ignorePatterns);
|
|
7597
|
+
});
|
|
7598
|
+
const syncEntries = [];
|
|
7599
|
+
for (const fp of syncFiles) {
|
|
7600
|
+
let content = '';
|
|
7601
|
+
try { content = fs.readFileSync(fp, 'utf8'); } catch (_) { continue; }
|
|
7602
|
+
const sigs = detectAndExtract(fp, content, config.maxSigsPerFile || 25);
|
|
7603
|
+
if (sigs.length === 0) continue;
|
|
7604
|
+
syncEntries.push({ filePath: fp, sigs, language: null });
|
|
7605
|
+
}
|
|
7606
|
+
const syncContext = {
|
|
7607
|
+
projectName: path.basename(cwd),
|
|
7608
|
+
fileEntries: syncEntries,
|
|
7609
|
+
srcDirs: config.srcDirs || [],
|
|
7610
|
+
};
|
|
7611
|
+
|
|
7612
|
+
const llmTxtPath = llmTxt.outputPath(cwd);
|
|
7613
|
+
const llmFullPath = llmFullMod.outputPath(cwd);
|
|
7614
|
+
const llmsTxtPath = llmsGen.outputPath(cwd);
|
|
7615
|
+
|
|
7616
|
+
fs.writeFileSync(llmTxtPath, llmTxt.format(syncContext, cwd, VERSION));
|
|
7617
|
+
llmFullMod.write(syncContext, cwd, { version: VERSION });
|
|
7618
|
+
|
|
7619
|
+
const prev = fs.existsSync(llmsTxtPath) ? fs.readFileSync(llmsTxtPath, 'utf8') : '';
|
|
7620
|
+
const next = llmsGen.format(syncContext, cwd, [
|
|
7621
|
+
{ path: llmTxtPath, label: 'llm.txt' },
|
|
7622
|
+
{ path: llmFullPath, label: 'llm-full.txt' },
|
|
7623
|
+
], VERSION);
|
|
7624
|
+
const changed = prev !== next ? 'updated' : 'no change';
|
|
7625
|
+
fs.writeFileSync(llmsTxtPath, next);
|
|
7626
|
+
|
|
7627
|
+
console.log('[sigmap] sync complete');
|
|
7628
|
+
console.log(` .github/copilot-instructions.md updated`);
|
|
7629
|
+
console.log(` llm.txt updated`);
|
|
7630
|
+
console.log(` llm-full.txt updated`);
|
|
7631
|
+
console.log(` llms.txt ${changed}`);
|
|
7632
|
+
} catch (err) {
|
|
7633
|
+
console.error(`[sigmap] sync error: ${err.message}`);
|
|
7634
|
+
process.exit(1);
|
|
7635
|
+
}
|
|
7636
|
+
process.exit(0);
|
|
7637
|
+
}
|
|
7638
|
+
|
|
7639
|
+
// Feature 1: `sigmap explain <file>` — why a file is included or excluded
|
|
7640
|
+
if (args[0] === 'explain' || args.includes('--explain')) {
|
|
7641
|
+
const target = args[0] === 'explain'
|
|
7642
|
+
? args[1]
|
|
7643
|
+
: args[args.indexOf('--explain') + 1];
|
|
7644
|
+
|
|
7645
|
+
if (!target || target.startsWith('--')) {
|
|
7646
|
+
console.error('[sigmap] Usage: sigmap explain <file>');
|
|
7647
|
+
process.exit(1);
|
|
7648
|
+
}
|
|
7649
|
+
|
|
7650
|
+
const absPath = path.resolve(cwd, target);
|
|
7651
|
+
const rel = path.relative(cwd, absPath);
|
|
7652
|
+
const jsonOut = args.includes('--json');
|
|
7653
|
+
|
|
7654
|
+
// 1. Check .contextignore
|
|
7655
|
+
const ignorePatterns = loadIgnorePatterns(cwd);
|
|
7656
|
+
const ignored = matchesIgnore(rel.replace(/\\/g, '/'), ignorePatterns);
|
|
7657
|
+
if (ignored) {
|
|
7658
|
+
if (jsonOut) {
|
|
7659
|
+
process.stdout.write(JSON.stringify({ status: 'excluded', reason: '.contextignore', fix: `remove the pattern or add '!${rel}' as an exception` }) + '\n');
|
|
7660
|
+
} else {
|
|
7661
|
+
console.log(`[sigmap] ${rel} — EXCLUDED`);
|
|
7662
|
+
console.log(` Reason: matched .contextignore`);
|
|
7663
|
+
console.log(` Fix: remove the pattern or add '!${rel}' as an exception`);
|
|
7664
|
+
}
|
|
7665
|
+
process.exit(0);
|
|
7666
|
+
}
|
|
7667
|
+
|
|
7668
|
+
// 2. Check srcDirs membership
|
|
7669
|
+
const inSrcDirs = (config.srcDirs || []).some(d => absPath.startsWith(path.resolve(cwd, d)));
|
|
7670
|
+
if (!inSrcDirs) {
|
|
7671
|
+
if (jsonOut) {
|
|
7672
|
+
process.stdout.write(JSON.stringify({ status: 'excluded', reason: 'not in srcDirs', srcDirs: config.srcDirs, fix: 'add the containing directory to srcDirs in gen-context.config.json' }) + '\n');
|
|
7673
|
+
} else {
|
|
7674
|
+
console.log(`[sigmap] ${rel} — EXCLUDED`);
|
|
7675
|
+
console.log(` Reason: not under any srcDir (${(config.srcDirs || []).join(', ')})`);
|
|
7676
|
+
console.log(` Fix: add the containing directory to srcDirs in gen-context.config.json`);
|
|
7677
|
+
}
|
|
7678
|
+
process.exit(0);
|
|
7679
|
+
}
|
|
7680
|
+
|
|
7681
|
+
// 3. Detect extractor and extract sigs
|
|
7682
|
+
const base = path.basename(absPath);
|
|
7683
|
+
const ext = path.extname(base).toLowerCase();
|
|
7684
|
+
let extractorName = EXT_MAP[ext] || null;
|
|
7685
|
+
if (!extractorName && isDockerfile(base)) extractorName = 'dockerfile';
|
|
7686
|
+
if (!extractorName) extractorName = 'generic';
|
|
7687
|
+
|
|
7688
|
+
let sigs = [];
|
|
7689
|
+
if (fs.existsSync(absPath)) {
|
|
7690
|
+
try {
|
|
7691
|
+
const content = fs.readFileSync(absPath, 'utf8');
|
|
7692
|
+
const extractor = getExtractor(extractorName);
|
|
7693
|
+
if (extractor) sigs = extractor.extract(content).slice(0, config.maxSigsPerFile || 25);
|
|
7694
|
+
} catch (_) {}
|
|
7695
|
+
}
|
|
7696
|
+
|
|
7697
|
+
if (!sigs.length) {
|
|
7698
|
+
if (jsonOut) {
|
|
7699
|
+
process.stdout.write(JSON.stringify({ status: 'excluded', reason: 'no signatures', extractor: extractorName, fix: 'check that the file contains function/class definitions' }) + '\n');
|
|
7700
|
+
} else {
|
|
7701
|
+
console.log(`[sigmap] ${rel} — EXCLUDED`);
|
|
7702
|
+
console.log(` Reason: no extractable signatures (extractor: ${extractorName})`);
|
|
7703
|
+
console.log(` Fix: check that the file contains function/class definitions`);
|
|
7704
|
+
}
|
|
7705
|
+
process.exit(0);
|
|
7706
|
+
}
|
|
7707
|
+
|
|
7708
|
+
// 4. Included
|
|
7709
|
+
if (jsonOut) {
|
|
7710
|
+
process.stdout.write(JSON.stringify({ status: 'included', extractor: extractorName, signatures: sigs.length, preview: sigs.slice(0, 3), sigs }) + '\n');
|
|
7711
|
+
} else {
|
|
7712
|
+
console.log(`[sigmap] ${rel} — INCLUDED`);
|
|
7713
|
+
console.log(` Extractor : ${extractorName}`);
|
|
7714
|
+
console.log(` Signatures: ${sigs.length}`);
|
|
7715
|
+
console.log(` Preview : ${sigs.slice(0, 3).join(' · ')}`);
|
|
7716
|
+
}
|
|
7717
|
+
process.exit(0);
|
|
7718
|
+
}
|
|
7719
|
+
|
|
7357
7720
|
if (args.includes('--init')) {
|
|
7358
7721
|
writeInitConfig(cwd);
|
|
7359
7722
|
process.exit(0);
|
|
@@ -7363,7 +7726,14 @@ function main() {
|
|
|
7363
7726
|
const { score } = __require('./src/health/scorer');
|
|
7364
7727
|
const result = score(cwd);
|
|
7365
7728
|
if (args.includes('--json')) {
|
|
7366
|
-
|
|
7729
|
+
// Feature 3 (VS Code) + Feature 5 (JetBrains): emit tokens + reduction for plugins
|
|
7730
|
+
const ctxPath = path.join(cwd, '.github', 'copilot-instructions.md');
|
|
7731
|
+
let tokens = 0;
|
|
7732
|
+
let reduction = result.tokenReductionPct || 0;
|
|
7733
|
+
if (fs.existsSync(ctxPath)) {
|
|
7734
|
+
try { tokens = estimateTokens(fs.readFileSync(ctxPath, 'utf8')); } catch (_) {}
|
|
7735
|
+
}
|
|
7736
|
+
process.stdout.write(JSON.stringify({ ...result, tokens, reduction }) + '\n');
|
|
7367
7737
|
} else {
|
|
7368
7738
|
console.log('[sigmap] health:');
|
|
7369
7739
|
console.log(` score : ${result.score}/100 (grade ${result.grade})`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigmap",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.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": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"init": "node gen-context.js --init",
|
|
25
25
|
"report": "node gen-context.js --report",
|
|
26
26
|
"audit:strategies": "node scripts/run-strategy-audit.mjs",
|
|
27
|
+
"benchmark:matrix": "node scripts/run-benchmark-matrix.mjs --save --skip-clone",
|
|
27
28
|
"health": "node gen-context.js --health",
|
|
28
29
|
"map": "node gen-project-map.js",
|
|
29
30
|
"mcp": "node gen-context.js --mcp",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
module.exports = { name: 'llm-full', format, outputPath, write };
|
|
5
|
+
|
|
6
|
+
function outputPath(cwd) { return path.join(cwd, 'llm-full.txt'); }
|
|
7
|
+
|
|
8
|
+
function format(context, opts) {
|
|
9
|
+
opts = opts || {};
|
|
10
|
+
const lines = [
|
|
11
|
+
`# ${context.projectName || 'Project'} — SigMap Context`,
|
|
12
|
+
`Generated: ${new Date().toISOString()} | SigMap v${opts.version || ''}`,
|
|
13
|
+
'',
|
|
14
|
+
];
|
|
15
|
+
for (const entry of (context.fileEntries || [])) {
|
|
16
|
+
const rel = path.relative(opts.cwd || '', entry.filePath);
|
|
17
|
+
lines.push(`## ${rel}`, '```', ...(entry.sigs || []), '```', '');
|
|
18
|
+
}
|
|
19
|
+
return lines.join('\n');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function write(context, cwd, opts) {
|
|
23
|
+
opts = opts || {};
|
|
24
|
+
fs.writeFileSync(outputPath(cwd), format(context, { ...opts, cwd }));
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
module.exports = { extract };
|
|
3
|
+
|
|
4
|
+
const PATTERNS = [
|
|
5
|
+
/^(?:pub\s+)?(?:async\s+)?function\s+\w+\s*\(/,
|
|
6
|
+
/^(?:pub\s+)?(?:async\s+)?fn\s+\w+[\s(<]/,
|
|
7
|
+
/^def\s+\w+[\s(|:]/,
|
|
8
|
+
/^(?:pub\s+)?func\s+\w+\s*\(/,
|
|
9
|
+
/^(?:let|let\s+rec)\s+\w+\s*[=(]/,
|
|
10
|
+
/^class\s+\w+/,
|
|
11
|
+
/^(?:proc|sub|method)\s+\w+\s*\(/,
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function extract(src) {
|
|
15
|
+
if (!src || typeof src !== 'string') return [];
|
|
16
|
+
const results = [];
|
|
17
|
+
for (const raw of src.split('\n')) {
|
|
18
|
+
const line = raw.trim();
|
|
19
|
+
if (!line || /^[#\-]/.test(line) || /^\/\//.test(line) || line.includes('\0')) continue;
|
|
20
|
+
for (const pat of PATTERNS) {
|
|
21
|
+
if (pat.test(line)) { results.push(line.slice(0, 120)); break; }
|
|
22
|
+
}
|
|
23
|
+
if (results.length >= 15) break;
|
|
24
|
+
}
|
|
25
|
+
return results;
|
|
26
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const path = require('path');
|
|
3
|
+
module.exports = { format, outputPath };
|
|
4
|
+
|
|
5
|
+
function outputPath(cwd) { return path.join(cwd, 'llm.txt'); }
|
|
6
|
+
|
|
7
|
+
function format(context, cwd, version) {
|
|
8
|
+
const name = context.projectName || path.basename(cwd);
|
|
9
|
+
const langs = [...new Set((context.fileEntries || []).map(f => f.language).filter(Boolean))];
|
|
10
|
+
const mods = context.srcDirs || [];
|
|
11
|
+
|
|
12
|
+
return [
|
|
13
|
+
`# Project: ${name}`,
|
|
14
|
+
`Languages: ${langs.join(', ') || 'unknown'}`,
|
|
15
|
+
`Root: ${mods[0] || 'src/'}`,
|
|
16
|
+
'',
|
|
17
|
+
'## Modules',
|
|
18
|
+
...mods.map(m => `- ${m}/`),
|
|
19
|
+
'',
|
|
20
|
+
'## Key flows',
|
|
21
|
+
'- <!-- describe your main user flows here -->',
|
|
22
|
+
'',
|
|
23
|
+
'## Rules',
|
|
24
|
+
'- <!-- describe your team conventions here -->',
|
|
25
|
+
'',
|
|
26
|
+
`Generated: ${new Date().toISOString()} | SigMap v${version}`,
|
|
27
|
+
].join('\n');
|
|
28
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
module.exports = { format, outputPath };
|
|
6
|
+
|
|
7
|
+
function outputPath(cwd) { return path.join(cwd, 'llms.txt'); }
|
|
8
|
+
|
|
9
|
+
function getShortCommit(cwd) {
|
|
10
|
+
try { return execSync('git rev-parse --short HEAD', { cwd, timeout: 2000 }).toString().trim(); }
|
|
11
|
+
catch (_) { return ''; }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function detectVersion(cwd) {
|
|
15
|
+
try {
|
|
16
|
+
const pkg = path.join(cwd, 'package.json');
|
|
17
|
+
if (fs.existsSync(pkg)) return JSON.parse(fs.readFileSync(pkg, 'utf8')).version || '';
|
|
18
|
+
} catch (_) {}
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function format(context, cwd, writtenFiles, sigmapVersion) {
|
|
23
|
+
writtenFiles = writtenFiles || [];
|
|
24
|
+
sigmapVersion = sigmapVersion || '';
|
|
25
|
+
|
|
26
|
+
const name = context.projectName || path.basename(cwd);
|
|
27
|
+
const ver = detectVersion(cwd);
|
|
28
|
+
const commit = getShortCommit(cwd);
|
|
29
|
+
const langs = [...new Set((context.fileEntries || []).map(f => f.language).filter(Boolean))];
|
|
30
|
+
|
|
31
|
+
const lines = [
|
|
32
|
+
'# SigMap Context Index',
|
|
33
|
+
`> Generated by SigMap v${sigmapVersion} — zero-dependency AI context engine`,
|
|
34
|
+
'',
|
|
35
|
+
'## Project',
|
|
36
|
+
`- Name: ${name}`,
|
|
37
|
+
];
|
|
38
|
+
if (ver) lines.push(`- Version: ${ver}`);
|
|
39
|
+
if (langs.length) lines.push(`- Language: ${langs.join(', ')}`);
|
|
40
|
+
if (commit) lines.push(`- Commit: ${commit}`);
|
|
41
|
+
|
|
42
|
+
if (writtenFiles.length) {
|
|
43
|
+
lines.push('', '## Context Files');
|
|
44
|
+
for (const f of writtenFiles) {
|
|
45
|
+
const rel = path.relative(cwd, f.path);
|
|
46
|
+
const extra = f.tokens ? `: ${f.tokens} tokens` : '';
|
|
47
|
+
lines.push(`- [${f.label || rel}](${rel})${extra}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const mods = context.srcDirs || [];
|
|
52
|
+
if (mods.length) {
|
|
53
|
+
lines.push('', '## Source Modules');
|
|
54
|
+
for (const m of mods) lines.push(`- [${m}/](${m}/)`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const top5 = (context.fileEntries || [])
|
|
58
|
+
.sort((a, b) => (b.sigs || []).length - (a.sigs || []).length)
|
|
59
|
+
.slice(0, 5);
|
|
60
|
+
if (top5.length) {
|
|
61
|
+
lines.push('', '## Key Files');
|
|
62
|
+
for (const f of top5) {
|
|
63
|
+
const rel = path.relative(cwd, f.filePath);
|
|
64
|
+
const preview = (f.sigs || []).slice(0, 3).join(', ');
|
|
65
|
+
lines.push(`- ${rel}: ${preview}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return lines.join('\n');
|
|
70
|
+
}
|