makefx 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/makefx.mjs +1032 -114
  3. package/package.json +1 -1
package/makefx.mjs CHANGED
@@ -660,6 +660,9 @@ function createVariantRef(name, assetId, variantId) {
660
660
  function createDraftRef(name, draftId) {
661
661
  return `draft:${slugify(name, "draft")}~${compactIdPrefix(draftId)}`;
662
662
  }
663
+ function createGraphRunRef(runId) {
664
+ return `graph-run:${compactIdPrefix(runId)}`;
665
+ }
663
666
  function parseAssetRef(value) {
664
667
  const match = /^asset:[^~]+~([a-z0-9]{4,8})$/u.exec(value);
665
668
  return match ? { idPrefix: match[1] } : null;
@@ -4399,6 +4402,7 @@ var WebSocketClient = class WebSocketClient {
4399
4402
  chatHandlers = /* @__PURE__ */ new Map();
4400
4403
  generateHandlers = /* @__PURE__ */ new Map();
4401
4404
  earlyTerminalVariants = /* @__PURE__ */ new Map();
4405
+ draftRunStartsAwaitingVariant = /* @__PURE__ */ new Set();
4402
4406
  variantCompletionHandlers = /* @__PURE__ */ new Map();
4403
4407
  describeHandlers = /* @__PURE__ */ new Map();
4404
4408
  compareHandlers = /* @__PURE__ */ new Map();
@@ -4724,7 +4728,7 @@ var WebSocketClient = class WebSocketClient {
4724
4728
  return handled;
4725
4729
  }
4726
4730
  hasRequestsAwaitingStarted() {
4727
- return this.generateHandlers.size > 0;
4731
+ return this.generateHandlers.size > 0 || this.draftRunStartsAwaitingVariant.size > 0;
4728
4732
  }
4729
4733
  clearOrphanedEarlyTerminalVariants() {
4730
4734
  if (!this.hasRequestsAwaitingStarted()) this.earlyTerminalVariants.clear();
@@ -4869,6 +4873,58 @@ var WebSocketClient = class WebSocketClient {
4869
4873
  bindingId
4870
4874
  }, (msg) => msg.type === "binding:cleared" && msg.draftId === draftId && msg.bindingId === bindingId);
4871
4875
  }
4876
+ async runDraft(draftId, requestId, onStarted) {
4877
+ if (onStarted) this.draftRunStartsAwaitingVariant.add(requestId);
4878
+ try {
4879
+ const result = await this.awaitServerMessage({
4880
+ type: "drafts.run",
4881
+ draftId,
4882
+ requestId,
4883
+ source: "cli"
4884
+ }, (msg) => (msg.type === "drafts.run_started" || msg.type === "drafts.run_error") && msg.requestId === requestId);
4885
+ if (result.type === "drafts.run_error") throw new Error(`${result.code}: ${result.error}`);
4886
+ onStarted?.(result);
4887
+ return result;
4888
+ } finally {
4889
+ this.draftRunStartsAwaitingVariant.delete(requestId);
4890
+ this.clearOrphanedEarlyTerminalVariants();
4891
+ }
4892
+ }
4893
+ async runGraph(input) {
4894
+ const result = await this.awaitServerMessage({
4895
+ type: "graph.run",
4896
+ ...input,
4897
+ source: "cli"
4898
+ }, (msg) => msg.type === "graph.run_started" && msg.run.request_id === input.requestId || msg.type === "graph.run_error" && msg.requestId === input.requestId);
4899
+ if (result.type === "graph.run_error") {
4900
+ const detail = result.failures.map((failure) => `${failure.draftId}: ${failure.error}`).join("; ");
4901
+ throw new Error(`${result.code}: ${detail || result.error}`);
4902
+ }
4903
+ return {
4904
+ type: "graph.run_status",
4905
+ run: result.run,
4906
+ drafts: result.drafts
4907
+ };
4908
+ }
4909
+ async getGraphRunStatus(runRef) {
4910
+ return this.awaitServerMessage({
4911
+ type: "graph.status",
4912
+ runRef
4913
+ }, (msg) => msg.type === "graph.run_status");
4914
+ }
4915
+ async cancelGraphRun(runId) {
4916
+ return this.awaitServerMessage({
4917
+ type: "graph.cancel",
4918
+ runId
4919
+ }, (msg) => msg.type === "graph.run_status" && msg.run.id === runId);
4920
+ }
4921
+ async waitForGraphRun(runRef, runId, timeoutMs = GENERATION_REQUEST_TIMEOUT_MS) {
4922
+ await this.awaitServerMessage({
4923
+ type: "graph.status",
4924
+ runRef
4925
+ }, (msg) => (msg.type === "graph.run_status" && msg.run.id === runId || msg.type === "graph.run_progress" && msg.run.id === runId) && msg.run.status !== "running", timeoutMs);
4926
+ return this.getGraphRunStatus(runRef);
4927
+ }
4872
4928
  async setCanvasLens(lens) {
4873
4929
  return (await this.awaitServerMessage({
4874
4930
  type: "canvas.set_lens",
@@ -4992,6 +5048,11 @@ var WebSocketClient = class WebSocketClient {
4992
5048
  reject,
4993
5049
  timeout
4994
5050
  });
5051
+ const earlyTerminal = this.earlyTerminalVariants.get(params.variantId);
5052
+ if (earlyTerminal) {
5053
+ this.earlyTerminalVariants.delete(params.variantId);
5054
+ this.handleTerminalVariant(earlyTerminal);
5055
+ }
4995
5056
  });
4996
5057
  }
4997
5058
  cancelFollowVariant(variantId, requestId) {
@@ -6017,6 +6078,11 @@ var VIDEO_GENERATION_RESOLUTIONS = [
6017
6078
  ];
6018
6079
  var ALL_VIDEO_GENERATION_RESOLUTIONS = ["480p", ...VIDEO_GENERATION_RESOLUTIONS];
6019
6080
  var KLING_VIDEO_GENERATION_RESOLUTIONS = ["720p", "1080p"];
6081
+ var VIDEO_GENERATION_DURATION_SECONDS = [
6082
+ 4,
6083
+ 6,
6084
+ 8
6085
+ ];
6020
6086
  var SEEDANCE_2_DURATION_SECONDS = [
6021
6087
  4,
6022
6088
  5,
@@ -6042,6 +6108,12 @@ var VIDEO_MODEL_SELECTIONS = [
6042
6108
  "kling",
6043
6109
  "fal-seedance"
6044
6110
  ];
6111
+ var VIDEO_MODEL_LABELS = {
6112
+ "veo-3.1": "Veo 3.1",
6113
+ "omni-flash": "Omni Flash",
6114
+ kling: "Kling 3.0",
6115
+ "fal-seedance": "fal.ai Seedance v1 (text-to-video)"
6116
+ };
6045
6117
  var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
6046
6118
  "veo-3.1": [
6047
6119
  "generate",
@@ -6069,6 +6141,7 @@ var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
6069
6141
  fast: VIDEO_GENERATION_RESOLUTIONS,
6070
6142
  lite: ["720p", "1080p"]
6071
6143
  };
6144
+ var DEFAULT_VIDEO_GENERATION_RESOLUTION = "720p";
6072
6145
  var DEFAULT_VIDEO_GENERATION_TIER = "generate";
6073
6146
  var DEFAULT_VIDEO_MODEL_SELECTION = "veo-3.1";
6074
6147
  function normalizeVideoGenerationAspectRatio(value) {
@@ -6144,6 +6217,12 @@ function isFalSeedanceV1VideoGenerationModel(model) {
6144
6217
  function isFalSeedance2VideoGenerationModel(model) {
6145
6218
  return typeof model === "string" && getSeedance2CapabilityByEndpoint(model) !== void 0;
6146
6219
  }
6220
+ function getVideoGenerationMaxReferenceImages(model) {
6221
+ if (isFalSeedanceV1VideoGenerationModel(model)) return 0;
6222
+ if (isFalSeedance2VideoGenerationModel(model)) return getSeedance2CapabilityByEndpoint(model)?.references.find((reference) => reference.mediaKind === "image")?.maxCount ?? 0;
6223
+ if (isKlingVideoGenerationModel(model)) return 1;
6224
+ return 3;
6225
+ }
6147
6226
  function isVideoOperationSupportedByModel(model, operation) {
6148
6227
  const seedanceCapability = getSeedance2CapabilityByEndpoint(model);
6149
6228
  if (seedanceCapability) return seedanceCapability.operations.includes(operation);
@@ -6234,6 +6313,9 @@ var IMAGE_MODEL_CAPABILITIES = {
6234
6313
  function isImageModelSelection(value) {
6235
6314
  return IMAGE_MODEL_SELECTIONS.includes(value);
6236
6315
  }
6316
+ function isImageModelId(value) {
6317
+ return Object.values(IMAGE_MODEL_IDS).includes(value);
6318
+ }
6237
6319
  function isImageSize(value) {
6238
6320
  return IMAGE_SIZES.includes(value);
6239
6321
  }
@@ -6382,9 +6464,21 @@ var AUDIO_FORGE_MEDIA_MODES = MEDIA_OPERATION_MATRIX.filter((entry) => entry.med
6382
6464
  function getMediaOperationEntry(mode) {
6383
6465
  return ENTRY_BY_MODE.get(mode) ?? MEDIA_OPERATION_MATRIX[0];
6384
6466
  }
6467
+ function getMediaKindForForgeMode(mode) {
6468
+ return getMediaOperationEntry(mode).mediaKind;
6469
+ }
6385
6470
  function isAudioForgeMediaMode(value) {
6386
6471
  return AUDIO_FORGE_MEDIA_MODES.includes(value);
6387
6472
  }
6473
+ function getForgeModeForAudioAssetType(assetType) {
6474
+ switch (assetType) {
6475
+ case "speech":
6476
+ case "dialogue":
6477
+ case "music":
6478
+ case "sfx": return assetType;
6479
+ default: return "speech";
6480
+ }
6481
+ }
6388
6482
  function getCliGenerationProfile(namespace) {
6389
6483
  const profile = PROFILE_BY_NAMESPACE.get(namespace);
6390
6484
  if (!profile) throw new Error(`Unknown CLI generation namespace: ${namespace}`);
@@ -6489,49 +6583,49 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$12, optio
6489
6583
  client.disconnect();
6490
6584
  }
6491
6585
  }
6586
+ var CLI_GENERATION_COMMON_OPTIONS = [
6587
+ "env",
6588
+ "local",
6589
+ "space",
6590
+ "force",
6591
+ "name",
6592
+ "type",
6593
+ "o",
6594
+ "output",
6595
+ "collection"
6596
+ ];
6597
+ var CLI_GENERATION_MEDIA_OPTIONS = {
6598
+ image: [
6599
+ "model",
6600
+ "refs",
6601
+ "aspect",
6602
+ "size"
6603
+ ],
6604
+ audio: [
6605
+ "model",
6606
+ "input",
6607
+ "voice",
6608
+ "dialogue-voices"
6609
+ ],
6610
+ video: [
6611
+ "model",
6612
+ "refs",
6613
+ "aspect",
6614
+ "audio",
6615
+ "no-audio",
6616
+ "resolution",
6617
+ "duration",
6618
+ "tier",
6619
+ "bitrate",
6620
+ "first-frame",
6621
+ "last-frame",
6622
+ "image-refs",
6623
+ "video-refs",
6624
+ "audio-refs"
6625
+ ]
6626
+ };
6492
6627
  function rejectUnknownGenerationOptions(options, mediaKind) {
6493
- const common = [
6494
- "env",
6495
- "local",
6496
- "space",
6497
- "force",
6498
- "name",
6499
- "type",
6500
- "o",
6501
- "output",
6502
- "collection"
6503
- ];
6504
- const byKind = {
6505
- image: [
6506
- "model",
6507
- "refs",
6508
- "aspect",
6509
- "size"
6510
- ],
6511
- audio: [
6512
- "model",
6513
- "input",
6514
- "voice",
6515
- "dialogue-voices"
6516
- ],
6517
- video: [
6518
- "model",
6519
- "refs",
6520
- "aspect",
6521
- "audio",
6522
- "no-audio",
6523
- "resolution",
6524
- "duration",
6525
- "tier",
6526
- "bitrate",
6527
- "first-frame",
6528
- "last-frame",
6529
- "image-refs",
6530
- "video-refs",
6531
- "audio-refs"
6532
- ]
6533
- };
6534
- const allowed = new Set([...common, ...byKind[mediaKind]]);
6628
+ const allowed = new Set([...CLI_GENERATION_COMMON_OPTIONS, ...CLI_GENERATION_MEDIA_OPTIONS[mediaKind]]);
6535
6629
  const unknown = Object.keys(options).find((name) => !allowed.has(name));
6536
6630
  if (unknown) throw new Error(`Unknown option: --${unknown}`);
6537
6631
  }
@@ -6585,12 +6679,16 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
6585
6679
  const seedanceCapability = mediaKind === "video" ? getSeedance2CapabilityByEndpoint(effectiveVideoModel) : void 0;
6586
6680
  const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
6587
6681
  const seedanceRefs = parseSeedanceReferenceOptions(parsed);
6682
+ const plainRefs = parseOptionalRefs(parsed, "refs");
6588
6683
  validateSeedanceReferenceOptions(seedanceRefs, effectiveVideoModel, "generate");
6589
6684
  if (seedanceCapability?.mode === "frame" && videoFrameRefs.length === 0) throw new Error(`--model ${seedanceCapability.selection} requires --first-frame`);
6590
6685
  if (seedanceCapability?.mode === "text" && videoFrameRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} does not accept references`);
6591
6686
  if (seedanceCapability?.mode === "reference" && videoFrameRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} uses --image-refs, --video-refs, and --audio-refs`);
6687
+ if (seedanceCapability && plainRefs.length > 0) throw new Error(`--model ${seedanceCapability.selection} uses --image-refs, --video-refs, and --audio-refs instead of --refs`);
6688
+ if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length + plainRefs.length > 1) throw new Error("--model kling supports at most one image reference");
6689
+ if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && (videoFrameRefs.length > 0 || plainRefs.length > 0)) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support image references`);
6592
6690
  const seedanceReferenceCount = seedanceRefs.imageRefs.length + seedanceRefs.videoRefs.length + seedanceRefs.audioRefs.length;
6593
- const state = videoFrameRefs.length > 0 || seedanceReferenceCount > 0 ? await requestSpaceState(client) : void 0;
6691
+ const state = videoFrameRefs.length > 0 || seedanceReferenceCount > 0 || plainRefs.length > 0 ? await requestSpaceState(client) : void 0;
6594
6692
  const referenceDeps = {
6595
6693
  ...deps,
6596
6694
  waitForReferenceVariant: (variant) => waitForReferenceVariant(client, variant)
@@ -6599,12 +6697,12 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
6599
6697
  refs: [],
6600
6698
  ids: []
6601
6699
  };
6602
- const referenceVariantIds = resolvedSeedanceRefs.ids.length > 0 ? resolvedSeedanceRefs.ids : videoFrameRefs.length > 0 ? await resolveReferenceVariantIds(videoFrameRefs, ctx, referenceDeps, state?.variants, CLI_GENERATION_MEDIA_KIND, state?.assets) : [];
6700
+ const directRefs = videoFrameRefs.length > 0 ? videoFrameRefs : plainRefs;
6701
+ const directRefMediaKind = videoFrameRefs.length > 0 ? CLI_GENERATION_MEDIA_KIND : mediaKind;
6702
+ const referenceVariantIds = resolvedSeedanceRefs.ids.length > 0 ? resolvedSeedanceRefs.ids : directRefs.length > 0 ? await resolveReferenceVariantIds(directRefs, ctx, referenceDeps, state?.variants, directRefMediaKind, state?.assets) : [];
6603
6703
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
6604
6704
  const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
6605
6705
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
6606
- if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length > 1) throw new Error("--model kling supports at most one image reference");
6607
- if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length > 0) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support image references`);
6608
6706
  const collectionPlacement = parseCollectionPlacementOptions(parsed);
6609
6707
  const followCommandOptions = {
6610
6708
  ...followOptions,
@@ -7290,7 +7388,7 @@ function cliImageModelValues(command) {
7290
7388
  function printUsage$6(command) {
7291
7389
  console.log(`
7292
7390
  Usage:
7293
- makefx image generate "prompt" --name <name> --type <type> -o <file> [--model ${cliImageModelValues(command)}] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
7391
+ makefx image generate "prompt" --name <name> --type <type> -o <file> [--model ${cliImageModelValues(command)}] [--refs <variant-ref-or-file,...>] [--size ${cliImageSizeValues()}] [--aspect ${cliImageAspectValues()}] [--collection <id>] [--space <id>]
7294
7392
  `);
7295
7393
  }
7296
7394
  //#endregion
@@ -7431,7 +7529,7 @@ function resolveVideoRegenerationModel(model, parsed, sourceRecipe) {
7431
7529
  "video-refs",
7432
7530
  "audio-refs"
7433
7531
  ].some((name) => parsed.options[name] !== void 0);
7434
- const storedRecipe = parseStoredRecipe$1(sourceRecipe);
7532
+ const storedRecipe = parseStoredRecipe$2(sourceRecipe);
7435
7533
  return getSeedance2RegenerationCapability(model, {
7436
7534
  model: storedRecipe?.model,
7437
7535
  references: storedRecipe?.references ?? [],
@@ -7442,7 +7540,7 @@ function resolveVideoRegenerationModel(model, parsed, sourceRecipe) {
7442
7540
  if (!selection) throw new Error("Unsupported video model. Expected veo-3.1, omni-flash, kling, seedance-1, seedance-2, or seedance-2-fast");
7443
7541
  return getVideoGenerationModelForSelection(selection, tier);
7444
7542
  }
7445
- function parseStoredRecipe$1(recipe) {
7543
+ function parseStoredRecipe$2(recipe) {
7446
7544
  if (!recipe) return void 0;
7447
7545
  try {
7448
7546
  const parsed = JSON.parse(recipe);
@@ -8360,13 +8458,575 @@ async function executeSpaceLens(parsed, deps = defaultDeps$8) {
8360
8458
  return result;
8361
8459
  }
8362
8460
  //#endregion
8461
+ //#region src/shared/generatorCapabilities.ts
8462
+ function input(name, type, required, description, options = {}) {
8463
+ return {
8464
+ name,
8465
+ type,
8466
+ required,
8467
+ description,
8468
+ ...options
8469
+ };
8470
+ }
8471
+ var SPACE_INPUT = input("space_id", "string", true, "Target Space ID from list_spaces.");
8472
+ var NAME_INPUT = input("name", "string", true, "Human-readable asset name.");
8473
+ var PROMPT_INPUT = input("prompt", "string", true, "Generation instruction.");
8474
+ function fixedInput(name, value, description) {
8475
+ return input(name, "string", true, description, { allowedValues: [value] });
8476
+ }
8477
+ function imageGenerator(capability) {
8478
+ const referenceInput = input("reference_variant_refs", "string_array", false, "Completed image variant references from find_assets or get_asset.", {
8479
+ minItems: 1,
8480
+ maxItems: capability.maxReferenceImages
8481
+ });
8482
+ const generateInputs = [
8483
+ SPACE_INPUT,
8484
+ fixedInput("generator_id", `image/${capability.selection}`, "Selects this image generator."),
8485
+ NAME_INPUT,
8486
+ input("asset_type", "string", true, "Asset classification stored in the Space."),
8487
+ PROMPT_INPUT,
8488
+ input("aspect_ratio", "string", false, "Output aspect ratio.", {
8489
+ allowedValues: capability.supportedAspectRatios,
8490
+ defaultValue: "1:1"
8491
+ }),
8492
+ input("image_size", "string", false, "Output image size.", {
8493
+ allowedValues: capability.supportedImageSizes,
8494
+ defaultValue: "1K"
8495
+ })
8496
+ ];
8497
+ const operations = [{
8498
+ operation: "generate",
8499
+ tool: "generate_image",
8500
+ description: "Create a new image asset from text.",
8501
+ inputs: generateInputs
8502
+ }];
8503
+ if (capability.supportedOperations.includes("derive")) operations.push({
8504
+ operation: "derive",
8505
+ tool: "generate_image",
8506
+ description: "Create a new image asset using completed image variants as references.",
8507
+ inputs: [...generateInputs, {
8508
+ ...referenceInput,
8509
+ required: true
8510
+ }]
8511
+ });
8512
+ if (capability.supportedOperations.includes("refine")) operations.push({
8513
+ operation: "refine",
8514
+ tool: "edit_image",
8515
+ description: "Create a new variant on an existing image asset.",
8516
+ inputs: [
8517
+ SPACE_INPUT,
8518
+ fixedInput("generator_id", `image/${capability.selection}`, "Selects this image generator."),
8519
+ input("asset_ref", "string", true, "Target image asset reference from find_assets."),
8520
+ PROMPT_INPUT,
8521
+ input("source_variant_ref", "string", true, "Completed image variant to edit."),
8522
+ input("reference_variant_refs", "string_array", false, "Additional completed image references.", {
8523
+ minItems: 1,
8524
+ maxItems: Math.max(0, capability.maxReferenceImages - 1)
8525
+ }),
8526
+ input("aspect_ratio", "string", false, "Output aspect ratio.", {
8527
+ allowedValues: capability.supportedAspectRatios,
8528
+ defaultValue: "1:1"
8529
+ }),
8530
+ input("image_size", "string", false, "Output image size.", {
8531
+ allowedValues: capability.supportedImageSizes,
8532
+ defaultValue: "1K"
8533
+ })
8534
+ ]
8535
+ });
8536
+ return {
8537
+ id: `image/${capability.selection}`,
8538
+ label: capability.label,
8539
+ mediaKind: "image",
8540
+ provider: capability.provider === "gemini" ? "google_ai" : "fal",
8541
+ modelIds: [capability.modelId],
8542
+ defaultModelId: capability.modelId,
8543
+ operations,
8544
+ referenceRules: {
8545
+ mediaKind: capability.maxReferenceImages > 0 ? "image" : null,
8546
+ completedOnly: capability.maxReferenceImages > 0,
8547
+ maxCount: capability.maxReferenceImages
8548
+ },
8549
+ notes: capability.maxReferenceImages > 0 ? ["Use compact variant references; binary image input is not accepted."] : ["Text-to-image only; reference inputs are not supported."]
8550
+ };
8551
+ }
8552
+ function videoGenerator(selection) {
8553
+ const defaultModel = getVideoGenerationModelForSelection(selection);
8554
+ const isVeo = selection === "veo-3.1";
8555
+ const isOmni = selection === "omni-flash";
8556
+ const isKling = selection === "kling";
8557
+ const modelIds = isVeo ? Object.values(VIDEO_GENERATION_TIER_MODELS) : [defaultModel];
8558
+ const resolutions = isVeo ? VIDEO_GENERATION_RESOLUTIONS : getVideoGenerationResolutionsForModel(defaultModel);
8559
+ const maxReferences = getVideoGenerationMaxReferenceImages(defaultModel);
8560
+ const parameterInputs = [input("aspect_ratio", "string", false, "Output aspect ratio.", {
8561
+ allowedValues: VIDEO_GENERATION_ASPECT_RATIOS,
8562
+ defaultValue: "16:9"
8563
+ })];
8564
+ if (!isOmni) parameterInputs.push(input("video_resolution", "string", false, "Output resolution.", {
8565
+ allowedValues: resolutions,
8566
+ defaultValue: DEFAULT_VIDEO_GENERATION_RESOLUTION
8567
+ }), input("video_duration_seconds", "integer", false, "Output duration in seconds.", {
8568
+ allowedValues: VIDEO_GENERATION_DURATION_SECONDS,
8569
+ defaultValue: 8
8570
+ }));
8571
+ if (isVeo) parameterInputs.push(input("video_tier", "string", false, "Veo model tier.", {
8572
+ allowedValues: VIDEO_GENERATION_TIERS,
8573
+ defaultValue: DEFAULT_VIDEO_GENERATION_TIER
8574
+ }));
8575
+ if (isKling) parameterInputs.push(input("generate_audio", "boolean", false, "Generate synchronized audio.", {
8576
+ allowedValues: [true, false],
8577
+ defaultValue: true
8578
+ }));
8579
+ const commonInputs = [
8580
+ SPACE_INPUT,
8581
+ fixedInput("generator_id", `video/${selection}`, "Selects this video generator."),
8582
+ NAME_INPUT,
8583
+ input("asset_type", "string", true, "Asset classification stored in the Space."),
8584
+ PROMPT_INPUT,
8585
+ ...parameterInputs
8586
+ ];
8587
+ const operations = [{
8588
+ operation: "generate",
8589
+ tool: "generate_video",
8590
+ description: "Create a new video asset from text.",
8591
+ inputs: commonInputs
8592
+ }];
8593
+ if (VIDEO_MODEL_SUPPORTED_OPERATIONS[selection].includes("refine")) operations.push({
8594
+ operation: "refine",
8595
+ tool: "edit_video",
8596
+ description: "Create a new sibling variant from a completed video variant.",
8597
+ inputs: [
8598
+ SPACE_INPUT,
8599
+ fixedInput("generator_id", `video/${selection}`, "Selects this video generator."),
8600
+ input("asset_ref", "string", true, "Target video asset reference from find_assets."),
8601
+ input("source_variant_ref", "string", true, "Completed video variant to refine."),
8602
+ PROMPT_INPUT,
8603
+ ...parameterInputs
8604
+ ]
8605
+ });
8606
+ if (VIDEO_MODEL_SUPPORTED_OPERATIONS[selection].includes("derive")) operations.push({
8607
+ operation: "derive",
8608
+ tool: "generate_video",
8609
+ description: "Create a new video from completed image variants.",
8610
+ inputs: [...commonInputs, input("reference_variant_refs", "string_array", true, "Completed image variant references from find_assets or get_asset.", {
8611
+ minItems: 1,
8612
+ maxItems: maxReferences
8613
+ })]
8614
+ });
8615
+ 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."];
8616
+ return {
8617
+ id: `video/${selection}`,
8618
+ label: VIDEO_MODEL_LABELS[selection],
8619
+ mediaKind: "video",
8620
+ provider: selection === "kling" ? "kling" : selection === "fal-seedance" ? "fal" : "google_ai",
8621
+ modelIds,
8622
+ defaultModelId: defaultModel,
8623
+ operations,
8624
+ referenceRules: {
8625
+ mediaKind: maxReferences > 0 ? "image" : null,
8626
+ completedOnly: maxReferences > 0,
8627
+ maxCount: maxReferences
8628
+ },
8629
+ notes
8630
+ };
8631
+ }
8632
+ function seedanceVideoGenerator(capability) {
8633
+ const fixedGenerator = fixedInput("generator_id", capability.generatorId, "Selects this exact Seedance 2 mode and tier.");
8634
+ const parameters = [
8635
+ input("aspect_ratio", "string", false, "Output aspect ratio; auto lets Seedance infer it.", {
8636
+ allowedValues: capability.aspectRatios,
8637
+ defaultValue: capability.defaultAspectRatio
8638
+ }),
8639
+ input("resolution", "string", false, "Output resolution.", {
8640
+ allowedValues: capability.resolutions,
8641
+ defaultValue: capability.defaultResolution
8642
+ }),
8643
+ input("duration", "string_or_integer", false, "Output seconds from 4 to 15, or auto.", {
8644
+ allowedValues: capability.durations,
8645
+ defaultValue: capability.defaultDuration
8646
+ }),
8647
+ input("generate_audio", "boolean", false, "Generate synchronized native audio.", {
8648
+ allowedValues: [true, false],
8649
+ defaultValue: capability.generateAudio.default
8650
+ }),
8651
+ input("bitrate_mode", "string", false, "Output bitrate quality.", {
8652
+ allowedValues: capability.bitrateModes,
8653
+ defaultValue: capability.defaultBitrateMode
8654
+ })
8655
+ ];
8656
+ const common = [
8657
+ SPACE_INPUT,
8658
+ fixedGenerator,
8659
+ NAME_INPUT,
8660
+ input("asset_type", "string", true, "Asset classification stored in the Space."),
8661
+ PROMPT_INPUT,
8662
+ ...parameters
8663
+ ];
8664
+ const frameInputs = [input("start_frame_variant_ref", "string", true, "Completed image variant used as the authoritative first frame; cannot be combined with extended references."), input("end_frame_variant_ref", "string", false, "Completed image variant used as the authoritative final frame; cannot be combined with extended references.")];
8665
+ const referenceInputs = [
8666
+ input("image_reference_variant_refs", "string_array", false, "Ordered completed images addressed as @Image1 through @Image9 for soft subject, style, or geography guidance; not authoritative boundary frames.", {
8667
+ minItems: 1,
8668
+ maxItems: 9
8669
+ }),
8670
+ input("video_reference_variant_refs", "string_array", false, "Ordered completed videos addressed as @Video1 through @Video3.", {
8671
+ minItems: 1,
8672
+ maxItems: 3
8673
+ }),
8674
+ input("audio_reference_variant_refs", "string_array", false, "Ordered completed audio clips addressed as @Audio1 through @Audio3.", {
8675
+ minItems: 1,
8676
+ maxItems: 3
8677
+ })
8678
+ ];
8679
+ const modeInputs = capability.mode === "frame" ? frameInputs : capability.mode === "reference" ? referenceInputs : [];
8680
+ const operations = capability.operations.filter((operation) => operation !== "refine").map((operation) => ({
8681
+ operation,
8682
+ tool: "generate_video",
8683
+ 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.",
8684
+ inputs: [...common, ...modeInputs]
8685
+ }));
8686
+ if (capability.operations.includes("refine")) {
8687
+ const budget = getSeedance2ReferenceBudget(capability, "refine");
8688
+ const editReferenceInputs = referenceInputs.map((referenceInput) => referenceInput.name === "video_reference_variant_refs" ? {
8689
+ ...referenceInput,
8690
+ maxItems: 2,
8691
+ description: "Up to two additional completed videos addressed as @Video2 and @Video3; the source video is @Video1."
8692
+ } : referenceInput);
8693
+ operations.push({
8694
+ operation: "refine",
8695
+ tool: "edit_video",
8696
+ description: "Edit or continue a completed video using it as @Video1 plus optional ordered references.",
8697
+ referenceLimits: {
8698
+ maxAdditionalCount: budget.maxAdditionalFiles,
8699
+ implicitSourceCount: 1,
8700
+ maxAdditionalByKind: budget.maxAdditionalByKind
8701
+ },
8702
+ inputs: [
8703
+ SPACE_INPUT,
8704
+ fixedGenerator,
8705
+ input("asset_ref", "string", true, "Target video asset reference from find_assets."),
8706
+ input("source_variant_ref", "string", true, "Completed target video used as @Video1."),
8707
+ PROMPT_INPUT,
8708
+ ...parameters,
8709
+ ...editReferenceInputs
8710
+ ]
8711
+ });
8712
+ }
8713
+ return {
8714
+ id: capability.generatorId,
8715
+ label: capability.label,
8716
+ mediaKind: "video",
8717
+ provider: "fal",
8718
+ modelIds: [capability.endpointId],
8719
+ defaultModelId: capability.endpointId,
8720
+ operations,
8721
+ referenceRules: {
8722
+ mediaKind: capability.mode === "frame" ? "image" : null,
8723
+ completedOnly: capability.mode !== "text",
8724
+ maxCount: capability.maxReferenceFiles,
8725
+ maxTotalCount: capability.maxReferenceFiles,
8726
+ requiresVisualWithAudio: capability.requiresVisualReferenceWithAudio,
8727
+ modalities: capability.references.map((reference) => ({
8728
+ mediaKind: reference.mediaKind,
8729
+ minCount: reference.minCount,
8730
+ maxCount: reference.maxCount,
8731
+ promptLabel: reference.promptLabel,
8732
+ acceptedMimeTypes: reference.acceptedMimeTypes,
8733
+ maxBytesPerFile: reference.maxBytesPerFile,
8734
+ ...reference.combinedMaxBytes !== void 0 ? { combinedMaxBytes: reference.combinedMaxBytes } : {},
8735
+ ...reference.combinedDurationSeconds ? { combinedDurationSeconds: reference.combinedDurationSeconds } : {}
8736
+ }))
8737
+ },
8738
+ notes: [
8739
+ "Use compact variant references; binary media input is not accepted.",
8740
+ capability.mode === "reference" ? "Prompt labels are modality-specific and one-based: @ImageN, @VideoN, and @AudioN. @ImageN guides content, style, or geography but is not an authoritative start/end frame." : capability.mode === "frame" ? "The start and end images are authoritative boundary frames. The provider does not allow extended image, video, or audio references in this mode." : "This mode rejects all reference inputs.",
8741
+ "Seedance 2 cannot combine authoritative start/end frames with extended multimodal references in one request.",
8742
+ capability.resolutions.includes("4k") ? "Standard supports 480p, 720p, 1080p, and 4K output." : "Fast supports 480p and 720p output."
8743
+ ]
8744
+ };
8745
+ }
8746
+ function audioGenerator(input_) {
8747
+ const inputs = [
8748
+ SPACE_INPUT,
8749
+ fixedInput("generator_id", input_.id, "Selects this audio generator and mode."),
8750
+ NAME_INPUT,
8751
+ PROMPT_INPUT
8752
+ ];
8753
+ if (input_.provider === "elevenlabs" && (input_.assetType === "speech" || input_.assetType === "dialogue")) inputs.push(input("model", "string", false, "Optional ElevenLabs model override.", { defaultValue: input_.modelId }));
8754
+ if (input_.assetType === "speech") inputs.push(input("voice_id", "string", true, "Voice ID returned by list_voices."));
8755
+ else if (input_.assetType === "dialogue") inputs.push(input("dialogue_voice_ids", "string_array", true, "One voice ID per distinct speaker, in first-appearance order.", { minItems: 2 }));
8756
+ const notes = input_.assetType === "dialogue" ? ["Prompt must contain at least two `Speaker: line` entries and at least two distinct speakers."] : input_.assetType === "speech" ? ["Prompt must be plain speech text, not `Speaker: line` dialogue."] : ["Prompt describes the desired audio; voice inputs and image references are not accepted."];
8757
+ return {
8758
+ id: input_.id,
8759
+ label: input_.label,
8760
+ mediaKind: "audio",
8761
+ provider: input_.provider,
8762
+ modelIds: [input_.modelId],
8763
+ defaultModelId: input_.modelId,
8764
+ operations: [{
8765
+ operation: "generate",
8766
+ tool: "generate_audio",
8767
+ description: `Create a new ${input_.assetType} audio asset.`,
8768
+ inputs
8769
+ }],
8770
+ referenceRules: {
8771
+ mediaKind: null,
8772
+ completedOnly: false,
8773
+ maxCount: 0
8774
+ },
8775
+ notes
8776
+ };
8777
+ }
8778
+ function getGeneratorCatalog(overrides = {}) {
8779
+ const elevenLabsSpeech = overrides.elevenLabsSpeech ?? "eleven_v3";
8780
+ const elevenLabsMusic = overrides.elevenLabsMusic ?? "music_v1";
8781
+ const elevenLabsSfx = overrides.elevenLabsSfx ?? "eleven_text_to_sound_v2";
8782
+ const lyria = overrides.lyria ?? "lyria-3-clip-preview";
8783
+ return [
8784
+ ...Object.values(IMAGE_MODEL_CAPABILITIES).map(imageGenerator),
8785
+ ...VIDEO_MODEL_SELECTIONS.map(videoGenerator),
8786
+ ...SEEDANCE_2_SELECTIONS.map((selection) => seedanceVideoGenerator(SEEDANCE_2_CAPABILITIES[selection])),
8787
+ audioGenerator({
8788
+ id: "audio/elevenlabs-speech",
8789
+ label: "ElevenLabs Speech",
8790
+ provider: "elevenlabs",
8791
+ assetType: "speech",
8792
+ modelId: elevenLabsSpeech
8793
+ }),
8794
+ audioGenerator({
8795
+ id: "audio/elevenlabs-dialogue",
8796
+ label: "ElevenLabs Dialogue",
8797
+ provider: "elevenlabs",
8798
+ assetType: "dialogue",
8799
+ modelId: elevenLabsSpeech
8800
+ }),
8801
+ audioGenerator({
8802
+ id: "audio/elevenlabs-music",
8803
+ label: "ElevenLabs Music",
8804
+ provider: "elevenlabs",
8805
+ assetType: "music",
8806
+ modelId: elevenLabsMusic
8807
+ }),
8808
+ audioGenerator({
8809
+ id: "audio/elevenlabs-sfx",
8810
+ label: "ElevenLabs Sound Effects",
8811
+ provider: "elevenlabs",
8812
+ assetType: "sfx",
8813
+ modelId: elevenLabsSfx
8814
+ }),
8815
+ audioGenerator({
8816
+ id: "audio/lyria-music",
8817
+ label: "Lyria Music",
8818
+ provider: "lyria",
8819
+ assetType: "music",
8820
+ modelId: lyria
8821
+ })
8822
+ ];
8823
+ }
8824
+ function getGeneratorDefinition(id, overrides = {}) {
8825
+ return getGeneratorCatalog(overrides).find((generator) => generator.id === id);
8826
+ }
8827
+ //#endregion
8828
+ //#region src/shared/generationReferences.ts
8829
+ function isGenerationReference(value) {
8830
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
8831
+ const reference = value;
8832
+ return typeof reference.variantId === "string" && reference.variantId.length > 0 && (reference.mediaKind === "image" || reference.mediaKind === "video" || reference.mediaKind === "audio") && typeof reference.storageKey === "string" && reference.storageKey.length > 0 && Number.isInteger(reference.sequenceIndex) && Number.isInteger(reference.modalityIndex) && (reference.mimeType === void 0 || typeof reference.mimeType === "string") && (reference.sizeBytes === void 0 || typeof reference.sizeBytes === "number") && (reference.width === void 0 || typeof reference.width === "number") && (reference.height === void 0 || typeof reference.height === "number") && (reference.durationMs === void 0 || typeof reference.durationMs === "number");
8833
+ }
8834
+ function areGenerationReferencesIndexed(value) {
8835
+ if (!Array.isArray(value)) return false;
8836
+ const modalityCounts = {
8837
+ image: 0,
8838
+ video: 0,
8839
+ audio: 0
8840
+ };
8841
+ return value.every((reference, sequenceIndex) => {
8842
+ if (!isGenerationReference(reference) || reference.sequenceIndex !== sequenceIndex) return false;
8843
+ const expectedModalityIndex = modalityCounts[reference.mediaKind]++;
8844
+ return reference.modalityIndex === expectedModalityIndex;
8845
+ });
8846
+ }
8847
+ //#endregion
8848
+ //#region src/shared/draftMapping.ts
8849
+ /** Generator input names map to the canonical camel-case keys stored in recipes. */
8850
+ var DRAFT_RECIPE_INPUT_KEYS = {
8851
+ asset_type: "assetType",
8852
+ prompt: "prompt",
8853
+ aspect_ratio: "aspectRatio",
8854
+ image_size: "imageSize",
8855
+ model: "model",
8856
+ voice_id: "voiceId",
8857
+ dialogue_voice_ids: "dialogueVoiceIds",
8858
+ generate_audio: "generateAudio",
8859
+ video_resolution: "videoResolution",
8860
+ resolution: "videoResolution",
8861
+ video_duration_seconds: "videoDurationSeconds",
8862
+ video_tier: "videoTier",
8863
+ duration: "seedanceDuration",
8864
+ bitrate_mode: "seedanceBitrateMode"
8865
+ };
8866
+ var DRAFT_REFERENCE_FIELD = /(?:_variant_refs?|VariantRefs?)$/;
8867
+ /**
8868
+ * The one slot-naming convention used while authoring and resolving Bindings.
8869
+ * Unknown reference slots inherit the Draft output kind.
8870
+ */
8871
+ function mediaKindForDraftSlot(slot, fallback) {
8872
+ if (slot.startsWith("image_") || slot === "start_frame_variant_ref" || slot === "end_frame_variant_ref" || slot === "reference_variant_refs") return "image";
8873
+ if (slot.startsWith("video_")) return "video";
8874
+ if (slot.startsWith("audio_")) return "audio";
8875
+ return fallback;
8876
+ }
8877
+ function generatorIdForDraftRecipe(mediaMode, recipe) {
8878
+ if (mediaMode === "image") {
8879
+ if (recipe.modelProvider === "custom") throw new Error("Custom-provider image Recipes do not map to a Draft generator");
8880
+ const model = typeof recipe.model === "string" ? recipe.model : "pro";
8881
+ if (!isImageModelSelection(model) && !isImageModelId(model)) throw new Error(`Stored image model ${model} does not map to a Draft generator`);
8882
+ return `image/${getImageModelSelection(model)}`;
8883
+ }
8884
+ if (mediaMode === "video") {
8885
+ const model = typeof recipe.model === "string" ? recipe.model : "veo-3.1";
8886
+ const seedance = getSeedance2CapabilityByEndpoint(model);
8887
+ if (seedance) return seedance.generatorId;
8888
+ const selection = getVideoModelSelectionForModel(model);
8889
+ if (!selection) throw new Error(`Stored video model ${model} does not map to a Draft generator`);
8890
+ return `video/${selection}`;
8891
+ }
8892
+ if (mediaMode === "speech") return "audio/elevenlabs-speech";
8893
+ if (mediaMode === "dialogue") return "audio/elevenlabs-dialogue";
8894
+ if (mediaMode === "sfx") return "audio/elevenlabs-sfx";
8895
+ return recipe.musicProvider === "lyria" ? "audio/lyria-music" : "audio/elevenlabs-music";
8896
+ }
8897
+ function mediaModeForDraftRecipe(mediaKind, assetType) {
8898
+ if (mediaKind === "image" || mediaKind === "video") return mediaKind;
8899
+ return getForgeModeForAudioAssetType(assetType);
8900
+ }
8901
+ function buildDraftMapping(args) {
8902
+ const { name, mediaMode, generatorId, recipe, references, destinationKind, destinationAssetId, sourceVariantId } = args;
8903
+ const operation = destinationKind === "sibling" ? "refine" : references.length > 0 ? "derive" : "generate";
8904
+ const operationDefinition = getGeneratorDefinition(generatorId)?.operations.find((candidate) => candidate.operation === operation);
8905
+ if (!operationDefinition) throw new Error(`${generatorId} does not support ${operation} drafts`);
8906
+ const recipeTemplate = { operation };
8907
+ for (const input of operationDefinition.inputs) {
8908
+ const key = DRAFT_RECIPE_INPUT_KEYS[input.name];
8909
+ if (!key) continue;
8910
+ const value = recipe[key];
8911
+ if (value !== void 0) recipeTemplate[key] = value;
8912
+ }
8913
+ const availableSlots = operationDefinition.inputs.filter((input) => DRAFT_REFERENCE_FIELD.test(input.name)).map((input) => input.name);
8914
+ const bindings = [];
8915
+ if (destinationKind === "sibling" && sourceVariantId && availableSlots.includes("source_variant_ref")) bindings.push({
8916
+ slot: "source_variant_ref",
8917
+ sourceKind: "variant",
8918
+ sourceVariantId,
8919
+ sortIndex: 0
8920
+ });
8921
+ const outputMediaKind = getMediaKindForForgeMode(mediaMode);
8922
+ const additionalSlots = availableSlots.filter((slot) => slot !== "source_variant_ref");
8923
+ const usedScalarSlots = /* @__PURE__ */ new Set();
8924
+ for (const [index, reference] of references.entries()) {
8925
+ const targetSlot = additionalSlots.filter((slot) => mediaKindForDraftSlot(slot, outputMediaKind) === reference.mediaKind).find((slot) => slot.endsWith("_refs") || !usedScalarSlots.has(slot));
8926
+ if (!targetSlot) throw new Error(`No ${reference.mediaKind} input slot is available for ${generatorId}`);
8927
+ if (!targetSlot.endsWith("_refs")) usedScalarSlots.add(targetSlot);
8928
+ bindings.push({
8929
+ id: reference.id,
8930
+ slot: targetSlot,
8931
+ sourceKind: reference.sourceKind,
8932
+ sourceVariantId: reference.sourceVariantId,
8933
+ sourceAssetId: reference.sourceAssetId,
8934
+ sourceDraftId: reference.sourceDraftId,
8935
+ sortIndex: index
8936
+ });
8937
+ }
8938
+ return {
8939
+ name,
8940
+ mediaMode,
8941
+ generatorId,
8942
+ recipeTemplate,
8943
+ destinationKind,
8944
+ destinationAssetId: destinationKind === "sibling" ? destinationAssetId : null,
8945
+ bindings
8946
+ };
8947
+ }
8948
+ function materializeDraftFromVariant(args) {
8949
+ const storedRecipe = parseStoredRecipe$1(args.recipe);
8950
+ if (!areGenerationReferencesIndexed(storedRecipe.references)) throw new Error("Variant recipe has invalid references");
8951
+ const mediaMode = args.mediaMode ?? mediaModeForDraftRecipe(args.variantMediaKind, args.assetType ?? stringValue(storedRecipe.assetType));
8952
+ const recipe = args.recipeOverride ?? storedRecipe;
8953
+ const generatorId = args.generatorId ?? generatorIdForDraftRecipe(mediaMode, storedRecipe);
8954
+ const storedOperation = stringValue(storedRecipe.operation);
8955
+ const destinationKind = args.destinationKind ?? (storedOperation === "refine" ? "sibling" : "new_asset");
8956
+ const storedReferences = storedRecipe.references;
8957
+ if (storedOperation === "refine" && destinationKind === "sibling" && storedReferences.length === 0) throw new Error("Stored refine Recipe has no source Variant reference");
8958
+ const preservesStoredRefine = storedOperation === "refine" && destinationKind === "sibling";
8959
+ const sourceVariantId = preservesStoredRefine ? storedReferences[0]?.variantId : destinationKind === "sibling" ? args.variantId : void 0;
8960
+ const additionalReferences = preservesStoredRefine ? storedReferences.slice(1) : storedReferences;
8961
+ return buildDraftMapping({
8962
+ name: args.name?.trim() || args.assetName,
8963
+ mediaMode,
8964
+ generatorId,
8965
+ recipe,
8966
+ references: additionalReferences.map((reference) => ({
8967
+ mediaKind: reference.mediaKind,
8968
+ sourceKind: "variant",
8969
+ sourceVariantId: reference.variantId
8970
+ })),
8971
+ destinationKind,
8972
+ destinationAssetId: destinationKind === "sibling" ? args.destinationAssetId ?? args.assetId : null,
8973
+ sourceVariantId
8974
+ });
8975
+ }
8976
+ function parseStoredRecipe$1(value) {
8977
+ let parsed = value;
8978
+ if (typeof value === "string") try {
8979
+ parsed = JSON.parse(value);
8980
+ } catch {
8981
+ throw new Error("Variant recipe is not valid JSON");
8982
+ }
8983
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Variant recipe is not a JSON object");
8984
+ return parsed;
8985
+ }
8986
+ function stringValue(value) {
8987
+ return typeof value === "string" && value.trim() ? value : void 0;
8988
+ }
8989
+ //#endregion
8363
8990
  //#region src/cli/commands/drafts.ts
8991
+ var CLI_DRAFT_OPTIONS = {
8992
+ list: [],
8993
+ show: [],
8994
+ create: [
8995
+ "from",
8996
+ "name",
8997
+ "media",
8998
+ "generator",
8999
+ "recipe",
9000
+ "destination",
9001
+ "asset",
9002
+ "x",
9003
+ "y"
9004
+ ],
9005
+ update: [
9006
+ "name",
9007
+ "media",
9008
+ "generator",
9009
+ "recipe",
9010
+ "destination",
9011
+ "asset",
9012
+ "x",
9013
+ "y"
9014
+ ],
9015
+ delete: [],
9016
+ run: ["request-id", "wait"]
9017
+ };
8364
9018
  var defaultDeps$7 = {
8365
9019
  loadConfig: loadStoredConfig,
8366
9020
  loadProjectConfig,
8367
9021
  createMutationClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
8368
9022
  print: console.log
8369
9023
  };
9024
+ var defaultGraphDeps = {
9025
+ loadConfig: loadStoredConfig,
9026
+ loadProjectConfig,
9027
+ createClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
9028
+ print: console.log
9029
+ };
8370
9030
  async function handleDrafts(parsed) {
8371
9031
  try {
8372
9032
  await executeDrafts(parsed);
@@ -8383,9 +9043,17 @@ async function handleBindings(parsed) {
8383
9043
  process$1.exitCode = 1;
8384
9044
  }
8385
9045
  }
9046
+ async function handleGraph(parsed) {
9047
+ try {
9048
+ await executeGraph(parsed);
9049
+ } catch (error) {
9050
+ console.error("Error:", error instanceof Error ? error.message : error);
9051
+ process$1.exitCode = 1;
9052
+ }
9053
+ }
8386
9054
  async function executeDrafts(parsed, deps = defaultDeps$7) {
8387
9055
  const subcommand = parsed.positionals[0];
8388
- if (!subcommand) throw new Error("Drafts command is required: list, create, update, or delete");
9056
+ if (!subcommand) throw new Error("Drafts command is required: list, show, create, update, delete, or run");
8389
9057
  rejectUnknownOptions("drafts", subcommand, parsed.options);
8390
9058
  const ctx = await buildContext$3(parsed, deps);
8391
9059
  if (subcommand === "list") {
@@ -8395,12 +9063,75 @@ async function executeDrafts(parsed, deps = defaultDeps$7) {
8395
9063
  return drafts;
8396
9064
  }
8397
9065
  if (subcommand === "create") {
8398
- const name = parsed.positionals.slice(1).join(" ").trim();
9066
+ const fromVariantRef = optionValue$2(parsed.options.from);
9067
+ const name = optionValue$2(parsed.options.name) ?? parsed.positionals.slice(1).join(" ").trim();
9068
+ if (fromVariantRef) {
9069
+ const state = await readDraftState(ctx, deps);
9070
+ const sourceVariantId = requireExactVariantRef$1(fromVariantRef, state);
9071
+ const sourceVariant = state.variants.find((variant) => variant.id === sourceVariantId);
9072
+ const sourceAsset = sourceVariant ? state.assets.find((asset) => asset.id === sourceVariant.asset_id) : void 0;
9073
+ if (!sourceVariant || !sourceAsset) throw new Error("Source Variant is unavailable");
9074
+ if (sourceVariant.status !== "completed") throw new Error("Source Variant must be completed");
9075
+ const destinationKind = parseDestination(parsed.options.destination);
9076
+ const destinationAssetRef = optionValue$2(parsed.options.asset);
9077
+ const mapped = materializeDraftFromVariant({
9078
+ variantId: sourceVariant.id,
9079
+ variantMediaKind: sourceVariant.media_kind,
9080
+ recipe: sourceVariant.recipe,
9081
+ assetName: sourceAsset.name,
9082
+ assetType: sourceAsset.type,
9083
+ assetId: sourceAsset.id,
9084
+ name,
9085
+ mediaMode: parseMediaMode(parsed.options.media),
9086
+ generatorId: optionValue$2(parsed.options.generator),
9087
+ recipeOverride: parseRecipe(parsed.options.recipe),
9088
+ destinationKind,
9089
+ destinationAssetId: destinationAssetRef ? requireAssetRef(destinationAssetRef, state.assets) : void 0
9090
+ });
9091
+ for (const binding of mapped.bindings) {
9092
+ const variantId = binding.sourceVariantId;
9093
+ if (variantId && !state.variants.some((variant) => variant.id === variantId)) throw new Error(`Variant recipe reference ${variantId} is unavailable`);
9094
+ }
9095
+ const created = await withClient(ctx, deps, async (client) => {
9096
+ const draft = await client.createDraft({
9097
+ name: mapped.name,
9098
+ mediaMode: mapped.mediaMode,
9099
+ generatorId: mapped.generatorId,
9100
+ recipeTemplate: mapped.recipeTemplate,
9101
+ destinationKind: mapped.destinationKind,
9102
+ destinationAssetId: mapped.destinationAssetId,
9103
+ canvasX: parseNullableFinite(parsed.options.x, "--x"),
9104
+ canvasY: parseNullableFinite(parsed.options.y, "--y")
9105
+ });
9106
+ const bindings = [];
9107
+ try {
9108
+ for (const binding of mapped.bindings) bindings.push(await client.setBinding({
9109
+ draftId: draft.id,
9110
+ ...binding
9111
+ }));
9112
+ } catch (error) {
9113
+ await client.deleteDraft(draft.id);
9114
+ throw error;
9115
+ }
9116
+ return {
9117
+ draft,
9118
+ bindings
9119
+ };
9120
+ });
9121
+ const resultState = {
9122
+ ...state,
9123
+ drafts: [...state.drafts, created.draft],
9124
+ bindings: [...state.bindings, ...created.bindings]
9125
+ };
9126
+ const result = publicDraft(created.draft, resultState);
9127
+ printJsonOrValue(parsed, deps, result, () => deps.print(`Created Draft ${result.draftRef}`));
9128
+ return created.draft;
9129
+ }
8399
9130
  const mediaMode = parseMediaMode(parsed.options.media);
8400
9131
  const generatorId = optionValue$2(parsed.options.generator);
8401
9132
  const recipeTemplate = parseRecipe(parsed.options.recipe);
8402
9133
  const destinationKind = parseDestination(parsed.options.destination);
8403
- if (!name || !mediaMode || !generatorId || recipeTemplate === void 0 || !destinationKind) throw new Error("Usage: makefx drafts create \"<name>\" --media <mode> --generator <id> --recipe <json> --destination new_asset|sibling [--asset <asset-ref>]");
9134
+ if (!name || !mediaMode || !generatorId || recipeTemplate === void 0 || !destinationKind) throw new Error("Usage: makefx drafts create \"<name>\" --media <mode> --generator <id> --recipe <json> --destination new_asset|sibling [--asset <asset-ref>], or makefx drafts create --from <variant-ref> [--name <name>]");
8404
9135
  const state = await readDraftState(ctx, deps);
8405
9136
  const destinationAssetRef = optionValue$2(parsed.options.asset);
8406
9137
  const destinationAssetId = destinationAssetRef ? requireAssetRef(destinationAssetRef, state.assets) : null;
@@ -8425,6 +9156,52 @@ async function executeDrafts(parsed, deps = defaultDeps$7) {
8425
9156
  if (!draftRef) throw new Error(`Usage: makefx drafts ${subcommand} <draft-ref>`);
8426
9157
  const state = await readDraftState(ctx, deps);
8427
9158
  const draftId = requireDraftRef(draftRef, state.drafts);
9159
+ if (subcommand === "show") {
9160
+ const draft = state.drafts.find((candidate) => candidate.id === draftId);
9161
+ if (!draft) throw new Error("Draft is unavailable");
9162
+ const result = publicDraft(draft, state);
9163
+ printJsonOrValue(parsed, deps, result, () => printDraft(result, deps.print));
9164
+ return result;
9165
+ }
9166
+ if (subcommand === "run") {
9167
+ const requestId = optionValue$2(parsed.options["request-id"]) ?? crypto.randomUUID();
9168
+ const waitSeconds = parsed.options.wait === void 0 ? void 0 : parseGraphWaitSeconds(parsed.options.wait);
9169
+ const run = await withClient(ctx, deps, async (client) => {
9170
+ if (!client.runDraft) throw new Error("The connected client does not support Draft runs");
9171
+ if (waitSeconds !== void 0 && !client.followVariant) throw new Error("The connected client does not support waiting for Draft runs");
9172
+ let outcomePromise;
9173
+ const started = await client.runDraft(draftId, requestId, waitSeconds === void 0 ? void 0 : (runStarted) => {
9174
+ if (runStarted.status !== "completed" && runStarted.status !== "failed") outcomePromise = client.followVariant({
9175
+ variantId: runStarted.variantId,
9176
+ requestId,
9177
+ timeoutMs: waitSeconds * 1e3
9178
+ });
9179
+ });
9180
+ if (waitSeconds === void 0 || started.status === "completed" || started.status === "failed") return {
9181
+ started,
9182
+ terminalStatus: started.status
9183
+ };
9184
+ if (!outcomePromise) throw new Error("Draft run wait was not initialized");
9185
+ return {
9186
+ started,
9187
+ terminalStatus: (await outcomePromise).success ? "completed" : "failed"
9188
+ };
9189
+ });
9190
+ const updatedState = await readDraftState(ctx, deps);
9191
+ const variantRef = variantRefForId(run.started.variantId, updatedState.assets, updatedState.variants);
9192
+ if (!variantRef) throw new Error("Draft run Variant is unavailable");
9193
+ const result = {
9194
+ draftRef,
9195
+ requestId,
9196
+ variantRef,
9197
+ status: run.terminalStatus
9198
+ };
9199
+ printJsonOrValue(parsed, deps, result, () => {
9200
+ deps.print(`${parsed.options.wait === void 0 ? "Started" : "Finished"} ${draftRef} (${run.terminalStatus})`);
9201
+ if (variantRef) deps.print(` Variant: ${variantRef}`);
9202
+ });
9203
+ return result;
9204
+ }
8428
9205
  if (subcommand === "update") {
8429
9206
  const destinationAssetRef = optionValue$2(parsed.options.asset);
8430
9207
  const changes = {
@@ -8495,6 +9272,47 @@ async function executeBindings(parsed, deps = defaultDeps$7) {
8495
9272
  printJsonOrValue(parsed, deps, publicBinding(binding, state), () => deps.print(`Set ${slot}[${sortIndex}] on ${draftRef}`));
8496
9273
  return binding;
8497
9274
  }
9275
+ async function executeGraph(parsed, deps = defaultGraphDeps) {
9276
+ const subcommand = parsed.positionals[0];
9277
+ if (subcommand !== "run" && subcommand !== "status" && subcommand !== "cancel") throw new Error("Graph command is required: run, status, or cancel");
9278
+ rejectGraphUnknownOptions(subcommand, parsed.options);
9279
+ const ctx = await buildContext$3(parsed, deps);
9280
+ const state = await readDraftState(ctx, { createMutationClient: deps.createClient });
9281
+ const client = await deps.createClient(ctx.env, ctx.spaceId);
9282
+ await client.connect();
9283
+ try {
9284
+ if (subcommand === "status" || subcommand === "cancel") {
9285
+ const runRef = parsed.positionals[1];
9286
+ if (!runRef) throw new Error(`Usage: makefx graph ${subcommand} <graph-run-ref>`);
9287
+ const current = await client.getGraphRunStatus(runRef);
9288
+ const status = subcommand === "cancel" ? await client.cancelGraphRun(current.run.id) : current;
9289
+ const result = publicGraphRun(status.run, status.drafts, state);
9290
+ printJsonOrValue(parsed, deps, result, () => {
9291
+ if (subcommand === "cancel") deps.print(`Cancelled pending work in ${runRef}`);
9292
+ printGraphRun(result, deps.print);
9293
+ });
9294
+ return result;
9295
+ }
9296
+ const draftRefs = parsed.positionals.slice(1);
9297
+ if (draftRefs.length === 0) throw new Error("Usage: makefx graph run <draft-ref> [draft-ref...] [--upstream] [--downstream] [--from-scratch] [--wait]");
9298
+ const requestId = optionValue$2(parsed.options["request-id"]) ?? crypto.randomUUID();
9299
+ let status = await client.runGraph({
9300
+ draftIds: draftRefs.map((draftRef) => requireDraftRef(draftRef, state.drafts)),
9301
+ requestId,
9302
+ includeUpstream: parsed.options.upstream === "true",
9303
+ includeDownstream: parsed.options.downstream === "true",
9304
+ fromScratch: parsed.options["from-scratch"] === "true"
9305
+ });
9306
+ const runRef = createGraphRunRef(status.run.id);
9307
+ if (parsed.options.wait !== void 0 && status.run.status === "running") status = await client.waitForGraphRun(runRef, status.run.id, parseGraphWaitSeconds(parsed.options.wait) * 1e3);
9308
+ const freshState = await readDraftState(ctx, { createMutationClient: deps.createClient });
9309
+ const result = publicGraphRun(status.run, status.drafts, freshState);
9310
+ printJsonOrValue(parsed, deps, result, () => printGraphRun(result, deps.print));
9311
+ return result;
9312
+ } finally {
9313
+ client.disconnect();
9314
+ }
9315
+ }
8498
9316
  async function buildContext$3(parsed, deps) {
8499
9317
  const project = await deps.loadProjectConfig();
8500
9318
  const env = resolveCommandEnvironment(parsed, project);
@@ -8655,29 +9473,7 @@ function rejectUnknownOptions(noun, subcommand, options) {
8655
9473
  "local",
8656
9474
  "json"
8657
9475
  ];
8658
- const commands = noun === "drafts" ? {
8659
- list: [],
8660
- create: [
8661
- "media",
8662
- "generator",
8663
- "recipe",
8664
- "destination",
8665
- "asset",
8666
- "x",
8667
- "y"
8668
- ],
8669
- update: [
8670
- "name",
8671
- "media",
8672
- "generator",
8673
- "recipe",
8674
- "destination",
8675
- "asset",
8676
- "x",
8677
- "y"
8678
- ],
8679
- delete: []
8680
- } : {
9476
+ const commands = noun === "drafts" ? CLI_DRAFT_OPTIONS : {
8681
9477
  set: [
8682
9478
  "source",
8683
9479
  "ref",
@@ -8689,6 +9485,50 @@ function rejectUnknownOptions(noun, subcommand, options) {
8689
9485
  const unknown = Object.keys(options).find((name) => !allowed.has(name));
8690
9486
  if (unknown) throw new Error(`Unknown option for ${noun} ${subcommand}: --${unknown}`);
8691
9487
  }
9488
+ function rejectGraphUnknownOptions(subcommand, options) {
9489
+ const allowed = new Set([...[
9490
+ "space",
9491
+ "env",
9492
+ "local",
9493
+ "json"
9494
+ ], ...subcommand === "run" ? [
9495
+ "upstream",
9496
+ "downstream",
9497
+ "from-scratch",
9498
+ "wait",
9499
+ "request-id"
9500
+ ] : []]);
9501
+ const unknown = Object.keys(options).find((name) => !allowed.has(name));
9502
+ if (unknown) throw new Error(`Unknown option for graph ${subcommand}: --${unknown}`);
9503
+ }
9504
+ function parseGraphWaitSeconds(value) {
9505
+ if (value === void 0 || value === "true") return 1800;
9506
+ const seconds = Number(value);
9507
+ if (!Number.isFinite(seconds) || seconds <= 0 || seconds > 3600) throw new Error("--wait must be between 1 and 3600 seconds");
9508
+ return seconds;
9509
+ }
9510
+ function publicGraphRun(run, drafts, state) {
9511
+ return {
9512
+ runRef: createGraphRunRef(run.id),
9513
+ requestId: run.request_id,
9514
+ status: run.status,
9515
+ drafts: drafts.map((item) => {
9516
+ const draft = state.drafts.find((candidate) => candidate.id === item.draft_id);
9517
+ const ancestor = state.drafts.find((candidate) => candidate.id === item.failing_ancestor_draft_id);
9518
+ return {
9519
+ draftRef: draft ? createDraftRef(draft.name, draft.id) : null,
9520
+ status: item.status,
9521
+ variantRef: item.variant_id ? variantRefForId(item.variant_id, state.assets, state.variants) : null,
9522
+ reused: item.reused,
9523
+ failingAncestorDraftRef: ancestor ? createDraftRef(ancestor.name, ancestor.id) : null
9524
+ };
9525
+ })
9526
+ };
9527
+ }
9528
+ function printGraphRun(result, print) {
9529
+ print(`${result.runRef} (${result.status})`);
9530
+ for (const draft of result.drafts) print(` ${draft.draftRef ?? "unavailable draft"}: ${draft.status}${draft.variantRef ? ` → ${draft.variantRef}` : ""}`);
9531
+ }
8692
9532
  function printJsonOrValue(parsed, deps, value, printHuman) {
8693
9533
  if (parsed.options.json === "true") deps.print(JSON.stringify(value, null, 2));
8694
9534
  else printHuman();
@@ -8700,6 +9540,20 @@ function printDrafts(drafts, print) {
8700
9540
  }
8701
9541
  for (const draft of drafts) print(`${draft.draftRef} ${draft.mediaMode} ${draft.status} ${draft.name}`);
8702
9542
  }
9543
+ function printDraft(draft, print) {
9544
+ print(`${draft.draftRef} ${draft.name}`);
9545
+ print(` Media: ${draft.mediaMode} (${draft.generatorId})`);
9546
+ print(` Destination: ${draft.destination}${draft.destinationAssetRef ? ` → ${draft.destinationAssetRef}` : ""}`);
9547
+ print(` Recipe: ${JSON.stringify(draft.recipeTemplate)}`);
9548
+ const bindings = draft.bindings;
9549
+ print(" Bindings:");
9550
+ if (bindings.length === 0) print(" none");
9551
+ else for (const binding of bindings) {
9552
+ const broken = binding.broken ? ` [broken${binding.brokenReason ? `: ${binding.brokenReason}` : ""}]` : "";
9553
+ print(` ${binding.slot}[${binding.sortIndex}]: ${binding.sourceKind} → ${binding.sourceRef ?? "unavailable"}${broken}`);
9554
+ }
9555
+ print(` Last run: ${draft.lastRunVariantRef ?? "none"}`);
9556
+ }
8703
9557
  //#endregion
8704
9558
  //#region src/cli/commands/image.ts
8705
9559
  async function handleImage(parsed) {
@@ -9749,6 +10603,33 @@ var defaultDeps$2 = {
9749
10603
  print: console.log
9750
10604
  };
9751
10605
  var UploadUsageError = class extends Error {};
10606
+ var LINEAGE_RELATION_TYPES = new Set([
10607
+ "derived",
10608
+ "refined",
10609
+ "forked"
10610
+ ]);
10611
+ function parseLineageOption(raw, defaultRelationType) {
10612
+ if (!raw) return [];
10613
+ const entries = raw.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
10614
+ if (entries.length === 0) throw new UploadUsageError("--lineage requires at least one compact variant ref");
10615
+ return entries.map((entry) => {
10616
+ const atIndex = entry.lastIndexOf("@");
10617
+ const separator = entry.lastIndexOf(":");
10618
+ let ref = entry;
10619
+ let relationType = defaultRelationType;
10620
+ if (atIndex !== -1 && separator > atIndex) {
10621
+ const suffix = entry.slice(separator + 1);
10622
+ if (!LINEAGE_RELATION_TYPES.has(suffix)) throw new UploadUsageError(`--lineage relation in "${entry}" must be derived, refined, or forked`);
10623
+ ref = entry.slice(0, separator);
10624
+ relationType = suffix;
10625
+ }
10626
+ if (!ref.startsWith("asset:")) throw new UploadUsageError(`--lineage requires compact variant refs, got "${ref}"`);
10627
+ return {
10628
+ ref,
10629
+ relationType
10630
+ };
10631
+ });
10632
+ }
9752
10633
  async function handleUpload(parsed) {
9753
10634
  try {
9754
10635
  await executeUpload(parsed);
@@ -9773,6 +10654,7 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
9773
10654
  const jsonOutput = parsed.options.json === "true";
9774
10655
  if (!spaceId) throw new UploadUsageError("--space is required, or run: makefx init --space <id>");
9775
10656
  if (!assetId && !assetName) throw new UploadUsageError("Either --asset or --name is required");
10657
+ const lineageEntries = parseLineageOption(parsed.options.lineage, assetId ? "refined" : "derived");
9776
10658
  const mediaType = resolveMediaType(path.extname(filePath).toLowerCase(), requestedMediaKind);
9777
10659
  const config = await deps.loadConfig(env);
9778
10660
  if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
@@ -9780,7 +10662,16 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
9780
10662
  const baseUrl = deps.resolveBaseUrl(env);
9781
10663
  const accessToken = config.token.accessToken;
9782
10664
  const createStateClient = () => (deps.createStateClient ?? defaultDeps$2.createStateClient)(env, spaceId);
9783
- if (assetId) assetId = await resolveCliAssetIdentifier(assetId, createStateClient);
10665
+ let lineage = [];
10666
+ if (assetId || lineageEntries.length > 0) {
10667
+ if (assetId && !assetId.startsWith("asset:")) throw new Error("A compact asset ref is required");
10668
+ const state = await readReferenceSpaceState(createStateClient);
10669
+ if (assetId) assetId = resolveAssetRef(assetId, state.assets);
10670
+ lineage = lineageEntries.map((entry) => ({
10671
+ parentVariantId: resolveVariantRef(entry.ref, state.assets, state.variants),
10672
+ relationType: entry.relationType
10673
+ }));
10674
+ }
9784
10675
  if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
9785
10676
  try {
9786
10677
  const fileStat = await deps.stat(filePath);
@@ -9798,11 +10689,13 @@ async function executeUpload(parsed, deps = defaultDeps$2) {
9798
10689
  formData.append("assetName", assetName);
9799
10690
  formData.append("assetType", assetType);
9800
10691
  }
10692
+ if (lineage.length > 0) formData.append("lineage", JSON.stringify(lineage));
9801
10693
  if (!jsonOutput) {
9802
10694
  deps.print(`\nUploading "${fileName}" to space ${spaceId}...`);
9803
10695
  deps.print(` Media kind: ${mediaType.mediaKind}`);
9804
10696
  if (assetId) deps.print(` Target asset: ${requestedAssetRef}`);
9805
10697
  else deps.print(` Creating asset: "${assetName}" (${assetType})`);
10698
+ for (const entry of lineageEntries) deps.print(` Lineage: ${entry.relationType} from ${entry.ref}`);
9806
10699
  }
9807
10700
  const response = await deps.fetch(`${baseUrl}/api/spaces/${spaceId}/upload`, {
9808
10701
  method: "POST",
@@ -9888,6 +10781,7 @@ function rejectUnknownUploadOptions(options) {
9888
10781
  "name",
9889
10782
  "type",
9890
10783
  "media-kind",
10784
+ "lineage",
9891
10785
  "json"
9892
10786
  ]);
9893
10787
  const unknown = Object.keys(options).find((name) => !allowed.has(name));
@@ -9905,6 +10799,9 @@ Options:
9905
10799
  --name <name> New asset name (creates asset + variant)
9906
10800
  --type <type> Asset type for new assets (default: character)
9907
10801
  --media-kind <k> Optional explicit kind: image, audio, or video
10802
+ --lineage <refs> Source variant refs this upload was made from, comma-separated,
10803
+ each optionally suffixed :derived, :refined, or :forked
10804
+ (default: refined with --asset, derived with --name)
9908
10805
  --json Print machine-readable output
9909
10806
  --env <env> Environment (production|stage|local)
9910
10807
  --local Shortcut for --env local
@@ -9912,6 +10809,7 @@ Options:
9912
10809
  Examples:
9913
10810
  makefx assets upload hero.png --name "Hero Character"
9914
10811
  makefx assets upload paintover.png --asset asset:hero~27f8f176
10812
+ makefx assets upload paintover.png --asset asset:hero~27f8f176 --lineage asset:hero~27f8f176@active
9915
10813
  `);
9916
10814
  }
9917
10815
  //#endregion
@@ -10317,15 +11215,45 @@ async function handleVideo(parsed) {
10317
11215
  }
10318
11216
  }
10319
11217
  //#endregion
10320
- //#region src/cli/index.ts
10321
- var CLI_VERSION = "1.4.0+d9f20045c1b1";
11218
+ //#region src/cli/help.ts
11219
+ var TOP_LEVEL_HELP = `Make Effects CLI
11220
+
11221
+ Creative:
11222
+ models list | show
11223
+ image generate | regenerate
11224
+ video generate | regenerate
11225
+ audio speech|dialogue|music|sfx generate|regenerate
11226
+ audio voices
11227
+ audio align
11228
+
11229
+ Assets:
11230
+ assets list | show | update | delete | upload | download
11231
+ variants show | update | activate | retry | delete
11232
+ collections list | show | create | update | delete | add | remove | pin | unpin
11233
+ drafts list | show | create | update | delete | run
11234
+ bindings set | clear
11235
+ graph run | status | cancel
11236
+
11237
+ Workspace:
11238
+ spaces list | show | create | delete | lens
11239
+ init | login | logout
11240
+ usage | spend | billing
11241
+
11242
+ Assets and variants use compact refs:
11243
+ asset:name~prefix
11244
+ asset:name~prefix@variant
11245
+
11246
+ Run makefx help <noun> for details.`;
10322
11247
  var HELP = {
10323
11248
  image: `Usage:
10324
- makefx image generate "prompt" --name <name> --type <type> -o <file> [--model pro|flash|flux] [--refs <variant-ref-or-file,...>]
11249
+ makefx image generate "prompt" --name <name> --type <type> -o <file> [--model pro|flash|flux] [--refs <variant-ref-or-file,...>] [--aspect <ratio>] [--size 1K|2K|4K] [--collection <id>] [--space <id>]
10325
11250
  makefx image regenerate <variant-ref> ["prompt"] [--model pro|flash|flux] [--aspect <ratio>] [--size <size>] [--refs <refs>] [--no-activate] [--wait]`,
10326
11251
  video: `Usage:
10327
11252
  makefx video generate "prompt" --name <name> --type <type> -o <file> [--model veo-3.1|omni-flash|kling|seedance-1|seedance-2|seedance-2-fast]
10328
- makefx video regenerate <variant-ref> ["prompt"] [--model <model>] [--aspect <ratio>] [--resolution <value>] [--duration <seconds>] [--no-activate] [--wait]
11253
+ [--refs <variant-ref-or-file,...>] [--first-frame <ref>] [--last-frame <ref>] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>]
11254
+ [--aspect <ratio>] [--resolution 480p|720p|1080p|4k] [--duration <seconds|auto>] [--tier generate|fast|lite] [--bitrate standard|high]
11255
+ [--audio | --no-audio] [--collection <id>] [--space <id>]
11256
+ makefx video regenerate <variant-ref> ["prompt"] [--model <model>] [--aspect <ratio>] [--resolution <value>] [--duration <seconds>] [--tier <tier>] [--bitrate standard|high] [--audio | --no-audio] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>] [--no-activate] [--wait]
10329
11257
 
10330
11258
  Seedance mode is inferred: first/last frame selects frame mode, image/video/audio refs select reference mode, and no references selects text mode.`,
10331
11259
  audio: `Usage:
@@ -10339,7 +11267,9 @@ Seedance mode is inferred: first/last frame selects frame mode, image/video/audi
10339
11267
  makefx audio music generate "prompt" --model eleven-music|lyria-3 --name <name> -o <file>
10340
11268
  makefx audio music regenerate <variant-ref> ["prompt"] [--model eleven-music|lyria-3] [--no-activate] [--wait]
10341
11269
  makefx audio sfx generate "prompt" --name <name> -o <file>
10342
- makefx audio sfx regenerate <variant-ref> ["prompt"] [--no-activate] [--wait]`,
11270
+ makefx audio sfx regenerate <variant-ref> ["prompt"] [--no-activate] [--wait]
11271
+
11272
+ Generate commands also accept [--collection <id>] [--space <id>].`,
10343
11273
  models: `Usage:
10344
11274
  makefx models list [--media image|video|audio] [--available] [--json]
10345
11275
  makefx models show <model> [--json]`,
@@ -10348,8 +11278,12 @@ Seedance mode is inferred: first/last frame selects frame mode, image/video/audi
10348
11278
  makefx assets show <asset-ref> [--json]
10349
11279
  makefx assets update <asset-ref> [--name <name>] [--type <type>] [--tags <tag,...>]
10350
11280
  makefx assets delete <asset-ref> [--yes]
10351
- makefx assets upload <file> (--name <name> | --asset <asset-ref>) [--type <type>]
10352
- makefx assets download <variant-ref> -o <file>`,
11281
+ makefx assets upload <file> (--name <name> | --asset <asset-ref>) [--type <type>] [--lineage <variant-ref[:relation],...>]
11282
+ makefx assets download <variant-ref> -o <file>
11283
+
11284
+ Upload --lineage records which variants the file was made from: comma-separated
11285
+ compact variant refs, each optionally suffixed :derived, :refined, or :forked
11286
+ (default: refined when uploading to --asset, derived when creating with --name).`,
10353
11287
  variants: `Usage:
10354
11288
  makefx variants show <variant-ref> [--wait <seconds>] [--json]
10355
11289
  makefx variants update <variant-ref> [--starred true|false] [--rating approved|rejected|none]
@@ -10368,9 +11302,15 @@ Seedance mode is inferred: first/last frame selects frame mode, image/video/audi
10368
11302
  makefx collections unpin <collection-id>`,
10369
11303
  drafts: `Usage:
10370
11304
  makefx drafts list [--json]
10371
- makefx drafts create "<name>" --media <mode> --generator <id> --recipe <json> --destination new_asset|sibling [--asset <asset-ref>]
10372
- makefx drafts update <draft-ref> [--name <name>] [--recipe <json>] [--destination new_asset|sibling] [--asset <asset-ref|none>]
10373
- makefx drafts delete <draft-ref>`,
11305
+ makefx drafts show <draft-ref> [--json]
11306
+ makefx drafts create ("<name>" --media <mode> --generator <id> --recipe <json> | --from <variant-ref> [--name <name>]) [--destination new_asset|sibling] [--asset <asset-ref>] [--x <number>] [--y <number>]
11307
+ makefx drafts update <draft-ref> [--name <name>] [--media <mode>] [--generator <id>] [--recipe <json>] [--destination new_asset|sibling] [--asset <asset-ref|none>] [--x <number|null>] [--y <number|null>]
11308
+ makefx drafts delete <draft-ref>
11309
+ makefx drafts run <draft-ref> [--request-id <id>] [--wait [seconds]]`,
11310
+ graph: `Usage:
11311
+ makefx graph run <draft-ref> [draft-ref...] [--upstream] [--downstream] [--from-scratch] [--wait [seconds]]
11312
+ makefx graph status <graph-run-ref> [--json]
11313
+ makefx graph cancel <graph-run-ref> [--json]`,
10374
11314
  bindings: `Usage:
10375
11315
  makefx bindings set <draft-ref> <slot> --source variant|asset-active|draft-output --ref <ref> [--sort <index>]
10376
11316
  makefx bindings clear <draft-ref> <slot> [--sort <index>]`,
@@ -10391,34 +11331,11 @@ Seedance mode is inferred: first/last frame selects frame mode, image/video/audi
10391
11331
  makefx billing reconcile
10392
11332
  makefx billing retry-failed`
10393
11333
  };
11334
+ //#endregion
11335
+ //#region src/cli/index.ts
11336
+ var CLI_VERSION = "1.5.0+27ffb5049678";
10394
11337
  function printHelp() {
10395
- console.log(`Make Effects CLI
10396
-
10397
- Creative:
10398
- models list | show
10399
- image generate | regenerate
10400
- video generate | regenerate
10401
- audio speech|dialogue|music|sfx generate|regenerate
10402
- audio voices
10403
- audio align
10404
-
10405
- Assets:
10406
- assets list | show | update | delete | upload | download
10407
- variants show | update | activate | retry | delete
10408
- collections list | show | create | update | delete | add | remove | pin | unpin
10409
- drafts list | create | update | delete
10410
- bindings set | clear
10411
-
10412
- Workspace:
10413
- spaces list | show | create | delete | lens
10414
- init | login | logout
10415
- usage | spend | billing
10416
-
10417
- Assets and variants use compact refs:
10418
- asset:name~prefix
10419
- asset:name~prefix@variant
10420
-
10421
- Run makefx help <noun> for details.`);
11338
+ console.log(TOP_LEVEL_HELP);
10422
11339
  }
10423
11340
  function printCommandHelp(noun) {
10424
11341
  if (!noun) {
@@ -10449,6 +11366,7 @@ async function dispatchCommand(command, parsed) {
10449
11366
  case "collections": return handleCollections(parsed);
10450
11367
  case "drafts": return handleDrafts(parsed);
10451
11368
  case "bindings": return handleBindings(parsed);
11369
+ case "graph": return handleGraph(parsed);
10452
11370
  case "usage": return handleUsage(parsed);
10453
11371
  case "spend": return handleSpend(parsed);
10454
11372
  case "variants": return handleVariants(parsed);