@vibeframe/mcp-server 0.76.0 → 0.78.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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +51 -52
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -98,7 +98,7 @@ Tool names are MCP-side. Your host typically prefixes them (e.g. Claude shows th
98
98
 
99
99
  | Tool | Description |
100
100
  |------|-------------|
101
- | `scene_styles` | List the 8 vendored visual identities (Swiss Pulse, Data Drift, …) or fetch one |
101
+ | `scene_list_styles` | List the 8 vendored visual identities (Swiss Pulse, Data Drift, …) or fetch one |
102
102
  | `scene_add` | Append a beat (narration + backdrop + composed HTML) |
103
103
  | `scene_install_skill` | Install the Hyperframes skill bundle into a scene project |
104
104
  | `scene_lint` | Validate composition HTML against the visual identity |
package/dist/index.js CHANGED
@@ -7410,7 +7410,7 @@ function buildEmptyRootHtml(opts) {
7410
7410
  }
7411
7411
  function buildDesignMd(opts) {
7412
7412
  const { name, style } = opts;
7413
- const intro = style ? `Visual identity for **${name}**, scaffolded from the **${style.name}** style (after ${style.designer}). Customise freely \u2014 this file is the single source of truth for every scene's palette, typography, and motion.` : `Visual identity for **${name}**. Fill the sections below before authoring any scene HTML or generating any backdrop. Pick a named style with \`vibe scene styles\` if you want a credible starting point.`;
7413
+ const intro = style ? `Visual identity for **${name}**, scaffolded from the **${style.name}** style (after ${style.designer}). Customise freely \u2014 this file is the single source of truth for every scene's palette, typography, and motion.` : `Visual identity for **${name}**. Fill the sections below before authoring any scene HTML or generating any backdrop. Pick a named style with \`vibe scene list-styles\` if you want a credible starting point.`;
7414
7414
  const moodLine = style ? `**Mood:** ${style.mood} \xB7 **Best for:** ${style.bestFor}` : `**Mood:** _(one line \u2014 what should the viewer FEEL?)_`;
7415
7415
  const palette = style ? `${style.palette.map((c) => `- \`${c}\``).join("\n")}
7416
7416
 
@@ -7468,7 +7468,7 @@ ${avoid}
7468
7468
 
7469
7469
  ---
7470
7470
 
7471
- _Browse other named styles: \`vibe scene styles\`_
7471
+ _Browse other named styles: \`vibe scene list-styles\`_
7472
7472
  ${style ? `_This file was seeded by \`vibe scene init --visual-style "${style.name}"\`._` : `_Seed this file from a named style: \`vibe scene init <dir> --visual-style "<name>"\`._`}
