sigmap 3.0.1 → 3.1.0-alpha.1

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,6 +6,66 @@ Format: [Semantic Versioning](https://semver.org/)
6
6
 
7
7
  ---
8
8
 
9
+ ## [Unreleased]
10
+
11
+ ---
12
+
13
+ ## [3.2.0] — Planned — Phase A: Cross-Platform Standalone Binaries
14
+
15
+ ### Added
16
+ - **Standalone binaries** — macOS (arm64 + x64), Linux x64, Windows x64 built via Node.js SEA
17
+ - No Node.js or npm required to run SigMap
18
+ - Download from GitHub Releases: `sigmap-darwin-arm64`, `sigmap-darwin-x64`, `sigmap-linux-x64`, `sigmap-win32-x64.exe`
19
+ - SHA-256 checksums in `sigmap-checksums.txt` attached to every release
20
+ - **`scripts/build-binary.mjs`** — reproducible local binary build for the current platform
21
+ - **`scripts/verify-binary.mjs`** — smoke tests `--version`, `--help`, `generate`, `health`, `report` against a fixture repo
22
+ - **`.github/workflows/release-binaries.yml`** — GHA matrix builds all 4 targets on tag push; attaches artifacts to the GitHub Release
23
+ - **`test/fixtures/binary-smoke/`** — minimal fixture project used by CI smoke tests
24
+ - **`docs/binaries.md`** — install guide covering download, `chmod +x`, macOS Gatekeeper, Windows SmartScreen, and checksum verification
25
+
26
+ ### Technical
27
+ - Uses [Node.js SEA](https://nodejs.org/api/single-executable-applications.html) (Node 20 `--experimental-sea-config` + `postject`)
28
+ - `gen-context.js` required no changes — existing `requireSourceOrBundled()` fallback and DEFAULTS fallback in `writeInitConfig()` are both SEA-compatible
29
+ - Binary builds run natively per OS in GHA (no cross-compilation)
30
+ - `release-attach` job waits for the npm-publish Release to exist before uploading binary assets
31
+
32
+ ---
33
+
34
+ ## [3.1.0] — 2026-04-07 — Global Command Detection & VS Code Prerelease Fix
35
+
36
+ ### Added
37
+ - **VS Code extension: global command auto-detection** — extension now finds `gen-context` installed via Volta, nvm, npm, or Homebrew without requiring `gen-context.js` in the project root or a manual `sigmap.scriptPath` setting
38
+ - Probe chain: local `node_modules/.bin` → `~/.volta/bin` → `~/.nvm/versions/node/*/bin` (newest first) → `/usr/local/bin` → `/opt/homebrew/bin` → `~/.npm-global/bin` → login-shell `which`
39
+ - Works on macOS GUI apps that do not inherit shell `PATH`
40
+ - `resolveGlobalCommand()` + unified `resolveRunner()` added to `vscode-extension/src/extension.js`
41
+ - **VS Code extension: actionable error message** — when command is not found, notification offers "Copy install command" (copies `npm install -g sigmap` to clipboard) and "Open settings" buttons instead of a plain warning
42
+ - **Prerelease GitHub Actions workflow** — new `prerelease-publish.yml` for manual alpha/beta/rc releases across all 5 platforms (npm, GitHub Packages, VS Code, Open VSX, JetBrains) without marking as @latest
43
+ - VS Code/Open VSX uses `major.minor.patch` versioning (VSCE prerelease constraint)
44
+ - npm/JetBrains use full semver prerelease suffix (e.g. `3.1.0-beta.1`)
45
+
46
+ ### Fixed
47
+ - **`output` config key not honored for copilot adapter** · [#30](https://github.com/manojmallick/sigmap/issues/30)
48
+ - Custom `output` path in config now correctly used for copilot adapter instead of hard-wired `.github/copilot-instructions.md`
49
+ - Added `resolveAdapterPath()` helper to centralize adapter path resolution
50
+ - Other adapters (claude, cursor, windsurf) continue to use fixed paths as designed
51
+ - 5 new integration tests ensure custom paths work correctly across all config combinations
52
+ - **JetBrains plugin: global `gen-context` command support** · [#29](https://github.com/manojmallick/sigmap/issues/29)
53
+ - Plugin now resolves command via fallback chain: local `gen-context.js` → `node_modules/.bin/gen-context` → system `PATH`
54
+ - Enables use in Java, Rust, Go and other non-Node projects with `gen-context` installed globally via Volta/nvm/npm
55
+ - **VS Code prerelease versioning** — workflow previously failed publishing because semver-suffixed versions (e.g. `3.1.0-alpha.1`) are rejected by VSCE; fixed by splitting into separate `npm_version` and `vscode_version` outputs
56
+
57
+ ### Technical
58
+ - `resolveRunner()` returns `{ type: 'script' | 'command', path }` allowing extension to run either `node "path/gen-context.js"` or `"~/.volta/bin/gen-context"` without modification to the terminal command
59
+
60
+ ### How to release (tag triggers automatic publish)
61
+ ```bash
62
+ git tag v3.1.0
63
+ git push origin v3.1.0
64
+ # npm-publish.yml auto-triggers and publishes to all 5 platforms
65
+ ```
66
+
67
+ ---
68
+
9
69
  ## [3.0.0] — 2026-04-06 — Platform: Multi-Adapter Architecture
10
70
 
11
71
  ### Added
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p>
8
8
  Every coding agent session starts with full codebase context at under 4K tokens.<br>
9
- No <code>npm install</code>. No setup. Runs on any machine with Node.js 18+.
9
+ Multiple install options. Zero runtime dependencies. Requires only Node.js 18+.
10
10
  </p>
11
11
 
12
12
  <!-- Status -->
@@ -26,7 +26,7 @@
26
26
  [![Changelog](https://img.shields.io/badge/changelog-CHANGELOG.md-blue)](CHANGELOG.md)
27
27
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
28
28
  [![VS Code](https://img.shields.io/badge/VS%20Code-extension-0078d4?logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=manojmallick.sigmap)
29
- [![JetBrains](https://img.shields.io/badge/JetBrains-plugin-000000?logo=jetbrains)](https://plugins.jetbrains.com/plugin/sigmap)
29
+ [![JetBrains](https://img.shields.io/badge/JetBrains-plugin-000000?logo=jetbrains)](https://plugins.jetbrains.com/plugin/31109-sigmap--ai-context-engine/)
30
30
  [![Open VSX](https://img.shields.io/open-vsx/v/manojmallick/sigmap?color=a251e3&label=Open%20VSX&logo=vscodium)](https://open-vsx.org/extension/manojmallick/sigmap)
31
31
 
32
32
  </div>
@@ -38,7 +38,8 @@
38
38
  | | |
39
39
  |---|---|
40
40
  | [What it does](#-what-it-does) | Token reduction table, pipeline overview |
41
- | [Quick start](#-quick-start) | Get running in 60 seconds |
41
+ | [Quick start](#-quick-start) | Install (binary or npm), generate in 60 seconds |
42
+ | [Standalone binaries](docs/binaries.md) | macOS, Linux, Windows — no Node required |
42
43
  | [VS Code extension](#-vs-code-extension) | Status bar, stale alerts, commands |
43
44
  | [JetBrains plugin](#-jetbrains-plugin) | IntelliJ IDEA, WebStorm, PyCharm support |
44
45
  | [Languages supported](#-languages-supported) | 21 languages |
@@ -47,6 +48,7 @@
47
48
  | [CLI reference](#-cli-reference) | All flags |
48
49
  | [Configuration](#-configuration) | Config file + .contextignore |
49
50
  | [Observability](#-observability) | Health score, reports, CI |
51
+ | [Programmatic API](#-programmatic-api) | Use as a Node.js library |
50
52
  | [Testing](#-testing) | Run the test suite |
51
53
  | [Project structure](#-project-structure) | File-by-file map |
52
54
  | [Principles](#-principles) | Design decisions |
@@ -88,57 +90,96 @@ AI agent session starts with full context
88
90
 
89
91
  ---
90
92
 
91
- ## 🆕 What's new in 2.4
93
+ ## Installation
92
94
 
93
- | Feature | Description |
94
- |---|---|
95
- | **Programmatic API** | `require('sigmap')` — use `extract`, `rank`, `buildSigIndex`, `scan`, `score` directly, no CLI subprocess |
96
- | **`packages/core/`** | New `sigmap-core` package with stable API surface for third-party integrations |
97
- | **`packages/cli/`** | Thin `sigmap-cli` forward-compat shim for the v3.0 adapter architecture |
98
- | **15 new tests** | `core-api.test.js` covers all exported functions, edge cases, and backward compat |
95
+ Pick the method that fits your workflow — all produce the same output.
99
96
 
100
- ## 🆕 What's new in 2.3
97
+ <details open>
98
+ <summary><strong>npx — try without installing</strong></summary>
101
99
 
102
- | Feature | Description |
103
- |---|---|
104
- | **`--query "<text>"` CLI** | Rank all context files by relevance to a free-text query — scored table + top-3 signature blocks |
105
- | **`--query --json`** | Machine-readable ranked results (`{ query, results[], totalResults }`) |
106
- | **`--query --top <n>`** | Limit results (default 10, configurable via `retrieval.topK`) |
107
- | **`query_context` MCP tool** | 8th MCP tool — `{ query, topK? }` returns ranked file list, usable live in any MCP session |
108
- | **`--analyze` / `--diagnose-extractors`** | Per-file breakdown of sigs/tokens/extractor/coverage; self-tests all 21 extractors (v2.2) |
109
- | **`--benchmark` / `--eval`** | Measure hit@5 and MRR retrieval quality against a JSONL task file (v2.1) |
100
+ ```bash
101
+ npx sigmap
102
+ ```
110
103
 
111
- > **Previous v2.0 additions:** enriched signatures, dependency map, TODO/FIXME section, test coverage markers, structural diff mode, impact radius hints. See [CHANGELOG.md](CHANGELOG.md) for the full history.
104
+ Runs the latest version without any permanent install. Great for a quick try.
112
105
 
113
- ---
106
+ </details>
107
+
108
+ <details>
109
+ <summary><strong>npm global — install once, run anywhere</strong></summary>
114
110
 
115
- ## 🔭 What's next — v2.10 (in progress · [#25](https://github.com/manojmallick/sigmap/issues/25))
111
+ ```bash
112
+ npm install -g sigmap
113
+ sigmap
114
+ ```
116
115
 
117
- ### v2.10 Reporting: Charts + Advanced Metrics
116
+ Available from any directory on your machine.
118
117
 
119
- | Feature | Description |
120
- |---|---|
121
- | **Charts in reports** | Visualize token reduction, signature counts, and budget usage per run |
122
- | **Advanced retrieval metrics** | Add precision@K, recall@K, MRR trend, and query-level diagnostics |
123
- | **Evaluation dashboard output** | Generate shareable HTML/JSON benchmark summaries from CLI runs |
124
- | **CI-friendly metrics export** | Persist machine-readable metrics for release gates and regression tracking |
125
- | **Release quality gates** | Add pass/fail thresholds for hit@5 and precision before publish |
126
- ## 🔌 v3.0 — Platform: Multi-Adapter Architecture
118
+ </details>
127
119
 
128
- SigMap is now an **adapter platform**. Any AI assistant — Copilot, Claude, Cursor, Windsurf, OpenAI, or Gemini — plugs in through a standard interface.
120
+ <details>
121
+ <summary><strong>npm local — per-project, version-pinned</strong></summary>
129
122
 
130
123
  ```bash
131
- # Generate for a specific AI assistant
132
- node gen-context.js --adapter copilot # → .github/copilot-instructions.md
133
- node gen-context.js --adapter openai # → .github/openai-context.md
134
- node gen-context.js --adapter gemini # → .github/gemini-context.md
135
- node gen-context.js --adapter claude # → CLAUDE.md (append)
124
+ npm install --save-dev sigmap
136
125
  ```
137
126
 
138
- ```js
139
- // Programmatic API — fully semver-stable from v3.0
140
- const { adapt } = require('sigmap');
141
- const systemPrompt = adapt(context, 'openai', { version: '3.0.0' });
127
+ Add to `package.json` scripts for team consistency:
128
+
129
+ ```json
130
+ {
131
+ "scripts": {
132
+ "context": "sigmap",
133
+ "context:watch": "sigmap --watch"
134
+ }
135
+ }
136
+ ```
137
+
138
+ Run with `npm run context`. Version is pinned per project.
139
+
140
+ </details>
141
+
142
+ <details>
143
+ <summary><strong>Volta — team-friendly, auto-pinned version</strong></summary>
144
+
145
+ ```bash
146
+ volta install sigmap
147
+ sigmap
148
+ ```
149
+
150
+ [Volta](https://volta.sh) pins the exact version in `package.json` — every team member runs the same version automatically without configuration.
151
+
152
+ </details>
153
+
154
+ <details>
155
+ <summary><strong>Single-file download — no npm, any machine</strong></summary>
156
+
157
+ ```bash
158
+ curl -O https://raw.githubusercontent.com/manojmallick/sigmap/main/gen-context.js
159
+ node gen-context.js
160
+ ```
161
+
162
+ No npm, no `node_modules`. Drop `gen-context.js` into any project and run it directly. Requires only Node.js 18+. Ideal for CI, locked-down environments, or one-off use.
163
+
164
+ </details>
165
+
166
+ > **Note:** When using the single-file download, replace `sigmap` with `node gen-context.js` in all commands below.
167
+
168
+ ---
169
+
170
+ ## 🚀 Features
171
+
172
+ ### Multi-adapter output
173
+
174
+ Generate context for any AI assistant from a single run:
175
+
176
+ ```bash
177
+ sigmap --adapter copilot # → .github/copilot-instructions.md
178
+ sigmap --adapter claude # → CLAUDE.md (appended below marker)
179
+ sigmap --adapter cursor # → .cursorrules
180
+ sigmap --adapter windsurf # → .windsurfrules
181
+ sigmap --adapter openai # → .github/openai-context.md
182
+ sigmap --adapter gemini # → .github/gemini-context.md
142
183
  ```
143
184
 
144
185
  | Adapter | Output file | AI assistant |
@@ -150,38 +191,80 @@ const systemPrompt = adapt(context, 'openai', { version: '3.0.0' });
150
191
  | `openai` | `.github/openai-context.md` | Any OpenAI model |
151
192
  | `gemini` | `.github/gemini-context.md` | Google Gemini |
152
193
 
153
- **Backward compat:** existing `outputs` config key silently maps to `adapters` — no migration needed.
194
+ Configure multiple adapters at once in `gen-context.config.json`:
195
+
196
+ ```json
197
+ { "outputs": ["copilot", "claude", "cursor"] }
198
+ ```
199
+
200
+ ### Programmatic API
201
+
202
+ Use SigMap as a Node.js library without spawning a subprocess. See the [full API reference](#-programmatic-api) below.
203
+
204
+ ### Query-aware retrieval
154
205
 
155
- See full roadmap: [manojmallick.github.io/sigmap/roadmap.html](https://manojmallick.github.io/sigmap/roadmap.html)
206
+ Find the most relevant files for any task without reading the whole codebase:
207
+
208
+ ```bash
209
+ sigmap --query "authentication middleware" # ranked file list
210
+ sigmap --query "auth" --json # machine-readable output
211
+ sigmap --query "auth" --top 5 # top 5 results only
212
+ ```
213
+
214
+ ### Diagnostic and evaluation tools
215
+
216
+ ```bash
217
+ sigmap --analyze # per-file: sigs, tokens, extractor, coverage
218
+ sigmap --analyze --slow # include extraction timing
219
+ sigmap --diagnose-extractors # self-test all 21 extractors against fixtures
220
+ sigmap --benchmark # hit@5 and MRR retrieval quality
221
+ sigmap --benchmark --json # machine-readable benchmark results
222
+ ```
156
223
 
157
224
  ---
158
- curl -O https://raw.githubusercontent.com/manojmallick/sigmap/main/gen-context.js
159
225
 
160
- # 2. Generate your context file
161
- node gen-context.js
226
+ ## Quick start
227
+
228
+ ### Install
229
+
230
+ **Standalone binary** — no Node.js or npm required:
162
231
 
163
- # 3. Output: .github/copilot-instructions.md
164
- # That file is auto-read by GitHub Copilot in VS Code
232
+ | Platform | Download |
233
+ |---|---|
234
+ | macOS Apple Silicon | [`sigmap-darwin-arm64`](https://github.com/manojmallick/sigmap/releases/latest/download/sigmap-darwin-arm64) |
235
+ | macOS Intel | [`sigmap-darwin-x64`](https://github.com/manojmallick/sigmap/releases/latest/download/sigmap-darwin-x64) |
236
+ | Linux x64 | [`sigmap-linux-x64`](https://github.com/manojmallick/sigmap/releases/latest/download/sigmap-linux-x64) |
237
+ | Windows x64 | [`sigmap-win32-x64.exe`](https://github.com/manojmallick/sigmap/releases/latest/download/sigmap-win32-x64.exe) |
238
+
239
+ ```bash
240
+ # macOS / Linux
241
+ chmod +x ./sigmap-darwin-arm64
242
+ ./sigmap-darwin-arm64 generate
165
243
  ```
166
244
 
167
- Or via npm (globally):
245
+ See [docs/binaries.md](docs/binaries.md) for Gatekeeper / SmartScreen notes and checksum verification.
246
+
247
+ **npm** (requires Node.js 18+):
168
248
 
169
249
  ```bash
170
- npx sigmap # run once without installing
171
- npm install -g sigmap # install globally
172
- sigmap # then use anywhere
250
+ npx sigmap # run once without installing
251
+ npm install -g sigmap # install globally
173
252
  ```
174
253
 
175
- ### Common workflows
254
+ ---
255
+
256
+ ### Generate context
257
+
258
+ Download the single-file CLI and generate context immediately:
176
259
 
177
260
  ```bash
178
- node gen-context.js # generate once and exit
179
- node gen-context.js --watch # regenerate on every file save
180
- node gen-context.js --setup # generate + install git hook + start watcher
181
- node gen-context.js --diff # context for git-changed files only (PR mode)
182
- node gen-context.js --diff --staged # staged files only (pre-commit check)
183
- node gen-context.js --health # show context health score (grade A–D)
184
- node gen-context.js --mcp # start MCP server on stdio
261
+ sigmap # generate once and exit
262
+ sigmap --watch # regenerate on every file save
263
+ sigmap --setup # generate + install git hook + start watcher
264
+ sigmap --diff # context for git-changed files only (PR mode)
265
+ sigmap --diff --staged # staged files only (pre-commit check)
266
+ sigmap --health # show context health score (grade A–D)
267
+ sigmap --mcp # start MCP server on stdio
185
268
  ```
186
269
 
187
270
  ### Companion tool: Repomix
@@ -194,8 +277,8 @@ SigMap and [Repomix](https://github.com/yamadashy/repomix) are **complementary,
194
277
  | **Repomix** | On-demand deep sessions, full file content, broader language support |
195
278
 
196
279
  ```bash
197
- node gen-context.js --setup # always-on context
198
- npx repomix --compress # deep dive sessions
280
+ sigmap --setup # always-on context
281
+ npx repomix --compress # deep dive sessions
199
282
  ```
200
283
 
201
284
  *"SigMap for daily always-on context; Repomix for deep one-off sessions — use both."*
@@ -204,8 +287,6 @@ npx repomix --compress # deep dive sessions
204
287
 
205
288
  ## 🧩 VS Code extension
206
289
 
207
- > Introduced in v1.5 — zero runtime npm dependencies.
208
-
209
290
  The `vscode-extension/` directory contains a first-party VS Code extension that keeps you informed without any manual commands.
210
291
 
211
292
  | Feature | Detail |
@@ -224,8 +305,6 @@ Activate on startup (`onStartupFinished`) — loads within 3 s, never blocks edi
224
305
 
225
306
  ## 🔧 JetBrains plugin
226
307
 
227
- > Introduced in v2.9 — brings SigMap to IntelliJ IDEA, WebStorm, PyCharm, and all JetBrains IDEs.
228
-
229
308
  The `jetbrains-plugin/` directory contains a Kotlin-based plugin for JetBrains IDEs with the same core features as the VS Code extension.
230
309
 
231
310
  | Feature | Detail |
@@ -238,7 +317,7 @@ The `jetbrains-plugin/` directory contains a Kotlin-based plugin for JetBrains I
238
317
 
239
318
  Compatible with **IntelliJ IDEA 2024.1+** (Community & Ultimate), **WebStorm**, **PyCharm**, **GoLand**, **RubyMine**, **PhpStorm**, and all other IntelliJ-based IDEs.
240
319
 
241
- **Install:** [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/sigmap) | [Manual setup guide](docs/JETBRAINS_SETUP.md)
320
+ **Install:** [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/31109-sigmap--ai-context-engine/) | [Manual setup guide](docs/JETBRAINS_SETUP.md)
242
321
 
243
322
  ---
244
323
 
@@ -279,7 +358,7 @@ Compatible with **IntelliJ IDEA 2024.1+** (Community & Ultimate), **WebStorm**,
279
358
 
280
359
  ## 🗂 Context strategies
281
360
 
282
- > Introduced in v1.1. Reduce always-injected tokens by 70–90%.
361
+ > Reduce always-injected tokens by 70–90%.
283
362
 
284
363
  Set `"strategy"` in `gen-context.config.json`:
285
364
 
@@ -326,8 +405,6 @@ Recently committed files are **hot** (auto-injected). Everything else is **cold*
326
405
 
327
406
  ## 🔌 MCP server
328
407
 
329
- > Introduced in v0.3, expanded to 8 tools through v2.3.
330
-
331
408
  Start the MCP server on stdio:
332
409
 
333
410
  ```bash
@@ -345,7 +422,7 @@ node gen-context.js --mcp
345
422
  | `list_modules` | — | Token-count table of all top-level module directories |
346
423
  | `create_checkpoint` | `{ summary: string }` | Write a session checkpoint to `.context/` |
347
424
  | `get_routing` | — | Full model routing table |
348
- | `query_context` | `{ query: string, topK?: number }` | Files ranked by relevance to the query (v2.3) |
425
+ | `query_context` | `{ query: string, topK?: number }` | Files ranked by relevance to the query |
349
426
 
350
427
  Reads files on every call — no stale state, no restart needed.
351
428
 
@@ -355,7 +432,7 @@ Reads files on every call — no stale state, no restart needed.
355
432
 
356
433
  ## ⚙️ CLI reference
357
434
 
358
- > All flags live in v1.5. See [CHANGELOG.md](CHANGELOG.md) for when each shipped.
435
+ > See [CHANGELOG.md](CHANGELOG.md) for the full history.
359
436
 
360
437
  ```
361
438
  node gen-context.js Generate once and exit
@@ -441,6 +518,7 @@ Copy `gen-context.config.json.example` to `gen-context.config.json`:
441
518
 
442
519
  ```json
443
520
  {
521
+ "output": ".github/copilot-instructions.md",
444
522
  "srcDirs": ["src", "app", "lib"],
445
523
  "maxTokens": 6000,
446
524
  "outputs": ["copilot"],
@@ -451,6 +529,15 @@ Copy `gen-context.config.json.example` to `gen-context.config.json`:
451
529
  }
452
530
  ```
453
531
 
532
+ **Key fields:**
533
+
534
+ - **`output`** — custom path for the primary markdown output file (used by `copilot` adapter). Default: `.github/copilot-instructions.md`
535
+ - **`outputs`** — which adapters to write to: `copilot` | `claude` | `cursor` | `windsurf`
536
+ - **`srcDirs`** — directories to scan (relative to project root)
537
+ - **`maxTokens`** — max tokens in final output before budget enforcement
538
+ - **`secretScan`** — redact secrets (AWS keys, tokens, etc.) from output
539
+ - **`strategy`** — output mode: `full` (default) | `per-module` | `hot-cold`
540
+
454
541
  Exclusions go in `.contextignore` (gitignore syntax). Also reads `.repomixignore` if present.
455
542
 
456
543
  ```
@@ -468,12 +555,25 @@ Run `node gen-context.js --init` to scaffold both files in one step.
468
555
 
469
556
  | Key | Output file | Read by |
470
557
  |---|---|---|
471
- | `"copilot"` | `.github/copilot-instructions.md` | GitHub Copilot |
558
+ | `"copilot"` | `.github/copilot-instructions.md` *(or custom path via `output`)* | GitHub Copilot |
472
559
  | `"claude"` | `CLAUDE.md` (appends below marker) | Claude Code |
473
560
  | `"cursor"` | `.cursorrules` | Cursor |
474
561
  | `"windsurf"` | `.windsurfrules` | Windsurf |
475
562
 
476
- ---
563
+ The **`output`** config key sets the primary output file path. It is used by the `copilot` adapter when enabled. Other adapters always write to their fixed paths.
564
+
565
+ **Example:**
566
+
567
+ ```json
568
+ {
569
+ "output": ".context/ai-context.md",
570
+ "outputs": ["copilot"]
571
+ }
572
+ ```
573
+
574
+ This writes to `.context/ai-context.md` instead of `.github/copilot-instructions.md`.
575
+
576
+ If `output` is omitted, the default `.github/copilot-instructions.md` is used.
477
577
 
478
578
  ## 📊 Observability
479
579
 
@@ -517,7 +617,7 @@ node gen-context.js --format cache
517
617
 
518
618
  ---
519
619
 
520
- ## 📦 Programmatic API (v2.4+)
620
+ ## 📦 Programmatic API
521
621
 
522
622
  Use SigMap as a library — no CLI subprocess needed:
523
623
 
@@ -652,61 +752,6 @@ sigmap/
652
752
 
653
753
  ---
654
754
 
655
- ## 📦 Publishing to npm
656
-
657
- Releases are published automatically via GitHub Actions whenever a version tag is pushed.
658
-
659
- ### One-time setup
660
-
661
- 1. **Create an npm account** at [npmjs.com](https://www.npmjs.com) (if you haven't already).
662
-
663
- 2. **Generate an npm access token**:
664
- - npmjs.com → Account → Access Tokens → Generate New Token → **Granular Access Token** (or Classic Automation token)
665
- - Scope: `sigmap` package, permission: **Read and Write**
666
-
667
- 3. **Add the secret to GitHub**:
668
- ```
669
- GitHub repo → Settings → Secrets and variables → Actions → New repository secret
670
- Name: NPM_TOKEN
671
- Value: <paste token>
672
- ```
673
-
674
- ### Releasing a new version
675
-
676
- ```bash
677
- # 1. Bump version in package.json
678
- npm version patch # or minor / major
679
-
680
- # 2. Push the commit AND the new tag
681
- git push && git push --tags
682
- ```
683
-
684
- The [npm-publish workflow](.github/workflows/npm-publish.yml) will:
685
- 1. Run the full test suite
686
- 2. Verify `package.json` version matches the pushed tag
687
- 3. Publish to npm with provenance attestation
688
- 4. Create a GitHub Release with auto-generated notes
689
-
690
- ### Backfilling historical versions
691
-
692
- Tags that existed before the workflow was set up can be published retroactively:
693
-
694
- ```bash
695
- # Dry run first — see what would be published
696
- ./scripts/backfill-npm.sh
697
-
698
- # Actually publish all historical tags
699
- export NPM_TOKEN=npm_xxxxxxxxxxxx
700
- ./scripts/backfill-npm.sh --publish
701
-
702
- # Start from a specific tag
703
- ./scripts/backfill-npm.sh --publish --from v0.5.0
704
- ```
705
-
706
- The script assigns `dist-tag: legacy` to all versions except `v1.5.0` (which gets `latest`), so `npm install sigmap` always resolves to the current release.
707
-
708
- ---
709
-
710
755
  ## 🤝 Contributing
711
756
 
712
757
  See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add a language extractor or new feature.
package/gen-context.js CHANGED
@@ -1892,6 +1892,152 @@ __factories["./src/extractors/yaml"] = function(module, exports) {
1892
1892
 
1893
1893
  };
1894
1894
 
1895
+ // ── ./src/extractors/todos ──
1896
+ __factories["./src/extractors/todos"] = function(module, exports) {
1897
+
1898
+ 'use strict';
1899
+
1900
+ /**
1901
+ * Extract TODO/FIXME/HACK/XXX comments from source text.
1902
+ * @param {string} src - Raw file content
1903
+ * @returns {{line:number, tag:string, text:string}[]}
1904
+ */
1905
+ function extractTodos(src) {
1906
+ if (!src || typeof src !== 'string') return [];
1907
+ const todos = [];
1908
+ const lines = src.split('\n');
1909
+
1910
+ for (let i = 0; i < lines.length; i++) {
1911
+ const m = lines[i].match(/(?:\/\/|#)\s*(TODO|FIXME|HACK|XXX)\s*:?\s*(.+)/i);
1912
+ if (!m) continue;
1913
+ todos.push({
1914
+ line: i + 1,
1915
+ tag: m[1].toUpperCase(),
1916
+ text: m[2].trim().slice(0, 70),
1917
+ });
1918
+ }
1919
+
1920
+ return todos;
1921
+ }
1922
+
1923
+ module.exports = { extractTodos };
1924
+
1925
+ };
1926
+
1927
+ // ── ./src/extractors/coverage ──
1928
+ __factories["./src/extractors/coverage"] = function(module, exports) {
1929
+
1930
+ 'use strict';
1931
+
1932
+ const fs = require('fs');
1933
+ const path = require('path');
1934
+
1935
+ function walkFiles(dir) {
1936
+ let out = [];
1937
+ let entries;
1938
+ try {
1939
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1940
+ } catch (_) {
1941
+ return out;
1942
+ }
1943
+ for (const entry of entries) {
1944
+ const full = path.join(dir, entry.name);
1945
+ if (entry.isDirectory()) out = out.concat(walkFiles(full));
1946
+ else if (entry.isFile()) out.push(full);
1947
+ }
1948
+ return out;
1949
+ }
1950
+
1951
+ function buildTestIndex(cwd, testDirs) {
1952
+ const dirs = Array.isArray(testDirs) && testDirs.length ? testDirs : ['tests', 'test', '__tests__', 'spec'];
1953
+ const names = new Set();
1954
+
1955
+ for (const dir of dirs) {
1956
+ const abs = path.join(cwd, dir);
1957
+ if (!fs.existsSync(abs)) continue;
1958
+ for (const file of walkFiles(abs)) {
1959
+ let src = '';
1960
+ try {
1961
+ src = fs.readFileSync(file, 'utf8');
1962
+ } catch (_) {
1963
+ continue;
1964
+ }
1965
+
1966
+ for (const m of src.matchAll(/\b(?:test_|it\(|test\(|describe\()\s*['"`]?([\w_]+)/g)) {
1967
+ if (m[1] && m[1].length >= 3) names.add(m[1].toLowerCase());
1968
+ }
1969
+
1970
+ for (const m of src.matchAll(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g)) {
1971
+ if (m[1] && m[1].length >= 4) names.add(m[1].toLowerCase());
1972
+ }
1973
+ }
1974
+ }
1975
+
1976
+ return names;
1977
+ }
1978
+
1979
+ function isTested(funcName, testIndex) {
1980
+ if (!funcName || funcName.length < 3 || !testIndex || testIndex.size === 0) return false;
1981
+ const lower = funcName.toLowerCase();
1982
+ if (testIndex.has(lower) || testIndex.has(`test_${lower}`)) return true;
1983
+ return false;
1984
+ }
1985
+
1986
+ module.exports = { buildTestIndex, isTested };
1987
+
1988
+ };
1989
+
1990
+ // ── ./src/extractors/prdiff ──
1991
+ __factories["./src/extractors/prdiff"] = function(module, exports) {
1992
+
1993
+ 'use strict';
1994
+
1995
+ /**
1996
+ * Compare signature arrays and produce compact diff markers.
1997
+ * @param {string[]} baseSigs
1998
+ * @param {string[]} currentSigs
1999
+ * @returns {{added:string[], removed:string[], modified:string[]}}
2000
+ */
2001
+ function diffSignatures(baseSigs, currentSigs) {
2002
+ const base = new Set(baseSigs || []);
2003
+ const curr = new Set(currentSigs || []);
2004
+
2005
+ const added = [...curr].filter((s) => !base.has(s));
2006
+ const removed = [...base].filter((s) => !curr.has(s));
2007
+
2008
+ const byName = (arr) => {
2009
+ const m = new Map();
2010
+ for (const s of arr) {
2011
+ const n = extractName(s);
2012
+ if (!n) continue;
2013
+ if (!m.has(n)) m.set(n, []);
2014
+ m.get(n).push(s);
2015
+ }
2016
+ return m;
2017
+ };
2018
+
2019
+ const aBy = byName(added);
2020
+ const rBy = byName(removed);
2021
+ const modified = [];
2022
+
2023
+ for (const [name] of aBy) {
2024
+ if (rBy.has(name)) modified.push(name);
2025
+ }
2026
+
2027
+ return { added, removed, modified };
2028
+ }
2029
+
2030
+ function extractName(sig) {
2031
+ if (!sig) return '';
2032
+ const t = sig.trim();
2033
+ const m = t.match(/(?:def|function|func|class|interface|trait|struct|enum|record)?\s*([A-Za-z_][A-Za-z0-9_]*)\s*(?:\(|$)/);
2034
+ return m ? m[1] : '';
2035
+ }
2036
+
2037
+ module.exports = { diffSignatures, extractName };
2038
+
2039
+ };
2040
+
1895
2041
  // ── ./src/format/cache ──
1896
2042
  __factories["./src/format/cache"] = function(module, exports) {
1897
2043
 
@@ -5445,6 +5591,29 @@ function ensureDir(filePath) {
5445
5591
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
5446
5592
  }
5447
5593
 
5594
+ // ---------------------------------------------------------------------------
5595
+ // Resolve output path for a given adapter
5596
+ // ---------------------------------------------------------------------------
5597
+ // Takes config.output into account for the copilot adapter.
5598
+ // Returns the full path where output should be written.
5599
+ function resolveAdapterPath(adapter, cwd, config) {
5600
+ config = config || {};
5601
+
5602
+ // Copilot uses config.output if available, otherwise default
5603
+ if (adapter === 'copilot') {
5604
+ return config.output
5605
+ ? path.join(cwd, config.output)
5606
+ : path.join(cwd, '.github', 'copilot-instructions.md');
5607
+ }
5608
+
5609
+ // Fixed paths for other adapters
5610
+ if (adapter === 'claude') return path.join(cwd, 'CLAUDE.md');
5611
+ if (adapter === 'cursor') return path.join(cwd, '.cursorrules');
5612
+ if (adapter === 'windsurf') return path.join(cwd, '.windsurfrules');
5613
+
5614
+ return null;
5615
+ }
5616
+
5448
5617
  // ---------------------------------------------------------------------------
5449
5618
  // Cache output writer (v0.8)
5450
5619
  // ---------------------------------------------------------------------------
@@ -5460,14 +5629,15 @@ function writeCacheOutput(content, cwd) {
5460
5629
  }
5461
5630
  }
5462
5631
 
5463
- function writeOutputs(content, targets, cwd) {
5632
+ function writeOutputs(content, targets, cwd, config) {
5633
+ config = config || {};
5464
5634
  // v3.0+: adapter-aware output targets
5465
5635
  const ADAPTER_TARGETS = new Set(['openai', 'gemini']);
5466
5636
 
5467
5637
  const targetMap = {
5468
- copilot: path.join(cwd, '.github', 'copilot-instructions.md'),
5469
- cursor: path.join(cwd, '.cursorrules'),
5470
- windsurf: path.join(cwd, '.windsurfrules'),
5638
+ copilot: resolveAdapterPath('copilot', cwd, config),
5639
+ cursor: resolveAdapterPath('cursor', cwd, config),
5640
+ windsurf: resolveAdapterPath('windsurf', cwd, config),
5471
5641
  };
5472
5642
 
5473
5643
  for (const target of targets) {
@@ -5709,7 +5879,7 @@ function runPerModuleStrategy(cwd, config, fileEntries, inputTokenTotal) {
5709
5879
  overviewLines.push('> For cross-module questions load both files.');
5710
5880
  const overviewContent = overviewLines.join('\n') + '\n';
5711
5881
  const primaryTargets = (config.outputs || ['copilot']).filter((t) => t !== 'claude');
5712
- writeOutputs(overviewContent, primaryTargets, cwd);
5882
+ writeOutputs(overviewContent, primaryTargets, cwd, config);
5713
5883
 
5714
5884
  const overviewTokens = estimateTokens(overviewContent);
5715
5885
  console.warn(`[sigmap] per-module: overview ~${overviewTokens} tokens (always-on), modules total ~${totalOut} tokens (on-demand)`);
@@ -5728,7 +5898,7 @@ function runHotColdStrategy(cwd, config, fileEntries, recentFiles, inputTokenTot
5728
5898
  ? formatOutput(hotEntries, cwd, false, config, null)
5729
5899
  : '<!-- Generated by SigMap — no recently changed files -->\n';
5730
5900
  const primaryTargets = (config.outputs || ['copilot']).filter((t) => t !== 'claude');
5731
- writeOutputs(hotContent, primaryTargets, cwd);
5901
+ writeOutputs(hotContent, primaryTargets, cwd, config);
5732
5902
  const hotTokens = estimateTokens(hotContent);
5733
5903
 
5734
5904
  // Cold → .github/context-cold.md (MCP reads this on demand)
@@ -5831,7 +6001,7 @@ function runDiff(cwd, config, stagedOnly, baseRef) {
5831
6001
  const diffSection = baseRef ? buildDiffSectionFromBase(cwd, baseRef, fileEntries, config) : [];
5832
6002
  const content = formatOutput(fileEntries, cwd, routingEnabled, config, { diffSection });
5833
6003
  const finalTokens = estimateTokens(content);
5834
- writeOutputs(content, config.outputs, cwd);
6004
+ writeOutputs(content, config.outputs, cwd, config);
5835
6005
 
5836
6006
  const scope = baseRef ? `diff-vs-${baseRef}` : (stagedOnly ? 'staged' : 'diff');
5837
6007
  console.warn(`[sigmap] ${scope} files: ${fileEntries.length}, diff tokens: ~${finalTokens}`);
@@ -5940,7 +6110,7 @@ function runGenerate(cwd, config, reportMode, reportJson = false) {
5940
6110
  const finalTokens = estimateTokens(content);
5941
6111
  const formatIdx = process.argv.indexOf('--format');
5942
6112
  const formatValue = formatIdx >= 0 ? process.argv[formatIdx + 1] : (config.format || 'default');
5943
- writeOutputs(content, config.outputs, cwd);
6113
+ writeOutputs(content, config.outputs, cwd, config);
5944
6114
  if (formatValue === 'cache') writeCacheOutput(content, cwd);
5945
6115
  result = { inputTokenTotal, finalTokens, fileCount: beforeCount, droppedCount };
5946
6116
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "3.0.1",
3
+ "version": "3.1.0-alpha.1",
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": {
@@ -25,7 +25,9 @@
25
25
  "report": "node gen-context.js --report",
26
26
  "health": "node gen-context.js --health",
27
27
  "map": "node gen-project-map.js",
28
- "mcp": "node gen-context.js --mcp"
28
+ "mcp": "node gen-context.js --mcp",
29
+ "build:binary": "node scripts/build-binary.mjs",
30
+ "verify:binary": "node scripts/verify-binary.mjs"
29
31
  },
30
32
  "files": [
31
33
  "gen-context.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-cli",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "SigMap CLI wrapper — thin adapter for programmatic CLI invocation",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-core",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [