@skill-map/spec 0.12.0 → 0.13.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 +48 -1923
- package/architecture.md +24 -7
- package/cli-contract.md +51 -7
- package/conformance/README.md +2 -2
- package/conformance/cases/plugin-missing-ui-rejected.json +17 -0
- package/conformance/coverage.md +13 -4
- package/conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/plugin.json +6 -0
- package/conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/provider.js +31 -0
- package/conformance/fixtures/plugin-missing-ui/notes/example.md +8 -0
- package/db-schema.md +1 -1
- package/index.json +14 -9
- package/package.json +1 -1
- package/plugin-author-guide.md +21 -11
- package/schemas/api/rest-envelope.schema.json +170 -0
- package/schemas/extensions/provider.schema.json +61 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,1984 +1,109 @@
|
|
|
1
1
|
# Spec changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
4
|
-
|
|
5
|
-
### Minor Changes
|
|
6
|
-
|
|
7
|
-
- 68c5e28: Step 14.1 — `sm serve` + Hono BFF skeleton
|
|
8
|
-
|
|
9
|
-
Adds `src/server/` Hono workspace with single-port wiring (`/api/health` real,
|
|
10
|
-
`/api/*` 404 stubs, `/ws` no-op upgrade, `serveStatic` + SPA fallback). Real
|
|
11
|
-
`ServeCommand` extracted from stub at `cli/commands/stubs.ts` to dedicated
|
|
12
|
-
`cli/commands/serve.ts` extending `SmCommand`. Loopback-only through v0.6.0
|
|
13
|
-
(Decision #119). Boot resilient to missing DB — `/api/health` reports
|
|
14
|
-
`db: 'missing'`. Spec `cli-contract.md` `sm serve` row updated to full flag
|
|
15
|
-
set; new `### Server` subsection (skeleton — endpoints fill at 14.2).
|
|
16
|
-
|
|
17
|
-
**Files added (server)**
|
|
18
|
-
|
|
19
|
-
- `src/server/index.ts` — `createServer(opts)` factory returning `ServerHandle` (`{ address, close }`); resolves spec version, builds the Hono app, instantiates a `WebSocketServer({ noServer: true })`, hands both to `@hono/node-server`'s `serve({ websocket: { server: wss } })`. Closing the http server tears down the WSS automatically (node-server registers the `'close'` hook internally); `close()` calls `wss.close()` defensively for forward-compatibility.
|
|
20
|
-
- `src/server/app.ts` — Hono app construction. Routes registered in single-port order: `GET /api/health` → real, `ALL /api/*` → structured 404, `GET /ws` via the injected `attachWs` registrar, static handler + SPA fallback. Global `app.onError` formats every uncaught throw into the error envelope.
|
|
21
|
-
- `src/server/options.ts` — `IServerOptions` + `validateServerOptions(input)`. Loopback-only check for `--dev-cors`; port range check `[0, 65535]`; scope validation.
|
|
22
|
-
- `src/server/paths.ts` — `resolveDefaultUiDist(ctx)` walks upwards from cwd looking for `ui/dist/browser/index.html`; `resolveExplicitUiDist(ctx, raw)` honours absolute paths for `--ui-dist`.
|
|
23
|
-
- `src/server/static.ts` — wraps `@hono/node-server`'s `serveStatic` middleware with the SPA-fallback layer (`serveStatic` does not do SPA fallback — it `next()`s on miss, which is exactly the seam we hook into). Absolute `root` paths work on POSIX in node-server@2.0.1 (verified runtime probe — implementation is `path.join(root, filename)`); the `.d.ts` "Absolute paths are not supported" string is stale (upstream issue honojs/node-server#187 still open). When the bundle is missing (`uiDist === null`), a tiny placeholder middleware serves the boot-without-bundle hint at `/`.
|
|
24
|
-
- `src/server/ws.ts` — `noopWebSocketRoute(app)` registers `GET /ws` via the official `upgradeWebSocket` re-exported from `@hono/node-server@2.x`. The 14.1 handler closes the connection in `onOpen` with code 1000 + reason `'no broadcaster yet'`. 14.4 swaps this registrar for the chokidar-fed broadcaster — one-line change in `index.ts`, `app.ts` untouched.
|
|
25
|
-
- `src/server/health.ts` — `buildHealth(deps)` synchronous; `resolveSpecVersion()` async, called once at boot.
|
|
26
|
-
- `src/server/i18n/server.texts.ts` — `SERVER_TEXTS` catalog.
|
|
27
|
-
|
|
28
|
-
**Files added (CLI)**
|
|
29
|
-
|
|
30
|
-
- `src/cli/commands/serve.ts` — `ServeCommand extends SmCommand`. Parses flags, validates, calls `createServer`, registers SIGINT/SIGTERM handlers, awaits shutdown. `protected emitElapsed = false` (long-running daemon).
|
|
31
|
-
- `src/cli/i18n/serve.texts.ts` — `SERVE_TEXTS` catalog.
|
|
32
|
-
|
|
33
|
-
**Tests added (15)**
|
|
34
|
-
|
|
35
|
-
- `src/test/server-boot.test.ts` (7) — boot/listen/health JSON, custom port, db state present/missing, structured 404, /ws upgrade closes with code 1000 + reason 'no broadcaster yet' (uses real `WebSocket` client from `ws`), shutdown < 1s + idempotent close, inline placeholder when uiDist null.
|
|
36
|
-
- `src/test/server-flags.test.ts` (6) — host non-loopback + dev-cors rejection, port out-of-range, port non-numeric, scope invalid, ui-dist missing, ui-dist with valid bundle.
|
|
37
|
-
- `src/test/server-db-missing.test.ts` (2) — `--db <missing>` exits 5, default boots cleanly with db:missing.
|
|
38
|
-
|
|
39
|
-
**Files edited**
|
|
40
|
-
|
|
41
|
-
- `src/cli/commands/stubs.ts` — `ServeCommand` removed; replaced with a comment pointer.
|
|
42
|
-
- `src/cli/entry.ts` — registers the new `ServeCommand`.
|
|
43
|
-
- `src/package.json` — adds `hono@4.12.16`, `@hono/node-server@2.0.1`, `ws@8.20.0` (deps); `@types/ws@8.18.1` (dev). All exact-pinned per AGENTS.md.
|
|
44
|
-
- `spec/cli-contract.md` — `sm serve` row replaced with the full 14.1 flag set; new `#### Server` subsection (stability: experimental).
|
|
45
|
-
- `spec/CHANGELOG.md` — `[Unreleased]` `### Minor` entry for the spec change.
|
|
46
|
-
- `spec/index.json` — regenerated (40 files hashed; previous head was 215 lines).
|
|
47
|
-
|
|
48
|
-
**Decisions during implementation (flag for orchestrator)**
|
|
49
|
-
|
|
50
|
-
- WebSocket support uses `@hono/node-server@2.x`'s built-in `upgradeWebSocket` plus the canonical `ws@8.20.0` Node WebSocket library, per the official README pattern. The previously-published `@hono/node-ws` adapter was deprecated when node-server@2.0 absorbed WebSocket support natively (PR honojs/node-server#328). The 14.4 broadcaster will replace `noopWebSocketRoute` with its own one-line registrar — no API churn between 14.1 and 14.4.
|
|
51
|
-
- The `/api/*` catch-all is wired with `app.all('/api/*', ...)` BEFORE the `/ws` registrar and the static handler so neither a `serveStatic` filesystem hit nor the SPA fallback can shadow API endpoints. `/ws` is registered BEFORE the static handler so a literal `/ws` path on disk inside `uiDist` cannot accidentally shadow the upgrade route.
|
|
52
|
-
- `serveStatic` from `@hono/node-server/serve-static` accepts absolute root paths at runtime on POSIX (its implementation is `path.join(root, filename)`); the `.d.ts` string saying otherwise is documentation drift, not a runtime contract. Verified with a runtime probe and cross-referenced against the open upstream issue (honojs/node-server#187). Documented in `src/server/static.ts` so future contributors don't re-investigate.
|
|
53
|
-
|
|
54
|
-
## 0.11.0
|
|
55
|
-
|
|
56
|
-
### Minor Changes
|
|
57
|
-
|
|
58
|
-
- f8fca25: Step 10 prep — job artifacts move into the database (B2: content-addressed storage)
|
|
59
|
-
|
|
60
|
-
Removes the on-disk `.skill-map/jobs/<id>.md` and `.skill-map/reports/<id>.json` artifacts from the spec. Rendered job content and report payloads now live in the kernel database; the filesystem is no longer a normative layer of the job lifecycle. Pre-1.0 minor breaking per `versioning.md` § Pre-1.0.
|
|
61
|
-
|
|
62
|
-
**Why**: every other piece of operational state (`state_summaries`, `state_enrichments`, `state_plugin_kvs`, `node_enrichments`) already lives in the DB. Jobs and reports were the only outliers — and being outliers cost real complexity (orphan-file detection, partial backups, two-source-of-truth GC). With B2 (content-addressed dedup keyed on the existing `content_hash`), retries / `--force` / cross-node fan-out reuse a single content blob, so DB-only does not blow up storage on heavy users.
|
|
63
|
-
|
|
64
|
-
**Schema changes**
|
|
65
|
-
|
|
66
|
-
- New table `state_job_contents` (`content_hash` PK, `content` TEXT, `created_at`). Content-addressed: multiple `state_jobs` rows MAY reference the same row.
|
|
67
|
-
- `state_jobs.file_path` removed. The rendered content is fetched via `state_job_contents.content_hash` join.
|
|
68
|
-
- `state_executions.report_path` → `state_executions.report_json` (TEXT, parsed-JSON-on-read per the `_json` naming convention).
|
|
69
|
-
|
|
70
|
-
**Schema-typed contract changes**
|
|
71
|
-
|
|
72
|
-
- `Job.filePath` removed.
|
|
73
|
-
- `ExecutionRecord.reportPath` → `ExecutionRecord.report` (object/null — the parsed JSON payload).
|
|
74
|
-
- `Job.failureReason` and `ExecutionRecord.failureReason` enums: `job-file-missing` → `content-missing` (defensive failure-mode label for DB corruption where a job row outlives its content row; the runtime invariant should keep this state unreachable).
|
|
75
|
-
- `history-stats.schema.json` `perFailureReason` mirrors the rename.
|
|
76
|
-
|
|
77
|
-
**CLI surface changes**
|
|
78
|
-
|
|
79
|
-
- `sm job preview <id>` now prints the rendered content from `state_job_contents` (no file). Same output, different source.
|
|
80
|
-
- `sm job claim --json` is the contracted Skill-agent handover: returns `{id, nonce, content}` so the agent can call `sm record` afterwards with the nonce in hand. The plain-stdout form (id only) is preserved for legacy scripts.
|
|
81
|
-
- `sm record --report <path-or-dash>` accepts a file path OR `-` (stdin); the kernel reads the payload and stores it inline in `report_json`. The on-disk report file becomes operationally ephemeral — implementations SHOULD remove it after the kernel acknowledges the callback (courtesy GC, not normative).
|
|
82
|
-
- `sm job prune --orphan-files` removed. Replaced by automatic `state_job_contents` GC inside `sm job prune`: deletes terminal jobs past retention, then collects orphan content rows in the same transaction.
|
|
83
|
-
- `sm doctor` checks change accordingly: drops the "orphan job files / orphan DB rows pointing at missing files" pair; adds two DB-internal checks (`state_jobs` rows whose `content_hash` is missing from `state_job_contents`; `state_job_contents` rows referenced by zero `state_jobs` rows).
|
|
84
|
-
|
|
85
|
-
**Event stream changes**
|
|
86
|
-
|
|
87
|
-
- `job.spawning.data.jobFilePath` → `job.spawning.data.contentHash` (references the content row instead of a file path).
|
|
88
|
-
- `job.callback.received.data.reportPath` and `job.completed.data.reportPath` → `executionId` (references the `state_executions` row that holds the inline report payload). Reports are intentionally NOT inlined in events — consumers query the row when they need the body.
|
|
89
|
-
|
|
90
|
-
**Architecture changes**
|
|
91
|
-
|
|
92
|
-
- `RunnerPort.run(jobFilePath, options)` → `run(jobContent, options)` returning `{report, ...}` instead of `{reportPath, ...}`. Path-based reporting is no longer part of the port contract. Runners that need an actual file (the canonical case being `claude -p` reading stdin from a path) materialize a temp file inside `run()` and remove it after spawn — temp files are operational, not normative.
|
|
93
|
-
|
|
94
|
-
**Atomicity edge cases consolidated**
|
|
95
|
-
|
|
96
|
-
`spec/job-lifecycle.md` §Atomicity edge cases drops the four file-related rows. Two new DB-internal cases take their place: `state_jobs` row outliving its `state_job_contents` row (failure: `content-missing`); `state_job_contents` row with no live job references (GC straggler — `sm job prune` collects).
|
|
97
|
-
|
|
98
|
-
**Files touched**
|
|
99
|
-
|
|
100
|
-
- `spec/db-schema.md` — new `state_job_contents` section, `state_jobs.file_path` removed, `state_executions.report_path` → `report_json`, integrity section rewritten.
|
|
101
|
-
- `spec/job-lifecycle.md` — §Submit step 8 rewritten (DB store), §Atomic claim documents `--json` shape, §Atomicity edge cases consolidated, §Record callback rewritten for `--report` path-or-stdin semantics, §Retention extended to cover `state_job_contents` GC, failure-reason rename.
|
|
102
|
-
- `spec/cli-contract.md` — `sm job preview` / `sm job claim` / `sm job prune` rows updated, `sm job prune --orphan-files` row removed, `sm record` block rewritten with `<path-or-dash>`, `sm doctor` integrity bullets updated.
|
|
103
|
-
- `spec/prompt-preamble.md` — §How the kernel applies step 5 rewritten (DB store, no file).
|
|
104
|
-
- `spec/architecture.md` — §`RunnerPort` operations + reference impls updated for content-string + parsed-report shape.
|
|
105
|
-
- `spec/job-events.md` — `job.spawning` / `job.callback.received` / `job.completed` payloads changed.
|
|
106
|
-
- `spec/conformance/README.md` + `coverage.md` — `preamble-bitwise-match` references updated to `sm job preview` stdout.
|
|
107
|
-
- `spec/schemas/job.schema.json` — `filePath` property removed, failure-reason enum rename.
|
|
108
|
-
- `spec/schemas/execution-record.schema.json` — `reportPath` → `report` (object/null), failure-reason enum rename.
|
|
109
|
-
- `spec/schemas/history-stats.schema.json` — `perFailureReason` enum rename.
|
|
110
|
-
- `spec/index.json` regenerated (40 files hashed); `npm run spec:check` green.
|
|
111
|
-
|
|
112
|
-
**Migration for consumers**
|
|
113
|
-
|
|
114
|
-
- Any consumer reading `state_jobs.file_path` or `state_executions.report_path` reads from the renamed columns / DB-only paths instead.
|
|
115
|
-
- Any tooling that watched `.skill-map/jobs/*.md` or `.skill-map/reports/*.json` needs to query the DB or call the relevant `sm` verb.
|
|
116
|
-
- `--orphan-files` flag callers must drop the flag; `sm job prune` already does the equivalent automatically.
|
|
117
|
-
- Skill agents drain via `sm job claim --json` (id + nonce + content together) instead of `sm job claim` + reading a file.
|
|
118
|
-
|
|
119
|
-
**Out of scope**
|
|
120
|
-
|
|
121
|
-
The reference impl side of this (migration that adds `state_job_contents` + drops `state_jobs.file_path`; storage-adapter helpers; runtime piping in `ClaudeCliRunner` for the temp-file dance) lands in follow-up changesets under `@skill-map/cli`. The spec change above is self-contained: shipping it alone changes nothing at runtime, but unblocks the implementation phases.
|
|
122
|
-
|
|
123
|
-
## 0.10.0
|
|
124
|
-
|
|
125
|
-
### Minor Changes
|
|
126
|
-
|
|
127
|
-
- f8a7125: Open `Node.kind` to any Provider-declared string (Phase A — spec only).
|
|
128
|
-
|
|
129
|
-
The kernel always documented `IProvider.kinds` as "open by design" so future Cursor / Obsidian / Roo Providers can declare their own kinds. The spec, however, had three layers underneath that closed it back to the original five-value Claude Provider catalog (`skill` / `agent` / `command` / `hook` / `note`):
|
|
130
|
-
|
|
131
|
-
- `node.schema.json#/properties/kind` carried `enum: [<5 values>]` — AJV-rejected anything else.
|
|
132
|
-
- `db-schema.md` § `scan_nodes` and § `state_summaries` mandated `CHECK in (<5 values>)` SQL constraints.
|
|
133
|
-
- `extensions/action.schema.json#/.../filter/kind` had the same closed list for the per-action applicability filter.
|
|
134
|
-
|
|
135
|
-
This phase opens the spec end:
|
|
136
|
-
|
|
137
|
-
- `node.schema.json#/properties/kind` → `{ "type": "string", "minLength": 1 }` with a description naming the built-in Claude catalog so consumers know the default contract.
|
|
138
|
-
- `db-schema.md` drops both `CHECK in (...)` constraint rows. Both columns stay `TEXT NOT NULL`.
|
|
139
|
-
- `extensions/action.schema.json#/.../filter/kind` widens to `{ items: { "type": "string", "minLength": 1 } }`.
|
|
140
|
-
|
|
141
|
-
The TS side (`Node.kind: string`, `IProvider.classify(...): { kind: string; ... }`, Kysely `TNodeKind = string`) and the SQL `002_open_node_kinds` migration that drops the live CHECK constraints land in follow-up phases under `@skill-map/cli`. Phase A is a safe checkpoint: shipping the spec change alone changes nothing at runtime (the kernel still emits closed kinds, the live DB still enforces the existing CHECK), but it unblocks the rest of the refactor and aligns the source-of-truth artifact with the design intent.
|
|
142
|
-
|
|
143
|
-
Migration for consumers:
|
|
144
|
-
|
|
145
|
-
- Anyone validating an exported `Node` JSON against `node.schema.json` now accepts external-Provider kinds.
|
|
146
|
-
- Any UI / dashboard / script that hard-coded the closed enum elsewhere (filter chips, assertion sets) needs to widen to `string` and accept whatever an enabled Provider declares.
|
|
147
|
-
|
|
148
|
-
Pre-1.0 minor bump per `spec/versioning.md` § Pre-1.0 (this is breaking for consumers that relied on the enum, but pre-1.0 breakings ship as minor).
|
|
149
|
-
|
|
150
|
-
## 0.9.0
|
|
151
|
-
|
|
152
|
-
### Minor Changes
|
|
3
|
+
## 0.13.1
|
|
153
4
|
|
|
154
|
-
|
|
155
|
-
conformance kill-switches.
|
|
156
|
-
|
|
157
|
-
**Pre-1.0 minor bump** per `spec/versioning.md` § Pre-1.0. The schema
|
|
158
|
-
field rename below is technically breaking, but ships as a minor while
|
|
159
|
-
the spec stays `0.Y.Z`.
|
|
160
|
-
|
|
161
|
-
## Spec changes (`@skill-map/spec`)
|
|
162
|
-
|
|
163
|
-
### Breaking — `conformance-case.schema.json`
|
|
5
|
+
### Patch Changes
|
|
164
6
|
|
|
165
|
-
|
|
166
|
-
Finishes the kind rename Detector → Extractor introduced in 0.8.0
|
|
167
|
-
(Phase 2 of the plug-in model overhaul). The previous name was the
|
|
168
|
-
last residue and it never reached a release where anything consumed
|
|
169
|
-
it.
|
|
170
|
-
- **`setup.disableAll{Providers,Extractors,Rules}` are now consumed
|
|
171
|
-
end-to-end.** Until this release the three toggles were declared in
|
|
172
|
-
the schema and accepted by the runner, but the runner never threaded
|
|
173
|
-
them anywhere — the `kernel-empty-boot` case happened to pass
|
|
174
|
-
because its fixture is empty. The runner now injects
|
|
175
|
-
`SKILL_MAP_DISABLE_ALL_{PROVIDERS,EXTRACTORS,RULES}=1` into the
|
|
176
|
-
child process environment when the matching toggle is `true`, and
|
|
177
|
-
the CLI's scan composer drops every extension of the disabled kind
|
|
178
|
-
from the in-scan pipeline regardless of granularity gates and
|
|
179
|
-
`--no-built-ins`. Each toggle now has a docstring on the schema
|
|
180
|
-
property pointing at the env-var convention.
|
|
181
|
-
- `kernel-empty-boot` case updated for the rename.
|
|
182
|
-
- `conformance/README.md` example updated.
|
|
7
|
+
- 103fc1a: Doc revision pass — greenfield framing across READMEs, spec prose, ROADMAP, AGENTS, web, and workspace landing pages.
|
|
183
8
|
|
|
184
|
-
|
|
9
|
+
Pure documentation changes; no normative schema or code changes.
|
|
185
10
|
|
|
186
|
-
-
|
|
187
|
-
refer to "Extractor" everywhere; only the schema field stayed on the
|
|
188
|
-
old name. No prose changes in this bump.
|
|
11
|
+
`@skill-map/spec`:
|
|
189
12
|
|
|
190
|
-
|
|
13
|
+
- `architecture.md` — terse rewrite of §Provider · `kinds` catalog (now lists three required fields: `schema`, `defaultRefreshAction`, `ui`); new §Provider · `ui` presentation section documenting the label / color / colorDark / emoji / icon contract; §Stability section updated for the six extension kinds + Hook trigger set.
|
|
14
|
+
- `plugin-author-guide.md` — Provider section gains the `ui` block documentation alongside `schema` and `defaultRefreshAction`; example manifest carries both icon variants (`pi` + `svg`); migration notes stripped under greenfield framing.
|
|
15
|
+
- `cli-contract.md` — §Server documents the `kindRegistry` envelope field on every payload-bearing variant (sentinel envelopes — health/scan/graph — exempt).
|
|
16
|
+
- `conformance/coverage.md` — row 18 (`extensions/provider.schema.json`) flipped 🔴 → 🟡, points at the new `plugin-missing-ui-rejected` case; new §Stability section.
|
|
17
|
+
- `conformance/README.md` — drop "(Phase 5 / A.13 of spec 0.8.0)" historical phase markers.
|
|
18
|
+
- `db-schema.md`, `plugin-author-guide.md` — fix `pisar` typo (Spanish leaked into English) → "are simply overwritten".
|
|
19
|
+
- `CHANGELOG.md` — aggressive sweep: 2114 → 77 lines (96% reduction). Every release gets a 1–3 line greenfield summary. Drops the `Files touched`, `Migration for consumers`, `Out of scope`, `Why`, and per-step decision sub-sections. Drops commit-hash prefixes and `Pre-1.0 minor per versioning.md` boilerplate from every entry. The `[Unreleased]` section preserves the three in-flight Step 14 entries.
|
|
20
|
+
- `conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/{plugin.json,provider.js}` — recovered (lost in the merge from `main` due to `.gitignore` masking gitignored-but-tracked files; `git add -f` brings them back into the index).
|
|
191
21
|
|
|
192
|
-
|
|
22
|
+
`@skill-map/cli`:
|
|
193
23
|
|
|
194
|
-
-
|
|
195
|
-
|
|
196
|
-
the runtime drifted to `loaded` and has now been pulled back so the
|
|
197
|
-
runtime status matches the spec contract. `'disabled'`, the
|
|
198
|
-
semantic pair, was already aligned. Every consumer (`sm plugins
|
|
199
|
-
list`, `sm plugins doctor`, `sm db prune` plugin filter, runtime
|
|
200
|
-
plugin composer) updated. No published consumers exist.
|
|
24
|
+
- `src/README.md` — Status section greenfield (terse: pre-1.0, what's next, what's after); usage examples expanded with `sm serve` + monorepo dev scripts.
|
|
25
|
+
- `src/built-in-plugins/README.md` — drop the contradictory "empty on purpose" framing; document the actual built-in inventory (Claude Provider + Extractors + Rules + Formatter + `validate-all`).
|
|
201
26
|
|
|
202
|
-
|
|
27
|
+
`@skill-map/testkit`:
|
|
203
28
|
|
|
204
|
-
-
|
|
205
|
-
names, JSDoc, comments, test fixture filenames, test variable
|
|
206
|
-
names) replaced with `Extractor` / `extractor` across the
|
|
207
|
-
production code and test suite. Excludes historical CHANGELOG
|
|
208
|
-
entries, explicit migration notes ("Renamed from Detector"), and
|
|
209
|
-
test data strings whose semantics are independent of the kind
|
|
210
|
-
name (e.g. `'@FooDetector'` in trigger normalization tests).
|
|
211
|
-
- A residual reference to "an audit reading `ScanResult.issues`" in
|
|
212
|
-
`validate-all`'s docstring rewritten without the removed kind name.
|
|
29
|
+
- `testkit/README.md` — rewrite end-to-end against the actual exported helper names (`runExtractorOnFixture` instead of the long-renamed `runDetectorOnFixture`); align example with the `extract(ctx) → void` Extractor shape and the `enabled` plugin status enum.
|
|
213
30
|
|
|
214
|
-
|
|
31
|
+
Plus `ui/` README rewrite, root README + ES mirror Status / badge bumps + `sm serve` mention + Star History embed, AGENTS.md greenfield BFF section, CONTRIBUTING.md refresh, ROADMAP.md greenfield sweep (`Earlier prose` blocks stripped, decision log reframed without rename history, 14.6+ content preserved), web copy revision (How-it-works section), examples/hello-world rewritten to the Extractor model with passing tests, and the spec/index.json regeneration that goes with it.
|
|
215
32
|
|
|
216
|
-
-
|
|
217
|
-
the env-var kill-switch in `composeScanExtensions` (per kind, all
|
|
218
|
-
three together, and stray-value resilience).
|
|
219
|
-
- `conformance-disable-flags.test.ts` — four new e2e tests pointing
|
|
220
|
-
the runner at a populated fixture with each toggle in turn (and a
|
|
221
|
-
baseline) so a regression in the env-var pipeline shows up
|
|
222
|
-
structurally rather than relying on the empty-fixture coincidence.
|
|
33
|
+
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|
223
34
|
|
|
224
35
|
## [Unreleased]
|
|
225
36
|
|
|
226
37
|
### Minor
|
|
227
38
|
|
|
228
|
-
-
|
|
229
|
-
Step 14.1 promotes `sm serve` from an implementation-defined stub to a
|
|
230
|
-
documented surface. The verb row at `§Verb catalog` › `### Server`
|
|
231
|
-
expands the flag set to the full 14.1 contract: `--port` (default
|
|
232
|
-
`4242`), `--host` (default `127.0.0.1`, loopback-only through v0.6.0),
|
|
233
|
-
`--scope project|global`, `--db <path>`, `--no-built-ins`,
|
|
234
|
-
`--no-plugins`, `--open` / `--no-open`, `--dev-cors`, `--ui-dist
|
|
235
|
-
<path>` (hidden). New `#### Server` subsection documents the
|
|
236
|
-
single-port mandate, the boot-with-missing-DB resilience contract
|
|
237
|
-
(`/api/health` returns `db: 'missing'`), the v14.1 endpoint surface
|
|
238
|
-
(`GET /api/health` real, `ALL /api/*` 404 stubs, `GET /ws` upgrade-only,
|
|
239
|
-
static + SPA fallback), the structured error envelope shape, and the
|
|
240
|
-
flag table. Marked `*(Stability: experimental — locks at v0.6.0.)*` —
|
|
241
|
-
endpoints fill at v14.2, broadcaster at v14.4. Additive minor per
|
|
242
|
-
`versioning.md` § Pre-1.0 (no breaking change to the existing row's
|
|
243
|
-
semantics; the old wording was strictly less specific).
|
|
244
|
-
|
|
245
|
-
### Minor (breaking, pre-1.0)
|
|
246
|
-
|
|
247
|
-
- **`Node.kind` opens to any non-empty string (was the closed enum
|
|
248
|
-
`skill` / `agent` / `command` / `hook` / `note`).** The kernel always
|
|
249
|
-
permitted external Providers — `IProvider.kinds` is documented as
|
|
250
|
-
"open by design" so a future Cursor / Obsidian / Roo Provider can
|
|
251
|
-
declare its own kinds — but the `node.schema.json` enum + the
|
|
252
|
-
`scan_nodes.kind` SQL CHECK + the closed TS `NodeKind` union closed
|
|
253
|
-
three layers underneath. Effects:
|
|
254
|
-
- `node.schema.json#/properties/kind` switches from `enum: [...5
|
|
255
|
-
values]` to `{ "type": "string", "minLength": 1 }`. The
|
|
256
|
-
description still names the built-in Claude Provider catalog so
|
|
257
|
-
consumers know what to expect from the default install.
|
|
258
|
-
- `db-schema.md` drops the `CHECK in (...)` constraint on
|
|
259
|
-
`scan_nodes.kind` and `state_summaries.kind`. Both columns stay
|
|
260
|
-
`TEXT NOT NULL`.
|
|
261
|
-
- `extensions/action.schema.json#/.../filter/kind` (the per-kind
|
|
262
|
-
filter for action applicability) widens the same way: `items:
|
|
263
|
-
{ type: 'string', minLength: 1 }` instead of the closed enum.
|
|
264
|
-
Migration: consumers who validate exported `Node` JSON against
|
|
265
|
-
`node.schema.json` will now accept external-Provider kinds. Any
|
|
266
|
-
consumer that hard-coded the closed enum elsewhere (UI filter chip
|
|
267
|
-
set, scripted assertions) needs to widen to "string". The TS +
|
|
268
|
-
SQL counterpart lands in `@skill-map/cli` (kernel TS contract +
|
|
269
|
-
migration `002_open_node_kinds`).
|
|
270
|
-
- **`conformance-case.schema.json` — rename `setup.disableAllDetectors`
|
|
271
|
-
→ `setup.disableAllExtractors`.** Finishes the kind rename Detector →
|
|
272
|
-
Extractor introduced in 0.8.0 (Phase 2 of the plug-in model
|
|
273
|
-
overhaul). The previous name was a residue from an unfinished sweep
|
|
274
|
-
and never reached a release that consumed it.
|
|
275
|
-
- **`setup.disableAll{Providers,Extractors,Rules}` are now wired
|
|
276
|
-
end-to-end.** Until this release the toggles were declared in the
|
|
277
|
-
schema but the runner threaded them nowhere; the `kernel-empty-boot`
|
|
278
|
-
case happened to pass because its fixture is empty. The runner now
|
|
279
|
-
injects `SKILL_MAP_DISABLE_ALL_{PROVIDERS,EXTRACTORS,RULES}=1` into
|
|
280
|
-
the child process environment per toggle, and the CLI's scan
|
|
281
|
-
composer drops every extension of the disabled kind from the
|
|
282
|
-
in-scan pipeline (overriding granularity gates and `--no-built-ins`).
|
|
283
|
-
Migration: any case JSON authored against the unwired schema needs
|
|
284
|
-
to swap `disableAllDetectors` for `disableAllExtractors`; behaviour
|
|
285
|
-
changes only when the toggles were already `true` (those cases will
|
|
286
|
-
now actually disable the kind, where previously they relied on
|
|
287
|
-
fixture content for the same outcome).
|
|
288
|
-
|
|
289
|
-
### Patch
|
|
290
|
-
|
|
291
|
-
- Updated `conformance/cases/kernel-empty-boot.json` for the field
|
|
292
|
-
rename above.
|
|
293
|
-
- Updated `conformance/README.md` example for the field rename above.
|
|
294
|
-
- Schema docstrings added to each `disableAll*` property documenting
|
|
295
|
-
the env-var convention the runner uses.
|
|
296
|
-
|
|
297
|
-
## 0.8.0
|
|
298
|
-
|
|
299
|
-
### Minor Changes
|
|
300
|
-
|
|
301
|
-
- 6dad772: v0.8.0 — Pre-1.0 stabilization pass.
|
|
302
|
-
|
|
303
|
-
This release combines two coherent pre-1.0 cleanup pieces that
|
|
304
|
-
both push the project closer to v1.0 stability: the cli-architect
|
|
305
|
-
audit review pass and the plugin model overhaul.
|
|
306
|
-
|
|
307
|
-
Pre-1.0 minor bumps per `versioning.md` § Pre-1.0; breaking
|
|
308
|
-
changes allowed within minor while in `0.Y.Z`. No real downstream
|
|
309
|
-
ecosystem exists yet, so the breaking surface costs nothing
|
|
310
|
-
today.
|
|
311
|
-
|
|
312
|
-
## Part 1 — Pre-1.0 audit review pass
|
|
313
|
-
|
|
314
|
-
Pre-1.0 review pass — `cli-architect` audit findings.
|
|
315
|
-
|
|
316
|
-
Internal audit run by the `cli-architect` agent in REVIEW mode
|
|
317
|
-
produced a Critical / High / Medium / Low / Nit catalog. This
|
|
318
|
-
pass bundles the implementation of every actionable finding into
|
|
319
|
-
one unit so the review can be read end-to-end. **Pre-1.0 minor
|
|
320
|
-
bump**: a few breaking surface changes ride along (CLI sub-verb
|
|
321
|
-
split, exit-code enum exposed, plugin loader option). No
|
|
322
|
-
published downstream consumers exist yet.
|
|
323
|
-
|
|
324
|
-
### Spec changes (`@skill-map/spec`)
|
|
325
|
-
|
|
326
|
-
- **`cli-contract.md`** — `sm scan compare-with <dump> [roots...]`
|
|
327
|
-
is now a sub-verb instead of a `--compare-with <path>` flag on
|
|
328
|
-
`sm scan`. Read-only delta report against a saved `ScanResult`
|
|
329
|
-
JSON dump. Read-only — does not modify the DB. Same exit codes
|
|
330
|
-
(`0` empty delta / `1` drift / `2` operational error). Old flag
|
|
331
|
-
form removed.
|
|
332
|
-
- **`cli-contract.md`** — exit-code `2` "Operational error" row
|
|
333
|
-
clarified to mention environment / runtime mismatches (wrong
|
|
334
|
-
Node version, missing native dependency) explicitly. The
|
|
335
|
-
"unhandled exception" catch-all already covered the case; this
|
|
336
|
-
just removes ambiguity for future implementers.
|
|
337
|
-
- **`cli-contract.md`** — new normative section **§Dry-run**
|
|
338
|
-
between §Exit codes and §Verb catalog defining the contract for
|
|
339
|
-
any verb exposing `-n` / `--dry-run`: no observable side effects
|
|
340
|
-
(DB / FS / config / network / spawns), no auto-provisioning of
|
|
341
|
-
scope directories, output mirrors the live mode with explicit
|
|
342
|
-
"would …" framing, exit codes mirror the live mode, dry-run
|
|
343
|
-
MUST short-circuit `--yes` / `--force` confirmation prompts.
|
|
344
|
-
Per-verb opt-in: the flag is not global, verbs that don't
|
|
345
|
-
declare it MUST reject it as an unknown option. Verb catalog
|
|
346
|
-
rows for `sm init`, `sm db reset` (default + `--state` +
|
|
347
|
-
`--hard`), and `sm db restore` amended to declare and describe
|
|
348
|
-
their `--dry-run` previews.
|
|
349
|
-
|
|
350
|
-
### CLI changes (`@skill-map/cli`)
|
|
351
|
-
|
|
352
|
-
#### Critical — kernel & adapter hygiene
|
|
353
|
-
|
|
354
|
-
- **C1 — `runScanInternal` decomposed.** The 290-line monolith in
|
|
355
|
-
`kernel/orchestrator.ts` split into a thin composer + four pure
|
|
356
|
-
functions: `validateRoots`, `indexPriorSnapshot`,
|
|
357
|
-
`walkAndDetect`, `runRules`. Composer is now 89 lines reading
|
|
358
|
-
top-to-bottom through the pipeline phases. Zero behavioural
|
|
359
|
-
change.
|
|
360
|
-
- **C2 — `withSqlite(options, fn)` helper.** Single utility at
|
|
361
|
-
`cli/util/with-sqlite.ts` standardises the open / use / close
|
|
362
|
-
idiom every read-side command was open-coding. Eliminates four
|
|
363
|
-
classes of boilerplate bugs (forgotten close, `autoBackup`
|
|
364
|
-
drift, double-close, missing `try/finally`). Migrated 20 call
|
|
365
|
-
sites across `check`, `export`, `graph`, `history`, `init`,
|
|
366
|
-
`jobs`, `list`, `orphans`, `plugins`, `scan`, `show`, `watch`,
|
|
367
|
-
plus `cli/util/plugin-runtime.ts`. Companion `tryWithSqlite`
|
|
368
|
-
short-circuits when the DB file does not exist, replacing the
|
|
369
|
-
`if (existsSync) { withSqlite(...) }` chain. In `scan.ts` the
|
|
370
|
-
read-prior + persist double-open consolidated into a single
|
|
371
|
-
`withSqlite` callback that brackets read prior → run scan →
|
|
372
|
-
guard → persist when `willPersist`. Saves one migration
|
|
373
|
-
discovery pass + one WAL setup per normal scan (~50–100ms).
|
|
374
|
-
|
|
375
|
-
#### High — UX & contract integrity
|
|
376
|
-
|
|
377
|
-
- **H3 — `--dry-run` semantics unified across `init` / `db reset`
|
|
378
|
-
/ `db restore`.** The new spec §Dry-run codifies the "no
|
|
379
|
-
writes, reads OK" contract; three verbs that did not previously
|
|
380
|
-
expose a preview now do: - `sm init --dry-run` — previews the would-create lines for
|
|
381
|
-
`.skill-map/`, `settings.json`, `settings.local.json`,
|
|
382
|
-
`.skill-mapignore`, the `.gitignore` entries that would be
|
|
383
|
-
appended (deduped against the existing file), the DB
|
|
384
|
-
provisioning, and the first-scan trigger. Honours `--force`
|
|
385
|
-
for the would-overwrite preview. Re-init over an existing
|
|
386
|
-
scope without `--force` still exits 2 (same gate as live). - `sm db reset --dry-run` (default + `--state`) — opens the DB
|
|
387
|
-
read-only, computes the row count per `scan_*` (and `state_*`
|
|
388
|
-
when `--state`) table, and prints them. No `DELETE`
|
|
389
|
-
statements issued. Bypasses the `--state` confirmation prompt
|
|
390
|
-
entirely. - `sm db reset --hard --dry-run` — reports the DB file path and
|
|
391
|
-
size that would be unlinked; missing-file case prints a clear
|
|
392
|
-
no-op line instead of an error. - `sm db restore <src> --dry-run` — validates the source exists
|
|
393
|
-
(still exits 5 if missing), reports the source size and
|
|
394
|
-
whether the target would be created or overwritten, plus the
|
|
395
|
-
WAL / SHM sidecars that would be dropped. Bypasses the
|
|
396
|
-
confirmation prompt.
|
|
397
|
-
Implementation: new helper `previewGitignoreEntries(scopeRoot,
|
|
398
|
-
entries)` in `init.ts` mirrors `ensureGitignoreEntries` parsing
|
|
399
|
-
so the preview tracks the live outcome exactly. Texts moved
|
|
400
|
-
into `cli/i18n/init.texts.ts` and `cli/i18n/db.texts.ts` per
|
|
401
|
-
the N4 pattern. **9 new tests** under `init-cli.test.ts` (5
|
|
402
|
-
cases) and `db-cli.test.ts` (9 cases) cover the previews + the
|
|
403
|
-
spec invariants ("DB file checksum unchanged after dry-run",
|
|
404
|
-
"scope directory absent after dry-run", "source-not-found
|
|
405
|
-
still exits 5", "confirmation prompt skipped under dry-run").
|
|
406
|
-
- **H1 — Centralised exit codes.** New `cli/util/exit-codes.ts`
|
|
407
|
-
exporting `ExitCode` (`Ok` / `Issues` / `Error` / `Duplicate` /
|
|
408
|
-
`NonceMismatch` / `NotFound`) and the type alias `TExitCode`.
|
|
409
|
-
Every `Command#execute()` migrated from numeric literals (123
|
|
410
|
-
sites across 17 files) to the enum. Single source of truth
|
|
411
|
-
aligned with `spec/cli-contract.md` §Exit codes. **Bug fix
|
|
412
|
-
surfaced en passant:** `sm job prune` returned `2` for "DB
|
|
413
|
-
missing" while every other read-side verb returned `5` via
|
|
414
|
-
`assertDbExists`; corrected to use the shared helper and return
|
|
415
|
-
`NotFound`. Companion test updated to expect `5`.
|
|
416
|
-
- **H2 — Plugin loader timeout.** `IPluginLoaderOptions.loadTimeoutMs`
|
|
417
|
-
(default `5000`, exported as `DEFAULT_PLUGIN_IMPORT_TIMEOUT_MS`).
|
|
418
|
-
Each dynamic `import()` now races against a timer; on timeout
|
|
419
|
-
the plugin is reported as `load-error` with a message naming
|
|
420
|
-
the elapsed budget and pointing at top-level side effects as
|
|
421
|
-
the likely cause (network call, infinite loop, large blocking
|
|
422
|
-
work). Without this a plugin with a hanging top-level `await`
|
|
423
|
-
blocks every host CLI command indefinitely.
|
|
424
|
-
- **H4 — `--strict` self-validates `--json` output.** When
|
|
425
|
-
`sm scan --strict --json` is invoked, the produced `ScanResult`
|
|
426
|
-
is validated against `scan-result.schema.json` before stdout.
|
|
427
|
-
Catches the case where a custom detector emits a Link that
|
|
428
|
-
passes the shallow `validateLink` guard but fails the full
|
|
429
|
-
schema, which would silently land in stdout and break a
|
|
430
|
-
downstream `sm scan compare-with -`.
|
|
431
|
-
- **H5 — External-link discrimination uses URL-shape regex.**
|
|
432
|
-
`isExternalUrlLink` was string-matching `http://` / `https://`
|
|
433
|
-
only; any other URL scheme (`mailto:`, `data:`, `file:///`,
|
|
434
|
-
`ftp://`) was silently classified as internal and polluted the
|
|
435
|
-
graph as a fake internal link with `byPath` lookups that always
|
|
436
|
-
missed. Replaced with the RFC 3986 scheme regex
|
|
437
|
-
(`/^[a-z][a-z0-9+\-.]+:/i`), guarding against Windows-style
|
|
438
|
-
absolute paths via the ≥ 2-char scheme constraint.
|
|
439
|
-
- **H6 — Prior snapshot validated under `--strict`.** Both
|
|
440
|
-
`sm scan` and `sm watch`, when run with `--strict`, validate
|
|
441
|
-
the DB-resident `ScanResult` against the spec schema before
|
|
442
|
-
handing it to the orchestrator. A DB corrupted manually or
|
|
443
|
-
mid-rollback used to slip nodes with malformed `bodyHash` /
|
|
444
|
-
`frontmatterHash` into the rename heuristic, where the
|
|
445
|
-
dereference would silently produce spurious matches.
|
|
446
|
-
|
|
447
|
-
#### Medium — surface & extensibility
|
|
448
|
-
|
|
449
|
-
- **M1 — `sm scan compare-with` sub-verb.** New
|
|
450
|
-
`ScanCompareCommand` in `cli/commands/scan-compare.ts`; the
|
|
451
|
-
`--compare-with` flag is removed from `ScanCommand`. The
|
|
452
|
-
sub-verb form structurally rejects flag combos that used to
|
|
453
|
-
require runtime guards (`--changed`, `--no-built-ins`,
|
|
454
|
-
`--allow-empty`, `--watch`): Clipanion rejects them at parse
|
|
455
|
-
time as unknown options.
|
|
456
|
-
- **M2 — `kernel/index.ts` enumerated exports.** Replaced the two
|
|
457
|
-
`export type *` wildcards (from `./types.js` and
|
|
458
|
-
`./ports/index.js`) with explicit named exports. Same set of
|
|
459
|
-
public types — the DTS size and tests confirm parity. Going
|
|
460
|
-
forward, any new domain type or port change requires an
|
|
461
|
-
explicit edit to the barrel, preventing silent surface drift.
|
|
462
|
-
- **M3 — Build hack documented (workaround retained).** Tried to
|
|
463
|
-
replace the post-build `restoreNodeSqliteImports` pass with
|
|
464
|
-
`external: ['node:sqlite']` in `tsup.config.ts`. Esbuild marks
|
|
465
|
-
the specifier as external but still strips the `node:` prefix;
|
|
466
|
-
same outcome with `[/^node:/]` regex and `packages: 'external'`
|
|
467
|
-
(which also externalises real npm deps). Reverted to the
|
|
468
|
-
post-build `replaceAll` pass, with a docstring documenting
|
|
469
|
-
every workaround attempted so the next agent does not repeat
|
|
470
|
-
the spike.
|
|
471
|
-
- **M4 — `tryWithSqlite` helper.** See C2.
|
|
472
|
-
- **M5 — `CamelCasePlugin` trap documented.** Added a
|
|
473
|
-
trap-warning block to `SqliteStorageAdapter`'s docstring:
|
|
474
|
-
`sql.raw` / `sql\`...\``template literals do NOT pass through
|
|
475
|
-
the`CamelCasePlugin`; raw SQL fragments must use snake_case to
|
|
476
|
-
match the migrations.
|
|
477
|
-
- **M6 — Per-extension error reporting.** When the orchestrator
|
|
478
|
-
drops a link emitted with an undeclared kind or an issue with
|
|
479
|
-
an invalid severity, it now emits a `type: 'extension.error'`
|
|
480
|
-
`ProgressEvent` instead of silently swallowing. The CLI
|
|
481
|
-
subscribes via the new `createCliProgressEmitter(stderr)`
|
|
482
|
-
helper and renders those events as `extension.error: <message>`
|
|
483
|
-
on stderr. Plugin authors finally see WHY their link / issue
|
|
484
|
-
disappears from the result. Wired in `scan` (normal +
|
|
485
|
-
compare-with), `watch`, and `init`.
|
|
486
|
-
- **M7 — Type naming convention documented (no rename).** Top-of-
|
|
487
|
-
file docstring in `kernel/types.ts` and a new section in
|
|
488
|
-
`AGENTS.md` describe the four-bucket convention the codebase
|
|
489
|
-
has always implicitly followed: domain types (no prefix,
|
|
490
|
-
mirrors spec schemas), hexagonal ports (`Port` suffix), runtime
|
|
491
|
-
extension contracts (`I` prefix), internal shapes (`I`
|
|
492
|
-
prefix). Mass rename was rejected after a cost-benefit pass —
|
|
493
|
-
naming changes are cheap to write but expensive to review;
|
|
494
|
-
existing names are mostly coherent. The agent base
|
|
495
|
-
(`_plugins/minions/shared/architect.md`) gained a "Naming
|
|
496
|
-
conventions check" sub-section in REVIEW mode so future audits
|
|
497
|
-
reach the same conclusion.
|
|
498
|
-
|
|
499
|
-
#### Low / nit — cleanup
|
|
500
|
-
|
|
501
|
-
- **L1 — `omitModule` JSON replacer precision.** Identifies the
|
|
502
|
-
ESM namespace by `[Symbol.toStringTag] === 'Module'` instead of
|
|
503
|
-
matching every `module` key blindly. A plugin manifest that
|
|
504
|
-
legitimately ships an unrelated `module` field (e.g. a string
|
|
505
|
-
property in `metadata`) is no longer silently dropped from
|
|
506
|
-
`sm plugins list --json` output.
|
|
507
|
-
- **L2 — Stub verbs flagged in `--help`.** Every
|
|
508
|
-
`not-yet-implemented` verb in `cli/commands/stubs.ts` carries a
|
|
509
|
-
`(planned)` suffix on its `description`, surfaced in
|
|
510
|
-
`sm --help`. The `notImplemented` helper now writes
|
|
511
|
-
`<verb>: not yet implemented (planned).` on stderr instead of
|
|
512
|
-
promising a specific Step number — roadmap step numbers shift
|
|
513
|
-
mid-flight, stale promises in `--help` are worse than no
|
|
514
|
-
promise.
|
|
515
|
-
- **L3 — Dead `eslint-disable` removed** from
|
|
516
|
-
`cli/util/plugin-runtime.ts`.
|
|
517
|
-
- **N1 — `Link.source` vs `Link.sources` doc clarified.** Both
|
|
518
|
-
fields now carry inline doc-comments calling out the singular /
|
|
519
|
-
plural naming trap. Spec-frozen, but the ambiguity is the
|
|
520
|
-
easiest way to misread the type for new contributors.
|
|
521
|
-
- **N2 — `sm check` Usage examples expanded.** The `-g/--global`
|
|
522
|
-
and `--db <path>` flags were declared but missing from the
|
|
523
|
-
`Usage.examples` block — asymmetry with `sm scan` and the rest
|
|
524
|
-
of the read-side verbs that ship the same flags. Two examples
|
|
525
|
-
added: `sm check --global` and `sm check --db
|
|
526
|
-
/path/to/skill-map.db`.
|
|
527
|
-
- **N4 — Error / hint strings extracted to `*.texts.ts` modules
|
|
528
|
-
with `{{name}}` template interpolation.** Pre-1.0 is the
|
|
529
|
-
natural moment to seed the pattern before the string set grows.
|
|
530
|
-
The workspace `ui/` already has a sibling layout at
|
|
531
|
-
`ui/src/i18n/` (functions returning template literals); CLI
|
|
532
|
-
takes a deliberately different shape — flat string templates
|
|
533
|
-
with `{{name}}` placeholders, interpolated by a tiny
|
|
534
|
-
`tx(template, vars)` helper. Rationale: the template form is
|
|
535
|
-
**drop-in compatible with Transloco / Mustache / Handlebars**
|
|
536
|
-
(the syntax they all share) so the day this project migrates to
|
|
537
|
-
a real i18n library, the strings move as-is. Functions would
|
|
538
|
-
have to be re-shaped first.
|
|
539
|
-
|
|
540
|
-
Helper at `kernel/util/tx.ts`. Contract:
|
|
541
|
-
|
|
542
|
-
- Every `{{name}}` token MUST have a matching key in the vars
|
|
543
|
-
object — missing key throws (silent fallback hides
|
|
544
|
-
forgotten args in production).
|
|
545
|
-
- `null` / `undefined` values throw — caller coerces
|
|
546
|
-
upstream.
|
|
547
|
-
- Whitespace inside the braces tolerated (`{{ name }}`) so
|
|
548
|
-
long templates wrap cleanly across `+`-joined lines.
|
|
549
|
-
- Plural / conditional logic does NOT live in the template;
|
|
550
|
-
the caller picks `*_singular` vs `*_plural` keys.
|
|
551
|
-
|
|
552
|
-
Files created:
|
|
553
|
-
|
|
554
|
-
- `kernel/util/tx.ts` — the helper itself, with 13 tests in
|
|
555
|
-
`test/tx.test.ts` (single / multi token, whitespace,
|
|
556
|
-
missing / null / undefined keys, identifier shapes, error
|
|
557
|
-
truncation).
|
|
558
|
-
- `kernel/i18n/orchestrator.texts.ts` — frontmatter
|
|
559
|
-
malformed/invalid templates, `extension.error` payloads,
|
|
560
|
-
root validation errors.
|
|
561
|
-
- `kernel/i18n/plugin-loader.texts.ts` — every `load-error` /
|
|
562
|
-
`invalid-manifest` / `incompatible-spec` reason, plus the
|
|
563
|
-
import timeout message.
|
|
564
|
-
- `cli/i18n/scan.texts.ts` — `sm scan` flag-clash / scan
|
|
565
|
-
failure / guard / summary templates, plus the `sm scan
|
|
566
|
-
|
|
567
|
-
compare-with`dump-load errors.
|
|
568
|
-
|
|
569
|
-
-`cli/i18n/watch.texts.ts`—`sm watch`lifecycle templates. -`cli/i18n/init.texts.ts`—`sm init`templates including
|
|
570
|
-
the`--dry-run`previews and the singular/plural pair for
|
|
571
|
-
gitignore updates. -`cli/i18n/db.texts.ts`—`sm db reset`/`sm db restore` templates including their`--dry-run`previews. -`cli/i18n/cli-progress-emitter.texts.ts`— the
|
|
572
|
-
`extension.error: ...` stderr line.
|
|
573
|
-
|
|
574
|
-
String content moved verbatim — every existing test that
|
|
575
|
-
matches on stderr / stdout content keeps passing. Trivial
|
|
576
|
-
single-token strings (`'No issues.\n'`) and rare per-handler
|
|
577
|
-
bespoke phrases stay inline; the pattern is now established
|
|
578
|
-
for whoever wants to migrate them in a follow-up.
|
|
579
|
-
|
|
580
|
-
Note on `ui/` divergence: today the two workspaces use
|
|
581
|
-
different shapes for their text tables (functions in `ui/`,
|
|
582
|
-
templates in `cli/`). Aligning them is a follow-up — the day a
|
|
583
|
-
real i18n library lands, both converge on its native shape.
|
|
584
|
-
The CLI shape is closer to the eventual destination.
|
|
585
|
-
|
|
586
|
-
- **N6 — `TIssueSeverity` aliased to `Severity`.** SQLite schema
|
|
587
|
-
type now reads `type TIssueSeverity = Severity` instead of
|
|
588
|
-
duplicating the union literal. Keeps DB and runtime in
|
|
589
|
-
lock-step if the union ever evolves.
|
|
590
|
-
|
|
591
|
-
### Migrations consolidation (kernel DB)
|
|
592
|
-
|
|
593
|
-
- **`src/migrations/001_initial.sql` + `002_scan_meta.sql`**
|
|
594
|
-
consolidated into a single `001_initial.sql`. Pre-1.0 with no
|
|
595
|
-
released DBs to forward-migrate, the two-file split was a
|
|
596
|
-
historical accident from an incremental shipment. After
|
|
597
|
-
consolidation: same 12 tables, same constraints, same indexes;
|
|
598
|
-
`PRAGMA user_version` of a freshly-initialised DB is now `1`
|
|
599
|
-
instead of `2`. Migration runner is unchanged (it tolerates any
|
|
600
|
-
count of `NNN_*.sql` files).
|
|
601
|
-
|
|
602
|
-
### Test coverage (Part 1)
|
|
603
|
-
|
|
604
|
-
- New tests for H2 (plugin loader timeout — 2 cases),
|
|
605
|
-
M6 (orchestrator `extension.error` emission — 3 cases),
|
|
606
|
-
CLI progress emitter wiring (4 cases). The compare-with suite
|
|
607
|
-
(`scan-compare.test.ts`, 9 cases) was migrated to
|
|
608
|
-
`ScanCompareCommand` and the three flag-clash tests dropped
|
|
609
|
-
(the flags are now structurally absent on the sub-verb). Test
|
|
610
|
-
totals: 479 (start of pass) → 488 (after H2/M6 tests) → 485
|
|
611
|
-
(after the three flag-clash deletions).
|
|
612
|
-
|
|
613
|
-
### Deferred / out of scope
|
|
614
|
-
|
|
615
|
-
The findings below were reviewed but did not warrant code
|
|
616
|
-
changes; each has its own resolution noted alongside.
|
|
617
|
-
|
|
618
|
-
- **L4 — `runScan` / `runScanWithRenames` unification.** Already
|
|
619
|
-
resolved by C1 (both are thin wrappers around
|
|
620
|
-
`runScanInternal`).
|
|
621
|
-
- **L5 — Node-version-guard exit code.** Reviewed against the
|
|
622
|
-
updated exit-code table; existing `2` is correct under
|
|
623
|
-
"operational error / unhandled exception". Spec table got the
|
|
624
|
-
environment-mismatch clarification (above).
|
|
625
|
-
- **L6 — `loadSchemaValidators()` cache.** Already cached at
|
|
626
|
-
module level since Step 5.12.
|
|
627
|
-
- **L7 — `pkg with { type: 'json' }` portability.** Stable in
|
|
628
|
-
Node ≥ 22; `engines.node": ">=24.0"` covers it. No fallback
|
|
629
|
-
needed.
|
|
630
|
-
- **N3 — `compare-with` "dump not found" exit code.** The error
|
|
631
|
-
paths in `ScanCompareCommand` already use the `ExitCode.Error`
|
|
632
|
-
enum (= 2) for dump load failures, matching the spec clause for
|
|
633
|
-
operational errors.
|
|
634
|
-
- **N5 — Exit-code list completeness.** Verified the comment in
|
|
635
|
-
`cli/entry.ts` against `spec/cli-contract.md` §Exit codes —
|
|
636
|
-
identical, no edit needed.
|
|
637
|
-
|
|
638
|
-
## Part 2 — Plugin model overhaul (5-phase implementation)
|
|
639
|
-
|
|
640
|
-
### Summary
|
|
641
|
-
|
|
642
|
-
The plugin model received a comprehensive overhaul before
|
|
643
|
-
stabilizing at v1.0. Plugin kinds total after this bump: **6**
|
|
644
|
-
(Provider, Extractor, Rule, Action, Formatter, Hook). All
|
|
645
|
-
breakings are pre-1.0 minor per `versioning.md` § Pre-1.0.
|
|
646
|
-
|
|
647
|
-
### Phase 1 (commit 7354c26) — Foundation
|
|
648
|
-
|
|
649
|
-
Five sub-phases, additive or pre-1.0 minor breakings:
|
|
650
|
-
|
|
651
|
-
- **A.4** — three-tier frontmatter validation model documented in
|
|
652
|
-
`plugin-author-guide.md` (default permissive + `unknown-field`
|
|
653
|
-
rule + `scan.strict` promote-to-error). Behavior unchanged.
|
|
654
|
-
- **A.5** — plugin id global uniqueness: `directory ==
|
|
655
|
-
manifest.id` rule, new status `id-collision` (sixth),
|
|
656
|
-
validation in boot/scan/doctor. Cross-root collisions block
|
|
657
|
-
both involved plugins; user resolves by renaming.
|
|
658
|
-
- **A.6** — extension ids qualified `<plugin-id>/<ext-id>` in
|
|
659
|
-
registry. Built-ins classified into `claude/*` (4 Claude-
|
|
660
|
-
specific) and `core/*` (7 kernel built-ins) bundles. New
|
|
661
|
-
`Registry.get/find` APIs; `defaultRefreshAction` schema
|
|
662
|
-
requires the qualified pattern; `extension.error` events emit
|
|
663
|
-
qualified ids.
|
|
664
|
-
- **A.10** — optional `applicableKinds` filter on Detector
|
|
665
|
-
manifest; fail-fast skip for non-matching kinds (zero CPU/LLM
|
|
666
|
-
cost); doctor warning for kinds not declared by any installed
|
|
667
|
-
Provider. Empty array invalid; absence preserves apply-to-all
|
|
668
|
-
default.
|
|
669
|
-
- **Granularity** — Built-ins now respect `config_plugins`
|
|
670
|
-
enable/disable via granularity-aware filtering. New
|
|
671
|
-
`IBuiltInBundle` shape with `granularity: 'bundle' |
|
|
672
|
-
'extension'`; `claude` ships as bundle (all-or-nothing), `core`
|
|
673
|
-
as extension (each toggleable). User plugins default to bundle;
|
|
674
|
-
opt in via `granularity` in `plugin.json`. Both plugin ids and
|
|
675
|
-
qualified extension ids accepted as keys in `config_plugins`
|
|
676
|
-
and `settings.json#/plugins` (no schema change needed).
|
|
677
|
-
|
|
678
|
-
550/550 tests pass (+33 vs baseline 517).
|
|
679
|
-
|
|
680
|
-
### Phase 2 (commit ae3eaa6) — Renames
|
|
39
|
+
- **Provider-driven kind presentation + `kindRegistry` envelope.** The Provider extension surface gains a required `kinds[*].ui` block (`label`, `color`, optional `colorDark`, optional `emoji`, optional discriminated icon `{ kind: 'pi', id }` or `{ kind: 'svg', path }`). Every payload-bearing REST envelope variant embeds a required `kindRegistry` field; sentinel envelopes (`health`, `scan`, `graph`) stay exempt. New conformance case `plugin-missing-ui-rejected` locks the loader's behaviour against drop-in Providers that omit the `ui` block.
|
|
681
40
|
|
|
682
|
-
|
|
41
|
+
- **`/api/nodes/:pathB64?include=body` body opt-in.** The single-node detail endpoint accepts `?include=body` to add `item.body: string | null` (read from disk on demand; `null` when the source file is missing or unreadable). Single-node response shape is `{ schemaVersion, kind: 'node', item, links: { incoming, outgoing }, issues }`. The body reader refuses absolute paths and any relative path that resolves outside the scope root.
|
|
683
42
|
|
|
684
|
-
|
|
685
|
-
Method `render(ctx)` → `format(ctx)`; manifest field `format`
|
|
686
|
-
→ `formatId` (TS clash resolution). Same contract: graph →
|
|
687
|
-
string, deterministic-only.
|
|
688
|
-
- **2b (Adapter → Provider)** — New required field
|
|
689
|
-
`explorationDir` on the manifest (e.g. `~/.claude` for the
|
|
690
|
-
Claude Provider). DB schema migrated in-place (column
|
|
691
|
-
`nodes.adapter` → `nodes.provider`, etc.). The
|
|
692
|
-
hexagonal-architecture `RunnerPort.adapter` /
|
|
693
|
-
`StoragePort.adapter` is unchanged.
|
|
694
|
-
- **2c (Audit removed)** — Audit kind removed. The single
|
|
695
|
-
built-in `validate-all` migrated to a Rule (qualified id
|
|
696
|
-
`core/validate-all`, `evaluate(ctx) → Issue[]`). CLI verbs
|
|
697
|
-
`sm audit *` removed; users invoke via `sm check --rules
|
|
698
|
-
core/validate-all`.
|
|
699
|
-
- **2d (Detector → Extractor)** — Method signature changes from
|
|
700
|
-
`detect(ctx) → Link[]` to `extract(ctx) → void` — output flows
|
|
701
|
-
through three ctx callbacks: `emitLink`, `enrichNode`, `store`.
|
|
702
|
-
Built-ins migrated maintain functional parity using `emitLink`.
|
|
703
|
-
Persistence of `enrichNode` deferred to Phase 4 (A.8 stale
|
|
704
|
-
layer); orchestrator buffers in memory today.
|
|
43
|
+
- **`/ws` WebSocket protocol + watcher contract.** `### Server` documents the wire envelope (delegated to `job-events.md` §Common envelope), the event catalog (`scan.started` / `scan.progress` / `scan.completed` plus `extractor.completed` / `rule.completed` / `extension.error` plus the BFF-internal advisories `watcher.started` / `watcher.error`), connection lifecycle, the backpressure rule (4 MiB `bufferedAmount` → close 1009 + unregister), and the loopback-only assumption. `sm serve --no-watcher` flag added.
|
|
705
44
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
### Phase 3 (commit 34f993e) — Schema relocation
|
|
709
|
-
|
|
710
|
-
**A.2** — Per-kind frontmatter schemas relocate from spec to the
|
|
711
|
-
Provider that declares them. Spec keeps only `frontmatter/base`
|
|
712
|
-
(universal).
|
|
713
|
-
|
|
714
|
-
- 5 schemas moved (`git mv`):
|
|
715
|
-
`spec/schemas/frontmatter/{skill,agent,command,hook,note}.schema.json`
|
|
716
|
-
→ built-in Claude Provider's `schemas/` directory. New `$id`:
|
|
717
|
-
`https://skill-map.dev/providers/claude/v1/frontmatter/<kind>`.
|
|
718
|
-
Cross-package `$ref` resolves via the spec base's `$id`
|
|
719
|
-
(`https://skill-map.dev/spec/v0/frontmatter/base.schema.json`);
|
|
720
|
-
AJV resolves by `$id` when both schemas register on the same
|
|
721
|
-
instance.
|
|
722
|
-
- Provider manifest gains a required `kinds` map subsuming three
|
|
723
|
-
former fields: `emits` (now derives from
|
|
724
|
-
`Object.keys(kinds)`), the flat `defaultRefreshAction` map (now
|
|
725
|
-
per-entry inside `kinds[<kind>].defaultRefreshAction`), and the
|
|
726
|
-
new `schema` (path to the per-kind schema relative to the
|
|
727
|
-
provider directory).
|
|
728
|
-
- Built-in Claude Provider migrated: 5 kind entries (skill,
|
|
729
|
-
agent, command, hook, note), each with `schema`, `schemaJson`
|
|
730
|
-
(runtime field, AJV-compiled at load), and qualified
|
|
731
|
-
`defaultRefreshAction` (`claude/summarize-<kind>`).
|
|
732
|
-
- Kernel orchestrator parse phase asks the Provider for the
|
|
733
|
-
schema via `IProviderFrontmatterValidator` (composed by scan
|
|
734
|
-
via `buildProviderFrontmatterValidator`) instead of reading
|
|
735
|
-
from spec/. Flow: validate base → look up provider → validate
|
|
736
|
-
per-kind schema from Provider.
|
|
737
|
-
- `schema-validators.ts` catalog loses the 5 per-kind frontmatter
|
|
738
|
-
entries; only `frontmatter-base` remains kernel-known.
|
|
739
|
-
`plugin-loader`'s `stripFunctionsAndPluginId` now also strips
|
|
740
|
-
`schemaJson` (runtime-only) from each `kinds` entry before
|
|
741
|
-
AJV-validating the manifest.
|
|
742
|
-
- Coverage matrix: 28 → 23 schemas (the 5 per-kind frontmatter
|
|
743
|
-
schemas are now Provider-owned and ship with their own
|
|
744
|
-
conformance suite in Phase 5 / A.13).
|
|
745
|
-
|
|
746
|
-
556/556 cli + 32/32 testkit pass.
|
|
747
|
-
|
|
748
|
-
### Phase 4 (commit e62695f) — Probabilistic infra
|
|
749
|
-
|
|
750
|
-
Five sub-phases, all breaking but allowed in minor pre-1.0:
|
|
751
|
-
|
|
752
|
-
- **4a (A.9)** — fine-grained Extractor cache via new
|
|
753
|
-
`scan_extractor_runs` table. Resolves gap where newly
|
|
754
|
-
registered Extractors silently skipped cached nodes; cache hit
|
|
755
|
-
logic now per-(node, extractor). Uninstalled Extractors cleaned
|
|
756
|
-
(rows + orphan links). Migration in-place.
|
|
757
|
-
- **4b (A.12)** — opt-in `outputSchema` for plugin custom
|
|
758
|
-
storage. Manifest gains `storage.schema` (Mode A) and
|
|
759
|
-
`storage.schemas` (Mode B) for AJV validation of
|
|
760
|
-
`ctx.store.write/.set` calls. Throws on shape violation;
|
|
761
|
-
default absent = permissive.
|
|
762
|
-
- **4c (A.8)** — enrichment layer + stale tracking. New
|
|
763
|
-
`node_enrichments` table persists per-(node, extractor)
|
|
764
|
-
partials separately from author's frontmatter (immutable).
|
|
765
|
-
Probabilistic enrichments track `body_hash_at_enrichment`; scan
|
|
766
|
-
flags `stale=1` on body change (NOT deleted, preserves LLM
|
|
767
|
-
cost). Helper `mergeNodeWithEnrichments` filters stale +
|
|
768
|
-
last-write-wins. New verbs `sm refresh <node>` and
|
|
769
|
-
`sm refresh --stale` (stubs awaiting Step 10).
|
|
770
|
-
- **4d (A.11)** — sixth plugin kind `hook`. Declarative
|
|
771
|
-
subscriber to a curated set of 8 lifecycle events (`scan.*`,
|
|
772
|
-
extractor/rule/action.completed,
|
|
773
|
-
job.spawning/completed/failed). Other events deliberately not
|
|
774
|
-
hookable. Manifest declares `triggers[]` (load-time validated)
|
|
775
|
-
and optional `filter`. Three new kernel events added to
|
|
776
|
-
catalog. Dual-mode (det dispatched in-process; prob deferred to
|
|
777
|
-
Step 10).
|
|
778
|
-
- **4e (A.7)** — `sm check --include-prob` opt-in flag (stub).
|
|
779
|
-
Default `sm check` unchanged: det only, CI-safe. With flag:
|
|
780
|
-
detects prob rules, emits stderr advisory; full dispatch awaits
|
|
781
|
-
Step 10. Combines with `--rules`, `-n`, `--no-plugins`.
|
|
782
|
-
|
|
783
|
-
591/591 cli + 32/32 testkit pass.
|
|
784
|
-
|
|
785
|
-
### Phase 5 (commit 03b5a65) — Conformance + cleanup
|
|
786
|
-
|
|
787
|
-
**A.13** — Conformance fixture relocation:
|
|
788
|
-
|
|
789
|
-
- 3 cases moved (`git mv`): `basic-scan`, `orphan-detection`,
|
|
790
|
-
`rename-high` →
|
|
791
|
-
`src/extensions/providers/claude/conformance/cases/`. 11
|
|
792
|
-
fixture files (`minimal-claude/`, `orphan-{before,after}/`,
|
|
793
|
-
`rename-high-{before,after}/`) moved alongside.
|
|
794
|
-
- New `coverage.md` per-Provider listing the 5 frontmatter
|
|
795
|
-
schemas (skill, agent, command, hook, note) and their cases.
|
|
796
|
-
- New verb `sm conformance run [--scope spec|provider:<id>|all]`.
|
|
797
|
-
Discovery by convention at `<plugin-dir>/conformance/`. The
|
|
798
|
-
existing runner gains optional `fixturesRoot` (default
|
|
799
|
-
`<specRoot>/conformance/fixtures` for compat); tooling using
|
|
800
|
-
the public API of `@skill-map/cli/conformance` keeps working.
|
|
801
|
-
`--json` deferred — reporter shape not yet frozen.
|
|
802
|
-
- Spec keeps only the kernel-agnostic case (`kernel-empty-boot`)
|
|
803
|
-
and the universal preamble fixture. Coverage matrix downgrades
|
|
804
|
-
conservatively (rows that depended on `basic-scan` are now
|
|
805
|
-
partial or missing, with cross-link to the Provider's matrix).
|
|
806
|
-
|
|
807
|
-
ROADMAP cleanup:
|
|
808
|
-
|
|
809
|
-
- The three "Status: target state for v0.8.0 — spec catch-up
|
|
810
|
-
pending" banners on §Plugin system / §Frontmatter standard /
|
|
811
|
-
§Enrichment are removed; prose shifts from future to present
|
|
812
|
-
("kinds from v0.7.0 are renamed" → "were renamed in spec
|
|
813
|
-
0.8.0"; Model B enrichment now describes the shipped
|
|
814
|
-
`node_enrichments` table with `body_hash_at_enrichment` rather
|
|
815
|
-
than "table or column set decided in PR").
|
|
816
|
-
- Decision-log entry for the working session rewritten to
|
|
817
|
-
reflect "shipped" rather than "pending".
|
|
818
|
-
- Last-updated header gains an "implementation" paragraph
|
|
819
|
-
listing the four prior phase commits.
|
|
820
|
-
|
|
821
|
-
593/593 cli + 32/32 testkit pass (+2 vs Phase 4 baseline).
|
|
822
|
-
spec:check green (40 files hashed — down from 53 because the
|
|
823
|
-
Claude-specific cases and fixtures left the spec's hash set).
|
|
824
|
-
|
|
825
|
-
### Breaking changes for plugin authors (Part 2)
|
|
826
|
-
|
|
827
|
-
Manifest renames:
|
|
828
|
-
|
|
829
|
-
- `kind: 'adapter'` → `kind: 'provider'`
|
|
830
|
-
- `kind: 'detector'` → `kind: 'extractor'`
|
|
831
|
-
- `kind: 'renderer'` → `kind: 'formatter'`
|
|
832
|
-
- `kind: 'audit'` removed (migrate to `kind: 'rule'`).
|
|
833
|
-
|
|
834
|
-
Method signatures:
|
|
835
|
-
|
|
836
|
-
- Detector `detect(ctx) → Link[]` → Extractor `extract(ctx) →
|
|
837
|
-
void` (output via `ctx.emitLink` / `ctx.enrichNode` /
|
|
838
|
-
`ctx.store`).
|
|
839
|
-
- Renderer `render(ctx) → string` → Formatter `format(ctx) →
|
|
840
|
-
string`.
|
|
841
|
-
|
|
842
|
-
Manifest fields:
|
|
843
|
-
|
|
844
|
-
- Provider gains required `explorationDir`.
|
|
845
|
-
- Provider's flat `defaultRefreshAction` map replaced by per-kind
|
|
846
|
-
entries inside `kinds[<kind>].defaultRefreshAction` (must
|
|
847
|
-
follow qualified pattern `<plugin-id>/<ext-id>`).
|
|
848
|
-
- Provider's `emits` derives from `Object.keys(kinds)` (the
|
|
849
|
-
manifest field is gone).
|
|
850
|
-
- Provider's per-kind schemas declared via `kinds[<kind>].schema`
|
|
851
|
-
(path relative to provider dir).
|
|
852
|
-
- Renderer's `format` field renamed to `formatId` on the
|
|
853
|
-
Formatter manifest (TS clash resolution).
|
|
854
|
-
- New plugin kind `hook` with `triggers[]` + optional `filter`.
|
|
855
|
-
- Optional `outputSchema` (`storage.schema` / `storage.schemas`)
|
|
856
|
-
for Mode A / Mode B plugin custom storage.
|
|
857
|
-
- Optional `applicableKinds` filter on Extractor manifest.
|
|
858
|
-
|
|
859
|
-
Extension ids:
|
|
860
|
-
|
|
861
|
-
- All extension ids must be qualified
|
|
862
|
-
`<plugin-id>/<extension-id>` (built-ins classified into
|
|
863
|
-
`claude/*` and `core/*`).
|
|
864
|
-
|
|
865
|
-
DB schema:
|
|
866
|
-
|
|
867
|
-
- Two new tables added in-place to `001_initial.sql` (pre-1.0
|
|
868
|
-
consolidation, no production DBs to migrate):
|
|
869
|
-
`scan_extractor_runs` and `node_enrichments`.
|
|
870
|
-
- Column rename `nodes.adapter` → `nodes.provider` (and parallel
|
|
871
|
-
in `result.adapters` → `result.providers`).
|
|
872
|
-
|
|
873
|
-
## Test stats
|
|
874
|
-
|
|
875
|
-
593/593 cli + 32/32 testkit pass (post-Phase 5).
|
|
876
|
-
Two new DB tables (`scan_extractor_runs`, `node_enrichments`)
|
|
877
|
-
added in-place to `001_initial.sql` (pre-1.0 consolidation, no
|
|
878
|
-
production DBs to migrate). The 5 per-kind frontmatter schemas
|
|
879
|
-
relocated from spec/ to the Claude Provider package.
|
|
880
|
-
|
|
881
|
-
## [Unreleased]
|
|
882
|
-
|
|
883
|
-
### Minor Changes
|
|
884
|
-
|
|
885
|
-
- Conformance fixture relocation (Phase 5 / A.13). The conformance suite splits along ownership lines: spec-owned cases (kernel-agnostic, today only `kernel-empty-boot` plus the deferred `preamble-bitwise-match`) keep living under `spec/conformance/`; Provider-owned cases that exercise a Provider's own kind catalog move next to that Provider's manifest, under `<plugin-dir>/conformance/`. The reference impl's Claude Provider now hosts `basic-scan`, `rename-high`, and `orphan-detection` together with their `minimal-claude` / `orphan-{before,after}` / `rename-high-{before,after}` fixtures at `src/extensions/providers/claude/conformance/`. The split mirrors the spec 0.8.0 Phase 3 schema relocation: cases that depend on Claude-specific kinds (`skill`) belong with the Provider that declares the kind, not in the spec. New CLI verb `sm conformance run [--scope spec|provider:<id>|all]` (default `all`) drives both buckets in one invocation; `--scope spec` and `--scope provider:claude` narrow to a single suite for targeted runs and CI matrices. The reference runner gains an optional `fixturesRoot` parameter so cases can resolve their fixtures against the Provider's directory instead of the spec's. `spec/conformance/README.md` updated for the dual-ownership layout (spec-owned + Provider-owned tables, `sm conformance run` documented, runner pseudocode amended). `spec/conformance/coverage.md` retargeted: rows that used to credit `basic-scan` (now Provider-owned) downgrade to `kernel-empty-boot`-only or `🔴 missing` and point to the Provider's coverage file (`src/extensions/providers/claude/conformance/coverage.md`); the rename-heuristic non-schema row notes the Provider ownership. `spec/cli-contract.md` adds a §Conformance subsection under §Verb catalog and adds `sm conformance run` to the elapsed-time §Scope. `spec/architecture.md` opening sentence credits both buckets. Pre-1.0 minor per `versioning.md` § Pre-1.0; breaking only for tooling that hard-codes the previous case paths under `spec/conformance/cases/{basic-scan,rename-high,orphan-detection}.json` — no real ecosystem affected today (the reference impl's runner already migrates).
|
|
886
|
-
|
|
887
|
-
- `sm check` gains `--include-prob` opt-in flag for probabilistic Rule dispatch (Phase 4 / A.7). Default unchanged: deterministic only, CI-safe — same status quo behaviour. With the flag, the verb loads the plugin runtime, finds Rules with `mode === 'probabilistic'` (filtered by `--rules` if set), and emits a stderr advisory naming the skipped rule ids. Full dispatch lands when the job subsystem ships at Step 10; until then the flag is a stub — prob rules never produce issues, never alter the exit code. New companion flag `--async` is reserved for the future encoding (returns job ids without waiting once jobs land); today it is a no-op the advisory mentions. Companion filters `-n <node.path>` and `--rules <ids>` (comma-separated qualified or short ids) added to `sm check` for granular reads — they restrict the persisted-issue list AND filter which prob rules surface in the advisory. Does NOT extend to `sm scan` or `sm list`. Documented in `cli-contract.md` §Browse and `plugin-author-guide.md` §Rules. Pre-1.0 minor per `versioning.md` § Pre-1.0; additive — no consumer breakage.
|
|
888
|
-
|
|
889
|
-
- Sixth plugin kind `hook` added (Phase 4 / A.11). Reacts declaratively to a curated set of 8 lifecycle events — `scan.started`, `scan.completed`, `extractor.completed`, `rule.completed`, `action.completed`, `job.spawning`, `job.completed`, `job.failed`. Other events (per-node `scan.progress`, `model.delta`, `run.*`, `job.claimed`, `job.callback.received`) are deliberately NOT hookable: too verbose, internal to the runner, or covered elsewhere. Manifest declares `triggers[]` (validated against the hookable set; an unknown trigger yields `invalid-manifest` at load time with a directed reason naming the offending trigger and the full hookable list) and an optional `filter` object (top-level field equality match against the event payload; cross-field validation is best-effort in v0.x). Dual-mode: `deterministic` (default) runs `on(ctx)` in-process during the dispatch of the matching event, synchronously between emission and the next pipeline step; `probabilistic` is enqueued as a job (deferred to the job subsystem at Step 10 — probabilistic hooks load but skip dispatch with a stderr advisory until then). Hooks REACT to events; they cannot mutate the pipeline, block emission, or alter outputs. Errors are caught by the dispatcher (logged through `extension.error` with `kind: 'hook-error'`) and never block the main flow. Three new event types added to the catalog so the aggregated Extractor / Rule / Action triggers have a normative shape: `extractor.completed` (one per Extractor, after the full walk), `rule.completed` (one per Rule, after issue validation), `action.completed` (one per Action invocation, after report recording — lands alongside the job subsystem at Step 10). New schema `schemas/extensions/hook.schema.json` (`$id` `https://skill-map.dev/spec/v0/extensions/hook.schema.json`); `schemas/extensions/base.schema.json#/properties/kind/enum` extended with `hook`. Documented in `architecture.md` §Extension kinds (table extended from 5 to 6 rows), §Mode capability matrix (Hook dual-mode), §Hook · curated trigger set (new dedicated section); `plugin-author-guide.md` retitled "## The six extension kinds" with a new Hooks subsection (worked example: Slack notifier on `scan.completed`); `job-events.md` cross-links Hook from each of the 8 hookable triggers, adds the three new aggregated event entries, and updates the experimental tag scope. Coverage matrix grows from 23 to 24 rows. Pre-1.0 minor per `versioning.md` § Pre-1.0; additive — no consumer breakage. Existing extension kinds (`provider`, `extractor`, `rule`, `action`, `formatter`) are untouched.
|
|
890
|
-
|
|
891
|
-
- Enrichment layer formalized (Phase 4 / A.8). New kernel table `node_enrichments(node_path, extractor_id, body_hash_at_enrichment, value_json, stale, enriched_at, is_probabilistic)` stores `ctx.enrichNode(partial)` outputs separately from the author's frontmatter (which remains IMMUTABLE from any Extractor — both deterministic and probabilistic). Per-Extractor attribution is preserved (one row per `(node, extractor)` pair). Probabilistic enrichments track `body_hash_at_enrichment`; when the scan loop sees a body change, those rows are flagged `stale = 1` (NOT deleted, so the LLM cost is preserved). Deterministic enrichments regenerate via the A.9 fine-grained cache and pisar via PRIMARY KEY conflict on the next re-extract — they are never stale-flagged. Read-side helper `mergeNodeWithEnrichments(node, enrichments)` produces a "merged view" by filtering stale rows, sorting by `enriched_at` ASC, and spread-merging onto the author frontmatter (last-write-wins per field). Stale visibility is opt-in (`includeStale: true`). Rules / `sm check` / `sm export` consume `node.frontmatter` directly (deterministic CI-safe baseline); enrichment consumption is opt-in by the caller. New verbs `sm refresh <node>` (granular) and `sm refresh --stale` (batch) re-run Extractors and upsert fresh enrichment rows — STUBBED until the job subsystem ships at Step 10: deterministic Extractors persist for real, probabilistic Extractors emit a stderr advisory and skip without touching their stale rows. Migration `001_initial.sql` updated in place per the pre-1.0 consolidation precedent (no released DBs to forward-migrate). Documented in `db-schema.md` §`node_enrichments`, `architecture.md` §Extractor · enrichment layer, `cli-contract.md` §Scan, and `plugin-author-guide.md` §Extractors. Pre-1.0 minor per `versioning.md` § Pre-1.0; additive — no consumer breakage.
|
|
892
|
-
|
|
893
|
-
- Plugin manifest gains optional `storage.schemas` map (Mode B / dedicated) and `storage.schema` (Mode A / KV) for opt-in JSON Schema validation of custom storage writes. AJV-validates `ctx.store.write(table, row)` and `ctx.store.set(key, value)` before persisting; throws on shape violation. Default absent = permissive (status quo). `emitLink` and `enrichNode` keep their universal kernel validation regardless. A schema file missing on disk or failing AJV compile at load time surfaces as `load-error` with a directed reason naming the plugin, the table (Mode B), and the schema path. Pre-1.0 minor per `versioning.md` § Pre-1.0; additive — no consumer breakage. Documented in `plugin-author-guide.md` §Storage and referenced from `architecture.md` §Extractor · output callbacks.
|
|
894
|
-
|
|
895
|
-
- New kernel table `scan_extractor_runs(node_path, extractor_id, body_hash_at_run, ran_at)` — fine-grained Extractor cache breadcrumbs (Phase 4 / A.9). Replaces the previous "trust the node-level body+frontmatter hash" model that silently bypassed any Extractor newly registered between scans. Cache decision per `(node, extractor)` pair: a new Extractor registered between scans yields a partial cache hit (only the newcomer runs over the cached node); an uninstalled Extractor's rows disappear via replace-all, and links whose sources are exclusively that Extractor disappear with them. Documented in `db-schema.md` §`scan_extractor_runs`. Migration `001_initial.sql` updated in place per the pre-1.0 consolidation precedent (no released DBs to forward-migrate). Pre-1.0 minor per `versioning.md` § Pre-1.0; additive — no consumer breakage.
|
|
896
|
-
|
|
897
|
-
- Per-kind frontmatter schemas relocate from spec to the Provider that declares them. Spec keeps only `frontmatter/base.schema.json` (universal — fields common to every node across every Provider). The Claude Provider gains a `kinds` map declaring its catalog (`skill` / `agent` / `command` / `hook` / `note`) with per-kind `schema` + `defaultRefreshAction`. The pre-0.8 flat fields `emits: string[]` and `defaultRefreshAction: { <kind>: actionId }` collapse into the new map: `emits` is removed (derived from `Object.keys(kinds)`); each `defaultRefreshAction[<kind>]` value moves into `kinds[<kind>].defaultRefreshAction`. The kernel parse phase asks the Provider for the schema instead of reading from `spec/schemas/frontmatter/<kind>.schema.json`. Schema files moved: `spec/schemas/frontmatter/{skill,agent,command,hook,note}.schema.json` → `src/extensions/providers/claude/schemas/{skill,agent,command,hook,note}.schema.json`; their `$id` updates from `https://skill-map.dev/spec/v0/frontmatter/<kind>.schema.json` to `https://skill-map.dev/providers/claude/v1/frontmatter/<kind>.schema.json`; their `$ref: 'base.schema.json'` updates to `$ref: 'https://skill-map.dev/spec/v0/frontmatter/base.schema.json'` (absolute `$ref`-by-`$id` so AJV resolves cross-package against the spec base registered into the same instance). `spec/schemas/extensions/provider.schema.json` updated: `kinds` is required, `emits` and the old shape of `defaultRefreshAction` removed. `spec/conformance/coverage.md` matrix shrinks from 28 to 23 rows (the five per-kind frontmatter rows belong to the Provider's own conformance suite, planned in Phase 5). `spec/index.json` no longer lists the per-kind schemas. `architecture.md` §Provider section retitled `Provider · kinds catalog and explorationDir`; `plugin-author-guide.md` Provider example updated; `README.md` directory tree updated to reflect spec/frontmatter/ now holds only `base.schema.json`. Pre-1.0 minor per `versioning.md` § Pre-1.0; breaking for any plugin or test referencing `spec/schemas/frontmatter/<kind>.schema.json` paths or `$id`s, the old `provider.emits` field, or the flat `provider.defaultRefreshAction` map — no real ecosystem affected today.
|
|
898
|
-
|
|
899
|
-
- Plugin kind `renderer` renamed to `formatter`. Method renamed `render(ctx) → format(ctx)`. Manifest field `format` (the identifier consumed by `--format`) renamed to `formatId` to avoid clashing with the new method name. Same contract otherwise: graph → string, deterministic-only. Aligns with industry tooling (ESLint formatter, Mocha reporter, Pandoc writer). `schemas/extensions/renderer.schema.json` renamed to `formatter.schema.json`; the `kind` const flips from `"renderer"` to `"formatter"`; `base.schema.json#/properties/kind/enum` updated. `architecture.md`, `cli-contract.md`, `plugin-author-guide.md`, `README.md` updated to match (Extension kinds table, Execution modes table, testkit helper names, worked CSV example). `conformance/coverage.md` row 28 retargeted at the new schema filename. Pre-1.0 minor per `versioning.md` § Pre-1.0; breaking for any plugin or test referencing `kind: "renderer"`, `IRenderer`, `r.format`, or `render(ctx)` — no real ecosystem affected today.
|
|
900
|
-
|
|
901
|
-
- Plugin kind `'detector'` renamed to `'extractor'`. Method signature
|
|
902
|
-
changes from `detect(ctx) → Link[]` to `extract(ctx) → void` — output
|
|
903
|
-
flows through three new ctx callbacks: `emitLink(link)` (kernel `links`
|
|
904
|
-
table), `enrichNode(partial)` (kernel enrichment layer, persisted into
|
|
905
|
-
`node_enrichments` per A.8), and the existing `ctx.store` (plugin's
|
|
906
|
-
own table). The Extractor absorbs what would have been a separate
|
|
907
|
-
`Enricher` kind via `enrichNode`. Built-ins migrated:
|
|
908
|
-
`claude/frontmatter`, `claude/slash`, `claude/at-directive`,
|
|
909
|
-
`core/external-url-counter` — all use `emitLink` to maintain
|
|
910
|
-
functional parity with their Detector ancestors. Schema files
|
|
911
|
-
renamed: `schemas/extensions/detector.schema.json` →
|
|
912
|
-
`schemas/extensions/extractor.schema.json`. Persisted DB rows are
|
|
913
|
-
unaffected (link `sources` carry extractor ids verbatim — the field
|
|
914
|
-
was always free-form). Pre-1.0 minor per `versioning.md` § Pre-1.0;
|
|
915
|
-
breaking for any plugin or test referencing `'detector'` as the
|
|
916
|
-
kind, `IDetector`, or the old `Link[]` return signature — no real
|
|
917
|
-
ecosystem affected today.
|
|
918
|
-
|
|
919
|
-
- Plugin kind `'audit'` removed. The single built-in `'validate-all'`
|
|
920
|
-
migrated to a Rule (qualified id `'core/validate-all'`, method
|
|
921
|
-
`evaluate(ctx) → Issue[]`). The kind had dual personality (composer +
|
|
922
|
-
standalone reporter); the standalone reporter case is naturally a Rule,
|
|
923
|
-
and the composer case is deferred to post-1.0 if a real use case
|
|
924
|
-
appears. CLI verbs `'sm audit run'` and `'sm audit show'` removed;
|
|
925
|
-
users invoke the rule via `sm check --rules core/validate-all`.
|
|
926
|
-
`state_executions.kind` enum narrowed to `['action']` (audit was the
|
|
927
|
-
only other value); the column is preserved as a forward-compatibility
|
|
928
|
-
lever. Schema files removed: `schemas/extensions/audit.schema.json`.
|
|
929
|
-
Coverage matrix shrinks from 29 to 28 rows. Pre-1.0 minor per
|
|
930
|
-
`versioning.md` § Pre-1.0; breaking for any plugin or test referencing
|
|
931
|
-
the audit kind, `IAudit`, `TAuditReport`, or `sm audit` verbs — no
|
|
932
|
-
real ecosystem affected today.
|
|
933
|
-
|
|
934
|
-
- Plugin kind `'adapter'` renamed to `'provider'`. Manifest gains required
|
|
935
|
-
field `'explorationDir'` (filesystem directory where the Provider's
|
|
936
|
-
content lives, e.g. `'~/.claude'` for the Claude Provider). Built-in
|
|
937
|
-
`claudeAdapter` renamed to `claudeProvider`. The hexagonal-architecture
|
|
938
|
-
`'adapter'` (`RunnerPort.adapter`, `StoragePort.adapter`,
|
|
939
|
-
`FilesystemPort.adapter`, `PluginLoaderPort.adapter`) is unchanged —
|
|
940
|
-
distinct concept, distinct namespace.
|
|
941
|
-
Persisted schema fields renamed: `node.adapter` → `node.provider`,
|
|
942
|
-
`scan-result.adapters` → `scan-result.providers` (pre-1.0 minor — no
|
|
943
|
-
production DBs to migrate; `001_initial.sql` was edited in place per
|
|
944
|
-
the consolidation precedent already established for pre-1.0).
|
|
945
|
-
Project config field renamed: `project-config.adapters` →
|
|
946
|
-
`project-config.providers`. Schema files renamed:
|
|
947
|
-
`schemas/extensions/adapter.schema.json` →
|
|
948
|
-
`schemas/extensions/provider.schema.json`. Pre-1.0 minor per
|
|
949
|
-
`versioning.md` § Pre-1.0; breaking for any plugin or test referencing
|
|
950
|
-
`'adapter'` as the kind, `IAdapter`, or any persisted/config schema
|
|
951
|
-
field renamed above — no real ecosystem affected today.
|
|
952
|
-
|
|
953
|
-
## 0.7.1
|
|
954
|
-
|
|
955
|
-
### Patch Changes
|
|
956
|
-
|
|
957
|
-
- 0463a0f: Step 9.4 — plugin author guide + reference plugin + diagnostics polish.
|
|
958
|
-
**Step 9 fully closed** with this changeset.
|
|
959
|
-
|
|
960
|
-
### Spec — plugin author guide (additive prose)
|
|
961
|
-
|
|
962
|
-
New document at `spec/plugin-author-guide.md` covering:
|
|
963
|
-
|
|
964
|
-
- Discovery roots (`<project>/.skill-map/plugins/`,
|
|
965
|
-
`~/.skill-map/plugins/`, `--plugin-dir <path>`).
|
|
966
|
-
- Manifest fields with the normative schema reference.
|
|
967
|
-
- `specCompat` strategy — narrow ranges pre-`v1.0.0`, `^1.0.0`
|
|
968
|
-
recommendation post-`v1.0.0`.
|
|
969
|
-
- The six extension kinds with one minimal worked example each
|
|
970
|
-
(detector, rule, renderer in full; adapter / audit / action flagged
|
|
971
|
-
for later expansion alongside Step 10).
|
|
972
|
-
- Storage choice (KV vs Dedicated) cross-linking `plugin-kv-api.md`
|
|
973
|
-
and the Step 9.2 triple-protection rule.
|
|
974
|
-
- Execution modes (deterministic / probabilistic) cross-linking
|
|
975
|
-
`architecture.md`.
|
|
976
|
-
- Testkit usage with `runDetectorOnFixture`, `runRuleOnGraph`,
|
|
977
|
-
`runRendererOnGraph`, `makeFakeRunner`.
|
|
978
|
-
- The five plugin statuses (`loaded` / `disabled` / `incompatible-spec`
|
|
979
|
-
/ `invalid-manifest` / `load-error`) and how to read them.
|
|
980
|
-
- Stability section (document is stable; widening additions are minor
|
|
981
|
-
bumps; breaking edits are major).
|
|
982
|
-
|
|
983
|
-
`spec/package.json#files` updated to ship the new doc; `spec/index.json`
|
|
984
|
-
regenerated (57 → 58 hashed files). `coverage.md` unchanged because the
|
|
985
|
-
guide is prose, not a schema.
|
|
986
|
-
|
|
987
|
-
### Reference plugin — `examples/hello-world/`
|
|
988
|
-
|
|
989
|
-
Smallest viable plugin in the principal repo (Arquitecto's pick: in
|
|
990
|
-
the main repo, not separate). One detector (`hello-world-greet`)
|
|
991
|
-
emitting `references` links per `@greet:<name>` token in node bodies.
|
|
992
|
-
Includes:
|
|
45
|
+
## 0.12.0
|
|
993
46
|
|
|
994
|
-
|
|
995
|
-
- `extensions/greet-detector.mjs` — runtime instance with both
|
|
996
|
-
manifest fields and the `detect` method.
|
|
997
|
-
- `README.md` — what it does, file layout, three-step "try it
|
|
998
|
-
locally" recipe, what's intentionally missing (storage,
|
|
999
|
-
multi-extension, probabilistic mode), pointers for production-grade
|
|
1000
|
-
patterns.
|
|
1001
|
-
- `test/greet-detector.test.mjs` — four-assertion test using
|
|
1002
|
-
`@skill-map/testkit`, runnable via `node --test` with no build step.
|
|
47
|
+
### Minor
|
|
1003
48
|
|
|
1004
|
-
|
|
1005
|
-
`sm plugins list`, scans contribute its links to the persisted graph,
|
|
1006
|
-
and the testkit-based test passes. The example is **not** registered
|
|
1007
|
-
as a workspace — it's intentionally standalone so users can copy it.
|
|
49
|
+
- **`sm serve` + Hono BFF skeleton.** New `### Server` subsection in `cli-contract.md`. Endpoints at this bump: `GET /api/health` (real), `ALL /api/*` (structured 404 stub), `GET /ws` (no-op upgrade — closes with code 1000 + reason `'no broadcaster yet'`), static handler + SPA fallback. Loopback-only through v0.6.0; boot resilient to a missing DB (`/api/health` reports `db: 'missing'`). `sm serve` flag set: `--port` (default 4242), `--host` (default 127.0.0.1), `--scope`, `--db`, `--no-built-ins`, `--no-plugins`, `--open` / `--no-open`, `--dev-cors`, `--ui-dist`.
|
|
1008
50
|
|
|
1009
|
-
|
|
51
|
+
## 0.11.0
|
|
1010
52
|
|
|
1011
|
-
|
|
53
|
+
### Minor
|
|
1012
54
|
|
|
1013
|
-
|
|
1014
|
-
validating the JSON.
|
|
1015
|
-
- `invalid-manifest` (AJV): names the manifest path AND points at
|
|
1016
|
-
`spec/schemas/plugins-registry.schema.json#/$defs/PluginManifest`.
|
|
1017
|
-
- `invalid-manifest` (specCompat not a valid range): suggests a range
|
|
1018
|
-
shape (`"^1.0.0"`).
|
|
1019
|
-
- `incompatible-spec`: suggests two remediations (update the plugin's
|
|
1020
|
-
`specCompat`, or pin sm to a compatible spec version).
|
|
1021
|
-
- `load-error` (extension file not found): includes the absolute
|
|
1022
|
-
resolved path, pointer to `plugin.json#/extensions`.
|
|
1023
|
-
- `load-error` (default export missing kind): lists the valid kinds.
|
|
1024
|
-
- `load-error` (unknown kind): lists the valid kinds.
|
|
1025
|
-
- `load-error` (extension manifest schema fails): names the
|
|
1026
|
-
per-kind schema (`spec/schemas/extensions/<kind>.schema.json`).
|
|
55
|
+
- **Job artifacts move into the database (content-addressed).** New `state_job_contents(content_hash PK, content, created_at)`; `state_jobs.file_path` removed (rendered content fetched via join). `state_executions.report_path` → `state_executions.report_json` (parsed-JSON-on-read). `Job.filePath` removed; `ExecutionRecord.reportPath` → `ExecutionRecord.report` (parsed JSON / null). `RunnerPort.run(jobContent, options)` returns `{ report, ... }` — path-based reporting is no longer part of the port contract. `sm job preview` reads from the DB; `sm job claim --json` returns `{ id, nonce, content }`; `sm record --report <path-or-dash>` accepts a file path or stdin; `sm job prune --orphan-files` removed (the verb auto-collects orphan content rows). `sm doctor` integrity checks updated. Event payload renames: `job.spawning.data.jobFilePath` → `contentHash`; `job.callback.received.data.reportPath` and `job.completed.data.reportPath` → `executionId`. The `job-file-missing` failure-reason enum is preserved with shifted semantics: it now flags a missing `state_job_contents` row (DB-corruption-only state).
|
|
1027
56
|
|
|
1028
|
-
|
|
1029
|
-
polish` describe block) assert each hint shape is present without
|
|
1030
|
-
pinning the full text. Test count 437 → **443 cli + 30 testkit = 473**.
|
|
57
|
+
## 0.10.0
|
|
1031
58
|
|
|
1032
|
-
|
|
59
|
+
### Minor
|
|
1033
60
|
|
|
1034
|
-
|
|
1035
|
-
migrations + triple protection), 9.3 (`@skill-map/testkit` workspace),
|
|
1036
|
-
9.4 (author guide + reference plugin + diagnostics polish) — together
|
|
1037
|
-
turn `skill-map` plugins from "discovered but inert" into a
|
|
1038
|
-
first-class authoring surface with documentation, tests, and a
|
|
1039
|
-
working reference. Next step: **Step 10 — job subsystem + first
|
|
1040
|
-
probabilistic extension** (wave 2 begins).
|
|
61
|
+
- **`Node.kind` opens to any Provider-declared string.** `node.schema.json#/properties/kind` becomes `{ type: 'string', minLength: 1 }`; the `CHECK in (...)` SQL constraints on `scan_nodes.kind` and `state_summaries.kind` drop; `extensions/action.schema.json#/.../filter/kind` widens to a string array. Providers declare their own kind catalog through the `kinds` map; the spec no longer enumerates a closed set.
|
|
1041
62
|
|
|
1042
63
|
## 0.7.0
|
|
1043
64
|
|
|
1044
|
-
### Minor
|
|
1045
|
-
|
|
1046
|
-
- d730094: Spec — Execution modes (deterministic / probabilistic) lifted to a first-class architectural property
|
|
1047
|
-
|
|
1048
|
-
Frames a meta-property of skill-map that was previously implicit and scattered:
|
|
1049
|
-
**every analytical extension is one of two modes** — `deterministic` (pure code,
|
|
1050
|
-
runs in scan-time pipelines) or `probabilistic` (invokes an LLM through
|
|
1051
|
-
`RunnerPort`, runs only as queued jobs). The dual-mode capability now spans four
|
|
1052
|
-
of the six extension kinds; Adapter and Renderer remain locked to deterministic
|
|
1053
|
-
because they sit at the system boundaries (filesystem and graph-to-string) where
|
|
1054
|
-
non-determinism would break boot reproducibility and snapshot diffing.
|
|
1055
|
-
|
|
1056
|
-
**Spec changes:**
|
|
1057
|
-
|
|
1058
|
-
- `architecture.md` — new top-level section **§Execution modes** before
|
|
1059
|
-
§Extension kinds. Defines the two modes, the per-kind capability matrix
|
|
1060
|
-
(Detector / Rule / Action dual-mode by manifest declaration; Audit dual-mode
|
|
1061
|
-
with mode **derived** from `composes[]`; Adapter / Renderer deterministic-only),
|
|
1062
|
-
the runtime separation (`deterministic` runs in `sm scan` / `sm check`;
|
|
1063
|
-
`probabilistic` runs only via `sm job submit <kind>:<id>`), and the
|
|
1064
|
-
`RunnerPort` injection contract for probabilistic extensions.
|
|
1065
|
-
- `architecture.md` §Extension kinds — table updated: each row clarifies the
|
|
1066
|
-
mode posture (Adapter / Renderer marked deterministic-only; Detector / Rule /
|
|
1067
|
-
Action marked dual-mode; Audit marked derived-mode).
|
|
1068
|
-
- `architecture.md` §Stability — new clause: execution modes and the per-kind
|
|
1069
|
-
capability matrix are stable as of v1.0.0; adding a third mode, changing
|
|
1070
|
-
which kinds are dual-mode, or changing the audit's derivation rule is a major
|
|
1071
|
-
bump.
|
|
1072
|
-
|
|
1073
|
-
**Schema changes:**
|
|
1074
|
-
|
|
1075
|
-
- `schemas/extensions/detector.schema.json`:
|
|
1076
|
-
- New optional `mode` field (`deterministic` | `probabilistic`, default
|
|
1077
|
-
`deterministic`). Omitting is equivalent to deterministic — keeps existing
|
|
1078
|
-
detectors valid without an update.
|
|
1079
|
-
- Description updated to spell out the dual-mode contract.
|
|
1080
|
-
- `schemas/extensions/rule.schema.json`:
|
|
1081
|
-
- Same shape: new optional `mode` field with default `deterministic`.
|
|
1082
|
-
- Description rewritten — the previous "Rules MUST be deterministic" claim
|
|
1083
|
-
moved into the deterministic-mode contract; probabilistic rules are now
|
|
1084
|
-
explicitly allowed and run only as queued jobs.
|
|
1085
|
-
- `schemas/extensions/action.schema.json`:
|
|
1086
|
-
- **Breaking** — `mode` enum renamed: `local` → `deterministic`,
|
|
1087
|
-
`invocation-template` → `probabilistic`. Pre-1.0; no consumers depend on
|
|
1088
|
-
the old values (no third-party action plugins shipped). Description, the
|
|
1089
|
-
two `if/then` branches, and the `expectedDurationSeconds` /
|
|
1090
|
-
`promptTemplateRef` field descriptions updated accordingly.
|
|
1091
|
-
- **Bug fix** — the schema previously declared `allOf` twice at the root
|
|
1092
|
-
(lines 6–8 and 71–80); the second silently overrode the first, dropping
|
|
1093
|
-
`$ref: base.schema.json`. Both blocks are now merged into a single `allOf`
|
|
1094
|
-
so the action schema actually composes the base shape.
|
|
1095
|
-
- `schemas/extensions/audit.schema.json`:
|
|
1096
|
-
- Description rewritten — the "deterministic workflow" claim is replaced by
|
|
1097
|
-
the **derived-mode** rule: the audit's effective mode is computed from
|
|
1098
|
-
`composes[]` at load time. If every composed primitive is deterministic,
|
|
1099
|
-
the audit is deterministic; if any is probabilistic, the audit is
|
|
1100
|
-
probabilistic and dispatches as a job. Declaring `mode` directly is a
|
|
1101
|
-
load-time error.
|
|
1102
|
-
- `composes[]` description updated to mention that each primitive's mode
|
|
1103
|
-
participates in derivation; dangling references stay a load-time error.
|
|
1104
|
-
- `reportSchemaRef` description updated: probabilistic audits MUST extend
|
|
1105
|
-
`report-base.schema.json` (carries `safety` / `confidence`); deterministic
|
|
1106
|
-
audits MAY extend it but are not required to.
|
|
1107
|
-
- `schemas/extensions/adapter.schema.json`:
|
|
1108
|
-
- Description updated to state explicitly that adapters are deterministic-only
|
|
1109
|
-
and that `mode` MUST NOT appear. Recommendation for users who want
|
|
1110
|
-
LLM-assisted classification: write a probabilistic Detector that emits
|
|
1111
|
-
classification hints as `Link[]`.
|
|
1112
|
-
- `schemas/extensions/renderer.schema.json`:
|
|
1113
|
-
- Description updated to state that renderers are deterministic-only and
|
|
1114
|
-
that `mode` MUST NOT appear. Probabilistic narrators of the graph belong
|
|
1115
|
-
in jobs and emit Findings, not in renderer manifests.
|
|
1116
|
-
|
|
1117
|
-
**Why major (despite pre-1.0 minor norm):**
|
|
1118
|
-
|
|
1119
|
-
Renaming the `Action.mode` enum (`local` → `deterministic`,
|
|
1120
|
-
`invocation-template` → `probabilistic`) is breaking by definition. No
|
|
1121
|
-
third-party Actions exist yet, but the rename touches the canonical surface and
|
|
1122
|
-
deserves the bump. New optional fields on Detector / Rule and the new derived-
|
|
1123
|
-
mode contract on Audit are additive and would have been minor on their own.
|
|
1124
|
-
|
|
1125
|
-
**Implementation work intentionally NOT included here:**
|
|
1126
|
-
|
|
1127
|
-
- `src/extensions/built-ins.ts` and the per-extension TS files keep working
|
|
1128
|
-
unchanged because the new `mode` is optional with `deterministic` default.
|
|
1129
|
-
Explicitly threading `mode: 'deterministic'` through every built-in is a
|
|
1130
|
-
follow-up.
|
|
1131
|
-
- `RunnerPort` injection through `ctx.runner` for probabilistic extensions is
|
|
1132
|
-
spec'd here; the actual context plumbing lands with the first probabilistic
|
|
1133
|
-
extension (Step 10 — first summarizer). `MockRunner` continues to satisfy
|
|
1134
|
-
tests until then.
|
|
1135
|
-
- Conformance case `extension-mode-derivation` (audit composes mixed
|
|
1136
|
-
primitives → derives `probabilistic`) is mentioned in `architecture.md` and
|
|
1137
|
-
pending under `spec/conformance/coverage.md` for the next release.
|
|
1138
|
-
- ROADMAP.md rephrase of Steps 10–11 (from "summarizers" to "wave 2:
|
|
1139
|
-
probabilistic extensions") and a positioning section in `README.md` follow
|
|
1140
|
-
in separate commits to keep this changeset spec-only.
|
|
1141
|
-
|
|
1142
|
-
### Minor Changes
|
|
1143
|
-
|
|
1144
|
-
- a73f3f4: Step 7.1 — File watcher (`sm watch` / `sm scan --watch`)
|
|
1145
|
-
|
|
1146
|
-
Long-running watcher that subscribes to the scan roots, debounces
|
|
1147
|
-
filesystem events, and triggers an incremental scan per batch. Reuses
|
|
1148
|
-
the existing `runScanWithRenames` pipeline, the `IIgnoreFilter` chain
|
|
1149
|
-
(`.skill-mapignore` + `config.ignore` + bundled defaults), and the
|
|
1150
|
-
`scan.*` non-job events from `job-events.md` — one ScanResult per
|
|
1151
|
-
batch, emitted as ndjson under `--json`.
|
|
1152
|
-
|
|
1153
|
-
**Spec changes (minor)**:
|
|
1154
|
-
|
|
1155
|
-
- `spec/schemas/project-config.schema.json` — new `scan.watch` object
|
|
1156
|
-
with a single key `debounceMs` (integer ≥ 0, default 300). Groups
|
|
1157
|
-
bursts of filesystem events (editor saves, branch switches, npm
|
|
1158
|
-
installs) into a single scan pass. Set to 0 to disable debouncing.
|
|
1159
|
-
- `spec/cli-contract.md` §Scan — documents `sm watch [roots...]` as
|
|
1160
|
-
the primary verb and `sm scan --watch` as the alias. Watcher
|
|
1161
|
-
respects the same ignore chain as one-shot scans, emits one
|
|
1162
|
-
ScanResult per batch (ndjson under `--json`), closes cleanly on
|
|
1163
|
-
`SIGINT` / `SIGTERM`, exits 0 on clean shutdown. Exit-code rule
|
|
1164
|
-
carved out for the watcher: per-batch error issues do not flip the
|
|
1165
|
-
exit code (the loop keeps running); operational errors still exit 2.
|
|
1166
|
-
|
|
1167
|
-
No new events. No new ports. The watcher is implementation-defined
|
|
1168
|
-
inside the kernel package; a future `WatchPort` can be added when /
|
|
1169
|
-
if a non-Node implementation needs to swap the chokidar wrapper.
|
|
1170
|
-
|
|
1171
|
-
**Runtime changes (minor — new verb + new config key)**:
|
|
1172
|
-
|
|
1173
|
-
- `chokidar@5.0.0` pinned in `src/package.json` (single new runtime
|
|
1174
|
-
dependency, MIT). Chokidar v5 requires Node ≥ 20.19; the project
|
|
1175
|
-
already pins `engines.node: ">=24.0"` so this is a no-op for
|
|
1176
|
-
consumers. Brings in `readdirp@5` as a transitive.
|
|
1177
|
-
- `src/kernel/scan/watcher.ts` — `IFsWatcher` interface + concrete
|
|
1178
|
-
`ChokidarWatcher` wrapping `chokidar.watch()` with the existing
|
|
1179
|
-
`IIgnoreFilter` plumbed through, debouncer, batch coalescing,
|
|
1180
|
-
and explicit `stop()` for clean teardown.
|
|
1181
|
-
- `src/cli/commands/watch.ts` — new `WatchCommand`. `sm scan
|
|
1182
|
-
--watch` delegates to the same code path so the two surfaces are
|
|
1183
|
-
byte-aligned (no parallel implementations).
|
|
1184
|
-
- `src/config/defaults.json` — new `scan.watch.debounceMs: 300`
|
|
1185
|
-
default.
|
|
1186
|
-
|
|
1187
|
-
**Why minor (not patch)**: new public verb (`sm watch`), new public
|
|
1188
|
-
config key (`scan.watch.debounceMs`), and a new flag on an existing
|
|
1189
|
-
verb (`sm scan --watch`). All three are surface additions, not bug
|
|
1190
|
-
fixes — minor under both the spec and the runtime semver policies.
|
|
1191
|
-
No breaking changes; existing `sm scan` without `--watch` is
|
|
1192
|
-
byte-identical to before.
|
|
1193
|
-
|
|
1194
|
-
**Roadmap**: Step 7 — Robustness, sub-step 7.1 (chokidar watcher).
|
|
1195
|
-
Trigger normalization is implicit-already-landed (cabled into every
|
|
1196
|
-
detector at Steps 3–4 with full unit tests in
|
|
1197
|
-
`src/kernel/trigger-normalize.test.ts`); we do not write a sub-step
|
|
1198
|
-
for it. Next sub-steps: 7.2 detector conflict resolution, 7.3 `sm
|
|
1199
|
-
job prune` + retention enforcement.
|
|
1200
|
-
|
|
1201
|
-
### Patch Changes
|
|
1202
|
-
|
|
1203
|
-
- a73f3f4: Step 7.2 — Detector conflict resolution
|
|
1204
|
-
|
|
1205
|
-
Two pieces:
|
|
1206
|
-
|
|
1207
|
-
1. **New built-in rule `link-conflict`** (`src/extensions/rules/link-conflict/`).
|
|
1208
|
-
Surfaces detector disagreement. Groups links by `(source, target)` and
|
|
1209
|
-
emits one `warn` Issue per pair where the set of distinct `kind` values
|
|
1210
|
-
has size ≥ 2. Agreement (single kind across multiple detectors) is
|
|
1211
|
-
silent — by design, to avoid massive noise on real graphs.
|
|
1212
|
-
Issue payload (`data`) carries `{ source, target, variants }` where
|
|
1213
|
-
each `variant` is `{ kind, sources: detectorId[], confidence }`. Variant
|
|
1214
|
-
sources are deduped + sorted; confidence is the highest across rows
|
|
1215
|
-
of the same kind (`high` > `medium` > `low`).
|
|
1216
|
-
|
|
1217
|
-
This is the kernel piece of Decision #90 read-time "consumers that
|
|
1218
|
-
need uniqueness aggregate at read time" — the rule is one such
|
|
1219
|
-
consumer, on the alarming side. Storage stays untouched (one row
|
|
1220
|
-
per detector, no merge, no dedup). Severity is `warn`, not `error`:
|
|
1221
|
-
the rule cannot pick which kind is correct, so per `cli-contract.md`
|
|
1222
|
-
§Exit codes the verb stays exit 0.
|
|
1223
|
-
|
|
1224
|
-
2. **`sm show` pretty link aggregation** (`src/cli/commands/show.ts`).
|
|
1225
|
-
The human renderer now groups `linksOut` / `linksIn` by `(endpoint,
|
|
1226
|
-
kind, normalizedTrigger)` and prints one row per group with the
|
|
1227
|
-
union of detector ids in a `sources:` field. The section header
|
|
1228
|
-
reports both the raw row count and the unique-after-grouping count
|
|
1229
|
-
(`Links out (12, 9 unique)`). When N > 1 detector emits the same
|
|
1230
|
-
logical link, the row also gets a `(×N)` suffix.
|
|
1231
|
-
|
|
1232
|
-
`--json` output is byte-identical to before — raw rows, no merge.
|
|
1233
|
-
Storage is byte-identical to before. The grouping is purely a
|
|
1234
|
-
read-time presentation choice for human eyes.
|
|
1235
|
-
|
|
1236
|
-
**Spec changes (patch)**:
|
|
1237
|
-
|
|
1238
|
-
- `spec/cli-contract.md` §Browse — `sm show` row clarifies that pretty
|
|
1239
|
-
output groups identical-shape links and that `--json` emits raw rows.
|
|
1240
|
-
Patch (not minor) because the JSON contract is unchanged; the human
|
|
1241
|
-
output format is non-normative anyway.
|
|
1242
|
-
|
|
1243
|
-
**Runtime changes (minor — new rule + new presentation)**:
|
|
1244
|
-
|
|
1245
|
-
- New rule `link-conflict` registered in `src/extensions/built-ins.ts`.
|
|
1246
|
-
- `sm show` pretty output groups links + reports unique counts.
|
|
1247
|
-
|
|
1248
|
-
**UI inspector aggregation deferred to Step 13**: the current Flavor A
|
|
1249
|
-
inspector renders the `Relations` card from `node.frontmatter.metadata.{
|
|
1250
|
-
related, requires, supersedes, provides, conflictsWith}` directly — it
|
|
1251
|
-
does NOT consume `linksOut` / `linksIn` rows from `scan_links`. There
|
|
1252
|
-
is no link table to aggregate today. When Step 13's Flavor B lands (Hono
|
|
1253
|
-
BFF + WS + full link panel from scan), the aggregation logic from
|
|
1254
|
-
`src/cli/commands/show.ts` will need to be ported.
|
|
1255
|
-
|
|
1256
|
-
**Roadmap**: Step 7 — Robustness, sub-step 7.2 (detector conflict
|
|
1257
|
-
resolution). Closes one of the three remaining frentes; 7.3 (`sm job
|
|
1258
|
-
prune` + retention) still pending. Decision #90 unchanged: storage
|
|
1259
|
-
keeps raw per-detector rows. The `related` vs LLM-amplification
|
|
1260
|
-
discussion is documented in `.tmp/skill-map-related-test/` (status
|
|
1261
|
-
quo retained — fields stay opt-in under `metadata.*`; revisit if
|
|
1262
|
-
real-world amplification appears).
|
|
65
|
+
### Minor
|
|
1263
66
|
|
|
1264
|
-
|
|
67
|
+
- **Execution modes lifted to a first-class architectural property.** `architecture.md` gains §Execution modes defining the per-kind capability matrix: Extractor / Rule / Action / Hook are dual-mode (declared in manifest); Provider and Formatter are deterministic-only (boundary-positioned). Extractor / Rule schemas gain optional `mode` (default `deterministic`); Action's `mode` enum becomes `deterministic` / `probabilistic`; Provider / Formatter forbid the field.
|
|
1265
68
|
|
|
1266
69
|
## 0.6.1
|
|
1267
70
|
|
|
1268
|
-
### Patch
|
|
1269
|
-
|
|
1270
|
-
- f41dbad: Step 6.1 — Spec migration: rename the canonical config file from
|
|
1271
|
-
`.skill-map.json` (single project-root file) to `.skill-map/settings.json`
|
|
1272
|
-
inside the `.skill-map/` scope folder, with a sibling `.skill-map/settings.local.json`
|
|
1273
|
-
partner for machine-specific overrides. Aligns the spec with the layered
|
|
1274
|
-
config hierarchy described in the roadmap (library defaults → user → user-local
|
|
1275
|
-
→ project → project-local → env / flags).
|
|
1276
|
-
|
|
1277
|
-
**Spec change (breaking, minor under pre-1.0 versioning policy)**:
|
|
1278
|
-
|
|
1279
|
-
- `spec/schemas/project-config.schema.json` description updated to point at
|
|
1280
|
-
`.skill-map/settings.json` and explicitly mention the `.local.json` partner
|
|
1281
|
-
and the layered-merge contract. The schema _shape_ (keys, types, validation
|
|
1282
|
-
rules) is unchanged — only the on-disk filename moves. Consumers that read
|
|
1283
|
-
values without caring about the source path are unaffected; consumers that
|
|
1284
|
-
hard-code the filename must update.
|
|
1285
|
-
- `spec/db-schema.md` §Scopes: `history.share: true` reference updated to
|
|
1286
|
-
`.skill-map/settings.json`.
|
|
1287
|
-
- `spec/conformance/coverage.md` row #6 description updated to reference the
|
|
1288
|
-
new path and the optional `settings.local.json` overlay.
|
|
1289
|
-
|
|
1290
|
-
**Why minor (not major) at pre-1.0**: per `spec/versioning.md` §Pre-1.0,
|
|
1291
|
-
breaking changes ARE allowed in minor bumps while the spec is `0.y.z`. The
|
|
1292
|
-
shape of the data is unchanged; only the file name on disk moves.
|
|
1293
|
-
|
|
1294
|
-
**No backward-compat shim**: there is no real implementation of the loader
|
|
1295
|
-
yet (lands in 6.2), so no live consumer reads `.skill-map.json` today. The
|
|
1296
|
-
only known prior reference is the demo `mock-collection/.claude/commands/init*.md`
|
|
1297
|
-
fixture, which is updated together with `sm init` in 6.5.
|
|
1298
|
-
|
|
1299
|
-
**Runtime change**: none in 6.1 — pure spec edit. The matching loader,
|
|
1300
|
-
`sm init`, and `sm config` verbs land in subsequent sub-steps.
|
|
1301
|
-
|
|
1302
|
-
**Roadmap update**: `ROADMAP.md` §Configuration "Spec migration" call-out
|
|
1303
|
-
flipped from "pending" to "landed Step 6.1, 2026-04-27".
|
|
1304
|
-
|
|
1305
|
-
Test count: unchanged (213 → 213 — spec-only edit).
|
|
1306
|
-
|
|
1307
|
-
- 8a4667f: Step 6.6 — `sm plugins enable / disable` + the `config_plugins`
|
|
1308
|
-
override layer they read from. The two stub verbs become real, and
|
|
1309
|
-
the `PluginLoader` finally honours user intent: a disabled plugin
|
|
1310
|
-
surfaces in `sm plugins list` with status `disabled`, but its
|
|
1311
|
-
extensions are NOT imported and the kernel will not run them.
|
|
1312
|
-
|
|
1313
|
-
**Decision (recorded in spec)**: enable/disable resolution favours the
|
|
1314
|
-
DB row over `settings.json` over the installed default. The DB
|
|
1315
|
-
override is local-machine; `settings.json` is the team-shared baseline.
|
|
1316
|
-
A developer can locally disable a misbehaving plugin without
|
|
1317
|
-
committing the toggle to the team's config; conversely, a baseline
|
|
1318
|
-
that explicitly enables a plugin is overridable per-machine. The rule
|
|
1319
|
-
is documented in `spec/db-schema.md` §`config_plugins`.
|
|
1320
|
-
|
|
1321
|
-
**Spec change (additive, patch)**:
|
|
1322
|
-
|
|
1323
|
-
- `spec/db-schema.md` — appended an "Effective enable/disable
|
|
1324
|
-
resolution" subsection under `config_plugins` documenting the
|
|
1325
|
-
three-layer precedence (DB > `settings.json` > installed default).
|
|
1326
|
-
No schema changes; the `config_plugins` table itself was already
|
|
1327
|
-
defined in the initial migration.
|
|
1328
|
-
|
|
1329
|
-
**Runtime change**:
|
|
1330
|
-
|
|
1331
|
-
- `src/kernel/types/plugin.ts` — `TPluginLoadStatus` gains a `disabled`
|
|
1332
|
-
variant. JSDoc explains all five states.
|
|
1333
|
-
- `src/kernel/adapters/sqlite/plugins.ts` — new file. Storage helpers
|
|
1334
|
-
over the `config_plugins` table: `setPluginEnabled` (upsert),
|
|
1335
|
-
`getPluginEnabled` (single read), `loadPluginOverrideMap` (bulk
|
|
1336
|
-
read for one round-trip per process), `deletePluginOverride`
|
|
1337
|
-
(idempotent drop, used by future `sm config reset plugins.<id>`).
|
|
1338
|
-
- `src/kernel/config/plugin-resolver.ts` — new file.
|
|
1339
|
-
`resolvePluginEnabled` implements the precedence above;
|
|
1340
|
-
`makeEnabledResolver` curries the layered config and DB map into
|
|
1341
|
-
the `(id) => boolean` shape `IPluginLoaderOptions.resolveEnabled`
|
|
1342
|
-
expects.
|
|
1343
|
-
- `src/kernel/adapters/plugin-loader.ts` — new optional
|
|
1344
|
-
`resolveEnabled` callback in `IPluginLoaderOptions`. When supplied,
|
|
1345
|
-
the loader checks AFTER manifest + specCompat validation and
|
|
1346
|
-
short-circuits with `status: 'disabled'` (manifest preserved,
|
|
1347
|
-
extensions array omitted, reason `"disabled by config_plugins or
|
|
1348
|
-
settings.json"`). Omitting the callback keeps the legacy "always
|
|
1349
|
-
load" behaviour for tests / kernel-empty-boot.
|
|
1350
|
-
- `src/cli/commands/plugins.ts` — wires the loader to the resolver:
|
|
1351
|
-
every read (`list / show / doctor`) loads `config_plugins` once and
|
|
1352
|
-
feeds the resolver. Two new commands `PluginsEnableCommand` and
|
|
1353
|
-
`PluginsDisableCommand` write to the DB. `--all` toggles every
|
|
1354
|
-
discovered plugin; `<id>` and `--all` are mutually exclusive.
|
|
1355
|
-
`sm plugins doctor` now treats `disabled` as intentional (does not
|
|
1356
|
-
contribute to the issue list, does not flip exit code).
|
|
1357
|
-
- `src/cli/commands/plugins.ts` — adds `off` to the status icon legend
|
|
1358
|
-
in human output (`off mock-a@0.1.0 · disabled by config_plugins or
|
|
1359
|
-
settings.json`).
|
|
1360
|
-
- `src/cli/commands/stubs.ts` — `PluginsEnableCommand` and
|
|
1361
|
-
`PluginsDisableCommand` removed; replaced-at-step comment kept.
|
|
1362
|
-
- `context/cli-reference.md` — regenerated; the two new verbs appear
|
|
1363
|
-
with their flag tables.
|
|
1364
|
-
|
|
1365
|
-
**Tests**:
|
|
1366
|
-
|
|
1367
|
-
- `src/test/plugin-overrides.test.ts` — 8 unit tests covering storage
|
|
1368
|
-
round-trip (upsert + read), `loadPluginOverrideMap` bulk read,
|
|
1369
|
-
`deletePluginOverride` idempotency, resolver precedence (default ⇒
|
|
1370
|
-
true, `settings.json` overrides default, DB overrides
|
|
1371
|
-
`settings.json`), `makeEnabledResolver` currying, and PluginLoader
|
|
1372
|
-
surfacing `disabled` status with manifest preserved + no extensions
|
|
1373
|
-
- omitting the resolver still loads.
|
|
1374
|
-
- `src/test/plugins-cli.test.ts` — 9 end-to-end tests via the binary:
|
|
1375
|
-
`disable <id>` writes a DB row + `sm plugins list` reflects `off`,
|
|
1376
|
-
`enable <id>` flips back, `--all` covers every discovered plugin,
|
|
1377
|
-
unknown id → exit 5, no-arg → exit 2, both `<id>` and `--all` →
|
|
1378
|
-
exit 2, `settings.json` baseline overridden by DB `enable`,
|
|
1379
|
-
`settings.json` baseline applies when DB has no row, and
|
|
1380
|
-
`sm plugins doctor` exits 0 when the only non-loaded plugin is
|
|
1381
|
-
intentionally disabled.
|
|
71
|
+
### Patch
|
|
1382
72
|
|
|
1383
|
-
|
|
73
|
+
- **Config folder rename** — `.skill-map.json` (single project-root file) → `.skill-map/settings.json` inside the canonical `.skill-map/` scope folder, with a sibling `.skill-map/settings.local.json` for per-machine overrides.
|
|
1384
74
|
|
|
1385
75
|
## 0.6.0
|
|
1386
76
|
|
|
1387
|
-
### Minor
|
|
1388
|
-
|
|
1389
|
-
- 9a89124: Step 5.1 — Persist scan-result metadata in a new `scan_meta` table so
|
|
1390
|
-
`loadScanResult` returns real values for `scope` / `roots` / `scannedAt` /
|
|
1391
|
-
`scannedBy` / `adapters` / `stats.filesWalked` / `stats.filesSkipped` /
|
|
1392
|
-
`stats.durationMs` instead of the synthetic envelope shipped at Step 4.7.
|
|
1393
|
-
|
|
1394
|
-
**Spec change (additive, minor)**:
|
|
1395
|
-
|
|
1396
|
-
- New `scan_meta` table in zone `scan_*`, single-row (CHECK `id = 1`).
|
|
1397
|
-
Columns: `scope`, `roots_json`, `scanned_at`, `scanned_by_name`,
|
|
1398
|
-
`scanned_by_version`, `scanned_by_spec_version`, `adapters_json`,
|
|
1399
|
-
`stats_files_walked`, `stats_files_skipped`, `stats_duration_ms`.
|
|
1400
|
-
`nodesCount` / `linksCount` / `issuesCount` are not stored — they are
|
|
1401
|
-
derived from `COUNT(*)` of the sibling tables.
|
|
1402
|
-
- Replaced atomically with the rest of `scan_*` on every `sm scan`.
|
|
1403
|
-
|
|
1404
|
-
**Runtime change**:
|
|
1405
|
-
|
|
1406
|
-
- New kernel migration `002_scan_meta.sql`.
|
|
1407
|
-
- `IScanMetaTable` added to `src/kernel/adapters/sqlite/schema.ts` and
|
|
1408
|
-
bound in `IDatabase`.
|
|
1409
|
-
- `persistScanResult` writes the row (and deletes prior rows in the same
|
|
1410
|
-
transaction).
|
|
1411
|
-
- `loadScanResult` reads from `scan_meta` when the row exists; degrades
|
|
1412
|
-
to the previous synthetic envelope when it does not (DB freshly
|
|
1413
|
-
migrated, never scanned, or pre-5.1 snapshot).
|
|
1414
|
-
- The Step 4.7 follow-up notes in `scan-load.ts` documenting the
|
|
1415
|
-
synthetic envelope are simplified to describe both branches.
|
|
1416
|
-
|
|
1417
|
-
Test count: 151 → 154 (+3 covering meta round-trip, replace-all
|
|
1418
|
-
single-row invariant, and synthetic-fallback on empty DB).
|
|
1419
|
-
|
|
1420
|
-
- 9a89124: Step 5.7 — Conformance coverage for the rename heuristic.
|
|
1421
|
-
|
|
1422
|
-
**Spec change (additive, minor)**:
|
|
1423
|
-
|
|
1424
|
-
- `spec/schemas/conformance-case.schema.json` gains
|
|
1425
|
-
`setup.priorScans: Array<{ fixture, flags? }>` — an ordered list of
|
|
1426
|
-
staging scans the runner executes BEFORE the main `invoke`. Each
|
|
1427
|
-
step replaces every non-`.skill-map/` directory in the scope with
|
|
1428
|
-
the named fixture and runs `sm scan` (with optional flags). The DB
|
|
1429
|
-
persists across steps because `.skill-map/` is preserved between
|
|
1430
|
-
swaps. After the last step, the runner copies the top-level
|
|
1431
|
-
`fixture` and runs the case's `invoke`.
|
|
1432
|
-
|
|
1433
|
-
Required to express scenarios that need a prior snapshot (rename
|
|
1434
|
-
heuristic, future incremental cases). The schema is purely
|
|
1435
|
-
additive — every existing case keeps passing without modification.
|
|
1436
|
-
|
|
1437
|
-
- Two new conformance cases under `spec/conformance/cases/`:
|
|
1438
|
-
|
|
1439
|
-
- **`rename-high`** — moving a single file with identical body
|
|
1440
|
-
triggers a high-confidence auto-rename. Asserts:
|
|
1441
|
-
`stats.nodesCount === 1`, `stats.issuesCount === 0`,
|
|
1442
|
-
`nodes[0].path === skills/bar.md`. Verifies the spec invariant
|
|
1443
|
-
that high-confidence renames emit NO issue.
|
|
1444
|
-
- **`orphan-detection`** — deleting a file with no replacement
|
|
1445
|
-
emits exactly one `orphan` issue (severity `info`). Asserts the
|
|
1446
|
-
`ruleId` and `severity` directly.
|
|
1447
|
-
|
|
1448
|
-
- Four new fixture directories under `spec/conformance/fixtures/`:
|
|
1449
|
-
`rename-high-before/`, `rename-high-after/`,
|
|
1450
|
-
`orphan-before/`, `orphan-after/`.
|
|
1451
|
-
|
|
1452
|
-
- `spec/conformance/coverage.md`: row I (Rename heuristic) flips
|
|
1453
|
-
from `🔴 missing` to `🟢 covered`. Notes the medium / ambiguous
|
|
1454
|
-
branches stay covered by `src/test/rename-heuristic.test.ts` for
|
|
1455
|
-
now (assertion vocabulary in the schema is not rich enough to
|
|
1456
|
-
express "the issues array contains an item with ruleId X and
|
|
1457
|
-
data.confidence === 'medium'" — when the conformance schema gains
|
|
1458
|
-
array-filter assertions, those branches can land here too).
|
|
1459
|
-
|
|
1460
|
-
**Runtime change**:
|
|
1461
|
-
|
|
1462
|
-
- `src/conformance/index.ts` runner: implements `setup.priorScans`.
|
|
1463
|
-
Helper `replaceFixture(scope, specRoot, fixture)` clears every
|
|
1464
|
-
top-level entry in the scope except `.skill-map/`, then copies the
|
|
1465
|
-
named fixture on top. Used by both staging steps and the main
|
|
1466
|
-
`fixture` phase.
|
|
1467
|
-
- `src/test/conformance.test.ts`: includes the two new cases in the
|
|
1468
|
-
Step-0b subset. Total conformance cases passing in CI: 1 → 3.
|
|
1469
|
-
|
|
1470
|
-
**`spec/index.json`** regenerated (50 → 57 files). `npm run spec:check`
|
|
1471
|
-
green.
|
|
1472
|
-
|
|
1473
|
-
Test count: 201 → 203 (+2 conformance cases). The Step 5 totals close
|
|
1474
|
-
at: 151 → 203 (+52 across 7 sub-steps).
|
|
1475
|
-
|
|
1476
|
-
### Patch Changes
|
|
1477
|
-
|
|
1478
|
-
- dacd4d9: Move the auto-generated CLI reference from `docs/cli-reference.md` to
|
|
1479
|
-
`context/cli-reference.md`. Spec change is editorial: `cli-contract.md`
|
|
1480
|
-
references the file path in three spots (`--format md` description, the
|
|
1481
|
-
NORMATIVE introspection section, and the "Related" link list); all three
|
|
1482
|
-
updated to the new location. No schema or behavioural change.
|
|
1483
|
-
|
|
1484
|
-
Reference impl: `scripts/build-cli-reference.mjs` writes to the new path,
|
|
1485
|
-
the `cli:reference` / `cli:check` npm scripts point there, and `sm help`
|
|
1486
|
-
output (which embeds the path in the `--format md` flag description) is
|
|
1487
|
-
regenerated. The `docs/` folder is gone.
|
|
1488
|
-
|
|
1489
|
-
## 0.5.1
|
|
1490
|
-
|
|
1491
|
-
### Patch Changes
|
|
77
|
+
### Minor
|
|
1492
78
|
|
|
1493
|
-
-
|
|
79
|
+
- **Persisted scan-result metadata.** New `scan_meta` table backs `loadScanResult` so `scope` / `roots` / `scannedAt` / `scannedBy` / `adapters` / `stats.{filesWalked,filesSkipped,durationMs}` are real values instead of synthesised on read.
|
|
1494
80
|
|
|
1495
81
|
## 0.5.0
|
|
1496
82
|
|
|
1497
|
-
### Minor
|
|
1498
|
-
|
|
1499
|
-
- 69572fd: Align `spec/index.json` with the manifest changes declared in the `0.3.0` changelog (they had been documented but never written to the file), and fix two small referential drifts surfaced in the same audit pass.
|
|
1500
|
-
|
|
1501
|
-
**`spec/index.json`** — closes the gap between what `0.3.0` notes promised and what actually shipped:
|
|
1502
|
-
|
|
1503
|
-
- `specVersion` top-level field renamed to `indexPayloadVersion`. The old name collided semantically with `specPackageVersion` and with every other use of `specVersion` in the spec (compat logic, `scan-result.specVersion`, `sm help --format json`). `indexPayloadVersion` describes the shape of `index.json` itself and bumps only when this manifest's structure changes — pinned at `0.0.1` today. **This is the breaking rename already announced in the `0.3.0` release notes.**
|
|
1504
|
-
- `schemas.topLevel` gains `history-stats` (shape for `sm history stats --json`, already referenced from `cli-contract.md` §History and hashed under `integrity.files`).
|
|
1505
|
-
- New `schemas.extensions` subsection listing the 7 kind-manifest schemas (`base`, `adapter`, `detector`, `rule`, `action`, `audit`, `renderer`) — already required by `architecture.md` §Extension kinds for load-time manifest validation and already present under `schemas/extensions/`.
|
|
1506
|
-
|
|
1507
|
-
**`spec/versioning.md` §Change process step 4** — the parenthetical `(see CLAUDE.md: "Every feature: update spec/ first, then src/")` was stale. `CLAUDE.md` has been a bare `@AGENTS.md` pointer since the 18d0c20 dedup; the rule itself lives in `AGENTS.md`. Reference fixed.
|
|
1508
|
-
|
|
1509
|
-
**`spec/CHANGELOG.md` 0.3.0 entry** — text-only renumber of "decision #40a" → "decision #40". The sub-letter was a leftover from an unreleased draft; the roadmap Decision log uses `40` as the canonical anchor (see companion ROADMAP edit).
|
|
1510
|
-
|
|
1511
|
-
Classification: minor per §Pre-1.0 (`0.Y.Z`). The `specVersion → indexPayloadVersion` rename is breaking for any consumer that read the old field, but the old name never shipped alongside a file that spelled it `indexPayloadVersion` — the rename is being applied here for the first time, not re-applied. The `topLevel`/`extensions` additions are purely additive.
|
|
1512
|
-
|
|
1513
|
-
### Patch Changes
|
|
1514
|
-
|
|
1515
|
-
- 2699276: Fix the extension-kind schemas so they actually validate against real extension manifests.
|
|
1516
|
-
|
|
1517
|
-
The six kind schemas (`schemas/extensions/action.schema.json`, `adapter.schema.json`, `audit.schema.json`, `detector.schema.json`, `renderer.schema.json`, `rule.schema.json`) used `additionalProperties: false` together with `allOf: [{ $ref: "base.schema.json" }]` — a classic JSON Schema Draft 2020-12 footgun. `additionalProperties` is evaluated independently per schema in an `allOf`, so when a consumer validated `{ id, kind, version, emitsLinkKinds, defaultConfidence }` against `detector.schema.json`, detector's `additionalProperties: false` rejected `id` / `version` / `description` (defined only on `base`) and base's own `additionalProperties: false` would have rejected `emitsLinkKinds` / `defaultConfidence` — the union of both closures is empty. No real extension could ever pass validation.
|
|
1518
|
-
|
|
1519
|
-
Discovered during Step 1b while wiring the AJV validators in `skill-map` (kernel plugin loader). The right fix is `unevaluatedProperties: false` — it sees through `allOf` composition and only rejects keys that no sibling schema declared.
|
|
1520
|
-
|
|
1521
|
-
Changes:
|
|
1522
|
-
|
|
1523
|
-
- Every kind schema: `additionalProperties: false` → `unevaluatedProperties: false` at the manifest level. Nested `additionalProperties: false` declarations inside `$defs` / `properties` were likewise replaced with `unevaluatedProperties: false` where they participate in `allOf` composition (e.g. `action.schema.json#/$defs/Parameter`, `audit.schema.json` nested items).
|
|
1524
|
-
- `extensions/base.schema.json`: closure removed entirely. Closed-content is now enforced only on the kind schemas, which see base's properties as "evaluated" through the `allOf` — adding closure to base too would force every kind to re-list every base key to stay valid.
|
|
1525
|
-
- `base.schema.json` description updated to spell out the new composition rule so a future reader does not accidentally re-introduce the footgun.
|
|
83
|
+
### Minor
|
|
1526
84
|
|
|
1527
|
-
|
|
85
|
+
- **`spec/index.json` integrity sweep.** Reconciles `index.json` with the manifest changes documented in v0.3.0 but never written to the file. No prose / schema changes.
|
|
1528
86
|
|
|
1529
87
|
## 0.4.0
|
|
1530
88
|
|
|
1531
|
-
### Minor
|
|
1532
|
-
|
|
1533
|
-
- 334c51a: Document `--all` as targeted fan-out, not a global flag, in `spec/cli-contract.md`.
|
|
1534
|
-
|
|
1535
|
-
`--all` is valid only on verbs whose contract explicitly lists it:
|
|
1536
|
-
|
|
1537
|
-
- `sm plugins enable <id> | --all` and `sm plugins disable <id> | --all`.
|
|
1538
|
-
- `sm job cancel <job.id> | --all` (cancels every `queued` and `running` job).
|
|
1539
|
-
- `sm job submit <action> --all` and `sm job run --all`.
|
|
1540
|
-
|
|
1541
|
-
Unsupported `--all` usage is an operational error (exit `2`), the same as any other unknown or invalid flag.
|
|
1542
|
-
|
|
1543
|
-
Classification: minor — targeted fan-out semantics are additive for the listed verbs, while avoiding a global flag contract.
|
|
1544
|
-
|
|
1545
|
-
- 3e89d8f: Audit-driven alignment pass. Multiple normative additions and a casing cleanup:
|
|
1546
|
-
|
|
1547
|
-
- **Extension schemas**: add `spec/schemas/extensions/{base,adapter,detector,rule,action,audit,renderer}.schema.json` (7 new files). `architecture.md` §Extension kinds now points to them and mandates manifest validation at load time. Unblocks the "contract tests for the 6 kinds" invariant.
|
|
1548
|
-
- **Adapter `defaultRefreshAction`**: normatively required on every `Adapter` extension. Maps node `kind` → `actionId` and drives the UI's `🧠 prob` button. Previously mentioned only in ROADMAP (Decision #45); now part of the schema.
|
|
1549
|
-
- **Triple protection for mode B**: `db-schema.md` now specifies the exact order — parse → DDL validation → prefix injection → scoped connection. Validation runs **before** the rewrite so kernel-table references are caught under their authored names.
|
|
1550
|
-
- **Automatic rename heuristic**: new `db-schema.md` §Rename detection. On scan, `body_hash` match → high-confidence auto-rename with `state_*` FK migration; `frontmatter_hash` match → medium-confidence, same migration + `auto-rename-medium` issue; no match → orphan with issue. Replaces the prior "scan emits orphans, user runs `sm orphans reconcile` manually" flow.
|
|
1551
|
-
- **Skill agent envelope**: `job-events.md` now mandates a synthetic `r-ext-<ts>-<hex>` run envelope (`run.started mode=external` → `job.claimed` → `job.callback.received` → `job.completed|failed` → `run.summary`) around jobs claimed by a Skill agent without entering `sm job run`. Keeps the WebSocket broadcaster contract ("every job event inside a run envelope") intact across both runner paths.
|
|
1552
|
-
- **"Skill runner" → "Skill agent"**: `architecture.md` and `job-lifecycle.md` clarify that the Skill path is a peer driving adapter (alongside CLI and Server), NOT a `RunnerPort` implementation. Only `ClaudeCliRunner` and its test fake implement the port. Name was misleading; structure unchanged.
|
|
1553
|
-
- **Casing**: `db-schema.md` `auto_migrate` → `autoMigrate`; `README.md` prose mention `spec-compat` → `specCompat`. Brings prose into sync with the camelCase rule already enforced by the schemas.
|
|
1554
|
-
- **Coverage matrix**: new `spec/conformance/coverage.md` tracks each schema (and each non-schema normative artifact) against its conformance case. 28 schemas + 11 artifact invariants catalogued; 19 schemas and 10 artifacts flagged as missing, each with a step-blocker note. Release gate: v1.0.0 requires every row 🟢 or explicitly deferred.
|
|
1555
|
-
|
|
1556
|
-
Classification: minor per §Pre-1.0 (`0.Y.Z`). The new required field `defaultRefreshAction` on the Adapter kind is technically breaking — no conforming Adapter ships in the reference impl yet, so the impact is zero. Post-1.0 the same change would be major.
|
|
1557
|
-
|
|
1558
|
-
### Patch Changes
|
|
1559
|
-
|
|
1560
|
-
- 93ffe34: Editorial pass: remove "MVP" terminology from four prose documents.
|
|
1561
|
-
|
|
1562
|
-
The project shipped two competing readings of "MVP" — sometimes "`v0.5.0`", sometimes "the whole product through `v1.0`". That drift produced contradictions in companion docs (e.g. the summarizer pattern: was `v0.8.0` or `v0.5.0` supposed to ship them?). To close the ambiguity once, `ROADMAP.md` and `AGENTS.md` standardised on explicit versioned releases and `post-v1.0` in the same audit window. This change brings the four spec prose touches that still said "MVP" into the same vocabulary.
|
|
1563
|
-
|
|
1564
|
-
- **`cli-contract.md` §Jobs**: `sm job run --all` description `(MVP: sequential)` → `(sequential through v1.0; in-runner parallelism deferred)`.
|
|
1565
|
-
- **`job-events.md` §Event catalog**: `(post-MVP)` parallel-run note → `(deferred to post-v1.0)`.
|
|
1566
|
-
- **`job-lifecycle.md` §Concurrency**: `MVP (v0.x): one job at a time.` → `Through v1.0 (spec v0.x): one job at a time.`
|
|
1567
|
-
- **`plugin-kv-api.md` §Backup and retention**: `sm plugins forget <id> (post-MVP)` → `sm plugins forget <id> (deferred to post-v1.0)`.
|
|
89
|
+
### Minor
|
|
1568
90
|
|
|
1569
|
-
|
|
91
|
+
- **`--all` documented as targeted fan-out** in `cli-contract.md`. Valid only on verbs whose contract explicitly lists it.
|
|
1570
92
|
|
|
1571
93
|
## 0.3.0
|
|
1572
94
|
|
|
1573
|
-
### Minor
|
|
1574
|
-
|
|
1575
|
-
- 334c51a: Promote `--all` to a normative universal flag in `spec/cli-contract.md §Global flags`.
|
|
1576
|
-
|
|
1577
|
-
Any verb that accepts a target identifier (`-n <node.path>`, `<job.id>`, `<plugin.id>`) MUST accept `--all` as "apply to every eligible target matching the verb's preconditions". Mutually exclusive with a positional target or `-n <path>` on the same invocation. Verbs that inherently target everything (`sm scan` without `-n`, `sm list`, `sm check`, `sm doctor`) accept the flag as a no-op for script-composition uniformity. Verbs where fan-out is nonsensical (`sm record`, `sm init`, `sm version`, `sm help`, `sm config get/set/reset/show`, `sm db *`, `sm serve`) MUST reject `--all` with exit `2`.
|
|
1578
|
-
|
|
1579
|
-
Concretely extended in this pass:
|
|
1580
|
-
|
|
1581
|
-
- `sm plugins enable <id> | --all` and `sm plugins disable <id> | --all`.
|
|
1582
|
-
- `sm job cancel <job.id> | --all` (cancels every `queued` and `running` job).
|
|
1583
|
-
|
|
1584
|
-
Already normative before this change: `sm job submit <action> --all` and `sm job run --all`.
|
|
1585
|
-
|
|
1586
|
-
Classification: minor — new global flag semantics, backward compatible (existing invocations without `--all` behave identically). ROADMAP Decision #60 stays as the canonical narrative; this changeset brings the spec into line with it.
|
|
1587
|
-
|
|
1588
|
-
- 3e89d8f: Audit-driven alignment pass. Multiple normative additions and a casing cleanup:
|
|
1589
|
-
|
|
1590
|
-
- **Extension schemas**: add `spec/schemas/extensions/{base,adapter,detector,rule,action,audit,renderer}.schema.json` (7 new files). `architecture.md` §Extension kinds now points to them and mandates manifest validation at load time. Unblocks the "contract tests for the 6 kinds" invariant.
|
|
1591
|
-
- **Adapter `defaultRefreshAction`**: normatively required on every `Adapter` extension. Maps node `kind` → `actionId` and drives the UI's `🧠 prob` button. Previously mentioned only in ROADMAP (Decision #45); now part of the schema.
|
|
1592
|
-
- **Triple protection for mode B**: `db-schema.md` now specifies the exact order — parse → DDL validation → prefix injection → scoped connection. Validation runs **before** the rewrite so kernel-table references are caught under their authored names.
|
|
1593
|
-
- **Automatic rename heuristic**: new `db-schema.md` §Rename detection. On scan, `body_hash` match → high-confidence auto-rename with `state_*` FK migration; `frontmatter_hash` match → medium-confidence, same migration + `auto-rename-medium` issue; no match → orphan with issue. Replaces the prior "scan emits orphans, user runs `sm orphans reconcile` manually" flow.
|
|
1594
|
-
- **Skill agent envelope**: `job-events.md` now mandates a synthetic `r-ext-<ts>-<hex>` run envelope (`run.started mode=external` → `job.claimed` → `job.callback.received` → `job.completed|failed` → `run.summary`) around jobs claimed by a Skill agent without entering `sm job run`. Keeps the WebSocket broadcaster contract ("every job event inside a run envelope") intact across both runner paths.
|
|
1595
|
-
- **"Skill runner" → "Skill agent"**: `architecture.md` and `job-lifecycle.md` clarify that the Skill path is a peer driving adapter (alongside CLI and Server), NOT a `RunnerPort` implementation. Only `ClaudeCliRunner` and its test fake implement the port. Name was misleading; structure unchanged.
|
|
1596
|
-
- **Casing**: `db-schema.md` `auto_migrate` → `autoMigrate`; `README.md` prose mention `spec-compat` → `specCompat`. Brings prose into sync with the camelCase rule already enforced by the schemas.
|
|
1597
|
-
- **Coverage matrix**: new `spec/conformance/coverage.md` tracks each schema (and each non-schema normative artifact) against its conformance case. 28 schemas + 11 artifact invariants catalogued; 19 schemas and 10 artifacts flagged as missing, each with a step-blocker note. Release gate: v1.0.0 cut requires every row 🟢 or explicitly deferred.
|
|
1598
|
-
|
|
1599
|
-
Classification: minor per §Pre-1.0 (`0.Y.Z`). The new required field `defaultRefreshAction` on the Adapter kind is technically breaking — no conforming Adapter ships in the reference impl yet, so the impact is zero. Post-1.0 the same change would be major.
|
|
1600
|
-
|
|
1601
|
-
- d41b9ae: Close two gaps surfaced in the audit pass: config keys that `ROADMAP.md` promised but `project-config.schema.json` did not declare, and WebSocket event families that `ROADMAP.md §UI` mentioned ("scan updates + issue changes") but `job-events.md` did not cover.
|
|
1602
|
-
|
|
1603
|
-
**`project-config.schema.json` — new optional fields, all non-breaking:**
|
|
1604
|
-
|
|
1605
|
-
- `autoMigrate: boolean` (default `true`) — auto-apply pending kernel + plugin migrations at startup after auto-backup. `false` → startup fails fast if migrations are pending.
|
|
1606
|
-
- `tokenizer: string` (default `cl100k_base`) — name of the offline tokenizer; stored alongside counts so consumers know which encoder produced them.
|
|
1607
|
-
- `scan.maxFileSizeBytes: integer` (default `1048576`) — files larger are skipped with an `info` log.
|
|
1608
|
-
- `jobs.ttlSeconds: integer` (default `3600`) — global fallback TTL when an action manifest omits `expectedDurationSeconds` (typically `mode: local` actions where the field is advisory).
|
|
1609
|
-
- `jobs.perActionPriority: { <actionId>: integer }` — per-action priority overrides. Frozen on `state_jobs.priority` at submit time; overrides action manifest `defaultPriority`; overridden by CLI `--priority`. Ratifies decision #40 in the schema.
|
|
1610
|
-
- `jobs.retention: { completed, failed }` — GC policy for `state_jobs` rows. Defaults: `completed = 2592000` (30 days), `failed = null` (never auto-prune; keep for post-mortem). `sm job prune` reads these; no implicit pruning during normal verbs.
|
|
1611
|
-
|
|
1612
|
-
**`job-events.md` — new `Non-job events` section, Stability: experimental across v0.x:**
|
|
1613
|
-
|
|
1614
|
-
- `scan.*`: `scan.started`, `scan.progress` (throttled ≥250 ms), `scan.completed`.
|
|
1615
|
-
- `issue.*`: `issue.added`, `issue.resolved` — emitted after `scan.completed` when the new scan's issue set differs from the previous one. Diff key: `(ruleId, nodeIds sorted, message)`.
|
|
1616
|
-
- Synthetic run ids follow the existing `r-<mode>-YYYYMMDD-HHMMSS-XXXX` pattern (`r-scan-...`, `r-check-...`) alongside `r-ext-...` for external Skill claims.
|
|
1617
|
-
|
|
1618
|
-
These families ship at Step 13 of the reference impl alongside the WebSocket broadcaster. Marking them experimental keeps the shape mutable until real UI consumers exercise the stream; promotion to `stable` is a later minor bump.
|
|
1619
|
-
|
|
1620
|
-
Classification: minor per §Pre-1.0. All additions are optional fields in a permissive config schema and new event types outside the stable job family — zero impact on existing implementations. Matching `ROADMAP.md` §Notable config keys and §Progress events updates land in the same change.
|
|
1621
|
-
|
|
1622
|
-
- d41b9ae: Align the frontmatter tools story with Claude Code's own conventions (the audit pass surfaced that the spec had `tools` on agent only and no equivalent for skills, while `ROADMAP.md` decision #55 referenced a non-existent `expected-tools` field).
|
|
1623
|
-
|
|
1624
|
-
**`spec/schemas/frontmatter/base.schema.json` — two new top-level optional fields:**
|
|
1625
|
-
|
|
1626
|
-
- `tools: string[]` — **allowlist**. When present, the host MUST restrict the node to exactly these tools. Matches Claude Code's subagent `tools` frontmatter. Kind-specific interpretation: an `agent` uses it to lock the spawned subagent; a `skill` uses it as a declarative hint (skills typically inherit their parent's tools, but the field is carried for parity and discovery); other kinds use it as information only.
|
|
1627
|
-
- `allowedTools: string[]` — **pre-approval**. Tools the host MAY use without per-use permission prompts while the node is active. Distinct from `tools`: every other tool remains callable, governed by the host's normal permission settings. Matches Claude Code's skill `allowed-tools` frontmatter. Accepts argument-scoped patterns where the host supports them (e.g. `Bash(git add *)`).
|
|
1628
|
-
|
|
1629
|
-
**`spec/schemas/frontmatter/agent.schema.json`:** `tools` removed from the kind-specific body because it now lives on `base` and is inherited via `allOf`. The agent schema's title/description updated to reflect that only `model` remains kind-specific. Consumers reading `tools` from an agent frontmatter see no behavioural change — the field is still there, just sourced from `base`.
|
|
1630
|
-
|
|
1631
|
-
`expectedTools` on `extensions/action.schema.json` is unchanged. That field is a hint from an action template to the runner (which tools the rendered prompt expects access to) — a distinct semantics from the node-level `tools` / `allowedTools` pair, and the name difference preserves the distinction.
|
|
1632
|
-
|
|
1633
|
-
Classification: minor per §Pre-1.0. Additions to `base` are optional fields in a permissive schema (no break for existing frontmatter). Removing `tools` from the agent schema's own properties is compatible because `allOf: [base]` continues to supply it — any document that validated before still validates, any document that used `additionalProperties: true` is unaffected. Matching `ROADMAP.md` updates (§Frontmatter standard, decision #55) land in the same change.
|
|
1634
|
-
|
|
1635
|
-
- 5935948: Add `sm history stats` schema and normative elapsed-time reporting.
|
|
1636
|
-
|
|
1637
|
-
- **New schema** `spec/schemas/history-stats.schema.json`. Shape for `sm history stats --json`: `range` (configurable via `--since` / `--until`), `totals`, `tokensPerAction[]`, `executionsPerPeriod[]` (granularity via `--period day|week|month`, default `month`), `topNodes[]` (length via `--top N`, default 10), `errorRates` (global + per-action + per failure reason — all failure-reason enum values always present with `0` when unseen for predictable dashboards), and top-level `elapsedMs`. Duration stats in `tokensPerAction[]`: `durationMsMean` + `durationMsMedian` for MVP; percentiles deferred to a later minor bump.
|
|
1638
|
-
- **cli-contract.md §Elapsed time** (new normative section). Every verb that does non-trivial work MUST report its own wall-clock:
|
|
1639
|
-
- **Pretty (stderr)**: last line `done in <formatted>` where `<formatted>` ∈ `{ <N>ms | <N.N>s | <M>m <S>s }`. Suppressed by `--quiet`.
|
|
1640
|
-
- **JSON stdout**: top-level `elapsedMs` when the shape is an object; schemas whose shape is an array or ndjson don't carry it (stderr is the sole carrier).
|
|
1641
|
-
- **Exempt** verbs (sub-millisecond, informational): `sm --version`, `sm --help`, `sm version`, `sm help`, `sm config get`, `sm config list`, `sm config show`.
|
|
1642
|
-
- Measurement spans from after arg-parsing to before terminal write.
|
|
1643
|
-
- **cli-contract.md** `sm history stats` entry: flags enumerated (`--since`, `--until`, `--period`, `--top`) and schema referenced.
|
|
1644
|
-
- **Coverage matrix**: row `29` for `history-stats.schema.json` (blocked by Step 5); artifact row `L` for the elapsed-time reporting invariant (blocked by Step 4).
|
|
1645
|
-
|
|
1646
|
-
Classification: minor per §Pre-1.0. The elapsed-time contract introduces a SHOULD-emit line that didn't exist before — no existing consumer breaks, and the line goes to stderr where it doesn't clash with stdout JSON.
|
|
1647
|
-
|
|
1648
|
-
- 1455cb1: Normative `priority` for jobs.
|
|
1649
|
-
|
|
1650
|
-
The `state_jobs.priority` column (INTEGER, default `0`) existed in the schema and was used by the atomic-claim SQL (`ORDER BY priority DESC, createdAt ASC`), but no surface let the user set it. This release closes the gap:
|
|
1651
|
-
|
|
1652
|
-
- **`cli-contract.md` §Jobs**: new flag `sm job submit ... --priority <n>`. Integer; higher runs first; default `0`; negatives permitted (deprioritize).
|
|
1653
|
-
- **`job-lifecycle.md` §Submit**: new step 6 resolving priority with precedence `action manifest defaultPriority → user config jobs.perActionPriority.<actionId> → flag`. The resolved value is frozen on submit and immutable for the life of the job. Ties in the claim order break by `createdAt ASC`.
|
|
1654
|
-
- Configuration key `jobs.perActionPriority.<actionId>`: optional per-action integer override.
|
|
1655
|
-
- Action manifest `defaultPriority`: optional integer; defaults to `0` when omitted.
|
|
1656
|
-
|
|
1657
|
-
Classification: minor per `cli-contract.md` §Stability ("adding a flag is a minor bump"). No existing consumer breaks: jobs submitted before this release default to `0`, which is the identity element of the ordering. The claim SQL already read `priority`, so the wire protocol is unchanged.
|
|
1658
|
-
|
|
1659
|
-
- 1455cb1: Manifest alignment pass on `spec/index.json`: expose already-normative schemas, rename the payload-shape field, and add a stable version field consumers can rely on.
|
|
1660
|
-
|
|
1661
|
-
- **Rename `specVersion` → `indexPayloadVersion`** (breaking). The old name collided semantically with every other use of `specVersion` (compat logic in `versioning.md`, `scan-result.specVersion`, `sm help --format json`). The field describes the shape of `index.json` itself, not the spec a caller implements.
|
|
1662
|
-
- **New `specPackageVersion`** top-level field, auto-populated by `scripts/build-spec-index.mjs` from `spec/package.json.version`. This is the source of truth for "which `@skill-map/spec` release is this", previously missing from the manifest — consumers had to read `package.json` separately, and `sm version` was incorrectly reporting the payload-shape version as the spec version.
|
|
1663
|
-
- **`schemas.topLevel`** gains `history-stats` (shape for `sm history stats --json`, already referenced in `cli-contract.md` §History).
|
|
1664
|
-
- **New `schemas.extensions` subsection** lists the 7 kind-manifest schemas (`base`, `adapter`, `detector`, `rule`, `action`, `audit`, `renderer`) already required by `architecture.md` §Extension kinds for load-time manifest validation.
|
|
1665
|
-
- **CHANGELOG fix** on the `[Unreleased]` v0.1.0 line: "10 event types" → "11 canonical event types plus one synthetic `emitter.error`". Text-only correction on a shipped release.
|
|
1666
|
-
- **README example** updated to show both fields side-by-side so the distinction is obvious to first-time consumers.
|
|
1667
|
-
- **Integrity block** regenerated.
|
|
1668
|
-
|
|
1669
|
-
No schema contents change. The schema files and their normative status are unchanged since 0.1.0; the index now enumerates them all and uses unambiguous field names.
|
|
1670
|
-
|
|
1671
|
-
**Migration for consumers**: any caller that reads `specIndex.specVersion` MUST switch to `specIndex.specPackageVersion` (for the release) or `specIndex.indexPayloadVersion` (for the manifest shape). The rename is the source of the `minor` bump rather than `patch` — pre-1.0 minors MAY contain breaking changes per `versioning.md` §Pre-1.0.
|
|
1672
|
-
|
|
1673
|
-
Classification: minor per §Pre-1.0. One breaking rename + two additive fields + two additive schema subsections. The reference impl's `sm version` is updated in the same release to read `specPackageVersion`, so `sm version` now reports the actual npm package version (was the payload-shape version, a latent bug).
|
|
1674
|
-
|
|
1675
|
-
- 1455cb1: New CLI verb `sm orphans undo-rename <new.path> [--force]` to reverse a medium-confidence auto-rename.
|
|
1676
|
-
|
|
1677
|
-
The scan's rename heuristic (added in the previous spec release) migrates `state_*` FKs automatically when a deleted path and a newly-seen path share the same `frontmatter_hash` ("medium" confidence, body differs) and emits an `auto-rename-medium` issue for the user to verify. Until now the spec said "revert via `sm orphans reconcile --to <old.path>`", but `sm orphans reconcile` is defined for the forward direction (orphan path → live node) and awkward for the reverse case where both paths exist.
|
|
1678
|
-
|
|
1679
|
-
This release closes the gap with a dedicated reverse verb:
|
|
1680
|
-
|
|
1681
|
-
- **`cli-contract.md` §Browse**: new row `sm orphans undo-rename <new.path> [--force]`. Requires an active `auto-rename-medium` or `auto-rename-ambiguous` issue targeting `<new.path>`. Reads the prior path from `issue.data_json.from`, migrates `state_*` FKs back, resolves the issue. Exit `5` if no matching active issue.
|
|
1682
|
-
- **`db-schema.md` §Rename detection**: issue payload now normative.
|
|
1683
|
-
- `auto-rename-medium.data_json` MUST include `{ from, to, confidence: "medium" }`.
|
|
1684
|
-
- `auto-rename-ambiguous.data_json` MUST include `{ to, candidates: [from_a, from_b, ...] }`. `sm orphans undo-rename` requires `--from <old.path>` to pick one.
|
|
1685
|
-
- **Destructive verb**: prompts for confirmation unless `--force`. After undo, the prior path becomes an `orphan` (file no longer exists), emitting the normal `orphan` issue on next scan.
|
|
1686
|
-
|
|
1687
|
-
Rationale: dedicated name makes intent clear (forward = reconcile, reverse = undo-rename), failure is early (no active issue → immediate exit 5 with a helpful message), and the user does not re-type paths the kernel already knows.
|
|
1688
|
-
|
|
1689
|
-
Classification: minor per `cli-contract.md` §Stability ("adding a verb is a minor bump"). No existing behavior changes; `sm orphans reconcile` semantics are unaffected.
|
|
1690
|
-
|
|
1691
|
-
- 334c51a: **Breaking**: rename two state-zone tables to comply with the normative plural rule in `db-schema.md §Naming conventions`.
|
|
1692
|
-
|
|
1693
|
-
- `state_enrichment` → `state_enrichments`
|
|
1694
|
-
- `state_plugin_kv` → `state_plugin_kvs`
|
|
1695
|
-
|
|
1696
|
-
Index names renamed in lockstep:
|
|
1697
|
-
|
|
1698
|
-
- `ix_state_enrichment_stale_after` → `ix_state_enrichments_stale_after`
|
|
1699
|
-
- `ix_state_plugin_kv_plugin_id` → `ix_state_plugin_kvs_plugin_id`
|
|
1700
|
-
|
|
1701
|
-
The two tables were the only kernel-owned state-zone tables violating the rule "Tables: `snake_case`, plural" — every other catalog entry (`state_jobs`, `state_executions`, `state_summaries`, `config_plugins`, `config_preferences`, `config_schema_versions`, `scan_nodes`, `scan_links`, `scan_issues`) was already plural. The exceptions were historical drift, not intentional.
|
|
1702
|
-
|
|
1703
|
-
Updated spec artefacts:
|
|
1704
|
-
|
|
1705
|
-
- `spec/db-schema.md` — table section headings, column comments, primary-key footers, index names, and the cross-reference list in §Rename heuristic.
|
|
1706
|
-
- `spec/cli-contract.md` — `sm db reset --state` row in §Database.
|
|
1707
|
-
- `spec/plugin-kv-api.md` — §Overview opener and every downstream reference.
|
|
1708
|
-
- `spec/schemas/plugins-registry.schema.json` — description of the `kv` mode `const`.
|
|
1709
|
-
|
|
1710
|
-
**Migration for implementations**: no reference implementation has shipped the SQLite adapter yet (Step 1a lands it), so this is a rename-on-paper change. Any future kernel migration that creates these tables MUST use the plural names. Any third-party implementation already experimenting with the spec against the old names MUST rename before targeting `@skill-map/spec ≥ 0.3.0`.
|
|
1711
|
-
|
|
1712
|
-
Classification: **minor with breaking change**, per `spec/versioning.md §Pre-1.0` which allows breaking changes on minor bumps while the spec is `0.y.z`. Reference-impl touch: `src/kernel/ports/plugin-loader.ts` comment updated; no code paths read these names at runtime yet.
|
|
1713
|
-
|
|
1714
|
-
Companion prose updates in `ROADMAP.md` (§Persistence, §Plugin system, §Enrichment, §Summarizer pattern, Decision #61) and `AGENTS.md` (§Persistence).
|
|
1715
|
-
|
|
1716
|
-
- 93ffe34: Clean up `history.*` in `spec/schemas/project-config.schema.json`.
|
|
1717
|
-
|
|
1718
|
-
**Breaking (pre-1.0 minor per `versioning.md` §Pre-1.0):**
|
|
1719
|
-
|
|
1720
|
-
- **Remove** `history.retentionDays`. The field promised execution-record GC, but `ROADMAP.md` §Step 7 and the job-retention section make it explicit that `state_executions` is append-only in `v0.1` and that the kernel does not use this key. Declaring a config key whose behaviour is "silently ignored" is worse than not declaring it — consumers would wire it in and never see an effect. The field will be re-introduced in a later minor bump when the GC path actually lands, with a concrete default and enforcement semantics.
|
|
1721
|
-
|
|
1722
|
-
**Editorial:**
|
|
1723
|
-
|
|
1724
|
-
- `history.share.description` mentioned `./.skill-map/history.json` — an artefact of the pre-SQLite architecture. The actual DB is `./.skill-map/skill-map.db` (see `db-schema.md` §Scope and location). Description corrected; field itself unchanged.
|
|
1725
|
-
|
|
1726
|
-
Classification: minor per §Pre-1.0 (`0.Y.Z` may contain breaking changes in a minor bump). Integrity block regenerated via `npm run spec:index`. Companion prose in `ROADMAP.md §Notable config keys` updated in the same change.
|
|
1727
|
-
|
|
1728
|
-
**Migration for consumers**: any `.skill-map.json` that set `history.retentionDays` will now fail schema validation (`additionalProperties: false` on `history`). Remove the key; no kernel behaviour changes because nothing was consuming it.
|
|
1729
|
-
|
|
1730
|
-
- 93ffe34: Promote the trigger-normalization pipeline (Decision #21) from implicit to normative in `spec/architecture.md`.
|
|
1731
|
-
|
|
1732
|
-
Before this change, `link.trigger` carried `originalTrigger` and `normalizedTrigger` fields (defined in `schemas/link.schema.json`), and the `trigger-collision` rule keyed on the normalized value — but no spec prose documented **how** to normalize. The pipeline lived only in `AGENTS.md §Decisions already locked` and in `ROADMAP.md` as a one-line Step 7 bullet. That left implementations free to diverge, which silently breaks the `trigger-collision` rule across implementations (two conforming CLIs could disagree on whether `hacer-review` and `Hacer Review` collide).
|
|
1733
|
-
|
|
1734
|
-
Added under `architecture.md §Extension kinds`, paralleling the existing `Adapter · defaultRefreshAction` subsection:
|
|
1735
|
-
|
|
1736
|
-
- **Detector · trigger normalization** — field contract, normative 6-step pipeline, and 8 worked examples.
|
|
1737
|
-
|
|
1738
|
-
Pipeline (applied in exactly this order):
|
|
1739
|
-
|
|
1740
|
-
1. Unicode NFD.
|
|
1741
|
-
2. Strip Unicode `Mn` (diacritics).
|
|
1742
|
-
3. Lowercase (locale-independent).
|
|
1743
|
-
4. Separator unification: hyphen / underscore / any whitespace run → single ASCII space.
|
|
1744
|
-
5. Collapse whitespace (run of ≥2 spaces → 1 space).
|
|
1745
|
-
6. Trim leading/trailing whitespace.
|
|
1746
|
-
|
|
1747
|
-
Non-letter / non-digit characters outside the separator set (`/`, `@`, `:`, `.`, etc.) are **preserved** — stripping them is the detector's concern, not the normalizer's. This keeps namespaced invocations (`/skill-map:explore`, `@my-plugin/foo`) comparable in their intended form.
|
|
1748
|
-
|
|
1749
|
-
§Stability in `architecture.md` updated: adding a new step at the end is a minor bump; reordering, removing, or changing any existing step (including the character classes in step 4) is a major bump. Implementations that produce different `normalizedTrigger` output for equivalent input are non-conforming.
|
|
1750
|
-
|
|
1751
|
-
Classification: minor. The pipeline was always the intent (Decision #21 existed since the 2026-04-19 session) and `schemas/link.schema.json` already carried the fields, but this is the first time the spec prose binds implementations to a specific algorithm. A strict v0 implementation that did not normalize (or normalized differently) would begin failing conformance at the next spec release; worth a minor bump so plugin authors and alternative impls see it in the changelog.
|
|
1752
|
-
|
|
1753
|
-
Companion prose in `ROADMAP.md §Trigger normalization` (Decision #21 now points here for full rationale + examples).
|
|
1754
|
-
|
|
1755
|
-
### Patch Changes
|
|
1756
|
-
|
|
1757
|
-
- 334c51a: Clarify `sm orphans undo-rename` signature in `spec/cli-contract.md §Browse` by surfacing the `[--from <old.path>]` flag in the command cell itself.
|
|
1758
|
-
|
|
1759
|
-
The flag was already documented prose-only in `spec/db-schema.md §Rename heuristic` ("`auto-rename-ambiguous` issues ... `sm orphans undo-rename` requires the user to pass `--from <old.path>` to disambiguate") but was absent from the signature in the `cli-contract.md` table. A reader consulting only the CLI contract would miss the flag and assume the command took `<new.path>` alone.
|
|
1760
|
-
|
|
1761
|
-
The row now:
|
|
1762
|
-
|
|
1763
|
-
- Shows `[--from <old.path>] [--force]` in the signature.
|
|
1764
|
-
- Explicitly distinguishes the `auto-rename-medium` case (omit `--from`, previous path read from `issue.data_json`) from `auto-rename-ambiguous` (REQUIRES `--from` to pick from `data_json.candidates`).
|
|
1765
|
-
- Adds an exit-`5` condition for `--from` referencing a path not in `candidates`.
|
|
1766
|
-
|
|
1767
|
-
No behavioural change — the flag was already normative and implementations were already expected to support it. Classification: patch (clarifying drift between two spec prose docs, not a new capability).
|
|
1768
|
-
|
|
1769
|
-
- 93ffe34: Split `sm db reset` into three explicit levels of destruction, each with distinct semantics.
|
|
1770
|
-
|
|
1771
|
-
Before: `sm db reset` dropped BOTH `scan_*` and `state_*` in one command — so a user who wanted "please rescan from scratch" would wipe their job history, summaries, enrichment, and plugin KV data. The "reset" name suggested a soft operation; the behavior was aggressive.
|
|
1772
|
-
|
|
1773
|
-
After:
|
|
1774
|
-
|
|
1775
|
-
- `sm db reset` — drops `scan_*` only. Keeps `state_*` and `config_*`. Non-destructive, no prompt. Equivalent to asking for a fresh scan.
|
|
1776
|
-
- `sm db reset --state` — also drops `state_*` and every `plugin_<normalized_id>_*` table (mode B) plus `state_plugin_kvs` (mode A). Keeps `config_*`. Destructive; requires confirmation unless `--yes` (or `--force`, kept as an alias).
|
|
1777
|
-
- `sm db reset --hard` — deletes the DB file entirely. Keeps the plugins folder on disk. Destructive; requires confirmation unless `--yes`.
|
|
1778
|
-
|
|
1779
|
-
Updated files:
|
|
1780
|
-
|
|
1781
|
-
- `spec/cli-contract.md` §Database — new table rows and a rewritten confirmation paragraph.
|
|
1782
|
-
- `spec/db-schema.md` §Zones — one-liner rewritten to list all three levels.
|
|
1783
|
-
- `spec/plugin-kv-api.md` §Scope and lifecycle — three bullets replacing the single prior bullet, explicit about which reset level touches plugin storage.
|
|
1784
|
-
|
|
1785
|
-
Classification: patch in intent but **behavior-changing for `sm db reset` without modifier**. Implementations of `v0.x` that currently drop `state_*` on `sm db reset` MUST narrow the behavior; users relying on the old "reset = wipe everything below config" workflow must switch to `sm db reset --state`. Classified as patch because the spec is pre-1.0 and no implementation has shipped the CLI yet (Step 1a lands storage + the `sm db *` verbs together — this is the first time the boundary is normative in code).
|
|
1786
|
-
|
|
1787
|
-
Companion prose updates in `ROADMAP.md` §DB management commands and §Step 1a acceptance list.
|
|
1788
|
-
|
|
1789
|
-
- 93ffe34: Editorial pass: remove "MVP" terminology from four prose documents.
|
|
1790
|
-
|
|
1791
|
-
The project shipped two competing readings of "MVP" — sometimes "CUT 1 / `v0.5.0`", sometimes "the whole product through `v1.0`". That drift produced contradictions in companion docs (e.g. the summarizer pattern: was `v0.8.0` or `v0.5.0` supposed to ship them?). To close the ambiguity once, `ROADMAP.md` and `AGENTS.md` standardised on `CUT 1` / `CUT 2` / `CUT 3` and `post-v1.0` in the same audit window. This change brings the four spec prose touches that still said "MVP" into the same vocabulary.
|
|
1792
|
-
|
|
1793
|
-
- **`cli-contract.md` §Jobs**: `sm job run --all` description `(MVP: sequential)` → `(sequential through v1.0; in-runner parallelism deferred)`.
|
|
1794
|
-
- **`job-events.md` §Event catalog**: `(post-MVP)` parallel-run note → `(deferred to post-v1.0)`.
|
|
1795
|
-
- **`job-lifecycle.md` §Concurrency**: `MVP (v0.x): one job at a time.` → `Through v1.0 (spec v0.x): one job at a time.`
|
|
1796
|
-
- **`plugin-kv-api.md` §Backup and retention**: `sm plugins forget <id> (post-MVP)` → `sm plugins forget <id> (deferred to post-v1.0)`.
|
|
1797
|
-
|
|
1798
|
-
Classification: patch. Editorial only — no schema, exit code, verb signature, or MUST/SHOULD statement changes meaning. All four replacements preserve the technical content; only the label changes from project-scoped ("MVP") to version-scoped (`v1.0`), which is the convention the rest of the spec already uses. Integrity block regenerated.
|
|
1799
|
-
|
|
1800
|
-
- 93ffe34: Refresh the `spec/README.md` §Repo layout tree so it matches reality.
|
|
1801
|
-
|
|
1802
|
-
The previous tree was frozen at the Step 0a snapshot and listed only 20 schemas (9 top-level + 6 frontmatter + 5 summaries) plus outdated `(Step 0a phase N)` annotations. The actual spec ships 29 schemas (11 top-level + 7 extension + 6 frontmatter + 5 summaries) and the package adds `index.json` and `package.json`.
|
|
1803
|
-
|
|
1804
|
-
Changes:
|
|
1805
|
-
|
|
1806
|
-
- Show the full set of 29 JSON Schemas with a brace grouping per bucket, making the counts and the `allOf` inheritance (frontmatter kinds → base; summaries → report-base) legible at a glance.
|
|
1807
|
-
- Add the missing top-level schemas `conformance-case.schema.json` and `history-stats.schema.json`.
|
|
1808
|
-
- Add the whole `schemas/extensions/` folder (base + one per extension kind) — validated at plugin load.
|
|
1809
|
-
- List `package.json` and `index.json` explicitly so external readers know they are published assets.
|
|
1810
|
-
- Drop `(Step 0a phase N)` annotations — Step 0a is complete, the marker is noise.
|
|
1811
|
-
- Under `conformance/cases/`, note `basic-scan` and `kernel-empty-boot` as the two shipped cases and point at `../ROADMAP.md` for the deferred `preamble-bitwise-match` case.
|
|
1812
|
-
- Under `interfaces/`, clarify that `security-scanner.md` is a convention over the Action kind, NOT a 7th extension kind — the six kinds remain locked.
|
|
1813
|
-
|
|
1814
|
-
Classification: patch. Editorial prose only — no normative schema, rule, or contract changes. Companion updates to `ROADMAP.md` (repo layout + package layout) ship alongside; they are outside the spec package and do not need a changeset.
|
|
1815
|
-
|
|
1816
|
-
- d41b9ae: Promote the casing rule from implicit (stated only in `CHANGELOG.md` §Conventions locked and in individual schema descriptions) to explicit, with a new **Naming conventions** section in `spec/README.md`. Two rules, both normative:
|
|
1817
|
-
|
|
1818
|
-
- **Filesystem artefacts in kebab-case**: every file, directory, enum value, and `issue.ruleId` value. Values stay URL/filename/log-key safe without escaping.
|
|
1819
|
-
- **JSON content in camelCase**: every key in schemas, frontmatter, configs, manifests, job records, reports, event payloads, API responses. The SQL layer (`snake_case`) is the sole exception, bridged by the storage adapter.
|
|
1820
|
-
|
|
1821
|
-
Companion alignment in `spec/db-schema.md` §Rename detection: the prose mixed column names (`body_hash`, `frontmatter_hash`, `rule_id`, `data_json`) with domain-object references. The heuristic is specified against the domain types (`bodyHash`, `frontmatterHash`, `ruleId`, `data`) as defined in `node.schema.json` / `issue.schema.json`; the SQLite columns are the storage shape, not the contract. Added a one-line casing note that points back to §Naming conventions so the bridge is explicit.
|
|
1822
|
-
|
|
1823
|
-
Classification: patch. The rule itself is unchanged — it was already enforced by every shipped schema and repeated in `CHANGELOG.md`. The additions are purely documentary so new implementers find the rule without digging through the changelog, and so the rename-detection prose stops looking like it references SQLite-specific identifiers when it means domain-object fields.
|
|
1824
|
-
|
|
1825
|
-
- 93ffe34: Clarify the TTL resolution procedure in `spec/job-lifecycle.md`.
|
|
1826
|
-
|
|
1827
|
-
The previous text defined the formula as `ttlSeconds = max(expectedDurationSeconds × graceMultiplier, minimumTtlSeconds)` and said the precedence chain was `global default → manifest → user config → flag`. Two problems:
|
|
1828
|
-
|
|
1829
|
-
- When `expectedDurationSeconds` is absent from the manifest (typical for `mode: local` actions), the formula is undefined. The existing config key `jobs.ttlSeconds` was documented elsewhere as a "global fallback" but never tied into the formula.
|
|
1830
|
-
- The word "precedence" collapsed three distinct mechanisms — base value selection, formula application, and full override — into one list, so `minimumTtlSeconds` (a floor, never a default) appeared as the first entry of a "later wins" chain.
|
|
1831
|
-
|
|
1832
|
-
This patch rewrites the §TTL precedence section as §TTL resolution, split into three explicit steps:
|
|
1833
|
-
|
|
1834
|
-
1. **Base duration**: manifest `expectedDurationSeconds` OR config `jobs.ttlSeconds` (default `3600`).
|
|
1835
|
-
2. **Computed TTL**: `max(base × graceMultiplier, minimumTtlSeconds)`.
|
|
1836
|
-
3. **Overrides** (later wins, skips formula): `jobs.perActionTtl.<actionId>`, then `--ttl` flag.
|
|
1837
|
-
|
|
1838
|
-
Five worked examples added. Negative / zero overrides are rejected at submit time (exit 2). A Stability note states the procedure is locked going forward — new override sources are minor, formula-shape changes are major. The §Submit checklist step 5 now references the new §TTL resolution section instead of inlining a broken one-liner.
|
|
1839
|
-
|
|
1840
|
-
Classification: patch. No field or schema changed. Every existing manifest and config combination resolves to the same TTL except for the previously-undefined case (manifest without `expectedDurationSeconds`), which was silently implementation-defined; the new text makes the `jobs.ttlSeconds` fallback normative. Companion prose updates land in `ROADMAP.md §TTL per action` and §Notable config keys.
|
|
1841
|
-
|
|
1842
|
-
## 0.2.1
|
|
1843
|
-
|
|
1844
|
-
### Patch Changes
|
|
95
|
+
### Minor
|
|
1845
96
|
|
|
1846
|
-
-
|
|
97
|
+
- **`--all` promoted to a normative universal flag** in `cli-contract.md §Global flags`. Any verb that accepts a target identifier (`-n <node.path>`, `<job.id>`, `<plugin.id>`) MUST accept `--all` as "apply to every eligible target matching the verb's preconditions". Mutually exclusive with a positional target on the same invocation. Verbs where fan-out is nonsensical (`sm record`, `sm init`, `sm version`, `sm help`, `sm config get/set/reset/show`, `sm db *`, `sm serve`) MUST reject `--all` with exit `2`.
|
|
1847
98
|
|
|
1848
99
|
## 0.2.0
|
|
1849
100
|
|
|
1850
|
-
### Minor
|
|
1851
|
-
|
|
1852
|
-
- 79aed4d: **Breaking**: rename `dispatch-lifecycle.md` → `job-lifecycle.md`.
|
|
1853
|
-
|
|
1854
|
-
ROADMAP decision #30 renamed the domain term "dispatch" to "job" (tables `state_jobs`, artifact "job file"). The spec prose filename had lagged behind; this change closes that gap.
|
|
1855
|
-
|
|
1856
|
-
All internal references updated: `architecture.md`, `cli-contract.md`, `db-schema.md`, `prompt-preamble.md`, `versioning.md`, `schemas/job.schema.json`, `README.md`, and `package.json` `files` list. `index.json` regenerated.
|
|
1857
|
-
|
|
1858
|
-
**Migration**: any external consumer that links to `spec/dispatch-lifecycle.md` (by URL or filename) MUST update to `spec/job-lifecycle.md`. The canonical URL becomes `https://skill-map.dev/spec/v0/job-lifecycle.md`.
|
|
1859
|
-
|
|
1860
|
-
Classification: breaking change on a normative prose doc. Per `versioning.md` §Pre-1.0, minor bumps MAY contain breaking changes while the spec is `0.Y.Z`.
|
|
1861
|
-
|
|
1862
|
-
## 0.1.2
|
|
1863
|
-
|
|
1864
|
-
### Patch Changes
|
|
1865
|
-
|
|
1866
|
-
- f4214fe: Expand `spec/README.md` §Distribution with concrete install and usage snippets now that `@skill-map/spec` is live on npm: install command, loading a schema via `exports`, and a small integrity-verification example using the `index.json` sha256 block.
|
|
1867
|
-
|
|
1868
|
-
## 0.1.1
|
|
1869
|
-
|
|
1870
|
-
### Patch Changes
|
|
101
|
+
### Minor
|
|
1871
102
|
|
|
1872
|
-
-
|
|
103
|
+
- **`@skill-map/spec` published on npm.** First public release of the spec package.
|
|
1873
104
|
|
|
1874
105
|
## 0.1.0
|
|
1875
106
|
|
|
1876
|
-
### Minor
|
|
1877
|
-
|
|
1878
|
-
- 5b3829a: Add conformance case `kernel-empty-boot`:
|
|
1879
|
-
|
|
1880
|
-
- New file: `spec/conformance/cases/kernel-empty-boot.json`.
|
|
1881
|
-
- Exercises the boot invariant from `architecture.md`: with every adapter, detector, and rule disabled, scanning an empty scope MUST return a valid `ScanResult` with `schemaVersion: 1` and zero-filled stats.
|
|
1882
|
-
- Referenced in `conformance/README.md` (§"Cases explicitly referenced elsewhere in the spec"). Entry moved from "pending" to "current" in the case inventory.
|
|
1883
|
-
- Registered in `spec/index.json` and the integrity block (SHA256 regenerated).
|
|
1884
|
-
|
|
1885
|
-
The second pending case, `preamble-bitwise-match`, is deferred to Step 10 (requires `sm job preview` from the job subsystem).
|
|
1886
|
-
|
|
1887
|
-
- 4e0aec4: Initial public spec surface (`v0.1.0`):
|
|
1888
|
-
|
|
1889
|
-
- 21 JSON Schemas (draft 2020-12): 10 top-level, 6 frontmatter, 5 summaries.
|
|
1890
|
-
- 7 prose contracts (architecture, cli-contract, dispatch-lifecycle, job-events, prompt-preamble, db-schema, plugin-kv-api).
|
|
1891
|
-
- 1 interface doc (security-scanner).
|
|
1892
|
-
- Conformance stub: `basic-scan` case, `minimal-claude` fixture, verbatim `preamble-v1.txt`.
|
|
1893
|
-
- Machine-readable `index.json` with integrity hashes per file.
|
|
1894
|
-
|
|
1895
|
-
This is the first tagged release of the skill-map specification.
|
|
1896
|
-
|
|
1897
|
-
Changelog for the **skill-map specification**, tracked independently from the reference CLI. See `versioning.md` for the policy that governs what constitutes a patch / minor / major change.
|
|
1898
|
-
|
|
1899
|
-
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) as refined in `versioning.md`.
|
|
1900
|
-
|
|
1901
|
-
Each entry classifies changes into four sections:
|
|
1902
|
-
|
|
1903
|
-
- **Added** — new optional fields, schemas, or contracts.
|
|
1904
|
-
- **Changed** — modifications to existing normative content. Breaking changes are called out explicitly.
|
|
1905
|
-
- **Deprecated** — features scheduled for removal in a future major.
|
|
1906
|
-
- **Removed** — features removed in a major bump.
|
|
1907
|
-
|
|
1908
|
-
Tag convention: `spec-vX.Y.Z` (distinct from CLI tags `cli-vX.Y.Z`).
|
|
1909
|
-
|
|
1910
|
-
---
|
|
1911
|
-
|
|
1912
|
-
## [Unreleased]
|
|
1913
|
-
|
|
1914
|
-
Initial public spec bootstrap (Step 0a phases 1–3).
|
|
1915
|
-
|
|
1916
|
-
### Added
|
|
1917
|
-
|
|
1918
|
-
- `cli-contract.md` — new normative section **§Dry-run** between §Exit codes and §Verb catalog. Codifies the contract every verb that exposes `-n` / `--dry-run` MUST honour: no observable side effects (DB / FS / config / network / spawns), no auto-provisioning of scope directories, output mirrors live mode with explicit "would …" framing, exit codes mirror live mode, dry-run MUST short-circuit `--yes` / `--force` confirmation prompts. Per-verb opt-in: the flag is not global and verbs that don't declare it MUST reject it as an unknown option (exit `2`). Verb catalog rows for `sm init`, `sm db reset` (default + `--state` + `--hard`), and `sm db restore` amended to declare and describe their `--dry-run` previews. Pre-1.0 minor (additive normative).
|
|
1919
|
-
- `plugin-author-guide.md` — consolidated section on the three-tier frontmatter validation model (default permissive `additionalProperties: true` + always-active `unknown-field` rule emitting `warn` + `scan.strict` / `--strict` promoting warnings to `error`). Includes a worked example through all three tiers and an explicit note on why no "schema-extender" plugin kind exists (the path for custom validation is a deterministic Rule, not a new plugin kind). Editorial only. No normative change — the model already exists implicitly via `base.schema.json`'s permissive `additionalProperties` and `project-config.schema.json#/properties/scan/properties/strict`. Patch.
|
|
1920
|
-
- `PluginManifest` gains optional `granularity` field (enum `bundle` / `extension`, default `bundle`). Built-in `claude` bundle is `granularity: bundle` (toggle the whole bundle); built-in `core` bundle is `granularity: extension` (each built-in toggle-able individually under `core/<ext-id>`). `sm plugins enable / disable` validates the supplied id against the bundle's declared granularity (bundle granularity rejects qualified ids; extension granularity rejects bare bundle ids) and persists in `config_plugins` with the appropriate key. `--all` operates only on bundle-granularity plugin ids; the "disable every kernel built-in" intent is served by `--no-built-ins`. `plugin-author-guide.md` adds a §Granularity — bundle vs extension section with the per-verb behaviour table and the built-in mapping; `architecture.md` §`PluginLoaderPort` documents the runtime split (loader's pre-import resolveEnabled is coarse / bundle-level; the CLI's runtime composer drops per-extension disabled extensions before they reach the orchestrator). Closes the spec-vs-impl drift between the spec promise that "no extension is privileged, removable" and the prior implementation where built-ins were always-on. Pre-1.0 minor per `versioning.md` § Pre-1.0; additive on the manifest schema, breaking only for users who relied on the `claude` adapter loading without an explicit `config_plugins` row (none today, since the row had no effect on built-ins before).
|
|
1921
|
-
- Detector manifest gains optional `applicableKinds` filter (array, `minItems: 1`, kebab-case strings, `uniqueItems: true`). When declared, the kernel skips invocation for nodes whose `kind` is not in the list — fail-fast, before the detect context is built, so a probabilistic detector wastes zero LLM cost (and a deterministic detector zero CPU) on inapplicable nodes. Absent = applies to every kind (the default); no wildcard syntax. Empty array `[]` is rejected at load time. Unknown kinds (no installed Adapter declares them via `defaultRefreshAction`) load OK with a `sm plugins doctor` warning — the Provider may arrive later — and the doctor exit code is NOT promoted by the warning. `plugin-author-guide.md` adds a §Detector `applicableKinds` — narrow the pipeline section under Granularity with the per-shape behaviour table and a worked example; `architecture.md` adds a §Detector · `applicableKinds` filter subsection above trigger normalization; `schemas/extensions/detector.schema.json` declares the new property. Pre-1.0 minor per `versioning.md` § Pre-1.0; additive, non-breaking for existing detectors (they all behave as if `applicableKinds: undefined`).
|
|
1922
|
-
|
|
1923
|
-
### Changed
|
|
1924
|
-
|
|
1925
|
-
- `cli-contract.md`: `--all` is no longer a global flag. It is valid only on verbs that explicitly document fan-out semantics: `sm job submit`, `sm job run`, `sm job cancel`, and `sm plugins enable/disable`.
|
|
1926
|
-
- `cli-contract.md`: `sm scan compare-with <dump> [roots...]` is now a sub-verb instead of a `--compare-with <path>` flag on `sm scan`. Read-only delta report against a saved `ScanResult` JSON dump. Same exit codes (`0` empty delta / `1` drift / `2` operational error). Old flag form removed. Pre-1.0 breaking change shipped as minor per `versioning.md` § Pre-1.0.
|
|
1927
|
-
- Plugin discovery — directory name MUST equal manifest id (else `invalid-manifest`); cross-root id collisions yield new `id-collision` status (sixth status, both collided plugins blocked, no precedence). `plugin-author-guide.md` Diagnostics table grows from five to six rows; `architecture.md` §`PluginLoaderPort` documents the two enforcement points; `schemas/plugins-registry.schema.json#/$defs/DiscoveredPlugin/status` adds `id-collision` to the enum. Pre-1.0 minor per `versioning.md` § Pre-1.0; breaking for any plugin whose directory name does not match its manifest id, but no real ecosystem affected today.
|
|
1928
|
-
- Plugin extensions are now identified by qualified ids `<plugin-id>/<extension-id>`. Built-in extensions adopt the `core/` namespace; the Claude adapter and its kind-aware detectors (frontmatter, slash, at-directive) live under `claude/`. The loader injects `pluginId` from `plugin.json#/id` into every extension at load time; an explicit `pluginId` field on an extension that disagrees with the manifest id is `invalid-manifest`. `architecture.md` §`PluginLoaderPort` documents the qualifier composition; `plugin-author-guide.md` adds a §Qualified extension ids section with the built-in mapping table; `schemas/extensions/base.schema.json` clarifies that extension `id` stays unqualified (single kebab-case segment, no `/`); `schemas/extensions/adapter.schema.json#/properties/defaultRefreshAction` now requires qualified action ids (pattern `^<plugin-id>/<action-id>$`). Pre-1.0 minor per `versioning.md` § Pre-1.0; breaking for any plugin or test that referenced an extension by short id.
|
|
1929
|
-
- `cli-contract.md`: exit-code `2` "Operational error" row clarified to mention runtime / environment mismatches (wrong Node version, missing native dependency) explicitly. The "unhandled exception" catch-all already covered the case; this just removes ambiguity for future implementers.
|
|
1930
|
-
- `job-events.md`: the common `runId` envelope now explicitly documents the optional mode segment (`r-<mode>-YYYYMMDD-HHMMSS-XXXX`) used by external Skill claims, scan runs, and standalone issue recomputations.
|
|
1931
|
-
- `versioning.md` and related prose: replace ambiguous milestone terminology with explicit versioned release language.
|
|
1932
|
-
|
|
1933
|
-
### Added
|
|
1934
|
-
|
|
1935
|
-
- Foundation:
|
|
1936
|
-
- `README.md` — human-readable introduction and repo layout.
|
|
1937
|
-
- `versioning.md` — evolution policy, stability tags, 3-minor deprecation window.
|
|
1938
|
-
- `CHANGELOG.md` — this file.
|
|
1939
|
-
- JSON Schemas (21 files, all draft 2020-12, camelCase keys):
|
|
1940
|
-
- Top-level (10): `node`, `link`, `issue`, `scan-result`, `execution-record`, `project-config`, `plugins-registry`, `job`, `report-base`, `conformance-case`.
|
|
1941
|
-
- Frontmatter (6): `base` + per-kind `skill` / `agent` / `command` / `hook` / `note`. Per-kind schemas extend `base` via `allOf`.
|
|
1942
|
-
- Summaries (5): per-kind `skill` / `agent` / `command` / `hook` / `note`. All extend `report-base` via `allOf`.
|
|
1943
|
-
- Prose contracts:
|
|
1944
|
-
- `architecture.md` — hexagonal ports & adapters; 5 ports (`StoragePort`, `FilesystemPort`, `PluginLoaderPort`, `RunnerPort`, `ProgressEmitterPort`); 6 extension kinds (Adapter, Detector, Rule, Action, Audit, Renderer); kernel boundary + forbidden/permitted imports.
|
|
1945
|
-
- `cli-contract.md` — CLI surface: global flags, env vars, 30+ verbs (`sm init`, `sm scan`, `sm list`, `sm show`, `sm check`, `sm findings`, `sm graph`, `sm export`, `sm job *`, `sm record`, `sm history`, `sm plugins *`, `sm audit *`, `sm db *`, `sm serve`, `sm help`), exit codes (0–5 defined, 6–15 reserved), `--json` output rules, `--format json|md|human` introspection.
|
|
1946
|
-
- `dispatch-lifecycle.md` — job state machine (queued → running → completed | failed), atomic claim (`UPDATE ... RETURNING id`), duplicate prevention via `contentHash`, TTL with auto-reap, nonce authentication for `sm record`, sequential concurrency for MVP, retention and GC.
|
|
1947
|
-
- `job-events.md` — canonical event stream: envelope (`type`, `timestamp`, `runId`, `jobId`, `data`), 11 canonical event types (`run.started`, `run.reap.started`, `run.reap.completed`, `job.claimed`, `job.skipped`, `job.spawning`, `model.delta`, `job.callback.received`, `job.completed`, `job.failed`, `run.summary`) plus one synthetic error event (`emitter.error`, emitted only on serialization failure), three output adapters (`pretty`, `stream-output`, `json`), ordering rules.
|
|
1948
|
-
- `prompt-preamble.md` — verbatim normative preamble text that the kernel prepends to every rendered job file; `<user-content id="...">` delimiter contract with zero-width-space escaping; `safety` + `confidence` contract on model output; conformance fixture at `conformance/fixtures/preamble-v1.txt`.
|
|
1949
|
-
- `db-schema.md` — engine-agnostic table catalog: three zones (`scan_*`, `state_*`, `config_*`), naming conventions (snake*case, zone prefix, `_at` / `_ms` / `_hash` / `_json` / `_count` suffixes, `is*`/`has\_` prefixes), kernel table list per zone, migration rules (`.sql`files,`NNN_snake_case.sql`, up-only, auto-backup), plugin storage modes.
|
|
1950
|
-
- `plugin-kv-api.md` — `ctx.store` contract for mode A (`KvStore.get/set/delete/list`, plugin-scoped, optional node-scoped), mode B dedicated-tables rules (prefix injection, DDL validation, scoped Database wrapper), typed errors (`KvKeyInvalidError`, `KvValueNotSerializableError`, `KvValueTooLargeError`, `KvOperationFailedError`, `ScopedDbViolationError`). Mixing modes in a plugin is forbidden.
|
|
1951
|
-
- Interfaces:
|
|
1952
|
-
- `interfaces/security-scanner.md` — convention over the Action kind (id prefix `security-`) for third-party security scanners (Snyk, Socket, custom). Defines `SecurityReport` shape extending `report-base.schema.json`, normative finding categories, deduplication rules, aggregation via `sm findings --security`. Marked `Stability: experimental` through v0.x.
|
|
1953
|
-
|
|
1954
|
-
### Conventions locked (normative)
|
|
1955
|
-
|
|
1956
|
-
- JSON Schema dialect: draft 2020-12.
|
|
1957
|
-
- Casing: camelCase for all JSON keys (domain, configs, manifests, reports); kebab-case for filenames.
|
|
1958
|
-
- `$id` scheme: `https://skill-map.dev/spec/v<major>/<path>.schema.json`. `v0` throughout pre-1.0; bumps to `v1` at the first stable release.
|
|
1959
|
-
- Identity: `node.path` (relative to scope root) is the canonical node identifier in v0. Future UUID-based `node.id` lands with write-back.
|
|
1960
|
-
- Required frontmatter: `name`, `description`, `metadata`, `metadata.version`.
|
|
1961
|
-
- Frontmatter: `additionalProperties: true` (rules handle unknown fields). Summaries: `additionalProperties: false` (strict).
|
|
1962
|
-
- Id prefixes: job `d-`, execution record `e-`, run `r-` (all `PREFIX-YYYYMMDD-HHMMSS-XXXX`).
|
|
1963
|
-
- Exit codes: 0 ok / 1 issues / 2 error / 3 duplicate / 4 nonce-mismatch / 5 not-found.
|
|
1964
|
-
- Deprecation window: 3 minor releases between `stable → deprecated` and removal.
|
|
1965
|
-
- Storage modes: a plugin declares exactly one (`kv` or `dedicated`). Mixing forbidden.
|
|
1966
|
-
|
|
1967
|
-
### Conformance (stub)
|
|
1968
|
-
|
|
1969
|
-
- `conformance/README.md` — suite layout, case format, assertion types (`exit-code`, `json-path`, `file-exists`, `file-contains-verbatim`, `file-matches-schema`, `stderr-matches`), runner pseudocode.
|
|
1970
|
-
- `conformance/fixtures/minimal-claude/` — 5 MDs (one per kind: skill, agent, command, hook, note) used as the first controlled corpus.
|
|
1971
|
-
- `conformance/fixtures/preamble-v1.txt` — verbatim extraction of the preamble from `prompt-preamble.md`, checked byte-for-byte by the future `preamble-bitwise-match` case.
|
|
1972
|
-
- `conformance/cases/basic-scan.json` — first declarative case. Scans the `minimal-claude` fixture; asserts `schemaVersion: 1`, 5 nodes, 0 issues.
|
|
1973
|
-
|
|
1974
|
-
### Packaging
|
|
1975
|
-
|
|
1976
|
-
- `package.json` at the spec root. Name: `@skill-map/spec`. Version `0.0.1` (first release line; spec versioning is strict pre-1.0 per `versioning.md`). `exports` surfaces `.` → `index.json`, plus every `./schemas/*.json`.
|
|
1977
|
-
- `index.json` at the spec root. Machine-readable manifest of schemas, prose, interfaces, and conformance. Carries an `integrity` block with a sha256 per shipped file, deterministically regenerated by `scripts/build-spec-index.mjs`. CI blocks drift via `npm run spec:check`.
|
|
1978
|
-
- `schemas/conformance-case.schema.json` — formal schema for entries under `conformance/cases/*.json`. Defines the `invoke` object and the six assertion types (`exit-code`, `json-path`, `file-exists`, `file-contains-verbatim`, `file-matches-schema`, `stderr-matches`) as a discriminated union via `oneOf`.
|
|
1979
|
-
|
|
1980
|
-
### Notes
|
|
107
|
+
### Minor
|
|
1981
108
|
|
|
1982
|
-
-
|
|
1983
|
-
- No tagged spec release yet. First tag (`spec-v0.1.0`) lands after Step 0b CI validates the implementation against this stub.
|
|
1984
|
-
- Release pipeline: `@skill-map/spec` is published via [changesets](https://github.com/changesets/changesets). Every PR that touches `spec/` includes a `.changeset/*.md` declaring the bump; merging to `main` opens a "Version Packages" PR; merging that PR publishes to npm and tags the release. See `CONTRIBUTING.md`.
|
|
109
|
+
- **Initial public spec bootstrap.** Ships the JSON Schemas (draft 2020-12) for `Node` / `Link` / `Issue` / `ScanResult` / `ExecutionRecord` / `ProjectConfig` / `PluginsRegistry` / `Job` / `ReportBase` / `ConformanceCase` / `HistoryStats` plus the per-kind extension schemas (Provider / Extractor / Rule / Action / Formatter / Hook). Prose normative contracts: `cli-contract.md`, `architecture.md`, `db-schema.md`, `job-lifecycle.md`, `job-events.md`, `prompt-preamble.md`, `plugin-kv-api.md`. Conformance case `kernel-empty-boot` exercises the boot invariant (kernel boots and returns an empty `ScanResult` with zero registered extensions); `preamble-bitwise-match` is deferred to Step 10.
|