@vibeframe/mcp-server 0.115.2 → 0.115.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +938 -647
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -191,8 +191,8 @@ var init_api_keys = __esm({
191
191
  envVar: "OPENAI_API_KEY",
192
192
  label: "OpenAI",
193
193
  showInSetup: true,
194
- setupDescription: "gpt-image-2 image gen ($, default since v0.56), gpt-4o-mini-tts narration, Whisper transcribe, Agent",
195
- envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2 \u2014 default text-to-image since v0.56)",
194
+ setupDescription: "gpt-image-2.5 image gen ($), gpt-4o-mini-tts narration, Whisper transcribe, Agent",
195
+ envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2.5 text-to-image)",
196
196
  envExampleUrl: "https://platform.openai.com/api-keys",
197
197
  keyFormat: { prefix: /^sk-/, example: "sk-..." }
198
198
  });
@@ -267,8 +267,7 @@ var init_api_keys = __esm({
267
267
  setupDescription: "v2.5/v3 video \u2014 std ($$) and pro ($$$) modes",
268
268
  envExampleComment: "Kling API Key (Kling video generation)",
269
269
  envExampleUrl: "https://platform.klingai.com/",
270
- envExampleExtraLines: ["Format: ACCESS_KEY:SECRET_KEY"],
271
- keyFormat: { prefix: /:/, example: "ACCESS_KEY:SECRET_KEY" }
270
+ envExampleExtraLines: ["API key from the Kling console (legacy ACCESS_KEY:SECRET_KEY also works)"]
272
271
  });
273
272
  defineApiKey({
274
273
  configKey: "replicate",
@@ -458,18 +457,20 @@ var GEMINI_DEFAULT_TEXT_MODEL, GEMINI_AGENT_DEFAULT_TEXT_MODEL, GEMINI_TEXT_MODE
458
457
  var init_gemini_models = __esm({
459
458
  "../ai-providers/dist/gemini/gemini-models.js"() {
460
459
  "use strict";
461
- GEMINI_DEFAULT_TEXT_MODEL = "gemini-3.5-flash";
462
- GEMINI_AGENT_DEFAULT_TEXT_MODEL = "gemini-2.5-flash";
460
+ GEMINI_DEFAULT_TEXT_MODEL = "gemini-3.8-flash";
461
+ GEMINI_AGENT_DEFAULT_TEXT_MODEL = GEMINI_DEFAULT_TEXT_MODEL;
463
462
  GEMINI_TEXT_MODEL_ALIASES = {
464
463
  flash: GEMINI_DEFAULT_TEXT_MODEL,
465
464
  latest: GEMINI_DEFAULT_TEXT_MODEL,
466
- "flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
465
+ "flash-3.8": GEMINI_DEFAULT_TEXT_MODEL,
466
+ "flash-3.5": "gemini-3.5-flash",
467
467
  "flash-3": "gemini-3-flash-preview",
468
468
  "flash-2.5": "gemini-2.5-flash",
469
- pro: "gemini-2.5-pro",
470
- "pro-3.1": "gemini-3.1-pro-preview"
469
+ pro: "gemini-3.1-pro-preview",
470
+ "pro-3.1": "gemini-3.1-pro-preview",
471
+ "pro-2.5": "gemini-2.5-pro"
471
472
  };
472
- GEMINI_TEXT_MODEL_HELP = "flash/latest (Gemini 3.5 Flash), flash-3.5, flash-3, flash-2.5, pro, pro-3.1, or a full gemini-* model ID";
473
+ GEMINI_TEXT_MODEL_HELP = "flash/latest (Gemini 3.8 Flash), flash-3.8, flash-3.5, flash-3, flash-2.5, pro (Gemini 3.1 Pro), pro-3.1, pro-2.5, or a full gemini-* model ID";
473
474
  }
474
475
  });
475
476
 
@@ -656,7 +657,6 @@ UNIVERSAL RULES:
656
657
  system_instruction: { parts: [{ text: systemPrompt }] },
657
658
  contents: [{ role: "user", parts: [{ text: userPrompt }] }],
658
659
  generationConfig: {
659
- temperature: 0.8,
660
660
  maxOutputTokens: 16384
661
661
  }
662
662
  })
@@ -757,7 +757,7 @@ Return the complete modified component as JSON.`
757
757
  ]
758
758
  }
759
759
  ],
760
- generationConfig: { temperature: 0.5, maxOutputTokens: 16384 }
760
+ generationConfig: { maxOutputTokens: 16384 }
761
761
  })
762
762
  });
763
763
  if (!response.ok) {
@@ -807,10 +807,11 @@ var init_gemini_motion = __esm({
807
807
  gemini: GEMINI_DEFAULT_TEXT_MODEL,
808
808
  flash: GEMINI_DEFAULT_TEXT_MODEL,
809
809
  latest: GEMINI_DEFAULT_TEXT_MODEL,
810
- "flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
810
+ "flash-3.8": GEMINI_DEFAULT_TEXT_MODEL,
811
+ "flash-3.5": "gemini-3.5-flash",
811
812
  "flash-3": "gemini-3-flash-preview",
812
813
  "flash-2.5": "gemini-2.5-flash",
813
- pro: "gemini-2.5-pro",
814
+ pro: "gemini-3.1-pro-preview",
814
815
  "2.5-pro": "gemini-2.5-pro",
815
816
  "3.1-pro": "gemini-3.1-pro-preview",
816
817
  "pro-3.1": "gemini-3.1-pro-preview"
@@ -922,7 +923,6 @@ var init_storyboard_prompt = __esm({
922
923
  async function analyzeContent(api, content, targetDuration, options) {
923
924
  const creativity = options?.creativity || "low";
924
925
  const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity);
925
- const temperature = creativity === "high" ? 1 : 0.7;
926
926
  try {
927
927
  const payload = {
928
928
  system_instruction: {
@@ -932,7 +932,6 @@ async function analyzeContent(api, content, targetDuration, options) {
932
932
  parts: [{ text: buildStoryboardUserMessage(content) }]
933
933
  }],
934
934
  generationConfig: {
935
- temperature,
936
935
  maxOutputTokens: 4096
937
936
  }
938
937
  };
@@ -1003,7 +1002,15 @@ var init_http = __esm({
1003
1002
  });
1004
1003
 
1005
1004
  // ../ai-providers/dist/gemini/GeminiProvider.js
1006
- var MODEL_MAP, GeminiProvider, geminiProvider;
1005
+ function resolveVeoModel(alias) {
1006
+ if (Object.hasOwn(VEO_MODEL_ALIASES, alias)) {
1007
+ return VEO_MODEL_ALIASES[alias];
1008
+ }
1009
+ const valid = Object.keys(VEO_MODEL_ALIASES).join(", ");
1010
+ const hint = alias === "3.0" ? " Veo 3.0 was shut down by Google on 2025-11-12." : "";
1011
+ throw new Error(`Unknown Veo model "${alias}". Valid: ${valid}.${hint}`);
1012
+ }
1013
+ var VEO_MODEL_ALIASES, MODEL_MAP, GeminiProvider, geminiProvider;
1007
1014
  var init_GeminiProvider = __esm({
1008
1015
  "../ai-providers/dist/gemini/GeminiProvider.js"() {
1009
1016
  "use strict";
@@ -1011,11 +1018,19 @@ var init_GeminiProvider = __esm({
1011
1018
  init_gemini_models();
1012
1019
  init_gemini_storyboard();
1013
1020
  init_http();
1021
+ VEO_MODEL_ALIASES = {
1022
+ "3.1": "veo-3.1-generate-preview",
1023
+ "3.1-fast": "veo-3.1-fast-generate-preview"
1024
+ };
1014
1025
  MODEL_MAP = {
1015
- "flash": "gemini-2.5-flash-image",
1016
- "3.1-flash": "gemini-3.1-flash-image-preview",
1017
- "latest": "gemini-3.1-flash-image-preview",
1018
- "pro": "gemini-3-pro-image-preview",
1026
+ "flash": "gemini-3.1-flash-image",
1027
+ "3.1-flash": "gemini-3.1-flash-image",
1028
+ "latest": "gemini-3.1-flash-image",
1029
+ "lite": "gemini-3.1-flash-lite-image",
1030
+ "pro": "gemini-3-pro-image",
1031
+ "gemini-3.1-flash-image": "gemini-3.1-flash-image",
1032
+ "gemini-3.1-flash-lite-image": "gemini-3.1-flash-lite-image",
1033
+ "gemini-3-pro-image": "gemini-3-pro-image",
1019
1034
  "gemini-2.5-flash-image": "gemini-2.5-flash-image",
1020
1035
  "gemini-3.1-flash-image-preview": "gemini-3.1-flash-image-preview",
1021
1036
  "gemini-3-pro-image-preview": "gemini-3-pro-image-preview"
@@ -1324,7 +1339,7 @@ var init_GeminiProvider = __esm({
1324
1339
  contents: [{ parts: [{ text: prompt3 }] }],
1325
1340
  generationConfig
1326
1341
  };
1327
- const is31Flash = modelId === "gemini-3.1-flash-image-preview";
1342
+ const is31Flash = modelId.startsWith("gemini-3.1-flash-image");
1328
1343
  if (options.imageSearchGrounding && is31Flash) {
1329
1344
  payload.tools = [{ googleSearch: { searchTypes: { webSearch: {}, imageSearch: {} } } }];
1330
1345
  } else if (options.grounding && isPro) {
@@ -1552,7 +1567,6 @@ var init_GeminiProvider = __esm({
1552
1567
  videoPart.video_metadata = videoMetadata;
1553
1568
  }
1554
1569
  const generationConfig = {
1555
- temperature: 0.4,
1556
1570
  maxOutputTokens: 8192
1557
1571
  };
1558
1572
  if (options.lowResolution) {
@@ -1634,7 +1648,6 @@ var init_GeminiProvider = __esm({
1634
1648
  }
1635
1649
  }));
1636
1650
  const generationConfig = {
1637
- temperature: 0.4,
1638
1651
  maxOutputTokens: 8192
1639
1652
  };
1640
1653
  if (options.lowResolution) {
@@ -1734,7 +1747,6 @@ Respond with ONLY the JSON array, no other text.`;
1734
1747
  body: JSON.stringify({
1735
1748
  contents: [{ parts: [{ text: prompt3 }] }],
1736
1749
  generationConfig: {
1737
- temperature: 0.3,
1738
1750
  maxOutputTokens: 1024
1739
1751
  }
1740
1752
  })
@@ -1828,7 +1840,7 @@ Respond with ONLY the JSON array, no other text.`;
1828
1840
  return refineMotion({ apiKey: this.apiKey, baseUrl: this.baseUrl }, existingCode, instructions, options);
1829
1841
  }
1830
1842
  /**
1831
- * Generate a storyboard from script content using Gemini 2.5 Flash.
1843
+ * Generate a storyboard from script content using the default Gemini Flash model.
1832
1844
  * Alternative to ClaudeProvider.analyzeContent for when Claude is unavailable.
1833
1845
  */
1834
1846
  async analyzeContent(content, targetDuration, options) {
@@ -1843,43 +1855,47 @@ Respond with ONLY the JSON array, no other text.`;
1843
1855
  });
1844
1856
 
1845
1857
  // ../ai-providers/dist/gemini/gemini-omni.js
