@vibeframe/cli 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.
- package/dist/agent/adapters/gemini.d.ts +2 -0
- package/dist/agent/adapters/provider-content.test.d.ts +6 -0
- package/dist/agent/memory/index.d.ts +1 -1
- package/dist/agent/types.d.ts +8 -0
- package/dist/commands/_shared/build-video-providers.d.ts +12 -0
- package/dist/commands/_shared/build-video-providers.test.d.ts +1 -0
- package/dist/commands/_shared/edit/translate-srt.test.d.ts +1 -0
- package/dist/commands/_shared/openai-image.d.ts +7 -7
- package/dist/commands/_shared/project-config.d.ts +2 -1
- package/dist/commands/_shared/scene-build.d.ts +3 -2
- package/dist/commands/ai-video.d.ts +2 -0
- package/dist/commands/generate/image.d.ts +1 -1
- package/dist/commands/generate/video.d.ts +1 -10
- package/dist/config/schema.d.ts +1 -1
- package/dist/index.js +1003 -709
- package/dist/tools/manifest/edit.d.ts +3 -3
- package/dist/tools/manifest/generate.d.ts +8 -2
- package/dist/tools/manifest/index.js +943 -652
- package/dist/tools/manifest/scene.d.ts +3 -3
- package/dist/tools/manifest/storyboard.d.ts +3 -3
- package/dist/utils/image-file.d.ts +19 -0
- package/dist/utils/image-file.test.d.ts +1 -0
- package/package.json +3 -3
|
@@ -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 (
|
|
195
|
-
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2
|
|
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: ["
|
|
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.
|
|
462
|
-
GEMINI_AGENT_DEFAULT_TEXT_MODEL =
|
|
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.
|
|
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-
|
|
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.
|
|
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: {
|
|
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.
|
|
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-
|
|
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
|
-
|
|
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-
|
|
1016
|
-
"3.1-flash": "gemini-3.1-flash-image
|
|
1017
|
-
"latest": "gemini-3.1-flash-image
|
|
1018
|
-
"
|
|
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
|
|
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
|
|
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
|
|
1847
|
-
const
|
|
1848
|
-
|
|
1849
|
-
return refs[0];
|
|
1850
|
-
const ref = options.referenceImage;
|
|
1851
|
-
if (typeof ref === "string" && ref) {
|
|
1858
|
+
function frameImages(options) {
|
|
1859
|
+
const frames = [];
|
|
1860
|
+
const toInline = (ref) => {
|
|
1852
1861
|
const m = ref.match(/^data:(.+?);base64,(.*)$/);
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1862
|
+
return m ? { mimeType: m[1], base64: m[2] } : { mimeType: "image/png", base64: ref };
|
|
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));
|
|
1868
|
+
}
|
|
1869
|
+
if (frames.length > 0 && options.lastFrame)
|
|
1870
|
+
frames.push(toInline(options.lastFrame));
|
|
1871
|
+
return frames;
|
|
1872
|
+
}
|
|
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((c) => c.type === "video");
|
|
1878
|
+
if (video)
|
|
1879
|
+
return video;
|
|
1856
1880
|
}
|
|
1857
|
-
return
|
|
1881
|
+
return response.output_video;
|
|
1858
1882
|
}
|
|
1859
|
-
function
|
|
1860
|
-
|
|
1861
|
-
return void 0;
|
|
1862
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
1863
|
-
if (typeof v === "string" && /^https?:\/\//.test(v) && /(uri|url|video)/i.test(k))
|
|
1864
|
-
return v;
|
|
1865
|
-
if (typeof v === "object") {
|
|
1866
|
-
const nested = findVideoUrl(v);
|
|
1867
|
-
if (nested)
|
|
1868
|
-
return nested;
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
return void 0;
|
|
1883
|
+
function fileIdFromUri(uri) {
|
|
1884
|
+
return uri.match(/files\/([^/?:]+)/)?.[1];
|
|
1872
1885
|
}
|
|
1873
|
-
var OMNI_MODEL,
|
|
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
|
-
|
|
1878
|
-
|
|
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
|
|
1898
|
+
this.label = "Gemini Omni 1.1 Flash";
|
|
1883
1899
|
}
|
|
1884
1900
|
async initialize(config2) {
|
|
1885
1901
|
this.apiKey = config2.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
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
inputs.push({ inline_data: { mime_type: image.mimeType, data: image.base64 } });
|
|
1901
|
-
}
|
|
1911
|
+
const frames = frameImages(opts);
|
|
1912
|
+
const input = frames.length === 0 ? prompt3 : [
|
|
1913
|
+
...frames.map((f) => ({ type: "image", data: f.base64, mime_type: f.mimeType })),
|
|
1914
|
+
{ type: "text", text: prompt3 }
|
|
1915
|
+
];
|
|
1902
1916
|
const body = {
|
|
1903
1917
|
model: OMNI_MODEL,
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1918
|
+
input,
|
|
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(
|
|
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
|
|
1937
|
+
error: `Gemini Omni request failed: HTTP ${res.status} - ${text.slice(0, 300)}`
|
|
1921
1938
|
};
|
|
1922
1939
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
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
|
|
1930
|
-
|
|
1931
|
-
|
|
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}` };
|
|
1937
1950
|
}
|
|
1938
|
-
|
|
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}` };
|
|
1954
|
+
}
|
|
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
|
|
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:
|
|
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
|
|
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
|
-
|
|
2012
|
-
|
|
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(config2) {
|
|
2072
2109
|
this.apiKey = config2.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
|
-
|
|
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
|
|
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
|
-
|
|
2459
|
-
|
|
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 match = text.match(/\[[\s\S]*\]/);
|
|
2481
2520
|
return match ? match[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-
|
|
3822
|
+
this.model = "claude-sonnet-5-5";
|
|
3770
3823
|
}
|
|
3771
3824
|
async initialize(config2) {
|
|
3772
3825
|
this.apiKey = config2.apiKey;
|
|
@@ -3870,7 +3923,7 @@ Or if clarification needed:
|
|
|
3870
3923
|
},
|
|
3871
3924
|
body: JSON.stringify({
|
|
3872
3925
|
model: this.model,
|
|
3873
|
-
max_tokens:
|
|
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:
|
|
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-
|
|
4073
|
-
opus: "claude-opus-
|
|
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(input) {
|
|
|
4408
4461
|
const availableVoices = Object.keys(KNOWN_VOICES).join(", ");
|
|
4409
4462
|
throw new Error(`Unknown voice "${input}". 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
|
-
|
|
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(
|
|
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:
|
|
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((p) => p.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 last = chunks.at(-1);
|
|
4933
|
+
if (last !== void 0 && last.length + unit.length + 1 <= maxChars) {
|
|
4934
|
+
chunks[chunks.length - 1] = `${last} ${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 (!base)
|
|
4891
4995
|
return null;
|
|
4892
4996
|
try {
|
|
4893
|
-
const { readFile: readFile44, writeFile:
|
|
4997
|
+
const { readFile: readFile44, writeFile: writeFile47, mkdir: mkdir27 } = await import("node:fs/promises");
|
|
4894
4998
|
const { join: join29, resolve: resolve65 } = await import("node:path");
|
|
4895
4999
|
const { pathToFileURL } = await import("node:url");
|
|
4896
5000
|
const { homedir: homedir5 } = await import("node:os");
|
|
@@ -4911,8 +5015,8 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4911
5015
|
async put(key, response) {
|
|
4912
5016
|
try {
|
|
4913
5017
|
const buf = Buffer.from(await response.arrayBuffer());
|
|
4914
|
-
await
|
|
4915
|
-
await
|
|
5018
|
+
await mkdir27(cacheRoot, { recursive: true });
|
|
5019
|
+
await writeFile47(join29(cacheRoot, encodeURIComponent(String(key))), buf);
|
|
4916
5020
|
} catch {
|
|
4917
5021
|
}
|
|
4918
5022
|
}
|
|
@@ -4961,12 +5065,13 @@ function normaliseEvent(raw) {
|
|
|
4961
5065
|
total: typeof r.total === "number" ? r.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
|
|
5101
|
+
const voiceOptions = {
|
|
4997
5102
|
voice: options.voice ?? KOKORO_DEFAULT_VOICE,
|
|
4998
5103
|
speed: options.speed ?? 1
|
|
4999
|
-
}
|
|
5000
|
-
const
|
|
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((n, part) => n + 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
|
-
|
|
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
|
|
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
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
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 data = await response.json();
|
|
5277
|
-
return {
|
|
5278
|
-
success: true,
|
|
5279
|
-
images: data.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 key = (alias ?? "v3").trim().toLowerCase();
|
|
5796
|
+
const aliases = {
|
|
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(aliases, key))
|
|
5806
|
+
return aliases[key];
|
|
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-
|
|
5723
|
-
STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3"
|
|
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(config2) {
|
|
5736
5833
|
if (config2.apiKey) {
|
|
5737
5834
|
const parts = config2.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.
|
|
5839
|
+
this.apiKey = config2.apiKey;
|
|
5743
5840
|
}
|
|
5744
5841
|
}
|
|
5745
5842
|
if (config2.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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
6257
|
+
function resolveGrokVideoModel(alias) {
|
|
6258
|
+
const key = (alias ?? "1.5").trim().toLowerCase();
|
|
6259
|
+
const aliases = {
|
|
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(aliases, key))
|
|
6269
|
+
return aliases[key];
|
|
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[data.status] || "pending",
|
|
6398
6529
|
videoUrl: data.video?.url,
|
|
6399
|
-
error: data.status === "expired" ? "Generation expired" : void 0
|
|
6530
|
+
error: data.status === "expired" ? "Generation expired" : data.status === "failed" ? `Generation failed: ${data.error?.message ?? data.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 key = (alias ?? "quality").trim().toLowerCase();
|
|
10726
|
+
const aliases = {
|
|
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(aliases, key))
|
|
10736
|
+
return aliases[key];
|
|
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 [a, b] = (opts.aspectRatio ?? "16:9").split(":").map(Number);
|
|
10596
10742
|
const ratioFactor = a > 0 && b > 0 ? Math.max(a, b) / Math.min(a, b) : 16 / 9;
|
|
10597
10743
|
const longSide = Math.round(shortSide * ratioFactor);
|
|
10598
10744
|
const tokensPerSecond = shortSide * longSide * 24 / 1024;
|
|
10599
|
-
|
|
10600
|
-
|
|
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(
|
|
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 input = {
|
|
10792
10947
|
prompt: prompt3,
|
|
10793
10948
|
aspect_ratio: aspect,
|
|
@@ -10805,10 +10960,12 @@ var init_FalProvider = __esm({
|
|
|
10805
10960
|
} else if (referenceImage) {
|
|
10806
10961
|
input.image_url = referenceImage;
|
|
10807
10962
|
}
|
|
10808
|
-
if (
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10963
|
+
if (variant !== "seedance-2.5") {
|
|
10964
|
+
if (options?.negativePrompt)
|
|
10965
|
+
input.negative_prompt = options.negativePrompt;
|
|
10966
|
+
if (typeof options?.seed === "number")
|
|
10967
|
+
input.seed = options.seed;
|
|
10968
|
+
}
|
|
10812
10969
|
if (typeof options?.generateAudio === "boolean")
|
|
10813
10970
|
input.generate_audio = options.generateAudio;
|
|
10814
10971
|
if (options?.endUserId)
|
|
@@ -11535,6 +11692,7 @@ var init_replicate = __esm({
|
|
|
11535
11692
|
var dist_exports2 = {};
|
|
11536
11693
|
__export(dist_exports2, {
|
|
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_exports2, {
|
|
|
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_exports2, {
|
|
|
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_exports2, {
|
|
|
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_exports2, {
|
|
|
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(output, buffer) {
|
|
20825
|
+
const outputPath = resolve3(process.cwd(), output);
|
|
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,
|
|
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
|
|
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 (output && result.videoUrl) {
|
|
20744
20918
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
20745
|
-
outputPath =
|
|
20746
|
-
await writeFile3(outputPath, buffer);
|
|
20919
|
+
outputPath = await saveOutput(output, 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 (output && finalResult.videoUrl) {
|
|
20776
20949
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20777
|
-
outputPath =
|
|
20778
|
-
await writeFile3(outputPath, buffer);
|
|
20950
|
+
outputPath = await saveOutput(output, 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 (output && finalResult.videoUrl) {
|
|
20821
20994
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20822
|
-
outputPath =
|
|
20823
|
-
await writeFile3(outputPath, buffer);
|
|
20995
|
+
outputPath = await saveOutput(output, 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: key });
|
|
20837
|
-
const
|
|
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 (output && finalResult.videoUrl) {
|
|
20862
21029
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20863
|
-
outputPath =
|
|
20864
|
-
await writeFile3(outputPath, buffer);
|
|
21030
|
+
outputPath = await saveOutput(output, buffer);
|
|
20865
21031
|
}
|
|
20866
21032
|
return {
|
|
20867
21033
|
success: true,
|
|
@@ -20876,9 +21042,12 @@ async function executeVideoGenerate(options) {
|
|
|
20876
21042
|
await grok.initialize({ apiKey: key });
|
|
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 (output && finalResult.videoUrl) {
|
|
20893
21062
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
20894
|
-
outputPath =
|
|
20895
|
-
await writeFile3(outputPath, buffer);
|
|
21063
|
+
outputPath = await saveOutput(output, 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 (output) {
|
|
20919
21088
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
20920
|
-
outputPath =
|
|
20921
|
-
await writeFile3(outputPath, buffer);
|
|
21089
|
+
outputPath = await saveOutput(output, 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 (output && result.videoUrl) {
|
|
21016
21184
|
const buffer = await downloadVideo(result.videoUrl);
|
|
21017
|
-
outputPath =
|
|
21018
|
-
await writeFile3(outputPath, buffer);
|
|
21185
|
+
outputPath = await saveOutput(output, 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 (output && result.videoUrl) {
|
|
21039
21206
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
21040
|
-
outputPath =
|
|
21041
|
-
await writeFile3(outputPath, buffer);
|
|
21207
|
+
outputPath = await saveOutput(output, 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 (output && result.videoUrl) {
|
|
21061
21227
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
21062
|
-
outputPath =
|
|
21063
|
-
await writeFile3(outputPath, buffer);
|
|
21228
|
+
outputPath = await saveOutput(output, 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 (output && result.videoUrl) {
|
|
21084
21249
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
21085
|
-
outputPath =
|
|
21086
|
-
await writeFile3(outputPath, buffer);
|
|
21250
|
+
outputPath = await saveOutput(output, 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 (output && finalResult.videoUrl) {
|
|
21155
21319
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
21156
|
-
outputPath =
|
|
21157
|
-
await writeFile3(outputPath, buffer);
|
|
21320
|
+
outputPath = await saveOutput(output, buffer);
|
|
21158
21321
|
}
|
|
21159
21322
|
return {
|
|
21160
21323
|
success: true,
|
|
@@ -21169,12 +21332,7 @@ async function executeVideoExtend(options) {
|
|
|
21169
21332
|
if (!key) return { success: false, error: "GOOGLE_API_KEY required" };
|
|
21170
21333
|
const gemini = new GeminiProvider();
|
|
21171
21334
|
await gemini.initialize({ apiKey: key });
|
|
21172
|
-
const
|
|
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 (output && finalResult.videoUrl) {
|
|
21191
21349
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
21192
|
-
outputPath =
|
|
21193
|
-
await writeFile3(outputPath, buffer);
|
|
21350
|
+
outputPath = await saveOutput(output, buffer);
|
|
21194
21351
|
}
|
|
21195
21352
|
return {
|
|
21196
21353
|
success: true,
|
|
@@ -21252,8 +21409,8 @@ var init_music_status = __esm({
|
|
|
21252
21409
|
|
|
21253
21410
|
// src/commands/_shared/build-asset-metadata.ts
|
|
21254
21411
|
import { existsSync, readFileSync } from "node:fs";
|
|
21255
|
-
import { mkdir as
|
|
21256
|
-
import { dirname as
|
|
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(kind, beatId) {
|
|
21258
21415
|
return `.vibeframe/assets/${kind}-${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
|
|
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
|
// src/commands/_shared/storyboard-source.ts
|
|
22262
22419
|
import { existsSync as existsSync2 } from "node:fs";
|
|
22263
|
-
import { mkdir as
|
|
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)(data, { lineWidth: 0 }).trimEnd()}
|
|
|
22373
22530
|
};
|
|
22374
22531
|
}
|
|
22375
22532
|
async function writeMigration(projectDir, plan) {
|
|
22376
|
-
await
|
|
22533
|
+
await mkdir4(join3(projectDir, SCENES_DIRNAME), { recursive: true });
|
|
22377
22534
|
for (const file of plan.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
|
|
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
|
// 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
|
|
22471
|
-
import { dirname as
|
|
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 =
|
|
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 =
|
|
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
|
|
22709
|
+
await mkdir5(dir, { recursive: true });
|
|
22553
22710
|
const path2 = jobRecordPath(record.id, record.projectDir);
|
|
22554
22711
|
const tmp = `${path2}.${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 output = resolveRefreshOutput(record, opts);
|
|
22600
|
-
if (output) await
|
|
22757
|
+
if (output) await mkdir5(dirname4(output), { 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
|
|
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
|
|
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
|
// src/commands/_shared/scene-project.ts
|
|
23474
|
-
import { mkdir as
|
|
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 kind = opts.kind ?? DEFAULT_SCENE_KIND;
|
|
24086
|
-
await
|
|
24243
|
+
await mkdir6(dir, { recursive: true });
|
|
24087
24244
|
if (profile === "full") {
|
|
24088
|
-
await
|
|
24089
|
-
await
|
|
24090
|
-
await
|
|
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 = [];
|
|
@@ -31642,7 +31799,7 @@ var init_scene_audio_scan = __esm({
|
|
|
31642
31799
|
|
|
31643
31800
|
// src/commands/_shared/scene-audio-mux.ts
|
|
31644
31801
|
import { rename as rename3, unlink } from "node:fs/promises";
|
|
31645
|
-
import { resolve as resolve17, dirname as
|
|
31802
|
+
import { resolve as resolve17, dirname as dirname6, extname as extname2, basename as basename3 } from "node:path";
|
|
31646
31803
|
function buildAudioMuxFilter(audios) {
|
|
31647
31804
|
if (audios.length === 0) return null;
|
|
31648
31805
|
const labels = [];
|
|
@@ -31703,7 +31860,7 @@ async function muxAudioIntoVideo(opts) {
|
|
|
31703
31860
|
}
|
|
31704
31861
|
const ext = extname2(opts.videoPath) || `.${opts.format}`;
|
|
31705
31862
|
const tmpPath = resolve17(
|
|
31706
|
-
|
|
31863
|
+
dirname6(opts.videoPath),
|
|
31707
31864
|
`.${basename3(opts.videoPath, ext)}.muxing${ext}`
|
|
31708
31865
|
);
|
|
31709
31866
|
const args = ["-y", "-loglevel", "error", "-i", opts.videoPath];
|
|
@@ -31851,8 +32008,8 @@ __export(scene_render_exports, {
|
|
|
31851
32008
|
});
|
|
31852
32009
|
import { execFile as execFile2 } from "node:child_process";
|
|
31853
32010
|
import { existsSync as existsSync15 } from "node:fs";
|
|
31854
|
-
import { mkdir as
|
|
31855
|
-
import { resolve as resolve19, relative as relative6, dirname as
|
|
32011
|
+
import { mkdir as mkdir9, readFile as readFile16, stat as stat3, writeFile as writeFile14 } from "node:fs/promises";
|
|
32012
|
+
import { resolve as resolve19, relative as relative6, dirname as dirname7, basename as basename4, join as join13, isAbsolute as isAbsolute2 } from "node:path";
|
|
31856
32013
|
import { promisify as promisify2 } from "node:util";
|
|
31857
32014
|
import {
|
|
31858
32015
|
createRenderJob,
|
|
@@ -31905,7 +32062,7 @@ function buildMediaOpenCommand(action, filePath, platform = process.platform) {
|
|
|
31905
32062
|
display: ["cmd", ...args].map(quoteCliArg).join(" ")
|
|
31906
32063
|
};
|
|
31907
32064
|
}
|
|
31908
|
-
const target = action === "reveal" ?
|
|
32065
|
+
const target = action === "reveal" ? dirname7(filePath) : filePath;
|
|
31909
32066
|
return {
|
|
31910
32067
|
command: "xdg-open",
|
|
31911
32068
|
args: [target],
|
|
@@ -32001,7 +32158,7 @@ async function executeSceneRender(opts = {}) {
|
|
|
32001
32158
|
}
|
|
32002
32159
|
const projectName = projectConfig.config.name;
|
|
32003
32160
|
const outputPath = opts.output ? resolve19(projectDir, opts.output) : defaultOutputPath({ projectDir, projectName, format: opts.format, beatId: opts.beatId });
|
|
32004
|
-
await
|
|
32161
|
+
await mkdir9(dirname7(outputPath), { recursive: true });
|
|
32005
32162
|
const config2 = buildRenderConfig({
|
|
32006
32163
|
fps: opts.fps,
|
|
32007
32164
|
quality: opts.quality,
|
|
@@ -32197,7 +32354,7 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
32197
32354
|
durationSec,
|
|
32198
32355
|
narrationPath
|
|
32199
32356
|
});
|
|
32200
|
-
await
|
|
32357
|
+
await mkdir9(dirname7(join13(opts.projectDir, root)), { recursive: true });
|
|
32201
32358
|
await writeFile14(join13(opts.projectDir, root), html, "utf-8");
|
|
32202
32359
|
return {
|
|
32203
32360
|
success: true,
|
|
@@ -32481,7 +32638,7 @@ var init_design_parse = __esm({
|
|
|
32481
32638
|
|
|
32482
32639
|
// src/commands/_shared/compose-aivideo.ts
|
|
32483
32640
|
import { existsSync as existsSync16 } from "node:fs";
|
|
32484
|
-
import { mkdir as
|
|
32641
|
+
import { mkdir as mkdir10, readFile as readFile17, writeFile as writeFile15 } from "node:fs/promises";
|
|
32485
32642
|
import { join as join14, resolve as resolve20 } from "node:path";
|
|
32486
32643
|
function headingDescriptor(heading) {
|
|
32487
32644
|
const stripped = heading.replace(/^\s*beat\s+/i, "");
|
|
@@ -32644,7 +32801,7 @@ async function composeAiVideo(opts) {
|
|
|
32644
32801
|
}
|
|
32645
32802
|
clipRels.push(rel);
|
|
32646
32803
|
}
|
|
32647
|
-
await
|
|
32804
|
+
await mkdir10(join14(projectDir, "assets"), { recursive: true });
|
|
32648
32805
|
const bgRel = "assets/bg-full.mp4";
|
|
32649
32806
|
const concatArgs = buildBgConcatArgs(
|
|
32650
32807
|
clipRels.map((r) => join14(projectDir, r)),
|
|
@@ -32652,7 +32809,7 @@ async function composeAiVideo(opts) {
|
|
|
32652
32809
|
);
|
|
32653
32810
|
await execSafe("ffmpeg", concatArgs, { timeout: 6e5 });
|
|
32654
32811
|
const totalDurationSec = await probeDurationSec(join14(projectDir, bgRel));
|
|
32655
|
-
await
|
|
32812
|
+
await mkdir10(join14(projectDir, "compositions"), { recursive: true });
|
|
32656
32813
|
const sceneFiles = [];
|
|
32657
32814
|
for (let i = 0; i < beats.length; i++) {
|
|
32658
32815
|
const beat = beats[i];
|
|
@@ -32801,8 +32958,8 @@ var init_compose_aivideo = __esm({
|
|
|
32801
32958
|
|
|
32802
32959
|
// src/commands/_shared/footage-assemble.ts
|
|
32803
32960
|
import { existsSync as existsSync17 } from "node:fs";
|
|
32804
|
-
import { mkdir as
|
|
32805
|
-
import { dirname as
|
|
32961
|
+
import { mkdir as mkdir11, writeFile as writeFile16 } from "node:fs/promises";
|
|
32962
|
+
import { dirname as dirname8, isAbsolute as isAbsolute3, join as join15, resolve as resolve21 } from "node:path";
|
|
32806
32963
|
function planFootageTimeline(inputs, opts = {}) {
|
|
32807
32964
|
if (inputs.length === 0) {
|
|
32808
32965
|
throw new Error("No clips to assemble.");
|
|
@@ -33131,7 +33288,7 @@ async function executeFootageAssemble(opts) {
|
|
|
33131
33288
|
if (opts.dryRun) {
|
|
33132
33289
|
return { success: true, dryRun: true, outputPath, report };
|
|
33133
33290
|
}
|
|
33134
|
-
await
|
|
33291
|
+
await mkdir11(dirname8(outputPath), { recursive: true });
|
|
33135
33292
|
const args = buildFootageAssembleArgs({
|
|
33136
33293
|
sources: sourceRels.map((s) => ({ path: join15(projectDir, s.rel), kind: s.kind })),
|
|
33137
33294
|
plan,
|
|
@@ -33492,9 +33649,40 @@ var init_composer_resolve = __esm({
|
|
|
33492
33649
|
}
|
|
33493
33650
|
});
|
|
33494
33651
|
|
|
33652
|
+
// src/commands/_shared/build-video-providers.ts
|
|
33653
|
+
function isBuildVideoProvider(value) {
|
|
33654
|
+
return BUILD_VIDEO_PROVIDERS.includes(value);
|
|
33655
|
+
}
|
|
33656
|
+
function resolveBuildVideoProvider(value) {
|
|
33657
|
+
const provider = String(value ?? "seedance").toLowerCase();
|
|
33658
|
+
if (provider === "fal") return "seedance";
|
|
33659
|
+
return isBuildVideoProvider(provider) ? provider : "seedance";
|
|
33660
|
+
}
|
|
33661
|
+
function videoProviderConfigKey(provider) {
|
|
33662
|
+
switch (provider) {
|
|
33663
|
+
case "seedance":
|
|
33664
|
+
case "fal":
|
|
33665
|
+
return "fal";
|
|
33666
|
+
case "grok":
|
|
33667
|
+
return "xai";
|
|
33668
|
+
case "veo":
|
|
33669
|
+
case "omni":
|
|
33670
|
+
return "google";
|
|
33671
|
+
default:
|
|
33672
|
+
return provider;
|
|
33673
|
+
}
|
|
33674
|
+
}
|
|
33675
|
+
var BUILD_VIDEO_PROVIDERS;
|
|
33676
|
+
var init_build_video_providers = __esm({
|
|
33677
|
+
"src/commands/_shared/build-video-providers.ts"() {
|
|
33678
|
+
"use strict";
|
|
33679
|
+
BUILD_VIDEO_PROVIDERS = ["seedance", "grok", "kling", "runway", "omni", "veo"];
|
|
33680
|
+
}
|
|
33681
|
+
});
|
|
33682
|
+
|
|
33495
33683
|
// src/commands/_shared/build-plan.ts
|
|
33496
33684
|
import { existsSync as existsSync19 } from "node:fs";
|
|
33497
|
-
import { dirname as
|
|
33685
|
+
import { dirname as dirname9, join as join16, resolve as resolve23 } from "node:path";
|
|
33498
33686
|
function backdropCostUsd(quality) {
|
|
33499
33687
|
return quality === "hd" ? 0.2 : 0.05;
|
|
33500
33688
|
}
|
|
@@ -34166,12 +34354,7 @@ function normalizeImageProvider(value) {
|
|
|
34166
34354
|
return provider || "openai";
|
|
34167
34355
|
}
|
|
34168
34356
|
function normalizeVideoProvider(value) {
|
|
34169
|
-
|
|
34170
|
-
if (provider === "fal") return "seedance";
|
|
34171
|
-
if (provider === "seedance" || provider === "grok" || provider === "kling" || provider === "runway" || provider === "veo") {
|
|
34172
|
-
return provider;
|
|
34173
|
-
}
|
|
34174
|
-
return "seedance";
|
|
34357
|
+
return resolveBuildVideoProvider(value);
|
|
34175
34358
|
}
|
|
34176
34359
|
function normalizeMusicProvider(value) {
|
|
34177
34360
|
const provider = String(value ?? "elevenlabs").toLowerCase();
|
|
@@ -34183,7 +34366,7 @@ function imageConfigKey(provider) {
|
|
|
34183
34366
|
return "openai";
|
|
34184
34367
|
}
|
|
34185
34368
|
function videoConfigKey(provider) {
|
|
34186
|
-
return provider
|
|
34369
|
+
return videoProviderConfigKey(provider);
|
|
34187
34370
|
}
|
|
34188
34371
|
function composerConfigKey(provider) {
|
|
34189
34372
|
return provider === "claude" ? "anthropic" : provider === "gemini" ? "google" : "openai";
|
|
@@ -34201,12 +34384,12 @@ function loadPlanEnv(projectDir) {
|
|
|
34201
34384
|
(0, import_dotenv2.config)({ path: join16(projectDir, ".env"), quiet: true });
|
|
34202
34385
|
(0, import_dotenv2.config)({ path: resolve23(process.cwd(), ".env"), quiet: true });
|
|
34203
34386
|
let dir = process.cwd();
|
|
34204
|
-
while (dir !==
|
|
34387
|
+
while (dir !== dirname9(dir)) {
|
|
34205
34388
|
if (existsSync19(join16(dir, "pnpm-workspace.yaml"))) {
|
|
34206
34389
|
(0, import_dotenv2.config)({ path: join16(dir, ".env"), quiet: true });
|
|
34207
34390
|
return;
|
|
34208
34391
|
}
|
|
34209
|
-
dir =
|
|
34392
|
+
dir = dirname9(dir);
|
|
34210
34393
|
}
|
|
34211
34394
|
}
|
|
34212
34395
|
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, OPENAI_NARRATION_COST_USD, TRANSCRIPT_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
@@ -34227,6 +34410,7 @@ var init_build_plan = __esm({
|
|
|
34227
34410
|
init_project_config();
|
|
34228
34411
|
init_scene_project();
|
|
34229
34412
|
init_storyboard_edit();
|
|
34413
|
+
init_build_video_providers();
|
|
34230
34414
|
VIDEO_COST_USD = 5;
|
|
34231
34415
|
MUSIC_COST_USD = 0.5;
|
|
34232
34416
|
ELEVENLABS_NARRATION_COST_USD = 0.05;
|
|
@@ -34405,7 +34589,7 @@ function registerMusicCommand(parent) {
|
|
|
34405
34589
|
console.log();
|
|
34406
34590
|
console.log(`Saved to: ${source_default.bold(outputPath)}`);
|
|
34407
34591
|
console.log(`Duration: ${duration}s`);
|
|
34408
|
-
console.log(`Provider: ElevenLabs (
|
|
34592
|
+
console.log(`Provider: ElevenLabs (${ELEVENLABS_MUSIC_MODEL})`);
|
|
34409
34593
|
if (options.instrumental) console.log(`Mode: Instrumental`);
|
|
34410
34594
|
console.log();
|
|
34411
34595
|
} else {
|
|
@@ -34544,6 +34728,48 @@ var init_scene_build_mode = __esm({
|
|
|
34544
34728
|
}
|
|
34545
34729
|
});
|
|
34546
34730
|
|
|
34731
|
+
// src/utils/image-file.ts
|
|
34732
|
+
import { rm as rm2, writeFile as writeFile18 } from "node:fs/promises";
|
|
34733
|
+
import { extname as extname4 } from "node:path";
|
|
34734
|
+
function detectImageFormat(buffer) {
|
|
34735
|
+
if (buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
34736
|
+
return "png";
|
|
34737
|
+
}
|
|
34738
|
+
if (buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) return "jpeg";
|
|
34739
|
+
if (buffer.toString("ascii", 0, 4) === "RIFF" && buffer.toString("ascii", 8, 12) === "WEBP") {
|
|
34740
|
+
return "webp";
|
|
34741
|
+
}
|
|
34742
|
+
return void 0;
|
|
34743
|
+
}
|
|
34744
|
+
async function writeImageFile(path2, buffer) {
|
|
34745
|
+
const wanted = EXTENSION_FORMATS[extname4(path2).toLowerCase()];
|
|
34746
|
+
const actual = detectImageFormat(buffer);
|
|
34747
|
+
if (!wanted || !actual || wanted === actual) {
|
|
34748
|
+
await writeFile18(path2, buffer);
|
|
34749
|
+
return;
|
|
34750
|
+
}
|
|
34751
|
+
const source = `${path2}.source.${actual === "jpeg" ? "jpg" : actual}`;
|
|
34752
|
+
await writeFile18(source, buffer);
|
|
34753
|
+
try {
|
|
34754
|
+
await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source, "-frames:v", "1", path2]);
|
|
34755
|
+
} finally {
|
|
34756
|
+
await rm2(source, { force: true });
|
|
34757
|
+
}
|
|
34758
|
+
}
|
|
34759
|
+
var EXTENSION_FORMATS;
|
|
34760
|
+
var init_image_file = __esm({
|
|
34761
|
+
"src/utils/image-file.ts"() {
|
|
34762
|
+
"use strict";
|
|
34763
|
+
init_exec_safe();
|
|
34764
|
+
EXTENSION_FORMATS = {
|
|
34765
|
+
".png": "png",
|
|
34766
|
+
".jpg": "jpeg",
|
|
34767
|
+
".jpeg": "jpeg",
|
|
34768
|
+
".webp": "webp"
|
|
34769
|
+
};
|
|
34770
|
+
}
|
|
34771
|
+
});
|
|
34772
|
+
|
|
34547
34773
|
// src/commands/_shared/scene-build.ts
|
|
34548
34774
|
var scene_build_exports = {};
|
|
34549
34775
|
__export(scene_build_exports, {
|
|
@@ -34552,8 +34778,8 @@ __export(scene_build_exports, {
|
|
|
34552
34778
|
resolveSceneBuildMode: () => resolveSceneBuildMode
|
|
34553
34779
|
});
|
|
34554
34780
|
import { existsSync as existsSync21, readFileSync as readFileSync2 } from "node:fs";
|
|
34555
|
-
import { copyFile as copyFile3, mkdir as
|
|
34556
|
-
import { dirname as
|
|
34781
|
+
import { copyFile as copyFile3, mkdir as mkdir12, readFile as readFile18, rm as rm3, writeFile as writeFile19 } from "node:fs/promises";
|
|
34782
|
+
import { dirname as dirname10, join as join17, resolve as resolve26 } from "node:path";
|
|
34557
34783
|
function readProjectKindSync(projectDir) {
|
|
34558
34784
|
try {
|
|
34559
34785
|
const raw = readFileSync2(join17(projectDir, "vibe.config.json"), "utf-8");
|
|
@@ -35406,7 +35632,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
35406
35632
|
};
|
|
35407
35633
|
}
|
|
35408
35634
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35409
|
-
await
|
|
35635
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35410
35636
|
await copyFile3(cacheAbs, abs);
|
|
35411
35637
|
await writeAssetMetadata({
|
|
35412
35638
|
projectDir: ctx.projectDir,
|
|
@@ -35437,14 +35663,14 @@ async function dispatchNarration(beat, ctx) {
|
|
|
35437
35663
|
ctx.onProgress({ type: "narration-failed", beatId: beat.id, error });
|
|
35438
35664
|
return { status: "failed", error };
|
|
35439
35665
|
}
|
|
35440
|
-
await
|
|
35441
|
-
await
|
|
35666
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35667
|
+
await writeFile19(abs, result.audioBuffer);
|
|
35442
35668
|
for (const otherExt of ["mp3", "wav"]) {
|
|
35443
35669
|
const sibling = join17(ctx.projectDir, `assets/narration-${beat.id}.${otherExt}`);
|
|
35444
|
-
if (sibling !== abs && existsSync21(sibling)) await
|
|
35670
|
+
if (sibling !== abs && existsSync21(sibling)) await rm3(sibling, { force: true });
|
|
35445
35671
|
}
|
|
35446
|
-
await
|
|
35447
|
-
await
|
|
35672
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
35673
|
+
await writeFile19(cacheAbs, result.audioBuffer);
|
|
35448
35674
|
await writeAssetMetadata({
|
|
35449
35675
|
projectDir: ctx.projectDir,
|
|
35450
35676
|
kind: "narration",
|
|
@@ -35500,8 +35726,8 @@ async function dispatchTranscript(beat, narrationPath, narrationFresh, ctx) {
|
|
|
35500
35726
|
return "skipped";
|
|
35501
35727
|
}
|
|
35502
35728
|
try {
|
|
35503
|
-
await
|
|
35504
|
-
await
|
|
35729
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35730
|
+
await writeFile19(abs, JSON.stringify(words, null, 2), "utf-8");
|
|
35505
35731
|
} catch (err) {
|
|
35506
35732
|
ctx.onProgress({
|
|
35507
35733
|
type: "transcript-skipped",
|
|
@@ -35589,7 +35815,7 @@ async function buildCharacters(characters, ctx) {
|
|
|
35589
35815
|
}
|
|
35590
35816
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35591
35817
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35592
|
-
await
|
|
35818
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35593
35819
|
await copyFile3(cacheAbs, abs);
|
|
35594
35820
|
await writeAssetMetadata({
|
|
35595
35821
|
projectDir: ctx.projectDir,
|
|
@@ -35622,10 +35848,10 @@ async function buildCharacters(characters, ctx) {
|
|
|
35622
35848
|
ctx.onProgress({ type: "character-failed", name: character.name, error: generated.error });
|
|
35623
35849
|
continue;
|
|
35624
35850
|
}
|
|
35625
|
-
await
|
|
35626
|
-
await
|
|
35627
|
-
await
|
|
35628
|
-
await
|
|
35851
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35852
|
+
await writeImageFile(abs, generated.buffer);
|
|
35853
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
35854
|
+
await writeImageFile(cacheAbs, generated.buffer);
|
|
35629
35855
|
await writeAssetMetadata({
|
|
35630
35856
|
projectDir: ctx.projectDir,
|
|
35631
35857
|
kind: "character",
|
|
@@ -35694,7 +35920,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
35694
35920
|
}
|
|
35695
35921
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35696
35922
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35697
|
-
await
|
|
35923
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35698
35924
|
await copyFile3(cacheAbs, abs);
|
|
35699
35925
|
await writeAssetMetadata({
|
|
35700
35926
|
projectDir: ctx.projectDir,
|
|
@@ -35724,11 +35950,11 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
35724
35950
|
ctx.onProgress({ type: "backdrop-failed", beatId: beat.id, error });
|
|
35725
35951
|
return { status: "failed", error };
|
|
35726
35952
|
}
|
|
35727
|
-
await
|
|
35953
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35728
35954
|
const buffer = generated.buffer;
|
|
35729
|
-
await
|
|
35730
|
-
await
|
|
35731
|
-
await
|
|
35955
|
+
await writeImageFile(abs, buffer);
|
|
35956
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
35957
|
+
await writeImageFile(cacheAbs, buffer);
|
|
35732
35958
|
await writeAssetMetadata({
|
|
35733
35959
|
projectDir: ctx.projectDir,
|
|
35734
35960
|
kind: "backdrop",
|
|
@@ -35772,7 +35998,7 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
|
|
|
35772
35998
|
const result2 = await provider2.generateImage(prompt3, {
|
|
35773
35999
|
// CLI input is free-form; an alias the provider doesn't know fails the
|
|
35774
36000
|
// API call and surfaces as a beat-scoped backdrop/keyframe error.
|
|
35775
|
-
model: ctx.imageModel ??
|
|
36001
|
+
model: ctx.imageModel ?? OPENAI_IMAGE_DEFAULT_MODEL,
|
|
35776
36002
|
size: ctx.imageSize,
|
|
35777
36003
|
quality: ctx.imageQuality
|
|
35778
36004
|
});
|
|
@@ -35857,7 +36083,7 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
35857
36083
|
}
|
|
35858
36084
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35859
36085
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35860
|
-
await
|
|
36086
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35861
36087
|
await copyFile3(cacheAbs, abs);
|
|
35862
36088
|
await writeAssetMetadata({
|
|
35863
36089
|
projectDir: ctx.projectDir,
|
|
@@ -35887,10 +36113,10 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
35887
36113
|
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. ";
|
|
35888
36114
|
const generated = sheetBuffers.length > 0 ? await editKeyframeImage(`${identityLock}${keyframeCue}`, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
|
|
35889
36115
|
if (!generated.success) return { status: "failed", error: generated.error };
|
|
35890
|
-
await
|
|
35891
|
-
await
|
|
35892
|
-
await
|
|
35893
|
-
await
|
|
36116
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
36117
|
+
await writeImageFile(abs, generated.buffer);
|
|
36118
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
36119
|
+
await writeImageFile(cacheAbs, generated.buffer);
|
|
35894
36120
|
await writeAssetMetadata({
|
|
35895
36121
|
projectDir: ctx.projectDir,
|
|
35896
36122
|
kind: "keyframe",
|
|
@@ -35986,7 +36212,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
35986
36212
|
}
|
|
35987
36213
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
35988
36214
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
35989
|
-
await
|
|
36215
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
35990
36216
|
await copyFile3(cacheAbs, abs);
|
|
35991
36217
|
await writeAssetMetadata({
|
|
35992
36218
|
projectDir: ctx.projectDir,
|
|
@@ -36063,7 +36289,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
36063
36289
|
}
|
|
36064
36290
|
}
|
|
36065
36291
|
if (result.status === "completed" && existsSync21(abs)) {
|
|
36066
|
-
await
|
|
36292
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
36067
36293
|
await copyFile3(abs, cacheAbs);
|
|
36068
36294
|
await writeAssetMetadata({
|
|
36069
36295
|
projectDir: ctx.projectDir,
|
|
@@ -36165,7 +36391,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
36165
36391
|
}
|
|
36166
36392
|
const cacheAbs = join17(ctx.projectDir, cache.path);
|
|
36167
36393
|
if (existsSync21(cacheAbs) && !ctx.force) {
|
|
36168
|
-
await
|
|
36394
|
+
await mkdir12(dirname10(abs), { recursive: true });
|
|
36169
36395
|
await copyFile3(cacheAbs, abs);
|
|
36170
36396
|
await writeAssetMetadata({
|
|
36171
36397
|
projectDir: ctx.projectDir,
|
|
@@ -36243,7 +36469,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
36243
36469
|
ctx.onProgress({ type: "music-failed", beatId: beat.id, error });
|
|
36244
36470
|
return { status: "failed", error };
|
|
36245
36471
|
}
|
|
36246
|
-
await
|
|
36472
|
+
await mkdir12(dirname10(cacheAbs), { recursive: true });
|
|
36247
36473
|
await copyFile3(abs, cacheAbs);
|
|
36248
36474
|
await writeAssetMetadata({
|
|
36249
36475
|
projectDir: ctx.projectDir,
|
|
@@ -36277,12 +36503,12 @@ function loadSceneBuildEnv(projectDir) {
|
|
|
36277
36503
|
(0, import_dotenv3.config)({ path: join17(projectDir, ".env"), quiet: true });
|
|
36278
36504
|
(0, import_dotenv3.config)({ path: resolve26(process.cwd(), ".env"), quiet: true });
|
|
36279
36505
|
let dir = process.cwd();
|
|
36280
|
-
while (dir !==
|
|
36506
|
+
while (dir !== dirname10(dir)) {
|
|
36281
36507
|
if (existsSync21(join17(dir, "pnpm-workspace.yaml"))) {
|
|
36282
36508
|
(0, import_dotenv3.config)({ path: join17(dir, ".env"), quiet: true });
|
|
36283
36509
|
return;
|
|
36284
36510
|
}
|
|
36285
|
-
dir =
|
|
36511
|
+
dir = dirname10(dir);
|
|
36286
36512
|
}
|
|
36287
36513
|
}
|
|
36288
36514
|
async function skipped(kind, beatId, reason, ctx) {
|
|
@@ -36507,14 +36733,6 @@ async function safeAudioDuration(absPath) {
|
|
|
36507
36733
|
return void 0;
|
|
36508
36734
|
}
|
|
36509
36735
|
}
|
|
36510
|
-
function resolveBuildVideoProvider(value) {
|
|
36511
|
-
const provider = String(value ?? "seedance").toLowerCase();
|
|
36512
|
-
if (provider === "fal") return "seedance";
|
|
36513
|
-
if (provider === "seedance" || provider === "grok" || provider === "kling" || provider === "runway" || provider === "veo") {
|
|
36514
|
-
return provider;
|
|
36515
|
-
}
|
|
36516
|
-
return "seedance";
|
|
36517
|
-
}
|
|
36518
36736
|
function resolveBuildMusicProvider(value) {
|
|
36519
36737
|
const provider = String(value ?? "elevenlabs").toLowerCase();
|
|
36520
36738
|
return provider === "replicate" ? "replicate" : "elevenlabs";
|
|
@@ -36526,8 +36744,7 @@ function stringOrUndefined4(value) {
|
|
|
36526
36744
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
36527
36745
|
}
|
|
36528
36746
|
async function apiKeyForVideoProvider(provider, projectDir) {
|
|
36529
|
-
|
|
36530
|
-
return getApiKeyFromConfig(providerKey, { cwd: projectDir });
|
|
36747
|
+
return getApiKeyFromConfig(videoProviderConfigKey(provider), { cwd: projectDir });
|
|
36531
36748
|
}
|
|
36532
36749
|
async function finalizeBuildResult(projectDir, startedAt, result, reportResult = result) {
|
|
36533
36750
|
const reportPath = join17(projectDir, "build-report.json");
|
|
@@ -36550,7 +36767,7 @@ async function finalizeBuildResult(projectDir, startedAt, result, reportResult =
|
|
|
36550
36767
|
const withMeta = decorate(result);
|
|
36551
36768
|
const reportMeta = reportResult === result ? withMeta : decorate(reportResult);
|
|
36552
36769
|
try {
|
|
36553
|
-
await
|
|
36770
|
+
await writeFile19(
|
|
36554
36771
|
reportPath,
|
|
36555
36772
|
JSON.stringify(toBuildReport(projectDir, reportMeta), null, 2) + "\n",
|
|
36556
36773
|
"utf-8"
|
|
@@ -36803,6 +37020,8 @@ var init_scene_build = __esm({
|
|
|
36803
37020
|
init_scene_repair();
|
|
36804
37021
|
init_tts_resolve();
|
|
36805
37022
|
init_scene_build_mode();
|
|
37023
|
+
init_image_file();
|
|
37024
|
+
init_build_video_providers();
|
|
36806
37025
|
init_scene_build_mode();
|
|
36807
37026
|
BEAT_PRIMITIVES_CONCURRENCY = 4;
|
|
36808
37027
|
}
|
|
@@ -36915,8 +37134,8 @@ __export(ai_audio_exports, {
|
|
|
36915
37134
|
executeTranscribe: () => executeTranscribe,
|
|
36916
37135
|
executeVoiceClone: () => executeVoiceClone
|
|
36917
37136
|
});
|
|
36918
|
-
import { resolve as resolve28, dirname as
|
|
36919
|
-
import { readFile as readFile19, writeFile as
|
|
37137
|
+
import { resolve as resolve28, dirname as dirname11, basename as basename5, extname as extname5 } from "node:path";
|
|
37138
|
+
import { readFile as readFile19, writeFile as writeFile20 } from "node:fs/promises";
|
|
36920
37139
|
import { existsSync as existsSync22 } from "node:fs";
|
|
36921
37140
|
async function executeTranscribe(options) {
|
|
36922
37141
|
const { audioPath, language, output, format, apiKey } = options;
|
|
@@ -36938,7 +37157,7 @@ async function executeTranscribe(options) {
|
|
|
36938
37157
|
outputPath = resolve28(process.cwd(), output);
|
|
36939
37158
|
const fmt = detectFormat(output, format);
|
|
36940
37159
|
const content = formatTranscript(result, fmt);
|
|
36941
|
-
await
|
|
37160
|
+
await writeFile20(outputPath, content, "utf-8");
|
|
36942
37161
|
}
|
|
36943
37162
|
return {
|
|
36944
37163
|
success: true,
|
|
@@ -36966,7 +37185,7 @@ async function executeIsolate(options) {
|
|
|
36966
37185
|
return { success: false, error: result.error || "Audio isolation failed" };
|
|
36967
37186
|
}
|
|
36968
37187
|
const outputPath = resolve28(process.cwd(), output);
|
|
36969
|
-
await
|
|
37188
|
+
await writeFile20(outputPath, result.audioBuffer);
|
|
36970
37189
|
return { success: true, outputPath };
|
|
36971
37190
|
} catch (error) {
|
|
36972
37191
|
return { success: false, error: `Audio isolation failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -37012,11 +37231,11 @@ async function executeDub(options) {
|
|
|
37012
37231
|
if (!openaiKey) return { success: false, error: "OPENAI_API_KEY required for Whisper transcription" };
|
|
37013
37232
|
if (!anthropicKey) return { success: false, error: "ANTHROPIC_API_KEY required for Claude translation" };
|
|
37014
37233
|
if (!analyzeOnly && !elevenlabsKey) return { success: false, error: "ELEVENLABS_API_KEY required for TTS" };
|
|
37015
|
-
const ext =
|
|
37234
|
+
const ext = extname5(absPath).toLowerCase();
|
|
37016
37235
|
const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
|
|
37017
37236
|
let audioPath = absPath;
|
|
37018
37237
|
if (isVideo) {
|
|
37019
|
-
const tempAudioPath = resolve28(
|
|
37238
|
+
const tempAudioPath = resolve28(dirname11(absPath), `temp-audio-${Date.now()}.mp3`);
|
|
37020
37239
|
execSafeSync("ffmpeg", ["-i", absPath, "-vn", "-acodec", "mp3", "-y", tempAudioPath]);
|
|
37021
37240
|
audioPath = tempAudioPath;
|
|
37022
37241
|
}
|
|
@@ -37077,7 +37296,7 @@ ${segmentTexts}`,
|
|
|
37077
37296
|
translated: translatedSegments[i]?.text || s.text
|
|
37078
37297
|
}))
|
|
37079
37298
|
};
|
|
37080
|
-
await
|
|
37299
|
+
await writeFile20(timingPath, JSON.stringify(timingData, null, 2));
|
|
37081
37300
|
}
|
|
37082
37301
|
return {
|
|
37083
37302
|
success: true,
|
|
@@ -37097,10 +37316,10 @@ ${segmentTexts}`,
|
|
|
37097
37316
|
}
|
|
37098
37317
|
}
|
|
37099
37318
|
const combinedBuffer = Buffer.concat(dubbedBuffers);
|
|
37100
|
-
const outputExt = isVideo ? ".mp3" :
|
|
37101
|
-
const defaultOutputPath2 = resolve28(
|
|
37319
|
+
const outputExt = isVideo ? ".mp3" : extname5(absPath);
|
|
37320
|
+
const defaultOutputPath2 = resolve28(dirname11(absPath), `${basename5(absPath, extname5(absPath))}-${language}${outputExt}`);
|
|
37102
37321
|
const finalOutputPath = resolve28(process.cwd(), output || defaultOutputPath2);
|
|
37103
|
-
await
|
|
37322
|
+
await writeFile20(finalOutputPath, combinedBuffer);
|
|
37104
37323
|
if (isVideo && audioPath !== absPath) {
|
|
37105
37324
|
try {
|
|
37106
37325
|
const { unlink: unlink3 } = await import("node:fs/promises");
|
|
@@ -37135,7 +37354,7 @@ async function executeDuck(options) {
|
|
|
37135
37354
|
const absVoicePath = resolve28(process.cwd(), voicePath);
|
|
37136
37355
|
if (!existsSync22(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
|
|
37137
37356
|
if (!existsSync22(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
|
|
37138
|
-
const defaultOutput = resolve28(
|
|
37357
|
+
const defaultOutput = resolve28(dirname11(absMusicPath), `${basename5(absMusicPath, extname5(absMusicPath))}-ducked${extname5(absMusicPath)}`);
|
|
37139
37358
|
const outputPath = resolve28(process.cwd(), output || defaultOutput);
|
|
37140
37359
|
const filter = `[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`;
|
|
37141
37360
|
await execSafe("ffmpeg", [
|
|
@@ -37400,7 +37619,7 @@ var init_silence_cut = __esm({
|
|
|
37400
37619
|
|
|
37401
37620
|
// src/commands/_shared/edit/jump-cut.ts
|
|
37402
37621
|
import { existsSync as existsSync24 } from "node:fs";
|
|
37403
|
-
import { readFile as readFile21, writeFile as
|
|
37622
|
+
import { readFile as readFile21, writeFile as writeFile21, mkdir as mkdir13 } from "node:fs/promises";
|
|
37404
37623
|
import { join as join18 } from "node:path";
|
|
37405
37624
|
async function transcribeWithWords(audioPath, apiKey, language) {
|
|
37406
37625
|
const audioBuffer = await readFile21(audioPath);
|
|
@@ -37480,7 +37699,7 @@ async function executeJumpCut(options) {
|
|
|
37480
37699
|
}
|
|
37481
37700
|
try {
|
|
37482
37701
|
const tmpDir = `/tmp/vibe_jumpcut_${Date.now()}`;
|
|
37483
|
-
await
|
|
37702
|
+
await mkdir13(tmpDir, { recursive: true });
|
|
37484
37703
|
const audioPath = join18(tmpDir, "audio.wav");
|
|
37485
37704
|
try {
|
|
37486
37705
|
await execSafe(
|
|
@@ -37559,7 +37778,7 @@ async function executeJumpCut(options) {
|
|
|
37559
37778
|
}
|
|
37560
37779
|
const concatList = segmentPaths.map((p) => `file '${p}'`).join("\n");
|
|
37561
37780
|
const listPath = join18(tmpDir, "concat.txt");
|
|
37562
|
-
await
|
|
37781
|
+
await writeFile21(listPath, concatList);
|
|
37563
37782
|
await execSafe(
|
|
37564
37783
|
"ffmpeg",
|
|
37565
37784
|
[
|
|
@@ -37586,8 +37805,8 @@ async function executeJumpCut(options) {
|
|
|
37586
37805
|
};
|
|
37587
37806
|
} finally {
|
|
37588
37807
|
try {
|
|
37589
|
-
const { rm:
|
|
37590
|
-
await
|
|
37808
|
+
const { rm: rm7 } = await import("node:fs/promises");
|
|
37809
|
+
await rm7(tmpDir, { recursive: true, force: true });
|
|
37591
37810
|
} catch {
|
|
37592
37811
|
}
|
|
37593
37812
|
}
|
|
@@ -37664,7 +37883,7 @@ __export(remotion_exports, {
|
|
|
37664
37883
|
wrapComponentWithImage: () => wrapComponentWithImage,
|
|
37665
37884
|
wrapComponentWithVideo: () => wrapComponentWithVideo
|
|
37666
37885
|
});
|
|
37667
|
-
import { writeFile as
|
|
37886
|
+
import { writeFile as writeFile22, mkdir as mkdir14, rm as rm4, copyFile as copyFile4 } from "node:fs/promises";
|
|
37668
37887
|
import { existsSync as existsSync25 } from "node:fs";
|
|
37669
37888
|
import { join as join19 } from "node:path";
|
|
37670
37889
|
import { tmpdir } from "node:os";
|
|
@@ -37686,7 +37905,7 @@ async function ensureRemotionInstalled() {
|
|
|
37686
37905
|
}
|
|
37687
37906
|
async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
37688
37907
|
const dir = join19(tmpdir(), `vibe_motion_${Date.now()}`);
|
|
37689
|
-
await
|
|
37908
|
+
await mkdir14(dir, { recursive: true });
|
|
37690
37909
|
const deps = {
|
|
37691
37910
|
remotion: REMOTION_VERSION,
|
|
37692
37911
|
"@remotion/cli": REMOTION_VERSION,
|
|
@@ -37704,7 +37923,7 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
37704
37923
|
dependencies: deps
|
|
37705
37924
|
};
|
|
37706
37925
|
const packageJsonStr = JSON.stringify(packageJson, null, 2);
|
|
37707
|
-
await
|
|
37926
|
+
await writeFile22(join19(dir, "package.json"), packageJsonStr);
|
|
37708
37927
|
const tsconfig = {
|
|
37709
37928
|
compilerOptions: {
|
|
37710
37929
|
target: "ES2020",
|
|
@@ -37716,8 +37935,8 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
37716
37935
|
skipLibCheck: true
|
|
37717
37936
|
}
|
|
37718
37937
|
};
|
|
37719
|
-
await
|
|
37720
|
-
await
|
|
37938
|
+
await writeFile22(join19(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
37939
|
+
await writeFile22(join19(dir, "Component.tsx"), componentCode);
|
|
37721
37940
|
const rootCode = `import { registerRoot, Composition } from "remotion";
|
|
37722
37941
|
import { ${componentName} } from "./Component";
|
|
37723
37942
|
|
|
@@ -37736,7 +37955,7 @@ const Root = () => {
|
|
|
37736
37955
|
|
|
37737
37956
|
registerRoot(Root);
|
|
37738
37957
|
`;
|
|
37739
|
-
await
|
|
37958
|
+
await writeFile22(join19(dir, "Root.tsx"), rootCode);
|
|
37740
37959
|
const depsHash = createHash4("md5").update(packageJsonStr).digest("hex").slice(0, 12);
|
|
37741
37960
|
const cacheMarker = join19(REMOTION_CACHE_DIR, `.deps-${depsHash}`);
|
|
37742
37961
|
const cachedModules = join19(REMOTION_CACHE_DIR, "node_modules");
|
|
@@ -37750,15 +37969,15 @@ registerRoot(Root);
|
|
|
37750
37969
|
} else {
|
|
37751
37970
|
await this_npmInstall(dir);
|
|
37752
37971
|
try {
|
|
37753
|
-
await
|
|
37754
|
-
await
|
|
37972
|
+
await mkdir14(REMOTION_CACHE_DIR, { recursive: true });
|
|
37973
|
+
await writeFile22(join19(REMOTION_CACHE_DIR, "package.json"), packageJsonStr);
|
|
37755
37974
|
if (existsSync25(join19(dir, "node_modules"))) {
|
|
37756
37975
|
const { rename: rename5, symlink } = await import("node:fs/promises");
|
|
37757
37976
|
await rename5(join19(dir, "node_modules"), cachedModules).catch(() => {
|
|
37758
37977
|
});
|
|
37759
37978
|
await symlink(cachedModules, join19(dir, "node_modules"), "dir").catch(() => {
|
|
37760
37979
|
});
|
|
37761
|
-
await
|
|
37980
|
+
await writeFile22(cacheMarker, depsHash);
|
|
37762
37981
|
}
|
|
37763
37982
|
} catch {
|
|
37764
37983
|
}
|
|
@@ -37858,7 +38077,7 @@ async function renderMotion(options) {
|
|
|
37858
38077
|
stderr: ${stderr}` : ""}`);
|
|
37859
38078
|
return { success: false, error: `Remotion render failed: ${msg}` };
|
|
37860
38079
|
} finally {
|
|
37861
|
-
await
|
|
38080
|
+
await rm4(dir, { recursive: true, force: true }).catch(() => {
|
|
37862
38081
|
});
|
|
37863
38082
|
}
|
|
37864
38083
|
}
|
|
@@ -37927,7 +38146,7 @@ async function renderWithEmbeddedImage(options) {
|
|
|
37927
38146
|
);
|
|
37928
38147
|
try {
|
|
37929
38148
|
const publicDir = join19(dir, "public");
|
|
37930
|
-
await
|
|
38149
|
+
await mkdir14(publicDir, { recursive: true });
|
|
37931
38150
|
await copyFile4(options.imagePath, join19(publicDir, options.imageFileName));
|
|
37932
38151
|
const entryPoint = join19(dir, "Root.tsx");
|
|
37933
38152
|
const mp4Out = options.outputPath.replace(/\.\w+$/, ".mp4");
|
|
@@ -37950,7 +38169,7 @@ async function renderWithEmbeddedImage(options) {
|
|
|
37950
38169
|
const msg = error instanceof Error ? error.message : String(error);
|
|
37951
38170
|
return { success: false, error: `Remotion image embed render failed: ${msg}` };
|
|
37952
38171
|
} finally {
|
|
37953
|
-
await
|
|
38172
|
+
await rm4(dir, { recursive: true, force: true }).catch(() => {
|
|
37954
38173
|
});
|
|
37955
38174
|
}
|
|
37956
38175
|
}
|
|
@@ -37991,7 +38210,7 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
37991
38210
|
);
|
|
37992
38211
|
try {
|
|
37993
38212
|
const publicDir = join19(dir, "public");
|
|
37994
|
-
await
|
|
38213
|
+
await mkdir14(publicDir, { recursive: true });
|
|
37995
38214
|
await copyFile4(options.videoPath, join19(publicDir, options.videoFileName));
|
|
37996
38215
|
const entryPoint = join19(dir, "Root.tsx");
|
|
37997
38216
|
const mp4VideoOnly = options.outputPath.replace(/\.\w+$/, "_video_only.mp4");
|
|
@@ -38027,14 +38246,14 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
38027
38246
|
"-shortest",
|
|
38028
38247
|
mp4Out
|
|
38029
38248
|
], { timeout: 12e4 });
|
|
38030
|
-
await
|
|
38249
|
+
await rm4(mp4VideoOnly, { force: true }).catch(() => {
|
|
38031
38250
|
});
|
|
38032
38251
|
return { success: true, outputPath: mp4Out };
|
|
38033
38252
|
} catch (error) {
|
|
38034
38253
|
const msg = error instanceof Error ? error.message : String(error);
|
|
38035
38254
|
return { success: false, error: `Remotion video embed render failed: ${msg}` };
|
|
38036
38255
|
} finally {
|
|
38037
|
-
await
|
|
38256
|
+
await rm4(dir, { recursive: true, force: true }).catch(() => {
|
|
38038
38257
|
});
|
|
38039
38258
|
}
|
|
38040
38259
|
}
|
|
@@ -38415,8 +38634,8 @@ var init_remotion = __esm({
|
|
|
38415
38634
|
|
|
38416
38635
|
// src/commands/_shared/edit/caption.ts
|
|
38417
38636
|
import { existsSync as existsSync26 } from "node:fs";
|
|
38418
|
-
import { readFile as readFile22, writeFile as
|
|
38419
|
-
import { dirname as
|
|
38637
|
+
import { readFile as readFile22, writeFile as writeFile23, mkdir as mkdir15 } from "node:fs/promises";
|
|
38638
|
+
import { dirname as dirname12, basename as basename6, extname as extname6, join as join20 } from "node:path";
|
|
38420
38639
|
function getCaptionForceStyle(style, fontSize, fontColor, position) {
|
|
38421
38640
|
const alignment = position === "top" ? 8 : position === "center" ? 5 : 2;
|
|
38422
38641
|
const marginV = position === "center" ? 0 : 30;
|
|
@@ -38462,7 +38681,7 @@ async function executeCaption(options) {
|
|
|
38462
38681
|
}
|
|
38463
38682
|
try {
|
|
38464
38683
|
const tmpDir = `/tmp/vibe_caption_${Date.now()}`;
|
|
38465
|
-
await
|
|
38684
|
+
await mkdir15(tmpDir, { recursive: true });
|
|
38466
38685
|
const audioPath = join20(tmpDir, "audio.wav");
|
|
38467
38686
|
const srtPath = join20(tmpDir, "captions.srt");
|
|
38468
38687
|
try {
|
|
@@ -38495,7 +38714,7 @@ async function executeCaption(options) {
|
|
|
38495
38714
|
};
|
|
38496
38715
|
}
|
|
38497
38716
|
const srtContent = formatSRT(transcriptResult.segments);
|
|
38498
|
-
await
|
|
38717
|
+
await writeFile23(srtPath, srtContent);
|
|
38499
38718
|
const { width, height } = await getVideoResolution(videoPath);
|
|
38500
38719
|
const fontSize = customFontSize || Math.round(height / 18);
|
|
38501
38720
|
let hasSubtitles = false;
|
|
@@ -38532,12 +38751,12 @@ async function executeCaption(options) {
|
|
|
38532
38751
|
} = await Promise.resolve().then(() => (init_remotion(), remotion_exports));
|
|
38533
38752
|
const remotionErr = await ensureRemotionInstalled2();
|
|
38534
38753
|
if (remotionErr) {
|
|
38535
|
-
const outputDir2 =
|
|
38754
|
+
const outputDir2 = dirname12(outputPath);
|
|
38536
38755
|
const outputSrtPath2 = join20(
|
|
38537
38756
|
outputDir2,
|
|
38538
|
-
basename6(outputPath,
|
|
38757
|
+
basename6(outputPath, extname6(outputPath)) + ".srt"
|
|
38539
38758
|
);
|
|
38540
|
-
await
|
|
38759
|
+
await writeFile23(outputSrtPath2, srtContent);
|
|
38541
38760
|
return { success: false, error: `${remotionErr}
|
|
38542
38761
|
SRT saved to: ${outputSrtPath2}` };
|
|
38543
38762
|
}
|
|
@@ -38571,12 +38790,12 @@ SRT saved to: ${outputSrtPath2}` };
|
|
|
38571
38790
|
outputPath
|
|
38572
38791
|
});
|
|
38573
38792
|
if (!renderResult.success) {
|
|
38574
|
-
const outputDir2 =
|
|
38793
|
+
const outputDir2 = dirname12(outputPath);
|
|
38575
38794
|
const outputSrtPath2 = join20(
|
|
38576
38795
|
outputDir2,
|
|
38577
|
-
basename6(outputPath,
|
|
38796
|
+
basename6(outputPath, extname6(outputPath)) + ".srt"
|
|
38578
38797
|
);
|
|
38579
|
-
await
|
|
38798
|
+
await writeFile23(outputSrtPath2, srtContent);
|
|
38580
38799
|
return {
|
|
38581
38800
|
success: false,
|
|
38582
38801
|
error: `${renderResult.error}
|
|
@@ -38584,12 +38803,12 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
38584
38803
|
};
|
|
38585
38804
|
}
|
|
38586
38805
|
}
|
|
38587
|
-
const outputDir =
|
|
38806
|
+
const outputDir = dirname12(outputPath);
|
|
38588
38807
|
const outputSrtPath = join20(
|
|
38589
38808
|
outputDir,
|
|
38590
|
-
basename6(outputPath,
|
|
38809
|
+
basename6(outputPath, extname6(outputPath)) + ".srt"
|
|
38591
38810
|
);
|
|
38592
|
-
await
|
|
38811
|
+
await writeFile23(outputSrtPath, srtContent);
|
|
38593
38812
|
return {
|
|
38594
38813
|
success: true,
|
|
38595
38814
|
outputPath,
|
|
@@ -38598,8 +38817,8 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
38598
38817
|
};
|
|
38599
38818
|
} finally {
|
|
38600
38819
|
try {
|
|
38601
|
-
const { rm:
|
|
38602
|
-
await
|
|
38820
|
+
const { rm: rm7 } = await import("node:fs/promises");
|
|
38821
|
+
await rm7(tmpDir, { recursive: true, force: true });
|
|
38603
38822
|
} catch {
|
|
38604
38823
|
}
|
|
38605
38824
|
}
|
|
@@ -38760,7 +38979,7 @@ var init_fade = __esm({
|
|
|
38760
38979
|
|
|
38761
38980
|
// src/commands/_shared/edit/translate-srt.ts
|
|
38762
38981
|
import { existsSync as existsSync29 } from "node:fs";
|
|
38763
|
-
import { readFile as readFile23, writeFile as
|
|
38982
|
+
import { readFile as readFile23, writeFile as writeFile24 } from "node:fs/promises";
|
|
38764
38983
|
async function executeTranslateSrt(options) {
|
|
38765
38984
|
const {
|
|
38766
38985
|
srtPath,
|
|
@@ -38803,15 +39022,14 @@ ${textsToTranslate}`;
|
|
|
38803
39022
|
Authorization: `Bearer ${openaiKey}`
|
|
38804
39023
|
},
|
|
38805
39024
|
body: JSON.stringify({
|
|
38806
|
-
model: "gpt-5-mini",
|
|
38807
|
-
messages: [{ role: "user", content: translatePrompt }]
|
|
38808
|
-
temperature: 0.3
|
|
39025
|
+
model: "gpt-5.4-mini",
|
|
39026
|
+
messages: [{ role: "user", content: translatePrompt }]
|
|
38809
39027
|
})
|
|
38810
39028
|
});
|
|
38811
39029
|
if (!response.ok) {
|
|
38812
39030
|
return {
|
|
38813
39031
|
success: false,
|
|
38814
|
-
error: `OpenAI API error: ${response.status} ${response.statusText}`
|
|
39032
|
+
error: `OpenAI API error: ${response.status} ${response.statusText}: ${await response.text()}`
|
|
38815
39033
|
};
|
|
38816
39034
|
}
|
|
38817
39035
|
const data = await response.json();
|
|
@@ -38832,15 +39050,15 @@ ${textsToTranslate}`;
|
|
|
38832
39050
|
"anthropic-version": "2023-06-01"
|
|
38833
39051
|
},
|
|
38834
39052
|
body: JSON.stringify({
|
|
38835
|
-
model: "claude-sonnet-
|
|
38836
|
-
max_tokens:
|
|
39053
|
+
model: "claude-sonnet-5-5",
|
|
39054
|
+
max_tokens: 16e3,
|
|
38837
39055
|
messages: [{ role: "user", content: translatePrompt }]
|
|
38838
39056
|
})
|
|
38839
39057
|
});
|
|
38840
39058
|
if (!response.ok) {
|
|
38841
39059
|
return {
|
|
38842
39060
|
success: false,
|
|
38843
|
-
error: `Claude API error: ${response.status} ${response.statusText}`
|
|
39061
|
+
error: `Claude API error: ${response.status} ${response.statusText}: ${await response.text()}`
|
|
38844
39062
|
};
|
|
38845
39063
|
}
|
|
38846
39064
|
const data = await response.json();
|
|
@@ -38864,7 +39082,7 @@ ${textsToTranslate}`;
|
|
|
38864
39082
|
}
|
|
38865
39083
|
}
|
|
38866
39084
|
const translatedSrt = formatSRT(translatedSegments);
|
|
38867
|
-
await
|
|
39085
|
+
await writeFile24(outputPath, translatedSrt);
|
|
38868
39086
|
return {
|
|
38869
39087
|
success: true,
|
|
38870
39088
|
outputPath,
|
|
@@ -39116,7 +39334,7 @@ var init_ai_edit = __esm({
|
|
|
39116
39334
|
});
|
|
39117
39335
|
|
|
39118
39336
|
// src/commands/ai-edit-cli.ts
|
|
39119
|
-
import { resolve as resolve30, extname as
|
|
39337
|
+
import { resolve as resolve30, extname as extname7, basename as basename7 } from "node:path";
|
|
39120
39338
|
import { existsSync as existsSync31 } from "node:fs";
|
|
39121
39339
|
function registerEditCommands(aiCommand) {
|
|
39122
39340
|
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", `
|
|
@@ -39140,7 +39358,7 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
|
|
|
39140
39358
|
if (!commandExists("ffmpeg")) {
|
|
39141
39359
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
39142
39360
|
}
|
|
39143
|
-
const ext =
|
|
39361
|
+
const ext = extname7(videoPath);
|
|
39144
39362
|
const name = basename7(videoPath, ext);
|
|
39145
39363
|
const outputPath = options.output || `${name}-cut${ext}`;
|
|
39146
39364
|
const useGemini = options.useGemini || false;
|
|
@@ -39270,7 +39488,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39270
39488
|
if (!apiKey) {
|
|
39271
39489
|
exitWithError(authError("OPENAI_API_KEY", "OpenAI"));
|
|
39272
39490
|
}
|
|
39273
|
-
const ext =
|
|
39491
|
+
const ext = extname7(videoPath);
|
|
39274
39492
|
const name = basename7(videoPath, ext);
|
|
39275
39493
|
const outputPath = options.output || `${name}-captioned${ext}`;
|
|
39276
39494
|
const spinner2 = ora("Starting caption process...").start();
|
|
@@ -39344,7 +39562,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39344
39562
|
});
|
|
39345
39563
|
return;
|
|
39346
39564
|
}
|
|
39347
|
-
const ext =
|
|
39565
|
+
const ext = extname7(inputPath);
|
|
39348
39566
|
const name = basename7(inputPath, ext);
|
|
39349
39567
|
const outputPath = options.output || `${name}-denoised${ext}`;
|
|
39350
39568
|
const spinner2 = ora("Applying noise reduction...").start();
|
|
@@ -39412,7 +39630,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39412
39630
|
});
|
|
39413
39631
|
return;
|
|
39414
39632
|
}
|
|
39415
|
-
const ext =
|
|
39633
|
+
const ext = extname7(videoPath);
|
|
39416
39634
|
const name = basename7(videoPath, ext);
|
|
39417
39635
|
const outputPath = options.output || `${name}-faded${ext}`;
|
|
39418
39636
|
const spinner2 = ora("Applying fade effects...").start();
|
|
@@ -39490,7 +39708,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39490
39708
|
if (!apiKey) {
|
|
39491
39709
|
exitWithError(authError(envKey, providerName));
|
|
39492
39710
|
}
|
|
39493
|
-
const ext =
|
|
39711
|
+
const ext = extname7(srtPath);
|
|
39494
39712
|
const name = basename7(srtPath, ext);
|
|
39495
39713
|
const outputPath = options.output || `${name}-${options.target}${ext}`;
|
|
39496
39714
|
const spinner2 = ora(`Translating to ${options.target}...`).start();
|
|
@@ -39568,7 +39786,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
39568
39786
|
if (!apiKey) {
|
|
39569
39787
|
exitWithError(authError("OPENAI_API_KEY", "OpenAI"));
|
|
39570
39788
|
}
|
|
39571
|
-
const ext =
|
|
39789
|
+
const ext = extname7(videoPath);
|
|
39572
39790
|
const name = basename7(videoPath, ext);
|
|
39573
39791
|
const outputPath = options.output || `${name}-jumpcut${ext}`;
|
|
39574
39792
|
const fillers = options.fillers ? options.fillers.split(",").map((f) => f.trim()) : void 0;
|
|
@@ -40029,8 +40247,8 @@ var init_project_resolver = __esm({
|
|
|
40029
40247
|
|
|
40030
40248
|
// src/commands/_shared/execute-fill-gaps.ts
|
|
40031
40249
|
import { existsSync as existsSync32 } from "node:fs";
|
|
40032
|
-
import { readFile as readFile24, writeFile as
|
|
40033
|
-
import { resolve as resolve32, dirname as
|
|
40250
|
+
import { readFile as readFile24, writeFile as writeFile25, mkdir as mkdir16, rename as renameFs } from "node:fs/promises";
|
|
40251
|
+
import { resolve as resolve32, dirname as dirname13 } from "node:path";
|
|
40034
40252
|
function detectVideoGaps(videoClips, totalDuration) {
|
|
40035
40253
|
const gaps = [];
|
|
40036
40254
|
const sortedClips = [...videoClips].sort((a, b) => a.startTime - b.startTime);
|
|
@@ -40240,14 +40458,14 @@ async function executeFillGaps(options) {
|
|
|
40240
40458
|
if (!kling.isConfigured()) {
|
|
40241
40459
|
return {
|
|
40242
40460
|
success: false,
|
|
40243
|
-
error: "Invalid KLING_API_KEY (
|
|
40461
|
+
error: "Invalid KLING_API_KEY (set your Kling API key, or the legacy ACCESS_KEY:SECRET_KEY pair)",
|
|
40244
40462
|
humanLines
|
|
40245
40463
|
};
|
|
40246
40464
|
}
|
|
40247
|
-
const projectDir =
|
|
40465
|
+
const projectDir = dirname13(filePath);
|
|
40248
40466
|
const footageDir = options.dir ? resolve32(process.cwd(), options.dir) : resolve32(projectDir, "footage");
|
|
40249
40467
|
if (!existsSync32(footageDir)) {
|
|
40250
|
-
await
|
|
40468
|
+
await mkdir16(footageDir, { recursive: true });
|
|
40251
40469
|
}
|
|
40252
40470
|
humanLines.push("Generating AI Videos");
|
|
40253
40471
|
const imgbbApiKey = options.imgbbApiKey || await getApiKey("IMGBB_API_KEY", "imgbb", void 0);
|
|
@@ -40312,13 +40530,13 @@ async function executeFillGaps(options) {
|
|
|
40312
40530
|
let generatedDuration = 0;
|
|
40313
40531
|
const generatedVideos = [];
|
|
40314
40532
|
const initialDuration = Math.min(10, targetDuration);
|
|
40315
|
-
const
|
|
40316
|
-
onProgress(`Generating ${
|
|
40533
|
+
const klingDuration2 = initialDuration > 5 ? "10" : "5";
|
|
40534
|
+
onProgress(`Generating ${klingDuration2}s video with Kling...`);
|
|
40317
40535
|
const prompt3 = options.prompt || "Continue the scene naturally with subtle motion";
|
|
40318
40536
|
const result = await kling.generateVideo(prompt3, {
|
|
40319
40537
|
prompt: prompt3,
|
|
40320
40538
|
referenceImage: frameUrl,
|
|
40321
|
-
duration: parseInt(
|
|
40539
|
+
duration: parseInt(klingDuration2),
|
|
40322
40540
|
aspectRatio: options.ratio || "16:9",
|
|
40323
40541
|
mode: options.mode || "std"
|
|
40324
40542
|
});
|
|
@@ -40341,8 +40559,8 @@ async function executeFillGaps(options) {
|
|
|
40341
40559
|
const videoPath = resolve32(footageDir, videoFileName);
|
|
40342
40560
|
onProgress("Downloading generated video...");
|
|
40343
40561
|
const videoBuffer = await downloadVideo(finalResult.videoUrl);
|
|
40344
|
-
await
|
|
40345
|
-
generatedDuration = finalResult.duration || parseInt(
|
|
40562
|
+
await writeFile25(videoPath, videoBuffer);
|
|
40563
|
+
generatedDuration = finalResult.duration || parseInt(klingDuration2);
|
|
40346
40564
|
generatedVideos.push(videoPath);
|
|
40347
40565
|
humanLines.push(` Generated: ${videoFileName} (${generatedDuration}s)`);
|
|
40348
40566
|
let segmentIndex = 1;
|
|
@@ -40411,11 +40629,11 @@ async function executeFillGaps(options) {
|
|
|
40411
40629
|
`gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-seg${segmentIndex}.mp4`
|
|
40412
40630
|
);
|
|
40413
40631
|
const segVideoBuffer = await downloadVideo(segFinalResult.videoUrl);
|
|
40414
|
-
await
|
|
40632
|
+
await writeFile25(segVideoPath, segVideoBuffer);
|
|
40415
40633
|
const concatListPath = resolve32(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
|
|
40416
40634
|
const concatList = generatedVideos.map((v) => `file '${v}'`).join("\n") + `
|
|
40417
40635
|
file '${segVideoPath}'`;
|
|
40418
|
-
await
|
|
40636
|
+
await writeFile25(concatListPath, concatList);
|
|
40419
40637
|
const concatOutputPath = resolve32(
|
|
40420
40638
|
footageDir,
|
|
40421
40639
|
`gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-merged.mp4`
|
|
@@ -40473,7 +40691,7 @@ file '${segVideoPath}'`;
|
|
|
40473
40691
|
let outputPath = filePath;
|
|
40474
40692
|
if (generatedCount > 0) {
|
|
40475
40693
|
outputPath = options.output ? resolve32(process.cwd(), options.output) : filePath;
|
|
40476
|
-
await
|
|
40694
|
+
await writeFile25(outputPath, JSON.stringify(project.toJSON(), null, 2));
|
|
40477
40695
|
humanLines.push(`\u2714 Filled ${generatedCount} gap(s) with AI-generated video`);
|
|
40478
40696
|
humanLines.push(`Project saved: ${outputPath}`);
|
|
40479
40697
|
} else {
|
|
@@ -40567,7 +40785,7 @@ __export(ai_motion_exports, {
|
|
|
40567
40785
|
});
|
|
40568
40786
|
import { resolve as resolve33 } from "node:path";
|
|
40569
40787
|
import { existsSync as existsSync33 } from "node:fs";
|
|
40570
|
-
import { readFile as readFile25, writeFile as
|
|
40788
|
+
import { readFile as readFile25, writeFile as writeFile26 } from "node:fs/promises";
|
|
40571
40789
|
async function getOptionalGoogleApiKey() {
|
|
40572
40790
|
const configKey = await getApiKeyFromConfig("google");
|
|
40573
40791
|
if (configKey) return configKey;
|
|
@@ -40737,7 +40955,7 @@ Use this video understanding to place motion graphics in safe zones, match the c
|
|
|
40737
40955
|
const defaultOutput = options.video || options.image ? "motion-output.mp4" : options.render ? "motion.webm" : "motion.tsx";
|
|
40738
40956
|
const outputPath = resolve33(process.cwd(), options.output || defaultOutput);
|
|
40739
40957
|
const codePath = outputPath.replace(/\.\w+$/, ".tsx");
|
|
40740
|
-
await
|
|
40958
|
+
await writeFile26(codePath, component.code, "utf-8");
|
|
40741
40959
|
const shouldRender = options.render || !!options.video || !!options.image;
|
|
40742
40960
|
if (!shouldRender) {
|
|
40743
40961
|
return { success: true, codePath, componentName: component.name };
|
|
@@ -40973,8 +41191,8 @@ var init_ai_motion = __esm({
|
|
|
40973
41191
|
init_output();
|
|
40974
41192
|
init_validate();
|
|
40975
41193
|
MODEL_MAP2 = {
|
|
40976
|
-
sonnet: { provider: "claude", modelId: "claude-sonnet-
|
|
40977
|
-
opus: { provider: "claude", modelId: "claude-opus-
|
|
41194
|
+
sonnet: { provider: "claude", modelId: "claude-sonnet-5-5" },
|
|
41195
|
+
opus: { provider: "claude", modelId: "claude-opus-5-5" },
|
|
40978
41196
|
"opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
|
|
40979
41197
|
gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
|
|
40980
41198
|
"gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
|
|
@@ -41216,7 +41434,7 @@ __export(project_builder_exports, {
|
|
|
41216
41434
|
buildTempProject: () => buildTempProject,
|
|
41217
41435
|
resolveSourceUrl: () => resolveSourceUrl
|
|
41218
41436
|
});
|
|
41219
|
-
import { mkdtemp, mkdir as
|
|
41437
|
+
import { mkdtemp, mkdir as mkdir17, copyFile as copyFile5, writeFile as writeFile27, rm as rm5, readdir as readdir4 } from "node:fs/promises";
|
|
41220
41438
|
import { existsSync as existsSync34 } from "node:fs";
|
|
41221
41439
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
41222
41440
|
import { createRequire } from "node:module";
|
|
@@ -41224,7 +41442,7 @@ import * as path from "node:path";
|
|
|
41224
41442
|
async function buildTempProject(state, projectFileDir) {
|
|
41225
41443
|
const dir = await mkdtemp(path.join(tmpdir2(), "vibeframe-hf-"));
|
|
41226
41444
|
const assetsDir = path.join(dir, "assets");
|
|
41227
|
-
await
|
|
41445
|
+
await mkdir17(assetsDir, { recursive: true });
|
|
41228
41446
|
const copied = /* @__PURE__ */ new Map();
|
|
41229
41447
|
for (const source of state.sources) {
|
|
41230
41448
|
if (copied.has(source.id)) continue;
|
|
@@ -41240,10 +41458,10 @@ async function buildTempProject(state, projectFileDir) {
|
|
|
41240
41458
|
await copyLottieRuntime(dir);
|
|
41241
41459
|
}
|
|
41242
41460
|
const html = generateCompositionHtml(state);
|
|
41243
|
-
await
|
|
41461
|
+
await writeFile27(path.join(dir, "index.html"), html, "utf-8");
|
|
41244
41462
|
return {
|
|
41245
41463
|
dir,
|
|
41246
|
-
cleanup: () =>
|
|
41464
|
+
cleanup: () => rm5(dir, { recursive: true, force: true })
|
|
41247
41465
|
};
|
|
41248
41466
|
}
|
|
41249
41467
|
async function copyLottieRuntime(tempDir) {
|
|
@@ -41254,7 +41472,7 @@ async function copyLottieRuntime(tempDir) {
|
|
|
41254
41472
|
const wasmSrc = path.join(path.dirname(webEntry), "dotlottie-player.wasm");
|
|
41255
41473
|
const vendorDir = path.join(tempDir, "vendor");
|
|
41256
41474
|
const wcDest = path.join(vendorDir, "dotlottie-wc");
|
|
41257
|
-
await
|
|
41475
|
+
await mkdir17(wcDest, { recursive: true });
|
|
41258
41476
|
for (const file of await readdir4(wcDistDir)) {
|
|
41259
41477
|
if (file.endsWith(".map") || file.endsWith(".d.ts")) continue;
|
|
41260
41478
|
await copyFile5(path.join(wcDistDir, file), path.join(wcDest, file));
|
|
@@ -41362,9 +41580,9 @@ __export(motion_overlay_exports, {
|
|
|
41362
41580
|
executeMotionOverlay: () => executeMotionOverlay,
|
|
41363
41581
|
registerMotionOverlayCommand: () => registerMotionOverlayCommand
|
|
41364
41582
|
});
|
|
41365
|
-
import { mkdir as
|
|
41583
|
+
import { mkdir as mkdir18 } from "node:fs/promises";
|
|
41366
41584
|
import { existsSync as existsSync35 } from "node:fs";
|
|
41367
|
-
import { basename as basename9, dirname as
|
|
41585
|
+
import { basename as basename9, dirname as dirname15, extname as extname8, resolve as resolve35 } from "node:path";
|
|
41368
41586
|
function normalizeUnderstand2(value) {
|
|
41369
41587
|
return value === "off" || value === "required" || value === "auto" ? value : "auto";
|
|
41370
41588
|
}
|
|
@@ -41387,7 +41605,7 @@ function assertValidRequest(options) {
|
|
|
41387
41605
|
return "Provide a motion description, or pass --asset <logo.json|logo.lottie>.";
|
|
41388
41606
|
}
|
|
41389
41607
|
if (hasAsset) {
|
|
41390
|
-
const ext =
|
|
41608
|
+
const ext = extname8(options.asset).toLowerCase();
|
|
41391
41609
|
if (ext !== ".json" && ext !== ".lottie") {
|
|
41392
41610
|
return "Lottie overlay asset must be a .json or .lottie file.";
|
|
41393
41611
|
}
|
|
@@ -41510,7 +41728,7 @@ async function executeMotionOverlay(options) {
|
|
|
41510
41728
|
const scale = Math.max(0.01, Math.min(2, numberOption(options.scale, position === "full" ? 1 : 0.25)));
|
|
41511
41729
|
const opacity = Math.max(0, Math.min(1, numberOption(options.opacity, 1)));
|
|
41512
41730
|
const loop = options.loop ?? true;
|
|
41513
|
-
await
|
|
41731
|
+
await mkdir18(dirname15(outputPath), { recursive: true });
|
|
41514
41732
|
const backend = createHyperframesBackend();
|
|
41515
41733
|
const result2 = await backend.render({
|
|
41516
41734
|
projectState: buildLottieTimelineState({
|
|
@@ -41536,7 +41754,7 @@ async function executeMotionOverlay(options) {
|
|
|
41536
41754
|
return { success: true, outputPath, provider: "lottie" };
|
|
41537
41755
|
}
|
|
41538
41756
|
const duration = options.duration ?? await ffprobeDuration(absVideo).catch(() => void 0);
|
|
41539
|
-
await
|
|
41757
|
+
await mkdir18(dirname15(outputPath), { recursive: true });
|
|
41540
41758
|
const result = await executeMotion({
|
|
41541
41759
|
description: options.description.trim(),
|
|
41542
41760
|
video: absVideo,
|
|
@@ -41664,8 +41882,8 @@ __export(edit_cmd_exports, {
|
|
|
41664
41882
|
executeSpeedRamp: () => executeSpeedRamp,
|
|
41665
41883
|
executeUpscale: () => executeUpscale
|
|
41666
41884
|
});
|
|
41667
|
-
import { resolve as resolve36, dirname as
|
|
41668
|
-
import { readFile as readFile26, writeFile as
|
|
41885
|
+
import { resolve as resolve36, dirname as dirname16 } from "node:path";
|
|
41886
|
+
import { readFile as readFile26, writeFile as writeFile28, mkdir as mkdir19 } from "node:fs/promises";
|
|
41669
41887
|
async function executeGrade(options) {
|
|
41670
41888
|
const { videoPath, style, preset, output, analyzeOnly, apiKey } = options;
|
|
41671
41889
|
try {
|
|
@@ -41858,6 +42076,7 @@ var init_edit_cmd = __esm({
|
|
|
41858
42076
|
init_output();
|
|
41859
42077
|
init_validate();
|
|
41860
42078
|
init_cost_tier();
|
|
42079
|
+
init_image_file();
|
|
41861
42080
|
editCommand = new Command("edit").alias("ed").description(
|
|
41862
42081
|
"Edit and post-process media (silence-cut, caption, grade, reframe, upscale...)"
|
|
41863
42082
|
).addHelpText(
|
|
@@ -42293,7 +42512,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42293
42512
|
console.log();
|
|
42294
42513
|
if (options.keyframes) {
|
|
42295
42514
|
const keyframesPath = resolve36(process.cwd(), options.keyframes);
|
|
42296
|
-
await
|
|
42515
|
+
await writeFile28(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
|
|
42297
42516
|
console.log(source_default.green(`Keyframes saved to: ${keyframesPath}`));
|
|
42298
42517
|
}
|
|
42299
42518
|
if (options.analyzeOnly) {
|
|
@@ -42317,7 +42536,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42317
42536
|
exitWithError(generalError(`Reframe failed: ${msg}`));
|
|
42318
42537
|
}
|
|
42319
42538
|
});
|
|
42320
|
-
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
|
|
42539
|
+
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) => {
|
|
42321
42540
|
const startedAt = Date.now();
|
|
42322
42541
|
try {
|
|
42323
42542
|
if (args.length < 2) {
|
|
@@ -42376,14 +42595,16 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42376
42595
|
const grok = new GrokProvider();
|
|
42377
42596
|
await grok.initialize({ apiKey });
|
|
42378
42597
|
result = await grok.editImage(imageBuffers[0], prompt3, {
|
|
42598
|
+
...resolveGrokImageModel(options.model),
|
|
42379
42599
|
aspectRatio: options.ratio
|
|
42380
42600
|
});
|
|
42381
42601
|
} else {
|
|
42382
42602
|
const editModelNames = {
|
|
42383
|
-
flash: "gemini-
|
|
42384
|
-
"3.1-flash": "gemini-3.1-flash-image
|
|
42385
|
-
latest: "gemini-3.1-flash-image
|
|
42386
|
-
|
|
42603
|
+
flash: "gemini-3.1-flash-image",
|
|
42604
|
+
"3.1-flash": "gemini-3.1-flash-image",
|
|
42605
|
+
latest: "gemini-3.1-flash-image",
|
|
42606
|
+
lite: "gemini-3.1-flash-lite-image",
|
|
42607
|
+
pro: "gemini-3-pro-image"
|
|
42387
42608
|
};
|
|
42388
42609
|
const editModelName = editModelNames[options.model] || editModelNames.flash;
|
|
42389
42610
|
spinner2.text = `Editing with ${editModelName}...`;
|
|
@@ -42394,15 +42615,6 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42394
42615
|
aspectRatio: options.ratio,
|
|
42395
42616
|
resolution: options.size
|
|
42396
42617
|
});
|
|
42397
|
-
const fallbackModels = ["latest", "3.1-flash"];
|
|
42398
|
-
if (!result.success && fallbackModels.includes(options.model)) {
|
|
42399
|
-
spinner2.text = `${source_default.dim(result.error || `${editModelName} failed`)} \u2014 retrying with flash...`;
|
|
42400
|
-
result = await gemini.editImage(imageBuffers, prompt3, {
|
|
42401
|
-
model: "flash",
|
|
42402
|
-
aspectRatio: options.ratio,
|
|
42403
|
-
resolution: options.size
|
|
42404
|
-
});
|
|
42405
|
-
}
|
|
42406
42618
|
}
|
|
42407
42619
|
if (!result.success || !result.images || result.images.length === 0) {
|
|
42408
42620
|
spinner2.fail(result.error || "Image editing failed");
|
|
@@ -42412,14 +42624,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42412
42624
|
const img = result.images[0];
|
|
42413
42625
|
const outputPath = resolve36(process.cwd(), options.output);
|
|
42414
42626
|
const saveImage = async () => {
|
|
42415
|
-
await
|
|
42627
|
+
await mkdir19(dirname16(outputPath), { recursive: true });
|
|
42416
42628
|
if (img.base64) {
|
|
42417
42629
|
const buffer = Buffer.from(img.base64, "base64");
|
|
42418
|
-
await
|
|
42630
|
+
await writeImageFile(outputPath, buffer);
|
|
42419
42631
|
} else if (img.url) {
|
|
42420
42632
|
const resp = await fetch(img.url);
|
|
42421
42633
|
const arrayBuf = await resp.arrayBuffer();
|
|
42422
|
-
await
|
|
42634
|
+
await writeImageFile(outputPath, Buffer.from(arrayBuf));
|
|
42423
42635
|
}
|
|
42424
42636
|
};
|
|
42425
42637
|
const resultModel = result.model;
|
|
@@ -42638,8 +42850,8 @@ __export(ai_image_exports, {
|
|
|
42638
42850
|
executeImageGenerate: () => executeImageGenerate,
|
|
42639
42851
|
executeThumbnailBestFrame: () => executeThumbnailBestFrame
|
|
42640
42852
|
});
|
|
42641
|
-
import { resolve as resolve38, dirname as
|
|
42642
|
-
import { readFile as readFile27,
|
|
42853
|
+
import { resolve as resolve38, dirname as dirname18 } from "node:path";
|
|
42854
|
+
import { readFile as readFile27, mkdir as mkdir21 } from "node:fs/promises";
|
|
42643
42855
|
import { existsSync as existsSync37 } from "node:fs";
|
|
42644
42856
|
async function executeImageGenerate(options) {
|
|
42645
42857
|
const {
|
|
@@ -42682,8 +42894,8 @@ async function executeImageGenerate(options) {
|
|
|
42682
42894
|
return { success: false, error: "No image data available" };
|
|
42683
42895
|
}
|
|
42684
42896
|
outputPath = resolve38(process.cwd(), output);
|
|
42685
|
-
await
|
|
42686
|
-
await
|
|
42897
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
42898
|
+
await writeImageFile(outputPath, buffer);
|
|
42687
42899
|
}
|
|
42688
42900
|
return {
|
|
42689
42901
|
success: true,
|
|
@@ -42717,8 +42929,8 @@ async function executeImageGenerate(options) {
|
|
|
42717
42929
|
const img = result.images[0];
|
|
42718
42930
|
if (img.base64) {
|
|
42719
42931
|
outputPath = resolve38(process.cwd(), output);
|
|
42720
|
-
await
|
|
42721
|
-
await
|
|
42932
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
42933
|
+
await writeImageFile(outputPath, Buffer.from(img.base64, "base64"));
|
|
42722
42934
|
}
|
|
42723
42935
|
}
|
|
42724
42936
|
return {
|
|
@@ -42731,10 +42943,11 @@ async function executeImageGenerate(options) {
|
|
|
42731
42943
|
} else if (provider === "grok") {
|
|
42732
42944
|
const key = apiKey || process.env.XAI_API_KEY;
|
|
42733
42945
|
if (!key) return { success: false, error: "XAI_API_KEY required" };
|
|
42734
|
-
const
|
|
42735
|
-
await
|
|
42736
|
-
const result = await
|
|
42737
|
-
|
|
42946
|
+
const grok = new GrokProvider();
|
|
42947
|
+
await grok.initialize({ apiKey: key });
|
|
42948
|
+
const result = await grok.generateImage(prompt3, {
|
|
42949
|
+
...resolveGrokImageModel(model),
|
|
42950
|
+
aspectRatio: ratio,
|
|
42738
42951
|
n: count
|
|
42739
42952
|
});
|
|
42740
42953
|
if (!result.success || !result.images) {
|
|
@@ -42753,8 +42966,8 @@ async function executeImageGenerate(options) {
|
|
|
42753
42966
|
return { success: false, error: "No image data available" };
|
|
42754
42967
|
}
|
|
42755
42968
|
outputPath = resolve38(process.cwd(), output);
|
|
42756
|
-
await
|
|
42757
|
-
await
|
|
42969
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
42970
|
+
await writeImageFile(outputPath, buffer);
|
|
42758
42971
|
}
|
|
42759
42972
|
return {
|
|
42760
42973
|
success: true,
|
|
@@ -42812,8 +43025,8 @@ async function executeGeminiEdit(options) {
|
|
|
42812
43025
|
let outputPath;
|
|
42813
43026
|
if (img.base64) {
|
|
42814
43027
|
outputPath = resolve38(process.cwd(), output);
|
|
42815
|
-
await
|
|
42816
|
-
await
|
|
43028
|
+
await mkdir21(dirname18(outputPath), { recursive: true });
|
|
43029
|
+
await writeImageFile(outputPath, Buffer.from(img.base64, "base64"));
|
|
42817
43030
|
}
|
|
42818
43031
|
return {
|
|
42819
43032
|
success: true,
|
|
@@ -42887,6 +43100,7 @@ var init_ai_image = __esm({
|
|
|
42887
43100
|
"use strict";
|
|
42888
43101
|
init_dist2();
|
|
42889
43102
|
init_exec_safe();
|
|
43103
|
+
init_image_file();
|
|
42890
43104
|
}
|
|
42891
43105
|
});
|
|
42892
43106
|
|
|
@@ -42898,7 +43112,7 @@ __export(ai_analyze_exports, {
|
|
|
42898
43112
|
registerAnalyzeCommands: () => registerAnalyzeCommands
|
|
42899
43113
|
});
|
|
42900
43114
|
import { readFile as readFile28 } from "node:fs/promises";
|
|
42901
|
-
import { extname as
|
|
43115
|
+
import { extname as extname9, resolve as resolve39 } from "node:path";
|
|
42902
43116
|
import { existsSync as existsSync38 } from "node:fs";
|
|
42903
43117
|
async function executeGeminiVideo(options) {
|
|
42904
43118
|
try {
|
|
@@ -42955,7 +43169,7 @@ async function executeAnalyze(options) {
|
|
|
42955
43169
|
const isYouTube = source.includes("youtube.com") || source.includes("youtu.be");
|
|
42956
43170
|
const isImageUrl = /^https?:\/\/.+\.(png|jpg|jpeg|webp|gif)(\?.*)?$/i.test(source);
|
|
42957
43171
|
const isVideoUrl = /^https?:\/\/.+\.(mp4|mov|webm)(\?.*)?$/i.test(source);
|
|
42958
|
-
const ext =
|
|
43172
|
+
const ext = extname9(source).toLowerCase();
|
|
42959
43173
|
const imageExts = [".png", ".jpg", ".jpeg", ".webp", ".gif"];
|
|
42960
43174
|
const videoExts = [".mp4", ".mov", ".webm", ".avi", ".mkv"];
|
|
42961
43175
|
const isLocalImage = imageExts.includes(ext);
|
|
@@ -43363,7 +43577,7 @@ async function executeSoundEffect(options) {
|
|
|
43363
43577
|
}
|
|
43364
43578
|
}
|
|
43365
43579
|
function registerSoundEffectCommand(parent) {
|
|
43366
|
-
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-
|
|
43580
|
+
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) => {
|
|
43367
43581
|
const startedAt = Date.now();
|
|
43368
43582
|
try {
|
|
43369
43583
|
rejectControlChars(prompt3);
|
|
@@ -43663,9 +43877,9 @@ var init_speech = __esm({
|
|
|
43663
43877
|
});
|
|
43664
43878
|
|
|
43665
43879
|
// src/commands/generate/thumbnail.ts
|
|
43666
|
-
import { resolve as resolve47, dirname as
|
|
43880
|
+
import { resolve as resolve47, dirname as dirname19, basename as basename13, extname as extname10 } from "node:path";
|
|
43667
43881
|
import { existsSync as existsSync42 } from "node:fs";
|
|
43668
|
-
import { writeFile as writeFile33, mkdir as
|
|
43882
|
+
import { writeFile as writeFile33, mkdir as mkdir22 } from "node:fs/promises";
|
|
43669
43883
|
function registerThumbnailCommand(parent) {
|
|
43670
43884
|
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) => {
|
|
43671
43885
|
const startedAt = Date.now();
|
|
@@ -43688,7 +43902,7 @@ function registerThumbnailCommand(parent) {
|
|
|
43688
43902
|
);
|
|
43689
43903
|
}
|
|
43690
43904
|
const apiKey2 = await requireApiKey("GOOGLE_API_KEY", "Google", options.apiKey);
|
|
43691
|
-
const name = basename13(options.bestFrame,
|
|
43905
|
+
const name = basename13(options.bestFrame, extname10(options.bestFrame));
|
|
43692
43906
|
const outputPath = options.output || `${name}-thumbnail.png`;
|
|
43693
43907
|
const spinner3 = ora("Analyzing video for best frame...").start();
|
|
43694
43908
|
const result2 = await executeThumbnailBestFrame({
|
|
@@ -43756,7 +43970,7 @@ function registerThumbnailCommand(parent) {
|
|
|
43756
43970
|
throw new Error("No image data available");
|
|
43757
43971
|
}
|
|
43758
43972
|
outputPath = resolve47(process.cwd(), options.output);
|
|
43759
|
-
await
|
|
43973
|
+
await mkdir22(dirname19(outputPath), { recursive: true });
|
|
43760
43974
|
await writeFile33(outputPath, buffer);
|
|
43761
43975
|
}
|
|
43762
43976
|
outputSuccess({
|
|
@@ -43787,7 +44001,7 @@ function registerThumbnailCommand(parent) {
|
|
|
43787
44001
|
throw new Error("No image data available");
|
|
43788
44002
|
}
|
|
43789
44003
|
const outputPath = resolve47(process.cwd(), options.output);
|
|
43790
|
-
await
|
|
44004
|
+
await mkdir22(dirname19(outputPath), { recursive: true });
|
|
43791
44005
|
await writeFile33(outputPath, buffer);
|
|
43792
44006
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
43793
44007
|
} catch {
|
|
@@ -43818,7 +44032,7 @@ var init_thumbnail = __esm({
|
|
|
43818
44032
|
import { resolve as resolve48 } from "node:path";
|
|
43819
44033
|
import { writeFile as writeFile34 } from "node:fs/promises";
|
|
43820
44034
|
function registerVideoExtendCommand(parent) {
|
|
43821
|
-
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.
|
|
44035
|
+
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) => {
|
|
43822
44036
|
const startedAt = Date.now();
|
|
43823
44037
|
try {
|
|
43824
44038
|
const provider = (options.provider || "kling").toLowerCase();
|
|
@@ -43936,12 +44150,7 @@ function registerVideoExtendCommand(parent) {
|
|
|
43936
44150
|
const spinner2 = ora("Initializing Veo...").start();
|
|
43937
44151
|
const gemini = new GeminiProvider();
|
|
43938
44152
|
await gemini.initialize({ apiKey });
|
|
43939
|
-
const
|
|
43940
|
-
"3.0": "veo-3.0-generate-preview",
|
|
43941
|
-
"3.1": "veo-3.1-generate-preview",
|
|
43942
|
-
"3.1-fast": "veo-3.1-fast-generate-preview"
|
|
43943
|
-
};
|
|
43944
|
-
const veoModel = veoModelMap[options.veoModel] || "veo-3.1-generate-preview";
|
|
44153
|
+
const veoModel = resolveVeoModel(options.veoModel);
|
|
43945
44154
|
spinner2.text = "Starting video extension...";
|
|
43946
44155
|
const result = await gemini.extendVideo(id, options.prompt, {
|
|
43947
44156
|
duration: parseInt(options.duration),
|
|
@@ -44102,10 +44311,15 @@ var init_provider_resolver = __esm({
|
|
|
44102
44311
|
|
|
44103
44312
|
// src/commands/_shared/openai-image.ts
|
|
44104
44313
|
function resolveOpenAIImageModel(modelAlias) {
|
|
44105
|
-
const
|
|
44314
|
+
const alias = modelAlias?.trim() ?? "";
|
|
44315
|
+
for (const [id, model] of Object.entries(OPENAI_IMAGE_MODELS)) {
|
|
44316
|
+
if (alias === id || model.aliases.includes(alias)) {
|
|
44317
|
+
return { openaiModel: id, modelLabel: model.label };
|
|
44318
|
+
}
|
|
44319
|
+
}
|
|
44106
44320
|
return {
|
|
44107
|
-
openaiModel:
|
|
44108
|
-
modelLabel:
|
|
44321
|
+
openaiModel: OPENAI_IMAGE_DEFAULT_MODEL,
|
|
44322
|
+
modelLabel: OPENAI_IMAGE_MODELS[OPENAI_IMAGE_DEFAULT_MODEL].label
|
|
44109
44323
|
};
|
|
44110
44324
|
}
|
|
44111
44325
|
async function executeOpenAIImageGenerate(prompt3, options, ctx) {
|
|
@@ -44121,17 +44335,24 @@ async function executeOpenAIImageGenerate(prompt3, options, ctx) {
|
|
|
44121
44335
|
});
|
|
44122
44336
|
return { result, openaiModel, modelLabel };
|
|
44123
44337
|
}
|
|
44338
|
+
var OPENAI_IMAGE_MODELS;
|
|
44124
44339
|
var init_openai_image2 = __esm({
|
|
44125
44340
|
"src/commands/_shared/openai-image.ts"() {
|
|
44126
44341
|
"use strict";
|
|
44127
44342
|
init_dist2();
|
|
44343
|
+
OPENAI_IMAGE_MODELS = {
|
|
44344
|
+
"gpt-image-2.5-sunburst": { label: "GPT Image 2.5 Sunburst", aliases: ["2.5", "sunburst"] },
|
|
44345
|
+
"gpt-image-2.5-flare": { label: "GPT Image 2.5 Flare", aliases: ["flare", "2.5-flare"] },
|
|
44346
|
+
"gpt-image-2": { label: "GPT Image 2", aliases: ["2"] },
|
|
44347
|
+
"gpt-image-1.5": { label: "GPT Image 1.5", aliases: ["1.5"] }
|
|
44348
|
+
};
|
|
44128
44349
|
}
|
|
44129
44350
|
});
|
|
44130
44351
|
|
|
44131
44352
|
// src/commands/generate/image.ts
|
|
44132
|
-
import { resolve as resolve49, dirname as
|
|
44353
|
+
import { resolve as resolve49, dirname as dirname20 } from "node:path";
|
|
44133
44354
|
import { fileURLToPath } from "node:url";
|
|
44134
|
-
import {
|
|
44355
|
+
import { mkdir as mkdir23 } from "node:fs/promises";
|
|
44135
44356
|
function registerImageCommand(parent) {
|
|
44136
44357
|
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(
|
|
44137
44358
|
"-p, --provider <provider>",
|
|
@@ -44142,7 +44363,7 @@ function registerImageCommand(parent) {
|
|
|
44142
44363
|
"1:1"
|
|
44143
44364
|
).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(
|
|
44144
44365
|
"-m, --model <model>",
|
|
44145
|
-
"Model. Gemini: flash
|
|
44366
|
+
"Model. Gemini: flash (default), lite, pro. OpenAI: 2.5 (default), flare, 2, 1.5. Grok: pro"
|
|
44146
44367
|
).option("--dry-run", "Preview parameters without executing").addHelpText(
|
|
44147
44368
|
"after",
|
|
44148
44369
|
`
|
|
@@ -44245,7 +44466,7 @@ Examples:
|
|
|
44245
44466
|
const apiKey = await requireApiKey(envKey, providerName, options.apiKey);
|
|
44246
44467
|
const spinner2 = ora(`Generating image with ${providerName}...`).start();
|
|
44247
44468
|
if (provider === "openai") {
|
|
44248
|
-
const { result, modelLabel } = await executeOpenAIImageGenerate(prompt3, options, {
|
|
44469
|
+
const { result, modelLabel, openaiModel } = await executeOpenAIImageGenerate(prompt3, options, {
|
|
44249
44470
|
apiKey
|
|
44250
44471
|
});
|
|
44251
44472
|
if (!result.success || !result.images) {
|
|
@@ -44268,14 +44489,16 @@ Examples:
|
|
|
44268
44489
|
} else {
|
|
44269
44490
|
throw new Error("No image data available");
|
|
44270
44491
|
}
|
|
44271
|
-
await
|
|
44272
|
-
await
|
|
44492
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44493
|
+
await writeImageFile(outputPath, buffer);
|
|
44273
44494
|
}
|
|
44274
44495
|
outputSuccess({
|
|
44275
44496
|
command: "generate image",
|
|
44276
44497
|
startedAt,
|
|
44277
44498
|
data: {
|
|
44278
44499
|
provider: "openai",
|
|
44500
|
+
model: modelLabel,
|
|
44501
|
+
modelId: openaiModel,
|
|
44279
44502
|
images: result.images.map((img) => ({
|
|
44280
44503
|
url: img.url,
|
|
44281
44504
|
revisedPrompt: img.revisedPrompt
|
|
@@ -44315,8 +44538,8 @@ Examples:
|
|
|
44315
44538
|
throw new Error("No image data available");
|
|
44316
44539
|
}
|
|
44317
44540
|
const outputPath = resolve49(process.cwd(), options.output);
|
|
44318
|
-
await
|
|
44319
|
-
await
|
|
44541
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44542
|
+
await writeImageFile(outputPath, buffer);
|
|
44320
44543
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
44321
44544
|
} catch (err) {
|
|
44322
44545
|
saveSpinner.fail(
|
|
@@ -44325,7 +44548,7 @@ Examples:
|
|
|
44325
44548
|
}
|
|
44326
44549
|
}
|
|
44327
44550
|
} else if (provider === "gemini") {
|
|
44328
|
-
const validGeminiModels = ["flash", "3.1-flash", "latest", "pro"];
|
|
44551
|
+
const validGeminiModels = ["flash", "3.1-flash", "latest", "lite", "pro"];
|
|
44329
44552
|
if (options.model && !validGeminiModels.includes(options.model)) {
|
|
44330
44553
|
console.warn(
|
|
44331
44554
|
source_default.yellow(
|
|
@@ -44358,26 +44581,17 @@ Examples:
|
|
|
44358
44581
|
const gemini = new GeminiProvider();
|
|
44359
44582
|
await gemini.initialize({ apiKey });
|
|
44360
44583
|
const geminiModelNames = {
|
|
44361
|
-
flash: "Nano Banana",
|
|
44584
|
+
flash: "Nano Banana 2",
|
|
44362
44585
|
"3.1-flash": "Nano Banana 2",
|
|
44363
44586
|
latest: "Nano Banana 2",
|
|
44587
|
+
lite: "Nano Banana 2 Lite",
|
|
44364
44588
|
pro: "Nano Banana Pro"
|
|
44365
44589
|
};
|
|
44366
|
-
const
|
|
44367
|
-
|
|
44590
|
+
const usedLabel = geminiModelNames[options.model] || "Nano Banana 2";
|
|
44591
|
+
const result = await gemini.generateImage(prompt3, {
|
|
44368
44592
|
model: options.model,
|
|
44369
44593
|
aspectRatio: options.ratio
|
|
44370
44594
|
});
|
|
44371
|
-
let usedLabel = modelLabel;
|
|
44372
|
-
const fallbackModels = ["latest", "3.1-flash"];
|
|
44373
|
-
if (!result.success && options.model && fallbackModels.includes(options.model)) {
|
|
44374
|
-
spinner2.text = `${source_default.dim(result.error || "Failed")} \u2014 retrying with Nano Banana (flash)...`;
|
|
44375
|
-
result = await gemini.generateImage(prompt3, {
|
|
44376
|
-
model: "flash",
|
|
44377
|
-
aspectRatio: options.ratio
|
|
44378
|
-
});
|
|
44379
|
-
usedLabel = "Nano Banana (fallback)";
|
|
44380
|
-
}
|
|
44381
44595
|
if (!result.success || !result.images) {
|
|
44382
44596
|
spinner2.fail(result.error || "Image generation failed");
|
|
44383
44597
|
exitWithError(apiError(result.error || "Image generation failed", true));
|
|
@@ -44390,16 +44604,17 @@ Examples:
|
|
|
44390
44604
|
if (outputPath && result.images.length > 0) {
|
|
44391
44605
|
const img = result.images[0];
|
|
44392
44606
|
const buffer = Buffer.from(img.base64, "base64");
|
|
44393
|
-
await
|
|
44394
|
-
await
|
|
44607
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44608
|
+
await writeImageFile(outputPath, buffer);
|
|
44395
44609
|
}
|
|
44396
44610
|
outputSuccess({
|
|
44397
44611
|
command: "generate image",
|
|
44398
44612
|
startedAt,
|
|
44399
|
-
warnings:
|
|
44613
|
+
warnings: [],
|
|
44400
44614
|
data: {
|
|
44401
44615
|
provider: "gemini",
|
|
44402
44616
|
model: usedLabel,
|
|
44617
|
+
modelId: result.model,
|
|
44403
44618
|
images: result.images.map((img) => ({
|
|
44404
44619
|
mimeType: img.mimeType
|
|
44405
44620
|
})),
|
|
@@ -44423,8 +44638,8 @@ Examples:
|
|
|
44423
44638
|
const img = result.images[0];
|
|
44424
44639
|
const buffer = Buffer.from(img.base64, "base64");
|
|
44425
44640
|
const outputPath = resolve49(process.cwd(), options.output);
|
|
44426
|
-
await
|
|
44427
|
-
await
|
|
44641
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44642
|
+
await writeImageFile(outputPath, buffer);
|
|
44428
44643
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
44429
44644
|
} catch (err) {
|
|
44430
44645
|
saveSpinner.fail(
|
|
@@ -44462,6 +44677,7 @@ Examples:
|
|
|
44462
44677
|
options.ratio = "1:1";
|
|
44463
44678
|
}
|
|
44464
44679
|
const result = await grok.generateImage(prompt3, {
|
|
44680
|
+
...resolveGrokImageModel(options.model),
|
|
44465
44681
|
aspectRatio: options.ratio || "1:1",
|
|
44466
44682
|
n: parseInt(options.count)
|
|
44467
44683
|
});
|
|
@@ -44483,14 +44699,15 @@ Examples:
|
|
|
44483
44699
|
} else {
|
|
44484
44700
|
throw new Error("No image data available");
|
|
44485
44701
|
}
|
|
44486
|
-
await
|
|
44487
|
-
await
|
|
44702
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44703
|
+
await writeImageFile(outputPath, buffer);
|
|
44488
44704
|
}
|
|
44489
44705
|
outputSuccess({
|
|
44490
44706
|
command: "generate image",
|
|
44491
44707
|
startedAt,
|
|
44492
44708
|
data: {
|
|
44493
44709
|
provider: "grok",
|
|
44710
|
+
modelId: resolveGrokImageModel(options.model).model,
|
|
44494
44711
|
images: result.images.map((img) => ({ url: img.url })),
|
|
44495
44712
|
outputPath
|
|
44496
44713
|
}
|
|
@@ -44524,8 +44741,8 @@ Examples:
|
|
|
44524
44741
|
throw new Error("No image data available");
|
|
44525
44742
|
}
|
|
44526
44743
|
const outputPath = resolve49(process.cwd(), options.output);
|
|
44527
|
-
await
|
|
44528
|
-
await
|
|
44744
|
+
await mkdir23(dirname20(outputPath), { recursive: true });
|
|
44745
|
+
await writeImageFile(outputPath, buffer);
|
|
44529
44746
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
44530
44747
|
} catch (err) {
|
|
44531
44748
|
saveSpinner.fail(
|
|
@@ -44536,7 +44753,7 @@ Examples:
|
|
|
44536
44753
|
} else if (provider === "runway") {
|
|
44537
44754
|
const { spawn: spawn2 } = await import("child_process");
|
|
44538
44755
|
const __filename = fileURLToPath(import.meta.url);
|
|
44539
|
-
const __dirname =
|
|
44756
|
+
const __dirname = dirname20(__filename);
|
|
44540
44757
|
const scriptPath = resolve49(
|
|
44541
44758
|
__dirname,
|
|
44542
44759
|
"../../../../.claude/skills/runway-video/scripts/image.py"
|
|
@@ -44607,6 +44824,7 @@ var init_image = __esm({
|
|
|
44607
44824
|
init_validate();
|
|
44608
44825
|
init_provider_resolver();
|
|
44609
44826
|
init_openai_image2();
|
|
44827
|
+
init_image_file();
|
|
44610
44828
|
}
|
|
44611
44829
|
});
|
|
44612
44830
|
|
|
@@ -45555,11 +45773,11 @@ var init_dist3 = __esm({
|
|
|
45555
45773
|
|
|
45556
45774
|
// src/commands/generate/video.ts
|
|
45557
45775
|
import { resolve as resolve50 } from "node:path";
|
|
45558
|
-
import { readFile as readFile33, writeFile as
|
|
45776
|
+
import { readFile as readFile33, writeFile as writeFile35 } from "node:fs/promises";
|
|
45559
45777
|
function registerVideoCommand(parent) {
|
|
45560
45778
|
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(
|
|
45561
45779
|
"-p, --provider <provider>",
|
|
45562
|
-
"Provider: seedance (ByteDance Seedance 2.0 via fal.ai), grok, kling, runway,
|
|
45780
|
+
"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."
|
|
45563
45781
|
).option(
|
|
45564
45782
|
"-k, --api-key <key>",
|
|
45565
45783
|
"API key (or set FAL_API_KEY / XAI_API_KEY / RUNWAY_API_SECRET / KLING_API_KEY / GOOGLE_API_KEY env)"
|
|
@@ -45572,12 +45790,12 @@ function registerVideoCommand(parent) {
|
|
|
45572
45790
|
"Aspect ratio: 16:9, 9:16, or 1:1 (auto-detected from image if omitted)"
|
|
45573
45791
|
).option("--seed <number>", "Random seed for reproducibility (Runway only)").option("--mode <mode>", "Generation mode: std or pro (Kling only)", "std").option(
|
|
45574
45792
|
"--seedance-model <model>",
|
|
45575
|
-
"Seedance variant: quality
|
|
45793
|
+
"Seedance variant: quality (2.0), fast, or 2.5 (fal.ai only)",
|
|
45576
45794
|
"quality"
|
|
45577
|
-
).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(
|
|
45795
|
+
).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(
|
|
45578
45796
|
"--ref-images <paths...>",
|
|
45579
45797
|
"Reference images for Seedance reference-to-video or Veo character consistency"
|
|
45580
|
-
).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.
|
|
45798
|
+
).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(
|
|
45581
45799
|
"--runway-model <model>",
|
|
45582
45800
|
"Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)",
|
|
45583
45801
|
"gen4.5"
|
|
@@ -45638,7 +45856,7 @@ Examples:
|
|
|
45638
45856
|
exitWithError(
|
|
45639
45857
|
usageError(
|
|
45640
45858
|
`Invalid provider: ${provider}`,
|
|
45641
|
-
"Available providers: seedance, grok, kling, runway,
|
|
45859
|
+
"Available providers: seedance, grok, kling, runway, omni, veo. `fal` is a deprecated alias for seedance."
|
|
45642
45860
|
)
|
|
45643
45861
|
);
|
|
45644
45862
|
}
|
|
@@ -45706,13 +45924,7 @@ Examples:
|
|
|
45706
45924
|
options.ratio = "16:9";
|
|
45707
45925
|
}
|
|
45708
45926
|
if (options.dryRun) {
|
|
45709
|
-
const costUsd = provider === "seedance" || provider === "fal" ?
|
|
45710
|
-
durationSec: Number(options.duration) || 5,
|
|
45711
|
-
resolution: options.resolution,
|
|
45712
|
-
aspectRatio: options.ratio,
|
|
45713
|
-
fast: options.seedanceModel === "fast",
|
|
45714
|
-
hasVideoReference: Boolean(options.refVideos)
|
|
45715
|
-
}) : void 0;
|
|
45927
|
+
const costUsd = provider === "seedance" || provider === "fal" ? realRunCost(provider, options).costUsd : void 0;
|
|
45716
45928
|
outputSuccess({
|
|
45717
45929
|
command: "generate video",
|
|
45718
45930
|
startedAt,
|
|
@@ -45730,6 +45942,8 @@ Examples:
|
|
|
45730
45942
|
resolution: options.resolution,
|
|
45731
45943
|
veoModel: options.veoModel,
|
|
45732
45944
|
seedanceModel: options.seedanceModel,
|
|
45945
|
+
grokModel: options.grokModel,
|
|
45946
|
+
klingModel: options.klingModel,
|
|
45733
45947
|
refImages: options.refImages,
|
|
45734
45948
|
refVideos: options.refVideos,
|
|
45735
45949
|
refAudio: options.refAudio,
|
|
@@ -45751,7 +45965,7 @@ Examples:
|
|
|
45751
45965
|
runway: "Runway",
|
|
45752
45966
|
kling: "Kling",
|
|
45753
45967
|
veo: "Veo",
|
|
45754
|
-
omni: "Gemini Omni
|
|
45968
|
+
omni: "Gemini Omni 1.1 Flash",
|
|
45755
45969
|
grok: "Grok",
|
|
45756
45970
|
seedance: "Seedance 2.0 via fal.ai"
|
|
45757
45971
|
};
|
|
@@ -45850,6 +46064,7 @@ Examples:
|
|
|
45850
46064
|
}
|
|
45851
46065
|
result = await kling.generateVideo(prompt3, {
|
|
45852
46066
|
prompt: prompt3,
|
|
46067
|
+
model: resolveKlingModel(options.klingModel),
|
|
45853
46068
|
referenceImage: klingImage,
|
|
45854
46069
|
duration: parseInt(options.duration),
|
|
45855
46070
|
aspectRatio: options.ratio,
|
|
@@ -45899,12 +46114,7 @@ Examples:
|
|
|
45899
46114
|
} else if (provider === "veo") {
|
|
45900
46115
|
const gemini = new GeminiProvider();
|
|
45901
46116
|
await gemini.initialize({ apiKey });
|
|
45902
|
-
const
|
|
45903
|
-
"3.0": "veo-3.0-generate-preview",
|
|
45904
|
-
"3.1": "veo-3.1-generate-preview",
|
|
45905
|
-
"3.1-fast": "veo-3.1-fast-generate-preview"
|
|
45906
|
-
};
|
|
45907
|
-
const veoModel = veoModelMap[options.veoModel] || "veo-3.1-fast-generate-preview";
|
|
46117
|
+
const veoModel = resolveVeoModel(options.veoModel);
|
|
45908
46118
|
const veoDuration = parseInt(options.duration) <= 6 ? 6 : 8;
|
|
45909
46119
|
let lastFrame;
|
|
45910
46120
|
if (options.lastFrame) {
|
|
@@ -45978,9 +46188,12 @@ Examples:
|
|
|
45978
46188
|
await grok.initialize({ apiKey });
|
|
45979
46189
|
result = await grok.generateVideo(prompt3, {
|
|
45980
46190
|
prompt: prompt3,
|
|
46191
|
+
model: resolveGrokVideoModel(options.grokModel),
|
|
45981
46192
|
referenceImage,
|
|
45982
46193
|
duration: parseInt(options.duration),
|
|
45983
|
-
aspectRatio: options.ratio
|
|
46194
|
+
aspectRatio: options.ratio,
|
|
46195
|
+
resolution: options.resolution,
|
|
46196
|
+
generateAudio: options.generateAudio
|
|
45984
46197
|
});
|
|
45985
46198
|
if (result.status === "failed") {
|
|
45986
46199
|
spinner2.fail(result.error || "Failed to start generation");
|
|
@@ -46070,9 +46283,8 @@ Examples:
|
|
|
46070
46283
|
exitWithError(apiError(message, true));
|
|
46071
46284
|
}
|
|
46072
46285
|
}
|
|
46073
|
-
|
|
46074
|
-
|
|
46075
|
-
const falModel = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
|
|
46286
|
+
const falModel = resolveSeedanceVariant(options.seedanceModel);
|
|
46287
|
+
spinner2.text = `Generating video with fal.ai ${falModel} (this may take 1-3 minutes)...`;
|
|
46076
46288
|
result = await fal.generateVideo(prompt3, {
|
|
46077
46289
|
prompt: prompt3,
|
|
46078
46290
|
referenceImage: seedanceReferences.length > 0 ? void 0 : falImage,
|
|
@@ -46089,11 +46301,20 @@ Examples:
|
|
|
46089
46301
|
} else if (provider === "omni") {
|
|
46090
46302
|
const omni = new OmniProvider();
|
|
46091
46303
|
await omni.initialize({ apiKey });
|
|
46092
|
-
spinner2.text = "Generating video with Gemini Omni
|
|
46304
|
+
spinner2.text = "Generating video with Gemini Omni 1.1 Flash...";
|
|
46305
|
+
let lastFrame;
|
|
46306
|
+
if (options.lastFrame) {
|
|
46307
|
+
const lastFramePath = resolve50(process.cwd(), options.lastFrame);
|
|
46308
|
+
const ext = options.lastFrame.toLowerCase().split(".").pop();
|
|
46309
|
+
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
46310
|
+
lastFrame = `data:${mimeType};base64,${(await readFile33(lastFramePath)).toString("base64")}`;
|
|
46311
|
+
}
|
|
46093
46312
|
result = await omni.generateVideo(prompt3, {
|
|
46094
46313
|
prompt: prompt3,
|
|
46095
46314
|
referenceImage,
|
|
46096
|
-
|
|
46315
|
+
lastFrame,
|
|
46316
|
+
aspectRatio: options.ratio,
|
|
46317
|
+
resolution: options.resolution
|
|
46097
46318
|
});
|
|
46098
46319
|
finalResult = result;
|
|
46099
46320
|
}
|
|
@@ -46107,14 +46328,14 @@ Examples:
|
|
|
46107
46328
|
if (options.output && finalResult.videoUrl) {
|
|
46108
46329
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
46109
46330
|
outputPath = resolve50(process.cwd(), options.output);
|
|
46110
|
-
await
|
|
46331
|
+
await writeFile35(outputPath, buffer);
|
|
46111
46332
|
}
|
|
46112
46333
|
const cost = realRunCost(provider, options);
|
|
46113
46334
|
outputSuccess({
|
|
46114
46335
|
command: "generate video",
|
|
46115
46336
|
startedAt,
|
|
46116
46337
|
costUsd: cost.costUsd,
|
|
46117
|
-
warnings: cost.warnings,
|
|
46338
|
+
warnings: provider === "veo" ? [VEO_SHUTDOWN_WARNING, ...cost.warnings] : cost.warnings,
|
|
46118
46339
|
data: {
|
|
46119
46340
|
provider,
|
|
46120
46341
|
taskId: result?.id,
|
|
@@ -46126,6 +46347,9 @@ Examples:
|
|
|
46126
46347
|
return;
|
|
46127
46348
|
}
|
|
46128
46349
|
console.log();
|
|
46350
|
+
if (provider === "veo") {
|
|
46351
|
+
console.log(source_default.yellow(VEO_SHUTDOWN_WARNING));
|
|
46352
|
+
}
|
|
46129
46353
|
if (finalResult.videoUrl) {
|
|
46130
46354
|
console.log(`Video URL: ${finalResult.videoUrl}`);
|
|
46131
46355
|
}
|
|
@@ -46138,7 +46362,7 @@ Examples:
|
|
|
46138
46362
|
try {
|
|
46139
46363
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
46140
46364
|
const outputPath = resolve50(process.cwd(), options.output);
|
|
46141
|
-
await
|
|
46365
|
+
await writeFile35(outputPath, buffer);
|
|
46142
46366
|
downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
46143
46367
|
} catch (err) {
|
|
46144
46368
|
downloadSpinner.fail(
|
|
@@ -46153,12 +46377,14 @@ Examples:
|
|
|
46153
46377
|
}
|
|
46154
46378
|
function realRunCost(provider, options) {
|
|
46155
46379
|
if (provider === "seedance" || provider === "fal") {
|
|
46380
|
+
const variant = resolveSeedanceVariant(options.seedanceModel);
|
|
46156
46381
|
return {
|
|
46157
46382
|
costUsd: estimateSeedanceVideoCostUsd({
|
|
46158
46383
|
durationSec: Number(options.duration) || 5,
|
|
46159
46384
|
resolution: options.resolution,
|
|
46160
46385
|
aspectRatio: options.ratio,
|
|
46161
|
-
fast:
|
|
46386
|
+
fast: variant === "seedance-2.0-fast",
|
|
46387
|
+
v25: variant === "seedance-2.5",
|
|
46162
46388
|
hasVideoReference: Boolean(options.refVideos)
|
|
46163
46389
|
}),
|
|
46164
46390
|
warnings: []
|
|
@@ -46248,6 +46474,7 @@ function printVideoStarted(providerLabel, taskId, taskType) {
|
|
|
46248
46474
|
console.log(`Task ID: ${source_default.bold(taskId)}`);
|
|
46249
46475
|
if (taskType) console.log(`Type: ${taskType}`);
|
|
46250
46476
|
}
|
|
46477
|
+
var VEO_SHUTDOWN_WARNING;
|
|
46251
46478
|
var init_video = __esm({
|
|
46252
46479
|
"src/commands/generate/video.ts"() {
|
|
46253
46480
|
"use strict";
|
|
@@ -46263,6 +46490,7 @@ var init_video = __esm({
|
|
|
46263
46490
|
init_upload_host();
|
|
46264
46491
|
init_ai_helpers();
|
|
46265
46492
|
init_status_jobs();
|
|
46493
|
+
VEO_SHUTDOWN_WARNING = "Veo 3.1 preview models shut down on 2026-10-22. Use `-p omni` (Gemini Omni 1.1 Flash) instead.";
|
|
46266
46494
|
}
|
|
46267
46495
|
});
|
|
46268
46496
|
|
|
@@ -46282,7 +46510,7 @@ var init_sanitize = __esm({
|
|
|
46282
46510
|
|
|
46283
46511
|
// src/commands/generate/storyboard.ts
|
|
46284
46512
|
import { resolve as resolve51 } from "node:path";
|
|
46285
|
-
import { writeFile as
|
|
46513
|
+
import { writeFile as writeFile36 } from "node:fs/promises";
|
|
46286
46514
|
async function executeStoryboard(options) {
|
|
46287
46515
|
const { content, duration, creativity = "low", output, apiKey } = options;
|
|
46288
46516
|
try {
|
|
@@ -46301,7 +46529,7 @@ async function executeStoryboard(options) {
|
|
|
46301
46529
|
let outputPath;
|
|
46302
46530
|
if (output) {
|
|
46303
46531
|
outputPath = resolve51(process.cwd(), output);
|
|
46304
|
-
await
|
|
46532
|
+
await writeFile36(outputPath, JSON.stringify(segments, null, 2), "utf-8");
|
|
46305
46533
|
}
|
|
46306
46534
|
return { success: true, segments, segmentCount: segments.length, outputPath };
|
|
46307
46535
|
} catch (error) {
|
|
@@ -46420,7 +46648,7 @@ var init_openai2 = __esm({
|
|
|
46420
46648
|
OpenAIAdapter = class {
|
|
46421
46649
|
provider = "openai";
|
|
46422
46650
|
client = null;
|
|
46423
|
-
model = "gpt-5-mini";
|
|
46651
|
+
model = "gpt-5.4-mini";
|
|
46424
46652
|
async initialize(apiKey) {
|
|
46425
46653
|
this.client = new OpenAI({ apiKey });
|
|
46426
46654
|
}
|
|
@@ -46516,7 +46744,7 @@ var init_claude2 = __esm({
|
|
|
46516
46744
|
ClaudeAdapter = class {
|
|
46517
46745
|
provider = "claude";
|
|
46518
46746
|
client = null;
|
|
46519
|
-
model = "claude-sonnet-
|
|
46747
|
+
model = "claude-sonnet-5-5";
|
|
46520
46748
|
async initialize(apiKey) {
|
|
46521
46749
|
this.client = new Anthropic({ apiKey });
|
|
46522
46750
|
}
|
|
@@ -46541,6 +46769,13 @@ var init_claude2 = __esm({
|
|
|
46541
46769
|
content: msg.content
|
|
46542
46770
|
});
|
|
46543
46771
|
} else if (msg.role === "assistant") {
|
|
46772
|
+
if (msg.providerContent) {
|
|
46773
|
+
claudeMessages.push({
|
|
46774
|
+
role: "assistant",
|
|
46775
|
+
content: msg.providerContent
|
|
46776
|
+
});
|
|
46777
|
+
continue;
|
|
46778
|
+
}
|
|
46544
46779
|
const content = [];
|
|
46545
46780
|
if (msg.content) {
|
|
46546
46781
|
content.push({ type: "text", text: msg.content });
|
|
@@ -46562,16 +46797,17 @@ var init_claude2 = __esm({
|
|
|
46562
46797
|
});
|
|
46563
46798
|
}
|
|
46564
46799
|
} else if (msg.role === "tool") {
|
|
46565
|
-
|
|
46566
|
-
|
|
46567
|
-
|
|
46568
|
-
|
|
46569
|
-
|
|
46570
|
-
|
|
46571
|
-
|
|
46572
|
-
|
|
46573
|
-
|
|
46574
|
-
|
|
46800
|
+
const result = {
|
|
46801
|
+
type: "tool_result",
|
|
46802
|
+
tool_use_id: msg.toolCallId,
|
|
46803
|
+
content: msg.content
|
|
46804
|
+
};
|
|
46805
|
+
const last = claudeMessages.at(-1);
|
|
46806
|
+
if (last?.role === "user" && Array.isArray(last.content)) {
|
|
46807
|
+
last.content.push(result);
|
|
46808
|
+
} else {
|
|
46809
|
+
claudeMessages.push({ role: "user", content: [result] });
|
|
46810
|
+
}
|
|
46575
46811
|
}
|
|
46576
46812
|
}
|
|
46577
46813
|
const claudeTools = tools.map((tool) => ({
|
|
@@ -46585,7 +46821,8 @@ var init_claude2 = __esm({
|
|
|
46585
46821
|
}));
|
|
46586
46822
|
const response = await this.client.messages.create({
|
|
46587
46823
|
model: this.model,
|
|
46588
|
-
|
|
46824
|
+
// Thinking tokens count against this cap on Claude 5.x.
|
|
46825
|
+
max_tokens: 16e3,
|
|
46589
46826
|
system: systemPrompt,
|
|
46590
46827
|
messages: claudeMessages,
|
|
46591
46828
|
tools: claudeTools.length > 0 ? claudeTools : void 0
|
|
@@ -46612,7 +46849,8 @@ var init_claude2 = __esm({
|
|
|
46612
46849
|
return {
|
|
46613
46850
|
content: textContent,
|
|
46614
46851
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
46615
|
-
finishReason
|
|
46852
|
+
finishReason,
|
|
46853
|
+
providerContent: response.content
|
|
46616
46854
|
};
|
|
46617
46855
|
}
|
|
46618
46856
|
};
|
|
@@ -46622,17 +46860,51 @@ var init_claude2 = __esm({
|
|
|
46622
46860
|
// src/agent/adapters/gemini.ts
|
|
46623
46861
|
var gemini_exports = {};
|
|
46624
46862
|
__export(gemini_exports, {
|
|
46625
|
-
GeminiAdapter: () => GeminiAdapter
|
|
46863
|
+
GeminiAdapter: () => GeminiAdapter,
|
|
46864
|
+
toGeminiSchema: () => toGeminiSchema
|
|
46626
46865
|
});
|
|
46627
46866
|
import { GoogleGenerativeAI, SchemaType } from "@google/generative-ai";
|
|
46628
|
-
|
|
46867
|
+
function toGeminiSchema(schema) {
|
|
46868
|
+
if (Array.isArray(schema)) return schema.map(toGeminiSchema);
|
|
46869
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
46870
|
+
const out = {};
|
|
46871
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
46872
|
+
if (!GEMINI_SCHEMA_KEYS.has(key)) continue;
|
|
46873
|
+
if (key === "properties" && value && typeof value === "object") {
|
|
46874
|
+
out.properties = Object.fromEntries(
|
|
46875
|
+
Object.entries(value).map(([name, prop]) => [name, toGeminiSchema(prop)])
|
|
46876
|
+
);
|
|
46877
|
+
} else if (key === "items") {
|
|
46878
|
+
out.items = toGeminiSchema(value);
|
|
46879
|
+
} else {
|
|
46880
|
+
out[key] = value;
|
|
46881
|
+
}
|
|
46882
|
+
}
|
|
46883
|
+
return out;
|
|
46884
|
+
}
|
|
46885
|
+
var GEMINI_SCHEMA_KEYS, GeminiAdapter;
|
|
46629
46886
|
var init_gemini2 = __esm({
|
|
46630
46887
|
"src/agent/adapters/gemini.ts"() {
|
|
46631
46888
|
"use strict";
|
|
46889
|
+
init_dist2();
|
|
46890
|
+
GEMINI_SCHEMA_KEYS = /* @__PURE__ */ new Set([
|
|
46891
|
+
"type",
|
|
46892
|
+
"format",
|
|
46893
|
+
"description",
|
|
46894
|
+
"nullable",
|
|
46895
|
+
"enum",
|
|
46896
|
+
"items",
|
|
46897
|
+
"properties",
|
|
46898
|
+
"required",
|
|
46899
|
+
"minItems",
|
|
46900
|
+
"maxItems",
|
|
46901
|
+
"minimum",
|
|
46902
|
+
"maximum"
|
|
46903
|
+
]);
|
|
46632
46904
|
GeminiAdapter = class {
|
|
46633
46905
|
provider = "gemini";
|
|
46634
46906
|
client = null;
|
|
46635
|
-
model =
|
|
46907
|
+
model = GEMINI_AGENT_DEFAULT_TEXT_MODEL;
|
|
46636
46908
|
async initialize(apiKey) {
|
|
46637
46909
|
this.client = new GoogleGenerativeAI(apiKey);
|
|
46638
46910
|
}
|
|
@@ -46654,7 +46926,12 @@ var init_gemini2 = __esm({
|
|
|
46654
46926
|
description: tool.description,
|
|
46655
46927
|
parameters: {
|
|
46656
46928
|
type: SchemaType.OBJECT,
|
|
46657
|
-
properties:
|
|
46929
|
+
properties: Object.fromEntries(
|
|
46930
|
+
Object.entries(tool.parameters.properties).map(([name, prop]) => [
|
|
46931
|
+
name,
|
|
46932
|
+
toGeminiSchema(prop)
|
|
46933
|
+
])
|
|
46934
|
+
),
|
|
46658
46935
|
required: tool.parameters.required
|
|
46659
46936
|
}
|
|
46660
46937
|
}))
|
|
@@ -46673,6 +46950,10 @@ var init_gemini2 = __esm({
|
|
|
46673
46950
|
parts: [{ text: msg.content }]
|
|
46674
46951
|
});
|
|
46675
46952
|
} else if (msg.role === "assistant") {
|
|
46953
|
+
if (msg.providerContent) {
|
|
46954
|
+
geminiContents.push({ role: "model", parts: msg.providerContent });
|
|
46955
|
+
continue;
|
|
46956
|
+
}
|
|
46676
46957
|
const parts = [];
|
|
46677
46958
|
if (msg.content) {
|
|
46678
46959
|
parts.push({ text: msg.content });
|
|
@@ -46694,16 +46975,19 @@ var init_gemini2 = __esm({
|
|
|
46694
46975
|
});
|
|
46695
46976
|
}
|
|
46696
46977
|
} else if (msg.role === "tool") {
|
|
46697
|
-
|
|
46698
|
-
|
|
46699
|
-
|
|
46700
|
-
|
|
46701
|
-
|
|
46702
|
-
|
|
46703
|
-
|
|
46704
|
-
|
|
46705
|
-
|
|
46706
|
-
|
|
46978
|
+
const part = {
|
|
46979
|
+
functionResponse: {
|
|
46980
|
+
name: msg.toolCallId.split(":::")[0] || "unknown",
|
|
46981
|
+
// Extract function name from id
|
|
46982
|
+
response: { result: msg.content }
|
|
46983
|
+
}
|
|
46984
|
+
};
|
|
46985
|
+
const last = geminiContents.at(-1);
|
|
46986
|
+
if (last?.role === "user" && last.parts.every((p) => "functionResponse" in p)) {
|
|
46987
|
+
last.parts.push(part);
|
|
46988
|
+
} else {
|
|
46989
|
+
geminiContents.push({ role: "user", parts: [part] });
|
|
46990
|
+
}
|
|
46707
46991
|
}
|
|
46708
46992
|
}
|
|
46709
46993
|
const result = await model.generateContent({
|
|
@@ -46740,7 +47024,8 @@ var init_gemini2 = __esm({
|
|
|
46740
47024
|
return {
|
|
46741
47025
|
content: textContent,
|
|
46742
47026
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
46743
|
-
finishReason
|
|
47027
|
+
finishReason,
|
|
47028
|
+
providerContent: candidate.content.parts
|
|
46744
47029
|
};
|
|
46745
47030
|
}
|
|
46746
47031
|
};
|
|
@@ -46943,7 +47228,7 @@ var init_xai = __esm({
|
|
|
46943
47228
|
XAIAdapter = class {
|
|
46944
47229
|
provider = "xai";
|
|
46945
47230
|
client = null;
|
|
46946
|
-
model = "grok-4
|
|
47231
|
+
model = "grok-4.3";
|
|
46947
47232
|
async initialize(apiKey) {
|
|
46948
47233
|
this.client = new OpenAI2({
|
|
46949
47234
|
apiKey,
|
|
@@ -47243,7 +47528,7 @@ __export(detect_exports, {
|
|
|
47243
47528
|
executeDetectScenes: () => executeDetectScenes,
|
|
47244
47529
|
executeDetectSilence: () => executeDetectSilence
|
|
47245
47530
|
});
|
|
47246
|
-
import { readFile as readFile38, writeFile as
|
|
47531
|
+
import { readFile as readFile38, writeFile as writeFile40 } from "node:fs/promises";
|
|
47247
47532
|
import { resolve as resolve56, basename as basename15 } from "node:path";
|
|
47248
47533
|
async function executeDetectScenes(options) {
|
|
47249
47534
|
try {
|
|
@@ -47282,7 +47567,7 @@ async function executeDetectScenes(options) {
|
|
|
47282
47567
|
}));
|
|
47283
47568
|
if (options.outputPath) {
|
|
47284
47569
|
const outputPath = resolve56(process.cwd(), options.outputPath);
|
|
47285
|
-
await
|
|
47570
|
+
await writeFile40(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
|
|
47286
47571
|
}
|
|
47287
47572
|
return { success: true, scenes: result, totalDuration };
|
|
47288
47573
|
} catch (error) {
|
|
@@ -47329,7 +47614,7 @@ async function executeDetectSilence(options) {
|
|
|
47329
47614
|
}
|
|
47330
47615
|
if (options.outputPath) {
|
|
47331
47616
|
const outputPath = resolve56(process.cwd(), options.outputPath);
|
|
47332
|
-
await
|
|
47617
|
+
await writeFile40(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
|
|
47333
47618
|
}
|
|
47334
47619
|
return { success: true, silences };
|
|
47335
47620
|
} catch (error) {
|
|
@@ -47378,7 +47663,7 @@ async function executeDetectBeats(options) {
|
|
|
47378
47663
|
}
|
|
47379
47664
|
if (options.outputPath) {
|
|
47380
47665
|
const outputPath = resolve56(process.cwd(), options.outputPath);
|
|
47381
|
-
await
|
|
47666
|
+
await writeFile40(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
|
|
47382
47667
|
}
|
|
47383
47668
|
return { success: true, beats, beatCount: beats.length };
|
|
47384
47669
|
} catch (error) {
|
|
@@ -47482,7 +47767,7 @@ var init_detect = __esm({
|
|
|
47482
47767
|
duration: (i < scenes.length - 1 ? scenes[i + 1].timestamp : totalDuration) - s.timestamp
|
|
47483
47768
|
}))
|
|
47484
47769
|
};
|
|
47485
|
-
await
|
|
47770
|
+
await writeFile40(outputPath, JSON.stringify(result, null, 2), "utf-8");
|
|
47486
47771
|
console.log(source_default.green(`Saved to: ${outputPath}`));
|
|
47487
47772
|
}
|
|
47488
47773
|
if (options.project) {
|
|
@@ -47512,7 +47797,7 @@ var init_detect = __esm({
|
|
|
47512
47797
|
sourceEndOffset: end
|
|
47513
47798
|
});
|
|
47514
47799
|
}
|
|
47515
|
-
await
|
|
47800
|
+
await writeFile40(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
47516
47801
|
console.log(source_default.green(`Added ${scenes.length} clips to project`));
|
|
47517
47802
|
}
|
|
47518
47803
|
} catch (error) {
|
|
@@ -47594,7 +47879,7 @@ var init_detect = __esm({
|
|
|
47594
47879
|
console.log();
|
|
47595
47880
|
if (options.output) {
|
|
47596
47881
|
const outputPath = resolve56(process.cwd(), options.output);
|
|
47597
|
-
await
|
|
47882
|
+
await writeFile40(
|
|
47598
47883
|
outputPath,
|
|
47599
47884
|
JSON.stringify({ source: absPath, silences }, null, 2),
|
|
47600
47885
|
"utf-8"
|
|
@@ -47679,7 +47964,7 @@ var init_detect = __esm({
|
|
|
47679
47964
|
console.log();
|
|
47680
47965
|
if (options.output) {
|
|
47681
47966
|
const outputPath = resolve56(process.cwd(), options.output);
|
|
47682
|
-
await
|
|
47967
|
+
await writeFile40(
|
|
47683
47968
|
outputPath,
|
|
47684
47969
|
JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2),
|
|
47685
47970
|
"utf-8"
|
|
@@ -52300,8 +52585,8 @@ init_tts_resolve();
|
|
|
52300
52585
|
init_scene_project();
|
|
52301
52586
|
init_project_config();
|
|
52302
52587
|
init_cost_tier();
|
|
52303
|
-
import { resolve as resolve15, relative as relative5, dirname as
|
|
52304
|
-
import { mkdir as
|
|
52588
|
+
import { resolve as resolve15, relative as relative5, dirname as dirname5 } from "node:path";
|
|
52589
|
+
import { mkdir as mkdir8, readFile as readFile13, writeFile as writeFile13, access as access4, copyFile as copyFile2 } from "node:fs/promises";
|
|
52305
52590
|
import { existsSync as existsSync12 } from "node:fs";
|
|
52306
52591
|
|
|
52307
52592
|
// src/commands/_shared/scene-html-emit.ts
|
|
@@ -52781,7 +53066,7 @@ init_storyboard_parse();
|
|
|
52781
53066
|
init_storyboard_source();
|
|
52782
53067
|
init_root_sync();
|
|
52783
53068
|
import { existsSync as existsSync10 } from "node:fs";
|
|
52784
|
-
import { mkdir as
|
|
53069
|
+
import { mkdir as mkdir7, writeFile as writeFile11 } from "node:fs/promises";
|
|
52785
53070
|
import { join as join10, resolve as resolve12 } from "node:path";
|
|
52786
53071
|
async function executeSceneSubmit(opts) {
|
|
52787
53072
|
const projectDir = resolve12(opts.projectDir);
|
|
@@ -52875,7 +53160,7 @@ async function executeSceneSubmit(opts) {
|
|
|
52875
53160
|
return { ...base, success: true };
|
|
52876
53161
|
}
|
|
52877
53162
|
const absPath = join10(projectDir, scenePath);
|
|
52878
|
-
await
|
|
53163
|
+
await mkdir7(join10(projectDir, "compositions"), { recursive: true });
|
|
52879
53164
|
await writeFile11(absPath, html.endsWith("\n") ? html : `${html}
|
|
52880
53165
|
`, "utf-8");
|
|
52881
53166
|
return {
|
|
@@ -53466,7 +53751,7 @@ async function executeSceneAdd(opts) {
|
|
|
53466
53751
|
}
|
|
53467
53752
|
audioRelPath = `assets/narration-${id}.${ext}`;
|
|
53468
53753
|
audioAbsPath = resolve15(projectDir, audioRelPath);
|
|
53469
|
-
await
|
|
53754
|
+
await mkdir8(dirname5(audioAbsPath), { recursive: true });
|
|
53470
53755
|
await copyFile2(sourceAbs, audioAbsPath);
|
|
53471
53756
|
try {
|
|
53472
53757
|
narrationDuration = await getAudioDuration(audioAbsPath);
|
|
@@ -53499,7 +53784,7 @@ async function executeSceneAdd(opts) {
|
|
|
53499
53784
|
}
|
|
53500
53785
|
audioRelPath = `assets/narration-${id}.${resolution.audioExtension}`;
|
|
53501
53786
|
audioAbsPath = resolve15(projectDir, audioRelPath);
|
|
53502
|
-
await
|
|
53787
|
+
await mkdir8(dirname5(audioAbsPath), { recursive: true });
|
|
53503
53788
|
await writeFile13(audioAbsPath, tts.audioBuffer);
|
|
53504
53789
|
try {
|
|
53505
53790
|
narrationDuration = await getAudioDuration(audioAbsPath);
|
|
@@ -53562,7 +53847,7 @@ async function executeSceneAdd(opts) {
|
|
|
53562
53847
|
const img = imageResult.images[0];
|
|
53563
53848
|
imageRelPath = `assets/scene-${id}.png`;
|
|
53564
53849
|
imageAbsPath = resolve15(projectDir, imageRelPath);
|
|
53565
|
-
await
|
|
53850
|
+
await mkdir8(dirname5(imageAbsPath), { recursive: true });
|
|
53566
53851
|
let buffer;
|
|
53567
53852
|
if (img.base64) {
|
|
53568
53853
|
buffer = Buffer.from(img.base64, "base64");
|
|
@@ -53589,7 +53874,7 @@ async function executeSceneAdd(opts) {
|
|
|
53589
53874
|
}
|
|
53590
53875
|
imageRelPath = `assets/scene-${id}.png`;
|
|
53591
53876
|
imageAbsPath = resolve15(projectDir, imageRelPath);
|
|
53592
|
-
await
|
|
53877
|
+
await mkdir8(dirname5(imageAbsPath), { recursive: true });
|
|
53593
53878
|
const buffer = Buffer.from(imageResult.images[0].base64, "base64");
|
|
53594
53879
|
await writeFile13(imageAbsPath, buffer);
|
|
53595
53880
|
}
|
|
@@ -53608,7 +53893,7 @@ async function executeSceneAdd(opts) {
|
|
|
53608
53893
|
}
|
|
53609
53894
|
lottieRelPath = `assets/lottie-${id}.${ext}`;
|
|
53610
53895
|
lottieAbsPath = resolve15(projectDir, lottieRelPath);
|
|
53611
|
-
await
|
|
53896
|
+
await mkdir8(dirname5(lottieAbsPath), { recursive: true });
|
|
53612
53897
|
await copyFile2(sourceAbs, lottieAbsPath);
|
|
53613
53898
|
lottieInput = {
|
|
53614
53899
|
src: lottieRelPath,
|
|
@@ -53678,7 +53963,7 @@ async function executeSceneAdd(opts) {
|
|
|
53678
53963
|
transcript: transcriptWords,
|
|
53679
53964
|
lottie: lottieInput
|
|
53680
53965
|
});
|
|
53681
|
-
await
|
|
53966
|
+
await mkdir8(dirname5(scenePath), { recursive: true });
|
|
53682
53967
|
await writeFile13(scenePath, sceneHtml, "utf-8");
|
|
53683
53968
|
opts.onProgress?.("Updating root composition...");
|
|
53684
53969
|
let start = 0;
|
|
@@ -53895,6 +54180,7 @@ init_scene_build();
|
|
|
53895
54180
|
init_install_skill();
|
|
53896
54181
|
init_compose_prompts();
|
|
53897
54182
|
init_scene_repair();
|
|
54183
|
+
init_build_video_providers();
|
|
53898
54184
|
var SCENE_PRESETS2 = [
|
|
53899
54185
|
"simple",
|
|
53900
54186
|
"announcement",
|
|
@@ -54294,12 +54580,12 @@ var sceneBuildSchema = external_exports.object({
|
|
|
54294
54580
|
"TTS provider override. Default 'auto' (elevenlabs key > openai key > local kokoro)."
|
|
54295
54581
|
),
|
|
54296
54582
|
voice: external_exports.string().optional().describe("TTS voice id (provider-specific)."),
|
|
54297
|
-
imageProvider: external_exports.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2)."),
|
|
54298
|
-
videoProvider: external_exports.enum(
|
|
54583
|
+
imageProvider: external_exports.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2.5-sunburst)."),
|
|
54584
|
+
videoProvider: external_exports.enum(BUILD_VIDEO_PROVIDERS).optional().describe("Video provider for per-beat video cues. Default seedance."),
|
|
54299
54585
|
musicProvider: external_exports.enum(["elevenlabs", "replicate"]).optional().describe("Music provider for per-beat music cues. Default elevenlabs."),
|
|
54300
54586
|
imageQuality: external_exports.enum(["standard", "hd"]).optional().describe("OpenAI image quality. Default 'standard'."),
|
|
54301
54587
|
imageModel: external_exports.string().optional().describe(
|
|
54302
|
-
"Image model for keyframes/backdrops/character sheets (gemini: flash|pro, openai: gpt-image-2). Provider default when omitted."
|
|
54588
|
+
"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."
|
|
54303
54589
|
),
|
|
54304
54590
|
imageSize: external_exports.enum(["1024x1024", "1536x1024", "1024x1536"]).optional().describe("OpenAI image size. Default '1536x1024' (cinematic 16:9-ish)."),
|
|
54305
54591
|
maxCostUsd: external_exports.number().optional().describe("Fail before provider spend when estimated cost exceeds this USD cap."),
|
|
@@ -54729,8 +55015,8 @@ init_ai_edit();
|
|
|
54729
55015
|
init_api_key();
|
|
54730
55016
|
init_exec_safe();
|
|
54731
55017
|
init_remotion();
|
|
54732
|
-
import { resolve as resolve37, dirname as
|
|
54733
|
-
import { writeFile as
|
|
55018
|
+
import { resolve as resolve37, dirname as dirname17, basename as basename10 } from "node:path";
|
|
55019
|
+
import { writeFile as writeFile29, mkdir as mkdir20, rm as rm6 } from "node:fs/promises";
|
|
54734
55020
|
import { existsSync as existsSync36 } from "node:fs";
|
|
54735
55021
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
54736
55022
|
var ASS_STYLES = ["karaoke-sweep", "typewriter"];
|
|
@@ -54882,7 +55168,7 @@ async function executeAnimatedCaption(options) {
|
|
|
54882
55168
|
}
|
|
54883
55169
|
const effectiveFontSize = fontSize ?? Math.round(height * 0.04);
|
|
54884
55170
|
const tmpAudioDir = resolve37(tmpdir3(), `vf-ac-${Date.now()}`);
|
|
54885
|
-
await
|
|
55171
|
+
await mkdir20(tmpAudioDir, { recursive: true });
|
|
54886
55172
|
const audioPath = resolve37(tmpAudioDir, "audio.wav");
|
|
54887
55173
|
await execSafe("ffmpeg", [
|
|
54888
55174
|
"-y",
|
|
@@ -54899,21 +55185,21 @@ async function executeAnimatedCaption(options) {
|
|
|
54899
55185
|
], { timeout: 12e4 });
|
|
54900
55186
|
const apiKey = await getApiKey("OPENAI_API_KEY", "OpenAI");
|
|
54901
55187
|
if (!apiKey) {
|
|
54902
|
-
await
|
|
55188
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54903
55189
|
});
|
|
54904
55190
|
return { success: false, error: "OPENAI_API_KEY required for Whisper transcription. Run 'vibe setup' or set OPENAI_API_KEY in .env" };
|
|
54905
55191
|
}
|
|
54906
55192
|
const transcript = await transcribeWithWords(audioPath, apiKey, language);
|
|
54907
55193
|
if (!transcript.words || transcript.words.length === 0) {
|
|
54908
|
-
await
|
|
55194
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54909
55195
|
});
|
|
54910
55196
|
return { success: false, error: "No words detected in transcription" };
|
|
54911
55197
|
}
|
|
54912
55198
|
const groups = groupWords(transcript.words, { wordsPerGroup, maxChars });
|
|
54913
55199
|
const absOutputPath = resolve37(process.cwd(), outputPath);
|
|
54914
|
-
const outDir =
|
|
55200
|
+
const outDir = dirname17(absOutputPath);
|
|
54915
55201
|
if (!existsSync36(outDir)) {
|
|
54916
|
-
await
|
|
55202
|
+
await mkdir20(outDir, { recursive: true });
|
|
54917
55203
|
}
|
|
54918
55204
|
if (tier === "ass") {
|
|
54919
55205
|
const assContent = generateASS(
|
|
@@ -54922,7 +55208,7 @@ async function executeAnimatedCaption(options) {
|
|
|
54922
55208
|
{ highlightColor, fontSize: effectiveFontSize, position, width, height }
|
|
54923
55209
|
);
|
|
54924
55210
|
const assPath = resolve37(tmpAudioDir, "captions.ass");
|
|
54925
|
-
await
|
|
55211
|
+
await writeFile29(assPath, assContent, "utf-8");
|
|
54926
55212
|
const escapedAssPath = assPath.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
|
|
54927
55213
|
await execSafe("ffmpeg", [
|
|
54928
55214
|
"-y",
|
|
@@ -54959,12 +55245,12 @@ async function executeAnimatedCaption(options) {
|
|
|
54959
55245
|
outputPath: absOutputPath
|
|
54960
55246
|
});
|
|
54961
55247
|
if (!renderResult.success) {
|
|
54962
|
-
await
|
|
55248
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54963
55249
|
});
|
|
54964
55250
|
return { success: false, error: renderResult.error };
|
|
54965
55251
|
}
|
|
54966
55252
|
}
|
|
54967
|
-
await
|
|
55253
|
+
await rm6(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
54968
55254
|
});
|
|
54969
55255
|
return {
|
|
54970
55256
|
success: true,
|
|
@@ -55373,7 +55659,7 @@ var editImageTool = defineTool({
|
|
|
55373
55659
|
imagePaths: external_exports.array(external_exports.string()).describe("Input image file path(s)"),
|
|
55374
55660
|
prompt: external_exports.string().describe("Edit instruction"),
|
|
55375
55661
|
output: external_exports.string().optional().describe("Output file path (default: edited.png)"),
|
|
55376
|
-
model: external_exports.enum(["flash", "3.1-flash", "latest", "pro"]).optional().describe("Gemini model (default: flash)"),
|
|
55662
|
+
model: external_exports.enum(["flash", "3.1-flash", "latest", "lite", "pro"]).optional().describe("Gemini model (default: flash = Nano Banana 2)"),
|
|
55377
55663
|
ratio: external_exports.string().optional().describe("Output aspect ratio"),
|
|
55378
55664
|
resolution: external_exports.string().optional().describe("Resolution: 1K, 2K, 4K (Pro only)")
|
|
55379
55665
|
}),
|
|
@@ -57224,7 +57510,7 @@ var generateSoundEffectTool = defineTool({
|
|
|
57224
57510
|
schema: external_exports.object({
|
|
57225
57511
|
prompt: external_exports.string().describe("Description of the sound effect"),
|
|
57226
57512
|
output: external_exports.string().optional().describe("Output audio file path (default: sound-effect.mp3)"),
|
|
57227
|
-
duration: external_exports.number().optional().describe("Duration in seconds (0.5-
|
|
57513
|
+
duration: external_exports.number().optional().describe("Duration in seconds (0.5-30, default: auto)"),
|
|
57228
57514
|
promptInfluence: external_exports.number().optional().describe("Prompt influence 0-1 (default: 0.3)")
|
|
57229
57515
|
}),
|
|
57230
57516
|
async execute(args) {
|
|
@@ -57301,7 +57587,7 @@ var generateImageTool = defineTool({
|
|
|
57301
57587
|
ratio: external_exports.string().optional().describe("Aspect ratio for Gemini (1:1, 16:9, 9:16, 4:3, 3:4, etc.)"),
|
|
57302
57588
|
quality: external_exports.string().optional().describe("Quality for OpenAI: standard, hd"),
|
|
57303
57589
|
count: external_exports.number().optional().describe("Number of images (default: 1)"),
|
|
57304
|
-
model: external_exports.string().optional().describe("
|
|
57590
|
+
model: external_exports.string().optional().describe("Image model. Gemini: flash (default), lite, pro. OpenAI: 2.5 (default), flare, 2, 1.5. Grok: pro")
|
|
57305
57591
|
}),
|
|
57306
57592
|
async execute(args) {
|
|
57307
57593
|
const result = await executeImageGenerate(args);
|
|
@@ -57364,9 +57650,11 @@ var generateVideoTool = defineTool({
|
|
|
57364
57650
|
mode: external_exports.string().optional().describe("Kling mode: std or pro"),
|
|
57365
57651
|
negative: external_exports.string().optional().describe("Negative prompt (Seedance/Kling/Veo)"),
|
|
57366
57652
|
resolution: external_exports.string().optional().describe("Resolution: 480p, 720p, 1080p, or 4k depending on provider"),
|
|
57367
|
-
veoModel: external_exports.string().optional().describe("Veo model: 3.
|
|
57653
|
+
veoModel: external_exports.string().optional().describe("Veo model: 3.1, 3.1-fast"),
|
|
57368
57654
|
runwayModel: external_exports.string().optional().describe("Runway model: gen4.5, gen4_turbo"),
|
|
57369
|
-
seedanceModel: external_exports.string().optional().describe("Seedance variant: quality
|
|
57655
|
+
seedanceModel: external_exports.string().optional().describe("Seedance variant: quality (2.0), fast, or 2.5 (fal.ai only)"),
|
|
57656
|
+
grokModel: external_exports.string().optional().describe("Grok video model: 1.5 (default), lite, classic"),
|
|
57657
|
+
klingModel: external_exports.string().optional().describe("Kling model: v3 (default), v2.6, v2.5-turbo"),
|
|
57370
57658
|
generateAudio: external_exports.boolean().optional().describe("Generate native synchronized audio when supported"),
|
|
57371
57659
|
output: external_exports.string().optional().describe("Output file path (downloads video)"),
|
|
57372
57660
|
wait: external_exports.boolean().optional().describe("Wait for completion (default: true)")
|
|
@@ -57438,7 +57726,7 @@ var generateVideoExtendTool = defineTool({
|
|
|
57438
57726
|
prompt: external_exports.string().optional().describe("Continuation prompt"),
|
|
57439
57727
|
duration: external_exports.number().optional().describe("Duration in seconds"),
|
|
57440
57728
|
negative: external_exports.string().optional().describe("Negative prompt (Kling)"),
|
|
57441
|
-
veoModel: external_exports.string().optional().describe("Veo model: 3.
|
|
57729
|
+
veoModel: external_exports.string().optional().describe("Veo model: 3.1, 3.1-fast"),
|
|
57442
57730
|
output: external_exports.string().optional().describe("Output file path"),
|
|
57443
57731
|
wait: external_exports.boolean().optional().describe("Wait for completion (default: true)")
|
|
57444
57732
|
}),
|
|
@@ -57474,14 +57762,14 @@ var generateTools = [
|
|
|
57474
57762
|
|
|
57475
57763
|
// src/tools/manifest/storyboard.ts
|
|
57476
57764
|
import { existsSync as existsSync44 } from "node:fs";
|
|
57477
|
-
import { readFile as readFile35, writeFile as
|
|
57765
|
+
import { readFile as readFile35, writeFile as writeFile38 } from "node:fs/promises";
|
|
57478
57766
|
import { resolve as resolve53 } from "node:path";
|
|
57479
57767
|
init_storyboard_parse();
|
|
57480
57768
|
init_storyboard_edit();
|
|
57481
57769
|
|
|
57482
57770
|
// src/commands/_shared/storyboard-revise.ts
|
|
57483
57771
|
import { existsSync as existsSync43 } from "node:fs";
|
|
57484
|
-
import { readFile as readFile34, writeFile as
|
|
57772
|
+
import { readFile as readFile34, writeFile as writeFile37 } from "node:fs/promises";
|
|
57485
57773
|
import { join as join24, resolve as resolve52 } from "node:path";
|
|
57486
57774
|
|
|
57487
57775
|
// src/agent/adapters/index.ts
|
|
@@ -57650,7 +57938,7 @@ async function executeStoryboardRevision(opts) {
|
|
|
57650
57938
|
if (loaded.layout === "bundle") {
|
|
57651
57939
|
await rewriteBundleFromMarkdown(projectDir, storyboardMd);
|
|
57652
57940
|
} else {
|
|
57653
|
-
await
|
|
57941
|
+
await writeFile37(storyboardPath, storyboardMd, "utf-8");
|
|
57654
57942
|
}
|
|
57655
57943
|
}
|
|
57656
57944
|
const changedBeats = unique5([...diffChangedBeats(currentStoryboard, storyboardMd), ...payload.changedBeats]);
|
|
@@ -57828,6 +58116,7 @@ function stripUndefined3(value) {
|
|
|
57828
58116
|
|
|
57829
58117
|
// src/tools/manifest/storyboard.ts
|
|
57830
58118
|
init_build_plan();
|
|
58119
|
+
init_build_video_providers();
|
|
57831
58120
|
var PROJECT_DIR_DESCRIPTION3 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
|
|
57832
58121
|
var projectDirSchema = external_exports.object({
|
|
57833
58122
|
projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3)
|
|
@@ -57948,7 +58237,7 @@ var storyboardSetTool = defineTool({
|
|
|
57948
58237
|
value,
|
|
57949
58238
|
unset: args.unset
|
|
57950
58239
|
});
|
|
57951
|
-
await
|
|
58240
|
+
await writeFile38(file.path, next, "utf-8");
|
|
57952
58241
|
return {
|
|
57953
58242
|
success: true,
|
|
57954
58243
|
data: { beat: args.beat, key: args.key },
|
|
@@ -57980,7 +58269,7 @@ var storyboardMoveTool = defineTool({
|
|
|
57980
58269
|
beatId: args.beat,
|
|
57981
58270
|
afterBeatId: args.after
|
|
57982
58271
|
});
|
|
57983
|
-
await
|
|
58272
|
+
await writeFile38(file.path, next, "utf-8");
|
|
57984
58273
|
return {
|
|
57985
58274
|
success: true,
|
|
57986
58275
|
data: { beat: args.beat, after: args.after },
|
|
@@ -58045,7 +58334,7 @@ var planTool = defineTool({
|
|
|
58045
58334
|
imageProvider: external_exports.string().optional().describe("Image provider override."),
|
|
58046
58335
|
imageQuality: external_exports.enum(["standard", "hd"]).optional().describe("Image quality override."),
|
|
58047
58336
|
imageSize: external_exports.string().optional().describe("Image size override."),
|
|
58048
|
-
videoProvider: external_exports.enum(
|
|
58337
|
+
videoProvider: external_exports.enum(BUILD_VIDEO_PROVIDERS).optional().describe("Video provider override."),
|
|
58049
58338
|
musicProvider: external_exports.enum(["elevenlabs", "replicate"]).optional().describe("Music provider override."),
|
|
58050
58339
|
composer: external_exports.enum(["claude", "openai", "gemini"]).optional().describe("Composer provider override."),
|
|
58051
58340
|
force: external_exports.boolean().optional().describe("Plan regeneration even when outputs exist.")
|
|
@@ -58133,13 +58422,13 @@ var designValidateTool = defineTool({
|
|
|
58133
58422
|
var designTools = [designValidateTool];
|
|
58134
58423
|
|
|
58135
58424
|
// src/tools/manifest/remix.ts
|
|
58136
|
-
import { writeFile as
|
|
58425
|
+
import { writeFile as writeFile42 } from "node:fs/promises";
|
|
58137
58426
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
58138
58427
|
import { join as join26 } from "node:path";
|
|
58139
58428
|
|
|
58140
58429
|
// src/commands/ai-highlights.ts
|
|
58141
|
-
import { readFile as readFile37, writeFile as
|
|
58142
|
-
import { resolve as resolve55, dirname as
|
|
58430
|
+
import { readFile as readFile37, writeFile as writeFile39, mkdir as mkdir24 } from "node:fs/promises";
|
|
58431
|
+
import { resolve as resolve55, dirname as dirname21, basename as basename14, extname as extname11 } from "node:path";
|
|
58143
58432
|
import { existsSync as existsSync46 } from "node:fs";
|
|
58144
58433
|
init_dist2();
|
|
58145
58434
|
init_engine();
|
|
@@ -58174,7 +58463,7 @@ async function executeHighlights(options) {
|
|
|
58174
58463
|
if (!existsSync46(absPath)) {
|
|
58175
58464
|
return { success: false, highlights: [], totalDuration: 0, totalHighlightDuration: 0, error: `File not found: ${absPath}` };
|
|
58176
58465
|
}
|
|
58177
|
-
const ext =
|
|
58466
|
+
const ext = extname11(absPath).toLowerCase();
|
|
58178
58467
|
const videoExtensions = [".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"];
|
|
58179
58468
|
const isVideo = videoExtensions.includes(ext);
|
|
58180
58469
|
const targetDuration = options.duration;
|
|
@@ -58319,7 +58608,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
58319
58608
|
};
|
|
58320
58609
|
if (options.output) {
|
|
58321
58610
|
const outputPath = resolve55(process.cwd(), options.output);
|
|
58322
|
-
await
|
|
58611
|
+
await writeFile39(outputPath, JSON.stringify({
|
|
58323
58612
|
sourceFile: absPath,
|
|
58324
58613
|
totalDuration: sourceDuration,
|
|
58325
58614
|
criteria: options.criteria || "all",
|
|
@@ -58354,7 +58643,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
58354
58643
|
}
|
|
58355
58644
|
}
|
|
58356
58645
|
const projectPath = resolve55(process.cwd(), options.project);
|
|
58357
|
-
await
|
|
58646
|
+
await writeFile39(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
58358
58647
|
extractResult.projectPath = projectPath;
|
|
58359
58648
|
}
|
|
58360
58649
|
return extractResult;
|
|
@@ -58501,9 +58790,9 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
58501
58790
|
}))
|
|
58502
58791
|
};
|
|
58503
58792
|
}
|
|
58504
|
-
const outputDir = options.outputDir ? resolve55(process.cwd(), options.outputDir) :
|
|
58793
|
+
const outputDir = options.outputDir ? resolve55(process.cwd(), options.outputDir) : dirname21(absPath);
|
|
58505
58794
|
if (options.outputDir && !existsSync46(outputDir)) {
|
|
58506
|
-
await
|
|
58795
|
+
await mkdir24(outputDir, { recursive: true });
|
|
58507
58796
|
}
|
|
58508
58797
|
const result = {
|
|
58509
58798
|
success: true,
|
|
@@ -58511,7 +58800,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
58511
58800
|
};
|
|
58512
58801
|
for (let i = 0; i < selectedHighlights.length; i++) {
|
|
58513
58802
|
const h = selectedHighlights[i];
|
|
58514
|
-
const baseName = basename14(absPath,
|
|
58803
|
+
const baseName = basename14(absPath, extname11(absPath));
|
|
58515
58804
|
const outputPath = resolve55(outputDir, `${baseName}-short-${i + 1}.mp4`);
|
|
58516
58805
|
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
58517
58806
|
"-v",
|
|
@@ -58581,7 +58870,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
58581
58870
|
// src/pipeline/executor.ts
|
|
58582
58871
|
var import_yaml8 = __toESM(require_dist2(), 1);
|
|
58583
58872
|
import { resolve as resolve57 } from "node:path";
|
|
58584
|
-
import { readFile as readFile39, writeFile as
|
|
58873
|
+
import { readFile as readFile39, writeFile as writeFile41, mkdir as mkdir25 } from "node:fs/promises";
|
|
58585
58874
|
import { existsSync as existsSync47 } from "node:fs";
|
|
58586
58875
|
|
|
58587
58876
|
// src/pipeline/resolver.ts
|
|
@@ -58643,6 +58932,7 @@ function findUnresolvedRefs(params, availableStepIds) {
|
|
|
58643
58932
|
init_output();
|
|
58644
58933
|
init_config();
|
|
58645
58934
|
init_provider_resolver();
|
|
58935
|
+
init_build_video_providers();
|
|
58646
58936
|
var ACTION_METADATA = {
|
|
58647
58937
|
"generate-image": { id: "generate-image", title: "Generate image", category: "generate", command: "generate image", outputs: ["image"] },
|
|
58648
58938
|
"generate-video": { id: "generate-video", title: "Generate video", category: "generate", command: "generate video", outputs: ["video"], requiredKeys: ["provider-dependent"] },
|
|
@@ -58716,7 +59006,7 @@ async function resolvePipelineVideoProvider(provider) {
|
|
|
58716
59006
|
if (explicit === "fal") return "seedance";
|
|
58717
59007
|
if (explicit) return explicit;
|
|
58718
59008
|
await loadProviderDefaults();
|
|
58719
|
-
return resolveProvider("video")?.name ?? "grok";
|
|
59009
|
+
return resolveBuildVideoProvider(resolveProvider("video")?.name ?? "grok");
|
|
58720
59010
|
}
|
|
58721
59011
|
function providerKeyForImage(provider) {
|
|
58722
59012
|
switch (provider) {
|
|
@@ -58742,6 +59032,7 @@ function providerKeyForVideo(provider) {
|
|
|
58742
59032
|
case "runway":
|
|
58743
59033
|
return "runway";
|
|
58744
59034
|
case "veo":
|
|
59035
|
+
case "omni":
|
|
58745
59036
|
return "google";
|
|
58746
59037
|
default:
|
|
58747
59038
|
return void 0;
|
|
@@ -58993,7 +59284,7 @@ var CHECKPOINT_FILE = ".pipeline-state.yaml";
|
|
|
58993
59284
|
async function executePipeline(manifest2, options = {}) {
|
|
58994
59285
|
await ensureActionsRegistered();
|
|
58995
59286
|
const outputDir = resolve57(process.cwd(), options.outputDir || `${manifest2.name}-output`);
|
|
58996
|
-
await
|
|
59287
|
+
await mkdir25(outputDir, { recursive: true });
|
|
58997
59288
|
const completedSteps = /* @__PURE__ */ new Map();
|
|
58998
59289
|
const results = [];
|
|
58999
59290
|
const startTime = Date.now();
|
|
@@ -59118,7 +59409,7 @@ async function executePipeline(manifest2, options = {}) {
|
|
|
59118
59409
|
data: s.data
|
|
59119
59410
|
}))
|
|
59120
59411
|
};
|
|
59121
|
-
await
|
|
59412
|
+
await writeFile41(
|
|
59122
59413
|
resolve57(outputDir, CHECKPOINT_FILE),
|
|
59123
59414
|
(0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
|
|
59124
59415
|
"utf-8"
|
|
@@ -59273,7 +59564,7 @@ var pipelineRunTool = defineTool({
|
|
|
59273
59564
|
let tempPath;
|
|
59274
59565
|
if (args.pipelineYaml) {
|
|
59275
59566
|
tempPath = join26(tmpdir4(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
|
|
59276
|
-
await
|
|
59567
|
+
await writeFile42(tempPath, args.pipelineYaml, "utf-8");
|
|
59277
59568
|
resolvedPath = tempPath;
|
|
59278
59569
|
}
|
|
59279
59570
|
try {
|
|
@@ -59408,7 +59699,7 @@ var detectTools = [
|
|
|
59408
59699
|
];
|
|
59409
59700
|
|
|
59410
59701
|
// src/tools/manifest/timeline.ts
|
|
59411
|
-
import { mkdir as
|
|
59702
|
+
import { mkdir as mkdir26, writeFile as writeFile44 } from "node:fs/promises";
|
|
59412
59703
|
import { basename as basename16, resolve as resolve58 } from "node:path";
|
|
59413
59704
|
init_engine();
|
|
59414
59705
|
init_project_resolver();
|
|
@@ -59416,7 +59707,7 @@ init_project_resolver();
|
|
|
59416
59707
|
// src/tools/manifest/_project-io.ts
|
|
59417
59708
|
init_engine();
|
|
59418
59709
|
init_project_resolver();
|
|
59419
|
-
import { readFile as readFile40, writeFile as
|
|
59710
|
+
import { readFile as readFile40, writeFile as writeFile43 } from "node:fs/promises";
|
|
59420
59711
|
async function loadProject(projectPath, cwd) {
|
|
59421
59712
|
const absPath = await resolveTimelineFile(projectPath, cwd);
|
|
59422
59713
|
const content = await readFile40(absPath, "utf-8");
|
|
@@ -59424,7 +59715,7 @@ async function loadProject(projectPath, cwd) {
|
|
|
59424
59715
|
return { project: Project.fromJSON(data), absPath };
|
|
59425
59716
|
}
|
|
59426
59717
|
async function saveProject(absPath, project) {
|
|
59427
|
-
await
|
|
59718
|
+
await writeFile43(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
59428
59719
|
}
|
|
59429
59720
|
|
|
59430
59721
|
// src/tools/manifest/timeline.ts
|
|
@@ -59464,10 +59755,10 @@ var timelineCreateTool = defineTool({
|
|
|
59464
59755
|
outputPath = resolve58(ctx.workingDirectory, args.outputPath);
|
|
59465
59756
|
} else {
|
|
59466
59757
|
const dirPath = resolve58(ctx.workingDirectory, args.name);
|
|
59467
|
-
await
|
|
59758
|
+
await mkdir26(dirPath, { recursive: true });
|
|
59468
59759
|
outputPath = resolve58(dirPath, TIMELINE_FILENAME);
|
|
59469
59760
|
}
|
|
59470
|
-
await
|
|
59761
|
+
await writeFile44(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
59471
59762
|
return {
|
|
59472
59763
|
success: true,
|
|
59473
59764
|
data: { name: projectName, outputPath },
|
|
@@ -59764,7 +60055,7 @@ var timelineTools = [
|
|
|
59764
60055
|
|
|
59765
60056
|
// src/tools/manifest/project.ts
|
|
59766
60057
|
import { resolve as resolve60 } from "node:path";
|
|
59767
|
-
import { writeFile as
|
|
60058
|
+
import { writeFile as writeFile45 } from "node:fs/promises";
|
|
59768
60059
|
init_engine();
|
|
59769
60060
|
|
|
59770
60061
|
// src/commands/_shared/project-list.ts
|
|
@@ -59922,7 +60213,7 @@ var projectCreateTool = defineTool({
|
|
|
59922
60213
|
const outputPath = resolve60(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
|
|
59923
60214
|
const project = new Project(args.name);
|
|
59924
60215
|
if (args.fps) project.setFrameRate(args.fps);
|
|
59925
|
-
await
|
|
60216
|
+
await writeFile45(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
59926
60217
|
return {
|
|
59927
60218
|
success: true,
|
|
59928
60219
|
data: { name: args.name, outputPath },
|
|
@@ -60642,8 +60933,8 @@ var exportVideoTool = defineTool({
|
|
|
60642
60933
|
var exportTools = [exportVideoTool];
|
|
60643
60934
|
|
|
60644
60935
|
// src/tools/manifest/agent-only.ts
|
|
60645
|
-
import { readFile as readFile43, writeFile as
|
|
60646
|
-
import { resolve as resolve63, join as join28, basename as basename17, extname as
|
|
60936
|
+
import { readFile as readFile43, writeFile as writeFile46, readdir as readdir8, stat as stat8, access as access7, unlink as unlink2 } from "node:fs/promises";
|
|
60937
|
+
import { resolve as resolve63, join as join28, basename as basename17, extname as extname12 } from "node:path";
|
|
60647
60938
|
init_engine();
|
|
60648
60939
|
init_exec_safe();
|
|
60649
60940
|
init_project_resolver();
|
|
@@ -60665,7 +60956,7 @@ function formatSize(bytes) {
|
|
|
60665
60956
|
return `${size.toFixed(1)}${units2[unit]}`;
|
|
60666
60957
|
}
|
|
60667
60958
|
function detectMediaType(filePath) {
|
|
60668
|
-
const ext =
|
|
60959
|
+
const ext = extname12(filePath).toLowerCase();
|
|
60669
60960
|
if ([".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"].includes(ext)) return "video";
|
|
60670
60961
|
if ([".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a"].includes(ext)) return "audio";
|
|
60671
60962
|
if ([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"].includes(ext)) return "image";
|
|
@@ -60692,7 +60983,7 @@ function isMediaFile(filePath) {
|
|
|
60692
60983
|
".webp",
|
|
60693
60984
|
".bmp"
|
|
60694
60985
|
];
|
|
60695
|
-
return mediaExts.includes(
|
|
60986
|
+
return mediaExts.includes(extname12(filePath).toLowerCase());
|
|
60696
60987
|
}
|
|
60697
60988
|
async function getMediaDuration2(filePath) {
|
|
60698
60989
|
try {
|
|
@@ -60775,7 +61066,7 @@ var fsWriteTool = defineTool({
|
|
|
60775
61066
|
async execute(args, ctx) {
|
|
60776
61067
|
try {
|
|
60777
61068
|
const absPath = resolve63(ctx.workingDirectory, args.path);
|
|
60778
|
-
await
|
|
61069
|
+
await writeFile46(absPath, args.content, "utf-8");
|
|
60779
61070
|
return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
|
|
60780
61071
|
} catch (error) {
|
|
60781
61072
|
return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -60838,7 +61129,7 @@ var batchImportTool = defineTool({
|
|
|
60838
61129
|
if (entry.isDirectory() && recursive) {
|
|
60839
61130
|
await scanDir(entryPath);
|
|
60840
61131
|
} else if (entry.isFile()) {
|
|
60841
|
-
const ext =
|
|
61132
|
+
const ext = extname12(entry.name).toLowerCase();
|
|
60842
61133
|
const matchesFilter = !filterExts || filterExts.includes(ext);
|
|
60843
61134
|
if (matchesFilter && isMediaFile(entryPath)) mediaFiles.push(entryPath);
|
|
60844
61135
|
}
|
|
@@ -60861,7 +61152,7 @@ var batchImportTool = defineTool({
|
|
|
60861
61152
|
const source = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
|
|
60862
61153
|
addedSources.push({ id: source.id, name: mediaName, type: mediaType });
|
|
60863
61154
|
}
|
|
60864
|
-
await
|
|
61155
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
60865
61156
|
return {
|
|
60866
61157
|
success: true,
|
|
60867
61158
|
data: { count: addedSources.length, sources: addedSources },
|
|
@@ -60931,7 +61222,7 @@ var batchConcatTool = defineTool({
|
|
|
60931
61222
|
createdClips.push({ id: clip.id, sourceName: source.name, startTime: currentTime, duration: source.duration });
|
|
60932
61223
|
currentTime += source.duration + gap;
|
|
60933
61224
|
}
|
|
60934
|
-
await
|
|
61225
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
60935
61226
|
const totalDuration = currentTime - gap - startTime;
|
|
60936
61227
|
return {
|
|
60937
61228
|
success: true,
|
|
@@ -60994,7 +61285,7 @@ var batchApplyEffectTool = defineTool({
|
|
|
60994
61285
|
});
|
|
60995
61286
|
if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
|
|
60996
61287
|
}
|
|
60997
|
-
await
|
|
61288
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
60998
61289
|
return {
|
|
60999
61290
|
success: true,
|
|
61000
61291
|
data: { applied: appliedEffects.length, effectType: args.effectType },
|
|
@@ -61063,7 +61354,7 @@ var timelineClearTool = defineTool({
|
|
|
61063
61354
|
removed.sources++;
|
|
61064
61355
|
}
|
|
61065
61356
|
}
|
|
61066
|
-
await
|
|
61357
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
61067
61358
|
const parts = [];
|
|
61068
61359
|
if (removed.clips > 0) parts.push(`${removed.clips} clips`);
|
|
61069
61360
|
if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
|
|
@@ -61114,7 +61405,7 @@ var projectSetTool = defineTool({
|
|
|
61114
61405
|
project.setFrameRate(args.fps);
|
|
61115
61406
|
updates.push(`Frame Rate: ${args.fps} fps`);
|
|
61116
61407
|
}
|
|
61117
|
-
await
|
|
61408
|
+
await writeFile46(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
61118
61409
|
return {
|
|
61119
61410
|
success: true,
|
|
61120
61411
|
data: { updates },
|
|
@@ -61484,7 +61775,7 @@ var mediaConcatTool = defineTool({
|
|
|
61484
61775
|
} else {
|
|
61485
61776
|
const tempList = resolve63(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
|
|
61486
61777
|
const listContent = args.inputs.map((i) => `file '${resolve63(ctx.workingDirectory, i)}'`).join("\n");
|
|
61487
|
-
await
|
|
61778
|
+
await writeFile46(tempList, listContent, "utf-8");
|
|
61488
61779
|
try {
|
|
61489
61780
|
await execSafe(
|
|
61490
61781
|
"ffmpeg",
|