@dtmd/temper 0.0.12 → 0.0.13
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 +3 -2
- package/dist/src/builtins.d.ts +10 -0
- package/dist/src/builtins.js +20 -1
- package/dist/src/contract.d.ts +1 -1
- package/dist/src/contract.js +1 -1
- package/dist/src/declarations.d.ts +4 -2
- package/dist/src/declarations.js +35 -32
- package/dist/src/generated/Features.d.ts +1 -1
- package/dist/src/generated/RequirementRow.d.ts +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -16,8 +16,9 @@ installed:
|
|
|
16
16
|
npx @dtmd/temper check --harness .
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
It validates every
|
|
20
|
-
|
|
19
|
+
It validates every member Claude Code reads, from skills and rules to hooks,
|
|
20
|
+
MCP servers, and plugin manifests, against the documented Anthropic schemas
|
|
21
|
+
and best practices, then reports what is malformed, what Claude Code
|
|
21
22
|
silently ignores, and what a requirement you declared would strand. Every
|
|
22
23
|
finding arrives with its guidance attached.
|
|
23
24
|
|
package/dist/src/builtins.d.ts
CHANGED
|
@@ -314,6 +314,16 @@ export declare const SETTINGS_MANIFEST = "settings.json";
|
|
|
314
314
|
* temper ships — the read side of 0021's manifest-authoring surface.
|
|
315
315
|
*/
|
|
316
316
|
export declare const hook: KindDefinition<Hook>;
|
|
317
|
+
/**
|
|
318
|
+
* The tap hook registration's `hooks.<Event>` key-path and `Hook` field triple — the
|
|
319
|
+
* provider fact {@link tapHookRows} (`declarations.ts`) fills rather than authors inline.
|
|
320
|
+
* A tap hook always fires a `command` handler (`type` fixed), so only the tap's own
|
|
321
|
+
* `command` string and the per-event `matcher` {@link TELEMETRY_EVENT_HOOKS} names vary.
|
|
322
|
+
*/
|
|
323
|
+
export declare function tapHookRegistration(command: string, matcher: string): {
|
|
324
|
+
readonly keyPath: string;
|
|
325
|
+
readonly fields: Array<[string, unknown]>;
|
|
326
|
+
};
|
|
317
327
|
/**
|
|
318
328
|
* A Claude Code MCP server — a fields-only registration member surfacing inside
|
|
319
329
|
* `.mcp.json`, keyed by name under `mcpServers`. It owns no artifact of its own; its
|
package/dist/src/builtins.js
CHANGED
|
@@ -115,6 +115,9 @@ export const memory = kind({
|
|
|
115
115
|
* registrations surface inside (code.claude.com/docs/en/settings, retrieved 2026-07-16).
|
|
116
116
|
*/
|
|
117
117
|
export const SETTINGS_MANIFEST = "settings.json";
|
|
118
|
+
/** The `hooks.<Event>` collection address's key-path — the `hook` kind's own address, and
|
|
119
|
+
* the tap hook registration's, since a tap hook is an ordinary `hook` entry. */
|
|
120
|
+
const HOOK_KEY_PATH = "hooks.<Event>";
|
|
118
121
|
/**
|
|
119
122
|
* `hook` — a `settings.json` `hooks.<Event>` registration member: a fields-only kind (no
|
|
120
123
|
* body slot), its members discovered off the `.claude/settings.json` manifest at the
|
|
@@ -128,9 +131,25 @@ export const hook = kind({
|
|
|
128
131
|
unitShape: "file",
|
|
129
132
|
registration: [{ via: "event", field: "event" }],
|
|
130
133
|
shape: "fields",
|
|
131
|
-
collectionAddress: { manifest: SETTINGS_MANIFEST, keyPath:
|
|
134
|
+
collectionAddress: { manifest: SETTINGS_MANIFEST, keyPath: HOOK_KEY_PATH, entryShape: "group-array(hooks;matcher)" },
|
|
132
135
|
guidance: "keep a handler's `type` among `command`/`http`/`mcp_tool`/`prompt`/`agent`; a `command` handler needs a `command`, an `http` handler a `url`; the `matcher` filters tool-scoped events and is inert on events that carry no tool (`UserPromptSubmit`, `Stop`, and their siblings).",
|
|
133
136
|
});
|
|
137
|
+
/**
|
|
138
|
+
* The tap hook registration's `hooks.<Event>` key-path and `Hook` field triple — the
|
|
139
|
+
* provider fact {@link tapHookRows} (`declarations.ts`) fills rather than authors inline.
|
|
140
|
+
* A tap hook always fires a `command` handler (`type` fixed), so only the tap's own
|
|
141
|
+
* `command` string and the per-event `matcher` {@link TELEMETRY_EVENT_HOOKS} names vary.
|
|
142
|
+
*/
|
|
143
|
+
export function tapHookRegistration(command, matcher) {
|
|
144
|
+
return {
|
|
145
|
+
keyPath: HOOK_KEY_PATH,
|
|
146
|
+
fields: [
|
|
147
|
+
["type", "command"],
|
|
148
|
+
["command", command],
|
|
149
|
+
["matcher", matcher],
|
|
150
|
+
],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
134
153
|
/**
|
|
135
154
|
* `mcpServer` — a `.mcp.json` `mcpServers.*` registration member: a fields-only kind (no
|
|
136
155
|
* body slot), its members discovered off the `.mcp.json` manifest at the `mcpServers.*`
|
package/dist/src/contract.d.ts
CHANGED
|
@@ -275,7 +275,7 @@ export declare const script: (path: string) => Verifier;
|
|
|
275
275
|
* A telemetry verifier — the named documented harness events the emitted tap records
|
|
276
276
|
* to a local-locus log, judged by reading the field record. Each name must be a
|
|
277
277
|
* documented harness lifecycle event — the gate checks each resolves, never records
|
|
278
|
-
* into it. See `TELEMETRY_EVENT_HOOKS` in `
|
|
278
|
+
* into it. See `TELEMETRY_EVENT_HOOKS` in `builtins.ts` for the vocabulary.
|
|
279
279
|
*/
|
|
280
280
|
export declare const telemetry: (events: readonly string[]) => Verifier;
|
|
281
281
|
/**
|
package/dist/src/contract.js
CHANGED
|
@@ -209,7 +209,7 @@ export const script = (path) => ({ species: "script", path });
|
|
|
209
209
|
* A telemetry verifier — the named documented harness events the emitted tap records
|
|
210
210
|
* to a local-locus log, judged by reading the field record. Each name must be a
|
|
211
211
|
* documented harness lifecycle event — the gate checks each resolves, never records
|
|
212
|
-
* into it. See `TELEMETRY_EVENT_HOOKS` in `
|
|
212
|
+
* into it. See `TELEMETRY_EVENT_HOOKS` in `builtins.ts` for the vocabulary.
|
|
213
213
|
*/
|
|
214
214
|
export const telemetry = (events) => ({ species: "telemetry", events });
|
|
215
215
|
/** An identity helper — types a requirement literal at the keystroke. */
|
|
@@ -70,8 +70,10 @@ export declare function buildTapHookDedupeKey(event: string, matcher: string): s
|
|
|
70
70
|
* records every fire and read time joins raw events to members, so however many
|
|
71
71
|
* verifiers name an event it takes exactly one hook — the derived-aggregate precedent
|
|
72
72
|
* the permission union sets ({@link permissionUnion}). Each row runs {@link TAP_COMMAND}
|
|
73
|
-
* under the event's documented matcher ({@link TELEMETRY_EVENT_HOOKS})
|
|
74
|
-
*
|
|
73
|
+
* under the event's documented matcher ({@link TELEMETRY_EVENT_HOOKS}), its key-path and
|
|
74
|
+
* field triple sourced from the provider face ({@link tapHookRegistration},
|
|
75
|
+
* `builtins.ts`); an event-name outside that table is the roster's inadmissibility
|
|
76
|
+
* finding, never a row.
|
|
75
77
|
*/
|
|
76
78
|
export declare function tapHookRows(harness: Harness): RegistrationRow[];
|
|
77
79
|
/**
|
package/dist/src/declarations.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { isTextSpan, resolveLeaf } from "./prose.js";
|
|
13
|
-
import { SETTINGS_MANIFEST, TELEMETRY_EVENT_HOOKS } from "./builtins.js";
|
|
13
|
+
import { SETTINGS_MANIFEST, TELEMETRY_EVENT_HOOKS, tapHookRegistration } from "./builtins.js";
|
|
14
14
|
/**
|
|
15
15
|
* Compile one `Clause` into its lock row: the shared `key`/`field`/`severity`/
|
|
16
16
|
* `guidance`/`cite` columns — the clause's four channels surviving erasure
|
|
@@ -223,20 +223,19 @@ function collectionAddressRow(facts) {
|
|
|
223
223
|
};
|
|
224
224
|
}
|
|
225
225
|
/**
|
|
226
|
-
* One kind's fact row — an `at` locus supplies `governs_root`/`governs_glob` and
|
|
227
|
-
* nested-file kind
|
|
228
|
-
* template's pattern
|
|
229
|
-
* the same spelling, absent for the committed
|
|
230
|
-
* corpus admits over it, and `content`
|
|
231
|
-
* `file`-content kind). A registration kind
|
|
232
|
-
*
|
|
226
|
+
* One kind's fact row — an `at` locus supplies `governs_root`/`governs_glob` and any
|
|
227
|
+
* other locus neither (a nested-file kind's path composes from its host's unit and the
|
|
228
|
+
* host template's pattern; an embedded kind owns no unit at all — both govern no glob).
|
|
229
|
+
* A file locus's `commitment` class rides the same spelling, absent for the committed
|
|
230
|
+
* default. `templates` names the embedded kinds the corpus admits over it, and `content`
|
|
231
|
+
* lowers a declared layout (absent for a `file`-content kind). A registration kind
|
|
232
|
+
* extends the row with its `shape` marker and `collection_address`. Advisory
|
|
233
|
+
* `guidance`/`cite` pair rides alongside, locus-optional so an embedded kind's own
|
|
234
|
+
* counsel reaches the lock the same way a nested-file kind's already does (decision
|
|
235
|
+
* 0045) — callable for any locus; [`kindFactKindsInPlay`] decides which embedded kinds
|
|
236
|
+
* actually take a row.
|
|
233
237
|
*/
|
|
234
238
|
function kindFactRow(facts, admissions) {
|
|
235
|
-
if (facts.locus.kind === "embedded") {
|
|
236
|
-
// An embedded kind inherits its world residue through its host; it owns no unit at
|
|
237
|
-
// all, so it takes no kind-fact row. Callers filter these out before this point.
|
|
238
|
-
throw new Error(`kind \`${facts.name}\` is embedded — it carries no locus-bearing kind fact.`);
|
|
239
|
-
}
|
|
240
239
|
const governs = facts.locus.kind === "at" ? facts.locus : undefined;
|
|
241
240
|
return {
|
|
242
241
|
name: facts.name,
|
|
@@ -298,12 +297,15 @@ function atLocusKindsInPlay(allKinds) {
|
|
|
298
297
|
return allKinds.filter((facts) => facts.locus.kind === "at");
|
|
299
298
|
}
|
|
300
299
|
/**
|
|
301
|
-
* The distinct
|
|
302
|
-
*
|
|
303
|
-
* off its row, though it governs no glob to be discovered at
|
|
300
|
+
* The distinct kinds in play that take a kind-fact row: every non-embedded locus
|
|
301
|
+
* unconditionally (a nested-file kind owns a file the engine must place, and places it
|
|
302
|
+
* off its row, though it governs no glob to be discovered at), plus an embedded kind
|
|
303
|
+
* only when it declares `guidance` or `cite` of its own (decision 0045) — an embedded
|
|
304
|
+
* kind with neither has nothing for the row to carry, and its members already reach the
|
|
305
|
+
* corpus through their host's `templates` column alone (`kindsInPlay`), never the row.
|
|
304
306
|
*/
|
|
305
|
-
function
|
|
306
|
-
return allKinds.filter((facts) => facts.locus.kind !== "embedded");
|
|
307
|
+
function kindFactKindsInPlay(allKinds) {
|
|
308
|
+
return allKinds.filter((facts) => facts.locus.kind !== "embedded" || facts.guidance !== undefined || facts.cite !== undefined);
|
|
307
309
|
}
|
|
308
310
|
/** The requirement rows — assembly `require` and every member's `requires`, one namespace. */
|
|
309
311
|
function requirementRows(harness) {
|
|
@@ -648,8 +650,10 @@ export function buildTapHookDedupeKey(event, matcher) {
|
|
|
648
650
|
* records every fire and read time joins raw events to members, so however many
|
|
649
651
|
* verifiers name an event it takes exactly one hook — the derived-aggregate precedent
|
|
650
652
|
* the permission union sets ({@link permissionUnion}). Each row runs {@link TAP_COMMAND}
|
|
651
|
-
* under the event's documented matcher ({@link TELEMETRY_EVENT_HOOKS})
|
|
652
|
-
*
|
|
653
|
+
* under the event's documented matcher ({@link TELEMETRY_EVENT_HOOKS}), its key-path and
|
|
654
|
+
* field triple sourced from the provider face ({@link tapHookRegistration},
|
|
655
|
+
* `builtins.ts`); an event-name outside that table is the roster's inadmissibility
|
|
656
|
+
* finding, never a row.
|
|
653
657
|
*/
|
|
654
658
|
export function tapHookRows(harness) {
|
|
655
659
|
const deduped = new Map();
|
|
@@ -670,17 +674,16 @@ export function tapHookRows(harness) {
|
|
|
670
674
|
}
|
|
671
675
|
return [...deduped.values()]
|
|
672
676
|
.sort((a, b) => compareStrings(a.event, b.event) || compareStrings(a.matcher, b.matcher))
|
|
673
|
-
.map(({ event, matcher }) =>
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}));
|
|
677
|
+
.map(({ event, matcher }) => {
|
|
678
|
+
const { keyPath, fields } = tapHookRegistration(TAP_COMMAND, matcher);
|
|
679
|
+
return {
|
|
680
|
+
kind: "hook",
|
|
681
|
+
key: event,
|
|
682
|
+
manifest: SETTINGS_MANIFEST,
|
|
683
|
+
key_path: keyPath,
|
|
684
|
+
fields,
|
|
685
|
+
};
|
|
686
|
+
});
|
|
684
687
|
}
|
|
685
688
|
/**
|
|
686
689
|
* The `settings` rows — the assembly's harness-level residual settings keys, each folded
|
|
@@ -762,7 +765,7 @@ export function compileDeclarations(harness, placements, extents) {
|
|
|
762
765
|
}
|
|
763
766
|
}
|
|
764
767
|
return {
|
|
765
|
-
kinds:
|
|
768
|
+
kinds: kindFactKindsInPlay(allKinds).map((facts) => kindFactRow(facts, admissions)),
|
|
766
769
|
clauses,
|
|
767
770
|
requirements: requirementRows(harness),
|
|
768
771
|
assembly: assemblyFactRows(harness, allKinds),
|
|
@@ -94,7 +94,7 @@ export type Features = {
|
|
|
94
94
|
/**
|
|
95
95
|
* The host member's own **nested members** — its declared [`EmbeddedMember`]s,
|
|
96
96
|
* read off the lock's own `Declarations::nested_members` rows by this member's
|
|
97
|
-
* `kind:name` address ([`nested_members_from_rows`]), never mined from
|
|
97
|
+
* `kind:name` address ([`nested_members_from_rows`](crate::drift::nested_members_from_rows)), never mined from
|
|
98
98
|
* [`fenced_blocks`](Features::fenced_blocks) (0018, "the projection is not the
|
|
99
99
|
* database"). Empty when the lock carries no row for this member.
|
|
100
100
|
*/
|
|
@@ -31,7 +31,7 @@ export type RequirementRow = {
|
|
|
31
31
|
clauses: Array<ClauseRow>;
|
|
32
32
|
/**
|
|
33
33
|
* The typed verifier for the behavioral remainder, when declared — a
|
|
34
|
-
* species-tagged [`Verifier`], resolved at admissibility, never run.
|
|
34
|
+
* species-tagged [`Verifier`](crate::compose::Verifier), resolved at admissibility, never run.
|
|
35
35
|
*/
|
|
36
36
|
verifier?: Verifier;
|
|
37
37
|
/**
|
package/dist/src/index.d.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* Every type erases at the seam, and Turing-completeness
|
|
10
10
|
* stays quarantined at authoring time.
|
|
11
11
|
*
|
|
12
|
-
* The first-party Claude Code provider face — the built-in
|
|
13
|
-
*
|
|
12
|
+
* The first-party Claude Code provider face — the built-in kinds — lives at
|
|
13
|
+
* the `./claude-code` subpath, never here.
|
|
14
14
|
*/
|
|
15
15
|
export type { Blocks, File, Include, Mention, Mentionable, Prose, Reference, Text } from "./prose.js";
|
|
16
16
|
export { blocks, file, include, mentionOf, renderText, text } from "./prose.js";
|
package/dist/src/index.js
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* Every type erases at the seam, and Turing-completeness
|
|
10
10
|
* stays quarantined at authoring time.
|
|
11
11
|
*
|
|
12
|
-
* The first-party Claude Code provider face — the built-in
|
|
13
|
-
*
|
|
12
|
+
* The first-party Claude Code provider face — the built-in kinds — lives at
|
|
13
|
+
* the `./claude-code` subpath, never here.
|
|
14
14
|
*/
|
|
15
15
|
export { blocks, file, include, mentionOf, renderText, text } from "./prose.js";
|
|
16
16
|
export { bash, capability, permissionUnion } from "./needs.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dtmd/temper",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "The temper authoring face — the six-noun model as typed modules: harness(), kind<T>(), clause values, needs, and file()/text/blocks(). Emit compiles to the declaration rows the engine reads, a byte-faithful projection, and the lock.",
|
|
5
5
|
"license": "(MIT OR Apache-2.0)",
|
|
6
6
|
"repository": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"temper": "bin/temper.js"
|
|
53
53
|
},
|
|
54
54
|
"optionalDependencies": {
|
|
55
|
-
"@dtmd/temper-linux-x64": "0.0.
|
|
56
|
-
"@dtmd/temper-win32-x64": "0.0.
|
|
55
|
+
"@dtmd/temper-linux-x64": "0.0.13",
|
|
56
|
+
"@dtmd/temper-win32-x64": "0.0.13"
|
|
57
57
|
}
|
|
58
58
|
}
|