makefx 1.0.2 → 1.0.4

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 +260 -76
  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.2
179
+ Version: 1.0.4
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
  }
@@ -5609,33 +5663,6 @@ Examples:
5609
5663
  `);
5610
5664
  }
5611
5665
  //#endregion
5612
- //#region src/cli/lib/error-format.ts
5613
- function formatServerErrorMessage(code, message) {
5614
- return `${code}: ${formatGenerationFailureMessage(message)}`;
5615
- }
5616
- function formatGenerationFailureMessage(message) {
5617
- const rawMessage = message?.trim() || "Generation failed";
5618
- const cleanMessage = extractProviderErrorMessage(rawMessage) ?? rawMessage;
5619
- if (isProviderAuthenticationError(cleanMessage)) return "The generation provider is not configured correctly. Try again later or contact Make Effects support.";
5620
- return cleanMessage;
5621
- }
5622
- function extractProviderErrorMessage(message) {
5623
- const match = message.match(/ApiError:\s*(\{.*\})/s);
5624
- if (!match) return null;
5625
- try {
5626
- const parsed = JSON.parse(match[1]);
5627
- if (typeof parsed.error?.message === "string") return parsed.error.message;
5628
- if (typeof parsed.error?.status === "string") return parsed.error.status;
5629
- } catch {
5630
- return "Provider request failed";
5631
- }
5632
- return "Provider request failed";
5633
- }
5634
- function isProviderAuthenticationError(message) {
5635
- const lower = message.toLowerCase();
5636
- return lower.includes("api key not valid") || lower.includes("api_key_invalid") || lower.includes("invalid api key") || lower.includes("generativelanguage.googleapis.com");
5637
- }
5638
- //#endregion
5639
5666
  //#region src/cli/lib/run-manifest.ts
5640
5667
  function createRunId(date = /* @__PURE__ */ new Date()) {
5641
5668
  return `${date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z")}-${crypto.randomUUID().slice(0, 8)}`;
@@ -6114,7 +6141,7 @@ var WebSocketClient = class WebSocketClient {
6114
6141
  if (variant.status === "completed") batchHandler.completed.push(variant);
6115
6142
  else batchHandler.failed.push({
6116
6143
  variantId: variant.id,
6117
- error: formatGenerationFailureMessage(variant.error_message)
6144
+ error: formatGenerationFailureMessage(variant.error_message, variant.provider_metadata)
6118
6145
  });
6119
6146
  if (batchHandler.pending.size === 0) {
6120
6147
  this.batchHandlers.delete(batchRequestId);
@@ -6142,7 +6169,7 @@ var WebSocketClient = class WebSocketClient {
6142
6169
  jobId: variant.id,
6143
6170
  success: variant.status === "completed",
6144
6171
  variant: variant.status === "completed" ? variant : void 0,
6145
- error: variant.status === "failed" ? formatGenerationFailureMessage(variant.error_message) : void 0
6172
+ error: variant.status === "failed" ? formatGenerationFailureMessage(variant.error_message, variant.provider_metadata) : void 0
6146
6173
  };
6147
6174
  handler.onResult(result);
6148
6175
  }
@@ -6745,6 +6772,8 @@ var VIDEO_GENERATION_TIERS = [
6745
6772
  "fast",
6746
6773
  "lite"
6747
6774
  ];
6775
+ var VIDEO_MODEL_SELECTIONS = ["veo-3.1", "omni-flash"];
6776
+ var GEMINI_OMNI_FLASH_VIDEO_MODEL = "gemini-omni-flash-preview";
6748
6777
  var VIDEO_GENERATION_AUDIO_TOGGLE_MODELS = [];
6749
6778
  var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
6750
6779
  generate: VIDEO_GENERATION_RESOLUTIONS,
@@ -6752,6 +6781,7 @@ var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
6752
6781
  lite: ["720p", "1080p"]
6753
6782
  };
6754
6783
  var DEFAULT_VIDEO_GENERATION_TIER = "generate";
6784
+ var DEFAULT_VIDEO_MODEL_SELECTION = "veo-3.1";
6755
6785
  function normalizeVideoGenerationAspectRatio(value) {
6756
6786
  return VIDEO_GENERATION_ASPECT_RATIOS.includes(value) ? value : void 0;
6757
6787
  }
@@ -6770,24 +6800,43 @@ function normalizeVideoGenerationDurationSeconds(value) {
6770
6800
  function normalizeVideoGenerationTier(value) {
6771
6801
  return VIDEO_GENERATION_TIERS.includes(value) ? value : void 0;
6772
6802
  }
6803
+ function normalizeVideoModelSelection(value) {
6804
+ return VIDEO_MODEL_SELECTIONS.includes(value) ? value : void 0;
6805
+ }
6773
6806
  function getVideoGenerationModelForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
6774
6807
  return VIDEO_GENERATION_TIER_MODELS[tier];
6775
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
+ }
6776
6812
  function getVideoGenerationResolutionsForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
6777
6813
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier];
6778
6814
  }
