@wzrdtech/core 0.2.0 → 0.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/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/manifest.d.ts +12 -0
- package/dist/manifest.js +40 -0
- package/dist/planner.d.ts +18 -0
- package/dist/planner.js +61 -0
- package/dist/schema.d.ts +292 -0
- package/dist/schema.js +194 -0
- package/package.json +26 -5
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type SkillManifestEntry = {
|
|
2
|
+
fileCount: number;
|
|
3
|
+
hash: string;
|
|
4
|
+
path: string;
|
|
5
|
+
skill: string;
|
|
6
|
+
};
|
|
7
|
+
export type SkillManifest = {
|
|
8
|
+
generatedAt: string;
|
|
9
|
+
skills: SkillManifestEntry[];
|
|
10
|
+
version: 1;
|
|
11
|
+
};
|
|
12
|
+
export declare function generateSkillManifest(skillsDir: string): Promise<SkillManifest>;
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export async function generateSkillManifest(skillsDir) {
|
|
5
|
+
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
6
|
+
const skills = [];
|
|
7
|
+
for (const entry of entries) {
|
|
8
|
+
if (!entry.isDirectory())
|
|
9
|
+
continue;
|
|
10
|
+
const root = path.join(skillsDir, entry.name);
|
|
11
|
+
const files = await listFiles(root);
|
|
12
|
+
const hash = createHash("sha256");
|
|
13
|
+
for (const file of files) {
|
|
14
|
+
const relative = path.relative(root, file);
|
|
15
|
+
hash.update(relative);
|
|
16
|
+
hash.update(await fs.readFile(file));
|
|
17
|
+
}
|
|
18
|
+
skills.push({
|
|
19
|
+
fileCount: files.length,
|
|
20
|
+
hash: hash.digest("hex"),
|
|
21
|
+
path: path.relative(process.cwd(), root),
|
|
22
|
+
skill: entry.name,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
generatedAt: new Date().toISOString(),
|
|
27
|
+
skills: skills.sort((left, right) => left.skill.localeCompare(right.skill)),
|
|
28
|
+
version: 1,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function listFiles(root) {
|
|
32
|
+
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
33
|
+
const files = await Promise.all(entries.map(async (entry) => {
|
|
34
|
+
const fullPath = path.join(root, entry.name);
|
|
35
|
+
if (entry.isDirectory())
|
|
36
|
+
return listFiles(fullPath);
|
|
37
|
+
return [fullPath];
|
|
38
|
+
}));
|
|
39
|
+
return files.flat().sort();
|
|
40
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ZapSpec, ZapStep } from "./schema.js";
|
|
2
|
+
export type PlannedZapStep = ZapStep & {
|
|
3
|
+
originalId: string;
|
|
4
|
+
repeatIndex?: number;
|
|
5
|
+
};
|
|
6
|
+
export type ZapPlan = {
|
|
7
|
+
budgetCapUsd: number;
|
|
8
|
+
estimateUsd: number;
|
|
9
|
+
extendCount: number;
|
|
10
|
+
steps: PlannedZapStep[];
|
|
11
|
+
zap: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function planZapRun(zap: ZapSpec, extendCount: number): ZapPlan;
|
|
14
|
+
export declare function assertWithinBudget(plan: ZapPlan): void;
|
|
15
|
+
export declare function validateRequiredInputs(zap: ZapSpec, inputs: Record<string, unknown>): void;
|
|
16
|
+
export declare function isLocalStep(step: ZapStep): boolean;
|
|
17
|
+
export declare function quoteStep(step: ZapStep): number;
|
|
18
|
+
export declare function expandRepeatSteps(zap: ZapSpec, extendCount: number): PlannedZapStep[];
|
package/dist/planner.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const modelRates = {
|
|
2
|
+
"fal-ai/flux/dev": { perRequest: 0.03 },
|
|
3
|
+
"fal-ai/kling-video/v2.1/pro/image-to-video": { perSecond: 0.28 },
|
|
4
|
+
"fal-ai/veo3.1": { perSecond: 0.45 },
|
|
5
|
+
"gemini-omni-flash-preview": { perSecond: 0.1 },
|
|
6
|
+
"happyhorse-1.1-i2v": { perSecond: 0.28 },
|
|
7
|
+
"seedance-2-0-260128": { perSecond: 0.07 },
|
|
8
|
+
"seedance-2-0-260128-upscale": { perSecond: 0.056 },
|
|
9
|
+
};
|
|
10
|
+
export function planZapRun(zap, extendCount) {
|
|
11
|
+
const steps = expandRepeatSteps(zap, extendCount);
|
|
12
|
+
const estimateUsd = steps.reduce((sum, step) => sum + quoteStep(step), 0);
|
|
13
|
+
return {
|
|
14
|
+
budgetCapUsd: zap.budget.cap_usd,
|
|
15
|
+
estimateUsd,
|
|
16
|
+
extendCount,
|
|
17
|
+
steps,
|
|
18
|
+
zap: zap.zap,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function assertWithinBudget(plan) {
|
|
22
|
+
if (plan.estimateUsd > plan.budgetCapUsd) {
|
|
23
|
+
throw new Error(`Run quote $${plan.estimateUsd.toFixed(2)} exceeds recipe cap $${plan.budgetCapUsd}.`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function validateRequiredInputs(zap, inputs) {
|
|
27
|
+
for (const [name, spec] of Object.entries(zap.inputs)) {
|
|
28
|
+
if (spec.required && inputs[name] === undefined) {
|
|
29
|
+
throw new Error(`Missing required input ${name}.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function isLocalStep(step) {
|
|
34
|
+
return step.kind === "stitch" || step.kind === "keyframes";
|
|
35
|
+
}
|
|
36
|
+
export function quoteStep(step) {
|
|
37
|
+
if (isLocalStep(step))
|
|
38
|
+
return 0;
|
|
39
|
+
const model = step.model ?? "local";
|
|
40
|
+
const rate = modelRates[model];
|
|
41
|
+
if (!rate)
|
|
42
|
+
return 0;
|
|
43
|
+
if (rate.perRequest !== undefined)
|
|
44
|
+
return rate.perRequest;
|
|
45
|
+
return (rate.perSecond ?? 0) * (step.duration_s ?? 1);
|
|
46
|
+
}
|
|
47
|
+
export function expandRepeatSteps(zap, extendCount) {
|
|
48
|
+
return zap.steps.flatMap((step) => {
|
|
49
|
+
if (step.kind !== "video.extend")
|
|
50
|
+
return [{ ...step, originalId: step.id }];
|
|
51
|
+
const max = step.repeat?.max ?? 64;
|
|
52
|
+
const min = step.repeat?.min ?? 0;
|
|
53
|
+
const count = Math.max(min, Math.min(extendCount, max));
|
|
54
|
+
return Array.from({ length: count }, (_, index) => ({
|
|
55
|
+
...step,
|
|
56
|
+
id: `${step.id}_${index + 1}`,
|
|
57
|
+
originalId: step.id,
|
|
58
|
+
repeatIndex: index + 1,
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare class ZapSchemaError extends Error {
|
|
3
|
+
readonly code = "SCHEMA_INVALID";
|
|
4
|
+
readonly retryable = false;
|
|
5
|
+
}
|
|
6
|
+
export declare const zapInputSchema: z.ZodObject<{
|
|
7
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
8
|
+
label: z.ZodOptional<z.ZodString>;
|
|
9
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
10
|
+
required: z.ZodDefault<z.ZodBoolean>;
|
|
11
|
+
type: z.ZodEnum<{
|
|
12
|
+
string: "string";
|
|
13
|
+
number: "number";
|
|
14
|
+
textarea: "textarea";
|
|
15
|
+
image: "image";
|
|
16
|
+
video: "video";
|
|
17
|
+
select: "select";
|
|
18
|
+
}>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
export declare const zapStepKindSchema: z.ZodEnum<{
|
|
21
|
+
"image.gen": "image.gen";
|
|
22
|
+
"image.edit": "image.edit";
|
|
23
|
+
"video.gen": "video.gen";
|
|
24
|
+
"video.extend": "video.extend";
|
|
25
|
+
"video.edit": "video.edit";
|
|
26
|
+
"video.upscale": "video.upscale";
|
|
27
|
+
"audio.tts": "audio.tts";
|
|
28
|
+
"audio.music": "audio.music";
|
|
29
|
+
"audio.sfx": "audio.sfx";
|
|
30
|
+
keyframes: "keyframes";
|
|
31
|
+
stitch: "stitch";
|
|
32
|
+
}>;
|
|
33
|
+
export declare const zapProviderSchema: z.ZodEnum<{
|
|
34
|
+
gmi: "gmi";
|
|
35
|
+
fal: "fal";
|
|
36
|
+
prodia: "prodia";
|
|
37
|
+
runware: "runware";
|
|
38
|
+
}>;
|
|
39
|
+
export type ZapProvider = z.infer<typeof zapProviderSchema>;
|
|
40
|
+
export declare const zapStitchSchema: z.ZodDefault<z.ZodObject<{
|
|
41
|
+
engine: z.ZodDefault<z.ZodEnum<{
|
|
42
|
+
auto: "auto";
|
|
43
|
+
local: "local";
|
|
44
|
+
hyperframes: "hyperframes";
|
|
45
|
+
}>>;
|
|
46
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
47
|
+
format: z.ZodDefault<z.ZodEnum<{
|
|
48
|
+
mp4: "mp4";
|
|
49
|
+
webm: "webm";
|
|
50
|
+
}>>;
|
|
51
|
+
quality: z.ZodDefault<z.ZodEnum<{
|
|
52
|
+
draft: "draft";
|
|
53
|
+
standard: "standard";
|
|
54
|
+
high: "high";
|
|
55
|
+
}>>;
|
|
56
|
+
}, z.core.$strip>>;
|
|
57
|
+
export declare const zapStepSchema: z.ZodObject<{
|
|
58
|
+
audio: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
59
|
+
candidates: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
duration_s: z.ZodOptional<z.ZodNumber>;
|
|
61
|
+
extend: z.ZodOptional<z.ZodObject<{
|
|
62
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
63
|
+
chain: "chain";
|
|
64
|
+
anchored: "anchored";
|
|
65
|
+
}>>;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
first_frame: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
68
|
+
id: z.ZodString;
|
|
69
|
+
inputs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
70
|
+
judge: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
71
|
+
keyframes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
72
|
+
kind: z.ZodEnum<{
|
|
73
|
+
"image.gen": "image.gen";
|
|
74
|
+
"image.edit": "image.edit";
|
|
75
|
+
"video.gen": "video.gen";
|
|
76
|
+
"video.extend": "video.extend";
|
|
77
|
+
"video.edit": "video.edit";
|
|
78
|
+
"video.upscale": "video.upscale";
|
|
79
|
+
"audio.tts": "audio.tts";
|
|
80
|
+
"audio.music": "audio.music";
|
|
81
|
+
"audio.sfx": "audio.sfx";
|
|
82
|
+
keyframes: "keyframes";
|
|
83
|
+
stitch: "stitch";
|
|
84
|
+
}>;
|
|
85
|
+
model: z.ZodOptional<z.ZodString>;
|
|
86
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
87
|
+
provider: z.ZodOptional<z.ZodEnum<{
|
|
88
|
+
gmi: "gmi";
|
|
89
|
+
fal: "fal";
|
|
90
|
+
prodia: "prodia";
|
|
91
|
+
runware: "runware";
|
|
92
|
+
}>>;
|
|
93
|
+
reference_images: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
94
|
+
repeat: z.ZodOptional<z.ZodObject<{
|
|
95
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
96
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
97
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
98
|
+
}, z.core.$strip>>;
|
|
99
|
+
retry: z.ZodOptional<z.ZodObject<{
|
|
100
|
+
backoff_s: z.ZodDefault<z.ZodNumber>;
|
|
101
|
+
fallback_model: z.ZodOptional<z.ZodString>;
|
|
102
|
+
fallback_provider: z.ZodOptional<z.ZodEnum<{
|
|
103
|
+
gmi: "gmi";
|
|
104
|
+
fal: "fal";
|
|
105
|
+
prodia: "prodia";
|
|
106
|
+
runware: "runware";
|
|
107
|
+
}>>;
|
|
108
|
+
max: z.ZodDefault<z.ZodNumber>;
|
|
109
|
+
}, z.core.$strip>>;
|
|
110
|
+
rlhf: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"optional">, z.ZodBoolean]>>;
|
|
111
|
+
shared: z.ZodOptional<z.ZodBoolean>;
|
|
112
|
+
stitch: z.ZodOptional<z.ZodDefault<z.ZodObject<{
|
|
113
|
+
engine: z.ZodDefault<z.ZodEnum<{
|
|
114
|
+
auto: "auto";
|
|
115
|
+
local: "local";
|
|
116
|
+
hyperframes: "hyperframes";
|
|
117
|
+
}>>;
|
|
118
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
119
|
+
format: z.ZodDefault<z.ZodEnum<{
|
|
120
|
+
mp4: "mp4";
|
|
121
|
+
webm: "webm";
|
|
122
|
+
}>>;
|
|
123
|
+
quality: z.ZodDefault<z.ZodEnum<{
|
|
124
|
+
draft: "draft";
|
|
125
|
+
standard: "standard";
|
|
126
|
+
high: "high";
|
|
127
|
+
}>>;
|
|
128
|
+
}, z.core.$strip>>>;
|
|
129
|
+
tier: z.ZodOptional<z.ZodEnum<{
|
|
130
|
+
draft: "draft";
|
|
131
|
+
final: "final";
|
|
132
|
+
}>>;
|
|
133
|
+
}, z.core.$strip>;
|
|
134
|
+
export declare const zapPublishSchema: z.ZodOptional<z.ZodObject<{
|
|
135
|
+
embed: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
136
|
+
allowOrigins: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
137
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
138
|
+
height: z.ZodDefault<z.ZodNumber>;
|
|
139
|
+
theme: z.ZodDefault<z.ZodEnum<{
|
|
140
|
+
auto: "auto";
|
|
141
|
+
dark: "dark";
|
|
142
|
+
light: "light";
|
|
143
|
+
}>>;
|
|
144
|
+
width: z.ZodDefault<z.ZodNumber>;
|
|
145
|
+
}, z.core.$strip>>>;
|
|
146
|
+
slug: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
147
|
+
visibility: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
|
|
148
|
+
public: "public";
|
|
149
|
+
unlisted: "unlisted";
|
|
150
|
+
private: "private";
|
|
151
|
+
}>>>;
|
|
152
|
+
}, z.core.$strip>>;
|
|
153
|
+
export declare const zapSpecSchema: z.ZodObject<{
|
|
154
|
+
budget: z.ZodObject<{
|
|
155
|
+
cap_usd: z.ZodNumber;
|
|
156
|
+
estimate_usd: z.ZodNumber;
|
|
157
|
+
}, z.core.$strip>;
|
|
158
|
+
defaults: z.ZodDefault<z.ZodObject<{
|
|
159
|
+
aspect: z.ZodOptional<z.ZodString>;
|
|
160
|
+
models: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
161
|
+
provider: z.ZodDefault<z.ZodEnum<{
|
|
162
|
+
gmi: "gmi";
|
|
163
|
+
fal: "fal";
|
|
164
|
+
prodia: "prodia";
|
|
165
|
+
runware: "runware";
|
|
166
|
+
}>>;
|
|
167
|
+
}, z.core.$strip>>;
|
|
168
|
+
description: z.ZodString;
|
|
169
|
+
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
170
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
171
|
+
label: z.ZodOptional<z.ZodString>;
|
|
172
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
173
|
+
required: z.ZodDefault<z.ZodBoolean>;
|
|
174
|
+
type: z.ZodEnum<{
|
|
175
|
+
string: "string";
|
|
176
|
+
number: "number";
|
|
177
|
+
textarea: "textarea";
|
|
178
|
+
image: "image";
|
|
179
|
+
video: "video";
|
|
180
|
+
select: "select";
|
|
181
|
+
}>;
|
|
182
|
+
}, z.core.$strip>>>;
|
|
183
|
+
output: z.ZodDefault<z.ZodString>;
|
|
184
|
+
publish: z.ZodOptional<z.ZodObject<{
|
|
185
|
+
embed: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
186
|
+
allowOrigins: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
187
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
188
|
+
height: z.ZodDefault<z.ZodNumber>;
|
|
189
|
+
theme: z.ZodDefault<z.ZodEnum<{
|
|
190
|
+
auto: "auto";
|
|
191
|
+
dark: "dark";
|
|
192
|
+
light: "light";
|
|
193
|
+
}>>;
|
|
194
|
+
width: z.ZodDefault<z.ZodNumber>;
|
|
195
|
+
}, z.core.$strip>>>;
|
|
196
|
+
slug: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
197
|
+
visibility: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
|
|
198
|
+
public: "public";
|
|
199
|
+
unlisted: "unlisted";
|
|
200
|
+
private: "private";
|
|
201
|
+
}>>>;
|
|
202
|
+
}, z.core.$strip>>;
|
|
203
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
204
|
+
audio: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
205
|
+
candidates: z.ZodOptional<z.ZodNumber>;
|
|
206
|
+
duration_s: z.ZodOptional<z.ZodNumber>;
|
|
207
|
+
extend: z.ZodOptional<z.ZodObject<{
|
|
208
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
209
|
+
chain: "chain";
|
|
210
|
+
anchored: "anchored";
|
|
211
|
+
}>>;
|
|
212
|
+
}, z.core.$strip>>;
|
|
213
|
+
first_frame: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
214
|
+
id: z.ZodString;
|
|
215
|
+
inputs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
216
|
+
judge: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
217
|
+
keyframes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
218
|
+
kind: z.ZodEnum<{
|
|
219
|
+
"image.gen": "image.gen";
|
|
220
|
+
"image.edit": "image.edit";
|
|
221
|
+
"video.gen": "video.gen";
|
|
222
|
+
"video.extend": "video.extend";
|
|
223
|
+
"video.edit": "video.edit";
|
|
224
|
+
"video.upscale": "video.upscale";
|
|
225
|
+
"audio.tts": "audio.tts";
|
|
226
|
+
"audio.music": "audio.music";
|
|
227
|
+
"audio.sfx": "audio.sfx";
|
|
228
|
+
keyframes: "keyframes";
|
|
229
|
+
stitch: "stitch";
|
|
230
|
+
}>;
|
|
231
|
+
model: z.ZodOptional<z.ZodString>;
|
|
232
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
233
|
+
provider: z.ZodOptional<z.ZodEnum<{
|
|
234
|
+
gmi: "gmi";
|
|
235
|
+
fal: "fal";
|
|
236
|
+
prodia: "prodia";
|
|
237
|
+
runware: "runware";
|
|
238
|
+
}>>;
|
|
239
|
+
reference_images: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
240
|
+
repeat: z.ZodOptional<z.ZodObject<{
|
|
241
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
242
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
243
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
244
|
+
}, z.core.$strip>>;
|
|
245
|
+
retry: z.ZodOptional<z.ZodObject<{
|
|
246
|
+
backoff_s: z.ZodDefault<z.ZodNumber>;
|
|
247
|
+
fallback_model: z.ZodOptional<z.ZodString>;
|
|
248
|
+
fallback_provider: z.ZodOptional<z.ZodEnum<{
|
|
249
|
+
gmi: "gmi";
|
|
250
|
+
fal: "fal";
|
|
251
|
+
prodia: "prodia";
|
|
252
|
+
runware: "runware";
|
|
253
|
+
}>>;
|
|
254
|
+
max: z.ZodDefault<z.ZodNumber>;
|
|
255
|
+
}, z.core.$strip>>;
|
|
256
|
+
rlhf: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"optional">, z.ZodBoolean]>>;
|
|
257
|
+
shared: z.ZodOptional<z.ZodBoolean>;
|
|
258
|
+
stitch: z.ZodOptional<z.ZodDefault<z.ZodObject<{
|
|
259
|
+
engine: z.ZodDefault<z.ZodEnum<{
|
|
260
|
+
auto: "auto";
|
|
261
|
+
local: "local";
|
|
262
|
+
hyperframes: "hyperframes";
|
|
263
|
+
}>>;
|
|
264
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
265
|
+
format: z.ZodDefault<z.ZodEnum<{
|
|
266
|
+
mp4: "mp4";
|
|
267
|
+
webm: "webm";
|
|
268
|
+
}>>;
|
|
269
|
+
quality: z.ZodDefault<z.ZodEnum<{
|
|
270
|
+
draft: "draft";
|
|
271
|
+
standard: "standard";
|
|
272
|
+
high: "high";
|
|
273
|
+
}>>;
|
|
274
|
+
}, z.core.$strip>>>;
|
|
275
|
+
tier: z.ZodOptional<z.ZodEnum<{
|
|
276
|
+
draft: "draft";
|
|
277
|
+
final: "final";
|
|
278
|
+
}>>;
|
|
279
|
+
}, z.core.$strip>>;
|
|
280
|
+
version: z.ZodLiteral<2>;
|
|
281
|
+
zap: z.ZodString;
|
|
282
|
+
}, z.core.$strip>;
|
|
283
|
+
export type ZapInput = z.infer<typeof zapInputSchema>;
|
|
284
|
+
export type ZapStep = z.infer<typeof zapStepSchema>;
|
|
285
|
+
export type ZapStepKind = z.infer<typeof zapStepKindSchema>;
|
|
286
|
+
export type ZapSpec = z.infer<typeof zapSpecSchema>;
|
|
287
|
+
export type PublicZapSpec = ZapSpec & {
|
|
288
|
+
title: string;
|
|
289
|
+
};
|
|
290
|
+
export declare function parseZapMarkdown(markdown: string): ZapSpec;
|
|
291
|
+
export declare function validateZapPromptTemplates(spec: ZapSpec, promptContents: Record<string, string>): void;
|
|
292
|
+
export declare function publicZapSpec(spec: ZapSpec): PublicZapSpec;
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { parseDocument } from "yaml";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export class ZapSchemaError extends Error {
|
|
4
|
+
code = "SCHEMA_INVALID";
|
|
5
|
+
retryable = false;
|
|
6
|
+
}
|
|
7
|
+
export const zapInputSchema = z.object({
|
|
8
|
+
hint: z.string().optional(),
|
|
9
|
+
label: z.string().optional(),
|
|
10
|
+
options: z.array(z.string()).optional(),
|
|
11
|
+
required: z.boolean().default(false),
|
|
12
|
+
type: z.enum(["string", "textarea", "image", "video", "select", "number"]),
|
|
13
|
+
});
|
|
14
|
+
export const zapStepKindSchema = z.enum([
|
|
15
|
+
"image.gen",
|
|
16
|
+
"image.edit",
|
|
17
|
+
"video.gen",
|
|
18
|
+
"video.extend",
|
|
19
|
+
"video.edit",
|
|
20
|
+
"video.upscale",
|
|
21
|
+
"audio.tts",
|
|
22
|
+
"audio.music",
|
|
23
|
+
"audio.sfx",
|
|
24
|
+
"keyframes",
|
|
25
|
+
"stitch",
|
|
26
|
+
]);
|
|
27
|
+
export const zapProviderSchema = z.enum(["gmi", "fal", "prodia", "runware"]);
|
|
28
|
+
export const zapStitchSchema = z.object({
|
|
29
|
+
engine: z.enum(["auto", "local", "hyperframes"]).default("auto"),
|
|
30
|
+
fps: z.number().int().min(1).max(120).optional(),
|
|
31
|
+
format: z.enum(["mp4", "webm"]).default("mp4"),
|
|
32
|
+
quality: z.enum(["draft", "standard", "high"]).default("standard"),
|
|
33
|
+
}).default({ engine: "auto", format: "mp4", quality: "standard" });
|
|
34
|
+
export const zapStepSchema = z.object({
|
|
35
|
+
audio: z.record(z.string(), z.unknown()).optional(),
|
|
36
|
+
candidates: z.number().int().min(1).max(16).optional(),
|
|
37
|
+
duration_s: z.number().positive().optional(),
|
|
38
|
+
extend: z.object({ mode: z.enum(["chain", "anchored"]).default("chain") }).optional(),
|
|
39
|
+
first_frame: z.record(z.string(), z.unknown()).optional(),
|
|
40
|
+
id: z.string().min(1),
|
|
41
|
+
inputs: z.array(z.string()).optional(),
|
|
42
|
+
judge: z.record(z.string(), z.unknown()).optional(),
|
|
43
|
+
keyframes: z.record(z.string(), z.unknown()).optional(),
|
|
44
|
+
kind: zapStepKindSchema,
|
|
45
|
+
model: z.string().optional(),
|
|
46
|
+
prompt: z.string().optional(),
|
|
47
|
+
provider: zapProviderSchema.optional(),
|
|
48
|
+
reference_images: z.array(z.string()).optional(),
|
|
49
|
+
repeat: z.object({
|
|
50
|
+
default: z.number().int().min(0).optional(),
|
|
51
|
+
max: z.number().int().min(0).max(64).optional(),
|
|
52
|
+
min: z.number().int().min(0).optional(),
|
|
53
|
+
}).optional(),
|
|
54
|
+
retry: z.object({
|
|
55
|
+
backoff_s: z.number().min(0).max(300).default(0),
|
|
56
|
+
fallback_model: z.string().optional(),
|
|
57
|
+
fallback_provider: zapProviderSchema.optional(),
|
|
58
|
+
max: z.number().int().min(0).max(8).default(0),
|
|
59
|
+
}).optional(),
|
|
60
|
+
rlhf: z.union([z.literal("optional"), z.boolean()]).optional(),
|
|
61
|
+
shared: z.boolean().optional(),
|
|
62
|
+
stitch: zapStitchSchema.optional(),
|
|
63
|
+
tier: z.enum(["draft", "final"]).optional(),
|
|
64
|
+
});
|
|
65
|
+
export const zapPublishSchema = z.object({
|
|
66
|
+
embed: z.object({
|
|
67
|
+
allowOrigins: z.array(z.string()).default(["*"]),
|
|
68
|
+
enabled: z.boolean().default(true),
|
|
69
|
+
height: z.number().int().min(240).max(2160).default(720),
|
|
70
|
+
theme: z.enum(["auto", "dark", "light"]).default("auto"),
|
|
71
|
+
width: z.number().int().min(240).max(3840).default(1280),
|
|
72
|
+
}).optional(),
|
|
73
|
+
slug: z.string().regex(/^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/).optional(),
|
|
74
|
+
visibility: z.enum(["public", "unlisted", "private"]).default("public"),
|
|
75
|
+
}).partial().optional();
|
|
76
|
+
export const zapSpecSchema = z.object({
|
|
77
|
+
budget: z.object({
|
|
78
|
+
cap_usd: z.number().positive(),
|
|
79
|
+
estimate_usd: z.number().nonnegative(),
|
|
80
|
+
}),
|
|
81
|
+
defaults: z.object({
|
|
82
|
+
aspect: z.string().optional(),
|
|
83
|
+
models: z.record(z.string(), z.string()).default(() => ({})),
|
|
84
|
+
provider: zapProviderSchema.default("gmi"),
|
|
85
|
+
}).default(() => ({ models: {}, provider: "gmi" })),
|
|
86
|
+
description: z.string(),
|
|
87
|
+
inputs: z.record(z.string(), zapInputSchema).default({}),
|
|
88
|
+
output: z.string().default("Zap.mp4"),
|
|
89
|
+
publish: zapPublishSchema,
|
|
90
|
+
steps: z.array(zapStepSchema).min(1),
|
|
91
|
+
version: z.literal(2),
|
|
92
|
+
zap: z.string().regex(/^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/),
|
|
93
|
+
});
|
|
94
|
+
export function parseZapMarkdown(markdown) {
|
|
95
|
+
const frontmatter = extractFrontmatter(markdown);
|
|
96
|
+
const parsed = parseDocument(frontmatter).toJS();
|
|
97
|
+
const spec = zapSpecSchema.parse(parsed);
|
|
98
|
+
validateSpec(spec);
|
|
99
|
+
return spec;
|
|
100
|
+
}
|
|
101
|
+
export function validateZapPromptTemplates(spec, promptContents) {
|
|
102
|
+
for (const step of spec.steps) {
|
|
103
|
+
const promptRef = step.prompt;
|
|
104
|
+
if (!promptRef || !isPromptFile(promptRef))
|
|
105
|
+
continue;
|
|
106
|
+
const content = promptContents[promptRef];
|
|
107
|
+
if (content === undefined) {
|
|
108
|
+
throw new ZapSchemaError(`Step ${step.id} references missing prompt file ${promptRef}.`);
|
|
109
|
+
}
|
|
110
|
+
validateTemplateVariables(spec, step.id, content);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export function publicZapSpec(spec) {
|
|
114
|
+
return { ...spec, title: titleize(spec.zap) };
|
|
115
|
+
}
|
|
116
|
+
function extractFrontmatter(markdown) {
|
|
117
|
+
const match = markdown.match(/^---\n([\s\S]*?)\n---/);
|
|
118
|
+
if (!match) {
|
|
119
|
+
throw new Error("Zap recipe is missing YAML frontmatter.");
|
|
120
|
+
}
|
|
121
|
+
return match[1];
|
|
122
|
+
}
|
|
123
|
+
function validateSpec(spec) {
|
|
124
|
+
validateDuplicateStepIds(spec);
|
|
125
|
+
validateStepRefs(spec);
|
|
126
|
+
validateVideoDurations(spec);
|
|
127
|
+
validateInlineVariables(spec);
|
|
128
|
+
}
|
|
129
|
+
function validateInlineVariables(spec) {
|
|
130
|
+
for (const step of spec.steps) {
|
|
131
|
+
const promptRef = step.prompt ?? "";
|
|
132
|
+
if (!isPromptFile(promptRef))
|
|
133
|
+
validateTemplateVariables(spec, step.id, promptRef);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function validateDuplicateStepIds(spec) {
|
|
137
|
+
const seen = new Set();
|
|
138
|
+
for (const step of spec.steps) {
|
|
139
|
+
if (seen.has(step.id))
|
|
140
|
+
throw new Error(`Duplicate step id ${step.id}.`);
|
|
141
|
+
seen.add(step.id);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function validateStepRefs(spec) {
|
|
145
|
+
const declaredInputs = new Set(Object.keys(spec.inputs));
|
|
146
|
+
const priorSteps = new Set();
|
|
147
|
+
for (const step of spec.steps) {
|
|
148
|
+
for (const ref of [...(step.inputs ?? []), ...(step.reference_images ?? [])]) {
|
|
149
|
+
validateRef({ declaredInputs, priorSteps, ref, stepId: step.id });
|
|
150
|
+
}
|
|
151
|
+
priorSteps.add(step.id);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function validateRef({ declaredInputs, priorSteps, ref, stepId, }) {
|
|
155
|
+
if (ref.startsWith("user.")) {
|
|
156
|
+
const inputName = ref.slice("user.".length);
|
|
157
|
+
if (declaredInputs.has(inputName))
|
|
158
|
+
return;
|
|
159
|
+
throw new ZapSchemaError(`Step ${stepId} references undeclared input ${ref}.`);
|
|
160
|
+
}
|
|
161
|
+
if (ref.endsWith(".*")) {
|
|
162
|
+
const prefix = ref.slice(0, -2);
|
|
163
|
+
if (priorSteps.has(prefix))
|
|
164
|
+
return;
|
|
165
|
+
throw new ZapSchemaError(`Step ${stepId} references unknown repeated step ${ref}.`);
|
|
166
|
+
}
|
|
167
|
+
if (priorSteps.has(ref) || declaredInputs.has(ref))
|
|
168
|
+
return;
|
|
169
|
+
throw new ZapSchemaError(`Step ${stepId} references unknown input or step ${ref}.`);
|
|
170
|
+
}
|
|
171
|
+
function validateVideoDurations(spec) {
|
|
172
|
+
for (const step of spec.steps) {
|
|
173
|
+
if (step.kind.startsWith("video.") && step.duration_s === undefined) {
|
|
174
|
+
throw new ZapSchemaError(`Video step ${step.id} is missing duration_s.`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function validateTemplateVariables(spec, stepId, template) {
|
|
179
|
+
const declared = new Set(Object.keys(spec.inputs));
|
|
180
|
+
for (const variable of template.matchAll(/\{([A-Z0-9_]+)\}/g)) {
|
|
181
|
+
if (!declared.has(variable[1])) {
|
|
182
|
+
throw new ZapSchemaError(`Step ${stepId} references undeclared input {${variable[1]}}.`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function isPromptFile(prompt) {
|
|
187
|
+
return prompt.endsWith(".md") || prompt.startsWith("prompts/");
|
|
188
|
+
}
|
|
189
|
+
function titleize(slug) {
|
|
190
|
+
return slug
|
|
191
|
+
.split("-")
|
|
192
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
193
|
+
.join(" ");
|
|
194
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wzrdtech/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Core Zap recipe schema, planning, and registry utilities.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
8
9
|
"publishConfig": {
|
|
9
10
|
"access": "public"
|
|
10
11
|
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"src"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.build.json && node ../../scripts/rewrite-dts-imports.mjs dist",
|
|
18
|
+
"prepack": "npm run build"
|
|
19
|
+
},
|
|
11
20
|
"repository": {
|
|
12
21
|
"type": "git",
|
|
13
22
|
"url": "git+https://github.com/gratitude5dee/Zap.git",
|
|
@@ -18,10 +27,22 @@
|
|
|
18
27
|
},
|
|
19
28
|
"homepage": "https://zap.wzrd.tech",
|
|
20
29
|
"exports": {
|
|
21
|
-
".":
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./manifest": {
|
|
35
|
+
"types": "./dist/manifest.d.ts",
|
|
36
|
+
"import": "./dist/manifest.js"
|
|
37
|
+
},
|
|
38
|
+
"./planner": {
|
|
39
|
+
"types": "./dist/planner.d.ts",
|
|
40
|
+
"import": "./dist/planner.js"
|
|
41
|
+
},
|
|
42
|
+
"./schema": {
|
|
43
|
+
"types": "./dist/schema.d.ts",
|
|
44
|
+
"import": "./dist/schema.js"
|
|
45
|
+
}
|
|
25
46
|
},
|
|
26
47
|
"dependencies": {
|
|
27
48
|
"yaml": "^2.8.1",
|