7473
7473
  `;
7474
7474
  }
@@ -7534,7 +7534,7 @@ typography, motion, and transition rules. Both the agent-driven path and
7534
7534
  the fallback emit reference it; scenes that contradict DESIGN.md are
7535
7535
  rejected by the Hyperframes \`hyperframes\` skill.
7536
7536
 
7537
- Browse named styles: \`vibe scene styles\`. Re-seed from one with
7537
+ Browse named styles: \`vibe scene list-styles\`. Re-seed from one with
7538
7538
  \`vibe scene init . --visual-style "Swiss Pulse"\` (idempotent).
7539
7539
 
7540
7540
  ## Skills \u2014 USE THESE FIRST
@@ -18508,8 +18508,8 @@ var init_elevenlabs = __esm({
18508
18508
  "generate speech",
18509
18509
  "generate sound-effect",
18510
18510
  "generate music",
18511
- "audio voices",
18512
- "audio voice-clone",
18511
+ "audio list-voices",
18512
+ "audio clone-voice",
18513
18513
  "audio dub"
18514
18514
  ]
18515
18515
  });
@@ -452403,7 +452403,7 @@ var init_validate = __esm({
452403
452403
  import { resolve as resolve27, extname as extname7, basename as basename8 } from "node:path";
452404
452404
  import { existsSync as existsSync39 } from "node:fs";
452405
452405
  function registerEditCommands(aiCommand) {
452406
- aiCommand.command("silence-cut").alias("sc").description("Remove silent segments from video (FFmpeg default, or Gemini for smart detection)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-cut.<ext>)").option("-n, --noise <dB>", "Silence threshold in dB (default: -30)", "-30").option("-d, --min-duration <seconds>", "Minimum silence duration to cut (default: 0.5)", "0.5").option("--padding <seconds>", "Padding around non-silent segments (default: 0.1)", "0.1").option("--analyze-only", "Only detect silence, don't cut").option("--use-gemini", "Use Gemini Video Understanding for context-aware silence detection").option("-m, --model <model>", "Gemini model (default: flash)").option("--low-res", "Low resolution mode for longer videos (Gemini only)").option("-k, --api-key <key>", "Google API key override (or set GOOGLE_API_KEY env)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
452406
+ aiCommand.command("silence-cut").alias("sc").description("Remove silent segments from video (FFmpeg default, or Gemini for smart detection)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-cut.<ext>)").option("--noise <dB>", "Silence threshold in dB (default: -30)", "-30").option("-d, --min-duration <seconds>", "Minimum silence duration to cut (default: 0.5)", "0.5").option("--padding <seconds>", "Padding around non-silent segments (default: 0.1)", "0.1").option("--analyze-only", "Only detect silence, don't cut").option("--use-gemini", "Use Gemini Video Understanding for context-aware silence detection").option("-m, --model <model>", "Gemini model (default: flash)").option("--low-res", "Low resolution mode for longer videos (Gemini only)").option("-k, --api-key <key>", "Google API key override (or set GOOGLE_API_KEY env)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
452407
452407
  Examples:
452408
452408
  $ vibe edit silence-cut interview.mp4 -o clean.mp4
452409
452409
  $ vibe ed sc podcast.mp4 -o trimmed.mp4 -n -25 -d 1.0
@@ -452504,7 +452504,7 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
452504
452504
  exitWithError(apiError(`Silence cut failed: ${error instanceof Error ? error.message : String(error)}`, true));
452505
452505
  }
452506
452506
  });
452507
- aiCommand.command("caption").alias("cap").description("Transcribe and burn styled captions onto video (Whisper + FFmpeg)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-captioned.<ext>)").option("-s, --style <style>", "Caption style: minimal, bold, outline, karaoke (default: bold)", "bold").option("--font-size <pixels>", "Override auto-calculated font size").option("--color <color>", "Font color (default: white)", "white").option("-l, --language <lang>", "Language code for transcription (e.g., en, ko)").option("--position <pos>", "Caption position: top, center, bottom (default: bottom)", "bottom").option("-k, --api-key <key>", "OpenAI API key (or set OPENAI_API_KEY env)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
452507
+ aiCommand.command("caption").alias("cap").description("Transcribe and burn styled captions onto video (Whisper + FFmpeg)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-captioned.<ext>)").option("--style <style>", "Caption style: minimal, bold, outline, karaoke (default: bold)", "bold").option("--font-size <pixels>", "Override auto-calculated font size").option("--color <color>", "Font color (default: white)", "white").option("-l, --language <lang>", "Language code for transcription (e.g., en, ko)").option("--position <pos>", "Caption position: top, center, bottom (default: bottom)", "bottom").option("-k, --api-key <key>", "OpenAI API key (or set OPENAI_API_KEY env)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
452508
452508
  Examples:
452509
452509
  $ vibe edit caption video.mp4 -o captioned.mp4
452510
452510
  $ vibe ed cap video.mp4 -o out.mp4 -s bold --position top
@@ -452593,7 +452593,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
452593
452593
  exitWithError(apiError(`Caption failed: ${error instanceof Error ? error.message : String(error)}`, true));
452594
452594
  }
452595
452595
  });
452596
- aiCommand.command("noise-reduce").description("Remove background noise from audio/video using FFmpeg (no API key needed)").argument("<input>", "Audio or video file path").option("-o, --output <path>", "Output file path (default: <name>-denoised.<ext>)").option("-s, --strength <level>", "Noise reduction strength: low, medium, high (default: medium)", "medium").option("-n, --noise-floor <dB>", "Custom noise floor in dB (overrides strength preset)").option("--dry-run", "Preview parameters without executing").action(async (inputPath, options) => {
452596
+ aiCommand.command("noise-reduce").description("Remove background noise from audio/video using FFmpeg (no API key needed)").argument("<input>", "Audio or video file path").option("-o, --output <path>", "Output file path (default: <name>-denoised.<ext>)").option("--strength <level>", "Noise reduction strength: low, medium, high (default: medium)", "medium").option("--noise-floor <dB>", "Custom noise floor in dB (overrides strength preset)").option("--dry-run", "Preview parameters without executing").action(async (inputPath, options) => {
452597
452597
  const startedAt = Date.now();
452598
452598
  try {
452599
452599
  if (options.output) {
@@ -452731,7 +452731,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
452731
452731
  exitWithError(generalError(`Fade failed: ${error instanceof Error ? error.message : String(error)}`));
452732
452732
  }
452733
452733
  });
452734
- aiCommand.command("translate-srt").description("Translate SRT subtitle file to another language (Claude/OpenAI)").argument("<srt>", "SRT file path").option("-t, --target <language>", "Target language (e.g., ko, es, fr, ja, zh)").option("-o, --output <path>", "Output file path (default: <name>-<target>.srt)").option("-p, --provider <provider>", "Translation provider: claude, openai (default: claude)", "claude").option("--source <language>", "Source language (auto-detected if omitted)").option("-k, --api-key <key>", "API key (or set ANTHROPIC_API_KEY / OPENAI_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (srtPath, options) => {
452734
+ aiCommand.command("translate-srt").description("Translate SRT subtitle file to another language (Claude or OpenAI)").argument("<srt>", "SRT file path").option("--target <language>", "Target language (e.g., ko, es, fr, ja, zh)").option("-o, --output <path>", "Output file path (default: <name>-<target>.srt)").option("-p, --provider <provider>", "Translation provider: claude, openai (default: claude)", "claude").option("--source <language>", "Source language (auto-detected if omitted)").option("-k, --api-key <key>", "API key (or set ANTHROPIC_API_KEY / OPENAI_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (srtPath, options) => {
452735
452735
  const startedAt = Date.now();
452736
452736
  try {
452737
452737
  if (options.output) {
@@ -453740,7 +453740,7 @@ var init_execute_fill_gaps = __esm({
453740
453740
 
453741
453741
  // ../cli/src/commands/ai-fill-gaps.ts
453742
453742
  function registerFillGapsCommand(aiCommand) {
453743
- aiCommand.command("fill-gaps").description("Fill timeline gaps with AI-generated video (Kling image-to-video)").argument("<project>", "Project file path").option("-p, --provider <provider>", "AI provider (kling)", "kling").option("-o, --output <path>", "Output project path (default: overwrite)").option("-d, --dir <path>", "Directory to save generated videos").option("--prompt <text>", "Custom prompt for video generation").option("--dry-run", "Show gaps without generating").option("-m, --mode <mode>", "Generation mode: std or pro (Kling)", "std").option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1", "16:9").action(async (projectPath, options) => {
453743
+ aiCommand.command("fill-gaps").description("Fill timeline gaps with AI-generated video (Kling image-to-video)").argument("<project>", "Project file path").option("-p, --provider <provider>", "AI provider (kling)", "kling").option("-o, --output <path>", "Output project path (default: overwrite)").option("-d, --dir <path>", "Directory to save generated videos").option("--prompt <text>", "Custom prompt for video generation").option("--dry-run", "Show gaps without generating").option("--mode <mode>", "Generation mode: std or pro (Kling)", "std").option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1", "16:9").action(async (projectPath, options) => {
453744
453744
  try {
453745
453745
  if (options.output) {
453746
453746
  validateOutputPath(options.output);
@@ -454018,7 +454018,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454018
454018
  );
454019
454019
  registerEditCommands(editCommand);
454020
454020
  registerFillGapsCommand(editCommand);
454021
- editCommand.command("grade").description("Apply AI-generated color grading (Claude + FFmpeg)").argument("<video>", "Video file path").option("-s, --style <prompt>", "Style description (e.g., 'cinematic warm')").option("--preset <name>", "Built-in preset: film-noir, vintage, cinematic-warm, cool-tones, high-contrast, pastel, cyberpunk, horror").option("-o, --output <path>", "Output video file path").option("--analyze-only", "Show filter without applying").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454021
+ editCommand.command("grade").description("Apply AI-generated color grading (Claude + FFmpeg)").argument("<video>", "Video file path").option("--style <prompt>", "Style description (e.g., 'cinematic warm')").option("--preset <name>", "Built-in preset: film-noir, vintage, cinematic-warm, cool-tones, high-contrast, pastel, cyberpunk, horror").option("-o, --output <path>", "Output video file path").option("--analyze-only", "Show filter without applying").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454022
454022
  const startedAt = Date.now();
454023
454023
  try {
454024
454024
  if (options.style) rejectControlChars(options.style);
@@ -454106,7 +454106,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454106
454106
  exitWithError(apiError(`Color grading failed: ${error.message}`));
454107
454107
  }
454108
454108
  });
454109
- editCommand.command("text-overlay").description("Apply text overlays to video (FFmpeg drawtext)").argument("<video>", "Video file path").option("-t, --text <texts...>", "Text lines to overlay (repeat for multiple)").option("-s, --style <style>", "Overlay style: lower-third, center-bold, subtitle, minimal", "lower-third").option("--font-size <size>", "Font size in pixels (auto-calculated if omitted)").option("--font-color <color>", "Font color (default: white)", "white").option("--fade <seconds>", "Fade in/out duration in seconds", "0.3").option("--start <seconds>", "Start time in seconds", "0").option("--end <seconds>", "End time in seconds (default: video duration)").option("-o, --output <path>", "Output video file path").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454109
+ editCommand.command("text-overlay").description("Apply text overlays to video (FFmpeg drawtext)").argument("<video>", "Video file path").option("--text <texts...>", "Text lines to overlay (repeat for multiple)").option("--style <style>", "Overlay style: lower-third, center-bold, subtitle, minimal", "lower-third").option("--font-size <size>", "Font size in pixels (auto-calculated if omitted)").option("--font-color <color>", "Font color (default: white)", "white").option("--fade <seconds>", "Fade in/out duration in seconds", "0.3").option("--start <seconds>", "Start time in seconds", "0").option("--end <seconds>", "End time in seconds (default: video duration)").option("-o, --output <path>", "Output video file path").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454110
454110
  const startedAt = Date.now();
454111
454111
  try {
454112
454112
  if (!options.text || options.text.length === 0) {
@@ -454182,7 +454182,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454182
454182
  exitWithError(generalError(`Text overlay failed: ${msg}`));
454183
454183
  }
454184
454184
  });
454185
- editCommand.command("speed-ramp").description("Apply content-aware speed ramping (Whisper + Claude + FFmpeg)").argument("<video>", "Video file path").option("-o, --output <path>", "Output video file path").option("-s, --style <style>", "Style: dramatic, smooth, action", "dramatic").option("--min-speed <factor>", "Minimum speed factor", "0.25").option("--max-speed <factor>", "Maximum speed factor", "4.0").option("--analyze-only", "Show keyframes without applying").option("-l, --language <lang>", "Language code for transcription").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454185
+ editCommand.command("speed-ramp").description("Apply content-aware speed ramping (Whisper + Claude + FFmpeg)").argument("<video>", "Video file path").option("-o, --output <path>", "Output video file path").option("--style <style>", "Style: dramatic, smooth, action", "dramatic").option("--min-speed <factor>", "Minimum speed factor", "0.25").option("--max-speed <factor>", "Maximum speed factor", "4.0").option("--analyze-only", "Show keyframes without applying").option("-l, --language <lang>", "Language code for transcription").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454186
454186
  const startedAt = Date.now();
454187
454187
  try {
454188
454188
  if (options.output) {
@@ -454302,7 +454302,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454302
454302
  exitWithError(generalError(`Speed ramping failed: ${msg}`));
454303
454303
  }
454304
454304
  });
454305
- editCommand.command("reframe").description("Auto-reframe video to different aspect ratio (Claude Vision + FFmpeg)").argument("<video>", "Video file path").option("-a, --aspect <ratio>", "Target aspect ratio: 9:16, 1:1, 4:5", "9:16").option("-f, --focus <mode>", "Focus mode: auto, face, center, action", "auto").option("-o, --output <path>", "Output video file path").option("--analyze-only", "Show crop regions without applying").option("--keyframes <path>", "Export keyframes to JSON file").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454305
+ editCommand.command("reframe").description("Auto-reframe video to different aspect ratio (Claude Vision + FFmpeg)").argument("<video>", "Video file path").option("-a, --aspect <ratio>", "Target aspect ratio: 9:16, 1:1, 4:5", "9:16").option("--focus <mode>", "Focus mode: auto, face, center, action", "auto").option("-o, --output <path>", "Output video file path").option("--analyze-only", "Show crop regions without applying").option("--keyframes <path>", "Export keyframes to JSON file").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454306
454306
  const startedAt = Date.now();
454307
454307
  try {
454308
454308
  if (options.output) {
@@ -454449,7 +454449,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454449
454449
  exitWithError(generalError(`Reframe failed: ${msg}`));
454450
454450
  }
454451
454451
  });
454452
- editCommand.command("image").description("Edit image(s) using AI (Gemini/OpenAI/Grok)").argument("<images...>", "Input image file(s) followed by edit prompt").option("-p, --provider <provider>", "Provider: gemini (default), openai, grok", "gemini").option("-k, --api-key <key>", "API key (or set env variable)").option("-o, --output <path>", "Output file path", "edited.png").option("-m, --model <model>", "Model: flash/3.1-flash/latest/pro (Gemini only)", "flash").option("-r, --ratio <ratio>", "Output aspect ratio").option("-s, --size <resolution>", "Resolution: 1K, 2K, 4K (Gemini Pro only)").option("--dry-run", "Preview parameters without executing").action(async (args, options) => {
454452
+ editCommand.command("image").description("Edit image(s) using AI (Gemini, OpenAI, or Grok)").argument("<images...>", "Input image file(s) followed by edit prompt").option("-p, --provider <provider>", "Provider: gemini (default), openai, grok", "gemini").option("-k, --api-key <key>", "API key (or set env variable)").option("-o, --output <path>", "Output file path", "edited.png").option("-m, --model <model>", "Model: flash/3.1-flash/latest/pro (Gemini only)", "flash").option("-r, --ratio <ratio>", "Output aspect ratio").option("--size <resolution>", "Resolution: 1K, 2K, 4K (Gemini Pro only)").option("--dry-run", "Preview parameters without executing").action(async (args, options) => {
454453
454453
  const startedAt = Date.now();
454454
454454
  try {
454455
454455
  if (args.length < 2) {
@@ -454578,7 +454578,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454578
454578
  exitWithError(apiError(`Image editing failed: ${msg}`, true));
454579
454579
  }
454580
454580
  });
454581
- editCommand.command("interpolate").description("Create slow motion with frame interpolation (FFmpeg)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path").option("-f, --factor <number>", "Slow motion factor: 2, 4, or 8", "2").option("--fps <number>", "Target output FPS").option("--quality <mode>", "Quality: fast or quality", "quality").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454581
+ editCommand.command("interpolate").description("Create slow motion with frame interpolation (FFmpeg)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path").option("--factor <number>", "Slow motion factor: 2, 4, or 8", "2").option("--fps <number>", "Target output FPS").option("--mode <mode>", "Speed/quality tradeoff: fast or quality", "quality").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454582
454582
  const startedAt = Date.now();
454583
454583
  try {
454584
454584
  if (options.output) {
@@ -454599,7 +454599,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454599
454599
  videoPath: absPath,
454600
454600
  factor,
454601
454601
  fps: options.fps ? parseInt(options.fps) : void 0,
454602
- quality: options.quality
454602
+ mode: options.mode
454603
454603
  }
454604
454604
  }
454605
454605
  });
@@ -454622,7 +454622,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454622
454622
  const [num, den] = fpsOut.trim().split("/").map(Number);
454623
454623
  const originalFps = num / (den || 1);
454624
454624
  const targetFps = options.fps ? parseInt(options.fps) : originalFps * factor;
454625
- const mi = options.quality === "fast" ? "mi_mode=mci" : "mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1";
454625
+ const mi = options.mode === "fast" ? "mi_mode=mci" : "mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1";
454626
454626
  spinner2.text = `Interpolating frames (${originalFps.toFixed(1)} \u2192 ${targetFps}fps)...`;
454627
454627
  await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 6e5 });
454628
454628
  spinner2.succeed(source_default.green(`Created ${factor}x slow motion`));
@@ -454660,7 +454660,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454660
454660
  exitWithError(generalError(`Frame interpolation failed: ${msg}`));
454661
454661
  }
454662
454662
  });
454663
- editCommand.command("upscale-video").description("Upscale video resolution using AI or FFmpeg").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path").option("-s, --scale <factor>", "Scale factor: 2 or 4", "2").option("-m, --model <model>", "Model: real-esrgan, topaz", "real-esrgan").option("--ffmpeg", "Use FFmpeg lanczos (free, no API)").option("-k, --api-key <key>", "Replicate API token (or set REPLICATE_API_TOKEN env)").option("--no-wait", "Start processing and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454663
+ editCommand.command("upscale").description("Upscale video resolution using AI or FFmpeg").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path").option("--scale <factor>", "Scale factor: 2 or 4", "2").option("-m, --model <model>", "Model: real-esrgan, topaz", "real-esrgan").option("--ffmpeg", "Use FFmpeg lanczos (free, no API)").option("-k, --api-key <key>", "Replicate API token (or set REPLICATE_API_TOKEN env)").option("--no-wait", "Start processing and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
454664
454664
  const startedAt = Date.now();
454665
454665
  try {
454666
454666
  if (options.output) {
@@ -454673,7 +454673,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454673
454673
  }
454674
454674
  if (options.dryRun) {
454675
454675
  outputSuccess({
454676
- command: "edit upscale-video",
454676
+ command: "edit upscale",
454677
454677
  startedAt,
454678
454678
  dryRun: true,
454679
454679
  data: {
@@ -454709,7 +454709,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
454709
454709
  spinner3.succeed(source_default.green(`Upscaled to ${newWidth}x${newHeight}`));
454710
454710
  if (isJsonMode()) {
454711
454711
  outputSuccess({
454712
- command: "edit upscale-video",
454712
+ command: "edit upscale",
454713
454713
  startedAt,
454714
454714
  data: {
454715
454715
  dimensions: `${newWidth}x${newHeight}`,
@@ -455418,7 +455418,7 @@ Score each category 1-10. For fixable issues, provide an FFmpeg filter in autoFi
455418
455418
  return result;
455419
455419
  }
455420
455420
  function registerReviewCommand(aiCommand) {
455421
- aiCommand.command("review").description("Review video quality using Gemini AI and optionally auto-fix issues").argument("<video>", "Video file path").option("-s, --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) => {
455421
+ aiCommand.command("review").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) => {
455422
455422
  const startedAt = Date.now();
455423
455423
  try {
455424
455424
  if (options.output) {
@@ -455426,7 +455426,7 @@ function registerReviewCommand(aiCommand) {
455426
455426
  }
455427
455427
  if (options.dryRun) {
455428
455428
  outputSuccess({
455429
- command: "ai review",
455429
+ command: "inspect review",
455430
455430
  startedAt,
455431
455431
  dryRun: true,
455432
455432
  data: {
@@ -455704,7 +455704,7 @@ Use this image analysis to inform the color palette, typography placement, and o
455704
455704
  return { success: true, codePath, componentName: component.name, renderedPath: renderResult.outputPath };
455705
455705
  }
455706
455706
  function registerMotionCommand(aiCommand) {
455707
- aiCommand.command("motion").description("Generate motion graphics using Claude + Remotion (render & composite)").argument("<description>", "Natural language description of the motion graphic").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("-o, --output <path>", "Output file path", "motion.tsx").option("-d, --duration <sec>", "Duration in seconds", "5").option("-w, --width <px>", "Width in pixels", "1920").option("-h, --height <px>", "Height in pixels", "1080").option("--fps <fps>", "Frame rate", "30").option("-s, --style <style>", "Style preset: minimal, corporate, playful, cinematic").option("--render", "Render the generated code with Remotion (output .webm)").option("--video <path>", "Base video to composite the motion graphic onto").option("--image <path>", "Image to analyze with Gemini \u2014 color/mood fed into Claude prompt").option("--from-tsx <path>", "Refine an existing TSX file instead of generating from scratch").option("-m, --model <alias>", "LLM model: sonnet (default), opus, gemini, gemini-3.1-pro", "sonnet").option("--dry-run", "Preview parameters without executing").action(async (description, options) => {
455707
+ aiCommand.command("motion").description("Generate motion graphics using Claude + Remotion (render & composite)").argument("<description>", "Natural language description of the motion graphic").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("-o, --output <path>", "Output file path", "motion.tsx").option("-d, --duration <sec>", "Duration in seconds", "5").option("--width <px>", "Width in pixels", "1920").option("--height <px>", "Height in pixels", "1080").option("--fps <fps>", "Frame rate", "30").option("--style <style>", "Style preset: minimal, corporate, playful, cinematic").option("--render", "Render the generated code with Remotion (output .webm)").option("--video <path>", "Base video to composite the motion graphic onto").option("--image <path>", "Image to analyze with Gemini \u2014 color/mood fed into Claude prompt").option("--from-tsx <path>", "Refine an existing TSX file instead of generating from scratch").option("-m, --model <alias>", "LLM model: sonnet (default), opus, gemini, gemini-3.1-pro", "sonnet").option("--dry-run", "Preview parameters without executing").action(async (description, options) => {
455708
455708
  const startedAt = Date.now();
455709
455709
  try {
455710
455710
  if (options.output) {
@@ -456259,7 +456259,7 @@ async function executeStoryboard(options) {
456259
456259
  }
456260
456260
  }
456261
456261
  function registerStoryboardCommand(parent) {
456262
- parent.command("storyboard").description("Generate video storyboard from content using Claude").argument("<content>", "Content to analyze (text or file path)").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("-o, --output <path>", "Output JSON file path").option("-d, --duration <sec>", "Target total duration in seconds").option("-f, --file", "Treat content argument as file path").option("-c, --creativity <level>", "Creativity level: low (default, consistent) or high (varied, unexpected)", "low").option("--dry-run", "Preview parameters without executing").action(async (content, options) => {
456262
+ parent.command("storyboard").description("Generate video storyboard from content using Claude").argument("<content>", "Content to analyze (text or file path)").option("-k, --api-key <key>", "Anthropic API key (or set ANTHROPIC_API_KEY env)").option("-o, --output <path>", "Output JSON file path").option("-d, --duration <sec>", "Target total duration in seconds").option("--file", "Treat content argument as file path").option("--creativity <level>", "Creativity level: low (default, consistent) or high (varied, unexpected)", "low").option("--dry-run", "Preview parameters without executing").action(async (content, options) => {
456263
456263
  const startedAt = Date.now();
456264
456264
  try {
456265
456265
  rejectControlChars(content);
@@ -456464,7 +456464,7 @@ async function executeSpeech(options) {
456464
456464
  }
456465
456465
  }
456466
456466
  function registerSpeechCommand(parent) {
456467
- parent.command("speech").alias("tts").description("Generate speech from text using ElevenLabs").argument("[text]", "Text to convert to speech (interactive if omitted)").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-o, --output <path>", "Output audio file path", "output.mp3").option("-v, --voice <id>", "Voice ID (default: Rachel)", "21m00Tcm4TlvDq8ikWAM").option("--list-voices", "List available voices").option("--fit-duration <seconds>", "Speed up audio to fit target duration (via FFmpeg atempo)", parseFloat).option("--dry-run", "Preview parameters without executing").action(async (text, options) => {
456467
+ parent.command("speech").alias("tts").description("Generate speech from text using ElevenLabs").argument("[text]", "Text to convert to speech (interactive if omitted)").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-o, --output <path>", "Output audio file path", "output.mp3").option("--voice <id>", "Voice ID (default: Rachel)", "21m00Tcm4TlvDq8ikWAM").option("--list-voices", "List available voices").option("--fit-duration <seconds>", "Speed up audio to fit target duration (via FFmpeg atempo)", parseFloat).option("--dry-run", "Preview parameters without executing").action(async (text, options) => {
456468
456468
  const startedAt = Date.now();
456469
456469
  try {
456470
456470
  if (!text) {
@@ -456674,7 +456674,7 @@ async function executeMusic(options) {
456674
456674
  }
456675
456675
  }
456676
456676
  function registerMusicCommand(parent) {
456677
- parent.command("music").description("Generate background music from a text prompt (ElevenLabs or Replicate MusicGen)").argument("<prompt>", "Description of the music to generate").option("-p, --provider <provider>", "Provider: elevenlabs (default, up to 10min), replicate (MusicGen, max 30s)", "elevenlabs").option("-k, --api-key <key>", "API key (or set ELEVENLABS_API_KEY / REPLICATE_API_TOKEN env)").option("-d, --duration <seconds>", "Duration in seconds (elevenlabs: 3-600, replicate: 1-30)", "8").option("--instrumental", "Force instrumental music, no vocals (ElevenLabs only)").option("-m, --melody <file>", "Reference melody audio file for conditioning (Replicate only)").option("--model <model>", "Model variant (Replicate only): large, stereo-large, melody-large, stereo-melody-large", "stereo-large").option("-o, --output <path>", "Output audio file path", "music.mp3").option("--no-wait", "Don't wait for generation to complete (Replicate async mode)").option("--dry-run", "Preview parameters without executing").action(async (prompt3, options) => {
456677
+ parent.command("music").description("Generate background music from a text prompt (ElevenLabs or Replicate MusicGen)").argument("<prompt>", "Description of the music to generate").option("-p, --provider <provider>", "Provider: elevenlabs (default, up to 10min), replicate (MusicGen, max 30s)", "elevenlabs").option("-k, --api-key <key>", "API key (or set ELEVENLABS_API_KEY / REPLICATE_API_TOKEN env)").option("-d, --duration <seconds>", "Duration in seconds (elevenlabs: 3-600, replicate: 1-30)", "8").option("--instrumental", "Force instrumental music, no vocals (ElevenLabs only)").option("--melody <file>", "Reference melody audio file for conditioning (Replicate only)").option("--model <model>", "Model variant (Replicate only): large, stereo-large, melody-large, stereo-melody-large", "stereo-large").option("-o, --output <path>", "Output audio file path", "music.mp3").option("--no-wait", "Don't wait for generation to complete (Replicate async mode)").option("--dry-run", "Preview parameters without executing").action(async (prompt3, options) => {
456678
456678
  const startedAt = Date.now();
456679
456679
  try {
456680
456680
  rejectControlChars(prompt3);
@@ -456839,7 +456839,7 @@ import { resolve as resolve43, dirname as dirname26, basename as basename10, ext
456839
456839
  import { existsSync as existsSync47 } from "node:fs";
456840
456840
  import { writeFile as writeFile27, mkdir as mkdir19 } from "node:fs/promises";
456841
456841
  function registerThumbnailCommand(parent) {
456842
- 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("-s, --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) => {
456842
+ 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) => {
456843
456843
  const startedAt = Date.now();
456844
456844
  try {
456845
456845
  if (description) rejectControlChars(description);
@@ -457005,7 +457005,7 @@ function getStatusColor(status) {
457005
457005
  }
457006
457006
  }
457007
457007
  function registerVideoStatusCommand(parent) {
457008
- parent.command("video-status", { hidden: true }).description("Check video generation status (Grok, Runway, or Kling)").argument("<task-id>", "Task ID from video generation").option("-p, --provider <provider>", "Provider: grok, runway, kling", "grok").option("-k, --api-key <key>", "API key (or set XAI_API_KEY / RUNWAY_API_SECRET / KLING_API_KEY env)").option("-t, --type <type>", "Task type: text2video or image2video (Kling only)", "text2video").option("-w, --wait", "Wait for completion").option("-o, --output <path>", "Download video when complete").action(async (taskId, options) => {
457008
+ parent.command("video-status", { hidden: true }).description("Check video generation status (Grok, Runway, or Kling)").argument("<task-id>", "Task ID from video generation").option("-p, --provider <provider>", "Provider: grok, runway, kling", "grok").option("-k, --api-key <key>", "API key (or set XAI_API_KEY / RUNWAY_API_SECRET / KLING_API_KEY env)").option("--type <type>", "Task type: text2video or image2video (Kling only)", "text2video").option("--wait", "Wait for completion").option("-o, --output <path>", "Download video when complete").action(async (taskId, options) => {
457009
457009
  const startedAt = Date.now();
457010
457010
  try {
457011
457011
  const provider = (options.provider || "grok").toLowerCase();
@@ -457238,7 +457238,7 @@ var init_video_status = __esm({
457238
457238
  import { resolve as resolve45 } from "node:path";
457239
457239
  import { writeFile as writeFile29 } from "node:fs/promises";
457240
457240
  function registerVideoExtendCommand(parent) {
457241
- parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("-n, --negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast", "3.1").option("--no-wait", "Start extension and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (id, options) => {
457241
+ parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("--negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast", "3.1").option("--no-wait", "Start extension and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (id, options) => {
457242
457242
  const startedAt = Date.now();
457243
457243
  try {
457244
457244
  const provider = (options.provider || "kling").toLowerCase();
@@ -457521,7 +457521,7 @@ import { resolve as resolve46, dirname as dirname27 } from "node:path";
457521
457521
  import { fileURLToPath as fileURLToPath4 } from "node:url";
457522
457522
  import { writeFile as writeFile30, mkdir as mkdir20 } from "node:fs/promises";
457523
457523
  function registerImageCommand(parent) {
457524
- parent.command("image").alias("img").description("Generate image using AI (Gemini, OpenAI gpt-image, Grok, or Runway)").argument("[prompt]", "Image description prompt (interactive if omitted)").option("-p, --provider <provider>", "Provider: openai (default when OPENAI_API_KEY set), gemini, grok, runway").option("-k, --api-key <key>", "API key (or set env: OPENAI_API_KEY, GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path (downloads image)").option("-s, --size <size>", "Image size (openai: 1024x1024, 1536x1024, 1024x1536)", "1024x1024").option("-r, --ratio <ratio>", "Aspect ratio (gemini: 1:1, 1:4, 1:8, 4:1, 8:1, 16:9, 9:16, 3:4, 4:3, etc.)", "1:1").option("--quality <quality>", "Quality: standard, hd (openai only)", "standard").option("--style <style>", "Style: vivid, natural (openai only)", "vivid").option("-n, --count <n>", "Number of images to generate", "1").option("-m, --model <model>", "Model. Gemini: flash, 3.1-flash, latest, pro. OpenAI: 1.5 (default), 2 (gpt-image-2)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
457524
+ parent.command("image").alias("img").description("Generate image using AI (Gemini, OpenAI gpt-image, Grok, or Runway)").argument("[prompt]", "Image description prompt (interactive if omitted)").option("-p, --provider <provider>", "Provider: openai (default when OPENAI_API_KEY set), gemini, grok, runway").option("-k, --api-key <key>", "API key (or set env: OPENAI_API_KEY, GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path (downloads image)").option("--size <size>", "Image size (openai: 1024x1024, 1536x1024, 1024x1536)", "1024x1024").option("-r, --ratio <ratio>", "Aspect ratio (gemini: 1:1, 1:4, 1:8, 4:1, 8:1, 16:9, 9:16, 3:4, 4:3, etc.)", "1:1").option("--quality <quality>", "Quality: standard, hd (openai only)", "standard").option("--style <style>", "Style: vivid, natural (openai only)", "vivid").option("--count <n>", "Number of images to generate", "1").option("-m, --model <model>", "Model. Gemini: flash, 3.1-flash, latest, pro. OpenAI: 1.5 (default), 2 (gpt-image-2)").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
457525
457525
  Examples:
457526
457526
  $ vibe generate image "a sunset over the ocean" -o sunset.png
457527
457527
  $ vibe gen img "logo design" -o logo.png -p openai
@@ -459664,7 +459664,7 @@ function registerVideoCommand(parent) {
459664
459664
  "-d, --duration <sec>",
459665
459665
  "Duration in seconds. Seedance accepts 4-15 (`fal` alias supported); Kling accepts 5 or 10; Veo maps to 6 or 8.",
459666
459666
  "5"
459667
- ).option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1 (auto-detected from image if omitted)").option("-s, --seed <number>", "Random seed for reproducibility (Runway only)").option("-m, --mode <mode>", "Generation mode: std or pro (Kling only)", "std").option("--seedance-model <model>", "Seedance variant: quality or fast (fal.ai only)", "quality").option("-n, --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("--ref-images <paths...>", "Reference images for character consistency (Veo 3.1 only, max 3)").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("--runway-model <model>", "Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)", "gen4.5").option("--no-wait", "Start generation and return task ID without waiting").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
459667
+ ).option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1 (auto-detected from image if omitted)").option("--seed <number>", "Random seed for reproducibility (Runway only)").option("--mode <mode>", "Generation mode: std or pro (Kling only)", "std").option("--seedance-model <model>", "Seedance variant: quality or fast (fal.ai only)", "quality").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("--ref-images <paths...>", "Reference images for character consistency (Veo 3.1 only, max 3)").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("--runway-model <model>", "Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)", "gen4.5").option("--no-wait", "Start generation and return task ID without waiting").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
459668
459668
  Examples:
459669
459669
  $ vibe generate video "dancing cat" -o cat.mp4 # Seedance when FAL_KEY is set
459670
459670
  $ vibe gen vid "cinematic city timelapse" -o city.mp4 -p seedance # Seedance via fal.ai
@@ -460670,15 +460670,14 @@ var init_detect = __esm({
460670
460670
  "use strict";
460671
460671
  init_esm();
460672
460672
  init_source();
460673
- init_ora();
460674
460673
  init_engine();
460675
460674
  init_exec_safe();
460676
460675
  init_output();
460677
460676
  init_validate();
460678
460677
  detectCommand = new Command("detect").description("Auto-detect scenes, beats, and silences in media");
460679
- detectCommand.command("scenes").description("Detect scene changes in video").argument("<video>", "Video file path").option("-t, --threshold <value>", "Scene change threshold (0-1)", "0.3").option("-o, --output <path>", "Output JSON file with timestamps").option("-p, --project <path>", "Add scenes as clips to project").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
460678
+ detectCommand.command("scenes").description("Detect scene changes in video").argument("<video>", "Video file path").option("--threshold <value>", "Scene change threshold (0-1)", "0.3").option("-o, --output <path>", "Output JSON file with timestamps").option("--project <path>", "Add scenes as clips to project").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
460680
460679
  const startedAt = Date.now();
460681
- const spinner2 = ora("Detecting scenes...").start();
460680
+ const spinner2 = spinner("Detecting scenes...").start();
460682
460681
  try {
460683
460682
  if (options.output) {
460684
460683
  validateOutputPath(options.output);
@@ -460795,9 +460794,9 @@ var init_detect = __esm({
460795
460794
  exitWithError(generalError(`Scene detection failed: ${msg}`));
460796
460795
  }
460797
460796
  });
460798
- detectCommand.command("silence").description("Detect silence in audio/video").argument("<media>", "Media file path").option("-n, --noise <dB>", "Noise threshold in dB", "-30").option("-d, --duration <sec>", "Minimum silence duration", "0.5").option("-o, --output <path>", "Output JSON file with timestamps").option("--dry-run", "Preview parameters without executing").action(async (mediaPath, options) => {
460797
+ detectCommand.command("silence").description("Detect silence in audio/video").argument("<media>", "Media file path").option("--noise <dB>", "Noise threshold in dB", "-30").option("-d, --duration <sec>", "Minimum silence duration", "0.5").option("-o, --output <path>", "Output JSON file with timestamps").option("--dry-run", "Preview parameters without executing").action(async (mediaPath, options) => {
460799
460798
  const startedAt = Date.now();
460800
- const spinner2 = ora("Detecting silence...").start();
460799
+ const spinner2 = spinner("Detecting silence...").start();
460801
460800
  try {
460802
460801
  if (options.output) {
460803
460802
  validateOutputPath(options.output);
@@ -460883,7 +460882,7 @@ var init_detect = __esm({
460883
460882
  });
460884
460883
  detectCommand.command("beats").description("Detect beats in audio (for music sync)").argument("<audio>", "Audio file path").option("-o, --output <path>", "Output JSON file with timestamps").option("--dry-run", "Preview parameters without executing").action(async (audioPath, options) => {
460885
460884
  const startedAt = Date.now();
460886
- const spinner2 = ora("Detecting beats...").start();
460885
+ const spinner2 = spinner("Detecting beats...").start();
460887
460886
  try {
460888
460887
  if (options.output) {
460889
460888
  validateOutputPath(options.output);
@@ -462007,7 +462006,7 @@ function validatePreset(value) {
462007
462006
  }
462008
462007
  return value;
462009
462008
  }
462010
- var sceneCommand = new Command("scene").description("Lower-level scene authoring (add, lint, styles). For project flow use `vibe init` / `vibe build` / `vibe render`.").addHelpText("after", `
462009
+ var sceneCommand = new Command("scene").description("Lower-level scene authoring (add, lint, list-styles). For project flow use `vibe init` / `vibe build` / `vibe render`.").addHelpText("after", `
462011
462010
  Examples:
462012
462011
  $ vibe scene add intro --style announcement \\
462013
462012
  --headline "Welcome to VibeFrame" # Headline-only scene
@@ -462016,7 +462015,7 @@ Examples:
462016
462015
  $ vibe scene lint # Validate every scene against composition rules
462017
462016
  $ vibe scene lint --fix # Auto-fix mechanical issues (e.g. missing class="clip")
462018
462017
  $ vibe scene lint --json # Structured output for agent loops
462019
- $ vibe scene styles # Browse seed visual styles for DESIGN.md
462018
+ $ vibe scene list-styles # Browse seed visual styles for DESIGN.md
462020
462019
 
462021
462020
  For the project flow (init / build / render), use the top-level commands.
462022
462021
  The \`scene init\`, \`scene build\`, and \`scene render\` legacy aliases
@@ -462131,13 +462130,13 @@ sceneCommand.command("compose-prompts").description("Emit the per-beat compose p
462131
462130
  console.log();
462132
462131
  console.log(source_default.dim("Re-run with --json to get the full per-beat userPrompt + cues for direct consumption."));
462133
462132
  });
462134
- sceneCommand.command("styles").description("List vendored visual styles (or show one) for DESIGN.md seeding").argument("[name]", "Style name to inspect (omit to list all)").action((name) => {
462133
+ sceneCommand.command("list-styles").description("List vendored visual styles (or show one) for DESIGN.md seeding").argument("[name]", "Style name to inspect (omit to list all)").action((name) => {
462135
462134
  const startedAt = Date.now();
462136
462135
  if (!name) {
462137
462136
  const all = listVisualStyles();
462138
462137
  if (isJsonMode()) {
462139
462138
  outputSuccess({
462140
- command: "scene styles",
462139
+ command: "scene list-styles",
462141
462140
  startedAt,
462142
462141
  data: {
462143
462142
  count: all.length,
@@ -462161,7 +462160,7 @@ sceneCommand.command("styles").description("List vendored visual styles (or show
462161
462160
  );
462162
462161
  }
462163
462162
  console.log();
462164
- console.log(source_default.dim("Show details: "), source_default.cyan('vibe scene styles "<name>"'));
462163
+ console.log(source_default.dim("Show details: "), source_default.cyan('vibe scene list-styles "<name>"'));
462165
462164
  console.log(source_default.dim("Seed DESIGN.md:"), source_default.cyan('vibe scene init <dir> --visual-style "<name>"'));
462166
462165
  return;
462167
462166
  }
@@ -462177,7 +462176,7 @@ sceneCommand.command("styles").description("List vendored visual styles (or show
462177
462176
  }
462178
462177
  if (isJsonMode()) {
462179
462178
  outputSuccess({
462180
- command: "scene styles",
462179
+ command: "scene list-styles",
462181
462180
  startedAt,
462182
462181
  data: { style }
462183
462182
  });
@@ -462652,7 +462651,7 @@ var sceneStylesSchema = z.object({
462652
462651
  )
462653
462652
  });
462654
462653
  var sceneStylesTool = defineTool({
462655
- name: "scene_styles",
462654
+ name: "scene_list_styles",
462656
462655
  category: "scene",
462657
462656
  cost: "free",
462658
462657
  description: "List the 8 vendored visual identities available for `init --visual-style` (Swiss Pulse, Data Drift, \u2026) or, when `name` is provided, return the full DESIGN.md hard-gate body for one style. The DESIGN.md content is what the LLM uses as a non-negotiable visual rulebook during compose-scenes-with-skills.",
@@ -462663,7 +462662,7 @@ var sceneStylesTool = defineTool({
462663
462662
  if (!style) {
462664
462663
  return {
462665
462664
  success: false,
462666
- error: `Unknown visual style "${args.name}". Run scene_styles with no name to list all 8.`
462665
+ error: `Unknown visual style "${args.name}". Run scene_list_styles with no name to list all 8.`
462667
462666
  };
462668
462667
  }
462669
462668
  return {
@@ -462703,7 +462702,7 @@ var sceneStylesTool = defineTool({
462703
462702
  (s) => ` \u2022 ${s.name} (${s.slug}) \u2014 ${s.mood}; best for ${s.bestFor}`
462704
462703
  ),
462705
462704
  ``,
462706
- `Run scene_styles { name: "<slug>" } to fetch the full DESIGN.md hard-gate body for one style.`
462705
+ `Run scene_list_styles { name: "<slug>" } to fetch the full DESIGN.md hard-gate body for one style.`
462707
462706
  ]
462708
462707
  };
462709
462708
  }
@@ -466061,11 +466060,11 @@ async function runExport(projectPath, outputPath, options = {}) {
466061
466060
  };
466062
466061
  }
466063
466062
  }
466064
- var exportCommand = new Command("export").description("Export project to video file").argument("<project>", "Project file path").option("-o, --output <path>", "Output file path").option("-f, --format <format>", "Output format (mp4, webm, mov, gif)", "mp4").option(
466065
- "-p, --preset <preset>",
466063
+ var exportCommand = new Command("export").description("Export project to video file").argument("<project>", "Project file path").option("-o, --output <path>", "Output file path").option("--format <format>", "Output format (mp4, webm, mov, gif)", "mp4").option(
466064
+ "--preset <preset>",
466066
466065
  "Quality preset (draft, standard, high, ultra)",
466067
466066
  "standard"
466068
- ).option("-y, --overwrite", "Overwrite output file if exists", false).option("-g, --gap-fill <strategy>", "Gap filling strategy (black, extend)", "extend").option("--backend <name>", "Render backend: ffmpeg (default) | hyperframes (experimental)", "ffmpeg").option("--bitrate <value>", "Video bitrate (e.g. 5000k, 8M) \u2014 overrides preset").option("--fps <number>", "Frames per second (e.g. 24, 30, 60) \u2014 overrides preset").option("--resolution <WxH>", "Output resolution (e.g. 1920x1080) \u2014 overrides preset").option("--codec <codec>", "Video codec: h264 (default) | h265 | vp9 \u2014 overrides preset").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
466067
+ ).option("--overwrite", "Overwrite output file if exists", false).option("--gap-fill <strategy>", "Gap filling strategy (black, extend)", "extend").option("--backend <name>", "Render backend: ffmpeg (default) | hyperframes (experimental)", "ffmpeg").option("--bitrate <value>", "Video bitrate (e.g. 5000k, 8M) \u2014 overrides preset").option("--fps <number>", "Frames per second (e.g. 24, 30, 60) \u2014 overrides preset").option("--resolution <WxH>", "Output resolution (e.g. 1920x1080) \u2014 overrides preset").option("--codec <codec>", "Video codec: h264 (default) | h265 | vp9 \u2014 overrides preset").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
466069
466068
  Examples:
466070
466069
  $ vibe export project.vibe.json -o output.mp4
466071
466070
  $ vibe export project.vibe.json -o output.mp4 -p high -y
@@ -467728,7 +467727,7 @@ Safe to invoke on user-provided projects.
467728
467727
 
467729
467728
  \`\`\`bash
467730
467729
  vibe scene init <dir> [-r 16:9|9:16|1:1|4:5] [-d <sec>] [--visual-style "<name>"]
467731
- vibe scene styles [<name>] # list / show vendored visual identities
467730
+ vibe scene list-styles [<name>] # list / show vendored visual identities
467732
467731
  vibe scene install-skill [<dir>] [--host all] # retroactive composition-rules install
467733
467732
  vibe scene add <name> --style <preset> [...]
467734
467733
  vibe scene compose-prompts [<dir>] [--beat <id>] # H2: emit plan, no LLM call
@@ -467916,7 +467915,7 @@ var META = {
467916
467915
  ],
467917
467916
  relatedCommands: [
467918
467917
  "vibe init",
467919
- "vibe scene styles",
467918
+ "vibe scene list-styles",
467920
467919
  "vibe scene install-skill",
467921
467920
  "vibe scene compose-prompts",
467922
467921
  "vibe build",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/mcp-server",
3
- "version": "0.76.0",
3
+ "version": "0.78.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/core": "0.76.0",
61
- "@vibeframe/cli": "0.76.0"
60
+ "@vibeframe/cli": "0.78.0",
61
+ "@vibeframe/core": "0.78.0"
62
62
  },
63
63
  "engines": {
64
64
  "node": ">=20"