@vibeframe/mcp-server 0.70.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 +1230 -551
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -79585,19 +79585,19 @@ var require_range = __commonJS({
|
|
|
79585
79585
|
var replaceCaret = (comp, options) => {
|
|
79586
79586
|
debug7("caret", comp, options);
|
|
79587
79587
|
const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
|
|
79588
|
-
const
|
|
79588
|
+
const z13 = options.includePrerelease ? "-0" : "";
|
|
79589
79589
|
return comp.replace(r, (_, M, m, p, pr) => {
|
|
79590
79590
|
debug7("caret", comp, _, M, m, p, pr);
|
|
79591
79591
|
let ret;
|
|
79592
79592
|
if (isX(M)) {
|
|
79593
79593
|
ret = "";
|
|
79594
79594
|
} else if (isX(m)) {
|
|
79595
|
-
ret = `>=${M}.0.0${
|
|
79595
|
+
ret = `>=${M}.0.0${z13} <${+M + 1}.0.0-0`;
|
|
79596
79596
|
} else if (isX(p)) {
|
|
79597
79597
|
if (M === "0") {
|
|
79598
|
-
ret = `>=${M}.${m}.0${
|
|
79598
|
+
ret = `>=${M}.${m}.0${z13} <${M}.${+m + 1}.0-0`;
|
|
79599
79599
|
} else {
|
|
79600
|
-
ret = `>=${M}.${m}.0${
|
|
79600
|
+
ret = `>=${M}.${m}.0${z13} <${+M + 1}.0.0-0`;
|
|
79601
79601
|
}
|
|
79602
79602
|
} else if (pr) {
|
|
79603
79603
|
debug7("replaceCaret pr", pr);
|
|
@@ -79614,9 +79614,9 @@ var require_range = __commonJS({
|
|
|
79614
79614
|
debug7("no pr");
|
|
79615
79615
|
if (M === "0") {
|
|
79616
79616
|
if (m === "0") {
|
|
79617
|
-
ret = `>=${M}.${m}.${p}${
|
|
79617
|
+
ret = `>=${M}.${m}.${p}${z13} <${M}.${m}.${+p + 1}-0`;
|
|
79618
79618
|
} else {
|
|
79619
|
-
ret = `>=${M}.${m}.${p}${
|
|
79619
|
+
ret = `>=${M}.${m}.${p}${z13} <${M}.${+m + 1}.0-0`;
|
|
79620
79620
|
}
|
|
79621
79621
|
} else {
|
|
79622
79622
|
ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;
|
|
@@ -106350,7 +106350,7 @@ var require_emscripten_module_WASM_RELEASE_SYNC = __commonJS({
|
|
|
106350
106350
|
m = b;
|
|
106351
106351
|
n = c;
|
|
106352
106352
|
});
|
|
106353
|
-
var p = Object.assign({}, a), t = "./this.program", u = "object" == typeof window, v = "function" == typeof importScripts, w = "object" == typeof process && "object" == typeof process.versions && "string" == typeof process.versions.node, x = "", y,
|
|
106353
|
+
var p = Object.assign({}, a), t = "./this.program", u = "object" == typeof window, v = "function" == typeof importScripts, w = "object" == typeof process && "object" == typeof process.versions && "string" == typeof process.versions.node, x = "", y, z13, A;
|
|
106354
106354
|
if (w) {
|
|
106355
106355
|
var fs8 = __require("fs"), B = __require("path");
|
|
106356
106356
|
x = v ? B.dirname(x) + "/" : __dirname + "/";
|
|
@@ -106366,7 +106366,7 @@ var require_emscripten_module_WASM_RELEASE_SYNC = __commonJS({
|
|
|
106366
106366
|
b.buffer || (b = new Uint8Array(b));
|
|
106367
106367
|
return b;
|
|
106368
106368
|
};
|
|
106369
|
-
|
|
106369
|
+
z13 = (b, c, d) => {
|
|
106370
106370
|
var e = C(b);
|
|
106371
106371
|
e && c(e);
|
|
106372
106372
|
b = b.startsWith("file://") ? new URL(b) : B.normalize(b);
|
|
@@ -106410,7 +106410,7 @@ var require_emscripten_module_WASM_RELEASE_SYNC = __commonJS({
|
|
|
106410
106410
|
return b;
|
|
106411
106411
|
throw d;
|
|
106412
106412
|
}
|
|
106413
|
-
}),
|
|
106413
|
+
}), z13 = (b, c, d) => {
|
|
106414
106414
|
var e = new XMLHttpRequest();
|
|
106415
106415
|
e.open("GET", b, true);
|
|
106416
106416
|
e.responseType = "arraybuffer";
|
|
@@ -106491,9 +106491,9 @@ var require_emscripten_module_WASM_RELEASE_SYNC = __commonJS({
|
|
|
106491
106491
|
}).catch(function() {
|
|
106492
106492
|
return ha(b);
|
|
106493
106493
|
});
|
|
106494
|
-
if (
|
|
106494
|
+
if (z13)
|
|
106495
106495
|
return new Promise(function(c, d) {
|
|
106496
|
-
|
|
106496
|
+
z13(b, function(e) {
|
|
106497
106497
|
c(new Uint8Array(e));
|
|
106498
106498
|
}, d);
|
|
106499
106499
|
});
|
|
@@ -347714,8 +347714,8 @@ async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
|
347714
347714
|
while (current) {
|
|
347715
347715
|
const cs = window.getComputedStyle(current);
|
|
347716
347716
|
const pos = cs.position;
|
|
347717
|
-
const
|
|
347718
|
-
if (!Number.isNaN(
|
|
347717
|
+
const z13 = parseInt(cs.zIndex);
|
|
347718
|
+
if (!Number.isNaN(z13) && pos !== "static") return z13;
|
|
347719
347719
|
current = current.parentElement;
|
|
347720
347720
|
}
|
|
347721
347721
|
return 0;
|
|
@@ -396287,19 +396287,19 @@ ${sourceUrlComment}
|
|
|
396287
396287
|
var replaceCaret = (comp, options) => {
|
|
396288
396288
|
debug62("caret", comp, options);
|
|
396289
396289
|
const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
|
|
396290
|
-
const
|
|
396290
|
+
const z13 = options.includePrerelease ? "-0" : "";
|
|
396291
396291
|
return comp.replace(r, (_, M, m, p, pr) => {
|
|
396292
396292
|
debug62("caret", comp, _, M, m, p, pr);
|
|
396293
396293
|
let ret;
|
|
396294
396294
|
if (isX(M)) {
|
|
396295
396295
|
ret = "";
|
|
396296
396296
|
} else if (isX(m)) {
|
|
396297
|
-
ret = `>=${M}.0.0${
|
|
396297
|
+
ret = `>=${M}.0.0${z13} <${+M + 1}.0.0-0`;
|
|
396298
396298
|
} else if (isX(p)) {
|
|
396299
396299
|
if (M === "0") {
|
|
396300
|
-
ret = `>=${M}.${m}.0${
|
|
396300
|
+
ret = `>=${M}.${m}.0${z13} <${M}.${+m + 1}.0-0`;
|
|
396301
396301
|
} else {
|
|
396302
|
-
ret = `>=${M}.${m}.0${
|
|
396302
|
+
ret = `>=${M}.${m}.0${z13} <${+M + 1}.0.0-0`;
|
|
396303
396303
|
}
|
|
396304
396304
|
} else if (pr) {
|
|
396305
396305
|
debug62("replaceCaret pr", pr);
|
|
@@ -396316,9 +396316,9 @@ ${sourceUrlComment}
|
|
|
396316
396316
|
debug62("no pr");
|
|
396317
396317
|
if (M === "0") {
|
|
396318
396318
|
if (m === "0") {
|
|
396319
|
-
ret = `>=${M}.${m}.${p}${
|
|
396319
|
+
ret = `>=${M}.${m}.${p}${z13} <${M}.${m}.${+p + 1}-0`;
|
|
396320
396320
|
} else {
|
|
396321
|
-
ret = `>=${M}.${m}.${p}${
|
|
396321
|
+
ret = `>=${M}.${m}.${p}${z13} <${M}.${+m + 1}.0-0`;
|
|
396322
396322
|
}
|
|
396323
396323
|
} else {
|
|
396324
396324
|
ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;
|
|
@@ -422114,7 +422114,7 @@ Attempted to suspend at:`);
|
|
|
422114
422114
|
m = b;
|
|
422115
422115
|
n = c;
|
|
422116
422116
|
});
|
|
422117
|
-
var p = Object.assign({}, a), t = "./this.program", u = "object" == typeof window, v = "function" == typeof importScripts, w = "object" == typeof process && "object" == typeof process.versions && "string" == typeof process.versions.node, x = "", y,
|
|
422117
|
+
var p = Object.assign({}, a), t = "./this.program", u = "object" == typeof window, v = "function" == typeof importScripts, w = "object" == typeof process && "object" == typeof process.versions && "string" == typeof process.versions.node, x = "", y, z13, A;
|
|
422118
422118
|
if (w) {
|
|
422119
422119
|
var fs8 = __require2("fs"), B = __require2("path");
|
|
422120
422120
|
x = v ? B.dirname(x) + "/" : __dirname + "/";
|
|
@@ -422130,7 +422130,7 @@ Attempted to suspend at:`);
|
|
|
422130
422130
|
b.buffer || (b = new Uint8Array(b));
|
|
422131
422131
|
return b;
|
|
422132
422132
|
};
|
|
422133
|
-
|
|
422133
|
+
z13 = (b, c, d) => {
|
|
422134
422134
|
var e = C(b);
|
|
422135
422135
|
e && c(e);
|
|
422136
422136
|
b = b.startsWith("file://") ? new URL(b) : B.normalize(b);
|
|
@@ -422174,7 +422174,7 @@ Attempted to suspend at:`);
|
|
|
422174
422174
|
return b;
|
|
422175
422175
|
throw d;
|
|
422176
422176
|
}
|
|
422177
|
-
}),
|
|
422177
|
+
}), z13 = (b, c, d) => {
|
|
422178
422178
|
var e = new XMLHttpRequest();
|
|
422179
422179
|
e.open("GET", b, true);
|
|
422180
422180
|
e.responseType = "arraybuffer";
|
|
@@ -422255,9 +422255,9 @@ Attempted to suspend at:`);
|
|
|
422255
422255
|
}).catch(function() {
|
|
422256
422256
|
return ha(b);
|
|
422257
422257
|
});
|
|
422258
|
-
if (
|
|
422258
|
+
if (z13)
|
|
422259
422259
|
return new Promise(function(c, d) {
|
|
422260
|
-
|
|
422260
|
+
z13(b, function(e) {
|
|
422261
422261
|
c(new Uint8Array(e));
|
|
422262
422262
|
}, d);
|
|
422263
422263
|
});
|
|
@@ -448826,6 +448826,26 @@ function detectAgentHosts(env4 = process.env) {
|
|
|
448826
448826
|
detected: false,
|
|
448827
448827
|
signals: [],
|
|
448828
448828
|
projectFiles: ["AGENTS.md", ".aider.conf.yml"]
|
|
448829
|
+
},
|
|
448830
|
+
{
|
|
448831
|
+
id: "gemini-cli",
|
|
448832
|
+
label: "Gemini CLI",
|
|
448833
|
+
detected: false,
|
|
448834
|
+
signals: [],
|
|
448835
|
+
// Per https://geminicli.com/docs/cli/gemini-md/ Gemini CLI's primary
|
|
448836
|
+
// context file is GEMINI.md; AGENTS.md is the cross-tool fallback
|
|
448837
|
+
// VibeFrame writes by default. Both are honoured.
|
|
448838
|
+
projectFiles: ["GEMINI.md", "AGENTS.md", ".gemini/"]
|
|
448839
|
+
},
|
|
448840
|
+
{
|
|
448841
|
+
id: "opencode",
|
|
448842
|
+
label: "OpenCode",
|
|
448843
|
+
detected: false,
|
|
448844
|
+
signals: [],
|
|
448845
|
+
// sst/opencode officially supports the agents.md spec — AGENTS.md at
|
|
448846
|
+
// project root is the standard place. Local config also under
|
|
448847
|
+
// `.opencode/` per https://opencode.ai/docs/config/.
|
|
448848
|
+
projectFiles: ["AGENTS.md", ".opencode/"]
|
|
448829
448849
|
}
|
|
448830
448850
|
].map((host) => {
|
|
448831
448851
|
const signals2 = [];
|
|
@@ -448873,14 +448893,21 @@ var init_agent_host_detect = __esm({
|
|
|
448873
448893
|
"claude-code": "claude",
|
|
448874
448894
|
codex: "codex",
|
|
448875
448895
|
cursor: "cursor",
|
|
448876
|
-
aider: "aider"
|
|
448896
|
+
aider: "aider",
|
|
448897
|
+
"gemini-cli": "gemini",
|
|
448898
|
+
opencode: "opencode"
|
|
448877
448899
|
};
|
|
448878
448900
|
HOST_CONFIG_DIRS = {
|
|
448879
448901
|
"claude-code": ".claude",
|
|
448880
448902
|
codex: ".codex",
|
|
448881
448903
|
cursor: ".cursor",
|
|
448882
448904
|
// some installs; macOS app stores prefs elsewhere
|
|
448883
|
-
aider: null
|
|
448905
|
+
aider: null,
|
|
448906
|
+
"gemini-cli": ".gemini",
|
|
448907
|
+
// sst/opencode uses XDG-style `~/.config/opencode/` per
|
|
448908
|
+
// https://opencode.ai/docs/config/. The path is relative to $HOME so
|
|
448909
|
+
// the join in detectAgentHosts() resolves correctly.
|
|
448910
|
+
opencode: ".config/opencode"
|
|
448884
448911
|
};
|
|
448885
448912
|
}
|
|
448886
448913
|
});
|
|
@@ -449205,6 +449232,7 @@ __export(output_exports, {
|
|
|
449205
449232
|
notFoundError: () => notFoundError,
|
|
449206
449233
|
outputError: () => outputError,
|
|
449207
449234
|
outputResult: () => outputResult,
|
|
449235
|
+
outputSuccess: () => outputSuccess,
|
|
449208
449236
|
spinner: () => spinner,
|
|
449209
449237
|
suggestNext: () => suggestNext,
|
|
449210
449238
|
usageError: () => usageError
|
|
@@ -449263,6 +449291,40 @@ function formatCost(min, max, unit) {
|
|
|
449263
449291
|
if (min === max) return `~$${min.toFixed(2)} ${unit}`;
|
|
449264
449292
|
return `~$${min.toFixed(2)}-$${max.toFixed(2)} ${unit}`;
|
|
449265
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
|
+
}
|
|
449266
449328
|
function outputResult(result) {
|
|
449267
449329
|
if (result.dryRun && result.command && typeof result.command === "string") {
|
|
449268
449330
|
const cost = COST_ESTIMATES[result.command];
|
|
@@ -451854,6 +451916,7 @@ Examples:
|
|
|
451854
451916
|
$ vibe ed sc video.mp4 --dry-run --json
|
|
451855
451917
|
|
|
451856
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();
|
|
451857
451920
|
try {
|
|
451858
451921
|
if (options.output) {
|
|
451859
451922
|
validateOutputPath(options.output);
|
|
@@ -451870,16 +451933,19 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
|
|
|
451870
451933
|
const outputPath = options.output || `${name}-cut${ext}`;
|
|
451871
451934
|
const useGemini = options.useGemini || false;
|
|
451872
451935
|
if (options.dryRun) {
|
|
451873
|
-
|
|
451874
|
-
dryRun: true,
|
|
451936
|
+
outputSuccess({
|
|
451875
451937
|
command: "edit silence-cut",
|
|
451876
|
-
|
|
451877
|
-
|
|
451878
|
-
|
|
451879
|
-
|
|
451880
|
-
|
|
451881
|
-
|
|
451882
|
-
|
|
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
|
+
}
|
|
451883
451949
|
}
|
|
451884
451950
|
});
|
|
451885
451951
|
return;
|
|
@@ -451904,13 +451970,16 @@ No API key needed (FFmpeg only). Use --use-gemini for smart detection (requires
|
|
|
451904
451970
|
}
|
|
451905
451971
|
spinner2.succeed(source_default.green("Silence detection complete"));
|
|
451906
451972
|
if (isJsonMode()) {
|
|
451907
|
-
|
|
451908
|
-
|
|
451909
|
-
|
|
451910
|
-
|
|
451911
|
-
|
|
451912
|
-
|
|
451913
|
-
|
|
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
|
+
}
|
|
451914
451983
|
});
|
|
451915
451984
|
return;
|
|
451916
451985
|
}
|
|
@@ -451948,6 +452017,7 @@ Examples:
|
|
|
451948
452017
|
$ vibe ed cap video.mp4 --dry-run --json
|
|
451949
452018
|
|
|
451950
452019
|
Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoPath, options) => {
|
|
452020
|
+
const startedAt = Date.now();
|
|
451951
452021
|
try {
|
|
451952
452022
|
if (options.output) {
|
|
451953
452023
|
validateOutputPath(options.output);
|
|
@@ -451960,16 +452030,19 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
451960
452030
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
451961
452031
|
}
|
|
451962
452032
|
if (options.dryRun) {
|
|
451963
|
-
|
|
451964
|
-
dryRun: true,
|
|
452033
|
+
outputSuccess({
|
|
451965
452034
|
command: "edit caption",
|
|
451966
|
-
|
|
451967
|
-
|
|
451968
|
-
|
|
451969
|
-
|
|
451970
|
-
|
|
451971
|
-
|
|
451972
|
-
|
|
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
|
+
}
|
|
451973
452046
|
}
|
|
451974
452047
|
});
|
|
451975
452048
|
return;
|
|
@@ -451998,12 +452071,15 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
451998
452071
|
}
|
|
451999
452072
|
spinner2.succeed(source_default.green("Captions applied"));
|
|
452000
452073
|
if (isJsonMode()) {
|
|
452001
|
-
|
|
452002
|
-
|
|
452003
|
-
|
|
452004
|
-
|
|
452005
|
-
|
|
452006
|
-
|
|
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
|
+
}
|
|
452007
452083
|
});
|
|
452008
452084
|
return;
|
|
452009
452085
|
}
|
|
@@ -452022,6 +452098,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452022
452098
|
}
|
|
452023
452099
|
});
|
|
452024
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();
|
|
452025
452102
|
try {
|
|
452026
452103
|
if (options.output) {
|
|
452027
452104
|
validateOutputPath(options.output);
|
|
@@ -452034,13 +452111,16 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452034
452111
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
452035
452112
|
}
|
|
452036
452113
|
if (options.dryRun) {
|
|
452037
|
-
|
|
452038
|
-
dryRun: true,
|
|
452114
|
+
outputSuccess({
|
|
452039
452115
|
command: "edit noise-reduce",
|
|
452040
|
-
|
|
452041
|
-
|
|
452042
|
-
|
|
452043
|
-
|
|
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
|
+
}
|
|
452044
452124
|
}
|
|
452045
452125
|
});
|
|
452046
452126
|
return;
|
|
@@ -452061,11 +452141,14 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452061
452141
|
}
|
|
452062
452142
|
spinner2.succeed(source_default.green("Noise reduction complete"));
|
|
452063
452143
|
if (isJsonMode()) {
|
|
452064
|
-
|
|
452065
|
-
|
|
452066
|
-
|
|
452067
|
-
|
|
452068
|
-
|
|
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
|
+
}
|
|
452069
452152
|
});
|
|
452070
452153
|
return;
|
|
452071
452154
|
}
|
|
@@ -452081,6 +452164,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452081
452164
|
}
|
|
452082
452165
|
});
|
|
452083
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();
|
|
452084
452168
|
try {
|
|
452085
452169
|
if (options.output) {
|
|
452086
452170
|
validateOutputPath(options.output);
|
|
@@ -452093,15 +452177,18 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452093
452177
|
exitWithError(generalError("FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details."));
|
|
452094
452178
|
}
|
|
452095
452179
|
if (options.dryRun) {
|
|
452096
|
-
|
|
452097
|
-
dryRun: true,
|
|
452180
|
+
outputSuccess({
|
|
452098
452181
|
command: "edit fade",
|
|
452099
|
-
|
|
452100
|
-
|
|
452101
|
-
|
|
452102
|
-
|
|
452103
|
-
|
|
452104
|
-
|
|
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
|
+
}
|
|
452105
452192
|
}
|
|
452106
452193
|
});
|
|
452107
452194
|
return;
|
|
@@ -452124,12 +452211,15 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452124
452211
|
}
|
|
452125
452212
|
spinner2.succeed(source_default.green("Fade effects applied"));
|
|
452126
452213
|
if (isJsonMode()) {
|
|
452127
|
-
|
|
452128
|
-
|
|
452129
|
-
|
|
452130
|
-
|
|
452131
|
-
|
|
452132
|
-
|
|
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
|
+
}
|
|
452133
452223
|
});
|
|
452134
452224
|
return;
|
|
452135
452225
|
}
|
|
@@ -452146,6 +452236,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452146
452236
|
}
|
|
452147
452237
|
});
|
|
452148
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();
|
|
452149
452240
|
try {
|
|
452150
452241
|
if (options.output) {
|
|
452151
452242
|
validateOutputPath(options.output);
|
|
@@ -452158,14 +452249,17 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452158
452249
|
exitWithError(notFoundError(absSrtPath));
|
|
452159
452250
|
}
|
|
452160
452251
|
if (options.dryRun) {
|
|
452161
|
-
|
|
452162
|
-
dryRun: true,
|
|
452252
|
+
outputSuccess({
|
|
452163
452253
|
command: "edit translate-srt",
|
|
452164
|
-
|
|
452165
|
-
|
|
452166
|
-
|
|
452167
|
-
|
|
452168
|
-
|
|
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
|
+
}
|
|
452169
452263
|
}
|
|
452170
452264
|
});
|
|
452171
452265
|
return;
|
|
@@ -452195,12 +452289,15 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452195
452289
|
}
|
|
452196
452290
|
spinner2.succeed(source_default.green("Translation complete"));
|
|
452197
452291
|
if (isJsonMode()) {
|
|
452198
|
-
|
|
452199
|
-
|
|
452200
|
-
|
|
452201
|
-
|
|
452202
|
-
|
|
452203
|
-
|
|
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
|
+
}
|
|
452204
452301
|
});
|
|
452205
452302
|
return;
|
|
452206
452303
|
}
|
|
@@ -452217,6 +452314,7 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452217
452314
|
}
|
|
452218
452315
|
});
|
|
452219
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();
|
|
452220
452318
|
try {
|
|
452221
452319
|
if (options.output) {
|
|
452222
452320
|
validateOutputPath(options.output);
|
|
@@ -452231,15 +452329,18 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452231
452329
|
}
|
|
452232
452330
|
if (options.dryRun) {
|
|
452233
452331
|
const fillers2 = options.fillers ? options.fillers.split(",").map((f) => f.trim()) : void 0;
|
|
452234
|
-
|
|
452235
|
-
dryRun: true,
|
|
452332
|
+
outputSuccess({
|
|
452236
452333
|
command: "edit jump-cut",
|
|
452237
|
-
|
|
452238
|
-
|
|
452239
|
-
|
|
452240
|
-
|
|
452241
|
-
|
|
452242
|
-
|
|
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
|
+
}
|
|
452243
452344
|
}
|
|
452244
452345
|
});
|
|
452245
452346
|
return;
|
|
@@ -452268,13 +452369,16 @@ Requires: OPENAI_API_KEY (Whisper transcription) + FFmpeg`).action(async (videoP
|
|
|
452268
452369
|
}
|
|
452269
452370
|
spinner2.succeed(source_default.green("Filler detection complete"));
|
|
452270
452371
|
if (isJsonMode()) {
|
|
452271
|
-
|
|
452272
|
-
|
|
452273
|
-
|
|
452274
|
-
|
|
452275
|
-
|
|
452276
|
-
|
|
452277
|
-
|
|
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
|
+
}
|
|
452278
452382
|
});
|
|
452279
452383
|
return;
|
|
452280
452384
|
}
|
|
@@ -453419,6 +453523,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453419
453523
|
registerEditCommands(editCommand);
|
|
453420
453524
|
registerFillGapsCommand(editCommand);
|
|
453421
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();
|
|
453422
453527
|
try {
|
|
453423
453528
|
if (options.style) rejectControlChars(options.style);
|
|
453424
453529
|
if (options.output) {
|
|
@@ -453434,13 +453539,16 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453434
453539
|
exitWithError(notFoundError("FFmpeg not found. Install with: brew install ffmpeg"));
|
|
453435
453540
|
}
|
|
453436
453541
|
if (options.dryRun) {
|
|
453437
|
-
|
|
453438
|
-
dryRun: true,
|
|
453542
|
+
outputSuccess({
|
|
453439
453543
|
command: "edit grade",
|
|
453440
|
-
|
|
453441
|
-
|
|
453442
|
-
|
|
453443
|
-
|
|
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
|
+
}
|
|
453444
453552
|
}
|
|
453445
453553
|
});
|
|
453446
453554
|
return;
|
|
@@ -453466,12 +453574,15 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453466
453574
|
if (isJsonMode()) {
|
|
453467
453575
|
const absPath2 = resolve29(process.cwd(), videoPath);
|
|
453468
453576
|
const gradeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
|
|
453469
|
-
|
|
453470
|
-
|
|
453471
|
-
|
|
453472
|
-
|
|
453473
|
-
|
|
453474
|
-
|
|
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
|
+
}
|
|
453475
453586
|
});
|
|
453476
453587
|
return;
|
|
453477
453588
|
}
|
|
@@ -453500,6 +453611,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453500
453611
|
}
|
|
453501
453612
|
});
|
|
453502
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();
|
|
453503
453615
|
try {
|
|
453504
453616
|
if (!options.text || options.text.length === 0) {
|
|
453505
453617
|
exitWithError(usageError("At least one --text option is required", 'Example: vibe edit text-overlay video.mp4 -t "NEXUS AI" --style center-bold'));
|
|
@@ -453512,18 +453624,21 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453512
453624
|
exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
|
|
453513
453625
|
}
|
|
453514
453626
|
if (options.dryRun) {
|
|
453515
|
-
|
|
453516
|
-
dryRun: true,
|
|
453627
|
+
outputSuccess({
|
|
453517
453628
|
command: "edit text-overlay",
|
|
453518
|
-
|
|
453519
|
-
|
|
453520
|
-
|
|
453521
|
-
|
|
453522
|
-
|
|
453523
|
-
|
|
453524
|
-
|
|
453525
|
-
|
|
453526
|
-
|
|
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
|
+
}
|
|
453527
453642
|
}
|
|
453528
453643
|
});
|
|
453529
453644
|
return;
|
|
@@ -453548,11 +453663,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453548
453663
|
}
|
|
453549
453664
|
spinner2.succeed(source_default.green("Text overlays applied"));
|
|
453550
453665
|
if (isJsonMode()) {
|
|
453551
|
-
|
|
453552
|
-
|
|
453553
|
-
|
|
453554
|
-
|
|
453555
|
-
|
|
453666
|
+
outputSuccess({
|
|
453667
|
+
command: "edit text-overlay",
|
|
453668
|
+
startedAt,
|
|
453669
|
+
data: {
|
|
453670
|
+
style: options.style,
|
|
453671
|
+
texts: options.text,
|
|
453672
|
+
outputPath: result.outputPath
|
|
453673
|
+
}
|
|
453556
453674
|
});
|
|
453557
453675
|
return;
|
|
453558
453676
|
}
|
|
@@ -453569,6 +453687,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453569
453687
|
}
|
|
453570
453688
|
});
|
|
453571
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();
|
|
453572
453691
|
try {
|
|
453573
453692
|
if (options.output) {
|
|
453574
453693
|
validateOutputPath(options.output);
|
|
@@ -453577,15 +453696,18 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453577
453696
|
exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
|
|
453578
453697
|
}
|
|
453579
453698
|
if (options.dryRun) {
|
|
453580
|
-
|
|
453581
|
-
dryRun: true,
|
|
453699
|
+
outputSuccess({
|
|
453582
453700
|
command: "edit speed-ramp",
|
|
453583
|
-
|
|
453584
|
-
|
|
453585
|
-
|
|
453586
|
-
|
|
453587
|
-
|
|
453588
|
-
|
|
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
|
+
}
|
|
453589
453711
|
}
|
|
453590
453712
|
});
|
|
453591
453713
|
return;
|
|
@@ -453638,11 +453760,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453638
453760
|
if (isJsonMode()) {
|
|
453639
453761
|
const avgSpeed2 = speedResult.keyframes.reduce((sum, kf) => sum + kf.speed, 0) / speedResult.keyframes.length;
|
|
453640
453762
|
const speedRampOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
|
|
453641
|
-
|
|
453642
|
-
|
|
453643
|
-
|
|
453644
|
-
|
|
453645
|
-
|
|
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
|
+
}
|
|
453646
453771
|
});
|
|
453647
453772
|
return;
|
|
453648
453773
|
}
|
|
@@ -453682,6 +453807,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453682
453807
|
}
|
|
453683
453808
|
});
|
|
453684
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();
|
|
453685
453811
|
try {
|
|
453686
453812
|
if (options.output) {
|
|
453687
453813
|
validateOutputPath(options.output);
|
|
@@ -453690,14 +453816,17 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453690
453816
|
exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
|
|
453691
453817
|
}
|
|
453692
453818
|
if (options.dryRun) {
|
|
453693
|
-
|
|
453694
|
-
dryRun: true,
|
|
453819
|
+
outputSuccess({
|
|
453695
453820
|
command: "edit reframe",
|
|
453696
|
-
|
|
453697
|
-
|
|
453698
|
-
|
|
453699
|
-
|
|
453700
|
-
|
|
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
|
+
}
|
|
453701
453830
|
}
|
|
453702
453831
|
});
|
|
453703
453832
|
return;
|
|
@@ -453765,13 +453894,16 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453765
453894
|
spinner2.succeed(source_default.green(`Analyzed ${cropKeyframes.length} keyframes`));
|
|
453766
453895
|
if (isJsonMode()) {
|
|
453767
453896
|
const reframeOutputPath = options.output ? resolve29(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
|
|
453768
|
-
|
|
453769
|
-
|
|
453770
|
-
|
|
453771
|
-
|
|
453772
|
-
|
|
453773
|
-
|
|
453774
|
-
|
|
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
|
+
}
|
|
453775
453907
|
});
|
|
453776
453908
|
return;
|
|
453777
453909
|
}
|
|
@@ -453822,6 +453954,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453822
453954
|
}
|
|
453823
453955
|
});
|
|
453824
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();
|
|
453825
453958
|
try {
|
|
453826
453959
|
if (args.length < 2) {
|
|
453827
453960
|
exitWithError(usageError("Need at least one image and a prompt"));
|
|
@@ -453837,16 +453970,19 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453837
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."));
|
|
453838
453971
|
}
|
|
453839
453972
|
if (options.dryRun) {
|
|
453840
|
-
|
|
453841
|
-
dryRun: true,
|
|
453973
|
+
outputSuccess({
|
|
453842
453974
|
command: "edit image",
|
|
453843
|
-
|
|
453844
|
-
|
|
453845
|
-
|
|
453846
|
-
|
|
453847
|
-
|
|
453848
|
-
|
|
453849
|
-
|
|
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
|
+
}
|
|
453850
453986
|
}
|
|
453851
453987
|
});
|
|
453852
453988
|
return;
|
|
@@ -453924,11 +454060,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453924
454060
|
};
|
|
453925
454061
|
const resultModel = result.model;
|
|
453926
454062
|
if (isJsonMode()) {
|
|
453927
|
-
|
|
453928
|
-
|
|
453929
|
-
|
|
453930
|
-
|
|
453931
|
-
|
|
454063
|
+
outputSuccess({
|
|
454064
|
+
command: "edit image",
|
|
454065
|
+
startedAt,
|
|
454066
|
+
data: {
|
|
454067
|
+
provider,
|
|
454068
|
+
model: resultModel || options.model,
|
|
454069
|
+
outputPath
|
|
454070
|
+
}
|
|
453932
454071
|
});
|
|
453933
454072
|
await saveImage();
|
|
453934
454073
|
return;
|
|
@@ -453944,6 +454083,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453944
454083
|
}
|
|
453945
454084
|
});
|
|
453946
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();
|
|
453947
454087
|
try {
|
|
453948
454088
|
if (options.output) {
|
|
453949
454089
|
validateOutputPath(options.output);
|
|
@@ -453954,14 +454094,17 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453954
454094
|
exitWithError(usageError("Factor must be 2, 4, or 8"));
|
|
453955
454095
|
}
|
|
453956
454096
|
if (options.dryRun) {
|
|
453957
|
-
|
|
453958
|
-
dryRun: true,
|
|
454097
|
+
outputSuccess({
|
|
453959
454098
|
command: "edit interpolate",
|
|
453960
|
-
|
|
453961
|
-
|
|
453962
|
-
|
|
453963
|
-
|
|
453964
|
-
|
|
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
|
+
}
|
|
453965
454108
|
}
|
|
453966
454109
|
});
|
|
453967
454110
|
return;
|
|
@@ -453988,12 +454131,15 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
453988
454131
|
await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 6e5 });
|
|
453989
454132
|
spinner2.succeed(source_default.green(`Created ${factor}x slow motion`));
|
|
453990
454133
|
if (isJsonMode()) {
|
|
453991
|
-
|
|
453992
|
-
|
|
453993
|
-
|
|
453994
|
-
|
|
453995
|
-
|
|
453996
|
-
|
|
454134
|
+
outputSuccess({
|
|
454135
|
+
command: "edit interpolate",
|
|
454136
|
+
startedAt,
|
|
454137
|
+
data: {
|
|
454138
|
+
originalFps,
|
|
454139
|
+
targetFps,
|
|
454140
|
+
factor,
|
|
454141
|
+
outputPath
|
|
454142
|
+
}
|
|
453997
454143
|
});
|
|
453998
454144
|
return;
|
|
453999
454145
|
}
|
|
@@ -454019,6 +454165,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
454019
454165
|
}
|
|
454020
454166
|
});
|
|
454021
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();
|
|
454022
454169
|
try {
|
|
454023
454170
|
if (options.output) {
|
|
454024
454171
|
validateOutputPath(options.output);
|
|
@@ -454029,14 +454176,17 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
454029
454176
|
exitWithError(usageError("Scale must be 2 or 4"));
|
|
454030
454177
|
}
|
|
454031
454178
|
if (options.dryRun) {
|
|
454032
|
-
|
|
454033
|
-
dryRun: true,
|
|
454179
|
+
outputSuccess({
|
|
454034
454180
|
command: "edit upscale-video",
|
|
454035
|
-
|
|
454036
|
-
|
|
454037
|
-
|
|
454038
|
-
|
|
454039
|
-
|
|
454181
|
+
startedAt,
|
|
454182
|
+
dryRun: true,
|
|
454183
|
+
data: {
|
|
454184
|
+
params: {
|
|
454185
|
+
videoPath: absPath,
|
|
454186
|
+
scale,
|
|
454187
|
+
model: options.model,
|
|
454188
|
+
ffmpeg: options.ffmpeg || false
|
|
454189
|
+
}
|
|
454040
454190
|
}
|
|
454041
454191
|
});
|
|
454042
454192
|
return;
|
|
@@ -454062,10 +454212,13 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
454062
454212
|
await execSafe("ffmpeg", ["-i", absPath, "-vf", `scale=${newWidth}:${newHeight}:flags=lanczos`, "-c:a", "copy", outputPath, "-y"]);
|
|
454063
454213
|
spinner3.succeed(source_default.green(`Upscaled to ${newWidth}x${newHeight}`));
|
|
454064
454214
|
if (isJsonMode()) {
|
|
454065
|
-
|
|
454066
|
-
|
|
454067
|
-
|
|
454068
|
-
|
|
454215
|
+
outputSuccess({
|
|
454216
|
+
command: "edit upscale-video",
|
|
454217
|
+
startedAt,
|
|
454218
|
+
data: {
|
|
454219
|
+
dimensions: `${newWidth}x${newHeight}`,
|
|
454220
|
+
outputPath
|
|
454221
|
+
}
|
|
454069
454222
|
});
|
|
454070
454223
|
return;
|
|
454071
454224
|
}
|
|
@@ -454770,21 +454923,25 @@ Score each category 1-10. For fixable issues, provide an FFmpeg filter in autoFi
|
|
|
454770
454923
|
}
|
|
454771
454924
|
function registerReviewCommand(aiCommand) {
|
|
454772
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();
|
|
454773
454927
|
try {
|
|
454774
454928
|
if (options.output) {
|
|
454775
454929
|
validateOutputPath(options.output);
|
|
454776
454930
|
}
|
|
454777
454931
|
if (options.dryRun) {
|
|
454778
|
-
|
|
454779
|
-
dryRun: true,
|
|
454932
|
+
outputSuccess({
|
|
454780
454933
|
command: "ai review",
|
|
454781
|
-
|
|
454782
|
-
|
|
454783
|
-
|
|
454784
|
-
|
|
454785
|
-
|
|
454786
|
-
|
|
454787
|
-
|
|
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
|
+
}
|
|
454788
454945
|
}
|
|
454789
454946
|
});
|
|
454790
454947
|
return;
|
|
@@ -455052,27 +455209,31 @@ Use this image analysis to inform the color palette, typography placement, and o
|
|
|
455052
455209
|
}
|
|
455053
455210
|
function registerMotionCommand(aiCommand) {
|
|
455054
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();
|
|
455055
455213
|
try {
|
|
455056
455214
|
if (options.output) {
|
|
455057
455215
|
validateOutputPath(options.output);
|
|
455058
455216
|
}
|
|
455059
455217
|
if (options.dryRun) {
|
|
455060
|
-
|
|
455218
|
+
outputSuccess({
|
|
455219
|
+
command: "generate motion",
|
|
455220
|
+
startedAt,
|
|
455061
455221
|
dryRun: true,
|
|
455062
|
-
|
|
455063
|
-
|
|
455064
|
-
|
|
455065
|
-
|
|
455066
|
-
|
|
455067
|
-
|
|
455068
|
-
|
|
455069
|
-
|
|
455070
|
-
|
|
455071
|
-
|
|
455072
|
-
|
|
455073
|
-
|
|
455074
|
-
|
|
455075
|
-
|
|
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
|
+
}
|
|
455076
455237
|
}
|
|
455077
455238
|
});
|
|
455078
455239
|
return;
|
|
@@ -455186,20 +455347,24 @@ async function executeSoundEffect(options) {
|
|
|
455186
455347
|
}
|
|
455187
455348
|
function registerSoundEffectCommand(parent) {
|
|
455188
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();
|
|
455189
455351
|
try {
|
|
455190
455352
|
rejectControlChars(prompt3);
|
|
455191
455353
|
if (options.output) {
|
|
455192
455354
|
validateOutputPath(options.output);
|
|
455193
455355
|
}
|
|
455194
455356
|
if (options.dryRun) {
|
|
455195
|
-
|
|
455196
|
-
dryRun: true,
|
|
455357
|
+
outputSuccess({
|
|
455197
455358
|
command: "generate sound-effect",
|
|
455198
|
-
|
|
455199
|
-
|
|
455200
|
-
|
|
455201
|
-
|
|
455202
|
-
|
|
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
|
+
}
|
|
455203
455368
|
}
|
|
455204
455369
|
});
|
|
455205
455370
|
return;
|
|
@@ -455226,7 +455391,11 @@ function registerSoundEffectCommand(parent) {
|
|
|
455226
455391
|
await writeFile22(outputPath, result.audioBuffer);
|
|
455227
455392
|
spinner2.succeed(source_default.green("Sound effect generated"));
|
|
455228
455393
|
if (isJsonMode()) {
|
|
455229
|
-
|
|
455394
|
+
outputSuccess({
|
|
455395
|
+
command: "generate sound-effect",
|
|
455396
|
+
startedAt,
|
|
455397
|
+
data: { outputPath }
|
|
455398
|
+
});
|
|
455230
455399
|
return;
|
|
455231
455400
|
}
|
|
455232
455401
|
console.log(source_default.green(`Saved to: ${outputPath}`));
|
|
@@ -455276,6 +455445,7 @@ async function executeMusicStatus(options) {
|
|
|
455276
455445
|
}
|
|
455277
455446
|
function registerMusicStatusCommand(parent) {
|
|
455278
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();
|
|
455279
455449
|
try {
|
|
455280
455450
|
const apiKey = await requireApiKey(
|
|
455281
455451
|
"REPLICATE_API_TOKEN",
|
|
@@ -455287,12 +455457,15 @@ function registerMusicStatusCommand(parent) {
|
|
|
455287
455457
|
const result = await replicate.getMusicStatus(taskId);
|
|
455288
455458
|
if (isJsonMode()) {
|
|
455289
455459
|
const status = result.audioUrl ? "completed" : result.error ? "failed" : "processing";
|
|
455290
|
-
|
|
455291
|
-
|
|
455292
|
-
|
|
455293
|
-
|
|
455294
|
-
|
|
455295
|
-
|
|
455460
|
+
outputSuccess({
|
|
455461
|
+
command: "generate music-status",
|
|
455462
|
+
startedAt,
|
|
455463
|
+
data: {
|
|
455464
|
+
taskId,
|
|
455465
|
+
status,
|
|
455466
|
+
audioUrl: result.audioUrl,
|
|
455467
|
+
error: result.error
|
|
455468
|
+
}
|
|
455296
455469
|
});
|
|
455297
455470
|
return;
|
|
455298
455471
|
}
|
|
@@ -455330,6 +455503,7 @@ var init_music_status = __esm({
|
|
|
455330
455503
|
// ../cli/src/commands/generate/video-cancel.ts
|
|
455331
455504
|
function registerVideoCancelCommand(parent) {
|
|
455332
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();
|
|
455333
455507
|
try {
|
|
455334
455508
|
const provider = (options.provider || "grok").toLowerCase();
|
|
455335
455509
|
let success = false;
|
|
@@ -455342,7 +455516,11 @@ function registerVideoCancelCommand(parent) {
|
|
|
455342
455516
|
if (success) {
|
|
455343
455517
|
spinner2.succeed(source_default.green("Generation cancelled"));
|
|
455344
455518
|
if (isJsonMode()) {
|
|
455345
|
-
|
|
455519
|
+
outputSuccess({
|
|
455520
|
+
command: "generate video-cancel",
|
|
455521
|
+
startedAt,
|
|
455522
|
+
data: { taskId, provider: "grok", cancelled: true }
|
|
455523
|
+
});
|
|
455346
455524
|
return;
|
|
455347
455525
|
}
|
|
455348
455526
|
} else {
|
|
@@ -455362,7 +455540,11 @@ function registerVideoCancelCommand(parent) {
|
|
|
455362
455540
|
if (success) {
|
|
455363
455541
|
spinner2.succeed(source_default.green("Generation cancelled"));
|
|
455364
455542
|
if (isJsonMode()) {
|
|
455365
|
-
|
|
455543
|
+
outputSuccess({
|
|
455544
|
+
command: "generate video-cancel",
|
|
455545
|
+
startedAt,
|
|
455546
|
+
data: { taskId, provider: "runway", cancelled: true }
|
|
455547
|
+
});
|
|
455366
455548
|
return;
|
|
455367
455549
|
}
|
|
455368
455550
|
} else {
|
|
@@ -455435,16 +455617,18 @@ async function executeBackground(options) {
|
|
|
455435
455617
|
}
|
|
455436
455618
|
function registerBackgroundCommand(parent) {
|
|
455437
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();
|
|
455438
455621
|
try {
|
|
455439
455622
|
rejectControlChars(description);
|
|
455440
455623
|
if (options.output) {
|
|
455441
455624
|
validateOutputPath(options.output);
|
|
455442
455625
|
}
|
|
455443
455626
|
if (options.dryRun) {
|
|
455444
|
-
|
|
455445
|
-
dryRun: true,
|
|
455627
|
+
outputSuccess({
|
|
455446
455628
|
command: "generate background",
|
|
455447
|
-
|
|
455629
|
+
startedAt,
|
|
455630
|
+
dryRun: true,
|
|
455631
|
+
data: { params: { description, aspect: options.aspect, output: options.output } }
|
|
455448
455632
|
});
|
|
455449
455633
|
return;
|
|
455450
455634
|
}
|
|
@@ -455479,7 +455663,11 @@ function registerBackgroundCommand(parent) {
|
|
|
455479
455663
|
await mkdir18(dirname25(outputPath), { recursive: true });
|
|
455480
455664
|
await writeFile23(outputPath, buffer);
|
|
455481
455665
|
}
|
|
455482
|
-
|
|
455666
|
+
outputSuccess({
|
|
455667
|
+
command: "generate background",
|
|
455668
|
+
startedAt,
|
|
455669
|
+
data: { imageUrl: img.url, outputPath }
|
|
455670
|
+
});
|
|
455483
455671
|
return;
|
|
455484
455672
|
}
|
|
455485
455673
|
console.log();
|
|
@@ -455576,6 +455764,7 @@ async function executeStoryboard(options) {
|
|
|
455576
455764
|
}
|
|
455577
455765
|
function registerStoryboardCommand(parent) {
|
|
455578
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();
|
|
455579
455768
|
try {
|
|
455580
455769
|
rejectControlChars(content);
|
|
455581
455770
|
if (options.output) {
|
|
@@ -455591,13 +455780,16 @@ function registerStoryboardCommand(parent) {
|
|
|
455591
455780
|
textContent2 = await readFile23(filePath, "utf-8");
|
|
455592
455781
|
}
|
|
455593
455782
|
if (options.dryRun) {
|
|
455594
|
-
|
|
455595
|
-
dryRun: true,
|
|
455783
|
+
outputSuccess({
|
|
455596
455784
|
command: "generate storyboard",
|
|
455597
|
-
|
|
455598
|
-
|
|
455599
|
-
|
|
455600
|
-
|
|
455785
|
+
startedAt,
|
|
455786
|
+
dryRun: true,
|
|
455787
|
+
data: {
|
|
455788
|
+
params: {
|
|
455789
|
+
content: textContent2.substring(0, 200),
|
|
455790
|
+
duration: options.duration,
|
|
455791
|
+
creativity
|
|
455792
|
+
}
|
|
455601
455793
|
}
|
|
455602
455794
|
});
|
|
455603
455795
|
return;
|
|
@@ -455629,16 +455821,23 @@ function registerStoryboardCommand(parent) {
|
|
|
455629
455821
|
const outputPath = resolve39(process.cwd(), options.output);
|
|
455630
455822
|
await writeFile24(outputPath, JSON.stringify(segments, null, 2), "utf-8");
|
|
455631
455823
|
if (isJsonMode()) {
|
|
455632
|
-
|
|
455633
|
-
|
|
455634
|
-
|
|
455635
|
-
|
|
455636
|
-
|
|
455824
|
+
outputSuccess({
|
|
455825
|
+
command: "generate storyboard",
|
|
455826
|
+
startedAt,
|
|
455827
|
+
data: {
|
|
455828
|
+
segmentCount: segments.length,
|
|
455829
|
+
segments,
|
|
455830
|
+
outputPath
|
|
455831
|
+
}
|
|
455637
455832
|
});
|
|
455638
455833
|
return;
|
|
455639
455834
|
}
|
|
455640
455835
|
} else if (isJsonMode()) {
|
|
455641
|
-
|
|
455836
|
+
outputSuccess({
|
|
455837
|
+
command: "generate storyboard",
|
|
455838
|
+
startedAt,
|
|
455839
|
+
data: { segmentCount: segments.length, segments }
|
|
455840
|
+
});
|
|
455642
455841
|
return;
|
|
455643
455842
|
}
|
|
455644
455843
|
console.log();
|
|
@@ -455770,6 +455969,7 @@ async function executeSpeech(options) {
|
|
|
455770
455969
|
}
|
|
455771
455970
|
function registerSpeechCommand(parent) {
|
|
455772
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();
|
|
455773
455973
|
try {
|
|
455774
455974
|
if (!text) {
|
|
455775
455975
|
if (hasTTY()) {
|
|
@@ -455791,10 +455991,11 @@ function registerSpeechCommand(parent) {
|
|
|
455791
455991
|
validateOutputPath(options.output);
|
|
455792
455992
|
}
|
|
455793
455993
|
if (options.dryRun) {
|
|
455794
|
-
|
|
455795
|
-
dryRun: true,
|
|
455994
|
+
outputSuccess({
|
|
455796
455995
|
command: "generate speech",
|
|
455797
|
-
|
|
455996
|
+
startedAt,
|
|
455997
|
+
dryRun: true,
|
|
455998
|
+
data: { params: { text, voice: options.voice, output: options.output } }
|
|
455798
455999
|
});
|
|
455799
456000
|
return;
|
|
455800
456001
|
}
|
|
@@ -455883,10 +456084,13 @@ function registerSpeechCommand(parent) {
|
|
|
455883
456084
|
}
|
|
455884
456085
|
}
|
|
455885
456086
|
if (isJsonMode()) {
|
|
455886
|
-
|
|
455887
|
-
|
|
455888
|
-
|
|
455889
|
-
|
|
456087
|
+
outputSuccess({
|
|
456088
|
+
command: "generate speech",
|
|
456089
|
+
startedAt,
|
|
456090
|
+
data: {
|
|
456091
|
+
characterCount: result.characterCount,
|
|
456092
|
+
outputPath
|
|
456093
|
+
}
|
|
455890
456094
|
});
|
|
455891
456095
|
return;
|
|
455892
456096
|
}
|
|
@@ -455975,6 +456179,7 @@ async function executeMusic(options) {
|
|
|
455975
456179
|
}
|
|
455976
456180
|
function registerMusicCommand(parent) {
|
|
455977
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();
|
|
455978
456183
|
try {
|
|
455979
456184
|
rejectControlChars(prompt3);
|
|
455980
456185
|
if (options.output) {
|
|
@@ -455982,16 +456187,19 @@ function registerMusicCommand(parent) {
|
|
|
455982
456187
|
}
|
|
455983
456188
|
const provider = (options.provider || "elevenlabs").toLowerCase();
|
|
455984
456189
|
if (options.dryRun) {
|
|
455985
|
-
|
|
455986
|
-
dryRun: true,
|
|
456190
|
+
outputSuccess({
|
|
455987
456191
|
command: "generate music",
|
|
455988
|
-
|
|
455989
|
-
|
|
455990
|
-
|
|
455991
|
-
|
|
455992
|
-
|
|
455993
|
-
|
|
455994
|
-
|
|
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
|
+
}
|
|
455995
456203
|
}
|
|
455996
456204
|
});
|
|
455997
456205
|
return;
|
|
@@ -456018,11 +456226,14 @@ function registerMusicCommand(parent) {
|
|
|
456018
456226
|
await writeFile26(outputPath, result.audioBuffer);
|
|
456019
456227
|
spinner2.succeed(source_default.green("Music generated successfully"));
|
|
456020
456228
|
if (isJsonMode()) {
|
|
456021
|
-
|
|
456022
|
-
|
|
456023
|
-
|
|
456024
|
-
|
|
456025
|
-
|
|
456229
|
+
outputSuccess({
|
|
456230
|
+
command: "generate music",
|
|
456231
|
+
startedAt,
|
|
456232
|
+
data: {
|
|
456233
|
+
provider: "elevenlabs",
|
|
456234
|
+
outputPath,
|
|
456235
|
+
duration
|
|
456236
|
+
}
|
|
456026
456237
|
});
|
|
456027
456238
|
return;
|
|
456028
456239
|
}
|
|
@@ -456090,12 +456301,15 @@ function registerMusicCommand(parent) {
|
|
|
456090
456301
|
await writeFile26(outputPath, audioBuffer);
|
|
456091
456302
|
spinner2.succeed(source_default.green("Music generated successfully"));
|
|
456092
456303
|
if (isJsonMode()) {
|
|
456093
|
-
|
|
456094
|
-
|
|
456095
|
-
|
|
456096
|
-
|
|
456097
|
-
|
|
456098
|
-
|
|
456304
|
+
outputSuccess({
|
|
456305
|
+
command: "generate music",
|
|
456306
|
+
startedAt,
|
|
456307
|
+
data: {
|
|
456308
|
+
provider: "replicate",
|
|
456309
|
+
taskId: result.taskId,
|
|
456310
|
+
audioUrl: finalResult.audioUrl,
|
|
456311
|
+
outputPath
|
|
456312
|
+
}
|
|
456099
456313
|
});
|
|
456100
456314
|
return;
|
|
456101
456315
|
}
|
|
@@ -456130,6 +456344,7 @@ import { existsSync as existsSync47 } from "node:fs";
|
|
|
456130
456344
|
import { writeFile as writeFile27, mkdir as mkdir19 } from "node:fs/promises";
|
|
456131
456345
|
function registerThumbnailCommand(parent) {
|
|
456132
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();
|
|
456133
456348
|
try {
|
|
456134
456349
|
if (description) rejectControlChars(description);
|
|
456135
456350
|
if (options.output) {
|
|
@@ -456165,11 +456380,14 @@ function registerThumbnailCommand(parent) {
|
|
|
456165
456380
|
}
|
|
456166
456381
|
spinner3.succeed(source_default.green("Best frame extracted"));
|
|
456167
456382
|
if (isJsonMode()) {
|
|
456168
|
-
|
|
456169
|
-
|
|
456170
|
-
|
|
456171
|
-
|
|
456172
|
-
|
|
456383
|
+
outputSuccess({
|
|
456384
|
+
command: "generate thumbnail",
|
|
456385
|
+
startedAt,
|
|
456386
|
+
data: {
|
|
456387
|
+
timestamp: result2.timestamp,
|
|
456388
|
+
reason: result2.reason,
|
|
456389
|
+
outputPath: result2.outputPath
|
|
456390
|
+
}
|
|
456173
456391
|
});
|
|
456174
456392
|
return;
|
|
456175
456393
|
}
|
|
@@ -456217,7 +456435,11 @@ function registerThumbnailCommand(parent) {
|
|
|
456217
456435
|
await mkdir19(dirname26(outputPath), { recursive: true });
|
|
456218
456436
|
await writeFile27(outputPath, buffer);
|
|
456219
456437
|
}
|
|
456220
|
-
|
|
456438
|
+
outputSuccess({
|
|
456439
|
+
command: "generate thumbnail",
|
|
456440
|
+
startedAt,
|
|
456441
|
+
data: { imageUrl: img.url, outputPath }
|
|
456442
|
+
});
|
|
456221
456443
|
return;
|
|
456222
456444
|
}
|
|
456223
456445
|
console.log();
|
|
@@ -456288,6 +456510,7 @@ function getStatusColor(status) {
|
|
|
456288
456510
|
}
|
|
456289
456511
|
function registerVideoStatusCommand(parent) {
|
|
456290
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();
|
|
456291
456514
|
try {
|
|
456292
456515
|
const provider = (options.provider || "grok").toLowerCase();
|
|
456293
456516
|
if (provider === "grok") {
|
|
@@ -456310,14 +456533,17 @@ function registerVideoStatusCommand(parent) {
|
|
|
456310
456533
|
outputPath = resolve44(process.cwd(), options.output);
|
|
456311
456534
|
await writeFile28(outputPath, buffer);
|
|
456312
456535
|
}
|
|
456313
|
-
|
|
456314
|
-
|
|
456315
|
-
|
|
456316
|
-
|
|
456317
|
-
|
|
456318
|
-
|
|
456319
|
-
|
|
456320
|
-
|
|
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
|
+
}
|
|
456321
456547
|
});
|
|
456322
456548
|
return;
|
|
456323
456549
|
}
|
|
@@ -456375,15 +456601,18 @@ function registerVideoStatusCommand(parent) {
|
|
|
456375
456601
|
outputPath = resolve44(process.cwd(), options.output);
|
|
456376
456602
|
await writeFile28(outputPath, buffer);
|
|
456377
456603
|
}
|
|
456378
|
-
|
|
456379
|
-
|
|
456380
|
-
|
|
456381
|
-
|
|
456382
|
-
|
|
456383
|
-
|
|
456384
|
-
|
|
456385
|
-
|
|
456386
|
-
|
|
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
|
+
}
|
|
456387
456616
|
});
|
|
456388
456617
|
return;
|
|
456389
456618
|
}
|
|
@@ -456439,15 +456668,18 @@ function registerVideoStatusCommand(parent) {
|
|
|
456439
456668
|
outputPath = resolve44(process.cwd(), options.output);
|
|
456440
456669
|
await writeFile28(outputPath, buffer);
|
|
456441
456670
|
}
|
|
456442
|
-
|
|
456443
|
-
|
|
456444
|
-
|
|
456445
|
-
|
|
456446
|
-
|
|
456447
|
-
|
|
456448
|
-
|
|
456449
|
-
|
|
456450
|
-
|
|
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
|
+
}
|
|
456451
456683
|
});
|
|
456452
456684
|
return;
|
|
456453
456685
|
}
|
|
@@ -456511,22 +456743,26 @@ import { resolve as resolve45 } from "node:path";
|
|
|
456511
456743
|
import { writeFile as writeFile29 } from "node:fs/promises";
|
|
456512
456744
|
function registerVideoExtendCommand(parent) {
|
|
456513
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();
|
|
456514
456747
|
try {
|
|
456515
456748
|
const provider = (options.provider || "kling").toLowerCase();
|
|
456516
456749
|
if (options.output) {
|
|
456517
456750
|
validateOutputPath(options.output);
|
|
456518
456751
|
}
|
|
456519
456752
|
if (options.dryRun) {
|
|
456520
|
-
|
|
456521
|
-
dryRun: true,
|
|
456753
|
+
outputSuccess({
|
|
456522
456754
|
command: "generate video-extend",
|
|
456523
|
-
|
|
456524
|
-
|
|
456525
|
-
|
|
456526
|
-
|
|
456527
|
-
|
|
456528
|
-
|
|
456529
|
-
|
|
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
|
+
}
|
|
456530
456766
|
}
|
|
456531
456767
|
});
|
|
456532
456768
|
return;
|
|
@@ -456583,13 +456819,16 @@ function registerVideoExtendCommand(parent) {
|
|
|
456583
456819
|
outputPath = resolve45(process.cwd(), options.output);
|
|
456584
456820
|
await writeFile29(outputPath, buffer);
|
|
456585
456821
|
}
|
|
456586
|
-
|
|
456587
|
-
|
|
456588
|
-
|
|
456589
|
-
|
|
456590
|
-
|
|
456591
|
-
|
|
456592
|
-
|
|
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
|
+
}
|
|
456593
456832
|
});
|
|
456594
456833
|
return;
|
|
456595
456834
|
}
|
|
@@ -456669,13 +456908,16 @@ function registerVideoExtendCommand(parent) {
|
|
|
456669
456908
|
outputPath = resolve45(process.cwd(), options.output);
|
|
456670
456909
|
await writeFile29(outputPath, buffer);
|
|
456671
456910
|
}
|
|
456672
|
-
|
|
456673
|
-
|
|
456674
|
-
|
|
456675
|
-
|
|
456676
|
-
|
|
456677
|
-
|
|
456678
|
-
|
|
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
|
+
}
|
|
456679
456921
|
});
|
|
456680
456922
|
return;
|
|
456681
456923
|
}
|
|
@@ -456790,6 +457032,7 @@ Examples:
|
|
|
456790
457032
|
$ vibe gen img "landscape photo" -o wide.png -r 16:9
|
|
456791
457033
|
$ vibe gen img "portrait" -o portrait.png -p gemini -m pro
|
|
456792
457034
|
$ vibe gen img "product shot" --dry-run --json`).action(async (prompt3, options) => {
|
|
457035
|
+
const startedAt = Date.now();
|
|
456793
457036
|
try {
|
|
456794
457037
|
if (!prompt3) {
|
|
456795
457038
|
if (hasTTY()) {
|
|
@@ -456848,18 +457091,21 @@ Examples:
|
|
|
456848
457091
|
provider = resolved?.name ?? "gemini";
|
|
456849
457092
|
}
|
|
456850
457093
|
if (options.dryRun) {
|
|
456851
|
-
|
|
456852
|
-
dryRun: true,
|
|
457094
|
+
outputSuccess({
|
|
456853
457095
|
command: "generate image",
|
|
456854
|
-
|
|
456855
|
-
|
|
456856
|
-
|
|
456857
|
-
|
|
456858
|
-
|
|
456859
|
-
|
|
456860
|
-
|
|
456861
|
-
|
|
456862
|
-
|
|
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
|
+
}
|
|
456863
457109
|
}
|
|
456864
457110
|
});
|
|
456865
457111
|
return;
|
|
@@ -456897,14 +457143,17 @@ Examples:
|
|
|
456897
457143
|
await mkdir20(dirname27(outputPath), { recursive: true });
|
|
456898
457144
|
await writeFile30(outputPath, buffer);
|
|
456899
457145
|
}
|
|
456900
|
-
|
|
456901
|
-
|
|
456902
|
-
|
|
456903
|
-
|
|
456904
|
-
|
|
456905
|
-
|
|
456906
|
-
|
|
456907
|
-
|
|
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
|
+
}
|
|
456908
457157
|
});
|
|
456909
457158
|
return;
|
|
456910
457159
|
}
|
|
@@ -457016,13 +457265,18 @@ Examples:
|
|
|
457016
457265
|
await mkdir20(dirname27(outputPath), { recursive: true });
|
|
457017
457266
|
await writeFile30(outputPath, buffer);
|
|
457018
457267
|
}
|
|
457019
|
-
|
|
457020
|
-
|
|
457021
|
-
|
|
457022
|
-
|
|
457023
|
-
|
|
457024
|
-
|
|
457025
|
-
|
|
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
|
+
}
|
|
457026
457280
|
});
|
|
457027
457281
|
return;
|
|
457028
457282
|
}
|
|
@@ -457106,11 +457360,14 @@ Examples:
|
|
|
457106
457360
|
await mkdir20(dirname27(outputPath), { recursive: true });
|
|
457107
457361
|
await writeFile30(outputPath, buffer);
|
|
457108
457362
|
}
|
|
457109
|
-
|
|
457110
|
-
|
|
457111
|
-
|
|
457112
|
-
|
|
457113
|
-
|
|
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
|
+
}
|
|
457114
457371
|
});
|
|
457115
457372
|
return;
|
|
457116
457373
|
}
|
|
@@ -457181,11 +457438,14 @@ Examples:
|
|
|
457181
457438
|
proc.on("close", (code) => {
|
|
457182
457439
|
if (code === 0) {
|
|
457183
457440
|
if (isJsonMode()) {
|
|
457184
|
-
|
|
457185
|
-
|
|
457186
|
-
|
|
457187
|
-
|
|
457188
|
-
|
|
457441
|
+
outputSuccess({
|
|
457442
|
+
command: "generate image",
|
|
457443
|
+
startedAt,
|
|
457444
|
+
data: {
|
|
457445
|
+
provider: "runway",
|
|
457446
|
+
images: [{ format: "file" }],
|
|
457447
|
+
outputPath
|
|
457448
|
+
}
|
|
457189
457449
|
});
|
|
457190
457450
|
} else {
|
|
457191
457451
|
spinner2.succeed(source_default.green("Generated image with Runway"));
|
|
@@ -458911,6 +459171,7 @@ Examples:
|
|
|
458911
459171
|
$ vibe gen vid "epic scene" -i frame.png -o out.mp4 -p runway # Image-to-video
|
|
458912
459172
|
$ vibe gen vid "ocean waves" -o waves.mp4 -p veo --resolution 1080p # Veo
|
|
458913
459173
|
$ vibe gen vid "sunset" -o sun.mp4 -d 10 --dry-run --json`).action(async (prompt3, options) => {
|
|
459174
|
+
const startedAt = Date.now();
|
|
458914
459175
|
try {
|
|
458915
459176
|
if (!prompt3) {
|
|
458916
459177
|
if (hasTTY()) {
|
|
@@ -459002,19 +459263,22 @@ Examples:
|
|
|
459002
459263
|
options.ratio = "16:9";
|
|
459003
459264
|
}
|
|
459004
459265
|
if (options.dryRun) {
|
|
459005
|
-
|
|
459006
|
-
dryRun: true,
|
|
459266
|
+
outputSuccess({
|
|
459007
459267
|
command: "generate video",
|
|
459008
|
-
|
|
459009
|
-
|
|
459010
|
-
|
|
459011
|
-
|
|
459012
|
-
|
|
459013
|
-
|
|
459014
|
-
|
|
459015
|
-
|
|
459016
|
-
|
|
459017
|
-
|
|
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
|
+
}
|
|
459018
459282
|
}
|
|
459019
459283
|
});
|
|
459020
459284
|
return;
|
|
@@ -459294,13 +459558,16 @@ Examples:
|
|
|
459294
459558
|
outputPath = resolve49(process.cwd(), options.output);
|
|
459295
459559
|
await writeFile33(outputPath, buffer);
|
|
459296
459560
|
}
|
|
459297
|
-
|
|
459298
|
-
|
|
459299
|
-
|
|
459300
|
-
|
|
459301
|
-
|
|
459302
|
-
|
|
459303
|
-
|
|
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
|
+
}
|
|
459304
459571
|
});
|
|
459305
459572
|
return;
|
|
459306
459573
|
}
|
|
@@ -459865,20 +460132,24 @@ var init_detect = __esm({
|
|
|
459865
460132
|
init_validate();
|
|
459866
460133
|
detectCommand = new Command("detect").description("Auto-detect scenes, beats, and silences in media");
|
|
459867
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();
|
|
459868
460136
|
const spinner2 = ora("Detecting scenes...").start();
|
|
459869
460137
|
try {
|
|
459870
460138
|
if (options.output) {
|
|
459871
460139
|
validateOutputPath(options.output);
|
|
459872
460140
|
}
|
|
459873
460141
|
if (options.dryRun) {
|
|
459874
|
-
|
|
459875
|
-
dryRun: true,
|
|
460142
|
+
outputSuccess({
|
|
459876
460143
|
command: "detect scenes",
|
|
459877
|
-
|
|
459878
|
-
|
|
459879
|
-
|
|
459880
|
-
|
|
459881
|
-
|
|
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
|
+
}
|
|
459882
460153
|
}
|
|
459883
460154
|
});
|
|
459884
460155
|
return;
|
|
@@ -459980,20 +460251,24 @@ var init_detect = __esm({
|
|
|
459980
460251
|
}
|
|
459981
460252
|
});
|
|
459982
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();
|
|
459983
460255
|
const spinner2 = ora("Detecting silence...").start();
|
|
459984
460256
|
try {
|
|
459985
460257
|
if (options.output) {
|
|
459986
460258
|
validateOutputPath(options.output);
|
|
459987
460259
|
}
|
|
459988
460260
|
if (options.dryRun) {
|
|
459989
|
-
|
|
459990
|
-
dryRun: true,
|
|
460261
|
+
outputSuccess({
|
|
459991
460262
|
command: "detect silence",
|
|
459992
|
-
|
|
459993
|
-
|
|
459994
|
-
|
|
459995
|
-
|
|
459996
|
-
|
|
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
|
+
}
|
|
459997
460272
|
}
|
|
459998
460273
|
});
|
|
459999
460274
|
return;
|
|
@@ -460062,18 +460337,22 @@ var init_detect = __esm({
|
|
|
460062
460337
|
}
|
|
460063
460338
|
});
|
|
460064
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();
|
|
460065
460341
|
const spinner2 = ora("Detecting beats...").start();
|
|
460066
460342
|
try {
|
|
460067
460343
|
if (options.output) {
|
|
460068
460344
|
validateOutputPath(options.output);
|
|
460069
460345
|
}
|
|
460070
460346
|
if (options.dryRun) {
|
|
460071
|
-
|
|
460072
|
-
dryRun: true,
|
|
460347
|
+
outputSuccess({
|
|
460073
460348
|
command: "detect beats",
|
|
460074
|
-
|
|
460075
|
-
|
|
460076
|
-
|
|
460349
|
+
startedAt,
|
|
460350
|
+
dryRun: true,
|
|
460351
|
+
data: {
|
|
460352
|
+
params: {
|
|
460353
|
+
audio: audioPath,
|
|
460354
|
+
output: options.output || null
|
|
460355
|
+
}
|
|
460077
460356
|
}
|
|
460078
460357
|
});
|
|
460079
460358
|
return;
|
|
@@ -461547,20 +461826,24 @@ Examples:
|
|
|
461547
461826
|
A scene project is bilingual: it works with both \`vibe\` and \`npx hyperframes\`.
|
|
461548
461827
|
Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
461549
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();
|
|
461550
461830
|
const aspect = validateAspect(options.ratio);
|
|
461551
461831
|
const duration = validateDuration(options.duration);
|
|
461552
461832
|
const name = options.name ?? basename6(dir.replace(/\/+$/, ""));
|
|
461553
461833
|
const visualStyle = options.visualStyle ? validateVisualStyle(options.visualStyle) : void 0;
|
|
461554
461834
|
if (options.dryRun) {
|
|
461555
|
-
|
|
461556
|
-
dryRun: true,
|
|
461835
|
+
outputSuccess({
|
|
461557
461836
|
command: "scene init",
|
|
461558
|
-
|
|
461559
|
-
|
|
461560
|
-
|
|
461561
|
-
|
|
461562
|
-
|
|
461563
|
-
|
|
461837
|
+
startedAt,
|
|
461838
|
+
dryRun: true,
|
|
461839
|
+
data: {
|
|
461840
|
+
params: {
|
|
461841
|
+
dir,
|
|
461842
|
+
name,
|
|
461843
|
+
aspect,
|
|
461844
|
+
duration,
|
|
461845
|
+
visualStyle: visualStyle?.name ?? null
|
|
461846
|
+
}
|
|
461564
461847
|
}
|
|
461565
461848
|
});
|
|
461566
461849
|
return;
|
|
@@ -461576,19 +461859,21 @@ sceneCommand.command("init").description("Scaffold a new scene project (or safel
|
|
|
461576
461859
|
hosts: skillHosts
|
|
461577
461860
|
});
|
|
461578
461861
|
if (isJsonMode()) {
|
|
461579
|
-
|
|
461580
|
-
success: true,
|
|
461862
|
+
outputSuccess({
|
|
461581
461863
|
command: "scene init",
|
|
461582
|
-
|
|
461583
|
-
|
|
461584
|
-
|
|
461585
|
-
|
|
461586
|
-
|
|
461587
|
-
|
|
461588
|
-
|
|
461589
|
-
|
|
461590
|
-
|
|
461591
|
-
|
|
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
|
+
}
|
|
461592
461877
|
});
|
|
461593
461878
|
return;
|
|
461594
461879
|
}
|
|
@@ -461629,6 +461914,7 @@ sceneCommand.command("init").description("Scaffold a new scene project (or safel
|
|
|
461629
461914
|
});
|
|
461630
461915
|
var VALID_INSTALL_SKILL_HOSTS = ["claude-code", "cursor", "auto", "all"];
|
|
461631
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();
|
|
461632
461918
|
const hostFlag = options.host ?? "auto";
|
|
461633
461919
|
if (!VALID_INSTALL_SKILL_HOSTS.includes(hostFlag)) {
|
|
461634
461920
|
exitWithError(usageError(`Invalid --host: ${hostFlag}`, `Valid: ${VALID_INSTALL_SKILL_HOSTS.join(", ")}`));
|
|
@@ -461648,15 +461934,17 @@ sceneCommand.command("install-skill").description("Install the Hyperframes skill
|
|
|
461648
461934
|
dryRun: options.dryRun ?? false
|
|
461649
461935
|
});
|
|
461650
461936
|
if (isJsonMode()) {
|
|
461651
|
-
|
|
461652
|
-
success: true,
|
|
461937
|
+
outputSuccess({
|
|
461653
461938
|
command: "scene install-skill",
|
|
461654
|
-
|
|
461655
|
-
|
|
461656
|
-
|
|
461657
|
-
|
|
461658
|
-
|
|
461659
|
-
|
|
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
|
+
}
|
|
461660
461948
|
});
|
|
461661
461949
|
return;
|
|
461662
461950
|
}
|
|
@@ -461678,6 +461966,7 @@ sceneCommand.command("install-skill").description("Install the Hyperframes skill
|
|
|
461678
461966
|
}
|
|
461679
461967
|
});
|
|
461680
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();
|
|
461681
461970
|
const projectDir = resolve21(projectDirArg);
|
|
461682
461971
|
const result = await getComposePrompts({
|
|
461683
461972
|
projectDir,
|
|
@@ -461685,18 +461974,21 @@ sceneCommand.command("compose-prompts").description("Emit the per-beat compose p
|
|
|
461685
461974
|
});
|
|
461686
461975
|
if (!result.success) {
|
|
461687
461976
|
if (isJsonMode()) {
|
|
461688
|
-
|
|
461977
|
+
outputSuccess({
|
|
461689
461978
|
command: "scene compose-prompts",
|
|
461690
|
-
|
|
461979
|
+
startedAt,
|
|
461980
|
+
data: { ...result }
|
|
461691
461981
|
});
|
|
461692
|
-
process.
|
|
461982
|
+
process.exitCode = 1;
|
|
461983
|
+
return;
|
|
461693
461984
|
}
|
|
461694
461985
|
exitWithError(generalError(result.error ?? "compose-prompts failed"));
|
|
461695
461986
|
}
|
|
461696
461987
|
if (isJsonMode()) {
|
|
461697
|
-
|
|
461988
|
+
outputSuccess({
|
|
461698
461989
|
command: "scene compose-prompts",
|
|
461699
|
-
|
|
461990
|
+
startedAt,
|
|
461991
|
+
data: { ...result }
|
|
461700
461992
|
});
|
|
461701
461993
|
return;
|
|
461702
461994
|
}
|
|
@@ -461730,20 +462022,23 @@ sceneCommand.command("compose-prompts").description("Emit the per-beat compose p
|
|
|
461730
462022
|
console.log(source_default.dim("Re-run with --json to get the full per-beat userPrompt + cues for direct consumption."));
|
|
461731
462023
|
});
|
|
461732
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();
|
|
461733
462026
|
if (!name) {
|
|
461734
462027
|
const all = listVisualStyles();
|
|
461735
462028
|
if (isJsonMode()) {
|
|
461736
|
-
|
|
461737
|
-
success: true,
|
|
462029
|
+
outputSuccess({
|
|
461738
462030
|
command: "scene styles",
|
|
461739
|
-
|
|
461740
|
-
|
|
461741
|
-
|
|
461742
|
-
|
|
461743
|
-
|
|
461744
|
-
|
|
461745
|
-
|
|
461746
|
-
|
|
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
|
+
}
|
|
461747
462042
|
});
|
|
461748
462043
|
return;
|
|
461749
462044
|
}
|
|
@@ -461771,7 +462066,11 @@ sceneCommand.command("styles").description("List vendored visual styles (or show
|
|
|
461771
462066
|
return;
|
|
461772
462067
|
}
|
|
461773
462068
|
if (isJsonMode()) {
|
|
461774
|
-
|
|
462069
|
+
outputSuccess({
|
|
462070
|
+
command: "scene styles",
|
|
462071
|
+
startedAt,
|
|
462072
|
+
data: { style }
|
|
462073
|
+
});
|
|
461775
462074
|
return;
|
|
461776
462075
|
}
|
|
461777
462076
|
console.log();
|
|
@@ -461793,6 +462092,7 @@ sceneCommand.command("styles").description("List vendored visual styles (or show
|
|
|
461793
462092
|
console.log(source_default.dim("Seed DESIGN.md:"), source_default.cyan(`vibe scene init <dir> --visual-style "${style.name}"`));
|
|
461794
462093
|
});
|
|
461795
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();
|
|
461796
462096
|
if (options.style) options.style = validatePreset(options.style);
|
|
461797
462097
|
if (options.duration !== void 0) options.duration = validateDuration(options.duration);
|
|
461798
462098
|
let tts;
|
|
@@ -461803,25 +462103,28 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
461803
462103
|
}
|
|
461804
462104
|
if (options.dryRun) {
|
|
461805
462105
|
const id = slugifySceneName(name);
|
|
461806
|
-
|
|
461807
|
-
dryRun: true,
|
|
462106
|
+
outputSuccess({
|
|
461808
462107
|
command: "scene add",
|
|
461809
|
-
|
|
461810
|
-
|
|
461811
|
-
|
|
461812
|
-
|
|
461813
|
-
|
|
461814
|
-
|
|
461815
|
-
|
|
461816
|
-
|
|
461817
|
-
|
|
461818
|
-
|
|
461819
|
-
|
|
461820
|
-
|
|
461821
|
-
|
|
461822
|
-
|
|
461823
|
-
|
|
461824
|
-
|
|
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
|
+
}
|
|
461825
462128
|
}
|
|
461826
462129
|
});
|
|
461827
462130
|
return;
|
|
@@ -461856,9 +462159,10 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
461856
462159
|
exitWithError(generalError(result.error ?? "Scene add failed"));
|
|
461857
462160
|
}
|
|
461858
462161
|
if (isJsonMode()) {
|
|
461859
|
-
|
|
462162
|
+
outputSuccess({
|
|
461860
462163
|
command: "scene add",
|
|
461861
|
-
|
|
462164
|
+
startedAt,
|
|
462165
|
+
data: { ...result }
|
|
461862
462166
|
});
|
|
461863
462167
|
return;
|
|
461864
462168
|
}
|
|
@@ -462154,6 +462458,7 @@ async function executeSceneAdd(opts) {
|
|
|
462154
462458
|
};
|
|
462155
462459
|
}
|
|
462156
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();
|
|
462157
462462
|
const projectDir = resolve21(options.project);
|
|
462158
462463
|
if (!await rootExists(projectDir, root2)) {
|
|
462159
462464
|
exitWithError(generalError(
|
|
@@ -462171,11 +462476,12 @@ sceneCommand.command("lint").description("Validate scene HTML against Hyperframe
|
|
|
462171
462476
|
exitWithError(generalError(`Lint failed: ${msg}`));
|
|
462172
462477
|
}
|
|
462173
462478
|
if (isJsonMode()) {
|
|
462174
|
-
|
|
462479
|
+
outputSuccess({
|
|
462175
462480
|
command: "scene lint",
|
|
462176
|
-
|
|
462481
|
+
startedAt,
|
|
462482
|
+
data: { ...result }
|
|
462177
462483
|
});
|
|
462178
|
-
if (!result.ok) process.
|
|
462484
|
+
if (!result.ok) process.exitCode = 1;
|
|
462179
462485
|
return;
|
|
462180
462486
|
}
|
|
462181
462487
|
if (result.ok && result.warningCount === 0 && result.infoCount === 0) {
|
|
@@ -462209,7 +462515,7 @@ sceneCommand.command("lint").description("Validate scene HTML against Hyperframe
|
|
|
462209
462515
|
console.log(` ${source_default.green("\u2714")} ${fx.file} ${source_default.dim(fx.codes.join(", "))}`);
|
|
462210
462516
|
}
|
|
462211
462517
|
}
|
|
462212
|
-
if (!result.ok) process.
|
|
462518
|
+
if (!result.ok) process.exitCode = 1;
|
|
462213
462519
|
});
|
|
462214
462520
|
function severityTag(severity) {
|
|
462215
462521
|
if (severity === "error") return source_default.red("\u2718 error ");
|
|
@@ -462246,23 +462552,27 @@ function validateWorkers(value) {
|
|
|
462246
462552
|
return n;
|
|
462247
462553
|
}
|
|
462248
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();
|
|
462249
462556
|
const fps = validateFps(options.fps);
|
|
462250
462557
|
const quality = validateQuality(options.quality);
|
|
462251
462558
|
const format4 = validateFormat(options.format);
|
|
462252
462559
|
const workers = validateWorkers(options.workers);
|
|
462253
462560
|
const projectDir = resolve21(options.project);
|
|
462254
462561
|
if (options.dryRun) {
|
|
462255
|
-
|
|
462256
|
-
dryRun: true,
|
|
462562
|
+
outputSuccess({
|
|
462257
462563
|
command: "scene render",
|
|
462258
|
-
|
|
462259
|
-
|
|
462260
|
-
|
|
462261
|
-
|
|
462262
|
-
|
|
462263
|
-
|
|
462264
|
-
|
|
462265
|
-
|
|
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
|
+
}
|
|
462266
462576
|
}
|
|
462267
462577
|
});
|
|
462268
462578
|
return;
|
|
@@ -462283,13 +462593,22 @@ sceneCommand.command("render").description("Render a scene project to MP4/WebM/M
|
|
|
462283
462593
|
if (!result.success) {
|
|
462284
462594
|
spinner2?.fail("Render failed");
|
|
462285
462595
|
if (isJsonMode()) {
|
|
462286
|
-
|
|
462287
|
-
|
|
462596
|
+
outputSuccess({
|
|
462597
|
+
command: "scene render",
|
|
462598
|
+
startedAt,
|
|
462599
|
+
data: { ...result }
|
|
462600
|
+
});
|
|
462601
|
+
process.exitCode = 1;
|
|
462602
|
+
return;
|
|
462288
462603
|
}
|
|
462289
462604
|
exitWithError(generalError(result.error ?? "Render failed"));
|
|
462290
462605
|
}
|
|
462291
462606
|
if (isJsonMode()) {
|
|
462292
|
-
|
|
462607
|
+
outputSuccess({
|
|
462608
|
+
command: "scene render",
|
|
462609
|
+
startedAt,
|
|
462610
|
+
data: { ...result }
|
|
462611
|
+
});
|
|
462293
462612
|
return;
|
|
462294
462613
|
}
|
|
462295
462614
|
spinner2?.succeed(source_default.green(`Render complete: ${result.outputPath}`));
|
|
@@ -462309,25 +462628,29 @@ sceneCommand.command("render").description("Render a scene project to MP4/WebM/M
|
|
|
462309
462628
|
}
|
|
462310
462629
|
});
|
|
462311
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();
|
|
462312
462632
|
const projectDir = resolve21(projectDirArg);
|
|
462313
462633
|
if (options.dryRun) {
|
|
462314
|
-
|
|
462315
|
-
dryRun: true,
|
|
462634
|
+
outputSuccess({
|
|
462316
462635
|
command: "scene build",
|
|
462317
|
-
|
|
462318
|
-
|
|
462319
|
-
|
|
462320
|
-
|
|
462321
|
-
|
|
462322
|
-
|
|
462323
|
-
|
|
462324
|
-
|
|
462325
|
-
|
|
462326
|
-
|
|
462327
|
-
|
|
462328
|
-
|
|
462329
|
-
|
|
462330
|
-
|
|
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
|
+
}
|
|
462331
462654
|
}
|
|
462332
462655
|
});
|
|
462333
462656
|
return;
|
|
@@ -462381,13 +462704,22 @@ sceneCommand.command("build").description("One-shot: read STORYBOARD.md cues, di
|
|
|
462381
462704
|
if (!result.success) {
|
|
462382
462705
|
spinner2?.fail(`Build failed: ${result.error}`);
|
|
462383
462706
|
if (isJsonMode()) {
|
|
462384
|
-
|
|
462385
|
-
|
|
462707
|
+
outputSuccess({
|
|
462708
|
+
command: "scene build",
|
|
462709
|
+
startedAt,
|
|
462710
|
+
data: { ...result }
|
|
462711
|
+
});
|
|
462712
|
+
process.exitCode = 1;
|
|
462713
|
+
return;
|
|
462386
462714
|
}
|
|
462387
462715
|
exitWithError(generalError(result.error ?? "Build failed"));
|
|
462388
462716
|
}
|
|
462389
462717
|
if (isJsonMode()) {
|
|
462390
|
-
|
|
462718
|
+
outputSuccess({
|
|
462719
|
+
command: "scene build",
|
|
462720
|
+
startedAt,
|
|
462721
|
+
data: { ...result }
|
|
462722
|
+
});
|
|
462391
462723
|
return;
|
|
462392
462724
|
}
|
|
462393
462725
|
if (result.phase === "needs-author") {
|
|
@@ -465897,6 +466229,7 @@ Cost: Free (no API keys needed). Requires FFmpeg.
|
|
|
465897
466229
|
GIF format: 15fps, no audio, looping. Good for previews and sharing.
|
|
465898
466230
|
Custom flags (--bitrate, --fps, --resolution, --codec) override preset values.
|
|
465899
466231
|
Run 'vibe schema export' for structured parameter info.`).action(async (projectPath, options) => {
|
|
466232
|
+
const startedAt = Date.now();
|
|
465900
466233
|
const spinner2 = ora("Checking FFmpeg...").start();
|
|
465901
466234
|
try {
|
|
465902
466235
|
if (options.output) {
|
|
@@ -465914,27 +466247,30 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
|
|
|
465914
466247
|
exitWithError(usageError(overrideError));
|
|
465915
466248
|
}
|
|
465916
466249
|
if (options.dryRun) {
|
|
465917
|
-
|
|
465918
|
-
dryRun: true,
|
|
466250
|
+
outputSuccess({
|
|
465919
466251
|
command: "export",
|
|
465920
|
-
|
|
465921
|
-
|
|
465922
|
-
|
|
465923
|
-
|
|
465924
|
-
|
|
465925
|
-
|
|
465926
|
-
|
|
465927
|
-
|
|
465928
|
-
|
|
465929
|
-
|
|
465930
|
-
|
|
465931
|
-
|
|
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
|
+
}
|
|
465932
466268
|
}
|
|
465933
466269
|
});
|
|
465934
466270
|
return;
|
|
465935
466271
|
}
|
|
465936
466272
|
if (options.backend === "hyperframes") {
|
|
465937
|
-
await runHyperframesExport(projectPath, options, spinner2);
|
|
466273
|
+
await runHyperframesExport(projectPath, options, spinner2, startedAt);
|
|
465938
466274
|
return;
|
|
465939
466275
|
}
|
|
465940
466276
|
const ffmpegPath = await findFFmpeg();
|
|
@@ -466521,13 +466857,13 @@ function getPresetSettings(preset, aspectRatio) {
|
|
|
466521
466857
|
}
|
|
466522
466858
|
return settings;
|
|
466523
466859
|
}
|
|
466524
|
-
async function runHyperframesExport(projectPath, options, spinner2) {
|
|
466860
|
+
async function runHyperframesExport(projectPath, options, spinner2, startedAt) {
|
|
466525
466861
|
spinner2.text = "Loading project...";
|
|
466526
466862
|
const { readFile: readFile34 } = await import("node:fs/promises");
|
|
466527
466863
|
const { resolve: resolve64, basename: basename18 } = await import("node:path");
|
|
466528
466864
|
const { Project: Project2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
466529
466865
|
const { createHyperframesBackend: createHyperframesBackend2 } = await Promise.resolve().then(() => (init_hyperframes(), hyperframes_exports));
|
|
466530
|
-
const { exitWithError: exitWithError2, generalError: generalError2,
|
|
466866
|
+
const { exitWithError: exitWithError2, generalError: generalError2, outputSuccess: outputSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
466531
466867
|
const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
|
|
466532
466868
|
const filePath = resolve64(process.cwd(), projectPath);
|
|
466533
466869
|
const content = await readFile34(filePath, "utf-8");
|
|
@@ -466553,10 +466889,10 @@ async function runHyperframesExport(projectPath, options, spinner2) {
|
|
|
466553
466889
|
return;
|
|
466554
466890
|
}
|
|
466555
466891
|
spinner2.succeed(chalk2.green(`Exported: ${result.outputPath}`));
|
|
466556
|
-
|
|
466557
|
-
success: true,
|
|
466892
|
+
outputSuccess2({
|
|
466558
466893
|
command: "export",
|
|
466559
|
-
|
|
466894
|
+
startedAt,
|
|
466895
|
+
data: {
|
|
466560
466896
|
outputPath: result.outputPath,
|
|
466561
466897
|
backend: "hyperframes",
|
|
466562
466898
|
durationMs: result.durationMs,
|
|
@@ -467461,6 +467797,348 @@ var agentOnlyTools = [
|
|
|
467461
467797
|
mediaConcatTool
|
|
467462
467798
|
];
|
|
467463
467799
|
|
|
467800
|
+
// ../cli/src/tools/manifest/walkthrough.ts
|
|
467801
|
+
import { z as z12 } from "zod";
|
|
467802
|
+
|
|
467803
|
+
// ../cli/src/commands/_shared/walkthroughs/walkthroughs.ts
|
|
467804
|
+
var SCENE_WALKTHROUGH = `# Scene authoring with vibe
|
|
467805
|
+
|
|
467806
|
+
A scene project is a directory that is **bilingual**: it works with both
|
|
467807
|
+
\`vibe\` and \`npx hyperframes\`. Each scene is one HTML file with scoped CSS
|
|
467808
|
+
and a paused GSAP timeline. Cheap to edit, cheap to lint, expensive only
|
|
467809
|
+
at render.
|
|
467810
|
+
|
|
467811
|
+
\`vibe scene build\` (v0.60+) is the supported one-shot driver from a
|
|
467812
|
+
written storyboard to an MP4. Plan H (v0.70) added \`--mode agent\` so the
|
|
467813
|
+
host agent itself authors the per-beat HTML \u2014 no internal LLM call.
|
|
467814
|
+
|
|
467815
|
+
## Three authoring paths
|
|
467816
|
+
|
|
467817
|
+
| Path | Command | When to use |
|
|
467818
|
+
|---|---|---|
|
|
467819
|
+
| **One-shot (default, v0.60+)** | \`vibe scene build [project-dir]\` | STORYBOARD.md has YAML frontmatter + per-beat cues |
|
|
467820
|
+
| **High-craft (manual)** | \`DESIGN.md\` + Hyperframes skill in your agent | Maximum control: hand-author each scene |
|
|
467821
|
+
| **Quick draft** | \`vibe scene add --style <preset>\` | No agent or no API keys; fast iteration |
|
|
467822
|
+
|
|
467823
|
+
Recommend \`vibe scene build\` whenever the user has a STORYBOARD with
|
|
467824
|
+
narration / backdrop intent.
|
|
467825
|
+
|
|
467826
|
+
## High-craft path
|
|
467827
|
+
|
|
467828
|
+
1. \`vibe scene init my-promo --visual-style "Swiss Pulse"\` \u2014 seeds
|
|
467829
|
+
\`DESIGN.md\` (palette, typography, motion, transitions) plus the
|
|
467830
|
+
\`vibe.project.yaml\` / \`hyperframes.json\` / \`index.html\` scaffold.
|
|
467831
|
+
In Plan H this **also installs the Hyperframes skill** at the
|
|
467832
|
+
right place for your host (\`.claude/skills/hyperframes/\` for Claude
|
|
467833
|
+
Code, \`.cursor/rules/hyperframes.mdc\` for Cursor, universal
|
|
467834
|
+
\`SKILL.md\` for everyone else).
|
|
467835
|
+
2. Read \`SKILL.md\` (or the host-specific copy) \u2014 Hyperframes
|
|
467836
|
+
framework rules, motion principles, type system, transition recipes.
|
|
467837
|
+
3. Read \`DESIGN.md\` \u2014 project-specific palette / typography / motion
|
|
467838
|
+
signature (visual identity hard-gate).
|
|
467839
|
+
4. Author each scene HTML directly under \`compositions/scene-<id>.html\`
|
|
467840
|
+
using the rules from steps 2 and 3. The skill enforces the visual
|
|
467841
|
+
identity contract \u2014 scenes that contradict DESIGN.md fail lint.
|
|
467842
|
+
5. \`vibe scene lint --fix\` for mechanical issues, \`vibe scene render\`
|
|
467843
|
+
to MP4.
|
|
467844
|
+
|
|
467845
|
+
## Quick-draft path
|
|
467846
|
+
|
|
467847
|
+
\`\`\`bash
|
|
467848
|
+
vibe scene init my-promo -r 16:9 -d 30
|
|
467849
|
+
vibe scene add intro --style announcement \\
|
|
467850
|
+
--headline "Ship videos, not clicks"
|
|
467851
|
+
vibe scene lint
|
|
467852
|
+
vibe scene render
|
|
467853
|
+
\`\`\`
|
|
467854
|
+
|
|
467855
|
+
\`vibe scene init\` is **idempotent** \u2014 running it on an existing
|
|
467856
|
+
Hyperframes directory merges \`hyperframes.json\` instead of clobbering it.
|
|
467857
|
+
Safe to invoke on user-provided projects.
|
|
467858
|
+
|
|
467859
|
+
## Subcommands
|
|
467860
|
+
|
|
467861
|
+
\`\`\`bash
|
|
467862
|
+
vibe scene init <dir> [-r 16:9|9:16|1:1|4:5] [-d <sec>] [--visual-style "<name>"]
|
|
467863
|
+
vibe scene styles [<name>] # list / show vendored visual identities
|
|
467864
|
+
vibe scene install-skill [<dir>] [--host all] # retroactive Hyperframes-skill install
|
|
467865
|
+
vibe scene add <name> --style <preset> [...]
|
|
467866
|
+
vibe scene compose-prompts [<dir>] [--beat <id>] # H2: emit plan, no LLM call
|
|
467867
|
+
vibe scene lint [<root>] [--json] [--fix]
|
|
467868
|
+
vibe scene render [<root>] [--fps 30] [--quality standard] [--format mp4]
|
|
467869
|
+
vibe scene build [<dir>] [--mode agent|batch|auto] # H3 dispatch
|
|
467870
|
+
\`\`\`
|
|
467871
|
+
|
|
467872
|
+
## Style presets (for \`vibe scene add --style\`)
|
|
467873
|
+
|
|
467874
|
+
- **simple** \u2014 backdrop + bottom caption (default)
|
|
467875
|
+
- **announcement** \u2014 single huge headline, gradient text
|
|
467876
|
+
- **explainer** \u2014 kicker + title + subtitle stack
|
|
467877
|
+
- **kinetic-type** \u2014 words animate in word-by-word
|
|
467878
|
+
- **product-shot** \u2014 corner label + bottom headline + slow zoom
|
|
467879
|
+
|
|
467880
|
+
All presets accept \`--narration <text|file>\`, \`--visuals <prompt>\`,
|
|
467881
|
+
\`--headline\`, \`--kicker\`. With \`--narration\`, scene duration auto-derives
|
|
467882
|
+
from the generated TTS audio.
|
|
467883
|
+
|
|
467884
|
+
## STORYBOARD-to-MP4 (one command, v0.60+)
|
|
467885
|
+
|
|
467886
|
+
\`\`\`bash
|
|
467887
|
+
vibe scene init my-promo --visual-style "Swiss Pulse" -d 12
|
|
467888
|
+
# (edit STORYBOARD.md with per-beat YAML cues \u2014 narration, backdrop, duration)
|
|
467889
|
+
vibe scene build my-promo
|
|
467890
|
+
\`\`\`
|
|
467891
|
+
|
|
467892
|
+
\`vibe scene build\` reads the STORYBOARD frontmatter + per-beat cues,
|
|
467893
|
+
dispatches TTS + image-gen per beat, then either:
|
|
467894
|
+
|
|
467895
|
+
- **\`--mode agent\`** (default when an agent host is detected) \u2014 emits a
|
|
467896
|
+
\`needs-author\` plan via \`vibe scene compose-prompts\`. The host agent
|
|
467897
|
+
authors each \`compositions/scene-<id>.html\` itself, then re-invoking
|
|
467898
|
+
\`vibe scene build\` proceeds to lint + render.
|
|
467899
|
+
- **\`--mode batch\`** \u2014 VibeFrame runs an internal LLM (Claude / OpenAI /
|
|
467900
|
+
Gemini) to compose the HTML, then renders.
|
|
467901
|
+
|
|
467902
|
+
\`VIBE_BUILD_MODE\` env var overrides the auto-resolve.
|
|
467903
|
+
|
|
467904
|
+
## Lint feedback loop
|
|
467905
|
+
|
|
467906
|
+
\`\`\`bash
|
|
467907
|
+
vibe scene lint --json --fix
|
|
467908
|
+
\`\`\`
|
|
467909
|
+
|
|
467910
|
+
Returns structured findings. The recommended loop: 1) run lint with
|
|
467911
|
+
\`--fix\` (mechanical fixes applied), 2) if \`errorCount > 0\`, edit the
|
|
467912
|
+
scene HTML, 3) re-lint. Cap retries at 3 \u2014 if errors persist, fall back
|
|
467913
|
+
to a template preset (\`vibe scene add <id> --style simple --force\`)
|
|
467914
|
+
and surface the error to the user.
|
|
467915
|
+
|
|
467916
|
+
## When to use VibeFrame vs raw Hyperframes
|
|
467917
|
+
|
|
467918
|
+
| Task | Tool |
|
|
467919
|
+
|------|------|
|
|
467920
|
+
| Generate narration + image, then author scene | \`vibe scene add\` |
|
|
467921
|
+
| Generate a full scenes project from a STORYBOARD | \`vibe scene build\` |
|
|
467922
|
+
| Hand-tweak a single scene's animation | edit \`compositions/<file>.html\` directly |
|
|
467923
|
+
| Render the project | \`vibe scene render\` *or* \`npx hyperframes render\` (equivalent) |
|
|
467924
|
+
| Lint | \`vibe scene lint\` *or* \`npx hyperframes lint\` (equivalent) |
|
|
467925
|
+
|
|
467926
|
+
The \`vibe\` CLI adds asset generation, AI orchestration, and pipeline
|
|
467927
|
+
integration on top of Hyperframes' rendering primitives.
|
|
467928
|
+
|
|
467929
|
+
## Quality checklist before render
|
|
467930
|
+
|
|
467931
|
+
- [ ] \`vibe scene lint\` exits 0 (or only warnings)
|
|
467932
|
+
- [ ] \`vibe doctor\` confirms a usable Chrome (required for render)
|
|
467933
|
+
- [ ] Root \`data-duration\` matches the sum of clip durations
|
|
467934
|
+
- [ ] Aspect ratio in \`vibe.project.yaml\` matches the destination platform
|
|
467935
|
+
`;
|
|
467936
|
+
var PIPELINE_WALKTHROUGH = `# YAML pipelines (Video as Code)
|
|
467937
|
+
|
|
467938
|
+
A pipeline is a YAML manifest with steps that reference each other's
|
|
467939
|
+
outputs. \`vibe run pipeline.yaml\` executes them with checkpointing and
|
|
467940
|
+
cost estimation.
|
|
467941
|
+
|
|
467942
|
+
## Minimal skeleton
|
|
467943
|
+
|
|
467944
|
+
\`\`\`yaml
|
|
467945
|
+
name: promo-video
|
|
467946
|
+
description: 15s product teaser
|
|
467947
|
+
steps:
|
|
467948
|
+
- id: backdrop
|
|
467949
|
+
action: generate-image
|
|
467950
|
+
prompt: "sleek product shot on white background"
|
|
467951
|
+
output: backdrop.png
|
|
467952
|
+
- id: scene
|
|
467953
|
+
action: generate-video
|
|
467954
|
+
image: $backdrop.output # reference previous step output
|
|
467955
|
+
prompt: "slow camera pan"
|
|
467956
|
+
duration: 5
|
|
467957
|
+
output: scene.mp4
|
|
467958
|
+
- id: voice
|
|
467959
|
+
action: generate-tts
|
|
467960
|
+
text: "Meet the new standard."
|
|
467961
|
+
output: voice.mp3
|
|
467962
|
+
- id: final
|
|
467963
|
+
action: compose
|
|
467964
|
+
video: $scene.output
|
|
467965
|
+
audio: $voice.output
|
|
467966
|
+
output: final.mp4
|
|
467967
|
+
\`\`\`
|
|
467968
|
+
|
|
467969
|
+
## Supported actions
|
|
467970
|
+
|
|
467971
|
+
- \`generate-image\`, \`generate-video\`, \`generate-tts\`, \`generate-music\`,
|
|
467972
|
+
\`generate-sound-effect\`, \`generate-storyboard\`, \`generate-motion\`
|
|
467973
|
+
- \`edit-silence-cut\`, \`edit-jump-cut\`, \`edit-caption\`, \`edit-grade\`,
|
|
467974
|
+
\`edit-reframe\`, \`edit-speed-ramp\`, \`edit-fade\`, \`edit-noise-reduce\`,
|
|
467975
|
+
\`edit-text-overlay\`, \`edit-fill-gaps\`
|
|
467976
|
+
- \`analyze-media\`, \`analyze-video\`, \`analyze-review\`, \`analyze-suggest\`
|
|
467977
|
+
- \`audio-transcribe\`, \`audio-isolate\`, \`audio-voice-clone\`, \`audio-dub\`,
|
|
467978
|
+
\`audio-duck\`
|
|
467979
|
+
- \`detect-scenes\`, \`detect-silence\`, \`detect-beats\`
|
|
467980
|
+
- \`compose\`, \`export\`
|
|
467981
|
+
- \`scene-build\` (Plan H one-shot driver) and \`scene-render\`
|
|
467982
|
+
- \`compose-scenes-with-skills\` (internal-LLM compose pass)
|
|
467983
|
+
|
|
467984
|
+
The full set lives in \`packages/cli/src/pipeline/executor.ts\`.
|
|
467985
|
+
|
|
467986
|
+
## Variable references
|
|
467987
|
+
|
|
467988
|
+
- \`$<step-id>.output\` \u2014 previous step's output path
|
|
467989
|
+
- \`$<step-id>.result.<field>\` \u2014 structured field from JSON result
|
|
467990
|
+
- \`\${ENV_VAR}\` \u2014 environment variable
|
|
467991
|
+
- Values can be templated: \`"\${SCRIPT_TITLE} - Episode \${EPISODE}"\`
|
|
467992
|
+
|
|
467993
|
+
## Running
|
|
467994
|
+
|
|
467995
|
+
\`\`\`bash
|
|
467996
|
+
vibe run pipeline.yaml --dry-run # plan + cost estimate, no execution
|
|
467997
|
+
vibe run pipeline.yaml # execute
|
|
467998
|
+
vibe run pipeline.yaml --resume # retry from last successful step
|
|
467999
|
+
vibe run pipeline.yaml --from scene # start at specific step
|
|
468000
|
+
vibe run pipeline.yaml --provider-video kling # override provider
|
|
468001
|
+
\`\`\`
|
|
468002
|
+
|
|
468003
|
+
Checkpoints land next to the YAML: \`pipeline.yaml.checkpoint.json\`.
|
|
468004
|
+
|
|
468005
|
+
## Authoring tips
|
|
468006
|
+
|
|
468007
|
+
1. **Start from examples** \u2014 \`examples/demo-pipeline.yaml\` (FFmpeg-only,
|
|
468008
|
+
no keys), \`examples/promo-video.yaml\` (AI providers).
|
|
468009
|
+
2. **Dry-run first** \u2014 you see estimated cost and resolved variable
|
|
468010
|
+
graph before spending API credits.
|
|
468011
|
+
3. **Keep step ids short and descriptive** (\`intro\`, \`scene1\`, \`voice\`,
|
|
468012
|
+
\`bgm\`) \u2014 they appear in logs and variable refs.
|
|
468013
|
+
4. **Name outputs** with extensions matching the action (\`.mp4\`, \`.mp3\`,
|
|
468014
|
+
\`.png\`, \`.json\`).
|
|
468015
|
+
5. **Declare \`budget:\`** on expensive pipelines:
|
|
468016
|
+
\`\`\`yaml
|
|
468017
|
+
budget:
|
|
468018
|
+
tokens: 500_000
|
|
468019
|
+
max_tool_errors: 3
|
|
468020
|
+
cost_usd: 5.00
|
|
468021
|
+
\`\`\`
|
|
468022
|
+
6. **Split large pipelines** into smaller YAML files and compose via
|
|
468023
|
+
\`action: run-pipeline\` (nested).
|
|
468024
|
+
|
|
468025
|
+
## Converting ad-hoc shell sessions to pipelines
|
|
468026
|
+
|
|
468027
|
+
When the user has a working shell sequence, extract steps:
|
|
468028
|
+
|
|
468029
|
+
- Each \`vibe ...\` command becomes one step
|
|
468030
|
+
- File outputs become step outputs; downstream \`-i <file>\` references
|
|
468031
|
+
become \`$<id>.output\`
|
|
468032
|
+
- Shared parameters move to a top-level \`defaults:\` section
|
|
468033
|
+
- Wrap the entire chain in a \`name:\` + \`steps:\` skeleton
|
|
468034
|
+
|
|
468035
|
+
The \`compose\` action is the catch-all assembly step (audio mux, video
|
|
468036
|
+
overlay, etc.) \u2014 useful at the tail of a pipeline.
|
|
468037
|
+
`;
|
|
468038
|
+
var META = {
|
|
468039
|
+
scene: {
|
|
468040
|
+
title: "Scene authoring with vibe",
|
|
468041
|
+
summary: "Author per-scene HTML compositions and render to MP4 (BUILD flow)",
|
|
468042
|
+
steps: [
|
|
468043
|
+
'Run `vibe scene init <dir> --visual-style "<style name>"` to scaffold the project + install the Hyperframes skill (Plan H).',
|
|
468044
|
+
"Edit `STORYBOARD.md` with per-beat YAML cues (narration / backdrop / duration).",
|
|
468045
|
+
"Read `SKILL.md` for the framework rules and `DESIGN.md` for the visual-identity hard-gate.",
|
|
468046
|
+
"Run `vibe scene build <dir>`. With an agent host detected, the CLI emits a `needs-author` plan; the host agent authors each `compositions/scene-<id>.html` and re-invokes to render.",
|
|
468047
|
+
"Run `vibe scene lint --fix` to validate, then `vibe scene render` to produce the MP4."
|
|
468048
|
+
],
|
|
468049
|
+
relatedCommands: [
|
|
468050
|
+
"vibe scene init",
|
|
468051
|
+
"vibe scene styles",
|
|
468052
|
+
"vibe scene install-skill",
|
|
468053
|
+
"vibe scene compose-prompts",
|
|
468054
|
+
"vibe scene build",
|
|
468055
|
+
"vibe scene lint",
|
|
468056
|
+
"vibe scene render",
|
|
468057
|
+
"vibe scene add"
|
|
468058
|
+
]
|
|
468059
|
+
},
|
|
468060
|
+
pipeline: {
|
|
468061
|
+
title: "YAML pipelines (Video as Code)",
|
|
468062
|
+
summary: "Author and run reproducible multi-step video workflows",
|
|
468063
|
+
steps: [
|
|
468064
|
+
"Sketch the workflow as YAML \u2014 `name`, `description`, then `steps:` with `id` + `action` + inputs/outputs.",
|
|
468065
|
+
"Reference previous step outputs via `$<step-id>.output` (or `$<step-id>.result.<field>` for structured returns).",
|
|
468066
|
+
"Run `vibe run pipeline.yaml --dry-run` to see the resolved graph + cost estimate before spending API budget.",
|
|
468067
|
+
"Add a `budget:` block (tokens / cost_usd / max_tool_errors) to cap expensive runs.",
|
|
468068
|
+
"Run `vibe run pipeline.yaml` to execute. Failed steps checkpoint to `pipeline.yaml.checkpoint.json`; resume with `--resume`."
|
|
468069
|
+
],
|
|
468070
|
+
relatedCommands: [
|
|
468071
|
+
"vibe run",
|
|
468072
|
+
"vibe schema --list",
|
|
468073
|
+
"vibe doctor"
|
|
468074
|
+
]
|
|
468075
|
+
}
|
|
468076
|
+
};
|
|
468077
|
+
var CONTENT2 = {
|
|
468078
|
+
scene: SCENE_WALKTHROUGH,
|
|
468079
|
+
pipeline: PIPELINE_WALKTHROUGH
|
|
468080
|
+
};
|
|
468081
|
+
var WALKTHROUGH_TOPICS = ["scene", "pipeline"];
|
|
468082
|
+
function loadWalkthrough(topic) {
|
|
468083
|
+
const meta = META[topic];
|
|
468084
|
+
const content = CONTENT2[topic];
|
|
468085
|
+
if (!meta || !content) {
|
|
468086
|
+
throw new Error(`Unknown walkthrough topic: ${topic}`);
|
|
468087
|
+
}
|
|
468088
|
+
return {
|
|
468089
|
+
topic,
|
|
468090
|
+
title: meta.title,
|
|
468091
|
+
summary: meta.summary,
|
|
468092
|
+
steps: meta.steps,
|
|
468093
|
+
relatedCommands: meta.relatedCommands,
|
|
468094
|
+
content
|
|
468095
|
+
};
|
|
468096
|
+
}
|
|
468097
|
+
function listWalkthroughs() {
|
|
468098
|
+
return WALKTHROUGH_TOPICS.map((topic) => ({
|
|
468099
|
+
topic,
|
|
468100
|
+
title: META[topic].title,
|
|
468101
|
+
summary: META[topic].summary
|
|
468102
|
+
}));
|
|
468103
|
+
}
|
|
468104
|
+
|
|
468105
|
+
// ../cli/src/tools/manifest/walkthrough.ts
|
|
468106
|
+
var walkthroughSchema = z12.object({
|
|
468107
|
+
topic: z12.enum(WALKTHROUGH_TOPICS).optional().describe(
|
|
468108
|
+
"Walkthrough topic to load. Omit to list every available walkthrough \u2014 useful for discovery on first contact."
|
|
468109
|
+
)
|
|
468110
|
+
});
|
|
468111
|
+
var walkthroughTool = defineTool({
|
|
468112
|
+
name: "walkthrough",
|
|
468113
|
+
category: "agent",
|
|
468114
|
+
cost: "free",
|
|
468115
|
+
description: "Load the step-by-step authoring guide for a vibe workflow (BUILD scene authoring, YAML pipeline authoring). Universal CLI-equivalent of Claude Code's /vibe-* slash commands \u2014 any host agent that calls this tool gets the same content the slash menu delivers in Claude Code, with no Claude Code dependency. Without a topic, returns the catalog of walkthroughs for discovery.",
|
|
468116
|
+
schema: walkthroughSchema,
|
|
468117
|
+
async execute(args) {
|
|
468118
|
+
if (!args.topic) {
|
|
468119
|
+
const topics = listWalkthroughs();
|
|
468120
|
+
return {
|
|
468121
|
+
success: true,
|
|
468122
|
+
data: { action: "list", topics },
|
|
468123
|
+
humanLines: [
|
|
468124
|
+
`Available walkthroughs: ${topics.map((t) => t.topic).join(", ")}.`,
|
|
468125
|
+
`Call again with topic to load full content.`
|
|
468126
|
+
]
|
|
468127
|
+
};
|
|
468128
|
+
}
|
|
468129
|
+
const result = loadWalkthrough(args.topic);
|
|
468130
|
+
return {
|
|
468131
|
+
success: true,
|
|
468132
|
+
data: { action: "show", ...result },
|
|
468133
|
+
humanLines: [
|
|
468134
|
+
`Loaded walkthrough: ${result.title}.`,
|
|
468135
|
+
`${result.steps.length} steps, ${result.relatedCommands.length} related commands, ${result.content.length} chars of guide content.`
|
|
468136
|
+
]
|
|
468137
|
+
};
|
|
468138
|
+
}
|
|
468139
|
+
});
|
|
468140
|
+
var walkthroughTools = [walkthroughTool];
|
|
468141
|
+
|
|
467464
468142
|
// ../cli/src/tools/manifest/index.ts
|
|
467465
468143
|
var manifest = [
|
|
467466
468144
|
...sceneTools,
|
|
@@ -467473,15 +468151,16 @@ var manifest = [
|
|
|
467473
468151
|
...timelineTools,
|
|
467474
468152
|
...projectTools,
|
|
467475
468153
|
...exportTools,
|
|
467476
|
-
...agentOnlyTools
|
|
468154
|
+
...agentOnlyTools,
|
|
468155
|
+
...walkthroughTools
|
|
467477
468156
|
];
|
|
467478
468157
|
|
|
467479
468158
|
// ../cli/src/tools/zod-to-json-schema.ts
|
|
467480
|
-
function getDef(
|
|
467481
|
-
return
|
|
468159
|
+
function getDef(z13) {
|
|
468160
|
+
return z13._def;
|
|
467482
468161
|
}
|
|
467483
|
-
function getDescription(
|
|
467484
|
-
let current =
|
|
468162
|
+
function getDescription(z13) {
|
|
468163
|
+
let current = z13;
|
|
467485
468164
|
while (current) {
|
|
467486
468165
|
const def = getDef(current);
|
|
467487
468166
|
if (def.description) return def.description;
|
|
@@ -467489,24 +468168,24 @@ function getDescription(z12) {
|
|
|
467489
468168
|
}
|
|
467490
468169
|
return void 0;
|
|
467491
468170
|
}
|
|
467492
|
-
function unwrapOptional(
|
|
467493
|
-
const def = getDef(
|
|
468171
|
+
function unwrapOptional(z13) {
|
|
468172
|
+
const def = getDef(z13);
|
|
467494
468173
|
if (def.typeName === "ZodOptional" && def.innerType) {
|
|
467495
468174
|
return { inner: def.innerType, optional: true };
|
|
467496
468175
|
}
|
|
467497
|
-
return { inner:
|
|
468176
|
+
return { inner: z13, optional: false };
|
|
467498
468177
|
}
|
|
467499
|
-
function unwrapDefault(
|
|
467500
|
-
const def = getDef(
|
|
468178
|
+
function unwrapDefault(z13) {
|
|
468179
|
+
const def = getDef(z13);
|
|
467501
468180
|
if (def.typeName === "ZodDefault" && def.innerType && def.defaultValue) {
|
|
467502
468181
|
return { inner: def.innerType, defaultValue: def.defaultValue() };
|
|
467503
468182
|
}
|
|
467504
|
-
return { inner:
|
|
468183
|
+
return { inner: z13 };
|
|
467505
468184
|
}
|
|
467506
|
-
function convertLeaf(
|
|
467507
|
-
const { inner: afterDefault, defaultValue } = unwrapDefault(
|
|
468185
|
+
function convertLeaf(z13, description) {
|
|
468186
|
+
const { inner: afterDefault, defaultValue } = unwrapDefault(z13);
|
|
467508
468187
|
const def = getDef(afterDefault);
|
|
467509
|
-
const desc = description ?? getDescription(
|
|
468188
|
+
const desc = description ?? getDescription(z13);
|
|
467510
468189
|
const base = {};
|
|
467511
468190
|
if (desc) base.description = desc;
|
|
467512
468191
|
if (defaultValue !== void 0) base.default = defaultValue;
|
|
@@ -467553,8 +468232,8 @@ function convertLeaf(z12, description) {
|
|
|
467553
468232
|
);
|
|
467554
468233
|
}
|
|
467555
468234
|
}
|
|
467556
|
-
function convertObject(
|
|
467557
|
-
const def = getDef(
|
|
468235
|
+
function convertObject(z13, description) {
|
|
468236
|
+
const def = getDef(z13);
|
|
467558
468237
|
if (def.typeName !== "ZodObject" || !def.shape) {
|
|
467559
468238
|
throw new Error(`zod-to-json-schema: convertObject called on non-ZodObject (${def.typeName})`);
|
|
467560
468239
|
}
|