@skill-map/spec 0.21.0 → 0.22.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 +46 -0
- package/architecture.md +6 -11
- package/cli-contract.md +6 -9
- package/conformance/coverage.md +1 -1
- package/conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/provider.js +0 -1
- package/index.json +10 -10
- package/package.json +3 -2
- package/plugin-author-guide.md +5 -6
- package/schemas/api/rest-envelope.schema.json +5 -1
- package/schemas/extensions/provider.schema.json +2 -7
- package/schemas/project-config.schema.json +3 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Spec changelog
|
|
2
2
|
|
|
3
|
+
## 0.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 39a61e9: Remove the implicit "scan HOME" surface and consolidate every out-of-project scan path under a single, explicit `scan.extraFolders` setting. Privacy-by-default: the CLI / BFF / UI never read the user's home automatically anymore; every path outside the project root must be listed by the operator.
|
|
8
|
+
|
|
9
|
+
**Removed**
|
|
10
|
+
|
|
11
|
+
- `scan.includeHome` (project config boolean). The toggle that appended every Provider's HOME path is gone.
|
|
12
|
+
- `explorationDir` on the Provider manifest. Built-in providers (`claude`, `gemini`, `agent-skills`, `core-markdown`) no longer declare it; the field is dropped from `spec/schemas/extensions/provider.schema.json`. Each Provider's walker hardcodes the project-relative paths it cares about (e.g. `.claude/`, `.gemini/`, `.agents/`).
|
|
13
|
+
- `sm scan -g` / `sm scan --global`. The scan verb no longer accepts the global scope flag (there is no global scan surface once HOME auto-inclusion is gone). Other verbs (`config`, `db`, `plugins`, `init`, …) keep their `-g` flag — those point at `~/.skill-map/` (skill-map's own data dir), not at scanned content.
|
|
14
|
+
- `sm plugins doctor` no longer emits the `explorationDir missing` warning.
|
|
15
|
+
|
|
16
|
+
**Renamed**
|
|
17
|
+
|
|
18
|
+
- `scan.extraRoots` → `scan.extraFolders` (same shape `string[]`, same semantics — clearer name in the Settings UI and config). Privacy-sensitive: writes that add out-of-project paths still require `--yes` on the CLI and a confirm dialog in the UI.
|
|
19
|
+
|
|
20
|
+
**BFF**
|
|
21
|
+
|
|
22
|
+
- `GET /api/project-preferences` response now returns `{ scan: { extraFolders, referencePaths } }` (dropped `includeHome`, renamed `extraRoots`).
|
|
23
|
+
- `PATCH /api/project-preferences` accepts the same shape; `additionalProperties: false` still applies.
|
|
24
|
+
|
|
25
|
+
**UI**
|
|
26
|
+
|
|
27
|
+
- Settings → Project section drops the "Include HOME folders" toggle; only the "Extra folders to scan" list and "Folders for link validation" list remain.
|
|
28
|
+
|
|
29
|
+
**Greenfield migration**
|
|
30
|
+
|
|
31
|
+
No backwards-compat shim. Users with `scan.includeHome: true` or `scan.extraRoots: [...]` in `<cwd>/.skill-map/settings.local.json` (or `~/.skill-map/settings.json`) need to manually rename `extraRoots` → `extraFolders` and, if they want to keep HOME scanning, list the specific paths they care about (e.g. `~/.claude/agents`) in `scan.extraFolders` — instead of opting into "everything under HOME" at once.
|
|
32
|
+
|
|
33
|
+
## User-facing
|
|
34
|
+
|
|
35
|
+
The "include HOME" toggle is gone. To scan paths outside the project, list them in **Extra folders to scan** (renamed from _Extra roots_). If you had `scan.includeHome: true`, add the paths you actually need (e.g. `~/.claude/agents`) — not one click anymore.
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- 1e48d2e: Follow-up sweep on the cli-architect spec-drift audit. Three pieces:
|
|
40
|
+
|
|
41
|
+
- **5a — plugin loader status alignment.** The loader now returns `invalid-manifest` (not `load-error`) when the exported extension shape fails its kind-specific AJV schema. Aligns with `spec/architecture.md` §Plugin discovery: "AJV rejects unknown `slot` names with `invalid-manifest`". The module imported fine; only the declared shape is wrong, so `invalid-manifest` is the semantically correct status (`load-error` is for genuine module-load failures: import threw, timeout, unknown kind). Renames `PLUGIN_LOADER_TEXTS.loadErrorManifestInvalid` → `invalidManifestExtensionShape` to match. 4 tests updated.
|
|
42
|
+
|
|
43
|
+
- **7 — `emitScopeContribution` docs alignment.** Added a "pending, not yet implemented" status note to `spec/view-slots.md` and `spec/plugin-author-guide.md`. The two author-facing docs previously showed the callback as if it existed; `spec/architecture.md` already says it's "reserved, lands when the first scope-level adopter arrives". A plugin author who copies the example now sees the caveat upfront instead of hitting `TypeError: ctx.emitScopeContribution is not a function` at runtime.
|
|
44
|
+
|
|
45
|
+
- **P2 cosmetic prose sweep.** Slot-count references corrected ("15 slots" → "14" — the closed enum has 14 entries since the topbar scope-slot rename); `IViewContribution` field count corrected ("six fields" → "seven" — `priority?` was declared in the schema since the beginning but never documented in prose). Three spec docs swept; `spec/index.json` regenerated.
|
|
46
|
+
|
|
47
|
+
`catalogCompat` (5b in the audit) — schema field declared but loader check not implemented — is deferred until catalog v2 evolution demands it. No catalog evolution is pending pre-1.0, so the gap is acceptable; flagged in audit follow-ups, not in this changeset.
|
|
48
|
+
|
|
3
49
|
## 0.21.0
|
|
4
50
|
|
|
5
51
|
### Minor Changes
|
package/architecture.md
CHANGED
|
@@ -173,7 +173,7 @@ 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).
|
|
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
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
178
|
| **Analyzer** | Evaluates the graph. Dual-mode: `deterministic` runs in `sm check`, `probabilistic` runs in jobs. | Full graph (nodes + links). | `Issue[]`. |
|
|
179
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. |
|
|
@@ -216,10 +216,6 @@ The `ui` block is required (not optional) by design: making it optional would fo
|
|
|
216
216
|
|
|
217
217
|
The kernel ships every Provider's `ui` block to the BFF at boot; the BFF aggregates them into a `kindRegistry` map and embeds it in every payload-bearing REST envelope (see [`cli-contract.md` §Server](./cli-contract.md#server)). The UI consumes `kindRegistry` directly — built-in and user-plugin kinds render identically.
|
|
218
218
|
|
|
219
|
-
### Provider · `explorationDir`
|
|
220
|
-
|
|
221
|
-
Every `Provider` extension MUST declare an `explorationDir: string` naming the filesystem directory (relative to user home or project root) where its content lives. Examples: `'~/.claude'` for the Claude Provider, `'~/.cursor'` for a hypothetical Cursor Provider. The kernel walks this directory during boot/scan to discover nodes; the Provider's `globs` (if declared) refines what to match inside. `sm doctor` (and `sm plugins doctor`) validates the directory exists; missing directory yields a non-blocking warning so the user sees the gap without the load failing — the Provider may legitimately precede installation of its platform.
|
|
222
|
-
|
|
223
219
|
### Provider · dispatch order and the universal markdown fallback
|
|
224
220
|
|
|
225
221
|
`sm scan` iterates Providers in **registration order** — vendor-specific Providers first (built-in: `claude` → `gemini` → `agent-skills`; user-installed plugins follow in load order), then the built-in `core/markdown` Provider LAST. Each Provider's walker enumerates the full project tree for its declared `read.extensions`; for every emitted file, the orchestrator calls `provider.classify(path, frontmatter)`. The kernel maintains a per-scan `Set<path>` of already-classified files so each path is offered to AT MOST one Provider's `classify`: the first Provider whose `classify` returns non-null claims the file, and subsequent Providers see the path as taken and skip.
|
|
@@ -453,11 +449,10 @@ Two locality classes constrain which layers a given key MAY live in. Both are en
|
|
|
453
449
|
|
|
454
450
|
Members:
|
|
455
451
|
- `allowEditSmFiles` — per-project consent to create / modify `.sm` sidecars.
|
|
456
|
-
- `scan.
|
|
457
|
-
- `scan.extraRoots` — additional scan paths.
|
|
452
|
+
- `scan.extraFolders` — additional scan paths (the ONLY way to extend the scan beyond the project root).
|
|
458
453
|
- `scan.referencePaths` — additional link-validation paths.
|
|
459
454
|
|
|
460
|
-
All
|
|
455
|
+
All three describe disk access the local operator opted into; sharing them via the repo would silently expand every collaborator's scan surface to paths that only make sense on the original author's machine.
|
|
461
456
|
|
|
462
457
|
Adding a new entry to either set is a behaviour change for older installs that wrote the key into a committed file — the value gets stripped (PROJECT_LOCAL_ONLY) or ignored (USER_ONLY) at read time. The changeset that adds the entry MUST document the migration.
|
|
463
458
|
|
|
@@ -579,7 +574,7 @@ Sibling system to the annotation contributions above. Both let plugins extend th
|
|
|
579
574
|
|
|
580
575
|
Two schemas describe the wire shape:
|
|
581
576
|
|
|
582
|
-
- [`schemas/view-slots.schema.json`](./schemas/view-slots.schema.json) — closed catalog:
|
|
577
|
+
- [`schemas/view-slots.schema.json`](./schemas/view-slots.schema.json) — closed catalog: 14 slot names + the `IViewContribution` manifest declaration shape + per-slot payload schemas (in `$defs/payloads`) the kernel uses to validate emit-time payloads.
|
|
583
578
|
- [`schemas/input-types.schema.json`](./schemas/input-types.schema.json) — closed catalog: 10 input-type names + the `ISettingDeclaration` manifest declaration shape (discriminated by `type`).
|
|
584
579
|
|
|
585
580
|
### Identity
|
|
@@ -608,7 +603,7 @@ Each entry picks a `slot` name from the closed catalog and supplies presentation
|
|
|
608
603
|
}
|
|
609
604
|
```
|
|
610
605
|
|
|
611
|
-
The plugin author picks ONE slot per contribution; that single decision determines where the data renders, what payload shape `ctx.emitContribution(...)` must produce, and which Angular component draws it.
|
|
606
|
+
The plugin author picks ONE slot per contribution; that single decision determines where the data renders, what payload shape `ctx.emitContribution(...)` must produce, and which Angular component draws it. Seven manifest fields per contribution (`slot`, `label?`, `tooltip?`, `icon?`, `emptyText?`, `emitWhenEmpty?`, `priority?`) + the slot catalog page is the entire mental model. See [`plugin-author-guide.md`](./plugin-author-guide.md) §View contributions for worked examples.
|
|
612
607
|
|
|
613
608
|
### Settings
|
|
614
609
|
|
|
@@ -721,7 +716,7 @@ Pre-1.0 versioning analyzer (per [`AGENTS.md`](../AGENTS.md)): catalog breaking
|
|
|
721
716
|
|
|
722
717
|
The **closed catalog of view slots** is stable as of the v1 of this system: adding a new slot is a minor bump; renaming or removing one is a catalog-major bump and triggers `sm plugins upgrade` migration of every dependent plugin.
|
|
723
718
|
|
|
724
|
-
The **`IViewContribution` manifest shape** (
|
|
719
|
+
The **`IViewContribution` manifest shape** (seven fields: `slot`, `label?`, `tooltip?`, `icon?`, `emptyText?`, `emitWhenEmpty?`, `priority?`) is stable. Adding a new optional field is a minor bump; making a field required or removing one is a catalog-major bump.
|
|
725
720
|
|
|
726
721
|
The **closed catalog of input-types** is stable on the same model: adding minor, renaming/removing major.
|
|
727
722
|
|
package/cli-contract.md
CHANGED
|
@@ -141,7 +141,7 @@ Diagnostic report:
|
|
|
141
141
|
- `state_job_contents` GC stragglers (count of rows referenced by zero `state_jobs` rows; `sm job prune` collects these).
|
|
142
142
|
- Plugins in error state (list).
|
|
143
143
|
- LLM runner availability (`claude` binary on PATH, version).
|
|
144
|
-
- Detected Providers that matched nothing
|
|
144
|
+
- Detected Providers that matched nothing (non-blocking warning).
|
|
145
145
|
|
|
146
146
|
Exit: 0 if all green, 1 if warnings, 2 if any `error`-level problem.
|
|
147
147
|
|
|
@@ -188,11 +188,11 @@ Keys are dot-paths (`jobs.minimumTtlSeconds`, `scan.tokenize`). Unknown keys →
|
|
|
188
188
|
|
|
189
189
|
#### Privacy-sensitive config
|
|
190
190
|
|
|
191
|
-
Keys whose value opens disk access OUTSIDE the project root (today: `scan.
|
|
191
|
+
Keys whose value opens disk access OUTSIDE the project root (today: `scan.extraFolders`, `scan.referencePaths`) are gated behind `--yes` so the user never expands the scan surface by accident. The analyzer:
|
|
192
192
|
|
|
193
|
-
- `sm config set <privacy-key> <value>` (without `--yes`) — when the new value would expand the surface (
|
|
193
|
+
- `sm config set <privacy-key> <value>` (without `--yes`) — when the new value would expand the surface (adding paths to `extraFolders` / `referencePaths` that resolve outside the project root) — exits with code `2` and prints the full list of paths the change would expose to stderr, suggesting `--yes` to confirm.
|
|
194
194
|
- `sm config set <privacy-key> <value> --yes` — proceeds with the write and prints the same list as a confirmation receipt.
|
|
195
|
-
- Writes that NARROW the surface (
|
|
195
|
+
- Writes that NARROW the surface (removing paths) do not require `--yes`.
|
|
196
196
|
|
|
197
197
|
The Settings UI's Project section enforces the same analyzer via a confirm dialog that enumerates the paths.
|
|
198
198
|
|
|
@@ -214,7 +214,6 @@ The three privacy-sensitive keys above PLUS `allowEditSmFiles` are members of `P
|
|
|
214
214
|
| `sm scan -n <node.path>` | Partial scan: one node. |
|
|
215
215
|
| `sm scan --changed` | Incremental: only files changed since last scan (mtime heuristic). |
|
|
216
216
|
| `sm scan --watch` | Long-running: watch the roots and trigger an incremental scan after each debounced batch of filesystem events. Alias of `sm watch`. |
|
|
217
|
-
| `sm scan -g` / `sm scan --global` | Global scan. Roots default to every active Provider's `explorationDir` resolved against `~` (typically `~/.claude`, `~/.gemini`, `~/.agents`); the cwd is NOT included. Config + DB resolve from the global scope (`~/.skill-map/...`). Mutually exclusive with explicit positional roots — passing both is rejected with exit `2`. |
|
|
218
217
|
| `sm scan compare-with <dump> [roots...]` | Delta report: run a fresh scan in memory and compare against the saved `ScanResult` dump at `<dump>`. Read-only — does not modify the DB. Exit `0` on empty delta, `1` on any drift, `2` on operational error (missing or malformed dump, schema violation). |
|
|
219
218
|
| `sm watch [roots...]` | Long-running watcher. Same semantics as `sm scan --watch`, exposed as a top-level verb because the watcher is a loop, not a one-shot scan. |
|
|
220
219
|
| `sm refresh <node.path>` | Re-run Extractors against a single node and upsert their outputs into the universal enrichment layer (`node_enrichments`, see [`db-schema.md`](./db-schema.md#node_enrichments)). Extractors are deterministic-only — they run synchronously and persist. Exit `0` on success, `2` on failure, `5` if the node is not in the persisted scan. |
|
|
@@ -224,10 +223,8 @@ The three privacy-sensitive keys above PLUS `allowEditSmFiles` are members of `P
|
|
|
224
223
|
|
|
225
224
|
**Effective roots** (one-shot `sm scan`):
|
|
226
225
|
|
|
227
|
-
- `sm scan [roots...]`: when positional roots are given, they ARE the effective roots (verbatim). When omitted: the effective roots are `[cwd]` plus the appended
|
|
228
|
-
- `scan.
|
|
229
|
-
- `scan.extraRoots[]` is appended verbatim (entries starting with `~` resolve against the user home; relative entries resolve against the project root).
|
|
230
|
-
- `sm scan -g`: effective roots are the active Providers' `explorationDir` only; `scan.includeHome` and `scan.extraRoots` are ignored. The cwd is NOT included. Config + DB resolve from the global scope.
|
|
226
|
+
- `sm scan [roots...]`: when positional roots are given, they ARE the effective roots (verbatim). When omitted: the effective roots are `[cwd]` plus the appended set below.
|
|
227
|
+
- `scan.extraFolders[]` is appended verbatim (entries starting with `~` resolve against the user home; relative entries resolve against the project root). This is the ONLY way to extend the scan beyond the project: there is no implicit HOME walk and Providers cannot opt their own directory in.
|
|
231
228
|
|
|
232
229
|
**Reference paths** (`scan.referencePaths[]`): walked in parallel by the scan to collect existing absolute paths into a side set. Files there are NOT parsed and NOT indexed as nodes; the kernel passes the set to analyzers via `IAnalyzerContext.referenceablePaths` so `core/broken-ref` can resolve a link against the filesystem when the in-graph lookup misses.
|
|
233
230
|
|
package/conformance/coverage.md
CHANGED
|
@@ -25,7 +25,7 @@ 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
|
|
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
29
|
| 19 | `extensions/extractor.schema.json` | — | 🔴 missing | Case: `frontmatter` + `slash` + `at-directive` extractor manifests validate; an extractor emitting a disallowed `emitsLinkKinds` value fails. |
|
|
30
30
|
| 20 | `extensions/analyzer.schema.json` | — | 🔴 missing | Case: `trigger-collision`, `broken-ref`, `superseded` manifests validate. |
|
|
31
31
|
| 21 | `extensions/action.schema.json` | — | 🔴 missing | Case: a `deterministic` action manifest validates; a `probabilistic` action WITHOUT `promptTemplateRef` fails. |
|
package/index.json
CHANGED
|
@@ -174,24 +174,24 @@
|
|
|
174
174
|
}
|
|
175
175
|
]
|
|
176
176
|
},
|
|
177
|
-
"specPackageVersion": "0.
|
|
177
|
+
"specPackageVersion": "0.22.0",
|
|
178
178
|
"integrity": {
|
|
179
179
|
"algorithm": "sha256",
|
|
180
180
|
"files": {
|
|
181
|
-
"CHANGELOG.md": "
|
|
181
|
+
"CHANGELOG.md": "8e8333f49fecfe1b7a36efe23ede8ca17edc6caa5123b9a816b693feaa913e56",
|
|
182
182
|
"README.md": "b551522ab0c7f5ef702e9ea4d4f67fd7ad838b080d85975c2834d8d40af14a00",
|
|
183
|
-
"architecture.md": "
|
|
184
|
-
"cli-contract.md": "
|
|
183
|
+
"architecture.md": "ca37e20cbe61a52c156a34f5ea2d660c3b920dfcda40cdb5601b5eac11f8fc21",
|
|
184
|
+
"cli-contract.md": "49a2f8042868f32f42a2504bc1c7e07d14642dc4f354c8ff6833d3a5a97a9a76",
|
|
185
185
|
"conformance/README.md": "70e3101104765ef359d5322d0a7c9248d2157f78a510fb2cc8005b4eba3173d6",
|
|
186
186
|
"conformance/cases/kernel-empty-boot.json": "2a5be9c93143d07a16d998df09dcc8fa4ea2d2f9a0bff6417573ed5a770352c1",
|
|
187
187
|
"conformance/cases/orphan-markdown-fallback.json": "8ef6e49b7e6532bd845d9f54974a16e537cf98d355f0c5e4f4fb06abac3adcc5",
|
|
188
188
|
"conformance/cases/plugin-missing-ui-rejected.json": "bdebee810436e6be88edf2fe38ddc6939fd3f53e6a12dc1d66da051c4922f1e9",
|
|
189
189
|
"conformance/cases/sidecar-end-to-end.json": "24a73e7c857709d001cf7013b8fe5ccad4027e064b39533dda33697d80b56e7a",
|
|
190
|
-
"conformance/coverage.md": "
|
|
190
|
+
"conformance/coverage.md": "c35846bea401fcb1f4fd6e26f6ef8f6459ab46b48757f9b3f39c137636628260",
|
|
191
191
|
"conformance/fixtures/orphan-markdown/.claude/agents/reviewer.md": "7f062731106f2d9811e4fffcf6ab44b8dfff4cfb16536a469514cc0664e832bf",
|
|
192
192
|
"conformance/fixtures/orphan-markdown/ARCHITECTURE.md": "d6b6e18d4b963b26a292de73348c3396fd4710ab4c4bdd6cf094e581f99ec8d6",
|
|
193
193
|
"conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/plugin.json": "4d78af6f12faa9d131e2a19f1dbb8f250baacc525978f3a8c858932b95da4ff6",
|
|
194
|
-
"conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/provider.js": "
|
|
194
|
+
"conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/provider.js": "45843e8e1a679482a17e01dcd43e1800e1d3148f4ac2cd6ab8a29ef0430b6152",
|
|
195
195
|
"conformance/fixtures/plugin-missing-ui/notes/example.md": "55767f0aa1b6774546a99f28c58e7b732aa9cfa5dfce8d0326470f7f622f577e",
|
|
196
196
|
"conformance/fixtures/preamble-v1.txt": "1e0aeef224b64477bdc13a949c3ad402e68249caf499ecdba1302371677c068b",
|
|
197
197
|
"conformance/fixtures/sidecar-end-to-end/.claude/agents/orphan.sm": "3102ff10a0f08f60c014f82409d45ad4faf2cefa04d652a87676d3557ad64944",
|
|
@@ -203,11 +203,11 @@
|
|
|
203
203
|
"interfaces/security-scanner.md": "aefe9f02f190615ba18649df03c1bdd79d98691039563c659e90f34362e5f1d5",
|
|
204
204
|
"job-events.md": "b223bf0e576cbd481688e163ab3ce0a6e952a8a4a3912f1342237b664984e388",
|
|
205
205
|
"job-lifecycle.md": "1d9c42632f8e77ef58ff47ae6d9680e7ed5939760627c75253aab8c80f728fd1",
|
|
206
|
-
"plugin-author-guide.md": "
|
|
206
|
+
"plugin-author-guide.md": "c77d5ac616d0f8ce029ef183cc4d29a480ffc50a0910320ed95a26cf1b33bce9",
|
|
207
207
|
"plugin-kv-api.md": "673e0a65825ba1aabf9b4ba0b4e0d5baf8e81dc5de1c13bee9532fbb33e7b440",
|
|
208
208
|
"prompt-preamble.md": "4860c310ccf2823870d318993ad8f067571799dade90bddb6634c3dbedd636b7",
|
|
209
209
|
"schemas/annotations.schema.json": "b3a9aa66de17058ccfd890ea9ff1b9ee315a0877e9dd4a58fd8b76e26a99d00e",
|
|
210
|
-
"schemas/api/rest-envelope.schema.json": "
|
|
210
|
+
"schemas/api/rest-envelope.schema.json": "80d5480ebb96d41de497f35e4e5415025e0b69d1b424435c6b0d3a45945e2f63",
|
|
211
211
|
"schemas/bump-report.schema.json": "c2d853715d5f50098567bc23382a4e81baf78d589c6e1baf67d3b841e7f7d8ae",
|
|
212
212
|
"schemas/conformance-case.schema.json": "f6d4c9fb92e79cb516eeeb9d042223572a3bd5ff8e7871a0becce13916f20cf6",
|
|
213
213
|
"schemas/execution-record.schema.json": "9628fa557cb856402f3a5f1d1167c609e46a197c850fe8171abfddd46c1028a8",
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
"schemas/extensions/extractor.schema.json": "a859a53a7a5b009b1fe20d322bc1a8ff62e4b91ef938e98b1c80c802bd734b37",
|
|
218
218
|
"schemas/extensions/formatter.schema.json": "2ab092aa37ae349c69b93071ed4f0e131affb7bb5799516ca82c721262631b36",
|
|
219
219
|
"schemas/extensions/hook.schema.json": "a55cec50f6fda5b924de86359b910d22548d0a5bb61b2051edb82a80d3b36a2b",
|
|
220
|
-
"schemas/extensions/provider.schema.json": "
|
|
220
|
+
"schemas/extensions/provider.schema.json": "c33219571b7bf5a80f8424c302e85f779895fd6a71daec58d0948be609b1310a",
|
|
221
221
|
"schemas/frontmatter/base.schema.json": "ec4abde950c31639974fc078e6bdc74ed48da4d2c0a996f5248684406910a178",
|
|
222
222
|
"schemas/history-stats.schema.json": "23f472d1de06d23fc775aabba821f8375f347af4dc8d89ba567980d61a11f9de",
|
|
223
223
|
"schemas/input-types.schema.json": "f1f51ccda746ea3c8a404757f60c89e403619e88ec4137a50af100ec89f8f4b5",
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
"schemas/link.schema.json": "7fc429d03aca7e4c0b9a28241712c1aa2a5275870cea5ed938c2f97e8cccb081",
|
|
227
227
|
"schemas/node.schema.json": "2ede4385e796cbf416c494d810dcb6d6036b35e71561efee46f5675bf0a015fe",
|
|
228
228
|
"schemas/plugins-registry.schema.json": "678f476cf460d0b5876a92e72e0d572b6db265dd9fad6e95db553c56f77db5d9",
|
|
229
|
-
"schemas/project-config.schema.json": "
|
|
229
|
+
"schemas/project-config.schema.json": "a34fc136e606fe9700228a836d1211add068613226ef16239af1101843aef76e",
|
|
230
230
|
"schemas/report-base-deterministic.schema.json": "6f8b38c097994ee87e0639935c42b5e85d8ea4244959ca397978171b0d7d2222",
|
|
231
231
|
"schemas/report-base.schema.json": "a1021e9a59b4df9f99cd92454d797e88469766e7d49f52d231c4645ffdfdad8f",
|
|
232
232
|
"schemas/scan-result.schema.json": "d1a8782e198bc9bb92dad247437aefa1b02f92ff8dca8562eaf2348fd7c5cf0c",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skill-map/spec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "JSON Schemas, prose contracts, and conformance suite for the skill-map specification.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
"spec:check": "node scripts/build-index.js --check && node scripts/check-coverage.js",
|
|
50
50
|
"pin": "node scripts/sync-pin.js",
|
|
51
51
|
"pin:check": "node scripts/sync-pin.js --check",
|
|
52
|
-
"validate": "npm run
|
|
52
|
+
"validate": "npm run validate:compile",
|
|
53
|
+
"validate:compile": "npm run spec:check && npm run pin:check"
|
|
53
54
|
},
|
|
54
55
|
"publishConfig": {
|
|
55
56
|
"access": "public"
|
package/plugin-author-guide.md
CHANGED
|
@@ -408,9 +408,9 @@ export default {
|
|
|
408
408
|
|
|
409
409
|
These ship later in the v1.x line as bundled built-ins; the spec already pins their manifest shapes. Until the testkit grows full helpers for them (planned alongside Step 10), authors are encouraged to test them with a live kernel via `sm scan` against a fixture directory rather than in unit tests.
|
|
410
410
|
|
|
411
|
-
#### Provider — `kinds` catalog
|
|
411
|
+
#### Provider — `kinds` catalog
|
|
412
412
|
|
|
413
|
-
Every Provider declares
|
|
413
|
+
Every Provider declares one required top-level field beyond the manifest base: `kinds`.
|
|
414
414
|
|
|
415
415
|
**`kinds` catalog.** Maps each kind the Provider emits to its frontmatter schema, its qualified `defaultRefreshAction`, and its `ui` presentation block. The kernel derives the supported kind set from `Object.keys(kinds)`. Each entry has three required fields:
|
|
416
416
|
|
|
@@ -418,14 +418,13 @@ Every Provider declares two required top-level fields beyond the manifest base:
|
|
|
418
418
|
- **`defaultRefreshAction`** — qualified action id (`<plugin-id>/<action-id>`) the UI's `🧠 prob` button dispatches. The action MUST exist in the registry; a dangling reference disables the Provider with `invalid-manifest`.
|
|
419
419
|
- **`ui`** — presentation block: `{ label, color, colorDark?, emoji?, icon? }`. The UI ships every `ui` block to the front-end via the `kindRegistry` envelope so built-in and user-plugin kinds render identically. `icon` is a discriminated union (`{ kind: 'pi'; id }` for PrimeIcons, `{ kind: 'svg'; path }` for raw SVG). The `ui` block is required (not optional) so the UI never has to invent visuals for unknown kinds. See [`architecture.md` §Provider · `ui` presentation](./architecture.md#provider--ui-presentation) for the field-by-field contract.
|
|
420
420
|
|
|
421
|
-
|
|
421
|
+
The Provider's walker hardcodes the paths it scans within the project (e.g. `.claude/`, `.cursor/rules`). The kernel does NOT extend the scan into the user's HOME based on Provider hints; the only way to scan paths outside the project is `scan.extraFolders` (set by the operator), which is privacy-sensitive and gated by `--yes`.
|
|
422
422
|
|
|
423
423
|
```jsonc
|
|
424
424
|
{
|
|
425
425
|
"id": "cursor",
|
|
426
426
|
"kind": "provider",
|
|
427
427
|
"version": "1.0.0",
|
|
428
|
-
"explorationDir": "~/.cursor",
|
|
429
428
|
"kinds": {
|
|
430
429
|
"skill": {
|
|
431
430
|
"schema": "./schemas/skill.schema.json",
|
|
@@ -883,7 +882,7 @@ Anything else (e.g. bare `"search"` without a prefix) is rejected at manifest lo
|
|
|
883
882
|
|
|
884
883
|
### Slot catalog (closed)
|
|
885
884
|
|
|
886
|
-
The kernel ships exactly these
|
|
885
|
+
The kernel ships exactly these 14 slots. Each slot fixes a renderer + a payload shape; multiple slots may share a payload shape (e.g. all counter slots accept `{ value }`). Adding a slot requires a spec / UI / scaffolder round-trip — discuss in [`ROADMAP.md`](../ROADMAP.md) before opening a PR.
|
|
887
886
|
|
|
888
887
|
| Slot | Payload shape | Renderer |
|
|
889
888
|
|---|---|---|
|
|
@@ -920,7 +919,7 @@ The first argument is the manifest Record key (`'breakdown'` or `'total'` above)
|
|
|
920
919
|
|
|
921
920
|
The kernel validates the payload against the slot's payload schema in `view-slots.schema.json#/$defs/payloads/<slot>`. Off-shape payloads emit an `extension.error` event and drop silently — same posture as `emitLink` rejecting links not in your `emitsLinkKinds`.
|
|
922
921
|
|
|
923
|
-
For `topbar.nav.start`, analyzers use `ctx.emitScopeContribution(id, payload)` (extractors do not see this method — scope-level emission lives in analyzer context).
|
|
922
|
+
For `topbar.nav.start`, analyzers use `ctx.emitScopeContribution(id, payload)` (extractors do not see this method — scope-level emission lives in analyzer context). **The `emitScopeContribution` callback is reserved in the spec but not yet implemented** on `IAnalyzerContext`; a manifest declaring a `topbar.nav.start` contribution loads fine, but emissions are deferred until the runtime callback ships. See `architecture.md` §View contribution system → Emit path for the canonical status.
|
|
924
923
|
|
|
925
924
|
### Multi-slot rendering
|
|
926
925
|
|
|
@@ -120,7 +120,11 @@
|
|
|
120
120
|
"tooltip": { "type": "string", "maxLength": 256 },
|
|
121
121
|
"icon": { "type": "string", "maxLength": 64 },
|
|
122
122
|
"emptyText": { "type": "string", "maxLength": 128 },
|
|
123
|
-
"emitWhenEmpty": { "type": "boolean", "default": false }
|
|
123
|
+
"emitWhenEmpty": { "type": "boolean", "default": false },
|
|
124
|
+
"priority": {
|
|
125
|
+
"type": "number",
|
|
126
|
+
"description": "Optional ordering hint (default 100 when omitted). Slots whose `order` is `'priority'` sort contributions ASC by this value with alphabetical tie-break by qualified id. Mirror of `IViewContribution.priority` in `view-slots.schema.json#/$defs/ViewContribution`; propagated so the UI can apply the manifest-declared order without a second round-trip."
|
|
127
|
+
}
|
|
124
128
|
}
|
|
125
129
|
}
|
|
126
130
|
},
|
|
@@ -2,20 +2,15 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://skill-map.dev/spec/v0/extensions/provider.schema.json",
|
|
4
4
|
"title": "ExtensionProvider",
|
|
5
|
-
"description": "Manifest shape for a `Provider` extension. A Provider declares its own universe: the platform it recognises (Claude Code, Codex, Gemini, Obsidian vault, generic MD), the catalog of node `kind`s it emits, the per-kind frontmatter schema each kind follows
|
|
5
|
+
"description": "Manifest shape for a `Provider` extension. A Provider declares its own universe: the platform it recognises (Claude Code, Codex, Gemini, Obsidian vault, generic MD), the catalog of node `kind`s it emits, and the per-kind frontmatter schema each kind follows. The catalog lives in the `kinds` map, keyed by kind name. Each map entry declares the relative path to the kind's frontmatter schema (resolved against the Provider's directory) and the qualified `defaultRefreshAction` id the UI's probabilistic-refresh surface dispatches for that kind. Spec only ships `frontmatter/base.schema.json` (universal); per-kind schemas live with their owning Provider so that adding a new platform is purely additive — no spec bump needed to introduce kinds. Exactly zero or one Provider MUST match any given file; multiple matches → the kernel emits an issue `provider-ambiguous` and the file is left unclassified. Providers are deterministic-only — they sit at the filesystem boundary and run during boot; probabilistic classification would make boot slow, costly, and non-reproducible. The `mode` field MUST NOT appear in Provider manifests. If you need LLM-assisted classification, write a probabilistic Action that runs as a queued job and writes back through the enrichment layer; Extractors are deterministic-only and Providers stay on the deterministic boot path. Distinct from the **hexagonal-architecture** 'adapter' (`RunnerPort.adapter`, `StoragePort.adapter`, etc.), which is an internal driven-adapter implementing a port — Providers live in the extension surface, hexagonal adapters live in `src/kernel/adapters/`. Stability: stable as of spec v1.0.0 except where noted.",
|
|
6
6
|
"allOf": [
|
|
7
7
|
{ "$ref": "base.schema.json" }
|
|
8
8
|
],
|
|
9
9
|
"type": "object",
|
|
10
|
-
"required": ["id", "kind", "version", "kinds"
|
|
10
|
+
"required": ["id", "kind", "version", "kinds"],
|
|
11
11
|
"unevaluatedProperties": false,
|
|
12
12
|
"properties": {
|
|
13
13
|
"kind": { "const": "provider" },
|
|
14
|
-
"explorationDir": {
|
|
15
|
-
"type": "string",
|
|
16
|
-
"minLength": 1,
|
|
17
|
-
"description": "Filesystem directory (relative to user home or project root) where this Provider's content lives. Required. Examples: '~/.claude' for the Claude Provider; '~/.cursor' for a hypothetical Cursor Provider. The kernel walks this directory during boot/scan to discover nodes; the Provider's `globs` (if declared) refines what to match inside. `sm doctor` validates the directory exists; missing directory yields a non-blocking warning."
|
|
18
|
-
},
|
|
19
14
|
"roots": {
|
|
20
15
|
"type": "array",
|
|
21
16
|
"description": "Path globs (relative to scope root) that this Provider SHOULD be consulted for. Advisory — the kernel walks all roots and consults every Provider regardless, but this field lets `sm doctor` warn when no file matched a specific Provider (i.e. the Provider was loaded for a platform that isn't in this scope).",
|
|
@@ -58,19 +58,15 @@
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
|
-
"
|
|
62
|
-
"type": "boolean",
|
|
63
|
-
"description": "**Privacy-sensitive, project-local only** (per `core/config/helper:PROJECT_LOCAL_ONLY_KEYS`) — opens disk access outside the project. Default false. When true, `sm scan` (without `-g`) appends every active Provider's `explorationDir` resolved against `~` (typically `~/.claude`, `~/.gemini`, `~/.agents`) to the scan roots. Files there are walked, parsed, and indexed as nodes alongside the project content. Reference impl: `sm config set scan.includeHome true` requires `--yes` to confirm; the Settings UI's Project section requires an explicit confirm dialog. The scan emits a stderr line listing the HOME paths it added so the operator sees the expanded surface. **Stripped with a warning when found in the committed `project` layer** so a teammate's `~/` is never scanned because of a shared checkout."
|
|
64
|
-
},
|
|
65
|
-
"extraRoots": {
|
|
61
|
+
"extraFolders": {
|
|
66
62
|
"type": "array",
|
|
67
63
|
"items": { "type": "string" },
|
|
68
|
-
"description": "**Privacy-sensitive, project-local only** (per `core/config/helper:PROJECT_LOCAL_ONLY_KEYS`) when entries point outside the project — opens disk access there. Default `[]`. Additional directories appended to the scan roots; same parsing / indexing as the project root. Paths starting with `~` resolve against the user home; relative paths resolve against the project root. Reference impl gates writes that introduce out-of-project paths behind `--yes` (CLI) and a confirm dialog (UI)
|
|
64
|
+
"description": "**Privacy-sensitive, project-local only** (per `core/config/helper:PROJECT_LOCAL_ONLY_KEYS`) when entries point outside the project — opens disk access there. Default `[]`. Additional directories appended to the scan roots; same parsing / indexing as the project root. Paths starting with `~` resolve against the user home; relative paths resolve against the project root. Reference impl gates writes that introduce out-of-project paths behind `--yes` (CLI) and a confirm dialog (UI). **Stripped with a warning when found in the committed `project` layer** — paths are inherently per-machine and must not travel via the shared repo. This is the ONLY mechanism to extend the scan beyond the project root: skill-map does NOT auto-include the user's HOME based on Provider hints — every out-of-project path must be listed here explicitly."
|
|
69
65
|
},
|
|
70
66
|
"referencePaths": {
|
|
71
67
|
"type": "array",
|
|
72
68
|
"items": { "type": "string" },
|
|
73
|
-
"description": "**Privacy-sensitive, project-local only** (per `core/config/helper:PROJECT_LOCAL_ONLY_KEYS`) when entries point outside the project — opens read-only disk access for link validation only. Default `[]`. Directories walked in parallel by the scan to collect existing absolute paths into a side set; the kernel passes the set to analyzers via `IAnalyzerContext.referenceablePaths` so `core/broken-ref` can resolve a link against the filesystem when the in-graph lookup misses. Files under these paths are NOT parsed and NOT indexed as nodes — the only effect is suppressing `broken-ref` warnings for targets that exist on disk outside the scan. Same write-gate analyzers as `
|
|
69
|
+
"description": "**Privacy-sensitive, project-local only** (per `core/config/helper:PROJECT_LOCAL_ONLY_KEYS`) when entries point outside the project — opens read-only disk access for link validation only. Default `[]`. Directories walked in parallel by the scan to collect existing absolute paths into a side set; the kernel passes the set to analyzers via `IAnalyzerContext.referenceablePaths` so `core/broken-ref` can resolve a link against the filesystem when the in-graph lookup misses. Files under these paths are NOT parsed and NOT indexed as nodes — the only effect is suppressing `broken-ref` warnings for targets that exist on disk outside the scan. Same write-gate analyzers as `extraFolders`. **Stripped with a warning when found in the committed `project` layer**."
|
|
74
70
|
}
|
|
75
71
|
}
|
|
76
72
|
},
|