@vibeframe/mcp-server 0.113.3 → 0.113.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +66 -34
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -472894,6 +472894,14 @@ async function createBuildPlan(opts) {
472894
472894
  duration: beat.duration,
472895
472895
  keyframe: keyframePrompt
472896
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
472904
+ }) : null;
472897
472905
  const musicCache = musicPrompt && !musicReference ? musicCacheDescriptor({
472898
472906
  beatId: beat.id,
472899
472907
  cue: musicPrompt,
@@ -472929,6 +472937,19 @@ async function createBuildPlan(opts) {
472929
472937
  cost: backdropCostUsd(imageQuality),
472930
472938
  active: includeAssets
472931
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;
472932
472953
  const video = videoCue && !opts.skipVideo ? assetPlan({
472933
472954
  kind: "video",
472934
472955
  beatId: beat.id,
@@ -472961,7 +472982,7 @@ async function createBuildPlan(opts) {
472961
472982
  }) : null;
472962
472983
  const compositionPath = `compositions/scene-${beat.id}.html`;
472963
472984
  const compositionExists = existsSync33(join30(projectDir, compositionPath));
472964
- for (const asset of [narration, backdrop, video, music]) {
472985
+ for (const asset of [narration, backdrop, keyframe, video, music]) {
472965
472986
  if (!asset) continue;
472966
472987
  if (asset.referenceError) {
472967
472988
  missing.add("assets");
@@ -472986,13 +473007,9 @@ async function createBuildPlan(opts) {
472986
473007
  if (narration?.willGenerate) noteProviderNeed(resolved.narration, "Narration");
472987
473008
  if (backdrop?.willGenerate && isSupportedBuildImageProvider(resolved.image.resolved))
472988
473009
  noteProviderNeed(resolved.image, "Backdrop generation");
473010
+ if (keyframe?.willGenerate && isSupportedBuildImageProvider(resolved.image.resolved))
473011
+ noteProviderNeed(resolved.image, "Keyframe generation");
472989
473012
  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
- }
472996
473013
  if (music?.willGenerate) noteProviderNeed(resolved.music, "Music generation");
472997
473014
  if (!compositionExists) missing.add("compositions");
472998
473015
  if (includeCompose && !compositionExists && mode !== "agent") {
@@ -473005,7 +473022,7 @@ async function createBuildPlan(opts) {
473005
473022
  heading: beat.heading,
473006
473023
  durationSec: beat.duration ?? null,
473007
473024
  cues: cue,
473008
- assets: { narration, backdrop, video, music },
473025
+ assets: { narration, backdrop, keyframe, video, music },
473009
473026
  composition: {
473010
473027
  path: compositionPath,
473011
473028
  exists: compositionExists
@@ -473221,6 +473238,7 @@ function providerResolutionsForPlan(resolved, beats, opts, includeAssets) {
473221
473238
  return [
473222
473239
  includeAssets && !opts.skipNarration && needsProvider("narration") ? resolved.narration : null,
473223
473240
  includeAssets && !opts.skipBackdrop && needsProvider("backdrop") ? resolved.image : null,
473241
+ includeAssets && !opts.skipKeyframe && needsProvider("keyframe") ? resolved.image : null,
473224
473242
  includeAssets && !opts.skipVideo && needsProvider("video") ? resolved.video : null,
473225
473243
  includeAssets && !opts.skipMusic && needsProvider("music") ? resolved.music : null,
473226
473244
  resolved.composer ?? null
@@ -473781,10 +473799,17 @@ async function executeSceneBuild(opts) {
473781
473799
  const onProgress = opts.onProgress ?? (() => {
473782
473800
  });
473783
473801
  const mode = resolveSceneBuildMode(opts);
473784
- const selectedStage = opts.stage ?? (opts.skipRender ? "sync" : "all");
473802
+ let selectedStage = opts.stage ?? (opts.skipRender ? "sync" : "all");
473803
+ const skipVideoStopsRender = (opts.skipVideo ?? false) && (selectedStage === "all" || selectedStage === "render");
473804
+ if (skipVideoStopsRender) selectedStage = "sync";
473785
473805
  const stageReports = createEmptyStageReports();
473786
473806
  const warnings = [];
473787
473807
  const retryWith = [];
473808
+ if (skipVideoStopsRender) {
473809
+ warnings.push(
473810
+ "--skip-video: skipped render (no clips to capture). Review assets/keyframe-*.png, then build without --skip-video to animate them."
473811
+ );
473812
+ }
473788
473813
  let sceneRepair = skippedSceneRepairSummary();
473789
473814
  const storyboardPath = join31(projectDir, "STORYBOARD.md");
473790
473815
  const buildPlan = await createBuildPlan({
@@ -473795,6 +473820,7 @@ async function executeSceneBuild(opts) {
473795
473820
  skipNarration: opts.skipNarration,
473796
473821
  skipBackdrop: opts.skipBackdrop,
473797
473822
  skipVideo: opts.skipVideo,
473823
+ skipKeyframe: opts.skipKeyframe,
473798
473824
  skipMusic: opts.skipMusic,
473799
473825
  ttsProvider: opts.ttsProvider,
473800
473826
  voice: opts.voice,
@@ -473943,7 +473969,7 @@ async function executeSceneBuild(opts) {
473943
473969
  if (shouldRunStage(selectedStage, "assets")) {
473944
473970
  onProgress({ type: "phase-start", phase: "primitives" });
473945
473971
  const characterPaths = /* @__PURE__ */ new Map();
473946
- if (!(opts.skipVideo ?? false)) {
473972
+ if (!((opts.skipVideo ?? false) && (opts.skipKeyframe ?? false))) {
473947
473973
  const referenced = /* @__PURE__ */ new Set();
473948
473974
  for (const beat of activeBeats) {
473949
473975
  for (const name of beatCharacterNames(beat.cues)) referenced.add(name);
@@ -473980,6 +474006,7 @@ async function executeSceneBuild(opts) {
473980
474006
  skipNarration: opts.skipNarration ?? false,
473981
474007
  skipBackdrop: opts.skipBackdrop ?? false,
473982
474008
  skipVideo: opts.skipVideo ?? false,
474009
+ skipKeyframe: opts.skipKeyframe ?? false,
473983
474010
  skipMusic: opts.skipMusic ?? false,
473984
474011
  force: opts.force ?? false,
473985
474012
  onProgress,
@@ -474356,10 +474383,11 @@ async function executeSceneBuild(opts) {
474356
474383
  });
474357
474384
  }
474358
474385
  async function buildBeatPrimitives(beat, ctx) {
474386
+ const keyframe = ctx.skipKeyframe ? await skipped("keyframe", beat.id, "--skip-keyframe", ctx) : await dispatchKeyframe(beat, ctx);
474359
474387
  const [narration, backdrop, video, music] = await Promise.all([
474360
474388
  ctx.skipNarration ? skipped("narration", beat.id, "--skip-narration", ctx) : dispatchNarration(beat, ctx),
474361
474389
  ctx.skipBackdrop ? skipped("backdrop", beat.id, "--skip-backdrop", ctx) : dispatchBackdrop(beat, ctx),
474362
- ctx.skipVideo ? skipped("video", beat.id, "--skip-video", ctx) : dispatchVideo(beat, ctx),
474390
+ ctx.skipVideo ? skipped("video", beat.id, "--skip-video", ctx) : dispatchVideo(beat, ctx, keyframe),
474363
474391
  ctx.skipMusic ? skipped("music", beat.id, "--skip-music", ctx) : dispatchMusic(beat, ctx)
474364
474392
  ]);
474365
474393
  return {
@@ -474403,8 +474431,8 @@ async function buildBeatPrimitives(beat, ctx) {
474403
474431
  videoMetadataPath: video.metadataPath,
474404
474432
  videoFreshness: video.freshness,
474405
474433
  videoSourcePath: video.sourcePath,
474406
- keyframeStatus: video.keyframeStatus,
474407
- keyframePath: video.keyframePath,
474434
+ keyframeStatus: keyframe.status,
474435
+ keyframePath: keyframe.path,
474408
474436
  musicStatus: music.status,
474409
474437
  musicPath: music.path,
474410
474438
  musicJobId: music.job?.id,
@@ -474975,7 +475003,21 @@ function imageProviderKeyInfo(provider) {
474975
475003
  if (provider === "grok") return { configKey: "xai", envVar: "XAI_API_KEY" };
474976
475004
  return { configKey: "openai", envVar: "OPENAI_API_KEY" };
474977
475005
  }
474978
- async function dispatchVideo(beat, ctx) {
475006
+ async function dispatchKeyframe(beat, ctx) {
475007
+ const keyframeCue = stringOrUndefined4(beat.cues?.keyframe);
475008
+ if (!keyframeCue) return { status: "no-cue" };
475009
+ const characterRefsRel = beatCharacterNames(beat.cues).map((name) => ctx.characterPaths?.get(name)).filter((p2) => typeof p2 === "string");
475010
+ const kf = await ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel);
475011
+ if (kf.status === "failed") {
475012
+ ctx.onProgress({ type: "keyframe-failed", beatId: beat.id, error: kf.error });
475013
+ return { status: "failed", error: kf.error };
475014
+ }
475015
+ ctx.onProgress(
475016
+ kf.status === "cached" ? { type: "keyframe-cached", beatId: beat.id, path: kf.rel } : { type: "keyframe-generated", beatId: beat.id, path: kf.rel, provider: ctx.imageProvider }
475017
+ );
475018
+ return { status: kf.status, path: kf.rel, provider: ctx.imageProvider };
475019
+ }
475020
+ async function dispatchVideo(beat, ctx, keyframe) {
474979
475021
  const reference = assetReferenceForBeat(ctx.projectDir, "video", beat);
474980
475022
  if (reference) return referencePrimitiveOutcome("video", beat, ctx, reference);
474981
475023
  const keyframeCue = stringOrUndefined4(beat.cues?.keyframe);
@@ -475045,20 +475087,14 @@ async function dispatchVideo(beat, ctx) {
475045
475087
  freshness: "fresh"
475046
475088
  };
475047
475089
  }
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);
475090
+ const keyframeImageRel = keyframeCue && (keyframe.status === "generated" || keyframe.status === "cached") ? keyframe.path : void 0;
475091
+ if (keyframeCue && !keyframeImageRel) {
475092
+ const reason = keyframe.status === "failed" ? `keyframe unavailable: ${keyframe.error ?? "generation failed"}` : "keyframe not generated (build without --skip-keyframe first)";
475093
+ ctx.onProgress({ type: "video-skipped", beatId: beat.id, reason });
475094
+ return { status: "skipped" };
475061
475095
  }
475096
+ const keyframeImageAbs = keyframeImageRel ? join31(ctx.projectDir, keyframeImageRel) : void 0;
475097
+ loadSceneBuildEnv(ctx.projectDir);
475062
475098
  const result = await executeVideoGenerate({
475063
475099
  prompt: prompt3,
475064
475100
  provider: ctx.videoProvider,
@@ -475104,9 +475140,7 @@ async function dispatchVideo(beat, ctx) {
475104
475140
  cachePath: cache.path,
475105
475141
  cacheKey: cache.key,
475106
475142
  metadataPath,
475107
- freshness: "fresh",
475108
- keyframeStatus,
475109
- keyframePath: keyframeRel
475143
+ freshness: "fresh"
475110
475144
  };
475111
475145
  }
475112
475146
  const job = await createAndWriteJobRecord({
@@ -475138,9 +475172,7 @@ async function dispatchVideo(beat, ctx) {
475138
475172
  provider: job.provider,
475139
475173
  cachePath: cache.path,
475140
475174
  cacheKey: cache.key,
475141
- metadataPath,
475142
- keyframeStatus,
475143
- keyframePath: keyframeRel
475175
+ metadataPath
475144
475176
  };
475145
475177
  }
475146
475178
  async function dispatchMusic(beat, ctx) {
@@ -499699,7 +499731,7 @@ var server2 = new Server(
499699
499731
  {
499700
499732
  name: "vibeframe",
499701
499733
  // Stamped with the package version by build.js at bundle time.
499702
- version: "0.113.3"
499734
+ version: "0.113.5"
499703
499735
  },
499704
499736
  {
499705
499737
  capabilities: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/mcp-server",
3
- "version": "0.113.3",
3
+ "version": "0.113.5",
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.3",
64
- "@vibeframe/core": "0.113.3"
63
+ "@vibeframe/cli": "0.113.5",
64
+ "@vibeframe/core": "0.113.5"
65
65
  },
66
66
  "engines": {
67
67
  "node": ">=20"