@pixeldojo/mcp 0.6.0 → 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 +292 -63
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +292 -63
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +292 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +292 -63
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -181,6 +181,85 @@ var init_upload_helpers = __esm({
|
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
});
|
|
184
|
+
|
|
185
|
+
// src/skills/schema-snap.ts
|
|
186
|
+
function getFieldConstraints(apiId, client) {
|
|
187
|
+
const cached = schemaCache.get(apiId);
|
|
188
|
+
if (cached) return cached;
|
|
189
|
+
const pending = client.getModelSchema(apiId).then(
|
|
190
|
+
(res) => res.schema?.properties ?? {}
|
|
191
|
+
).catch(() => {
|
|
192
|
+
schemaCache.delete(apiId);
|
|
193
|
+
return null;
|
|
194
|
+
});
|
|
195
|
+
schemaCache.set(apiId, pending);
|
|
196
|
+
return pending;
|
|
197
|
+
}
|
|
198
|
+
function parseAspectRatio(ar) {
|
|
199
|
+
const m = /^\s*(\d+)\s*:\s*(\d+)\s*$/.exec(ar);
|
|
200
|
+
if (!m) return null;
|
|
201
|
+
const w = Number(m[1]);
|
|
202
|
+
const h = Number(m[2]);
|
|
203
|
+
return h > 0 ? w / h : null;
|
|
204
|
+
}
|
|
205
|
+
function nearestAspectFromEnum(requested, allowed) {
|
|
206
|
+
if (allowed.includes(requested)) return requested;
|
|
207
|
+
const target = parseAspectRatio(requested);
|
|
208
|
+
if (target === null) return requested;
|
|
209
|
+
let best = requested;
|
|
210
|
+
let bestDiff = Infinity;
|
|
211
|
+
for (const candidate of allowed) {
|
|
212
|
+
const r = parseAspectRatio(candidate);
|
|
213
|
+
if (r === null) continue;
|
|
214
|
+
const diff = Math.abs(r - target);
|
|
215
|
+
if (diff < bestDiff) {
|
|
216
|
+
bestDiff = diff;
|
|
217
|
+
best = candidate;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return best;
|
|
221
|
+
}
|
|
222
|
+
async function snapAspectRatio(apiId, requested, client, opts = {}) {
|
|
223
|
+
if (!requested) return void 0;
|
|
224
|
+
const props = await getFieldConstraints(apiId, client);
|
|
225
|
+
if (props === null) {
|
|
226
|
+
return opts.onUnknown === "omit" ? void 0 : requested;
|
|
227
|
+
}
|
|
228
|
+
const field = props.aspect_ratio;
|
|
229
|
+
if (!field) return void 0;
|
|
230
|
+
if (!field.enum || field.enum.length === 0) return requested;
|
|
231
|
+
return nearestAspectFromEnum(requested, field.enum);
|
|
232
|
+
}
|
|
233
|
+
async function snapDuration(apiId, requested, client, opts = {}) {
|
|
234
|
+
if (requested === void 0) return void 0;
|
|
235
|
+
const props = await getFieldConstraints(apiId, client);
|
|
236
|
+
if (props === null) {
|
|
237
|
+
return opts.onUnknown === "omit" ? void 0 : requested;
|
|
238
|
+
}
|
|
239
|
+
const field = props.duration;
|
|
240
|
+
if (!field) return void 0;
|
|
241
|
+
if (field.enum && field.enum.length > 0) {
|
|
242
|
+
const allowed = field.enum.map(Number).filter((n) => Number.isFinite(n));
|
|
243
|
+
if (allowed.length === 0) return requested;
|
|
244
|
+
if (allowed.includes(requested)) return requested;
|
|
245
|
+
return allowed.reduce(
|
|
246
|
+
(best, candidate) => Math.abs(candidate - requested) < Math.abs(best - requested) ? candidate : best
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (typeof field.minimum === "number" || typeof field.maximum === "number") {
|
|
250
|
+
let v = requested;
|
|
251
|
+
if (typeof field.minimum === "number") v = Math.max(field.minimum, v);
|
|
252
|
+
if (typeof field.maximum === "number") v = Math.min(field.maximum, v);
|
|
253
|
+
return v;
|
|
254
|
+
}
|
|
255
|
+
return requested;
|
|
256
|
+
}
|
|
257
|
+
var schemaCache;
|
|
258
|
+
var init_schema_snap = __esm({
|
|
259
|
+
"src/skills/schema-snap.ts"() {
|
|
260
|
+
schemaCache = /* @__PURE__ */ new Map();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
184
263
|
function buildPayload(apiId, input) {
|
|
185
264
|
const body = { prompt: input.prompt };
|
|
186
265
|
if (input.aspect_ratio) body.aspect_ratio = input.aspect_ratio;
|
|
@@ -233,6 +312,13 @@ async function run(input, ctx) {
|
|
|
233
312
|
};
|
|
234
313
|
}
|
|
235
314
|
}
|
|
315
|
+
if (!VIDEO_INPUT_MODELS.has(apiId)) {
|
|
316
|
+
const [aspect_ratio, duration] = await Promise.all([
|
|
317
|
+
snapAspectRatio(apiId, resolved.aspect_ratio, ctx.client),
|
|
318
|
+
snapDuration(apiId, resolved.duration, ctx.client)
|
|
319
|
+
]);
|
|
320
|
+
resolved = { ...resolved, aspect_ratio, duration };
|
|
321
|
+
}
|
|
236
322
|
const body = buildPayload(apiId, resolved);
|
|
237
323
|
const submitted = await ctx.client.run(apiId, body);
|
|
238
324
|
const result = await pollJobUntilDoneOrHandoff(
|
|
@@ -249,12 +335,13 @@ async function run(input, ctx) {
|
|
|
249
335
|
(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(", ")}`
|
|
250
336
|
);
|
|
251
337
|
}
|
|
252
|
-
var InputSchema, DEFAULT_MODEL, InputJsonSchema, generateSkill;
|
|
338
|
+
var InputSchema, DEFAULT_MODEL, VIDEO_INPUT_MODELS, InputJsonSchema, generateSkill;
|
|
253
339
|
var init_generate = __esm({
|
|
254
340
|
"src/skills/generate.ts"() {
|
|
255
341
|
init_poll();
|
|
256
342
|
init_types();
|
|
257
343
|
init_upload_helpers();
|
|
344
|
+
init_schema_snap();
|
|
258
345
|
InputSchema = z.object({
|
|
259
346
|
prompt: z.string().min(1).max(8e3).describe("Prompt describing what to generate."),
|
|
260
347
|
model: z.string().optional().describe(
|
|
@@ -271,6 +358,7 @@ var init_generate = __esm({
|
|
|
271
358
|
)
|
|
272
359
|
});
|
|
273
360
|
DEFAULT_MODEL = "google-nano-banana";
|
|
361
|
+
VIDEO_INPUT_MODELS = /* @__PURE__ */ new Set(["grok-video-extend", "wan-video-edit", "seedance-video-edit"]);
|
|
274
362
|
InputJsonSchema = {
|
|
275
363
|
type: "object",
|
|
276
364
|
properties: {
|
|
@@ -368,6 +456,10 @@ async function run2(input, ctx) {
|
|
|
368
456
|
};
|
|
369
457
|
}
|
|
370
458
|
const apiId = resolved.model ?? DEFAULT_MODEL2;
|
|
459
|
+
resolved = {
|
|
460
|
+
...resolved,
|
|
461
|
+
aspect_ratio: await snapAspectRatio(apiId, resolved.aspect_ratio, ctx.client)
|
|
462
|
+
};
|
|
371
463
|
const body = buildPayload2(apiId, resolved);
|
|
372
464
|
const submitted = await ctx.client.run(apiId, body);
|
|
373
465
|
const result = await pollJobUntilDoneOrHandoff(
|
|
@@ -390,6 +482,7 @@ var init_edit = __esm({
|
|
|
390
482
|
init_poll();
|
|
391
483
|
init_types();
|
|
392
484
|
init_upload_helpers();
|
|
485
|
+
init_schema_snap();
|
|
393
486
|
DEFAULT_MODEL2 = "wan-2.7-image-edit";
|
|
394
487
|
ALLOWED_MODELS = [
|
|
395
488
|
"wan-2.7-image-edit",
|
|
@@ -485,9 +578,10 @@ async function run3(input, ctx) {
|
|
|
485
578
|
body.image_urls = [input.reference_image_url];
|
|
486
579
|
}
|
|
487
580
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
581
|
+
const snappedAspect = await snapAspectRatio(apiId, input.aspect_ratio, ctx.client, {
|
|
582
|
+
onUnknown: "omit"
|
|
583
|
+
});
|
|
584
|
+
if (snappedAspect !== void 0) body.aspect_ratio = snappedAspect;
|
|
491
585
|
const submitted = await ctx.client.run(apiId, body);
|
|
492
586
|
const result = await pollJobUntilDoneOrHandoff(
|
|
493
587
|
submitted.jobId,
|
|
@@ -503,28 +597,15 @@ async function run3(input, ctx) {
|
|
|
503
597
|
(urls) => urls.length === 0 ? `Job ${submitted.jobId} completed but returned no assets.` : `Character shot ready. Asset: ${urls[0]}`
|
|
504
598
|
);
|
|
505
599
|
}
|
|
506
|
-
var ALLOWED, DEFAULT_MODEL3, REQUIRES_REFERENCE,
|
|
600
|
+
var ALLOWED, DEFAULT_MODEL3, REQUIRES_REFERENCE, InputSchema3, InputJsonSchema3, characterSkill;
|
|
507
601
|
var init_character = __esm({
|
|
508
602
|
"src/skills/character.ts"() {
|
|
509
603
|
init_poll();
|
|
510
604
|
init_types();
|
|
605
|
+
init_schema_snap();
|
|
511
606
|
ALLOWED = ["seedream-5", "seedream-4", "flux-edit", "gpt-image-2-edit"];
|
|
512
607
|
DEFAULT_MODEL3 = "seedream-5";
|
|
513
608
|
REQUIRES_REFERENCE = /* @__PURE__ */ new Set(["flux-edit", "gpt-image-2-edit"]);
|
|
514
|
-
FLUX_EDIT_ASPECT_RATIOS = /* @__PURE__ */ new Set([
|
|
515
|
-
"1:1",
|
|
516
|
-
"16:9",
|
|
517
|
-
"9:16",
|
|
518
|
-
"21:9",
|
|
519
|
-
"9:21",
|
|
520
|
-
"3:2",
|
|
521
|
-
"2:3",
|
|
522
|
-
"4:5",
|
|
523
|
-
"5:4",
|
|
524
|
-
"3:4",
|
|
525
|
-
"4:3",
|
|
526
|
-
"match_input_image"
|
|
527
|
-
]);
|
|
528
609
|
InputSchema3 = z.object({
|
|
529
610
|
prompt: z.string().min(1).max(8e3),
|
|
530
611
|
model: z.string().optional().describe(`One of: ${ALLOWED.join(", ")}. Defaults to ${DEFAULT_MODEL3}.`),
|
|
@@ -567,9 +648,13 @@ async function run4(input, ctx) {
|
|
|
567
648
|
};
|
|
568
649
|
}
|
|
569
650
|
const apiId = requested;
|
|
651
|
+
const [snappedAspect, snappedDuration] = await Promise.all([
|
|
652
|
+
snapAspectRatio(apiId, input.aspect_ratio, ctx.client),
|
|
653
|
+
snapDuration(apiId, input.duration, ctx.client)
|
|
654
|
+
]);
|
|
570
655
|
const body = { prompt: input.brief };
|
|
571
|
-
if (
|
|
572
|
-
if (
|
|
656
|
+
if (snappedAspect !== void 0) body.aspect_ratio = snappedAspect;
|
|
657
|
+
if (snappedDuration !== void 0) body.duration = snappedDuration;
|
|
573
658
|
const submitted = await ctx.client.run(apiId, body);
|
|
574
659
|
const result = await pollJobUntilDoneOrHandoff(
|
|
575
660
|
submitted.jobId,
|
|
@@ -590,6 +675,7 @@ var init_storyboard = __esm({
|
|
|
590
675
|
"src/skills/storyboard.ts"() {
|
|
591
676
|
init_poll();
|
|
592
677
|
init_types();
|
|
678
|
+
init_schema_snap();
|
|
593
679
|
ALLOWED2 = [
|
|
594
680
|
"veo-3.1-fast",
|
|
595
681
|
"veo-3.1-standard",
|
|
@@ -848,6 +934,146 @@ var init_from_url = __esm({
|
|
|
848
934
|
}
|
|
849
935
|
});
|
|
850
936
|
async function run8(input, ctx) {
|
|
937
|
+
const productImages = [
|
|
938
|
+
...input.product_image_urls ?? [],
|
|
939
|
+
...await Promise.all((input.product_image_paths ?? []).map((p) => uploadLocalFile(p, ctx.client)))
|
|
940
|
+
];
|
|
941
|
+
const characterImages = [
|
|
942
|
+
...input.character_image_urls ?? [],
|
|
943
|
+
...await Promise.all((input.character_image_paths ?? []).map((p) => uploadLocalFile(p, ctx.client)))
|
|
944
|
+
];
|
|
945
|
+
const body = {
|
|
946
|
+
style: input.style,
|
|
947
|
+
product_url: input.product_url,
|
|
948
|
+
product: !input.product_url && input.product_name ? {
|
|
949
|
+
name: input.product_name,
|
|
950
|
+
description: input.product_description,
|
|
951
|
+
images: productImages
|
|
952
|
+
} : void 0,
|
|
953
|
+
character_images: characterImages.length > 0 ? characterImages : void 0,
|
|
954
|
+
location: input.location_description || input.location_image_url ? { description: input.location_description, image_url: input.location_image_url } : void 0,
|
|
955
|
+
hook: input.hook,
|
|
956
|
+
script: input.script,
|
|
957
|
+
quality: input.quality,
|
|
958
|
+
resolution: input.resolution,
|
|
959
|
+
aspect_ratio: input.aspect_ratio,
|
|
960
|
+
duration: input.duration
|
|
961
|
+
};
|
|
962
|
+
const client = ctx.client;
|
|
963
|
+
const submitted = await client.runAd(body);
|
|
964
|
+
const result = await pollJobUntilDoneOrHandoff(
|
|
965
|
+
submitted.jobId,
|
|
966
|
+
(id) => ctx.client.getJob(id),
|
|
967
|
+
ctx.buildStatusUrl,
|
|
968
|
+
{
|
|
969
|
+
now: ctx.pollOverrides?.now,
|
|
970
|
+
sleep: ctx.pollOverrides?.sleep
|
|
971
|
+
}
|
|
972
|
+
);
|
|
973
|
+
const styleLabel = submitted.ad?.style ?? input.style ?? "ugc-testimonial";
|
|
974
|
+
return pollResultToSkillResult(
|
|
975
|
+
result,
|
|
976
|
+
(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]}`
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
var InputSchema8, InputJsonSchema8, adSkill;
|
|
980
|
+
var init_ad = __esm({
|
|
981
|
+
"src/skills/ad.ts"() {
|
|
982
|
+
init_types();
|
|
983
|
+
init_poll();
|
|
984
|
+
init_upload_helpers();
|
|
985
|
+
InputSchema8 = z.object({
|
|
986
|
+
style: z.string().max(80).optional().describe(
|
|
987
|
+
"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."
|
|
988
|
+
),
|
|
989
|
+
product_url: z.string().url().optional().describe("Product page URL. Name, description, and images are extracted automatically."),
|
|
990
|
+
product_name: z.string().max(200).optional(),
|
|
991
|
+
product_description: z.string().max(2e3).optional(),
|
|
992
|
+
product_image_urls: z.array(z.string().url()).max(5).optional(),
|
|
993
|
+
product_image_paths: z.array(z.string()).max(5).optional().describe("Absolute local paths; uploaded to 24h temp storage automatically."),
|
|
994
|
+
character_image_urls: z.array(z.string().url()).max(4).optional().describe("Presenter reference images for a consistent on-camera character."),
|
|
995
|
+
character_image_paths: z.array(z.string()).max(4).optional(),
|
|
996
|
+
location_description: z.string().max(1500).optional().describe('Where the ad takes place ("a sunlit Parisian cafe"). Text is enough; no image needed.'),
|
|
997
|
+
location_image_url: z.string().url().optional(),
|
|
998
|
+
hook: z.string().max(1e3).optional().describe("The opening visual beat (first 1-2 seconds). Omit to use the style default."),
|
|
999
|
+
script: z.string().max(1e3).optional().describe("The exact spoken line, voiced word for word. Omit and the presenter improvises."),
|
|
1000
|
+
quality: z.enum(["mini", "fast", "high"]).optional(),
|
|
1001
|
+
resolution: z.enum(["480p", "720p", "1080p", "4k"]).optional().describe('1080p/4k require quality "high".'),
|
|
1002
|
+
aspect_ratio: z.enum(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]).optional(),
|
|
1003
|
+
duration: z.number().int().min(4).max(15).optional()
|
|
1004
|
+
}).refine(
|
|
1005
|
+
(v) => v.product_url || (v.product_image_urls?.length || v.product_image_paths?.length) && v.product_name,
|
|
1006
|
+
{
|
|
1007
|
+
message: "Pass product_url, OR product_name plus product_image_urls/product_image_paths.",
|
|
1008
|
+
path: ["product_url"]
|
|
1009
|
+
}
|
|
1010
|
+
);
|
|
1011
|
+
InputJsonSchema8 = {
|
|
1012
|
+
type: "object",
|
|
1013
|
+
properties: {
|
|
1014
|
+
style: {
|
|
1015
|
+
type: "string",
|
|
1016
|
+
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."
|
|
1017
|
+
},
|
|
1018
|
+
product_url: {
|
|
1019
|
+
type: "string",
|
|
1020
|
+
format: "uri",
|
|
1021
|
+
description: "Product page URL. Name, description, and images are extracted automatically."
|
|
1022
|
+
},
|
|
1023
|
+
product_name: { type: "string" },
|
|
1024
|
+
product_description: { type: "string" },
|
|
1025
|
+
product_image_urls: { type: "array", items: { type: "string", format: "uri" }, maxItems: 5 },
|
|
1026
|
+
product_image_paths: {
|
|
1027
|
+
type: "array",
|
|
1028
|
+
items: { type: "string" },
|
|
1029
|
+
maxItems: 5,
|
|
1030
|
+
description: "Absolute local file paths; uploaded to 24h temp storage automatically."
|
|
1031
|
+
},
|
|
1032
|
+
character_image_urls: {
|
|
1033
|
+
type: "array",
|
|
1034
|
+
items: { type: "string", format: "uri" },
|
|
1035
|
+
maxItems: 4,
|
|
1036
|
+
description: "Presenter reference images for a consistent on-camera character."
|
|
1037
|
+
},
|
|
1038
|
+
character_image_paths: { type: "array", items: { type: "string" }, maxItems: 4 },
|
|
1039
|
+
location_description: {
|
|
1040
|
+
type: "string",
|
|
1041
|
+
description: 'Where the ad takes place ("a sunlit Parisian cafe"). Text is enough.'
|
|
1042
|
+
},
|
|
1043
|
+
location_image_url: { type: "string", format: "uri" },
|
|
1044
|
+
hook: {
|
|
1045
|
+
type: "string",
|
|
1046
|
+
description: "The opening visual beat (first 1-2 seconds). Omit to use the style default."
|
|
1047
|
+
},
|
|
1048
|
+
script: {
|
|
1049
|
+
type: "string",
|
|
1050
|
+
description: "The exact spoken line, voiced word for word. Omit and the presenter improvises."
|
|
1051
|
+
},
|
|
1052
|
+
quality: { type: "string", enum: ["mini", "fast", "high"] },
|
|
1053
|
+
resolution: {
|
|
1054
|
+
type: "string",
|
|
1055
|
+
enum: ["480p", "720p", "1080p", "4k"],
|
|
1056
|
+
description: '1080p/4k require quality "high".'
|
|
1057
|
+
},
|
|
1058
|
+
aspect_ratio: { type: "string", enum: ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"] },
|
|
1059
|
+
duration: { type: "integer", minimum: 4, maximum: 15 }
|
|
1060
|
+
}
|
|
1061
|
+
// "product_url OR product_name+images" is enforced by the server and the
|
|
1062
|
+
// Zod refine; no root-level oneOf (Grok rejects non-object root unions).
|
|
1063
|
+
};
|
|
1064
|
+
adSkill = {
|
|
1065
|
+
name: "pixeldojo:ad",
|
|
1066
|
+
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.",
|
|
1067
|
+
inputZod: InputSchema8,
|
|
1068
|
+
inputJsonSchema: InputJsonSchema8,
|
|
1069
|
+
// Composition skill — the server routes to the ad engine internally.
|
|
1070
|
+
allowedModels: [],
|
|
1071
|
+
defaultModel: "",
|
|
1072
|
+
run: run8
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
});
|
|
1076
|
+
async function run9(input, ctx) {
|
|
851
1077
|
const client = ctx.client;
|
|
852
1078
|
const result = await client.runCampaign(input);
|
|
853
1079
|
if (result.kind === "campaign") {
|
|
@@ -874,10 +1100,10 @@ async function run8(input, ctx) {
|
|
|
874
1100
|
statusUrl: result.statusUrl ?? ctx.buildStatusUrl(result.campaignId)
|
|
875
1101
|
};
|
|
876
1102
|
}
|
|
877
|
-
var
|
|
1103
|
+
var InputSchema9, InputJsonSchema9, campaignSkill;
|
|
878
1104
|
var init_campaign = __esm({
|
|
879
1105
|
"src/skills/campaign.ts"() {
|
|
880
|
-
|
|
1106
|
+
InputSchema9 = z.object({
|
|
881
1107
|
productUrl: z.string().url().optional().describe("Product page URL. We extract name + description + images automatically."),
|
|
882
1108
|
product: z.object({
|
|
883
1109
|
name: z.string().min(1).max(200),
|
|
@@ -893,7 +1119,7 @@ var init_campaign = __esm({
|
|
|
893
1119
|
message: "productUrl or product is required",
|
|
894
1120
|
path: ["productUrl"]
|
|
895
1121
|
});
|
|
896
|
-
|
|
1122
|
+
InputJsonSchema9 = {
|
|
897
1123
|
type: "object",
|
|
898
1124
|
properties: {
|
|
899
1125
|
productUrl: {
|
|
@@ -924,17 +1150,17 @@ var init_campaign = __esm({
|
|
|
924
1150
|
campaignSkill = {
|
|
925
1151
|
name: "pixeldojo:campaign",
|
|
926
1152
|
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.",
|
|
927
|
-
inputZod:
|
|
928
|
-
inputJsonSchema:
|
|
1153
|
+
inputZod: InputSchema9,
|
|
1154
|
+
inputJsonSchema: InputJsonSchema9,
|
|
929
1155
|
// Composition skill — internal sub-jobs route to per-tool models, no
|
|
930
1156
|
// single allowed-models list applies here.
|
|
931
1157
|
allowedModels: [],
|
|
932
1158
|
defaultModel: "",
|
|
933
|
-
run:
|
|
1159
|
+
run: run9
|
|
934
1160
|
};
|
|
935
1161
|
}
|
|
936
1162
|
});
|
|
937
|
-
async function
|
|
1163
|
+
async function run10(input, ctx) {
|
|
938
1164
|
const client = ctx.client;
|
|
939
1165
|
const result = await client.getCampaign(input.campaignId);
|
|
940
1166
|
if (result.kind === "campaign") {
|
|
@@ -964,13 +1190,13 @@ async function run9(input, ctx) {
|
|
|
964
1190
|
statusUrl: result.statusUrl ?? ctx.buildStatusUrl(result.campaignId)
|
|
965
1191
|
};
|
|
966
1192
|
}
|
|
967
|
-
var
|
|
1193
|
+
var InputSchema10, InputJsonSchema10, campaignStatusSkill;
|
|
968
1194
|
var init_campaign_status = __esm({
|
|
969
1195
|
"src/skills/campaign-status.ts"() {
|
|
970
|
-
|
|
1196
|
+
InputSchema10 = z.object({
|
|
971
1197
|
campaignId: z.string().min(1).max(200).describe("Campaign id returned from a prior pixeldojo:campaign handoff.")
|
|
972
1198
|
});
|
|
973
|
-
|
|
1199
|
+
InputJsonSchema10 = {
|
|
974
1200
|
type: "object",
|
|
975
1201
|
properties: {
|
|
976
1202
|
campaignId: {
|
|
@@ -983,15 +1209,15 @@ var init_campaign_status = __esm({
|
|
|
983
1209
|
campaignStatusSkill = {
|
|
984
1210
|
name: "pixeldojo:campaign_status",
|
|
985
1211
|
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.",
|
|
986
|
-
inputZod:
|
|
987
|
-
inputJsonSchema:
|
|
1212
|
+
inputZod: InputSchema10,
|
|
1213
|
+
inputJsonSchema: InputJsonSchema10,
|
|
988
1214
|
allowedModels: [],
|
|
989
1215
|
defaultModel: "",
|
|
990
|
-
run:
|
|
1216
|
+
run: run10
|
|
991
1217
|
};
|
|
992
1218
|
}
|
|
993
1219
|
});
|
|
994
|
-
async function
|
|
1220
|
+
async function run11(input, ctx) {
|
|
995
1221
|
let url;
|
|
996
1222
|
try {
|
|
997
1223
|
url = await uploadLocalFile(input.path, ctx.client);
|
|
@@ -1007,16 +1233,16 @@ async function run10(input, ctx) {
|
|
|
1007
1233
|
(temp storage; auto-deletes in ~24h \u2014 pass this URL as image_url to :generate or :edit)`
|
|
1008
1234
|
};
|
|
1009
1235
|
}
|
|
1010
|
-
var
|
|
1236
|
+
var InputSchema11, InputJsonSchema11, uploadSkill;
|
|
1011
1237
|
var init_upload = __esm({
|
|
1012
1238
|
"src/skills/upload.ts"() {
|
|
1013
1239
|
init_upload_helpers();
|
|
1014
|
-
|
|
1240
|
+
InputSchema11 = z.object({
|
|
1015
1241
|
path: z.string().min(1).max(4096).describe(
|
|
1016
1242
|
"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."
|
|
1017
1243
|
)
|
|
1018
1244
|
});
|
|
1019
|
-
|
|
1245
|
+
InputJsonSchema11 = {
|
|
1020
1246
|
type: "object",
|
|
1021
1247
|
properties: {
|
|
1022
1248
|
path: {
|
|
@@ -1029,15 +1255,15 @@ var init_upload = __esm({
|
|
|
1029
1255
|
uploadSkill = {
|
|
1030
1256
|
name: "pixeldojo:upload",
|
|
1031
1257
|
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.",
|
|
1032
|
-
inputZod:
|
|
1033
|
-
inputJsonSchema:
|
|
1258
|
+
inputZod: InputSchema11,
|
|
1259
|
+
inputJsonSchema: InputJsonSchema11,
|
|
1034
1260
|
allowedModels: [],
|
|
1035
1261
|
defaultModel: "",
|
|
1036
|
-
run:
|
|
1262
|
+
run: run11
|
|
1037
1263
|
};
|
|
1038
1264
|
}
|
|
1039
1265
|
});
|
|
1040
|
-
async function
|
|
1266
|
+
async function run12(input, ctx) {
|
|
1041
1267
|
const requested = input.model ?? DEFAULT_MODEL6;
|
|
1042
1268
|
if (!ALLOWED4.includes(requested)) {
|
|
1043
1269
|
return {
|
|
@@ -1086,7 +1312,7 @@ async function run11(input, ctx) {
|
|
|
1086
1312
|
(urls) => urls.length === 0 ? `Job ${submitted.jobId} completed but returned no assets.` : `Audio ready. Asset: ${urls[0]}`
|
|
1087
1313
|
);
|
|
1088
1314
|
}
|
|
1089
|
-
var ALLOWED4, DEFAULT_MODEL6,
|
|
1315
|
+
var ALLOWED4, DEFAULT_MODEL6, InputSchema12, InputJsonSchema12, audioSkill;
|
|
1090
1316
|
var init_audio = __esm({
|
|
1091
1317
|
"src/skills/audio.ts"() {
|
|
1092
1318
|
init_poll();
|
|
@@ -1094,7 +1320,7 @@ var init_audio = __esm({
|
|
|
1094
1320
|
init_types();
|
|
1095
1321
|
ALLOWED4 = ["seed-audio", "text-to-speech"];
|
|
1096
1322
|
DEFAULT_MODEL6 = "seed-audio";
|
|
1097
|
-
|
|
1323
|
+
InputSchema12 = z.object({
|
|
1098
1324
|
prompt: z.string().min(1).describe(
|
|
1099
1325
|
"A script for speech, or a scene description for cinematic audio (dialogue + effects + music). Reference uploaded clips as @Audio1..@Audio3."
|
|
1100
1326
|
),
|
|
@@ -1105,7 +1331,7 @@ var init_audio = __esm({
|
|
|
1105
1331
|
output_format: z.string().optional().describe("seed-audio: mp3 (default), wav, pcm, ogg_opus. text-to-speech: mp3, wav, flac, pcm."),
|
|
1106
1332
|
speed: z.number().min(0.5).max(2).optional().describe("Speech speed multiplier (0.5\u20132).")
|
|
1107
1333
|
});
|
|
1108
|
-
|
|
1334
|
+
InputJsonSchema12 = {
|
|
1109
1335
|
type: "object",
|
|
1110
1336
|
properties: {
|
|
1111
1337
|
prompt: { type: "string" },
|
|
@@ -1121,15 +1347,15 @@ var init_audio = __esm({
|
|
|
1121
1347
|
audioSkill = {
|
|
1122
1348
|
name: "pixeldojo:audio",
|
|
1123
1349
|
description: "Generate audio: speech, multi-character dialogue, sound effects, and background music from one prompt (Seed Audio 1.0 by default; plain TTS available).",
|
|
1124
|
-
inputZod:
|
|
1125
|
-
inputJsonSchema:
|
|
1350
|
+
inputZod: InputSchema12,
|
|
1351
|
+
inputJsonSchema: InputJsonSchema12,
|
|
1126
1352
|
allowedModels: [...ALLOWED4],
|
|
1127
1353
|
defaultModel: DEFAULT_MODEL6,
|
|
1128
|
-
run:
|
|
1354
|
+
run: run12
|
|
1129
1355
|
};
|
|
1130
1356
|
}
|
|
1131
1357
|
});
|
|
1132
|
-
async function
|
|
1358
|
+
async function run13(input, ctx) {
|
|
1133
1359
|
const res = await ctx.client.listLibrary({
|
|
1134
1360
|
q: input.q,
|
|
1135
1361
|
model: input.model,
|
|
@@ -1160,16 +1386,16 @@ ${lines.join("\n")}
|
|
|
1160
1386
|
Pass any URL back into :generate, :edit, :character, or :upscale as a reference input.`
|
|
1161
1387
|
};
|
|
1162
1388
|
}
|
|
1163
|
-
var
|
|
1389
|
+
var InputSchema13, InputJsonSchema13, librarySkill;
|
|
1164
1390
|
var init_library = __esm({
|
|
1165
1391
|
"src/skills/library.ts"() {
|
|
1166
|
-
|
|
1392
|
+
InputSchema13 = z.object({
|
|
1167
1393
|
q: z.string().optional().describe("Substring match against the prompt that produced the asset."),
|
|
1168
1394
|
model: z.string().optional().describe("Restrict to a single model (apiId)."),
|
|
1169
1395
|
modality: z.enum(["image", "video", "audio"]).optional().describe("Restrict to one output type."),
|
|
1170
1396
|
limit: z.number().int().min(1).max(50).optional().describe("Max results (default 10).")
|
|
1171
1397
|
});
|
|
1172
|
-
|
|
1398
|
+
InputJsonSchema13 = {
|
|
1173
1399
|
type: "object",
|
|
1174
1400
|
properties: {
|
|
1175
1401
|
q: { type: "string" },
|
|
@@ -1182,15 +1408,15 @@ var init_library = __esm({
|
|
|
1182
1408
|
librarySkill = {
|
|
1183
1409
|
name: "pixeldojo:library",
|
|
1184
1410
|
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.",
|
|
1185
|
-
inputZod:
|
|
1186
|
-
inputJsonSchema:
|
|
1411
|
+
inputZod: InputSchema13,
|
|
1412
|
+
inputJsonSchema: InputJsonSchema13,
|
|
1187
1413
|
allowedModels: [],
|
|
1188
1414
|
defaultModel: "",
|
|
1189
|
-
run:
|
|
1415
|
+
run: run13
|
|
1190
1416
|
};
|
|
1191
1417
|
}
|
|
1192
1418
|
});
|
|
1193
|
-
async function
|
|
1419
|
+
async function run14(input, ctx) {
|
|
1194
1420
|
const res = await ctx.client.saveMedia({
|
|
1195
1421
|
url: input.url,
|
|
1196
1422
|
prompt: input.prompt,
|
|
@@ -1204,17 +1430,17 @@ async function run13(input, ctx) {
|
|
|
1204
1430
|
It will appear at https://pixeldojo.ai/my-images and in pixeldojo:library searches.`
|
|
1205
1431
|
};
|
|
1206
1432
|
}
|
|
1207
|
-
var
|
|
1433
|
+
var InputSchema14, InputJsonSchema14, saveSkill;
|
|
1208
1434
|
var init_save = __esm({
|
|
1209
1435
|
"src/skills/save.ts"() {
|
|
1210
|
-
|
|
1436
|
+
InputSchema14 = z.object({
|
|
1211
1437
|
url: z.string().url().describe("The asset URL to save (image or video)."),
|
|
1212
1438
|
prompt: z.string().optional().describe("The prompt that produced it \u2014 makes it findable in the library later."),
|
|
1213
1439
|
tool_name: z.string().optional().describe("Tool/model slug that produced it."),
|
|
1214
1440
|
modality: z.enum(["image", "video", "audio"]).optional(),
|
|
1215
1441
|
job_id: z.string().optional().describe("The jobId that produced this asset, when known.")
|
|
1216
1442
|
});
|
|
1217
|
-
|
|
1443
|
+
InputJsonSchema14 = {
|
|
1218
1444
|
type: "object",
|
|
1219
1445
|
properties: {
|
|
1220
1446
|
url: { type: "string", format: "uri" },
|
|
@@ -1228,11 +1454,11 @@ var init_save = __esm({
|
|
|
1228
1454
|
saveSkill = {
|
|
1229
1455
|
name: "pixeldojo:save",
|
|
1230
1456
|
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.",
|
|
1231
|
-
inputZod:
|
|
1232
|
-
inputJsonSchema:
|
|
1457
|
+
inputZod: InputSchema14,
|
|
1458
|
+
inputJsonSchema: InputJsonSchema14,
|
|
1233
1459
|
allowedModels: [],
|
|
1234
1460
|
defaultModel: "",
|
|
1235
|
-
run:
|
|
1461
|
+
run: run14
|
|
1236
1462
|
};
|
|
1237
1463
|
}
|
|
1238
1464
|
});
|
|
@@ -1444,6 +1670,7 @@ var init_workflows = __esm({
|
|
|
1444
1670
|
var skills_exports = {};
|
|
1445
1671
|
__export(skills_exports, {
|
|
1446
1672
|
ALL_SKILLS: () => ALL_SKILLS,
|
|
1673
|
+
adSkill: () => adSkill,
|
|
1447
1674
|
audioSkill: () => audioSkill,
|
|
1448
1675
|
campaignSkill: () => campaignSkill,
|
|
1449
1676
|
campaignStatusSkill: () => campaignStatusSkill,
|
|
@@ -1475,6 +1702,7 @@ var init_skills = __esm({
|
|
|
1475
1702
|
init_upscale();
|
|
1476
1703
|
init_status();
|
|
1477
1704
|
init_from_url();
|
|
1705
|
+
init_ad();
|
|
1478
1706
|
init_campaign();
|
|
1479
1707
|
init_campaign_status();
|
|
1480
1708
|
init_upload();
|
|
@@ -1497,6 +1725,7 @@ var init_skills = __esm({
|
|
|
1497
1725
|
statusSkill,
|
|
1498
1726
|
fromUrlSkill,
|
|
1499
1727
|
uploadSkill,
|
|
1728
|
+
adSkill,
|
|
1500
1729
|
campaignSkill,
|
|
1501
1730
|
campaignStatusSkill
|
|
1502
1731
|
];
|
|
@@ -1553,7 +1782,7 @@ function makeRedactedLogger(target = console) {
|
|
|
1553
1782
|
}
|
|
1554
1783
|
|
|
1555
1784
|
// src/server.ts
|
|
1556
|
-
var PACKAGE_VERSION = "0.
|
|
1785
|
+
var PACKAGE_VERSION = "0.8.0" ;
|
|
1557
1786
|
function buildServer(options) {
|
|
1558
1787
|
if (!options.apiKey) {
|
|
1559
1788
|
throw new Error(
|