makefx 1.0.7 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/makefx.mjs +398 -258
  3. package/package.json +1 -1
package/makefx.mjs CHANGED
@@ -844,7 +844,7 @@ function validateProjectConfig(config, configPath) {
844
844
  * makefx spaces inspect-deleted <space_id> Inspect a soft-deleted space
845
845
  * makefx spaces restore <space_id> Restore a soft-deleted space
846
846
  */
847
- var defaultDeps$10 = {
847
+ var defaultDeps$11 = {
848
848
  loadConfig: loadStoredConfig,
849
849
  resolveBaseUrl,
850
850
  saveProjectConfig,
@@ -859,7 +859,7 @@ async function handleSpaces(parsed) {
859
859
  process$1.exitCode = 1;
860
860
  }
861
861
  }
862
- async function executeSpaces(parsed, deps = defaultDeps$10) {
862
+ async function executeSpaces(parsed, deps = defaultDeps$11) {
863
863
  const env = resolveCommandEnvironment(parsed);
864
864
  const showDetails = parsed.options.details === "true";
865
865
  const spaceId = parsed.options.id;
@@ -5386,7 +5386,7 @@ function isMirrorEntry(value) {
5386
5386
  * makefx upload <file> --space <id> --name <name> Upload as new asset
5387
5387
  * makefx upload <file> --space <id> --name <name> --type <type>
5388
5388
  */
5389
- var defaultDeps$9 = {
5389
+ var defaultDeps$10 = {
5390
5390
  loadConfig: loadStoredConfig,
5391
5391
  loadProjectConfig,
5392
5392
  resolveBaseUrl,
@@ -5415,11 +5415,11 @@ async function handleUpload(parsed) {
5415
5415
  await executeUpload(parsed);
5416
5416
  } catch (error) {
5417
5417
  console.error(error instanceof Error ? `Error: ${error.message}` : "Error: Upload failed");
5418
- if (error instanceof UploadUsageError) printUsage$9();
5418
+ if (error instanceof UploadUsageError) printUsage$10();
5419
5419
  process$1.exitCode = 1;
5420
5420
  }
5421
5421
  }
5422
- async function executeUpload(parsed, deps = defaultDeps$9) {
5422
+ async function executeUpload(parsed, deps = defaultDeps$10) {
5423
5423
  const filePath = parsed.positionals[0];
5424
5424
  if (!filePath) throw new UploadUsageError("File path is required");
5425
5425
  rejectRetiredUploadOrganizationOptions(parsed);
@@ -5599,7 +5599,7 @@ function parseCsvOption(value, optionName) {
5599
5599
  if (value === "true") throw new UploadUsageError(`${optionName} requires a value`);
5600
5600
  return value.split(",").map((entry) => entry.trim()).filter(Boolean);
5601
5601
  }
5602
- function printUsage$9() {
5602
+ function printUsage$10() {
5603
5603
  console.log(`
5604
5604
  Usage:
5605
5605
  makefx upload <file> --asset <id> [--space <id>] Upload media to existing asset
@@ -5916,6 +5916,9 @@ var ServerConfirmationTimeoutError = class extends Error {
5916
5916
  this.name = "ServerConfirmationTimeoutError";
5917
5917
  }
5918
5918
  };
5919
+ function booleanFromSqlite(value) {
5920
+ return value === true || value === 1;
5921
+ }
5919
5922
  function collectionItemMatchesInput(item, input) {
5920
5923
  if (item.subject_type !== input.subjectType) return false;
5921
5924
  if (input.subjectType === "asset" && item.asset_id !== input.assetId) return false;
@@ -5935,7 +5938,6 @@ var WebSocketClient = class WebSocketClient {
5935
5938
  chatHandlers = /* @__PURE__ */ new Map();
5936
5939
  generateHandlers = /* @__PURE__ */ new Map();
5937
5940
  batchHandlers = /* @__PURE__ */ new Map();
5938
- estimateHandlers = /* @__PURE__ */ new Map();
5939
5941
  batchVariantToRequestId = /* @__PURE__ */ new Map();
5940
5942
  variantCompletionHandlers = /* @__PURE__ */ new Map();
5941
5943
  describeHandlers = /* @__PURE__ */ new Map();
@@ -6131,16 +6133,6 @@ var WebSocketClient = class WebSocketClient {
6131
6133
  }
6132
6134
  break;
6133
6135
  }
6134
- case "generation:estimate": {
6135
- const estimateMsg = message;
6136
- const handler = this.estimateHandlers.get(estimateMsg.requestId);
6137
- if (handler) {
6138
- this.estimateHandlers.delete(estimateMsg.requestId);
6139
- clearTimeout(handler.timeout);
6140
- handler.resolve(estimateMsg);
6141
- }
6142
- break;
6143
- }
6144
6136
  case "variant:updated": {
6145
6137
  const variant = message.variant;
6146
6138
  const batchRequestId = this.batchVariantToRequestId.get(variant.id);
@@ -6296,13 +6288,6 @@ var WebSocketClient = class WebSocketClient {
6296
6288
  return true;
6297
6289
  }
6298
6290
  failRequestHandler(requestId, error) {
6299
- const estimateHandler = this.estimateHandlers.get(requestId);
6300
- if (estimateHandler) {
6301
- this.estimateHandlers.delete(requestId);
6302
- clearTimeout(estimateHandler.timeout);
6303
- estimateHandler.reject(error);
6304
- return true;
6305
- }
6306
6291
  const generateHandler = this.generateHandlers.get(requestId);
6307
6292
  if (generateHandler) {
6308
6293
  this.generateHandlers.delete(requestId);
@@ -6395,11 +6380,15 @@ var WebSocketClient = class WebSocketClient {
6395
6380
  }
6396
6381
  /** Star or unstar a variant. Resolves with the updated variant. */
6397
6382
  async starVariant(variantId, starred) {
6398
- return (await this.awaitServerMessage({
6383
+ const result = await this.awaitServerMessage({
6399
6384
  type: "variant:star",
6400
6385
  variantId,
6401
6386
  starred
6402
- }, (msg) => msg.type === "variant:updated" && msg.variant.id === variantId && msg.variant.starred === starred)).variant;
6387
+ }, (msg) => msg.type === "variant:updated" && msg.variant.id === variantId && booleanFromSqlite(msg.variant.starred) === starred);
6388
+ return {
6389
+ ...result.variant,
6390
+ starred: booleanFromSqlite(result.variant.starred)
6391
+ };
6403
6392
  }
6404
6393
  /** Rate a variant (approved/rejected). Resolves with the updated variant. */
6405
6394
  async rateVariant(variantId, rating) {
@@ -6484,46 +6473,6 @@ var WebSocketClient = class WebSocketClient {
6484
6473
  }, 12e4);
6485
6474
  });
6486
6475
  }
6487
- async sendGenerationEstimateRequest(params) {
6488
- const requestId = crypto.randomUUID();
6489
- return new Promise((resolve, reject) => {
6490
- const timeout = setTimeout(() => {
6491
- if (this.estimateHandlers.has(requestId)) {
6492
- this.estimateHandlers.delete(requestId);
6493
- reject(/* @__PURE__ */ new Error("Generation estimate request timed out"));
6494
- }
6495
- }, 3e4);
6496
- this.estimateHandlers.set(requestId, {
6497
- resolve,
6498
- reject,
6499
- timeout
6500
- });
6501
- const message = {
6502
- type: "generation:estimate",
6503
- requestId,
6504
- operation: params.operation,
6505
- assetId: params.assetId,
6506
- assetType: params.assetType,
6507
- mediaKind: params.mediaKind,
6508
- prompt: params.prompt,
6509
- count: params.count,
6510
- model: params.model,
6511
- imageSize: params.imageSize,
6512
- musicProvider: params.musicProvider,
6513
- generateAudio: params.generateAudio,
6514
- videoResolution: params.videoResolution,
6515
- videoDurationSeconds: params.videoDurationSeconds,
6516
- videoTier: params.videoTier
6517
- };
6518
- try {
6519
- this.send(message);
6520
- } catch (err) {
6521
- this.estimateHandlers.delete(requestId);
6522
- clearTimeout(timeout);
6523
- reject(err);
6524
- }
6525
- });
6526
- }
6527
6476
  /**
6528
6477
  * Send a generate request and wait for result
6529
6478
  */
@@ -6831,17 +6780,64 @@ var VIDEO_GENERATION_RESOLUTIONS = [
6831
6780
  "1080p",
6832
6781
  "4k"
6833
6782
  ];
6783
+ var ALL_VIDEO_GENERATION_RESOLUTIONS = ["480p", ...VIDEO_GENERATION_RESOLUTIONS];
6784
+ var KLING_VIDEO_GENERATION_RESOLUTIONS = ["720p", "1080p"];
6834
6785
  var VIDEO_GENERATION_DURATION_SECONDS = [
6835
6786
  4,
6836
6787
  6,
6837
6788
  8
6838
6789
  ];
6790
+ var SEEDANCE_2_DURATION_SECONDS = [
6791
+ 4,
6792
+ 5,
6793
+ 6,
6794
+ 7,
6795
+ 8,
6796
+ 9,
6797
+ 10,
6798
+ 11,
6799
+ 12,
6800
+ 13,
6801
+ 14,
6802
+ 15
6803
+ ];
6839
6804
  var VIDEO_GENERATION_TIERS = [
6840
6805
  "generate",
6841
6806
  "fast",
6842
6807
  "lite"
6843
6808
  ];
6844
- var VIDEO_MODEL_SELECTIONS = ["veo-3.1", "omni-flash"];
6809
+ var VIDEO_MODEL_SELECTIONS = [
6810
+ "veo-3.1",
6811
+ "omni-flash",
6812
+ "kling",
6813
+ "fal-seedance",
6814
+ "seedance-2",
6815
+ "seedance-2-fast"
6816
+ ];
6817
+ var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
6818
+ "veo-3.1": [
6819
+ "generate",
6820
+ "refine",
6821
+ "derive"
6822
+ ],
6823
+ "omni-flash": [
6824
+ "generate",
6825
+ "refine",
6826
+ "derive"
6827
+ ],
6828
+ kling: [
6829
+ "generate",
6830
+ "refine",
6831
+ "derive"
6832
+ ],
6833
+ "fal-seedance": ["generate"],
6834
+ "seedance-2": ["generate", "derive"],
6835
+ "seedance-2-fast": ["generate", "derive"]
6836
+ };
6837
+ var KLING_VIDEO_MODEL = "kling-v3";
6838
+ var FAL_VIDEO_MODEL = "fal-ai/bytedance/seedance/v1/pro/text-to-video";
6839
+ var FAL_SEEDANCE_2_MODEL = "bytedance/seedance-2.0/image-to-video";
6840
+ var FAL_SEEDANCE_2_FAST_MODEL = "bytedance/seedance-2.0/fast/image-to-video";
6845
6841
  var GEMINI_OMNI_FLASH_VIDEO_MODEL = "gemini-omni-flash-preview";
6846
6842
  var VIDEO_GENERATION_AUDIO_TOGGLE_MODELS = [];
6847
6843
  var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
@@ -6860,11 +6856,11 @@ var VIDEO_GENERATION_TIER_MODELS = {
6860
6856
  lite: "veo-3.1-lite-generate-preview"
6861
6857
  };
6862
6858
  function normalizeVideoGenerationResolution(value) {
6863
- return VIDEO_GENERATION_RESOLUTIONS.includes(value) ? value : void 0;
6859
+ return ALL_VIDEO_GENERATION_RESOLUTIONS.includes(value) ? value : void 0;
6864
6860
  }
6865
6861
  function normalizeVideoGenerationDurationSeconds(value) {
6866
6862
  const numeric = typeof value === "string" ? Number(value) : value;
6867
- return VIDEO_GENERATION_DURATION_SECONDS.includes(numeric) ? numeric : void 0;
6863
+ return SEEDANCE_2_DURATION_SECONDS.includes(numeric) ? numeric : void 0;
6868
6864
  }
6869
6865
  function normalizeVideoGenerationTier(value) {
6870
6866
  return VIDEO_GENERATION_TIERS.includes(value) ? value : void 0;
@@ -6876,7 +6872,12 @@ function getVideoGenerationModelForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
6876
6872
  return VIDEO_GENERATION_TIER_MODELS[tier];
6877
6873
  }
6878
6874
  function getVideoGenerationModelForSelection(selection = DEFAULT_VIDEO_MODEL_SELECTION, tier = DEFAULT_VIDEO_GENERATION_TIER) {
6879
- return selection === "omni-flash" ? GEMINI_OMNI_FLASH_VIDEO_MODEL : getVideoGenerationModelForTier(tier);
6875
+ if (selection === "omni-flash") return GEMINI_OMNI_FLASH_VIDEO_MODEL;
6876
+ if (selection === "kling") return KLING_VIDEO_MODEL;
6877
+ if (selection === "fal-seedance") return FAL_VIDEO_MODEL;
6878
+ if (selection === "seedance-2") return FAL_SEEDANCE_2_MODEL;
6879
+ if (selection === "seedance-2-fast") return FAL_SEEDANCE_2_FAST_MODEL;
6880
+ return getVideoGenerationModelForTier(tier);
6880
6881
  }
6881
6882
  function getVideoGenerationResolutionsForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
6882
6883
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier];
@@ -6884,28 +6885,70 @@ function getVideoGenerationResolutionsForTier(tier = DEFAULT_VIDEO_GENERATION_TI
6884
6885
  function isVideoGenerationResolutionSupportedForTier(resolution, tier = DEFAULT_VIDEO_GENERATION_TIER) {
6885
6886
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].includes(resolution);
6886
6887
  }
6888
+ function getVideoGenerationResolutionsForModel(model) {
6889
+ if (isKlingVideoGenerationModel(model) || isFalSeedanceV1VideoGenerationModel(model)) return KLING_VIDEO_GENERATION_RESOLUTIONS;
6890
+ if (model === "bytedance/seedance-2.0/fast/image-to-video") return ["480p", "720p"];
6891
+ if (isFalSeedance2VideoGenerationModel(model)) return [
6892
+ "480p",
6893
+ "720p",
6894
+ "1080p"
6895
+ ];
6896
+ return getVideoGenerationResolutionsForTier(getVideoGenerationTierForModel(model));
6897
+ }
6898
+ function isVideoGenerationResolutionSupportedForModel(model, resolution) {
6899
+ return getVideoGenerationResolutionsForModel(model).includes(resolution);
6900
+ }
6887
6901
  function getVideoGenerationTierForModel(model) {
6888
6902
  if (typeof model !== "string") return void 0;
6889
6903
  return VIDEO_GENERATION_TIERS.find((tier) => VIDEO_GENERATION_TIER_MODELS[tier] === model);
6890
6904
  }
6905
+ function getVideoModelSelectionForModel(model) {
6906
+ if (model === "gemini-omni-flash-preview") return "omni-flash";
6907
+ if (model === "kling-v3") return "kling";
6908
+ if (model === "fal-ai/bytedance/seedance/v1/pro/text-to-video") return "fal-seedance";
6909
+ if (model === "bytedance/seedance-2.0/image-to-video") return "seedance-2";
6910
+ if (model === "bytedance/seedance-2.0/fast/image-to-video") return "seedance-2-fast";
6911
+ return getVideoGenerationTierForModel(model) ? "veo-3.1" : void 0;
6912
+ }
6891
6913
  function isVeoVideoGenerationModel(model) {
6892
6914
  return typeof model === "string" && getVideoGenerationTierForModel(model) !== void 0;
6893
6915
  }
6894
6916
  function isGeminiOmniVideoGenerationModel(model) {
6895
6917
  return model === GEMINI_OMNI_FLASH_VIDEO_MODEL;
6896
6918
  }
6919
+ function isKlingVideoGenerationModel(model) {
6920
+ return model === KLING_VIDEO_MODEL;
6921
+ }
6922
+ function isFalVideoGenerationModel(model) {
6923
+ return isFalSeedanceV1VideoGenerationModel(model) || isFalSeedance2VideoGenerationModel(model);
6924
+ }
6925
+ function isFalSeedanceV1VideoGenerationModel(model) {
6926
+ return model === FAL_VIDEO_MODEL;
6927
+ }
6928
+ function isFalSeedance2VideoGenerationModel(model) {
6929
+ return model === "bytedance/seedance-2.0/image-to-video" || model === "bytedance/seedance-2.0/fast/image-to-video";
6930
+ }
6897
6931
  function isVideoGenerationModel(model) {
6898
- return isVeoVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model);
6932
+ return isVeoVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model);
6933
+ }
6934
+ function isVideoOperationSupportedByModel(model, operation) {
6935
+ const selection = getVideoModelSelectionForModel(model);
6936
+ return selection !== void 0 && VIDEO_MODEL_SUPPORTED_OPERATIONS[selection].includes(operation);
6899
6937
  }
6900
6938
  function doesVideoGenerationModelSupportAudioToggle(model) {
6901
- return isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6939
+ return isKlingVideoGenerationModel(model) || isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6902
6940
  }
6903
6941
  //#endregion
6904
6942
  //#region src/shared/imageGenerationOptions.ts
6905
- var IMAGE_MODEL_SELECTIONS = ["pro", "flash"];
6943
+ var IMAGE_MODEL_SELECTIONS = [
6944
+ "pro",
6945
+ "flash",
6946
+ "flux"
6947
+ ];
6906
6948
  var IMAGE_MODEL_IDS = {
6907
6949
  pro: "gemini-3-pro-image",
6908
- flash: "gemini-3.1-flash-image"
6950
+ flash: "gemini-3.1-flash-image",
6951
+ flux: "fal-ai/flux/dev"
6909
6952
  };
6910
6953
  IMAGE_MODEL_IDS["pro"];
6911
6954
  var IMAGE_ASPECT_RATIOS = [
@@ -6929,6 +6972,13 @@ var IMAGE_MODEL_CAPABILITIES = {
6929
6972
  pro: {
6930
6973
  selection: "pro",
6931
6974
  modelId: IMAGE_MODEL_IDS.pro,
6975
+ label: "Pro",
6976
+ provider: "gemini",
6977
+ supportedOperations: [
6978
+ "generate",
6979
+ "derive",
6980
+ "refine"
6981
+ ],
6932
6982
  maxReferenceImages: 14,
6933
6983
  supportedImageSizes: [
6934
6984
  "1K",
@@ -6940,6 +6990,13 @@ var IMAGE_MODEL_CAPABILITIES = {
6940
6990
  flash: {
6941
6991
  selection: "flash",
6942
6992
  modelId: IMAGE_MODEL_IDS.flash,
6993
+ label: "Flash",
6994
+ provider: "gemini",
6995
+ supportedOperations: [
6996
+ "generate",
6997
+ "derive",
6998
+ "refine"
6999
+ ],
6943
7000
  maxReferenceImages: 14,
6944
7001
  supportedImageSizes: [
6945
7002
  "1K",
@@ -6947,6 +7004,16 @@ var IMAGE_MODEL_CAPABILITIES = {
6947
7004
  "4K"
6948
7005
  ],
6949
7006
  supportedAspectRatios: IMAGE_ASPECT_RATIOS
7007
+ },
7008
+ flux: {
7009
+ selection: "flux",
7010
+ modelId: IMAGE_MODEL_IDS.flux,
7011
+ label: "fal.ai FLUX.1 Dev",
7012
+ provider: "fal",
7013
+ supportedOperations: ["generate"],
7014
+ maxReferenceImages: 0,
7015
+ supportedImageSizes: ["1K"],
7016
+ supportedAspectRatios: IMAGE_ASPECT_RATIOS
6950
7017
  }
6951
7018
  };
6952
7019
  function isImageModelSelection(value) {
@@ -6964,7 +7031,9 @@ function normalizeImageSize(value) {
6964
7031
  }
6965
7032
  function getImageModelSelection(value) {
6966
7033
  if (isImageModelSelection(value)) return value;
6967
- return value === IMAGE_MODEL_IDS.flash ? "flash" : "pro";
7034
+ if (value === IMAGE_MODEL_IDS.flash) return "flash";
7035
+ if (value === IMAGE_MODEL_IDS.flux) return "flux";
7036
+ return "pro";
6968
7037
  }
6969
7038
  function getImageModelCapabilities(model) {
6970
7039
  return IMAGE_MODEL_CAPABILITIES[getImageModelSelection(model ?? "pro")];
@@ -6978,6 +7047,9 @@ function isImageAspectRatioSupportedByModel(model, aspectRatio) {
6978
7047
  function getImageModelMaxReferenceImages(model) {
6979
7048
  return getImageModelCapabilities(model).maxReferenceImages;
6980
7049
  }
7050
+ function isImageOperationSupportedByModel(model, operation) {
7051
+ return getImageModelCapabilities(model).supportedOperations.includes(operation);
7052
+ }
6981
7053
  //#endregion
6982
7054
  //#region src/shared/mediaOperationMatrix.ts
6983
7055
  var MEDIA_OPERATION_MATRIX = [
@@ -7139,7 +7211,7 @@ function cliGenerationSupportsRefs(namespace) {
7139
7211
  //#endregion
7140
7212
  //#region src/cli/commands/forge.ts
7141
7213
  var CLI_GENERATION_MEDIA_KIND = getCliGenerationMediaKind("top-level");
7142
- var defaultDeps$8 = {
7214
+ var defaultDeps$9 = {
7143
7215
  loadConfig: loadStoredConfig,
7144
7216
  loadProjectConfig,
7145
7217
  resolveBaseUrl,
@@ -7162,43 +7234,6 @@ var defaultDeps$8 = {
7162
7234
  }
7163
7235
  }
7164
7236
  };
7165
- var ESTIMATE_METER_LABELS = {
7166
- gemini_images: "Gemini image",
7167
- gemini_videos: "Veo video unit",
7168
- gemini_audio: "Lyria generation",
7169
- elevenlabs_audio: "ElevenLabs unit"
7170
- };
7171
- function formatEstimatedUsd(microUsd) {
7172
- if (!Number.isFinite(microUsd) || microUsd <= 0) return "$0.00";
7173
- if (microUsd < 1e4) return "<$0.01";
7174
- return `$${(microUsd / 1e6).toFixed(2)}`;
7175
- }
7176
- function formatEstimateQuantity(quantity, singular) {
7177
- const normalized = Number.isFinite(quantity) ? quantity : 0;
7178
- const suffix = normalized === 1 ? singular : `${singular}s`;
7179
- return `${normalized.toLocaleString()} ${suffix}`;
7180
- }
7181
- async function printPreflightEstimate(client, params) {
7182
- let result;
7183
- try {
7184
- result = await client.sendGenerationEstimateRequest(params);
7185
- } catch (error) {
7186
- console.warn(`Preflight estimate unavailable: ${error instanceof Error ? error.message : String(error)}`);
7187
- return;
7188
- }
7189
- if (!result.success || !result.estimate) {
7190
- console.warn(`Preflight estimate unavailable: ${result.error || "unknown error"}`);
7191
- return;
7192
- }
7193
- const estimate = result.estimate;
7194
- const meterLabel = ESTIMATE_METER_LABELS[estimate.meterEventName] ?? estimate.meterEventName;
7195
- const quotaLine = estimate.quota?.limit === null || estimate.quota?.limit === void 0 ? void 0 : `${estimate.quota.used.toLocaleString()} used / ${estimate.quota.limit.toLocaleString()} limit`;
7196
- console.log("Preflight estimate:");
7197
- console.log(` Usage: ${formatEstimateQuantity(estimate.quotaQuantity, meterLabel)}, ${formatEstimateQuantity(estimate.platformWorkflowRuns, "workflow")}`);
7198
- console.log(` Estimated provider cost: ${formatEstimatedUsd(estimate.providerCostMicroUsd)}${estimate.billingMode === "byok" ? " (BYOK)" : ""}`);
7199
- if (quotaLine) console.log(` Quota: ${quotaLine}`);
7200
- if (!estimate.allowed) throw new Error(estimate.denyMessage || "Preflight check denied this generation request");
7201
- }
7202
7237
  async function handleGenerate(parsed) {
7203
7238
  await handleForgeCommand("generate", parsed);
7204
7239
  }
@@ -7213,10 +7248,10 @@ async function handleBatch(parsed) {
7213
7248
  }
7214
7249
  async function handleForgeCommand(command, parsed) {
7215
7250
  try {
7216
- await executeForgeCommand(command, parsed, defaultDeps$8);
7251
+ await executeForgeCommand(command, parsed, defaultDeps$9);
7217
7252
  } catch (error) {
7218
7253
  console.error("Error:", error instanceof Error ? error.message : error);
7219
- if (shouldPrintUsageForForgeError(error)) printUsage$8(command);
7254
+ if (shouldPrintUsageForForgeError(error)) printUsage$9(command);
7220
7255
  process$1.exitCode = 1;
7221
7256
  }
7222
7257
  }
@@ -7225,11 +7260,11 @@ function shouldPrintUsageForForgeError(error) {
7225
7260
  const message = error.message;
7226
7261
  return message.startsWith("--") || message.startsWith("Output path is required") || message.startsWith("Output directory is required") || message.startsWith("Pass either prompt text") || message.startsWith("Speech generation requires") || message.startsWith("Dialogue generation requires") || message.startsWith("Prompt is required");
7227
7262
  }
7228
- async function executeForgeCommand(command, parsed, deps = defaultDeps$8, options = {}) {
7263
+ async function executeForgeCommand(command, parsed, deps = defaultDeps$9, options = {}) {
7229
7264
  const mediaKind = options.mediaKind || CLI_GENERATION_MEDIA_KIND;
7230
7265
  if (parsed.options.follow) {
7231
7266
  if (command === "batch") throw new Error("--follow is only supported for single-output generation commands");
7232
- const ctx = await buildContext$5(parsed, deps);
7267
+ const ctx = await buildContext$6(parsed, deps);
7233
7268
  const client = await deps.createClient(ctx.env, ctx.spaceId);
7234
7269
  try {
7235
7270
  await client.connect();
@@ -7239,11 +7274,13 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$8, option
7239
7274
  }
7240
7275
  }
7241
7276
  const saveBatchManifest = options.saveBatchManifest ?? mediaKind === "image";
7242
- validateImageCommandReferenceCount(command, parsed, mediaKind, parseImageGenerationOptions(parsed, mediaKind).model);
7277
+ const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
7278
+ validateImageModelOperation(command, mediaKind, imageOptions.model);
7279
+ validateImageCommandReferenceCount(command, parsed, mediaKind, imageOptions.model);
7243
7280
  validateVideoAudioOptions(parsed, mediaKind);
7244
- parseVideoGenerationOptions(parsed, mediaKind);
7281
+ validateVideoModelOperation(command, mediaKind, parseVideoGenerationOptions(parsed, mediaKind).model);
7245
7282
  validateVideoFrameReferenceOptions(command, parsed, mediaKind);
7246
- const ctx = await buildContext$5(parsed, deps);
7283
+ const ctx = await buildContext$6(parsed, deps);
7247
7284
  const client = await deps.createClient(ctx.env, ctx.spaceId);
7248
7285
  try {
7249
7286
  await client.connect();
@@ -7257,7 +7294,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$8, option
7257
7294
  client.disconnect();
7258
7295
  }
7259
7296
  }
7260
- async function executeAudioCommand(command, parsed, deps = defaultDeps$8, options = {}) {
7297
+ async function executeAudioCommand(command, parsed, deps = defaultDeps$9, options = {}) {
7261
7298
  const audioProfile = getCliGenerationProfile("audio");
7262
7299
  if (!audioProfile.commands.includes(command)) throw new Error(`Audio generation does not support ${command}`);
7263
7300
  const modeEntry = options.mode ? getMediaOperationEntry(options.mode) : void 0;
@@ -7270,7 +7307,7 @@ async function executeAudioCommand(command, parsed, deps = defaultDeps$8, option
7270
7307
  audioMode: options.mode
7271
7308
  });
7272
7309
  }
7273
- async function executeVideoCommand(command, parsed, deps = defaultDeps$8) {
7310
+ async function executeVideoCommand(command, parsed, deps = defaultDeps$9) {
7274
7311
  const videoProfile = getCliGenerationProfile("video");
7275
7312
  if (!videoProfile.commands.includes(command)) throw new Error(`Video generation does not support ${command}`);
7276
7313
  return executeForgeCommand(command, parsed, deps, {
@@ -7315,23 +7352,14 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
7315
7352
  const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
7316
7353
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
7317
7354
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
7355
+ const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
7356
+ if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length > 1) throw new Error("--model kling supports at most one image reference");
7357
+ if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length > 0) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support image references`);
7318
7358
  const collectionPlacement = parseCollectionPlacementOptions(parsed);
7319
7359
  const followCommandOptions = {
7320
7360
  ...followOptions,
7321
7361
  ...collectionPlacement
7322
7362
  };
7323
- await printPreflightEstimate(client, {
7324
- operation: "generate",
7325
- assetType,
7326
- mediaKind,
7327
- prompt,
7328
- count: 1,
7329
- model: imageOptions.model ?? audioModelOptions.model ?? videoOptions.model,
7330
- imageSize: imageOptions.imageSize,
7331
- ...musicProvider ? { musicProvider } : {},
7332
- ...videoAudioOptions,
7333
- ...videoOptions
7334
- });
7335
7363
  console.log(`Generating "${name}" in space ${ctx.spaceId}...`);
7336
7364
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
7337
7365
  let startedVariantId;
@@ -7417,18 +7445,6 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
7417
7445
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
7418
7446
  const collectionPlacement = parseCollectionPlacementOptions(parsed);
7419
7447
  const followCommandOptions = { ...collectionPlacement };
7420
- await printPreflightEstimate(client, {
7421
- operation: "refine",
7422
- assetId: sourceVariant.asset_id,
7423
- assetType: sourceAsset?.type || void 0,
7424
- mediaKind,
7425
- prompt,
7426
- count: 1,
7427
- model: imageOptions.model ?? videoOptions.model,
7428
- imageSize: imageOptions.imageSize,
7429
- ...videoAudioOptions,
7430
- ...videoOptions
7431
- });
7432
7448
  console.log(`Refining variant ${sourceVariantId}...`);
7433
7449
  let startedVariantId;
7434
7450
  let result;
@@ -7491,22 +7507,14 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
7491
7507
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
7492
7508
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
7493
7509
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
7510
+ const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
7511
+ if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && referenceRefs.length > 1) throw new Error("--model kling supports at most one image reference");
7512
+ if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && referenceRefs.length > 0) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support ${referenceRefs.length} image references`);
7494
7513
  const collectionPlacement = parseCollectionPlacementOptions(parsed);
7495
7514
  const followCommandOptions = {
7496
7515
  ...followOptions,
7497
7516
  ...collectionPlacement
7498
7517
  };
7499
- await printPreflightEstimate(client, {
7500
- operation: "derive",
7501
- assetType,
7502
- mediaKind,
7503
- prompt,
7504
- count: 1,
7505
- model: imageOptions.model ?? videoOptions.model,
7506
- imageSize: imageOptions.imageSize,
7507
- ...videoAudioOptions,
7508
- ...videoOptions
7509
- });
7510
7518
  console.log(`Deriving "${name}" from ${referenceVariantIds.length} reference(s)...`);
7511
7519
  let startedVariantId;
7512
7520
  let result;
@@ -7719,16 +7727,6 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
7719
7727
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
7720
7728
  const runId = deps.createRunId();
7721
7729
  const collectionPlacement = parseCollectionPlacementOptions(parsed);
7722
- await printPreflightEstimate(client, {
7723
- operation: "batch",
7724
- assetType,
7725
- mediaKind,
7726
- prompt,
7727
- count,
7728
- model: imageOptions.model ?? audioModelOptions.model,
7729
- imageSize: imageOptions.imageSize,
7730
- ...musicProvider ? { musicProvider } : {}
7731
- });
7732
7730
  console.log(`Batch generating ${count} ${mediaKind === "image" ? "image" : mediaKind === "video" ? "video" : "audio file"}(s) for "${name}"...`);
7733
7731
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
7734
7732
  let startedBatch;
@@ -7905,7 +7903,7 @@ async function createCollectionAssetItem(input) {
7905
7903
  throw new Error(`Failed to place asset ${input.assetId} in collection ${input.collectionId} (${response.status}): ${errorText || response.statusText}`);
7906
7904
  }
7907
7905
  }
7908
- async function buildContext$5(parsed, deps) {
7906
+ async function buildContext$6(parsed, deps) {
7909
7907
  const projectConfig = await deps.loadProjectConfig();
7910
7908
  const env = resolveCommandEnvironment(parsed, projectConfig);
7911
7909
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -8190,7 +8188,7 @@ function validateVideoAudioOptions(parsed, mediaKind) {
8190
8188
  const videoTier = tierValue === void 0 ? DEFAULT_VIDEO_GENERATION_TIER : normalizeVideoGenerationTier(tierValue);
8191
8189
  if (!videoTier) throw new Error("--tier must be generate, fast, or lite");
8192
8190
  const model = parseVideoModelOption(modelValue, videoTier);
8193
- if (parsed.options.audio !== void 0 && isGeminiOmniVideoGenerationModel(model)) throw new Error("--audio is only supported with --model veo-3.1");
8191
+ if (parsed.options.audio !== void 0 && (isGeminiOmniVideoGenerationModel(model) || isFalVideoGenerationModel(model))) throw new Error("--audio is only supported with --model veo-3.1 or kling");
8194
8192
  if (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0) {
8195
8193
  if (!doesVideoGenerationModelSupportAudioToggle(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
8196
8194
  }
@@ -8211,14 +8209,21 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
8211
8209
  if (mediaKind !== "video" && resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0) return {};
8212
8210
  if (mediaKind !== "video") throw new Error("--resolution, --duration, and --tier are only supported for video generation");
8213
8211
  const videoResolution = resolutionValue === void 0 ? void 0 : normalizeVideoGenerationResolution(resolutionValue);
8214
- if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 720p, 1080p, or 4k");
8212
+ if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 480p, 720p, 1080p, or 4k");
8215
8213
  const videoDurationSeconds = durationValue === void 0 ? void 0 : normalizeVideoGenerationDurationSeconds(durationValue);
8216
- if (durationValue !== void 0 && !videoDurationSeconds) throw new Error("--duration must be 4, 6, or 8");
8214
+ if (durationValue !== void 0 && !videoDurationSeconds) throw new Error("--duration must be an integer from 4 to 15");
8217
8215
  const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
8218
8216
  if (tierValue !== void 0 && !videoTier) throw new Error("--tier must be generate, fast, or lite");
8219
8217
  const model = parseVideoModelOption(modelValue, videoTier);
8220
8218
  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");
8219
+ if ((isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && tierValue !== void 0) throw new Error("--tier is only supported with --model veo-3.1");
8221
8220
  if (videoResolution && videoTier && !isVideoGenerationResolutionSupportedForTier(videoResolution, videoTier)) throw new Error("--resolution 4k is not supported with --tier lite");
8221
+ if (videoResolution && (isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && !isVideoGenerationResolutionSupportedForModel(model, videoResolution)) throw new Error(`--model ${getVideoModelSelectionForModel(model) ?? model} does not support --resolution ${videoResolution}`);
8222
+ if (!isFalSeedance2VideoGenerationModel(model) && videoDurationSeconds && ![
8223
+ 4,
8224
+ 6,
8225
+ 8
8226
+ ].includes(videoDurationSeconds)) throw new Error("--duration must be 4, 6, or 8 for this model");
8222
8227
  const aspectRatio = aspectValue === void 0 ? void 0 : normalizeVideoGenerationAspectRatio(aspectValue);
8223
8228
  if (aspectValue !== void 0 && !aspectRatio) throw new Error("--aspect must be 16:9 or 9:16");
8224
8229
  return {
@@ -8245,7 +8250,9 @@ function validateVideoFrameReferenceOptions(command, parsed, mediaKind) {
8245
8250
  if (parsed.options.refs) throw new Error("--first-frame and --last-frame cannot be combined with --refs");
8246
8251
  const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
8247
8252
  const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
8248
- if (isGeminiOmniVideoGenerationModel(parseVideoModelOption(readOptionalOption(parsed, "model", "model"), videoTier))) throw new Error("--first-frame and --last-frame are only supported with --model veo-3.1");
8253
+ const model = parseVideoModelOption(readOptionalOption(parsed, "model", "model"), videoTier);
8254
+ if (isFalSeedance2VideoGenerationModel(model) && !firstFrame) throw new Error("--model seedance-2 requires --first-frame");
8255
+ if (!isFalSeedance2VideoGenerationModel(model) && (isFalVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) && Boolean(lastFrame))) throw new Error("--first-frame and --last-frame are only supported with --model veo-3.1 or seedance-2");
8249
8256
  }
8250
8257
  function readVideoFrameOption(parsed, kebabName, camelName) {
8251
8258
  const value = parsed.options[kebabName] ?? parsed.options[camelName];
@@ -8299,17 +8306,18 @@ function parseVideoModelOption(value, tier) {
8299
8306
  if (selection) return getVideoGenerationModelForSelection(selection, effectiveTier);
8300
8307
  if (isVideoGenerationModel(normalized)) {
8301
8308
  const modelTier = normalizeVideoGenerationTier(tier) ?? void 0;
8302
- if (modelTier && getVideoGenerationModelForTier(modelTier) !== normalized && !isGeminiOmniVideoGenerationModel(normalized)) throw new Error("--model and --tier select different Veo models");
8309
+ if (modelTier && getVideoGenerationModelForTier(modelTier) !== normalized && !isGeminiOmniVideoGenerationModel(normalized) && !isKlingVideoGenerationModel(normalized) && !isFalVideoGenerationModel(normalized)) throw new Error("--model and --tier select different Veo models");
8303
8310
  return normalized;
8304
8311
  }
8305
- throw new Error("--model must be veo-3.1, omni-flash, or an exact video model ID");
8312
+ throw new Error("--model must be veo-3.1, omni-flash, kling, or an exact video model ID");
8306
8313
  }
8307
8314
  function parseImageModelOption(value) {
8308
8315
  if (!value) return void 0;
8309
8316
  if (isImageModelSelection(value)) return value;
8310
8317
  if (value === IMAGE_MODEL_IDS.pro) return "pro";
8311
8318
  if (value === IMAGE_MODEL_IDS.flash) return "flash";
8312
- throw new Error("--model must be pro or flash");
8319
+ if (value === IMAGE_MODEL_IDS.flux) return "flux";
8320
+ throw new Error("--model must be pro, flash, or flux");
8313
8321
  }
8314
8322
  function parseImageSizeOption(value) {
8315
8323
  if (!value) return void 0;
@@ -8332,9 +8340,23 @@ function validateImageReferenceCount(model, referenceCount) {
8332
8340
  }
8333
8341
  function validateImageCommandReferenceCount(command, parsed, mediaKind, model) {
8334
8342
  if (mediaKind !== "image") return;
8335
- if (command !== "derive" && command !== "batch") return;
8336
- if (!parsed.options.refs) return;
8337
- validateImageReferenceCount(model, parseRefs(parsed.options.refs).length);
8343
+ if (command === "refine") {
8344
+ validateImageReferenceCount(model, 1);
8345
+ return;
8346
+ }
8347
+ if ((command === "derive" || command === "batch") && parsed.options.refs) validateImageReferenceCount(model, parseRefs(parsed.options.refs).length);
8348
+ }
8349
+ function validateImageModelOperation(command, mediaKind, model) {
8350
+ if (mediaKind !== "image") return;
8351
+ const operation = command === "batch" ? "generate" : command;
8352
+ if (isImageOperationSupportedByModel(model, operation)) return;
8353
+ throw new Error(`--model ${model ?? "pro"} does not support ${operation}`);
8354
+ }
8355
+ function validateVideoModelOperation(command, mediaKind, model) {
8356
+ if (mediaKind !== "video" || command === "batch") return;
8357
+ const effectiveModel = model ?? getVideoGenerationModelForSelection();
8358
+ if (isVideoOperationSupportedByModel(effectiveModel, command)) return;
8359
+ throw new Error(`--model ${getVideoModelSelectionForModel(effectiveModel) ?? effectiveModel} does not support video ${command}`);
8338
8360
  }
8339
8361
  function readOptionalOption(parsed, kebabName, camelName) {
8340
8362
  const value = parsed.options[kebabName] ?? parsed.options[camelName];
@@ -8378,11 +8400,15 @@ function cliImageSizeValues() {
8378
8400
  function cliImageAspectValues() {
8379
8401
  return cliOptionValues(getImageModelCapabilities().supportedAspectRatios);
8380
8402
  }
8381
- function printUsage$8(command) {
8403
+ function cliImageModelValues(command) {
8404
+ const operation = command === "batch" ? "generate" : command;
8405
+ return cliOptionValues(IMAGE_MODEL_SELECTIONS.filter((model) => isImageOperationSupportedByModel(model, operation)));
8406
+ }
8407
+ function printUsage$9(command) {
8382
8408
  if (command === "generate") {
8383
8409
  console.log(`
8384
8410
  Usage:
8385
- makefx generate "prompt" --name <name> --type <type> -o <file> [--model pro|flash] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
8411
+ makefx generate "prompt" --name <name> --type <type> -o <file> [--model ${cliImageModelValues(command)}] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
8386
8412
  makefx generate --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
8387
8413
  `);
8388
8414
  return;
@@ -8390,7 +8416,7 @@ Usage:
8390
8416
  if (command === "refine") {
8391
8417
  console.log(`
8392
8418
  Usage:
8393
- makefx refine --variant <variant_id> "prompt" -o <file> [--model pro|flash] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
8419
+ makefx refine --variant <variant_id> "prompt" -o <file> [--model ${cliImageModelValues(command)}] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
8394
8420
  makefx refine --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
8395
8421
  `);
8396
8422
  return;
@@ -8398,13 +8424,13 @@ Usage:
8398
8424
  if (command === "batch") {
8399
8425
  console.log(`
8400
8426
  Usage:
8401
- makefx batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--model pro|flash] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>]
8427
+ makefx batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--model ${cliImageModelValues(command)}] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>]
8402
8428
  `);
8403
8429
  return;
8404
8430
  }
8405
8431
  console.log(`
8406
8432
  Usage:
8407
- makefx derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model pro|flash] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
8433
+ makefx derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${cliImageModelValues(command)}] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
8408
8434
  makefx derive --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
8409
8435
  `);
8410
8436
  }
@@ -8419,7 +8445,7 @@ function printBatchResult(result, outputDir, manifestPath, ctx, mediaKind) {
8419
8445
  }
8420
8446
  //#endregion
8421
8447
  //#region src/cli/commands/audio.ts
8422
- var defaultDeps$7 = {
8448
+ var defaultDeps$8 = {
8423
8449
  loadConfig: loadStoredConfig,
8424
8450
  loadProjectConfig,
8425
8451
  resolveBaseUrl,
@@ -8432,11 +8458,11 @@ async function handleAudio(parsed) {
8432
8458
  await executeAudio(parsed);
8433
8459
  } catch (error) {
8434
8460
  console.error("Error:", error instanceof Error ? error.message : error);
8435
- printUsage$7();
8461
+ printUsage$8();
8436
8462
  process$1.exitCode = 1;
8437
8463
  }
8438
8464
  }
8439
- async function executeAudio(parsed, deps = defaultDeps$7) {
8465
+ async function executeAudio(parsed, deps = defaultDeps$8) {
8440
8466
  const invocation = parseAudioInvocation(parsed.positionals);
8441
8467
  if (invocation.command === "voices") return executeAudioVoices({
8442
8468
  ...parsed,
@@ -8509,7 +8535,7 @@ function printVoices(response, print) {
8509
8535
  function formatLabels(labels) {
8510
8536
  return Object.entries(labels).map(([key, value]) => `${key}:${value}`).join(", ");
8511
8537
  }
8512
- function printUsage$7() {
8538
+ function printUsage$8() {
8513
8539
  const modes = AUDIO_FORGE_MEDIA_MODES.join("|");
8514
8540
  console.log(`
8515
8541
  Usage:
@@ -8538,7 +8564,7 @@ async function handleVideo(parsed) {
8538
8564
  });
8539
8565
  } catch (error) {
8540
8566
  console.error("Error:", error instanceof Error ? error.message : error);
8541
- printUsage$6();
8567
+ printUsage$7();
8542
8568
  process$1.exitCode = 1;
8543
8569
  }
