@vibeframe/mcp-server 0.105.2 → 0.106.0

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 +250 -65
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -435908,6 +435908,40 @@ var init_whisper = __esm3({
435908
435908
  init_WhisperProvider();
435909
435909
  }
435910
435910
  });
435911
+ function isGeminiTextModelAlias(model) {
435912
+ return Object.prototype.hasOwnProperty.call(GEMINI_TEXT_MODEL_ALIASES, model);
435913
+ }
435914
+ function resolveGeminiTextModel(model) {
435915
+ const trimmed = model?.trim();
435916
+ if (!trimmed)
435917
+ return GEMINI_DEFAULT_TEXT_MODEL;
435918
+ if (isGeminiTextModelAlias(trimmed))
435919
+ return GEMINI_TEXT_MODEL_ALIASES[trimmed];
435920
+ if (trimmed.startsWith("gemini-"))
435921
+ return trimmed;
435922
+ return GEMINI_DEFAULT_TEXT_MODEL;
435923
+ }
435924
+ var GEMINI_DEFAULT_TEXT_MODEL;
435925
+ var GEMINI_AGENT_DEFAULT_TEXT_MODEL;
435926
+ var GEMINI_TEXT_MODEL_ALIASES;
435927
+ var GEMINI_TEXT_MODEL_HELP;
435928
+ var init_gemini_models = __esm3({
435929
+ "../ai-providers/dist/gemini/gemini-models.js"() {
435930
+ "use strict";
435931
+ GEMINI_DEFAULT_TEXT_MODEL = "gemini-3.5-flash";
435932
+ GEMINI_AGENT_DEFAULT_TEXT_MODEL = "gemini-2.5-flash";
435933
+ GEMINI_TEXT_MODEL_ALIASES = {
435934
+ flash: GEMINI_DEFAULT_TEXT_MODEL,
435935
+ latest: GEMINI_DEFAULT_TEXT_MODEL,
435936
+ "flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
435937
+ "flash-3": "gemini-3-flash-preview",
435938
+ "flash-2.5": "gemini-2.5-flash",
435939
+ pro: "gemini-2.5-pro",
435940
+ "pro-3.1": "gemini-3.1-pro-preview"
435941
+ };
435942
+ GEMINI_TEXT_MODEL_HELP = "flash/latest (Gemini 3.5 Flash), flash-3.5, flash-3, flash-2.5, pro, pro-3.1, or a full gemini-* model ID";
435943
+ }
435944
+ });
435911
435945
  function buildMotionSystemPrompt(width, height, fps, duration, durationInFrames, stylePreset) {
435912
435946
  return `You are a world-class broadcast motion graphics designer (like Apple Keynote, Netflix intros, ESPN graphics). Create STUNNING, jaw-dropping overlays that make viewers go "wow".
435913
435947
 
@@ -436060,7 +436094,7 @@ async function generateMotion(api, description, options = {}) {
436060
436094
  const duration = options.duration || 5;
436061
436095
  const durationInFrames = Math.round(duration * fps);
436062
436096
  const stylePreset = options.style || "modern and clean";
436063
- const modelId = options.model || "gemini-2.5-pro";
436097
+ const modelId = resolveGeminiTextModel(options.model);
436064
436098
  let systemPrompt = buildMotionSystemPrompt(width, height, fps, duration, durationInFrames, stylePreset);
436065
436099
  if (options.videoContext) {
436066
436100
  const sourceLabel = options.sourceType === "image" ? "IMAGE" : "VIDEO";
@@ -436141,7 +436175,7 @@ async function refineMotion(api, existingCode, instructions, options = {}) {
436141
436175
  const fps = options.fps || 30;
436142
436176
  const duration = options.duration || 5;
436143
436177
  const durationInFrames = Math.round(duration * fps);
436144
- const modelId = options.model || "gemini-2.5-pro";
436178
+ const modelId = resolveGeminiTextModel(options.model);
436145
436179
  const systemPrompt = `You are a world-class broadcast motion graphics designer. Modify the provided Remotion component based on instructions.
436146
436180
 
436147
436181
  CANVAS: ${width}\xD7${height}px | ${fps}fps | ${durationInFrames} frames (${duration}s)
@@ -436237,9 +436271,18 @@ var STYLE_USER_INSTRUCTIONS;
436237
436271
  var init_gemini_motion = __esm3({
436238
436272
  "../ai-providers/dist/gemini/gemini-motion.js"() {
436239
436273
  "use strict";
436274
+ init_gemini_models();
436240
436275
  GEMINI_MOTION_MODELS = {
436276
+ gemini: GEMINI_DEFAULT_TEXT_MODEL,
436277
+ flash: GEMINI_DEFAULT_TEXT_MODEL,
436278
+ latest: GEMINI_DEFAULT_TEXT_MODEL,
436279
+ "flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
436280
+ "flash-3": "gemini-3-flash-preview",
436281
+ "flash-2.5": "gemini-2.5-flash",
436241
436282
  pro: "gemini-2.5-pro",
436242
- "3.1-pro": "gemini-3.1-pro-preview"
436283
+ "2.5-pro": "gemini-2.5-pro",
436284
+ "3.1-pro": "gemini-3.1-pro-preview",
436285
+ "pro-3.1": "gemini-3.1-pro-preview"
436243
436286
  };
436244
436287
  STYLE_USER_INSTRUCTIONS = {
436245
436288
  minimal: "CENTER-ALIGNED pure typography. Thin lines + large title + subtitle. NO glass panels, NO bokeh, NO dark bars. Breathing pulse during hold.",
@@ -436358,7 +436401,7 @@ async function analyzeContent(api, content, targetDuration, options) {
436358
436401
  maxOutputTokens: 4096
436359
436402
  }
436360
436403
  };
436361
- const response = await fetch(`${api.baseUrl}/models/gemini-2.5-flash:generateContent?key=${api.apiKey}`, {
436404
+ const response = await fetch(`${api.baseUrl}/models/${GEMINI_DEFAULT_TEXT_MODEL}:generateContent?key=${api.apiKey}`, {
436362
436405
  method: "POST",
436363
436406
  headers: { "Content-Type": "application/json" },
436364
436407
  body: JSON.stringify(payload)
@@ -436391,6 +436434,7 @@ var init_gemini_storyboard = __esm3({
436391
436434
  "../ai-providers/dist/gemini/gemini-storyboard.js"() {
436392
436435
  "use strict";
436393
436436
  init_storyboard_prompt();
436437
+ init_gemini_models();
436394
436438
  }
436395
436439
  });
436396
436440
  async function fetchJson(label, url, init) {
@@ -436427,6 +436471,7 @@ var init_GeminiProvider = __esm3({
436427
436471
  "../ai-providers/dist/gemini/GeminiProvider.js"() {
436428
436472
  "use strict";
436429
436473
  init_gemini_motion();
436474
+ init_gemini_models();
436430
436475
  init_gemini_storyboard();
436431
436476
  init_http();
436432
436477
  MODEL_MAP = {
@@ -436935,7 +436980,7 @@ var init_GeminiProvider = __esm3({
436935
436980
  error: "Google API key not configured"
436936
436981
  };
436937
436982
  }
436938
- const modelId = options.model || "gemini-3-flash-preview";
436983
+ const modelId = resolveGeminiTextModel(options.model);
436939
436984
  try {
436940
436985
  let videoPart;
436941
436986
  if (typeof videoData === "string") {
@@ -437042,7 +437087,7 @@ var init_GeminiProvider = __esm3({
437042
437087
  error: "Google API key not configured"
437043
437088
  };
437044
437089
  }
437045
- const modelId = options.model || "gemini-3-flash-preview";
437090
+ const modelId = resolveGeminiTextModel(options.model);
437046
437091
  try {
437047
437092
  const buffers = Array.isArray(imageData) ? imageData : [imageData];
437048
437093
  const imageParts = buffers.map((buf) => ({
@@ -437144,7 +437189,7 @@ Example response:
437144
437189
  [{"type":"trim","description":"Trim intro to 3 seconds","clipIds":["clip-1"],"params":{"newDuration":3},"confidence":0.9}]
437145
437190
 
437146
437191
  Respond with ONLY the JSON array, no other text.`;
437147
- const response = await fetch(`${this.baseUrl}/models/gemini-2.5-flash:generateContent?key=${this.apiKey}`, {
437192
+ const response = await fetch(`${this.baseUrl}/models/${GEMINI_DEFAULT_TEXT_MODEL}:generateContent?key=${this.apiKey}`, {
437148
437193
  method: "POST",
437149
437194
  headers: {
437150
437195
  "Content-Type": "application/json"
@@ -437264,6 +437309,7 @@ var init_gemini = __esm3({
437264
437309
  "use strict";
437265
437310
  init_GeminiProvider();
437266
437311
  init_gemini_motion();
437312
+ init_gemini_models();
437267
437313
  init_define_provider();
437268
437314
  defineProvider({
437269
437315
  id: "gemini",
@@ -446526,6 +446572,10 @@ __export3(dist_exports22, {
446526
446572
  ClaudeProvider: () => ClaudeProvider,
446527
446573
  ElevenLabsProvider: () => ElevenLabsProvider,
446528
446574
  FalProvider: () => FalProvider,
446575
+ GEMINI_AGENT_DEFAULT_TEXT_MODEL: () => GEMINI_AGENT_DEFAULT_TEXT_MODEL,
446576
+ GEMINI_DEFAULT_TEXT_MODEL: () => GEMINI_DEFAULT_TEXT_MODEL,
446577
+ GEMINI_TEXT_MODEL_ALIASES: () => GEMINI_TEXT_MODEL_ALIASES,
446578
+ GEMINI_TEXT_MODEL_HELP: () => GEMINI_TEXT_MODEL_HELP,
446529
446579
  GeminiProvider: () => GeminiProvider,
446530
446580
  GrokProvider: () => GrokProvider,
446531
446581
  KNOWN_VOICES: () => KNOWN_VOICES,
@@ -446556,6 +446606,7 @@ __export3(dist_exports22, {
446556
446606
  getProvidersFor: () => getProvidersFor,
446557
446607
  getSetupProviders: () => getSetupProviders,
446558
446608
  grokProvider: () => grokProvider,
446609
+ isGeminiTextModelAlias: () => isGeminiTextModelAlias,
446559
446610
  klingProvider: () => klingProvider,
446560
446611
  kokoroProvider: () => kokoroProvider,
446561
446612
  ollamaProvider: () => ollamaProvider,
@@ -446563,6 +446614,7 @@ __export3(dist_exports22, {
446563
446614
  openaiProvider: () => openaiProvider,
446564
446615
  providerRegistry: () => providerRegistry,
446565
446616
  replicateProvider: () => replicateProvider,
446617
+ resolveGeminiTextModel: () => resolveGeminiTextModel,
446566
446618
  resolveVoiceId: () => resolveVoiceId,
446567
446619
  runwayProvider: () => runwayProvider,
446568
446620
  whisperProvider: () => whisperProvider
@@ -449708,6 +449760,7 @@ var CONFIG_PROVIDER_BY_COMPOSER;
449708
449760
  var init_compose_scenes_skills = __esm3({
449709
449761
  "src/commands/_shared/compose-scenes-skills.ts"() {
449710
449762
  "use strict";
449763
+ init_dist22();
449711
449764
  init_config();
449712
449765
  init_bundle();
449713
449766
  init_scene_lint();
@@ -449729,12 +449782,12 @@ var init_compose_scenes_skills = __esm3({
449729
449782
  medium: { model: "gpt-5", maxTokens: 6e3, costPerMTokIn: 1.25, costPerMTokOut: 10 },
449730
449783
  high: { model: "gpt-5", maxTokens: 8e3, costPerMTokIn: 1.25, costPerMTokOut: 10 }
449731
449784
  },
449732
- // Google Gemini 2.5 Pro~2.6× cheaper than Claude per spike, ~20 s/beat.
449733
- // Strong instruction-following on the Hyperframes skill bundle.
449785
+ // Google Gemini 3.5 Flashcurrent one-shot Gemini default for
449786
+ // analysis/composition. Keep agent loops on their explicit 2.5 Flash default.
449734
449787
  gemini: {
449735
- low: { model: "gemini-2.5-pro", maxTokens: 4e3, costPerMTokIn: 1.25, costPerMTokOut: 5 },
449736
- medium: { model: "gemini-2.5-pro", maxTokens: 6e3, costPerMTokIn: 1.25, costPerMTokOut: 5 },
449737
- high: { model: "gemini-2.5-pro", maxTokens: 8e3, costPerMTokIn: 1.25, costPerMTokOut: 5 }
449788
+ low: { model: GEMINI_DEFAULT_TEXT_MODEL, maxTokens: 4e3, costPerMTokIn: 1.5, costPerMTokOut: 9 },
449789
+ medium: { model: GEMINI_DEFAULT_TEXT_MODEL, maxTokens: 6e3, costPerMTokIn: 1.5, costPerMTokOut: 9 },
449790
+ high: { model: GEMINI_DEFAULT_TEXT_MODEL, maxTokens: 8e3, costPerMTokIn: 1.5, costPerMTokOut: 9 }
449738
449791
  }
449739
449792
  };
449740
449793
  ComposeBeatError = class extends Error {
@@ -456309,12 +456362,7 @@ async function detectSilencePeriodsWithGemini(videoPath, minDuration, options) {
456309
456362
  const gemini = new GeminiProvider();
456310
456363
  await gemini.initialize({ apiKey: geminiApiKey });
456311
456364
  const videoBuffer = await readFile18(videoPath);
456312
- const modelMap = {
456313
- flash: "gemini-3-flash-preview",
456314
- "flash-2.5": "gemini-2.5-flash",
456315
- pro: "gemini-2.5-pro"
456316
- };
456317
- const modelId = options.model ? modelMap[options.model] || modelMap.flash : void 0;
456365
+ const modelId = options.model ? resolveGeminiTextModel(options.model) : void 0;
456318
456366
  const prompt3 = `Analyze this video and identify all silent or dead segments where there is NO meaningful content.
456319
456367
 
456320
456368
  Detect these as silent/dead segments:
@@ -459710,7 +459758,7 @@ Use this image analysis to inform the color palette, typography placement, and o
459710
459758
  6. Recommended animation timing and entrance/exit style
459711
459759
  7. Any moments where overlays should pause, fade, or stay minimal`;
459712
459760
  const analysisResult = await gemini.analyzeVideo(videoBuffer, analysisPrompt, {
459713
- model: "gemini-2.5-flash",
459761
+ model: GEMINI_DEFAULT_TEXT_MODEL,
459714
459762
  fps: 1,
459715
459763
  lowResolution: true
459716
459764
  });
@@ -459879,7 +459927,7 @@ function registerMotionCommand(aiCommand) {
459879
459927
  "auto"
459880
459928
  ).option("--understanding-prompt <text>", "Custom prompt for --video understanding").option("--from-tsx <path>", "Refine an existing TSX file instead of generating from scratch").option(
459881
459929
  "-m, --model <alias>",
459882
- "LLM model: sonnet (default), opus, gemini, gemini-3.1-pro",
459930
+ "LLM model: sonnet (default), opus, gemini, gemini-2.5-pro, gemini-3.1-pro",
459883
459931
  "sonnet"
459884
459932
  ).option("--dry-run", "Preview parameters without executing").action(async (description, options) => {
459885
459933
  const startedAt = Date.now();
@@ -460023,7 +460071,8 @@ var init_ai_motion = __esm3({
460023
460071
  sonnet: { provider: "claude", modelId: "claude-sonnet-4-6" },
460024
460072
  opus: { provider: "claude", modelId: "claude-opus-4-7" },
460025
460073
  "opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
460026
- gemini: { provider: "gemini", modelId: "gemini-2.5-pro" },
460074
+ gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
460075
+ "gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
460027
460076
  "gemini-3.1-pro": { provider: "gemini", modelId: "gemini-3.1-pro-preview" }
460028
460077
  };
460029
460078
  }
@@ -460584,7 +460633,7 @@ async function executeMotionOverlay(options) {
460584
460633
  };
460585
460634
  }
460586
460635
  function registerMotionOverlayCommand(parent) {
460587
- parent.command("motion-overlay").description("Apply designed motion graphics overlays to an existing video").argument("<video>", "Video file path").argument("[description]", "Motion overlay description (omit when using --asset)").option("--asset <path>", "User-provided .json/.lottie animation to overlay").option("-o, --output <path>", "Output video file path").option("-d, --duration <sec>", "Overlay/render duration in seconds").option("--start <sec>", "Overlay start time in seconds", "0").option("--style <style>", "Style preset for generated overlays: minimal, corporate, playful, cinematic").option("-m, --model <alias>", "LLM model for generated overlays: sonnet, opus, gemini, gemini-3.1-pro", "sonnet").option("--understand <mode>", "Analyze video before generated overlay: auto, off, required", "auto").option("--understanding-prompt <text>", "Custom prompt for video understanding").option("--position <position>", "Lottie position: full, center, top-left, top-right, bottom-left, bottom-right", "full").option("--scale <number>", "Lottie overlay scale (0.01-2)").option("--opacity <number>", "Lottie overlay opacity (0-1)", "1").option("--loop", "Loop Lottie overlay", true).option("--no-loop", "Do not loop Lottie overlay").option("--dry-run", "Preview parameters without executing").action(async (videoPath, description, options) => {
460636
+ parent.command("motion-overlay").description("Apply designed motion graphics overlays to an existing video").argument("<video>", "Video file path").argument("[description]", "Motion overlay description (omit when using --asset)").option("--asset <path>", "User-provided .json/.lottie animation to overlay").option("-o, --output <path>", "Output video file path").option("-d, --duration <sec>", "Overlay/render duration in seconds").option("--start <sec>", "Overlay start time in seconds", "0").option("--style <style>", "Style preset for generated overlays: minimal, corporate, playful, cinematic").option("-m, --model <alias>", "LLM model for generated overlays: sonnet, opus, gemini, gemini-2.5-pro, gemini-3.1-pro", "sonnet").option("--understand <mode>", "Analyze video before generated overlay: auto, off, required", "auto").option("--understanding-prompt <text>", "Custom prompt for video understanding").option("--position <position>", "Lottie position: full, center, top-left, top-right, bottom-left, bottom-right", "full").option("--scale <number>", "Lottie overlay scale (0.01-2)").option("--opacity <number>", "Lottie overlay opacity (0-1)", "1").option("--loop", "Loop Lottie overlay", true).option("--no-loop", "Do not loop Lottie overlay").option("--dry-run", "Preview parameters without executing").action(async (videoPath, description, options) => {
460588
460637
  const startedAt = Date.now();
460589
460638
  try {
460590
460639
  if (options.output) validateOutputPath(options.output);
@@ -461864,13 +461913,7 @@ async function executeThumbnailBestFrame(options) {
461864
461913
  await gemini.initialize({ apiKey: googleKey });
461865
461914
  const videoData = await readFile25(videoPath);
461866
461915
  const analysisPrompt = prompt3 || 'Analyze this video and find the single best frame for a thumbnail. Look for frames that are visually striking, well-composed, emotionally engaging, and representative of the video content. Avoid blurry frames, transitions, or dark scenes. Return ONLY a JSON object: {"timestamp": <seconds as number>, "reason": "<brief explanation>"}';
461867
- const modelMap = {
461868
- flash: "gemini-3-flash-preview",
461869
- latest: "gemini-2.5-flash",
461870
- "flash-2.5": "gemini-2.5-flash",
461871
- pro: "gemini-2.5-pro"
461872
- };
461873
- const modelId = modelMap[model] || "gemini-3-flash-preview";
461916
+ const modelId = resolveGeminiTextModel(model);
461874
461917
  const result = await gemini.analyzeVideo(videoData, analysisPrompt, {
461875
461918
  model: modelId,
461876
461919
  fps: 1
@@ -461925,12 +461968,7 @@ async function executeGeminiVideo(options) {
461925
461968
  return { success: false, error: "Google API key required. Run 'vibe setup' or set GOOGLE_API_KEY in .env" };
461926
461969
  }
461927
461970
  const isYouTube = options.source.includes("youtube.com") || options.source.includes("youtu.be");
461928
- const modelMap = {
461929
- flash: "gemini-3-flash-preview",
461930
- "flash-2.5": "gemini-2.5-flash",
461931
- pro: "gemini-2.5-pro"
461932
- };
461933
- const modelId = modelMap[options.model || "flash"] || modelMap.flash;
461971
+ const modelId = resolveGeminiTextModel(options.model);
461934
461972
  let videoData;
461935
461973
  if (isYouTube) {
461936
461974
  videoData = options.source;
@@ -461991,12 +462029,7 @@ async function executeAnalyze(options) {
461991
462029
  error: "Cannot detect source type. Supported: images (.png/.jpg/.webp/.gif), videos (.mp4/.mov/.webm), YouTube URLs, image URLs."
461992
462030
  };
461993
462031
  }
461994
- const modelMap = {
461995
- flash: "gemini-3-flash-preview",
461996
- "flash-2.5": "gemini-2.5-flash",
461997
- pro: "gemini-2.5-pro"
461998
- };
461999
- const modelId = modelMap[options.model || "flash"] || modelMap.flash;
462032
+ const modelId = resolveGeminiTextModel(options.model);
462000
462033
  const gemini = new GeminiProvider();
462001
462034
  await gemini.initialize({ apiKey });
462002
462035
  if (isImage) {
@@ -462076,7 +462109,7 @@ async function executeAnalyze(options) {
462076
462109
  }
462077
462110
  }
462078
462111
  function registerAnalyzeCommands(aiCommand) {
462079
- aiCommand.command("gemini-video").description("Analyze video using Gemini (summarize, Q&A, extract info)").argument("<source>", "Video file path or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", "Model: flash (default), flash-2.5, pro", "flash").option("--fps <number>", "Frames per second (default: 1, higher for action)").option("--start <seconds>", "Start offset in seconds (for clipping)").option("--end <seconds>", "End offset in seconds (for clipping)").option("--low-res", "Use low resolution mode (fewer tokens, longer videos)").option("-v, --verbose", "Show token usage").action(async (source3, prompt3, options) => {
462112
+ aiCommand.command("gemini-video").description("Analyze video using Gemini (summarize, Q&A, extract info)").argument("<source>", "Video file path or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", `Model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("--fps <number>", "Frames per second (default: 1, higher for action)").option("--start <seconds>", "Start offset in seconds (for clipping)").option("--end <seconds>", "End offset in seconds (for clipping)").option("--low-res", "Use low resolution mode (fewer tokens, longer videos)").option("-v, --verbose", "Show token usage").action(async (source3, prompt3, options) => {
462080
462113
  try {
462081
462114
  if (options.apiKey) {
462082
462115
  process.env.GOOGLE_API_KEY = options.apiKey;
@@ -462119,7 +462152,7 @@ function registerAnalyzeCommands(aiCommand) {
462119
462152
  exitWithError(apiError(`Video analysis failed: ${error instanceof Error ? error.message : String(error)}`, true));
462120
462153
  }
462121
462154
  });
462122
- aiCommand.command("analyze").description("Analyze any media: images, videos, or YouTube URLs using Gemini").argument("<source>", "Image/video file path, image URL, or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", "Model: flash (default), flash-2.5, pro", "flash").option("--fps <number>", "Frames per second for video (default: 1)").option("--start <seconds>", "Start offset in seconds (video only)").option("--end <seconds>", "End offset in seconds (video only)").option("--low-res", "Use low resolution mode (fewer tokens)").option("-v, --verbose", "Show token usage").action(async (source3, prompt3, options) => {
462155
+ aiCommand.command("analyze").description("Analyze any media: images, videos, or YouTube URLs using Gemini").argument("<source>", "Image/video file path, image URL, or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", `Model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("--fps <number>", "Frames per second for video (default: 1)").option("--start <seconds>", "Start offset in seconds (video only)").option("--end <seconds>", "End offset in seconds (video only)").option("--low-res", "Use low resolution mode (fewer tokens)").option("-v, --verbose", "Show token usage").action(async (source3, prompt3, options) => {
462123
462156
  try {
462124
462157
  if (options.apiKey) {
462125
462158
  process.env.GOOGLE_API_KEY = options.apiKey;
@@ -462235,12 +462268,7 @@ ${content}`;
462235
462268
 
462236
462269
  Project context for beat-aware review:
462237
462270
  ${projectContext}` : "";
462238
- const modelMap = {
462239
- flash: "gemini-3-flash-preview",
462240
- "flash-2.5": "gemini-2.5-flash",
462241
- pro: "gemini-2.5-pro"
462242
- };
462243
- const modelId = modelMap[model] || modelMap.flash;
462271
+ const modelId = resolveGeminiTextModel(model);
462244
462272
  const reviewPrompt = `You are a professional video editor reviewing this video for quality. Analyze the video and return a JSON review with the following structure. Return ONLY valid JSON, no extra text.
462245
462273
 
462246
462274
  {
@@ -462347,7 +462375,7 @@ Score each category 1-10. Prefer beatIssues when you can map a problem to a stor
462347
462375
  return result;
462348
462376
  }
462349
462377
  function registerReviewCommand(aiCommand) {
462350
- aiCommand.command("review", { hidden: true }).description("Review video quality using Gemini AI and optionally auto-fix issues").argument("<source>", "Video file path").option("--storyboard <path>", "Storyboard JSON file for context").option("--auto-apply", "Automatically apply fixable corrections").option("--verify", "Run verification pass after applying fixes").option("-m, --model <model>", "Gemini model: flash (default), flash-2.5, pro", "flash").option("-o, --output <path>", "Output video file path (for auto-apply)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
462378
+ aiCommand.command("review", { hidden: true }).description("Review video quality using Gemini AI and optionally auto-fix issues").argument("<source>", "Video file path").option("--storyboard <path>", "Storyboard JSON file for context").option("--auto-apply", "Automatically apply fixable corrections").option("--verify", "Run verification pass after applying fixes").option("-m, --model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("-o, --output <path>", "Output video file path (for auto-apply)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
462351
462379
  const startedAt = Date.now();
462352
462380
  try {
462353
462381
  if (options.output) {
@@ -463204,7 +463232,7 @@ var init_speech = __esm3({
463204
463232
  }
463205
463233
  });
463206
463234
  function registerThumbnailCommand(parent) {
463207
- parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>", "Gemini model: flash, latest, pro (default: flash)", "flash").action(async (description, options) => {
463235
+ parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").action(async (description, options) => {
463208
463236
  const startedAt = Date.now();
463209
463237
  try {
463210
463238
  if (description) rejectControlChars(description);
@@ -465404,7 +465432,7 @@ function registerVideoCommand(parent) {
465404
465432
  "--seedance-model <model>",
465405
465433
  "Seedance variant: quality or fast (fal.ai only)",
465406
465434
  "quality"
465407
- ).option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 720p, 1080p, 4k (Veo only)").option("--last-frame <path>", "Last frame image for frame interpolation (Veo only)").option(
465435
+ ).option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 480p, 720p, 1080p, or 4k depending on provider").option("--last-frame <path>", "Last frame image for frame interpolation (Veo) or Seedance end frame").option("--end-image <path>", "Ending frame image for Seedance image-to-video").option(
465408
465436
  "--ref-images <paths...>",
465409
465437
  "Reference images for Seedance reference-to-video or Veo character consistency"
465410
465438
  ).option("--ref-videos <paths...>", "Reference videos for Seedance reference-to-video").option("--ref-audio <paths...>", "Reference audio for Seedance reference-to-video").option("--no-generate-audio", "Disable native audio when the provider supports it").option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast (default: 3.1-fast)", "3.1-fast").option(
@@ -465865,6 +465893,30 @@ Examples:
465865
465893
  exitWithError(apiError(message, true));
465866
465894
  }
465867
465895
  }
465896
+ let seedanceEndImage;
465897
+ const seedanceEndImagePath = options.endImage ?? options.lastFrame;
465898
+ if (seedanceEndImagePath && seedanceReferences.length === 0) {
465899
+ try {
465900
+ const absEndImagePath = resolve50(process.cwd(), seedanceEndImagePath);
465901
+ const endImageBuffer = await readFile32(absEndImagePath);
465902
+ const ext = seedanceEndImagePath.toLowerCase().split(".").pop();
465903
+ const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
465904
+ const uploadHost = await resolveUploadHost();
465905
+ spinner2.text = `Uploading end image via ${uploadHost.provider} for Seedance...`;
465906
+ const upload = await uploadHost.uploadImage(endImageBuffer, {
465907
+ filename: seedanceEndImagePath,
465908
+ mimeType
465909
+ });
465910
+ seedanceEndImage = upload.url;
465911
+ } catch (err) {
465912
+ spinner2.fail("End image upload failed");
465913
+ const message = err instanceof Error ? err.message : String(err);
465914
+ if (message.includes("IMGBB_API_KEY")) {
465915
+ exitWithError(authError("IMGBB_API_KEY", "ImgBB"));
465916
+ }
465917
+ exitWithError(apiError(message, true));
465918
+ }
465919
+ }
465868
465920
  spinner2.text = "Generating video with fal.ai Seedance 2.0 (this may take 1-3 minutes)...";
465869
465921
  const seedanceModel = String(options.seedanceModel ?? "quality").toLowerCase();
465870
465922
  const falModel = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
@@ -465877,7 +465929,8 @@ Examples:
465877
465929
  negativePrompt: options.negative,
465878
465930
  model: falModel,
465879
465931
  resolution: options.resolution,
465880
- generateAudio: options.generateAudio
465932
+ generateAudio: options.generateAudio,
465933
+ lastFrame: seedanceEndImage
465881
465934
  });
465882
465935
  finalResult = result;
465883
465936
  }
@@ -471712,6 +471765,14 @@ var SCENE_PRESETS = [
471712
471765
  "kinetic-type",
471713
471766
  "product-shot"
471714
471767
  ];
471768
+ var LOTTIE_POSITIONS = [
471769
+ "full",
471770
+ "center",
471771
+ "top-left",
471772
+ "top-right",
471773
+ "bottom-left",
471774
+ "bottom-right"
471775
+ ];
471715
471776
  var GSAP_CDN = "https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js";
471716
471777
  function esc(text) {
471717
471778
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
@@ -471992,6 +472053,56 @@ function buildPreset(input3) {
471992
472053
  }
471993
472054
  }
471994
472055
  }
472056
+ var DOTLOTTIE_WC_VERSION = "0.9.12";
472057
+ var DOTLOTTIE_WEB_VERSION = "0.71.0";
472058
+ var DOTLOTTIE_WC_CDN = `https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-wc@${DOTLOTTIE_WC_VERSION}/dist/index.js`;
472059
+ var DOTLOTTIE_WASM_CDN = `https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-web@${DOTLOTTIE_WEB_VERSION}/dist/dotlottie-player.wasm`;
472060
+ function lottieOverlayStyle(input3) {
472061
+ const pos = input3.position ?? "full";
472062
+ const rawScale = input3.scale ?? (pos === "full" ? 1 : 0.25);
472063
+ const scale = Math.max(0.01, Math.min(2, rawScale));
472064
+ const opacity = Math.max(0, Math.min(1, input3.opacity ?? 1));
472065
+ const base = [
472066
+ "position:absolute",
472067
+ "pointer-events:none",
472068
+ `opacity:${opacity}`
472069
+ ];
472070
+ if (pos === "full") {
472071
+ base.push("inset:0", "width:100%", "height:100%");
472072
+ } else {
472073
+ const pct = scale * 100;
472074
+ base.push(`width:${pct}%`, `height:${pct}%`);
472075
+ switch (pos) {
472076
+ case "center":
472077
+ base.push("top:50%", "left:50%", "transform:translate(-50%,-50%)");
472078
+ break;
472079
+ case "top-left":
472080
+ base.push("top:4%", "left:4%");
472081
+ break;
472082
+ case "top-right":
472083
+ base.push("top:4%", "right:4%");
472084
+ break;
472085
+ case "bottom-left":
472086
+ base.push("bottom:4%", "left:4%");
472087
+ break;
472088
+ case "bottom-right":
472089
+ base.push("bottom:4%", "right:4%");
472090
+ break;
472091
+ }
472092
+ }
472093
+ return base.join(";");
472094
+ }
472095
+ function buildLottieOverlay(input3, sceneId) {
472096
+ const loop = input3.loop ?? true ? " loop" : "";
472097
+ const style = lottieOverlayStyle(input3);
472098
+ const overlayId = `lottie-overlay-${sceneId}`;
472099
+ const markup = `<dotlottie-wc id="${overlayId}" src="${esc(input3.src)}" autoplay${loop} style="${style}"></dotlottie-wc>`;
472100
+ const script = `<script type="module">
472101
+ import { setWasmUrl } from "${DOTLOTTIE_WC_CDN}";
472102
+ setWasmUrl("${DOTLOTTIE_WASM_CDN}");
472103
+ </script>`;
472104
+ return { markup, script };
472105
+ }
471995
472106
  function emitSceneHtml(input3) {
471996
472107
  if (input3.duration <= 0) {
471997
472108
  throw new Error(`Scene duration must be > 0, got ${input3.duration}`);
@@ -472012,15 +472123,20 @@ function emitSceneHtml(input3) {
472012
472123
  data-volume="1"
472013
472124
  ></audio>
472014
472125
  ` : "";
472126
+ const lottieLayer = input3.lottie ? buildLottieOverlay(input3.lottie, id) : null;
472127
+ const lottieMarkup = lottieLayer ? `
472128
+ ${lottieLayer.markup}` : "";
472129
+ const lottieScript = lottieLayer ? `
472130
+ ${lottieLayer.script}` : "";
472015
472131
  return `<template id="scene-${id}-template">
472016
472132
  <div data-composition-id="${id}" data-start="0" data-duration="${dur}" data-width="${input3.width}" data-height="${input3.height}">
472017
472133
  <style>
472018
472134
  ${parts.css}
472019
472135
  </style>
472020
472136
 
472021
- ${parts.body}
472137
+ ${parts.body}${lottieMarkup}
472022
472138
  ${audioBlock}
472023
- <script src="${GSAP_CDN}"></script>
472139
+ <script src="${GSAP_CDN}"></script>${lottieScript}
472024
472140
  <script>
472025
472141
  window.__timelines = window.__timelines || {};
472026
472142
  const tl = gsap.timeline({ paused: true });
@@ -472435,9 +472551,40 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
472435
472551
  ).option("--no-image", "Skip image generation even when --visuals is provided").option(
472436
472552
  "--no-transcribe",
472437
472553
  "Skip Whisper word-level transcribe step (no transcript-<id>.json emitted)"
472438
- ).option("--transcribe-language <code>", "BCP-47 language code passed to Whisper (e.g. en, ko)").option("--force", "Overwrite an existing compositions/scene-<id>.html").option("--dry-run", "Preview parameters without writing files or calling APIs").action(async (name, options) => {
472554
+ ).option("--transcribe-language <code>", "BCP-47 language code passed to Whisper (e.g. en, ko)").option("--force", "Overwrite an existing compositions/scene-<id>.html").option("--lottie <path>", "Lottie animation file (.json/.lottie) to overlay on the scene").option(
472555
+ "--lottie-position <position>",
472556
+ `Lottie position: ${LOTTIE_POSITIONS.join(", ")}`,
472557
+ "full"
472558
+ ).option("--lottie-scale <number>", "Lottie overlay scale (0.01-2)").option("--lottie-opacity <number>", "Lottie overlay opacity (0-1)", "1").option("--lottie-no-loop", "Do not loop the Lottie animation").option("--dry-run", "Preview parameters without writing files or calling APIs").action(async (name, options) => {
472439
472559
  const startedAt = Date.now();
472440
472560
  if (options.style) options.style = validatePreset(options.style);
472561
+ if (options.lottiePosition) {
472562
+ if (!LOTTIE_POSITIONS.includes(options.lottiePosition)) {
472563
+ exitWithError(
472564
+ usageError(
472565
+ `Invalid --lottie-position "${options.lottiePosition}". Valid: ${LOTTIE_POSITIONS.join(", ")}`
472566
+ )
472567
+ );
472568
+ }
472569
+ }
472570
+ let lottieScale;
472571
+ if (options.lottieScale !== void 0) {
472572
+ lottieScale = Number(options.lottieScale);
472573
+ if (!Number.isFinite(lottieScale) || lottieScale < 0.01 || lottieScale > 2) {
472574
+ exitWithError(
472575
+ usageError(`Invalid --lottie-scale "${options.lottieScale}". Must be between 0.01 and 2.`)
472576
+ );
472577
+ }
472578
+ }
472579
+ let lottieOpacity = 1;
472580
+ if (options.lottieOpacity !== void 0) {
472581
+ lottieOpacity = Number(options.lottieOpacity);
472582
+ if (!Number.isFinite(lottieOpacity) || lottieOpacity < 0 || lottieOpacity > 1) {
472583
+ exitWithError(
472584
+ usageError(`Invalid --lottie-opacity "${options.lottieOpacity}". Must be between 0 and 1.`)
472585
+ );
472586
+ }
472587
+ }
472441
472588
  if (options.duration !== void 0) options.duration = validateDuration(options.duration);
472442
472589
  let tts;
472443
472590
  try {
@@ -472466,7 +472613,11 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
472466
472613
  imageProvider: options.imageProvider,
472467
472614
  tts,
472468
472615
  audio: options.audio,
472469
- // commander sets `audio: false` when --no-audio is passed
472616
+ lottie: options.lottie ?? null,
472617
+ lottiePosition: options.lottiePosition,
472618
+ lottieScale: lottieScale ?? null,
472619
+ lottieOpacity: options.lottieOpacity !== void 0 ? lottieOpacity : null,
472620
+ lottieLoop: !options.lottieNoLoop,
472470
472621
  image: options.image
472471
472622
  }
472472
472623
  }
@@ -472494,6 +472645,13 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
472494
472645
  skipTranscribe: options.transcribe === false,
472495
472646
  transcribeLanguage: options.transcribeLanguage,
472496
472647
  force: !!options.force,
472648
+ lottie: options.lottie ? {
472649
+ src: options.lottie,
472650
+ position: options.lottiePosition ?? "full",
472651
+ scale: lottieScale,
472652
+ opacity: options.lottieOpacity !== void 0 ? lottieOpacity : 1,
472653
+ loop: !options.lottieNoLoop
472654
+ } : void 0,
472497
472655
  onProgress: (msg) => {
472498
472656
  if (spinner2) spinner2.text = msg;
472499
472657
  }
@@ -472769,6 +472927,30 @@ async function executeSceneAdd(opts) {
472769
472927
  await writeFile10(imageAbsPath, buffer);
472770
472928
  }
472771
472929
  }
472930
+ let lottieRelPath;
472931
+ let lottieAbsPath;
472932
+ let lottieInput;
472933
+ if (opts.lottie) {
472934
+ const sourceAbs = resolve122(opts.lottie.src);
472935
+ if (!await pathExists2(sourceAbs)) {
472936
+ return errResult(`Lottie file not found: ${sourceAbs}`);
472937
+ }
472938
+ const ext = (sourceAbs.match(/\.([a-z0-9]+)$/i)?.[1] ?? "json").toLowerCase();
472939
+ if (ext !== "json" && ext !== "lottie") {
472940
+ return errResult(`Unsupported Lottie file extension: .${ext}. Use .json or .lottie.`);
472941
+ }
472942
+ lottieRelPath = `assets/lottie-${id}.${ext}`;
472943
+ lottieAbsPath = resolve122(projectDir, lottieRelPath);
472944
+ await mkdir5(dirname33(lottieAbsPath), { recursive: true });
472945
+ await copyFile6(sourceAbs, lottieAbsPath);
472946
+ lottieInput = {
472947
+ src: lottieRelPath,
472948
+ position: opts.lottie.position,
472949
+ scale: opts.lottie.scale,
472950
+ opacity: opts.lottie.opacity,
472951
+ loop: opts.lottie.loop
472952
+ };
472953
+ }
472772
472954
  const cfg = await loadVibeProjectConfig(projectDir);
472773
472955
  const fallback2 = cfg?.defaultSceneDuration ?? 5;
472774
472956
  const NARRATION_TAIL_BUFFER = 0.5;
@@ -472797,7 +472979,8 @@ async function executeSceneAdd(opts) {
472797
472979
  kicker: opts.kicker,
472798
472980
  imagePath: imageRelPath,
472799
472981
  audioPath: audioRelPath,
472800
- transcript: transcriptWords
472982
+ transcript: transcriptWords,
472983
+ lottie: lottieInput
472801
472984
  });
472802
472985
  await mkdir5(dirname33(scenePath), { recursive: true });
472803
472986
  await writeFile10(scenePath, sceneHtml, "utf-8");
@@ -472818,6 +473001,7 @@ async function executeSceneAdd(opts) {
472818
473001
  rootPath: relative5(process.cwd(), rootPath) || rootPath,
472819
473002
  audioPath: audioAbsPath ? relative5(process.cwd(), audioAbsPath) || audioAbsPath : void 0,
472820
473003
  imagePath: imageAbsPath ? relative5(process.cwd(), imageAbsPath) || imageAbsPath : void 0,
473004
+ lottiePath: lottieAbsPath ? relative5(process.cwd(), lottieAbsPath) || lottieAbsPath : void 0,
472821
473005
  transcriptPath: transcriptAbsPath ? relative5(process.cwd(), transcriptAbsPath) || transcriptAbsPath : void 0,
472822
473006
  transcriptWordCount
472823
473007
  };
@@ -474070,7 +474254,7 @@ var editMotionOverlayTool = defineTool({
474070
474254
  duration: external_exports.number().optional().describe("Overlay/render duration in seconds"),
474071
474255
  start: external_exports.number().optional().describe("Overlay start time in seconds"),
474072
474256
  style: external_exports.string().optional().describe("Style preset for generated overlays"),
474073
- model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-3.1-pro"]).optional().describe("LLM model for generated overlays"),
474257
+ model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-2.5-pro", "gemini-3.1-pro"]).optional().describe("LLM model for generated overlays"),
474074
474258
  understand: external_exports.enum(["auto", "off", "required"]).optional().describe("Analyze video before generated overlay (default: auto)"),
474075
474259
  understandingPrompt: external_exports.string().optional().describe("Custom prompt for video understanding"),
474076
474260
  position: external_exports.enum(["full", "center", "top-left", "top-right", "bottom-left", "bottom-right"]).optional().describe("Lottie overlay position"),
@@ -475785,7 +475969,7 @@ var inspectRenderTool = defineTool({
475785
475969
  outputPath: external_exports.string().optional().describe("Optional review report path. Defaults to <project>/review-report.json."),
475786
475970
  report: external_exports.boolean().optional().describe("Write review-report.json. Default true."),
475787
475971
  ai: external_exports.boolean().optional().describe("Also run Gemini video review and merge findings into review-report.json. Default false."),
475788
- model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant for ai review. Default flash."),
475972
+ model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant for ai review. Default flash."),
475789
475973
  dryRun: external_exports.boolean().optional().describe("Preview resolved inputs without probing video or calling Gemini.")
475790
475974
  }),
475791
475975
  async execute(args, ctx) {
@@ -475837,7 +476021,7 @@ var analyzeMediaTool = defineTool({
475837
476021
  schema: external_exports.object({
475838
476022
  source: external_exports.string().describe("Path to image/video or YouTube URL"),
475839
476023
  prompt: external_exports.string().describe("Analysis prompt (e.g., 'Describe the scene', 'Count people')"),
475840
- model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant (default: flash)"),
476024
+ model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant (default: flash)"),
475841
476025
  fps: external_exports.number().optional().describe("Frames per second for video sampling (default: 1)"),
475842
476026
  start: external_exports.number().optional().describe("Start time in seconds for video analysis"),
475843
476027
  end: external_exports.number().optional().describe("End time in seconds for video analysis"),
@@ -475865,7 +476049,7 @@ var analyzeVideoTool = defineTool({
475865
476049
  schema: external_exports.object({
475866
476050
  source: external_exports.string().describe("Path to video file"),
475867
476051
  prompt: external_exports.string().describe("Analysis prompt"),
475868
- model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant (default: flash)"),
476052
+ model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant (default: flash)"),
475869
476053
  fps: external_exports.number().optional().describe("Frames per second for sampling"),
475870
476054
  start: external_exports.number().optional().describe("Start time in seconds"),
475871
476055
  end: external_exports.number().optional().describe("End time in seconds"),
@@ -475895,7 +476079,7 @@ var analyzeReviewTool = defineTool({
475895
476079
  storyboardPath: external_exports.string().optional().describe("Path to storyboard.json for intent comparison"),
475896
476080
  autoApply: external_exports.boolean().optional().describe("Automatically apply suggested fixes (default: false)"),
475897
476081
  verify: external_exports.boolean().optional().describe("Re-review after applying fixes (default: false)"),
475898
- model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant (default: flash)"),
476082
+ model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant (default: flash)"),
475899
476083
  outputPath: external_exports.string().optional().describe("Output path for fixed video")
475900
476084
  }),
475901
476085
  async execute(args) {
@@ -475977,7 +476161,7 @@ var generateMotionTool = defineTool({
475977
476161
  "Analyze the base video with Gemini before generating motion graphics: auto, off, or required (default: auto)"
475978
476162
  ),
475979
476163
  understandingPrompt: external_exports.string().optional().describe("Custom prompt for video understanding when --video is provided"),
475980
- model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-3.1-pro"]).optional().describe("LLM model for code generation (default: sonnet)"),
476164
+ model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-2.5-pro", "gemini-3.1-pro"]).optional().describe("LLM model for code generation (default: sonnet)"),
475981
476165
  output: external_exports.string().optional().describe("Output path (TSX if code-only, MP4 if rendered)")
475982
476166
  }),
475983
476167
  async execute(args) {
@@ -476242,6 +476426,7 @@ var generateVideoTool = defineTool({
476242
476426
  "Video provider (default: seedance when FAL_API_KEY is configured, otherwise first configured provider)"
476243
476427
  ),
476244
476428
  image: external_exports.string().optional().describe("Reference image path for image-to-video"),
476429
+ endImage: external_exports.string().optional().describe("Ending frame image path for Seedance image-to-video"),
476245
476430
  refImages: external_exports.array(external_exports.string()).optional().describe("Reference images for Seedance reference-to-video"),
476246
476431
  refVideos: external_exports.array(external_exports.string()).optional().describe("Reference videos for Seedance reference-to-video"),
476247
476432
  refAudio: external_exports.array(external_exports.string()).optional().describe("Reference audio files for Seedance reference-to-video"),
@@ -476249,7 +476434,7 @@ var generateVideoTool = defineTool({
476249
476434
  ratio: external_exports.string().optional().describe("Aspect ratio: 16:9, 9:16, 1:1 (default: 16:9)"),
476250
476435
  mode: external_exports.string().optional().describe("Kling mode: std or pro"),
476251
476436
  negative: external_exports.string().optional().describe("Negative prompt (Seedance/Kling/Veo)"),
476252
- resolution: external_exports.string().optional().describe("Resolution: 720p, 1080p, 4k (Veo only)"),
476437
+ resolution: external_exports.string().optional().describe("Resolution: 480p, 720p, 1080p, or 4k depending on provider"),
476253
476438
  veoModel: external_exports.string().optional().describe("Veo model: 3.0, 3.1, 3.1-fast"),
476254
476439
  runwayModel: external_exports.string().optional().describe("Runway model: gen4.5, gen4_turbo"),
476255
476440
  seedanceModel: external_exports.string().optional().describe("Seedance variant: quality or fast (fal.ai only)"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/mcp-server",
3
- "version": "0.105.2",
3
+ "version": "0.106.0",
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.105.2",
61
- "@vibeframe/core": "0.105.2"
60
+ "@vibeframe/cli": "0.106.0",
61
+ "@vibeframe/core": "0.106.0"
62
62
  },
63
63
  "engines": {
64
64
  "node": ">=20"