6779
6815
  function isVideoGenerationResolutionSupportedForTier(resolution, tier = DEFAULT_VIDEO_GENERATION_TIER) {
6780
6816
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].includes(resolution);
6781
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
+ }
6782
6831
  function doesVideoGenerationModelSupportAudioToggle(model) {
6783
- return VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6832
+ return isVeoVideoGenerationModel(model) && VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
6784
6833
  }
6785
6834
  //#endregion
6786
6835
  //#region src/shared/imageGenerationOptions.ts
6787
6836
  var IMAGE_MODEL_SELECTIONS = ["pro", "flash"];
6788
6837
  var IMAGE_MODEL_IDS = {
6789
- pro: "gemini-3-pro-image-preview",
6790
- flash: "gemini-2.5-flash-image"
6838
+ pro: "gemini-3-pro-image",
6839
+ flash: "gemini-3.1-flash-image"
6791
6840
  };
6792
6841
  IMAGE_MODEL_IDS["pro"];
6793
6842
  var IMAGE_ASPECT_RATIOS = [
@@ -6822,8 +6871,12 @@ var IMAGE_MODEL_CAPABILITIES = {
6822
6871
  flash: {
6823
6872
  selection: "flash",
6824
6873
  modelId: IMAGE_MODEL_IDS.flash,
6825
- maxReferenceImages: 1,
6826
- supportedImageSizes: ["1K"],
6874
+ maxReferenceImages: 14,
6875
+ supportedImageSizes: [
6876
+ "1K",
6877
+ "2K",
6878
+ "4K"
6879
+ ],
6827
6880
  supportedAspectRatios: IMAGE_ASPECT_RATIOS
6828
6881
  }
6829
6882
  };
@@ -7182,8 +7235,8 @@ function validateAudioModeRequiredVoiceOptions(options, mode) {
7182
7235
  async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptions = {}) {
7183
7236
  const prompt = getPrompt(parsed, "generate");
7184
7237
  const outputPath = getOutputPath$1(parsed);
7185
- const name = requireOption(parsed, "name");
7186
- const assetType = requireOption(parsed, "type");
7238
+ const name = requireOption$1(parsed, "name");
7239
+ const assetType = requireOption$1(parsed, "type");
7187
7240
  const musicProvider = parseMusicProviderOption(parsed, mediaKind, assetType);
7188
7241
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
7189
7242
  const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
@@ -7199,7 +7252,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
7199
7252
  mediaKind,
7200
7253
  prompt,
7201
7254
  count: 1,
7202
- model: imageOptions.model ?? audioModelOptions.model,
7255
+ model: imageOptions.model ?? audioModelOptions.model ?? videoOptions.model,
7203
7256
  imageSize: imageOptions.imageSize,
7204
7257
  ...musicProvider ? { musicProvider } : {},
7205
7258
  ...videoAudioOptions,
@@ -7278,7 +7331,7 @@ function parseMusicProviderOption(parsed, mediaKind, assetType) {
7278
7331
  async function executeRefine(parsed, ctx, client, deps, mediaKind) {
7279
7332
  const prompt = getPrompt(parsed, "refine");
7280
7333
  const outputPath = getOutputPath$1(parsed);
7281
- const sourceVariantId = requireOption(parsed, "variant");
7334
+ const sourceVariantId = requireOption$1(parsed, "variant");
7282
7335
  const state = await requestSpaceState(client);
7283
7336
  const sourceVariant = state.variants.find((variant) => variant.id === sourceVariantId);
7284
7337
  if (!sourceVariant) throw new Error(`Variant not found in space sync state: ${sourceVariantId}`);
@@ -7294,7 +7347,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
7294
7347
  mediaKind,
7295
7348
  prompt,
7296
7349
  count: 1,
7297
- model: imageOptions.model,
7350
+ model: imageOptions.model ?? videoOptions.model,
7298
7351
  imageSize: imageOptions.imageSize,
7299
7352
  ...videoAudioOptions,
7300
7353
  ...videoOptions
@@ -7347,10 +7400,10 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
7347
7400
  async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions = {}) {
7348
7401
  const prompt = getPrompt(parsed, "derive");
7349
7402
  const outputPath = getOutputPath$1(parsed);
7350
- const name = requireOption(parsed, "name");
7351
- const assetType = requireOption(parsed, "type");
7403
+ const name = requireOption$1(parsed, "name");
7404
+ const assetType = requireOption$1(parsed, "type");
7352
7405
  const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "derive", mediaKind).refs;
7353
- const refs = parsed.options.refs ? parseRefs(requireOption(parsed, "refs")) : [];
7406
+ const refs = parsed.options.refs ? parseRefs(requireOption$1(parsed, "refs")) : [];
7354
7407
  const referenceRefs = videoFrameRefs.length > 0 ? videoFrameRefs : refs;
7355
7408
  if (referenceRefs.length === 0) throw new Error("--refs is required");
7356
7409
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
@@ -7365,7 +7418,7 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
7365
7418
  mediaKind,
7366
7419
  prompt,
7367
7420
  count: 1,
7368
- model: imageOptions.model,
7421
+ model: imageOptions.model ?? videoOptions.model,
7369
7422
  imageSize: imageOptions.imageSize,
7370
7423
  ...videoAudioOptions,
7371
7424
  ...videoOptions
@@ -7528,7 +7581,7 @@ function resultFromTerminalVariant(variant, requestId) {
7528
7581
  requestId,
7529
7582
  jobId: variant.id,
7530
7583
  success: false,
7531
- error: formatGenerationFailureMessage(variant.error_message)
7584
+ error: formatGenerationFailureMessage(variant.error_message, variant.provider_metadata)
7532
7585
  };
7533
7586
  }
7534
7587
  function parseGenerationRecipe(recipeJson) {
@@ -7561,10 +7614,10 @@ function timestampToIso(timestamp) {
7561
7614
  async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManifest) {
7562
7615
  const prompt = getPrompt(parsed, "batch");
7563
7616
  const outputDir = getOutputDir(parsed);
7564
- const name = requireOption(parsed, "name");
7565
- const assetType = requireOption(parsed, "type");
7617
+ const name = requireOption$1(parsed, "name");
7618
+ const assetType = requireOption$1(parsed, "type");
7566
7619
  const musicProvider = parseMusicProviderOption(parsed, mediaKind, assetType);
7567
- const count = parseBatchCount(requireOption(parsed, "count"));
7620
+ const count = parseBatchCount(requireOption$1(parsed, "count"));
7568
7621
  const mode = parseBatchMode(parsed.options.mode || "explore");
7569
7622
  const refs = parsed.options.refs ? parseRefs(parsed.options.refs) : [];
7570
7623
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
@@ -7973,11 +8026,13 @@ function validateVideoAudioOptions(parsed, mediaKind) {
7973
8026
  if (!(parsed.options.audio !== void 0 || parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0)) return;
7974
8027
  if (mediaKind !== "video") throw new Error("--audio and --no-audio are only supported for video generation");
7975
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");
7976
8035
  if (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0) {
7977
- const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
7978
- const videoTier = tierValue === void 0 ? DEFAULT_VIDEO_GENERATION_TIER : normalizeVideoGenerationTier(tierValue);
7979
- if (!videoTier) throw new Error("--tier must be generate, fast, or lite");
7980
- const model = getVideoGenerationModelForTier(videoTier);
7981
8036
  if (!doesVideoGenerationModelSupportAudioToggle(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
7982
8037
  }
7983
8038
  }
@@ -7992,8 +8047,9 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
7992
8047
  const resolutionValue = readOptionalOption(parsed, "resolution", "resolution") ?? readOptionalOption(parsed, "video-resolution", "videoResolution");
7993
8048
  const durationValue = readOptionalOption(parsed, "duration", "duration") ?? readOptionalOption(parsed, "video-duration", "videoDuration");
7994
8049
  const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
8050
+ const modelValue = mediaKind === "video" ? readOptionalOption(parsed, "model", "model") : void 0;
7995
8051
  const aspectValue = mediaKind === "video" ? readOptionalOption(parsed, "aspect", "aspect") : void 0;
7996
- 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 {};
7997
8053
  if (mediaKind !== "video") throw new Error("--resolution, --duration, and --tier are only supported for video generation");
7998
8054
  const videoResolution = resolutionValue === void 0 ? void 0 : normalizeVideoGenerationResolution(resolutionValue);
7999
8055
  if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 720p, 1080p, or 4k");
@@ -8001,10 +8057,13 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
8001
8057
  if (durationValue !== void 0 && !videoDurationSeconds) throw new Error("--duration must be 4, 6, or 8");
8002
8058
  const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
8003
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");
8004
8062
  if (videoResolution && videoTier && !isVideoGenerationResolutionSupportedForTier(videoResolution, videoTier)) throw new Error("--resolution 4k is not supported with --tier lite");
8005
8063
  const aspectRatio = aspectValue === void 0 ? void 0 : normalizeVideoGenerationAspectRatio(aspectValue);
8006
8064
  if (aspectValue !== void 0 && !aspectRatio) throw new Error("--aspect must be 16:9 or 9:16");
8007
8065
  return {
8066
+ model,
8008
8067
  ...aspectRatio ? { aspectRatio } : {},
8009
8068
  ...videoResolution ? { videoResolution } : {},
8010
8069
  ...videoDurationSeconds ? { videoDurationSeconds } : {},
@@ -8025,6 +8084,9 @@ function validateVideoFrameReferenceOptions(command, parsed, mediaKind) {
8025
8084
  if (command !== "generate" && command !== "derive") throw new Error("--first-frame and --last-frame are only supported for video generate and video derive");
8026
8085
  if (lastFrame && !firstFrame) throw new Error("--last-frame requires --first-frame");
8027
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");
8028
8090
  }
8029
8091
  function readVideoFrameOption(parsed, kebabName, camelName) {
8030
8092
  const value = parsed.options[kebabName] ?? parsed.options[camelName];
@@ -8070,6 +8132,19 @@ function parseImageGenerationOptions(parsed, mediaKind) {
8070
8132
  ...aspectRatio ? { aspectRatio } : {}
8071
8133
  };
8072
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
+ }
8073
8148
  function parseImageModelOption(value) {
8074
8149
  if (!value) return void 0;
8075
8150
  if (isImageModelSelection(value)) return value;
@@ -8130,7 +8205,7 @@ function getOutputExtension(variant, mediaKind) {
8130
8205
  function isImageManifestMedia(media) {
8131
8206
  return media.mediaKind === "image" && Boolean(media.imageKey);
8132
8207
  }
8133
- function requireOption(parsed, name) {
8208
+ function requireOption$1(parsed, name) {
8134
8209
  const value = parsed.options[name];
8135
8210
  if (!value || value === "true") throw new Error(`--${name} is required`);
8136
8211
  return value;
@@ -8318,22 +8393,24 @@ function printUsage$5() {
8318
8393
  const resolutionValues = Array.from(new Set(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier)))).join("|");
8319
8394
  const durationValues = VIDEO_GENERATION_DURATION_SECONDS.join("|");
8320
8395
  const tierValues = VIDEO_GENERATION_TIERS.join("|");
8396
+ const modelValues = VIDEO_MODEL_SELECTIONS.join("|");
8321
8397
  const resolutionByTier = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
8322
8398
  console.log(`
8323
8399
  Usage:
8324
- 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>]
8325
8401
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
8326
- 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>]
8327
8403
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
8328
- 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>]
8329
- 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>]
8330
8406
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
8331
8407
 
8332
8408
  Video:
8333
- --aspect <ratio> Veo aspect ratio: ${aspectValues}
8334
- --resolution <value> Veo output resolution (${resolutionByTier})
8335
- --duration <seconds> Veo output duration: ${durationValues}
8336
- --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}
8337
8414
  --first-frame <ref> Veo start frame image variant or local image path
8338
8415
  --last-frame <ref> Veo final frame image variant or local image path
8339
8416
 
@@ -8574,8 +8651,10 @@ async function handleAssets(parsed) {
8574
8651
  }
8575
8652
  }
8576
8653
  async function executeAssets(parsed, deps = defaultDeps$3) {
8577
- const ctx = await buildContext$3(parsed, deps);
8578
8654
  const subcommand = parsed.positionals[0] || "list";
8655
+ if (subcommand === "search") return searchAssets(parsed, deps);
8656
+ if (subcommand === "clone") return cloneAsset(parsed, deps);
8657
+ const ctx = await buildContext$3(parsed, deps);
8579
8658
  if (subcommand === "list") {
8580
8659
  const assets = await listAssets(ctx, deps);
8581
8660
  if (parsed.options.json === "true") deps.print(JSON.stringify(assets.map(toAssetJson), null, 2));
@@ -8677,6 +8756,85 @@ async function buildContext$3(parsed, deps) {
8677
8756
  projectRoot: projectConfig?.projectRoot
8678
8757
  };
8679
8758
  }
8759
+ async function buildAuthContext(parsed, deps) {
8760
+ const env = resolveCommandEnvironment(parsed, await deps.loadProjectConfig());
8761
+ const config = await deps.loadConfig(env);
8762
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
8763
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
8764
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
8765
+ return {
8766
+ env,
8767
+ baseUrl: deps.resolveBaseUrl(env),
8768
+ accessToken: config.token.accessToken
8769
+ };
8770
+ }
8771
+ function requireOption(parsed, names, usage) {
8772
+ for (const name of names) {
8773
+ const value = normalizeOption(parsed.options[name]);
8774
+ if (value) return value;
8775
+ }
8776
+ throw new Error(usage);
8777
+ }
8778
+ async function searchAssets(parsed, deps) {
8779
+ const ctx = await buildAuthContext(parsed, deps);
8780
+ const query = parsed.positionals.slice(1).join(" ").trim();
8781
+ const params = new URLSearchParams();
8782
+ if (query) params.set("q", query);
8783
+ const mediaKind = normalizeOption(parsed.options.media) ?? normalizeOption(parsed.options["media-kind"]);
8784
+ const assetType = normalizeOption(parsed.options.type);
8785
+ const limit = normalizeOption(parsed.options.limit);
8786
+ if (mediaKind) params.set("media_kind", mediaKind);
8787
+ if (assetType) params.set("type", assetType);
8788
+ if (limit) params.set("limit", limit);
8789
+ const response = await deps.fetch(`${ctx.baseUrl}/api/assets/search?${params.toString()}`, { headers: { Authorization: `Bearer ${ctx.accessToken}` } });
8790
+ if (!response.ok) throw new Error(`Search failed: ${response.status} - ${await response.text()}`);
8791
+ const results = (await response.json()).results ?? [];
8792
+ if (parsed.options.json === "true") deps.print(JSON.stringify(results, null, 2));
8793
+ else printAssetSearchResults(results, deps.print);
8794
+ return {
8795
+ type: "search",
8796
+ results
8797
+ };
8798
+ }
8799
+ async function cloneAsset(parsed, deps) {
8800
+ const ctx = await buildAuthContext(parsed, deps);
8801
+ const sourceVariantId = parsed.positionals[1] ?? normalizeOption(parsed.options.variant);
8802
+ if (!sourceVariantId) throw new Error("Usage: makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>");
8803
+ const sourceSpaceId = requireOption(parsed, ["from-space", "source-space"], "Usage: makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>");
8804
+ const targetSpaceId = requireOption(parsed, ["to-space", "target-space"], "Usage: makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>");
8805
+ const body = {
8806
+ sourceSpaceId,
8807
+ sourceVariantId
8808
+ };
8809
+ const name = normalizeOption(parsed.options.name);
8810
+ const type = normalizeOption(parsed.options.type);
8811
+ if (name) body.name = name;
8812
+ if (type) body.type = type;
8813
+ const response = await deps.fetch(`${ctx.baseUrl}/api/spaces/${encodeURIComponent(targetSpaceId)}/assets/clone`, {
8814
+ method: "POST",
8815
+ headers: {
8816
+ Authorization: `Bearer ${ctx.accessToken}`,
8817
+ "Content-Type": "application/json"
8818
+ },
8819
+ body: JSON.stringify(body)
8820
+ });
8821
+ if (!response.ok) throw new Error(`Clone failed: ${response.status} - ${await response.text()}`);
8822
+ const payload = await response.json();
8823
+ if (parsed.options.json === "true") deps.print(JSON.stringify(payload, null, 2));
8824
+ else {
8825
+ const asset = payload.asset;
8826
+ const variantPayload = payload.variant;
8827
+ const variant = variantPayload?.variant ?? variantPayload;
8828
+ deps.print(`Cloned variant ${sourceVariantId} into space ${targetSpaceId}`);
8829
+ if (asset?.id) deps.print(` Asset: ${asset.id}${asset.name ? ` (${asset.name})` : ""}`);
8830
+ if (variant?.id) deps.print(` Variant: ${variant.id}`);
8831
+ }
8832
+ return {
8833
+ type: "clone",
8834
+ asset: payload.asset,
8835
+ variant: payload.variant
8836
+ };
8837
+ }
8680
8838
  async function recordDownloadedMirror(input) {
8681
8839
  const variant = input.variant;
8682
8840
  if (!variant || !input.deps.recordMirrorForFile) return;
@@ -8782,6 +8940,19 @@ function printAssetList(assets, print) {
8782
8940
  print("-".repeat(113));
8783
8941
  for (const asset of assets) print(formatTimestamp(asset.updated_at).padEnd(21) + truncate(asset.type || "unknown", 12).padEnd(14) + truncate(asset.media_kind || "-", 7).padEnd(9) + truncate(asset.active_variant_id || "-", 24).padEnd(26) + truncate(asset.id, 26).padEnd(28) + truncate(asset.name, 32));
8784
8942
  }
8943
+ function printAssetSearchResults(results, print) {
8944
+ if (results.length === 0) {
8945
+ print("No matching assets found.");
8946
+ return;
8947
+ }
8948
+ for (const result of results) {
8949
+ print(`${result.assetName} (${result.assetId})`);
8950
+ print(` Space: ${result.spaceName} (${result.spaceId})`);
8951
+ print(` Type: ${result.assetType ?? "-"} Media: ${result.mediaKind}`);
8952
+ print(` Active: ${result.activeVariantId ?? "-"}${result.activeVariantStatus ? ` (${result.activeVariantStatus})` : ""}`);
8953
+ print(` Counts: variants=${result.variantCount} completed=${result.completedVariantCount} starred=${result.starredVariantCount}`);
8954
+ }
8955
+ }
8785
8956
  function printAssetDetails(details, ctx, print) {
8786
8957
  const { asset, variants, lineage } = details;
8787
8958
  print(`\nAsset ${asset.id}\n`);
@@ -8873,9 +9044,11 @@ function printUsage$2() {
8873
9044
  Usage:
8874
9045
  makefx assets
8875
9046
  makefx assets --json
9047
+ makefx assets search "query" [--media image|audio|video] [--type <type>] [--json]
8876
9048
  makefx assets show <asset-id>
8877
9049
  makefx assets show <asset-id> --json
8878
9050
  makefx assets download <variant-id|legacy-image-key> -o output-file
9051
+ makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>
8879
9052
  makefx assets delete <asset-id>
8880
9053
  makefx assets rename <asset-id> "<new-name>"
8881
9054
  makefx assets set-active <asset-id> <variant-id>
@@ -9287,7 +9460,7 @@ Options:
9287
9460
  }
9288
9461
  //#endregion
9289
9462
  //#region src/cli/index.ts
9290
- var CLI_VERSION = "1.0.2+ce1ff2c1182d";
9463
+ var CLI_VERSION = "1.0.4+20bbdda462d5";
9291
9464
  async function main() {
9292
9465
  const argv = process$1.argv.slice(2);
9293
9466
  if (argv[0] === "--") argv.shift();
@@ -9352,13 +9525,17 @@ function videoDurationValues() {
9352
9525
  function videoTierValues() {
9353
9526
  return optionValues(VIDEO_GENERATION_TIERS);
9354
9527
  }
9528
+ function videoModelValues() {
9529
+ return optionValues(VIDEO_MODEL_SELECTIONS);
9530
+ }
9355
9531
  function videoCapabilityHelp() {
9356
9532
  const resolutionLines = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
9357
9533
  return `Video:
9358
- --aspect <ratio> Veo aspect ratio: ${videoAspectValues()}
9359
- --resolution <value> Veo output resolution (${resolutionLines})
9360
- --duration <seconds> Veo output duration: ${videoDurationValues()}
9361
- --tier <tier> Veo model tier: ${videoTierValues()}
9534
+ --model <value> Video model: ${videoModelValues()}
9535
+ --aspect <ratio> Video aspect ratio: ${videoAspectValues()}
9536
+ --resolution <value> Veo-only output resolution (${resolutionLines})
9537
+ --duration <seconds> Veo-only output duration: ${videoDurationValues()}
9538
+ --tier <tier> Veo-only model tier: ${videoTierValues()}
9362
9539
  --first-frame <ref> Veo start frame image variant or local image path
9363
9540
  --last-frame <ref> Veo final frame image variant or local image path
9364
9541
  --follow <id> Resume/download a variant after a long generation or disconnect
@@ -9470,8 +9647,10 @@ Continue:
9470
9647
 
9471
9648
  Inspect:
9472
9649
  assets List assets
9650
+ assets search "query" Search assets across Spaces
9473
9651
  assets show <asset-id> Show variants and lineage
9474
9652
  assets download <variant-id> -o <file> Download variant media
9653
+ assets clone <variant-id> --from-space <id> --to-space <id>
9475
9654
  variants rate <variant-id> approved|rejected
9476
9655
  variants star <variant-id>
9477
9656
 
@@ -9758,7 +9937,7 @@ function printVideoHelp(positionals) {
9758
9937
  if (subcommand === "generate") {
9759
9938
  console.log(`
9760
9939
  Usage:
9761
- 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>]
9940
+ 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>]
9762
9941
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
9763
9942
 
9764
9943
  ${videoCapabilityHelp()}
@@ -9774,7 +9953,7 @@ Long runs:
9774
9953
  if (subcommand === "refine") {
9775
9954
  console.log(`
9776
9955
  Usage:
9777
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9956
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9778
9957
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
9779
9958
 
9780
9959
  ${videoCapabilityHelp()}
@@ -9790,8 +9969,8 @@ Long runs:
9790
9969
  if (subcommand === "derive") {
9791
9970
  console.log(`
9792
9971
  Usage:
9793
- 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>]
9794
- 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>]
9972
+ 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>]
9973
+ 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>]
9795
9974
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
9796
9975
 
9797
9976
  ${videoCapabilityHelp()}
@@ -9806,11 +9985,11 @@ Long runs:
9806
9985
  }
9807
9986
  console.log(`
9808
9987
  Usage:
9809
- 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>]
9988
+ 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>]
9810
9989
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
9811
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9812
- 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>]
9813
- 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>]
9990
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
9991
+ 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>]
9992
+ 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>]
9814
9993
 
9815
9994
  ${videoCapabilityHelp()}
9816
9995
 
@@ -9858,9 +10037,14 @@ function printAssetsHelp() {
9858
10037
  Usage:
9859
10038
  makefx assets
9860
10039
  makefx assets --json
10040
+ makefx assets search "query" [--media image|audio|video] [--type <type>] [--json]
9861
10041
  makefx assets show <asset-id>
9862
10042
  makefx assets show <asset-id> --json
9863
10043
  makefx assets download <variant-id|legacy-image-key> -o output-file
10044
+ makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>
10045
+ makefx assets delete <asset-id>
10046
+ makefx assets rename <asset-id> "<new-name>"
10047
+ makefx assets set-active <asset-id> <variant-id>
9864
10048
  `);
9865
10049
  }
9866
10050
  function printUsageHelp() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makefx",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Command-line interface for AI-assisted game asset production with Make Effects.",
5
5
  "license": "MIT",
6
6
  "type": "module",