@plaintake/scenario 1.2.1
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/LICENSE +21 -0
- package/README.md +68 -0
- package/dist/define.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +753 -0
- package/dist/schema/errors.d.ts +20 -0
- package/dist/schema/event.d.ts +58 -0
- package/dist/schema/index.d.ts +9 -0
- package/dist/schema/json-schema.d.ts +9 -0
- package/dist/schema/manifest.d.ts +46 -0
- package/dist/schema/render-plan.d.ts +454 -0
- package/dist/schema/results.d.ts +335 -0
- package/dist/schema/scenario.d.ts +89 -0
- package/dist/schema/stable-json.d.ts +4 -0
- package/dist/schema/zod-format.d.ts +8 -0
- package/dist/types.d.ts +194 -0
- package/package.json +29 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const EXIT_CODES: {
|
|
2
|
+
readonly ok: 0;
|
|
3
|
+
readonly assertion: 1;
|
|
4
|
+
readonly usage: 2;
|
|
5
|
+
readonly toolchain: 3;
|
|
6
|
+
readonly capture: 4;
|
|
7
|
+
readonly render: 5;
|
|
8
|
+
readonly verification: 6;
|
|
9
|
+
};
|
|
10
|
+
export type FailureKind = Exclude<keyof typeof EXIT_CODES, 'ok'>;
|
|
11
|
+
/**
|
|
12
|
+
* Satisfies the structural exit-code contract: any thrown error carrying a numeric
|
|
13
|
+
* `exitCode` maps to that process exit code.
|
|
14
|
+
*/
|
|
15
|
+
export declare class DemoError extends Error {
|
|
16
|
+
readonly kind: FailureKind;
|
|
17
|
+
readonly exitCode: number;
|
|
18
|
+
readonly details: Record<string, unknown>;
|
|
19
|
+
constructor(kind: FailureKind, message: string, details?: Record<string, unknown>);
|
|
20
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const DemoEventTypeSchema: z.ZodEnum<{
|
|
3
|
+
"session.start": "session.start";
|
|
4
|
+
"session.finish": "session.finish";
|
|
5
|
+
chapter: "chapter";
|
|
6
|
+
"step.start": "step.start";
|
|
7
|
+
"step.finish": "step.finish";
|
|
8
|
+
"assertion.pass": "assertion.pass";
|
|
9
|
+
"assertion.fail": "assertion.fail";
|
|
10
|
+
"privacy.mask": "privacy.mask";
|
|
11
|
+
"human.wait": "human.wait";
|
|
12
|
+
}>;
|
|
13
|
+
export declare const TargetSchema: z.ZodObject<{
|
|
14
|
+
role: z.ZodOptional<z.ZodString>;
|
|
15
|
+
accessibleName: z.ZodOptional<z.ZodString>;
|
|
16
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
17
|
+
rect: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
x: z.ZodNumber;
|
|
19
|
+
y: z.ZodNumber;
|
|
20
|
+
width: z.ZodNumber;
|
|
21
|
+
height: z.ZodNumber;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
export declare const DemoEventSchema: z.ZodObject<{
|
|
25
|
+
schema: z.ZodLiteral<"agent-demo.event/v1">;
|
|
26
|
+
seq: z.ZodNumber;
|
|
27
|
+
tStartNs: z.ZodString;
|
|
28
|
+
tEndNs: z.ZodOptional<z.ZodString>;
|
|
29
|
+
type: z.ZodEnum<{
|
|
30
|
+
"session.start": "session.start";
|
|
31
|
+
"session.finish": "session.finish";
|
|
32
|
+
chapter: "chapter";
|
|
33
|
+
"step.start": "step.start";
|
|
34
|
+
"step.finish": "step.finish";
|
|
35
|
+
"assertion.pass": "assertion.pass";
|
|
36
|
+
"assertion.fail": "assertion.fail";
|
|
37
|
+
"privacy.mask": "privacy.mask";
|
|
38
|
+
"human.wait": "human.wait";
|
|
39
|
+
}>;
|
|
40
|
+
stableId: z.ZodOptional<z.ZodString>;
|
|
41
|
+
title: z.ZodOptional<z.ZodString>;
|
|
42
|
+
subtitle: z.ZodOptional<z.ZodString>;
|
|
43
|
+
target: z.ZodOptional<z.ZodObject<{
|
|
44
|
+
role: z.ZodOptional<z.ZodString>;
|
|
45
|
+
accessibleName: z.ZodOptional<z.ZodString>;
|
|
46
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
47
|
+
rect: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
x: z.ZodNumber;
|
|
49
|
+
y: z.ZodNumber;
|
|
50
|
+
width: z.ZodNumber;
|
|
51
|
+
height: z.ZodNumber;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
}, z.core.$strip>>;
|
|
54
|
+
payload: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
export type DemoEvent = z.infer<typeof DemoEventSchema>;
|
|
57
|
+
export type DemoEventType = z.infer<typeof DemoEventTypeSchema>;
|
|
58
|
+
export type Target = z.infer<typeof TargetSchema>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './errors.js';
|
|
2
|
+
export * from './event.js';
|
|
3
|
+
export * from './json-schema.js';
|
|
4
|
+
export * from './manifest.js';
|
|
5
|
+
export * from './render-plan.js';
|
|
6
|
+
export * from './results.js';
|
|
7
|
+
export * from './scenario.js';
|
|
8
|
+
export * from './stable-json.js';
|
|
9
|
+
export * from './zod-format.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The published counterpart to `ScenarioMetaSchema`, for an agent or IDE that wants to
|
|
3
|
+
* validate scenario metadata without this package's source or a running `demo_validate`.
|
|
4
|
+
*
|
|
5
|
+
* `io: 'input'` on purpose: a scenario author never supplies `handoff`, `handoffTimeoutMs` or
|
|
6
|
+
* `allowedConsoleErrors`, so the schema a caller validates *against* must mark them optional,
|
|
7
|
+
* even though `ScenarioMeta` (the parsed *output* type) always carries them.
|
|
8
|
+
*/
|
|
9
|
+
export declare function scenarioJsonSchema(): Record<string, unknown>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const BundleManifestSchema: z.ZodObject<{
|
|
3
|
+
schema: z.ZodLiteral<"agent-demo.bundle/v1">;
|
|
4
|
+
status: z.ZodEnum<{
|
|
5
|
+
passed: "passed";
|
|
6
|
+
failed: "failed";
|
|
7
|
+
}>;
|
|
8
|
+
scenario: z.ZodObject<{
|
|
9
|
+
id: z.ZodString;
|
|
10
|
+
sourceSha256: z.ZodString;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
toolchain: z.ZodObject<{
|
|
13
|
+
node: z.ZodString;
|
|
14
|
+
playwright: z.ZodString;
|
|
15
|
+
chromiumRevision: z.ZodString;
|
|
16
|
+
ffmpeg: z.ZodString;
|
|
17
|
+
libass: z.ZodString;
|
|
18
|
+
fontSha256: z.ZodString;
|
|
19
|
+
containerImage: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
environment: z.ZodObject<{
|
|
22
|
+
os: z.ZodString;
|
|
23
|
+
architecture: z.ZodString;
|
|
24
|
+
locale: z.ZodLiteral<"en-US">;
|
|
25
|
+
timezone: z.ZodLiteral<"UTC">;
|
|
26
|
+
viewport: z.ZodTuple<[z.ZodLiteral<1920>, z.ZodLiteral<1080>], null>;
|
|
27
|
+
deviceScaleFactor: z.ZodLiteral<1>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
assertions: z.ZodArray<z.ZodObject<{
|
|
30
|
+
id: z.ZodString;
|
|
31
|
+
status: z.ZodEnum<{
|
|
32
|
+
passed: "passed";
|
|
33
|
+
failed: "failed";
|
|
34
|
+
}>;
|
|
35
|
+
}, z.core.$strip>>;
|
|
36
|
+
artifacts: z.ZodArray<z.ZodObject<{
|
|
37
|
+
path: z.ZodString;
|
|
38
|
+
sha256: z.ZodString;
|
|
39
|
+
bytes: z.ZodNumber;
|
|
40
|
+
role: z.ZodEnum<{
|
|
41
|
+
source: "source";
|
|
42
|
+
derived: "derived";
|
|
43
|
+
}>;
|
|
44
|
+
}, z.core.$strip>>;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
export type BundleManifest = z.infer<typeof BundleManifestSchema>;
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const CueSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
startMs: z.ZodNumber;
|
|
5
|
+
endMs: z.ZodNumber;
|
|
6
|
+
lines: z.ZodArray<z.ZodString>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
/**
|
|
9
|
+
* The closing credit card. Absent means no card, which is a Pro-Tier-only outcome.
|
|
10
|
+
*
|
|
11
|
+
* This lives in the **plan**, not in a licence check inside the renderer, and that is the
|
|
12
|
+
* single most important thing about it. The plan is built once, when the bundle is
|
|
13
|
+
* created, from the licence state at that moment; rendering then executes it verbatim. So
|
|
14
|
+
* a bundle produces the same bytes on a licensed and an unlicensed machine, and
|
|
15
|
+
* `compareRenders`, `refreshManifestArtifacts` and every reproducibility claim keep
|
|
16
|
+
* holding. Reading licence state at render time would have voided all of them.
|
|
17
|
+
*
|
|
18
|
+
* The colour regexes are also the injection guard: these values reach an FFmpeg
|
|
19
|
+
* filtergraph, and on the Pro Tier they come from user configuration. `#RRGGBB` admits no
|
|
20
|
+
* filtergraph metacharacter. The *text* never reaches the filtergraph at all — it goes
|
|
21
|
+
* into `captions/outro.ass`.
|
|
22
|
+
*/
|
|
23
|
+
export declare const OutroSchema: z.ZodObject<{
|
|
24
|
+
durationMs: z.ZodNumber;
|
|
25
|
+
lines: z.ZodArray<z.ZodString>;
|
|
26
|
+
backgroundColor: z.ZodString;
|
|
27
|
+
textColor: z.ZodString;
|
|
28
|
+
assPath: z.ZodLiteral<"captions/outro.ass">;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type Outro = z.infer<typeof OutroSchema>;
|
|
31
|
+
/**
|
|
32
|
+
* The opening card. Absent means the video starts on the recording, which is what every
|
|
33
|
+
* plan before this did and what any scenario declaring no `intro` still does.
|
|
34
|
+
*
|
|
35
|
+
* Structurally the outro's twin, and frozen for the same reason: the plan is built once,
|
|
36
|
+
* when the bundle is created, and rendering executes it verbatim. The colour regexes carry
|
|
37
|
+
* the same duty here — these values reach an FFmpeg filtergraph and `#RRGGBB` admits no
|
|
38
|
+
* metacharacter, while the *text* never goes near it and lands in `captions/intro.ass`.
|
|
39
|
+
*
|
|
40
|
+
* What differs is upstream, not here: the outro's content is decided by the licence, the
|
|
41
|
+
* intro's by the scenario. By the time either reaches the plan that distinction is spent —
|
|
42
|
+
* both are just a card to draw.
|
|
43
|
+
*
|
|
44
|
+
* The spoken hook is **not** in this schema. It is synthesised at record time into
|
|
45
|
+
* `speech/clips/intro.wav` like any step's narration, and reaches the render through
|
|
46
|
+
* `speech` with every other clip. A plan that carried the text would be a plan whose
|
|
47
|
+
* rendering depended on a voice model being installed.
|
|
48
|
+
*/
|
|
49
|
+
export declare const IntroSchema: z.ZodObject<{
|
|
50
|
+
durationMs: z.ZodNumber;
|
|
51
|
+
lines: z.ZodArray<z.ZodString>;
|
|
52
|
+
backgroundColor: z.ZodString;
|
|
53
|
+
textColor: z.ZodString;
|
|
54
|
+
assPath: z.ZodLiteral<"captions/intro.ass">;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
export type Intro = z.infer<typeof IntroSchema>;
|
|
57
|
+
/**
|
|
58
|
+
* One MP4 chapter marker. `endMs` is stored rather than derived from the next mark, so
|
|
59
|
+
* `render/chapters.ffmetadata` is a pure function of the plan and nothing is recomputed at
|
|
60
|
+
* render time — the same reason `ffmpeg` holds literal argument arrays.
|
|
61
|
+
*/
|
|
62
|
+
export declare const ChapterMarkSchema: z.ZodObject<{
|
|
63
|
+
startMs: z.ZodNumber;
|
|
64
|
+
endMs: z.ZodNumber;
|
|
65
|
+
title: z.ZodString;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
/**
|
|
68
|
+
* Chapter markers. Only ever produced on the Pro Tier — but nothing here knows that,
|
|
69
|
+
* and that is the point: the tier decision is taken once when the bundle is created, and the
|
|
70
|
+
* renderer executes what it finds.
|
|
71
|
+
*
|
|
72
|
+
* Unlike the outro's colours, chapter titles are arbitrary scenario text and cannot be
|
|
73
|
+
* restricted to a safe character set. They never reach a filtergraph — they go into
|
|
74
|
+
* `render/chapters.ffmetadata`, which is passed as an `-i` input and where `=`, `;`, `#`,
|
|
75
|
+
* `\` and newline are backslash-escaped.
|
|
76
|
+
*/
|
|
77
|
+
export declare const ChaptersSchema: z.ZodObject<{
|
|
78
|
+
metadataPath: z.ZodLiteral<"render/chapters.ffmetadata">;
|
|
79
|
+
marks: z.ZodArray<z.ZodObject<{
|
|
80
|
+
startMs: z.ZodNumber;
|
|
81
|
+
endMs: z.ZodNumber;
|
|
82
|
+
title: z.ZodString;
|
|
83
|
+
}, z.core.$strip>>;
|
|
84
|
+
}, z.core.$strip>;
|
|
85
|
+
export type Chapters = z.infer<typeof ChaptersSchema>;
|
|
86
|
+
export type ChapterMark = z.infer<typeof ChapterMarkSchema>;
|
|
87
|
+
/**
|
|
88
|
+
* One point on the cursor track. `x`/`y` are the centre of the step's `target`
|
|
89
|
+
* rect, in PlayRes (= viewport) pixels, so the same coordinates libass will draw at.
|
|
90
|
+
* `arriveMs` is when the cursor reaches the point — no later than the step's start, and
|
|
91
|
+
* pulled earlier for clicks so the arrow is parked and visible before it ripples — and
|
|
92
|
+
* `departMs` is when it may leave for the next point, pulled back from the step's finish
|
|
93
|
+
* to leave the glide room. `rippleMs` is when a click's ripple *starts*: the step's own
|
|
94
|
+
* start minus a measured 200ms lead, so the ripple is visibly under way before the
|
|
95
|
+
* screen the click changes — the step start rather than the action end because whatever
|
|
96
|
+
* `run()` awaits after the click is the change itself. Present only on `action: 'click'`
|
|
97
|
+
* points.
|
|
98
|
+
*
|
|
99
|
+
* Like chapter marks, these are stored rather than re-derived from `events/events.ndjson`
|
|
100
|
+
* at render time, so `captions/cursor.ass` is a pure function of the plan — which is also
|
|
101
|
+
* why retiming the derivation was not a compatibility event at all: an older reader
|
|
102
|
+
* executes the same frozen numbers over the same frozen ASS.
|
|
103
|
+
*/
|
|
104
|
+
export declare const CursorPointSchema: z.ZodObject<{
|
|
105
|
+
id: z.ZodString;
|
|
106
|
+
x: z.ZodNumber;
|
|
107
|
+
y: z.ZodNumber;
|
|
108
|
+
arriveMs: z.ZodNumber;
|
|
109
|
+
departMs: z.ZodNumber;
|
|
110
|
+
action: z.ZodEnum<{
|
|
111
|
+
type: "type";
|
|
112
|
+
click: "click";
|
|
113
|
+
point: "point";
|
|
114
|
+
}>;
|
|
115
|
+
rippleMs: z.ZodOptional<z.ZodNumber>;
|
|
116
|
+
scale: z.ZodOptional<z.ZodNumber>;
|
|
117
|
+
}, z.core.$strip>;
|
|
118
|
+
export declare const CursorSchema: z.ZodObject<{
|
|
119
|
+
assPath: z.ZodLiteral<"captions/cursor.ass">;
|
|
120
|
+
points: z.ZodArray<z.ZodObject<{
|
|
121
|
+
id: z.ZodString;
|
|
122
|
+
x: z.ZodNumber;
|
|
123
|
+
y: z.ZodNumber;
|
|
124
|
+
arriveMs: z.ZodNumber;
|
|
125
|
+
departMs: z.ZodNumber;
|
|
126
|
+
action: z.ZodEnum<{
|
|
127
|
+
type: "type";
|
|
128
|
+
click: "click";
|
|
129
|
+
point: "point";
|
|
130
|
+
}>;
|
|
131
|
+
rippleMs: z.ZodOptional<z.ZodNumber>;
|
|
132
|
+
scale: z.ZodOptional<z.ZodNumber>;
|
|
133
|
+
}, z.core.$strip>>;
|
|
134
|
+
}, z.core.$strip>;
|
|
135
|
+
export type Cursor = z.infer<typeof CursorSchema>;
|
|
136
|
+
export type CursorPoint = z.infer<typeof CursorPointSchema>;
|
|
137
|
+
/**
|
|
138
|
+
* One camera window over the source frame. `enterMs` is when the ease INTO this
|
|
139
|
+
* shot starts; `holdFromMs` is when that ease ends and the shot is held. The window is
|
|
140
|
+
* then constant until the next shot's `enterMs`, which is why the list must *tile* the
|
|
141
|
+
* timeline rather than merely sort.
|
|
142
|
+
*/
|
|
143
|
+
export declare const CameraShotSchema: z.ZodObject<{
|
|
144
|
+
id: z.ZodString;
|
|
145
|
+
enterMs: z.ZodNumber;
|
|
146
|
+
holdFromMs: z.ZodNumber;
|
|
147
|
+
x: z.ZodNumber;
|
|
148
|
+
y: z.ZodNumber;
|
|
149
|
+
w: z.ZodNumber;
|
|
150
|
+
h: z.ZodNumber;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
/**
|
|
153
|
+
* The camera. A shot **list**, not frame-sampled
|
|
154
|
+
* keyframes: keyframing the window at 30 fps would add ~190 KB to a plan that is
|
|
155
|
+
* currently ~3 KB, for windows that hold constant for whole seconds. `render/camera.cmd`
|
|
156
|
+
* is generated from these shots at plan-freeze time and then frozen like every other
|
|
157
|
+
* command array, so the renderer stays a pure executor of arguments it does not
|
|
158
|
+
* recompute.
|
|
159
|
+
*
|
|
160
|
+
* The geometry rules below are measured, not stylistic (M10): on `yuv420p`, FFmpeg
|
|
161
|
+
* silently masks odd crop geometry down by a pixel, so a plan freezing an odd `x`/`y`/
|
|
162
|
+
* `w`/`h` would render a window different from the one it froze — the schema rejects
|
|
163
|
+
* loudly instead. `w % 32` is not a separate alignment rule: with `h` pinned to `9w/16`
|
|
164
|
+
* and 9 odd, `h` is even exactly when `w` is a multiple of 32, so it *is* the even-height
|
|
165
|
+
* rule, expressed on `w`. The ladder it implies — windows step down 1920, 1888, 1856, …,
|
|
166
|
+
* one rung ≈ 1.7% of zoom — is the measured granularity of the feature, not an accident
|
|
167
|
+
* to be trimmed.
|
|
168
|
+
*/
|
|
169
|
+
export declare const CameraSchema: z.ZodObject<{
|
|
170
|
+
commandPath: z.ZodLiteral<"render/camera.cmd">;
|
|
171
|
+
shots: z.ZodArray<z.ZodObject<{
|
|
172
|
+
id: z.ZodString;
|
|
173
|
+
enterMs: z.ZodNumber;
|
|
174
|
+
holdFromMs: z.ZodNumber;
|
|
175
|
+
x: z.ZodNumber;
|
|
176
|
+
y: z.ZodNumber;
|
|
177
|
+
w: z.ZodNumber;
|
|
178
|
+
h: z.ZodNumber;
|
|
179
|
+
}, z.core.$strip>>;
|
|
180
|
+
}, z.core.$strip>;
|
|
181
|
+
export type Camera = z.infer<typeof CameraSchema>;
|
|
182
|
+
export type CameraShot = z.infer<typeof CameraShotSchema>;
|
|
183
|
+
/**
|
|
184
|
+
* One frozen narration clip and where it lands on the timeline.
|
|
185
|
+
*
|
|
186
|
+
* `durationMs` is stored rather than measured from the file, for the reason chapter marks
|
|
187
|
+
* store their own `endMs`: it makes `speech/narration.wav` a pure function of the plan, so
|
|
188
|
+
* nothing is re-derived at render time. It is also the number the *timeline* was built from
|
|
189
|
+
* — the recorder held the step open for it — so a file whose length disagrees means the
|
|
190
|
+
* bundle was edited after it was frozen, which is worth failing on rather than papering over.
|
|
191
|
+
*
|
|
192
|
+
* `source` distinguishes a synthesised clip from an author-supplied WAV, because they are the
|
|
193
|
+
* same bytes by the time they reach here and the distinction is not otherwise recoverable.
|
|
194
|
+
*/
|
|
195
|
+
export declare const SpeechClipSchema: z.ZodObject<{
|
|
196
|
+
id: z.ZodString;
|
|
197
|
+
path: z.ZodString;
|
|
198
|
+
atMs: z.ZodNumber;
|
|
199
|
+
durationMs: z.ZodNumber;
|
|
200
|
+
source: z.ZodEnum<{
|
|
201
|
+
file: "file";
|
|
202
|
+
synth: "synth";
|
|
203
|
+
}>;
|
|
204
|
+
}, z.core.$strip>;
|
|
205
|
+
/**
|
|
206
|
+
* What produced the synthesised clips. Evidence only — nothing reads it to make a decision,
|
|
207
|
+
* exactly as `source.durationMs` is evidence only.
|
|
208
|
+
*
|
|
209
|
+
* It earns its place because it is the answer to the one question a frozen audio track cannot
|
|
210
|
+
* otherwise answer: *this bundle sounds different from that one, why?* The voice, the model
|
|
211
|
+
* bytes and the engine version are the three things that can change it, and none of them is
|
|
212
|
+
* recoverable from the WAV.
|
|
213
|
+
*
|
|
214
|
+
* Absent when every clip came from a file, which is why it is optional rather than filled
|
|
215
|
+
* with placeholders — an author-supplied voiceover has no model hash, and inventing one
|
|
216
|
+
* ("unknown", `0`.repeat(64)) would make the field lie in the one case it exists to explain.
|
|
217
|
+
*/
|
|
218
|
+
export declare const SpeechEngineSchema: z.ZodObject<{
|
|
219
|
+
name: z.ZodString;
|
|
220
|
+
version: z.ZodString;
|
|
221
|
+
modelSha256: z.ZodString;
|
|
222
|
+
voice: z.ZodString;
|
|
223
|
+
}, z.core.$strip>;
|
|
224
|
+
/**
|
|
225
|
+
* Spoken narration. Absent means a silent video, which is every plan before this and
|
|
226
|
+
* the default after it.
|
|
227
|
+
*
|
|
228
|
+
* The clips are frozen *and* the mixed track is frozen. That is one more file than strictly
|
|
229
|
+
* needed, and it is deliberate: the clips are what the timeline was derived from — each one's
|
|
230
|
+
* length set its step's hold — so keeping them makes the bundle self-explanatory and lets
|
|
231
|
+
* `verify` hash them, while the mixed track is what FFmpeg muxes. Regenerating the mix from
|
|
232
|
+
* the clips is pure integer arithmetic (`narration.ts`), so the two can never disagree, and
|
|
233
|
+
* `renderBundle` reads the mix without regenerating anything.
|
|
234
|
+
*/
|
|
235
|
+
export declare const SpeechSchema: z.ZodObject<{
|
|
236
|
+
trackPath: z.ZodLiteral<"speech/narration.wav">;
|
|
237
|
+
sampleRate: z.ZodLiteral<24000>;
|
|
238
|
+
channels: z.ZodLiteral<1>;
|
|
239
|
+
clips: z.ZodArray<z.ZodObject<{
|
|
240
|
+
id: z.ZodString;
|
|
241
|
+
path: z.ZodString;
|
|
242
|
+
atMs: z.ZodNumber;
|
|
243
|
+
durationMs: z.ZodNumber;
|
|
244
|
+
source: z.ZodEnum<{
|
|
245
|
+
file: "file";
|
|
246
|
+
synth: "synth";
|
|
247
|
+
}>;
|
|
248
|
+
}, z.core.$strip>>;
|
|
249
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
250
|
+
name: z.ZodString;
|
|
251
|
+
version: z.ZodString;
|
|
252
|
+
modelSha256: z.ZodString;
|
|
253
|
+
voice: z.ZodString;
|
|
254
|
+
}, z.core.$strip>>;
|
|
255
|
+
}, z.core.$strip>;
|
|
256
|
+
export type Speech = z.infer<typeof SpeechSchema>;
|
|
257
|
+
export type SpeechClip = z.infer<typeof SpeechClipSchema>;
|
|
258
|
+
/**
|
|
259
|
+
* The speech decision as the application layer supplies it; `trackPath`, `sampleRate` and
|
|
260
|
+
* `channels` are filled in by `buildRenderPlan`, exactly as `OutroInput` works.
|
|
261
|
+
*/
|
|
262
|
+
export type SpeechInput = Omit<Speech, 'trackPath' | 'sampleRate' | 'channels'>;
|
|
263
|
+
/** The cursor decision as the application layer supplies it; `assPath` is filled in by
|
|
264
|
+
* `buildRenderPlan`, exactly as `OutroInput` and `ChaptersInput` work. */
|
|
265
|
+
export type CursorInput = Omit<Cursor, 'assPath'>;
|
|
266
|
+
/** The chapter decision as the application layer supplies it; `metadataPath` is filled in
|
|
267
|
+
* by `buildRenderPlan`, exactly as `OutroInput` works. */
|
|
268
|
+
export type ChaptersInput = {
|
|
269
|
+
marks: ChapterMark[];
|
|
270
|
+
};
|
|
271
|
+
/** The camera decision as the application layer supplies it; `commandPath` is filled in
|
|
272
|
+
* by `buildRenderPlan`, exactly as `CursorInput` and `ChaptersInput` work. */
|
|
273
|
+
export type CameraInput = Omit<Camera, 'commandPath'>;
|
|
274
|
+
/**
|
|
275
|
+
* The branding decision as the application layer supplies it: everything about the card
|
|
276
|
+
* except where its ASS file lives, which `buildRenderPlan` fills in. Declared here rather
|
|
277
|
+
* than in the renderer so that `@plaintake/license` can produce one without depending
|
|
278
|
+
* on the render path — the direction `renderer-no-license` forbids.
|
|
279
|
+
*/
|
|
280
|
+
export type OutroInput = Omit<Outro, 'assPath'>;
|
|
281
|
+
/** The opening card as the application layer supplies it, exactly as `OutroInput` works. */
|
|
282
|
+
export type IntroInput = Omit<Intro, 'assPath'>;
|
|
283
|
+
/**
|
|
284
|
+
* The one value a plan's `schema` field ever holds.
|
|
285
|
+
*
|
|
286
|
+
* The field names the *document kind* — it is what makes a manifest or a result envelope
|
|
287
|
+
* handed to the renderer fail at the parse instead of three frames into an encode. The
|
|
288
|
+
* `/v1` suffix is frozen, not incremented: capabilities are stated by the plan's own
|
|
289
|
+
* optional fields, which is where they always were.
|
|
290
|
+
*/
|
|
291
|
+
export declare const RENDER_PLAN_SCHEMA = "agent-demo.render/v1";
|
|
292
|
+
/**
|
|
293
|
+
* The frozen render contract. `ffmpeg` holds the exact argument arrays, which is what
|
|
294
|
+
* makes re-rendering a bundle bit-for-bit repeatable without re-deriving anything.
|
|
295
|
+
*
|
|
296
|
+
* **The version ladder this schema once carried has been retired.** It ran `/v1` (nothing) → `/v2`
|
|
297
|
+
* (outro) → `/v3` (chapters) → `/v4` (cursor) → `/v5` (camera), each rung the highest
|
|
298
|
+
* capability a plan used, stamped by `declaredVersion` and cross-checked by a refinement.
|
|
299
|
+
* Three things were wrong with it, and the third is why it went:
|
|
300
|
+
*
|
|
301
|
+
* 1. **It carried no information.** `declaredVersion` was a pure function of `outro`,
|
|
302
|
+
* `chapters`, `cursor` and `camera` — fields sitting in the same object — and the
|
|
303
|
+
* refinement asserted the stamp equalled that function. So the field was a cache of a
|
|
304
|
+
* derivation over its own neighbours, and the refinement was the cache-coherence check.
|
|
305
|
+
* `plan.camera !== undefined` is the capability test; `/v5` was a restatement of it.
|
|
306
|
+
* 2. **It encoded build order, not capability structure.** The four capabilities are
|
|
307
|
+
* independent booleans. A single integer cannot describe sixteen combinations, so `/v5`
|
|
308
|
+
* meant "a camera, and who knows what else" and every new feature had to become the new
|
|
309
|
+
* top rung by definition of having been built last.
|
|
310
|
+
* 3. **It cost forward compatibility rather than buying backward compatibility.** The
|
|
311
|
+
* backward direction — an old plan read by a new build — is carried by the fields being
|
|
312
|
+
* `.optional()`, and always was; the version string did nothing there. The forward
|
|
313
|
+
* direction is where the enum bit: `renderBundle` executes `plan.ffmpeg[variant]`
|
|
314
|
+
* verbatim and never regenerates the derived files, so a bundle from a newer build
|
|
315
|
+
* would have rendered *correctly* on an older one — the frozen arguments already name
|
|
316
|
+
* every input, and the files they name are already in the bundle. The enum refused it
|
|
317
|
+
* first. A marker justified as compatibility was the only thing preventing it.
|
|
318
|
+
*
|
|
319
|
+
* So a plan states its capabilities by carrying them. An unknown *field* is ignored, which
|
|
320
|
+
* is Zod's default and the right one — an older build ignoring `speech` still
|
|
321
|
+
* executes the frozen arguments that mux the frozen WAV. An unknown *document kind* is
|
|
322
|
+
* still rejected, because that is what the field is for.
|
|
323
|
+
*
|
|
324
|
+
* **`/v2`–`/v5` are not accepted.** They are gone rather than tolerated: this is pre-1.0
|
|
325
|
+
* software, a bundle is cheap to re-record, and a list of five strings where four exist only
|
|
326
|
+
* to be inert is the kind of thing that outlives the reason for it. A plan carrying one now
|
|
327
|
+
* fails at the parse, naming the value it should have — which is a better outcome than the
|
|
328
|
+
* ladder's, where the same bundle failed while carrying arguments that would have rendered.
|
|
329
|
+
*
|
|
330
|
+
* A plan using no optional capability remains byte-identical to what every earlier version
|
|
331
|
+
* produced, so `scripts/make-golden-bundle.sh` regenerates the committed golden bundle
|
|
332
|
+
* exactly — the version string was already `/v1` there.
|
|
333
|
+
*/
|
|
334
|
+
export declare const RenderPlanSchema: z.ZodObject<{
|
|
335
|
+
schema: z.ZodLiteral<"agent-demo.render/v1">;
|
|
336
|
+
source: z.ZodObject<{
|
|
337
|
+
path: z.ZodLiteral<"raw/session.webm">;
|
|
338
|
+
sha256: z.ZodString;
|
|
339
|
+
durationMs: z.ZodNumber;
|
|
340
|
+
}, z.core.$strip>;
|
|
341
|
+
video: z.ZodObject<{
|
|
342
|
+
width: z.ZodLiteral<1920>;
|
|
343
|
+
height: z.ZodLiteral<1080>;
|
|
344
|
+
fps: z.ZodLiteral<30>;
|
|
345
|
+
pixelFormat: z.ZodLiteral<"yuv420p">;
|
|
346
|
+
durationMs: z.ZodNumber;
|
|
347
|
+
tailPadMs: z.ZodNumber;
|
|
348
|
+
}, z.core.$strip>;
|
|
349
|
+
captions: z.ZodObject<{
|
|
350
|
+
language: z.ZodString;
|
|
351
|
+
srtPath: z.ZodLiteral<"captions/captions.srt">;
|
|
352
|
+
vttPath: z.ZodLiteral<"captions/captions.vtt">;
|
|
353
|
+
assPath: z.ZodLiteral<"captions/captions.ass">;
|
|
354
|
+
cues: z.ZodArray<z.ZodObject<{
|
|
355
|
+
id: z.ZodString;
|
|
356
|
+
startMs: z.ZodNumber;
|
|
357
|
+
endMs: z.ZodNumber;
|
|
358
|
+
lines: z.ZodArray<z.ZodString>;
|
|
359
|
+
}, z.core.$strip>>;
|
|
360
|
+
}, z.core.$strip>;
|
|
361
|
+
style: z.ZodObject<{
|
|
362
|
+
fontFile: z.ZodLiteral<"assets/fonts/NotoSans-Regular.ttf">;
|
|
363
|
+
fontName: z.ZodLiteral<"Noto Sans">;
|
|
364
|
+
fontSize: z.ZodNumber;
|
|
365
|
+
textColor: z.ZodString;
|
|
366
|
+
outlineColor: z.ZodString;
|
|
367
|
+
outlineWidth: z.ZodNumber;
|
|
368
|
+
marginBottom: z.ZodNumber;
|
|
369
|
+
marginSide: z.ZodDefault<z.ZodNumber>;
|
|
370
|
+
borderStyle: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<4>]>>;
|
|
371
|
+
outlineOpacity: z.ZodDefault<z.ZodNumber>;
|
|
372
|
+
boxColor: z.ZodDefault<z.ZodString>;
|
|
373
|
+
boxOpacity: z.ZodDefault<z.ZodNumber>;
|
|
374
|
+
}, z.core.$strip>;
|
|
375
|
+
ffmpeg: z.ZodObject<{
|
|
376
|
+
base: z.ZodArray<z.ZodString>;
|
|
377
|
+
soft: z.ZodArray<z.ZodString>;
|
|
378
|
+
hard: z.ZodArray<z.ZodString>;
|
|
379
|
+
}, z.core.$strip>;
|
|
380
|
+
intro: z.ZodOptional<z.ZodObject<{
|
|
381
|
+
durationMs: z.ZodNumber;
|
|
382
|
+
lines: z.ZodArray<z.ZodString>;
|
|
383
|
+
backgroundColor: z.ZodString;
|
|
384
|
+
textColor: z.ZodString;
|
|
385
|
+
assPath: z.ZodLiteral<"captions/intro.ass">;
|
|
386
|
+
}, z.core.$strip>>;
|
|
387
|
+
outro: z.ZodOptional<z.ZodObject<{
|
|
388
|
+
durationMs: z.ZodNumber;
|
|
389
|
+
lines: z.ZodArray<z.ZodString>;
|
|
390
|
+
backgroundColor: z.ZodString;
|
|
391
|
+
textColor: z.ZodString;
|
|
392
|
+
assPath: z.ZodLiteral<"captions/outro.ass">;
|
|
393
|
+
}, z.core.$strip>>;
|
|
394
|
+
chapters: z.ZodOptional<z.ZodObject<{
|
|
395
|
+
metadataPath: z.ZodLiteral<"render/chapters.ffmetadata">;
|
|
396
|
+
marks: z.ZodArray<z.ZodObject<{
|
|
397
|
+
startMs: z.ZodNumber;
|
|
398
|
+
endMs: z.ZodNumber;
|
|
399
|
+
title: z.ZodString;
|
|
400
|
+
}, z.core.$strip>>;
|
|
401
|
+
}, z.core.$strip>>;
|
|
402
|
+
cursor: z.ZodOptional<z.ZodObject<{
|
|
403
|
+
assPath: z.ZodLiteral<"captions/cursor.ass">;
|
|
404
|
+
points: z.ZodArray<z.ZodObject<{
|
|
405
|
+
id: z.ZodString;
|
|
406
|
+
x: z.ZodNumber;
|
|
407
|
+
y: z.ZodNumber;
|
|
408
|
+
arriveMs: z.ZodNumber;
|
|
409
|
+
departMs: z.ZodNumber;
|
|
410
|
+
action: z.ZodEnum<{
|
|
411
|
+
type: "type";
|
|
412
|
+
click: "click";
|
|
413
|
+
point: "point";
|
|
414
|
+
}>;
|
|
415
|
+
rippleMs: z.ZodOptional<z.ZodNumber>;
|
|
416
|
+
scale: z.ZodOptional<z.ZodNumber>;
|
|
417
|
+
}, z.core.$strip>>;
|
|
418
|
+
}, z.core.$strip>>;
|
|
419
|
+
camera: z.ZodOptional<z.ZodObject<{
|
|
420
|
+
commandPath: z.ZodLiteral<"render/camera.cmd">;
|
|
421
|
+
shots: z.ZodArray<z.ZodObject<{
|
|
422
|
+
id: z.ZodString;
|
|
423
|
+
enterMs: z.ZodNumber;
|
|
424
|
+
holdFromMs: z.ZodNumber;
|
|
425
|
+
x: z.ZodNumber;
|
|
426
|
+
y: z.ZodNumber;
|
|
427
|
+
w: z.ZodNumber;
|
|
428
|
+
h: z.ZodNumber;
|
|
429
|
+
}, z.core.$strip>>;
|
|
430
|
+
}, z.core.$strip>>;
|
|
431
|
+
speech: z.ZodOptional<z.ZodObject<{
|
|
432
|
+
trackPath: z.ZodLiteral<"speech/narration.wav">;
|
|
433
|
+
sampleRate: z.ZodLiteral<24000>;
|
|
434
|
+
channels: z.ZodLiteral<1>;
|
|
435
|
+
clips: z.ZodArray<z.ZodObject<{
|
|
436
|
+
id: z.ZodString;
|
|
437
|
+
path: z.ZodString;
|
|
438
|
+
atMs: z.ZodNumber;
|
|
439
|
+
durationMs: z.ZodNumber;
|
|
440
|
+
source: z.ZodEnum<{
|
|
441
|
+
file: "file";
|
|
442
|
+
synth: "synth";
|
|
443
|
+
}>;
|
|
444
|
+
}, z.core.$strip>>;
|
|
445
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
446
|
+
name: z.ZodString;
|
|
447
|
+
version: z.ZodString;
|
|
448
|
+
modelSha256: z.ZodString;
|
|
449
|
+
voice: z.ZodString;
|
|
450
|
+
}, z.core.$strip>>;
|
|
451
|
+
}, z.core.$strip>>;
|
|
452
|
+
}, z.core.$strip>;
|
|
453
|
+
export type RenderPlan = z.infer<typeof RenderPlanSchema>;
|
|
454
|
+
export type Cue = z.infer<typeof CueSchema>;
|