@skill-map/spec 0.18.0 → 0.20.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 +680 -1
- package/README.md +6 -6
- package/architecture.md +244 -41
- package/cli-contract.md +48 -20
- package/conformance/README.md +2 -2
- package/conformance/cases/kernel-empty-boot.json +2 -2
- package/conformance/cases/orphan-markdown-fallback.json +22 -0
- package/conformance/cases/plugin-missing-ui-rejected.json +2 -1
- package/conformance/cases/sidecar-end-to-end.json +3 -4
- package/conformance/coverage.md +8 -6
- package/conformance/fixtures/orphan-markdown/.claude/agents/reviewer.md +6 -0
- package/conformance/fixtures/orphan-markdown/ARCHITECTURE.md +10 -0
- package/conformance/fixtures/sidecar-end-to-end/.claude/agents/orphan.sm +2 -2
- package/conformance/fixtures/sidecar-end-to-end/.claude/agents/stale.sm +1 -1
- package/conformance/fixtures/sidecar-example/agent-example.md +1 -1
- package/conformance/fixtures/sidecar-example/agent-example.sm +1 -1
- package/db-schema.md +68 -23
- package/index.json +47 -42
- package/interfaces/security-scanner.md +2 -2
- package/job-events.md +12 -12
- package/job-lifecycle.md +1 -1
- package/package.json +1 -1
- package/plugin-author-guide.md +374 -69
- package/plugin-kv-api.md +5 -5
- package/prompt-preamble.md +1 -1
- package/schemas/annotations.schema.json +5 -9
- package/schemas/api/rest-envelope.schema.json +55 -11
- package/schemas/conformance-case.schema.json +2 -2
- package/schemas/extensions/analyzer.schema.json +43 -0
- package/schemas/extensions/base.schema.json +14 -4
- package/schemas/extensions/extractor.schema.json +3 -10
- package/schemas/extensions/hook.schema.json +6 -4
- package/schemas/extensions/provider.schema.json +1 -1
- package/schemas/frontmatter/base.schema.json +6 -1
- package/schemas/input-types.schema.json +260 -0
- package/schemas/issue.schema.json +6 -6
- package/schemas/link.schema.json +2 -2
- package/schemas/node.schema.json +1 -19
- package/schemas/plugins-registry.schema.json +14 -2
- package/schemas/project-config.schema.json +25 -0
- package/schemas/sidecar.schema.json +6 -6
- package/schemas/summaries/agent.schema.json +1 -1
- package/schemas/summaries/command.schema.json +1 -1
- package/schemas/summaries/hook.schema.json +1 -1
- package/schemas/summaries/markdown.schema.json +1 -1
- package/schemas/view-slots.schema.json +335 -0
- package/schemas/extensions/rule.schema.json +0 -43
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://skill-map.dev/spec/v0/input-types.schema.json",
|
|
4
|
+
"title": "InputTypes",
|
|
5
|
+
"description": "Closed catalog of input-types for plugin settings. The plugin author declares each user-configurable setting in the manifest's `settings` map by picking an `input-type` from this catalog; the kernel knows the schema for each type, the UI ships a generated form per type, and the CLI's `sm plugins config <id>` command exposes the same surface. Plugin authors NEVER write JSON Schema for settings — they pick a type by name and supply per-type parameters (label, default, min/max, options for enums, etc.). Closed catalog by design: every new input-type requires spec + UI form + CLI prompter + tests. Versioned via the manifest field `catalogCompat` (semver against the catalog as a whole). For the rationale and open issues, see ROADMAP.md §UI contribution system.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"$defs": {
|
|
8
|
+
"InputTypeName": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"enum": [
|
|
11
|
+
"string-list",
|
|
12
|
+
"single-string",
|
|
13
|
+
"boolean-flag",
|
|
14
|
+
"integer",
|
|
15
|
+
"enum-pick",
|
|
16
|
+
"enum-multipick",
|
|
17
|
+
"path-glob",
|
|
18
|
+
"regex",
|
|
19
|
+
"secret",
|
|
20
|
+
"key-value-list"
|
|
21
|
+
],
|
|
22
|
+
"description": "Closed enum of input-type identifiers. Adding an entry requires the full spec/UI/CLI/tests round-trip. Removing or renaming an entry is a catalog-major-bump and triggers `sm plugins upgrade` migration."
|
|
23
|
+
},
|
|
24
|
+
"ISettingDeclaration": {
|
|
25
|
+
"description": "Manifest-side declaration of a single setting, keyed in `IPluginManifest.settings[<settingId>]`. Discriminated by `type`; per-type parameters live in the `oneOf` branches below. The plugin author NEVER writes JSON Schema — `type` is a name from `InputTypeName`, the kernel validates the user-supplied value against the per-type value schema.",
|
|
26
|
+
"oneOf": [
|
|
27
|
+
{ "$ref": "#/$defs/Setting_StringList" },
|
|
28
|
+
{ "$ref": "#/$defs/Setting_SingleString" },
|
|
29
|
+
{ "$ref": "#/$defs/Setting_BooleanFlag" },
|
|
30
|
+
{ "$ref": "#/$defs/Setting_Integer" },
|
|
31
|
+
{ "$ref": "#/$defs/Setting_EnumPick" },
|
|
32
|
+
{ "$ref": "#/$defs/Setting_EnumMultipick" },
|
|
33
|
+
{ "$ref": "#/$defs/Setting_PathGlob" },
|
|
34
|
+
{ "$ref": "#/$defs/Setting_Regex" },
|
|
35
|
+
{ "$ref": "#/$defs/Setting_Secret" },
|
|
36
|
+
{ "$ref": "#/$defs/Setting_KeyValueList" }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"_Common": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"required": ["type", "label"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"label": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"minLength": 1,
|
|
46
|
+
"maxLength": 64,
|
|
47
|
+
"description": "Short human-readable label shown above the form control. English-only per AGENTS.md."
|
|
48
|
+
},
|
|
49
|
+
"description": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"maxLength": 256,
|
|
52
|
+
"description": "Optional helper text shown below the control. English-only."
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"Setting_StringList": {
|
|
57
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"required": ["type", "label"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"type": { "const": "string-list" },
|
|
63
|
+
"label": true,
|
|
64
|
+
"description": true,
|
|
65
|
+
"default": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"items": { "type": "string" }
|
|
68
|
+
},
|
|
69
|
+
"min": { "type": "integer", "minimum": 0, "description": "Minimum item count required to validate." },
|
|
70
|
+
"max": { "type": "integer", "minimum": 1, "description": "Maximum item count permitted." },
|
|
71
|
+
"itemMaxLength": { "type": "integer", "minimum": 1, "default": 256 }
|
|
72
|
+
},
|
|
73
|
+
"description": "Array of free-form strings. Renders as a tag input. Use for keyword lists, ignore patterns, allow-lists. Value type at runtime: `string[]`."
|
|
74
|
+
},
|
|
75
|
+
"Setting_SingleString": {
|
|
76
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
77
|
+
"type": "object",
|
|
78
|
+
"additionalProperties": false,
|
|
79
|
+
"required": ["type", "label"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"type": { "const": "single-string" },
|
|
82
|
+
"label": true,
|
|
83
|
+
"description": true,
|
|
84
|
+
"default": { "type": "string" },
|
|
85
|
+
"minLength": { "type": "integer", "minimum": 0 },
|
|
86
|
+
"maxLength": { "type": "integer", "minimum": 1 },
|
|
87
|
+
"pattern": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "Optional ECMAScript regex (no flags) the value must match. Validated at form submit AND at extractor invocation."
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"description": "Single text input. Use for short identifiers, URLs, names. Value type at runtime: `string`."
|
|
93
|
+
},
|
|
94
|
+
"Setting_BooleanFlag": {
|
|
95
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
96
|
+
"type": "object",
|
|
97
|
+
"additionalProperties": false,
|
|
98
|
+
"required": ["type", "label"],
|
|
99
|
+
"properties": {
|
|
100
|
+
"type": { "const": "boolean-flag" },
|
|
101
|
+
"label": true,
|
|
102
|
+
"description": true,
|
|
103
|
+
"default": { "type": "boolean", "default": false }
|
|
104
|
+
},
|
|
105
|
+
"description": "On/off toggle. Renders as PrimeNG `<p-toggleswitch>`. Value type at runtime: `boolean`."
|
|
106
|
+
},
|
|
107
|
+
"Setting_Integer": {
|
|
108
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
109
|
+
"type": "object",
|
|
110
|
+
"additionalProperties": false,
|
|
111
|
+
"required": ["type", "label"],
|
|
112
|
+
"properties": {
|
|
113
|
+
"type": { "const": "integer" },
|
|
114
|
+
"label": true,
|
|
115
|
+
"description": true,
|
|
116
|
+
"default": { "type": "integer" },
|
|
117
|
+
"min": { "type": "integer" },
|
|
118
|
+
"max": { "type": "integer" },
|
|
119
|
+
"step": { "type": "integer", "minimum": 1, "default": 1 }
|
|
120
|
+
},
|
|
121
|
+
"description": "Integer input with optional bounds. Renders as PrimeNG `<p-inputnumber>` with spinner. Value type at runtime: `number` (always integer)."
|
|
122
|
+
},
|
|
123
|
+
"Setting_EnumPick": {
|
|
124
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
125
|
+
"type": "object",
|
|
126
|
+
"additionalProperties": false,
|
|
127
|
+
"required": ["type", "label", "options"],
|
|
128
|
+
"properties": {
|
|
129
|
+
"type": { "const": "enum-pick" },
|
|
130
|
+
"label": true,
|
|
131
|
+
"description": true,
|
|
132
|
+
"options": {
|
|
133
|
+
"type": "array",
|
|
134
|
+
"minItems": 2,
|
|
135
|
+
"items": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"additionalProperties": false,
|
|
138
|
+
"required": ["value", "label"],
|
|
139
|
+
"properties": {
|
|
140
|
+
"value": { "type": "string", "minLength": 1, "maxLength": 64 },
|
|
141
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 64 }
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"default": { "type": "string" }
|
|
146
|
+
},
|
|
147
|
+
"description": "Pick one from a closed set. Renders as PrimeNG `<p-select>` (≤ 7 options) or `<p-radiobutton>` group (≤ 4 options). Value type at runtime: `string` (the picked option's `value`)."
|
|
148
|
+
},
|
|
149
|
+
"Setting_EnumMultipick": {
|
|
150
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
151
|
+
"type": "object",
|
|
152
|
+
"additionalProperties": false,
|
|
153
|
+
"required": ["type", "label", "options"],
|
|
154
|
+
"properties": {
|
|
155
|
+
"type": { "const": "enum-multipick" },
|
|
156
|
+
"label": true,
|
|
157
|
+
"description": true,
|
|
158
|
+
"options": {
|
|
159
|
+
"type": "array",
|
|
160
|
+
"minItems": 2,
|
|
161
|
+
"items": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"additionalProperties": false,
|
|
164
|
+
"required": ["value", "label"],
|
|
165
|
+
"properties": {
|
|
166
|
+
"value": { "type": "string", "minLength": 1, "maxLength": 64 },
|
|
167
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 64 }
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"default": { "type": "array", "items": { "type": "string" } },
|
|
172
|
+
"min": { "type": "integer", "minimum": 0 },
|
|
173
|
+
"max": { "type": "integer", "minimum": 1 }
|
|
174
|
+
},
|
|
175
|
+
"description": "Pick zero or more from a closed set. Renders as PrimeNG `<p-multiselect>` or checkbox group. Value type at runtime: `string[]`."
|
|
176
|
+
},
|
|
177
|
+
"Setting_PathGlob": {
|
|
178
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
179
|
+
"type": "object",
|
|
180
|
+
"additionalProperties": false,
|
|
181
|
+
"required": ["type", "label"],
|
|
182
|
+
"properties": {
|
|
183
|
+
"type": { "const": "path-glob" },
|
|
184
|
+
"label": true,
|
|
185
|
+
"description": true,
|
|
186
|
+
"default": { "type": "string" },
|
|
187
|
+
"multiple": {
|
|
188
|
+
"type": "boolean",
|
|
189
|
+
"default": false,
|
|
190
|
+
"description": "When true, accepts `string[]` of glob patterns; when false (default), single `string`."
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"description": "Glob pattern (POSIX-style, `**` / `*` / `?`). Validated against the project's installed glob library at form submit. Value type at runtime: `string` (when `multiple: false`) or `string[]`."
|
|
194
|
+
},
|
|
195
|
+
"Setting_Regex": {
|
|
196
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
197
|
+
"type": "object",
|
|
198
|
+
"additionalProperties": false,
|
|
199
|
+
"required": ["type", "label"],
|
|
200
|
+
"properties": {
|
|
201
|
+
"type": { "const": "regex" },
|
|
202
|
+
"label": true,
|
|
203
|
+
"description": true,
|
|
204
|
+
"default": { "type": "string" },
|
|
205
|
+
"flags": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"pattern": "^[gimsuy]*$",
|
|
208
|
+
"default": "",
|
|
209
|
+
"description": "ECMAScript regex flags allowed. Subset: `g`, `i`, `m`, `s`, `u`, `y`. Author chooses which flags the user-supplied pattern compiles with — the user supplies only the body."
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"description": "ECMAScript regex pattern (the body, no `/` delimiters). Validated by attempting `new RegExp(value, flags)` at form submit and at extractor invocation. Compilation failure → form error / `invalid-settings` at runtime. Value type at runtime: `string`."
|
|
213
|
+
},
|
|
214
|
+
"Setting_Secret": {
|
|
215
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
216
|
+
"type": "object",
|
|
217
|
+
"additionalProperties": false,
|
|
218
|
+
"required": ["type", "label"],
|
|
219
|
+
"properties": {
|
|
220
|
+
"type": { "const": "secret" },
|
|
221
|
+
"label": true,
|
|
222
|
+
"description": true,
|
|
223
|
+
"envVar": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"pattern": "^[A-Z][A-Z0-9_]*$",
|
|
226
|
+
"description": "Optional env var name the kernel checks first; if set in the process environment, that value wins over any stored value (lets CI inject without writing to disk). The user-supplied value is stored encrypted at rest."
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"description": "Sensitive string (token, password, API key). Renders as `<input type=\"password\">` with reveal toggle. Stored encrypted at rest (kernel-managed key in `state_secrets` table). Logged as `<redacted>` in CLI output. Value type at runtime: `string`. Triggers an `audit.secret-read` event on every read."
|
|
230
|
+
},
|
|
231
|
+
"Setting_KeyValueList": {
|
|
232
|
+
"allOf": [{ "$ref": "#/$defs/_Common" }],
|
|
233
|
+
"type": "object",
|
|
234
|
+
"additionalProperties": false,
|
|
235
|
+
"required": ["type", "label"],
|
|
236
|
+
"properties": {
|
|
237
|
+
"type": { "const": "key-value-list" },
|
|
238
|
+
"label": true,
|
|
239
|
+
"description": true,
|
|
240
|
+
"keyLabel": { "type": "string", "minLength": 1, "maxLength": 32, "default": "Key" },
|
|
241
|
+
"valueLabel": { "type": "string", "minLength": 1, "maxLength": 32, "default": "Value" },
|
|
242
|
+
"default": {
|
|
243
|
+
"type": "array",
|
|
244
|
+
"items": {
|
|
245
|
+
"type": "object",
|
|
246
|
+
"additionalProperties": false,
|
|
247
|
+
"required": ["key", "value"],
|
|
248
|
+
"properties": {
|
|
249
|
+
"key": { "type": "string" },
|
|
250
|
+
"value": { "type": "string" }
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
"min": { "type": "integer", "minimum": 0 },
|
|
255
|
+
"max": { "type": "integer", "minimum": 1 }
|
|
256
|
+
},
|
|
257
|
+
"description": "Editable mapping of strings to strings. Renders as a small editable table. Use for custom translations, alias maps, header overrides. Value type at runtime: `Array<{ key: string, value: string }>`."
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://skill-map.dev/spec/v0/issue.schema.json",
|
|
4
4
|
"title": "Issue",
|
|
5
|
-
"description": "Deterministic finding emitted by a
|
|
5
|
+
"description": "Deterministic finding emitted by a analyzer when evaluating the graph. Not to be confused with `Finding`, which is probabilistic (LLM-produced).",
|
|
6
6
|
"type": "object",
|
|
7
|
-
"required": ["
|
|
7
|
+
"required": ["analyzerId", "severity", "nodeIds", "message"],
|
|
8
8
|
"additionalProperties": false,
|
|
9
9
|
"properties": {
|
|
10
|
-
"
|
|
10
|
+
"analyzerId": {
|
|
11
11
|
"type": "string",
|
|
12
12
|
"pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
|
|
13
|
-
"description": "Kebab-case identifier of the
|
|
13
|
+
"description": "Kebab-case identifier of the analyzer that emitted this issue (e.g. `trigger-collision`, `broken-ref`, `superseded`)."
|
|
14
14
|
},
|
|
15
15
|
"severity": {
|
|
16
16
|
"type": "string",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"nodeIds": {
|
|
21
21
|
"type": "array",
|
|
22
|
-
"description": "`node.path` values involved in this issue. Most
|
|
22
|
+
"description": "`node.path` values involved in this issue. Most analyzers emit 1 or 2; trigger-collision may emit N. Field name uses `id` generically to remain stable across future identifier changes.",
|
|
23
23
|
"minItems": 1,
|
|
24
24
|
"items": { "type": "string" }
|
|
25
25
|
},
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"data": {
|
|
49
49
|
"type": "object",
|
|
50
|
-
"description": "
|
|
50
|
+
"description": "Analyzer-specific structured payload (e.g. the colliding trigger string, the missing target). Free-form.",
|
|
51
51
|
"additionalProperties": true
|
|
52
52
|
}
|
|
53
53
|
}
|
package/schemas/link.schema.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"target": {
|
|
15
15
|
"type": "string",
|
|
16
|
-
"description": "`node.path` of the destination. MAY point to a missing node;
|
|
16
|
+
"description": "`node.path` of the destination. MAY point to a missing node; analyzers detect broken refs."
|
|
17
17
|
},
|
|
18
18
|
"kind": {
|
|
19
19
|
"type": "string",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"confidence": {
|
|
24
24
|
"type": "string",
|
|
25
25
|
"enum": ["high", "medium", "low"],
|
|
26
|
-
"description": "Extractor's self-assessed confidence.
|
|
26
|
+
"description": "Extractor's self-assessed confidence. Analyzers MAY filter by confidence."
|
|
27
27
|
},
|
|
28
28
|
"sources": {
|
|
29
29
|
"type": "array",
|
package/schemas/node.schema.json
CHANGED
|
@@ -20,24 +20,6 @@
|
|
|
20
20
|
"type": "string",
|
|
21
21
|
"description": "Identifier of the Provider extension that classified this node (e.g. `claude`)."
|
|
22
22
|
},
|
|
23
|
-
"title": {
|
|
24
|
-
"type": ["string", "null"],
|
|
25
|
-
"description": "Human-readable title. Sourced from frontmatter `name` or falls back to filename. Null if neither is usable."
|
|
26
|
-
},
|
|
27
|
-
"description": {
|
|
28
|
-
"type": ["string", "null"],
|
|
29
|
-
"description": "Short description from frontmatter `description`. Null if absent."
|
|
30
|
-
},
|
|
31
|
-
"stability": {
|
|
32
|
-
"type": ["string", "null"],
|
|
33
|
-
"enum": ["experimental", "stable", "deprecated", null],
|
|
34
|
-
"description": "Denormalized from `metadata.stability` for fast queries."
|
|
35
|
-
},
|
|
36
|
-
"version": {
|
|
37
|
-
"type": ["integer", "null"],
|
|
38
|
-
"minimum": 1,
|
|
39
|
-
"description": "Monotonic version counter denormalised from sidecar `annotations.version` (Step 9.6.2). Pre-9.6.2 this field was a semver string sourced from `frontmatter.metadata.version`; the new shape is a single integer monotonic counter, orthogonal to `stability`. Major bumps mean `create a new node, supersede the old one`, not increment. See Decision #125 and `annotations.schema.json#/properties/version`."
|
|
40
|
-
},
|
|
41
23
|
"frontmatter": {
|
|
42
24
|
"type": "object",
|
|
43
25
|
"description": "Full parsed frontmatter. See `frontmatter/base.schema.json` and `frontmatter/<kind>.schema.json`.",
|
|
@@ -118,7 +100,7 @@
|
|
|
118
100
|
"root": {
|
|
119
101
|
"type": ["object", "null"],
|
|
120
102
|
"additionalProperties": true,
|
|
121
|
-
"description": "Parsed YAML root of the matching `.sm` sidecar. Mirrors the shape of `sidecar.schema.json` (top-level reserved blocks `
|
|
103
|
+
"description": "Parsed YAML root of the matching `.sm` sidecar. Mirrors the shape of `sidecar.schema.json` (top-level reserved blocks `identity` / `annotations` / `settings` / `audit` plus opt-in `<plugin-id>:` namespaces). Surfaced for the UI inspector's audit panel, plugin-contributions panel, and debug panel; NULL when the sidecar is absent or failed to parse. Note the duplication with `annotations` at this overlay level — existing consumers read from `annotations`, new consumers read structured sub-fields off `root` (`root.identity.*`, `root.audit.*`, etc.). The duplication is intentional and documented; do NOT remove the top-level `annotations` field."
|
|
122
104
|
}
|
|
123
105
|
}
|
|
124
106
|
}
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"type": "string",
|
|
28
28
|
"description": "Semver range this plugin is compatible with (e.g. `^1.0.0`, `>=0.3.0 <0.4.0`). Checked via `semver.satisfies(specVersion, this)` at load time."
|
|
29
29
|
},
|
|
30
|
+
"catalogCompat": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "Optional semver range against the kernel's view-slots + input-types catalog version (e.g. `^1.0.0`). Independent from `specCompat` because the catalog evolves on its own cadence (new slots ship as minor bumps; rename/remove ships as catalog-major bumps that trigger `sm plugins upgrade`). Absent = the plugin declares no view contributions or settings AND opts out of catalog-version checking; `sm plugins doctor` will warn if such a plugin actually emits via `viewContributions` or `settings`. Mismatch surfaces as `incompatible-catalog` plugin status."
|
|
33
|
+
},
|
|
30
34
|
"description": {
|
|
31
35
|
"type": "string"
|
|
32
36
|
},
|
|
@@ -73,6 +77,14 @@
|
|
|
73
77
|
}
|
|
74
78
|
]
|
|
75
79
|
},
|
|
80
|
+
"settings": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"additionalProperties": { "$ref": "input-types.schema.json#/$defs/ISettingDeclaration" },
|
|
83
|
+
"propertyNames": {
|
|
84
|
+
"pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$"
|
|
85
|
+
},
|
|
86
|
+
"description": "Plugin user-configurable settings. Each entry picks an `input-type` from the closed catalog at `input-types.schema.json#/$defs/InputTypeName`. The plugin author NEVER writes JSON Schema for settings — they pick by `type` name and provide per-type parameters (label, default, min/max, options for enums, etc.). The kernel exposes the resolved settings to extractors via `ctx.settings.<settingId>` (or via the runtime as `IPluginSettings`); the UI generates a form per declaration; the CLI's `sm plugins config <id>` exposes the same surface. Settings are read once at extractor invocation; changing a setting requires `sm scan` to re-emit (per ROADMAP.md decision D4)."
|
|
87
|
+
},
|
|
76
88
|
"author": { "type": "string" },
|
|
77
89
|
"license": { "type": "string", "description": "SPDX identifier." },
|
|
78
90
|
"homepage": { "type": "string", "format": "uri" },
|
|
@@ -101,8 +113,8 @@
|
|
|
101
113
|
"manifest": { "$ref": "#/$defs/PluginManifest" },
|
|
102
114
|
"status": {
|
|
103
115
|
"type": "string",
|
|
104
|
-
"enum": ["enabled", "disabled", "incompatible-spec", "invalid-manifest", "load-error", "id-collision"],
|
|
105
|
-
"description": "Resolved state after discovery. `disabled` = user-disabled via config; `id-collision` = two plugins (any combination of project / global / --plugin-dir) declared the same `id`, both blocked, no precedence; others = automatic."
|
|
116
|
+
"enum": ["enabled", "disabled", "incompatible-spec", "incompatible-catalog", "invalid-manifest", "load-error", "id-collision"],
|
|
117
|
+
"description": "Resolved state after discovery. `disabled` = user-disabled via config; `id-collision` = two plugins (any combination of project / global / --plugin-dir) declared the same `id`, both blocked, no precedence; `incompatible-catalog` = manifest's `catalogCompat` does not satisfy the kernel's catalog version (resolved via `sm plugins upgrade`); others = automatic."
|
|
106
118
|
},
|
|
107
119
|
"statusReason": {
|
|
108
120
|
"type": ["string", "null"],
|
|
@@ -57,6 +57,20 @@
|
|
|
57
57
|
"description": "Milliseconds to wait after the last filesystem event before triggering an incremental scan. Groups bursts (editor saves, branch switches, package installs) into a single scan pass. Default 300. Set to 0 to disable debouncing — every filesystem event triggers a scan immediately."
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
},
|
|
61
|
+
"includeHome": {
|
|
62
|
+
"type": "boolean",
|
|
63
|
+
"description": "**Privacy-sensitive** — 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."
|
|
64
|
+
},
|
|
65
|
+
"extraRoots": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"items": { "type": "string" },
|
|
68
|
+
"description": "**Privacy-sensitive** 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), per the same analyzers as `includeHome`."
|
|
69
|
+
},
|
|
70
|
+
"referencePaths": {
|
|
71
|
+
"type": "array",
|
|
72
|
+
"items": { "type": "string" },
|
|
73
|
+
"description": "**Privacy-sensitive** 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 `extraRoots`."
|
|
60
74
|
}
|
|
61
75
|
}
|
|
62
76
|
},
|
|
@@ -129,6 +143,17 @@
|
|
|
129
143
|
"properties": {
|
|
130
144
|
"locale": { "type": "string", "description": "BCP-47 tag. Default `en`." }
|
|
131
145
|
}
|
|
146
|
+
},
|
|
147
|
+
"updateCheck": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"additionalProperties": false,
|
|
150
|
+
"description": "Controls the once-per-day notification when a newer @skill-map/cli release is published on npm. Disabled in CI, when SM_NO_UPDATE_CHECK=1, when stderr is not a TTY, or when the project DB is missing. **User-scope only**: this key SHOULD live in `~/.skill-map/settings.json` and the reference implementation forces user-scope reads via `core/config/helper:USER_ONLY_KEYS` — a project-layer entry from an older install continues to validate but is silently ignored at read time. `sm config set` rejects writes to the project layer for this key (rerun with `-g`); the Settings UI's General section persists toggles to the user layer.",
|
|
151
|
+
"properties": {
|
|
152
|
+
"enabled": {
|
|
153
|
+
"type": "boolean",
|
|
154
|
+
"description": "Default true. Set to false to disable both the npm registry probe and the CLI / UI banner."
|
|
155
|
+
}
|
|
156
|
+
}
|
|
132
157
|
}
|
|
133
158
|
}
|
|
134
159
|
}
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://skill-map.dev/spec/v0/sidecar.schema.json",
|
|
4
4
|
"title": "Sidecar",
|
|
5
|
-
"description": "Root shape of a co-located YAML sidecar (`<basename>.sm` next to `<basename>.md`).
|
|
5
|
+
"description": "Root shape of a co-located YAML sidecar (`<basename>.sm` next to `<basename>.md`). The `.sm` file IS the annotations file — every key under it is, conceptually, an annotation on the node. The YAML root organizes those annotations into structural blocks: `identity` (anchor + drift-detection hashes), `annotations` (the curated catalog of conventional fields), `audit` (timestamps), `settings` (reserved), and arbitrary `<plugin-id>:` namespaces for plugin-contributed data. Vendor file (`<basename>.md`) stays untouched. Schema is `additionalProperties: true` so plugins can add namespaces without coordination; the built-in `unknown-field` analyzer warns on truly unrecognized root keys (typo guard). Format is YAML — comments via `#`, multiline strings via `|` / `>`, permissive types per the YAML 1.2 spec. See `architecture.md` §Annotation system and ROADMAP §Step 9.6 for the design rationale.",
|
|
6
6
|
"type": "object",
|
|
7
|
-
"required": ["
|
|
7
|
+
"required": ["identity"],
|
|
8
8
|
"additionalProperties": true,
|
|
9
9
|
"properties": {
|
|
10
|
-
"
|
|
10
|
+
"identity": {
|
|
11
11
|
"$ref": "#/$defs/identity",
|
|
12
|
-
"description": "
|
|
12
|
+
"description": "Anchor block linking this sidecar to its markdown node and capturing the body / frontmatter hashes at the moment of the last `bump`. Drift detection compares stored hashes against the current file at scan time; mismatch emits the built-in `annotation-stale` warning (soft mode, never blocking)."
|
|
13
13
|
},
|
|
14
14
|
"annotations": {
|
|
15
15
|
"$ref": "annotations.schema.json",
|
|
16
|
-
"description": "Skill-map annotation catalog. See `annotations.schema.json` for the curated
|
|
16
|
+
"description": "Skill-map annotation catalog. See `annotations.schema.json` for the curated 13-field surface; users / plugins MAY add custom keys (rides on `additionalProperties: true`)."
|
|
17
17
|
},
|
|
18
18
|
"settings": {
|
|
19
19
|
"type": "object",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"frontmatterHash": {
|
|
71
71
|
"type": "string",
|
|
72
72
|
"pattern": "^[a-f0-9]{64}$",
|
|
73
|
-
"description": "sha256 of the canonical frontmatter (per the kernel's `canonicalFrontmatter`
|
|
73
|
+
"description": "sha256 of the canonical frontmatter (per the kernel's `canonicalFrontmatter` analyzer), hex-encoded lowercase, captured at the moment this sidecar was last bumped. Compared against the current frontmatter hash to detect drift."
|
|
74
74
|
},
|
|
75
75
|
"resolvedAs": {
|
|
76
76
|
"type": "object",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"toolsObserved": {
|
|
29
29
|
"type": "array",
|
|
30
|
-
"description": "Tool names the summarizer observed referenced in the body. MAY differ from `metadata.tools` / frontmatter.tools;
|
|
30
|
+
"description": "Tool names the summarizer observed referenced in the body. MAY differ from `metadata.tools` / frontmatter.tools; analyzers can emit drift issues.",
|
|
31
31
|
"items": { "type": "string" }
|
|
32
32
|
},
|
|
33
33
|
"interactionStyle": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"argsObserved": {
|
|
24
24
|
"type": "array",
|
|
25
|
-
"description": "Argument structure as inferred from the body. MAY differ from declared `frontmatter.args`;
|
|
25
|
+
"description": "Argument structure as inferred from the body. MAY differ from declared `frontmatter.args`; analyzers can emit drift issues.",
|
|
26
26
|
"items": {
|
|
27
27
|
"type": "object",
|
|
28
28
|
"required": ["name"],
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"triggerInferred": {
|
|
20
20
|
"type": "string",
|
|
21
|
-
"description": "Event or condition the summarizer inferred from the body. MAY differ from declared `frontmatter.event`/`condition`;
|
|
21
|
+
"description": "Event or condition the summarizer inferred from the body. MAY differ from declared `frontmatter.event`/`condition`; analyzers can emit drift issues."
|
|
22
22
|
},
|
|
23
23
|
"sideEffects": {
|
|
24
24
|
"type": "array",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://skill-map.dev/spec/v0/summaries/markdown.schema.json",
|
|
4
4
|
"title": "SummaryMarkdown",
|
|
5
|
-
"description": "Report produced by `markdown-summarizer` for a single `markdown` node (the format-named generic fallback
|
|
5
|
+
"description": "Report produced by `markdown-summarizer` for a single `markdown` node (the format-named generic fallback owned by the built-in `core/markdown` Provider — see `architecture.md` §Provider · dispatch order). Extends `report-base.schema.json`. Stability: experimental.",
|
|
6
6
|
"allOf": [
|
|
7
7
|
{ "$ref": "../report-base.schema.json" }
|
|
8
8
|
],
|