8544
8570
  }
@@ -8547,35 +8573,36 @@ function parseVideoCommand(value) {
8547
8573
  if (value && commands.includes(value)) return value;
8548
8574
  throw new Error("Video command is required: generate, refine, or derive");
8549
8575
  }
8550
- function printUsage$6() {
8576
+ function printUsage$7() {
8551
8577
  const aspectValues = VIDEO_GENERATION_ASPECT_RATIOS.join("|");
8552
- const resolutionValues = Array.from(new Set(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier)))).join("|");
8553
- const durationValues = VIDEO_GENERATION_DURATION_SECONDS.join("|");
8578
+ const resolutionValues = Array.from(new Set(["480p", ...VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier))])).join("|");
8579
+ const durationValues = Array.from(new Set([...VIDEO_GENERATION_DURATION_SECONDS, ...SEEDANCE_2_DURATION_SECONDS])).join("|");
8554
8580
  const tierValues = VIDEO_GENERATION_TIERS.join("|");
8555
- const modelValues = VIDEO_MODEL_SELECTIONS.join("|");
8581
+ const modelValues = (operation) => VIDEO_MODEL_SELECTIONS.filter((model) => VIDEO_MODEL_SUPPORTED_OPERATIONS[model].includes(operation)).join("|");
8556
8582
  const resolutionByTier = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
