makefx 1.0.1 → 1.0.3

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 +160 -45
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -176,4 +176,4 @@ Run `makefx --help` or `makefx help <command>` for command-specific options.
176
176
  - Media generation guide: https://makefx.app/docs/media-playbooks
177
177
  - Source: https://github.com/krasnoperov/inventory
178
178
 
179
- Version: 1.0.1
179
+ Version: 1.0.3
package/makefx.mjs CHANGED
@@ -4746,6 +4746,57 @@ var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
4746
4746
  require_websocket_server();
4747
4747
  var wrapper_default = import_websocket.default;
4748
4748
  //#endregion
4749
+ //#region src/shared/generation-errors.ts
4750
+ var GENERATION_PROVIDER_AUTH_MESSAGE = "The generation provider is not configured correctly. Try again later or contact Make Effects support.";
4751
+ var MAX_GENERATION_DIAGNOSTIC_TEXT_LENGTH = 1e3;
4752
+ function extractGenerationDiagnostic(providerMetadata) {
4753
+ if (!providerMetadata) return null;
4754
+ try {
4755
+ const diagnostic = JSON.parse(providerMetadata).generationDiagnostic;
4756
+ if (diagnostic && typeof diagnostic === "object" && diagnostic.kind === "generation_error") return diagnostic;
4757
+ } catch {
4758
+ return null;
4759
+ }
4760
+ return null;
4761
+ }
4762
+ function sanitizeGenerationFailureMessage(errorMessage, providerMetadata) {
4763
+ const diagnostic = extractGenerationDiagnostic(providerMetadata);
4764
+ if (diagnostic?.userMessage) return redactGenerationDiagnosticText(diagnostic.userMessage) ?? "Generation failed";
4765
+ const rawMessage = errorMessage?.trim() || "Generation failed";
4766
+ const cleanMessage = redactGenerationDiagnosticText(extractProviderErrorMessage(rawMessage) ?? rawMessage) ?? "Generation failed";
4767
+ if (isProviderAuthMessage(cleanMessage.toLowerCase(), void 0)) return GENERATION_PROVIDER_AUTH_MESSAGE;
4768
+ return cleanMessage;
4769
+ }
4770
+ function redactGenerationDiagnosticText(message) {
4771
+ if (!message) return message;
4772
+ const redacted = message.replace(/(authorization(?:\s+header)?\s*["']?\s*[:=]\s*["']?(?:Bearer\s+)?)[^"',\s}]+/gi, "$1[redacted]").replace(/(authorization(?:\s+header)?\s+(?:Bearer\s+)?)([^"',\s}]*[0-9._~+/=-][^"',\s}]*)/gi, "$1[redacted]").replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]").replace(/((?:x-goog-api-key|xi-api-key|api[_-\s]?key|access[_-\s]?token|refresh[_-\s]?token|id[_-\s]?token|secret)\s*["']?\s*[:=]\s*["']?)[^"',\s}]+/gi, "$1[redacted]").replace(/((?:api\s+key|access\s+token|refresh\s+token|id\s+token|secret)(?:\s+text)?\s+(?:is\s+|was\s+)?)[A-Za-z0-9._~+/=-]{6,}/gi, "$1[redacted]").replace(/([?&]key=)[^&"',\s}]+/gi, "$1[redacted]").replace(/\bAIza[0-9A-Za-z_-]{10,}\b/g, "[redacted-google-api-key]").replace(/\bsk-[A-Za-z0-9]{16,}\b/g, "[redacted-api-key]").replace(/("(?:data|imageData|audioData|videoData|mediaData|base64|bytes)"\s*:\s*")[^"]{80,}(")/gi, "$1[redacted-binary-data]$2").replace(/data:[^;,\s]+;base64,[A-Za-z0-9+/=]{80,}/gi, "[redacted-data-url]").replace(/\b[A-Za-z0-9+/]{160,}={0,2}\b/g, "[redacted-large-token]");
4773
+ return redacted.length > MAX_GENERATION_DIAGNOSTIC_TEXT_LENGTH ? `${redacted.slice(0, MAX_GENERATION_DIAGNOSTIC_TEXT_LENGTH)}... [truncated]` : redacted;
4774
+ }
4775
+ function extractProviderErrorMessage(message) {
4776
+ const match = message.match(/ApiError:\s*(\{.*\})/s) ?? message.match(/(?:Gemini|Google|Veo).*?:\s*(\{.*\})/s);
4777
+ if (!match) return null;
4778
+ try {
4779
+ const parsed = JSON.parse(match[1]);
4780
+ if (typeof parsed.error?.message === "string") return parsed.error.message;
4781
+ if (typeof parsed.error?.status === "string") return parsed.error.status;
4782
+ } catch {
4783
+ return "Provider request failed";
4784
+ }
4785
+ return "Provider request failed";
4786
+ }
4787
+ function isProviderAuthMessage(message, providerErrorCode, provider) {
4788
+ if (provider === "r2" || provider === "space_do" || provider === "workflow" || provider === "polar") return false;
4789
+ return providerErrorCode?.toLowerCase() === "api_key_invalid" || message.includes("api_key_invalid") || message.includes("api key not valid") || message.includes("invalid api key") || message.includes("api key is required") || message.includes("not configured") || message.includes("unauthenticated");
4790
+ }
4791
+ //#endregion
4792
+ //#region src/cli/lib/error-format.ts
4793
+ function formatServerErrorMessage(code, message) {
4794
+ return `${code}: ${formatGenerationFailureMessage(message)}`;
4795
+ }
4796
+ function formatGenerationFailureMessage(message, providerMetadata) {
4797
+ return sanitizeGenerationFailureMessage(message, providerMetadata);
4798
+ }
4799
+ //#endregion
4749
4800
  //#region src/cli/commands/listen.ts
4750
4801
  /**
4751
4802
  * Listen Command - Connect to space WebSocket and stream all events
@@ -4812,6 +4863,9 @@ var eventColors = {
4812
4863
  "simple_plan:archived": colors.yellow,
4813
4864
  "error": colors.red
4814
4865
  };
4866
+ function formatListenVariantError(message, providerMetadata) {
4867
+ return formatGenerationFailureMessage(message, providerMetadata);
4868
+ }
4815
4869
  async function handleListen(parsed) {
4816
4870
  const projectConfig = await loadProjectConfig();
4817
4871
  const env = resolveCommandEnvironment(parsed, projectConfig);
@@ -4921,7 +4975,7 @@ function printMessageDetails(message, type) {
4921
4975
  const variant = message.variant;
4922
4976
  if (variant) {
4923
4977
  console.log(` Variant: ${variant.id} [${variant.status}]`);
4924
- if (variant.error_message) console.log(` ${colors.red}Error: ${variant.error_message}${colors.reset}`);
4978
+ if (variant.error_message) console.log(` ${colors.red}Error: ${formatListenVariantError(variant.error_message, variant.provider_metadata)}${colors.reset}`);
4925
4979
  }
4926
4980
  break;
4927
4981
  }
@@ -5866,7 +5920,7 @@ var WebSocketClient = class WebSocketClient {
5866
5920
  accessToken;
5867
5921
  env;
5868
5922
  spaceId;
5869
- connectionLoggingEnabled = true;
5923
+ connectionLoggingEnabled = false;
5870
5924
  chatHandlers = /* @__PURE__ */ new Map();
5871
5925
  generateHandlers = /* @__PURE__ */ new Map();
5872
5926
  batchHandlers = /* @__PURE__ */ new Map();
@@ -5926,11 +5980,10 @@ var WebSocketClient = class WebSocketClient {
5926
5980
  const message = JSON.parse(data.toString());
5927
5981
  this.handleMessage(message);
5928
5982
  } catch (err) {
5929
- console.error("[WebSocketClient] Error parsing message:", err);
5983
+ this.onError?.(err instanceof Error ? err : /* @__PURE__ */ new Error("Received an unreadable real-time update"));
5930
5984
  }
5931
5985
  });
