@pixeldojo/mcp 0.5.1 → 0.8.0
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/cli.cjs +356 -66
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +356 -66
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +356 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +356 -66
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -183,6 +183,85 @@ var init_upload_helpers = __esm({
|
|
|
183
183
|
};
|
|
184
184
|
}
|
|
185
185
|
});
|
|
186
|
+
|
|
187
|
+
// src/skills/schema-snap.ts
|
|
188
|
+
function getFieldConstraints(apiId, client) {
|
|
189
|
+
const cached = schemaCache.get(apiId);
|
|
190
|
+
if (cached) return cached;
|
|
191
|
+
const pending = client.getModelSchema(apiId).then(
|
|
192
|
+
(res) => res.schema?.properties ?? {}
|
|
193
|
+
).catch(() => {
|
|
194
|
+
schemaCache.delete(apiId);
|
|
195
|
+
return null;
|
|
196
|
+
});
|
|
197
|
+
schemaCache.set(apiId, pending);
|
|
198
|
+
return pending;
|
|
199
|
+
}
|
|
200
|
+
function parseAspectRatio(ar) {
|
|
201
|
+
const m = /^\s*(\d+)\s*:\s*(\d+)\s*$/.exec(ar);
|
|
202
|
+
if (!m) return null;
|
|
203
|
+
const w = Number(m[1]);
|
|
204
|
+
const h = Number(m[2]);
|
|
205
|
+
return h > 0 ? w / h : null;
|
|
206
|
+
}
|
|
207
|
+
function nearestAspectFromEnum(requested, allowed) {
|
|
208
|
+
if (allowed.includes(requested)) return requested;
|
|
209
|
+
const target = parseAspectRatio(requested);
|
|
210
|
+
if (target === null) return requested;
|
|
211
|
+
let best = requested;
|
|
212
|
+
let bestDiff = Infinity;
|
|
213
|
+
for (const candidate of allowed) {
|
|
214
|
+
const r = parseAspectRatio(candidate);
|
|
215
|
+
if (r === null) continue;
|
|
216
|
+
const diff = Math.abs(r - target);
|
|
217
|
+
if (diff < bestDiff) {
|
|
218
|
+
bestDiff = diff;
|
|
219
|
+
best = candidate;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return best;
|
|
223
|
+
}
|
|
224
|
+
async function snapAspectRatio(apiId, requested, client, opts = {}) {
|
|
225
|
+
if (!requested) return void 0;
|
|
226
|
+
const props = await getFieldConstraints(apiId, client);
|
|
227
|
+
if (props === null) {
|
|
228
|
+
return opts.onUnknown === "omit" ? void 0 : requested;
|
|
229
|
+
}
|
|
230
|
+
const field = props.aspect_ratio;
|
|
231
|
+
if (!field) return void 0;
|
|
232
|
+
if (!field.enum || field.enum.length === 0) return requested;
|
|
233
|
+
return nearestAspectFromEnum(requested, field.enum);
|
|
234
|
+
}
|
|
235
|
+
async function snapDuration(apiId, requested, client, opts = {}) {
|
|
236
|
+
if (requested === void 0) return void 0;
|
|
237
|
+
const props = await getFieldConstraints(apiId, client);
|
|
238
|
+
if (props === null) {
|
|
239
|
+
return opts.onUnknown === "omit" ? void 0 : requested;
|
|
240
|
+
}
|
|
241
|
+
const field = props.duration;
|
|
242
|
+
if (!field) return void 0;
|
|
243
|
+
if (field.enum && field.enum.length > 0) {
|
|
244
|
+
const allowed = field.enum.map(Number).filter((n) => Number.isFinite(n));
|
|
245
|
+
if (allowed.length === 0) return requested;
|
|
246
|
+
if (allowed.includes(requested)) return requested;
|
|
247
|
+
return allowed.reduce(
|
|
248
|
+
(best, candidate) => Math.abs(candidate - requested) < Math.abs(best - requested) ? candidate : best
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
if (typeof field.minimum === "number" || typeof field.maximum === "number") {
|
|
252
|
+
let v = requested;
|
|
253
|
+
if (typeof field.minimum === "number") v = Math.max(field.minimum, v);
|
|
254
|
+
if (typeof field.maximum === "number") v = Math.min(field.maximum, v);
|
|
255
|
+
return v;
|
|
256
|
+
}
|
|
257
|
+
return requested;
|
|
258
|
+
}
|
|
259
|
+
var schemaCache;
|
|
260
|
+
var init_schema_snap = __esm({
|
|
261
|
+
"src/skills/schema-snap.ts"() {
|
|
262
|
+
schemaCache = /* @__PURE__ */ new Map();
|
|
263
|
+
}
|
|
264
|
+
});
|
|
186
265
|
function buildPayload(apiId, input) {
|
|
187
266
|
const body = { prompt: input.prompt };
|
|
188
267
|
if (input.aspect_ratio) body.aspect_ratio = input.aspect_ratio;
|
|
@@ -235,6 +314,13 @@ async function run(input, ctx) {
|
|
|
235
314
|
};
|
|
236
315
|
}
|
|
237
316
|
}
|
|
317
|
+
if (!VIDEO_INPUT_MODELS.has(apiId)) {
|
|
318
|
+
const [aspect_ratio, duration] = await Promise.all([
|
|
319
|
+
snapAspectRatio(apiId, resolved.aspect_ratio, ctx.client),
|
|
320
|
+
snapDuration(apiId, resolved.duration, ctx.client)
|
|
321
|
+
]);
|
|
322
|
+
resolved = { ...resolved, aspect_ratio, duration };
|
|
323
|
+
}
|
|
238
324
|
const body = buildPayload(apiId, resolved);
|
|
239
325
|
const submitted = await ctx.client.run(apiId, body);
|
|
240
326
|
const result = await pollJobUntilDoneOrHandoff(
|
|
@@ -251,16 +337,17 @@ async function run(input, ctx) {
|
|
|
251
337
|
(urls) => urls.length === 0 ? `Job ${submitted.jobId} completed but returned no assets.` : urls.length === 1 ? `Generated. Asset: ${urls[0]}` : `Generated ${urls.length} assets. URLs: ${urls.join(", ")}`
|
|
252
338
|
);
|
|
253
339
|
}
|
|
254
|
-
var InputSchema, DEFAULT_MODEL, InputJsonSchema, generateSkill;
|
|
340
|
+
var InputSchema, DEFAULT_MODEL, VIDEO_INPUT_MODELS, InputJsonSchema, generateSkill;
|
|
255
341
|
var init_generate = __esm({
|
|
256
342
|
"src/skills/generate.ts"() {
|
|
257
343
|
init_poll();
|
|
258
344
|
init_types();
|
|
259
345
|
init_upload_helpers();
|
|
346
|
+
init_schema_snap();
|
|
260
347
|
InputSchema = zod.z.object({
|
|
261
348
|
prompt: zod.z.string().min(1).max(8e3).describe("Prompt describing what to generate."),
|
|
262
349
|
model: zod.z.string().optional().describe(
|
|
263
|
-
'Override the model. Any apiId from /api/v1/models (e.g. "flux", "google-nano-banana", "veo-3.1", "kling-video"). Omit to use the default.'
|
|
350
|
+
'Override the model. Any apiId from /api/v1/models (e.g. "flux", "google-nano-banana", "veo-3.1-fast", "kling-video-v3-standard-text"). Omit to use the default.'
|
|
264
351
|
),
|
|
265
352
|
preset: zod.z.string().optional().describe(
|
|
266
353
|
'Preset slug to seed the params (e.g. "cinematic-portrait", "product-floating-clean", "magazine-cover-text"). Browse the catalog at https://pixeldojo.ai/presets. Explicit fields override preset values.'
|
|
@@ -273,13 +360,14 @@ var init_generate = __esm({
|
|
|
273
360
|
)
|
|
274
361
|
});
|
|
275
362
|
DEFAULT_MODEL = "google-nano-banana";
|
|
363
|
+
VIDEO_INPUT_MODELS = /* @__PURE__ */ new Set(["grok-video-extend", "wan-video-edit", "seedance-video-edit"]);
|
|
276
364
|
InputJsonSchema = {
|
|
277
365
|
type: "object",
|
|
278
366
|
properties: {
|
|
279
367
|
prompt: { type: "string", description: "Prompt describing what to generate." },
|
|
280
368
|
model: {
|
|
281
369
|
type: "string",
|
|
282
|
-
description: 'Override the model. Any apiId from /api/v1/models (e.g. "flux", "google-nano-banana", "veo-3.1", "kling-video"). Omit to use the default.'
|
|
370
|
+
description: 'Override the model. Any apiId from /api/v1/models (e.g. "flux", "google-nano-banana", "veo-3.1-fast", "kling-video-v3-standard-text"). Omit to use the default.'
|
|
283
371
|
},
|
|
284
372
|
preset: {
|
|
285
373
|
type: "string",
|
|
@@ -370,6 +458,10 @@ async function run2(input, ctx) {
|
|
|
370
458
|
};
|
|
371
459
|
}
|
|
372
460
|
const apiId = resolved.model ?? DEFAULT_MODEL2;
|
|
461
|
+
resolved = {
|
|
462
|
+
...resolved,
|
|
463
|
+
aspect_ratio: await snapAspectRatio(apiId, resolved.aspect_ratio, ctx.client)
|
|
464
|
+
};
|
|
373
465
|
const body = buildPayload2(apiId, resolved);
|
|
374
466
|
const submitted = await ctx.client.run(apiId, body);
|
|
375
467
|
const result = await pollJobUntilDoneOrHandoff(
|
|
@@ -392,6 +484,7 @@ var init_edit = __esm({
|
|
|
392
484
|
init_poll();
|
|
393
485
|
init_types();
|
|
394
486
|
init_upload_helpers();
|
|
487
|
+
init_schema_snap();
|
|
395
488
|
DEFAULT_MODEL2 = "wan-2.7-image-edit";
|
|
396
489
|
ALLOWED_MODELS = [
|
|
397
490
|
"wan-2.7-image-edit",
|
|
@@ -473,18 +566,24 @@ async function run3(input, ctx) {
|
|
|
473
566
|
};
|
|
474
567
|
}
|
|
475
568
|
const apiId = requested;
|
|
476
|
-
if ((apiId
|
|
569
|
+
if (REQUIRES_REFERENCE.has(apiId) && !input.reference_image_url) {
|
|
477
570
|
return {
|
|
478
571
|
kind: "text",
|
|
479
|
-
text: `pixeldojo:character with model="${apiId}" requires reference_image_url (the source image of the character to edit). For generation from a prompt alone, use model="
|
|
572
|
+
text: `pixeldojo:character with model="${apiId}" requires reference_image_url (the source image of the character to edit). For generation from a prompt alone, use model="${DEFAULT_MODEL3}".`
|
|
480
573
|
};
|
|
481
574
|
}
|
|
482
575
|
const body = { prompt: input.prompt };
|
|
483
|
-
if (input.aspect_ratio) body.aspect_ratio = input.aspect_ratio;
|
|
484
576
|
if (input.reference_image_url) {
|
|
485
|
-
|
|
486
|
-
|
|
577
|
+
if (apiId === "flux-edit") {
|
|
578
|
+
body.input_image = input.reference_image_url;
|
|
579
|
+
} else {
|
|
580
|
+
body.image_urls = [input.reference_image_url];
|
|
581
|
+
}
|
|
487
582
|
}
|
|
583
|
+
const snappedAspect = await snapAspectRatio(apiId, input.aspect_ratio, ctx.client, {
|
|
584
|
+
onUnknown: "omit"
|
|
585
|
+
});
|
|
586
|
+
if (snappedAspect !== void 0) body.aspect_ratio = snappedAspect;
|
|
488
587
|
const submitted = await ctx.client.run(apiId, body);
|
|
489
588
|
const result = await pollJobUntilDoneOrHandoff(
|
|
490
589
|
submitted.jobId,
|
|
@@ -500,20 +599,22 @@ async function run3(input, ctx) {
|
|
|
500
599
|
(urls) => urls.length === 0 ? `Job ${submitted.jobId} completed but returned no assets.` : `Character shot ready. Asset: ${urls[0]}`
|
|
501
600
|
);
|
|
502
601
|
}
|
|
503
|
-
var ALLOWED, DEFAULT_MODEL3, InputSchema3, InputJsonSchema3, characterSkill;
|
|
602
|
+
var ALLOWED, DEFAULT_MODEL3, REQUIRES_REFERENCE, InputSchema3, InputJsonSchema3, characterSkill;
|
|
504
603
|
var init_character = __esm({
|
|
505
604
|
"src/skills/character.ts"() {
|
|
506
605
|
init_poll();
|
|
507
606
|
init_types();
|
|
508
|
-
|
|
509
|
-
|
|
607
|
+
init_schema_snap();
|
|
608
|
+
ALLOWED = ["seedream-5", "seedream-4", "flux-edit", "gpt-image-2-edit"];
|
|
609
|
+
DEFAULT_MODEL3 = "seedream-5";
|
|
610
|
+
REQUIRES_REFERENCE = /* @__PURE__ */ new Set(["flux-edit", "gpt-image-2-edit"]);
|
|
510
611
|
InputSchema3 = zod.z.object({
|
|
511
612
|
prompt: zod.z.string().min(1).max(8e3),
|
|
512
613
|
model: zod.z.string().optional().describe(`One of: ${ALLOWED.join(", ")}. Defaults to ${DEFAULT_MODEL3}.`),
|
|
513
614
|
reference_image_url: zod.z.string().url().optional().describe(
|
|
514
|
-
"Reference image of the character. Required by flux-edit and gpt-image-2-edit; optional for
|
|
615
|
+
"Reference image of the character. Required by flux-edit and gpt-image-2-edit; optional for seedream-5/seedream-4."
|
|
515
616
|
),
|
|
516
|
-
aspect_ratio: zod.z.string().optional()
|
|
617
|
+
aspect_ratio: zod.z.string().optional().describe('Only honored for model="flux-edit".')
|
|
517
618
|
});
|
|
518
619
|
InputJsonSchema3 = {
|
|
519
620
|
type: "object",
|
|
@@ -531,7 +632,7 @@ var init_character = __esm({
|
|
|
531
632
|
};
|
|
532
633
|
characterSkill = {
|
|
533
634
|
name: "pixeldojo:character",
|
|
534
|
-
description: "Generate or edit consistent characters across shots. Pass a reference_image_url for
|
|
635
|
+
description: "Generate or edit consistent characters across shots. Pass a reference_image_url for identity locking (seedream-5 by default).",
|
|
535
636
|
inputZod: InputSchema3,
|
|
536
637
|
inputJsonSchema: InputJsonSchema3,
|
|
537
638
|
allowedModels: [...ALLOWED],
|
|
@@ -549,9 +650,13 @@ async function run4(input, ctx) {
|
|
|
549
650
|
};
|
|
550
651
|
}
|
|
551
652
|
const apiId = requested;
|
|
653
|
+
const [snappedAspect, snappedDuration] = await Promise.all([
|
|
654
|
+
snapAspectRatio(apiId, input.aspect_ratio, ctx.client),
|
|
655
|
+
snapDuration(apiId, input.duration, ctx.client)
|
|
656
|
+
]);
|
|
552
657
|
const body = { prompt: input.brief };
|
|
553
|
-
if (
|
|
554
|
-
if (
|
|
658
|
+
if (snappedAspect !== void 0) body.aspect_ratio = snappedAspect;
|
|
659
|
+
if (snappedDuration !== void 0) body.duration = snappedDuration;
|
|
555
660
|
const submitted = await ctx.client.run(apiId, body);
|
|
556
661
|
const result = await pollJobUntilDoneOrHandoff(
|
|
557
662
|
submitted.jobId,
|
|
@@ -572,8 +677,14 @@ var init_storyboard = __esm({
|
|
|
572
677
|
"src/skills/storyboard.ts"() {
|
|
573
678
|
init_poll();
|
|
574
679
|
init_types();
|
|
575
|
-
|
|
576
|
-
|
|
680
|
+
init_schema_snap();
|
|
681
|
+
ALLOWED2 = [
|
|
682
|
+
"veo-3.1-fast",
|
|
683
|
+
"veo-3.1-standard",
|
|
684
|
+
"kling-video-v3-standard-text",
|
|
685
|
+
"seedance-2-high"
|
|
686
|
+
];
|
|
687
|
+
DEFAULT_MODEL4 = "veo-3.1-fast";
|
|
577
688
|
InputSchema4 = zod.z.object({
|
|
578
689
|
brief: zod.z.string().min(1).max(8e3).describe("Storyboard brief: scene, shots, mood, action."),
|
|
579
690
|
model: zod.z.string().optional().describe(`One of: ${ALLOWED2.join(", ")}. Defaults to ${DEFAULT_MODEL4}.`),
|
|
@@ -619,11 +730,20 @@ async function run5(input, ctx) {
|
|
|
619
730
|
const apiId = requested;
|
|
620
731
|
const body = {
|
|
621
732
|
prompt: "",
|
|
622
|
-
|
|
733
|
+
image: input.image_url
|
|
623
734
|
};
|
|
624
735
|
if (apiId === "magnific-upscaler") {
|
|
625
|
-
|
|
736
|
+
const allowed = [2, 4, 8, 16];
|
|
737
|
+
const requestedScale = input.scale_factor ?? 2;
|
|
738
|
+
const nearest = allowed.reduce(
|
|
739
|
+
(a, b) => Math.abs(b - requestedScale) < Math.abs(a - requestedScale) ? b : a
|
|
740
|
+
);
|
|
741
|
+
body.scale_factor = `${nearest}x`;
|
|
626
742
|
if (input.creativity !== void 0) body.creativity = input.creativity;
|
|
743
|
+
} else if (apiId === "creative-upscale") {
|
|
744
|
+
body.scale_factor = Math.min(10, Math.max(1, input.scale_factor ?? 2));
|
|
745
|
+
} else if (apiId === "face-enhance") {
|
|
746
|
+
body.scale_factor = Math.min(8, Math.max(1, input.scale_factor ?? 4));
|
|
627
747
|
}
|
|
628
748
|
const submitted = await ctx.client.run(apiId, body);
|
|
629
749
|
const result = await pollJobUntilDoneOrHandoff(
|
|
@@ -650,7 +770,9 @@ var init_upscale = __esm({
|
|
|
650
770
|
InputSchema5 = zod.z.object({
|
|
651
771
|
image_url: zod.z.string().url().describe("URL of the source image to upscale."),
|
|
652
772
|
model: zod.z.string().optional().describe(`One of: ${ALLOWED3.join(", ")}. Defaults to ${DEFAULT_MODEL5}.`),
|
|
653
|
-
scale_factor: zod.z.number().
|
|
773
|
+
scale_factor: zod.z.number().min(1).max(16).optional().describe(
|
|
774
|
+
"Upscale multiplier. Magnific snaps to the nearest of 2/4/8/16 (default 2); creative-upscale accepts 1-10 (default 2); face-enhance accepts 1-8 (default 4)."
|
|
775
|
+
),
|
|
654
776
|
creativity: zod.z.number().min(0).max(1).optional().describe("Magnific only: 0 (preserve) \u2192 1 (creative). Defaults to 0.")
|
|
655
777
|
});
|
|
656
778
|
InputJsonSchema5 = {
|
|
@@ -658,7 +780,7 @@ var init_upscale = __esm({
|
|
|
658
780
|
properties: {
|
|
659
781
|
image_url: { type: "string", format: "uri" },
|
|
660
782
|
model: { type: "string", enum: ALLOWED3 },
|
|
661
|
-
scale_factor: { type: "
|
|
783
|
+
scale_factor: { type: "number", minimum: 1, maximum: 16 },
|
|
662
784
|
creativity: { type: "number", minimum: 0, maximum: 1 }
|
|
663
785
|
},
|
|
664
786
|
required: ["image_url"]
|
|
@@ -814,6 +936,146 @@ var init_from_url = __esm({
|
|
|
814
936
|
}
|
|
815
937
|
});
|
|
816
938
|
async function run8(input, ctx) {
|
|
939
|
+
const productImages = [
|
|
940
|
+
...input.product_image_urls ?? [],
|
|
941
|
+
...await Promise.all((input.product_image_paths ?? []).map((p) => uploadLocalFile(p, ctx.client)))
|
|
942
|
+
];
|
|
943
|
+
const characterImages = [
|
|
944
|
+
...input.character_image_urls ?? [],
|
|
945
|
+
...await Promise.all((input.character_image_paths ?? []).map((p) => uploadLocalFile(p, ctx.client)))
|
|
946
|
+
];
|
|
947
|
+
const body = {
|
|
948
|
+
style: input.style,
|
|
949
|
+
product_url: input.product_url,
|
|
950
|
+
product: !input.product_url && input.product_name ? {
|
|
951
|
+
name: input.product_name,
|
|
952
|
+
description: input.product_description,
|
|
953
|
+
images: productImages
|
|
954
|
+
} : void 0,
|
|
955
|
+
character_images: characterImages.length > 0 ? characterImages : void 0,
|
|
956
|
+
location: input.location_description || input.location_image_url ? { description: input.location_description, image_url: input.location_image_url } : void 0,
|
|
957
|
+
hook: input.hook,
|
|
958
|
+
script: input.script,
|
|
959
|
+
quality: input.quality,
|
|
960
|
+
resolution: input.resolution,
|
|
961
|
+
aspect_ratio: input.aspect_ratio,
|
|
962
|
+
duration: input.duration
|
|
963
|
+
};
|
|
964
|
+
const client = ctx.client;
|
|
965
|
+
const submitted = await client.runAd(body);
|
|
966
|
+
const result = await pollJobUntilDoneOrHandoff(
|
|
967
|
+
submitted.jobId,
|
|
968
|
+
(id) => ctx.client.getJob(id),
|
|
969
|
+
ctx.buildStatusUrl,
|
|
970
|
+
{
|
|
971
|
+
now: ctx.pollOverrides?.now,
|
|
972
|
+
sleep: ctx.pollOverrides?.sleep
|
|
973
|
+
}
|
|
974
|
+
);
|
|
975
|
+
const styleLabel = submitted.ad?.style ?? input.style ?? "ugc-testimonial";
|
|
976
|
+
return pollResultToSkillResult(
|
|
977
|
+
result,
|
|
978
|
+
(urls) => urls.length === 0 ? `Ad job ${submitted.jobId} completed but returned no assets.` : `Ad rendered (style: ${styleLabel}${submitted.ad?.product?.name ? `, product: ${submitted.ad.product.name}` : ""}). Video: ${urls[0]}`
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
var InputSchema8, InputJsonSchema8, adSkill;
|
|
982
|
+
var init_ad = __esm({
|
|
983
|
+
"src/skills/ad.ts"() {
|
|
984
|
+
init_types();
|
|
985
|
+
init_poll();
|
|
986
|
+
init_upload_helpers();
|
|
987
|
+
InputSchema8 = zod.z.object({
|
|
988
|
+
style: zod.z.string().max(80).optional().describe(
|
|
989
|
+
"Ad style slug (default ugc-testimonial). Catalog: GET /api/v1/marketing/presets \u2014 e.g. ugc-testimonial, unboxing-reveal, unboxing-asmr, virtual-try-on, street-style, product-showcase, macro-details, crush-test, hyper-motion, before-after, day-in-the-life, the-gift, tv-spot."
|
|
990
|
+
),
|
|
991
|
+
product_url: zod.z.string().url().optional().describe("Product page URL. Name, description, and images are extracted automatically."),
|
|
992
|
+
product_name: zod.z.string().max(200).optional(),
|
|
993
|
+
product_description: zod.z.string().max(2e3).optional(),
|
|
994
|
+
product_image_urls: zod.z.array(zod.z.string().url()).max(5).optional(),
|
|
995
|
+
product_image_paths: zod.z.array(zod.z.string()).max(5).optional().describe("Absolute local paths; uploaded to 24h temp storage automatically."),
|
|
996
|
+
character_image_urls: zod.z.array(zod.z.string().url()).max(4).optional().describe("Presenter reference images for a consistent on-camera character."),
|
|
997
|
+
character_image_paths: zod.z.array(zod.z.string()).max(4).optional(),
|
|
998
|
+
location_description: zod.z.string().max(1500).optional().describe('Where the ad takes place ("a sunlit Parisian cafe"). Text is enough; no image needed.'),
|
|
999
|
+
location_image_url: zod.z.string().url().optional(),
|
|
1000
|
+
hook: zod.z.string().max(1e3).optional().describe("The opening visual beat (first 1-2 seconds). Omit to use the style default."),
|
|
1001
|
+
script: zod.z.string().max(1e3).optional().describe("The exact spoken line, voiced word for word. Omit and the presenter improvises."),
|
|
1002
|
+
quality: zod.z.enum(["mini", "fast", "high"]).optional(),
|
|
1003
|
+
resolution: zod.z.enum(["480p", "720p", "1080p", "4k"]).optional().describe('1080p/4k require quality "high".'),
|
|
1004
|
+
aspect_ratio: zod.z.enum(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]).optional(),
|
|
1005
|
+
duration: zod.z.number().int().min(4).max(15).optional()
|
|
1006
|
+
}).refine(
|
|
1007
|
+
(v) => v.product_url || (v.product_image_urls?.length || v.product_image_paths?.length) && v.product_name,
|
|
1008
|
+
{
|
|
1009
|
+
message: "Pass product_url, OR product_name plus product_image_urls/product_image_paths.",
|
|
1010
|
+
path: ["product_url"]
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
InputJsonSchema8 = {
|
|
1014
|
+
type: "object",
|
|
1015
|
+
properties: {
|
|
1016
|
+
style: {
|
|
1017
|
+
type: "string",
|
|
1018
|
+
description: "Ad style slug (default ugc-testimonial). Catalog: GET /api/v1/marketing/presets \u2014 e.g. ugc-testimonial, unboxing-reveal, unboxing-asmr, virtual-try-on, street-style, mirror-fit-check, pro-try-on, product-showcase, macro-details, secret-hack-reveal, crush-test, hyper-motion, before-after, day-in-the-life, the-gift, tv-spot, gadget-saved-me, selfie-testimonial, direct-to-camera, pack-an-order, mystery-box."
|
|
1019
|
+
},
|
|
1020
|
+
product_url: {
|
|
1021
|
+
type: "string",
|
|
1022
|
+
format: "uri",
|
|
1023
|
+
description: "Product page URL. Name, description, and images are extracted automatically."
|
|
1024
|
+
},
|
|
1025
|
+
product_name: { type: "string" },
|
|
1026
|
+
product_description: { type: "string" },
|
|
1027
|
+
product_image_urls: { type: "array", items: { type: "string", format: "uri" }, maxItems: 5 },
|
|
1028
|
+
product_image_paths: {
|
|
1029
|
+
type: "array",
|
|
1030
|
+
items: { type: "string" },
|
|
1031
|
+
maxItems: 5,
|
|
1032
|
+
description: "Absolute local file paths; uploaded to 24h temp storage automatically."
|
|
1033
|
+
},
|
|
1034
|
+
character_image_urls: {
|
|
1035
|
+
type: "array",
|
|
1036
|
+
items: { type: "string", format: "uri" },
|
|
1037
|
+
maxItems: 4,
|
|
1038
|
+
description: "Presenter reference images for a consistent on-camera character."
|
|
1039
|
+
},
|
|
1040
|
+
character_image_paths: { type: "array", items: { type: "string" }, maxItems: 4 },
|
|
1041
|
+
location_description: {
|
|
1042
|
+
type: "string",
|
|
1043
|
+
description: 'Where the ad takes place ("a sunlit Parisian cafe"). Text is enough.'
|
|
1044
|
+
},
|
|
1045
|
+
location_image_url: { type: "string", format: "uri" },
|
|
1046
|
+
hook: {
|
|
1047
|
+
type: "string",
|
|
1048
|
+
description: "The opening visual beat (first 1-2 seconds). Omit to use the style default."
|
|
1049
|
+
},
|
|
1050
|
+
script: {
|
|
1051
|
+
type: "string",
|
|
1052
|
+
description: "The exact spoken line, voiced word for word. Omit and the presenter improvises."
|
|
1053
|
+
},
|
|
1054
|
+
quality: { type: "string", enum: ["mini", "fast", "high"] },
|
|
1055
|
+
resolution: {
|
|
1056
|
+
type: "string",
|
|
1057
|
+
enum: ["480p", "720p", "1080p", "4k"],
|
|
1058
|
+
description: '1080p/4k require quality "high".'
|
|
1059
|
+
},
|
|
1060
|
+
aspect_ratio: { type: "string", enum: ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"] },
|
|
1061
|
+
duration: { type: "integer", minimum: 4, maximum: 15 }
|
|
1062
|
+
}
|
|
1063
|
+
// "product_url OR product_name+images" is enforced by the server and the
|
|
1064
|
+
// Zod refine; no root-level oneOf (Grok rejects non-object root unions).
|
|
1065
|
+
};
|
|
1066
|
+
adSkill = {
|
|
1067
|
+
name: "pixeldojo:ad",
|
|
1068
|
+
description: "Marketing Studio: turn any product into a video ad. Pass a product URL (auto-extracted) or product images, pick an ad style (UGC testimonial, unboxing, try-on, showcase, TV spot, and more via GET /api/v1/marketing/presets), optionally add presenter reference images, a location, a hook, and the exact spoken script. Renders with voiceover; returns the video or a statusUrl handoff to poll via pixeldojo:status. Ideal for automated generate-and-post workflows.",
|
|
1069
|
+
inputZod: InputSchema8,
|
|
1070
|
+
inputJsonSchema: InputJsonSchema8,
|
|
1071
|
+
// Composition skill — the server routes to the ad engine internally.
|
|
1072
|
+
allowedModels: [],
|
|
1073
|
+
defaultModel: "",
|
|
1074
|
+
run: run8
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
async function run9(input, ctx) {
|
|
817
1079
|
const client = ctx.client;
|
|
818
1080
|
const result = await client.runCampaign(input);
|
|
819
1081
|
if (result.kind === "campaign") {
|
|
@@ -840,10 +1102,10 @@ async function run8(input, ctx) {
|
|
|
840
1102
|
statusUrl: result.statusUrl ?? ctx.buildStatusUrl(result.campaignId)
|
|
841
1103
|
};
|
|
842
1104
|
}
|
|
843
|
-
var
|
|
1105
|
+
var InputSchema9, InputJsonSchema9, campaignSkill;
|
|
844
1106
|
var init_campaign = __esm({
|
|
845
1107
|
"src/skills/campaign.ts"() {
|
|
846
|
-
|
|
1108
|
+
InputSchema9 = zod.z.object({
|
|
847
1109
|
productUrl: zod.z.string().url().optional().describe("Product page URL. We extract name + description + images automatically."),
|
|
848
1110
|
product: zod.z.object({
|
|
849
1111
|
name: zod.z.string().min(1).max(200),
|
|
@@ -859,7 +1121,7 @@ var init_campaign = __esm({
|
|
|
859
1121
|
message: "productUrl or product is required",
|
|
860
1122
|
path: ["productUrl"]
|
|
861
1123
|
});
|
|
862
|
-
|
|
1124
|
+
InputJsonSchema9 = {
|
|
863
1125
|
type: "object",
|
|
864
1126
|
properties: {
|
|
865
1127
|
productUrl: {
|
|
@@ -890,17 +1152,17 @@ var init_campaign = __esm({
|
|
|
890
1152
|
campaignSkill = {
|
|
891
1153
|
name: "pixeldojo:campaign",
|
|
892
1154
|
description: "Generate a coherent product launch package (hero image + N lifestyle variants + optional vertical video) from one URL or product profile. Composes hero / lifestyle / video models server-side; returns assets in one call or a handoff with campaignId to poll via pixeldojo:campaign_status.",
|
|
893
|
-
inputZod:
|
|
894
|
-
inputJsonSchema:
|
|
1155
|
+
inputZod: InputSchema9,
|
|
1156
|
+
inputJsonSchema: InputJsonSchema9,
|
|
895
1157
|
// Composition skill — internal sub-jobs route to per-tool models, no
|
|
896
1158
|
// single allowed-models list applies here.
|
|
897
1159
|
allowedModels: [],
|
|
898
1160
|
defaultModel: "",
|
|
899
|
-
run:
|
|
1161
|
+
run: run9
|
|
900
1162
|
};
|
|
901
1163
|
}
|
|
902
1164
|
});
|
|
903
|
-
async function
|
|
1165
|
+
async function run10(input, ctx) {
|
|
904
1166
|
const client = ctx.client;
|
|
905
1167
|
const result = await client.getCampaign(input.campaignId);
|
|
906
1168
|
if (result.kind === "campaign") {
|
|
@@ -930,13 +1192,13 @@ async function run9(input, ctx) {
|
|
|
930
1192
|
statusUrl: result.statusUrl ?? ctx.buildStatusUrl(result.campaignId)
|
|
931
1193
|
};
|
|
932
1194
|
}
|
|
933
|
-
var
|
|
1195
|
+
var InputSchema10, InputJsonSchema10, campaignStatusSkill;
|
|
934
1196
|
var init_campaign_status = __esm({
|
|
935
1197
|
"src/skills/campaign-status.ts"() {
|
|
936
|
-
|
|
1198
|
+
InputSchema10 = zod.z.object({
|
|
937
1199
|
campaignId: zod.z.string().min(1).max(200).describe("Campaign id returned from a prior pixeldojo:campaign handoff.")
|
|
938
1200
|
});
|
|
939
|
-
|
|
1201
|
+
InputJsonSchema10 = {
|
|
940
1202
|
type: "object",
|
|
941
1203
|
properties: {
|
|
942
1204
|
campaignId: {
|
|
@@ -949,15 +1211,15 @@ var init_campaign_status = __esm({
|
|
|
949
1211
|
campaignStatusSkill = {
|
|
950
1212
|
name: "pixeldojo:campaign_status",
|
|
951
1213
|
description: "Poll a campaign by campaignId returned from pixeldojo:campaign. Returns assets when every sub-job is done, or a handoff describing what is still in flight.",
|
|
952
|
-
inputZod:
|
|
953
|
-
inputJsonSchema:
|
|
1214
|
+
inputZod: InputSchema10,
|
|
1215
|
+
inputJsonSchema: InputJsonSchema10,
|
|
954
1216
|
allowedModels: [],
|
|
955
1217
|
defaultModel: "",
|
|
956
|
-
run:
|
|
1218
|
+
run: run10
|
|
957
1219
|
};
|
|
958
1220
|
}
|
|
959
1221
|
});
|
|
960
|
-
async function
|
|
1222
|
+
async function run11(input, ctx) {
|
|
961
1223
|
let url;
|
|
962
1224
|
try {
|
|
963
1225
|
url = await uploadLocalFile(input.path, ctx.client);
|
|
@@ -973,16 +1235,16 @@ async function run10(input, ctx) {
|
|
|
973
1235
|
(temp storage; auto-deletes in ~24h \u2014 pass this URL as image_url to :generate or :edit)`
|
|
974
1236
|
};
|
|
975
1237
|
}
|
|
976
|
-
var
|
|
1238
|
+
var InputSchema11, InputJsonSchema11, uploadSkill;
|
|
977
1239
|
var init_upload = __esm({
|
|
978
1240
|
"src/skills/upload.ts"() {
|
|
979
1241
|
init_upload_helpers();
|
|
980
|
-
|
|
1242
|
+
InputSchema11 = zod.z.object({
|
|
981
1243
|
path: zod.z.string().min(1).max(4096).describe(
|
|
982
1244
|
"Absolute local file path to upload. JPEG, PNG, WebP, GIF (\u226450MB) or MP4, WebM, MOV (\u2264200MB). Returns a public URL on the temp CDN; storage auto-expires after 24 hours."
|
|
983
1245
|
)
|
|
984
1246
|
});
|
|
985
|
-
|
|
1247
|
+
InputJsonSchema11 = {
|
|
986
1248
|
type: "object",
|
|
987
1249
|
properties: {
|
|
988
1250
|
path: {
|
|
@@ -995,15 +1257,15 @@ var init_upload = __esm({
|
|
|
995
1257
|
uploadSkill = {
|
|
996
1258
|
name: "pixeldojo:upload",
|
|
997
1259
|
description: "Upload a local image or video file and get back a public URL you can pass to :generate or :edit as image_url. Use when the user has a reference image on disk (drag-dropped into Claude Code, screenshot, etc.) and you need a URL. Storage auto-expires after 24 hours.",
|
|
998
|
-
inputZod:
|
|
999
|
-
inputJsonSchema:
|
|
1260
|
+
inputZod: InputSchema11,
|
|
1261
|
+
inputJsonSchema: InputJsonSchema11,
|
|
1000
1262
|
allowedModels: [],
|
|
1001
1263
|
defaultModel: "",
|
|
1002
|
-
run:
|
|
1264
|
+
run: run11
|
|
1003
1265
|
};
|
|
1004
1266
|
}
|
|
1005
1267
|
});
|
|
1006
|
-
async function
|
|
1268
|
+
async function run12(input, ctx) {
|
|
1007
1269
|
const requested = input.model ?? DEFAULT_MODEL6;
|
|
1008
1270
|
if (!ALLOWED4.includes(requested)) {
|
|
1009
1271
|
return {
|
|
@@ -1052,7 +1314,7 @@ async function run11(input, ctx) {
|
|
|
1052
1314
|
(urls) => urls.length === 0 ? `Job ${submitted.jobId} completed but returned no assets.` : `Audio ready. Asset: ${urls[0]}`
|
|
1053
1315
|
);
|
|
1054
1316
|
}
|
|
1055
|
-
var ALLOWED4, DEFAULT_MODEL6,
|
|
1317
|
+
var ALLOWED4, DEFAULT_MODEL6, InputSchema12, InputJsonSchema12, audioSkill;
|
|
1056
1318
|
var init_audio = __esm({
|
|
1057
1319
|
"src/skills/audio.ts"() {
|
|
1058
1320
|
init_poll();
|
|
@@ -1060,7 +1322,7 @@ var init_audio = __esm({
|
|
|
1060
1322
|
init_types();
|
|
1061
1323
|
ALLOWED4 = ["seed-audio", "text-to-speech"];
|
|
1062
1324
|
DEFAULT_MODEL6 = "seed-audio";
|
|
1063
|
-
|
|
1325
|
+
InputSchema12 = zod.z.object({
|
|
1064
1326
|
prompt: zod.z.string().min(1).describe(
|
|
1065
1327
|
"A script for speech, or a scene description for cinematic audio (dialogue + effects + music). Reference uploaded clips as @Audio1..@Audio3."
|
|
1066
1328
|
),
|
|
@@ -1071,7 +1333,7 @@ var init_audio = __esm({
|
|
|
1071
1333
|
output_format: zod.z.string().optional().describe("seed-audio: mp3 (default), wav, pcm, ogg_opus. text-to-speech: mp3, wav, flac, pcm."),
|
|
1072
1334
|
speed: zod.z.number().min(0.5).max(2).optional().describe("Speech speed multiplier (0.5\u20132).")
|
|
1073
1335
|
});
|
|
1074
|
-
|
|
1336
|
+
InputJsonSchema12 = {
|
|
1075
1337
|
type: "object",
|
|
1076
1338
|
properties: {
|
|
1077
1339
|
prompt: { type: "string" },
|
|
@@ -1087,15 +1349,15 @@ var init_audio = __esm({
|
|
|
1087
1349
|
audioSkill = {
|
|
1088
1350
|
name: "pixeldojo:audio",
|
|
1089
1351
|
description: "Generate audio: speech, multi-character dialogue, sound effects, and background music from one prompt (Seed Audio 1.0 by default; plain TTS available).",
|
|
1090
|
-
inputZod:
|
|
1091
|
-
inputJsonSchema:
|
|
1352
|
+
inputZod: InputSchema12,
|
|
1353
|
+
inputJsonSchema: InputJsonSchema12,
|
|
1092
1354
|
allowedModels: [...ALLOWED4],
|
|
1093
1355
|
defaultModel: DEFAULT_MODEL6,
|
|
1094
|
-
run:
|
|
1356
|
+
run: run12
|
|
1095
1357
|
};
|
|
1096
1358
|
}
|
|
1097
1359
|
});
|
|
1098
|
-
async function
|
|
1360
|
+
async function run13(input, ctx) {
|
|
1099
1361
|
const res = await ctx.client.listLibrary({
|
|
1100
1362
|
q: input.q,
|
|
1101
1363
|
model: input.model,
|
|
@@ -1126,16 +1388,16 @@ ${lines.join("\n")}
|
|
|
1126
1388
|
Pass any URL back into :generate, :edit, :character, or :upscale as a reference input.`
|
|
1127
1389
|
};
|
|
1128
1390
|
}
|
|
1129
|
-
var
|
|
1391
|
+
var InputSchema13, InputJsonSchema13, librarySkill;
|
|
1130
1392
|
var init_library = __esm({
|
|
1131
1393
|
"src/skills/library.ts"() {
|
|
1132
|
-
|
|
1394
|
+
InputSchema13 = zod.z.object({
|
|
1133
1395
|
q: zod.z.string().optional().describe("Substring match against the prompt that produced the asset."),
|
|
1134
1396
|
model: zod.z.string().optional().describe("Restrict to a single model (apiId)."),
|
|
1135
1397
|
modality: zod.z.enum(["image", "video", "audio"]).optional().describe("Restrict to one output type."),
|
|
1136
1398
|
limit: zod.z.number().int().min(1).max(50).optional().describe("Max results (default 10).")
|
|
1137
1399
|
});
|
|
1138
|
-
|
|
1400
|
+
InputJsonSchema13 = {
|
|
1139
1401
|
type: "object",
|
|
1140
1402
|
properties: {
|
|
1141
1403
|
q: { type: "string" },
|
|
@@ -1148,15 +1410,15 @@ var init_library = __esm({
|
|
|
1148
1410
|
librarySkill = {
|
|
1149
1411
|
name: "pixeldojo:library",
|
|
1150
1412
|
description: "Search your media library: saved My Media items (permanent) and recent API/MCP generations (expire after 24h), newest first. Returns asset URLs to reuse as reference inputs. Keep a result forever with pixeldojo:save.",
|
|
1151
|
-
inputZod:
|
|
1152
|
-
inputJsonSchema:
|
|
1413
|
+
inputZod: InputSchema13,
|
|
1414
|
+
inputJsonSchema: InputJsonSchema13,
|
|
1153
1415
|
allowedModels: [],
|
|
1154
1416
|
defaultModel: "",
|
|
1155
|
-
run:
|
|
1417
|
+
run: run13
|
|
1156
1418
|
};
|
|
1157
1419
|
}
|
|
1158
1420
|
});
|
|
1159
|
-
async function
|
|
1421
|
+
async function run14(input, ctx) {
|
|
1160
1422
|
const res = await ctx.client.saveMedia({
|
|
1161
1423
|
url: input.url,
|
|
1162
1424
|
prompt: input.prompt,
|
|
@@ -1170,17 +1432,17 @@ async function run13(input, ctx) {
|
|
|
1170
1432
|
It will appear at https://pixeldojo.ai/my-images and in pixeldojo:library searches.`
|
|
1171
1433
|
};
|
|
1172
1434
|
}
|
|
1173
|
-
var
|
|
1435
|
+
var InputSchema14, InputJsonSchema14, saveSkill;
|
|
1174
1436
|
var init_save = __esm({
|
|
1175
1437
|
"src/skills/save.ts"() {
|
|
1176
|
-
|
|
1438
|
+
InputSchema14 = zod.z.object({
|
|
1177
1439
|
url: zod.z.string().url().describe("The asset URL to save (image or video)."),
|
|
1178
1440
|
prompt: zod.z.string().optional().describe("The prompt that produced it \u2014 makes it findable in the library later."),
|
|
1179
1441
|
tool_name: zod.z.string().optional().describe("Tool/model slug that produced it."),
|
|
1180
1442
|
modality: zod.z.enum(["image", "video", "audio"]).optional(),
|
|
1181
1443
|
job_id: zod.z.string().optional().describe("The jobId that produced this asset, when known.")
|
|
1182
1444
|
});
|
|
1183
|
-
|
|
1445
|
+
InputJsonSchema14 = {
|
|
1184
1446
|
type: "object",
|
|
1185
1447
|
properties: {
|
|
1186
1448
|
url: { type: "string", format: "uri" },
|
|
@@ -1194,11 +1456,11 @@ var init_save = __esm({
|
|
|
1194
1456
|
saveSkill = {
|
|
1195
1457
|
name: "pixeldojo:save",
|
|
1196
1458
|
description: "Save a generated image or video into the user's My Media library permanently. Generation outputs otherwise expire after 24 hours \u2014 call this when the user wants to keep a result.",
|
|
1197
|
-
inputZod:
|
|
1198
|
-
inputJsonSchema:
|
|
1459
|
+
inputZod: InputSchema14,
|
|
1460
|
+
inputJsonSchema: InputJsonSchema14,
|
|
1199
1461
|
allowedModels: [],
|
|
1200
1462
|
defaultModel: "",
|
|
1201
|
-
run:
|
|
1463
|
+
run: run14
|
|
1202
1464
|
};
|
|
1203
1465
|
}
|
|
1204
1466
|
});
|
|
@@ -1287,7 +1549,24 @@ async function runWorkflow(input, ctx) {
|
|
|
1287
1549
|
text: `Step ${i + 1} (${step.skill}) has invalid args: ${issue?.path.join(".") || "input"} ${issue?.message || "invalid"}.`
|
|
1288
1550
|
};
|
|
1289
1551
|
}
|
|
1290
|
-
|
|
1552
|
+
let result = await skill.run(parsed.data, ctx);
|
|
1553
|
+
if (result.kind === "handoff") {
|
|
1554
|
+
const handoffJobId = result.jobId;
|
|
1555
|
+
const polled = await pollJobUntilDoneOrHandoff(
|
|
1556
|
+
handoffJobId,
|
|
1557
|
+
(id) => ctx.client.getJob(id),
|
|
1558
|
+
ctx.buildStatusUrl,
|
|
1559
|
+
{
|
|
1560
|
+
syncBudgetMs: WORKFLOW_STEP_EXTRA_BUDGET_MS,
|
|
1561
|
+
now: ctx.pollOverrides?.now,
|
|
1562
|
+
sleep: ctx.pollOverrides?.sleep
|
|
1563
|
+
}
|
|
1564
|
+
);
|
|
1565
|
+
result = pollResultToSkillResult(
|
|
1566
|
+
polled,
|
|
1567
|
+
(urls) => urls.length === 0 ? `Job ${handoffJobId} completed but returned no assets.` : `Done. Asset: ${urls[0]}`
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1291
1570
|
const url = firstUrl(result);
|
|
1292
1571
|
if (url) {
|
|
1293
1572
|
prevUrl = url;
|
|
@@ -1297,6 +1576,11 @@ async function runWorkflow(input, ctx) {
|
|
|
1297
1576
|
kind: "text",
|
|
1298
1577
|
text: `Workflow "${workflow.name}" stopped at step ${i + 1} (${step.skill}): ${result.text}`
|
|
1299
1578
|
};
|
|
1579
|
+
} else if (result.kind === "handoff") {
|
|
1580
|
+
return {
|
|
1581
|
+
kind: "text",
|
|
1582
|
+
text: `Workflow "${workflow.name}" is still on step ${i + 1} (${step.skill}) after an extended wait. Poll with pixeldojo:status { jobId: "${result.jobId}" }, then re-run the workflow once it completes.`
|
|
1583
|
+
};
|
|
1300
1584
|
} else {
|
|
1301
1585
|
outputs.push(`step ${i + 1} (${step.skill}): done (no asset URL)`);
|
|
1302
1586
|
}
|
|
@@ -1307,9 +1591,12 @@ async function runWorkflow(input, ctx) {
|
|
|
1307
1591
|
${outputs.join("\n")}`
|
|
1308
1592
|
};
|
|
1309
1593
|
}
|
|
1310
|
-
var StepSchema, SaveInputSchema, RunInputSchema, ListInputSchema, stepJson, saveWorkflowSkill, runWorkflowSkill, listWorkflowsSkill;
|
|
1594
|
+
var WORKFLOW_STEP_EXTRA_BUDGET_MS, StepSchema, SaveInputSchema, RunInputSchema, ListInputSchema, stepJson, saveWorkflowSkill, runWorkflowSkill, listWorkflowsSkill;
|
|
1311
1595
|
var init_workflows = __esm({
|
|
1312
1596
|
"src/skills/workflows.ts"() {
|
|
1597
|
+
init_poll();
|
|
1598
|
+
init_types();
|
|
1599
|
+
WORKFLOW_STEP_EXTRA_BUDGET_MS = 6e4;
|
|
1313
1600
|
StepSchema = zod.z.object({
|
|
1314
1601
|
skill: zod.z.string().regex(/^pixeldojo:(generate|edit|character|storyboard|upscale|audio|upload|from_url)$/, {
|
|
1315
1602
|
message: "Runnable skills only: generate, edit, character, storyboard, upscale, audio, upload, from_url."
|
|
@@ -1385,6 +1672,7 @@ var init_workflows = __esm({
|
|
|
1385
1672
|
var skills_exports = {};
|
|
1386
1673
|
__export(skills_exports, {
|
|
1387
1674
|
ALL_SKILLS: () => ALL_SKILLS,
|
|
1675
|
+
adSkill: () => adSkill,
|
|
1388
1676
|
audioSkill: () => audioSkill,
|
|
1389
1677
|
campaignSkill: () => campaignSkill,
|
|
1390
1678
|
campaignStatusSkill: () => campaignStatusSkill,
|
|
@@ -1416,6 +1704,7 @@ var init_skills = __esm({
|
|
|
1416
1704
|
init_upscale();
|
|
1417
1705
|
init_status();
|
|
1418
1706
|
init_from_url();
|
|
1707
|
+
init_ad();
|
|
1419
1708
|
init_campaign();
|
|
1420
1709
|
init_campaign_status();
|
|
1421
1710
|
init_upload();
|
|
@@ -1438,6 +1727,7 @@ var init_skills = __esm({
|
|
|
1438
1727
|
statusSkill,
|
|
1439
1728
|
fromUrlSkill,
|
|
1440
1729
|
uploadSkill,
|
|
1730
|
+
adSkill,
|
|
1441
1731
|
campaignSkill,
|
|
1442
1732
|
campaignStatusSkill
|
|
1443
1733
|
];
|
|
@@ -1494,7 +1784,7 @@ function makeRedactedLogger(target = console) {
|
|
|
1494
1784
|
}
|
|
1495
1785
|
|
|
1496
1786
|
// src/server.ts
|
|
1497
|
-
var PACKAGE_VERSION = "0.
|
|
1787
|
+
var PACKAGE_VERSION = "0.8.0" ;
|
|
1498
1788
|
function buildServer(options) {
|
|
1499
1789
|
if (!options.apiKey) {
|
|
1500
1790
|
throw new Error(
|