@skill-map/cli 0.52.0 → 0.53.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.
Files changed (50) hide show
  1. package/dist/cli/tutorial/sm-tutorial/SKILL.md +239 -1659
  2. package/dist/cli/tutorial/sm-tutorial/references/_core.md +332 -0
  3. package/dist/cli/tutorial/sm-tutorial/references/_manifest.yml +175 -0
  4. package/dist/cli/tutorial/sm-tutorial/references/fixtures.md +251 -0
  5. package/dist/cli/tutorial/{sm-master/references/tour-authoring.md → sm-tutorial/references/part-authoring.md} +14 -15
  6. package/dist/cli/tutorial/sm-tutorial/references/part-cli.md +267 -0
  7. package/dist/cli/tutorial/sm-tutorial/references/part-connect-harness.md +180 -0
  8. package/dist/cli/tutorial/sm-tutorial/references/part-fundamentals.md +424 -0
  9. package/dist/cli/tutorial/sm-tutorial/references/part-live-site.md +156 -0
  10. package/dist/cli/tutorial/sm-tutorial/references/part-maintain.md +286 -0
  11. package/dist/cli/tutorial/sm-tutorial/references/part-mcp.md +78 -0
  12. package/dist/cli/tutorial/{sm-master/references/tour-plugins.md → sm-tutorial/references/part-plugins.md} +11 -11
  13. package/dist/cli/tutorial/sm-tutorial/references/part-project-kickoff.md +186 -0
  14. package/dist/cli/tutorial/{sm-master/references/tour-settings.md → sm-tutorial/references/part-settings.md} +22 -24
  15. package/dist/cli.js +1213 -550
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +334 -207
  18. package/dist/kernel/index.d.ts +320 -15
  19. package/dist/kernel/index.js +334 -207
  20. package/dist/migrations/001_initial.sql +36 -0
  21. package/dist/ui/chunk-EQ72PEHT.js +1 -0
  22. package/dist/ui/chunk-GBKHMJ4B.js +1110 -0
  23. package/dist/ui/chunk-GEI6INVH.js +515 -0
  24. package/dist/ui/chunk-JXRIGHET.js +552 -0
  25. package/dist/ui/{chunk-WQMZOINB.js → chunk-K2MAVAHG.js} +1 -1
  26. package/dist/ui/{chunk-BV323KTK.js → chunk-KHARMPTZ.js} +1 -1
  27. package/dist/ui/chunk-L4NIF75A.js +2 -0
  28. package/dist/ui/chunk-LCOYSPKE.js +1 -0
  29. package/dist/ui/chunk-OFDQMBSJ.js +1 -0
  30. package/dist/ui/chunk-P2DAPRK7.js +2 -0
  31. package/dist/ui/chunk-Q2A6FWC7.js +4 -0
  32. package/dist/ui/{chunk-ZNDMBION.js → chunk-TXTY24G4.js} +28 -30
  33. package/dist/ui/chunk-UBQUCSQ4.js +1 -0
  34. package/dist/ui/chunk-WFLPMCK4.js +392 -0
  35. package/dist/ui/chunk-YQFIXHKM.js +123 -0
  36. package/dist/ui/index.html +2 -2
  37. package/dist/ui/{main-2DWVSRRX.js → main-OYITFJ7B.js} +3 -3
  38. package/dist/ui/{styles-QBTVKEVX.css → styles-Q4NCOJQY.css} +1 -1
  39. package/migrations/001_initial.sql +36 -0
  40. package/package.json +10 -8
  41. package/dist/cli/tutorial/sm-master/SKILL.md +0 -688
  42. package/dist/cli/tutorial/sm-master/references/fixture-templates.md +0 -212
  43. package/dist/ui/chunk-5MCXQKRN.js +0 -1066
  44. package/dist/ui/chunk-6B5EAHIM.js +0 -1110
  45. package/dist/ui/chunk-AEA5GIA7.js +0 -1
  46. package/dist/ui/chunk-AQN27TN2.js +0 -123
  47. package/dist/ui/chunk-CAJ7ZI44.js +0 -1
  48. package/dist/ui/chunk-E2XO4JVD.js +0 -1
  49. package/dist/ui/chunk-VJ57LHDR.js +0 -4
  50. package/dist/ui/chunk-WMGW2UAL.js +0 -2
