@skill-map/spec 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,255 @@
1
1
  # Spec changelog
2
2
 
3
+ ## 0.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4e0646c: Document the LLM-aligned semantics that landed in `core/at-directive`
8
+ and `core/slash`. `spec/plugin-author-guide.md` § Extractors now
9
+ describes the dispatch rules the built-ins follow: bare and
10
+ namespaced `@<handle>` tokens emit `mentions`, file-flavoured
11
+ `@<...>.ext` / `@./<...>` / `@/<...>` tokens emit `references`,
12
+ `/<token>` is dropped when followed by another identifier or slash
13
+ (path / URL territory), and both extractors strip fenced + inline
14
+ code regions before matching. Plus a normative note in
15
+ `spec/db-schema.md` § Rename detection: the `orphan` info issue is
16
+ suppressed when the disappeared `deletedPath` is currently filtered
17
+ by the active ignore-source (still on disk, just silenced).
18
+
19
+ ## 0.28.0
20
+
21
+ ### Minor Changes
22
+
23
+ - e21216e: Simplify plugin manifest fields beyond the file-layout refactor. The
24
+ previous `structure-as-truth-plugins` changeset moved bundle / kind /
25
+ id discovery onto the filesystem; this one extends the same principle
26
+ into the manifest schemas themselves so the only fields that survive
27
+ are the ones the kernel cannot derive from disk.
28
+
29
+ **Plugin manifest (`plugin.json`):**
30
+
31
+ - Drop `id` (the directory name is the id; AJV rejects manifests that
32
+ declare it).
33
+ - `description` and `catalogCompat` are now required (were optional).
34
+ - `granularity` is now optional with a default of `'extension'` (was
35
+ required). Most plugins drop the field entirely.
36
+ - Drop `settings` at the plugin level; settings move to the extension
37
+ manifests that actually consume them.
38
+
39
+ **Extension base (every kind):**
40
+
41
+ - Drop `id`, `kind`, `stability`, `preconditions` (free-form). The
42
+ loader injects `id` / `kind` / `pluginId` from the folder layout;
43
+ the other two were display-only and free-form respectively, and
44
+ the kernel never consumed them.
45
+ - `description` is now required.
46
+ - Rename `annotationContributions` (map) to `annotation` (singular):
47
+ one extension contributes at most one annotation key, and the key
48
+ is the extension's folder name. Use multiple extensions to
49
+ contribute multiple keys.
50
+ - Rename `viewContributions` to `ui` on the manifest. The
51
+ runtime-aggregated catalog (`Kernel.getRegisteredViewContributions()`,
52
+ `IPluginRuntimeBundle.viewContributions`) keeps its name.
53
+ - Add `settings: Record<id, ISettingDeclaration>` (moved from the
54
+ plugin manifest).
55
+
56
+ **Provider:**
57
+
58
+ - Drop the inline `kinds` map. The kind catalog now lives under
59
+ `<plugin>/kinds/<kindName>/` with two files per kind:
60
+ `schema.json` (frontmatter schema) and `kind.json` carrying the
61
+ `{ ui }` block. The loader walks the directory and projects each
62
+ entry into the runtime `kinds` descriptor.
63
+ - New schema `extensions/provider-kind.schema.json` validates the
64
+ `kind.json` shape.
65
+ - Drop `defaultRefreshAction`. The UI's `🧠 prob` refresh button is
66
+ retired; a replacement UX is TBD.
67
+ - `roots` is enforcement-grade: a Provider with declared `roots`
68
+ only sees files matching at least one glob; a Provider without
69
+ `roots` acts as the fallback for files unmatched by any other
70
+ Provider. Supported patterns: `prefix/**` (deep), `prefix/*`
71
+ (shallow), exact path. Two Providers whose roots both match the
72
+ same file produce `provider-ambiguous` (already in spec) and the
73
+ file stays unclassified.
74
+
75
+ **Extractor:**
76
+
77
+ - Drop `emitsLinkKinds` (the global closed enum of link kinds is the
78
+ contract; off-enum emissions drop with `extension.error`).
79
+ - Drop `defaultConfidence` (declare confidence per-emit on
80
+ `ctx.emitLink({ ..., confidence })`).
81
+ - Drop `applicableKinds` (array). Use `precondition.kind` instead with
82
+ qualified ids like `'claude/agent'`. The same `precondition` shape
83
+ is shared with Analyzer and Action.
84
+
85
+ **Analyzer:**
86
+
87
+ - Drop `emitsAnalyzerIds` (the qualified extension id is the default
88
+ `analyzer_id`).
89
+ - Drop `defaultSeverity` (declare severity per-emit on
90
+ `ctx.emitIssue({ ..., severity })`).
91
+ - Drop `consumes`, `configurable`, `recommendedActions`. The
92
+ analyzer↔action relationship is now declared from the Action side
93
+ via `precondition.analyzerIds` (Modelo B): one Action says "I
94
+ resolve these analyzer findings", instead of one Analyzer saying
95
+ "these actions help".
96
+ - Add `precondition: { kind?, provider? }` (same shape as Extractor).
97
+
98
+ **Action:**
99
+
100
+ - Drop `reportSchemaRef` and `promptTemplateRef`. The kernel now
101
+ resolves these by convention from the action folder:
102
+ `<action-dir>/report.schema.json` (always required) and
103
+ `<action-dir>/prompt.md` (required when `mode='probabilistic'`,
104
+ forbidden when `mode='deterministic'`).
105
+ - Drop `expectedTools`, `fanOutPolicy`, `precondition.stability`,
106
+ `precondition.custom`.
107
+ - Add `precondition.analyzerIds` (Modelo B).
108
+ - Rename `expectedDurationSeconds` to `probExpectedDurationSeconds`
109
+ to mark it as probabilistic-only via the `prob*` prefix convention.
110
+ - `mode` is now optional with default `'deterministic'` (was
111
+ required).
112
+
113
+ **Formatter:**
114
+
115
+ - Drop `formatId` (comes from the folder name; the loader injects it
116
+ into the runtime instance).
117
+ - Drop `supportsFilter` (every formatter supports `--filter`).
118
+
119
+ **Hook:**
120
+
121
+ - Drop `mode`. Hooks are deterministic-only; LLM-dependent reactions
122
+ are modeled as a deterministic hook that enqueues a probabilistic
123
+ Action via `ctx.queue('<plugin>/<action>', payload)`.
124
+
125
+ **Loader changes (`src/kernel/adapters/plugin-loader/`):**
126
+
127
+ - The exported manifest is stripped of any `id` / `kind` / `pluginId`
128
+ / `kinds` / `formatId` keys before AJV validation; the loader
129
+ injects the canonical values from the folder layout. Legacy
130
+ manifests that still inline these fields load cleanly.
131
+ - New `discoverProviderKinds(...)` reads `<plugin>/kinds/<k>/{schema.json,
132
+ kind.json}` and merges the result into the runtime Provider
133
+ instance. Failure modes: missing or unparseable `schema.json`
134
+ → `load-error`; missing, unparseable, or AJV-invalid `kind.json`
135
+ → `invalid-manifest`.
136
+ - New `validateActionFileConventions(...)` enforces the
137
+ `report.schema.json` / `prompt.md` conventions.
138
+ - New `matchesAnyRoot(...)` powers Provider `roots` enforcement
139
+ inside `processRawNode`.
140
+
141
+ **Spec docs:**
142
+
143
+ - `architecture.md` §Extension kinds table, §Provider · `kinds`
144
+ catalog, §View contribution system updated.
145
+ - `plugin-author-guide.md` §Manifest section rewritten (id from
146
+ folder; description/catalogCompat required), §Extractor section
147
+ reworked around `precondition.kind`, drop guidance for
148
+ `emitsLinkKinds` / `defaultConfidence`.
149
+ - `view-slots.md` references `ui` map.
150
+
151
+ **Built-ins migration:**
152
+
153
+ - `core/bump/report.schema.json` and `core/mark-superseded/report.schema.json`
154
+ added (file conventions).
155
+ - `core/tools-count` extractor uses
156
+ `precondition: { kind: ['claude/agent'] }`.
157
+ - All built-in extensions drop `stability`, `preconditions`,
158
+ `emitsLinkKinds`, `defaultConfidence`, `emitsAnalyzerIds`,
159
+ `defaultSeverity`, `consumes`, `configurable`, `recommendedActions`,
160
+ `defaultRefreshAction`, `formatId` (formatter), `supportsFilter`,
161
+ `mode` (hook).
162
+ - `scripts/generate-built-ins.js` updated: `id` from bundle folder,
163
+ `granularity ?? 'extension'`, `toExtensionRow` drops the retired
164
+ display fields.
165
+
166
+ **Testkit:**
167
+
168
+ - `makeExtractorContext` populates `settings: {}` so test fixtures
169
+ satisfy the new required field on `IExtractorContext`.
170
+
171
+ ## User-facing
172
+
173
+ **Plugin manifests are smaller.** `plugin.json` drops `id`; every extension declares only `version` + `description` plus kind-specific fields. View contributions move to `ui:`. Provider kinds live under `kinds/<kindName>/`. Run `sm plugins doctor` after upgrading.
174
+
175
+ - 8b7abbf: Structure-as-truth refactor for plugin extensions. The filesystem
176
+ layout (rather than declarative manifest fields) is now the single
177
+ source of truth for bundle / kind / extension id.
178
+
179
+ **Schema changes:**
180
+
181
+ - `PluginManifest` drops the required `extensions: string[]` array;
182
+ the kernel now auto-discovers extensions by walking
183
+ `<plugin-dir>/<kind>s/<name>/index.{js,mjs,ts}` for each known
184
+ kind. `granularity` is now required (no implicit default).
185
+ - `ExtensionBase` drops the `entry` field (it was an override for
186
+ the now-gone `extensions[]` path; the loader computes the entry
187
+ path from the discovered file).
188
+ - `viewContributions` moves from `base.schema.json` to
189
+ `extractor.schema.json` and `analyzer.schema.json`. Runtime
190
+ `ctx.emitContribution` only exists for those two kinds; declaring
191
+ view contributions on other kinds used to be a silent no-op and
192
+ is now rejected at manifest load.
193
+
194
+ **Loader changes:**
195
+
196
+ - `<plugin-dir>/<kind>s/<name>/` is the unit of discovery; the
197
+ loader walks `providers`, `extractors`, `analyzers`, `actions`,
198
+ `formatters`, `hooks` in canonical order, looking for an
199
+ `index.{js,mjs,ts}` inside each name directory.
200
+ - A manifest whose `kind` disagrees with the folder it lives under
201
+ (e.g. an `extractor` placed under `analyzers/`) is rejected as
202
+ `invalid-manifest` with a directed reason.
203
+ - Containment is enforced by construction: the loader never reads
204
+ paths the manifest could redirect, so `..`-escape and
205
+ absolute-path lanes are closed without runtime checks.
206
+
207
+ **Built-ins reorganization:**
208
+
209
+ - Source tree renamed `src/built-in-plugins/` → `src/plugins/` and
210
+ reorganized to `src/plugins/<bundle>/<kind>s/<name>/index.ts`.
211
+ Each bundle (`core`, `claude`, `gemini`, `agent-skills`) gains a
212
+ `plugin.json` with its metadata.
213
+ - `src/plugins/built-ins.ts` is now generated by
214
+ `scripts/generate-built-ins.js` (runs as `prebuild`, checked for
215
+ drift by `built-ins:check` in CI). The generator walks the
216
+ filesystem, reads each bundle's `plugin.json`, and emits static
217
+ imports + the legacy API surface (`builtIns()`,
218
+ `listBuiltIns()`, `builtInBundles`).
219
+
220
+ **Scaffolder (`sm plugins create`):**
221
+
222
+ - Emits the new layout: `extractors/<plugin-id>-extractor/index.js`
223
+ plus a `plugin.json` without `extensions` and without
224
+ `pluginId` on the extension export (the loader injects it from
225
+ `plugin.json#/id`). The legacy `mode: 'deterministic'` field on
226
+ the extractor stub was a no-op holdover from when extractors had
227
+ a mode and has been removed.
228
+
229
+ **Per-extension co-located files convention:**
230
+
231
+ Files that share the extension's folder with `index.{js,mjs,ts}`
232
+ are author-owned siblings. Two blessed names so consumers know
233
+ where to look:
234
+
235
+ - `text.ts` for externalised user-facing strings (one per
236
+ extension, imported by `index.ts` as `./text.js`).
237
+ - `<extension-name>.test.{ts,mjs,js}` for the colocated test
238
+ suite (picked up by the workspace's `plugins/**/*.test.ts`
239
+ glob).
240
+
241
+ Both are optional; the loader ignores anything that is not
242
+ `index.{js,mjs,ts}`, so future schemas / fixtures / conformance
243
+ scopes can live next to the code without manifest plumbing. The
244
+ in-tree built-ins under `src/plugins/` were migrated to this
245
+ shape: each analyzer's user-facing strings now live at
246
+ `<bundle>/analyzers/<name>/text.ts` instead of a centralised
247
+ `i18n/` directory.
248
+
249
+ ## User-facing
250
+
251
+ **Plugin layout changed.** Extensions now live at `<kind>s/<name>/index.js` (e.g. `extractors/keyword-counter/index.js`); `plugin.json` no longer lists `extensions[]` and requires `granularity`. Run `sm plugins doctor` after migrating, or use `sm plugins create` for new plugins.
252
+
3
253
  ## 0.27.0
