@ai-matrx/content-ir 0.9.0 → 0.10.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 (45) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +24 -5
  3. package/dist/convert.cjs +1680 -0
  4. package/dist/convert.cjs.map +1 -0
  5. package/dist/convert.d.cts +230 -0
  6. package/dist/convert.d.ts +230 -0
  7. package/dist/convert.js +1666 -0
  8. package/dist/convert.js.map +1 -0
  9. package/dist/core.cjs +2493 -0
  10. package/dist/core.cjs.map +1 -0
  11. package/dist/core.d.cts +370 -0
  12. package/dist/core.d.ts +370 -0
  13. package/dist/core.js +2452 -0
  14. package/dist/core.js.map +1 -0
  15. package/dist/index.cjs +3 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +9 -2030
  18. package/dist/index.d.ts +9 -2030
  19. package/dist/index.js +3 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/ir-tree-DbLVxbf1.d.cts +441 -0
  22. package/dist/ir-tree-Dsc_66ek.d.ts +441 -0
  23. package/dist/ir-types-95bA2cXH.d.cts +119 -0
  24. package/dist/ir-types-95bA2cXH.d.ts +119 -0
  25. package/dist/kind-schema.types-CwncWj9U.d.cts +139 -0
  26. package/dist/kind-schema.types-CwncWj9U.d.ts +139 -0
  27. package/dist/registry.cjs +468 -0
  28. package/dist/registry.cjs.map +1 -0
  29. package/dist/registry.d.cts +357 -0
  30. package/dist/registry.d.ts +357 -0
  31. package/dist/registry.js +456 -0
  32. package/dist/registry.js.map +1 -0
  33. package/dist/session.cjs +2052 -0
  34. package/dist/session.cjs.map +1 -0
  35. package/dist/session.d.cts +75 -0
  36. package/dist/session.d.ts +75 -0
  37. package/dist/session.js +2047 -0
  38. package/dist/session.js.map +1 -0
  39. package/dist/wire.cjs +310 -0
  40. package/dist/wire.cjs.map +1 -0
  41. package/dist/wire.d.cts +326 -0
  42. package/dist/wire.d.ts +326 -0
  43. package/dist/wire.js +291 -0
  44. package/dist/wire.js.map +1 -0
  45. package/package.json +73 -1