@@ -86,12 +86,237 @@ interface IRegisteredAnnotationKey {
86
86
  * Closed enum of view slot names. Mirror of
87
87
  * `spec/schemas/view-slots.schema.json#/$defs/SlotName`.
88
88
  */
89
- type TSlotName = 'card.title.right' | 'card.subtitle.left' | 'card.footer.left' | 'card.footer.right' | 'graph.node.alert' | 'inspector.header.badge.counter' | 'inspector.header.badge.tag' | 'inspector.body.panel.breakdown' | 'inspector.body.panel.records' | 'inspector.body.panel.tree' | 'inspector.body.panel.key-values' | 'inspector.body.panel.link-list' | 'inspector.body.panel.markdown' | 'topbar.nav.start';
89
+ type TSlotName = 'card.title.right' | 'card.subtitle.left' | 'card.footer.left' | 'card.footer.right' | 'graph.node.alert' | 'inspector.header.badge' | 'inspector.action.button' | 'inspector.body.panel.breakdown' | 'inspector.body.panel.records' | 'inspector.body.panel.tree' | 'inspector.body.panel.key-values' | 'inspector.body.panel.link-list' | 'inspector.body.panel.markdown' | 'topbar.nav.start';
90
90
  /**
91
91
  * Closed enum of input-type names for plugin settings. Mirror of
92
92
  * `spec/schemas/input-types.schema.json#/$defs/InputTypeName`.
93
93
  */
94
94
  type TInputTypeName = 'string-list' | 'single-string' | 'boolean-flag' | 'integer' | 'enum-pick' | 'enum-multipick' | 'path-glob' | 'regex' | 'secret' | 'key-value-list';
95
+ /**
96
+ * Closed severity palette aligned with PrimeNG `<p-tag>` / `<p-message>` severities. Used by counter, tag, alert, and icon slots for color/contrast hints. The UI maps each severity to a theme-aware tint; plugins do not pick raw colors.
97
+ */
98
+ type Severity$1 = 'info' | 'warn' | 'success' | 'danger';
99
+ /**
100
+ * Single string, prefix-discriminated by the UI. Four valid shapes: (1) emoji, any value starting with a non-ASCII-letter codepoint renders as text; (2) PrimeIcons, `pi-foo` or `pi pi-foo` renders as `<i class="pi pi-foo">`; (3) FontAwesome explicit family, `fa-solid fa-foo` / `fa-regular fa-foo` / `fa-brands fa-foo` passes through as-is; (4) FontAwesome shorthand, `fa-foo` (no family token) defaults to `fa-solid fa-foo`. Bare class names without a `pi-` / `fa-` prefix are rejected at manifest load (invalid-manifest). Unknown PrimeIcons / FontAwesome names render no icon (silent fallback) plus a console warning.
101
+ */
102
+ type IconString = string;
103
+ interface SlotPayloadMap {
104
+ 'card.title.right': IconMarkerPayload;
105
+ 'card.subtitle.left': CounterPayload;
106
+ 'card.footer.left': CounterPayload;
107
+ 'card.footer.right': CounterPayload;
108
+ 'graph.node.alert': AlertPayload;
109
+ 'inspector.header.badge': BadgePayload;
110
+ 'inspector.action.button': ActionButtonPayload;
111
+ 'inspector.body.panel.breakdown': BreakdownPayload;
112
+ 'inspector.body.panel.records': RecordsPayload;
113
+ 'inspector.body.panel.tree': TreeNode;
114
+ 'inspector.body.panel.key-values': KeyValuesPayload;
115
+ 'inspector.body.panel.link-list': LinkListPayload;
116
+ 'inspector.body.panel.markdown': MarkdownPayload;
117
+ 'topbar.nav.start': ScopeStatPayload;
118
+ }
119
+ /**
120
+ * Single icon per node, small standalone marker rendered next to the card title. The manifest requires `icon`; the payload optionally overrides it per node and may add `severity` (color tint) and `tooltip`. No counts, no labels, for chip + number use a counter slot; for label + severity use a tag slot. 'Empty' for `emitWhenEmpty` is the absence of both payload `icon` and a manifest fallback (in practice never empty since the manifest icon is required).
121
+ */
122
+ interface IconMarkerPayload {
123
+ /**
124
+ * Single string, prefix-discriminated by the UI. Four valid shapes: (1) emoji, any value starting with a non-ASCII-letter codepoint renders as text; (2) PrimeIcons, `pi-foo` or `pi pi-foo` renders as `<i class="pi pi-foo">`; (3) FontAwesome explicit family, `fa-solid fa-foo` / `fa-regular fa-foo` / `fa-brands fa-foo` passes through as-is; (4) FontAwesome shorthand, `fa-foo` (no family token) defaults to `fa-solid fa-foo`. Bare class names without a `pi-` / `fa-` prefix are rejected at manifest load (invalid-manifest). Unknown PrimeIcons / FontAwesome names render no icon (silent fallback) plus a console warning.
125
+ */
126
+ icon?: string;
127
+ severity?: Severity$1;
128
+ tooltip?: string;
129
+ }
130
+ /**
131
+ * 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
+ */
133
+ interface CounterPayload {
134
+ /**
135
+ * Single non-negative integer for the chip / badge. 'Empty' for `emitWhenEmpty` purposes is `value === 0`.
136
+ */
137
+ value: number;
138
+ tooltip?: string;
139
+ /**
140
+ * Closed severity palette aligned with PrimeNG `<p-tag>` / `<p-message>` severities. Used by counter, tag, alert, and icon slots for color/contrast hints. The UI maps each severity to a theme-aware tint; plugins do not pick raw colors.
141
+ */
142
+ severity?: 'info' | 'warn' | 'success' | 'danger';
143
+ }
144
+ /**
145
+ * 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).
146
+ */
147
+ interface AlertPayload {
148
+ icon?: IconString;
149
+ severity?: Severity$1;
150
+ /**
151
+ * Optional badge count rendered next to the icon (1-99; 99+ collapses to '99+'). Omit for an icon-only marker.
152
+ */
153
+ count?: number;
154
+ tooltip?: string;
155
+ }
156
+ /**
157
+ * 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`.
158
+ */
159
+ interface BadgePayload {
160
+ icon?: IconString;
161
+ label?: string;
162
+ count?: number;
163
+ severity?: Severity$1;
164
+ tooltip?: string;
165
+ }
166
+ /**
167
+ * 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).
168
+ */
169
+ interface ActionButtonPayload {
170
+ /**
171
+ * 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.
172
+ */
173
+ actionId: string;
174
+ label: string;
175
+ icon?: IconString;
176
+ severity?: Severity$1;
177
+ /**
178
+ * 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.
179
+ */
180
+ enabled: boolean;
181
+ /**
182
+ * Tooltip shown when `enabled` is false.
183
+ */
184
+ disabledReason?: string;
185
+ /**
186
+ * Reserved (Step 2+). Static input merged into the dispatch body for parametrized actions that need no user prompt.
187
+ */
188
+ input?: {};
189
+ prompt?: ActionPrompt;
190
+ /**
191
+ * Reserved. Require an extra confirm step before dispatch (destructive actions).
192
+ */
193
+ confirm?: boolean;
194
+ }
195
+ /**
196
+ * Reserved (Step 3+). Declares an input-type prompt the UI collects before dispatching (enum-pick for stability, single-string for tags).
197
+ */
198
+ interface ActionPrompt {
199
+ /**
200
+ * 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).
201
+ */
202
+ inputType: ('string-list' | 'single-string' | 'boolean-flag' | 'integer' | 'enum-pick' | 'enum-multipick' | 'path-glob' | 'regex' | 'secret' | 'key-value-list') & string;
203
+ /**
204
+ * Key under which the collected value is placed in the dispatch `input` body.
205
+ */
206
+ paramKey: string;
207
+ label: string;
208
+ /**
209
+ * 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.
210
+ */
211
+ defaultValue?: string | string[];
212
+ /**
213
+ * Choice list for `enum-pick` / `enum-multipick` input types.
214
+ */
215
+ options?: {
216
+ value: string;
217
+ label: string;
218
+ }[];
219
+ }
220
+ interface BreakdownPayload {
221
+ /**
222
+ * 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`.
223
+ *
224
+ * @maxItems 20
225
+ */
226
+ bars: {
227
+ label: string;
228
+ value: number;
229
+ tooltip?: string;
230
+ }[];
231
+ }
232
+ interface RecordsPayload {
233
+ /**
234
+ * Column declarations (max 6). Each row's value at `key` is rendered under `label`.
235
+ *
236
+ * @minItems 1
237
+ * @maxItems 6
238
+ */
239
+ columns: {
240
+ key: string;
241
+ label: string;
242
+ }[];
243
+ /**
244
+ * Tabular rows (max 50). Cell values are scalar only (string ≤256 chars, number, boolean, or null). 'Empty' for `emitWhenEmpty` is `rows.length === 0`.
245
+ *
246
+ * @maxItems 50
247
+ */
248
+ rows: {
249
+ [k: string]: string | number | boolean | null;
250
+ }[];
251
+ }
252
+ /**
253
+ * 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`.
254
+ */
255
+ interface TreeNode {
256
+ label: string;
257
+ marker?: IconString;
258
+ tooltip?: string;
259
+ children?: TreeNode1[];
260
+ }
261
+ interface TreeNode1 {
262
+ label: string;
263
+ marker?: IconString;
264
+ tooltip?: string;
265
+ children?: TreeNode1[];
266
+ }
267
+ interface KeyValuesPayload {
268
+ /**
269
+ * Flat key/value pairs (max 50). Renders as a definition list. 'Empty' for `emitWhenEmpty` is `pairs.length === 0`.
270
+ *
271
+ * @maxItems 50
272
+ */
273
+ pairs: {
274
+ key: string;
275
+ value: string | number | boolean | null;
276
+ tooltip?: string;
277
+ }[];
278
+ }
279
+ interface LinkListPayload {
280
+ /**
281
+ * List of in-scope node paths (max 100). 'Empty' for `emitWhenEmpty` is `links.length === 0`.
282
+ *
283
+ * @maxItems 100
284
+ */
285
+ links: {
286
+ /**
287
+ * Node path within the scope. Resolved by the UI to a clickable link via `Router.navigate`, never rendered as a raw `[href]` (per the renderer attr-sanitization analyzer).
288
+ */
289
+ path: string;
290
+ label?: string;
291
+ /**
292
+ * Optional Provider kind id (informational). The UI may apply per-kind tinting from `kindRegistry`.
293
+ */
294
+ kind?: string;
295
+ }[];
296
+ }
297
+ interface MarkdownPayload {
298
+ /**
299
+ * Markdown text rendered with a sanitized allow-list (paragraphs, headings up to H3, lists, inline code, fenced code, emphasis, strong, blockquote). HTML, scripts, embedded SVG, image tags, and link autodetection are stripped. Hard cap 4096 chars to keep render cost bounded. 'Empty' for `emitWhenEmpty` is `markdown.trim() === ''`.
300
+ */
301
+ markdown: string;
302
+ }
303
+ /**
304
+ * Single value summarizing the entire scope. Emitted ONCE per scan (not per node). Plugins use `ctx.emitScopeContribution(...)` (analyzer context), extractors do not see `emitScopeContribution`.
305
+ */
306
+ interface ScopeStatPayload {
307
+ /**
308
+ * Either a non-negative integer or a short string. The UI renders it as a single chip in the topbar.
309
+ */
310
+ value: number | string;
311
+ label?: string;
312
+ tooltip?: string;
313
+ severity?: Severity$1;
314
+ }
315
+ /**
316
+ * Payload type for a given slot. `ctx.emitContribution` infers this from the
317
+ * declared contribution's `slot`, so the author gets a typed payload argument.
318
+ */
319
+ type SlotPayload<S extends TSlotName> = SlotPayloadMap[S];
95
320
 
96
321
  /**
97
322
  * Step 11.x, runtime view-contribution catalog types.
@@ -199,6 +424,19 @@ interface IRegisteredViewContribution {
199
424
  emitWhenEmpty: boolean;
200
425
  /** Manifest-declared ordering hint (default 100). See `IViewContribution.priority`. */
201
426
  priority?: number;
427
+ /**
428
+ * Inspector-only ordering hint, denormalised from the owning plugin's
429
+ * `plugin.json` `order` field (default 100). Orders the per-plugin
430
+ * inspector body sections. Same value on every contribution of a plugin.
431
+ */
432
+ pluginOrder?: number;
433
+ /**
434
+ * Inspector-only ordering hint, denormalised from the owning extension's
435
+ * `order` manifest field (default 100). Orders the bricks inside a
436
+ * plugin's inspector section. Same value on every contribution of an
437
+ * extension.
438
+ */
439
+ extensionOrder?: number;
202
440
  }