5932
5986
  this.ws.on("error", (err) => {
5933
- console.error("[WebSocketClient] WebSocket error:", err);
5934
5987
  this.onError?.(err);
5935
5988
  reject(err);
5936
5989
  });
@@ -6053,7 +6106,7 @@ var WebSocketClient = class WebSocketClient {
6053
6106
  if (handler) {
6054
6107
  this.generateHandlers.delete(errorMsg.requestId);
6055
6108
  clearTimeout(handler.timeout);
6056
- handler.reject(/* @__PURE__ */ new Error(`${errorMsg.code}: ${errorMsg.error}`));
6109
+ handler.reject(new Error(formatServerErrorMessage(errorMsg.code, errorMsg.error)));
6057
6110
  }
6058
6111
  break;
6059
6112
  }
@@ -6063,7 +6116,7 @@ var WebSocketClient = class WebSocketClient {
6063
6116
  if (handler) {
6064
6117
  this.batchHandlers.delete(errorMsg.requestId);
6065
6118
  clearTimeout(handler.timeout);
6066
- handler.reject(/* @__PURE__ */ new Error(`${errorMsg.code}: ${errorMsg.error}`));
6119
+ handler.reject(new Error(formatServerErrorMessage(errorMsg.code, errorMsg.error)));
6067
6120
  }
6068
6121
  break;
6069
6122
  }
