@ai-matrx/content-ir 0.10.4 → 0.11.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.
@@ -0,0 +1,294 @@
1
+ import { K as KIND_KEY } from './kind-schema.types-CwncWj9U.cjs';
2
+
3
+ /**
4
+ * Kind Directives — the grammar, the shell, and the position law (kernel edition).
5
+ *
6
+ * ONE system (Arman, 2026-08-23): the Matrx Envelope/Directive protocol and the
7
+ * Content IR kind system are one system. A directive is an ordinary kind
8
+ * instance — `{ "__kind": "directive_v1_<class>_<noun>", "items": [...] }` —
9
+ * whose registered shape additionally carries execution semantics on the
10
+ * server. This module is the PURE half, ported verbatim from the aidream source
11
+ * of record (`packages/matrx-graph/matrx_graph/content_ir/directives.py`) so
12
+ * every UI parses the grammar identically. It lives in the KERNEL because a
13
+ * host that can parse a kind must be able to recognise a directive without a
14
+ * second copy of these rules (matrx-frontend carried the only copy until
15
+ * 2026-09-08; Workflow Studio had none and rendered directives as raw text).
16
+ *
17
+ * THE SLUG GRAMMAR — `directive_v<version>_<class>_<noun>`:
18
+ * - `directive_v` is a RESERVED prefix; a hand-authored kind may never claim it.
19
+ * - `<class>` comes from a CLOSED vocabulary, so parsing is unambiguous even
20
+ * though nouns contain underscores: `directive_v1_reference_create_task` is
21
+ * `(reference, "create_task")`.
22
+ * - capability is DERIVED from the class, never stored twice.
23
+ */
24
+
25
+ /** The reserved slug prefix. ANY kind slug starting with this belongs to the Kind Directives protocol. */
26
+ declare const RESERVED_PREFIX: "directive_v";
27
+ /** Current directive grammar version. */
28
+ declare const DIRECTIVE_VERSION: 1;
29
+ /** The full prefix of a v1 directive slug. */
30
+ declare const SLUG_PREFIX: "directive_v1_";
31
+ /** The CLOSED class vocabulary. Closed is what makes the grammar parseable. */
32
+ declare const CLASSES: readonly ["reference", "view", "create", "update", "delete", "action", "validation", "secret"];
33
+ type DirectiveClass = (typeof CLASSES)[number];
34
+ type DirectiveCapability = "pure" | "sensitive" | "side_effect";
35
+ /** class → capability. DERIVED, never stored on a shape. */
36
+ declare const CAPABILITY_BY_CLASS: Readonly<Record<DirectiveClass, DirectiveCapability>>;
37
+ /** The classes that EXECUTE at an agent's output root — a durable side effect. */
38
+ declare const SIDE_EFFECT_CLASSES: ReadonlySet<DirectiveClass>;
39
+ /**
40
+ * The classes that resolve to a LIVE VALUE inside content. STRICT BY CHOICE,
41
+ * mirroring the server: exactly `reference` + `secret`.
42
+ */
43
+ declare const IN_CONTENT_CLASSES: ReadonlySet<DirectiveClass>;
44
+ /** A parsed directive slug. `slug` round-trips through `buildDirectiveSlug`. */
45
+ interface DirectiveSlug {
46
+ slug: string;
47
+ version: number;
48
+ directiveClass: DirectiveClass;
49
+ noun: string;
50
+ capability: DirectiveCapability;
51
+ /** Executes at an agent's output root (THE position law, half one). */
52
+ executes: boolean;
53
+ /** Resolves to a live value inside content (THE position law, half two). */
54
+ inContent: boolean;
55
+ }
56
+ declare function isDirectiveClass(value: unknown): value is DirectiveClass;
57
+ /**
58
+ * Whether `slug` sits in the reserved Kind Directives namespace. Deliberately
59
+ * broader than {@link parseDirectiveSlug}: a MALFORMED `directive_v…` slug is
60
+ * still reserved, so authoring gates reject it instead of letting a near-miss
61
+ * through as an ordinary kind.
62
+ */
63
+ declare function isReservedDirectiveSlug(slug: unknown): slug is string;
64
+ /**
65
+ * `("create", "task") → "directive_v1_create_task"`. THROWS on a class outside
66
+ * the closed vocabulary or an ill-formed noun — a slug that cannot be parsed
67
+ * back must never be mintable.
68
+ */
69
+ declare function buildDirectiveSlug(directiveClass: string, noun: string, version?: number): string;
70
+ /**
71
+ * Parse a directive slug, or `null` when `slug` is not one. A slug that IS in
72
+ * the reserved namespace but does not parse returns `null` too — pair with
73
+ * {@link isReservedDirectiveSlug} to tell "ordinary kind" from "malformed
74
+ * directive"; every such caller treats the malformed case as an ERROR.
75
+ */
76
+ declare function parseDirectiveSlug(slug: unknown): DirectiveSlug | null;
77
+ declare function capabilityOf(directiveClass: DirectiveClass): DirectiveCapability;
78
+ /** THE position law, half one: only a side-effect class executes at an agent's output root. */
79
+ declare function executesAtOutputRoot(directiveClass: string): boolean;
80
+ /** THE position law, half two: only a pointer or a sensitive value resolves to a live value inside content. */
81
+ declare function resolvesInContent(directiveClass: string): boolean;
82
+ /**
83
+ * The `__kind` of `obj` when it is in the reserved namespace, else null. Reads
84
+ * the RESERVED namespace, not the parsed grammar, so a malformed directive is
85
+ * still recognised as a directive (and rejected downstream with a real message).
86
+ */
87
+ declare function directiveSlugOf(obj: unknown): string | null;
88
+ /** THE detector — a dict whose `__kind` is in the reserved namespace. */
89
+ declare function isKindDirective(obj: unknown): boolean;
90
+ /**
91
+ * The two-key shell, as it travels on the wire. A TYPE alias, not an interface,
92
+ * so a shell is structurally assignable to `Record<string, unknown>`.
93
+ */
94
+ type KindDirectiveShell<Item = Record<string, unknown>> = {
95
+ /** The slug. Serialized FIRST — see the module doc. */
96
+ [KIND_KEY]: string;
97
+ items: Item[];
98
+ };
99
+ /**
100
+ * Build the two-key shell with `__kind` FIRST. Never hand-assemble the object
101
+ * literal elsewhere: JS preserves insertion order for string keys, and the
102
+ * first-key rule is what lets the streaming detector type a directive early.
103
+ */
104
+ declare function buildKindDirective<Item>(slug: string, items: Item[]): KindDirectiveShell<Item>;
105
+ /**
106
+ * Mid-stream recognition: the opening of a document whose FIRST key is a
107
+ * reserved directive slug, before the closing brace has arrived. Used by
108
+ * content splitters so a streaming envelope is typed early.
109
+ */
110
+ declare function looksLikeDirectiveHead(content: string): boolean;
111
+
112
+ /**
113
+ * Decode a Kind Directive — THE one entry point on every client.
114
+ *
115
+ * `decodeDirective()` recognises the shell (current OR, for stored content
116
+ * only, the retired 4-key one), reads the slug, and derives class + noun. A
117
+ * caller only ever sees a parsed {@link DecodedDirective}; nothing downstream
118
+ * inspects a raw shell again.
119
+ *
120
+ * ITEM VALIDATION IS THE SERVER'S. The registered item models live in aidream
121
+ * (`services/content_ir_directives/registry.py`) and validate on apply; a
122
+ * client-side copy of ~120 item models is exactly the drift the merge exists
123
+ * to kill. The client parses identity, routes, and renders. Mirror of aidream
124
+ * `services/content_ir_directives/decode.py`.
125
+ */
126
+
127
+ /**
128
+ * A well-formed-looking directive that cannot be honoured (a malformed slug, or
129
+ * a retired shell that does not map onto the grammar). Never thrown for "this
130
+ * isn't a directive" — that is `null`.
131
+ */
132
+ declare class DirectiveDecodeError extends Error {
133
+ constructor(message: string);
134
+ }
135
+ interface DecodedDirective {
136
+ /** The parsed slug — class, noun, capability and the position law. */
137
+ readonly parsed: DirectiveSlug;
138
+ readonly slug: string;
139
+ readonly directiveClass: DirectiveClass;
140
+ readonly noun: string;
141
+ readonly items: Record<string, unknown>[];
142
+ /** The two-key shell, normalised — what a confirm POST round-trips. */
143
+ readonly shell: Record<string, unknown>;
144
+ /** True when this arrived in the retired 4-key shell and was translated. */
145
+ readonly legacyShell: boolean;
146
+ }
147
+ /**
148
+ * A typed directive, or `null` when `value` is not a directive at all. Throws
149
+ * {@link DirectiveDecodeError} when it IS one but cannot be honoured.
150
+ */
151
+ declare function decodeDirective(value: unknown): DecodedDirective | null;
152
+ /**
153
+ * The forgiving read used at render seams: `decodeDirective`, but a directive
154
+ * that cannot be honoured comes back as `null` after the reason is handed to
155
+ * `onError`. A render seam must never take a whole message block down over one
156
+ * bad fence — but it must never swallow the reason either.
157
+ */
158
+ declare function tryDecodeDirective(value: unknown, onError?: (message: string) => void): DecodedDirective | null;
159
+ /** `decodeDirective` over a JSON string or an already-parsed value. Non-JSON text is `null`. */
160
+ declare function tryDecodeDirectiveContent(content: unknown, onError?: (message: string) => void): DecodedDirective | null;
161
+
162
+ /**
163
+ * THE ONE LEGACY SURFACE of the Kind Directives protocol — read-only.
164
+ *
165
+ * Stored content written before 2026-08-23 carries the retired 4-key shell
166
+ * (`matrx_version` / `kind` / `type` / `items`). This module translates it into
167
+ * the current two-key shell so `decodeDirective` sees one shape, forever. It
168
+ * never emits, never registers a shape, has no fallback branch, and every use
169
+ * is counted so the containment can be measured. Only `decode.ts` may import
170
+ * it (matrx-frontend's `check-legacy-shim-containment` and aidream's
171
+ * `test_legacy_shim_containment.py` enforce the mirror).
172
+ */
173
+ declare function legacyShellUses(): number;
174
+ declare function resetLegacyShellUses(): void;
175
+ /** True ONLY for a genuine retired-shell directive claim (sentinel + a retired kind token). */
176
+ declare function isLegacyShell(obj: unknown): boolean;
177
+
178
+ /**
179
+ * THE AUTO-VIEW's naming half: every enrolled noun "instantly has a view" —
180
+ * the prefix rule gives it a renderer, and this gives it a NAME. A shape the
181
+ * client has never heard of must still read as "Create Agent · Agents", never
182
+ * as the raw `agent` token and never as a slug.
183
+ *
184
+ * The catalog (`platform.entity_types` → the server's directive catalog) is the
185
+ * authority for `label` / `family` / `title_column`; a host that mirrors it
186
+ * passes a {@link DirectiveNounCatalog}. Without one — or for a noun the
187
+ * catalog does not carry (a Kind Action like `plan_tree`) — the name degrades
188
+ * to a title-cased token: legible, honestly derived, never blank.
189
+ */
190
+
191
+ interface DirectiveNounEntry {
192
+ /** The noun's human name — "Agent", "Plan tree". */
193
+ label?: string | null;
194
+ /** The catalog family ("Agents"). */
195
+ family?: string | null;
196
+ /** Which field of a row names it (`name`, `title`, …). */
197
+ titleColumn?: string | null;
198
+ }
199
+ /** A host-supplied lookup over the mirrored catalog. `undefined` = not carried. */
200
+ type DirectiveNounCatalog = (noun: string) => DirectiveNounEntry | undefined;
201
+ interface DirectiveDisplay {
202
+ /** The noun's human name — "Agent", "Plan tree". */
203
+ noun: string;
204
+ /** The catalog family ("Agents"), or "" when the catalog has none. */
205
+ family: string;
206
+ /** What this directive DOES, in the user's words — "Create", "Reference". */
207
+ action: string;
208
+ /** One line: "Create Agent". */
209
+ title: string;
210
+ }
211
+ /** `plan_node_patch` → `Plan node patch`. The honest last resort. */
212
+ declare function titleCaseToken(token: string): string;
213
+ /**
214
+ * How a class reads to a human. `action` is deliberately "Run": a Kind Action
215
+ * is a named procedure, and "Action Plan tree" reads like a noun phrase where a
216
+ * verb belongs. Mirrored by the server's kind-catalog label.
217
+ */
218
+ declare const ACTION_BY_CLASS: Readonly<Record<DirectiveClass, string>>;
219
+ declare function nounLabel(noun: string, catalog?: DirectiveNounCatalog): string;
220
+ declare function nounFamily(noun: string, catalog?: DirectiveNounCatalog): string;
221
+ declare function nounTitleColumn(noun: string, catalog?: DirectiveNounCatalog): string | null;
222
+ /** Everything a generic card needs to name a directive it cannot render. */
223
+ declare function directiveDisplay(directiveClass: DirectiveClass, noun: string, catalog?: DirectiveNounCatalog): DirectiveDisplay;
224
+
225
+ /**
226
+ * Naming and summarising ONE item of a directive, for the compact card.
227
+ *
228
+ * THE RULE: a user is never asked to approve a write they cannot identify. The
229
+ * card must say WHAT is about to be created/updated/deleted, derived from
230
+ * authority rather than guesswork, in this order:
231
+ * 1. the noun's catalog `title_column` — the server's own answer to "what
232
+ * names a row of this table";
233
+ * 2. the conventional identity fields, in a fixed order;
234
+ * 3. the honest last resort — "Item 2 of 3", never a blank chip and never a
235
+ * slug pretending to be a name.
236
+ *
237
+ * Facts are scalars ONLY. Nesting goes to the panel, never into the row.
238
+ */
239
+ /**
240
+ * What to call this item. `titleColumn` is the noun's catalog title column
241
+ * (consulted first); null when the catalog carries none.
242
+ */
243
+ declare function itemTitle(item: Record<string, unknown>, titleColumn: string | null, index: number, total: number): string;
244
+ /** A one-line subtitle when the item carries prose about itself. */
245
+ declare function itemSubtitle(item: Record<string, unknown>): string | null;
246
+ interface ItemFact {
247
+ key: string;
248
+ label: string;
249
+ value: string;
250
+ }
251
+ /**
252
+ * Up to `limit` scalar facts about the item — counts for collections, values
253
+ * for scalars. Nested objects are deliberately absent (they belong in the
254
+ * panel), and so is anything already carried by the title/subtitle.
255
+ */
256
+ declare function itemFacts(item: Record<string, unknown>, limit?: number): ItemFact[];
257
+
258
+ /**
259
+ * THE DIRECTIVE⇄KIND SEAM, client side.
260
+ *
261
+ * Arman, 2026-08-26: the envelope / Matrx-Actions system and the Shape (kind)
262
+ * system are ONE system with several methods inside it. They meet at the ITEM.
263
+ * A directive is a CONTAINER; its items are the payload, and when the server's
264
+ * item model is already a `KindModel`, that payload IS a registered kind
265
+ * instance — so the kind system already knows how to validate, render and copy
266
+ * it.
267
+ *
268
+ * The seam is SERVER-DERIVED (`ShapeSpec.item_kind`). Since 2026-09-08 the ONE
269
+ * kind endpoint publishes every directive shape as a KindDescriptor whose
270
+ * `items` EDGE names the item kind, so a client reads it from the same
271
+ * catalog it already holds — {@link directiveItemKindFromEdges}. A host that
272
+ * mirrors the directive catalog manifest instead passes its map as a
273
+ * {@link DirectiveItemKindLookup}. `null` is HONEST, never a gap-filler.
274
+ */
275
+ /** A host-supplied lookup: slug → the kind ONE item is, or null. */
276
+ type DirectiveItemKindLookup = (slug: string) => string | null;
277
+ /** The `items` edge of a directive KindDescriptor, as the kind catalog serves it. */
278
+ interface DirectiveItemsEdge {
279
+ field_name?: string;
280
+ fieldPath?: string;
281
+ child_kind?: string;
282
+ childKind?: string;
283
+ }
284
+ /** The item kind named by a directive descriptor's `items` edge, or null. */
285
+ declare function directiveItemKindFromEdges(edges: readonly DirectiveItemsEdge[] | null | undefined): string | null;
286
+ /**
287
+ * The item, presented the way the kind pipeline expects it: `__kind` FIRST so a
288
+ * consumer types the object from its own first key. `__kind` is ADDED, never
289
+ * overwritten: an item that already carries its marker keeps the value it was
290
+ * emitted with. Null when no kind is known — the caller owns the generic floor.
291
+ */
292
+ declare function asKindInstance(item: Record<string, unknown>, kind: string | null): Record<string, unknown> | null;
293
+
294
+ export { ACTION_BY_CLASS, CAPABILITY_BY_CLASS, CLASSES, DIRECTIVE_VERSION, type DecodedDirective, type DirectiveCapability, type DirectiveClass, DirectiveDecodeError, type DirectiveDisplay, type DirectiveItemKindLookup, type DirectiveItemsEdge, type DirectiveNounCatalog, type DirectiveNounEntry, type DirectiveSlug, IN_CONTENT_CLASSES, type ItemFact, KIND_KEY, type KindDirectiveShell, RESERVED_PREFIX, SIDE_EFFECT_CLASSES, SLUG_PREFIX, asKindInstance, buildDirectiveSlug, buildKindDirective, capabilityOf, decodeDirective, directiveDisplay, directiveItemKindFromEdges, directiveSlugOf, executesAtOutputRoot, isDirectiveClass, isKindDirective, isLegacyShell, isReservedDirectiveSlug, itemFacts, itemSubtitle, itemTitle, legacyShellUses, looksLikeDirectiveHead, nounFamily, nounLabel, nounTitleColumn, parseDirectiveSlug, resetLegacyShellUses, resolvesInContent, titleCaseToken, tryDecodeDirective, tryDecodeDirectiveContent };
@@ -0,0 +1,294 @@
1
+ import { K as KIND_KEY } from './kind-schema.types-CwncWj9U.js';
2
+
3
+ /**
4
+ * Kind Directives — the grammar, the shell, and the position law (kernel edition).
5
+ *
6
+ * ONE system (Arman, 2026-08-23): the Matrx Envelope/Directive protocol and the
7
+ * Content IR kind system are one system. A directive is an ordinary kind
8
+ * instance — `{ "__kind": "directive_v1_<class>_<noun>", "items": [...] }` —
9
+ * whose registered shape additionally carries execution semantics on the
10
+ * server. This module is the PURE half, ported verbatim from the aidream source
11
+ * of record (`packages/matrx-graph/matrx_graph/content_ir/directives.py`) so
12
+ * every UI parses the grammar identically. It lives in the KERNEL because a
13
+ * host that can parse a kind must be able to recognise a directive without a
14
+ * second copy of these rules (matrx-frontend carried the only copy until
15
+ * 2026-09-08; Workflow Studio had none and rendered directives as raw text).
16
+ *
17
+ * THE SLUG GRAMMAR — `directive_v<version>_<class>_<noun>`:
18
+ * - `directive_v` is a RESERVED prefix; a hand-authored kind may never claim it.
19
+ * - `<class>` comes from a CLOSED vocabulary, so parsing is unambiguous even
20
+ * though nouns contain underscores: `directive_v1_reference_create_task` is
21
+ * `(reference, "create_task")`.
22
+ * - capability is DERIVED from the class, never stored twice.
23
+ */
24
+
25
+ /** The reserved slug prefix. ANY kind slug starting with this belongs to the Kind Directives protocol. */
26
+ declare const RESERVED_PREFIX: "directive_v";
27
+ /** Current directive grammar version. */
28
+ declare const DIRECTIVE_VERSION: 1;
29
+ /** The full prefix of a v1 directive slug. */
30
+ declare const SLUG_PREFIX: "directive_v1_";
31
+ /** The CLOSED class vocabulary. Closed is what makes the grammar parseable. */
32
+ declare const CLASSES: readonly ["reference", "view", "create", "update", "delete", "action", "validation", "secret"];
33
+ type DirectiveClass = (typeof CLASSES)[number];
34
+ type DirectiveCapability = "pure" | "sensitive" | "side_effect";
35
+ /** class → capability. DERIVED, never stored on a shape. */
36
+ declare const CAPABILITY_BY_CLASS: Readonly<Record<DirectiveClass, DirectiveCapability>>;
37
+ /** The classes that EXECUTE at an agent's output root — a durable side effect. */
38
+ declare const SIDE_EFFECT_CLASSES: ReadonlySet<DirectiveClass>;
39
+ /**
40
+ * The classes that resolve to a LIVE VALUE inside content. STRICT BY CHOICE,
41
+ * mirroring the server: exactly `reference` + `secret`.
42
+ */
43
+ declare const IN_CONTENT_CLASSES: ReadonlySet<DirectiveClass>;
44
+ /** A parsed directive slug. `slug` round-trips through `buildDirectiveSlug`. */
45
+ interface DirectiveSlug {
46
+ slug: string;
47
+ version: number;
48
+ directiveClass: DirectiveClass;
49
+ noun: string;
50
+ capability: DirectiveCapability;
51
+ /** Executes at an agent's output root (THE position law, half one). */
52
+ executes: boolean;
53
+ /** Resolves to a live value inside content (THE position law, half two). */
54
+ inContent: boolean;
55
+ }
56
+ declare function isDirectiveClass(value: unknown): value is DirectiveClass;
57
+ /**
58
+ * Whether `slug` sits in the reserved Kind Directives namespace. Deliberately
59
+ * broader than {@link parseDirectiveSlug}: a MALFORMED `directive_v…` slug is
60
+ * still reserved, so authoring gates reject it instead of letting a near-miss
61
+ * through as an ordinary kind.
62
+ */
63
+ declare function isReservedDirectiveSlug(slug: unknown): slug is string;
64
+ /**
65
+ * `("create", "task") → "directive_v1_create_task"`. THROWS on a class outside
66
+ * the closed vocabulary or an ill-formed noun — a slug that cannot be parsed
67
+ * back must never be mintable.
68
+ */
69
+ declare function buildDirectiveSlug(directiveClass: string, noun: string, version?: number): string;
70
+ /**
71
+ * Parse a directive slug, or `null` when `slug` is not one. A slug that IS in
72
+ * the reserved namespace but does not parse returns `null` too — pair with
73
+ * {@link isReservedDirectiveSlug} to tell "ordinary kind" from "malformed
74
+ * directive"; every such caller treats the malformed case as an ERROR.
75
+ */
76
+ declare function parseDirectiveSlug(slug: unknown): DirectiveSlug | null;
77
+ declare function capabilityOf(directiveClass: DirectiveClass): DirectiveCapability;
78
+ /** THE position law, half one: only a side-effect class executes at an agent's output root. */
79
+ declare function executesAtOutputRoot(directiveClass: string): boolean;
80
+ /** THE position law, half two: only a pointer or a sensitive value resolves to a live value inside content. */
81
+ declare function resolvesInContent(directiveClass: string): boolean;
82
+ /**
83
+ * The `__kind` of `obj` when it is in the reserved namespace, else null. Reads
84
+ * the RESERVED namespace, not the parsed grammar, so a malformed directive is
85
+ * still recognised as a directive (and rejected downstream with a real message).
86
+ */
87
+ declare function directiveSlugOf(obj: unknown): string | null;
88
+ /** THE detector — a dict whose `__kind` is in the reserved namespace. */
89
+ declare function isKindDirective(obj: unknown): boolean;
90
+ /**
91
+ * The two-key shell, as it travels on the wire. A TYPE alias, not an interface,
92
+ * so a shell is structurally assignable to `Record<string, unknown>`.
93
+ */
94
+ type KindDirectiveShell<Item = Record<string, unknown>> = {
95
+ /** The slug. Serialized FIRST — see the module doc. */
96
+ [KIND_KEY]: string;
97
+ items: Item[];
98
+ };
99
+ /**
100
+ * Build the two-key shell with `__kind` FIRST. Never hand-assemble the object
101
+ * literal elsewhere: JS preserves insertion order for string keys, and the
102
+ * first-key rule is what lets the streaming detector type a directive early.
103
+ */
104
+ declare function buildKindDirective<Item>(slug: string, items: Item[]): KindDirectiveShell<Item>;
105
+ /**
106
+ * Mid-stream recognition: the opening of a document whose FIRST key is a
107
+ * reserved directive slug, before the closing brace has arrived. Used by
108
+ * content splitters so a streaming envelope is typed early.
109
+ */
110
+ declare function looksLikeDirectiveHead(content: string): boolean;
111
+
112
+ /**
113
+ * Decode a Kind Directive — THE one entry point on every client.
114
+ *
115
+ * `decodeDirective()` recognises the shell (current OR, for stored content
116
+ * only, the retired 4-key one), reads the slug, and derives class + noun. A
117
+ * caller only ever sees a parsed {@link DecodedDirective}; nothing downstream
118
+ * inspects a raw shell again.
119
+ *
120
+ * ITEM VALIDATION IS THE SERVER'S. The registered item models live in aidream
121
+ * (`services/content_ir_directives/registry.py`) and validate on apply; a
122
+ * client-side copy of ~120 item models is exactly the drift the merge exists
123
+ * to kill. The client parses identity, routes, and renders. Mirror of aidream
124
+ * `services/content_ir_directives/decode.py`.
125
+ */
126
+
127
+ /**
128
+ * A well-formed-looking directive that cannot be honoured (a malformed slug, or
129
+ * a retired shell that does not map onto the grammar). Never thrown for "this
130
+ * isn't a directive" — that is `null`.
131
+ */
132
+ declare class DirectiveDecodeError extends Error {
133
+ constructor(message: string);
134
+ }
135
+ interface DecodedDirective {
136
+ /** The parsed slug — class, noun, capability and the position law. */
137
+ readonly parsed: DirectiveSlug;
138
+ readonly slug: string;
139
+ readonly directiveClass: DirectiveClass;
140
+ readonly noun: string;
141
+ readonly items: Record<string, unknown>[];
142
+ /** The two-key shell, normalised — what a confirm POST round-trips. */
143
+ readonly shell: Record<string, unknown>;
144
+ /** True when this arrived in the retired 4-key shell and was translated. */
145
+ readonly legacyShell: boolean;
146
+ }
147
+ /**
148
+ * A typed directive, or `null` when `value` is not a directive at all. Throws
149
+ * {@link DirectiveDecodeError} when it IS one but cannot be honoured.
150
+ */
151
+ declare function decodeDirective(value: unknown): DecodedDirective | null;
152
+ /**
153
+ * The forgiving read used at render seams: `decodeDirective`, but a directive
154
+ * that cannot be honoured comes back as `null` after the reason is handed to
155
+ * `onError`. A render seam must never take a whole message block down over one
156
+ * bad fence — but it must never swallow the reason either.
157
+ */
158
+ declare function tryDecodeDirective(value: unknown, onError?: (message: string) => void): DecodedDirective | null;
159
+ /** `decodeDirective` over a JSON string or an already-parsed value. Non-JSON text is `null`. */
160
+ declare function tryDecodeDirectiveContent(content: unknown, onError?: (message: string) => void): DecodedDirective | null;
161
+
162
+ /**
163
+ * THE ONE LEGACY SURFACE of the Kind Directives protocol — read-only.
164
+ *
165
+ * Stored content written before 2026-08-23 carries the retired 4-key shell
166
+ * (`matrx_version` / `kind` / `type` / `items`). This module translates it into
167
+ * the current two-key shell so `decodeDirective` sees one shape, forever. It
168
+ * never emits, never registers a shape, has no fallback branch, and every use
169
+ * is counted so the containment can be measured. Only `decode.ts` may import
170
+ * it (matrx-frontend's `check-legacy-shim-containment` and aidream's
171
+ * `test_legacy_shim_containment.py` enforce the mirror).
172
+ */
173
+ declare function legacyShellUses(): number;
174
+ declare function resetLegacyShellUses(): void;
175
+ /** True ONLY for a genuine retired-shell directive claim (sentinel + a retired kind token). */
176
+ declare function isLegacyShell(obj: unknown): boolean;
177
+
178
+ /**
179
+ * THE AUTO-VIEW's naming half: every enrolled noun "instantly has a view" —
180
+ * the prefix rule gives it a renderer, and this gives it a NAME. A shape the
181
+ * client has never heard of must still read as "Create Agent · Agents", never
182
+ * as the raw `agent` token and never as a slug.
183
+ *
184
+ * The catalog (`platform.entity_types` → the server's directive catalog) is the
185
+ * authority for `label` / `family` / `title_column`; a host that mirrors it
186
+ * passes a {@link DirectiveNounCatalog}. Without one — or for a noun the
187
+ * catalog does not carry (a Kind Action like `plan_tree`) — the name degrades
188
+ * to a title-cased token: legible, honestly derived, never blank.
189
+ */
190
+
191
+ interface DirectiveNounEntry {
192
+ /** The noun's human name — "Agent", "Plan tree". */
193
+ label?: string | null;
194
+ /** The catalog family ("Agents"). */
195
+ family?: string | null;
196
+ /** Which field of a row names it (`name`, `title`, …). */
197
+ titleColumn?: string | null;
198
+ }
199
+ /** A host-supplied lookup over the mirrored catalog. `undefined` = not carried. */
200
+ type DirectiveNounCatalog = (noun: string) => DirectiveNounEntry | undefined;
201
+ interface DirectiveDisplay {
202
+ /** The noun's human name — "Agent", "Plan tree". */
203
+ noun: string;
204
+ /** The catalog family ("Agents"), or "" when the catalog has none. */
205
+ family: string;
206
+ /** What this directive DOES, in the user's words — "Create", "Reference". */
207
+ action: string;
208
+ /** One line: "Create Agent". */
209
+ title: string;
210
+ }
211
+ /** `plan_node_patch` → `Plan node patch`. The honest last resort. */
212
+ declare function titleCaseToken(token: string): string;
213
+ /**
214
+ * How a class reads to a human. `action` is deliberately "Run": a Kind Action
215
+ * is a named procedure, and "Action Plan tree" reads like a noun phrase where a
216
+ * verb belongs. Mirrored by the server's kind-catalog label.
217
+ */
218
+ declare const ACTION_BY_CLASS: Readonly<Record<DirectiveClass, string>>;
219
+ declare function nounLabel(noun: string, catalog?: DirectiveNounCatalog): string;
220
+ declare function nounFamily(noun: string, catalog?: DirectiveNounCatalog): string;
221
+ declare function nounTitleColumn(noun: string, catalog?: DirectiveNounCatalog): string | null;
222
+ /** Everything a generic card needs to name a directive it cannot render. */
223
+ declare function directiveDisplay(directiveClass: DirectiveClass, noun: string, catalog?: DirectiveNounCatalog): DirectiveDisplay;
224
+
225
+ /**
226
+ * Naming and summarising ONE item of a directive, for the compact card.
227
+ *
228
+ * THE RULE: a user is never asked to approve a write they cannot identify. The
229
+ * card must say WHAT is about to be created/updated/deleted, derived from
230
+ * authority rather than guesswork, in this order:
231
+ * 1. the noun's catalog `title_column` — the server's own answer to "what
232
+ * names a row of this table";
233
+ * 2. the conventional identity fields, in a fixed order;
234
+ * 3. the honest last resort — "Item 2 of 3", never a blank chip and never a
235
+ * slug pretending to be a name.
236
+ *
237
+ * Facts are scalars ONLY. Nesting goes to the panel, never into the row.
238
+ */
239
+ /**
240
+ * What to call this item. `titleColumn` is the noun's catalog title column
241
+ * (consulted first); null when the catalog carries none.
242
+ */
243
+ declare function itemTitle(item: Record<string, unknown>, titleColumn: string | null, index: number, total: number): string;
244
+ /** A one-line subtitle when the item carries prose about itself. */
245
+ declare function itemSubtitle(item: Record<string, unknown>): string | null;
246
+ interface ItemFact {
247
+ key: string;
248
+ label: string;
249
+ value: string;
250
+ }
251
+ /**
252
+ * Up to `limit` scalar facts about the item — counts for collections, values
253
+ * for scalars. Nested objects are deliberately absent (they belong in the
254
+ * panel), and so is anything already carried by the title/subtitle.
255
+ */
256
+ declare function itemFacts(item: Record<string, unknown>, limit?: number): ItemFact[];
257
+
258
+ /**
259
+ * THE DIRECTIVE⇄KIND SEAM, client side.
260
+ *
261
+ * Arman, 2026-08-26: the envelope / Matrx-Actions system and the Shape (kind)
262
+ * system are ONE system with several methods inside it. They meet at the ITEM.
263
+ * A directive is a CONTAINER; its items are the payload, and when the server's
264
+ * item model is already a `KindModel`, that payload IS a registered kind
265
+ * instance — so the kind system already knows how to validate, render and copy
266
+ * it.
267
+ *
268
+ * The seam is SERVER-DERIVED (`ShapeSpec.item_kind`). Since 2026-09-08 the ONE
269
+ * kind endpoint publishes every directive shape as a KindDescriptor whose
270
+ * `items` EDGE names the item kind, so a client reads it from the same
271
+ * catalog it already holds — {@link directiveItemKindFromEdges}. A host that
272
+ * mirrors the directive catalog manifest instead passes its map as a
273
+ * {@link DirectiveItemKindLookup}. `null` is HONEST, never a gap-filler.
274
+ */
275
+ /** A host-supplied lookup: slug → the kind ONE item is, or null. */
276
+ type DirectiveItemKindLookup = (slug: string) => string | null;
277
+ /** The `items` edge of a directive KindDescriptor, as the kind catalog serves it. */
278
+ interface DirectiveItemsEdge {
279
+ field_name?: string;
280
+ fieldPath?: string;
281
+ child_kind?: string;
282
+ childKind?: string;
283
+ }
284
+ /** The item kind named by a directive descriptor's `items` edge, or null. */
285
+ declare function directiveItemKindFromEdges(edges: readonly DirectiveItemsEdge[] | null | undefined): string | null;
286
+ /**
287
+ * The item, presented the way the kind pipeline expects it: `__kind` FIRST so a
288
+ * consumer types the object from its own first key. `__kind` is ADDED, never
289
+ * overwritten: an item that already carries its marker keeps the value it was
290
+ * emitted with. Null when no kind is known — the caller owns the generic floor.
291
+ */
292
+ declare function asKindInstance(item: Record<string, unknown>, kind: string | null): Record<string, unknown> | null;
293
+
294
+ export { ACTION_BY_CLASS, CAPABILITY_BY_CLASS, CLASSES, DIRECTIVE_VERSION, type DecodedDirective, type DirectiveCapability, type DirectiveClass, DirectiveDecodeError, type DirectiveDisplay, type DirectiveItemKindLookup, type DirectiveItemsEdge, type DirectiveNounCatalog, type DirectiveNounEntry, type DirectiveSlug, IN_CONTENT_CLASSES, type ItemFact, KIND_KEY, type KindDirectiveShell, RESERVED_PREFIX, SIDE_EFFECT_CLASSES, SLUG_PREFIX, asKindInstance, buildDirectiveSlug, buildKindDirective, capabilityOf, decodeDirective, directiveDisplay, directiveItemKindFromEdges, directiveSlugOf, executesAtOutputRoot, isDirectiveClass, isKindDirective, isLegacyShell, isReservedDirectiveSlug, itemFacts, itemSubtitle, itemTitle, legacyShellUses, looksLikeDirectiveHead, nounFamily, nounLabel, nounTitleColumn, parseDirectiveSlug, resetLegacyShellUses, resolvesInContent, titleCaseToken, tryDecodeDirective, tryDecodeDirectiveContent };