@dtmd/temper 0.0.7 → 0.0.9

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 (44) hide show
  1. package/README.md +84 -53
  2. package/bin/temper.js +0 -0
  3. package/dist/src/assembly.d.ts +15 -1
  4. package/dist/src/assembly.js +2 -1
  5. package/dist/src/builtins.d.ts +682 -66
  6. package/dist/src/builtins.js +664 -92
  7. package/dist/src/claude-code.d.ts +2 -2
  8. package/dist/src/claude-code.js +1 -1
  9. package/dist/src/contract.d.ts +180 -29
  10. package/dist/src/contract.js +128 -15
  11. package/dist/src/declarations.d.ts +72 -5
  12. package/dist/src/declarations.js +389 -107
  13. package/dist/src/dial.d.ts +75 -0
  14. package/dist/src/dial.js +82 -0
  15. package/dist/src/emit.d.ts +35 -1
  16. package/dist/src/emit.js +369 -63
  17. package/dist/src/generated/AssemblyFactRow.d.ts +2 -2
  18. package/dist/src/generated/BoundRow.d.ts +2 -2
  19. package/dist/src/generated/ClauseRow.d.ts +73 -3
  20. package/dist/src/generated/CollectionAddressRow.d.ts +4 -0
  21. package/dist/src/generated/EmbeddedMember.d.ts +3 -3
  22. package/dist/src/generated/FeatureValue.d.ts +2 -2
  23. package/dist/src/generated/Features.d.ts +52 -3
  24. package/dist/src/generated/KindFactRow.d.ts +24 -7
  25. package/dist/src/generated/MentionRow.d.ts +5 -3
  26. package/dist/src/generated/NestedMemberRow.d.ts +32 -0
  27. package/dist/src/generated/PayloadMember.d.ts +6 -0
  28. package/dist/src/generated/RequirementRow.d.ts +4 -2
  29. package/dist/src/generated/SatisfiesRow.d.ts +2 -1
  30. package/dist/src/generated/Shape.d.ts +15 -0
  31. package/dist/src/generated/Shape.js +2 -0
  32. package/dist/src/generated/TemplateRow.d.ts +24 -0
  33. package/dist/src/generated/TemplateRow.js +2 -0
  34. package/dist/src/generated/ValueType.d.ts +11 -2
  35. package/dist/src/generated/Verifier.d.ts +20 -0
  36. package/dist/src/generated/Verifier.js +2 -0
  37. package/dist/src/generated/index.d.ts +3 -0
  38. package/dist/src/index.d.ts +8 -8
  39. package/dist/src/index.js +3 -3
  40. package/dist/src/kind.d.ts +135 -29
  41. package/dist/src/kind.js +35 -8
  42. package/dist/src/prose.d.ts +81 -25
  43. package/dist/src/prose.js +91 -21
  44. package/package.json +4 -4
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Kinds — the engine room. A kind is a plain typed surface — an interface
3
- * `T` and a constructor `kind<T>()` — plus six facts of runtime residue: label,
4
- * locus, layout, registration, edge fields, and content. A registration kind (a hook,
3
+ * `T` and a constructor `kind<T>()` — plus seven facts of runtime residue: label,
4
+ * locus, projection, registration, edge fields, content, and template. A registration kind (a hook,
5
5
  * an MCP server) extends the content fact with a fields-only `shape` and a
6
6
  * `collectionAddress` naming the host manifest it surfaces in. `tsc` is the keystroke
7
7
  * wall; every type erases at the seam, and what a kind leaves behind rides the lock as
@@ -11,15 +11,25 @@
11
11
  import type { Prose, Text } from "./prose.js";
12
12
  import type { Capability } from "./needs.js";
13
13
  import type { Requirement } from "./contract.js";
14
- /** The shape of the on-disk artifact a member projects to (fact 3, layout). */
15
- export type Format = "yaml-frontmatter";
14
+ /**
15
+ * The shape of the on-disk artifact a member projects to (fact 3, projection) — a closed
16
+ * vocabulary the engine implements once per entry, and the fact deciding which adapter
17
+ * reads a file kind's artifact. `"json-document"` is a whole artifact that is one JSON
18
+ * object: its top-level keys the member's fields, its identity a declared key among them.
19
+ * `"toml-document"` is that read over TOML, and a **read face only** — nothing projects a
20
+ * member declaring it, so it serves a document temper reads in place and never writes.
21
+ */
22
+ export type Format = "yaml-frontmatter" | "json-document" | "toml-document";
16
23
  /**
17
24
  * Whether a member is a lone file (identity from the stem), a directory with an
18
- * entry file (identity from the directory name), or a lone file whose identity is
19
- * read from a declared frontmatter field (`identityField`) instead of derived from
20
- * the path (an agent's `name`).
25
+ * entry file (identity from the directory name), a lone file whose identity is
26
+ * read from a declared field (`identityField`) instead of derived from the path (an
27
+ * agent's `name`) — on whichever surface the kind's `format` carries its fields — or a
28
+ * lone file keyed by the directory segment its single-`*` segment glob stars
29
+ * (`"starred-segment"`), coexisting inside another kind's directory rather than owning
30
+ * one. The identity source is this spelled fact, never inferred from the glob.
21
31
  */
22
- export type UnitShape = "file" | "directory" | "named-field";
32
+ export type UnitShape = "file" | "directory" | "named-field" | "starred-segment";
23
33
  /**
24
34
  * One **channel** a kind's registration declares — a documented way a member
25
35
  * reaches the world (fact 4, `builtins.md`, "The shipped kinds": "user
@@ -42,25 +52,57 @@ export type Registration = {
42
52
  readonly field: string;
43
53
  } | {
44
54
  readonly via: "connection";
55
+ } | {
56
+ readonly via: "enablement";
57
+ readonly field: string;
58
+ } | {
59
+ readonly via: "registry";
45
60
  };
46
61
  /** One of a kind's fields that is a reference to another member — a graph edge (fact 5). */
47
62
  export interface EdgeField {
48
63
  readonly field: string;
49
- /** The target kind's name — the far end of the edge. */
50
- readonly to: string;
64
+ /**
65
+ * The far end of the edge: the non-empty **set** of kinds the field may target.
66
+ * A one-element set resolves a bare address within its one kind; a multi-element
67
+ * set demands the kind-qualified `kind:name` address always, since resolution
68
+ * reads the written text and never infers from the member population. The
69
+ * non-emptiness is the type's to hold — an edge declaring no target kind can
70
+ * never resolve.
71
+ */
72
+ readonly to: readonly [string, ...string[]];
51
73
  }
52
74
  /**
53
- * A kind's **locus** (fact 2): members live at path globs (`at`) or as typed
54
- * fenced blocks inside host documents (`embedded`). An `at` locus is split root +
55
- * glob so the kind fact row carries `governs_root`/`governs_glob` directly.
75
+ * A kind's **locus** (fact 2), in three spellings: members live at path globs (`at`),
76
+ * as typed fenced blocks inside host documents (`embedded`), or as `nested-file`
77
+ * children owning a file whose path composes from their host member's unit and the host
78
+ * kind's template pattern. An `at` locus is split root + glob so the kind fact row
79
+ * carries `governs_root`/`governs_glob` directly; a `nested-file` kind declares neither
80
+ * — the pattern is the host {@link Template}'s one home, so a child can never collide
81
+ * with its host's own governs glob. An `embedded` locus names no host: which types may
82
+ * compose a kind's body is the adopting corpus's `admit` declaration over the host kind
83
+ * (`assembly.ts`), so one embedded type means the same thing in every body that admits
84
+ * it. A `nested-file` child names its host per member ({@link MemberInit}'s `host`) —
85
+ * the unit its path composes under.
86
+ *
87
+ * An `at` locus may declare a `commitment` class of `local`: per-machine and
88
+ * uncommitted — the kind is declared and reviewed, its members' documents are not. The
89
+ * class is a *file* locus's own fact, which is why only `at` spells it. A local locus is
90
+ * read-side only (the document is the governed source, read at check in place under
91
+ * whatever format the kind declares, and never an `emit` input or target), and its
92
+ * members' rows never enter the lock —
93
+ * they derive at read time under the kind the lock declares. Absent is the other class
94
+ * and the default: committed, where the kind and its members' documents are reviewed
95
+ * together and `emit` owns the bytes.
56
96
  */
57
97
  export type Locus = {
58
98
  readonly kind: "at";
59
99
  readonly root: string;
60
100
  readonly glob: string;
101
+ readonly commitment?: "local";
61
102
  } | {
62
103
  readonly kind: "embedded";
63
- readonly withinHosts: readonly string[];
104
+ } | {
105
+ readonly kind: "nested-file";
64
106
  };
65
107
  /**
66
108
  * One region of a kind's **layout** — one of the three corpus primitives over the
@@ -98,24 +140,47 @@ export type Shape = "fields";
98
140
  /**
99
141
  * A registration member's **collection address** — where inside a host manifest its
100
142
  * registration surfaces: which `manifest` (`settings.json`, `.mcp.json`) and which
101
- * `keyPath` (`hooks.<Event>`, `mcpServers.*`) it keys at. Carried by a fields-only
102
- * registration kind; absent for a kind that owns its own file locus.
143
+ * `keyPath` it keys at — one of the four addresses the shipped kinds surface at.
144
+ * Carried by a fields-only registration kind; absent for a kind that owns its own file
145
+ * locus.
103
146
  */
104
147
  export interface CollectionAddress {
105
148
  readonly manifest: string;
106
- readonly keyPath: "hooks.<Event>" | "mcpServers.*";
149
+ readonly keyPath: "hooks.<Event>" | "mcpServers.*" | "enabledPlugins.*" | "extraKnownMarketplaces.*";
150
+ readonly entryShape: string;
151
+ }
152
+ /**
153
+ * A kind's **template** for one inner layer of nested members it hosts (fact 7): the
154
+ * child `kind`, plus the `path` pattern its children sit at — relative to the parent's
155
+ * own unit — when they are files (a skill's bundled reference documents at `*.md`).
156
+ * Omit `path` for an embedded layer, whose children live in the host's body and own no
157
+ * unit of their own.
158
+ *
159
+ * The declaration is the kind's own nesting fact, and a declared fact only: nothing
160
+ * discovers a file child off the pattern, exactly as a host's embedded members resolve
161
+ * off `nested_members` by address rather than off its templates. An adopting corpus may
162
+ * override the child kind by admitting its own over the host (`declarations.ts`'s
163
+ * `templatesFor`).
164
+ */
165
+ export interface Template {
166
+ /** The child kind this layer templates — a kind value, since identity travels by import. */
167
+ readonly kind: KindDefinition<any>;
168
+ /** Where a file child's unit sits, relative to the parent's unit; absent for an embedded layer. */
169
+ readonly path?: string;
107
170
  }
108
- /** The six facts of a kind's runtime residue. */
171
+ /** The seven facts of a kind's runtime residue. */
109
172
  export interface KindFacts {
110
173
  /** Fact 1, label — the compiled debug label findings speak; the kind's name. */
111
174
  readonly name: string;
112
175
  /** The declared provider authority, when the kind qualifies by one. */
113
176
  readonly provider?: string;
114
- /** Fact 2, locus — where members live. */
177
+ /** Fact 2, locus — where members live, and for a file locus whether their documents
178
+ * are committed: a `local` commitment class declares the kind reviewed and its
179
+ * members' documents not. */
115
180
  readonly locus: Locus;
116
- /** Fact 3a, layout — the projection format; omitted for a frontmatterless kind. */
181
+ /** Fact 3a, projection — the artifact format; omitted for a kind that declares none. */
117
182
  readonly format?: Format;
118
- /** Fact 3b, layout — the on-disk unit shape. */
183
+ /** Fact 3b, projection — the on-disk unit shape. */
119
184
  readonly unitShape: UnitShape;
120
185
  /** Fact 4, registration — the declared channel set naming every documented way
121
186
  * the world reaches a member (never rivals — a member is live if any one is). */
@@ -126,7 +191,9 @@ export interface KindFacts {
126
191
  * identity is read from (an agent's `name`), never the filename or directory.
127
192
  * For `"directory"` it is a projection-order detail only (a skill's `name`
128
193
  * still writes into frontmatter, but identity is the directory name); absent
129
- * when identity is the file stem and no field carries it (a rule).
194
+ * when identity is the file stem and no field carries it (a rule), or the
195
+ * starred directory segment (`"starred-segment"`) — both path-derived, never a
196
+ * field.
130
197
  */
131
198
  readonly identityField?: string;
132
199
  /** Fact 5, edge fields — the kind's fields that are references to other members. */
@@ -140,6 +207,9 @@ export interface KindFacts {
140
207
  /** The registration member's {@link CollectionAddress} — which manifest and key path
141
208
  * its registration surfaces at; absent for a kind that owns its own file locus. */
142
209
  readonly collectionAddress?: CollectionAddress;
210
+ /** Fact 7, template — one {@link Template} per inner layer of nested members the kind
211
+ * hosts; absent for a kind that nests nothing. */
212
+ readonly templates?: readonly Template[];
143
213
  }
144
214
  /**
145
215
  * One authored member — a typed value in the library. Kind identity travels by
@@ -150,10 +220,12 @@ export interface KindFacts {
150
220
  export interface Member {
151
221
  /** The kind's name — its declaration-row and lock identity. */
152
222
  readonly kind: string;
153
- /** The kind's six facts — carried for projection and the declaration rows. */
223
+ /** The kind's seven facts — carried for projection and the declaration rows. */
154
224
  readonly facts: KindFacts;
155
225
  /** Identity within the kind. */
156
226
  readonly name: string;
227
+ /** The host member a nested-file child's path composes under; absent at every other locus. */
228
+ readonly host?: Member;
157
229
  /** The member's words. */
158
230
  readonly prose?: Prose;
159
231
  /** The kind's typed fields, flat and ordered — the projected frontmatter. */
@@ -168,13 +240,15 @@ export interface Member {
168
240
  /** The init a kind constructor takes — the framework keys plus the kind's typed fields `T`. */
169
241
  export type MemberInit<T> = {
170
242
  readonly name: string;
243
+ /** The host member this member's unit composes under — a nested-file child's, and only its. */
244
+ readonly host?: Member;
171
245
  readonly prose?: Prose;
172
246
  readonly satisfies?: readonly string[];
173
247
  readonly requires?: Readonly<Record<string, Requirement>>;
174
248
  readonly needs?: readonly Capability[];
175
249
  } & T;
176
250
  /**
177
- * A kind — a callable constructor carrying its six facts. Calling it builds a
251
+ * A kind — a callable constructor carrying its seven facts. Calling it builds a
178
252
  * member; `key` (its name) keys `expect` and a `kind` reference in a requirement.
179
253
  * The value *is* the identity — it travels by import, never by string.
180
254
  */
@@ -193,14 +267,14 @@ export interface KindDefinition<T> {
193
267
  */
194
268
  readonly render?: (value: ResolvedEmbeddedMemberValue) => string;
195
269
  }
196
- /** The options `kind()` takes beyond its six facts — today, only the embedded `render` hook. */
270
+ /** The options `kind()` takes beyond its seven facts — today, only the embedded `render` hook. */
197
271
  export interface KindOptions {
198
272
  readonly render?: (value: ResolvedEmbeddedMemberValue) => string;
199
273
  }
200
274
  /**
201
275
  * Define a kind. Returns a constructor over the kind's typed
202
276
  * fields `T`; every type erases at the seam, so what the returned member carries
203
- * into emit is the six facts plus flat field data. `options.render`, when given,
277
+ * into emit is the seven facts plus flat field data. `options.render`, when given,
204
278
  * rides alongside `facts`/`key` on the returned constructor — never on the member
205
279
  * it builds, since it is erased before a member reaches emit.
206
280
  */
@@ -220,7 +294,7 @@ export interface EmbeddedMemberCollectionEntry {
220
294
  readonly leaves: Readonly<Record<string, string | Text>>;
221
295
  }
222
296
  /**
223
- * An **embedded member's** composed value (posture 3, passed to `blocks()`):
297
+ * An **embedded member's** composed value — one child of a composed body, passed to `blocks()`:
224
298
  * leaves are authored strings keyed by field name; sibling collections are keyed
225
299
  * by collection name, each an authored-order list of entries — leaf addresses
226
300
  * are structural and keyed. Its
@@ -244,6 +318,12 @@ export interface EmbeddedMemberValue {
244
318
  readonly collections: Readonly<Record<string, readonly EmbeddedMemberCollectionEntry[]>>;
245
319
  /** The originating kind's `render` hook, when declared — resolved once at construction. */
246
320
  readonly render?: (value: ResolvedEmbeddedMemberValue) => string;
321
+ /**
322
+ * The originating kind's declared edge fields — which of the value's leaves are
323
+ * addresses, and the target facts emit derives from them. Resolved once at
324
+ * construction, the way `render` is.
325
+ */
326
+ readonly edgeFields?: readonly EdgeField[];
247
327
  }
248
328
  /**
249
329
  * One resolved sibling-collection entry: its own key plus its leaf fields,
@@ -255,6 +335,23 @@ export interface ResolvedEmbeddedMemberCollectionEntry {
255
335
  /** The entry's own leaf fields, already resolved to their final strings. */
256
336
  readonly leaves: Readonly<Record<string, string>>;
257
337
  }
338
+ /**
339
+ * The closed set of facts an embedded format may place about one edge field's
340
+ * target — derived at emit off the resolved target member, never authored at the
341
+ * instance and never fabricated, so a rendered reference is true by construction.
342
+ * The set is exactly these four; a fifth fact is a spec question, not a
343
+ * convenience.
344
+ */
345
+ export interface EdgeTargetFacts {
346
+ /** The target member's identity within its kind. */
347
+ readonly name: string;
348
+ /** The target's `kind:name` address — what the edge field's leaf authored. */
349
+ readonly address: string;
350
+ /** The target member's kind. */
351
+ readonly kind: string;
352
+ /** The target's projection, relative to the host member's own projection. */
353
+ readonly path: string;
354
+ }
258
355
  /**
259
356
  * An {@link EmbeddedMemberValue} after every leaf (top-level and each
260
357
  * collection entry's) resolves to its final stored string
@@ -270,12 +367,21 @@ export interface ResolvedEmbeddedMemberValue {
270
367
  readonly leaves: Readonly<Record<string, string>>;
271
368
  /** Sibling collections, each entry's leaves already resolved. */
272
369
  readonly collections: Readonly<Record<string, readonly ResolvedEmbeddedMemberCollectionEntry[]>>;
370
+ /**
371
+ * The target facts of each edge field this value *fills*, keyed by the edge field's
372
+ * own name — the data a `render` hook selects to spell a reference. An unfilled
373
+ * field is no edge and carries no entry; a kind declaring no edge fields (or a value
374
+ * composed off a bare kind name, which carries none) has an empty map.
375
+ */
376
+ readonly targets: Readonly<Record<string, EdgeTargetFacts>>;
273
377
  }
274
378
  /**
275
379
  * Compose an embedded member's value for `blocks()` — the shape any project's own
276
380
  * child kind uses. `kind` names the child kind: a bare string, or the child kind's
277
- * own `KindDefinition` — passing the definition carries its `render` hook (when
278
- * declared) through to emit, with no other change to the composed value's shape.
381
+ * own `KindDefinition` — passing the definition carries its `render` hook and its
382
+ * declared edge fields (when declared) through to emit, with no other change to the
383
+ * composed value's shape. A bare string names a kind whose facts are out of reach, so
384
+ * such a value renders with no target facts.
279
385
  */
280
386
  export declare function embeddedMemberValue(init: {
281
387
  kind: string | KindDefinition<any>;
package/dist/src/kind.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Kinds — the engine room. A kind is a plain typed surface — an interface
3
- * `T` and a constructor `kind<T>()` — plus six facts of runtime residue: label,
4
- * locus, layout, registration, edge fields, and content. A registration kind (a hook,
3
+ * `T` and a constructor `kind<T>()` — plus seven facts of runtime residue: label,
4
+ * locus, projection, registration, edge fields, content, and template. A registration kind (a hook,
5
5
  * an MCP server) extends the content fact with a fields-only `shape` and a
6
6
  * `collectionAddress` naming the host manifest it surfaces in. `tsc` is the keystroke
7
7
  * wall; every type erases at the seam, and what a kind leaves behind rides the lock as
@@ -9,7 +9,7 @@
9
9
  * value.
10
10
  */
11
11
  /** The framework keys of a member init — everything else is a typed field (flat). */
12
- const FRAMEWORK_KEYS = new Set(["name", "prose", "satisfies", "requires", "needs"]);
12
+ const FRAMEWORK_KEYS = new Set(["name", "host", "prose", "satisfies", "requires", "needs"]);
13
13
  /**
14
14
  * Build the ordered projected fields for a member: nothing for a frontmatterless
15
15
  * body-bearing kind (memory declares no `format` and is not fields-only), else the
@@ -29,10 +29,31 @@ function orderedFields(facts, init) {
29
29
  const head = facts.identityField !== undefined ? [[facts.identityField, init.name]] : [];
30
30
  return [...head, ...typed];
31
31
  }
32
+ /**
33
+ * The host a member init names, checked against its kind's locus: a nested-file child's
34
+ * path composes from its host's unit, so it names one and every other locus names none.
35
+ *
36
+ * # Throws
37
+ * If a nested-file member declares no host, or a member at any other locus declares one.
38
+ */
39
+ function hostOf(facts, init) {
40
+ const nested = facts.locus.kind === "nested-file";
41
+ if (nested && init.host === undefined) {
42
+ throw new Error(`member \`${init.name}\` of kind \`${facts.name}\`: a nested file child owns a file whose ` +
43
+ `path composes from its host's unit, so it names the \`host\` member it sits under ` +
44
+ `(specs/model/representation.md, "locus").`);
45
+ }
46
+ if (!nested && init.host !== undefined) {
47
+ throw new Error(`member \`${init.name}\` of kind \`${facts.name}\`: \`host\` names the member a nested ` +
48
+ `file child composes its path under, and this kind's locus is \`${facts.locus.kind}\` — ` +
49
+ `its path composes from nobody.`);
50
+ }
51
+ return init.host;
52
+ }
32
53
  /**
33
54
  * Define a kind. Returns a constructor over the kind's typed
34
55
  * fields `T`; every type erases at the seam, so what the returned member carries
35
- * into emit is the six facts plus flat field data. `options.render`, when given,
56
+ * into emit is the seven facts plus flat field data. `options.render`, when given,
36
57
  * rides alongside `facts`/`key` on the returned constructor — never on the member
37
58
  * it builds, since it is erased before a member reaches emit.
38
59
  */
@@ -41,6 +62,7 @@ export function kind(facts, options = {}) {
41
62
  kind: facts.name,
42
63
  facts,
43
64
  name: init.name,
65
+ host: hostOf(facts, init),
44
66
  prose: init.prose,
45
67
  fields: orderedFields(facts, init),
46
68
  satisfies: init.satisfies ?? [],
@@ -52,16 +74,21 @@ export function kind(facts, options = {}) {
52
74
  /**
53
75
  * Compose an embedded member's value for `blocks()` — the shape any project's own
54
76
  * child kind uses. `kind` names the child kind: a bare string, or the child kind's
55
- * own `KindDefinition` — passing the definition carries its `render` hook (when
56
- * declared) through to emit, with no other change to the composed value's shape.
77
+ * own `KindDefinition` — passing the definition carries its `render` hook and its
78
+ * declared edge fields (when declared) through to emit, with no other change to the
79
+ * composed value's shape. A bare string names a kind whose facts are out of reach, so
80
+ * such a value renders with no target facts.
57
81
  */
58
82
  export function embeddedMemberValue(init) {
59
- const [kindName, render] = typeof init.kind === "string" ? [init.kind, undefined] : [init.kind.key, init.kind.render];
83
+ const definition = typeof init.kind === "string" ? undefined : init.kind;
84
+ const render = definition?.render;
85
+ const edgeFields = definition?.facts.edgeFields;
60
86
  return {
61
- kind: kindName,
87
+ kind: definition?.key ?? init.kind,
62
88
  key: init.key,
63
89
  leaves: init.leaves,
64
90
  collections: init.collections ?? {},
65
91
  ...(render !== undefined ? { render } : {}),
92
+ ...(edgeFields !== undefined ? { edgeFields } : {}),
66
93
  };
67
94
  }
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Prose — three constructors, one field type. A member's words are data the
3
3
  * member declares: `file()` for a document that keeps its medium, `` text`…` ``
4
- * for short inline prose, `blocks()` for fully composed embedded-member values. Whatever
5
- * the constructor, the words land byte-identical to their authored text (law 5).
4
+ * for short inline prose, `blocks()` for a composed body that interleaves verbatim
5
+ * prose spans with embedded-member values in authored order. Whatever
6
+ * the constructor, the words land byte-identical to their authored text.
6
7
  * Interpolations in `` text`…` `` are references, two intents apart: a **mention**
7
8
  * (a {@link Mentionable}) is a declared one-way edge that moves no content, and an
8
9
  * **include** (an {@link Include}) pulls the target file's bytes into the host's emitted
9
- * projection. Both are authored per word and resolution-checked at emit, never mined
10
- * (law 8).
10
+ * projection. Both are authored per word and resolution-checked at emit, never mined.
11
11
  */
12
- import type { EmbeddedMemberValue } from "./kind.js";
12
+ import type { EmbeddedMemberValue, Member } from "./kind.js";
13
13
  /** A declared value a mention may name — the target of the one-way citation edge. */
14
14
  export interface Mentionable {
15
15
  /** The mention's rendered form and graph edge target (`kind:name` or a leaf address). */
@@ -17,6 +17,12 @@ export interface Mentionable {
17
17
  /** The display text the one corpus-wide rule renders in place. */
18
18
  readonly display: string;
19
19
  }
20
+ /**
21
+ * Spell a top-level member as the {@link Mentionable} a mention carries: its
22
+ * `kind:name` address, its bare name the display text — the convention every
23
+ * corpus repeats to cite a member from prose, captured once here.
24
+ */
25
+ export declare function mentionOf(member: Member): Mentionable;
20
26
  /** One authored interpolation: position in the template plus its target. */
21
27
  export interface Mention {
22
28
  readonly index: number;
@@ -37,11 +43,42 @@ export interface Include {
37
43
  }
38
44
  /** A `` text`…` `` interpolation — a mention (moves no content) or an include (moves content). */
39
45
  export type Reference = Mentionable | Include;
46
+ /**
47
+ * The resolution universe a mention is checked against at emit: the addresses that
48
+ * resolve here and now ({@link mentionable}), and the kinds whose members the program
49
+ * declares but does not compose ({@link deferrableKinds}) — a mention naming one of
50
+ * those defers to `check` rather than refusing at emit.
51
+ */
52
+ export interface MentionScope {
53
+ /** Every address a mention may resolve against in the program's own universe. */
54
+ readonly mentionable: ReadonlySet<string>;
55
+ /** The discoverable (`at`-locus) kinds the program declares — the deferral signal. */
56
+ readonly deferrableKinds: ReadonlySet<string>;
57
+ }
58
+ /**
59
+ * Whether a mention's unresolved address **defers to the gate** rather than refusing at
60
+ * emit: a top-level `kind:name` address whose kind is one the program declares at a
61
+ * discovery locus (an `at`-locus kind) may name a member discovered on disk, so `check`
62
+ * owns the verdict. An embedded leaf address (a `<host>/<kind>/<key>` form, carrying a
63
+ * `/`), a bare requirement name (no `:`), or a kind the program does not declare has no
64
+ * discovery locus and stays a dangling refusal.
65
+ */
66
+ export declare function defersToGate(address: string, deferrableKinds: ReadonlySet<string>): boolean;
67
+ /**
68
+ * Refuse a mention whose address neither resolves against the scope's `mentionable`
69
+ * set nor defers to the gate ({@link defersToGate}) — the one dangling-mention refusal,
70
+ * shared by a member-level `Text` body, a composed body's prose span, and an embedded
71
+ * `Text` leaf. `context` prefixes the error so it names the host.
72
+ *
73
+ * # Throws
74
+ * If a mention names no declared value and its address has no discovery locus.
75
+ */
76
+ export declare function checkMentions(mentions: readonly Mention[], scope: MentionScope, context: string): void;
40
77
  /**
41
78
  * `file(moduleUrl, path)` — the document keeps its medium: markdown in a
42
- * markdown file, full tooling, forever legal (posture 1, `15-kinds.md`).
43
- * Resolved and read in byte-for-byte at emit, relative to the declaring
44
- * module, never the process cwd.
79
+ * markdown file, full tooling, forever legal. Resolved and read in
80
+ * byte-for-byte at emit, relative to the declaring module, never the
81
+ * process cwd.
45
82
  */
46
83
  export interface File {
47
84
  readonly kind: "file";
@@ -53,7 +90,7 @@ export interface File {
53
90
  /**
54
91
  * `` text`…` `` — short prose inline, dedented, byte-deterministic; the
55
92
  * three-line rule that would be silly as a sidecar file. Mentions ride beside
56
- * the text, never inside it (law 5).
93
+ * the text, never inside it.
57
94
  */
58
95
  export interface Text {
59
96
  readonly kind: "text";
@@ -67,20 +104,23 @@ export interface Text {
67
104
  readonly includes: readonly Include[];
68
105
  }
69
106
  /**
70
- * `blocks(…)` — fully composed embedded-member values (posture 3): typed
71
- * collections rendered to `member.<kind> <key>` TOML fences, byte-identical to
72
- * the same values authored as fences directly (posture 2) and read back by the
107
+ * `blocks(…)` — a composed body of ordered children: verbatim prose spans
108
+ * ({@link Text}) and embedded-member values interleaved in authored order,
109
+ * the write-side mirror of a layout's ordered regions. A {@link Text} span stays
110
+ * prose — it carries its own mentions and includes and mints no wrapper member;
111
+ * an embedded value renders to its `member.<kind> <key>` TOML fence, byte-identical
112
+ * to the same value authored as a fence directly and read back by the
73
113
  * engine's fold (`src/extract.rs` `parse_embedded_info`/`parse_embedded_member`).
74
114
  */
75
115
  export interface Blocks {
76
116
  readonly kind: "blocks";
77
- readonly values: readonly EmbeddedMemberValue[];
117
+ readonly values: readonly (Text | EmbeddedMemberValue)[];
78
118
  }
79
119
  /** A member's prose — one of the three constructors, one field type. */
80
120
  export type Prose = File | Text | Blocks;
81
121
  /**
82
- * Declare a document whose medium is preserved — read in whole at emit
83
- * (posture 1). `moduleUrl` is the declaring module's own `import.meta.url`,
122
+ * Declare a document whose medium is preserved — read in whole at emit.
123
+ * `moduleUrl` is the declaring module's own `import.meta.url`,
84
124
  * so `path` resolves relative to that module, never the process cwd:
85
125
  * `file(import.meta.url, "./long.md")`.
86
126
  */
@@ -89,7 +129,7 @@ export declare function file(moduleUrl: string, path: string): File;
89
129
  * The inline dedenting prose constructor. Interpolate {@link Reference} values — a
90
130
  * {@link Mentionable} is a mention (moves no content), an {@link Include} pulls the
91
131
  * target's bytes in; either is opt-in per word, and plain prose with zero references is
92
- * fully legal forever (the opt-in Decision, `20-surface.md`).
132
+ * fully legal forever.
93
133
  *
94
134
  * # Throws
95
135
  * If an authored chunk carries {@link MENTION_SLOT} or {@link INCLUDE_SLOT} — the markers
@@ -103,23 +143,39 @@ export declare function text(strings: TemplateStringsArray, ...targets: Referenc
103
143
  * `include(import.meta.url, "./fragment.md")`.
104
144
  */
105
145
  export declare function include(moduleUrl: string, path: string): Include;
106
- /** Compose fully-typed embedded-member values into a member's body (posture 3). */
107
- export declare function blocks(...values: EmbeddedMemberValue[]): Blocks;
146
+ /**
147
+ * Compose a member's body from ordered children: verbatim prose spans
148
+ * ({@link text}) and embedded-member values interleaved in authored order. A prose
149
+ * span rides as prose — no wrapper member is minted to carry a narrative.
150
+ *
151
+ * # Throws
152
+ * If a child is a {@link File} — the parameter type excludes one, so only a JS or
153
+ * cast caller arrives here, and the alternative is a raw crash downstream on the
154
+ * `leaves` a `File` has no reason to carry.
155
+ */
156
+ export declare function blocks(...values: (Text | EmbeddedMemberValue)[]): Blocks;
157
+ /**
158
+ * Whether a composed-body child is a verbatim prose span rather than an embedded
159
+ * member value — the discriminant emit and the row builders branch on to render a
160
+ * span as prose and count its refs at host level, never as a nested member.
161
+ */
162
+ export declare function isTextSpan(value: Text | EmbeddedMemberValue): value is Text;
108
163
  /**
109
164
  * Render an inline body to its final text — the display rule applied: each
110
165
  * mention slot becomes its target's display form, the surrounding words
111
- * untouched (law 5). The chunk count is `mentions.length + 1` by {@link text}'s
166
+ * untouched. The chunk count is `mentions.length + 1` by {@link text}'s
112
167
  * construction, so the walk consumes every slot.
113
168
  */
114
169
  export declare function renderText(prose: Text): string;
115
170
  /**
116
171
  * Resolve a leaf's authored value to its stored/rendered string: a bare string
117
- * is unchanged; a `Text` leaf is mention-resolution-checked against
118
- * `mentionable` (loud on a dangling address) and rendered by {@link renderText}
119
- * — the same rule a member-level `Text` body resolves by. `context` prefixes
120
- * the dangling-mention error so it names the leaf, not just the mention.
172
+ * is unchanged; a `Text` leaf is mention-resolution-checked against `scope`
173
+ * ({@link checkMentions}: loud on a dangling address, a discovery-locus one
174
+ * deferred) and rendered by {@link renderText} — the same rule a member-level
175
+ * `Text` body resolves by. `context` prefixes the dangling-mention error so it
176
+ * names the leaf, not just the mention.
121
177
  *
122
178
  * # Throws
123
- * If a mention names no declared value.
179
+ * If a mention names no declared value and has no discovery locus.
124
180
  */
125
- export declare function resolveLeaf(value: string | Text, mentionable: ReadonlySet<string>, context: string): string;
181
+ export declare function resolveLeaf(value: string | Text, scope: MentionScope, context: string): string;