@dtmd/temper 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -53
- package/bin/temper.js +52 -0
- package/dist/src/assembly.d.ts +15 -1
- package/dist/src/assembly.js +2 -1
- package/dist/src/builtins.d.ts +765 -48
- package/dist/src/builtins.js +767 -68
- package/dist/src/claude-code.d.ts +2 -2
- package/dist/src/claude-code.js +1 -1
- package/dist/src/contract.d.ts +180 -29
- package/dist/src/contract.js +128 -15
- package/dist/src/declarations.d.ts +92 -6
- package/dist/src/declarations.js +448 -102
- package/dist/src/dial.d.ts +75 -0
- package/dist/src/dial.js +82 -0
- package/dist/src/emit.d.ts +82 -1
- package/dist/src/emit.js +402 -56
- package/dist/src/generated/AssemblyFactRow.d.ts +2 -2
- package/dist/src/generated/BoundRow.d.ts +2 -2
- package/dist/src/generated/ClauseRow.d.ts +73 -3
- package/dist/src/generated/CollectionAddressRow.d.ts +21 -0
- package/dist/src/generated/CollectionAddressRow.js +2 -0
- package/dist/src/generated/Declarations.d.ts +17 -0
- package/dist/src/generated/EmbeddedMember.d.ts +3 -3
- package/dist/src/generated/FeatureValue.d.ts +2 -2
- package/dist/src/generated/Features.d.ts +52 -3
- package/dist/src/generated/KindFactRow.d.ts +38 -7
- package/dist/src/generated/MentionRow.d.ts +5 -3
- package/dist/src/generated/NestedMemberRow.d.ts +32 -0
- package/dist/src/generated/PayloadMember.d.ts +6 -0
- package/dist/src/generated/RegistrationRow.d.ts +35 -0
- package/dist/src/generated/RegistrationRow.js +2 -0
- package/dist/src/generated/RequirementRow.d.ts +4 -2
- package/dist/src/generated/SatisfiesRow.d.ts +2 -1
- package/dist/src/generated/SettingsRow.d.ts +25 -0
- package/dist/src/generated/SettingsRow.js +2 -0
- package/dist/src/generated/Shape.d.ts +15 -0
- package/dist/src/generated/Shape.js +2 -0
- package/dist/src/generated/TemplateRow.d.ts +24 -0
- package/dist/src/generated/TemplateRow.js +2 -0
- package/dist/src/generated/ValueType.d.ts +11 -2
- package/dist/src/generated/Verifier.d.ts +20 -0
- package/dist/src/generated/Verifier.js +2 -0
- package/dist/src/generated/index.d.ts +6 -0
- package/dist/src/index.d.ts +8 -8
- package/dist/src/index.js +3 -3
- package/dist/src/kind.d.ts +160 -29
- package/dist/src/kind.js +47 -16
- package/dist/src/prose.d.ts +81 -25
- package/dist/src/prose.js +91 -21
- package/package.json +10 -2
package/dist/src/index.d.ts
CHANGED
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
* `memory` kinds — lives at the `./claude-code` subpath, never here.
|
|
14
14
|
*/
|
|
15
15
|
export type { Blocks, File, Include, Mention, Mentionable, Prose, Reference, Text } from "./prose.js";
|
|
16
|
-
export { blocks, file, include, renderText, text } from "./prose.js";
|
|
16
|
+
export { blocks, file, include, mentionOf, renderText, text } from "./prose.js";
|
|
17
17
|
export type { Capability } from "./needs.js";
|
|
18
18
|
export { bash, capability, permissionUnion } from "./needs.js";
|
|
19
|
-
export type { Charset, Clause, Predicate, Requirement, Severity } from "./contract.js";
|
|
20
|
-
export { allowedChars, clause, count, degree, deny, enumOf, forbiddenKeys,
|
|
21
|
-
export type { EdgeField, EmbeddedMemberCollectionEntry, EmbeddedMemberValue, Format, KindDefinition, KindFacts, Layout, LayoutRegion, Locus, Member, MemberInit, Registration, UnitShape, } from "./kind.js";
|
|
19
|
+
export type { Charset, Clause, ExtentUnit, Predicate, Requirement, Severity, Verifier } from "./contract.js";
|
|
20
|
+
export { allowedChars, clause, closedKeys, count, degree, deny, enumOf, extent, forbiddenKeys, formatPlacesEdges, globValid, maxLen, membership, mentionReachable, minLen, mustDefine, nameMatchesDir, optional, range, required, requireSections, requirement, script, sectionContains, shape, telemetry, type, unique, uniqueName, when, } from "./contract.js";
|
|
21
|
+
export type { CollectionAddress, EdgeField, EdgeTargetFacts, EmbeddedMemberCollectionEntry, EmbeddedMemberValue, Format, KindDefinition, KindFacts, KindOptions, Layout, LayoutRegion, Locus, Member, MemberInit, Registration, ResolvedEmbeddedMemberCollectionEntry, ResolvedEmbeddedMemberValue, Shape, Template, UnitShape, } from "./kind.js";
|
|
22
22
|
export { embeddedMemberValue, kind } from "./kind.js";
|
|
23
|
-
export type { EnforcementMode, ExpectBinding, Harness } from "./assembly.js";
|
|
23
|
+
export type { Admission, EnforcementMode, ExpectBinding, Harness } from "./assembly.js";
|
|
24
24
|
export { harness } from "./assembly.js";
|
|
25
|
-
export type {
|
|
26
|
-
export { SEAM_VERSION, compileDeclarations } from "./declarations.js";
|
|
27
|
-
export type { EmitResult, PayloadMember, ResolveOptions } from "./emit.js";
|
|
25
|
+
export type { EmitResult, RegistrationFact, ResolveOptions, SettingsResidue } from "./emit.js";
|
|
28
26
|
export { emit } from "./emit.js";
|
|
27
|
+
export type { Dial, DialEntry } from "./dial.js";
|
|
28
|
+
export { dial, dialDefaultContract } from "./dial.js";
|
package/dist/src/index.js
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* The first-party Claude Code provider face — the built-in `skill`/`rule`/
|
|
13
13
|
* `memory` kinds — lives at the `./claude-code` subpath, never here.
|
|
14
14
|
*/
|
|
15
|
-
export { blocks, file, include, renderText, text } from "./prose.js";
|
|
15
|
+
export { blocks, file, include, mentionOf, renderText, text } from "./prose.js";
|
|
16
16
|
export { bash, capability, permissionUnion } from "./needs.js";
|
|
17
|
-
export { allowedChars, clause, count, degree, deny, enumOf, forbiddenKeys,
|
|
17
|
+
export { allowedChars, clause, closedKeys, count, degree, deny, enumOf, extent, forbiddenKeys, formatPlacesEdges, globValid, maxLen, membership, mentionReachable, minLen, mustDefine, nameMatchesDir, optional, range, required, requireSections, requirement, script, sectionContains, shape, telemetry, type, unique, uniqueName, when, } from "./contract.js";
|
|
18
18
|
export { embeddedMemberValue, kind } from "./kind.js";
|
|
19
19
|
export { harness } from "./assembly.js";
|
|
20
|
-
export { SEAM_VERSION, compileDeclarations } from "./declarations.js";
|
|
21
20
|
export { emit } from "./emit.js";
|
|
21
|
+
export { dial, dialDefaultContract } from "./dial.js";
|
package/dist/src/kind.d.ts
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
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
|
|
4
|
-
* locus,
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
+
* an MCP server) extends the content fact with a fields-only `shape` and a
|
|
6
|
+
* `collectionAddress` naming the host manifest it surfaces in. `tsc` is the keystroke
|
|
7
|
+
* wall; every type erases at the seam, and what a kind leaves behind rides the lock as
|
|
8
|
+
* rows. Identity travels by import, never by string — a `kind` reference is the imported
|
|
9
|
+
* value.
|
|
8
10
|
*/
|
|
9
11
|
import type { Prose, Text } from "./prose.js";
|
|
10
12
|
import type { Capability } from "./needs.js";
|
|
11
13
|
import type { Requirement } from "./contract.js";
|
|
12
|
-
/**
|
|
13
|
-
|
|
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";
|
|
14
23
|
/**
|
|
15
24
|
* Whether a member is a lone file (identity from the stem), a directory with an
|
|
16
|
-
* entry file (identity from the directory name),
|
|
17
|
-
* read from a declared
|
|
18
|
-
*
|
|
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.
|
|
19
31
|
*/
|
|
20
|
-
export type UnitShape = "file" | "directory" | "named-field";
|
|
32
|
+
export type UnitShape = "file" | "directory" | "named-field" | "starred-segment";
|
|
21
33
|
/**
|
|
22
34
|
* One **channel** a kind's registration declares — a documented way a member
|
|
23
35
|
* reaches the world (fact 4, `builtins.md`, "The shipped kinds": "user
|
|
@@ -40,25 +52,57 @@ export type Registration = {
|
|
|
40
52
|
readonly field: string;
|
|
41
53
|
} | {
|
|
42
54
|
readonly via: "connection";
|
|
55
|
+
} | {
|
|
56
|
+
readonly via: "enablement";
|
|
57
|
+
readonly field: string;
|
|
58
|
+
} | {
|
|
59
|
+
readonly via: "registry";
|
|
43
60
|
};
|
|
44
61
|
/** One of a kind's fields that is a reference to another member — a graph edge (fact 5). */
|
|
45
62
|
export interface EdgeField {
|
|
46
63
|
readonly field: string;
|
|
47
|
-
/**
|
|
48
|
-
|
|
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[]];
|
|
49
73
|
}
|
|
50
74
|
/**
|
|
51
|
-
* A kind's **locus** (fact 2): members live at path globs (`at`)
|
|
52
|
-
* fenced blocks inside host documents (`embedded`)
|
|
53
|
-
*
|
|
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.
|
|
54
96
|
*/
|
|
55
97
|
export type Locus = {
|
|
56
98
|
readonly kind: "at";
|
|
57
99
|
readonly root: string;
|
|
58
100
|
readonly glob: string;
|
|
101
|
+
readonly commitment?: "local";
|
|
59
102
|
} | {
|
|
60
103
|
readonly kind: "embedded";
|
|
61
|
-
|
|
104
|
+
} | {
|
|
105
|
+
readonly kind: "nested-file";
|
|
62
106
|
};
|
|
63
107
|
/**
|
|
64
108
|
* One region of a kind's **layout** — one of the three corpus primitives over the
|
|
@@ -86,17 +130,57 @@ export type LayoutRegion = {
|
|
|
86
130
|
export interface Layout {
|
|
87
131
|
readonly regions: readonly LayoutRegion[];
|
|
88
132
|
}
|
|
89
|
-
/**
|
|
133
|
+
/**
|
|
134
|
+
* A kind's **body shape** marker — `"fields"` for a fields-only kind: no body slot at
|
|
135
|
+
* all, the member its typed fields and edges and nothing more (a hook, an MCP server).
|
|
136
|
+
* Absent leaves the kind body-bearing, its body `file` (the default) or a declared
|
|
137
|
+
* {@link Layout}.
|
|
138
|
+
*/
|
|
139
|
+
export type Shape = "fields";
|
|
140
|
+
/**
|
|
141
|
+
* A registration member's **collection address** — where inside a host manifest its
|
|
142
|
+
* registration surfaces: which `manifest` (`settings.json`, `.mcp.json`) and which
|
|
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.
|
|
146
|
+
*/
|
|
147
|
+
export interface CollectionAddress {
|
|
148
|
+
readonly manifest: string;
|
|
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;
|
|
170
|
+
}
|
|
171
|
+
/** The seven facts of a kind's runtime residue. */
|
|
90
172
|
export interface KindFacts {
|
|
91
173
|
/** Fact 1, label — the compiled debug label findings speak; the kind's name. */
|
|
92
174
|
readonly name: string;
|
|
93
175
|
/** The declared provider authority, when the kind qualifies by one. */
|
|
94
176
|
readonly provider?: string;
|
|
95
|
-
/** 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. */
|
|
96
180
|
readonly locus: Locus;
|
|
97
|
-
/** Fact 3a,
|
|
181
|
+
/** Fact 3a, projection — the artifact format; omitted for a kind that declares none. */
|
|
98
182
|
readonly format?: Format;
|
|
99
|
-
/** Fact 3b,
|
|
183
|
+
/** Fact 3b, projection — the on-disk unit shape. */
|
|
100
184
|
readonly unitShape: UnitShape;
|
|
101
185
|
/** Fact 4, registration — the declared channel set naming every documented way
|
|
102
186
|
* the world reaches a member (never rivals — a member is live if any one is). */
|
|
@@ -107,7 +191,9 @@ export interface KindFacts {
|
|
|
107
191
|
* identity is read from (an agent's `name`), never the filename or directory.
|
|
108
192
|
* For `"directory"` it is a projection-order detail only (a skill's `name`
|
|
109
193
|
* still writes into frontmatter, but identity is the directory name); absent
|
|
110
|
-
* 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.
|
|
111
197
|
*/
|
|
112
198
|
readonly identityField?: string;
|
|
113
199
|
/** Fact 5, edge fields — the kind's fields that are references to other members. */
|
|
@@ -115,6 +201,15 @@ export interface KindFacts {
|
|
|
115
201
|
/** Fact 6, content — a declared {@link Layout} over the body's heading tree; absent
|
|
116
202
|
* leaves the kind `file`-content (one verbatim prose body, the default). */
|
|
117
203
|
readonly content?: Layout;
|
|
204
|
+
/** Fact 6b, content — the fields-only body shape (`"fields"`, no body slot); absent
|
|
205
|
+
* leaves the kind body-bearing (`file` or a {@link Layout}). */
|
|
206
|
+
readonly shape?: Shape;
|
|
207
|
+
/** The registration member's {@link CollectionAddress} — which manifest and key path
|
|
208
|
+
* its registration surfaces at; absent for a kind that owns its own file locus. */
|
|
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[];
|
|
118
213
|
}
|
|
119
214
|
/**
|
|
120
215
|
* One authored member — a typed value in the library. Kind identity travels by
|
|
@@ -125,10 +220,12 @@ export interface KindFacts {
|
|
|
125
220
|
export interface Member {
|
|
126
221
|
/** The kind's name — its declaration-row and lock identity. */
|
|
127
222
|
readonly kind: string;
|
|
128
|
-
/** The kind's
|
|
223
|
+
/** The kind's seven facts — carried for projection and the declaration rows. */
|
|
129
224
|
readonly facts: KindFacts;
|
|
130
225
|
/** Identity within the kind. */
|
|
131
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;
|
|
132
229
|
/** The member's words. */
|
|
133
230
|
readonly prose?: Prose;
|
|
134
231
|
/** The kind's typed fields, flat and ordered — the projected frontmatter. */
|
|
@@ -143,13 +240,15 @@ export interface Member {
|
|
|
143
240
|
/** The init a kind constructor takes — the framework keys plus the kind's typed fields `T`. */
|
|
144
241
|
export type MemberInit<T> = {
|
|
145
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;
|
|
146
245
|
readonly prose?: Prose;
|
|
147
246
|
readonly satisfies?: readonly string[];
|
|
148
247
|
readonly requires?: Readonly<Record<string, Requirement>>;
|
|
149
248
|
readonly needs?: readonly Capability[];
|
|
150
249
|
} & T;
|
|
151
250
|
/**
|
|
152
|
-
* A kind — a callable constructor carrying its
|
|
251
|
+
* A kind — a callable constructor carrying its seven facts. Calling it builds a
|
|
153
252
|
* member; `key` (its name) keys `expect` and a `kind` reference in a requirement.
|
|
154
253
|
* The value *is* the identity — it travels by import, never by string.
|
|
155
254
|
*/
|
|
@@ -168,14 +267,14 @@ export interface KindDefinition<T> {
|
|
|
168
267
|
*/
|
|
169
268
|
readonly render?: (value: ResolvedEmbeddedMemberValue) => string;
|
|
170
269
|
}
|
|
171
|
-
/** The options `kind()` takes beyond its
|
|
270
|
+
/** The options `kind()` takes beyond its seven facts — today, only the embedded `render` hook. */
|
|
172
271
|
export interface KindOptions {
|
|
173
272
|
readonly render?: (value: ResolvedEmbeddedMemberValue) => string;
|
|
174
273
|
}
|
|
175
274
|
/**
|
|
176
275
|
* Define a kind. Returns a constructor over the kind's typed
|
|
177
276
|
* fields `T`; every type erases at the seam, so what the returned member carries
|
|
178
|
-
* into emit is the
|
|
277
|
+
* into emit is the seven facts plus flat field data. `options.render`, when given,
|
|
179
278
|
* rides alongside `facts`/`key` on the returned constructor — never on the member
|
|
180
279
|
* it builds, since it is erased before a member reaches emit.
|
|
181
280
|
*/
|
|
@@ -195,7 +294,7 @@ export interface EmbeddedMemberCollectionEntry {
|
|
|
195
294
|
readonly leaves: Readonly<Record<string, string | Text>>;
|
|
196
295
|
}
|
|
197
296
|
/**
|
|
198
|
-
* An **embedded member's** composed value
|
|
297
|
+
* An **embedded member's** composed value — one child of a composed body, passed to `blocks()`:
|
|
199
298
|
* leaves are authored strings keyed by field name; sibling collections are keyed
|
|
200
299
|
* by collection name, each an authored-order list of entries — leaf addresses
|
|
201
300
|
* are structural and keyed. Its
|
|
@@ -219,6 +318,12 @@ export interface EmbeddedMemberValue {
|
|
|
219
318
|
readonly collections: Readonly<Record<string, readonly EmbeddedMemberCollectionEntry[]>>;
|
|
220
319
|
/** The originating kind's `render` hook, when declared — resolved once at construction. */
|
|
221
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[];
|
|
222
327
|
}
|
|
223
328
|
/**
|
|
224
329
|
* One resolved sibling-collection entry: its own key plus its leaf fields,
|
|
@@ -230,6 +335,23 @@ export interface ResolvedEmbeddedMemberCollectionEntry {
|
|
|
230
335
|
/** The entry's own leaf fields, already resolved to their final strings. */
|
|
231
336
|
readonly leaves: Readonly<Record<string, string>>;
|
|
232
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
|
+
}
|
|
233
355
|
/**
|
|
234
356
|
* An {@link EmbeddedMemberValue} after every leaf (top-level and each
|
|
235
357
|
* collection entry's) resolves to its final stored string
|
|
@@ -245,12 +367,21 @@ export interface ResolvedEmbeddedMemberValue {
|
|
|
245
367
|
readonly leaves: Readonly<Record<string, string>>;
|
|
246
368
|
/** Sibling collections, each entry's leaves already resolved. */
|
|
247
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>>;
|
|
248
377
|
}
|
|
249
378
|
/**
|
|
250
379
|
* Compose an embedded member's value for `blocks()` — the shape any project's own
|
|
251
380
|
* child kind uses. `kind` names the child kind: a bare string, or the child kind's
|
|
252
|
-
* own `KindDefinition` — passing the definition carries its `render` hook
|
|
253
|
-
* declared) through to emit, with no other change to the
|
|
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.
|
|
254
385
|
*/
|
|
255
386
|
export declare function embeddedMemberValue(init: {
|
|
256
387
|
kind: string | KindDefinition<any>;
|
package/dist/src/kind.js
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
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
|
|
4
|
-
* locus,
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
+
* an MCP server) extends the content fact with a fields-only `shape` and a
|
|
6
|
+
* `collectionAddress` naming the host manifest it surfaces in. `tsc` is the keystroke
|
|
7
|
+
* wall; every type erases at the seam, and what a kind leaves behind rides the lock as
|
|
8
|
+
* rows. Identity travels by import, never by string — a `kind` reference is the imported
|
|
9
|
+
* value.
|
|
8
10
|
*/
|
|
9
11
|
/** The framework keys of a member init — everything else is a typed field (flat). */
|
|
10
|
-
const FRAMEWORK_KEYS = new Set(["name", "prose", "satisfies", "requires", "needs"]);
|
|
12
|
+
const FRAMEWORK_KEYS = new Set(["name", "host", "prose", "satisfies", "requires", "needs"]);
|
|
11
13
|
/**
|
|
12
|
-
* Build the ordered projected
|
|
13
|
-
*
|
|
14
|
-
* (when the kind writes its name into frontmatter) followed by the
|
|
15
|
-
* in the author's declared order.
|
|
14
|
+
* Build the ordered projected fields for a member: nothing for a frontmatterless
|
|
15
|
+
* body-bearing kind (memory declares no `format` and is not fields-only), else the
|
|
16
|
+
* identity field (when the kind writes its name into frontmatter) followed by the
|
|
17
|
+
* typed fields in the author's declared order. A fields-only registration kind (a
|
|
18
|
+
* hook, an MCP server) carries its typed fields though it declares no `format` —
|
|
19
|
+
* the fields are the whole member, folded into a manifest entry, never a header.
|
|
16
20
|
*/
|
|
17
21
|
function orderedFields(facts, init) {
|
|
18
|
-
if (facts.format === undefined)
|
|
22
|
+
if (facts.format === undefined && facts.shape !== "fields")
|
|
19
23
|
return [];
|
|
20
24
|
const typed = [];
|
|
21
25
|
for (const [key, value] of Object.entries(init)) {
|
|
@@ -25,10 +29,31 @@ function orderedFields(facts, init) {
|
|
|
25
29
|
const head = facts.identityField !== undefined ? [[facts.identityField, init.name]] : [];
|
|
26
30
|
return [...head, ...typed];
|
|
27
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
|
+
}
|
|
28
53
|
/**
|
|
29
54
|
* Define a kind. Returns a constructor over the kind's typed
|
|
30
55
|
* fields `T`; every type erases at the seam, so what the returned member carries
|
|
31
|
-
* into emit is the
|
|
56
|
+
* into emit is the seven facts plus flat field data. `options.render`, when given,
|
|
32
57
|
* rides alongside `facts`/`key` on the returned constructor — never on the member
|
|
33
58
|
* it builds, since it is erased before a member reaches emit.
|
|
34
59
|
*/
|
|
@@ -37,6 +62,7 @@ export function kind(facts, options = {}) {
|
|
|
37
62
|
kind: facts.name,
|
|
38
63
|
facts,
|
|
39
64
|
name: init.name,
|
|
65
|
+
host: hostOf(facts, init),
|
|
40
66
|
prose: init.prose,
|
|
41
67
|
fields: orderedFields(facts, init),
|
|
42
68
|
satisfies: init.satisfies ?? [],
|
|
@@ -48,16 +74,21 @@ export function kind(facts, options = {}) {
|
|
|
48
74
|
/**
|
|
49
75
|
* Compose an embedded member's value for `blocks()` — the shape any project's own
|
|
50
76
|
* child kind uses. `kind` names the child kind: a bare string, or the child kind's
|
|
51
|
-
* own `KindDefinition` — passing the definition carries its `render` hook
|
|
52
|
-
* declared) through to emit, with no other change to the
|
|
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.
|
|
53
81
|
*/
|
|
54
82
|
export function embeddedMemberValue(init) {
|
|
55
|
-
const
|
|
83
|
+
const definition = typeof init.kind === "string" ? undefined : init.kind;
|
|
84
|
+
const render = definition?.render;
|
|
85
|
+
const edgeFields = definition?.facts.edgeFields;
|
|
56
86
|
return {
|
|
57
|
-
kind:
|
|
87
|
+
kind: definition?.key ?? init.kind,
|
|
58
88
|
key: init.key,
|
|
59
89
|
leaves: init.leaves,
|
|
60
90
|
collections: init.collections ?? {},
|
|
61
91
|
...(render !== undefined ? { render } : {}),
|
|
92
|
+
...(edgeFields !== undefined ? { edgeFields } : {}),
|
|
62
93
|
};
|
|
63
94
|
}
|
package/dist/src/prose.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
|
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(…)` —
|
|
71
|
-
*
|
|
72
|
-
* 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
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
107
|
-
|
|
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
|
|
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
|
-
*
|
|
119
|
-
* — the same rule a member-level
|
|
120
|
-
* the dangling-mention error so it
|
|
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,
|
|
181
|
+
export declare function resolveLeaf(value: string | Text, scope: MentionScope, context: string): string;
|