@vibeframe/mcp-server 0.71.0 → 0.72.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/README.md +37 -9
- package/dist/index.js +818 -509
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -449232,6 +449232,7 @@ __export(output_exports, {
|
|
|
449232
449232
|
notFoundError: () => notFoundError,
|
|
449233
449233
|
outputError: () => outputError,
|
|
449234
449234
|
outputResult: () => outputResult,
|
|
449235
|
+
outputSuccess: () => outputSuccess,
|
|
449235
449236
|
spinner: () => spinner,
|
|
449236
449237
|
suggestNext: () => suggestNext,
|
|
449237
449238
|
usageError: () => usageError
|
|
@@ -449290,6 +449291,40 @@ function formatCost(min, max, unit) {
|
|
|
449290
449291
|
if (min === max) return `~$${min.toFixed(2)} ${unit}`;
|
|
449291
449292
|
return `~$${min.toFixed(2)}-$${max.toFixed(2)} ${unit}`;
|
|
449292
449293
|
}
|
|
449294
|
+
function lookupCostEstimateUpperBound(command3) {
|
|
449295
|
+
return COST_ESTIMATES[command3]?.max ?? 0;
|
|
449296
|
+
}
|
|
449297
|
+
function outputSuccess(opts) {
|
|
449298
|
+
const elapsedMs = Math.max(0, Date.now() - opts.startedAt);
|
|
449299
|
+
const costUsd = opts.costUsd ?? (opts.dryRun ? lookupCostEstimateUpperBound(opts.command) : 0);
|
|
449300
|
+
const envelope = {
|
|
449301
|
+
command: opts.command,
|
|
449302
|
+
...opts.dryRun ? { dryRun: true } : {},
|
|
449303
|
+
elapsedMs,
|
|
449304
|
+
costUsd,
|
|
449305
|
+
warnings: opts.warnings ?? [],
|
|
449306
|
+
data: opts.data
|
|
449307
|
+
};
|
|
449308
|
+
if (isJsonMode()) {
|
|
449309
|
+
const fields = process.env.VIBE_OUTPUT_FIELDS;
|
|
449310
|
+
if (fields) {
|
|
449311
|
+
const keys2 = fields.split(",").map((k) => k.trim());
|
|
449312
|
+
const data = opts.data;
|
|
449313
|
+
const filteredData = {};
|
|
449314
|
+
for (const key2 of keys2) {
|
|
449315
|
+
if (key2 in data) filteredData[key2] = data[key2];
|
|
449316
|
+
}
|
|
449317
|
+
envelope.data = filteredData;
|
|
449318
|
+
}
|
|
449319
|
+
console.log(JSON.stringify(envelope, null, 2));
|
|
449320
|
+
return;
|
|
449321
|
+
}
|
|
449322
|
+
if (isQuietMode()) {
|
|
449323
|
+
const data = opts.data;
|
|
449324
|
+
const primary = data.outputPath ?? data.output ?? data.path ?? data.url ?? data.id;
|
|
449325
|
+
if (primary !== void 0) console.log(String(primary));
|
|
449326
|
+
}
|
|
449327
|
+
}
|
|
449293
449328
|
function outputResult(result) {
|
|
449294
449329
|
if (result.dryRun && result.command && typeof result.command === "string") {
|
|
449295
449330
|
const cost = COST_ESTIMATES[result.command];
|
|
@@ -451881,6 +451916,7 @@ Examples:
|
|
|
451881
451916
|
$ vibe ed sc video.mp4 --dry-run --json
|
|
451882
451917
|
|
|
451883
451918
|
No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires GOOGLE_API_KEY).`).action(async (videoPath, options) => {
|
|
451919
|
+
const startedAt = Date.now();
|
|
451884
451920
|
try {
|
|
451885
451921
|
if (options.output) {
|
|
451886
451922
|
validateOutputPath(options.output);
|
|
@@ -451897,16 +451933,19 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
|
|
|
451897
451933
|
const outputPath = options.output || `${name}-cut${ext}`;
|
|
451898
451934
|
const useGemini = options.useGemini || false;
|
|
451899
451935
|
if (options.dryRun) {
|
|
451900
|
-
|
|
451901
|
-
dryRun: true,
|
|
451936
|
+
outputSuccess({
|
|
451902
451937
|
command: "edit silence-cut",
|
|
451903
|
-
|
|
451904
|
-
|
|
451905
|
-
|
|
451906
|
-
|
|
451907
|
-
|
|
451908
|
-
|
|
451909
|
-
|
|
451938
|
+
startedAt,
|
|
451939
|
+
dryRun: true,
|
|
451940
|
+
data: {
|
|
451941
|
+
params: {
|
|
451942
|
+
videoPath: absVideoPath,
|
|
451943
|
+
noiseThreshold: parseFloat(options.noise),
|
|
451944
|
+
minDuration: parseFloat(options.minDuration),
|
|
451945
|
+
padding: parseFloat(options.padding),
|
|
451946
|
+
useGemini,
|
|
451947
|
+
analyzeOnly: options.analyzeOnly || false
|
|
451948
|
+
}
|
|
451910
451949
|
}
|
|
451911
451950
|
});
|
|
451912
451951
|
return;
|
|
@@ -451931,13 +451970,16 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
|
|
|
451931
451970
|
}
|
|
451932
451971
|
spinner2.succeed(source_default.green("Silence detection complete"));
|
|
451933
451972
|
if (isJsonMode()) {
|
|
451934
|
-
|
|
451935
|
-
|
|
451936
|
-
|
|
451937
|
-
|
|
451938
|
-
|
|
451939
|
-
|
|
451940
|
-
|
|
451973
|
+
outputSuccess({
|
|
451974
|
+
command: "edit silence-cut",
|
|
451975
|
+
startedAt,
|
|
451976
|
+
data: {
|
|
451977
|
+
method: result.method,
|
|
451978
|
+
totalDuration: result.totalDuration,
|
|
451979
|
+
silentPeriods: result.silentPeriods,
|
|
451980
|
+
silentDuration: result.silentDuration,
|
|
451981
|
+
outputPath: result.outputPath
|
|
451982
|
+
}
|
|
451941
451983
|
});
|
|
451942
451984
|
return;
|
|
451943
451985
|
}
|
|
@@ -451975,6 +452017,7 @@ Examples:
|
|
|
451975
452017
|
$ vibe ed cap video.mp4 --dry-run --json
|
|
451976
452018
|
|
|
451977
452019
|
Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoPath, options) => {
|
|
452020
|
+
const startedAt = Date.now();
|
|
451978
452021
|
try {
|
|
451979
452022
|
if (options.output) {
|
|
451980
452023
|
validateOutputPath(options.output);
|
|
@@ -451987,16 +452030,19 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
451987
452030
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
451988
452031
|
}
|
|
451989
452032
|
if (options.dryRun) {
|
|
451990
|
-
|
|
451991
|
-
dryRun: true,
|
|
452033
|
+
outputSuccess({
|
|
451992
452034
|
command: "edit caption",
|
|
451993
|
-
|
|
451994
|
-
|
|
451995
|
-
|
|
451996
|
-
|
|
451997
|
-
|
|
451998
|
-
|
|
451999
|
-
|
|
452035
|
+
startedAt,
|
|
452036
|
+
dryRun: true,
|
|
452037
|
+
data: {
|
|
452038
|
+
params: {
|
|
452039
|
+
videoPath: absVideoPath,
|
|
452040
|
+
style: options.style,
|
|
452041
|
+
fontSize: options.fontSize ? parseInt(options.fontSize) : void 0,
|
|
452042
|
+
fontColor: options.color,
|
|
452043
|
+
language: options.language,
|
|
452044
|
+
position: options.position
|
|
452045
|
+
}
|
|
452000
452046
|
}
|
|
452001
452047
|
});
|
|
452002
452048
|
return;
|
|
@@ -452025,12 +452071,15 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452025
452071
|
}
|
|
452026
452072
|
spinner2.succeed(source_default.green("Captions applied"));
|
|
452027
452073
|
if (isJsonMode()) {
|
|
452028
|
-
|
|
452029
|
-
|
|
452030
|
-
|
|
452031
|
-
|
|
452032
|
-
|
|
452033
|
-
|
|
452074
|
+
outputSuccess({
|
|
452075
|
+
command: "edit caption",
|
|
452076
|
+
startedAt,
|
|
452077
|
+
data: {
|
|
452078
|
+
segmentCount: result.segmentCount,
|
|
452079
|
+
style: options.style || "bold",
|
|
452080
|
+
outputPath: result.outputPath,
|
|
452081
|
+
srtPath: result.srtPath
|
|
452082
|
+
}
|
|
452034
452083
|
});
|
|
452035
452084
|
return;
|
|
452036
452085
|
}
|
|
@@ -452049,6 +452098,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452049
452098
|
}
|
|
452050
452099
|
});
|
|
452051
452100
|
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) => {
|
|
452101
|
+
const startedAt = Date.now();
|
|
452052
452102
|
try {
|
|
452053
452103
|
if (options.output) {
|
|
452054
452104
|
validateOutputPath(options.output);
|
|
@@ -452061,13 +452111,16 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452061
452111
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
452062
452112
|
}
|
|
452063
452113
|
if (options.dryRun) {
|
|
452064
|
-
|
|
452065
|
-
dryRun: true,
|
|
452114
|
+
outputSuccess({
|
|
452066
452115
|
command: "edit noise-reduce",
|
|
452067
|
-
|
|
452068
|
-
|
|
452069
|
-
|
|
452070
|
-
|
|
452116
|
+
startedAt,
|
|
452117
|
+
dryRun: true,
|
|
452118
|
+
data: {
|
|
452119
|
+
params: {
|
|
452120
|
+
inputPath: absInputPath,
|
|
452121
|
+
strength: options.strength,
|
|
452122
|
+
noiseFloor: options.noiseFloor ? parseFloat(options.noiseFloor) : void 0
|
|
452123
|
+
}
|
|
452071
452124
|
}
|
|
452072
452125
|
});
|
|
452073
452126
|
return;
|
|
@@ -452088,11 +452141,14 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452088
452141
|
}
|
|
452089
452142
|
spinner2.succeed(source_default.green("Noise reduction complete"));
|
|
452090
452143
|
if (isJsonMode()) {
|
|
452091
|
-
|
|
452092
|
-
|
|
452093
|
-
|
|
452094
|
-
|
|
452095
|
-
|
|
452144
|
+
outputSuccess({
|
|
452145
|
+
command: "edit noise-reduce",
|
|
452146
|
+
startedAt,
|
|
452147
|
+
data: {
|
|
452148
|
+
inputDuration: result.inputDuration,
|
|
452149
|
+
strength: options.strength || "medium",
|
|
452150
|
+
outputPath: result.outputPath
|
|
452151
|
+
}
|
|
452096
452152
|
});
|
|
452097
452153
|
return;
|
|
452098
452154
|
}
|
|
@@ -452108,6 +452164,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452108
452164
|
}
|
|
452109
452165
|
});
|
|
452110
452166
|
aiCommand.command("fade").description("Apply fade in/out effects to video (FFmpeg only, no API key needed)").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-faded.<ext>)").option("--fade-in <seconds>", "Fade-in duration in seconds (default: 1)", "1").option("--fade-out <seconds>", "Fade-out duration in seconds (default: 1)", "1").option("--audio-only", "Apply fade to audio only (video stream copied)").option("--video-only", "Apply fade to video only (audio stream copied)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
|
|
452167
|
+
const startedAt = Date.now();
|
|
452111
452168
|
try {
|
|
452112
452169
|
if (options.output) {
|
|
452113
452170
|
validateOutputPath(options.output);
|
|
@@ -452120,15 +452177,18 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452120
452177
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
452121
452178
|
}
|
|
452122
452179
|
if (options.dryRun) {
|
|
452123
|
-
|
|
452124
|
-
dryRun: true,
|
|
452180
|
+
outputSuccess({
|
|
452125
452181
|
command: "edit fade",
|
|
452126
|
-
|
|
452127
|
-
|
|
452128
|
-
|
|
452129
|
-
|
|
452130
|
-
|
|
452131
|
-
|
|
452182
|
+
startedAt,
|
|
452183
|
+
dryRun: true,
|
|
452184
|
+
data: {
|
|
452185
|
+
params: {
|
|
452186
|
+
videoPath: absVideoPath,
|
|
452187
|
+
fadeIn: parseFloat(options.fadeIn),
|
|
452188
|
+
fadeOut: parseFloat(options.fadeOut),
|
|
452189
|
+
audioOnly: options.audioOnly || false,
|
|
452190
|
+
videoOnly: options.videoOnly || false
|
|
452191
|
+
}
|
|
452132
452192
|
}
|
|
452133
452193
|
});
|
|
452134
452194
|
return;
|
|
@@ -452151,12 +452211,15 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452151
452211
|
}
|
|
452152
452212
|
spinner2.succeed(source_default.green("Fade effects applied"));
|
|
452153
452213
|
if (isJsonMode()) {
|
|
452154
|
-
|
|
452155
|
-
|
|
452156
|
-
|
|
452157
|
-
|
|
452158
|
-
|
|
452159
|
-
|
|
452214
|
+
outputSuccess({
|
|
452215
|
+
command: "edit fade",
|
|
452216
|
+
startedAt,
|
|
452217
|
+
data: {
|
|
452218
|
+
totalDuration: result.totalDuration,
|
|
452219
|
+
fadeInApplied: result.fadeInApplied,
|
|
452220
|
+
fadeOutApplied: result.fadeOutApplied,
|
|
452221
|
+
outputPath: result.outputPath
|
|
452222
|
+
}
|
|
452160
452223
|
});
|
|
452161
452224
|
return;
|
|
452162
452225
|
}
|
|
@@ -452173,6 +452236,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452173
452236
|
}
|
|
452174
452237
|
});
|
|
452175
452238
|
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) => {
|
|
452239
|
+
const startedAt = Date.now();
|
|
452176
452240
|
try {
|
|
452177
452241
|
if (options.output) {
|
|
452178
452242
|
validateOutputPath(options.output);
|
|
@@ -452185,14 +452249,17 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452185
452249
|
exitWithError(notFoundError(absSrtPath));
|
|
452186
452250
|
}
|
|
452187
452251
|
if (options.dryRun) {
|
|
452188
|
-
|
|
452189
|
-
dryRun: true,
|
|
452252
|
+
outputSuccess({
|
|
452190
452253
|
command: "edit translate-srt",
|
|
452191
|
-
|
|
452192
|
-
|
|
452193
|
-
|
|
452194
|
-
|
|
452195
|
-
|
|
452254
|
+
startedAt,
|
|
452255
|
+
dryRun: true,
|
|
452256
|
+
data: {
|
|
452257
|
+
params: {
|
|
452258
|
+
srtPath: absSrtPath,
|
|
452259
|
+
targetLanguage: options.target,
|
|
452260
|
+
provider: options.provider || "claude",
|
|
452261
|
+
sourceLanguage: options.source
|
|
452262
|
+
}
|
|
452196
452263
|
}
|
|
452197
452264
|
});
|
|
452198
452265
|
return;
|
|
@@ -452222,12 +452289,15 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452222
452289
|
}
|
|
452223
452290
|
spinner2.succeed(source_default.green("Translation complete"));
|
|
452224
452291
|
if (isJsonMode()) {
|
|
452225
|
-
|
|
452226
|
-
|
|
452227
|
-
|
|
452228
|
-
|
|
452229
|
-
|
|
452230
|
-
|
|
452292
|
+
outputSuccess({
|
|
452293
|
+
command: "edit translate-srt",
|
|
452294
|
+
startedAt,
|
|
452295
|
+
data: {
|
|
452296
|
+
segmentCount: result.segmentCount,
|
|
452297
|
+
sourceLanguage: result.sourceLanguage,
|
|
452298
|
+
targetLanguage: result.targetLanguage,
|
|
452299
|
+
outputPath: result.outputPath
|
|
452300
|
+
}
|
|
452231
452301
|
});
|
|
452232
452302
|
return;
|
|
452233
452303
|
}
|
|
@@ -452244,6 +452314,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452244
452314
|
}
|
|
452245
452315
|
});
|
|
452246
452316
|
aiCommand.command("jump-cut").description("Remove filler words (um, uh, like, etc.) from video using Whisper word-level timestamps").argument("<video>", "Video file path").option("-o, --output <path>", "Output file path (default: <name>-jumpcut.<ext>)").option("--fillers <words>", "Comma-separated filler words to detect").option("--padding <seconds>", "Padding around cuts in seconds (default: 0.05)", "0.05").option("-l, --language <lang>", "Language code for transcription (e.g., en, ko)").option("--analyze-only", "Only detect fillers, don't cut").option("-k, --api-key <key>", "OpenAI API key (or set OPENAI_API_KEY env)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
|
|
452317
|
+
const startedAt = Date.now();
|
|
452247
452318
|
try {
|
|
452248
452319
|
if (options.output) {
|
|
452249
452320
|
validateOutputPath(options.output);
|
|
@@ -452258,15 +452329,18 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452258
452329
|
}
|
|
452259
452330
|
if (options.dryRun) {
|
|
452260
452331
|
const fillers2 = options.fillers ? options.fillers.split(",").map((f) => f.trim()) : void 0;
|
|
452261
|
-
|
|
452262
|
-
dryRun: true,
|
|
452332
|
+
outputSuccess({
|
|
452263
452333
|
command: "edit jump-cut",
|
|
452264
|
-
|
|
452265
|
-
|
|
452266
|
-
|
|
452267
|
-
|
|
452268
|
-
|
|
452269
|
-
|
|
452334
|
+
startedAt,
|
|
452335
|
+
dryRun: true,
|
|
452336
|
+
data: {
|
|
452337
|
+
params: {
|
|
452338
|
+
videoPath: absVideoPath,
|
|
452339
|
+
fillers: fillers2,
|
|
452340
|
+
padding: parseFloat(options.padding),
|
|
452341
|
+
language: options.language,
|
|
452342
|
+
analyzeOnly: options.analyzeOnly || false
|
|
452343
|
+
}
|
|
452270
452344
|
}
|
|
452271
452345
|
});
|
|
452272
452346
|
return;
|
|
@@ -452295,13 +452369,16 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452295
452369
|
}
|
|
452296
452370
|
spinner2.succeed(source_default.green("Filler detection complete"));
|
|
452297
452371
|
if (isJsonMode()) {
|
|
452298
|
-
|
|
452299
|
-
|
|
452300
|
-
|
|
452301
|
-
|
|
452302
|
-
|
|
452303
|
-
|
|
452304
|
-
|
|
452372
|
+
outputSuccess({
|
|
452373
|
+
command: "edit jump-cut",
|
|
452374
|
+
startedAt,
|
|
452375
|
+
data: {
|
|
452376
|
+
totalDuration: result.totalDuration,
|
|
452377
|
+
fillerCount: result.fillerCount,
|
|
452378
|
+
fillerDuration: result.fillerDuration,
|
|
452379
|
+
fillers: result.fillers,
|
|
452380
|
+
outputPath: result.outputPath
|
|
452381
|
+
}
|
|
452305
452382
|
});
|
|
452306
452383
|
return;
|
|
452307
452384
|
}
|
|
@@ -453446,6 +453523,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453446
453523
|
registerEditCommands(editCommand);
|
|
453447
453524
|
registerFillGapsCommand(editCommand);
|
|
453448
453525
|
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) => {
|
|
453526
|
+
const startedAt = Date.now();
|
|
453449
453527
|
try {
|
|
453450
453528
|
if (options.style) rejectControlChars(options.style);
|
|
453451
453529
|
if (options.output) {
|
|
@@ -453461,13 +453539,16 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453461
453539
|
exitWithError(notFoundError("FFmpeg not found. Install with: brew install ffmpeg"));
|
|
453462
453540
|
}
|
|
453463
453541
|
if (options.dryRun) {
|
|
453464
|
-
|
|
453465
|
-
dryRun: true,
|
|
453542
|
+
outputSuccess({
|
|
453466
453543
|
command: "edit grade",
|
|
453467
|
-
|
|
453468
|
-
|
|
453469
|
-
|
|
453470
|
-
|
|
453544
|
+
startedAt,
|
|
453545
|
+
dryRun: true,
|
|
453546
|
+
data: {
|
|
453547
|
+
params: {
|
|
453548
|
+
videoPath: resolve29(process.cwd(), videoPath),
|
|
453549
|
+
style: options.style || options.preset,
|
|
453550
|
+
analyzeOnly: options.analyzeOnly || false
|
|
453551
|
+
}
|
|
453471
453552
|
}
|
|
453472
453553
|
});
|
|
453473
453554
|
return;
|
|
@@ -453493,12 +453574,15 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453493
453574
|
if (isJsonMode()) {
|
|
453494
453575
|
const absPath2 = resolve29(process.cwd(), videoPath);
|
|
453495
453576
|
const gradeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
|
|
453496
|
-
|
|
453497
|
-
|
|
453498
|
-
|
|
453499
|
-
|
|
453500
|
-
|
|
453501
|
-
|
|
453577
|
+
outputSuccess({
|
|
453578
|
+
command: "edit grade",
|
|
453579
|
+
startedAt,
|
|
453580
|
+
data: {
|
|
453581
|
+
style: options.preset || options.style,
|
|
453582
|
+
description: gradeResult.description,
|
|
453583
|
+
ffmpegFilter: gradeResult.ffmpegFilter,
|
|
453584
|
+
outputPath: options.analyzeOnly ? void 0 : gradeOutputPath
|
|
453585
|
+
}
|
|
453502
453586
|
});
|
|
453503
453587
|
return;
|
|
453504
453588
|
}
|
|
@@ -453527,6 +453611,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453527
453611
|
}
|
|
453528
453612
|
});
|
|
453529
453613
|
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) => {
|
|
453614
|
+
const startedAt = Date.now();
|
|
453530
453615
|
try {
|
|
453531
453616
|
if (!options.text || options.text.length === 0) {
|
|
453532
453617
|
exitWithError(usageError("At least one --text option is required", 'Example: vibe edit text-overlay video.mp4 -t "NEXUS AI" --style center-bold'));
|
|
@@ -453539,18 +453624,21 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453539
453624
|
exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
|
|
453540
453625
|
}
|
|
453541
453626
|
if (options.dryRun) {
|
|
453542
|
-
|
|
453543
|
-
dryRun: true,
|
|
453627
|
+
outputSuccess({
|
|
453544
453628
|
command: "edit text-overlay",
|
|
453545
|
-
|
|
453546
|
-
|
|
453547
|
-
|
|
453548
|
-
|
|
453549
|
-
|
|
453550
|
-
|
|
453551
|
-
|
|
453552
|
-
|
|
453553
|
-
|
|
453629
|
+
startedAt,
|
|
453630
|
+
dryRun: true,
|
|
453631
|
+
data: {
|
|
453632
|
+
params: {
|
|
453633
|
+
videoPath: resolve29(process.cwd(), videoPath),
|
|
453634
|
+
texts: options.text,
|
|
453635
|
+
style: options.style,
|
|
453636
|
+
fontSize: options.fontSize ? parseInt(options.fontSize) : void 0,
|
|
453637
|
+
fontColor: options.fontColor,
|
|
453638
|
+
fade: parseFloat(options.fade),
|
|
453639
|
+
start: parseFloat(options.start),
|
|
453640
|
+
end: options.end ? parseFloat(options.end) : void 0
|
|
453641
|
+
}
|
|
453554
453642
|
}
|
|
453555
453643
|
});
|
|
453556
453644
|
return;
|
|
@@ -453575,11 +453663,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453575
453663
|
}
|
|
453576
453664
|
spinner2.succeed(source_default.green("Text overlays applied"));
|
|
453577
453665
|
if (isJsonMode()) {
|
|
453578
|
-
|
|
453579
|
-
|
|
453580
|
-
|
|
453581
|
-
|
|
453582
|
-
|
|
453666
|
+
outputSuccess({
|
|
453667
|
+
command: "edit text-overlay",
|
|
453668
|
+
startedAt,
|
|
453669
|
+
data: {
|
|
453670
|
+
style: options.style,
|
|
453671
|
+
texts: options.text,
|
|
453672
|
+
outputPath: result.outputPath
|
|
453673
|
+
}
|
|
453583
453674
|
});
|
|
453584
453675
|
return;
|
|
453585
453676
|
}
|
|
@@ -453596,6 +453687,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453596
453687
|
}
|
|
453597
453688
|
});
|
|
453598
453689
|
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) => {
|
|
453690
|
+
const startedAt = Date.now();
|
|
453599
453691
|
try {
|
|
453600
453692
|
if (options.output) {
|
|
453601
453693
|
validateOutputPath(options.output);
|
|
@@ -453604,15 +453696,18 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453604
453696
|
exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
|
|
453605
453697
|
}
|
|
453606
453698
|
if (options.dryRun) {
|
|
453607
|
-
|
|
453608
|
-
dryRun: true,
|
|
453699
|
+
outputSuccess({
|
|
453609
453700
|
command: "edit speed-ramp",
|
|
453610
|
-
|
|
453611
|
-
|
|
453612
|
-
|
|
453613
|
-
|
|
453614
|
-
|
|
453615
|
-
|
|
453701
|
+
startedAt,
|
|
453702
|
+
dryRun: true,
|
|
453703
|
+
data: {
|
|
453704
|
+
params: {
|
|
453705
|
+
videoPath: resolve29(process.cwd(), videoPath),
|
|
453706
|
+
style: options.style,
|
|
453707
|
+
minSpeed: parseFloat(options.minSpeed),
|
|
453708
|
+
maxSpeed: parseFloat(options.maxSpeed),
|
|
453709
|
+
analyzeOnly: options.analyzeOnly || false
|
|
453710
|
+
}
|
|
453616
453711
|
}
|
|
453617
453712
|
});
|
|
453618
453713
|
return;
|
|
@@ -453665,11 +453760,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453665
453760
|
if (isJsonMode()) {
|
|
453666
453761
|
const avgSpeed2 = speedResult.keyframes.reduce((sum, kf) => sum + kf.speed, 0) / speedResult.keyframes.length;
|
|
453667
453762
|
const speedRampOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
|
|
453668
|
-
|
|
453669
|
-
|
|
453670
|
-
|
|
453671
|
-
|
|
453672
|
-
|
|
453763
|
+
outputSuccess({
|
|
453764
|
+
command: "edit speed-ramp",
|
|
453765
|
+
startedAt,
|
|
453766
|
+
data: {
|
|
453767
|
+
keyframes: speedResult.keyframes,
|
|
453768
|
+
avgSpeed: avgSpeed2,
|
|
453769
|
+
outputPath: options.analyzeOnly ? void 0 : speedRampOutputPath
|
|
453770
|
+
}
|
|
453673
453771
|
});
|
|
453674
453772
|
return;
|
|
453675
453773
|
}
|
|
@@ -453709,6 +453807,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453709
453807
|
}
|
|
453710
453808
|
});
|
|
453711
453809
|
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) => {
|
|
453810
|
+
const startedAt = Date.now();
|
|
453712
453811
|
try {
|
|
453713
453812
|
if (options.output) {
|
|
453714
453813
|
validateOutputPath(options.output);
|
|
@@ -453717,14 +453816,17 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453717
453816
|
exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
|
|
453718
453817
|
}
|
|
453719
453818
|
if (options.dryRun) {
|
|
453720
|
-
|
|
453721
|
-
dryRun: true,
|
|
453819
|
+
outputSuccess({
|
|
453722
453820
|
command: "edit reframe",
|
|
453723
|
-
|
|
453724
|
-
|
|
453725
|
-
|
|
453726
|
-
|
|
453727
|
-
|
|
453821
|
+
startedAt,
|
|
453822
|
+
dryRun: true,
|
|
453823
|
+
data: {
|
|
453824
|
+
params: {
|
|
453825
|
+
videoPath: resolve29(process.cwd(), videoPath),
|
|
453826
|
+
aspect: options.aspect,
|
|
453827
|
+
focus: options.focus,
|
|
453828
|
+
analyzeOnly: options.analyzeOnly || false
|
|
453829
|
+
}
|
|
453728
453830
|
}
|
|
453729
453831
|
});
|
|
453730
453832
|
return;
|
|
@@ -453792,13 +453894,16 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453792
453894
|
spinner2.succeed(source_default.green(`Analyzed ${cropKeyframes.length} keyframes`));
|
|
453793
453895
|
if (isJsonMode()) {
|
|
453794
453896
|
const reframeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
|
|
453795
|
-
|
|
453796
|
-
|
|
453797
|
-
|
|
453798
|
-
|
|
453799
|
-
|
|
453800
|
-
|
|
453801
|
-
|
|
453897
|
+
outputSuccess({
|
|
453898
|
+
command: "edit reframe",
|
|
453899
|
+
startedAt,
|
|
453900
|
+
data: {
|
|
453901
|
+
sourceWidth,
|
|
453902
|
+
sourceHeight,
|
|
453903
|
+
aspect: options.aspect,
|
|
453904
|
+
cropKeyframes,
|
|
453905
|
+
outputPath: options.analyzeOnly ? void 0 : reframeOutputPath
|
|
453906
|
+
}
|
|
453802
453907
|
});
|
|
453803
453908
|
return;
|
|
453804
453909
|
}
|
|
@@ -453849,6 +453954,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453849
453954
|
}
|
|
453850
453955
|
});
|
|
453851
453956
|
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) => {
|
|
453957
|
+
const startedAt = Date.now();
|
|
453852
453958
|
try {
|
|
453853
453959
|
if (args.length < 2) {
|
|
453854
453960
|
exitWithError(usageError("Need at least one image and a prompt"));
|
|
@@ -453864,16 +453970,19 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453864
453970
|
exitWithError(usageError("Grok supports only 1 input image for editing.", "Use -p gemini (up to 14 images) or -p openai (up to 16 images) for multi-image editing."));
|
|
453865
453971
|
}
|
|
453866
453972
|
if (options.dryRun) {
|
|
453867
|
-
|
|
453868
|
-
dryRun: true,
|
|
453973
|
+
outputSuccess({
|
|
453869
453974
|
command: "edit image",
|
|
453870
|
-
|
|
453871
|
-
|
|
453872
|
-
|
|
453873
|
-
|
|
453874
|
-
|
|
453875
|
-
|
|
453876
|
-
|
|
453975
|
+
startedAt,
|
|
453976
|
+
dryRun: true,
|
|
453977
|
+
data: {
|
|
453978
|
+
params: {
|
|
453979
|
+
imagePaths: imagePaths.map((p) => resolve29(process.cwd(), p)),
|
|
453980
|
+
prompt: prompt3,
|
|
453981
|
+
provider,
|
|
453982
|
+
model: options.model,
|
|
453983
|
+
ratio: options.ratio,
|
|
453984
|
+
size: options.size
|
|
453985
|
+
}
|
|
453877
453986
|
}
|
|
453878
453987
|
});
|
|
453879
453988
|
return;
|
|
@@ -453951,11 +454060,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453951
454060
|
};
|
|
453952
454061
|
const resultModel = result.model;
|
|
453953
454062
|
if (isJsonMode()) {
|
|
453954
|
-
|
|
453955
|
-
|
|
453956
|
-
|
|
453957
|
-
|
|
453958
|
-
|
|
454063
|
+
outputSuccess({
|
|
454064
|
+
command: "edit image",
|
|
454065
|
+
startedAt,
|
|
454066
|
+
data: {
|
|
454067
|
+
provider,
|
|
454068
|
+
model: resultModel || options.model,
|
|
454069
|
+
outputPath
|
|
454070
|
+
}
|
|
453959
454071
|
});
|
|
453960
454072
|
await saveImage();
|
|
453961
454073
|
return;
|
|
@@ -453971,6 +454083,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453971
454083
|
}
|
|
453972
454084
|
});
|
|
453973
454085
|
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) => {
|
|
454086
|
+
const startedAt = Date.now();
|
|
453974
454087
|
try {
|
|
453975
454088
|
if (options.output) {
|
|
453976
454089
|
validateOutputPath(options.output);
|
|
@@ -453981,14 +454094,17 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453981
454094
|
exitWithError(usageError("Factor must be 2, 4, or 8"));
|
|
453982
454095
|
}
|
|
453983
454096
|
if (options.dryRun) {
|
|
453984
|
-
|
|
453985
|
-
dryRun: true,
|
|
454097
|
+
outputSuccess({
|
|
453986
454098
|
command: "edit interpolate",
|
|
453987
|
-
|
|
453988
|
-
|
|
453989
|
-
|
|
453990
|
-
|
|
453991
|
-
|
|
454099
|
+
startedAt,
|
|
454100
|
+
dryRun: true,
|
|
454101
|
+
data: {
|
|
454102
|
+
params: {
|
|
454103
|
+
videoPath: absPath,
|
|
454104
|
+
factor,
|
|
454105
|
+
fps: options.fps ? parseInt(options.fps) : void 0,
|
|
454106
|
+
quality: options.quality
|
|
454107
|
+
}
|
|
453992
454108
|
}
|
|
453993
454109
|
});
|
|
453994
454110
|
return;
|
|
@@ -454015,12 +454131,15 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
454015
454131
|
await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 6e5 });
|
|
454016
454132
|
spinner2.succeed(source_default.green(`Created ${factor}x slow motion`));
|
|
454017
454133
|
if (isJsonMode()) {
|
|
454018
|
-
|
|
454019
|
-
|
|
454020
|
-
|
|
454021
|
-
|
|
454022
|
-
|
|
454023
|
-
|
|
454134
|
+
outputSuccess({
|
|
454135
|
+
command: "edit interpolate",
|
|
454136
|
+
startedAt,
|
|
454137
|
+
data: {
|
|
454138
|
+
originalFps,
|
|
454139
|
+
targetFps,
|
|
454140
|
+
factor,
|
|
454141
|
+
outputPath
|
|
454142
|
+
}
|
|
454024
454143
|
});
|
|
454025
454144
|
return;
|
|
454026
454145
|
}
|
|
@@ -454046,6 +454165,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
454046
454165
|
}
|
|
454047
454166
|
});
|
|
454048
454167
|
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) => {
|
|
454168
|
+
const startedAt = Date.now();
|
|
454049
454169
|
try {
|
|
454050
454170
|
if (options.output) {
|
|
454051
454171
|
validateOutputPath(options.output);
|
|
@@ -454056,14 +454176,17 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
454056
454176
|
exitWithError(usageError("Scale must be 2 or 4"));
|
|
454057
454177
|
}
|
|
454058
454178
|
if (options.dryRun) {
|
|
454059
|
-
|
|
454060
|
-
dryRun: true,
|
|
454179
|
+
outputSuccess({
|
|
454061
454180
|
command: "edit upscale-video",
|
|
454062
|
-
|
|
454063
|
-
|
|
454064
|
-
|
|
454065
|
-
|
|
454066
|
-
|
|
454181
|
+
startedAt,
|
|
454182
|
+
dryRun: true,
|
|
454183
|
+
data: {
|
|
454184
|
+
params: {
|
|
454185
|
+
videoPath: absPath,
|
|
454186
|
+
scale,
|
|
454187
|
+
model: options.model,
|
|
454188
|
+
ffmpeg: options.ffmpeg || false
|
|
454189
|
+
}
|
|
454067
454190
|
}
|
|
454068
454191
|
});
|
|
454069
454192
|
return;
|
|
@@ -454089,10 +454212,13 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
454089
454212
|
await execSafe("ffmpeg", ["-i", absPath, "-vf", `scale=${newWidth}:${newHeight}:flags=lanczos`, "-c:a", "copy", outputPath, "-y"]);
|
|
454090
454213
|
spinner3.succeed(source_default.green(`Upscaled to ${newWidth}x${newHeight}`));
|
|
454091
454214
|
if (isJsonMode()) {
|
|
454092
|
-
|
|
454093
|
-
|
|
454094
|
-
|
|
454095
|
-
|
|
454215
|
+
outputSuccess({
|
|
454216
|
+
command: "edit upscale-video",
|
|
454217
|
+
startedAt,
|
|
454218
|
+
data: {
|
|
454219
|
+
dimensions: `${newWidth}x${newHeight}`,
|
|
454220
|
+
outputPath
|
|
454221
|
+
}
|
|
454096
454222
|
});
|
|
454097
454223
|
return;
|
|
454098
454224
|
}
|
|
@@ -454797,21 +454923,25 @@ Score each category 1-10. For fixable issues, provide an FFmpeg filter in autoFi
|
|
|
454797
454923
|
}
|
|
454798
454924
|
function registerReviewCommand(aiCommand) {
|
|
454799
454925
|
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) => {
|
|
454926
|
+
const startedAt = Date.now();
|
|
454800
454927
|
try {
|
|
454801
454928
|
if (options.output) {
|
|
454802
454929
|
validateOutputPath(options.output);
|
|
454803
454930
|
}
|
|
454804
454931
|
if (options.dryRun) {
|
|
454805
|
-
|
|
454806
|
-
dryRun: true,
|
|
454932
|
+
outputSuccess({
|
|
454807
454933
|
command: "ai review",
|
|
454808
|
-
|
|
454809
|
-
|
|
454810
|
-
|
|
454811
|
-
|
|
454812
|
-
|
|
454813
|
-
|
|
454814
|
-
|
|
454934
|
+
startedAt,
|
|
454935
|
+
dryRun: true,
|
|
454936
|
+
data: {
|
|
454937
|
+
params: {
|
|
454938
|
+
videoPath,
|
|
454939
|
+
storyboard: options.storyboard,
|
|
454940
|
+
autoApply: options.autoApply ?? false,
|
|
454941
|
+
verify: options.verify ?? false,
|
|
454942
|
+
model: options.model,
|
|
454943
|
+
output: options.output
|
|
454944
|
+
}
|
|
454815
454945
|
}
|
|
454816
454946
|
});
|
|
454817
454947
|
return;
|
|
@@ -455079,27 +455209,31 @@ Use this image analysis to inform the color palette, typography placement, and o
|
|
|
455079
455209
|
}
|
|
455080
455210
|
function registerMotionCommand(aiCommand) {
|
|
455081
455211
|
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) => {
|
|
455212
|
+
const startedAt = Date.now();
|
|
455082
455213
|
try {
|
|
455083
455214
|
if (options.output) {
|
|
455084
455215
|
validateOutputPath(options.output);
|
|
455085
455216
|
}
|
|
455086
455217
|
if (options.dryRun) {
|
|
455087
|
-
|
|
455218
|
+
outputSuccess({
|
|
455219
|
+
command: "generate motion",
|
|
455220
|
+
startedAt,
|
|
455088
455221
|
dryRun: true,
|
|
455089
|
-
|
|
455090
|
-
|
|
455091
|
-
|
|
455092
|
-
|
|
455093
|
-
|
|
455094
|
-
|
|
455095
|
-
|
|
455096
|
-
|
|
455097
|
-
|
|
455098
|
-
|
|
455099
|
-
|
|
455100
|
-
|
|
455101
|
-
|
|
455102
|
-
|
|
455222
|
+
data: {
|
|
455223
|
+
params: {
|
|
455224
|
+
description: description.slice(0, 200),
|
|
455225
|
+
duration: options.duration,
|
|
455226
|
+
width: options.width,
|
|
455227
|
+
height: options.height,
|
|
455228
|
+
fps: options.fps,
|
|
455229
|
+
style: options.style,
|
|
455230
|
+
render: options.render ?? false,
|
|
455231
|
+
video: options.video,
|
|
455232
|
+
image: options.image,
|
|
455233
|
+
fromTsx: options.fromTsx,
|
|
455234
|
+
model: options.model,
|
|
455235
|
+
output: options.output
|
|
455236
|
+
}
|
|
455103
455237
|
}
|
|
455104
455238
|
});
|
|
455105
455239
|
return;
|
|
@@ -455213,20 +455347,24 @@ async function executeSoundEffect(options) {
|
|
|
455213
455347
|
}
|
|
455214
455348
|
function registerSoundEffectCommand(parent) {
|
|
455215
455349
|
parent.command("sound-effect").description("Generate sound effect using ElevenLabs").argument("<prompt>", "Description of the sound effect").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-o, --output <path>", "Output audio file path", "sound-effect.mp3").option("-d, --duration <seconds>", "Duration in seconds (0.5-22, default: auto)").option("--prompt-influence <value>", "Prompt influence (0-1, default: 0.3)").option("--dry-run", "Preview parameters without executing").action(async (prompt3, options) => {
|
|
455350
|
+
const startedAt = Date.now();
|
|
455216
455351
|
try {
|
|
455217
455352
|
rejectControlChars(prompt3);
|
|
455218
455353
|
if (options.output) {
|
|
455219
455354
|
validateOutputPath(options.output);
|
|
455220
455355
|
}
|
|
455221
455356
|
if (options.dryRun) {
|
|
455222
|
-
|
|
455223
|
-
dryRun: true,
|
|
455357
|
+
outputSuccess({
|
|
455224
455358
|
command: "generate sound-effect",
|
|
455225
|
-
|
|
455226
|
-
|
|
455227
|
-
|
|
455228
|
-
|
|
455229
|
-
|
|
455359
|
+
startedAt,
|
|
455360
|
+
dryRun: true,
|
|
455361
|
+
data: {
|
|
455362
|
+
params: {
|
|
455363
|
+
prompt: prompt3,
|
|
455364
|
+
duration: options.duration,
|
|
455365
|
+
promptInfluence: options.promptInfluence,
|
|
455366
|
+
output: options.output
|
|
455367
|
+
}
|
|
455230
455368
|
}
|
|
455231
455369
|
});
|
|
455232
455370
|
return;
|
|
@@ -455253,7 +455391,11 @@ function registerSoundEffectCommand(parent) {
|
|
|
455253
455391
|
await writeFile22(outputPath, result.audioBuffer);
|
|
455254
455392
|
spinner2.succeed(source_default.green("Sound effect generated"));
|
|
455255
455393
|
if (isJsonMode()) {
|
|
455256
|
-
|
|
455394
|
+
outputSuccess({
|
|
455395
|
+
command: "generate sound-effect",
|
|
455396
|
+
startedAt,
|
|
455397
|
+
data: { outputPath }
|
|
455398
|
+
});
|
|
455257
455399
|
return;
|
|
455258
455400
|
}
|
|
455259
455401
|
console.log(source_default.green(`Saved to: ${outputPath}`));
|
|
@@ -455303,6 +455445,7 @@ async function executeMusicStatus(options) {
|
|
|
455303
455445
|
}
|
|
455304
455446
|
function registerMusicStatusCommand(parent) {
|
|
455305
455447
|
parent.command("music-status", { hidden: true }).description("Check music generation status").argument("<task-id>", "Task ID from music generation").option("-k, --api-key <key>", "Replicate API token (or set REPLICATE_API_TOKEN env)").action(async (taskId, options) => {
|
|
455448
|
+
const startedAt = Date.now();
|
|
455306
455449
|
try {
|
|
455307
455450
|
const apiKey = await requireApiKey(
|
|
455308
455451
|
"REPLICATE_API_TOKEN",
|
|
@@ -455314,12 +455457,15 @@ function registerMusicStatusCommand(parent) {
|
|
|
455314
455457
|
const result = await replicate.getMusicStatus(taskId);
|
|
455315
455458
|
if (isJsonMode()) {
|
|
455316
455459
|
const status = result.audioUrl ? "completed" : result.error ? "failed" : "processing";
|
|
455317
|
-
|
|
455318
|
-
|
|
455319
|
-
|
|
455320
|
-
|
|
455321
|
-
|
|
455322
|
-
|
|
455460
|
+
outputSuccess({
|
|
455461
|
+
command: "generate music-status",
|
|
455462
|
+
startedAt,
|
|
455463
|
+
data: {
|
|
455464
|
+
taskId,
|
|
455465
|
+
status,
|
|
455466
|
+
audioUrl: result.audioUrl,
|
|
455467
|
+
error: result.error
|
|
455468
|
+
}
|
|
455323
455469
|
});
|
|
455324
455470
|
return;
|
|
455325
455471
|
}
|
|
@@ -455357,6 +455503,7 @@ var init_music_status = __esm({
|
|
|
455357
455503
|
// ../cli/src/commands/generate/video-cancel.ts
|
|
455358
455504
|
function registerVideoCancelCommand(parent) {
|
|
455359
455505
|
parent.command("video-cancel", { hidden: true }).description("Cancel video generation (Grok or Runway)").argument("<task-id>", "Task ID to cancel").option("-p, --provider <provider>", "Provider: grok, runway", "grok").option("-k, --api-key <key>", "API key (or set XAI_API_KEY / RUNWAY_API_SECRET env)").action(async (taskId, options) => {
|
|
455506
|
+
const startedAt = Date.now();
|
|
455360
455507
|
try {
|
|
455361
455508
|
const provider = (options.provider || "grok").toLowerCase();
|
|
455362
455509
|
let success = false;
|
|
@@ -455369,7 +455516,11 @@ function registerVideoCancelCommand(parent) {
|
|
|
455369
455516
|
if (success) {
|
|
455370
455517
|
spinner2.succeed(source_default.green("Generation cancelled"));
|
|
455371
455518
|
if (isJsonMode()) {
|
|
455372
|
-
|
|
455519
|
+
outputSuccess({
|
|
455520
|
+
command: "generate video-cancel",
|
|
455521
|
+
startedAt,
|
|
455522
|
+
data: { taskId, provider: "grok", cancelled: true }
|
|
455523
|
+
});
|
|
455373
455524
|
return;
|
|
455374
455525
|
}
|
|
455375
455526
|
} else {
|
|
@@ -455389,7 +455540,11 @@ function registerVideoCancelCommand(parent) {
|
|
|
455389
455540
|
if (success) {
|
|
455390
455541
|
spinner2.succeed(source_default.green("Generation cancelled"));
|
|
455391
455542
|
if (isJsonMode()) {
|
|
455392
|
-
|
|
455543
|
+
outputSuccess({
|
|
455544
|
+
command: "generate video-cancel",
|
|
455545
|
+
startedAt,
|
|
455546
|
+
data: { taskId, provider: "runway", cancelled: true }
|
|
455547
|
+
});
|
|
455393
455548
|
return;
|
|
455394
455549
|
}
|
|
455395
455550
|
} else {
|
|
@@ -455462,16 +455617,18 @@ async function executeBackground(options) {
|
|
|
455462
455617
|
}
|
|
455463
455618
|
function registerBackgroundCommand(parent) {
|
|
455464
455619
|
parent.command("background").description("Generate video background using DALL-E").argument("<description>", "Background description").option("-k, --api-key <key>", "OpenAI API key (or set OPENAI_API_KEY env)").option("-o, --output <path>", "Output file path (downloads image)").option("-a, --aspect <ratio>", "Aspect ratio: 16:9, 9:16, 1:1", "16:9").option("--dry-run", "Preview parameters without executing").action(async (description, options) => {
|
|
455620
|
+
const startedAt = Date.now();
|
|
455465
455621
|
try {
|
|
455466
455622
|
rejectControlChars(description);
|
|
455467
455623
|
if (options.output) {
|
|
455468
455624
|
validateOutputPath(options.output);
|
|
455469
455625
|
}
|
|
455470
455626
|
if (options.dryRun) {
|
|
455471
|
-
|
|
455472
|
-
dryRun: true,
|
|
455627
|
+
outputSuccess({
|
|
455473
455628
|
command: "generate background",
|
|
455474
|
-
|
|
455629
|
+
startedAt,
|
|
455630
|
+
dryRun: true,
|
|
455631
|
+
data: { params: { description, aspect: options.aspect, output: options.output } }
|
|
455475
455632
|
});
|
|
455476
455633
|
return;
|
|
455477
455634
|
}
|
|
@@ -455506,7 +455663,11 @@ function registerBackgroundCommand(parent) {
|
|
|
455506
455663
|
await mkdir18(dirname25(outputPath), { recursive: true });
|
|
455507
455664
|
await writeFile23(outputPath, buffer);
|
|
455508
455665
|
}
|
|
455509
|
-
|
|
455666
|
+
outputSuccess({
|
|
455667
|
+
command: "generate background",
|
|
455668
|
+
startedAt,
|
|
455669
|
+
data: { imageUrl: img.url, outputPath }
|
|
455670
|
+
});
|
|
455510
455671
|
return;
|
|
455511
455672
|
}
|
|
455512
455673
|
console.log();
|
|
@@ -455603,6 +455764,7 @@ async function executeStoryboard(options) {
|
|
|
455603
455764
|
}
|
|
455604
455765
|
function registerStoryboardCommand(parent) {
|
|
455605
455766
|
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) => {
|
|
455767
|
+
const startedAt = Date.now();
|
|
455606
455768
|
try {
|
|
455607
455769
|
rejectControlChars(content);
|
|
455608
455770
|
if (options.output) {
|
|
@@ -455618,13 +455780,16 @@ function registerStoryboardCommand(parent) {
|
|
|
455618
455780
|
textContent2 = await readFile23(filePath, "utf-8");
|
|
455619
455781
|
}
|
|
455620
455782
|
if (options.dryRun) {
|
|
455621
|
-
|
|
455622
|
-
dryRun: true,
|
|
455783
|
+
outputSuccess({
|
|
455623
455784
|
command: "generate storyboard",
|
|
455624
|
-
|
|
455625
|
-
|
|
455626
|
-
|
|
455627
|
-
|
|
455785
|
+
startedAt,
|
|
455786
|
+
dryRun: true,
|
|
455787
|
+
data: {
|
|
455788
|
+
params: {
|
|
455789
|
+
content: textContent2.substring(0, 200),
|
|
455790
|
+
duration: options.duration,
|
|
455791
|
+
creativity
|
|
455792
|
+
}
|
|
455628
455793
|
}
|
|
455629
455794
|
});
|
|
455630
455795
|
return;
|
|
@@ -455656,16 +455821,23 @@ function registerStoryboardCommand(parent) {
|
|
|
455656
455821
|
const outputPath = resolve39(process.cwd(), options.output);
|
|
455657
455822
|
await writeFile24(outputPath, JSON.stringify(segments, null, 2), "utf-8");
|
|
455658
455823
|
if (isJsonMode()) {
|
|
455659
|
-
|
|
455660
|
-
|
|
455661
|
-
|
|
455662
|
-
|
|
455663
|
-
|
|
455824
|
+
outputSuccess({
|
|
455825
|
+
command: "generate storyboard",
|
|
455826
|
+
startedAt,
|
|
455827
|
+
data: {
|
|
455828
|
+
segmentCount: segments.length,
|
|
455829
|
+
segments,
|
|
455830
|
+
outputPath
|
|
455831
|
+
}
|
|
455664
455832
|
});
|
|
455665
455833
|
return;
|
|
455666
455834
|
}
|
|
455667
455835
|
} else if (isJsonMode()) {
|
|
455668
|
-
|
|
455836
|
+
outputSuccess({
|
|
455837
|
+
command: "generate storyboard",
|
|
455838
|
+
startedAt,
|
|
455839
|
+
data: { segmentCount: segments.length, segments }
|
|
455840
|
+
});
|
|
455669
455841
|
return;
|
|
455670
455842
|
}
|
|
455671
455843
|
console.log();
|
|
@@ -455797,6 +455969,7 @@ async function executeSpeech(options) {
|
|
|
455797
455969
|
}
|
|
455798
455970
|
function registerSpeechCommand(parent) {
|
|
455799
455971
|
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) => {
|
|
455972
|
+
const startedAt = Date.now();
|
|
455800
455973
|
try {
|
|
455801
455974
|
if (!text) {
|
|
455802
455975
|
if (hasTTY()) {
|
|
@@ -455818,10 +455991,11 @@ function registerSpeechCommand(parent) {
|
|
|
455818
455991
|
validateOutputPath(options.output);
|
|
455819
455992
|
}
|
|
455820
455993
|
if (options.dryRun) {
|
|
455821
|
-
|
|
455822
|
-
dryRun: true,
|
|
455994
|
+
outputSuccess({
|
|
455823
455995
|
command: "generate speech",
|
|
455824
|
-
|
|
455996
|
+
startedAt,
|
|
455997
|
+
dryRun: true,
|
|
455998
|
+
data: { params: { text, voice: options.voice, output: options.output } }
|
|
455825
455999
|
});
|
|
455826
456000
|
return;
|
|
455827
456001
|
}
|
|
@@ -455910,10 +456084,13 @@ function registerSpeechCommand(parent) {
|
|
|
455910
456084
|
}
|
|
455911
456085
|
}
|
|
455912
456086
|
if (isJsonMode()) {
|
|
455913
|
-
|
|
455914
|
-
|
|
455915
|
-
|
|
455916
|
-
|
|
456087
|
+
outputSuccess({
|
|
456088
|
+
command: "generate speech",
|
|
456089
|
+
startedAt,
|
|
456090
|
+
data: {
|
|
456091
|
+
characterCount: result.characterCount,
|
|
456092
|
+
outputPath
|
|
456093
|
+
}
|
|
455917
456094
|
});
|
|
455918
456095
|
return;
|
|
455919
456096
|
}
|
|
@@ -456002,6 +456179,7 @@ async function executeMusic(options) {
|
|
|
456002
456179
|
}
|
|
456003
456180
|
function registerMusicCommand(parent) {
|
|
456004
456181
|
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) => {
|
|
456182
|
+
const startedAt = Date.now();
|
|
456005
456183
|
try {
|
|
456006
456184
|
rejectControlChars(prompt3);
|
|
456007
456185
|
if (options.output) {
|
|
@@ -456009,16 +456187,19 @@ function registerMusicCommand(parent) {
|
|
|
456009
456187
|
}
|
|
456010
456188
|
const provider = (options.provider || "elevenlabs").toLowerCase();
|
|
456011
456189
|
if (options.dryRun) {
|
|
456012
|
-
|
|
456013
|
-
dryRun: true,
|
|
456190
|
+
outputSuccess({
|
|
456014
456191
|
command: "generate music",
|
|
456015
|
-
|
|
456016
|
-
|
|
456017
|
-
|
|
456018
|
-
|
|
456019
|
-
|
|
456020
|
-
|
|
456021
|
-
|
|
456192
|
+
startedAt,
|
|
456193
|
+
dryRun: true,
|
|
456194
|
+
data: {
|
|
456195
|
+
params: {
|
|
456196
|
+
prompt: prompt3,
|
|
456197
|
+
provider,
|
|
456198
|
+
duration: options.duration,
|
|
456199
|
+
model: options.model,
|
|
456200
|
+
output: options.output,
|
|
456201
|
+
instrumental: options.instrumental
|
|
456202
|
+
}
|
|
456022
456203
|
}
|
|
456023
456204
|
});
|
|
456024
456205
|
return;
|
|
@@ -456045,11 +456226,14 @@ function registerMusicCommand(parent) {
|
|
|
456045
456226
|
await writeFile26(outputPath, result.audioBuffer);
|
|
456046
456227
|
spinner2.succeed(source_default.green("Music generated successfully"));
|
|
456047
456228
|
if (isJsonMode()) {
|
|
456048
|
-
|
|
456049
|
-
|
|
456050
|
-
|
|
456051
|
-
|
|
456052
|
-
|
|
456229
|
+
outputSuccess({
|
|
456230
|
+
command: "generate music",
|
|
456231
|
+
startedAt,
|
|
456232
|
+
data: {
|
|
456233
|
+
provider: "elevenlabs",
|
|
456234
|
+
outputPath,
|
|
456235
|
+
duration
|
|
456236
|
+
}
|
|
456053
456237
|
});
|
|
456054
456238
|
return;
|
|
456055
456239
|
}
|
|
@@ -456117,12 +456301,15 @@ function registerMusicCommand(parent) {
|
|
|
456117
456301
|
await writeFile26(outputPath, audioBuffer);
|
|
456118
456302
|
spinner2.succeed(source_default.green("Music generated successfully"));
|
|
456119
456303
|
if (isJsonMode()) {
|
|
456120
|
-
|
|
456121
|
-
|
|
456122
|
-
|
|
456123
|
-
|
|
456124
|
-
|
|
456125
|
-
|
|
456304
|
+
outputSuccess({
|
|
456305
|
+
command: "generate music",
|
|
456306
|
+
startedAt,
|
|
456307
|
+
data: {
|
|
456308
|
+
provider: "replicate",
|
|
456309
|
+
taskId: result.taskId,
|
|
456310
|
+
audioUrl: finalResult.audioUrl,
|
|
456311
|
+
outputPath
|
|
456312
|
+
}
|
|
456126
456313
|
});
|
|
456127
456314
|
return;
|
|
456128
456315
|
}
|
|
@@ -456157,6 +456344,7 @@ import { existsSync as existsSync47 } from "node:fs";
|
|
|
456157
456344
|
import { writeFile as writeFile27, mkdir as mkdir19 } from "node:fs/promises";
|
|
456158
456345
|
function registerThumbnailCommand(parent) {
|
|
456159
456346
|
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) => {
|
|
456347
|
+
const startedAt = Date.now();
|
|
456160
456348
|
try {
|
|
456161
456349
|
if (description) rejectControlChars(description);
|
|
456162
456350
|
if (options.output) {
|
|
@@ -456192,11 +456380,14 @@ function registerThumbnailCommand(parent) {
|
|
|
456192
456380
|
}
|
|
456193
456381
|
spinner3.succeed(source_default.green("Best frame extracted"));
|
|
456194
456382
|
if (isJsonMode()) {
|
|
456195
|
-
|
|
456196
|
-
|
|
456197
|
-
|
|
456198
|
-
|
|
456199
|
-
|
|
456383
|
+
outputSuccess({
|
|
456384
|
+
command: "generate thumbnail",
|
|
456385
|
+
startedAt,
|
|
456386
|
+
data: {
|
|
456387
|
+
timestamp: result2.timestamp,
|
|
456388
|
+
reason: result2.reason,
|
|
456389
|
+
outputPath: result2.outputPath
|
|
456390
|
+
}
|
|
456200
456391
|
});
|
|
456201
456392
|
return;
|
|
456202
456393
|
}
|
|
@@ -456244,7 +456435,11 @@ function registerThumbnailCommand(parent) {
|
|
|
456244
456435
|
await mkdir19(dirname26(outputPath), { recursive: true });
|
|
456245
456436
|
await writeFile27(outputPath, buffer);
|
|
456246
456437
|
}
|
|
456247
|
-
|
|
456438
|
+
outputSuccess({
|
|
456439
|
+
command: "generate thumbnail",
|
|
456440
|
+
startedAt,
|
|
456441
|
+
data: { imageUrl: img.url, outputPath }
|
|
456442
|
+
});
|
|
456248
456443
|
return;
|
|
456249
456444
|
}
|
|
456250
456445
|
console.log();
|
|
@@ -456315,6 +456510,7 @@ function getStatusColor(status) {
|
|
|
456315
456510
|
}
|
|
456316
456511
|
function registerVideoStatusCommand(parent) {
|
|
456317
456512
|
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) => {
|
|
456513
|
+
const startedAt = Date.now();
|
|
456318
456514
|
try {
|
|
456319
456515
|
const provider = (options.provider || "grok").toLowerCase();
|
|
456320
456516
|
if (provider === "grok") {
|
|
@@ -456337,14 +456533,17 @@ function registerVideoStatusCommand(parent) {
|
|
|
456337
456533
|
outputPath = resolve44(process.cwd(), options.output);
|
|
456338
456534
|
await writeFile28(outputPath, buffer);
|
|
456339
456535
|
}
|
|
456340
|
-
|
|
456341
|
-
|
|
456342
|
-
|
|
456343
|
-
|
|
456344
|
-
|
|
456345
|
-
|
|
456346
|
-
|
|
456347
|
-
|
|
456536
|
+
outputSuccess({
|
|
456537
|
+
command: "generate video-status",
|
|
456538
|
+
startedAt,
|
|
456539
|
+
data: {
|
|
456540
|
+
taskId,
|
|
456541
|
+
provider: "grok",
|
|
456542
|
+
status: result.status,
|
|
456543
|
+
videoUrl: result.videoUrl,
|
|
456544
|
+
error: result.error,
|
|
456545
|
+
outputPath
|
|
456546
|
+
}
|
|
456348
456547
|
});
|
|
456349
456548
|
return;
|
|
456350
456549
|
}
|
|
@@ -456402,15 +456601,18 @@ function registerVideoStatusCommand(parent) {
|
|
|
456402
456601
|
outputPath = resolve44(process.cwd(), options.output);
|
|
456403
456602
|
await writeFile28(outputPath, buffer);
|
|
456404
456603
|
}
|
|
456405
|
-
|
|
456406
|
-
|
|
456407
|
-
|
|
456408
|
-
|
|
456409
|
-
|
|
456410
|
-
|
|
456411
|
-
|
|
456412
|
-
|
|
456413
|
-
|
|
456604
|
+
outputSuccess({
|
|
456605
|
+
command: "generate video-status",
|
|
456606
|
+
startedAt,
|
|
456607
|
+
data: {
|
|
456608
|
+
taskId,
|
|
456609
|
+
provider: "runway",
|
|
456610
|
+
status: result.status,
|
|
456611
|
+
videoUrl: result.videoUrl,
|
|
456612
|
+
progress: result.progress,
|
|
456613
|
+
error: result.error,
|
|
456614
|
+
outputPath
|
|
456615
|
+
}
|
|
456414
456616
|
});
|
|
456415
456617
|
return;
|
|
456416
456618
|
}
|
|
@@ -456466,15 +456668,18 @@ function registerVideoStatusCommand(parent) {
|
|
|
456466
456668
|
outputPath = resolve44(process.cwd(), options.output);
|
|
456467
456669
|
await writeFile28(outputPath, buffer);
|
|
456468
456670
|
}
|
|
456469
|
-
|
|
456470
|
-
|
|
456471
|
-
|
|
456472
|
-
|
|
456473
|
-
|
|
456474
|
-
|
|
456475
|
-
|
|
456476
|
-
|
|
456477
|
-
|
|
456671
|
+
outputSuccess({
|
|
456672
|
+
command: "generate video-status",
|
|
456673
|
+
startedAt,
|
|
456674
|
+
data: {
|
|
456675
|
+
taskId,
|
|
456676
|
+
provider: "kling",
|
|
456677
|
+
status: result.status,
|
|
456678
|
+
videoUrl: result.videoUrl,
|
|
456679
|
+
duration: result.duration,
|
|
456680
|
+
error: result.error,
|
|
456681
|
+
outputPath
|
|
456682
|
+
}
|
|
456478
456683
|
});
|
|
456479
456684
|
return;
|
|
456480
456685
|
}
|
|
@@ -456538,22 +456743,26 @@ import { resolve as resolve45 } from "node:path";
|
|
|
456538
456743
|
import { writeFile as writeFile29 } from "node:fs/promises";
|
|
456539
456744
|
function registerVideoExtendCommand(parent) {
|
|
456540
456745
|
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) => {
|
|
456746
|
+
const startedAt = Date.now();
|
|
456541
456747
|
try {
|
|
456542
456748
|
const provider = (options.provider || "kling").toLowerCase();
|
|
456543
456749
|
if (options.output) {
|
|
456544
456750
|
validateOutputPath(options.output);
|
|
456545
456751
|
}
|
|
456546
456752
|
if (options.dryRun) {
|
|
456547
|
-
|
|
456548
|
-
dryRun: true,
|
|
456753
|
+
outputSuccess({
|
|
456549
456754
|
command: "generate video-extend",
|
|
456550
|
-
|
|
456551
|
-
|
|
456552
|
-
|
|
456553
|
-
|
|
456554
|
-
|
|
456555
|
-
|
|
456556
|
-
|
|
456755
|
+
startedAt,
|
|
456756
|
+
dryRun: true,
|
|
456757
|
+
data: {
|
|
456758
|
+
params: {
|
|
456759
|
+
id,
|
|
456760
|
+
provider,
|
|
456761
|
+
prompt: options.prompt,
|
|
456762
|
+
duration: options.duration,
|
|
456763
|
+
negative: options.negative,
|
|
456764
|
+
veoModel: options.veoModel
|
|
456765
|
+
}
|
|
456557
456766
|
}
|
|
456558
456767
|
});
|
|
456559
456768
|
return;
|
|
@@ -456610,13 +456819,16 @@ function registerVideoExtendCommand(parent) {
|
|
|
456610
456819
|
outputPath = resolve45(process.cwd(), options.output);
|
|
456611
456820
|
await writeFile29(outputPath, buffer);
|
|
456612
456821
|
}
|
|
456613
|
-
|
|
456614
|
-
|
|
456615
|
-
|
|
456616
|
-
|
|
456617
|
-
|
|
456618
|
-
|
|
456619
|
-
|
|
456822
|
+
outputSuccess({
|
|
456823
|
+
command: "generate video-extend",
|
|
456824
|
+
startedAt,
|
|
456825
|
+
data: {
|
|
456826
|
+
provider: "kling",
|
|
456827
|
+
taskId: result.id,
|
|
456828
|
+
videoUrl: finalResult.videoUrl,
|
|
456829
|
+
duration: finalResult.duration,
|
|
456830
|
+
outputPath
|
|
456831
|
+
}
|
|
456620
456832
|
});
|
|
456621
456833
|
return;
|
|
456622
456834
|
}
|
|
@@ -456696,13 +456908,16 @@ function registerVideoExtendCommand(parent) {
|
|
|
456696
456908
|
outputPath = resolve45(process.cwd(), options.output);
|
|
456697
456909
|
await writeFile29(outputPath, buffer);
|
|
456698
456910
|
}
|
|
456699
|
-
|
|
456700
|
-
|
|
456701
|
-
|
|
456702
|
-
|
|
456703
|
-
|
|
456704
|
-
|
|
456705
|
-
|
|
456911
|
+
outputSuccess({
|
|
456912
|
+
command: "generate video-extend",
|
|
456913
|
+
startedAt,
|
|
456914
|
+
data: {
|
|
456915
|
+
provider: "veo",
|
|
456916
|
+
taskId: result.id,
|
|
456917
|
+
videoUrl: finalResult.videoUrl,
|
|
456918
|
+
duration: finalResult.duration,
|
|
456919
|
+
outputPath
|
|
456920
|
+
}
|
|
456706
456921
|
});
|
|
456707
456922
|
return;
|
|
456708
456923
|
}
|
|
@@ -456817,6 +457032,7 @@ Examples:
|
|
|
456817
457032
|
$ vibe gen img "landscape photo" -o wide.png -r 16:9
|
|
456818
457033
|
$ vibe gen img "portrait" -o portrait.png -p gemini -m pro
|
|
456819
457034
|
$ vibe gen img "product shot" --dry-run --json`).action(async (prompt3, options) => {
|
|
457035
|
+
const startedAt = Date.now();
|
|
456820
457036
|
try {
|
|
456821
457037
|
if (!prompt3) {
|
|
456822
457038
|
if (hasTTY()) {
|
|
@@ -456875,18 +457091,21 @@ Examples:
|
|
|
456875
457091
|
provider = resolved?.name ?? "gemini";
|
|
456876
457092
|
}
|
|
456877
457093
|
if (options.dryRun) {
|
|
456878
|
-
|
|
456879
|
-
dryRun: true,
|
|
457094
|
+
outputSuccess({
|
|
456880
457095
|
command: "generate image",
|
|
456881
|
-
|
|
456882
|
-
|
|
456883
|
-
|
|
456884
|
-
|
|
456885
|
-
|
|
456886
|
-
|
|
456887
|
-
|
|
456888
|
-
|
|
456889
|
-
|
|
457096
|
+
startedAt,
|
|
457097
|
+
dryRun: true,
|
|
457098
|
+
data: {
|
|
457099
|
+
params: {
|
|
457100
|
+
prompt: prompt3,
|
|
457101
|
+
provider,
|
|
457102
|
+
model: options.model,
|
|
457103
|
+
ratio: options.ratio,
|
|
457104
|
+
size: options.size,
|
|
457105
|
+
quality: options.quality,
|
|
457106
|
+
count: options.count,
|
|
457107
|
+
output: options.output
|
|
457108
|
+
}
|
|
456890
457109
|
}
|
|
456891
457110
|
});
|
|
456892
457111
|
return;
|
|
@@ -456924,14 +457143,17 @@ Examples:
|
|
|
456924
457143
|
await mkdir20(dirname27(outputPath), { recursive: true });
|
|
456925
457144
|
await writeFile30(outputPath, buffer);
|
|
456926
457145
|
}
|
|
456927
|
-
|
|
456928
|
-
|
|
456929
|
-
|
|
456930
|
-
|
|
456931
|
-
|
|
456932
|
-
|
|
456933
|
-
|
|
456934
|
-
|
|
457146
|
+
outputSuccess({
|
|
457147
|
+
command: "generate image",
|
|
457148
|
+
startedAt,
|
|
457149
|
+
data: {
|
|
457150
|
+
provider: "openai",
|
|
457151
|
+
images: result.images.map((img) => ({
|
|
457152
|
+
url: img.url,
|
|
457153
|
+
revisedPrompt: img.revisedPrompt
|
|
457154
|
+
})),
|
|
457155
|
+
outputPath
|
|
457156
|
+
}
|
|
456935
457157
|
});
|
|
456936
457158
|
return;
|
|
456937
457159
|
}
|
|
@@ -457043,13 +457265,18 @@ Examples:
|
|
|
457043
457265
|
await mkdir20(dirname27(outputPath), { recursive: true });
|
|
457044
457266
|
await writeFile30(outputPath, buffer);
|
|
457045
457267
|
}
|
|
457046
|
-
|
|
457047
|
-
|
|
457048
|
-
|
|
457049
|
-
|
|
457050
|
-
|
|
457051
|
-
|
|
457052
|
-
|
|
457268
|
+
outputSuccess({
|
|
457269
|
+
command: "generate image",
|
|
457270
|
+
startedAt,
|
|
457271
|
+
warnings: usedLabel.includes("fallback") ? [`Model "${options.model}" failed; fell back to flash`] : [],
|
|
457272
|
+
data: {
|
|
457273
|
+
provider: "gemini",
|
|
457274
|
+
model: usedLabel,
|
|
457275
|
+
images: result.images.map((img) => ({
|
|
457276
|
+
mimeType: img.mimeType
|
|
457277
|
+
})),
|
|
457278
|
+
outputPath
|
|
457279
|
+
}
|
|
457053
457280
|
});
|
|
457054
457281
|
return;
|
|
457055
457282
|
}
|
|
@@ -457133,11 +457360,14 @@ Examples:
|
|
|
457133
457360
|
await mkdir20(dirname27(outputPath), { recursive: true });
|
|
457134
457361
|
await writeFile30(outputPath, buffer);
|
|
457135
457362
|
}
|
|
457136
|
-
|
|
457137
|
-
|
|
457138
|
-
|
|
457139
|
-
|
|
457140
|
-
|
|
457363
|
+
outputSuccess({
|
|
457364
|
+
command: "generate image",
|
|
457365
|
+
startedAt,
|
|
457366
|
+
data: {
|
|
457367
|
+
provider: "grok",
|
|
457368
|
+
images: result.images.map((img) => ({ url: img.url })),
|
|
457369
|
+
outputPath
|
|
457370
|
+
}
|
|
457141
457371
|
});
|
|
457142
457372
|
return;
|
|
457143
457373
|
}
|
|
@@ -457208,11 +457438,14 @@ Examples:
|
|
|
457208
457438
|
proc.on("close", (code) => {
|
|
457209
457439
|
if (code === 0) {
|
|
457210
457440
|
if (isJsonMode()) {
|
|
457211
|
-
|
|
457212
|
-
|
|
457213
|
-
|
|
457214
|
-
|
|
457215
|
-
|
|
457441
|
+
outputSuccess({
|
|
457442
|
+
command: "generate image",
|
|
457443
|
+
startedAt,
|
|
457444
|
+
data: {
|
|
457445
|
+
provider: "runway",
|
|
457446
|
+
images: [{ format: "file" }],
|
|
457447
|
+
outputPath
|
|
457448
|
+
}
|
|
457216
457449
|
});
|
|
457217
457450
|
} else {
|
|
457218
457451
|
spinner2.succeed(source_default.green("Generated image with Runway"));
|
|
@@ -458938,6 +459171,7 @@ Examples:
|
|
|
458938
459171
|
$ vibe gen vid "epic scene" -i frame.png -o out.mp4 -p runway # Image-to-video
|
|
458939
459172
|
$ vibe gen vid "ocean waves" -o waves.mp4 -p veo --resolution 1080p # Veo
|
|
458940
459173
|
$ vibe gen vid "sunset" -o sun.mp4 -d 10 --dry-run --json`).action(async (prompt3, options) => {
|
|
459174
|
+
const startedAt = Date.now();
|
|
458941
459175
|
try {
|
|
458942
459176
|
if (!prompt3) {
|
|
458943
459177
|
if (hasTTY()) {
|
|
@@ -459029,19 +459263,22 @@ Examples:
|
|
|
459029
459263
|
options.ratio = "16:9";
|
|
459030
459264
|
}
|
|
459031
459265
|
if (options.dryRun) {
|
|
459032
|
-
|
|
459033
|
-
dryRun: true,
|
|
459266
|
+
outputSuccess({
|
|
459034
459267
|
command: "generate video",
|
|
459035
|
-
|
|
459036
|
-
|
|
459037
|
-
|
|
459038
|
-
|
|
459039
|
-
|
|
459040
|
-
|
|
459041
|
-
|
|
459042
|
-
|
|
459043
|
-
|
|
459044
|
-
|
|
459268
|
+
startedAt,
|
|
459269
|
+
dryRun: true,
|
|
459270
|
+
data: {
|
|
459271
|
+
params: {
|
|
459272
|
+
prompt: prompt3,
|
|
459273
|
+
provider,
|
|
459274
|
+
duration: options.duration,
|
|
459275
|
+
ratio: options.ratio,
|
|
459276
|
+
image: options.image,
|
|
459277
|
+
mode: options.mode,
|
|
459278
|
+
negative: options.negative,
|
|
459279
|
+
resolution: options.resolution,
|
|
459280
|
+
veoModel: options.veoModel
|
|
459281
|
+
}
|
|
459045
459282
|
}
|
|
459046
459283
|
});
|
|
459047
459284
|
return;
|
|
@@ -459321,13 +459558,16 @@ Examples:
|
|
|
459321
459558
|
outputPath = resolve49(process.cwd(), options.output);
|
|
459322
459559
|
await writeFile33(outputPath, buffer);
|
|
459323
459560
|
}
|
|
459324
|
-
|
|
459325
|
-
|
|
459326
|
-
|
|
459327
|
-
|
|
459328
|
-
|
|
459329
|
-
|
|
459330
|
-
|
|
459561
|
+
outputSuccess({
|
|
459562
|
+
command: "generate video",
|
|
459563
|
+
startedAt,
|
|
459564
|
+
data: {
|
|
459565
|
+
provider,
|
|
459566
|
+
taskId: result?.id,
|
|
459567
|
+
videoUrl: finalResult.videoUrl,
|
|
459568
|
+
duration: finalResult.duration,
|
|
459569
|
+
outputPath
|
|
459570
|
+
}
|
|
459331
459571
|
});
|
|
459332
459572
|
return;
|
|
459333
459573
|
}
|
|
@@ -459892,20 +460132,24 @@ var init_detect = __esm({
|
|
|
459892
460132
|
init_validate();
|
|
459893
460133
|
detectCommand = new Command("detect").description("Auto-detect scenes, beats, and silences in media");
|
|
459894
460134
|
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) => {
|
|
460135
|
+
const startedAt = Date.now();
|
|
459895
460136
|
const spinner2 = ora("Detecting scenes...").start();
|
|
459896
460137
|
try {
|
|
459897
460138
|
if (options.output) {
|
|
459898
460139
|
validateOutputPath(options.output);
|
|
459899
460140
|
}
|
|
459900
460141
|
if (options.dryRun) {
|
|
459901
|
-
|
|
459902
|
-
dryRun: true,
|
|
460142
|
+
outputSuccess({
|
|
459903
460143
|
command: "detect scenes",
|
|
459904
|
-
|
|
459905
|
-
|
|
459906
|
-
|
|
459907
|
-
|
|
459908
|
-
|
|
460144
|
+
startedAt,
|
|
460145
|
+
dryRun: true,
|
|
460146
|
+
data: {
|
|
460147
|
+
params: {
|
|
460148
|
+
video: videoPath,
|
|
460149
|
+
threshold: options.threshold,
|
|
460150
|
+
output: options.output || null,
|
|
460151
|
+
project: options.project || null
|
|
460152
|
+
}
|
|
459909
460153
|
}
|
|
459910
460154
|
});
|
|
459911
460155
|
return;
|
|
@@ -460007,20 +460251,24 @@ var init_detect = __esm({
|
|
|
460007
460251
|
}
|
|
460008
460252
|
});
|
|
460009
460253
|
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) => {
|
|
460254
|
+
const startedAt = Date.now();
|
|
460010
460255
|
const spinner2 = ora("Detecting silence...").start();
|
|
460011
460256
|
try {
|
|
460012
460257
|
if (options.output) {
|
|
460013
460258
|
validateOutputPath(options.output);
|
|
460014
460259
|
}
|
|
460015
460260
|
if (options.dryRun) {
|
|
460016
|
-
|
|
460017
|
-
dryRun: true,
|
|
460261
|
+
outputSuccess({
|
|
460018
460262
|
command: "detect silence",
|
|
460019
|
-
|
|
460020
|
-
|
|
460021
|
-
|
|
460022
|
-
|
|
460023
|
-
|
|
460263
|
+
startedAt,
|
|
460264
|
+
dryRun: true,
|
|
460265
|
+
data: {
|
|
460266
|
+
params: {
|
|
460267
|
+
media: mediaPath,
|
|
460268
|
+
noise: options.noise,
|
|
460269
|
+
duration: options.duration,
|
|
460270
|
+
output: options.output || null
|
|
460271
|
+
}
|
|
460024
460272
|
}
|
|
460025
460273
|
});
|
|
460026
460274
|
return;
|
|
@@ -460089,18 +460337,22 @@ var init_detect = __esm({
|
|
|
460089
460337
|
}
|
|
460090
460338
|
});
|
|
460091
460339
|
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) => {
|
|
460340
|
+
const startedAt = Date.now();
|
|
460092
460341
|
const spinner2 = ora("Detecting beats...").start();
|
|
460093
460342
|
try {
|
|
460094
460343
|
if (options.output) {
|
|
460095
460344
|
validateOutputPath(options.output);
|
|
460096
460345
|
}
|
|
460097
460346
|
if (options.dryRun) {
|
|
460098
|
-
|
|
460099
|
-
dryRun: true,
|
|
460347
|
+
outputSuccess({
|
|
460100
460348
|
command: "detect beats",
|
|
460101
|
-
|
|
460102
|
-
|
|
460103
|
-
|
|
460349
|
+
startedAt,
|
|
460350
|
+
dryRun: true,
|
|
460351
|
+
data: {
|
|
460352
|
+
params: {
|
|
460353
|
+
audio: audioPath,
|
|
460354
|
+
output: options.output || null
|
|
460355
|
+
}
|
|
460104
460356
|
}
|
|
460105
460357
|
});
|
|
460106
460358
|
return;
|
|
@@ -461574,20 +461826,24 @@ Examples:
|
|
|
461574
461826
|
A scene project is bilingual: it works with both \`vibe\` and \`npx hyperframes\`.
|
|
461575
461827
|
Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
461576
461828
|
sceneCommand.command("init").description("Scaffold a new scene project (or safely augment an existing Hyperframes project)").argument("<dir>", "Project directory (created if it doesn't exist)").option("-n, --name <name>", "Project name (defaults to directory basename)").option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, 1:1, 4:5", "16:9").option("-d, --duration <sec>", "Default root composition duration (seconds)", "10").option("--visual-style <name>", `Seed DESIGN.md from a named style (browse via \`vibe scene styles\`). E.g. "Swiss Pulse"`).option("--dry-run", "Preview parameters without writing files").action(async (dir, options) => {
|
|
461829
|
+
const startedAt = Date.now();
|
|
461577
461830
|
const aspect = validateAspect(options.ratio);
|
|
461578
461831
|
const duration = validateDuration(options.duration);
|
|
461579
461832
|
const name = options.name ?? basename6(dir.replace(/\/+$/, ""));
|
|
461580
461833
|
const visualStyle = options.visualStyle ? validateVisualStyle(options.visualStyle) : void 0;
|
|
461581
461834
|
if (options.dryRun) {
|
|
461582
|
-
|
|
461583
|
-
dryRun: true,
|
|
461835
|
+
outputSuccess({
|
|
461584
461836
|
command: "scene init",
|
|
461585
|
-
|
|
461586
|
-
|
|
461587
|
-
|
|
461588
|
-
|
|
461589
|
-
|
|
461590
|
-
|
|
461837
|
+
startedAt,
|
|
461838
|
+
dryRun: true,
|
|
461839
|
+
data: {
|
|
461840
|
+
params: {
|
|
461841
|
+
dir,
|
|
461842
|
+
name,
|
|
461843
|
+
aspect,
|
|
461844
|
+
duration,
|
|
461845
|
+
visualStyle: visualStyle?.name ?? null
|
|
461846
|
+
}
|
|
461591
461847
|
}
|
|
461592
461848
|
});
|
|
461593
461849
|
return;
|
|
@@ -461603,19 +461859,21 @@ sceneCommand.command("init").description("Scaffold a new scene project (or safel
|
|
|
461603
461859
|
hosts: skillHosts
|
|
461604
461860
|
});
|
|
461605
461861
|
if (isJsonMode()) {
|
|
461606
|
-
|
|
461607
|
-
success: true,
|
|
461862
|
+
outputSuccess({
|
|
461608
461863
|
command: "scene init",
|
|
461609
|
-
|
|
461610
|
-
|
|
461611
|
-
|
|
461612
|
-
|
|
461613
|
-
|
|
461614
|
-
|
|
461615
|
-
|
|
461616
|
-
|
|
461617
|
-
|
|
461618
|
-
|
|
461864
|
+
startedAt,
|
|
461865
|
+
data: {
|
|
461866
|
+
dir,
|
|
461867
|
+
name,
|
|
461868
|
+
aspect,
|
|
461869
|
+
duration,
|
|
461870
|
+
visualStyle: visualStyle?.name ?? null,
|
|
461871
|
+
created: result.created,
|
|
461872
|
+
merged: result.merged,
|
|
461873
|
+
skipped: result.skipped,
|
|
461874
|
+
skillFiles: skillResult.files,
|
|
461875
|
+
skillBundleVersion: skillResult.bundleVersion
|
|
461876
|
+
}
|
|
461619
461877
|
});
|
|
461620
461878
|
return;
|
|
461621
461879
|
}
|
|
@@ -461656,6 +461914,7 @@ sceneCommand.command("init").description("Scaffold a new scene project (or safel
|
|
|
461656
461914
|
});
|
|
461657
461915
|
var VALID_INSTALL_SKILL_HOSTS = ["claude-code", "cursor", "auto", "all"];
|
|
461658
461916
|
sceneCommand.command("install-skill").description("Install the Hyperframes skill into a scene project so the host agent can read it (Phase H1)").argument("[project-dir]", "Project directory containing STORYBOARD.md / DESIGN.md", ".").option("--host <id>", `Host layout target: ${VALID_INSTALL_SKILL_HOSTS.join(" | ")}`, "auto").option("--force", "Overwrite existing skill files (default: skip-on-exist)").option("--dry-run", "Preview which files would be written without changing anything").action(async (projectDirArg, options) => {
|
|
461917
|
+
const startedAt = Date.now();
|
|
461659
461918
|
const hostFlag = options.host ?? "auto";
|
|
461660
461919
|
if (!VALID_INSTALL_SKILL_HOSTS.includes(hostFlag)) {
|
|
461661
461920
|
exitWithError(usageError(`Invalid --host: ${hostFlag}`, `Valid: ${VALID_INSTALL_SKILL_HOSTS.join(", ")}`));
|
|
@@ -461675,15 +461934,17 @@ sceneCommand.command("install-skill").description("Install the Hyperframes skill
|
|
|
461675
461934
|
dryRun: options.dryRun ?? false
|
|
461676
461935
|
});
|
|
461677
461936
|
if (isJsonMode()) {
|
|
461678
|
-
|
|
461679
|
-
success: true,
|
|
461937
|
+
outputSuccess({
|
|
461680
461938
|
command: "scene install-skill",
|
|
461681
|
-
|
|
461682
|
-
|
|
461683
|
-
|
|
461684
|
-
|
|
461685
|
-
|
|
461686
|
-
|
|
461939
|
+
startedAt,
|
|
461940
|
+
dryRun: options.dryRun ?? false,
|
|
461941
|
+
data: {
|
|
461942
|
+
projectDir,
|
|
461943
|
+
host: hostFlag,
|
|
461944
|
+
resolvedHosts: hosts,
|
|
461945
|
+
bundleVersion: result.bundleVersion,
|
|
461946
|
+
files: result.files
|
|
461947
|
+
}
|
|
461687
461948
|
});
|
|
461688
461949
|
return;
|
|
461689
461950
|
}
|
|
@@ -461705,6 +461966,7 @@ sceneCommand.command("install-skill").description("Install the Hyperframes skill
|
|
|
461705
461966
|
}
|
|
461706
461967
|
});
|
|
461707
461968
|
sceneCommand.command("compose-prompts").description("Emit the per-beat compose plan for the host agent to author HTML itself (Phase H2 \u2014 no LLM call)").argument("[project-dir]", "Project directory containing STORYBOARD.md / DESIGN.md", ".").option("--beat <id>", "Restrict the plan to a single beat by id (e.g. 'hook', '1')").action(async (projectDirArg, options) => {
|
|
461969
|
+
const startedAt = Date.now();
|
|
461708
461970
|
const projectDir = resolve21(projectDirArg);
|
|
461709
461971
|
const result = await getComposePrompts({
|
|
461710
461972
|
projectDir,
|
|
@@ -461712,18 +461974,21 @@ sceneCommand.command("compose-prompts").description("Emit the per-beat compose p
|
|
|
461712
461974
|
});
|
|
461713
461975
|
if (!result.success) {
|
|
461714
461976
|
if (isJsonMode()) {
|
|
461715
|
-
|
|
461977
|
+
outputSuccess({
|
|
461716
461978
|
command: "scene compose-prompts",
|
|
461717
|
-
|
|
461979
|
+
startedAt,
|
|
461980
|
+
data: { ...result }
|
|
461718
461981
|
});
|
|
461719
|
-
process.
|
|
461982
|
+
process.exitCode = 1;
|
|
461983
|
+
return;
|
|
461720
461984
|
}
|
|
461721
461985
|
exitWithError(generalError(result.error ?? "compose-prompts failed"));
|
|
461722
461986
|
}
|
|
461723
461987
|
if (isJsonMode()) {
|
|
461724
|
-
|
|
461988
|
+
outputSuccess({
|
|
461725
461989
|
command: "scene compose-prompts",
|
|
461726
|
-
|
|
461990
|
+
startedAt,
|
|
461991
|
+
data: { ...result }
|
|
461727
461992
|
});
|
|
461728
461993
|
return;
|
|
461729
461994
|
}
|
|
@@ -461757,20 +462022,23 @@ sceneCommand.command("compose-prompts").description("Emit the per-beat compose p
|
|
|
461757
462022
|
console.log(source_default.dim("Re-run with --json to get the full per-beat userPrompt + cues for direct consumption."));
|
|
461758
462023
|
});
|
|
461759
462024
|
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) => {
|
|
462025
|
+
const startedAt = Date.now();
|
|
461760
462026
|
if (!name) {
|
|
461761
462027
|
const all = listVisualStyles();
|
|
461762
462028
|
if (isJsonMode()) {
|
|
461763
|
-
|
|
461764
|
-
success: true,
|
|
462029
|
+
outputSuccess({
|
|
461765
462030
|
command: "scene styles",
|
|
461766
|
-
|
|
461767
|
-
|
|
461768
|
-
|
|
461769
|
-
|
|
461770
|
-
|
|
461771
|
-
|
|
461772
|
-
|
|
461773
|
-
|
|
462031
|
+
startedAt,
|
|
462032
|
+
data: {
|
|
462033
|
+
count: all.length,
|
|
462034
|
+
styles: all.map((s) => ({
|
|
462035
|
+
name: s.name,
|
|
462036
|
+
slug: s.slug,
|
|
462037
|
+
designer: s.designer,
|
|
462038
|
+
mood: s.mood,
|
|
462039
|
+
bestFor: s.bestFor
|
|
462040
|
+
}))
|
|
462041
|
+
}
|
|
461774
462042
|
});
|
|
461775
462043
|
return;
|
|
461776
462044
|
}
|
|
@@ -461798,7 +462066,11 @@ sceneCommand.command("styles").description("List vendored visual styles (or show
|
|
|
461798
462066
|
return;
|
|
461799
462067
|
}
|
|
461800
462068
|
if (isJsonMode()) {
|
|
461801
|
-
|
|
462069
|
+
outputSuccess({
|
|
462070
|
+
command: "scene styles",
|
|
462071
|
+
startedAt,
|
|
462072
|
+
data: { style }
|
|
462073
|
+
});
|
|
461802
462074
|
return;
|
|
461803
462075
|
}
|
|
461804
462076
|
console.log();
|
|
@@ -461820,6 +462092,7 @@ sceneCommand.command("styles").description("List vendored visual styles (or show
|
|
|
461820
462092
|
console.log(source_default.dim("Seed DESIGN.md:"), source_default.cyan(`vibe scene init <dir> --visual-style "${style.name}"`));
|
|
461821
462093
|
});
|
|
461822
462094
|
sceneCommand.command("add").description("Add a new scene to a project: AI narration + image + per-scene HTML").argument("<name>", "Scene name (slugified into the composition id)").option("--style <preset>", `Style preset: ${SCENE_PRESETS.join(", ")}`, "simple").option("--narration <text>", "Narration text (or path to a .txt file). Drives TTS + scene duration.").option("--narration-file <path>", "Existing narration audio file (.wav/.mp3). Skips TTS \u2014 useful with hyperframes tts, Mac say, or other external tools.").option("-d, --duration <sec>", "Explicit scene duration in seconds (overrides narration audio)").option("--visuals <prompt>", "Image prompt \u2014 generates assets/scene-<id>.png via the configured image provider").option("--headline <text>", "Visible headline (defaults to the humanised scene name)").option("--kicker <text>", "Small label above the headline (explainer / product-shot)").option("--insert-into <path>", "Root composition file to update", "index.html").option("--project <dir>", "Project directory", ".").option("--image-provider <name>", "Image provider: gemini, openai", "gemini").option("--tts <provider>", "TTS provider: auto, elevenlabs, kokoro (default auto \u2014 picks ElevenLabs when key set, else Kokoro local)", "auto").option("--voice <id>", "Voice id (ElevenLabs name/id, or Kokoro id like af_heart, am_michael)").option("--no-audio", "Skip TTS even when --narration is provided (useful for tests/agent dry runs)").option("--no-image", "Skip image generation even when --visuals is provided").option("--no-transcribe", "Skip Whisper word-level transcribe step (no transcript-<id>.json emitted)").option("--transcribe-language <code>", "BCP-47 language code passed to Whisper (e.g. en, ko)").option("--force", "Overwrite an existing compositions/scene-<id>.html").option("--dry-run", "Preview parameters without writing files or calling APIs").action(async (name, options) => {
|
|
462095
|
+
const startedAt = Date.now();
|
|
461823
462096
|
if (options.style) options.style = validatePreset(options.style);
|
|
461824
462097
|
if (options.duration !== void 0) options.duration = validateDuration(options.duration);
|
|
461825
462098
|
let tts;
|
|
@@ -461830,25 +462103,28 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
461830
462103
|
}
|
|
461831
462104
|
if (options.dryRun) {
|
|
461832
462105
|
const id = slugifySceneName(name);
|
|
461833
|
-
|
|
461834
|
-
dryRun: true,
|
|
462106
|
+
outputSuccess({
|
|
461835
462107
|
command: "scene add",
|
|
461836
|
-
|
|
461837
|
-
|
|
461838
|
-
|
|
461839
|
-
|
|
461840
|
-
|
|
461841
|
-
|
|
461842
|
-
|
|
461843
|
-
|
|
461844
|
-
|
|
461845
|
-
|
|
461846
|
-
|
|
461847
|
-
|
|
461848
|
-
|
|
461849
|
-
|
|
461850
|
-
|
|
461851
|
-
|
|
462108
|
+
startedAt,
|
|
462109
|
+
dryRun: true,
|
|
462110
|
+
data: {
|
|
462111
|
+
params: {
|
|
462112
|
+
name,
|
|
462113
|
+
id,
|
|
462114
|
+
preset: options.style,
|
|
462115
|
+
narration: !!options.narration,
|
|
462116
|
+
visuals: !!options.visuals,
|
|
462117
|
+
duration: options.duration,
|
|
462118
|
+
headline: options.headline,
|
|
462119
|
+
kicker: options.kicker,
|
|
462120
|
+
project: options.project,
|
|
462121
|
+
insertInto: options.insertInto,
|
|
462122
|
+
imageProvider: options.imageProvider,
|
|
462123
|
+
tts,
|
|
462124
|
+
audio: options.audio,
|
|
462125
|
+
// commander sets `audio: false` when --no-audio is passed
|
|
462126
|
+
image: options.image
|
|
462127
|
+
}
|
|
461852
462128
|
}
|
|
461853
462129
|
});
|
|
461854
462130
|
return;
|
|
@@ -461883,9 +462159,10 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
461883
462159
|
exitWithError(generalError(result.error ?? "Scene add failed"));
|
|
461884
462160
|
}
|
|
461885
462161
|
if (isJsonMode()) {
|
|
461886
|
-
|
|
462162
|
+
outputSuccess({
|
|
461887
462163
|
command: "scene add",
|
|
461888
|
-
|
|
462164
|
+
startedAt,
|
|
462165
|
+
data: { ...result }
|
|
461889
462166
|
});
|
|
461890
462167
|
return;
|
|
461891
462168
|
}
|
|
@@ -462181,6 +462458,7 @@ async function executeSceneAdd(opts) {
|
|
|
462181
462458
|
};
|
|
462182
462459
|
}
|
|
462183
462460
|
sceneCommand.command("lint").description("Validate scene HTML against Hyperframes rules (in-process, no Chrome required)").argument("[root]", "Root composition file relative to --project", "index.html").option("--project <dir>", "Project directory", ".").option("--fix", 'Apply mechanical auto-fixes (currently: missing class="clip")').action(async (root2, options) => {
|
|
462461
|
+
const startedAt = Date.now();
|
|
462184
462462
|
const projectDir = resolve21(options.project);
|
|
462185
462463
|
if (!await rootExists(projectDir, root2)) {
|
|
462186
462464
|
exitWithError(generalError(
|
|
@@ -462198,11 +462476,12 @@ sceneCommand.command("lint").description("Validate scene HTML against Hyperframe
|
|
|
462198
462476
|
exitWithError(generalError(`Lint failed: ${msg}`));
|
|
462199
462477
|
}
|
|
462200
462478
|
if (isJsonMode()) {
|
|
462201
|
-
|
|
462479
|
+
outputSuccess({
|
|
462202
462480
|
command: "scene lint",
|
|
462203
|
-
|
|
462481
|
+
startedAt,
|
|
462482
|
+
data: { ...result }
|
|
462204
462483
|
});
|
|
462205
|
-
if (!result.ok) process.
|
|
462484
|
+
if (!result.ok) process.exitCode = 1;
|
|
462206
462485
|
return;
|
|
462207
462486
|
}
|
|
462208
462487
|
if (result.ok && result.warningCount === 0 && result.infoCount === 0) {
|
|
@@ -462236,7 +462515,7 @@ sceneCommand.command("lint").description("Validate scene HTML against Hyperframe
|
|
|
462236
462515
|
console.log(` ${source_default.green("\u2714")} ${fx.file} ${source_default.dim(fx.codes.join(", "))}`);
|
|
462237
462516
|
}
|
|
462238
462517
|
}
|
|
462239
|
-
if (!result.ok) process.
|
|
462518
|
+
if (!result.ok) process.exitCode = 1;
|
|
462240
462519
|
});
|
|
462241
462520
|
function severityTag(severity) {
|
|
462242
462521
|
if (severity === "error") return source_default.red("\u2718 error ");
|
|
@@ -462273,23 +462552,27 @@ function validateWorkers(value) {
|
|
|
462273
462552
|
return n;
|
|
462274
462553
|
}
|
|
462275
462554
|
sceneCommand.command("render").description("Render a scene project to MP4/WebM/MOV via the Hyperframes producer (requires Chrome)").argument("[root]", "Root composition file relative to --project", "index.html").option("--project <dir>", "Project directory", ".").option("-o, --out <path>", "Output file (default: renders/<name>-<timestamp>.<format>)").option("--fps <n>", `Frames per second: ${VALID_FPS.join("|")}`, "30").option("--quality <q>", `Quality preset: ${VALID_QUALITIES.join("|")}`, "standard").option("--format <f>", `Output container: ${VALID_FORMATS.join("|")}`, "mp4").option("--workers <n>", "Capture workers (1-16, default 1)", "1").option("--dry-run", "Preview parameters without rendering").action(async (root2, options) => {
|
|
462555
|
+
const startedAt = Date.now();
|
|
462276
462556
|
const fps = validateFps(options.fps);
|
|
462277
462557
|
const quality = validateQuality(options.quality);
|
|
462278
462558
|
const format4 = validateFormat(options.format);
|
|
462279
462559
|
const workers = validateWorkers(options.workers);
|
|
462280
462560
|
const projectDir = resolve21(options.project);
|
|
462281
462561
|
if (options.dryRun) {
|
|
462282
|
-
|
|
462283
|
-
dryRun: true,
|
|
462562
|
+
outputSuccess({
|
|
462284
462563
|
command: "scene render",
|
|
462285
|
-
|
|
462286
|
-
|
|
462287
|
-
|
|
462288
|
-
|
|
462289
|
-
|
|
462290
|
-
|
|
462291
|
-
|
|
462292
|
-
|
|
462564
|
+
startedAt,
|
|
462565
|
+
dryRun: true,
|
|
462566
|
+
data: {
|
|
462567
|
+
params: {
|
|
462568
|
+
projectDir,
|
|
462569
|
+
root: root2,
|
|
462570
|
+
output: options.out,
|
|
462571
|
+
fps,
|
|
462572
|
+
quality,
|
|
462573
|
+
format: format4,
|
|
462574
|
+
workers
|
|
462575
|
+
}
|
|
462293
462576
|
}
|
|
462294
462577
|
});
|
|
462295
462578
|
return;
|
|
@@ -462310,13 +462593,22 @@ sceneCommand.command("render").description("Render a scene project to MP4/WebM/M
|
|
|
462310
462593
|
if (!result.success) {
|
|
462311
462594
|
spinner2?.fail("Render failed");
|
|
462312
462595
|
if (isJsonMode()) {
|
|
462313
|
-
|
|
462314
|
-
|
|
462596
|
+
outputSuccess({
|
|
462597
|
+
command: "scene render",
|
|
462598
|
+
startedAt,
|
|
462599
|
+
data: { ...result }
|
|
462600
|
+
});
|
|
462601
|
+
process.exitCode = 1;
|
|
462602
|
+
return;
|
|
462315
462603
|
}
|
|
462316
462604
|
exitWithError(generalError(result.error ?? "Render failed"));
|
|
462317
462605
|
}
|
|
462318
462606
|
if (isJsonMode()) {
|
|
462319
|
-
|
|
462607
|
+
outputSuccess({
|
|
462608
|
+
command: "scene render",
|
|
462609
|
+
startedAt,
|
|
462610
|
+
data: { ...result }
|
|
462611
|
+
});
|
|
462320
462612
|
return;
|
|
462321
462613
|
}
|
|
462322
462614
|
spinner2?.succeed(source_default.green(`Render complete: ${result.outputPath}`));
|
|
@@ -462336,25 +462628,29 @@ sceneCommand.command("render").description("Render a scene project to MP4/WebM/M
|
|
|
462336
462628
|
}
|
|
462337
462629
|
});
|
|
462338
462630
|
sceneCommand.command("build").description("One-shot: read STORYBOARD.md cues, dispatch TTS + image-gen per beat, compose, render to MP4 (v0.60)").argument("[project-dir]", "Project directory containing STORYBOARD.md", ".").option("--mode <mode>", "Build mode: agent (host-agent authors HTML) | batch (CLI's internal LLM authors HTML) | auto (agent if any host detected) [Plan H \u2014 Phase 3]", "auto").option("--effort <level>", "Compose effort tier (batch mode only): low|medium|high", "medium").option("--composer <provider>", "LLM that composes scene HTML in batch mode: claude|openai|gemini (default: auto-resolve from available API keys, claude > gemini > openai)").option("--skip-narration", "Don't dispatch TTS even when beats declare narration cues").option("--skip-backdrop", "Don't dispatch image-gen even when beats declare backdrop cues").option("--skip-render", "Compose only \u2014 don't render to MP4").option("--tts <provider>", "TTS provider: auto|elevenlabs|kokoro (overrides frontmatter)").option("--voice <id>", "Voice id (provider-specific \u2014 overrides frontmatter)").option("--image-provider <name>", "Image provider: openai (only one supported in v0.60)").option("--quality <q>", "Image quality: standard|hd", "hd").option("--image-size <s>", "Image size: 1024x1024|1536x1024|1024x1536", "1536x1024").option("--force", "Re-dispatch primitives even when assets already exist").option("--dry-run", "Preview parameters without dispatching").action(async (projectDirArg, options) => {
|
|
462631
|
+
const startedAt = Date.now();
|
|
462339
462632
|
const projectDir = resolve21(projectDirArg);
|
|
462340
462633
|
if (options.dryRun) {
|
|
462341
|
-
|
|
462342
|
-
dryRun: true,
|
|
462634
|
+
outputSuccess({
|
|
462343
462635
|
command: "scene build",
|
|
462344
|
-
|
|
462345
|
-
|
|
462346
|
-
|
|
462347
|
-
|
|
462348
|
-
|
|
462349
|
-
|
|
462350
|
-
|
|
462351
|
-
|
|
462352
|
-
|
|
462353
|
-
|
|
462354
|
-
|
|
462355
|
-
|
|
462356
|
-
|
|
462357
|
-
|
|
462636
|
+
startedAt,
|
|
462637
|
+
dryRun: true,
|
|
462638
|
+
data: {
|
|
462639
|
+
params: {
|
|
462640
|
+
projectDir,
|
|
462641
|
+
mode: options.mode,
|
|
462642
|
+
effort: options.effort,
|
|
462643
|
+
composer: options.composer,
|
|
462644
|
+
skipNarration: options.skipNarration ?? false,
|
|
462645
|
+
skipBackdrop: options.skipBackdrop ?? false,
|
|
462646
|
+
skipRender: options.skipRender ?? false,
|
|
462647
|
+
ttsProvider: options.tts,
|
|
462648
|
+
voice: options.voice,
|
|
462649
|
+
imageProvider: options.imageProvider,
|
|
462650
|
+
imageQuality: options.quality,
|
|
462651
|
+
imageSize: options.imageSize,
|
|
462652
|
+
force: options.force ?? false
|
|
462653
|
+
}
|
|
462358
462654
|
}
|
|
462359
462655
|
});
|
|
462360
462656
|
return;
|
|
@@ -462408,13 +462704,22 @@ sceneCommand.command("build").description("One-shot: read STORYBOARD.md cues, di
|
|
|
462408
462704
|
if (!result.success) {
|
|
462409
462705
|
spinner2?.fail(`Build failed: ${result.error}`);
|
|
462410
462706
|
if (isJsonMode()) {
|
|
462411
|
-
|
|
462412
|
-
|
|
462707
|
+
outputSuccess({
|
|
462708
|
+
command: "scene build",
|
|
462709
|
+
startedAt,
|
|
462710
|
+
data: { ...result }
|
|
462711
|
+
});
|
|
462712
|
+
process.exitCode = 1;
|
|
462713
|
+
return;
|
|
462413
462714
|
}
|
|
462414
462715
|
exitWithError(generalError(result.error ?? "Build failed"));
|
|
462415
462716
|
}
|
|
462416
462717
|
if (isJsonMode()) {
|
|
462417
|
-
|
|
462718
|
+
outputSuccess({
|
|
462719
|
+
command: "scene build",
|
|
462720
|
+
startedAt,
|
|
462721
|
+
data: { ...result }
|
|
462722
|
+
});
|
|
462418
462723
|
return;
|
|
462419
462724
|
}
|
|
462420
462725
|
if (result.phase === "needs-author") {
|
|
@@ -465924,6 +466229,7 @@ Cost: Free (no API keys needed). Requires FFmpeg.
|
|
|
465924
466229
|
GIF format: 15fps, no audio, looping. Good for previews and sharing.
|
|
465925
466230
|
Custom flags (--bitrate, --fps, --resolution, --codec) override preset values.
|
|
465926
466231
|
Run 'vibe schema export' for structured parameter info.`).action(async (projectPath, options) => {
|
|
466232
|
+
const startedAt = Date.now();
|
|
465927
466233
|
const spinner2 = ora("Checking FFmpeg...").start();
|
|
465928
466234
|
try {
|
|
465929
466235
|
if (options.output) {
|
|
@@ -465941,27 +466247,30 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
|
|
|
465941
466247
|
exitWithError(usageError(overrideError));
|
|
465942
466248
|
}
|
|
465943
466249
|
if (options.dryRun) {
|
|
465944
|
-
|
|
465945
|
-
dryRun: true,
|
|
466250
|
+
outputSuccess({
|
|
465946
466251
|
command: "export",
|
|
465947
|
-
|
|
465948
|
-
|
|
465949
|
-
|
|
465950
|
-
|
|
465951
|
-
|
|
465952
|
-
|
|
465953
|
-
|
|
465954
|
-
|
|
465955
|
-
|
|
465956
|
-
|
|
465957
|
-
|
|
465958
|
-
|
|
466252
|
+
startedAt,
|
|
466253
|
+
dryRun: true,
|
|
466254
|
+
data: {
|
|
466255
|
+
params: {
|
|
466256
|
+
project: projectPath,
|
|
466257
|
+
output: options.output || null,
|
|
466258
|
+
format: options.format,
|
|
466259
|
+
preset: options.preset,
|
|
466260
|
+
overwrite: options.overwrite,
|
|
466261
|
+
gapFill: options.gapFill,
|
|
466262
|
+
backend: options.backend,
|
|
466263
|
+
bitrate: options.bitrate ?? null,
|
|
466264
|
+
fps: customOverrides.fps ?? null,
|
|
466265
|
+
resolution: options.resolution ?? null,
|
|
466266
|
+
codec: options.codec ?? null
|
|
466267
|
+
}
|
|
465959
466268
|
}
|
|
465960
466269
|
});
|
|
465961
466270
|
return;
|
|
465962
466271
|
}
|
|
465963
466272
|
if (options.backend === "hyperframes") {
|
|
465964
|
-
await runHyperframesExport(projectPath, options, spinner2);
|
|
466273
|
+
await runHyperframesExport(projectPath, options, spinner2, startedAt);
|
|
465965
466274
|
return;
|
|
465966
466275
|
}
|
|
465967
466276
|
const ffmpegPath = await findFFmpeg();
|
|
@@ -466548,13 +466857,13 @@ function getPresetSettings(preset, aspectRatio) {
|
|
|
466548
466857
|
}
|
|
466549
466858
|
return settings;
|
|
466550
466859
|
}
|
|
466551
|
-
async function runHyperframesExport(projectPath, options, spinner2) {
|
|
466860
|
+
async function runHyperframesExport(projectPath, options, spinner2, startedAt) {
|
|
466552
466861
|
spinner2.text = "Loading project...";
|
|
466553
466862
|
const { readFile: readFile34 } = await import("node:fs/promises");
|
|
466554
466863
|
const { resolve: resolve64, basename: basename18 } = await import("node:path");
|
|
466555
466864
|
const { Project: Project2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
466556
466865
|
const { createHyperframesBackend: createHyperframesBackend2 } = await Promise.resolve().then(() => (init_hyperframes(), hyperframes_exports));
|
|
466557
|
-
const { exitWithError: exitWithError2, generalError: generalError2,
|
|
466866
|
+
const { exitWithError: exitWithError2, generalError: generalError2, outputSuccess: outputSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
466558
466867
|
const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
|
|
466559
466868
|
const filePath = resolve64(process.cwd(), projectPath);
|
|
466560
466869
|
const content = await readFile34(filePath, "utf-8");
|
|
@@ -466580,10 +466889,10 @@ async function runHyperframesExport(projectPath, options, spinner2) {
|
|
|
466580
466889
|
return;
|
|
466581
466890
|
}
|
|
466582
466891
|
spinner2.succeed(chalk2.green(`Exported: ${result.outputPath}`));
|
|
466583
|
-
|
|
466584
|
-
success: true,
|
|
466892
|
+
outputSuccess2({
|
|
466585
466893
|
command: "export",
|
|
466586
|
-
|
|
466894
|
+
startedAt,
|
|
466895
|
+
data: {
|
|
466587
466896
|
outputPath: result.outputPath,
|
|
466588
466897
|
backend: "hyperframes",
|
|
466589
466898
|
durationMs: result.durationMs,
|