@skill-map/spec 0.45.1 → 0.47.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 +66 -0
- package/architecture.md +18 -11
- package/cli-contract.md +11 -14
- package/conformance/README.md +1 -0
- package/conformance/cases/plugin-missing-ui-rejected.json +1 -1
- package/conformance/cases/sidecar-end-to-end.json +1 -1
- package/conformance/cases/view-action-button.json +21 -0
- package/conformance/cases/view-contribution-payloads.json +19 -0
- package/conformance/cases/view-slots-all.json +15 -0
- package/conformance/coverage.md +1 -1
- package/conformance/fixtures/view-action-button/.skill-map/plugins/badge-actions/analyzers/good-badges/index.js +46 -0
- package/conformance/fixtures/view-action-button/.skill-map/plugins/badge-actions/plugin.json +6 -0
- package/conformance/fixtures/view-action-button/.skill-map/plugins/legacy-badge/analyzers/header-counter/index.js +28 -0
- package/conformance/fixtures/view-action-button/.skill-map/plugins/legacy-badge/plugin.json +6 -0
- package/conformance/fixtures/view-action-button/notes/example.md +6 -0
- package/conformance/fixtures/view-contribution-payloads/.skill-map/plugins/payloads-demo/analyzers/panels/index.js +37 -0
- package/conformance/fixtures/view-contribution-payloads/.skill-map/plugins/payloads-demo/plugin.json +6 -0
- package/conformance/fixtures/view-contribution-payloads/notes/example.md +5 -0
- package/conformance/fixtures/view-slots-all/.skill-map/plugins/all-slots/analyzers/everything/index.js +35 -0
- package/conformance/fixtures/view-slots-all/.skill-map/plugins/all-slots/plugin.json +6 -0
- package/index.json +29 -16
- package/package.json +1 -1
- package/plugin-author-guide.md +42 -6
- package/schemas/api/rest-envelope.schema.json +13 -4
- package/schemas/extensions/action.schema.json +32 -0
- package/schemas/extensions/base.schema.json +4 -0
- package/schemas/plugins-doctor.schema.json +45 -2
- package/schemas/plugins-registry.schema.json +4 -0
- package/schemas/sidecar.schema.json +1 -1
- package/schemas/view-slots.schema.json +112 -23
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
{ "const": "card.footer.left", "description": "Counter chip in the left footer of the card." },
|
|
14
14
|
{ "const": "card.footer.right", "description": "Counter chip in the right footer of the card." },
|
|
15
15
|
{ "const": "graph.node.alert", "description": "Reserved corner badge on the graph node, special-case signals only. No core analyzer emits here; routine \"this node has a problem\" findings belong in `card.footer.right`." },
|
|
16
|
-
{ "const": "inspector.header.badge
|
|
17
|
-
{ "const": "inspector.
|
|
16
|
+
{ "const": "inspector.header.badge", "description": "Unified badge in the inspector header cluster: icon and/or label and/or count, optional severity. Multi-cardinality, priority order, modeled on card.footer.left. Replaces the retired inspector.header.badge.counter and inspector.header.badge.tag sub-slots." },
|
|
17
|
+
{ "const": "inspector.action.button", "description": "Action button in the inspector. Click dispatches a kernel Action by qualified id via POST /api/actions/:id. Always emitted; the payload `enabled` flag carries the dynamic condition (e.g. isStale for the bump button)." },
|
|
18
18
|
{ "const": "inspector.body.panel.breakdown", "description": "Top-N labeled values rendered as a bar chart in the inspector body." },
|
|
19
19
|
{ "const": "inspector.body.panel.records", "description": "Tabular data (rows × columns ≤ 50 × 6) in the inspector body." },
|
|
20
20
|
{ "const": "inspector.body.panel.tree", "description": "Recursive label/children hierarchy (depth ≤ 6, total ≤ 200) in the inspector body." },
|
|
@@ -78,8 +78,7 @@
|
|
|
78
78
|
"enum": [
|
|
79
79
|
"card.subtitle.left",
|
|
80
80
|
"card.footer.left",
|
|
81
|
-
"card.footer.right"
|
|
82
|
-
"inspector.header.badge.counter"
|
|
81
|
+
"card.footer.right"
|
|
83
82
|
]
|
|
84
83
|
}
|
|
85
84
|
}
|
|
@@ -96,6 +95,7 @@
|
|
|
96
95
|
"payloads": {
|
|
97
96
|
"description": "Per-slot payload schemas. The kernel validates `ctx.emitContribution(id, payload)` calls against the entry corresponding to the declared slot before persisting to `scan_contributions`. Off-shape payloads emit an `extension.error` event and drop silently (mirror of `emitLink` off-contract drop pattern). Slots that share a renderer share a payload shape; the schema is defined inline at each slot to keep lookups direct (no internal indirection).",
|
|
98
97
|
"card.title.right": {
|
|
98
|
+
"title": "IconMarkerPayload",
|
|
99
99
|
"type": "object",
|
|
100
100
|
"additionalProperties": false,
|
|
101
101
|
"properties": {
|
|
@@ -111,8 +111,8 @@
|
|
|
111
111
|
"card.subtitle.left": { "$ref": "#/$defs/payloads/_counter" },
|
|
112
112
|
"card.footer.left": { "$ref": "#/$defs/payloads/_counter" },
|
|
113
113
|
"card.footer.right": { "$ref": "#/$defs/payloads/_counter" },
|
|
114
|
-
"inspector.header.badge.counter": { "$ref": "#/$defs/payloads/_counter" },
|
|
115
114
|
"_counter": {
|
|
115
|
+
"title": "CounterPayload",
|
|
116
116
|
"type": "object",
|
|
117
117
|
"additionalProperties": false,
|
|
118
118
|
"required": ["value"],
|
|
@@ -130,23 +130,105 @@
|
|
|
130
130
|
},
|
|
131
131
|
"description": "Single icon + integer pair, modelled after the `.sm-gnode__stat` rows in the card footer. Manifest requires `icon` (enforced by `IViewContribution.allOf` for every counter slot); payload carries `value`, optionally `severity` and `tooltip`. The manifest `label` is metadata (docs / plugin-doctor / aria-label) and is NOT rendered inline."
|
|
132
132
|
},
|
|
133
|
-
"inspector.header.badge
|
|
134
|
-
|
|
133
|
+
"inspector.header.badge": {
|
|
134
|
+
"title": "BadgePayload",
|
|
135
135
|
"type": "object",
|
|
136
136
|
"additionalProperties": false,
|
|
137
|
-
"required": ["label"],
|
|
138
137
|
"properties": {
|
|
139
|
-
"
|
|
138
|
+
"icon": { "$ref": "#/$defs/IconString" },
|
|
139
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 32 },
|
|
140
|
+
"count": { "type": "integer", "minimum": 0 },
|
|
141
|
+
"severity": { "$ref": "#/$defs/Severity" },
|
|
142
|
+
"tooltip": { "type": "string", "maxLength": 256 }
|
|
143
|
+
},
|
|
144
|
+
"anyOf": [
|
|
145
|
+
{ "required": ["icon"] },
|
|
146
|
+
{ "required": ["label"] },
|
|
147
|
+
{ "required": ["count"] }
|
|
148
|
+
],
|
|
149
|
+
"description": "Unified inspector header badge. At least one of `icon`, `label`, `count` is required; optional `severity` tint and `tooltip`. Multi-cardinality slot (priority order, modeled on card.footer.left); a plugin extension may emit several. 'Empty' for `emitWhenEmpty` is the absence of `icon` AND `label` AND `count`. Replaces the retired `_counter`/`_tag` header sub-slots: a counter-style badge sets `count` (+`icon`), a tag-style badge sets `label` (+`severity`), the stale clock sets `icon` + `tooltip`."
|
|
150
|
+
},
|
|
151
|
+
"inspector.action.button": {
|
|
152
|
+
"title": "ActionButtonPayload",
|
|
153
|
+
"type": "object",
|
|
154
|
+
"additionalProperties": false,
|
|
155
|
+
"required": ["actionId", "label", "enabled"],
|
|
156
|
+
"properties": {
|
|
157
|
+
"actionId": {
|
|
140
158
|
"type": "string",
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"description": "Tag text (e.g. 'fresh', 'stale', '7d ago'). 'Empty' for `emitWhenEmpty` is `label === ''`."
|
|
159
|
+
"pattern": "^[a-z][a-z0-9-]*/[a-z][a-z0-9-]*$",
|
|
160
|
+
"description": "Qualified Action id `<plugin>/<action>` the click dispatches via POST /api/actions/:id. Resolved by the kernel registry; an unknown id makes the BFF answer 404."
|
|
144
161
|
},
|
|
162
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 48 },
|
|
163
|
+
"icon": { "$ref": "#/$defs/IconString" },
|
|
145
164
|
"severity": { "$ref": "#/$defs/Severity" },
|
|
146
|
-
"
|
|
147
|
-
|
|
165
|
+
"enabled": {
|
|
166
|
+
"type": "boolean",
|
|
167
|
+
"description": "Dynamic gate. The button is ALWAYS emitted (the persistence upsert refreshes the row each scan); `false` renders it disabled. e.g. `isStale` for the bump button."
|
|
168
|
+
},
|
|
169
|
+
"disabledReason": {
|
|
170
|
+
"type": "string",
|
|
171
|
+
"maxLength": 128,
|
|
172
|
+
"description": "Tooltip shown when `enabled` is false."
|
|
173
|
+
},
|
|
174
|
+
"input": {
|
|
175
|
+
"type": "object",
|
|
176
|
+
"description": "Reserved (Step 2+). Static input merged into the dispatch body for parametrized actions that need no user prompt."
|
|
177
|
+
},
|
|
178
|
+
"prompt": {
|
|
179
|
+
"$ref": "#/$defs/payloads/_ActionPrompt",
|
|
180
|
+
"description": "Reserved (Step 3+). Declares an input-type prompt the UI collects before dispatching (enum-pick for stability, single-string for tags)."
|
|
181
|
+
},
|
|
182
|
+
"confirm": {
|
|
183
|
+
"type": "boolean",
|
|
184
|
+
"default": false,
|
|
185
|
+
"description": "Reserved. Require an extra confirm step before dispatch (destructive actions)."
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"description": "An action button rendered in the inspector. The manifest declares only `{ slot: 'inspector.action.button' }`; the per-node payload carries the action id, label, and the dynamic `enabled` flag. Click dispatches the Action via POST /api/actions/:id. `emitWhenEmpty` does not apply (a button is always meaningful)."
|
|
189
|
+
},
|
|
190
|
+
"_ActionPrompt": {
|
|
191
|
+
"title": "ActionPrompt",
|
|
192
|
+
"type": "object",
|
|
193
|
+
"additionalProperties": false,
|
|
194
|
+
"required": ["inputType", "paramKey", "label"],
|
|
195
|
+
"properties": {
|
|
196
|
+
"inputType": {
|
|
197
|
+
"$ref": "input-types.schema.json#/$defs/InputTypeName",
|
|
198
|
+
"description": "Input-type id from the closed catalog. The UI renders the matching control before dispatch (`single-string`, `enum-pick` and `string-list` today; other types degrade to a graceful 'unsupported' notice)."
|
|
199
|
+
},
|
|
200
|
+
"paramKey": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"minLength": 1,
|
|
203
|
+
"maxLength": 48,
|
|
204
|
+
"description": "Key under which the collected value is placed in the dispatch `input` body."
|
|
205
|
+
},
|
|
206
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 64 },
|
|
207
|
+
"defaultValue": {
|
|
208
|
+
"oneOf": [
|
|
209
|
+
{ "type": "string" },
|
|
210
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
211
|
+
],
|
|
212
|
+
"description": "Optional pre-filled value the UI seeds the control with before the user edits (e.g. a node's current tags for a `string-list` edit). String for scalar input-types, string array for list input-types."
|
|
213
|
+
},
|
|
214
|
+
"options": {
|
|
215
|
+
"type": "array",
|
|
216
|
+
"items": {
|
|
217
|
+
"type": "object",
|
|
218
|
+
"additionalProperties": false,
|
|
219
|
+
"required": ["value", "label"],
|
|
220
|
+
"properties": {
|
|
221
|
+
"value": { "type": "string" },
|
|
222
|
+
"label": { "type": "string" }
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
"description": "Choice list for `enum-pick` / `enum-multipick` input types."
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"description": "Reserved (Steps 3+). Declares a parameter the UI prompts for before dispatching the Action, reusing the input-type catalog. Step 1 actions (bump) omit it."
|
|
148
229
|
},
|
|
149
230
|
"graph.node.alert": {
|
|
231
|
+
"title": "AlertPayload",
|
|
150
232
|
"type": "object",
|
|
151
233
|
"additionalProperties": false,
|
|
152
234
|
"properties": {
|
|
@@ -163,11 +245,12 @@
|
|
|
163
245
|
"description": "Decoration on the graph node (corner badge / pin). At least one of `icon`, `severity`, `count` is required. 'Empty' for `emitWhenEmpty` is the absence of `icon` AND `count`. Hard cap 1 marker per node per plugin extension (slot config enforces)."
|
|
164
246
|
},
|
|
165
247
|
"inspector.body.panel.breakdown": {
|
|
248
|
+
"title": "BreakdownPayload",
|
|
166
249
|
"type": "object",
|
|
167
250
|
"additionalProperties": false,
|
|
168
|
-
"required": ["
|
|
251
|
+
"required": ["bars"],
|
|
169
252
|
"properties": {
|
|
170
|
-
"
|
|
253
|
+
"bars": {
|
|
171
254
|
"type": "array",
|
|
172
255
|
"maxItems": 20,
|
|
173
256
|
"items": {
|
|
@@ -180,11 +263,12 @@
|
|
|
180
263
|
"tooltip": { "type": "string", "maxLength": 256 }
|
|
181
264
|
}
|
|
182
265
|
},
|
|
183
|
-
"description": "Top-N labeled values rendered as a horizontal bar chart. Hard cap 20
|
|
266
|
+
"description": "Top-N labeled values rendered as a horizontal bar chart. Hard cap 20 bars (overflow rejected at validation, plugin should pre-truncate). 'Empty' for `emitWhenEmpty` is `bars.length === 0`."
|
|
184
267
|
}
|
|
185
268
|
}
|
|
186
269
|
},
|
|
187
270
|
"inspector.body.panel.records": {
|
|
271
|
+
"title": "RecordsPayload",
|
|
188
272
|
"type": "object",
|
|
189
273
|
"additionalProperties": false,
|
|
190
274
|
"required": ["columns", "rows"],
|
|
@@ -227,6 +311,7 @@
|
|
|
227
311
|
"description": "Recursive tree rendered as an indented hierarchy. Hard caps: max depth 6, max 200 total nodes per tree (validator enforces). 'Empty' for `emitWhenEmpty` is the root having no `children`."
|
|
228
312
|
},
|
|
229
313
|
"_TreeNode": {
|
|
314
|
+
"title": "TreeNode",
|
|
230
315
|
"type": "object",
|
|
231
316
|
"additionalProperties": false,
|
|
232
317
|
"required": ["label"],
|
|
@@ -241,11 +326,12 @@
|
|
|
241
326
|
}
|
|
242
327
|
},
|
|
243
328
|
"inspector.body.panel.key-values": {
|
|
329
|
+
"title": "KeyValuesPayload",
|
|
244
330
|
"type": "object",
|
|
245
331
|
"additionalProperties": false,
|
|
246
|
-
"required": ["
|
|
332
|
+
"required": ["pairs"],
|
|
247
333
|
"properties": {
|
|
248
|
-
"
|
|
334
|
+
"pairs": {
|
|
249
335
|
"type": "array",
|
|
250
336
|
"maxItems": 50,
|
|
251
337
|
"items": {
|
|
@@ -265,16 +351,17 @@
|
|
|
265
351
|
"tooltip": { "type": "string", "maxLength": 256 }
|
|
266
352
|
}
|
|
267
353
|
},
|
|
268
|
-
"description": "Flat key/value pairs (max 50). Renders as a definition list. 'Empty' for `emitWhenEmpty` is `
|
|
354
|
+
"description": "Flat key/value pairs (max 50). Renders as a definition list. 'Empty' for `emitWhenEmpty` is `pairs.length === 0`."
|
|
269
355
|
}
|
|
270
356
|
}
|
|
271
357
|
},
|
|
272
358
|
"inspector.body.panel.link-list": {
|
|
359
|
+
"title": "LinkListPayload",
|
|
273
360
|
"type": "object",
|
|
274
361
|
"additionalProperties": false,
|
|
275
|
-
"required": ["
|
|
362
|
+
"required": ["links"],
|
|
276
363
|
"properties": {
|
|
277
|
-
"
|
|
364
|
+
"links": {
|
|
278
365
|
"type": "array",
|
|
279
366
|
"maxItems": 100,
|
|
280
367
|
"items": {
|
|
@@ -297,11 +384,12 @@
|
|
|
297
384
|
}
|
|
298
385
|
}
|
|
299
386
|
},
|
|
300
|
-
"description": "List of in-scope node paths (max 100). 'Empty' for `emitWhenEmpty` is `
|
|
387
|
+
"description": "List of in-scope node paths (max 100). 'Empty' for `emitWhenEmpty` is `links.length === 0`."
|
|
301
388
|
}
|
|
302
389
|
}
|
|
303
390
|
},
|
|
304
391
|
"inspector.body.panel.markdown": {
|
|
392
|
+
"title": "MarkdownPayload",
|
|
305
393
|
"type": "object",
|
|
306
394
|
"additionalProperties": false,
|
|
307
395
|
"required": ["markdown"],
|
|
@@ -314,6 +402,7 @@
|
|
|
314
402
|
}
|
|
315
403
|
},
|
|
316
404
|
"topbar.nav.start": {
|
|
405
|
+
"title": "ScopeStatPayload",
|
|
317
406
|
"type": "object",
|
|
318
407
|
"additionalProperties": false,
|
|
319
408
|
"required": ["value"],
|