@vibeframe/mcp-server 0.113.2 → 0.113.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/index.js +169 -12
- 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,12 @@ 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
|
|
472878
472896
|
}) : null;
|
|
472879
472897
|
const musicCache = musicPrompt && !musicReference ? musicCacheDescriptor({
|
|
472880
472898
|
beatId: beat.id,
|
|
@@ -472969,6 +472987,12 @@ async function createBuildPlan(opts) {
|
|
|
472969
472987
|
if (backdrop?.willGenerate && isSupportedBuildImageProvider(resolved.image.resolved))
|
|
472970
472988
|
noteProviderNeed(resolved.image, "Backdrop generation");
|
|
472971
472989
|
if (video?.willGenerate) noteProviderNeed(resolved.video, "Video generation");
|
|
472990
|
+
if (keyframePrompt && video?.willGenerate) {
|
|
472991
|
+
estimatedCostUsd += backdropCostUsd(imageQuality);
|
|
472992
|
+
providers.add(resolved.image.resolved);
|
|
472993
|
+
if (isSupportedBuildImageProvider(resolved.image.resolved))
|
|
472994
|
+
noteProviderNeed(resolved.image, "Keyframe generation");
|
|
472995
|
+
}
|
|
472972
472996
|
if (music?.willGenerate) noteProviderNeed(resolved.music, "Music generation");
|
|
472973
472997
|
if (!compositionExists) missing.add("compositions");
|
|
472974
472998
|
if (includeCompose && !compositionExists && mode !== "agent") {
|
|
@@ -474379,6 +474403,8 @@ async function buildBeatPrimitives(beat, ctx) {
|
|
|
474379
474403
|
videoMetadataPath: video.metadataPath,
|
|
474380
474404
|
videoFreshness: video.freshness,
|
|
474381
474405
|
videoSourcePath: video.sourcePath,
|
|
474406
|
+
keyframeStatus: video.keyframeStatus,
|
|
474407
|
+
keyframePath: video.keyframePath,
|
|
474382
474408
|
musicStatus: music.status,
|
|
474383
474409
|
musicPath: music.path,
|
|
474384
474410
|
musicJobId: music.job?.id,
|
|
@@ -474823,6 +474849,112 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
|
|
|
474823
474849
|
});
|
|
474824
474850
|
return imageBufferFromResult(result);
|
|
474825
474851
|
}
|
|
474852
|
+
async function editKeyframeImage(prompt3, sheetBuffers, ctx, ratio) {
|
|
474853
|
+
loadSceneBuildEnv(ctx.projectDir);
|
|
474854
|
+
const keyInfo = imageProviderKeyInfo(ctx.imageProvider);
|
|
474855
|
+
const apiKey = await getApiKeyFromConfig(keyInfo.configKey, { cwd: ctx.projectDir }) ?? process.env[keyInfo.envVar] ?? "";
|
|
474856
|
+
if (!apiKey) {
|
|
474857
|
+
return {
|
|
474858
|
+
success: false,
|
|
474859
|
+
error: `${keyInfo.envVar} not set \u2014 cannot generate keyframe with ${ctx.imageProvider}`
|
|
474860
|
+
};
|
|
474861
|
+
}
|
|
474862
|
+
if (ctx.imageProvider === "openai") {
|
|
474863
|
+
const provider2 = new OpenAIImageProvider();
|
|
474864
|
+
await provider2.initialize({ apiKey });
|
|
474865
|
+
const result2 = await provider2.editImage(sheetBuffers, prompt3);
|
|
474866
|
+
return imageBufferFromResult(result2);
|
|
474867
|
+
}
|
|
474868
|
+
if (ctx.imageProvider === "gemini") {
|
|
474869
|
+
const provider2 = new GeminiProvider();
|
|
474870
|
+
await provider2.initialize({ apiKey });
|
|
474871
|
+
const result2 = await provider2.editImage(sheetBuffers, prompt3, {
|
|
474872
|
+
model: "flash",
|
|
474873
|
+
aspectRatio: ratio
|
|
474874
|
+
});
|
|
474875
|
+
return imageBufferFromResult(result2);
|
|
474876
|
+
}
|
|
474877
|
+
const provider = new GrokProvider();
|
|
474878
|
+
await provider.initialize({ apiKey });
|
|
474879
|
+
const result = await provider.editImage(sheetBuffers[0], prompt3, { aspectRatio: ratio });
|
|
474880
|
+
return imageBufferFromResult(result);
|
|
474881
|
+
}
|
|
474882
|
+
async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
474883
|
+
const rel = `assets/keyframe-${beat.id}.png`;
|
|
474884
|
+
const abs = join31(ctx.projectDir, rel);
|
|
474885
|
+
const size = ctx.imageSize ?? "1536x1024";
|
|
474886
|
+
const ratio = imageRatioForSize(size);
|
|
474887
|
+
const metadataOptions = { quality: ctx.imageQuality, size, ratio };
|
|
474888
|
+
const cache = keyframeCacheDescriptor({
|
|
474889
|
+
beatId: beat.id,
|
|
474890
|
+
cue: keyframeCue,
|
|
474891
|
+
provider: ctx.imageProvider,
|
|
474892
|
+
quality: ctx.imageQuality,
|
|
474893
|
+
size,
|
|
474894
|
+
ratio,
|
|
474895
|
+
characters: characterRefsRel
|
|
474896
|
+
});
|
|
474897
|
+
if (existsSync35(abs) && !ctx.force) {
|
|
474898
|
+
const metadata = readAssetMetadata(ctx.projectDir, "keyframe", beat.id);
|
|
474899
|
+
if (!metadata || isFreshCanonicalAsset({
|
|
474900
|
+
projectDir: ctx.projectDir,
|
|
474901
|
+
kind: "keyframe",
|
|
474902
|
+
beatId: beat.id,
|
|
474903
|
+
cue: keyframeCue,
|
|
474904
|
+
provider: ctx.imageProvider,
|
|
474905
|
+
options: metadataOptions,
|
|
474906
|
+
cacheKey: cache.key
|
|
474907
|
+
})) {
|
|
474908
|
+
return { status: "cached", rel };
|
|
474909
|
+
}
|
|
474910
|
+
}
|
|
474911
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474912
|
+
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474913
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474914
|
+
await copyFile4(cacheAbs, abs);
|
|
474915
|
+
await writeAssetMetadata({
|
|
474916
|
+
projectDir: ctx.projectDir,
|
|
474917
|
+
kind: "keyframe",
|
|
474918
|
+
beatId: beat.id,
|
|
474919
|
+
cue: keyframeCue,
|
|
474920
|
+
provider: ctx.imageProvider,
|
|
474921
|
+
options: metadataOptions,
|
|
474922
|
+
cacheKey: cache.key,
|
|
474923
|
+
canonicalPath: rel,
|
|
474924
|
+
cachePath: cache.path
|
|
474925
|
+
});
|
|
474926
|
+
return { status: "cached", rel };
|
|
474927
|
+
}
|
|
474928
|
+
const sheetBuffers = [];
|
|
474929
|
+
for (const relPath of characterRefsRel) {
|
|
474930
|
+
const sheetAbs = join31(ctx.projectDir, relPath);
|
|
474931
|
+
if (existsSync35(sheetAbs)) sheetBuffers.push(await readFile18(sheetAbs));
|
|
474932
|
+
}
|
|
474933
|
+
const imgCtx = {
|
|
474934
|
+
projectDir: ctx.projectDir,
|
|
474935
|
+
imageProvider: ctx.imageProvider,
|
|
474936
|
+
imageSize: size,
|
|
474937
|
+
imageQuality: ctx.imageQuality
|
|
474938
|
+
};
|
|
474939
|
+
const generated = sheetBuffers.length > 0 ? await editKeyframeImage(keyframeCue, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
|
|
474940
|
+
if (!generated.success) return { status: "failed", error: generated.error };
|
|
474941
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474942
|
+
await writeFile20(abs, generated.buffer);
|
|
474943
|
+
await mkdir13(dirname18(cacheAbs), { recursive: true });
|
|
474944
|
+
await writeFile20(cacheAbs, generated.buffer);
|
|
474945
|
+
await writeAssetMetadata({
|
|
474946
|
+
projectDir: ctx.projectDir,
|
|
474947
|
+
kind: "keyframe",
|
|
474948
|
+
beatId: beat.id,
|
|
474949
|
+
cue: keyframeCue,
|
|
474950
|
+
provider: ctx.imageProvider,
|
|
474951
|
+
options: metadataOptions,
|
|
474952
|
+
cacheKey: cache.key,
|
|
474953
|
+
canonicalPath: rel,
|
|
474954
|
+
cachePath: cache.path
|
|
474955
|
+
});
|
|
474956
|
+
return { status: "generated", rel };
|
|
474957
|
+
}
|
|
474826
474958
|
async function imageBufferFromResult(result) {
|
|
474827
474959
|
const image = result.images?.[0];
|
|
474828
474960
|
if (!result.success || !image) {
|
|
@@ -474846,7 +474978,8 @@ function imageProviderKeyInfo(provider) {
|
|
|
474846
474978
|
async function dispatchVideo(beat, ctx) {
|
|
474847
474979
|
const reference = assetReferenceForBeat(ctx.projectDir, "video", beat);
|
|
474848
474980
|
if (reference) return referencePrimitiveOutcome("video", beat, ctx, reference);
|
|
474849
|
-
const
|
|
474981
|
+
const keyframeCue = stringOrUndefined4(beat.cues?.keyframe);
|
|
474982
|
+
const prompt3 = stringOrUndefined4(beat.cues?.video) ?? keyframeCue;
|
|
474850
474983
|
if (!prompt3) return { status: "no-cue" };
|
|
474851
474984
|
const characterRefsRel = beatCharacterNames(beat.cues).map((name) => ctx.characterPaths?.get(name)).filter((p2) => typeof p2 === "string");
|
|
474852
474985
|
const characterRefsAbs = characterRefsRel.map((p2) => join31(ctx.projectDir, p2));
|
|
@@ -474857,7 +474990,10 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474857
474990
|
cue: prompt3,
|
|
474858
474991
|
provider: ctx.videoProvider,
|
|
474859
474992
|
duration: normalizeVideoDuration(beat.duration),
|
|
474860
|
-
|
|
474993
|
+
// Keyframe mode keys the clip to the keyframe prompt; refs feed the keyframe,
|
|
474994
|
+
// not the clip directly.
|
|
474995
|
+
characters: keyframeCue ? void 0 : characterRefsRel,
|
|
474996
|
+
keyframe: keyframeCue
|
|
474861
474997
|
});
|
|
474862
474998
|
const metadataPath = assetMetadataPath("video", beat.id);
|
|
474863
474999
|
if (existsSync35(abs) && !ctx.force) {
|
|
@@ -474910,6 +475046,19 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474910
475046
|
};
|
|
474911
475047
|
}
|
|
474912
475048
|
loadSceneBuildEnv(ctx.projectDir);
|
|
475049
|
+
let keyframeStatus;
|
|
475050
|
+
let keyframeRel;
|
|
475051
|
+
let keyframeImageAbs;
|
|
475052
|
+
if (keyframeCue) {
|
|
475053
|
+
const kf = await ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel);
|
|
475054
|
+
if (kf.status === "failed") {
|
|
475055
|
+
ctx.onProgress({ type: "video-failed", beatId: beat.id, error: kf.error });
|
|
475056
|
+
return { status: "failed", error: kf.error };
|
|
475057
|
+
}
|
|
475058
|
+
keyframeStatus = kf.status;
|
|
475059
|
+
keyframeRel = kf.rel;
|
|
475060
|
+
keyframeImageAbs = join31(ctx.projectDir, kf.rel);
|
|
475061
|
+
}
|
|
474913
475062
|
const result = await executeVideoGenerate({
|
|
474914
475063
|
prompt: prompt3,
|
|
474915
475064
|
provider: ctx.videoProvider,
|
|
@@ -474917,7 +475066,10 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474917
475066
|
ratio: "16:9",
|
|
474918
475067
|
output: abs,
|
|
474919
475068
|
wait: false,
|
|
474920
|
-
|
|
475069
|
+
// Keyframe mode → single init frame (image-to-video); otherwise character
|
|
475070
|
+
// reference-to-video.
|
|
475071
|
+
image: keyframeImageAbs,
|
|
475072
|
+
refImages: keyframeImageAbs ? void 0 : characterRefsAbs.length > 0 ? characterRefsAbs : void 0,
|
|
474921
475073
|
apiKey: await apiKeyForVideoProvider(ctx.videoProvider, ctx.projectDir)
|
|
474922
475074
|
});
|
|
474923
475075
|
if (!result.success || !result.taskId) {
|
|
@@ -474952,14 +475104,16 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474952
475104
|
cachePath: cache.path,
|
|
474953
475105
|
cacheKey: cache.key,
|
|
474954
475106
|
metadataPath,
|
|
474955
|
-
freshness: "fresh"
|
|
475107
|
+
freshness: "fresh",
|
|
475108
|
+
keyframeStatus,
|
|
475109
|
+
keyframePath: keyframeRel
|
|
474956
475110
|
};
|
|
474957
475111
|
}
|
|
474958
475112
|
const job = await createAndWriteJobRecord({
|
|
474959
475113
|
jobType: "generate-video",
|
|
474960
475114
|
provider: result.provider ?? ctx.videoProvider,
|
|
474961
475115
|
providerTaskId: result.taskId,
|
|
474962
|
-
providerTaskType: "text2video",
|
|
475116
|
+
providerTaskType: keyframeImageAbs ? "image2video" : "text2video",
|
|
474963
475117
|
status: "running",
|
|
474964
475118
|
projectDir: ctx.projectDir,
|
|
474965
475119
|
workingDirectory: ctx.projectDir,
|
|
@@ -474984,7 +475138,9 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474984
475138
|
provider: job.provider,
|
|
474985
475139
|
cachePath: cache.path,
|
|
474986
475140
|
cacheKey: cache.key,
|
|
474987
|
-
metadataPath
|
|
475141
|
+
metadataPath,
|
|
475142
|
+
keyframeStatus,
|
|
475143
|
+
keyframePath: keyframeRel
|
|
474988
475144
|
};
|
|
474989
475145
|
}
|
|
474990
475146
|
async function dispatchMusic(beat, ctx) {
|
|
@@ -475286,6 +475442,7 @@ function estimateActualAssetCost(outcomes, imageQuality) {
|
|
|
475286
475442
|
for (const outcome of outcomes) {
|
|
475287
475443
|
if (outcome.narrationStatus === "generated") cost += 0.05;
|
|
475288
475444
|
if (outcome.backdropStatus === "generated") cost += backdropCostUsd(imageQuality);
|
|
475445
|
+
if (outcome.keyframeStatus === "generated") cost += backdropCostUsd(imageQuality);
|
|
475289
475446
|
if (outcome.videoStatus === "generated" || outcome.videoStatus === "pending") {
|
|
475290
475447
|
cost += outcome.videoProvider === "seedance" || outcome.videoProvider === "fal" ? estimateSeedanceVideoCostUsd({
|
|
475291
475448
|
durationSec: normalizeVideoDuration(outcome.sceneDurationSec),
|
|
@@ -499542,7 +499699,7 @@ var server2 = new Server(
|
|
|
499542
499699
|
{
|
|
499543
499700
|
name: "vibeframe",
|
|
499544
499701
|
// Stamped with the package version by build.js at bundle time.
|
|
499545
|
-
version: "0.113.
|
|
499702
|
+
version: "0.113.3"
|
|
499546
499703
|
},
|
|
499547
499704
|
{
|
|
499548
499705
|
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.3",
|
|
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.3",
|
|
64
|
+
"@vibeframe/core": "0.113.3"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">=20"
|