makefx 1.6.7 → 1.6.9

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/makefx.mjs +447 -37
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -61,4 +61,4 @@ IDs, or runs. Retired commands and aliases are not redirected.
61
61
 
62
62
  Run `makefx --help` or `makefx <noun> --help` for current options.
63
63
 
64
- Version: 1.6.7
64
+ Version: 1.6.9
package/makefx.mjs CHANGED
@@ -198,6 +198,24 @@ function loginCommandForEnvironment(environment) {
198
198
  if (environment === "local") return "makefx login --local";
199
199
  return `makefx login --env ${environment}`;
200
200
  }
201
+ //#endregion
202
+ //#region src/cli/lib/http-response.ts
203
+ var MAX_ERROR_BODY_LENGTH = 500;
204
+ function boundedBody(body) {
205
+ const trimmed = body.trim();
206
+ if (trimmed.length <= MAX_ERROR_BODY_LENGTH) return trimmed;
207
+ return `${trimmed.slice(0, MAX_ERROR_BODY_LENGTH)}…`;
208
+ }
209
+ async function readJsonResponse(response, description) {
210
+ const contentType = response.headers.get("content-type") ?? "unknown";
211
+ const body = await response.text();
212
+ try {
213
+ return JSON.parse(body);
214
+ } catch {
215
+ const detail = boundedBody(body);
216
+ throw new Error(`${description} returned non-JSON (HTTP ${response.status}; content-type: ${contentType})${detail ? `: ${detail}` : ""}`);
217
+ }
218
+ }
201
219
  var EXT_TO_MEDIA_TYPE = {
202
220
  ".aac": {
203
221
  mediaKind: "audio",
@@ -301,7 +319,7 @@ async function uploadLocalMediaAsReference(input) {
301
319
  headers: { "Authorization": `Bearer ${input.accessToken}` },
302
320
  body: formData
303
321
  });
304
- const data = await response.json();
322
+ const data = await readJsonResponse(response, "Reference upload request");
305
323
  if (!response.ok || !data.success || !data.variant) throw new Error(`Failed to upload reference "${input.filePath}": ${data.error || response.statusText}`);
306
324
  return {
307
325
  asset: data.asset,
@@ -4442,7 +4460,7 @@ require_websocket_server();
4442
4460
  var wrapper_default = import_websocket.default;
4443
4461
  //#endregion
4444
4462
  //#region src/cli/version.ts
4445
- var CLI_VERSION = "1.6.7+0439271d1461";
4463
+ var CLI_VERSION = "1.6.9+4949b061ecf5";
4446
4464
  var CLI_VERSION_HEADER = "X-MakeFX-CLI-Version";
4447
4465
  function cliVersionHeaders() {
4448
4466
  return {
@@ -5200,6 +5218,10 @@ var WebSocketClient = class WebSocketClient {
5200
5218
  videoTier: params.videoTier,
5201
5219
  seedanceDuration: params.seedanceDuration,
5202
5220
  seedanceBitrateMode: params.seedanceBitrateMode,
5221
+ wan3Duration: params.wan3Duration,
5222
+ wan3Seed: params.wan3Seed,
5223
+ wan3PromptExpansion: params.wan3PromptExpansion,
5224
+ wan3Thinking: params.wan3Thinking,
5203
5225
  provider: params.provider,
5204
5226
  avatarResolution: params.avatarResolution,
5205
5227
  avatarMode: params.avatarMode,
@@ -6078,7 +6100,7 @@ var SEEDANCE_25_DURATIONS = [
6078
6100
  30
6079
6101
  ];
6080
6102
  var SEEDANCE_2_BITRATE_MODES = ["standard", "high"];
6081
- var MB = 1024 * 1024;
6103
+ var MB$1 = 1024 * 1024;
6082
6104
  var IMAGE_REFERENCE_RULE = {
6083
6105
  mediaKind: "image",
6084
6106
  minCount: 0,
@@ -6089,7 +6111,7 @@ var IMAGE_REFERENCE_RULE = {
6089
6111
  "image/png",
6090
6112
  "image/webp"
6091
6113
  ],
6092
- maxBytesPerFile: 30 * MB
6114
+ maxBytesPerFile: 30 * MB$1
6093
6115
  };
6094
6116
  var VIDEO_REFERENCE_RULE = {
6095
6117
  mediaKind: "video",
@@ -6097,8 +6119,8 @@ var VIDEO_REFERENCE_RULE = {
6097
6119
  maxCount: 3,
6098
6120
  promptLabel: "@VideoN",
6099
6121
  acceptedMimeTypes: ["video/mp4", "video/quicktime"],
6100
- maxBytesPerFile: 50 * MB,
6101
- combinedMaxBytes: 50 * MB,
6122
+ maxBytesPerFile: 50 * MB$1,
6123
+ combinedMaxBytes: 50 * MB$1,
6102
6124
  combinedDurationSeconds: {
6103
6125
  min: 2,
6104
6126
  max: 15
@@ -6118,7 +6140,7 @@ var AUDIO_REFERENCE_RULE = {
6118
6140
  "audio/wav",
6119
6141
  "audio/x-wav"
6120
6142
  ],
6121
- maxBytesPerFile: 15 * MB,
6143
+ maxBytesPerFile: 15 * MB$1,
6122
6144
  combinedDurationSeconds: { max: 15 }
6123
6145
  };
6124
6146
  function profile(mode, tier, endpointId) {
@@ -6187,7 +6209,7 @@ var SEEDANCE_25_IMAGE_REFERENCE_RULE = {
6187
6209
  "image/webp",
6188
6210
  "image/gif"
6189
6211
  ],
6190
- maxBytesPerFile: 30 * MB
6212
+ maxBytesPerFile: 30 * MB$1
6191
6213
  };
6192
6214
  var SEEDANCE_25_FRAME_IMAGE_REFERENCE_RULE = {
6193
6215
  ...SEEDANCE_25_IMAGE_REFERENCE_RULE,
@@ -6205,7 +6227,7 @@ var SEEDANCE_25_VIDEO_REFERENCE_RULE = {
6205
6227
  maxCount: 10,
6206
6228
  promptLabel: "@VideoN",
6207
6229
  acceptedMimeTypes: ["video/mp4", "video/quicktime"],
6208
- maxBytesPerFile: 50 * MB,
6230
+ maxBytesPerFile: 50 * MB$1,
6209
6231
  combinedDurationSeconds: { max: 30.2 },
6210
6232
  perFileDurationSeconds: {
6211
6233
  min: 1.8,
@@ -6230,7 +6252,7 @@ var SEEDANCE_25_AUDIO_REFERENCE_RULE = {
6230
6252
  "audio/wav",
6231
6253
  "audio/x-wav"
6232
6254
  ],
6233
- maxBytesPerFile: 15 * MB,
6255
+ maxBytesPerFile: 15 * MB$1,
6234
6256
  combinedDurationSeconds: { max: 30.2 },
6235
6257
  perFileDurationSeconds: {
6236
6258
  min: 1.8,
@@ -6371,6 +6393,158 @@ function getSeedance2CapabilityByEndpoint(endpointId) {
6371
6393
  return SEEDANCE_2_SELECTIONS.map((selection) => SEEDANCE_2_CAPABILITIES[selection]).find((capability) => capability.endpointId === endpointId);
6372
6394
  }
6373
6395
  //#endregion
6396
+ //#region src/shared/wan3Capabilities.ts
6397
+ var WAN_3_ASPECT_RATIOS = [
6398
+ "adaptive",
6399
+ "16:9",
6400
+ "4:3",
6401
+ "1:1",
6402
+ "3:4",
6403
+ "9:16"
6404
+ ];
6405
+ var WAN_3_RESOLUTIONS = [
6406
+ "480p",
6407
+ "720p",
6408
+ "1080p"
6409
+ ];
6410
+ var WAN_3_DURATIONS = [
6411
+ "auto",
6412
+ 2,
6413
+ 3,
6414
+ 4,
6415
+ 5,
6416
+ 6,
6417
+ 7,
6418
+ 8,
6419
+ 9,
6420
+ 10,
6421
+ 11,
6422
+ 12,
6423
+ 13,
6424
+ 14,
6425
+ 15,
6426
+ 16,
6427
+ 17,
6428
+ 18,
6429
+ 19,
6430
+ 20,
6431
+ 21,
6432
+ 22,
6433
+ 23,
6434
+ 24,
6435
+ 25,
6436
+ 26,
6437
+ 27,
6438
+ 28,
6439
+ 29,
6440
+ 30
6441
+ ];
6442
+ var MB = 1024 * 1024;
6443
+ var IMAGE_RULE = {
6444
+ mediaKind: "image",
6445
+ minCount: 0,
6446
+ maxCount: 10,
6447
+ promptLabel: "@ImageN",
6448
+ acceptedMimeTypes: [
6449
+ "image/jpeg",
6450
+ "image/png",
6451
+ "image/webp"
6452
+ ],
6453
+ maxBytesPerFile: 30 * MB
6454
+ };
6455
+ var FRAME_RULE = {
6456
+ ...IMAGE_RULE,
6457
+ minCount: 1,
6458
+ maxCount: 2
6459
+ };
6460
+ var VIDEO_RULE = {
6461
+ mediaKind: "video",
6462
+ minCount: 0,
6463
+ maxCount: 5,
6464
+ promptLabel: "@VideoN",
6465
+ acceptedMimeTypes: ["video/mp4", "video/quicktime"],
6466
+ maxBytesPerFile: 50 * MB,
6467
+ combinedDurationSeconds: { max: 15 }
6468
+ };
6469
+ var AUDIO_RULE = {
6470
+ mediaKind: "audio",
6471
+ minCount: 0,
6472
+ maxCount: 5,
6473
+ promptLabel: "@AudioN",
6474
+ acceptedMimeTypes: [
6475
+ "audio/mpeg",
6476
+ "audio/wav",
6477
+ "audio/x-wav"
6478
+ ],
6479
+ maxBytesPerFile: 15 * MB,
6480
+ combinedDurationSeconds: { max: 15 }
6481
+ };
6482
+ function capability(mode, endpointId) {
6483
+ const selection = `wan-3-${mode}`;
6484
+ const references = mode === "frame" ? [FRAME_RULE] : mode === "reference" ? [
6485
+ IMAGE_RULE,
6486
+ VIDEO_RULE,
6487
+ AUDIO_RULE
6488
+ ] : [];
6489
+ return {
6490
+ selection,
6491
+ generatorId: `video/${selection}`,
6492
+ endpointId,
6493
+ label: `WAN 3.0 ${mode === "text" ? "Text" : mode === "frame" ? "Frames" : "References"}`,
6494
+ mode,
6495
+ resolutions: WAN_3_RESOLUTIONS,
6496
+ aspectRatios: WAN_3_ASPECT_RATIOS,
6497
+ durations: WAN_3_DURATIONS,
6498
+ defaultResolution: "1080p",
6499
+ defaultAspectRatio: "adaptive",
6500
+ defaultDuration: 5,
6501
+ references,
6502
+ maxReferenceFiles: mode === "frame" ? 2 : mode === "reference" ? 20 : 0
6503
+ };
6504
+ }
6505
+ var WAN_3_CAPABILITIES = [
6506
+ capability("text", "alibaba/wan-3.0/text-to-video"),
6507
+ capability("frame", "alibaba/wan-3.0/image-to-video"),
6508
+ capability("reference", "alibaba/wan-3.0/reference-to-video")
6509
+ ];
6510
+ var WAN_3_SELECTIONS = WAN_3_CAPABILITIES.map((item) => item.selection);
6511
+ WAN_3_CAPABILITIES.map((item) => item.endpointId);
6512
+ function getWan3CapabilityBySelection(value) {
6513
+ return WAN_3_CAPABILITIES.find((item) => item.selection === value);
6514
+ }
6515
+ function getWan3CapabilityByEndpoint(value) {
6516
+ return WAN_3_CAPABILITIES.find((item) => item.endpointId === value);
6517
+ }
6518
+ function isWan3Duration(value) {
6519
+ return WAN_3_DURATIONS.includes(value);
6520
+ }
6521
+ function countWan3References(references) {
6522
+ return references.reduce((counts, reference) => {
6523
+ if (reference.mediaKind in counts) counts[reference.mediaKind] += 1;
6524
+ return counts;
6525
+ }, {
6526
+ image: 0,
6527
+ video: 0,
6528
+ audio: 0
6529
+ });
6530
+ }
6531
+ function getWan3ReferenceError(capability_, references) {
6532
+ const counts = countWan3References(references);
6533
+ const unsupported = references.find((reference) => !capability_.references.some((rule) => rule.mediaKind === reference.mediaKind));
6534
+ if (unsupported) return `${capability_.label} does not accept ${unsupported.mediaKind} references`;
6535
+ if (references.length > capability_.maxReferenceFiles) return `${capability_.label} accepts at most ${capability_.maxReferenceFiles} references`;
6536
+ if (capability_.mode === "reference" && references.length === 0) return "WAN 3.0 reference-to-video requires at least one image, video, or audio reference";
6537
+ for (const rule of capability_.references) {
6538
+ const count = counts[rule.mediaKind];
6539
+ if (count < rule.minCount || count > rule.maxCount) return `${capability_.label} requires ${rule.minCount}-${rule.maxCount} ${rule.mediaKind} references`;
6540
+ if (rule.combinedDurationSeconds) {
6541
+ if (references.filter((reference) => reference.mediaKind === rule.mediaKind).reduce((total, reference) => total + (reference.durationMs ?? 0), 0) / 1e3 > rule.combinedDurationSeconds.max) return `${capability_.label} accepts at most ${rule.combinedDurationSeconds.max}s of ${rule.mediaKind} references combined`;
6542
+ }
6543
+ }
6544
+ if (capability_.mode === "text" && references.length > 0) return "WAN 3.0 text-to-video does not accept references";
6545
+ return null;
6546
+ }
6547
+ //#endregion
6374
6548
  //#region src/shared/videoGenerationOptions.ts
6375
6549
  var VIDEO_GENERATION_ASPECT_RATIOS = ["16:9", "9:16"];
6376
6550
  var VIDEO_GENERATION_RESOLUTIONS = [
@@ -6408,13 +6582,17 @@ var VIDEO_MODEL_SELECTIONS = [
6408
6582
  "veo-3.1",
6409
6583
  "omni-flash",
6410
6584
  "kling",
6411
- "fal-seedance"
6585
+ "fal-seedance",
6586
+ ...WAN_3_SELECTIONS
6412
6587
  ];
6413
6588
  var VIDEO_MODEL_LABELS = {
6414
6589
  "veo-3.1": "Veo 3.1",
6415
6590
  "omni-flash": "Omni Flash",
6416
6591
  kling: "Kling 3.0",
6417
- "fal-seedance": "fal.ai Seedance v1 (text-to-video)"
6592
+ "fal-seedance": "fal.ai Seedance v1 (text-to-video)",
6593
+ "wan-3-text": "WAN 3.0 Text",
6594
+ "wan-3-frame": "WAN 3.0 Frames",
6595
+ "wan-3-reference": "WAN 3.0 References"
6418
6596
  };
6419
6597
  var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
6420
6598
  "veo-3.1": [
@@ -6432,7 +6610,10 @@ var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
6432
6610
  "refine",
6433
6611
  "derive"
6434
6612
  ],
6435
- "fal-seedance": ["generate"]
6613
+ "fal-seedance": ["generate"],
6614
+ "wan-3-text": ["generate"],
6615
+ "wan-3-frame": ["derive"],
6616
+ "wan-3-reference": ["derive", "refine"]
6436
6617
  };
6437
6618
  var KLING_VIDEO_MODEL = "kling-v3";
6438
6619
  var FAL_VIDEO_MODEL = "fal-ai/bytedance/seedance/v1/pro/text-to-video";
@@ -6490,6 +6671,8 @@ function getVideoGenerationModelForSelection(selection = DEFAULT_VIDEO_MODEL_SEL
6490
6671
  if (selection === "omni-flash") return GEMINI_OMNI_FLASH_VIDEO_MODEL;
6491
6672
  if (selection === "kling") return KLING_VIDEO_MODEL;
6492
6673
  if (selection === "fal-seedance") return FAL_VIDEO_MODEL;
6674
+ const wan3 = getWan3CapabilityBySelection(selection);
6675
+ if (wan3) return wan3.endpointId;
6493
6676
  return getVideoGenerationModelForTier(tier);
6494
6677
  }
6495
6678
  function resolveVideoGenerationModel(model, tier = DEFAULT_VIDEO_GENERATION_TIER) {
@@ -6505,6 +6688,8 @@ function isVideoGenerationResolutionSupportedForTier(resolution, tier = DEFAULT_
6505
6688
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].includes(resolution);
6506
6689
  }
6507
6690
  function getVideoGenerationResolutionsForModel(model) {
6691
+ const wan3 = getWan3CapabilityByEndpoint(model);
6692
+ if (wan3) return [...wan3.resolutions];
6508
6693
  if (isKlingVideoGenerationModel(model) || isFalSeedanceV1VideoGenerationModel(model)) return KLING_VIDEO_GENERATION_RESOLUTIONS;
6509
6694
  const seedanceCapability = getSeedance2CapabilityByEndpoint(model);
6510
6695
  if (seedanceCapability) return [...seedanceCapability.resolutions];
@@ -6521,6 +6706,8 @@ function getVideoModelSelectionForModel(model) {
6521
6706
  if (model === "gemini-omni-flash-preview") return "omni-flash";
6522
6707
  if (model === "kling-v3") return "kling";
6523
6708
  if (model === "fal-ai/bytedance/seedance/v1/pro/text-to-video") return "fal-seedance";
6709
+ const wan3 = getWan3CapabilityByEndpoint(model);
6710
+ if (wan3) return wan3.selection;
6524
6711
  return getVideoGenerationTierForModel(model) ? "veo-3.1" : void 0;
6525
6712
  }
6526
6713
  function isVeoVideoGenerationModel(model) {
@@ -6533,7 +6720,7 @@ function isKlingVideoGenerationModel(model) {
6533
6720
  return model === KLING_VIDEO_MODEL;
6534
6721
  }
6535
6722
  function isFalVideoGenerationModel(model) {
6536
- return isFalSeedanceV1VideoGenerationModel(model) || isFalSeedance2VideoGenerationModel(model);
6723
+ return isFalSeedanceV1VideoGenerationModel(model) || isFalSeedance2VideoGenerationModel(model) || isFalWan3VideoGenerationModel(model);
6537
6724
  }
6538
6725
  function isFalSeedanceV1VideoGenerationModel(model) {
6539
6726
  return model === FAL_VIDEO_MODEL;
@@ -6541,10 +6728,15 @@ function isFalSeedanceV1VideoGenerationModel(model) {
6541
6728
  function isFalSeedance2VideoGenerationModel(model) {
6542
6729
  return typeof model === "string" && getSeedance2CapabilityByEndpoint(model) !== void 0;
6543
6730
  }
6731
+ function isFalWan3VideoGenerationModel(model) {
6732
+ return getWan3CapabilityByEndpoint(model) !== void 0;
6733
+ }
6544
6734
  function isVideoGenerationModel(model) {
6545
6735
  return isVeoVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model);
6546
6736
  }
6547
6737
  function getVideoGenerationMaxReferenceImages(model) {
6738
+ const wan3 = getWan3CapabilityByEndpoint(model);
6739
+ if (wan3) return wan3.references.find((reference) => reference.mediaKind === "image")?.maxCount ?? 0;
6548
6740
  if (isFalSeedanceV1VideoGenerationModel(model)) return 0;
6549
6741
  if (isFalSeedance2VideoGenerationModel(model)) return getSeedance2CapabilityByEndpoint(model)?.references.find((reference) => reference.mediaKind === "image")?.maxCount ?? 0;
6550
6742
  if (isKlingVideoGenerationModel(model)) return 1;
@@ -6557,7 +6749,7 @@ function isVideoOperationSupportedByModel(model, operation) {
6557
6749
  return selection !== void 0 && VIDEO_MODEL_SUPPORTED_OPERATIONS[selection].includes(operation);
6558
6750
  }
6559
6751
  function doesVideoGenerationModelSupportAudioToggle(model) {
6560
- return isKlingVideoGenerationModel(model) || isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6752
+ return isFalWan3VideoGenerationModel(model) || isKlingVideoGenerationModel(model) || isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6561
6753
  }
6562
6754
  //#endregion
6563
6755
  //#region src/shared/generationRouting.ts
@@ -7075,6 +7267,9 @@ var CLI_GENERATION_MEDIA_OPTIONS = {
7075
7267
  "mode",
7076
7268
  "guidance-scale",
7077
7269
  "audio-guidance-scale",
7270
+ "seed",
7271
+ "prompt-expansion",
7272
+ "thinking",
7078
7273
  "provider"
7079
7274
  ]
7080
7275
  };
@@ -7131,23 +7326,28 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
7131
7326
  const musicProvider = parseMusicProviderOption(parsed, mediaKind, assetType);
7132
7327
  const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
7133
7328
  const seedanceCapability = mediaKind === "video" ? getSeedance2CapabilityByEndpoint(effectiveVideoModel) : void 0;
7329
+ const wan3Capability = mediaKind === "video" ? getWan3CapabilityByEndpoint(effectiveVideoModel) : void 0;
7134
7330
  const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
7135
7331
  const seedanceRefs = parseSeedanceReferenceOptions(parsed);
7332
+ const seedanceReferenceCount = seedanceRefs.imageRefs.length + seedanceRefs.videoRefs.length + seedanceRefs.audioRefs.length;
7136
7333
  const plainRefs = parseOptionalRefs(parsed, "refs");
7137
7334
  validateSeedanceReferenceOptions(seedanceRefs, effectiveVideoModel, "generate");
7138
7335
  if (seedanceCapability?.mode === "frame" && videoFrameRefs.length === 0) throw new Error(`--model ${seedanceCapability.selection} requires --first-frame`);
7139
7336
  if (seedanceCapability?.mode === "text" && videoFrameRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} does not accept references`);
7140
7337
  if (seedanceCapability?.mode === "reference" && videoFrameRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} uses --image-refs, --video-refs, and --audio-refs`);
7141
7338
  if (seedanceCapability && plainRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} uses --image-refs, --video-refs, and --audio-refs instead of --refs`);
7339
+ if (wan3Capability?.mode === "frame" && videoFrameRefs.length === 0) throw new Error(`--model ${wan3Capability.selection} requires --first-frame`);
7340
+ if (wan3Capability?.mode === "text" && (videoFrameRefs.length > 0 || seedanceReferenceCount > 0)) throw new Error(`--model ${wan3Capability.selection} does not accept references`);
7341
+ if (wan3Capability?.mode === "reference" && videoFrameRefs.length > 0) throw new Error(`--model ${wan3Capability.selection} uses --image-refs, --video-refs, and --audio-refs`);
7342
+ if (wan3Capability && plainRefs.length > 0) throw new Error(`--model ${wan3Capability.selection} uses typed frame or grouped reference options instead of --refs`);
7142
7343
  if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length + plainRefs.length > 1) throw new Error("--model kling supports at most one image reference");
7143
- if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && (videoFrameRefs.length > 0 || plainRefs.length > 0)) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support image references`);
7144
- const seedanceReferenceCount = seedanceRefs.imageRefs.length + seedanceRefs.videoRefs.length + seedanceRefs.audioRefs.length;
7344
+ if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && !isFalWan3VideoGenerationModel(effectiveVideoModel) && (videoFrameRefs.length > 0 || plainRefs.length > 0)) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support image references`);
7145
7345
  const state = videoFrameRefs.length > 0 || seedanceReferenceCount > 0 || plainRefs.length > 0 ? await requestSpaceState(client) : void 0;
7146
7346
  const referenceDeps = {
7147
7347
  ...deps,
7148
7348
  waitForReferenceVariant: (variant) => waitForReferenceVariant(client, variant)
7149
7349
  };
7150
- const resolvedSeedanceRefs = state && seedanceReferenceCount > 0 ? isAvatarModelId(effectiveVideoModel) ? await resolveAvatarReferenceIds(seedanceRefs, ctx, referenceDeps, state) : await resolveSeedanceReferenceIds(seedanceRefs, seedanceCapability, ctx, referenceDeps, state) : {
7350
+ const resolvedSeedanceRefs = state && seedanceReferenceCount > 0 ? isAvatarModelId(effectiveVideoModel) ? await resolveAvatarReferenceIds(seedanceRefs, ctx, referenceDeps, state) : wan3Capability ? await resolveWan3ReferenceIds(seedanceRefs, ctx, referenceDeps, state) : await resolveSeedanceReferenceIds(seedanceRefs, seedanceCapability, ctx, referenceDeps, state) : {
7151
7351
  refs: [],
7152
7352
  ids: []
7153
7353
  };
@@ -7326,11 +7526,26 @@ function validateSeedanceReferenceOptions(options, model, command) {
7326
7526
  return;
7327
7527
  }
7328
7528
  const capability = getSeedance2CapabilityByEndpoint(model);
7529
+ const wan3Capability = getWan3CapabilityByEndpoint(model);
7329
7530
  const total = options.imageRefs.length + options.videoRefs.length + options.audioRefs.length;
7330
- if (!capability) {
7331
- if (total > 0) throw new Error("--image-refs, --video-refs, and --audio-refs require a Seedance 2 reference model");
7531
+ if (!capability && !wan3Capability) {
7532
+ if (total > 0) throw new Error("--image-refs, --video-refs, and --audio-refs require a Seedance 2 or WAN 3.0 reference model");
7332
7533
  return;
7333
7534
  }
7535
+ if (wan3Capability) {
7536
+ if (wan3Capability.mode !== "reference") {
7537
+ if (total > 0) throw new Error(`--model ${wan3Capability.selection} does not accept grouped references`);
7538
+ return;
7539
+ }
7540
+ const error = getWan3ReferenceError(wan3Capability, [
7541
+ ...options.imageRefs.map(() => ({ mediaKind: "image" })),
7542
+ ...options.videoRefs.map(() => ({ mediaKind: "video" })),
7543
+ ...options.audioRefs.map(() => ({ mediaKind: "audio" }))
7544
+ ]);
7545
+ if (error) throw new Error(error);
7546
+ return;
7547
+ }
7548
+ if (!capability) return;
7334
7549
  if (capability.mode !== "reference") {
7335
7550
  if (total > 0) throw new Error(`--model ${capability.selection} does not accept grouped references`);
7336
7551
  return;
@@ -7373,6 +7588,26 @@ async function resolveSeedanceReferenceIds(options, capability, ctx, deps, state
7373
7588
  ]
7374
7589
  };
7375
7590
  }
7591
+ async function resolveWan3ReferenceIds(options, ctx, deps, state) {
7592
+ const resolve = (refs, kind) => resolveReferenceVariantIds(refs, ctx, deps, state.variants, "video", state.assets, kind);
7593
+ const [imageIds, videoIds, audioIds] = await Promise.all([
7594
+ resolve(options.imageRefs, "image"),
7595
+ resolve(options.videoRefs, "video"),
7596
+ resolve(options.audioRefs, "audio")
7597
+ ]);
7598
+ return {
7599
+ refs: [
7600
+ ...options.imageRefs,
7601
+ ...options.videoRefs,
7602
+ ...options.audioRefs
7603
+ ],
7604
+ ids: [
7605
+ ...imageIds,
7606
+ ...videoIds,
7607
+ ...audioIds
7608
+ ]
7609
+ };
7610
+ }
7376
7611
  async function preflightLocalSeedanceReferences(options, deps, state, capability = SEEDANCE_2_CAPABILITIES["seedance-2-reference"]) {
7377
7612
  if (!deps.inspectLocalReference) return;
7378
7613
  const inspections = {
@@ -7718,9 +7953,12 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7718
7953
  const modeValue = readOptionalOption(parsed, "mode");
7719
7954
  const guidanceScaleValue = readOptionalOption(parsed, "guidance-scale");
7720
7955
  const audioGuidanceScaleValue = readOptionalOption(parsed, "audio-guidance-scale");
7956
+ const seedValue = mediaKind === "video" ? readOptionalOption(parsed, "seed") : void 0;
7957
+ const promptExpansionValue = mediaKind === "video" ? parsed.options["prompt-expansion"] : void 0;
7958
+ const thinkingValue = mediaKind === "video" ? parsed.options.thinking : void 0;
7721
7959
  const modelValue = mediaKind === "video" ? readOptionalOption(parsed, "model") : void 0;
7722
7960
  const aspectValue = mediaKind === "video" ? readOptionalOption(parsed, "aspect") : void 0;
7723
- if (mediaKind !== "video" && resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0 && bitrateValue === void 0 && modeValue === void 0 && guidanceScaleValue === void 0 && audioGuidanceScaleValue === void 0) return {};
7961
+ if (mediaKind !== "video" && resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0 && bitrateValue === void 0 && modeValue === void 0 && guidanceScaleValue === void 0 && audioGuidanceScaleValue === void 0 && seedValue === void 0 && promptExpansionValue === void 0 && thinkingValue === void 0) return {};
7724
7962
  if (mediaKind !== "video") throw new Error("Video model controls are only supported for video generation");
7725
7963
  const videoResolution = resolutionValue === void 0 ? void 0 : normalizeVideoGenerationResolution(resolutionValue);
7726
7964
  if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 480p, 720p, 1080p, or 4k");
@@ -7729,7 +7967,7 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7729
7967
  const model = parseVideoModelOption(modelValue, videoTier, parsed);
7730
7968
  if (isAvatarModelId(model)) {
7731
7969
  if (parsed.options.refs !== void 0 || parsed.options["first-frame"] !== void 0 || parsed.options["last-frame"] !== void 0) throw new Error("Avatar models accept only --image-refs and --audio-refs");
7732
- if (aspectValue !== void 0 || durationValue !== void 0 || tierValue !== void 0 || bitrateValue !== void 0 || parsed.options.audio !== void 0 || parsed.options["no-audio"] !== void 0) throw new Error("Avatar models do not accept --aspect, --duration, --tier, --bitrate, --audio, or --no-audio");
7970
+ if (aspectValue !== void 0 || durationValue !== void 0 || tierValue !== void 0 || bitrateValue !== void 0 || parsed.options.audio !== void 0 || parsed.options["no-audio"] !== void 0 || seedValue !== void 0 || promptExpansionValue !== void 0 || thinkingValue !== void 0) throw new Error("Avatar models do not accept --aspect, --duration, --tier, --bitrate, --audio, or --no-audio");
7733
7971
  if (model === "kling-avatar-v2") {
7734
7972
  if (parsed.options.provider !== void 0) throw new Error("Kling Avatar V2 does not accept --provider");
7735
7973
  if (resolutionValue !== void 0 || guidanceScaleValue !== void 0 || audioGuidanceScaleValue !== void 0) throw new Error("Aurora controls are not supported by --model kling-avatar-v2");
@@ -7759,26 +7997,39 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7759
7997
  if (modeValue !== void 0) throw new Error("--mode is only supported by --model kling-avatar-v2");
7760
7998
  if (guidanceScaleValue !== void 0 || audioGuidanceScaleValue !== void 0) throw new Error("--guidance-scale and --audio-guidance-scale require --model creatify-aurora");
7761
7999
  const seedanceCapability = getSeedance2CapabilityByEndpoint(model);
8000
+ const wan3Capability = getWan3CapabilityByEndpoint(model);
7762
8001
  const seedanceDuration = durationValue === void 0 ? void 0 : seedanceCapability ? normalizeSeedanceDuration(durationValue, model) : void 0;
8002
+ const wan3Duration = durationValue === void 0 ? void 0 : wan3Capability ? durationValue === "auto" ? "auto" : Number(durationValue) : void 0;
7763
8003
  const videoDurationSeconds = durationValue === void 0 || durationValue === "auto" ? void 0 : normalizeVideoGenerationDurationSeconds(durationValue);
7764
8004
  if (seedanceCapability && durationValue !== void 0 && seedanceDuration === void 0) {
7765
8005
  const numericDurations = seedanceCapability.durations.filter((value) => typeof value === "number");
7766
8006
  throw new Error(`--duration must be auto or an integer from ${numericDurations[0]} to ${numericDurations.at(-1)}`);
7767
8007
  }
7768
- if (!seedanceCapability && durationValue === "auto") throw new Error("--duration auto is only supported by Seedance 2");
8008
+ if (wan3Capability && durationValue !== void 0 && !isWan3Duration(wan3Duration)) throw new Error("--duration must be auto or an integer from 2 to 30 for WAN 3.0");
8009
+ if (!seedanceCapability && !wan3Capability && durationValue === "auto") throw new Error("--duration auto is only supported by Seedance 2 and WAN 3.0");
7769
8010
  if (isGeminiOmniVideoGenerationModel(model) && (resolutionValue !== void 0 || durationValue !== void 0 || tierValue !== void 0)) throw new Error("--resolution, --duration, and --tier are only supported with --model veo-3.1");
7770
8011
  if ((isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && tierValue !== void 0) throw new Error("--tier is only supported with --model veo-3.1");
7771
8012
  if (videoResolution && videoTier && !isVideoGenerationResolutionSupportedForTier(videoResolution, videoTier)) throw new Error("--resolution 4k is not supported with --tier lite");
7772
8013
  if (videoResolution && (isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && !isVideoGenerationResolutionSupportedForModel(model, videoResolution)) throw new Error(`--model ${getVideoModelSelectionForModel(model) ?? model} does not support --resolution ${videoResolution}`);
7773
- if (!seedanceCapability && videoDurationSeconds && ![
8014
+ if (!seedanceCapability && !wan3Capability && videoDurationSeconds && ![
7774
8015
  4,
7775
8016
  6,
7776
8017
  8
7777
8018
  ].includes(videoDurationSeconds)) throw new Error("--duration must be 4, 6, or 8 for this model");
7778
- const aspectRatio = aspectValue === void 0 ? void 0 : seedanceCapability ? seedanceCapability.aspectRatios.includes(aspectValue) ? aspectValue : void 0 : normalizeVideoGenerationAspectRatio(aspectValue);
7779
- if (aspectValue !== void 0 && !aspectRatio) throw new Error(seedanceCapability ? `--aspect must be one of: ${seedanceCapability.aspectRatios.join(", ")}` : "--aspect must be 16:9 or 9:16");
8019
+ const aspectRatio = aspectValue === void 0 ? void 0 : seedanceCapability ? seedanceCapability.aspectRatios.includes(aspectValue) ? aspectValue : void 0 : wan3Capability ? wan3Capability.aspectRatios.includes(aspectValue) ? aspectValue : void 0 : normalizeVideoGenerationAspectRatio(aspectValue);
8020
+ if (aspectValue !== void 0 && !aspectRatio) throw new Error(seedanceCapability ? `--aspect must be one of: ${seedanceCapability.aspectRatios.join(", ")}` : wan3Capability ? `--aspect must be one of: ${wan3Capability.aspectRatios.join(", ")}` : "--aspect must be 16:9 or 9:16");
7780
8021
  const seedanceBitrateMode = bitrateValue;
7781
8022
  if (bitrateValue !== void 0 && (!seedanceCapability || !seedanceCapability.bitrateModes.includes(seedanceBitrateMode))) throw new Error(seedanceCapability ? `${seedanceCapability.familyLabel} does not accept --bitrate` : "--bitrate standard|high is only supported by Seedance 2");
8023
+ const wan3Seed = seedValue === void 0 ? void 0 : Number(seedValue);
8024
+ if (seedValue !== void 0 && (!wan3Capability || !Number.isSafeInteger(wan3Seed) || wan3Seed < 0 || wan3Seed > 2147483647)) throw new Error(wan3Capability ? "--seed must be an integer from 0 to 2147483647" : "--seed is only supported by WAN 3.0 for video generation");
8025
+ const parseWanBoolean = (value, option) => {
8026
+ if (value === void 0) return void 0;
8027
+ if (!wan3Capability) throw new Error(`${option} is only supported by WAN 3.0`);
8028
+ if (value !== "true" && value !== "false") throw new Error(`${option} must be true or false`);
8029
+ return value === "true";
8030
+ };
8031
+ const wan3PromptExpansion = parseWanBoolean(promptExpansionValue, "--prompt-expansion");
8032
+ const wan3Thinking = parseWanBoolean(thinkingValue, "--thinking");
7782
8033
  return {
7783
8034
  model,
7784
8035
  ...aspectRatio ? { aspectRatio } : {},
@@ -7786,7 +8037,11 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7786
8037
  ...videoDurationSeconds ? { videoDurationSeconds } : {},
7787
8038
  ...videoTier ? { videoTier } : {},
7788
8039
  ...seedanceCapability && seedanceDuration !== void 0 ? { seedanceDuration } : {},
7789
- ...seedanceBitrateMode ? { seedanceBitrateMode } : {}
8040
+ ...seedanceBitrateMode ? { seedanceBitrateMode } : {},
8041
+ ...wan3Capability && wan3Duration !== void 0 ? { wan3Duration } : {},
8042
+ ...wan3Seed !== void 0 ? { wan3Seed } : {},
8043
+ ...wan3PromptExpansion !== void 0 ? { wan3PromptExpansion } : {},
8044
+ ...wan3Thinking !== void 0 ? { wan3Thinking } : {}
7790
8045
  };
7791
8046
  }
7792
8047
  function parseGenerationProviderOption(parsed, mediaKind, videoModel) {
@@ -7810,12 +8065,13 @@ function validateVideoFrameReferenceOptions(command, parsed, mediaKind) {
7810
8065
  if (mediaKind !== "video") throw new Error("--first-frame and --last-frame are only supported for video generation");
7811
8066
  if (lastFrame && !firstFrame) throw new Error("--last-frame requires --first-frame");
7812
8067
  if (parsed.options.refs) throw new Error("--first-frame and --last-frame cannot be combined with --refs");
7813
- if (parsed.options["image-refs"] || parsed.options["video-refs"] || parsed.options["audio-refs"]) throw new Error("Seedance 2 cannot combine authoritative --first-frame/--last-frame inputs with extended --image-refs/--video-refs/--audio-refs; choose frame mode or reference mode");
8068
+ if (parsed.options["image-refs"] || parsed.options["video-refs"] || parsed.options["audio-refs"]) throw new Error("Frame mode cannot combine --first-frame/--last-frame with grouped --image-refs/--video-refs/--audio-refs");
7814
8069
  const tierValue = readOptionalOption(parsed, "tier");
7815
8070
  const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
7816
8071
  const model = parseVideoModelOption(readOptionalOption(parsed, "model"), videoTier, parsed);
8072
+ const wan3Capability = getWan3CapabilityByEndpoint(model);
7817
8073
  if (isFalSeedance2VideoGenerationModel(model) && !firstFrame) throw new Error("Seedance frame mode requires --first-frame");
7818
- if (!isFalSeedance2VideoGenerationModel(model) && (isFalVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) && Boolean(lastFrame))) throw new Error("--first-frame and --last-frame require a frame-capable video model");
8074
+ if (!(isFalSeedance2VideoGenerationModel(model) || wan3Capability?.mode === "frame") && (isFalVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) && Boolean(lastFrame))) throw new Error("--first-frame and --last-frame require a frame-capable video model");
7819
8075
  }
7820
8076
  function readVideoFrameOption(parsed, name) {
7821
8077
  const value = parsed.options[name];
@@ -7882,9 +8138,14 @@ function parseVideoModelOption(value, tier, parsed) {
7882
8138
  const hasReferences = Boolean(parsed?.options.refs || parsed?.options["image-refs"] || parsed?.options["video-refs"] || parsed?.options["audio-refs"]);
7883
8139
  return SEEDANCE_2_CAPABILITIES[`${normalized}-${hasFrames ? "frame" : hasReferences ? "reference" : "text"}`].endpointId;
7884
8140
  }
8141
+ if (normalized === "wan-3") {
8142
+ const hasFrames = Boolean(parsed?.options["first-frame"] || parsed?.options["last-frame"]);
8143
+ const hasReferences = Boolean(parsed?.options["image-refs"] || parsed?.options["video-refs"] || parsed?.options["audio-refs"]);
8144
+ return getWan3CapabilityBySelection(`wan-3-${hasFrames ? "frame" : hasReferences ? "reference" : "text"}`).endpointId;
8145
+ }
7885
8146
  const selection = normalizeVideoModelSelection(normalized === "seedance-1" ? "fal-seedance" : normalized);
7886
8147
  if (selection) return getVideoGenerationModelForSelection(selection, effectiveTier);
7887
- throw new Error("--model must be veo-3.1, omni-flash, kling, seedance-1, seedance-2, seedance-2-fast, seedance-2.5, kling-avatar-v2, or creatify-aurora");
8148
+ throw new Error("--model must be veo-3.1, omni-flash, kling, seedance-1, seedance-2, seedance-2-fast, seedance-2.5, wan-3, kling-avatar-v2, or creatify-aurora");
7888
8149
  }
7889
8150
  function parseImageModelOption(value) {
7890
8151
  if (!value) return void 0;
@@ -8066,6 +8327,8 @@ function parseWaitSeconds$1(value) {
8066
8327
  function buildRegenerationBody(mediaKind, parsed, referenceVariantIds, audioMode, sourceRecipe) {
8067
8328
  const prompt = parsed.positionals[1] ?? parsed.options.prompt;
8068
8329
  const model = parsed.options.model;
8330
+ const storedRecipe = parseStoredRecipe$2(sourceRecipe);
8331
+ const isWan3 = mediaKind === "video" && (model !== void 0 ? model === "wan-3" : Boolean(getWan3CapabilityByEndpoint(storedRecipe?.model)));
8069
8332
  const audioModel = mediaKind === "audio" && (audioMode === "speech" || audioMode === "dialogue") ? normalizeElevenLabsSpeechModelId(model) : void 0;
8070
8333
  const params = {};
8071
8334
  let duration;
@@ -8085,11 +8348,23 @@ function buildRegenerationBody(mediaKind, parsed, referenceVariantIds, audioMode
8085
8348
  } else if (mediaKind === "video") {
8086
8349
  if (parsed.options.aspect) params.aspectRatio = parsed.options.aspect;
8087
8350
  if (parsed.options.resolution) params.videoResolution = parsed.options.resolution;
8088
- if (parsed.options.duration) duration = parseInteger(parsed.options.duration, "--duration");
8351
+ if (parsed.options.duration) if (isWan3) {
8352
+ const wan3Duration = parsed.options.duration === "auto" ? "auto" : parseInteger(parsed.options.duration, "--duration");
8353
+ if (!isWan3Duration(wan3Duration)) throw new Error("--duration must be auto or an integer from 2 to 30 for WAN 3.0");
8354
+ params.wan3Duration = wan3Duration;
8355
+ } else duration = parseInteger(parsed.options.duration, "--duration");
8089
8356
  if (parsed.options.tier) params.videoTier = parsed.options.tier;
8090
8357
  if (parsed.options.bitrate) params.seedanceBitrateMode = parsed.options.bitrate;
8091
8358
  if (parsed.options.audio === "true") params.generateAudio = true;
8092
8359
  if (parsed.options["no-audio"] === "true") params.generateAudio = false;
8360
+ if ((parsed.options.seed !== void 0 || parsed.options["prompt-expansion"] !== void 0 || parsed.options.thinking !== void 0) && !isWan3) throw new Error("--seed, --prompt-expansion, and --thinking require --model wan-3 or a stored WAN 3.0 recipe");
8361
+ if (parsed.options.seed !== void 0) {
8362
+ const seed = parseInteger(parsed.options.seed, "--seed");
8363
+ if (seed < 0 || seed > 2147483647) throw new Error("--seed must be an integer from 0 to 2147483647 for WAN 3.0");
8364
+ params.wan3Seed = seed;
8365
+ }
8366
+ if (parsed.options["prompt-expansion"] !== void 0) params.wan3PromptExpansion = parseBooleanOption(parsed.options["prompt-expansion"], "--prompt-expansion");
8367
+ if (parsed.options.thinking !== void 0) params.wan3Thinking = parseBooleanOption(parsed.options.thinking, "--thinking");
8093
8368
  } else {
8094
8369
  if (!audioMode) throw new Error("Audio regeneration mode is required");
8095
8370
  validateAudioModel(audioMode, audioModel ?? model);
@@ -8112,6 +8387,7 @@ function buildRegenerationBody(mediaKind, parsed, referenceVariantIds, audioMode
8112
8387
  }
8113
8388
  function resolveVideoRegenerationModel(model, parsed, sourceRecipe) {
8114
8389
  const tier = parsed.options.tier ?? "generate";
8390
+ if (model === "wan-3") return getWan3CapabilityBySelection("wan-3-reference").endpointId;
8115
8391
  if (model === "seedance-2" || model === "seedance-2-fast" || model === "seedance-2.5") {
8116
8392
  const referencesWereOverridden = [
8117
8393
  "image-refs",
@@ -8131,7 +8407,7 @@ function resolveVideoRegenerationModel(model, parsed, sourceRecipe) {
8131
8407
  }, referencesWereOverridden).endpointId;
8132
8408
  }
8133
8409
  const selection = normalizeVideoModelSelection(model === "seedance-1" ? "fal-seedance" : model);
8134
- if (!selection) throw new Error("Unsupported video model. Expected veo-3.1, omni-flash, kling, seedance-1, seedance-2, seedance-2-fast, or seedance-2.5");
8410
+ if (!selection) throw new Error("Unsupported video model. Expected veo-3.1, omni-flash, kling, seedance-1, seedance-2, seedance-2-fast, seedance-2.5, or wan-3");
8135
8411
  return getVideoGenerationModelForSelection(selection, tier);
8136
8412
  }
8137
8413
  function parseStoredRecipe$2(recipe) {
@@ -8175,6 +8451,11 @@ function parseInteger(value, option) {
8175
8451
  if (!Number.isInteger(parsed)) throw new Error(`${option} must be an integer`);
8176
8452
  return parsed;
8177
8453
  }
8454
+ function parseBooleanOption(value, option) {
8455
+ if (value === "true") return true;
8456
+ if (value === "false") return false;
8457
+ throw new Error(`${option} must be true or false`);
8458
+ }
8178
8459
  //#endregion
8179
8460
  //#region src/cli/commands/audio.ts
8180
8461
  var defaultDeps$10 = {
@@ -9359,6 +9640,124 @@ function seedanceVideoGenerator(capability) {
9359
9640
  ]
9360
9641
  };
9361
9642
  }
9643
+ function wan3VideoGenerator(capability) {
9644
+ const fixedGenerator = fixedInput("generator_id", capability.generatorId, "Selects this exact WAN 3.0 mode.");
9645
+ const parameters = [
9646
+ input("aspect_ratio", "string", false, "Output aspect ratio; adaptive lets WAN choose.", {
9647
+ allowedValues: capability.aspectRatios,
9648
+ defaultValue: capability.defaultAspectRatio
9649
+ }),
9650
+ input("resolution", "string", false, "Output resolution.", {
9651
+ allowedValues: capability.resolutions,
9652
+ defaultValue: capability.defaultResolution
9653
+ }),
9654
+ input("duration", "string_or_integer", false, "Output duration from 2 to 30 seconds, or auto.", {
9655
+ allowedValues: capability.durations,
9656
+ defaultValue: capability.defaultDuration
9657
+ }),
9658
+ input("generate_audio", "boolean", false, "Generate synchronized native audio.", {
9659
+ allowedValues: [true, false],
9660
+ defaultValue: true
9661
+ }),
9662
+ input("seed", "integer", false, "Optional deterministic provider seed.", {
9663
+ minimum: 0,
9664
+ maximum: 2147483647
9665
+ }),
9666
+ input("prompt_expansion", "boolean", false, "Allow WAN to expand the prompt for quality.", {
9667
+ allowedValues: [true, false],
9668
+ defaultValue: true
9669
+ }),
9670
+ input("thinking", "boolean", false, "Enable enhanced composition and motion reasoning.", {
9671
+ allowedValues: [true, false],
9672
+ defaultValue: false
9673
+ })
9674
+ ];
9675
+ const common = [
9676
+ SPACE_INPUT,
9677
+ fixedGenerator,
9678
+ NAME_INPUT,
9679
+ input("asset_type", "string", true, "Asset classification stored in the Space."),
9680
+ PROMPT_INPUT,
9681
+ ...parameters
9682
+ ];
9683
+ const max = (kind) => capability.references.find((rule) => rule.mediaKind === kind)?.maxCount ?? 0;
9684
+ const referenceInputs = [
9685
+ input("image_reference_variant_refs", "string_array", false, `Ordered completed images addressed as Image 1 through Image ${max("image")}.`, {
9686
+ minItems: 1,
9687
+ maxItems: max("image")
9688
+ }),
9689
+ input("video_reference_variant_refs", "string_array", false, `Ordered completed videos addressed as Video 1 through Video ${max("video")}; 15 seconds combined maximum.`, {
9690
+ minItems: 1,
9691
+ maxItems: max("video")
9692
+ }),
9693
+ input("audio_reference_variant_refs", "string_array", false, `Ordered completed audio clips addressed as Audio 1 through Audio ${max("audio")}; 15 seconds combined maximum.`, {
9694
+ minItems: 1,
9695
+ maxItems: max("audio")
9696
+ })
9697
+ ];
9698
+ const modeInputs = capability.mode === "frame" ? [input("start_frame_variant_ref", "string", true, "Required authoritative first frame."), input("end_frame_variant_ref", "string", false, "Optional authoritative final frame.")] : capability.mode === "reference" ? referenceInputs : [];
9699
+ const operations = [{
9700
+ operation: capability.mode === "text" ? "generate" : "derive",
9701
+ tool: "generate_video",
9702
+ description: capability.mode === "text" ? "Create a native-audio video from text." : capability.mode === "frame" ? "Animate a start frame and optional end frame." : "Direct one video from up to 20 ordered image, video, and audio references.",
9703
+ inputs: [...common, ...modeInputs]
9704
+ }];
9705
+ if (capability.mode === "reference") operations.push({
9706
+ operation: "refine",
9707
+ tool: "edit_video",
9708
+ description: "Refine a completed video as Video 1 with up to 19 additional references.",
9709
+ referenceLimits: {
9710
+ maxAdditionalCount: 19,
9711
+ implicitSourceCount: 1,
9712
+ maxAdditionalByKind: {
9713
+ image: 10,
9714
+ video: 4,
9715
+ audio: 5
9716
+ }
9717
+ },
9718
+ inputs: [
9719
+ SPACE_INPUT,
9720
+ fixedGenerator,
9721
+ input("asset_ref", "string", true, "Target video asset reference."),
9722
+ input("source_variant_ref", "string", true, "Completed target video used as Video 1."),
9723
+ PROMPT_INPUT,
9724
+ ...parameters,
9725
+ ...referenceInputs.map((item) => item.name === "video_reference_variant_refs" ? {
9726
+ ...item,
9727
+ maxItems: 4,
9728
+ description: "Up to 4 additional videos; the source video is Video 1."
9729
+ } : item)
9730
+ ]
9731
+ });
9732
+ return {
9733
+ id: capability.generatorId,
9734
+ label: capability.label,
9735
+ mediaKind: "video",
9736
+ modelIds: [capability.endpointId],
9737
+ defaultModelId: capability.endpointId,
9738
+ operations,
9739
+ referenceRules: {
9740
+ mediaKind: capability.mode === "frame" ? "image" : null,
9741
+ completedOnly: capability.mode !== "text",
9742
+ maxCount: capability.maxReferenceFiles,
9743
+ maxTotalCount: capability.maxReferenceFiles,
9744
+ modalities: capability.references.map((rule) => ({
9745
+ mediaKind: rule.mediaKind,
9746
+ minCount: rule.minCount,
9747
+ maxCount: rule.maxCount,
9748
+ promptLabel: rule.promptLabel,
9749
+ acceptedMimeTypes: rule.acceptedMimeTypes,
9750
+ maxBytesPerFile: rule.maxBytesPerFile,
9751
+ ...rule.combinedDurationSeconds ? { combinedDurationSeconds: rule.combinedDurationSeconds } : {}
9752
+ }))
9753
+ },
9754
+ notes: [
9755
+ "WAN 3.0 generates native synchronized audio and supports 480p, 720p, and 1080p.",
9756
+ "Safety checking remains enabled by MakeFX and is not a user-controlled option.",
9757
+ capability.mode === "reference" ? "Reference mode accepts up to 10 images, 5 videos, and 5 audio clips (20 total)." : capability.mode === "frame" ? "Frame mode accepts exactly one start frame and one optional end frame." : "Text mode rejects all media references."
9758
+ ]
9759
+ };
9760
+ }
9362
9761
  function avatarVideoGenerator(model) {
9363
9762
  const capability = getAvatarModelCapabilities(model);
9364
9763
  const parameters = capability.model === "kling-avatar-v2" ? [input("mode", "string", false, "Generation quality.", {
@@ -9479,8 +9878,9 @@ function getGeneratorCatalog(overrides = {}) {
9479
9878
  const lyria = overrides.lyria ?? "lyria-3-clip-preview";
9480
9879
  return [
9481
9880
  ...Object.values(IMAGE_MODEL_CAPABILITIES).map(imageGenerator),
9482
- ...VIDEO_MODEL_SELECTIONS.map(videoGenerator),
9881
+ ...VIDEO_MODEL_SELECTIONS.filter((selection) => !getWan3CapabilityBySelection(selection)).map(videoGenerator),
9483
9882
  ...SEEDANCE_2_SELECTIONS.map((selection) => seedanceVideoGenerator(SEEDANCE_2_CAPABILITIES[selection])),
9883
+ ...WAN_3_CAPABILITIES.map(wan3VideoGenerator),
9484
9884
  ...AVATAR_MODEL_IDS.map(avatarVideoGenerator),
9485
9885
  audioGenerator({
9486
9886
  id: "audio/elevenlabs-speech",
@@ -9562,9 +9962,15 @@ var DRAFT_RECIPE_INPUT_KEYS = {
9562
9962
  video_tier: "videoTier",
9563
9963
  duration: "seedanceDuration",
9564
9964
  bitrate_mode: "seedanceBitrateMode",
9965
+ prompt_expansion: "wan3PromptExpansion",
9966
+ thinking: "wan3Thinking",
9565
9967
  provider: "provider"
9566
9968
  };
9567
9969
  function draftRecipeInputKey(inputName, generatorId) {
9970
+ if (generatorId.startsWith("video/wan-3-")) {
9971
+ if (inputName === "duration") return "wan3Duration";
9972
+ if (inputName === "seed") return "wan3Seed";
9973
+ }
9568
9974
  if ((generatorId === "video/p-video-avatar" || generatorId === "video/creatify-aurora") && inputName === "resolution") return "avatarResolution";
9569
9975
  if (generatorId === "video/kling-avatar-v2" && inputName === "mode") return "avatarMode";
9570
9976
  if (generatorId === "video/creatify-aurora" && inputName === "guidance_scale") return "avatarGuidanceScale";
@@ -11451,7 +11857,7 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
11451
11857
  headers: { "Authorization": `Bearer ${accessToken}` },
11452
11858
  body: formData
11453
11859
  });
11454
- const data = await response.json();
11860
+ const data = await readJsonResponse(response, "Upload request");
11455
11861
  if (!response.ok) throw new Error(`Upload failed: ${"error" in data ? data.error : response.statusText}`);
11456
11862
  const upload = data;
11457
11863
  const result = {
@@ -11998,17 +12404,21 @@ var HELP = {
11998
12404
  makefx image generate "prompt" --name <name> --type <type> -o <file> [--model pro|flash|flux|gpt-image-2|seedream-5-pro|seedream-5-lite] [--provider <provider>] [--refs <variant-ref-or-file,...>] [--aspect <ratio>] [--size 1K|2K|3K|4K] [--quality low|medium|high] [--seed <integer>] [--collection <id>] [--space <id>]
11999
12405
  makefx image regenerate <variant-ref> ["prompt"] [--model pro|flash|flux|gpt-image-2|seedream-5-pro|seedream-5-lite] [--provider <provider>] [--aspect <ratio>] [--size <size>] [--quality low|medium|high] [--seed <integer|random>] [--refs <refs>] [--no-activate] [--wait]`,
12000
12406
  video: `Usage:
12001
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--model veo-3.1|omni-flash|kling|seedance-1|seedance-2|seedance-2-fast|seedance-2.5|kling-avatar-v2|creatify-aurora] [--provider fal|elevenlabs|pika]
12407
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--model veo-3.1|omni-flash|kling|seedance-1|seedance-2|seedance-2-fast|seedance-2.5|wan-3|kling-avatar-v2|creatify-aurora] [--provider fal|elevenlabs|pika]
12002
12408
  [--refs <variant-ref-or-file,...>] [--first-frame <ref>] [--last-frame <ref>] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>]
12003
12409
  [--aspect <ratio>] [--resolution 480p|720p|1080p|4k] [--duration <seconds|auto>] [--tier generate|fast|lite] [--bitrate standard|high]
12004
12410
  [--audio | --no-audio] [--collection <id>] [--space <id>]
12411
+ makefx video generate "prompt" --model wan-3 --name <name> --type <type> -o <file>
12412
+ [--first-frame <ref> [--last-frame <ref>] | --image-refs <refs> --video-refs <refs> --audio-refs <refs>]
12413
+ [--aspect adaptive|16:9|4:3|1:1|3:4|9:16] [--resolution 480p|720p|1080p] [--duration 2..30|auto]
12414
+ [--audio | --no-audio] [--seed 0..2147483647] [--prompt-expansion true|false] [--thinking true|false]
12005
12415
  makefx video generate ["prompt"] --model kling-avatar-v2 --image-refs <portrait-ref> --audio-refs <audio-ref>
12006
12416
  --name <name> --type <type> -o <file> [--mode standard|pro] [--collection <id>] [--space <id>]
12007
12417
  makefx video generate ["prompt"] --model creatify-aurora --image-refs <portrait-ref> --audio-refs <audio-ref>
12008
12418
  --name <name> --type <type> -o <file> [--resolution 480p|720p] [--guidance-scale 0..5] [--audio-guidance-scale 0..5] [--collection <id>] [--space <id>]
12009
- makefx video regenerate <variant-ref> ["prompt"] [--model <model>] [--provider fal|elevenlabs|pika] [--aspect <ratio>] [--resolution <value>] [--duration <seconds>] [--tier <tier>] [--bitrate standard|high] [--audio | --no-audio] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>] [--no-activate] [--wait]
12419
+ makefx video regenerate <variant-ref> ["prompt"] [--model <model>] [--provider fal|elevenlabs|pika] [--aspect <ratio>] [--resolution <value>] [--duration <seconds|auto>] [--tier <tier>] [--bitrate standard|high] [--audio | --no-audio] [--seed 0..2147483647] [--prompt-expansion true|false] [--thinking true|false] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>] [--no-activate] [--wait]
12010
12420
 
12011
- Seedance mode is inferred: first/last frame selects frame mode, image/video/audio refs select reference mode, and no references selects text mode.`,
12421
+ Seedance and WAN mode are inferred: first/last frame selects frame mode, image/video/audio refs select reference mode, and no references selects text mode.`,
12012
12422
  audio: `Usage:
12013
12423
  makefx audio voices [--json]
12014
12424
  makefx audio align <variant-ref> "transcript" [--space <id>] [--json]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makefx",
3
- "version": "1.6.7",
3
+ "version": "1.6.9",
4
4
  "description": "Command-line interface for AI-assisted game asset production with Make Effects.",
5
5
  "license": "MIT",
6
6
  "type": "module",