203
441
  /**
204
442
  * Common fields on every setting declaration. The discriminated union
@@ -367,6 +605,13 @@ interface IExtensionBase {
367
605
  version: string;
368
606
  /** Required short description shown by `sm <kind>s list` / UI. */
369
607
  description: string;
608
+ /**
609
+ * Optional inspector-only ordering hint (default 100). Inside the
610
+ * owning plugin's inspector section, orders this extension's
611
+ * `inspector.body.panel.*` bricks relative to its sibling extensions.
612
+ * Never affects execution order. See `extensions/base.schema.json`.
613
+ */
614
+ order?: number;
370
615
  /**
371
616
  * Optional opt-in single annotation contribution. Renamed from
372
617
  * `annotationContributions` (mapa) with the structure-as-truth
@@ -1134,6 +1379,12 @@ interface IPluginManifest {
1134
1379
  catalogCompat: string;
1135
1380
  /** Required short description shown in `sm plugins list` and the UI. */
1136
1381
  description: string;
1382
+ /**
1383
+ * Optional inspector-only ordering hint (default 100). Sorts the
1384
+ * per-plugin sections in the inspector body. Never affects execution
1385
+ * order. See `plugins-registry.schema.json#/$defs/PluginManifest`.
1386
+ */
1387
+ order?: number;
1137
1388
  storage?: TPluginStorage;
