@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.
- package/README.md +84 -53
- package/bin/temper.js +0 -0
- package/dist/src/assembly.d.ts +15 -1
- package/dist/src/assembly.js +2 -1
- package/dist/src/builtins.d.ts +682 -66
- package/dist/src/builtins.js +664 -92
- 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 +72 -5
- package/dist/src/declarations.js +389 -107
- package/dist/src/dial.d.ts +75 -0
- package/dist/src/dial.js +82 -0
- package/dist/src/emit.d.ts +35 -1
- package/dist/src/emit.js +369 -63
- 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 +4 -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 +24 -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/RequirementRow.d.ts +4 -2
- package/dist/src/generated/SatisfiesRow.d.ts +2 -1
- 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 +3 -0
- package/dist/src/index.d.ts +8 -8
- package/dist/src/index.js +3 -3
- package/dist/src/kind.d.ts +135 -29
- package/dist/src/kind.js +35 -8
- package/dist/src/prose.d.ts +81 -25
- package/dist/src/prose.js +91 -21
- package/package.json +4 -4
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* specifier like any other. The built-in default contracts join the kinds here
|
|
8
8
|
* too: adoption is `import { skill, skillDefaultContract } from "@dtmd/temper/claude-code"`.
|
|
9
9
|
*/
|
|
10
|
-
export type { Agent, Hook, McpServer, Memory, Rule, Skill } from "./builtins.js";
|
|
11
|
-
export { agent, agentDefaultContract, command, commandDefaultContract, hook, hookDefaultContract, mcpServer, mcpServerDefaultContract, memory,
|
|
10
|
+
export type { Agent, Hook, InstalledPlugin, KnownMarketplace, Marketplace, MarketplacePlugin, MarketplaceSource, McpServer, Memory, PluginManifest, Rule, SettingsLocal, Skill, SupportingDoc, } from "./builtins.js";
|
|
11
|
+
export { agent, agentDefaultContract, command, commandDefaultContract, hook, hookDefaultContract, installedPlugin, installedPluginDefaultContract, knownMarketplace, knownMarketplaceDefaultContract, marketplace, marketplaceDefaultContract, mcpServer, mcpServerDefaultContract, memory, memoryAnthropicDefaultContract, pluginManifest, pluginManifestDefaultContract, rule, ruleDefaultContract, settingsLocal, settingsLocalDefaultContract, skill, skillDefaultContract, supportingDoc, supportingDocDefaultContract, } from "./builtins.js";
|
|
12
12
|
export type { Blocks, File, Prose, Text } from "./prose.js";
|
|
13
13
|
export { blocks, file, text } from "./prose.js";
|
package/dist/src/claude-code.js
CHANGED
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
* specifier like any other. The built-in default contracts join the kinds here
|
|
8
8
|
* too: adoption is `import { skill, skillDefaultContract } from "@dtmd/temper/claude-code"`.
|
|
9
9
|
*/
|
|
10
|
-
export { agent, agentDefaultContract, command, commandDefaultContract, hook, hookDefaultContract, mcpServer, mcpServerDefaultContract, memory,
|
|
10
|
+
export { agent, agentDefaultContract, command, commandDefaultContract, hook, hookDefaultContract, installedPlugin, installedPluginDefaultContract, knownMarketplace, knownMarketplaceDefaultContract, marketplace, marketplaceDefaultContract, mcpServer, mcpServerDefaultContract, memory, memoryAnthropicDefaultContract, pluginManifest, pluginManifestDefaultContract, rule, ruleDefaultContract, settingsLocal, settingsLocalDefaultContract, skill, skillDefaultContract, supportingDoc, supportingDocDefaultContract, } from "./builtins.js";
|
|
11
11
|
export { blocks, file, text } from "./prose.js";
|
package/dist/src/contract.d.ts
CHANGED
|
@@ -1,26 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Contracts — clauses and requirements as typed values.
|
|
3
3
|
* A clause is `predicate · severity · guidance · cite`; a requirement is
|
|
4
|
-
* `prose · kind · required · clauses? ·
|
|
4
|
+
* `prose · kind · required · clauses? · verifier?`. Both erase to compiled data
|
|
5
5
|
* at the seam: the author composes typed objects, the engine
|
|
6
6
|
* consumes their rows. The predicate vocabulary is the closed algebra — a clause
|
|
7
7
|
* outside it is a squiggle, not a runtime rejection.
|
|
8
8
|
*/
|
|
9
|
+
import type { Shape, ValueType } from "./generated/index.js";
|
|
9
10
|
import type { KindDefinition } from "./kind.js";
|
|
10
11
|
/** A clause's delivery posture: `required` gate-blocks, `advisory` reports. */
|
|
11
12
|
export type Severity = "required" | "advisory";
|
|
12
13
|
/**
|
|
13
|
-
* A member of the closed predicate algebra. Both a kind's
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* A member of the closed predicate algebra. Both a kind's own `expect` clauses and a
|
|
15
|
+
* requirement's `clauses` compile to the row's full `key`/`field`/`severity`/argument
|
|
16
|
+
* shape (`declarations.ts` `clauseRow`) — one spelling, whichever selection the clause
|
|
17
|
+
* binds to: `bound`/`charset`/`keys`/`values` ride the row alongside
|
|
18
|
+
* `count`/`target`/`degree`, so the lock encodes the clause losslessly rather than
|
|
19
|
+
* identity+severity alone.
|
|
19
20
|
*/
|
|
20
21
|
export interface Predicate {
|
|
21
|
-
/** The predicate's clause key (`required`, `max_len`, `
|
|
22
|
+
/** The predicate's clause key (`required`, `max_len`, `extent`, …). */
|
|
22
23
|
readonly key: string;
|
|
23
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The field (or marker) the predicate constrains, when it names one.
|
|
26
|
+
*
|
|
27
|
+
* A value predicate's `field` is an **addressing path**: name segments walk into an
|
|
28
|
+
* object (`owner.name`), and `[*]` is the each-grain over an array's elements, so
|
|
29
|
+
* `plugins[*].source` decides once per entry and indicts each offending one by its own
|
|
30
|
+
* address. Nothing else is spellable — an index, a slice, a filter, and a recursive
|
|
31
|
+
* descent are all refused when the contract is checked, not silently evaluated. The
|
|
32
|
+
* subset is the whole surface on purpose: a clause names *where* a value lives, never
|
|
33
|
+
* a pattern that matches it.
|
|
34
|
+
*
|
|
35
|
+
* `forbidden_keys` and `must_define` name a top-level **key**, not a path, and
|
|
36
|
+
* `closed-keys` names neither — it reads the key set its sibling clauses declare.
|
|
37
|
+
*/
|
|
24
38
|
readonly field?: string;
|
|
25
39
|
/** The predicate's scalar bounds, keyed per predicate (`min`/`max`,
|
|
26
40
|
* `incoming_min`/`incoming_max`/`outgoing_min`/`outgoing_max`). */
|
|
@@ -30,6 +44,23 @@ export interface Predicate {
|
|
|
30
44
|
* checked field) since `membership` names both.
|
|
31
45
|
*/
|
|
32
46
|
readonly target?: string;
|
|
47
|
+
/**
|
|
48
|
+
* `mention-reachable`'s **target-side gate field** — a separate slot from `field`
|
|
49
|
+
* (which carries the source-side scope field) since it is the one predicate naming a
|
|
50
|
+
* field on *both* ends. Spelled to match the lock's own `gate` column.
|
|
51
|
+
*/
|
|
52
|
+
readonly gate?: string;
|
|
53
|
+
/**
|
|
54
|
+
* `type`'s declared source kinds over the closed scalar/container lattice — the set
|
|
55
|
+
* the field may carry any one of. Spelled to match the lock's own `value_type`
|
|
56
|
+
* column.
|
|
57
|
+
*/
|
|
58
|
+
readonly value_type?: readonly ValueType[];
|
|
59
|
+
/**
|
|
60
|
+
* `shape`'s declared shape — one member of the closed set, spelled to match the lock's
|
|
61
|
+
* own `shape` column.
|
|
62
|
+
*/
|
|
63
|
+
readonly shape?: Shape;
|
|
33
64
|
/** `allowed_chars`'s declared character class. */
|
|
34
65
|
readonly charset?: Charset;
|
|
35
66
|
/** `forbidden_keys`'s forbidden key list. */
|
|
@@ -46,7 +77,15 @@ export interface Predicate {
|
|
|
46
77
|
readonly heading: string;
|
|
47
78
|
readonly marker: string;
|
|
48
79
|
};
|
|
80
|
+
/** `require_sections`'s required heading list. */
|
|
81
|
+
readonly sections?: readonly string[];
|
|
82
|
+
/** `extent`'s declared unit — the render-side size proxy the bound is measured in. */
|
|
83
|
+
readonly unit?: ExtentUnit;
|
|
49
84
|
}
|
|
85
|
+
/** The unit an `extent` bound is measured in — the closed set of stable render-side size
|
|
86
|
+
* proxies. Token count is deliberately absent: a verdict that moves when a tokenizer
|
|
87
|
+
* updates is a gate that changes its mind with no diff. */
|
|
88
|
+
export type ExtentUnit = "lines" | "characters";
|
|
50
89
|
/**
|
|
51
90
|
* The character class `allowed_chars` admits — inclusive ranges plus individual
|
|
52
91
|
* characters, e.g. `[a-z0-9-]`. Each range is a `"<lo>-<hi>"` two-character
|
|
@@ -56,24 +95,60 @@ export interface Charset {
|
|
|
56
95
|
readonly ranges?: readonly string[];
|
|
57
96
|
readonly chars?: string;
|
|
58
97
|
}
|
|
59
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* A field or marker is present. Presence is asked of the path's trailing name segment,
|
|
100
|
+
* so `required("plugins[*].source")` fires once per entry that omits it — and a path
|
|
101
|
+
* ending in `[*]` names elements rather than a key, which is refused.
|
|
102
|
+
*/
|
|
60
103
|
export declare const required: (field: string) => Predicate;
|
|
61
|
-
/**
|
|
62
|
-
|
|
104
|
+
/**
|
|
105
|
+
* The field's parsed source kind is one of the declared ones. `kinds` is a set: a
|
|
106
|
+
* format that documents a field as `string|array` is gated by `["string", "list"]`,
|
|
107
|
+
* and a one-element `["list"]` is the plain single-kind check.
|
|
108
|
+
*/
|
|
109
|
+
export declare const type: (field: string, kinds: readonly ValueType[]) => Predicate;
|
|
63
110
|
/** The field's value is at least `n` characters. */
|
|
64
111
|
export declare const minLen: (field: string, n: number) => Predicate;
|
|
65
112
|
/** The field's value is at most `n` characters. */
|
|
66
113
|
export declare const maxLen: (field: string, n: number) => Predicate;
|
|
67
114
|
/** The field's characters are drawn from a declared class (`allowed_chars`). */
|
|
68
115
|
export declare const allowedChars: (field: string, charset: Charset) => Predicate;
|
|
69
|
-
/**
|
|
70
|
-
|
|
116
|
+
/**
|
|
117
|
+
* The field's value holds one named `Shape` from the closed set the engine generates
|
|
118
|
+
* across the seam — the union *is* the vocabulary, so an author picks a member and can
|
|
119
|
+
* spell nothing else. There is no escape to a hand-written pattern, which is the point.
|
|
120
|
+
*
|
|
121
|
+
* - `hyphen-placement` — a hyphen neither leads, trails, nor doubles (`pdf-processing`,
|
|
122
|
+
* never `-pdf`, `pdf-`, or `pdf--processing`). Says nothing about the alphabet; pair it
|
|
123
|
+
* with `allowedChars` where the character set matters.
|
|
124
|
+
* - `no-xml-tags` — the value carries no XML tag (`<br/>`, `</note>`, `<a href="x">`).
|
|
125
|
+
* Prose spelling a comparison (`use when x < y`) is not a tag and does not fire.
|
|
126
|
+
*/
|
|
127
|
+
export declare const shape: (field: string, shape: Shape) => Predicate;
|
|
128
|
+
/**
|
|
129
|
+
* The selected item's **rendered** extent is at most `bound`, in the declared `unit`
|
|
130
|
+
* (`lines` or `characters`). Node-scope and render-side: the measure is the bytes the
|
|
131
|
+
* item contributes to its projection, not the source body a count reads before a
|
|
132
|
+
* reference resolves or a render hook runs.
|
|
133
|
+
*/
|
|
134
|
+
export declare const extent: (unit: ExtentUnit, bound: number) => Predicate;
|
|
71
135
|
/** The forbidden keys (e.g. the Cursor `globs`/`alwaysApply` keys) are absent. */
|
|
72
136
|
export declare const forbiddenKeys: (keys: readonly string[]) => Predicate;
|
|
137
|
+
/**
|
|
138
|
+
* The kind's declared key set is exhaustive — a member carrying any other top-level key
|
|
139
|
+
* is a finding. `forbiddenKeys`' complement: a deny-list names a finite set over an open
|
|
140
|
+
* key space, this closes the space.
|
|
141
|
+
*
|
|
142
|
+
* It takes no arguments, and that is the point: the allow-list is the contract's own
|
|
143
|
+
* `required`/`optional` clauses, so the key set is declared once. Adding `optional("x")`
|
|
144
|
+
* admits `x` with no second edit here — and a contract declaring no key at all fails
|
|
145
|
+
* admissibility rather than indicting every key of every member.
|
|
146
|
+
*/
|
|
147
|
+
export declare const closedKeys: () => Predicate;
|
|
73
148
|
/** The field's value is none of `values` (forbidden values). */
|
|
74
149
|
export declare const deny: (field: string, values: readonly string[]) => Predicate;
|
|
75
150
|
/** The named headings are present. */
|
|
76
|
-
export declare const requireSections: () => Predicate;
|
|
151
|
+
export declare const requireSections: (sections: readonly string[]) => Predicate;
|
|
77
152
|
/** The member's name matches its directory. */
|
|
78
153
|
export declare const nameMatchesDir: () => Predicate;
|
|
79
154
|
/** Names are unique within the artifact kind (a scope-wide identity collision). */
|
|
@@ -93,16 +168,41 @@ export declare const enumOf: (field: string, values: readonly string[]) => Predi
|
|
|
93
168
|
export declare const mustDefine: (marker: string) => Predicate;
|
|
94
169
|
/** Every body section whose heading *starts with* `heading` carries `marker` in its body. */
|
|
95
170
|
export declare const sectionContains: (heading: string, marker: string) => Predicate;
|
|
96
|
-
/**
|
|
171
|
+
/** Every glob the field carries parses under globset (brace-expansion aware). */
|
|
172
|
+
export declare const globValid: (field: string) => Predicate;
|
|
173
|
+
/**
|
|
174
|
+
* Every mention a selected member authors can fire where its target can be invoked. A
|
|
175
|
+
* target whose `gateField` carries globs is gated — removed from every invocation
|
|
176
|
+
* channel until the agent reads a matching file — so a mention of it is actionable only
|
|
177
|
+
* inside that gate. Fires on a scoped source whose `scopeField` globs are not contained
|
|
178
|
+
* in the target's gate, and on an unscoped source mentioning a gated target.
|
|
179
|
+
*
|
|
180
|
+
* Generic over both ends, hard-coding no kind: the trigger is the target's gate field
|
|
181
|
+
* carrying a value, never its registration set. Containment is *literal* — every source
|
|
182
|
+
* glob must appear verbatim in the gate — since true glob-set containment is
|
|
183
|
+
* undecidable, so it false-fires on a semantically contained narrower glob
|
|
184
|
+
* (`src/**\/*.ts` inside `src/**`). Declare it at advisory severity: a check that can be
|
|
185
|
+
* wrong must not block.
|
|
186
|
+
*/
|
|
187
|
+
export declare const mentionReachable: (scopeField: string, gateField: string) => Predicate;
|
|
188
|
+
/**
|
|
189
|
+
* Every edge the member's kind declares is placed by the format that renders the member
|
|
190
|
+
* — a format that omits one renders a contract the prose does not represent. Names no
|
|
191
|
+
* field: the selection is the member's whole incident edge set, at the `each` grain.
|
|
192
|
+
* Decided over the placement `emit` observes while rendering and lowers into the
|
|
193
|
+
* member's `nested_member` row, since the engine never sees a format.
|
|
194
|
+
*/
|
|
195
|
+
export declare const formatPlacesEdges: () => Predicate;
|
|
196
|
+
/** The selection's size lies in the inclusive `[min, max]` bound. */
|
|
97
197
|
export declare const count: (bounds: {
|
|
98
198
|
min?: number;
|
|
99
199
|
max?: number;
|
|
100
200
|
}) => Predicate;
|
|
101
|
-
/** The field's extracted value does not repeat across the
|
|
201
|
+
/** The field's extracted value does not repeat across the selection. */
|
|
102
202
|
export declare const unique: (field: string) => Predicate;
|
|
103
|
-
/** Every
|
|
203
|
+
/** Every selected member's `field` value is drawn from a feature over the selection `target` declares. */
|
|
104
204
|
export declare const membership: (field: string, target: string) => Predicate;
|
|
105
|
-
/** The in/out edge-count bound every
|
|
205
|
+
/** The in/out edge-count bound every selected member must land in. At least one direction must be given. */
|
|
106
206
|
export declare const degree: (bounds: {
|
|
107
207
|
incoming?: {
|
|
108
208
|
min?: number;
|
|
@@ -113,16 +213,38 @@ export declare const degree: (bounds: {
|
|
|
113
213
|
max?: number;
|
|
114
214
|
};
|
|
115
215
|
}) => Predicate;
|
|
216
|
+
/**
|
|
217
|
+
* A guarded clause — a predicate (restricted to `type` or `enum`) that acts as a
|
|
218
|
+
* guard, with a body of ordinary clauses that fire only where the guard holds.
|
|
219
|
+
* The guard and body share the guard's address binding: the body's field paths
|
|
220
|
+
* evaluate at the concrete element address the guard locates.
|
|
221
|
+
*
|
|
222
|
+
* The guard must be a `type` or `enumOf` predicate, named for the decidable
|
|
223
|
+
* field it addresses. Neither is enforced here; emit validates admissibility.
|
|
224
|
+
*
|
|
225
|
+
* Options for `severity`, `guidance`, and `cite` are supported and follow the
|
|
226
|
+
* same pattern as `clause()`. Default severity is `required`.
|
|
227
|
+
*/
|
|
228
|
+
export declare function when(guard: Predicate, body: readonly Clause[], opts?: {
|
|
229
|
+
severity?: Severity;
|
|
230
|
+
guidance?: string;
|
|
231
|
+
cite?: string;
|
|
232
|
+
}): Clause;
|
|
116
233
|
/**
|
|
117
234
|
* A clause — a predicate the author marks with a severity, the just-in-time
|
|
118
235
|
* guidance the predicate cannot encode, and the external-fact `cite` that makes
|
|
119
|
-
* a maintained floor auditable.
|
|
236
|
+
* a maintained floor auditable. A `when` clause carries an additional guard
|
|
237
|
+
* predicate and a body of nested clauses that fire only where the guard holds.
|
|
120
238
|
*/
|
|
121
239
|
export interface Clause {
|
|
122
240
|
readonly predicate: Predicate;
|
|
123
241
|
readonly severity: Severity;
|
|
124
242
|
readonly guidance?: string;
|
|
125
243
|
readonly cite?: string;
|
|
244
|
+
/** The guard predicate for a `when` clause; absent for all others. */
|
|
245
|
+
readonly when_guard?: Predicate;
|
|
246
|
+
/** The nested body clauses for a `when` clause; absent for all others. */
|
|
247
|
+
readonly when_body?: readonly Clause[];
|
|
126
248
|
}
|
|
127
249
|
/** Compose a clause value — a predicate under a declared severity, with optional guidance/cite. */
|
|
128
250
|
export declare function clause(predicate: Predicate, opts: {
|
|
@@ -130,22 +252,51 @@ export declare function clause(predicate: Predicate, opts: {
|
|
|
130
252
|
guidance?: string;
|
|
131
253
|
cite?: string;
|
|
132
254
|
}): Clause;
|
|
255
|
+
/**
|
|
256
|
+
* A requirement's **typed verifier** — the declared delegate that judges the
|
|
257
|
+
* behavioral remainder, a species-tagged union the gate resolves at admissibility
|
|
258
|
+
* and never runs. Two species this slice: a `script` (path-resolved) and a
|
|
259
|
+
* `telemetry` declaration (named documented harness events). A probe stays a
|
|
260
|
+
* documented pattern until a consumer types it — no `probe()` constructor is minted.
|
|
261
|
+
*/
|
|
262
|
+
export type Verifier = {
|
|
263
|
+
readonly species: "script";
|
|
264
|
+
readonly path: string;
|
|
265
|
+
} | {
|
|
266
|
+
readonly species: "telemetry";
|
|
267
|
+
readonly events: readonly string[];
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* A script verifier — a path-resolved reference to the test or CI job that executes
|
|
271
|
+
* the behavioral judgment. The gate checks the `path` resolves, never runs it.
|
|
272
|
+
*/
|
|
273
|
+
export declare const script: (path: string) => Verifier;
|
|
274
|
+
/**
|
|
275
|
+
* A telemetry verifier — the named documented harness events the emitted tap records
|
|
276
|
+
* to a local-locus log, judged by reading the field record. Each name must be a
|
|
277
|
+
* documented harness lifecycle event (`InstructionsLoaded`, `Skill`,
|
|
278
|
+
* `UserPromptExpansion`, `PostToolUse`; code.claude.com/docs/en/hooks, retrieved
|
|
279
|
+
* 2026-07-17) — the gate checks each resolves, never records into it.
|
|
280
|
+
*/
|
|
281
|
+
export declare const telemetry: (events: readonly string[]) => Verifier;
|
|
133
282
|
/**
|
|
134
283
|
* A requirement — a named obligation on the harness. `prose` is the authored
|
|
135
|
-
* intent, carried never interpreted; `kind` constrains what may fill it
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
284
|
+
* intent, carried never interpreted; `kind` constrains what may fill it —
|
|
285
|
+
* either a bare kind-name string or the kind's `KindDefinition`, since the slot
|
|
286
|
+
* carries only the kind's *identity* for coverage resolution, never its field
|
|
287
|
+
* type: a kind whose fields carry required members (skill, hook) assigns here,
|
|
288
|
+
* where `KindDefinition<never>` would have rejected it. `required` is the
|
|
289
|
+
* posture declaration; `clauses` bind to the requirement's **opt-in selection** —
|
|
290
|
+
* ordinary [`Clause`] values, the same four-channel clause as everywhere, judged
|
|
291
|
+
* over that selection by the same algebra a kind's own clauses are judged over its
|
|
292
|
+
* population; `verifier` wires the behavioral remainder as a typed species union.
|
|
142
293
|
*/
|
|
143
294
|
export interface Requirement {
|
|
144
295
|
readonly prose: string;
|
|
145
|
-
readonly kind?: KindDefinition<
|
|
296
|
+
readonly kind?: string | KindDefinition<any>;
|
|
146
297
|
readonly required?: boolean;
|
|
147
298
|
readonly clauses?: readonly Clause[];
|
|
148
|
-
readonly
|
|
299
|
+
readonly verifier?: Verifier;
|
|
149
300
|
}
|
|
150
301
|
/** An identity helper — types a requirement literal at the keystroke. */
|
|
151
302
|
export declare function requirement(init: Requirement): Requirement;
|
package/dist/src/contract.js
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Contracts — clauses and requirements as typed values.
|
|
3
3
|
* A clause is `predicate · severity · guidance · cite`; a requirement is
|
|
4
|
-
* `prose · kind · required · clauses? ·
|
|
4
|
+
* `prose · kind · required · clauses? · verifier?`. Both erase to compiled data
|
|
5
5
|
* at the seam: the author composes typed objects, the engine
|
|
6
6
|
* consumes their rows. The predicate vocabulary is the closed algebra — a clause
|
|
7
7
|
* outside it is a squiggle, not a runtime rejection.
|
|
8
8
|
*/
|
|
9
|
-
// Node-scope predicates.
|
|
10
|
-
|
|
9
|
+
// Node-scope predicates. A value predicate takes an addressing path as its `field` — see
|
|
10
|
+
// `Predicate.field` for the subset an author may spell, and for the key-naming and
|
|
11
|
+
// fieldless exceptions that sit here too.
|
|
12
|
+
/**
|
|
13
|
+
* A field or marker is present. Presence is asked of the path's trailing name segment,
|
|
14
|
+
* so `required("plugins[*].source")` fires once per entry that omits it — and a path
|
|
15
|
+
* ending in `[*]` names elements rather than a key, which is refused.
|
|
16
|
+
*/
|
|
11
17
|
export const required = (field) => ({ key: "required", field });
|
|
12
|
-
/**
|
|
13
|
-
|
|
18
|
+
/**
|
|
19
|
+
* The field's parsed source kind is one of the declared ones. `kinds` is a set: a
|
|
20
|
+
* format that documents a field as `string|array` is gated by `["string", "list"]`,
|
|
21
|
+
* and a one-element `["list"]` is the plain single-kind check.
|
|
22
|
+
*/
|
|
23
|
+
export const type = (field, kinds) => ({
|
|
24
|
+
key: "type",
|
|
25
|
+
field,
|
|
26
|
+
value_type: kinds,
|
|
27
|
+
});
|
|
14
28
|
/** The field's value is at least `n` characters. */
|
|
15
29
|
export const minLen = (field, n) => ({ key: "min_len", field, args: { min: n } });
|
|
16
30
|
/** The field's value is at most `n` characters. */
|
|
@@ -21,10 +35,42 @@ export const allowedChars = (field, charset) => ({
|
|
|
21
35
|
field,
|
|
22
36
|
charset,
|
|
23
37
|
});
|
|
24
|
-
/**
|
|
25
|
-
|
|
38
|
+
/**
|
|
39
|
+
* The field's value holds one named `Shape` from the closed set the engine generates
|
|
40
|
+
* across the seam — the union *is* the vocabulary, so an author picks a member and can
|
|
41
|
+
* spell nothing else. There is no escape to a hand-written pattern, which is the point.
|
|
42
|
+
*
|
|
43
|
+
* - `hyphen-placement` — a hyphen neither leads, trails, nor doubles (`pdf-processing`,
|
|
44
|
+
* never `-pdf`, `pdf-`, or `pdf--processing`). Says nothing about the alphabet; pair it
|
|
45
|
+
* with `allowedChars` where the character set matters.
|
|
46
|
+
* - `no-xml-tags` — the value carries no XML tag (`<br/>`, `</note>`, `<a href="x">`).
|
|
47
|
+
* Prose spelling a comparison (`use when x < y`) is not a tag and does not fire.
|
|
48
|
+
*/
|
|
49
|
+
export const shape = (field, shape) => ({ key: "shape", field, shape });
|
|
50
|
+
/**
|
|
51
|
+
* The selected item's **rendered** extent is at most `bound`, in the declared `unit`
|
|
52
|
+
* (`lines` or `characters`). Node-scope and render-side: the measure is the bytes the
|
|
53
|
+
* item contributes to its projection, not the source body a count reads before a
|
|
54
|
+
* reference resolves or a render hook runs.
|
|
55
|
+
*/
|
|
56
|
+
export const extent = (unit, bound) => ({
|
|
57
|
+
key: "extent",
|
|
58
|
+
unit,
|
|
59
|
+
args: { max: bound },
|
|
60
|
+
});
|
|
26
61
|
/** The forbidden keys (e.g. the Cursor `globs`/`alwaysApply` keys) are absent. */
|
|
27
62
|
export const forbiddenKeys = (keys) => ({ key: "forbidden_keys", keys });
|
|
63
|
+
/**
|
|
64
|
+
* The kind's declared key set is exhaustive — a member carrying any other top-level key
|
|
65
|
+
* is a finding. `forbiddenKeys`' complement: a deny-list names a finite set over an open
|
|
66
|
+
* key space, this closes the space.
|
|
67
|
+
*
|
|
68
|
+
* It takes no arguments, and that is the point: the allow-list is the contract's own
|
|
69
|
+
* `required`/`optional` clauses, so the key set is declared once. Adding `optional("x")`
|
|
70
|
+
* admits `x` with no second edit here — and a contract declaring no key at all fails
|
|
71
|
+
* admissibility rather than indicting every key of every member.
|
|
72
|
+
*/
|
|
73
|
+
export const closedKeys = () => ({ key: "closed-keys" });
|
|
28
74
|
/** The field's value is none of `values` (forbidden values). */
|
|
29
75
|
export const deny = (field, values) => ({
|
|
30
76
|
key: "deny",
|
|
@@ -32,7 +78,7 @@ export const deny = (field, values) => ({
|
|
|
32
78
|
values,
|
|
33
79
|
});
|
|
34
80
|
/** The named headings are present. */
|
|
35
|
-
export const requireSections = () => ({ key: "require_sections" });
|
|
81
|
+
export const requireSections = (sections) => ({ key: "require_sections", sections });
|
|
36
82
|
/** The member's name matches its directory. */
|
|
37
83
|
export const nameMatchesDir = () => ({ key: "name-matches-dir" });
|
|
38
84
|
/** Names are unique within the artifact kind (a scope-wide identity collision). */
|
|
@@ -63,10 +109,42 @@ export const sectionContains = (heading, marker) => ({
|
|
|
63
109
|
key: "section_contains",
|
|
64
110
|
section: { heading, marker },
|
|
65
111
|
});
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
112
|
+
/** Every glob the field carries parses under globset (brace-expansion aware). */
|
|
113
|
+
export const globValid = (field) => ({ key: "glob-valid", field });
|
|
114
|
+
/**
|
|
115
|
+
* Every mention a selected member authors can fire where its target can be invoked. A
|
|
116
|
+
* target whose `gateField` carries globs is gated — removed from every invocation
|
|
117
|
+
* channel until the agent reads a matching file — so a mention of it is actionable only
|
|
118
|
+
* inside that gate. Fires on a scoped source whose `scopeField` globs are not contained
|
|
119
|
+
* in the target's gate, and on an unscoped source mentioning a gated target.
|
|
120
|
+
*
|
|
121
|
+
* Generic over both ends, hard-coding no kind: the trigger is the target's gate field
|
|
122
|
+
* carrying a value, never its registration set. Containment is *literal* — every source
|
|
123
|
+
* glob must appear verbatim in the gate — since true glob-set containment is
|
|
124
|
+
* undecidable, so it false-fires on a semantically contained narrower glob
|
|
125
|
+
* (`src/**\/*.ts` inside `src/**`). Declare it at advisory severity: a check that can be
|
|
126
|
+
* wrong must not block.
|
|
127
|
+
*/
|
|
128
|
+
export const mentionReachable = (scopeField, gateField) => ({
|
|
129
|
+
key: "mention-reachable",
|
|
130
|
+
field: scopeField,
|
|
131
|
+
gate: gateField,
|
|
132
|
+
});
|
|
133
|
+
/**
|
|
134
|
+
* Every edge the member's kind declares is placed by the format that renders the member
|
|
135
|
+
* — a format that omits one renders a contract the prose does not represent. Names no
|
|
136
|
+
* field: the selection is the member's whole incident edge set, at the `each` grain.
|
|
137
|
+
* Decided over the placement `emit` observes while rendering and lowers into the
|
|
138
|
+
* member's `nested_member` row, since the engine never sees a format.
|
|
139
|
+
*/
|
|
140
|
+
export const formatPlacesEdges = () => ({ key: "format-places-edges" });
|
|
141
|
+
// Set predicates — they range over the **selection** their clause binds to, not one
|
|
142
|
+
// member's own fields: a kind's `expect` binds them to that kind's whole population
|
|
143
|
+
// (the universal binding), a requirement's `clauses` to its opt-in satisfiers (the
|
|
144
|
+
// existential one). The quantifier is the clause's grain, so the same value says the
|
|
145
|
+
// same thing in either place, riding the same four-channel `clause()` shape as the
|
|
146
|
+
// member-scope predicates above.
|
|
147
|
+
/** The selection's size lies in the inclusive `[min, max]` bound. */
|
|
70
148
|
export const count = (bounds) => {
|
|
71
149
|
const args = {};
|
|
72
150
|
if (bounds.min !== undefined)
|
|
@@ -75,15 +153,15 @@ export const count = (bounds) => {
|
|
|
75
153
|
args.max = bounds.max;
|
|
76
154
|
return { key: "count", args };
|
|
77
155
|
};
|
|
78
|
-
/** The field's extracted value does not repeat across the
|
|
156
|
+
/** The field's extracted value does not repeat across the selection. */
|
|
79
157
|
export const unique = (field) => ({ key: "unique", field });
|
|
80
|
-
/** Every
|
|
158
|
+
/** Every selected member's `field` value is drawn from a feature over the selection `target` declares. */
|
|
81
159
|
export const membership = (field, target) => ({
|
|
82
160
|
key: "membership",
|
|
83
161
|
field,
|
|
84
162
|
target,
|
|
85
163
|
});
|
|
86
|
-
/** The in/out edge-count bound every
|
|
164
|
+
/** The in/out edge-count bound every selected member must land in. At least one direction must be given. */
|
|
87
165
|
export const degree = (bounds) => {
|
|
88
166
|
const args = {};
|
|
89
167
|
if (bounds.incoming?.min !== undefined)
|
|
@@ -96,10 +174,45 @@ export const degree = (bounds) => {
|
|
|
96
174
|
args.outgoing_max = bounds.outgoing.max;
|
|
97
175
|
return { key: "degree", args };
|
|
98
176
|
};
|
|
177
|
+
/**
|
|
178
|
+
* A guarded clause — a predicate (restricted to `type` or `enum`) that acts as a
|
|
179
|
+
* guard, with a body of ordinary clauses that fire only where the guard holds.
|
|
180
|
+
* The guard and body share the guard's address binding: the body's field paths
|
|
181
|
+
* evaluate at the concrete element address the guard locates.
|
|
182
|
+
*
|
|
183
|
+
* The guard must be a `type` or `enumOf` predicate, named for the decidable
|
|
184
|
+
* field it addresses. Neither is enforced here; emit validates admissibility.
|
|
185
|
+
*
|
|
186
|
+
* Options for `severity`, `guidance`, and `cite` are supported and follow the
|
|
187
|
+
* same pattern as `clause()`. Default severity is `required`.
|
|
188
|
+
*/
|
|
189
|
+
export function when(guard, body, opts) {
|
|
190
|
+
return {
|
|
191
|
+
predicate: { key: "when" },
|
|
192
|
+
severity: opts?.severity ?? "required",
|
|
193
|
+
guidance: opts?.guidance,
|
|
194
|
+
cite: opts?.cite,
|
|
195
|
+
when_guard: guard,
|
|
196
|
+
when_body: body,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
99
199
|
/** Compose a clause value — a predicate under a declared severity, with optional guidance/cite. */
|
|
100
200
|
export function clause(predicate, opts) {
|
|
101
201
|
return { predicate, severity: opts.severity, guidance: opts.guidance, cite: opts.cite };
|
|
102
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* A script verifier — a path-resolved reference to the test or CI job that executes
|
|
205
|
+
* the behavioral judgment. The gate checks the `path` resolves, never runs it.
|
|
206
|
+
*/
|
|
207
|
+
export const script = (path) => ({ species: "script", path });
|
|
208
|
+
/**
|
|
209
|
+
* A telemetry verifier — the named documented harness events the emitted tap records
|
|
210
|
+
* to a local-locus log, judged by reading the field record. Each name must be a
|
|
211
|
+
* documented harness lifecycle event (`InstructionsLoaded`, `Skill`,
|
|
212
|
+
* `UserPromptExpansion`, `PostToolUse`; code.claude.com/docs/en/hooks, retrieved
|
|
213
|
+
* 2026-07-17) — the gate checks each resolves, never records into it.
|
|
214
|
+
*/
|
|
215
|
+
export const telemetry = (events) => ({ species: "telemetry", events });
|
|
103
216
|
/** An identity helper — types a requirement literal at the keystroke. */
|
|
104
217
|
export function requirement(init) {
|
|
105
218
|
return init;
|
|
@@ -9,10 +9,40 @@
|
|
|
9
9
|
* in lockstep.
|
|
10
10
|
*/
|
|
11
11
|
import type { Harness } from "./assembly.js";
|
|
12
|
+
import type { MentionScope } from "./prose.js";
|
|
12
13
|
import type { Declarations, Payload, RegistrationRow, SettingsRow } from "./generated/index.js";
|
|
13
14
|
export type { AssemblyFactRow, ClauseRow, Declarations, KindFactRow, RequirementRow, SatisfiesRow, } from "./generated/index.js";
|
|
14
15
|
/** The stable-sort ordering every declaration row family shares. */
|
|
15
16
|
export declare function compareStrings(a: string, b: string): number;
|
|
17
|
+
/**
|
|
18
|
+
* One composed embedded value's key in an {@link EdgePlacements} table — its host's
|
|
19
|
+
* `kind:name` address plus the value's own kind and key, the same triple the
|
|
20
|
+
* `nested_member` row it feeds is identified by.
|
|
21
|
+
*/
|
|
22
|
+
export declare function placementKey(host: string, kind: string, key: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Each composed embedded value's placed edge fields, by {@link placementKey} — `emit`'s
|
|
25
|
+
* record of which declared edges each value's format actually rendered (`emit.ts`'s
|
|
26
|
+
* `edgePlacements`). A value with no entry had no format observe it, which is distinct
|
|
27
|
+
* from a format that placed nothing: the row omits the column entirely and the
|
|
28
|
+
* `format-places-edges` clause stays undecided rather than indict a format that never ran.
|
|
29
|
+
*/
|
|
30
|
+
export type EdgePlacements = ReadonlyMap<string, readonly string[]>;
|
|
31
|
+
/** One composed embedded value's rendered extent — the line and character count of the
|
|
32
|
+
* block `emit` projected for it ({@link RenderedExtents}), the span an `extent` clause
|
|
33
|
+
* budgets. */
|
|
34
|
+
export interface RenderedExtent {
|
|
35
|
+
readonly lines: number;
|
|
36
|
+
readonly chars: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Each composed embedded value's rendered extent, by {@link placementKey} — `emit`'s
|
|
40
|
+
* record of the span it projected for each value (`emit.ts`'s `renderedExtents`). A value
|
|
41
|
+
* with no entry had no format rendered it (a member read off a layout host's source),
|
|
42
|
+
* which the row spells by omitting both span columns rather than a captured zero: an
|
|
43
|
+
* unmeasured member's `extent` stays undecidable, never a zero read as a pass.
|
|
44
|
+
*/
|
|
45
|
+
export type RenderedExtents = ReadonlyMap<string, RenderedExtent>;
|
|
16
46
|
/**
|
|
17
47
|
* The `registration` rows — every fields-only registration member (a hook, an MCP server)
|
|
18
48
|
* erased for the manifest write face, kind-then-key sorted so double emit is byte-stable.
|
|
@@ -26,6 +56,19 @@ export declare function compareStrings(a: string, b: string): number;
|
|
|
26
56
|
* If a fields-only member declares no collection address — it surfaces in no host manifest.
|
|
27
57
|
*/
|
|
28
58
|
export declare function registrationRows(harness: Harness): RegistrationRow[];
|
|
59
|
+
/**
|
|
60
|
+
* The synthesized tap-hook `registration` rows — one deduped `hooks.<Event>`
|
|
61
|
+
* registration per (lifecycle event, matcher) any telemetry verifier names. Scans the
|
|
62
|
+
* same requirement sources {@link requirementRows} reads (assembly `require` ∪ each
|
|
63
|
+
* member's `requires`), keeps the telemetry-species verifiers ({@link Verifier}), and
|
|
64
|
+
* unions the lifecycle events they name into one dumb registration apiece: the tap
|
|
65
|
+
* records every fire and read time joins raw events to members, so however many
|
|
66
|
+
* verifiers name an event it takes exactly one hook — the derived-aggregate precedent
|
|
67
|
+
* the permission union sets ({@link permissionUnion}). Each row runs {@link TAP_COMMAND}
|
|
68
|
+
* under the event's documented matcher ({@link TELEMETRY_EVENT_HOOKS}); an event-name
|
|
69
|
+
* outside that table is the roster's inadmissibility finding, never a row.
|
|
70
|
+
*/
|
|
71
|
+
export declare function tapHookRows(harness: Harness): RegistrationRow[];
|
|
29
72
|
/**
|
|
30
73
|
* The `settings` rows — the assembly's harness-level residual settings keys, each folded
|
|
31
74
|
* into the settings.json manifest's opaque residue at emit. Key-sorted so double emit is
|
|
@@ -36,13 +79,37 @@ export declare function settingsRows(harness: Harness): SettingsRow[];
|
|
|
36
79
|
export declare function declaredRequirements(harness: Harness): Set<string>;
|
|
37
80
|
/**
|
|
38
81
|
* Every address a mention may name — declared requirement names ∪ each member's
|
|
39
|
-
* `kind:name
|
|
40
|
-
*
|
|
41
|
-
*
|
|
82
|
+
* `kind:name` ∪ each `blocks()`-declared embedded member's host-scoped
|
|
83
|
+
* `<host-kind>:<host-name>/<kind>/<key>` address. Shared by `emit.ts` (a
|
|
84
|
+
* member-level `Text` body's mentions) and this module (an embedded member's
|
|
85
|
+
* `Text` leaves) — the one resolution-check set, so a leaf mention and a member
|
|
86
|
+
* mention are held to the identical bar. The embedded address is host-scoped,
|
|
87
|
+
* never a flat `<kind>:<key>` — flat would force corpus-wide key uniqueness on
|
|
88
|
+
* embedded kinds.
|
|
42
89
|
*/
|
|
43
90
|
export declare function declaredAddresses(harness: Harness): Set<string>;
|
|
44
|
-
/**
|
|
45
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Every discoverable (`at`-locus) kind the program declares — the deferral signal a
|
|
93
|
+
* dangling mention is measured against (`prose.ts`'s `defersToGate`): a mention naming
|
|
94
|
+
* one of these whose member is not a composed value defers to `check`, while a mention
|
|
95
|
+
* naming no declared kind refuses at emit. Member kinds ∪ `expect` kinds; an embedded
|
|
96
|
+
* kind is excluded — its members are composed within a host, never discovered, so a
|
|
97
|
+
* flat `kind:name` mention of one has no discovery locus to defer to.
|
|
98
|
+
*/
|
|
99
|
+
export declare function declaredAtLocusKinds(harness: Harness): Set<string>;
|
|
100
|
+
/** The full {@link MentionScope} the program resolves a mention against — its addresses and its deferral kinds. */
|
|
101
|
+
export declare function mentionScope(harness: Harness): MentionScope;
|
|
102
|
+
/**
|
|
103
|
+
* Compile a harness into its seven declaration families — the erased program.
|
|
104
|
+
*
|
|
105
|
+
* `placements` and `extents` are `emit`'s record of what each embedded value's format
|
|
106
|
+
* rendered (`emit.ts`'s `edgePlacements`) and the span it spanned (`renderedExtents`); this
|
|
107
|
+
* pass compiles declarations and never renders, so it observes neither itself. Omitted,
|
|
108
|
+
* every `nested_member` row omits its `placed_edges`/`rendered_lines`/`rendered_chars`
|
|
109
|
+
* columns — honest (nothing observed a render) but undecidable for a `format-places-edges`
|
|
110
|
+
* or `extent` clause, so a whole compile goes through `emit`, never this alone.
|
|
111
|
+
*/
|
|
112
|
+
export declare function compileDeclarations(harness: Harness, placements?: EdgePlacements, extents?: RenderedExtents): Declarations;
|
|
46
113
|
/** The SDK's pinned engine/interchange version — the JSON pipe rides it in lockstep. */
|
|
47
114
|
export declare const SEAM_VERSION = 2;
|
|
48
115
|
/**
|