@@ -6088,7 +6141,7 @@ var WebSocketClient = class WebSocketClient {
6088
6141
  if (variant.status === "completed") batchHandler.completed.push(variant);
6089
6142
  else batchHandler.failed.push({
6090
6143
  variantId: variant.id,
6091
- error: variant.error_message || "Generation failed"
6144
+ error: formatGenerationFailureMessage(variant.error_message, variant.provider_metadata)
6092
6145
  });
6093
6146
  if (batchHandler.pending.size === 0) {
6094
6147
  this.batchHandlers.delete(batchRequestId);
@@ -6116,7 +6169,7 @@ var WebSocketClient = class WebSocketClient {
6116
6169
  jobId: variant.id,
6117
6170
  success: variant.status === "completed",
6118
6171
  variant: variant.status === "completed" ? variant : void 0,
6119
- error: variant.status === "failed" ? variant.error_message || "Generation failed" : void 0
6172
+ error: variant.status === "failed" ? formatGenerationFailureMessage(variant.error_message, variant.provider_metadata) : void 0
6120
6173
  };
6121
6174
  handler.onResult(result);
6122
6175
  }
@@ -6167,7 +6220,7 @@ var WebSocketClient = class WebSocketClient {
6167
6220
  const mutationConsumed = this.failMutationWaiters(error);
6168
6221
  const estimateConsumed = this.failEstimateHandlers(error);
6169
6222
  if (!(mutationConsumed || estimateConsumed)) {
6170
- console.error(`[WebSocketClient] Server error: ${errorMsg.code} - ${errorMsg.message}`);
6223
+ console.error(`Server error: ${formatServerErrorMessage(errorMsg.code, errorMsg.message)}`);
6171
6224
  this.onError?.(new Error(errorMsg.message));
6172
6225
  }
6173
6226
  break;
@@ -6719,6 +6772,8 @@ var VIDEO_GENERATION_TIERS = [
6719
6772
  "fast",
6720
6773
  "lite"
6721
6774
  ];
6775
+ var VIDEO_MODEL_SELECTIONS = ["veo-3.1", "omni-flash"];
6776
+ var GEMINI_OMNI_FLASH_VIDEO_MODEL = "gemini-omni-flash-preview";
6722
6777
  var VIDEO_GENERATION_AUDIO_TOGGLE_MODELS = [];
6723
6778
  var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
6724
6779
  generate: VIDEO_GENERATION_RESOLUTIONS,
@@ -6726,6 +6781,7 @@ var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
6726
6781
  lite: ["720p", "1080p"]
6727
6782
  };
6728
6783
  var DEFAULT_VIDEO_GENERATION_TIER = "generate";
6784
+ var DEFAULT_VIDEO_MODEL_SELECTION = "veo-3.1";
6729
6785
  function normalizeVideoGenerationAspectRatio(value) {
6730
6786
  return VIDEO_GENERATION_ASPECT_RATIOS.includes(value) ? value : void 0;
6731
6787
  }
@@ -6744,24 +6800,43 @@ function normalizeVideoGenerationDurationSeconds(value) {
6744
6800
  function normalizeVideoGenerationTier(value) {
6745
6801
  return VIDEO_GENERATION_TIERS.includes(value) ? value : void 0;
6746
6802
  }
6803
+ function normalizeVideoModelSelection(value) {
6804
+ return VIDEO_MODEL_SELECTIONS.includes(value) ? value : void 0;
6805
+ }
6747
6806
  function getVideoGenerationModelForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
6748
6807
  return VIDEO_GENERATION_TIER_MODELS[tier];
6749
6808
  }
6809
+ function getVideoGenerationModelForSelection(selection = DEFAULT_VIDEO_MODEL_SELECTION, tier = DEFAULT_VIDEO_GENERATION_TIER) {
6810
+ return selection === "omni-flash" ? GEMINI_OMNI_FLASH_VIDEO_MODEL : getVideoGenerationModelForTier(tier);
6811
+ }
6750
6812
  function getVideoGenerationResolutionsForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
6751
6813
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier];
6752
6814
  }
