@vibeframe/mcp-server 0.48.6 → 0.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +400 -70
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6751,14 +6751,14 @@ var init_output = __esm({
|
|
|
6751
6751
|
return ExitCode2;
|
|
6752
6752
|
})(ExitCode || {});
|
|
6753
6753
|
PROVIDER_ERROR_HINTS = [
|
|
6754
|
+
// Billing (must precede the 429 rate-limit pattern)
|
|
6755
|
+
{ pattern: /402|payment.*required|billing|INSUFFICIENT_BALANCE|insufficient.*(credit|funds|balance)|balance.*(not.*enough|insufficient)|credits?.*exhausted|account.*balance/i, suggestion: "Account balance or credits exhausted. Top up at the provider dashboard, or try -p <other-provider>.", retryable: false },
|
|
6754
6756
|
// Rate limits / quota
|
|
6755
6757
|
{ pattern: /429|rate.?limit|too many requests/i, suggestion: "Rate limited. Wait 30-60 seconds and retry, or check your plan's rate limits.", retryable: true },
|
|
6756
6758
|
{ pattern: /RESOURCE_EXHAUSTED|quota.*exceeded|requests.*per.*(minute|day)/i, suggestion: "Quota exceeded. Wait for the quota window to reset, or upgrade your plan. Consider -p <other-provider> to use a different provider.", retryable: true },
|
|
6757
6759
|
// Auth
|
|
6758
6760
|
{ pattern: /401|unauthorized|(invalid|incorrect).*api.?key|invalid_api_key|authentication.*(failed|error)|missing.*api.?key|did not start with 'key_'/i, suggestion: "API key is invalid or expired. Run 'vibe setup' to update, or check the key at the provider's dashboard.", retryable: false },
|
|
6759
6761
|
{ pattern: /403|forbidden|permission.*denied/i, suggestion: "Access denied. Your API key may lack required permissions, or the feature requires a paid plan.", retryable: false },
|
|
6760
|
-
// Billing
|
|
6761
|
-
{ pattern: /402|payment.*required|billing|INSUFFICIENT_BALANCE|insufficient.*(credit|funds|balance)|credits?.*exhausted/i, suggestion: "Account balance or credits exhausted. Top up at the provider dashboard, or try -p <other-provider>.", retryable: false },
|
|
6762
6762
|
// Server
|
|
6763
6763
|
{ pattern: /500|internal.*error|server.*error/i, suggestion: "Provider server error. Retry in a few minutes.", retryable: true },
|
|
6764
6764
|
{ pattern: /503|service.*unavailable|overloaded|overloaded_error/i, suggestion: "Provider is temporarily overloaded. Retry in 1-2 minutes, or switch provider with -p.", retryable: true },
|
|
@@ -12835,7 +12835,7 @@ var require_previous_map = __commonJS({
|
|
|
12835
12835
|
"../../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/previous-map.js"(exports, module) {
|
|
12836
12836
|
"use strict";
|
|
12837
12837
|
var { existsSync: existsSync35, readFileSync: readFileSync11 } = __require("fs");
|
|
12838
|
-
var { dirname:
|
|
12838
|
+
var { dirname: dirname21, join: join23 } = __require("path");
|
|
12839
12839
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
12840
12840
|
function fromBase64(str) {
|
|
12841
12841
|
if (Buffer) {
|
|
@@ -12854,7 +12854,7 @@ var require_previous_map = __commonJS({
|
|
|
12854
12854
|
if (!this.mapFile && opts.from) {
|
|
12855
12855
|
this.mapFile = opts.from;
|
|
12856
12856
|
}
|
|
12857
|
-
if (this.mapFile) this.root =
|
|
12857
|
+
if (this.mapFile) this.root = dirname21(this.mapFile);
|
|
12858
12858
|
if (text) this.text = text;
|
|
12859
12859
|
}
|
|
12860
12860
|
consumer() {
|
|
@@ -12896,7 +12896,7 @@ var require_previous_map = __commonJS({
|
|
|
12896
12896
|
}
|
|
12897
12897
|
}
|
|
12898
12898
|
loadFile(path15) {
|
|
12899
|
-
this.root =
|
|
12899
|
+
this.root = dirname21(path15);
|
|
12900
12900
|
if (existsSync35(path15)) {
|
|
12901
12901
|
this.mapFile = path15;
|
|
12902
12902
|
return readFileSync11(path15, "utf-8").toString().trim();
|
|
@@ -12933,7 +12933,7 @@ var require_previous_map = __commonJS({
|
|
|
12933
12933
|
return this.decodeInline(this.annotation);
|
|
12934
12934
|
} else if (this.annotation) {
|
|
12935
12935
|
let map3 = this.annotation;
|
|
12936
|
-
if (file) map3 = join23(
|
|
12936
|
+
if (file) map3 = join23(dirname21(file), map3);
|
|
12937
12937
|
return this.loadFile(map3);
|
|
12938
12938
|
}
|
|
12939
12939
|
}
|
|
@@ -13369,12 +13369,12 @@ var require_fromJSON = __commonJS({
|
|
|
13369
13369
|
var require_map_generator = __commonJS({
|
|
13370
13370
|
"../../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/map-generator.js"(exports, module) {
|
|
13371
13371
|
"use strict";
|
|
13372
|
-
var { dirname:
|
|
13372
|
+
var { dirname: dirname21, relative: relative4, resolve: resolve35, sep } = __require("path");
|
|
13373
13373
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
13374
13374
|
var { pathToFileURL } = __require("url");
|
|
13375
13375
|
var Input2 = require_input();
|
|
13376
13376
|
var sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator);
|
|
13377
|
-
var pathAvailable = Boolean(
|
|
13377
|
+
var pathAvailable = Boolean(dirname21 && resolve35 && relative4 && sep);
|
|
13378
13378
|
var MapGenerator = class {
|
|
13379
13379
|
constructor(stringify5, root2, opts, cssString) {
|
|
13380
13380
|
this.stringify = stringify5;
|
|
@@ -13406,7 +13406,7 @@ var require_map_generator = __commonJS({
|
|
|
13406
13406
|
applyPrevMaps() {
|
|
13407
13407
|
for (let prev of this.previous()) {
|
|
13408
13408
|
let from3 = this.toUrl(this.path(prev.file));
|
|
13409
|
-
let root2 = prev.root ||
|
|
13409
|
+
let root2 = prev.root || dirname21(prev.file);
|
|
13410
13410
|
let map3;
|
|
13411
13411
|
if (this.mapOpts.sourcesContent === false) {
|
|
13412
13412
|
map3 = new SourceMapConsumer(prev.text);
|
|
@@ -13593,9 +13593,9 @@ var require_map_generator = __commonJS({
|
|
|
13593
13593
|
if (/^\w+:\/\//.test(file)) return file;
|
|
13594
13594
|
let cached = this.memoizedPaths.get(file);
|
|
13595
13595
|
if (cached) return cached;
|
|
13596
|
-
let from3 = this.opts.to ?
|
|
13596
|
+
let from3 = this.opts.to ? dirname21(this.opts.to) : ".";
|
|
13597
13597
|
if (typeof this.mapOpts.annotation === "string") {
|
|
13598
|
-
from3 =
|
|
13598
|
+
from3 = dirname21(resolve35(from3, this.mapOpts.annotation));
|
|
13599
13599
|
}
|
|
13600
13600
|
let path15 = relative4(from3, file);
|
|
13601
13601
|
this.memoizedPaths.set(file, path15);
|
|
@@ -443791,7 +443791,7 @@ var init_ai_helpers = __esm({
|
|
|
443791
443791
|
|
|
443792
443792
|
// ../cli/src/commands/ai-script-pipeline.ts
|
|
443793
443793
|
import { readFile as readFile9, writeFile as writeFile10, mkdir as mkdir9, unlink as unlink4, rename as rename4 } from "node:fs/promises";
|
|
443794
|
-
import { resolve as resolve20, basename as basename7, extname as extname7 } from "node:path";
|
|
443794
|
+
import { resolve as resolve20, basename as basename7, dirname as dirname14, extname as extname7 } from "node:path";
|
|
443795
443795
|
import { existsSync as existsSync25 } from "node:fs";
|
|
443796
443796
|
function sleep(ms) {
|
|
443797
443797
|
return new Promise((resolve35) => setTimeout(resolve35, ms));
|
|
@@ -443819,6 +443819,73 @@ async function uploadToImgbb(imageBuffer, apiKey) {
|
|
|
443819
443819
|
return { success: false, error: String(err) };
|
|
443820
443820
|
}
|
|
443821
443821
|
}
|
|
443822
|
+
async function extendVideoToTarget(videoPath, targetDuration, outputDir, sceneLabel, options) {
|
|
443823
|
+
const actualDuration = await getVideoDuration(videoPath);
|
|
443824
|
+
if (actualDuration >= targetDuration - 0.1) return;
|
|
443825
|
+
const ratio = targetDuration / actualDuration;
|
|
443826
|
+
const extendedPath = resolve20(outputDir, `${basename7(videoPath, ".mp4")}-extended.mp4`);
|
|
443827
|
+
if (ratio > 1.4 && options?.kling && options?.videoId) {
|
|
443828
|
+
try {
|
|
443829
|
+
options.onProgress?.(`${sceneLabel}: Extending via Kling API...`);
|
|
443830
|
+
const extendResult = await options.kling.extendVideo(options.videoId, {
|
|
443831
|
+
duration: "5"
|
|
443832
|
+
});
|
|
443833
|
+
if (extendResult.status !== "failed" && extendResult.id) {
|
|
443834
|
+
const waitResult = await options.kling.waitForExtendCompletion(
|
|
443835
|
+
extendResult.id,
|
|
443836
|
+
(status) => {
|
|
443837
|
+
options.onProgress?.(`${sceneLabel}: extend ${status.status}...`);
|
|
443838
|
+
},
|
|
443839
|
+
6e5
|
|
443840
|
+
);
|
|
443841
|
+
if (waitResult.status === "completed" && waitResult.videoUrl) {
|
|
443842
|
+
const extendedVideoPath = resolve20(outputDir, `${basename7(videoPath, ".mp4")}-kling-ext.mp4`);
|
|
443843
|
+
const buffer = await downloadVideo(waitResult.videoUrl);
|
|
443844
|
+
await writeFile10(extendedVideoPath, buffer);
|
|
443845
|
+
const concatPath = resolve20(outputDir, `${basename7(videoPath, ".mp4")}-concat.mp4`);
|
|
443846
|
+
const listPath = resolve20(outputDir, `${basename7(videoPath, ".mp4")}-concat.txt`);
|
|
443847
|
+
await writeFile10(listPath, `file '${videoPath}'
|
|
443848
|
+
file '${extendedVideoPath}'`, "utf-8");
|
|
443849
|
+
await execSafe("ffmpeg", ["-y", "-f", "concat", "-safe", "0", "-i", listPath, "-c", "copy", concatPath]);
|
|
443850
|
+
const concatDuration = await getVideoDuration(concatPath);
|
|
443851
|
+
if (concatDuration > targetDuration + 0.5) {
|
|
443852
|
+
await execSafe("ffmpeg", ["-y", "-i", concatPath, "-t", targetDuration.toFixed(2), "-c", "copy", extendedPath]);
|
|
443853
|
+
await unlink4(concatPath);
|
|
443854
|
+
} else {
|
|
443855
|
+
await rename4(concatPath, extendedPath);
|
|
443856
|
+
}
|
|
443857
|
+
await unlink4(extendedVideoPath).catch(() => {
|
|
443858
|
+
});
|
|
443859
|
+
await unlink4(listPath).catch(() => {
|
|
443860
|
+
});
|
|
443861
|
+
await unlink4(videoPath);
|
|
443862
|
+
await rename4(extendedPath, videoPath);
|
|
443863
|
+
return;
|
|
443864
|
+
}
|
|
443865
|
+
}
|
|
443866
|
+
options.onProgress?.(`${sceneLabel}: Kling extend failed, using FFmpeg fallback...`);
|
|
443867
|
+
} catch {
|
|
443868
|
+
options.onProgress?.(`${sceneLabel}: Kling extend error, using FFmpeg fallback...`);
|
|
443869
|
+
}
|
|
443870
|
+
}
|
|
443871
|
+
await extendVideoNaturally(videoPath, targetDuration, extendedPath);
|
|
443872
|
+
await unlink4(videoPath);
|
|
443873
|
+
await rename4(extendedPath, videoPath);
|
|
443874
|
+
}
|
|
443875
|
+
function logSceneFailure(provider, sceneLabel, err) {
|
|
443876
|
+
let msg;
|
|
443877
|
+
if (err instanceof Error) {
|
|
443878
|
+
msg = err.message;
|
|
443879
|
+
} else if (typeof err === "string") {
|
|
443880
|
+
msg = err;
|
|
443881
|
+
} else if (err && typeof err === "object" && "error" in err && typeof err.error === "string") {
|
|
443882
|
+
msg = err.error;
|
|
443883
|
+
} else {
|
|
443884
|
+
msg = String(err);
|
|
443885
|
+
}
|
|
443886
|
+
console.error(source_default.dim(`
|
|
443887
|
+
[${provider} ${sceneLabel}: ${msg}]`));
|
|
443888
|
+
}
|
|
443822
443889
|
async function generateVideoWithRetryGrok(grok, segment, options, maxRetries, onProgress) {
|
|
443823
443890
|
const prompt3 = segment.visualStyle ? `${segment.visuals}. Style: ${segment.visualStyle}` : segment.visuals;
|
|
443824
443891
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
@@ -443832,9 +443899,13 @@ async function generateVideoWithRetryGrok(grok, segment, options, maxRetries, on
|
|
|
443832
443899
|
if (result.status !== "failed" && result.id) {
|
|
443833
443900
|
return { requestId: result.id };
|
|
443834
443901
|
}
|
|
443902
|
+
const providerErr = result.error || "Grok returned failed status";
|
|
443835
443903
|
if (attempt < maxRetries) {
|
|
443836
|
-
onProgress?.(`\u26A0
|
|
443904
|
+
onProgress?.(`\u26A0 ${providerErr.slice(0, 50)}... retry ${attempt + 1}/${maxRetries}`);
|
|
443837
443905
|
await sleep(RETRY_DELAY_MS);
|
|
443906
|
+
} else {
|
|
443907
|
+
console.error(source_default.dim(`
|
|
443908
|
+
[Grok error: ${providerErr}]`));
|
|
443838
443909
|
}
|
|
443839
443910
|
} catch (err) {
|
|
443840
443911
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -443868,9 +443939,13 @@ async function generateVideoWithRetryKling(kling, segment, options, maxRetries,
|
|
|
443868
443939
|
type: options.referenceImage ? "image2video" : "text2video"
|
|
443869
443940
|
};
|
|
443870
443941
|
}
|
|
443942
|
+
const providerErr = result.error || "Kling returned failed status";
|
|
443871
443943
|
if (attempt < maxRetries) {
|
|
443872
|
-
onProgress?.(`\u26A0
|
|
443944
|
+
onProgress?.(`\u26A0 ${providerErr.slice(0, 50)}... retry ${attempt + 1}/${maxRetries}`);
|
|
443873
443945
|
await sleep(RETRY_DELAY_MS);
|
|
443946
|
+
} else {
|
|
443947
|
+
console.error(source_default.dim(`
|
|
443948
|
+
[Kling error: ${providerErr}]`));
|
|
443874
443949
|
}
|
|
443875
443950
|
} catch (err) {
|
|
443876
443951
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -443897,9 +443972,13 @@ async function generateVideoWithRetryRunway(runway, segment, referenceImage, opt
|
|
|
443897
443972
|
if (result.status !== "failed" && result.id) {
|
|
443898
443973
|
return { taskId: result.id };
|
|
443899
443974
|
}
|
|
443975
|
+
const providerErr = result.error || "Runway returned failed status";
|
|
443900
443976
|
if (attempt < maxRetries) {
|
|
443901
|
-
onProgress?.(`\u26A0
|
|
443977
|
+
onProgress?.(`\u26A0 ${providerErr.slice(0, 50)}... retry ${attempt + 1}/${maxRetries}`);
|
|
443902
443978
|
await sleep(RETRY_DELAY_MS);
|
|
443979
|
+
} else {
|
|
443980
|
+
console.error(source_default.dim(`
|
|
443981
|
+
[Runway error: ${providerErr}]`));
|
|
443903
443982
|
}
|
|
443904
443983
|
} catch (err) {
|
|
443905
443984
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -443928,9 +444007,13 @@ async function generateVideoWithRetryVeo(gemini, segment, options, maxRetries, o
|
|
|
443928
444007
|
if (result.status !== "failed" && result.id) {
|
|
443929
444008
|
return { operationName: result.id };
|
|
443930
444009
|
}
|
|
444010
|
+
const providerErr = result.error || "Veo returned failed status";
|
|
443931
444011
|
if (attempt < maxRetries) {
|
|
443932
|
-
onProgress?.(`\u26A0
|
|
444012
|
+
onProgress?.(`\u26A0 ${providerErr.slice(0, 50)}... retry ${attempt + 1}/${maxRetries}`);
|
|
443933
444013
|
await sleep(RETRY_DELAY_MS);
|
|
444014
|
+
} else {
|
|
444015
|
+
console.error(source_default.dim(`
|
|
444016
|
+
[Veo error: ${providerErr}]`));
|
|
443934
444017
|
}
|
|
443935
444018
|
} catch (err) {
|
|
443936
444019
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -444063,13 +444146,42 @@ async function executeScriptToVideo(options) {
|
|
|
444063
444146
|
});
|
|
444064
444147
|
continue;
|
|
444065
444148
|
}
|
|
444066
|
-
const
|
|
444149
|
+
const wordCount = narrationText.split(/\s+/).filter(Boolean).length;
|
|
444150
|
+
const maxWords = segment.duration > 5 ? 24 : 12;
|
|
444151
|
+
if (wordCount > maxWords * 1.3) {
|
|
444152
|
+
options.onProgress?.(
|
|
444153
|
+
`\u26A0 Scene ${i + 1} narration has ${wordCount} words (target ~${maxWords} for ${segment.duration}s); speech may rush.`
|
|
444154
|
+
);
|
|
444155
|
+
}
|
|
444156
|
+
options.onProgress?.(`Scene ${i + 1}/${segments.length}: generating narration...`);
|
|
444157
|
+
let ttsResult = await elevenlabs.textToSpeech(narrationText, {
|
|
444067
444158
|
voiceId: options.voice
|
|
444068
444159
|
});
|
|
444069
444160
|
if (ttsResult.success && ttsResult.audioBuffer) {
|
|
444070
444161
|
const audioPath = resolve20(absOutputDir, `narration-${i + 1}.mp3`);
|
|
444071
444162
|
await writeFile10(audioPath, ttsResult.audioBuffer);
|
|
444072
|
-
|
|
444163
|
+
let actualDuration = await getAudioDuration(audioPath);
|
|
444164
|
+
const videoBracket = segment.duration > 5 ? 10 : 5;
|
|
444165
|
+
const overageRatio = actualDuration / videoBracket;
|
|
444166
|
+
if (overageRatio > 1 && overageRatio <= 1.35) {
|
|
444167
|
+
const adjustedSpeed = Math.min(1.35, parseFloat(overageRatio.toFixed(2)));
|
|
444168
|
+
options.onProgress?.(
|
|
444169
|
+
`Scene ${i + 1}: adjusting narration speed to ${adjustedSpeed}x...`
|
|
444170
|
+
);
|
|
444171
|
+
const speedResult = await elevenlabs.textToSpeech(narrationText, {
|
|
444172
|
+
voiceId: options.voice,
|
|
444173
|
+
speed: adjustedSpeed
|
|
444174
|
+
});
|
|
444175
|
+
if (speedResult.success && speedResult.audioBuffer) {
|
|
444176
|
+
await writeFile10(audioPath, speedResult.audioBuffer);
|
|
444177
|
+
actualDuration = await getAudioDuration(audioPath);
|
|
444178
|
+
ttsResult = speedResult;
|
|
444179
|
+
}
|
|
444180
|
+
} else if (overageRatio > 1.35) {
|
|
444181
|
+
options.onProgress?.(
|
|
444182
|
+
`\u26A0 Scene ${i + 1} narration is ${((overageRatio - 1) * 100).toFixed(0)}% over target (${actualDuration.toFixed(1)}s vs ${videoBracket}s bracket)`
|
|
444183
|
+
);
|
|
444184
|
+
}
|
|
444073
444185
|
segment.duration = actualDuration;
|
|
444074
444186
|
result.narrations.push(audioPath);
|
|
444075
444187
|
result.narrationEntries.push({
|
|
@@ -444120,6 +444232,7 @@ async function executeScriptToVideo(options) {
|
|
|
444120
444232
|
for (let i = 0; i < segments.length; i++) {
|
|
444121
444233
|
const segment = segments[i];
|
|
444122
444234
|
const imagePrompt = segment.visualStyle ? `${segment.visuals}. Style: ${segment.visualStyle}` : segment.visuals;
|
|
444235
|
+
options.onProgress?.(`Scene ${i + 1}/${segments.length}: generating image...`);
|
|
444123
444236
|
try {
|
|
444124
444237
|
let imageBuffer;
|
|
444125
444238
|
let imageUrl;
|
|
@@ -444191,6 +444304,7 @@ async function executeScriptToVideo(options) {
|
|
|
444191
444304
|
}
|
|
444192
444305
|
const segment = segments[i];
|
|
444193
444306
|
const videoDuration = Math.min(15, Math.max(1, segment.duration));
|
|
444307
|
+
options.onProgress?.(`Scene ${i + 1}/${segments.length}: generating video (grok)...`);
|
|
444194
444308
|
const imageBuffer = await readFile9(imagePaths[i]);
|
|
444195
444309
|
const ext = extname7(imagePaths[i]).toLowerCase().slice(1);
|
|
444196
444310
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png";
|
|
@@ -444219,10 +444333,12 @@ async function executeScriptToVideo(options) {
|
|
|
444219
444333
|
videoPaths.push(videoPath);
|
|
444220
444334
|
result.videos.push(videoPath);
|
|
444221
444335
|
} else {
|
|
444336
|
+
logSceneFailure("Grok", `scene ${i + 1}`, waitResult);
|
|
444222
444337
|
videoPaths.push("");
|
|
444223
444338
|
result.failedScenes.push(i + 1);
|
|
444224
444339
|
}
|
|
444225
|
-
} catch {
|
|
444340
|
+
} catch (err) {
|
|
444341
|
+
logSceneFailure("Grok", `scene ${i + 1}`, err);
|
|
444226
444342
|
videoPaths.push("");
|
|
444227
444343
|
result.failedScenes.push(i + 1);
|
|
444228
444344
|
}
|
|
@@ -444237,6 +444353,24 @@ async function executeScriptToVideo(options) {
|
|
|
444237
444353
|
if (!kling.isConfigured()) {
|
|
444238
444354
|
return { success: false, outputDir: absOutputDir, scenes: segments.length, error: "Invalid Kling API key format. Use ACCESS_KEY:SECRET_KEY" };
|
|
444239
444355
|
}
|
|
444356
|
+
const imgbbApiKey = await getApiKeyFromConfig("imgbb") || process.env.IMGBB_API_KEY;
|
|
444357
|
+
const imageUrls = new Array(segments.length);
|
|
444358
|
+
if (imgbbApiKey) {
|
|
444359
|
+
options.onProgress?.("Uploading scene images for Kling image-to-video...");
|
|
444360
|
+
for (let i = 0; i < imagePaths.length; i++) {
|
|
444361
|
+
if (imagePaths[i]) {
|
|
444362
|
+
try {
|
|
444363
|
+
const imageBuffer = await readFile9(imagePaths[i]);
|
|
444364
|
+
const uploadResult = await uploadToImgbb(imageBuffer, imgbbApiKey);
|
|
444365
|
+
if (uploadResult.success && uploadResult.url) {
|
|
444366
|
+
imageUrls[i] = uploadResult.url;
|
|
444367
|
+
}
|
|
444368
|
+
} catch {
|
|
444369
|
+
imageUrls[i] = void 0;
|
|
444370
|
+
}
|
|
444371
|
+
}
|
|
444372
|
+
}
|
|
444373
|
+
}
|
|
444240
444374
|
for (let i = 0; i < segments.length; i++) {
|
|
444241
444375
|
if (!imagePaths[i]) {
|
|
444242
444376
|
videoPaths.push("");
|
|
@@ -444244,10 +444378,15 @@ async function executeScriptToVideo(options) {
|
|
|
444244
444378
|
}
|
|
444245
444379
|
const segment = segments[i];
|
|
444246
444380
|
const videoDuration = segment.duration > 5 ? 10 : 5;
|
|
444381
|
+
options.onProgress?.(`Scene ${i + 1}/${segments.length}: generating video (kling)...`);
|
|
444247
444382
|
const taskResult = await generateVideoWithRetryKling(
|
|
444248
444383
|
kling,
|
|
444249
444384
|
segment,
|
|
444250
|
-
{
|
|
444385
|
+
{
|
|
444386
|
+
duration: videoDuration,
|
|
444387
|
+
aspectRatio: options.aspectRatio || "16:9",
|
|
444388
|
+
referenceImage: imageUrls[i]
|
|
444389
|
+
},
|
|
444251
444390
|
maxRetries
|
|
444252
444391
|
);
|
|
444253
444392
|
if (taskResult) {
|
|
@@ -444257,21 +444396,26 @@ async function executeScriptToVideo(options) {
|
|
|
444257
444396
|
const videoPath = resolve20(absOutputDir, `scene-${i + 1}.mp4`);
|
|
444258
444397
|
const buffer = await downloadVideo(waitResult.videoUrl, videoApiKey);
|
|
444259
444398
|
await writeFile10(videoPath, buffer);
|
|
444260
|
-
|
|
444261
|
-
|
|
444262
|
-
|
|
444263
|
-
|
|
444264
|
-
|
|
444265
|
-
|
|
444266
|
-
|
|
444267
|
-
|
|
444399
|
+
await extendVideoToTarget(
|
|
444400
|
+
videoPath,
|
|
444401
|
+
segment.duration,
|
|
444402
|
+
absOutputDir,
|
|
444403
|
+
`Scene ${i + 1}`,
|
|
444404
|
+
{
|
|
444405
|
+
kling,
|
|
444406
|
+
videoId: waitResult.videoId,
|
|
444407
|
+
onProgress: options.onProgress
|
|
444408
|
+
}
|
|
444409
|
+
);
|
|
444268
444410
|
videoPaths.push(videoPath);
|
|
444269
444411
|
result.videos.push(videoPath);
|
|
444270
444412
|
} else {
|
|
444413
|
+
logSceneFailure("Kling", `scene ${i + 1}`, waitResult);
|
|
444271
444414
|
videoPaths.push("");
|
|
444272
444415
|
result.failedScenes.push(i + 1);
|
|
444273
444416
|
}
|
|
444274
|
-
} catch {
|
|
444417
|
+
} catch (err) {
|
|
444418
|
+
logSceneFailure("Kling", `scene ${i + 1}`, err);
|
|
444275
444419
|
videoPaths.push("");
|
|
444276
444420
|
result.failedScenes.push(i + 1);
|
|
444277
444421
|
}
|
|
@@ -444290,6 +444434,7 @@ async function executeScriptToVideo(options) {
|
|
|
444290
444434
|
}
|
|
444291
444435
|
const segment = segments[i];
|
|
444292
444436
|
const veoDuration = segment.duration > 6 ? 8 : segment.duration > 4 ? 6 : 4;
|
|
444437
|
+
options.onProgress?.(`Scene ${i + 1}/${segments.length}: generating video (veo)...`);
|
|
444293
444438
|
const taskResult = await generateVideoWithRetryVeo(
|
|
444294
444439
|
veo,
|
|
444295
444440
|
segment,
|
|
@@ -444314,10 +444459,12 @@ async function executeScriptToVideo(options) {
|
|
|
444314
444459
|
videoPaths.push(videoPath);
|
|
444315
444460
|
result.videos.push(videoPath);
|
|
444316
444461
|
} else {
|
|
444462
|
+
logSceneFailure("Veo", `scene ${i + 1}`, waitResult);
|
|
444317
444463
|
videoPaths.push("");
|
|
444318
444464
|
result.failedScenes.push(i + 1);
|
|
444319
444465
|
}
|
|
444320
|
-
} catch {
|
|
444466
|
+
} catch (err) {
|
|
444467
|
+
logSceneFailure("Veo", `scene ${i + 1}`, err);
|
|
444321
444468
|
videoPaths.push("");
|
|
444322
444469
|
result.failedScenes.push(i + 1);
|
|
444323
444470
|
}
|
|
@@ -444341,6 +444488,7 @@ async function executeScriptToVideo(options) {
|
|
|
444341
444488
|
const referenceImage = `data:${mimeType};base64,${imageBuffer.toString("base64")}`;
|
|
444342
444489
|
const videoDuration = segment.duration > 5 ? 10 : 5;
|
|
444343
444490
|
const aspectRatio = options.aspectRatio === "1:1" ? "16:9" : options.aspectRatio || "16:9";
|
|
444491
|
+
options.onProgress?.(`Scene ${i + 1}/${segments.length}: generating video (runway)...`);
|
|
444344
444492
|
const taskResult = await generateVideoWithRetryRunway(
|
|
444345
444493
|
runway,
|
|
444346
444494
|
segment,
|
|
@@ -444366,10 +444514,12 @@ async function executeScriptToVideo(options) {
|
|
|
444366
444514
|
videoPaths.push(videoPath);
|
|
444367
444515
|
result.videos.push(videoPath);
|
|
444368
444516
|
} else {
|
|
444517
|
+
logSceneFailure("Runway", `scene ${i + 1}`, waitResult);
|
|
444369
444518
|
videoPaths.push("");
|
|
444370
444519
|
result.failedScenes.push(i + 1);
|
|
444371
444520
|
}
|
|
444372
|
-
} catch {
|
|
444521
|
+
} catch (err) {
|
|
444522
|
+
logSceneFailure("Runway", `scene ${i + 1}`, err);
|
|
444373
444523
|
videoPaths.push("");
|
|
444374
444524
|
result.failedScenes.push(i + 1);
|
|
444375
444525
|
}
|
|
@@ -444474,7 +444624,11 @@ async function executeScriptToVideo(options) {
|
|
|
444474
444624
|
});
|
|
444475
444625
|
currentTime += actualDuration;
|
|
444476
444626
|
}
|
|
444477
|
-
const projectPath = resolve20(absOutputDir, "project.vibe.json");
|
|
444627
|
+
const projectPath = options.projectFilePath ? resolve20(process.cwd(), options.projectFilePath) : resolve20(absOutputDir, "project.vibe.json");
|
|
444628
|
+
const projectParentDir = dirname14(projectPath);
|
|
444629
|
+
if (!existsSync25(projectParentDir)) {
|
|
444630
|
+
await mkdir9(projectParentDir, { recursive: true });
|
|
444631
|
+
}
|
|
444478
444632
|
await writeFile10(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
444479
444633
|
result.projectPath = projectPath;
|
|
444480
444634
|
result.totalDuration = currentTime;
|
|
@@ -444536,6 +444690,8 @@ async function executeRegenerateScene(options) {
|
|
|
444536
444690
|
}
|
|
444537
444691
|
}
|
|
444538
444692
|
const regenerateVideo = options.videoOnly || !options.narrationOnly && !options.imageOnly;
|
|
444693
|
+
const regenerateNarration = options.narrationOnly || !options.videoOnly && !options.imageOnly;
|
|
444694
|
+
const regenerateImage = options.imageOnly || !options.videoOnly && !options.narrationOnly;
|
|
444539
444695
|
let videoApiKey;
|
|
444540
444696
|
if (regenerateVideo) {
|
|
444541
444697
|
const generatorKeyMap = {
|
|
@@ -444554,11 +444710,163 @@ async function executeRegenerateScene(options) {
|
|
|
444554
444710
|
return { ...result, error: `${genInfo.name} API key required. Run 'vibe setup' or set ${genInfo.envVar} in .env` };
|
|
444555
444711
|
}
|
|
444556
444712
|
}
|
|
444713
|
+
let imageApiKey;
|
|
444714
|
+
if (regenerateImage) {
|
|
444715
|
+
const imageProvider = options.imageProvider || "openai";
|
|
444716
|
+
const imageKeyMap = {
|
|
444717
|
+
openai: { envVar: "OPENAI_API_KEY", name: "OpenAI" },
|
|
444718
|
+
gemini: { envVar: "GOOGLE_API_KEY", name: "Google" },
|
|
444719
|
+
grok: { envVar: "XAI_API_KEY", name: "xAI" }
|
|
444720
|
+
};
|
|
444721
|
+
const info = imageKeyMap[imageProvider];
|
|
444722
|
+
if (!info) {
|
|
444723
|
+
return { ...result, error: `Invalid imageProvider: ${imageProvider}` };
|
|
444724
|
+
}
|
|
444725
|
+
imageApiKey = await getApiKey(info.envVar, info.name) ?? void 0;
|
|
444726
|
+
if (!imageApiKey) {
|
|
444727
|
+
return { ...result, error: `${info.name} API key required. Run 'vibe setup' or set ${info.envVar} in .env` };
|
|
444728
|
+
}
|
|
444729
|
+
}
|
|
444730
|
+
let elevenlabsApiKey;
|
|
444731
|
+
if (regenerateNarration) {
|
|
444732
|
+
elevenlabsApiKey = await getApiKey("ELEVENLABS_API_KEY", "ElevenLabs") ?? void 0;
|
|
444733
|
+
if (!elevenlabsApiKey) {
|
|
444734
|
+
return { ...result, error: "ElevenLabs API key required. Run 'vibe setup' or set ELEVENLABS_API_KEY in .env" };
|
|
444735
|
+
}
|
|
444736
|
+
}
|
|
444737
|
+
let storyboardMutated = false;
|
|
444557
444738
|
for (const sceneNum of options.scenes) {
|
|
444558
444739
|
const segment = segments[sceneNum - 1];
|
|
444740
|
+
const narrationPath = resolve20(outputDir, `narration-${sceneNum}.mp3`);
|
|
444559
444741
|
const imagePath = resolve20(outputDir, `scene-${sceneNum}.png`);
|
|
444560
444742
|
const videoPath = resolve20(outputDir, `scene-${sceneNum}.mp4`);
|
|
444743
|
+
let sceneFailed = false;
|
|
444744
|
+
if (regenerateNarration && elevenlabsApiKey) {
|
|
444745
|
+
options.onProgress?.(`Scene ${sceneNum}: regenerating narration...`);
|
|
444746
|
+
const elevenlabs = new ElevenLabsProvider();
|
|
444747
|
+
await elevenlabs.initialize({ apiKey: elevenlabsApiKey });
|
|
444748
|
+
const narrationText = segment.narration || segment.description;
|
|
444749
|
+
const ttsResult = await elevenlabs.textToSpeech(narrationText, {
|
|
444750
|
+
voiceId: options.voice
|
|
444751
|
+
});
|
|
444752
|
+
if (ttsResult.success && ttsResult.audioBuffer) {
|
|
444753
|
+
await writeFile10(narrationPath, ttsResult.audioBuffer);
|
|
444754
|
+
segment.duration = await getAudioDuration(narrationPath);
|
|
444755
|
+
storyboardMutated = true;
|
|
444756
|
+
} else {
|
|
444757
|
+
sceneFailed = true;
|
|
444758
|
+
}
|
|
444759
|
+
}
|
|
444760
|
+
if (!sceneFailed && regenerateImage && imageApiKey) {
|
|
444761
|
+
options.onProgress?.(`Scene ${sceneNum}: regenerating image...`);
|
|
444762
|
+
const imageProvider = options.imageProvider || "openai";
|
|
444763
|
+
const characterDesc = segment.characterDescription || segments[0]?.characterDescription;
|
|
444764
|
+
let imagePrompt = segment.visualStyle ? `${segment.visuals}. Style: ${segment.visualStyle}` : segment.visuals;
|
|
444765
|
+
if (characterDesc) {
|
|
444766
|
+
imagePrompt = `${imagePrompt}
|
|
444767
|
+
|
|
444768
|
+
IMPORTANT - Character appearance must match exactly: ${characterDesc}`;
|
|
444769
|
+
}
|
|
444770
|
+
let referenceImageBuffer;
|
|
444771
|
+
const refSceneNum = options.referenceScene;
|
|
444772
|
+
if (refSceneNum && refSceneNum >= 1 && refSceneNum <= segments.length && refSceneNum !== sceneNum) {
|
|
444773
|
+
const refImagePath = resolve20(outputDir, `scene-${refSceneNum}.png`);
|
|
444774
|
+
if (existsSync25(refImagePath)) {
|
|
444775
|
+
referenceImageBuffer = await readFile9(refImagePath);
|
|
444776
|
+
}
|
|
444777
|
+
} else if (!refSceneNum) {
|
|
444778
|
+
for (let i = 1; i <= segments.length; i++) {
|
|
444779
|
+
if (i !== sceneNum) {
|
|
444780
|
+
const otherImagePath = resolve20(outputDir, `scene-${i}.png`);
|
|
444781
|
+
if (existsSync25(otherImagePath)) {
|
|
444782
|
+
referenceImageBuffer = await readFile9(otherImagePath);
|
|
444783
|
+
break;
|
|
444784
|
+
}
|
|
444785
|
+
}
|
|
444786
|
+
}
|
|
444787
|
+
}
|
|
444788
|
+
const dalleImageSizes = {
|
|
444789
|
+
"16:9": "1536x1024",
|
|
444790
|
+
"9:16": "1024x1536",
|
|
444791
|
+
"1:1": "1024x1024"
|
|
444792
|
+
};
|
|
444793
|
+
let imageBuffer;
|
|
444794
|
+
let imageUrl;
|
|
444795
|
+
if (imageProvider === "openai") {
|
|
444796
|
+
const openaiImage = new OpenAIImageProvider();
|
|
444797
|
+
await openaiImage.initialize({ apiKey: imageApiKey });
|
|
444798
|
+
const imageResult = await openaiImage.generateImage(imagePrompt, {
|
|
444799
|
+
size: dalleImageSizes[options.aspectRatio || "16:9"] || "1536x1024",
|
|
444800
|
+
quality: "standard"
|
|
444801
|
+
});
|
|
444802
|
+
if (imageResult.success && imageResult.images?.[0]) {
|
|
444803
|
+
const img = imageResult.images[0];
|
|
444804
|
+
if (img.base64) imageBuffer = Buffer.from(img.base64, "base64");
|
|
444805
|
+
else if (img.url) imageUrl = img.url;
|
|
444806
|
+
}
|
|
444807
|
+
} else if (imageProvider === "gemini") {
|
|
444808
|
+
const gemini = new GeminiProvider();
|
|
444809
|
+
await gemini.initialize({ apiKey: imageApiKey });
|
|
444810
|
+
if (referenceImageBuffer) {
|
|
444811
|
+
const simplifiedVisuals = segment.visuals.split(/[,.]/).find(
|
|
444812
|
+
(part) => part.includes("standing") || part.includes("sitting") || part.includes("walking") || part.includes("lying") || part.includes("reaching") || part.includes("looking") || part.includes("working") || part.includes("coding") || part.includes("typing")
|
|
444813
|
+
) || segment.visuals.split(".")[0];
|
|
444814
|
+
const editPrompt = `Generate a new image showing the SAME SINGLE person from the reference image in a new scene.
|
|
444815
|
+
|
|
444816
|
+
REFERENCE: Look at the person in the reference image - their face, hair, build, and overall appearance.
|
|
444817
|
+
|
|
444818
|
+
NEW SCENE: ${simplifiedVisuals}
|
|
444819
|
+
|
|
444820
|
+
CRITICAL RULES:
|
|
444821
|
+
1. Show ONLY ONE person - the exact same individual from the reference image
|
|
444822
|
+
2. The person must have the IDENTICAL face, hair style, and body type
|
|
444823
|
+
3. Do NOT show multiple people or duplicate the character
|
|
444824
|
+
4. Create a single moment in time, one pose, one action
|
|
444825
|
+
5. Match the art style and quality of the reference image
|
|
444826
|
+
|
|
444827
|
+
Generate the single-person scene image now.`;
|
|
444828
|
+
const imageResult = await gemini.editImage([referenceImageBuffer], editPrompt, {
|
|
444829
|
+
aspectRatio: options.aspectRatio || "16:9"
|
|
444830
|
+
});
|
|
444831
|
+
if (imageResult.success && imageResult.images?.[0]?.base64) {
|
|
444832
|
+
imageBuffer = Buffer.from(imageResult.images[0].base64, "base64");
|
|
444833
|
+
}
|
|
444834
|
+
} else {
|
|
444835
|
+
const imageResult = await gemini.generateImage(imagePrompt, {
|
|
444836
|
+
aspectRatio: options.aspectRatio || "16:9"
|
|
444837
|
+
});
|
|
444838
|
+
if (imageResult.success && imageResult.images?.[0]?.base64) {
|
|
444839
|
+
imageBuffer = Buffer.from(imageResult.images[0].base64, "base64");
|
|
444840
|
+
}
|
|
444841
|
+
}
|
|
444842
|
+
} else if (imageProvider === "grok") {
|
|
444843
|
+
const grok = new GrokProvider();
|
|
444844
|
+
await grok.initialize({ apiKey: imageApiKey });
|
|
444845
|
+
const imageResult = await grok.generateImage(imagePrompt, {
|
|
444846
|
+
aspectRatio: options.aspectRatio || "16:9"
|
|
444847
|
+
});
|
|
444848
|
+
if (imageResult.success && imageResult.images?.[0]) {
|
|
444849
|
+
const img = imageResult.images[0];
|
|
444850
|
+
if (img.base64) imageBuffer = Buffer.from(img.base64, "base64");
|
|
444851
|
+
else if (img.url) imageUrl = img.url;
|
|
444852
|
+
}
|
|
444853
|
+
}
|
|
444854
|
+
if (imageBuffer) {
|
|
444855
|
+
await writeFile10(imagePath, imageBuffer);
|
|
444856
|
+
} else if (imageUrl) {
|
|
444857
|
+
const response = await fetch(imageUrl);
|
|
444858
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
444859
|
+
await writeFile10(imagePath, buffer);
|
|
444860
|
+
} else {
|
|
444861
|
+
sceneFailed = true;
|
|
444862
|
+
}
|
|
444863
|
+
}
|
|
444864
|
+
if (sceneFailed) {
|
|
444865
|
+
result.failedScenes.push(sceneNum);
|
|
444866
|
+
continue;
|
|
444867
|
+
}
|
|
444561
444868
|
if (regenerateVideo && videoApiKey) {
|
|
444869
|
+
options.onProgress?.(`Scene ${sceneNum}: regenerating video (${options.generator || "grok"})...`);
|
|
444562
444870
|
if (!existsSync25(imagePath)) {
|
|
444563
444871
|
result.failedScenes.push(sceneNum);
|
|
444564
444872
|
continue;
|
|
@@ -444599,9 +444907,11 @@ async function executeRegenerateScene(options) {
|
|
|
444599
444907
|
}
|
|
444600
444908
|
result.regeneratedScenes.push(sceneNum);
|
|
444601
444909
|
} else {
|
|
444910
|
+
logSceneFailure("Grok", `scene ${sceneNum}`, waitResult);
|
|
444602
444911
|
result.failedScenes.push(sceneNum);
|
|
444603
444912
|
}
|
|
444604
|
-
} catch {
|
|
444913
|
+
} catch (err) {
|
|
444914
|
+
logSceneFailure("Grok", `scene ${sceneNum}`, err);
|
|
444605
444915
|
result.failedScenes.push(sceneNum);
|
|
444606
444916
|
}
|
|
444607
444917
|
} else {
|
|
@@ -444640,9 +444950,11 @@ async function executeRegenerateScene(options) {
|
|
|
444640
444950
|
}
|
|
444641
444951
|
result.regeneratedScenes.push(sceneNum);
|
|
444642
444952
|
} else {
|
|
444953
|
+
logSceneFailure("Veo", `scene ${sceneNum}`, waitResult);
|
|
444643
444954
|
result.failedScenes.push(sceneNum);
|
|
444644
444955
|
}
|
|
444645
|
-
} catch {
|
|
444956
|
+
} catch (err) {
|
|
444957
|
+
logSceneFailure("Veo", `scene ${sceneNum}`, err);
|
|
444646
444958
|
result.failedScenes.push(sceneNum);
|
|
444647
444959
|
}
|
|
444648
444960
|
} else {
|
|
@@ -444679,19 +444991,24 @@ async function executeRegenerateScene(options) {
|
|
|
444679
444991
|
if (waitResult.status === "completed" && waitResult.videoUrl) {
|
|
444680
444992
|
const buffer = await downloadVideo(waitResult.videoUrl, videoApiKey);
|
|
444681
444993
|
await writeFile10(videoPath, buffer);
|
|
444682
|
-
|
|
444683
|
-
|
|
444684
|
-
|
|
444685
|
-
|
|
444686
|
-
|
|
444687
|
-
|
|
444688
|
-
|
|
444689
|
-
|
|
444994
|
+
await extendVideoToTarget(
|
|
444995
|
+
videoPath,
|
|
444996
|
+
segment.duration,
|
|
444997
|
+
outputDir,
|
|
444998
|
+
`Scene ${sceneNum}`,
|
|
444999
|
+
{
|
|
445000
|
+
kling,
|
|
445001
|
+
videoId: waitResult.videoId,
|
|
445002
|
+
onProgress: options.onProgress
|
|
445003
|
+
}
|
|
445004
|
+
);
|
|
444690
445005
|
result.regeneratedScenes.push(sceneNum);
|
|
444691
445006
|
} else {
|
|
445007
|
+
logSceneFailure("Kling", `scene ${sceneNum}`, waitResult);
|
|
444692
445008
|
result.failedScenes.push(sceneNum);
|
|
444693
445009
|
}
|
|
444694
|
-
} catch {
|
|
445010
|
+
} catch (err) {
|
|
445011
|
+
logSceneFailure("Kling", `scene ${sceneNum}`, err);
|
|
444695
445012
|
result.failedScenes.push(sceneNum);
|
|
444696
445013
|
}
|
|
444697
445014
|
} else {
|
|
@@ -444727,16 +445044,29 @@ async function executeRegenerateScene(options) {
|
|
|
444727
445044
|
}
|
|
444728
445045
|
result.regeneratedScenes.push(sceneNum);
|
|
444729
445046
|
} else {
|
|
445047
|
+
logSceneFailure("Runway", `scene ${sceneNum}`, waitResult);
|
|
444730
445048
|
result.failedScenes.push(sceneNum);
|
|
444731
445049
|
}
|
|
444732
|
-
} catch {
|
|
445050
|
+
} catch (err) {
|
|
445051
|
+
logSceneFailure("Runway", `scene ${sceneNum}`, err);
|
|
444733
445052
|
result.failedScenes.push(sceneNum);
|
|
444734
445053
|
}
|
|
444735
445054
|
} else {
|
|
444736
445055
|
result.failedScenes.push(sceneNum);
|
|
444737
445056
|
}
|
|
444738
445057
|
}
|
|
445058
|
+
} else if (!sceneFailed) {
|
|
445059
|
+
result.regeneratedScenes.push(sceneNum);
|
|
445060
|
+
}
|
|
445061
|
+
}
|
|
445062
|
+
if (storyboardMutated) {
|
|
445063
|
+
let currentTime = 0;
|
|
445064
|
+
for (const segment of segments) {
|
|
445065
|
+
segment.startTime = currentTime;
|
|
445066
|
+
currentTime += segment.duration;
|
|
444739
445067
|
}
|
|
445068
|
+
const serialized = storyboardPath.endsWith(".yaml") ? (0, import_yaml2.stringify)({ scenes: segments }, { indent: 2 }) : JSON.stringify(segments, null, 2);
|
|
445069
|
+
await writeFile10(storyboardPath, serialized, "utf-8");
|
|
444740
445070
|
}
|
|
444741
445071
|
result.success = result.failedScenes.length === 0;
|
|
444742
445072
|
return result;
|
|
@@ -447094,7 +447424,7 @@ __export(generate_exports, {
|
|
|
447094
447424
|
executeStoryboard: () => executeStoryboard,
|
|
447095
447425
|
generateCommand: () => generateCommand
|
|
447096
447426
|
});
|
|
447097
|
-
import { resolve as resolve25, dirname as
|
|
447427
|
+
import { resolve as resolve25, dirname as dirname16, basename as basename9, extname as extname9 } from "node:path";
|
|
447098
447428
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
447099
447429
|
import { readFile as readFile13, writeFile as writeFile14, mkdir as mkdir11 } from "node:fs/promises";
|
|
447100
447430
|
import { existsSync as existsSync28 } from "node:fs";
|
|
@@ -447360,7 +447690,7 @@ Examples:
|
|
|
447360
447690
|
} else {
|
|
447361
447691
|
throw new Error("No image data available");
|
|
447362
447692
|
}
|
|
447363
|
-
await mkdir11(
|
|
447693
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
447364
447694
|
await writeFile14(outputPath, buffer);
|
|
447365
447695
|
}
|
|
447366
447696
|
outputResult({ success: true, provider: "openai", images: result.images.map((img) => ({ url: img.url, revisedPrompt: img.revisedPrompt })), outputPath });
|
|
@@ -447396,7 +447726,7 @@ Examples:
|
|
|
447396
447726
|
throw new Error("No image data available");
|
|
447397
447727
|
}
|
|
447398
447728
|
const outputPath = resolve25(process.cwd(), options.output);
|
|
447399
|
-
await mkdir11(
|
|
447729
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
447400
447730
|
await writeFile14(outputPath, buffer);
|
|
447401
447731
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
447402
447732
|
} catch (err) {
|
|
@@ -447446,7 +447776,7 @@ Examples:
|
|
|
447446
447776
|
if (outputPath && result.images.length > 0) {
|
|
447447
447777
|
const img = result.images[0];
|
|
447448
447778
|
const buffer = Buffer.from(img.base64, "base64");
|
|
447449
|
-
await mkdir11(
|
|
447779
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
447450
447780
|
await writeFile14(outputPath, buffer);
|
|
447451
447781
|
}
|
|
447452
447782
|
outputResult({ success: true, provider: "gemini", images: result.images.map((img) => ({ mimeType: img.mimeType })), outputPath });
|
|
@@ -447467,7 +447797,7 @@ Examples:
|
|
|
447467
447797
|
const img = result.images[0];
|
|
447468
447798
|
const buffer = Buffer.from(img.base64, "base64");
|
|
447469
447799
|
const outputPath = resolve25(process.cwd(), options.output);
|
|
447470
|
-
await mkdir11(
|
|
447800
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
447471
447801
|
await writeFile14(outputPath, buffer);
|
|
447472
447802
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
447473
447803
|
} catch (err) {
|
|
@@ -447506,7 +447836,7 @@ Examples:
|
|
|
447506
447836
|
} else {
|
|
447507
447837
|
throw new Error("No image data available");
|
|
447508
447838
|
}
|
|
447509
|
-
await mkdir11(
|
|
447839
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
447510
447840
|
await writeFile14(outputPath, buffer);
|
|
447511
447841
|
}
|
|
447512
447842
|
outputResult({ success: true, provider: "grok", images: result.images.map((img) => ({ url: img.url })), outputPath });
|
|
@@ -447539,7 +447869,7 @@ Examples:
|
|
|
447539
447869
|
throw new Error("No image data available");
|
|
447540
447870
|
}
|
|
447541
447871
|
const outputPath = resolve25(process.cwd(), options.output);
|
|
447542
|
-
await mkdir11(
|
|
447872
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
447543
447873
|
await writeFile14(outputPath, buffer);
|
|
447544
447874
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
447545
447875
|
} catch (err) {
|
|
@@ -447549,7 +447879,7 @@ Examples:
|
|
|
447549
447879
|
} else if (provider === "runway") {
|
|
447550
447880
|
const { spawn: spawn10 } = await import("child_process");
|
|
447551
447881
|
const __filename2 = fileURLToPath5(import.meta.url);
|
|
447552
|
-
const __dirname3 =
|
|
447882
|
+
const __dirname3 = dirname16(__filename2);
|
|
447553
447883
|
const scriptPath = resolve25(__dirname3, "../../../../.claude/skills/runway-video/scripts/image.py");
|
|
447554
447884
|
if (!options.output) {
|
|
447555
447885
|
spinner2.fail("Output path required for Runway");
|
|
@@ -448344,7 +448674,7 @@ Examples:
|
|
|
448344
448674
|
throw new Error("No image data available");
|
|
448345
448675
|
}
|
|
448346
448676
|
outputPath = resolve25(process.cwd(), options.output);
|
|
448347
|
-
await mkdir11(
|
|
448677
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
448348
448678
|
await writeFile14(outputPath, buffer);
|
|
448349
448679
|
}
|
|
448350
448680
|
outputResult({ success: true, imageUrl: img.url, outputPath });
|
|
@@ -448371,7 +448701,7 @@ Examples:
|
|
|
448371
448701
|
throw new Error("No image data available");
|
|
448372
448702
|
}
|
|
448373
448703
|
const outputPath = resolve25(process.cwd(), options.output);
|
|
448374
|
-
await mkdir11(
|
|
448704
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
448375
448705
|
await writeFile14(outputPath, buffer);
|
|
448376
448706
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
448377
448707
|
} catch (err) {
|
|
@@ -448417,7 +448747,7 @@ Examples:
|
|
|
448417
448747
|
throw new Error("No image data available");
|
|
448418
448748
|
}
|
|
448419
448749
|
outputPath = resolve25(process.cwd(), options.output);
|
|
448420
|
-
await mkdir11(
|
|
448750
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
448421
448751
|
await writeFile14(outputPath, buffer);
|
|
448422
448752
|
}
|
|
448423
448753
|
outputResult({ success: true, imageUrl: img.url, outputPath });
|
|
@@ -448444,7 +448774,7 @@ Examples:
|
|
|
448444
448774
|
throw new Error("No image data available");
|
|
448445
448775
|
}
|
|
448446
448776
|
const outputPath = resolve25(process.cwd(), options.output);
|
|
448447
|
-
await mkdir11(
|
|
448777
|
+
await mkdir11(dirname16(outputPath), { recursive: true });
|
|
448448
448778
|
await writeFile14(outputPath, buffer);
|
|
448449
448779
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
448450
448780
|
} catch (err) {
|
|
@@ -449316,7 +449646,7 @@ var init_ai_edit_cli = __esm({
|
|
|
449316
449646
|
|
|
449317
449647
|
// ../cli/src/commands/ai-fill-gaps.ts
|
|
449318
449648
|
import { readFile as readFile14, writeFile as writeFile15, mkdir as mkdir12 } from "node:fs/promises";
|
|
449319
|
-
import { resolve as resolve27, dirname as
|
|
449649
|
+
import { resolve as resolve27, dirname as dirname17 } from "node:path";
|
|
449320
449650
|
import { existsSync as existsSync30 } from "node:fs";
|
|
449321
449651
|
function detectVideoGaps(videoClips, totalDuration) {
|
|
449322
449652
|
const gaps = [];
|
|
@@ -449460,7 +449790,7 @@ function registerFillGapsCommand(aiCommand) {
|
|
|
449460
449790
|
if (!kling.isConfigured()) {
|
|
449461
449791
|
exitWithError(authError("KLING_API_KEY", "Kling"));
|
|
449462
449792
|
}
|
|
449463
|
-
const projectDir =
|
|
449793
|
+
const projectDir = dirname17(filePath);
|
|
449464
449794
|
const footageDir = options.dir ? resolve27(process.cwd(), options.dir) : resolve27(projectDir, "footage");
|
|
449465
449795
|
if (!existsSync30(footageDir)) {
|
|
449466
449796
|
await mkdir12(footageDir, { recursive: true });
|
|
@@ -449709,7 +450039,7 @@ __export(edit_cmd_exports, {
|
|
|
449709
450039
|
executeSpeedRamp: () => executeSpeedRamp,
|
|
449710
450040
|
executeUpscale: () => executeUpscale
|
|
449711
450041
|
});
|
|
449712
|
-
import { resolve as resolve28, dirname as
|
|
450042
|
+
import { resolve as resolve28, dirname as dirname18 } from "node:path";
|
|
449713
450043
|
import { readFile as readFile15, writeFile as writeFile16, mkdir as mkdir13 } from "node:fs/promises";
|
|
449714
450044
|
async function executeGrade(options) {
|
|
449715
450045
|
const { videoPath, style, preset, output: output3, analyzeOnly, apiKey } = options;
|
|
@@ -450421,7 +450751,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
450421
450751
|
const img = result.images[0];
|
|
450422
450752
|
const outputPath = resolve28(process.cwd(), options.output);
|
|
450423
450753
|
const saveImage = async () => {
|
|
450424
|
-
await mkdir13(
|
|
450754
|
+
await mkdir13(dirname18(outputPath), { recursive: true });
|
|
450425
450755
|
if (img.base64) {
|
|
450426
450756
|
const buffer = Buffer.from(img.base64, "base64");
|
|
450427
450757
|
await writeFile16(outputPath, buffer);
|
|
@@ -450612,7 +450942,7 @@ __export(ai_audio_exports, {
|
|
|
450612
450942
|
executeVoiceClone: () => executeVoiceClone,
|
|
450613
450943
|
registerAudioCommands: () => registerAudioCommands
|
|
450614
450944
|
});
|
|
450615
|
-
import { resolve as resolve29, dirname as
|
|
450945
|
+
import { resolve as resolve29, dirname as dirname19, basename as basename11, extname as extname11 } from "node:path";
|
|
450616
450946
|
import { readFile as readFile16, writeFile as writeFile17 } from "node:fs/promises";
|
|
450617
450947
|
import { existsSync as existsSync31 } from "node:fs";
|
|
450618
450948
|
function _registerAudioCommands(aiCommand) {
|
|
@@ -451068,7 +451398,7 @@ function _registerAudioCommands(aiCommand) {
|
|
|
451068
451398
|
const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
|
|
451069
451399
|
let audioPath = absPath;
|
|
451070
451400
|
if (isVideo) {
|
|
451071
|
-
const tempAudioPath = resolve29(
|
|
451401
|
+
const tempAudioPath = resolve29(dirname19(absPath), `temp-audio-${Date.now()}.mp3`);
|
|
451072
451402
|
try {
|
|
451073
451403
|
execSafeSync("ffmpeg", ["-i", absPath, "-vn", "-acodec", "mp3", "-y", tempAudioPath]);
|
|
451074
451404
|
audioPath = tempAudioPath;
|
|
@@ -451200,7 +451530,7 @@ ${segmentTexts}`,
|
|
|
451200
451530
|
const combinedBuffer = Buffer.concat(dubbedAudioBuffers.map((a) => a.buffer));
|
|
451201
451531
|
const outputExt = isVideo ? ".mp3" : extname11(absPath);
|
|
451202
451532
|
const defaultOutputPath = resolve29(
|
|
451203
|
-
|
|
451533
|
+
dirname19(absPath),
|
|
451204
451534
|
`${basename11(absPath, extname11(absPath))}-${options.language}${outputExt}`
|
|
451205
451535
|
);
|
|
451206
451536
|
const finalOutputPath = resolve29(process.cwd(), options.output || defaultOutputPath);
|
|
@@ -451363,7 +451693,7 @@ async function executeDub(options) {
|
|
|
451363
451693
|
const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
|
|
451364
451694
|
let audioPath = absPath;
|
|
451365
451695
|
if (isVideo) {
|
|
451366
|
-
const tempAudioPath = resolve29(
|
|
451696
|
+
const tempAudioPath = resolve29(dirname19(absPath), `temp-audio-${Date.now()}.mp3`);
|
|
451367
451697
|
execSafeSync("ffmpeg", ["-i", absPath, "-vn", "-acodec", "mp3", "-y", tempAudioPath]);
|
|
451368
451698
|
audioPath = tempAudioPath;
|
|
451369
451699
|
}
|
|
@@ -451445,7 +451775,7 @@ ${segmentTexts}`,
|
|
|
451445
451775
|
}
|
|
451446
451776
|
const combinedBuffer = Buffer.concat(dubbedBuffers);
|
|
451447
451777
|
const outputExt = isVideo ? ".mp3" : extname11(absPath);
|
|
451448
|
-
const defaultOutputPath = resolve29(
|
|
451778
|
+
const defaultOutputPath = resolve29(dirname19(absPath), `${basename11(absPath, extname11(absPath))}-${language}${outputExt}`);
|
|
451449
451779
|
const finalOutputPath = resolve29(process.cwd(), output3 || defaultOutputPath);
|
|
451450
451780
|
await writeFile17(finalOutputPath, combinedBuffer);
|
|
451451
451781
|
if (isVideo && audioPath !== absPath) {
|
|
@@ -451482,7 +451812,7 @@ async function executeDuck(options) {
|
|
|
451482
451812
|
const absVoicePath = resolve29(process.cwd(), voicePath);
|
|
451483
451813
|
if (!existsSync31(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
|
|
451484
451814
|
if (!existsSync31(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
|
|
451485
|
-
const defaultOutput = resolve29(
|
|
451815
|
+
const defaultOutput = resolve29(dirname19(absMusicPath), `${basename11(absMusicPath, extname11(absMusicPath))}-ducked${extname11(absMusicPath)}`);
|
|
451486
451816
|
const outputPath = resolve29(process.cwd(), output3 || defaultOutput);
|
|
451487
451817
|
const filter4 = `[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`;
|
|
451488
451818
|
await execSafe("ffmpeg", [
|
|
@@ -453637,7 +453967,7 @@ import { join as join21 } from "node:path";
|
|
|
453637
453967
|
|
|
453638
453968
|
// ../cli/src/commands/ai-highlights.ts
|
|
453639
453969
|
import { readFile as readFile10, writeFile as writeFile11, mkdir as mkdir10 } from "node:fs/promises";
|
|
453640
|
-
import { resolve as resolve21, dirname as
|
|
453970
|
+
import { resolve as resolve21, dirname as dirname15, basename as basename8, extname as extname8 } from "node:path";
|
|
453641
453971
|
import { existsSync as existsSync26 } from "node:fs";
|
|
453642
453972
|
init_dist2();
|
|
453643
453973
|
init_engine();
|
|
@@ -453999,7 +454329,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
453999
454329
|
}))
|
|
454000
454330
|
};
|
|
454001
454331
|
}
|
|
454002
|
-
const outputDir = options.outputDir ? resolve21(process.cwd(), options.outputDir) :
|
|
454332
|
+
const outputDir = options.outputDir ? resolve21(process.cwd(), options.outputDir) : dirname15(absPath);
|
|
454003
454333
|
if (options.outputDir && !existsSync26(outputDir)) {
|
|
454004
454334
|
await mkdir10(outputDir, { recursive: true });
|
|
454005
454335
|
}
|
|
@@ -454785,7 +455115,7 @@ init_ai_edit();
|
|
|
454785
455115
|
init_api_key();
|
|
454786
455116
|
init_exec_safe();
|
|
454787
455117
|
init_remotion();
|
|
454788
|
-
import { resolve as resolve33, dirname as
|
|
455118
|
+
import { resolve as resolve33, dirname as dirname20, basename as basename13 } from "node:path";
|
|
454789
455119
|
import { writeFile as writeFile21, mkdir as mkdir15, rm as rm5 } from "node:fs/promises";
|
|
454790
455120
|
import { existsSync as existsSync34 } from "node:fs";
|
|
454791
455121
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
@@ -454967,7 +455297,7 @@ async function executeAnimatedCaption(options) {
|
|
|
454967
455297
|
}
|
|
454968
455298
|
const groups = groupWords(transcript.words, { wordsPerGroup, maxChars });
|
|
454969
455299
|
const absOutputPath = resolve33(process.cwd(), outputPath);
|
|
454970
|
-
const outDir =
|
|
455300
|
+
const outDir = dirname20(absOutputPath);
|
|
454971
455301
|
if (!existsSync34(outDir)) {
|
|
454972
455302
|
await mkdir15(outDir, { recursive: true });
|
|
454973
455303
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.1",
|
|
4
4
|
"description": "VibeFrame MCP Server - AI-native video editing via Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"tsx": "^4.21.0",
|
|
58
58
|
"typescript": "^5.3.3",
|
|
59
59
|
"vitest": "^1.2.2",
|
|
60
|
-
"@vibeframe/cli": "0.
|
|
61
|
-
"@vibeframe/core": "0.
|
|
60
|
+
"@vibeframe/cli": "0.49.1",
|
|
61
|
+
"@vibeframe/core": "0.49.1"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=20"
|