makefx 1.6.6 → 1.6.8

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 +456 -36
  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.6
64
+ Version: 1.6.8
package/makefx.mjs CHANGED
@@ -4442,7 +4442,7 @@ require_websocket_server();
4442
4442
  var wrapper_default = import_websocket.default;
4443
4443
  //#endregion
4444
4444
  //#region src/cli/version.ts
4445
- var CLI_VERSION = "1.6.6+b1c0c6d222d7";
4445
+ var CLI_VERSION = "1.6.8+06570e7d00c2";
4446
4446
  var CLI_VERSION_HEADER = "X-MakeFX-CLI-Version";
4447
4447
  function cliVersionHeaders() {
4448
4448
  return {
@@ -4461,6 +4461,7 @@ function cliVersionHeaders() {
4461
4461
  var GENERATION_REQUEST_TIMEOUT_MS = 3e5;
4462
4462
  var VIDEO_GENERATION_REQUEST_TIMEOUT_MS = 72e4;
4463
4463
  var VARIANT_SYNC_POLL_INTERVAL_MS = 15e3;
4464
+ var GENERATION_RECONNECT_RETRY_MS = 1e3;
4464
4465
  function getGenerationRequestTimeoutMs(mediaKind) {
4465
4466
  return mediaKind === "video" ? VIDEO_GENERATION_REQUEST_TIMEOUT_MS : GENERATION_REQUEST_TIMEOUT_MS;
4466
4467
  }
@@ -4493,6 +4494,8 @@ var WebSocketClient = class WebSocketClient {
4493
4494
  env;
4494
4495
  spaceId;
4495
4496
  connectionLoggingEnabled = false;
4497
+ disconnectRequested = false;
4498
+ generationReconnect = null;
4496
4499
  chatHandlers = /* @__PURE__ */ new Map();
4497
4500
  generateHandlers = /* @__PURE__ */ new Map();
4498
4501
  earlyTerminalVariants = /* @__PURE__ */ new Map();
@@ -4535,6 +4538,7 @@ var WebSocketClient = class WebSocketClient {
4535
4538
  * Connect to the WebSocket endpoint
4536
4539
  */
4537
4540
  async connect() {
4541
+ this.disconnectRequested = false;
4538
4542
  return new Promise((resolve, reject) => {
4539
4543
  const protocol = this.baseUrl.startsWith("https") ? "wss" : "ws";
4540
4544
  const url = `${protocol}://${this.baseUrl.replace(/^https?:\/\//, "")}/api/spaces/${this.spaceId}/ws`;
@@ -4563,7 +4567,7 @@ var WebSocketClient = class WebSocketClient {
4563
4567
  });
4564
4568
  this.ws.on("close", (code, reason) => {
4565
4569
  if (this.connectionLoggingEnabled) console.log(`[WebSocketClient] Disconnected: ${code} - ${reason}`);
4566
- this.ws = null;
4570
+ this.handleSocketClose();
4567
4571
  });
4568
4572
  });
4569
4573
  }
@@ -4571,11 +4575,35 @@ var WebSocketClient = class WebSocketClient {
4571
4575
  * Disconnect from the WebSocket
4572
4576
  */
4573
4577
  disconnect() {
4578
+ this.disconnectRequested = true;
4574
4579
  if (this.ws) {
4575
4580
  this.ws.close();
4576
4581
  this.ws = null;
4577
4582
  }
4578
4583
  }
4584
+ handleSocketClose() {
4585
+ this.ws = null;
4586
+ if (!this.disconnectRequested && this.hasPendingGenerationWaits()) this.reconnectPendingGeneration();
4587
+ }
4588
+ hasPendingGenerationWaits() {
4589
+ return this.generateHandlers.size > 0 || this.variantCompletionHandlers.size > 0;
4590
+ }
4591
+ reconnectPendingGeneration() {
4592
+ if (this.generationReconnect || this.disconnectRequested || !this.hasPendingGenerationWaits()) return;
4593
+ this.generationReconnect = this.runGenerationReconnect().finally(() => {
4594
+ this.generationReconnect = null;
4595
+ });
4596
+ }
4597
+ async runGenerationReconnect() {
4598
+ while (!this.disconnectRequested && this.hasPendingGenerationWaits()) try {
4599
+ await this.connect();
4600
+ if (this.hasPendingGenerationWaits()) this.requestSync();
4601
+ return;
4602
+ } catch {
4603
+ if (this.disconnectRequested || !this.hasPendingGenerationWaits()) return;
4604
+ await new Promise((resolve) => setTimeout(resolve, GENERATION_RECONNECT_RETRY_MS));
4605
+ }
4606
+ }
4579
4607
  /**
4580
4608
  * Set error handler
4581
4609
  */
@@ -5172,6 +5200,10 @@ var WebSocketClient = class WebSocketClient {
5172
5200
  videoTier: params.videoTier,
5173
5201
  seedanceDuration: params.seedanceDuration,
5174
5202
  seedanceBitrateMode: params.seedanceBitrateMode,
5203
+ wan3Duration: params.wan3Duration,
5204
+ wan3Seed: params.wan3Seed,
5205
+ wan3PromptExpansion: params.wan3PromptExpansion,
5206
+ wan3Thinking: params.wan3Thinking,
5175
5207
  provider: params.provider,
5176
5208
  avatarResolution: params.avatarResolution,
5177
5209
  avatarMode: params.avatarMode,
@@ -6050,7 +6082,7 @@ var SEEDANCE_25_DURATIONS = [
6050
6082
  30
6051
6083
  ];
6052
6084
  var SEEDANCE_2_BITRATE_MODES = ["standard", "high"];
6053
- var MB = 1024 * 1024;
6085
+ var MB$1 = 1024 * 1024;
6054
6086
  var IMAGE_REFERENCE_RULE = {
6055
6087
  mediaKind: "image",
6056
6088
  minCount: 0,
@@ -6061,7 +6093,7 @@ var IMAGE_REFERENCE_RULE = {
6061
6093
  "image/png",
6062
6094
  "image/webp"
6063
6095
  ],
6064
- maxBytesPerFile: 30 * MB
6096
+ maxBytesPerFile: 30 * MB$1
6065
6097
  };
6066
6098
  var VIDEO_REFERENCE_RULE = {
6067
6099
  mediaKind: "video",
@@ -6069,8 +6101,8 @@ var VIDEO_REFERENCE_RULE = {
6069
6101
  maxCount: 3,
6070
6102
  promptLabel: "@VideoN",
6071
6103
  acceptedMimeTypes: ["video/mp4", "video/quicktime"],
6072
- maxBytesPerFile: 50 * MB,
6073
- combinedMaxBytes: 50 * MB,
6104
+ maxBytesPerFile: 50 * MB$1,
6105
+ combinedMaxBytes: 50 * MB$1,
6074
6106
  combinedDurationSeconds: {
6075
6107
  min: 2,
6076
6108
  max: 15
@@ -6090,7 +6122,7 @@ var AUDIO_REFERENCE_RULE = {
6090
6122
  "audio/wav",
6091
6123
  "audio/x-wav"
6092
6124
  ],
6093
- maxBytesPerFile: 15 * MB,
6125
+ maxBytesPerFile: 15 * MB$1,
6094
6126
  combinedDurationSeconds: { max: 15 }
6095
6127
  };
6096
6128
  function profile(mode, tier, endpointId) {
@@ -6159,7 +6191,7 @@ var SEEDANCE_25_IMAGE_REFERENCE_RULE = {
6159
6191
  "image/webp",
6160
6192
  "image/gif"
6161
6193
  ],
6162
- maxBytesPerFile: 30 * MB
6194
+ maxBytesPerFile: 30 * MB$1
6163
6195
  };
6164
6196
  var SEEDANCE_25_FRAME_IMAGE_REFERENCE_RULE = {
6165
6197
  ...SEEDANCE_25_IMAGE_REFERENCE_RULE,
@@ -6177,7 +6209,7 @@ var SEEDANCE_25_VIDEO_REFERENCE_RULE = {
6177
6209
  maxCount: 10,
6178
6210
  promptLabel: "@VideoN",
6179
6211
  acceptedMimeTypes: ["video/mp4", "video/quicktime"],
6180
- maxBytesPerFile: 50 * MB,
6212
+ maxBytesPerFile: 50 * MB$1,
6181
6213
  combinedDurationSeconds: { max: 30.2 },
6182
6214
  perFileDurationSeconds: {
6183
6215
  min: 1.8,
@@ -6202,7 +6234,7 @@ var SEEDANCE_25_AUDIO_REFERENCE_RULE = {
6202
6234
  "audio/wav",
6203
6235
  "audio/x-wav"
6204
6236
  ],
6205
- maxBytesPerFile: 15 * MB,
6237
+ maxBytesPerFile: 15 * MB$1,
6206
6238
  combinedDurationSeconds: { max: 30.2 },
6207
6239
  perFileDurationSeconds: {
6208
6240
  min: 1.8,
@@ -6343,6 +6375,158 @@ function getSeedance2CapabilityByEndpoint(endpointId) {
6343
6375
  return SEEDANCE_2_SELECTIONS.map((selection) => SEEDANCE_2_CAPABILITIES[selection]).find((capability) => capability.endpointId === endpointId);
6344
6376
  }
6345
6377
  //#endregion
6378
+ //#region src/shared/wan3Capabilities.ts
6379
+ var WAN_3_ASPECT_RATIOS = [
6380
+ "adaptive",
6381
+ "16:9",
6382
+ "4:3",
6383
+ "1:1",
6384
+ "3:4",
6385
+ "9:16"
6386
+ ];
6387
+ var WAN_3_RESOLUTIONS = [
6388
+ "480p",
6389
+ "720p",
6390
+ "1080p"
6391
+ ];
6392
+ var WAN_3_DURATIONS = [
6393
+ "auto",
6394
+ 2,
6395
+ 3,
6396
+ 4,
6397
+ 5,
6398
+ 6,
6399
+ 7,
6400
+ 8,
6401
+ 9,
6402
+ 10,
6403
+ 11,
6404
+ 12,
6405
+ 13,
6406
+ 14,
6407
+ 15,
6408
+ 16,
6409
+ 17,
6410
+ 18,
6411
+ 19,
6412
+ 20,
6413
+ 21,
6414
+ 22,
6415
+ 23,
6416
+ 24,
6417
+ 25,
6418
+ 26,
6419
+ 27,
6420
+ 28,
6421
+ 29,
6422
+ 30
6423
+ ];
6424
+ var MB = 1024 * 1024;
6425
+ var IMAGE_RULE = {
6426
+ mediaKind: "image",
6427
+ minCount: 0,
6428
+ maxCount: 10,
6429
+ promptLabel: "@ImageN",
6430
+ acceptedMimeTypes: [
6431
+ "image/jpeg",
6432
+ "image/png",
6433
+ "image/webp"
6434
+ ],
6435
+ maxBytesPerFile: 30 * MB
6436
+ };
6437
+ var FRAME_RULE = {
6438
+ ...IMAGE_RULE,
6439
+ minCount: 1,
6440
+ maxCount: 2
6441
+ };
6442
+ var VIDEO_RULE = {
6443
+ mediaKind: "video",
6444
+ minCount: 0,
6445
+ maxCount: 5,
6446
+ promptLabel: "@VideoN",
6447
+ acceptedMimeTypes: ["video/mp4", "video/quicktime"],
6448
+ maxBytesPerFile: 50 * MB,
6449
+ combinedDurationSeconds: { max: 15 }
6450
+ };
6451
+ var AUDIO_RULE = {
6452
+ mediaKind: "audio",
6453
+ minCount: 0,
6454
+ maxCount: 5,
6455
+ promptLabel: "@AudioN",
6456
+ acceptedMimeTypes: [
6457
+ "audio/mpeg",
6458
+ "audio/wav",
6459
+ "audio/x-wav"
6460
+ ],
6461
+ maxBytesPerFile: 15 * MB,
6462
+ combinedDurationSeconds: { max: 15 }
6463
+ };
6464
+ function capability(mode, endpointId) {
6465
+ const selection = `wan-3-${mode}`;
6466
+ const references = mode === "frame" ? [FRAME_RULE] : mode === "reference" ? [
6467
+ IMAGE_RULE,
6468
+ VIDEO_RULE,
6469
+ AUDIO_RULE
6470
+ ] : [];
6471
+ return {
6472
+ selection,
6473
+ generatorId: `video/${selection}`,
6474
+ endpointId,
6475
+ label: `WAN 3.0 ${mode === "text" ? "Text" : mode === "frame" ? "Frames" : "References"}`,
6476
+ mode,
6477
+ resolutions: WAN_3_RESOLUTIONS,
6478
+ aspectRatios: WAN_3_ASPECT_RATIOS,
6479
+ durations: WAN_3_DURATIONS,
6480
+ defaultResolution: "1080p",
6481
+ defaultAspectRatio: "adaptive",
6482
+ defaultDuration: 5,
6483
+ references,
6484
+ maxReferenceFiles: mode === "frame" ? 2 : mode === "reference" ? 20 : 0
6485
+ };
6486
+ }
6487
+ var WAN_3_CAPABILITIES = [
6488
+ capability("text", "alibaba/wan-3.0/text-to-video"),
6489
+ capability("frame", "alibaba/wan-3.0/image-to-video"),
6490
+ capability("reference", "alibaba/wan-3.0/reference-to-video")
6491
+ ];
6492
+ var WAN_3_SELECTIONS = WAN_3_CAPABILITIES.map((item) => item.selection);
6493
+ WAN_3_CAPABILITIES.map((item) => item.endpointId);
6494
+ function getWan3CapabilityBySelection(value) {
6495
+ return WAN_3_CAPABILITIES.find((item) => item.selection === value);
6496
+ }
6497
+ function getWan3CapabilityByEndpoint(value) {
6498
+ return WAN_3_CAPABILITIES.find((item) => item.endpointId === value);
6499
+ }
6500
+ function isWan3Duration(value) {
6501
+ return WAN_3_DURATIONS.includes(value);
6502
+ }
6503
+ function countWan3References(references) {
6504
+ return references.reduce((counts, reference) => {
6505
+ if (reference.mediaKind in counts) counts[reference.mediaKind] += 1;
6506
+ return counts;
6507
+ }, {
6508
+ image: 0,
6509
+ video: 0,
6510
+ audio: 0
6511
+ });
6512
+ }
6513
+ function getWan3ReferenceError(capability_, references) {
6514
+ const counts = countWan3References(references);
6515
+ const unsupported = references.find((reference) => !capability_.references.some((rule) => rule.mediaKind === reference.mediaKind));
6516
+ if (unsupported) return `${capability_.label} does not accept ${unsupported.mediaKind} references`;
6517
+ if (references.length > capability_.maxReferenceFiles) return `${capability_.label} accepts at most ${capability_.maxReferenceFiles} references`;
6518
+ if (capability_.mode === "reference" && references.length === 0) return "WAN 3.0 reference-to-video requires at least one image, video, or audio reference";
6519
+ for (const rule of capability_.references) {
6520
+ const count = counts[rule.mediaKind];
6521
+ if (count < rule.minCount || count > rule.maxCount) return `${capability_.label} requires ${rule.minCount}-${rule.maxCount} ${rule.mediaKind} references`;
6522
+ if (rule.combinedDurationSeconds) {
6523
+ 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`;
6524
+ }
6525
+ }
6526
+ if (capability_.mode === "text" && references.length > 0) return "WAN 3.0 text-to-video does not accept references";
6527
+ return null;
6528
+ }
6529
+ //#endregion
6346
6530
  //#region src/shared/videoGenerationOptions.ts
6347
6531
  var VIDEO_GENERATION_ASPECT_RATIOS = ["16:9", "9:16"];
6348
6532
  var VIDEO_GENERATION_RESOLUTIONS = [
@@ -6380,13 +6564,17 @@ var VIDEO_MODEL_SELECTIONS = [
6380
6564
  "veo-3.1",
6381
6565
  "omni-flash",
6382
6566
  "kling",
6383
- "fal-seedance"
6567
+ "fal-seedance",
6568
+ ...WAN_3_SELECTIONS
6384
6569
  ];
6385
6570
  var VIDEO_MODEL_LABELS = {
6386
6571
  "veo-3.1": "Veo 3.1",
6387
6572
  "omni-flash": "Omni Flash",
6388
6573
  kling: "Kling 3.0",
6389
- "fal-seedance": "fal.ai Seedance v1 (text-to-video)"
6574
+ "fal-seedance": "fal.ai Seedance v1 (text-to-video)",
6575
+ "wan-3-text": "WAN 3.0 Text",
6576
+ "wan-3-frame": "WAN 3.0 Frames",
6577
+ "wan-3-reference": "WAN 3.0 References"
6390
6578
  };
6391
6579
  var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
6392
6580
  "veo-3.1": [
@@ -6404,7 +6592,10 @@ var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
6404
6592
  "refine",
6405
6593
  "derive"
6406
6594
  ],
6407
- "fal-seedance": ["generate"]
6595
+ "fal-seedance": ["generate"],
6596
+ "wan-3-text": ["generate"],
6597
+ "wan-3-frame": ["derive"],
6598
+ "wan-3-reference": ["derive", "refine"]
6408
6599
  };
6409
6600
  var KLING_VIDEO_MODEL = "kling-v3";
6410
6601
  var FAL_VIDEO_MODEL = "fal-ai/bytedance/seedance/v1/pro/text-to-video";
@@ -6462,6 +6653,8 @@ function getVideoGenerationModelForSelection(selection = DEFAULT_VIDEO_MODEL_SEL
6462
6653
  if (selection === "omni-flash") return GEMINI_OMNI_FLASH_VIDEO_MODEL;
6463
6654
  if (selection === "kling") return KLING_VIDEO_MODEL;
6464
6655
  if (selection === "fal-seedance") return FAL_VIDEO_MODEL;
6656
+ const wan3 = getWan3CapabilityBySelection(selection);
6657
+ if (wan3) return wan3.endpointId;
6465
6658
  return getVideoGenerationModelForTier(tier);
6466
6659
  }
6467
6660
  function resolveVideoGenerationModel(model, tier = DEFAULT_VIDEO_GENERATION_TIER) {
@@ -6477,6 +6670,8 @@ function isVideoGenerationResolutionSupportedForTier(resolution, tier = DEFAULT_
6477
6670
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].includes(resolution);
6478
6671
  }
6479
6672
  function getVideoGenerationResolutionsForModel(model) {
6673
+ const wan3 = getWan3CapabilityByEndpoint(model);
6674
+ if (wan3) return [...wan3.resolutions];
6480
6675
  if (isKlingVideoGenerationModel(model) || isFalSeedanceV1VideoGenerationModel(model)) return KLING_VIDEO_GENERATION_RESOLUTIONS;
6481
6676
  const seedanceCapability = getSeedance2CapabilityByEndpoint(model);
6482
6677
  if (seedanceCapability) return [...seedanceCapability.resolutions];
@@ -6493,6 +6688,8 @@ function getVideoModelSelectionForModel(model) {
6493
6688
  if (model === "gemini-omni-flash-preview") return "omni-flash";
6494
6689
  if (model === "kling-v3") return "kling";
6495
6690
  if (model === "fal-ai/bytedance/seedance/v1/pro/text-to-video") return "fal-seedance";
6691
+ const wan3 = getWan3CapabilityByEndpoint(model);
6692
+ if (wan3) return wan3.selection;
6496
6693
  return getVideoGenerationTierForModel(model) ? "veo-3.1" : void 0;
6497
6694
  }
6498
6695
  function isVeoVideoGenerationModel(model) {
@@ -6505,7 +6702,7 @@ function isKlingVideoGenerationModel(model) {
6505
6702
  return model === KLING_VIDEO_MODEL;
6506
6703
  }
6507
6704
  function isFalVideoGenerationModel(model) {
6508
- return isFalSeedanceV1VideoGenerationModel(model) || isFalSeedance2VideoGenerationModel(model);
6705
+ return isFalSeedanceV1VideoGenerationModel(model) || isFalSeedance2VideoGenerationModel(model) || isFalWan3VideoGenerationModel(model);
6509
6706
  }
6510
6707
  function isFalSeedanceV1VideoGenerationModel(model) {
6511
6708
  return model === FAL_VIDEO_MODEL;
@@ -6513,10 +6710,15 @@ function isFalSeedanceV1VideoGenerationModel(model) {
6513
6710
  function isFalSeedance2VideoGenerationModel(model) {
6514
6711
  return typeof model === "string" && getSeedance2CapabilityByEndpoint(model) !== void 0;
6515
6712
  }
6713
+ function isFalWan3VideoGenerationModel(model) {
6714
+ return getWan3CapabilityByEndpoint(model) !== void 0;
6715
+ }
6516
6716
  function isVideoGenerationModel(model) {
6517
6717
  return isVeoVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model);
6518
6718
  }
6519
6719
  function getVideoGenerationMaxReferenceImages(model) {
6720
+ const wan3 = getWan3CapabilityByEndpoint(model);
6721
+ if (wan3) return wan3.references.find((reference) => reference.mediaKind === "image")?.maxCount ?? 0;
6520
6722
  if (isFalSeedanceV1VideoGenerationModel(model)) return 0;
6521
6723
  if (isFalSeedance2VideoGenerationModel(model)) return getSeedance2CapabilityByEndpoint(model)?.references.find((reference) => reference.mediaKind === "image")?.maxCount ?? 0;
6522
6724
  if (isKlingVideoGenerationModel(model)) return 1;
@@ -6529,7 +6731,7 @@ function isVideoOperationSupportedByModel(model, operation) {
6529
6731
  return selection !== void 0 && VIDEO_MODEL_SUPPORTED_OPERATIONS[selection].includes(operation);
6530
6732
  }
6531
6733
  function doesVideoGenerationModelSupportAudioToggle(model) {
6532
- return isKlingVideoGenerationModel(model) || isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6734
+ return isFalWan3VideoGenerationModel(model) || isKlingVideoGenerationModel(model) || isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6533
6735
  }
6534
6736
  //#endregion
6535
6737
  //#region src/shared/generationRouting.ts
@@ -7047,6 +7249,9 @@ var CLI_GENERATION_MEDIA_OPTIONS = {
7047
7249
  "mode",
7048
7250
  "guidance-scale",
7049
7251
  "audio-guidance-scale",
7252
+ "seed",
7253
+ "prompt-expansion",
7254
+ "thinking",
7050
7255
  "provider"
7051
7256
  ]
7052
7257
  };
@@ -7103,23 +7308,28 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
7103
7308
  const musicProvider = parseMusicProviderOption(parsed, mediaKind, assetType);
7104
7309
  const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
7105
7310
  const seedanceCapability = mediaKind === "video" ? getSeedance2CapabilityByEndpoint(effectiveVideoModel) : void 0;
7311
+ const wan3Capability = mediaKind === "video" ? getWan3CapabilityByEndpoint(effectiveVideoModel) : void 0;
7106
7312
  const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
7107
7313
  const seedanceRefs = parseSeedanceReferenceOptions(parsed);
7314
+ const seedanceReferenceCount = seedanceRefs.imageRefs.length + seedanceRefs.videoRefs.length + seedanceRefs.audioRefs.length;
7108
7315
  const plainRefs = parseOptionalRefs(parsed, "refs");
7109
7316
  validateSeedanceReferenceOptions(seedanceRefs, effectiveVideoModel, "generate");
7110
7317
  if (seedanceCapability?.mode === "frame" && videoFrameRefs.length === 0) throw new Error(`--model ${seedanceCapability.selection} requires --first-frame`);
7111
7318
  if (seedanceCapability?.mode === "text" && videoFrameRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} does not accept references`);
7112
7319
  if (seedanceCapability?.mode === "reference" && videoFrameRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} uses --image-refs, --video-refs, and --audio-refs`);
7113
7320
  if (seedanceCapability && plainRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} uses --image-refs, --video-refs, and --audio-refs instead of --refs`);
7321
+ if (wan3Capability?.mode === "frame" && videoFrameRefs.length === 0) throw new Error(`--model ${wan3Capability.selection} requires --first-frame`);
7322
+ if (wan3Capability?.mode === "text" && (videoFrameRefs.length > 0 || seedanceReferenceCount > 0)) throw new Error(`--model ${wan3Capability.selection} does not accept references`);
7323
+ if (wan3Capability?.mode === "reference" && videoFrameRefs.length > 0) throw new Error(`--model ${wan3Capability.selection} uses --image-refs, --video-refs, and --audio-refs`);
7324
+ if (wan3Capability && plainRefs.length > 0) throw new Error(`--model ${wan3Capability.selection} uses typed frame or grouped reference options instead of --refs`);
7114
7325
  if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length + plainRefs.length > 1) throw new Error("--model kling supports at most one image reference");
7115
- 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`);
7116
- const seedanceReferenceCount = seedanceRefs.imageRefs.length + seedanceRefs.videoRefs.length + seedanceRefs.audioRefs.length;
7326
+ 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`);
7117
7327
  const state = videoFrameRefs.length > 0 || seedanceReferenceCount > 0 || plainRefs.length > 0 ? await requestSpaceState(client) : void 0;
7118
7328
  const referenceDeps = {
7119
7329
  ...deps,
7120
7330
  waitForReferenceVariant: (variant) => waitForReferenceVariant(client, variant)
7121
7331
  };
7122
- const resolvedSeedanceRefs = state && seedanceReferenceCount > 0 ? isAvatarModelId(effectiveVideoModel) ? await resolveAvatarReferenceIds(seedanceRefs, ctx, referenceDeps, state) : await resolveSeedanceReferenceIds(seedanceRefs, seedanceCapability, ctx, referenceDeps, state) : {
7332
+ 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) : {
7123
7333
  refs: [],
7124
7334
  ids: []
7125
7335
  };
@@ -7298,11 +7508,26 @@ function validateSeedanceReferenceOptions(options, model, command) {
7298
7508
  return;
7299
7509
  }
7300
7510
  const capability = getSeedance2CapabilityByEndpoint(model);
7511
+ const wan3Capability = getWan3CapabilityByEndpoint(model);
7301
7512
  const total = options.imageRefs.length + options.videoRefs.length + options.audioRefs.length;
7302
- if (!capability) {
7303
- if (total > 0) throw new Error("--image-refs, --video-refs, and --audio-refs require a Seedance 2 reference model");
7513
+ if (!capability && !wan3Capability) {
7514
+ if (total > 0) throw new Error("--image-refs, --video-refs, and --audio-refs require a Seedance 2 or WAN 3.0 reference model");
7304
7515
  return;
7305
7516
  }
7517
+ if (wan3Capability) {
7518
+ if (wan3Capability.mode !== "reference") {
7519
+ if (total > 0) throw new Error(`--model ${wan3Capability.selection} does not accept grouped references`);
7520
+ return;
7521
+ }
7522
+ const error = getWan3ReferenceError(wan3Capability, [
7523
+ ...options.imageRefs.map(() => ({ mediaKind: "image" })),
7524
+ ...options.videoRefs.map(() => ({ mediaKind: "video" })),
7525
+ ...options.audioRefs.map(() => ({ mediaKind: "audio" }))
7526
+ ]);
7527
+ if (error) throw new Error(error);
7528
+ return;
7529
+ }
7530
+ if (!capability) return;
7306
7531
  if (capability.mode !== "reference") {
7307
7532
  if (total > 0) throw new Error(`--model ${capability.selection} does not accept grouped references`);
7308
7533
  return;
@@ -7345,6 +7570,26 @@ async function resolveSeedanceReferenceIds(options, capability, ctx, deps, state
7345
7570
  ]
7346
7571
  };
7347
7572
  }
7573
+ async function resolveWan3ReferenceIds(options, ctx, deps, state) {
7574
+ const resolve = (refs, kind) => resolveReferenceVariantIds(refs, ctx, deps, state.variants, "video", state.assets, kind);
7575
+ const [imageIds, videoIds, audioIds] = await Promise.all([
7576
+ resolve(options.imageRefs, "image"),
7577
+ resolve(options.videoRefs, "video"),
7578
+ resolve(options.audioRefs, "audio")
7579
+ ]);
7580
+ return {
7581
+ refs: [
7582
+ ...options.imageRefs,
7583
+ ...options.videoRefs,
7584
+ ...options.audioRefs
7585
+ ],
7586
+ ids: [
7587
+ ...imageIds,
7588
+ ...videoIds,
7589
+ ...audioIds
7590
+ ]
7591
+ };
7592
+ }
7348
7593
  async function preflightLocalSeedanceReferences(options, deps, state, capability = SEEDANCE_2_CAPABILITIES["seedance-2-reference"]) {
7349
7594
  if (!deps.inspectLocalReference) return;
7350
7595
  const inspections = {
@@ -7690,9 +7935,12 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7690
7935
  const modeValue = readOptionalOption(parsed, "mode");
7691
7936
  const guidanceScaleValue = readOptionalOption(parsed, "guidance-scale");
7692
7937
  const audioGuidanceScaleValue = readOptionalOption(parsed, "audio-guidance-scale");
7938
+ const seedValue = mediaKind === "video" ? readOptionalOption(parsed, "seed") : void 0;
7939
+ const promptExpansionValue = mediaKind === "video" ? parsed.options["prompt-expansion"] : void 0;
7940
+ const thinkingValue = mediaKind === "video" ? parsed.options.thinking : void 0;
7693
7941
  const modelValue = mediaKind === "video" ? readOptionalOption(parsed, "model") : void 0;
7694
7942
  const aspectValue = mediaKind === "video" ? readOptionalOption(parsed, "aspect") : void 0;
7695
- 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 {};
7943
+ 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 {};
7696
7944
  if (mediaKind !== "video") throw new Error("Video model controls are only supported for video generation");
7697
7945
  const videoResolution = resolutionValue === void 0 ? void 0 : normalizeVideoGenerationResolution(resolutionValue);
7698
7946
  if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 480p, 720p, 1080p, or 4k");
@@ -7701,7 +7949,7 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7701
7949
  const model = parseVideoModelOption(modelValue, videoTier, parsed);
7702
7950
  if (isAvatarModelId(model)) {
7703
7951
  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");
7704
- 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");
7952
+ 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");
7705
7953
  if (model === "kling-avatar-v2") {
7706
7954
  if (parsed.options.provider !== void 0) throw new Error("Kling Avatar V2 does not accept --provider");
7707
7955
  if (resolutionValue !== void 0 || guidanceScaleValue !== void 0 || audioGuidanceScaleValue !== void 0) throw new Error("Aurora controls are not supported by --model kling-avatar-v2");
@@ -7731,26 +7979,39 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7731
7979
  if (modeValue !== void 0) throw new Error("--mode is only supported by --model kling-avatar-v2");
7732
7980
  if (guidanceScaleValue !== void 0 || audioGuidanceScaleValue !== void 0) throw new Error("--guidance-scale and --audio-guidance-scale require --model creatify-aurora");
7733
7981
  const seedanceCapability = getSeedance2CapabilityByEndpoint(model);
7982
+ const wan3Capability = getWan3CapabilityByEndpoint(model);
7734
7983
  const seedanceDuration = durationValue === void 0 ? void 0 : seedanceCapability ? normalizeSeedanceDuration(durationValue, model) : void 0;
7984
+ const wan3Duration = durationValue === void 0 ? void 0 : wan3Capability ? durationValue === "auto" ? "auto" : Number(durationValue) : void 0;
7735
7985
  const videoDurationSeconds = durationValue === void 0 || durationValue === "auto" ? void 0 : normalizeVideoGenerationDurationSeconds(durationValue);
7736
7986
  if (seedanceCapability && durationValue !== void 0 && seedanceDuration === void 0) {
7737
7987
  const numericDurations = seedanceCapability.durations.filter((value) => typeof value === "number");
7738
7988
  throw new Error(`--duration must be auto or an integer from ${numericDurations[0]} to ${numericDurations.at(-1)}`);
7739
7989
  }
7740
- if (!seedanceCapability && durationValue === "auto") throw new Error("--duration auto is only supported by Seedance 2");
7990
+ 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");
7991
+ if (!seedanceCapability && !wan3Capability && durationValue === "auto") throw new Error("--duration auto is only supported by Seedance 2 and WAN 3.0");
7741
7992
  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");
7742
7993
  if ((isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && tierValue !== void 0) throw new Error("--tier is only supported with --model veo-3.1");
7743
7994
  if (videoResolution && videoTier && !isVideoGenerationResolutionSupportedForTier(videoResolution, videoTier)) throw new Error("--resolution 4k is not supported with --tier lite");
7744
7995
  if (videoResolution && (isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && !isVideoGenerationResolutionSupportedForModel(model, videoResolution)) throw new Error(`--model ${getVideoModelSelectionForModel(model) ?? model} does not support --resolution ${videoResolution}`);
7745
- if (!seedanceCapability && videoDurationSeconds && ![
7996
+ if (!seedanceCapability && !wan3Capability && videoDurationSeconds && ![
7746
7997
  4,
7747
7998
  6,
7748
7999
  8
7749
8000
  ].includes(videoDurationSeconds)) throw new Error("--duration must be 4, 6, or 8 for this model");
7750
- const aspectRatio = aspectValue === void 0 ? void 0 : seedanceCapability ? seedanceCapability.aspectRatios.includes(aspectValue) ? aspectValue : void 0 : normalizeVideoGenerationAspectRatio(aspectValue);
7751
- 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");
8001
+ 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);
8002
+ 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");
7752
8003
  const seedanceBitrateMode = bitrateValue;
7753
8004
  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");
8005
+ const wan3Seed = seedValue === void 0 ? void 0 : Number(seedValue);
8006
+ 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");
8007
+ const parseWanBoolean = (value, option) => {
8008
+ if (value === void 0) return void 0;
8009
+ if (!wan3Capability) throw new Error(`${option} is only supported by WAN 3.0`);
8010
+ if (value !== "true" && value !== "false") throw new Error(`${option} must be true or false`);
8011
+ return value === "true";
8012
+ };
8013
+ const wan3PromptExpansion = parseWanBoolean(promptExpansionValue, "--prompt-expansion");
8014
+ const wan3Thinking = parseWanBoolean(thinkingValue, "--thinking");
7754
8015
  return {
7755
8016
  model,
7756
8017
  ...aspectRatio ? { aspectRatio } : {},
@@ -7758,7 +8019,11 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7758
8019
  ...videoDurationSeconds ? { videoDurationSeconds } : {},
7759
8020
  ...videoTier ? { videoTier } : {},
7760
8021
  ...seedanceCapability && seedanceDuration !== void 0 ? { seedanceDuration } : {},
7761
- ...seedanceBitrateMode ? { seedanceBitrateMode } : {}
8022
+ ...seedanceBitrateMode ? { seedanceBitrateMode } : {},
8023
+ ...wan3Capability && wan3Duration !== void 0 ? { wan3Duration } : {},
8024
+ ...wan3Seed !== void 0 ? { wan3Seed } : {},
8025
+ ...wan3PromptExpansion !== void 0 ? { wan3PromptExpansion } : {},
8026
+ ...wan3Thinking !== void 0 ? { wan3Thinking } : {}
7762
8027
  };
7763
8028
  }
7764
8029
  function parseGenerationProviderOption(parsed, mediaKind, videoModel) {
@@ -7782,12 +8047,13 @@ function validateVideoFrameReferenceOptions(command, parsed, mediaKind) {
7782
8047
  if (mediaKind !== "video") throw new Error("--first-frame and --last-frame are only supported for video generation");
7783
8048
  if (lastFrame && !firstFrame) throw new Error("--last-frame requires --first-frame");
7784
8049
  if (parsed.options.refs) throw new Error("--first-frame and --last-frame cannot be combined with --refs");
7785
- 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");
8050
+ 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");
7786
8051
  const tierValue = readOptionalOption(parsed, "tier");
7787
8052
  const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
7788
8053
  const model = parseVideoModelOption(readOptionalOption(parsed, "model"), videoTier, parsed);
8054
+ const wan3Capability = getWan3CapabilityByEndpoint(model);
7789
8055
  if (isFalSeedance2VideoGenerationModel(model) && !firstFrame) throw new Error("Seedance frame mode requires --first-frame");
7790
- 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");
8056
+ 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");
7791
8057
  }
7792
8058
  function readVideoFrameOption(parsed, name) {
7793
8059
  const value = parsed.options[name];
@@ -7854,9 +8120,14 @@ function parseVideoModelOption(value, tier, parsed) {
7854
8120
  const hasReferences = Boolean(parsed?.options.refs || parsed?.options["image-refs"] || parsed?.options["video-refs"] || parsed?.options["audio-refs"]);
7855
8121
  return SEEDANCE_2_CAPABILITIES[`${normalized}-${hasFrames ? "frame" : hasReferences ? "reference" : "text"}`].endpointId;
7856
8122
  }
8123
+ if (normalized === "wan-3") {
8124
+ const hasFrames = Boolean(parsed?.options["first-frame"] || parsed?.options["last-frame"]);
8125
+ const hasReferences = Boolean(parsed?.options["image-refs"] || parsed?.options["video-refs"] || parsed?.options["audio-refs"]);
8126
+ return getWan3CapabilityBySelection(`wan-3-${hasFrames ? "frame" : hasReferences ? "reference" : "text"}`).endpointId;
8127
+ }
7857
8128
  const selection = normalizeVideoModelSelection(normalized === "seedance-1" ? "fal-seedance" : normalized);
7858
8129
  if (selection) return getVideoGenerationModelForSelection(selection, effectiveTier);
7859
- 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");
8130
+ 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");
7860
8131
  }
7861
8132
  function parseImageModelOption(value) {
7862
8133
  if (!value) return void 0;
@@ -8038,6 +8309,8 @@ function parseWaitSeconds$1(value) {
8038
8309
  function buildRegenerationBody(mediaKind, parsed, referenceVariantIds, audioMode, sourceRecipe) {
8039
8310
  const prompt = parsed.positionals[1] ?? parsed.options.prompt;
8040
8311
  const model = parsed.options.model;
8312
+ const storedRecipe = parseStoredRecipe$2(sourceRecipe);
8313
+ const isWan3 = mediaKind === "video" && (model !== void 0 ? model === "wan-3" : Boolean(getWan3CapabilityByEndpoint(storedRecipe?.model)));
8041
8314
  const audioModel = mediaKind === "audio" && (audioMode === "speech" || audioMode === "dialogue") ? normalizeElevenLabsSpeechModelId(model) : void 0;
8042
8315
  const params = {};
8043
8316
  let duration;
@@ -8057,11 +8330,23 @@ function buildRegenerationBody(mediaKind, parsed, referenceVariantIds, audioMode
8057
8330
  } else if (mediaKind === "video") {
8058
8331
  if (parsed.options.aspect) params.aspectRatio = parsed.options.aspect;
8059
8332
  if (parsed.options.resolution) params.videoResolution = parsed.options.resolution;
8060
- if (parsed.options.duration) duration = parseInteger(parsed.options.duration, "--duration");
8333
+ if (parsed.options.duration) if (isWan3) {
8334
+ const wan3Duration = parsed.options.duration === "auto" ? "auto" : parseInteger(parsed.options.duration, "--duration");
8335
+ if (!isWan3Duration(wan3Duration)) throw new Error("--duration must be auto or an integer from 2 to 30 for WAN 3.0");
8336
+ params.wan3Duration = wan3Duration;
8337
+ } else duration = parseInteger(parsed.options.duration, "--duration");
8061
8338
  if (parsed.options.tier) params.videoTier = parsed.options.tier;
8062
8339
  if (parsed.options.bitrate) params.seedanceBitrateMode = parsed.options.bitrate;
8063
8340
  if (parsed.options.audio === "true") params.generateAudio = true;
8064
8341
  if (parsed.options["no-audio"] === "true") params.generateAudio = false;
8342
+ 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");
8343
+ if (parsed.options.seed !== void 0) {
8344
+ const seed = parseInteger(parsed.options.seed, "--seed");
8345
+ if (seed < 0 || seed > 2147483647) throw new Error("--seed must be an integer from 0 to 2147483647 for WAN 3.0");
8346
+ params.wan3Seed = seed;
8347
+ }
8348
+ if (parsed.options["prompt-expansion"] !== void 0) params.wan3PromptExpansion = parseBooleanOption(parsed.options["prompt-expansion"], "--prompt-expansion");
8349
+ if (parsed.options.thinking !== void 0) params.wan3Thinking = parseBooleanOption(parsed.options.thinking, "--thinking");
8065
8350
  } else {
8066
8351
  if (!audioMode) throw new Error("Audio regeneration mode is required");
8067
8352
  validateAudioModel(audioMode, audioModel ?? model);
@@ -8084,6 +8369,7 @@ function buildRegenerationBody(mediaKind, parsed, referenceVariantIds, audioMode
8084
8369
  }
8085
8370
  function resolveVideoRegenerationModel(model, parsed, sourceRecipe) {
8086
8371
  const tier = parsed.options.tier ?? "generate";
8372
+ if (model === "wan-3") return getWan3CapabilityBySelection("wan-3-reference").endpointId;
8087
8373
  if (model === "seedance-2" || model === "seedance-2-fast" || model === "seedance-2.5") {
8088
8374
  const referencesWereOverridden = [
8089
8375
  "image-refs",
@@ -8103,7 +8389,7 @@ function resolveVideoRegenerationModel(model, parsed, sourceRecipe) {
8103
8389
  }, referencesWereOverridden).endpointId;
8104
8390
  }
8105
8391
  const selection = normalizeVideoModelSelection(model === "seedance-1" ? "fal-seedance" : model);
8106
- 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");
8392
+ 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");
8107
8393
  return getVideoGenerationModelForSelection(selection, tier);
8108
8394
  }
8109
8395
  function parseStoredRecipe$2(recipe) {
@@ -8147,6 +8433,11 @@ function parseInteger(value, option) {
8147
8433
  if (!Number.isInteger(parsed)) throw new Error(`${option} must be an integer`);
8148
8434
  return parsed;
8149
8435
  }
8436
+ function parseBooleanOption(value, option) {
8437
+ if (value === "true") return true;
8438
+ if (value === "false") return false;
8439
+ throw new Error(`${option} must be true or false`);
8440
+ }
8150
8441
  //#endregion
8151
8442
  //#region src/cli/commands/audio.ts
8152
8443
  var defaultDeps$10 = {
@@ -9331,6 +9622,124 @@ function seedanceVideoGenerator(capability) {
9331
9622
  ]
9332
9623
  };
9333
9624
  }
9625
+ function wan3VideoGenerator(capability) {
9626
+ const fixedGenerator = fixedInput("generator_id", capability.generatorId, "Selects this exact WAN 3.0 mode.");
9627
+ const parameters = [
9628
+ input("aspect_ratio", "string", false, "Output aspect ratio; adaptive lets WAN choose.", {
9629
+ allowedValues: capability.aspectRatios,
9630
+ defaultValue: capability.defaultAspectRatio
9631
+ }),
9632
+ input("resolution", "string", false, "Output resolution.", {
9633
+ allowedValues: capability.resolutions,
9634
+ defaultValue: capability.defaultResolution
9635
+ }),
9636
+ input("duration", "string_or_integer", false, "Output duration from 2 to 30 seconds, or auto.", {
9637
+ allowedValues: capability.durations,
9638
+ defaultValue: capability.defaultDuration
9639
+ }),
9640
+ input("generate_audio", "boolean", false, "Generate synchronized native audio.", {
9641
+ allowedValues: [true, false],
9642
+ defaultValue: true
9643
+ }),
9644
+ input("seed", "integer", false, "Optional deterministic provider seed.", {
9645
+ minimum: 0,
9646
+ maximum: 2147483647
9647
+ }),
9648
+ input("prompt_expansion", "boolean", false, "Allow WAN to expand the prompt for quality.", {
9649
+ allowedValues: [true, false],
9650
+ defaultValue: true
9651
+ }),
9652
+ input("thinking", "boolean", false, "Enable enhanced composition and motion reasoning.", {
9653
+ allowedValues: [true, false],
9654
+ defaultValue: false
9655
+ })
9656
+ ];
9657
+ const common = [
9658
+ SPACE_INPUT,
9659
+ fixedGenerator,
9660
+ NAME_INPUT,
9661
+ input("asset_type", "string", true, "Asset classification stored in the Space."),
9662
+ PROMPT_INPUT,
9663
+ ...parameters
9664
+ ];
9665
+ const max = (kind) => capability.references.find((rule) => rule.mediaKind === kind)?.maxCount ?? 0;
9666
+ const referenceInputs = [
9667
+ input("image_reference_variant_refs", "string_array", false, `Ordered completed images addressed as Image 1 through Image ${max("image")}.`, {
9668
+ minItems: 1,
9669
+ maxItems: max("image")
9670
+ }),
9671
+ input("video_reference_variant_refs", "string_array", false, `Ordered completed videos addressed as Video 1 through Video ${max("video")}; 15 seconds combined maximum.`, {
9672
+ minItems: 1,
9673
+ maxItems: max("video")
9674
+ }),
9675
+ input("audio_reference_variant_refs", "string_array", false, `Ordered completed audio clips addressed as Audio 1 through Audio ${max("audio")}; 15 seconds combined maximum.`, {
9676
+ minItems: 1,
9677
+ maxItems: max("audio")
9678
+ })
9679
+ ];
9680
+ 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 : [];
9681
+ const operations = [{
9682
+ operation: capability.mode === "text" ? "generate" : "derive",
9683
+ tool: "generate_video",
9684
+ 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.",
9685
+ inputs: [...common, ...modeInputs]
9686
+ }];
9687
+ if (capability.mode === "reference") operations.push({
9688
+ operation: "refine",
9689
+ tool: "edit_video",
9690
+ description: "Refine a completed video as Video 1 with up to 19 additional references.",
9691
+ referenceLimits: {
9692
+ maxAdditionalCount: 19,
9693
+ implicitSourceCount: 1,
9694
+ maxAdditionalByKind: {
9695
+ image: 10,
9696
+ video: 4,
9697
+ audio: 5
9698
+ }
9699
+ },
9700
+ inputs: [
9701
+ SPACE_INPUT,
9702
+ fixedGenerator,
9703
+ input("asset_ref", "string", true, "Target video asset reference."),
9704
+ input("source_variant_ref", "string", true, "Completed target video used as Video 1."),
9705
+ PROMPT_INPUT,
9706
+ ...parameters,
9707
+ ...referenceInputs.map((item) => item.name === "video_reference_variant_refs" ? {
9708
+ ...item,
9709
+ maxItems: 4,
9710
+ description: "Up to 4 additional videos; the source video is Video 1."
9711
+ } : item)
9712
+ ]
9713
+ });
9714
+ return {
9715
+ id: capability.generatorId,
9716
+ label: capability.label,
9717
+ mediaKind: "video",
9718
+ modelIds: [capability.endpointId],
9719
+ defaultModelId: capability.endpointId,
9720
+ operations,
9721
+ referenceRules: {
9722
+ mediaKind: capability.mode === "frame" ? "image" : null,
9723
+ completedOnly: capability.mode !== "text",
9724
+ maxCount: capability.maxReferenceFiles,
9725
+ maxTotalCount: capability.maxReferenceFiles,
9726
+ modalities: capability.references.map((rule) => ({
9727
+ mediaKind: rule.mediaKind,
9728
+ minCount: rule.minCount,
9729
+ maxCount: rule.maxCount,
9730
+ promptLabel: rule.promptLabel,
9731
+ acceptedMimeTypes: rule.acceptedMimeTypes,
9732
+ maxBytesPerFile: rule.maxBytesPerFile,
9733
+ ...rule.combinedDurationSeconds ? { combinedDurationSeconds: rule.combinedDurationSeconds } : {}
9734
+ }))
9735
+ },
9736
+ notes: [
9737
+ "WAN 3.0 generates native synchronized audio and supports 480p, 720p, and 1080p.",
9738
+ "Safety checking remains enabled by MakeFX and is not a user-controlled option.",
9739
+ 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."
9740
+ ]
9741
+ };
9742
+ }
9334
9743
  function avatarVideoGenerator(model) {
9335
9744
  const capability = getAvatarModelCapabilities(model);
9336
9745
  const parameters = capability.model === "kling-avatar-v2" ? [input("mode", "string", false, "Generation quality.", {
@@ -9451,8 +9860,9 @@ function getGeneratorCatalog(overrides = {}) {
9451
9860
  const lyria = overrides.lyria ?? "lyria-3-clip-preview";
9452
9861
  return [
9453
9862
  ...Object.values(IMAGE_MODEL_CAPABILITIES).map(imageGenerator),
9454
- ...VIDEO_MODEL_SELECTIONS.map(videoGenerator),
9863
+ ...VIDEO_MODEL_SELECTIONS.filter((selection) => !getWan3CapabilityBySelection(selection)).map(videoGenerator),
9455
9864
  ...SEEDANCE_2_SELECTIONS.map((selection) => seedanceVideoGenerator(SEEDANCE_2_CAPABILITIES[selection])),
9865
+ ...WAN_3_CAPABILITIES.map(wan3VideoGenerator),
9456
9866
  ...AVATAR_MODEL_IDS.map(avatarVideoGenerator),
9457
9867
  audioGenerator({
9458
9868
  id: "audio/elevenlabs-speech",
@@ -9534,9 +9944,15 @@ var DRAFT_RECIPE_INPUT_KEYS = {
9534
9944
  video_tier: "videoTier",
9535
9945
  duration: "seedanceDuration",
9536
9946
  bitrate_mode: "seedanceBitrateMode",
9947
+ prompt_expansion: "wan3PromptExpansion",
9948
+ thinking: "wan3Thinking",
9537
9949
  provider: "provider"
9538
9950
  };
9539
9951
  function draftRecipeInputKey(inputName, generatorId) {
9952
+ if (generatorId.startsWith("video/wan-3-")) {
9953
+ if (inputName === "duration") return "wan3Duration";
9954
+ if (inputName === "seed") return "wan3Seed";
9955
+ }
9540
9956
  if ((generatorId === "video/p-video-avatar" || generatorId === "video/creatify-aurora") && inputName === "resolution") return "avatarResolution";
9541
9957
  if (generatorId === "video/kling-avatar-v2" && inputName === "mode") return "avatarMode";
9542
9958
  if (generatorId === "video/creatify-aurora" && inputName === "guidance_scale") return "avatarGuidanceScale";
@@ -11970,17 +12386,21 @@ var HELP = {
11970
12386
  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>]
11971
12387
  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]`,
11972
12388
  video: `Usage:
11973
- 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]
12389
+ 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]
11974
12390
  [--refs <variant-ref-or-file,...>] [--first-frame <ref>] [--last-frame <ref>] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>]
11975
12391
  [--aspect <ratio>] [--resolution 480p|720p|1080p|4k] [--duration <seconds|auto>] [--tier generate|fast|lite] [--bitrate standard|high]
11976
12392
  [--audio | --no-audio] [--collection <id>] [--space <id>]
12393
+ makefx video generate "prompt" --model wan-3 --name <name> --type <type> -o <file>
12394
+ [--first-frame <ref> [--last-frame <ref>] | --image-refs <refs> --video-refs <refs> --audio-refs <refs>]
12395
+ [--aspect adaptive|16:9|4:3|1:1|3:4|9:16] [--resolution 480p|720p|1080p] [--duration 2..30|auto]
12396
+ [--audio | --no-audio] [--seed 0..2147483647] [--prompt-expansion true|false] [--thinking true|false]
11977
12397
  makefx video generate ["prompt"] --model kling-avatar-v2 --image-refs <portrait-ref> --audio-refs <audio-ref>
11978
12398
  --name <name> --type <type> -o <file> [--mode standard|pro] [--collection <id>] [--space <id>]
11979
12399
  makefx video generate ["prompt"] --model creatify-aurora --image-refs <portrait-ref> --audio-refs <audio-ref>
11980
12400
  --name <name> --type <type> -o <file> [--resolution 480p|720p] [--guidance-scale 0..5] [--audio-guidance-scale 0..5] [--collection <id>] [--space <id>]
11981
- 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]
12401
+ 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]
11982
12402
 
11983
- Seedance mode is inferred: first/last frame selects frame mode, image/video/audio refs select reference mode, and no references selects text mode.`,
12403
+ 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.`,
11984
12404
  audio: `Usage:
11985
12405
  makefx audio voices [--json]
11986
12406
  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.6",
3
+ "version": "1.6.8",
4
4
  "description": "Command-line interface for AI-assisted game asset production with Make Effects.",
5
5
  "license": "MIT",
6
6
  "type": "module",