@vibeframe/cli 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.
- package/dist/index.js +152 -97
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -18722,8 +18722,8 @@ var init_elevenlabs = __esm({
|
|
|
18722
18722
|
"generate speech",
|
|
18723
18723
|
"generate sound-effect",
|
|
18724
18724
|
"generate music",
|
|
18725
|
-
"audio voices",
|
|
18726
|
-
"audio voice
|
|
18725
|
+
"audio list-voices",
|
|
18726
|
+
"audio clone-voice",
|
|
18727
18727
|
"audio dub"
|
|
18728
18728
|
]
|
|
18729
18729
|
});
|
|
@@ -25999,7 +25999,7 @@ function buildEmptyRootHtml(opts) {
|
|
|
25999
25999
|
}
|
|
26000
26000
|
function buildDesignMd(opts) {
|
|
26001
26001
|
const { name, style } = opts;
|
|
26002
|
-
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.`;
|
|
26002
|
+
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.`;
|
|
26003
26003
|
const moodLine = style ? `**Mood:** ${style.mood} \xB7 **Best for:** ${style.bestFor}` : `**Mood:** _(one line \u2014 what should the viewer FEEL?)_`;
|
|
26004
26004
|
const palette = style ? `${style.palette.map((c) => `- \`${c}\``).join("\n")}
|
|
26005
26005
|
|
|
@@ -26057,7 +26057,7 @@ ${avoid}
|
|
|
26057
26057
|
|
|
26058
26058
|
---
|
|
26059
26059
|
|
|
26060
|
-
_Browse other named styles: \`vibe scene styles\`_
|
|
26060
|
+
_Browse other named styles: \`vibe scene list-styles\`_
|
|
26061
26061
|
${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>"\`._`}
|
|
26062
26062
|
`;
|
|
26063
26063
|
}
|
|
@@ -26123,7 +26123,7 @@ typography, motion, and transition rules. Both the agent-driven path and
|
|
|
26123
26123
|
the fallback emit reference it; scenes that contradict DESIGN.md are
|
|
26124
26124
|
rejected by the Hyperframes \`hyperframes\` skill.
|
|
26125
26125
|
|
|
26126
|
-
Browse named styles: \`vibe scene styles\`. Re-seed from one with
|
|
26126
|
+
Browse named styles: \`vibe scene list-styles\`. Re-seed from one with
|
|
26127
26127
|
\`vibe scene init . --visual-style "Swiss Pulse"\` (idempotent).
|
|
26128
26128
|
|
|
26129
26129
|
## Skills \u2014 USE THESE FIRST
|
|
@@ -29396,7 +29396,7 @@ var init_scene = __esm({
|
|
|
29396
29396
|
init_agent_host_detect();
|
|
29397
29397
|
init_install_skill();
|
|
29398
29398
|
init_compose_prompts();
|
|
29399
|
-
sceneCommand = new Command("scene").description("Lower-level scene authoring (add, lint, styles). For project flow use `vibe init` / `vibe build` / `vibe render`.").addHelpText("after", `
|
|
29399
|
+
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", `
|
|
29400
29400
|
Examples:
|
|
29401
29401
|
$ vibe scene add intro --style announcement \\
|
|
29402
29402
|
--headline "Welcome to VibeFrame" # Headline-only scene
|
|
@@ -29405,7 +29405,7 @@ Examples:
|
|
|
29405
29405
|
$ vibe scene lint # Validate every scene against composition rules
|
|
29406
29406
|
$ vibe scene lint --fix # Auto-fix mechanical issues (e.g. missing class="clip")
|
|
29407
29407
|
$ vibe scene lint --json # Structured output for agent loops
|
|
29408
|
-
$ vibe scene styles # Browse seed visual styles for DESIGN.md
|
|
29408
|
+
$ vibe scene list-styles # Browse seed visual styles for DESIGN.md
|
|
29409
29409
|
|
|
29410
29410
|
For the project flow (init / build / render), use the top-level commands.
|
|
29411
29411
|
The \`scene init\`, \`scene build\`, and \`scene render\` legacy aliases
|
|
@@ -29520,13 +29520,13 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
29520
29520
|
console.log();
|
|
29521
29521
|
console.log(source_default.dim("Re-run with --json to get the full per-beat userPrompt + cues for direct consumption."));
|
|
29522
29522
|
});
|
|
29523
|
-
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) => {
|
|
29523
|
+
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) => {
|
|
29524
29524
|
const startedAt = Date.now();
|
|
29525
29525
|
if (!name) {
|
|
29526
29526
|
const all = listVisualStyles();
|
|
29527
29527
|
if (isJsonMode()) {
|
|
29528
29528
|
outputSuccess({
|
|
29529
|
-
command: "scene styles",
|
|
29529
|
+
command: "scene list-styles",
|
|
29530
29530
|
startedAt,
|
|
29531
29531
|
data: {
|
|
29532
29532
|
count: all.length,
|
|
@@ -29550,7 +29550,7 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
29550
29550
|
);
|
|
29551
29551
|
}
|
|
29552
29552
|
console.log();
|
|
29553
|
-
console.log(source_default.dim("Show details: "), source_default.cyan('vibe scene styles "<name>"'));
|
|
29553
|
+
console.log(source_default.dim("Show details: "), source_default.cyan('vibe scene list-styles "<name>"'));
|
|
29554
29554
|
console.log(source_default.dim("Seed DESIGN.md:"), source_default.cyan('vibe scene init <dir> --visual-style "<name>"'));
|
|
29555
29555
|
return;
|
|
29556
29556
|
}
|
|
@@ -29566,7 +29566,7 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
29566
29566
|
}
|
|
29567
29567
|
if (isJsonMode()) {
|
|
29568
29568
|
outputSuccess({
|
|
29569
|
-
command: "scene styles",
|
|
29569
|
+
command: "scene list-styles",
|
|
29570
29570
|
startedAt,
|
|
29571
29571
|
data: { style }
|
|
29572
29572
|
});
|
|
@@ -30703,7 +30703,7 @@ Use this image analysis to inform the color palette, typography placement, and o
|
|
|
30703
30703
|
return { success: true, codePath, componentName: component.name, renderedPath: renderResult.outputPath };
|
|
30704
30704
|
}
|
|
30705
30705
|
function registerMotionCommand(aiCommand) {
|
|
30706
|
-
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("
|
|
30706
|
+
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) => {
|
|
30707
30707
|
const startedAt = Date.now();
|
|
30708
30708
|
try {
|
|
30709
30709
|
if (options.output) {
|
|
@@ -31307,7 +31307,7 @@ async function executeStoryboard(options) {
|
|
|
31307
31307
|
}
|
|
31308
31308
|
}
|
|
31309
31309
|
function registerStoryboardCommand(parent) {
|
|
31310
|
-
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("
|
|
31310
|
+
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) => {
|
|
31311
31311
|
const startedAt = Date.now();
|
|
31312
31312
|
try {
|
|
31313
31313
|
rejectControlChars(content);
|
|
@@ -31625,7 +31625,7 @@ async function executeSpeech(options) {
|
|
|
31625
31625
|
}
|
|
31626
31626
|
}
|
|
31627
31627
|
function registerSpeechCommand(parent) {
|
|
31628
|
-
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("
|
|
31628
|
+
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) => {
|
|
31629
31629
|
const startedAt = Date.now();
|
|
31630
31630
|
try {
|
|
31631
31631
|
if (!text) {
|
|
@@ -31835,7 +31835,7 @@ async function executeMusic(options) {
|
|
|
31835
31835
|
}
|
|
31836
31836
|
}
|
|
31837
31837
|
function registerMusicCommand(parent) {
|
|
31838
|
-
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("
|
|
31838
|
+
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) => {
|
|
31839
31839
|
const startedAt = Date.now();
|
|
31840
31840
|
try {
|
|
31841
31841
|
rejectControlChars(prompt3);
|
|
@@ -32265,7 +32265,7 @@ import { resolve as resolve19, dirname as dirname6, basename as basename3, extna
|
|
|
32265
32265
|
import { existsSync as existsSync12 } from "node:fs";
|
|
32266
32266
|
import { writeFile as writeFile18, mkdir as mkdir9 } from "node:fs/promises";
|
|
32267
32267
|
function registerThumbnailCommand(parent) {
|
|
32268
|
-
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("
|
|
32268
|
+
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) => {
|
|
32269
32269
|
const startedAt = Date.now();
|
|
32270
32270
|
try {
|
|
32271
32271
|
if (description) rejectControlChars(description);
|
|
@@ -32431,7 +32431,7 @@ function getStatusColor(status) {
|
|
|
32431
32431
|
}
|
|
32432
32432
|
}
|
|
32433
32433
|
function registerVideoStatusCommand(parent) {
|
|
32434
|
-
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("
|
|
32434
|
+
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) => {
|
|
32435
32435
|
const startedAt = Date.now();
|
|
32436
32436
|
try {
|
|
32437
32437
|
const provider = (options.provider || "grok").toLowerCase();
|
|
@@ -32664,7 +32664,7 @@ var init_video_status = __esm({
|
|
|
32664
32664
|
import { resolve as resolve21 } from "node:path";
|
|
32665
32665
|
import { writeFile as writeFile20 } from "node:fs/promises";
|
|
32666
32666
|
function registerVideoExtendCommand(parent) {
|
|
32667
|
-
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("
|
|
32667
|
+
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) => {
|
|
32668
32668
|
const startedAt = Date.now();
|
|
32669
32669
|
try {
|
|
32670
32670
|
const provider = (options.provider || "kling").toLowerCase();
|
|
@@ -32947,7 +32947,7 @@ import { resolve as resolve22, dirname as dirname7 } from "node:path";
|
|
|
32947
32947
|
import { fileURLToPath } from "node:url";
|
|
32948
32948
|
import { writeFile as writeFile21, mkdir as mkdir10 } from "node:fs/promises";
|
|
32949
32949
|
function registerImageCommand(parent) {
|
|
32950
|
-
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("
|
|
32950
|
+
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", `
|
|
32951
32951
|
Examples:
|
|
32952
32952
|
$ vibe generate image "a sunset over the ocean" -o sunset.png
|
|
32953
32953
|
$ vibe gen img "logo design" -o logo.png -p openai
|
|
@@ -35090,7 +35090,7 @@ function registerVideoCommand(parent) {
|
|
|
35090
35090
|
"-d, --duration <sec>",
|
|
35091
35091
|
"Duration in seconds. Seedance accepts 4-15 (`fal` alias supported); Kling accepts 5 or 10; Veo maps to 6 or 8.",
|
|
35092
35092
|
"5"
|
|
35093
|
-
).option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1 (auto-detected from image if omitted)").option("
|
|
35093
|
+
).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", `
|
|
35094
35094
|
Examples:
|
|
35095
35095
|
$ vibe generate video "dancing cat" -o cat.mp4 # Seedance when FAL_KEY is set
|
|
35096
35096
|
$ vibe gen vid "cinematic city timelapse" -o city.mp4 -p seedance # Seedance via fal.ai
|
|
@@ -36925,7 +36925,7 @@ var init_ai_edit = __esm({
|
|
|
36925
36925
|
import { resolve as resolve27, extname as extname5, basename as basename6 } from "node:path";
|
|
36926
36926
|
import { existsSync as existsSync21 } from "node:fs";
|
|
36927
36927
|
function registerEditCommands(aiCommand) {
|
|
36928
|
-
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("
|
|
36928
|
+
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", `
|
|
36929
36929
|
Examples:
|
|
36930
36930
|
$ vibe edit silence-cut interview.mp4 -o clean.mp4
|
|
36931
36931
|
$ vibe ed sc podcast.mp4 -o trimmed.mp4 -n -25 -d 1.0
|
|
@@ -37026,7 +37026,7 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
|
|
|
37026
37026
|
exitWithError(apiError(`Silence cut failed: ${error instanceof Error ? error.message : String(error)}`, true));
|
|
37027
37027
|
}
|
|
37028
37028
|
});
|
|
37029
|
-
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("
|
|
37029
|
+
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", `
|
|
37030
37030
|
Examples:
|
|
37031
37031
|
$ vibe edit caption video.mp4 -o captioned.mp4
|
|
37032
37032
|
$ vibe ed cap video.mp4 -o out.mp4 -s bold --position top
|
|
@@ -37115,7 +37115,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
37115
37115
|
exitWithError(apiError(`Caption failed: ${error instanceof Error ? error.message : String(error)}`, true));
|
|
37116
37116
|
}
|
|
37117
37117
|
});
|
|
37118
|
-
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("
|
|
37118
|
+
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) => {
|
|
37119
37119
|
const startedAt = Date.now();
|
|
37120
37120
|
try {
|
|
37121
37121
|
if (options.output) {
|
|
@@ -37253,7 +37253,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
37253
37253
|
exitWithError(generalError(`Fade failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
37254
37254
|
}
|
|
37255
37255
|
});
|
|
37256
|
-
aiCommand.command("translate-srt").description("Translate SRT subtitle file to another language (Claude
|
|
37256
|
+
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) => {
|
|
37257
37257
|
const startedAt = Date.now();
|
|
37258
37258
|
try {
|
|
37259
37259
|
if (options.output) {
|
|
@@ -37919,7 +37919,7 @@ var init_execute_fill_gaps = __esm({
|
|
|
37919
37919
|
|
|
37920
37920
|
// src/commands/ai-fill-gaps.ts
|
|
37921
37921
|
function registerFillGapsCommand(aiCommand) {
|
|
37922
|
-
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("
|
|
37922
|
+
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) => {
|
|
37923
37923
|
try {
|
|
37924
37924
|
if (options.output) {
|
|
37925
37925
|
validateOutputPath(options.output);
|
|
@@ -38197,7 +38197,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38197
38197
|
);
|
|
38198
38198
|
registerEditCommands(editCommand);
|
|
38199
38199
|
registerFillGapsCommand(editCommand);
|
|
38200
|
-
editCommand.command("grade").description("Apply AI-generated color grading (Claude + FFmpeg)").argument("<video>", "Video file path").option("
|
|
38200
|
+
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) => {
|
|
38201
38201
|
const startedAt = Date.now();
|
|
38202
38202
|
try {
|
|
38203
38203
|
if (options.style) rejectControlChars(options.style);
|
|
@@ -38285,7 +38285,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38285
38285
|
exitWithError(apiError(`Color grading failed: ${error.message}`));
|
|
38286
38286
|
}
|
|
38287
38287
|
});
|
|
38288
|
-
editCommand.command("text-overlay").description("Apply text overlays to video (FFmpeg drawtext)").argument("<video>", "Video file path").option("
|
|
38288
|
+
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) => {
|
|
38289
38289
|
const startedAt = Date.now();
|
|
38290
38290
|
try {
|
|
38291
38291
|
if (!options.text || options.text.length === 0) {
|
|
@@ -38361,7 +38361,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38361
38361
|
exitWithError(generalError(`Text overlay failed: ${msg}`));
|
|
38362
38362
|
}
|
|
38363
38363
|
});
|
|
38364
|
-
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("
|
|
38364
|
+
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) => {
|
|
38365
38365
|
const startedAt = Date.now();
|
|
38366
38366
|
try {
|
|
38367
38367
|
if (options.output) {
|
|
@@ -38481,7 +38481,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38481
38481
|
exitWithError(generalError(`Speed ramping failed: ${msg}`));
|
|
38482
38482
|
}
|
|
38483
38483
|
});
|
|
38484
|
-
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("
|
|
38484
|
+
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) => {
|
|
38485
38485
|
const startedAt = Date.now();
|
|
38486
38486
|
try {
|
|
38487
38487
|
if (options.output) {
|
|
@@ -38628,7 +38628,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38628
38628
|
exitWithError(generalError(`Reframe failed: ${msg}`));
|
|
38629
38629
|
}
|
|
38630
38630
|
});
|
|
38631
|
-
editCommand.command("image").description("Edit image(s) using AI (Gemini
|
|
38631
|
+
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) => {
|
|
38632
38632
|
const startedAt = Date.now();
|
|
38633
38633
|
try {
|
|
38634
38634
|
if (args.length < 2) {
|
|
@@ -38757,7 +38757,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38757
38757
|
exitWithError(apiError(`Image editing failed: ${msg}`, true));
|
|
38758
38758
|
}
|
|
38759
38759
|
});
|
|
38760
|
-
editCommand.command("interpolate").description("Create slow motion with frame interpolation (FFmpeg)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path").option("
|
|
38760
|
+
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) => {
|
|
38761
38761
|
const startedAt = Date.now();
|
|
38762
38762
|
try {
|
|
38763
38763
|
if (options.output) {
|
|
@@ -38778,7 +38778,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38778
38778
|
videoPath: absPath,
|
|
38779
38779
|
factor,
|
|
38780
38780
|
fps: options.fps ? parseInt(options.fps) : void 0,
|
|
38781
|
-
|
|
38781
|
+
mode: options.mode
|
|
38782
38782
|
}
|
|
38783
38783
|
}
|
|
38784
38784
|
});
|
|
@@ -38801,7 +38801,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38801
38801
|
const [num, den] = fpsOut.trim().split("/").map(Number);
|
|
38802
38802
|
const originalFps = num / (den || 1);
|
|
38803
38803
|
const targetFps = options.fps ? parseInt(options.fps) : originalFps * factor;
|
|
38804
|
-
const mi = options.
|
|
38804
|
+
const mi = options.mode === "fast" ? "mi_mode=mci" : "mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1";
|
|
38805
38805
|
spinner2.text = `Interpolating frames (${originalFps.toFixed(1)} \u2192 ${targetFps}fps)...`;
|
|
38806
38806
|
await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 6e5 });
|
|
38807
38807
|
spinner2.succeed(source_default.green(`Created ${factor}x slow motion`));
|
|
@@ -38839,7 +38839,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38839
38839
|
exitWithError(generalError(`Frame interpolation failed: ${msg}`));
|
|
38840
38840
|
}
|
|
38841
38841
|
});
|
|
38842
|
-
editCommand.command("upscale
|
|
38842
|
+
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) => {
|
|
38843
38843
|
const startedAt = Date.now();
|
|
38844
38844
|
try {
|
|
38845
38845
|
if (options.output) {
|
|
@@ -38852,7 +38852,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38852
38852
|
}
|
|
38853
38853
|
if (options.dryRun) {
|
|
38854
38854
|
outputSuccess({
|
|
38855
|
-
command: "edit upscale
|
|
38855
|
+
command: "edit upscale",
|
|
38856
38856
|
startedAt,
|
|
38857
38857
|
dryRun: true,
|
|
38858
38858
|
data: {
|
|
@@ -38888,7 +38888,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
38888
38888
|
spinner3.succeed(source_default.green(`Upscaled to ${newWidth}x${newHeight}`));
|
|
38889
38889
|
if (isJsonMode()) {
|
|
38890
38890
|
outputSuccess({
|
|
38891
|
-
command: "edit upscale
|
|
38891
|
+
command: "edit upscale",
|
|
38892
38892
|
startedAt,
|
|
38893
38893
|
data: {
|
|
38894
38894
|
dimensions: `${newWidth}x${newHeight}`,
|
|
@@ -39332,7 +39332,7 @@ Score each category 1-10. For fixable issues, provide an FFmpeg filter in autoFi
|
|
|
39332
39332
|
return result;
|
|
39333
39333
|
}
|
|
39334
39334
|
function registerReviewCommand(aiCommand) {
|
|
39335
|
-
aiCommand.command("review").description("Review video quality using Gemini AI and optionally auto-fix issues").argument("<
|
|
39335
|
+
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) => {
|
|
39336
39336
|
const startedAt = Date.now();
|
|
39337
39337
|
try {
|
|
39338
39338
|
if (options.output) {
|
|
@@ -39340,7 +39340,7 @@ function registerReviewCommand(aiCommand) {
|
|
|
39340
39340
|
}
|
|
39341
39341
|
if (options.dryRun) {
|
|
39342
39342
|
outputSuccess({
|
|
39343
|
-
command: "
|
|
39343
|
+
command: "inspect review",
|
|
39344
39344
|
startedAt,
|
|
39345
39345
|
dryRun: true,
|
|
39346
39346
|
data: {
|
|
@@ -39884,7 +39884,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
39884
39884
|
}
|
|
39885
39885
|
}
|
|
39886
39886
|
function registerHighlightsCommands(aiCommand) {
|
|
39887
|
-
aiCommand.command("highlights").description("Extract highlights from long-form video/audio content").argument("<media>", "Video or audio file path").option("-o, --output <path>", "Output JSON file with highlights").option("--project <path>", "Create project with highlight clips").option("-d, --duration <seconds>", "Target highlight reel duration", "60").option("
|
|
39887
|
+
aiCommand.command("highlights").description("Extract highlights from long-form video/audio content").argument("<media>", "Video or audio file path").option("-o, --output <path>", "Output JSON file with highlights").option("--project <path>", "Create project with highlight clips").option("-d, --duration <seconds>", "Target highlight reel duration", "60").option("--count <number>", "Maximum number of highlights").option("--threshold <value>", "Confidence threshold (0-1)", "0.7").option("--criteria <type>", "Selection criteria: emotional | informative | funny | all", "all").option("-l, --language <lang>", "Language code for transcription (e.g., en, ko)").option("--use-gemini", "Use Gemini Video Understanding for enhanced visual+audio analysis").option("--low-res", "Use low resolution mode for longer videos (Gemini only)").option("--dry-run", "Preview parameters without executing").action(async (mediaPath, options) => {
|
|
39888
39888
|
const startedAt = Date.now();
|
|
39889
39889
|
try {
|
|
39890
39890
|
if (options.output) {
|
|
@@ -40185,7 +40185,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
40185
40185
|
exitWithError(apiError(`Highlight extraction failed: ${error instanceof Error ? error.message : String(error)}`, true));
|
|
40186
40186
|
}
|
|
40187
40187
|
});
|
|
40188
|
-
aiCommand.command("auto-shorts").alias("shorts").description("Auto-generate shorts from long-form video").argument("<video>", "Video file path").option("-o, --output <path>", "Output file (single) or directory (multiple)").option("-d, --duration <seconds>", "Target duration in seconds (15-60)", "60").option("
|
|
40188
|
+
aiCommand.command("auto-shorts").alias("shorts").description("Auto-generate shorts from long-form video").argument("<video>", "Video file path").option("-o, --output <path>", "Output file (single) or directory (multiple)").option("-d, --duration <seconds>", "Target duration in seconds (15-60)", "60").option("--count <number>", "Number of shorts to generate", "1").option("-a, --aspect <ratio>", "Aspect ratio: 9:16, 1:1", "9:16").option("--output-dir <dir>", "Output directory for multiple shorts").option("--add-captions", "Add auto-generated captions").option("--caption-style <style>", "Caption style: minimal, bold, animated", "bold").option("--analyze-only", "Show segments without generating").option("-l, --language <lang>", "Language code for transcription").option("--use-gemini", "Use Gemini Video Understanding for enhanced visual+audio analysis").option("--low-res", "Use low resolution mode for longer videos (Gemini only)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
|
|
40189
40189
|
const startedAt = Date.now();
|
|
40190
40190
|
try {
|
|
40191
40191
|
if (options.output) {
|
|
@@ -50304,15 +50304,14 @@ var init_detect = __esm({
|
|
|
50304
50304
|
"use strict";
|
|
50305
50305
|
init_esm();
|
|
50306
50306
|
init_source();
|
|
50307
|
-
init_ora();
|
|
50308
50307
|
init_engine();
|
|
50309
50308
|
init_exec_safe();
|
|
50310
50309
|
init_output();
|
|
50311
50310
|
init_validate();
|
|
50312
50311
|
detectCommand = new Command("detect").description("Auto-detect scenes, beats, and silences in media");
|
|
50313
|
-
detectCommand.command("scenes").description("Detect scene changes in video").argument("<video>", "Video file path").option("
|
|
50312
|
+
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) => {
|
|
50314
50313
|
const startedAt = Date.now();
|
|
50315
|
-
const spinner2 =
|
|
50314
|
+
const spinner2 = spinner("Detecting scenes...").start();
|
|
50316
50315
|
try {
|
|
50317
50316
|
if (options.output) {
|
|
50318
50317
|
validateOutputPath(options.output);
|
|
@@ -50429,9 +50428,9 @@ var init_detect = __esm({
|
|
|
50429
50428
|
exitWithError(generalError(`Scene detection failed: ${msg}`));
|
|
50430
50429
|
}
|
|
50431
50430
|
});
|
|
50432
|
-
detectCommand.command("silence").description("Detect silence in audio/video").argument("<media>", "Media file path").option("
|
|
50431
|
+
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) => {
|
|
50433
50432
|
const startedAt = Date.now();
|
|
50434
|
-
const spinner2 =
|
|
50433
|
+
const spinner2 = spinner("Detecting silence...").start();
|
|
50435
50434
|
try {
|
|
50436
50435
|
if (options.output) {
|
|
50437
50436
|
validateOutputPath(options.output);
|
|
@@ -50517,7 +50516,7 @@ var init_detect = __esm({
|
|
|
50517
50516
|
});
|
|
50518
50517
|
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) => {
|
|
50519
50518
|
const startedAt = Date.now();
|
|
50520
|
-
const spinner2 =
|
|
50519
|
+
const spinner2 = spinner("Detecting beats...").start();
|
|
50521
50520
|
try {
|
|
50522
50521
|
if (options.output) {
|
|
50523
50522
|
validateOutputPath(options.output);
|
|
@@ -57372,7 +57371,7 @@ var init_scene2 = __esm({
|
|
|
57372
57371
|
)
|
|
57373
57372
|
});
|
|
57374
57373
|
sceneStylesTool = defineTool({
|
|
57375
|
-
name: "
|
|
57374
|
+
name: "scene_list_styles",
|
|
57376
57375
|
category: "scene",
|
|
57377
57376
|
cost: "free",
|
|
57378
57377
|
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.",
|
|
@@ -57383,7 +57382,7 @@ var init_scene2 = __esm({
|
|
|
57383
57382
|
if (!style) {
|
|
57384
57383
|
return {
|
|
57385
57384
|
success: false,
|
|
57386
|
-
error: `Unknown visual style "${args.name}". Run
|
|
57385
|
+
error: `Unknown visual style "${args.name}". Run scene_list_styles with no name to list all 8.`
|
|
57387
57386
|
};
|
|
57388
57387
|
}
|
|
57389
57388
|
return {
|
|
@@ -57423,7 +57422,7 @@ var init_scene2 = __esm({
|
|
|
57423
57422
|
(s) => ` \u2022 ${s.name} (${s.slug}) \u2014 ${s.mood}; best for ${s.bestFor}`
|
|
57424
57423
|
),
|
|
57425
57424
|
``,
|
|
57426
|
-
`Run
|
|
57425
|
+
`Run scene_list_styles { name: "<slug>" } to fetch the full DESIGN.md hard-gate body for one style.`
|
|
57427
57426
|
]
|
|
57428
57427
|
};
|
|
57429
57428
|
}
|
|
@@ -60488,11 +60487,11 @@ var init_export = __esm({
|
|
|
60488
60487
|
BITRATE_PATTERN = /^\d+(?:\.\d+)?[kKmMgG]?$/;
|
|
60489
60488
|
RESOLUTION_PATTERN = /^\d+x\d+$/;
|
|
60490
60489
|
VALID_CODECS = ["h264", "h265", "vp9"];
|
|
60491
|
-
exportCommand = new Command("export").description("Export project to video file").argument("<project>", "Project file path").option("-o, --output <path>", "Output file path").option("
|
|
60492
|
-
"
|
|
60490
|
+
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(
|
|
60491
|
+
"--preset <preset>",
|
|
60493
60492
|
"Quality preset (draft, standard, high, ultra)",
|
|
60494
60493
|
"standard"
|
|
60495
|
-
).option("
|
|
60494
|
+
).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", `
|
|
60496
60495
|
Examples:
|
|
60497
60496
|
$ vibe export project.vibe.json -o output.mp4
|
|
60498
60497
|
$ vibe export project.vibe.json -o output.mp4 -p high -y
|
|
@@ -61650,7 +61649,7 @@ Safe to invoke on user-provided projects.
|
|
|
61650
61649
|
|
|
61651
61650
|
\`\`\`bash
|
|
61652
61651
|
vibe scene init <dir> [-r 16:9|9:16|1:1|4:5] [-d <sec>] [--visual-style "<name>"]
|
|
61653
|
-
vibe scene styles [<name>] # list / show vendored visual identities
|
|
61652
|
+
vibe scene list-styles [<name>] # list / show vendored visual identities
|
|
61654
61653
|
vibe scene install-skill [<dir>] [--host all] # retroactive composition-rules install
|
|
61655
61654
|
vibe scene add <name> --style <preset> [...]
|
|
61656
61655
|
vibe scene compose-prompts [<dir>] [--beat <id>] # H2: emit plan, no LLM call
|
|
@@ -61838,7 +61837,7 @@ overlay, etc.) \u2014 useful at the tail of a pipeline.
|
|
|
61838
61837
|
],
|
|
61839
61838
|
relatedCommands: [
|
|
61840
61839
|
"vibe init",
|
|
61841
|
-
"vibe scene styles",
|
|
61840
|
+
"vibe scene list-styles",
|
|
61842
61841
|
"vibe scene install-skill",
|
|
61843
61842
|
"vibe scene compose-prompts",
|
|
61844
61843
|
"vibe build",
|
|
@@ -62167,7 +62166,7 @@ init_source();
|
|
|
62167
62166
|
// package.json
|
|
62168
62167
|
var package_default = {
|
|
62169
62168
|
name: "@vibeframe/cli",
|
|
62170
|
-
version: "0.
|
|
62169
|
+
version: "0.78.0",
|
|
62171
62170
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
62172
62171
|
private: false,
|
|
62173
62172
|
license: "MIT",
|
|
@@ -62389,7 +62388,7 @@ async function resolveProjectPath(inputPath) {
|
|
|
62389
62388
|
}
|
|
62390
62389
|
return filePath;
|
|
62391
62390
|
}
|
|
62392
|
-
var projectCommand = new Command("project").description("
|
|
62391
|
+
var projectCommand = new Command("project").description("Manage VibeFrame .vibe.json project files (create, info, set)").addHelpText("after", `
|
|
62393
62392
|
Examples:
|
|
62394
62393
|
$ vibe project create "my-video" -o project.vibe.json
|
|
62395
62394
|
$ vibe project create "shorts" -r 9:16 -o vertical.vibe.json
|
|
@@ -62398,7 +62397,7 @@ Examples:
|
|
|
62398
62397
|
|
|
62399
62398
|
Cost: Free (no API keys needed). Projects are saved as .vibe.json files.
|
|
62400
62399
|
Run 'vibe schema project.<command>' for structured parameter info.`);
|
|
62401
|
-
projectCommand.command("create").description("Create a new project").argument("<name>", "Project name or path (e.g., 'my-project' or 'output/my-project')").option("-o, --output <path>", "Output file path (overrides name-based path)").option("-r, --ratio <ratio>", "Aspect ratio (16:9, 9:16, 1:1, 4:5)", "16:9").option("
|
|
62400
|
+
projectCommand.command("create").description("Create a new project").argument("<name>", "Project name or path (e.g., 'my-project' or 'output/my-project')").option("-o, --output <path>", "Output file path (overrides name-based path)").option("-r, --ratio <ratio>", "Aspect ratio (16:9, 9:16, 1:1, 4:5)", "16:9").option("--fps <fps>", "Frame rate", "30").option("--dry-run", "Preview parameters without executing").action(async (name, options) => {
|
|
62402
62401
|
const startedAt = Date.now();
|
|
62403
62402
|
const spinner2 = ora("Creating project...").start();
|
|
62404
62403
|
try {
|
|
@@ -62512,7 +62511,7 @@ projectCommand.command("info").description("Show project information").argument(
|
|
|
62512
62511
|
exitWithError(generalError(`Failed to load project: ${msg}`));
|
|
62513
62512
|
}
|
|
62514
62513
|
});
|
|
62515
|
-
projectCommand.command("set").description("Update project settings").argument("<file>", "Project file path").option("
|
|
62514
|
+
projectCommand.command("set").description("Update project settings").argument("<file>", "Project file path").option("--name <name>", "Project name").option("-r, --ratio <ratio>", "Aspect ratio (16:9, 9:16, 1:1, 4:5)").option("--fps <fps>", "Frame rate").option("--dry-run", "Preview parameters without executing").action(async (file, options) => {
|
|
62516
62515
|
const startedAt = Date.now();
|
|
62517
62516
|
const spinner2 = ora("Updating project...").start();
|
|
62518
62517
|
try {
|
|
@@ -62584,15 +62583,15 @@ var timelineCommand = new Command("timeline").description("Timeline editing comm
|
|
|
62584
62583
|
Examples:
|
|
62585
62584
|
$ vibe timeline add-source project.vibe.json video.mp4 # Returns source ID
|
|
62586
62585
|
$ vibe timeline add-clip project.vibe.json <source-id> # Add clip from source
|
|
62587
|
-
$ vibe timeline trim project.vibe.json <clip-id> --start 5 --end 30
|
|
62588
|
-
$ vibe timeline split project.vibe.json <clip-id> --time 10
|
|
62586
|
+
$ vibe timeline trim-clip project.vibe.json <clip-id> --start 5 --end 30
|
|
62587
|
+
$ vibe timeline split-clip project.vibe.json <clip-id> --time 10
|
|
62589
62588
|
$ vibe timeline list project.vibe.json --json
|
|
62590
|
-
$ vibe timeline delete project.vibe.json <clip-id>
|
|
62589
|
+
$ vibe timeline delete-clip project.vibe.json <clip-id>
|
|
62591
62590
|
|
|
62592
|
-
Typical workflow: create project \u2192 add-source \u2192 add-clip \u2192 trim/split \u2192 export
|
|
62591
|
+
Typical workflow: create project \u2192 add-source \u2192 add-clip \u2192 trim-clip/split-clip \u2192 export
|
|
62593
62592
|
Cost: Free (no API keys needed).
|
|
62594
62593
|
Run 'vibe schema timeline.<command>' for structured parameter info.`);
|
|
62595
|
-
timelineCommand.command("add-source").description("Add a media source to the project").argument("<project>", "Project file path").argument("<media>", "Media file path").option("
|
|
62594
|
+
timelineCommand.command("add-source").description("Add a media source to the project").argument("<project>", "Project file path").argument("<media>", "Media file path").option("--name <name>", "Source name (defaults to filename)").option("--type <type>", "Media type (video, audio, image, lottie)").option("-d, --duration <seconds>", "Duration in seconds (required for images)").option("--dry-run", "Preview parameters without executing").action(async (projectPath, mediaPath, options) => {
|
|
62596
62595
|
const startedAt = Date.now();
|
|
62597
62596
|
const spinner2 = ora("Adding source...").start();
|
|
62598
62597
|
try {
|
|
@@ -62654,7 +62653,7 @@ timelineCommand.command("add-source").description("Add a media source to the pro
|
|
|
62654
62653
|
exitWithError(generalError(`Failed to add source: ${msg}`));
|
|
62655
62654
|
}
|
|
62656
62655
|
});
|
|
62657
|
-
timelineCommand.command("add-clip").description("Add a clip to the timeline").argument("<project>", "Project file path").argument("<source-id>", "Source ID to use").option("
|
|
62656
|
+
timelineCommand.command("add-clip").description("Add a clip to the timeline").argument("<project>", "Project file path").argument("<source-id>", "Source ID to use").option("--track <id>", "Track ID (defaults to first matching track)").option("--start <seconds>", "Start time in timeline", "0").option("-d, --duration <seconds>", "Clip duration (defaults to source duration)").option("--offset <seconds>", "Source start offset", "0").option("--dry-run", "Preview parameters without executing").action(async (projectPath, sourceId, options) => {
|
|
62658
62657
|
const startedAt = Date.now();
|
|
62659
62658
|
const spinner2 = ora("Adding clip...").start();
|
|
62660
62659
|
try {
|
|
@@ -62736,7 +62735,7 @@ timelineCommand.command("add-clip").description("Add a clip to the timeline").ar
|
|
|
62736
62735
|
exitWithError(generalError(`Failed to add clip: ${msg}`));
|
|
62737
62736
|
}
|
|
62738
62737
|
});
|
|
62739
|
-
timelineCommand.command("add-track").description("Add a new track").argument("<project>", "Project file path").argument("<type>", "Track type (video, audio)").option("
|
|
62738
|
+
timelineCommand.command("add-track").description("Add a new track").argument("<project>", "Project file path").argument("<type>", "Track type (video, audio)").option("--name <name>", "Track name").option("--dry-run", "Preview parameters without executing").action(async (projectPath, type, options) => {
|
|
62740
62739
|
const startedAt = Date.now();
|
|
62741
62740
|
const spinner2 = ora("Adding track...").start();
|
|
62742
62741
|
try {
|
|
@@ -62793,7 +62792,7 @@ timelineCommand.command("add-track").description("Add a new track").argument("<p
|
|
|
62793
62792
|
exitWithError(generalError(`Failed to add track: ${msg}`));
|
|
62794
62793
|
}
|
|
62795
62794
|
});
|
|
62796
|
-
timelineCommand.command("add-effect").description("Add an effect to a clip").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID").argument("<effect-type>", "Effect type (fadeIn, fadeOut, blur, brightness, contrast, saturation, speed, volume)").option("
|
|
62795
|
+
timelineCommand.command("add-effect").description("Add an effect to a clip").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID").argument("<effect-type>", "Effect type (fadeIn, fadeOut, blur, brightness, contrast, saturation, speed, volume)").option("--start <seconds>", "Effect start time (relative to clip)", "0").option("-d, --duration <seconds>", "Effect duration (defaults to clip duration)").option("--params <json>", "Effect parameters as JSON", "{}").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, effectType, options) => {
|
|
62797
62796
|
const startedAt = Date.now();
|
|
62798
62797
|
const spinner2 = ora("Adding effect...").start();
|
|
62799
62798
|
try {
|
|
@@ -62865,14 +62864,14 @@ timelineCommand.command("add-effect").description("Add an effect to a clip").arg
|
|
|
62865
62864
|
exitWithError(generalError(`Failed to add effect: ${msg}`));
|
|
62866
62865
|
}
|
|
62867
62866
|
});
|
|
62868
|
-
timelineCommand.command("trim").description("Trim a clip").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID").option("--start <seconds>", "New start time").option("--duration <seconds>", "New duration").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, options) => {
|
|
62867
|
+
timelineCommand.command("trim-clip").description("Trim a clip").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID").option("--start <seconds>", "New start time").option("--duration <seconds>", "New duration").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, options) => {
|
|
62869
62868
|
const startedAt = Date.now();
|
|
62870
62869
|
const spinner2 = ora("Trimming clip...").start();
|
|
62871
62870
|
try {
|
|
62872
62871
|
validateResourceId(clipId);
|
|
62873
62872
|
if (options.dryRun) {
|
|
62874
62873
|
outputSuccess({
|
|
62875
|
-
command: "timeline trim",
|
|
62874
|
+
command: "timeline trim-clip",
|
|
62876
62875
|
startedAt,
|
|
62877
62876
|
dryRun: true,
|
|
62878
62877
|
data: {
|
|
@@ -62906,7 +62905,7 @@ timelineCommand.command("trim").description("Trim a clip").argument("<project>",
|
|
|
62906
62905
|
spinner2.succeed(source_default.green("Clip trimmed"));
|
|
62907
62906
|
if (isJsonMode()) {
|
|
62908
62907
|
outputSuccess({
|
|
62909
|
-
command: "timeline trim",
|
|
62908
|
+
command: "timeline trim-clip",
|
|
62910
62909
|
startedAt,
|
|
62911
62910
|
data: {
|
|
62912
62911
|
id: updatedClip.id,
|
|
@@ -63027,14 +63026,14 @@ timelineCommand.command("list").description("List timeline contents").argument("
|
|
|
63027
63026
|
exitWithError(generalError(`Failed to list timeline: ${msg}`));
|
|
63028
63027
|
}
|
|
63029
63028
|
});
|
|
63030
|
-
timelineCommand.command("split").description("Split a clip at a specific time").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to split").option("
|
|
63029
|
+
timelineCommand.command("split-clip").description("Split a clip at a specific time").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to split").option("--time <seconds>", "Split time relative to clip start", "0").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, options) => {
|
|
63031
63030
|
const startedAt = Date.now();
|
|
63032
63031
|
const spinner2 = ora("Splitting clip...").start();
|
|
63033
63032
|
try {
|
|
63034
63033
|
validateResourceId(clipId);
|
|
63035
63034
|
if (options.dryRun) {
|
|
63036
63035
|
outputSuccess({
|
|
63037
|
-
command: "timeline split",
|
|
63036
|
+
command: "timeline split-clip",
|
|
63038
63037
|
startedAt,
|
|
63039
63038
|
dryRun: true,
|
|
63040
63039
|
data: {
|
|
@@ -63071,7 +63070,7 @@ timelineCommand.command("split").description("Split a clip at a specific time").
|
|
|
63071
63070
|
spinner2.succeed(source_default.green("Clip split successfully"));
|
|
63072
63071
|
if (isJsonMode()) {
|
|
63073
63072
|
outputSuccess({
|
|
63074
|
-
command: "timeline split",
|
|
63073
|
+
command: "timeline split-clip",
|
|
63075
63074
|
startedAt,
|
|
63076
63075
|
data: {
|
|
63077
63076
|
first: { id: first.id, duration: first.duration },
|
|
@@ -63089,14 +63088,14 @@ timelineCommand.command("split").description("Split a clip at a specific time").
|
|
|
63089
63088
|
exitWithError(generalError(`Failed to split clip: ${msg}`));
|
|
63090
63089
|
}
|
|
63091
63090
|
});
|
|
63092
|
-
timelineCommand.command("duplicate").description("Duplicate a clip").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to duplicate").option("
|
|
63091
|
+
timelineCommand.command("duplicate-clip").description("Duplicate a clip").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to duplicate").option("--time <seconds>", "Start time for duplicate (default: after original)").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, options) => {
|
|
63093
63092
|
const startedAt = Date.now();
|
|
63094
63093
|
const spinner2 = ora("Duplicating clip...").start();
|
|
63095
63094
|
try {
|
|
63096
63095
|
validateResourceId(clipId);
|
|
63097
63096
|
if (options.dryRun) {
|
|
63098
63097
|
outputSuccess({
|
|
63099
|
-
command: "timeline duplicate",
|
|
63098
|
+
command: "timeline duplicate-clip",
|
|
63100
63099
|
startedAt,
|
|
63101
63100
|
dryRun: true,
|
|
63102
63101
|
data: {
|
|
@@ -63128,7 +63127,7 @@ timelineCommand.command("duplicate").description("Duplicate a clip").argument("<
|
|
|
63128
63127
|
spinner2.succeed(source_default.green(`Clip duplicated: ${duplicated.id}`));
|
|
63129
63128
|
if (isJsonMode()) {
|
|
63130
63129
|
outputSuccess({
|
|
63131
|
-
command: "timeline duplicate",
|
|
63130
|
+
command: "timeline duplicate-clip",
|
|
63132
63131
|
startedAt,
|
|
63133
63132
|
data: {
|
|
63134
63133
|
id: duplicated.id,
|
|
@@ -63148,14 +63147,14 @@ timelineCommand.command("duplicate").description("Duplicate a clip").argument("<
|
|
|
63148
63147
|
exitWithError(generalError(`Failed to duplicate clip: ${msg}`));
|
|
63149
63148
|
}
|
|
63150
63149
|
});
|
|
63151
|
-
timelineCommand.command("delete").description("Delete a clip from the timeline").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to delete").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, options) => {
|
|
63150
|
+
timelineCommand.command("delete-clip").description("Delete a clip from the timeline").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to delete").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, options) => {
|
|
63152
63151
|
const startedAt = Date.now();
|
|
63153
63152
|
const spinner2 = ora("Deleting clip...").start();
|
|
63154
63153
|
try {
|
|
63155
63154
|
validateResourceId(clipId);
|
|
63156
63155
|
if (options.dryRun) {
|
|
63157
63156
|
outputSuccess({
|
|
63158
|
-
command: "timeline delete",
|
|
63157
|
+
command: "timeline delete-clip",
|
|
63159
63158
|
startedAt,
|
|
63160
63159
|
dryRun: true,
|
|
63161
63160
|
data: {
|
|
@@ -63185,7 +63184,7 @@ timelineCommand.command("delete").description("Delete a clip from the timeline")
|
|
|
63185
63184
|
spinner2.succeed(source_default.green("Clip deleted"));
|
|
63186
63185
|
if (isJsonMode()) {
|
|
63187
63186
|
outputSuccess({
|
|
63188
|
-
command: "timeline delete",
|
|
63187
|
+
command: "timeline delete-clip",
|
|
63189
63188
|
startedAt,
|
|
63190
63189
|
data: {
|
|
63191
63190
|
id: clipId,
|
|
@@ -63200,7 +63199,7 @@ timelineCommand.command("delete").description("Delete a clip from the timeline")
|
|
|
63200
63199
|
exitWithError(generalError(`Failed to delete clip: ${msg}`));
|
|
63201
63200
|
}
|
|
63202
63201
|
});
|
|
63203
|
-
timelineCommand.command("move").description("Move a clip to a new position").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to move").option("
|
|
63202
|
+
timelineCommand.command("move-clip").description("Move a clip to a new position").argument("<project>", "Project file path").argument("<clip-id>", "Clip ID to move").option("--time <seconds>", "New start time").option("--track <track-id>", "Move to different track").option("--dry-run", "Preview parameters without executing").action(async (projectPath, clipId, options) => {
|
|
63204
63203
|
const startedAt = Date.now();
|
|
63205
63204
|
const spinner2 = ora("Moving clip...").start();
|
|
63206
63205
|
try {
|
|
@@ -63208,7 +63207,7 @@ timelineCommand.command("move").description("Move a clip to a new position").arg
|
|
|
63208
63207
|
if (options.track) validateResourceId(options.track);
|
|
63209
63208
|
if (options.dryRun) {
|
|
63210
63209
|
outputSuccess({
|
|
63211
|
-
command: "timeline move",
|
|
63210
|
+
command: "timeline move-clip",
|
|
63212
63211
|
startedAt,
|
|
63213
63212
|
dryRun: true,
|
|
63214
63213
|
data: {
|
|
@@ -63243,7 +63242,7 @@ timelineCommand.command("move").description("Move a clip to a new position").arg
|
|
|
63243
63242
|
spinner2.succeed(source_default.green("Clip moved"));
|
|
63244
63243
|
if (isJsonMode()) {
|
|
63245
63244
|
outputSuccess({
|
|
63246
|
-
command: "timeline move",
|
|
63245
|
+
command: "timeline move-clip",
|
|
63247
63246
|
startedAt,
|
|
63248
63247
|
data: {
|
|
63249
63248
|
id: updated.id,
|
|
@@ -63311,10 +63310,29 @@ Use '--fields response,model' to limit output size.
|
|
|
63311
63310
|
Run 'vibe schema inspect.<command>' for structured parameter info.
|
|
63312
63311
|
`
|
|
63313
63312
|
);
|
|
63314
|
-
analyzeCommand.command("media").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("
|
|
63313
|
+
analyzeCommand.command("media").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("--verbose", "Show token usage").option("--fields <fields>", "Comma-separated fields to include in output (e.g., response,model)").option("--dry-run", "Preview parameters without executing").action(async (source, prompt3, options) => {
|
|
63315
63314
|
const startedAt = Date.now();
|
|
63316
63315
|
try {
|
|
63317
63316
|
rejectControlChars(prompt3);
|
|
63317
|
+
if (options.dryRun) {
|
|
63318
|
+
outputSuccess({
|
|
63319
|
+
command: "inspect media",
|
|
63320
|
+
startedAt,
|
|
63321
|
+
dryRun: true,
|
|
63322
|
+
data: {
|
|
63323
|
+
params: {
|
|
63324
|
+
source,
|
|
63325
|
+
prompt: prompt3,
|
|
63326
|
+
model: options.model,
|
|
63327
|
+
fps: options.fps,
|
|
63328
|
+
start: options.start,
|
|
63329
|
+
end: options.end,
|
|
63330
|
+
lowRes: options.lowRes ?? false
|
|
63331
|
+
}
|
|
63332
|
+
}
|
|
63333
|
+
});
|
|
63334
|
+
return;
|
|
63335
|
+
}
|
|
63318
63336
|
if (options.apiKey) {
|
|
63319
63337
|
process.env.GOOGLE_API_KEY = options.apiKey;
|
|
63320
63338
|
} else {
|
|
@@ -63344,7 +63362,7 @@ analyzeCommand.command("media").description("Analyze any media: images, videos,
|
|
|
63344
63362
|
data.totalTokens = result.totalTokens;
|
|
63345
63363
|
}
|
|
63346
63364
|
outputSuccess({
|
|
63347
|
-
command: "
|
|
63365
|
+
command: "inspect media",
|
|
63348
63366
|
startedAt,
|
|
63349
63367
|
data
|
|
63350
63368
|
});
|
|
@@ -63369,10 +63387,29 @@ analyzeCommand.command("media").description("Analyze any media: images, videos,
|
|
|
63369
63387
|
exitWithError(apiError(`Analysis failed: ${error.message}`));
|
|
63370
63388
|
}
|
|
63371
63389
|
});
|
|
63372
|
-
analyzeCommand.command("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("
|
|
63390
|
+
analyzeCommand.command("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("--verbose", "Show token usage").option("--fields <fields>", "Comma-separated fields to include in output (e.g., response,model)").option("--dry-run", "Preview parameters without executing").action(async (source, prompt3, options) => {
|
|
63373
63391
|
const startedAt = Date.now();
|
|
63374
63392
|
try {
|
|
63375
63393
|
rejectControlChars(prompt3);
|
|
63394
|
+
if (options.dryRun) {
|
|
63395
|
+
outputSuccess({
|
|
63396
|
+
command: "inspect video",
|
|
63397
|
+
startedAt,
|
|
63398
|
+
dryRun: true,
|
|
63399
|
+
data: {
|
|
63400
|
+
params: {
|
|
63401
|
+
source,
|
|
63402
|
+
prompt: prompt3,
|
|
63403
|
+
model: options.model,
|
|
63404
|
+
fps: options.fps,
|
|
63405
|
+
start: options.start,
|
|
63406
|
+
end: options.end,
|
|
63407
|
+
lowRes: options.lowRes ?? false
|
|
63408
|
+
}
|
|
63409
|
+
}
|
|
63410
|
+
});
|
|
63411
|
+
return;
|
|
63412
|
+
}
|
|
63376
63413
|
if (options.apiKey) {
|
|
63377
63414
|
process.env.GOOGLE_API_KEY = options.apiKey;
|
|
63378
63415
|
} else {
|
|
@@ -63402,7 +63439,7 @@ analyzeCommand.command("video").description("Analyze video using Gemini (summari
|
|
|
63402
63439
|
data.totalTokens = result.totalTokens;
|
|
63403
63440
|
}
|
|
63404
63441
|
outputSuccess({
|
|
63405
|
-
command: "
|
|
63442
|
+
command: "inspect video",
|
|
63406
63443
|
startedAt,
|
|
63407
63444
|
data
|
|
63408
63445
|
});
|
|
@@ -63427,10 +63464,25 @@ analyzeCommand.command("video").description("Analyze video using Gemini (summari
|
|
|
63427
63464
|
}
|
|
63428
63465
|
});
|
|
63429
63466
|
registerReviewCommand(analyzeCommand);
|
|
63430
|
-
analyzeCommand.command("suggest").description("Get AI edit suggestions using Gemini").argument("<project>", "Project file path").argument("<instruction>", "Natural language instruction").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("--apply", "Apply the first suggestion automatically").action(async (projectPath, instruction, options) => {
|
|
63467
|
+
analyzeCommand.command("suggest").description("Get AI edit suggestions using Gemini").argument("<project>", "Project file path").argument("<instruction>", "Natural language instruction").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("--apply", "Apply the first suggestion automatically").option("--dry-run", "Preview parameters without executing").action(async (projectPath, instruction, options) => {
|
|
63431
63468
|
const startedAt = Date.now();
|
|
63432
63469
|
try {
|
|
63433
63470
|
rejectControlChars(instruction);
|
|
63471
|
+
if (options.dryRun) {
|
|
63472
|
+
outputSuccess({
|
|
63473
|
+
command: "inspect suggest",
|
|
63474
|
+
startedAt,
|
|
63475
|
+
dryRun: true,
|
|
63476
|
+
data: {
|
|
63477
|
+
params: {
|
|
63478
|
+
project: projectPath,
|
|
63479
|
+
instruction,
|
|
63480
|
+
apply: options.apply ?? false
|
|
63481
|
+
}
|
|
63482
|
+
}
|
|
63483
|
+
});
|
|
63484
|
+
return;
|
|
63485
|
+
}
|
|
63434
63486
|
const apiKey = await requireApiKey("GOOGLE_API_KEY", "Google", options.apiKey);
|
|
63435
63487
|
const spinner2 = ora("Initializing Gemini...").start();
|
|
63436
63488
|
const filePath = resolve32(process.cwd(), projectPath);
|
|
@@ -63445,7 +63497,7 @@ analyzeCommand.command("suggest").description("Get AI edit suggestions using Gem
|
|
|
63445
63497
|
spinner2.succeed(source_default.green(`Found ${suggestions.length} suggestion(s)`));
|
|
63446
63498
|
if (isJsonMode()) {
|
|
63447
63499
|
outputSuccess({
|
|
63448
|
-
command: "
|
|
63500
|
+
command: "inspect suggest",
|
|
63449
63501
|
startedAt,
|
|
63450
63502
|
data: {
|
|
63451
63503
|
suggestions: suggestions.map((s) => ({ type: s.type, description: s.description, confidence: s.confidence, clipIds: s.clipIds, params: s.params }))
|
|
@@ -63518,7 +63570,7 @@ API Keys:
|
|
|
63518
63570
|
Run 'vibe schema audio.<command>' for structured parameter info.
|
|
63519
63571
|
`
|
|
63520
63572
|
);
|
|
63521
|
-
audioCommand.command("transcribe").description("Transcribe audio using Whisper").argument("<audio>", "Audio file path").option("-k, --api-key <key>", "OpenAI API key (or set OPENAI_API_KEY env)").option("-l, --language <lang>", "Language code (e.g., en, ko)").option("-o, --output <path>", "Output file path").option("
|
|
63573
|
+
audioCommand.command("transcribe").description("Transcribe audio using Whisper").argument("<audio>", "Audio file path").option("-k, --api-key <key>", "OpenAI API key (or set OPENAI_API_KEY env)").option("-l, --language <lang>", "Language code (e.g., en, ko)").option("-o, --output <path>", "Output file path").option("--format <format>", "Output format: json, srt, vtt (auto-detected from extension)").action(async (audioPath, options) => {
|
|
63522
63574
|
const startedAt = Date.now();
|
|
63523
63575
|
try {
|
|
63524
63576
|
if (options.output) {
|
|
@@ -63656,7 +63708,7 @@ audioCommand.command("isolate").description("Isolate vocals from audio using Ele
|
|
|
63656
63708
|
exitWithError(apiError(`Audio isolation failed: ${msg}`, true));
|
|
63657
63709
|
}
|
|
63658
63710
|
});
|
|
63659
|
-
audioCommand.command("clone-voice").description("Clone a voice from audio samples using ElevenLabs").argument("[samples...]", "Audio sample files (1-25 files)").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("
|
|
63711
|
+
audioCommand.command("clone-voice").description("Clone a voice from audio samples using ElevenLabs").argument("[samples...]", "Audio sample files (1-25 files)").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("--name <name>", "Voice name (required)").option("-d, --description <desc>", "Voice description").option("--labels <json>", `Labels as JSON (e.g., '{"accent": "american"}')`).option("--remove-noise", "Remove background noise from samples").option("--list", "List all available voices").option("--dry-run", "Preview parameters without executing").action(async (samples, options) => {
|
|
63660
63712
|
const startedAt = Date.now();
|
|
63661
63713
|
try {
|
|
63662
63714
|
if (options.dryRun) {
|
|
@@ -63742,7 +63794,7 @@ audioCommand.command("clone-voice").description("Clone a voice from audio sample
|
|
|
63742
63794
|
exitWithError(apiError(`Voice cloning failed: ${msg}`, true));
|
|
63743
63795
|
}
|
|
63744
63796
|
});
|
|
63745
|
-
audioCommand.command("dub").description("Dub audio/video to another language (transcribe, translate, TTS)").argument("<media>", "Input media file (video or audio)").option("-l, --language <lang>", "Target language code (e.g., es, ko, ja) (required)").option("--source <lang>", "Source language code (default: auto-detect)").option("
|
|
63797
|
+
audioCommand.command("dub").description("Dub audio/video to another language (transcribe, translate, TTS)").argument("<media>", "Input media file (video or audio)").option("-l, --language <lang>", "Target language code (e.g., es, ko, ja) (required)").option("--source <lang>", "Source language code (default: auto-detect)").option("--voice <id>", "ElevenLabs voice ID for output").option("--analyze-only", "Only analyze and show timing, don't generate audio").option("-o, --output <path>", "Output file path").option("--dry-run", "Preview parameters without executing").action(async (mediaPath, options) => {
|
|
63746
63798
|
const startedAt = Date.now();
|
|
63747
63799
|
try {
|
|
63748
63800
|
if (options.dryRun) {
|
|
@@ -63938,7 +63990,7 @@ ${segmentTexts}`,
|
|
|
63938
63990
|
exitWithError(apiError(`Dubbing failed: ${msg}`, true));
|
|
63939
63991
|
}
|
|
63940
63992
|
});
|
|
63941
|
-
audioCommand.command("duck").description("Auto-duck background music when voice is present (FFmpeg)").argument("<music>", "Background music file path").option("
|
|
63993
|
+
audioCommand.command("duck").description("Auto-duck background music when voice is present (FFmpeg)").argument("<music>", "Background music file path").option("--voice <path>", "Voice/narration track (required)").option("-o, --output <path>", "Output audio file path").option("--threshold <dB>", "Sidechain threshold in dB", "-30").option("-r, --ratio <ratio>", "Compression ratio", "3").option("-a, --attack <ms>", "Attack time in ms", "20").option("-l, --release <ms>", "Release time in ms", "200").option("--dry-run", "Preview parameters without executing").action(async (musicPath, options) => {
|
|
63942
63994
|
const startedAt = Date.now();
|
|
63943
63995
|
try {
|
|
63944
63996
|
if (options.dryRun) {
|
|
@@ -64017,7 +64069,7 @@ import { readFile as readFile25, writeFile as writeFile32 } from "node:fs/promis
|
|
|
64017
64069
|
import { resolve as resolve34 } from "node:path";
|
|
64018
64070
|
import { existsSync as existsSync26 } from "node:fs";
|
|
64019
64071
|
function registerScriptPipelineCommands(aiCommand) {
|
|
64020
|
-
aiCommand.command("regenerate-scene").description("Regenerate a specific scene in a script-to-video output directory").argument("<project-dir>", "Path to the script-to-video output directory").requiredOption("--scene <numbers>", "Scene number(s) to regenerate (1-based), e.g., 3 or 3,4,5").option("--video-only", "Only regenerate video").option("--narration-only", "Only regenerate narration").option("--image-only", "Only regenerate image").option("
|
|
64072
|
+
aiCommand.command("regenerate-scene").description("Regenerate a specific scene in a script-to-video output directory").argument("<project-dir>", "Path to the script-to-video output directory").requiredOption("--scene <numbers>", "Scene number(s) to regenerate (1-based), e.g., 3 or 3,4,5").option("--video-only", "Only regenerate video").option("--narration-only", "Only regenerate narration").option("--image-only", "Only regenerate image").option("--generator <engine>", "Video generator: grok | kling | runway | veo", "grok").option("-i, --image-provider <provider>", "Image provider: gemini | openai | grok", "gemini").option("--voice <id>", "ElevenLabs voice ID for narration").option("-a, --aspect-ratio <ratio>", "Aspect ratio: 16:9 | 9:16 | 1:1", "16:9").option("--retries <count>", "Number of retries for video generation failures", String(DEFAULT_VIDEO_RETRIES)).option("--reference-scene <num>", "Use another scene's image as reference for character consistency").option("--dry-run", "Preview parameters without executing").action(async (projectDir, options) => {
|
|
64021
64073
|
const startedAt = Date.now();
|
|
64022
64074
|
try {
|
|
64023
64075
|
const outputDir = resolve34(process.cwd(), projectDir);
|
|
@@ -64189,7 +64241,7 @@ init_ai_highlights();
|
|
|
64189
64241
|
init_ai_animated_caption();
|
|
64190
64242
|
init_output();
|
|
64191
64243
|
var pipelineCommand = new Command("remix").description(
|
|
64192
|
-
"
|
|
64244
|
+
"Transform existing media (highlights, auto-shorts, animated captions, regenerate-scene)"
|
|
64193
64245
|
).addHelpText(
|
|
64194
64246
|
"after",
|
|
64195
64247
|
`
|
|
@@ -64225,7 +64277,7 @@ Run 'vibe schema remix.<command>' for structured parameter info.
|
|
|
64225
64277
|
registerScriptPipelineCommands(pipelineCommand);
|
|
64226
64278
|
registerHighlightsCommands(pipelineCommand);
|
|
64227
64279
|
var ANIMATED_CAPTION_STYLES = ["highlight", "bounce", "pop-in", "neon", "karaoke-sweep", "typewriter"];
|
|
64228
|
-
pipelineCommand.command("animated-caption").description("Add animated captions with word-by-word effects (Whisper + Remotion/ASS)").argument("<video>", "Video file path").option("
|
|
64280
|
+
pipelineCommand.command("animated-caption").description("Add animated captions with word-by-word effects (Whisper + Remotion/ASS)").argument("<video>", "Video file path").option("--style <preset>", "Style preset (default: highlight)", "highlight").option("--highlight-color <color>", "Active word highlight color", "#FFFF00").option("--font-size <px>", "Font size (default: auto based on resolution)").option("--position <pos>", "Caption position: top, center, bottom", "bottom").option("--words-per-group <n>", "Words shown at once (default: auto 3-5)").option("--max-chars <n>", "Max characters per group").option("-l, --language <lang>", "Whisper language hint").option("--fast", "Use ASS/FFmpeg only (no Remotion, forces ASS tier styles)").option("-o, --output <path>", "Output file path").option("--dry-run", "Preview parameters without executing").addHelpText(
|
|
64229
64281
|
"after",
|
|
64230
64282
|
`
|
|
64231
64283
|
Examples:
|
|
@@ -68747,7 +68799,7 @@ batchCommand.command("concat").description("Concatenate multiple sources into se
|
|
|
68747
68799
|
exitWithError(generalError(`Concat failed: ${msg}`));
|
|
68748
68800
|
}
|
|
68749
68801
|
});
|
|
68750
|
-
batchCommand.command("apply-effect").description("Apply an effect to multiple clips").argument("<project>", "Project file path").argument("<effect-type>", "Effect type (fadeIn, fadeOut, blur, etc.)").argument("[clip-ids...]", "Clip IDs to apply effect to (or --all)").option("--all", "Apply to all clips", false).option("-d, --duration <seconds>", "Effect duration", "1").option("
|
|
68802
|
+
batchCommand.command("apply-effect").description("Apply an effect to multiple clips").argument("<project>", "Project file path").argument("<effect-type>", "Effect type (fadeIn, fadeOut, blur, etc.)").argument("[clip-ids...]", "Clip IDs to apply effect to (or --all)").option("--all", "Apply to all clips", false).option("-d, --duration <seconds>", "Effect duration", "1").option("--start <seconds>", "Effect start time (relative to clip)", "0").option("--intensity <value>", "Effect intensity (0-1)", "1").option("--dry-run", "Preview parameters without executing").action(
|
|
68751
68803
|
async (projectPath, effectType, clipIds, options) => {
|
|
68752
68804
|
const startedAt = Date.now();
|
|
68753
68805
|
const spinner2 = ora("Applying effects...").start();
|
|
@@ -69745,7 +69797,7 @@ async function runSceneInit(projectDirArg, options, startedAt) {
|
|
|
69745
69797
|
}
|
|
69746
69798
|
const visualStyle = options.visualStyle ? getVisualStyle(String(options.visualStyle)) : void 0;
|
|
69747
69799
|
if (options.visualStyle && !visualStyle) {
|
|
69748
|
-
exitWithError(usageError(`Unknown visual style: ${String(options.visualStyle)}`, `Valid: ${visualStyleNames()}. Browse with \`vibe scene styles\`.`));
|
|
69800
|
+
exitWithError(usageError(`Unknown visual style: ${String(options.visualStyle)}`, `Valid: ${visualStyleNames()}. Browse with \`vibe scene list-styles\`.`));
|
|
69749
69801
|
}
|
|
69750
69802
|
const projectDir = resolve42(projectDirArg);
|
|
69751
69803
|
const projectName = basename14(projectDir);
|
|
@@ -71923,10 +71975,13 @@ program2.name("vibe").showSuggestionAfterError(true).description("VibeFrame CLI
|
|
|
71923
71975
|
"after",
|
|
71924
71976
|
`
|
|
71925
71977
|
Global flags (work with any command):
|
|
71978
|
+
-V, --version Print version and exit
|
|
71979
|
+
-h, --help Print help for the command and exit
|
|
71926
71980
|
--json Output JSON (auto-enabled when piped)
|
|
71927
71981
|
--fields Limit output fields (e.g., --fields "path,duration")
|
|
71928
|
-
--quiet
|
|
71982
|
+
-q, --quiet Output only the result value (path, URL, or ID)
|
|
71929
71983
|
--stdin Read options from stdin as JSON (for agent/script use)
|
|
71984
|
+
--describe Print the command's JSON schema and exit (no execution)
|
|
71930
71985
|
--dry-run Preview without executing (most commands)
|
|
71931
71986
|
|
|
71932
71987
|
Get started (90% of users start here):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.78.0",
|
|
4
4
|
"description": "VibeFrame CLI - natural language video editing from the terminal",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -182,8 +182,8 @@
|
|
|
182
182
|
"tsx": "^4.21.0",
|
|
183
183
|
"typescript": "^5.3.3",
|
|
184
184
|
"vitest": "^1.2.2",
|
|
185
|
-
"@vibeframe/core": "0.
|
|
186
|
-
"@vibeframe/ai-providers": "0.
|
|
185
|
+
"@vibeframe/core": "0.78.0",
|
|
186
|
+
"@vibeframe/ai-providers": "0.78.0"
|
|
187
187
|
},
|
|
188
188
|
"engines": {
|
|
189
189
|
"node": ">=20"
|