6753
6815
  function isVideoGenerationResolutionSupportedForTier(resolution, tier = DEFAULT_VIDEO_GENERATION_TIER) {
6754
6816
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].includes(resolution);
6755
6817
  }
6818
+ function getVideoGenerationTierForModel(model) {
6819
+ if (typeof model !== "string") return void 0;
6820
+ return VIDEO_GENERATION_TIERS.find((tier) => VIDEO_GENERATION_TIER_MODELS[tier] === model);
6821
+ }
6822
+ function isVeoVideoGenerationModel(model) {
6823
+ return typeof model === "string" && getVideoGenerationTierForModel(model) !== void 0;
6824
+ }
6825
+ function isGeminiOmniVideoGenerationModel(model) {
6826
+ return model === GEMINI_OMNI_FLASH_VIDEO_MODEL;
6827
+ }
6828
+ function isVideoGenerationModel(model) {
6829
+ return isVeoVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model);
6830
+ }
6756
6831
  function doesVideoGenerationModelSupportAudioToggle(model) {
6757
- return VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6832
+ return isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6758
6833
  }
6759
6834
  //#endregion
6760
6835
  //#region src/shared/imageGenerationOptions.ts
6761
6836
  var IMAGE_MODEL_SELECTIONS = ["pro", "flash"];
6762
6837
  var IMAGE_MODEL_IDS = {
6763
- pro: "gemini-3-pro-image-preview",
6764
- flash: "gemini-2.5-flash-image"
6838
+ pro: "gemini-3-pro-image",
6839
+ flash: "gemini-3.1-flash-image"
6765
6840
  };
6766
6841
  IMAGE_MODEL_IDS["pro"];
6767
6842
  var IMAGE_ASPECT_RATIOS = [
@@ -6796,8 +6871,12 @@ var IMAGE_MODEL_CAPABILITIES = {
6796
6871
  flash: {
6797
6872
  selection: "flash",
6798
6873
  modelId: IMAGE_MODEL_IDS.flash,
6799
- maxReferenceImages: 1,
6800
- supportedImageSizes: ["1K"],
6874
+ maxReferenceImages: 14,
6875
+ supportedImageSizes: [
6876
+ "1K",
6877
+ "2K",
6878
+ "4K"
6879
+ ],
6801
6880
  supportedAspectRatios: IMAGE_ASPECT_RATIOS
6802
6881
  }
6803
6882
  };
@@ -7068,10 +7147,15 @@ async function handleForgeCommand(command, parsed) {
7068
7147
  await executeForgeCommand(command, parsed, defaultDeps$7);
7069
7148
  } catch (error) {
7070
7149
  console.error("Error:", error instanceof Error ? error.message : error);
7071
- printUsage$7(command);
7150
+ if (shouldPrintUsageForForgeError(error)) printUsage$7(command);
7072
7151
  process$1.exitCode = 1;
7073
7152
  }
7074
7153
  }
