@vibeframe/cli 0.72.0 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1458 -453
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6546,8 +6546,10 @@ var output_exports = {};
|
|
|
6546
6546
|
__export(output_exports, {
|
|
6547
6547
|
COST_ESTIMATES: () => COST_ESTIMATES,
|
|
6548
6548
|
ExitCode: () => ExitCode,
|
|
6549
|
+
_resetDeprecationMemoryForTesting: () => _resetDeprecationMemoryForTesting,
|
|
6549
6550
|
apiError: () => apiError,
|
|
6550
6551
|
authError: () => authError,
|
|
6552
|
+
emitDeprecationWarning: () => emitDeprecationWarning,
|
|
6551
6553
|
exitWithError: () => exitWithError,
|
|
6552
6554
|
generalError: () => generalError,
|
|
6553
6555
|
isJsonMode: () => isJsonMode,
|
|
@@ -6692,6 +6694,19 @@ function suggestNext(tip) {
|
|
|
6692
6694
|
Tip: ${tip}`));
|
|
6693
6695
|
}
|
|
6694
6696
|
}
|
|
6697
|
+
function emitDeprecationWarning(oldName, newName, removeIn) {
|
|
6698
|
+
if (isJsonMode() || isQuietMode()) return;
|
|
6699
|
+
if (!process.stderr.isTTY) return;
|
|
6700
|
+
const key = `${oldName}\u2192${newName}`;
|
|
6701
|
+
if (_seenDeprecations.has(key)) return;
|
|
6702
|
+
_seenDeprecations.add(key);
|
|
6703
|
+
process.stderr.write(
|
|
6704
|
+
source_default.yellow(`[deprecated] '${oldName}' is deprecated; use '${newName}' instead. Alias will be removed in ${removeIn}.`) + "\n"
|
|
6705
|
+
);
|
|
6706
|
+
}
|
|
6707
|
+
function _resetDeprecationMemoryForTesting() {
|
|
6708
|
+
_seenDeprecations.clear();
|
|
6709
|
+
}
|
|
6695
6710
|
function outputError(error, details) {
|
|
6696
6711
|
if (isJsonMode()) {
|
|
6697
6712
|
console.error(JSON.stringify({ success: false, error, ...details }, null, 2));
|
|
@@ -6699,7 +6714,7 @@ function outputError(error, details) {
|
|
|
6699
6714
|
console.error(error);
|
|
6700
6715
|
}
|
|
6701
6716
|
}
|
|
6702
|
-
var ExitCode, PROVIDER_ERROR_HINTS, COST_ESTIMATES;
|
|
6717
|
+
var ExitCode, PROVIDER_ERROR_HINTS, COST_ESTIMATES, _seenDeprecations;
|
|
6703
6718
|
var init_output = __esm({
|
|
6704
6719
|
"src/commands/output.ts"() {
|
|
6705
6720
|
"use strict";
|
|
@@ -6734,7 +6749,7 @@ var init_output = __esm({
|
|
|
6734
6749
|
{ pattern: /context_length_exceeded|maximum.*context.*length|token.*limit.*exceeded|prompt.*too.*long/i, suggestion: "Input exceeds the model's context window. Shorten the prompt, or use a model with larger context (run 'vibe schema <command>' for options).", retryable: false },
|
|
6735
6750
|
{ pattern: /model.*not.*found|invalid.*model|unknown.*model|model_not_found/i, suggestion: "The specified model is unavailable. Check 'vibe schema <command>' for valid model options.", retryable: false },
|
|
6736
6751
|
// Provider-specific
|
|
6737
|
-
{ pattern: /voice.*not.*found|voice_not_found|invalid.*voice.?id/i, suggestion: "Voice ID not found. Run 'vibe audio voices' to list available voices, then pass --voice <id>.", retryable: false },
|
|
6752
|
+
{ pattern: /voice.*not.*found|voice_not_found|invalid.*voice.?id/i, suggestion: "Voice ID not found. Run 'vibe audio list-voices' to list available voices, then pass --voice <id>.", retryable: false },
|
|
6738
6753
|
{ pattern: /character.*(count|limit).*exceeded|invalid_character_count/i, suggestion: "Text exceeds the TTS provider's character limit. Shorten the text or split into chunks.", retryable: false },
|
|
6739
6754
|
{ pattern: /invalid.*aspect.*ratio|unsupported.*aspect.*ratio|unsupported.*resolution/i, suggestion: "This aspect ratio or resolution isn't supported by the chosen model. Check 'vibe schema <command>' for supported values.", retryable: false },
|
|
6740
6755
|
{ pattern: /invalid.*file.*format|unsupported.*(format|codec)|unsupported.*media.?type/i, suggestion: "Input file format not supported. Convert to MP4/MP3/PNG first with 'vibe export' or 'ffmpeg'.", retryable: false },
|
|
@@ -6785,6 +6800,7 @@ var init_output = __esm({
|
|
|
6785
6800
|
// pre-flight). Range covers a 1-beat preview to a 10-beat long-form.
|
|
6786
6801
|
"compose scenes with skills": { min: 0.05, max: 1.5, unit: "per pipeline" }
|
|
6787
6802
|
};
|
|
6803
|
+
_seenDeprecations = /* @__PURE__ */ new Set();
|
|
6788
6804
|
}
|
|
6789
6805
|
});
|
|
6790
6806
|
|
|
@@ -14343,12 +14359,12 @@ var init_api_keys = __esm({
|
|
|
14343
14359
|
label: "ImgBB",
|
|
14344
14360
|
showInSetup: false,
|
|
14345
14361
|
// not prompted in setup wizard — internal upload host
|
|
14346
|
-
envExampleComment: "ImgBB API Key (image hosting \u2014 used by Kling and
|
|
14362
|
+
envExampleComment: "ImgBB API Key (image hosting \u2014 used by Kling and Seedance for image-to-video uploads)",
|
|
14347
14363
|
envExampleUrl: "https://api.imgbb.com/",
|
|
14348
14364
|
// ImgBB has no provider class (envvar-only); doctor still shows what it
|
|
14349
14365
|
// unlocks at the apiKey level.
|
|
14350
14366
|
commandsUnlocked: [
|
|
14351
|
-
"generate video -p kling/
|
|
14367
|
+
"generate video -p kling/seedance (image-to-video upload host)"
|
|
14352
14368
|
]
|
|
14353
14369
|
});
|
|
14354
14370
|
defineProvider({
|
|
@@ -15194,7 +15210,7 @@ var init_GeminiProvider = __esm({
|
|
|
15194
15210
|
* Sleep helper
|
|
15195
15211
|
*/
|
|
15196
15212
|
sleep(ms) {
|
|
15197
|
-
return new Promise((
|
|
15213
|
+
return new Promise((resolve64) => setTimeout(resolve64, ms));
|
|
15198
15214
|
}
|
|
15199
15215
|
/**
|
|
15200
15216
|
* Extend a previously generated Veo video
|
|
@@ -19366,7 +19382,7 @@ var init_RunwayProvider = __esm({
|
|
|
19366
19382
|
* Sleep helper
|
|
19367
19383
|
*/
|
|
19368
19384
|
sleep(ms) {
|
|
19369
|
-
return new Promise((
|
|
19385
|
+
return new Promise((resolve64) => setTimeout(resolve64, ms));
|
|
19370
19386
|
}
|
|
19371
19387
|
};
|
|
19372
19388
|
RunwayProvider.API_VERSION = "2024-11-06";
|
|
@@ -19807,7 +19823,7 @@ var init_KlingProvider = __esm({
|
|
|
19807
19823
|
* Sleep helper
|
|
19808
19824
|
*/
|
|
19809
19825
|
sleep(ms) {
|
|
19810
|
-
return new Promise((
|
|
19826
|
+
return new Promise((resolve64) => setTimeout(resolve64, ms));
|
|
19811
19827
|
}
|
|
19812
19828
|
};
|
|
19813
19829
|
klingProvider = new KlingProvider();
|
|
@@ -20125,7 +20141,7 @@ var init_GrokProvider = __esm({
|
|
|
20125
20141
|
}
|
|
20126
20142
|
}
|
|
20127
20143
|
sleep(ms) {
|
|
20128
|
-
return new Promise((
|
|
20144
|
+
return new Promise((resolve64) => setTimeout(resolve64, ms));
|
|
20129
20145
|
}
|
|
20130
20146
|
};
|
|
20131
20147
|
grokProvider = new GrokProvider();
|
|
@@ -20160,11 +20176,11 @@ var require_middleware = __commonJS({
|
|
|
20160
20176
|
"use strict";
|
|
20161
20177
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
20162
20178
|
function adopt(value) {
|
|
20163
|
-
return value instanceof P ? value : new P(function(
|
|
20164
|
-
|
|
20179
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
20180
|
+
resolve64(value);
|
|
20165
20181
|
});
|
|
20166
20182
|
}
|
|
20167
|
-
return new (P || (P = Promise))(function(
|
|
20183
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
20168
20184
|
function fulfilled(value) {
|
|
20169
20185
|
try {
|
|
20170
20186
|
step(generator.next(value));
|
|
@@ -20180,7 +20196,7 @@ var require_middleware = __commonJS({
|
|
|
20180
20196
|
}
|
|
20181
20197
|
}
|
|
20182
20198
|
function step(result) {
|
|
20183
|
-
result.done ?
|
|
20199
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
20184
20200
|
}
|
|
20185
20201
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20186
20202
|
});
|
|
@@ -20265,11 +20281,11 @@ var require_response = __commonJS({
|
|
|
20265
20281
|
"use strict";
|
|
20266
20282
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
20267
20283
|
function adopt(value) {
|
|
20268
|
-
return value instanceof P ? value : new P(function(
|
|
20269
|
-
|
|
20284
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
20285
|
+
resolve64(value);
|
|
20270
20286
|
});
|
|
20271
20287
|
}
|
|
20272
|
-
return new (P || (P = Promise))(function(
|
|
20288
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
20273
20289
|
function fulfilled(value) {
|
|
20274
20290
|
try {
|
|
20275
20291
|
step(generator.next(value));
|
|
@@ -20285,7 +20301,7 @@ var require_response = __commonJS({
|
|
|
20285
20301
|
}
|
|
20286
20302
|
}
|
|
20287
20303
|
function step(result) {
|
|
20288
|
-
result.done ?
|
|
20304
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
20289
20305
|
}
|
|
20290
20306
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20291
20307
|
});
|
|
@@ -20392,11 +20408,11 @@ var require_utils = __commonJS({
|
|
|
20392
20408
|
"use strict";
|
|
20393
20409
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
20394
20410
|
function adopt(value) {
|
|
20395
|
-
return value instanceof P ? value : new P(function(
|
|
20396
|
-
|
|
20411
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
20412
|
+
resolve64(value);
|
|
20397
20413
|
});
|
|
20398
20414
|
}
|
|
20399
|
-
return new (P || (P = Promise))(function(
|
|
20415
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
20400
20416
|
function fulfilled(value) {
|
|
20401
20417
|
try {
|
|
20402
20418
|
step(generator.next(value));
|
|
@@ -20412,7 +20428,7 @@ var require_utils = __commonJS({
|
|
|
20412
20428
|
}
|
|
20413
20429
|
}
|
|
20414
20430
|
function step(result) {
|
|
20415
|
-
result.done ?
|
|
20431
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
20416
20432
|
}
|
|
20417
20433
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20418
20434
|
});
|
|
@@ -20505,7 +20521,7 @@ var require_utils = __commonJS({
|
|
|
20505
20521
|
}
|
|
20506
20522
|
function sleep2(ms) {
|
|
20507
20523
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20508
|
-
return new Promise((
|
|
20524
|
+
return new Promise((resolve64) => setTimeout(resolve64, ms));
|
|
20509
20525
|
});
|
|
20510
20526
|
}
|
|
20511
20527
|
}
|
|
@@ -20517,11 +20533,11 @@ var require_retry = __commonJS({
|
|
|
20517
20533
|
"use strict";
|
|
20518
20534
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
20519
20535
|
function adopt(value) {
|
|
20520
|
-
return value instanceof P ? value : new P(function(
|
|
20521
|
-
|
|
20536
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
20537
|
+
resolve64(value);
|
|
20522
20538
|
});
|
|
20523
20539
|
}
|
|
20524
|
-
return new (P || (P = Promise))(function(
|
|
20540
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
20525
20541
|
function fulfilled(value) {
|
|
20526
20542
|
try {
|
|
20527
20543
|
step(generator.next(value));
|
|
@@ -20537,7 +20553,7 @@ var require_retry = __commonJS({
|
|
|
20537
20553
|
}
|
|
20538
20554
|
}
|
|
20539
20555
|
function step(result) {
|
|
20540
|
-
result.done ?
|
|
20556
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
20541
20557
|
}
|
|
20542
20558
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20543
20559
|
});
|
|
@@ -20744,11 +20760,11 @@ var require_request = __commonJS({
|
|
|
20744
20760
|
"use strict";
|
|
20745
20761
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
20746
20762
|
function adopt(value) {
|
|
20747
|
-
return value instanceof P ? value : new P(function(
|
|
20748
|
-
|
|
20763
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
20764
|
+
resolve64(value);
|
|
20749
20765
|
});
|
|
20750
20766
|
}
|
|
20751
|
-
return new (P || (P = Promise))(function(
|
|
20767
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
20752
20768
|
function fulfilled(value) {
|
|
20753
20769
|
try {
|
|
20754
20770
|
step(generator.next(value));
|
|
@@ -20764,7 +20780,7 @@ var require_request = __commonJS({
|
|
|
20764
20780
|
}
|
|
20765
20781
|
}
|
|
20766
20782
|
function step(result) {
|
|
20767
|
-
result.done ?
|
|
20783
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
20768
20784
|
}
|
|
20769
20785
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20770
20786
|
});
|
|
@@ -20851,11 +20867,11 @@ var require_storage = __commonJS({
|
|
|
20851
20867
|
"use strict";
|
|
20852
20868
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
20853
20869
|
function adopt(value) {
|
|
20854
|
-
return value instanceof P ? value : new P(function(
|
|
20855
|
-
|
|
20870
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
20871
|
+
resolve64(value);
|
|
20856
20872
|
});
|
|
20857
20873
|
}
|
|
20858
|
-
return new (P || (P = Promise))(function(
|
|
20874
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
20859
20875
|
function fulfilled(value) {
|
|
20860
20876
|
try {
|
|
20861
20877
|
step(generator.next(value));
|
|
@@ -20871,7 +20887,7 @@ var require_storage = __commonJS({
|
|
|
20871
20887
|
}
|
|
20872
20888
|
}
|
|
20873
20889
|
function step(result) {
|
|
20874
|
-
result.done ?
|
|
20890
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
20875
20891
|
}
|
|
20876
20892
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20877
20893
|
});
|
|
@@ -21199,11 +21215,11 @@ var require_auth = __commonJS({
|
|
|
21199
21215
|
"use strict";
|
|
21200
21216
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
21201
21217
|
function adopt(value) {
|
|
21202
|
-
return value instanceof P ? value : new P(function(
|
|
21203
|
-
|
|
21218
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
21219
|
+
resolve64(value);
|
|
21204
21220
|
});
|
|
21205
21221
|
}
|
|
21206
|
-
return new (P || (P = Promise))(function(
|
|
21222
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
21207
21223
|
function fulfilled(value) {
|
|
21208
21224
|
try {
|
|
21209
21225
|
step(generator.next(value));
|
|
@@ -21219,7 +21235,7 @@ var require_auth = __commonJS({
|
|
|
21219
21235
|
}
|
|
21220
21236
|
}
|
|
21221
21237
|
function step(result) {
|
|
21222
|
-
result.done ?
|
|
21238
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
21223
21239
|
}
|
|
21224
21240
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21225
21241
|
});
|
|
@@ -21258,11 +21274,11 @@ var require_streaming = __commonJS({
|
|
|
21258
21274
|
"use strict";
|
|
21259
21275
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
21260
21276
|
function adopt(value) {
|
|
21261
|
-
return value instanceof P ? value : new P(function(
|
|
21262
|
-
|
|
21277
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
21278
|
+
resolve64(value);
|
|
21263
21279
|
});
|
|
21264
21280
|
}
|
|
21265
|
-
return new (P || (P = Promise))(function(
|
|
21281
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
21266
21282
|
function fulfilled(value) {
|
|
21267
21283
|
try {
|
|
21268
21284
|
step(generator.next(value));
|
|
@@ -21278,7 +21294,7 @@ var require_streaming = __commonJS({
|
|
|
21278
21294
|
}
|
|
21279
21295
|
}
|
|
21280
21296
|
function step(result) {
|
|
21281
|
-
result.done ?
|
|
21297
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
21282
21298
|
}
|
|
21283
21299
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21284
21300
|
});
|
|
@@ -21511,7 +21527,7 @@ var require_streaming = __commonJS({
|
|
|
21511
21527
|
query: options.queryParams
|
|
21512
21528
|
});
|
|
21513
21529
|
this.options = options;
|
|
21514
|
-
this.donePromise = new Promise((
|
|
21530
|
+
this.donePromise = new Promise((resolve64, reject) => {
|
|
21515
21531
|
if (this.streamClosed) {
|
|
21516
21532
|
reject(new response_1.ApiError({
|
|
21517
21533
|
message: "Streaming connection is already closed.",
|
|
@@ -21522,11 +21538,11 @@ var require_streaming = __commonJS({
|
|
|
21522
21538
|
}
|
|
21523
21539
|
this.signal.addEventListener("abort", () => {
|
|
21524
21540
|
var _a2;
|
|
21525
|
-
|
|
21541
|
+
resolve64((_a2 = this.currentData) !== null && _a2 !== void 0 ? _a2 : {});
|
|
21526
21542
|
});
|
|
21527
21543
|
this.on("done", (data) => {
|
|
21528
21544
|
this.streamClosed = true;
|
|
21529
|
-
|
|
21545
|
+
resolve64(data);
|
|
21530
21546
|
});
|
|
21531
21547
|
this.on("error", (error) => {
|
|
21532
21548
|
this.streamClosed = true;
|
|
@@ -21551,7 +21567,7 @@ var require_streaming = __commonJS({
|
|
|
21551
21567
|
if (data) {
|
|
21552
21568
|
yield yield __await(data);
|
|
21553
21569
|
}
|
|
21554
|
-
yield __await(new Promise((
|
|
21570
|
+
yield __await(new Promise((resolve64) => setTimeout(resolve64, 16)));
|
|
21555
21571
|
}
|
|
21556
21572
|
});
|
|
21557
21573
|
}
|
|
@@ -21596,11 +21612,11 @@ var require_queue = __commonJS({
|
|
|
21596
21612
|
"use strict";
|
|
21597
21613
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
21598
21614
|
function adopt(value) {
|
|
21599
|
-
return value instanceof P ? value : new P(function(
|
|
21600
|
-
|
|
21615
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
21616
|
+
resolve64(value);
|
|
21601
21617
|
});
|
|
21602
21618
|
}
|
|
21603
|
-
return new (P || (P = Promise))(function(
|
|
21619
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
21604
21620
|
function fulfilled(value) {
|
|
21605
21621
|
try {
|
|
21606
21622
|
step(generator.next(value));
|
|
@@ -21616,7 +21632,7 @@ var require_queue = __commonJS({
|
|
|
21616
21632
|
}
|
|
21617
21633
|
}
|
|
21618
21634
|
function step(result) {
|
|
21619
|
-
result.done ?
|
|
21635
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
21620
21636
|
}
|
|
21621
21637
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21622
21638
|
});
|
|
@@ -21751,7 +21767,7 @@ var require_queue = __commonJS({
|
|
|
21751
21767
|
}
|
|
21752
21768
|
return doneStatus;
|
|
21753
21769
|
}
|
|
21754
|
-
return new Promise((
|
|
21770
|
+
return new Promise((resolve64, reject) => {
|
|
21755
21771
|
var _a;
|
|
21756
21772
|
let pollingTimeoutId;
|
|
21757
21773
|
const pollInterval = "pollInterval" in options && typeof options.pollInterval === "number" ? (_a = options.pollInterval) !== null && _a !== void 0 ? _a : DEFAULT_POLL_INTERVAL : DEFAULT_POLL_INTERVAL;
|
|
@@ -21783,7 +21799,7 @@ var require_queue = __commonJS({
|
|
|
21783
21799
|
}
|
|
21784
21800
|
if (requestStatus.status === "COMPLETED") {
|
|
21785
21801
|
clearScheduledTasks();
|
|
21786
|
-
|
|
21802
|
+
resolve64(requestStatus);
|
|
21787
21803
|
return;
|
|
21788
21804
|
}
|
|
21789
21805
|
pollingTimeoutId = setTimeout(poll, pollInterval);
|
|
@@ -23744,11 +23760,11 @@ var require_realtime = __commonJS({
|
|
|
23744
23760
|
"use strict";
|
|
23745
23761
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
23746
23762
|
function adopt(value) {
|
|
23747
|
-
return value instanceof P ? value : new P(function(
|
|
23748
|
-
|
|
23763
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
23764
|
+
resolve64(value);
|
|
23749
23765
|
});
|
|
23750
23766
|
}
|
|
23751
|
-
return new (P || (P = Promise))(function(
|
|
23767
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
23752
23768
|
function fulfilled(value) {
|
|
23753
23769
|
try {
|
|
23754
23770
|
step(generator.next(value));
|
|
@@ -23764,7 +23780,7 @@ var require_realtime = __commonJS({
|
|
|
23764
23780
|
}
|
|
23765
23781
|
}
|
|
23766
23782
|
function step(result) {
|
|
23767
|
-
result.done ?
|
|
23783
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
23768
23784
|
}
|
|
23769
23785
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23770
23786
|
});
|
|
@@ -24089,11 +24105,11 @@ var require_client = __commonJS({
|
|
|
24089
24105
|
"use strict";
|
|
24090
24106
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
24091
24107
|
function adopt(value) {
|
|
24092
|
-
return value instanceof P ? value : new P(function(
|
|
24093
|
-
|
|
24108
|
+
return value instanceof P ? value : new P(function(resolve64) {
|
|
24109
|
+
resolve64(value);
|
|
24094
24110
|
});
|
|
24095
24111
|
}
|
|
24096
|
-
return new (P || (P = Promise))(function(
|
|
24112
|
+
return new (P || (P = Promise))(function(resolve64, reject) {
|
|
24097
24113
|
function fulfilled(value) {
|
|
24098
24114
|
try {
|
|
24099
24115
|
step(generator.next(value));
|
|
@@ -24109,7 +24125,7 @@ var require_client = __commonJS({
|
|
|
24109
24125
|
}
|
|
24110
24126
|
}
|
|
24111
24127
|
function step(result) {
|
|
24112
|
-
result.done ?
|
|
24128
|
+
result.done ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
24113
24129
|
}
|
|
24114
24130
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24115
24131
|
});
|
|
@@ -24417,13 +24433,18 @@ var init_fal = __esm({
|
|
|
24417
24433
|
defineProvider({
|
|
24418
24434
|
id: "fal",
|
|
24419
24435
|
label: "fal.ai (Seedance 2.0)",
|
|
24436
|
+
displayName: "Seedance 2.0",
|
|
24437
|
+
gateway: "fal.ai",
|
|
24438
|
+
aliases: ["seedance"],
|
|
24439
|
+
models: ["seedance-2.0", "seedance-2.0-fast"],
|
|
24440
|
+
capabilities: ["text-to-video", "image-to-video", "native-audio"],
|
|
24420
24441
|
apiKey: "fal",
|
|
24421
24442
|
kinds: ["video"],
|
|
24422
24443
|
resolverPriority: { video: 1 },
|
|
24423
24444
|
commandsUnlocked: [
|
|
24424
|
-
"generate video -p
|
|
24425
|
-
"generate video -p
|
|
24426
|
-
"generate video -p
|
|
24445
|
+
"generate video -p seedance (Seedance 2.0 via fal.ai \u2014 default since v0.57)",
|
|
24446
|
+
"generate video -p seedance --seedance-model fast (lower-latency variant)",
|
|
24447
|
+
"generate video -p seedance -i <image> (image-to-video)"
|
|
24427
24448
|
]
|
|
24428
24449
|
});
|
|
24429
24450
|
}
|
|
@@ -24687,7 +24708,7 @@ var init_ReplicateProvider = __esm({
|
|
|
24687
24708
|
* Sleep helper
|
|
24688
24709
|
*/
|
|
24689
24710
|
sleep(ms) {
|
|
24690
|
-
return new Promise((
|
|
24711
|
+
return new Promise((resolve64) => setTimeout(resolve64, ms));
|
|
24691
24712
|
}
|
|
24692
24713
|
/**
|
|
24693
24714
|
* Generate music from text prompt using MusicGen
|
|
@@ -25680,7 +25701,7 @@ async function prompt(question, hidden = false) {
|
|
|
25680
25701
|
input: process.stdin,
|
|
25681
25702
|
output: process.stdout
|
|
25682
25703
|
});
|
|
25683
|
-
return new Promise((
|
|
25704
|
+
return new Promise((resolve64) => {
|
|
25684
25705
|
if (hidden && process.stdin.isTTY) {
|
|
25685
25706
|
process.stdout.write(question);
|
|
25686
25707
|
let input = "";
|
|
@@ -25694,7 +25715,7 @@ async function prompt(question, hidden = false) {
|
|
|
25694
25715
|
process.stdin.removeListener("data", onData);
|
|
25695
25716
|
process.stdout.write("\n");
|
|
25696
25717
|
rl.close();
|
|
25697
|
-
|
|
25718
|
+
resolve64(input);
|
|
25698
25719
|
} else if (char === "") {
|
|
25699
25720
|
process.exit(1);
|
|
25700
25721
|
} else if (char === "\x7F" || char === "\b") {
|
|
@@ -25709,7 +25730,7 @@ async function prompt(question, hidden = false) {
|
|
|
25709
25730
|
} else {
|
|
25710
25731
|
rl.question(question, (answer) => {
|
|
25711
25732
|
rl.close();
|
|
25712
|
-
|
|
25733
|
+
resolve64(answer);
|
|
25713
25734
|
});
|
|
25714
25735
|
}
|
|
25715
25736
|
});
|
|
@@ -26040,6 +26061,54 @@ _Browse other named styles: \`vibe scene styles\`_
|
|
|
26040
26061
|
${style ? `_This file was seeded by \`vibe scene init --visual-style "${style.name}"\`._` : `_Seed this file from a named style: \`vibe scene init <dir> --visual-style "<name>"\`._`}
|
|
26041
26062
|
`;
|
|
26042
26063
|
}
|
|
26064
|
+
function buildStoryboardMd(name, duration = 12) {
|
|
26065
|
+
return `---
|
|
26066
|
+
title: ${name}
|
|
26067
|
+
duration: ${duration}
|
|
26068
|
+
aspect: 16:9
|
|
26069
|
+
tts: auto
|
|
26070
|
+
imageProvider: openai
|
|
26071
|
+
---
|
|
26072
|
+
|
|
26073
|
+
# ${name} \u2014 Storyboard
|
|
26074
|
+
|
|
26075
|
+
Edit these beats before running \`vibe build\`. Each beat starts with
|
|
26076
|
+
YAML cues that drive narration, backdrop generation, and timing.
|
|
26077
|
+
|
|
26078
|
+
## Beat hook \u2014 Hook
|
|
26079
|
+
|
|
26080
|
+
\`\`\`yaml
|
|
26081
|
+
narration: "Introduce the promise in one crisp sentence."
|
|
26082
|
+
backdrop: "Cinematic abstract technology backdrop, precise light, premium editorial feel"
|
|
26083
|
+
duration: 4
|
|
26084
|
+
\`\`\`
|
|
26085
|
+
|
|
26086
|
+
Show the core visual identity immediately. Keep copy short enough for one
|
|
26087
|
+
screen and one spoken breath.
|
|
26088
|
+
|
|
26089
|
+
## Beat proof \u2014 Proof
|
|
26090
|
+
|
|
26091
|
+
\`\`\`yaml
|
|
26092
|
+
narration: "Show the mechanism or proof point that makes the promise believable."
|
|
26093
|
+
backdrop: "Layered interface details, subtle motion trails, high-contrast product storytelling"
|
|
26094
|
+
duration: 4
|
|
26095
|
+
\`\`\`
|
|
26096
|
+
|
|
26097
|
+
Use this beat for the concrete differentiator: command, workflow, metric, or
|
|
26098
|
+
before/after.
|
|
26099
|
+
|
|
26100
|
+
## Beat close \u2014 Close
|
|
26101
|
+
|
|
26102
|
+
\`\`\`yaml
|
|
26103
|
+
narration: "Close with the action the viewer should remember."
|
|
26104
|
+
backdrop: "Resolved hero frame, confident final composition, clean negative space"
|
|
26105
|
+
duration: 4
|
|
26106
|
+
\`\`\`
|
|
26107
|
+
|
|
26108
|
+
End on the product name, offer, or command. Avoid adding a new idea in the
|
|
26109
|
+
final beat.
|
|
26110
|
+
`;
|
|
26111
|
+
}
|
|
26043
26112
|
function buildProjectClaudeMd(name) {
|
|
26044
26113
|
return `# ${name} \u2014 Scene Authoring Project
|
|
26045
26114
|
|
|
@@ -26069,7 +26138,7 @@ semantics, VibeFrame pipeline conventions) that are NOT in generic web docs.
|
|
|
26069
26138
|
| **vibe-scene** | \`/vibe-scene\` | VibeFrame's authoring loop, AI assets, lint feedback, pipeline integration |
|
|
26070
26139
|
| **gsap** | \`/gsap\` | GSAP tweens, timelines, easing |
|
|
26071
26140
|
|
|
26072
|
-
|
|
26141
|
+
Optional: install the upstream Hyperframes skills once per machine when your agent supports skill commands:
|
|
26073
26142
|
|
|
26074
26143
|
\`\`\`bash
|
|
26075
26144
|
npx skills add heygen-com/hyperframes
|
|
@@ -26082,6 +26151,7 @@ the framework-level minimum, not the cinematic craft layer.
|
|
|
26082
26151
|
## Project structure
|
|
26083
26152
|
|
|
26084
26153
|
- \`DESIGN.md\` \u2014 visual identity contract (palette, type, motion, transitions)
|
|
26154
|
+
- \`STORYBOARD.md\` \u2014 per-beat narration/backdrop/duration cues for \`vibe build\`
|
|
26085
26155
|
- \`index.html\` \u2014 root composition (timeline)
|
|
26086
26156
|
- \`compositions/scene-*.html\` \u2014 per-scene HTML authored by you or the agent
|
|
26087
26157
|
- \`assets/\` \u2014 shared media (narration audio, images, video)
|
|
@@ -26094,6 +26164,7 @@ the framework-level minimum, not the cinematic craft layer.
|
|
|
26094
26164
|
|
|
26095
26165
|
\`\`\`bash
|
|
26096
26166
|
vibe scene add <name> --narration "..." --visuals "..." # Author a new scene via AI
|
|
26167
|
+
vibe build # STORYBOARD.md \u2192 narrated MP4
|
|
26097
26168
|
vibe scene lint # Validate scenes (in-process HF linter)
|
|
26098
26169
|
vibe scene render # Render to MP4
|
|
26099
26170
|
|
|
@@ -26138,6 +26209,41 @@ tmp/
|
|
|
26138
26209
|
*.log
|
|
26139
26210
|
`;
|
|
26140
26211
|
}
|
|
26212
|
+
function isSceneScaffoldProfile(value) {
|
|
26213
|
+
return value === "minimal" || value === "agent" || value === "full";
|
|
26214
|
+
}
|
|
26215
|
+
function describeSceneScaffold(opts) {
|
|
26216
|
+
const dir = resolve5(opts.dir);
|
|
26217
|
+
const profile = opts.profile ?? "full";
|
|
26218
|
+
const groups = {
|
|
26219
|
+
authoring: [
|
|
26220
|
+
resolve5(dir, "STORYBOARD.md"),
|
|
26221
|
+
resolve5(dir, "DESIGN.md"),
|
|
26222
|
+
resolve5(dir, "vibe.project.yaml"),
|
|
26223
|
+
resolve5(dir, ".gitignore")
|
|
26224
|
+
],
|
|
26225
|
+
render: [],
|
|
26226
|
+
agent: []
|
|
26227
|
+
};
|
|
26228
|
+
if (profile === "full") {
|
|
26229
|
+
groups.render = [
|
|
26230
|
+
resolve5(dir, "index.html"),
|
|
26231
|
+
resolve5(dir, "compositions"),
|
|
26232
|
+
resolve5(dir, "assets"),
|
|
26233
|
+
resolve5(dir, "renders"),
|
|
26234
|
+
resolve5(dir, "hyperframes.json"),
|
|
26235
|
+
resolve5(dir, "meta.json")
|
|
26236
|
+
];
|
|
26237
|
+
}
|
|
26238
|
+
if (profile === "agent" || profile === "full") {
|
|
26239
|
+
groups.agent = [
|
|
26240
|
+
resolve5(dir, "SKILL.md"),
|
|
26241
|
+
resolve5(dir, "references"),
|
|
26242
|
+
resolve5(dir, "CLAUDE.md")
|
|
26243
|
+
];
|
|
26244
|
+
}
|
|
26245
|
+
return groups;
|
|
26246
|
+
}
|
|
26141
26247
|
async function pathExists(p) {
|
|
26142
26248
|
try {
|
|
26143
26249
|
await access3(p);
|
|
@@ -26152,37 +26258,43 @@ async function scaffoldSceneProject(opts) {
|
|
|
26152
26258
|
const aspect = opts.aspect ?? "16:9";
|
|
26153
26259
|
const duration = opts.duration ?? 10;
|
|
26154
26260
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
26261
|
+
const profile = opts.profile ?? "full";
|
|
26155
26262
|
await mkdir2(dir, { recursive: true });
|
|
26156
|
-
|
|
26157
|
-
|
|
26263
|
+
if (profile === "full") {
|
|
26264
|
+
await mkdir2(resolve5(dir, "compositions"), { recursive: true });
|
|
26265
|
+
await mkdir2(resolve5(dir, "assets"), { recursive: true });
|
|
26266
|
+
await mkdir2(resolve5(dir, "renders"), { recursive: true });
|
|
26267
|
+
}
|
|
26158
26268
|
const created = [];
|
|
26159
26269
|
const skipped2 = [];
|
|
26160
26270
|
const merged = [];
|
|
26161
|
-
|
|
26162
|
-
|
|
26163
|
-
|
|
26164
|
-
|
|
26165
|
-
|
|
26166
|
-
|
|
26167
|
-
|
|
26168
|
-
|
|
26169
|
-
|
|
26170
|
-
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26174
|
-
|
|
26175
|
-
|
|
26176
|
-
|
|
26177
|
-
|
|
26178
|
-
|
|
26179
|
-
|
|
26180
|
-
|
|
26181
|
-
|
|
26182
|
-
|
|
26183
|
-
|
|
26184
|
-
|
|
26185
|
-
|
|
26271
|
+
if (profile === "full") {
|
|
26272
|
+
const hfPath = resolve5(dir, "hyperframes.json");
|
|
26273
|
+
const hfDefaults = buildHyperframesConfig();
|
|
26274
|
+
if (await pathExists(hfPath)) {
|
|
26275
|
+
const existingRaw = await readFile4(hfPath, "utf-8");
|
|
26276
|
+
const existing = JSON.parse(existingRaw);
|
|
26277
|
+
const mergedConfig = mergeHyperframesConfig(existing, hfDefaults);
|
|
26278
|
+
await writeFile4(hfPath, JSON.stringify(mergedConfig, null, 2) + "\n", "utf-8");
|
|
26279
|
+
merged.push(hfPath);
|
|
26280
|
+
} else {
|
|
26281
|
+
await writeFile4(hfPath, JSON.stringify(hfDefaults, null, 2) + "\n", "utf-8");
|
|
26282
|
+
created.push(hfPath);
|
|
26283
|
+
}
|
|
26284
|
+
const metaPath = resolve5(dir, "meta.json");
|
|
26285
|
+
if (await pathExists(metaPath)) {
|
|
26286
|
+
skipped2.push(metaPath);
|
|
26287
|
+
} else {
|
|
26288
|
+
await writeFile4(metaPath, JSON.stringify(buildHyperframesMeta(name, now), null, 2) + "\n", "utf-8");
|
|
26289
|
+
created.push(metaPath);
|
|
26290
|
+
}
|
|
26291
|
+
const rootPath = resolve5(dir, "index.html");
|
|
26292
|
+
if (await pathExists(rootPath)) {
|
|
26293
|
+
skipped2.push(rootPath);
|
|
26294
|
+
} else {
|
|
26295
|
+
await writeFile4(rootPath, buildEmptyRootHtml({ aspect, duration }), "utf-8");
|
|
26296
|
+
created.push(rootPath);
|
|
26297
|
+
}
|
|
26186
26298
|
}
|
|
26187
26299
|
const vibePath = resolve5(dir, "vibe.project.yaml");
|
|
26188
26300
|
if (await pathExists(vibePath)) {
|
|
@@ -26192,12 +26304,14 @@ async function scaffoldSceneProject(opts) {
|
|
|
26192
26304
|
await writeFile4(vibePath, (0, import_yaml2.stringify)(cfg), "utf-8");
|
|
26193
26305
|
created.push(vibePath);
|
|
26194
26306
|
}
|
|
26195
|
-
|
|
26196
|
-
|
|
26197
|
-
|
|
26198
|
-
|
|
26199
|
-
|
|
26200
|
-
|
|
26307
|
+
if (profile === "agent" || profile === "full") {
|
|
26308
|
+
const claudePath = resolve5(dir, "CLAUDE.md");
|
|
26309
|
+
if (await pathExists(claudePath)) {
|
|
26310
|
+
skipped2.push(claudePath);
|
|
26311
|
+
} else {
|
|
26312
|
+
await writeFile4(claudePath, buildProjectClaudeMd(name), "utf-8");
|
|
26313
|
+
created.push(claudePath);
|
|
26314
|
+
}
|
|
26201
26315
|
}
|
|
26202
26316
|
const designPath = resolve5(dir, "DESIGN.md");
|
|
26203
26317
|
if (await pathExists(designPath)) {
|
|
@@ -26210,6 +26324,13 @@ async function scaffoldSceneProject(opts) {
|
|
|
26210
26324
|
);
|
|
26211
26325
|
created.push(designPath);
|
|
26212
26326
|
}
|
|
26327
|
+
const storyboardPath = resolve5(dir, "STORYBOARD.md");
|
|
26328
|
+
if (await pathExists(storyboardPath)) {
|
|
26329
|
+
skipped2.push(storyboardPath);
|
|
26330
|
+
} else {
|
|
26331
|
+
await writeFile4(storyboardPath, buildStoryboardMd(name, duration), "utf-8");
|
|
26332
|
+
created.push(storyboardPath);
|
|
26333
|
+
}
|
|
26213
26334
|
const gitignorePath = resolve5(dir, ".gitignore");
|
|
26214
26335
|
if (await pathExists(gitignorePath)) {
|
|
26215
26336
|
skipped2.push(gitignorePath);
|
|
@@ -26217,7 +26338,7 @@ async function scaffoldSceneProject(opts) {
|
|
|
26217
26338
|
await writeFile4(gitignorePath, buildSceneGitignore(), "utf-8");
|
|
26218
26339
|
created.push(gitignorePath);
|
|
26219
26340
|
}
|
|
26220
|
-
return { created, skipped: skipped2, merged };
|
|
26341
|
+
return { created, skipped: skipped2, merged, groups: describeSceneScaffold({ dir, profile }) };
|
|
26221
26342
|
}
|
|
26222
26343
|
var import_yaml2, ASPECT_DIMS;
|
|
26223
26344
|
var init_scene_project = __esm({
|
|
@@ -27157,7 +27278,9 @@ function buildAudioMuxFilter(audios) {
|
|
|
27157
27278
|
const inputIdx = i + 1;
|
|
27158
27279
|
const delayMs = Math.max(0, Math.round(a.absoluteStart * 1e3));
|
|
27159
27280
|
const volume = Number.isFinite(a.volume) ? a.volume : 1;
|
|
27160
|
-
const
|
|
27281
|
+
const durationHint = typeof a.durationHint === "number" && Number.isFinite(a.durationHint) ? Math.max(0, a.durationHint) : null;
|
|
27282
|
+
const clipCap = Math.max(0, a.clipDurationCap);
|
|
27283
|
+
const trimSec = durationHint === null ? clipCap : Math.min(durationHint, clipCap);
|
|
27161
27284
|
const label = `a${i}`;
|
|
27162
27285
|
const stage = [
|
|
27163
27286
|
`[${inputIdx}:a]`,
|
|
@@ -27419,6 +27542,57 @@ var init_scene_render = __esm({
|
|
|
27419
27542
|
}
|
|
27420
27543
|
});
|
|
27421
27544
|
|
|
27545
|
+
// src/utils/audio.ts
|
|
27546
|
+
async function getAudioDuration(filePath) {
|
|
27547
|
+
try {
|
|
27548
|
+
return await ffprobeDuration(filePath);
|
|
27549
|
+
} catch (error) {
|
|
27550
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
27551
|
+
throw new Error(`Failed to get audio duration: ${message}`);
|
|
27552
|
+
}
|
|
27553
|
+
}
|
|
27554
|
+
async function getVideoDuration(filePath) {
|
|
27555
|
+
try {
|
|
27556
|
+
return await ffprobeDuration(filePath);
|
|
27557
|
+
} catch (error) {
|
|
27558
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
27559
|
+
throw new Error(`Failed to get video duration: ${message}`);
|
|
27560
|
+
}
|
|
27561
|
+
}
|
|
27562
|
+
async function extendVideoNaturally(videoPath, targetDuration, outputPath) {
|
|
27563
|
+
const videoDuration = await getVideoDuration(videoPath);
|
|
27564
|
+
const ratio = targetDuration / videoDuration;
|
|
27565
|
+
if (ratio <= 1) {
|
|
27566
|
+
const { copyFile: copyFile4 } = await import("node:fs/promises");
|
|
27567
|
+
await copyFile4(videoPath, outputPath);
|
|
27568
|
+
return;
|
|
27569
|
+
}
|
|
27570
|
+
if (ratio <= 1.15) {
|
|
27571
|
+
const slowFactor = (1 / ratio).toFixed(4);
|
|
27572
|
+
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `setpts=${slowFactor}*PTS`, "-an", outputPath]);
|
|
27573
|
+
} else if (ratio <= 1.4) {
|
|
27574
|
+
const slowFactor = (1 / ratio).toFixed(4);
|
|
27575
|
+
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `minterpolate=fps=60:mi_mode=mci,setpts=${slowFactor}*PTS`, "-an", outputPath]);
|
|
27576
|
+
} else {
|
|
27577
|
+
const slowRatio = 0.7;
|
|
27578
|
+
const slowedDuration = videoDuration / slowRatio;
|
|
27579
|
+
const freezeDuration = targetDuration - slowedDuration;
|
|
27580
|
+
if (freezeDuration <= 0) {
|
|
27581
|
+
const slowFactor = (1 / ratio).toFixed(4);
|
|
27582
|
+
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `minterpolate=fps=60:mi_mode=mci,setpts=${slowFactor}*PTS`, "-an", outputPath]);
|
|
27583
|
+
} else {
|
|
27584
|
+
const slowFactor = (1 / slowRatio).toFixed(4);
|
|
27585
|
+
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `setpts=${slowFactor}*PTS,tpad=stop_mode=clone:stop_duration=${freezeDuration.toFixed(2)}`, "-an", outputPath]);
|
|
27586
|
+
}
|
|
27587
|
+
}
|
|
27588
|
+
}
|
|
27589
|
+
var init_audio = __esm({
|
|
27590
|
+
"src/utils/audio.ts"() {
|
|
27591
|
+
"use strict";
|
|
27592
|
+
init_exec_safe();
|
|
27593
|
+
}
|
|
27594
|
+
});
|
|
27595
|
+
|
|
27422
27596
|
// src/commands/_shared/hf-skill-bundle/bundle-content.ts
|
|
27423
27597
|
var SKILL_MD, HOUSE_STYLE_MD, MOTION_PRINCIPLES_MD, TYPOGRAPHY_MD, TRANSITIONS_MD;
|
|
27424
27598
|
var init_bundle_content = __esm({
|
|
@@ -29020,7 +29194,7 @@ async function getComposePrompts(opts) {
|
|
|
29020
29194
|
return baseError(`DESIGN.md not found at ${designPath}. Run \`vibe scene init <dir>\` first.`);
|
|
29021
29195
|
}
|
|
29022
29196
|
if (!existsSync6(storyboardPath)) {
|
|
29023
|
-
return baseError(`STORYBOARD.md not found at ${storyboardPath}. Run \`vibe scene init <dir>\`
|
|
29197
|
+
return baseError(`STORYBOARD.md not found at ${storyboardPath}. Run \`vibe scene init <dir>\` to create a starter, or add STORYBOARD.md with per-beat cues.`);
|
|
29024
29198
|
}
|
|
29025
29199
|
if (!existsSync6(skillPath)) {
|
|
29026
29200
|
warnings.push(
|
|
@@ -29256,7 +29430,10 @@ async function executeSceneBuild(opts) {
|
|
|
29256
29430
|
const mode = resolveSceneBuildMode(opts);
|
|
29257
29431
|
const storyboardPath = join7(projectDir, "STORYBOARD.md");
|
|
29258
29432
|
if (!existsSync8(storyboardPath)) {
|
|
29259
|
-
return failBeforePrimitives(
|
|
29433
|
+
return failBeforePrimitives(
|
|
29434
|
+
`STORYBOARD.md not found at ${storyboardPath}. Run \`vibe scene init <dir>\` to create a starter, or add STORYBOARD.md with per-beat cues.`,
|
|
29435
|
+
startedAt
|
|
29436
|
+
);
|
|
29260
29437
|
}
|
|
29261
29438
|
const storyboardMd = await readFile10(storyboardPath, "utf-8");
|
|
29262
29439
|
const parsed = parseStoryboard(storyboardMd);
|
|
@@ -29336,6 +29513,13 @@ async function executeSceneBuild(opts) {
|
|
|
29336
29513
|
}
|
|
29337
29514
|
composeData = composeResult.data;
|
|
29338
29515
|
}
|
|
29516
|
+
if (!existsSync8(join7(projectDir, "index.html"))) {
|
|
29517
|
+
await scaffoldSceneProject({
|
|
29518
|
+
dir: projectDir,
|
|
29519
|
+
name: projectDir.split(/[\\/]/).filter(Boolean).pop(),
|
|
29520
|
+
profile: "full"
|
|
29521
|
+
});
|
|
29522
|
+
}
|
|
29339
29523
|
await syncRootClipReferences(parsed.beats, projectDir, beatOutcomes);
|
|
29340
29524
|
let outputPath;
|
|
29341
29525
|
let renderResult;
|
|
@@ -29434,6 +29618,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
29434
29618
|
ctx.onProgress({ type: "backdrop-cached", beatId: beat.id, path: rel });
|
|
29435
29619
|
return { status: "cached", path: rel };
|
|
29436
29620
|
}
|
|
29621
|
+
loadSceneBuildEnv(ctx.projectDir);
|
|
29437
29622
|
const apiKey = process.env.OPENAI_API_KEY ?? "";
|
|
29438
29623
|
if (!apiKey) {
|
|
29439
29624
|
const error = "OPENAI_API_KEY not set \u2014 cannot dispatch backdrop";
|
|
@@ -29462,6 +29647,18 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
29462
29647
|
});
|
|
29463
29648
|
return { status: "generated", path: rel };
|
|
29464
29649
|
}
|
|
29650
|
+
function loadSceneBuildEnv(projectDir) {
|
|
29651
|
+
(0, import_dotenv2.config)({ path: join7(projectDir, ".env"), quiet: true });
|
|
29652
|
+
(0, import_dotenv2.config)({ path: resolve12(process.cwd(), ".env"), quiet: true });
|
|
29653
|
+
let dir = process.cwd();
|
|
29654
|
+
while (dir !== dirname4(dir)) {
|
|
29655
|
+
if (existsSync8(join7(dir, "pnpm-workspace.yaml"))) {
|
|
29656
|
+
(0, import_dotenv2.config)({ path: join7(dir, ".env"), quiet: true });
|
|
29657
|
+
return;
|
|
29658
|
+
}
|
|
29659
|
+
dir = dirname4(dir);
|
|
29660
|
+
}
|
|
29661
|
+
}
|
|
29465
29662
|
async function skipped(kind, beatId, reason, ctx) {
|
|
29466
29663
|
ctx.onProgress({ type: `${kind}-skipped`, beatId, reason });
|
|
29467
29664
|
return { status: "skipped" };
|
|
@@ -29492,20 +29689,24 @@ async function syncRootClipReferences(beats, projectDir, outcomes) {
|
|
|
29492
29689
|
const clipLines = [];
|
|
29493
29690
|
const audioLines = [];
|
|
29494
29691
|
for (const beat of beats) {
|
|
29495
|
-
const
|
|
29692
|
+
const outcome = outcomes.find((o) => o.beatId === beat.id);
|
|
29693
|
+
const duration = await resolveBeatDuration({
|
|
29694
|
+
beatDuration: beat.duration,
|
|
29695
|
+
narrationPath: outcome?.narrationPath,
|
|
29696
|
+
projectDir
|
|
29697
|
+
});
|
|
29496
29698
|
const compositionId = `scene-${beat.id}`;
|
|
29497
29699
|
clipLines.push(
|
|
29498
29700
|
` <div class="clip" data-composition-id="${compositionId}" data-composition-src="compositions/${compositionId}.html" data-start="${cursor}" data-duration="${duration}" data-track-index="0"></div>`
|
|
29499
29701
|
);
|
|
29500
|
-
const outcome = outcomes.find((o) => o.beatId === beat.id);
|
|
29501
29702
|
if (outcome?.narrationPath) {
|
|
29502
29703
|
audioLines.push(
|
|
29503
|
-
` <audio src="${outcome.narrationPath}" data-start="${cursor}" data-duration="${duration}" data-track-index="2"></audio>`
|
|
29704
|
+
` <audio id="narration-${beat.id}" src="${outcome.narrationPath}" data-start="${cursor}" data-duration="${duration}" data-track-index="2"></audio>`
|
|
29504
29705
|
);
|
|
29505
29706
|
}
|
|
29506
29707
|
cursor += duration;
|
|
29507
29708
|
}
|
|
29508
|
-
const totalDuration = cursor;
|
|
29709
|
+
const totalDuration = Number(cursor.toFixed(2));
|
|
29509
29710
|
const block = " <!-- vibe-scene-build: clip refs (auto-generated; safe to re-run) -->\n" + clipLines.join("\n") + (audioLines.length > 0 ? "\n" + audioLines.join("\n") : "") + "\n <!-- /vibe-scene-build -->";
|
|
29510
29711
|
let next;
|
|
29511
29712
|
const markerRe = /\n? *<!-- vibe-scene-build: clip refs.*?<!-- \/vibe-scene-build -->/s;
|
|
@@ -29523,77 +29724,40 @@ ${block}
|
|
|
29523
29724
|
}
|
|
29524
29725
|
}
|
|
29525
29726
|
next = next.replace(
|
|
29526
|
-
/(id="root"[\s\S]*?data-duration=")(
|
|
29727
|
+
/(id="root"[\s\S]*?data-duration=")([^"]*)(")/,
|
|
29527
29728
|
`$1${totalDuration}$3`
|
|
29528
29729
|
);
|
|
29529
29730
|
if (next !== html) {
|
|
29530
29731
|
await writeFile7(rootPath, next, "utf-8");
|
|
29531
29732
|
}
|
|
29532
29733
|
}
|
|
29734
|
+
async function resolveBeatDuration(opts) {
|
|
29735
|
+
const storyboardMin = opts.beatDuration ?? 3;
|
|
29736
|
+
if (!opts.narrationPath) return Number(storyboardMin.toFixed(2));
|
|
29737
|
+
try {
|
|
29738
|
+
const audioDuration = await getAudioDuration(join7(opts.projectDir, opts.narrationPath));
|
|
29739
|
+
return Number(Math.max(storyboardMin, audioDuration + 0.5).toFixed(2));
|
|
29740
|
+
} catch {
|
|
29741
|
+
return Number(storyboardMin.toFixed(2));
|
|
29742
|
+
}
|
|
29743
|
+
}
|
|
29744
|
+
var import_dotenv2;
|
|
29533
29745
|
var init_scene_build = __esm({
|
|
29534
29746
|
"src/commands/_shared/scene-build.ts"() {
|
|
29535
29747
|
"use strict";
|
|
29748
|
+
import_dotenv2 = __toESM(require_main(), 1);
|
|
29536
29749
|
init_dist2();
|
|
29750
|
+
init_audio();
|
|
29537
29751
|
init_compose_scenes_skills();
|
|
29538
29752
|
init_compose_prompts();
|
|
29539
29753
|
init_agent_host_detect();
|
|
29540
29754
|
init_scene_render();
|
|
29541
29755
|
init_storyboard_parse();
|
|
29756
|
+
init_scene_project();
|
|
29542
29757
|
init_tts_resolve();
|
|
29543
29758
|
}
|
|
29544
29759
|
});
|
|
29545
29760
|
|
|
29546
|
-
// src/utils/audio.ts
|
|
29547
|
-
async function getAudioDuration(filePath) {
|
|
29548
|
-
try {
|
|
29549
|
-
return await ffprobeDuration(filePath);
|
|
29550
|
-
} catch (error) {
|
|
29551
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
29552
|
-
throw new Error(`Failed to get audio duration: ${message}`);
|
|
29553
|
-
}
|
|
29554
|
-
}
|
|
29555
|
-
async function getVideoDuration(filePath) {
|
|
29556
|
-
try {
|
|
29557
|
-
return await ffprobeDuration(filePath);
|
|
29558
|
-
} catch (error) {
|
|
29559
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
29560
|
-
throw new Error(`Failed to get video duration: ${message}`);
|
|
29561
|
-
}
|
|
29562
|
-
}
|
|
29563
|
-
async function extendVideoNaturally(videoPath, targetDuration, outputPath) {
|
|
29564
|
-
const videoDuration = await getVideoDuration(videoPath);
|
|
29565
|
-
const ratio = targetDuration / videoDuration;
|
|
29566
|
-
if (ratio <= 1) {
|
|
29567
|
-
const { copyFile: copyFile4 } = await import("node:fs/promises");
|
|
29568
|
-
await copyFile4(videoPath, outputPath);
|
|
29569
|
-
return;
|
|
29570
|
-
}
|
|
29571
|
-
if (ratio <= 1.15) {
|
|
29572
|
-
const slowFactor = (1 / ratio).toFixed(4);
|
|
29573
|
-
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `setpts=${slowFactor}*PTS`, "-an", outputPath]);
|
|
29574
|
-
} else if (ratio <= 1.4) {
|
|
29575
|
-
const slowFactor = (1 / ratio).toFixed(4);
|
|
29576
|
-
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `minterpolate=fps=60:mi_mode=mci,setpts=${slowFactor}*PTS`, "-an", outputPath]);
|
|
29577
|
-
} else {
|
|
29578
|
-
const slowRatio = 0.7;
|
|
29579
|
-
const slowedDuration = videoDuration / slowRatio;
|
|
29580
|
-
const freezeDuration = targetDuration - slowedDuration;
|
|
29581
|
-
if (freezeDuration <= 0) {
|
|
29582
|
-
const slowFactor = (1 / ratio).toFixed(4);
|
|
29583
|
-
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `minterpolate=fps=60:mi_mode=mci,setpts=${slowFactor}*PTS`, "-an", outputPath]);
|
|
29584
|
-
} else {
|
|
29585
|
-
const slowFactor = (1 / slowRatio).toFixed(4);
|
|
29586
|
-
await execSafe("ffmpeg", ["-y", "-i", videoPath, "-filter:v", `setpts=${slowFactor}*PTS,tpad=stop_mode=clone:stop_duration=${freezeDuration.toFixed(2)}`, "-an", outputPath]);
|
|
29587
|
-
}
|
|
29588
|
-
}
|
|
29589
|
-
}
|
|
29590
|
-
var init_audio = __esm({
|
|
29591
|
-
"src/utils/audio.ts"() {
|
|
29592
|
-
"use strict";
|
|
29593
|
-
init_exec_safe();
|
|
29594
|
-
}
|
|
29595
|
-
});
|
|
29596
|
-
|
|
29597
29761
|
// src/commands/_shared/install-skill.ts
|
|
29598
29762
|
import { mkdir as mkdir6, writeFile as writeFile8 } from "node:fs/promises";
|
|
29599
29763
|
import { existsSync as existsSync9 } from "node:fs";
|
|
@@ -29730,6 +29894,30 @@ function validateVisualStyle(value) {
|
|
|
29730
29894
|
}
|
|
29731
29895
|
return found;
|
|
29732
29896
|
}
|
|
29897
|
+
function formatSceneInitProfile(profile) {
|
|
29898
|
+
if (profile === "minimal") return "authoring files only; build will add render scaffold when needed";
|
|
29899
|
+
if (profile === "agent") return "authoring files plus local composition rules for host agents";
|
|
29900
|
+
return "complete authoring, agent, and render scaffold";
|
|
29901
|
+
}
|
|
29902
|
+
function printSceneInitDryRun(opts) {
|
|
29903
|
+
console.log();
|
|
29904
|
+
console.log(source_default.bold.cyan("VibeFrame Scene Init - dry run"));
|
|
29905
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
29906
|
+
console.log(` Project: ${source_default.bold(opts.dir)}`);
|
|
29907
|
+
console.log(` Name: ${source_default.bold(opts.name)}`);
|
|
29908
|
+
console.log(` Profile: ${source_default.bold(opts.profile)} ${source_default.dim(formatSceneInitProfile(opts.profile))}`);
|
|
29909
|
+
console.log(` Aspect: ${opts.aspect}`);
|
|
29910
|
+
console.log(` Duration: ${opts.duration}s`);
|
|
29911
|
+
console.log(` Visual style: ${opts.visualStyleName ?? "none"}`);
|
|
29912
|
+
console.log();
|
|
29913
|
+
console.log(source_default.bold.cyan("Files that would be prepared"));
|
|
29914
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
29915
|
+
for (const file of opts.groups.authoring) console.log(` authoring ${file}`);
|
|
29916
|
+
for (const file of opts.groups.agent) console.log(` agent ${file}`);
|
|
29917
|
+
for (const file of opts.groups.render) console.log(` render ${file}`);
|
|
29918
|
+
console.log();
|
|
29919
|
+
console.log(source_default.dim("No files were written."));
|
|
29920
|
+
}
|
|
29733
29921
|
async function pathExists2(p) {
|
|
29734
29922
|
try {
|
|
29735
29923
|
await access4(p);
|
|
@@ -30041,7 +30229,7 @@ function formatPrimitiveStatus(status, path2) {
|
|
|
30041
30229
|
return status;
|
|
30042
30230
|
}
|
|
30043
30231
|
}
|
|
30044
|
-
var import_yaml5, VALID_ASPECTS2, sceneCommand, VALID_INSTALL_SKILL_HOSTS, VALID_FPS, VALID_QUALITIES, VALID_FORMATS;
|
|
30232
|
+
var import_yaml5, VALID_ASPECTS2, VALID_SCENE_INIT_PROFILES, sceneCommand, VALID_INSTALL_SKILL_HOSTS, VALID_FPS, VALID_QUALITIES, VALID_FORMATS;
|
|
30045
30233
|
var init_scene = __esm({
|
|
30046
30234
|
"src/commands/scene.ts"() {
|
|
30047
30235
|
"use strict";
|
|
@@ -30064,30 +30252,38 @@ var init_scene = __esm({
|
|
|
30064
30252
|
init_install_skill();
|
|
30065
30253
|
init_compose_prompts();
|
|
30066
30254
|
VALID_ASPECTS2 = ["16:9", "9:16", "1:1", "4:5"];
|
|
30067
|
-
|
|
30255
|
+
VALID_SCENE_INIT_PROFILES = ["minimal", "agent", "full"];
|
|
30256
|
+
sceneCommand = new Command("scene").description("Lower-level scene authoring (add, lint, styles). For project flow use `vibe init` / `vibe build` / `vibe render`.").addHelpText("after", `
|
|
30068
30257
|
Examples:
|
|
30069
|
-
$ vibe scene init my-video # Scaffold a new project
|
|
30070
|
-
$ vibe scene init my-video -r 9:16 -d 30 # Vertical 30s project
|
|
30071
30258
|
$ vibe scene add intro --style announcement \\
|
|
30072
30259
|
--headline "Welcome to VibeFrame" # Headline-only scene
|
|
30073
30260
|
$ vibe scene add overview --narration "VibeFrame turns scripts into video." \\
|
|
30074
30261
|
--visuals "studio desk, soft lighting" # AI narration + image
|
|
30075
|
-
$ vibe scene lint # Validate every scene against
|
|
30262
|
+
$ vibe scene lint # Validate every scene against composition rules
|
|
30076
30263
|
$ vibe scene lint --fix # Auto-fix mechanical issues (e.g. missing class="clip")
|
|
30077
30264
|
$ vibe scene lint --json # Structured output for agent loops
|
|
30078
|
-
$ vibe scene
|
|
30079
|
-
$ vibe scene render -o demo.mp4 --quality high # Custom output path + quality
|
|
30080
|
-
$ vibe scene render --fps 60 --format webm # 60fps WebM render
|
|
30265
|
+
$ vibe scene styles # Browse seed visual styles for DESIGN.md
|
|
30081
30266
|
|
|
30082
|
-
|
|
30267
|
+
For the project flow (init / build / render), use the top-level commands.
|
|
30268
|
+
The \`scene init\`, \`scene build\`, and \`scene render\` legacy aliases
|
|
30269
|
+
are still callable but hidden from this help \u2014 they will be removed in v1.0.
|
|
30083
30270
|
Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
30084
|
-
sceneCommand.command("init").description("Scaffold a new scene project (or safely augment an existing
|
|
30271
|
+
sceneCommand.command("init", { hidden: true }).description("Scaffold a new scene project (or safely augment an existing project) [legacy \u2014 prefer `vibe init`]").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("--profile <profile>", "Scene profile: minimal (storyboard/design only), agent (recommended), full (render scaffold upfront)", "agent").option("--dry-run", "Preview parameters without writing files").action(async (dir, options) => {
|
|
30085
30272
|
const startedAt = Date.now();
|
|
30086
30273
|
const aspect = validateAspect(options.ratio);
|
|
30087
30274
|
const duration = validateDuration(options.duration);
|
|
30088
30275
|
const name = options.name ?? basename4(dir.replace(/\/+$/, ""));
|
|
30089
30276
|
const visualStyle = options.visualStyle ? validateVisualStyle(options.visualStyle) : void 0;
|
|
30277
|
+
const profile = String(options.profile ?? "agent");
|
|
30278
|
+
if (!isSceneScaffoldProfile(profile)) {
|
|
30279
|
+
exitWithError(usageError(`Invalid --profile: ${profile}`, `Must be one of: ${VALID_SCENE_INIT_PROFILES.join(", ")}`));
|
|
30280
|
+
}
|
|
30281
|
+
const groups = describeSceneScaffold({ dir, profile });
|
|
30090
30282
|
if (options.dryRun) {
|
|
30283
|
+
if (!isJsonMode() && !isQuietMode()) {
|
|
30284
|
+
printSceneInitDryRun({ dir, name, aspect, duration, visualStyleName: visualStyle?.name ?? null, profile, groups });
|
|
30285
|
+
return;
|
|
30286
|
+
}
|
|
30091
30287
|
outputSuccess({
|
|
30092
30288
|
command: "scene init",
|
|
30093
30289
|
startedAt,
|
|
@@ -30098,23 +30294,25 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30098
30294
|
name,
|
|
30099
30295
|
aspect,
|
|
30100
30296
|
duration,
|
|
30101
|
-
visualStyle: visualStyle?.name ?? null
|
|
30102
|
-
|
|
30297
|
+
visualStyle: visualStyle?.name ?? null,
|
|
30298
|
+
profile
|
|
30299
|
+
},
|
|
30300
|
+
groups
|
|
30103
30301
|
}
|
|
30104
30302
|
});
|
|
30105
30303
|
return;
|
|
30106
30304
|
}
|
|
30107
|
-
const spinner2 = isJsonMode() ? null : ora(`Scaffolding scene project at ${dir}...`).start();
|
|
30305
|
+
const spinner2 = isJsonMode() || isQuietMode() ? null : ora(`Scaffolding scene project at ${dir}...`).start();
|
|
30108
30306
|
try {
|
|
30109
|
-
const result = await scaffoldSceneProject({ dir, name, aspect, duration, visualStyle });
|
|
30307
|
+
const result = await scaffoldSceneProject({ dir, name, aspect, duration, visualStyle, profile });
|
|
30110
30308
|
const detectedIds = detectedAgentHosts().map((h) => h.id);
|
|
30111
30309
|
const skillHosts = deriveInstallHosts(detectedIds);
|
|
30112
30310
|
const projectAbs = resolve14(dir);
|
|
30113
|
-
const skillResult = await installHyperframesSkill({
|
|
30311
|
+
const skillResult = profile === "agent" || profile === "full" ? await installHyperframesSkill({
|
|
30114
30312
|
projectDir: projectAbs,
|
|
30115
30313
|
hosts: skillHosts
|
|
30116
|
-
});
|
|
30117
|
-
if (isJsonMode()) {
|
|
30314
|
+
}) : { success: true, files: [], bundleVersion: "not-installed" };
|
|
30315
|
+
if (isJsonMode() || isQuietMode()) {
|
|
30118
30316
|
outputSuccess({
|
|
30119
30317
|
command: "scene init",
|
|
30120
30318
|
startedAt,
|
|
@@ -30124,16 +30322,27 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30124
30322
|
aspect,
|
|
30125
30323
|
duration,
|
|
30126
30324
|
visualStyle: visualStyle?.name ?? null,
|
|
30325
|
+
profile,
|
|
30127
30326
|
created: result.created,
|
|
30128
30327
|
merged: result.merged,
|
|
30129
30328
|
skipped: result.skipped,
|
|
30329
|
+
groups: result.groups,
|
|
30130
30330
|
skillFiles: skillResult.files,
|
|
30131
30331
|
skillBundleVersion: skillResult.bundleVersion
|
|
30132
30332
|
}
|
|
30133
30333
|
});
|
|
30134
30334
|
return;
|
|
30135
30335
|
}
|
|
30136
|
-
spinner2?.succeed(source_default.green(`
|
|
30336
|
+
spinner2?.succeed(source_default.green(`Video project ready: ${dir}`));
|
|
30337
|
+
console.log();
|
|
30338
|
+
console.log(source_default.bold.cyan("Edit first"));
|
|
30339
|
+
console.log(source_default.dim("\u2500".repeat(60)));
|
|
30340
|
+
console.log(` ${source_default.bold("STORYBOARD.md")} ${source_default.dim("# beats: narration, backdrop, minimum duration")}`);
|
|
30341
|
+
console.log(` ${source_default.bold("DESIGN.md")} ${source_default.dim("# palette, typography, motion rules")}`);
|
|
30342
|
+
console.log();
|
|
30343
|
+
console.log(source_default.bold.cyan("Profile"));
|
|
30344
|
+
console.log(source_default.dim("\u2500".repeat(60)));
|
|
30345
|
+
console.log(` ${source_default.bold(profile)} ${source_default.dim(formatSceneInitProfile(profile))}`);
|
|
30137
30346
|
console.log();
|
|
30138
30347
|
console.log(source_default.bold.cyan("Files"));
|
|
30139
30348
|
console.log(source_default.dim("\u2500".repeat(60)));
|
|
@@ -30144,7 +30353,7 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30144
30353
|
const skillSkipped = skillResult.files.filter((f) => f.status === "skipped-exists");
|
|
30145
30354
|
if (skillWritten.length + skillSkipped.length > 0) {
|
|
30146
30355
|
console.log();
|
|
30147
|
-
console.log(source_default.bold.cyan("
|
|
30356
|
+
console.log(source_default.bold.cyan("Composition rules"));
|
|
30148
30357
|
console.log(source_default.dim("\u2500".repeat(60)));
|
|
30149
30358
|
for (const f of skillWritten) console.log(source_default.green(" +"), f.path);
|
|
30150
30359
|
for (const f of skillSkipped) console.log(source_default.dim(" \xB7"), f.path, source_default.dim("(kept existing)"));
|
|
@@ -30158,10 +30367,14 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30158
30367
|
} else {
|
|
30159
30368
|
console.log(` ${source_default.cyan("vibe scene styles")} ${source_default.dim("# pick a named style for DESIGN.md")}`);
|
|
30160
30369
|
}
|
|
30161
|
-
|
|
30370
|
+
if (profile === "agent" || profile === "full") {
|
|
30371
|
+
console.log(` ${source_default.dim("Your agent now has composition rules in")} ${source_default.cyan("SKILL.md")} ${source_default.dim("\u2014 ask it to author scene HTML directly.")}`);
|
|
30372
|
+
} else {
|
|
30373
|
+
console.log(` ${source_default.cyan("vibe scene install-skill")} ${source_default.dim("# add agent authoring rules later")}`);
|
|
30374
|
+
}
|
|
30162
30375
|
console.log(` ${source_default.cyan("vibe scene add")} <name> ${source_default.dim("# fallback: 5-preset emit (no agent)")}`);
|
|
30163
|
-
console.log(` ${source_default.cyan("vibe
|
|
30164
|
-
console.log(` ${source_default.cyan("vibe
|
|
30376
|
+
console.log(` ${source_default.cyan("vibe build")} ${source_default.dim("# build STORYBOARD.md into scenes/assets")}`);
|
|
30377
|
+
console.log(` ${source_default.cyan("vibe render")} ${source_default.dim("# render to video")}`);
|
|
30165
30378
|
} catch (error) {
|
|
30166
30379
|
spinner2?.fail("Failed to scaffold scene project");
|
|
30167
30380
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -30449,7 +30662,7 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30449
30662
|
exitWithError(generalError(msg));
|
|
30450
30663
|
}
|
|
30451
30664
|
});
|
|
30452
|
-
sceneCommand.command("lint").description("Validate scene HTML against
|
|
30665
|
+
sceneCommand.command("lint").description("Validate scene HTML against composition 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 (root, options) => {
|
|
30453
30666
|
const startedAt = Date.now();
|
|
30454
30667
|
const projectDir = resolve14(options.project);
|
|
30455
30668
|
if (!await rootExists(projectDir, root)) {
|
|
@@ -30512,7 +30725,7 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30512
30725
|
VALID_FPS = [24, 30, 60];
|
|
30513
30726
|
VALID_QUALITIES = ["draft", "standard", "high"];
|
|
30514
30727
|
VALID_FORMATS = ["mp4", "webm", "mov"];
|
|
30515
|
-
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 (root, options) => {
|
|
30728
|
+
sceneCommand.command("render", { hidden: true }).description("Render a scene project to MP4/WebM/MOV via the Hyperframes producer (requires Chrome) [legacy \u2014 prefer `vibe render`]").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 (root, options) => {
|
|
30516
30729
|
const startedAt = Date.now();
|
|
30517
30730
|
const fps = validateFps(options.fps);
|
|
30518
30731
|
const quality = validateQuality(options.quality);
|
|
@@ -30588,7 +30801,7 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30588
30801
|
}
|
|
30589
30802
|
}
|
|
30590
30803
|
});
|
|
30591
|
-
sceneCommand.command("build").description("One-shot: read STORYBOARD.md cues, dispatch TTS + image-gen per beat, compose, render to MP4
|
|
30804
|
+
sceneCommand.command("build", { hidden: true }).description("One-shot: read STORYBOARD.md cues, dispatch TTS + image-gen per beat, compose, render to MP4 [legacy \u2014 prefer `vibe build`]").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) => {
|
|
30592
30805
|
const startedAt = Date.now();
|
|
30593
30806
|
const projectDir = resolve14(projectDirArg);
|
|
30594
30807
|
if (options.dryRun) {
|
|
@@ -30705,7 +30918,7 @@ Run 'vibe schema scene.<command>' for structured parameter info.`);
|
|
|
30705
30918
|
}
|
|
30706
30919
|
}
|
|
30707
30920
|
console.log();
|
|
30708
|
-
console.log(source_default.dim("Once you've authored each beat's HTML, re-run `vibe
|
|
30921
|
+
console.log(source_default.dim("Once you've authored each beat's HTML, re-run `vibe build` to lint + render."));
|
|
30709
30922
|
console.log(source_default.dim("Or pass `--mode batch` to use the internal LLM compose path instead."));
|
|
30710
30923
|
return;
|
|
30711
30924
|
}
|
|
@@ -32463,16 +32676,16 @@ async function prompt2(question) {
|
|
|
32463
32676
|
input,
|
|
32464
32677
|
output: process.stdout
|
|
32465
32678
|
});
|
|
32466
|
-
return new Promise((
|
|
32679
|
+
return new Promise((resolve64) => {
|
|
32467
32680
|
rl.question(question, (answer) => {
|
|
32468
32681
|
rl.close();
|
|
32469
|
-
|
|
32682
|
+
resolve64(answer);
|
|
32470
32683
|
});
|
|
32471
32684
|
});
|
|
32472
32685
|
}
|
|
32473
32686
|
async function promptHidden(question) {
|
|
32474
32687
|
const input = getTTYInputStream();
|
|
32475
|
-
return new Promise((
|
|
32688
|
+
return new Promise((resolve64) => {
|
|
32476
32689
|
process.stdout.write(question);
|
|
32477
32690
|
let value = "";
|
|
32478
32691
|
if (typeof input.setRawMode === "function") {
|
|
@@ -32484,7 +32697,7 @@ async function promptHidden(question) {
|
|
|
32484
32697
|
input.setRawMode(false);
|
|
32485
32698
|
input.removeListener("data", onData);
|
|
32486
32699
|
process.stdout.write("\n");
|
|
32487
|
-
|
|
32700
|
+
resolve64(value);
|
|
32488
32701
|
} else if (char === "") {
|
|
32489
32702
|
input.setRawMode(false);
|
|
32490
32703
|
process.stdout.write("\n");
|
|
@@ -32504,7 +32717,7 @@ async function promptHidden(question) {
|
|
|
32504
32717
|
const rl = createInterface2({ input, output: process.stdout });
|
|
32505
32718
|
rl.question("", (answer) => {
|
|
32506
32719
|
rl.close();
|
|
32507
|
-
|
|
32720
|
+
resolve64(answer);
|
|
32508
32721
|
});
|
|
32509
32722
|
}
|
|
32510
32723
|
});
|
|
@@ -32512,7 +32725,7 @@ async function promptHidden(question) {
|
|
|
32512
32725
|
async function promptSelect(_question, options, defaultIndex = 0) {
|
|
32513
32726
|
const input = getTTYInputStream();
|
|
32514
32727
|
if (typeof input.setRawMode === "function") {
|
|
32515
|
-
return new Promise((
|
|
32728
|
+
return new Promise((resolve64) => {
|
|
32516
32729
|
let selected = defaultIndex;
|
|
32517
32730
|
const render = () => {
|
|
32518
32731
|
if (renderCount > 0) {
|
|
@@ -32536,7 +32749,7 @@ async function promptSelect(_question, options, defaultIndex = 0) {
|
|
|
32536
32749
|
input.setRawMode(false);
|
|
32537
32750
|
input.removeListener("data", onData);
|
|
32538
32751
|
process.stdout.write("\n");
|
|
32539
|
-
|
|
32752
|
+
resolve64(selected);
|
|
32540
32753
|
} else if (char === "") {
|
|
32541
32754
|
input.setRawMode(false);
|
|
32542
32755
|
process.stdout.write("\n");
|
|
@@ -32553,7 +32766,7 @@ async function promptSelect(_question, options, defaultIndex = 0) {
|
|
|
32553
32766
|
input.removeListener("data", onData);
|
|
32554
32767
|
render();
|
|
32555
32768
|
process.stdout.write("\n");
|
|
32556
|
-
|
|
32769
|
+
resolve64(selected);
|
|
32557
32770
|
}
|
|
32558
32771
|
};
|
|
32559
32772
|
input.on("data", onData);
|
|
@@ -35343,7 +35556,7 @@ var init_dist3 = __esm({
|
|
|
35343
35556
|
import { writeFile as writeFile23, unlink as unlink2, rename as rename2 } from "node:fs/promises";
|
|
35344
35557
|
import { resolve as resolve27, basename as basename7 } from "node:path";
|
|
35345
35558
|
function sleep(ms) {
|
|
35346
|
-
return new Promise((
|
|
35559
|
+
return new Promise((resolve64) => setTimeout(resolve64, ms));
|
|
35347
35560
|
}
|
|
35348
35561
|
async function uploadToImgbb(imageBuffer, apiKey) {
|
|
35349
35562
|
try {
|
|
@@ -36076,9 +36289,14 @@ var init_ai_script_pipeline = __esm({
|
|
|
36076
36289
|
import { resolve as resolve29 } from "node:path";
|
|
36077
36290
|
import { readFile as readFile17, writeFile as writeFile25 } from "node:fs/promises";
|
|
36078
36291
|
function registerVideoCommand(parent) {
|
|
36079
|
-
parent.command("video").alias("vid").description("Generate video using AI (Kling, Runway,
|
|
36292
|
+
parent.command("video").alias("vid").description("Generate video using AI (Seedance, Grok, Kling, Runway, or Veo)").argument("[prompt]", "Text prompt describing the video (interactive if omitted)").option("-p, --provider <provider>", "Provider: seedance (ByteDance Seedance 2.0 via fal.ai), grok, kling, runway, veo. `fal` is a backwards-compatible alias for seedance.").option("-k, --api-key <key>", "API key (or set FAL_KEY / XAI_API_KEY / RUNWAY_API_SECRET / KLING_API_KEY / GOOGLE_API_KEY env)").option("-o, --output <path>", "Output file path (downloads video)").option("-i, --image <path>", "Reference image for image-to-video").option(
|
|
36293
|
+
"-d, --duration <sec>",
|
|
36294
|
+
"Duration in seconds. Seedance accepts 4-15 (`fal` alias supported); Kling accepts 5 or 10; Veo maps to 6 or 8.",
|
|
36295
|
+
"5"
|
|
36296
|
+
).option("-r, --ratio <ratio>", "Aspect ratio: 16:9, 9:16, or 1:1 (auto-detected from image if omitted)").option("-s, --seed <number>", "Random seed for reproducibility (Runway only)").option("-m, --mode <mode>", "Generation mode: std or pro (Kling only)", "std").option("--seedance-model <model>", "Seedance variant: quality or fast (fal.ai only)", "quality").option("-n, --negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 720p, 1080p, 4k (Veo only)").option("--last-frame <path>", "Last frame image for frame interpolation (Veo only)").option("--ref-images <paths...>", "Reference images for character consistency (Veo 3.1 only, max 3)").option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast (default: 3.1-fast)", "3.1-fast").option("--runway-model <model>", "Runway model: gen4.5 (default, text+image-to-video), gen4_turbo (image-to-video only)", "gen4.5").option("--no-wait", "Start generation and return task ID without waiting").option("--dry-run", "Preview parameters without executing").addHelpText("after", `
|
|
36080
36297
|
Examples:
|
|
36081
|
-
$ vibe generate video "dancing cat" -o cat.mp4 #
|
|
36298
|
+
$ vibe generate video "dancing cat" -o cat.mp4 # Seedance when FAL_KEY is set
|
|
36299
|
+
$ vibe gen vid "cinematic city timelapse" -o city.mp4 -p seedance # Seedance via fal.ai
|
|
36082
36300
|
$ vibe gen vid "city timelapse" -o city.mp4 -p kling # Kling
|
|
36083
36301
|
$ vibe gen vid "epic scene" -i frame.png -o out.mp4 -p runway # Image-to-video
|
|
36084
36302
|
$ vibe gen vid "ocean waves" -o waves.mp4 -p veo --resolution 1080p # Veo
|
|
@@ -36104,12 +36322,13 @@ Examples:
|
|
|
36104
36322
|
if (options.output) {
|
|
36105
36323
|
validateOutputPath(options.output);
|
|
36106
36324
|
}
|
|
36107
|
-
const validProviders = ["runway", "kling", "veo", "grok", "fal"];
|
|
36325
|
+
const validProviders = ["runway", "kling", "veo", "grok", "seedance", "fal"];
|
|
36108
36326
|
const videoEnvMap = {
|
|
36109
36327
|
grok: "XAI_API_KEY",
|
|
36110
36328
|
veo: "GOOGLE_API_KEY",
|
|
36111
36329
|
kling: "KLING_API_KEY",
|
|
36112
36330
|
runway: "RUNWAY_API_SECRET",
|
|
36331
|
+
seedance: "FAL_KEY",
|
|
36113
36332
|
fal: "FAL_KEY"
|
|
36114
36333
|
};
|
|
36115
36334
|
let provider;
|
|
@@ -36119,7 +36338,7 @@ Examples:
|
|
|
36119
36338
|
exitWithError(
|
|
36120
36339
|
usageError(
|
|
36121
36340
|
`Invalid provider: ${provider}`,
|
|
36122
|
-
|
|
36341
|
+
"Available providers: seedance, grok, kling, runway, veo. `fal` is a backwards-compatible alias for seedance."
|
|
36123
36342
|
)
|
|
36124
36343
|
);
|
|
36125
36344
|
}
|
|
@@ -36182,14 +36401,15 @@ Examples:
|
|
|
36182
36401
|
data: {
|
|
36183
36402
|
params: {
|
|
36184
36403
|
prompt: prompt3,
|
|
36185
|
-
provider,
|
|
36404
|
+
provider: provider === "fal" ? "seedance" : provider,
|
|
36186
36405
|
duration: options.duration,
|
|
36187
36406
|
ratio: options.ratio,
|
|
36188
36407
|
image: options.image,
|
|
36189
36408
|
mode: options.mode,
|
|
36190
36409
|
negative: options.negative,
|
|
36191
36410
|
resolution: options.resolution,
|
|
36192
|
-
veoModel: options.veoModel
|
|
36411
|
+
veoModel: options.veoModel,
|
|
36412
|
+
seedanceModel: options.seedanceModel
|
|
36193
36413
|
}
|
|
36194
36414
|
}
|
|
36195
36415
|
});
|
|
@@ -36200,6 +36420,7 @@ Examples:
|
|
|
36200
36420
|
kling: "KLING_API_KEY",
|
|
36201
36421
|
veo: "GOOGLE_API_KEY",
|
|
36202
36422
|
grok: "XAI_API_KEY",
|
|
36423
|
+
seedance: "FAL_KEY",
|
|
36203
36424
|
fal: "FAL_KEY"
|
|
36204
36425
|
};
|
|
36205
36426
|
const providerNameMap = {
|
|
@@ -36207,7 +36428,8 @@ Examples:
|
|
|
36207
36428
|
kling: "Kling",
|
|
36208
36429
|
veo: "Veo",
|
|
36209
36430
|
grok: "Grok",
|
|
36210
|
-
|
|
36431
|
+
seedance: "Seedance 2.0 via fal.ai",
|
|
36432
|
+
fal: "Seedance 2.0 via fal.ai"
|
|
36211
36433
|
};
|
|
36212
36434
|
const envKey = envKeyMap[provider];
|
|
36213
36435
|
const providerName = providerNameMap[provider];
|
|
@@ -36426,15 +36648,15 @@ Examples:
|
|
|
36426
36648
|
},
|
|
36427
36649
|
3e5
|
|
36428
36650
|
);
|
|
36429
|
-
} else if (provider === "fal") {
|
|
36651
|
+
} else if (provider === "fal" || provider === "seedance") {
|
|
36430
36652
|
const fal = new FalProvider();
|
|
36431
36653
|
await fal.initialize({ apiKey });
|
|
36432
36654
|
let falImage = referenceImage;
|
|
36433
36655
|
if (falImage && falImage.startsWith("data:")) {
|
|
36434
|
-
spinner2.text = "Uploading image to ImgBB for
|
|
36656
|
+
spinner2.text = "Uploading image to ImgBB for Seedance...";
|
|
36435
36657
|
const imgbbKey = await getApiKeyFromConfig("imgbb") || process.env.IMGBB_API_KEY;
|
|
36436
36658
|
if (!imgbbKey) {
|
|
36437
|
-
spinner2.fail("ImgBB API key required for
|
|
36659
|
+
spinner2.fail("ImgBB API key required for Seedance image-to-video");
|
|
36438
36660
|
exitWithError(authError("IMGBB_API_KEY", "ImgBB"));
|
|
36439
36661
|
}
|
|
36440
36662
|
const base64Data = falImage.split(",")[1];
|
|
@@ -36446,8 +36668,9 @@ Examples:
|
|
|
36446
36668
|
}
|
|
36447
36669
|
falImage = uploadResult.url;
|
|
36448
36670
|
}
|
|
36449
|
-
spinner2.text = "Generating video with Seedance 2.0 (this may take 1-3 minutes)...";
|
|
36450
|
-
const
|
|
36671
|
+
spinner2.text = "Generating video with fal.ai Seedance 2.0 (this may take 1-3 minutes)...";
|
|
36672
|
+
const seedanceModel = String(options.seedanceModel ?? "quality").toLowerCase();
|
|
36673
|
+
const falModel = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
|
|
36451
36674
|
result = await fal.generateVideo(prompt3, {
|
|
36452
36675
|
prompt: prompt3,
|
|
36453
36676
|
referenceImage: falImage,
|
|
@@ -36572,7 +36795,8 @@ var init_generate = __esm({
|
|
|
36572
36795
|
Examples:
|
|
36573
36796
|
$ vibe generate image "a sunset over the ocean" -o sunset.png
|
|
36574
36797
|
$ vibe generate image "logo design" -o logo.png -p openai
|
|
36575
|
-
$ vibe generate video "dancing cat" -o cat.mp4 #
|
|
36798
|
+
$ vibe generate video "dancing cat" -o cat.mp4 # Seedance when FAL_KEY is set
|
|
36799
|
+
$ vibe generate video "city timelapse" -o city.mp4 -p seedance # Seedance via fal.ai
|
|
36576
36800
|
$ vibe generate video "city timelapse" -o city.mp4 -p kling # Kling
|
|
36577
36801
|
$ vibe generate video "epic scene" -i frame.png -o out.mp4 -p runway # Image-to-video
|
|
36578
36802
|
$ vibe generate speech "Hello world" -o hello.mp3
|
|
@@ -36582,7 +36806,8 @@ Examples:
|
|
|
36582
36806
|
API Keys (per provider):
|
|
36583
36807
|
GOOGLE_API_KEY Image (default), Veo video
|
|
36584
36808
|
OPENAI_API_KEY Image (-p openai)
|
|
36585
|
-
|
|
36809
|
+
FAL_KEY Seedance video (-p seedance, default video)
|
|
36810
|
+
XAI_API_KEY Grok image/video
|
|
36586
36811
|
KLING_API_KEY Kling video (-p kling)
|
|
36587
36812
|
RUNWAY_API_SECRET Runway video (-p runway)
|
|
36588
36813
|
ELEVENLABS_API_KEY Speech, sound effects, music
|
|
@@ -51922,7 +52147,7 @@ function buildFFmpegArgs(clips, sources, presetSettings, outputPath, options, so
|
|
|
51922
52147
|
return args;
|
|
51923
52148
|
}
|
|
51924
52149
|
function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
51925
|
-
return new Promise((
|
|
52150
|
+
return new Promise((resolve64, reject) => {
|
|
51926
52151
|
const ffmpeg = spawn(ffmpegPath, args, {
|
|
51927
52152
|
stdio: ["pipe", "pipe", "pipe"]
|
|
51928
52153
|
});
|
|
@@ -51946,7 +52171,7 @@ function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
|
51946
52171
|
});
|
|
51947
52172
|
ffmpeg.on("close", (code) => {
|
|
51948
52173
|
if (code === 0) {
|
|
51949
|
-
|
|
52174
|
+
resolve64();
|
|
51950
52175
|
} else {
|
|
51951
52176
|
const errorMatch = stderr.match(/Error.*$/m);
|
|
51952
52177
|
const errorMsg = errorMatch ? errorMatch[0] : `FFmpeg exited with code ${code}`;
|
|
@@ -52083,16 +52308,16 @@ function getPresetSettings(preset, aspectRatio) {
|
|
|
52083
52308
|
async function runHyperframesExport(projectPath, options, spinner2, startedAt) {
|
|
52084
52309
|
spinner2.text = "Loading project...";
|
|
52085
52310
|
const { readFile: readFile42 } = await import("node:fs/promises");
|
|
52086
|
-
const { resolve:
|
|
52311
|
+
const { resolve: resolve64, basename: basename22 } = await import("node:path");
|
|
52087
52312
|
const { Project: Project2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
52088
52313
|
const { createHyperframesBackend: createHyperframesBackend2 } = await Promise.resolve().then(() => (init_hyperframes(), hyperframes_exports));
|
|
52089
52314
|
const { exitWithError: exitWithError2, generalError: generalError2, outputSuccess: outputSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
52090
52315
|
const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
|
|
52091
|
-
const filePath =
|
|
52316
|
+
const filePath = resolve64(process.cwd(), projectPath);
|
|
52092
52317
|
const content = await readFile42(filePath, "utf-8");
|
|
52093
52318
|
const project = Project2.fromJSON(JSON.parse(content));
|
|
52094
52319
|
const state = project.getState();
|
|
52095
|
-
const outputPath = options.output ?
|
|
52320
|
+
const outputPath = options.output ? resolve64(process.cwd(), options.output) : resolve64(process.cwd(), `${basename22(projectPath, ".vibe.json")}.${options.format ?? "mp4"}`);
|
|
52096
52321
|
const quality = ["draft", "standard", "high"].includes(options.preset ?? "") ? options.preset : "standard";
|
|
52097
52322
|
const backend = createHyperframesBackend2();
|
|
52098
52323
|
spinner2.text = "Rendering with Hyperframes...";
|
|
@@ -52263,6 +52488,25 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
|
|
|
52263
52488
|
spinner2.text = `Encoding... ${progress}%`;
|
|
52264
52489
|
});
|
|
52265
52490
|
spinner2.succeed(source_default.green(`Exported: ${outputPath}`));
|
|
52491
|
+
if (isJsonMode()) {
|
|
52492
|
+
outputSuccess({
|
|
52493
|
+
command: "export",
|
|
52494
|
+
startedAt,
|
|
52495
|
+
data: {
|
|
52496
|
+
outputPath,
|
|
52497
|
+
backend: "ffmpeg",
|
|
52498
|
+
format: options.format,
|
|
52499
|
+
preset: options.preset,
|
|
52500
|
+
resolution: presetSettings.resolution,
|
|
52501
|
+
duration: summary.duration,
|
|
52502
|
+
clipCount: summary.clipCount,
|
|
52503
|
+
bitrate: options.bitrate ?? null,
|
|
52504
|
+
fps: options.fps ?? null,
|
|
52505
|
+
codec: options.codec ?? null
|
|
52506
|
+
}
|
|
52507
|
+
});
|
|
52508
|
+
return;
|
|
52509
|
+
}
|
|
52266
52510
|
console.log();
|
|
52267
52511
|
console.log(source_default.dim(" Duration:"), `${summary.duration.toFixed(1)}s`);
|
|
52268
52512
|
console.log(source_default.dim(" Clips:"), summary.clipCount);
|
|
@@ -52811,7 +53055,7 @@ __export(ai_video_exports, {
|
|
|
52811
53055
|
executeVideoStatus: () => executeVideoStatus
|
|
52812
53056
|
});
|
|
52813
53057
|
import { readFile as readFile36, writeFile as writeFile40 } from "node:fs/promises";
|
|
52814
|
-
import { resolve as
|
|
53058
|
+
import { resolve as resolve54 } from "node:path";
|
|
52815
53059
|
async function executeVideoGenerate(options) {
|
|
52816
53060
|
const {
|
|
52817
53061
|
prompt: prompt3,
|
|
@@ -52824,24 +53068,61 @@ async function executeVideoGenerate(options) {
|
|
|
52824
53068
|
negative,
|
|
52825
53069
|
resolution,
|
|
52826
53070
|
veoModel = "3.1-fast",
|
|
53071
|
+
seedanceModel = "quality",
|
|
52827
53072
|
output,
|
|
52828
53073
|
wait = true,
|
|
52829
53074
|
apiKey
|
|
52830
53075
|
} = options;
|
|
52831
53076
|
try {
|
|
52832
|
-
const envKeyMap = {
|
|
53077
|
+
const envKeyMap = {
|
|
53078
|
+
grok: "XAI_API_KEY",
|
|
53079
|
+
runway: "RUNWAY_API_SECRET",
|
|
53080
|
+
kling: "KLING_API_KEY",
|
|
53081
|
+
veo: "GOOGLE_API_KEY",
|
|
53082
|
+
seedance: "FAL_KEY",
|
|
53083
|
+
fal: "FAL_KEY"
|
|
53084
|
+
};
|
|
52833
53085
|
const key = apiKey || process.env[envKeyMap[provider] || ""];
|
|
52834
53086
|
if (!key) return { success: false, error: `${envKeyMap[provider]} required for ${provider}` };
|
|
52835
53087
|
let referenceImage;
|
|
52836
53088
|
if (image) {
|
|
52837
|
-
const imagePath =
|
|
53089
|
+
const imagePath = resolve54(process.cwd(), image);
|
|
52838
53090
|
const imageBuffer = await readFile36(imagePath);
|
|
52839
53091
|
const ext = image.toLowerCase().split(".").pop();
|
|
52840
53092
|
const mimeTypes2 = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp" };
|
|
52841
53093
|
const mimeType = mimeTypes2[ext || "png"] || "image/png";
|
|
52842
53094
|
referenceImage = `data:${mimeType};base64,${imageBuffer.toString("base64")}`;
|
|
52843
53095
|
}
|
|
52844
|
-
if (provider === "
|
|
53096
|
+
if (provider === "seedance" || provider === "fal") {
|
|
53097
|
+
const fal = new FalProvider();
|
|
53098
|
+
await fal.initialize({ apiKey: key });
|
|
53099
|
+
let falImage = referenceImage;
|
|
53100
|
+
if (falImage && falImage.startsWith("data:")) {
|
|
53101
|
+
const imgbbKey = process.env.IMGBB_API_KEY;
|
|
53102
|
+
if (!imgbbKey) return { success: false, error: "IMGBB_API_KEY required for Seedance image-to-video" };
|
|
53103
|
+
const base64Data = falImage.split(",")[1];
|
|
53104
|
+
const uploadResult = await uploadToImgbb(Buffer.from(base64Data, "base64"), imgbbKey);
|
|
53105
|
+
if (!uploadResult.success || !uploadResult.url) return { success: false, error: `ImgBB upload failed: ${uploadResult.error}` };
|
|
53106
|
+
falImage = uploadResult.url;
|
|
53107
|
+
}
|
|
53108
|
+
const model = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
|
|
53109
|
+
const result = await fal.generateVideo(prompt3, {
|
|
53110
|
+
prompt: prompt3,
|
|
53111
|
+
referenceImage: falImage,
|
|
53112
|
+
duration,
|
|
53113
|
+
aspectRatio: ratio,
|
|
53114
|
+
negativePrompt: negative,
|
|
53115
|
+
model
|
|
53116
|
+
});
|
|
53117
|
+
if (result.status === "failed") return { success: false, error: result.error || "Seedance generation failed" };
|
|
53118
|
+
let outputPath;
|
|
53119
|
+
if (output && result.videoUrl) {
|
|
53120
|
+
const buffer = await downloadVideo(result.videoUrl, key);
|
|
53121
|
+
outputPath = resolve54(process.cwd(), output);
|
|
53122
|
+
await writeFile40(outputPath, buffer);
|
|
53123
|
+
}
|
|
53124
|
+
return { success: true, taskId: result.id, status: "completed", videoUrl: result.videoUrl, outputPath, provider: "seedance" };
|
|
53125
|
+
} else if (provider === "runway") {
|
|
52845
53126
|
const runway = new RunwayProvider();
|
|
52846
53127
|
await runway.initialize({ apiKey: key });
|
|
52847
53128
|
const result = await runway.generateVideo(prompt3, {
|
|
@@ -52859,7 +53140,7 @@ async function executeVideoGenerate(options) {
|
|
|
52859
53140
|
let outputPath;
|
|
52860
53141
|
if (output && finalResult.videoUrl) {
|
|
52861
53142
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
52862
|
-
outputPath =
|
|
53143
|
+
outputPath = resolve54(process.cwd(), output);
|
|
52863
53144
|
await writeFile40(outputPath, buffer);
|
|
52864
53145
|
}
|
|
52865
53146
|
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "runway" };
|
|
@@ -52893,7 +53174,7 @@ async function executeVideoGenerate(options) {
|
|
|
52893
53174
|
let outputPath;
|
|
52894
53175
|
if (output && finalResult.videoUrl) {
|
|
52895
53176
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
52896
|
-
outputPath =
|
|
53177
|
+
outputPath = resolve54(process.cwd(), output);
|
|
52897
53178
|
await writeFile40(outputPath, buffer);
|
|
52898
53179
|
}
|
|
52899
53180
|
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "kling" };
|
|
@@ -52920,7 +53201,7 @@ async function executeVideoGenerate(options) {
|
|
|
52920
53201
|
let outputPath;
|
|
52921
53202
|
if (output && finalResult.videoUrl) {
|
|
52922
53203
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
52923
|
-
outputPath =
|
|
53204
|
+
outputPath = resolve54(process.cwd(), output);
|
|
52924
53205
|
await writeFile40(outputPath, buffer);
|
|
52925
53206
|
}
|
|
52926
53207
|
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath, provider: "veo" };
|
|
@@ -52941,7 +53222,7 @@ async function executeVideoGenerate(options) {
|
|
|
52941
53222
|
let outputPath;
|
|
52942
53223
|
if (output && finalResult.videoUrl) {
|
|
52943
53224
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
52944
|
-
outputPath =
|
|
53225
|
+
outputPath = resolve54(process.cwd(), output);
|
|
52945
53226
|
await writeFile40(outputPath, buffer);
|
|
52946
53227
|
}
|
|
52947
53228
|
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath, provider: "grok" };
|
|
@@ -52968,7 +53249,7 @@ async function executeVideoStatus(options) {
|
|
|
52968
53249
|
let outputPath;
|
|
52969
53250
|
if (output && result.videoUrl) {
|
|
52970
53251
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
52971
|
-
outputPath =
|
|
53252
|
+
outputPath = resolve54(process.cwd(), output);
|
|
52972
53253
|
await writeFile40(outputPath, buffer);
|
|
52973
53254
|
}
|
|
52974
53255
|
return { success: true, taskId, status: result.status, progress: result.progress, videoUrl: result.videoUrl, outputPath };
|
|
@@ -52983,7 +53264,7 @@ async function executeVideoStatus(options) {
|
|
|
52983
53264
|
let outputPath;
|
|
52984
53265
|
if (output && result.videoUrl) {
|
|
52985
53266
|
const buffer = await downloadVideo(result.videoUrl, key);
|
|
52986
|
-
outputPath =
|
|
53267
|
+
outputPath = resolve54(process.cwd(), output);
|
|
52987
53268
|
await writeFile40(outputPath, buffer);
|
|
52988
53269
|
}
|
|
52989
53270
|
return { success: true, taskId, status: result.status, videoUrl: result.videoUrl, duration: result.duration, outputPath };
|
|
@@ -53028,7 +53309,7 @@ async function executeVideoExtend(options) {
|
|
|
53028
53309
|
let outputPath;
|
|
53029
53310
|
if (output && finalResult.videoUrl) {
|
|
53030
53311
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
53031
|
-
outputPath =
|
|
53312
|
+
outputPath = resolve54(process.cwd(), output);
|
|
53032
53313
|
await writeFile40(outputPath, buffer);
|
|
53033
53314
|
}
|
|
53034
53315
|
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, duration: finalResult.duration, outputPath };
|
|
@@ -53051,7 +53332,7 @@ async function executeVideoExtend(options) {
|
|
|
53051
53332
|
let outputPath;
|
|
53052
53333
|
if (output && finalResult.videoUrl) {
|
|
53053
53334
|
const buffer = await downloadVideo(finalResult.videoUrl, key);
|
|
53054
|
-
outputPath =
|
|
53335
|
+
outputPath = resolve54(process.cwd(), output);
|
|
53055
53336
|
await writeFile40(outputPath, buffer);
|
|
53056
53337
|
}
|
|
53057
53338
|
return { success: true, taskId: result.id, status: "completed", videoUrl: finalResult.videoUrl, outputPath };
|
|
@@ -53079,7 +53360,7 @@ __export(ai_audio_exports, {
|
|
|
53079
53360
|
executeTranscribe: () => executeTranscribe,
|
|
53080
53361
|
executeVoiceClone: () => executeVoiceClone
|
|
53081
53362
|
});
|
|
53082
|
-
import { resolve as
|
|
53363
|
+
import { resolve as resolve55, dirname as dirname20, basename as basename20, extname as extname12 } from "node:path";
|
|
53083
53364
|
import { readFile as readFile37, writeFile as writeFile41 } from "node:fs/promises";
|
|
53084
53365
|
import { existsSync as existsSync37 } from "node:fs";
|
|
53085
53366
|
async function executeTranscribe(options) {
|
|
@@ -53087,7 +53368,7 @@ async function executeTranscribe(options) {
|
|
|
53087
53368
|
try {
|
|
53088
53369
|
const key = apiKey || process.env.OPENAI_API_KEY;
|
|
53089
53370
|
if (!key) return { success: false, error: "OPENAI_API_KEY required" };
|
|
53090
|
-
const absPath =
|
|
53371
|
+
const absPath = resolve55(process.cwd(), audioPath);
|
|
53091
53372
|
if (!existsSync37(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
53092
53373
|
const whisper = new WhisperProvider();
|
|
53093
53374
|
await whisper.initialize({ apiKey: key });
|
|
@@ -53099,7 +53380,7 @@ async function executeTranscribe(options) {
|
|
|
53099
53380
|
}
|
|
53100
53381
|
let outputPath;
|
|
53101
53382
|
if (output) {
|
|
53102
|
-
outputPath =
|
|
53383
|
+
outputPath = resolve55(process.cwd(), output);
|
|
53103
53384
|
const fmt = detectFormat(output, format);
|
|
53104
53385
|
const content = formatTranscript(result, fmt);
|
|
53105
53386
|
await writeFile41(outputPath, content, "utf-8");
|
|
@@ -53120,7 +53401,7 @@ async function executeIsolate(options) {
|
|
|
53120
53401
|
try {
|
|
53121
53402
|
const key = apiKey || process.env.ELEVENLABS_API_KEY;
|
|
53122
53403
|
if (!key) return { success: false, error: "ELEVENLABS_API_KEY required" };
|
|
53123
|
-
const absPath =
|
|
53404
|
+
const absPath = resolve55(process.cwd(), audioPath);
|
|
53124
53405
|
if (!existsSync37(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
53125
53406
|
const audioBuffer = await readFile37(absPath);
|
|
53126
53407
|
const elevenlabs = new ElevenLabsProvider();
|
|
@@ -53129,7 +53410,7 @@ async function executeIsolate(options) {
|
|
|
53129
53410
|
if (!result.success || !result.audioBuffer) {
|
|
53130
53411
|
return { success: false, error: result.error || "Audio isolation failed" };
|
|
53131
53412
|
}
|
|
53132
|
-
const outputPath =
|
|
53413
|
+
const outputPath = resolve55(process.cwd(), output);
|
|
53133
53414
|
await writeFile41(outputPath, result.audioBuffer);
|
|
53134
53415
|
return { success: true, outputPath };
|
|
53135
53416
|
} catch (error) {
|
|
@@ -53146,7 +53427,7 @@ async function executeVoiceClone(options) {
|
|
|
53146
53427
|
}
|
|
53147
53428
|
const audioBuffers = [];
|
|
53148
53429
|
for (const samplePath of samplePaths) {
|
|
53149
|
-
const absPath =
|
|
53430
|
+
const absPath = resolve55(process.cwd(), samplePath);
|
|
53150
53431
|
if (!existsSync37(absPath)) return { success: false, error: `File not found: ${samplePath}` };
|
|
53151
53432
|
const buffer = await readFile37(absPath);
|
|
53152
53433
|
audioBuffers.push(buffer);
|
|
@@ -53168,7 +53449,7 @@ async function executeVoiceClone(options) {
|
|
|
53168
53449
|
async function executeDub(options) {
|
|
53169
53450
|
const { mediaPath, language, source, voice, analyzeOnly, output } = options;
|
|
53170
53451
|
try {
|
|
53171
|
-
const absPath =
|
|
53452
|
+
const absPath = resolve55(process.cwd(), mediaPath);
|
|
53172
53453
|
if (!existsSync37(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
53173
53454
|
const openaiKey = process.env.OPENAI_API_KEY;
|
|
53174
53455
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
@@ -53180,7 +53461,7 @@ async function executeDub(options) {
|
|
|
53180
53461
|
const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
|
|
53181
53462
|
let audioPath = absPath;
|
|
53182
53463
|
if (isVideo) {
|
|
53183
|
-
const tempAudioPath =
|
|
53464
|
+
const tempAudioPath = resolve55(dirname20(absPath), `temp-audio-${Date.now()}.mp3`);
|
|
53184
53465
|
execSafeSync("ffmpeg", ["-i", absPath, "-vn", "-acodec", "mp3", "-y", tempAudioPath]);
|
|
53185
53466
|
audioPath = tempAudioPath;
|
|
53186
53467
|
}
|
|
@@ -53229,7 +53510,7 @@ ${segmentTexts}`,
|
|
|
53229
53510
|
}
|
|
53230
53511
|
if (analyzeOnly) {
|
|
53231
53512
|
if (output) {
|
|
53232
|
-
const timingPath =
|
|
53513
|
+
const timingPath = resolve55(process.cwd(), output);
|
|
53233
53514
|
const timingData = {
|
|
53234
53515
|
sourcePath: absPath,
|
|
53235
53516
|
sourceLanguage: transcriptResult.detectedLanguage || source || "auto",
|
|
@@ -53248,7 +53529,7 @@ ${segmentTexts}`,
|
|
|
53248
53529
|
sourceLanguage: transcriptResult.detectedLanguage || source || "auto",
|
|
53249
53530
|
targetLanguage: language,
|
|
53250
53531
|
segmentCount: segments.length,
|
|
53251
|
-
outputPath: output ?
|
|
53532
|
+
outputPath: output ? resolve55(process.cwd(), output) : void 0
|
|
53252
53533
|
};
|
|
53253
53534
|
}
|
|
53254
53535
|
const elevenlabs = new ElevenLabsProvider();
|
|
@@ -53262,8 +53543,8 @@ ${segmentTexts}`,
|
|
|
53262
53543
|
}
|
|
53263
53544
|
const combinedBuffer = Buffer.concat(dubbedBuffers);
|
|
53264
53545
|
const outputExt = isVideo ? ".mp3" : extname12(absPath);
|
|
53265
|
-
const defaultOutputPath2 =
|
|
53266
|
-
const finalOutputPath =
|
|
53546
|
+
const defaultOutputPath2 = resolve55(dirname20(absPath), `${basename20(absPath, extname12(absPath))}-${language}${outputExt}`);
|
|
53547
|
+
const finalOutputPath = resolve55(process.cwd(), output || defaultOutputPath2);
|
|
53267
53548
|
await writeFile41(finalOutputPath, combinedBuffer);
|
|
53268
53549
|
if (isVideo && audioPath !== absPath) {
|
|
53269
53550
|
try {
|
|
@@ -53295,12 +53576,12 @@ async function executeDuck(options) {
|
|
|
53295
53576
|
} = options;
|
|
53296
53577
|
try {
|
|
53297
53578
|
if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
|
|
53298
|
-
const absMusicPath =
|
|
53299
|
-
const absVoicePath =
|
|
53579
|
+
const absMusicPath = resolve55(process.cwd(), musicPath);
|
|
53580
|
+
const absVoicePath = resolve55(process.cwd(), voicePath);
|
|
53300
53581
|
if (!existsSync37(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
|
|
53301
53582
|
if (!existsSync37(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
|
|
53302
|
-
const defaultOutput =
|
|
53303
|
-
const outputPath =
|
|
53583
|
+
const defaultOutput = resolve55(dirname20(absMusicPath), `${basename20(absMusicPath, extname12(absMusicPath))}-ducked${extname12(absMusicPath)}`);
|
|
53584
|
+
const outputPath = resolve55(process.cwd(), output || defaultOutput);
|
|
53304
53585
|
const filter = `[1:a]asplit=2[sc][mix];[0:a][sc]sidechaincompress=threshold=${threshold}dB:ratio=${ratio}:attack=${attack}:release=${release}[ducked];[ducked][mix]amix=inputs=2:duration=longest`;
|
|
53305
53586
|
await execSafe("ffmpeg", [
|
|
53306
53587
|
"-i",
|
|
@@ -53328,11 +53609,11 @@ var init_ai_audio = __esm({
|
|
|
53328
53609
|
});
|
|
53329
53610
|
|
|
53330
53611
|
// src/pipeline/executor.ts
|
|
53331
|
-
import { resolve as
|
|
53612
|
+
import { resolve as resolve56 } from "node:path";
|
|
53332
53613
|
import { readFile as readFile38, writeFile as writeFile42, mkdir as mkdir22 } from "node:fs/promises";
|
|
53333
53614
|
import { existsSync as existsSync38 } from "node:fs";
|
|
53334
53615
|
function maxCostFor(action) {
|
|
53335
|
-
const cmd =
|
|
53616
|
+
const cmd = ACTION_METADATA[action]?.command;
|
|
53336
53617
|
if (!cmd) return 0;
|
|
53337
53618
|
return COST_ESTIMATES[cmd]?.max ?? 0;
|
|
53338
53619
|
}
|
|
@@ -53341,9 +53622,9 @@ function registerAction(action, handler) {
|
|
|
53341
53622
|
}
|
|
53342
53623
|
function getOutput(params, outputDir, defaultName) {
|
|
53343
53624
|
if (params.output && typeof params.output === "string") {
|
|
53344
|
-
return
|
|
53625
|
+
return resolve56(outputDir, params.output);
|
|
53345
53626
|
}
|
|
53346
|
-
return
|
|
53627
|
+
return resolve56(outputDir, defaultName);
|
|
53347
53628
|
}
|
|
53348
53629
|
async function ensureActionsRegistered() {
|
|
53349
53630
|
if (Object.keys(ACTION_HANDLERS).length > 0) return;
|
|
@@ -53356,7 +53637,15 @@ async function ensureActionsRegistered() {
|
|
|
53356
53637
|
registerAction("generate-video", async (params, outputDir) => {
|
|
53357
53638
|
const { executeVideoGenerate: executeVideoGenerate2 } = await Promise.resolve().then(() => (init_ai_video(), ai_video_exports));
|
|
53358
53639
|
const output = getOutput(params, outputDir, "video.mp4");
|
|
53359
|
-
const r = await executeVideoGenerate2({
|
|
53640
|
+
const r = await executeVideoGenerate2({
|
|
53641
|
+
prompt: params.prompt,
|
|
53642
|
+
provider: params.provider,
|
|
53643
|
+
image: params.image,
|
|
53644
|
+
duration: params.duration,
|
|
53645
|
+
ratio: params.ratio,
|
|
53646
|
+
output,
|
|
53647
|
+
wait: true
|
|
53648
|
+
});
|
|
53360
53649
|
return { id: "", action: "generate-video", success: r.success, output: r.outputPath || r.videoUrl, data: { taskId: r.taskId, provider: r.provider, videoUrl: r.videoUrl }, error: r.error };
|
|
53361
53650
|
});
|
|
53362
53651
|
registerAction("generate-tts", async (params, outputDir) => {
|
|
@@ -53488,7 +53777,7 @@ async function ensureActionsRegistered() {
|
|
|
53488
53777
|
const { executeSceneBuild: executeSceneBuild2 } = await Promise.resolve().then(() => (init_scene_build(), scene_build_exports));
|
|
53489
53778
|
const projectRel = params.project ?? ".";
|
|
53490
53779
|
const r = await executeSceneBuild2({
|
|
53491
|
-
projectDir:
|
|
53780
|
+
projectDir: resolve56(outputDir, projectRel),
|
|
53492
53781
|
mode: params.mode,
|
|
53493
53782
|
effort: params.effort,
|
|
53494
53783
|
composer: params.composer,
|
|
@@ -53514,7 +53803,7 @@ async function ensureActionsRegistered() {
|
|
|
53514
53803
|
const { executeSceneRender: executeSceneRender2 } = await Promise.resolve().then(() => (init_scene_render(), scene_render_exports));
|
|
53515
53804
|
const projectRel = params.project ?? ".";
|
|
53516
53805
|
const r = await executeSceneRender2({
|
|
53517
|
-
projectDir:
|
|
53806
|
+
projectDir: resolve56(outputDir, projectRel),
|
|
53518
53807
|
root: params.root,
|
|
53519
53808
|
output: params.output,
|
|
53520
53809
|
fps: params.fps,
|
|
@@ -53538,7 +53827,7 @@ async function ensureActionsRegistered() {
|
|
|
53538
53827
|
});
|
|
53539
53828
|
}
|
|
53540
53829
|
async function loadPipeline(filePath) {
|
|
53541
|
-
const absPath =
|
|
53830
|
+
const absPath = resolve56(process.cwd(), filePath);
|
|
53542
53831
|
if (!existsSync38(absPath)) {
|
|
53543
53832
|
throw new Error(`Pipeline file not found: ${absPath}`);
|
|
53544
53833
|
}
|
|
@@ -53557,13 +53846,13 @@ async function loadPipeline(filePath) {
|
|
|
53557
53846
|
}
|
|
53558
53847
|
async function executePipeline(manifest2, options = {}) {
|
|
53559
53848
|
await ensureActionsRegistered();
|
|
53560
|
-
const outputDir =
|
|
53849
|
+
const outputDir = resolve56(process.cwd(), options.outputDir || `${manifest2.name}-output`);
|
|
53561
53850
|
await mkdir22(outputDir, { recursive: true });
|
|
53562
53851
|
const completedSteps = /* @__PURE__ */ new Map();
|
|
53563
53852
|
const results = [];
|
|
53564
53853
|
const startTime = Date.now();
|
|
53565
53854
|
if (options.resume) {
|
|
53566
|
-
const checkpointPath =
|
|
53855
|
+
const checkpointPath = resolve56(outputDir, CHECKPOINT_FILE);
|
|
53567
53856
|
if (existsSync38(checkpointPath)) {
|
|
53568
53857
|
const checkpointContent = await readFile38(checkpointPath, "utf-8");
|
|
53569
53858
|
const checkpoint = (0, import_yaml8.parse)(checkpointContent);
|
|
@@ -53684,7 +53973,7 @@ async function executePipeline(manifest2, options = {}) {
|
|
|
53684
53973
|
}))
|
|
53685
53974
|
};
|
|
53686
53975
|
await writeFile42(
|
|
53687
|
-
|
|
53976
|
+
resolve56(outputDir, CHECKPOINT_FILE),
|
|
53688
53977
|
(0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
|
|
53689
53978
|
"utf-8"
|
|
53690
53979
|
);
|
|
@@ -53731,42 +54020,48 @@ async function executePipeline(manifest2, options = {}) {
|
|
|
53731
54020
|
budget: effectiveBudget ? budgetUsage : void 0
|
|
53732
54021
|
};
|
|
53733
54022
|
}
|
|
53734
|
-
var import_yaml8,
|
|
54023
|
+
var import_yaml8, ACTION_METADATA, ACTION_HANDLERS, CHECKPOINT_FILE;
|
|
53735
54024
|
var init_executor = __esm({
|
|
53736
54025
|
"src/pipeline/executor.ts"() {
|
|
53737
54026
|
"use strict";
|
|
53738
54027
|
import_yaml8 = __toESM(require_dist(), 1);
|
|
53739
54028
|
init_resolver();
|
|
53740
54029
|
init_output();
|
|
53741
|
-
|
|
53742
|
-
"generate-image": "generate image",
|
|
53743
|
-
"generate-video": "generate video",
|
|
53744
|
-
"generate-tts": "generate speech",
|
|
53745
|
-
"generate-sfx": "generate sound-effect",
|
|
53746
|
-
"generate-music": "generate music",
|
|
53747
|
-
"generate-storyboard": "generate storyboard",
|
|
53748
|
-
"generate-motion": "generate motion",
|
|
53749
|
-
"edit-silence-cut": "edit silence-cut",
|
|
53750
|
-
"edit-jump-cut": "edit jump-cut",
|
|
53751
|
-
"edit-caption": "edit caption",
|
|
53752
|
-
"edit-noise-reduce": "edit noise-reduce",
|
|
53753
|
-
"edit-fade": "edit fade",
|
|
53754
|
-
"edit-translate-srt": "edit translate-srt",
|
|
53755
|
-
"edit-text-overlay": "edit text-overlay",
|
|
53756
|
-
"edit-grade": "edit grade",
|
|
53757
|
-
"edit-speed-ramp": "edit speed-ramp",
|
|
53758
|
-
"edit-reframe": "edit reframe",
|
|
53759
|
-
"edit-interpolate": "edit interpolate",
|
|
53760
|
-
"edit-upscale": "edit upscale-video",
|
|
53761
|
-
"edit-image": "edit image",
|
|
53762
|
-
"audio-transcribe": "audio transcribe",
|
|
53763
|
-
"
|
|
53764
|
-
"
|
|
53765
|
-
"
|
|
53766
|
-
"
|
|
53767
|
-
"
|
|
53768
|
-
"
|
|
53769
|
-
"
|
|
54030
|
+
ACTION_METADATA = {
|
|
54031
|
+
"generate-image": { id: "generate-image", title: "Generate image", category: "generate", command: "generate image", outputs: ["image"] },
|
|
54032
|
+
"generate-video": { id: "generate-video", title: "Generate video", category: "generate", command: "generate video", outputs: ["video"], requiredKeys: ["provider-dependent"] },
|
|
54033
|
+
"generate-tts": { id: "generate-tts", title: "Generate speech", category: "generate", command: "generate speech", outputs: ["audio"] },
|
|
54034
|
+
"generate-sfx": { id: "generate-sfx", title: "Generate sound effect", category: "generate", command: "generate sound-effect", outputs: ["audio"] },
|
|
54035
|
+
"generate-music": { id: "generate-music", title: "Generate music", category: "generate", command: "generate music", outputs: ["audio"] },
|
|
54036
|
+
"generate-storyboard": { id: "generate-storyboard", title: "Generate storyboard", category: "generate", command: "generate storyboard", outputs: ["storyboard"] },
|
|
54037
|
+
"generate-motion": { id: "generate-motion", title: "Generate motion", category: "generate", command: "generate motion", outputs: ["code", "video"] },
|
|
54038
|
+
"edit-silence-cut": { id: "edit-silence-cut", title: "Cut silence", category: "edit", command: "edit silence-cut", outputs: ["video"] },
|
|
54039
|
+
"edit-jump-cut": { id: "edit-jump-cut", title: "Jump cut", category: "edit", command: "edit jump-cut", outputs: ["video"] },
|
|
54040
|
+
"edit-caption": { id: "edit-caption", title: "Caption video", category: "edit", command: "edit caption", outputs: ["video", "srt"] },
|
|
54041
|
+
"edit-noise-reduce": { id: "edit-noise-reduce", title: "Reduce noise", category: "edit", command: "edit noise-reduce", outputs: ["video"] },
|
|
54042
|
+
"edit-fade": { id: "edit-fade", title: "Add fade", category: "edit", command: "edit fade", outputs: ["video"] },
|
|
54043
|
+
"edit-translate-srt": { id: "edit-translate-srt", title: "Translate subtitles", category: "edit", command: "edit translate-srt", outputs: ["srt"] },
|
|
54044
|
+
"edit-text-overlay": { id: "edit-text-overlay", title: "Add text overlay", category: "edit", command: "edit text-overlay", outputs: ["video"] },
|
|
54045
|
+
"edit-grade": { id: "edit-grade", title: "Color grade", category: "edit", command: "edit grade", outputs: ["video"] },
|
|
54046
|
+
"edit-speed-ramp": { id: "edit-speed-ramp", title: "Speed ramp", category: "edit", command: "edit speed-ramp", outputs: ["video"] },
|
|
54047
|
+
"edit-reframe": { id: "edit-reframe", title: "Reframe video", category: "edit", command: "edit reframe", outputs: ["video"] },
|
|
54048
|
+
"edit-interpolate": { id: "edit-interpolate", title: "Interpolate frames", category: "edit", command: "edit interpolate", outputs: ["video"] },
|
|
54049
|
+
"edit-upscale": { id: "edit-upscale", title: "Upscale video", category: "edit", command: "edit upscale-video", outputs: ["video"] },
|
|
54050
|
+
"edit-image": { id: "edit-image", title: "Edit image", category: "edit", command: "edit image", outputs: ["image"] },
|
|
54051
|
+
"audio-transcribe": { id: "audio-transcribe", title: "Transcribe audio", category: "audio", command: "audio transcribe", outputs: ["transcript", "srt"] },
|
|
54052
|
+
"audio-isolate": { id: "audio-isolate", title: "Isolate audio", category: "audio", outputs: ["audio"] },
|
|
54053
|
+
"audio-dub": { id: "audio-dub", title: "Dub audio", category: "audio", outputs: ["audio", "video"] },
|
|
54054
|
+
"audio-duck": { id: "audio-duck", title: "Duck audio", category: "audio", outputs: ["video"] },
|
|
54055
|
+
"detect-scenes": { id: "detect-scenes", title: "Detect scenes", category: "detect", command: "detect scenes", outputs: ["json"] },
|
|
54056
|
+
"detect-silence": { id: "detect-silence", title: "Detect silence", category: "detect", command: "detect silence", outputs: ["json"] },
|
|
54057
|
+
"detect-beats": { id: "detect-beats", title: "Detect beats", category: "detect", command: "detect beats", outputs: ["json"] },
|
|
54058
|
+
"analyze-media": { id: "analyze-media", title: "Analyze media", category: "analyze", command: "analyze media", outputs: ["json"] },
|
|
54059
|
+
"analyze-video": { id: "analyze-video", title: "Analyze video", category: "analyze", command: "analyze video", outputs: ["json"] },
|
|
54060
|
+
"review-video": { id: "review-video", title: "Review video", category: "analyze", command: "analyze review", outputs: ["json"] },
|
|
54061
|
+
"compose-scenes-with-skills": { id: "compose-scenes-with-skills", title: "Compose scenes with skills", category: "scene", command: "compose scenes with skills", outputs: ["html"] },
|
|
54062
|
+
"scene-build": { id: "scene-build", title: "Build scene project", category: "scene", outputs: ["video", "html", "assets"] },
|
|
54063
|
+
"scene-render": { id: "scene-render", title: "Render scene project", category: "scene", outputs: ["video"] },
|
|
54064
|
+
export: { id: "export", title: "Export project", category: "export", outputs: ["video"] }
|
|
53770
54065
|
};
|
|
53771
54066
|
ACTION_HANDLERS = {};
|
|
53772
54067
|
CHECKPOINT_FILE = ".pipeline-state.yaml";
|
|
@@ -58641,7 +58936,7 @@ var init_define_tool = __esm({
|
|
|
58641
58936
|
});
|
|
58642
58937
|
|
|
58643
58938
|
// src/tools/manifest/scene.ts
|
|
58644
|
-
import { resolve as
|
|
58939
|
+
import { resolve as resolve57, relative as relative7 } from "node:path";
|
|
58645
58940
|
function summariseLint(result) {
|
|
58646
58941
|
return {
|
|
58647
58942
|
ok: result.ok,
|
|
@@ -58757,10 +59052,10 @@ var init_scene2 = __esm({
|
|
|
58757
59052
|
name: "scene_init",
|
|
58758
59053
|
category: "scene",
|
|
58759
59054
|
cost: "free",
|
|
58760
|
-
description: "Scaffold a new
|
|
59055
|
+
description: "Scaffold a new VibeFrame video scene project. Supports minimal, agent, and full profiles; full includes the current HTML render backend metadata. Idempotent: re-running keeps user-authored files and merges backend config instead of overwriting. No API keys required.",
|
|
58761
59056
|
schema: sceneInitSchema,
|
|
58762
59057
|
async execute(args, ctx) {
|
|
58763
|
-
const dir =
|
|
59058
|
+
const dir = resolve57(ctx.workingDirectory, args.dir);
|
|
58764
59059
|
const result = await scaffoldSceneProject({
|
|
58765
59060
|
dir,
|
|
58766
59061
|
name: args.name,
|
|
@@ -58808,7 +59103,7 @@ var init_scene2 = __esm({
|
|
|
58808
59103
|
description: "Add a single scene to an existing scene project. Optionally generates narration audio (ElevenLabs) and/or a backdrop image (Gemini/OpenAI), then emits compositions/scene-<id>.html with a paused GSAP timeline and splices a clip reference into the root index.html. Use skipAudio:true and skipImage:true for text-only scenes that need no API calls.",
|
|
58809
59104
|
schema: sceneAddSchema,
|
|
58810
59105
|
async execute(args, ctx) {
|
|
58811
|
-
const projectDir = args.projectDir ?
|
|
59106
|
+
const projectDir = args.projectDir ? resolve57(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
58812
59107
|
const result = await executeSceneAdd({
|
|
58813
59108
|
name: args.name,
|
|
58814
59109
|
preset: args.preset ?? "simple",
|
|
@@ -58865,7 +59160,7 @@ var init_scene2 = __esm({
|
|
|
58865
59160
|
description: "Validate every scene file in a project against the public Hyperframes lint rules (in-process, no Chrome required). Returns errors, warnings, and info findings per file. Optional fix:true mechanically repairs `timed_element_missing_clip_class` only \u2014 other issues surface with fixHints.",
|
|
58866
59161
|
schema: sceneLintSchema,
|
|
58867
59162
|
async execute(args, ctx) {
|
|
58868
|
-
const projectDir = args.projectDir ?
|
|
59163
|
+
const projectDir = args.projectDir ? resolve57(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
58869
59164
|
const result = await runProjectLint({
|
|
58870
59165
|
projectDir,
|
|
58871
59166
|
rootRel: args.root,
|
|
@@ -58906,7 +59201,7 @@ var init_scene2 = __esm({
|
|
|
58906
59201
|
description: "Render a scene project to MP4/WebM/MOV via the Hyperframes producer. Requires Chrome installed locally. Output defaults to renders/<projectName>-<isoStamp>.<format>.",
|
|
58907
59202
|
schema: sceneRenderSchema,
|
|
58908
59203
|
async execute(args, ctx) {
|
|
58909
|
-
const projectDir = args.projectDir ?
|
|
59204
|
+
const projectDir = args.projectDir ? resolve57(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
58910
59205
|
const result = await executeSceneRender({
|
|
58911
59206
|
projectDir,
|
|
58912
59207
|
root: args.root,
|
|
@@ -58961,7 +59256,7 @@ var init_scene2 = __esm({
|
|
|
58961
59256
|
description: "v0.60 one-shot orchestrator: read STORYBOARD.md per-beat YAML cues (narration / backdrop / duration), dispatch TTS + image generation per beat, compose scene HTML via the compose-scenes-with-skills pipeline, then render to MP4. Use this instead of chaining scene_init + scene_add + scene_render manually. Caches by SHA256 of (DESIGN.md + cue body) so re-runs are idempotent and cheap.",
|
|
58962
59257
|
schema: sceneBuildSchema,
|
|
58963
59258
|
async execute(args, ctx) {
|
|
58964
|
-
const projectDir = args.projectDir ?
|
|
59259
|
+
const projectDir = args.projectDir ? resolve57(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
58965
59260
|
const result = await executeSceneBuild({
|
|
58966
59261
|
projectDir,
|
|
58967
59262
|
mode: args.mode,
|
|
@@ -59022,7 +59317,7 @@ var init_scene2 = __esm({
|
|
|
59022
59317
|
description: "Install the vendored Hyperframes skill bundle into a scene project so the host agent (Claude Code, Cursor, Codex, Aider) can read framework rules + house style directly. Writes a universal SKILL.md + references/ at the project root, plus per-host layouts (.claude/skills/hyperframes/ for Claude Code, .cursor/rules/hyperframes.mdc for Cursor) when those hosts are detected. Phase H1 of the agentic-native composer plan \u2014 once installed, the host agent itself can author scene HTML using the rules instead of relying on vibe's internal LLM call.",
|
|
59023
59318
|
schema: sceneInstallSkillSchema,
|
|
59024
59319
|
async execute(args, ctx) {
|
|
59025
|
-
const projectDir =
|
|
59320
|
+
const projectDir = resolve57(ctx.workingDirectory, args.projectDir);
|
|
59026
59321
|
const hostFlag = args.host ?? "auto";
|
|
59027
59322
|
const hosts = (() => {
|
|
59028
59323
|
if (hostFlag === "all") return ["all"];
|
|
@@ -59064,7 +59359,7 @@ var init_scene2 = __esm({
|
|
|
59064
59359
|
description: "Emit the per-beat compose plan for the host agent to author scene HTML itself. Reads STORYBOARD.md + DESIGN.md and returns each beat's outputPath + userPrompt + cues + body, plus references to the project's SKILL.md (Hyperframes rules) and DESIGN.md (visual identity). The host agent writes each compositions/scene-<id>.html file directly \u2014 VibeFrame makes NO LLM call here. Pairs with scene_install_skill (Phase H1). Phase H2 of the agentic-native composer plan; the internal-LLM batch path (scene_build) remains as a fallback for non-agent contexts.",
|
|
59065
59360
|
schema: sceneComposePromptsSchema,
|
|
59066
59361
|
async execute(args, ctx) {
|
|
59067
|
-
const projectDir =
|
|
59362
|
+
const projectDir = resolve57(ctx.workingDirectory, args.projectDir);
|
|
59068
59363
|
const result = await getComposePrompts({
|
|
59069
59364
|
projectDir,
|
|
59070
59365
|
beatId: args.beat
|
|
@@ -59654,12 +59949,12 @@ var init_edit = __esm({
|
|
|
59654
59949
|
|
|
59655
59950
|
// src/commands/ai-suggest-edit.ts
|
|
59656
59951
|
import { readFile as readFile39, writeFile as writeFile43 } from "node:fs/promises";
|
|
59657
|
-
import { resolve as
|
|
59952
|
+
import { resolve as resolve58 } from "node:path";
|
|
59658
59953
|
async function executeSuggestEdit(options) {
|
|
59659
59954
|
try {
|
|
59660
59955
|
const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY;
|
|
59661
59956
|
if (!apiKey) return { success: false, error: "GOOGLE_API_KEY required for suggest" };
|
|
59662
|
-
const filePath =
|
|
59957
|
+
const filePath = resolve58(process.cwd(), options.projectPath);
|
|
59663
59958
|
const content = await readFile39(filePath, "utf-8");
|
|
59664
59959
|
const data = JSON.parse(content);
|
|
59665
59960
|
const project = Project.fromJSON(data);
|
|
@@ -60438,9 +60733,9 @@ var init_detect2 = __esm({
|
|
|
60438
60733
|
|
|
60439
60734
|
// src/tools/manifest/_project-io.ts
|
|
60440
60735
|
import { readFile as readFile40, writeFile as writeFile45 } from "node:fs/promises";
|
|
60441
|
-
import { resolve as
|
|
60736
|
+
import { resolve as resolve59 } from "node:path";
|
|
60442
60737
|
async function loadProject(projectPath, cwd) {
|
|
60443
|
-
const absPath =
|
|
60738
|
+
const absPath = resolve59(cwd, projectPath);
|
|
60444
60739
|
const content = await readFile40(absPath, "utf-8");
|
|
60445
60740
|
const data = JSON.parse(content);
|
|
60446
60741
|
return { project: Project.fromJSON(data), absPath };
|
|
@@ -60456,7 +60751,7 @@ var init_project_io = __esm({
|
|
|
60456
60751
|
});
|
|
60457
60752
|
|
|
60458
60753
|
// src/tools/manifest/timeline.ts
|
|
60459
|
-
import { resolve as
|
|
60754
|
+
import { resolve as resolve60 } from "node:path";
|
|
60460
60755
|
var MEDIA_TYPES, timelineAddSourceTool, timelineAddClipTool, timelineSplitClipTool, timelineTrimClipTool, timelineMoveClipTool, timelineDeleteClipTool, timelineDuplicateClipTool, timelineAddEffectTool, timelineAddTrackTool, timelineListTool, timelineTools;
|
|
60461
60756
|
var init_timeline = __esm({
|
|
60462
60757
|
"src/tools/manifest/timeline.ts"() {
|
|
@@ -60492,7 +60787,7 @@ var init_timeline = __esm({
|
|
|
60492
60787
|
}),
|
|
60493
60788
|
async execute(args, ctx) {
|
|
60494
60789
|
const { project, absPath } = await loadProject(args.projectPath, ctx.workingDirectory);
|
|
60495
|
-
const mediaPath =
|
|
60790
|
+
const mediaPath = resolve60(ctx.workingDirectory, args.mediaPath);
|
|
60496
60791
|
const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "";
|
|
60497
60792
|
const source = project.addSource({
|
|
60498
60793
|
name: args.name ?? mediaPath.split("/").pop() ?? "media",
|
|
@@ -60718,7 +61013,7 @@ var init_timeline = __esm({
|
|
|
60718
61013
|
});
|
|
60719
61014
|
|
|
60720
61015
|
// src/tools/manifest/project.ts
|
|
60721
|
-
import { resolve as
|
|
61016
|
+
import { resolve as resolve61 } from "node:path";
|
|
60722
61017
|
import { writeFile as writeFile46 } from "node:fs/promises";
|
|
60723
61018
|
var projectCreateTool, projectInfoTool, projectTools;
|
|
60724
61019
|
var init_project2 = __esm({
|
|
@@ -60741,7 +61036,7 @@ var init_project2 = __esm({
|
|
|
60741
61036
|
fps: external_exports.number().optional().describe("Frames per second (default: 30)")
|
|
60742
61037
|
}),
|
|
60743
61038
|
async execute(args, ctx) {
|
|
60744
|
-
const outputPath =
|
|
61039
|
+
const outputPath = resolve61(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
|
|
60745
61040
|
const project = new Project(args.name);
|
|
60746
61041
|
if (args.fps) project.setFrameRate(args.fps);
|
|
60747
61042
|
await writeFile46(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
@@ -60787,7 +61082,7 @@ var init_project2 = __esm({
|
|
|
60787
61082
|
});
|
|
60788
61083
|
|
|
60789
61084
|
// src/tools/manifest/export.ts
|
|
60790
|
-
import { resolve as
|
|
61085
|
+
import { resolve as resolve62 } from "node:path";
|
|
60791
61086
|
var exportVideoTool, exportTools;
|
|
60792
61087
|
var init_export2 = __esm({
|
|
60793
61088
|
"src/tools/manifest/export.ts"() {
|
|
@@ -60808,8 +61103,8 @@ var init_export2 = __esm({
|
|
|
60808
61103
|
overwrite: external_exports.boolean().optional().describe("Overwrite existing output file (default: false)")
|
|
60809
61104
|
}),
|
|
60810
61105
|
async execute(args, ctx) {
|
|
60811
|
-
const projectPath =
|
|
60812
|
-
const outputPath =
|
|
61106
|
+
const projectPath = resolve62(ctx.workingDirectory, args.projectPath);
|
|
61107
|
+
const outputPath = resolve62(ctx.workingDirectory, args.outputPath);
|
|
60813
61108
|
const result = await runExport(projectPath, outputPath, {
|
|
60814
61109
|
preset: args.preset,
|
|
60815
61110
|
format: args.format,
|
|
@@ -60829,7 +61124,7 @@ var init_export2 = __esm({
|
|
|
60829
61124
|
|
|
60830
61125
|
// src/tools/manifest/agent-only.ts
|
|
60831
61126
|
import { readFile as readFile41, writeFile as writeFile47, readdir as readdir4, stat as stat6, access as access8, unlink as unlink4 } from "node:fs/promises";
|
|
60832
|
-
import { resolve as
|
|
61127
|
+
import { resolve as resolve63, join as join15, basename as basename21, extname as extname13 } from "node:path";
|
|
60833
61128
|
function matchPattern(filename, pattern) {
|
|
60834
61129
|
const regex2 = new RegExp(
|
|
60835
61130
|
"^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".") + "$",
|
|
@@ -60885,11 +61180,11 @@ async function getMediaDuration2(filePath) {
|
|
|
60885
61180
|
}
|
|
60886
61181
|
}
|
|
60887
61182
|
async function resolveProjectPath3(inputPath, cwd) {
|
|
60888
|
-
const filePath =
|
|
61183
|
+
const filePath = resolve63(cwd, inputPath);
|
|
60889
61184
|
try {
|
|
60890
61185
|
const stats = await stat6(filePath);
|
|
60891
61186
|
if (stats.isDirectory()) {
|
|
60892
|
-
return
|
|
61187
|
+
return resolve63(filePath, "project.vibe.json");
|
|
60893
61188
|
}
|
|
60894
61189
|
} catch {
|
|
60895
61190
|
}
|
|
@@ -60917,7 +61212,7 @@ var init_agent_only = __esm({
|
|
|
60917
61212
|
async execute(args, ctx) {
|
|
60918
61213
|
const dirPath = args.path ?? ".";
|
|
60919
61214
|
try {
|
|
60920
|
-
const absPath =
|
|
61215
|
+
const absPath = resolve63(ctx.workingDirectory, dirPath);
|
|
60921
61216
|
const entries = await readdir4(absPath, { withFileTypes: true });
|
|
60922
61217
|
const results = [];
|
|
60923
61218
|
for (const entry of entries) {
|
|
@@ -60948,7 +61243,7 @@ var init_agent_only = __esm({
|
|
|
60948
61243
|
}),
|
|
60949
61244
|
async execute(args, ctx) {
|
|
60950
61245
|
try {
|
|
60951
|
-
const absPath =
|
|
61246
|
+
const absPath = resolve63(ctx.workingDirectory, args.path);
|
|
60952
61247
|
const content = await readFile41(absPath, "utf-8");
|
|
60953
61248
|
const maxLength = 4e3;
|
|
60954
61249
|
const truncated = content.length > maxLength;
|
|
@@ -60971,7 +61266,7 @@ var init_agent_only = __esm({
|
|
|
60971
61266
|
}),
|
|
60972
61267
|
async execute(args, ctx) {
|
|
60973
61268
|
try {
|
|
60974
|
-
const absPath =
|
|
61269
|
+
const absPath = resolve63(ctx.workingDirectory, args.path);
|
|
60975
61270
|
await writeFile47(absPath, args.content, "utf-8");
|
|
60976
61271
|
return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
|
|
60977
61272
|
} catch (error) {
|
|
@@ -60989,7 +61284,7 @@ var init_agent_only = __esm({
|
|
|
60989
61284
|
path: external_exports.string().describe("Path to check")
|
|
60990
61285
|
}),
|
|
60991
61286
|
async execute(args, ctx) {
|
|
60992
|
-
const absPath =
|
|
61287
|
+
const absPath = resolve63(ctx.workingDirectory, args.path);
|
|
60993
61288
|
try {
|
|
60994
61289
|
await access8(absPath);
|
|
60995
61290
|
const stats = await stat6(absPath);
|
|
@@ -61015,11 +61310,11 @@ var init_agent_only = __esm({
|
|
|
61015
61310
|
}),
|
|
61016
61311
|
async execute(args, ctx) {
|
|
61017
61312
|
try {
|
|
61018
|
-
const filePath =
|
|
61313
|
+
const filePath = resolve63(ctx.workingDirectory, args.project);
|
|
61019
61314
|
const content = await readFile41(filePath, "utf-8");
|
|
61020
61315
|
const data = JSON.parse(content);
|
|
61021
61316
|
const project = Project.fromJSON(data);
|
|
61022
|
-
const dirPath =
|
|
61317
|
+
const dirPath = resolve63(ctx.workingDirectory, args.directory);
|
|
61023
61318
|
const filterExts = args.filter ? args.filter.split(",").map((e) => e.trim().toLowerCase()) : null;
|
|
61024
61319
|
const imageDuration = args.imageDuration ?? 5;
|
|
61025
61320
|
const recursive = args.recursive ?? false;
|
|
@@ -61085,7 +61380,7 @@ var init_agent_only = __esm({
|
|
|
61085
61380
|
}),
|
|
61086
61381
|
async execute(args, ctx) {
|
|
61087
61382
|
try {
|
|
61088
|
-
const filePath =
|
|
61383
|
+
const filePath = resolve63(ctx.workingDirectory, args.project);
|
|
61089
61384
|
const content = await readFile41(filePath, "utf-8");
|
|
61090
61385
|
const data = JSON.parse(content);
|
|
61091
61386
|
const project = Project.fromJSON(data);
|
|
@@ -61154,7 +61449,7 @@ var init_agent_only = __esm({
|
|
|
61154
61449
|
}),
|
|
61155
61450
|
async execute(args, ctx) {
|
|
61156
61451
|
try {
|
|
61157
|
-
const filePath =
|
|
61452
|
+
const filePath = resolve63(ctx.workingDirectory, args.project);
|
|
61158
61453
|
const content = await readFile41(filePath, "utf-8");
|
|
61159
61454
|
const data = JSON.parse(content);
|
|
61160
61455
|
const project = Project.fromJSON(data);
|
|
@@ -61432,7 +61727,7 @@ var init_agent_only = __esm({
|
|
|
61432
61727
|
}),
|
|
61433
61728
|
async execute(args, ctx) {
|
|
61434
61729
|
try {
|
|
61435
|
-
const absPath =
|
|
61730
|
+
const absPath = resolve63(ctx.workingDirectory, args.path);
|
|
61436
61731
|
const { stdout } = await execSafe(
|
|
61437
61732
|
"ffprobe",
|
|
61438
61733
|
["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", absPath],
|
|
@@ -61519,10 +61814,10 @@ Audio:`);
|
|
|
61519
61814
|
}),
|
|
61520
61815
|
async execute(args, ctx) {
|
|
61521
61816
|
try {
|
|
61522
|
-
const absInput =
|
|
61817
|
+
const absInput = resolve63(ctx.workingDirectory, args.input);
|
|
61523
61818
|
const ext = args.input.split(".").pop() || "mp4";
|
|
61524
61819
|
const baseName = args.input.replace(/\.[^/.]+$/, "");
|
|
61525
|
-
const outputPath = args.output ?
|
|
61820
|
+
const outputPath = args.output ? resolve63(ctx.workingDirectory, args.output) : resolve63(ctx.workingDirectory, `${baseName}-compressed.${ext}`);
|
|
61526
61821
|
const crfValues = { low: 28, medium: 23, high: 18 };
|
|
61527
61822
|
const crf = crfValues[args.quality ?? "medium"];
|
|
61528
61823
|
await execSafe(
|
|
@@ -61580,8 +61875,8 @@ Audio:`);
|
|
|
61580
61875
|
}),
|
|
61581
61876
|
async execute(args, ctx) {
|
|
61582
61877
|
try {
|
|
61583
|
-
const absInput =
|
|
61584
|
-
const absOutput =
|
|
61878
|
+
const absInput = resolve63(ctx.workingDirectory, args.input);
|
|
61879
|
+
const absOutput = resolve63(ctx.workingDirectory, args.output);
|
|
61585
61880
|
const codecMap = {
|
|
61586
61881
|
h264: "libx264",
|
|
61587
61882
|
h265: "libx265",
|
|
@@ -61632,11 +61927,11 @@ Audio:`);
|
|
|
61632
61927
|
};
|
|
61633
61928
|
}
|
|
61634
61929
|
try {
|
|
61635
|
-
const absOutput =
|
|
61930
|
+
const absOutput = resolve63(ctx.workingDirectory, args.output);
|
|
61636
61931
|
if (args.reencode) {
|
|
61637
61932
|
const ffmpegArgs = [];
|
|
61638
61933
|
for (const i of args.inputs) {
|
|
61639
|
-
ffmpegArgs.push("-i",
|
|
61934
|
+
ffmpegArgs.push("-i", resolve63(ctx.workingDirectory, i));
|
|
61640
61935
|
}
|
|
61641
61936
|
const filterComplex = args.inputs.map((_, i) => `[${i}:v][${i}:a]`).join("");
|
|
61642
61937
|
ffmpegArgs.push(
|
|
@@ -61651,8 +61946,8 @@ Audio:`);
|
|
|
61651
61946
|
);
|
|
61652
61947
|
await execSafe("ffmpeg", ffmpegArgs, { maxBuffer: 100 * 1024 * 1024 });
|
|
61653
61948
|
} else {
|
|
61654
|
-
const tempList =
|
|
61655
|
-
const listContent = args.inputs.map((i) => `file '${
|
|
61949
|
+
const tempList = resolve63(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
|
|
61950
|
+
const listContent = args.inputs.map((i) => `file '${resolve63(ctx.workingDirectory, i)}'`).join("\n");
|
|
61656
61951
|
await writeFile47(tempList, listContent, "utf-8");
|
|
61657
61952
|
try {
|
|
61658
61953
|
await execSafe(
|
|
@@ -61737,7 +62032,7 @@ A scene project is a directory that is **bilingual**: it works with both
|
|
|
61737
62032
|
and a paused GSAP timeline. Cheap to edit, cheap to lint, expensive only
|
|
61738
62033
|
at render.
|
|
61739
62034
|
|
|
61740
|
-
\`vibe
|
|
62035
|
+
\`vibe build\` (v0.60+) is the supported one-shot driver from a
|
|
61741
62036
|
written storyboard to an MP4. Plan H (v0.70) added \`--mode agent\` so the
|
|
61742
62037
|
host agent itself authors the per-beat HTML \u2014 no internal LLM call.
|
|
61743
62038
|
|
|
@@ -61745,19 +62040,19 @@ host agent itself authors the per-beat HTML \u2014 no internal LLM call.
|
|
|
61745
62040
|
|
|
61746
62041
|
| Path | Command | When to use |
|
|
61747
62042
|
|---|---|---|
|
|
61748
|
-
| **One-shot (default, v0.60+)** | \`vibe
|
|
61749
|
-
| **High-craft (manual)** | \`DESIGN.md\` +
|
|
62043
|
+
| **One-shot (default, v0.60+)** | \`vibe build [project-dir]\` | STORYBOARD.md has YAML frontmatter + per-beat cues |
|
|
62044
|
+
| **High-craft (manual)** | \`DESIGN.md\` + local composition rules in your agent | Maximum control: hand-author each scene |
|
|
61750
62045
|
| **Quick draft** | \`vibe scene add --style <preset>\` | No agent or no API keys; fast iteration |
|
|
61751
62046
|
|
|
61752
|
-
Recommend \`vibe
|
|
62047
|
+
Recommend \`vibe build\` whenever the user has a STORYBOARD with
|
|
61753
62048
|
narration / backdrop intent.
|
|
61754
62049
|
|
|
61755
62050
|
## High-craft path
|
|
61756
62051
|
|
|
61757
|
-
1. \`vibe
|
|
62052
|
+
1. \`vibe init my-promo --visual-style "Swiss Pulse"\` \u2014 seeds
|
|
61758
62053
|
\`DESIGN.md\` (palette, typography, motion, transitions) plus the
|
|
61759
62054
|
\`vibe.project.yaml\` / \`hyperframes.json\` / \`index.html\` scaffold.
|
|
61760
|
-
In Plan H this **also installs
|
|
62055
|
+
In Plan H this **also installs local composition rules** at the
|
|
61761
62056
|
right place for your host (\`.claude/skills/hyperframes/\` for Claude
|
|
61762
62057
|
Code, \`.cursor/rules/hyperframes.mdc\` for Cursor, universal
|
|
61763
62058
|
\`SKILL.md\` for everyone else).
|
|
@@ -61768,7 +62063,7 @@ narration / backdrop intent.
|
|
|
61768
62063
|
4. Author each scene HTML directly under \`compositions/scene-<id>.html\`
|
|
61769
62064
|
using the rules from steps 2 and 3. The skill enforces the visual
|
|
61770
62065
|
identity contract \u2014 scenes that contradict DESIGN.md fail lint.
|
|
61771
|
-
5. \`vibe scene lint --fix\` for mechanical issues, \`vibe
|
|
62066
|
+
5. \`vibe scene lint --fix\` for mechanical issues, \`vibe render my-promo\`
|
|
61772
62067
|
to MP4.
|
|
61773
62068
|
|
|
61774
62069
|
## Quick-draft path
|
|
@@ -61778,7 +62073,7 @@ vibe scene init my-promo -r 16:9 -d 30
|
|
|
61778
62073
|
vibe scene add intro --style announcement \\
|
|
61779
62074
|
--headline "Ship videos, not clicks"
|
|
61780
62075
|
vibe scene lint
|
|
61781
|
-
vibe
|
|
62076
|
+
vibe render my-promo
|
|
61782
62077
|
\`\`\`
|
|
61783
62078
|
|
|
61784
62079
|
\`vibe scene init\` is **idempotent** \u2014 running it on an existing
|
|
@@ -61790,12 +62085,12 @@ Safe to invoke on user-provided projects.
|
|
|
61790
62085
|
\`\`\`bash
|
|
61791
62086
|
vibe scene init <dir> [-r 16:9|9:16|1:1|4:5] [-d <sec>] [--visual-style "<name>"]
|
|
61792
62087
|
vibe scene styles [<name>] # list / show vendored visual identities
|
|
61793
|
-
vibe scene install-skill [<dir>] [--host all] # retroactive
|
|
62088
|
+
vibe scene install-skill [<dir>] [--host all] # retroactive composition-rules install
|
|
61794
62089
|
vibe scene add <name> --style <preset> [...]
|
|
61795
62090
|
vibe scene compose-prompts [<dir>] [--beat <id>] # H2: emit plan, no LLM call
|
|
61796
62091
|
vibe scene lint [<root>] [--json] [--fix]
|
|
61797
62092
|
vibe scene render [<root>] [--fps 30] [--quality standard] [--format mp4]
|
|
61798
|
-
vibe
|
|
62093
|
+
vibe build [<dir>] [--mode agent|batch|auto] # H3 dispatch
|
|
61799
62094
|
\`\`\`
|
|
61800
62095
|
|
|
61801
62096
|
## Style presets (for \`vibe scene add --style\`)
|
|
@@ -61813,18 +62108,18 @@ from the generated TTS audio.
|
|
|
61813
62108
|
## STORYBOARD-to-MP4 (one command, v0.60+)
|
|
61814
62109
|
|
|
61815
62110
|
\`\`\`bash
|
|
61816
|
-
vibe
|
|
62111
|
+
vibe init my-promo --visual-style "Swiss Pulse" -d 12
|
|
61817
62112
|
# (edit STORYBOARD.md with per-beat YAML cues \u2014 narration, backdrop, duration)
|
|
61818
|
-
vibe
|
|
62113
|
+
vibe build my-promo
|
|
61819
62114
|
\`\`\`
|
|
61820
62115
|
|
|
61821
|
-
\`vibe
|
|
62116
|
+
\`vibe build\` reads the STORYBOARD frontmatter + per-beat cues,
|
|
61822
62117
|
dispatches TTS + image-gen per beat, then either:
|
|
61823
62118
|
|
|
61824
62119
|
- **\`--mode agent\`** (default when an agent host is detected) \u2014 emits a
|
|
61825
62120
|
\`needs-author\` plan via \`vibe scene compose-prompts\`. The host agent
|
|
61826
62121
|
authors each \`compositions/scene-<id>.html\` itself, then re-invoking
|
|
61827
|
-
\`vibe
|
|
62122
|
+
\`vibe build\` proceeds to lint + render.
|
|
61828
62123
|
- **\`--mode batch\`** \u2014 VibeFrame runs an internal LLM (Claude / OpenAI /
|
|
61829
62124
|
Gemini) to compose the HTML, then renders.
|
|
61830
62125
|
|
|
@@ -61847,9 +62142,9 @@ and surface the error to the user.
|
|
|
61847
62142
|
| Task | Tool |
|
|
61848
62143
|
|------|------|
|
|
61849
62144
|
| Generate narration + image, then author scene | \`vibe scene add\` |
|
|
61850
|
-
| Generate a full scenes project from a STORYBOARD | \`vibe
|
|
62145
|
+
| Generate a full scenes project from a STORYBOARD | \`vibe build\` |
|
|
61851
62146
|
| Hand-tweak a single scene's animation | edit \`compositions/<file>.html\` directly |
|
|
61852
|
-
| Render the project | \`vibe
|
|
62147
|
+
| Render the project | \`vibe render\` *or* \`vibe scene render\` for lower-level control |
|
|
61853
62148
|
| Lint | \`vibe scene lint\` *or* \`npx hyperframes lint\` (equivalent) |
|
|
61854
62149
|
|
|
61855
62150
|
The \`vibe\` CLI adds asset generation, AI orchestration, and pipeline
|
|
@@ -61933,8 +62228,8 @@ Checkpoints land next to the YAML: \`pipeline.yaml.checkpoint.json\`.
|
|
|
61933
62228
|
|
|
61934
62229
|
## Authoring tips
|
|
61935
62230
|
|
|
61936
|
-
1. **Start from
|
|
61937
|
-
|
|
62231
|
+
1. **Start from a tiny YAML** \u2014 keep it in your project directory and run
|
|
62232
|
+
\`vibe run pipeline.yaml --dry-run\` before spending provider budget.
|
|
61938
62233
|
2. **Dry-run first** \u2014 you see estimated cost and resolved variable
|
|
61939
62234
|
graph before spending API credits.
|
|
61940
62235
|
3. **Keep step ids short and descriptive** (\`intro\`, \`scene1\`, \`voice\`,
|
|
@@ -61969,18 +62264,18 @@ overlay, etc.) \u2014 useful at the tail of a pipeline.
|
|
|
61969
62264
|
title: "Scene authoring with vibe",
|
|
61970
62265
|
summary: "Author per-scene HTML compositions and render to MP4 (BUILD flow)",
|
|
61971
62266
|
steps: [
|
|
61972
|
-
'Run `vibe
|
|
62267
|
+
'Run `vibe init <dir> --visual-style "<style name>"` to scaffold the project + install local composition rules.',
|
|
61973
62268
|
"Edit `STORYBOARD.md` with per-beat YAML cues (narration / backdrop / duration).",
|
|
61974
62269
|
"Read `SKILL.md` for the framework rules and `DESIGN.md` for the visual-identity hard-gate.",
|
|
61975
|
-
"Run `vibe
|
|
61976
|
-
"Run `vibe scene lint --fix` to validate, then `vibe
|
|
62270
|
+
"Run `vibe 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.",
|
|
62271
|
+
"Run `vibe scene lint --fix` to validate, then `vibe render <dir>` to produce the MP4."
|
|
61977
62272
|
],
|
|
61978
62273
|
relatedCommands: [
|
|
61979
|
-
"vibe
|
|
62274
|
+
"vibe init",
|
|
61980
62275
|
"vibe scene styles",
|
|
61981
62276
|
"vibe scene install-skill",
|
|
61982
62277
|
"vibe scene compose-prompts",
|
|
61983
|
-
"vibe
|
|
62278
|
+
"vibe build",
|
|
61984
62279
|
"vibe scene lint",
|
|
61985
62280
|
"vibe scene render",
|
|
61986
62281
|
"vibe scene add"
|
|
@@ -62306,7 +62601,7 @@ init_source();
|
|
|
62306
62601
|
// package.json
|
|
62307
62602
|
var package_default = {
|
|
62308
62603
|
name: "@vibeframe/cli",
|
|
62309
|
-
version: "0.
|
|
62604
|
+
version: "0.74.0",
|
|
62310
62605
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
62311
62606
|
private: false,
|
|
62312
62607
|
license: "MIT",
|
|
@@ -62578,6 +62873,19 @@ projectCommand.command("create").description("Create a new project").argument("<
|
|
|
62578
62873
|
const data = JSON.stringify(project.toJSON(), null, 2);
|
|
62579
62874
|
await writeFile(outputPath, data, "utf-8");
|
|
62580
62875
|
spinner2.succeed(source_default.green(`Project created: ${outputPath}`));
|
|
62876
|
+
if (isJsonMode()) {
|
|
62877
|
+
outputSuccess({
|
|
62878
|
+
command: "project create",
|
|
62879
|
+
startedAt,
|
|
62880
|
+
data: {
|
|
62881
|
+
outputPath,
|
|
62882
|
+
name: projectName,
|
|
62883
|
+
aspectRatio: options.ratio,
|
|
62884
|
+
frameRate: parseInt(options.fps, 10)
|
|
62885
|
+
}
|
|
62886
|
+
});
|
|
62887
|
+
return;
|
|
62888
|
+
}
|
|
62581
62889
|
console.log();
|
|
62582
62890
|
console.log(source_default.dim(" Name:"), projectName);
|
|
62583
62891
|
console.log(source_default.dim(" Aspect Ratio:"), options.ratio);
|
|
@@ -62589,6 +62897,7 @@ projectCommand.command("create").description("Create a new project").argument("<
|
|
|
62589
62897
|
}
|
|
62590
62898
|
});
|
|
62591
62899
|
projectCommand.command("info").description("Show project information").argument("<file>", "Project file path").action(async (file) => {
|
|
62900
|
+
const startedAt = Date.now();
|
|
62592
62901
|
const spinner2 = ora("Loading project...").start();
|
|
62593
62902
|
try {
|
|
62594
62903
|
const filePath = await resolveProjectPath(file);
|
|
@@ -62598,6 +62907,24 @@ projectCommand.command("info").description("Show project information").argument(
|
|
|
62598
62907
|
spinner2.stop();
|
|
62599
62908
|
const summary = project.getSummary();
|
|
62600
62909
|
const meta = project.getMeta();
|
|
62910
|
+
if (isJsonMode()) {
|
|
62911
|
+
outputSuccess({
|
|
62912
|
+
command: "project info",
|
|
62913
|
+
startedAt,
|
|
62914
|
+
data: {
|
|
62915
|
+
name: summary.name,
|
|
62916
|
+
duration: summary.duration,
|
|
62917
|
+
aspectRatio: summary.aspectRatio,
|
|
62918
|
+
frameRate: summary.frameRate,
|
|
62919
|
+
trackCount: summary.trackCount,
|
|
62920
|
+
clipCount: summary.clipCount,
|
|
62921
|
+
sourceCount: summary.sourceCount,
|
|
62922
|
+
createdAt: meta.createdAt.toISOString(),
|
|
62923
|
+
updatedAt: meta.updatedAt.toISOString()
|
|
62924
|
+
}
|
|
62925
|
+
});
|
|
62926
|
+
return;
|
|
62927
|
+
}
|
|
62601
62928
|
console.log();
|
|
62602
62929
|
console.log(source_default.bold.cyan("Project Info"));
|
|
62603
62930
|
console.log(source_default.dim("\u2500".repeat(40)));
|
|
@@ -62648,6 +62975,21 @@ projectCommand.command("set").description("Update project settings").argument("<
|
|
|
62648
62975
|
if (options.fps) project.setFrameRate(parseInt(options.fps, 10));
|
|
62649
62976
|
await writeFile(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
62650
62977
|
spinner2.succeed(source_default.green("Project updated"));
|
|
62978
|
+
if (isJsonMode()) {
|
|
62979
|
+
outputSuccess({
|
|
62980
|
+
command: "project set",
|
|
62981
|
+
startedAt,
|
|
62982
|
+
data: {
|
|
62983
|
+
file: filePath,
|
|
62984
|
+
updates: {
|
|
62985
|
+
name: options.name ?? null,
|
|
62986
|
+
ratio: options.ratio ?? null,
|
|
62987
|
+
fps: options.fps ? parseInt(options.fps, 10) : null
|
|
62988
|
+
}
|
|
62989
|
+
}
|
|
62990
|
+
});
|
|
62991
|
+
return;
|
|
62992
|
+
}
|
|
62651
62993
|
} catch (error) {
|
|
62652
62994
|
spinner2.fail("Failed to update project");
|
|
62653
62995
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -62721,6 +63063,20 @@ timelineCommand.command("add-source").description("Add a media source to the pro
|
|
|
62721
63063
|
});
|
|
62722
63064
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
62723
63065
|
spinner2.succeed(source_default.green(`Source added: ${source.id}`));
|
|
63066
|
+
if (isJsonMode()) {
|
|
63067
|
+
outputSuccess({
|
|
63068
|
+
command: "timeline add-source",
|
|
63069
|
+
startedAt,
|
|
63070
|
+
data: {
|
|
63071
|
+
id: source.id,
|
|
63072
|
+
name: mediaName,
|
|
63073
|
+
type: mediaType,
|
|
63074
|
+
path: absMediaPath,
|
|
63075
|
+
duration
|
|
63076
|
+
}
|
|
63077
|
+
});
|
|
63078
|
+
return;
|
|
63079
|
+
}
|
|
62724
63080
|
console.log();
|
|
62725
63081
|
console.log(source_default.dim(" Name:"), mediaName);
|
|
62726
63082
|
console.log(source_default.dim(" Type:"), mediaType);
|
|
@@ -62788,6 +63144,21 @@ timelineCommand.command("add-clip").description("Add a clip to the timeline").ar
|
|
|
62788
63144
|
});
|
|
62789
63145
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
62790
63146
|
spinner2.succeed(source_default.green(`Clip added: ${clip.id}`));
|
|
63147
|
+
if (isJsonMode()) {
|
|
63148
|
+
outputSuccess({
|
|
63149
|
+
command: "timeline add-clip",
|
|
63150
|
+
startedAt,
|
|
63151
|
+
data: {
|
|
63152
|
+
id: clip.id,
|
|
63153
|
+
sourceId,
|
|
63154
|
+
sourceName: source.name,
|
|
63155
|
+
trackId,
|
|
63156
|
+
startTime,
|
|
63157
|
+
duration
|
|
63158
|
+
}
|
|
63159
|
+
});
|
|
63160
|
+
return;
|
|
63161
|
+
}
|
|
62791
63162
|
console.log();
|
|
62792
63163
|
console.log(source_default.dim(" Source:"), source.name);
|
|
62793
63164
|
console.log(source_default.dim(" Track:"), trackId);
|
|
@@ -62835,6 +63206,18 @@ timelineCommand.command("add-track").description("Add a new track").argument("<p
|
|
|
62835
63206
|
});
|
|
62836
63207
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
62837
63208
|
spinner2.succeed(source_default.green(`Track added: ${track.id}`));
|
|
63209
|
+
if (isJsonMode()) {
|
|
63210
|
+
outputSuccess({
|
|
63211
|
+
command: "timeline add-track",
|
|
63212
|
+
startedAt,
|
|
63213
|
+
data: {
|
|
63214
|
+
id: track.id,
|
|
63215
|
+
name: track.name,
|
|
63216
|
+
type: track.type
|
|
63217
|
+
}
|
|
63218
|
+
});
|
|
63219
|
+
return;
|
|
63220
|
+
}
|
|
62838
63221
|
console.log();
|
|
62839
63222
|
console.log(source_default.dim(" Name:"), track.name);
|
|
62840
63223
|
console.log(source_default.dim(" Type:"), track.type);
|
|
@@ -62891,6 +63274,21 @@ timelineCommand.command("add-effect").description("Add an effect to a clip").arg
|
|
|
62891
63274
|
}
|
|
62892
63275
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
62893
63276
|
spinner2.succeed(source_default.green(`Effect added: ${effect.id}`));
|
|
63277
|
+
if (isJsonMode()) {
|
|
63278
|
+
outputSuccess({
|
|
63279
|
+
command: "timeline add-effect",
|
|
63280
|
+
startedAt,
|
|
63281
|
+
data: {
|
|
63282
|
+
id: effect.id,
|
|
63283
|
+
type: effectType,
|
|
63284
|
+
clipId,
|
|
63285
|
+
startTime,
|
|
63286
|
+
duration,
|
|
63287
|
+
params
|
|
63288
|
+
}
|
|
63289
|
+
});
|
|
63290
|
+
return;
|
|
63291
|
+
}
|
|
62894
63292
|
console.log();
|
|
62895
63293
|
console.log(source_default.dim(" Type:"), effectType);
|
|
62896
63294
|
console.log(source_default.dim(" Start:"), startTime, "s");
|
|
@@ -62940,6 +63338,18 @@ timelineCommand.command("trim").description("Trim a clip").argument("<project>",
|
|
|
62940
63338
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
62941
63339
|
const updatedClip = project.getClip(clipId);
|
|
62942
63340
|
spinner2.succeed(source_default.green("Clip trimmed"));
|
|
63341
|
+
if (isJsonMode()) {
|
|
63342
|
+
outputSuccess({
|
|
63343
|
+
command: "timeline trim",
|
|
63344
|
+
startedAt,
|
|
63345
|
+
data: {
|
|
63346
|
+
id: updatedClip.id,
|
|
63347
|
+
startTime: updatedClip.startTime,
|
|
63348
|
+
duration: updatedClip.duration
|
|
63349
|
+
}
|
|
63350
|
+
});
|
|
63351
|
+
return;
|
|
63352
|
+
}
|
|
62943
63353
|
console.log();
|
|
62944
63354
|
console.log(source_default.dim(" Start:"), updatedClip.startTime, "s");
|
|
62945
63355
|
console.log(source_default.dim(" Duration:"), updatedClip.duration, "s");
|
|
@@ -62950,17 +63360,61 @@ timelineCommand.command("trim").description("Trim a clip").argument("<project>",
|
|
|
62950
63360
|
}
|
|
62951
63361
|
});
|
|
62952
63362
|
timelineCommand.command("list").description("List timeline contents").argument("<project>", "Project file path").option("--sources", "List sources only").option("--tracks", "List tracks only").option("--clips", "List clips only").action(async (projectPath, options) => {
|
|
63363
|
+
const startedAt = Date.now();
|
|
62953
63364
|
try {
|
|
62954
63365
|
const filePath = resolve15(process.cwd(), projectPath);
|
|
62955
63366
|
const content = await readFile12(filePath, "utf-8");
|
|
62956
63367
|
const data = JSON.parse(content);
|
|
62957
63368
|
const project = Project.fromJSON(data);
|
|
62958
63369
|
const showAll = !options.sources && !options.tracks && !options.clips;
|
|
63370
|
+
const sources = project.getSources();
|
|
63371
|
+
const tracks = project.getTracks();
|
|
63372
|
+
const clips = project.getClips();
|
|
63373
|
+
if (isJsonMode()) {
|
|
63374
|
+
const result = {};
|
|
63375
|
+
if (showAll || options.sources) {
|
|
63376
|
+
result.sources = sources.map((s) => ({
|
|
63377
|
+
id: s.id,
|
|
63378
|
+
name: s.name,
|
|
63379
|
+
type: s.type,
|
|
63380
|
+
duration: s.duration
|
|
63381
|
+
}));
|
|
63382
|
+
}
|
|
63383
|
+
if (showAll || options.tracks) {
|
|
63384
|
+
result.tracks = tracks.map((t) => ({
|
|
63385
|
+
id: t.id,
|
|
63386
|
+
name: t.name,
|
|
63387
|
+
type: t.type,
|
|
63388
|
+
isMuted: t.isMuted,
|
|
63389
|
+
isLocked: t.isLocked,
|
|
63390
|
+
isVisible: t.isVisible
|
|
63391
|
+
}));
|
|
63392
|
+
}
|
|
63393
|
+
if (showAll || options.clips) {
|
|
63394
|
+
result.clips = clips.map((c) => {
|
|
63395
|
+
const source = project.getSource(c.sourceId);
|
|
63396
|
+
return {
|
|
63397
|
+
id: c.id,
|
|
63398
|
+
sourceId: c.sourceId,
|
|
63399
|
+
sourceName: source?.name ?? null,
|
|
63400
|
+
trackId: c.trackId,
|
|
63401
|
+
startTime: c.startTime,
|
|
63402
|
+
duration: c.duration,
|
|
63403
|
+
effects: c.effects.map((e) => ({ id: e.id, type: e.type }))
|
|
63404
|
+
};
|
|
63405
|
+
});
|
|
63406
|
+
}
|
|
63407
|
+
outputSuccess({
|
|
63408
|
+
command: "timeline list",
|
|
63409
|
+
startedAt,
|
|
63410
|
+
data: result
|
|
63411
|
+
});
|
|
63412
|
+
return;
|
|
63413
|
+
}
|
|
62959
63414
|
if (showAll || options.sources) {
|
|
62960
63415
|
console.log();
|
|
62961
63416
|
console.log(source_default.bold.cyan("Sources"));
|
|
62962
63417
|
console.log(source_default.dim("\u2500".repeat(60)));
|
|
62963
|
-
const sources = project.getSources();
|
|
62964
63418
|
if (sources.length === 0) {
|
|
62965
63419
|
console.log(source_default.dim(" (none)"));
|
|
62966
63420
|
} else {
|
|
@@ -62974,7 +63428,6 @@ timelineCommand.command("list").description("List timeline contents").argument("
|
|
|
62974
63428
|
console.log();
|
|
62975
63429
|
console.log(source_default.bold.cyan("Tracks"));
|
|
62976
63430
|
console.log(source_default.dim("\u2500".repeat(60)));
|
|
62977
|
-
const tracks = project.getTracks();
|
|
62978
63431
|
for (const track of tracks) {
|
|
62979
63432
|
const status = [
|
|
62980
63433
|
track.isMuted ? "muted" : null,
|
|
@@ -62989,7 +63442,6 @@ timelineCommand.command("list").description("List timeline contents").argument("
|
|
|
62989
63442
|
console.log();
|
|
62990
63443
|
console.log(source_default.bold.cyan("Clips"));
|
|
62991
63444
|
console.log(source_default.dim("\u2500".repeat(60)));
|
|
62992
|
-
const clips = project.getClips();
|
|
62993
63445
|
if (clips.length === 0) {
|
|
62994
63446
|
console.log(source_default.dim(" (none)"));
|
|
62995
63447
|
} else {
|
|
@@ -63051,6 +63503,17 @@ timelineCommand.command("split").description("Split a clip at a specific time").
|
|
|
63051
63503
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
63052
63504
|
const [first, second] = result;
|
|
63053
63505
|
spinner2.succeed(source_default.green("Clip split successfully"));
|
|
63506
|
+
if (isJsonMode()) {
|
|
63507
|
+
outputSuccess({
|
|
63508
|
+
command: "timeline split",
|
|
63509
|
+
startedAt,
|
|
63510
|
+
data: {
|
|
63511
|
+
first: { id: first.id, duration: first.duration },
|
|
63512
|
+
second: { id: second.id, duration: second.duration }
|
|
63513
|
+
}
|
|
63514
|
+
});
|
|
63515
|
+
return;
|
|
63516
|
+
}
|
|
63054
63517
|
console.log();
|
|
63055
63518
|
console.log(source_default.dim(" First clip:"), first.id, `(${first.duration.toFixed(2)}s)`);
|
|
63056
63519
|
console.log(source_default.dim(" Second clip:"), second.id, `(${second.duration.toFixed(2)}s)`);
|
|
@@ -63097,6 +63560,19 @@ timelineCommand.command("duplicate").description("Duplicate a clip").argument("<
|
|
|
63097
63560
|
}
|
|
63098
63561
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
63099
63562
|
spinner2.succeed(source_default.green(`Clip duplicated: ${duplicated.id}`));
|
|
63563
|
+
if (isJsonMode()) {
|
|
63564
|
+
outputSuccess({
|
|
63565
|
+
command: "timeline duplicate",
|
|
63566
|
+
startedAt,
|
|
63567
|
+
data: {
|
|
63568
|
+
id: duplicated.id,
|
|
63569
|
+
sourceClipId: clipId,
|
|
63570
|
+
startTime: duplicated.startTime,
|
|
63571
|
+
duration: duplicated.duration
|
|
63572
|
+
}
|
|
63573
|
+
});
|
|
63574
|
+
return;
|
|
63575
|
+
}
|
|
63100
63576
|
console.log();
|
|
63101
63577
|
console.log(source_default.dim(" Start:"), duplicated.startTime, "s");
|
|
63102
63578
|
console.log(source_default.dim(" Duration:"), duplicated.duration, "s");
|
|
@@ -63141,6 +63617,17 @@ timelineCommand.command("delete").description("Delete a clip from the timeline")
|
|
|
63141
63617
|
}
|
|
63142
63618
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
63143
63619
|
spinner2.succeed(source_default.green("Clip deleted"));
|
|
63620
|
+
if (isJsonMode()) {
|
|
63621
|
+
outputSuccess({
|
|
63622
|
+
command: "timeline delete",
|
|
63623
|
+
startedAt,
|
|
63624
|
+
data: {
|
|
63625
|
+
id: clipId,
|
|
63626
|
+
deleted: true
|
|
63627
|
+
}
|
|
63628
|
+
});
|
|
63629
|
+
return;
|
|
63630
|
+
}
|
|
63144
63631
|
} catch (error) {
|
|
63145
63632
|
spinner2.fail("Failed to delete clip");
|
|
63146
63633
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -63188,6 +63675,18 @@ timelineCommand.command("move").description("Move a clip to a new position").arg
|
|
|
63188
63675
|
await writeFile10(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
63189
63676
|
const updated = project.getClip(clipId);
|
|
63190
63677
|
spinner2.succeed(source_default.green("Clip moved"));
|
|
63678
|
+
if (isJsonMode()) {
|
|
63679
|
+
outputSuccess({
|
|
63680
|
+
command: "timeline move",
|
|
63681
|
+
startedAt,
|
|
63682
|
+
data: {
|
|
63683
|
+
id: updated.id,
|
|
63684
|
+
trackId: updated.trackId,
|
|
63685
|
+
startTime: updated.startTime
|
|
63686
|
+
}
|
|
63687
|
+
});
|
|
63688
|
+
return;
|
|
63689
|
+
}
|
|
63191
63690
|
console.log();
|
|
63192
63691
|
console.log(source_default.dim(" Track:"), updated.trackId);
|
|
63193
63692
|
console.log(source_default.dim(" Start:"), updated.startTime, "s");
|
|
@@ -63228,22 +63727,28 @@ init_sanitize();
|
|
|
63228
63727
|
init_validate();
|
|
63229
63728
|
import { readFile as readFile26, writeFile as writeFile31 } from "node:fs/promises";
|
|
63230
63729
|
import { resolve as resolve36 } from "node:path";
|
|
63231
|
-
var analyzeCommand = new Command("analyze").alias("az").description("
|
|
63730
|
+
var analyzeCommand = new Command("inspect").alias("analyze").alias("az").description("Inspect media using AI (images, videos, YouTube URLs)").hook("preAction", () => {
|
|
63731
|
+
const invoked = process.argv[2];
|
|
63732
|
+
if (invoked === "analyze" || invoked === "az") {
|
|
63733
|
+
emitDeprecationWarning(invoked, "inspect", "v1.0");
|
|
63734
|
+
}
|
|
63735
|
+
}).addHelpText(
|
|
63232
63736
|
"after",
|
|
63233
63737
|
`
|
|
63234
63738
|
Examples:
|
|
63235
|
-
$ vibe
|
|
63236
|
-
$ vibe
|
|
63237
|
-
$ vibe
|
|
63238
|
-
$ vibe
|
|
63239
|
-
$ vibe
|
|
63240
|
-
$ vibe
|
|
63739
|
+
$ vibe inspect media image.png "Describe this image"
|
|
63740
|
+
$ vibe inspect media video.mp4 "Summarize this video"
|
|
63741
|
+
$ vibe inspect media "https://youtube.com/watch?v=..." "Key takeaways"
|
|
63742
|
+
$ vibe inspect video video.mp4 "List all scene changes" --low-res
|
|
63743
|
+
$ vibe inspect review video.mp4 --auto-apply -o fixed.mp4
|
|
63744
|
+
$ vibe inspect suggest project.vibe.json "make it more dramatic"
|
|
63241
63745
|
|
|
63242
63746
|
API Keys:
|
|
63243
|
-
GOOGLE_API_KEY Required for all
|
|
63747
|
+
GOOGLE_API_KEY Required for all inspect commands (Gemini)
|
|
63244
63748
|
|
|
63749
|
+
Aliases: \`analyze\`, \`az\` (deprecated \u2014 removed in v1.0).
|
|
63245
63750
|
Use '--fields response,model' to limit output size.
|
|
63246
|
-
Run 'vibe schema
|
|
63751
|
+
Run 'vibe schema inspect.<command>' for structured parameter info.
|
|
63247
63752
|
`
|
|
63248
63753
|
);
|
|
63249
63754
|
analyzeCommand.command("media").description("Analyze any media: images, videos, or YouTube URLs using Gemini").argument("<source>", "Image/video file path, image URL, or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", "Model: flash (default), flash-2.5, pro", "flash").option("--fps <number>", "Frames per second for video (default: 1)").option("--start <seconds>", "Start offset in seconds (video only)").option("--end <seconds>", "End offset in seconds (video only)").option("--low-res", "Use low resolution mode (fewer tokens)").option("-v, --verbose", "Show token usage").option("--fields <fields>", "Comma-separated fields to include in output (e.g., response,model)").action(async (source, prompt3, options) => {
|
|
@@ -63438,18 +63943,19 @@ var audioCommand = new Command("audio").alias("au").description("Audio operation
|
|
|
63438
63943
|
Examples:
|
|
63439
63944
|
$ vibe audio transcribe interview.mp3 -o transcript.srt -f srt
|
|
63440
63945
|
$ vibe audio transcribe video.mp4 -l ko # Specify language
|
|
63441
|
-
$ vibe audio voices
|
|
63946
|
+
$ vibe audio list-voices # List available voices
|
|
63442
63947
|
$ vibe audio isolate song.mp3 -o vocals.mp3
|
|
63443
|
-
$ vibe audio voice
|
|
63948
|
+
$ vibe audio clone-voice sample.mp3 -n "my-voice"
|
|
63444
63949
|
$ vibe audio dub video.mp4 -l ko -o dubbed.mp4
|
|
63445
63950
|
$ vibe audio duck music.mp3 --voice narration.mp3 -o ducked.mp3
|
|
63446
63951
|
|
|
63447
63952
|
API Keys:
|
|
63448
63953
|
OPENAI_API_KEY transcribe (Whisper)
|
|
63449
|
-
ELEVENLABS_API_KEY voices, isolate, voice
|
|
63954
|
+
ELEVENLABS_API_KEY list-voices, isolate, clone-voice
|
|
63450
63955
|
OPENAI_API_KEY + ANTHROPIC_API_KEY + ELEVENLABS_API_KEY dub (full pipeline)
|
|
63451
63956
|
No key needed duck (FFmpeg only)
|
|
63452
63957
|
|
|
63958
|
+
Aliases (deprecated, removed in v1.0): voices \u2192 list-voices, voice-clone \u2192 clone-voice
|
|
63453
63959
|
Run 'vibe schema audio.<command>' for structured parameter info.
|
|
63454
63960
|
`
|
|
63455
63961
|
);
|
|
@@ -63513,7 +64019,9 @@ audioCommand.command("transcribe").description("Transcribe audio using Whisper")
|
|
|
63513
64019
|
exitWithError(apiError(`Transcription failed: ${msg}`, true));
|
|
63514
64020
|
}
|
|
63515
64021
|
});
|
|
63516
|
-
audioCommand.command("voices").description("List available ElevenLabs voices").
|
|
64022
|
+
audioCommand.command("list-voices").alias("voices").description("List available ElevenLabs voices").hook("preAction", () => {
|
|
64023
|
+
if (process.argv[3] === "voices") emitDeprecationWarning("audio voices", "audio list-voices", "v1.0");
|
|
64024
|
+
}).option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").action(async (options) => {
|
|
63517
64025
|
const startedAt = Date.now();
|
|
63518
64026
|
try {
|
|
63519
64027
|
const apiKey = await requireApiKey("ELEVENLABS_API_KEY", "ElevenLabs", options.apiKey);
|
|
@@ -63524,7 +64032,7 @@ audioCommand.command("voices").description("List available ElevenLabs voices").o
|
|
|
63524
64032
|
spinner2.succeed(source_default.green(`Found ${voices.length} voices`));
|
|
63525
64033
|
if (isJsonMode()) {
|
|
63526
64034
|
outputSuccess({
|
|
63527
|
-
command: "audio voices",
|
|
64035
|
+
command: "audio list-voices",
|
|
63528
64036
|
startedAt,
|
|
63529
64037
|
data: {
|
|
63530
64038
|
voices: voices.map((v) => ({ name: v.name, voiceId: v.voice_id, category: v.category, labels: v.labels }))
|
|
@@ -63591,12 +64099,14 @@ audioCommand.command("isolate").description("Isolate vocals from audio using Ele
|
|
|
63591
64099
|
exitWithError(apiError(`Audio isolation failed: ${msg}`, true));
|
|
63592
64100
|
}
|
|
63593
64101
|
});
|
|
63594
|
-
audioCommand.command("voice-clone").description("Clone a voice from audio samples using ElevenLabs").
|
|
64102
|
+
audioCommand.command("clone-voice").alias("voice-clone").description("Clone a voice from audio samples using ElevenLabs").hook("preAction", () => {
|
|
64103
|
+
if (process.argv[3] === "voice-clone") emitDeprecationWarning("audio voice-clone", "audio clone-voice", "v1.0");
|
|
64104
|
+
}).argument("[samples...]", "Audio sample files (1-25 files)").option("-k, --api-key <key>", "ElevenLabs API key (or set ELEVENLABS_API_KEY env)").option("-n, --name <name>", "Voice name (required)").option("-d, --description <desc>", "Voice description").option("--labels <json>", `Labels as JSON (e.g., '{"accent": "american"}')`).option("--remove-noise", "Remove background noise from samples").option("--list", "List all available voices").option("--dry-run", "Preview parameters without executing").action(async (samples, options) => {
|
|
63595
64105
|
const startedAt = Date.now();
|
|
63596
64106
|
try {
|
|
63597
64107
|
if (options.dryRun) {
|
|
63598
64108
|
outputSuccess({
|
|
63599
|
-
command: "audio voice
|
|
64109
|
+
command: "audio clone-voice",
|
|
63600
64110
|
startedAt,
|
|
63601
64111
|
dryRun: true,
|
|
63602
64112
|
data: { params: { samples: samples?.length, name: options.name } }
|
|
@@ -63657,7 +64167,7 @@ audioCommand.command("voice-clone").description("Clone a voice from audio sample
|
|
|
63657
64167
|
spinner2.succeed(source_default.green("Voice cloned successfully"));
|
|
63658
64168
|
if (isJsonMode()) {
|
|
63659
64169
|
outputSuccess({
|
|
63660
|
-
command: "audio voice
|
|
64170
|
+
command: "audio clone-voice",
|
|
63661
64171
|
startedAt,
|
|
63662
64172
|
data: { name: options.name, voiceId: result.voiceId }
|
|
63663
64173
|
});
|
|
@@ -64123,26 +64633,31 @@ function registerScriptPipelineCommands(aiCommand) {
|
|
|
64123
64633
|
init_ai_highlights();
|
|
64124
64634
|
init_ai_animated_caption();
|
|
64125
64635
|
init_output();
|
|
64126
|
-
var pipelineCommand = new Command("pipeline").alias("pipe").description(
|
|
64127
|
-
"AI media transformations on existing video / audio (highlights, auto-shorts, animated captions). For BUILD-from-text flows see `vibe
|
|
64128
|
-
).
|
|
64636
|
+
var pipelineCommand = new Command("remix").alias("pipeline").alias("pipe").description(
|
|
64637
|
+
"AI media transformations on existing video / audio (highlights, auto-shorts, animated captions). For BUILD-from-text flows see `vibe build`."
|
|
64638
|
+
).hook("preAction", () => {
|
|
64639
|
+
const invoked = process.argv[2];
|
|
64640
|
+
if (invoked === "pipeline" || invoked === "pipe") {
|
|
64641
|
+
emitDeprecationWarning(invoked, "remix", "v1.0");
|
|
64642
|
+
}
|
|
64643
|
+
}).addHelpText(
|
|
64129
64644
|
"after",
|
|
64130
64645
|
`
|
|
64131
64646
|
Two flows \u2014 pick by intent:
|
|
64132
64647
|
BUILD \u2014 text \u2192 MP4 (intent \u2192 AI generation \u2192 new video)
|
|
64133
|
-
Use \`vibe
|
|
64648
|
+
Use \`vibe build\` with a STORYBOARD.md + DESIGN.md.
|
|
64134
64649
|
Idempotent, agent-editable, skills-driven (v0.60+).
|
|
64135
|
-
|
|
64136
|
-
Use \`vibe
|
|
64650
|
+
REMIX \u2014 existing video/audio \u2192 transformed media
|
|
64651
|
+
Use \`vibe remix\` (this group) or \`vibe edit\` / \`vibe audio\`.
|
|
64137
64652
|
One-shot, batch-oriented, no storyboard required.
|
|
64138
64653
|
|
|
64139
|
-
Examples (
|
|
64140
|
-
$ vibe
|
|
64141
|
-
$ vibe
|
|
64142
|
-
$ vibe
|
|
64143
|
-
$ vibe
|
|
64654
|
+
Examples (REMIX):
|
|
64655
|
+
$ vibe remix highlights long-video.mp4 -o highlights.json -d 60
|
|
64656
|
+
$ vibe remix auto-shorts long-video.mp4 -o shorts/ -n 3 --add-captions
|
|
64657
|
+
$ vibe remix animated-caption video.mp4 -o captioned.mp4 -s highlight
|
|
64658
|
+
$ vibe remix animated-caption video.mp4 -o out.mp4 -s karaoke-sweep --fast
|
|
64144
64659
|
|
|
64145
|
-
|
|
64660
|
+
Provider API Keys:
|
|
64146
64661
|
highlights: GOOGLE_API_KEY (Gemini analysis)
|
|
64147
64662
|
auto-shorts: GOOGLE_API_KEY + OPENAI_API_KEY (optional captions)
|
|
64148
64663
|
animated-caption: OPENAI_API_KEY (Whisper transcription)
|
|
@@ -64153,12 +64668,9 @@ Cost tiers:
|
|
|
64153
64668
|
animated-caption: $ Low (~$0.01)
|
|
64154
64669
|
regenerate-scene: $$$ High (per-scene re-run; depends on provider)
|
|
64155
64670
|
|
|
64156
|
-
|
|
64157
|
-
text \u2192 MP4. \`pipeline regenerate-scene\` still operates on the
|
|
64158
|
-
storyboard.{yaml,json} layout produced by older runs.
|
|
64159
|
-
|
|
64671
|
+
Aliases: \`pipeline\`, \`pipe\` (deprecated \u2014 removed in v1.0).
|
|
64160
64672
|
Use '--dry-run' to preview parameters before execution.
|
|
64161
|
-
Run 'vibe schema
|
|
64673
|
+
Run 'vibe schema remix.<command>' for structured parameter info.
|
|
64162
64674
|
`
|
|
64163
64675
|
);
|
|
64164
64676
|
registerScriptPipelineCommands(pipelineCommand);
|
|
@@ -64168,9 +64680,9 @@ pipelineCommand.command("animated-caption").description("Add animated captions w
|
|
|
64168
64680
|
"after",
|
|
64169
64681
|
`
|
|
64170
64682
|
Examples:
|
|
64171
|
-
$ vibe
|
|
64172
|
-
$ vibe
|
|
64173
|
-
$ vibe
|
|
64683
|
+
$ vibe remix animated-caption video.mp4 -o captioned.mp4
|
|
64684
|
+
$ vibe remix animated-caption video.mp4 -o out.mp4 -s bounce
|
|
64685
|
+
$ vibe remix animated-caption video.mp4 -o out.mp4 -s karaoke-sweep --fast
|
|
64174
64686
|
|
|
64175
64687
|
Styles:
|
|
64176
64688
|
highlight (default) TikTok-style background highlight on active word (Remotion)
|
|
@@ -64343,18 +64855,36 @@ function listCommands(program3) {
|
|
|
64343
64855
|
console.log(JSON.stringify(commands, null, 2));
|
|
64344
64856
|
}
|
|
64345
64857
|
function extractEnumFromDescription(description) {
|
|
64346
|
-
const
|
|
64347
|
-
|
|
64858
|
+
const cleaned = description.replace(/\s*\([^()]*\)/g, "");
|
|
64859
|
+
const finalize = (raw) => {
|
|
64860
|
+
const values = raw.map((v) => v.trim().replace(/^or\s+/i, "")).filter(Boolean);
|
|
64861
|
+
if (values.some((v) => /\s/.test(v))) return void 0;
|
|
64862
|
+
if (values.length >= 2 && values.length <= 12) return values;
|
|
64863
|
+
return void 0;
|
|
64864
|
+
};
|
|
64865
|
+
const providerMatch = cleaned.match(
|
|
64866
|
+
/(?:Provider|Providers?):\s*([a-z0-9,\s-]+?)$/i
|
|
64348
64867
|
);
|
|
64349
64868
|
if (providerMatch) {
|
|
64350
|
-
|
|
64869
|
+
const values = finalize(providerMatch[1].split(","));
|
|
64870
|
+
if (values) return values;
|
|
64351
64871
|
}
|
|
64352
|
-
const
|
|
64353
|
-
/^[A-Z][a-z]
|
|
64872
|
+
const labeledMatch = cleaned.match(
|
|
64873
|
+
/^([A-Z][a-z]+(?:\s+[a-z]+){0,2}):\s*([a-z0-9:,\s/-]+?)$/
|
|
64354
64874
|
);
|
|
64355
|
-
if (
|
|
64356
|
-
|
|
64357
|
-
|
|
64875
|
+
if (labeledMatch) {
|
|
64876
|
+
return finalize(labeledMatch[2].split(","));
|
|
64877
|
+
}
|
|
64878
|
+
const parenMatch = description.match(/\(([^()]+)\)\s*$/);
|
|
64879
|
+
if (parenMatch) {
|
|
64880
|
+
const inner = parenMatch[1].trim();
|
|
64881
|
+
if (/^default:|^e\.g\.|^or\s|via\s|run\s/i.test(inner)) return void 0;
|
|
64882
|
+
const rawValues = inner.split(",").map((s) => s.trim()).filter(Boolean);
|
|
64883
|
+
const values = rawValues.map((v) => v.replace(/^or\s+/i, "").trim());
|
|
64884
|
+
const looksLikeEnum = values.every(
|
|
64885
|
+
(v) => /^[a-z0-9][a-z0-9:/_-]*$/i.test(v) && v.length <= 24
|
|
64886
|
+
);
|
|
64887
|
+
if (looksLikeEnum && values.length >= 2 && values.length <= 12) return values;
|
|
64358
64888
|
}
|
|
64359
64889
|
return void 0;
|
|
64360
64890
|
}
|
|
@@ -68849,7 +69379,7 @@ init_detect();
|
|
|
68849
69379
|
// src/commands/setup.ts
|
|
68850
69380
|
init_esm();
|
|
68851
69381
|
init_source();
|
|
68852
|
-
var
|
|
69382
|
+
var import_dotenv3 = __toESM(require_main(), 1);
|
|
68853
69383
|
init_config();
|
|
68854
69384
|
init_output();
|
|
68855
69385
|
init_tty();
|
|
@@ -68898,7 +69428,7 @@ var AI_FEATURES = [
|
|
|
68898
69428
|
{
|
|
68899
69429
|
label: "Videos",
|
|
68900
69430
|
desc: "generate + extend",
|
|
68901
|
-
defaultProvider: "
|
|
69431
|
+
defaultProvider: "Seedance 2.0 via fal.ai (Artificial Analysis #2 t2v + i2v, since v0.57)",
|
|
68902
69432
|
alsoAvailable: "Grok Imagine, Kling, Runway Gen-4.5, Google Veo",
|
|
68903
69433
|
keys: [{ configKey: "fal", envVar: "FAL_KEY", name: "fal.ai", url: "https://fal.ai/dashboard/keys", what: "ByteDance Seedance 2.0 text-to-video and image-to-video" }],
|
|
68904
69434
|
tryCommand: 'vibe generate video "ocean waves" -o waves.mp4'
|
|
@@ -68973,7 +69503,7 @@ async function runSetupWizard(fullSetup = false) {
|
|
|
68973
69503
|
console.log();
|
|
68974
69504
|
await collectKeys(config2, pipelineKeys);
|
|
68975
69505
|
await saveConfig(config2);
|
|
68976
|
-
showComplete(config2, "vibe
|
|
69506
|
+
showComplete(config2, "vibe build my-story/ # see CONTRIBUTING.md for STORYBOARD.md format");
|
|
68977
69507
|
return;
|
|
68978
69508
|
}
|
|
68979
69509
|
console.log(source_default.dim("Step 2 of 2"));
|
|
@@ -69138,7 +69668,7 @@ function showComplete(config2, defaultTryCommand, features = []) {
|
|
|
69138
69668
|
console.log(source_default.bold(" Next steps:"));
|
|
69139
69669
|
console.log(source_default.dim(" cd <project>; vibe init Scaffold AGENTS.md / CLAUDE.md / .env.example (project scope)"));
|
|
69140
69670
|
console.log(source_default.dim(" vibe doctor Check system health + available commands"));
|
|
69141
|
-
console.log(source_default.dim(" vibe schema --list Discover all
|
|
69671
|
+
console.log(source_default.dim(" vibe schema --list Discover all 81 commands"));
|
|
69142
69672
|
console.log(source_default.dim(" vibe setup Re-run user-scope setup anytime"));
|
|
69143
69673
|
const hosts = detectedAgentHosts();
|
|
69144
69674
|
const primary = hosts[0];
|
|
@@ -69151,14 +69681,14 @@ function showComplete(config2, defaultTryCommand, features = []) {
|
|
|
69151
69681
|
);
|
|
69152
69682
|
console.log(
|
|
69153
69683
|
source_default.dim(
|
|
69154
|
-
` Scene composer will auto-dispatch to ${primary.label} (${source_default.bold("--mode agent")}). Run \`vibe
|
|
69684
|
+
` Scene composer will auto-dispatch to ${primary.label} (${source_default.bold("--mode agent")}). Run \`vibe init my-promo\` to scaffold a video project + install local composition rules.`
|
|
69155
69685
|
)
|
|
69156
69686
|
);
|
|
69157
69687
|
} else {
|
|
69158
69688
|
console.log();
|
|
69159
69689
|
console.log(
|
|
69160
69690
|
source_default.dim(
|
|
69161
|
-
` No agent host detected \u2014 \`vibe
|
|
69691
|
+
` No agent host detected \u2014 \`vibe build\` will use the internal LLM composer (${source_default.bold("--mode batch")}).`
|
|
69162
69692
|
)
|
|
69163
69693
|
);
|
|
69164
69694
|
}
|
|
@@ -69207,7 +69737,7 @@ async function showConfig() {
|
|
|
69207
69737
|
if (hasCwdEnv) {
|
|
69208
69738
|
try {
|
|
69209
69739
|
const envContent = await readFile33(cwdEnvPath, "utf-8");
|
|
69210
|
-
dotenvKeys = (0,
|
|
69740
|
+
dotenvKeys = (0, import_dotenv3.parse)(Buffer.from(envContent));
|
|
69211
69741
|
} catch {
|
|
69212
69742
|
}
|
|
69213
69743
|
}
|
|
@@ -69269,6 +69799,9 @@ async function showConfig() {
|
|
|
69269
69799
|
init_esm();
|
|
69270
69800
|
init_source();
|
|
69271
69801
|
init_agent_host_detect();
|
|
69802
|
+
init_scene_project();
|
|
69803
|
+
init_visual_styles();
|
|
69804
|
+
init_install_skill();
|
|
69272
69805
|
import { existsSync as existsSync34 } from "node:fs";
|
|
69273
69806
|
import { mkdir as mkdir20, readFile as readFile34, writeFile as writeFile39 } from "node:fs/promises";
|
|
69274
69807
|
import { basename as basename19, dirname as dirname18, resolve as resolve48 } from "node:path";
|
|
@@ -69322,18 +69855,18 @@ VibeFrame splits cleanly into two flows. Routing the user's request
|
|
|
69322
69855
|
correctly is the most important judgement call you'll make.
|
|
69323
69856
|
|
|
69324
69857
|
**BUILD \u2014 create new video from text intent.**
|
|
69325
|
-
Use \`vibe
|
|
69858
|
+
Use \`vibe build\` with a STORYBOARD.md + DESIGN.md. The
|
|
69326
69859
|
skills-driven pipeline (v0.60+) dispatches narration TTS + backdrop
|
|
69327
|
-
image-gen per beat, composes scene HTML via the
|
|
69860
|
+
image-gen per beat, composes scene HTML via the bundled composition rules
|
|
69328
69861
|
bundle, then renders to MP4. Idempotent re-runs reuse cached assets.
|
|
69329
69862
|
|
|
69330
|
-
**
|
|
69331
|
-
Use \`vibe
|
|
69863
|
+
**REMIX \u2014 transform existing video / audio.**
|
|
69864
|
+
Use \`vibe remix\`, \`vibe edit\`, or \`vibe audio\`. One-shot,
|
|
69332
69865
|
batch-oriented operations on a file the user already has on disk.
|
|
69333
69866
|
|
|
69334
69867
|
Decision rule: if the user is starting from intent (a script, a brand,
|
|
69335
69868
|
an idea), it's BUILD. If the user is starting from a media file, it's
|
|
69336
|
-
|
|
69869
|
+
REMIX.
|
|
69337
69870
|
|
|
69338
69871
|
## Common workflows
|
|
69339
69872
|
|
|
@@ -69341,25 +69874,25 @@ PROCESS.
|
|
|
69341
69874
|
|
|
69342
69875
|
| Task | Command |
|
|
69343
69876
|
|---|---|
|
|
69344
|
-
| One-shot storyboard \u2192
|
|
69345
|
-
| Render an existing scene project | \`vibe
|
|
69877
|
+
| One-shot storyboard \u2192 video | \`vibe build [project-dir]\` |
|
|
69878
|
+
| Render an existing scene project | \`vibe render [project-dir] -o out.mp4\` |
|
|
69346
69879
|
| Lint scene HTML | \`vibe scene lint --json\` |
|
|
69347
69880
|
| Generate a single image | \`vibe generate image "prompt" -o img.png --quality hd\` |
|
|
69348
69881
|
| Generate a single video | \`vibe generate video "prompt" -i image.png -o clip.mp4\` |
|
|
69349
69882
|
| Generate narration | \`vibe generate speech "text" -o voice.mp3\` |
|
|
69350
69883
|
|
|
69351
|
-
###
|
|
69884
|
+
### REMIX (transform existing media)
|
|
69352
69885
|
|
|
69353
69886
|
| Task | Command |
|
|
69354
69887
|
|---|---|
|
|
69355
|
-
| Extract highlights from a long video | \`vibe
|
|
69356
|
-
| Long video \u2192 vertical shorts | \`vibe
|
|
69357
|
-
| Add animated word-by-word captions | \`vibe
|
|
69888
|
+
| Extract highlights from a long video | \`vibe remix highlights file.mp4 -d 60\` |
|
|
69889
|
+
| Long video \u2192 vertical shorts | \`vibe remix auto-shorts file.mp4 -n 3 --add-captions\` |
|
|
69890
|
+
| Add animated word-by-word captions | \`vibe remix animated-caption file.mp4 -s karaoke-sweep\` |
|
|
69358
69891
|
| Remove silence | \`vibe edit silence-cut in.mp4 -o out.mp4\` |
|
|
69359
69892
|
| Add static captions | \`vibe edit caption in.mp4 -o out.mp4\` |
|
|
69360
69893
|
| Translate audio (transcribe \u2192 TTS) | \`vibe audio dub file.mp4 -t ko\` |
|
|
69361
69894
|
| Transcribe (Whisper, word-level) | \`vibe audio transcribe file.mp4 --granularity word\` |
|
|
69362
|
-
|
|
|
69895
|
+
| Inspect a video | \`vibe inspect video file.mp4 "summarise"\` |
|
|
69363
69896
|
|
|
69364
69897
|
### Compose pipelines (Video as Code)
|
|
69365
69898
|
|
|
@@ -69373,9 +69906,9 @@ PROCESS.
|
|
|
69373
69906
|
| Tier | Examples | Approx. per call |
|
|
69374
69907
|
|---|---|---|
|
|
69375
69908
|
| **Free** | \`detect *\`, \`edit silence-cut/fade/noise-reduce\`, \`schema\`, \`project\`, \`timeline\` | $0 |
|
|
69376
|
-
| **Low** | \`
|
|
69909
|
+
| **Low** | \`inspect *\`, \`audio transcribe\`, \`generate image\` | $0.01\u2013$0.10 |
|
|
69377
69910
|
| **High** | \`generate video\`, \`edit image\` | $1\u2013$5 |
|
|
69378
|
-
| **Very High** | \`
|
|
69911
|
+
| **Very High** | \`remix *\` (highlights, auto-shorts, regenerate-scene), \`build\` | $5\u2013$50+ |
|
|
69379
69912
|
|
|
69380
69913
|
## Agent invariants
|
|
69381
69914
|
|
|
@@ -69387,7 +69920,7 @@ When you run vibe commands programmatically:
|
|
|
69387
69920
|
3. **Use \`vibe schema <command>\`** to discover parameters; do not guess flags
|
|
69388
69921
|
4. **Pass complex options via \`--stdin\`**:
|
|
69389
69922
|
\`\`\`bash
|
|
69390
|
-
echo '{"video":"long.mp4","count":3,"aspect":"9:16"}' | vibe
|
|
69923
|
+
echo '{"video":"long.mp4","count":3,"aspect":"9:16"}' | vibe remix auto-shorts --stdin --json
|
|
69391
69924
|
\`\`\`
|
|
69392
69925
|
|
|
69393
69926
|
## Provider keys
|
|
@@ -69396,9 +69929,9 @@ API keys live in \`.env\` (gitignored). Copy \`.env.example\` to start. Run
|
|
|
69396
69929
|
\`vibe doctor\` to see which keys are currently detected and which providers
|
|
69397
69930
|
they unlock.
|
|
69398
69931
|
|
|
69399
|
-
###
|
|
69932
|
+
### Composition rules (scene HTML)
|
|
69400
69933
|
|
|
69401
|
-
\`vibe
|
|
69934
|
+
\`vibe init\` installs local composition rules into your project. The
|
|
69402
69935
|
universal copy lives at \`SKILL.md\` (with \`references/*.md\`), and
|
|
69403
69936
|
host-specific copies are placed where each agent expects them
|
|
69404
69937
|
(\`.claude/skills/hyperframes/\` for Claude Code, \`.cursor/rules/hyperframes.mdc\`
|
|
@@ -69413,7 +69946,7 @@ To retro-install on a project scaffolded before this command existed, run
|
|
|
69413
69946
|
|
|
69414
69947
|
### Scene composer (batch / non-agent fallback)
|
|
69415
69948
|
|
|
69416
|
-
When you don't want to author HTML yourself, \`vibe
|
|
69949
|
+
When you don't want to author HTML yourself, \`vibe build --mode batch\` runs an
|
|
69417
69950
|
LLM internally with the same skill bundle. It auto-picks a provider based
|
|
69418
69951
|
on available keys (\`claude > gemini > openai\`) \u2014 pass \`--composer <name>\`
|
|
69419
69952
|
to force one:
|
|
@@ -69453,7 +69986,7 @@ pack is available as slash commands (consolidated to 2 in v0.62 \u2014 the
|
|
|
69453
69986
|
overview content moved into AGENTS.md above):
|
|
69454
69987
|
|
|
69455
69988
|
- \`/vibe-pipeline\` \u2014 YAML pipeline authoring helper (Video as Code)
|
|
69456
|
-
- \`/vibe-scene\` \u2014 per-scene HTML authoring + \`vibe
|
|
69989
|
+
- \`/vibe-scene\` \u2014 per-scene HTML authoring + \`vibe build\`
|
|
69457
69990
|
|
|
69458
69991
|
To install / update them later:
|
|
69459
69992
|
|
|
@@ -69518,7 +70051,7 @@ renders/
|
|
|
69518
70051
|
`;
|
|
69519
70052
|
function renderProjectYaml(opts) {
|
|
69520
70053
|
return `# VibeFrame project config. Used by \`vibe scene render\` to name
|
|
69521
|
-
# outputs and by \`vibe
|
|
70054
|
+
# outputs and by \`vibe build\` for default providers / budget.
|
|
69522
70055
|
name: ${opts.name}
|
|
69523
70056
|
aspect: "16:9"
|
|
69524
70057
|
defaults:
|
|
@@ -69539,8 +70072,16 @@ defaults:
|
|
|
69539
70072
|
// src/commands/init.ts
|
|
69540
70073
|
init_output();
|
|
69541
70074
|
var VALID_AGENTS = ["claude-code", "codex", "cursor", "aider", "gemini-cli", "opencode", "all", "auto"];
|
|
69542
|
-
var initCommand = new Command("init").description("Scaffold
|
|
70075
|
+
var initCommand = new Command("init").description("Scaffold a VibeFrame project (video scene project or project-scope agent files)").argument("[project-dir]", "Project directory (defaults to cwd)", ".").option("--type <type>", "Project type: scene (video project) | agent (agent files only)", "scene").option("--profile <profile>", "Scene profile: minimal (storyboard/design only), agent (recommended), full (render scaffold upfront)", "agent").option("-r, --ratio <ratio>", "Scene aspect ratio: 16:9, 9:16, 1:1, 4:5", "16:9").option("-d, --duration <sec>", "Default scene/root duration in seconds", "10").option("--visual-style <name>", "Seed scene DESIGN.md from a named style").option("--agent <id>", `Agent target: ${VALID_AGENTS.join(" | ")}`, "auto").option("--force", "Overwrite existing files instead of skipping").option("--dry-run", "Print the file list without writing anything").action(async (projectDirArg, options) => {
|
|
69543
70076
|
const startedAt = Date.now();
|
|
70077
|
+
const initType = String(options.type ?? "scene");
|
|
70078
|
+
if (initType !== "scene" && initType !== "agent") {
|
|
70079
|
+
exitWithError(usageError(`Invalid --type: ${initType}`, "Must be one of: scene, agent"));
|
|
70080
|
+
}
|
|
70081
|
+
if (initType === "scene") {
|
|
70082
|
+
await runSceneInit(projectDirArg, options, startedAt);
|
|
70083
|
+
return;
|
|
70084
|
+
}
|
|
69544
70085
|
const agent = options.agent;
|
|
69545
70086
|
if (!VALID_AGENTS.includes(agent)) {
|
|
69546
70087
|
exitWithError(usageError(`Invalid --agent: ${agent}`, `Must be one of: ${VALID_AGENTS.join(", ")}`));
|
|
@@ -69642,6 +70183,150 @@ var initCommand = new Command("init").description("Scaffold project-scope agent
|
|
|
69642
70183
|
console.log(source_default.dim(" vibe scene init my-promo Scaffold a starter scene project"));
|
|
69643
70184
|
console.log();
|
|
69644
70185
|
});
|
|
70186
|
+
var VALID_SCENE_ASPECTS = ["16:9", "9:16", "1:1", "4:5"];
|
|
70187
|
+
async function runSceneInit(projectDirArg, options, startedAt) {
|
|
70188
|
+
const profile = String(options.profile ?? "agent");
|
|
70189
|
+
if (!isSceneScaffoldProfile(profile)) {
|
|
70190
|
+
exitWithError(usageError(`Invalid --profile: ${profile}`, "Must be one of: minimal, agent, full"));
|
|
70191
|
+
}
|
|
70192
|
+
const aspect = String(options.ratio ?? "16:9");
|
|
70193
|
+
if (!VALID_SCENE_ASPECTS.includes(aspect)) {
|
|
70194
|
+
exitWithError(usageError(`Invalid --ratio: ${aspect}`, `Must be one of: ${VALID_SCENE_ASPECTS.join(", ")}`));
|
|
70195
|
+
}
|
|
70196
|
+
const duration = Number.parseFloat(String(options.duration ?? "10"));
|
|
70197
|
+
if (!Number.isFinite(duration) || duration <= 0 || duration > 3600) {
|
|
70198
|
+
exitWithError(usageError(`Invalid --duration: ${String(options.duration)}`, "Duration must be a positive number of seconds (\u22643600)"));
|
|
70199
|
+
}
|
|
70200
|
+
const visualStyle = options.visualStyle ? getVisualStyle(String(options.visualStyle)) : void 0;
|
|
70201
|
+
if (options.visualStyle && !visualStyle) {
|
|
70202
|
+
exitWithError(usageError(`Unknown visual style: ${String(options.visualStyle)}`, `Valid: ${visualStyleNames()}. Browse with \`vibe scene styles\`.`));
|
|
70203
|
+
}
|
|
70204
|
+
const projectDir = resolve48(projectDirArg);
|
|
70205
|
+
const projectName = basename19(projectDir);
|
|
70206
|
+
const groups = describeSceneScaffold({ dir: projectDir, profile });
|
|
70207
|
+
if (options.dryRun) {
|
|
70208
|
+
if (!isJsonMode()) {
|
|
70209
|
+
printSceneInitPlan({
|
|
70210
|
+
projectDir,
|
|
70211
|
+
profile,
|
|
70212
|
+
aspect,
|
|
70213
|
+
duration,
|
|
70214
|
+
visualStyleName: visualStyle?.name ?? null,
|
|
70215
|
+
groups,
|
|
70216
|
+
dryRun: true
|
|
70217
|
+
});
|
|
70218
|
+
return;
|
|
70219
|
+
}
|
|
70220
|
+
outputSuccess({
|
|
70221
|
+
command: "init",
|
|
70222
|
+
startedAt,
|
|
70223
|
+
dryRun: true,
|
|
70224
|
+
data: {
|
|
70225
|
+
type: "scene",
|
|
70226
|
+
projectDir,
|
|
70227
|
+
name: projectName,
|
|
70228
|
+
profile,
|
|
70229
|
+
aspect,
|
|
70230
|
+
duration,
|
|
70231
|
+
visualStyle: visualStyle?.name ?? null,
|
|
70232
|
+
groups
|
|
70233
|
+
}
|
|
70234
|
+
});
|
|
70235
|
+
return;
|
|
70236
|
+
}
|
|
70237
|
+
const result = await scaffoldSceneProject({
|
|
70238
|
+
dir: projectDir,
|
|
70239
|
+
name: projectName,
|
|
70240
|
+
aspect,
|
|
70241
|
+
duration,
|
|
70242
|
+
visualStyle,
|
|
70243
|
+
profile
|
|
70244
|
+
});
|
|
70245
|
+
const detectedIds = detectedAgentHosts().map((h) => h.id);
|
|
70246
|
+
const skillResult = profile === "agent" || profile === "full" ? await installHyperframesSkill({
|
|
70247
|
+
projectDir,
|
|
70248
|
+
hosts: deriveInstallHosts(detectedIds)
|
|
70249
|
+
}) : { success: true, files: [], bundleVersion: "not-installed" };
|
|
70250
|
+
if (isJsonMode()) {
|
|
70251
|
+
outputSuccess({
|
|
70252
|
+
command: "init",
|
|
70253
|
+
startedAt,
|
|
70254
|
+
data: {
|
|
70255
|
+
type: "scene",
|
|
70256
|
+
projectDir,
|
|
70257
|
+
name: projectName,
|
|
70258
|
+
profile,
|
|
70259
|
+
aspect,
|
|
70260
|
+
duration,
|
|
70261
|
+
visualStyle: visualStyle?.name ?? null,
|
|
70262
|
+
created: result.created,
|
|
70263
|
+
merged: result.merged,
|
|
70264
|
+
skipped: result.skipped,
|
|
70265
|
+
groups: result.groups,
|
|
70266
|
+
skillFiles: skillResult.files,
|
|
70267
|
+
skillBundleVersion: skillResult.bundleVersion
|
|
70268
|
+
}
|
|
70269
|
+
});
|
|
70270
|
+
return;
|
|
70271
|
+
}
|
|
70272
|
+
console.log();
|
|
70273
|
+
console.log(source_default.bold.magenta("VibeFrame Init") + source_default.dim(" \u2014 video project ready"));
|
|
70274
|
+
console.log(source_default.dim("\u2500".repeat(60)));
|
|
70275
|
+
console.log(`${source_default.dim("Project")} ${projectDir}`);
|
|
70276
|
+
console.log(`${source_default.dim("Profile")} ${profile} ${source_default.dim(sceneProfileSummary(profile))}`);
|
|
70277
|
+
console.log();
|
|
70278
|
+
console.log(source_default.bold("Edit first"));
|
|
70279
|
+
console.log(` ${source_default.cyan("STORYBOARD.md")} ${source_default.dim("beats: narration, backdrop, minimum duration")}`);
|
|
70280
|
+
console.log(` ${source_default.cyan("DESIGN.md")} ${source_default.dim("palette, typography, motion rules")}`);
|
|
70281
|
+
console.log();
|
|
70282
|
+
console.log(source_default.bold("Then run"));
|
|
70283
|
+
console.log(` ${source_default.cyan("vibe build")} ${source_default.dim("build storyboard assets/compositions")}`);
|
|
70284
|
+
console.log(` ${source_default.cyan("vibe render")} ${source_default.dim("render final MP4")}`);
|
|
70285
|
+
console.log();
|
|
70286
|
+
console.log(source_default.bold("Files"));
|
|
70287
|
+
for (const p of result.created) console.log(source_default.green(` + ${p.replace(projectDir + "/", "")}`));
|
|
70288
|
+
for (const p of result.merged) console.log(source_default.yellow(` ~ ${p.replace(projectDir + "/", "")} (merged)`));
|
|
70289
|
+
for (const p of result.skipped) console.log(source_default.dim(` \xB7 ${p.replace(projectDir + "/", "")} (kept existing)`));
|
|
70290
|
+
for (const f of skillResult.files.filter((f2) => f2.status === "wrote")) {
|
|
70291
|
+
console.log(source_default.green(` + ${f.path.replace(projectDir + "/", "")}`));
|
|
70292
|
+
}
|
|
70293
|
+
console.log();
|
|
70294
|
+
console.log(source_default.dim(`Tip: cd ${projectDirArg} before running the next commands.`));
|
|
70295
|
+
console.log();
|
|
70296
|
+
}
|
|
70297
|
+
function sceneProfileSummary(profile) {
|
|
70298
|
+
if (profile === "minimal") return "(storyboard/design only)";
|
|
70299
|
+
if (profile === "agent") return "(recommended: + local agent authoring rules)";
|
|
70300
|
+
return "(+ render scaffold upfront)";
|
|
70301
|
+
}
|
|
70302
|
+
function printSceneInitPlan(opts) {
|
|
70303
|
+
console.log();
|
|
70304
|
+
console.log(source_default.bold.magenta("VibeFrame Init") + source_default.dim(opts.dryRun ? " \u2014 dry run" : ""));
|
|
70305
|
+
console.log(source_default.dim("\u2500".repeat(60)));
|
|
70306
|
+
console.log(`${source_default.dim("Project")} ${opts.projectDir}`);
|
|
70307
|
+
console.log(`${source_default.dim("Profile")} ${opts.profile} ${source_default.dim(sceneProfileSummary(opts.profile))}`);
|
|
70308
|
+
console.log(`${source_default.dim("Canvas")} ${opts.aspect} \xB7 ${opts.duration}s default`);
|
|
70309
|
+
if (opts.visualStyleName) console.log(`${source_default.dim("Style")} ${opts.visualStyleName}`);
|
|
70310
|
+
console.log();
|
|
70311
|
+
console.log(source_default.bold("Edit first"));
|
|
70312
|
+
console.log(` ${source_default.cyan("STORYBOARD.md")} ${source_default.dim("beats: narration, backdrop, minimum duration")}`);
|
|
70313
|
+
console.log(` ${source_default.cyan("DESIGN.md")} ${source_default.dim("palette, typography, motion rules")}`);
|
|
70314
|
+
console.log();
|
|
70315
|
+
console.log(source_default.bold("Project contents"));
|
|
70316
|
+
printGroup("authoring", opts.groups.authoring, opts.projectDir);
|
|
70317
|
+
printGroup("agent", opts.groups.agent, opts.projectDir);
|
|
70318
|
+
printGroup("render", opts.groups.render, opts.projectDir);
|
|
70319
|
+
console.log();
|
|
70320
|
+
console.log(source_default.dim("Dry run \u2014 no files were written. Re-run without --dry-run to create the project."));
|
|
70321
|
+
console.log();
|
|
70322
|
+
}
|
|
70323
|
+
function printGroup(label, files, projectDir) {
|
|
70324
|
+
if (files.length === 0) return;
|
|
70325
|
+
console.log(` ${source_default.bold(label)}`);
|
|
70326
|
+
for (const file of files) {
|
|
70327
|
+
console.log(source_default.dim(` ${file.replace(projectDir + "/", "")}`));
|
|
70328
|
+
}
|
|
70329
|
+
}
|
|
69645
70330
|
function resolveTargets(agent) {
|
|
69646
70331
|
if (agent === "all") {
|
|
69647
70332
|
return ["claude-code", "codex", "cursor", "aider", "gemini-cli", "opencode"];
|
|
@@ -69696,6 +70381,306 @@ function formatStatusIcon(status) {
|
|
|
69696
70381
|
}
|
|
69697
70382
|
}
|
|
69698
70383
|
|
|
70384
|
+
// src/commands/build.ts
|
|
70385
|
+
init_esm();
|
|
70386
|
+
init_source();
|
|
70387
|
+
init_ora();
|
|
70388
|
+
init_scene_build();
|
|
70389
|
+
init_output();
|
|
70390
|
+
import { resolve as resolve49 } from "node:path";
|
|
70391
|
+
var VALID_MODES = ["agent", "batch", "auto"];
|
|
70392
|
+
var buildCommand = new Command("build").description("Build a VibeFrame video project from STORYBOARD.md").argument("[project-dir]", "Video project directory", ".").option("--mode <mode>", "Build mode: agent|batch|auto", "auto").option("--effort <level>", "Compose effort tier (batch mode only): low|medium|high", "medium").option("--composer <provider>", "Batch composer: claude|openai|gemini").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").option("--voice <id>", "Voice id").option("--image-provider <name>", "Image provider: openai").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").addHelpText("after", `
|
|
70393
|
+
Examples:
|
|
70394
|
+
$ vibe init my-video --profile agent
|
|
70395
|
+
$ vibe build my-video --mode agent --tts kokoro
|
|
70396
|
+
$ vibe build my-video --skip-render
|
|
70397
|
+
|
|
70398
|
+
Advanced equivalent: \`vibe scene build\`.`).action(async (projectDirArg, options) => {
|
|
70399
|
+
const startedAt = Date.now();
|
|
70400
|
+
const projectDir = resolve49(projectDirArg);
|
|
70401
|
+
const mode = String(options.mode ?? "auto");
|
|
70402
|
+
if (!VALID_MODES.includes(mode)) {
|
|
70403
|
+
exitWithError(usageError(`Invalid --mode: ${mode}`, `Must be one of: ${VALID_MODES.join(", ")}`));
|
|
70404
|
+
}
|
|
70405
|
+
const params = {
|
|
70406
|
+
projectDir,
|
|
70407
|
+
mode,
|
|
70408
|
+
effort: options.effort,
|
|
70409
|
+
composer: options.composer,
|
|
70410
|
+
skipNarration: options.skipNarration ?? false,
|
|
70411
|
+
skipBackdrop: options.skipBackdrop ?? false,
|
|
70412
|
+
skipRender: options.skipRender ?? false,
|
|
70413
|
+
ttsProvider: options.tts,
|
|
70414
|
+
voice: options.voice,
|
|
70415
|
+
imageProvider: options.imageProvider,
|
|
70416
|
+
imageQuality: options.quality,
|
|
70417
|
+
imageSize: options.imageSize,
|
|
70418
|
+
force: options.force ?? false
|
|
70419
|
+
};
|
|
70420
|
+
if (options.dryRun) {
|
|
70421
|
+
if (!isJsonMode() && !isQuietMode()) {
|
|
70422
|
+
printBuildDryRun(projectDirArg, params);
|
|
70423
|
+
return;
|
|
70424
|
+
}
|
|
70425
|
+
outputSuccess({
|
|
70426
|
+
command: "build",
|
|
70427
|
+
startedAt,
|
|
70428
|
+
dryRun: true,
|
|
70429
|
+
data: { params }
|
|
70430
|
+
});
|
|
70431
|
+
return;
|
|
70432
|
+
}
|
|
70433
|
+
const spinner2 = isJsonMode() || isQuietMode() ? null : ora("Building video project...").start();
|
|
70434
|
+
const result = await executeSceneBuild({
|
|
70435
|
+
projectDir,
|
|
70436
|
+
mode,
|
|
70437
|
+
effort: options.effort,
|
|
70438
|
+
composer: options.composer,
|
|
70439
|
+
skipNarration: options.skipNarration,
|
|
70440
|
+
skipBackdrop: options.skipBackdrop,
|
|
70441
|
+
skipRender: options.skipRender,
|
|
70442
|
+
ttsProvider: options.tts,
|
|
70443
|
+
voice: options.voice,
|
|
70444
|
+
imageProvider: options.imageProvider,
|
|
70445
|
+
imageQuality: options.quality,
|
|
70446
|
+
imageSize: options.imageSize,
|
|
70447
|
+
force: options.force,
|
|
70448
|
+
onProgress: (e) => {
|
|
70449
|
+
if (!spinner2) return;
|
|
70450
|
+
if (e.type === "phase-start") spinner2.text = `Phase: ${e.phase}...`;
|
|
70451
|
+
else if (e.type === "render-done") spinner2.text = `Rendered: ${e.outputPath}`;
|
|
70452
|
+
}
|
|
70453
|
+
});
|
|
70454
|
+
if (!result.success) {
|
|
70455
|
+
spinner2?.fail(`Build failed: ${result.error}`);
|
|
70456
|
+
if (isJsonMode()) {
|
|
70457
|
+
outputSuccess({ command: "build", startedAt, data: { ...result } });
|
|
70458
|
+
process.exitCode = 1;
|
|
70459
|
+
return;
|
|
70460
|
+
}
|
|
70461
|
+
exitWithError(generalError(result.error ?? "Build failed"));
|
|
70462
|
+
}
|
|
70463
|
+
if (isJsonMode() || isQuietMode()) {
|
|
70464
|
+
outputSuccess({ command: "build", startedAt, data: { ...result } });
|
|
70465
|
+
return;
|
|
70466
|
+
}
|
|
70467
|
+
if (result.phase === "needs-author") {
|
|
70468
|
+
printNeedsAuthor(result);
|
|
70469
|
+
return;
|
|
70470
|
+
}
|
|
70471
|
+
printBuildResult(spinner2, result, projectDirArg);
|
|
70472
|
+
});
|
|
70473
|
+
function printBuildDryRun(projectDirArg, params) {
|
|
70474
|
+
console.log();
|
|
70475
|
+
console.log(source_default.bold.cyan("VibeFrame Build - dry run"));
|
|
70476
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70477
|
+
console.log(` Project: ${source_default.bold(projectDirArg)}`);
|
|
70478
|
+
console.log(` Mode: ${source_default.bold(params.mode)}`);
|
|
70479
|
+
console.log(` Composer: ${source_default.bold(String(params.composer ?? "auto"))}`);
|
|
70480
|
+
console.log(` TTS: ${source_default.bold(String(params.ttsProvider ?? "auto"))}${params.skipNarration ? source_default.dim(" (skipped)") : ""}`);
|
|
70481
|
+
console.log(` Image: ${source_default.bold(String(params.imageProvider ?? "openai"))} ${source_default.dim(`${params.imageQuality} ${params.imageSize}`)}${params.skipBackdrop ? source_default.dim(" (skipped)") : ""}`);
|
|
70482
|
+
console.log(` Render: ${source_default.bold(params.skipRender ? "skip" : "yes")}`);
|
|
70483
|
+
console.log(` Regenerate: ${source_default.bold(params.force ? "yes" : "cache when possible")}`);
|
|
70484
|
+
console.log();
|
|
70485
|
+
console.log(source_default.dim("No assets, provider calls, or video files were created."));
|
|
70486
|
+
}
|
|
70487
|
+
function printNeedsAuthor(result) {
|
|
70488
|
+
console.log(source_default.cyan("Agent authoring required"));
|
|
70489
|
+
console.log();
|
|
70490
|
+
console.log(source_default.bold.cyan("Missing compositions"));
|
|
70491
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70492
|
+
const missing = result.composePrompts?.beats.filter((beat) => !beat.exists) ?? [];
|
|
70493
|
+
if (missing.length === 0) {
|
|
70494
|
+
console.log(source_default.dim(" No missing files were reported. Re-run `vibe build` to continue."));
|
|
70495
|
+
} else {
|
|
70496
|
+
for (const beat of missing) {
|
|
70497
|
+
const dur = beat.duration !== void 0 ? source_default.dim(` ${beat.duration}s`) : "";
|
|
70498
|
+
console.log(` ${source_default.bold(beat.id)}${dur} -> ${beat.outputPath}`);
|
|
70499
|
+
}
|
|
70500
|
+
}
|
|
70501
|
+
console.log();
|
|
70502
|
+
console.log(source_default.bold.cyan("Next"));
|
|
70503
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70504
|
+
console.log(" Ask your coding agent to author the missing HTML files.");
|
|
70505
|
+
console.log(" Then run: vibe build");
|
|
70506
|
+
console.log(source_default.dim(" Use `vibe build --mode batch` when you want the CLI to call an LLM composer instead."));
|
|
70507
|
+
}
|
|
70508
|
+
function printBuildResult(spinner2, result, projectDirArg) {
|
|
70509
|
+
spinner2?.succeed(source_default.green(result.outputPath ? `Build complete: ${result.outputPath}` : "Build complete"));
|
|
70510
|
+
console.log();
|
|
70511
|
+
console.log(source_default.bold.cyan("Beats"));
|
|
70512
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70513
|
+
for (const beat of result.beats) {
|
|
70514
|
+
const narration = formatPrimitiveStatus2(beat.narrationStatus, beat.narrationPath);
|
|
70515
|
+
const backdrop = formatPrimitiveStatus2(beat.backdropStatus, beat.backdropPath);
|
|
70516
|
+
console.log(` ${source_default.bold(beat.beatId.padEnd(12))} narration: ${narration} backdrop: ${backdrop}`);
|
|
70517
|
+
if (beat.narrationError) console.log(source_default.red(` ! narration: ${beat.narrationError}`));
|
|
70518
|
+
if (beat.backdropError) console.log(source_default.red(` ! backdrop: ${beat.backdropError}`));
|
|
70519
|
+
}
|
|
70520
|
+
if (result.composeData) {
|
|
70521
|
+
console.log();
|
|
70522
|
+
console.log(source_default.bold.cyan("Compose"));
|
|
70523
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70524
|
+
console.log(` beats ${result.composeData.beats}`);
|
|
70525
|
+
console.log(` cache ${result.composeData.cacheHits} hit / ${result.composeData.beats - result.composeData.cacheHits} fresh`);
|
|
70526
|
+
console.log(` cost $${result.composeData.totalCostUsd.toFixed(4)}`);
|
|
70527
|
+
}
|
|
70528
|
+
console.log();
|
|
70529
|
+
console.log(source_default.bold.cyan("Next"));
|
|
70530
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70531
|
+
if (result.outputPath) {
|
|
70532
|
+
console.log(` Watch: ${result.outputPath}`);
|
|
70533
|
+
} else {
|
|
70534
|
+
console.log(` Render: vibe render ${projectDirArg}`);
|
|
70535
|
+
}
|
|
70536
|
+
console.log(source_default.dim(` Total: ${(result.totalLatencyMs / 1e3).toFixed(1)}s`));
|
|
70537
|
+
}
|
|
70538
|
+
function formatPrimitiveStatus2(status, path2) {
|
|
70539
|
+
switch (status) {
|
|
70540
|
+
case "generated":
|
|
70541
|
+
return source_default.green(path2 ?? "generated");
|
|
70542
|
+
case "cached":
|
|
70543
|
+
return source_default.dim(path2 ?? "cached");
|
|
70544
|
+
case "skipped":
|
|
70545
|
+
return source_default.dim("skipped");
|
|
70546
|
+
case "missing":
|
|
70547
|
+
return source_default.yellow("missing cue");
|
|
70548
|
+
case "failed":
|
|
70549
|
+
return source_default.red("failed");
|
|
70550
|
+
default:
|
|
70551
|
+
return status;
|
|
70552
|
+
}
|
|
70553
|
+
}
|
|
70554
|
+
|
|
70555
|
+
// src/commands/render.ts
|
|
70556
|
+
init_esm();
|
|
70557
|
+
init_source();
|
|
70558
|
+
init_ora();
|
|
70559
|
+
init_scene_render();
|
|
70560
|
+
init_output();
|
|
70561
|
+
import { resolve as resolve50 } from "node:path";
|
|
70562
|
+
var VALID_FPS2 = [24, 30, 60];
|
|
70563
|
+
var VALID_QUALITIES2 = ["draft", "standard", "high"];
|
|
70564
|
+
var VALID_FORMATS2 = ["mp4", "webm", "mov"];
|
|
70565
|
+
var renderCommand = new Command("render").description("Render a VibeFrame video project to MP4/WebM/MOV").argument("[project-dir]", "Video project directory", ".").option("-o, --out <path>", "Output file (default: renders/<name>-<timestamp>.<format>)").option("--root <file>", "Root composition file", "index.html").option("--fps <n>", `Frames per second: ${VALID_FPS2.join("|")}`, "30").option("--quality <q>", `Quality preset: ${VALID_QUALITIES2.join("|")}`, "standard").option("--format <f>", `Output container: ${VALID_FORMATS2.join("|")}`, "mp4").option("--workers <n>", "Capture workers (1-16, default 1)", "1").option("--dry-run", "Preview parameters without rendering").addHelpText("after", `
|
|
70566
|
+
Examples:
|
|
70567
|
+
$ vibe render my-video
|
|
70568
|
+
$ vibe render my-video -o renders/final.mp4 --quality high
|
|
70569
|
+
|
|
70570
|
+
Alias note: this is the project-level entrypoint for \`vibe scene render\`.`).action(async (projectDirArg, options) => {
|
|
70571
|
+
const startedAt = Date.now();
|
|
70572
|
+
const projectDir = resolve50(projectDirArg);
|
|
70573
|
+
const fps = parseFps(String(options.fps));
|
|
70574
|
+
const quality = parseQuality(String(options.quality));
|
|
70575
|
+
const format = parseFormat(String(options.format));
|
|
70576
|
+
const workers = parseWorkers(String(options.workers));
|
|
70577
|
+
const params = {
|
|
70578
|
+
projectDir,
|
|
70579
|
+
root: options.root,
|
|
70580
|
+
output: options.out,
|
|
70581
|
+
fps,
|
|
70582
|
+
quality,
|
|
70583
|
+
format,
|
|
70584
|
+
workers
|
|
70585
|
+
};
|
|
70586
|
+
if (options.dryRun) {
|
|
70587
|
+
if (!isJsonMode() && !isQuietMode()) {
|
|
70588
|
+
printRenderDryRun(projectDirArg, params);
|
|
70589
|
+
return;
|
|
70590
|
+
}
|
|
70591
|
+
outputSuccess({
|
|
70592
|
+
command: "render",
|
|
70593
|
+
startedAt,
|
|
70594
|
+
dryRun: true,
|
|
70595
|
+
data: { params }
|
|
70596
|
+
});
|
|
70597
|
+
return;
|
|
70598
|
+
}
|
|
70599
|
+
const spinner2 = isJsonMode() || isQuietMode() ? null : ora("Rendering video project...").start();
|
|
70600
|
+
const result = await executeSceneRender({
|
|
70601
|
+
projectDir,
|
|
70602
|
+
root: options.root,
|
|
70603
|
+
output: options.out,
|
|
70604
|
+
fps,
|
|
70605
|
+
quality,
|
|
70606
|
+
format,
|
|
70607
|
+
workers,
|
|
70608
|
+
onProgress: (pct, stage) => {
|
|
70609
|
+
if (spinner2) spinner2.text = `Rendering [${Math.round(pct * 100)}%] ${stage}`;
|
|
70610
|
+
}
|
|
70611
|
+
});
|
|
70612
|
+
if (!result.success) {
|
|
70613
|
+
spinner2?.fail("Render failed");
|
|
70614
|
+
if (isJsonMode()) {
|
|
70615
|
+
outputSuccess({ command: "render", startedAt, data: { ...result } });
|
|
70616
|
+
process.exitCode = 1;
|
|
70617
|
+
return;
|
|
70618
|
+
}
|
|
70619
|
+
exitWithError(generalError(result.error ?? "Render failed"));
|
|
70620
|
+
}
|
|
70621
|
+
if (isJsonMode() || isQuietMode()) {
|
|
70622
|
+
outputSuccess({ command: "render", startedAt, data: { ...result } });
|
|
70623
|
+
return;
|
|
70624
|
+
}
|
|
70625
|
+
printRenderResult(spinner2, result);
|
|
70626
|
+
});
|
|
70627
|
+
function printRenderDryRun(projectDirArg, params) {
|
|
70628
|
+
console.log();
|
|
70629
|
+
console.log(source_default.bold.cyan("VibeFrame Render - dry run"));
|
|
70630
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70631
|
+
console.log(` Project: ${source_default.bold(projectDirArg)}`);
|
|
70632
|
+
console.log(` Root: ${source_default.bold(String(params.root))}`);
|
|
70633
|
+
console.log(` Output: ${source_default.bold(String(params.output ?? `renders/<name>-<timestamp>.${params.format}`))}`);
|
|
70634
|
+
console.log(` Format: ${source_default.bold(params.format)}`);
|
|
70635
|
+
console.log(` Quality/FPS: ${source_default.bold(`${params.quality} / ${params.fps}`)}`);
|
|
70636
|
+
console.log(` Workers: ${source_default.bold(String(params.workers))}`);
|
|
70637
|
+
console.log();
|
|
70638
|
+
console.log(source_default.dim("No browser capture, FFmpeg mux, or video files were created."));
|
|
70639
|
+
}
|
|
70640
|
+
function printRenderResult(spinner2, result) {
|
|
70641
|
+
spinner2?.succeed(source_default.green(`Render complete: ${result.outputPath}`));
|
|
70642
|
+
console.log();
|
|
70643
|
+
console.log(source_default.bold.cyan("Output"));
|
|
70644
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
70645
|
+
console.log(` File: ${source_default.bold(result.outputPath)}`);
|
|
70646
|
+
console.log(` Format: ${result.format ?? "mp4"}`);
|
|
70647
|
+
console.log(` Quality: ${result.quality ?? "standard"}`);
|
|
70648
|
+
console.log(` FPS: ${result.fps ?? 30}`);
|
|
70649
|
+
if (result.totalFrames !== void 0) console.log(` Frames: ${result.framesRendered ?? result.totalFrames}/${result.totalFrames}`);
|
|
70650
|
+
if (result.durationMs !== void 0) console.log(` Duration: ${(result.durationMs / 1e3).toFixed(2)}s`);
|
|
70651
|
+
if (result.audioCount !== void 0) {
|
|
70652
|
+
const audio = result.audioCount > 0 ? `${result.audioCount} track${result.audioCount === 1 ? "" : "s"} muxed` : "silent";
|
|
70653
|
+
console.log(` Audio: ${audio}`);
|
|
70654
|
+
}
|
|
70655
|
+
if (result.audioMuxWarning) console.log(source_default.yellow(` Warning: ${result.audioMuxWarning}`));
|
|
70656
|
+
}
|
|
70657
|
+
function parseFps(value) {
|
|
70658
|
+
const n = Number.parseInt(value, 10);
|
|
70659
|
+
if (!VALID_FPS2.includes(n)) {
|
|
70660
|
+
exitWithError(usageError(`Invalid --fps: ${value}`, `Valid: ${VALID_FPS2.join(", ")}`));
|
|
70661
|
+
}
|
|
70662
|
+
return n;
|
|
70663
|
+
}
|
|
70664
|
+
function parseQuality(value) {
|
|
70665
|
+
if (!VALID_QUALITIES2.includes(value)) {
|
|
70666
|
+
exitWithError(usageError(`Invalid --quality: ${value}`, `Valid: ${VALID_QUALITIES2.join(", ")}`));
|
|
70667
|
+
}
|
|
70668
|
+
return value;
|
|
70669
|
+
}
|
|
70670
|
+
function parseFormat(value) {
|
|
70671
|
+
if (!VALID_FORMATS2.includes(value)) {
|
|
70672
|
+
exitWithError(usageError(`Invalid --format: ${value}`, `Valid: ${VALID_FORMATS2.join(", ")}`));
|
|
70673
|
+
}
|
|
70674
|
+
return value;
|
|
70675
|
+
}
|
|
70676
|
+
function parseWorkers(value) {
|
|
70677
|
+
const n = Number.parseInt(value, 10);
|
|
70678
|
+
if (!Number.isFinite(n) || n < 1 || n > 16) {
|
|
70679
|
+
exitWithError(usageError(`Invalid --workers: ${value}`, "Must be an integer between 1 and 16"));
|
|
70680
|
+
}
|
|
70681
|
+
return n;
|
|
70682
|
+
}
|
|
70683
|
+
|
|
69699
70684
|
// src/commands/doctor.ts
|
|
69700
70685
|
init_esm();
|
|
69701
70686
|
init_source();
|
|
@@ -69711,7 +70696,7 @@ init_scene_build();
|
|
|
69711
70696
|
init_output();
|
|
69712
70697
|
import { access as access7 } from "node:fs/promises";
|
|
69713
70698
|
import { existsSync as existsSync35 } from "node:fs";
|
|
69714
|
-
import { resolve as
|
|
70699
|
+
import { resolve as resolve51 } from "node:path";
|
|
69715
70700
|
var COMMAND_KEY_MAP = getCommandKeyMap();
|
|
69716
70701
|
var FREE_COMMANDS = [
|
|
69717
70702
|
"edit silence-cut",
|
|
@@ -69868,7 +70853,7 @@ async function runDiagnostics() {
|
|
|
69868
70853
|
const cwd = process.cwd();
|
|
69869
70854
|
const projectFiles = ["AGENTS.md", "CLAUDE.md", "vibe.project.yaml"].map((rel) => ({
|
|
69870
70855
|
path: rel,
|
|
69871
|
-
exists: existsSync35(
|
|
70856
|
+
exists: existsSync35(resolve51(cwd, rel))
|
|
69872
70857
|
}));
|
|
69873
70858
|
const projectInitialized = projectFiles.some((f) => f.exists);
|
|
69874
70859
|
const hosts = detectAgentHosts();
|
|
@@ -69883,8 +70868,8 @@ async function runDiagnostics() {
|
|
|
69883
70868
|
} catch (err) {
|
|
69884
70869
|
if (!(err instanceof ComposerResolveError)) throw err;
|
|
69885
70870
|
}
|
|
69886
|
-
const sceneProjectInCwd = existsSync35(
|
|
69887
|
-
const skillInstalled = existsSync35(
|
|
70871
|
+
const sceneProjectInCwd = existsSync35(resolve51(cwd, "STORYBOARD.md"));
|
|
70872
|
+
const skillInstalled = existsSync35(resolve51(cwd, "SKILL.md"));
|
|
69888
70873
|
return {
|
|
69889
70874
|
system: {
|
|
69890
70875
|
node: { version: nodeVersion, ok: true },
|
|
@@ -70049,10 +71034,10 @@ init_exec_safe();
|
|
|
70049
71034
|
init_detect();
|
|
70050
71035
|
init_ai_edit();
|
|
70051
71036
|
init_output();
|
|
70052
|
-
import { resolve as
|
|
71037
|
+
import { resolve as resolve52 } from "node:path";
|
|
70053
71038
|
import { existsSync as existsSync36 } from "node:fs";
|
|
70054
71039
|
import { mkdir as mkdir21, rm as rm4 } from "node:fs/promises";
|
|
70055
|
-
var DEMO_DIR =
|
|
71040
|
+
var DEMO_DIR = resolve52(process.cwd(), ".vibeframe-demo");
|
|
70056
71041
|
async function generateTestVideo(outputPath) {
|
|
70057
71042
|
const filter = [
|
|
70058
71043
|
// Video: color bars with text
|
|
@@ -70132,7 +71117,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
70132
71117
|
console.log();
|
|
70133
71118
|
}
|
|
70134
71119
|
await mkdir21(DEMO_DIR, { recursive: true });
|
|
70135
|
-
const testVideo =
|
|
71120
|
+
const testVideo = resolve52(DEMO_DIR, "test-input.mp4");
|
|
70136
71121
|
const genSpinner = !isJson ? ora("Generating test video...").start() : null;
|
|
70137
71122
|
const generated = await generateTestVideo(testVideo);
|
|
70138
71123
|
if (!generated) {
|
|
@@ -70161,7 +71146,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
70161
71146
|
name: "Silence Cut",
|
|
70162
71147
|
description: "Removing silent segments",
|
|
70163
71148
|
run: async () => {
|
|
70164
|
-
const output =
|
|
71149
|
+
const output = resolve52(DEMO_DIR, "silence-cut.mp4");
|
|
70165
71150
|
const r = await executeSilenceCut({ videoPath: testVideo, outputPath: output, padding: 0.1 });
|
|
70166
71151
|
if (r.success && r.totalDuration && r.silentDuration) {
|
|
70167
71152
|
return { success: true, detail: `Removed ${r.silentDuration.toFixed(1)}s silence (${r.totalDuration.toFixed(1)}s \u2192 ${(r.totalDuration - r.silentDuration).toFixed(1)}s)` };
|
|
@@ -70173,7 +71158,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
70173
71158
|
name: "Noise Reduce",
|
|
70174
71159
|
description: "Reducing background noise",
|
|
70175
71160
|
run: async () => {
|
|
70176
|
-
const output =
|
|
71161
|
+
const output = resolve52(DEMO_DIR, "noise-reduced.mp4");
|
|
70177
71162
|
const r = await executeNoiseReduce({ inputPath: testVideo, outputPath: output, strength: "medium" });
|
|
70178
71163
|
return { success: r.success, detail: r.success ? `Cleaned audio \u2192 ${output}` : r.error };
|
|
70179
71164
|
}
|
|
@@ -70182,7 +71167,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
70182
71167
|
name: "Fade Effects",
|
|
70183
71168
|
description: "Adding fade in/out",
|
|
70184
71169
|
run: async () => {
|
|
70185
|
-
const output =
|
|
71170
|
+
const output = resolve52(DEMO_DIR, "faded.mp4");
|
|
70186
71171
|
const r = await executeFade({ videoPath: testVideo, outputPath: output, fadeIn: 1, fadeOut: 1 });
|
|
70187
71172
|
return { success: r.success, detail: r.success ? `1s fade in + 1s fade out \u2192 ${output}` : r.error };
|
|
70188
71173
|
}
|
|
@@ -70250,13 +71235,13 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
70250
71235
|
// src/commands/context.ts
|
|
70251
71236
|
init_esm();
|
|
70252
71237
|
import { readFile as readFile35 } from "node:fs/promises";
|
|
70253
|
-
import { resolve as
|
|
71238
|
+
import { resolve as resolve53, dirname as dirname19 } from "node:path";
|
|
70254
71239
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
70255
71240
|
var __filename = fileURLToPath2(import.meta.url);
|
|
70256
71241
|
var __dirname = dirname19(__filename);
|
|
70257
71242
|
var contextCommand = new Command("context").description("Print CLI context/guidelines for AI agent integration").action(async (_options, cmd) => {
|
|
70258
71243
|
const options = { json: cmd.parent?.opts()?.json || cmd.opts()?.json };
|
|
70259
|
-
const contextPath =
|
|
71244
|
+
const contextPath = resolve53(__dirname, "../../CONTEXT.md");
|
|
70260
71245
|
try {
|
|
70261
71246
|
const content = await readFile35(contextPath, "utf-8");
|
|
70262
71247
|
if (options.json) {
|
|
@@ -70997,14 +71982,14 @@ async function promptConfirm2(toolName, args) {
|
|
|
70997
71982
|
output: process.stdout,
|
|
70998
71983
|
terminal: process.stdin.isTTY ?? false
|
|
70999
71984
|
});
|
|
71000
|
-
return new Promise((
|
|
71985
|
+
return new Promise((resolve64) => {
|
|
71001
71986
|
const argsStr = JSON.stringify(args, null, 2);
|
|
71002
71987
|
console.log();
|
|
71003
71988
|
console.log(source_default.yellow(`Execute ${source_default.bold(toolName)}?`));
|
|
71004
71989
|
console.log(source_default.dim(argsStr));
|
|
71005
71990
|
rl.question(source_default.cyan("(y/n): "), (answer) => {
|
|
71006
71991
|
rl.close();
|
|
71007
|
-
|
|
71992
|
+
resolve64(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
71008
71993
|
});
|
|
71009
71994
|
});
|
|
71010
71995
|
}
|
|
@@ -71093,7 +72078,7 @@ async function startAgent(options = {}) {
|
|
|
71093
72078
|
console.log();
|
|
71094
72079
|
console.log(source_default.dim(" Commands: exit \xB7 reset \xB7 tools \xB7 context"));
|
|
71095
72080
|
console.log();
|
|
71096
|
-
return new Promise((
|
|
72081
|
+
return new Promise((resolve64) => {
|
|
71097
72082
|
if (typeof process.stdin.ref === "function") {
|
|
71098
72083
|
process.stdin.ref();
|
|
71099
72084
|
}
|
|
@@ -71195,7 +72180,7 @@ async function startAgent(options = {}) {
|
|
|
71195
72180
|
clearInterval(keepalive);
|
|
71196
72181
|
console.log();
|
|
71197
72182
|
console.log(source_default.dim("Goodbye!"));
|
|
71198
|
-
|
|
72183
|
+
resolve64();
|
|
71199
72184
|
});
|
|
71200
72185
|
rl.prompt();
|
|
71201
72186
|
});
|
|
@@ -71378,7 +72363,7 @@ async function readStdin() {
|
|
|
71378
72363
|
return Buffer.concat(chunks).toString("utf-8").trim();
|
|
71379
72364
|
}
|
|
71380
72365
|
var program2 = new Command();
|
|
71381
|
-
program2.name("vibe").showSuggestionAfterError(true).description("VibeFrame CLI - AI
|
|
72366
|
+
program2.name("vibe").showSuggestionAfterError(true).description("VibeFrame CLI - video projects, AI media generation, and workflow automation").version(package_default.version).option("--json", "Output in JSON format").option("-q, --quiet", "Output only the primary result value (path, URL, or ID)").option("--fields <fields>", "Limit JSON output to specific fields (comma-separated)").option("--stdin", "Read options from stdin as JSON (for agent/script use)").option("--describe", "Show JSON schema for the command and exit (no execution)").exitOverride().configureOutput({
|
|
71382
72367
|
outputError: (str, write2) => {
|
|
71383
72368
|
if (process.env.VIBE_JSON_OUTPUT === "1" || process.argv.includes("--json")) {
|
|
71384
72369
|
const err = { success: false, error: str.trim(), code: "USAGE_ERROR", exitCode: 2, retryable: false };
|
|
@@ -71398,20 +72383,38 @@ Global flags (work with any command):
|
|
|
71398
72383
|
--stdin Read options from stdin as JSON (for agent/script use)
|
|
71399
72384
|
--dry-run Preview without executing (most commands)
|
|
71400
72385
|
|
|
71401
|
-
|
|
71402
|
-
Free detect, edit (silence-cut/fade/noise-reduce), project, timeline, export
|
|
71403
|
-
Low analyze, audio transcribe, generate image ~$0.01-$0.10
|
|
71404
|
-
High generate video, edit image ~$1-$5
|
|
71405
|
-
V.High pipeline (regenerate-scene, highlights, auto-shorts) ~$5-$50+
|
|
71406
|
-
|
|
71407
|
-
Quick start:
|
|
72386
|
+
Get started (90% of users start here):
|
|
71408
72387
|
vibe doctor Check system health and API keys
|
|
71409
72388
|
vibe setup Configure API keys interactively
|
|
71410
|
-
vibe
|
|
71411
|
-
|
|
71412
|
-
|
|
71413
|
-
|
|
71414
|
-
|
|
72389
|
+
vibe init my-video Scaffold a video project
|
|
72390
|
+
vibe build my-video Build STORYBOARD.md into scene compositions/assets
|
|
72391
|
+
vibe render my-video Render the project to MP4
|
|
72392
|
+
vibe demo Try VibeFrame without API keys
|
|
72393
|
+
|
|
72394
|
+
One-shot media tools:
|
|
72395
|
+
vibe generate image "..." Generate a still image
|
|
72396
|
+
vibe generate video "..." Generate a standalone AI video
|
|
72397
|
+
vibe edit caption clip.mp4 -o out.mp4
|
|
72398
|
+
vibe inspect media clip.mp4 "Summarize this"
|
|
72399
|
+
vibe remix highlights long.mp4 -d 60
|
|
72400
|
+
|
|
72401
|
+
Advanced authoring:
|
|
72402
|
+
vibe project create my-video CRUD on .vibe.json
|
|
72403
|
+
vibe scene add intro --headline "Welcome"
|
|
72404
|
+
vibe timeline add-clip project.vibe.json <source-id>
|
|
72405
|
+
|
|
72406
|
+
Automation & agents:
|
|
72407
|
+
vibe run workflow.yaml Run a Video-as-YAML pipeline
|
|
72408
|
+
vibe agent Natural-language interface
|
|
72409
|
+
vibe schema generate.video Tool schema for any command
|
|
72410
|
+
vibe walkthrough scene Step-by-step authoring guide
|
|
72411
|
+
|
|
72412
|
+
Cost tiers (per call):
|
|
72413
|
+
Free detect, edit (silence-cut/fade/noise-reduce), project, timeline, export
|
|
72414
|
+
Low inspect, audio transcribe, generate image ~$0.01-$0.10
|
|
72415
|
+
High generate video, edit image ~$1-$5
|
|
72416
|
+
V.High remix (regenerate-scene, highlights, auto-shorts) ~$5-$50+
|
|
72417
|
+
Tip Add --dry-run before paid generation to preview the work.
|
|
71415
72418
|
`
|
|
71416
72419
|
);
|
|
71417
72420
|
program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -71478,6 +72481,8 @@ program2.addCommand(audioCommand);
|
|
|
71478
72481
|
program2.addCommand(pipelineCommand);
|
|
71479
72482
|
program2.addCommand(setupCommand);
|
|
71480
72483
|
program2.addCommand(initCommand);
|
|
72484
|
+
program2.addCommand(buildCommand);
|
|
72485
|
+
program2.addCommand(renderCommand);
|
|
71481
72486
|
program2.addCommand(doctorCommand);
|
|
71482
72487
|
program2.addCommand(demoCommand);
|
|
71483
72488
|
program2.addCommand(runCommand);
|
|
@@ -71485,7 +72490,7 @@ program2.addCommand(agentCommand);
|
|
|
71485
72490
|
program2.addCommand(projectCommand);
|
|
71486
72491
|
program2.addCommand(sceneCommand);
|
|
71487
72492
|
program2.addCommand(timelineCommand);
|
|
71488
|
-
program2.addCommand(exportCommand);
|
|
72493
|
+
program2.addCommand(exportCommand, { hidden: true });
|
|
71489
72494
|
program2.addCommand(detectCommand);
|
|
71490
72495
|
program2.addCommand(batchCommand);
|
|
71491
72496
|
program2.addCommand(schemaCommand);
|