8557
8583
  console.log(`
8558
8584
  Usage:
8559
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--model ${modelValues}] [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8585
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--model ${modelValues("generate")}] [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8560
8586
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
8561
- makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${modelValues}] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8587
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${modelValues("refine")}] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8562
8588
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
8563
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${modelValues}] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8564
- makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8589
+ makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${modelValues("derive")}] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8590
+ makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1|seedance-2|seedance-2-fast] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8565
8591
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
8566
8592
 
8567
8593
  Video:
8568
- --model <value> Video model: ${modelValues}
8594
+ --model <value> Generate: ${modelValues("generate")}; refine/derive: ${modelValues("refine")}
8569
8595
  --aspect <ratio> Video aspect ratio: ${aspectValues}
8570
- --resolution <value> Veo-only output resolution (${resolutionByTier})
8571
- --duration <seconds> Veo-only output duration: ${durationValues}
8596
+ --resolution <value> Supported: ${resolutionValues}; Veo: 720p|1080p|4k; Kling: 720p|1080p; Seedance 2: standard 480p|720p|1080p, fast 480p|720p (${resolutionByTier})
8597
+ --duration <seconds> Veo/Kling: ${VIDEO_GENERATION_DURATION_SECONDS.join("|")}; Seedance 2: ${SEEDANCE_2_DURATION_SECONDS.join("|")}
8572
8598
  --tier <tier> Veo-only model tier: ${tierValues}
8573
- --first-frame <ref> Veo start frame image variant or local image path
8574
- --last-frame <ref> Veo final frame image variant or local image path
8599
+ --first-frame <ref> Veo or Seedance 2 start frame image variant or local image path
8600
+ --last-frame <ref> Veo or Seedance 2 final frame image variant or local image path
8575
8601
 
8576
- Veo 3.1 frames:
8602
+ Frame inputs:
8577
8603
  --first-frame resolves to the first referenceVariantId and becomes the Veo top-level image input.
8578
- --last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame.
8604
+ --last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame or Seedance 2 end_image_url.
8605
+ Seedance 2 requires --first-frame and supports an optional --last-frame.
8579
8606
  Use both flags together for first/last-frame generation; --last-frame requires --first-frame.
8580
8607
  Do not combine frame flags with --refs. Use --refs when you want generic Veo reference images instead of first/last-frame inputs.
8581
8608
 
@@ -8586,17 +8613,17 @@ Audio:
8586
8613
  }
8587
8614
  //#endregion
8588
8615
  //#region src/cli/commands/init.ts
8589
- var defaultDeps$6 = { saveProjectConfig };
8616
+ var defaultDeps$7 = { saveProjectConfig };
8590
8617
  async function handleInit(parsed) {
8591
8618
  try {
8592
8619
  await executeInit(parsed);
8593
8620
  } catch (error) {
8594
8621
  console.error("Error:", error instanceof Error ? error.message : error);
8595
- printUsage$5();
8622
+ printUsage$6();
8596
8623
  process$1.exitCode = 1;
8597
8624
  }
8598
8625
  }
8599
- async function executeInit(parsed, deps = defaultDeps$6) {
8626
+ async function executeInit(parsed, deps = defaultDeps$7) {
8600
8627
  const environment = resolveCommandEnvironment(parsed);
8601
8628
  const spaceId = resolveCommandSpace(parsed);
8602
8629
  if (!spaceId) throw new Error("--space is required");
@@ -8622,7 +8649,7 @@ async function executeInit(parsed, deps = defaultDeps$6) {
8622
8649
  spaceId
8623
8650
  };
8624
8651
  }
8625
- function printUsage$5() {
8652
+ function printUsage$6() {
8626
8653
  console.log(`
8627
8654
  Usage:
8628
8655
  makefx init --space <id> [--env production|stage|local]
@@ -8631,7 +8658,7 @@ Usage:
8631
8658
  }