7154
+ function shouldPrintUsageForForgeError(error) {
7155
+ if (!(error instanceof Error)) return false;
7156
+ const message = error.message;
7157
+ 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");
7158
+ }
7075
7159
  async function executeForgeCommand(command, parsed, deps = defaultDeps$7, options = {}) {
7076
7160
  const mediaKind = options.mediaKind || CLI_GENERATION_MEDIA_KIND;
7077
7161
  if (parsed.options.follow) {
@@ -7168,7 +7252,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
7168
7252
  mediaKind,
7169
7253
  prompt,
7170
7254
  count: 1,
7171
- model: imageOptions.model ?? audioModelOptions.model,
7255
+ model: imageOptions.model ?? audioModelOptions.model ?? videoOptions.model,
7172
7256
  imageSize: imageOptions.imageSize,
7173
7257
  ...musicProvider ? { musicProvider } : {},
7174
7258
  ...videoAudioOptions,
@@ -7263,7 +7347,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
7263
7347
  mediaKind,
7264
7348
  prompt,
7265
7349
  count: 1,
7266
- model: imageOptions.model,
7350
+ model: imageOptions.model ?? videoOptions.model,
7267
7351
  imageSize: imageOptions.imageSize,
7268
7352
  ...videoAudioOptions,
7269
7353
  ...videoOptions
@@ -7334,7 +7418,7 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
7334
7418
  mediaKind,
7335
7419
  prompt,
7336
7420
  count: 1,
7337
- model: imageOptions.model,
7421
+ model: imageOptions.model ?? videoOptions.model,
7338
7422
  imageSize: imageOptions.imageSize,
7339
7423
  ...videoAudioOptions,
7340
7424
  ...videoOptions
@@ -7497,7 +7581,7 @@ function resultFromTerminalVariant(variant, requestId) {
7497
7581
  requestId,
7498
7582
  jobId: variant.id,
7499
7583
  success: false,
7500
- error: variant.error_message || "Generation failed"
7584
+ error: formatGenerationFailureMessage(variant.error_message, variant.provider_metadata)
7501
7585
  };
7502
7586
  }
7503
7587
  function parseGenerationRecipe(recipeJson) {
@@ -7942,11 +8026,13 @@ function validateVideoAudioOptions(parsed, mediaKind) {
7942
8026
  if (!(parsed.options.audio !== void 0 || parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0)) return;
7943
8027
  if (mediaKind !== "video") throw new Error("--audio and --no-audio are only supported for video generation");
7944
8028
  if (parsed.options.audio !== void 0 && (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0)) throw new Error("Pass either --audio or --no-audio, not both");
8029
+ const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
8030
+ const modelValue = readOptionalOption(parsed, "model", "model");
8031
+ const videoTier = tierValue === void 0 ? DEFAULT_VIDEO_GENERATION_TIER : normalizeVideoGenerationTier(tierValue);
8032
+ if (!videoTier) throw new Error("--tier must be generate, fast, or lite");
8033
+ const model = parseVideoModelOption(modelValue, videoTier);
8034
+ if (parsed.options.audio !== void 0 && isGeminiOmniVideoGenerationModel(model)) throw new Error("--audio is only supported with --model veo-3.1");
7945
8035
  if (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0) {
7946
- const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
7947
- const videoTier = tierValue === void 0 ? DEFAULT_VIDEO_GENERATION_TIER : normalizeVideoGenerationTier(tierValue);
7948
- if (!videoTier) throw new Error("--tier must be generate, fast, or lite");
7949
- const model = getVideoGenerationModelForTier(videoTier);
7950
8036
  if (!doesVideoGenerationModelSupportAudioToggle(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
7951
8037
  }
7952
8038
  }
@@ -7961,8 +8047,9 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7961
8047
  const resolutionValue = readOptionalOption(parsed, "resolution", "resolution") ?? readOptionalOption(parsed, "video-resolution", "videoResolution");
7962
8048
  const durationValue = readOptionalOption(parsed, "duration", "duration") ?? readOptionalOption(parsed, "video-duration", "videoDuration");
7963
8049
  const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
8050
+ const modelValue = mediaKind === "video" ? readOptionalOption(parsed, "model", "model") : void 0;
7964
8051
  const aspectValue = mediaKind === "video" ? readOptionalOption(parsed, "aspect", "aspect") : void 0;
7965
- if (resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0) return {};
8052
+ if (mediaKind !== "video" && resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0) return {};
7966
8053
  if (mediaKind !== "video") throw new Error("--resolution, --duration, and --tier are only supported for video generation");
7967
8054
  const videoResolution = resolutionValue === void 0 ? void 0 : normalizeVideoGenerationResolution(resolutionValue);
7968
8055
  if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 720p, 1080p, or 4k");
@@ -7970,10 +8057,13 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7970
8057
  if (durationValue !== void 0 && !videoDurationSeconds) throw new Error("--duration must be 4, 6, or 8");
7971
8058
  const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
7972
8059
  if (tierValue !== void 0 && !videoTier) throw new Error("--tier must be generate, fast, or lite");
8060
+ const model = parseVideoModelOption(modelValue, videoTier);
8061
+ 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");
7973
8062
  if (videoResolution && videoTier && !isVideoGenerationResolutionSupportedForTier(videoResolution, videoTier)) throw new Error("--resolution 4k is not supported with --tier lite");
7974
8063
  const aspectRatio = aspectValue === void 0 ? void 0 : normalizeVideoGenerationAspectRatio(aspectValue);
7975
8064
  if (aspectValue !== void 0 && !aspectRatio) throw new Error("--aspect must be 16:9 or 9:16");
7976
8065
  return {
8066
+ model,
7977
8067
  ...aspectRatio ? { aspectRatio } : {},
7978
8068
  ...videoResolution ? { videoResolution } : {},
7979
8069
  ...videoDurationSeconds ? { videoDurationSeconds } : {},
@@ -7994,6 +8084,9 @@ function validateVideoFrameReferenceOptions(command, parsed, mediaKind) {
7994
8084
  if (command !== "generate" && command !== "derive") throw new Error("--first-frame and --last-frame are only supported for video generate and video derive");
7995
8085
  if (lastFrame && !firstFrame) throw new Error("--last-frame requires --first-frame");
7996
8086
  if (parsed.options.refs) throw new Error("--first-frame and --last-frame cannot be combined with --refs");
8087
+ const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
8088
+ const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
8089
+ if (isGeminiOmniVideoGenerationModel(parseVideoModelOption(readOptionalOption(parsed, "model", "model"), videoTier))) throw new Error("--first-frame and --last-frame are only supported with --model veo-3.1");
7997
8090
  }
7998
8091
  function readVideoFrameOption(parsed, kebabName, camelName) {
7999
8092
  const value = parsed.options[kebabName] ?? parsed.options[camelName];
@@ -8039,6 +8132,19 @@ function parseImageGenerationOptions(parsed, mediaKind) {
8039
8132
  ...aspectRatio ? { aspectRatio } : {}
8040
8133
  };
8041
8134
  }
8135
+ function parseVideoModelOption(value, tier) {
8136
+ const normalized = normalizeCliOption(value);
8137
+ const effectiveTier = tier ?? "generate";
8138
+ if (!normalized) return getVideoGenerationModelForSelection(DEFAULT_VIDEO_MODEL_SELECTION, effectiveTier);
8139
+ const selection = normalizeVideoModelSelection(normalized);
8140
+ if (selection) return getVideoGenerationModelForSelection(selection, effectiveTier);
8141
+ if (isVideoGenerationModel(normalized)) {
8142
+ const modelTier = normalizeVideoGenerationTier(tier) ?? void 0;
8143
+ if (modelTier && getVideoGenerationModelForTier(modelTier) !== normalized && !isGeminiOmniVideoGenerationModel(normalized)) throw new Error("--model and --tier select different Veo models");
8144
+ return normalized;
8145
+ }
8146
+ throw new Error("--model must be veo-3.1, omni-flash, or an exact video model ID");
8147
+ }
8042
8148
  function parseImageModelOption(value) {
8043
8149
  if (!value) return void 0;
8044
8150
  if (isImageModelSelection(value)) return value;
@@ -8287,22 +8393,24 @@ function printUsage$5() {
8287
8393
  const resolutionValues = Array.from(new Set(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier)))).join("|");
8288
8394
  const durationValues = VIDEO_GENERATION_DURATION_SECONDS.join("|");
8289
8395
  const tierValues = VIDEO_GENERATION_TIERS.join("|");
8396
+ const modelValues = VIDEO_MODEL_SELECTIONS.join("|");
8290
8397
  const resolutionByTier = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
8291
8398
  console.log(`
8292
8399
  Usage:
8293
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8400
+ 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>]
8294
8401
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
8295
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8402
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${modelValues}] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8296
8403
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
8297
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8298
- makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
8404
+ 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>]
8405
+ 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>]
8299
8406
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
8300
8407
 
8301
8408
  Video:
8302
- --aspect <ratio> Veo aspect ratio: ${aspectValues}
8303
- --resolution <value> Veo output resolution (${resolutionByTier})
8304
- --duration <seconds> Veo output duration: ${durationValues}
8305
- --tier <tier> Veo model tier: ${tierValues}
8409
+ --model <value> Video model: ${modelValues}
8410
+ --aspect <ratio> Video aspect ratio: ${aspectValues}
8411
+ --resolution <value> Veo-only output resolution (${resolutionByTier})
8412
+ --duration <seconds> Veo-only output duration: ${durationValues}
8413
+ --tier <tier> Veo-only model tier: ${tierValues}
8306
8414
  --first-frame <ref> Veo start frame image variant or local image path
8307
8415
  --last-frame <ref> Veo final frame image variant or local image path
8308
8416
 
@@ -9256,7 +9364,7 @@ Options:
9256
9364
  }
9257
9365
  //#endregion
9258
9366
  //#region src/cli/index.ts
9259
- var CLI_VERSION = "1.0.1+b273381daffd";
9367
+ var CLI_VERSION = "1.0.3+9dc1e273aed1";
9260
9368
  async function main() {
9261
9369
  const argv = process$1.argv.slice(2);
9262
9370
  if (argv[0] === "--") argv.shift();
@@ -9321,13 +9429,17 @@ function videoDurationValues() {
9321
9429
  function videoTierValues() {
9322
9430
  return optionValues(VIDEO_GENERATION_TIERS);
9323
9431
  }
9432
+ function videoModelValues() {
9433
+ return optionValues(VIDEO_MODEL_SELECTIONS);
9434
+ }
9324
9435
  function videoCapabilityHelp() {
9325
9436
  const resolutionLines = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
9326
9437
  return `Video:
9327
- --aspect <ratio> Veo aspect ratio: ${videoAspectValues()}
9328
- --resolution <value> Veo output resolution (${resolutionLines})
9329
- --duration <seconds> Veo output duration: ${videoDurationValues()}
9330
- --tier <tier> Veo model tier: ${videoTierValues()}
9438
+ --model <value> Video model: ${videoModelValues()}
9439
+ --aspect <ratio> Video aspect ratio: ${videoAspectValues()}
9440
+ --resolution <value> Veo-only output resolution (${resolutionLines})
9441
+ --duration <seconds> Veo-only output duration: ${videoDurationValues()}
9442
+ --tier <tier> Veo-only model tier: ${videoTierValues()}
9331
9443
  --first-frame <ref> Veo start frame image variant or local image path
9332
9444
  --last-frame <ref> Veo final frame image variant or local image path
9333
9445
  --follow <id> Resume/download a variant after a long generation or disconnect
@@ -9727,7 +9839,7 @@ function printVideoHelp(positionals) {
9727
9839
  if (subcommand === "generate") {
9728
9840
  console.log(`
9729
9841
  Usage:
9730
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9842
+ 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] [--space <id>]
9731
9843
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
9732
9844
 
9733
9845
  ${videoCapabilityHelp()}
@@ -9743,7 +9855,7 @@ Long runs:
9743
9855
  if (subcommand === "refine") {
9744
9856
  console.log(`
9745
9857
  Usage:
9746
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9858
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9747
9859
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
9748
9860
 
9749
9861
  ${videoCapabilityHelp()}
@@ -9759,8 +9871,8 @@ Long runs:
9759
9871
  if (subcommand === "derive") {
9760
9872
  console.log(`
9761
9873
  Usage:
9762
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9763
- makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9874
+ 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] [--space <id>]
9875
+ 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] [--space <id>]
9764
9876
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
9765
9877
 
9766
9878
  ${videoCapabilityHelp()}
@@ -9775,11 +9887,11 @@ Long runs:
9775
9887
  }
9776
9888
  console.log(`
9777
9889
  Usage:
9778
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9890
+ 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] [--space <id>]
9779
9891
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
9780
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9781
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9782
- makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9892
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9893
+ 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] [--space <id>]
9894
+ 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] [--space <id>]
9783
9895
 
9784
9896
  ${videoCapabilityHelp()}
9785
9897
 
@@ -9830,6 +9942,9 @@ Usage:
9830
9942
  makefx assets show <asset-id>
9831
9943
  makefx assets show <asset-id> --json
9832
9944
  makefx assets download <variant-id|legacy-image-key> -o output-file
9945
+ makefx assets delete <asset-id>
9946
+ makefx assets rename <asset-id> "<new-name>"
9947
+ makefx assets set-active <asset-id> <variant-id>
9833
9948
  `);
9834
9949
  }
9835
9950
  function printUsageHelp() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makefx",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Command-line interface for AI-assisted game asset production with Make Effects.",
5
5
  "license": "MIT",
6
6
  "type": "module",