1846
- function firstReferenceImage(options) {
1847
- const refs3 = options.referenceImages;
1848
- if (refs3 && refs3.length > 0 && refs3[0].base64)
1849
- return refs3[0];
1850
- const ref2 = options.referenceImage;
1851
- if (typeof ref2 === "string" && ref2) {
1858
+ function frameImages(options) {
1859
+ const frames = [];
1860
+ const toInline = (ref2) => {
1852
1861
  const m2 = ref2.match(/^data:(.+?);base64,(.*)$/);
1853
- if (m2)
1854
- return { mimeType: m2[1], base64: m2[2] };
1855
- return { mimeType: "image/png", base64: ref2 };
1862
+ return m2 ? { mimeType: m2[1], base64: m2[2] } : { mimeType: "image/png", base64: ref2 };
1863
+ };
1864
+ if (options.referenceImages?.[0]?.base64)
1865
+ frames.push(options.referenceImages[0]);
1866
+ else if (typeof options.referenceImage === "string" && options.referenceImage) {
1867
+ frames.push(toInline(options.referenceImage));
1856
1868
  }
1857
- return void 0;
1869
+ if (frames.length > 0 && options.lastFrame)
1870
+ frames.push(toInline(options.lastFrame));
1871
+ return frames;
1858
1872
  }
1859
- function findVideoUrl(obj) {
1860
- if (!obj || typeof obj !== "object")
1861
- return void 0;
1862
- for (const [k2, v4] of Object.entries(obj)) {
1863
- if (typeof v4 === "string" && /^https?:\/\//.test(v4) && /(uri|url|video)/i.test(k2))
1864
- return v4;
1865
- if (typeof v4 === "object") {
1866
- const nested = findVideoUrl(v4);
1867
- if (nested)
1868
- return nested;
1869
- }
1873
+ function findOmniVideo(response) {
1874
+ for (const step of response.steps ?? []) {
1875
+ if (step.type !== "model_output")
1876
+ continue;
1877
+ const video = step.content?.find((c2) => c2.type === "video");
1878
+ if (video)
1879
+ return video;
1870
1880
  }
1871
- return void 0;
1881
+ return response.output_video;
1882
+ }
1883
+ function fileIdFromUri(uri) {
1884
+ return uri.match(/files\/([^/?:]+)/)?.[1];
1872
1885
  }
1873
- var OMNI_MODEL, INTERACTIONS_URL, OmniProvider, omniProvider;
1886
+ var OMNI_MODEL, API_ROOT, FILE_POLL_INTERVAL_MS, FILE_POLL_TIMEOUT_MS, OmniProvider, omniProvider;
1874
1887
  var init_gemini_omni = __esm({
1875
1888
  "../ai-providers/dist/gemini/gemini-omni.js"() {
1876
1889
  "use strict";
1877
- OMNI_MODEL = "gemini-omni-flash-preview";
1878
- INTERACTIONS_URL = "https://generativelanguage.googleapis.com/v1beta/interactions";
1890
+ init_http();
1891
+ OMNI_MODEL = "gemini-omni-1.1-flash";
1892
+ API_ROOT = "https://generativelanguage.googleapis.com";
1893
+ FILE_POLL_INTERVAL_MS = 3e3;
1894
+ FILE_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
1879
1895
  OmniProvider = class {
1880
1896
  constructor() {
1881
1897
  this.id = "omni";
1882
- this.label = "Gemini Omni (experimental)";
1898
+ this.label = "Gemini Omni 1.1 Flash";
1883
1899
  }
1884
1900
  async initialize(config4) {
1885
1901
  this.apiKey = config4.apiKey;
@@ -1892,22 +1908,23 @@ var init_gemini_omni = __esm({
1892
1908
  return { id: "", status: "failed", error: "GOOGLE_API_KEY not configured for Gemini Omni" };
1893
1909
  }
1894
1910
  const opts = options ?? { prompt: prompt3 };
1895
- const image = firstReferenceImage(opts);
1896
- const task = image ? "image_to_video" : "text_to_video";
1897
- const aspectRatio2 = opts.aspectRatio === "9:16" ? "9:16" : "16:9";
1898
- const inputs = [{ text: prompt3 }];
1899
- if (image) {
1900
- inputs.push({ inline_data: { mime_type: image.mimeType, data: image.base64 } });
1901
- }
1911
+ const frames = frameImages(opts);
1912
+ const input3 = frames.length === 0 ? prompt3 : [
1913
+ ...frames.map((f2) => ({ type: "image", data: f2.base64, mime_type: f2.mimeType })),
1914
+ { type: "text", text: prompt3 }
1915
+ ];
1902
1916
  const body = {
1903
1917
  model: OMNI_MODEL,
1904
- inputs,
1905
- generation_config: {
1906
- video_config: { task, aspect_ratio: aspectRatio2 }
1918
+ input: input3,
1919
+ response_format: {
1920
+ type: "video",
1921
+ aspect_ratio: opts.aspectRatio === "9:16" ? "9:16" : "16:9",
1922
+ resolution: opts.resolution ?? "720p",
1923
+ delivery: "uri"
1907
1924
  }
1908
1925
  };
1909
1926
  try {
1910
- const res = await fetch(INTERACTIONS_URL, {
1927
+ const res = await fetch(`${API_ROOT}/v1beta/interactions`, {
1911
1928
  method: "POST",
1912
1929
  headers: { "Content-Type": "application/json", "x-goog-api-key": this.apiKey },
1913
1930
  body: JSON.stringify(body)
@@ -1917,33 +1934,52 @@ var init_gemini_omni = __esm({
1917
1934
  return {
1918
1935
  id: "",
1919
1936
  status: "failed",
1920
- error: `Gemini Omni (experimental) request failed: HTTP ${res.status} \u2014 ${text.slice(0, 300)}`
1937
+ error: `Gemini Omni request failed: HTTP ${res.status} - ${text.slice(0, 300)}`
1921
1938
  };
1922
1939
  }
1923
- let parsed;
1924
- try {
1925
- parsed = JSON.parse(text);
1926
- } catch {
1927
- return { id: "", status: "failed", error: "Gemini Omni returned a non-JSON response" };
1940
+ const parsed = JSON.parse(text);
1941
+ const id = parsed.id ?? "";
1942
+ const video = findOmniVideo(parsed);
1943
+ if (!video?.uri) {
1944
+ const reason = parsed.error?.message ?? `status ${parsed.status ?? "unknown"}`;
1945
+ return { id, status: "failed", error: `Gemini Omni returned no video (${reason})` };
1928
1946
  }
1929
- const videoUrl = findVideoUrl(parsed);
1930
- const id = parsed?.interaction_id ?? parsed?.name ?? "";
1931
- if (!videoUrl) {
1932
- return {
1933
- id,
1934
- status: "failed",
1935
- error: "Gemini Omni response contained no video URL (the preview interactions schema may have changed)."
1936
- };
1947
+ const fileId = fileIdFromUri(video.uri);
1948
+ if (!fileId) {
1949
+ return { id, status: "failed", error: `Gemini Omni returned an unexpected video URI: ${video.uri}` };
1950
+ }
1951
+ const ready = await this.waitForFile(fileId);
1952
+ if (ready !== "ACTIVE") {
1953
+ return { id, status: "failed", error: `Gemini Omni video file ended in state ${ready}` };
1937
1954
  }
1938
- return { id, status: "completed", videoUrl };
1955
+ return {
1956
+ id,
1957
+ status: "completed",
1958
+ videoUrl: `${API_ROOT}/download/v1beta/files/${fileId}:download?alt=media`
1959
+ };
1939
1960
  } catch (err) {
1940
1961
  return {
1941
1962
  id: "",
1942
1963
  status: "failed",
1943
- error: `Gemini Omni (experimental) error: ${err instanceof Error ? err.message : String(err)}`
1964
+ error: `Gemini Omni error: ${err instanceof Error ? err.message : String(err)}`
1944
1965
  };
1945
1966
  }
1946
1967
  }
1968
+ /** Poll the Files API until the generated video is downloadable. */
1969
+ async waitForFile(fileId) {
1970
+ const deadline = Date.now() + FILE_POLL_TIMEOUT_MS;
1971
+ for (; ; ) {
1972
+ const res = await fetch(`${API_ROOT}/v1beta/files/${fileId}`, {
1973
+ headers: { "x-goog-api-key": this.apiKey }
1974
+ });
1975
+ const state = res.ok ? (await res.json()).state : `HTTP ${res.status}`;
1976
+ if (state !== "PROCESSING")
1977
+ return state ?? "UNKNOWN";
1978
+ if (Date.now() > deadline)
1979
+ return "TIMEOUT";
1980
+ await sleep(FILE_POLL_INTERVAL_MS);
1981
+ }
1982
+ }
1947
1983
  };
1948
1984
  omniProvider = new OmniProvider();
1949
1985
  }
@@ -1977,14 +2013,16 @@ var init_gemini = __esm({
1977
2013
  label: "Veo",
1978
2014
  apiKey: "google",
1979
2015
  kinds: ["video"],
1980
- resolverPriority: { video: 3 },
2016
+ // No resolverPriority: the Veo 3.1 previews shut down on 2026-10-22, so
2017
+ // Veo is explicit-only (`-p veo`) and Omni is the Google default.
1981
2018
  commandsUnlocked: ["generate video -p veo"]
1982
2019
  });
1983
2020
  defineProvider({
1984
2021
  id: "omni",
1985
- label: "Gemini Omni (experimental)",
2022
+ label: "Gemini Omni",
1986
2023
  apiKey: "google",
1987
2024
  kinds: ["video"],
2025
+ resolverPriority: { video: 3 },
1988
2026
  commandsUnlocked: ["generate video -p omni"]
1989
2027
  });
1990
2028
  }
@@ -1993,8 +2031,7 @@ var init_gemini = __esm({
1993
2031
  // ../ai-providers/dist/openai/openai-storyboard.js
1994
2032
  async function analyzeContent2(apiKey, content, targetDuration, options) {
1995
2033
  const creativity = options?.creativity || "low";
1996
- const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity);
1997
- const temperature = creativity === "high" ? 1 : 0.7;
2034
+ const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity) + '\n\nWrap the array in a JSON object: {"segments": [ ...segment objects... ]}.';
1998
2035
  try {
1999
2036
  const response = await fetch("https://api.openai.com/v1/chat/completions", {
2000
2037
  method: "POST",
@@ -2003,13 +2040,13 @@ async function analyzeContent2(apiKey, content, targetDuration, options) {
2003
2040
  Authorization: `Bearer ${apiKey}`
2004
2041
  },
2005
2042
  body: JSON.stringify({
2006
- model: "gpt-5-mini",
2043
+ model: "gpt-5.4-mini",
2007
2044
  messages: [
2008
2045
  { role: "system", content: systemPrompt },
2009
2046
  { role: "user", content: buildStoryboardUserMessage(content) }
2010
2047
  ],
2011
- temperature,
2012
- max_tokens: 4096,
2048
+ // Reasoning tokens count against this cap.
2049
+ max_completion_tokens: 16384,
2013
2050
  response_format: { type: "json_object" }
2014
2051
  })
2015
2052
  });
@@ -2066,7 +2103,7 @@ var init_OpenAIProvider = __esm({
2066
2103
  this.iconUrl = "/icons/openai.svg";
2067
2104
  this.isAvailable = true;
2068
2105
  this.baseUrl = "https://api.openai.com/v1";
2069
- this.model = "gpt-5-mini";
2106
+ this.model = "gpt-5.4-mini";
2070
2107
  }
2071
2108
  async initialize(config4) {
2072
2109
  this.apiKey = config4.apiKey;
@@ -2162,7 +2199,6 @@ Or if clarification needed:
2162
2199
  { role: "system", content: systemPrompt },
2163
2200
  { role: "user", content: instruction }
2164
2201
  ],
2165
- temperature: 0.2,
2166
2202
  response_format: { type: "json_object" }
2167
2203
  })
2168
2204
  });
@@ -2373,8 +2409,9 @@ Each segment should be 3-10 seconds long.`;
2373
2409
  Authorization: `Bearer ${this.apiKey}`
2374
2410
  },
2375
2411
  body: JSON.stringify({
2376
- model: "gpt-5-mini",
2377
- max_tokens: 4096,
2412
+ model: "gpt-5.4-mini",
2413
+ // Reasoning tokens count against this cap.
2414
+ max_completion_tokens: 16384,
2378
2415
  response_format: { type: "json_object" },
2379
2416
  messages: [
2380
2417
  { role: "system", content: systemPrompt },
@@ -2407,7 +2444,7 @@ ${videoAnalysis}` }
2407
2444
  }
2408
2445
  }
2409
2446
  /**
2410
- * Generate a storyboard from script content using GPT-5-mini.
2447
+ * Generate a storyboard from script content using GPT-5.4 mini.
2411
2448
  * Alternative to ClaudeProvider.analyzeContent for when Claude is unavailable.
2412
2449
  */
2413
2450
  async analyzeContent(content, targetDuration, options) {
@@ -2455,10 +2492,12 @@ async function callClaude(params, opts) {
2455
2492
  },
2456
2493
  body: JSON.stringify({
2457
2494
  model: params.model,
2458
- max_tokens: opts.maxTokens,
2459
- ...opts.temperature !== void 0 ? { temperature: opts.temperature } : {},
2495
+ // Claude 5.x thinks by default and thinking tokens count against
2496
+ // max_tokens, so a small cap can end before any text is written.
2497
+ max_tokens: Math.max(opts.maxTokens, CLAUDE_MIN_MAX_TOKENS),
2460
2498
  messages: opts.messages,
2461
- system: opts.system
2499
+ system: opts.system,
2500
+ ...opts.jsonSchema ? { output_config: { format: { type: "json_schema", schema: opts.jsonSchema } } } : {}
2462
2501
  })
2463
2502
  });
2464
2503
  if (!response.ok) {
@@ -2480,9 +2519,11 @@ function extractJsonArray(text) {
2480
2519
  const match2 = text.match(/\[[\s\S]*\]/);
2481
2520
  return match2 ? match2[0] : null;
2482
2521
  }
2522
+ var CLAUDE_MIN_MAX_TOKENS;
2483
2523
  var init_claude_api = __esm({
2484
2524
  "../ai-providers/dist/claude/claude-api.js"() {
2485
2525
  "use strict";
2526
+ CLAUDE_MIN_MAX_TOKENS = 16e3;
2486
2527
  }
2487
2528
  });
2488
2529
 
@@ -2518,7 +2559,8 @@ MANDATORY ADAPTATION RULES:
2518
2559
  const text = await callClaude(api, {
2519
2560
  system: systemPrompt,
2520
2561
  messages: [{ role: "user", content: userContent }],
2521
- maxTokens: 16e3
2562
+ maxTokens: 16e3,
2563
+ jsonSchema: MOTION_COMPONENT_SCHEMA
2522
2564
  });
2523
2565
  const jsonStr = extractJsonObject(text);
2524
2566
  if (!jsonStr) {
@@ -2593,7 +2635,8 @@ Modification instructions: ${instructions}
2593
2635
 
2594
2636
  Return the complete modified component as JSON.`
2595
2637
  }],
2596
- maxTokens: 16e3
2638
+ maxTokens: 16e3,
2639
+ jsonSchema: MOTION_COMPONENT_SCHEMA
2597
2640
  });
2598
2641
  const jsonStr = extractJsonObject(text);
2599
2642
  if (!jsonStr)
@@ -2622,15 +2665,13 @@ async function analyzeContent3(api, content, targetDuration, options) {
2622
2665
  const creativity = options?.creativity || "low";
2623
2666
  const systemPrompt = buildStoryboardSystemPrompt(targetDuration, creativity);
2624
2667
  try {
2625
- const temperature = creativity === "high" ? 1 : 0.7;
2626
2668
  const text = await callClaude(api, {
2627
2669
  system: systemPrompt,
2628
2670
  messages: [{
2629
2671
  role: "user",
2630
2672
  content: buildStoryboardUserMessage(content)
2631
2673
  }],
2632
- maxTokens: 4096,
2633
- temperature
2674
+ maxTokens: 4096
2634
2675
  });
2635
2676
  const jsonStr = extractJsonArray(text);
2636
2677
  if (!jsonStr) {
@@ -2987,11 +3028,22 @@ UNIVERSAL RULES:
2987
3028
  - Both entrance AND exit animations
2988
3029
  - whiteSpace: "nowrap" on all text`;
2989
3030
  }
3031
+ var MOTION_COMPONENT_SCHEMA;
2990
3032
  var init_claude_motion = __esm({
2991
3033
  "../ai-providers/dist/claude/claude-motion.js"() {
2992
3034
  "use strict";
2993
3035
  init_claude_api();
2994
3036
  init_storyboard_prompt();
3037
+ MOTION_COMPONENT_SCHEMA = {
3038
+ type: "object",
3039
+ properties: {
3040
+ name: { type: "string" },
3041
+ code: { type: "string" },
3042
+ description: { type: "string" }
3043
+ },
3044
+ required: ["name", "code", "description"],
3045
+ additionalProperties: false
3046
+ };
2995
3047
  }
2996
3048
  });
2997
3049
 
@@ -3753,6 +3805,7 @@ var ClaudeProvider, claudeProvider;
3753
3805
  var init_ClaudeProvider = __esm({
3754
3806
  "../ai-providers/dist/claude/ClaudeProvider.js"() {
3755
3807
  "use strict";
3808
+ init_claude_api();
3756
3809
  init_claude_motion();
3757
3810
  init_claude_analysis();
3758
3811
  init_claude_viral();
@@ -3766,7 +3819,7 @@ var init_ClaudeProvider = __esm({
3766
3819
  this.iconUrl = "/icons/claude.svg";
3767
3820
  this.isAvailable = true;
3768
3821
  this.baseUrl = "https://api.anthropic.com/v1";
3769
- this.model = "claude-sonnet-4-6";
3822
+ this.model = "claude-sonnet-5-5";
3770
3823
  }
3771
3824
  async initialize(config4) {
3772
3825
  this.apiKey = config4.apiKey;
@@ -3870,7 +3923,7 @@ Or if clarification needed:
3870
3923
  },
3871
3924
  body: JSON.stringify({
3872
3925
  model: this.model,
3873
- max_tokens: 2048,
3926
+ max_tokens: CLAUDE_MIN_MAX_TOKENS,
3874
3927
  messages: [{ role: "user", content: instruction }],
3875
3928
  system: systemPrompt
3876
3929
  })
@@ -3940,7 +3993,7 @@ Respond with JSON array:
3940
3993
  },
3941
3994
  body: JSON.stringify({
3942
3995
  model: this.model,
3943
- max_tokens: 2048,
3996
+ max_tokens: CLAUDE_MIN_MAX_TOKENS,
3944
3997
  messages: [{
3945
3998
  role: "user",
3946
3999
  content: `Clips: ${JSON.stringify(clipsInfo)}
@@ -4069,8 +4122,8 @@ Instruction: ${instruction}`
4069
4122
  }
4070
4123
  };
4071
4124
  ClaudeProvider.MOTION_MODELS = {
4072
- sonnet: "claude-sonnet-4-6",
4073
- opus: "claude-opus-4-7",
4125
+ sonnet: "claude-sonnet-5-5",
4126
+ opus: "claude-opus-5-5",
4074
4127
  "opus-4-6": "claude-opus-4-6"
4075
4128
  };
4076
4129
  claudeProvider = new ClaudeProvider();
@@ -4408,7 +4461,7 @@ function resolveVoiceId(input3) {
4408
4461
  const availableVoices = Object.keys(KNOWN_VOICES).join(", ");
4409
4462
  throw new Error(`Unknown voice "${input3}". Available voices: ${availableVoices}. You can also use a custom voice ID from your ElevenLabs account.`);
4410
4463
  }
4411
- var KNOWN_VOICES, TTS_429_MAX_RETRIES, TTS_429_RETRY_DELAY_MS, ElevenLabsProvider, elevenLabsProvider;
4464
+ var KNOWN_VOICES, TTS_429_MAX_RETRIES, TTS_429_RETRY_DELAY_MS, ELEVENLABS_MUSIC_MODEL, ElevenLabsProvider, elevenLabsProvider;
4412
4465
  var init_ElevenLabsProvider = __esm({
4413
4466
  "../ai-providers/dist/elevenlabs/ElevenLabsProvider.js"() {
4414
4467
  "use strict";
@@ -4445,6 +4498,7 @@ var init_ElevenLabsProvider = __esm({
4445
4498
  };
4446
4499
  TTS_429_MAX_RETRIES = 1;
4447
4500
  TTS_429_RETRY_DELAY_MS = 2e3;
4501
+ ELEVENLABS_MUSIC_MODEL = "music_v2_5";
4448
4502
  ElevenLabsProvider = class {
4449
4503
  constructor() {
4450
4504
  this.id = "elevenlabs";
@@ -4525,9 +4579,10 @@ var init_ElevenLabsProvider = __esm({
4525
4579
  stability: options.stability ?? 0.5,
4526
4580
  similarity_boost: options.similarityBoost ?? 0.75,
4527
4581
  style: options.style ?? 0,
4528
- use_speaker_boost: true
4529
- },
4530
- ...options.speed !== void 0 && { speed: options.speed }
4582
+ use_speaker_boost: true,
4583
+ // The API reads speed only inside voice_settings.
4584
+ ...options.speed !== void 0 && { speed: options.speed }
4585
+ }
4531
4586
  })
4532
4587
  });
4533
4588
  if (response.status === 429 && attempt < TTS_429_MAX_RETRIES) {
@@ -4597,7 +4652,7 @@ var init_ElevenLabsProvider = __esm({
4597
4652
  prompt_influence: options.promptInfluence ?? 0.3
4598
4653
  };
4599
4654
  if (options.duration !== void 0) {
4600
- const duration = Math.max(0.5, Math.min(22, options.duration));
4655
+ const duration = Math.max(0.5, Math.min(30, options.duration));
4601
4656
  body.duration_seconds = duration;
4602
4657
  }
4603
4658
  const response = await fetch(`${this.baseUrl}/sound-generation`, {
@@ -4642,7 +4697,7 @@ var init_ElevenLabsProvider = __esm({
4642
4697
  try {
4643
4698
  const body = {
4644
4699
  prompt: prompt3,
4645
- model_id: "music_v1"
4700
+ model_id: ELEVENLABS_MUSIC_MODEL
4646
4701
  };
4647
4702
  if (options.duration !== void 0) {
4648
4703
  const duration = Math.max(3, Math.min(600, options.duration));
@@ -4853,6 +4908,55 @@ var init_elevenlabs = __esm({
4853
4908
  });
4854
4909
 
4855
4910
  // ../ai-providers/dist/kokoro/KokoroProvider.js
4911
+ function splitForKokoro(text, maxChars = KOKORO_MAX_CHUNK_CHARS) {
4912
+ const pieces = (part, pattern) => part.length <= maxChars ? [part] : part.split(pattern).filter((p2) => p2.trim().length > 0);
4913
+ const units2 = text.trim().split(/(?<=[.!?…])\s+/).flatMap((sentence) => pieces(sentence, /(?<=[,;:])\s+/)).flatMap((clause) => {
4914
+ if (clause.length <= maxChars)
4915
+ return [clause];
4916
+ const words = [];
4917
+ let line = "";
4918
+ for (const word of clause.split(/\s+/)) {
4919
+ if (line && line.length + word.length + 1 > maxChars) {
4920
+ words.push(line);
4921
+ line = word;
4922
+ } else {
4923
+ line = line ? `${line} ${word}` : word;
4924
+ }
4925
+ }
4926
+ if (line)
4927
+ words.push(line);
4928
+ return words;
4929
+ });
4930
+ const chunks = [];
4931
+ for (const unit of units2) {
4932
+ const last3 = chunks.at(-1);
4933
+ if (last3 !== void 0 && last3.length + unit.length + 1 <= maxChars) {
4934
+ chunks[chunks.length - 1] = `${last3} ${unit}`;
4935
+ } else {
4936
+ chunks.push(unit);
4937
+ }
4938
+ }
4939
+ return chunks;
4940
+ }
4941
+ function encodeFloatWav(samples, sampleRate) {
4942
+ const dataBytes = samples.length * 4;
4943
+ const buffer = Buffer.alloc(44 + dataBytes);
4944
+ buffer.write("RIFF", 0, "ascii");
4945
+ buffer.writeUInt32LE(36 + dataBytes, 4);
4946
+ buffer.write("WAVE", 8, "ascii");
4947
+ buffer.write("fmt ", 12, "ascii");
4948
+ buffer.writeUInt32LE(16, 16);
4949
+ buffer.writeUInt16LE(3, 20);
4950
+ buffer.writeUInt16LE(1, 22);
4951
+ buffer.writeUInt32LE(sampleRate, 24);
4952
+ buffer.writeUInt32LE(sampleRate * 4, 28);
4953
+ buffer.writeUInt16LE(4, 32);
4954
+ buffer.writeUInt16LE(32, 34);
4955
+ buffer.write("data", 36, "ascii");
4956
+ buffer.writeUInt32LE(dataBytes, 40);
4957
+ Buffer.from(samples.buffer, samples.byteOffset, dataBytes).copy(buffer, 44);
4958
+ return buffer;
4959
+ }
4856
4960
  async function loadKokoroRuntime() {
4857
4961
  if (factoryOverride)
4858
4962
  return { factory: factoryOverride, device: "cpu" };
@@ -4890,7 +4994,7 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
4890
4994
  if (!base2)
4891
4995
  return null;
4892
4996
  try {
4893
- const { readFile: readFile48, writeFile: writeFile52, mkdir: mkdir31 } = await import("node:fs/promises");
4997
+ const { readFile: readFile48, writeFile: writeFile51, mkdir: mkdir33 } = await import("node:fs/promises");
4894
4998
  const { join: join79, resolve: resolve86 } = await import("node:path");
4895
4999
  const { pathToFileURL: pathToFileURL2 } = await import("node:url");
4896
5000
  const { homedir: homedir8 } = await import("node:os");
@@ -4911,8 +5015,8 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
4911
5015
  async put(key2, response) {
4912
5016
  try {
4913
5017
  const buf = Buffer.from(await response.arrayBuffer());
4914
- await mkdir31(cacheRoot, { recursive: true });
4915
- await writeFile52(join79(cacheRoot, encodeURIComponent(String(key2))), buf);
5018
+ await mkdir33(cacheRoot, { recursive: true });
5019
+ await writeFile51(join79(cacheRoot, encodeURIComponent(String(key2))), buf);
4916
5020
  } catch {
4917
5021
  }
4918
5022
  }
@@ -4961,12 +5065,13 @@ function normaliseEvent(raw2) {
4961
5065
  total: typeof r2.total === "number" ? r2.total : void 0
4962
5066
  };
4963
5067
  }
4964
- var KOKORO_DEFAULT_VOICE, KOKORO_MODEL_ID, modelPromise, factoryOverride, KokoroProvider, kokoroProvider;
5068
+ var KOKORO_DEFAULT_VOICE, KOKORO_MODEL_ID, KOKORO_MAX_CHUNK_CHARS, modelPromise, factoryOverride, KokoroProvider, kokoroProvider;
4965
5069
  var init_KokoroProvider = __esm({
4966
5070
  "../ai-providers/dist/kokoro/KokoroProvider.js"() {
4967
5071
  "use strict";
4968
5072
  KOKORO_DEFAULT_VOICE = "af_heart";
4969
5073
  KOKORO_MODEL_ID = "onnx-community/Kokoro-82M-v1.0-ONNX";
5074
+ KOKORO_MAX_CHUNK_CHARS = 300;
4970
5075
  modelPromise = null;
4971
5076
  factoryOverride = null;
4972
5077
  KokoroProvider = class {
@@ -4993,11 +5098,32 @@ var init_KokoroProvider = __esm({
4993
5098
  }
4994
5099
  try {
4995
5100
  const model = await loadModel(options.onProgress);
4996
- const audio = await model.generate(text, {
5101
+ const voiceOptions = {
4997
5102
  voice: options.voice ?? KOKORO_DEFAULT_VOICE,
4998
5103
  speed: options.speed ?? 1
4999
- });
5000
- const buffer = Buffer.from(audio.toWav());
5104
+ };
5105
+ const chunks = splitForKokoro(text);
5106
+ let buffer;
5107
+ if (chunks.length === 1) {
5108
+ buffer = Buffer.from((await model.generate(chunks[0], voiceOptions)).toWav());
5109
+ } else {
5110
+ const parts = [];
5111
+ let sampleRate = 24e3;
5112
+ for (const chunk of chunks) {
5113
+ const audio = await model.generate(chunk, voiceOptions);
5114
+ if (!audio.audio)
5115
+ throw new Error("Kokoro returned no raw samples to join");
5116
+ parts.push(audio.audio);
5117
+ sampleRate = audio.sampling_rate ?? sampleRate;
5118
+ }
5119
+ const samples = new Float32Array(parts.reduce((n2, part) => n2 + part.length, 0));
5120
+ let offset = 0;
5121
+ for (const part of parts) {
5122
+ samples.set(part, offset);
5123
+ offset += part.length;
5124
+ }
5125
+ buffer = encodeFloatWav(samples, sampleRate);
5126
+ }
5001
5127
  return {
5002
5128
  success: true,
5003
5129
  audioBuffer: buffer,
@@ -5032,11 +5158,12 @@ var init_kokoro = __esm({
5032
5158
  });
5033
5159
 
5034
5160
  // ../ai-providers/dist/openai-image/OpenAIImageProvider.js
5035
- var DEFAULT_MODEL, OpenAIImageProvider, openaiImageProvider;
5161
+ var OPENAI_IMAGE_DEFAULT_MODEL, DEFAULT_MODEL, OpenAIImageProvider, openaiImageProvider;
5036
5162
  var init_OpenAIImageProvider = __esm({
5037
5163
  "../ai-providers/dist/openai-image/OpenAIImageProvider.js"() {
5038
5164
  "use strict";
5039
- DEFAULT_MODEL = "gpt-image-2";
5165
+ OPENAI_IMAGE_DEFAULT_MODEL = "gpt-image-2.5-sunburst";
5166
+ DEFAULT_MODEL = OPENAI_IMAGE_DEFAULT_MODEL;
5040
5167
  OpenAIImageProvider = class {
5041
5168
  constructor() {
5042
5169
  this.id = "openai-image";
@@ -5058,7 +5185,7 @@ var init_OpenAIImageProvider = __esm({
5058
5185
  }
5059
5186
  /**
5060
5187
  * Generate images from text prompt
5061
- * Uses GPT Image 1.5 by default (fastest, best quality)
5188
+ * Uses GPT Image 2.5 Sunburst by default
5062
5189
  */
5063
5190
  async generateImage(prompt3, options = {}) {
5064
5191
  if (!this.apiKey) {
@@ -5068,28 +5195,20 @@ var init_OpenAIImageProvider = __esm({
5068
5195
  };
5069
5196
  }
5070
5197
  const model = options.model || DEFAULT_MODEL;
5071
- const isGPTImage = model === "gpt-image-1.5" || model === "gpt-image-2";
5072
5198
  try {
5073
5199
  const body = {
5074
5200
  model,
5075
5201
  prompt: prompt3,
5076
5202
  n: options.n || 1
5077
5203
  };
5078
- if (isGPTImage) {
5079
- const qualityMap = {
5080
- standard: "medium",
5081
- hd: "high"
5082
- };
5083
- const quality = options.quality || "medium";
5084
- body.quality = qualityMap[quality] || quality;
5085
- if (options.size && options.size !== "auto") {
5086
- body.size = options.size;
5087
- }
5088
- } else {
5089
- body.response_format = "url";
5090
- body.size = options.size || "1024x1024";
5091
- body.quality = options.quality === "high" ? "hd" : options.quality || "standard";
5092
- body.style = options.style || "vivid";
5204
+ const qualityMap = {
5205
+ standard: "medium",
5206
+ hd: "high"
5207
+ };
5208
+ const quality = options.quality || "medium";
5209
+ body.quality = qualityMap[quality] || quality;
5210
+ if (options.size && options.size !== "auto") {
5211
+ body.size = options.size;
5093
5212
  }
5094
5213
  const response = await fetch(`${this.baseUrl}/images/generations`, {
5095
5214
  method: "POST",
@@ -5242,49 +5361,6 @@ var init_OpenAIImageProvider = __esm({
5242
5361
  };
5243
5362
  }
5244
5363
  }
5245
- /**
5246
- * Create image variations (uses DALL-E 2)
5247
- */
5248
- async createVariation(imageBuffer, options = {}) {
5249
- if (!this.apiKey) {
5250
- return {
5251
- success: false,
5252
- error: "OpenAI API key not configured"
5253
- };
5254
- }
5255
- try {
5256
- const formData = new FormData();
5257
- const uint8Array = new Uint8Array(imageBuffer);
5258
- formData.append("image", new Blob([uint8Array], { type: "image/png" }), "image.png");
5259
- formData.append("model", "dall-e-2");
5260
- formData.append("n", String(options.n || 1));
5261
- formData.append("size", options.size || "1024x1024");
5262
- const response = await fetch(`${this.baseUrl}/images/variations`, {
5263
- method: "POST",
5264
- headers: {
5265
- Authorization: `Bearer ${this.apiKey}`
5266
- },
5267
- body: formData
5268
- });
5269
- if (!response.ok) {
5270
- const error = await response.text();
5271
- return {
5272
- success: false,
5273
- error: `API error: ${response.status} - ${error}`
5274
- };
5275
- }
5276
- const data2 = await response.json();
5277
- return {
5278
- success: true,
5279
- images: data2.data.map((img) => ({ url: img.url }))
5280
- };
5281
- } catch (error) {
5282
- return {
5283
- success: false,
5284
- error: error instanceof Error ? error.message : "Unknown error"
5285
- };
5286
- }
5287
- }
5288
5364
  };
5289
5365
  openaiImageProvider = new OpenAIImageProvider();
5290
5366
  }
@@ -5715,12 +5791,33 @@ var init_runway = __esm({
5715
5791
 
5716
5792
  // ../ai-providers/dist/kling/KlingProvider.js
5717
5793
  import { createHmac } from "node:crypto";
5794
+ function resolveKlingModel(alias) {
5795
+ const key2 = (alias ?? "v3").trim().toLowerCase();
5796
+ const aliases2 = {
5797
+ v3: "kling-v3",
5798
+ "kling-v3": "kling-v3",
5799
+ "v2.6": "kling-v2-6",
5800
+ "kling-v2-6": "kling-v2-6",
5801
+ "v2.5-turbo": "kling-v2-5-turbo",
5802
+ "v2.5": "kling-v2-5-turbo",
5803
+ "kling-v2-5-turbo": "kling-v2-5-turbo"
5804
+ };
5805
+ if (Object.hasOwn(aliases2, key2))
5806
+ return aliases2[key2];
5807
+ throw new Error(`Unknown Kling model "${alias}". Valid: v3, v2.6, v2.5-turbo.`);
5808
+ }
5809
+ function klingDuration(model, seconds) {
5810
+ const requested = typeof seconds === "number" && Number.isFinite(seconds) ? Math.round(seconds) : 5;
5811
+ if (model === "kling-v3")
5812
+ return String(Math.max(3, Math.min(15, requested)));
5813
+ return requested >= 10 ? "10" : "5";
5814
+ }
5718
5815
  var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
5719
5816
  var init_KlingProvider = __esm({
5720
5817
  "../ai-providers/dist/kling/KlingProvider.js"() {
5721
5818
  "use strict";
5722
- DEFAULT_MODEL4 = "kling-v2-5-turbo";
5723
- STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3", "kling-v3-omni"];
5819
+ DEFAULT_MODEL4 = "kling-v3";
5820
+ STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3"];
5724
5821
  KlingProvider = class {
5725
5822
  constructor() {
5726
5823
  this.id = "kling";
@@ -5735,11 +5832,11 @@ var init_KlingProvider = __esm({
5735
5832
  async initialize(config4) {
5736
5833
  if (config4.apiKey) {
5737
5834
  const parts = config4.apiKey.split(":");
5738
- if (parts.length === 2) {
5835
+ if (parts.length === 2 && parts[0] && parts[1]) {
5739
5836
  this.accessKey = parts[0];
5740
5837
  this.secretKey = parts[1];
5741
5838
  } else {
5742
- this.accessKey = config4.apiKey;
5839
+ this.apiKey = config4.apiKey;
5743
5840
  }
5744
5841
  }
5745
5842
  if (config4.baseUrl) {
@@ -5747,7 +5844,11 @@ var init_KlingProvider = __esm({
5747
5844
  }
5748
5845
  }
5749
5846
  isConfigured() {
5750
- return !!(this.accessKey && this.secretKey);
5847
+ return !!(this.apiKey || this.accessKey && this.secretKey);
5848
+ }
5849
+ /** Bearer value: the API key itself, or a JWT signed from the legacy pair. */
5850
+ bearerToken() {
5851
+ return this.apiKey ?? this.generateToken();
5751
5852
  }
5752
5853
  /**
5753
5854
  * Generate JWT token for Kling API authentication
@@ -5777,11 +5878,11 @@ var init_KlingProvider = __esm({
5777
5878
  return {
5778
5879
  id: "",
5779
5880
  status: "failed",
5780
- error: "Kling API credentials not configured. Use format: KLING_ACCESS_KEY:KLING_SECRET_KEY"
5881
+ error: "Kling API credentials not configured. Set KLING_API_KEY to your Kling API key (or the legacy ACCESS_KEY:SECRET_KEY pair)."
5781
5882
  };
5782
5883
  }
5783
5884
  try {
5784
- const token = this.generateToken();
5885
+ const token = this.bearerToken();
5785
5886
  const model = options?.model || DEFAULT_MODEL4;
5786
5887
  let mode = options?.mode || "std";
5787
5888
  if (!STD_MODE_MODELS.includes(model) && mode === "std") {
@@ -5799,7 +5900,7 @@ var init_KlingProvider = __esm({
5799
5900
  model_name: model,
5800
5901
  mode,
5801
5902
  aspect_ratio: aspectRatioMap[options?.aspectRatio || "16:9"] || "16:9",
5802
- duration: options?.duration === 10 ? "10" : "5"
5903
+ duration: klingDuration(model, options?.duration)
5803
5904
  };
5804
5905
  if (options?.negativePrompt) {
5805
5906
  body.negative_prompt = options.negativePrompt;
@@ -5911,7 +6012,7 @@ var init_KlingProvider = __esm({
5911
6012
  };
5912
6013
  }
5913
6014
  try {
5914
- const token = this.generateToken();
6015
+ const token = this.bearerToken();
5915
6016
  const response = await fetch(`${this.baseUrl}/videos/${type}/${id}`, {
5916
6017
  headers: {
5917
6018
  "Content-Type": "application/json",
@@ -5993,11 +6094,11 @@ var init_KlingProvider = __esm({
5993
6094
  return {
5994
6095
  id: "",
5995
6096
  status: "failed",
5996
- error: "Kling API credentials not configured. Use format: KLING_ACCESS_KEY:KLING_SECRET_KEY"
6097
+ error: "Kling API credentials not configured. Set KLING_API_KEY to your Kling API key (or the legacy ACCESS_KEY:SECRET_KEY pair)."
5997
6098
  };
5998
6099
  }
5999
6100
  try {
6000
- const token = this.generateToken();
6101
+ const token = this.bearerToken();
6001
6102
  const body = {
6002
6103
  video_id: videoId,
6003
6104
  duration: options?.duration || "5"
@@ -6037,7 +6138,7 @@ var init_KlingProvider = __esm({
6037
6138
  };
6038
6139
  }
6039
6140
  try {
6040
- const token = this.generateToken();
6141
+ const token = this.bearerToken();
6041
6142
  const response = await fetch(`${this.baseUrl}/videos/video-extend/${id}`, {
6042
6143
  headers: {
6043
6144
  "Content-Type": "application/json",
@@ -6153,11 +6254,34 @@ var init_kling = __esm({
6153
6254
  });
6154
6255
 
6155
6256
  // ../ai-providers/dist/grok/GrokProvider.js
6156
- var DEFAULT_MODEL5, GrokProvider, grokProvider;
6257
+ function resolveGrokVideoModel(alias) {
6258
+ const key2 = (alias ?? "1.5").trim().toLowerCase();
6259
+ const aliases2 = {
6260
+ "1.5": "grok-imagine-video-1.5",
6261
+ "grok-imagine-video-1.5": "grok-imagine-video-1.5",
6262
+ lite: "grok-imagine-video-1.5-lite",
6263
+ "1.5-lite": "grok-imagine-video-1.5-lite",
6264
+ "grok-imagine-video-1.5-lite": "grok-imagine-video-1.5-lite",
6265
+ classic: "grok-imagine-video",
6266
+ "grok-imagine-video": "grok-imagine-video"
6267
+ };
6268
+ if (Object.hasOwn(aliases2, key2))
6269
+ return aliases2[key2];
6270
+ throw new Error(`Unknown Grok video model "${alias}". Valid: 1.5, lite, classic.`);
6271
+ }
6272
+ function resolveGrokImageModel(alias) {
6273
+ if (alias === "pro" || alias === "2.0" || alias === "quality" || alias === "grok-imagine-image-2.0") {
6274
+ return { model: "grok-imagine-image-2.0", quality: "medium" };
6275
+ }
6276
+ return { model: "grok-imagine-image" };
6277
+ }
6278
+ var DEFAULT_MODEL5, DEFAULT_VIDEO_RESOLUTION, GROK_VIDEO_RESOLUTIONS, GrokProvider, grokProvider;
6157
6279
  var init_GrokProvider = __esm({
6158
6280
  "../ai-providers/dist/grok/GrokProvider.js"() {
6159
6281
  "use strict";
6160
- DEFAULT_MODEL5 = "grok-imagine-video";
6282
+ DEFAULT_MODEL5 = "grok-imagine-video-1.5";
6283
+ DEFAULT_VIDEO_RESOLUTION = "720p";
6284
+ GROK_VIDEO_RESOLUTIONS = ["480p", "720p", "1080p"];
6161
6285
  GrokProvider = class {
6162
6286
  constructor() {
6163
6287
  this.id = "grok";
@@ -6191,6 +6315,7 @@ var init_GrokProvider = __esm({
6191
6315
  try {
6192
6316
  const body = {
6193
6317
  model: options.model || "grok-imagine-image",
6318
+ ...options.quality ? { quality: options.quality } : {},
6194
6319
  prompt: prompt3,
6195
6320
  n: options.n || 1,
6196
6321
  response_format: options.responseFormat || "url"
@@ -6258,6 +6383,7 @@ var init_GrokProvider = __esm({
6258
6383
  const dataUri = `data:image/png;base64,${base64}`;
6259
6384
  const body = {
6260
6385
  model: options.model || "grok-imagine-image",
6386
+ ...options.quality ? { quality: options.quality } : {},
6261
6387
  prompt: prompt3,
6262
6388
  image: {
6263
6389
  url: dataUri,
@@ -6324,11 +6450,15 @@ var init_GrokProvider = __esm({
6324
6450
  try {
6325
6451
  const duration = Math.round(Math.min(15, Math.max(1, options?.duration || 5)));
6326
6452
  const body = {
6327
- model: DEFAULT_MODEL5,
6453
+ model: options?.model || DEFAULT_MODEL5,
6328
6454
  prompt: prompt3,
6329
6455
  duration,
6330
- aspect_ratio: options?.aspectRatio || "16:9"
6456
+ aspect_ratio: options?.aspectRatio || "16:9",
6457
+ resolution: GROK_VIDEO_RESOLUTIONS.includes(options?.resolution ?? "") ? options.resolution : DEFAULT_VIDEO_RESOLUTION
6331
6458
  };
6459
+ if (typeof options?.generateAudio === "boolean") {
6460
+ body.generate_audio = options.generateAudio;
6461
+ }
6332
6462
  if (options?.referenceImage) {
6333
6463
  body.image = { url: options.referenceImage };
6334
6464
  }
@@ -6390,13 +6520,14 @@ var init_GrokProvider = __esm({
6390
6520
  const statusMap = {
6391
6521
  pending: "pending",
6392
6522
  done: "completed",
6393
- expired: "failed"
6523
+ expired: "failed",
6524
+ failed: "failed"
6394
6525
  };
6395
6526
  return {
6396
6527
  id,
6397
6528
  status: statusMap[data2.status] || "pending",
6398
6529
  videoUrl: data2.video?.url,
6399
- error: data2.status === "expired" ? "Generation expired" : void 0
6530
+ error: data2.status === "expired" ? "Generation expired" : data2.status === "failed" ? `Generation failed: ${data2.error?.message ?? data2.error?.code ?? "unknown error"}` : void 0
6400
6531
  };
6401
6532
  } catch (error) {
6402
6533
  return {
@@ -10590,14 +10721,30 @@ var require_src = __commonJS({
10590
10721
  });
10591
10722
 
10592
10723
  // ../ai-providers/dist/fal/FalProvider.js
10724
+ function resolveSeedanceVariant(alias) {
10725
+ const key2 = (alias ?? "quality").trim().toLowerCase();
10726
+ const aliases2 = {
10727
+ quality: "seedance-2.0",
10728
+ "2.0": "seedance-2.0",
10729
+ "seedance-2.0": "seedance-2.0",
10730
+ fast: "seedance-2.0-fast",
10731
+ "seedance-2.0-fast": "seedance-2.0-fast",
10732
+ "2.5": "seedance-2.5",
10733
+ "seedance-2.5": "seedance-2.5"
10734
+ };
10735
+ if (Object.hasOwn(aliases2, key2))
10736
+ return aliases2[key2];
10737
+ throw new Error(`Unknown Seedance model "${alias}". Valid: quality, fast, 2.5.`);
10738
+ }
10593
10739
  function estimateSeedanceVideoCostUsd(opts) {
10594
10740
  const shortSide = SEEDANCE_SHORT_SIDE[opts.resolution ?? "720p"] ?? 720;
10595
10741
  const [a4, b4] = (opts.aspectRatio ?? "16:9").split(":").map(Number);
10596
10742
  const ratioFactor = a4 > 0 && b4 > 0 ? Math.max(a4, b4) / Math.min(a4, b4) : 16 / 9;
10597
10743
  const longSide = Math.round(shortSide * ratioFactor);
10598
10744
  const tokensPerSecond = shortSide * longSide * 24 / 1024;
10599
- let usdPerSecond = tokensPerSecond / 1e3 * SEEDANCE_USD_PER_1K_TOKENS;
10600
- if (opts.fast && shortSide <= 720)
10745
+ const rate = opts.v25 ? shortSide >= 1080 ? SEEDANCE_25_1080P_USD_PER_1K_TOKENS : SEEDANCE_25_USD_PER_1K_TOKENS : SEEDANCE_USD_PER_1K_TOKENS;
10746
+ let usdPerSecond = tokensPerSecond / 1e3 * rate;
10747
+ if (opts.fast && !opts.v25 && shortSide <= 720)
10601
10748
  usdPerSecond *= SEEDANCE_FAST_FACTOR;
10602
10749
  if (opts.hasVideoReference)
10603
10750
  usdPerSecond *= SEEDANCE_VIDEO_REF_FACTOR;
@@ -10705,34 +10852,42 @@ function normaliseResolution(value) {
10705
10852
  return "1080p";
10706
10853
  return "720p";
10707
10854
  }
10708
- function normaliseDuration(value) {
10709
- if (typeof value !== "number")
10710
- return "auto";
10711
- if (!Number.isFinite(value))
10855
+ function normaliseDuration(value, maxSec) {
10856
+ if (typeof value !== "number" || !Number.isFinite(value))
10712
10857
  return "auto";
10713
- return Math.max(4, Math.min(15, Math.round(value)));
10858
+ return String(Math.max(4, Math.min(maxSec, Math.round(value))));
10714
10859
  }
10715
- var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, ENDPOINT_REFERENCE_TO_VIDEO, DEFAULT_VARIANT, VALID_RESOLUTIONS, VALID_ASPECTS, SEEDANCE_USD_PER_1K_TOKENS, SEEDANCE_FAST_FACTOR, SEEDANCE_VIDEO_REF_FACTOR, SEEDANCE_SHORT_SIDE, FalProvider, falProvider;
10860
+ var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, ENDPOINT_REFERENCE_TO_VIDEO, DEFAULT_VARIANT, MAX_DURATION_SEC, VALID_RESOLUTIONS, VALID_ASPECTS, SEEDANCE_USD_PER_1K_TOKENS, SEEDANCE_25_USD_PER_1K_TOKENS, SEEDANCE_25_1080P_USD_PER_1K_TOKENS, SEEDANCE_FAST_FACTOR, SEEDANCE_VIDEO_REF_FACTOR, SEEDANCE_SHORT_SIDE, FalProvider, falProvider;
10716
10861
  var init_FalProvider = __esm({
10717
10862
  "../ai-providers/dist/fal/FalProvider.js"() {
10718
10863
  "use strict";
10719
10864
  import_client = __toESM(require_src(), 1);
10720
10865
  ENDPOINT_TEXT_TO_VIDEO = {
10721
10866
  "seedance-2.0": "bytedance/seedance-2.0/text-to-video",
10722
- "seedance-2.0-fast": "bytedance/seedance-2.0/fast/text-to-video"
10867
+ "seedance-2.0-fast": "bytedance/seedance-2.0/fast/text-to-video",
10868
+ "seedance-2.5": "bytedance/seedance-2.5/text-to-video"
10723
10869
  };
10724
10870
  ENDPOINT_IMAGE_TO_VIDEO = {
10725
10871
  "seedance-2.0": "bytedance/seedance-2.0/image-to-video",
10726
- "seedance-2.0-fast": "bytedance/seedance-2.0/fast/image-to-video"
10872
+ "seedance-2.0-fast": "bytedance/seedance-2.0/fast/image-to-video",
10873
+ "seedance-2.5": "bytedance/seedance-2.5/image-to-video"
10727
10874
  };
10728
10875
  ENDPOINT_REFERENCE_TO_VIDEO = {
10729
10876
  "seedance-2.0": "bytedance/seedance-2.0/reference-to-video",
10730
- "seedance-2.0-fast": "bytedance/seedance-2.0/fast/reference-to-video"
10877
+ "seedance-2.0-fast": "bytedance/seedance-2.0/fast/reference-to-video",
10878
+ "seedance-2.5": "bytedance/seedance-2.5/reference-to-video"
10731
10879
  };
10732
10880
  DEFAULT_VARIANT = "seedance-2.0";
10881
+ MAX_DURATION_SEC = {
10882
+ "seedance-2.0": 15,
10883
+ "seedance-2.0-fast": 15,
10884
+ "seedance-2.5": 30
10885
+ };
10733
10886
  VALID_RESOLUTIONS = ["480p", "720p", "1080p"];
10734
10887
  VALID_ASPECTS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "auto"];
10735
10888
  SEEDANCE_USD_PER_1K_TOKENS = 0.014;
10889
+ SEEDANCE_25_USD_PER_1K_TOKENS = 0.0214;
10890
+ SEEDANCE_25_1080P_USD_PER_1K_TOKENS = 0.0234;
10736
10891
  SEEDANCE_FAST_FACTOR = 0.8;
10737
10892
  SEEDANCE_VIDEO_REF_FACTOR = 0.6;
10738
10893
  SEEDANCE_SHORT_SIDE = { "480p": 480, "720p": 720, "1080p": 1080 };
@@ -10787,7 +10942,7 @@ var init_FalProvider = __esm({
10787
10942
  const endpointId = hasReferences ? ENDPOINT_REFERENCE_TO_VIDEO[variant] : isImageToVideo ? ENDPOINT_IMAGE_TO_VIDEO[variant] : ENDPOINT_TEXT_TO_VIDEO[variant];
10788
10943
  const aspect = normaliseAspect(options?.aspectRatio);
10789
10944
  const resolution = normaliseResolution(options?.resolution);
10790
- const duration = normaliseDuration(options?.duration);
10945
+ const duration = normaliseDuration(options?.duration, MAX_DURATION_SEC[variant]);
10791
10946
  const input3 = {
10792
10947
  prompt: prompt3,
10793
10948
  aspect_ratio: aspect,
@@ -10805,10 +10960,12 @@ var init_FalProvider = __esm({
10805
10960
  } else if (referenceImage) {
10806
10961
  input3.image_url = referenceImage;
10807
10962
  }
10808
- if (options?.negativePrompt)
10809
- input3.negative_prompt = options.negativePrompt;
10810
- if (typeof options?.seed === "number")
10811
- input3.seed = options.seed;
10963
+ if (variant !== "seedance-2.5") {
10964
+ if (options?.negativePrompt)
10965
+ input3.negative_prompt = options.negativePrompt;
10966
+ if (typeof options?.seed === "number")
10967
+ input3.seed = options.seed;
10968
+ }
10812
10969
  if (typeof options?.generateAudio === "boolean")
10813
10970
  input3.generate_audio = options.generateAudio;
10814
10971
  if (options?.endUserId)
@@ -11535,6 +11692,7 @@ var init_replicate = __esm({
11535
11692
  var dist_exports = {};
11536
11693
  __export(dist_exports, {
11537
11694
  ClaudeProvider: () => ClaudeProvider,
11695
+ ELEVENLABS_MUSIC_MODEL: () => ELEVENLABS_MUSIC_MODEL,
11538
11696
  ElevenLabsProvider: () => ElevenLabsProvider,
11539
11697
  FalProvider: () => FalProvider,
11540
11698
  GEMINI_AGENT_DEFAULT_TEXT_MODEL: () => GEMINI_AGENT_DEFAULT_TEXT_MODEL,
@@ -11548,6 +11706,7 @@ __export(dist_exports, {
11548
11706
  KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
11549
11707
  KlingProvider: () => KlingProvider,
11550
11708
  KokoroProvider: () => KokoroProvider,
11709
+ OPENAI_IMAGE_DEFAULT_MODEL: () => OPENAI_IMAGE_DEFAULT_MODEL,
11551
11710
  OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
11552
11711
  OllamaProvider: () => OllamaProvider,
11553
11712
  OmniProvider: () => OmniProvider,
@@ -11556,6 +11715,7 @@ __export(dist_exports, {
11556
11715
  OpenAiTtsProvider: () => OpenAiTtsProvider,
11557
11716
  ReplicateProvider: () => ReplicateProvider,
11558
11717
  RunwayProvider: () => RunwayProvider,
11718
+ VEO_MODEL_ALIASES: () => VEO_MODEL_ALIASES,
11559
11719
  WhisperProvider: () => WhisperProvider,
11560
11720
  claudeProvider: () => claudeProvider,
11561
11721
  defineApiKey: () => defineApiKey,
@@ -11576,6 +11736,7 @@ __export(dist_exports, {
11576
11736
  getSetupProviders: () => getSetupProviders,
11577
11737
  grokProvider: () => grokProvider,
11578
11738
  isGeminiTextModelAlias: () => isGeminiTextModelAlias,
11739
+ klingDuration: () => klingDuration,
11579
11740
  klingProvider: () => klingProvider,
11580
11741
  kokoroProvider: () => kokoroProvider,
11581
11742
  loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
@@ -11588,6 +11749,11 @@ __export(dist_exports, {
11588
11749
  providerRegistry: () => providerRegistry,
11589
11750
  replicateProvider: () => replicateProvider,
11590
11751
  resolveGeminiTextModel: () => resolveGeminiTextModel,
11752
+ resolveGrokImageModel: () => resolveGrokImageModel,
11753
+ resolveGrokVideoModel: () => resolveGrokVideoModel,
11754
+ resolveKlingModel: () => resolveKlingModel,
11755
+ resolveSeedanceVariant: () => resolveSeedanceVariant,
11756
+ resolveVeoModel: () => resolveVeoModel,
11591
11757
  resolveVoiceId: () => resolveVoiceId,
11592
11758
  runwayProvider: () => runwayProvider,
11593
11759
  whisperProvider: () => whisperProvider
@@ -20653,8 +20819,14 @@ __export(ai_video_exports, {
20653
20819
  executeVideoGenerate: () => executeVideoGenerate,
20654
20820
  executeVideoStatus: () => executeVideoStatus
20655
20821
  });
20656
- import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
20657
- import { resolve as resolve3 } from "node:path";
20822
+ import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
20823
+ import { dirname as dirname2, resolve as resolve3 } from "node:path";
20824
+ async function saveOutput(output3, buffer) {
20825
+ const outputPath = resolve3(process.cwd(), output3);
20826
+ await mkdir2(dirname2(outputPath), { recursive: true });
20827
+ await writeFile3(outputPath, buffer);
20828
+ return outputPath;
20829
+ }
20658
20830
  async function executeVideoGenerate(options) {
20659
20831
  const {
20660
20832
  prompt: prompt3,
@@ -20671,6 +20843,8 @@ async function executeVideoGenerate(options) {
20671
20843
  resolution,
20672
20844
  veoModel = "3.1-fast",
20673
20845
  seedanceModel = "quality",
20846
+ grokModel,
20847
+ klingModel,
20674
20848
  generateAudio,
20675
20849
  output: output3,
20676
20850
  wait = true,
@@ -20725,7 +20899,7 @@ async function executeVideoGenerate(options) {
20725
20899
  });
20726
20900
  falImage = upload.url;
20727
20901
  }
20728
- const model = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
20902
+ const model = resolveSeedanceVariant(seedanceModel);
20729
20903
  const result = await fal.generateVideo(prompt3, {
20730
20904
  prompt: prompt3,
20731
20905
  referenceImage: references.length > 0 ? void 0 : falImage,
@@ -20742,8 +20916,7 @@ async function executeVideoGenerate(options) {
20742
20916
  let outputPath;
20743
20917
  if (output3 && result.videoUrl) {
20744
20918
  const buffer = await downloadVideo(result.videoUrl, key2);
20745
- outputPath = resolve3(process.cwd(), output3);
20746
- await writeFile3(outputPath, buffer);
20919
+ outputPath = await saveOutput(output3, buffer);
20747
20920
  }
20748
20921
  return {
20749
20922
  success: true,
@@ -20774,8 +20947,7 @@ async function executeVideoGenerate(options) {
20774
20947
  let outputPath;
20775
20948
  if (output3 && finalResult.videoUrl) {
20776
20949
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
20777
- outputPath = resolve3(process.cwd(), output3);
20778
- await writeFile3(outputPath, buffer);
20950
+ outputPath = await saveOutput(output3, buffer);
20779
20951
  }
20780
20952
  return {
20781
20953
  success: true,
@@ -20801,6 +20973,7 @@ async function executeVideoGenerate(options) {
20801
20973
  }
20802
20974
  const result = await kling.generateVideo(prompt3, {
20803
20975
  prompt: prompt3,
20976
+ model: resolveKlingModel(klingModel),
20804
20977
  referenceImage: klingImage,
20805
20978
  duration,
20806
20979
  aspectRatio: ratio,
@@ -20819,8 +20992,7 @@ async function executeVideoGenerate(options) {
20819
20992
  let outputPath;
20820
20993
  if (output3 && finalResult.videoUrl) {
20821
20994
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
20822
- outputPath = resolve3(process.cwd(), output3);
20823
- await writeFile3(outputPath, buffer);
20995
+ outputPath = await saveOutput(output3, buffer);
20824
20996
  }
20825
20997
  return {
20826
20998
  success: true,
@@ -20834,12 +21006,7 @@ async function executeVideoGenerate(options) {
20834
21006
  } else if (provider === "veo") {
20835
21007
  const gemini = new GeminiProvider();
20836
21008
  await gemini.initialize({ apiKey: key2 });
20837
- const veoModelMap = {
20838
- "3.0": "veo-3.0-generate-preview",
20839
- "3.1": "veo-3.1-generate-preview",
20840
- "3.1-fast": "veo-3.1-fast-generate-preview"
20841
- };
20842
- const model = veoModelMap[veoModel] || "veo-3.1-fast-generate-preview";
21009
+ const model = resolveVeoModel(veoModel);
20843
21010
  const veoDuration = duration <= 6 ? 6 : 8;
20844
21011
  const result = await gemini.generateVideo(prompt3, {
20845
21012
  prompt: prompt3,
@@ -20860,8 +21027,7 @@ async function executeVideoGenerate(options) {
20860
21027
  let outputPath;
20861
21028
  if (output3 && finalResult.videoUrl) {
20862
21029
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
20863
- outputPath = resolve3(process.cwd(), output3);
20864
- await writeFile3(outputPath, buffer);
21030
+ outputPath = await saveOutput(output3, buffer);
20865
21031
  }
20866
21032
  return {
20867
21033
  success: true,
@@ -20876,9 +21042,12 @@ async function executeVideoGenerate(options) {
20876
21042
  await grok.initialize({ apiKey: key2 });
20877
21043
  const result = await grok.generateVideo(prompt3, {
20878
21044
  prompt: prompt3,
21045
+ model: resolveGrokVideoModel(grokModel),
20879
21046
  referenceImage,
20880
21047
  duration,
20881
- aspectRatio: ratio
21048
+ aspectRatio: ratio,
21049
+ resolution,
21050
+ generateAudio
20882
21051
  });
20883
21052
  if (result.status === "failed")
20884
21053
  return { success: false, error: result.error || "Grok generation failed" };
@@ -20891,8 +21060,7 @@ async function executeVideoGenerate(options) {
20891
21060
  let outputPath;
20892
21061
  if (output3 && finalResult.videoUrl) {
20893
21062
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
20894
- outputPath = resolve3(process.cwd(), output3);
20895
- await writeFile3(outputPath, buffer);
21063
+ outputPath = await saveOutput(output3, buffer);
20896
21064
  }
20897
21065
  return {
20898
21066
  success: true,
@@ -20909,7 +21077,8 @@ async function executeVideoGenerate(options) {
20909
21077
  const result = await omni.generateVideo(prompt3, {
20910
21078
  prompt: prompt3,
20911
21079
  referenceImage,
20912
- aspectRatio: ratio
21080
+ aspectRatio: ratio,
21081
+ resolution
20913
21082
  });
20914
21083
  if (result.status !== "completed" || !result.videoUrl) {
20915
21084
  return { success: false, error: result.error || "Gemini Omni generation failed" };
@@ -20917,8 +21086,7 @@ async function executeVideoGenerate(options) {
20917
21086
  let outputPath;
20918
21087
  if (output3) {
20919
21088
  const buffer = await downloadVideo(result.videoUrl, key2);
20920
- outputPath = resolve3(process.cwd(), output3);
20921
- await writeFile3(outputPath, buffer);
21089
+ outputPath = await saveOutput(output3, buffer);
20922
21090
  }
20923
21091
  return {
20924
21092
  success: true,
@@ -21014,8 +21182,7 @@ async function executeVideoStatus(options) {
21014
21182
  let outputPath;
21015
21183
  if (output3 && result.videoUrl) {
21016
21184
  const buffer = await downloadVideo(result.videoUrl);
21017
- outputPath = resolve3(process.cwd(), output3);
21018
- await writeFile3(outputPath, buffer);
21185
+ outputPath = await saveOutput(output3, buffer);
21019
21186
  }
21020
21187
  return {
21021
21188
  success: true,
@@ -21037,8 +21204,7 @@ async function executeVideoStatus(options) {
21037
21204
  let outputPath;
21038
21205
  if (output3 && result.videoUrl) {
21039
21206
  const buffer = await downloadVideo(result.videoUrl, key2);
21040
- outputPath = resolve3(process.cwd(), output3);
21041
- await writeFile3(outputPath, buffer);
21207
+ outputPath = await saveOutput(output3, buffer);
21042
21208
  }
21043
21209
  return {
21044
21210
  success: true,
@@ -21059,8 +21225,7 @@ async function executeVideoStatus(options) {
21059
21225
  let outputPath;
21060
21226
  if (output3 && result.videoUrl) {
21061
21227
  const buffer = await downloadVideo(result.videoUrl, key2);
21062
- outputPath = resolve3(process.cwd(), output3);
21063
- await writeFile3(outputPath, buffer);
21228
+ outputPath = await saveOutput(output3, buffer);
21064
21229
  }
21065
21230
  return {
21066
21231
  success: true,
@@ -21082,8 +21247,7 @@ async function executeVideoStatus(options) {
21082
21247
  let outputPath;
21083
21248
  if (output3 && result.videoUrl) {
21084
21249
  const buffer = await downloadVideo(result.videoUrl, key2);
21085
- outputPath = resolve3(process.cwd(), output3);
21086
- await writeFile3(outputPath, buffer);
21250
+ outputPath = await saveOutput(output3, buffer);
21087
21251
  }
21088
21252
  return {
21089
21253
  success: true,
@@ -21153,8 +21317,7 @@ async function executeVideoExtend(options) {
21153
21317
  let outputPath;
21154
21318
  if (output3 && finalResult.videoUrl) {
21155
21319
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
21156
- outputPath = resolve3(process.cwd(), output3);
21157
- await writeFile3(outputPath, buffer);
21320
+ outputPath = await saveOutput(output3, buffer);
21158
21321
  }
21159
21322
  return {
21160
21323
  success: true,
@@ -21169,12 +21332,7 @@ async function executeVideoExtend(options) {
21169
21332
  if (!key2) return { success: false, error: "GOOGLE_API_KEY required" };
21170
21333
  const gemini = new GeminiProvider();
21171
21334
  await gemini.initialize({ apiKey: key2 });
21172
- const veoModelMap = {
21173
- "3.0": "veo-3.0-generate-preview",
21174
- "3.1": "veo-3.1-generate-preview",
21175
- "3.1-fast": "veo-3.1-fast-generate-preview"
21176
- };
21177
- const model = veoModelMap[veoModel] || "veo-3.1-generate-preview";
21335
+ const model = resolveVeoModel(veoModel);
21178
21336
  const result = await gemini.extendVideo(videoId, prompt3, {
21179
21337
  duration,
21180
21338
  model
@@ -21189,8 +21347,7 @@ async function executeVideoExtend(options) {
21189
21347
  let outputPath;
21190
21348
  if (output3 && finalResult.videoUrl) {
21191
21349
  const buffer = await downloadVideo(finalResult.videoUrl, key2);
21192
- outputPath = resolve3(process.cwd(), output3);
21193
- await writeFile3(outputPath, buffer);
21350
+ outputPath = await saveOutput(output3, buffer);
21194
21351
  }
21195
21352
  return {
21196
21353
  success: true,
@@ -21252,8 +21409,8 @@ var init_music_status = __esm({
21252
21409
 
21253
21410
  // ../cli/src/commands/_shared/build-asset-metadata.ts
21254
21411
  import { existsSync, readFileSync } from "node:fs";
21255
- import { mkdir as mkdir2, writeFile as writeFile4 } from "node:fs/promises";
21256
- import { dirname as dirname2, join } from "node:path";
21412
+ import { mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
21413
+ import { dirname as dirname3, join } from "node:path";
21257
21414
  function assetMetadataPath(kind3, beatId) {
21258
21415
  return `.vibeframe/assets/${kind3}-${beatId}.json`;
21259
21416
  }
@@ -21301,7 +21458,7 @@ async function writeAssetMetadata(opts) {
21301
21458
  cachePath: opts.cachePath,
21302
21459
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
21303
21460
  };
21304
- await mkdir2(dirname2(abs), { recursive: true });
21461
+ await mkdir3(dirname3(abs), { recursive: true });
21305
21462
  await writeFile4(abs, JSON.stringify(metadata, null, 2) + "\n", "utf-8");
21306
21463
  }
21307
21464
  var init_build_asset_metadata = __esm({
@@ -22260,7 +22417,7 @@ var init_storyboard_edit = __esm({
22260
22417
 
22261
22418
  // ../cli/src/commands/_shared/storyboard-source.ts
22262
22419
  import { existsSync as existsSync2 } from "node:fs";
22263
- import { mkdir as mkdir3, readdir, readFile as readFile4, rename, rm, writeFile as writeFile6 } from "node:fs/promises";
22420
+ import { mkdir as mkdir4, readdir, readFile as readFile4, rename, rm, writeFile as writeFile6 } from "node:fs/promises";
22264
22421
  import { basename, join as join3 } from "node:path";
22265
22422
  function sceneFileFrom(dir, filename) {
22266
22423
  const stem = filename.replace(/\.mdx?$/i, "");
@@ -22373,7 +22530,7 @@ ${(0, import_yaml5.stringify)(data2, { lineWidth: 0 }).trimEnd()}
22373
22530
  };
22374
22531
  }
22375
22532
  async function writeMigration(projectDir, plan2) {
22376
- await mkdir3(join3(projectDir, SCENES_DIRNAME), { recursive: true });
22533
+ await mkdir4(join3(projectDir, SCENES_DIRNAME), { recursive: true });
22377
22534
  for (const file of plan2.scenes) {
22378
22535
  await writeFile6(join3(projectDir, file.path), file.contents, "utf-8");
22379
22536
  }
@@ -22395,7 +22552,7 @@ function strayBeatIssues(strayBeatIds) {
22395
22552
  async function upsertScene(projectDir, opts) {
22396
22553
  const beatId = deriveBeatId(opts.beatId);
22397
22554
  const dir = join3(projectDir, SCENES_DIRNAME);
22398
- await mkdir3(dir, { recursive: true });
22555
+ await mkdir4(dir, { recursive: true });
22399
22556
  const cues = {};
22400
22557
  if (opts.duration !== void 0) cues.duration = opts.duration;
22401
22558
  if (opts.narration?.trim()) cues.narration = opts.narration.trim();
@@ -22467,22 +22624,22 @@ var init_storyboard_source = __esm({
22467
22624
  // ../cli/src/commands/_shared/status-jobs.ts
22468
22625
  import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
22469
22626
  import { existsSync as existsSync3, statSync } from "node:fs";
22470
- import { copyFile, mkdir as mkdir4, readFile as readFile5, readdir as readdir2, rename as rename2, stat, writeFile as writeFile7 } from "node:fs/promises";
22471
- import { dirname as dirname3, join as join4, parse as parse2, relative, resolve as resolve5 } from "node:path";
22627
+ import { copyFile, mkdir as mkdir5, readFile as readFile5, readdir as readdir2, rename as rename2, stat, writeFile as writeFile7 } from "node:fs/promises";
22628
+ import { dirname as dirname4, join as join4, parse as parse2, relative, resolve as resolve5 } from "node:path";
22472
22629
  function isLocalJob(record) {
22473
22630
  return record.jobType === "build" || record.jobType === "render";
22474
22631
  }
22475
22632
  function findProjectRoot(start = process.cwd()) {
22476
22633
  let dir = resolve5(start);
22477
22634
  try {
22478
- if (existsSync3(dir) && statSync(dir).isFile()) dir = dirname3(dir);
22635
+ if (existsSync3(dir) && statSync(dir).isFile()) dir = dirname4(dir);
22479
22636
  } catch {
22480
22637
  }
22481
22638
  for (; ; ) {
22482
22639
  if (existsSync3(join4(dir, "vibe.config.json")) || existsSync3(join4(dir, "STORYBOARD.md"))) {
22483
22640
  return dir;
22484
22641
  }
22485
- const parent = dirname3(dir);
22642
+ const parent = dirname4(dir);
22486
22643
  if (parent === dir) return resolve5(start);
22487
22644
  dir = parent;
22488
22645
  }
@@ -22549,7 +22706,7 @@ async function createAndWriteJobRecord(opts) {
22549
22706
  }
22550
22707
  async function writeJobRecord(record) {
22551
22708
  const dir = jobsDir(record.projectDir);
22552
- await mkdir4(dir, { recursive: true });
22709
+ await mkdir5(dir, { recursive: true });
22553
22710
  const path16 = jobRecordPath(record.id, record.projectDir);
22554
22711
  const tmp = `${path16}.${randomUUID2()}.tmp`;
22555
22712
  await writeFile7(tmp, JSON.stringify(stripUndefined2(record), null, 2) + "\n", "utf-8");
@@ -22597,7 +22754,7 @@ async function refreshJobRecord(record, opts = {}) {
22597
22754
  try {
22598
22755
  if (record.jobType === "generate-video") {
22599
22756
  const output3 = resolveRefreshOutput(record, opts);
22600
- if (output3) await mkdir4(dirname3(output3), { recursive: true });
22757
+ if (output3) await mkdir5(dirname4(output3), { recursive: true });
22601
22758
  const result = await executeVideoStatus({
22602
22759
  taskId: record.providerTaskId,
22603
22760
  provider: record.provider,
@@ -22880,14 +23037,14 @@ async function downloadUrl(url, outputPath) {
22880
23037
  const response = await fetch(url);
22881
23038
  if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`);
22882
23039
  const buffer = Buffer.from(await response.arrayBuffer());
22883
- await mkdir4(dirname3(outputPath), { recursive: true });
23040
+ await mkdir5(dirname4(outputPath), { recursive: true });
22884
23041
  await writeFile7(outputPath, buffer);
22885
23042
  return outputPath;
22886
23043
  }
22887
23044
  async function maybeCacheOutput(record) {
22888
23045
  if (record.status !== "completed" || !record.outputPath || !record.cachePath) return;
22889
23046
  try {
22890
- await mkdir4(dirname3(record.cachePath), { recursive: true });
23047
+ await mkdir5(dirname4(record.cachePath), { recursive: true });
22891
23048
  await copyFile(record.outputPath, record.cachePath);
22892
23049
  } catch {
22893
23050
  }
@@ -23471,7 +23628,7 @@ var init_project_config = __esm({
23471
23628
  });
23472
23629
 
23473
23630
  // ../cli/src/commands/_shared/scene-project.ts
23474
- import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile8, access as access3 } from "node:fs/promises";
23631
+ import { mkdir as mkdir6, readFile as readFile7, writeFile as writeFile8, access as access3 } from "node:fs/promises";
23475
23632
  import { resolve as resolve7, basename as basename2 } from "node:path";
23476
23633
  function isSceneKind(value) {
23477
23634
  return VALID_SCENE_KINDS.includes(value);
@@ -24083,11 +24240,11 @@ async function scaffoldSceneProject(opts) {
24083
24240
  const now = opts.now ?? /* @__PURE__ */ new Date();
24084
24241
  const profile = opts.profile ?? "full";
24085
24242
  const kind3 = opts.kind ?? DEFAULT_SCENE_KIND;
24086
- await mkdir5(dir, { recursive: true });
24243
+ await mkdir6(dir, { recursive: true });
24087
24244
  if (profile === "full") {
24088
- await mkdir5(resolve7(dir, "compositions"), { recursive: true });
24089
- await mkdir5(resolve7(dir, "assets"), { recursive: true });
24090
- await mkdir5(resolve7(dir, "renders"), { recursive: true });
24245
+ await mkdir6(resolve7(dir, "compositions"), { recursive: true });
24246
+ await mkdir6(resolve7(dir, "assets"), { recursive: true });
24247
+ await mkdir6(resolve7(dir, "renders"), { recursive: true });
24091
24248
  }
24092
24249
  const created = [];
24093
24250
  const skipped2 = [];
@@ -87788,7 +87945,7 @@ var require_yauzl = __commonJS({
87788
87945
  // ../../node_modules/.pnpm/@puppeteer+browsers@3.0.6_yauzl@2.10.0/node_modules/@puppeteer/browsers/lib/fileUtil.js
87789
87946
  import { spawnSync, spawn, execFile as execFile2 } from "node:child_process";
87790
87947
  import { constants as constants2, createReadStream, createWriteStream as createWriteStream2 } from "node:fs";
87791
- import { mkdir as mkdir7, readdir as readdir4, symlink as symlink2 } from "node:fs/promises";
87948
+ import { mkdir as mkdir8, readdir as readdir4, symlink as symlink2 } from "node:fs/promises";
87792
87949
  import * as path9 from "node:path";
87793
87950
  import { Stream, Writable as Writable2 } from "node:stream";
87794
87951
  import { pipeline } from "node:stream/promises";
@@ -87798,12 +87955,12 @@ async function unpackArchive(archivePath, folderPath) {
87798
87955
  folderPath = path9.resolve(process.cwd(), folderPath);
87799
87956
  }
87800
87957
  if (archivePath.endsWith(".zip")) {
87801
- await mkdir7(folderPath, { recursive: true });
87958
+ await mkdir8(folderPath, { recursive: true });
87802
87959
  await extractZip(archivePath, folderPath);
87803
87960
  } else if (archivePath.endsWith(".tar.bz2")) {
87804
87961
  await extractTar(archivePath, folderPath, "bzip2");
87805
87962
  } else if (archivePath.endsWith(".dmg")) {
87806
- await mkdir7(folderPath);
87963
+ await mkdir8(folderPath);
87807
87964
  await installDMG(archivePath, folderPath);
87808
87965
  } else if (archivePath.endsWith(".exe")) {
87809
87966
  const result = spawnSync(archivePath, [`/ExtractDir=${folderPath}`], {
@@ -87991,10 +88148,10 @@ async function extractZipEntry(zipFile, entry, folderPath) {
87991
88148
  const mode = unixMode === 0 ? isDirectory2 ? 493 : 420 : unixMode & 511;
87992
88149
  const destination = path9.join(folderPath, entry.fileName);
87993
88150
  if (isDirectory2) {
87994
- await mkdir7(destination, { recursive: true, mode });
88151
+ await mkdir8(destination, { recursive: true, mode });
87995
88152
  return;
87996
88153
  }
87997
- await mkdir7(path9.dirname(destination), { recursive: true });
88154
+ await mkdir8(path9.dirname(destination), { recursive: true });
87998
88155
  const readStream = await promisify2(zipFile.openReadStream.bind(zipFile))(entry);
87999
88156
  if (isSymlink) {
88000
88157
  const chunks = [];
@@ -88162,7 +88319,7 @@ var init_ProgressBar = __esm({
88162
88319
  import assert3 from "node:assert";
88163
88320
  import { spawnSync as spawnSync2 } from "node:child_process";
88164
88321
  import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
88165
- import { mkdir as mkdir8, unlink } from "node:fs/promises";
88322
+ import { mkdir as mkdir9, unlink } from "node:fs/promises";
88166
88323
  import os6 from "node:os";
88167
88324
  import path10 from "node:path";
88168
88325
  function debugTime(label) {
@@ -88215,7 +88372,7 @@ async function installWithProviders(options) {
88215
88372
  }
88216
88373
  debugInstall?.(`Successfully got URL from ${provider.getName()}: ${url}`);
88217
88374
  if (!existsSync5(browserRoot)) {
88218
- await mkdir8(browserRoot, { recursive: true });
88375
+ await mkdir9(browserRoot, { recursive: true });
88219
88376
  }
88220
88377
  return await installUrl(url, options, provider);
88221
88378
  } catch (err) {
@@ -88288,7 +88445,7 @@ async function installUrl(url, options, provider) {
88288
88445
  const browserRoot = cache.browserRoot(options.browser);
88289
88446
  const archivePath = path10.join(browserRoot, `${options.buildId}-${fileName}`);
88290
88447
  if (!existsSync5(browserRoot)) {
88291
- await mkdir8(browserRoot, { recursive: true });
88448
+ await mkdir9(browserRoot, { recursive: true });
88292
88449
  }
88293
88450
  if (options.expectedHash) {
88294
88451
  debugInstall?.(`Using provided checksum for ${fileName}: ${options.expectedHash}`);
@@ -89079,18 +89236,18 @@ var init_cliui = __esm({
89079
89236
  });
89080
89237
 
89081
89238
  // ../../node_modules/.pnpm/escalade@3.2.0/node_modules/escalade/sync/index.mjs
89082
- import { dirname as dirname6, resolve as resolve10 } from "path";
89239
+ import { dirname as dirname7, resolve as resolve10 } from "path";
89083
89240
  import { readdirSync, statSync as statSync2 } from "fs";
89084
89241
  function sync_default(start, callback) {
89085
89242
  let dir = resolve10(".", start);
89086
89243
  let tmp, stats = statSync2(dir);
89087
89244
  if (!stats.isDirectory()) {
89088
- dir = dirname6(dir);
89245
+ dir = dirname7(dir);
89089
89246
  }
89090
89247
  while (true) {
89091
89248
  tmp = callback(dir, readdirSync(dir));
89092
89249
  if (tmp) return resolve10(dir, tmp);
89093
- dir = dirname6(tmp = dir);
89250
+ dir = dirname7(tmp = dir);
89094
89251
  if (tmp === dir) break;
89095
89252
  }
89096
89253
  }
@@ -90359,7 +90516,7 @@ var require_get_caller_file = __commonJS({
90359
90516
  import { notStrictEqual, strictEqual } from "assert";
90360
90517
  import { inspect } from "util";
90361
90518
  import { fileURLToPath } from "url";
90362
- import { basename as basename4, dirname as dirname7, extname as extname2, relative as relative3, resolve as resolve13, join as join7 } from "path";
90519
+ import { basename as basename4, dirname as dirname8, extname as extname2, relative as relative3, resolve as resolve13, join as join7 } from "path";
90363
90520
  import { createRequire as createRequire2 } from "node:module";
90364
90521
  import { readFileSync as readFileSync5, readdirSync as readdirSync2 } from "node:fs";
90365
90522
  var import_get_caller_file, __dirname2, mainFilename, require3, esm_default;
@@ -90392,7 +90549,7 @@ var init_esm2 = __esm({
90392
90549
  Parser: lib_default,
90393
90550
  path: {
90394
90551
  basename: basename4,
90395
- dirname: dirname7,
90552
+ dirname: dirname8,
90396
90553
  extname: extname2,
90397
90554
  relative: relative3,
90398
90555
  resolve: resolve13,
@@ -95599,7 +95756,7 @@ var init_PuppeteerNode = __esm({
95599
95756
  import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
95600
95757
  import fs8 from "node:fs";
95601
95758
  import os10 from "node:os";
95602
- import { dirname as dirname8 } from "node:path";
95759
+ import { dirname as dirname9 } from "node:path";
95603
95760
  import { PassThrough } from "node:stream";
95604
95761
  function countFrames(startTimestamp, previousTimestamp, timestamp, fps) {
95605
95762
  const end = Math.round((timestamp - startTimestamp) * fps);
@@ -95723,7 +95880,7 @@ var init_ScreenRecorder = __esm({
95723
95880
  filters2.push(formatArgs.splice(vf, 2).at(-1) ?? "");
95724
95881
  }
95725
95882
  if (path16) {
95726
- fs8.mkdirSync(dirname8(path16), { recursive: overwrite });
95883
+ fs8.mkdirSync(dirname9(path16), { recursive: overwrite });
95727
95884
  }
95728
95885
  this.#process = spawn3(
95729
95886
  ffmpegPath,
@@ -96910,7 +97067,7 @@ import {
96910
97067
  symlinkSync,
96911
97068
  writeFileSync as writeFileSync6
96912
97069
  } from "node:fs";
96913
- import { basename as basename42, dirname as dirname11, isAbsolute as isAbsolute42, join as join21, relative as relative22, resolve as resolve122 } from "node:path";
97070
+ import { basename as basename42, dirname as dirname112, isAbsolute as isAbsolute42, join as join21, relative as relative22, resolve as resolve122 } from "node:path";
96914
97071
  import {
96915
97072
  basename as basename32,
96916
97073
  join as join20,
@@ -124195,7 +124352,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
124195
124352
  writeFileSync6(join21(compileDir, "index.html"), compiled.html, "utf-8");
124196
124353
  for (const [srcPath, html] of compiled.subCompositions) {
124197
124354
  const outPath = join21(compileDir, srcPath);
124198
- mkdirSync9(dirname11(outPath), { recursive: true });
124355
+ mkdirSync9(dirname112(outPath), { recursive: true });
124199
124356
  writeFileSync6(outPath, html, "utf-8");
124200
124357
  }
124201
124358
  for (const [relativePath, absolutePath] of compiled.externalAssets) {
@@ -124204,7 +124361,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
124204
124361
  console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
124205
124362
  continue;
124206
124363
  }
124207
- mkdirSync9(dirname11(outPath), { recursive: true });
124364
+ mkdirSync9(dirname112(outPath), { recursive: true });
124208
124365
  copyFileSync3(absolutePath, outPath);
124209
124366
  }
124210
124367
  if (includeSummary) {
@@ -267045,7 +267202,7 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
267045
267202
  materializePathModule = {
267046
267203
  resolve: resolve122,
267047
267204
  join: join21,
267048
- dirname: dirname11,
267205
+ dirname: dirname112,
267049
267206
  basename: basename42,
267050
267207
  relative: relative22,
267051
267208
  isAbsolute: isAbsolute42
@@ -269905,7 +270062,7 @@ __export(scene_render_exports, {
269905
270062
  });
269906
270063
  import { execFile as execFile4 } from "node:child_process";
269907
270064
  import { existsSync as existsSync49 } from "node:fs";
269908
- import { mkdir as mkdir12, readFile as readFile17, stat as stat5, writeFile as writeFile16 } from "node:fs/promises";
270065
+ import { mkdir as mkdir13, readFile as readFile17, stat as stat5, writeFile as writeFile16 } from "node:fs/promises";
269909
270066
  import { resolve as resolve33, relative as relative9, dirname as dirname26, basename as basename8, join as join61, isAbsolute as isAbsolute8 } from "node:path";
269910
270067
  import { promisify as promisify4 } from "node:util";
269911
270068
  function qualityToCrf(quality = "standard") {
@@ -270051,7 +270208,7 @@ async function executeSceneRender(opts = {}) {
270051
270208
  }
270052
270209
  const projectName = projectConfig.config.name;
270053
270210
  const outputPath = opts.output ? resolve33(projectDir, opts.output) : defaultOutputPath({ projectDir, projectName, format: opts.format, beatId: opts.beatId });
270054
- await mkdir12(dirname26(outputPath), { recursive: true });
270211
+ await mkdir13(dirname26(outputPath), { recursive: true });
270055
270212
  const config4 = buildRenderConfig({
270056
270213
  fps: opts.fps,
270057
270214
  quality: opts.quality,
@@ -270247,7 +270404,7 @@ async function prepareBeatRenderRoot(opts) {
270247
270404
  durationSec,
270248
270405
  narrationPath
270249
270406
  });
270250
- await mkdir12(dirname26(join61(opts.projectDir, root2)), { recursive: true });
270407
+ await mkdir13(dirname26(join61(opts.projectDir, root2)), { recursive: true });
270251
270408
  await writeFile16(join61(opts.projectDir, root2), html, "utf-8");
270252
270409
  return {
270253
270410
  success: true,
@@ -270532,7 +270689,7 @@ var init_design_parse = __esm({
270532
270689
 
270533
270690
  // ../cli/src/commands/_shared/compose-aivideo.ts
270534
270691
  import { existsSync as existsSync50 } from "node:fs";
270535
- import { mkdir as mkdir13, readFile as readFile18, writeFile as writeFile17 } from "node:fs/promises";
270692
+ import { mkdir as mkdir14, readFile as readFile18, writeFile as writeFile17 } from "node:fs/promises";
270536
270693
  import { join as join63, resolve as resolve34 } from "node:path";
270537
270694
  function headingDescriptor(heading) {
270538
270695
  const stripped = heading.replace(/^\s*beat\s+/i, "");
@@ -270695,7 +270852,7 @@ async function composeAiVideo(opts) {
270695
270852
  }
270696
270853
  clipRels.push(rel);
270697
270854
  }
270698
- await mkdir13(join63(projectDir, "assets"), { recursive: true });
270855
+ await mkdir14(join63(projectDir, "assets"), { recursive: true });
270699
270856
  const bgRel = "assets/bg-full.mp4";
270700
270857
  const concatArgs = buildBgConcatArgs(
270701
270858
  clipRels.map((r2) => join63(projectDir, r2)),
@@ -270703,7 +270860,7 @@ async function composeAiVideo(opts) {
270703
270860
  );
270704
270861
  await execSafe("ffmpeg", concatArgs, { timeout: 6e5 });
270705
270862
  const totalDurationSec = await probeDurationSec(join63(projectDir, bgRel));
270706
- await mkdir13(join63(projectDir, "compositions"), { recursive: true });
270863
+ await mkdir14(join63(projectDir, "compositions"), { recursive: true });
270707
270864
  const sceneFiles = [];
270708
270865
  for (let i3 = 0; i3 < beats.length; i3++) {
270709
270866
  const beat = beats[i3];
@@ -270852,7 +271009,7 @@ var init_compose_aivideo = __esm({
270852
271009
 
270853
271010
  // ../cli/src/commands/_shared/footage-assemble.ts
270854
271011
  import { existsSync as existsSync51 } from "node:fs";
270855
- import { mkdir as mkdir14, writeFile as writeFile18 } from "node:fs/promises";
271012
+ import { mkdir as mkdir15, writeFile as writeFile18 } from "node:fs/promises";
270856
271013
  import { dirname as dirname27, isAbsolute as isAbsolute9, join as join64, resolve as resolve35 } from "node:path";
270857
271014
  function planFootageTimeline(inputs, opts = {}) {
270858
271015
  if (inputs.length === 0) {
@@ -271182,7 +271339,7 @@ async function executeFootageAssemble(opts) {
271182
271339
  if (opts.dryRun) {
271183
271340
  return { success: true, dryRun: true, outputPath, report };
271184
271341
  }
271185
- await mkdir14(dirname27(outputPath), { recursive: true });
271342
+ await mkdir15(dirname27(outputPath), { recursive: true });
271186
271343
  const args = buildFootageAssembleArgs({
271187
271344
  sources: sourceRels.map((s2) => ({ path: join64(projectDir, s2.rel), kind: s2.kind })),
271188
271345
  plan: plan2,
@@ -271543,6 +271700,37 @@ var init_composer_resolve = __esm({
271543
271700
  }
271544
271701
  });
271545
271702
 
271703
+ // ../cli/src/commands/_shared/build-video-providers.ts
271704
+ function isBuildVideoProvider(value) {
271705
+ return BUILD_VIDEO_PROVIDERS.includes(value);
271706
+ }
271707
+ function resolveBuildVideoProvider(value) {
271708
+ const provider = String(value ?? "seedance").toLowerCase();
271709
+ if (provider === "fal") return "seedance";
271710
+ return isBuildVideoProvider(provider) ? provider : "seedance";
271711
+ }
271712
+ function videoProviderConfigKey(provider) {
271713
+ switch (provider) {
271714
+ case "seedance":
271715
+ case "fal":
271716
+ return "fal";
271717
+ case "grok":
271718
+ return "xai";
271719
+ case "veo":
271720
+ case "omni":
271721
+ return "google";
271722
+ default:
271723
+ return provider;
271724
+ }
271725
+ }
271726
+ var BUILD_VIDEO_PROVIDERS;
271727
+ var init_build_video_providers = __esm({
271728
+ "../cli/src/commands/_shared/build-video-providers.ts"() {
271729
+ "use strict";
271730
+ BUILD_VIDEO_PROVIDERS = ["seedance", "grok", "kling", "runway", "omni", "veo"];
271731
+ }
271732
+ });
271733
+
271546
271734
  // ../cli/src/commands/_shared/build-plan.ts
271547
271735
  import { existsSync as existsSync54 } from "node:fs";
271548
271736
  import { dirname as dirname28, join as join65, resolve as resolve37 } from "node:path";
@@ -272217,12 +272405,7 @@ function normalizeImageProvider(value) {
272217
272405
  return provider || "openai";
272218
272406
  }
272219
272407
  function normalizeVideoProvider(value) {
272220
- const provider = String(value ?? "seedance").toLowerCase();
272221
- if (provider === "fal") return "seedance";
272222
- if (provider === "seedance" || provider === "grok" || provider === "kling" || provider === "runway" || provider === "veo") {
272223
- return provider;
272224
- }
272225
- return "seedance";
272408
+ return resolveBuildVideoProvider(value);
272226
272409
  }
272227
272410
  function normalizeMusicProvider(value) {
272228
272411
  const provider = String(value ?? "elevenlabs").toLowerCase();
@@ -272234,7 +272417,7 @@ function imageConfigKey(provider) {
272234
272417
  return "openai";
272235
272418
  }
272236
272419
  function videoConfigKey(provider) {
272237
- return provider === "seedance" ? "fal" : provider === "grok" ? "xai" : provider === "veo" ? "google" : provider;
272420
+ return videoProviderConfigKey(provider);
272238
272421
  }
272239
272422
  function composerConfigKey(provider) {
272240
272423
  return provider === "claude" ? "anthropic" : provider === "gemini" ? "google" : "openai";
@@ -272278,6 +272461,7 @@ var init_build_plan = __esm({
272278
272461
  init_project_config();
272279
272462
  init_scene_project();
272280
272463
  init_storyboard_edit();
272464
+ init_build_video_providers();
272281
272465
  VIDEO_COST_USD = 5;
272282
272466
  MUSIC_COST_USD = 0.5;
272283
272467
  ELEVENLABS_NARRATION_COST_USD = 0.05;
@@ -272456,7 +272640,7 @@ function registerMusicCommand(parent) {
272456
272640
  console.log();
272457
272641
  console.log(`Saved to: ${source_default.bold(outputPath)}`);
272458
272642
  console.log(`Duration: ${duration}s`);
272459
- console.log(`Provider: ElevenLabs (music_v1)`);
272643
+ console.log(`Provider: ElevenLabs (${ELEVENLABS_MUSIC_MODEL})`);
272460
272644
  if (options.instrumental) console.log(`Mode: Instrumental`);
272461
272645
  console.log();
272462
272646
  } else {
@@ -272596,6 +272780,48 @@ var init_scene_build_mode = __esm({
272596
272780
  }
272597
272781
  });
272598
272782
 
272783
+ // ../cli/src/utils/image-file.ts
272784
+ import { rm as rm6, writeFile as writeFile20 } from "node:fs/promises";
272785
+ import { extname as extname12 } from "node:path";
272786
+ function detectImageFormat(buffer) {
272787
+ if (buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
272788
+ return "png";
272789
+ }
272790
+ if (buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) return "jpeg";
272791
+ if (buffer.toString("ascii", 0, 4) === "RIFF" && buffer.toString("ascii", 8, 12) === "WEBP") {
272792
+ return "webp";
272793
+ }
272794
+ return void 0;
272795
+ }
272796
+ async function writeImageFile(path16, buffer) {
272797
+ const wanted = EXTENSION_FORMATS[extname12(path16).toLowerCase()];
272798
+ const actual = detectImageFormat(buffer);
272799
+ if (!wanted || !actual || wanted === actual) {
272800
+ await writeFile20(path16, buffer);
272801
+ return;
272802
+ }
272803
+ const source3 = `${path16}.source.${actual === "jpeg" ? "jpg" : actual}`;
272804
+ await writeFile20(source3, buffer);
272805
+ try {
272806
+ await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source3, "-frames:v", "1", path16]);
272807
+ } finally {
272808
+ await rm6(source3, { force: true });
272809
+ }
272810
+ }
272811
+ var EXTENSION_FORMATS;
272812
+ var init_image_file = __esm({
272813
+ "../cli/src/utils/image-file.ts"() {
272814
+ "use strict";
272815
+ init_exec_safe();
272816
+ EXTENSION_FORMATS = {
272817
+ ".png": "png",
272818
+ ".jpg": "jpeg",
272819
+ ".jpeg": "jpeg",
272820
+ ".webp": "webp"
272821
+ };
272822
+ }
272823
+ });
272824
+
272599
272825
  // ../cli/src/commands/_shared/scene-build.ts
272600
272826
  var scene_build_exports = {};
272601
272827
  __export(scene_build_exports, {
@@ -272604,7 +272830,7 @@ __export(scene_build_exports, {
272604
272830
  resolveSceneBuildMode: () => resolveSceneBuildMode
272605
272831
  });
272606
272832
  import { existsSync as existsSync56, readFileSync as readFileSync21 } from "node:fs";
272607
- import { copyFile as copyFile4, mkdir as mkdir15, readFile as readFile19, rm as rm6, writeFile as writeFile20 } from "node:fs/promises";
272833
+ import { copyFile as copyFile4, mkdir as mkdir16, readFile as readFile19, rm as rm7, writeFile as writeFile21 } from "node:fs/promises";
272608
272834
  import { dirname as dirname29, join as join66, resolve as resolve40 } from "node:path";
272609
272835
  function readProjectKindSync(projectDir) {
272610
272836
  try {
@@ -273458,7 +273684,7 @@ async function dispatchNarration(beat, ctx) {
273458
273684
  };
273459
273685
  }
273460
273686
  if (existsSync56(cacheAbs) && !ctx.force) {
273461
- await mkdir15(dirname29(abs), { recursive: true });
273687
+ await mkdir16(dirname29(abs), { recursive: true });
273462
273688
  await copyFile4(cacheAbs, abs);
273463
273689
  await writeAssetMetadata({
273464
273690
  projectDir: ctx.projectDir,
@@ -273489,14 +273715,14 @@ async function dispatchNarration(beat, ctx) {
273489
273715
  ctx.onProgress({ type: "narration-failed", beatId: beat.id, error });
273490
273716
  return { status: "failed", error };
273491
273717
  }
273492
- await mkdir15(dirname29(abs), { recursive: true });
273493
- await writeFile20(abs, result.audioBuffer);
273718
+ await mkdir16(dirname29(abs), { recursive: true });
273719
+ await writeFile21(abs, result.audioBuffer);
273494
273720
  for (const otherExt of ["mp3", "wav"]) {
273495
273721
  const sibling = join66(ctx.projectDir, `assets/narration-${beat.id}.${otherExt}`);
273496
- if (sibling !== abs && existsSync56(sibling)) await rm6(sibling, { force: true });
273722
+ if (sibling !== abs && existsSync56(sibling)) await rm7(sibling, { force: true });
273497
273723
  }
273498
- await mkdir15(dirname29(cacheAbs), { recursive: true });
273499
- await writeFile20(cacheAbs, result.audioBuffer);
273724
+ await mkdir16(dirname29(cacheAbs), { recursive: true });
273725
+ await writeFile21(cacheAbs, result.audioBuffer);
273500
273726
  await writeAssetMetadata({
273501
273727
  projectDir: ctx.projectDir,
273502
273728
  kind: "narration",
@@ -273552,8 +273778,8 @@ async function dispatchTranscript(beat, narrationPath, narrationFresh, ctx) {
273552
273778
  return "skipped";
273553
273779
  }
273554
273780
  try {
273555
- await mkdir15(dirname29(abs), { recursive: true });
273556
- await writeFile20(abs, JSON.stringify(words, null, 2), "utf-8");
273781
+ await mkdir16(dirname29(abs), { recursive: true });
273782
+ await writeFile21(abs, JSON.stringify(words, null, 2), "utf-8");
273557
273783
  } catch (err) {
273558
273784
  ctx.onProgress({
273559
273785
  type: "transcript-skipped",
@@ -273641,7 +273867,7 @@ async function buildCharacters(characters, ctx) {
273641
273867
  }
273642
273868
  const cacheAbs = join66(ctx.projectDir, cache.path);
273643
273869
  if (existsSync56(cacheAbs) && !ctx.force) {
273644
- await mkdir15(dirname29(abs), { recursive: true });
273870
+ await mkdir16(dirname29(abs), { recursive: true });
273645
273871
  await copyFile4(cacheAbs, abs);
273646
273872
  await writeAssetMetadata({
273647
273873
  projectDir: ctx.projectDir,
@@ -273674,10 +273900,10 @@ async function buildCharacters(characters, ctx) {
273674
273900
  ctx.onProgress({ type: "character-failed", name: character.name, error: generated.error });
273675
273901
  continue;
273676
273902
  }
273677
- await mkdir15(dirname29(abs), { recursive: true });
273678
- await writeFile20(abs, generated.buffer);
273679
- await mkdir15(dirname29(cacheAbs), { recursive: true });
273680
- await writeFile20(cacheAbs, generated.buffer);
273903
+ await mkdir16(dirname29(abs), { recursive: true });
273904
+ await writeImageFile(abs, generated.buffer);
273905
+ await mkdir16(dirname29(cacheAbs), { recursive: true });
273906
+ await writeImageFile(cacheAbs, generated.buffer);
273681
273907
  await writeAssetMetadata({
273682
273908
  projectDir: ctx.projectDir,
273683
273909
  kind: "character",
@@ -273746,7 +273972,7 @@ async function dispatchBackdrop(beat, ctx) {
273746
273972
  }
273747
273973
  const cacheAbs = join66(ctx.projectDir, cache.path);
273748
273974
  if (existsSync56(cacheAbs) && !ctx.force) {
273749
- await mkdir15(dirname29(abs), { recursive: true });
273975
+ await mkdir16(dirname29(abs), { recursive: true });
273750
273976
  await copyFile4(cacheAbs, abs);
273751
273977
  await writeAssetMetadata({
273752
273978
  projectDir: ctx.projectDir,
@@ -273776,11 +274002,11 @@ async function dispatchBackdrop(beat, ctx) {
273776
274002
  ctx.onProgress({ type: "backdrop-failed", beatId: beat.id, error });
273777
274003
  return { status: "failed", error };
273778
274004
  }
273779
- await mkdir15(dirname29(abs), { recursive: true });
274005
+ await mkdir16(dirname29(abs), { recursive: true });
273780
274006
  const buffer = generated.buffer;
273781
- await writeFile20(abs, buffer);
273782
- await mkdir15(dirname29(cacheAbs), { recursive: true });
273783
- await writeFile20(cacheAbs, buffer);
274007
+ await writeImageFile(abs, buffer);
274008
+ await mkdir16(dirname29(cacheAbs), { recursive: true });
274009
+ await writeImageFile(cacheAbs, buffer);
273784
274010
  await writeAssetMetadata({
273785
274011
  projectDir: ctx.projectDir,
273786
274012
  kind: "backdrop",
@@ -273824,7 +274050,7 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
273824
274050
  const result2 = await provider2.generateImage(prompt3, {
273825
274051
  // CLI input is free-form; an alias the provider doesn't know fails the
273826
274052
  // API call and surfaces as a beat-scoped backdrop/keyframe error.
273827
- model: ctx.imageModel ?? "gpt-image-2",
274053
+ model: ctx.imageModel ?? OPENAI_IMAGE_DEFAULT_MODEL,
273828
274054
  size: ctx.imageSize,
273829
274055
  quality: ctx.imageQuality
273830
274056
  });
@@ -273909,7 +274135,7 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
273909
274135
  }
273910
274136
  const cacheAbs = join66(ctx.projectDir, cache.path);
273911
274137
  if (existsSync56(cacheAbs) && !ctx.force) {
273912
- await mkdir15(dirname29(abs), { recursive: true });
274138
+ await mkdir16(dirname29(abs), { recursive: true });
273913
274139
  await copyFile4(cacheAbs, abs);
273914
274140
  await writeAssetMetadata({
273915
274141
  projectDir: ctx.projectDir,
@@ -273939,10 +274165,10 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
273939
274165
  const identityLock = "Keep the EXACT same person and face as the reference image(s): identical facial features (eyes, nose shape, jawline), skin tone and complexion, hairstyle, hair color, and wardrobe. Do not restyle or change the face. Change only the scene, pose, framing, and lighting. ";
273940
274166
  const generated = sheetBuffers.length > 0 ? await editKeyframeImage(`${identityLock}${keyframeCue}`, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
273941
274167
  if (!generated.success) return { status: "failed", error: generated.error };
273942
- await mkdir15(dirname29(abs), { recursive: true });
273943
- await writeFile20(abs, generated.buffer);
273944
- await mkdir15(dirname29(cacheAbs), { recursive: true });
273945
- await writeFile20(cacheAbs, generated.buffer);
274168
+ await mkdir16(dirname29(abs), { recursive: true });
274169
+ await writeImageFile(abs, generated.buffer);
274170
+ await mkdir16(dirname29(cacheAbs), { recursive: true });
274171
+ await writeImageFile(cacheAbs, generated.buffer);
273946
274172
  await writeAssetMetadata({
273947
274173
  projectDir: ctx.projectDir,
273948
274174
  kind: "keyframe",
@@ -274038,7 +274264,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
274038
274264
  }
274039
274265
  const cacheAbs = join66(ctx.projectDir, cache.path);
274040
274266
  if (existsSync56(cacheAbs) && !ctx.force) {
274041
- await mkdir15(dirname29(abs), { recursive: true });
274267
+ await mkdir16(dirname29(abs), { recursive: true });
274042
274268
  await copyFile4(cacheAbs, abs);
274043
274269
  await writeAssetMetadata({
274044
274270
  projectDir: ctx.projectDir,
@@ -274115,7 +274341,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
274115
274341
  }
274116
274342
  }
274117
274343
  if (result.status === "completed" && existsSync56(abs)) {
274118
- await mkdir15(dirname29(cacheAbs), { recursive: true });
274344
+ await mkdir16(dirname29(cacheAbs), { recursive: true });
274119
274345
  await copyFile4(abs, cacheAbs);
274120
274346
  await writeAssetMetadata({
274121
274347
  projectDir: ctx.projectDir,
@@ -274217,7 +274443,7 @@ async function dispatchMusic(beat, ctx) {
274217
274443
  }
274218
274444
  const cacheAbs = join66(ctx.projectDir, cache.path);
274219
274445
  if (existsSync56(cacheAbs) && !ctx.force) {
274220
- await mkdir15(dirname29(abs), { recursive: true });
274446
+ await mkdir16(dirname29(abs), { recursive: true });
274221
274447
  await copyFile4(cacheAbs, abs);
274222
274448
  await writeAssetMetadata({
274223
274449
  projectDir: ctx.projectDir,
@@ -274295,7 +274521,7 @@ async function dispatchMusic(beat, ctx) {
274295
274521
  ctx.onProgress({ type: "music-failed", beatId: beat.id, error });
274296
274522
  return { status: "failed", error };
274297
274523
  }
274298
- await mkdir15(dirname29(cacheAbs), { recursive: true });
274524
+ await mkdir16(dirname29(cacheAbs), { recursive: true });
274299
274525
  await copyFile4(abs, cacheAbs);
274300
274526
  await writeAssetMetadata({
274301
274527
  projectDir: ctx.projectDir,
@@ -274559,14 +274785,6 @@ async function safeAudioDuration(absPath) {
274559
274785
  return void 0;
274560
274786
  }
274561
274787
  }
274562
- function resolveBuildVideoProvider(value) {
274563
- const provider = String(value ?? "seedance").toLowerCase();
274564
- if (provider === "fal") return "seedance";
274565
- if (provider === "seedance" || provider === "grok" || provider === "kling" || provider === "runway" || provider === "veo") {
274566
- return provider;
274567
- }
274568
- return "seedance";
274569
- }
274570
274788
  function resolveBuildMusicProvider(value) {
274571
274789
  const provider = String(value ?? "elevenlabs").toLowerCase();
274572
274790
  return provider === "replicate" ? "replicate" : "elevenlabs";
@@ -274578,8 +274796,7 @@ function stringOrUndefined4(value) {
274578
274796
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
274579
274797
  }
274580
274798
  async function apiKeyForVideoProvider(provider, projectDir) {
274581
- const providerKey = provider === "seedance" ? "fal" : provider === "grok" ? "xai" : provider === "veo" ? "google" : provider;
274582
- return getApiKeyFromConfig(providerKey, { cwd: projectDir });
274799
+ return getApiKeyFromConfig(videoProviderConfigKey(provider), { cwd: projectDir });
274583
274800
  }
274584
274801
  async function finalizeBuildResult(projectDir, startedAt, result, reportResult = result) {
274585
274802
  const reportPath = join66(projectDir, "build-report.json");
@@ -274602,7 +274819,7 @@ async function finalizeBuildResult(projectDir, startedAt, result, reportResult =
274602
274819
  const withMeta = decorate(result);
274603
274820
  const reportMeta = reportResult === result ? withMeta : decorate(reportResult);
274604
274821
  try {
274605
- await writeFile20(
274822
+ await writeFile21(
274606
274823
  reportPath,
274607
274824
  JSON.stringify(toBuildReport(projectDir, reportMeta), null, 2) + "\n",
274608
274825
  "utf-8"
@@ -274855,6 +275072,8 @@ var init_scene_build = __esm({
274855
275072
  init_scene_repair();
274856
275073
  init_tts_resolve();
274857
275074
  init_scene_build_mode();
275075
+ init_image_file();
275076
+ init_build_video_providers();
274858
275077
  init_scene_build_mode();
274859
275078
  BEAT_PRIMITIVES_CONCURRENCY = 4;
274860
275079
  }
@@ -274967,8 +275186,8 @@ __export(ai_audio_exports, {
274967
275186
  executeTranscribe: () => executeTranscribe,
274968
275187
  executeVoiceClone: () => executeVoiceClone
274969
275188
  });
274970
- import { resolve as resolve43, dirname as dirname30, basename as basename9, extname as extname12 } from "node:path";
274971
- import { readFile as readFile20, writeFile as writeFile21 } from "node:fs/promises";
275189
+ import { resolve as resolve43, dirname as dirname30, basename as basename9, extname as extname13 } from "node:path";
275190
+ import { readFile as readFile20, writeFile as writeFile23 } from "node:fs/promises";
274972
275191
  import { existsSync as existsSync57 } from "node:fs";
274973
275192
  async function executeTranscribe(options) {
274974
275193
  const { audioPath, language, output: output3, format: format4, apiKey } = options;
@@ -274990,7 +275209,7 @@ async function executeTranscribe(options) {
274990
275209
  outputPath = resolve43(process.cwd(), output3);
274991
275210
  const fmt = detectFormat(output3, format4);
274992
275211
  const content = formatTranscript(result, fmt);
274993
- await writeFile21(outputPath, content, "utf-8");
275212
+ await writeFile23(outputPath, content, "utf-8");
274994
275213
  }
274995
275214
  return {
274996
275215
  success: true,
@@ -275018,7 +275237,7 @@ async function executeIsolate(options) {
275018
275237
  return { success: false, error: result.error || "Audio isolation failed" };
275019
275238
  }
275020
275239
  const outputPath = resolve43(process.cwd(), output3);
275021
- await writeFile21(outputPath, result.audioBuffer);
275240
+ await writeFile23(outputPath, result.audioBuffer);
275022
275241
  return { success: true, outputPath };
275023
275242
  } catch (error) {
275024
275243
  return { success: false, error: `Audio isolation failed: ${error instanceof Error ? error.message : String(error)}` };
@@ -275064,7 +275283,7 @@ async function executeDub(options) {
275064
275283
  if (!openaiKey) return { success: false, error: "OPENAI_API_KEY required for Whisper transcription" };
275065
275284
  if (!anthropicKey) return { success: false, error: "ANTHROPIC_API_KEY required for Claude translation" };
275066
275285
  if (!analyzeOnly && !elevenlabsKey) return { success: false, error: "ELEVENLABS_API_KEY required for TTS" };
275067
- const ext = extname12(absPath).toLowerCase();
275286
+ const ext = extname13(absPath).toLowerCase();
275068
275287
  const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
275069
275288
  let audioPath = absPath;
275070
275289
  if (isVideo) {
@@ -275129,7 +275348,7 @@ ${segmentTexts}`,
275129
275348
  translated: translatedSegments[i3]?.text || s2.text
275130
275349
  }))
275131
275350
  };
275132
- await writeFile21(timingPath, JSON.stringify(timingData, null, 2));
275351
+ await writeFile23(timingPath, JSON.stringify(timingData, null, 2));
275133
275352
  }
275134
275353
  return {
275135
275354
  success: true,
@@ -275149,10 +275368,10 @@ ${segmentTexts}`,
275149
275368
  }
275150
275369
  }
275151
275370
  const combinedBuffer = Buffer.concat(dubbedBuffers);
275152
- const outputExt = isVideo ? ".mp3" : extname12(absPath);
275153
- const defaultOutputPath2 = resolve43(dirname30(absPath), `${basename9(absPath, extname12(absPath))}-${language}${outputExt}`);
275371
+ const outputExt = isVideo ? ".mp3" : extname13(absPath);
275372
+ const defaultOutputPath2 = resolve43(dirname30(absPath), `${basename9(absPath, extname13(absPath))}-${language}${outputExt}`);
275154
275373
  const finalOutputPath = resolve43(process.cwd(), output3 || defaultOutputPath2);
275155
- await writeFile21(finalOutputPath, combinedBuffer);
275374
+ await writeFile23(finalOutputPath, combinedBuffer);
275156
275375
  if (isVideo && audioPath !== absPath) {
275157
275376
  try {
275158
275377
  const { unlink: unlink6 } = await import("node:fs/promises");
@@ -275187,7 +275406,7 @@ async function executeDuck(options) {
275187
275406
  const absVoicePath = resolve43(process.cwd(), voicePath);
275188
275407
  if (!existsSync57(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
275189
275408
  if (!existsSync57(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
275190
- const defaultOutput = resolve43(dirname30(absMusicPath), `${basename9(absMusicPath, extname12(absMusicPath))}-ducked${extname12(absMusicPath)}`);
275409
+ const defaultOutput = resolve43(dirname30(absMusicPath), `${basename9(absMusicPath, extname13(absMusicPath))}-ducked${extname13(absMusicPath)}`);
275191
275410
  const outputPath = resolve43(process.cwd(), output3 || defaultOutput);
275192
275411
  const filter3 = `[1:a]asplit=2[sc][mix];[0:a][sc]sidechaincompress=threshold=${threshold}dB:ratio=${ratio}:attack=${attack}:release=${release}[ducked];[ducked][mix]amix=inputs=2:duration=longest`;
275193
275412
  await execSafe("ffmpeg", [
@@ -275452,7 +275671,7 @@ var init_silence_cut = __esm({
275452
275671
 
275453
275672
  // ../cli/src/commands/_shared/edit/jump-cut.ts
275454
275673
  import { existsSync as existsSync59 } from "node:fs";
275455
- import { readFile as readFile23, writeFile as writeFile23, mkdir as mkdir16 } from "node:fs/promises";
275674
+ import { readFile as readFile23, writeFile as writeFile24, mkdir as mkdir17 } from "node:fs/promises";
275456
275675
  import { join as join67 } from "node:path";
275457
275676
  async function transcribeWithWords(audioPath, apiKey, language) {
275458
275677
  const audioBuffer = await readFile23(audioPath);
@@ -275532,7 +275751,7 @@ async function executeJumpCut(options) {
275532
275751
  }
275533
275752
  try {
275534
275753
  const tmpDir = `/tmp/vibe_jumpcut_${Date.now()}`;
275535
- await mkdir16(tmpDir, { recursive: true });
275754
+ await mkdir17(tmpDir, { recursive: true });
275536
275755
  const audioPath = join67(tmpDir, "audio.wav");
275537
275756
  try {
275538
275757
  await execSafe(
@@ -275611,7 +275830,7 @@ async function executeJumpCut(options) {
275611
275830
  }
275612
275831
  const concatList = segmentPaths.map((p2) => `file '${p2}'`).join("\n");
275613
275832
  const listPath = join67(tmpDir, "concat.txt");
275614
- await writeFile23(listPath, concatList);
275833
+ await writeFile24(listPath, concatList);
275615
275834
  await execSafe(
275616
275835
  "ffmpeg",
275617
275836
  [
@@ -275638,8 +275857,8 @@ async function executeJumpCut(options) {
275638
275857
  };
275639
275858
  } finally {
275640
275859
  try {
275641
- const { rm: rm10 } = await import("node:fs/promises");
275642
- await rm10(tmpDir, { recursive: true, force: true });
275860
+ const { rm: rm11 } = await import("node:fs/promises");
275861
+ await rm11(tmpDir, { recursive: true, force: true });
275643
275862
  } catch {
275644
275863
  }
275645
275864
  }
@@ -275716,7 +275935,7 @@ __export(remotion_exports, {
275716
275935
  wrapComponentWithImage: () => wrapComponentWithImage,
275717
275936
  wrapComponentWithVideo: () => wrapComponentWithVideo
275718
275937
  });
275719
- import { writeFile as writeFile24, mkdir as mkdir17, rm as rm7, copyFile as copyFile5 } from "node:fs/promises";
275938
+ import { writeFile as writeFile25, mkdir as mkdir18, rm as rm8, copyFile as copyFile5 } from "node:fs/promises";
275720
275939
  import { existsSync as existsSync60 } from "node:fs";
275721
275940
  import { join as join68 } from "node:path";
275722
275941
  import { tmpdir as tmpdir9 } from "node:os";
@@ -275738,7 +275957,7 @@ async function ensureRemotionInstalled() {
275738
275957
  }
275739
275958
  async function scaffoldRemotionProject(componentCode, componentName, opts) {
275740
275959
  const dir = join68(tmpdir9(), `vibe_motion_${Date.now()}`);
275741
- await mkdir17(dir, { recursive: true });
275960
+ await mkdir18(dir, { recursive: true });
275742
275961
  const deps = {
275743
275962
  remotion: REMOTION_VERSION,
275744
275963
  "@remotion/cli": REMOTION_VERSION,
@@ -275756,7 +275975,7 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
275756
275975
  dependencies: deps
275757
275976
  };
275758
275977
  const packageJsonStr = JSON.stringify(packageJson, null, 2);
275759
- await writeFile24(join68(dir, "package.json"), packageJsonStr);
275978
+ await writeFile25(join68(dir, "package.json"), packageJsonStr);
275760
275979
  const tsconfig = {
275761
275980
  compilerOptions: {
275762
275981
  target: "ES2020",
@@ -275768,8 +275987,8 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
275768
275987
  skipLibCheck: true
275769
275988
  }
275770
275989
  };
275771
- await writeFile24(join68(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
275772
- await writeFile24(join68(dir, "Component.tsx"), componentCode);
275990
+ await writeFile25(join68(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
275991
+ await writeFile25(join68(dir, "Component.tsx"), componentCode);
275773
275992
  const rootCode = `import { registerRoot, Composition } from "remotion";
275774
275993
  import { ${componentName} } from "./Component";
275775
275994
 
@@ -275788,7 +276007,7 @@ const Root = () => {
275788
276007
 
275789
276008
  registerRoot(Root);
275790
276009
  `;
275791
- await writeFile24(join68(dir, "Root.tsx"), rootCode);
276010
+ await writeFile25(join68(dir, "Root.tsx"), rootCode);
275792
276011
  const depsHash = createHash11("md5").update(packageJsonStr).digest("hex").slice(0, 12);
275793
276012
  const cacheMarker = join68(REMOTION_CACHE_DIR, `.deps-${depsHash}`);
275794
276013
  const cachedModules = join68(REMOTION_CACHE_DIR, "node_modules");
@@ -275802,15 +276021,15 @@ registerRoot(Root);
275802
276021
  } else {
275803
276022
  await this_npmInstall(dir);
275804
276023
  try {
275805
- await mkdir17(REMOTION_CACHE_DIR, { recursive: true });
275806
- await writeFile24(join68(REMOTION_CACHE_DIR, "package.json"), packageJsonStr);
276024
+ await mkdir18(REMOTION_CACHE_DIR, { recursive: true });
276025
+ await writeFile25(join68(REMOTION_CACHE_DIR, "package.json"), packageJsonStr);
275807
276026
  if (existsSync60(join68(dir, "node_modules"))) {
275808
276027
  const { rename: rename7, symlink: symlink4 } = await import("node:fs/promises");
275809
276028
  await rename7(join68(dir, "node_modules"), cachedModules).catch(() => {
275810
276029
  });
275811
276030
  await symlink4(cachedModules, join68(dir, "node_modules"), "dir").catch(() => {
275812
276031
  });
275813
- await writeFile24(cacheMarker, depsHash);
276032
+ await writeFile25(cacheMarker, depsHash);
275814
276033
  }
275815
276034
  } catch {
275816
276035
  }
@@ -275910,7 +276129,7 @@ async function renderMotion(options) {
275910
276129
  stderr: ${stderr}` : ""}`);
275911
276130
  return { success: false, error: `Remotion render failed: ${msg}` };
275912
276131
  } finally {
275913
- await rm7(dir, { recursive: true, force: true }).catch(() => {
276132
+ await rm8(dir, { recursive: true, force: true }).catch(() => {
275914
276133
  });
275915
276134
  }
275916
276135
  }
@@ -275979,7 +276198,7 @@ async function renderWithEmbeddedImage(options) {
275979
276198
  );
275980
276199
  try {
275981
276200
  const publicDir = join68(dir, "public");
275982
- await mkdir17(publicDir, { recursive: true });
276201
+ await mkdir18(publicDir, { recursive: true });
275983
276202
  await copyFile5(options.imagePath, join68(publicDir, options.imageFileName));
275984
276203
  const entryPoint = join68(dir, "Root.tsx");
275985
276204
  const mp4Out = options.outputPath.replace(/\.\w+$/, ".mp4");
@@ -276002,7 +276221,7 @@ async function renderWithEmbeddedImage(options) {
276002
276221
  const msg = error instanceof Error ? error.message : String(error);
276003
276222
  return { success: false, error: `Remotion image embed render failed: ${msg}` };
276004
276223
  } finally {
276005
- await rm7(dir, { recursive: true, force: true }).catch(() => {
276224
+ await rm8(dir, { recursive: true, force: true }).catch(() => {
276006
276225
  });
276007
276226
  }
276008
276227
  }
@@ -276043,7 +276262,7 @@ async function renderWithEmbeddedVideo(options) {
276043
276262
  );
276044
276263
  try {
276045
276264
  const publicDir = join68(dir, "public");
276046
- await mkdir17(publicDir, { recursive: true });
276265
+ await mkdir18(publicDir, { recursive: true });
276047
276266
  await copyFile5(options.videoPath, join68(publicDir, options.videoFileName));
276048
276267
  const entryPoint = join68(dir, "Root.tsx");
276049
276268
  const mp4VideoOnly = options.outputPath.replace(/\.\w+$/, "_video_only.mp4");
@@ -276079,14 +276298,14 @@ async function renderWithEmbeddedVideo(options) {
276079
276298
  "-shortest",
276080
276299
  mp4Out
276081
276300
  ], { timeout: 12e4 });
276082
- await rm7(mp4VideoOnly, { force: true }).catch(() => {
276301
+ await rm8(mp4VideoOnly, { force: true }).catch(() => {
276083
276302
  });
276084
276303
  return { success: true, outputPath: mp4Out };
276085
276304
  } catch (error) {
276086
276305
  const msg = error instanceof Error ? error.message : String(error);
276087
276306
  return { success: false, error: `Remotion video embed render failed: ${msg}` };
276088
276307
  } finally {
276089
- await rm7(dir, { recursive: true, force: true }).catch(() => {
276308
+ await rm8(dir, { recursive: true, force: true }).catch(() => {
276090
276309
  });
276091
276310
  }
276092
276311
  }
@@ -276467,8 +276686,8 @@ var init_remotion = __esm({
276467
276686
 
276468
276687
  // ../cli/src/commands/_shared/edit/caption.ts
276469
276688
  import { existsSync as existsSync61 } from "node:fs";
276470
- import { readFile as readFile24, writeFile as writeFile25, mkdir as mkdir18 } from "node:fs/promises";
276471
- import { dirname as dirname31, basename as basename10, extname as extname13, join as join69 } from "node:path";
276689
+ import { readFile as readFile24, writeFile as writeFile26, mkdir as mkdir19 } from "node:fs/promises";
276690
+ import { dirname as dirname31, basename as basename10, extname as extname14, join as join69 } from "node:path";
276472
276691
  function getCaptionForceStyle(style, fontSize, fontColor, position) {
276473
276692
  const alignment = position === "top" ? 8 : position === "center" ? 5 : 2;
276474
276693
  const marginV = position === "center" ? 0 : 30;
@@ -276514,7 +276733,7 @@ async function executeCaption(options) {
276514
276733
  }
276515
276734
  try {
276516
276735
  const tmpDir = `/tmp/vibe_caption_${Date.now()}`;
276517
- await mkdir18(tmpDir, { recursive: true });
276736
+ await mkdir19(tmpDir, { recursive: true });
276518
276737
  const audioPath = join69(tmpDir, "audio.wav");
276519
276738
  const srtPath = join69(tmpDir, "captions.srt");
276520
276739
  try {
@@ -276547,7 +276766,7 @@ async function executeCaption(options) {
276547
276766
  };
276548
276767
  }
276549
276768
  const srtContent = formatSRT(transcriptResult.segments);
276550
- await writeFile25(srtPath, srtContent);
276769
+ await writeFile26(srtPath, srtContent);
276551
276770
  const { width, height } = await getVideoResolution(videoPath);
276552
276771
  const fontSize = customFontSize || Math.round(height / 18);
276553
276772
  let hasSubtitles = false;
@@ -276587,9 +276806,9 @@ async function executeCaption(options) {
276587
276806
  const outputDir2 = dirname31(outputPath);
276588
276807
  const outputSrtPath2 = join69(
276589
276808
  outputDir2,
276590
- basename10(outputPath, extname13(outputPath)) + ".srt"
276809
+ basename10(outputPath, extname14(outputPath)) + ".srt"
276591
276810
  );
276592
- await writeFile25(outputSrtPath2, srtContent);
276811
+ await writeFile26(outputSrtPath2, srtContent);
276593
276812
  return { success: false, error: `${remotionErr}
276594
276813
  SRT saved to: ${outputSrtPath2}` };
276595
276814
  }
@@ -276626,9 +276845,9 @@ SRT saved to: ${outputSrtPath2}` };
276626
276845
  const outputDir2 = dirname31(outputPath);
276627
276846
  const outputSrtPath2 = join69(
276628
276847
  outputDir2,
276629
- basename10(outputPath, extname13(outputPath)) + ".srt"
276848
+ basename10(outputPath, extname14(outputPath)) + ".srt"
276630
276849
  );
276631
- await writeFile25(outputSrtPath2, srtContent);
276850
+ await writeFile26(outputSrtPath2, srtContent);
276632
276851
  return {
276633
276852
  success: false,
276634
276853
  error: `${renderResult.error}
@@ -276639,9 +276858,9 @@ SRT saved to: ${outputSrtPath2}`
276639
276858
  const outputDir = dirname31(outputPath);
276640
276859
  const outputSrtPath = join69(
276641
276860
  outputDir,
276642
- basename10(outputPath, extname13(outputPath)) + ".srt"
276861
+ basename10(outputPath, extname14(outputPath)) + ".srt"
276643
276862
  );
276644
- await writeFile25(outputSrtPath, srtContent);
276863
+ await writeFile26(outputSrtPath, srtContent);
276645
276864
  return {
276646
276865
  success: true,
276647
276866
  outputPath,
@@ -276650,8 +276869,8 @@ SRT saved to: ${outputSrtPath2}`
276650
276869
  };
276651
276870
  } finally {
276652
276871
  try {
276653
- const { rm: rm10 } = await import("node:fs/promises");
276654
- await rm10(tmpDir, { recursive: true, force: true });
276872
+ const { rm: rm11 } = await import("node:fs/promises");
276873
+ await rm11(tmpDir, { recursive: true, force: true });
276655
276874
  } catch {
276656
276875
  }
276657
276876
  }
@@ -276812,7 +277031,7 @@ var init_fade = __esm({
276812
277031
 
276813
277032
  // ../cli/src/commands/_shared/edit/translate-srt.ts
276814
277033
  import { existsSync as existsSync65 } from "node:fs";
276815
- import { readFile as readFile25, writeFile as writeFile26 } from "node:fs/promises";
277034
+ import { readFile as readFile25, writeFile as writeFile27 } from "node:fs/promises";
276816
277035
  async function executeTranslateSrt(options) {
276817
277036
  const {
276818
277037
  srtPath,
@@ -276855,15 +277074,14 @@ ${textsToTranslate}`;
276855
277074
  Authorization: `Bearer ${openaiKey}`
276856
277075
  },
276857
277076
  body: JSON.stringify({
276858
- model: "gpt-5-mini",
276859
- messages: [{ role: "user", content: translatePrompt }],
276860
- temperature: 0.3
277077
+ model: "gpt-5.4-mini",
277078
+ messages: [{ role: "user", content: translatePrompt }]
276861
277079
  })
276862
277080
  });
276863
277081
  if (!response.ok) {
276864
277082
  return {
276865
277083
  success: false,
276866
- error: `OpenAI API error: ${response.status} ${response.statusText}`
277084
+ error: `OpenAI API error: ${response.status} ${response.statusText}: ${await response.text()}`
276867
277085
  };
276868
277086
  }
276869
277087
  const data2 = await response.json();
@@ -276884,15 +277102,15 @@ ${textsToTranslate}`;
276884
277102
  "anthropic-version": "2023-06-01"
276885
277103
  },
276886
277104
  body: JSON.stringify({
276887
- model: "claude-sonnet-4-6-20250514",
276888
- max_tokens: 4096,
277105
+ model: "claude-sonnet-5-5",
277106
+ max_tokens: 16e3,
276889
277107
  messages: [{ role: "user", content: translatePrompt }]
276890
277108
  })
276891
277109
  });
276892
277110
  if (!response.ok) {
276893
277111
  return {
276894
277112
  success: false,
276895
- error: `Claude API error: ${response.status} ${response.statusText}`
277113
+ error: `Claude API error: ${response.status} ${response.statusText}: ${await response.text()}`
276896
277114
  };
276897
277115
  }
276898
277116
  const data2 = await response.json();
@@ -276916,7 +277134,7 @@ ${textsToTranslate}`;
276916
277134
  }
276917
277135
  }
276918
277136
  const translatedSrt = formatSRT(translatedSegments);
276919
- await writeFile26(outputPath, translatedSrt);
277137
+ await writeFile27(outputPath, translatedSrt);
276920
277138
  return {
276921
277139
  success: true,
276922
277140
  outputPath,
@@ -277168,7 +277386,7 @@ var init_ai_edit = __esm({
277168
277386
  });
277169
277387
 
277170
277388
  // ../cli/src/commands/ai-edit-cli.ts
277171
- import { resolve as resolve45, extname as extname14, basename as basename11 } from "node:path";
277389
+ import { resolve as resolve45, extname as extname15, basename as basename11 } from "node:path";
277172
277390
  import { existsSync as existsSync67 } from "node:fs";
277173
277391
  function registerEditCommands(aiCommand) {
277174
277392
  aiCommand.command("silence-cut").alias("sc").description("Remove silent segments from video (FFmpeg default, or Gemini for smart detection)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-cut.<ext>)").option("--noise <dB>", "Silence threshold in dB (default: -30)", "-30").option("-d, --min-duration <seconds>", "Minimum silence duration to cut (default: 0.5)", "0.5").option("--padding <seconds>", "Padding around non-silent segments (default: 0.1)", "0.1").option("--analyze-only", "(deprecated - use `vibe detect silence`) Only detect silence, don't cut").option("--use-gemini", "Use Gemini Video Understanding for context-aware silence detection").option("-m, --model <model>", "Gemini model (default: flash)").option("--low-res", "Low resolution mode for longer videos (Gemini only)").option("-k, --api-key <key>", "Google API key override (or set GOOGLE_API_KEY env)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
@@ -277192,7 +277410,7 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
277192
277410
  if (!commandExists("ffmpeg")) {
277193
277411
  exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
277194
277412
  }
277195
- const ext = extname14(videoPath);
277413
+ const ext = extname15(videoPath);
277196
277414
  const name = basename11(videoPath, ext);
277197
277415
  const outputPath = options.output || `${name}-cut${ext}`;
277198
277416
  const useGemini = options.useGemini || false;
@@ -277322,7 +277540,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
277322
277540
  if (!apiKey) {
277323
277541
  exitWithError(authError("OPENAI_API_KEY", "OpenAI"));
277324
277542
  }
277325
- const ext = extname14(videoPath);
277543
+ const ext = extname15(videoPath);
277326
277544
  const name = basename11(videoPath, ext);
277327
277545
  const outputPath = options.output || `${name}-captioned${ext}`;
277328
277546
  const spinner2 = ora("Starting caption process...").start();
@@ -277396,7 +277614,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
277396
277614
  });
277397
277615
  return;
277398
277616
  }
277399
- const ext = extname14(inputPath);
277617
+ const ext = extname15(inputPath);
277400
277618
  const name = basename11(inputPath, ext);
277401
277619
  const outputPath = options.output || `${name}-denoised${ext}`;
277402
277620
  const spinner2 = ora("Applying noise reduction...").start();
@@ -277464,7 +277682,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
277464
277682
  });
277465
277683
  return;
277466
277684
  }
277467
- const ext = extname14(videoPath);
277685
+ const ext = extname15(videoPath);
277468
277686
  const name = basename11(videoPath, ext);
277469
277687
  const outputPath = options.output || `${name}-faded${ext}`;
277470
277688
  const spinner2 = ora("Applying fade effects...").start();
@@ -277542,7 +277760,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
277542
277760
  if (!apiKey) {
277543
277761
  exitWithError(authError(envKey, providerName));
277544
277762
  }
277545
- const ext = extname14(srtPath);
277763
+ const ext = extname15(srtPath);
277546
277764
  const name = basename11(srtPath, ext);
277547
277765
  const outputPath = options.output || `${name}-${options.target}${ext}`;
277548
277766
  const spinner2 = ora(`Translating to ${options.target}...`).start();
@@ -277620,7 +277838,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
277620
277838
  if (!apiKey) {
277621
277839
  exitWithError(authError("OPENAI_API_KEY", "OpenAI"));
277622
277840
  }
277623
- const ext = extname14(videoPath);
277841
+ const ext = extname15(videoPath);
277624
277842
  const name = basename11(videoPath, ext);
277625
277843
  const outputPath = options.output || `${name}-jumpcut${ext}`;
277626
277844
  const fillers = options.fillers ? options.fillers.split(",").map((f2) => f2.trim()) : void 0;
@@ -278080,7 +278298,7 @@ var init_project_resolver = __esm({
278080
278298
 
278081
278299
  // ../cli/src/commands/_shared/execute-fill-gaps.ts
278082
278300
  import { existsSync as existsSync68 } from "node:fs";
278083
- import { readFile as readFile26, writeFile as writeFile27, mkdir as mkdir19, rename as renameFs } from "node:fs/promises";
278301
+ import { readFile as readFile26, writeFile as writeFile28, mkdir as mkdir20, rename as renameFs } from "node:fs/promises";
278084
278302
  import { resolve as resolve47, dirname as dirname32 } from "node:path";
278085
278303
  function detectVideoGaps(videoClips, totalDuration) {
278086
278304
  const gaps = [];
@@ -278291,14 +278509,14 @@ async function executeFillGaps(options) {
278291
278509
  if (!kling.isConfigured()) {
278292
278510
  return {
278293
278511
  success: false,
278294
- error: "Invalid KLING_API_KEY (expected ACCESS_KEY:SECRET_KEY format)",
278512
+ error: "Invalid KLING_API_KEY (set your Kling API key, or the legacy ACCESS_KEY:SECRET_KEY pair)",
278295
278513
  humanLines
278296
278514
  };
278297
278515
  }
278298
278516
  const projectDir = dirname32(filePath);
278299
278517
  const footageDir = options.dir ? resolve47(process.cwd(), options.dir) : resolve47(projectDir, "footage");
278300
278518
  if (!existsSync68(footageDir)) {
278301
- await mkdir19(footageDir, { recursive: true });
278519
+ await mkdir20(footageDir, { recursive: true });
278302
278520
  }
278303
278521
  humanLines.push("Generating AI Videos");
278304
278522
  const imgbbApiKey = options.imgbbApiKey || await getApiKey("IMGBB_API_KEY", "imgbb", void 0);
@@ -278363,13 +278581,13 @@ async function executeFillGaps(options) {
278363
278581
  let generatedDuration = 0;
278364
278582
  const generatedVideos = [];
278365
278583
  const initialDuration = Math.min(10, targetDuration);
278366
- const klingDuration = initialDuration > 5 ? "10" : "5";
278367
- onProgress(`Generating ${klingDuration}s video with Kling...`);
278584
+ const klingDuration2 = initialDuration > 5 ? "10" : "5";
278585
+ onProgress(`Generating ${klingDuration2}s video with Kling...`);
278368
278586
  const prompt3 = options.prompt || "Continue the scene naturally with subtle motion";
278369
278587
  const result = await kling.generateVideo(prompt3, {
278370
278588
  prompt: prompt3,
278371
278589
  referenceImage: frameUrl,
278372
- duration: parseInt(klingDuration),
278590
+ duration: parseInt(klingDuration2),
278373
278591
  aspectRatio: options.ratio || "16:9",
278374
278592
  mode: options.mode || "std"
278375
278593
  });
@@ -278392,8 +278610,8 @@ async function executeFillGaps(options) {
278392
278610
  const videoPath = resolve47(footageDir, videoFileName);
278393
278611
  onProgress("Downloading generated video...");
278394
278612
  const videoBuffer = await downloadVideo(finalResult.videoUrl);
278395
- await writeFile27(videoPath, videoBuffer);
278396
- generatedDuration = finalResult.duration || parseInt(klingDuration);
278613
+ await writeFile28(videoPath, videoBuffer);
278614
+ generatedDuration = finalResult.duration || parseInt(klingDuration2);
278397
278615
  generatedVideos.push(videoPath);
278398
278616
  humanLines.push(` Generated: ${videoFileName} (${generatedDuration}s)`);
278399
278617
  let segmentIndex = 1;
@@ -278462,11 +278680,11 @@ async function executeFillGaps(options) {
278462
278680
  `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-seg${segmentIndex}.mp4`
278463
278681
  );
278464
278682
  const segVideoBuffer = await downloadVideo(segFinalResult.videoUrl);
278465
- await writeFile27(segVideoPath, segVideoBuffer);
278683
+ await writeFile28(segVideoPath, segVideoBuffer);
278466
278684
  const concatListPath = resolve47(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
278467
278685
  const concatList = generatedVideos.map((v4) => `file '${v4}'`).join("\n") + `
278468
278686
  file '${segVideoPath}'`;
278469
- await writeFile27(concatListPath, concatList);
278687
+ await writeFile28(concatListPath, concatList);
278470
278688
  const concatOutputPath = resolve47(
278471
278689
  footageDir,
278472
278690
  `gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-merged.mp4`
@@ -278524,7 +278742,7 @@ file '${segVideoPath}'`;
278524
278742
  let outputPath = filePath;
278525
278743
  if (generatedCount > 0) {
278526
278744
  outputPath = options.output ? resolve47(process.cwd(), options.output) : filePath;
278527
- await writeFile27(outputPath, JSON.stringify(project.toJSON(), null, 2));
278745
+ await writeFile28(outputPath, JSON.stringify(project.toJSON(), null, 2));
278528
278746
  humanLines.push(`\u2714 Filled ${generatedCount} gap(s) with AI-generated video`);
278529
278747
  humanLines.push(`Project saved: ${outputPath}`);
278530
278748
  } else {
@@ -278618,7 +278836,7 @@ __export(ai_motion_exports, {
278618
278836
  });
278619
278837
  import { resolve as resolve48 } from "node:path";
278620
278838
  import { existsSync as existsSync69 } from "node:fs";
278621
- import { readFile as readFile27, writeFile as writeFile28 } from "node:fs/promises";
278839
+ import { readFile as readFile27, writeFile as writeFile29 } from "node:fs/promises";
278622
278840
  async function getOptionalGoogleApiKey() {
278623
278841
  const configKey = await getApiKeyFromConfig("google");
278624
278842
  if (configKey) return configKey;
@@ -278788,7 +279006,7 @@ Use this video understanding to place motion graphics in safe zones, match the c
278788
279006
  const defaultOutput = options.video || options.image ? "motion-output.mp4" : options.render ? "motion.webm" : "motion.tsx";
278789
279007
  const outputPath = resolve48(process.cwd(), options.output || defaultOutput);
278790
279008
  const codePath = outputPath.replace(/\.\w+$/, ".tsx");
278791
- await writeFile28(codePath, component.code, "utf-8");
279009
+ await writeFile29(codePath, component.code, "utf-8");
278792
279010
  const shouldRender = options.render || !!options.video || !!options.image;
278793
279011
  if (!shouldRender) {
278794
279012
  return { success: true, codePath, componentName: component.name };
@@ -279024,8 +279242,8 @@ var init_ai_motion = __esm({
279024
279242
  init_output();
279025
279243
  init_validate();
279026
279244
  MODEL_MAP2 = {
279027
- sonnet: { provider: "claude", modelId: "claude-sonnet-4-6" },
279028
- opus: { provider: "claude", modelId: "claude-opus-4-7" },
279245
+ sonnet: { provider: "claude", modelId: "claude-sonnet-5-5" },
279246
+ opus: { provider: "claude", modelId: "claude-opus-5-5" },
279029
279247
  "opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
279030
279248
  gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
279031
279249
  "gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
@@ -279267,7 +279485,7 @@ __export(project_builder_exports, {
279267
279485
  buildTempProject: () => buildTempProject,
279268
279486
  resolveSourceUrl: () => resolveSourceUrl
279269
279487
  });
279270
- import { mkdtemp as mkdtemp5, mkdir as mkdir20, copyFile as copyFile6, writeFile as writeFile29, rm as rm8, readdir as readdir7 } from "node:fs/promises";
279488
+ import { mkdtemp as mkdtemp5, mkdir as mkdir21, copyFile as copyFile6, writeFile as writeFile30, rm as rm9, readdir as readdir7 } from "node:fs/promises";
279271
279489
  import { existsSync as existsSync70 } from "node:fs";
279272
279490
  import { tmpdir as tmpdir10 } from "node:os";
279273
279491
  import { createRequire as createRequire4 } from "node:module";
@@ -279275,7 +279493,7 @@ import * as path15 from "node:path";
279275
279493
  async function buildTempProject(state, projectFileDir) {
279276
279494
  const dir = await mkdtemp5(path15.join(tmpdir10(), "vibeframe-hf-"));
279277
279495
  const assetsDir = path15.join(dir, "assets");
279278
- await mkdir20(assetsDir, { recursive: true });
279496
+ await mkdir21(assetsDir, { recursive: true });
279279
279497
  const copied = /* @__PURE__ */ new Map();
279280
279498
  for (const source3 of state.sources) {
279281
279499
  if (copied.has(source3.id)) continue;
@@ -279291,10 +279509,10 @@ async function buildTempProject(state, projectFileDir) {
279291
279509
  await copyLottieRuntime(dir);
279292
279510
  }
279293
279511
  const html = generateCompositionHtml(state);
279294
- await writeFile29(path15.join(dir, "index.html"), html, "utf-8");
279512
+ await writeFile30(path15.join(dir, "index.html"), html, "utf-8");
279295
279513
  return {
279296
279514
  dir,
279297
- cleanup: () => rm8(dir, { recursive: true, force: true })
279515
+ cleanup: () => rm9(dir, { recursive: true, force: true })
279298
279516
  };
279299
279517
  }
279300
279518
  async function copyLottieRuntime(tempDir) {
@@ -279305,7 +279523,7 @@ async function copyLottieRuntime(tempDir) {
279305
279523
  const wasmSrc = path15.join(path15.dirname(webEntry), "dotlottie-player.wasm");
279306
279524
  const vendorDir = path15.join(tempDir, "vendor");
279307
279525
  const wcDest = path15.join(vendorDir, "dotlottie-wc");
279308
- await mkdir20(wcDest, { recursive: true });
279526
+ await mkdir21(wcDest, { recursive: true });
279309
279527
  for (const file of await readdir7(wcDistDir)) {
279310
279528
  if (file.endsWith(".map") || file.endsWith(".d.ts")) continue;
279311
279529
  await copyFile6(path15.join(wcDistDir, file), path15.join(wcDest, file));
@@ -279413,9 +279631,9 @@ __export(motion_overlay_exports, {
279413
279631
  executeMotionOverlay: () => executeMotionOverlay,
279414
279632
  registerMotionOverlayCommand: () => registerMotionOverlayCommand
279415
279633
  });
279416
- import { mkdir as mkdir21 } from "node:fs/promises";
279634
+ import { mkdir as mkdir23 } from "node:fs/promises";
279417
279635
  import { existsSync as existsSync71 } from "node:fs";
279418
- import { basename as basename13, dirname as dirname34, extname as extname15, resolve as resolve50 } from "node:path";
279636
+ import { basename as basename13, dirname as dirname34, extname as extname16, resolve as resolve50 } from "node:path";
279419
279637
  function normalizeUnderstand2(value) {
279420
279638
  return value === "off" || value === "required" || value === "auto" ? value : "auto";
279421
279639
  }
@@ -279438,7 +279656,7 @@ function assertValidRequest(options) {
279438
279656
  return "Provide a motion description, or pass --asset <logo.json|logo.lottie>.";
279439
279657
  }
279440
279658
  if (hasAsset) {
279441
- const ext = extname15(options.asset).toLowerCase();
279659
+ const ext = extname16(options.asset).toLowerCase();
279442
279660
  if (ext !== ".json" && ext !== ".lottie") {
279443
279661
  return "Lottie overlay asset must be a .json or .lottie file.";
279444
279662
  }
@@ -279561,7 +279779,7 @@ async function executeMotionOverlay(options) {
279561
279779
  const scale = Math.max(0.01, Math.min(2, numberOption(options.scale, position === "full" ? 1 : 0.25)));
279562
279780
  const opacity = Math.max(0, Math.min(1, numberOption(options.opacity, 1)));
279563
279781
  const loop = options.loop ?? true;
279564
- await mkdir21(dirname34(outputPath), { recursive: true });
279782
+ await mkdir23(dirname34(outputPath), { recursive: true });
279565
279783
  const backend = createHyperframesBackend();
279566
279784
  const result2 = await backend.render({
279567
279785
  projectState: buildLottieTimelineState({
@@ -279587,7 +279805,7 @@ async function executeMotionOverlay(options) {
279587
279805
  return { success: true, outputPath, provider: "lottie" };
279588
279806
  }
279589
279807
  const duration = options.duration ?? await ffprobeDuration(absVideo).catch(() => void 0);
279590
- await mkdir21(dirname34(outputPath), { recursive: true });
279808
+ await mkdir23(dirname34(outputPath), { recursive: true });
279591
279809
  const result = await executeMotion({
279592
279810
  description: options.description.trim(),
279593
279811
  video: absVideo,
@@ -279716,7 +279934,7 @@ __export(edit_cmd_exports, {
279716
279934
  executeUpscale: () => executeUpscale
279717
279935
  });
279718
279936
  import { resolve as resolve51, dirname as dirname35 } from "node:path";
279719
- import { readFile as readFile28, writeFile as writeFile30, mkdir as mkdir23 } from "node:fs/promises";
279937
+ import { readFile as readFile28, writeFile as writeFile31, mkdir as mkdir24 } from "node:fs/promises";
279720
279938
  async function executeGrade(options) {
279721
279939
  const { videoPath, style, preset: preset3, output: output3, analyzeOnly, apiKey } = options;
279722
279940
  try {
@@ -279909,6 +280127,7 @@ var init_edit_cmd = __esm({
279909
280127
  init_output();
279910
280128
  init_validate();
279911
280129
  init_cost_tier();
280130
+ init_image_file();
279912
280131
  editCommand = new Command("edit").alias("ed").description(
279913
280132
  "Edit and post-process media (silence-cut, caption, grade, reframe, upscale...)"
279914
280133
  ).addHelpText(
@@ -280344,7 +280563,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
280344
280563
  console.log();
280345
280564
  if (options.keyframes) {
280346
280565
  const keyframesPath = resolve51(process.cwd(), options.keyframes);
280347
- await writeFile30(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
280566
+ await writeFile31(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
280348
280567
  console.log(source_default.green(`Keyframes saved to: ${keyframesPath}`));
280349
280568
  }
280350
280569
  if (options.analyzeOnly) {
@@ -280368,7 +280587,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
280368
280587
  exitWithError(generalError(`Reframe failed: ${msg}`));
280369
280588
  }
280370
280589
  });
280371
- editCommand.command("image").description("Edit image(s) using AI (Gemini, OpenAI, or Grok)").argument("<images...>", "Input image file(s) followed by edit prompt").option("-p, --provider <provider>", "Provider: gemini (default), openai, grok", "gemini").option("-k, --api-key <key>", "API key (or set env variable)").option("-o, --output <path>", "Output file path", "edited.png").option("-m, --model <model>", "Model: flash/3.1-flash/latest/pro (Gemini only)", "flash").option("-r, --ratio <ratio>", "Output aspect ratio").option("--size <resolution>", "Resolution: 1K, 2K, 4K (Gemini Pro only)").option("--dry-run", "Preview parameters without executing").action(async (args, options) => {
280590
+ editCommand.command("image").description("Edit image(s) using AI (Gemini, OpenAI, or Grok)").argument("<images...>", "Input image file(s) followed by edit prompt").option("-p, --provider <provider>", "Provider: gemini (default), openai, grok", "gemini").option("-k, --api-key <key>", "API key (or set env variable)").option("-o, --output <path>", "Output file path", "edited.png").option("-m, --model <model>", "Model: flash, lite, pro (Gemini); pro (Grok)", "flash").option("-r, --ratio <ratio>", "Output aspect ratio").option("--size <resolution>", "Resolution: 1K, 2K, 4K (Gemini Pro only)").option("--dry-run", "Preview parameters without executing").action(async (args, options) => {
280372
280591
  const startedAt = Date.now();
280373
280592
  try {
280374
280593
  if (args.length < 2) {
@@ -280427,14 +280646,16 @@ Run 'vibe schema edit.<command>' for structured parameter info.
280427
280646
  const grok = new GrokProvider();
280428
280647
  await grok.initialize({ apiKey });
280429
280648
  result = await grok.editImage(imageBuffers[0], prompt3, {
280649
+ ...resolveGrokImageModel(options.model),
280430
280650
  aspectRatio: options.ratio
280431
280651
  });
280432
280652
  } else {
280433
280653
  const editModelNames = {
280434
- flash: "gemini-2.5-flash-image",
280435
- "3.1-flash": "gemini-3.1-flash-image-preview",
280436
- latest: "gemini-3.1-flash-image-preview",
280437
- pro: "gemini-3-pro-image-preview"
280654
+ flash: "gemini-3.1-flash-image",
280655
+ "3.1-flash": "gemini-3.1-flash-image",
280656
+ latest: "gemini-3.1-flash-image",
280657
+ lite: "gemini-3.1-flash-lite-image",
280658
+ pro: "gemini-3-pro-image"
280438
280659
  };
280439
280660
  const editModelName = editModelNames[options.model] || editModelNames.flash;
280440
280661
  spinner2.text = `Editing with ${editModelName}...`;
@@ -280445,15 +280666,6 @@ Run 'vibe schema edit.<command>' for structured parameter info.
280445
280666
  aspectRatio: options.ratio,
280446
280667
  resolution: options.size
280447
280668
  });
280448
- const fallbackModels = ["latest", "3.1-flash"];
280449
- if (!result.success && fallbackModels.includes(options.model)) {
280450
- spinner2.text = `${source_default.dim(result.error || `${editModelName} failed`)} \u2014 retrying with flash...`;
280451
- result = await gemini.editImage(imageBuffers, prompt3, {
280452
- model: "flash",
280453
- aspectRatio: options.ratio,
280454
- resolution: options.size
280455
- });
280456
- }
280457
280669
  }
280458
280670
  if (!result.success || !result.images || result.images.length === 0) {
280459
280671
  spinner2.fail(result.error || "Image editing failed");
@@ -280463,14 +280675,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
280463
280675
  const img = result.images[0];
280464
280676
  const outputPath = resolve51(process.cwd(), options.output);
280465
280677
  const saveImage = async () => {
280466
- await mkdir23(dirname35(outputPath), { recursive: true });
280678
+ await mkdir24(dirname35(outputPath), { recursive: true });
280467
280679
  if (img.base64) {
280468
280680
  const buffer = Buffer.from(img.base64, "base64");
280469
- await writeFile30(outputPath, buffer);
280681
+ await writeImageFile(outputPath, buffer);
280470
280682
  } else if (img.url) {
280471
280683
  const resp = await fetch(img.url);
280472
280684
  const arrayBuf = await resp.arrayBuffer();
280473
- await writeFile30(outputPath, Buffer.from(arrayBuf));
280685
+ await writeImageFile(outputPath, Buffer.from(arrayBuf));
280474
280686
  }
280475
280687
  };
280476
280688
  const resultModel = result.model;
@@ -280690,7 +280902,7 @@ __export(ai_image_exports, {
280690
280902
  executeThumbnailBestFrame: () => executeThumbnailBestFrame
280691
280903
  });
280692
280904
  import { resolve as resolve54, dirname as dirname37 } from "node:path";
280693
- import { readFile as readFile29, writeFile as writeFile33, mkdir as mkdir25 } from "node:fs/promises";
280905
+ import { readFile as readFile29, mkdir as mkdir26 } from "node:fs/promises";
280694
280906
  import { existsSync as existsSync74 } from "node:fs";
280695
280907
  async function executeImageGenerate(options) {
280696
280908
  const {
@@ -280733,8 +280945,8 @@ async function executeImageGenerate(options) {
280733
280945
  return { success: false, error: "No image data available" };
280734
280946
  }
280735
280947
  outputPath = resolve54(process.cwd(), output3);
280736
- await mkdir25(dirname37(outputPath), { recursive: true });
280737
- await writeFile33(outputPath, buffer);
280948
+ await mkdir26(dirname37(outputPath), { recursive: true });
280949
+ await writeImageFile(outputPath, buffer);
280738
280950
  }
280739
280951
  return {
280740
280952
  success: true,
@@ -280768,8 +280980,8 @@ async function executeImageGenerate(options) {
280768
280980
  const img = result.images[0];
280769
280981
  if (img.base64) {
280770
280982
  outputPath = resolve54(process.cwd(), output3);
280771
- await mkdir25(dirname37(outputPath), { recursive: true });
280772
- await writeFile33(outputPath, Buffer.from(img.base64, "base64"));
280983
+ await mkdir26(dirname37(outputPath), { recursive: true });
280984
+ await writeImageFile(outputPath, Buffer.from(img.base64, "base64"));
280773
280985
  }
280774
280986
  }
280775
280987
  return {
@@ -280782,10 +280994,11 @@ async function executeImageGenerate(options) {
280782
280994
  } else if (provider === "grok") {
280783
280995
  const key2 = apiKey || process.env.XAI_API_KEY;
280784
280996
  if (!key2) return { success: false, error: "XAI_API_KEY required" };
280785
- const openaiImage = new OpenAIImageProvider();
280786
- await openaiImage.initialize({ apiKey: key2, baseUrl: "https://api.x.ai/v1" });
280787
- const result = await openaiImage.generateImage(prompt3, {
280788
- size,
280997
+ const grok = new GrokProvider();
280998
+ await grok.initialize({ apiKey: key2 });
280999
+ const result = await grok.generateImage(prompt3, {
281000
+ ...resolveGrokImageModel(model),
281001
+ aspectRatio: ratio,
280789
281002
  n: count
280790
281003
  });
280791
281004
  if (!result.success || !result.images) {
@@ -280804,8 +281017,8 @@ async function executeImageGenerate(options) {
280804
281017
  return { success: false, error: "No image data available" };
280805
281018
  }
280806
281019
  outputPath = resolve54(process.cwd(), output3);
280807
- await mkdir25(dirname37(outputPath), { recursive: true });
280808
- await writeFile33(outputPath, buffer);
281020
+ await mkdir26(dirname37(outputPath), { recursive: true });
281021
+ await writeImageFile(outputPath, buffer);
280809
281022
  }
280810
281023
  return {
280811
281024
  success: true,
@@ -280863,8 +281076,8 @@ async function executeGeminiEdit(options) {
280863
281076
  let outputPath;
280864
281077
  if (img.base64) {
280865
281078
  outputPath = resolve54(process.cwd(), output3);
280866
- await mkdir25(dirname37(outputPath), { recursive: true });
280867
- await writeFile33(outputPath, Buffer.from(img.base64, "base64"));
281079
+ await mkdir26(dirname37(outputPath), { recursive: true });
281080
+ await writeImageFile(outputPath, Buffer.from(img.base64, "base64"));
280868
281081
  }
280869
281082
  return {
280870
281083
  success: true,
@@ -280938,6 +281151,7 @@ var init_ai_image = __esm({
280938
281151
  "use strict";
280939
281152
  init_dist();
280940
281153
  init_exec_safe();
281154
+ init_image_file();
280941
281155
  }
280942
281156
  });
280943
281157
 
@@ -280949,7 +281163,7 @@ __export(ai_analyze_exports, {
280949
281163
  registerAnalyzeCommands: () => registerAnalyzeCommands
280950
281164
  });
280951
281165
  import { readFile as readFile30 } from "node:fs/promises";
280952
- import { extname as extname16, resolve as resolve55 } from "node:path";
281166
+ import { extname as extname17, resolve as resolve55 } from "node:path";
280953
281167
  import { existsSync as existsSync75 } from "node:fs";
280954
281168
  async function executeGeminiVideo(options) {
280955
281169
  try {
@@ -281006,7 +281220,7 @@ async function executeAnalyze(options) {
281006
281220
  const isYouTube = source3.includes("youtube.com") || source3.includes("youtu.be");
281007
281221
  const isImageUrl = /^https?:\/\/.+\.(png|jpg|jpeg|webp|gif)(\?.*)?$/i.test(source3);
281008
281222
  const isVideoUrl = /^https?:\/\/.+\.(mp4|mov|webm)(\?.*)?$/i.test(source3);
281009
- const ext = extname16(source3).toLowerCase();
281223
+ const ext = extname17(source3).toLowerCase();
281010
281224
  const imageExts = [".png", ".jpg", ".jpeg", ".webp", ".gif"];
281011
281225
  const videoExts = [".mp4", ".mov", ".webm", ".avi", ".mkv"];
281012
281226
  const isLocalImage = imageExts.includes(ext);
@@ -281414,7 +281628,7 @@ async function executeSoundEffect(options) {
281414
281628
  }
281415
281629
  }
281416
281630
  function registerSoundEffectCommand(parent) {
281417
- parent.command("sound-effect").description("Generate sound effect using ElevenLabs").argument("<prompt>", "Description of the sound effect").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-o, --output <path>", "Output audio file path", "sound-effect.mp3").option("-d, --duration <seconds>", "Duration in seconds (0.5-22, default: auto)").option("--prompt-influence <value>", "Prompt influence (0-1, default: 0.3)").option("--dry-run", "Preview parameters without executing").action(async (prompt3, options) => {
281631
+ parent.command("sound-effect").description("Generate sound effect using ElevenLabs").argument("<prompt>", "Description of the sound effect").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-o, --output <path>", "Output audio file path", "sound-effect.mp3").option("-d, --duration <seconds>", "Duration in seconds (0.5-30, default: auto)").option("--prompt-influence <value>", "Prompt influence (0-1, default: 0.3)").option("--dry-run", "Preview parameters without executing").action(async (prompt3, options) => {
281418
281632
  const startedAt = Date.now();
281419
281633
  try {
281420
281634
  rejectControlChars(prompt3);
@@ -281714,9 +281928,9 @@ var init_speech = __esm({
281714
281928
  });
281715
281929
 
281716
281930
  // ../cli/src/commands/generate/thumbnail.ts
281717
- import { resolve as resolve64, dirname as dirname38, basename as basename17, extname as extname17 } from "node:path";
281931
+ import { resolve as resolve64, dirname as dirname38, basename as basename17, extname as extname18 } from "node:path";
281718
281932
  import { existsSync as existsSync79 } from "node:fs";
281719
- import { writeFile as writeFile37, mkdir as mkdir26 } from "node:fs/promises";
281933
+ import { writeFile as writeFile37, mkdir as mkdir27 } from "node:fs/promises";
281720
281934
  function registerThumbnailCommand(parent) {
281721
281935
  parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").action(async (description, options) => {
281722
281936
  const startedAt = Date.now();
@@ -281739,7 +281953,7 @@ function registerThumbnailCommand(parent) {
281739
281953
  );
281740
281954
  }
281741
281955
  const apiKey2 = await requireApiKey("GOOGLE_API_KEY", "Google", options.apiKey);
281742
- const name = basename17(options.bestFrame, extname17(options.bestFrame));
281956
+ const name = basename17(options.bestFrame, extname18(options.bestFrame));
281743
281957
  const outputPath = options.output || `${name}-thumbnail.png`;
281744
281958
  const spinner3 = ora("Analyzing video for best frame...").start();
281745
281959
  const result2 = await executeThumbnailBestFrame({
@@ -281807,7 +282021,7 @@ function registerThumbnailCommand(parent) {
281807
282021
  throw new Error("No image data available");
281808
282022
  }
281809
282023
  outputPath = resolve64(process.cwd(), options.output);
281810
- await mkdir26(dirname38(outputPath), { recursive: true });
282024
+ await mkdir27(dirname38(outputPath), { recursive: true });
281811
282025
  await writeFile37(outputPath, buffer);
281812
282026
  }
281813
282027
  outputSuccess({
@@ -281838,7 +282052,7 @@ function registerThumbnailCommand(parent) {
281838
282052
  throw new Error("No image data available");
281839
282053
  }
281840
282054
  const outputPath = resolve64(process.cwd(), options.output);
281841
- await mkdir26(dirname38(outputPath), { recursive: true });
282055
+ await mkdir27(dirname38(outputPath), { recursive: true });
281842
282056
  await writeFile37(outputPath, buffer);
281843
282057
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
281844
282058
  } catch {
@@ -281869,7 +282083,7 @@ var init_thumbnail = __esm({
281869
282083
  import { resolve as resolve65 } from "node:path";
281870
282084
  import { writeFile as writeFile38 } from "node:fs/promises";
281871
282085
  function registerVideoExtendCommand(parent) {
281872
- parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("--negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast", "3.1").option("--no-wait", "Start extension and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (id, options) => {
282086
+ parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("--negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.1, 3.1-fast", "3.1").option("--no-wait", "Start extension and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (id, options) => {
281873
282087
  const startedAt = Date.now();
281874
282088
  try {
281875
282089
  const provider = (options.provider || "kling").toLowerCase();
@@ -281987,12 +282201,7 @@ function registerVideoExtendCommand(parent) {
281987
282201
  const spinner2 = ora("Initializing Veo...").start();
281988
282202
  const gemini = new GeminiProvider();
281989
282203
  await gemini.initialize({ apiKey });
281990
- const veoModelMap = {
281991
- "3.0": "veo-3.0-generate-preview",
281992
- "3.1": "veo-3.1-generate-preview",
281993
- "3.1-fast": "veo-3.1-fast-generate-preview"
281994
- };
281995
- const veoModel = veoModelMap[options.veoModel] || "veo-3.1-generate-preview";
282204
+ const veoModel = resolveVeoModel(options.veoModel);
281996
282205
  spinner2.text = "Starting video extension...";
281997
282206
  const result = await gemini.extendVideo(id, options.prompt, {
281998
282207
  duration: parseInt(options.duration),
@@ -282153,10 +282362,15 @@ var init_provider_resolver = __esm({
282153
282362
 
282154
282363
  // ../cli/src/commands/_shared/openai-image.ts
282155
282364
  function resolveOpenAIImageModel(modelAlias) {
282156
- const isGptImage15 = modelAlias === "1.5" || modelAlias === "gpt-image-1.5";
282365
+ const alias = modelAlias?.trim() ?? "";
282366
+ for (const [id, model] of Object.entries(OPENAI_IMAGE_MODELS)) {
282367
+ if (alias === id || model.aliases.includes(alias)) {
282368
+ return { openaiModel: id, modelLabel: model.label };
282369
+ }
282370
+ }
282157
282371
  return {
282158
- openaiModel: isGptImage15 ? "gpt-image-1.5" : "gpt-image-2",
282159
- modelLabel: isGptImage15 ? "GPT Image 1.5" : "GPT Image 2"
282372
+ openaiModel: OPENAI_IMAGE_DEFAULT_MODEL,
282373
+ modelLabel: OPENAI_IMAGE_MODELS[OPENAI_IMAGE_DEFAULT_MODEL].label
282160
282374
  };
282161
282375
  }
282162
282376
  async function executeOpenAIImageGenerate(prompt3, options, ctx) {
@@ -282172,17 +282386,24 @@ async function executeOpenAIImageGenerate(prompt3, options, ctx) {
282172
282386
  });
282173
282387
  return { result, openaiModel, modelLabel };
282174
282388
  }
282389
+ var OPENAI_IMAGE_MODELS;
282175
282390
  var init_openai_image2 = __esm({
282176
282391
  "../cli/src/commands/_shared/openai-image.ts"() {
282177
282392
  "use strict";
282178
282393
  init_dist();
282394
+ OPENAI_IMAGE_MODELS = {
282395
+ "gpt-image-2.5-sunburst": { label: "GPT Image 2.5 Sunburst", aliases: ["2.5", "sunburst"] },
282396
+ "gpt-image-2.5-flare": { label: "GPT Image 2.5 Flare", aliases: ["flare", "2.5-flare"] },
282397
+ "gpt-image-2": { label: "GPT Image 2", aliases: ["2"] },
282398
+ "gpt-image-1.5": { label: "GPT Image 1.5", aliases: ["1.5"] }
282399
+ };
282179
282400
  }
282180
282401
  });
282181
282402
 
282182
282403
  // ../cli/src/commands/generate/image.ts
282183
282404
  import { resolve as resolve66, dirname as dirname39 } from "node:path";
282184
282405
  import { fileURLToPath as fileURLToPath8 } from "node:url";
282185
- import { writeFile as writeFile39, mkdir as mkdir27 } from "node:fs/promises";
282406
+ import { mkdir as mkdir28 } from "node:fs/promises";
282186
282407
  function registerImageCommand(parent) {
282187
282408
  parent.command("image").alias("img").description("Generate image using AI (Gemini, OpenAI gpt-image, Grok, or Runway)").argument("[prompt]", "Image description prompt (interactive if omitted)").option(
282188
282409
  "-p, --provider <provider>",
@@ -282193,7 +282414,7 @@ function registerImageCommand(parent) {
282193
282414
  "1:1"
282194
282415
  ).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(
282195
282416
  "-m, --model <model>",
282196
- "Model. Gemini: flash, 3.1-flash, latest, pro. OpenAI: 2 (default), 1.5"
282417
+ "Model. Gemini: flash (default), lite, pro. OpenAI: 2.5 (default), flare, 2, 1.5. Grok: pro"
282197
282418
  ).option("--dry-run", "Preview parameters without executing").addHelpText(
282198
282419
  "after",
282199
282420
  `
@@ -282296,7 +282517,7 @@ Examples:
282296
282517
  const apiKey = await requireApiKey(envKey, providerName, options.apiKey);
282297
282518
  const spinner2 = ora(`Generating image with ${providerName}...`).start();
282298
282519
  if (provider === "openai") {
282299
- const { result, modelLabel } = await executeOpenAIImageGenerate(prompt3, options, {
282520
+ const { result, modelLabel, openaiModel } = await executeOpenAIImageGenerate(prompt3, options, {
282300
282521
  apiKey
282301
282522
  });
282302
282523
  if (!result.success || !result.images) {
@@ -282319,14 +282540,16 @@ Examples:
282319
282540
  } else {
282320
282541
  throw new Error("No image data available");
282321
282542
  }
282322
- await mkdir27(dirname39(outputPath), { recursive: true });
282323
- await writeFile39(outputPath, buffer);
282543
+ await mkdir28(dirname39(outputPath), { recursive: true });
282544
+ await writeImageFile(outputPath, buffer);
282324
282545
  }
282325
282546
  outputSuccess({
282326
282547
  command: "generate image",
282327
282548
  startedAt,
282328
282549
  data: {
282329
282550
  provider: "openai",
282551
+ model: modelLabel,
282552
+ modelId: openaiModel,
282330
282553
  images: result.images.map((img) => ({
282331
282554
  url: img.url,
282332
282555
  revisedPrompt: img.revisedPrompt
@@ -282366,8 +282589,8 @@ Examples:
282366
282589
  throw new Error("No image data available");
282367
282590
  }
282368
282591
  const outputPath = resolve66(process.cwd(), options.output);
282369
- await mkdir27(dirname39(outputPath), { recursive: true });
282370
- await writeFile39(outputPath, buffer);
282592
+ await mkdir28(dirname39(outputPath), { recursive: true });
282593
+ await writeImageFile(outputPath, buffer);
282371
282594
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
282372
282595
  } catch (err) {
282373
282596
  saveSpinner.fail(
@@ -282376,7 +282599,7 @@ Examples:
282376
282599
  }
282377
282600
  }
282378
282601
  } else if (provider === "gemini") {
282379
- const validGeminiModels = ["flash", "3.1-flash", "latest", "pro"];
282602
+ const validGeminiModels = ["flash", "3.1-flash", "latest", "lite", "pro"];
282380
282603
  if (options.model && !validGeminiModels.includes(options.model)) {
282381
282604
  console.warn(
282382
282605
  source_default.yellow(
@@ -282409,26 +282632,17 @@ Examples:
282409
282632
  const gemini = new GeminiProvider();
282410
282633
  await gemini.initialize({ apiKey });
282411
282634
  const geminiModelNames = {
282412
- flash: "Nano Banana",
282635
+ flash: "Nano Banana 2",
282413
282636
  "3.1-flash": "Nano Banana 2",
282414
282637
  latest: "Nano Banana 2",
282638
+ lite: "Nano Banana 2 Lite",
282415
282639
  pro: "Nano Banana Pro"
282416
282640
  };
282417
- const modelLabel = geminiModelNames[options.model] || "Nano Banana";
282418
- let result = await gemini.generateImage(prompt3, {
282641
+ const usedLabel = geminiModelNames[options.model] || "Nano Banana 2";
282642
+ const result = await gemini.generateImage(prompt3, {
282419
282643
  model: options.model,
282420
282644
  aspectRatio: options.ratio
282421
282645
  });
282422
- let usedLabel = modelLabel;
282423
- const fallbackModels = ["latest", "3.1-flash"];
282424
- if (!result.success && options.model && fallbackModels.includes(options.model)) {
282425
- spinner2.text = `${source_default.dim(result.error || "Failed")} \u2014 retrying with Nano Banana (flash)...`;
282426
- result = await gemini.generateImage(prompt3, {
282427
- model: "flash",
282428
- aspectRatio: options.ratio
282429
- });
282430
- usedLabel = "Nano Banana (fallback)";
282431
- }
282432
282646
  if (!result.success || !result.images) {
282433
282647
  spinner2.fail(result.error || "Image generation failed");
282434
282648
  exitWithError(apiError(result.error || "Image generation failed", true));
@@ -282441,16 +282655,17 @@ Examples:
282441
282655
  if (outputPath && result.images.length > 0) {
282442
282656
  const img = result.images[0];
282443
282657
  const buffer = Buffer.from(img.base64, "base64");
282444
- await mkdir27(dirname39(outputPath), { recursive: true });
282445
- await writeFile39(outputPath, buffer);
282658
+ await mkdir28(dirname39(outputPath), { recursive: true });
282659
+ await writeImageFile(outputPath, buffer);
282446
282660
  }
282447
282661
  outputSuccess({
282448
282662
  command: "generate image",
282449
282663
  startedAt,
282450
- warnings: usedLabel.includes("fallback") ? [`Model "${options.model}" failed; fell back to flash`] : [],
282664
+ warnings: [],
282451
282665
  data: {
282452
282666
  provider: "gemini",
282453
282667
  model: usedLabel,
282668
+ modelId: result.model,
282454
282669
  images: result.images.map((img) => ({
282455
282670
  mimeType: img.mimeType
282456
282671
  })),
@@ -282474,8 +282689,8 @@ Examples:
282474
282689
  const img = result.images[0];
282475
282690
  const buffer = Buffer.from(img.base64, "base64");
282476
282691
  const outputPath = resolve66(process.cwd(), options.output);
282477
- await mkdir27(dirname39(outputPath), { recursive: true });
282478
- await writeFile39(outputPath, buffer);
282692
+ await mkdir28(dirname39(outputPath), { recursive: true });
282693
+ await writeImageFile(outputPath, buffer);
282479
282694
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
282480
282695
  } catch (err) {
282481
282696
  saveSpinner.fail(
@@ -282513,6 +282728,7 @@ Examples:
282513
282728
  options.ratio = "1:1";
282514
282729
  }
282515
282730
  const result = await grok.generateImage(prompt3, {
282731
+ ...resolveGrokImageModel(options.model),
282516
282732
  aspectRatio: options.ratio || "1:1",
282517
282733
  n: parseInt(options.count)
282518
282734
  });
@@ -282534,14 +282750,15 @@ Examples:
282534
282750
  } else {
282535
282751
  throw new Error("No image data available");
282536
282752
  }
282537
- await mkdir27(dirname39(outputPath), { recursive: true });
282538
- await writeFile39(outputPath, buffer);
282753
+ await mkdir28(dirname39(outputPath), { recursive: true });
282754
+ await writeImageFile(outputPath, buffer);
282539
282755
  }
282540
282756
  outputSuccess({
282541
282757
  command: "generate image",
282542
282758
  startedAt,
282543
282759
  data: {
282544
282760
  provider: "grok",
282761
+ modelId: resolveGrokImageModel(options.model).model,
282545
282762
  images: result.images.map((img) => ({ url: img.url })),
282546
282763
  outputPath
282547
282764
  }
@@ -282575,8 +282792,8 @@ Examples:
282575
282792
  throw new Error("No image data available");
282576
282793
  }
282577
282794
  const outputPath = resolve66(process.cwd(), options.output);
282578
- await mkdir27(dirname39(outputPath), { recursive: true });
282579
- await writeFile39(outputPath, buffer);
282795
+ await mkdir28(dirname39(outputPath), { recursive: true });
282796
+ await writeImageFile(outputPath, buffer);
282580
282797
  saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
282581
282798
  } catch (err) {
282582
282799
  saveSpinner.fail(
@@ -282658,6 +282875,7 @@ var init_image2 = __esm({
282658
282875
  init_validate();
282659
282876
  init_provider_resolver();
282660
282877
  init_openai_image2();
282878
+ init_image_file();
282661
282879
  }
282662
282880
  });
282663
282881
 
@@ -283606,11 +283824,11 @@ var init_dist5 = __esm({
283606
283824
 
283607
283825
  // ../cli/src/commands/generate/video.ts
283608
283826
  import { resolve as resolve67 } from "node:path";
283609
- import { readFile as readFile36, writeFile as writeFile40 } from "node:fs/promises";
283827
+ import { readFile as readFile36, writeFile as writeFile39 } from "node:fs/promises";
283610
283828
  function registerVideoCommand(parent) {
283611
283829
  parent.command("video").alias("vid").description("Generate video using AI (Seedance, Grok, Kling, Runway, Veo, or Gemini Omni)").argument("[prompt]", "Text prompt describing the video (interactive if omitted)").option(
283612
283830
  "-p, --provider <provider>",
283613
- "Provider: seedance (ByteDance Seedance 2.0 via fal.ai), grok, kling, runway, veo, omni (Gemini Omni, experimental). `fal` is a deprecated v0.x alias for seedance and will be removed in 1.0."
283831
+ "Provider: seedance (ByteDance Seedance 2.0 via fal.ai), grok, kling, runway, omni (Gemini Omni 1.1 Flash; Google default), veo (Veo 3.1 preview, shuts down 2026-10-22). `fal` is a deprecated v0.x alias for seedance and will be removed in 1.0."
283614
283832
  ).option(
283615
283833
  "-k, --api-key <key>",
283616
283834
  "API key (or set FAL_API_KEY / XAI_API_KEY / RUNWAY_API_SECRET / KLING_API_KEY / GOOGLE_API_KEY env)"
@@ -283623,12 +283841,12 @@ function registerVideoCommand(parent) {
283623
283841
  "Aspect ratio: 16:9, 9:16, or 1:1 (auto-detected from image if omitted)"
283624
283842
  ).option("--seed <number>", "Random seed for reproducibility (Runway only)").option("--mode <mode>", "Generation mode: std or pro (Kling only)", "std").option(
283625
283843
  "--seedance-model <model>",
283626
- "Seedance variant: quality or fast (fal.ai only)",
283844
+ "Seedance variant: quality (2.0), fast, or 2.5 (fal.ai only)",
283627
283845
  "quality"
283628
- ).option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 480p, 720p, 1080p, or 4k depending on provider").option("--last-frame <path>", "Last frame image for frame interpolation (Veo) or Seedance end frame").option("--end-image <path>", "Ending frame image for Seedance image-to-video").option(
283846
+ ).option("--grok-model <model>", "Grok video model: 1.5 (default), lite, classic", "1.5").option("--kling-model <model>", "Kling model: v3 (default), v2.6, v2.5-turbo", "v3").option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 480p, 720p, 1080p, or 4k depending on provider").option("--last-frame <path>", "Last frame image for frame interpolation (Veo) or Seedance end frame").option("--end-image <path>", "Ending frame image for Seedance image-to-video").option(
283629
283847
  "--ref-images <paths...>",
283630
283848
  "Reference images for Seedance reference-to-video or Veo character consistency"
283631
- ).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(
283849
+ ).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.1, 3.1-fast (default: 3.1-fast)", "3.1-fast").option(
283632
283850
  "--runway-model <model>",
283633
283851
  "Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)",
283634
283852
  "gen4.5"
@@ -283689,7 +283907,7 @@ Examples:
283689
283907
  exitWithError(
283690
283908
  usageError(
283691
283909
  `Invalid provider: ${provider}`,
283692
- "Available providers: seedance, grok, kling, runway, veo, omni (experimental). `fal` is a deprecated alias for seedance."
283910
+ "Available providers: seedance, grok, kling, runway, omni, veo. `fal` is a deprecated alias for seedance."
283693
283911
  )
283694
283912
  );
283695
283913
  }
@@ -283757,13 +283975,7 @@ Examples:
283757
283975
  options.ratio = "16:9";
283758
283976
  }
283759
283977
  if (options.dryRun) {
283760
- const costUsd = provider === "seedance" || provider === "fal" ? estimateSeedanceVideoCostUsd({
283761
- durationSec: Number(options.duration) || 5,
283762
- resolution: options.resolution,
283763
- aspectRatio: options.ratio,
283764
- fast: options.seedanceModel === "fast",
283765
- hasVideoReference: Boolean(options.refVideos)
283766
- }) : void 0;
283978
+ const costUsd = provider === "seedance" || provider === "fal" ? realRunCost(provider, options).costUsd : void 0;
283767
283979
  outputSuccess({
283768
283980
  command: "generate video",
283769
283981
  startedAt,
@@ -283781,6 +283993,8 @@ Examples:
283781
283993
  resolution: options.resolution,
283782
283994
  veoModel: options.veoModel,
283783
283995
  seedanceModel: options.seedanceModel,
283996
+ grokModel: options.grokModel,
283997
+ klingModel: options.klingModel,
283784
283998
  refImages: options.refImages,
283785
283999
  refVideos: options.refVideos,
283786
284000
  refAudio: options.refAudio,
@@ -283802,7 +284016,7 @@ Examples:
283802
284016
  runway: "Runway",
283803
284017
  kling: "Kling",
283804
284018
  veo: "Veo",
283805
- omni: "Gemini Omni (experimental)",
284019
+ omni: "Gemini Omni 1.1 Flash",
283806
284020
  grok: "Grok",
283807
284021
  seedance: "Seedance 2.0 via fal.ai"
283808
284022
  };
@@ -283901,6 +284115,7 @@ Examples:
283901
284115
  }
283902
284116
  result = await kling.generateVideo(prompt3, {
283903
284117
  prompt: prompt3,
284118
+ model: resolveKlingModel(options.klingModel),
283904
284119
  referenceImage: klingImage,
283905
284120
  duration: parseInt(options.duration),
283906
284121
  aspectRatio: options.ratio,
@@ -283950,12 +284165,7 @@ Examples:
283950
284165
  } else if (provider === "veo") {
283951
284166
  const gemini = new GeminiProvider();
283952
284167
  await gemini.initialize({ apiKey });
283953
- const veoModelMap = {
283954
- "3.0": "veo-3.0-generate-preview",
283955
- "3.1": "veo-3.1-generate-preview",
283956
- "3.1-fast": "veo-3.1-fast-generate-preview"
283957
- };
283958
- const veoModel = veoModelMap[options.veoModel] || "veo-3.1-fast-generate-preview";
284168
+ const veoModel = resolveVeoModel(options.veoModel);
283959
284169
  const veoDuration = parseInt(options.duration) <= 6 ? 6 : 8;
283960
284170
  let lastFrame;
283961
284171
  if (options.lastFrame) {
@@ -284029,9 +284239,12 @@ Examples:
284029
284239
  await grok.initialize({ apiKey });
284030
284240
  result = await grok.generateVideo(prompt3, {
284031
284241
  prompt: prompt3,
284242
+ model: resolveGrokVideoModel(options.grokModel),
284032
284243
  referenceImage,
284033
284244
  duration: parseInt(options.duration),
284034
- aspectRatio: options.ratio
284245
+ aspectRatio: options.ratio,
284246
+ resolution: options.resolution,
284247
+ generateAudio: options.generateAudio
284035
284248
  });
284036
284249
  if (result.status === "failed") {
284037
284250
  spinner2.fail(result.error || "Failed to start generation");
@@ -284121,9 +284334,8 @@ Examples:
284121
284334
  exitWithError(apiError(message, true));
284122
284335
  }
284123
284336
  }
284124
- spinner2.text = "Generating video with fal.ai Seedance 2.0 (this may take 1-3 minutes)...";
284125
- const seedanceModel = String(options.seedanceModel ?? "quality").toLowerCase();
284126
- const falModel = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
284337
+ const falModel = resolveSeedanceVariant(options.seedanceModel);
284338
+ spinner2.text = `Generating video with fal.ai ${falModel} (this may take 1-3 minutes)...`;
284127
284339
  result = await fal.generateVideo(prompt3, {
284128
284340
  prompt: prompt3,
284129
284341
  referenceImage: seedanceReferences.length > 0 ? void 0 : falImage,
@@ -284140,11 +284352,20 @@ Examples:
284140
284352
  } else if (provider === "omni") {
284141
284353
  const omni = new OmniProvider();
284142
284354
  await omni.initialize({ apiKey });
284143
- spinner2.text = "Generating video with Gemini Omni (experimental)...";
284355
+ spinner2.text = "Generating video with Gemini Omni 1.1 Flash...";
284356
+ let lastFrame;
284357
+ if (options.lastFrame) {
284358
+ const lastFramePath = resolve67(process.cwd(), options.lastFrame);
284359
+ const ext = options.lastFrame.toLowerCase().split(".").pop();
284360
+ const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
284361
+ lastFrame = `data:${mimeType};base64,${(await readFile36(lastFramePath)).toString("base64")}`;
284362
+ }
284144
284363
  result = await omni.generateVideo(prompt3, {
284145
284364
  prompt: prompt3,
284146
284365
  referenceImage,
284147
- aspectRatio: options.ratio
284366
+ lastFrame,
284367
+ aspectRatio: options.ratio,
284368
+ resolution: options.resolution
284148
284369
  });
284149
284370
  finalResult = result;
284150
284371
  }
@@ -284158,14 +284379,14 @@ Examples:
284158
284379
  if (options.output && finalResult.videoUrl) {
284159
284380
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
284160
284381
  outputPath = resolve67(process.cwd(), options.output);
284161
- await writeFile40(outputPath, buffer);
284382
+ await writeFile39(outputPath, buffer);
284162
284383
  }
284163
284384
  const cost = realRunCost(provider, options);
284164
284385
  outputSuccess({
284165
284386
  command: "generate video",
284166
284387
  startedAt,
284167
284388
  costUsd: cost.costUsd,
284168
- warnings: cost.warnings,
284389
+ warnings: provider === "veo" ? [VEO_SHUTDOWN_WARNING, ...cost.warnings] : cost.warnings,
284169
284390
  data: {
284170
284391
  provider,
284171
284392
  taskId: result?.id,
@@ -284177,6 +284398,9 @@ Examples:
284177
284398
  return;
284178
284399
  }
284179
284400
  console.log();
284401
+ if (provider === "veo") {
284402
+ console.log(source_default.yellow(VEO_SHUTDOWN_WARNING));
284403
+ }
284180
284404
  if (finalResult.videoUrl) {
284181
284405
  console.log(`Video URL: ${finalResult.videoUrl}`);
284182
284406
  }
@@ -284189,7 +284413,7 @@ Examples:
284189
284413
  try {
284190
284414
  const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
284191
284415
  const outputPath = resolve67(process.cwd(), options.output);
284192
- await writeFile40(outputPath, buffer);
284416
+ await writeFile39(outputPath, buffer);
284193
284417
  downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
284194
284418
  } catch (err) {
284195
284419
  downloadSpinner.fail(
@@ -284204,12 +284428,14 @@ Examples:
284204
284428
  }
284205
284429
  function realRunCost(provider, options) {
284206
284430
  if (provider === "seedance" || provider === "fal") {
284431
+ const variant = resolveSeedanceVariant(options.seedanceModel);
284207
284432
  return {
284208
284433
  costUsd: estimateSeedanceVideoCostUsd({
284209
284434
  durationSec: Number(options.duration) || 5,
284210
284435
  resolution: options.resolution,
284211
284436
  aspectRatio: options.ratio,
284212
- fast: options.seedanceModel === "fast",
284437
+ fast: variant === "seedance-2.0-fast",
284438
+ v25: variant === "seedance-2.5",
284213
284439
  hasVideoReference: Boolean(options.refVideos)
284214
284440
  }),
284215
284441
  warnings: []
@@ -284299,6 +284525,7 @@ function printVideoStarted(providerLabel, taskId, taskType) {
284299
284525
  console.log(`Task ID: ${source_default.bold(taskId)}`);
284300
284526
  if (taskType) console.log(`Type: ${taskType}`);
284301
284527
  }
284528
+ var VEO_SHUTDOWN_WARNING;
284302
284529
  var init_video = __esm({
284303
284530
  "../cli/src/commands/generate/video.ts"() {
284304
284531
  "use strict";
@@ -284314,6 +284541,7 @@ var init_video = __esm({
284314
284541
  init_upload_host();
284315
284542
  init_ai_helpers();
284316
284543
  init_status_jobs();
284544
+ VEO_SHUTDOWN_WARNING = "Veo 3.1 preview models shut down on 2026-10-22. Use `-p omni` (Gemini Omni 1.1 Flash) instead.";
284317
284545
  }
284318
284546
  });
284319
284547
 
@@ -284333,7 +284561,7 @@ var init_sanitize = __esm({
284333
284561
 
284334
284562
  // ../cli/src/commands/generate/storyboard.ts
284335
284563
  import { resolve as resolve68 } from "node:path";
284336
- import { writeFile as writeFile41 } from "node:fs/promises";
284564
+ import { writeFile as writeFile40 } from "node:fs/promises";
284337
284565
  async function executeStoryboard(options) {
284338
284566
  const { content, duration, creativity = "low", output: output3, apiKey } = options;
284339
284567
  try {
@@ -284352,7 +284580,7 @@ async function executeStoryboard(options) {
284352
284580
  let outputPath;
284353
284581
  if (output3) {
284354
284582
  outputPath = resolve68(process.cwd(), output3);
284355
- await writeFile41(outputPath, JSON.stringify(segments, null, 2), "utf-8");
284583
+ await writeFile40(outputPath, JSON.stringify(segments, null, 2), "utf-8");
284356
284584
  }
284357
284585
  return { success: true, segments, segmentCount: segments.length, outputPath };
284358
284586
  } catch (error) {
@@ -298150,7 +298378,7 @@ var init_openai3 = __esm({
298150
298378
  OpenAIAdapter = class {
298151
298379
  provider = "openai";
298152
298380
  client = null;
298153
- model = "gpt-5-mini";
298381
+ model = "gpt-5.4-mini";
298154
298382
  async initialize(apiKey) {
298155
298383
  this.client = new openai_default({ apiKey });
298156
298384
  }
@@ -301699,7 +301927,7 @@ var init_claude2 = __esm({
301699
301927
  ClaudeAdapter = class {
301700
301928
  provider = "claude";
301701
301929
  client = null;
301702
- model = "claude-sonnet-4-6";
301930
+ model = "claude-sonnet-5-5";
301703
301931
  async initialize(apiKey) {
301704
301932
  this.client = new sdk_default({ apiKey });
301705
301933
  }
@@ -301724,6 +301952,13 @@ var init_claude2 = __esm({
301724
301952
  content: msg.content
301725
301953
  });
301726
301954
  } else if (msg.role === "assistant") {
301955
+ if (msg.providerContent) {
301956
+ claudeMessages.push({
301957
+ role: "assistant",
301958
+ content: msg.providerContent
301959
+ });
301960
+ continue;
301961
+ }
301727
301962
  const content = [];
301728
301963
  if (msg.content) {
301729
301964
  content.push({ type: "text", text: msg.content });
@@ -301745,16 +301980,17 @@ var init_claude2 = __esm({
301745
301980
  });
301746
301981
  }
301747
301982
  } else if (msg.role === "tool") {
301748
- claudeMessages.push({
301749
- role: "user",
301750
- content: [
301751
- {
301752
- type: "tool_result",
301753
- tool_use_id: msg.toolCallId,
301754
- content: msg.content
301755
- }
301756
- ]
301757
- });
301983
+ const result = {
301984
+ type: "tool_result",
301985
+ tool_use_id: msg.toolCallId,
301986
+ content: msg.content
301987
+ };
301988
+ const last3 = claudeMessages.at(-1);
301989
+ if (last3?.role === "user" && Array.isArray(last3.content)) {
301990
+ last3.content.push(result);
301991
+ } else {
301992
+ claudeMessages.push({ role: "user", content: [result] });
301993
+ }
301758
301994
  }
301759
301995
  }
301760
301996
  const claudeTools = tools2.map((tool) => ({
@@ -301768,7 +302004,8 @@ var init_claude2 = __esm({
301768
302004
  }));
301769
302005
  const response = await this.client.messages.create({
301770
302006
  model: this.model,
301771
- max_tokens: 4096,
302007
+ // Thinking tokens count against this cap on Claude 5.x.
302008
+ max_tokens: 16e3,
301772
302009
  system: systemPrompt,
301773
302010
  messages: claudeMessages,
301774
302011
  tools: claudeTools.length > 0 ? claudeTools : void 0
@@ -301795,7 +302032,8 @@ var init_claude2 = __esm({
301795
302032
  return {
301796
302033
  content: textContent2,
301797
302034
  toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
301798
- finishReason
302035
+ finishReason,
302036
+ providerContent: response.content
301799
302037
  };
301800
302038
  }
301801
302039
  };
@@ -302760,17 +302998,51 @@ var init_dist6 = __esm({
302760
302998
  // ../cli/src/agent/adapters/gemini.ts
302761
302999
  var gemini_exports = {};
302762
303000
  __export(gemini_exports, {
302763
- GeminiAdapter: () => GeminiAdapter
303001
+ GeminiAdapter: () => GeminiAdapter,
303002
+ toGeminiSchema: () => toGeminiSchema
302764
303003
  });
302765
- var GeminiAdapter;
303004
+ function toGeminiSchema(schema) {
303005
+ if (Array.isArray(schema)) return schema.map(toGeminiSchema);
303006
+ if (!schema || typeof schema !== "object") return schema;
303007
+ const out = {};
303008
+ for (const [key2, value] of Object.entries(schema)) {
303009
+ if (!GEMINI_SCHEMA_KEYS.has(key2)) continue;
303010
+ if (key2 === "properties" && value && typeof value === "object") {
303011
+ out.properties = Object.fromEntries(
303012
+ Object.entries(value).map(([name, prop2]) => [name, toGeminiSchema(prop2)])
303013
+ );
303014
+ } else if (key2 === "items") {
303015
+ out.items = toGeminiSchema(value);
303016
+ } else {
303017
+ out[key2] = value;
303018
+ }
303019
+ }
303020
+ return out;
303021
+ }
303022
+ var GEMINI_SCHEMA_KEYS, GeminiAdapter;
302766
303023
  var init_gemini2 = __esm({
302767
303024
  "../cli/src/agent/adapters/gemini.ts"() {
302768
303025
  "use strict";
302769
303026
  init_dist6();
303027
+ init_dist();
303028
+ GEMINI_SCHEMA_KEYS = /* @__PURE__ */ new Set([
303029
+ "type",
303030
+ "format",
303031
+ "description",
303032
+ "nullable",
303033
+ "enum",
303034
+ "items",
303035
+ "properties",
303036
+ "required",
303037
+ "minItems",
303038
+ "maxItems",
303039
+ "minimum",
303040
+ "maximum"
303041
+ ]);
302770
303042
  GeminiAdapter = class {
302771
303043
  provider = "gemini";
302772
303044
  client = null;
302773
- model = "gemini-2.5-flash";
303045
+ model = GEMINI_AGENT_DEFAULT_TEXT_MODEL;
302774
303046
  async initialize(apiKey) {
302775
303047
  this.client = new GoogleGenerativeAI(apiKey);
302776
303048
  }
@@ -302792,7 +303064,12 @@ var init_gemini2 = __esm({
302792
303064
  description: tool.description,
302793
303065
  parameters: {
302794
303066
  type: SchemaType.OBJECT,
302795
- properties: tool.parameters.properties,
303067
+ properties: Object.fromEntries(
303068
+ Object.entries(tool.parameters.properties).map(([name, prop2]) => [
303069
+ name,
303070
+ toGeminiSchema(prop2)
303071
+ ])
303072
+ ),
302796
303073
  required: tool.parameters.required
302797
303074
  }
302798
303075
  }))
@@ -302811,6 +303088,10 @@ var init_gemini2 = __esm({
302811
303088
  parts: [{ text: msg.content }]
302812
303089
  });
302813
303090
  } else if (msg.role === "assistant") {
303091
+ if (msg.providerContent) {
303092
+ geminiContents.push({ role: "model", parts: msg.providerContent });
303093
+ continue;
303094
+ }
302814
303095
  const parts = [];
302815
303096
  if (msg.content) {
302816
303097
  parts.push({ text: msg.content });
@@ -302832,16 +303113,19 @@ var init_gemini2 = __esm({
302832
303113
  });
302833
303114
  }
302834
303115
  } else if (msg.role === "tool") {
302835
- geminiContents.push({
302836
- role: "user",
302837
- parts: [{
302838
- functionResponse: {
302839
- name: msg.toolCallId.split(":::")[0] || "unknown",
302840
- // Extract function name from id
302841
- response: { result: msg.content }
302842
- }
302843
- }]
302844
- });
303116
+ const part = {
303117
+ functionResponse: {
303118
+ name: msg.toolCallId.split(":::")[0] || "unknown",
303119
+ // Extract function name from id
303120
+ response: { result: msg.content }
303121
+ }
303122
+ };
303123
+ const last3 = geminiContents.at(-1);
303124
+ if (last3?.role === "user" && last3.parts.every((p2) => "functionResponse" in p2)) {
303125
+ last3.parts.push(part);
303126
+ } else {
303127
+ geminiContents.push({ role: "user", parts: [part] });
303128
+ }
302845
303129
  }
302846
303130
  }
302847
303131
  const result = await model.generateContent({
@@ -302878,7 +303162,8 @@ var init_gemini2 = __esm({
302878
303162
  return {
302879
303163
  content: textContent2,
302880
303164
  toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
302881
- finishReason
303165
+ finishReason,
303166
+ providerContent: candidate.content.parts
302882
303167
  };
302883
303168
  }
302884
303169
  };
@@ -303081,7 +303366,7 @@ var init_xai = __esm({
303081
303366
  XAIAdapter = class {
303082
303367
  provider = "xai";
303083
303368
  client = null;
303084
- model = "grok-4-1-fast-reasoning";
303369
+ model = "grok-4.3";
303085
303370
  async initialize(apiKey) {
303086
303371
  this.client = new openai_default({
303087
303372
  apiKey,
@@ -303381,7 +303666,7 @@ __export(detect_exports, {
303381
303666
  executeDetectScenes: () => executeDetectScenes,
303382
303667
  executeDetectSilence: () => executeDetectSilence
303383
303668
  });
303384
- import { readFile as readFile41, writeFile as writeFile45 } from "node:fs/promises";
303669
+ import { readFile as readFile41, writeFile as writeFile44 } from "node:fs/promises";
303385
303670
  import { resolve as resolve74, basename as basename20 } from "node:path";
303386
303671
  async function executeDetectScenes(options) {
303387
303672
  try {
@@ -303420,7 +303705,7 @@ async function executeDetectScenes(options) {
303420
303705
  }));
303421
303706
  if (options.outputPath) {
303422
303707
  const outputPath = resolve74(process.cwd(), options.outputPath);
303423
- await writeFile45(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
303708
+ await writeFile44(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
303424
303709
  }
303425
303710
  return { success: true, scenes: result, totalDuration };
303426
303711
  } catch (error) {
@@ -303467,7 +303752,7 @@ async function executeDetectSilence(options) {
303467
303752
  }
303468
303753
  if (options.outputPath) {
303469
303754
  const outputPath = resolve74(process.cwd(), options.outputPath);
303470
- await writeFile45(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
303755
+ await writeFile44(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
303471
303756
  }
303472
303757
  return { success: true, silences };
303473
303758
  } catch (error) {
@@ -303516,7 +303801,7 @@ async function executeDetectBeats(options) {
303516
303801
  }
303517
303802
  if (options.outputPath) {
303518
303803
  const outputPath = resolve74(process.cwd(), options.outputPath);
303519
- await writeFile45(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
303804
+ await writeFile44(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
303520
303805
  }
303521
303806
  return { success: true, beats, beatCount: beats.length };
303522
303807
  } catch (error) {
@@ -303620,7 +303905,7 @@ var init_detect = __esm({
303620
303905
  duration: (i3 < scenes.length - 1 ? scenes[i3 + 1].timestamp : totalDuration) - s2.timestamp
303621
303906
  }))
303622
303907
  };
303623
- await writeFile45(outputPath, JSON.stringify(result, null, 2), "utf-8");
303908
+ await writeFile44(outputPath, JSON.stringify(result, null, 2), "utf-8");
303624
303909
  console.log(source_default.green(`Saved to: ${outputPath}`));
303625
303910
  }
303626
303911
  if (options.project) {
@@ -303650,7 +303935,7 @@ var init_detect = __esm({
303650
303935
  sourceEndOffset: end
303651
303936
  });
303652
303937
  }
303653
- await writeFile45(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
303938
+ await writeFile44(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
303654
303939
  console.log(source_default.green(`Added ${scenes.length} clips to project`));
303655
303940
  }
303656
303941
  } catch (error) {
@@ -303732,7 +304017,7 @@ var init_detect = __esm({
303732
304017
  console.log();
303733
304018
  if (options.output) {
303734
304019
  const outputPath = resolve74(process.cwd(), options.output);
303735
- await writeFile45(
304020
+ await writeFile44(
303736
304021
  outputPath,
303737
304022
  JSON.stringify({ source: absPath, silences }, null, 2),
303738
304023
  "utf-8"
@@ -303817,7 +304102,7 @@ var init_detect = __esm({
303817
304102
  console.log();
303818
304103
  if (options.output) {
303819
304104
  const outputPath = resolve74(process.cwd(), options.output);
303820
- await writeFile45(
304105
+ await writeFile44(
303821
304106
  outputPath,
303822
304107
  JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2),
303823
304108
  "utf-8"
@@ -304411,7 +304696,7 @@ init_scene_project();
304411
304696
  init_project_config();
304412
304697
  init_cost_tier();
304413
304698
  import { resolve as resolve29, relative as relative8, dirname as dirname24 } from "node:path";
304414
- import { mkdir as mkdir11, readFile as readFile14, writeFile as writeFile15, access as access4, copyFile as copyFile3 } from "node:fs/promises";
304699
+ import { mkdir as mkdir12, readFile as readFile14, writeFile as writeFile15, access as access4, copyFile as copyFile3 } from "node:fs/promises";
304415
304700
  import { existsSync as existsSync46 } from "node:fs";
304416
304701
 
304417
304702
  // ../cli/src/commands/_shared/scene-html-emit.ts
@@ -304891,7 +305176,7 @@ init_storyboard_parse();
304891
305176
  init_storyboard_source();
304892
305177
  init_root_sync();
304893
305178
  import { existsSync as existsSync44 } from "node:fs";
304894
- import { mkdir as mkdir10, writeFile as writeFile13 } from "node:fs/promises";
305179
+ import { mkdir as mkdir11, writeFile as writeFile13 } from "node:fs/promises";
304895
305180
  import { join as join58, resolve as resolve26 } from "node:path";
304896
305181
  async function executeSceneSubmit(opts) {
304897
305182
  const projectDir = resolve26(opts.projectDir);
@@ -304985,7 +305270,7 @@ async function executeSceneSubmit(opts) {
304985
305270
  return { ...base2, success: true };
304986
305271
  }
304987
305272
  const absPath = join58(projectDir, scenePath);
304988
- await mkdir10(join58(projectDir, "compositions"), { recursive: true });
305273
+ await mkdir11(join58(projectDir, "compositions"), { recursive: true });
304989
305274
  await writeFile13(absPath, html.endsWith("\n") ? html : `${html}
304990
305275
  `, "utf-8");
304991
305276
  return {
@@ -305576,7 +305861,7 @@ async function executeSceneAdd(opts) {
305576
305861
  }
305577
305862
  audioRelPath = `assets/narration-${id}.${ext}`;
305578
305863
  audioAbsPath = resolve29(projectDir, audioRelPath);
305579
- await mkdir11(dirname24(audioAbsPath), { recursive: true });
305864
+ await mkdir12(dirname24(audioAbsPath), { recursive: true });
305580
305865
  await copyFile3(sourceAbs, audioAbsPath);
305581
305866
  try {
305582
305867
  narrationDuration = await getAudioDuration(audioAbsPath);
@@ -305609,7 +305894,7 @@ async function executeSceneAdd(opts) {
305609
305894
  }
305610
305895
  audioRelPath = `assets/narration-${id}.${resolution.audioExtension}`;
305611
305896
  audioAbsPath = resolve29(projectDir, audioRelPath);
305612
- await mkdir11(dirname24(audioAbsPath), { recursive: true });
305897
+ await mkdir12(dirname24(audioAbsPath), { recursive: true });
305613
305898
  await writeFile15(audioAbsPath, tts.audioBuffer);
305614
305899
  try {
305615
305900
  narrationDuration = await getAudioDuration(audioAbsPath);
@@ -305672,7 +305957,7 @@ async function executeSceneAdd(opts) {
305672
305957
  const img = imageResult.images[0];
305673
305958
  imageRelPath = `assets/scene-${id}.png`;
305674
305959
  imageAbsPath = resolve29(projectDir, imageRelPath);
305675
- await mkdir11(dirname24(imageAbsPath), { recursive: true });
305960
+ await mkdir12(dirname24(imageAbsPath), { recursive: true });
305676
305961
  let buffer;
305677
305962
  if (img.base64) {
305678
305963
  buffer = Buffer.from(img.base64, "base64");
@@ -305699,7 +305984,7 @@ async function executeSceneAdd(opts) {
305699
305984
  }
305700
305985
  imageRelPath = `assets/scene-${id}.png`;
305701
305986
  imageAbsPath = resolve29(projectDir, imageRelPath);
305702
- await mkdir11(dirname24(imageAbsPath), { recursive: true });
305987
+ await mkdir12(dirname24(imageAbsPath), { recursive: true });
305703
305988
  const buffer = Buffer.from(imageResult.images[0].base64, "base64");
305704
305989
  await writeFile15(imageAbsPath, buffer);
305705
305990
  }
@@ -305718,7 +306003,7 @@ async function executeSceneAdd(opts) {
305718
306003
  }
305719
306004
  lottieRelPath = `assets/lottie-${id}.${ext}`;
305720
306005
  lottieAbsPath = resolve29(projectDir, lottieRelPath);
305721
- await mkdir11(dirname24(lottieAbsPath), { recursive: true });
306006
+ await mkdir12(dirname24(lottieAbsPath), { recursive: true });
305722
306007
  await copyFile3(sourceAbs, lottieAbsPath);
305723
306008
  lottieInput = {
305724
306009
  src: lottieRelPath,
@@ -305788,7 +306073,7 @@ async function executeSceneAdd(opts) {
305788
306073
  transcript: transcriptWords,
305789
306074
  lottie: lottieInput
305790
306075
  });
305791
- await mkdir11(dirname24(scenePath), { recursive: true });
306076
+ await mkdir12(dirname24(scenePath), { recursive: true });
305792
306077
  await writeFile15(scenePath, sceneHtml, "utf-8");
305793
306078
  opts.onProgress?.("Updating root composition...");
305794
306079
  let start = 0;
@@ -306005,6 +306290,7 @@ init_scene_build();
306005
306290
  init_install_skill();
306006
306291
  init_compose_prompts();
306007
306292
  init_scene_repair();
306293
+ init_build_video_providers();
306008
306294
  var SCENE_PRESETS2 = [
306009
306295
  "simple",
306010
306296
  "announcement",
@@ -306404,12 +306690,12 @@ var sceneBuildSchema = z3.object({
306404
306690
  "TTS provider override. Default 'auto' (elevenlabs key > openai key > local kokoro)."
306405
306691
  ),
306406
306692
  voice: z3.string().optional().describe("TTS voice id (provider-specific)."),
306407
- imageProvider: z3.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2)."),
306408
- videoProvider: z3.enum(["seedance", "grok", "kling", "runway", "veo"]).optional().describe("Video provider for per-beat video cues. Default seedance."),
306693
+ imageProvider: z3.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2.5-sunburst)."),
306694
+ videoProvider: z3.enum(BUILD_VIDEO_PROVIDERS).optional().describe("Video provider for per-beat video cues. Default seedance."),
306409
306695
  musicProvider: z3.enum(["elevenlabs", "replicate"]).optional().describe("Music provider for per-beat music cues. Default elevenlabs."),
306410
306696
  imageQuality: z3.enum(["standard", "hd"]).optional().describe("OpenAI image quality. Default 'standard'."),
306411
306697
  imageModel: z3.string().optional().describe(
306412
- "Image model for keyframes/backdrops/character sheets (gemini: flash|pro, openai: gpt-image-2). Provider default when omitted."
306698
+ "Image model for keyframes/backdrops/character sheets (gemini: flash|lite|pro, openai: gpt-image-2.5-sunburst|gpt-image-2.5-flare|gpt-image-2). Provider default when omitted."
306413
306699
  ),
306414
306700
  imageSize: z3.enum(["1024x1024", "1536x1024", "1024x1536"]).optional().describe("OpenAI image size. Default '1536x1024' (cinematic 16:9-ish)."),
306415
306701
  maxCostUsd: z3.number().optional().describe("Fail before provider spend when estimated cost exceeds this USD cap."),
@@ -306842,7 +307128,7 @@ init_api_key();
306842
307128
  init_exec_safe();
306843
307129
  init_remotion();
306844
307130
  import { resolve as resolve53, dirname as dirname36, basename as basename14 } from "node:path";
306845
- import { writeFile as writeFile31, mkdir as mkdir24, rm as rm9 } from "node:fs/promises";
307131
+ import { writeFile as writeFile33, mkdir as mkdir25, rm as rm10 } from "node:fs/promises";
306846
307132
  import { existsSync as existsSync73 } from "node:fs";
306847
307133
  import { tmpdir as tmpdir11 } from "node:os";
306848
307134
  var ASS_STYLES = ["karaoke-sweep", "typewriter"];
@@ -306994,7 +307280,7 @@ async function executeAnimatedCaption(options) {
306994
307280
  }
306995
307281
  const effectiveFontSize = fontSize ?? Math.round(height * 0.04);
306996
307282
  const tmpAudioDir = resolve53(tmpdir11(), `vf-ac-${Date.now()}`);
306997
- await mkdir24(tmpAudioDir, { recursive: true });
307283
+ await mkdir25(tmpAudioDir, { recursive: true });
306998
307284
  const audioPath = resolve53(tmpAudioDir, "audio.wav");
306999
307285
  await execSafe("ffmpeg", [
307000
307286
  "-y",
@@ -307011,13 +307297,13 @@ async function executeAnimatedCaption(options) {
307011
307297
  ], { timeout: 12e4 });
307012
307298
  const apiKey = await getApiKey("OPENAI_API_KEY", "OpenAI");
307013
307299
  if (!apiKey) {
307014
- await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307300
+ await rm10(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307015
307301
  });
307016
307302
  return { success: false, error: "OPENAI_API_KEY required for Whisper transcription. Run 'vibe setup' or set OPENAI_API_KEY in .env" };
307017
307303
  }
307018
307304
  const transcript = await transcribeWithWords(audioPath, apiKey, language);
307019
307305
  if (!transcript.words || transcript.words.length === 0) {
307020
- await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307306
+ await rm10(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307021
307307
  });
307022
307308
  return { success: false, error: "No words detected in transcription" };
307023
307309
  }
@@ -307025,7 +307311,7 @@ async function executeAnimatedCaption(options) {
307025
307311
  const absOutputPath = resolve53(process.cwd(), outputPath);
307026
307312
  const outDir = dirname36(absOutputPath);
307027
307313
  if (!existsSync73(outDir)) {
307028
- await mkdir24(outDir, { recursive: true });
307314
+ await mkdir25(outDir, { recursive: true });
307029
307315
  }
307030
307316
  if (tier === "ass") {
307031
307317
  const assContent = generateASS(
@@ -307034,7 +307320,7 @@ async function executeAnimatedCaption(options) {
307034
307320
  { highlightColor, fontSize: effectiveFontSize, position, width, height }
307035
307321
  );
307036
307322
  const assPath = resolve53(tmpAudioDir, "captions.ass");
307037
- await writeFile31(assPath, assContent, "utf-8");
307323
+ await writeFile33(assPath, assContent, "utf-8");
307038
307324
  const escapedAssPath = assPath.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
307039
307325
  await execSafe("ffmpeg", [
307040
307326
  "-y",
@@ -307071,12 +307357,12 @@ async function executeAnimatedCaption(options) {
307071
307357
  outputPath: absOutputPath
307072
307358
  });
307073
307359
  if (!renderResult.success) {
307074
- await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307360
+ await rm10(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307075
307361
  });
307076
307362
  return { success: false, error: renderResult.error };
307077
307363
  }
307078
307364
  }
307079
- await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307365
+ await rm10(tmpAudioDir, { recursive: true, force: true }).catch(() => {
307080
307366
  });
307081
307367
  return {
307082
307368
  success: true,
@@ -307485,7 +307771,7 @@ var editImageTool = defineTool({
307485
307771
  imagePaths: z5.array(z5.string()).describe("Input image file path(s)"),
307486
307772
  prompt: z5.string().describe("Edit instruction"),
307487
307773
  output: z5.string().optional().describe("Output file path (default: edited.png)"),
307488
- model: z5.enum(["flash", "3.1-flash", "latest", "pro"]).optional().describe("Gemini model (default: flash)"),
307774
+ model: z5.enum(["flash", "3.1-flash", "latest", "lite", "pro"]).optional().describe("Gemini model (default: flash = Nano Banana 2)"),
307489
307775
  ratio: z5.string().optional().describe("Output aspect ratio"),
307490
307776
  resolution: z5.string().optional().describe("Resolution: 1K, 2K, 4K (Pro only)")
307491
307777
  }),
@@ -309338,7 +309624,7 @@ var generateSoundEffectTool = defineTool({
309338
309624
  schema: z7.object({
309339
309625
  prompt: z7.string().describe("Description of the sound effect"),
309340
309626
  output: z7.string().optional().describe("Output audio file path (default: sound-effect.mp3)"),
309341
- duration: z7.number().optional().describe("Duration in seconds (0.5-22, default: auto)"),
309627
+ duration: z7.number().optional().describe("Duration in seconds (0.5-30, default: auto)"),
309342
309628
  promptInfluence: z7.number().optional().describe("Prompt influence 0-1 (default: 0.3)")
309343
309629
  }),
309344
309630
  async execute(args) {
@@ -309415,7 +309701,7 @@ var generateImageTool = defineTool({
309415
309701
  ratio: z7.string().optional().describe("Aspect ratio for Gemini (1:1, 16:9, 9:16, 4:3, 3:4, etc.)"),
309416
309702
  quality: z7.string().optional().describe("Quality for OpenAI: standard, hd"),
309417
309703
  count: z7.number().optional().describe("Number of images (default: 1)"),
309418
- model: z7.string().optional().describe("Gemini model: flash, 3.1-flash, latest, pro")
309704
+ model: z7.string().optional().describe("Image model. Gemini: flash (default), lite, pro. OpenAI: 2.5 (default), flare, 2, 1.5. Grok: pro")
309419
309705
  }),
309420
309706
  async execute(args) {
309421
309707
  const result = await executeImageGenerate(args);
@@ -309478,9 +309764,11 @@ var generateVideoTool = defineTool({
309478
309764
  mode: z7.string().optional().describe("Kling mode: std or pro"),
309479
309765
  negative: z7.string().optional().describe("Negative prompt (Seedance/Kling/Veo)"),
309480
309766
  resolution: z7.string().optional().describe("Resolution: 480p, 720p, 1080p, or 4k depending on provider"),
309481
- veoModel: z7.string().optional().describe("Veo model: 3.0, 3.1, 3.1-fast"),
309767
+ veoModel: z7.string().optional().describe("Veo model: 3.1, 3.1-fast"),
309482
309768
  runwayModel: z7.string().optional().describe("Runway model: gen4.5, gen4_turbo"),
309483
- seedanceModel: z7.string().optional().describe("Seedance variant: quality or fast (fal.ai only)"),
309769
+ seedanceModel: z7.string().optional().describe("Seedance variant: quality (2.0), fast, or 2.5 (fal.ai only)"),
309770
+ grokModel: z7.string().optional().describe("Grok video model: 1.5 (default), lite, classic"),
309771
+ klingModel: z7.string().optional().describe("Kling model: v3 (default), v2.6, v2.5-turbo"),
309484
309772
  generateAudio: z7.boolean().optional().describe("Generate native synchronized audio when supported"),
309485
309773
  output: z7.string().optional().describe("Output file path (downloads video)"),
309486
309774
  wait: z7.boolean().optional().describe("Wait for completion (default: true)")
@@ -309552,7 +309840,7 @@ var generateVideoExtendTool = defineTool({
309552
309840
  prompt: z7.string().optional().describe("Continuation prompt"),
309553
309841
  duration: z7.number().optional().describe("Duration in seconds"),
309554
309842
  negative: z7.string().optional().describe("Negative prompt (Kling)"),
309555
- veoModel: z7.string().optional().describe("Veo model: 3.0, 3.1, 3.1-fast"),
309843
+ veoModel: z7.string().optional().describe("Veo model: 3.1, 3.1-fast"),
309556
309844
  output: z7.string().optional().describe("Output file path"),
309557
309845
  wait: z7.boolean().optional().describe("Wait for completion (default: true)")
309558
309846
  }),
@@ -309588,7 +309876,7 @@ var generateTools = [
309588
309876
 
309589
309877
  // ../cli/src/tools/manifest/storyboard.ts
309590
309878
  import { existsSync as existsSync81 } from "node:fs";
309591
- import { readFile as readFile38, writeFile as writeFile43 } from "node:fs/promises";
309879
+ import { readFile as readFile38, writeFile as writeFile42 } from "node:fs/promises";
309592
309880
  import { resolve as resolve70 } from "node:path";
309593
309881
  import { z as z9 } from "zod";
309594
309882
  init_storyboard_parse();
@@ -309596,7 +309884,7 @@ init_storyboard_edit();
309596
309884
 
309597
309885
  // ../cli/src/commands/_shared/storyboard-revise.ts
309598
309886
  import { existsSync as existsSync80 } from "node:fs";
309599
- import { readFile as readFile37, writeFile as writeFile42 } from "node:fs/promises";
309887
+ import { readFile as readFile37, writeFile as writeFile41 } from "node:fs/promises";
309600
309888
  import { join as join74, resolve as resolve69 } from "node:path";
309601
309889
 
309602
309890
  // ../cli/src/agent/adapters/index.ts
@@ -309765,7 +310053,7 @@ async function executeStoryboardRevision(opts) {
309765
310053
  if (loaded.layout === "bundle") {
309766
310054
  await rewriteBundleFromMarkdown(projectDir, storyboardMd);
309767
310055
  } else {
309768
- await writeFile42(storyboardPath, storyboardMd, "utf-8");
310056
+ await writeFile41(storyboardPath, storyboardMd, "utf-8");
309769
310057
  }
309770
310058
  }
309771
310059
  const changedBeats = unique5([...diffChangedBeats(currentStoryboard, storyboardMd), ...payload.changedBeats]);
@@ -309943,6 +310231,7 @@ function stripUndefined4(value) {
309943
310231
 
309944
310232
  // ../cli/src/tools/manifest/storyboard.ts
309945
310233
  init_build_plan();
310234
+ init_build_video_providers();
309946
310235
  var PROJECT_DIR_DESCRIPTION3 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
309947
310236
  var projectDirSchema = z9.object({
309948
310237
  projectDir: z9.string().optional().describe(PROJECT_DIR_DESCRIPTION3)
@@ -310063,7 +310352,7 @@ var storyboardSetTool = defineTool({
310063
310352
  value,
310064
310353
  unset: args.unset
310065
310354
  });
310066
- await writeFile43(file.path, next, "utf-8");
310355
+ await writeFile42(file.path, next, "utf-8");
310067
310356
  return {
310068
310357
  success: true,
310069
310358
  data: { beat: args.beat, key: args.key },
@@ -310095,7 +310384,7 @@ var storyboardMoveTool = defineTool({
310095
310384
  beatId: args.beat,
310096
310385
  afterBeatId: args.after
310097
310386
  });
310098
- await writeFile43(file.path, next, "utf-8");
310387
+ await writeFile42(file.path, next, "utf-8");
310099
310388
  return {
310100
310389
  success: true,
310101
310390
  data: { beat: args.beat, after: args.after },
@@ -310160,7 +310449,7 @@ var planTool = defineTool({
310160
310449
  imageProvider: z9.string().optional().describe("Image provider override."),
310161
310450
  imageQuality: z9.enum(["standard", "hd"]).optional().describe("Image quality override."),
310162
310451
  imageSize: z9.string().optional().describe("Image size override."),
310163
- videoProvider: z9.enum(["seedance", "grok", "kling", "runway", "veo"]).optional().describe("Video provider override."),
310452
+ videoProvider: z9.enum(BUILD_VIDEO_PROVIDERS).optional().describe("Video provider override."),
310164
310453
  musicProvider: z9.enum(["elevenlabs", "replicate"]).optional().describe("Music provider override."),
310165
310454
  composer: z9.enum(["claude", "openai", "gemini"]).optional().describe("Composer provider override."),
310166
310455
  force: z9.boolean().optional().describe("Plan regeneration even when outputs exist.")
@@ -310249,14 +310538,14 @@ var designValidateTool = defineTool({
310249
310538
  var designTools = [designValidateTool];
310250
310539
 
310251
310540
  // ../cli/src/tools/manifest/remix.ts
310252
- import { writeFile as writeFile47 } from "node:fs/promises";
310541
+ import { writeFile as writeFile46 } from "node:fs/promises";
310253
310542
  import { tmpdir as tmpdir12 } from "node:os";
310254
310543
  import { join as join76 } from "node:path";
310255
310544
  import { z as z11 } from "zod";
310256
310545
 
310257
310546
  // ../cli/src/commands/ai-highlights.ts
310258
- import { readFile as readFile40, writeFile as writeFile44, mkdir as mkdir28 } from "node:fs/promises";
310259
- import { resolve as resolve73, dirname as dirname40, basename as basename19, extname as extname18 } from "node:path";
310547
+ import { readFile as readFile40, writeFile as writeFile43, mkdir as mkdir29 } from "node:fs/promises";
310548
+ import { resolve as resolve73, dirname as dirname40, basename as basename19, extname as extname19 } from "node:path";
310260
310549
  import { existsSync as existsSync83 } from "node:fs";
310261
310550
  init_dist();
310262
310551
  init_engine();
@@ -310291,7 +310580,7 @@ async function executeHighlights(options) {
310291
310580
  if (!existsSync83(absPath)) {
310292
310581
  return { success: false, highlights: [], totalDuration: 0, totalHighlightDuration: 0, error: `File not found: ${absPath}` };
310293
310582
  }
310294
- const ext = extname18(absPath).toLowerCase();
310583
+ const ext = extname19(absPath).toLowerCase();
310295
310584
  const videoExtensions = [".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"];
310296
310585
  const isVideo = videoExtensions.includes(ext);
310297
310586
  const targetDuration = options.duration;
@@ -310436,7 +310725,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
310436
310725
  };
310437
310726
  if (options.output) {
310438
310727
  const outputPath = resolve73(process.cwd(), options.output);
310439
- await writeFile44(outputPath, JSON.stringify({
310728
+ await writeFile43(outputPath, JSON.stringify({
310440
310729
  sourceFile: absPath,
310441
310730
  totalDuration: sourceDuration,
310442
310731
  criteria: options.criteria || "all",
@@ -310471,7 +310760,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
310471
310760
  }
310472
310761
  }
310473
310762
  const projectPath = resolve73(process.cwd(), options.project);
310474
- await writeFile44(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
310763
+ await writeFile43(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
310475
310764
  extractResult.projectPath = projectPath;
310476
310765
  }
310477
310766
  return extractResult;
@@ -310620,7 +310909,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
310620
310909
  }
310621
310910
  const outputDir = options.outputDir ? resolve73(process.cwd(), options.outputDir) : dirname40(absPath);
310622
310911
  if (options.outputDir && !existsSync83(outputDir)) {
310623
- await mkdir28(outputDir, { recursive: true });
310912
+ await mkdir29(outputDir, { recursive: true });
310624
310913
  }
310625
310914
  const result = {
310626
310915
  success: true,
@@ -310628,7 +310917,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
310628
310917
  };
310629
310918
  for (let i3 = 0; i3 < selectedHighlights.length; i3++) {
310630
310919
  const h2 = selectedHighlights[i3];
310631
- const baseName = basename19(absPath, extname18(absPath));
310920
+ const baseName = basename19(absPath, extname19(absPath));
310632
310921
  const outputPath = resolve73(outputDir, `${baseName}-short-${i3 + 1}.mp4`);
310633
310922
  const { stdout: probeOut } = await execSafe("ffprobe", [
310634
310923
  "-v",
@@ -310698,7 +310987,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
310698
310987
  // ../cli/src/pipeline/executor.ts
310699
310988
  var import_yaml8 = __toESM(require_dist3(), 1);
310700
310989
  import { resolve as resolve75 } from "node:path";
310701
- import { readFile as readFile42, writeFile as writeFile46, mkdir as mkdir29 } from "node:fs/promises";
310990
+ import { readFile as readFile42, writeFile as writeFile45, mkdir as mkdir30 } from "node:fs/promises";
310702
310991
  import { existsSync as existsSync84 } from "node:fs";
310703
310992
 
310704
310993
  // ../cli/src/pipeline/resolver.ts
@@ -310760,6 +311049,7 @@ function findUnresolvedRefs(params, availableStepIds) {
310760
311049
  init_output();
310761
311050
  init_config();
310762
311051
  init_provider_resolver();
311052
+ init_build_video_providers();
310763
311053
  var ACTION_METADATA = {
310764
311054
  "generate-image": { id: "generate-image", title: "Generate image", category: "generate", command: "generate image", outputs: ["image"] },
310765
311055
  "generate-video": { id: "generate-video", title: "Generate video", category: "generate", command: "generate video", outputs: ["video"], requiredKeys: ["provider-dependent"] },
@@ -310833,7 +311123,7 @@ async function resolvePipelineVideoProvider(provider) {
310833
311123
  if (explicit === "fal") return "seedance";
310834
311124
  if (explicit) return explicit;
310835
311125
  await loadProviderDefaults();
310836
- return resolveProvider("video")?.name ?? "grok";
311126
+ return resolveBuildVideoProvider(resolveProvider("video")?.name ?? "grok");
310837
311127
  }
310838
311128
  function providerKeyForImage(provider) {
310839
311129
  switch (provider) {
@@ -310859,6 +311149,7 @@ function providerKeyForVideo(provider) {
310859
311149
  case "runway":
310860
311150
  return "runway";
310861
311151
  case "veo":
311152
+ case "omni":
310862
311153
  return "google";
310863
311154
  default:
310864
311155
  return void 0;
@@ -311110,7 +311401,7 @@ var CHECKPOINT_FILE = ".pipeline-state.yaml";
311110
311401
  async function executePipeline(manifest2, options = {}) {
311111
311402
  await ensureActionsRegistered();
311112
311403
  const outputDir = resolve75(process.cwd(), options.outputDir || `${manifest2.name}-output`);
311113
- await mkdir29(outputDir, { recursive: true });
311404
+ await mkdir30(outputDir, { recursive: true });
311114
311405
  const completedSteps = /* @__PURE__ */ new Map();
311115
311406
  const results = [];
311116
311407
  const startTime = Date.now();
@@ -311235,7 +311526,7 @@ async function executePipeline(manifest2, options = {}) {
311235
311526
  data: s2.data
311236
311527
  }))
311237
311528
  };
311238
- await writeFile46(
311529
+ await writeFile45(
311239
311530
  resolve75(outputDir, CHECKPOINT_FILE),
311240
311531
  (0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
311241
311532
  "utf-8"
@@ -311390,7 +311681,7 @@ var pipelineRunTool = defineTool({
311390
311681
  let tempPath;
311391
311682
  if (args.pipelineYaml) {
311392
311683
  tempPath = join76(tmpdir12(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
311393
- await writeFile47(tempPath, args.pipelineYaml, "utf-8");
311684
+ await writeFile46(tempPath, args.pipelineYaml, "utf-8");
311394
311685
  resolvedPath = tempPath;
311395
311686
  }
311396
311687
  try {
@@ -311527,7 +311818,7 @@ var detectTools = [
311527
311818
 
311528
311819
  // ../cli/src/tools/manifest/timeline.ts
311529
311820
  import { z as z13 } from "zod";
311530
- import { mkdir as mkdir30, writeFile as writeFile49 } from "node:fs/promises";
311821
+ import { mkdir as mkdir31, writeFile as writeFile48 } from "node:fs/promises";
311531
311822
  import { basename as basename21, resolve as resolve76 } from "node:path";
311532
311823
  init_engine();
311533
311824
  init_project_resolver();
@@ -311535,7 +311826,7 @@ init_project_resolver();
311535
311826
  // ../cli/src/tools/manifest/_project-io.ts
311536
311827
  init_engine();
311537
311828
  init_project_resolver();
311538
- import { readFile as readFile43, writeFile as writeFile48 } from "node:fs/promises";
311829
+ import { readFile as readFile43, writeFile as writeFile47 } from "node:fs/promises";
311539
311830
  async function loadProject(projectPath, cwd) {
311540
311831
  const absPath = await resolveTimelineFile(projectPath, cwd);
311541
311832
  const content = await readFile43(absPath, "utf-8");
@@ -311543,7 +311834,7 @@ async function loadProject(projectPath, cwd) {
311543
311834
  return { project: Project.fromJSON(data2), absPath };
311544
311835
  }
311545
311836
  async function saveProject(absPath, project) {
311546
- await writeFile48(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
311837
+ await writeFile47(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
311547
311838
  }
311548
311839
 
311549
311840
  // ../cli/src/tools/manifest/timeline.ts
@@ -311583,10 +311874,10 @@ var timelineCreateTool = defineTool({
311583
311874
  outputPath = resolve76(ctx.workingDirectory, args.outputPath);
311584
311875
  } else {
311585
311876
  const dirPath = resolve76(ctx.workingDirectory, args.name);
311586
- await mkdir30(dirPath, { recursive: true });
311877
+ await mkdir31(dirPath, { recursive: true });
311587
311878
  outputPath = resolve76(dirPath, TIMELINE_FILENAME);
311588
311879
  }
311589
- await writeFile49(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
311880
+ await writeFile48(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
311590
311881
  return {
311591
311882
  success: true,
311592
311883
  data: { name: projectName, outputPath },
@@ -311884,7 +312175,7 @@ var timelineTools = [
311884
312175
  // ../cli/src/tools/manifest/project.ts
311885
312176
  import { z as z14 } from "zod";
311886
312177
  import { resolve as resolve78 } from "node:path";
311887
- import { writeFile as writeFile50 } from "node:fs/promises";
312178
+ import { writeFile as writeFile49 } from "node:fs/promises";
311888
312179
  init_engine();
311889
312180
 
311890
312181
  // ../cli/src/commands/_shared/project-list.ts
@@ -312042,7 +312333,7 @@ var projectCreateTool = defineTool({
312042
312333
  const outputPath = resolve78(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
312043
312334
  const project = new Project(args.name);
312044
312335
  if (args.fps) project.setFrameRate(args.fps);
312045
- await writeFile50(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
312336
+ await writeFile49(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
312046
312337
  return {
312047
312338
  success: true,
312048
312339
  data: { name: args.name, outputPath },
@@ -312763,8 +313054,8 @@ var exportVideoTool = defineTool({
312763
313054
  var exportTools = [exportVideoTool];
312764
313055
 
312765
313056
  // ../cli/src/tools/manifest/agent-only.ts
312766
- import { readFile as readFile46, writeFile as writeFile51, readdir as readdir11, stat as stat10, access as access7, unlink as unlink5 } from "node:fs/promises";
312767
- import { resolve as resolve81, join as join78, basename as basename23, extname as extname19 } from "node:path";
313057
+ import { readFile as readFile46, writeFile as writeFile50, readdir as readdir11, stat as stat10, access as access7, unlink as unlink5 } from "node:fs/promises";
313058
+ import { resolve as resolve81, join as join78, basename as basename23, extname as extname20 } from "node:path";
312768
313059
  import { z as z16 } from "zod";
312769
313060
  init_engine();
312770
313061
  init_exec_safe();
@@ -312787,7 +313078,7 @@ function formatSize(bytes) {
312787
313078
  return `${size.toFixed(1)}${units2[unit]}`;
312788
313079
  }
312789
313080
  function detectMediaType(filePath) {
312790
- const ext = extname19(filePath).toLowerCase();
313081
+ const ext = extname20(filePath).toLowerCase();
312791
313082
  if ([".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"].includes(ext)) return "video";
312792
313083
  if ([".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a"].includes(ext)) return "audio";
312793
313084
  if ([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"].includes(ext)) return "image";
@@ -312814,7 +313105,7 @@ function isMediaFile(filePath) {
312814
313105
  ".webp",
312815
313106
  ".bmp"
312816
313107
  ];
312817
- return mediaExts.includes(extname19(filePath).toLowerCase());
313108
+ return mediaExts.includes(extname20(filePath).toLowerCase());
312818
313109
  }
312819
313110
  async function getMediaDuration2(filePath) {
312820
313111
  try {
@@ -312897,7 +313188,7 @@ var fsWriteTool = defineTool({
312897
313188
  async execute(args, ctx) {
312898
313189
  try {
312899
313190
  const absPath = resolve81(ctx.workingDirectory, args.path);
312900
- await writeFile51(absPath, args.content, "utf-8");
313191
+ await writeFile50(absPath, args.content, "utf-8");
312901
313192
  return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
312902
313193
  } catch (error) {
312903
313194
  return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
@@ -312960,7 +313251,7 @@ var batchImportTool = defineTool({
312960
313251
  if (entry.isDirectory() && recursive) {
312961
313252
  await scanDir(entryPath);
312962
313253
  } else if (entry.isFile()) {
312963
- const ext = extname19(entry.name).toLowerCase();
313254
+ const ext = extname20(entry.name).toLowerCase();
312964
313255
  const matchesFilter = !filterExts || filterExts.includes(ext);
312965
313256
  if (matchesFilter && isMediaFile(entryPath)) mediaFiles.push(entryPath);
312966
313257
  }
@@ -312983,7 +313274,7 @@ var batchImportTool = defineTool({
312983
313274
  const source3 = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
312984
313275
  addedSources.push({ id: source3.id, name: mediaName, type: mediaType });
312985
313276
  }
312986
- await writeFile51(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313277
+ await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
312987
313278
  return {
312988
313279
  success: true,
312989
313280
  data: { count: addedSources.length, sources: addedSources },
@@ -313053,7 +313344,7 @@ var batchConcatTool = defineTool({
313053
313344
  createdClips.push({ id: clip.id, sourceName: source3.name, startTime: currentTime, duration: source3.duration });
313054
313345
  currentTime += source3.duration + gap;
313055
313346
  }
313056
- await writeFile51(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313347
+ await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313057
313348
  const totalDuration = currentTime - gap - startTime;
313058
313349
  return {
313059
313350
  success: true,
@@ -313116,7 +313407,7 @@ var batchApplyEffectTool = defineTool({
313116
313407
  });
313117
313408
  if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
313118
313409
  }
313119
- await writeFile51(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313410
+ await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313120
313411
  return {
313121
313412
  success: true,
313122
313413
  data: { applied: appliedEffects.length, effectType: args.effectType },
@@ -313185,7 +313476,7 @@ var timelineClearTool = defineTool({
313185
313476
  removed.sources++;
313186
313477
  }
313187
313478
  }
313188
- await writeFile51(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313479
+ await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313189
313480
  const parts = [];
313190
313481
  if (removed.clips > 0) parts.push(`${removed.clips} clips`);
313191
313482
  if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
@@ -313236,7 +313527,7 @@ var projectSetTool = defineTool({
313236
313527
  project.setFrameRate(args.fps);
313237
313528
  updates.push(`Frame Rate: ${args.fps} fps`);
313238
313529
  }
313239
- await writeFile51(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313530
+ await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
313240
313531
  return {
313241
313532
  success: true,
313242
313533
  data: { updates },
@@ -313606,7 +313897,7 @@ var mediaConcatTool = defineTool({
313606
313897
  } else {
313607
313898
  const tempList = resolve81(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
313608
313899
  const listContent = args.inputs.map((i3) => `file '${resolve81(ctx.workingDirectory, i3)}'`).join("\n");
313609
- await writeFile51(tempList, listContent, "utf-8");
313900
+ await writeFile50(tempList, listContent, "utf-8");
313610
313901
  try {
313611
313902
  await execSafe(
313612
313903
  "ffmpeg",
@@ -315058,7 +315349,7 @@ function handleCliFlags(argv, version2) {
315058
315349
  }
315059
315350
 
315060
315351
  // src/index.ts
315061
- if (handleCliFlags(process.argv.slice(2), "0.115.2")) {
315352
+ if (handleCliFlags(process.argv.slice(2), "0.115.3")) {
315062
315353
  process.exit(0);
315063
315354
  }
315064
315355
  console.log = (...args) => console.error(...args);
@@ -315071,7 +315362,7 @@ var server = new Server(
315071
315362
  {
315072
315363
  name: "vibeframe",
315073
315364
  // Stamped with the package version by build.js at bundle time.
315074
- version: "0.115.2"
315365
+ version: "0.115.3"
315075
315366
  },
315076
315367
  {
315077
315368
  capabilities: {