@vibeframe/cli 0.115.1 → 0.115.2
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/commands/_shared/build-cache-model.test.d.ts +1 -0
- package/dist/commands/_shared/build-cache.d.ts +6 -0
- package/dist/commands/_shared/build-plan.d.ts +2 -0
- package/dist/commands/_shared/footage-assemble.d.ts +166 -0
- package/dist/commands/_shared/footage-assemble.test.d.ts +1 -0
- package/dist/commands/_shared/scene-build.d.ts +26 -1
- package/dist/commands/_shared/storyboard-parse.d.ts +7 -1
- package/dist/index.js +1065 -455
- package/dist/tools/manifest/index.js +1317 -794
- package/dist/tools/manifest/scene.d.ts +3 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -7768,7 +7768,7 @@ function errorMessage(error) {
|
|
|
7768
7768
|
return error instanceof Error ? error.message : "Unknown error";
|
|
7769
7769
|
}
|
|
7770
7770
|
function sleep(ms) {
|
|
7771
|
-
return new Promise((
|
|
7771
|
+
return new Promise((resolve87) => setTimeout(resolve87, ms));
|
|
7772
7772
|
}
|
|
7773
7773
|
var ProviderHttpError;
|
|
7774
7774
|
var init_http = __esm({
|
|
@@ -11655,14 +11655,14 @@ async function loadKokoroRuntime() {
|
|
|
11655
11655
|
async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
11656
11656
|
try {
|
|
11657
11657
|
const { readFile: readFile55 } = await import("node:fs/promises");
|
|
11658
|
-
const { join:
|
|
11658
|
+
const { join: join34, resolve: resolve87 } = await import("node:path");
|
|
11659
11659
|
const { pathToFileURL } = await import("node:url");
|
|
11660
|
-
const pkgDir =
|
|
11661
|
-
const pkg = JSON.parse(await readFile55(
|
|
11660
|
+
const pkgDir = resolve87(baseDir, "node_modules", "kokoro-js");
|
|
11661
|
+
const pkg = JSON.parse(await readFile55(join34(pkgDir, "package.json"), "utf-8"));
|
|
11662
11662
|
const entry = pkg.exports?.node?.import ?? pkg.exports?.default ?? pkg.module ?? pkg.main;
|
|
11663
11663
|
if (!entry)
|
|
11664
11664
|
return null;
|
|
11665
|
-
const mod = await import(pathToFileURL(
|
|
11665
|
+
const mod = await import(pathToFileURL(join34(pkgDir, entry)).href);
|
|
11666
11666
|
return mod.KokoroTTS ?? null;
|
|
11667
11667
|
} catch {
|
|
11668
11668
|
return null;
|
|
@@ -11673,20 +11673,20 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
11673
11673
|
if (!base)
|
|
11674
11674
|
return null;
|
|
11675
11675
|
try {
|
|
11676
|
-
const { readFile: readFile55, writeFile:
|
|
11677
|
-
const { join:
|
|
11676
|
+
const { readFile: readFile55, writeFile: writeFile57, mkdir: mkdir31 } = await import("node:fs/promises");
|
|
11677
|
+
const { join: join34, resolve: resolve87 } = await import("node:path");
|
|
11678
11678
|
const { pathToFileURL } = await import("node:url");
|
|
11679
11679
|
const { homedir: homedir8 } = await import("node:os");
|
|
11680
|
-
const transformersDir =
|
|
11681
|
-
const ortDistDir =
|
|
11682
|
-
const transformers = await import(pathToFileURL(
|
|
11683
|
-
const cacheRoot =
|
|
11680
|
+
const transformersDir = resolve87(base, "node_modules", "@huggingface", "transformers");
|
|
11681
|
+
const ortDistDir = resolve87(base, "node_modules", "onnxruntime-web", "dist");
|
|
11682
|
+
const transformers = await import(pathToFileURL(join34(transformersDir, "dist", "transformers.web.js")).href);
|
|
11683
|
+
const cacheRoot = join34(homedir8(), ".cache", "vibeframe", "models");
|
|
11684
11684
|
transformers.env.allowLocalModels = false;
|
|
11685
11685
|
transformers.env.useCustomCache = true;
|
|
11686
11686
|
transformers.env.customCache = {
|
|
11687
11687
|
async match(key) {
|
|
11688
11688
|
try {
|
|
11689
|
-
return new Response(await readFile55(
|
|
11689
|
+
return new Response(await readFile55(join34(cacheRoot, encodeURIComponent(String(key)))));
|
|
11690
11690
|
} catch {
|
|
11691
11691
|
return void 0;
|
|
11692
11692
|
}
|
|
@@ -11694,8 +11694,8 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
11694
11694
|
async put(key, response) {
|
|
11695
11695
|
try {
|
|
11696
11696
|
const buf = Buffer.from(await response.arrayBuffer());
|
|
11697
|
-
await
|
|
11698
|
-
await
|
|
11697
|
+
await mkdir31(cacheRoot, { recursive: true });
|
|
11698
|
+
await writeFile57(join34(cacheRoot, encodeURIComponent(String(key))), buf);
|
|
11699
11699
|
} catch {
|
|
11700
11700
|
}
|
|
11701
11701
|
}
|
|
@@ -12470,7 +12470,7 @@ var init_RunwayProvider = __esm({
|
|
|
12470
12470
|
* Sleep helper
|
|
12471
12471
|
*/
|
|
12472
12472
|
sleep(ms) {
|
|
12473
|
-
return new Promise((
|
|
12473
|
+
return new Promise((resolve87) => setTimeout(resolve87, ms));
|
|
12474
12474
|
}
|
|
12475
12475
|
};
|
|
12476
12476
|
RunwayProvider.API_VERSION = "2024-11-06";
|
|
@@ -12911,7 +12911,7 @@ var init_KlingProvider = __esm({
|
|
|
12911
12911
|
* Sleep helper
|
|
12912
12912
|
*/
|
|
12913
12913
|
sleep(ms) {
|
|
12914
|
-
return new Promise((
|
|
12914
|
+
return new Promise((resolve87) => setTimeout(resolve87, ms));
|
|
12915
12915
|
}
|
|
12916
12916
|
};
|
|
12917
12917
|
klingProvider = new KlingProvider();
|
|
@@ -13229,7 +13229,7 @@ var init_GrokProvider = __esm({
|
|
|
13229
13229
|
}
|
|
13230
13230
|
}
|
|
13231
13231
|
sleep(ms) {
|
|
13232
|
-
return new Promise((
|
|
13232
|
+
return new Promise((resolve87) => setTimeout(resolve87, ms));
|
|
13233
13233
|
}
|
|
13234
13234
|
};
|
|
13235
13235
|
grokProvider = new GrokProvider();
|
|
@@ -13264,11 +13264,11 @@ var require_middleware = __commonJS({
|
|
|
13264
13264
|
"use strict";
|
|
13265
13265
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
13266
13266
|
function adopt(value) {
|
|
13267
|
-
return value instanceof P ? value : new P(function(
|
|
13268
|
-
|
|
13267
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
13268
|
+
resolve87(value);
|
|
13269
13269
|
});
|
|
13270
13270
|
}
|
|
13271
|
-
return new (P || (P = Promise))(function(
|
|
13271
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
13272
13272
|
function fulfilled(value) {
|
|
13273
13273
|
try {
|
|
13274
13274
|
step(generator.next(value));
|
|
@@ -13284,7 +13284,7 @@ var require_middleware = __commonJS({
|
|
|
13284
13284
|
}
|
|
13285
13285
|
}
|
|
13286
13286
|
function step(result) {
|
|
13287
|
-
result.done ?
|
|
13287
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
13288
13288
|
}
|
|
13289
13289
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13290
13290
|
});
|
|
@@ -13369,11 +13369,11 @@ var require_response = __commonJS({
|
|
|
13369
13369
|
"use strict";
|
|
13370
13370
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
13371
13371
|
function adopt(value) {
|
|
13372
|
-
return value instanceof P ? value : new P(function(
|
|
13373
|
-
|
|
13372
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
13373
|
+
resolve87(value);
|
|
13374
13374
|
});
|
|
13375
13375
|
}
|
|
13376
|
-
return new (P || (P = Promise))(function(
|
|
13376
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
13377
13377
|
function fulfilled(value) {
|
|
13378
13378
|
try {
|
|
13379
13379
|
step(generator.next(value));
|
|
@@ -13389,7 +13389,7 @@ var require_response = __commonJS({
|
|
|
13389
13389
|
}
|
|
13390
13390
|
}
|
|
13391
13391
|
function step(result) {
|
|
13392
|
-
result.done ?
|
|
13392
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
13393
13393
|
}
|
|
13394
13394
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13395
13395
|
});
|
|
@@ -13496,11 +13496,11 @@ var require_utils = __commonJS({
|
|
|
13496
13496
|
"use strict";
|
|
13497
13497
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
13498
13498
|
function adopt(value) {
|
|
13499
|
-
return value instanceof P ? value : new P(function(
|
|
13500
|
-
|
|
13499
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
13500
|
+
resolve87(value);
|
|
13501
13501
|
});
|
|
13502
13502
|
}
|
|
13503
|
-
return new (P || (P = Promise))(function(
|
|
13503
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
13504
13504
|
function fulfilled(value) {
|
|
13505
13505
|
try {
|
|
13506
13506
|
step(generator.next(value));
|
|
@@ -13516,7 +13516,7 @@ var require_utils = __commonJS({
|
|
|
13516
13516
|
}
|
|
13517
13517
|
}
|
|
13518
13518
|
function step(result) {
|
|
13519
|
-
result.done ?
|
|
13519
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
13520
13520
|
}
|
|
13521
13521
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13522
13522
|
});
|
|
@@ -13609,7 +13609,7 @@ var require_utils = __commonJS({
|
|
|
13609
13609
|
}
|
|
13610
13610
|
function sleep3(ms) {
|
|
13611
13611
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13612
|
-
return new Promise((
|
|
13612
|
+
return new Promise((resolve87) => setTimeout(resolve87, ms));
|
|
13613
13613
|
});
|
|
13614
13614
|
}
|
|
13615
13615
|
}
|
|
@@ -13621,11 +13621,11 @@ var require_retry = __commonJS({
|
|
|
13621
13621
|
"use strict";
|
|
13622
13622
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
13623
13623
|
function adopt(value) {
|
|
13624
|
-
return value instanceof P ? value : new P(function(
|
|
13625
|
-
|
|
13624
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
13625
|
+
resolve87(value);
|
|
13626
13626
|
});
|
|
13627
13627
|
}
|
|
13628
|
-
return new (P || (P = Promise))(function(
|
|
13628
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
13629
13629
|
function fulfilled(value) {
|
|
13630
13630
|
try {
|
|
13631
13631
|
step(generator.next(value));
|
|
@@ -13641,7 +13641,7 @@ var require_retry = __commonJS({
|
|
|
13641
13641
|
}
|
|
13642
13642
|
}
|
|
13643
13643
|
function step(result) {
|
|
13644
|
-
result.done ?
|
|
13644
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
13645
13645
|
}
|
|
13646
13646
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13647
13647
|
});
|
|
@@ -13848,11 +13848,11 @@ var require_request = __commonJS({
|
|
|
13848
13848
|
"use strict";
|
|
13849
13849
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
13850
13850
|
function adopt(value) {
|
|
13851
|
-
return value instanceof P ? value : new P(function(
|
|
13852
|
-
|
|
13851
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
13852
|
+
resolve87(value);
|
|
13853
13853
|
});
|
|
13854
13854
|
}
|
|
13855
|
-
return new (P || (P = Promise))(function(
|
|
13855
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
13856
13856
|
function fulfilled(value) {
|
|
13857
13857
|
try {
|
|
13858
13858
|
step(generator.next(value));
|
|
@@ -13868,7 +13868,7 @@ var require_request = __commonJS({
|
|
|
13868
13868
|
}
|
|
13869
13869
|
}
|
|
13870
13870
|
function step(result) {
|
|
13871
|
-
result.done ?
|
|
13871
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
13872
13872
|
}
|
|
13873
13873
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13874
13874
|
});
|
|
@@ -13955,11 +13955,11 @@ var require_storage = __commonJS({
|
|
|
13955
13955
|
"use strict";
|
|
13956
13956
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
13957
13957
|
function adopt(value) {
|
|
13958
|
-
return value instanceof P ? value : new P(function(
|
|
13959
|
-
|
|
13958
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
13959
|
+
resolve87(value);
|
|
13960
13960
|
});
|
|
13961
13961
|
}
|
|
13962
|
-
return new (P || (P = Promise))(function(
|
|
13962
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
13963
13963
|
function fulfilled(value) {
|
|
13964
13964
|
try {
|
|
13965
13965
|
step(generator.next(value));
|
|
@@ -13975,7 +13975,7 @@ var require_storage = __commonJS({
|
|
|
13975
13975
|
}
|
|
13976
13976
|
}
|
|
13977
13977
|
function step(result) {
|
|
13978
|
-
result.done ?
|
|
13978
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
13979
13979
|
}
|
|
13980
13980
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13981
13981
|
});
|
|
@@ -14303,11 +14303,11 @@ var require_auth = __commonJS({
|
|
|
14303
14303
|
"use strict";
|
|
14304
14304
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
14305
14305
|
function adopt(value) {
|
|
14306
|
-
return value instanceof P ? value : new P(function(
|
|
14307
|
-
|
|
14306
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
14307
|
+
resolve87(value);
|
|
14308
14308
|
});
|
|
14309
14309
|
}
|
|
14310
|
-
return new (P || (P = Promise))(function(
|
|
14310
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
14311
14311
|
function fulfilled(value) {
|
|
14312
14312
|
try {
|
|
14313
14313
|
step(generator.next(value));
|
|
@@ -14323,7 +14323,7 @@ var require_auth = __commonJS({
|
|
|
14323
14323
|
}
|
|
14324
14324
|
}
|
|
14325
14325
|
function step(result) {
|
|
14326
|
-
result.done ?
|
|
14326
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
14327
14327
|
}
|
|
14328
14328
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14329
14329
|
});
|
|
@@ -14362,11 +14362,11 @@ var require_streaming = __commonJS({
|
|
|
14362
14362
|
"use strict";
|
|
14363
14363
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
14364
14364
|
function adopt(value) {
|
|
14365
|
-
return value instanceof P ? value : new P(function(
|
|
14366
|
-
|
|
14365
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
14366
|
+
resolve87(value);
|
|
14367
14367
|
});
|
|
14368
14368
|
}
|
|
14369
|
-
return new (P || (P = Promise))(function(
|
|
14369
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
14370
14370
|
function fulfilled(value) {
|
|
14371
14371
|
try {
|
|
14372
14372
|
step(generator.next(value));
|
|
@@ -14382,7 +14382,7 @@ var require_streaming = __commonJS({
|
|
|
14382
14382
|
}
|
|
14383
14383
|
}
|
|
14384
14384
|
function step(result) {
|
|
14385
|
-
result.done ?
|
|
14385
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
14386
14386
|
}
|
|
14387
14387
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14388
14388
|
});
|
|
@@ -14615,7 +14615,7 @@ var require_streaming = __commonJS({
|
|
|
14615
14615
|
query: options.queryParams
|
|
14616
14616
|
});
|
|
14617
14617
|
this.options = options;
|
|
14618
|
-
this.donePromise = new Promise((
|
|
14618
|
+
this.donePromise = new Promise((resolve87, reject) => {
|
|
14619
14619
|
if (this.streamClosed) {
|
|
14620
14620
|
reject(new response_1.ApiError({
|
|
14621
14621
|
message: "Streaming connection is already closed.",
|
|
@@ -14626,11 +14626,11 @@ var require_streaming = __commonJS({
|
|
|
14626
14626
|
}
|
|
14627
14627
|
this.signal.addEventListener("abort", () => {
|
|
14628
14628
|
var _a2;
|
|
14629
|
-
|
|
14629
|
+
resolve87((_a2 = this.currentData) !== null && _a2 !== void 0 ? _a2 : {});
|
|
14630
14630
|
});
|
|
14631
14631
|
this.on("done", (data) => {
|
|
14632
14632
|
this.streamClosed = true;
|
|
14633
|
-
|
|
14633
|
+
resolve87(data);
|
|
14634
14634
|
});
|
|
14635
14635
|
this.on("error", (error) => {
|
|
14636
14636
|
this.streamClosed = true;
|
|
@@ -14655,7 +14655,7 @@ var require_streaming = __commonJS({
|
|
|
14655
14655
|
if (data) {
|
|
14656
14656
|
yield yield __await(data);
|
|
14657
14657
|
}
|
|
14658
|
-
yield __await(new Promise((
|
|
14658
|
+
yield __await(new Promise((resolve87) => setTimeout(resolve87, 16)));
|
|
14659
14659
|
}
|
|
14660
14660
|
});
|
|
14661
14661
|
}
|
|
@@ -14700,11 +14700,11 @@ var require_queue = __commonJS({
|
|
|
14700
14700
|
"use strict";
|
|
14701
14701
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
14702
14702
|
function adopt(value) {
|
|
14703
|
-
return value instanceof P ? value : new P(function(
|
|
14704
|
-
|
|
14703
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
14704
|
+
resolve87(value);
|
|
14705
14705
|
});
|
|
14706
14706
|
}
|
|
14707
|
-
return new (P || (P = Promise))(function(
|
|
14707
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
14708
14708
|
function fulfilled(value) {
|
|
14709
14709
|
try {
|
|
14710
14710
|
step(generator.next(value));
|
|
@@ -14720,7 +14720,7 @@ var require_queue = __commonJS({
|
|
|
14720
14720
|
}
|
|
14721
14721
|
}
|
|
14722
14722
|
function step(result) {
|
|
14723
|
-
result.done ?
|
|
14723
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
14724
14724
|
}
|
|
14725
14725
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14726
14726
|
});
|
|
@@ -14855,7 +14855,7 @@ var require_queue = __commonJS({
|
|
|
14855
14855
|
}
|
|
14856
14856
|
return doneStatus;
|
|
14857
14857
|
}
|
|
14858
|
-
return new Promise((
|
|
14858
|
+
return new Promise((resolve87, reject) => {
|
|
14859
14859
|
var _a;
|
|
14860
14860
|
let pollingTimeoutId;
|
|
14861
14861
|
const pollInterval = "pollInterval" in options && typeof options.pollInterval === "number" ? (_a = options.pollInterval) !== null && _a !== void 0 ? _a : DEFAULT_POLL_INTERVAL : DEFAULT_POLL_INTERVAL;
|
|
@@ -14887,7 +14887,7 @@ var require_queue = __commonJS({
|
|
|
14887
14887
|
}
|
|
14888
14888
|
if (requestStatus.status === "COMPLETED") {
|
|
14889
14889
|
clearScheduledTasks();
|
|
14890
|
-
|
|
14890
|
+
resolve87(requestStatus);
|
|
14891
14891
|
return;
|
|
14892
14892
|
}
|
|
14893
14893
|
pollingTimeoutId = setTimeout(poll, pollInterval);
|
|
@@ -16848,11 +16848,11 @@ var require_realtime = __commonJS({
|
|
|
16848
16848
|
"use strict";
|
|
16849
16849
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
16850
16850
|
function adopt(value) {
|
|
16851
|
-
return value instanceof P ? value : new P(function(
|
|
16852
|
-
|
|
16851
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
16852
|
+
resolve87(value);
|
|
16853
16853
|
});
|
|
16854
16854
|
}
|
|
16855
|
-
return new (P || (P = Promise))(function(
|
|
16855
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
16856
16856
|
function fulfilled(value) {
|
|
16857
16857
|
try {
|
|
16858
16858
|
step(generator.next(value));
|
|
@@ -16868,7 +16868,7 @@ var require_realtime = __commonJS({
|
|
|
16868
16868
|
}
|
|
16869
16869
|
}
|
|
16870
16870
|
function step(result) {
|
|
16871
|
-
result.done ?
|
|
16871
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
16872
16872
|
}
|
|
16873
16873
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16874
16874
|
});
|
|
@@ -17193,11 +17193,11 @@ var require_client = __commonJS({
|
|
|
17193
17193
|
"use strict";
|
|
17194
17194
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
17195
17195
|
function adopt(value) {
|
|
17196
|
-
return value instanceof P ? value : new P(function(
|
|
17197
|
-
|
|
17196
|
+
return value instanceof P ? value : new P(function(resolve87) {
|
|
17197
|
+
resolve87(value);
|
|
17198
17198
|
});
|
|
17199
17199
|
}
|
|
17200
|
-
return new (P || (P = Promise))(function(
|
|
17200
|
+
return new (P || (P = Promise))(function(resolve87, reject) {
|
|
17201
17201
|
function fulfilled(value) {
|
|
17202
17202
|
try {
|
|
17203
17203
|
step(generator.next(value));
|
|
@@ -17213,7 +17213,7 @@ var require_client = __commonJS({
|
|
|
17213
17213
|
}
|
|
17214
17214
|
}
|
|
17215
17215
|
function step(result) {
|
|
17216
|
-
result.done ?
|
|
17216
|
+
result.done ? resolve87(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
17217
17217
|
}
|
|
17218
17218
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
17219
17219
|
});
|
|
@@ -17915,7 +17915,7 @@ var init_ReplicateProvider = __esm({
|
|
|
17915
17915
|
* Sleep helper
|
|
17916
17916
|
*/
|
|
17917
17917
|
sleep(ms) {
|
|
17918
|
-
return new Promise((
|
|
17918
|
+
return new Promise((resolve87) => setTimeout(resolve87, ms));
|
|
17919
17919
|
}
|
|
17920
17920
|
/**
|
|
17921
17921
|
* Generate music from text prompt using MusicGen
|
|
@@ -26399,7 +26399,7 @@ async function prompt(question, hidden = false) {
|
|
|
26399
26399
|
input: process.stdin,
|
|
26400
26400
|
output: process.stdout
|
|
26401
26401
|
});
|
|
26402
|
-
return new Promise((
|
|
26402
|
+
return new Promise((resolve87) => {
|
|
26403
26403
|
if (hidden && process.stdin.isTTY) {
|
|
26404
26404
|
process.stdout.write(question);
|
|
26405
26405
|
let input = "";
|
|
@@ -26413,7 +26413,7 @@ async function prompt(question, hidden = false) {
|
|
|
26413
26413
|
process.stdin.removeListener("data", onData);
|
|
26414
26414
|
process.stdout.write("\n");
|
|
26415
26415
|
rl.close();
|
|
26416
|
-
|
|
26416
|
+
resolve87(input);
|
|
26417
26417
|
} else if (char === "") {
|
|
26418
26418
|
process.exit(1);
|
|
26419
26419
|
} else if (char === "\x7F" || char === "\b") {
|
|
@@ -26428,7 +26428,7 @@ async function prompt(question, hidden = false) {
|
|
|
26428
26428
|
} else {
|
|
26429
26429
|
rl.question(question, (answer) => {
|
|
26430
26430
|
rl.close();
|
|
26431
|
-
|
|
26431
|
+
resolve87(answer);
|
|
26432
26432
|
});
|
|
26433
26433
|
}
|
|
26434
26434
|
});
|
|
@@ -26802,6 +26802,7 @@ var init_storyboard_parse = __esm({
|
|
|
26802
26802
|
"backdrop",
|
|
26803
26803
|
"video",
|
|
26804
26804
|
"keyframe",
|
|
26805
|
+
"provider",
|
|
26805
26806
|
"motion",
|
|
26806
26807
|
"voice",
|
|
26807
26808
|
"music",
|
|
@@ -27097,7 +27098,7 @@ var init_storyboard_edit = __esm({
|
|
|
27097
27098
|
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
27098
27099
|
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
27099
27100
|
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
27100
|
-
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "keyframe", "motion", "voice", "music", "asset", "eyebrow", "title", "caption", "kicker", "sub"]);
|
|
27101
|
+
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "keyframe", "provider", "motion", "voice", "music", "asset", "eyebrow", "title", "caption", "kicker", "sub"]);
|
|
27101
27102
|
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
27102
27103
|
}
|
|
27103
27104
|
});
|
|
@@ -33448,16 +33449,16 @@ async function prompt2(question) {
|
|
|
33448
33449
|
input,
|
|
33449
33450
|
output: process.stdout
|
|
33450
33451
|
});
|
|
33451
|
-
return new Promise((
|
|
33452
|
+
return new Promise((resolve87) => {
|
|
33452
33453
|
rl.question(question, (answer) => {
|
|
33453
33454
|
rl.close();
|
|
33454
|
-
|
|
33455
|
+
resolve87(answer);
|
|
33455
33456
|
});
|
|
33456
33457
|
});
|
|
33457
33458
|
}
|
|
33458
33459
|
async function promptHidden(question, opts = {}) {
|
|
33459
33460
|
const input = getTTYInputStream();
|
|
33460
|
-
return new Promise((
|
|
33461
|
+
return new Promise((resolve87) => {
|
|
33461
33462
|
let value = "";
|
|
33462
33463
|
if (typeof input.setRawMode === "function") {
|
|
33463
33464
|
input.setRawMode(true);
|
|
@@ -33471,7 +33472,7 @@ async function promptHidden(question, opts = {}) {
|
|
|
33471
33472
|
input.setRawMode(false);
|
|
33472
33473
|
input.removeListener("data", onData);
|
|
33473
33474
|
process.stdout.write("\n");
|
|
33474
|
-
|
|
33475
|
+
resolve87(value);
|
|
33475
33476
|
} else if (char === "") {
|
|
33476
33477
|
input.setRawMode(false);
|
|
33477
33478
|
process.stdout.write("\n");
|
|
@@ -33497,7 +33498,7 @@ async function promptHidden(question, opts = {}) {
|
|
|
33497
33498
|
const rl = createInterface2({ input, output: process.stdout });
|
|
33498
33499
|
rl.question(question, (answer) => {
|
|
33499
33500
|
rl.close();
|
|
33500
|
-
|
|
33501
|
+
resolve87(answer);
|
|
33501
33502
|
});
|
|
33502
33503
|
}
|
|
33503
33504
|
});
|
|
@@ -33505,7 +33506,7 @@ async function promptHidden(question, opts = {}) {
|
|
|
33505
33506
|
async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
|
|
33506
33507
|
const input = getTTYInputStream();
|
|
33507
33508
|
if (typeof input.setRawMode === "function") {
|
|
33508
|
-
return new Promise((
|
|
33509
|
+
return new Promise((resolve87) => {
|
|
33509
33510
|
let selected = defaultIndex;
|
|
33510
33511
|
const render = () => {
|
|
33511
33512
|
if (renderCount > 0) {
|
|
@@ -33533,7 +33534,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
|
|
|
33533
33534
|
input.setRawMode(false);
|
|
33534
33535
|
input.removeListener("data", onData);
|
|
33535
33536
|
process.stdout.write("\n");
|
|
33536
|
-
|
|
33537
|
+
resolve87(selected);
|
|
33537
33538
|
} else if (char === "") {
|
|
33538
33539
|
input.setRawMode(false);
|
|
33539
33540
|
process.stdout.write("\n");
|
|
@@ -33543,7 +33544,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
|
|
|
33543
33544
|
input.setRawMode(false);
|
|
33544
33545
|
input.removeListener("data", onData);
|
|
33545
33546
|
process.stdout.write("\n");
|
|
33546
|
-
|
|
33547
|
+
resolve87(opts.backIndex);
|
|
33547
33548
|
} else if (char === "\x1B[A" || char === "k") {
|
|
33548
33549
|
selected = (selected - 1 + options.length) % options.length;
|
|
33549
33550
|
render();
|
|
@@ -33557,7 +33558,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
|
|
|
33557
33558
|
input.removeListener("data", onData);
|
|
33558
33559
|
render();
|
|
33559
33560
|
process.stdout.write("\n");
|
|
33560
|
-
|
|
33561
|
+
resolve87(selected);
|
|
33561
33562
|
}
|
|
33562
33563
|
};
|
|
33563
33564
|
const onData = (chunk) => {
|
|
@@ -33581,7 +33582,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
|
|
|
33581
33582
|
async function promptConfirm(question, defaultYes = true) {
|
|
33582
33583
|
const input = getTTYInputStream();
|
|
33583
33584
|
if (typeof input.setRawMode === "function") {
|
|
33584
|
-
return new Promise((
|
|
33585
|
+
return new Promise((resolve87) => {
|
|
33585
33586
|
const options = ["Yes", "No"];
|
|
33586
33587
|
let selected = defaultYes ? 0 : 1;
|
|
33587
33588
|
let renderCount = 0;
|
|
@@ -33611,7 +33612,7 @@ async function promptConfirm(question, defaultYes = true) {
|
|
|
33611
33612
|
finished = true;
|
|
33612
33613
|
input.setRawMode(false);
|
|
33613
33614
|
input.removeListener("data", onData);
|
|
33614
|
-
|
|
33615
|
+
resolve87(selected === 0);
|
|
33615
33616
|
} else if (char === "") {
|
|
33616
33617
|
input.setRawMode(false);
|
|
33617
33618
|
process.stdout.write("\n");
|
|
@@ -33625,14 +33626,14 @@ async function promptConfirm(question, defaultYes = true) {
|
|
|
33625
33626
|
input.setRawMode(false);
|
|
33626
33627
|
input.removeListener("data", onData);
|
|
33627
33628
|
render();
|
|
33628
|
-
|
|
33629
|
+
resolve87(true);
|
|
33629
33630
|
} else if (char === "n" || char === "N") {
|
|
33630
33631
|
selected = 1;
|
|
33631
33632
|
finished = true;
|
|
33632
33633
|
input.setRawMode(false);
|
|
33633
33634
|
input.removeListener("data", onData);
|
|
33634
33635
|
render();
|
|
33635
|
-
|
|
33636
|
+
resolve87(false);
|
|
33636
33637
|
}
|
|
33637
33638
|
};
|
|
33638
33639
|
const onData = (chunk) => {
|
|
@@ -33651,7 +33652,7 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
|
|
|
33651
33652
|
const input = getTTYInputStream();
|
|
33652
33653
|
const selected = options.map((_, i) => Boolean(defaultSelected[i]));
|
|
33653
33654
|
if (typeof input.setRawMode === "function") {
|
|
33654
|
-
return new Promise((
|
|
33655
|
+
return new Promise((resolve87) => {
|
|
33655
33656
|
let cursor = 0;
|
|
33656
33657
|
let renderCount = 0;
|
|
33657
33658
|
let userToggled = false;
|
|
@@ -33681,7 +33682,7 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
|
|
|
33681
33682
|
for (let i = 0; i < selected.length; i++) {
|
|
33682
33683
|
if (selected[i]) result.push(i);
|
|
33683
33684
|
}
|
|
33684
|
-
|
|
33685
|
+
resolve87(result);
|
|
33685
33686
|
};
|
|
33686
33687
|
let finished = false;
|
|
33687
33688
|
const handleChar = (char) => {
|
|
@@ -35648,7 +35649,7 @@ function unique(items) {
|
|
|
35648
35649
|
];
|
|
35649
35650
|
}
|
|
35650
35651
|
function sleep2(ms) {
|
|
35651
|
-
return new Promise((
|
|
35652
|
+
return new Promise((resolve87) => setTimeout(resolve87, ms));
|
|
35652
35653
|
}
|
|
35653
35654
|
var LOCAL_JOB_ORPHAN_AFTER_MS;
|
|
35654
35655
|
var init_status_jobs = __esm({
|
|
@@ -58291,6 +58292,7 @@ function backdropCacheDescriptor(opts) {
|
|
|
58291
58292
|
beatId: opts.beatId,
|
|
58292
58293
|
cue: opts.cue,
|
|
58293
58294
|
provider: opts.provider,
|
|
58295
|
+
model: opts.model,
|
|
58294
58296
|
quality: opts.quality,
|
|
58295
58297
|
size: opts.size,
|
|
58296
58298
|
ratio: opts.ratio,
|
|
@@ -58302,6 +58304,7 @@ function characterCacheDescriptor(opts) {
|
|
|
58302
58304
|
name: opts.name,
|
|
58303
58305
|
cue: opts.cue,
|
|
58304
58306
|
provider: opts.provider,
|
|
58307
|
+
model: opts.model,
|
|
58305
58308
|
quality: opts.quality,
|
|
58306
58309
|
size: opts.size,
|
|
58307
58310
|
ext: "png"
|
|
@@ -58311,6 +58314,7 @@ function keyframeCacheDescriptor(opts) {
|
|
|
58311
58314
|
return cacheAssetDescriptor("keyframe", {
|
|
58312
58315
|
beatId: opts.beatId,
|
|
58313
58316
|
cue: opts.cue,
|
|
58317
|
+
model: opts.model,
|
|
58314
58318
|
provider: opts.provider,
|
|
58315
58319
|
quality: opts.quality,
|
|
58316
58320
|
size: opts.size,
|
|
@@ -58411,7 +58415,8 @@ async function createBuildPlan(opts) {
|
|
|
58411
58415
|
const stage = opts.stage ?? "all";
|
|
58412
58416
|
const config2 = await readProjectConfig(projectDir);
|
|
58413
58417
|
const kindPolicy = kindAssetPolicy(config2.config.kind);
|
|
58414
|
-
const
|
|
58418
|
+
const composerIsFootage = stringOrUndefined3(opts.composer)?.toLowerCase() === "footage";
|
|
58419
|
+
const skipBackdrop = opts.skipBackdrop ?? (composerIsFootage ? true : kindPolicy.skipBackdrop ?? false);
|
|
58415
58420
|
const skipKeyframe = opts.skipKeyframe ?? kindPolicy.skipKeyframe ?? false;
|
|
58416
58421
|
const skipVideo = opts.skipVideo ?? kindPolicy.skipVideo ?? false;
|
|
58417
58422
|
const storyboardPath2 = join24(projectDir, "STORYBOARD.md");
|
|
@@ -58530,7 +58535,8 @@ async function createBuildPlan(opts) {
|
|
|
58530
58535
|
provider: resolved.image.resolved,
|
|
58531
58536
|
quality: imageQuality,
|
|
58532
58537
|
size: imageSize2,
|
|
58533
|
-
ratio: imageRatio
|
|
58538
|
+
ratio: imageRatio,
|
|
58539
|
+
model: opts.imageModel
|
|
58534
58540
|
}) : null;
|
|
58535
58541
|
const videoCache = (videoPrompt || keyframePrompt) && !videoReference ? videoCacheDescriptor({
|
|
58536
58542
|
beatId: beat.id,
|
|
@@ -58545,7 +58551,8 @@ async function createBuildPlan(opts) {
|
|
|
58545
58551
|
provider: resolved.image.resolved,
|
|
58546
58552
|
quality: imageQuality,
|
|
58547
58553
|
size: imageSize2,
|
|
58548
|
-
ratio: imageRatio
|
|
58554
|
+
ratio: imageRatio,
|
|
58555
|
+
model: opts.imageModel
|
|
58549
58556
|
}) : null;
|
|
58550
58557
|
const musicCache = musicPrompt && !musicReference ? musicCacheDescriptor({
|
|
58551
58558
|
beatId: beat.id,
|
|
@@ -59020,6 +59027,17 @@ async function keyedProviderResolution(opts, projectDir) {
|
|
|
59020
59027
|
}
|
|
59021
59028
|
async function resolveComposerProvider(input, projectDir) {
|
|
59022
59029
|
const requested = input.value.toLowerCase();
|
|
59030
|
+
if (requested === "template" || requested === "footage") {
|
|
59031
|
+
return {
|
|
59032
|
+
kind: "composer",
|
|
59033
|
+
requested: input.requested,
|
|
59034
|
+
resolved: requested,
|
|
59035
|
+
source: input.source,
|
|
59036
|
+
requiresKey: false,
|
|
59037
|
+
configured: true,
|
|
59038
|
+
retryWith: []
|
|
59039
|
+
};
|
|
59040
|
+
}
|
|
59023
59041
|
const explicit = isComposerProvider(requested) ? requested : void 0;
|
|
59024
59042
|
const resolved = explicit ?? await firstConfiguredComposer(projectDir) ?? "claude";
|
|
59025
59043
|
const configKey = composerConfigKey(resolved);
|
|
@@ -59494,9 +59512,422 @@ var init_compose_aivideo = __esm({
|
|
|
59494
59512
|
}
|
|
59495
59513
|
});
|
|
59496
59514
|
|
|
59515
|
+
// src/commands/_shared/footage-assemble.ts
|
|
59516
|
+
import { existsSync as existsSync48 } from "node:fs";
|
|
59517
|
+
import { mkdir as mkdir24, writeFile as writeFile44 } from "node:fs/promises";
|
|
59518
|
+
import { dirname as dirname19, isAbsolute as isAbsolute6, join as join26, resolve as resolve58 } from "node:path";
|
|
59519
|
+
function planFootageTimeline(inputs, opts = {}) {
|
|
59520
|
+
if (inputs.length === 0) {
|
|
59521
|
+
throw new Error("No clips to assemble.");
|
|
59522
|
+
}
|
|
59523
|
+
const fadeSec = opts.fadeSec ?? FOOTAGE_DEFAULTS.fadeSec;
|
|
59524
|
+
const narrationLeadSec = opts.narrationLeadSec ?? FOOTAGE_DEFAULTS.narrationLeadSec;
|
|
59525
|
+
const narrationTailSec = opts.narrationTailSec ?? FOOTAGE_DEFAULTS.narrationTailSec;
|
|
59526
|
+
const warnings = [];
|
|
59527
|
+
let transitionSec = opts.transitionSec ?? FOOTAGE_DEFAULTS.transitionSec;
|
|
59528
|
+
if (inputs.length > 1) {
|
|
59529
|
+
const shortest = Math.min(...inputs.map((c) => c.clipDurationSec));
|
|
59530
|
+
const maxTransition = round3(Math.max(0, shortest / 2 - 0.05));
|
|
59531
|
+
if (transitionSec > maxTransition) {
|
|
59532
|
+
warnings.push(
|
|
59533
|
+
`Transition ${transitionSec}s exceeds half the shortest clip (${shortest}s); clamped to ${maxTransition}s.`
|
|
59534
|
+
);
|
|
59535
|
+
transitionSec = maxTransition;
|
|
59536
|
+
}
|
|
59537
|
+
}
|
|
59538
|
+
const beats = [];
|
|
59539
|
+
let cursor = 0;
|
|
59540
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
59541
|
+
const input = inputs[i];
|
|
59542
|
+
const isFirst = i === 0;
|
|
59543
|
+
const isLast = i === inputs.length - 1;
|
|
59544
|
+
const startSec = round3(cursor);
|
|
59545
|
+
const inSegmentOffset = (isFirst ? 0 : transitionSec / 2) + narrationLeadSec;
|
|
59546
|
+
let segmentDurationSec = input.clipDurationSec;
|
|
59547
|
+
let narrationStartSec;
|
|
59548
|
+
if (input.narrationDurationSec !== void 0) {
|
|
59549
|
+
narrationStartSec = round3(startSec + inSegmentOffset);
|
|
59550
|
+
const tail = isLast ? Math.max(narrationTailSec, fadeSec) : narrationTailSec;
|
|
59551
|
+
const required = inSegmentOffset + input.narrationDurationSec + tail;
|
|
59552
|
+
segmentDurationSec = Math.max(segmentDurationSec, required);
|
|
59553
|
+
}
|
|
59554
|
+
segmentDurationSec = round3(segmentDurationSec);
|
|
59555
|
+
const extendedSec = round3(segmentDurationSec - input.clipDurationSec);
|
|
59556
|
+
if (extendedSec > 0) {
|
|
59557
|
+
warnings.push(
|
|
59558
|
+
`Beat "${input.id}": narration outruns the clip; last frame held for ${extendedSec}s.`
|
|
59559
|
+
);
|
|
59560
|
+
}
|
|
59561
|
+
beats.push({
|
|
59562
|
+
id: input.id,
|
|
59563
|
+
clipDurationSec: input.clipDurationSec,
|
|
59564
|
+
narrationDurationSec: input.narrationDurationSec,
|
|
59565
|
+
segmentDurationSec,
|
|
59566
|
+
extendedSec,
|
|
59567
|
+
startSec,
|
|
59568
|
+
narrationStartSec
|
|
59569
|
+
});
|
|
59570
|
+
cursor = startSec + segmentDurationSec - (isLast ? 0 : transitionSec);
|
|
59571
|
+
}
|
|
59572
|
+
return {
|
|
59573
|
+
beats,
|
|
59574
|
+
transitionSec,
|
|
59575
|
+
fadeSec,
|
|
59576
|
+
totalDurationSec: round3(cursor),
|
|
59577
|
+
warnings
|
|
59578
|
+
};
|
|
59579
|
+
}
|
|
59580
|
+
function buildFootageAssembleArgs(opts) {
|
|
59581
|
+
const { plan, sources, narrationPaths, musicPath, outputPath } = opts;
|
|
59582
|
+
const width = opts.width ?? FOOTAGE_DEFAULTS.width;
|
|
59583
|
+
const height = opts.height ?? FOOTAGE_DEFAULTS.height;
|
|
59584
|
+
const fps = opts.fps ?? FOOTAGE_DEFAULTS.fps;
|
|
59585
|
+
const crf = opts.crf ?? (opts.finish ? FOOTAGE_DEFAULTS.finishCrf : FOOTAGE_DEFAULTS.crf);
|
|
59586
|
+
const musicVolume = opts.musicVolume ?? FOOTAGE_DEFAULTS.musicVolume;
|
|
59587
|
+
const total = plan.totalDurationSec;
|
|
59588
|
+
const fade = plan.fadeSec;
|
|
59589
|
+
const args = ["-y"];
|
|
59590
|
+
for (let i = 0; i < sources.length; i++) {
|
|
59591
|
+
const source = sources[i];
|
|
59592
|
+
if (source.kind === "image") {
|
|
59593
|
+
args.push(
|
|
59594
|
+
"-loop",
|
|
59595
|
+
"1",
|
|
59596
|
+
"-framerate",
|
|
59597
|
+
String(fps),
|
|
59598
|
+
"-t",
|
|
59599
|
+
String(plan.beats[i].segmentDurationSec),
|
|
59600
|
+
"-i",
|
|
59601
|
+
source.path
|
|
59602
|
+
);
|
|
59603
|
+
} else {
|
|
59604
|
+
args.push("-i", source.path);
|
|
59605
|
+
}
|
|
59606
|
+
}
|
|
59607
|
+
const narrationEntries = [...narrationPaths.entries()].sort(([a], [b]) => a - b);
|
|
59608
|
+
const narrationInputIndex = /* @__PURE__ */ new Map();
|
|
59609
|
+
for (const [beatIndex, path2] of narrationEntries) {
|
|
59610
|
+
narrationInputIndex.set(beatIndex, sources.length + narrationInputIndex.size);
|
|
59611
|
+
args.push("-i", path2);
|
|
59612
|
+
}
|
|
59613
|
+
let musicInputIndex;
|
|
59614
|
+
if (musicPath) {
|
|
59615
|
+
musicInputIndex = sources.length + narrationInputIndex.size;
|
|
59616
|
+
args.push("-stream_loop", "-1", "-i", musicPath);
|
|
59617
|
+
}
|
|
59618
|
+
const filters = [];
|
|
59619
|
+
for (let i = 0; i < sources.length; i++) {
|
|
59620
|
+
const seg = plan.beats[i].segmentDurationSec;
|
|
59621
|
+
if (sources[i].kind === "image") {
|
|
59622
|
+
const rate = round6((FOOTAGE_DEFAULTS.kenburnsMaxZoom - 1) / Math.max(1, seg * fps));
|
|
59623
|
+
filters.push(
|
|
59624
|
+
`[${i}:v]scale=${width * 2}:${height * 2}:force_original_aspect_ratio=increase,crop=${width * 2}:${height * 2},zoompan=z='min(pzoom+${rate},${FOOTAGE_DEFAULTS.kenburnsMaxZoom})':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=1:s=${width}x${height}:fps=${fps},setsar=1,settb=AVTB,format=yuv420p[v${i}]`
|
|
59625
|
+
);
|
|
59626
|
+
continue;
|
|
59627
|
+
}
|
|
59628
|
+
const extend = plan.beats[i].extendedSec;
|
|
59629
|
+
const tpad = extend > 0 ? `,tpad=stop_mode=clone:stop_duration=${extend}` : "";
|
|
59630
|
+
filters.push(
|
|
59631
|
+
`[${i}:v]scale=${width}:${height}:force_original_aspect_ratio=increase,crop=${width}:${height},setsar=1,fps=${fps},settb=AVTB,format=yuv420p${tpad}[v${i}]`
|
|
59632
|
+
);
|
|
59633
|
+
}
|
|
59634
|
+
let videoLabel = "[v0]";
|
|
59635
|
+
for (let i = 1; i < sources.length; i++) {
|
|
59636
|
+
const out = `[vx${i}]`;
|
|
59637
|
+
filters.push(
|
|
59638
|
+
`${videoLabel}[v${i}]xfade=transition=fade:duration=${plan.transitionSec}:offset=${plan.beats[i].startSec}${out}`
|
|
59639
|
+
);
|
|
59640
|
+
videoLabel = out;
|
|
59641
|
+
}
|
|
59642
|
+
const finishChain = opts.finish ? `${FOOTAGE_DEFAULTS.finish.join(",")},` : "";
|
|
59643
|
+
filters.push(
|
|
59644
|
+
`${videoLabel}${finishChain}fade=t=in:st=0:d=${fade},fade=t=out:st=${round3(Math.max(0, total - fade))}:d=${fade}[vout]`
|
|
59645
|
+
);
|
|
59646
|
+
let audioLabel;
|
|
59647
|
+
if (narrationInputIndex.size > 0) {
|
|
59648
|
+
const delayed = [];
|
|
59649
|
+
for (const [beatIndex, inputIndex] of narrationInputIndex) {
|
|
59650
|
+
const ms = Math.round((plan.beats[beatIndex].narrationStartSec ?? 0) * 1e3);
|
|
59651
|
+
const label = `[nd${beatIndex}]`;
|
|
59652
|
+
filters.push(`[${inputIndex}:a]adelay=${ms}:all=1${label}`);
|
|
59653
|
+
delayed.push(label);
|
|
59654
|
+
}
|
|
59655
|
+
if (delayed.length === 1) {
|
|
59656
|
+
filters.push(`${delayed[0]}anull[nar]`);
|
|
59657
|
+
} else {
|
|
59658
|
+
filters.push(`${delayed.join("")}amix=inputs=${delayed.length}:normalize=0[nar]`);
|
|
59659
|
+
}
|
|
59660
|
+
audioLabel = "[nar]";
|
|
59661
|
+
}
|
|
59662
|
+
if (musicInputIndex !== void 0) {
|
|
59663
|
+
filters.push(
|
|
59664
|
+
`[${musicInputIndex}:a]atrim=0:${total},asetpts=PTS-STARTPTS,volume=${musicVolume}[mb]`
|
|
59665
|
+
);
|
|
59666
|
+
if (audioLabel) {
|
|
59667
|
+
const { thresholdDb, ratio, attackMs, releaseMs } = FOOTAGE_DEFAULTS.duck;
|
|
59668
|
+
const thresholdLinear = round3(Math.pow(10, thresholdDb / 20));
|
|
59669
|
+
filters.push(
|
|
59670
|
+
`${audioLabel}asplit=2[narA][narSC]`,
|
|
59671
|
+
`[mb][narSC]sidechaincompress=threshold=${thresholdLinear}:ratio=${ratio}:attack=${attackMs}:release=${releaseMs}[mduck]`,
|
|
59672
|
+
`[mduck][narA]amix=inputs=2:normalize=0[mix]`
|
|
59673
|
+
);
|
|
59674
|
+
audioLabel = "[mix]";
|
|
59675
|
+
} else {
|
|
59676
|
+
audioLabel = "[mb]";
|
|
59677
|
+
}
|
|
59678
|
+
}
|
|
59679
|
+
if (audioLabel) {
|
|
59680
|
+
filters.push(
|
|
59681
|
+
`${audioLabel}apad,atrim=0:${total},afade=t=out:st=${round3(Math.max(0, total - fade))}:d=${fade}[aout]`
|
|
59682
|
+
);
|
|
59683
|
+
}
|
|
59684
|
+
args.push("-filter_complex", filters.join(";"), "-map", "[vout]");
|
|
59685
|
+
if (audioLabel) {
|
|
59686
|
+
args.push("-map", "[aout]", "-c:a", "aac", "-b:a", "192k");
|
|
59687
|
+
} else {
|
|
59688
|
+
args.push("-an");
|
|
59689
|
+
}
|
|
59690
|
+
args.push(
|
|
59691
|
+
"-c:v",
|
|
59692
|
+
"libx264",
|
|
59693
|
+
"-crf",
|
|
59694
|
+
String(crf),
|
|
59695
|
+
"-pix_fmt",
|
|
59696
|
+
"yuv420p",
|
|
59697
|
+
"-movflags",
|
|
59698
|
+
"+faststart",
|
|
59699
|
+
"-t",
|
|
59700
|
+
String(total),
|
|
59701
|
+
outputPath
|
|
59702
|
+
);
|
|
59703
|
+
return args;
|
|
59704
|
+
}
|
|
59705
|
+
async function executeFootageAssemble(opts) {
|
|
59706
|
+
const projectDir = resolve58(opts.projectDir);
|
|
59707
|
+
const outputRel = opts.output ?? DEFAULT_FOOTAGE_OUTPUT;
|
|
59708
|
+
const outputPath = isAbsolute6(outputRel) ? outputRel : resolve58(projectDir, outputRel);
|
|
59709
|
+
if (!ffmpegToolsAvailable()) {
|
|
59710
|
+
return {
|
|
59711
|
+
success: false,
|
|
59712
|
+
dryRun: Boolean(opts.dryRun),
|
|
59713
|
+
outputPath,
|
|
59714
|
+
error: "FFmpeg toolchain (ffmpeg + ffprobe) not found in PATH.",
|
|
59715
|
+
suggestion: "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)."
|
|
59716
|
+
};
|
|
59717
|
+
}
|
|
59718
|
+
let beats;
|
|
59719
|
+
try {
|
|
59720
|
+
const md = await loadStoryboardMarkdown(projectDir);
|
|
59721
|
+
beats = parseStoryboard(md).beats;
|
|
59722
|
+
} catch (err) {
|
|
59723
|
+
return {
|
|
59724
|
+
success: false,
|
|
59725
|
+
dryRun: Boolean(opts.dryRun),
|
|
59726
|
+
outputPath,
|
|
59727
|
+
error: err instanceof Error ? err.message : String(err),
|
|
59728
|
+
suggestion: "Run inside a vibe scene project (needs STORYBOARD.md / scenes/)."
|
|
59729
|
+
};
|
|
59730
|
+
}
|
|
59731
|
+
if (beats.length === 0) {
|
|
59732
|
+
return {
|
|
59733
|
+
success: false,
|
|
59734
|
+
dryRun: Boolean(opts.dryRun),
|
|
59735
|
+
outputPath,
|
|
59736
|
+
error: "STORYBOARD.md has no beats to assemble."
|
|
59737
|
+
};
|
|
59738
|
+
}
|
|
59739
|
+
const missing = [];
|
|
59740
|
+
const sourceRels = [];
|
|
59741
|
+
const kenburnsBeatIds = [];
|
|
59742
|
+
for (const beat of beats) {
|
|
59743
|
+
const clipRel = `assets/video-${beat.id}.mp4`;
|
|
59744
|
+
if (existsSync48(join26(projectDir, clipRel))) {
|
|
59745
|
+
sourceRels.push({ rel: clipRel, kind: "video" });
|
|
59746
|
+
continue;
|
|
59747
|
+
}
|
|
59748
|
+
const keyframeRel = `assets/keyframe-${beat.id}.png`;
|
|
59749
|
+
if (existsSync48(join26(projectDir, keyframeRel))) {
|
|
59750
|
+
sourceRels.push({ rel: keyframeRel, kind: "image" });
|
|
59751
|
+
kenburnsBeatIds.push(beat.id);
|
|
59752
|
+
continue;
|
|
59753
|
+
}
|
|
59754
|
+
missing.push(`${beat.id} (${clipRel})`);
|
|
59755
|
+
sourceRels.push({ rel: clipRel, kind: "video" });
|
|
59756
|
+
}
|
|
59757
|
+
if (missing.length > 0) {
|
|
59758
|
+
return {
|
|
59759
|
+
success: false,
|
|
59760
|
+
dryRun: Boolean(opts.dryRun),
|
|
59761
|
+
outputPath,
|
|
59762
|
+
error: `No clip or keyframe for beat(s): ${missing.join(", ")}.`,
|
|
59763
|
+
suggestion: `Generate them first: vibe build ${projectDir} --stage assets --json`
|
|
59764
|
+
};
|
|
59765
|
+
}
|
|
59766
|
+
const narrationRels = /* @__PURE__ */ new Map();
|
|
59767
|
+
for (let i = 0; i < beats.length; i++) {
|
|
59768
|
+
const rel = ["mp3", "wav"].map((ext) => `assets/narration-${beats[i].id}.${ext}`).find((r) => existsSync48(join26(projectDir, r)));
|
|
59769
|
+
if (rel) narrationRels.set(i, rel);
|
|
59770
|
+
}
|
|
59771
|
+
const music = resolveMusicBed(projectDir, beats[0]?.id, opts.music);
|
|
59772
|
+
if (!music.ok) {
|
|
59773
|
+
return {
|
|
59774
|
+
success: false,
|
|
59775
|
+
dryRun: Boolean(opts.dryRun),
|
|
59776
|
+
outputPath,
|
|
59777
|
+
error: music.error
|
|
59778
|
+
};
|
|
59779
|
+
}
|
|
59780
|
+
const inputs = [];
|
|
59781
|
+
for (let i = 0; i < beats.length; i++) {
|
|
59782
|
+
const clipDurationSec = sourceRels[i].kind === "image" ? beats[i].duration ?? FOOTAGE_DEFAULTS.kenburnsSec : round3(await ffprobeDuration(join26(projectDir, sourceRels[i].rel)));
|
|
59783
|
+
const narrationRel = narrationRels.get(i);
|
|
59784
|
+
const narrationDurationSec = narrationRel ? round3(await ffprobeDuration(join26(projectDir, narrationRel))) : void 0;
|
|
59785
|
+
inputs.push({ id: beats[i].id, clipDurationSec, narrationDurationSec });
|
|
59786
|
+
}
|
|
59787
|
+
const plan = planFootageTimeline(inputs, {
|
|
59788
|
+
transitionSec: opts.transitionSec,
|
|
59789
|
+
fadeSec: opts.fadeSec
|
|
59790
|
+
});
|
|
59791
|
+
const musicVolume = opts.musicVolume ?? FOOTAGE_DEFAULTS.musicVolume;
|
|
59792
|
+
const report = {
|
|
59793
|
+
schemaVersion: "1",
|
|
59794
|
+
kind: "footage-assemble",
|
|
59795
|
+
project: projectDir,
|
|
59796
|
+
output: outputPath,
|
|
59797
|
+
totalDurationSec: plan.totalDurationSec,
|
|
59798
|
+
transitionSec: plan.transitionSec,
|
|
59799
|
+
fadeSec: plan.fadeSec,
|
|
59800
|
+
beats: plan.beats.map((b, i) => ({
|
|
59801
|
+
...b,
|
|
59802
|
+
clip: sourceRels[i].rel,
|
|
59803
|
+
source: sourceRels[i].kind === "image" ? "keyframe-kenburns" : "clip",
|
|
59804
|
+
narration: narrationRels.get(i)
|
|
59805
|
+
})),
|
|
59806
|
+
music: music.rel ? {
|
|
59807
|
+
path: music.rel,
|
|
59808
|
+
source: music.source,
|
|
59809
|
+
volume: musicVolume,
|
|
59810
|
+
ducked: narrationRels.size > 0
|
|
59811
|
+
} : null,
|
|
59812
|
+
finish: opts.finish ? { filters: [...FOOTAGE_DEFAULTS.finish] } : null,
|
|
59813
|
+
warnings: [
|
|
59814
|
+
...plan.warnings,
|
|
59815
|
+
...kenburnsBeatIds.map(
|
|
59816
|
+
(id) => `Beat "${id}": no generated clip; keyframe ken-burns fallback used.`
|
|
59817
|
+
)
|
|
59818
|
+
],
|
|
59819
|
+
nextActions: [
|
|
59820
|
+
{
|
|
59821
|
+
id: "inspect-footage-cut",
|
|
59822
|
+
kind: "command",
|
|
59823
|
+
label: "Inspect the assembled cut",
|
|
59824
|
+
command: `vibe inspect render ${outputPath} --cheap --json`,
|
|
59825
|
+
fixOwner: "vibe",
|
|
59826
|
+
costTier: "free",
|
|
59827
|
+
safeToAutoRun: true,
|
|
59828
|
+
requiresConfirmation: false,
|
|
59829
|
+
reason: "Verify duration, black frames, and audio coverage without watching the video."
|
|
59830
|
+
},
|
|
59831
|
+
...kenburnsBeatIds.map((id) => ({
|
|
59832
|
+
id: `regenerate-clip-${id}`,
|
|
59833
|
+
kind: "command",
|
|
59834
|
+
label: `Regenerate the missing clip for beat "${id}"`,
|
|
59835
|
+
command: `vibe build ${projectDir} --beat ${id} --stage assets --force --json`,
|
|
59836
|
+
fixOwner: "vibe",
|
|
59837
|
+
costTier: "very-high",
|
|
59838
|
+
safeToAutoRun: false,
|
|
59839
|
+
requiresConfirmation: true,
|
|
59840
|
+
reason: `Beat "${id}" shipped as a ken-burns still; regenerating the clip restores real motion.`
|
|
59841
|
+
}))
|
|
59842
|
+
]
|
|
59843
|
+
};
|
|
59844
|
+
if (opts.dryRun) {
|
|
59845
|
+
return { success: true, dryRun: true, outputPath, report };
|
|
59846
|
+
}
|
|
59847
|
+
await mkdir24(dirname19(outputPath), { recursive: true });
|
|
59848
|
+
const args = buildFootageAssembleArgs({
|
|
59849
|
+
sources: sourceRels.map((s) => ({ path: join26(projectDir, s.rel), kind: s.kind })),
|
|
59850
|
+
plan,
|
|
59851
|
+
narrationPaths: new Map(
|
|
59852
|
+
[...narrationRels.entries()].map(([i, rel]) => [i, join26(projectDir, rel)])
|
|
59853
|
+
),
|
|
59854
|
+
musicPath: music.rel ? isAbsolute6(music.rel) ? music.rel : join26(projectDir, music.rel) : void 0,
|
|
59855
|
+
outputPath,
|
|
59856
|
+
musicVolume,
|
|
59857
|
+
finish: opts.finish
|
|
59858
|
+
});
|
|
59859
|
+
try {
|
|
59860
|
+
await execSafe("ffmpeg", args, { timeout: 6e5 });
|
|
59861
|
+
} catch (err) {
|
|
59862
|
+
return {
|
|
59863
|
+
success: false,
|
|
59864
|
+
dryRun: false,
|
|
59865
|
+
outputPath,
|
|
59866
|
+
report,
|
|
59867
|
+
error: `FFmpeg assembly failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
59868
|
+
suggestion: "Re-run with --dry-run --json to inspect the planned timeline."
|
|
59869
|
+
};
|
|
59870
|
+
}
|
|
59871
|
+
const reportPath = join26(projectDir, "assemble-report.json");
|
|
59872
|
+
await writeFile44(reportPath, `${JSON.stringify(report, null, 2)}
|
|
59873
|
+
`, "utf-8");
|
|
59874
|
+
return { success: true, dryRun: false, outputPath, reportPath, report };
|
|
59875
|
+
}
|
|
59876
|
+
function resolveMusicBed(projectDir, firstBeatId, flag) {
|
|
59877
|
+
if (flag === "none") return { ok: true, source: "flag" };
|
|
59878
|
+
if (flag) {
|
|
59879
|
+
const abs = isAbsolute6(flag) ? flag : join26(projectDir, flag);
|
|
59880
|
+
if (!existsSync48(abs)) return { ok: false, error: `Music file not found: ${abs}` };
|
|
59881
|
+
return { ok: true, rel: flag, source: "flag" };
|
|
59882
|
+
}
|
|
59883
|
+
const candidates = ["assets/music.mp3", "assets/music.wav"];
|
|
59884
|
+
if (firstBeatId) {
|
|
59885
|
+
candidates.push(`assets/music-${firstBeatId}.mp3`, `assets/music-${firstBeatId}.wav`);
|
|
59886
|
+
}
|
|
59887
|
+
const rel = candidates.find((r) => existsSync48(join26(projectDir, r)));
|
|
59888
|
+
return { ok: true, rel, source: "auto" };
|
|
59889
|
+
}
|
|
59890
|
+
var FOOTAGE_DEFAULTS, round3, round6, DEFAULT_FOOTAGE_OUTPUT;
|
|
59891
|
+
var init_footage_assemble = __esm({
|
|
59892
|
+
"src/commands/_shared/footage-assemble.ts"() {
|
|
59893
|
+
"use strict";
|
|
59894
|
+
init_exec_safe();
|
|
59895
|
+
init_ffmpeg_gate();
|
|
59896
|
+
init_storyboard_parse();
|
|
59897
|
+
init_storyboard_source();
|
|
59898
|
+
FOOTAGE_DEFAULTS = {
|
|
59899
|
+
transitionSec: 0.5,
|
|
59900
|
+
fadeSec: 0.6,
|
|
59901
|
+
narrationLeadSec: 0.35,
|
|
59902
|
+
narrationTailSec: 0.4,
|
|
59903
|
+
width: 1920,
|
|
59904
|
+
height: 1080,
|
|
59905
|
+
fps: 30,
|
|
59906
|
+
crf: 18,
|
|
59907
|
+
finishCrf: 23,
|
|
59908
|
+
musicVolume: 0.35,
|
|
59909
|
+
duck: { thresholdDb: -30, ratio: 3, attackMs: 20, releaseMs: 200 },
|
|
59910
|
+
/**
|
|
59911
|
+
* The cinematic finish pass: subtle vignette + temporal film grain, applied
|
|
59912
|
+
* before the head/tail fades. These are the field-tested values that pull
|
|
59913
|
+
* provider clips away from the too-clean "AI look"; the fades multiply over
|
|
59914
|
+
* them so blacks stay black.
|
|
59915
|
+
*/
|
|
59916
|
+
finish: ["vignette=angle=PI/5", "noise=alls=7:allf=t"],
|
|
59917
|
+
/** Base segment length for a ken-burns keyframe fallback (no clip to probe). */
|
|
59918
|
+
kenburnsSec: 4,
|
|
59919
|
+
/** Slow-push ceiling for the ken-burns zoom. */
|
|
59920
|
+
kenburnsMaxZoom: 1.1
|
|
59921
|
+
};
|
|
59922
|
+
round3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
59923
|
+
round6 = (n) => Math.round(n * 1e6) / 1e6;
|
|
59924
|
+
DEFAULT_FOOTAGE_OUTPUT = "renders/footage.mp4";
|
|
59925
|
+
}
|
|
59926
|
+
});
|
|
59927
|
+
|
|
59497
59928
|
// src/commands/_shared/scene-audio-scan.ts
|
|
59498
59929
|
import { readFile as readFile41 } from "node:fs/promises";
|
|
59499
|
-
import { resolve as
|
|
59930
|
+
import { resolve as resolve59 } from "node:path";
|
|
59500
59931
|
function parseRootClips(rootHtml) {
|
|
59501
59932
|
const clips = [];
|
|
59502
59933
|
const clipRegex = /<div\b[^>]*class="clip"[^>]*>/gi;
|
|
@@ -59534,7 +59965,7 @@ function parseSceneAudios(compositionHtml) {
|
|
|
59534
59965
|
}
|
|
59535
59966
|
function makeFsCompositionReader(projectDir) {
|
|
59536
59967
|
return async (compositionSrcRel) => {
|
|
59537
|
-
const abs =
|
|
59968
|
+
const abs = resolve59(projectDir, compositionSrcRel);
|
|
59538
59969
|
try {
|
|
59539
59970
|
return await readFile41(abs, "utf-8");
|
|
59540
59971
|
} catch {
|
|
@@ -59553,7 +59984,7 @@ async function scanSceneAudio(opts) {
|
|
|
59553
59984
|
for (const audio of audios) {
|
|
59554
59985
|
out.push({
|
|
59555
59986
|
srcRel: audio.srcRel,
|
|
59556
|
-
srcAbs:
|
|
59987
|
+
srcAbs: resolve59(opts.projectDir, audio.srcRel),
|
|
59557
59988
|
absoluteStart: clip.start + audio.localStart,
|
|
59558
59989
|
durationHint: audio.durationHint,
|
|
59559
59990
|
clipDurationCap: clip.duration - audio.localStart,
|
|
@@ -59568,7 +59999,7 @@ async function scanSceneAudio(opts) {
|
|
|
59568
59999
|
for (const audio of rootAudios) {
|
|
59569
60000
|
out.push({
|
|
59570
60001
|
srcRel: audio.srcRel,
|
|
59571
|
-
srcAbs:
|
|
60002
|
+
srcAbs: resolve59(opts.projectDir, audio.srcRel),
|
|
59572
60003
|
absoluteStart: audio.localStart,
|
|
59573
60004
|
durationHint: audio.durationHint,
|
|
59574
60005
|
clipDurationCap: Math.max(0, maxClipEnd - audio.localStart),
|
|
@@ -59603,7 +60034,7 @@ var init_scene_audio_scan = __esm({
|
|
|
59603
60034
|
|
|
59604
60035
|
// src/commands/_shared/scene-audio-mux.ts
|
|
59605
60036
|
import { rename as rename4, unlink } from "node:fs/promises";
|
|
59606
|
-
import { resolve as
|
|
60037
|
+
import { resolve as resolve60, dirname as dirname20, extname as extname13, basename as basename20 } from "node:path";
|
|
59607
60038
|
function buildAudioMuxFilter(audios) {
|
|
59608
60039
|
if (audios.length === 0) return null;
|
|
59609
60040
|
const labels = [];
|
|
@@ -59663,8 +60094,8 @@ async function muxAudioIntoVideo(opts) {
|
|
|
59663
60094
|
return { success: true, outputPath: opts.videoPath, audioCount: 0 };
|
|
59664
60095
|
}
|
|
59665
60096
|
const ext = extname13(opts.videoPath) || `.${opts.format}`;
|
|
59666
|
-
const tmpPath =
|
|
59667
|
-
|
|
60097
|
+
const tmpPath = resolve60(
|
|
60098
|
+
dirname20(opts.videoPath),
|
|
59668
60099
|
`.${basename20(opts.videoPath, ext)}.muxing${ext}`
|
|
59669
60100
|
);
|
|
59670
60101
|
const args = ["-y", "-loglevel", "error", "-i", opts.videoPath];
|
|
@@ -59726,15 +60157,15 @@ var init_scene_audio_mux = __esm({
|
|
|
59726
60157
|
});
|
|
59727
60158
|
|
|
59728
60159
|
// src/commands/_shared/scene-assemble.ts
|
|
59729
|
-
import { existsSync as
|
|
60160
|
+
import { existsSync as existsSync49 } from "node:fs";
|
|
59730
60161
|
import { readFile as readFile42 } from "node:fs/promises";
|
|
59731
|
-
import { resolve as
|
|
60162
|
+
import { resolve as resolve61, isAbsolute as isAbsolute7 } from "node:path";
|
|
59732
60163
|
async function executeSceneAssemble(opts) {
|
|
59733
|
-
const projectDir =
|
|
60164
|
+
const projectDir = resolve61(opts.projectDir);
|
|
59734
60165
|
const root = opts.root ?? "index.html";
|
|
59735
60166
|
const format = opts.format ?? "mp4";
|
|
59736
|
-
const videoPath =
|
|
59737
|
-
if (!
|
|
60167
|
+
const videoPath = isAbsolute7(opts.videoPath) ? opts.videoPath : resolve61(projectDir, opts.videoPath);
|
|
60168
|
+
if (!existsSync49(videoPath)) {
|
|
59738
60169
|
return {
|
|
59739
60170
|
success: false,
|
|
59740
60171
|
audioCount: 0,
|
|
@@ -59743,8 +60174,8 @@ async function executeSceneAssemble(opts) {
|
|
|
59743
60174
|
error: `Video not found: ${videoPath}. Render it first (e.g. \`vibe render --silent\`).`
|
|
59744
60175
|
};
|
|
59745
60176
|
}
|
|
59746
|
-
const rootPath =
|
|
59747
|
-
if (!
|
|
60177
|
+
const rootPath = resolve61(projectDir, root);
|
|
60178
|
+
if (!existsSync49(rootPath)) {
|
|
59748
60179
|
return {
|
|
59749
60180
|
success: false,
|
|
59750
60181
|
audioCount: 0,
|
|
@@ -59811,9 +60242,9 @@ __export(scene_render_exports, {
|
|
|
59811
60242
|
qualityToCrf: () => qualityToCrf2
|
|
59812
60243
|
});
|
|
59813
60244
|
import { execFile as execFile2 } from "node:child_process";
|
|
59814
|
-
import { existsSync as
|
|
59815
|
-
import { mkdir as
|
|
59816
|
-
import { resolve as
|
|
60245
|
+
import { existsSync as existsSync50 } from "node:fs";
|
|
60246
|
+
import { mkdir as mkdir25, readFile as readFile43, stat as stat8, writeFile as writeFile45 } from "node:fs/promises";
|
|
60247
|
+
import { resolve as resolve62, relative as relative10, dirname as dirname21, basename as basename21, join as join27, isAbsolute as isAbsolute8 } from "node:path";
|
|
59817
60248
|
import { promisify as promisify2 } from "node:util";
|
|
59818
60249
|
import {
|
|
59819
60250
|
createRenderJob,
|
|
@@ -59826,9 +60257,9 @@ function defaultOutputPath(opts) {
|
|
|
59826
60257
|
const fmt = opts.format ?? "mp4";
|
|
59827
60258
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
59828
60259
|
const stamp = now.toISOString().replace(/[:T]/g, "-").replace(/\..+$/, "");
|
|
59829
|
-
const name = (opts.projectName ?? basename21(
|
|
60260
|
+
const name = (opts.projectName ?? basename21(resolve62(opts.projectDir))) || "scene";
|
|
59830
60261
|
const beat = opts.beatId ? `-${sanitizeFileSegment2(opts.beatId)}` : "";
|
|
59831
|
-
return
|
|
60262
|
+
return resolve62(opts.projectDir, "renders", `${name}${beat}-${stamp}.${fmt}`);
|
|
59832
60263
|
}
|
|
59833
60264
|
function buildRenderConfig(opts) {
|
|
59834
60265
|
const quality = opts.quality ?? "standard";
|
|
@@ -59866,7 +60297,7 @@ function buildMediaOpenCommand(action, filePath, platform3 = process.platform) {
|
|
|
59866
60297
|
display: ["cmd", ...args].map(quoteCliArg).join(" ")
|
|
59867
60298
|
};
|
|
59868
60299
|
}
|
|
59869
|
-
const target = action === "reveal" ?
|
|
60300
|
+
const target = action === "reveal" ? dirname21(filePath) : filePath;
|
|
59870
60301
|
return {
|
|
59871
60302
|
command: "xdg-open",
|
|
59872
60303
|
args: [target],
|
|
@@ -59874,7 +60305,7 @@ function buildMediaOpenCommand(action, filePath, platform3 = process.platform) {
|
|
|
59874
60305
|
};
|
|
59875
60306
|
}
|
|
59876
60307
|
async function executeSceneRender(opts = {}) {
|
|
59877
|
-
const projectDir =
|
|
60308
|
+
const projectDir = resolve62(opts.projectDir ?? ".");
|
|
59878
60309
|
const projectConfig = await readProjectConfig(projectDir);
|
|
59879
60310
|
const engine = projectConfig.config.composition.engine;
|
|
59880
60311
|
if (engine !== "hyperframes") {
|
|
@@ -59905,7 +60336,7 @@ async function executeSceneRender(opts = {}) {
|
|
|
59905
60336
|
}
|
|
59906
60337
|
let autoSyncApplied = false;
|
|
59907
60338
|
let autoSyncWarning;
|
|
59908
|
-
if (!opts.beatId &&
|
|
60339
|
+
if (!opts.beatId && existsSync50(join27(projectDir, "STORYBOARD.md"))) {
|
|
59909
60340
|
try {
|
|
59910
60341
|
const rootPlan = await createProjectRootSyncPlan({ projectDir });
|
|
59911
60342
|
const subPlans = await createSubCompDurationSyncPlans({
|
|
@@ -59947,7 +60378,7 @@ async function executeSceneRender(opts = {}) {
|
|
|
59947
60378
|
kind: "render",
|
|
59948
60379
|
beat: opts.beatId ?? null,
|
|
59949
60380
|
root,
|
|
59950
|
-
error: `Root composition not found: ${
|
|
60381
|
+
error: `Root composition not found: ${resolve62(projectDir, root)}. Run \`vibe build ${projectDir}\` once to create the render scaffold, or scaffold it up front with \`vibe init <dir> --profile full\`.`
|
|
59951
60382
|
};
|
|
59952
60383
|
}
|
|
59953
60384
|
const chrome = await preflightChrome();
|
|
@@ -59961,8 +60392,8 @@ async function executeSceneRender(opts = {}) {
|
|
|
59961
60392
|
};
|
|
59962
60393
|
}
|
|
59963
60394
|
const projectName = projectConfig.config.name;
|
|
59964
|
-
const outputPath = opts.output ?
|
|
59965
|
-
await
|
|
60395
|
+
const outputPath = opts.output ? resolve62(projectDir, opts.output) : defaultOutputPath({ projectDir, projectName, format: opts.format, beatId: opts.beatId });
|
|
60396
|
+
await mkdir25(dirname21(outputPath), { recursive: true });
|
|
59966
60397
|
const config2 = buildRenderConfig({
|
|
59967
60398
|
fps: opts.fps,
|
|
59968
60399
|
quality: opts.quality,
|
|
@@ -60074,11 +60505,11 @@ async function safeStat(p) {
|
|
|
60074
60505
|
}
|
|
60075
60506
|
async function prepareBeatRenderRoot(opts) {
|
|
60076
60507
|
const root = `.vibeframe/tmp/render-beat-${sanitizeFileSegment2(opts.beatId)}.html`;
|
|
60077
|
-
const reportPath =
|
|
60508
|
+
const reportPath = join27(opts.projectDir, "build-report.json");
|
|
60078
60509
|
const retryWith = [
|
|
60079
60510
|
`vibe build ${opts.projectDir} --beat ${opts.beatId} --stage sync --json`
|
|
60080
60511
|
];
|
|
60081
|
-
if (!
|
|
60512
|
+
if (!existsSync50(reportPath)) {
|
|
60082
60513
|
return {
|
|
60083
60514
|
success: false,
|
|
60084
60515
|
root,
|
|
@@ -60158,8 +60589,8 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
60158
60589
|
durationSec,
|
|
60159
60590
|
narrationPath
|
|
60160
60591
|
});
|
|
60161
|
-
await
|
|
60162
|
-
await
|
|
60592
|
+
await mkdir25(dirname21(join27(opts.projectDir, root)), { recursive: true });
|
|
60593
|
+
await writeFile45(join27(opts.projectDir, root), html, "utf-8");
|
|
60163
60594
|
return {
|
|
60164
60595
|
success: true,
|
|
60165
60596
|
root,
|
|
@@ -60223,9 +60654,9 @@ function reportedBeatAssetPaths(beat) {
|
|
|
60223
60654
|
]);
|
|
60224
60655
|
}
|
|
60225
60656
|
async function writeRenderReport(projectDir, result) {
|
|
60226
|
-
const reportPath =
|
|
60657
|
+
const reportPath = join27(projectDir, "render-report.json");
|
|
60227
60658
|
try {
|
|
60228
|
-
await
|
|
60659
|
+
await writeFile45(
|
|
60229
60660
|
reportPath,
|
|
60230
60661
|
JSON.stringify(
|
|
60231
60662
|
{
|
|
@@ -60264,8 +60695,8 @@ async function writeRenderReport(projectDir, result) {
|
|
|
60264
60695
|
}
|
|
60265
60696
|
}
|
|
60266
60697
|
function pathExists3(projectDir, value) {
|
|
60267
|
-
const abs =
|
|
60268
|
-
return
|
|
60698
|
+
const abs = isAbsolute8(value) ? value : resolve62(projectDir, value);
|
|
60699
|
+
return existsSync50(abs);
|
|
60269
60700
|
}
|
|
60270
60701
|
function stringValue(value) {
|
|
60271
60702
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
@@ -60318,14 +60749,15 @@ var init_scene_build_mode = __esm({
|
|
|
60318
60749
|
var scene_build_exports = {};
|
|
60319
60750
|
__export(scene_build_exports, {
|
|
60320
60751
|
executeSceneBuild: () => executeSceneBuild,
|
|
60752
|
+
isLikenessRejection: () => isLikenessRejection,
|
|
60321
60753
|
resolveSceneBuildMode: () => resolveSceneBuildMode
|
|
60322
60754
|
});
|
|
60323
|
-
import { existsSync as
|
|
60324
|
-
import { copyFile as copyFile5, mkdir as
|
|
60325
|
-
import { dirname as
|
|
60755
|
+
import { existsSync as existsSync51, readFileSync as readFileSync2 } from "node:fs";
|
|
60756
|
+
import { copyFile as copyFile5, mkdir as mkdir26, readFile as readFile44, rm as rm5, writeFile as writeFile46 } from "node:fs/promises";
|
|
60757
|
+
import { dirname as dirname22, join as join28, resolve as resolve63 } from "node:path";
|
|
60326
60758
|
function readProjectKindSync(projectDir) {
|
|
60327
60759
|
try {
|
|
60328
|
-
const raw = readFileSync2(
|
|
60760
|
+
const raw = readFileSync2(join28(projectDir, "vibe.config.json"), "utf-8");
|
|
60329
60761
|
const k = JSON.parse(raw).kind;
|
|
60330
60762
|
return typeof k === "string" && isSceneKind(k) ? k : "cinema";
|
|
60331
60763
|
} catch {
|
|
@@ -60334,16 +60766,17 @@ function readProjectKindSync(projectDir) {
|
|
|
60334
60766
|
}
|
|
60335
60767
|
async function executeSceneBuild(opts) {
|
|
60336
60768
|
const startedAt = Date.now();
|
|
60337
|
-
const projectDir =
|
|
60769
|
+
const projectDir = resolve63(opts.projectDir);
|
|
60338
60770
|
const onProgress = opts.onProgress ?? (() => {
|
|
60339
60771
|
});
|
|
60340
60772
|
const projectKind = readProjectKindSync(projectDir);
|
|
60341
60773
|
const kindPolicy = kindAssetPolicy(projectKind);
|
|
60342
60774
|
const composer = opts.composer ?? composerDefaultForKind(projectKind);
|
|
60343
|
-
const skipBackdrop = opts.skipBackdrop ?? kindPolicy.skipBackdrop ?? false;
|
|
60775
|
+
const skipBackdrop = opts.skipBackdrop ?? (composer === "footage" ? true : kindPolicy.skipBackdrop ?? false);
|
|
60344
60776
|
const skipKeyframe = opts.skipKeyframe ?? kindPolicy.skipKeyframe ?? false;
|
|
60345
60777
|
const skipVideoAssets = opts.skipVideo ?? kindPolicy.skipVideo ?? false;
|
|
60346
|
-
const
|
|
60778
|
+
const skipTranscript = opts.skipTranscript ?? composer === "footage";
|
|
60779
|
+
const mode = composer === "template" || composer === "footage" ? "batch" : resolveSceneBuildMode(opts);
|
|
60347
60780
|
const selectedStage = opts.stage ?? (opts.skipRender ? "sync" : "all");
|
|
60348
60781
|
const skipVideoStopsRender = (opts.skipVideo ?? false) && (selectedStage === "all" || selectedStage === "render");
|
|
60349
60782
|
const effectiveSkipRender = (opts.skipRender ?? false) || skipVideoStopsRender;
|
|
@@ -60356,7 +60789,7 @@ async function executeSceneBuild(opts) {
|
|
|
60356
60789
|
);
|
|
60357
60790
|
}
|
|
60358
60791
|
let sceneRepair = skippedSceneRepairSummary();
|
|
60359
|
-
const storyboardPath2 =
|
|
60792
|
+
const storyboardPath2 = join28(projectDir, "STORYBOARD.md");
|
|
60360
60793
|
const buildPlan = await createBuildPlan({
|
|
60361
60794
|
projectDir,
|
|
60362
60795
|
stage: selectedStage,
|
|
@@ -60372,8 +60805,10 @@ async function executeSceneBuild(opts) {
|
|
|
60372
60805
|
imageProvider: opts.imageProvider,
|
|
60373
60806
|
imageQuality: opts.imageQuality,
|
|
60374
60807
|
imageSize: opts.imageSize,
|
|
60808
|
+
imageModel: opts.imageModel,
|
|
60375
60809
|
videoProvider: opts.videoProvider,
|
|
60376
60810
|
musicProvider: opts.musicProvider,
|
|
60811
|
+
skipTranscript,
|
|
60377
60812
|
composer,
|
|
60378
60813
|
force: opts.force
|
|
60379
60814
|
});
|
|
@@ -60426,7 +60861,7 @@ async function executeSceneBuild(opts) {
|
|
|
60426
60861
|
}
|
|
60427
60862
|
if (!buildPlan.validation.ok) {
|
|
60428
60863
|
let invalidBeats = [];
|
|
60429
|
-
if (
|
|
60864
|
+
if (existsSync51(storyboardPath2)) {
|
|
60430
60865
|
invalidBeats = parseStoryboard(await loadStoryboardMarkdown(projectDir)).beats;
|
|
60431
60866
|
}
|
|
60432
60867
|
return finishBuildResult({
|
|
@@ -60451,7 +60886,7 @@ async function executeSceneBuild(opts) {
|
|
|
60451
60886
|
totalLatencyMs: Date.now() - startedAt
|
|
60452
60887
|
});
|
|
60453
60888
|
}
|
|
60454
|
-
if (!
|
|
60889
|
+
if (!existsSync51(storyboardPath2)) {
|
|
60455
60890
|
return finishBuildResult({
|
|
60456
60891
|
success: false,
|
|
60457
60892
|
phase: "failed",
|
|
@@ -60546,6 +60981,7 @@ async function executeSceneBuild(opts) {
|
|
|
60546
60981
|
imageProvider,
|
|
60547
60982
|
imageSize: opts.imageSize ?? "1536x1024",
|
|
60548
60983
|
imageQuality: opts.imageQuality ?? "hd",
|
|
60984
|
+
imageModel: opts.imageModel,
|
|
60549
60985
|
force: opts.force ?? false,
|
|
60550
60986
|
onProgress
|
|
60551
60987
|
}
|
|
@@ -60567,6 +61003,7 @@ async function executeSceneBuild(opts) {
|
|
|
60567
61003
|
musicProvider,
|
|
60568
61004
|
imageQuality: opts.imageQuality ?? "hd",
|
|
60569
61005
|
imageSize: opts.imageSize ?? "1536x1024",
|
|
61006
|
+
imageModel: opts.imageModel,
|
|
60570
61007
|
skipNarration: opts.skipNarration ?? false,
|
|
60571
61008
|
skipBackdrop,
|
|
60572
61009
|
skipVideo: skipVideoAssets,
|
|
@@ -60656,7 +61093,7 @@ async function executeSceneBuild(opts) {
|
|
|
60656
61093
|
totalLatencyMs: Date.now() - startedAt
|
|
60657
61094
|
});
|
|
60658
61095
|
}
|
|
60659
|
-
if (shouldRunStage(selectedStage, "transcript") && !
|
|
61096
|
+
if (shouldRunStage(selectedStage, "transcript") && !skipTranscript) {
|
|
60660
61097
|
const { statuses } = await runTranscriptStage(activeBeats, beatOutcomes, {
|
|
60661
61098
|
projectDir,
|
|
60662
61099
|
force: opts.force ?? false,
|
|
@@ -60685,9 +61122,9 @@ async function executeSceneBuild(opts) {
|
|
|
60685
61122
|
}
|
|
60686
61123
|
if (shouldRunStage(selectedStage, "compose")) {
|
|
60687
61124
|
if (mode === "agent") {
|
|
60688
|
-
const compositionsDir =
|
|
61125
|
+
const compositionsDir = join28(projectDir, "compositions");
|
|
60689
61126
|
const missingBeats = activeBeats.filter(
|
|
60690
|
-
(b) => !
|
|
61127
|
+
(b) => !existsSync51(join28(compositionsDir, `scene-${b.id}.html`))
|
|
60691
61128
|
);
|
|
60692
61129
|
if (missingBeats.length > 0) {
|
|
60693
61130
|
const plan = await getComposePrompts({ projectDir, beatId: opts.beatId });
|
|
@@ -60721,6 +61158,8 @@ async function executeSceneBuild(opts) {
|
|
|
60721
61158
|
}
|
|
60722
61159
|
onProgress({ type: "phase-start", phase: "compose" });
|
|
60723
61160
|
stageReports.compose.status = "done";
|
|
61161
|
+
} else if (composer === "footage") {
|
|
61162
|
+
stageReports.compose.status = "skipped";
|
|
60724
61163
|
} else if (composer === "template") {
|
|
60725
61164
|
onProgress({ type: "phase-start", phase: "compose" });
|
|
60726
61165
|
try {
|
|
@@ -60760,8 +61199,8 @@ async function executeSceneBuild(opts) {
|
|
|
60760
61199
|
if (stageReports.compose.status === "done") {
|
|
60761
61200
|
for (const beat of composer === "template" ? [] : activeBeats) {
|
|
60762
61201
|
const videoRel = `assets/video-${beat.id}.mp4`;
|
|
60763
|
-
const compositionAbs =
|
|
60764
|
-
if (!
|
|
61202
|
+
const compositionAbs = join28(projectDir, "compositions", `scene-${beat.id}.html`);
|
|
61203
|
+
if (!existsSync51(join28(projectDir, videoRel)) || !existsSync51(compositionAbs)) continue;
|
|
60765
61204
|
const html = readFileSync2(compositionAbs, "utf-8");
|
|
60766
61205
|
if (!html.includes(videoRel)) {
|
|
60767
61206
|
warnings.push(
|
|
@@ -60816,8 +61255,8 @@ async function executeSceneBuild(opts) {
|
|
|
60816
61255
|
totalLatencyMs: Date.now() - startedAt
|
|
60817
61256
|
});
|
|
60818
61257
|
}
|
|
60819
|
-
if (shouldRunStage(selectedStage, "sync")) {
|
|
60820
|
-
if (!
|
|
61258
|
+
if (composer !== "footage" && shouldRunStage(selectedStage, "sync")) {
|
|
61259
|
+
if (!existsSync51(join28(projectDir, "index.html"))) {
|
|
60821
61260
|
await scaffoldSceneProject({
|
|
60822
61261
|
dir: projectDir,
|
|
60823
61262
|
name: projectDir.split(/[\\/]/).filter(Boolean).pop(),
|
|
@@ -60886,7 +61325,50 @@ async function executeSceneBuild(opts) {
|
|
|
60886
61325
|
}
|
|
60887
61326
|
let outputPath;
|
|
60888
61327
|
let renderResult;
|
|
60889
|
-
|
|
61328
|
+
let footageReport;
|
|
61329
|
+
if (composer === "footage" && shouldRunStage(selectedStage, "render")) {
|
|
61330
|
+
onProgress({ type: "phase-start", phase: "render" });
|
|
61331
|
+
onProgress({ type: "render-start" });
|
|
61332
|
+
const assembled = await executeFootageAssemble({ projectDir, finish: true });
|
|
61333
|
+
if (!assembled.success) {
|
|
61334
|
+
stageReports.render.status = "failed";
|
|
61335
|
+
const renderRetryWith = unique5([
|
|
61336
|
+
...retryWith,
|
|
61337
|
+
`vibe build ${projectDir} --stage assets --json`,
|
|
61338
|
+
`vibe assemble ${projectDir} --footage --dry-run --json`
|
|
61339
|
+
]);
|
|
61340
|
+
stageReports.render.retryWith = unique5([
|
|
61341
|
+
...stageReports.render.retryWith,
|
|
61342
|
+
...renderRetryWith
|
|
61343
|
+
]);
|
|
61344
|
+
return finishBuildResult({
|
|
61345
|
+
success: false,
|
|
61346
|
+
phase: "failed",
|
|
61347
|
+
mode,
|
|
61348
|
+
selectedStage,
|
|
61349
|
+
code: "FOOTAGE_ASSEMBLE_FAILED",
|
|
61350
|
+
error: `footage assemble failed: ${assembled.error ?? "unknown"}`,
|
|
61351
|
+
message: `footage assemble failed: ${assembled.error ?? "unknown"}`,
|
|
61352
|
+
suggestion: assembled.suggestion ?? "Ensure every beat has a generated clip (run --stage assets), then retry.",
|
|
61353
|
+
recoverable: true,
|
|
61354
|
+
beats: beatOutcomes,
|
|
61355
|
+
estimatedCostUsd: buildPlan.estimatedCostUsd,
|
|
61356
|
+
costUsd: stageReports.assets.costUsd + stageReports.compose.costUsd,
|
|
61357
|
+
stageReports,
|
|
61358
|
+
sceneRepair,
|
|
61359
|
+
warnings,
|
|
61360
|
+
retryWith: renderRetryWith,
|
|
61361
|
+
status: "failed",
|
|
61362
|
+
currentStage: "render",
|
|
61363
|
+
totalLatencyMs: Date.now() - startedAt
|
|
61364
|
+
});
|
|
61365
|
+
}
|
|
61366
|
+
outputPath = assembled.outputPath;
|
|
61367
|
+
footageReport = assembled.report;
|
|
61368
|
+
warnings.push(...assembled.report?.warnings ?? []);
|
|
61369
|
+
onProgress({ type: "render-done", outputPath });
|
|
61370
|
+
stageReports.render.status = "done";
|
|
61371
|
+
} else if (shouldRunStage(selectedStage, "render")) {
|
|
60890
61372
|
onProgress({ type: "phase-start", phase: "render" });
|
|
60891
61373
|
onProgress({ type: "render-start" });
|
|
60892
61374
|
renderResult = await executeSceneRender({ projectDir });
|
|
@@ -60941,6 +61423,7 @@ async function executeSceneBuild(opts) {
|
|
|
60941
61423
|
beats: beatOutcomes,
|
|
60942
61424
|
outputPath,
|
|
60943
61425
|
renderResult,
|
|
61426
|
+
footageReport,
|
|
60944
61427
|
estimatedCostUsd: buildPlan.estimatedCostUsd,
|
|
60945
61428
|
costUsd: stageReports.assets.costUsd + stageReports.compose.costUsd,
|
|
60946
61429
|
stageReports,
|
|
@@ -61075,7 +61558,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
61075
61558
|
return {
|
|
61076
61559
|
status: "cached",
|
|
61077
61560
|
path: existingRel,
|
|
61078
|
-
durationSec: await safeAudioDuration(
|
|
61561
|
+
durationSec: await safeAudioDuration(join28(ctx.projectDir, existingRel)),
|
|
61079
61562
|
provider: metadata?.provider,
|
|
61080
61563
|
cachePath: metadata?.cachePath,
|
|
61081
61564
|
cacheKey: metadata?.cacheKey,
|
|
@@ -61099,9 +61582,9 @@ async function dispatchNarration(beat, ctx) {
|
|
|
61099
61582
|
voice,
|
|
61100
61583
|
ext: resolution.audioExtension
|
|
61101
61584
|
});
|
|
61102
|
-
const cacheAbs =
|
|
61585
|
+
const cacheAbs = join28(ctx.projectDir, cache.path);
|
|
61103
61586
|
const rel = `assets/narration-${beat.id}.${resolution.audioExtension}`;
|
|
61104
|
-
const abs =
|
|
61587
|
+
const abs = join28(ctx.projectDir, rel);
|
|
61105
61588
|
if (existingRel && !ctx.force && isFreshCanonicalAsset({
|
|
61106
61589
|
projectDir: ctx.projectDir,
|
|
61107
61590
|
kind: "narration",
|
|
@@ -61115,7 +61598,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
61115
61598
|
return {
|
|
61116
61599
|
status: "cached",
|
|
61117
61600
|
path: existingRel,
|
|
61118
|
-
durationSec: await safeAudioDuration(
|
|
61601
|
+
durationSec: await safeAudioDuration(join28(ctx.projectDir, existingRel)),
|
|
61119
61602
|
provider: resolution.provider,
|
|
61120
61603
|
cachePath: cache.path,
|
|
61121
61604
|
cacheKey: cache.key,
|
|
@@ -61123,8 +61606,8 @@ async function dispatchNarration(beat, ctx) {
|
|
|
61123
61606
|
freshness: "fresh"
|
|
61124
61607
|
};
|
|
61125
61608
|
}
|
|
61126
|
-
if (
|
|
61127
|
-
await
|
|
61609
|
+
if (existsSync51(cacheAbs) && !ctx.force) {
|
|
61610
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61128
61611
|
await copyFile5(cacheAbs, abs);
|
|
61129
61612
|
await writeAssetMetadata({
|
|
61130
61613
|
projectDir: ctx.projectDir,
|
|
@@ -61155,14 +61638,14 @@ async function dispatchNarration(beat, ctx) {
|
|
|
61155
61638
|
ctx.onProgress({ type: "narration-failed", beatId: beat.id, error });
|
|
61156
61639
|
return { status: "failed", error };
|
|
61157
61640
|
}
|
|
61158
|
-
await
|
|
61159
|
-
await
|
|
61641
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61642
|
+
await writeFile46(abs, result.audioBuffer);
|
|
61160
61643
|
for (const otherExt of ["mp3", "wav"]) {
|
|
61161
|
-
const sibling =
|
|
61162
|
-
if (sibling !== abs &&
|
|
61644
|
+
const sibling = join28(ctx.projectDir, `assets/narration-${beat.id}.${otherExt}`);
|
|
61645
|
+
if (sibling !== abs && existsSync51(sibling)) await rm5(sibling, { force: true });
|
|
61163
61646
|
}
|
|
61164
|
-
await
|
|
61165
|
-
await
|
|
61647
|
+
await mkdir26(dirname22(cacheAbs), { recursive: true });
|
|
61648
|
+
await writeFile46(cacheAbs, result.audioBuffer);
|
|
61166
61649
|
await writeAssetMetadata({
|
|
61167
61650
|
projectDir: ctx.projectDir,
|
|
61168
61651
|
kind: "narration",
|
|
@@ -61194,8 +61677,8 @@ async function dispatchNarration(beat, ctx) {
|
|
|
61194
61677
|
async function dispatchTranscript(beat, narrationPath, narrationFresh, ctx) {
|
|
61195
61678
|
if (!narrationPath) return "skipped";
|
|
61196
61679
|
const relPath = beatTranscriptRelPath(beat.id);
|
|
61197
|
-
const abs =
|
|
61198
|
-
if (
|
|
61680
|
+
const abs = join28(ctx.projectDir, relPath);
|
|
61681
|
+
if (existsSync51(abs) && !ctx.force && !narrationFresh) {
|
|
61199
61682
|
ctx.onProgress({ type: "transcript-cached", beatId: beat.id, path: relPath });
|
|
61200
61683
|
return "cached";
|
|
61201
61684
|
}
|
|
@@ -61208,7 +61691,7 @@ async function dispatchTranscript(beat, narrationPath, narrationFresh, ctx) {
|
|
|
61208
61691
|
});
|
|
61209
61692
|
return "skipped";
|
|
61210
61693
|
}
|
|
61211
|
-
const words = await transcribeNarrationWords(
|
|
61694
|
+
const words = await transcribeNarrationWords(join28(ctx.projectDir, narrationPath), { apiKey });
|
|
61212
61695
|
if (words.length === 0) {
|
|
61213
61696
|
ctx.onProgress({
|
|
61214
61697
|
type: "transcript-skipped",
|
|
@@ -61218,8 +61701,8 @@ async function dispatchTranscript(beat, narrationPath, narrationFresh, ctx) {
|
|
|
61218
61701
|
return "skipped";
|
|
61219
61702
|
}
|
|
61220
61703
|
try {
|
|
61221
|
-
await
|
|
61222
|
-
await
|
|
61704
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61705
|
+
await writeFile46(abs, JSON.stringify(words, null, 2), "utf-8");
|
|
61223
61706
|
} catch (err) {
|
|
61224
61707
|
ctx.onProgress({
|
|
61225
61708
|
type: "transcript-skipped",
|
|
@@ -61266,7 +61749,7 @@ async function buildCharacters(characters, ctx) {
|
|
|
61266
61749
|
const size = ctx.imageSize ?? "1536x1024";
|
|
61267
61750
|
for (const character of characters) {
|
|
61268
61751
|
if (character.imagePath) {
|
|
61269
|
-
if (
|
|
61752
|
+
if (existsSync51(join28(ctx.projectDir, character.imagePath))) {
|
|
61270
61753
|
paths.set(character.name, character.imagePath);
|
|
61271
61754
|
ctx.onProgress({ type: "character-cached", name: character.name, path: character.imagePath });
|
|
61272
61755
|
} else {
|
|
@@ -61279,16 +61762,17 @@ async function buildCharacters(characters, ctx) {
|
|
|
61279
61762
|
if (!character.prompt) continue;
|
|
61280
61763
|
const prompt3 = characterSheetPrompt(character.name, character.prompt);
|
|
61281
61764
|
const rel = `assets/character-${character.name}.png`;
|
|
61282
|
-
const abs =
|
|
61765
|
+
const abs = join28(ctx.projectDir, rel);
|
|
61283
61766
|
const metadataOptions = { quality: ctx.imageQuality, size };
|
|
61284
61767
|
const cache = characterCacheDescriptor({
|
|
61285
61768
|
name: character.name,
|
|
61286
61769
|
cue: prompt3,
|
|
61287
61770
|
provider: ctx.imageProvider,
|
|
61288
61771
|
quality: ctx.imageQuality,
|
|
61289
|
-
size
|
|
61772
|
+
size,
|
|
61773
|
+
model: ctx.imageModel
|
|
61290
61774
|
});
|
|
61291
|
-
if (
|
|
61775
|
+
if (existsSync51(abs) && !ctx.force) {
|
|
61292
61776
|
const metadata = readAssetMetadata(ctx.projectDir, "character", character.name);
|
|
61293
61777
|
if (!metadata || isFreshCanonicalAsset({
|
|
61294
61778
|
projectDir: ctx.projectDir,
|
|
@@ -61304,9 +61788,9 @@ async function buildCharacters(characters, ctx) {
|
|
|
61304
61788
|
continue;
|
|
61305
61789
|
}
|
|
61306
61790
|
}
|
|
61307
|
-
const cacheAbs =
|
|
61308
|
-
if (
|
|
61309
|
-
await
|
|
61791
|
+
const cacheAbs = join28(ctx.projectDir, cache.path);
|
|
61792
|
+
if (existsSync51(cacheAbs) && !ctx.force) {
|
|
61793
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61310
61794
|
await copyFile5(cacheAbs, abs);
|
|
61311
61795
|
await writeAssetMetadata({
|
|
61312
61796
|
projectDir: ctx.projectDir,
|
|
@@ -61329,7 +61813,8 @@ async function buildCharacters(characters, ctx) {
|
|
|
61329
61813
|
projectDir: ctx.projectDir,
|
|
61330
61814
|
imageProvider: ctx.imageProvider,
|
|
61331
61815
|
imageSize: size,
|
|
61332
|
-
imageQuality: ctx.imageQuality
|
|
61816
|
+
imageQuality: ctx.imageQuality,
|
|
61817
|
+
imageModel: ctx.imageModel
|
|
61333
61818
|
},
|
|
61334
61819
|
imageRatioForSize(size)
|
|
61335
61820
|
);
|
|
@@ -61338,10 +61823,10 @@ async function buildCharacters(characters, ctx) {
|
|
|
61338
61823
|
ctx.onProgress({ type: "character-failed", name: character.name, error: generated.error });
|
|
61339
61824
|
continue;
|
|
61340
61825
|
}
|
|
61341
|
-
await
|
|
61342
|
-
await
|
|
61343
|
-
await
|
|
61344
|
-
await
|
|
61826
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61827
|
+
await writeFile46(abs, generated.buffer);
|
|
61828
|
+
await mkdir26(dirname22(cacheAbs), { recursive: true });
|
|
61829
|
+
await writeFile46(cacheAbs, generated.buffer);
|
|
61345
61830
|
await writeAssetMetadata({
|
|
61346
61831
|
projectDir: ctx.projectDir,
|
|
61347
61832
|
kind: "character",
|
|
@@ -61371,7 +61856,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
61371
61856
|
if (!cue) return { status: "no-cue" };
|
|
61372
61857
|
const prompt3 = augmentBackdropPrompt(cue);
|
|
61373
61858
|
const rel = `assets/backdrop-${beat.id}.png`;
|
|
61374
|
-
const abs =
|
|
61859
|
+
const abs = join28(ctx.projectDir, rel);
|
|
61375
61860
|
const size = ctx.imageSize ?? "1536x1024";
|
|
61376
61861
|
const ratio = imageRatioForSize(size);
|
|
61377
61862
|
const metadataOptions = { quality: ctx.imageQuality, size, ratio };
|
|
@@ -61381,10 +61866,11 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
61381
61866
|
provider: ctx.imageProvider,
|
|
61382
61867
|
quality: ctx.imageQuality,
|
|
61383
61868
|
size,
|
|
61384
|
-
ratio
|
|
61869
|
+
ratio,
|
|
61870
|
+
model: ctx.imageModel
|
|
61385
61871
|
});
|
|
61386
61872
|
const metadataPath = assetMetadataPath("backdrop", beat.id);
|
|
61387
|
-
if (
|
|
61873
|
+
if (existsSync51(abs) && !ctx.force) {
|
|
61388
61874
|
const metadata = readAssetMetadata(ctx.projectDir, "backdrop", beat.id);
|
|
61389
61875
|
if (!metadata || isFreshCanonicalAsset({
|
|
61390
61876
|
projectDir: ctx.projectDir,
|
|
@@ -61407,9 +61893,9 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
61407
61893
|
};
|
|
61408
61894
|
}
|
|
61409
61895
|
}
|
|
61410
|
-
const cacheAbs =
|
|
61411
|
-
if (
|
|
61412
|
-
await
|
|
61896
|
+
const cacheAbs = join28(ctx.projectDir, cache.path);
|
|
61897
|
+
if (existsSync51(cacheAbs) && !ctx.force) {
|
|
61898
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61413
61899
|
await copyFile5(cacheAbs, abs);
|
|
61414
61900
|
await writeAssetMetadata({
|
|
61415
61901
|
projectDir: ctx.projectDir,
|
|
@@ -61439,11 +61925,11 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
61439
61925
|
ctx.onProgress({ type: "backdrop-failed", beatId: beat.id, error });
|
|
61440
61926
|
return { status: "failed", error };
|
|
61441
61927
|
}
|
|
61442
|
-
await
|
|
61928
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61443
61929
|
const buffer = generated.buffer;
|
|
61444
|
-
await
|
|
61445
|
-
await
|
|
61446
|
-
await
|
|
61930
|
+
await writeFile46(abs, buffer);
|
|
61931
|
+
await mkdir26(dirname22(cacheAbs), { recursive: true });
|
|
61932
|
+
await writeFile46(cacheAbs, buffer);
|
|
61447
61933
|
await writeAssetMetadata({
|
|
61448
61934
|
projectDir: ctx.projectDir,
|
|
61449
61935
|
kind: "backdrop",
|
|
@@ -61485,7 +61971,9 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
|
|
|
61485
61971
|
const provider2 = new OpenAIImageProvider();
|
|
61486
61972
|
await provider2.initialize({ apiKey });
|
|
61487
61973
|
const result2 = await provider2.generateImage(prompt3, {
|
|
61488
|
-
|
|
61974
|
+
// CLI input is free-form; an alias the provider doesn't know fails the
|
|
61975
|
+
// API call and surfaces as a beat-scoped backdrop/keyframe error.
|
|
61976
|
+
model: ctx.imageModel ?? "gpt-image-2",
|
|
61489
61977
|
size: ctx.imageSize,
|
|
61490
61978
|
quality: ctx.imageQuality
|
|
61491
61979
|
});
|
|
@@ -61495,7 +61983,7 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
|
|
|
61495
61983
|
const provider2 = new GeminiProvider();
|
|
61496
61984
|
await provider2.initialize({ apiKey });
|
|
61497
61985
|
const result2 = await provider2.generateImage(prompt3, {
|
|
61498
|
-
model: "flash",
|
|
61986
|
+
model: ctx.imageModel ?? "flash",
|
|
61499
61987
|
aspectRatio: ratio
|
|
61500
61988
|
});
|
|
61501
61989
|
return imageBufferFromResult(result2);
|
|
@@ -61528,7 +62016,7 @@ async function editKeyframeImage(prompt3, sheetBuffers, ctx, ratio) {
|
|
|
61528
62016
|
const provider2 = new GeminiProvider();
|
|
61529
62017
|
await provider2.initialize({ apiKey });
|
|
61530
62018
|
const result2 = await provider2.editImage(sheetBuffers, prompt3, {
|
|
61531
|
-
model: "flash",
|
|
62019
|
+
model: ctx.imageModel ?? "flash",
|
|
61532
62020
|
aspectRatio: ratio
|
|
61533
62021
|
});
|
|
61534
62022
|
return imageBufferFromResult(result2);
|
|
@@ -61540,7 +62028,7 @@ async function editKeyframeImage(prompt3, sheetBuffers, ctx, ratio) {
|
|
|
61540
62028
|
}
|
|
61541
62029
|
async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
61542
62030
|
const rel = `assets/keyframe-${beat.id}.png`;
|
|
61543
|
-
const abs =
|
|
62031
|
+
const abs = join28(ctx.projectDir, rel);
|
|
61544
62032
|
const size = ctx.imageSize ?? "1536x1024";
|
|
61545
62033
|
const ratio = imageRatioForSize(size);
|
|
61546
62034
|
const metadataOptions = { quality: ctx.imageQuality, size, ratio };
|
|
@@ -61551,9 +62039,10 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
61551
62039
|
quality: ctx.imageQuality,
|
|
61552
62040
|
size,
|
|
61553
62041
|
ratio,
|
|
61554
|
-
characters: characterRefsRel
|
|
62042
|
+
characters: characterRefsRel,
|
|
62043
|
+
model: ctx.imageModel
|
|
61555
62044
|
});
|
|
61556
|
-
if (
|
|
62045
|
+
if (existsSync51(abs) && !ctx.force) {
|
|
61557
62046
|
const metadata = readAssetMetadata(ctx.projectDir, "keyframe", beat.id);
|
|
61558
62047
|
if (!metadata || isFreshCanonicalAsset({
|
|
61559
62048
|
projectDir: ctx.projectDir,
|
|
@@ -61567,9 +62056,9 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
61567
62056
|
return { status: "cached", rel };
|
|
61568
62057
|
}
|
|
61569
62058
|
}
|
|
61570
|
-
const cacheAbs =
|
|
61571
|
-
if (
|
|
61572
|
-
await
|
|
62059
|
+
const cacheAbs = join28(ctx.projectDir, cache.path);
|
|
62060
|
+
if (existsSync51(cacheAbs) && !ctx.force) {
|
|
62061
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61573
62062
|
await copyFile5(cacheAbs, abs);
|
|
61574
62063
|
await writeAssetMetadata({
|
|
61575
62064
|
projectDir: ctx.projectDir,
|
|
@@ -61586,22 +62075,23 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
61586
62075
|
}
|
|
61587
62076
|
const sheetBuffers = [];
|
|
61588
62077
|
for (const relPath of characterRefsRel) {
|
|
61589
|
-
const sheetAbs =
|
|
61590
|
-
if (
|
|
62078
|
+
const sheetAbs = join28(ctx.projectDir, relPath);
|
|
62079
|
+
if (existsSync51(sheetAbs)) sheetBuffers.push(await readFile44(sheetAbs));
|
|
61591
62080
|
}
|
|
61592
62081
|
const imgCtx = {
|
|
61593
62082
|
projectDir: ctx.projectDir,
|
|
61594
62083
|
imageProvider: ctx.imageProvider,
|
|
61595
62084
|
imageSize: size,
|
|
61596
|
-
imageQuality: ctx.imageQuality
|
|
62085
|
+
imageQuality: ctx.imageQuality,
|
|
62086
|
+
imageModel: ctx.imageModel
|
|
61597
62087
|
};
|
|
61598
62088
|
const identityLock = "Keep the EXACT same person and face as the reference image(s): identical facial features (eyes, nose shape, jawline), skin tone and complexion, hairstyle, hair color, and wardrobe. Do not restyle or change the face. Change only the scene, pose, framing, and lighting. ";
|
|
61599
62089
|
const generated = sheetBuffers.length > 0 ? await editKeyframeImage(`${identityLock}${keyframeCue}`, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
|
|
61600
62090
|
if (!generated.success) return { status: "failed", error: generated.error };
|
|
61601
|
-
await
|
|
61602
|
-
await
|
|
61603
|
-
await
|
|
61604
|
-
await
|
|
62091
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
62092
|
+
await writeFile46(abs, generated.buffer);
|
|
62093
|
+
await mkdir26(dirname22(cacheAbs), { recursive: true });
|
|
62094
|
+
await writeFile46(cacheAbs, generated.buffer);
|
|
61605
62095
|
await writeAssetMetadata({
|
|
61606
62096
|
projectDir: ctx.projectDir,
|
|
61607
62097
|
kind: "keyframe",
|
|
@@ -61655,14 +62145,16 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61655
62145
|
const keyframeCue = stringOrUndefined4(beat.cues?.keyframe);
|
|
61656
62146
|
const prompt3 = stringOrUndefined4(beat.cues?.video) ?? keyframeCue;
|
|
61657
62147
|
if (!prompt3) return { status: "no-cue" };
|
|
62148
|
+
const providerCue = stringOrUndefined4(beat.cues?.provider);
|
|
62149
|
+
const requestedProvider = providerCue ? resolveBuildVideoProvider(providerCue) : ctx.videoProvider;
|
|
61658
62150
|
const characterRefsRel = beatCharacterNames(beat.cues).map((name) => ctx.characterPaths?.get(name)).filter((p) => typeof p === "string");
|
|
61659
|
-
const characterRefsAbs = characterRefsRel.map((p) =>
|
|
62151
|
+
const characterRefsAbs = characterRefsRel.map((p) => join28(ctx.projectDir, p));
|
|
61660
62152
|
const rel = `assets/video-${beat.id}.mp4`;
|
|
61661
|
-
const abs =
|
|
62153
|
+
const abs = join28(ctx.projectDir, rel);
|
|
61662
62154
|
const cache = videoCacheDescriptor({
|
|
61663
62155
|
beatId: beat.id,
|
|
61664
62156
|
cue: prompt3,
|
|
61665
|
-
provider:
|
|
62157
|
+
provider: requestedProvider,
|
|
61666
62158
|
duration: normalizeVideoDuration(beat.duration),
|
|
61667
62159
|
// Keyframe mode keys the clip to the keyframe prompt; refs feed the keyframe,
|
|
61668
62160
|
// not the clip directly.
|
|
@@ -61670,14 +62162,14 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61670
62162
|
keyframe: keyframeCue
|
|
61671
62163
|
});
|
|
61672
62164
|
const metadataPath = assetMetadataPath("video", beat.id);
|
|
61673
|
-
if (
|
|
62165
|
+
if (existsSync51(abs) && !ctx.force) {
|
|
61674
62166
|
const metadata = readAssetMetadata(ctx.projectDir, "video", beat.id);
|
|
61675
62167
|
if (!metadata || isFreshCanonicalAsset({
|
|
61676
62168
|
projectDir: ctx.projectDir,
|
|
61677
62169
|
kind: "video",
|
|
61678
62170
|
beatId: beat.id,
|
|
61679
62171
|
cue: prompt3,
|
|
61680
|
-
provider:
|
|
62172
|
+
provider: requestedProvider,
|
|
61681
62173
|
options: { duration: normalizeVideoDuration(beat.duration), ratio: "16:9" },
|
|
61682
62174
|
cacheKey: cache.key
|
|
61683
62175
|
})) {
|
|
@@ -61685,7 +62177,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61685
62177
|
return {
|
|
61686
62178
|
status: "cached",
|
|
61687
62179
|
path: rel,
|
|
61688
|
-
provider: metadata?.provider ??
|
|
62180
|
+
provider: metadata?.provider ?? requestedProvider,
|
|
61689
62181
|
cachePath: metadata?.cachePath ?? cache.path,
|
|
61690
62182
|
cacheKey: metadata?.cacheKey ?? cache.key,
|
|
61691
62183
|
metadataPath,
|
|
@@ -61693,16 +62185,16 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61693
62185
|
};
|
|
61694
62186
|
}
|
|
61695
62187
|
}
|
|
61696
|
-
const cacheAbs =
|
|
61697
|
-
if (
|
|
61698
|
-
await
|
|
62188
|
+
const cacheAbs = join28(ctx.projectDir, cache.path);
|
|
62189
|
+
if (existsSync51(cacheAbs) && !ctx.force) {
|
|
62190
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61699
62191
|
await copyFile5(cacheAbs, abs);
|
|
61700
62192
|
await writeAssetMetadata({
|
|
61701
62193
|
projectDir: ctx.projectDir,
|
|
61702
62194
|
kind: "video",
|
|
61703
62195
|
beatId: beat.id,
|
|
61704
62196
|
cue: prompt3,
|
|
61705
|
-
provider:
|
|
62197
|
+
provider: requestedProvider,
|
|
61706
62198
|
options: { duration: normalizeVideoDuration(beat.duration), ratio: "16:9" },
|
|
61707
62199
|
cacheKey: cache.key,
|
|
61708
62200
|
canonicalPath: rel,
|
|
@@ -61712,7 +62204,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61712
62204
|
return {
|
|
61713
62205
|
status: "cached",
|
|
61714
62206
|
path: rel,
|
|
61715
|
-
provider:
|
|
62207
|
+
provider: requestedProvider,
|
|
61716
62208
|
cachePath: cache.path,
|
|
61717
62209
|
cacheKey: cache.key,
|
|
61718
62210
|
metadataPath,
|
|
@@ -61725,11 +62217,11 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61725
62217
|
ctx.onProgress({ type: "video-skipped", beatId: beat.id, reason });
|
|
61726
62218
|
return { status: "skipped" };
|
|
61727
62219
|
}
|
|
61728
|
-
const keyframeImageAbs = keyframeImageRel ?
|
|
62220
|
+
const keyframeImageAbs = keyframeImageRel ? join28(ctx.projectDir, keyframeImageRel) : void 0;
|
|
61729
62221
|
loadSceneBuildEnv(ctx.projectDir);
|
|
61730
|
-
const
|
|
62222
|
+
const generateWith = (provider, apiKey) => executeVideoGenerate({
|
|
61731
62223
|
prompt: prompt3,
|
|
61732
|
-
provider
|
|
62224
|
+
provider,
|
|
61733
62225
|
duration: normalizeVideoDuration(beat.duration),
|
|
61734
62226
|
ratio: "16:9",
|
|
61735
62227
|
output: abs,
|
|
@@ -61742,22 +62234,44 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61742
62234
|
// track carries audio), so the model's generated audio is never used. Disable
|
|
61743
62235
|
// it: it's wasted, and Seedance's audio moderation can spuriously fail a beat.
|
|
61744
62236
|
generateAudio: false,
|
|
61745
|
-
apiKey
|
|
62237
|
+
apiKey
|
|
61746
62238
|
});
|
|
62239
|
+
let activeProvider = requestedProvider;
|
|
62240
|
+
let result = await generateWith(
|
|
62241
|
+
activeProvider,
|
|
62242
|
+
await apiKeyForVideoProvider(activeProvider, ctx.projectDir)
|
|
62243
|
+
);
|
|
61747
62244
|
if (!result.success || !result.taskId) {
|
|
61748
62245
|
const error = result.error ?? "video generation did not return a task id";
|
|
61749
|
-
|
|
61750
|
-
|
|
62246
|
+
const runwayKey = isLikenessRejection(error) && activeProvider !== "runway" ? await apiKeyForVideoProvider("runway", ctx.projectDir) : void 0;
|
|
62247
|
+
if (!runwayKey) {
|
|
62248
|
+
ctx.onProgress({ type: "video-failed", beatId: beat.id, error });
|
|
62249
|
+
return { status: "failed", error };
|
|
62250
|
+
}
|
|
62251
|
+
ctx.onProgress({
|
|
62252
|
+
type: "video-fallback",
|
|
62253
|
+
beatId: beat.id,
|
|
62254
|
+
from: activeProvider,
|
|
62255
|
+
to: "runway",
|
|
62256
|
+
reason: error
|
|
62257
|
+
});
|
|
62258
|
+
activeProvider = "runway";
|
|
62259
|
+
result = await generateWith(activeProvider, runwayKey);
|
|
62260
|
+
if (!result.success || !result.taskId) {
|
|
62261
|
+
const fallbackError = result.error ?? "video generation did not return a task id";
|
|
62262
|
+
ctx.onProgress({ type: "video-failed", beatId: beat.id, error: fallbackError });
|
|
62263
|
+
return { status: "failed", error: fallbackError };
|
|
62264
|
+
}
|
|
61751
62265
|
}
|
|
61752
|
-
if (result.status === "completed" &&
|
|
61753
|
-
await
|
|
62266
|
+
if (result.status === "completed" && existsSync51(abs)) {
|
|
62267
|
+
await mkdir26(dirname22(cacheAbs), { recursive: true });
|
|
61754
62268
|
await copyFile5(abs, cacheAbs);
|
|
61755
62269
|
await writeAssetMetadata({
|
|
61756
62270
|
projectDir: ctx.projectDir,
|
|
61757
62271
|
kind: "video",
|
|
61758
62272
|
beatId: beat.id,
|
|
61759
62273
|
cue: prompt3,
|
|
61760
|
-
provider: result.provider ??
|
|
62274
|
+
provider: result.provider ?? activeProvider,
|
|
61761
62275
|
options: { duration: normalizeVideoDuration(beat.duration), ratio: "16:9" },
|
|
61762
62276
|
cacheKey: cache.key,
|
|
61763
62277
|
canonicalPath: rel,
|
|
@@ -61767,12 +62281,12 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61767
62281
|
type: "video-generated",
|
|
61768
62282
|
beatId: beat.id,
|
|
61769
62283
|
path: rel,
|
|
61770
|
-
provider: result.provider ??
|
|
62284
|
+
provider: result.provider ?? activeProvider
|
|
61771
62285
|
});
|
|
61772
62286
|
return {
|
|
61773
62287
|
status: "generated",
|
|
61774
62288
|
path: rel,
|
|
61775
|
-
provider: result.provider ??
|
|
62289
|
+
provider: result.provider ?? activeProvider,
|
|
61776
62290
|
cachePath: cache.path,
|
|
61777
62291
|
cacheKey: cache.key,
|
|
61778
62292
|
metadataPath,
|
|
@@ -61781,7 +62295,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
61781
62295
|
}
|
|
61782
62296
|
const job = await createAndWriteJobRecord({
|
|
61783
62297
|
jobType: "generate-video",
|
|
61784
|
-
provider: result.provider ??
|
|
62298
|
+
provider: result.provider ?? activeProvider,
|
|
61785
62299
|
providerTaskId: result.taskId,
|
|
61786
62300
|
providerTaskType: keyframeImageAbs ? "image2video" : "text2video",
|
|
61787
62301
|
status: "running",
|
|
@@ -61817,7 +62331,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
61817
62331
|
const prompt3 = stringOrUndefined4(beat.cues?.music);
|
|
61818
62332
|
if (!prompt3) return { status: "no-cue" };
|
|
61819
62333
|
const rel = `assets/music-${beat.id}.mp3`;
|
|
61820
|
-
const abs =
|
|
62334
|
+
const abs = join28(ctx.projectDir, rel);
|
|
61821
62335
|
const duration = normalizeMusicDuration(beat.duration);
|
|
61822
62336
|
const cache = musicCacheDescriptor({
|
|
61823
62337
|
beatId: beat.id,
|
|
@@ -61826,7 +62340,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
61826
62340
|
duration
|
|
61827
62341
|
});
|
|
61828
62342
|
const metadataPath = assetMetadataPath("music", beat.id);
|
|
61829
|
-
if (
|
|
62343
|
+
if (existsSync51(abs) && !ctx.force) {
|
|
61830
62344
|
const metadata = readAssetMetadata(ctx.projectDir, "music", beat.id);
|
|
61831
62345
|
if (!metadata || isFreshCanonicalAsset({
|
|
61832
62346
|
projectDir: ctx.projectDir,
|
|
@@ -61850,9 +62364,9 @@ async function dispatchMusic(beat, ctx) {
|
|
|
61850
62364
|
};
|
|
61851
62365
|
}
|
|
61852
62366
|
}
|
|
61853
|
-
const cacheAbs =
|
|
61854
|
-
if (
|
|
61855
|
-
await
|
|
62367
|
+
const cacheAbs = join28(ctx.projectDir, cache.path);
|
|
62368
|
+
if (existsSync51(cacheAbs) && !ctx.force) {
|
|
62369
|
+
await mkdir26(dirname22(abs), { recursive: true });
|
|
61856
62370
|
await copyFile5(cacheAbs, abs);
|
|
61857
62371
|
await writeAssetMetadata({
|
|
61858
62372
|
projectDir: ctx.projectDir,
|
|
@@ -61925,12 +62439,12 @@ async function dispatchMusic(beat, ctx) {
|
|
|
61925
62439
|
metadataPath
|
|
61926
62440
|
};
|
|
61927
62441
|
}
|
|
61928
|
-
if (!
|
|
62442
|
+
if (!existsSync51(abs)) {
|
|
61929
62443
|
const error = result.outputPath ? `music output was not written at ${abs}` : "music generation did not return an output file";
|
|
61930
62444
|
ctx.onProgress({ type: "music-failed", beatId: beat.id, error });
|
|
61931
62445
|
return { status: "failed", error };
|
|
61932
62446
|
}
|
|
61933
|
-
await
|
|
62447
|
+
await mkdir26(dirname22(cacheAbs), { recursive: true });
|
|
61934
62448
|
await copyFile5(abs, cacheAbs);
|
|
61935
62449
|
await writeAssetMetadata({
|
|
61936
62450
|
projectDir: ctx.projectDir,
|
|
@@ -61961,15 +62475,15 @@ async function dispatchMusic(beat, ctx) {
|
|
|
61961
62475
|
};
|
|
61962
62476
|
}
|
|
61963
62477
|
function loadSceneBuildEnv(projectDir) {
|
|
61964
|
-
(0, import_dotenv4.config)({ path:
|
|
61965
|
-
(0, import_dotenv4.config)({ path:
|
|
62478
|
+
(0, import_dotenv4.config)({ path: join28(projectDir, ".env"), quiet: true });
|
|
62479
|
+
(0, import_dotenv4.config)({ path: resolve63(process.cwd(), ".env"), quiet: true });
|
|
61966
62480
|
let dir = process.cwd();
|
|
61967
|
-
while (dir !==
|
|
61968
|
-
if (
|
|
61969
|
-
(0, import_dotenv4.config)({ path:
|
|
62481
|
+
while (dir !== dirname22(dir)) {
|
|
62482
|
+
if (existsSync51(join28(dir, "pnpm-workspace.yaml"))) {
|
|
62483
|
+
(0, import_dotenv4.config)({ path: join28(dir, ".env"), quiet: true });
|
|
61970
62484
|
return;
|
|
61971
62485
|
}
|
|
61972
|
-
dir =
|
|
62486
|
+
dir = dirname22(dir);
|
|
61973
62487
|
}
|
|
61974
62488
|
}
|
|
61975
62489
|
async function skipped(kind, beatId, reason, ctx) {
|
|
@@ -62183,7 +62697,7 @@ function mergeBeatOutcomes(base, updates) {
|
|
|
62183
62697
|
}
|
|
62184
62698
|
function firstExisting3(projectDir, relPaths) {
|
|
62185
62699
|
for (const rel of relPaths) {
|
|
62186
|
-
if (
|
|
62700
|
+
if (existsSync51(join28(projectDir, rel))) return rel;
|
|
62187
62701
|
}
|
|
62188
62702
|
return null;
|
|
62189
62703
|
}
|
|
@@ -62206,6 +62720,9 @@ function resolveBuildMusicProvider(value) {
|
|
|
62206
62720
|
const provider = String(value ?? "elevenlabs").toLowerCase();
|
|
62207
62721
|
return provider === "replicate" ? "replicate" : "elevenlabs";
|
|
62208
62722
|
}
|
|
62723
|
+
function isLikenessRejection(error) {
|
|
62724
|
+
return typeof error === "string" && /likeness(es)? of real people/i.test(error);
|
|
62725
|
+
}
|
|
62209
62726
|
function stringOrUndefined4(value) {
|
|
62210
62727
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
62211
62728
|
}
|
|
@@ -62214,7 +62731,7 @@ async function apiKeyForVideoProvider(provider, projectDir) {
|
|
|
62214
62731
|
return getApiKeyFromConfig(providerKey, { cwd: projectDir });
|
|
62215
62732
|
}
|
|
62216
62733
|
async function finalizeBuildResult(projectDir, startedAt, result, reportResult = result) {
|
|
62217
|
-
const reportPath =
|
|
62734
|
+
const reportPath = join28(projectDir, "build-report.json");
|
|
62218
62735
|
for (const source of /* @__PURE__ */ new Set([result, reportResult])) {
|
|
62219
62736
|
if (source.stageReports) {
|
|
62220
62737
|
for (const report of Object.values(source.stageReports)) {
|
|
@@ -62234,7 +62751,7 @@ async function finalizeBuildResult(projectDir, startedAt, result, reportResult =
|
|
|
62234
62751
|
const withMeta = decorate(result);
|
|
62235
62752
|
const reportMeta = reportResult === result ? withMeta : decorate(reportResult);
|
|
62236
62753
|
try {
|
|
62237
|
-
await
|
|
62754
|
+
await writeFile46(
|
|
62238
62755
|
reportPath,
|
|
62239
62756
|
JSON.stringify(toBuildReport(projectDir, reportMeta), null, 2) + "\n",
|
|
62240
62757
|
"utf-8"
|
|
@@ -62377,7 +62894,7 @@ function normalizeReportDuration(value) {
|
|
|
62377
62894
|
}
|
|
62378
62895
|
function buildReportComposition(projectDir, result, beatId) {
|
|
62379
62896
|
const path2 = `compositions/scene-${beatId}.html`;
|
|
62380
|
-
const exists =
|
|
62897
|
+
const exists = existsSync51(join28(projectDir, path2));
|
|
62381
62898
|
if (result.stageReports?.compose.status === "failed") return { path: path2, exists, status: "failed" };
|
|
62382
62899
|
if (result.phase === "needs-author" && !exists) return { path: path2, exists, status: "needs-author" };
|
|
62383
62900
|
if (exists) return { path: path2, exists, status: "exists" };
|
|
@@ -62424,8 +62941,8 @@ function summarizeBuildBeats(projectDir, beats) {
|
|
|
62424
62941
|
let compositionsReady = 0;
|
|
62425
62942
|
for (const beat of beats) {
|
|
62426
62943
|
if (beatAssetsReady(beat)) assetsReady += 1;
|
|
62427
|
-
const compositionPath =
|
|
62428
|
-
if (
|
|
62944
|
+
const compositionPath = join28(projectDir, "compositions", `scene-${beat.beatId}.html`);
|
|
62945
|
+
if (existsSync51(compositionPath)) {
|
|
62429
62946
|
compositionsReady += 1;
|
|
62430
62947
|
} else {
|
|
62431
62948
|
needsAuthor.push(beat.beatId);
|
|
@@ -62465,6 +62982,7 @@ var init_scene_build = __esm({
|
|
|
62465
62982
|
init_ffmpeg_gate();
|
|
62466
62983
|
init_concurrency();
|
|
62467
62984
|
init_compose_aivideo();
|
|
62985
|
+
init_footage_assemble();
|
|
62468
62986
|
init_scene_project();
|
|
62469
62987
|
init_compose_prompts();
|
|
62470
62988
|
init_config();
|
|
@@ -62560,16 +63078,16 @@ __export(ai_audio_exports, {
|
|
|
62560
63078
|
executeTranscribe: () => executeTranscribe,
|
|
62561
63079
|
executeVoiceClone: () => executeVoiceClone
|
|
62562
63080
|
});
|
|
62563
|
-
import { resolve as
|
|
62564
|
-
import { readFile as readFile46, writeFile as
|
|
62565
|
-
import { existsSync as
|
|
63081
|
+
import { resolve as resolve73, dirname as dirname24, basename as basename22, extname as extname14 } from "node:path";
|
|
63082
|
+
import { readFile as readFile46, writeFile as writeFile47 } from "node:fs/promises";
|
|
63083
|
+
import { existsSync as existsSync56 } from "node:fs";
|
|
62566
63084
|
async function executeTranscribe(options) {
|
|
62567
63085
|
const { audioPath, language, output, format, apiKey } = options;
|
|
62568
63086
|
try {
|
|
62569
63087
|
const key = apiKey || process.env.OPENAI_API_KEY;
|
|
62570
63088
|
if (!key) return { success: false, error: "OPENAI_API_KEY required" };
|
|
62571
|
-
const absPath =
|
|
62572
|
-
if (!
|
|
63089
|
+
const absPath = resolve73(process.cwd(), audioPath);
|
|
63090
|
+
if (!existsSync56(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
62573
63091
|
const whisper = new WhisperProvider();
|
|
62574
63092
|
await whisper.initialize({ apiKey: key });
|
|
62575
63093
|
const audioBuffer = await readFile46(absPath);
|
|
@@ -62580,10 +63098,10 @@ async function executeTranscribe(options) {
|
|
|
62580
63098
|
}
|
|
62581
63099
|
let outputPath;
|
|
62582
63100
|
if (output) {
|
|
62583
|
-
outputPath =
|
|
63101
|
+
outputPath = resolve73(process.cwd(), output);
|
|
62584
63102
|
const fmt = detectFormat(output, format);
|
|
62585
63103
|
const content = formatTranscript(result, fmt);
|
|
62586
|
-
await
|
|
63104
|
+
await writeFile47(outputPath, content, "utf-8");
|
|
62587
63105
|
}
|
|
62588
63106
|
return {
|
|
62589
63107
|
success: true,
|
|
@@ -62601,8 +63119,8 @@ async function executeIsolate(options) {
|
|
|
62601
63119
|
try {
|
|
62602
63120
|
const key = apiKey || process.env.ELEVENLABS_API_KEY;
|
|
62603
63121
|
if (!key) return { success: false, error: "ELEVENLABS_API_KEY required" };
|
|
62604
|
-
const absPath =
|
|
62605
|
-
if (!
|
|
63122
|
+
const absPath = resolve73(process.cwd(), audioPath);
|
|
63123
|
+
if (!existsSync56(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
62606
63124
|
const audioBuffer = await readFile46(absPath);
|
|
62607
63125
|
const elevenlabs = new ElevenLabsProvider();
|
|
62608
63126
|
await elevenlabs.initialize({ apiKey: key });
|
|
@@ -62610,8 +63128,8 @@ async function executeIsolate(options) {
|
|
|
62610
63128
|
if (!result.success || !result.audioBuffer) {
|
|
62611
63129
|
return { success: false, error: result.error || "Audio isolation failed" };
|
|
62612
63130
|
}
|
|
62613
|
-
const outputPath =
|
|
62614
|
-
await
|
|
63131
|
+
const outputPath = resolve73(process.cwd(), output);
|
|
63132
|
+
await writeFile47(outputPath, result.audioBuffer);
|
|
62615
63133
|
return { success: true, outputPath };
|
|
62616
63134
|
} catch (error) {
|
|
62617
63135
|
return { success: false, error: `Audio isolation failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -62627,8 +63145,8 @@ async function executeVoiceClone(options) {
|
|
|
62627
63145
|
}
|
|
62628
63146
|
const audioBuffers = [];
|
|
62629
63147
|
for (const samplePath of samplePaths) {
|
|
62630
|
-
const absPath =
|
|
62631
|
-
if (!
|
|
63148
|
+
const absPath = resolve73(process.cwd(), samplePath);
|
|
63149
|
+
if (!existsSync56(absPath)) return { success: false, error: `File not found: ${samplePath}` };
|
|
62632
63150
|
const buffer = await readFile46(absPath);
|
|
62633
63151
|
audioBuffers.push(buffer);
|
|
62634
63152
|
}
|
|
@@ -62649,8 +63167,8 @@ async function executeVoiceClone(options) {
|
|
|
62649
63167
|
async function executeDub(options) {
|
|
62650
63168
|
const { mediaPath, language, source, voice, analyzeOnly, output } = options;
|
|
62651
63169
|
try {
|
|
62652
|
-
const absPath =
|
|
62653
|
-
if (!
|
|
63170
|
+
const absPath = resolve73(process.cwd(), mediaPath);
|
|
63171
|
+
if (!existsSync56(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
62654
63172
|
const openaiKey = process.env.OPENAI_API_KEY;
|
|
62655
63173
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
62656
63174
|
const elevenlabsKey = process.env.ELEVENLABS_API_KEY;
|
|
@@ -62661,7 +63179,7 @@ async function executeDub(options) {
|
|
|
62661
63179
|
const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
|
|
62662
63180
|
let audioPath = absPath;
|
|
62663
63181
|
if (isVideo) {
|
|
62664
|
-
const tempAudioPath =
|
|
63182
|
+
const tempAudioPath = resolve73(dirname24(absPath), `temp-audio-${Date.now()}.mp3`);
|
|
62665
63183
|
execSafeSync("ffmpeg", ["-i", absPath, "-vn", "-acodec", "mp3", "-y", tempAudioPath]);
|
|
62666
63184
|
audioPath = tempAudioPath;
|
|
62667
63185
|
}
|
|
@@ -62710,7 +63228,7 @@ ${segmentTexts}`,
|
|
|
62710
63228
|
}
|
|
62711
63229
|
if (analyzeOnly) {
|
|
62712
63230
|
if (output) {
|
|
62713
|
-
const timingPath =
|
|
63231
|
+
const timingPath = resolve73(process.cwd(), output);
|
|
62714
63232
|
const timingData = {
|
|
62715
63233
|
sourcePath: absPath,
|
|
62716
63234
|
sourceLanguage: transcriptResult.detectedLanguage || source || "auto",
|
|
@@ -62722,14 +63240,14 @@ ${segmentTexts}`,
|
|
|
62722
63240
|
translated: translatedSegments[i]?.text || s.text
|
|
62723
63241
|
}))
|
|
62724
63242
|
};
|
|
62725
|
-
await
|
|
63243
|
+
await writeFile47(timingPath, JSON.stringify(timingData, null, 2));
|
|
62726
63244
|
}
|
|
62727
63245
|
return {
|
|
62728
63246
|
success: true,
|
|
62729
63247
|
sourceLanguage: transcriptResult.detectedLanguage || source || "auto",
|
|
62730
63248
|
targetLanguage: language,
|
|
62731
63249
|
segmentCount: segments.length,
|
|
62732
|
-
outputPath: output ?
|
|
63250
|
+
outputPath: output ? resolve73(process.cwd(), output) : void 0
|
|
62733
63251
|
};
|
|
62734
63252
|
}
|
|
62735
63253
|
const elevenlabs = new ElevenLabsProvider();
|
|
@@ -62743,9 +63261,9 @@ ${segmentTexts}`,
|
|
|
62743
63261
|
}
|
|
62744
63262
|
const combinedBuffer = Buffer.concat(dubbedBuffers);
|
|
62745
63263
|
const outputExt = isVideo ? ".mp3" : extname14(absPath);
|
|
62746
|
-
const defaultOutputPath2 =
|
|
62747
|
-
const finalOutputPath =
|
|
62748
|
-
await
|
|
63264
|
+
const defaultOutputPath2 = resolve73(dirname24(absPath), `${basename22(absPath, extname14(absPath))}-${language}${outputExt}`);
|
|
63265
|
+
const finalOutputPath = resolve73(process.cwd(), output || defaultOutputPath2);
|
|
63266
|
+
await writeFile47(finalOutputPath, combinedBuffer);
|
|
62749
63267
|
if (isVideo && audioPath !== absPath) {
|
|
62750
63268
|
try {
|
|
62751
63269
|
const { unlink: unlink3 } = await import("node:fs/promises");
|
|
@@ -62776,12 +63294,12 @@ async function executeDuck(options) {
|
|
|
62776
63294
|
} = options;
|
|
62777
63295
|
try {
|
|
62778
63296
|
if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
|
|
62779
|
-
const absMusicPath =
|
|
62780
|
-
const absVoicePath =
|
|
62781
|
-
if (!
|
|
62782
|
-
if (!
|
|
62783
|
-
const defaultOutput =
|
|
62784
|
-
const outputPath =
|
|
63297
|
+
const absMusicPath = resolve73(process.cwd(), musicPath);
|
|
63298
|
+
const absVoicePath = resolve73(process.cwd(), voicePath);
|
|
63299
|
+
if (!existsSync56(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
|
|
63300
|
+
if (!existsSync56(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
|
|
63301
|
+
const defaultOutput = resolve73(dirname24(absMusicPath), `${basename22(absMusicPath, extname14(absMusicPath))}-ducked${extname14(absMusicPath)}`);
|
|
63302
|
+
const outputPath = resolve73(process.cwd(), output || defaultOutput);
|
|
62785
63303
|
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`;
|
|
62786
63304
|
await execSafe("ffmpeg", [
|
|
62787
63305
|
"-i",
|
|
@@ -62793,7 +63311,7 @@ async function executeDuck(options) {
|
|
|
62793
63311
|
"-y",
|
|
62794
63312
|
outputPath
|
|
62795
63313
|
], { timeout: 12e4, maxBuffer: 50 * 1024 * 1024 });
|
|
62796
|
-
if (!
|
|
63314
|
+
if (!existsSync56(outputPath)) return { success: false, error: "FFmpeg failed to create output" };
|
|
62797
63315
|
return { success: true, outputPath };
|
|
62798
63316
|
} catch (error) {
|
|
62799
63317
|
return { success: false, error: `Audio ducking failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -62809,9 +63327,9 @@ var init_ai_audio = __esm({
|
|
|
62809
63327
|
});
|
|
62810
63328
|
|
|
62811
63329
|
// src/pipeline/executor.ts
|
|
62812
|
-
import { resolve as
|
|
62813
|
-
import { readFile as readFile47, writeFile as
|
|
62814
|
-
import { existsSync as
|
|
63330
|
+
import { resolve as resolve74 } from "node:path";
|
|
63331
|
+
import { readFile as readFile47, writeFile as writeFile48, mkdir as mkdir28 } from "node:fs/promises";
|
|
63332
|
+
import { existsSync as existsSync57 } from "node:fs";
|
|
62815
63333
|
function maxCostFor(action) {
|
|
62816
63334
|
const cmd = ACTION_METADATA[action]?.command;
|
|
62817
63335
|
if (!cmd) return 0;
|
|
@@ -62822,9 +63340,9 @@ function registerAction(action, handler) {
|
|
|
62822
63340
|
}
|
|
62823
63341
|
function getOutput(params, outputDir, defaultName) {
|
|
62824
63342
|
if (params.output && typeof params.output === "string") {
|
|
62825
|
-
return
|
|
63343
|
+
return resolve74(outputDir, params.output);
|
|
62826
63344
|
}
|
|
62827
|
-
return
|
|
63345
|
+
return resolve74(outputDir, defaultName);
|
|
62828
63346
|
}
|
|
62829
63347
|
function stringParam(value) {
|
|
62830
63348
|
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
@@ -63054,7 +63572,7 @@ async function ensureActionsRegistered() {
|
|
|
63054
63572
|
const { executeSceneBuild: executeSceneBuild2 } = await Promise.resolve().then(() => (init_scene_build(), scene_build_exports));
|
|
63055
63573
|
const projectRel = params.project ?? ".";
|
|
63056
63574
|
const r = await executeSceneBuild2({
|
|
63057
|
-
projectDir:
|
|
63575
|
+
projectDir: resolve74(outputDir, projectRel),
|
|
63058
63576
|
mode: params.mode,
|
|
63059
63577
|
composer: params.composer,
|
|
63060
63578
|
skipNarration: params.skipNarration,
|
|
@@ -63064,6 +63582,7 @@ async function ensureActionsRegistered() {
|
|
|
63064
63582
|
voice: params.voice,
|
|
63065
63583
|
imageProvider: params.imageProvider,
|
|
63066
63584
|
imageQuality: params.quality,
|
|
63585
|
+
imageModel: params.imageModel,
|
|
63067
63586
|
force: params.force
|
|
63068
63587
|
});
|
|
63069
63588
|
return {
|
|
@@ -63079,7 +63598,7 @@ async function ensureActionsRegistered() {
|
|
|
63079
63598
|
const { executeSceneRender: executeSceneRender2 } = await Promise.resolve().then(() => (init_scene_render(), scene_render_exports));
|
|
63080
63599
|
const projectRel = params.project ?? ".";
|
|
63081
63600
|
const r = await executeSceneRender2({
|
|
63082
|
-
projectDir:
|
|
63601
|
+
projectDir: resolve74(outputDir, projectRel),
|
|
63083
63602
|
root: params.root,
|
|
63084
63603
|
output: params.output,
|
|
63085
63604
|
fps: params.fps,
|
|
@@ -63103,8 +63622,8 @@ async function ensureActionsRegistered() {
|
|
|
63103
63622
|
});
|
|
63104
63623
|
}
|
|
63105
63624
|
async function loadPipeline(filePath) {
|
|
63106
|
-
const absPath =
|
|
63107
|
-
if (!
|
|
63625
|
+
const absPath = resolve74(process.cwd(), filePath);
|
|
63626
|
+
if (!existsSync57(absPath)) {
|
|
63108
63627
|
throw new Error(`Pipeline file not found: ${absPath}`);
|
|
63109
63628
|
}
|
|
63110
63629
|
const content = await readFile47(absPath, "utf-8");
|
|
@@ -63122,14 +63641,14 @@ async function loadPipeline(filePath) {
|
|
|
63122
63641
|
}
|
|
63123
63642
|
async function executePipeline(manifest2, options = {}) {
|
|
63124
63643
|
await ensureActionsRegistered();
|
|
63125
|
-
const outputDir =
|
|
63126
|
-
await
|
|
63644
|
+
const outputDir = resolve74(process.cwd(), options.outputDir || `${manifest2.name}-output`);
|
|
63645
|
+
await mkdir28(outputDir, { recursive: true });
|
|
63127
63646
|
const completedSteps = /* @__PURE__ */ new Map();
|
|
63128
63647
|
const results = [];
|
|
63129
63648
|
const startTime = Date.now();
|
|
63130
63649
|
if (options.resume) {
|
|
63131
|
-
const checkpointPath =
|
|
63132
|
-
if (
|
|
63650
|
+
const checkpointPath = resolve74(outputDir, CHECKPOINT_FILE);
|
|
63651
|
+
if (existsSync57(checkpointPath)) {
|
|
63133
63652
|
const checkpointContent = await readFile47(checkpointPath, "utf-8");
|
|
63134
63653
|
const checkpoint = (0, import_yaml8.parse)(checkpointContent);
|
|
63135
63654
|
for (const cs of checkpoint.completedSteps) {
|
|
@@ -63248,8 +63767,8 @@ async function executePipeline(manifest2, options = {}) {
|
|
|
63248
63767
|
data: s.data
|
|
63249
63768
|
}))
|
|
63250
63769
|
};
|
|
63251
|
-
await
|
|
63252
|
-
|
|
63770
|
+
await writeFile48(
|
|
63771
|
+
resolve74(outputDir, CHECKPOINT_FILE),
|
|
63253
63772
|
(0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
|
|
63254
63773
|
"utf-8"
|
|
63255
63774
|
);
|
|
@@ -67717,7 +68236,7 @@ var init_elicit = __esm({
|
|
|
67717
68236
|
});
|
|
67718
68237
|
|
|
67719
68238
|
// src/tools/manifest/scene.ts
|
|
67720
|
-
import { resolve as
|
|
68239
|
+
import { resolve as resolve75, relative as relative11 } from "node:path";
|
|
67721
68240
|
function summariseLint(result) {
|
|
67722
68241
|
return {
|
|
67723
68242
|
ok: result.ok,
|
|
@@ -67952,7 +68471,7 @@ var init_scene2 = __esm({
|
|
|
67952
68471
|
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.",
|
|
67953
68472
|
schema: sceneInitSchema,
|
|
67954
68473
|
async execute(args, ctx) {
|
|
67955
|
-
const dir =
|
|
68474
|
+
const dir = resolve75(ctx.workingDirectory, args.dir);
|
|
67956
68475
|
const result = await scaffoldSceneProject({
|
|
67957
68476
|
dir,
|
|
67958
68477
|
name: args.name,
|
|
@@ -68007,7 +68526,7 @@ var init_scene2 = __esm({
|
|
|
68007
68526
|
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. By default, syncs STORYBOARD.md and rebuilds root refs from it; set syncStoryboard:false for root-only insertion. Use skipAudio:true and skipImage:true for text-only scenes that need no API calls.",
|
|
68008
68527
|
schema: sceneAddSchema,
|
|
68009
68528
|
async execute(args, ctx) {
|
|
68010
|
-
const projectDir = args.projectDir ?
|
|
68529
|
+
const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
68011
68530
|
const result = await executeSceneAdd({
|
|
68012
68531
|
name: args.name,
|
|
68013
68532
|
preset: args.preset ?? "simple",
|
|
@@ -68073,7 +68592,7 @@ var init_scene2 = __esm({
|
|
|
68073
68592
|
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.",
|
|
68074
68593
|
schema: sceneLintSchema,
|
|
68075
68594
|
async execute(args, ctx) {
|
|
68076
|
-
const projectDir = args.projectDir ?
|
|
68595
|
+
const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
68077
68596
|
const result = await runProjectLint({
|
|
68078
68597
|
projectDir,
|
|
68079
68598
|
rootRel: args.root,
|
|
@@ -68112,7 +68631,7 @@ var init_scene2 = __esm({
|
|
|
68112
68631
|
description: "Apply deterministic mechanical scene repairs. Currently uses the safe lint auto-fix allow-list and never performs semantic creative rewrites.",
|
|
68113
68632
|
schema: sceneRepairSchema,
|
|
68114
68633
|
async execute(args, ctx) {
|
|
68115
|
-
const projectDir = args.projectDir ?
|
|
68634
|
+
const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
68116
68635
|
const result = await executeSceneRepair({
|
|
68117
68636
|
projectDir,
|
|
68118
68637
|
rootRel: args.root,
|
|
@@ -68150,7 +68669,7 @@ var init_scene2 = __esm({
|
|
|
68150
68669
|
description: "Render a scene project to MP4/WebM/MOV via the Hyperframes producer. Requires Chrome installed locally. Output defaults to renders/<projectName>-<isoStamp>.<format>. Long runs: over MCP, calls exceeding ~45s return immediately with { promoted: true, jobId, status: 'running' } \u2014 poll status_job every 15-30s until completed/failed instead of re-invoking render. Emits MCP progress notifications when the client supplies a progressToken.",
|
|
68151
68670
|
schema: sceneRenderSchema,
|
|
68152
68671
|
async execute(args, ctx) {
|
|
68153
|
-
const projectDir = args.projectDir ?
|
|
68672
|
+
const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
68154
68673
|
const runRender = (report) => executeSceneRender({
|
|
68155
68674
|
projectDir,
|
|
68156
68675
|
root: args.root,
|
|
@@ -68203,6 +68722,9 @@ var init_scene2 = __esm({
|
|
|
68203
68722
|
videoProvider: external_exports.enum(["seedance", "grok", "kling", "runway", "veo"]).optional().describe("Video provider for per-beat video cues. Default seedance."),
|
|
68204
68723
|
musicProvider: external_exports.enum(["elevenlabs", "replicate"]).optional().describe("Music provider for per-beat music cues. Default elevenlabs."),
|
|
68205
68724
|
imageQuality: external_exports.enum(["standard", "hd"]).optional().describe("OpenAI image quality. Default 'standard'."),
|
|
68725
|
+
imageModel: external_exports.string().optional().describe(
|
|
68726
|
+
"Image model for keyframes/backdrops/character sheets (gemini: flash|pro, openai: gpt-image-2). Provider default when omitted."
|
|
68727
|
+
),
|
|
68206
68728
|
imageSize: external_exports.enum(["1024x1024", "1536x1024", "1024x1536"]).optional().describe("OpenAI image size. Default '1536x1024' (cinematic 16:9-ish)."),
|
|
68207
68729
|
maxCostUsd: external_exports.number().optional().describe("Fail before provider spend when estimated cost exceeds this USD cap."),
|
|
68208
68730
|
force: external_exports.boolean().optional().describe("Re-dispatch primitives even when cached assets exist.")
|
|
@@ -68239,7 +68761,7 @@ var init_scene2 = __esm({
|
|
|
68239
68761
|
}
|
|
68240
68762
|
}
|
|
68241
68763
|
}
|
|
68242
|
-
const projectDir = args.projectDir ?
|
|
68764
|
+
const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
68243
68765
|
const runBuild = (report) => executeSceneBuild({
|
|
68244
68766
|
projectDir,
|
|
68245
68767
|
stage: args.stage,
|
|
@@ -68257,6 +68779,7 @@ var init_scene2 = __esm({
|
|
|
68257
68779
|
videoProvider: args.videoProvider,
|
|
68258
68780
|
musicProvider: args.musicProvider,
|
|
68259
68781
|
imageQuality: args.imageQuality,
|
|
68782
|
+
imageModel: args.imageModel,
|
|
68260
68783
|
imageSize: args.imageSize,
|
|
68261
68784
|
maxCostUsd: args.maxCostUsd,
|
|
68262
68785
|
force: args.force,
|
|
@@ -68295,7 +68818,7 @@ var init_scene2 = __esm({
|
|
|
68295
68818
|
description: "Install the Hyperframes composition rules into a scene project by running upstream's installer (`npx skills add heygen-com/hyperframes`). Lands at .agents/skills/hyperframes/ and is picked up by ~19 agents, with symlinks for the ones that want their own directory. Skips when the rules are already available in the project or globally unless force is set. Needs network access. Build and render do not read these files - they exist so you can read the rules while authoring scene HTML.",
|
|
68296
68819
|
schema: sceneInstallSkillSchema,
|
|
68297
68820
|
async execute(args, ctx) {
|
|
68298
|
-
const projectDir =
|
|
68821
|
+
const projectDir = resolve75(ctx.workingDirectory, args.projectDir);
|
|
68299
68822
|
const result = await installHyperframesSkill({
|
|
68300
68823
|
projectDir,
|
|
68301
68824
|
global: args.global ?? false,
|
|
@@ -68340,7 +68863,7 @@ var init_scene2 = __esm({
|
|
|
68340
68863
|
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 the path to the Hyperframes rules (skillReference) and DESIGN.md (visual identity). The host agent writes each compositions/scene-<id>.html file directly \u2014 VibeFrame makes NO LLM call here, and there is no internal-LLM fallback: authoring is always the host agent's job. Hosts that cannot write files (e.g. Claude Desktop) submit each authored beat with scene_submit instead. Pairs with scene_install_skill, which fetches the rules from upstream when the agent does not already have them.",
|
|
68341
68864
|
schema: sceneComposePromptsSchema,
|
|
68342
68865
|
async execute(args, ctx) {
|
|
68343
|
-
const projectDir =
|
|
68866
|
+
const projectDir = resolve75(ctx.workingDirectory, args.projectDir);
|
|
68344
68867
|
const result = await getComposePrompts({
|
|
68345
68868
|
projectDir,
|
|
68346
68869
|
beatId: args.beat
|
|
@@ -68384,7 +68907,7 @@ var init_scene2 = __esm({
|
|
|
68384
68907
|
description: "Submit host-authored Hyperframes scene HTML for one beat. Validates with the same lint as the batch composer and writes compositions/scene-<id>.html on pass; on lint errors it returns the findings WITHOUT writing so you can fix and resubmit. This completes agent-mode compose for hosts that cannot write files (e.g. Claude Desktop): build (mode agent) \u2192 needs-author plan \u2192 author each beat from its composePrompts userPrompt \u2192 scene_submit per beat \u2192 build (stage sync) \u2192 render. No internal LLM call \u2014 the submitting agent is the composer.",
|
|
68385
68908
|
schema: sceneSubmitSchema,
|
|
68386
68909
|
async execute(args, ctx) {
|
|
68387
|
-
const projectDir = args.projectDir ?
|
|
68910
|
+
const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
68388
68911
|
const result = await executeSceneSubmit({
|
|
68389
68912
|
projectDir,
|
|
68390
68913
|
beatId: args.beat,
|
|
@@ -69047,13 +69570,13 @@ var init_edit = __esm({
|
|
|
69047
69570
|
});
|
|
69048
69571
|
|
|
69049
69572
|
// src/commands/ai-suggest-edit.ts
|
|
69050
|
-
import { readFile as readFile48, writeFile as
|
|
69051
|
-
import { resolve as
|
|
69573
|
+
import { readFile as readFile48, writeFile as writeFile49 } from "node:fs/promises";
|
|
69574
|
+
import { resolve as resolve76 } from "node:path";
|
|
69052
69575
|
async function executeSuggestEdit(options) {
|
|
69053
69576
|
try {
|
|
69054
69577
|
const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY;
|
|
69055
69578
|
if (!apiKey) return { success: false, error: "GOOGLE_API_KEY required for suggest" };
|
|
69056
|
-
const filePath =
|
|
69579
|
+
const filePath = resolve76(process.cwd(), options.projectPath);
|
|
69057
69580
|
const content = await readFile48(filePath, "utf-8");
|
|
69058
69581
|
const data = JSON.parse(content);
|
|
69059
69582
|
const project = Project.fromJSON(data);
|
|
@@ -69065,7 +69588,7 @@ async function executeSuggestEdit(options) {
|
|
|
69065
69588
|
const first = suggestions[0];
|
|
69066
69589
|
const applied = applySuggestion(project, first);
|
|
69067
69590
|
if (applied) {
|
|
69068
|
-
await
|
|
69591
|
+
await writeFile49(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
69069
69592
|
return {
|
|
69070
69593
|
success: true,
|
|
69071
69594
|
suggestions,
|
|
@@ -69094,7 +69617,7 @@ var init_ai_suggest_edit = __esm({
|
|
|
69094
69617
|
});
|
|
69095
69618
|
|
|
69096
69619
|
// src/tools/manifest/inspect.ts
|
|
69097
|
-
import { resolve as
|
|
69620
|
+
import { resolve as resolve77 } from "node:path";
|
|
69098
69621
|
var PROJECT_DIR_DESCRIPTION2, inspectProjectTool, inspectRenderTool, analyzeMediaTool, analyzeSuggestTool, inspectTools;
|
|
69099
69622
|
var init_inspect = __esm({
|
|
69100
69623
|
"src/tools/manifest/inspect.ts"() {
|
|
@@ -69120,11 +69643,11 @@ var init_inspect = __esm({
|
|
|
69120
69643
|
report: external_exports.boolean().optional().describe("Write review-report.json. Default true.")
|
|
69121
69644
|
}),
|
|
69122
69645
|
async execute(args, ctx) {
|
|
69123
|
-
const projectDir = args.projectDir ?
|
|
69646
|
+
const projectDir = args.projectDir ? resolve77(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69124
69647
|
const result = await inspectProject({
|
|
69125
69648
|
projectDir,
|
|
69126
69649
|
beatId: args.beat,
|
|
69127
|
-
outputPath: args.outputPath ?
|
|
69650
|
+
outputPath: args.outputPath ? resolve77(ctx.workingDirectory, args.outputPath) : void 0,
|
|
69128
69651
|
writeReport: args.report !== false
|
|
69129
69652
|
});
|
|
69130
69653
|
return {
|
|
@@ -69160,13 +69683,13 @@ var init_inspect = __esm({
|
|
|
69160
69683
|
dryRun: external_exports.boolean().optional().describe("Preview resolved inputs without probing video or calling Gemini.")
|
|
69161
69684
|
}),
|
|
69162
69685
|
async execute(args, ctx) {
|
|
69163
|
-
const projectDir = args.projectDir ?
|
|
69686
|
+
const projectDir = args.projectDir ? resolve77(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69164
69687
|
if (args.dryRun) {
|
|
69165
69688
|
const result2 = await previewInspectRender({
|
|
69166
69689
|
projectDir,
|
|
69167
69690
|
beatId: args.beat,
|
|
69168
|
-
videoPath: args.videoPath ?
|
|
69169
|
-
outputPath: args.outputPath ?
|
|
69691
|
+
videoPath: args.videoPath ? resolve77(ctx.workingDirectory, args.videoPath) : void 0,
|
|
69692
|
+
outputPath: args.outputPath ? resolve77(ctx.workingDirectory, args.outputPath) : void 0,
|
|
69170
69693
|
writeReport: args.report !== false,
|
|
69171
69694
|
ai: args.ai === true,
|
|
69172
69695
|
model: args.model
|
|
@@ -69187,8 +69710,8 @@ var init_inspect = __esm({
|
|
|
69187
69710
|
const result = await inspectRender({
|
|
69188
69711
|
projectDir,
|
|
69189
69712
|
beatId: args.beat,
|
|
69190
|
-
videoPath: args.videoPath ?
|
|
69191
|
-
outputPath: args.outputPath ?
|
|
69713
|
+
videoPath: args.videoPath ? resolve77(ctx.workingDirectory, args.videoPath) : void 0,
|
|
69714
|
+
outputPath: args.outputPath ? resolve77(ctx.workingDirectory, args.outputPath) : void 0,
|
|
69192
69715
|
writeReport: args.report !== false,
|
|
69193
69716
|
ai: args.ai === true,
|
|
69194
69717
|
model: args.model
|
|
@@ -69621,12 +70144,12 @@ var init_generate2 = __esm({
|
|
|
69621
70144
|
});
|
|
69622
70145
|
|
|
69623
70146
|
// src/tools/manifest/storyboard.ts
|
|
69624
|
-
import { existsSync as
|
|
69625
|
-
import { readFile as readFile49, writeFile as
|
|
69626
|
-
import { resolve as
|
|
70147
|
+
import { existsSync as existsSync58 } from "node:fs";
|
|
70148
|
+
import { readFile as readFile49, writeFile as writeFile50 } from "node:fs/promises";
|
|
70149
|
+
import { resolve as resolve78 } from "node:path";
|
|
69627
70150
|
async function readStoryboard2(projectDir) {
|
|
69628
|
-
const path2 =
|
|
69629
|
-
if (!
|
|
70151
|
+
const path2 = resolve78(projectDir, "STORYBOARD.md");
|
|
70152
|
+
if (!existsSync58(path2)) return null;
|
|
69630
70153
|
return { path: path2, markdown: await readFile49(path2, "utf-8") };
|
|
69631
70154
|
}
|
|
69632
70155
|
var PROJECT_DIR_DESCRIPTION3, projectDirSchema, storyboardListTool, storyboardValidateTool, storyboardGetTool, storyboardSetTool, storyboardMoveTool, storyboardReviseTool, planTool, storyboardTools;
|
|
@@ -69652,7 +70175,7 @@ var init_storyboard2 = __esm({
|
|
|
69652
70175
|
description: "List beats, ids, durations, and cue blocks from a project's STORYBOARD.md.",
|
|
69653
70176
|
schema: projectDirSchema,
|
|
69654
70177
|
async execute(args, ctx) {
|
|
69655
|
-
const projectDir = args.projectDir ?
|
|
70178
|
+
const projectDir = args.projectDir ? resolve78(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69656
70179
|
const file = await readStoryboard2(projectDir);
|
|
69657
70180
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
69658
70181
|
const parsed = parseStoryboard(file.markdown);
|
|
@@ -69680,7 +70203,7 @@ var init_storyboard2 = __esm({
|
|
|
69680
70203
|
description: "Validate STORYBOARD.md beat ids and cue blocks.",
|
|
69681
70204
|
schema: projectDirSchema,
|
|
69682
70205
|
async execute(args, ctx) {
|
|
69683
|
-
const projectDir = args.projectDir ?
|
|
70206
|
+
const projectDir = args.projectDir ? resolve78(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69684
70207
|
const file = await readStoryboard2(projectDir);
|
|
69685
70208
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
69686
70209
|
const result = validateStoryboardMarkdown(file.markdown);
|
|
@@ -69715,7 +70238,7 @@ var init_storyboard2 = __esm({
|
|
|
69715
70238
|
beat: external_exports.string().describe("Beat id to return.")
|
|
69716
70239
|
}),
|
|
69717
70240
|
async execute(args, ctx) {
|
|
69718
|
-
const projectDir = args.projectDir ?
|
|
70241
|
+
const projectDir = args.projectDir ? resolve78(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69719
70242
|
const file = await readStoryboard2(projectDir);
|
|
69720
70243
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
69721
70244
|
const beat = getStoryboardBeat(file.markdown, args.beat);
|
|
@@ -69743,7 +70266,7 @@ var init_storyboard2 = __esm({
|
|
|
69743
70266
|
unset: external_exports.boolean().optional().describe("Remove the cue key.")
|
|
69744
70267
|
}),
|
|
69745
70268
|
async execute(args, ctx) {
|
|
69746
|
-
const projectDir = args.projectDir ?
|
|
70269
|
+
const projectDir = args.projectDir ? resolve78(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69747
70270
|
const file = await readStoryboard2(projectDir);
|
|
69748
70271
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
69749
70272
|
try {
|
|
@@ -69754,7 +70277,7 @@ var init_storyboard2 = __esm({
|
|
|
69754
70277
|
value,
|
|
69755
70278
|
unset: args.unset
|
|
69756
70279
|
});
|
|
69757
|
-
await
|
|
70280
|
+
await writeFile50(file.path, next, "utf-8");
|
|
69758
70281
|
return {
|
|
69759
70282
|
success: true,
|
|
69760
70283
|
data: { beat: args.beat, key: args.key },
|
|
@@ -69778,7 +70301,7 @@ var init_storyboard2 = __esm({
|
|
|
69778
70301
|
after: external_exports.string().describe("Beat id that should precede the moved beat.")
|
|
69779
70302
|
}),
|
|
69780
70303
|
async execute(args, ctx) {
|
|
69781
|
-
const projectDir = args.projectDir ?
|
|
70304
|
+
const projectDir = args.projectDir ? resolve78(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69782
70305
|
const file = await readStoryboard2(projectDir);
|
|
69783
70306
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
69784
70307
|
try {
|
|
@@ -69786,7 +70309,7 @@ var init_storyboard2 = __esm({
|
|
|
69786
70309
|
beatId: args.beat,
|
|
69787
70310
|
afterBeatId: args.after
|
|
69788
70311
|
});
|
|
69789
|
-
await
|
|
70312
|
+
await writeFile50(file.path, next, "utf-8");
|
|
69790
70313
|
return {
|
|
69791
70314
|
success: true,
|
|
69792
70315
|
data: { beat: args.beat, after: args.after },
|
|
@@ -69812,7 +70335,7 @@ var init_storyboard2 = __esm({
|
|
|
69812
70335
|
dryRun: external_exports.boolean().optional().describe("Preview the revised storyboard without writing.")
|
|
69813
70336
|
}),
|
|
69814
70337
|
async execute(args, ctx) {
|
|
69815
|
-
const projectDir = args.projectDir ?
|
|
70338
|
+
const projectDir = args.projectDir ? resolve78(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69816
70339
|
const result = await executeStoryboardRevision({
|
|
69817
70340
|
projectDir,
|
|
69818
70341
|
request: args.request,
|
|
@@ -69857,7 +70380,7 @@ var init_storyboard2 = __esm({
|
|
|
69857
70380
|
force: external_exports.boolean().optional().describe("Plan regeneration even when outputs exist.")
|
|
69858
70381
|
}),
|
|
69859
70382
|
async execute(args, ctx) {
|
|
69860
|
-
const projectDir = args.projectDir ?
|
|
70383
|
+
const projectDir = args.projectDir ? resolve78(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
69861
70384
|
const plan = await createBuildPlan({
|
|
69862
70385
|
projectDir,
|
|
69863
70386
|
stage: args.stage,
|
|
@@ -69900,9 +70423,9 @@ var init_storyboard2 = __esm({
|
|
|
69900
70423
|
});
|
|
69901
70424
|
|
|
69902
70425
|
// src/tools/manifest/design.ts
|
|
69903
|
-
import { existsSync as
|
|
70426
|
+
import { existsSync as existsSync59 } from "node:fs";
|
|
69904
70427
|
import { readFile as readFile50 } from "node:fs/promises";
|
|
69905
|
-
import { resolve as
|
|
70428
|
+
import { resolve as resolve79, join as join30 } from "node:path";
|
|
69906
70429
|
var PROJECT_DIR_DESCRIPTION4, projectDirSchema2, designValidateTool, designTools;
|
|
69907
70430
|
var init_design = __esm({
|
|
69908
70431
|
"src/tools/manifest/design.ts"() {
|
|
@@ -69923,9 +70446,9 @@ var init_design = __esm({
|
|
|
69923
70446
|
description: "Validate DESIGN.md front-matter color/typography tokens and sections (google-labs design.md format).",
|
|
69924
70447
|
schema: projectDirSchema2,
|
|
69925
70448
|
async execute(args, ctx) {
|
|
69926
|
-
const projectDir = args.projectDir ?
|
|
69927
|
-
const path2 =
|
|
69928
|
-
if (!
|
|
70449
|
+
const projectDir = args.projectDir ? resolve79(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
70450
|
+
const path2 = join30(projectDir, "DESIGN.md");
|
|
70451
|
+
if (!existsSync59(path2)) return { success: false, error: `DESIGN.md not found in ${projectDir}` };
|
|
69929
70452
|
const md = await readFile50(path2, "utf-8");
|
|
69930
70453
|
const issues = validateDesignMarkdown(md);
|
|
69931
70454
|
const design = parseDesign(md);
|
|
@@ -69949,9 +70472,9 @@ var init_design = __esm({
|
|
|
69949
70472
|
});
|
|
69950
70473
|
|
|
69951
70474
|
// src/tools/manifest/remix.ts
|
|
69952
|
-
import { writeFile as
|
|
70475
|
+
import { writeFile as writeFile51 } from "node:fs/promises";
|
|
69953
70476
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
69954
|
-
import { join as
|
|
70477
|
+
import { join as join31 } from "node:path";
|
|
69955
70478
|
var pipelineHighlightsTool, pipelineAutoShortsTool, pipelineRunTool, remixTools;
|
|
69956
70479
|
var init_remix = __esm({
|
|
69957
70480
|
"src/tools/manifest/remix.ts"() {
|
|
@@ -70064,8 +70587,8 @@ var init_remix = __esm({
|
|
|
70064
70587
|
let resolvedPath = args.pipelinePath;
|
|
70065
70588
|
let tempPath;
|
|
70066
70589
|
if (args.pipelineYaml) {
|
|
70067
|
-
tempPath =
|
|
70068
|
-
await
|
|
70590
|
+
tempPath = join31(tmpdir4(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
|
|
70591
|
+
await writeFile51(tempPath, args.pipelineYaml, "utf-8");
|
|
70069
70592
|
resolvedPath = tempPath;
|
|
70070
70593
|
}
|
|
70071
70594
|
try {
|
|
@@ -70210,7 +70733,7 @@ var init_detect2 = __esm({
|
|
|
70210
70733
|
});
|
|
70211
70734
|
|
|
70212
70735
|
// src/tools/manifest/_project-io.ts
|
|
70213
|
-
import { readFile as readFile51, writeFile as
|
|
70736
|
+
import { readFile as readFile51, writeFile as writeFile52 } from "node:fs/promises";
|
|
70214
70737
|
async function loadProject2(projectPath, cwd) {
|
|
70215
70738
|
const absPath = await resolveTimelineFile(projectPath, cwd);
|
|
70216
70739
|
const content = await readFile51(absPath, "utf-8");
|
|
@@ -70218,7 +70741,7 @@ async function loadProject2(projectPath, cwd) {
|
|
|
70218
70741
|
return { project: Project.fromJSON(data), absPath };
|
|
70219
70742
|
}
|
|
70220
70743
|
async function saveProject(absPath, project) {
|
|
70221
|
-
await
|
|
70744
|
+
await writeFile52(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
70222
70745
|
}
|
|
70223
70746
|
var init_project_io = __esm({
|
|
70224
70747
|
"src/tools/manifest/_project-io.ts"() {
|
|
@@ -70229,8 +70752,8 @@ var init_project_io = __esm({
|
|
|
70229
70752
|
});
|
|
70230
70753
|
|
|
70231
70754
|
// src/tools/manifest/timeline.ts
|
|
70232
|
-
import { mkdir as
|
|
70233
|
-
import { basename as basename23, resolve as
|
|
70755
|
+
import { mkdir as mkdir29, writeFile as writeFile53 } from "node:fs/promises";
|
|
70756
|
+
import { basename as basename23, resolve as resolve80 } from "node:path";
|
|
70234
70757
|
var MEDIA_TYPES, timelineCreateTool, timelineInfoTool, timelineAddSourceTool, timelineAddClipTool, timelineSplitClipTool, timelineTrimClipTool, timelineMoveClipTool, timelineDeleteClipTool, timelineDuplicateClipTool, timelineAddEffectTool, timelineAddTrackTool, timelineListTool, timelineTools;
|
|
70235
70758
|
var init_timeline = __esm({
|
|
70236
70759
|
"src/tools/manifest/timeline.ts"() {
|
|
@@ -70268,18 +70791,18 @@ var init_timeline = __esm({
|
|
|
70268
70791
|
fps: external_exports.number().optional().describe("Frames per second (default: 30)")
|
|
70269
70792
|
}),
|
|
70270
70793
|
async execute(args, ctx) {
|
|
70271
|
-
const projectName = args.name === "." ? basename23(ctx.workingDirectory) : basename23(
|
|
70794
|
+
const projectName = args.name === "." ? basename23(ctx.workingDirectory) : basename23(resolve80(ctx.workingDirectory, args.name));
|
|
70272
70795
|
const project = new Project(projectName);
|
|
70273
70796
|
if (args.fps) project.setFrameRate(args.fps);
|
|
70274
70797
|
let outputPath;
|
|
70275
70798
|
if (args.outputPath) {
|
|
70276
|
-
outputPath =
|
|
70799
|
+
outputPath = resolve80(ctx.workingDirectory, args.outputPath);
|
|
70277
70800
|
} else {
|
|
70278
|
-
const dirPath =
|
|
70279
|
-
await
|
|
70280
|
-
outputPath =
|
|
70801
|
+
const dirPath = resolve80(ctx.workingDirectory, args.name);
|
|
70802
|
+
await mkdir29(dirPath, { recursive: true });
|
|
70803
|
+
outputPath = resolve80(dirPath, TIMELINE_FILENAME);
|
|
70281
70804
|
}
|
|
70282
|
-
await
|
|
70805
|
+
await writeFile53(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
70283
70806
|
return {
|
|
70284
70807
|
success: true,
|
|
70285
70808
|
data: { name: projectName, outputPath },
|
|
@@ -70331,7 +70854,7 @@ var init_timeline = __esm({
|
|
|
70331
70854
|
}),
|
|
70332
70855
|
async execute(args, ctx) {
|
|
70333
70856
|
const { project, absPath } = await loadProject2(args.projectPath, ctx.workingDirectory);
|
|
70334
|
-
const mediaPath =
|
|
70857
|
+
const mediaPath = resolve80(ctx.workingDirectory, args.mediaPath);
|
|
70335
70858
|
const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "";
|
|
70336
70859
|
const source = project.addSource({
|
|
70337
70860
|
name: args.name ?? mediaPath.split("/").pop() ?? "media",
|
|
@@ -70578,11 +71101,11 @@ var init_timeline = __esm({
|
|
|
70578
71101
|
|
|
70579
71102
|
// src/commands/_shared/project-list.ts
|
|
70580
71103
|
import { readdir as readdir8, readFile as readFile52, stat as stat9 } from "node:fs/promises";
|
|
70581
|
-
import { existsSync as
|
|
70582
|
-
import { join as
|
|
71104
|
+
import { existsSync as existsSync60 } from "node:fs";
|
|
71105
|
+
import { join as join32, resolve as resolve81 } from "node:path";
|
|
70583
71106
|
async function executeProjectList(opts = {}) {
|
|
70584
|
-
const workspaceDir =
|
|
70585
|
-
if (!
|
|
71107
|
+
const workspaceDir = resolve81(opts.workspaceDir ?? ".");
|
|
71108
|
+
if (!existsSync60(workspaceDir)) {
|
|
70586
71109
|
return {
|
|
70587
71110
|
success: false,
|
|
70588
71111
|
workspaceDir,
|
|
@@ -70599,11 +71122,11 @@ async function executeProjectList(opts = {}) {
|
|
|
70599
71122
|
if (entry.name === "node_modules") continue;
|
|
70600
71123
|
if (entry.name.startsWith(".")) continue;
|
|
70601
71124
|
if (entry.name.startsWith("_")) {
|
|
70602
|
-
archivedCount += await countProjects(
|
|
71125
|
+
archivedCount += await countProjects(join32(workspaceDir, entry.name));
|
|
70603
71126
|
continue;
|
|
70604
71127
|
}
|
|
70605
|
-
const projectDir =
|
|
70606
|
-
if (!
|
|
71128
|
+
const projectDir = join32(workspaceDir, entry.name);
|
|
71129
|
+
if (!existsSync60(join32(projectDir, "STORYBOARD.md"))) continue;
|
|
70607
71130
|
projects.push(await describeProject(entry.name, projectDir));
|
|
70608
71131
|
}
|
|
70609
71132
|
projects.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
@@ -70613,7 +71136,7 @@ async function countProjects(dir) {
|
|
|
70613
71136
|
try {
|
|
70614
71137
|
const entries = await readdir8(dir, { withFileTypes: true });
|
|
70615
71138
|
return entries.filter(
|
|
70616
|
-
(e) => e.isDirectory() &&
|
|
71139
|
+
(e) => e.isDirectory() && existsSync60(join32(dir, e.name, "STORYBOARD.md"))
|
|
70617
71140
|
).length;
|
|
70618
71141
|
} catch {
|
|
70619
71142
|
return 0;
|
|
@@ -70624,7 +71147,7 @@ async function describeProject(name, projectDir) {
|
|
|
70624
71147
|
let storyboardDurationSec = 0;
|
|
70625
71148
|
const timestamps = [];
|
|
70626
71149
|
try {
|
|
70627
|
-
const storyboardPath2 =
|
|
71150
|
+
const storyboardPath2 = join32(projectDir, "STORYBOARD.md");
|
|
70628
71151
|
const parsed = parseStoryboard(await loadStoryboardMarkdown(projectDir));
|
|
70629
71152
|
beats = parsed.beats.length;
|
|
70630
71153
|
storyboardDurationSec = Number(
|
|
@@ -70636,7 +71159,7 @@ async function describeProject(name, projectDir) {
|
|
|
70636
71159
|
let buildStatus;
|
|
70637
71160
|
let buildUpdatedAt;
|
|
70638
71161
|
try {
|
|
70639
|
-
const reportPath =
|
|
71162
|
+
const reportPath = join32(projectDir, "build-report.json");
|
|
70640
71163
|
const report = JSON.parse(await readFile52(reportPath, "utf-8"));
|
|
70641
71164
|
buildStatus = report.status ?? report.phase;
|
|
70642
71165
|
buildUpdatedAt = report.updatedAt;
|
|
@@ -70645,12 +71168,12 @@ async function describeProject(name, projectDir) {
|
|
|
70645
71168
|
}
|
|
70646
71169
|
let latestRender;
|
|
70647
71170
|
try {
|
|
70648
|
-
const rendersDir =
|
|
71171
|
+
const rendersDir = join32(projectDir, "renders");
|
|
70649
71172
|
const files = await readdir8(rendersDir);
|
|
70650
71173
|
let newest;
|
|
70651
71174
|
for (const file of files) {
|
|
70652
71175
|
if (!/\.(mp4|webm|mov)$/i.test(file)) continue;
|
|
70653
|
-
const { mtimeMs } = await stat9(
|
|
71176
|
+
const { mtimeMs } = await stat9(join32(rendersDir, file));
|
|
70654
71177
|
if (!newest || mtimeMs > newest.mtimeMs) newest = { file, mtimeMs };
|
|
70655
71178
|
}
|
|
70656
71179
|
if (newest) {
|
|
@@ -70682,8 +71205,8 @@ var init_project_list = __esm({
|
|
|
70682
71205
|
});
|
|
70683
71206
|
|
|
70684
71207
|
// src/tools/manifest/project.ts
|
|
70685
|
-
import { resolve as
|
|
70686
|
-
import { writeFile as
|
|
71208
|
+
import { resolve as resolve82 } from "node:path";
|
|
71209
|
+
import { writeFile as writeFile54 } from "node:fs/promises";
|
|
70687
71210
|
var projectListTool, projectCreateTool, projectInfoTool, projectTools;
|
|
70688
71211
|
var init_project2 = __esm({
|
|
70689
71212
|
"src/tools/manifest/project.ts"() {
|
|
@@ -70707,7 +71230,7 @@ var init_project2 = __esm({
|
|
|
70707
71230
|
}),
|
|
70708
71231
|
async execute(args, ctx) {
|
|
70709
71232
|
const result = await executeProjectList({
|
|
70710
|
-
workspaceDir: args.dir ?
|
|
71233
|
+
workspaceDir: args.dir ? resolve82(ctx.workingDirectory, args.dir) : ctx.workingDirectory
|
|
70711
71234
|
});
|
|
70712
71235
|
if (!result.success) {
|
|
70713
71236
|
return { success: false, error: result.error ?? "project list failed" };
|
|
@@ -70744,10 +71267,10 @@ var init_project2 = __esm({
|
|
|
70744
71267
|
fps: external_exports.number().optional().describe("Frames per second (default: 30)")
|
|
70745
71268
|
}),
|
|
70746
71269
|
async execute(args, ctx) {
|
|
70747
|
-
const outputPath =
|
|
71270
|
+
const outputPath = resolve82(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
|
|
70748
71271
|
const project = new Project(args.name);
|
|
70749
71272
|
if (args.fps) project.setFrameRate(args.fps);
|
|
70750
|
-
await
|
|
71273
|
+
await writeFile54(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
70751
71274
|
return {
|
|
70752
71275
|
success: true,
|
|
70753
71276
|
data: { name: args.name, outputPath },
|
|
@@ -70794,7 +71317,7 @@ var init_project2 = __esm({
|
|
|
70794
71317
|
|
|
70795
71318
|
// src/commands/export.ts
|
|
70796
71319
|
import { readFile as readFile53, access as access7 } from "node:fs/promises";
|
|
70797
|
-
import { resolve as
|
|
71320
|
+
import { resolve as resolve83 } from "node:path";
|
|
70798
71321
|
import { spawn as spawn3 } from "node:child_process";
|
|
70799
71322
|
async function getMediaDuration(filePath, mediaType, defaultImageDuration = 5) {
|
|
70800
71323
|
if (mediaType === "image") {
|
|
@@ -70866,7 +71389,7 @@ async function runExport(projectPath, outputPath, options = {}) {
|
|
|
70866
71389
|
message: "Project has no clips to export"
|
|
70867
71390
|
};
|
|
70868
71391
|
}
|
|
70869
|
-
const finalOutputPath =
|
|
71392
|
+
const finalOutputPath = resolve83(process.cwd(), outputPath);
|
|
70870
71393
|
const basePresetSettings = getPresetSettings(preset, summary.aspectRatio);
|
|
70871
71394
|
const presetSettings = applyCustomOverrides(basePresetSettings, { bitrate, fps, resolution, codec });
|
|
70872
71395
|
const clips = project.getClips().sort((a, b) => a.startTime - b.startTime);
|
|
@@ -71262,7 +71785,7 @@ function buildFFmpegArgs(clips, sources, presetSettings, outputPath, options, so
|
|
|
71262
71785
|
return args;
|
|
71263
71786
|
}
|
|
71264
71787
|
function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
71265
|
-
return new Promise((
|
|
71788
|
+
return new Promise((resolve87, reject) => {
|
|
71266
71789
|
const ffmpeg = spawn3(ffmpegPath, args, {
|
|
71267
71790
|
stdio: ["pipe", "pipe", "pipe"]
|
|
71268
71791
|
});
|
|
@@ -71286,7 +71809,7 @@ function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
|
71286
71809
|
});
|
|
71287
71810
|
ffmpeg.on("close", (code) => {
|
|
71288
71811
|
if (code === 0) {
|
|
71289
|
-
|
|
71812
|
+
resolve87();
|
|
71290
71813
|
} else {
|
|
71291
71814
|
const errorMatch = stderr.match(/Error.*$/m);
|
|
71292
71815
|
const errorMsg = errorMatch ? errorMatch[0] : `FFmpeg exited with code ${code}`;
|
|
@@ -71439,7 +71962,7 @@ var init_export = __esm({
|
|
|
71439
71962
|
});
|
|
71440
71963
|
|
|
71441
71964
|
// src/tools/manifest/export.ts
|
|
71442
|
-
import { resolve as
|
|
71965
|
+
import { resolve as resolve84 } from "node:path";
|
|
71443
71966
|
var exportVideoTool, exportTools;
|
|
71444
71967
|
var init_export2 = __esm({
|
|
71445
71968
|
"src/tools/manifest/export.ts"() {
|
|
@@ -71462,8 +71985,8 @@ var init_export2 = __esm({
|
|
|
71462
71985
|
overwrite: external_exports.boolean().optional().describe("Overwrite existing output file (default: false)")
|
|
71463
71986
|
}),
|
|
71464
71987
|
async execute(args, ctx) {
|
|
71465
|
-
const projectPath =
|
|
71466
|
-
const outputPath =
|
|
71988
|
+
const projectPath = resolve84(ctx.workingDirectory, args.projectPath);
|
|
71989
|
+
const outputPath = resolve84(ctx.workingDirectory, args.outputPath);
|
|
71467
71990
|
const result = await runExport(projectPath, outputPath, {
|
|
71468
71991
|
preset: args.preset,
|
|
71469
71992
|
format: args.format,
|
|
@@ -71482,8 +72005,8 @@ var init_export2 = __esm({
|
|
|
71482
72005
|
});
|
|
71483
72006
|
|
|
71484
72007
|
// src/tools/manifest/agent-only.ts
|
|
71485
|
-
import { readFile as readFile54, writeFile as
|
|
71486
|
-
import { resolve as
|
|
72008
|
+
import { readFile as readFile54, writeFile as writeFile55, readdir as readdir9, stat as stat10, access as access8, unlink as unlink2 } from "node:fs/promises";
|
|
72009
|
+
import { resolve as resolve85, join as join33, basename as basename24, extname as extname15 } from "node:path";
|
|
71487
72010
|
function matchPattern(filename, pattern) {
|
|
71488
72011
|
const regex2 = new RegExp(
|
|
71489
72012
|
"^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".") + "$",
|
|
@@ -71563,12 +72086,12 @@ var init_agent_only = __esm({
|
|
|
71563
72086
|
async execute(args, ctx) {
|
|
71564
72087
|
const dirPath = args.path ?? ".";
|
|
71565
72088
|
try {
|
|
71566
|
-
const absPath =
|
|
72089
|
+
const absPath = resolve85(ctx.workingDirectory, dirPath);
|
|
71567
72090
|
const entries = await readdir9(absPath, { withFileTypes: true });
|
|
71568
72091
|
const results = [];
|
|
71569
72092
|
for (const entry of entries) {
|
|
71570
72093
|
if (args.pattern && !matchPattern(entry.name, args.pattern)) continue;
|
|
71571
|
-
const fullPath =
|
|
72094
|
+
const fullPath = join33(absPath, entry.name);
|
|
71572
72095
|
const stats = await stat10(fullPath);
|
|
71573
72096
|
if (entry.isDirectory()) {
|
|
71574
72097
|
results.push(`[DIR] ${entry.name}/`);
|
|
@@ -71596,7 +72119,7 @@ var init_agent_only = __esm({
|
|
|
71596
72119
|
}),
|
|
71597
72120
|
async execute(args, ctx) {
|
|
71598
72121
|
try {
|
|
71599
|
-
const absPath =
|
|
72122
|
+
const absPath = resolve85(ctx.workingDirectory, args.path);
|
|
71600
72123
|
const content = await readFile54(absPath, "utf-8");
|
|
71601
72124
|
const maxLength = 4e3;
|
|
71602
72125
|
const truncated = content.length > maxLength;
|
|
@@ -71621,8 +72144,8 @@ var init_agent_only = __esm({
|
|
|
71621
72144
|
}),
|
|
71622
72145
|
async execute(args, ctx) {
|
|
71623
72146
|
try {
|
|
71624
|
-
const absPath =
|
|
71625
|
-
await
|
|
72147
|
+
const absPath = resolve85(ctx.workingDirectory, args.path);
|
|
72148
|
+
await writeFile55(absPath, args.content, "utf-8");
|
|
71626
72149
|
return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
|
|
71627
72150
|
} catch (error) {
|
|
71628
72151
|
return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -71641,7 +72164,7 @@ var init_agent_only = __esm({
|
|
|
71641
72164
|
path: external_exports.string().describe("Path to check")
|
|
71642
72165
|
}),
|
|
71643
72166
|
async execute(args, ctx) {
|
|
71644
|
-
const absPath =
|
|
72167
|
+
const absPath = resolve85(ctx.workingDirectory, args.path);
|
|
71645
72168
|
try {
|
|
71646
72169
|
await access8(absPath);
|
|
71647
72170
|
const stats = await stat10(absPath);
|
|
@@ -71669,11 +72192,11 @@ var init_agent_only = __esm({
|
|
|
71669
72192
|
}),
|
|
71670
72193
|
async execute(args, ctx) {
|
|
71671
72194
|
try {
|
|
71672
|
-
const filePath =
|
|
72195
|
+
const filePath = resolve85(ctx.workingDirectory, args.project);
|
|
71673
72196
|
const content = await readFile54(filePath, "utf-8");
|
|
71674
72197
|
const data = JSON.parse(content);
|
|
71675
72198
|
const project = Project.fromJSON(data);
|
|
71676
|
-
const dirPath =
|
|
72199
|
+
const dirPath = resolve85(ctx.workingDirectory, args.directory);
|
|
71677
72200
|
const filterExts = args.filter ? args.filter.split(",").map((e) => e.trim().toLowerCase()) : null;
|
|
71678
72201
|
const imageDuration = args.imageDuration ?? 5;
|
|
71679
72202
|
const recursive = args.recursive ?? false;
|
|
@@ -71681,7 +72204,7 @@ var init_agent_only = __esm({
|
|
|
71681
72204
|
const scanDir = async (dir) => {
|
|
71682
72205
|
const entries = await readdir9(dir, { withFileTypes: true });
|
|
71683
72206
|
for (const entry of entries) {
|
|
71684
|
-
const entryPath =
|
|
72207
|
+
const entryPath = join33(dir, entry.name);
|
|
71685
72208
|
if (entry.isDirectory() && recursive) {
|
|
71686
72209
|
await scanDir(entryPath);
|
|
71687
72210
|
} else if (entry.isFile()) {
|
|
@@ -71708,7 +72231,7 @@ var init_agent_only = __esm({
|
|
|
71708
72231
|
const source = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
|
|
71709
72232
|
addedSources.push({ id: source.id, name: mediaName, type: mediaType });
|
|
71710
72233
|
}
|
|
71711
|
-
await
|
|
72234
|
+
await writeFile55(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
71712
72235
|
return {
|
|
71713
72236
|
success: true,
|
|
71714
72237
|
data: { count: addedSources.length, sources: addedSources },
|
|
@@ -71741,7 +72264,7 @@ var init_agent_only = __esm({
|
|
|
71741
72264
|
}),
|
|
71742
72265
|
async execute(args, ctx) {
|
|
71743
72266
|
try {
|
|
71744
|
-
const filePath =
|
|
72267
|
+
const filePath = resolve85(ctx.workingDirectory, args.project);
|
|
71745
72268
|
const content = await readFile54(filePath, "utf-8");
|
|
71746
72269
|
const data = JSON.parse(content);
|
|
71747
72270
|
const project = Project.fromJSON(data);
|
|
@@ -71778,7 +72301,7 @@ var init_agent_only = __esm({
|
|
|
71778
72301
|
createdClips.push({ id: clip.id, sourceName: source.name, startTime: currentTime, duration: source.duration });
|
|
71779
72302
|
currentTime += source.duration + gap;
|
|
71780
72303
|
}
|
|
71781
|
-
await
|
|
72304
|
+
await writeFile55(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
71782
72305
|
const totalDuration = currentTime - gap - startTime;
|
|
71783
72306
|
return {
|
|
71784
72307
|
success: true,
|
|
@@ -71812,7 +72335,7 @@ var init_agent_only = __esm({
|
|
|
71812
72335
|
}),
|
|
71813
72336
|
async execute(args, ctx) {
|
|
71814
72337
|
try {
|
|
71815
|
-
const filePath =
|
|
72338
|
+
const filePath = resolve85(ctx.workingDirectory, args.project);
|
|
71816
72339
|
const content = await readFile54(filePath, "utf-8");
|
|
71817
72340
|
const data = JSON.parse(content);
|
|
71818
72341
|
const project = Project.fromJSON(data);
|
|
@@ -71841,7 +72364,7 @@ var init_agent_only = __esm({
|
|
|
71841
72364
|
});
|
|
71842
72365
|
if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
|
|
71843
72366
|
}
|
|
71844
|
-
await
|
|
72367
|
+
await writeFile55(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
71845
72368
|
return {
|
|
71846
72369
|
success: true,
|
|
71847
72370
|
data: { applied: appliedEffects.length, effectType: args.effectType },
|
|
@@ -71910,7 +72433,7 @@ var init_agent_only = __esm({
|
|
|
71910
72433
|
removed.sources++;
|
|
71911
72434
|
}
|
|
71912
72435
|
}
|
|
71913
|
-
await
|
|
72436
|
+
await writeFile55(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
71914
72437
|
const parts = [];
|
|
71915
72438
|
if (removed.clips > 0) parts.push(`${removed.clips} clips`);
|
|
71916
72439
|
if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
|
|
@@ -71961,7 +72484,7 @@ var init_agent_only = __esm({
|
|
|
71961
72484
|
project.setFrameRate(args.fps);
|
|
71962
72485
|
updates.push(`Frame Rate: ${args.fps} fps`);
|
|
71963
72486
|
}
|
|
71964
|
-
await
|
|
72487
|
+
await writeFile55(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
71965
72488
|
return {
|
|
71966
72489
|
success: true,
|
|
71967
72490
|
data: { updates },
|
|
@@ -72104,7 +72627,7 @@ var init_agent_only = __esm({
|
|
|
72104
72627
|
}),
|
|
72105
72628
|
async execute(args, ctx) {
|
|
72106
72629
|
try {
|
|
72107
|
-
const absPath =
|
|
72630
|
+
const absPath = resolve85(ctx.workingDirectory, args.path);
|
|
72108
72631
|
const { stdout } = await execSafe(
|
|
72109
72632
|
"ffprobe",
|
|
72110
72633
|
["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", absPath],
|
|
@@ -72193,10 +72716,10 @@ Audio:`);
|
|
|
72193
72716
|
}),
|
|
72194
72717
|
async execute(args, ctx) {
|
|
72195
72718
|
try {
|
|
72196
|
-
const absInput =
|
|
72719
|
+
const absInput = resolve85(ctx.workingDirectory, args.input);
|
|
72197
72720
|
const ext = args.input.split(".").pop() || "mp4";
|
|
72198
72721
|
const baseName = args.input.replace(/\.[^/.]+$/, "");
|
|
72199
|
-
const outputPath = args.output ?
|
|
72722
|
+
const outputPath = args.output ? resolve85(ctx.workingDirectory, args.output) : resolve85(ctx.workingDirectory, `${baseName}-compressed.${ext}`);
|
|
72200
72723
|
const crfValues = { low: 28, medium: 23, high: 18 };
|
|
72201
72724
|
const crf = crfValues[args.quality ?? "medium"];
|
|
72202
72725
|
await execSafe(
|
|
@@ -72256,8 +72779,8 @@ Audio:`);
|
|
|
72256
72779
|
}),
|
|
72257
72780
|
async execute(args, ctx) {
|
|
72258
72781
|
try {
|
|
72259
|
-
const absInput =
|
|
72260
|
-
const absOutput =
|
|
72782
|
+
const absInput = resolve85(ctx.workingDirectory, args.input);
|
|
72783
|
+
const absOutput = resolve85(ctx.workingDirectory, args.output);
|
|
72261
72784
|
const codecMap = {
|
|
72262
72785
|
h264: "libx264",
|
|
72263
72786
|
h265: "libx265",
|
|
@@ -72310,11 +72833,11 @@ Audio:`);
|
|
|
72310
72833
|
};
|
|
72311
72834
|
}
|
|
72312
72835
|
try {
|
|
72313
|
-
const absOutput =
|
|
72836
|
+
const absOutput = resolve85(ctx.workingDirectory, args.output);
|
|
72314
72837
|
if (args.reencode) {
|
|
72315
72838
|
const ffmpegArgs = [];
|
|
72316
72839
|
for (const i of args.inputs) {
|
|
72317
|
-
ffmpegArgs.push("-i",
|
|
72840
|
+
ffmpegArgs.push("-i", resolve85(ctx.workingDirectory, i));
|
|
72318
72841
|
}
|
|
72319
72842
|
const filterComplex = args.inputs.map((_, i) => `[${i}:v][${i}:a]`).join("");
|
|
72320
72843
|
ffmpegArgs.push(
|
|
@@ -72329,9 +72852,9 @@ Audio:`);
|
|
|
72329
72852
|
);
|
|
72330
72853
|
await execSafe("ffmpeg", ffmpegArgs, { maxBuffer: 100 * 1024 * 1024 });
|
|
72331
72854
|
} else {
|
|
72332
|
-
const tempList =
|
|
72333
|
-
const listContent = args.inputs.map((i) => `file '${
|
|
72334
|
-
await
|
|
72855
|
+
const tempList = resolve85(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
|
|
72856
|
+
const listContent = args.inputs.map((i) => `file '${resolve85(ctx.workingDirectory, i)}'`).join("\n");
|
|
72857
|
+
await writeFile55(tempList, listContent, "utf-8");
|
|
72335
72858
|
try {
|
|
72336
72859
|
await execSafe(
|
|
72337
72860
|
"ffmpeg",
|
|
@@ -72427,7 +72950,7 @@ var init_walkthrough = __esm({
|
|
|
72427
72950
|
});
|
|
72428
72951
|
|
|
72429
72952
|
// src/tools/manifest/status.ts
|
|
72430
|
-
import { resolve as
|
|
72953
|
+
import { resolve as resolve86 } from "node:path";
|
|
72431
72954
|
var PROJECT_DIR_DESCRIPTION5, statusJobTool, statusProjectTool, statusTools;
|
|
72432
72955
|
var init_status = __esm({
|
|
72433
72956
|
"src/tools/manifest/status.ts"() {
|
|
@@ -72451,7 +72974,7 @@ var init_status = __esm({
|
|
|
72451
72974
|
output: external_exports.string().optional().describe("Download result media to this path when complete.")
|
|
72452
72975
|
}),
|
|
72453
72976
|
async execute(args, ctx) {
|
|
72454
|
-
const projectDir = args.projectDir ?
|
|
72977
|
+
const projectDir = args.projectDir ? resolve86(ctx.workingDirectory, args.projectDir) : findProjectRoot(ctx.workingDirectory);
|
|
72455
72978
|
const record = await readJobRecord(args.jobId, projectDir);
|
|
72456
72979
|
if (!record) return { success: false, error: `Job not found: ${args.jobId}` };
|
|
72457
72980
|
const result = args.refresh === false ? makeJobStatusResult(record, {
|
|
@@ -72460,7 +72983,7 @@ var init_status = __esm({
|
|
|
72460
72983
|
warnings: []
|
|
72461
72984
|
}) : await refreshJobRecord(record, {
|
|
72462
72985
|
wait: args.wait,
|
|
72463
|
-
output: args.output ?
|
|
72986
|
+
output: args.output ? resolve86(ctx.workingDirectory, args.output) : void 0,
|
|
72464
72987
|
workingDirectory: ctx.workingDirectory
|
|
72465
72988
|
});
|
|
72466
72989
|
return {
|
|
@@ -72485,7 +73008,7 @@ var init_status = __esm({
|
|
|
72485
73008
|
refresh: external_exports.boolean().optional().describe("Refresh active supported jobs before summarizing. Default false.")
|
|
72486
73009
|
}),
|
|
72487
73010
|
async execute(args, ctx) {
|
|
72488
|
-
const projectDir = args.projectDir ?
|
|
73011
|
+
const projectDir = args.projectDir ? resolve86(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
72489
73012
|
const result = await inspectProjectStatus(projectDir, { refresh: args.refresh === true });
|
|
72490
73013
|
return {
|
|
72491
73014
|
success: true,
|
|
@@ -72774,7 +73297,7 @@ init_source();
|
|
|
72774
73297
|
// package.json
|
|
72775
73298
|
var package_default = {
|
|
72776
73299
|
name: "@vibeframe/cli",
|
|
72777
|
-
version: "0.115.
|
|
73300
|
+
version: "0.115.2",
|
|
72778
73301
|
description: "Frontier AI video generation for coding agents - Seedance, Runway, Veo, and Kling on your own keys, behind a hard cost cap",
|
|
72779
73302
|
private: false,
|
|
72780
73303
|
license: "MIT",
|
|
@@ -79649,12 +80172,12 @@ function resolveCopier() {
|
|
|
79649
80172
|
async function copyToClipboard(text) {
|
|
79650
80173
|
const opener = resolveCopier();
|
|
79651
80174
|
if (!opener) return false;
|
|
79652
|
-
return new Promise((
|
|
80175
|
+
return new Promise((resolve87) => {
|
|
79653
80176
|
let settled = false;
|
|
79654
80177
|
const finish = (ok) => {
|
|
79655
80178
|
if (settled) return;
|
|
79656
80179
|
settled = true;
|
|
79657
|
-
|
|
80180
|
+
resolve87(ok);
|
|
79658
80181
|
};
|
|
79659
80182
|
try {
|
|
79660
80183
|
const child = spawn2(opener.command, opener.args, {
|
|
@@ -82991,8 +83514,8 @@ init_scene_build();
|
|
|
82991
83514
|
init_build_plan();
|
|
82992
83515
|
init_storyboard_parse();
|
|
82993
83516
|
init_output();
|
|
82994
|
-
import { resolve as
|
|
82995
|
-
import { readFileSync as readFileSync3, existsSync as
|
|
83517
|
+
import { resolve as resolve64, join as join29 } from "node:path";
|
|
83518
|
+
import { readFileSync as readFileSync3, existsSync as existsSync52 } from "node:fs";
|
|
82996
83519
|
var VALID_MODES2 = ["agent", "batch", "auto"];
|
|
82997
83520
|
var VALID_STAGES2 = ["assets", "transcript", "compose", "sync", "render", "all"];
|
|
82998
83521
|
var VALID_IMAGE_PROVIDERS2 = ["openai", "gemini", "grok"];
|
|
@@ -83000,14 +83523,17 @@ var VALID_VIDEO_PROVIDERS2 = ["seedance", "grok", "kling", "runway", "veo"];
|
|
|
83000
83523
|
var VALID_MUSIC_PROVIDERS2 = ["elevenlabs", "replicate"];
|
|
83001
83524
|
var buildCommand = new Command("build").description("Build a VibeFrame video project from STORYBOARD.md").argument("[project-dir]", "Video project directory", ".").option("--stage <stage>", `Build stage: ${VALID_STAGES2.join("|")}`, "all").option("--beat <id>", "Restrict asset/compose work to one beat id").option("--mode <mode>", "Retained for compatibility; scene HTML is always authored by your host agent unless --composer template is set", "auto").option(
|
|
83002
83525
|
"--composer <provider>",
|
|
83003
|
-
"Set to `template` for the deterministic AI-video composer (concat bg + lower-thirds, no model). Omit to let the host agent author each scene."
|
|
83526
|
+
"Set to `template` for the deterministic AI-video composer (concat bg + lower-thirds, no model) or `footage` for the crossfade footage cut (clips + narration + music, no HTML render). Omit to let the host agent author each scene."
|
|
83004
83527
|
).option("--max-cost <usd>", "Fail before provider spend when estimated cost exceeds this USD cap").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-video", "Don't dispatch video generation even when beats declare video cues").option(
|
|
83005
83528
|
"--skip-keyframe",
|
|
83006
83529
|
"Don't generate keyframe stills (review keyframes first with --skip-video, then build)"
|
|
83007
83530
|
).option("--skip-music", "Don't dispatch music generation even when beats declare music cues").option(
|
|
83008
83531
|
"--skip-transcript",
|
|
83009
83532
|
"Don't transcribe narration for word-sync (default: transcribe when narration + OpenAI key exist)"
|
|
83010
|
-
).option("--skip-render", "Compose only - don't render to MP4").option("--tts <provider>", "TTS provider: auto|elevenlabs|openai|kokoro").option("--voice <id>", "Voice id").option("--image-provider <name>", `Image provider: ${VALID_IMAGE_PROVIDERS2.join("|")}`).option(
|
|
83533
|
+
).option("--skip-render", "Compose only - don't render to MP4").option("--tts <provider>", "TTS provider: auto|elevenlabs|openai|kokoro").option("--voice <id>", "Voice id").option("--image-provider <name>", `Image provider: ${VALID_IMAGE_PROVIDERS2.join("|")}`).option(
|
|
83534
|
+
"--image-model <model>",
|
|
83535
|
+
"Image model for keyframes/backdrops/character sheets (gemini: flash|pro, openai: gpt-image-2). Provider default when omitted."
|
|
83536
|
+
).option("--video-provider <name>", `Video provider: ${VALID_VIDEO_PROVIDERS2.join("|")}`).option("--music-provider <name>", `Music provider: ${VALID_MUSIC_PROVIDERS2.join("|")}`).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(
|
|
83011
83537
|
"after",
|
|
83012
83538
|
`
|
|
83013
83539
|
Examples:
|
|
@@ -83018,7 +83544,7 @@ Examples:
|
|
|
83018
83544
|
Advanced equivalent: \`vibe scene build\`.`
|
|
83019
83545
|
).action(async (projectDirArg, options) => {
|
|
83020
83546
|
const startedAt = Date.now();
|
|
83021
|
-
const projectDir =
|
|
83547
|
+
const projectDir = resolve64(projectDirArg);
|
|
83022
83548
|
const mode = String(options.mode ?? "auto");
|
|
83023
83549
|
if (!VALID_MODES2.includes(mode)) {
|
|
83024
83550
|
exitWithError(
|
|
@@ -83075,6 +83601,7 @@ Advanced equivalent: \`vibe scene build\`.`
|
|
|
83075
83601
|
videoProvider,
|
|
83076
83602
|
musicProvider,
|
|
83077
83603
|
imageQuality: options.quality,
|
|
83604
|
+
imageModel: options.imageModel,
|
|
83078
83605
|
imageSize: options.imageSize,
|
|
83079
83606
|
force: options.force ?? false
|
|
83080
83607
|
};
|
|
@@ -83094,6 +83621,7 @@ Advanced equivalent: \`vibe scene build\`.`
|
|
|
83094
83621
|
voice: options.voice,
|
|
83095
83622
|
imageProvider,
|
|
83096
83623
|
imageQuality: options.quality,
|
|
83624
|
+
imageModel: options.imageModel,
|
|
83097
83625
|
imageSize: options.imageSize,
|
|
83098
83626
|
videoProvider,
|
|
83099
83627
|
musicProvider,
|
|
@@ -83168,6 +83696,7 @@ Advanced equivalent: \`vibe scene build\`.`
|
|
|
83168
83696
|
videoProvider,
|
|
83169
83697
|
musicProvider,
|
|
83170
83698
|
imageQuality: options.quality,
|
|
83699
|
+
imageModel: options.imageModel,
|
|
83171
83700
|
imageSize: options.imageSize,
|
|
83172
83701
|
force: options.force,
|
|
83173
83702
|
onProgress: (e) => {
|
|
@@ -83350,8 +83879,8 @@ function buildPlanValidationFailureData(plan) {
|
|
|
83350
83879
|
};
|
|
83351
83880
|
}
|
|
83352
83881
|
function estimateBuildCost(params) {
|
|
83353
|
-
const storyboardPath2 =
|
|
83354
|
-
if (!
|
|
83882
|
+
const storyboardPath2 = join29(params.projectDir, "STORYBOARD.md");
|
|
83883
|
+
if (!existsSync52(storyboardPath2)) return null;
|
|
83355
83884
|
let beats = 0;
|
|
83356
83885
|
try {
|
|
83357
83886
|
const md = readFileSync3(storyboardPath2, "utf-8");
|
|
@@ -83485,7 +84014,7 @@ init_source();
|
|
|
83485
84014
|
init_ora();
|
|
83486
84015
|
init_scene_render();
|
|
83487
84016
|
init_output();
|
|
83488
|
-
import { resolve as
|
|
84017
|
+
import { resolve as resolve65 } from "node:path";
|
|
83489
84018
|
var VALID_FPS = [24, 30, 60];
|
|
83490
84019
|
var VALID_QUALITIES = ["draft", "standard", "high"];
|
|
83491
84020
|
var VALID_FORMATS = ["mp4", "webm", "mov"];
|
|
@@ -83496,7 +84025,7 @@ Examples:
|
|
|
83496
84025
|
|
|
83497
84026
|
Alias note: this is the project-level entrypoint for \`vibe scene render\`.`).action(async (projectDirArg, options) => {
|
|
83498
84027
|
const startedAt = Date.now();
|
|
83499
|
-
const projectDir =
|
|
84028
|
+
const projectDir = resolve65(projectDirArg);
|
|
83500
84029
|
const fps = parseFps(String(options.fps));
|
|
83501
84030
|
const quality = parseQuality(String(options.quality));
|
|
83502
84031
|
const format = parseFormat(String(options.format));
|
|
@@ -83638,7 +84167,7 @@ init_source();
|
|
|
83638
84167
|
init_ora();
|
|
83639
84168
|
init_scene_render();
|
|
83640
84169
|
init_output();
|
|
83641
|
-
import { resolve as
|
|
84170
|
+
import { resolve as resolve66 } from "node:path";
|
|
83642
84171
|
var VALID_FPS2 = [24, 30, 60];
|
|
83643
84172
|
var VALID_QUALITIES2 = ["draft", "standard", "high"];
|
|
83644
84173
|
var VALID_FORMATS2 = ["mp4", "webm", "mov"];
|
|
@@ -83656,7 +84185,7 @@ Examples:
|
|
|
83656
84185
|
$ vibe preview my-video --beat hook
|
|
83657
84186
|
$ vibe preview my-video --fps 30 # override the cheap default`).action(async (projectDirArg, options) => {
|
|
83658
84187
|
const startedAt = Date.now();
|
|
83659
|
-
const projectDir =
|
|
84188
|
+
const projectDir = resolve66(projectDirArg);
|
|
83660
84189
|
const fps = parseFps2(String(options.fps));
|
|
83661
84190
|
const quality = parseQuality2(String(options.quality));
|
|
83662
84191
|
const format = parseFormat2(String(options.format));
|
|
@@ -83793,21 +84322,35 @@ init_esm();
|
|
|
83793
84322
|
init_source();
|
|
83794
84323
|
init_ora();
|
|
83795
84324
|
init_scene_assemble();
|
|
84325
|
+
init_footage_assemble();
|
|
83796
84326
|
init_output();
|
|
83797
|
-
import { resolve as
|
|
84327
|
+
import { resolve as resolve67 } from "node:path";
|
|
83798
84328
|
var VALID_FORMATS3 = ["mp4", "webm", "mov"];
|
|
83799
84329
|
var DEFAULT_VIDEO = "preview.mp4";
|
|
83800
|
-
var assembleCommand = new Command("assemble").description(
|
|
83801
|
-
|
|
83802
|
-
one
|
|
84330
|
+
var assembleCommand = new Command("assemble").description(
|
|
84331
|
+
"Mux a scene project's audio onto a rendered video, or crossfade-cut its generated clips (--footage)"
|
|
84332
|
+
).argument("[project-dir]", "Video project directory", ".").option("--video <path>", `Rendered video to add audio to (default: ${DEFAULT_VIDEO})`, DEFAULT_VIDEO).option("--root <file>", "Root composition file", "index.html").option("--format <f>", `Output container: ${VALID_FORMATS3.join("|")}`, "mp4").option("--footage", "Assemble assets/video-<beat>.mp4 clips into one cinematic cut (no HTML render)").option("-o, --output <path>", "Footage-cut output path (default: renders/footage.mp4)").option("--transition <sec>", "Footage crossfade length in seconds", "0.5").option("--fade <sec>", "Footage fade-from/to-black length in seconds", "0.6").option("--music <path>", 'Footage music bed: a file path or "none" (default: auto-detect assets/music*)').option("--music-volume <v>", "Footage music-bed volume before ducking (0-1)", "0.35").option("--finish", "Footage cinematic finish: vignette + film grain before the fades").option("--dry-run", "Preview parameters without muxing").addHelpText("after", `
|
|
84333
|
+
The default assemble stage lays the project's <audio> elements onto a silent
|
|
84334
|
+
video in one FFmpeg pass (-c:v copy, no re-encode). Pair it with \`vibe render
|
|
84335
|
+
--silent\`:
|
|
83803
84336
|
|
|
83804
84337
|
$ vibe render my-video --silent -o draft.mp4
|
|
83805
84338
|
$ vibe assemble my-video --video draft.mp4
|
|
83806
84339
|
|
|
83807
|
-
|
|
83808
|
-
|
|
84340
|
+
With --footage the project's generated clips become the picture: they are
|
|
84341
|
+
crossfade-concatenated in beat order, narration is laid at computed offsets,
|
|
84342
|
+
an optional music bed is ducked under it, and the head/tail fade to black -
|
|
84343
|
+
one FFmpeg pass, no HTML composition or browser capture. Timing comes from
|
|
84344
|
+
the real files (ffprobe), and assemble-report.json records every offset:
|
|
84345
|
+
|
|
84346
|
+
$ vibe build my-video --stage assets --json # clips + narration
|
|
84347
|
+
$ vibe assemble my-video --footage --json`).action(async (projectDirArg, options) => {
|
|
83809
84348
|
const startedAt = Date.now();
|
|
83810
|
-
const projectDir =
|
|
84349
|
+
const projectDir = resolve67(projectDirArg);
|
|
84350
|
+
if (options.footage) {
|
|
84351
|
+
await runFootageAssemble(projectDir, options, startedAt);
|
|
84352
|
+
return;
|
|
84353
|
+
}
|
|
83811
84354
|
const format = parseFormat3(String(options.format));
|
|
83812
84355
|
const video = String(options.video ?? DEFAULT_VIDEO);
|
|
83813
84356
|
const params = { projectDir, root: options.root, video, format };
|
|
@@ -83844,6 +84387,73 @@ you want the two steps separated (e.g. swap the audio bed without re-rendering).
|
|
|
83844
84387
|
}
|
|
83845
84388
|
printAssembleResult(spinner2, result);
|
|
83846
84389
|
});
|
|
84390
|
+
async function runFootageAssemble(projectDir, options, startedAt) {
|
|
84391
|
+
const transitionSec = parseSeconds("--transition", options.transition);
|
|
84392
|
+
const fadeSec = parseSeconds("--fade", options.fade);
|
|
84393
|
+
const musicVolume = parseSeconds("--music-volume", options.musicVolume);
|
|
84394
|
+
const spinner2 = isJsonMode() || isQuietMode() || options.dryRun ? null : ora("Assembling footage cut...").start();
|
|
84395
|
+
const result = await executeFootageAssemble({
|
|
84396
|
+
projectDir,
|
|
84397
|
+
output: options.output,
|
|
84398
|
+
transitionSec,
|
|
84399
|
+
fadeSec,
|
|
84400
|
+
music: options.music,
|
|
84401
|
+
musicVolume,
|
|
84402
|
+
finish: Boolean(options.finish),
|
|
84403
|
+
dryRun: Boolean(options.dryRun)
|
|
84404
|
+
});
|
|
84405
|
+
if (!result.success) {
|
|
84406
|
+
spinner2?.fail("Footage assemble failed");
|
|
84407
|
+
exitWithError(generalError(result.error ?? "Footage assemble failed", result.suggestion));
|
|
84408
|
+
}
|
|
84409
|
+
if (isJsonMode() || isQuietMode()) {
|
|
84410
|
+
outputSuccess({ command: "assemble", startedAt, dryRun: result.dryRun, data: { ...result } });
|
|
84411
|
+
return;
|
|
84412
|
+
}
|
|
84413
|
+
printFootageResult(spinner2, result);
|
|
84414
|
+
}
|
|
84415
|
+
function printFootageResult(spinner2, result) {
|
|
84416
|
+
const report = result.report;
|
|
84417
|
+
if (result.dryRun) {
|
|
84418
|
+
console.log();
|
|
84419
|
+
console.log(source_default.bold.cyan("VibeFrame Assemble - footage dry run"));
|
|
84420
|
+
} else {
|
|
84421
|
+
spinner2?.succeed(source_default.green(`Footage cut assembled: ${result.outputPath}`));
|
|
84422
|
+
console.log();
|
|
84423
|
+
console.log(source_default.bold.cyan("Footage cut"));
|
|
84424
|
+
}
|
|
84425
|
+
console.log(source_default.dim("-".repeat(60)));
|
|
84426
|
+
if (report) {
|
|
84427
|
+
console.log(` Output: ${source_default.bold(report.output)}`);
|
|
84428
|
+
console.log(` Duration: ${source_default.bold(`${report.totalDurationSec}s`)}`);
|
|
84429
|
+
console.log(` Transition: ${report.transitionSec}s crossfade, ${report.fadeSec}s head/tail fade`);
|
|
84430
|
+
console.log(
|
|
84431
|
+
` Music: ${report.music ? `${report.music.path}${report.music.ducked ? " (ducked)" : ""}` : source_default.dim("none")}`
|
|
84432
|
+
);
|
|
84433
|
+
for (const beat of report.beats) {
|
|
84434
|
+
const narration = beat.narrationStartSec !== void 0 ? ` nar@${beat.narrationStartSec}s` : "";
|
|
84435
|
+
const extended = beat.extendedSec > 0 ? source_default.yellow(` +${beat.extendedSec}s hold`) : "";
|
|
84436
|
+
console.log(
|
|
84437
|
+
` ${beat.id.padEnd(12)} ${String(beat.startSec).padStart(7)}s ${beat.segmentDurationSec}s${narration}${extended}`
|
|
84438
|
+
);
|
|
84439
|
+
}
|
|
84440
|
+
for (const warning of report.warnings) console.log(source_default.yellow(` Warning: ${warning}`));
|
|
84441
|
+
}
|
|
84442
|
+
if (result.dryRun) {
|
|
84443
|
+
console.log();
|
|
84444
|
+
console.log(source_default.dim("No FFmpeg pass ran; nothing was written."));
|
|
84445
|
+
} else if (result.reportPath) {
|
|
84446
|
+
console.log(` Report: ${result.reportPath}`);
|
|
84447
|
+
}
|
|
84448
|
+
}
|
|
84449
|
+
function parseSeconds(flag, value) {
|
|
84450
|
+
if (value === void 0) return void 0;
|
|
84451
|
+
const n = Number.parseFloat(String(value));
|
|
84452
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
84453
|
+
exitWithError(usageError(`Invalid ${flag}: ${String(value)}`, "Expected a non-negative number."));
|
|
84454
|
+
}
|
|
84455
|
+
return n;
|
|
84456
|
+
}
|
|
83847
84457
|
function printAssembleDryRun(projectDirArg, params) {
|
|
83848
84458
|
console.log();
|
|
83849
84459
|
console.log(source_default.bold.cyan("VibeFrame Assemble - dry run"));
|
|
@@ -83879,7 +84489,7 @@ init_source();
|
|
|
83879
84489
|
init_cost_tier();
|
|
83880
84490
|
init_status_jobs();
|
|
83881
84491
|
init_output();
|
|
83882
|
-
import { resolve as
|
|
84492
|
+
import { resolve as resolve68 } from "node:path";
|
|
83883
84493
|
var statusCommand = new Command("status").description("Inspect local async jobs and project workflow status").addHelpText("after", `
|
|
83884
84494
|
Examples:
|
|
83885
84495
|
$ vibe status job job_abc123 --json
|
|
@@ -83890,7 +84500,7 @@ Examples:
|
|
|
83890
84500
|
statusCommand.command("job").description("Show one async job status").argument("<job-id>", "Local job id from a no-wait command").option("--project <dir>", "Project directory containing .vibeframe/jobs").option("--no-refresh", "Read local job record only; do not call provider APIs").option("--wait", "Wait for completion when the provider status helper supports it").option("-o, --output <path>", "Download result media when complete").action(async (jobId, options) => {
|
|
83891
84501
|
const startedAt = Date.now();
|
|
83892
84502
|
try {
|
|
83893
|
-
const projectDir = options.project ?
|
|
84503
|
+
const projectDir = options.project ? resolve68(options.project) : findProjectRoot();
|
|
83894
84504
|
const record = await readJobRecord(jobId, projectDir);
|
|
83895
84505
|
if (!record) {
|
|
83896
84506
|
exitWithError(generalError(`Job not found: ${jobId}`, `Run 'vibe status project ${projectDir} --json' to list known jobs.`));
|
|
@@ -83918,7 +84528,7 @@ applyTier(statusCommand.commands[statusCommand.commands.length - 1], "free");
|
|
|
83918
84528
|
statusCommand.command("project").description("Summarize build, review, and async job status for a project").argument("[project-dir]", "VibeFrame project directory", ".").option("--refresh", "Refresh active supported jobs before summarizing").action(async (projectDirArg, options) => {
|
|
83919
84529
|
const startedAt = Date.now();
|
|
83920
84530
|
try {
|
|
83921
|
-
const result = await inspectProjectStatus(
|
|
84531
|
+
const result = await inspectProjectStatus(resolve68(projectDirArg), {
|
|
83922
84532
|
refresh: options.refresh === true
|
|
83923
84533
|
});
|
|
83924
84534
|
if (isJsonMode()) {
|
|
@@ -84025,8 +84635,8 @@ init_dist2();
|
|
|
84025
84635
|
init_exec_safe();
|
|
84026
84636
|
init_exec_safe();
|
|
84027
84637
|
init_api_key();
|
|
84028
|
-
import { existsSync as
|
|
84029
|
-
import { resolve as
|
|
84638
|
+
import { existsSync as existsSync53 } from "node:fs";
|
|
84639
|
+
import { resolve as resolve69 } from "node:path";
|
|
84030
84640
|
init_composer_resolve();
|
|
84031
84641
|
init_cost_tier();
|
|
84032
84642
|
init_install_skill();
|
|
@@ -84157,13 +84767,13 @@ async function runDiagnostics() {
|
|
|
84157
84767
|
installed = false;
|
|
84158
84768
|
}
|
|
84159
84769
|
} else if (toolName === "chrome") {
|
|
84160
|
-
const { existsSync:
|
|
84770
|
+
const { existsSync: existsSync61 } = await import("node:fs");
|
|
84161
84771
|
const { homedir: homedir8 } = await import("node:os");
|
|
84162
|
-
const { join:
|
|
84772
|
+
const { join: join34 } = await import("node:path");
|
|
84163
84773
|
const chromePaths = [
|
|
84164
84774
|
process.env.HYPERFRAMES_CHROME_PATH,
|
|
84165
84775
|
process.env.CHROME_PATH,
|
|
84166
|
-
|
|
84776
|
+
join34(
|
|
84167
84777
|
homedir8(),
|
|
84168
84778
|
".cache",
|
|
84169
84779
|
"puppeteer",
|
|
@@ -84178,7 +84788,7 @@ async function runDiagnostics() {
|
|
|
84178
84788
|
"/usr/bin/chromium",
|
|
84179
84789
|
"/usr/bin/chromium-browser"
|
|
84180
84790
|
];
|
|
84181
|
-
installed = chromePaths.some((p) => p &&
|
|
84791
|
+
installed = chromePaths.some((p) => p && existsSync61(p));
|
|
84182
84792
|
} else {
|
|
84183
84793
|
installed = commandExists(toolName);
|
|
84184
84794
|
}
|
|
@@ -84218,7 +84828,7 @@ async function runDiagnostics() {
|
|
|
84218
84828
|
}
|
|
84219
84829
|
const projectFiles = ["AGENTS.md", "CLAUDE.md", "vibe.project.yaml"].map((rel) => ({
|
|
84220
84830
|
path: rel,
|
|
84221
|
-
exists:
|
|
84831
|
+
exists: existsSync53(resolve69(cwd, rel))
|
|
84222
84832
|
}));
|
|
84223
84833
|
const projectInitialized = projectFiles.some((f) => f.exists);
|
|
84224
84834
|
const nearestProjectConfigPath = await findProjectConfigPath(cwd);
|
|
@@ -84236,7 +84846,7 @@ async function runDiagnostics() {
|
|
|
84236
84846
|
} catch (err) {
|
|
84237
84847
|
if (!(err instanceof ComposerResolveError)) throw err;
|
|
84238
84848
|
}
|
|
84239
|
-
const sceneProjectInCwd =
|
|
84849
|
+
const sceneProjectInCwd = existsSync53(resolve69(cwd, "STORYBOARD.md"));
|
|
84240
84850
|
const skillInstalled = hyperframesSkillAvailable(cwd);
|
|
84241
84851
|
const skillPath = resolveSkillReference(cwd);
|
|
84242
84852
|
return {
|
|
@@ -84589,7 +85199,7 @@ init_esm();
|
|
|
84589
85199
|
init_source();
|
|
84590
85200
|
init_exec_safe();
|
|
84591
85201
|
init_cost_tier();
|
|
84592
|
-
import { resolve as
|
|
85202
|
+
import { resolve as resolve70 } from "node:path";
|
|
84593
85203
|
init_output();
|
|
84594
85204
|
var hostCommand = new Command("host").description("Set up Codex, Claude, and Cursor app integrations").addHelpText(
|
|
84595
85205
|
"after",
|
|
@@ -84603,7 +85213,7 @@ Examples:
|
|
|
84603
85213
|
);
|
|
84604
85214
|
hostCommand.command("list").description("List supported app hosts and integration surfaces").action(() => {
|
|
84605
85215
|
const startedAt = Date.now();
|
|
84606
|
-
const hosts = hostDefinitions(
|
|
85216
|
+
const hosts = hostDefinitions(resolve70(".")).map((host) => ({
|
|
84607
85217
|
id: host.id,
|
|
84608
85218
|
label: host.label,
|
|
84609
85219
|
surfaces: host.surfaces,
|
|
@@ -84630,7 +85240,7 @@ applyTier(hostCommand.commands[hostCommand.commands.length - 1], "free");
|
|
|
84630
85240
|
hostCommand.command("setup").description("Print or write Codex/Claude/Cursor MCP and project integration config").argument("[host]", `Host target: ${HOST_SELECTIONS.join(" | ")}`, "all").argument("[project-dir]", "Project directory for project-scoped config", ".").option("--write", "Write config files instead of printing snippets only").option("--dry-run", "Show file actions without writing").option("--force", "Replace an existing vibeframe MCP entry").action(async (hostArg, projectDirArg, options) => {
|
|
84631
85241
|
const startedAt = Date.now();
|
|
84632
85242
|
const selection = validateHostSelection(hostArg);
|
|
84633
|
-
const projectDir =
|
|
85243
|
+
const projectDir = resolve70(projectDirArg);
|
|
84634
85244
|
const ids = resolveHostSelection(selection);
|
|
84635
85245
|
const defs = hostDefinitions(projectDir).filter((host) => ids.includes(host.id));
|
|
84636
85246
|
const plans = [];
|
|
@@ -84664,7 +85274,7 @@ applyTier(hostCommand.commands[hostCommand.commands.length - 1], "free");
|
|
|
84664
85274
|
hostCommand.command("doctor").description("Check Codex/Claude/Cursor app integration readiness").argument("[host]", `Host target: ${HOST_SELECTIONS.join(" | ")}`, "all").argument("[project-dir]", "Project directory to inspect", ".").action(async (hostArg, projectDirArg) => {
|
|
84665
85275
|
const startedAt = Date.now();
|
|
84666
85276
|
const selection = validateHostSelection(hostArg);
|
|
84667
|
-
const projectDir =
|
|
85277
|
+
const projectDir = resolve70(projectDirArg);
|
|
84668
85278
|
const ids = resolveHostSelection(selection);
|
|
84669
85279
|
const defs = hostDefinitions(projectDir).filter((host) => ids.includes(host.id));
|
|
84670
85280
|
const hosts = await Promise.all(defs.map((host) => inspectHost(host, projectDir)));
|
|
@@ -84784,10 +85394,10 @@ init_exec_safe();
|
|
|
84784
85394
|
init_detect();
|
|
84785
85395
|
init_ai_edit();
|
|
84786
85396
|
init_output();
|
|
84787
|
-
import { resolve as
|
|
84788
|
-
import { existsSync as
|
|
84789
|
-
import { mkdir as
|
|
84790
|
-
var DEMO_DIR =
|
|
85397
|
+
import { resolve as resolve71 } from "node:path";
|
|
85398
|
+
import { existsSync as existsSync54 } from "node:fs";
|
|
85399
|
+
import { mkdir as mkdir27, rm as rm6 } from "node:fs/promises";
|
|
85400
|
+
var DEMO_DIR = resolve71(process.cwd(), ".vibeframe-demo");
|
|
84791
85401
|
async function generateTestVideo(outputPath) {
|
|
84792
85402
|
const filter = [
|
|
84793
85403
|
// Video: color bars with text
|
|
@@ -84816,7 +85426,7 @@ async function generateTestVideo(outputPath) {
|
|
|
84816
85426
|
"-y",
|
|
84817
85427
|
outputPath
|
|
84818
85428
|
], { timeout: 3e4, maxBuffer: 50 * 1024 * 1024 });
|
|
84819
|
-
return
|
|
85429
|
+
return existsSync54(outputPath);
|
|
84820
85430
|
} catch {
|
|
84821
85431
|
try {
|
|
84822
85432
|
await execSafe("ffmpeg", [
|
|
@@ -84842,7 +85452,7 @@ async function generateTestVideo(outputPath) {
|
|
|
84842
85452
|
"-y",
|
|
84843
85453
|
outputPath
|
|
84844
85454
|
], { timeout: 3e4, maxBuffer: 50 * 1024 * 1024 });
|
|
84845
|
-
return
|
|
85455
|
+
return existsSync54(outputPath);
|
|
84846
85456
|
} catch {
|
|
84847
85457
|
return false;
|
|
84848
85458
|
}
|
|
@@ -84866,8 +85476,8 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
84866
85476
|
console.log(source_default.dim(" " + "\u2500".repeat(50)));
|
|
84867
85477
|
console.log();
|
|
84868
85478
|
}
|
|
84869
|
-
await
|
|
84870
|
-
const testVideo =
|
|
85479
|
+
await mkdir27(DEMO_DIR, { recursive: true });
|
|
85480
|
+
const testVideo = resolve71(DEMO_DIR, "test-input.mp4");
|
|
84871
85481
|
const genSpinner = !isJson ? ora("Generating test video...").start() : null;
|
|
84872
85482
|
const generated = await generateTestVideo(testVideo);
|
|
84873
85483
|
if (!generated) {
|
|
@@ -84896,7 +85506,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
84896
85506
|
name: "Silence Cut",
|
|
84897
85507
|
description: "Removing silent segments",
|
|
84898
85508
|
run: async () => {
|
|
84899
|
-
const output =
|
|
85509
|
+
const output = resolve71(DEMO_DIR, "silence-cut.mp4");
|
|
84900
85510
|
const r = await executeSilenceCut({ videoPath: testVideo, outputPath: output, padding: 0.1 });
|
|
84901
85511
|
if (r.success && r.totalDuration && r.silentDuration) {
|
|
84902
85512
|
return { success: true, detail: `Removed ${r.silentDuration.toFixed(1)}s silence (${r.totalDuration.toFixed(1)}s \u2192 ${(r.totalDuration - r.silentDuration).toFixed(1)}s)` };
|
|
@@ -84908,7 +85518,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
84908
85518
|
name: "Noise Reduce",
|
|
84909
85519
|
description: "Reducing background noise",
|
|
84910
85520
|
run: async () => {
|
|
84911
|
-
const output =
|
|
85521
|
+
const output = resolve71(DEMO_DIR, "noise-reduced.mp4");
|
|
84912
85522
|
const r = await executeNoiseReduce({ inputPath: testVideo, outputPath: output, strength: "medium" });
|
|
84913
85523
|
return { success: r.success, detail: r.success ? `Cleaned audio \u2192 ${output}` : r.error };
|
|
84914
85524
|
}
|
|
@@ -84917,7 +85527,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
84917
85527
|
name: "Fade Effects",
|
|
84918
85528
|
description: "Adding fade in/out",
|
|
84919
85529
|
run: async () => {
|
|
84920
|
-
const output =
|
|
85530
|
+
const output = resolve71(DEMO_DIR, "faded.mp4");
|
|
84921
85531
|
const r = await executeFade({ videoPath: testVideo, outputPath: output, fadeIn: 1, fadeOut: 1 });
|
|
84922
85532
|
return { success: r.success, detail: r.success ? `1s fade in + 1s fade out \u2192 ${output}` : r.error };
|
|
84923
85533
|
}
|
|
@@ -84984,20 +85594,20 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
|
|
|
84984
85594
|
|
|
84985
85595
|
// src/commands/context.ts
|
|
84986
85596
|
init_esm();
|
|
84987
|
-
import { existsSync as
|
|
85597
|
+
import { existsSync as existsSync55 } from "node:fs";
|
|
84988
85598
|
import { readFile as readFile45 } from "node:fs/promises";
|
|
84989
|
-
import { resolve as
|
|
85599
|
+
import { resolve as resolve72, dirname as dirname23 } from "node:path";
|
|
84990
85600
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
84991
85601
|
var __filename = fileURLToPath2(import.meta.url);
|
|
84992
|
-
var __dirname =
|
|
85602
|
+
var __dirname = dirname23(__filename);
|
|
84993
85603
|
function resolveContextPath(baseDir = __dirname) {
|
|
84994
85604
|
const candidates = [
|
|
84995
85605
|
// Bundled package layout: packages/cli/dist/index.js -> packages/cli/CONTEXT.md
|
|
84996
|
-
|
|
85606
|
+
resolve72(baseDir, "../CONTEXT.md"),
|
|
84997
85607
|
// Source/dev layout: packages/cli/src/commands/context.ts -> packages/cli/CONTEXT.md
|
|
84998
|
-
|
|
85608
|
+
resolve72(baseDir, "../../CONTEXT.md")
|
|
84999
85609
|
];
|
|
85000
|
-
return candidates.find((candidate) =>
|
|
85610
|
+
return candidates.find((candidate) => existsSync55(candidate)) ?? null;
|
|
85001
85611
|
}
|
|
85002
85612
|
var contextCommand = new Command("context").description("Print CLI context/guidelines for AI agent integration").option("--format <format>", "Output format: markdown | json", "markdown").action(async (_options, cmd) => {
|
|
85003
85613
|
const options = {
|
|
@@ -86052,7 +86662,7 @@ async function startAgent(options = {}) {
|
|
|
86052
86662
|
console.log();
|
|
86053
86663
|
console.log(source_default.dim(" Commands: exit \xB7 reset \xB7 tools \xB7 context"));
|
|
86054
86664
|
console.log();
|
|
86055
|
-
return new Promise((
|
|
86665
|
+
return new Promise((resolve87) => {
|
|
86056
86666
|
if (typeof process.stdin.ref === "function") {
|
|
86057
86667
|
process.stdin.ref();
|
|
86058
86668
|
}
|
|
@@ -86159,7 +86769,7 @@ async function startAgent(options = {}) {
|
|
|
86159
86769
|
clearInterval(keepalive);
|
|
86160
86770
|
console.log();
|
|
86161
86771
|
console.log(source_default.dim("Goodbye!"));
|
|
86162
|
-
|
|
86772
|
+
resolve87();
|
|
86163
86773
|
});
|
|
86164
86774
|
rl.prompt();
|
|
86165
86775
|
});
|
|
@@ -86433,8 +87043,8 @@ init_source();
|
|
|
86433
87043
|
init_config();
|
|
86434
87044
|
init_schema();
|
|
86435
87045
|
init_api_key();
|
|
86436
|
-
import { access as access9, writeFile as
|
|
86437
|
-
import { dirname as
|
|
87046
|
+
import { access as access9, writeFile as writeFile56, mkdir as mkdir30 } from "node:fs/promises";
|
|
87047
|
+
import { dirname as dirname25 } from "node:path";
|
|
86438
87048
|
var BANNER_SHOWN_PATH = `${USER_CONFIG_DIR}/.banner-shown`;
|
|
86439
87049
|
async function isFirstRun() {
|
|
86440
87050
|
try {
|
|
@@ -86453,8 +87063,8 @@ async function isFirstRun() {
|
|
|
86453
87063
|
}
|
|
86454
87064
|
async function markBannerShown() {
|
|
86455
87065
|
try {
|
|
86456
|
-
await
|
|
86457
|
-
await
|
|
87066
|
+
await mkdir30(dirname25(BANNER_SHOWN_PATH), { recursive: true });
|
|
87067
|
+
await writeFile56(BANNER_SHOWN_PATH, (/* @__PURE__ */ new Date()).toISOString());
|
|
86458
87068
|
} catch {
|
|
86459
87069
|
}
|
|
86460
87070
|
}
|