makefx 1.6.9 → 1.6.11

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 +400 -104
  3. package/package.json +11 -2
package/README.md CHANGED
@@ -61,4 +61,4 @@ IDs, or runs. Retired commands and aliases are not redirected.
61
61
 
62
62
  Run `makefx --help` or `makefx <noun> --help` for current options.
63
63
 
64
- Version: 1.6.9
64
+ Version: 1.6.11
package/makefx.mjs CHANGED
@@ -291,6 +291,16 @@ function resolveMediaType(ext, requestedMediaKind) {
291
291
  return mediaType;
292
292
  }
293
293
  //#endregion
294
+ //#region src/cli/version.ts
295
+ var CLI_VERSION = "1.6.11+23d6e4fbd1a7";
296
+ var CLI_VERSION_HEADER = "X-MakeFX-CLI-Version";
297
+ function cliVersionHeaders() {
298
+ return {
299
+ [CLI_VERSION_HEADER]: CLI_VERSION,
300
+ "User-Agent": `makefx/${CLI_VERSION}`
301
+ };
302
+ }
303
+ //#endregion
294
304
  //#region src/cli/lib/image-transfer.ts
295
305
  function looksLikeFilePath(value) {
296
306
  let supportedMediaExtension = false;
@@ -316,7 +326,10 @@ async function uploadLocalMediaAsReference(input) {
316
326
  formData.append("mediaKind", mediaType.mediaKind);
317
327
  const response = await fetch(`${input.baseUrl}/api/spaces/${input.spaceId}/upload`, {
318
328
  method: "POST",
319
- headers: { "Authorization": `Bearer ${input.accessToken}` },
329
+ headers: {
330
+ "Authorization": `Bearer ${input.accessToken}`,
331
+ ...cliVersionHeaders()
332
+ },
320
333
  body: formData
321
334
  });
322
335
  const data = await readJsonResponse(response, "Reference upload request");
@@ -4459,16 +4472,6 @@ var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
4459
4472
  require_websocket_server();
4460
4473
  var wrapper_default = import_websocket.default;
4461
4474
  //#endregion
4462
- //#region src/cli/version.ts
4463
- var CLI_VERSION = "1.6.9+4949b061ecf5";
4464
- var CLI_VERSION_HEADER = "X-MakeFX-CLI-Version";
4465
- function cliVersionHeaders() {
4466
- return {
4467
- [CLI_VERSION_HEADER]: CLI_VERSION,
4468
- "User-Agent": `makefx/${CLI_VERSION}`
4469
- };
4470
- }
4471
- //#endregion
4472
4475
  //#region src/cli/lib/websocket-client.ts
4473
4476
  /**
4474
4477
  * WebSocket Client for CLI
@@ -4738,7 +4741,6 @@ var WebSocketClient = class WebSocketClient {
4738
4741
  this.onSyncState?.({
4739
4742
  assets: syncMsg.assets,
4740
4743
  variants: syncMsg.variants,
4741
- lineage: syncMsg.lineage,
4742
4744
  collections: syncMsg.collections,
4743
4745
  collectionItems: syncMsg.collectionItems,
4744
4746
  canvasSettings: syncMsg.canvasSettings,
@@ -5807,7 +5809,7 @@ function printAssetSearchResults(results, print) {
5807
5809
  }
5808
5810
  }
5809
5811
  function printAssetDetails(details, ctx, print) {
5810
- const { asset, variants, lineage } = details;
5812
+ const { asset, variants, recipe_references: recipeReferences } = details;
5811
5813
  print(`\nAsset ${createAssetRef(asset.name, asset.id)}\n`);
5812
5814
  print(` Name: ${asset.name}`);
5813
5815
  print(` Type: ${asset.type || "unknown"}`);
@@ -5822,17 +5824,24 @@ function printAssetDetails(details, ctx, print) {
5822
5824
  print(` Status: ${variant.status}`);
5823
5825
  print(` Media: ${variant.media_kind || "-"}`);
5824
5826
  if (variant.media_mime_type) print(` MIME: ${variant.media_mime_type}`);
5825
- const provenance = formatMetadataSummary(variant.generation_provenance, [
5826
- "operation",
5827
- "assetType",
5828
- "mediaKind",
5829
- "model",
5830
- "prompt"
5831
- ]);
5832
- if (provenance) print(` Provenance: ${provenance}`);
5827
+ const detail = recipeReferences.variants.find((candidate) => candidate.variant_id === variant.id);
5828
+ if (detail) {
5829
+ print(` Recipe: ${detail.recipe_state.status}; ${detail.recipe_state.replayability.replace("_", " ")}`);
5830
+ const generator = detail.recipe?.generator;
5831
+ const execution = detail.recipe?.execution;
5832
+ const parameters = generator?.parameters;
5833
+ if (generator?.id) print(` Generator: ${String(generator.id)}`);
5834
+ if (execution?.provider) print(` Provider: ${String(execution.provider)}`);
5835
+ if (execution?.model) print(` Model: ${String(execution.model)}`);
5836
+ if (parameters?.prompt !== void 0) print(` Prompt: ${String(parameters.prompt)}`);
5837
+ if (detail.made_from.length > 0) for (const reference of detail.made_from) print(` Reference[${reference.sequence_index}] ${reference.slot}: ${formatRecipeReferenceTarget(reference)}`);
5838
+ print(` Views: made_from=${detail.made_from.length} used_by=${detail.used_by_total}${detail.used_by_truncated ? "+" : ""}`);
5839
+ }
5833
5840
  }
5834
5841
  }
5835
- if (lineage.length > 0) print(`\nLineage links: ${lineage.length}`);
5842
+ }
5843
+ function formatRecipeReferenceTarget(target) {
5844
+ return target.available && target.asset_id && target.asset_name ? createVariantRef(target.asset_name, target.asset_id, target.variant_id) : `unresolved:${target.variant_id}`;
5836
5845
  }
5837
5846
  function toAssetJson(asset) {
5838
5847
  return {
@@ -5858,29 +5867,41 @@ function toAssetDetailsJson(details) {
5858
5867
  createdAt: variant.created_at || null,
5859
5868
  updatedAt: variant.updated_at || null
5860
5869
  })),
5861
- lineageCount: details.lineage.length
5870
+ recipeReferences: details.recipe_references.variants.map((detail) => ({
5871
+ variantRef: createVariantRef(details.asset.name, details.asset.id, detail.variant_id),
5872
+ recipe: publicCliRecipe(detail.recipe),
5873
+ recipeState: {
5874
+ status: detail.recipe_state.status,
5875
+ replayability: detail.recipe_state.replayability,
5876
+ issues: detail.recipe_state.issues,
5877
+ replayabilityIssues: detail.recipe_state.replayability_issues
5878
+ },
5879
+ references: detail.made_from.map((reference) => ({
5880
+ variantRef: reference.available && reference.asset_id && reference.asset_name ? createVariantRef(reference.asset_name, reference.asset_id, reference.variant_id) : null,
5881
+ ...!reference.available ? { historicalVariantId: reference.variant_id } : {},
5882
+ slot: reference.slot,
5883
+ sequenceIndex: reference.sequence_index,
5884
+ modalityIndex: reference.modality_index,
5885
+ mediaKind: reference.media_kind,
5886
+ mimeType: reference.mime_type,
5887
+ sizeBytes: reference.size_bytes,
5888
+ width: reference.width,
5889
+ height: reference.height,
5890
+ durationMs: reference.duration_ms
5891
+ })),
5892
+ madeFrom: detail.made_from.map(formatRecipeReferenceTarget),
5893
+ usedBy: detail.used_by.map(formatRecipeReferenceTarget),
5894
+ usedByTotal: detail.used_by_total,
5895
+ usedByTruncated: detail.used_by_truncated
5896
+ })),
5897
+ totalVariantCount: details.recipe_references.total_variant_count,
5898
+ truncated: details.recipe_references.truncated
5862
5899
  };
5863
5900
  }
5864
- function formatMetadataSummary(value, preferredKeys) {
5865
- if (!value) return null;
5866
- const parsed = parseJsonObject(value);
5867
- if (!parsed) return truncate(value, 120);
5868
- const parts = [];
5869
- for (const key of preferredKeys) {
5870
- const field = parsed[key];
5871
- if (field === void 0 || field === null || typeof field === "object") continue;
5872
- parts.push(`${key}=${String(field)}`);
5873
- }
5874
- return parts.length > 0 ? truncate(parts.join(" "), 160) : truncate(JSON.stringify(parsed), 160);
5875
- }
5876
- function parseJsonObject(value) {
5877
- try {
5878
- const parsed = JSON.parse(value);
5879
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
5880
- } catch {
5881
- return null;
5882
- }
5883
- return null;
5901
+ function publicCliRecipe(recipe) {
5902
+ if (!recipe) return null;
5903
+ const { references: _references, regeneration: _regeneration, copiedFromVariantId: _copiedFromVariantId, ...publicRecipe } = recipe;
5904
+ return publicRecipe;
5884
5905
  }
5885
5906
  function formatTimestamp(value) {
5886
5907
  if (!value) return "-";
@@ -9345,6 +9366,17 @@ async function executeSpaceLens(parsed, deps = defaultDeps$8) {
9345
9366
  return result;
9346
9367
  }
9347
9368
  IMAGE_MODEL_SELECTIONS.map((selection) => `image/${selection}`);
9369
+ function referenceSlot(slot, mediaKind, minCount, maxCount, providerPosition, requiredMetadata = []) {
9370
+ return {
9371
+ slot,
9372
+ mediaKinds: [mediaKind],
9373
+ minCount,
9374
+ maxCount,
9375
+ providerPosition,
9376
+ ordering: "preserve_occurrence_order",
9377
+ ...requiredMetadata.length ? { requiredMetadata } : {}
9378
+ };
9379
+ }
9348
9380
  function input(name, type, required, description, options = {}) {
9349
9381
  return {
9350
9382
  name,
@@ -9389,7 +9421,12 @@ function imageGenerator(capability) {
9389
9421
  operation: "generate",
9390
9422
  tool: "generate_image",
9391
9423
  description: "Create a new image asset from text.",
9392
- inputs: generateInputs
9424
+ inputs: generateInputs,
9425
+ referenceSlots: [],
9426
+ referenceCardinality: {
9427
+ minCount: 0,
9428
+ maxCount: 0
9429
+ }
9393
9430
  }];
9394
9431
  if (capability.supportedOperations.includes("derive")) operations.push({
9395
9432
  operation: "derive",
@@ -9398,7 +9435,12 @@ function imageGenerator(capability) {
9398
9435
  inputs: [...generateInputs, {
9399
9436
  ...referenceInput,
9400
9437
  required: true
9401
- }]
9438
+ }],
9439
+ referenceSlots: [referenceSlot("reference_variant_refs", "image", 1, capability.maxReferenceImages, 0)],
9440
+ referenceCardinality: {
9441
+ minCount: 1,
9442
+ maxCount: capability.maxReferenceImages
9443
+ }
9402
9444
  });
9403
9445
  if (capability.supportedOperations.includes("refine")) operations.push({
9404
9446
  operation: "refine",
@@ -9427,7 +9469,12 @@ function imageGenerator(capability) {
9427
9469
  defaultValue: "medium"
9428
9470
  })] : [],
9429
9471
  ...capability.supportsSeed ? [input("seed", "integer", false, "Optional reproducible generation seed.")] : []
9430
- ]
9472
+ ],
9473
+ referenceSlots: [referenceSlot("source_variant_ref", "image", 1, 1, 0), referenceSlot("reference_variant_refs", "image", 0, Math.max(0, capability.maxReferenceImages - 1), 1)],
9474
+ referenceCardinality: {
9475
+ minCount: 1,
9476
+ maxCount: capability.maxReferenceImages
9477
+ }
9431
9478
  });
9432
9479
  return {
9433
9480
  id: `image/${capability.selection}`,
@@ -9444,6 +9491,72 @@ function imageGenerator(capability) {
9444
9491
  notes: capability.maxReferenceImages > 0 ? ["Use compact variant references; binary image input is not accepted."] : ["Text-to-image only; reference inputs are not supported."]
9445
9492
  };
9446
9493
  }
9494
+ function customImageGenerator(modelId) {
9495
+ const common = [
9496
+ SPACE_INPUT,
9497
+ fixedInput("generator_id", "image/custom", "Selects the configured custom image generator."),
9498
+ NAME_INPUT,
9499
+ input("asset_type", "string", true, "Asset classification stored in the Space."),
9500
+ PROMPT_INPUT,
9501
+ input("aspect_ratio", "string", false, "Output aspect ratio."),
9502
+ input("image_size", "string", false, "Output image size.")
9503
+ ];
9504
+ const referenceInput = input("reference_variant_refs", "string_array", false, "Ordered image references.", {
9505
+ minItems: 1,
9506
+ maxItems: 14
9507
+ });
9508
+ return {
9509
+ id: "image/custom",
9510
+ label: "Custom image",
9511
+ mediaKind: "image",
9512
+ modelIds: [modelId],
9513
+ defaultModelId: modelId,
9514
+ operations: [
9515
+ {
9516
+ operation: "generate",
9517
+ tool: "generate_image",
9518
+ description: "Generate with the configured custom model.",
9519
+ inputs: common,
9520
+ referenceSlots: [],
9521
+ referenceCardinality: {
9522
+ minCount: 0,
9523
+ maxCount: 0
9524
+ }
9525
+ },
9526
+ {
9527
+ operation: "derive",
9528
+ tool: "generate_image",
9529
+ description: "Generate with ordered image references.",
9530
+ inputs: [...common, {
9531
+ ...referenceInput,
9532
+ required: true
9533
+ }],
9534
+ referenceSlots: [referenceSlot("reference_variant_refs", "image", 1, 14, 0)],
9535
+ referenceCardinality: {
9536
+ minCount: 1,
9537
+ maxCount: 14
9538
+ }
9539
+ },
9540
+ {
9541
+ operation: "refine",
9542
+ tool: "edit_image",
9543
+ description: "Edit a source image.",
9544
+ inputs: [...common, input("source_variant_ref", "string", true, "Source image.")],
9545
+ referenceSlots: [referenceSlot("source_variant_ref", "image", 1, 1, 0)],
9546
+ referenceCardinality: {
9547
+ minCount: 1,
9548
+ maxCount: 1
9549
+ }
9550
+ }
9551
+ ],
9552
+ referenceRules: {
9553
+ mediaKind: "image",
9554
+ completedOnly: true,
9555
+ maxCount: 14
9556
+ },
9557
+ notes: ["The configured custom endpoint owns model-specific parameter support."]
9558
+ };
9559
+ }
9447
9560
  function videoGenerator(selection) {
9448
9561
  const defaultModel = getVideoGenerationModelForSelection(selection);
9449
9562
  const isVeo = selection === "veo-3.1";
@@ -9467,7 +9580,7 @@ function videoGenerator(selection) {
9467
9580
  allowedValues: VIDEO_GENERATION_TIERS,
9468
9581
  defaultValue: DEFAULT_VIDEO_GENERATION_TIER
9469
9582
  }));
9470
- if (isKling) parameterInputs.push(input("generate_audio", "boolean", false, "Generate synchronized audio.", {
9583
+ if (isKling || isVeo) parameterInputs.push(input("generate_audio", "boolean", false, "Generate synchronized audio.", {
9471
9584
  allowedValues: [true, false],
9472
9585
  defaultValue: true
9473
9586
  }));
@@ -9483,7 +9596,12 @@ function videoGenerator(selection) {
9483
9596
  operation: "generate",
9484
9597
  tool: "generate_video",
9485
9598
  description: "Create a new video asset from text.",
9486
- inputs: commonInputs
9599
+ inputs: commonInputs,
9600
+ referenceSlots: [],
9601
+ referenceCardinality: {
9602
+ minCount: 0,
9603
+ maxCount: 0
9604
+ }
9487
9605
  }];
9488
9606
  if (VIDEO_MODEL_SUPPORTED_OPERATIONS[selection].includes("refine")) operations.push({
9489
9607
  operation: "refine",
@@ -9496,7 +9614,12 @@ function videoGenerator(selection) {
9496
9614
  input("source_variant_ref", "string", true, "Completed video variant to refine."),
9497
9615
  PROMPT_INPUT,
9498
9616
  ...parameterInputs
9499
- ]
9617
+ ],
9618
+ referenceSlots: [referenceSlot("source_variant_ref", "video", 1, 1, 0)],
9619
+ referenceCardinality: {
9620
+ minCount: 1,
9621
+ maxCount: 1
9622
+ }
9500
9623
  });
9501
9624
  if (VIDEO_MODEL_SUPPORTED_OPERATIONS[selection].includes("derive")) operations.push({
9502
9625
  operation: "derive",
@@ -9505,9 +9628,14 @@ function videoGenerator(selection) {
9505
9628
  inputs: [...commonInputs, input("reference_variant_refs", "string_array", true, "Completed image variant references from find_assets or get_asset.", {
9506
9629
  minItems: 1,
9507
9630
  maxItems: maxReferences
9508
- })]
9631
+ })],
9632
+ referenceSlots: [referenceSlot("reference_variant_refs", "image", 1, maxReferences, 0)],
9633
+ referenceCardinality: {
9634
+ minCount: 1,
9635
+ maxCount: maxReferences
9636
+ }
9509
9637
  });
9510
- const notes = isVeo ? [`Resolution support by tier: ${VIDEO_GENERATION_TIERS.map((tier) => `${tier}=${VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].join("/")}`).join(", ")}.`, "Synchronized audio is always enabled."] : isOmni ? ["Resolution, duration, tier, and generated-audio options are not accepted."] : selection === "fal-seedance" ? ["Text-to-video only; generated audio is not supported."] : ["At most one completed image reference is accepted."];
9638
+ const notes = isVeo ? [`Resolution support by tier: ${VIDEO_GENERATION_TIERS.map((tier) => `${tier}=${VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].join("/")}`).join(", ")}.`] : isOmni ? ["Resolution, duration, tier, and generated-audio options are not accepted."] : selection === "fal-seedance" ? ["Text-to-video only; generated audio is not supported."] : ["At most one completed image reference is accepted."];
9511
9639
  return {
9512
9640
  id: `video/${selection}`,
9513
9641
  label: VIDEO_MODEL_LABELS[selection],
@@ -9579,7 +9707,22 @@ function seedanceVideoGenerator(capability) {
9579
9707
  operation,
9580
9708
  tool: "generate_video",
9581
9709
  description: capability.mode === "text" ? "Create a video from text." : capability.mode === "frame" ? "Animate a required authoritative start frame and optional authoritative end frame; extended references cannot be combined with them." : "Direct a video with ordered image, video, and audio references; these guide generation but cannot serve as authoritative start/end frames.",
9582
- inputs: [...common, ...modeInputs]
9710
+ inputs: [...common, ...modeInputs],
9711
+ referenceSlots: capability.mode === "frame" ? [referenceSlot("start_frame_variant_ref", "image", 1, 1, 0), referenceSlot("end_frame_variant_ref", "image", 0, 1, 1)] : capability.mode === "reference" ? [
9712
+ referenceSlot("image_reference_variant_refs", "image", 0, referenceMax("image"), 0, ["mimeType", "sizeBytes"]),
9713
+ referenceSlot("video_reference_variant_refs", "video", 0, referenceMax("video"), 1, ["mimeType", "sizeBytes"]),
9714
+ referenceSlot("audio_reference_variant_refs", "audio", 0, referenceMax("audio"), 2, ["mimeType", "sizeBytes"])
9715
+ ] : [],
9716
+ referenceCardinality: capability.mode === "text" ? {
9717
+ minCount: 0,
9718
+ maxCount: 0
9719
+ } : capability.mode === "frame" ? {
9720
+ minCount: 1,
9721
+ maxCount: 2
9722
+ } : {
9723
+ minCount: operation === "derive" ? 1 : 0,
9724
+ maxCount: capability.maxReferenceFiles
9725
+ }
9583
9726
  }));
9584
9727
  if (capability.operations.includes("refine")) {
9585
9728
  const budget = getSeedance2ReferenceBudget(capability, "refine");
@@ -9605,7 +9748,17 @@ function seedanceVideoGenerator(capability) {
9605
9748
  PROMPT_INPUT,
9606
9749
  ...parameters,
9607
9750
  ...editReferenceInputs
9608
- ]
9751
+ ],
9752
+ referenceSlots: [
9753
+ referenceSlot("source_variant_ref", "video", 1, 1, 0, ["mimeType", "sizeBytes"]),
9754
+ referenceSlot("image_reference_variant_refs", "image", 0, budget.maxAdditionalByKind.image, 1, ["mimeType", "sizeBytes"]),
9755
+ referenceSlot("video_reference_variant_refs", "video", 0, budget.maxAdditionalByKind.video, 2, ["mimeType", "sizeBytes"]),
9756
+ referenceSlot("audio_reference_variant_refs", "audio", 0, budget.maxAdditionalByKind.audio, 3, ["mimeType", "sizeBytes"])
9757
+ ],
9758
+ referenceCardinality: {
9759
+ minCount: 1,
9760
+ maxCount: capability.maxReferenceFiles
9761
+ }
9609
9762
  });
9610
9763
  }
9611
9764
  return {
@@ -9628,8 +9781,7 @@ function seedanceVideoGenerator(capability) {
9628
9781
  promptLabel: reference.promptLabel,
9629
9782
  acceptedMimeTypes: reference.acceptedMimeTypes,
9630
9783
  maxBytesPerFile: reference.maxBytesPerFile,
9631
- ...reference.combinedMaxBytes !== void 0 ? { combinedMaxBytes: reference.combinedMaxBytes } : {},
9632
- ...reference.combinedDurationSeconds ? { combinedDurationSeconds: reference.combinedDurationSeconds } : {}
9784
+ ...reference.combinedMaxBytes !== void 0 ? { combinedMaxBytes: reference.combinedMaxBytes } : {}
9633
9785
  }))
9634
9786
  },
9635
9787
  notes: [
@@ -9700,7 +9852,30 @@ function wan3VideoGenerator(capability) {
9700
9852
  operation: capability.mode === "text" ? "generate" : "derive",
9701
9853
  tool: "generate_video",
9702
9854
  description: capability.mode === "text" ? "Create a native-audio video from text." : capability.mode === "frame" ? "Animate a start frame and optional end frame." : "Direct one video from up to 20 ordered image, video, and audio references.",
9703
- inputs: [...common, ...modeInputs]
9855
+ inputs: [...common, ...modeInputs],
9856
+ referenceSlots: capability.mode === "frame" ? [referenceSlot("start_frame_variant_ref", "image", 1, 1, 0), referenceSlot("end_frame_variant_ref", "image", 0, 1, 1)] : capability.mode === "reference" ? [
9857
+ referenceSlot("image_reference_variant_refs", "image", 0, max("image"), 0, ["mimeType", "sizeBytes"]),
9858
+ referenceSlot("video_reference_variant_refs", "video", 0, max("video"), 1, [
9859
+ "mimeType",
9860
+ "sizeBytes",
9861
+ "durationMs"
9862
+ ]),
9863
+ referenceSlot("audio_reference_variant_refs", "audio", 0, max("audio"), 2, [
9864
+ "mimeType",
9865
+ "sizeBytes",
9866
+ "durationMs"
9867
+ ])
9868
+ ] : [],
9869
+ referenceCardinality: capability.mode === "text" ? {
9870
+ minCount: 0,
9871
+ maxCount: 0
9872
+ } : capability.mode === "frame" ? {
9873
+ minCount: 1,
9874
+ maxCount: 2
9875
+ } : {
9876
+ minCount: 1,
9877
+ maxCount: capability.maxReferenceFiles
9878
+ }
9704
9879
  }];
9705
9880
  if (capability.mode === "reference") operations.push({
9706
9881
  operation: "refine",
@@ -9727,7 +9902,29 @@ function wan3VideoGenerator(capability) {
9727
9902
  maxItems: 4,
9728
9903
  description: "Up to 4 additional videos; the source video is Video 1."
9729
9904
  } : item)
9730
- ]
9905
+ ],
9906
+ referenceSlots: [
9907
+ referenceSlot("source_variant_ref", "video", 1, 1, 0, [
9908
+ "mimeType",
9909
+ "sizeBytes",
9910
+ "durationMs"
9911
+ ]),
9912
+ referenceSlot("image_reference_variant_refs", "image", 0, 10, 1, ["mimeType", "sizeBytes"]),
9913
+ referenceSlot("video_reference_variant_refs", "video", 0, 4, 2, [
9914
+ "mimeType",
9915
+ "sizeBytes",
9916
+ "durationMs"
9917
+ ]),
9918
+ referenceSlot("audio_reference_variant_refs", "audio", 0, 5, 3, [
9919
+ "mimeType",
9920
+ "sizeBytes",
9921
+ "durationMs"
9922
+ ])
9923
+ ],
9924
+ referenceCardinality: {
9925
+ minCount: 1,
9926
+ maxCount: capability.maxReferenceFiles
9927
+ }
9731
9928
  });
9732
9929
  return {
9733
9930
  id: capability.generatorId,
@@ -9804,7 +10001,12 @@ function avatarVideoGenerator(model) {
9804
10001
  minItems: 1,
9805
10002
  maxItems: 1
9806
10003
  })
9807
- ]
10004
+ ],
10005
+ referenceSlots: [referenceSlot("image_reference_variant_refs", "image", 1, 1, 0, ["mimeType", "sizeBytes"]), referenceSlot("audio_reference_variant_refs", "audio", 1, 1, 1, ["mimeType", "sizeBytes"])],
10006
+ referenceCardinality: {
10007
+ minCount: 2,
10008
+ maxCount: 2
10009
+ }
9808
10010
  }],
9809
10011
  referenceRules: {
9810
10012
  mediaKind: null,
@@ -9855,13 +10057,18 @@ function audioGenerator(input_) {
9855
10057
  id: input_.id,
9856
10058
  label: input_.label,
9857
10059
  mediaKind: "audio",
9858
- modelIds: [input_.modelId],
10060
+ modelIds: input_.assetType === "speech" || input_.assetType === "dialogue" ? [...new Set([input_.modelId, DEFAULT_ELEVENLABS_SPEECH_MODEL_ID])] : [input_.modelId],
9859
10061
  defaultModelId: input_.modelId,
9860
10062
  operations: [{
9861
10063
  operation: "generate",
9862
10064
  tool: "generate_audio",
9863
10065
  description: `Create a new ${input_.assetType} audio asset.`,
9864
- inputs
10066
+ inputs,
10067
+ referenceSlots: [],
10068
+ referenceCardinality: {
10069
+ minCount: 0,
10070
+ maxCount: 0
10071
+ }
9865
10072
  }],
9866
10073
  referenceRules: {
9867
10074
  mediaKind: null,
@@ -9878,6 +10085,7 @@ function getGeneratorCatalog(overrides = {}) {
9878
10085
  const lyria = overrides.lyria ?? "lyria-3-clip-preview";
9879
10086
  return [
9880
10087
  ...Object.values(IMAGE_MODEL_CAPABILITIES).map(imageGenerator),
10088
+ ...overrides.customImage ? [customImageGenerator(overrides.customImage)] : [],
9881
10089
  ...VIDEO_MODEL_SELECTIONS.filter((selection) => !getWan3CapabilityBySelection(selection)).map(videoGenerator),
9882
10090
  ...SEEDANCE_2_SELECTIONS.map((selection) => seedanceVideoGenerator(SEEDANCE_2_CAPABILITIES[selection])),
9883
10091
  ...WAN_3_CAPABILITIES.map(wan3VideoGenerator),
@@ -9924,6 +10132,15 @@ function getGeneratorDefinition(id, overrides = {}) {
9924
10132
  }
9925
10133
  //#endregion
9926
10134
  //#region src/shared/generationReferences.ts
10135
+ var GENERATION_REFERENCE_SLOTS = [
10136
+ "source_variant_ref",
10137
+ "reference_variant_refs",
10138
+ "start_frame_variant_ref",
10139
+ "end_frame_variant_ref",
10140
+ "image_reference_variant_refs",
10141
+ "video_reference_variant_refs",
10142
+ "audio_reference_variant_refs"
10143
+ ];
9927
10144
  function isGenerationReference(value) {
9928
10145
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
9929
10146
  const reference = value;
@@ -11324,6 +11541,7 @@ function rejectUnknownModelOptions(command, options) {
11324
11541
  var defaultDeps$4 = {
11325
11542
  loadConfig: loadStoredConfig,
11326
11543
  resolveBaseUrl,
11544
+ loadProjectConfig,
11327
11545
  saveProjectConfig,
11328
11546
  fetch,
11329
11547
  print: console.log
@@ -11337,10 +11555,12 @@ async function handleSpaces(parsed) {
11337
11555
  }
11338
11556
  }
11339
11557
  async function executeSpaces(parsed, deps = defaultDeps$4) {
11340
- const env = resolveCommandEnvironment(parsed);
11341
11558
  const subcommand = parsed.positionals[0];
11342
11559
  rejectUnknownSpaceOptions(subcommand, parsed.options);
11343
11560
  const jsonOutput = parsed.options.json === "true";
11561
+ const projectConfig = subcommand === "current" ? await deps.loadProjectConfig() : null;
11562
+ if (subcommand === "current" && !projectConfig) throw new Error("No current MakeFX Space. Run: makefx init --space <space-id>");
11563
+ const env = resolveCommandEnvironment(parsed, projectConfig);
11344
11564
  const config = await deps.loadConfig(env);
11345
11565
  if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
11346
11566
  if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
@@ -11406,7 +11626,35 @@ async function executeSpaces(parsed, deps = defaultDeps$4) {
11406
11626
  assets: details.assets
11407
11627
  };
11408
11628
  }
11409
- if (subcommand !== "list") throw new Error("Spaces command is required: list, show, create, or delete");
11629
+ if (subcommand === "current") {
11630
+ const details = await getSpaceDetails(ctx, deps, projectConfig.spaceId);
11631
+ if (jsonOutput) deps.print(JSON.stringify({
11632
+ project: {
11633
+ root: projectConfig.projectRoot ?? null,
11634
+ configPath: projectConfig.configPath ?? null,
11635
+ environment: env
11636
+ },
11637
+ space: publicSpace(details.space),
11638
+ assets: details.assets.map((asset) => ({
11639
+ assetRef: createAssetRef(asset.name, asset.id),
11640
+ name: asset.name,
11641
+ type: asset.type,
11642
+ mediaKind: asset.media_kind ?? null,
11643
+ activeVariantRef: asset.active_variant_id ? createVariantRef(asset.name, asset.id, asset.active_variant_id) : null
11644
+ }))
11645
+ }, null, 2));
11646
+ else {
11647
+ deps.print(`Current project: ${projectConfig.projectRoot ?? projectConfig.configPath ?? "unknown"}`);
11648
+ printSpaceDetails(details, deps.print);
11649
+ }
11650
+ return {
11651
+ type: "current",
11652
+ space: details.space,
11653
+ assets: details.assets,
11654
+ projectRoot: projectConfig.projectRoot ?? null
11655
+ };
11656
+ }
11657
+ if (subcommand !== "list") throw new Error("Spaces command is required: current, list, show, create, or delete");
11410
11658
  const spaces = await fetchSpaces(ctx, deps);
11411
11659
  if (jsonOutput) deps.print(JSON.stringify(spaces.map(publicSpace), null, 2));
11412
11660
  else printSpaces(spaces, deps.print);
@@ -11422,6 +11670,7 @@ function rejectUnknownSpaceOptions(subcommand, options) {
11422
11670
  "json"
11423
11671
  ];
11424
11672
  const commandOptions = subcommand ? {
11673
+ current: [],
11425
11674
  list: [],
11426
11675
  show: [],
11427
11676
  create: ["name", "init"],
@@ -11758,33 +12007,31 @@ var defaultDeps$2 = {
11758
12007
  print: console.log
11759
12008
  };
11760
12009
  var UploadUsageError = class extends Error {};
11761
- var LINEAGE_RELATION_TYPES = new Set([
11762
- "derived",
11763
- "refined",
11764
- "forked"
11765
- ]);
11766
- function parseLineageOption(raw, defaultRelationType) {
12010
+ function parseRecipeReferencesOption(raw) {
11767
12011
  if (!raw) return [];
11768
12012
  const entries = raw.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
11769
- if (entries.length === 0) throw new UploadUsageError("--lineage requires at least one compact variant ref");
12013
+ if (entries.length === 0) throw new UploadUsageError("--reference requires at least one slot=variant-ref entry");
11770
12014
  return entries.map((entry) => {
11771
- const atIndex = entry.lastIndexOf("@");
11772
- const separator = entry.lastIndexOf(":");
11773
- let ref = entry;
11774
- let relationType = defaultRelationType;
11775
- if (atIndex !== -1 && separator > atIndex) {
11776
- const suffix = entry.slice(separator + 1);
11777
- if (!LINEAGE_RELATION_TYPES.has(suffix)) throw new UploadUsageError(`--lineage relation in "${entry}" must be derived, refined, or forked`);
11778
- ref = entry.slice(0, separator);
11779
- relationType = suffix;
11780
- }
11781
- if (!ref.startsWith("asset:")) throw new UploadUsageError(`--lineage requires compact variant refs, got "${ref}"`);
12015
+ const separator = entry.indexOf("=");
12016
+ const slot = entry.slice(0, separator);
12017
+ const ref = entry.slice(separator + 1);
12018
+ if (separator <= 0 || !GENERATION_REFERENCE_SLOTS.includes(slot)) throw new UploadUsageError(`--reference requires a canonical slot before "=", got "${entry}"`);
12019
+ const parsed = parseVariantRef(ref);
12020
+ if (!parsed || parsed.variant === "active") throw new UploadUsageError(`--reference requires an exact compact variant ref, got "${ref}"`);
11782
12021
  return {
11783
- ref,
11784
- relationType
12022
+ slot,
12023
+ ref
11785
12024
  };
11786
12025
  });
11787
12026
  }
12027
+ function parseParametersOption(raw) {
12028
+ if (!raw) return {};
12029
+ try {
12030
+ const parsed = JSON.parse(raw);
12031
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
12032
+ } catch {}
12033
+ throw new UploadUsageError("--parameters must be a JSON object");
12034
+ }
11788
12035
  async function handleUpload(parsed) {
11789
12036
  try {
11790
12037
  await executeUpload(parsed);
@@ -11809,7 +12056,8 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
11809
12056
  const jsonOutput = parsed.options.json === "true";
11810
12057
  if (!spaceId) throw new UploadUsageError("--space is required, or run: makefx init --space <id>");
11811
12058
  if (!assetId && !assetName) throw new UploadUsageError("Either --asset or --name is required");
11812
- const lineageEntries = parseLineageOption(parsed.options.lineage, assetId ? "refined" : "derived");
12059
+ const recipeReferences = parseRecipeReferencesOption(parsed.options.reference);
12060
+ const parameters = parseParametersOption(parsed.options.parameters);
11813
12061
  const mediaType = resolveMediaType(path.extname(filePath).toLowerCase(), requestedMediaKind);
11814
12062
  const config = await deps.loadConfig(env);
11815
12063
  if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
@@ -11817,15 +12065,10 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
11817
12065
  const baseUrl = deps.resolveBaseUrl(env);
11818
12066
  const accessToken = config.token.accessToken;
11819
12067
  const createStateClient = () => (deps.createStateClient ?? defaultDeps$2.createStateClient)(env, spaceId);
11820
- let lineage = [];
11821
- if (assetId || lineageEntries.length > 0) {
12068
+ if (assetId) {
11822
12069
  if (assetId && !assetId.startsWith("asset:")) throw new Error("A compact asset ref is required");
11823
12070
  const state = await readReferenceSpaceState(createStateClient);
11824
12071
  if (assetId) assetId = resolveAssetRef(assetId, state.assets);
11825
- lineage = lineageEntries.map((entry) => ({
11826
- parentVariantId: resolveVariantRef(entry.ref, state.assets, state.variants),
11827
- relationType: entry.relationType
11828
- }));
11829
12072
  }
11830
12073
  if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
11831
12074
  try {
@@ -11844,17 +12087,34 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
11844
12087
  formData.append("assetName", assetName);
11845
12088
  formData.append("assetType", assetType);
11846
12089
  }
11847
- if (lineage.length > 0) formData.append("lineage", JSON.stringify(lineage));
12090
+ if (hasExternalRecipeOptions(parsed.options)) {
12091
+ formData.append("operation", "import");
12092
+ if (parsed.options.generator) formData.append("generatorId", parsed.options.generator);
12093
+ if (parsed.options["generator-operation"]) formData.append("generatorOperation", parsed.options["generator-operation"]);
12094
+ if (parsed.options.service) formData.append("service", parsed.options.service);
12095
+ if (parsed.options.provider) formData.append("provider", parsed.options.provider);
12096
+ if (parsed.options.model) formData.append("model", parsed.options.model);
12097
+ if (parsed.options.prompt !== void 0) formData.append("prompt", parsed.options.prompt);
12098
+ if (parsed.options["external-run-id"]) formData.append("externalRunId", parsed.options["external-run-id"]);
12099
+ formData.append("parameters", JSON.stringify(parameters));
12100
+ formData.append("references", JSON.stringify(recipeReferences.map((reference) => ({
12101
+ slot: reference.slot,
12102
+ variantRef: reference.ref
12103
+ }))));
12104
+ }
11848
12105
  if (!jsonOutput) {
11849
12106
  deps.print(`\nUploading "${fileName}" to space ${spaceId}...`);
11850
12107
  deps.print(` Media kind: ${mediaType.mediaKind}`);
11851
12108
  if (assetId) deps.print(` Target asset: ${requestedAssetRef}`);
11852
12109
  else deps.print(` Creating asset: "${assetName}" (${assetType})`);
11853
- for (const entry of lineageEntries) deps.print(` Lineage: ${entry.relationType} from ${entry.ref}`);
12110
+ for (const entry of recipeReferences) deps.print(` Recipe Reference: ${entry.slot} = ${entry.ref}`);
11854
12111
  }
11855
12112
  const response = await deps.fetch(`${baseUrl}/api/spaces/${spaceId}/upload`, {
11856
12113
  method: "POST",
11857
- headers: { "Authorization": `Bearer ${accessToken}` },
12114
+ headers: {
12115
+ "Authorization": `Bearer ${accessToken}`,
12116
+ ...cliVersionHeaders()
12117
+ },
11858
12118
  body: formData
11859
12119
  });
11860
12120
  const data = await readJsonResponse(response, "Upload request");
@@ -11884,7 +12144,8 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
11884
12144
  assetRef: result.assetRef,
11885
12145
  variantRef: result.variantRef,
11886
12146
  status: upload.variant.status,
11887
- mediaKind: upload.variant.media_kind || mediaType.mediaKind
12147
+ mediaKind: upload.variant.media_kind || mediaType.mediaKind,
12148
+ ...upload.provenance ? { provenance: upload.provenance } : {}
11888
12149
  }, null, 2));
11889
12150
  return result;
11890
12151
  }
@@ -11901,6 +12162,10 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
11901
12162
  deps.print(` Status: ${upload.variant.status}`);
11902
12163
  deps.print(` Media: ${upload.variant.media_kind || mediaType.mediaKind}`);
11903
12164
  if (upload.variant.media_mime_type) deps.print(` MIME: ${upload.variant.media_mime_type}`);
12165
+ if (upload.provenance) {
12166
+ deps.print(` Recipe: ${upload.provenance.state}`);
12167
+ if (upload.provenance.missingReasons.length > 0) deps.print(` Guidance: ${upload.provenance.missingReasons.join(", ")}`);
12168
+ }
11904
12169
  deps.print("\nTo inspect:");
11905
12170
  deps.print(` makefx variants show ${result.variantRef} --wait --space ${spaceId}`);
11906
12171
  return result;
@@ -11936,12 +12201,33 @@ function rejectUnknownUploadOptions(options) {
11936
12201
  "name",
11937
12202
  "type",
11938
12203
  "media-kind",
11939
- "lineage",
11940
- "json"
12204
+ "json",
12205
+ "generator",
12206
+ "generator-operation",
12207
+ "service",
12208
+ "provider",
12209
+ "model",
12210
+ "prompt",
12211
+ "parameters",
12212
+ "reference",
12213
+ "external-run-id"
11941
12214
  ]);
11942
12215
  const unknown = Object.keys(options).find((name) => !allowed.has(name));
11943
12216
  if (unknown) throw new UploadUsageError(`Unknown option: --${unknown}`);
11944
12217
  }
12218
+ function hasExternalRecipeOptions(options) {
12219
+ return [
12220
+ "generator",
12221
+ "generator-operation",
12222
+ "service",
12223
+ "provider",
12224
+ "model",
12225
+ "prompt",
12226
+ "parameters",
12227
+ "reference",
12228
+ "external-run-id"
12229
+ ].some((name) => options[name] !== void 0);
12230
+ }
11945
12231
  function printUsage$2() {
11946
12232
  console.log(`
11947
12233
  Usage:
@@ -11954,9 +12240,14 @@ Options:
11954
12240
  --name <name> New asset name (creates asset + variant)
11955
12241
  --type <type> Asset type for new assets (default: character)
11956
12242
  --media-kind <k> Optional explicit kind: image, audio, or video
11957
- --lineage <refs> Source variant refs this upload was made from, comma-separated,
11958
- each optionally suffixed :derived, :refined, or :forked
11959
- (default: refined with --asset, derived with --name)
12243
+ --generator <id> Canonical generator/service schema for an external result
12244
+ --service <id> External execution service
12245
+ --provider <id> Exact external provider
12246
+ --model <id> Exact external model
12247
+ --prompt <text> Exact submitted prompt
12248
+ --parameters <j> Additional exact generator parameters as a JSON object
12249
+ --reference <r> Ordered slot=exact-variant-ref entries, comma-separated
12250
+ --external-run-id <id> Optional bounded external execution identifier
11960
12251
  --json Print machine-readable output
11961
12252
  --env <env> Environment (production|stage|local)
11962
12253
  --local Shortcut for --env local
@@ -11964,7 +12255,9 @@ Options:
11964
12255
  Examples:
11965
12256
  makefx assets upload hero.png --name "Hero Character"
11966
12257
  makefx assets upload paintover.png --asset asset:hero~27f8f176
11967
- makefx assets upload paintover.png --asset asset:hero~27f8f176 --lineage asset:hero~27f8f176@active
12258
+ makefx assets upload avatar.mp4 --name "Avatar" --generator avatar --service fal \
12259
+ --provider fal --model avatar-v1 --prompt "Welcome" \
12260
+ --reference image_reference_variant_refs=asset:portrait~27f8@a1,audio_reference_variant_refs=asset:voice~91ab@b2
11968
12261
  `);
11969
12262
  }
11970
12263
  //#endregion
@@ -12390,7 +12683,7 @@ Assets:
12390
12683
  graph run | status | cancel
12391
12684
 
12392
12685
  Workspace:
12393
- spaces list | show | create | delete | lens
12686
+ spaces current | list | show | create | delete | lens
12394
12687
  init | login | logout
12395
12688
  usage | spend | billing
12396
12689
 
@@ -12442,12 +12735,14 @@ Generate commands also accept [--collection <id>] [--space <id>].`,
12442
12735
  makefx assets show <asset-ref> [--json]
12443
12736
  makefx assets update <asset-ref> [--name <name>] [--type <type>] [--tags <tag,...>]
12444
12737
  makefx assets delete <asset-ref> [--yes]
12445
- makefx assets upload <file> (--name <name> | --asset <asset-ref>) [--type <type>] [--lineage <variant-ref[:relation],...>]
12738
+ makefx assets upload <file> (--name <name> | --asset <asset-ref>) [--type <type>]
12739
+ [--generator <id> --service <id> --provider <id> --model <id>]
12740
+ [--prompt <text>] [--parameters <json>] [--reference <slot=variant-ref,...>]
12446
12741
  makefx assets download <variant-ref> -o <file>
12447
12742
 
12448
- Upload --lineage records which variants the file was made from: comma-separated
12449
- compact variant refs, each optionally suffixed :derived, :refined, or :forked
12450
- (default: refined when uploading to --asset, derived when creating with --name).`,
12743
+ External import options attach the exact canonical Recipe without executing a
12744
+ provider or billing generation. --reference accepts ordered canonical slots and
12745
+ exact compact Variant refs; raw uploads omit all external Recipe options.`,
12451
12746
  variants: `Usage:
12452
12747
  makefx variants show <variant-ref> [--wait <seconds>] [--json]
12453
12748
  makefx variants update <variant-ref> [--starred true|false] [--rating approved|rejected|none]
@@ -12479,6 +12774,7 @@ compact variant refs, each optionally suffixed :derived, :refined, or :forked
12479
12774
  makefx bindings set <draft-ref> <slot> --source variant|asset-active|draft-output --ref <ref> [--sort <index>]
12480
12775
  makefx bindings clear <draft-ref> <slot> [--sort <index>]`,
12481
12776
  spaces: `Usage:
12777
+ makefx spaces current [--json]
12482
12778
  makefx spaces list [--json]
12483
12779
  makefx spaces show <space-id> [--json]
12484
12780
  makefx spaces create "<name>" [--init] [--json]
package/package.json CHANGED
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "makefx",
3
- "version": "1.6.9",
4
- "description": "Command-line interface for AI-assisted game asset production with Make Effects.",
3
+ "version": "1.6.11",
4
+ "description": "MakeFX CLI for reproducible image, video, and audio Assets in Make Effects.",
5
+ "homepage": "https://makefx.app/docs/cli",
6
+ "keywords": [
7
+ "makefx",
8
+ "make-effects",
9
+ "mcp",
10
+ "media-generation",
11
+ "reproducibility",
12
+ "cli"
13
+ ],
5
14
  "license": "MIT",
6
15
  "type": "module",
7
16
  "repository": {