@skill-map/spec 0.5.1 → 0.6.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 +223 -0
- package/cli-contract.md +3 -3
- package/conformance/cases/orphan-detection.json +22 -0
- package/conformance/cases/rename-high.json +21 -0
- package/conformance/coverage.md +2 -2
- package/conformance/fixtures/orphan-after/skills/keep.md +13 -0
- package/conformance/fixtures/orphan-before/skills/keep.md +13 -0
- package/conformance/fixtures/orphan-before/skills/lonely.md +13 -0
- package/conformance/fixtures/rename-high-after/skills/bar.md +14 -0
- package/conformance/fixtures/rename-high-before/skills/foo.md +14 -0
- package/db-schema.md +31 -1
- package/index.json +14 -7
- package/package.json +1 -1
- package/schemas/conformance-case.schema.json +22 -2
- package/schemas/project-config.schema.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,228 @@
|
|
|
1
1
|
# Spec changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f41dbad: Step 6.1 — Spec migration: rename the canonical config file from
|
|
8
|
+
`.skill-map.json` (single project-root file) to `.skill-map/settings.json`
|
|
9
|
+
inside the `.skill-map/` scope folder, with a sibling `.skill-map/settings.local.json`
|
|
10
|
+
partner for machine-specific overrides. Aligns the spec with the layered
|
|
11
|
+
config hierarchy described in the roadmap (library defaults → user → user-local
|
|
12
|
+
→ project → project-local → env / flags).
|
|
13
|
+
|
|
14
|
+
**Spec change (breaking, minor under pre-1.0 versioning policy)**:
|
|
15
|
+
|
|
16
|
+
- `spec/schemas/project-config.schema.json` description updated to point at
|
|
17
|
+
`.skill-map/settings.json` and explicitly mention the `.local.json` partner
|
|
18
|
+
and the layered-merge contract. The schema _shape_ (keys, types, validation
|
|
19
|
+
rules) is unchanged — only the on-disk filename moves. Consumers that read
|
|
20
|
+
values without caring about the source path are unaffected; consumers that
|
|
21
|
+
hard-code the filename must update.
|
|
22
|
+
- `spec/db-schema.md` §Scopes: `history.share: true` reference updated to
|
|
23
|
+
`.skill-map/settings.json`.
|
|
24
|
+
- `spec/conformance/coverage.md` row #6 description updated to reference the
|
|
25
|
+
new path and the optional `settings.local.json` overlay.
|
|
26
|
+
|
|
27
|
+
**Why minor (not major) at pre-1.0**: per `spec/versioning.md` §Pre-1.0,
|
|
28
|
+
breaking changes ARE allowed in minor bumps while the spec is `0.y.z`. The
|
|
29
|
+
shape of the data is unchanged; only the file name on disk moves.
|
|
30
|
+
|
|
31
|
+
**No backward-compat shim**: there is no real implementation of the loader
|
|
32
|
+
yet (lands in 6.2), so no live consumer reads `.skill-map.json` today. The
|
|
33
|
+
only known prior reference is the demo `mock-collection/.claude/commands/init*.md`
|
|
34
|
+
fixture, which is updated together with `sm init` in 6.5.
|
|
35
|
+
|
|
36
|
+
**Runtime change**: none in 6.1 — pure spec edit. The matching loader,
|
|
37
|
+
`sm init`, and `sm config` verbs land in subsequent sub-steps.
|
|
38
|
+
|
|
39
|
+
**Roadmap update**: `ROADMAP.md` §Configuration "Spec migration" call-out
|
|
40
|
+
flipped from "pending" to "landed Step 6.1, 2026-04-27".
|
|
41
|
+
|
|
42
|
+
Test count: unchanged (213 → 213 — spec-only edit).
|
|
43
|
+
|
|
44
|
+
- 8a4667f: Step 6.6 — `sm plugins enable / disable` + the `config_plugins`
|
|
45
|
+
override layer they read from. The two stub verbs become real, and
|
|
46
|
+
the `PluginLoader` finally honours user intent: a disabled plugin
|
|
47
|
+
surfaces in `sm plugins list` with status `disabled`, but its
|
|
48
|
+
extensions are NOT imported and the kernel will not run them.
|
|
49
|
+
|
|
50
|
+
**Decision (recorded in spec)**: enable/disable resolution favours the
|
|
51
|
+
DB row over `settings.json` over the installed default. The DB
|
|
52
|
+
override is local-machine; `settings.json` is the team-shared baseline.
|
|
53
|
+
A developer can locally disable a misbehaving plugin without
|
|
54
|
+
committing the toggle to the team's config; conversely, a baseline
|
|
55
|
+
that explicitly enables a plugin is overridable per-machine. The rule
|
|
56
|
+
is documented in `spec/db-schema.md` §`config_plugins`.
|
|
57
|
+
|
|
58
|
+
**Spec change (additive, patch)**:
|
|
59
|
+
|
|
60
|
+
- `spec/db-schema.md` — appended an "Effective enable/disable
|
|
61
|
+
resolution" subsection under `config_plugins` documenting the
|
|
62
|
+
three-layer precedence (DB > `settings.json` > installed default).
|
|
63
|
+
No schema changes; the `config_plugins` table itself was already
|
|
64
|
+
defined in the initial migration.
|
|
65
|
+
|
|
66
|
+
**Runtime change**:
|
|
67
|
+
|
|
68
|
+
- `src/kernel/types/plugin.ts` — `TPluginLoadStatus` gains a `disabled`
|
|
69
|
+
variant. JSDoc explains all five states.
|
|
70
|
+
- `src/kernel/adapters/sqlite/plugins.ts` — new file. Storage helpers
|
|
71
|
+
over the `config_plugins` table: `setPluginEnabled` (upsert),
|
|
72
|
+
`getPluginEnabled` (single read), `loadPluginOverrideMap` (bulk
|
|
73
|
+
read for one round-trip per process), `deletePluginOverride`
|
|
74
|
+
(idempotent drop, used by future `sm config reset plugins.<id>`).
|
|
75
|
+
- `src/kernel/config/plugin-resolver.ts` — new file.
|
|
76
|
+
`resolvePluginEnabled` implements the precedence above;
|
|
77
|
+
`makeEnabledResolver` curries the layered config and DB map into
|
|
78
|
+
the `(id) => boolean` shape `IPluginLoaderOptions.resolveEnabled`
|
|
79
|
+
expects.
|
|
80
|
+
- `src/kernel/adapters/plugin-loader.ts` — new optional
|
|
81
|
+
`resolveEnabled` callback in `IPluginLoaderOptions`. When supplied,
|
|
82
|
+
the loader checks AFTER manifest + specCompat validation and
|
|
83
|
+
short-circuits with `status: 'disabled'` (manifest preserved,
|
|
84
|
+
extensions array omitted, reason `"disabled by config_plugins or
|
|
85
|
+
settings.json"`). Omitting the callback keeps the legacy "always
|
|
86
|
+
load" behaviour for tests / kernel-empty-boot.
|
|
87
|
+
- `src/cli/commands/plugins.ts` — wires the loader to the resolver:
|
|
88
|
+
every read (`list / show / doctor`) loads `config_plugins` once and
|
|
89
|
+
feeds the resolver. Two new commands `PluginsEnableCommand` and
|
|
90
|
+
`PluginsDisableCommand` write to the DB. `--all` toggles every
|
|
91
|
+
discovered plugin; `<id>` and `--all` are mutually exclusive.
|
|
92
|
+
`sm plugins doctor` now treats `disabled` as intentional (does not
|
|
93
|
+
contribute to the issue list, does not flip exit code).
|
|
94
|
+
- `src/cli/commands/plugins.ts` — adds `off` to the status icon legend
|
|
95
|
+
in human output (`off mock-a@0.1.0 · disabled by config_plugins or
|
|
96
|
+
settings.json`).
|
|
97
|
+
- `src/cli/commands/stubs.ts` — `PluginsEnableCommand` and
|
|
98
|
+
`PluginsDisableCommand` removed; replaced-at-step comment kept.
|
|
99
|
+
- `context/cli-reference.md` — regenerated; the two new verbs appear
|
|
100
|
+
with their flag tables.
|
|
101
|
+
|
|
102
|
+
**Tests**:
|
|
103
|
+
|
|
104
|
+
- `src/test/plugin-overrides.test.ts` — 8 unit tests covering storage
|
|
105
|
+
round-trip (upsert + read), `loadPluginOverrideMap` bulk read,
|
|
106
|
+
`deletePluginOverride` idempotency, resolver precedence (default ⇒
|
|
107
|
+
true, `settings.json` overrides default, DB overrides
|
|
108
|
+
`settings.json`), `makeEnabledResolver` currying, and PluginLoader
|
|
109
|
+
surfacing `disabled` status with manifest preserved + no extensions
|
|
110
|
+
- omitting the resolver still loads.
|
|
111
|
+
- `src/test/plugins-cli.test.ts` — 9 end-to-end tests via the binary:
|
|
112
|
+
`disable <id>` writes a DB row + `sm plugins list` reflects `off`,
|
|
113
|
+
`enable <id>` flips back, `--all` covers every discovered plugin,
|
|
114
|
+
unknown id → exit 5, no-arg → exit 2, both `<id>` and `--all` →
|
|
115
|
+
exit 2, `settings.json` baseline overridden by DB `enable`,
|
|
116
|
+
`settings.json` baseline applies when DB has no row, and
|
|
117
|
+
`sm plugins doctor` exits 0 when the only non-loaded plugin is
|
|
118
|
+
intentionally disabled.
|
|
119
|
+
|
|
120
|
+
Test count: 273 → 291 (+18).
|
|
121
|
+
|
|
122
|
+
## 0.6.0
|
|
123
|
+
|
|
124
|
+
### Minor Changes
|
|
125
|
+
|
|
126
|
+
- 9a89124: Step 5.1 — Persist scan-result metadata in a new `scan_meta` table so
|
|
127
|
+
`loadScanResult` returns real values for `scope` / `roots` / `scannedAt` /
|
|
128
|
+
`scannedBy` / `adapters` / `stats.filesWalked` / `stats.filesSkipped` /
|
|
129
|
+
`stats.durationMs` instead of the synthetic envelope shipped at Step 4.7.
|
|
130
|
+
|
|
131
|
+
**Spec change (additive, minor)**:
|
|
132
|
+
|
|
133
|
+
- New `scan_meta` table in zone `scan_*`, single-row (CHECK `id = 1`).
|
|
134
|
+
Columns: `scope`, `roots_json`, `scanned_at`, `scanned_by_name`,
|
|
135
|
+
`scanned_by_version`, `scanned_by_spec_version`, `adapters_json`,
|
|
136
|
+
`stats_files_walked`, `stats_files_skipped`, `stats_duration_ms`.
|
|
137
|
+
`nodesCount` / `linksCount` / `issuesCount` are not stored — they are
|
|
138
|
+
derived from `COUNT(*)` of the sibling tables.
|
|
139
|
+
- Replaced atomically with the rest of `scan_*` on every `sm scan`.
|
|
140
|
+
|
|
141
|
+
**Runtime change**:
|
|
142
|
+
|
|
143
|
+
- New kernel migration `002_scan_meta.sql`.
|
|
144
|
+
- `IScanMetaTable` added to `src/kernel/adapters/sqlite/schema.ts` and
|
|
145
|
+
bound in `IDatabase`.
|
|
146
|
+
- `persistScanResult` writes the row (and deletes prior rows in the same
|
|
147
|
+
transaction).
|
|
148
|
+
- `loadScanResult` reads from `scan_meta` when the row exists; degrades
|
|
149
|
+
to the previous synthetic envelope when it does not (DB freshly
|
|
150
|
+
migrated, never scanned, or pre-5.1 snapshot).
|
|
151
|
+
- The Step 4.7 follow-up notes in `scan-load.ts` documenting the
|
|
152
|
+
synthetic envelope are simplified to describe both branches.
|
|
153
|
+
|
|
154
|
+
Test count: 151 → 154 (+3 covering meta round-trip, replace-all
|
|
155
|
+
single-row invariant, and synthetic-fallback on empty DB).
|
|
156
|
+
|
|
157
|
+
- 9a89124: Step 5.7 — Conformance coverage for the rename heuristic.
|
|
158
|
+
|
|
159
|
+
**Spec change (additive, minor)**:
|
|
160
|
+
|
|
161
|
+
- `spec/schemas/conformance-case.schema.json` gains
|
|
162
|
+
`setup.priorScans: Array<{ fixture, flags? }>` — an ordered list of
|
|
163
|
+
staging scans the runner executes BEFORE the main `invoke`. Each
|
|
164
|
+
step replaces every non-`.skill-map/` directory in the scope with
|
|
165
|
+
the named fixture and runs `sm scan` (with optional flags). The DB
|
|
166
|
+
persists across steps because `.skill-map/` is preserved between
|
|
167
|
+
swaps. After the last step, the runner copies the top-level
|
|
168
|
+
`fixture` and runs the case's `invoke`.
|
|
169
|
+
|
|
170
|
+
Required to express scenarios that need a prior snapshot (rename
|
|
171
|
+
heuristic, future incremental cases). The schema is purely
|
|
172
|
+
additive — every existing case keeps passing without modification.
|
|
173
|
+
|
|
174
|
+
- Two new conformance cases under `spec/conformance/cases/`:
|
|
175
|
+
|
|
176
|
+
- **`rename-high`** — moving a single file with identical body
|
|
177
|
+
triggers a high-confidence auto-rename. Asserts:
|
|
178
|
+
`stats.nodesCount === 1`, `stats.issuesCount === 0`,
|
|
179
|
+
`nodes[0].path === skills/bar.md`. Verifies the spec invariant
|
|
180
|
+
that high-confidence renames emit NO issue.
|
|
181
|
+
- **`orphan-detection`** — deleting a file with no replacement
|
|
182
|
+
emits exactly one `orphan` issue (severity `info`). Asserts the
|
|
183
|
+
`ruleId` and `severity` directly.
|
|
184
|
+
|
|
185
|
+
- Four new fixture directories under `spec/conformance/fixtures/`:
|
|
186
|
+
`rename-high-before/`, `rename-high-after/`,
|
|
187
|
+
`orphan-before/`, `orphan-after/`.
|
|
188
|
+
|
|
189
|
+
- `spec/conformance/coverage.md`: row I (Rename heuristic) flips
|
|
190
|
+
from `🔴 missing` to `🟢 covered`. Notes the medium / ambiguous
|
|
191
|
+
branches stay covered by `src/test/rename-heuristic.test.ts` for
|
|
192
|
+
now (assertion vocabulary in the schema is not rich enough to
|
|
193
|
+
express "the issues array contains an item with ruleId X and
|
|
194
|
+
data.confidence === 'medium'" — when the conformance schema gains
|
|
195
|
+
array-filter assertions, those branches can land here too).
|
|
196
|
+
|
|
197
|
+
**Runtime change**:
|
|
198
|
+
|
|
199
|
+
- `src/conformance/index.ts` runner: implements `setup.priorScans`.
|
|
200
|
+
Helper `replaceFixture(scope, specRoot, fixture)` clears every
|
|
201
|
+
top-level entry in the scope except `.skill-map/`, then copies the
|
|
202
|
+
named fixture on top. Used by both staging steps and the main
|
|
203
|
+
`fixture` phase.
|
|
204
|
+
- `src/test/conformance.test.ts`: includes the two new cases in the
|
|
205
|
+
Step-0b subset. Total conformance cases passing in CI: 1 → 3.
|
|
206
|
+
|
|
207
|
+
**`spec/index.json`** regenerated (50 → 57 files). `npm run spec:check`
|
|
208
|
+
green.
|
|
209
|
+
|
|
210
|
+
Test count: 201 → 203 (+2 conformance cases). The Step 5 totals close
|
|
211
|
+
at: 151 → 203 (+52 across 7 sub-steps).
|
|
212
|
+
|
|
213
|
+
### Patch Changes
|
|
214
|
+
|
|
215
|
+
- dacd4d9: Move the auto-generated CLI reference from `docs/cli-reference.md` to
|
|
216
|
+
`context/cli-reference.md`. Spec change is editorial: `cli-contract.md`
|
|
217
|
+
references the file path in three spots (`--format md` description, the
|
|
218
|
+
NORMATIVE introspection section, and the "Related" link list); all three
|
|
219
|
+
updated to the new location. No schema or behavioural change.
|
|
220
|
+
|
|
221
|
+
Reference impl: `scripts/build-cli-reference.mjs` writes to the new path,
|
|
222
|
+
the `cli:reference` / `cli:check` npm scripts point there, and `sm help`
|
|
223
|
+
output (which embeds the path in the `--format md` flag description) is
|
|
224
|
+
regenerated. The `docs/` folder is gone.
|
|
225
|
+
|
|
3
226
|
## 0.5.1
|
|
4
227
|
|
|
5
228
|
### Patch Changes
|
package/cli-contract.md
CHANGED
|
@@ -121,7 +121,7 @@ Exit: 0 if all green, 1 if warnings, 2 if any `error`-level problem.
|
|
|
121
121
|
Self-describing introspection.
|
|
122
122
|
|
|
123
123
|
- `human` (default): pretty terminal output.
|
|
124
|
-
- `md`: canonical markdown for documentation sites. Implementations MUST NOT hand-maintain equivalent markdown; `
|
|
124
|
+
- `md`: canonical markdown for documentation sites. Implementations MUST NOT hand-maintain equivalent markdown; `context/cli-reference.md` (in the reference impl) is regenerated from this output in CI.
|
|
125
125
|
- `json`: structured surface dump. Shape:
|
|
126
126
|
|
|
127
127
|
```json
|
|
@@ -314,7 +314,7 @@ Destructive verbs (`reset --state`, `reset --hard`, `restore`) require interacti
|
|
|
314
314
|
### Introspection
|
|
315
315
|
|
|
316
316
|
- `sm help --format json` — structured CLI surface dump.
|
|
317
|
-
- `sm help --format md` — canonical markdown, CI-enforced for the reference impl's `
|
|
317
|
+
- `sm help --format md` — canonical markdown, CI-enforced for the reference impl's `context/cli-reference.md`.
|
|
318
318
|
|
|
319
319
|
These two formats are NORMATIVE: any change to verbs, flags, or exit codes MUST reflect in `--format json` output immediately. Third-party consumers rely on this.
|
|
320
320
|
|
|
@@ -390,7 +390,7 @@ The `done in …` stderr line, its format grammar, and the `elapsedMs` field con
|
|
|
390
390
|
- [`job-lifecycle.md`](./job-lifecycle.md) — state machine behind `sm job` verbs.
|
|
391
391
|
- [`job-events.md`](./job-events.md) — event stream emitted via `--json` and `--stream-output`.
|
|
392
392
|
- [`db-schema.md`](./db-schema.md) — tables behind `sm db` verbs.
|
|
393
|
-
- [`../
|
|
393
|
+
- [`../context/cli-reference.md`](../context/cli-reference.md) — auto-generated reference from `sm help --format md`.
|
|
394
394
|
- [`conformance/`](./conformance/README.md) — test suite exercising CLI behavior.
|
|
395
395
|
|
|
396
396
|
---
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
|
|
3
|
+
"id": "orphan-detection",
|
|
4
|
+
"description": "Deleting a file with no replacement triggers the orphan branch of the rename heuristic: exactly one issue with ruleId `orphan` is emitted, severity `info`, naming the dead path. The remaining survivor node is reported normally.",
|
|
5
|
+
"fixture": "orphan-after",
|
|
6
|
+
"setup": {
|
|
7
|
+
"priorScans": [
|
|
8
|
+
{ "fixture": "orphan-before" }
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"invoke": {
|
|
12
|
+
"verb": "scan",
|
|
13
|
+
"flags": ["--changed", "--json"]
|
|
14
|
+
},
|
|
15
|
+
"assertions": [
|
|
16
|
+
{ "type": "exit-code", "value": 0 },
|
|
17
|
+
{ "type": "json-path", "path": "$.stats.nodesCount", "equals": 1 },
|
|
18
|
+
{ "type": "json-path", "path": "$.stats.issuesCount", "equals": 1 },
|
|
19
|
+
{ "type": "json-path", "path": "$.issues[0].ruleId", "equals": "orphan" },
|
|
20
|
+
{ "type": "json-path", "path": "$.issues[0].severity", "equals": "info" }
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
|
|
3
|
+
"id": "rename-high",
|
|
4
|
+
"description": "Moving a single file with identical body across the rename triggers a high-confidence auto-rename: NO issue is emitted (per spec/db-schema.md §Rename detection), the new path is the only node in the result, and the rename heuristic operates silently.",
|
|
5
|
+
"fixture": "rename-high-after",
|
|
6
|
+
"setup": {
|
|
7
|
+
"priorScans": [
|
|
8
|
+
{ "fixture": "rename-high-before" }
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"invoke": {
|
|
12
|
+
"verb": "scan",
|
|
13
|
+
"flags": ["--changed", "--json"]
|
|
14
|
+
},
|
|
15
|
+
"assertions": [
|
|
16
|
+
{ "type": "exit-code", "value": 0 },
|
|
17
|
+
{ "type": "json-path", "path": "$.stats.nodesCount", "equals": 1 },
|
|
18
|
+
{ "type": "json-path", "path": "$.stats.issuesCount", "equals": 0 },
|
|
19
|
+
{ "type": "json-path", "path": "$.nodes[0].path", "equals": "skills/bar.md" }
|
|
20
|
+
]
|
|
21
|
+
}
|
package/conformance/coverage.md
CHANGED
|
@@ -13,7 +13,7 @@ This file is hand-maintained. A CI check before spec release compares the schema
|
|
|
13
13
|
| 3 | `issue.schema.json` | — | 🔴 missing | Needs fixture triggering `trigger-collision` + `broken-ref` + `superseded`. |
|
|
14
14
|
| 4 | `scan-result.schema.json` | `basic-scan`, `kernel-empty-boot` | 🟢 covered | Zero-filled (empty-boot) + populated (minimal-claude) both asserted. |
|
|
15
15
|
| 5 | `execution-record.schema.json` | — | 🔴 missing | Blocked by Step 5 (history). Needs a case that runs a `local` action and inspects `state_executions` via `sm history --json`. |
|
|
16
|
-
| 6 | `project-config.schema.json` | — | 🔴 missing | Case: init a scope, write a partial `.skill-map.json
|
|
16
|
+
| 6 | `project-config.schema.json` | — | 🔴 missing | Case: init a scope, write a partial `.skill-map/settings.json` (optionally with a `.skill-map/settings.local.json` overlay), assert effective config after the layered merge. |
|
|
17
17
|
| 7 | `plugins-registry.schema.json` | — | 🔴 missing | Two sub-cases required: (a) `PluginManifest` validation via `sm plugins show --json`; (b) aggregate `PluginsRegistry` via `sm plugins list --json`. |
|
|
18
18
|
| 8 | `job.schema.json` | — | 🔴 missing | Blocked by Step 10 (job system). Needs a case that submits a local action (no LLM), inspects `sm job show --json`. |
|
|
19
19
|
| 9 | `report-base.schema.json` | — | 🔴 missing | Indirect coverage once any summarizer case lands. Direct contract case: validate a handcrafted minimal report ({confidence, safety}) against the base schema. |
|
|
@@ -54,7 +54,7 @@ These have their own conformance cases even though they are not JSON Schemas.
|
|
|
54
54
|
| F | Nonce mismatch | — | 🔴 missing | Blocked by Step 10. `sm record` with wrong nonce → exit 4. |
|
|
55
55
|
| G | Reap | — | 🔴 missing | Blocked by Step 10. Set TTL to 1s; claim; wait; next `sm job run` reaps with reason `abandoned`. |
|
|
56
56
|
| H | `run.*` event envelope for Skill agent | — | 🔴 missing | Blocked by Step 10. Skill-agent flow emits synthetic `r-ext-*` run envelope around one job. |
|
|
57
|
-
| I | Rename heuristic |
|
|
57
|
+
| I | Rename heuristic | `rename-high`, `orphan-detection` | 🟢 covered | High-confidence rename emits no issue and the new path is the sole node. Orphan branch emits exactly one `orphan` issue (severity `info`) when a deleted node has no replacement. Medium / ambiguous branches are exercised by `src/test/rename-heuristic.test.ts` until the conformance schema grows richer assertions. |
|
|
58
58
|
| J | Plugin DDL rejection | — | 🔴 missing | Blocked by Step 9. Plugin migration referencing `state_jobs` → disabled with `invalid-manifest`. |
|
|
59
59
|
| K | Plugin prefix injection | — | 🔴 missing | Blocked by Step 9. Plugin declares `CREATE TABLE foo` → kernel applies as `plugin_<id>_foo`. |
|
|
60
60
|
| L | Elapsed-time reporting | — | 🔴 missing | Blocked by Step 4 (first real verb work). Run any in-scope verb; stderr last line MUST match `/^done in (\d+ms\|\d+\.\d+s\|\d+m \d+s)$/`. In-scope verb with `--json` returning an object MUST carry `elapsedMs`. Exempt verb (`sm version`) MUST NOT emit the line. |
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orphan-keep
|
|
3
|
+
description: Fixture node that survives across before/after, so the after-state still has at least one node.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
stability: stable
|
|
7
|
+
author: conformance
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Survivor
|
|
11
|
+
|
|
12
|
+
Keeps the after-state graph non-empty so we can assert that the orphan
|
|
13
|
+
issue is the only one emitted.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orphan-keep
|
|
3
|
+
description: Fixture node that survives across before/after, so the after-state still has at least one node.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
stability: stable
|
|
7
|
+
author: conformance
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Survivor
|
|
11
|
+
|
|
12
|
+
Keeps the after-state graph non-empty so we can assert that the orphan
|
|
13
|
+
issue is the only one emitted.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orphan-lonely
|
|
3
|
+
description: Fixture node that gets deleted in the after-state to trigger the orphan path.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
stability: stable
|
|
7
|
+
author: conformance
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Orphan lonely body
|
|
11
|
+
|
|
12
|
+
This file disappears in `orphan-after`. With no replacement matching
|
|
13
|
+
its hashes, the rename heuristic emits an `orphan` issue.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rename-high-foo
|
|
3
|
+
description: Fixture node for the high-confidence rename conformance case.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
stability: stable
|
|
7
|
+
author: conformance
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Rename high body
|
|
11
|
+
|
|
12
|
+
Body content kept identical between the before and after fixtures so
|
|
13
|
+
the body hash matches across the rename. Move it to `bar.md` to trigger
|
|
14
|
+
a high-confidence auto-rename.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rename-high-foo
|
|
3
|
+
description: Fixture node for the high-confidence rename conformance case.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
stability: stable
|
|
7
|
+
author: conformance
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Rename high body
|
|
11
|
+
|
|
12
|
+
Body content kept identical between the before and after fixtures so
|
|
13
|
+
the body hash matches across the rename. Move it to `bar.md` to trigger
|
|
14
|
+
a high-confidence auto-rename.
|
package/db-schema.md
CHANGED
|
@@ -19,7 +19,7 @@ Two scopes. Each has its own database file and its own migration ledger.
|
|
|
19
19
|
| `project` (default) | `./.skill-map/skill-map.db` | The current repository. |
|
|
20
20
|
| `global` (`-g`) | `~/.skill-map/skill-map.db` | User-level skill directories (e.g. `~/.claude/`). |
|
|
21
21
|
|
|
22
|
-
The project DB is gitignored by default. Teams MAY opt in to sharing it by setting `history.share: true` in `.skill-map.json` — the file is then committed and the execution log becomes a team artifact. Both zones use the same schema.
|
|
22
|
+
The project DB is gitignored by default. Teams MAY opt in to sharing it by setting `history.share: true` in `.skill-map/settings.json` — the file is then committed and the execution log becomes a team artifact. Both zones use the same schema.
|
|
23
23
|
|
|
24
24
|
The `--db <path>` CLI flag overrides location for both scopes as an escape hatch.
|
|
25
25
|
|
|
@@ -134,6 +134,28 @@ One row per rule-emitted issue, matching [`schemas/issue.schema.json`](./schemas
|
|
|
134
134
|
|
|
135
135
|
Indexes: `ix_scan_issues_rule_id`, `ix_scan_issues_severity`.
|
|
136
136
|
|
|
137
|
+
### `scan_meta`
|
|
138
|
+
|
|
139
|
+
Single-row table holding the metadata of the last persisted scan. Lets `loadScanResult` return the real `scope` / `roots` / `scannedAt` / `scannedBy` / `adapters` / `stats.filesWalked|filesSkipped|durationMs` instead of synthesising them. Replaced atomically with the rest of the `scan_*` zone on every `sm scan`.
|
|
140
|
+
|
|
141
|
+
`nodesCount` / `linksCount` / `issuesCount` are not stored here — they derive from `COUNT(*)` of the sibling tables.
|
|
142
|
+
|
|
143
|
+
| Column | Type | Constraint |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `id` | INTEGER | PRIMARY KEY, CHECK `id = 1` |
|
|
146
|
+
| `scope` | TEXT | NOT NULL, CHECK in (`project`, `global`) |
|
|
147
|
+
| `roots_json` | TEXT | NOT NULL | JSON array of strings (filesystem roots walked). |
|
|
148
|
+
| `scanned_at` | INTEGER | NOT NULL | Unix milliseconds. |
|
|
149
|
+
| `scanned_by_name` | TEXT | NOT NULL |
|
|
150
|
+
| `scanned_by_version` | TEXT | NOT NULL |
|
|
151
|
+
| `scanned_by_spec_version` | TEXT | NOT NULL |
|
|
152
|
+
| `adapters_json` | TEXT | NOT NULL | JSON array of adapter ids. |
|
|
153
|
+
| `stats_files_walked` | INTEGER | NOT NULL |
|
|
154
|
+
| `stats_files_skipped` | INTEGER | NOT NULL |
|
|
155
|
+
| `stats_duration_ms` | INTEGER | NOT NULL |
|
|
156
|
+
|
|
157
|
+
No indexes (single row).
|
|
158
|
+
|
|
137
159
|
---
|
|
138
160
|
|
|
139
161
|
## Table catalog: zone `state_`
|
|
@@ -250,6 +272,14 @@ Persists user-toggled enable/disable overrides. Discovery is still filesystem-ba
|
|
|
250
272
|
| `config_json` | TEXT | NULL |
|
|
251
273
|
| `updated_at` | INTEGER | NOT NULL |
|
|
252
274
|
|
|
275
|
+
**Effective enable/disable resolution.** A plugin is enabled iff the highest-precedence layer that mentions it says so. Order from highest to lowest:
|
|
276
|
+
|
|
277
|
+
1. `config_plugins.enabled` for the row whose `plugin_id` matches — written by `sm plugins enable/disable`. Local-machine user override; never committed (the DB is gitignored unless `history.share: true`).
|
|
278
|
+
2. `.skill-map/settings.json#/plugins/<id>/enabled` — committed team-shared baseline.
|
|
279
|
+
3. Installed default — every discovered plugin is enabled until told otherwise.
|
|
280
|
+
|
|
281
|
+
The DB intentionally takes precedence over `settings.json` so a developer can locally disable a misbehaving plugin without committing the toggle to the team's config. Conversely, a team baseline that explicitly enables a plugin is overridable per-machine — no agreement is required to experiment.
|
|
282
|
+
|
|
253
283
|
### `config_preferences`
|
|
254
284
|
|
|
255
285
|
General-purpose key-value for user preferences (`sm config set`).
|
package/index.json
CHANGED
|
@@ -190,31 +190,38 @@
|
|
|
190
190
|
}
|
|
191
191
|
]
|
|
192
192
|
},
|
|
193
|
-
"specPackageVersion": "0.
|
|
193
|
+
"specPackageVersion": "0.6.1",
|
|
194
194
|
"integrity": {
|
|
195
195
|
"algorithm": "sha256",
|
|
196
196
|
"files": {
|
|
197
|
-
"CHANGELOG.md": "
|
|
197
|
+
"CHANGELOG.md": "73e7db22a362dfe6b1d7aa8f456d57d2106936b831c7de6fc9b44c9f7f9642a2",
|
|
198
198
|
"README.md": "8bd57e02d9a9d3f0a4efd18c0f0bd1f4bbe13eb206add0317659e48eab435e7e",
|
|
199
199
|
"architecture.md": "99f9d6a1a90e6c96d3c8a6f36c2650da4a1af0a1bc21173ea8eb2c492008539a",
|
|
200
|
-
"cli-contract.md": "
|
|
200
|
+
"cli-contract.md": "bab14bb72ddd8a57e00808f7f12741c63a33da99055b278e4407ab9b4bb7e2c1",
|
|
201
201
|
"conformance/README.md": "79c5e63f18a368951dc9f3e31e9bf9574de3f8b97150b2d75365d4febd8eb6dc",
|
|
202
202
|
"conformance/cases/basic-scan.json": "24623da0cad8c8c54b3ff9b09820ea1276fe8b8f0fc680bf6e8abeb4edb8e424",
|
|
203
203
|
"conformance/cases/kernel-empty-boot.json": "175524674b14d993d29f10080d7697074b3a2eee25b359ff903344d73c6acc98",
|
|
204
|
-
"conformance/
|
|
204
|
+
"conformance/cases/orphan-detection.json": "7fea6e866d775d09cadb70ccd764f6c8317ca61316c6d187a97cb2466db4e19e",
|
|
205
|
+
"conformance/cases/rename-high.json": "f23513893e25fc4259db06a497906137de981da775d8ab2ef262554d54af5f27",
|
|
206
|
+
"conformance/coverage.md": "ef98b87b70c46d7deb9853a8015c3e366a296088a70e13e4ffe223d91b9b4622",
|
|
205
207
|
"conformance/fixtures/minimal-claude/agents/reviewer.md": "d0dd681ba63838301e480116aa09825329f01832b0116de5c5476fdd8a5dcf54",
|
|
206
208
|
"conformance/fixtures/minimal-claude/commands/status.md": "3f36e053fd1c059ffd902f84a55be8a458c26072f97cb37dd7e97314ae2a9bf5",
|
|
207
209
|
"conformance/fixtures/minimal-claude/hooks/pre-commit.md": "ec9cec8ac4ce34d40ec055ffd90e8f06ea3e5764d6ec3ee84e0d97de71b930c7",
|
|
208
210
|
"conformance/fixtures/minimal-claude/notes/architecture.md": "5a7e6fdbb1556733dacebad63758057dc1e19090b5a983292c0c65e90b98bcf1",
|
|
209
211
|
"conformance/fixtures/minimal-claude/skills/hello.md": "8598074020430f294ff1eac39876302448f004b6c48446d453092159319bcbee",
|
|
212
|
+
"conformance/fixtures/orphan-after/skills/keep.md": "a6fdc33104cb2e8092f386a427784685eee1c8d7cb8fddb934cf65984143c7fd",
|
|
213
|
+
"conformance/fixtures/orphan-before/skills/keep.md": "a6fdc33104cb2e8092f386a427784685eee1c8d7cb8fddb934cf65984143c7fd",
|
|
214
|
+
"conformance/fixtures/orphan-before/skills/lonely.md": "4ba2bb336fa46644d2b0dfef4c3b97879ecbf693b825a5348f032d1af049d80a",
|
|
210
215
|
"conformance/fixtures/preamble-v1.txt": "1e0aeef224b64477bdc13a949c3ad402e68249caf499ecdba1302371677c068b",
|
|
211
|
-
"
|
|
216
|
+
"conformance/fixtures/rename-high-after/skills/bar.md": "16f7678829c7702f8ebaeef920a891756da198466a1884badd8d8b4a7d1bab6a",
|
|
217
|
+
"conformance/fixtures/rename-high-before/skills/foo.md": "16f7678829c7702f8ebaeef920a891756da198466a1884badd8d8b4a7d1bab6a",
|
|
218
|
+
"db-schema.md": "002224f629403a247c0243d4b242c1e35e28bd93073ea53137ec1d30084d9bd7",
|
|
212
219
|
"interfaces/security-scanner.md": "81dc3dc2c439a75f4603b6d52e714f44ac564032c8aa424385ebbf4502adae3e",
|
|
213
220
|
"job-events.md": "08796b7fbeb55e5b03cf3bc394224e70a23438a4d15a46ad1d70121c2c68b967",
|
|
214
221
|
"job-lifecycle.md": "1fe88b1a2ed204e41bb41ac172fbb3e912dccd0dd8a1f8ea8e21a681b336d6ee",
|
|
215
222
|
"plugin-kv-api.md": "04b2178f46fb88adeae9240df9c9e1761b660396072001dac32cd402e11a2d7d",
|
|
216
223
|
"prompt-preamble.md": "23a8eff0477fbbc46192a27781bc781bda4202bb9c669b7a7a002b0d668146b0",
|
|
217
|
-
"schemas/conformance-case.schema.json": "
|
|
224
|
+
"schemas/conformance-case.schema.json": "d69c501bbca079da0ca87685eb4cbdbc2e405334469fc937929ca9134e01a2b3",
|
|
218
225
|
"schemas/execution-record.schema.json": "ec0f3acf1d0ce099c059d73eb434936bfd1bcf12023693bd572efb2a7352faa6",
|
|
219
226
|
"schemas/extensions/action.schema.json": "c7520d3cefecf75d27d3e04473821fd6e5dc5a7924eede147f74275ba6caccad",
|
|
220
227
|
"schemas/extensions/adapter.schema.json": "429b865e738664bb437ac62690a2d7282ce992339fbb300417c73625f5cdb7c8",
|
|
@@ -235,7 +242,7 @@
|
|
|
235
242
|
"schemas/link.schema.json": "3e92f5c9def61a857a2c7b22846d82b988157de083463615144ddc92403a489e",
|
|
236
243
|
"schemas/node.schema.json": "14f345fac450f5728c895d1b878e0015eabb9d72ba9da4a8d2236c82933d3fcf",
|
|
237
244
|
"schemas/plugins-registry.schema.json": "92b2052bd06e366709dd6e1449d99408999e33707c4007afc7662980e73c3ef1",
|
|
238
|
-
"schemas/project-config.schema.json": "
|
|
245
|
+
"schemas/project-config.schema.json": "a37acdd6198e38dfc429161d92988170ddac91c6e98969e0aaaa8d717f5b9ba3",
|
|
239
246
|
"schemas/report-base.schema.json": "a1021e9a59b4df9f99cd92454d797e88469766e7d49f52d231c4645ffdfdad8f",
|
|
240
247
|
"schemas/scan-result.schema.json": "5efe9b1954c5e729c4b55dbc4dd51263d97967d16c0b3cea398877ace74d37b7",
|
|
241
248
|
"schemas/summaries/agent.schema.json": "3d22558eeb170e00c4fc32018a810d27333cc632c9e528ff386100cfdfded087",
|
package/package.json
CHANGED
|
@@ -28,12 +28,32 @@
|
|
|
28
28
|
},
|
|
29
29
|
"setup": {
|
|
30
30
|
"type": "object",
|
|
31
|
-
"description": "Pre-invocation toggles. All default to `false`.",
|
|
31
|
+
"description": "Pre-invocation toggles and ordered staging steps. All toggles default to `false`. `priorScans`, when present, run BEFORE the main `invoke` so a case can establish a prior snapshot the heuristic-driven verbs (e.g. `sm scan` rename detection) can react to.",
|
|
32
32
|
"additionalProperties": false,
|
|
33
33
|
"properties": {
|
|
34
34
|
"disableAllAdapters": { "type": "boolean" },
|
|
35
35
|
"disableAllDetectors": { "type": "boolean" },
|
|
36
|
-
"disableAllRules": { "type": "boolean" }
|
|
36
|
+
"disableAllRules": { "type": "boolean" },
|
|
37
|
+
"priorScans": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"description": "Ordered staging scans, each running before the next. For step N, the runner first replaces the scope's adapter content with `priorScans[N].fixture`, then invokes `sm scan` with the supplied flags. After the last step, the runner copies the top-level `fixture` (overwriting again) and runs the main `invoke`. The DB persists across all steps because `.skill-map/` is preserved between fixture swaps.",
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"required": ["fixture"],
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"properties": {
|
|
45
|
+
"fixture": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "Folder under `conformance/fixtures/` to copy into the scope, replacing every non-`.skill-map/` directory."
|
|
48
|
+
},
|
|
49
|
+
"flags": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"description": "Flags passed to `sm scan`. Default: empty (full scan).",
|
|
52
|
+
"items": { "type": "string" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
37
57
|
}
|
|
38
58
|
},
|
|
39
59
|
"invoke": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://skill-map.dev/spec/v0/project-config.schema.json",
|
|
4
4
|
"title": "ProjectConfig",
|
|
5
|
-
"description": "Shape of `.skill-map.json`
|
|
5
|
+
"description": "Shape of `.skill-map/settings.json` (and its `.skill-map/settings.local.json` partner) inside a scope. Loaded by the layered config hierarchy (library defaults → user → user-local → project → project-local → env/flags) and deep-merged per key. All fields optional; defaults apply when absent. camelCase keys throughout — consistent with the rest of the spec.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"properties": {
|