@vibeframe/cli 0.104.3 → 0.105.1

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 (2) hide show
  1. package/dist/index.js +250 -34
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -17106,6 +17106,53 @@ function pickReferenceImageUrl(input) {
17106
17106
  return input;
17107
17107
  return void 0;
17108
17108
  }
17109
+ function isFalFileInput(value) {
17110
+ return value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:");
17111
+ }
17112
+ async function normaliseReferences(input, client) {
17113
+ if (!input)
17114
+ return [];
17115
+ const references = [];
17116
+ for (const ref of input) {
17117
+ if (!isFalFileInput(ref.url))
17118
+ continue;
17119
+ references.push({
17120
+ ...ref,
17121
+ url: ref.url.startsWith("data:") ? await uploadDataUri(client, ref.url) : ref.url
17122
+ });
17123
+ }
17124
+ return references;
17125
+ }
17126
+ async function uploadDataUri(client, dataUri) {
17127
+ const blob = dataUriToBlob(dataUri);
17128
+ return client.storage.upload(blob, {
17129
+ lifecycle: { expiresIn: "1h" }
17130
+ });
17131
+ }
17132
+ function dataUriToBlob(dataUri) {
17133
+ const match = /^data:([^;,]+)?(;base64)?,(.*)$/s.exec(dataUri);
17134
+ if (!match)
17135
+ throw new Error("Invalid data URI reference.");
17136
+ const mimeType = match[1] || "application/octet-stream";
17137
+ const isBase64 = Boolean(match[2]);
17138
+ const payload = match[3] ?? "";
17139
+ const buffer = isBase64 ? Buffer.from(payload, "base64") : Buffer.from(decodeURIComponent(payload), "utf-8");
17140
+ return new Blob([new Uint8Array(buffer)], { type: mimeType });
17141
+ }
17142
+ function groupReferences(references) {
17143
+ const image_urls = [];
17144
+ const video_urls = [];
17145
+ const audio_urls = [];
17146
+ for (const ref of references) {
17147
+ if (ref.kind === "image")
17148
+ image_urls.push(ref.url);
17149
+ if (ref.kind === "video")
17150
+ video_urls.push(ref.url);
17151
+ if (ref.kind === "audio")
17152
+ audio_urls.push(ref.url);
17153
+ }
17154
+ return { image_urls, video_urls, audio_urls };
17155
+ }
17109
17156
  function normaliseAspect(value) {
17110
17157
  if (!value)
17111
17158
  return "auto";
@@ -17128,7 +17175,7 @@ function normaliseDuration(value) {
17128
17175
  return "auto";
17129
17176
  return Math.max(4, Math.min(15, Math.round(value)));
17130
17177
  }
17131
- var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, DEFAULT_VARIANT, VALID_RESOLUTIONS, VALID_ASPECTS, FalProvider, falProvider;
17178
+ var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, ENDPOINT_REFERENCE_TO_VIDEO, DEFAULT_VARIANT, VALID_RESOLUTIONS, VALID_ASPECTS, FalProvider, falProvider;
17132
17179
  var init_FalProvider = __esm({
17133
17180
  "../ai-providers/dist/fal/FalProvider.js"() {
17134
17181
  "use strict";
@@ -17141,6 +17188,10 @@ var init_FalProvider = __esm({
17141
17188
  "seedance-2.0": "bytedance/seedance-2.0/image-to-video",
17142
17189
  "seedance-2.0-fast": "bytedance/seedance-2.0/fast/image-to-video"
17143
17190
  };
17191
+ ENDPOINT_REFERENCE_TO_VIDEO = {
17192
+ "seedance-2.0": "bytedance/seedance-2.0/reference-to-video",
17193
+ "seedance-2.0-fast": "bytedance/seedance-2.0/fast/reference-to-video"
17194
+ };
17144
17195
  DEFAULT_VARIANT = "seedance-2.0";
17145
17196
  VALID_RESOLUTIONS = ["480p", "720p", "1080p"];
17146
17197
  VALID_ASPECTS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "auto"];
@@ -17149,7 +17200,7 @@ var init_FalProvider = __esm({
17149
17200
  this.id = "seedance";
17150
17201
  this.name = "fal.ai (Seedance 2.0)";
17151
17202
  this.description = "fal.ai hosting ByteDance Seedance 2.0 \u2014 Artificial Analysis #2 on both text-to-video and image-to-video leaderboards";
17152
- this.capabilities = ["text-to-video", "image-to-video"];
17203
+ this.capabilities = ["text-to-video", "image-to-video", "reference-to-video"];
17153
17204
  this.iconUrl = "/icons/fal.svg";
17154
17205
  this.isAvailable = true;
17155
17206
  }
@@ -17188,9 +17239,11 @@ var init_FalProvider = __esm({
17188
17239
  error: `Unknown Seedance variant: ${variant}. Valid: ${Object.keys(ENDPOINT_TEXT_TO_VIDEO).join(", ")}.`
17189
17240
  };
17190
17241
  }
17191
- const referenceImage = pickReferenceImageUrl(options?.referenceImage);
17242
+ const references = await normaliseReferences(options?.references, this.client);
17243
+ const hasReferences = references.length > 0;
17244
+ const referenceImage = hasReferences ? void 0 : pickReferenceImageUrl(options?.referenceImage);
17192
17245
  const isImageToVideo = !!referenceImage;
17193
- const endpointId = isImageToVideo ? ENDPOINT_IMAGE_TO_VIDEO[variant] : ENDPOINT_TEXT_TO_VIDEO[variant];
17246
+ const endpointId = hasReferences ? ENDPOINT_REFERENCE_TO_VIDEO[variant] : isImageToVideo ? ENDPOINT_IMAGE_TO_VIDEO[variant] : ENDPOINT_TEXT_TO_VIDEO[variant];
17194
17247
  const aspect = normaliseAspect(options?.aspectRatio);
17195
17248
  const resolution = normaliseResolution(options?.resolution);
17196
17249
  const duration = normaliseDuration(options?.duration);
@@ -17200,13 +17253,26 @@ var init_FalProvider = __esm({
17200
17253
  resolution,
17201
17254
  duration
17202
17255
  };
17203
- if (referenceImage)
17256
+ if (hasReferences) {
17257
+ const grouped = groupReferences(references);
17258
+ if (grouped.image_urls.length > 0)
17259
+ input.image_urls = grouped.image_urls;
17260
+ if (grouped.video_urls.length > 0)
17261
+ input.video_urls = grouped.video_urls;
17262
+ if (grouped.audio_urls.length > 0)
17263
+ input.audio_urls = grouped.audio_urls;
17264
+ } else if (referenceImage) {
17204
17265
  input.image_url = referenceImage;
17266
+ }
17205
17267
  if (options?.negativePrompt)
17206
17268
  input.negative_prompt = options.negativePrompt;
17207
17269
  if (typeof options?.seed === "number")
17208
17270
  input.seed = options.seed;
17209
- if (options?.lastFrame)
17271
+ if (typeof options?.generateAudio === "boolean")
17272
+ input.generate_audio = options.generateAudio;
17273
+ if (options?.endUserId)
17274
+ input.end_user_id = options.endUserId;
17275
+ if (!hasReferences && options?.lastFrame)
17210
17276
  input.end_image_url = options.lastFrame;
17211
17277
  try {
17212
17278
  const out = await this.client.subscribe(endpointId, { input, logs: false });
@@ -17253,14 +17319,15 @@ var init_fal = __esm({
17253
17319
  // Review this alias at the 1.0 cut.
17254
17320
  aliases: ["fal"],
17255
17321
  models: ["seedance-2.0", "seedance-2.0-fast"],
17256
- capabilities: ["text-to-video", "image-to-video", "native-audio"],
17322
+ capabilities: ["text-to-video", "image-to-video", "reference-to-video", "native-audio"],
17257
17323
  apiKey: "fal",
17258
17324
  kinds: ["video"],
17259
17325
  resolverPriority: { video: 1 },
17260
17326
  commandsUnlocked: [
17261
17327
  "generate video -p seedance (Seedance 2.0 via fal.ai \u2014 default since v0.57)",
17262
17328
  "generate video -p seedance --seedance-model fast (lower-latency variant)",
17263
- "generate video -p seedance -i <image> (image-to-video)"
17329
+ "generate video -p seedance -i <image> (image-to-video)",
17330
+ "generate video -p seedance --ref-images <images...> (reference-to-video)"
17264
17331
  ]
17265
17332
  });
17266
17333
  }
@@ -26553,6 +26620,33 @@ consult this file \u2014 run the generate command directly.
26553
26620
  Browse named styles: \`vibe scene list-styles\`. Re-seed from one with
26554
26621
  \`vibe scene init . --visual-style "Swiss Pulse"\` (idempotent).
26555
26622
 
26623
+ ## Brief and local media
26624
+
26625
+ \`brief.md\` is raw intent, not a strict schema. It may contain messy notes,
26626
+ pasted research, links, product requirements, or a one-line idea. \`vibe init
26627
+ --from brief.md\` uses it only to seed \`STORYBOARD.md\` and \`DESIGN.md\`;
26628
+ after init, those two files are the working source of truth.
26629
+
26630
+ Use \`media/\` for user-provided source files: product photos, screenshots,
26631
+ logos, B-roll, recorded narration, or reference clips. Keep those inputs
26632
+ inside this project so build references stay project-relative. Do not put user
26633
+ media in \`references/\`; that directory is reserved for local composition
26634
+ rules installed by VibeFrame.
26635
+
26636
+ When a beat should reuse a local file, reference it from \`STORYBOARD.md\`
26637
+ with a project-relative path:
26638
+
26639
+ \`\`\`yaml
26640
+ backdrop: "media/product-shot.png" # existing still image
26641
+ video: "media/broll.mp4" # existing video/B-roll
26642
+ narration: "media/voice.wav" # existing recorded narration
26643
+ asset: "media/logo.png" # generic local asset reference
26644
+ \`\`\`
26645
+
26646
+ Use text cues when you want VibeFrame to generate an asset. Use path cues
26647
+ when you want VibeFrame to reuse a local file. Avoid absolute paths or parent
26648
+ directory references; copy files into \`media/\` first.
26649
+
26556
26650
  ## Provider keys and project scope
26557
26651
 
26558
26652
  Use VibeFrame CLI generation for project assets:
@@ -26600,9 +26694,11 @@ the framework-level minimum, not the cinematic craft layer.
26600
26694
 
26601
26695
  - \`DESIGN.md\` \u2014 visual identity contract (palette, type, motion, transitions)
26602
26696
  - \`STORYBOARD.md\` \u2014 per-beat narration/backdrop/duration cues for \`vibe build\`
26697
+ - \`media/\` \u2014 user-provided source files (photos, logos, clips, voice recordings)
26603
26698
  - \`index.html\` \u2014 root composition (timeline)
26604
26699
  - \`compositions/scene-*.html\` \u2014 per-scene HTML authored by you or the agent
26605
- - \`assets/\` \u2014 shared media (narration audio, images, video)
26700
+ - \`assets/\` \u2014 generated/canonical build media (narration audio, images, video)
26701
+ - \`references/\` \u2014 composition rule docs installed by VibeFrame, not user media
26606
26702
  - \`transcript.json\` \u2014 Whisper word-level transcript (if narration exists)
26607
26703
  - \`hyperframes.json\` \u2014 HF registry config (speak to both toolchains)
26608
26704
  - \`vibe.config.json\` \u2014 canonical VibeFrame config (providers, budget)
@@ -26750,7 +26846,11 @@ async function scaffoldSceneProject(opts) {
26750
26846
  if (await pathExists(metaPath)) {
26751
26847
  skipped2.push(metaPath);
26752
26848
  } else {
26753
- await writeFile4(metaPath, JSON.stringify(buildHyperframesMeta(name, now), null, 2) + "\n", "utf-8");
26849
+ await writeFile4(
26850
+ metaPath,
26851
+ JSON.stringify(buildHyperframesMeta(name, now), null, 2) + "\n",
26852
+ "utf-8"
26853
+ );
26754
26854
  created.push(metaPath);
26755
26855
  }
26756
26856
  const rootPath = resolve7(dir, "index.html");
@@ -26765,11 +26865,7 @@ async function scaffoldSceneProject(opts) {
26765
26865
  if (await pathExists(vibeConfigJsonPath)) {
26766
26866
  skipped2.push(vibeConfigJsonPath);
26767
26867
  } else {
26768
- await writeFile4(
26769
- vibeConfigJsonPath,
26770
- projectConfigJson({ name, aspect }),
26771
- "utf-8"
26772
- );
26868
+ await writeFile4(vibeConfigJsonPath, projectConfigJson({ name, aspect }), "utf-8");
26773
26869
  created.push(vibeConfigJsonPath);
26774
26870
  }
26775
26871
  const vibePath = resolve7(dir, "vibe.project.yaml");
@@ -26808,11 +26904,7 @@ ${existing}`, "utf-8");
26808
26904
  if (await pathExists(designPath)) {
26809
26905
  skipped2.push(designPath);
26810
26906
  } else {
26811
- await writeFile4(
26812
- designPath,
26813
- buildDesignMd({ name, style: opts.visualStyle }),
26814
- "utf-8"
26815
- );
26907
+ await writeFile4(designPath, buildDesignMd({ name, style: opts.visualStyle }), "utf-8");
26816
26908
  created.push(designPath);
26817
26909
  }
26818
26910
  const storyboardPath2 = resolve7(dir, "STORYBOARD.md");
@@ -33820,6 +33912,9 @@ async function executeVideoGenerate(options) {
33820
33912
  prompt: prompt3,
33821
33913
  provider = "kling",
33822
33914
  image,
33915
+ refImages,
33916
+ refVideos,
33917
+ refAudio,
33823
33918
  duration = 5,
33824
33919
  ratio = "16:9",
33825
33920
  seed,
@@ -33828,6 +33923,7 @@ async function executeVideoGenerate(options) {
33828
33923
  resolution,
33829
33924
  veoModel = "3.1-fast",
33830
33925
  seedanceModel = "quality",
33926
+ generateAudio,
33831
33927
  output,
33832
33928
  wait = true,
33833
33929
  apiKey
@@ -33866,8 +33962,13 @@ async function executeVideoGenerate(options) {
33866
33962
  if (provider === "seedance" || provider === "fal") {
33867
33963
  const fal = new FalProvider();
33868
33964
  await fal.initialize({ apiKey: key });
33965
+ const references = await prepareSeedanceReferences({
33966
+ refImages,
33967
+ refVideos,
33968
+ refAudio
33969
+ });
33869
33970
  let falImage = referenceImage;
33870
- if (falImage && falImage.startsWith("data:")) {
33971
+ if (falImage && falImage.startsWith("data:") && references.length === 0) {
33871
33972
  const uploadHost = await resolveUploadHost();
33872
33973
  const upload = await uploadHost.uploadImage(referenceImageBuffer, {
33873
33974
  filename: image,
@@ -33878,11 +33979,14 @@ async function executeVideoGenerate(options) {
33878
33979
  const model = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
33879
33980
  const result = await fal.generateVideo(prompt3, {
33880
33981
  prompt: prompt3,
33881
- referenceImage: falImage,
33982
+ referenceImage: references.length > 0 ? void 0 : falImage,
33983
+ references: references.length > 0 ? references : void 0,
33882
33984
  duration,
33883
33985
  aspectRatio: ratio,
33884
33986
  negativePrompt: negative,
33885
- model
33987
+ model,
33988
+ resolution,
33989
+ generateAudio
33886
33990
  });
33887
33991
  if (result.status === "failed")
33888
33992
  return { success: false, error: result.error || "Seedance generation failed" };
@@ -34059,6 +34163,54 @@ async function executeVideoGenerate(options) {
34059
34163
  };
34060
34164
  }
34061
34165
  }
34166
+ async function prepareSeedanceReferences(opts) {
34167
+ const references = [];
34168
+ for (const sourcePath of opts.refImages ?? []) {
34169
+ references.push({
34170
+ kind: "image",
34171
+ url: await fileInputToUrlOrDataUri(sourcePath, "image/png"),
34172
+ sourcePath
34173
+ });
34174
+ }
34175
+ for (const sourcePath of opts.refVideos ?? []) {
34176
+ references.push({
34177
+ kind: "video",
34178
+ url: await fileInputToUrlOrDataUri(sourcePath, "video/mp4"),
34179
+ sourcePath
34180
+ });
34181
+ }
34182
+ for (const sourcePath of opts.refAudio ?? []) {
34183
+ references.push({
34184
+ kind: "audio",
34185
+ url: await fileInputToUrlOrDataUri(sourcePath, "audio/mpeg"),
34186
+ sourcePath
34187
+ });
34188
+ }
34189
+ return references;
34190
+ }
34191
+ async function fileInputToUrlOrDataUri(input, fallbackMimeType) {
34192
+ if (input.startsWith("http://") || input.startsWith("https://") || input.startsWith("data:")) {
34193
+ return input;
34194
+ }
34195
+ const absPath = resolve23(process.cwd(), input);
34196
+ const buffer = await readFile15(absPath);
34197
+ return `data:${mimeTypeForPath(input, fallbackMimeType)};base64,${buffer.toString("base64")}`;
34198
+ }
34199
+ function mimeTypeForPath(path2, fallback2) {
34200
+ const ext = path2.toLowerCase().split(".").pop();
34201
+ const mimeTypes2 = {
34202
+ jpg: "image/jpeg",
34203
+ jpeg: "image/jpeg",
34204
+ png: "image/png",
34205
+ gif: "image/gif",
34206
+ webp: "image/webp",
34207
+ mp4: "video/mp4",
34208
+ mov: "video/quicktime",
34209
+ mp3: "audio/mpeg",
34210
+ wav: "audio/wav"
34211
+ };
34212
+ return mimeTypes2[ext || ""] || fallback2;
34213
+ }
34062
34214
  async function executeVideoStatus(options) {
34063
34215
  const {
34064
34216
  taskId,
@@ -36312,10 +36464,10 @@ var init_provider_resolver = __esm({
36312
36464
 
36313
36465
  // src/commands/_shared/openai-image.ts
36314
36466
  function resolveOpenAIImageModel(modelAlias) {
36315
- const isGptImage2 = modelAlias === "2" || modelAlias === "gpt-image-2";
36467
+ const isGptImage15 = modelAlias === "1.5" || modelAlias === "gpt-image-1.5";
36316
36468
  return {
36317
- openaiModel: isGptImage2 ? "gpt-image-2" : void 0,
36318
- modelLabel: isGptImage2 ? "GPT Image 2" : "GPT Image 1.5"
36469
+ openaiModel: isGptImage15 ? "gpt-image-1.5" : "gpt-image-2",
36470
+ modelLabel: isGptImage15 ? "GPT Image 1.5" : "GPT Image 2"
36319
36471
  };
36320
36472
  }
36321
36473
  async function executeOpenAIImageGenerate(prompt3, options, ctx) {
@@ -36352,7 +36504,7 @@ function registerImageCommand(parent) {
36352
36504
  "1:1"
36353
36505
  ).option("--quality <quality>", "Quality: standard, hd (openai only)", "standard").option("--style <style>", "Style: vivid, natural (openai only)", "vivid").option("--count <n>", "Number of images to generate", "1").option(
36354
36506
  "-m, --model <model>",
36355
- "Model. Gemini: flash, 3.1-flash, latest, pro. OpenAI: 1.5 (default), 2 (gpt-image-2)"
36507
+ "Model. Gemini: flash, 3.1-flash, latest, pro. OpenAI: 2 (default), 1.5"
36356
36508
  ).option("--dry-run", "Preview parameters without executing").addHelpText(
36357
36509
  "after",
36358
36510
  `
@@ -37786,8 +37938,8 @@ function registerVideoCommand(parent) {
37786
37938
  "quality"
37787
37939
  ).option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 720p, 1080p, 4k (Veo only)").option("--last-frame <path>", "Last frame image for frame interpolation (Veo only)").option(
37788
37940
  "--ref-images <paths...>",
37789
- "Reference images for character consistency (Veo 3.1 only, max 3)"
37790
- ).option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast (default: 3.1-fast)", "3.1-fast").option(
37941
+ "Reference images for Seedance reference-to-video or Veo character consistency"
37942
+ ).option("--ref-videos <paths...>", "Reference videos for Seedance reference-to-video").option("--ref-audio <paths...>", "Reference audio for Seedance reference-to-video").option("--no-generate-audio", "Disable native audio when the provider supports it").option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast (default: 3.1-fast)", "3.1-fast").option(
37791
37943
  "--runway-model <model>",
37792
37944
  "Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)",
37793
37945
  "gen4.5"
@@ -37930,7 +38082,11 @@ Examples:
37930
38082
  negative: options.negative,
37931
38083
  resolution: options.resolution,
37932
38084
  veoModel: options.veoModel,
37933
- seedanceModel: options.seedanceModel
38085
+ seedanceModel: options.seedanceModel,
38086
+ refImages: options.refImages,
38087
+ refVideos: options.refVideos,
38088
+ refAudio: options.refAudio,
38089
+ generateAudio: options.generateAudio
37934
38090
  }
37935
38091
  }
37936
38092
  });
@@ -38217,8 +38373,13 @@ Examples:
38217
38373
  } else if (provider === "seedance") {
38218
38374
  const fal = new FalProvider();
38219
38375
  await fal.initialize({ apiKey });
38376
+ const seedanceReferences = await prepareSeedanceReferences2({
38377
+ refImages: options.refImages,
38378
+ refVideos: options.refVideos,
38379
+ refAudio: options.refAudio
38380
+ });
38220
38381
  let falImage = referenceImage;
38221
- if (falImage && falImage.startsWith("data:")) {
38382
+ if (falImage && falImage.startsWith("data:") && seedanceReferences.length === 0) {
38222
38383
  try {
38223
38384
  const uploadHost = await resolveUploadHost();
38224
38385
  spinner2.text = `Uploading image via ${uploadHost.provider} for Seedance...`;
@@ -38241,11 +38402,14 @@ Examples:
38241
38402
  const falModel = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
38242
38403
  result = await fal.generateVideo(prompt3, {
38243
38404
  prompt: prompt3,
38244
- referenceImage: falImage,
38405
+ referenceImage: seedanceReferences.length > 0 ? void 0 : falImage,
38406
+ references: seedanceReferences.length > 0 ? seedanceReferences : void 0,
38245
38407
  duration: options.duration ? parseInt(options.duration) : void 0,
38246
38408
  aspectRatio: options.ratio,
38247
38409
  negativePrompt: options.negative,
38248
- model: falModel
38410
+ model: falModel,
38411
+ resolution: options.resolution,
38412
+ generateAudio: options.generateAudio
38249
38413
  });
38250
38414
  finalResult = result;
38251
38415
  }
@@ -38300,6 +38464,54 @@ Examples:
38300
38464
  }
38301
38465
  });
38302
38466
  }
38467
+ async function prepareSeedanceReferences2(opts) {
38468
+ const references = [];
38469
+ for (const sourcePath of opts.refImages ?? []) {
38470
+ references.push({
38471
+ kind: "image",
38472
+ url: await fileInputToUrlOrDataUri2(sourcePath, "image/png"),
38473
+ sourcePath
38474
+ });
38475
+ }
38476
+ for (const sourcePath of opts.refVideos ?? []) {
38477
+ references.push({
38478
+ kind: "video",
38479
+ url: await fileInputToUrlOrDataUri2(sourcePath, "video/mp4"),
38480
+ sourcePath
38481
+ });
38482
+ }
38483
+ for (const sourcePath of opts.refAudio ?? []) {
38484
+ references.push({
38485
+ kind: "audio",
38486
+ url: await fileInputToUrlOrDataUri2(sourcePath, "audio/mpeg"),
38487
+ sourcePath
38488
+ });
38489
+ }
38490
+ return references;
38491
+ }
38492
+ async function fileInputToUrlOrDataUri2(input, fallbackMimeType) {
38493
+ if (input.startsWith("http://") || input.startsWith("https://") || input.startsWith("data:")) {
38494
+ return input;
38495
+ }
38496
+ const absPath = resolve31(process.cwd(), input);
38497
+ const buffer = await readFile18(absPath);
38498
+ return `data:${mimeTypeForPath2(input, fallbackMimeType)};base64,${buffer.toString("base64")}`;
38499
+ }
38500
+ function mimeTypeForPath2(path2, fallback2) {
38501
+ const ext = path2.toLowerCase().split(".").pop();
38502
+ const mimeTypes2 = {
38503
+ jpg: "image/jpeg",
38504
+ jpeg: "image/jpeg",
38505
+ png: "image/png",
38506
+ gif: "image/gif",
38507
+ webp: "image/webp",
38508
+ mp4: "video/mp4",
38509
+ mov: "video/quicktime",
38510
+ mp3: "audio/mpeg",
38511
+ wav: "audio/wav"
38512
+ };
38513
+ return mimeTypes2[ext || ""] || fallback2;
38514
+ }
38303
38515
  async function recordVideoNoWaitJob(opts) {
38304
38516
  return createAndWriteJobRecord({
38305
38517
  jobType: "generate-video",
@@ -68197,6 +68409,9 @@ var init_generate2 = __esm({
68197
68409
  "Video provider (default: seedance when FAL_API_KEY is configured, otherwise first configured provider)"
68198
68410
  ),
68199
68411
  image: external_exports.string().optional().describe("Reference image path for image-to-video"),
68412
+ refImages: external_exports.array(external_exports.string()).optional().describe("Reference images for Seedance reference-to-video"),
68413
+ refVideos: external_exports.array(external_exports.string()).optional().describe("Reference videos for Seedance reference-to-video"),
68414
+ refAudio: external_exports.array(external_exports.string()).optional().describe("Reference audio files for Seedance reference-to-video"),
68200
68415
  duration: external_exports.number().optional().describe("Duration in seconds (default: 5; Seedance accepts 4-15)"),
68201
68416
  ratio: external_exports.string().optional().describe("Aspect ratio: 16:9, 9:16, 1:1 (default: 16:9)"),
68202
68417
  mode: external_exports.string().optional().describe("Kling mode: std or pro"),
@@ -68205,6 +68420,7 @@ var init_generate2 = __esm({
68205
68420
  veoModel: external_exports.string().optional().describe("Veo model: 3.0, 3.1, 3.1-fast"),
68206
68421
  runwayModel: external_exports.string().optional().describe("Runway model: gen4.5, gen4_turbo"),
68207
68422
  seedanceModel: external_exports.string().optional().describe("Seedance variant: quality or fast (fal.ai only)"),
68423
+ generateAudio: external_exports.boolean().optional().describe("Generate native synchronized audio when supported"),
68208
68424
  output: external_exports.string().optional().describe("Output file path (downloads video)"),
68209
68425
  wait: external_exports.boolean().optional().describe("Wait for completion (default: true)")
68210
68426
  }),
@@ -71438,7 +71654,7 @@ init_source();
71438
71654
  // package.json
71439
71655
  var package_default = {
71440
71656
  name: "@vibeframe/cli",
71441
- version: "0.104.3",
71657
+ version: "0.105.1",
71442
71658
  description: "VibeFrame CLI - natural language video editing from the terminal",
71443
71659
  private: false,
71444
71660
  license: "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/cli",
3
- "version": "0.104.3",
3
+ "version": "0.105.1",
4
4
  "description": "VibeFrame CLI - natural language video editing from the terminal",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -183,8 +183,8 @@
183
183
  "tsx": "^4.21.0",
184
184
  "typescript": "^5.3.3",
185
185
  "vitest": "^1.2.2",
186
- "@vibeframe/core": "0.104.3",
187
- "@vibeframe/ai-providers": "0.104.3"
186
+ "@vibeframe/ai-providers": "0.105.1",
187
+ "@vibeframe/core": "0.105.1"
188
188
  },
189
189
  "engines": {
190
190
  "node": ">=20"