4
254
 
5
255
  ### Minor Changes
package/architecture.md CHANGED
@@ -173,12 +173,12 @@ Six kinds, all first-class, all loaded through the same registry. Each kind has
173
173
 
174
174
  | Kind | Role | Input | Output |
175
175
  |---|---|---|---|
176
- | **Provider** | Recognizes a platform. Declares the catalog of node `kind`s it emits via the `kinds` map; each map entry pairs the kind's frontmatter schema (path relative to the Provider's package directory) with its `defaultRefreshAction` (a qualified action id that drives the probabilistic-refresh surface). The Provider's walker hardcodes the paths it scans within the project (e.g. `.claude/`, `.gemini/`); it does NOT extend the scan into the user's HOME. Deterministic-only. | Filesystem walk results, candidate path. | `{ kind, provider } \| null`. |
177
- | **Extractor** | Extracts signals from a node body. Deterministic-only: runs synchronously inside `sm scan`. Output flows through three context callbacks (no return value): `ctx.emitLink(link)` for the kernel's `links` table, `ctx.enrichNode(partial)` for the kernel's enrichment layer (separate from the author's frontmatter), `ctx.store` for the plugin's own KV / dedicated tables. | Parsed node (frontmatter + body) + callbacks. | `void` (output via callbacks). |
178
- | **Analyzer** | Evaluates the graph. Dual-mode: `deterministic` runs in `sm check`, `probabilistic` runs in jobs. | Full graph (nodes + links). | `Issue[]`. |
179
- | **Action** | Operates on one or more nodes. Dual-mode: `deterministic` (in-process code) or `probabilistic` (rendered prompt the runner executes). | Node(s), optional args. | Deterministic: report JSON. Probabilistic: rendered prompt that a runner executes. |
180
- | **Formatter** | Serializes the graph. Deterministic-only. | Graph + optional filter. | String (ASCII / Mermaid / DOT / JSON / user-defined). |
181
- | **Hook** | Reacts declaratively to one of ten curated lifecycle events, eight pipeline-driven (`scan.started`, `scan.completed`, `extractor.completed`, `analyzer.completed`, `action.completed`, `job.spawning`, `job.completed`, `job.failed`) plus two CLI-process-driven (`boot` before verb routing, `shutdown` after the verb's exit code resolves). Dual-mode: `deterministic` runs in-process during the dispatch, `probabilistic` is enqueued as a job. Hooks REACT to events; they cannot block, mutate, or steer the pipeline. | A curated event payload (run-scoped, scan-scoped, job-scoped, or process-scoped) plus an optional declarative `filter` map. | `void` (reactions are side effects). |
176
+ | **Provider** | Recognizes a platform. The kind catalog lives on disk under `<plugin>/kinds/<kindName>/{schema.json, kind.json}` (structure-as-truth); the loader projects it onto the runtime descriptor. The Provider's walker hardcodes the paths it scans within the project (e.g. `.claude/`, `.gemini/`); it does NOT extend the scan into the user's HOME. `Provider.roots` is enforcement-grade: a Provider with declared roots only sees matching files; a Provider without `roots` acts as the fallback. Deterministic-only. | Filesystem walk results, candidate path. | `{ kind, provider } \| null`. |
177
+ | **Extractor** | Extracts signals from a node body. Deterministic-only: runs synchronously inside `sm scan`. Output flows through context callbacks (no return value): `ctx.emitLink(link)` for the kernel's `links` table (validated against the global closed enum of link kinds; per-extractor allowlist was retired with the structure-as-truth refactor), `ctx.enrichNode(partial)` for the kernel's enrichment layer (separate from the author's frontmatter), `ctx.emitContribution(id, payload)` for view contributions, `ctx.store` for the plugin's own KV / dedicated tables. | Parsed node (frontmatter + body) + callbacks. | `void` (output via callbacks). |
178
+ | **Analyzer** | Evaluates the graph. Dual-mode: `deterministic` runs in `sm check`, `probabilistic` runs in jobs. The analyzer↔action relationship is declared from the Action side via `precondition.analyzerIds` (Modelo B). | Full graph (nodes + links). | `Issue[]`. |
179
+ | **Action** | Operates on one or more nodes. Dual-mode: `deterministic` (in-process code) or `probabilistic` (rendered prompt the runner executes). Files-by-convention: every Action carries `<action-dir>/report.schema.json`; probabilistic Actions additionally carry `<action-dir>/prompt.md`. The retired `reportSchemaRef` / `promptTemplateRef` / `expectedTools` / `fanOutPolicy` manifest fields were replaced by these conventions and the simplified `precondition` block. | Node(s), optional args. | Deterministic: report JSON. Probabilistic: rendered prompt that a runner executes. |
180
+ | **Formatter** | Serializes the graph. Deterministic-only. The `formatId` consumed by `sm graph --format <name>` comes from the formatter's folder name. | Graph + optional filter. | String (ASCII / Mermaid / DOT / JSON / user-defined). |
181
+ | **Hook** | Reacts declaratively to one of ten curated lifecycle events, eight pipeline-driven (`scan.started`, `scan.completed`, `extractor.completed`, `analyzer.completed`, `action.completed`, `job.spawning`, `job.completed`, `job.failed`) plus two CLI-process-driven (`boot` before verb routing, `shutdown` after the verb's exit code resolves). **Deterministic-only** since the structure-as-truth refactor: LLM-dependent reactions are modeled as a deterministic Hook that enqueues a probabilistic Action via `ctx.queue('<plugin>/<action>', payload)`. Hooks REACT to events; they cannot block, mutate, or steer the pipeline. | A curated event payload (run-scoped, scan-scoped, job-scoped, or process-scoped) plus an optional declarative `filter` map. | `void` (reactions are side effects). |
182
182
 
183
183
  ### IO discipline, extensions never write to the filesystem
184
184
 
@@ -194,13 +194,14 @@ This invariant is what makes the consent gate at the kernel boundary sufficient:
194
194
 
195
195
  ### Provider · `kinds` catalog
196
196
 
197
- Every `Provider` MUST declare a non-empty map `kinds: { <kind>: { schema, defaultRefreshAction, ui } }` covering every `kind` it classifies into. Each entry carries three required fields:
197
+ Every `Provider` declares its kind catalog via the filesystem (structure-as-truth): each kind lives under `<plugin>/kinds/<kindName>/` and ships exactly two files:
198
198
 
199
- - **`schema`**, path (relative to the Provider package) to the kind's frontmatter JSON Schema. The schema MUST extend [`frontmatter/base.schema.json`](./schemas/frontmatter/base.schema.json) via `allOf` + `$ref` to base's `$id`. The kernel registers it with AJV at boot and validates every node's frontmatter against the entry matching its classified kind.
200
- - **`defaultRefreshAction`**, qualified action id (`<plugin-id>/<action-id>`) the UI's probabilistic-refresh surface (`🧠 prob`) dispatches for nodes of this kind. The action MUST exist in the registry; a dangling reference disables the Provider with status `invalid-manifest`. Plugins MAY override per-node via `metadata.refreshAction`; the Provider default is normative.
201
- - **`ui`**, presentation block: `{ label, color, colorDark?, emoji?, icon? }`. See §Provider · `ui` presentation below.
199
+ - **`schema.json`**, the kind's frontmatter JSON Schema. MUST extend [`frontmatter/base.schema.json`](./schemas/frontmatter/base.schema.json) via `allOf` + `$ref` to base's `$id`. The kernel reads it once at boot, registers it with AJV, and validates every node's frontmatter against the entry matching its classified kind.
200
+ - **`kind.json`**, the per-kind metadata, today just `{ ui: { label, color, colorDark?, emoji?, icon? } }`. See §Provider · `ui` presentation below. Validated against [`schemas/extensions/provider-kind.schema.json`](./schemas/extensions/provider-kind.schema.json) at load time.
202
201
 
203
- The catalog is the single source of truth for "which kinds does this Provider emit", the `IProvider` runtime contract derives the kind set from `Object.keys(kinds)`.
202
+ The loader's discovery (`discoverProviderKinds`) projects every `kinds/<kindName>/` directory into the runtime descriptor `instance.kinds[<kindName>] = { schema, schemaJson, ui }`. The `IProvider` runtime contract derives the kind set from `Object.keys(kinds)`; authors do not write the map by hand any more.
203
+
204
+ The retired manifest field `defaultRefreshAction` (the qualified action id the UI's `🧠 prob` button dispatched) was removed alongside the button. A replacement UX is TBD; until then, the kernel does not surface a Provider-declared "default refresh" path.
204
205
 
205
206
  ### Provider · `ui` presentation
206
207
 
@@ -588,7 +589,7 @@ Two schemas describe the wire shape:
588
589
 
589
590
  ### Identity
590
591
 
591
- Each view contribution is identified by the qualified id `<pluginId>/<extensionId>/<contributionId>`. The plugin author declares contributions in the extension manifest under `viewContributions: Record<string, IViewContribution>`; the loader composes the qualified id from the plugin id, the extension id, and the Record key.
592
+ Each view contribution is identified by the qualified id `<pluginId>/<extensionId>/<contributionId>`. The plugin author declares contributions in the extension manifest under `ui: Record<string, IViewContribution>` (renamed from `viewContributions` with the structure-as-truth refactor); the loader composes the qualified id from the plugin id, the extension id, and the Record key. The runtime catalog aggregated by `Kernel.getRegisteredViewContributions()` keeps the original `viewContributions` name, only the manifest-side field changed.
592
593
 
593
594
  ### Manifest
594
595
 
@@ -596,7 +597,7 @@ Each entry picks a `slot` name from the closed catalog and supplies presentation
596
597
 
597
598
  ```jsonc
598
599
  {
599
- "viewContributions": {
600
+ "ui": {
600
601
  "breakdown": {
601
602
  "slot": "inspector.body.panel.breakdown",
602
603
  "label": "Keyword hits",
@@ -616,13 +617,13 @@ The plugin author picks ONE slot per contribution; that single decision determin
616
617
 
617
618
  ### Settings
618
619
 
619
- Plugin user-configurable settings live at the manifest root in `settings: Record<string, ISettingDeclaration>` (see [`schemas/plugins-registry.schema.json`](./schemas/plugins-registry.schema.json)). Each setting picks an input-type from the closed catalog at [`schemas/input-types.schema.json`](./schemas/input-types.schema.json) (`string-list`, `single-string`, `boolean-flag`, `integer`, `enum-pick`, `enum-multipick`, `path-glob`, `regex`, `secret`, `key-value-list`). The kernel exposes resolved settings to extractors via `ctx.settings.<settingId>`; the UI generates a form per declaration; the CLI's `sm plugins config <id>` exposes the same surface.
620
+ Plugin user-configurable settings live **on each extension's manifest** (structure-as-truth) in `settings: Record<string, ISettingDeclaration>` (see [`schemas/extensions/base.schema.json`](./schemas/extensions/base.schema.json) and [`schemas/input-types.schema.json`](./schemas/input-types.schema.json)). Each setting picks an input-type from the closed catalog (`string-list`, `single-string`, `boolean-flag`, `integer`, `enum-pick`, `enum-multipick`, `path-glob`, `regex`, `secret`, `key-value-list`). The kernel exposes resolved settings via `ctx.settings.<settingId>` to the extension's runtime methods (`extract`, `evaluate`, `invoke`, etc.); the UI generates a form per declaration; the CLI's `sm plugins config <plugin>/<extension>` exposes the same surface. Plugin-level settings are no longer supported; the field was moved from `plugin.json` to each extension that consumes it.
620
621
 
621
- Settings are read once at extractor invocation; changing a setting requires `sm scan` to re-emit affected contributions. The UI surfaces a "settings changed, rescan needed" indicator when the manifest detects mismatch; live re-emission is explicitly out of scope (rescan-required is a stability decision per `ROADMAP.md` §UI contribution system D4).
622
+ Settings are read once at extension invocation; changing a setting requires `sm scan` to re-emit affected contributions. The UI surfaces a "settings changed, rescan needed" indicator when the manifest detects mismatch; live re-emission is explicitly out of scope (rescan-required is a stability decision per `ROADMAP.md` §UI contribution system D4).
622
623
 
623
624
  ### Runtime catalog
624
625
 
625
- The kernel exposes a runtime catalog (`Kernel.getRegisteredViewContributions()`) listing every plugin-contributed view contribution with its `pluginId`, `extensionId`, `contributionId`, `slot`, and the manifest-declared `label` / `tooltip` / `icon` / `emptyText` / `emitWhenEmpty`. The catalog is built once at boot from every loaded extension's `viewContributions` map, AJV-validated, and frozen, same lifecycle as `getRegisteredAnnotationKeys()`.
626
+ The kernel exposes a runtime catalog (`Kernel.getRegisteredViewContributions()`) listing every plugin-contributed view contribution with its `pluginId`, `extensionId`, `contributionId`, `slot`, and the manifest-declared `label` / `tooltip` / `icon` / `emptyText` / `emitWhenEmpty`. The catalog is built once at boot from every loaded extension's `ui` map (renamed from `viewContributions` with the structure-as-truth refactor), AJV-validated, and frozen, same lifecycle as `getRegisteredAnnotationKeys()`.
626
627
 
627
628
  Analyzers see the catalog through `IAnalyzerContext.viewContributions` so cross-cutting checks (`core/unknown-slot`, `core/contribution-orphan`) can reason about emissions.
628
629
 
@@ -712,7 +713,7 @@ Same honest-note posture as [`plugin-kv-api.md`](./plugin-kv-api.md): isolated a
712
713
 
713
714
  Two built-ins ship with the system to cover catalog evolution and rename edge cases:
714
715
 
715
- - **`core/unknown-slot`**, walks every loaded plugin's `viewContributions[*].slot`; emits an `Issue` of severity `warn` for any slot not in the current kernel catalog. Parallel to `core/unknown-field` for annotations. Note: AJV at manifest load already rejects unknown slots as `invalid-manifest`; this analyzer covers the soft-warning path when a plugin remains loaded across a catalog version bump.
716
+ - **`core/unknown-slot`**, walks every loaded plugin's `ui[*].slot`; emits an `Issue` of severity `warn` for any slot not in the current kernel catalog. Parallel to `core/unknown-field` for annotations. Note: AJV at manifest load already rejects unknown slots as `invalid-manifest`; this analyzer covers the soft-warning path when a plugin remains loaded across a catalog version bump.
716
717
  - **`core/contribution-orphan`**, joins `scan_contributions` against the live `scan_nodes` set; emits an `Issue` of severity `warn` for emissions whose `node_path` no longer exists (post-rename heuristic miss).
717
718
 
718
719
  ### Catalog versioning
@@ -16,10 +16,10 @@
16
16
  { "type": "json-path", "path": "$.nodes[0].sidecar.status", "matches": "^stale-(body|frontmatter|both)$" },
17
17
  { "type": "json-path", "path": "$.nodes[0].sidecar.annotations.version", "equals": 7 },
18
18
  { "type": "json-path", "path": "$.stats.issuesCount", "equals": 2 },
19
- { "type": "json-path", "path": "$.issues[0].analyzerId", "equals": "annotation-stale" },
19
+ { "type": "json-path", "path": "$.issues[0].analyzerId", "equals": "annotation-orphan" },
20
20
  { "type": "json-path", "path": "$.issues[0].severity", "equals": "warn" },
21
- { "type": "json-path", "path": "$.issues[1].analyzerId", "equals": "annotation-orphan" },
22
- { "type": "json-path", "path": "$.issues[1].severity", "equals": "warn" },
23
- { "type": "json-path", "path": "$.issues[1].data.expectedMdPath", "equals": ".claude/agents/orphan.md" }
21
+ { "type": "json-path", "path": "$.issues[0].data.expectedMdPath", "equals": ".claude/agents/orphan.md" },
22
+ { "type": "json-path", "path": "$.issues[1].analyzerId", "equals": "annotation-stale" },
23
+ { "type": "json-path", "path": "$.issues[1].severity", "equals": "warn" }
24
24
  ]
25
25
  }
@@ -25,13 +25,14 @@ This file is hand-maintained. A CI check before spec release compares the schema
25
25
  | 15 | `summaries/hook.schema.json` |, | 🔴 missing | Blocked by Step 11. |
26
26
  | 16 | `summaries/markdown.schema.json` |, | 🔴 missing | Blocked by Step 11. |
27
27
  | 17 | `extensions/base.schema.json` |, | 🔴 missing | Meta-case: every manifest under `src/extensions/` validates against the appropriate kind schema (which extends base via `allOf`). |
28
- | 18 | `extensions/provider.schema.json` | `plugin-missing-ui-rejected` | 🟡 partial | A drop-in Provider whose `kinds[*]` entry omits the required `ui` block fails AJV validation with `invalid-manifest` while the rest of the pipeline keeps running (built-in Claude Provider, exit 0). The complementary positive case (canonical Claude Provider manifest validates) lives in `provider:claude` conformance. Direct case for missing `kinds` rejection still pending. |
29
- | 19 | `extensions/extractor.schema.json` |, | 🔴 missing | Case: `frontmatter` + `slash` + `at-directive` extractor manifests validate; an extractor emitting a disallowed `emitsLinkKinds` value fails. |
28
+ | 18 | `extensions/provider.schema.json` | `plugin-missing-ui-rejected` | 🟡 partial | A Provider plugin whose `kinds/<kindName>/kind.json` omits the required `ui` block fails AJV validation with `invalid-manifest` while the rest of the pipeline keeps running (built-in Claude Provider, exit 0). Since the structure-as-truth refactor, Providers no longer carry a `kinds` map in the manifest; per-kind metadata lives under `kinds/<kindName>/kind.json` and frontmatter schemas under `kinds/<kindName>/schema.json`. The complementary positive case (canonical Claude Provider validates) lives in `provider:claude` conformance. Direct case for missing `kinds/` directory rejection still pending. |
29
+ | 19 | `extensions/extractor.schema.json` |, | 🔴 missing | Case: `frontmatter` + `slash` + `at-directive` extractor manifests validate; an extractor declaring a `precondition.kind` against an unknown qualified kind emits `precondition-kind-unknown` in `sm plugins doctor`. |
30
30
  | 20 | `extensions/analyzer.schema.json` |, | 🔴 missing | Case: `trigger-collision`, `broken-ref`, `superseded` manifests validate. |
31
- | 21 | `extensions/action.schema.json` |, | 🔴 missing | Case: a `deterministic` action manifest validates; a `probabilistic` action WITHOUT `promptTemplateRef` fails. |
31
+ | 21 | `extensions/action.schema.json` |, | 🔴 missing | Case: a `deterministic` action manifest validates; a `probabilistic` action without `<action-dir>/prompt.md` surfaces as `load-error` (structure-as-truth: prompt template lives on disk by convention, no `promptTemplateRef` field). |
32
32
  | 22 | `extensions/formatter.schema.json` |, | 🔴 missing | Case: `ascii` formatter manifest validates. |
33
33
  | 23 | `history-stats.schema.json` |, | 🔴 missing | Blocked by Step 5 (history). Case: seed `state_executions` with a deterministic fixture, run `sm history stats --json --since <T0> --until <T1> --period month --top 5`, assert the document validates and that `totals.executionsCount == sum(perAction.executionsCount)` and `errorRates.global == totals.failedCount / totals.executionsCount`. Percentiles (`p95`/`p99`) intentionally omitted in v1, add later as a minor bump without breaking consumers. |
34
- | 24 | `extensions/hook.schema.json` |, | 🔴 missing | Case: a `deterministic` hook manifest with `triggers: ['scan.completed']` validates; a hook declaring an unknown trigger (e.g. `scan.progress`) fails with `invalid-manifest` at load time. |
34
+ | 24 | `extensions/hook.schema.json` |, | 🔴 missing | Case: a hook manifest with `triggers: ['scan.completed']` validates; a hook declaring an unknown trigger (e.g. `scan.progress`) fails with `invalid-manifest` at load time. Hooks are deterministic-only since structure-as-truth; manifests carrying a `mode` field are rejected. |
35
+ | 36 | `extensions/provider-kind.schema.json` |, | 🔴 missing | Case: `<plugin>/kinds/<kindName>/kind.json` carrying a valid `{ ui }` block validates; a kind folder missing `kind.json` or `schema.json` surfaces as `invalid-manifest`; a `kind.json` whose `ui.color` is not `#RRGGBB` fails AJV. |
35
36
  | 25 | `api/rest-envelope.schema.json` |, | 🔴 missing | Step 14.2 BFF list-envelope shape (`{ schemaVersion, kind, items \| item \| value, filters, counts }`). Case: hit `GET /api/nodes` against a primed scope, validate the response against the schema; assert the `oneOf` rejects an envelope that carries both `items` and `item`. Implementation-side coverage exists today (`src/test/server-endpoints.test.ts`) but a kernel-agnostic conformance case is required before v1.0.0 ships. |
36
37
  | 26 | `sidecar.schema.json` | `sidecar-end-to-end` | 🟢 covered | Co-located YAML sidecar (`<basename>.sm`) root shape: reserved blocks `for` / `annotations` / `settings` / `audit` plus opt-in plugin namespacing. Step 9.6.2 (2026-05-05) shipped the kernel reader; Step 9.6.3 (2026-05-05) formalised the `audit:` sub-shape populated by the built-in `bump` Action; Step 9.6.6 (2026-05-06) flips this row 🟢 with the end-to-end `sidecar-end-to-end` case (fixture `sidecar-end-to-end/`): a scan over a stale-`.sm` + orphan-`.sm` corpus produces a populated `Node.sidecar` overlay with `present: true` and `status: stale-*`, denormalises `annotations.version` into the node row, and emits both `annotation-stale` and `annotation-orphan` issues from the built-in core analyzers. Structural sample (untouched) at `fixtures/sidecar-example/agent-example.sm`. |
37
38
  | 27 | `annotations.schema.json` | `sidecar-end-to-end` | 🟢 covered | Curated catalog of 15 conventional skill-map annotation fields (versioning, supersession, provenance, lifecycle, taxonomy, display, docs). `additionalProperties: true` so users / plugins extend without coordination; the `unknown-field` Tier-1 analyzer shipped in Step 9.6.6 emits warnings on truly unrecognized keys. Step 9.6.2 (2026-05-05) wired the kernel reader; Step 9.6.6 (2026-05-06) flips this row 🟢 via `sidecar-end-to-end`, which asserts that an `annotations.version: 7` value round-trips through `state_scan_nodes.annotations_json` and surfaces in the node's `sidecar.annotations` overlay AND in the denormalised `Node.version` column. Structural sample at `fixtures/sidecar-example/agent-example.sm`. Catalog trimmed from 31 to 15 fields on 2026-05-07 after UX review. |
@@ -0,0 +1,3 @@
1
+ {
2
+ "_comment": "Conformance fixture: this kind.json deliberately omits the required `ui` block; the loader MUST reject the plugin as invalid-manifest."
3
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:test:bad-provider/markdown",
4
+ "type": "object",
5
+ "additionalProperties": true
6
+ }
@@ -1,6 +1,7 @@
1
1
  {
2
- "id": "bad-provider",
3
2
  "version": "0.1.0",
4
3
  "specCompat": "*",
5
- "extensions": ["provider.js"]
4
+ "catalogCompat": "*",
5
+ "description": "Conformance fixture: provider missing `ui` block.",
6
+ "granularity": "bundle"
6
7
  }
@@ -0,0 +1,17 @@
1
+ // Conformance fixture: provider whose `kinds/markdown/kind.json`
2
+ // deliberately omits the required `ui` block (structure-as-truth
3
+ // refactor moved the kind catalog from the manifest map to per-kind
4
+ // folders on disk). The plugin loader MUST reject this manifest with
5
+ // a clear "missing required property 'ui'" diagnostic and the plugin
6
+ // MUST end up in `invalid-manifest` status. The companion case
7
+ // `plugin-missing-ui-rejected.json` asserts the stderr text and that
8
+ // `sm scan` survives (the loader degrades the bad plugin and lets the
9
+ // rest of the pipeline continue).
10
+ export default {
11
+ version: '0.1.0',
12
+ description: 'provider whose markdown kind is missing the ui block',
13
+ async *walk() {},
14
+ classify() {
15
+ return 'markdown';
16
+ },
17
+ };
package/db-schema.md CHANGED
@@ -527,6 +527,7 @@ Implementations MUST apply a rename heuristic at scan time **before** committing
527
527
  - Apply the same FK migration.
528
528
  - Emit an issue with `analyzerId: auto-rename-medium` (severity `warn`) pointing to both paths. The issue's `data` MUST include `{ from: <old.path>, to: <new.path>, confidence: "medium" }` so `sm orphans undo-rename <new.path>` can read the prior path without user input.
529
529
  4. Any `deletedPath` left without a match after steps 2–3 becomes an **orphan**: the kernel emits an issue with `analyzerId: orphan` (severity `info`) and keeps the `state_*` rows referencing the dead path untouched until the user runs `sm orphans reconcile <dead.path> --to <new.path>` or accepts the orphan.
530
+ - **Silenced exception**: the kernel skips the `orphan` issue when the `deletedPath` is currently filtered out of the scan by the active ignore-source (e.g. the user added an entry to `.skillmapignore` between scans and the file still exists on disk). The intent there is "hide from the graph", not "lost without a rename"; emitting an `orphan` info would pollute `sm check` with noise the user explicitly asked for. The reference impl threads a `silenced(path): boolean` predicate from the orchestrator into the rename heuristic; callers that do not supply one preserve the previous "always emit" behaviour. The `state_*` rows are still kept; if the user removes the entry from the ignore the path re-enters the scan as a live node, transparent to history.
530
531
 
531
532
  Matching is 1-to-1: once a `newPath` is claimed as the rename target of some `deletedPath`, no other deletion can match it in the same scan. Ambiguity (two deletions share a body hash with the same new path) → fall back to the orphan path for all candidates, with issue `auto-rename-ambiguous` listing every conflict. `auto-rename-ambiguous` issues MUST populate `data` with `{ to: <new.path>, candidates: [<old.path.a>, <old.path.b>, ...] }`; in this case `sm orphans undo-rename` requires the user to pass `--from <old.path>` to disambiguate.
532
533
 
package/index.json CHANGED
@@ -174,25 +174,27 @@
174
174
  }
175
175
  ]
176
176
  },
177
- "specPackageVersion": "0.27.0",
177
+ "specPackageVersion": "0.29.0",
178
178
  "integrity": {
179
179
  "algorithm": "sha256",
180
180
  "files": {
181
- "CHANGELOG.md": "609e04963f4a7302161bc01718643fa60c358b62cf564cd683e68892be6a65de",
181
+ "CHANGELOG.md": "9de333733bb26b8f1044d823568c4e7d0f92a770b9afe562f835b19a16c48e0a",
182
182
  "README.md": "54c4649fa9742bf2f74423ea78788a7474ce09649cbe1e72a270b606cf16a0a5",
183
- "architecture.md": "7c735b2d305798d610760d23b03a450361131927109d7271ef78257fbf36b1f4",
183
+ "architecture.md": "d40423d3df102c31744186f3b5e91446e57fb78839e67c010501fb210db6d545",
184
184
  "cli-contract.md": "c22f7c82d460714efaf34a04a2d2367d21eb04985100aef1291071e6726cbc64",
185
185
  "conformance/README.md": "6871dde25b5770ed945284c9e0f749e0768ec3f5ba4966bdb215985789e43887",
186
186
  "conformance/cases/kernel-empty-boot.json": "2a5be9c93143d07a16d998df09dcc8fa4ea2d2f9a0bff6417573ed5a770352c1",
187
187
  "conformance/cases/no-global-scope.json": "1284763988026d924c0bd78ba8a9f417dc88f5b7e9f4c2b642ae0c447758bfd4",
188
188
  "conformance/cases/orphan-markdown-fallback.json": "8ef6e49b7e6532bd845d9f54974a16e537cf98d355f0c5e4f4fb06abac3adcc5",
189
189
  "conformance/cases/plugin-missing-ui-rejected.json": "bdebee810436e6be88edf2fe38ddc6939fd3f53e6a12dc1d66da051c4922f1e9",
190
- "conformance/cases/sidecar-end-to-end.json": "24a73e7c857709d001cf7013b8fe5ccad4027e064b39533dda33697d80b56e7a",
191
- "conformance/coverage.md": "0d202baf257f6690c107e1e20aff0c7db0399a53fcd72536e2d87ab7641510ab",
190
+ "conformance/cases/sidecar-end-to-end.json": "dbb3640f95769a36b881855a261f918481edadea13a7eb0765c6090f2417a142",
191
+ "conformance/coverage.md": "7c02052750ee5fca711218cbf993313dd1ed7c68bcac000b2cb23b5f688a4a2c",
192
192
  "conformance/fixtures/orphan-markdown/.claude/agents/reviewer.md": "7f062731106f2d9811e4fffcf6ab44b8dfff4cfb16536a469514cc0664e832bf",
193
193
  "conformance/fixtures/orphan-markdown/ARCHITECTURE.md": "d6b6e18d4b963b26a292de73348c3396fd4710ab4c4bdd6cf094e581f99ec8d6",
194
- "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/plugin.json": "4d78af6f12faa9d131e2a19f1dbb8f250baacc525978f3a8c858932b95da4ff6",
195
- "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/provider.js": "45843e8e1a679482a17e01dcd43e1800e1d3148f4ac2cd6ab8a29ef0430b6152",
194
+ "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/kinds/markdown/kind.json": "6676a89bae5197e23cf50f1c11d596db558ac80f7334a7208fe57d8b92422251",
195
+ "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/kinds/markdown/schema.json": "42795e7f1759fa25115a426edf5cd1b0c91b091b408aeee3f4f9fbc8f89f32bc",
196
+ "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/plugin.json": "fb3f52f82f1635d0e5de74788eb5f640d0e36b19464a46f0b2812f6aa9db435f",
197
+ "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/providers/bad-provider/index.js": "6eac0555de4194c3266c2abef89e39d833159990e1822ae1d4895df67c31d18f",
196
198
  "conformance/fixtures/plugin-missing-ui/notes/example.md": "55767f0aa1b6774546a99f28c58e7b732aa9cfa5dfce8d0326470f7f622f577e",
197
199
  "conformance/fixtures/preamble-v1.txt": "1e0aeef224b64477bdc13a949c3ad402e68249caf499ecdba1302371677c068b",
198
200
  "conformance/fixtures/sidecar-end-to-end/.claude/agents/orphan.sm": "3102ff10a0f08f60c014f82409d45ad4faf2cefa04d652a87676d3557ad64944",
@@ -200,11 +202,11 @@
200
202
  "conformance/fixtures/sidecar-end-to-end/.claude/agents/stale.sm": "cb04f7f3103b4218b09fd4da92f7ea429588b04c1dac6a9547ce362263b11224",
201
203
  "conformance/fixtures/sidecar-example/agent-example.md": "741131403e8c9580d0b7a8c2446cb4502d01f80053b7a2092663de92431aaa82",
202
204
  "conformance/fixtures/sidecar-example/agent-example.sm": "8329950d49c69a1199bbe6c06e32b8513973e64207b0db8756b67301e6a1f1e2",
203
- "db-schema.md": "51fb96bb372ca20de0478b3d6596e39a87f882a561264c4857ec55a23c422548",
205
+ "db-schema.md": "8ff3d1fcb7b3e2e06f23fa2a65fe308c6b0876e8a028b7e19a40546d0270f6a7",
204
206
  "interfaces/security-scanner.md": "e8049712b9cf7a07c786bf19f8f775f8ef9638f063f7fba5c7a8b1431b92f38e",
205
207
  "job-events.md": "84206168ac12b536d34470d62f8c8cba95dab181fee66d23203c2cf5dfbee716",
206
208
  "job-lifecycle.md": "9c429121f98a07c8795f8979ed1abc5e5334e3f89db51585a8da55c527ef855b",
207
- "plugin-author-guide.md": "03c2f666d7856eae76594484a1580968e1292f247fb10c8abcff5d99c9d38f01",
209
+ "plugin-author-guide.md": "2c5f8e563908f55a5d608d1e35b28b425ef6cd62958cfcb03dfd475c3dc9ffa4",
208
210
  "plugin-kv-api.md": "1acc69ed82433a74e35ada61d63a6d7379fb61046ff83de1e0facbe884c64704",
209
211
  "prompt-preamble.md": "9dd4f6d1bc6a425f8782fcee10cbe75909e8d64e28781fda56c2fae909b02f40",
210
212
  "schemas/annotations.schema.json": "e39990d47f53e25a1b3a5587a5714486d0b819b8eeaac10d42783a675296aee1",
@@ -213,13 +215,14 @@
213
215
  "schemas/conformance-case.schema.json": "f6d4c9fb92e79cb516eeeb9d042223572a3bd5ff8e7871a0becce13916f20cf6",
214
216
  "schemas/conformance-result.schema.json": "426998e4f5cb079778ca7d0233634667d4fbc5a7e399cc41211fabd768db8ee0",
215
217
  "schemas/execution-record.schema.json": "0d61e33f2dc1aaa4cc7337b5eac4ea8b9034022ce24bae9156c3c9f33204c250",
216
- "schemas/extensions/action.schema.json": "262272175c06a2e33c08f819a45c3ef8260276c91a9d0542fdffc932aeb32db7",
217
- "schemas/extensions/analyzer.schema.json": "c3c5fc7de89318c178d170629dc9aecd6bcce9418e9ce7cc2f8d4f5ea8db99a6",
218
- "schemas/extensions/base.schema.json": "5a593f74678485b2e2dc5b92ba9a345d6290ef7381921758a852934e09db7a64",
219
- "schemas/extensions/extractor.schema.json": "38000aea61c4d06cd136ccbcf740d3608b2c5586c7a0ff93a75e75f0df09f018",
220
- "schemas/extensions/formatter.schema.json": "816136b9b933a93fde6859110d1d68dafe39099dea589786282b90627b464f7c",
221
- "schemas/extensions/hook.schema.json": "abfa75881a4bd20c367f1eada29fb577b89752920c9f9351f8247e1340f5f2ca",
222
- "schemas/extensions/provider.schema.json": "e9f026b7c6c3a167a55c581ebb92425e10563cc3b1864b18f48462b813d01ff3",
218
+ "schemas/extensions/action.schema.json": "9f6c2427ce3f0d6fa329adf0f13129821116ab79a1d2a53f96464513ff044ebe",
219
+ "schemas/extensions/analyzer.schema.json": "f9bed3ba1305b2b64da277dccfbe760f7c058c4bb62a2d845af9c75787f159f6",
220
+ "schemas/extensions/base.schema.json": "8aaf1f8f1693d401e32feb91d4e064ff80ec7d4b0e3f15eff4202c708febaef4",
221
+ "schemas/extensions/extractor.schema.json": "5994088bf669321d2a7b8262c07cc94e05e5e2f49a235ae5389b7c66ecc1b2e1",
222
+ "schemas/extensions/formatter.schema.json": "d6d417df20260e5ddfe71f104b11a45873869706f86372c3c3c78c583e06e8d5",
223
+ "schemas/extensions/hook.schema.json": "76bf2c07f9e689b3fd1c67cbad4516a4df10604f07103759e82670e5213ddcdf",
224
+ "schemas/extensions/provider-kind.schema.json": "add3c5648721e67887eb971a76b39319628effac6315cffd51f7dcf679810740",
225
+ "schemas/extensions/provider.schema.json": "ae528d6ce1e083a2b5e3e7c6c701fbfaa8d58c79fb1f71616dc2d00c1a841cb7",
223
226
  "schemas/frontmatter/base.schema.json": "df0056a9478514a0db7a705e59868fa4f67673ac1cc9c9da979de4237cdd62a1",
224
227
  "schemas/history-stats.schema.json": "5170dec0299f3d04382a38079a27b1f26300a6b95fdb1ea0fae11050ad9f0574",
225
228
  "schemas/input-types.schema.json": "c713b768d0b0e3d0c764afb401189f7fb624a82b4e988b73aab015cf9c67c01f",
@@ -228,7 +231,7 @@
228
231
  "schemas/link.schema.json": "7fc429d03aca7e4c0b9a28241712c1aa2a5275870cea5ed938c2f97e8cccb081",
229
232
  "schemas/node.schema.json": "e5da06c9262cc0f2f7584d5733ebc1c08acd75487952ed7b4d6035fb417aaa4b",
230
233
  "schemas/plugins-doctor.schema.json": "c1d92f30fdb0080e8cd8f7dc5d43e01aae02a16640bc5eb04811c337a275de58",
231
- "schemas/plugins-registry.schema.json": "3d8a29aa045d46d70be127aabbc59831da0c71a54f18eae752676e452577ae3d",
234
+ "schemas/plugins-registry.schema.json": "cca7ae65f0c22510ea27ea5ae34e0074f5beb5871a57b005b6b831e6ceaff5c0",
232
235
  "schemas/project-config.schema.json": "7bb695476015b6b43026db78208aedf67350f4bc2c796c822fa87d0c9093b13f",
233
236
  "schemas/refresh-report.schema.json": "54519b8caf86ba84c182f9565be9b5084bc1631ae05e9217ee18f34c0039fff3",
234
237
  "schemas/report-base-deterministic.schema.json": "9d318d0181d121097c906ef3af1c52d71c782740bd04cf23418d7627ce2c3ed5",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skill-map/spec",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "description": "JSON Schemas, prose contracts, and conformance suite for the skill-map specification.",
5
5
  "license": "MIT",
6
6
  "type": "module",