@@ -0,0 +1,357 @@
1
+ import { ComponentType } from 'react';
2
+ import { a as KindSchema, R as RecordValueType } from './kind-schema.types-CwncWj9U.cjs';
3
+ import { g as IrResidue, f as IrPath, C as CanonicalBlockIR } from './ir-types-95bA2cXH.cjs';
4
+
5
+ /**
6
+ * KindDefinition — one kind, many facets. THE canonical registry entry.
7
+ *
8
+ * This does NOT merge BlockComponentRegistry or artifact-type-registry; the
9
+ * `legacyBlockType` and `artifact` facets are FACADES pointing into them, so
10
+ * migration is incremental and each registry keeps its own job.
11
+ */
12
+
13
+ /**
14
+ * The uniform props contract for kind-driven block components. This is what
15
+ * de-special-cases flashcards: no component receives bespoke glue — every
16
+ * kind component gets exactly this shape.
17
+ */
18
+ interface KindBlockProps {
19
+ kind: string;
20
+ schema: KindSchema;
21
+ /** Compliant snapshot value (schema fields + __kind). */
22
+ data: Record<string, unknown>;
23
+ status: "streaming" | "complete" | "error";
24
+ residue: IrResidue | null;
25
+ path: IrPath;
26
+ /** ParseSession identity for live child subscriptions; null after reload. */
27
+ identity: string | null;
28
+ /** Child-kind schema lookup (replaces passing allSchemas around). */
29
+ resolve: (kind: string) => KindSchema | undefined;
30
+ }
31
+ type KindTier = "eager" | "warm" | "cold";
32
+ interface KindDefinition {
33
+ /** Canonical slug — THE key. */
34
+ kind: string;
35
+ /** null until the warm/cold fetch delivers it. */
36
+ schema: KindSchema | null;
37
+ schemaSource: "system" | "flexible_data" | "content_ir";
38
+ tier: KindTier;
39
+ /** Component facet — lazy-loaded renderer for this kind. */
40
+ component?: {
41
+ load: () => Promise<{
42
+ default: ComponentType<KindBlockProps>;
43
+ }>;
44
+ };
45
+ /** Facade → BlockComponentRegistry type string (e.g. "flashcards"). */
46
+ legacyBlockType?: string;
47
+ /**
48
+ * Legacy-bridge facet: derive the existing component's `serverData` from a
49
+ * canonical envelope. This is what lets a kind light up the REAL component
50
+ * (FlashcardsBlock, …) with zero component changes during migration.
51
+ */
52
+ toLegacyServerData?: (envelope: CanonicalBlockIR) => Record<string, unknown> | undefined;
53
+ /** Facade → artifact-type-registry canvasType. */
54
+ artifact?: {
55
+ canvasType: string;
56
+ };
57
+ /**
58
+ * Markdown export facet — the FORWARD leg of artifact ⇄ markdown. Receives
59
+ * the ZERO-LOSS reconstructed value object (the CALLER reconstructs — for
60
+ * persisted structured artifacts `content.data` already IS that object;
61
+ * this facet only renders it; `__kind` discriminators may still be
62
+ * present and must be ignored). MUST produce human-readable markdown
63
+ * (headings / lists / bold), never a JSON dump — a fenced json body under
64
+ * a heading is acceptable only for inherently-code payloads (e.g. a
65
+ * schema_proposal's JSON Schema). Unknown extra keys the renderer doesn't
66
+ * understand MUST be appended under a small "Additional details"
67
+ * (key: value) section so nothing silently vanishes. Kinds without this
68
+ * facet fall back to `genericKindMarkdown` (kinds/kind-markdown-utils.ts).
69
+ */
70
+ toMarkdown?: (value: Record<string, unknown>) => string;
71
+ persistence?: {
72
+ persistStructured: boolean;
73
+ };
74
+ /** Future XML tags / kind aliases resolving to this kind. */
75
+ discriminatorAliases?: string[];
76
+ /**
77
+ * PARTIAL-READY opt-in — the streaming partial-kinds posture.
78
+ *
79
+ * While a structured region streams, the server may announce a PROVISIONAL
80
+ * instance of this kind on `metadata.__ir_partial` (valid, closed JSON that
81
+ * may be missing required fields). The default posture is WITHHOLD: a
82
+ * provisional value is never routed to a component, and the block keeps its
83
+ * loading skeleton until the region completes — because a component that
84
+ * throws on an absent field must not be handed one.
85
+ *
86
+ * Setting this to `true` declares "this kind's component renders a partial
87
+ * value without throwing", and the provisional value is routed to the SAME
88
+ * component that renders the final one, filling in as tokens arrive. A kind
89
+ * with a `toLegacyServerData` bridge must ALSO pass `{ provisional: true }`
90
+ * to `makeCompleteEnvelopeBridge` (pinned by a test). A component that
91
+ * throws anyway is caught, screams, and permanently drops this kind back to
92
+ * withhold for the session.
93
+ *
94
+ * Contract: common-docs/systems/content-ir-system/STREAMING_PARTIAL_KINDS.md
95
+ */
96
+ partialReady?: boolean;
97
+ /**
98
+ * Loading-library slug (`kind_definition.metadata.loading_component`) —
99
+ * which of the ~20 hardcoded loading components renders while this kind's
100
+ * instance streams in / its schema+component fetch is in flight. Null or
101
+ * unknown slugs fall back to the generic structured skeleton.
102
+ */
103
+ loadingComponent?: string | null;
104
+ }
105
+
106
+ /**
107
+ * Kind ↔ content_ir storage shape — the pure, DB-free reshaping between the
108
+ * consumed `KindSchema` and the `content_ir.kind_definition.data` array +
109
+ * `content_ir.kind_edge` rows.
110
+ *
111
+ * Two exact inverses:
112
+ * - `kindSchemaToStorage` — the MIGRATION / write direction: a parsed
113
+ * `KindSchema` (fields Record, targets inline) → an ORDERED `data` array
114
+ * (targets stripped) + externalized `kind_edge` specs (targets, keyed by
115
+ * field PATH). This is what pours `flexible_data` (and future authored
116
+ * kinds) into the canonical tables.
117
+ * - `storageToKindSchema` — the ADAPTER / read direction: `data` array +
118
+ * edges → the same `KindSchema` the parser/emitter consume, re-attaching
119
+ * `object.kind` / `array.itemKinds` from the edges by path.
120
+ *
121
+ * Design invariants (from the 2026-07-05 kind-registry storage design, since deleted):
122
+ * - The `data` element is `FieldSchema` + `name`, MINUS ref targets. Order is
123
+ * intrinsic to the array (fixes the jsonb key-reorder bug).
124
+ * - `kind_edge` is the SINGLE source of truth for kind→kind refs: `object`
125
+ * → one edge (position null); `array` → N edges (union) ordered by
126
+ * `position`. `field_name` is a dot-PATH so a ref nested inside an
127
+ * `inline_object` still gets a distinct, collision-free edge.
128
+ * - `inline_object` is structural: its `fields` is an ordered array, it never
129
+ * becomes a registry row and never carries `__kind`. Its nested refs DO get
130
+ * edges (path-prefixed) so cascade/pinning see every dependency. Its
131
+ * `open` flag persists on the element (losing it is the open-empty-object
132
+ * defect).
133
+ * - `union.kinds` refs externalize to edges exactly like `array.itemKinds`;
134
+ * the stored element keeps `hasKinds: true` so lost edges scream on read.
135
+ * - A NON-OBJECT ROOT (`KindSchema.root`) stores as ONE reserved element
136
+ * named `ROOT_STORAGE_NAME` ("__root") — the only element allowed in that
137
+ * kind's `data`. Real fields may never use the reserved name.
138
+ *
139
+ * NO imports of supabase / the DB — this is pure and unit-tested by round-trip
140
+ * (`__tests__/kind-storage-transform.test.ts`).
141
+ */
142
+
143
+ /**
144
+ * Reserved `data[]` element name for a NON-OBJECT ROOT form (`KindSchema.root`).
145
+ * A root-form kind stores exactly one element under this name; the read
146
+ * direction reconstructs `{ root }` instead of a field map. The write
147
+ * direction rejects any REAL field with this name — the name is the marker.
148
+ */
149
+ declare const ROOT_STORAGE_NAME = "__root";
150
+ type StoredFieldBase = {
151
+ name: string;
152
+ required?: boolean;
153
+ nullable?: boolean;
154
+ /** Human guidance — mirrors FieldBase.description. */
155
+ description?: string;
156
+ /** Default VALUE (annotation-level) — mirrors FieldBase.default. */
157
+ default?: unknown;
158
+ };
159
+ /** One element of `kind_definition.data` — FieldSchema + name, ref targets removed. */
160
+ type StoredFieldElement = (StoredFieldBase & {
161
+ type: "string" | "boolean";
162
+ }) | (StoredFieldBase & {
163
+ type: "number";
164
+ min?: number;
165
+ max?: number;
166
+ step?: number;
167
+ }) | (StoredFieldBase & {
168
+ type: "string[]";
169
+ values?: string[];
170
+ open?: boolean;
171
+ }) | (StoredFieldBase & {
172
+ type: "number[]" | "boolean[]";
173
+ }) | (StoredFieldBase & {
174
+ type: "json";
175
+ }) | (StoredFieldBase & {
176
+ type: "json[]";
177
+ }) | (StoredFieldBase & {
178
+ type: "array";
179
+ }) | (StoredFieldBase & {
180
+ type: "object";
181
+ }) | (StoredFieldBase & {
182
+ type: "inline_object";
183
+ fields: StoredFieldElement[];
184
+ open?: boolean;
185
+ }) | (StoredFieldBase & {
186
+ type: "record";
187
+ values: RecordValueType;
188
+ }) | (StoredFieldBase & {
189
+ type: "enum";
190
+ values: string[];
191
+ open?: boolean;
192
+ }) | (StoredFieldBase & {
193
+ type: "union";
194
+ scalars: Array<"string" | "number" | "boolean">;
195
+ /** Marker that this union's kind refs live in edges (positions ordered). */
196
+ hasKinds?: boolean;
197
+ });
198
+ /** One `content_ir.kind_edge` row (child resolved to an id at insert time). */
199
+ type KindEdgeSpec = {
200
+ /** Field PATH in the parent's `data` (dot-notation into inline_objects). */
201
+ fieldPath: string;
202
+ /** Child kind slug — insert resolves this to `child_definition_id`. */
203
+ childKind: string;
204
+ /** Union (anyOf) ordering for array refs; null for a single object ref. */
205
+ position: number | null;
206
+ };
207
+ /** The full write payload for one kind: the ordered data array + its edges. */
208
+ type KindStorageShape = {
209
+ data: StoredFieldElement[];
210
+ edges: KindEdgeSpec[];
211
+ };
212
+ declare class KindStorageError extends Error {
213
+ constructor(message: string);
214
+ }
215
+ /**
216
+ * MIGRATION / write direction. Order of `data` follows `Object.entries(fields)`
217
+ * — the caller supplies the KindSchema whose field order is authoritative
218
+ * (prefer the compiled `system-kinds.ts` order for system kinds during the
219
+ * one-time flexible_data migration; jsonb order is the fallback for user kinds).
220
+ */
221
+ declare function kindSchemaToStorage(schema: KindSchema): KindStorageShape;
222
+ /** ADAPTER / read direction — the exact inverse of `kindSchemaToStorage`. */
223
+ declare function storageToKindSchema(kind: string, shape: KindStorageShape): KindSchema;
224
+
225
+ /**
226
+ * The dual gate — Arman's law as executable code: a kind is only `is_active`
227
+ * when its canonical `sample_data` passes BOTH systems.
228
+ *
229
+ * 1. Structural (Pydantic): the sample validates against the kind's
230
+ * `emitted_json_schema`. Python's Pydantic is the AUTHORITATIVE owner of
231
+ * this leg, but it reads the SAME materialized `emitted_json_schema` — so
232
+ * this TS ajv check and the Python check validate the same sample against
233
+ * the same schema and agree by construction. A disagreement IS the
234
+ * screamer (a schema Pydantic can't express, or an ajv/Pydantic gap).
235
+ * 2. Render (UI): the sample lights up the kind's real component. TS is the
236
+ * AUTHORITATIVE owner of this leg. It is a PROXY for a DOM render, not a
237
+ * DOM render. Exactly what it checks, and nothing more:
238
+ * · the kind has something to render with (`legacyBlockType` or
239
+ * `component`);
240
+ * · for BRIDGED kinds, `toLegacyServerData(sample)` returns a plain
241
+ * object that is SEMANTICALLY non-empty — see
242
+ * `describeUnrenderableBridgeOutput` for the exact predicate;
243
+ * · BRIDGELESS kinds pass with a recorded caveat — nothing is verified.
244
+ *
245
+ * This catches the 2026-07-04 "No flashcards available yet" class: a
246
+ * bridge that returns `undefined`, `{}`, `{language:"json"}` (the raw
247
+ * code-region annotation), or an object whose every value is empty.
248
+ *
249
+ * What it does NOT do — stated plainly, because a gate that overclaims is
250
+ * worse than no gate: it does not mount the component, and it cannot know
251
+ * WHICH key carries the payload. `{title:"Cell Biology", cards:[]}` passes
252
+ * this leg on `title` alone. Proving the payload key is populated needs
253
+ * per-kind knowledge the gate deliberately does not have; a DOM-level
254
+ * render check is the deeper leg, deferred to an RTL harness.
255
+ *
256
+ * Both legs necessary, neither sufficient. Fail either → `isActive: false` and
257
+ * the caller reports it loudly (Error Inspector, `content-ir`) and holds the
258
+ * row out of production. This module is PURE (deps injected) so it runs in the
259
+ * harness, in CI, and in a browser author-save alike.
260
+ *
261
+ * Ownership split (the 2026-07-05 kind-registry storage design, since deleted; the live contract is the code below): the caller writes the outcome
262
+ * to the LIVE `content_ir.kind_definition` row's `is_active`; the canonical
263
+ * `_version_capture` trigger snapshots that state into `history.row_versions`
264
+ * (never a post-hoc history mutation).
265
+ */
266
+
267
+ /** The facets the render leg needs — a structural subset of KindDefinition. */
268
+ interface DualGateDefinition {
269
+ legacyBlockType?: string;
270
+ toLegacyServerData?: (envelope: CanonicalBlockIR) => Record<string, unknown> | undefined;
271
+ component?: {
272
+ load: () => Promise<unknown>;
273
+ };
274
+ }
275
+ /**
276
+ * The render leg's second satisfier: an ACTIVE `role='output'` component
277
+ * resolved from `content_ir.kind_component`. Feed this from
278
+ * `resolveComponent(kind, "web", "output")`.
279
+ *
280
+ * Why this exists: the render leg originally consulted only the compiled TS
281
+ * registry, so an agent-authored kind whose renderer is a `source='db'` row was
282
+ * structurally unable to pass — `definition` came back null and the gate said
283
+ * "no component" about a kind that had a live, working one. Six authored kinds
284
+ * (wine_tasting, employee_card, employee_roster, employee_of_the_week,
285
+ * flashcard_deck, arman_video_prompt) sat permanently inactive because of it.
286
+ *
287
+ * NOT a mirror of `content_ir.evaluate_kind_activation`. The SQL render leg is
288
+ * presence-only — it checks that an active `role='output'` row exists, because
289
+ * SQL cannot execute a TypeScript bridge. THIS leg is strictly stronger: for a
290
+ * compiled kind it also runs `toLegacyServerData` and rejects semantically
291
+ * empty output (the "No <kind> available" class).
292
+ *
293
+ * The asymmetry is deliberate and bounded: SQL is the FLOOR (necessary, and
294
+ * sufficient for DB-authored components, which own no bridge), while this leg
295
+ * is the CEILING for compiled kinds. Consequence to know: activating a COMPILED
296
+ * kind whose bridge is broken would pass the RPC and fail here. Compiled kinds
297
+ * are activated by developers through `scripts/shape/activate-kinds.ts`, which
298
+ * runs this leg — the studio control only ever reaches owner-authored kinds.
299
+ * If that ever stops being true, the browser control must run this gate before
300
+ * enabling its button.
301
+ */
302
+ interface DualGateResolvedComponent {
303
+ componentKey: string;
304
+ /** The row's own render-trust verdict (R6). Inactive rows do not satisfy. */
305
+ isActive: boolean;
306
+ /** "bundled" | "db" — reported in the leg detail, never gates the verdict. */
307
+ source: string;
308
+ }
309
+ interface DualGateInput {
310
+ kind: string;
311
+ /** The canonical instance (kind_definition.sample_data). */
312
+ sample: Record<string, unknown>;
313
+ /** The materialized kind_definition.emitted_json_schema (plain, no __kind). */
314
+ emittedJsonSchema: unknown;
315
+ /** The registry definition for the kind (or null when unregistered). */
316
+ definition: DualGateDefinition | null;
317
+ /**
318
+ * The resolver's `(kind, web, output)` answer, when the caller has one.
319
+ * Omit (or pass null) to check the compiled registry alone.
320
+ */
321
+ resolvedComponent?: DualGateResolvedComponent | null;
322
+ /**
323
+ * True when the kind is a generated data-only contract
324
+ * (`metadata.family` ∈ workflow_io | tool_io | action_io | agent_io).
325
+ * Those are passed between nodes and never rendered, so the render leg is
326
+ * structurally inapplicable — the same `n/a` doctrine the shape doctor uses.
327
+ * Failing them would be noise, and noise erodes the gate.
328
+ */
329
+ dataOnly?: boolean;
330
+ }
331
+ interface LegResult {
332
+ ok: boolean;
333
+ detail?: string;
334
+ }
335
+ interface DualGateResult {
336
+ /** True only when BOTH legs pass — the value the caller writes to is_active. */
337
+ isActive: boolean;
338
+ structural: LegResult;
339
+ render: LegResult;
340
+ }
341
+ /**
342
+ * The structural leg, exported on its own so the shape doctor
343
+ * (`shape-doctor.ts`) RECOMPUTES gate validation with the exact same ajv
344
+ * config + marker semantics as activation (verbatim first, marker-free retry
345
+ * second) — never a parallel validator. `sample` is `unknown` (not `Record`) because kind examples may
346
+ * legitimately be scalars/arrays (workflow I/O kinds like `text`/`number`).
347
+ */
348
+ declare function validateStructuralLeg(sample: unknown, emittedJsonSchema: unknown): LegResult;
349
+ declare function runKindDualGate(input: DualGateInput): DualGateResult;
350
+ /**
351
+ * One-line, Error-Inspector-ready reason for a failed gate (empty string when
352
+ * it passed). The caller feeds this to `captureError({ source: "content-ir" })`
353
+ * and sets `is_active=false`.
354
+ */
355
+ declare function describeDualGateFailure(kind: string, result: DualGateResult): string;
356
+
357
+ export { type DualGateDefinition, type DualGateInput, type DualGateResolvedComponent, type DualGateResult, type KindBlockProps, type KindDefinition, type KindEdgeSpec, KindStorageError, type KindStorageShape, type KindTier, type LegResult, ROOT_STORAGE_NAME, type StoredFieldElement, describeDualGateFailure, kindSchemaToStorage, runKindDualGate, storageToKindSchema, validateStructuralLeg };