1138
1389
  author?: string;
1139
1390
  license?: string;
@@ -1422,6 +1673,15 @@ interface IPersistOptions {
1422
1673
  extractorRuns?: IExtractorRunRecord[];
1423
1674
  enrichments?: IEnrichmentRecord[];
1424
1675
  contributions?: IContributionRecord[];
1676
+ /**
1677
+ * "off-shape visible" follow-up, per-scan records of view
1678
+ * contributions REJECTED at emit time (undeclared ref, or payload
1679
+ * failed the slot's AJV schema). Plain REPLACE-ALL into
1680
+ * `scan_contribution_errors` (delete all, then insert), the same
1681
+ * posture as `scan_issues`. Empty / absent wipes the table (a clean
1682
+ * scan clears any stale rows). Surfaced by `sm plugins doctor`.
1683
+ */
1684
+ contributionErrors?: IContributionErrorRecord[];
1425
1685
  /**
1426
1686
  * Phase 3 / View contribution system, active runtime catalog of
1427
1687
  * registered view contributions, keyed by qualified id
@@ -1720,6 +1980,36 @@ interface IContributionRecord {
1720
1980
  payload: unknown;
1721
1981
  emittedAt: number;
1722
1982
  }
1983
+ /**
1984
+ * In-memory record of a view contribution REJECTED at emit time,
1985
+ * buffered during scan and flushed to `scan_contribution_errors` by
1986
+ * `persistScanResult`. The "off-shape visible" follow-up to the
1987
+ * ephemeral `extension.error` event (kind `contribution-rejected`):
1988
+ * the orchestrator still fires the event, AND pushes one of these so
1989
+ * the rejection survives the scan and surfaces in `sm plugins doctor`.
1990
+ *
1991
+ * Two rejection shapes share the record:
1992
+ * - `undeclared-contribution-ref`, the `ref` passed to
1993
+ * `ctx.emitContribution` was not one of the extension's declared
1994
+ * `viewContributions` objects. `contributionId` / `slot` absent.
1995
+ * - AJV failure, the payload failed the slot's payload schema.
1996
+ * `reason` is the AJV error string; `contributionId` / `slot` name
1997
+ * the resolved target.
1998
+ */
1999
+ interface IContributionErrorRecord {
2000
+ pluginId: string;
2001
+ extensionId: string;
2002
+ nodePath: string;
2003
+ /** `undeclared-contribution-ref` literal, or the AJV error string. */
2004
+ reason: string;
2005
+ /** Rendered diagnostic (mirrors the `extension.error` event message). */
2006
+ message: string;
2007
+ /** Absent for the `undeclared-contribution-ref` shape. */
2008
+ contributionId?: string;
2009
+ /** Absent for the `undeclared-contribution-ref` shape. */
2010
+ slot?: string;
2011
+ emittedAt: number;
2012
+ }
1723
2013
 
1724
2014
  /**
1725
2015
  * `loadScanResult`, driving inverse of `persistScanResult`. Reads the
@@ -2487,15 +2777,18 @@ interface IExtractorCallbacks {
2487
2777
  */
2488
2778
  enrichNode(partial: Partial<Node>): void;
2489
2779
  /**
2490
- * Emit a per-node view contribution. `contributionId` MUST be a key
2491
- * declared under the manifest's `ui` map; the payload MUST conform to
2492
- * the slot's payload schema in
2493
- * `spec/schemas/view-slots.schema.json#/$defs/payloads/<slot>`. Off-shape
2494
- * payloads (or unknown contribution ids) drop silently with an
2495
- * `extension.error`. Renamed from `viewContributions` with the
2496
- * structure-as-truth refactor.
2780
+ * Emit a per-node view contribution. Pass the contribution object you
2781
+ * declared in the manifest's `ui` map BY REFERENCE, e.g.
2782
+ * `const facts = { slot: '...' } satisfies IViewContribution; ui: { facts };`
2783
+ * then `ctx.emitContribution(facts, payload)`. The kernel recovers the
2784
+ * contribution id + slot by object identity, then validates `payload`
2785
+ * against the slot's payload schema in
2786
+ * `spec/schemas/view-slots.schema.json#/$defs/payloads/<slot>`. `payload`
2787
+ * is typed from `ref.slot` (`SlotPayload<C['slot']>`), so the wrong shape
2788
+ * is a compile error; an undeclared `ref` (a spread copy / inline literal)
2789
+ * or an off-shape payload drops at runtime with a loud `extension.error`.
2497
2790
  */
2498
- emitContribution(contributionId: string, payload: unknown): void;
2791
+ emitContribution<C extends IViewContribution>(ref: C, payload: SlotPayload<C['slot']>): void;
2499
2792
  }
