@vibeframe/mcp-server 0.113.2 → 0.113.4
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 +196 -14
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -471698,6 +471698,7 @@ var init_storyboard_edit = __esm({
|
|
|
471698
471698
|
"narration",
|
|
471699
471699
|
"backdrop",
|
|
471700
471700
|
"video",
|
|
471701
|
+
"keyframe",
|
|
471701
471702
|
"motion",
|
|
471702
471703
|
"voice",
|
|
471703
471704
|
"music",
|
|
@@ -471707,7 +471708,7 @@ var init_storyboard_edit = __esm({
|
|
|
471707
471708
|
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
471708
471709
|
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
471709
471710
|
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
471710
|
-
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "motion", "voice", "music", "asset"]);
|
|
471711
|
+
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "keyframe", "motion", "voice", "music", "asset"]);
|
|
471711
471712
|
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
471712
471713
|
}
|
|
471713
471714
|
});
|
|
@@ -472626,6 +472627,7 @@ var init_build_asset_reference = __esm({
|
|
|
472626
472627
|
narration: [".mp3", ".wav", ".m4a"],
|
|
472627
472628
|
backdrop: [".png", ".jpg", ".jpeg", ".webp"],
|
|
472628
472629
|
character: [".png", ".jpg", ".jpeg", ".webp"],
|
|
472630
|
+
keyframe: [".png", ".jpg", ".jpeg", ".webp"],
|
|
472629
472631
|
video: [".mp4", ".mov", ".webm"],
|
|
472630
472632
|
music: [".mp3", ".wav", ".m4a"]
|
|
472631
472633
|
};
|
|
@@ -472673,6 +472675,18 @@ function characterCacheDescriptor(opts) {
|
|
|
472673
472675
|
ext: "png"
|
|
472674
472676
|
});
|
|
472675
472677
|
}
|
|
472678
|
+
function keyframeCacheDescriptor(opts) {
|
|
472679
|
+
return cacheAssetDescriptor("keyframe", {
|
|
472680
|
+
beatId: opts.beatId,
|
|
472681
|
+
cue: opts.cue,
|
|
472682
|
+
provider: opts.provider,
|
|
472683
|
+
quality: opts.quality,
|
|
472684
|
+
size: opts.size,
|
|
472685
|
+
ratio: opts.ratio,
|
|
472686
|
+
characters: opts.characters && opts.characters.length > 0 ? opts.characters : void 0,
|
|
472687
|
+
ext: "png"
|
|
472688
|
+
});
|
|
472689
|
+
}
|
|
472676
472690
|
function imageRatioForSize(size) {
|
|
472677
472691
|
switch (size) {
|
|
472678
472692
|
case "1024x1024":
|
|
@@ -472694,6 +472708,8 @@ function videoCacheDescriptor(opts) {
|
|
|
472694
472708
|
ratio: "16:9",
|
|
472695
472709
|
// Omit when empty so existing (character-less) clips keep their cache key.
|
|
472696
472710
|
characters: opts.characters && opts.characters.length > 0 ? opts.characters : void 0,
|
|
472711
|
+
// Omit when absent so existing (non-keyframe) clips keep their cache key.
|
|
472712
|
+
keyframe: opts.keyframe || void 0,
|
|
472697
472713
|
ext: "mp4"
|
|
472698
472714
|
});
|
|
472699
472715
|
}
|
|
@@ -472844,6 +472860,7 @@ async function createBuildPlan(opts) {
|
|
|
472844
472860
|
const backdropPrompt = stringOrUndefined3(cue.backdrop);
|
|
472845
472861
|
const augmentedBackdropPrompt = backdropPrompt ? augmentBackdropPrompt(backdropPrompt) : null;
|
|
472846
472862
|
const videoPrompt = stringOrUndefined3(cue.video);
|
|
472863
|
+
const keyframePrompt = stringOrUndefined3(cue.keyframe);
|
|
472847
472864
|
const musicPrompt = stringOrUndefined3(cue.music);
|
|
472848
472865
|
const genericReference = resolveGenericAssetReference(projectDir, cue.asset);
|
|
472849
472866
|
const narrationReference = resolveTypedAssetReference(projectDir, "narration", cue.narration);
|
|
@@ -472852,7 +472869,7 @@ async function createBuildPlan(opts) {
|
|
|
472852
472869
|
const musicReference = resolveTypedAssetReference(projectDir, "music", cue.music) ?? (!musicPrompt && genericReference?.kind === "music" ? genericReference : null);
|
|
472853
472870
|
const narrationCue = narrationText ?? narrationReference?.raw;
|
|
472854
472871
|
const backdropCue = backdropPrompt ?? backdropReference?.raw;
|
|
472855
|
-
const videoCue = videoPrompt ?? videoReference?.raw;
|
|
472872
|
+
const videoCue = videoPrompt ?? videoReference?.raw ?? keyframePrompt;
|
|
472856
472873
|
const musicCue = musicPrompt ?? musicReference?.raw;
|
|
472857
472874
|
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : resolved.narration.resolved === "openai" ? OPENAI_NARRATION_COST_USD : 0;
|
|
472858
472875
|
const narrationCache = narrationText && !narrationReference ? narrationCacheDescriptor({
|
|
@@ -472870,11 +472887,20 @@ async function createBuildPlan(opts) {
|
|
|
472870
472887
|
size: imageSize2,
|
|
472871
472888
|
ratio: imageRatio
|
|
472872
472889
|
}) : null;
|
|
472873
|
-
const videoCache = videoPrompt && !videoReference ? videoCacheDescriptor({
|
|
472890
|
+
const videoCache = (videoPrompt || keyframePrompt) && !videoReference ? videoCacheDescriptor({
|
|
472874
472891
|
beatId: beat.id,
|
|
472875
|
-
cue: videoPrompt,
|
|
472892
|
+
cue: videoPrompt ?? keyframePrompt,
|
|
472876
472893
|
provider: resolved.video.resolved,
|
|
472877
|
-
duration: beat.duration
|
|
472894
|
+
duration: beat.duration,
|
|
472895
|
+
keyframe: keyframePrompt
|
|
472896
|
+
}) : null;
|
|
472897
|
+
const keyframeCache2 = keyframePrompt ? keyframeCacheDescriptor({
|
|
472898
|
+
beatId: beat.id,
|
|
472899
|
+
cue: keyframePrompt,
|
|
472900
|
+
provider: resolved.image.resolved,
|
|
472901
|
+
quality: imageQuality,
|
|
472902
|
+
size: imageSize2,
|
|
472903
|
+
ratio: imageRatio
|
|
472878
472904
|
}) : null;
|
|
472879
472905
|
const musicCache = musicPrompt && !musicReference ? musicCacheDescriptor({
|
|
472880
472906
|
beatId: beat.id,
|
|
@@ -472911,6 +472937,19 @@ async function createBuildPlan(opts) {
|
|
|
472911
472937
|
cost: backdropCostUsd(imageQuality),
|
|
472912
472938
|
active: includeAssets
|
|
472913
472939
|
}) : null;
|
|
472940
|
+
const keyframe = keyframePrompt && !opts.skipKeyframe ? assetPlan({
|
|
472941
|
+
kind: "keyframe",
|
|
472942
|
+
beatId: beat.id,
|
|
472943
|
+
cue: keyframePrompt,
|
|
472944
|
+
provider: resolved.image.resolved,
|
|
472945
|
+
path: `assets/keyframe-${beat.id}.png`,
|
|
472946
|
+
cache: keyframeCache2,
|
|
472947
|
+
reference: null,
|
|
472948
|
+
projectDir,
|
|
472949
|
+
force: opts.force,
|
|
472950
|
+
cost: backdropCostUsd(imageQuality),
|
|
472951
|
+
active: includeAssets
|
|
472952
|
+
}) : null;
|
|
472914
472953
|
const video = videoCue && !opts.skipVideo ? assetPlan({
|
|
472915
472954
|
kind: "video",
|
|
472916
472955
|
beatId: beat.id,
|
|
@@ -472943,7 +472982,7 @@ async function createBuildPlan(opts) {
|
|
|
472943
472982
|
}) : null;
|
|
472944
472983
|
const compositionPath = `compositions/scene-${beat.id}.html`;
|
|
472945
472984
|
const compositionExists = existsSync33(join30(projectDir, compositionPath));
|
|
472946
|
-
for (const asset of [narration, backdrop, video, music]) {
|
|
472985
|
+
for (const asset of [narration, backdrop, keyframe, video, music]) {
|
|
472947
472986
|
if (!asset) continue;
|
|
472948
472987
|
if (asset.referenceError) {
|
|
472949
472988
|
missing.add("assets");
|
|
@@ -472968,6 +473007,8 @@ async function createBuildPlan(opts) {
|
|
|
472968
473007
|
if (narration?.willGenerate) noteProviderNeed(resolved.narration, "Narration");
|
|
472969
473008
|
if (backdrop?.willGenerate && isSupportedBuildImageProvider(resolved.image.resolved))
|
|
472970
473009
|
noteProviderNeed(resolved.image, "Backdrop generation");
|
|
473010
|
+
if (keyframe?.willGenerate && isSupportedBuildImageProvider(resolved.image.resolved))
|
|
473011
|
+
noteProviderNeed(resolved.image, "Keyframe generation");
|
|
472971
473012
|
if (video?.willGenerate) noteProviderNeed(resolved.video, "Video generation");
|
|
472972
473013
|
if (music?.willGenerate) noteProviderNeed(resolved.music, "Music generation");
|
|
472973
473014
|
if (!compositionExists) missing.add("compositions");
|
|
@@ -472981,7 +473022,7 @@ async function createBuildPlan(opts) {
|
|
|
472981
473022
|
heading: beat.heading,
|
|
472982
473023
|
durationSec: beat.duration ?? null,
|
|
472983
473024
|
cues: cue,
|
|
472984
|
-
assets: { narration, backdrop, video, music },
|
|
473025
|
+
assets: { narration, backdrop, keyframe, video, music },
|
|
472985
473026
|
composition: {
|
|
472986
473027
|
path: compositionPath,
|
|
472987
473028
|
exists: compositionExists
|
|
@@ -473197,6 +473238,7 @@ function providerResolutionsForPlan(resolved, beats, opts, includeAssets) {
|
|
|
473197
473238
|
return [
|
|
473198
473239
|
includeAssets && !opts.skipNarration && needsProvider("narration") ? resolved.narration : null,
|
|
473199
473240
|
includeAssets && !opts.skipBackdrop && needsProvider("backdrop") ? resolved.image : null,
|
|
473241
|
+
includeAssets && !opts.skipKeyframe && needsProvider("keyframe") ? resolved.image : null,
|
|
473200
473242
|
includeAssets && !opts.skipVideo && needsProvider("video") ? resolved.video : null,
|
|
473201
473243
|
includeAssets && !opts.skipMusic && needsProvider("music") ? resolved.music : null,
|
|
473202
473244
|
resolved.composer ?? null
|
|
@@ -473771,6 +473813,7 @@ async function executeSceneBuild(opts) {
|
|
|
473771
473813
|
skipNarration: opts.skipNarration,
|
|
473772
473814
|
skipBackdrop: opts.skipBackdrop,
|
|
473773
473815
|
skipVideo: opts.skipVideo,
|
|
473816
|
+
skipKeyframe: opts.skipKeyframe,
|
|
473774
473817
|
skipMusic: opts.skipMusic,
|
|
473775
473818
|
ttsProvider: opts.ttsProvider,
|
|
473776
473819
|
voice: opts.voice,
|
|
@@ -473956,6 +473999,7 @@ async function executeSceneBuild(opts) {
|
|
|
473956
473999
|
skipNarration: opts.skipNarration ?? false,
|
|
473957
474000
|
skipBackdrop: opts.skipBackdrop ?? false,
|
|
473958
474001
|
skipVideo: opts.skipVideo ?? false,
|
|
474002
|
+
skipKeyframe: opts.skipKeyframe ?? false,
|
|
473959
474003
|
skipMusic: opts.skipMusic ?? false,
|
|
473960
474004
|
force: opts.force ?? false,
|
|
473961
474005
|
onProgress,
|
|
@@ -474332,10 +474376,11 @@ async function executeSceneBuild(opts) {
|
|
|
474332
474376
|
});
|
|
474333
474377
|
}
|
|
474334
474378
|
async function buildBeatPrimitives(beat, ctx) {
|
|
474379
|
+
const keyframe = ctx.skipKeyframe ? await skipped("keyframe", beat.id, "--skip-keyframe", ctx) : await dispatchKeyframe(beat, ctx);
|
|
474335
474380
|
const [narration, backdrop, video, music] = await Promise.all([
|
|
474336
474381
|
ctx.skipNarration ? skipped("narration", beat.id, "--skip-narration", ctx) : dispatchNarration(beat, ctx),
|
|
474337
474382
|
ctx.skipBackdrop ? skipped("backdrop", beat.id, "--skip-backdrop", ctx) : dispatchBackdrop(beat, ctx),
|
|
474338
|
-
ctx.skipVideo ? skipped("video", beat.id, "--skip-video", ctx) : dispatchVideo(beat, ctx),
|
|
474383
|
+
ctx.skipVideo ? skipped("video", beat.id, "--skip-video", ctx) : dispatchVideo(beat, ctx, keyframe),
|
|
474339
474384
|
ctx.skipMusic ? skipped("music", beat.id, "--skip-music", ctx) : dispatchMusic(beat, ctx)
|
|
474340
474385
|
]);
|
|
474341
474386
|
return {
|
|
@@ -474379,6 +474424,8 @@ async function buildBeatPrimitives(beat, ctx) {
|
|
|
474379
474424
|
videoMetadataPath: video.metadataPath,
|
|
474380
474425
|
videoFreshness: video.freshness,
|
|
474381
474426
|
videoSourcePath: video.sourcePath,
|
|
474427
|
+
keyframeStatus: keyframe.status,
|
|
474428
|
+
keyframePath: keyframe.path,
|
|
474382
474429
|
musicStatus: music.status,
|
|
474383
474430
|
musicPath: music.path,
|
|
474384
474431
|
musicJobId: music.job?.id,
|
|
@@ -474823,6 +474870,112 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
|
|
|
474823
474870
|
});
|
|
474824
474871
|
return imageBufferFromResult(result);
|
|
474825
474872
|
}
|
|
474873
|
+
async function editKeyframeImage(prompt3, sheetBuffers, ctx, ratio) {
|
|
474874
|
+
loadSceneBuildEnv(ctx.projectDir);
|
|
474875
|
+
const keyInfo = imageProviderKeyInfo(ctx.imageProvider);
|
|
474876
|
+
const apiKey = await getApiKeyFromConfig(keyInfo.configKey, { cwd: ctx.projectDir }) ?? process.env[keyInfo.envVar] ?? "";
|
|
474877
|
+
if (!apiKey) {
|
|
474878
|
+
return {
|
|
474879
|
+
success: false,
|
|
474880
|
+
error: `${keyInfo.envVar} not set \u2014 cannot generate keyframe with ${ctx.imageProvider}`
|
|
474881
|
+
};
|
|
474882
|
+
}
|
|
474883
|
+
if (ctx.imageProvider === "openai") {
|
|
474884
|
+
const provider2 = new OpenAIImageProvider();
|
|
474885
|
+
await provider2.initialize({ apiKey });
|
|
474886
|
+
const result2 = await provider2.editImage(sheetBuffers, prompt3);
|
|
474887
|
+
return imageBufferFromResult(result2);
|
|
474888
|
+
}
|
|
474889
|
+
if (ctx.imageProvider === "gemini") {
|
|
474890
|
+
const provider2 = new GeminiProvider();
|
|
474891
|
+
await provider2.initialize({ apiKey });
|
|
474892
|
+
const result2 = await provider2.editImage(sheetBuffers, prompt3, {
|
|
474893
|
+
model: "flash",
|
|
474894
|
+
aspectRatio: ratio
|
|
474895
|
+
});
|
|
474896
|
+
return imageBufferFromResult(result2);
|
|
474897
|
+
}
|
|
474898
|
+
const provider = new GrokProvider();
|
|
474899
|
+
await provider.initialize({ apiKey });
|
|
474900
|
+
const result = await provider.editImage(sheetBuffers[0], prompt3, { aspectRatio: ratio });
|
|
474901
|
+
return imageBufferFromResult(result);
|
|
474902
|
+
}
|
|
474903
|
+
async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
474904
|
+
const rel = `assets/keyframe-${beat.id}.png`;
|
|
474905
|
+
const abs = join31(ctx.projectDir, rel);
|
|
474906
|
+
const size = ctx.imageSize ?? "1536x1024";
|
|
474907
|
+
const ratio = imageRatioForSize(size);
|
|
474908
|
+
const metadataOptions = { quality: ctx.imageQuality, size, ratio };
|
|
474909
|
+
const cache = keyframeCacheDescriptor({
|
|
474910
|
+
beatId: beat.id,
|
|
474911
|
+
cue: keyframeCue,
|
|
474912
|
+
provider: ctx.imageProvider,
|
|
474913
|
+
quality: ctx.imageQuality,
|
|
474914
|
+
size,
|
|
474915
|
+
ratio,
|
|
474916
|
+
characters: characterRefsRel
|
|
474917
|
+
});
|
|
474918
|
+
if (existsSync35(abs) && !ctx.force) {
|
|
474919
|
+
const metadata = readAssetMetadata(ctx.projectDir, "keyframe", beat.id);
|
|
474920
|
+
if (!metadata || isFreshCanonicalAsset({
|
|
474921
|
+
projectDir: ctx.projectDir,
|
|
474922
|
+
kind: "keyframe",
|
|
474923
|
+
beatId: beat.id,
|
|
474924
|
+
cue: keyframeCue,
|
|
474925
|
+
provider: ctx.imageProvider,
|
|
474926
|
+
options: metadataOptions,
|
|
474927
|
+
cacheKey: cache.key
|
|
474928
|
+
})) {
|
|
474929
|
+
return { status: "cached", rel };
|
|
474930
|
+
}
|
|
474931
|
+
}
|
|
474932
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474933
|
+
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474934
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474935
|
+
await copyFile4(cacheAbs, abs);
|
|
474936
|
+
await writeAssetMetadata({
|
|
474937
|
+
projectDir: ctx.projectDir,
|
|
474938
|
+
kind: "keyframe",
|
|
474939
|
+
beatId: beat.id,
|
|
474940
|
+
cue: keyframeCue,
|
|
474941
|
+
provider: ctx.imageProvider,
|
|
474942
|
+
options: metadataOptions,
|
|
474943
|
+
cacheKey: cache.key,
|
|
474944
|
+
canonicalPath: rel,
|
|
474945
|
+
cachePath: cache.path
|
|
474946
|
+
});
|
|
474947
|
+
return { status: "cached", rel };
|
|
474948
|
+
}
|
|
474949
|
+
const sheetBuffers = [];
|
|
474950
|
+
for (const relPath of characterRefsRel) {
|
|
474951
|
+
const sheetAbs = join31(ctx.projectDir, relPath);
|
|
474952
|
+
if (existsSync35(sheetAbs)) sheetBuffers.push(await readFile18(sheetAbs));
|
|
474953
|
+
}
|
|
474954
|
+
const imgCtx = {
|
|
474955
|
+
projectDir: ctx.projectDir,
|
|
474956
|
+
imageProvider: ctx.imageProvider,
|
|
474957
|
+
imageSize: size,
|
|
474958
|
+
imageQuality: ctx.imageQuality
|
|
474959
|
+
};
|
|
474960
|
+
const generated = sheetBuffers.length > 0 ? await editKeyframeImage(keyframeCue, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
|
|
474961
|
+
if (!generated.success) return { status: "failed", error: generated.error };
|
|
474962
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474963
|
+
await writeFile20(abs, generated.buffer);
|
|
474964
|
+
await mkdir13(dirname18(cacheAbs), { recursive: true });
|
|
474965
|
+
await writeFile20(cacheAbs, generated.buffer);
|
|
474966
|
+
await writeAssetMetadata({
|
|
474967
|
+
projectDir: ctx.projectDir,
|
|
474968
|
+
kind: "keyframe",
|
|
474969
|
+
beatId: beat.id,
|
|
474970
|
+
cue: keyframeCue,
|
|
474971
|
+
provider: ctx.imageProvider,
|
|
474972
|
+
options: metadataOptions,
|
|
474973
|
+
cacheKey: cache.key,
|
|
474974
|
+
canonicalPath: rel,
|
|
474975
|
+
cachePath: cache.path
|
|
474976
|
+
});
|
|
474977
|
+
return { status: "generated", rel };
|
|
474978
|
+
}
|
|
474826
474979
|
async function imageBufferFromResult(result) {
|
|
474827
474980
|
const image = result.images?.[0];
|
|
474828
474981
|
if (!result.success || !image) {
|
|
@@ -474843,10 +474996,25 @@ function imageProviderKeyInfo(provider) {
|
|
|
474843
474996
|
if (provider === "grok") return { configKey: "xai", envVar: "XAI_API_KEY" };
|
|
474844
474997
|
return { configKey: "openai", envVar: "OPENAI_API_KEY" };
|
|
474845
474998
|
}
|
|
474846
|
-
async function
|
|
474999
|
+
async function dispatchKeyframe(beat, ctx) {
|
|
475000
|
+
const keyframeCue = stringOrUndefined4(beat.cues?.keyframe);
|
|
475001
|
+
if (!keyframeCue) return { status: "no-cue" };
|
|
475002
|
+
const characterRefsRel = beatCharacterNames(beat.cues).map((name) => ctx.characterPaths?.get(name)).filter((p2) => typeof p2 === "string");
|
|
475003
|
+
const kf = await ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel);
|
|
475004
|
+
if (kf.status === "failed") {
|
|
475005
|
+
ctx.onProgress({ type: "keyframe-failed", beatId: beat.id, error: kf.error });
|
|
475006
|
+
return { status: "failed", error: kf.error };
|
|
475007
|
+
}
|
|
475008
|
+
ctx.onProgress(
|
|
475009
|
+
kf.status === "cached" ? { type: "keyframe-cached", beatId: beat.id, path: kf.rel } : { type: "keyframe-generated", beatId: beat.id, path: kf.rel, provider: ctx.imageProvider }
|
|
475010
|
+
);
|
|
475011
|
+
return { status: kf.status, path: kf.rel, provider: ctx.imageProvider };
|
|
475012
|
+
}
|
|
475013
|
+
async function dispatchVideo(beat, ctx, keyframe) {
|
|
474847
475014
|
const reference = assetReferenceForBeat(ctx.projectDir, "video", beat);
|
|
474848
475015
|
if (reference) return referencePrimitiveOutcome("video", beat, ctx, reference);
|
|
474849
|
-
const
|
|
475016
|
+
const keyframeCue = stringOrUndefined4(beat.cues?.keyframe);
|
|
475017
|
+
const prompt3 = stringOrUndefined4(beat.cues?.video) ?? keyframeCue;
|
|
474850
475018
|
if (!prompt3) return { status: "no-cue" };
|
|
474851
475019
|
const characterRefsRel = beatCharacterNames(beat.cues).map((name) => ctx.characterPaths?.get(name)).filter((p2) => typeof p2 === "string");
|
|
474852
475020
|
const characterRefsAbs = characterRefsRel.map((p2) => join31(ctx.projectDir, p2));
|
|
@@ -474857,7 +475025,10 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474857
475025
|
cue: prompt3,
|
|
474858
475026
|
provider: ctx.videoProvider,
|
|
474859
475027
|
duration: normalizeVideoDuration(beat.duration),
|
|
474860
|
-
|
|
475028
|
+
// Keyframe mode keys the clip to the keyframe prompt; refs feed the keyframe,
|
|
475029
|
+
// not the clip directly.
|
|
475030
|
+
characters: keyframeCue ? void 0 : characterRefsRel,
|
|
475031
|
+
keyframe: keyframeCue
|
|
474861
475032
|
});
|
|
474862
475033
|
const metadataPath = assetMetadataPath("video", beat.id);
|
|
474863
475034
|
if (existsSync35(abs) && !ctx.force) {
|
|
@@ -474909,6 +475080,13 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474909
475080
|
freshness: "fresh"
|
|
474910
475081
|
};
|
|
474911
475082
|
}
|
|
475083
|
+
const keyframeImageRel = keyframeCue && (keyframe.status === "generated" || keyframe.status === "cached") ? keyframe.path : void 0;
|
|
475084
|
+
if (keyframeCue && !keyframeImageRel) {
|
|
475085
|
+
const reason = keyframe.status === "failed" ? `keyframe unavailable: ${keyframe.error ?? "generation failed"}` : "keyframe not generated (build without --skip-keyframe first)";
|
|
475086
|
+
ctx.onProgress({ type: "video-skipped", beatId: beat.id, reason });
|
|
475087
|
+
return { status: "skipped" };
|
|
475088
|
+
}
|
|
475089
|
+
const keyframeImageAbs = keyframeImageRel ? join31(ctx.projectDir, keyframeImageRel) : void 0;
|
|
474912
475090
|
loadSceneBuildEnv(ctx.projectDir);
|
|
474913
475091
|
const result = await executeVideoGenerate({
|
|
474914
475092
|
prompt: prompt3,
|
|
@@ -474917,7 +475095,10 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474917
475095
|
ratio: "16:9",
|
|
474918
475096
|
output: abs,
|
|
474919
475097
|
wait: false,
|
|
474920
|
-
|
|
475098
|
+
// Keyframe mode → single init frame (image-to-video); otherwise character
|
|
475099
|
+
// reference-to-video.
|
|
475100
|
+
image: keyframeImageAbs,
|
|
475101
|
+
refImages: keyframeImageAbs ? void 0 : characterRefsAbs.length > 0 ? characterRefsAbs : void 0,
|
|
474921
475102
|
apiKey: await apiKeyForVideoProvider(ctx.videoProvider, ctx.projectDir)
|
|
474922
475103
|
});
|
|
474923
475104
|
if (!result.success || !result.taskId) {
|
|
@@ -474959,7 +475140,7 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474959
475140
|
jobType: "generate-video",
|
|
474960
475141
|
provider: result.provider ?? ctx.videoProvider,
|
|
474961
475142
|
providerTaskId: result.taskId,
|
|
474962
|
-
providerTaskType: "text2video",
|
|
475143
|
+
providerTaskType: keyframeImageAbs ? "image2video" : "text2video",
|
|
474963
475144
|
status: "running",
|
|
474964
475145
|
projectDir: ctx.projectDir,
|
|
474965
475146
|
workingDirectory: ctx.projectDir,
|
|
@@ -475286,6 +475467,7 @@ function estimateActualAssetCost(outcomes, imageQuality) {
|
|
|
475286
475467
|
for (const outcome of outcomes) {
|
|
475287
475468
|
if (outcome.narrationStatus === "generated") cost += 0.05;
|
|
475288
475469
|
if (outcome.backdropStatus === "generated") cost += backdropCostUsd(imageQuality);
|
|
475470
|
+
if (outcome.keyframeStatus === "generated") cost += backdropCostUsd(imageQuality);
|
|
475289
475471
|
if (outcome.videoStatus === "generated" || outcome.videoStatus === "pending") {
|
|
475290
475472
|
cost += outcome.videoProvider === "seedance" || outcome.videoProvider === "fal" ? estimateSeedanceVideoCostUsd({
|
|
475291
475473
|
durationSec: normalizeVideoDuration(outcome.sceneDurationSec),
|
|
@@ -499542,7 +499724,7 @@ var server2 = new Server(
|
|
|
499542
499724
|
{
|
|
499543
499725
|
name: "vibeframe",
|
|
499544
499726
|
// Stamped with the package version by build.js at bundle time.
|
|
499545
|
-
version: "0.113.
|
|
499727
|
+
version: "0.113.4"
|
|
499546
499728
|
},
|
|
499547
499729
|
{
|
|
499548
499730
|
capabilities: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/mcp-server",
|
|
3
|
-
"version": "0.113.
|
|
3
|
+
"version": "0.113.4",
|
|
4
4
|
"description": "VibeFrame MCP Server - AI-native video editing via Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tsx": "^4.21.0",
|
|
61
61
|
"typescript": "^5.3.3",
|
|
62
62
|
"vitest": "^1.2.2",
|
|
63
|
-
"@vibeframe/cli": "0.113.
|
|
64
|
-
"@vibeframe/core": "0.113.
|
|
63
|
+
"@vibeframe/cli": "0.113.4",
|
|
64
|
+
"@vibeframe/core": "0.113.4"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">=20"
|