8632
8659
  //#endregion
8633
8660
  //#region src/cli/commands/runs.ts
8634
- var defaultDeps$5 = {
8661
+ var defaultDeps$6 = {
8635
8662
  loadProjectConfig,
8636
8663
  listRunManifests,
8637
8664
  readRunManifest,
@@ -8644,11 +8671,11 @@ async function handleRuns(parsed) {
8644
8671
  await executeRuns(parsed);
8645
8672
  } catch (error) {
8646
8673
  console.error("Error:", error instanceof Error ? error.message : error);
8647
- printUsage$4();
8674
+ printUsage$5();
8648
8675
  process$1.exitCode = 1;
8649
8676
  }
8650
8677
  }
8651
- async function executeRuns(parsed, deps = defaultDeps$5) {
8678
+ async function executeRuns(parsed, deps = defaultDeps$6) {
8652
8679
  const projectConfig = await deps.loadProjectConfig();
8653
8680
  if (!projectConfig?.projectRoot) throw new Error("Make Effects project config not found. Run: makefx init --space <id>");
8654
8681
  requireDebugAcknowledgement(parsed);
@@ -8766,7 +8793,7 @@ function formatCreated(value) {
8766
8793
  if (Number.isNaN(date.getTime())) return value;
8767
8794
  return value.replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
8768
8795
  }
8769
- function printUsage$4() {
8796
+ function printUsage$5() {
8770
8797
  console.log(`
8771
8798
  Usage:
8772
8799
  makefx runs --debug
@@ -8781,7 +8808,7 @@ Local run manifests are debug-only artifacts, not a source of truth.
8781
8808
  }
8782
8809
  //#endregion
8783
8810
  //#region src/cli/commands/assets.ts
8784
- var defaultDeps$4 = {
8811
+ var defaultDeps$5 = {
8785
8812
  loadConfig: loadStoredConfig,
8786
8813
  loadProjectConfig,
8787
8814
  resolveBaseUrl,
@@ -8805,15 +8832,15 @@ async function handleAssets(parsed) {
8805
8832
  await executeAssets(parsed);
8806
8833
  } catch (error) {
8807
8834
  console.error("Error:", error instanceof Error ? error.message : error);
8808
- printUsage$3();
8835
+ printUsage$4();
8809
8836
  process$1.exitCode = 1;
8810
8837
  }
8811
8838
  }
8812
- async function executeAssets(parsed, deps = defaultDeps$4) {
8839
+ async function executeAssets(parsed, deps = defaultDeps$5) {
8813
8840
  const subcommand = parsed.positionals[0] || "list";
8814
8841
  if (subcommand === "search") return searchAssets(parsed, deps);
8815
8842
  if (subcommand === "clone") return cloneAsset(parsed, deps);
8816
- const ctx = await buildContext$4(parsed, deps);
8843
+ const ctx = await buildContext$5(parsed, deps);
8817
8844
  if (subcommand === "list") {
8818
8845
  const assets = await listAssets(ctx, deps);
8819
8846
  if (parsed.options.json === "true") deps.print(JSON.stringify(assets.map(toAssetJson), null, 2));
@@ -8905,7 +8932,7 @@ async function executeAssets(parsed, deps = defaultDeps$4) {
8905
8932
  function normalizeOption$1(value) {
8906
8933
  return !value || value === "true" ? void 0 : value;
8907
8934
  }
8908
- async function buildContext$4(parsed, deps) {
8935
+ async function buildContext$5(parsed, deps) {
8909
8936
  const projectConfig = await deps.loadProjectConfig();
8910
8937
  const env = resolveCommandEnvironment(parsed, projectConfig);
8911
8938
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -9275,7 +9302,7 @@ function formatTimestamp(value) {
9275
9302
  if (Number.isNaN(date.getTime())) return String(value);
9276
9303
  return date.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
9277
9304
  }
9278
- function printUsage$3() {
9305
+ function printUsage$4() {
9279
9306
  console.log(`
9280
9307
  Usage:
9281
9308
  makefx assets
@@ -9292,7 +9319,7 @@ Usage:
9292
9319
  }
9293
9320
  //#endregion
9294
9321
  //#region src/cli/commands/variants.ts
9295
- var defaultDeps$3 = {
9322
+ var defaultDeps$4 = {
9296
9323
  loadConfig: loadStoredConfig,
9297
9324
  loadProjectConfig,
9298
9325
  resolveBaseUrl,
@@ -9304,12 +9331,12 @@ async function handleVariants(parsed) {
9304
9331
  await executeVariants(parsed);
9305
9332
  } catch (error) {
9306
9333
  console.error("Error:", error instanceof Error ? error.message : error);
9307
- printUsage$2();
9334
+ printUsage$3();
9308
9335
  process$1.exitCode = 1;
9309
9336
  }
9310
9337
  }
9311
- async function executeVariants(parsed, deps = defaultDeps$3) {
9312
- const ctx = await buildContext$3(parsed, deps);
9338
+ async function executeVariants(parsed, deps = defaultDeps$4) {
9339
+ const ctx = await buildContext$4(parsed, deps);
9313
9340
  const subcommand = parsed.positionals[0];
9314
9341
  if (subcommand === "delete") {
9315
9342
  const variantId = requireVariantId(parsed, "delete");
@@ -9357,7 +9384,7 @@ function requireVariantId(parsed, verb) {
9357
9384
  if (!variantId) throw new Error(`Variant ID is required: makefx variants ${verb} <variant-id>`);
9358
9385
  return variantId;
9359
9386
  }
9360
- async function buildContext$3(parsed, deps) {
9387
+ async function buildContext$4(parsed, deps) {
9361
9388
  const projectConfig = await deps.loadProjectConfig();
9362
9389
  const env = resolveCommandEnvironment(parsed, projectConfig);
9363
9390
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -9380,7 +9407,7 @@ async function withVariantClient(ctx, deps, run) {
9380
9407
  client.disconnect();
9381
9408
  }
9382
9409
  }
9383
- function printUsage$2() {
9410
+ function printUsage$3() {
9384
9411
  console.log(`
9385
9412
  Usage:
9386
9413
  makefx variants delete <variant-id>
@@ -9396,6 +9423,84 @@ Options:
9396
9423
  `);
9397
9424
  }
9398
9425
  //#endregion
9426
+ //#region src/cli/commands/recipes.ts
9427
+ var defaultDeps$3 = {
9428
+ loadConfig: loadStoredConfig,
9429
+ loadProjectConfig,
9430
+ resolveBaseUrl,
9431
+ fetch,
9432
+ print: console.log
9433
+ };
9434
+ async function handleRecipes(parsed) {
9435
+ try {
9436
+ await executeRecipes(parsed);
9437
+ } catch (error) {
9438
+ console.error("Error:", error instanceof Error ? error.message : error);
9439
+ printUsage$2();
9440
+ process$1.exitCode = 1;
9441
+ }
9442
+ }
9443
+ async function executeRecipes(parsed, deps = defaultDeps$3) {
9444
+ const subcommand = parsed.positionals[0];
9445
+ if (subcommand !== "run") throw new Error(`Unknown recipes command: ${subcommand ?? "(none)"}`);
9446
+ const sourceVariantId = parsed.positionals[1];
9447
+ if (!sourceVariantId) throw new Error("Variant ID is required: makefx recipes run <variant-id>");
9448
+ const rerun = await runRecipe(await buildContext$3(parsed, deps), deps, sourceVariantId);
9449
+ if (parsed.options.json === "true") deps.print(JSON.stringify(rerun, null, 2));
9450
+ else {
9451
+ deps.print(`Re-ran recipe from variant ${rerun.sourceVariantId}`);
9452
+ deps.print(` Variant: ${rerun.variant.id} (status: ${rerun.variant.status})`);
9453
+ deps.print(` Request: ${rerun.requestId}`);
9454
+ deps.print(`Watch progress with: makefx assets show ${rerun.variant.asset_id}`);
9455
+ }
9456
+ return {
9457
+ type: "run",
9458
+ rerun
9459
+ };
9460
+ }
9461
+ async function buildContext$3(parsed, deps) {
9462
+ const projectConfig = await deps.loadProjectConfig();
9463
+ const env = resolveCommandEnvironment(parsed, projectConfig);
9464
+ const spaceId = resolveCommandSpace(parsed, projectConfig);
9465
+ if (!spaceId) throw new Error("--space is required, or run: makefx init --space <id>");
9466
+ const config = await deps.loadConfig(env);
9467
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
9468
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
9469
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
9470
+ return {
9471
+ spaceId,
9472
+ baseUrl: deps.resolveBaseUrl(env),
9473
+ accessToken: config.token.accessToken
9474
+ };
9475
+ }
9476
+ async function runRecipe(ctx, deps, sourceVariantId) {
9477
+ const response = await deps.fetch(`${ctx.baseUrl}/api/spaces/${encodeURIComponent(ctx.spaceId)}/variants/${encodeURIComponent(sourceVariantId)}/rerun`, {
9478
+ method: "POST",
9479
+ headers: {
9480
+ Authorization: `Bearer ${ctx.accessToken}`,
9481
+ Accept: "application/json"
9482
+ }
9483
+ });
9484
+ if (!response.ok) {
9485
+ const text = await response.text();
9486
+ throw new Error(`Recipe rerun failed (${response.status}): ${text || response.statusText}`);
9487
+ }
9488
+ return response.json();
9489
+ }
9490
+ function printUsage$2() {
9491
+ console.log(`
9492
+ Usage:
9493
+ makefx recipes run <variant-id>
9494
+ makefx recipes run <variant-id> --json
9495
+
9496
+ Options:
9497
+ --space <id> Target space ID; defaults from the initialized project
9498
+ --json Print machine-readable output
9499
+ --env <env> Environment (production|stage|local)
9500
+ --local Shortcut for --env local
9501
+ `);
9502
+ }
9503
+ //#endregion
9399
9504
  //#region src/cli/commands/collections.ts
9400
9505
  var COLLECTION_KINDS = new Set([
9401
9506
  "cast",
@@ -9712,6 +9817,7 @@ function printUsageSummary(summary, print) {
9712
9817
  print(` Storage: ${formatBytes(summary.totals.storageBytes)}`);
9713
9818
  print(` Workflow runs: ${summary.totals.workflowRuns}`);
9714
9819
  print(` Delivery: ${formatBytes(summary.totals.deliveryBytes)}`);
9820
+ print(` Provider spend: $${summary.providerSpend.amountUsd.toFixed(6)} (${summary.providerSpend.entries} recorded entr${summary.providerSpend.entries === 1 ? "y" : "ies"}, ${summary.providerSpend.unpricedEntries} unpriced)`);
9715
9821
  if (summary.byMediaKind.length > 0) {
9716
9822
  print("\nBy media kind:");
9717
9823
  print("Media".padEnd(10) + "Storage".padEnd(14) + "Workflows".padEnd(12) + "Delivery".padEnd(14) + "Events");
@@ -9941,7 +10047,7 @@ Options:
9941
10047
  }
9942
10048
  //#endregion
9943
10049
  //#region src/cli/index.ts
9944
- var CLI_VERSION = "1.0.7+686298a71cee";
10050
+ var CLI_VERSION = "1.2.0+10cb109b7379";
9945
10051
  async function main() {
9946
10052
  const argv = process$1.argv.slice(2);
9947
10053
  if (argv[0] === "--") argv.shift();
@@ -9984,48 +10090,56 @@ function imageSizeValues() {
9984
10090
  function imageAspectValues() {
9985
10091
  return optionValues(IMAGE_MODEL_CAPABILITIES["pro"].supportedAspectRatios);
9986
10092
  }
9987
- function imageCapabilityHelp() {
10093
+ function imageModelValues(operation) {
10094
+ return optionValues(IMAGE_MODEL_SELECTIONS.filter((model) => operation === void 0 || isImageOperationSupportedByModel(model, operation)));
10095
+ }
10096
+ function imageCapabilityHelp(operation) {
9988
10097
  const sizeLines = IMAGE_MODEL_SELECTIONS.map((model) => `${model}: ${IMAGE_MODEL_CAPABILITIES[model].supportedImageSizes.join(", ")}`).join("; ");
9989
10098
  const referenceLines = IMAGE_MODEL_SELECTIONS.map((model) => `${model}: ${IMAGE_MODEL_CAPABILITIES[model].maxReferenceImages}`).join("; ");
10099
+ const operationLines = IMAGE_MODEL_SELECTIONS.map((model) => `${model}: ${IMAGE_MODEL_CAPABILITIES[model].supportedOperations.join(", ")}`).join("; ");
9990
10100
  return `Image:
9991
- --model <value> Image model: ${optionValues(IMAGE_MODEL_SELECTIONS)}
10101
+ --model <value> Image model: ${imageModelValues(operation)}
9992
10102
  --size <value> Output size (${sizeLines})
9993
10103
  --aspect <ratio> Aspect ratio: ${imageAspectValues()}
9994
10104
  --refs <refs> Reference limit (${referenceLines})
10105
+ Model operations: ${operationLines}
9995
10106
  --follow <id> Resume/download a variant after a long generation or disconnect
9996
10107
  --collection <id> Place the completed asset in a Space collection`;
9997
10108
  }
9998
10109
  function videoResolutionValues() {
9999
- return optionValues(uniqueValues(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier))));
10110
+ return optionValues(uniqueValues(["480p", ...VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier))]));
10000
10111
  }
10001
10112
  function videoAspectValues() {
10002
10113
  return optionValues(VIDEO_GENERATION_ASPECT_RATIOS);
10003
10114
  }
10004
10115
  function videoDurationValues() {
10005
- return optionValues(VIDEO_GENERATION_DURATION_SECONDS);
10116
+ return optionValues(uniqueValues([...VIDEO_GENERATION_DURATION_SECONDS, ...SEEDANCE_2_DURATION_SECONDS]));
10006
10117
  }
10007
10118
  function videoTierValues() {
10008
10119
  return optionValues(VIDEO_GENERATION_TIERS);
10009
10120
  }
10010
- function videoModelValues() {
10011
- return optionValues(VIDEO_MODEL_SELECTIONS);
10121
+ function videoModelValues(operation) {
10122
+ return optionValues(VIDEO_MODEL_SELECTIONS.filter((model) => operation === void 0 || VIDEO_MODEL_SUPPORTED_OPERATIONS[model].includes(operation)));
10012
10123
  }
10013
- function videoCapabilityHelp() {
10124
+ function videoCapabilityHelp(operation) {
10014
10125
  const resolutionLines = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
10126
+ const operationLines = VIDEO_MODEL_SELECTIONS.map((model) => `${model}: ${VIDEO_MODEL_SUPPORTED_OPERATIONS[model].join(", ")}`).join("; ");
10015
10127
  return `Video:
10016
- --model <value> Video model: ${videoModelValues()}
10128
+ --model <value> Video model: ${videoModelValues(operation)}
10017
10129
  --aspect <ratio> Video aspect ratio: ${videoAspectValues()}
10018
- --resolution <value> Veo-only output resolution (${resolutionLines})
10019
- --duration <seconds> Veo-only output duration: ${videoDurationValues()}
10130
+ --resolution <value> Supported: ${videoResolutionValues()}; Veo: 720p|1080p|4k; Kling: 720p|1080p; Seedance 2: standard 480p|720p|1080p, fast 480p|720p (${resolutionLines})
10131
+ --duration <seconds> Veo/Kling: ${optionValues(VIDEO_GENERATION_DURATION_SECONDS)}; Seedance 2: ${optionValues(SEEDANCE_2_DURATION_SECONDS)}
10020
10132
  --tier <tier> Veo-only model tier: ${videoTierValues()}
10021
- --first-frame <ref> Veo start frame image variant or local image path
10022
- --last-frame <ref> Veo final frame image variant or local image path
10133
+ --first-frame <ref> Veo or Seedance 2 start frame image variant or local image path
10134
+ --last-frame <ref> Veo or Seedance 2 final frame image variant or local image path
10135
+ Model operations: ${operationLines}
10023
10136
  --follow <id> Resume/download a variant after a long generation or disconnect
10024
10137
  --collection <id> Place the completed asset in a Space collection
10025
10138
 
10026
- Veo 3.1 frames:
10139
+ Frame inputs:
10027
10140
  --first-frame resolves to the first referenceVariantId and becomes the Veo top-level image input.
10028
- --last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame.
10141
+ --last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame or Seedance 2 end_image_url.
10142
+ Seedance 2 requires --first-frame and supports an optional --last-frame.
10029
10143
  Use both flags together for first/last-frame generation; --last-frame requires --first-frame.
10030
10144
  Do not combine frame flags with --refs. Use --refs when you want generic Veo reference images instead of first/last-frame inputs.`;
10031
10145
  }
@@ -10102,6 +10216,10 @@ function printCommandHelp(command, positionals) {
10102
10216
  case "variant":
10103
10217
  printVariantsHelp();
10104
10218
  return;
10219
+ case "recipes":
10220
+ case "recipe":
10221
+ printRecipesHelp();
10222
+ return;
10105
10223
  default:
10106
10224
  console.error(`Unknown command: ${command}`);
10107
10225
  printHelp();
@@ -10128,6 +10246,7 @@ Generate:
10128
10246
  video generate "prompt" --name <name> --type animation -o <file>
10129
10247
 
10130
10248
  Continue:
10249
+ recipes run <variant-id> Re-run a stored recipe as a new sibling variant
10131
10250
  generate --follow <variant_id> -o <file>
10132
10251
  video generate --follow <variant_id> -o <file>
10133
10252
  audio <mode> generate --follow <variant_id> -o <file>
@@ -10281,10 +10400,10 @@ function printForgeHelp(command) {
10281
10400
  if (command === "generate") {
10282
10401
  console.log(`
10283
10402
  Usage:
10284
- makefx generate "prompt" --name <name> --type <type> -o <file> [--model ${optionValues(IMAGE_MODEL_SELECTIONS)}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>] [--space <id>]
10403
+ makefx generate "prompt" --name <name> --type <type> -o <file> [--model ${imageModelValues("generate")}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>] [--space <id>]
10285
10404
  makefx generate --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
10286
10405
 
10287
- ${imageCapabilityHelp()}
10406
+ ${imageCapabilityHelp("generate")}
10288
10407
 
10289
10408
  If the CLI stops waiting after a job has started, the job keeps running in Make Effects.
10290
10409
  Rerun the printed --follow command to resume the same variant instead of starting a duplicate.
@@ -10294,10 +10413,10 @@ Rerun the printed --follow command to resume the same variant instead of startin
10294
10413
  if (command === "refine") {
10295
10414
  console.log(`
10296
10415
  Usage:
10297
- makefx refine --variant <variant_id> "prompt" -o <file> [--model ${optionValues(IMAGE_MODEL_SELECTIONS)}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>] [--space <id>]
10416
+ makefx refine --variant <variant_id> "prompt" -o <file> [--model ${imageModelValues("refine")}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>] [--space <id>]
10298
10417
  makefx refine --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
10299
10418
 
10300
- ${imageCapabilityHelp()}
10419
+ ${imageCapabilityHelp("refine")}
10301
10420
 
10302
10421
  If the CLI stops waiting after a job has started, the job keeps running in Make Effects.
10303
10422
  Rerun the printed --follow command to resume the same variant instead of starting a duplicate.
@@ -10307,9 +10426,9 @@ Rerun the printed --follow command to resume the same variant instead of startin
10307
10426
  if (command === "batch") {
10308
10427
  console.log(`
10309
10428
  Usage:
10310
- makefx batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--model ${optionValues(IMAGE_MODEL_SELECTIONS)}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>]
10429
+ makefx batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--model ${imageModelValues("generate")}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>]
10311
10430
 
10312
- ${imageCapabilityHelp()}
10431
+ ${imageCapabilityHelp("generate")}
10313
10432
 
10314
10433
  Batch creates several variants. If waiting stops, inspect the Space or download completed variants with:
10315
10434
  makefx assets download <variant_id> -o <file>
@@ -10318,10 +10437,10 @@ Batch creates several variants. If waiting stops, inspect the Space or download
10318
10437
  }
10319
10438
  console.log(`
10320
10439
  Usage:
10321
- makefx derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${optionValues(IMAGE_MODEL_SELECTIONS)}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>] [--space <id>]
10440
+ makefx derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${imageModelValues("derive")}] [--size ${imageSizeValues()}] [--aspect <ratio>] [--collection <id>] [--space <id>]
10322
10441
  makefx derive --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
10323
10442
 
10324
- ${imageCapabilityHelp()}
10443
+ ${imageCapabilityHelp("derive")}
10325
10444
 
10326
10445
  If the CLI stops waiting after a job has started, the job keeps running in Make Effects.
10327
10446
  Rerun the printed --follow command to resume the same variant instead of starting a duplicate.
@@ -10433,13 +10552,14 @@ function printVideoHelp(positionals) {
10433
10552
  if (subcommand === "generate") {
10434
10553
  console.log(`
10435
10554
  Usage:
10436
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--model ${videoModelValues()}] [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10555
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--model ${videoModelValues("generate")}] [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10437
10556
  makefx video generate --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
10438
10557
 
10439
- ${videoCapabilityHelp()}
10558
+ ${videoCapabilityHelp("generate")}
10440
10559
 
10441
10560
  Audio:
10442
- Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
10561
+ Veo and Kling default to generated audio. fal Seedance is silent and rejects --audio.
10562
+ Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
10443
10563
 
10444
10564
  Long runs:
10445
10565
  If the CLI stops waiting after a job has started, the job keeps running in Make Effects.
@@ -10450,13 +10570,13 @@ Long runs:
10450
10570
  if (subcommand === "refine") {
10451
10571
  console.log(`
10452
10572
  Usage:
10453
- makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10573
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues("refine")}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10454
10574
  makefx video refine --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
10455
10575
 
10456
- ${videoCapabilityHelp()}
10576
+ ${videoCapabilityHelp("refine")}
10457
10577
 
10458
10578
  Audio:
10459
- Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
10579
+ Veo and Kling default to generated audio. Current Veo models do not support --no-audio.
10460
10580
 
10461
10581
  Long runs:
10462
10582
  If the CLI stops waiting after a job has started, the job keeps running in Make Effects.
@@ -10467,14 +10587,14 @@ Long runs:
10467
10587
  if (subcommand === "derive") {
10468
10588
  console.log(`
10469
10589
  Usage:
10470
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10471
- makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10590
+ makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${videoModelValues("derive")}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10591
+ makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1|seedance-2|seedance-2-fast] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10472
10592
  makefx video derive --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
10473
10593
 
10474
- ${videoCapabilityHelp()}
10594
+ ${videoCapabilityHelp("derive")}
10475
10595
 
10476
10596
  Audio:
10477
- Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
10597
+ Veo and Kling default to generated audio. Current Veo models do not support --no-audio.
10478
10598
 
10479
10599
  Long runs:
10480
10600
  If the CLI stops waiting after a job has started, the job keeps running in Make Effects.
@@ -10488,12 +10608,13 @@ Usage:
10488
10608
  makefx video generate --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
10489
10609
  makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10490
10610
  makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10491
- makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10611
+ makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1|seedance-2|seedance-2-fast] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
10492
10612
 
10493
10613
  ${videoCapabilityHelp()}
10494
10614
 
10495
10615
  Audio:
10496
- Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
10616
+ Veo and Kling default to generated audio. Seedance v1 is silent and generate-only; Seedance 2 is silent and supports generate and derive.
10617
+ Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
10497
10618
 
10498
10619
  Long runs:
10499
10620
  If the CLI stops waiting after a job has started, the job keeps running in Make Effects.
@@ -10532,6 +10653,21 @@ Options:
10532
10653
  --local Shortcut for --env local
10533
10654
  `);
10534
10655
  }
10656
+ function printRecipesHelp() {
10657
+ console.log(`
10658
+ Usage:
10659
+ makefx recipes run <variant-id>
10660
+ makefx recipes run <variant-id> --json
10661
+
10662
+ Re-runs the stored generation recipe as a new sibling variant of the same asset.
10663
+
10664
+ Options:
10665
+ --space <id> Target space ID; defaults from the initialized project
10666
+ --json Print machine-readable output
10667
+ --env <env> Environment (production|stage|local)
10668
+ --local Shortcut for --env local
10669
+ `);
10670
+ }
10535
10671
  function printAssetsHelp() {
10536
10672
  console.log(`
10537
10673
  Usage:
@@ -10663,6 +10799,10 @@ async function dispatchCommand(command, parsed) {
10663
10799
  case "variant":
10664
10800
  await handleVariants(parsed);
10665
10801
  break;
10802
+ case "recipes":
10803
+ case "recipe":
10804
+ await handleRecipes(parsed);
10805
+ break;
10666
10806
  default:
10667
10807
  console.error(`Unknown command: ${command}`);
10668
10808
  printHelp();