2500
2793
  interface IExtractorContext extends IExtractorCallbacks {
2501
2794
  node: Node;
@@ -2700,12 +2993,14 @@ interface IAnalyzerContext {
2700
2993
  * sees the full graph at once. The analyzer walks `ctx.nodes` itself
2701
2994
  * and MUST supply the target node path explicitly per emission.
2702
2995
  *
2703
- * Calling `emitContribution` with a `contributionId` that is not
2704
- * declared in the manifest is dropped with an `extension.error`. The
2705
- * kernel routes emitted contributions to the same persistence
2706
- * pipeline as Extractor emissions (`scan_contributions`).
2996
+ * Pass the contribution object declared in the manifest `ui` map BY
2997
+ * REFERENCE (same model as the Extractor emit). `payload` is typed from
2998
+ * `ref.slot`. An undeclared `ref` (a spread copy / inline literal) or an
2999
+ * off-shape payload drops with a loud `extension.error`. The kernel routes
3000
+ * accepted contributions to the same persistence pipeline as Extractor
3001
+ * emissions (`scan_contributions`).
2707
3002
  */
2708
- emitContribution(nodePath: string, contributionId: string, payload: unknown): void;
3003
+ emitContribution<C extends IViewContribution>(nodePath: string, ref: C, payload: SlotPayload<C['slot']>): void;
2709
3004
  }
2710
3005
  interface IAnalyzer extends IExtensionBase {
2711
3006
  /** Discriminant injected by the loader from the folder structure. */
@@ -3192,6 +3487,7 @@ declare function runExtractorsForNode(opts: {
3192
3487
  externalLinks: Link[];
3193
3488
  enrichments: IEnrichmentRecord[];
3194
3489
  contributions: IContributionRecord[];
3490
+ contributionErrors: IContributionErrorRecord[];
3195
3491
  signals: Signal[];
3196
3492
  virtualNodes: Node[];
3197
3493
  }>;
@@ -3563,6 +3859,7 @@ declare function runScanWithRenames(_kernel: Kernel, options: RunScanOptions): P
3563
3859
  extractorRuns: IExtractorRunRecord[];
3564
3860
  enrichments: IEnrichmentRecord[];
3565
3861
  contributions: IContributionRecord[];
3862
+ contributionErrors: IContributionErrorRecord[];
3566
3863
  freshlyRunTuples: ReadonlySet<string>;
3567
3864
  }>;
3568
3865
  declare function runScan(_kernel: Kernel, options: RunScanOptions): Promise<ScanResult>;
@@ -4095,6 +4392,14 @@ interface StoragePort {
4095
4392
  * the disabled plugin's chips before the next scan.
4096
4393
  */
4097
4394
  purgeByPlugin(pluginId: string, extensionId?: string): Promise<number>;
4395
+ /**
4396
+ * "off-shape visible" follow-up, every view contribution the last
4397
+ * scan REJECTED at emit time (undeclared ref, or payload failed the
4398
+ * slot's AJV schema), ordered by `(pluginId, extensionId, nodePath,
4399
+ * emittedAt)` ASC. Consumed by `sm plugins doctor` to surface
4400
+ * runtime contribution rejections per plugin (and later the BFF).
4401
+ */
4402
+ listAllErrors(): Promise<IContributionErrorRecord[]>;
4098
4403
  };
4099
4404
  /**
4100
4405
  * Read-only access to `scan_node_tags`. Writes happen exclusively
@@ -4522,4 +4827,4 @@ interface Kernel {
4522
4827
  }
4523
4828
  declare function createKernel(): Kernel;
4524
4829
 
4525
- export { type Confidence, DuplicateExtensionError, EXTENSION_KINDS, type ExecutionFailureReason, type ExecutionKind, type ExecutionRecord, type ExecutionRunner, type ExecutionStatus, ExportQueryError, type ExtensionKind, type FilesystemPort, HOOK_TRIGGERS, type HistoryStats, type HistoryStatsErrorRates, type HistoryStatsExecutionsPerPeriod, type HistoryStatsPerActionRate, type HistoryStatsTokensPerAction, type HistoryStatsTopNode, type HistoryStatsTotals, type IAction, type IActionContext, type IActionPrecondition, type IActionResult, type IAnalyzer, type IAnalyzerContext, type IAnnotationContribution, type ICreateFsWatcherOptions, type IDedicatedStorePersist, type IDedicatedStoreWrapper, type IDiscoveredPlugin, type IEnrichmentRecord, type IExportQuery, type IExportSubset, type IExtension, type IExtensionBase, type IExternalRef, type IExtractor, type IExtractorCallbacks, type IExtractorContext, type IExtractorRunRecord, type IFormatter, type IFormatterContext, type IFsWatcher, type IHook, type IHookContext, type IHookDispatcher, type IIssueRow, type IKvStorePersist, type IKvStoreWrapper, type ILoadedExtension, type INodeBundle, type INodeChange, type INodeCounts, type INodeFilter, type IPersistOptions, type IPersistedEnrichment, type IPluginManifest, type IPluginStorageSchema, type IProvider, type IRawNode, type IRegisteredAnnotationKey, type IRegisteredViewContribution, type IRunOptions, type IRunResult, type IScanDelta, type ITransactionalStorage, type IViewContribution, type IWalkOptions, type IWatchBatch, type IWatchEvent, InMemoryProgressEmitter, type Issue, type IssueFix, KV_SCHEMA_KEY, type Kernel, LOG_LEVELS, type Link, type LinkKind, type LinkLocation, type LinkOccurrence, type LinkTrigger, type LogRecord, type LoggerPort, type Node, type NodeKind, type NodeStat, type PluginLoaderPort, type ProgressEmitterPort, type ProgressEvent, Registry, type RenameOp, type RunScanOptions, type RunnerPort, type ScanResult, type ScanScannedBy, type ScanStats, type Severity, SilentLogger, type Stability, type StoragePort, type TActionWrite, type TExecutionMode, type THookFilter, type THookTrigger, type TInputTypeName, type TLogLevel, type TLogMethodLevel, type TNodeChangeReason, type TPluginLoadStatus, type TPluginStorage, type TPluginStore, type TProgressListener, type TSettingDeclaration, type TSettingValue, type TSeverity, type TSlotName, type TWatchEventKind, type TripleSplit, applyExportQuery, computeScanDelta, configureLogger, createChokidarWatcher, createKernel, detectRenamesAndOrphans, getActiveLogger, isEmptyDelta, isLogLevel, log, logLevelRank, makeDedicatedStoreWrapper, makeEvent, makeHookDispatcher, makeKvStoreWrapper, makePluginStore, mergeNodeWithEnrichments, parseExportQuery, parseLogLevel, qualifiedExtensionId, resetLogger, runExtractorsForNode, runScan, runScanWithRenames };
4830
+ export { type Confidence, DuplicateExtensionError, EXTENSION_KINDS, type ExecutionFailureReason, type ExecutionKind, type ExecutionRecord, type ExecutionRunner, type ExecutionStatus, ExportQueryError, type ExtensionKind, type FilesystemPort, HOOK_TRIGGERS, type HistoryStats, type HistoryStatsErrorRates, type HistoryStatsExecutionsPerPeriod, type HistoryStatsPerActionRate, type HistoryStatsTokensPerAction, type HistoryStatsTopNode, type HistoryStatsTotals, type IAction, type IActionContext, type IActionPrecondition, type IActionResult, type IAnalyzer, type IAnalyzerContext, type IAnnotationContribution, type ICreateFsWatcherOptions, type IDedicatedStorePersist, type IDedicatedStoreWrapper, type IDiscoveredPlugin, type IEnrichmentRecord, type IExportQuery, type IExportSubset, type IExtension, type IExtensionBase, type IExternalRef, type IExtractor, type IExtractorCallbacks, type IExtractorContext, type IExtractorRunRecord, type IFormatter, type IFormatterContext, type IFsWatcher, type IHook, type IHookContext, type IHookDispatcher, type IIssueRow, type IKvStorePersist, type IKvStoreWrapper, type ILoadedExtension, type INodeBundle, type INodeChange, type INodeCounts, type INodeFilter, type IPersistOptions, type IPersistedEnrichment, type IPluginManifest, type IPluginStorageSchema, type IProvider, type IRawNode, type IRegisteredAnnotationKey, type IRegisteredViewContribution, type IRunOptions, type IRunResult, type IScanDelta, type ITransactionalStorage, type IViewContribution, type IWalkOptions, type IWatchBatch, type IWatchEvent, InMemoryProgressEmitter, type Issue, type IssueFix, KV_SCHEMA_KEY, type Kernel, LOG_LEVELS, type Link, type LinkKind, type LinkLocation, type LinkOccurrence, type LinkTrigger, type LogRecord, type LoggerPort, type Node, type NodeKind, type NodeStat, type PluginLoaderPort, type ProgressEmitterPort, type ProgressEvent, Registry, type RenameOp, type RunScanOptions, type RunnerPort, type ScanResult, type ScanScannedBy, type ScanStats, type Severity, SilentLogger, type SlotPayload, type SlotPayloadMap, type Stability, type StoragePort, type TActionWrite, type TExecutionMode, type THookFilter, type THookTrigger, type TInputTypeName, type TLogLevel, type TLogMethodLevel, type TNodeChangeReason, type TPluginLoadStatus, type TPluginStorage, type TPluginStore, type TProgressListener, type TSettingDeclaration, type TSettingValue, type TSeverity, type TSlotName, type TWatchEventKind, type TripleSplit, applyExportQuery, computeScanDelta, configureLogger, createChokidarWatcher, createKernel, detectRenamesAndOrphans, getActiveLogger, isEmptyDelta, isLogLevel, log, logLevelRank, makeDedicatedStoreWrapper, makeEvent, makeHookDispatcher, makeKvStoreWrapper, makePluginStore, mergeNodeWithEnrichments, parseExportQuery, parseLogLevel, qualifiedExtensionId, resetLogger, runExtractorsForNode, runScan, runScanWithRenames };