sigmap 8.25.0 → 8.26.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 +24 -0
- package/README.md +13 -1
- package/gen-context.js +248 -2
- package/llms-full.txt +4 -2
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/mcp/server.js +1 -1
- package/src/skills/skills.js +182 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,30 @@ Format: [Semantic Versioning](https://semver.org/)
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [8.26.1] — 2026-08-18
|
|
14
|
+
|
|
15
|
+
Patch release — **"Trust Quick Wins II" (G1)**: the extraction layer gets the same honesty treatment the benchmarks got in v8.19.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **`KNOWN_LIMITATIONS.md` + README extraction-honesty tiers (#520, PR #521):** one page stating plainly what each extractor tier can and cannot do — Tier 1 AST (Python via `python_ast.py`, regex fallback without `python3`), Tier 2 anchored regex (the 11 `withAnchor` brace languages, doc hints on 6), Tier 3 pattern/heuristic (the rest + generic fallback) — plus the truncation caps (25 signatures/file, 8 members/block) and what falls off, the nested-paren regex gap (the stated G4/D1 precondition), and the honest `verify` implication: a real symbol missing from the index flags `fake-symbol` at **medium** confidence — a conservative false positive, never a silent pass. README carries a compact "Extraction honesty" tier label linking the page. A 6-check guard test drift-locks the doc's counts to `version.json` and cross-checks the Tier-2 count against the extractors that actually call `withAnchor`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- 6 new guard checks (133 test files). No runtime code changed; the npm tarball is unaffected.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [8.26.0] — 2026-08-18
|
|
26
|
+
|
|
27
|
+
Minor release — **"Agent Economy III" (v8.26, F3+F4)**: the optimal SigMap usage loop ships as installable agent skills in every client's native format — completing the Agent Economy pillar (F1 budget → F2 tune → F3+F4 skills).
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **`sigmap skills` (#517, PR #518):** new `src/skills/skills.js` — two canonical, deterministic skill documents: **sigmap-usage-maximizer** (F3 — the spend-minimizing loop: `ask` before any file read · `get_lines` for anchored ranges instead of whole files · `verify_suggestion` before trusting generated code · `squeeze` any big log/trace/JSON · checkpoint via `create_checkpoint`/`note` · check `get_budget` and, near budget, summarize-then-drop; token accounting reads the F1 ledger — no LLM calls) and **sigmap-config-optimizer** (the F2 playbook: `tune` → review the evidence-naming reasons → `tune --apply` → `validate`). Multi-client installer mirroring the `mcp/install.js` CLIENTS pattern: Claude Code (`.claude/skills/<skill>/SKILL.md`), Cursor (`.cursor/rules/*.mdc`), Windsurf (`.windsurf/rules/*.md`), GitHub Copilot (`.github/instructions/*.instructions.md`), and Codex — a marker-delimited block injected into `AGENTS.md` **above** the `## Auto-generated signatures` marker, so the codex adapter's regeneration preserves it (proven by an end-to-end regeneration test). Human content is never touched; every install is idempotent (`installed`/`updated`/`already`). CLI: `sigmap skills list` and `sigmap skills install [--client <name> | --all] [--json]` — plain `install` wires only clients whose parent artifact exists (the `--setup` only-touch-existing precedent); `--client`/`--all` create. Zero new dependencies.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- 8 new integration tests (132 test files); bundle rebuilt (149 modules).
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
13
37
|
## [8.25.0] — 2026-08-18
|
|
14
38
|
|
|
15
39
|
Minor release — **"Agent Economy II" (v8.25, F2)**: the discovery stack becomes a config optimizer — one command that recommends (and can apply) the config a repo actually needs.
|
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ Ask → Rank → Context → Validate → Judge → Learn
|
|
|
122
122
|
|
|
123
123
|
<!--SM:benchmarkBlock-->
|
|
124
124
|
```
|
|
125
|
-
Benchmark : sigmap-v8.
|
|
125
|
+
Benchmark : sigmap-v8.26-main (21 repositories, including R language)
|
|
126
126
|
Date : 2026-08-17
|
|
127
127
|
|
|
128
128
|
Hit@5 : 82.2% (grep-agent baseline 44.0% — 1.87× lift)
|
|
@@ -397,6 +397,18 @@ All implemented with zero external dependencies.
|
|
|
397
397
|
|
|
398
398
|
[Full language table →](https://sigmap.io/guide/generalization.html)
|
|
399
399
|
|
|
400
|
+
### Extraction honesty
|
|
401
|
+
|
|
402
|
+
Not all 33 languages get the same depth — and we say so plainly:
|
|
403
|
+
|
|
404
|
+
| Tier | Coverage | Depth |
|
|
405
|
+
|------|----------|-------|
|
|
406
|
+
| **AST** | Python (`python3` on PATH; regex fallback without) | Full parse |
|
|
407
|
+
| **Anchored regex** | 11 brace languages (JS, TS, Go, Rust, Java, Kotlin, Swift, PHP, Scala, Dart, C#) | Declarations + `:start-end` line anchors; doc hints on 6 |
|
|
408
|
+
| **Pattern/heuristic** | Everything else + generic fallback | Line-oriented patterns |
|
|
409
|
+
|
|
410
|
+
Caps: 25 signatures/file · 8 members/block. Full details, known regex gaps, and what they mean for `verify`: **[KNOWN_LIMITATIONS.md](KNOWN_LIMITATIONS.md)**.
|
|
411
|
+
|
|
400
412
|
---
|
|
401
413
|
|
|
402
414
|
## License
|
package/gen-context.js
CHANGED
|
@@ -15195,7 +15195,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
15195
15195
|
|
|
15196
15196
|
const SERVER_INFO = {
|
|
15197
15197
|
name: 'sigmap',
|
|
15198
|
-
version: '8.
|
|
15198
|
+
version: '8.26.1',
|
|
15199
15199
|
description: 'SigMap MCP server — code signatures on demand',
|
|
15200
15200
|
};
|
|
15201
15201
|
|
|
@@ -18089,6 +18089,192 @@ __factories["./src/session/notes"] = function(module, exports) {
|
|
|
18089
18089
|
|
|
18090
18090
|
};
|
|
18091
18091
|
|
|
18092
|
+
// ── ./src/skills/skills ──
|
|
18093
|
+
__factories["./src/skills/skills"] = function(module, exports) {
|
|
18094
|
+
|
|
18095
|
+
/**
|
|
18096
|
+
* sigmap skills — canonical agent playbooks + multi-client installer (F3+F4, #517).
|
|
18097
|
+
*
|
|
18098
|
+
* Two deterministic skill documents (the spend-minimizing usage loop and the
|
|
18099
|
+
* config-optimizer playbook) emitted in each client's native skill/rules
|
|
18100
|
+
* format — the `mcp/install.js` CLIENTS pattern applied to skills. File-based
|
|
18101
|
+
* clients get sigmap-namespaced files we own outright; AGENTS.md (codex) gets
|
|
18102
|
+
* a marker-delimited block inserted ABOVE the `## Auto-generated signatures`
|
|
18103
|
+
* marker, since the codex adapter preserves content above it and replaces
|
|
18104
|
+
* everything below. Idempotent; human content is never touched.
|
|
18105
|
+
*/
|
|
18106
|
+
|
|
18107
|
+
const fs = require('fs');
|
|
18108
|
+
const path = require('path');
|
|
18109
|
+
|
|
18110
|
+
const START = '<!-- sigmap-skills:start -->';
|
|
18111
|
+
const END = '<!-- sigmap-skills:end -->';
|
|
18112
|
+
const SIGNATURES_MARKER = '## Auto-generated signatures';
|
|
18113
|
+
|
|
18114
|
+
const SKILLS = {
|
|
18115
|
+
'sigmap-usage-maximizer': {
|
|
18116
|
+
title: 'SigMap usage maximizer',
|
|
18117
|
+
description: 'Spend-minimizing loop for agents in a SigMap-indexed repo: ask before reading, read ranges, verify before trusting, squeeze big pastes, checkpoint, watch the budget.',
|
|
18118
|
+
body: [
|
|
18119
|
+
'Follow this loop before any file exploration in a repo with SigMap installed.',
|
|
18120
|
+
'',
|
|
18121
|
+
'1. **Ask before reading.** `sigmap ask "<task>"` (or the `query_context` MCP tool) ranks the relevant files as ~hundreds of tokens of signatures instead of thousands of raw-file tokens. Never open files to "look around".',
|
|
18122
|
+
'2. **Read ranges, not files.** Use the `get_lines` MCP tool with the `:start-end` line anchors carried on every signature to pull only the lines you need.',
|
|
18123
|
+
'3. **Ground before trusting.** Run the `verify_suggestion` MCP tool (or `sigmap verify-ai-output`) on generated code before applying it — it flags fabricated files, imports, symbols, and npm scripts against the live index.',
|
|
18124
|
+
'4. **Squeeze big pastes.** Any stack trace, CI/build log, or JSON blob goes through `sigmap squeeze` (or the `squeeze_output` MCP tool) before it enters context — the signal survives, the noise does not.',
|
|
18125
|
+
'5. **Checkpoint progress.** Use the `create_checkpoint` MCP tool or `sigmap note "<decision>"` so a follow-up session resumes without re-deriving state.',
|
|
18126
|
+
'6. **Watch the budget.** Check the `get_budget` MCP tool or `sigmap budget` (estimates from SigMap\'s local ledger — no LLM calls). Near the budget: summarize-then-drop older context instead of accumulating, and prefer terse output.',
|
|
18127
|
+
].join('\n'),
|
|
18128
|
+
},
|
|
18129
|
+
'sigmap-config-optimizer': {
|
|
18130
|
+
title: 'SigMap config optimizer',
|
|
18131
|
+
description: 'Playbook for getting a correct SigMap config on any repo: detect with sigmap tune, review the per-change reasons, apply, validate.',
|
|
18132
|
+
body: [
|
|
18133
|
+
'Playbook for configuring SigMap on a new or misconfigured repo.',
|
|
18134
|
+
'',
|
|
18135
|
+
'1. **Detect.** `sigmap tune` prints a recommended config diff — srcDirs pin, monorepo mode, adapters, excludes, budget — with one evidence-naming reason per change. Read-only.',
|
|
18136
|
+
'2. **Review.** Every reason names its evidence (workspace marker, client artifact, vendored dir, file-count estimate). Explicit user config is never proposed against.',
|
|
18137
|
+
'3. **Apply.** `sigmap tune --apply` merges the recommendations into `gen-context.config.json`, preserving every existing key. Idempotent — a second `tune` proposes nothing.',
|
|
18138
|
+
'4. **Validate.** `sigmap validate` confirms the generated context matches the config; `sigmap doctor` diagnoses anything left.',
|
|
18139
|
+
].join('\n'),
|
|
18140
|
+
},
|
|
18141
|
+
};
|
|
18142
|
+
|
|
18143
|
+
// Client registry — parent = artifact whose presence means "user uses this
|
|
18144
|
+
// client" (the `--setup` only-touch-existing rule for plain `skills install`).
|
|
18145
|
+
const SKILL_CLIENTS = {
|
|
18146
|
+
claude: { label: 'Claude Code', parent: ['.claude'],
|
|
18147
|
+
target: (cwd, skill) => path.join(cwd, '.claude', 'skills', skill, 'SKILL.md') },
|
|
18148
|
+
cursor: { label: 'Cursor', parent: ['.cursor'],
|
|
18149
|
+
target: (cwd, skill) => path.join(cwd, '.cursor', 'rules', `${skill}.mdc`) },
|
|
18150
|
+
windsurf: { label: 'Windsurf', parent: ['.windsurf'],
|
|
18151
|
+
target: (cwd, skill) => path.join(cwd, '.windsurf', 'rules', `${skill}.md`) },
|
|
18152
|
+
copilot: { label: 'GitHub Copilot', parent: ['.github'],
|
|
18153
|
+
target: (cwd, skill) => path.join(cwd, '.github', 'instructions', `${skill}.instructions.md`) },
|
|
18154
|
+
codex: { label: 'Codex CLI (AGENTS.md)', parent: ['AGENTS.md'],
|
|
18155
|
+
target: (cwd) => path.join(cwd, 'AGENTS.md'), inject: true },
|
|
18156
|
+
};
|
|
18157
|
+
|
|
18158
|
+
function _footer(version) {
|
|
18159
|
+
const ver = version ? ` v${version}` : '';
|
|
18160
|
+
return `<sub>Generated by SigMap${ver} · run \`sigmap skills install\` to refresh.</sub>`;
|
|
18161
|
+
}
|
|
18162
|
+
|
|
18163
|
+
/** Render one skill's client-specific file content. */
|
|
18164
|
+
function renderSkill(client, skillName, version) {
|
|
18165
|
+
const skill = SKILLS[skillName];
|
|
18166
|
+
const body = `# ${skill.title}\n\n${skill.body}\n\n${_footer(version)}\n`;
|
|
18167
|
+
if (client === 'claude') {
|
|
18168
|
+
return `---\nname: ${skillName}\ndescription: ${skill.description}\n---\n\n${body}`;
|
|
18169
|
+
}
|
|
18170
|
+
if (client === 'cursor') {
|
|
18171
|
+
return `---\ndescription: ${skill.description}\nalwaysApply: false\n---\n\n${body}`;
|
|
18172
|
+
}
|
|
18173
|
+
if (client === 'copilot') {
|
|
18174
|
+
return `---\napplyTo: "**"\n---\n\n${body}`;
|
|
18175
|
+
}
|
|
18176
|
+
return body; // windsurf: plain markdown
|
|
18177
|
+
}
|
|
18178
|
+
|
|
18179
|
+
/** Render the combined AGENTS.md block (both skills, marker-delimited). */
|
|
18180
|
+
function renderAgentsBlock(version) {
|
|
18181
|
+
const parts = [START, '## SigMap agent skills', ''];
|
|
18182
|
+
for (const name of Object.keys(SKILLS)) {
|
|
18183
|
+
parts.push(`### ${SKILLS[name].title}`, '', SKILLS[name].body, '');
|
|
18184
|
+
}
|
|
18185
|
+
parts.push(_footer(version), END);
|
|
18186
|
+
return parts.join('\n');
|
|
18187
|
+
}
|
|
18188
|
+
|
|
18189
|
+
/**
|
|
18190
|
+
* Inject (or replace) the skills block in AGENTS.md content.
|
|
18191
|
+
* A new block is inserted ABOVE the `## Auto-generated signatures` marker —
|
|
18192
|
+
* the codex adapter's write() preserves content above that marker and
|
|
18193
|
+
* replaces everything below it. Never touches content outside the markers.
|
|
18194
|
+
*/
|
|
18195
|
+
function injectSkillsBlock(existing, block) {
|
|
18196
|
+
const src = String(existing || '');
|
|
18197
|
+
const startIdx = src.indexOf(START);
|
|
18198
|
+
if (startIdx !== -1) {
|
|
18199
|
+
const endIdx = src.indexOf(END, startIdx);
|
|
18200
|
+
if (endIdx !== -1) {
|
|
18201
|
+
return src.slice(0, startIdx) + block + src.slice(endIdx + END.length);
|
|
18202
|
+
}
|
|
18203
|
+
}
|
|
18204
|
+
const sigIdx = src.indexOf(SIGNATURES_MARKER);
|
|
18205
|
+
if (sigIdx !== -1) {
|
|
18206
|
+
return src.slice(0, sigIdx) + block + '\n\n' + src.slice(sigIdx);
|
|
18207
|
+
}
|
|
18208
|
+
if (src.trim() === '') return block + '\n';
|
|
18209
|
+
return src + (src.endsWith('\n') ? '\n' : '\n\n') + block + '\n';
|
|
18210
|
+
}
|
|
18211
|
+
|
|
18212
|
+
function _writeIfChanged(filePath, content) {
|
|
18213
|
+
if (fs.existsSync(filePath)) {
|
|
18214
|
+
const existing = fs.readFileSync(filePath, 'utf8');
|
|
18215
|
+
if (existing === content) return 'already';
|
|
18216
|
+
fs.writeFileSync(filePath, content);
|
|
18217
|
+
return 'updated';
|
|
18218
|
+
}
|
|
18219
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
18220
|
+
fs.writeFileSync(filePath, content);
|
|
18221
|
+
return 'installed';
|
|
18222
|
+
}
|
|
18223
|
+
|
|
18224
|
+
/**
|
|
18225
|
+
* Install both skills for one client.
|
|
18226
|
+
* @returns {{ client, label, results: Array<{skill, path, status}> }}
|
|
18227
|
+
* status: 'installed' | 'updated' | 'already'; or { status:'unknown', valid } for a bad client.
|
|
18228
|
+
*/
|
|
18229
|
+
function installSkills(client, opts = {}) {
|
|
18230
|
+
const spec = SKILL_CLIENTS[client];
|
|
18231
|
+
if (!spec) return { client, status: 'unknown', valid: Object.keys(SKILL_CLIENTS) };
|
|
18232
|
+
const cwd = opts.cwd || process.cwd();
|
|
18233
|
+
const version = opts.version || null;
|
|
18234
|
+
const results = [];
|
|
18235
|
+
|
|
18236
|
+
if (spec.inject) {
|
|
18237
|
+
const filePath = spec.target(cwd);
|
|
18238
|
+
const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
|
|
18239
|
+
const next = injectSkillsBlock(existing, renderAgentsBlock(version));
|
|
18240
|
+
let status;
|
|
18241
|
+
if (next === existing) status = 'already';
|
|
18242
|
+
else { fs.writeFileSync(filePath, next); status = existing ? 'updated' : 'installed'; }
|
|
18243
|
+
results.push({ skill: Object.keys(SKILLS).join(' + '), path: filePath, status });
|
|
18244
|
+
} else {
|
|
18245
|
+
for (const skillName of Object.keys(SKILLS)) {
|
|
18246
|
+
const filePath = spec.target(cwd, skillName);
|
|
18247
|
+
results.push({ skill: skillName, path: filePath, status: _writeIfChanged(filePath, renderSkill(client, skillName, version)) });
|
|
18248
|
+
}
|
|
18249
|
+
}
|
|
18250
|
+
return { client, label: spec.label, results };
|
|
18251
|
+
}
|
|
18252
|
+
|
|
18253
|
+
/** True when the client's parent artifact exists (plain-install eligibility). */
|
|
18254
|
+
function clientPresent(client, cwd) {
|
|
18255
|
+
const spec = SKILL_CLIENTS[client];
|
|
18256
|
+
return !!spec && fs.existsSync(path.join(cwd, ...spec.parent));
|
|
18257
|
+
}
|
|
18258
|
+
|
|
18259
|
+
/** List clients with target paths, presence, and installed state. */
|
|
18260
|
+
function listSkillClients(opts = {}) {
|
|
18261
|
+
const cwd = opts.cwd || process.cwd();
|
|
18262
|
+
return Object.keys(SKILL_CLIENTS).map((client) => {
|
|
18263
|
+
const spec = SKILL_CLIENTS[client];
|
|
18264
|
+
const targets = spec.inject
|
|
18265
|
+
? [spec.target(cwd)]
|
|
18266
|
+
: Object.keys(SKILLS).map((s) => spec.target(cwd, s));
|
|
18267
|
+
const installed = spec.inject
|
|
18268
|
+
? (fs.existsSync(targets[0]) && fs.readFileSync(targets[0], 'utf8').includes(START))
|
|
18269
|
+
: targets.every((t) => fs.existsSync(t));
|
|
18270
|
+
return { client, label: spec.label, present: clientPresent(client, cwd), installed, targets };
|
|
18271
|
+
});
|
|
18272
|
+
}
|
|
18273
|
+
|
|
18274
|
+
module.exports = { SKILLS, SKILL_CLIENTS, renderSkill, renderAgentsBlock, injectSkillsBlock, installSkills, listSkillClients, clientPresent, START, END };
|
|
18275
|
+
|
|
18276
|
+
};
|
|
18277
|
+
|
|
18092
18278
|
// ── ./src/squeeze/cilog ──
|
|
18093
18279
|
__factories["./src/squeeze/cilog"] = function(module, exports) {
|
|
18094
18280
|
|
|
@@ -20621,7 +20807,7 @@ function __tryGit(args, opts = {}) {
|
|
|
20621
20807
|
catch (_) { return ''; }
|
|
20622
20808
|
}
|
|
20623
20809
|
|
|
20624
|
-
const VERSION = '8.
|
|
20810
|
+
const VERSION = '8.26.1';
|
|
20625
20811
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
20626
20812
|
|
|
20627
20813
|
function requireSourceOrBundled(key) {
|
|
@@ -22511,6 +22697,8 @@ Usage:
|
|
|
22511
22697
|
${cmd} redact [file] Mask secrets in a file or stdin (10-pattern bank); redacted text to stdout (--json)
|
|
22512
22698
|
${cmd} tune Recommend config from repo detection — srcDirs, monorepo, adapters, exclude, budget (--json)
|
|
22513
22699
|
${cmd} tune --apply Write the recommendations into gen-context.config.json (merges; your keys preserved)
|
|
22700
|
+
${cmd} skills list List skill clients (Claude/Cursor/Windsurf/Copilot/AGENTS.md) and install state (--json)
|
|
22701
|
+
${cmd} skills install Install the SigMap agent playbooks for detected clients (--client <name> | --all)
|
|
22514
22702
|
${cmd} note "<text>" Append a note to the cross-session decision log
|
|
22515
22703
|
${cmd} note List recent notes (also: note --list <N>)
|
|
22516
22704
|
${cmd} status Show repo state — branch, dirty files, index freshness, notes
|
|
@@ -23940,6 +24128,64 @@ function main() {
|
|
|
23940
24128
|
process.exit(0);
|
|
23941
24129
|
}
|
|
23942
24130
|
|
|
24131
|
+
// `sigmap skills list|install [--client <name>|--all] [--json]` — install the
|
|
24132
|
+
// agent playbooks (usage-maximizer, config-optimizer) in each client's native
|
|
24133
|
+
// skill/rules format. Plain `install` touches only clients whose parent
|
|
24134
|
+
// artifact exists; --client/--all create. Idempotent.
|
|
24135
|
+
if (args[0] === 'skills') {
|
|
24136
|
+
const { installSkills, listSkillClients, SKILL_CLIENTS } = requireSourceOrBundled('./src/skills/skills');
|
|
24137
|
+
const sub = args[1];
|
|
24138
|
+
const jsonOut = args.includes('--json');
|
|
24139
|
+
|
|
24140
|
+
if (sub === 'list' || sub === undefined) {
|
|
24141
|
+
const clients = listSkillClients({ cwd });
|
|
24142
|
+
if (jsonOut) {
|
|
24143
|
+
process.stdout.write(JSON.stringify(clients, null, 2) + '\n');
|
|
24144
|
+
process.exit(0);
|
|
24145
|
+
}
|
|
24146
|
+
console.log('Supported skill clients:\n');
|
|
24147
|
+
for (const c of clients) {
|
|
24148
|
+
const state = c.installed ? 'installed' : (c.present ? 'client present, skills not installed' : 'client not detected');
|
|
24149
|
+
console.log(` ${c.client.padEnd(10)} ${c.label.padEnd(24)} ${state}`);
|
|
24150
|
+
for (const t of c.targets) console.log(` ${path.relative(cwd, t)}`);
|
|
24151
|
+
}
|
|
24152
|
+
console.log('\nInstall with: sigmap skills install [--client <name> | --all]');
|
|
24153
|
+
process.exit(0);
|
|
24154
|
+
}
|
|
24155
|
+
|
|
24156
|
+
if (sub === 'install') {
|
|
24157
|
+
const cIdx = args.indexOf('--client');
|
|
24158
|
+
const one = cIdx !== -1 ? args[cIdx + 1] : null;
|
|
24159
|
+
let targets;
|
|
24160
|
+
if (one) targets = [one];
|
|
24161
|
+
else if (args.includes('--all')) targets = Object.keys(SKILL_CLIENTS);
|
|
24162
|
+
else targets = listSkillClients({ cwd }).filter((c) => c.present).map((c) => c.client);
|
|
24163
|
+
if (targets.length === 0) {
|
|
24164
|
+
console.error('[sigmap] skills: no clients detected — use --client <name> or --all (see: sigmap skills list)');
|
|
24165
|
+
process.exit(1);
|
|
24166
|
+
}
|
|
24167
|
+
const out = targets.map((c) => installSkills(c, { cwd, version: VERSION }));
|
|
24168
|
+
const bad = out.find((r) => r.status === 'unknown');
|
|
24169
|
+
if (bad) {
|
|
24170
|
+
console.error(`[sigmap] skills: unknown client "${bad.client}" — valid: ${bad.valid.join(', ')}`);
|
|
24171
|
+
process.exit(1);
|
|
24172
|
+
}
|
|
24173
|
+
if (jsonOut) {
|
|
24174
|
+
process.stdout.write(JSON.stringify(out, null, 2) + '\n');
|
|
24175
|
+
process.exit(0);
|
|
24176
|
+
}
|
|
24177
|
+
for (const r of out) {
|
|
24178
|
+
for (const res of r.results) {
|
|
24179
|
+
console.log(` ${r.client.padEnd(10)} ${res.status.padEnd(10)} ${path.relative(cwd, res.path)}`);
|
|
24180
|
+
}
|
|
24181
|
+
}
|
|
24182
|
+
process.exit(0);
|
|
24183
|
+
}
|
|
24184
|
+
|
|
24185
|
+
console.error('[sigmap] usage: sigmap skills [list | install [--client <name> | --all]] [--json]');
|
|
24186
|
+
process.exit(1);
|
|
24187
|
+
}
|
|
24188
|
+
|
|
23943
24189
|
// `sigmap note "<text>"` — append to the cross-session decision log.
|
|
23944
24190
|
// With no text, lists recent notes (also `note --list [N]`).
|
|
23945
24191
|
// `sigmap memory` — one view over the cross-session stores in .context/.
|
package/llms-full.txt
CHANGED
|
@@ -11,13 +11,13 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.26.1 | Benchmark: sigmap-v8.26-main (2026-08-17)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
20
|
+
## Core metrics (benchmark: sigmap-v8.26-main, 2026-08-17)
|
|
21
21
|
|
|
22
22
|
| Metric | Without SigMap | With SigMap |
|
|
23
23
|
|--------|----------------|-------------|
|
|
@@ -130,6 +130,8 @@ sigmap budget --budget <tokens> One-off budget override (config: sessio
|
|
|
130
130
|
sigmap redact [file] Mask secrets in a file or stdin (10-pattern bank); redacted text to stdout (--json)
|
|
131
131
|
sigmap tune Recommend config from repo detection — srcDirs, monorepo, adapters, exclude, budget (--json)
|
|
132
132
|
sigmap tune --apply Write the recommendations into gen-context.config.json (merges; your keys preserved)
|
|
133
|
+
sigmap skills list List skill clients (Claude/Cursor/Windsurf/Copilot/AGENTS.md) and install state (--json)
|
|
134
|
+
sigmap skills install Install the SigMap agent playbooks for detected clients (--client <name> | --all)
|
|
133
135
|
sigmap note "<text>" Append a note to the cross-session decision log
|
|
134
136
|
sigmap note List recent notes (also: note --list <N>)
|
|
135
137
|
sigmap status Show repo state — branch, dirty files, index freshness, notes
|
package/llms.txt
CHANGED
|
@@ -11,7 +11,7 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.26.1 | Benchmark: sigmap-v8.26-main (2026-08-17)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
@@ -23,7 +23,7 @@ Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
|
23
23
|
- No blast-radius awareness before editing a hub file — `--impact` shows every file a change touches.
|
|
24
24
|
- Pasted stack traces, CI logs, and JSON bloat the prompt — `squeeze` minimizes them and enriches the top frame from the symbol index.
|
|
25
25
|
|
|
26
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
26
|
+
## Core metrics (benchmark: sigmap-v8.26-main, 2026-08-17)
|
|
27
27
|
|
|
28
28
|
- hit@5 retrieval: 82.2% vs 44.0% single-shot grep baseline (1.87× lift)
|
|
29
29
|
- Token reduction: 96.8% average across benchmark repos
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigmap",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.26.1",
|
|
4
4
|
"description": "The deterministic, verifiable grounding layer for AI code work — a zero-dependency signature-and-evidence map that grounds Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP agents against your real code (repo + installed libraries) so they stop hallucinating files, imports & APIs. Runs offline via npx; byte-stable output; ~97% token reduction as proof.",
|
|
5
5
|
"main": "packages/core/index.js",
|
|
6
6
|
"exports": {
|
package/src/mcp/server.js
CHANGED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* sigmap skills — canonical agent playbooks + multi-client installer (F3+F4, #517).
|
|
5
|
+
*
|
|
6
|
+
* Two deterministic skill documents (the spend-minimizing usage loop and the
|
|
7
|
+
* config-optimizer playbook) emitted in each client's native skill/rules
|
|
8
|
+
* format — the `mcp/install.js` CLIENTS pattern applied to skills. File-based
|
|
9
|
+
* clients get sigmap-namespaced files we own outright; AGENTS.md (codex) gets
|
|
10
|
+
* a marker-delimited block inserted ABOVE the `## Auto-generated signatures`
|
|
11
|
+
* marker, since the codex adapter preserves content above it and replaces
|
|
12
|
+
* everything below. Idempotent; human content is never touched.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const START = '<!-- sigmap-skills:start -->';
|
|
19
|
+
const END = '<!-- sigmap-skills:end -->';
|
|
20
|
+
const SIGNATURES_MARKER = '## Auto-generated signatures';
|
|
21
|
+
|
|
22
|
+
const SKILLS = {
|
|
23
|
+
'sigmap-usage-maximizer': {
|
|
24
|
+
title: 'SigMap usage maximizer',
|
|
25
|
+
description: 'Spend-minimizing loop for agents in a SigMap-indexed repo: ask before reading, read ranges, verify before trusting, squeeze big pastes, checkpoint, watch the budget.',
|
|
26
|
+
body: [
|
|
27
|
+
'Follow this loop before any file exploration in a repo with SigMap installed.',
|
|
28
|
+
'',
|
|
29
|
+
'1. **Ask before reading.** `sigmap ask "<task>"` (or the `query_context` MCP tool) ranks the relevant files as ~hundreds of tokens of signatures instead of thousands of raw-file tokens. Never open files to "look around".',
|
|
30
|
+
'2. **Read ranges, not files.** Use the `get_lines` MCP tool with the `:start-end` line anchors carried on every signature to pull only the lines you need.',
|
|
31
|
+
'3. **Ground before trusting.** Run the `verify_suggestion` MCP tool (or `sigmap verify-ai-output`) on generated code before applying it — it flags fabricated files, imports, symbols, and npm scripts against the live index.',
|
|
32
|
+
'4. **Squeeze big pastes.** Any stack trace, CI/build log, or JSON blob goes through `sigmap squeeze` (or the `squeeze_output` MCP tool) before it enters context — the signal survives, the noise does not.',
|
|
33
|
+
'5. **Checkpoint progress.** Use the `create_checkpoint` MCP tool or `sigmap note "<decision>"` so a follow-up session resumes without re-deriving state.',
|
|
34
|
+
'6. **Watch the budget.** Check the `get_budget` MCP tool or `sigmap budget` (estimates from SigMap\'s local ledger — no LLM calls). Near the budget: summarize-then-drop older context instead of accumulating, and prefer terse output.',
|
|
35
|
+
].join('\n'),
|
|
36
|
+
},
|
|
37
|
+
'sigmap-config-optimizer': {
|
|
38
|
+
title: 'SigMap config optimizer',
|
|
39
|
+
description: 'Playbook for getting a correct SigMap config on any repo: detect with sigmap tune, review the per-change reasons, apply, validate.',
|
|
40
|
+
body: [
|
|
41
|
+
'Playbook for configuring SigMap on a new or misconfigured repo.',
|
|
42
|
+
'',
|
|
43
|
+
'1. **Detect.** `sigmap tune` prints a recommended config diff — srcDirs pin, monorepo mode, adapters, excludes, budget — with one evidence-naming reason per change. Read-only.',
|
|
44
|
+
'2. **Review.** Every reason names its evidence (workspace marker, client artifact, vendored dir, file-count estimate). Explicit user config is never proposed against.',
|
|
45
|
+
'3. **Apply.** `sigmap tune --apply` merges the recommendations into `gen-context.config.json`, preserving every existing key. Idempotent — a second `tune` proposes nothing.',
|
|
46
|
+
'4. **Validate.** `sigmap validate` confirms the generated context matches the config; `sigmap doctor` diagnoses anything left.',
|
|
47
|
+
].join('\n'),
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Client registry — parent = artifact whose presence means "user uses this
|
|
52
|
+
// client" (the `--setup` only-touch-existing rule for plain `skills install`).
|
|
53
|
+
const SKILL_CLIENTS = {
|
|
54
|
+
claude: { label: 'Claude Code', parent: ['.claude'],
|
|
55
|
+
target: (cwd, skill) => path.join(cwd, '.claude', 'skills', skill, 'SKILL.md') },
|
|
56
|
+
cursor: { label: 'Cursor', parent: ['.cursor'],
|
|
57
|
+
target: (cwd, skill) => path.join(cwd, '.cursor', 'rules', `${skill}.mdc`) },
|
|
58
|
+
windsurf: { label: 'Windsurf', parent: ['.windsurf'],
|
|
59
|
+
target: (cwd, skill) => path.join(cwd, '.windsurf', 'rules', `${skill}.md`) },
|
|
60
|
+
copilot: { label: 'GitHub Copilot', parent: ['.github'],
|
|
61
|
+
target: (cwd, skill) => path.join(cwd, '.github', 'instructions', `${skill}.instructions.md`) },
|
|
62
|
+
codex: { label: 'Codex CLI (AGENTS.md)', parent: ['AGENTS.md'],
|
|
63
|
+
target: (cwd) => path.join(cwd, 'AGENTS.md'), inject: true },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function _footer(version) {
|
|
67
|
+
const ver = version ? ` v${version}` : '';
|
|
68
|
+
return `<sub>Generated by SigMap${ver} · run \`sigmap skills install\` to refresh.</sub>`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Render one skill's client-specific file content. */
|
|
72
|
+
function renderSkill(client, skillName, version) {
|
|
73
|
+
const skill = SKILLS[skillName];
|
|
74
|
+
const body = `# ${skill.title}\n\n${skill.body}\n\n${_footer(version)}\n`;
|
|
75
|
+
if (client === 'claude') {
|
|
76
|
+
return `---\nname: ${skillName}\ndescription: ${skill.description}\n---\n\n${body}`;
|
|
77
|
+
}
|
|
78
|
+
if (client === 'cursor') {
|
|
79
|
+
return `---\ndescription: ${skill.description}\nalwaysApply: false\n---\n\n${body}`;
|
|
80
|
+
}
|
|
81
|
+
if (client === 'copilot') {
|
|
82
|
+
return `---\napplyTo: "**"\n---\n\n${body}`;
|
|
83
|
+
}
|
|
84
|
+
return body; // windsurf: plain markdown
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Render the combined AGENTS.md block (both skills, marker-delimited). */
|
|
88
|
+
function renderAgentsBlock(version) {
|
|
89
|
+
const parts = [START, '## SigMap agent skills', ''];
|
|
90
|
+
for (const name of Object.keys(SKILLS)) {
|
|
91
|
+
parts.push(`### ${SKILLS[name].title}`, '', SKILLS[name].body, '');
|
|
92
|
+
}
|
|
93
|
+
parts.push(_footer(version), END);
|
|
94
|
+
return parts.join('\n');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Inject (or replace) the skills block in AGENTS.md content.
|
|
99
|
+
* A new block is inserted ABOVE the `## Auto-generated signatures` marker —
|
|
100
|
+
* the codex adapter's write() preserves content above that marker and
|
|
101
|
+
* replaces everything below it. Never touches content outside the markers.
|
|
102
|
+
*/
|
|
103
|
+
function injectSkillsBlock(existing, block) {
|
|
104
|
+
const src = String(existing || '');
|
|
105
|
+
const startIdx = src.indexOf(START);
|
|
106
|
+
if (startIdx !== -1) {
|
|
107
|
+
const endIdx = src.indexOf(END, startIdx);
|
|
108
|
+
if (endIdx !== -1) {
|
|
109
|
+
return src.slice(0, startIdx) + block + src.slice(endIdx + END.length);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const sigIdx = src.indexOf(SIGNATURES_MARKER);
|
|
113
|
+
if (sigIdx !== -1) {
|
|
114
|
+
return src.slice(0, sigIdx) + block + '\n\n' + src.slice(sigIdx);
|
|
115
|
+
}
|
|
116
|
+
if (src.trim() === '') return block + '\n';
|
|
117
|
+
return src + (src.endsWith('\n') ? '\n' : '\n\n') + block + '\n';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function _writeIfChanged(filePath, content) {
|
|
121
|
+
if (fs.existsSync(filePath)) {
|
|
122
|
+
const existing = fs.readFileSync(filePath, 'utf8');
|
|
123
|
+
if (existing === content) return 'already';
|
|
124
|
+
fs.writeFileSync(filePath, content);
|
|
125
|
+
return 'updated';
|
|
126
|
+
}
|
|
127
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
128
|
+
fs.writeFileSync(filePath, content);
|
|
129
|
+
return 'installed';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Install both skills for one client.
|
|
134
|
+
* @returns {{ client, label, results: Array<{skill, path, status}> }}
|
|
135
|
+
* status: 'installed' | 'updated' | 'already'; or { status:'unknown', valid } for a bad client.
|
|
136
|
+
*/
|
|
137
|
+
function installSkills(client, opts = {}) {
|
|
138
|
+
const spec = SKILL_CLIENTS[client];
|
|
139
|
+
if (!spec) return { client, status: 'unknown', valid: Object.keys(SKILL_CLIENTS) };
|
|
140
|
+
const cwd = opts.cwd || process.cwd();
|
|
141
|
+
const version = opts.version || null;
|
|
142
|
+
const results = [];
|
|
143
|
+
|
|
144
|
+
if (spec.inject) {
|
|
145
|
+
const filePath = spec.target(cwd);
|
|
146
|
+
const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
|
|
147
|
+
const next = injectSkillsBlock(existing, renderAgentsBlock(version));
|
|
148
|
+
let status;
|
|
149
|
+
if (next === existing) status = 'already';
|
|
150
|
+
else { fs.writeFileSync(filePath, next); status = existing ? 'updated' : 'installed'; }
|
|
151
|
+
results.push({ skill: Object.keys(SKILLS).join(' + '), path: filePath, status });
|
|
152
|
+
} else {
|
|
153
|
+
for (const skillName of Object.keys(SKILLS)) {
|
|
154
|
+
const filePath = spec.target(cwd, skillName);
|
|
155
|
+
results.push({ skill: skillName, path: filePath, status: _writeIfChanged(filePath, renderSkill(client, skillName, version)) });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return { client, label: spec.label, results };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** True when the client's parent artifact exists (plain-install eligibility). */
|
|
162
|
+
function clientPresent(client, cwd) {
|
|
163
|
+
const spec = SKILL_CLIENTS[client];
|
|
164
|
+
return !!spec && fs.existsSync(path.join(cwd, ...spec.parent));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** List clients with target paths, presence, and installed state. */
|
|
168
|
+
function listSkillClients(opts = {}) {
|
|
169
|
+
const cwd = opts.cwd || process.cwd();
|
|
170
|
+
return Object.keys(SKILL_CLIENTS).map((client) => {
|
|
171
|
+
const spec = SKILL_CLIENTS[client];
|
|
172
|
+
const targets = spec.inject
|
|
173
|
+
? [spec.target(cwd)]
|
|
174
|
+
: Object.keys(SKILLS).map((s) => spec.target(cwd, s));
|
|
175
|
+
const installed = spec.inject
|
|
176
|
+
? (fs.existsSync(targets[0]) && fs.readFileSync(targets[0], 'utf8').includes(START))
|
|
177
|
+
: targets.every((t) => fs.existsSync(t));
|
|
178
|
+
return { client, label: spec.label, present: clientPresent(client, cwd), installed, targets };
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = { SKILLS, SKILL_CLIENTS, renderSkill, renderAgentsBlock, injectSkillsBlock, installSkills, listSkillClients, clientPresent, START, END };
|