@vibeframe/cli 0.115.7 → 0.115.8
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/scene-inspect.d.ts +0 -1
- package/dist/commands/_shared/scene-render.d.ts +3 -9
- package/dist/commands/ai-analyze.d.ts +1 -3
- package/dist/commands/ai-helpers.d.ts +0 -8
- package/dist/commands/ai-image.d.ts +0 -6
- package/dist/commands/edit/lottie-overlay.d.ts +76 -0
- package/dist/commands/edit/motion-overlay.d.ts +6 -1
- package/dist/commands/generate.d.ts +0 -2
- package/dist/commands/output.d.ts +0 -3
- package/dist/commands/sanitize.d.ts +0 -5
- package/dist/commands/validate.d.ts +0 -11
- package/dist/config/index.d.ts +0 -9
- package/dist/index.js +1197 -1603
- package/dist/pipeline/executor.d.ts +0 -1
- package/dist/pipeline/renderers/chrome.d.ts +3 -4
- package/dist/tools/manifest/index.js +817 -1221
- package/dist/utils/audio.d.ts +0 -10
- package/dist/utils/input-validation.d.ts +0 -5
- package/dist/utils/remotion.d.ts +0 -14
- package/dist/utils/tty.d.ts +0 -8
- package/package.json +4 -6
- package/dist/pipeline/renderers/html-clips.d.ts +0 -19
- package/dist/pipeline/renderers/html-runtime.d.ts +0 -6
- package/dist/pipeline/renderers/html-template.d.ts +0 -2
- package/dist/pipeline/renderers/hyperframes.d.ts +0 -7
- package/dist/pipeline/renderers/project-builder.d.ts +0 -7
- package/dist/pipeline/renderers/types.d.ts +0 -39
- /package/dist/{pipeline/renderers/__tests__/html-template.test.d.ts → commands/edit/lottie-overlay.integration.test.d.ts} +0 -0
- /package/dist/{pipeline/renderers/__tests__/integration.test.d.ts → commands/edit/lottie-overlay.test.d.ts} +0 -0
|
@@ -469,7 +469,7 @@ function errorMessage(error) {
|
|
|
469
469
|
return error instanceof Error ? error.message : "Unknown error";
|
|
470
470
|
}
|
|
471
471
|
function sleep(ms) {
|
|
472
|
-
return new Promise((
|
|
472
|
+
return new Promise((resolve63) => setTimeout(resolve63, ms));
|
|
473
473
|
}
|
|
474
474
|
async function fetchJson(label, url, init) {
|
|
475
475
|
const response = await fetch(url, init);
|
|
@@ -2042,8 +2042,8 @@ var init_wait = __esm({
|
|
|
2042
2042
|
"use strict";
|
|
2043
2043
|
init_contract3();
|
|
2044
2044
|
init_errors();
|
|
2045
|
-
sleep2 = (ms, signal) => new Promise((
|
|
2046
|
-
const timer = setTimeout(
|
|
2045
|
+
sleep2 = (ms, signal) => new Promise((resolve63, reject) => {
|
|
2046
|
+
const timer = setTimeout(resolve63, ms);
|
|
2047
2047
|
signal?.addEventListener("abort", () => {
|
|
2048
2048
|
clearTimeout(timer);
|
|
2049
2049
|
reject(signal.reason);
|
|
@@ -2522,19 +2522,19 @@ var init_GrokProvider = __esm({
|
|
|
2522
2522
|
message: `Grok ${request.from.kind}s videos with ${CONTINUATION_MODEL} only, not ${model}.`
|
|
2523
2523
|
});
|
|
2524
2524
|
}
|
|
2525
|
-
let
|
|
2525
|
+
let path;
|
|
2526
2526
|
const body = { model, prompt: request.prompt };
|
|
2527
2527
|
if (request.from) {
|
|
2528
2528
|
const source = await this.continuationSource(request.from.job);
|
|
2529
2529
|
body.video = { url: source };
|
|
2530
2530
|
if (request.from.kind === "extend") {
|
|
2531
|
-
|
|
2531
|
+
path = "/videos/extensions";
|
|
2532
2532
|
body.duration = Math.round(Math.min(10, Math.max(2, request.durationSec ?? 6)));
|
|
2533
2533
|
} else {
|
|
2534
|
-
|
|
2534
|
+
path = "/videos/edits";
|
|
2535
2535
|
}
|
|
2536
2536
|
} else {
|
|
2537
|
-
|
|
2537
|
+
path = "/videos/generations";
|
|
2538
2538
|
body.duration = Math.round(Math.min(15, Math.max(1, request.durationSec || 5)));
|
|
2539
2539
|
body.aspect_ratio = request.aspectRatio || "16:9";
|
|
2540
2540
|
body.resolution = GROK_VIDEO_RESOLUTIONS.includes(request.resolution ?? "") ? request.resolution : DEFAULT_VIDEO_RESOLUTION;
|
|
@@ -2543,7 +2543,7 @@ var init_GrokProvider = __esm({
|
|
|
2543
2543
|
if (request.image)
|
|
2544
2544
|
body.image = { url: request.image };
|
|
2545
2545
|
}
|
|
2546
|
-
const response = await providerRequest(this.id, `${this.baseUrl}${
|
|
2546
|
+
const response = await providerRequest(this.id, `${this.baseUrl}${path}`, {
|
|
2547
2547
|
method: "POST",
|
|
2548
2548
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
2549
2549
|
body: JSON.stringify(body)
|
|
@@ -3101,8 +3101,8 @@ var init_ElevenLabsProvider = __esm({
|
|
|
3101
3101
|
}
|
|
3102
3102
|
}
|
|
3103
3103
|
/** An ElevenLabs API call through the shared HTTP layer (retries, classified errors). */
|
|
3104
|
-
request(
|
|
3105
|
-
return providerRequest(this.speechProvider, `${this.baseUrl}${
|
|
3104
|
+
request(path, init) {
|
|
3105
|
+
return providerRequest(this.speechProvider, `${this.baseUrl}${path}`, {
|
|
3106
3106
|
...init,
|
|
3107
3107
|
headers: { "xi-api-key": this.apiKey, ...init.headers }
|
|
3108
3108
|
});
|
|
@@ -3369,11 +3369,11 @@ async function loadKokoroRuntime() {
|
|
|
3369
3369
|
}
|
|
3370
3370
|
async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
3371
3371
|
try {
|
|
3372
|
-
const { readFile:
|
|
3373
|
-
const { join: join30, resolve:
|
|
3372
|
+
const { readFile: readFile45 } = await import("node:fs/promises");
|
|
3373
|
+
const { join: join30, resolve: resolve63 } = await import("node:path");
|
|
3374
3374
|
const { pathToFileURL } = await import("node:url");
|
|
3375
|
-
const pkgDir =
|
|
3376
|
-
const pkg = JSON.parse(await
|
|
3375
|
+
const pkgDir = resolve63(baseDir, "node_modules", "kokoro-js");
|
|
3376
|
+
const pkg = JSON.parse(await readFile45(join30(pkgDir, "package.json"), "utf-8"));
|
|
3377
3377
|
const entry = pkg.exports?.node?.import ?? pkg.exports?.default ?? pkg.module ?? pkg.main;
|
|
3378
3378
|
if (!entry)
|
|
3379
3379
|
return null;
|
|
@@ -3388,12 +3388,12 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
3388
3388
|
if (!base)
|
|
3389
3389
|
return null;
|
|
3390
3390
|
try {
|
|
3391
|
-
const { readFile:
|
|
3392
|
-
const { join: join30, resolve:
|
|
3391
|
+
const { readFile: readFile45, writeFile: writeFile45, mkdir: mkdir27 } = await import("node:fs/promises");
|
|
3392
|
+
const { join: join30, resolve: resolve63 } = await import("node:path");
|
|
3393
3393
|
const { pathToFileURL } = await import("node:url");
|
|
3394
3394
|
const { homedir: homedir5 } = await import("node:os");
|
|
3395
|
-
const transformersDir =
|
|
3396
|
-
const ortDistDir =
|
|
3395
|
+
const transformersDir = resolve63(base, "node_modules", "@huggingface", "transformers");
|
|
3396
|
+
const ortDistDir = resolve63(base, "node_modules", "onnxruntime-web", "dist");
|
|
3397
3397
|
const transformers = await import(pathToFileURL(join30(transformersDir, "dist", "transformers.web.js")).href);
|
|
3398
3398
|
const cacheRoot = join30(homedir5(), ".cache", "vibeframe", "models");
|
|
3399
3399
|
transformers.env.allowLocalModels = false;
|
|
@@ -3401,7 +3401,7 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
3401
3401
|
transformers.env.customCache = {
|
|
3402
3402
|
async match(key) {
|
|
3403
3403
|
try {
|
|
3404
|
-
return new Response(await
|
|
3404
|
+
return new Response(await readFile45(join30(cacheRoot, encodeURIComponent(String(key)))));
|
|
3405
3405
|
} catch {
|
|
3406
3406
|
return void 0;
|
|
3407
3407
|
}
|
|
@@ -3717,11 +3717,11 @@ var require_middleware = __commonJS({
|
|
|
3717
3717
|
"use strict";
|
|
3718
3718
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
3719
3719
|
function adopt(value) {
|
|
3720
|
-
return value instanceof P ? value : new P(function(
|
|
3721
|
-
|
|
3720
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
3721
|
+
resolve63(value);
|
|
3722
3722
|
});
|
|
3723
3723
|
}
|
|
3724
|
-
return new (P || (P = Promise))(function(
|
|
3724
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
3725
3725
|
function fulfilled(value) {
|
|
3726
3726
|
try {
|
|
3727
3727
|
step(generator.next(value));
|
|
@@ -3737,7 +3737,7 @@ var require_middleware = __commonJS({
|
|
|
3737
3737
|
}
|
|
3738
3738
|
}
|
|
3739
3739
|
function step(result) {
|
|
3740
|
-
result.done ?
|
|
3740
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
3741
3741
|
}
|
|
3742
3742
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
3743
3743
|
});
|
|
@@ -3822,11 +3822,11 @@ var require_response = __commonJS({
|
|
|
3822
3822
|
"use strict";
|
|
3823
3823
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
3824
3824
|
function adopt(value) {
|
|
3825
|
-
return value instanceof P ? value : new P(function(
|
|
3826
|
-
|
|
3825
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
3826
|
+
resolve63(value);
|
|
3827
3827
|
});
|
|
3828
3828
|
}
|
|
3829
|
-
return new (P || (P = Promise))(function(
|
|
3829
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
3830
3830
|
function fulfilled(value) {
|
|
3831
3831
|
try {
|
|
3832
3832
|
step(generator.next(value));
|
|
@@ -3842,7 +3842,7 @@ var require_response = __commonJS({
|
|
|
3842
3842
|
}
|
|
3843
3843
|
}
|
|
3844
3844
|
function step(result) {
|
|
3845
|
-
result.done ?
|
|
3845
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
3846
3846
|
}
|
|
3847
3847
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
3848
3848
|
});
|
|
@@ -3949,11 +3949,11 @@ var require_utils = __commonJS({
|
|
|
3949
3949
|
"use strict";
|
|
3950
3950
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
3951
3951
|
function adopt(value) {
|
|
3952
|
-
return value instanceof P ? value : new P(function(
|
|
3953
|
-
|
|
3952
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
3953
|
+
resolve63(value);
|
|
3954
3954
|
});
|
|
3955
3955
|
}
|
|
3956
|
-
return new (P || (P = Promise))(function(
|
|
3956
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
3957
3957
|
function fulfilled(value) {
|
|
3958
3958
|
try {
|
|
3959
3959
|
step(generator.next(value));
|
|
@@ -3969,7 +3969,7 @@ var require_utils = __commonJS({
|
|
|
3969
3969
|
}
|
|
3970
3970
|
}
|
|
3971
3971
|
function step(result) {
|
|
3972
|
-
result.done ?
|
|
3972
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
3973
3973
|
}
|
|
3974
3974
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
3975
3975
|
});
|
|
@@ -4012,9 +4012,9 @@ var require_utils = __commonJS({
|
|
|
4012
4012
|
path: parts.slice(2).join("/") || void 0
|
|
4013
4013
|
};
|
|
4014
4014
|
}
|
|
4015
|
-
function resolveEndpointPath(app,
|
|
4016
|
-
if (
|
|
4017
|
-
return `/${
|
|
4015
|
+
function resolveEndpointPath(app, path, defaultPath) {
|
|
4016
|
+
if (path) {
|
|
4017
|
+
return `/${path.replace(/^\/+/, "")}`;
|
|
4018
4018
|
}
|
|
4019
4019
|
if (app.endsWith(defaultPath)) {
|
|
4020
4020
|
return void 0;
|
|
@@ -4062,7 +4062,7 @@ var require_utils = __commonJS({
|
|
|
4062
4062
|
}
|
|
4063
4063
|
function sleep4(ms) {
|
|
4064
4064
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4065
|
-
return new Promise((
|
|
4065
|
+
return new Promise((resolve63) => setTimeout(resolve63, ms));
|
|
4066
4066
|
});
|
|
4067
4067
|
}
|
|
4068
4068
|
}
|
|
@@ -4074,11 +4074,11 @@ var require_retry = __commonJS({
|
|
|
4074
4074
|
"use strict";
|
|
4075
4075
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
4076
4076
|
function adopt(value) {
|
|
4077
|
-
return value instanceof P ? value : new P(function(
|
|
4078
|
-
|
|
4077
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
4078
|
+
resolve63(value);
|
|
4079
4079
|
});
|
|
4080
4080
|
}
|
|
4081
|
-
return new (P || (P = Promise))(function(
|
|
4081
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
4082
4082
|
function fulfilled(value) {
|
|
4083
4083
|
try {
|
|
4084
4084
|
step(generator.next(value));
|
|
@@ -4094,7 +4094,7 @@ var require_retry = __commonJS({
|
|
|
4094
4094
|
}
|
|
4095
4095
|
}
|
|
4096
4096
|
function step(result) {
|
|
4097
|
-
result.done ?
|
|
4097
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
4098
4098
|
}
|
|
4099
4099
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
4100
4100
|
});
|
|
@@ -4301,11 +4301,11 @@ var require_request = __commonJS({
|
|
|
4301
4301
|
"use strict";
|
|
4302
4302
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
4303
4303
|
function adopt(value) {
|
|
4304
|
-
return value instanceof P ? value : new P(function(
|
|
4305
|
-
|
|
4304
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
4305
|
+
resolve63(value);
|
|
4306
4306
|
});
|
|
4307
4307
|
}
|
|
4308
|
-
return new (P || (P = Promise))(function(
|
|
4308
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
4309
4309
|
function fulfilled(value) {
|
|
4310
4310
|
try {
|
|
4311
4311
|
step(generator.next(value));
|
|
@@ -4321,7 +4321,7 @@ var require_request = __commonJS({
|
|
|
4321
4321
|
}
|
|
4322
4322
|
}
|
|
4323
4323
|
function step(result) {
|
|
4324
|
-
result.done ?
|
|
4324
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
4325
4325
|
}
|
|
4326
4326
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
4327
4327
|
});
|
|
@@ -4386,17 +4386,17 @@ var require_request = __commonJS({
|
|
|
4386
4386
|
function buildUrl(id, options = {}) {
|
|
4387
4387
|
var _a, _b;
|
|
4388
4388
|
const method = ((_a = options.method) !== null && _a !== void 0 ? _a : "post").toLowerCase();
|
|
4389
|
-
const
|
|
4389
|
+
const path = ((_b = options.path) !== null && _b !== void 0 ? _b : "").replace(/^\//, "").replace(/\/{2,}/, "/");
|
|
4390
4390
|
const input = options.input;
|
|
4391
4391
|
const params = Object.assign(Object.assign({}, options.query || {}), method === "get" ? input : {});
|
|
4392
4392
|
const queryParams = Object.keys(params).length > 0 ? `?${new URLSearchParams(params).toString()}` : "";
|
|
4393
4393
|
if ((0, utils_1.isValidUrl)(id)) {
|
|
4394
4394
|
const url2 = id.endsWith("/") ? id : `${id}/`;
|
|
4395
|
-
return `${url2}${
|
|
4395
|
+
return `${url2}${path}${queryParams}`;
|
|
4396
4396
|
}
|
|
4397
4397
|
const appId = (0, utils_1.ensureEndpointIdFormat)(id);
|
|
4398
4398
|
const subdomain = options.subdomain ? `${options.subdomain}.` : "";
|
|
4399
|
-
const url = `https://${subdomain}fal.run/${appId}/${
|
|
4399
|
+
const url = `https://${subdomain}fal.run/${appId}/${path}`;
|
|
4400
4400
|
return `${url.replace(/\/$/, "")}${queryParams}`;
|
|
4401
4401
|
}
|
|
4402
4402
|
}
|
|
@@ -4408,11 +4408,11 @@ var require_storage = __commonJS({
|
|
|
4408
4408
|
"use strict";
|
|
4409
4409
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
4410
4410
|
function adopt(value) {
|
|
4411
|
-
return value instanceof P ? value : new P(function(
|
|
4412
|
-
|
|
4411
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
4412
|
+
resolve63(value);
|
|
4413
4413
|
});
|
|
4414
4414
|
}
|
|
4415
|
-
return new (P || (P = Promise))(function(
|
|
4415
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
4416
4416
|
function fulfilled(value) {
|
|
4417
4417
|
try {
|
|
4418
4418
|
step(generator.next(value));
|
|
@@ -4428,7 +4428,7 @@ var require_storage = __commonJS({
|
|
|
4428
4428
|
}
|
|
4429
4429
|
}
|
|
4430
4430
|
function step(result) {
|
|
4431
|
-
result.done ?
|
|
4431
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
4432
4432
|
}
|
|
4433
4433
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
4434
4434
|
});
|
|
@@ -4756,11 +4756,11 @@ var require_auth = __commonJS({
|
|
|
4756
4756
|
"use strict";
|
|
4757
4757
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
4758
4758
|
function adopt(value) {
|
|
4759
|
-
return value instanceof P ? value : new P(function(
|
|
4760
|
-
|
|
4759
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
4760
|
+
resolve63(value);
|
|
4761
4761
|
});
|
|
4762
4762
|
}
|
|
4763
|
-
return new (P || (P = Promise))(function(
|
|
4763
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
4764
4764
|
function fulfilled(value) {
|
|
4765
4765
|
try {
|
|
4766
4766
|
step(generator.next(value));
|
|
@@ -4776,7 +4776,7 @@ var require_auth = __commonJS({
|
|
|
4776
4776
|
}
|
|
4777
4777
|
}
|
|
4778
4778
|
function step(result) {
|
|
4779
|
-
result.done ?
|
|
4779
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
4780
4780
|
}
|
|
4781
4781
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
4782
4782
|
});
|
|
@@ -4815,11 +4815,11 @@ var require_streaming = __commonJS({
|
|
|
4815
4815
|
"use strict";
|
|
4816
4816
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
4817
4817
|
function adopt(value) {
|
|
4818
|
-
return value instanceof P ? value : new P(function(
|
|
4819
|
-
|
|
4818
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
4819
|
+
resolve63(value);
|
|
4820
4820
|
});
|
|
4821
4821
|
}
|
|
4822
|
-
return new (P || (P = Promise))(function(
|
|
4822
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
4823
4823
|
function fulfilled(value) {
|
|
4824
4824
|
try {
|
|
4825
4825
|
step(generator.next(value));
|
|
@@ -4835,7 +4835,7 @@ var require_streaming = __commonJS({
|
|
|
4835
4835
|
}
|
|
4836
4836
|
}
|
|
4837
4837
|
function step(result) {
|
|
4838
|
-
result.done ?
|
|
4838
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
4839
4839
|
}
|
|
4840
4840
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
4841
4841
|
});
|
|
@@ -5068,7 +5068,7 @@ var require_streaming = __commonJS({
|
|
|
5068
5068
|
query: options.queryParams
|
|
5069
5069
|
});
|
|
5070
5070
|
this.options = options;
|
|
5071
|
-
this.donePromise = new Promise((
|
|
5071
|
+
this.donePromise = new Promise((resolve63, reject) => {
|
|
5072
5072
|
if (this.streamClosed) {
|
|
5073
5073
|
reject(new response_1.ApiError({
|
|
5074
5074
|
message: "Streaming connection is already closed.",
|
|
@@ -5079,11 +5079,11 @@ var require_streaming = __commonJS({
|
|
|
5079
5079
|
}
|
|
5080
5080
|
this.signal.addEventListener("abort", () => {
|
|
5081
5081
|
var _a2;
|
|
5082
|
-
|
|
5082
|
+
resolve63((_a2 = this.currentData) !== null && _a2 !== void 0 ? _a2 : {});
|
|
5083
5083
|
});
|
|
5084
5084
|
this.on("done", (data) => {
|
|
5085
5085
|
this.streamClosed = true;
|
|
5086
|
-
|
|
5086
|
+
resolve63(data);
|
|
5087
5087
|
});
|
|
5088
5088
|
this.on("error", (error) => {
|
|
5089
5089
|
this.streamClosed = true;
|
|
@@ -5108,7 +5108,7 @@ var require_streaming = __commonJS({
|
|
|
5108
5108
|
if (data) {
|
|
5109
5109
|
yield yield __await(data);
|
|
5110
5110
|
}
|
|
5111
|
-
yield __await(new Promise((
|
|
5111
|
+
yield __await(new Promise((resolve63) => setTimeout(resolve63, 16)));
|
|
5112
5112
|
}
|
|
5113
5113
|
});
|
|
5114
5114
|
}
|
|
@@ -5153,11 +5153,11 @@ var require_queue = __commonJS({
|
|
|
5153
5153
|
"use strict";
|
|
5154
5154
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
5155
5155
|
function adopt(value) {
|
|
5156
|
-
return value instanceof P ? value : new P(function(
|
|
5157
|
-
|
|
5156
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
5157
|
+
resolve63(value);
|
|
5158
5158
|
});
|
|
5159
5159
|
}
|
|
5160
|
-
return new (P || (P = Promise))(function(
|
|
5160
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
5161
5161
|
function fulfilled(value) {
|
|
5162
5162
|
try {
|
|
5163
5163
|
step(generator.next(value));
|
|
@@ -5173,7 +5173,7 @@ var require_queue = __commonJS({
|
|
|
5173
5173
|
}
|
|
5174
5174
|
}
|
|
5175
5175
|
function step(result) {
|
|
5176
|
-
result.done ?
|
|
5176
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
5177
5177
|
}
|
|
5178
5178
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
5179
5179
|
});
|
|
@@ -5308,7 +5308,7 @@ var require_queue = __commonJS({
|
|
|
5308
5308
|
}
|
|
5309
5309
|
return doneStatus;
|
|
5310
5310
|
}
|
|
5311
|
-
return new Promise((
|
|
5311
|
+
return new Promise((resolve63, reject) => {
|
|
5312
5312
|
var _a;
|
|
5313
5313
|
let pollingTimeoutId;
|
|
5314
5314
|
const pollInterval = "pollInterval" in options && typeof options.pollInterval === "number" ? (_a = options.pollInterval) !== null && _a !== void 0 ? _a : DEFAULT_POLL_INTERVAL : DEFAULT_POLL_INTERVAL;
|
|
@@ -5340,7 +5340,7 @@ var require_queue = __commonJS({
|
|
|
5340
5340
|
}
|
|
5341
5341
|
if (requestStatus.status === "COMPLETED") {
|
|
5342
5342
|
clearScheduledTasks();
|
|
5343
|
-
|
|
5343
|
+
resolve63(requestStatus);
|
|
5344
5344
|
return;
|
|
5345
5345
|
}
|
|
5346
5346
|
pollingTimeoutId = setTimeout(poll, pollInterval);
|
|
@@ -7301,11 +7301,11 @@ var require_realtime = __commonJS({
|
|
|
7301
7301
|
"use strict";
|
|
7302
7302
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
7303
7303
|
function adopt(value) {
|
|
7304
|
-
return value instanceof P ? value : new P(function(
|
|
7305
|
-
|
|
7304
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
7305
|
+
resolve63(value);
|
|
7306
7306
|
});
|
|
7307
7307
|
}
|
|
7308
|
-
return new (P || (P = Promise))(function(
|
|
7308
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
7309
7309
|
function fulfilled(value) {
|
|
7310
7310
|
try {
|
|
7311
7311
|
step(generator.next(value));
|
|
@@ -7321,7 +7321,7 @@ var require_realtime = __commonJS({
|
|
|
7321
7321
|
}
|
|
7322
7322
|
}
|
|
7323
7323
|
function step(result) {
|
|
7324
|
-
result.done ?
|
|
7324
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
7325
7325
|
}
|
|
7326
7326
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
7327
7327
|
});
|
|
@@ -7381,7 +7381,7 @@ var require_realtime = __commonJS({
|
|
|
7381
7381
|
authInProgress: (0, robot3_1.state)((0, robot3_1.transition)("authenticated", "connecting", (0, robot3_1.reduce)(setToken)), (0, robot3_1.transition)("unauthorized", "idle", (0, robot3_1.reduce)(expireToken), (0, robot3_1.reduce)(closeConnection)), (0, robot3_1.transition)("send", "authInProgress", (0, robot3_1.reduce)(enqueueMessage)), (0, robot3_1.transition)("close", "idle", (0, robot3_1.reduce)(closeConnection))),
|
|
7382
7382
|
active: (0, robot3_1.state)((0, robot3_1.transition)("send", "active", (0, robot3_1.reduce)(sendMessage)), (0, robot3_1.transition)("authenticated", "active", (0, robot3_1.reduce)(setToken)), (0, robot3_1.transition)("unauthorized", "idle", (0, robot3_1.reduce)(expireToken)), (0, robot3_1.transition)("connectionClosed", "idle", (0, robot3_1.reduce)(expireToken), (0, robot3_1.reduce)(closeConnection)), (0, robot3_1.transition)("close", "idle", (0, robot3_1.reduce)(expireToken), (0, robot3_1.reduce)(closeConnection)))
|
|
7383
7383
|
}, initialState);
|
|
7384
|
-
function buildRealtimeUrl(app, { token, maxBuffering, path
|
|
7384
|
+
function buildRealtimeUrl(app, { token, maxBuffering, path }) {
|
|
7385
7385
|
var _a;
|
|
7386
7386
|
if (maxBuffering !== void 0 && (maxBuffering < 1 || maxBuffering > 60)) {
|
|
7387
7387
|
throw new Error("The `maxBuffering` must be between 1 and 60 (inclusive)");
|
|
@@ -7393,7 +7393,7 @@ var require_realtime = __commonJS({
|
|
|
7393
7393
|
queryParams.set("max_buffering", maxBuffering.toFixed(0));
|
|
7394
7394
|
}
|
|
7395
7395
|
const appId = (0, utils_1.ensureEndpointIdFormat)(app);
|
|
7396
|
-
const resolvedPath = (_a = (0, utils_1.resolveEndpointPath)(app,
|
|
7396
|
+
const resolvedPath = (_a = (0, utils_1.resolveEndpointPath)(app, path, "/realtime")) !== null && _a !== void 0 ? _a : "";
|
|
7397
7397
|
return `wss://fal.run/${appId}${resolvedPath}?${queryParams.toString()}`;
|
|
7398
7398
|
}
|
|
7399
7399
|
var DEFAULT_THROTTLE_INTERVAL = 128;
|
|
@@ -7502,7 +7502,7 @@ var require_realtime = __commonJS({
|
|
|
7502
7502
|
clientOnly = (0, utils_1.isReact)() && !(0, runtime_1.isBrowser)(),
|
|
7503
7503
|
connectionKey = crypto.randomUUID(),
|
|
7504
7504
|
maxBuffering,
|
|
7505
|
-
path
|
|
7505
|
+
path,
|
|
7506
7506
|
throttleInterval = DEFAULT_THROTTLE_INTERVAL,
|
|
7507
7507
|
encodeMessage: encodeMessageOverride,
|
|
7508
7508
|
decodeMessage: decodeMessageOverride,
|
|
@@ -7536,7 +7536,7 @@ var require_realtime = __commonJS({
|
|
|
7536
7536
|
tokenRefreshGeneration++;
|
|
7537
7537
|
const generation = tokenRefreshGeneration;
|
|
7538
7538
|
const appId = (0, utils_1.ensureEndpointIdFormat)(app);
|
|
7539
|
-
const resolvedPath = (_a = (0, utils_1.resolveEndpointPath)(app,
|
|
7539
|
+
const resolvedPath = (_a = (0, utils_1.resolveEndpointPath)(app, path, "/realtime")) !== null && _a !== void 0 ? _a : "";
|
|
7540
7540
|
const fetchToken = tokenProvider ? () => tokenProvider(`${appId}${resolvedPath}`) : () => {
|
|
7541
7541
|
console.warn("[fal.realtime] Using the default token provider is deprecated. Please provide a `tokenProvider` function to `fal.realtime.connect()`. See https://docs.fal.ai/model-apis/client#client-side-usage-with-token-provider for more information.");
|
|
7542
7542
|
return (0, auth_1.getTemporaryAuthToken)(app, config2);
|
|
@@ -7580,7 +7580,7 @@ var require_realtime = __commonJS({
|
|
|
7580
7580
|
});
|
|
7581
7581
|
}
|
|
7582
7582
|
if (machine.current === "connecting" && previousState !== machine.current && token !== void 0) {
|
|
7583
|
-
const ws = new WebSocket(buildRealtimeUrl(app, { token, maxBuffering, path
|
|
7583
|
+
const ws = new WebSocket(buildRealtimeUrl(app, { token, maxBuffering, path }));
|
|
7584
7584
|
ws.onopen = () => {
|
|
7585
7585
|
var _a2, _b;
|
|
7586
7586
|
send2({ type: "connected", websocket: ws });
|
|
@@ -7646,11 +7646,11 @@ var require_client = __commonJS({
|
|
|
7646
7646
|
"use strict";
|
|
7647
7647
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
7648
7648
|
function adopt(value) {
|
|
7649
|
-
return value instanceof P ? value : new P(function(
|
|
7650
|
-
|
|
7649
|
+
return value instanceof P ? value : new P(function(resolve63) {
|
|
7650
|
+
resolve63(value);
|
|
7651
7651
|
});
|
|
7652
7652
|
}
|
|
7653
|
-
return new (P || (P = Promise))(function(
|
|
7653
|
+
return new (P || (P = Promise))(function(resolve63, reject) {
|
|
7654
7654
|
function fulfilled(value) {
|
|
7655
7655
|
try {
|
|
7656
7656
|
step(generator.next(value));
|
|
@@ -7666,7 +7666,7 @@ var require_client = __commonJS({
|
|
|
7666
7666
|
}
|
|
7667
7667
|
}
|
|
7668
7668
|
function step(result) {
|
|
7669
|
-
result.done ?
|
|
7669
|
+
result.done ? resolve63(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
7670
7670
|
}
|
|
7671
7671
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
7672
7672
|
});
|
|
@@ -7868,8 +7868,8 @@ function falErrorDetails(error) {
|
|
|
7868
7868
|
items.push(`request ${withBody.requestId}`);
|
|
7869
7869
|
if (Array.isArray(withBody.fieldErrors) && withBody.fieldErrors.length > 0) {
|
|
7870
7870
|
items.push(withBody.fieldErrors.map((fieldError) => {
|
|
7871
|
-
const
|
|
7872
|
-
return `${
|
|
7871
|
+
const path = Array.isArray(fieldError.loc) ? fieldError.loc.join(".") : "body";
|
|
7872
|
+
return `${path}: ${fieldError.msg ?? fieldError.type ?? "invalid"}`;
|
|
7873
7873
|
}).join("; "));
|
|
7874
7874
|
} else if (withBody.body !== void 0) {
|
|
7875
7875
|
items.push(safeJson(withBody.body));
|
|
@@ -8458,8 +8458,8 @@ var init_KlingProvider = __esm({
|
|
|
8458
8458
|
requestOptions() {
|
|
8459
8459
|
return { classify: ({ code }) => klingErrorKind(code) };
|
|
8460
8460
|
}
|
|
8461
|
-
async post(
|
|
8462
|
-
const response = await providerRequest(this.id, `${this.baseUrl}${
|
|
8461
|
+
async post(path, body, token) {
|
|
8462
|
+
const response = await providerRequest(this.id, `${this.baseUrl}${path}`, {
|
|
8463
8463
|
method: "POST",
|
|
8464
8464
|
headers: this.headers(token),
|
|
8465
8465
|
body: JSON.stringify(body)
|
|
@@ -11576,7 +11576,7 @@ var init_ReplicateProvider = __esm({
|
|
|
11576
11576
|
* Sleep helper
|
|
11577
11577
|
*/
|
|
11578
11578
|
sleep(ms) {
|
|
11579
|
-
return new Promise((
|
|
11579
|
+
return new Promise((resolve63) => setTimeout(resolve63, ms));
|
|
11580
11580
|
}
|
|
11581
11581
|
/**
|
|
11582
11582
|
* Generate music from text prompt using MusicGen
|
|
@@ -12119,7 +12119,7 @@ var require_package2 = __commonJS({
|
|
|
12119
12119
|
var require_main = __commonJS({
|
|
12120
12120
|
"../../node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/lib/main.js"(exports, module) {
|
|
12121
12121
|
var fs = __require("fs");
|
|
12122
|
-
var
|
|
12122
|
+
var path = __require("path");
|
|
12123
12123
|
var os2 = __require("os");
|
|
12124
12124
|
var crypto2 = __require("crypto");
|
|
12125
12125
|
var packageJson = require_package2();
|
|
@@ -12268,7 +12268,7 @@ var require_main = __commonJS({
|
|
|
12268
12268
|
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
12269
12269
|
}
|
|
12270
12270
|
} else {
|
|
12271
|
-
possibleVaultPath =
|
|
12271
|
+
possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
|
|
12272
12272
|
}
|
|
12273
12273
|
if (fs.existsSync(possibleVaultPath)) {
|
|
12274
12274
|
return possibleVaultPath;
|
|
@@ -12276,7 +12276,7 @@ var require_main = __commonJS({
|
|
|
12276
12276
|
return null;
|
|
12277
12277
|
}
|
|
12278
12278
|
function _resolveHome(envPath) {
|
|
12279
|
-
return envPath[0] === "~" ?
|
|
12279
|
+
return envPath[0] === "~" ? path.join(os2.homedir(), envPath.slice(1)) : envPath;
|
|
12280
12280
|
}
|
|
12281
12281
|
function _configVault(options) {
|
|
12282
12282
|
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
@@ -12293,7 +12293,7 @@ var require_main = __commonJS({
|
|
|
12293
12293
|
return { parsed };
|
|
12294
12294
|
}
|
|
12295
12295
|
function configDotenv(options) {
|
|
12296
|
-
const dotenvPath =
|
|
12296
|
+
const dotenvPath = path.resolve(process.cwd(), ".env");
|
|
12297
12297
|
let encoding = "utf8";
|
|
12298
12298
|
let processEnv = process.env;
|
|
12299
12299
|
if (options && options.processEnv != null) {
|
|
@@ -12321,13 +12321,13 @@ var require_main = __commonJS({
|
|
|
12321
12321
|
}
|
|
12322
12322
|
let lastError;
|
|
12323
12323
|
const parsedAll = {};
|
|
12324
|
-
for (const
|
|
12324
|
+
for (const path2 of optionPaths) {
|
|
12325
12325
|
try {
|
|
12326
|
-
const parsed = DotenvModule.parse(fs.readFileSync(
|
|
12326
|
+
const parsed = DotenvModule.parse(fs.readFileSync(path2, { encoding }));
|
|
12327
12327
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
12328
12328
|
} catch (e) {
|
|
12329
12329
|
if (debug) {
|
|
12330
|
-
_debug(`Failed to load ${
|
|
12330
|
+
_debug(`Failed to load ${path2} ${e.message}`);
|
|
12331
12331
|
}
|
|
12332
12332
|
lastError = e;
|
|
12333
12333
|
}
|
|
@@ -12340,8 +12340,8 @@ var require_main = __commonJS({
|
|
|
12340
12340
|
const shortPaths = [];
|
|
12341
12341
|
for (const filePath of optionPaths) {
|
|
12342
12342
|
try {
|
|
12343
|
-
const
|
|
12344
|
-
shortPaths.push(
|
|
12343
|
+
const relative11 = path.relative(process.cwd(), filePath);
|
|
12344
|
+
shortPaths.push(relative11);
|
|
12345
12345
|
} catch (e) {
|
|
12346
12346
|
if (debug) {
|
|
12347
12347
|
_debug(`Failed to load ${filePath} ${e.message}`);
|
|
@@ -13037,17 +13037,17 @@ var require_visit = __commonJS({
|
|
|
13037
13037
|
visit.BREAK = BREAK;
|
|
13038
13038
|
visit.SKIP = SKIP;
|
|
13039
13039
|
visit.REMOVE = REMOVE;
|
|
13040
|
-
function visit_(key, node, visitor,
|
|
13041
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
13040
|
+
function visit_(key, node, visitor, path) {
|
|
13041
|
+
const ctrl = callVisitor(key, node, visitor, path);
|
|
13042
13042
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
13043
|
-
replaceNode(key,
|
|
13044
|
-
return visit_(key, ctrl, visitor,
|
|
13043
|
+
replaceNode(key, path, ctrl);
|
|
13044
|
+
return visit_(key, ctrl, visitor, path);
|
|
13045
13045
|
}
|
|
13046
13046
|
if (typeof ctrl !== "symbol") {
|
|
13047
13047
|
if (identity.isCollection(node)) {
|
|
13048
|
-
|
|
13048
|
+
path = Object.freeze(path.concat(node));
|
|
13049
13049
|
for (let i = 0; i < node.items.length; ++i) {
|
|
13050
|
-
const ci = visit_(i, node.items[i], visitor,
|
|
13050
|
+
const ci = visit_(i, node.items[i], visitor, path);
|
|
13051
13051
|
if (typeof ci === "number")
|
|
13052
13052
|
i = ci - 1;
|
|
13053
13053
|
else if (ci === BREAK)
|
|
@@ -13058,13 +13058,13 @@ var require_visit = __commonJS({
|
|
|
13058
13058
|
}
|
|
13059
13059
|
}
|
|
13060
13060
|
} else if (identity.isPair(node)) {
|
|
13061
|
-
|
|
13062
|
-
const ck = visit_("key", node.key, visitor,
|
|
13061
|
+
path = Object.freeze(path.concat(node));
|
|
13062
|
+
const ck = visit_("key", node.key, visitor, path);
|
|
13063
13063
|
if (ck === BREAK)
|
|
13064
13064
|
return BREAK;
|
|
13065
13065
|
else if (ck === REMOVE)
|
|
13066
13066
|
node.key = null;
|
|
13067
|
-
const cv = visit_("value", node.value, visitor,
|
|
13067
|
+
const cv = visit_("value", node.value, visitor, path);
|
|
13068
13068
|
if (cv === BREAK)
|
|
13069
13069
|
return BREAK;
|
|
13070
13070
|
else if (cv === REMOVE)
|
|
@@ -13085,17 +13085,17 @@ var require_visit = __commonJS({
|
|
|
13085
13085
|
visitAsync.BREAK = BREAK;
|
|
13086
13086
|
visitAsync.SKIP = SKIP;
|
|
13087
13087
|
visitAsync.REMOVE = REMOVE;
|
|
13088
|
-
async function visitAsync_(key, node, visitor,
|
|
13089
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
13088
|
+
async function visitAsync_(key, node, visitor, path) {
|
|
13089
|
+
const ctrl = await callVisitor(key, node, visitor, path);
|
|
13090
13090
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
13091
|
-
replaceNode(key,
|
|
13092
|
-
return visitAsync_(key, ctrl, visitor,
|
|
13091
|
+
replaceNode(key, path, ctrl);
|
|
13092
|
+
return visitAsync_(key, ctrl, visitor, path);
|
|
13093
13093
|
}
|
|
13094
13094
|
if (typeof ctrl !== "symbol") {
|
|
13095
13095
|
if (identity.isCollection(node)) {
|
|
13096
|
-
|
|
13096
|
+
path = Object.freeze(path.concat(node));
|
|
13097
13097
|
for (let i = 0; i < node.items.length; ++i) {
|
|
13098
|
-
const ci = await visitAsync_(i, node.items[i], visitor,
|
|
13098
|
+
const ci = await visitAsync_(i, node.items[i], visitor, path);
|
|
13099
13099
|
if (typeof ci === "number")
|
|
13100
13100
|
i = ci - 1;
|
|
13101
13101
|
else if (ci === BREAK)
|
|
@@ -13106,13 +13106,13 @@ var require_visit = __commonJS({
|
|
|
13106
13106
|
}
|
|
13107
13107
|
}
|
|
13108
13108
|
} else if (identity.isPair(node)) {
|
|
13109
|
-
|
|
13110
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
13109
|
+
path = Object.freeze(path.concat(node));
|
|
13110
|
+
const ck = await visitAsync_("key", node.key, visitor, path);
|
|
13111
13111
|
if (ck === BREAK)
|
|
13112
13112
|
return BREAK;
|
|
13113
13113
|
else if (ck === REMOVE)
|
|
13114
13114
|
node.key = null;
|
|
13115
|
-
const cv = await visitAsync_("value", node.value, visitor,
|
|
13115
|
+
const cv = await visitAsync_("value", node.value, visitor, path);
|
|
13116
13116
|
if (cv === BREAK)
|
|
13117
13117
|
return BREAK;
|
|
13118
13118
|
else if (cv === REMOVE)
|
|
@@ -13139,23 +13139,23 @@ var require_visit = __commonJS({
|
|
|
13139
13139
|
}
|
|
13140
13140
|
return visitor;
|
|
13141
13141
|
}
|
|
13142
|
-
function callVisitor(key, node, visitor,
|
|
13142
|
+
function callVisitor(key, node, visitor, path) {
|
|
13143
13143
|
if (typeof visitor === "function")
|
|
13144
|
-
return visitor(key, node,
|
|
13144
|
+
return visitor(key, node, path);
|
|
13145
13145
|
if (identity.isMap(node))
|
|
13146
|
-
return visitor.Map?.(key, node,
|
|
13146
|
+
return visitor.Map?.(key, node, path);
|
|
13147
13147
|
if (identity.isSeq(node))
|
|
13148
|
-
return visitor.Seq?.(key, node,
|
|
13148
|
+
return visitor.Seq?.(key, node, path);
|
|
13149
13149
|
if (identity.isPair(node))
|
|
13150
|
-
return visitor.Pair?.(key, node,
|
|
13150
|
+
return visitor.Pair?.(key, node, path);
|
|
13151
13151
|
if (identity.isScalar(node))
|
|
13152
|
-
return visitor.Scalar?.(key, node,
|
|
13152
|
+
return visitor.Scalar?.(key, node, path);
|
|
13153
13153
|
if (identity.isAlias(node))
|
|
13154
|
-
return visitor.Alias?.(key, node,
|
|
13154
|
+
return visitor.Alias?.(key, node, path);
|
|
13155
13155
|
return void 0;
|
|
13156
13156
|
}
|
|
13157
|
-
function replaceNode(key,
|
|
13158
|
-
const parent =
|
|
13157
|
+
function replaceNode(key, path, node) {
|
|
13158
|
+
const parent = path[path.length - 1];
|
|
13159
13159
|
if (identity.isCollection(parent)) {
|
|
13160
13160
|
parent.items[key] = node;
|
|
13161
13161
|
} else if (identity.isPair(parent)) {
|
|
@@ -13763,10 +13763,10 @@ var require_Collection = __commonJS({
|
|
|
13763
13763
|
var createNode = require_createNode();
|
|
13764
13764
|
var identity = require_identity();
|
|
13765
13765
|
var Node = require_Node();
|
|
13766
|
-
function collectionFromPath(schema,
|
|
13766
|
+
function collectionFromPath(schema, path, value) {
|
|
13767
13767
|
let v = value;
|
|
13768
|
-
for (let i =
|
|
13769
|
-
const k =
|
|
13768
|
+
for (let i = path.length - 1; i >= 0; --i) {
|
|
13769
|
+
const k = path[i];
|
|
13770
13770
|
if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
|
|
13771
13771
|
const a = [];
|
|
13772
13772
|
a[k] = v;
|
|
@@ -13785,7 +13785,7 @@ var require_Collection = __commonJS({
|
|
|
13785
13785
|
sourceObjects: /* @__PURE__ */ new Map()
|
|
13786
13786
|
});
|
|
13787
13787
|
}
|
|
13788
|
-
var isEmptyPath = (
|
|
13788
|
+
var isEmptyPath = (path) => path == null || typeof path === "object" && !!path[Symbol.iterator]().next().done;
|
|
13789
13789
|
var Collection = class extends Node.NodeBase {
|
|
13790
13790
|
constructor(type, schema) {
|
|
13791
13791
|
super(type);
|
|
@@ -13815,11 +13815,11 @@ var require_Collection = __commonJS({
|
|
|
13815
13815
|
* be a Pair instance or a `{ key, value }` object, which may not have a key
|
|
13816
13816
|
* that already exists in the map.
|
|
13817
13817
|
*/
|
|
13818
|
-
addIn(
|
|
13819
|
-
if (isEmptyPath(
|
|
13818
|
+
addIn(path, value) {
|
|
13819
|
+
if (isEmptyPath(path))
|
|
13820
13820
|
this.add(value);
|
|
13821
13821
|
else {
|
|
13822
|
-
const [key, ...rest] =
|
|
13822
|
+
const [key, ...rest] = path;
|
|
13823
13823
|
const node = this.get(key, true);
|
|
13824
13824
|
if (identity.isCollection(node))
|
|
13825
13825
|
node.addIn(rest, value);
|
|
@@ -13833,8 +13833,8 @@ var require_Collection = __commonJS({
|
|
|
13833
13833
|
* Removes a value from the collection.
|
|
13834
13834
|
* @returns `true` if the item was found and removed.
|
|
13835
13835
|
*/
|
|
13836
|
-
deleteIn(
|
|
13837
|
-
const [key, ...rest] =
|
|
13836
|
+
deleteIn(path) {
|
|
13837
|
+
const [key, ...rest] = path;
|
|
13838
13838
|
if (rest.length === 0)
|
|
13839
13839
|
return this.delete(key);
|
|
13840
13840
|
const node = this.get(key, true);
|
|
@@ -13848,8 +13848,8 @@ var require_Collection = __commonJS({
|
|
|
13848
13848
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
13849
13849
|
* `true` (collections are always returned intact).
|
|
13850
13850
|
*/
|
|
13851
|
-
getIn(
|
|
13852
|
-
const [key, ...rest] =
|
|
13851
|
+
getIn(path, keepScalar) {
|
|
13852
|
+
const [key, ...rest] = path;
|
|
13853
13853
|
const node = this.get(key, true);
|
|
13854
13854
|
if (rest.length === 0)
|
|
13855
13855
|
return !keepScalar && identity.isScalar(node) ? node.value : node;
|
|
@@ -13867,8 +13867,8 @@ var require_Collection = __commonJS({
|
|
|
13867
13867
|
/**
|
|
13868
13868
|
* Checks if the collection includes a value with the key `key`.
|
|
13869
13869
|
*/
|
|
13870
|
-
hasIn(
|
|
13871
|
-
const [key, ...rest] =
|
|
13870
|
+
hasIn(path) {
|
|
13871
|
+
const [key, ...rest] = path;
|
|
13872
13872
|
if (rest.length === 0)
|
|
13873
13873
|
return this.has(key);
|
|
13874
13874
|
const node = this.get(key, true);
|
|
@@ -13878,8 +13878,8 @@ var require_Collection = __commonJS({
|
|
|
13878
13878
|
* Sets a value in this collection. For `!!set`, `value` needs to be a
|
|
13879
13879
|
* boolean to add/remove the item from the set.
|
|
13880
13880
|
*/
|
|
13881
|
-
setIn(
|
|
13882
|
-
const [key, ...rest] =
|
|
13881
|
+
setIn(path, value) {
|
|
13882
|
+
const [key, ...rest] = path;
|
|
13883
13883
|
if (rest.length === 0) {
|
|
13884
13884
|
this.set(key, value);
|
|
13885
13885
|
} else {
|
|
@@ -16383,9 +16383,9 @@ var require_Document = __commonJS({
|
|
|
16383
16383
|
this.contents.add(value);
|
|
16384
16384
|
}
|
|
16385
16385
|
/** Adds a value to the document. */
|
|
16386
|
-
addIn(
|
|
16386
|
+
addIn(path, value) {
|
|
16387
16387
|
if (assertCollection(this.contents))
|
|
16388
|
-
this.contents.addIn(
|
|
16388
|
+
this.contents.addIn(path, value);
|
|
16389
16389
|
}
|
|
16390
16390
|
/**
|
|
16391
16391
|
* Create a new `Alias` node, ensuring that the target `node` has the required anchor.
|
|
@@ -16460,14 +16460,14 @@ var require_Document = __commonJS({
|
|
|
16460
16460
|
* Removes a value from the document.
|
|
16461
16461
|
* @returns `true` if the item was found and removed.
|
|
16462
16462
|
*/
|
|
16463
|
-
deleteIn(
|
|
16464
|
-
if (Collection.isEmptyPath(
|
|
16463
|
+
deleteIn(path) {
|
|
16464
|
+
if (Collection.isEmptyPath(path)) {
|
|
16465
16465
|
if (this.contents == null)
|
|
16466
16466
|
return false;
|
|
16467
16467
|
this.contents = null;
|
|
16468
16468
|
return true;
|
|
16469
16469
|
}
|
|
16470
|
-
return assertCollection(this.contents) ? this.contents.deleteIn(
|
|
16470
|
+
return assertCollection(this.contents) ? this.contents.deleteIn(path) : false;
|
|
16471
16471
|
}
|
|
16472
16472
|
/**
|
|
16473
16473
|
* Returns item at `key`, or `undefined` if not found. By default unwraps
|
|
@@ -16482,10 +16482,10 @@ var require_Document = __commonJS({
|
|
|
16482
16482
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
16483
16483
|
* `true` (collections are always returned intact).
|
|
16484
16484
|
*/
|
|
16485
|
-
getIn(
|
|
16486
|
-
if (Collection.isEmptyPath(
|
|
16485
|
+
getIn(path, keepScalar) {
|
|
16486
|
+
if (Collection.isEmptyPath(path))
|
|
16487
16487
|
return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
|
|
16488
|
-
return identity.isCollection(this.contents) ? this.contents.getIn(
|
|
16488
|
+
return identity.isCollection(this.contents) ? this.contents.getIn(path, keepScalar) : void 0;
|
|
16489
16489
|
}
|
|
16490
16490
|
/**
|
|
16491
16491
|
* Checks if the document includes a value with the key `key`.
|
|
@@ -16496,10 +16496,10 @@ var require_Document = __commonJS({
|
|
|
16496
16496
|
/**
|
|
16497
16497
|
* Checks if the document includes a value at `path`.
|
|
16498
16498
|
*/
|
|
16499
|
-
hasIn(
|
|
16500
|
-
if (Collection.isEmptyPath(
|
|
16499
|
+
hasIn(path) {
|
|
16500
|
+
if (Collection.isEmptyPath(path))
|
|
16501
16501
|
return this.contents !== void 0;
|
|
16502
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
16502
|
+
return identity.isCollection(this.contents) ? this.contents.hasIn(path) : false;
|
|
16503
16503
|
}
|
|
16504
16504
|
/**
|
|
16505
16505
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
@@ -16516,13 +16516,13 @@ var require_Document = __commonJS({
|
|
|
16516
16516
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
16517
16517
|
* boolean to add/remove the item from the set.
|
|
16518
16518
|
*/
|
|
16519
|
-
setIn(
|
|
16520
|
-
if (Collection.isEmptyPath(
|
|
16519
|
+
setIn(path, value) {
|
|
16520
|
+
if (Collection.isEmptyPath(path)) {
|
|
16521
16521
|
this.contents = value;
|
|
16522
16522
|
} else if (this.contents == null) {
|
|
16523
|
-
this.contents = Collection.collectionFromPath(this.schema, Array.from(
|
|
16523
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path), value);
|
|
16524
16524
|
} else if (assertCollection(this.contents)) {
|
|
16525
|
-
this.contents.setIn(
|
|
16525
|
+
this.contents.setIn(path, value);
|
|
16526
16526
|
}
|
|
16527
16527
|
}
|
|
16528
16528
|
/**
|
|
@@ -18474,9 +18474,9 @@ var require_cst_visit = __commonJS({
|
|
|
18474
18474
|
visit.BREAK = BREAK;
|
|
18475
18475
|
visit.SKIP = SKIP;
|
|
18476
18476
|
visit.REMOVE = REMOVE;
|
|
18477
|
-
visit.itemAtPath = (cst,
|
|
18477
|
+
visit.itemAtPath = (cst, path) => {
|
|
18478
18478
|
let item = cst;
|
|
18479
|
-
for (const [field, index] of
|
|
18479
|
+
for (const [field, index] of path) {
|
|
18480
18480
|
const tok = item?.[field];
|
|
18481
18481
|
if (tok && "items" in tok) {
|
|
18482
18482
|
item = tok.items[index];
|
|
@@ -18485,23 +18485,23 @@ var require_cst_visit = __commonJS({
|
|
|
18485
18485
|
}
|
|
18486
18486
|
return item;
|
|
18487
18487
|
};
|
|
18488
|
-
visit.parentCollection = (cst,
|
|
18489
|
-
const parent = visit.itemAtPath(cst,
|
|
18490
|
-
const field =
|
|
18488
|
+
visit.parentCollection = (cst, path) => {
|
|
18489
|
+
const parent = visit.itemAtPath(cst, path.slice(0, -1));
|
|
18490
|
+
const field = path[path.length - 1][0];
|
|
18491
18491
|
const coll = parent?.[field];
|
|
18492
18492
|
if (coll && "items" in coll)
|
|
18493
18493
|
return coll;
|
|
18494
18494
|
throw new Error("Parent collection not found");
|
|
18495
18495
|
};
|
|
18496
|
-
function _visit(
|
|
18497
|
-
let ctrl = visitor(item,
|
|
18496
|
+
function _visit(path, item, visitor) {
|
|
18497
|
+
let ctrl = visitor(item, path);
|
|
18498
18498
|
if (typeof ctrl === "symbol")
|
|
18499
18499
|
return ctrl;
|
|
18500
18500
|
for (const field of ["key", "value"]) {
|
|
18501
18501
|
const token = item[field];
|
|
18502
18502
|
if (token && "items" in token) {
|
|
18503
18503
|
for (let i = 0; i < token.items.length; ++i) {
|
|
18504
|
-
const ci = _visit(Object.freeze(
|
|
18504
|
+
const ci = _visit(Object.freeze(path.concat([[field, i]])), token.items[i], visitor);
|
|
18505
18505
|
if (typeof ci === "number")
|
|
18506
18506
|
i = ci - 1;
|
|
18507
18507
|
else if (ci === BREAK)
|
|
@@ -18512,10 +18512,10 @@ var require_cst_visit = __commonJS({
|
|
|
18512
18512
|
}
|
|
18513
18513
|
}
|
|
18514
18514
|
if (typeof ctrl === "function" && field === "key")
|
|
18515
|
-
ctrl = ctrl(item,
|
|
18515
|
+
ctrl = ctrl(item, path);
|
|
18516
18516
|
}
|
|
18517
18517
|
}
|
|
18518
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
18518
|
+
return typeof ctrl === "function" ? ctrl(item, path) : ctrl;
|
|
18519
18519
|
}
|
|
18520
18520
|
exports.visit = visit;
|
|
18521
18521
|
}
|
|
@@ -20303,10 +20303,8 @@ __export(config_exports, {
|
|
|
20303
20303
|
PROVIDER_ENV_ALIASES: () => PROVIDER_ENV_ALIASES,
|
|
20304
20304
|
PROVIDER_ENV_VARS: () => PROVIDER_ENV_VARS,
|
|
20305
20305
|
PROVIDER_NAMES: () => PROVIDER_NAMES,
|
|
20306
|
-
USER_CACHE_DIR: () => USER_CACHE_DIR,
|
|
20307
20306
|
USER_CONFIG_DIR: () => USER_CONFIG_DIR,
|
|
20308
20307
|
USER_CONFIG_PATH: () => USER_CONFIG_PATH,
|
|
20309
|
-
USER_DATA_DIR: () => USER_DATA_DIR,
|
|
20310
20308
|
createDefaultConfig: () => createDefaultConfig,
|
|
20311
20309
|
findProjectConfigPath: () => findProjectConfigPath,
|
|
20312
20310
|
getActiveScope: () => getActiveScope,
|
|
@@ -20318,8 +20316,7 @@ __export(config_exports, {
|
|
|
20318
20316
|
getUserConfigStatus: () => getUserConfigStatus,
|
|
20319
20317
|
isConfigured: () => isConfigured,
|
|
20320
20318
|
loadConfig: () => loadConfig,
|
|
20321
|
-
saveConfig: () => saveConfig
|
|
20322
|
-
updateProviderKey: () => updateProviderKey
|
|
20319
|
+
saveConfig: () => saveConfig
|
|
20323
20320
|
});
|
|
20324
20321
|
import { resolve } from "node:path";
|
|
20325
20322
|
import { homedir } from "node:os";
|
|
@@ -20328,13 +20325,6 @@ function resolveEnvPath(name) {
|
|
|
20328
20325
|
const value = process.env[name]?.trim();
|
|
20329
20326
|
return value ? resolve(value) : null;
|
|
20330
20327
|
}
|
|
20331
|
-
function resolveXdgAppDir(opts) {
|
|
20332
|
-
const override = resolveEnvPath(opts.overrideEnv);
|
|
20333
|
-
if (override) return override;
|
|
20334
|
-
const xdgBase = resolveEnvPath(opts.xdgEnv);
|
|
20335
|
-
const base = xdgBase ?? resolve(homedir(), opts.fallbackHomeRel);
|
|
20336
|
-
return resolve(base, "vibeframe");
|
|
20337
|
-
}
|
|
20338
20328
|
function getProjectConfigDir(cwd = process.cwd()) {
|
|
20339
20329
|
return resolve(cwd, ".vibeframe");
|
|
20340
20330
|
}
|
|
@@ -20347,9 +20337,9 @@ function getConfigPath(scope, cwd) {
|
|
|
20347
20337
|
function getConfigDir(scope, cwd) {
|
|
20348
20338
|
return scope === "project" ? getProjectConfigDir(cwd) : USER_CONFIG_DIR;
|
|
20349
20339
|
}
|
|
20350
|
-
async function fileExists(
|
|
20340
|
+
async function fileExists(path) {
|
|
20351
20341
|
try {
|
|
20352
|
-
await access(
|
|
20342
|
+
await access(path);
|
|
20353
20343
|
return true;
|
|
20354
20344
|
} catch {
|
|
20355
20345
|
return false;
|
|
@@ -20402,14 +20392,14 @@ function applyDefaults(parsed) {
|
|
|
20402
20392
|
repl: { ...defaults.repl, ...parsed.repl }
|
|
20403
20393
|
};
|
|
20404
20394
|
}
|
|
20405
|
-
async function readConfigFile(
|
|
20406
|
-
if (!await fileExists(
|
|
20395
|
+
async function readConfigFile(path) {
|
|
20396
|
+
if (!await fileExists(path)) return null;
|
|
20407
20397
|
try {
|
|
20408
|
-
const content = await readFile(
|
|
20398
|
+
const content = await readFile(path, "utf-8");
|
|
20409
20399
|
const parsed = (0, import_yaml.parse)(content);
|
|
20410
20400
|
return applyDefaults(parsed);
|
|
20411
20401
|
} catch (error) {
|
|
20412
|
-
throw new ConfigFileError(
|
|
20402
|
+
throw new ConfigFileError(path, error);
|
|
20413
20403
|
}
|
|
20414
20404
|
}
|
|
20415
20405
|
async function readUserConfigFile() {
|
|
@@ -20451,10 +20441,10 @@ async function loadConfig(options = {}) {
|
|
|
20451
20441
|
async function saveConfig(config2, options = {}) {
|
|
20452
20442
|
const scope = options.scope ?? "user";
|
|
20453
20443
|
const dir = getConfigDir(scope, options.cwd);
|
|
20454
|
-
const
|
|
20444
|
+
const path = getConfigPath(scope, options.cwd);
|
|
20455
20445
|
await mkdir(dir, { recursive: true });
|
|
20456
20446
|
const content = (0, import_yaml.stringify)(config2, { indent: 2, lineWidth: 0 });
|
|
20457
|
-
await writeFile(
|
|
20447
|
+
await writeFile(path, content, "utf-8");
|
|
20458
20448
|
}
|
|
20459
20449
|
async function isConfigured(options = {}) {
|
|
20460
20450
|
const config2 = await loadConfig({ cwd: options.cwd });
|
|
@@ -20482,14 +20472,7 @@ async function getApiKeyFromConfig(providerKey, options = {}) {
|
|
|
20482
20472
|
function getEnvValue(envVar) {
|
|
20483
20473
|
return process.env[envVar] || PROVIDER_ENV_ALIASES[envVar]?.map((alias) => process.env[alias]).find(Boolean);
|
|
20484
20474
|
}
|
|
20485
|
-
|
|
20486
|
-
const scope = options.scope ?? await getActiveScope(options.cwd);
|
|
20487
|
-
let config2 = await loadConfig({ scope, cwd: options.cwd });
|
|
20488
|
-
if (!config2) config2 = createDefaultConfig();
|
|
20489
|
-
config2.providers[providerKey] = apiKey;
|
|
20490
|
-
await saveConfig(config2, { scope, cwd: options.cwd });
|
|
20491
|
-
}
|
|
20492
|
-
var import_yaml, USER_CONFIG_DIR, USER_CONFIG_PATH, USER_DATA_DIR, USER_CACHE_DIR, LEGACY_USER_CONFIG_DIR, LEGACY_USER_CONFIG_PATH, CONFIG_DIR, CONFIG_PATH, ConfigFileError;
|
|
20475
|
+
var import_yaml, USER_CONFIG_DIR, USER_CONFIG_PATH, LEGACY_USER_CONFIG_DIR, LEGACY_USER_CONFIG_PATH, CONFIG_DIR, CONFIG_PATH, ConfigFileError;
|
|
20493
20476
|
var init_config = __esm({
|
|
20494
20477
|
"src/config/index.ts"() {
|
|
20495
20478
|
"use strict";
|
|
@@ -20498,23 +20481,17 @@ var init_config = __esm({
|
|
|
20498
20481
|
init_schema();
|
|
20499
20482
|
USER_CONFIG_DIR = resolveEnvPath("VIBEFRAME_CONFIG_HOME") ?? resolve(homedir(), ".vibeframe");
|
|
20500
20483
|
USER_CONFIG_PATH = resolve(USER_CONFIG_DIR, "config.yaml");
|
|
20501
|
-
USER_DATA_DIR = resolveXdgAppDir({
|
|
20502
|
-
overrideEnv: "VIBEFRAME_DATA_HOME",
|
|
20503
|
-
xdgEnv: "XDG_DATA_HOME",
|
|
20504
|
-
fallbackHomeRel: ".local/share"
|
|
20505
|
-
});
|
|
20506
|
-
USER_CACHE_DIR = resolveEnvPath("VIBEFRAME_CACHE_HOME") ?? resolve(USER_CONFIG_DIR, "cache");
|
|
20507
20484
|
LEGACY_USER_CONFIG_DIR = resolve(homedir(), ".vibeframe");
|
|
20508
20485
|
LEGACY_USER_CONFIG_PATH = resolve(LEGACY_USER_CONFIG_DIR, "config.yaml");
|
|
20509
20486
|
CONFIG_DIR = USER_CONFIG_DIR;
|
|
20510
20487
|
CONFIG_PATH = USER_CONFIG_PATH;
|
|
20511
20488
|
ConfigFileError = class extends Error {
|
|
20512
20489
|
path;
|
|
20513
|
-
constructor(
|
|
20490
|
+
constructor(path, cause) {
|
|
20514
20491
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
20515
|
-
super(`Failed to read VibeFrame config at ${
|
|
20492
|
+
super(`Failed to read VibeFrame config at ${path}: ${detail}`);
|
|
20516
20493
|
this.name = "ConfigFileError";
|
|
20517
|
-
this.path =
|
|
20494
|
+
this.path = path;
|
|
20518
20495
|
this.cause = cause;
|
|
20519
20496
|
}
|
|
20520
20497
|
};
|
|
@@ -20563,7 +20540,7 @@ async function prompt(question, hidden = false) {
|
|
|
20563
20540
|
input: process.stdin,
|
|
20564
20541
|
output: process.stdout
|
|
20565
20542
|
});
|
|
20566
|
-
return new Promise((
|
|
20543
|
+
return new Promise((resolve63) => {
|
|
20567
20544
|
if (hidden && process.stdin.isTTY) {
|
|
20568
20545
|
process.stdout.write(question);
|
|
20569
20546
|
let input = "";
|
|
@@ -20577,7 +20554,7 @@ async function prompt(question, hidden = false) {
|
|
|
20577
20554
|
process.stdin.removeListener("data", onData);
|
|
20578
20555
|
process.stdout.write("\n");
|
|
20579
20556
|
rl.close();
|
|
20580
|
-
|
|
20557
|
+
resolve63(input);
|
|
20581
20558
|
} else if (char === "") {
|
|
20582
20559
|
process.exit(1);
|
|
20583
20560
|
} else if (char === "\x7F" || char === "\b") {
|
|
@@ -20592,7 +20569,7 @@ async function prompt(question, hidden = false) {
|
|
|
20592
20569
|
} else {
|
|
20593
20570
|
rl.question(question, (answer) => {
|
|
20594
20571
|
rl.close();
|
|
20595
|
-
|
|
20572
|
+
resolve63(answer);
|
|
20596
20573
|
});
|
|
20597
20574
|
}
|
|
20598
20575
|
});
|
|
@@ -23423,8 +23400,8 @@ function providerFailure(message, kind) {
|
|
|
23423
23400
|
const retryable = kind === "rate-limit" || kind === "provider" || kind === "network" || kind === "timeout";
|
|
23424
23401
|
return { ...apiError(message, retryable), ...kind ? { errorKind: kind } : {} };
|
|
23425
23402
|
}
|
|
23426
|
-
function notFoundError(
|
|
23427
|
-
return { success: false, error: `File not found: ${
|
|
23403
|
+
function notFoundError(path) {
|
|
23404
|
+
return { success: false, error: `File not found: ${path}`, code: "NOT_FOUND", exitCode: 3 /* NOT_FOUND */, retryable: false };
|
|
23428
23405
|
}
|
|
23429
23406
|
function generalError(msg, suggestion) {
|
|
23430
23407
|
return { success: false, error: msg, code: "ERROR", exitCode: 1 /* GENERAL */, suggestion, retryable: false };
|
|
@@ -23891,8 +23868,8 @@ function jobFromTaskId(provider, taskId, opts = {}) {
|
|
|
23891
23868
|
...opts.taskType ? { meta: { type: opts.taskType } } : {}
|
|
23892
23869
|
};
|
|
23893
23870
|
}
|
|
23894
|
-
function mimeTypeForPath(
|
|
23895
|
-
return MIME_TYPES[
|
|
23871
|
+
function mimeTypeForPath(path, fallback2) {
|
|
23872
|
+
return MIME_TYPES[path.toLowerCase().split(".").pop() ?? ""] ?? fallback2;
|
|
23896
23873
|
}
|
|
23897
23874
|
async function fileToUrlOrDataUri(input, fallbackMimeType) {
|
|
23898
23875
|
if (/^(https?:|data:)/.test(input)) return input;
|
|
@@ -24163,10 +24140,10 @@ function assetMetadataPath(kind, beatId) {
|
|
|
24163
24140
|
return `.vibeframe/assets/${kind}-${beatId}.json`;
|
|
24164
24141
|
}
|
|
24165
24142
|
function readAssetMetadata(projectDir, kind, beatId) {
|
|
24166
|
-
const
|
|
24167
|
-
if (!existsSync(
|
|
24143
|
+
const path = join(projectDir, assetMetadataPath(kind, beatId));
|
|
24144
|
+
if (!existsSync(path)) return null;
|
|
24168
24145
|
try {
|
|
24169
|
-
const parsed = JSON.parse(readFileSync(
|
|
24146
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
24170
24147
|
if (parsed.schemaVersion !== "1" || parsed.kind !== kind || parsed.beatId !== beatId || typeof parsed.cacheKey !== "string") {
|
|
24171
24148
|
return null;
|
|
24172
24149
|
}
|
|
@@ -24397,8 +24374,8 @@ function buildReviewReport(opts) {
|
|
|
24397
24374
|
function defaultReviewReportPath(projectDir) {
|
|
24398
24375
|
return join2(resolve5(projectDir), "review-report.json");
|
|
24399
24376
|
}
|
|
24400
|
-
async function writeReviewReport(
|
|
24401
|
-
await writeFile5(
|
|
24377
|
+
async function writeReviewReport(path, report) {
|
|
24378
|
+
await writeFile5(path, JSON.stringify(report, null, 2) + "\n", "utf-8");
|
|
24402
24379
|
}
|
|
24403
24380
|
function stripUndefined(value) {
|
|
24404
24381
|
return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== void 0));
|
|
@@ -25330,11 +25307,11 @@ ${nextBody}
|
|
|
25330
25307
|
for (const scene of scenes) await rm(scene.path);
|
|
25331
25308
|
}
|
|
25332
25309
|
const order = starter ? 1 : scenes.length + 1;
|
|
25333
|
-
const
|
|
25310
|
+
const path = join3(dir, sceneFilename(order, beatId));
|
|
25334
25311
|
const front = { type: "Scene", ...cues };
|
|
25335
25312
|
const body = opts.body?.trim() || "Scene created with `vibe scene add`. Edit this body if the build flow should recompose it.";
|
|
25336
25313
|
await writeFile6(
|
|
25337
|
-
|
|
25314
|
+
path,
|
|
25338
25315
|
`---
|
|
25339
25316
|
${(0, import_yaml5.stringify)(front, { lineWidth: 0 }).trimEnd()}
|
|
25340
25317
|
---
|
|
@@ -25343,7 +25320,7 @@ ${body}
|
|
|
25343
25320
|
`,
|
|
25344
25321
|
"utf-8"
|
|
25345
25322
|
);
|
|
25346
|
-
return { action: starter ? "replaced-starter" : "appended", path
|
|
25323
|
+
return { action: starter ? "replaced-starter" : "appended", path };
|
|
25347
25324
|
}
|
|
25348
25325
|
async function rewriteBundleFromMarkdown(projectDir, markdown) {
|
|
25349
25326
|
const plan = planMigration(markdown);
|
|
@@ -25456,17 +25433,17 @@ async function createAndWriteJobRecord(opts) {
|
|
|
25456
25433
|
async function writeJobRecord(record) {
|
|
25457
25434
|
const dir = jobsDir(record.projectDir);
|
|
25458
25435
|
await mkdir5(dir, { recursive: true });
|
|
25459
|
-
const
|
|
25460
|
-
const tmp = `${
|
|
25436
|
+
const path = jobRecordPath(record.id, record.projectDir);
|
|
25437
|
+
const tmp = `${path}.${randomUUID2()}.tmp`;
|
|
25461
25438
|
await writeFile7(tmp, JSON.stringify(stripUndefined2(record), null, 2) + "\n", "utf-8");
|
|
25462
|
-
await rename2(tmp,
|
|
25439
|
+
await rename2(tmp, path);
|
|
25463
25440
|
}
|
|
25464
25441
|
async function readJobRecord(jobId, projectDir) {
|
|
25465
25442
|
const id = normalizeJobId(jobId);
|
|
25466
25443
|
const project = resolve6(projectDir ?? findProjectRoot());
|
|
25467
|
-
const
|
|
25468
|
-
if (!existsSync3(
|
|
25469
|
-
return parseJobRecord(await readFile5(
|
|
25444
|
+
const path = jobRecordPath(id, project);
|
|
25445
|
+
if (!existsSync3(path)) return null;
|
|
25446
|
+
return parseJobRecord(await readFile5(path, "utf-8"));
|
|
25470
25447
|
}
|
|
25471
25448
|
async function listJobRecords(projectDir) {
|
|
25472
25449
|
const dir = jobsDir(projectDir);
|
|
@@ -26193,21 +26170,21 @@ function assetKindForJob(record) {
|
|
|
26193
26170
|
if (record.jobType === "generate-music") return "music";
|
|
26194
26171
|
return void 0;
|
|
26195
26172
|
}
|
|
26196
|
-
function projectRelativePath(projectDir,
|
|
26197
|
-
const rel = relative(resolve6(projectDir), resolve6(
|
|
26198
|
-
if (!rel || rel.startsWith("..")) return
|
|
26173
|
+
function projectRelativePath(projectDir, path) {
|
|
26174
|
+
const rel = relative(resolve6(projectDir), resolve6(path));
|
|
26175
|
+
if (!rel || rel.startsWith("..")) return path;
|
|
26199
26176
|
return rel.replace(/\\/g, "/");
|
|
26200
26177
|
}
|
|
26201
|
-
async function readJson(
|
|
26178
|
+
async function readJson(path) {
|
|
26202
26179
|
try {
|
|
26203
|
-
return JSON.parse(await readFile5(
|
|
26180
|
+
return JSON.parse(await readFile5(path, "utf-8"));
|
|
26204
26181
|
} catch {
|
|
26205
26182
|
return null;
|
|
26206
26183
|
}
|
|
26207
26184
|
}
|
|
26208
|
-
async function statOrNull(
|
|
26185
|
+
async function statOrNull(path) {
|
|
26209
26186
|
try {
|
|
26210
|
-
return await stat(
|
|
26187
|
+
return await stat(path);
|
|
26211
26188
|
} catch {
|
|
26212
26189
|
return null;
|
|
26213
26190
|
}
|
|
@@ -26221,7 +26198,7 @@ function unique(items) {
|
|
|
26221
26198
|
];
|
|
26222
26199
|
}
|
|
26223
26200
|
function sleep3(ms) {
|
|
26224
|
-
return new Promise((
|
|
26201
|
+
return new Promise((resolve63) => setTimeout(resolve63, ms));
|
|
26225
26202
|
}
|
|
26226
26203
|
var LOCAL_JOB_ORPHAN_AFTER_MS;
|
|
26227
26204
|
var init_status_jobs = __esm({
|
|
@@ -28043,7 +28020,7 @@ var require_command = __commonJS({
|
|
|
28043
28020
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
28044
28021
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
28045
28022
|
var childProcess = __require("node:child_process");
|
|
28046
|
-
var
|
|
28023
|
+
var path = __require("node:path");
|
|
28047
28024
|
var fs = __require("node:fs");
|
|
28048
28025
|
var process10 = __require("node:process");
|
|
28049
28026
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -28976,9 +28953,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
28976
28953
|
let launchWithNode = false;
|
|
28977
28954
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
28978
28955
|
function findFile(baseDir, baseName) {
|
|
28979
|
-
const localBin =
|
|
28956
|
+
const localBin = path.resolve(baseDir, baseName);
|
|
28980
28957
|
if (fs.existsSync(localBin)) return localBin;
|
|
28981
|
-
if (sourceExt.includes(
|
|
28958
|
+
if (sourceExt.includes(path.extname(baseName))) return void 0;
|
|
28982
28959
|
const foundExt = sourceExt.find(
|
|
28983
28960
|
(ext) => fs.existsSync(`${localBin}${ext}`)
|
|
28984
28961
|
);
|
|
@@ -28996,17 +28973,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
28996
28973
|
} catch (err) {
|
|
28997
28974
|
resolvedScriptPath = this._scriptPath;
|
|
28998
28975
|
}
|
|
28999
|
-
executableDir =
|
|
29000
|
-
|
|
28976
|
+
executableDir = path.resolve(
|
|
28977
|
+
path.dirname(resolvedScriptPath),
|
|
29001
28978
|
executableDir
|
|
29002
28979
|
);
|
|
29003
28980
|
}
|
|
29004
28981
|
if (executableDir) {
|
|
29005
28982
|
let localFile = findFile(executableDir, executableFile);
|
|
29006
28983
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
29007
|
-
const legacyName =
|
|
28984
|
+
const legacyName = path.basename(
|
|
29008
28985
|
this._scriptPath,
|
|
29009
|
-
|
|
28986
|
+
path.extname(this._scriptPath)
|
|
29010
28987
|
);
|
|
29011
28988
|
if (legacyName !== this._name) {
|
|
29012
28989
|
localFile = findFile(
|
|
@@ -29017,7 +28994,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29017
28994
|
}
|
|
29018
28995
|
executableFile = localFile || executableFile;
|
|
29019
28996
|
}
|
|
29020
|
-
launchWithNode = sourceExt.includes(
|
|
28997
|
+
launchWithNode = sourceExt.includes(path.extname(executableFile));
|
|
29021
28998
|
let proc;
|
|
29022
28999
|
if (process10.platform !== "win32") {
|
|
29023
29000
|
if (launchWithNode) {
|
|
@@ -29857,7 +29834,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29857
29834
|
* @return {Command}
|
|
29858
29835
|
*/
|
|
29859
29836
|
nameFromFilename(filename) {
|
|
29860
|
-
this._name =
|
|
29837
|
+
this._name = path.basename(filename, path.extname(filename));
|
|
29861
29838
|
return this;
|
|
29862
29839
|
}
|
|
29863
29840
|
/**
|
|
@@ -29871,9 +29848,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29871
29848
|
* @param {string} [path]
|
|
29872
29849
|
* @return {(string|null|Command)}
|
|
29873
29850
|
*/
|
|
29874
|
-
executableDir(
|
|
29875
|
-
if (
|
|
29876
|
-
this._executableDir =
|
|
29851
|
+
executableDir(path2) {
|
|
29852
|
+
if (path2 === void 0) return this._executableDir;
|
|
29853
|
+
this._executableDir = path2;
|
|
29877
29854
|
return this;
|
|
29878
29855
|
}
|
|
29879
29856
|
/**
|
|
@@ -30530,17 +30507,17 @@ function detectImageFormat(buffer) {
|
|
|
30530
30507
|
}
|
|
30531
30508
|
return void 0;
|
|
30532
30509
|
}
|
|
30533
|
-
async function writeImageFile(
|
|
30534
|
-
const wanted = EXTENSION_FORMATS[extname2(
|
|
30510
|
+
async function writeImageFile(path, buffer) {
|
|
30511
|
+
const wanted = EXTENSION_FORMATS[extname2(path).toLowerCase()];
|
|
30535
30512
|
const actual = detectImageFormat(buffer);
|
|
30536
30513
|
if (!wanted || !actual || wanted === actual) {
|
|
30537
|
-
await writeFile10(
|
|
30514
|
+
await writeFile10(path, buffer);
|
|
30538
30515
|
return;
|
|
30539
30516
|
}
|
|
30540
|
-
const source = `${
|
|
30517
|
+
const source = `${path}.source.${actual === "jpeg" ? "jpg" : actual}`;
|
|
30541
30518
|
await writeFile10(source, buffer);
|
|
30542
30519
|
try {
|
|
30543
|
-
await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source, "-frames:v", "1",
|
|
30520
|
+
await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source, "-frames:v", "1", path]);
|
|
30544
30521
|
} finally {
|
|
30545
30522
|
await rm2(source, { force: true });
|
|
30546
30523
|
}
|
|
@@ -30576,12 +30553,12 @@ async function openImageGenerator(provider, apiKey) {
|
|
|
30576
30553
|
if (!key) throw new ProviderError({ kind: "auth", provider, message: `${envVar} required for ${provider}.` });
|
|
30577
30554
|
return createImageGenerator(provider, key);
|
|
30578
30555
|
}
|
|
30579
|
-
async function readImageInput(
|
|
30580
|
-
const absPath = resolve10(process.cwd(),
|
|
30556
|
+
async function readImageInput(path) {
|
|
30557
|
+
const absPath = resolve10(process.cwd(), path);
|
|
30581
30558
|
if (!existsSync6(absPath)) {
|
|
30582
30559
|
throw new ProviderError({ kind: "invalid-request", provider: "local", message: `Image not found: ${absPath}` });
|
|
30583
30560
|
}
|
|
30584
|
-
return { bytes: new Uint8Array(await readFile9(absPath)), mimeType: mimeTypeForPath(
|
|
30561
|
+
return { bytes: new Uint8Array(await readFile9(absPath)), mimeType: mimeTypeForPath(path, "image/png") };
|
|
30585
30562
|
}
|
|
30586
30563
|
async function saveImage(output, bytes) {
|
|
30587
30564
|
const outputPath = resolve10(process.cwd(), output);
|
|
@@ -31312,11 +31289,11 @@ var init_root_sync = __esm({
|
|
|
31312
31289
|
// src/commands/_shared/transcription.ts
|
|
31313
31290
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
31314
31291
|
import { basename as basename3 } from "node:path";
|
|
31315
|
-
async function transcribeAudioFile(
|
|
31292
|
+
async function transcribeAudioFile(path, options) {
|
|
31316
31293
|
try {
|
|
31317
31294
|
const transcriber = await createTranscriber("openai", options.apiKey);
|
|
31318
|
-
const audio = new Uint8Array(await readFile11(
|
|
31319
|
-
const name = basename3(
|
|
31295
|
+
const audio = new Uint8Array(await readFile11(path));
|
|
31296
|
+
const name = basename3(path);
|
|
31320
31297
|
const transcript = await transcriber.transcribeAudio({
|
|
31321
31298
|
audio,
|
|
31322
31299
|
// A real extension helps Whisper; temp files without one are sniffed from the bytes.
|
|
@@ -32499,7 +32476,7 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
32499
32476
|
};
|
|
32500
32477
|
}
|
|
32501
32478
|
const missingAssets = reportedBeatAssetPaths(beat).filter(
|
|
32502
|
-
(
|
|
32479
|
+
(path) => !isExternalRef(path) && !pathExists3(opts.projectDir, path)
|
|
32503
32480
|
);
|
|
32504
32481
|
if (missingAssets.length > 0) {
|
|
32505
32482
|
return {
|
|
@@ -33218,9 +33195,9 @@ function buildFootageAssembleArgs(opts) {
|
|
|
33218
33195
|
}
|
|
33219
33196
|
const narrationEntries = [...narrationPaths.entries()].sort(([a], [b]) => a - b);
|
|
33220
33197
|
const narrationInputIndex = /* @__PURE__ */ new Map();
|
|
33221
|
-
for (const [beatIndex,
|
|
33198
|
+
for (const [beatIndex, path] of narrationEntries) {
|
|
33222
33199
|
narrationInputIndex.set(beatIndex, sources.length + narrationInputIndex.size);
|
|
33223
|
-
args.push("-i",
|
|
33200
|
+
args.push("-i", path);
|
|
33224
33201
|
}
|
|
33225
33202
|
let musicInputIndex;
|
|
33226
33203
|
if (musicPath) {
|
|
@@ -34512,8 +34489,8 @@ async function firstConfiguredComposer(projectDir) {
|
|
|
34512
34489
|
return null;
|
|
34513
34490
|
}
|
|
34514
34491
|
function firstExisting2(projectDir, paths) {
|
|
34515
|
-
for (const
|
|
34516
|
-
if (existsSync20(join16(projectDir,
|
|
34492
|
+
for (const path of paths) {
|
|
34493
|
+
if (existsSync20(join16(projectDir, path))) return path;
|
|
34517
34494
|
}
|
|
34518
34495
|
return null;
|
|
34519
34496
|
}
|
|
@@ -34591,16 +34568,16 @@ var init_build_plan = __esm({
|
|
|
34591
34568
|
|
|
34592
34569
|
// src/commands/validate.ts
|
|
34593
34570
|
import { resolve as resolve26, relative as relative8, isAbsolute as isAbsolute5 } from "node:path";
|
|
34594
|
-
function validateOutputPath(
|
|
34595
|
-
rejectControlChars(
|
|
34596
|
-
if (isAbsolute5(
|
|
34597
|
-
return resolve26(
|
|
34571
|
+
function validateOutputPath(path, cwd = process.cwd()) {
|
|
34572
|
+
rejectControlChars(path);
|
|
34573
|
+
if (isAbsolute5(path)) {
|
|
34574
|
+
return resolve26(path);
|
|
34598
34575
|
}
|
|
34599
|
-
const resolved = resolve26(cwd,
|
|
34576
|
+
const resolved = resolve26(cwd, path);
|
|
34600
34577
|
const rel = relative8(cwd, resolved);
|
|
34601
34578
|
if (rel.startsWith("..")) {
|
|
34602
34579
|
throw new Error(
|
|
34603
|
-
`Output path "${
|
|
34580
|
+
`Output path "${path}" escapes the working directory. Use a path within "${cwd}".`
|
|
34604
34581
|
);
|
|
34605
34582
|
}
|
|
34606
34583
|
return resolved;
|
|
@@ -35041,7 +35018,7 @@ async function executeSceneBuild(opts) {
|
|
|
35041
35018
|
onProgress
|
|
35042
35019
|
}
|
|
35043
35020
|
);
|
|
35044
|
-
for (const [name,
|
|
35021
|
+
for (const [name, path] of charResult.paths) characterPaths.set(name, path);
|
|
35045
35022
|
characterCostUsd = charResult.costUsd;
|
|
35046
35023
|
warnings.push(...charResult.failures);
|
|
35047
35024
|
}
|
|
@@ -36903,13 +36880,13 @@ function normalizeReportDuration(value) {
|
|
|
36903
36880
|
return Number((value ?? 0).toFixed(3));
|
|
36904
36881
|
}
|
|
36905
36882
|
function buildReportComposition(projectDir, result, beatId) {
|
|
36906
|
-
const
|
|
36907
|
-
const exists = existsSync22(join17(projectDir,
|
|
36908
|
-
if (result.stageReports?.compose.status === "failed") return { path
|
|
36909
|
-
if (result.phase === "needs-author" && !exists) return { path
|
|
36910
|
-
if (exists) return { path
|
|
36911
|
-
if (result.stageReports?.compose.status === "skipped") return { path
|
|
36912
|
-
return { path
|
|
36883
|
+
const path = `compositions/scene-${beatId}.html`;
|
|
36884
|
+
const exists = existsSync22(join17(projectDir, path));
|
|
36885
|
+
if (result.stageReports?.compose.status === "failed") return { path, exists, status: "failed" };
|
|
36886
|
+
if (result.phase === "needs-author" && !exists) return { path, exists, status: "needs-author" };
|
|
36887
|
+
if (exists) return { path, exists, status: "exists" };
|
|
36888
|
+
if (result.stageReports?.compose.status === "skipped") return { path, exists, status: "skipped" };
|
|
36889
|
+
return { path, exists, status: "needs-author" };
|
|
36913
36890
|
}
|
|
36914
36891
|
function buildWorkflowStatus(result) {
|
|
36915
36892
|
if (!result.success || result.phase === "failed") return "failed";
|
|
@@ -37903,7 +37880,6 @@ __export(remotion_exports, {
|
|
|
37903
37880
|
renderWithEmbeddedImage: () => renderWithEmbeddedImage,
|
|
37904
37881
|
renderWithEmbeddedVideo: () => renderWithEmbeddedVideo,
|
|
37905
37882
|
scaffoldRemotionProject: () => scaffoldRemotionProject,
|
|
37906
|
-
validateAndFixMotionCode: () => validateAndFixMotionCode,
|
|
37907
37883
|
wrapComponentWithImage: () => wrapComponentWithImage,
|
|
37908
37884
|
wrapComponentWithVideo: () => wrapComponentWithVideo
|
|
37909
37885
|
});
|
|
@@ -38103,25 +38079,6 @@ async function renderMotion(options) {
|
|
|
38103
38079
|
});
|
|
38104
38080
|
}
|
|
38105
38081
|
}
|
|
38106
|
-
function validateAndFixMotionCode(code) {
|
|
38107
|
-
const fixes = [];
|
|
38108
|
-
let fixed = code;
|
|
38109
|
-
const pattern1 = /interpolate\(([^,]+),\s*(\[[^\]]+\]),\s*([a-zA-Z_$][a-zA-Z0-9_$.]*),\s*(-?[\d.]+)\s*\)/g;
|
|
38110
|
-
fixed = fixed.replace(pattern1, (_match, val, inputRange, outVar, outNum) => {
|
|
38111
|
-
const fix = `interpolate(${val}, ${inputRange}, [${outVar}, ${outNum}])`;
|
|
38112
|
-
fixes.push(`Fixed scalar outputRange: interpolate(..., ${outVar}, ${outNum}) \u2192 [..., [${outVar}, ${outNum}]]`);
|
|
38113
|
-
return fix;
|
|
38114
|
-
});
|
|
38115
|
-
const pattern2 = /interpolate\(([^,]+),\s*(\[[^\]]+\]),\s*([a-zA-Z_$][a-zA-Z0-9_$.]*)\s*\)/g;
|
|
38116
|
-
let p2match;
|
|
38117
|
-
while ((p2match = pattern2.exec(fixed)) !== null) {
|
|
38118
|
-
const varName = p2match[3];
|
|
38119
|
-
if (!varName.includes("[")) {
|
|
38120
|
-
fixes.push(`Warning: interpolate third arg "${varName}" may not be an array \u2014 verify outputRange is [from, to]`);
|
|
38121
|
-
}
|
|
38122
|
-
}
|
|
38123
|
-
return { code: fixed, fixes };
|
|
38124
|
-
}
|
|
38125
38082
|
function injectRemotionImports(code, additions) {
|
|
38126
38083
|
return code.replace(
|
|
38127
38084
|
/import\s*\{([^}]+)\}\s*from\s*['"]remotion['"]/,
|
|
@@ -40180,8 +40137,8 @@ var init_project = __esm({
|
|
|
40180
40137
|
};
|
|
40181
40138
|
return project;
|
|
40182
40139
|
}
|
|
40183
|
-
setFilePath(
|
|
40184
|
-
this.filePath =
|
|
40140
|
+
setFilePath(path) {
|
|
40141
|
+
this.filePath = path;
|
|
40185
40142
|
}
|
|
40186
40143
|
// ============ Summary ============
|
|
40187
40144
|
getSummary() {
|
|
@@ -41174,376 +41131,215 @@ var init_ai_motion = __esm({
|
|
|
41174
41131
|
}
|
|
41175
41132
|
});
|
|
41176
41133
|
|
|
41177
|
-
// src/
|
|
41178
|
-
|
|
41179
|
-
|
|
41180
|
-
|
|
41181
|
-
}
|
|
41182
|
-
function
|
|
41183
|
-
const
|
|
41184
|
-
|
|
41185
|
-
|
|
41186
|
-
|
|
41187
|
-
|
|
41188
|
-
|
|
41189
|
-
|
|
41190
|
-
|
|
41191
|
-
|
|
41192
|
-
|
|
41193
|
-
|
|
41194
|
-
|
|
41195
|
-
|
|
41196
|
-
|
|
41197
|
-
const
|
|
41198
|
-
|
|
41199
|
-
|
|
41200
|
-
|
|
41201
|
-
"top-right",
|
|
41202
|
-
"bottom-left",
|
|
41203
|
-
"bottom-right"
|
|
41204
|
-
].includes(rawPosition) ? rawPosition : "full";
|
|
41134
|
+
// src/commands/edit/lottie-overlay.ts
|
|
41135
|
+
import { createRequire } from "node:module";
|
|
41136
|
+
import { copyFile as copyFile5, mkdir as mkdir19, mkdtemp as mkdtemp2, readFile as readFile26, rm as rm6, writeFile as writeFile27 } from "node:fs/promises";
|
|
41137
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
41138
|
+
import { basename as basename9, extname as extname8, join as join22 } from "node:path";
|
|
41139
|
+
async function probeVideoStream(path) {
|
|
41140
|
+
const { stdout } = await execSafe("ffprobe", [
|
|
41141
|
+
"-v",
|
|
41142
|
+
"error",
|
|
41143
|
+
"-select_streams",
|
|
41144
|
+
"v:0",
|
|
41145
|
+
"-show_entries",
|
|
41146
|
+
"stream=width,height,r_frame_rate:stream_tags=rotate:stream_side_data=rotation:format=duration",
|
|
41147
|
+
"-of",
|
|
41148
|
+
"json",
|
|
41149
|
+
path
|
|
41150
|
+
]);
|
|
41151
|
+
const info = JSON.parse(stdout);
|
|
41152
|
+
const stream = info.streams?.[0];
|
|
41153
|
+
if (!stream?.width || !stream.height) throw new Error(`No video stream in ${path}`);
|
|
41154
|
+
const rotation = Number(stream.side_data_list?.find((s) => s.rotation !== void 0)?.rotation ?? stream.tags?.rotate ?? 0);
|
|
41155
|
+
const quarterTurn = Math.abs(rotation) % 180 === 90;
|
|
41156
|
+
const [num, den] = (stream.r_frame_rate ?? "30/1").split("/").map(Number);
|
|
41157
|
+
const fps = den > 0 && num > 0 ? num / den : 30;
|
|
41205
41158
|
return {
|
|
41206
|
-
|
|
41207
|
-
|
|
41208
|
-
|
|
41209
|
-
|
|
41159
|
+
width: quarterTurn ? stream.height : stream.width,
|
|
41160
|
+
height: quarterTurn ? stream.width : stream.height,
|
|
41161
|
+
fps,
|
|
41162
|
+
duration: Number(info.format?.duration ?? 0)
|
|
41210
41163
|
};
|
|
41211
41164
|
}
|
|
41212
|
-
function
|
|
41213
|
-
const
|
|
41214
|
-
|
|
41215
|
-
|
|
41216
|
-
|
|
41217
|
-
|
|
41218
|
-
|
|
41219
|
-
|
|
41220
|
-
}
|
|
41221
|
-
|
|
41222
|
-
const edge = "4%";
|
|
41223
|
-
const placement = {
|
|
41224
|
-
center: ["left:50%", "top:50%", "transform:translate(-50%,-50%)"],
|
|
41225
|
-
"top-left": [`left:${edge}`, `top:${edge}`],
|
|
41226
|
-
"top-right": [`right:${edge}`, `top:${edge}`],
|
|
41227
|
-
"bottom-left": [`left:${edge}`, `bottom:${edge}`],
|
|
41228
|
-
"bottom-right": [`right:${edge}`, `bottom:${edge}`]
|
|
41229
|
-
};
|
|
41230
|
-
return [...base, ...placement[params.position], `width:${size}`, `height:${size}`].join(";");
|
|
41231
|
-
}
|
|
41232
|
-
function buildClipElements(state) {
|
|
41233
|
-
return state.clips.map((clip) => {
|
|
41234
|
-
const source = state.sources.find((s) => s.id === clip.sourceId);
|
|
41235
|
-
const track = state.tracks.find((t) => t.id === clip.trackId);
|
|
41236
|
-
if (!source || !track) return `<!-- missing source/track for clip ${clip.id} -->`;
|
|
41237
|
-
const zIndex = track.order;
|
|
41238
|
-
switch (source.type) {
|
|
41239
|
-
case "image":
|
|
41240
|
-
return `<div id="${clip.id}" class="clip" style="z-index:${zIndex};"><img src="${relAsset(source.url)}" style="width:100%;height:100%;object-fit:cover;"></div>`;
|
|
41241
|
-
case "video":
|
|
41242
|
-
return `<div id="${clip.id}" class="clip" style="z-index:${zIndex};"><video id="${clip.id}-media" src="${relAsset(source.url)}" style="width:100%;height:100%;object-fit:cover;" muted playsinline></video></div>`;
|
|
41243
|
-
case "audio":
|
|
41244
|
-
return `<audio id="${clip.id}-media" src="${relAsset(source.url)}"></audio><div id="${clip.id}" class="clip" style="z-index:${zIndex};background:#111;"></div>`;
|
|
41245
|
-
case "lottie": {
|
|
41246
|
-
const params = lottieOverlayParams(clip);
|
|
41247
|
-
const loop = params.loop ? " loop" : "";
|
|
41248
|
-
return `<div id="${clip.id}" class="clip" style="z-index:${zIndex};"><dotlottie-wc src="${relAsset(source.url)}" autoplay${loop} style="${lottieInnerStyle(params)}"></dotlottie-wc></div>`;
|
|
41249
|
-
}
|
|
41250
|
-
default:
|
|
41251
|
-
return `<!-- unsupported source type: ${source.type} for clip ${clip.id} -->`;
|
|
41252
|
-
}
|
|
41253
|
-
}).join("\n ");
|
|
41254
|
-
}
|
|
41255
|
-
function buildMediaDeclarations(state) {
|
|
41256
|
-
return state.clips.map((clip) => ({ clip, source: state.sources.find((s) => s.id === clip.sourceId) })).filter(
|
|
41257
|
-
(x) => x.source !== void 0 && (x.source.type === "video" || x.source.type === "audio")
|
|
41258
|
-
).map(({ clip, source }) => ({
|
|
41259
|
-
elementId: `${clip.id}-media`,
|
|
41260
|
-
src: relAsset(source.url),
|
|
41261
|
-
startTime: clip.startTime,
|
|
41262
|
-
endTime: clip.startTime + clip.duration,
|
|
41263
|
-
mediaOffset: clip.sourceStartOffset ?? 0,
|
|
41264
|
-
volume: 1,
|
|
41265
|
-
hasAudio: true
|
|
41266
|
-
}));
|
|
41165
|
+
async function checkLottieAsset(path) {
|
|
41166
|
+
const bytes = await readFile26(path);
|
|
41167
|
+
const isZip = bytes.length > 4 && bytes[0] === 80 && bytes[1] === 75;
|
|
41168
|
+
if (isZip) return void 0;
|
|
41169
|
+
try {
|
|
41170
|
+
const json = JSON.parse(bytes.toString("utf-8"));
|
|
41171
|
+
if (Array.isArray(json.layers)) return void 0;
|
|
41172
|
+
} catch {
|
|
41173
|
+
}
|
|
41174
|
+
return `${basename9(path)} is not a Lottie animation (expected Lottie JSON or a .lottie archive).`;
|
|
41267
41175
|
}
|
|
41268
|
-
function
|
|
41269
|
-
|
|
41270
|
-
|
|
41271
|
-
|
|
41272
|
-
|
|
41273
|
-
|
|
41274
|
-
|
|
41176
|
+
function overlayBox(layer, position, scale) {
|
|
41177
|
+
if (position === "full") return { left: 0, top: 0, width: layer.width, height: layer.height };
|
|
41178
|
+
const width = Math.max(1, Math.round(layer.width * scale));
|
|
41179
|
+
const height = Math.max(1, Math.round(layer.height * scale));
|
|
41180
|
+
const marginX = Math.round(layer.width * 0.04);
|
|
41181
|
+
const marginY = Math.round(layer.height * 0.04);
|
|
41182
|
+
const left = position === "center" ? Math.round((layer.width - width) / 2) : position.endsWith("left") ? marginX : layer.width - marginX - width;
|
|
41183
|
+
const top = position === "center" ? Math.round((layer.height - height) / 2) : position.startsWith("top") ? marginY : layer.height - marginY - height;
|
|
41184
|
+
return { left, top, width, height };
|
|
41275
41185
|
}
|
|
41276
|
-
|
|
41277
|
-
|
|
41278
|
-
"use strict";
|
|
41279
|
-
}
|
|
41280
|
-
});
|
|
41281
|
-
|
|
41282
|
-
// src/pipeline/renderers/html-runtime.ts
|
|
41283
|
-
var RUNTIME_SCRIPT;
|
|
41284
|
-
var init_html_runtime = __esm({
|
|
41285
|
-
"src/pipeline/renderers/html-runtime.ts"() {
|
|
41286
|
-
"use strict";
|
|
41287
|
-
RUNTIME_SCRIPT = `
|
|
41288
|
-
(function () {
|
|
41289
|
-
var CLIPS = /*CLIPS_JSON*/[];
|
|
41290
|
-
|
|
41291
|
-
function interpolate(kfs, t) {
|
|
41292
|
-
if (!kfs || kfs.length === 0) return null;
|
|
41293
|
-
if (kfs.length === 1) return kfs[0].values;
|
|
41294
|
-
var prev = kfs[0], next = kfs[kfs.length - 1];
|
|
41295
|
-
for (var i = 0; i < kfs.length - 1; i++) {
|
|
41296
|
-
if (t >= kfs[i].time && t <= kfs[i + 1].time) { prev = kfs[i]; next = kfs[i + 1]; break; }
|
|
41297
|
-
}
|
|
41298
|
-
if (t <= prev.time) return prev.values;
|
|
41299
|
-
if (t >= next.time) return next.values;
|
|
41300
|
-
var raw = (t - prev.time) / (next.time - prev.time);
|
|
41301
|
-
var e = prev.easing || 'linear';
|
|
41302
|
-
var p = e === 'easeIn' ? raw * raw
|
|
41303
|
-
: e === 'easeOut' ? raw * (2 - raw)
|
|
41304
|
-
: e === 'easeInOut' ? (raw < 0.5 ? 2 * raw * raw : -1 + (4 - 2 * raw) * raw)
|
|
41305
|
-
: raw;
|
|
41306
|
-
var out = {};
|
|
41307
|
-
for (var k in prev.values) {
|
|
41308
|
-
var a = +prev.values[k], b = +next.values[k];
|
|
41309
|
-
out[k] = isNaN(a) || isNaN(b) ? prev.values[k] : a + (b - a) * p;
|
|
41310
|
-
}
|
|
41311
|
-
return out;
|
|
41312
|
-
}
|
|
41313
|
-
|
|
41314
|
-
function applyEffects(el, effects, clipTime) {
|
|
41315
|
-
var opacity = 1;
|
|
41316
|
-
var filters = [];
|
|
41317
|
-
for (var i = 0; i < effects.length; i++) {
|
|
41318
|
-
var fx = effects[i];
|
|
41319
|
-
var t = clipTime - fx.startTime;
|
|
41320
|
-
if (t < 0 || t > fx.duration) continue;
|
|
41321
|
-
var vals = (fx.keyframes && fx.keyframes.length > 0)
|
|
41322
|
-
? interpolate(fx.keyframes, t)
|
|
41323
|
-
: fx.params;
|
|
41324
|
-
if (!vals) continue;
|
|
41325
|
-
switch (fx.type) {
|
|
41326
|
-
case 'fadeIn':
|
|
41327
|
-
opacity = Math.min(opacity, t / fx.duration * (+(vals.intensity || 1))); break;
|
|
41328
|
-
case 'fadeOut':
|
|
41329
|
-
opacity = Math.min(opacity, (1 - t / fx.duration) * (+(vals.intensity || 1))); break;
|
|
41330
|
-
case 'blur':
|
|
41331
|
-
filters.push('blur(' + (+vals.radius || 0) + 'px)'); break;
|
|
41332
|
-
case 'brightness':
|
|
41333
|
-
filters.push('brightness(' + (+vals.value || 1) + ')'); break;
|
|
41334
|
-
case 'contrast':
|
|
41335
|
-
filters.push('contrast(' + (+vals.value || 1) + ')'); break;
|
|
41336
|
-
case 'saturation':
|
|
41337
|
-
filters.push('saturate(' + (+vals.value || 1) + ')'); break;
|
|
41338
|
-
}
|
|
41339
|
-
}
|
|
41340
|
-
el.style.opacity = String(opacity);
|
|
41341
|
-
if (filters.length > 0) el.style.filter = filters.join(' ');
|
|
41342
|
-
else el.style.filter = '';
|
|
41343
|
-
}
|
|
41344
|
-
|
|
41345
|
-
window.__hf = {
|
|
41346
|
-
duration: /*DURATION*/0,
|
|
41347
|
-
media: /*MEDIA_JSON*/[],
|
|
41348
|
-
seek: function (t) {
|
|
41349
|
-
for (var i = 0; i < CLIPS.length; i++) {
|
|
41350
|
-
var c = CLIPS[i];
|
|
41351
|
-
var el = document.getElementById(c.id);
|
|
41352
|
-
if (!el) continue;
|
|
41353
|
-
var active = t >= c.startTime && t < c.startTime + c.duration;
|
|
41354
|
-
el.style.display = active ? 'block' : 'none';
|
|
41355
|
-
if (active) applyEffects(el, c.effects, t - c.startTime);
|
|
41356
|
-
}
|
|
41357
|
-
}
|
|
41358
|
-
};
|
|
41359
|
-
})();
|
|
41360
|
-
`;
|
|
41361
|
-
}
|
|
41362
|
-
});
|
|
41363
|
-
|
|
41364
|
-
// src/pipeline/renderers/html-template.ts
|
|
41365
|
-
function generateCompositionHtml(state) {
|
|
41366
|
-
const { width, height } = aspectToResolution(state.project.aspectRatio);
|
|
41367
|
-
const clipMarkup = buildClipElements(state);
|
|
41368
|
-
const mediaDecls = buildMediaDeclarations(state);
|
|
41369
|
-
const clipData = buildClipRuntimeData(state);
|
|
41370
|
-
const duration = state.project.duration;
|
|
41371
|
-
const hasLottie = state.sources.some((s) => s.type === "lottie");
|
|
41372
|
-
const script = RUNTIME_SCRIPT.replace("/*CLIPS_JSON*/[]", JSON.stringify(clipData)).replace("/*DURATION*/0", String(duration)).replace("/*MEDIA_JSON*/[]", JSON.stringify(mediaDecls));
|
|
41373
|
-
const lottieRuntime = hasLottie ? `<script type="module">
|
|
41374
|
-
import { setWasmUrl } from "/vendor/dotlottie-wc/index.js";
|
|
41375
|
-
setWasmUrl("/vendor/dotlottie-player.wasm");
|
|
41376
|
-
</script>
|
|
41377
|
-
` : "";
|
|
41186
|
+
function lottieLayerHtml(opts) {
|
|
41187
|
+
const { box } = opts;
|
|
41378
41188
|
return `<!DOCTYPE html>
|
|
41379
41189
|
<html><head>
|
|
41380
41190
|
<meta charset="utf-8">
|
|
41381
41191
|
<style>
|
|
41382
|
-
html, body { margin: 0; width: ${width}px; height: ${height}px; overflow: hidden; background:
|
|
41383
|
-
#
|
|
41384
|
-
.clip { position: absolute; inset: 0; display: none; }
|
|
41192
|
+
html, body { margin: 0; width: ${opts.width}px; height: ${opts.height}px; overflow: hidden; background: transparent; }
|
|
41193
|
+
#lottie { position: absolute; left: ${box.left}px; top: ${box.top}px; width: ${box.width}px; height: ${box.height}px; opacity: ${opts.opacity}; }
|
|
41385
41194
|
</style>
|
|
41386
|
-
|
|
41387
|
-
<
|
|
41388
|
-
|
|
41389
|
-
|
|
41390
|
-
|
|
41391
|
-
|
|
41195
|
+
</head><body>
|
|
41196
|
+
<canvas id="lottie" width="${box.width}" height="${box.height}"></canvas>
|
|
41197
|
+
<script type="module">
|
|
41198
|
+
import { DotLottie } from "./vendor/dotlottie-web.js";
|
|
41199
|
+
// The render server sends .wasm without application/wasm, which makes
|
|
41200
|
+
// WebAssembly.instantiateStreaming reject it; a typed Blob URL avoids that.
|
|
41201
|
+
const wasm = await (await fetch("./vendor/dotlottie-player.wasm")).arrayBuffer();
|
|
41202
|
+
DotLottie.setWasmUrl(URL.createObjectURL(new Blob([wasm], { type: "application/wasm" })));
|
|
41203
|
+
const LOOP = ${opts.loop};
|
|
41204
|
+
const DURATION = ${opts.duration};
|
|
41205
|
+
const player = new DotLottie({
|
|
41206
|
+
canvas: document.getElementById("lottie"),
|
|
41207
|
+
src: ${JSON.stringify(opts.assetUrl)},
|
|
41208
|
+
autoplay: false,
|
|
41209
|
+
loop: false,
|
|
41210
|
+
renderConfig: { devicePixelRatio: 1, autoResize: false, freezeOnOffscreen: false },
|
|
41211
|
+
});
|
|
41212
|
+
player.addEventListener("loadError", (event) => {
|
|
41213
|
+
window.__lottieLoadError = String(event && event.error ? event.error.message || event.error : "load failed");
|
|
41214
|
+
});
|
|
41215
|
+
player.addEventListener("load", () => {
|
|
41216
|
+
window.__hf = {
|
|
41217
|
+
duration: DURATION,
|
|
41218
|
+
seek(t) {
|
|
41219
|
+
const length = player.duration;
|
|
41220
|
+
const frames = player.totalFrames;
|
|
41221
|
+
if (!(length > 0) || !(frames > 0)) return;
|
|
41222
|
+
const local = Math.max(0, Number(t) || 0);
|
|
41223
|
+
const at = LOOP ? local % length : Math.min(local, length);
|
|
41224
|
+
player.setFrame(Math.min(frames - 1, (at / length) * frames));
|
|
41225
|
+
},
|
|
41226
|
+
};
|
|
41227
|
+
window.__hf.seek(0);
|
|
41228
|
+
});
|
|
41392
41229
|
</script>
|
|
41393
|
-
</body></html
|
|
41394
|
-
|
|
41395
|
-
var init_html_template = __esm({
|
|
41396
|
-
"src/pipeline/renderers/html-template.ts"() {
|
|
41397
|
-
"use strict";
|
|
41398
|
-
init_hyperframes();
|
|
41399
|
-
init_html_clips();
|
|
41400
|
-
init_html_runtime();
|
|
41401
|
-
}
|
|
41402
|
-
});
|
|
41403
|
-
|
|
41404
|
-
// src/pipeline/renderers/project-builder.ts
|
|
41405
|
-
var project_builder_exports = {};
|
|
41406
|
-
__export(project_builder_exports, {
|
|
41407
|
-
buildTempProject: () => buildTempProject,
|
|
41408
|
-
resolveSourceUrl: () => resolveSourceUrl
|
|
41409
|
-
});
|
|
41410
|
-
import { mkdtemp as mkdtemp2, mkdir as mkdir19, copyFile as copyFile5, writeFile as writeFile27, rm as rm6, readdir as readdir4 } from "node:fs/promises";
|
|
41411
|
-
import { existsSync as existsSync35 } from "node:fs";
|
|
41412
|
-
import { tmpdir as tmpdir3 } from "node:os";
|
|
41413
|
-
import { createRequire } from "node:module";
|
|
41414
|
-
import * as path from "node:path";
|
|
41415
|
-
async function buildTempProject(state, projectFileDir) {
|
|
41416
|
-
const dir = await mkdtemp2(path.join(tmpdir3(), "vibeframe-hf-"));
|
|
41417
|
-
const assetsDir = path.join(dir, "assets");
|
|
41418
|
-
await mkdir19(assetsDir, { recursive: true });
|
|
41419
|
-
const copied = /* @__PURE__ */ new Map();
|
|
41420
|
-
for (const source of state.sources) {
|
|
41421
|
-
if (copied.has(source.id)) continue;
|
|
41422
|
-
const resolved = resolveSourceUrl(source.url, projectFileDir);
|
|
41423
|
-
if (!existsSync35(resolved)) {
|
|
41424
|
-
throw new Error(`Source file not found: ${resolved} (from source id=${source.id})`);
|
|
41425
|
-
}
|
|
41426
|
-
const dest = path.join(assetsDir, path.basename(resolved));
|
|
41427
|
-
await copyFile5(resolved, dest);
|
|
41428
|
-
copied.set(source.id, dest);
|
|
41429
|
-
}
|
|
41430
|
-
if (state.sources.some((s) => s.type === "lottie")) {
|
|
41431
|
-
await copyLottieRuntime(dir);
|
|
41432
|
-
}
|
|
41433
|
-
const html = generateCompositionHtml(state);
|
|
41434
|
-
await writeFile27(path.join(dir, "index.html"), html, "utf-8");
|
|
41435
|
-
return {
|
|
41436
|
-
dir,
|
|
41437
|
-
cleanup: () => rm6(dir, { recursive: true, force: true })
|
|
41438
|
-
};
|
|
41230
|
+
</body></html>
|
|
41231
|
+
`;
|
|
41439
41232
|
}
|
|
41440
|
-
|
|
41233
|
+
function vendorPaths() {
|
|
41441
41234
|
const require2 = createRequire(import.meta.url);
|
|
41442
|
-
const
|
|
41443
|
-
const
|
|
41444
|
-
|
|
41445
|
-
|
|
41446
|
-
|
|
41447
|
-
const
|
|
41448
|
-
|
|
41449
|
-
|
|
41450
|
-
|
|
41451
|
-
|
|
41452
|
-
|
|
41453
|
-
|
|
41235
|
+
const script = require2.resolve("@lottiefiles/dotlottie-web");
|
|
41236
|
+
const dist = join22(script, "..");
|
|
41237
|
+
return { script: join22(dist, "index.js"), wasm: join22(dist, "dotlottie-player.wasm") };
|
|
41238
|
+
}
|
|
41239
|
+
async function renderLayer(opts) {
|
|
41240
|
+
const { dir, info, options } = opts;
|
|
41241
|
+
const vendor = vendorPaths();
|
|
41242
|
+
await mkdir19(join22(dir, "vendor"), { recursive: true });
|
|
41243
|
+
await mkdir19(join22(dir, "assets"), { recursive: true });
|
|
41244
|
+
await copyFile5(vendor.script, join22(dir, "vendor", "dotlottie-web.js"));
|
|
41245
|
+
await copyFile5(vendor.wasm, join22(dir, "vendor", "dotlottie-player.wasm"));
|
|
41246
|
+
const assetName = `animation${extname8(options.assetPath).toLowerCase()}`;
|
|
41247
|
+
await copyFile5(options.assetPath, join22(dir, "assets", assetName));
|
|
41248
|
+
const html = lottieLayerHtml({
|
|
41249
|
+
width: info.width,
|
|
41250
|
+
height: info.height,
|
|
41251
|
+
duration: options.duration,
|
|
41252
|
+
assetUrl: `./assets/${assetName}`,
|
|
41253
|
+
box: overlayBox(info, options.position, options.scale),
|
|
41254
|
+
opacity: options.opacity,
|
|
41255
|
+
loop: options.loop
|
|
41256
|
+
});
|
|
41257
|
+
await writeFile27(join22(dir, "index.html"), html, "utf-8");
|
|
41258
|
+
const layerPath = join22(dir, "layer.mov");
|
|
41259
|
+
const { createRenderJob: createRenderJob2, executeRenderJob: executeRenderJob2 } = await import("@hyperframes/producer");
|
|
41260
|
+
const job = createRenderJob2({
|
|
41261
|
+
fps: Math.min(60, Math.max(1, Math.round(info.fps))),
|
|
41262
|
+
quality: "standard",
|
|
41263
|
+
format: "mov",
|
|
41264
|
+
entryFile: "index.html",
|
|
41265
|
+
workers: 1
|
|
41266
|
+
});
|
|
41267
|
+
await withStdoutOnStderr(() => executeRenderJob2(job, dir, layerPath));
|
|
41268
|
+
return layerPath;
|
|
41454
41269
|
}
|
|
41455
|
-
function
|
|
41456
|
-
|
|
41457
|
-
|
|
41458
|
-
|
|
41459
|
-
|
|
41270
|
+
async function composite(videoPath, layerPath, options) {
|
|
41271
|
+
const filter = `[1:v]setpts=PTS-STARTPTS+${options.start}/TB[layer];[0:v][layer]overlay=eof_action=pass:format=auto,format=yuv420p[v]`;
|
|
41272
|
+
const args = (audioCodec) => [
|
|
41273
|
+
"-y",
|
|
41274
|
+
"-i",
|
|
41275
|
+
videoPath,
|
|
41276
|
+
"-i",
|
|
41277
|
+
layerPath,
|
|
41278
|
+
"-filter_complex",
|
|
41279
|
+
filter,
|
|
41280
|
+
"-map",
|
|
41281
|
+
"[v]",
|
|
41282
|
+
"-map",
|
|
41283
|
+
"0:a?",
|
|
41284
|
+
"-c:v",
|
|
41285
|
+
"libx264",
|
|
41286
|
+
"-crf",
|
|
41287
|
+
"18",
|
|
41288
|
+
"-preset",
|
|
41289
|
+
"medium",
|
|
41290
|
+
...audioCodec,
|
|
41291
|
+
"-movflags",
|
|
41292
|
+
"+faststart",
|
|
41293
|
+
options.outputPath
|
|
41294
|
+
];
|
|
41295
|
+
const opts = { timeout: 10 * 6e4, maxBuffer: 50 * 1024 * 1024 };
|
|
41296
|
+
try {
|
|
41297
|
+
await execSafe("ffmpeg", args(["-c:a", "copy"]), opts);
|
|
41298
|
+
} catch {
|
|
41299
|
+
await execSafe("ffmpeg", args(["-c:a", "aac", "-b:a", "192k"]), opts);
|
|
41300
|
+
}
|
|
41460
41301
|
}
|
|
41461
|
-
|
|
41462
|
-
"
|
|
41463
|
-
"
|
|
41464
|
-
init_html_template();
|
|
41302
|
+
async function renderLottieOverlay(options) {
|
|
41303
|
+
if (!commandExists("ffmpeg") || !commandExists("ffprobe")) {
|
|
41304
|
+
return { success: false, error: FFMPEG_MISSING, suggestion: "Run `vibe doctor`." };
|
|
41465
41305
|
}
|
|
41466
|
-
|
|
41467
|
-
|
|
41468
|
-
|
|
41469
|
-
|
|
41470
|
-
|
|
41471
|
-
|
|
41472
|
-
|
|
41473
|
-
|
|
41474
|
-
|
|
41475
|
-
|
|
41476
|
-
|
|
41477
|
-
|
|
41478
|
-
|
|
41479
|
-
const { createRenderJob: createRenderJob2, executeRenderJob: executeRenderJob2 } = await import("@hyperframes/producer");
|
|
41480
|
-
let project;
|
|
41481
|
-
const start = Date.now();
|
|
41482
|
-
try {
|
|
41483
|
-
project = await buildTempProject2(options.projectState);
|
|
41484
|
-
} catch (err) {
|
|
41306
|
+
const chrome = await preflightChrome();
|
|
41307
|
+
if (!chrome.ok) return { success: false, error: chrome.reason, suggestion: "Run `vibe doctor`." };
|
|
41308
|
+
const assetProblem = await checkLottieAsset(options.assetPath);
|
|
41309
|
+
if (assetProblem) return { success: false, error: assetProblem };
|
|
41310
|
+
const info = await probeVideoStream(options.videoPath);
|
|
41311
|
+
const dir = await mkdtemp2(join22(tmpdir3(), "vibeframe-lottie-"));
|
|
41312
|
+
try {
|
|
41313
|
+
let layerPath;
|
|
41314
|
+
try {
|
|
41315
|
+
layerPath = await renderLayer({ dir, info, options });
|
|
41316
|
+
} catch (error) {
|
|
41317
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
41318
|
+
if (/__hf not ready/.test(message)) {
|
|
41485
41319
|
return {
|
|
41486
41320
|
success: false,
|
|
41487
|
-
error: `
|
|
41321
|
+
error: `Could not load the Lottie animation ${basename9(options.assetPath)}.`,
|
|
41322
|
+
suggestion: "Check that it opens in a Lottie player (https://lottiefiles.com/preview)."
|
|
41488
41323
|
};
|
|
41489
41324
|
}
|
|
41490
|
-
|
|
41491
|
-
fps: options.fps ?? 30,
|
|
41492
|
-
quality: options.quality ?? "standard",
|
|
41493
|
-
format: options.format ?? "mp4",
|
|
41494
|
-
entryFile: "index.html",
|
|
41495
|
-
crf: qualityToCrf2(options.quality),
|
|
41496
|
-
workers: options.workers ?? 1
|
|
41497
|
-
};
|
|
41498
|
-
const job = createRenderJob2(config2);
|
|
41499
|
-
try {
|
|
41500
|
-
await withStdoutOnStderr(
|
|
41501
|
-
() => executeRenderJob2(
|
|
41502
|
-
job,
|
|
41503
|
-
project.dir,
|
|
41504
|
-
options.outputPath,
|
|
41505
|
-
(j, msg) => {
|
|
41506
|
-
options.onProgress?.(j.progress, j.currentStage ?? msg);
|
|
41507
|
-
},
|
|
41508
|
-
options.signal
|
|
41509
|
-
)
|
|
41510
|
-
);
|
|
41511
|
-
await project.cleanup();
|
|
41512
|
-
return {
|
|
41513
|
-
success: true,
|
|
41514
|
-
outputPath: options.outputPath,
|
|
41515
|
-
durationMs: Date.now() - start,
|
|
41516
|
-
framesRendered: job.framesRendered
|
|
41517
|
-
};
|
|
41518
|
-
} catch (err) {
|
|
41519
|
-
console.error(`[hyperframes] render failed. Temp dir preserved: ${project?.dir}`);
|
|
41520
|
-
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
41521
|
-
}
|
|
41325
|
+
return { success: false, error: `Lottie layer render failed: ${message}` };
|
|
41522
41326
|
}
|
|
41523
|
-
|
|
41524
|
-
}
|
|
41525
|
-
|
|
41526
|
-
|
|
41527
|
-
|
|
41528
|
-
|
|
41529
|
-
case "9:16":
|
|
41530
|
-
return { width: 1080, height: 1920 };
|
|
41531
|
-
case "1:1":
|
|
41532
|
-
return { width: 1080, height: 1080 };
|
|
41533
|
-
case "4:5":
|
|
41534
|
-
return { width: 1080, height: 1350 };
|
|
41535
|
-
default:
|
|
41536
|
-
return { width: 1920, height: 1080 };
|
|
41327
|
+
await composite(options.videoPath, layerPath, options);
|
|
41328
|
+
return { success: true, outputPath: options.outputPath };
|
|
41329
|
+
} catch (error) {
|
|
41330
|
+
return { success: false, error: `Lottie overlay failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
41331
|
+
} finally {
|
|
41332
|
+
await rm6(dir, { recursive: true, force: true });
|
|
41537
41333
|
}
|
|
41538
41334
|
}
|
|
41539
|
-
|
|
41540
|
-
|
|
41541
|
-
|
|
41542
|
-
var init_hyperframes = __esm({
|
|
41543
|
-
"src/pipeline/renderers/hyperframes.ts"() {
|
|
41335
|
+
var FFMPEG_MISSING;
|
|
41336
|
+
var init_lottie_overlay = __esm({
|
|
41337
|
+
"src/commands/edit/lottie-overlay.ts"() {
|
|
41544
41338
|
"use strict";
|
|
41545
41339
|
init_chrome();
|
|
41340
|
+
init_exec_safe();
|
|
41546
41341
|
init_stdout_guard();
|
|
41342
|
+
FFMPEG_MISSING = "FFmpeg not found. Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux). Run `vibe doctor` for details.";
|
|
41547
41343
|
}
|
|
41548
41344
|
});
|
|
41549
41345
|
|
|
@@ -41554,8 +41350,8 @@ __export(motion_overlay_exports, {
|
|
|
41554
41350
|
registerMotionOverlayCommand: () => registerMotionOverlayCommand
|
|
41555
41351
|
});
|
|
41556
41352
|
import { mkdir as mkdir20 } from "node:fs/promises";
|
|
41557
|
-
import { existsSync as
|
|
41558
|
-
import {
|
|
41353
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
41354
|
+
import { dirname as dirname15, extname as extname9, resolve as resolve36 } from "node:path";
|
|
41559
41355
|
function normalizeUnderstand2(value) {
|
|
41560
41356
|
return value === "off" || value === "required" || value === "auto" ? value : "auto";
|
|
41561
41357
|
}
|
|
@@ -41567,7 +41363,7 @@ function numberOption(value, fallback2) {
|
|
|
41567
41363
|
return Number.isFinite(n) ? n : fallback2;
|
|
41568
41364
|
}
|
|
41569
41365
|
function defaultOverlayOutput(videoPath) {
|
|
41570
|
-
const absVideo =
|
|
41366
|
+
const absVideo = resolve36(process.cwd(), videoPath);
|
|
41571
41367
|
return absVideo.replace(/(\.[^.]+)$/, "-motion-overlay$1");
|
|
41572
41368
|
}
|
|
41573
41369
|
function assertValidRequest(options) {
|
|
@@ -41578,156 +41374,48 @@ function assertValidRequest(options) {
|
|
|
41578
41374
|
return "Provide a motion description, or pass --asset <logo.json|logo.lottie>.";
|
|
41579
41375
|
}
|
|
41580
41376
|
if (hasAsset) {
|
|
41581
|
-
const ext =
|
|
41377
|
+
const ext = extname9(options.asset).toLowerCase();
|
|
41582
41378
|
if (ext !== ".json" && ext !== ".lottie") {
|
|
41583
41379
|
return "Lottie overlay asset must be a .json or .lottie file.";
|
|
41584
41380
|
}
|
|
41585
41381
|
}
|
|
41586
41382
|
return void 0;
|
|
41587
41383
|
}
|
|
41588
|
-
function buildLottieTimelineState(opts) {
|
|
41589
|
-
const now = /* @__PURE__ */ new Date();
|
|
41590
|
-
const ratio = opts.width === opts.height ? "1:1" : opts.width < opts.height ? "9:16" : "16:9";
|
|
41591
|
-
return {
|
|
41592
|
-
project: {
|
|
41593
|
-
id: "motion-overlay",
|
|
41594
|
-
name: "Motion Overlay",
|
|
41595
|
-
createdAt: now,
|
|
41596
|
-
updatedAt: now,
|
|
41597
|
-
aspectRatio: ratio,
|
|
41598
|
-
frameRate: 30,
|
|
41599
|
-
duration: opts.duration
|
|
41600
|
-
},
|
|
41601
|
-
tracks: [
|
|
41602
|
-
{
|
|
41603
|
-
id: "track-video",
|
|
41604
|
-
name: "Video",
|
|
41605
|
-
type: "video",
|
|
41606
|
-
order: 0,
|
|
41607
|
-
isMuted: false,
|
|
41608
|
-
isLocked: false,
|
|
41609
|
-
isVisible: true
|
|
41610
|
-
},
|
|
41611
|
-
{
|
|
41612
|
-
id: "track-overlay",
|
|
41613
|
-
name: "Motion Overlay",
|
|
41614
|
-
type: "lottie",
|
|
41615
|
-
order: 1,
|
|
41616
|
-
isMuted: false,
|
|
41617
|
-
isLocked: false,
|
|
41618
|
-
isVisible: true
|
|
41619
|
-
}
|
|
41620
|
-
],
|
|
41621
|
-
sources: [
|
|
41622
|
-
{
|
|
41623
|
-
id: "source-video",
|
|
41624
|
-
name: basename10(opts.videoPath),
|
|
41625
|
-
type: "video",
|
|
41626
|
-
url: opts.videoPath,
|
|
41627
|
-
duration: opts.duration,
|
|
41628
|
-
width: opts.width,
|
|
41629
|
-
height: opts.height
|
|
41630
|
-
},
|
|
41631
|
-
{
|
|
41632
|
-
id: "source-lottie",
|
|
41633
|
-
name: basename10(opts.assetPath),
|
|
41634
|
-
type: "lottie",
|
|
41635
|
-
url: opts.assetPath,
|
|
41636
|
-
duration: opts.overlayDuration
|
|
41637
|
-
}
|
|
41638
|
-
],
|
|
41639
|
-
clips: [
|
|
41640
|
-
{
|
|
41641
|
-
id: "clip-video",
|
|
41642
|
-
sourceId: "source-video",
|
|
41643
|
-
trackId: "track-video",
|
|
41644
|
-
startTime: 0,
|
|
41645
|
-
duration: opts.duration,
|
|
41646
|
-
sourceStartOffset: 0,
|
|
41647
|
-
sourceEndOffset: opts.duration,
|
|
41648
|
-
effects: []
|
|
41649
|
-
},
|
|
41650
|
-
{
|
|
41651
|
-
id: "clip-lottie",
|
|
41652
|
-
sourceId: "source-lottie",
|
|
41653
|
-
trackId: "track-overlay",
|
|
41654
|
-
startTime: opts.overlayStart,
|
|
41655
|
-
duration: opts.overlayDuration,
|
|
41656
|
-
sourceStartOffset: 0,
|
|
41657
|
-
sourceEndOffset: opts.overlayDuration,
|
|
41658
|
-
effects: [
|
|
41659
|
-
{
|
|
41660
|
-
id: "effect-motion-overlay",
|
|
41661
|
-
type: "custom",
|
|
41662
|
-
startTime: 0,
|
|
41663
|
-
duration: opts.overlayDuration,
|
|
41664
|
-
params: {
|
|
41665
|
-
kind: "motion-overlay",
|
|
41666
|
-
position: opts.position,
|
|
41667
|
-
scale: opts.scale,
|
|
41668
|
-
opacity: opts.opacity,
|
|
41669
|
-
loop: opts.loop
|
|
41670
|
-
}
|
|
41671
|
-
}
|
|
41672
|
-
]
|
|
41673
|
-
}
|
|
41674
|
-
],
|
|
41675
|
-
transitions: [],
|
|
41676
|
-
currentTime: 0,
|
|
41677
|
-
isPlaying: false,
|
|
41678
|
-
zoom: 50,
|
|
41679
|
-
scrollX: 0,
|
|
41680
|
-
selectedClipIds: [],
|
|
41681
|
-
selectedTrackId: null
|
|
41682
|
-
};
|
|
41683
|
-
}
|
|
41684
41384
|
async function executeMotionOverlay(options) {
|
|
41685
41385
|
const validationError = assertValidRequest(options);
|
|
41686
41386
|
if (validationError) return { success: false, error: validationError };
|
|
41687
|
-
const absVideo =
|
|
41688
|
-
if (!
|
|
41689
|
-
const outputPath = options.output ?
|
|
41387
|
+
const absVideo = resolve36(process.cwd(), options.videoPath);
|
|
41388
|
+
if (!existsSync35(absVideo)) return { success: false, error: `Video file not found: ${absVideo}` };
|
|
41389
|
+
const outputPath = options.output ? resolve36(process.cwd(), options.output) : defaultOverlayOutput(options.videoPath);
|
|
41690
41390
|
if (options.asset) {
|
|
41691
|
-
const absAsset =
|
|
41692
|
-
if (!
|
|
41693
|
-
const
|
|
41694
|
-
ffprobeDuration(absVideo),
|
|
41695
|
-
ffprobeVideoSize(absVideo)
|
|
41696
|
-
]);
|
|
41391
|
+
const absAsset = resolve36(process.cwd(), options.asset);
|
|
41392
|
+
if (!existsSync35(absAsset)) return { success: false, error: `Lottie asset not found: ${absAsset}` };
|
|
41393
|
+
const videoDuration = await ffprobeDuration(absVideo);
|
|
41697
41394
|
const start = Math.max(0, options.start ?? 0);
|
|
41698
|
-
|
|
41699
|
-
|
|
41395
|
+
if (start >= videoDuration) {
|
|
41396
|
+
return { success: false, error: `--start ${start}s is past the end of the video (${videoDuration.toFixed(2)}s).` };
|
|
41397
|
+
}
|
|
41398
|
+
const remaining = videoDuration - start;
|
|
41700
41399
|
const position = normalizePosition(options.position);
|
|
41701
|
-
|
|
41702
|
-
const
|
|
41703
|
-
|
|
41704
|
-
|
|
41705
|
-
const backend = createHyperframesBackend();
|
|
41706
|
-
const result2 = await backend.render({
|
|
41707
|
-
projectState: buildLottieTimelineState({
|
|
41708
|
-
videoPath: absVideo,
|
|
41709
|
-
assetPath: absAsset,
|
|
41710
|
-
duration: videoDuration,
|
|
41711
|
-
overlayStart: start,
|
|
41712
|
-
overlayDuration,
|
|
41713
|
-
width: size.width,
|
|
41714
|
-
height: size.height,
|
|
41715
|
-
position,
|
|
41716
|
-
scale,
|
|
41717
|
-
opacity,
|
|
41718
|
-
loop
|
|
41719
|
-
}),
|
|
41400
|
+
await mkdir20(dirname15(outputPath), { recursive: true });
|
|
41401
|
+
const result2 = await renderLottieOverlay({
|
|
41402
|
+
videoPath: absVideo,
|
|
41403
|
+
assetPath: absAsset,
|
|
41720
41404
|
outputPath,
|
|
41721
|
-
|
|
41722
|
-
|
|
41723
|
-
|
|
41724
|
-
|
|
41405
|
+
start,
|
|
41406
|
+
duration: Math.min(options.duration ?? remaining, remaining),
|
|
41407
|
+
position,
|
|
41408
|
+
scale: Math.max(0.01, Math.min(2, numberOption(options.scale, position === "full" ? 1 : 0.25))),
|
|
41409
|
+
opacity: Math.max(0, Math.min(1, numberOption(options.opacity, 1))),
|
|
41410
|
+
loop: options.loop ?? true
|
|
41725
41411
|
});
|
|
41726
|
-
if (!result2.success)
|
|
41412
|
+
if (!result2.success) {
|
|
41413
|
+
return { success: false, error: result2.error ?? "Lottie overlay failed", suggestion: result2.suggestion, retryable: false };
|
|
41414
|
+
}
|
|
41727
41415
|
return { success: true, outputPath, provider: "lottie" };
|
|
41728
41416
|
}
|
|
41729
41417
|
const duration = options.duration ?? await ffprobeDuration(absVideo).catch(() => void 0);
|
|
41730
|
-
await mkdir20(
|
|
41418
|
+
await mkdir20(dirname15(outputPath), { recursive: true });
|
|
41731
41419
|
const result = await executeMotion({
|
|
41732
41420
|
description: options.description.trim(),
|
|
41733
41421
|
video: absVideo,
|
|
@@ -41798,7 +41486,8 @@ function registerMotionOverlayCommand(parent) {
|
|
|
41798
41486
|
const result = await executeMotionOverlay(parsed);
|
|
41799
41487
|
if (!result.success) {
|
|
41800
41488
|
spinner2.fail(result.error ?? "Motion overlay failed");
|
|
41801
|
-
|
|
41489
|
+
const message = result.error ?? "Motion overlay failed";
|
|
41490
|
+
exitWithError(result.retryable === false ? generalError(message, result.suggestion) : apiError(message, true));
|
|
41802
41491
|
}
|
|
41803
41492
|
spinner2.succeed(source_default.green("Motion overlay applied"));
|
|
41804
41493
|
if (isJsonMode()) {
|
|
@@ -41831,7 +41520,7 @@ var init_motion_overlay = __esm({
|
|
|
41831
41520
|
init_ora();
|
|
41832
41521
|
init_ai_motion();
|
|
41833
41522
|
init_exec_safe();
|
|
41834
|
-
|
|
41523
|
+
init_lottie_overlay();
|
|
41835
41524
|
init_output();
|
|
41836
41525
|
init_validate();
|
|
41837
41526
|
VALID_POSITIONS = [
|
|
@@ -41848,16 +41537,15 @@ var init_motion_overlay = __esm({
|
|
|
41848
41537
|
// src/commands/ai-image.ts
|
|
41849
41538
|
var ai_image_exports = {};
|
|
41850
41539
|
__export(ai_image_exports, {
|
|
41851
|
-
executeGeminiEdit: () => executeGeminiEdit,
|
|
41852
41540
|
executeImageEdit: () => executeImageEdit,
|
|
41853
41541
|
executeImageGenerate: () => executeImageGenerate,
|
|
41854
41542
|
executeThumbnailBestFrame: () => executeThumbnailBestFrame
|
|
41855
41543
|
});
|
|
41856
|
-
import { readFile as
|
|
41857
|
-
import { existsSync as
|
|
41858
|
-
function numberedPath(
|
|
41859
|
-
const dot =
|
|
41860
|
-
return dot >
|
|
41544
|
+
import { readFile as readFile27 } from "node:fs/promises";
|
|
41545
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
41546
|
+
function numberedPath(path, n) {
|
|
41547
|
+
const dot = path.lastIndexOf(".");
|
|
41548
|
+
return dot > path.lastIndexOf("/") ? `${path.slice(0, dot)}-${n}${path.slice(dot)}` : `${path}-${n}`;
|
|
41861
41549
|
}
|
|
41862
41550
|
function imageFailure(error, prefix, provider) {
|
|
41863
41551
|
if (isProviderError(error)) return { success: false, error: error.message, errorKind: error.kind, provider };
|
|
@@ -41902,7 +41590,7 @@ async function executeImageEdit(options) {
|
|
|
41902
41590
|
const provider = options.provider ?? "gemini";
|
|
41903
41591
|
try {
|
|
41904
41592
|
const generator = await openImageGenerator(provider, options.apiKey);
|
|
41905
|
-
const images = await Promise.all(options.imagePaths.map((
|
|
41593
|
+
const images = await Promise.all(options.imagePaths.map((path) => readImageInput(path)));
|
|
41906
41594
|
const result = await generator.createImage({
|
|
41907
41595
|
prompt: options.prompt,
|
|
41908
41596
|
model: options.model,
|
|
@@ -41918,9 +41606,6 @@ async function executeImageEdit(options) {
|
|
|
41918
41606
|
return { success: false, error: failed.error, errorKind: failed.errorKind, provider };
|
|
41919
41607
|
}
|
|
41920
41608
|
}
|
|
41921
|
-
function executeGeminiEdit(options) {
|
|
41922
|
-
return executeImageEdit({ ...options, provider: "gemini" });
|
|
41923
|
-
}
|
|
41924
41609
|
async function executeThumbnailBestFrame(options) {
|
|
41925
41610
|
const {
|
|
41926
41611
|
videoPath,
|
|
@@ -41929,7 +41614,7 @@ async function executeThumbnailBestFrame(options) {
|
|
|
41929
41614
|
model = "flash",
|
|
41930
41615
|
apiKey
|
|
41931
41616
|
} = options;
|
|
41932
|
-
if (!
|
|
41617
|
+
if (!existsSync36(videoPath)) {
|
|
41933
41618
|
return { success: false, error: `Video not found: ${videoPath}` };
|
|
41934
41619
|
}
|
|
41935
41620
|
if (!commandExists("ffmpeg")) {
|
|
@@ -41942,7 +41627,7 @@ async function executeThumbnailBestFrame(options) {
|
|
|
41942
41627
|
try {
|
|
41943
41628
|
const gemini = new GeminiProvider();
|
|
41944
41629
|
await gemini.initialize({ apiKey: googleKey });
|
|
41945
|
-
const videoData = await
|
|
41630
|
+
const videoData = await readFile27(videoPath);
|
|
41946
41631
|
const analysisPrompt = prompt3 || 'Analyze this video and find the single best frame for a thumbnail. Look for frames that are visually striking, well-composed, emotionally engaging, and representative of the video content. Avoid blurry frames, transitions, or dark scenes. Return ONLY a JSON object: {"timestamp": <seconds as number>, "reason": "<brief explanation>"}';
|
|
41947
41632
|
const modelId = resolveGeminiTextModel(model);
|
|
41948
41633
|
const result = await gemini.analyzeVideo(videoData, analysisPrompt, {
|
|
@@ -41963,7 +41648,7 @@ async function executeThumbnailBestFrame(options) {
|
|
|
41963
41648
|
reason = reasonMatch[1];
|
|
41964
41649
|
}
|
|
41965
41650
|
await execSafe("ffmpeg", ["-ss", String(timestamp), "-i", videoPath, "-frames:v", "1", "-q:v", "2", outputPath, "-y"], { timeout: 6e4, maxBuffer: 50 * 1024 * 1024 });
|
|
41966
|
-
if (!
|
|
41651
|
+
if (!existsSync36(outputPath)) {
|
|
41967
41652
|
return { success: false, error: "FFmpeg failed to extract frame" };
|
|
41968
41653
|
}
|
|
41969
41654
|
return {
|
|
@@ -41999,14 +41684,14 @@ __export(edit_cmd_exports, {
|
|
|
41999
41684
|
executeSpeedRamp: () => executeSpeedRamp,
|
|
42000
41685
|
executeUpscale: () => executeUpscale
|
|
42001
41686
|
});
|
|
42002
|
-
import { resolve as
|
|
42003
|
-
import { readFile as
|
|
41687
|
+
import { resolve as resolve37 } from "node:path";
|
|
41688
|
+
import { readFile as readFile28, writeFile as writeFile28 } from "node:fs/promises";
|
|
42004
41689
|
async function executeGrade(options) {
|
|
42005
41690
|
const { videoPath, style, preset, output, analyzeOnly, apiKey } = options;
|
|
42006
41691
|
try {
|
|
42007
41692
|
if (!style && !preset) return { success: false, error: "Either style or preset is required" };
|
|
42008
41693
|
if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
|
|
42009
|
-
const absPath =
|
|
41694
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42010
41695
|
let gradeResult;
|
|
42011
41696
|
if (preset) {
|
|
42012
41697
|
const claude = new ClaudeProvider();
|
|
@@ -42021,7 +41706,7 @@ async function executeGrade(options) {
|
|
|
42021
41706
|
if (analyzeOnly) {
|
|
42022
41707
|
return { success: true, style: preset || style, description: gradeResult.description, ffmpegFilter: gradeResult.ffmpegFilter };
|
|
42023
41708
|
}
|
|
42024
|
-
const outputPath = output ?
|
|
41709
|
+
const outputPath = output ? resolve37(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
|
|
42025
41710
|
await execSafe("ffmpeg", ["-i", absPath, "-vf", gradeResult.ffmpegFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
|
|
42026
41711
|
return { success: true, outputPath, style: preset || style, description: gradeResult.description, ffmpegFilter: gradeResult.ffmpegFilter };
|
|
42027
41712
|
} catch (error) {
|
|
@@ -42036,7 +41721,7 @@ async function executeSpeedRamp(options) {
|
|
|
42036
41721
|
const claudeKey = apiKey || process.env.ANTHROPIC_API_KEY;
|
|
42037
41722
|
if (!openaiKey) return { success: false, error: "OPENAI_API_KEY required for Whisper transcription" };
|
|
42038
41723
|
if (!claudeKey) return { success: false, error: "ANTHROPIC_API_KEY required for Claude analysis" };
|
|
42039
|
-
const absPath =
|
|
41724
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42040
41725
|
const tempAudio = absPath.replace(/(\.[^.]+)$/, "-temp-audio.mp3");
|
|
42041
41726
|
await execSafe("ffmpeg", ["-i", absPath, "-vn", "-acodec", "libmp3lame", "-q:a", "2", tempAudio, "-y"]);
|
|
42042
41727
|
const transcript = await transcribeAudioFile(tempAudio, { apiKey: openaiKey, language });
|
|
@@ -42058,7 +41743,7 @@ async function executeSpeedRamp(options) {
|
|
|
42058
41743
|
if (speedResult.keyframes.length < 2) {
|
|
42059
41744
|
return { success: false, error: "Not enough keyframes for speed ramping" };
|
|
42060
41745
|
}
|
|
42061
|
-
const outputPath = output ?
|
|
41746
|
+
const outputPath = output ? resolve37(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
|
|
42062
41747
|
const setpts = `setpts=${(1 / avgSpeed).toFixed(3)}*PTS`;
|
|
42063
41748
|
const atempo = avgSpeed >= 0.5 && avgSpeed <= 2 ? `atempo=${avgSpeed.toFixed(3)}` : "";
|
|
42064
41749
|
if (atempo) {
|
|
@@ -42075,7 +41760,7 @@ async function executeReframe(options) {
|
|
|
42075
41760
|
const { videoPath, aspect = "9:16", output, analyzeOnly } = options;
|
|
42076
41761
|
try {
|
|
42077
41762
|
if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
|
|
42078
|
-
const absPath =
|
|
41763
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42079
41764
|
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
42080
41765
|
"-v",
|
|
42081
41766
|
"error",
|
|
@@ -42110,7 +41795,7 @@ async function executeReframe(options) {
|
|
|
42110
41795
|
keyframeCount: 1
|
|
42111
41796
|
};
|
|
42112
41797
|
}
|
|
42113
|
-
const outputPath = output ?
|
|
41798
|
+
const outputPath = output ? resolve37(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, `-${aspect.replace(":", "x")}$1`);
|
|
42114
41799
|
await execSafe("ffmpeg", ["-i", absPath, "-vf", `crop=${cropWidth}:${cropHeight}:${cropX}:${cropY}`, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
|
|
42115
41800
|
return { success: true, outputPath, sourceAspect: `${sourceWidth}:${sourceHeight}`, targetAspect: aspect };
|
|
42116
41801
|
} catch (error) {
|
|
@@ -42122,7 +41807,7 @@ async function executeInterpolate(options) {
|
|
|
42122
41807
|
try {
|
|
42123
41808
|
if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
|
|
42124
41809
|
if (![2, 4, 8].includes(factor)) return { success: false, error: "Factor must be 2, 4, or 8" };
|
|
42125
|
-
const absPath =
|
|
41810
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42126
41811
|
const { stdout: fpsOut } = await execSafe("ffprobe", [
|
|
42127
41812
|
"-v",
|
|
42128
41813
|
"error",
|
|
@@ -42138,7 +41823,7 @@ async function executeInterpolate(options) {
|
|
|
42138
41823
|
const originalFps = num / (den || 1);
|
|
42139
41824
|
const targetFps = options.fps || originalFps * factor;
|
|
42140
41825
|
const mi = quality === "fast" ? "mi_mode=mci" : "mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1";
|
|
42141
|
-
const outputPath = output ?
|
|
41826
|
+
const outputPath = output ? resolve37(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
|
|
42142
41827
|
await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 6e5 });
|
|
42143
41828
|
return { success: true, outputPath, originalFps, targetFps, factor };
|
|
42144
41829
|
} catch (error) {
|
|
@@ -42149,7 +41834,7 @@ async function executeUpscale(options) {
|
|
|
42149
41834
|
const { videoPath, output, scale = 2, quality = "quality" } = options;
|
|
42150
41835
|
try {
|
|
42151
41836
|
if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
|
|
42152
|
-
const absPath =
|
|
41837
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42153
41838
|
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
42154
41839
|
"-v",
|
|
42155
41840
|
"error",
|
|
@@ -42165,7 +41850,7 @@ async function executeUpscale(options) {
|
|
|
42165
41850
|
const targetW = w * scale;
|
|
42166
41851
|
const targetH = h * scale;
|
|
42167
41852
|
const scaleFilter = quality === "quality" ? `scale=${targetW}:${targetH}:flags=lanczos` : `scale=${targetW}:${targetH}`;
|
|
42168
|
-
const outputPath = output ?
|
|
41853
|
+
const outputPath = output ? resolve37(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, `-${scale}x$1`);
|
|
42169
41854
|
await execSafe("ffmpeg", ["-i", absPath, "-vf", scaleFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
|
|
42170
41855
|
return { success: true, outputPath, originalRes: `${w}x${h}`, targetRes: `${targetW}x${targetH}` };
|
|
42171
41856
|
} catch (error) {
|
|
@@ -42244,7 +41929,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42244
41929
|
dryRun: true,
|
|
42245
41930
|
data: {
|
|
42246
41931
|
params: {
|
|
42247
|
-
videoPath:
|
|
41932
|
+
videoPath: resolve37(process.cwd(), videoPath),
|
|
42248
41933
|
style: options.style || options.preset,
|
|
42249
41934
|
analyzeOnly: options.analyzeOnly || false
|
|
42250
41935
|
}
|
|
@@ -42271,8 +41956,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42271
41956
|
}
|
|
42272
41957
|
spinner2.succeed(source_default.green("Color grade analyzed"));
|
|
42273
41958
|
if (isJsonMode()) {
|
|
42274
|
-
const absPath2 =
|
|
42275
|
-
const gradeOutputPath = options.output ?
|
|
41959
|
+
const absPath2 = resolve37(process.cwd(), videoPath);
|
|
41960
|
+
const gradeOutputPath = options.output ? resolve37(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
|
|
42276
41961
|
outputSuccess({
|
|
42277
41962
|
command: "edit grade",
|
|
42278
41963
|
startedAt,
|
|
@@ -42298,8 +41983,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42298
41983
|
console.log(source_default.dim("Use without --analyze-only to apply the grade."));
|
|
42299
41984
|
return;
|
|
42300
41985
|
}
|
|
42301
|
-
const absPath =
|
|
42302
|
-
const outputPath = options.output ?
|
|
41986
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
41987
|
+
const outputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
|
|
42303
41988
|
spinner2.start("Applying color grade...");
|
|
42304
41989
|
await execSafe("ffmpeg", ["-i", absPath, "-vf", gradeResult.ffmpegFilter, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
|
|
42305
41990
|
spinner2.succeed(source_default.green("Color grade applied"));
|
|
@@ -42329,7 +42014,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42329
42014
|
dryRun: true,
|
|
42330
42015
|
data: {
|
|
42331
42016
|
params: {
|
|
42332
|
-
videoPath:
|
|
42017
|
+
videoPath: resolve37(process.cwd(), videoPath),
|
|
42333
42018
|
texts: options.text,
|
|
42334
42019
|
style: options.style,
|
|
42335
42020
|
fontSize: options.fontSize ? parseInt(options.fontSize) : void 0,
|
|
@@ -42342,8 +42027,8 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42342
42027
|
});
|
|
42343
42028
|
return;
|
|
42344
42029
|
}
|
|
42345
|
-
const absPath =
|
|
42346
|
-
const outputPath = options.output ?
|
|
42030
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42031
|
+
const outputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-overlay$1");
|
|
42347
42032
|
const spinner2 = ora("Applying text overlays...").start();
|
|
42348
42033
|
const result = await applyTextOverlays({
|
|
42349
42034
|
videoPath: absPath,
|
|
@@ -42401,7 +42086,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42401
42086
|
dryRun: true,
|
|
42402
42087
|
data: {
|
|
42403
42088
|
params: {
|
|
42404
|
-
videoPath:
|
|
42089
|
+
videoPath: resolve37(process.cwd(), videoPath),
|
|
42405
42090
|
style: options.style,
|
|
42406
42091
|
minSpeed: parseFloat(options.minSpeed),
|
|
42407
42092
|
maxSpeed: parseFloat(options.maxSpeed),
|
|
@@ -42413,7 +42098,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42413
42098
|
}
|
|
42414
42099
|
const openaiApiKey = await requireApiKey("OPENAI_API_KEY", "OpenAI");
|
|
42415
42100
|
const claudeApiKey = await requireApiKey("ANTHROPIC_API_KEY", "Anthropic", options.apiKey);
|
|
42416
|
-
const absPath =
|
|
42101
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42417
42102
|
const spinner2 = ora("Extracting audio...").start();
|
|
42418
42103
|
const { stdout: speedRampProbe } = await execSafe("ffprobe", [
|
|
42419
42104
|
"-v",
|
|
@@ -42454,7 +42139,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42454
42139
|
spinner2.succeed(source_default.green(`Found ${speedResult.keyframes.length} speed keyframes`));
|
|
42455
42140
|
if (isJsonMode()) {
|
|
42456
42141
|
const avgSpeed2 = speedResult.keyframes.reduce((sum, kf) => sum + kf.speed, 0) / speedResult.keyframes.length;
|
|
42457
|
-
const speedRampOutputPath = options.output ?
|
|
42142
|
+
const speedRampOutputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
|
|
42458
42143
|
outputSuccess({
|
|
42459
42144
|
command: "edit speed-ramp",
|
|
42460
42145
|
startedAt,
|
|
@@ -42483,7 +42168,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42483
42168
|
return;
|
|
42484
42169
|
}
|
|
42485
42170
|
spinner2.start("Applying speed ramps...");
|
|
42486
|
-
const outputPath = options.output ?
|
|
42171
|
+
const outputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
|
|
42487
42172
|
const avgSpeed = speedResult.keyframes.reduce((sum, kf) => sum + kf.speed, 0) / speedResult.keyframes.length;
|
|
42488
42173
|
const setpts = `setpts=${(1 / avgSpeed).toFixed(3)}*PTS`;
|
|
42489
42174
|
const atempo = avgSpeed >= 0.5 && avgSpeed <= 2 ? `atempo=${avgSpeed.toFixed(3)}` : "";
|
|
@@ -42517,7 +42202,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42517
42202
|
dryRun: true,
|
|
42518
42203
|
data: {
|
|
42519
42204
|
params: {
|
|
42520
|
-
videoPath:
|
|
42205
|
+
videoPath: resolve37(process.cwd(), videoPath),
|
|
42521
42206
|
aspect: options.aspect,
|
|
42522
42207
|
focus: options.focus,
|
|
42523
42208
|
analyzeOnly: options.analyzeOnly || false
|
|
@@ -42526,7 +42211,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42526
42211
|
});
|
|
42527
42212
|
return;
|
|
42528
42213
|
}
|
|
42529
|
-
const absPath =
|
|
42214
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42530
42215
|
const spinner2 = ora("Analyzing video...").start();
|
|
42531
42216
|
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
42532
42217
|
"-v",
|
|
@@ -42564,7 +42249,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42564
42249
|
for (let i = 1; i <= numKeyframes && i <= 30; i++) {
|
|
42565
42250
|
const framePath = `${tempDir}/frame-${i.toString().padStart(4, "0")}.jpg`;
|
|
42566
42251
|
try {
|
|
42567
|
-
const frameBuffer = await
|
|
42252
|
+
const frameBuffer = await readFile28(framePath);
|
|
42568
42253
|
const frameBase64 = frameBuffer.toString("base64");
|
|
42569
42254
|
const result = await claude.analyzeFrameForReframe(frameBase64, options.aspect, {
|
|
42570
42255
|
focusMode: options.focus,
|
|
@@ -42588,7 +42273,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42588
42273
|
}
|
|
42589
42274
|
spinner2.succeed(source_default.green(`Analyzed ${cropKeyframes.length} keyframes`));
|
|
42590
42275
|
if (isJsonMode()) {
|
|
42591
|
-
const reframeOutputPath = options.output ?
|
|
42276
|
+
const reframeOutputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
|
|
42592
42277
|
outputSuccess({
|
|
42593
42278
|
command: "edit reframe",
|
|
42594
42279
|
startedAt,
|
|
@@ -42623,7 +42308,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42623
42308
|
}
|
|
42624
42309
|
console.log();
|
|
42625
42310
|
if (options.keyframes) {
|
|
42626
|
-
const keyframesPath =
|
|
42311
|
+
const keyframesPath = resolve37(process.cwd(), options.keyframes);
|
|
42627
42312
|
await writeFile28(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
|
|
42628
42313
|
console.log(source_default.green(`Keyframes saved to: ${keyframesPath}`));
|
|
42629
42314
|
}
|
|
@@ -42635,7 +42320,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42635
42320
|
const avgCropY = Math.round(cropKeyframes.reduce((sum, kf) => sum + kf.cropY, 0) / cropKeyframes.length);
|
|
42636
42321
|
const cropWidth = cropKeyframes[0]?.cropWidth || sourceWidth;
|
|
42637
42322
|
const cropHeight = cropKeyframes[0]?.cropHeight || sourceHeight;
|
|
42638
|
-
const outputPath = options.output ?
|
|
42323
|
+
const outputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
|
|
42639
42324
|
spinner2.start("Applying reframe...");
|
|
42640
42325
|
await execSafe("ffmpeg", ["-i", absPath, "-vf", `crop=${cropWidth}:${cropHeight}:${avgCropX}:${avgCropY}`, "-c:a", "copy", outputPath, "-y"], { timeout: 6e5 });
|
|
42641
42326
|
spinner2.succeed(source_default.green("Reframe applied"));
|
|
@@ -42672,7 +42357,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42672
42357
|
dryRun: true,
|
|
42673
42358
|
data: {
|
|
42674
42359
|
params: {
|
|
42675
|
-
imagePaths: imagePaths.map((p) =>
|
|
42360
|
+
imagePaths: imagePaths.map((p) => resolve37(process.cwd(), p)),
|
|
42676
42361
|
prompt: prompt3,
|
|
42677
42362
|
provider,
|
|
42678
42363
|
model: modelSpec.id,
|
|
@@ -42717,7 +42402,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42717
42402
|
if (options.output) {
|
|
42718
42403
|
validateOutputPath(options.output);
|
|
42719
42404
|
}
|
|
42720
|
-
const absPath =
|
|
42405
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42721
42406
|
const factor = parseInt(options.factor);
|
|
42722
42407
|
if (![2, 4, 8].includes(factor)) {
|
|
42723
42408
|
exitWithError(usageError("Factor must be 2, 4, or 8"));
|
|
@@ -42738,7 +42423,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42738
42423
|
});
|
|
42739
42424
|
return;
|
|
42740
42425
|
}
|
|
42741
|
-
const outputPath = options.output ?
|
|
42426
|
+
const outputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
|
|
42742
42427
|
const spinner2 = ora(`Creating ${factor}x slow motion...`).start();
|
|
42743
42428
|
try {
|
|
42744
42429
|
const { stdout: fpsOut } = await execSafe("ffprobe", [
|
|
@@ -42799,7 +42484,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42799
42484
|
if (options.output) {
|
|
42800
42485
|
validateOutputPath(options.output);
|
|
42801
42486
|
}
|
|
42802
|
-
const absPath =
|
|
42487
|
+
const absPath = resolve37(process.cwd(), videoPath);
|
|
42803
42488
|
const scale = parseInt(options.scale);
|
|
42804
42489
|
if (scale !== 2 && scale !== 4) {
|
|
42805
42490
|
exitWithError(usageError("Scale must be 2 or 4"));
|
|
@@ -42821,7 +42506,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42821
42506
|
return;
|
|
42822
42507
|
}
|
|
42823
42508
|
if (options.ffmpeg) {
|
|
42824
|
-
const outputPath = options.output ?
|
|
42509
|
+
const outputPath = options.output ? resolve37(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-upscaled-${scale}x$1`);
|
|
42825
42510
|
const spinner3 = ora(`Upscaling video with FFmpeg (${scale}x)...`).start();
|
|
42826
42511
|
try {
|
|
42827
42512
|
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
@@ -42900,12 +42585,11 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
42900
42585
|
var ai_analyze_exports = {};
|
|
42901
42586
|
__export(ai_analyze_exports, {
|
|
42902
42587
|
executeAnalyze: () => executeAnalyze,
|
|
42903
|
-
executeGeminiVideo: () => executeGeminiVideo
|
|
42904
|
-
registerAnalyzeCommands: () => registerAnalyzeCommands
|
|
42588
|
+
executeGeminiVideo: () => executeGeminiVideo
|
|
42905
42589
|
});
|
|
42906
|
-
import { readFile as
|
|
42907
|
-
import { extname as
|
|
42908
|
-
import { existsSync as
|
|
42590
|
+
import { readFile as readFile29 } from "node:fs/promises";
|
|
42591
|
+
import { extname as extname10, resolve as resolve39 } from "node:path";
|
|
42592
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
42909
42593
|
async function executeGeminiVideo(options) {
|
|
42910
42594
|
try {
|
|
42911
42595
|
const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
|
|
@@ -42918,11 +42602,11 @@ async function executeGeminiVideo(options) {
|
|
|
42918
42602
|
if (isYouTube) {
|
|
42919
42603
|
videoData = options.source;
|
|
42920
42604
|
} else {
|
|
42921
|
-
const absPath =
|
|
42922
|
-
if (!
|
|
42605
|
+
const absPath = resolve39(process.cwd(), options.source);
|
|
42606
|
+
if (!existsSync38(absPath)) {
|
|
42923
42607
|
return { success: false, error: `File not found: ${absPath}` };
|
|
42924
42608
|
}
|
|
42925
|
-
videoData = await
|
|
42609
|
+
videoData = await readFile29(absPath);
|
|
42926
42610
|
}
|
|
42927
42611
|
const gemini = new GeminiProvider();
|
|
42928
42612
|
await gemini.initialize({ apiKey });
|
|
@@ -42961,7 +42645,7 @@ async function executeAnalyze(options) {
|
|
|
42961
42645
|
const isYouTube = source.includes("youtube.com") || source.includes("youtu.be");
|
|
42962
42646
|
const isImageUrl = /^https?:\/\/.+\.(png|jpg|jpeg|webp|gif)(\?.*)?$/i.test(source);
|
|
42963
42647
|
const isVideoUrl = /^https?:\/\/.+\.(mp4|mov|webm)(\?.*)?$/i.test(source);
|
|
42964
|
-
const ext =
|
|
42648
|
+
const ext = extname10(source).toLowerCase();
|
|
42965
42649
|
const imageExts = [".png", ".jpg", ".jpeg", ".webp", ".gif"];
|
|
42966
42650
|
const videoExts = [".mp4", ".mov", ".webm", ".avi", ".mkv"];
|
|
42967
42651
|
const isLocalImage = imageExts.includes(ext);
|
|
@@ -42986,11 +42670,11 @@ async function executeAnalyze(options) {
|
|
|
42986
42670
|
}
|
|
42987
42671
|
imageBuffer = Buffer.from(await response.arrayBuffer());
|
|
42988
42672
|
} else {
|
|
42989
|
-
const absPath =
|
|
42990
|
-
if (!
|
|
42673
|
+
const absPath = resolve39(process.cwd(), source);
|
|
42674
|
+
if (!existsSync38(absPath)) {
|
|
42991
42675
|
return { success: false, error: `File not found: ${absPath}` };
|
|
42992
42676
|
}
|
|
42993
|
-
imageBuffer = await
|
|
42677
|
+
imageBuffer = await readFile29(absPath);
|
|
42994
42678
|
}
|
|
42995
42679
|
const result2 = await gemini.analyzeImage(imageBuffer, options.prompt, {
|
|
42996
42680
|
model: modelId,
|
|
@@ -43021,11 +42705,11 @@ async function executeAnalyze(options) {
|
|
|
43021
42705
|
}
|
|
43022
42706
|
videoData = Buffer.from(await response.arrayBuffer());
|
|
43023
42707
|
} else {
|
|
43024
|
-
const absPath =
|
|
43025
|
-
if (!
|
|
42708
|
+
const absPath = resolve39(process.cwd(), source);
|
|
42709
|
+
if (!existsSync38(absPath)) {
|
|
43026
42710
|
return { success: false, error: `File not found: ${absPath}` };
|
|
43027
42711
|
}
|
|
43028
|
-
videoData = await
|
|
42712
|
+
videoData = await readFile29(absPath);
|
|
43029
42713
|
}
|
|
43030
42714
|
const result = await gemini.analyzeVideo(videoData, options.prompt, {
|
|
43031
42715
|
model: modelId,
|
|
@@ -43053,103 +42737,11 @@ async function executeAnalyze(options) {
|
|
|
43053
42737
|
};
|
|
43054
42738
|
}
|
|
43055
42739
|
}
|
|
43056
|
-
function registerAnalyzeCommands(aiCommand) {
|
|
43057
|
-
aiCommand.command("gemini-video").description("Analyze video using Gemini (summarize, Q&A, extract info)").argument("<source>", "Video file path or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", `Model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("--fps <number>", "Frames per second (default: 1, higher for action)").option("--start <seconds>", "Start offset in seconds (for clipping)").option("--end <seconds>", "End offset in seconds (for clipping)").option("--low-res", "Use low resolution mode (fewer tokens, longer videos)").option("-v, --verbose", "Show token usage").action(async (source, prompt3, options) => {
|
|
43058
|
-
try {
|
|
43059
|
-
if (options.apiKey) {
|
|
43060
|
-
process.env.GOOGLE_API_KEY = options.apiKey;
|
|
43061
|
-
} else {
|
|
43062
|
-
const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
|
|
43063
|
-
if (!apiKey) {
|
|
43064
|
-
exitWithError(authError("GOOGLE_API_KEY", "Google"));
|
|
43065
|
-
}
|
|
43066
|
-
}
|
|
43067
|
-
const spinner2 = ora("Analyzing video...").start();
|
|
43068
|
-
const result = await executeGeminiVideo({
|
|
43069
|
-
source,
|
|
43070
|
-
prompt: prompt3,
|
|
43071
|
-
model: options.model,
|
|
43072
|
-
fps: options.fps ? parseFloat(options.fps) : void 0,
|
|
43073
|
-
start: options.start ? parseInt(options.start, 10) : void 0,
|
|
43074
|
-
end: options.end ? parseInt(options.end, 10) : void 0,
|
|
43075
|
-
lowRes: options.lowRes
|
|
43076
|
-
});
|
|
43077
|
-
if (!result.success) {
|
|
43078
|
-
spinner2.fail("Video analysis failed");
|
|
43079
|
-
exitWithError(apiError(result.error || "Video analysis failed", true));
|
|
43080
|
-
}
|
|
43081
|
-
spinner2.succeed(source_default.green("Video analyzed"));
|
|
43082
|
-
console.log();
|
|
43083
|
-
console.log(result.response);
|
|
43084
|
-
console.log();
|
|
43085
|
-
if (options.verbose && result.totalTokens) {
|
|
43086
|
-
console.log(source_default.dim("-".repeat(40)));
|
|
43087
|
-
console.log(source_default.dim(`Model: ${result.model}`));
|
|
43088
|
-
if (result.promptTokens) {
|
|
43089
|
-
console.log(source_default.dim(`Prompt tokens: ${result.promptTokens.toLocaleString()}`));
|
|
43090
|
-
}
|
|
43091
|
-
if (result.responseTokens) {
|
|
43092
|
-
console.log(source_default.dim(`Response tokens: ${result.responseTokens.toLocaleString()}`));
|
|
43093
|
-
}
|
|
43094
|
-
console.log(source_default.dim(`Total tokens: ${result.totalTokens.toLocaleString()}`));
|
|
43095
|
-
}
|
|
43096
|
-
} catch (error) {
|
|
43097
|
-
exitWithError(apiError(`Video analysis failed: ${error instanceof Error ? error.message : String(error)}`, true));
|
|
43098
|
-
}
|
|
43099
|
-
});
|
|
43100
|
-
aiCommand.command("analyze").description("Analyze any media: images, videos, or YouTube URLs using Gemini").argument("<source>", "Image/video file path, image URL, or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", `Model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("--fps <number>", "Frames per second for video (default: 1)").option("--start <seconds>", "Start offset in seconds (video only)").option("--end <seconds>", "End offset in seconds (video only)").option("--low-res", "Use low resolution mode (fewer tokens)").option("-v, --verbose", "Show token usage").action(async (source, prompt3, options) => {
|
|
43101
|
-
try {
|
|
43102
|
-
if (options.apiKey) {
|
|
43103
|
-
process.env.GOOGLE_API_KEY = options.apiKey;
|
|
43104
|
-
} else {
|
|
43105
|
-
const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
|
|
43106
|
-
if (!apiKey) {
|
|
43107
|
-
exitWithError(authError("GOOGLE_API_KEY", "Google"));
|
|
43108
|
-
}
|
|
43109
|
-
}
|
|
43110
|
-
const spinner2 = ora("Analyzing source...").start();
|
|
43111
|
-
const result = await executeAnalyze({
|
|
43112
|
-
source,
|
|
43113
|
-
prompt: prompt3,
|
|
43114
|
-
model: options.model,
|
|
43115
|
-
fps: options.fps ? parseFloat(options.fps) : void 0,
|
|
43116
|
-
start: options.start ? parseInt(options.start, 10) : void 0,
|
|
43117
|
-
end: options.end ? parseInt(options.end, 10) : void 0,
|
|
43118
|
-
lowRes: options.lowRes
|
|
43119
|
-
});
|
|
43120
|
-
if (!result.success) {
|
|
43121
|
-
spinner2.fail("Analysis failed");
|
|
43122
|
-
exitWithError(apiError(result.error || "Analysis failed", true));
|
|
43123
|
-
}
|
|
43124
|
-
spinner2.succeed(source_default.green("Analysis complete"));
|
|
43125
|
-
console.log();
|
|
43126
|
-
console.log(result.response);
|
|
43127
|
-
console.log();
|
|
43128
|
-
if (options.verbose && result.totalTokens) {
|
|
43129
|
-
console.log(source_default.dim("-".repeat(40)));
|
|
43130
|
-
console.log(source_default.dim(`Source type: ${result.sourceType}`));
|
|
43131
|
-
console.log(source_default.dim(`Model: ${result.model}`));
|
|
43132
|
-
if (result.promptTokens) {
|
|
43133
|
-
console.log(source_default.dim(`Prompt tokens: ${result.promptTokens.toLocaleString()}`));
|
|
43134
|
-
}
|
|
43135
|
-
if (result.responseTokens) {
|
|
43136
|
-
console.log(source_default.dim(`Response tokens: ${result.responseTokens.toLocaleString()}`));
|
|
43137
|
-
}
|
|
43138
|
-
console.log(source_default.dim(`Total tokens: ${result.totalTokens.toLocaleString()}`));
|
|
43139
|
-
}
|
|
43140
|
-
} catch (error) {
|
|
43141
|
-
exitWithError(apiError(`Analysis failed: ${error instanceof Error ? error.message : String(error)}`, true));
|
|
43142
|
-
}
|
|
43143
|
-
});
|
|
43144
|
-
}
|
|
43145
42740
|
var init_ai_analyze = __esm({
|
|
43146
42741
|
"src/commands/ai-analyze.ts"() {
|
|
43147
42742
|
"use strict";
|
|
43148
|
-
init_source();
|
|
43149
|
-
init_ora();
|
|
43150
42743
|
init_dist2();
|
|
43151
42744
|
init_api_key();
|
|
43152
|
-
init_output();
|
|
43153
42745
|
}
|
|
43154
42746
|
});
|
|
43155
42747
|
|
|
@@ -43158,9 +42750,9 @@ var ai_review_exports = {};
|
|
|
43158
42750
|
__export(ai_review_exports, {
|
|
43159
42751
|
executeReview: () => executeReview
|
|
43160
42752
|
});
|
|
43161
|
-
import { readFile as
|
|
43162
|
-
import { resolve as
|
|
43163
|
-
import { existsSync as
|
|
42753
|
+
import { readFile as readFile32, rename as rename4 } from "node:fs/promises";
|
|
42754
|
+
import { resolve as resolve42 } from "node:path";
|
|
42755
|
+
import { existsSync as existsSync40 } from "node:fs";
|
|
43164
42756
|
function parseReviewFeedback(response) {
|
|
43165
42757
|
let cleaned = response.trim();
|
|
43166
42758
|
if (cleaned.startsWith("```json")) {
|
|
@@ -43191,8 +42783,8 @@ async function executeReview(options) {
|
|
|
43191
42783
|
verify = false,
|
|
43192
42784
|
model = "flash"
|
|
43193
42785
|
} = options;
|
|
43194
|
-
const absVideoPath =
|
|
43195
|
-
if (!
|
|
42786
|
+
const absVideoPath = resolve42(process.cwd(), videoPath);
|
|
42787
|
+
if (!existsSync40(absVideoPath)) {
|
|
43196
42788
|
return { success: false, error: `Video not found: ${absVideoPath}` };
|
|
43197
42789
|
}
|
|
43198
42790
|
const apiKey = process.env.GOOGLE_API_KEY || await getApiKey("GOOGLE_API_KEY", "Google");
|
|
@@ -43204,9 +42796,9 @@ async function executeReview(options) {
|
|
|
43204
42796
|
}
|
|
43205
42797
|
let storyboardContext = "";
|
|
43206
42798
|
if (storyboardPath) {
|
|
43207
|
-
const absStoryboardPath =
|
|
43208
|
-
if (
|
|
43209
|
-
const content = await
|
|
42799
|
+
const absStoryboardPath = resolve42(process.cwd(), storyboardPath);
|
|
42800
|
+
if (existsSync40(absStoryboardPath)) {
|
|
42801
|
+
const content = await readFile32(absStoryboardPath, "utf-8");
|
|
43210
42802
|
storyboardContext = `
|
|
43211
42803
|
|
|
43212
42804
|
Original storyboard for reference:
|
|
@@ -43248,7 +42840,7 @@ ${projectContext}` : "";
|
|
|
43248
42840
|
Score each category 1-10. Prefer beatIssues when you can map a problem to a storyboard beat or timestamp. Use the exact beatId values from the storyboard or beat timing summary, and include timeRange in seconds for every localized finding. In particular, flag narration/visual mismatches, overly static holds, and audio-visual sync problems as beatIssues. Use category issue arrays only for problems that cannot be localized to a beat. For fixable issues, provide an FFmpeg filter in autoFixable. Be specific and practical.${storyboardContext}${extraProjectContext}`;
|
|
43249
42841
|
const gemini = new GeminiProvider();
|
|
43250
42842
|
await gemini.initialize({ apiKey });
|
|
43251
|
-
const videoData = await
|
|
42843
|
+
const videoData = await readFile32(absVideoPath);
|
|
43252
42844
|
const analysisResult = await gemini.analyzeVideo(videoData, reviewPrompt, {
|
|
43253
42845
|
model: modelId
|
|
43254
42846
|
});
|
|
@@ -43269,7 +42861,7 @@ Score each category 1-10. Prefer beatIssues when you can map a problem to a stor
|
|
|
43269
42861
|
};
|
|
43270
42862
|
if (autoApply && feedback.autoFixable.length > 0) {
|
|
43271
42863
|
let currentInput = absVideoPath;
|
|
43272
|
-
const outputBase = options.outputPath ?
|
|
42864
|
+
const outputBase = options.outputPath ? resolve42(process.cwd(), options.outputPath) : absVideoPath.replace(/(\.[^.]+)$/, "-reviewed$1");
|
|
43273
42865
|
for (const fix of feedback.autoFixable) {
|
|
43274
42866
|
if (fix.type === "color_grade" && fix.ffmpegFilter) {
|
|
43275
42867
|
try {
|
|
@@ -43303,7 +42895,7 @@ Score each category 1-10. Prefer beatIssues when you can map a problem to a stor
|
|
|
43303
42895
|
}
|
|
43304
42896
|
}
|
|
43305
42897
|
if (verify && result.outputPath) {
|
|
43306
|
-
const verifyVideoData = await
|
|
42898
|
+
const verifyVideoData = await readFile32(result.outputPath);
|
|
43307
42899
|
const verifyResult = await gemini.analyzeVideo(
|
|
43308
42900
|
verifyVideoData,
|
|
43309
42901
|
'Rate this video overall quality on a scale of 1-10. Return ONLY a JSON object: {"score": <number>}',
|
|
@@ -43333,7 +42925,7 @@ var init_ai_review = __esm({
|
|
|
43333
42925
|
});
|
|
43334
42926
|
|
|
43335
42927
|
// src/commands/generate/sound-effect.ts
|
|
43336
|
-
import { resolve as
|
|
42928
|
+
import { resolve as resolve45 } from "node:path";
|
|
43337
42929
|
import { writeFile as writeFile31 } from "node:fs/promises";
|
|
43338
42930
|
async function executeSoundEffect(options) {
|
|
43339
42931
|
try {
|
|
@@ -43350,7 +42942,7 @@ async function executeSoundEffect(options) {
|
|
|
43350
42942
|
if (!result.success || !result.audioBuffer) {
|
|
43351
42943
|
return { success: false, error: result.error || "Sound effect generation failed", errorKind: result.errorKind };
|
|
43352
42944
|
}
|
|
43353
|
-
const outputPath =
|
|
42945
|
+
const outputPath = resolve45(process.cwd(), options.output || "sound-effect.mp3");
|
|
43354
42946
|
await writeFile31(outputPath, result.audioBuffer);
|
|
43355
42947
|
return { success: true, outputPath };
|
|
43356
42948
|
} catch (error) {
|
|
@@ -43490,10 +43082,10 @@ async function prompt2(question) {
|
|
|
43490
43082
|
input,
|
|
43491
43083
|
output: process.stdout
|
|
43492
43084
|
});
|
|
43493
|
-
return new Promise((
|
|
43085
|
+
return new Promise((resolve63) => {
|
|
43494
43086
|
rl.question(question, (answer) => {
|
|
43495
43087
|
rl.close();
|
|
43496
|
-
|
|
43088
|
+
resolve63(answer);
|
|
43497
43089
|
});
|
|
43498
43090
|
});
|
|
43499
43091
|
}
|
|
@@ -43509,18 +43101,18 @@ var init_tty = __esm({
|
|
|
43509
43101
|
|
|
43510
43102
|
// src/utils/audio-file.ts
|
|
43511
43103
|
import { mkdir as mkdir22, rm as rm8, writeFile as writeFile32 } from "node:fs/promises";
|
|
43512
|
-
import { dirname as
|
|
43513
|
-
async function writeAudioFile(
|
|
43514
|
-
await mkdir22(
|
|
43515
|
-
const wanted =
|
|
43104
|
+
import { dirname as dirname17, extname as extname11 } from "node:path";
|
|
43105
|
+
async function writeAudioFile(path, bytes, container) {
|
|
43106
|
+
await mkdir22(dirname17(path), { recursive: true });
|
|
43107
|
+
const wanted = extname11(path).toLowerCase();
|
|
43516
43108
|
if (!CONVERTIBLE.has(wanted) || wanted === `.${container}`) {
|
|
43517
|
-
await writeFile32(
|
|
43109
|
+
await writeFile32(path, bytes);
|
|
43518
43110
|
return;
|
|
43519
43111
|
}
|
|
43520
|
-
const source = `${
|
|
43112
|
+
const source = `${path}.source.${container}`;
|
|
43521
43113
|
await writeFile32(source, bytes);
|
|
43522
43114
|
try {
|
|
43523
|
-
await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source,
|
|
43115
|
+
await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source, path]);
|
|
43524
43116
|
} finally {
|
|
43525
43117
|
await rm8(source, { force: true });
|
|
43526
43118
|
}
|
|
@@ -43535,7 +43127,7 @@ var init_audio_file = __esm({
|
|
|
43535
43127
|
});
|
|
43536
43128
|
|
|
43537
43129
|
// src/commands/generate/speech.ts
|
|
43538
|
-
import { resolve as
|
|
43130
|
+
import { resolve as resolve46 } from "node:path";
|
|
43539
43131
|
async function executeSpeech(options) {
|
|
43540
43132
|
let tts;
|
|
43541
43133
|
try {
|
|
@@ -43551,7 +43143,7 @@ async function executeSpeech(options) {
|
|
|
43551
43143
|
if (!result.success || !result.audioBuffer) {
|
|
43552
43144
|
return { success: false, provider: tts.provider, error: result.error ?? "TTS generation failed", errorKind: result.errorKind };
|
|
43553
43145
|
}
|
|
43554
|
-
const outputPath =
|
|
43146
|
+
const outputPath = resolve46(process.cwd(), options.output || `narration.${tts.audioExtension}`);
|
|
43555
43147
|
await writeAudioFile(outputPath, result.audioBuffer, tts.audioExtension);
|
|
43556
43148
|
return { success: true, outputPath, characterCount: result.characterCount, provider: tts.provider, model: result.model };
|
|
43557
43149
|
}
|
|
@@ -43626,8 +43218,8 @@ var init_speech2 = __esm({
|
|
|
43626
43218
|
});
|
|
43627
43219
|
|
|
43628
43220
|
// src/commands/generate/thumbnail.ts
|
|
43629
|
-
import { resolve as
|
|
43630
|
-
import { existsSync as
|
|
43221
|
+
import { resolve as resolve47, dirname as dirname18, basename as basename12, extname as extname12 } from "node:path";
|
|
43222
|
+
import { existsSync as existsSync42 } from "node:fs";
|
|
43631
43223
|
import { writeFile as writeFile33, mkdir as mkdir23 } from "node:fs/promises";
|
|
43632
43224
|
function registerThumbnailCommand(parent) {
|
|
43633
43225
|
parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").action(async (description, options) => {
|
|
@@ -43638,8 +43230,8 @@ function registerThumbnailCommand(parent) {
|
|
|
43638
43230
|
validateOutputPath(options.output);
|
|
43639
43231
|
}
|
|
43640
43232
|
if (options.bestFrame) {
|
|
43641
|
-
const absVideoPath =
|
|
43642
|
-
if (!
|
|
43233
|
+
const absVideoPath = resolve47(process.cwd(), options.bestFrame);
|
|
43234
|
+
if (!existsSync42(absVideoPath)) {
|
|
43643
43235
|
exitWithError(notFoundError(absVideoPath));
|
|
43644
43236
|
}
|
|
43645
43237
|
if (!commandExists("ffmpeg")) {
|
|
@@ -43651,12 +43243,12 @@ function registerThumbnailCommand(parent) {
|
|
|
43651
43243
|
);
|
|
43652
43244
|
}
|
|
43653
43245
|
const apiKey2 = await requireApiKey("GOOGLE_API_KEY", "Google", options.apiKey);
|
|
43654
|
-
const name =
|
|
43246
|
+
const name = basename12(options.bestFrame, extname12(options.bestFrame));
|
|
43655
43247
|
const outputPath = options.output || `${name}-thumbnail.png`;
|
|
43656
43248
|
const spinner3 = ora("Analyzing video for best frame...").start();
|
|
43657
43249
|
const result2 = await executeThumbnailBestFrame({
|
|
43658
43250
|
videoPath: absVideoPath,
|
|
43659
|
-
outputPath:
|
|
43251
|
+
outputPath: resolve47(process.cwd(), outputPath),
|
|
43660
43252
|
prompt: options.prompt,
|
|
43661
43253
|
model: options.model,
|
|
43662
43254
|
apiKey: apiKey2
|
|
@@ -43718,8 +43310,8 @@ function registerThumbnailCommand(parent) {
|
|
|
43718
43310
|
} else {
|
|
43719
43311
|
throw new Error("No image data available");
|
|
43720
43312
|
}
|
|
43721
|
-
outputPath =
|
|
43722
|
-
await mkdir23(
|
|
43313
|
+
outputPath = resolve47(process.cwd(), options.output);
|
|
43314
|
+
await mkdir23(dirname18(outputPath), { recursive: true });
|
|
43723
43315
|
await writeFile33(outputPath, buffer);
|
|
43724
43316
|
}
|
|
43725
43317
|
outputSuccess({
|
|
@@ -43749,8 +43341,8 @@ function registerThumbnailCommand(parent) {
|
|
|
43749
43341
|
} else {
|
|
43750
43342
|
throw new Error("No image data available");
|
|
43751
43343
|
}
|
|
43752
|
-
const outputPath =
|
|
43753
|
-
await mkdir23(
|
|
43344
|
+
const outputPath = resolve47(process.cwd(), options.output);
|
|
43345
|
+
await mkdir23(dirname18(outputPath), { recursive: true });
|
|
43754
43346
|
await writeFile33(outputPath, buffer);
|
|
43755
43347
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
43756
43348
|
} catch {
|
|
@@ -44043,7 +43635,7 @@ Examples:
|
|
|
44043
43635
|
if (img.revisedPrompt) console.log(source_default.dim(` [${i + 1}] Revised prompt: ${img.revisedPrompt.slice(0, 100)}`));
|
|
44044
43636
|
}
|
|
44045
43637
|
if (result.outputPaths?.length) {
|
|
44046
|
-
for (const
|
|
43638
|
+
for (const path of result.outputPaths) console.log(source_default.green(`Saved to: ${path}`));
|
|
44047
43639
|
} else {
|
|
44048
43640
|
console.log(source_default.yellow("Use -o to save the generated image to a file"));
|
|
44049
43641
|
}
|
|
@@ -45011,8 +44603,8 @@ var init_dist3 = __esm({
|
|
|
45011
44603
|
});
|
|
45012
44604
|
|
|
45013
44605
|
// src/commands/generate/video.ts
|
|
45014
|
-
import { resolve as
|
|
45015
|
-
import { readFile as
|
|
44606
|
+
import { resolve as resolve48 } from "node:path";
|
|
44607
|
+
import { readFile as readFile34 } from "node:fs/promises";
|
|
45016
44608
|
function registerVideoCommand(parent) {
|
|
45017
44609
|
parent.command("video").alias("vid").description("Generate video using AI (Seedance, Grok, Kling, Runway, Veo, or Gemini Omni)").argument("[prompt]", "Text prompt describing the video (interactive if omitted)").option(
|
|
45018
44610
|
"-p, --provider <provider>",
|
|
@@ -45119,7 +44711,7 @@ Examples:
|
|
|
45119
44711
|
provider = resolved?.name ?? "grok";
|
|
45120
44712
|
}
|
|
45121
44713
|
if (options.image) {
|
|
45122
|
-
const imageBuffer = await
|
|
44714
|
+
const imageBuffer = await readFile34(resolve48(process.cwd(), options.image));
|
|
45123
44715
|
if (!options.ratio) {
|
|
45124
44716
|
const dimensions = imageSize(imageBuffer);
|
|
45125
44717
|
if (dimensions.width && dimensions.height) {
|
|
@@ -45345,7 +44937,7 @@ var init_sanitize = __esm({
|
|
|
45345
44937
|
});
|
|
45346
44938
|
|
|
45347
44939
|
// src/commands/generate/storyboard.ts
|
|
45348
|
-
import { resolve as
|
|
44940
|
+
import { resolve as resolve49 } from "node:path";
|
|
45349
44941
|
import { writeFile as writeFile34 } from "node:fs/promises";
|
|
45350
44942
|
async function executeStoryboard(options) {
|
|
45351
44943
|
const { content, duration, creativity = "low", output, apiKey } = options;
|
|
@@ -45364,7 +44956,7 @@ async function executeStoryboard(options) {
|
|
|
45364
44956
|
}
|
|
45365
44957
|
let outputPath;
|
|
45366
44958
|
if (output) {
|
|
45367
|
-
outputPath =
|
|
44959
|
+
outputPath = resolve49(process.cwd(), output);
|
|
45368
44960
|
await writeFile34(outputPath, JSON.stringify(segments, null, 2), "utf-8");
|
|
45369
44961
|
}
|
|
45370
44962
|
return { success: true, segments, segmentCount: segments.length, outputPath };
|
|
@@ -45387,7 +44979,6 @@ var init_storyboard = __esm({
|
|
|
45387
44979
|
var generate_exports = {};
|
|
45388
44980
|
__export(generate_exports, {
|
|
45389
44981
|
executeMusic: () => executeMusic,
|
|
45390
|
-
executeMusicStatus: () => executeMusicStatus,
|
|
45391
44982
|
executeSoundEffect: () => executeSoundEffect,
|
|
45392
44983
|
executeSpeech: () => executeSpeech,
|
|
45393
44984
|
executeStoryboard: () => executeStoryboard,
|
|
@@ -45413,7 +45004,6 @@ var init_generate = __esm({
|
|
|
45413
45004
|
init_video2();
|
|
45414
45005
|
init_cost_tier();
|
|
45415
45006
|
init_sound_effect();
|
|
45416
|
-
init_music_status();
|
|
45417
45007
|
init_storyboard();
|
|
45418
45008
|
init_speech2();
|
|
45419
45009
|
init_music();
|
|
@@ -46367,14 +45957,14 @@ __export(detect_exports, {
|
|
|
46367
45957
|
executeDetectScenes: () => executeDetectScenes,
|
|
46368
45958
|
executeDetectSilence: () => executeDetectSilence
|
|
46369
45959
|
});
|
|
46370
|
-
import { readFile as
|
|
46371
|
-
import { resolve as
|
|
45960
|
+
import { readFile as readFile39, writeFile as writeFile38 } from "node:fs/promises";
|
|
45961
|
+
import { resolve as resolve54, basename as basename14 } from "node:path";
|
|
46372
45962
|
async function executeDetectScenes(options) {
|
|
46373
45963
|
try {
|
|
46374
45964
|
if (!commandExists("ffmpeg")) {
|
|
46375
45965
|
return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
|
|
46376
45966
|
}
|
|
46377
|
-
const absPath =
|
|
45967
|
+
const absPath = resolve54(process.cwd(), options.videoPath);
|
|
46378
45968
|
const threshold = options.threshold ?? 0.3;
|
|
46379
45969
|
const { stdout: sceneStdout, stderr: sceneStderr } = await execSafe("ffmpeg", [
|
|
46380
45970
|
"-i",
|
|
@@ -46405,7 +45995,7 @@ async function executeDetectScenes(options) {
|
|
|
46405
45995
|
duration: (i < scenes.length - 1 ? scenes[i + 1].timestamp : totalDuration) - s.timestamp
|
|
46406
45996
|
}));
|
|
46407
45997
|
if (options.outputPath) {
|
|
46408
|
-
const outputPath =
|
|
45998
|
+
const outputPath = resolve54(process.cwd(), options.outputPath);
|
|
46409
45999
|
await writeFile38(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
|
|
46410
46000
|
}
|
|
46411
46001
|
return { success: true, scenes: result, totalDuration };
|
|
@@ -46418,7 +46008,7 @@ async function executeDetectSilence(options) {
|
|
|
46418
46008
|
if (!commandExists("ffmpeg")) {
|
|
46419
46009
|
return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
|
|
46420
46010
|
}
|
|
46421
|
-
const absPath =
|
|
46011
|
+
const absPath = resolve54(process.cwd(), options.mediaPath);
|
|
46422
46012
|
const noise = options.noise ?? "-30";
|
|
46423
46013
|
const duration = options.duration ?? "0.5";
|
|
46424
46014
|
const { stdout: silStdout, stderr: silStderr } = await execSafe("ffmpeg", [
|
|
@@ -46452,7 +46042,7 @@ async function executeDetectSilence(options) {
|
|
|
46452
46042
|
}
|
|
46453
46043
|
}
|
|
46454
46044
|
if (options.outputPath) {
|
|
46455
|
-
const outputPath =
|
|
46045
|
+
const outputPath = resolve54(process.cwd(), options.outputPath);
|
|
46456
46046
|
await writeFile38(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
|
|
46457
46047
|
}
|
|
46458
46048
|
return { success: true, silences };
|
|
@@ -46465,7 +46055,7 @@ async function executeDetectBeats(options) {
|
|
|
46465
46055
|
if (!commandExists("ffmpeg")) {
|
|
46466
46056
|
return { success: false, error: "FFmpeg not found. Install with: brew install ffmpeg" };
|
|
46467
46057
|
}
|
|
46468
|
-
const absPath =
|
|
46058
|
+
const absPath = resolve54(process.cwd(), options.audioPath);
|
|
46469
46059
|
const { stdout: beatStdout, stderr: beatStderr } = await execSafe("ffmpeg", [
|
|
46470
46060
|
"-i",
|
|
46471
46061
|
absPath,
|
|
@@ -46501,7 +46091,7 @@ async function executeDetectBeats(options) {
|
|
|
46501
46091
|
}
|
|
46502
46092
|
}
|
|
46503
46093
|
if (options.outputPath) {
|
|
46504
|
-
const outputPath =
|
|
46094
|
+
const outputPath = resolve54(process.cwd(), options.outputPath);
|
|
46505
46095
|
await writeFile38(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
|
|
46506
46096
|
}
|
|
46507
46097
|
return { success: true, beats, beatCount: beats.length };
|
|
@@ -46554,7 +46144,7 @@ var init_detect = __esm({
|
|
|
46554
46144
|
spinner2.fail("FFmpeg not found");
|
|
46555
46145
|
exitWithError(generalError("FFmpeg not found", "Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"));
|
|
46556
46146
|
}
|
|
46557
|
-
const absPath =
|
|
46147
|
+
const absPath = resolve54(process.cwd(), videoPath);
|
|
46558
46148
|
const threshold = parseFloat(options.threshold);
|
|
46559
46149
|
spinner2.text = "Analyzing video...";
|
|
46560
46150
|
const { stdout: sceneStdout, stderr: sceneStderr } = await execSafe("ffmpeg", [
|
|
@@ -46595,7 +46185,7 @@ var init_detect = __esm({
|
|
|
46595
46185
|
}
|
|
46596
46186
|
console.log();
|
|
46597
46187
|
if (options.output) {
|
|
46598
|
-
const outputPath =
|
|
46188
|
+
const outputPath = resolve54(process.cwd(), options.output);
|
|
46599
46189
|
const result = {
|
|
46600
46190
|
source: absPath,
|
|
46601
46191
|
totalDuration,
|
|
@@ -46611,14 +46201,14 @@ var init_detect = __esm({
|
|
|
46611
46201
|
console.log(source_default.green(`Saved to: ${outputPath}`));
|
|
46612
46202
|
}
|
|
46613
46203
|
if (options.project) {
|
|
46614
|
-
const projectPath =
|
|
46615
|
-
const content = await
|
|
46204
|
+
const projectPath = resolve54(process.cwd(), options.project);
|
|
46205
|
+
const content = await readFile39(projectPath, "utf-8");
|
|
46616
46206
|
const data = JSON.parse(content);
|
|
46617
46207
|
const project = Project.fromJSON(data);
|
|
46618
46208
|
let source = project.getSources().find((s) => s.url === absPath);
|
|
46619
46209
|
if (!source) {
|
|
46620
46210
|
source = project.addSource({
|
|
46621
|
-
name:
|
|
46211
|
+
name: basename14(absPath),
|
|
46622
46212
|
type: "video",
|
|
46623
46213
|
url: absPath,
|
|
46624
46214
|
duration: totalDuration
|
|
@@ -46670,7 +46260,7 @@ var init_detect = __esm({
|
|
|
46670
46260
|
});
|
|
46671
46261
|
return;
|
|
46672
46262
|
}
|
|
46673
|
-
const absPath =
|
|
46263
|
+
const absPath = resolve54(process.cwd(), mediaPath);
|
|
46674
46264
|
const noise = options.noise;
|
|
46675
46265
|
const duration = options.duration;
|
|
46676
46266
|
const { stdout: silStdout, stderr: silStderr } = await execSafe("ffmpeg", [
|
|
@@ -46719,7 +46309,7 @@ var init_detect = __esm({
|
|
|
46719
46309
|
}
|
|
46720
46310
|
console.log();
|
|
46721
46311
|
if (options.output) {
|
|
46722
|
-
const outputPath =
|
|
46312
|
+
const outputPath = resolve54(process.cwd(), options.output);
|
|
46723
46313
|
await writeFile38(
|
|
46724
46314
|
outputPath,
|
|
46725
46315
|
JSON.stringify({ source: absPath, silences }, null, 2),
|
|
@@ -46755,7 +46345,7 @@ var init_detect = __esm({
|
|
|
46755
46345
|
});
|
|
46756
46346
|
return;
|
|
46757
46347
|
}
|
|
46758
|
-
const absPath =
|
|
46348
|
+
const absPath = resolve54(process.cwd(), audioPath);
|
|
46759
46349
|
const { stdout: beatStdout, stderr: beatStderr } = await execSafe("ffmpeg", [
|
|
46760
46350
|
"-i",
|
|
46761
46351
|
absPath,
|
|
@@ -46805,7 +46395,7 @@ var init_detect = __esm({
|
|
|
46805
46395
|
}
|
|
46806
46396
|
console.log();
|
|
46807
46397
|
if (options.output) {
|
|
46808
|
-
const outputPath =
|
|
46398
|
+
const outputPath = resolve54(process.cwd(), options.output);
|
|
46809
46399
|
await writeFile38(
|
|
46810
46400
|
outputPath,
|
|
46811
46401
|
JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2),
|
|
@@ -47305,8 +46895,8 @@ function getErrorMap() {
|
|
|
47305
46895
|
|
|
47306
46896
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
47307
46897
|
var makeIssue = (params) => {
|
|
47308
|
-
const { data, path
|
|
47309
|
-
const fullPath = [...
|
|
46898
|
+
const { data, path, errorMaps, issueData } = params;
|
|
46899
|
+
const fullPath = [...path, ...issueData.path || []];
|
|
47310
46900
|
const fullIssue = {
|
|
47311
46901
|
...issueData,
|
|
47312
46902
|
path: fullPath
|
|
@@ -47422,11 +47012,11 @@ var errorUtil;
|
|
|
47422
47012
|
|
|
47423
47013
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
47424
47014
|
var ParseInputLazyPath = class {
|
|
47425
|
-
constructor(parent, value,
|
|
47015
|
+
constructor(parent, value, path, key) {
|
|
47426
47016
|
this._cachedPath = [];
|
|
47427
47017
|
this.parent = parent;
|
|
47428
47018
|
this.data = value;
|
|
47429
|
-
this._path =
|
|
47019
|
+
this._path = path;
|
|
47430
47020
|
this._key = key;
|
|
47431
47021
|
}
|
|
47432
47022
|
get path() {
|
|
@@ -50977,23 +50567,23 @@ var EXPLICIT_COMMAND_METADATA = {
|
|
|
50977
50567
|
note: "Legacy timeline project alias."
|
|
50978
50568
|
}
|
|
50979
50569
|
};
|
|
50980
|
-
function productSurfaceForCommandPath(
|
|
50981
|
-
const explicit = EXPLICIT_COMMAND_METADATA[
|
|
50570
|
+
function productSurfaceForCommandPath(path) {
|
|
50571
|
+
const explicit = EXPLICIT_COMMAND_METADATA[path];
|
|
50982
50572
|
if (explicit) return explicit;
|
|
50983
|
-
if (
|
|
50573
|
+
if (path.startsWith("timeline.")) {
|
|
50984
50574
|
return { surface: "advanced", note: "Power tool for low-level timeline JSON edits." };
|
|
50985
50575
|
}
|
|
50986
|
-
if (
|
|
50576
|
+
if (path.startsWith("batch.")) {
|
|
50987
50577
|
return { surface: "advanced", note: "Power tool for bulk timeline/media operations." };
|
|
50988
50578
|
}
|
|
50989
|
-
if (
|
|
50579
|
+
if (path.startsWith("media.")) {
|
|
50990
50580
|
return { surface: "advanced", note: "Script utility for media metadata." };
|
|
50991
50581
|
}
|
|
50992
|
-
if (
|
|
50993
|
-
if (
|
|
50582
|
+
if (path.startsWith("detect.")) return { surface: "public" };
|
|
50583
|
+
if (path.startsWith("export.")) {
|
|
50994
50584
|
return { surface: "advanced", note: "Lower-level export helper." };
|
|
50995
50585
|
}
|
|
50996
|
-
if (
|
|
50586
|
+
if (path.startsWith("fs.")) {
|
|
50997
50587
|
return { surface: "internal", note: "In-process agent filesystem helper." };
|
|
50998
50588
|
}
|
|
50999
50589
|
return { surface: "advanced" };
|
|
@@ -51066,17 +50656,20 @@ async function runWithMcpPromotion(work, opts) {
|
|
|
51066
50656
|
let record = null;
|
|
51067
50657
|
let lastRecordWriteAt = 0;
|
|
51068
50658
|
let heartbeat = null;
|
|
51069
|
-
|
|
51070
|
-
|
|
50659
|
+
let writes = Promise.resolve();
|
|
50660
|
+
const writeRecord = (patch) => {
|
|
50661
|
+
if (!record) return writes;
|
|
51071
50662
|
record = {
|
|
51072
50663
|
...record,
|
|
51073
50664
|
...patch,
|
|
51074
50665
|
updatedAt: (opts.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
|
|
51075
50666
|
};
|
|
51076
|
-
|
|
51077
|
-
|
|
51078
|
-
|
|
51079
|
-
|
|
50667
|
+
const snapshot = record;
|
|
50668
|
+
writes = writes.then(
|
|
50669
|
+
() => writeJobRecord(snapshot).catch(() => {
|
|
50670
|
+
})
|
|
50671
|
+
);
|
|
50672
|
+
return writes;
|
|
51080
50673
|
};
|
|
51081
50674
|
const report = (update) => {
|
|
51082
50675
|
latest = { ...latest, ...update };
|
|
@@ -53826,9 +53419,9 @@ init_ai_edit();
|
|
|
53826
53419
|
init_api_key();
|
|
53827
53420
|
init_exec_safe();
|
|
53828
53421
|
init_remotion();
|
|
53829
|
-
import { resolve as
|
|
53422
|
+
import { resolve as resolve38, dirname as dirname16, basename as basename10 } from "node:path";
|
|
53830
53423
|
import { writeFile as writeFile29, mkdir as mkdir21, rm as rm7 } from "node:fs/promises";
|
|
53831
|
-
import { existsSync as
|
|
53424
|
+
import { existsSync as existsSync37 } from "node:fs";
|
|
53832
53425
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
53833
53426
|
var ASS_STYLES = ["karaoke-sweep", "typewriter"];
|
|
53834
53427
|
var SENTENCE_BREAKS = /[.!?]/;
|
|
@@ -53978,9 +53571,9 @@ async function executeAnimatedCaption(options) {
|
|
|
53978
53571
|
} catch {
|
|
53979
53572
|
}
|
|
53980
53573
|
const effectiveFontSize = fontSize ?? Math.round(height * 0.04);
|
|
53981
|
-
const tmpAudioDir =
|
|
53574
|
+
const tmpAudioDir = resolve38(tmpdir4(), `vf-ac-${Date.now()}`);
|
|
53982
53575
|
await mkdir21(tmpAudioDir, { recursive: true });
|
|
53983
|
-
const audioPath =
|
|
53576
|
+
const audioPath = resolve38(tmpAudioDir, "audio.wav");
|
|
53984
53577
|
await execSafe("ffmpeg", [
|
|
53985
53578
|
"-y",
|
|
53986
53579
|
"-i",
|
|
@@ -54007,9 +53600,9 @@ async function executeAnimatedCaption(options) {
|
|
|
54007
53600
|
return { success: false, error: "No words detected in transcription" };
|
|
54008
53601
|
}
|
|
54009
53602
|
const groups = groupWords(transcript.words, { wordsPerGroup, maxChars });
|
|
54010
|
-
const absOutputPath =
|
|
54011
|
-
const outDir =
|
|
54012
|
-
if (!
|
|
53603
|
+
const absOutputPath = resolve38(process.cwd(), outputPath);
|
|
53604
|
+
const outDir = dirname16(absOutputPath);
|
|
53605
|
+
if (!existsSync37(outDir)) {
|
|
54013
53606
|
await mkdir21(outDir, { recursive: true });
|
|
54014
53607
|
}
|
|
54015
53608
|
if (tier === "ass") {
|
|
@@ -54018,7 +53611,7 @@ async function executeAnimatedCaption(options) {
|
|
|
54018
53611
|
effectiveStyle,
|
|
54019
53612
|
{ highlightColor, fontSize: effectiveFontSize, position, width, height }
|
|
54020
53613
|
);
|
|
54021
|
-
const assPath =
|
|
53614
|
+
const assPath = resolve38(tmpAudioDir, "captions.ass");
|
|
54022
53615
|
await writeFile29(assPath, assContent, "utf-8");
|
|
54023
53616
|
const escapedAssPath = assPath.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
|
|
54024
53617
|
await execSafe("ffmpeg", [
|
|
@@ -54041,7 +53634,7 @@ async function executeAnimatedCaption(options) {
|
|
|
54041
53634
|
width,
|
|
54042
53635
|
height,
|
|
54043
53636
|
fps: videoFps,
|
|
54044
|
-
videoFileName:
|
|
53637
|
+
videoFileName: basename10(videoPath)
|
|
54045
53638
|
});
|
|
54046
53639
|
const durationInFrames = Math.ceil(duration * videoFps);
|
|
54047
53640
|
const renderResult = await renderWithEmbeddedVideo({
|
|
@@ -54052,7 +53645,7 @@ async function executeAnimatedCaption(options) {
|
|
|
54052
53645
|
fps: videoFps,
|
|
54053
53646
|
durationInFrames,
|
|
54054
53647
|
videoPath,
|
|
54055
|
-
videoFileName:
|
|
53648
|
+
videoFileName: basename10(videoPath),
|
|
54056
53649
|
outputPath: absOutputPath
|
|
54057
53650
|
});
|
|
54058
53651
|
if (!renderResult.success) {
|
|
@@ -54267,7 +53860,10 @@ var editMotionOverlayTool = defineTool({
|
|
|
54267
53860
|
}),
|
|
54268
53861
|
async execute(args) {
|
|
54269
53862
|
const result = await executeMotionOverlay(args);
|
|
54270
|
-
if (!result.success)
|
|
53863
|
+
if (!result.success) {
|
|
53864
|
+
const error = result.error ?? "Motion overlay failed";
|
|
53865
|
+
return { success: false, error: result.suggestion ? `${error} ${result.suggestion}` : error };
|
|
53866
|
+
}
|
|
54271
53867
|
return {
|
|
54272
53868
|
success: true,
|
|
54273
53869
|
data: {
|
|
@@ -54549,21 +54145,21 @@ var editTools = [
|
|
|
54549
54145
|
];
|
|
54550
54146
|
|
|
54551
54147
|
// src/tools/manifest/inspect.ts
|
|
54552
|
-
import { resolve as
|
|
54148
|
+
import { resolve as resolve44 } from "node:path";
|
|
54553
54149
|
init_ai_analyze();
|
|
54554
54150
|
|
|
54555
54151
|
// src/commands/ai-suggest-edit.ts
|
|
54556
54152
|
init_dist2();
|
|
54557
54153
|
init_engine();
|
|
54558
54154
|
init_ai_helpers();
|
|
54559
|
-
import { readFile as
|
|
54560
|
-
import { resolve as
|
|
54155
|
+
import { readFile as readFile30, writeFile as writeFile30 } from "node:fs/promises";
|
|
54156
|
+
import { resolve as resolve40 } from "node:path";
|
|
54561
54157
|
async function executeSuggestEdit(options) {
|
|
54562
54158
|
try {
|
|
54563
54159
|
const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY;
|
|
54564
54160
|
if (!apiKey) return { success: false, error: "GOOGLE_API_KEY required for suggest" };
|
|
54565
|
-
const filePath =
|
|
54566
|
-
const content = await
|
|
54161
|
+
const filePath = resolve40(process.cwd(), options.projectPath);
|
|
54162
|
+
const content = await readFile30(filePath, "utf-8");
|
|
54567
54163
|
const data = JSON.parse(content);
|
|
54568
54164
|
const project = Project.fromJSON(data);
|
|
54569
54165
|
const gemini = new GeminiProvider();
|
|
@@ -54600,11 +54196,11 @@ init_project_config();
|
|
|
54600
54196
|
init_scene_lint();
|
|
54601
54197
|
init_root_sync();
|
|
54602
54198
|
init_review_report();
|
|
54603
|
-
import { existsSync as
|
|
54604
|
-
import { readdir as
|
|
54605
|
-
import {
|
|
54199
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
54200
|
+
import { readdir as readdir4, readFile as readFile31, stat as stat5 } from "node:fs/promises";
|
|
54201
|
+
import { isAbsolute as isAbsolute6, join as join23, resolve as resolve41 } from "node:path";
|
|
54606
54202
|
async function inspectProject(opts) {
|
|
54607
|
-
const projectDir =
|
|
54203
|
+
const projectDir = resolve41(opts.projectDir);
|
|
54608
54204
|
const issues = [];
|
|
54609
54205
|
const retryWith = [];
|
|
54610
54206
|
const checks = {
|
|
@@ -54616,7 +54212,7 @@ async function inspectProject(opts) {
|
|
|
54616
54212
|
assets: { checked: 0, missing: [], stale: [], unknownFreshness: [] },
|
|
54617
54213
|
rootSync: { ok: null, issueCount: 0, issues: [] }
|
|
54618
54214
|
};
|
|
54619
|
-
if (!
|
|
54215
|
+
if (!existsSync39(projectDir) || !await isDirectory(projectDir)) {
|
|
54620
54216
|
issues.push({
|
|
54621
54217
|
severity: "error",
|
|
54622
54218
|
code: "PROJECT_NOT_FOUND",
|
|
@@ -54638,8 +54234,8 @@ async function inspectProject(opts) {
|
|
|
54638
54234
|
buildReport: join23(projectDir, "build-report.json"),
|
|
54639
54235
|
root: join23(projectDir, "index.html")
|
|
54640
54236
|
};
|
|
54641
|
-
for (const [name,
|
|
54642
|
-
checks.files[name] =
|
|
54237
|
+
for (const [name, path] of Object.entries(coreFiles)) {
|
|
54238
|
+
checks.files[name] = existsSync39(path);
|
|
54643
54239
|
}
|
|
54644
54240
|
let beatIds = [];
|
|
54645
54241
|
let inspectedBeatIds = [];
|
|
@@ -54653,7 +54249,7 @@ async function inspectProject(opts) {
|
|
|
54653
54249
|
});
|
|
54654
54250
|
retryWith.push(`vibe init ${projectDir} --from "<brief>" --json`);
|
|
54655
54251
|
} else {
|
|
54656
|
-
const storyboard = await
|
|
54252
|
+
const storyboard = await readFile31(coreFiles.storyboard, "utf-8");
|
|
54657
54253
|
const validation = validateStoryboardMarkdown(storyboard);
|
|
54658
54254
|
storyboardBeats = validation.beats;
|
|
54659
54255
|
beatIds = validation.beats.map((beat) => beat.id);
|
|
@@ -54695,7 +54291,7 @@ async function inspectProject(opts) {
|
|
|
54695
54291
|
suggestedFix: "Create DESIGN.md or rerun `vibe init --from` in a new project."
|
|
54696
54292
|
});
|
|
54697
54293
|
} else {
|
|
54698
|
-
const design = await
|
|
54294
|
+
const design = await readFile31(coreFiles.design, "utf-8");
|
|
54699
54295
|
for (const issue of designPlaceholderIssues(design)) {
|
|
54700
54296
|
issues.push(issue);
|
|
54701
54297
|
}
|
|
@@ -54721,7 +54317,7 @@ async function inspectProject(opts) {
|
|
|
54721
54317
|
retryWith.push(`vibe build ${projectDir} --stage sync --json`);
|
|
54722
54318
|
}
|
|
54723
54319
|
const compositionsDir = join23(projectDir, "compositions");
|
|
54724
|
-
const existingComps =
|
|
54320
|
+
const existingComps = existsSync39(compositionsDir) ? new Set(await listHtmlBasenames(compositionsDir)) : /* @__PURE__ */ new Set();
|
|
54725
54321
|
checks.compositions.expected = inspectedBeatIds.length;
|
|
54726
54322
|
for (const beatId of inspectedBeatIds) {
|
|
54727
54323
|
const file = `scene-${beatId}.html`;
|
|
@@ -54908,7 +54504,7 @@ function designPlaceholderIssues(design) {
|
|
|
54908
54504
|
}
|
|
54909
54505
|
async function maybeWriteProjectReport(projectDir, opts, result) {
|
|
54910
54506
|
if (opts.writeReport === false) return result;
|
|
54911
|
-
const reportPath = opts.outputPath ?
|
|
54507
|
+
const reportPath = opts.outputPath ? resolve41(process.cwd(), opts.outputPath) : defaultReviewReportPath(projectDir);
|
|
54912
54508
|
try {
|
|
54913
54509
|
const reviewReport = buildReviewReport({
|
|
54914
54510
|
project: projectDir,
|
|
@@ -54941,7 +54537,7 @@ function projectSourceReports(checks) {
|
|
|
54941
54537
|
async function inspectBuildReport(projectDir, reportPath, beatId, checks, issues, retryWith, storyboardBeats) {
|
|
54942
54538
|
checks.buildReport.exists = true;
|
|
54943
54539
|
try {
|
|
54944
|
-
const report = JSON.parse(await
|
|
54540
|
+
const report = JSON.parse(await readFile31(reportPath, "utf-8"));
|
|
54945
54541
|
if (typeof report.outputPath === "string") checks.buildReport.outputPath = report.outputPath;
|
|
54946
54542
|
const reportBeats = report.beats ?? [];
|
|
54947
54543
|
const selectedReportBeats = reportBeats.filter((item) => !beatId || item.id === beatId);
|
|
@@ -55077,8 +54673,8 @@ function inspectReportedAsset(opts) {
|
|
|
55077
54673
|
if (typeof opts.value !== "string" || opts.value.length === 0) return;
|
|
55078
54674
|
opts.checks.assets.checked++;
|
|
55079
54675
|
if (isExternalRef2(opts.value)) return;
|
|
55080
|
-
const abs =
|
|
55081
|
-
if (
|
|
54676
|
+
const abs = isAbsolute6(opts.value) ? opts.value : resolve41(opts.projectDir, opts.value);
|
|
54677
|
+
if (existsSync39(abs)) return;
|
|
55082
54678
|
opts.checks.assets.missing.push(opts.value);
|
|
55083
54679
|
opts.issues.push({
|
|
55084
54680
|
severity: "warning",
|
|
@@ -55097,11 +54693,11 @@ function inspectAssetFreshness(opts) {
|
|
|
55097
54693
|
const freshness = typeof opts.asset?.freshness === "string" ? opts.asset.freshness : void 0;
|
|
55098
54694
|
if (freshness !== "stale" && freshness !== "unknown") return;
|
|
55099
54695
|
const label = `${opts.kind}${opts.beatId ? ` for beat "${opts.beatId}"` : ""}`;
|
|
55100
|
-
const
|
|
54696
|
+
const path = typeof opts.asset?.path === "string" ? opts.asset.path : typeof opts.asset?.sourcePath === "string" ? opts.asset.sourcePath : `${opts.kind}:${opts.beatId ?? "unknown"}`;
|
|
55101
54697
|
if (freshness === "stale") {
|
|
55102
|
-
opts.checks.assets.stale.push(
|
|
54698
|
+
opts.checks.assets.stale.push(path);
|
|
55103
54699
|
} else {
|
|
55104
|
-
opts.checks.assets.unknownFreshness.push(
|
|
54700
|
+
opts.checks.assets.unknownFreshness.push(path);
|
|
55105
54701
|
}
|
|
55106
54702
|
opts.issues.push({
|
|
55107
54703
|
severity: "warning",
|
|
@@ -55151,15 +54747,15 @@ function countLintFindings(files) {
|
|
|
55151
54747
|
}
|
|
55152
54748
|
return { errorCount, warningCount, infoCount };
|
|
55153
54749
|
}
|
|
55154
|
-
async function isDirectory(
|
|
54750
|
+
async function isDirectory(path) {
|
|
55155
54751
|
try {
|
|
55156
|
-
return (await stat5(
|
|
54752
|
+
return (await stat5(path)).isDirectory();
|
|
55157
54753
|
} catch {
|
|
55158
54754
|
return false;
|
|
55159
54755
|
}
|
|
55160
54756
|
}
|
|
55161
54757
|
async function listHtmlBasenames(dir) {
|
|
55162
|
-
const entries = await
|
|
54758
|
+
const entries = await readdir4(dir, { withFileTypes: true });
|
|
55163
54759
|
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".html")).map((entry) => entry.name);
|
|
55164
54760
|
}
|
|
55165
54761
|
function isExternalRef2(value) {
|
|
@@ -55172,9 +54768,9 @@ init_exec_safe();
|
|
|
55172
54768
|
init_project_config();
|
|
55173
54769
|
init_storyboard_parse();
|
|
55174
54770
|
init_review_report();
|
|
55175
|
-
import { existsSync as
|
|
55176
|
-
import { readdir as
|
|
55177
|
-
import { basename as
|
|
54771
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
54772
|
+
import { readdir as readdir5, readFile as readFile33, stat as stat6 } from "node:fs/promises";
|
|
54773
|
+
import { basename as basename11, isAbsolute as isAbsolute7, join as join24, relative as relative10, resolve as resolve43 } from "node:path";
|
|
55178
54774
|
var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([".mp4", ".mov", ".webm", ".m4v"]);
|
|
55179
54775
|
var DEFAULT_AI_MODEL = "flash";
|
|
55180
54776
|
var BLACK_FRAME_MIN_DURATION_SEC = 1;
|
|
@@ -55309,10 +54905,10 @@ function durationDriftIssue(params) {
|
|
|
55309
54905
|
};
|
|
55310
54906
|
}
|
|
55311
54907
|
async function previewInspectRender(opts) {
|
|
55312
|
-
const projectDir =
|
|
54908
|
+
const projectDir = resolve43(opts.projectDir);
|
|
55313
54909
|
const videoPath = await resolveRenderVideoPath(projectDir, opts.videoPath, opts.beatId);
|
|
55314
54910
|
const writeReport = opts.writeReport !== false;
|
|
55315
|
-
const reportPath = writeReport ? opts.outputPath ?
|
|
54911
|
+
const reportPath = writeReport ? opts.outputPath ? resolve43(process.cwd(), opts.outputPath) : defaultReviewReportPath(projectDir) : void 0;
|
|
55316
54912
|
const storyboardPath = resolveStoryboardPath(projectDir);
|
|
55317
54913
|
return {
|
|
55318
54914
|
schemaVersion: "1",
|
|
@@ -55383,7 +54979,7 @@ function scoreRenderReview(issues, aiOverallScore) {
|
|
|
55383
54979
|
return Math.round((localScore + aiScore) / 2);
|
|
55384
54980
|
}
|
|
55385
54981
|
async function inspectRender(opts) {
|
|
55386
|
-
const projectDir =
|
|
54982
|
+
const projectDir = resolve43(opts.projectDir);
|
|
55387
54983
|
const issues = [];
|
|
55388
54984
|
const retryWith = [];
|
|
55389
54985
|
const model = opts.model ?? DEFAULT_AI_MODEL;
|
|
@@ -55674,7 +55270,7 @@ async function inspectRender(opts) {
|
|
|
55674
55270
|
return maybeWriteRenderReport(projectDir, opts, result);
|
|
55675
55271
|
}
|
|
55676
55272
|
async function renderExpectsAudio(projectDir, beatId) {
|
|
55677
|
-
const root =
|
|
55273
|
+
const root = resolve43(projectDir);
|
|
55678
55274
|
const rootHtml = await readTextIfExists(join24(root, "index.html"));
|
|
55679
55275
|
if (rootHtml && rootHtmlExpectsAudio(rootHtml, beatId)) return true;
|
|
55680
55276
|
const buildReport = await readJsonIfExists(join24(root, "build-report.json"));
|
|
@@ -55690,7 +55286,7 @@ async function renderExpectsAudio(projectDir, beatId) {
|
|
|
55690
55286
|
`assets/narration-${beat.id}.wav`,
|
|
55691
55287
|
`assets/music-${beat.id}.mp3`,
|
|
55692
55288
|
`assets/music-${beat.id}.wav`
|
|
55693
|
-
].some((asset) =>
|
|
55289
|
+
].some((asset) => existsSync41(join24(root, asset)))
|
|
55694
55290
|
);
|
|
55695
55291
|
} catch {
|
|
55696
55292
|
return false;
|
|
@@ -55735,8 +55331,8 @@ function beatReportExpectsAudio(beat) {
|
|
|
55735
55331
|
}
|
|
55736
55332
|
return false;
|
|
55737
55333
|
}
|
|
55738
|
-
async function readJsonIfExists(
|
|
55739
|
-
const text = await readTextIfExists(
|
|
55334
|
+
async function readJsonIfExists(path) {
|
|
55335
|
+
const text = await readTextIfExists(path);
|
|
55740
55336
|
if (!text) return null;
|
|
55741
55337
|
try {
|
|
55742
55338
|
return JSON.parse(text);
|
|
@@ -55777,7 +55373,7 @@ function makeRenderResult(projectDir, opts, videoPath, issues, checks, retryWith
|
|
|
55777
55373
|
}
|
|
55778
55374
|
async function maybeWriteRenderReport(projectDir, opts, result) {
|
|
55779
55375
|
if (opts.writeReport === false) return result;
|
|
55780
|
-
const reportPath = opts.outputPath ?
|
|
55376
|
+
const reportPath = opts.outputPath ? resolve43(process.cwd(), opts.outputPath) : defaultReviewReportPath(projectDir);
|
|
55781
55377
|
try {
|
|
55782
55378
|
const reviewReport = buildReviewReport({
|
|
55783
55379
|
project: projectDir,
|
|
@@ -55798,8 +55394,8 @@ async function maybeWriteRenderReport(projectDir, opts, result) {
|
|
|
55798
55394
|
}
|
|
55799
55395
|
function renderSourceReports(projectDir, videoPath, checks) {
|
|
55800
55396
|
const reports = [];
|
|
55801
|
-
if (
|
|
55802
|
-
if (
|
|
55397
|
+
if (existsSync41(join24(projectDir, "build-report.json"))) reports.push("build-report.json");
|
|
55398
|
+
if (existsSync41(join24(projectDir, "render-report.json"))) reports.push("render-report.json");
|
|
55803
55399
|
if (videoPath) reports.push(displayPath(videoPath));
|
|
55804
55400
|
if (checks.durationSec !== void 0 || checks.width !== void 0 || checks.height !== void 0) {
|
|
55805
55401
|
reports.push("ffprobe");
|
|
@@ -55811,33 +55407,33 @@ function renderSourceReports(projectDir, videoPath, checks) {
|
|
|
55811
55407
|
}
|
|
55812
55408
|
async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
55813
55409
|
if (explicit) {
|
|
55814
|
-
const candidate =
|
|
55815
|
-
return
|
|
55410
|
+
const candidate = resolve43(process.cwd(), explicit);
|
|
55411
|
+
return existsSync41(candidate) ? candidate : null;
|
|
55816
55412
|
}
|
|
55817
55413
|
const renderReportPath = join24(projectDir, "render-report.json");
|
|
55818
|
-
if (
|
|
55414
|
+
if (existsSync41(renderReportPath)) {
|
|
55819
55415
|
try {
|
|
55820
|
-
const report = JSON.parse(await
|
|
55416
|
+
const report = JSON.parse(await readFile33(renderReportPath, "utf-8"));
|
|
55821
55417
|
const reportBeat = typeof report.beat === "string" ? report.beat : null;
|
|
55822
55418
|
if (!beatId && reportBeat === null || beatId && reportBeat === beatId) {
|
|
55823
55419
|
const candidate = resolveReportedPath(projectDir, report.outputPath);
|
|
55824
|
-
if (candidate &&
|
|
55420
|
+
if (candidate && existsSync41(candidate)) return candidate;
|
|
55825
55421
|
}
|
|
55826
55422
|
} catch {
|
|
55827
55423
|
}
|
|
55828
55424
|
}
|
|
55829
55425
|
const reportPath = join24(projectDir, "build-report.json");
|
|
55830
|
-
if (!beatId &&
|
|
55426
|
+
if (!beatId && existsSync41(reportPath)) {
|
|
55831
55427
|
try {
|
|
55832
|
-
const report = JSON.parse(await
|
|
55428
|
+
const report = JSON.parse(await readFile33(reportPath, "utf-8"));
|
|
55833
55429
|
const candidate = resolveReportedPath(projectDir, report.outputPath);
|
|
55834
|
-
if (candidate &&
|
|
55430
|
+
if (candidate && existsSync41(candidate)) return candidate;
|
|
55835
55431
|
} catch {
|
|
55836
55432
|
}
|
|
55837
55433
|
}
|
|
55838
55434
|
const rendersDir = join24(projectDir, "renders");
|
|
55839
|
-
if (!
|
|
55840
|
-
const entries = await
|
|
55435
|
+
if (!existsSync41(rendersDir)) return null;
|
|
55436
|
+
const entries = await readdir5(rendersDir, { withFileTypes: true });
|
|
55841
55437
|
const candidates = [];
|
|
55842
55438
|
for (const entry of entries) {
|
|
55843
55439
|
if (!entry.isFile()) continue;
|
|
@@ -55863,13 +55459,13 @@ async function runAiRenderReview(projectDir, videoPath, model) {
|
|
|
55863
55459
|
}
|
|
55864
55460
|
function resolveStoryboardPath(projectDir) {
|
|
55865
55461
|
const storyboardPath = join24(projectDir, "STORYBOARD.md");
|
|
55866
|
-
return
|
|
55462
|
+
return existsSync41(storyboardPath) ? storyboardPath : null;
|
|
55867
55463
|
}
|
|
55868
55464
|
async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
55869
55465
|
const reportPath = join24(projectDir, "build-report.json");
|
|
55870
|
-
if (!
|
|
55466
|
+
if (!existsSync41(reportPath)) return void 0;
|
|
55871
55467
|
try {
|
|
55872
|
-
const report = JSON.parse(await
|
|
55468
|
+
const report = JSON.parse(await readFile33(reportPath, "utf-8"));
|
|
55873
55469
|
const beats = beatId ? (report.beats ?? []).filter((beat) => beat.id === beatId) : report.beats ?? [];
|
|
55874
55470
|
const durations = beats.map(
|
|
55875
55471
|
(beat) => parseOptionalNumber2(beat.sceneDurationSec) ?? parseOptionalNumber2(beat.narration?.sceneDurationSec)
|
|
@@ -55882,9 +55478,9 @@ async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
|
55882
55478
|
}
|
|
55883
55479
|
async function beatTimingsFromBuildReport(projectDir, beatId) {
|
|
55884
55480
|
const reportPath = join24(projectDir, "build-report.json");
|
|
55885
|
-
if (!
|
|
55481
|
+
if (!existsSync41(reportPath)) return [];
|
|
55886
55482
|
try {
|
|
55887
|
-
const report = JSON.parse(await
|
|
55483
|
+
const report = JSON.parse(await readFile33(reportPath, "utf-8"));
|
|
55888
55484
|
const source = report.beats ?? [];
|
|
55889
55485
|
const selected = beatId ? source.filter((beat) => beat.id === beatId) : source;
|
|
55890
55486
|
let cursor = 0;
|
|
@@ -55947,10 +55543,10 @@ function storyboardBeatCueSummary(storyboard) {
|
|
|
55947
55543
|
return "Storyboard could not be parsed.";
|
|
55948
55544
|
}
|
|
55949
55545
|
}
|
|
55950
|
-
async function readTextIfExists(
|
|
55951
|
-
if (!
|
|
55546
|
+
async function readTextIfExists(path) {
|
|
55547
|
+
if (!existsSync41(path)) return null;
|
|
55952
55548
|
try {
|
|
55953
|
-
return await
|
|
55549
|
+
return await readFile33(path, "utf-8");
|
|
55954
55550
|
} catch {
|
|
55955
55551
|
return null;
|
|
55956
55552
|
}
|
|
@@ -56047,8 +55643,8 @@ function aspectRatio(aspect) {
|
|
|
56047
55643
|
if (!Number.isFinite(w) || !Number.isFinite(h) || h === 0) return 16 / 9;
|
|
56048
55644
|
return w / h;
|
|
56049
55645
|
}
|
|
56050
|
-
function displayPath(
|
|
56051
|
-
return
|
|
55646
|
+
function displayPath(path) {
|
|
55647
|
+
return relative10(process.cwd(), path) || basename11(path);
|
|
56052
55648
|
}
|
|
56053
55649
|
function toSnakeCase(value) {
|
|
56054
55650
|
return value.replace(/[A-Z]/g, (match) => `_${match}`).toUpperCase();
|
|
@@ -56058,7 +55654,7 @@ function stringOrNull(value) {
|
|
|
56058
55654
|
}
|
|
56059
55655
|
function resolveReportedPath(projectDir, value) {
|
|
56060
55656
|
if (typeof value !== "string" || value.length === 0) return null;
|
|
56061
|
-
return
|
|
55657
|
+
return isAbsolute7(value) ? value : resolve43(projectDir, value);
|
|
56062
55658
|
}
|
|
56063
55659
|
function sanitizeFileSegment2(value) {
|
|
56064
55660
|
return value.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "beat";
|
|
@@ -56080,11 +55676,11 @@ var inspectProjectTool = defineTool({
|
|
|
56080
55676
|
report: external_exports.boolean().optional().describe("Write review-report.json. Default true.")
|
|
56081
55677
|
}),
|
|
56082
55678
|
async execute(args, ctx) {
|
|
56083
|
-
const projectDir = args.projectDir ?
|
|
55679
|
+
const projectDir = args.projectDir ? resolve44(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
56084
55680
|
const result = await inspectProject({
|
|
56085
55681
|
projectDir,
|
|
56086
55682
|
beatId: args.beat,
|
|
56087
|
-
outputPath: args.outputPath ?
|
|
55683
|
+
outputPath: args.outputPath ? resolve44(ctx.workingDirectory, args.outputPath) : void 0,
|
|
56088
55684
|
writeReport: args.report !== false
|
|
56089
55685
|
});
|
|
56090
55686
|
return {
|
|
@@ -56120,13 +55716,13 @@ var inspectRenderTool = defineTool({
|
|
|
56120
55716
|
dryRun: external_exports.boolean().optional().describe("Preview resolved inputs without probing video or calling Gemini.")
|
|
56121
55717
|
}),
|
|
56122
55718
|
async execute(args, ctx) {
|
|
56123
|
-
const projectDir = args.projectDir ?
|
|
55719
|
+
const projectDir = args.projectDir ? resolve44(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
56124
55720
|
if (args.dryRun) {
|
|
56125
55721
|
const result2 = await previewInspectRender({
|
|
56126
55722
|
projectDir,
|
|
56127
55723
|
beatId: args.beat,
|
|
56128
|
-
videoPath: args.videoPath ?
|
|
56129
|
-
outputPath: args.outputPath ?
|
|
55724
|
+
videoPath: args.videoPath ? resolve44(ctx.workingDirectory, args.videoPath) : void 0,
|
|
55725
|
+
outputPath: args.outputPath ? resolve44(ctx.workingDirectory, args.outputPath) : void 0,
|
|
56130
55726
|
writeReport: args.report !== false,
|
|
56131
55727
|
ai: args.ai === true,
|
|
56132
55728
|
model: args.model
|
|
@@ -56147,8 +55743,8 @@ var inspectRenderTool = defineTool({
|
|
|
56147
55743
|
const result = await inspectRender({
|
|
56148
55744
|
projectDir,
|
|
56149
55745
|
beatId: args.beat,
|
|
56150
|
-
videoPath: args.videoPath ?
|
|
56151
|
-
outputPath: args.outputPath ?
|
|
55746
|
+
videoPath: args.videoPath ? resolve44(ctx.workingDirectory, args.videoPath) : void 0,
|
|
55747
|
+
outputPath: args.outputPath ? resolve44(ctx.workingDirectory, args.outputPath) : void 0,
|
|
56152
55748
|
writeReport: args.report !== false,
|
|
56153
55749
|
ai: args.ai === true,
|
|
56154
55750
|
model: args.model
|
|
@@ -56576,16 +56172,16 @@ var generateTools = [
|
|
|
56576
56172
|
];
|
|
56577
56173
|
|
|
56578
56174
|
// src/tools/manifest/storyboard.ts
|
|
56579
|
-
import { existsSync as
|
|
56580
|
-
import { readFile as
|
|
56581
|
-
import { resolve as
|
|
56175
|
+
import { existsSync as existsSync44 } from "node:fs";
|
|
56176
|
+
import { readFile as readFile36, writeFile as writeFile36 } from "node:fs/promises";
|
|
56177
|
+
import { resolve as resolve51 } from "node:path";
|
|
56582
56178
|
init_storyboard_parse();
|
|
56583
56179
|
init_storyboard_edit();
|
|
56584
56180
|
|
|
56585
56181
|
// src/commands/_shared/storyboard-revise.ts
|
|
56586
|
-
import { existsSync as
|
|
56587
|
-
import { readFile as
|
|
56588
|
-
import { join as join25, resolve as
|
|
56182
|
+
import { existsSync as existsSync43 } from "node:fs";
|
|
56183
|
+
import { readFile as readFile35, writeFile as writeFile35 } from "node:fs/promises";
|
|
56184
|
+
import { join as join25, resolve as resolve50 } from "node:path";
|
|
56589
56185
|
|
|
56590
56186
|
// src/agent/adapters/index.ts
|
|
56591
56187
|
init_openai2();
|
|
@@ -56637,10 +56233,10 @@ init_storyboard_parse();
|
|
|
56637
56233
|
init_storyboard_source();
|
|
56638
56234
|
init_storyboard_edit();
|
|
56639
56235
|
async function executeStoryboardRevision(opts) {
|
|
56640
|
-
const projectDir =
|
|
56236
|
+
const projectDir = resolve50(opts.projectDir);
|
|
56641
56237
|
const storyboardPath = join25(projectDir, "STORYBOARD.md");
|
|
56642
56238
|
const retryWith = [`vibe storyboard revise ${projectDir} --from "<request>" --dry-run --json`];
|
|
56643
|
-
if (!
|
|
56239
|
+
if (!existsSync43(storyboardPath)) {
|
|
56644
56240
|
return failureResult({
|
|
56645
56241
|
projectDir,
|
|
56646
56242
|
storyboardPath,
|
|
@@ -56885,14 +56481,14 @@ async function readRevisionContext(projectDir) {
|
|
|
56885
56481
|
const buildReportJson = await readOptionalJsonText(join25(projectDir, "build-report.json"));
|
|
56886
56482
|
return { designMd, buildReportJson };
|
|
56887
56483
|
}
|
|
56888
|
-
async function readOptionalText(
|
|
56889
|
-
if (!
|
|
56890
|
-
return
|
|
56484
|
+
async function readOptionalText(path) {
|
|
56485
|
+
if (!existsSync43(path)) return null;
|
|
56486
|
+
return readFile35(path, "utf-8");
|
|
56891
56487
|
}
|
|
56892
|
-
async function readOptionalJsonText(
|
|
56893
|
-
if (!
|
|
56488
|
+
async function readOptionalJsonText(path) {
|
|
56489
|
+
if (!existsSync43(path)) return null;
|
|
56894
56490
|
try {
|
|
56895
|
-
const parsed = JSON.parse(await
|
|
56491
|
+
const parsed = JSON.parse(await readFile35(path, "utf-8"));
|
|
56896
56492
|
return JSON.stringify(parsed, null, 2);
|
|
56897
56493
|
} catch {
|
|
56898
56494
|
return null;
|
|
@@ -56937,9 +56533,9 @@ var projectDirSchema = external_exports.object({
|
|
|
56937
56533
|
projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3)
|
|
56938
56534
|
});
|
|
56939
56535
|
async function readStoryboard(projectDir) {
|
|
56940
|
-
const
|
|
56941
|
-
if (!
|
|
56942
|
-
return { path
|
|
56536
|
+
const path = resolve51(projectDir, "STORYBOARD.md");
|
|
56537
|
+
if (!existsSync44(path)) return null;
|
|
56538
|
+
return { path, markdown: await readFile36(path, "utf-8") };
|
|
56943
56539
|
}
|
|
56944
56540
|
var storyboardListTool = defineTool({
|
|
56945
56541
|
name: "storyboard_list",
|
|
@@ -56950,7 +56546,7 @@ var storyboardListTool = defineTool({
|
|
|
56950
56546
|
description: "List beats, ids, durations, and cue blocks from a project's STORYBOARD.md.",
|
|
56951
56547
|
schema: projectDirSchema,
|
|
56952
56548
|
async execute(args, ctx) {
|
|
56953
|
-
const projectDir = args.projectDir ?
|
|
56549
|
+
const projectDir = args.projectDir ? resolve51(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
56954
56550
|
const file = await readStoryboard(projectDir);
|
|
56955
56551
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
56956
56552
|
const parsed = parseStoryboard(file.markdown);
|
|
@@ -56978,7 +56574,7 @@ var storyboardValidateTool = defineTool({
|
|
|
56978
56574
|
description: "Validate STORYBOARD.md beat ids and cue blocks.",
|
|
56979
56575
|
schema: projectDirSchema,
|
|
56980
56576
|
async execute(args, ctx) {
|
|
56981
|
-
const projectDir = args.projectDir ?
|
|
56577
|
+
const projectDir = args.projectDir ? resolve51(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
56982
56578
|
const file = await readStoryboard(projectDir);
|
|
56983
56579
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
56984
56580
|
const result = validateStoryboardMarkdown(file.markdown);
|
|
@@ -57013,7 +56609,7 @@ var storyboardGetTool = defineTool({
|
|
|
57013
56609
|
beat: external_exports.string().describe("Beat id to return.")
|
|
57014
56610
|
}),
|
|
57015
56611
|
async execute(args, ctx) {
|
|
57016
|
-
const projectDir = args.projectDir ?
|
|
56612
|
+
const projectDir = args.projectDir ? resolve51(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
57017
56613
|
const file = await readStoryboard(projectDir);
|
|
57018
56614
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
57019
56615
|
const beat = getStoryboardBeat(file.markdown, args.beat);
|
|
@@ -57041,7 +56637,7 @@ var storyboardSetTool = defineTool({
|
|
|
57041
56637
|
unset: external_exports.boolean().optional().describe("Remove the cue key.")
|
|
57042
56638
|
}),
|
|
57043
56639
|
async execute(args, ctx) {
|
|
57044
|
-
const projectDir = args.projectDir ?
|
|
56640
|
+
const projectDir = args.projectDir ? resolve51(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
57045
56641
|
const file = await readStoryboard(projectDir);
|
|
57046
56642
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
57047
56643
|
try {
|
|
@@ -57076,7 +56672,7 @@ var storyboardMoveTool = defineTool({
|
|
|
57076
56672
|
after: external_exports.string().describe("Beat id that should precede the moved beat.")
|
|
57077
56673
|
}),
|
|
57078
56674
|
async execute(args, ctx) {
|
|
57079
|
-
const projectDir = args.projectDir ?
|
|
56675
|
+
const projectDir = args.projectDir ? resolve51(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
57080
56676
|
const file = await readStoryboard(projectDir);
|
|
57081
56677
|
if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
|
|
57082
56678
|
try {
|
|
@@ -57110,7 +56706,7 @@ var storyboardReviseTool = defineTool({
|
|
|
57110
56706
|
dryRun: external_exports.boolean().optional().describe("Preview the revised storyboard without writing.")
|
|
57111
56707
|
}),
|
|
57112
56708
|
async execute(args, ctx) {
|
|
57113
|
-
const projectDir = args.projectDir ?
|
|
56709
|
+
const projectDir = args.projectDir ? resolve51(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
57114
56710
|
const result = await executeStoryboardRevision({
|
|
57115
56711
|
projectDir,
|
|
57116
56712
|
request: args.request,
|
|
@@ -57155,7 +56751,7 @@ var planTool = defineTool({
|
|
|
57155
56751
|
force: external_exports.boolean().optional().describe("Plan regeneration even when outputs exist.")
|
|
57156
56752
|
}),
|
|
57157
56753
|
async execute(args, ctx) {
|
|
57158
|
-
const projectDir = args.projectDir ?
|
|
56754
|
+
const projectDir = args.projectDir ? resolve51(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
57159
56755
|
const plan = await createBuildPlan({
|
|
57160
56756
|
projectDir,
|
|
57161
56757
|
stage: args.stage,
|
|
@@ -57196,9 +56792,9 @@ var storyboardTools = [
|
|
|
57196
56792
|
];
|
|
57197
56793
|
|
|
57198
56794
|
// src/tools/manifest/design.ts
|
|
57199
|
-
import { existsSync as
|
|
57200
|
-
import { readFile as
|
|
57201
|
-
import { resolve as
|
|
56795
|
+
import { existsSync as existsSync45 } from "node:fs";
|
|
56796
|
+
import { readFile as readFile37 } from "node:fs/promises";
|
|
56797
|
+
import { resolve as resolve52, join as join26 } from "node:path";
|
|
57202
56798
|
init_design_parse();
|
|
57203
56799
|
var PROJECT_DIR_DESCRIPTION4 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
|
|
57204
56800
|
var projectDirSchema2 = external_exports.object({
|
|
@@ -57213,10 +56809,10 @@ var designValidateTool = defineTool({
|
|
|
57213
56809
|
description: "Validate DESIGN.md front-matter color/typography tokens and sections (google-labs design.md format).",
|
|
57214
56810
|
schema: projectDirSchema2,
|
|
57215
56811
|
async execute(args, ctx) {
|
|
57216
|
-
const projectDir = args.projectDir ?
|
|
57217
|
-
const
|
|
57218
|
-
if (!
|
|
57219
|
-
const md = await
|
|
56812
|
+
const projectDir = args.projectDir ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
56813
|
+
const path = join26(projectDir, "DESIGN.md");
|
|
56814
|
+
if (!existsSync45(path)) return { success: false, error: `DESIGN.md not found in ${projectDir}` };
|
|
56815
|
+
const md = await readFile37(path, "utf-8");
|
|
57220
56816
|
const issues = validateDesignMarkdown(md);
|
|
57221
56817
|
const design = parseDesign(md);
|
|
57222
56818
|
const ok = !issues.some((issue) => issue.severity === "error");
|
|
@@ -57242,9 +56838,9 @@ import { tmpdir as tmpdir5 } from "node:os";
|
|
|
57242
56838
|
import { join as join27 } from "node:path";
|
|
57243
56839
|
|
|
57244
56840
|
// src/commands/ai-highlights.ts
|
|
57245
|
-
import { readFile as
|
|
57246
|
-
import { resolve as
|
|
57247
|
-
import { existsSync as
|
|
56841
|
+
import { readFile as readFile38, writeFile as writeFile37, mkdir as mkdir24 } from "node:fs/promises";
|
|
56842
|
+
import { resolve as resolve53, dirname as dirname19, basename as basename13, extname as extname13 } from "node:path";
|
|
56843
|
+
import { existsSync as existsSync46 } from "node:fs";
|
|
57248
56844
|
init_dist2();
|
|
57249
56845
|
init_engine();
|
|
57250
56846
|
init_api_key();
|
|
@@ -57275,11 +56871,11 @@ function filterHighlights(highlights, options) {
|
|
|
57275
56871
|
}
|
|
57276
56872
|
async function executeHighlights(options) {
|
|
57277
56873
|
try {
|
|
57278
|
-
const absPath =
|
|
57279
|
-
if (!
|
|
56874
|
+
const absPath = resolve53(process.cwd(), options.media);
|
|
56875
|
+
if (!existsSync46(absPath)) {
|
|
57280
56876
|
return { success: false, highlights: [], totalDuration: 0, totalHighlightDuration: 0, error: `File not found: ${absPath}` };
|
|
57281
56877
|
}
|
|
57282
|
-
const ext =
|
|
56878
|
+
const ext = extname13(absPath).toLowerCase();
|
|
57283
56879
|
const videoExtensions = [".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"];
|
|
57284
56880
|
const isVideo = videoExtensions.includes(ext);
|
|
57285
56881
|
const targetDuration = options.duration;
|
|
@@ -57295,7 +56891,7 @@ async function executeHighlights(options) {
|
|
|
57295
56891
|
sourceDuration = await ffprobeDuration(absPath);
|
|
57296
56892
|
const gemini = new GeminiProvider();
|
|
57297
56893
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
57298
|
-
const videoBuffer = await
|
|
56894
|
+
const videoBuffer = await readFile38(absPath);
|
|
57299
56895
|
const criteriaText = options.criteria === "all" || !options.criteria ? "emotional, informative, and funny moments" : `${options.criteria} moments`;
|
|
57300
56896
|
const durationText = targetDuration ? `Target a total highlight duration of ${targetDuration} seconds.` : "";
|
|
57301
56897
|
const countText = maxCount ? `Find up to ${maxCount} highlights.` : "";
|
|
@@ -57388,7 +56984,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
57388
56984
|
sourceDuration = await ffprobeDuration(absPath);
|
|
57389
56985
|
}
|
|
57390
56986
|
const transcriptResult = await transcribeAudioFile(audioPath, { apiKey: openaiApiKey, language: options.language });
|
|
57391
|
-
if (tempAudioPath &&
|
|
56987
|
+
if (tempAudioPath && existsSync46(tempAudioPath)) {
|
|
57392
56988
|
const { unlink: unlinkFile } = await import("node:fs/promises");
|
|
57393
56989
|
await unlinkFile(tempAudioPath).catch(() => {
|
|
57394
56990
|
});
|
|
@@ -57419,7 +57015,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
57419
57015
|
totalHighlightDuration
|
|
57420
57016
|
};
|
|
57421
57017
|
if (options.output) {
|
|
57422
|
-
const outputPath =
|
|
57018
|
+
const outputPath = resolve53(process.cwd(), options.output);
|
|
57423
57019
|
await writeFile37(outputPath, JSON.stringify({
|
|
57424
57020
|
sourceFile: absPath,
|
|
57425
57021
|
totalDuration: sourceDuration,
|
|
@@ -57434,7 +57030,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
57434
57030
|
if (options.project) {
|
|
57435
57031
|
const project = new Project("Highlight Reel");
|
|
57436
57032
|
const source = project.addSource({
|
|
57437
|
-
name:
|
|
57033
|
+
name: basename13(absPath),
|
|
57438
57034
|
url: absPath,
|
|
57439
57035
|
type: isVideo ? "video" : "audio",
|
|
57440
57036
|
duration: sourceDuration
|
|
@@ -57454,7 +57050,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
57454
57050
|
currentTime += highlight.duration;
|
|
57455
57051
|
}
|
|
57456
57052
|
}
|
|
57457
|
-
const projectPath =
|
|
57053
|
+
const projectPath = resolve53(process.cwd(), options.project);
|
|
57458
57054
|
await writeFile37(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
57459
57055
|
extractResult.projectPath = projectPath;
|
|
57460
57056
|
}
|
|
@@ -57474,8 +57070,8 @@ async function executeAutoShorts(options) {
|
|
|
57474
57070
|
if (!commandExists("ffmpeg")) {
|
|
57475
57071
|
return { success: false, shorts: [], error: "FFmpeg not found" };
|
|
57476
57072
|
}
|
|
57477
|
-
const absPath =
|
|
57478
|
-
if (!
|
|
57073
|
+
const absPath = resolve53(process.cwd(), options.video);
|
|
57074
|
+
if (!existsSync46(absPath)) {
|
|
57479
57075
|
return { success: false, shorts: [], error: `File not found: ${absPath}` };
|
|
57480
57076
|
}
|
|
57481
57077
|
const targetDuration = options.duration ?? 60;
|
|
@@ -57488,7 +57084,7 @@ async function executeAutoShorts(options) {
|
|
|
57488
57084
|
}
|
|
57489
57085
|
const gemini = new GeminiProvider();
|
|
57490
57086
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
57491
|
-
const videoBuffer = await
|
|
57087
|
+
const videoBuffer = await readFile38(absPath);
|
|
57492
57088
|
const geminiPrompt = `Analyze this video to find the BEST moments for short-form vertical video content (TikTok, YouTube Shorts, Instagram Reels).
|
|
57493
57089
|
|
|
57494
57090
|
Find ${shortCount * 3} potential clips that are ${targetDuration} seconds or shorter each.
|
|
@@ -57598,8 +57194,8 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
57598
57194
|
}))
|
|
57599
57195
|
};
|
|
57600
57196
|
}
|
|
57601
|
-
const outputDir = options.outputDir ?
|
|
57602
|
-
if (options.outputDir && !
|
|
57197
|
+
const outputDir = options.outputDir ? resolve53(process.cwd(), options.outputDir) : dirname19(absPath);
|
|
57198
|
+
if (options.outputDir && !existsSync46(outputDir)) {
|
|
57603
57199
|
await mkdir24(outputDir, { recursive: true });
|
|
57604
57200
|
}
|
|
57605
57201
|
const result = {
|
|
@@ -57608,8 +57204,8 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
57608
57204
|
};
|
|
57609
57205
|
for (let i = 0; i < selectedHighlights.length; i++) {
|
|
57610
57206
|
const h = selectedHighlights[i];
|
|
57611
|
-
const baseName =
|
|
57612
|
-
const outputPath =
|
|
57207
|
+
const baseName = basename13(absPath, extname13(absPath));
|
|
57208
|
+
const outputPath = resolve53(outputDir, `${baseName}-short-${i + 1}.mp4`);
|
|
57613
57209
|
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
57614
57210
|
"-v",
|
|
57615
57211
|
"error",
|
|
@@ -57677,9 +57273,9 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
57677
57273
|
|
|
57678
57274
|
// src/pipeline/executor.ts
|
|
57679
57275
|
var import_yaml8 = __toESM(require_dist2(), 1);
|
|
57680
|
-
import { resolve as
|
|
57681
|
-
import { readFile as
|
|
57682
|
-
import { existsSync as
|
|
57276
|
+
import { resolve as resolve55 } from "node:path";
|
|
57277
|
+
import { readFile as readFile40, writeFile as writeFile39, mkdir as mkdir25 } from "node:fs/promises";
|
|
57278
|
+
import { existsSync as existsSync47 } from "node:fs";
|
|
57683
57279
|
|
|
57684
57280
|
// src/pipeline/resolver.ts
|
|
57685
57281
|
function resolveStepParams(params, completedSteps) {
|
|
@@ -57788,14 +57384,14 @@ function registerAction(action, handler) {
|
|
|
57788
57384
|
}
|
|
57789
57385
|
function getOutput(params, outputDir, defaultName) {
|
|
57790
57386
|
if (params.output && typeof params.output === "string") {
|
|
57791
|
-
return
|
|
57387
|
+
return resolve55(outputDir, params.output);
|
|
57792
57388
|
}
|
|
57793
|
-
return
|
|
57389
|
+
return resolve55(outputDir, defaultName);
|
|
57794
57390
|
}
|
|
57795
57391
|
function stringParam(value) {
|
|
57796
57392
|
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
57797
57393
|
}
|
|
57798
|
-
function
|
|
57394
|
+
function numberParam(value) {
|
|
57799
57395
|
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
57800
57396
|
if (typeof value === "string" && value.trim() !== "") {
|
|
57801
57397
|
const n = Number(value);
|
|
@@ -57863,7 +57459,7 @@ async function ensureActionsRegistered() {
|
|
|
57863
57459
|
ratio: stringParam(params.ratio),
|
|
57864
57460
|
size: stringParam(params.size),
|
|
57865
57461
|
quality: stringParam(params.quality),
|
|
57866
|
-
count:
|
|
57462
|
+
count: numberParam(params.count),
|
|
57867
57463
|
apiKey: await apiKeyForProvider(providerKeyForImage(provider))
|
|
57868
57464
|
});
|
|
57869
57465
|
return { id: "", action: "generate-image", success: r.success, output: r.outputPath, data: { provider: r.provider, model: r.model }, error: r.error };
|
|
@@ -57876,9 +57472,9 @@ async function ensureActionsRegistered() {
|
|
|
57876
57472
|
prompt: params.prompt,
|
|
57877
57473
|
provider,
|
|
57878
57474
|
image: stringParam(params.image),
|
|
57879
|
-
duration:
|
|
57475
|
+
duration: numberParam(params.duration),
|
|
57880
57476
|
ratio: stringParam(params.ratio),
|
|
57881
|
-
seed:
|
|
57477
|
+
seed: numberParam(params.seed),
|
|
57882
57478
|
mode: stringParam(params.mode),
|
|
57883
57479
|
negative: stringParam(params.negative),
|
|
57884
57480
|
resolution: stringParam(params.resolution),
|
|
@@ -58026,7 +57622,7 @@ async function ensureActionsRegistered() {
|
|
|
58026
57622
|
const { executeSceneBuild: executeSceneBuild2 } = await Promise.resolve().then(() => (init_scene_build(), scene_build_exports));
|
|
58027
57623
|
const projectRel = params.project ?? ".";
|
|
58028
57624
|
const r = await executeSceneBuild2({
|
|
58029
|
-
projectDir:
|
|
57625
|
+
projectDir: resolve55(outputDir, projectRel),
|
|
58030
57626
|
mode: params.mode,
|
|
58031
57627
|
composer: params.composer,
|
|
58032
57628
|
skipNarration: params.skipNarration,
|
|
@@ -58052,7 +57648,7 @@ async function ensureActionsRegistered() {
|
|
|
58052
57648
|
const { executeSceneRender: executeSceneRender2 } = await Promise.resolve().then(() => (init_scene_render(), scene_render_exports));
|
|
58053
57649
|
const projectRel = params.project ?? ".";
|
|
58054
57650
|
const r = await executeSceneRender2({
|
|
58055
|
-
projectDir:
|
|
57651
|
+
projectDir: resolve55(outputDir, projectRel),
|
|
58056
57652
|
root: params.root,
|
|
58057
57653
|
output: params.output,
|
|
58058
57654
|
fps: params.fps,
|
|
@@ -58076,11 +57672,11 @@ async function ensureActionsRegistered() {
|
|
|
58076
57672
|
});
|
|
58077
57673
|
}
|
|
58078
57674
|
async function loadPipeline(filePath) {
|
|
58079
|
-
const absPath =
|
|
58080
|
-
if (!
|
|
57675
|
+
const absPath = resolve55(process.cwd(), filePath);
|
|
57676
|
+
if (!existsSync47(absPath)) {
|
|
58081
57677
|
throw new Error(`Pipeline file not found: ${absPath}`);
|
|
58082
57678
|
}
|
|
58083
|
-
const content = await
|
|
57679
|
+
const content = await readFile40(absPath, "utf-8");
|
|
58084
57680
|
const manifest2 = (0, import_yaml8.parse)(content);
|
|
58085
57681
|
if (!manifest2.name) throw new Error("Pipeline missing 'name' field");
|
|
58086
57682
|
if (!manifest2.steps || !Array.isArray(manifest2.steps)) throw new Error("Pipeline missing 'steps' array");
|
|
@@ -58096,15 +57692,15 @@ async function loadPipeline(filePath) {
|
|
|
58096
57692
|
var CHECKPOINT_FILE = ".pipeline-state.yaml";
|
|
58097
57693
|
async function executePipeline(manifest2, options = {}) {
|
|
58098
57694
|
await ensureActionsRegistered();
|
|
58099
|
-
const outputDir =
|
|
57695
|
+
const outputDir = resolve55(process.cwd(), options.outputDir || `${manifest2.name}-output`);
|
|
58100
57696
|
await mkdir25(outputDir, { recursive: true });
|
|
58101
57697
|
const completedSteps = /* @__PURE__ */ new Map();
|
|
58102
57698
|
const results = [];
|
|
58103
57699
|
const startTime = Date.now();
|
|
58104
57700
|
if (options.resume) {
|
|
58105
|
-
const checkpointPath =
|
|
58106
|
-
if (
|
|
58107
|
-
const checkpointContent = await
|
|
57701
|
+
const checkpointPath = resolve55(outputDir, CHECKPOINT_FILE);
|
|
57702
|
+
if (existsSync47(checkpointPath)) {
|
|
57703
|
+
const checkpointContent = await readFile40(checkpointPath, "utf-8");
|
|
58108
57704
|
const checkpoint = (0, import_yaml8.parse)(checkpointContent);
|
|
58109
57705
|
for (const cs of checkpoint.completedSteps) {
|
|
58110
57706
|
completedSteps.set(cs.id, {
|
|
@@ -58223,7 +57819,7 @@ async function executePipeline(manifest2, options = {}) {
|
|
|
58223
57819
|
}))
|
|
58224
57820
|
};
|
|
58225
57821
|
await writeFile39(
|
|
58226
|
-
|
|
57822
|
+
resolve55(outputDir, CHECKPOINT_FILE),
|
|
58227
57823
|
(0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
|
|
58228
57824
|
"utf-8"
|
|
58229
57825
|
);
|
|
@@ -58513,17 +58109,17 @@ var detectTools = [
|
|
|
58513
58109
|
|
|
58514
58110
|
// src/tools/manifest/timeline.ts
|
|
58515
58111
|
import { mkdir as mkdir26, writeFile as writeFile42 } from "node:fs/promises";
|
|
58516
|
-
import { basename as
|
|
58112
|
+
import { basename as basename15, resolve as resolve56 } from "node:path";
|
|
58517
58113
|
init_engine();
|
|
58518
58114
|
init_project_resolver();
|
|
58519
58115
|
|
|
58520
58116
|
// src/tools/manifest/_project-io.ts
|
|
58521
58117
|
init_engine();
|
|
58522
58118
|
init_project_resolver();
|
|
58523
|
-
import { readFile as
|
|
58119
|
+
import { readFile as readFile41, writeFile as writeFile41 } from "node:fs/promises";
|
|
58524
58120
|
async function loadProject(projectPath, cwd) {
|
|
58525
58121
|
const absPath = await resolveTimelineFile(projectPath, cwd);
|
|
58526
|
-
const content = await
|
|
58122
|
+
const content = await readFile41(absPath, "utf-8");
|
|
58527
58123
|
const data = JSON.parse(content);
|
|
58528
58124
|
return { project: Project.fromJSON(data), absPath };
|
|
58529
58125
|
}
|
|
@@ -58560,16 +58156,16 @@ var timelineCreateTool = defineTool({
|
|
|
58560
58156
|
fps: external_exports.number().optional().describe("Frames per second (default: 30)")
|
|
58561
58157
|
}),
|
|
58562
58158
|
async execute(args, ctx) {
|
|
58563
|
-
const projectName = args.name === "." ?
|
|
58159
|
+
const projectName = args.name === "." ? basename15(ctx.workingDirectory) : basename15(resolve56(ctx.workingDirectory, args.name));
|
|
58564
58160
|
const project = new Project(projectName);
|
|
58565
58161
|
if (args.fps) project.setFrameRate(args.fps);
|
|
58566
58162
|
let outputPath;
|
|
58567
58163
|
if (args.outputPath) {
|
|
58568
|
-
outputPath =
|
|
58164
|
+
outputPath = resolve56(ctx.workingDirectory, args.outputPath);
|
|
58569
58165
|
} else {
|
|
58570
|
-
const dirPath =
|
|
58166
|
+
const dirPath = resolve56(ctx.workingDirectory, args.name);
|
|
58571
58167
|
await mkdir26(dirPath, { recursive: true });
|
|
58572
|
-
outputPath =
|
|
58168
|
+
outputPath = resolve56(dirPath, TIMELINE_FILENAME);
|
|
58573
58169
|
}
|
|
58574
58170
|
await writeFile42(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
58575
58171
|
return {
|
|
@@ -58623,7 +58219,7 @@ var timelineAddSourceTool = defineTool({
|
|
|
58623
58219
|
}),
|
|
58624
58220
|
async execute(args, ctx) {
|
|
58625
58221
|
const { project, absPath } = await loadProject(args.projectPath, ctx.workingDirectory);
|
|
58626
|
-
const mediaPath =
|
|
58222
|
+
const mediaPath = resolve56(ctx.workingDirectory, args.mediaPath);
|
|
58627
58223
|
const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "";
|
|
58628
58224
|
const source = project.addSource({
|
|
58629
58225
|
name: args.name ?? mediaPath.split("/").pop() ?? "media",
|
|
@@ -58867,19 +58463,19 @@ var timelineTools = [
|
|
|
58867
58463
|
];
|
|
58868
58464
|
|
|
58869
58465
|
// src/tools/manifest/project.ts
|
|
58870
|
-
import { resolve as
|
|
58466
|
+
import { resolve as resolve58 } from "node:path";
|
|
58871
58467
|
import { writeFile as writeFile43 } from "node:fs/promises";
|
|
58872
58468
|
init_engine();
|
|
58873
58469
|
|
|
58874
58470
|
// src/commands/_shared/project-list.ts
|
|
58875
58471
|
init_storyboard_parse();
|
|
58876
58472
|
init_storyboard_source();
|
|
58877
|
-
import { readdir as
|
|
58878
|
-
import { existsSync as
|
|
58879
|
-
import { join as join28, resolve as
|
|
58473
|
+
import { readdir as readdir6, readFile as readFile42, stat as stat7 } from "node:fs/promises";
|
|
58474
|
+
import { existsSync as existsSync48 } from "node:fs";
|
|
58475
|
+
import { join as join28, resolve as resolve57 } from "node:path";
|
|
58880
58476
|
async function executeProjectList(opts = {}) {
|
|
58881
|
-
const workspaceDir =
|
|
58882
|
-
if (!
|
|
58477
|
+
const workspaceDir = resolve57(opts.workspaceDir ?? ".");
|
|
58478
|
+
if (!existsSync48(workspaceDir)) {
|
|
58883
58479
|
return {
|
|
58884
58480
|
success: false,
|
|
58885
58481
|
workspaceDir,
|
|
@@ -58888,7 +58484,7 @@ async function executeProjectList(opts = {}) {
|
|
|
58888
58484
|
error: `Workspace directory not found: ${workspaceDir}`
|
|
58889
58485
|
};
|
|
58890
58486
|
}
|
|
58891
|
-
const entries = await
|
|
58487
|
+
const entries = await readdir6(workspaceDir, { withFileTypes: true });
|
|
58892
58488
|
const projects = [];
|
|
58893
58489
|
let archivedCount = 0;
|
|
58894
58490
|
for (const entry of entries) {
|
|
@@ -58900,7 +58496,7 @@ async function executeProjectList(opts = {}) {
|
|
|
58900
58496
|
continue;
|
|
58901
58497
|
}
|
|
58902
58498
|
const projectDir = join28(workspaceDir, entry.name);
|
|
58903
|
-
if (!
|
|
58499
|
+
if (!existsSync48(join28(projectDir, "STORYBOARD.md"))) continue;
|
|
58904
58500
|
projects.push(await describeProject(entry.name, projectDir));
|
|
58905
58501
|
}
|
|
58906
58502
|
projects.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
@@ -58908,9 +58504,9 @@ async function executeProjectList(opts = {}) {
|
|
|
58908
58504
|
}
|
|
58909
58505
|
async function countProjects(dir) {
|
|
58910
58506
|
try {
|
|
58911
|
-
const entries = await
|
|
58507
|
+
const entries = await readdir6(dir, { withFileTypes: true });
|
|
58912
58508
|
return entries.filter(
|
|
58913
|
-
(e) => e.isDirectory() &&
|
|
58509
|
+
(e) => e.isDirectory() && existsSync48(join28(dir, e.name, "STORYBOARD.md"))
|
|
58914
58510
|
).length;
|
|
58915
58511
|
} catch {
|
|
58916
58512
|
return 0;
|
|
@@ -58934,7 +58530,7 @@ async function describeProject(name, projectDir) {
|
|
|
58934
58530
|
let buildUpdatedAt;
|
|
58935
58531
|
try {
|
|
58936
58532
|
const reportPath = join28(projectDir, "build-report.json");
|
|
58937
|
-
const report = JSON.parse(await
|
|
58533
|
+
const report = JSON.parse(await readFile42(reportPath, "utf-8"));
|
|
58938
58534
|
buildStatus = report.status ?? report.phase;
|
|
58939
58535
|
buildUpdatedAt = report.updatedAt;
|
|
58940
58536
|
timestamps.push((await stat7(reportPath)).mtimeMs);
|
|
@@ -58943,7 +58539,7 @@ async function describeProject(name, projectDir) {
|
|
|
58943
58539
|
let latestRender;
|
|
58944
58540
|
try {
|
|
58945
58541
|
const rendersDir = join28(projectDir, "renders");
|
|
58946
|
-
const files = await
|
|
58542
|
+
const files = await readdir6(rendersDir);
|
|
58947
58543
|
let newest;
|
|
58948
58544
|
for (const file of files) {
|
|
58949
58545
|
if (!/\.(mp4|webm|mov)$/i.test(file)) continue;
|
|
@@ -58986,7 +58582,7 @@ var projectListTool = defineTool({
|
|
|
58986
58582
|
}),
|
|
58987
58583
|
async execute(args, ctx) {
|
|
58988
58584
|
const result = await executeProjectList({
|
|
58989
|
-
workspaceDir: args.dir ?
|
|
58585
|
+
workspaceDir: args.dir ? resolve58(ctx.workingDirectory, args.dir) : ctx.workingDirectory
|
|
58990
58586
|
});
|
|
58991
58587
|
if (!result.success) {
|
|
58992
58588
|
return { success: false, error: result.error ?? "project list failed" };
|
|
@@ -59023,7 +58619,7 @@ var projectCreateTool = defineTool({
|
|
|
59023
58619
|
fps: external_exports.number().optional().describe("Frames per second (default: 30)")
|
|
59024
58620
|
}),
|
|
59025
58621
|
async execute(args, ctx) {
|
|
59026
|
-
const outputPath =
|
|
58622
|
+
const outputPath = resolve58(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
|
|
59027
58623
|
const project = new Project(args.name);
|
|
59028
58624
|
if (args.fps) project.setFrameRate(args.fps);
|
|
59029
58625
|
await writeFile43(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
@@ -59070,14 +58666,14 @@ var projectTools = [
|
|
|
59070
58666
|
];
|
|
59071
58667
|
|
|
59072
58668
|
// src/tools/manifest/export.ts
|
|
59073
|
-
import { resolve as
|
|
58669
|
+
import { resolve as resolve60 } from "node:path";
|
|
59074
58670
|
|
|
59075
58671
|
// src/commands/export.ts
|
|
59076
58672
|
init_engine();
|
|
59077
58673
|
init_exec_safe();
|
|
59078
58674
|
init_project_resolver();
|
|
59079
|
-
import { readFile as
|
|
59080
|
-
import { resolve as
|
|
58675
|
+
import { readFile as readFile43, access as access6 } from "node:fs/promises";
|
|
58676
|
+
import { resolve as resolve59 } from "node:path";
|
|
59081
58677
|
import { spawn } from "node:child_process";
|
|
59082
58678
|
async function getMediaDuration(filePath, mediaType, defaultImageDuration = 5) {
|
|
59083
58679
|
if (mediaType === "image") {
|
|
@@ -59147,7 +58743,7 @@ async function runExport(projectPath, outputPath, options = {}) {
|
|
|
59147
58743
|
};
|
|
59148
58744
|
}
|
|
59149
58745
|
const filePath = await resolveTimelineFile(projectPath);
|
|
59150
|
-
const content = await
|
|
58746
|
+
const content = await readFile43(filePath, "utf-8");
|
|
59151
58747
|
const data = JSON.parse(content);
|
|
59152
58748
|
const project = Project.fromJSON(data);
|
|
59153
58749
|
const summary = project.getSummary();
|
|
@@ -59157,7 +58753,7 @@ async function runExport(projectPath, outputPath, options = {}) {
|
|
|
59157
58753
|
message: "Project has no clips to export"
|
|
59158
58754
|
};
|
|
59159
58755
|
}
|
|
59160
|
-
const finalOutputPath =
|
|
58756
|
+
const finalOutputPath = resolve59(process.cwd(), outputPath);
|
|
59161
58757
|
const basePresetSettings = getPresetSettings(preset, summary.aspectRatio);
|
|
59162
58758
|
const presetSettings = applyCustomOverrides(basePresetSettings, { bitrate, fps, resolution, codec });
|
|
59163
58759
|
const clips = project.getClips().sort((a, b) => a.startTime - b.startTime);
|
|
@@ -59553,7 +59149,7 @@ function buildFFmpegArgs(clips, sources, presetSettings, outputPath, options, so
|
|
|
59553
59149
|
return args;
|
|
59554
59150
|
}
|
|
59555
59151
|
function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
59556
|
-
return new Promise((
|
|
59152
|
+
return new Promise((resolve63, reject) => {
|
|
59557
59153
|
const ffmpeg = spawn(ffmpegPath, args, {
|
|
59558
59154
|
stdio: ["pipe", "pipe", "pipe"]
|
|
59559
59155
|
});
|
|
@@ -59577,7 +59173,7 @@ function runFFmpegProcess(ffmpegPath, args, onProgress) {
|
|
|
59577
59173
|
});
|
|
59578
59174
|
ffmpeg.on("close", (code) => {
|
|
59579
59175
|
if (code === 0) {
|
|
59580
|
-
|
|
59176
|
+
resolve63();
|
|
59581
59177
|
} else {
|
|
59582
59178
|
const errorMatch = stderr.match(/Error.*$/m);
|
|
59583
59179
|
const errorMsg = errorMatch ? errorMatch[0] : `FFmpeg exited with code ${code}`;
|
|
@@ -59728,8 +59324,8 @@ var exportVideoTool = defineTool({
|
|
|
59728
59324
|
overwrite: external_exports.boolean().optional().describe("Overwrite existing output file (default: false)")
|
|
59729
59325
|
}),
|
|
59730
59326
|
async execute(args, ctx) {
|
|
59731
|
-
const projectPath =
|
|
59732
|
-
const outputPath =
|
|
59327
|
+
const projectPath = resolve60(ctx.workingDirectory, args.projectPath);
|
|
59328
|
+
const outputPath = resolve60(ctx.workingDirectory, args.outputPath);
|
|
59733
59329
|
const result = await runExport(projectPath, outputPath, {
|
|
59734
59330
|
preset: args.preset,
|
|
59735
59331
|
format: args.format,
|
|
@@ -59746,8 +59342,8 @@ var exportVideoTool = defineTool({
|
|
|
59746
59342
|
var exportTools = [exportVideoTool];
|
|
59747
59343
|
|
|
59748
59344
|
// src/tools/manifest/agent-only.ts
|
|
59749
|
-
import { readFile as
|
|
59750
|
-
import { resolve as
|
|
59345
|
+
import { readFile as readFile44, writeFile as writeFile44, readdir as readdir7, stat as stat8, access as access7, unlink as unlink2 } from "node:fs/promises";
|
|
59346
|
+
import { resolve as resolve61, join as join29, basename as basename16, extname as extname14 } from "node:path";
|
|
59751
59347
|
init_engine();
|
|
59752
59348
|
init_exec_safe();
|
|
59753
59349
|
init_project_resolver();
|
|
@@ -59769,7 +59365,7 @@ function formatSize(bytes) {
|
|
|
59769
59365
|
return `${size.toFixed(1)}${units2[unit]}`;
|
|
59770
59366
|
}
|
|
59771
59367
|
function detectMediaType(filePath) {
|
|
59772
|
-
const ext =
|
|
59368
|
+
const ext = extname14(filePath).toLowerCase();
|
|
59773
59369
|
if ([".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"].includes(ext)) return "video";
|
|
59774
59370
|
if ([".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a"].includes(ext)) return "audio";
|
|
59775
59371
|
if ([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"].includes(ext)) return "image";
|
|
@@ -59796,7 +59392,7 @@ function isMediaFile(filePath) {
|
|
|
59796
59392
|
".webp",
|
|
59797
59393
|
".bmp"
|
|
59798
59394
|
];
|
|
59799
|
-
return mediaExts.includes(
|
|
59395
|
+
return mediaExts.includes(extname14(filePath).toLowerCase());
|
|
59800
59396
|
}
|
|
59801
59397
|
async function getMediaDuration2(filePath) {
|
|
59802
59398
|
try {
|
|
@@ -59820,8 +59416,8 @@ var fsListTool = defineTool({
|
|
|
59820
59416
|
async execute(args, ctx) {
|
|
59821
59417
|
const dirPath = args.path ?? ".";
|
|
59822
59418
|
try {
|
|
59823
|
-
const absPath =
|
|
59824
|
-
const entries = await
|
|
59419
|
+
const absPath = resolve61(ctx.workingDirectory, dirPath);
|
|
59420
|
+
const entries = await readdir7(absPath, { withFileTypes: true });
|
|
59825
59421
|
const results = [];
|
|
59826
59422
|
for (const entry of entries) {
|
|
59827
59423
|
if (args.pattern && !matchPattern(entry.name, args.pattern)) continue;
|
|
@@ -59853,8 +59449,8 @@ var fsReadTool = defineTool({
|
|
|
59853
59449
|
}),
|
|
59854
59450
|
async execute(args, ctx) {
|
|
59855
59451
|
try {
|
|
59856
|
-
const absPath =
|
|
59857
|
-
const content = await
|
|
59452
|
+
const absPath = resolve61(ctx.workingDirectory, args.path);
|
|
59453
|
+
const content = await readFile44(absPath, "utf-8");
|
|
59858
59454
|
const maxLength = 4e3;
|
|
59859
59455
|
const truncated = content.length > maxLength;
|
|
59860
59456
|
const output = truncated ? content.substring(0, maxLength) + "\n... (truncated)" : content;
|
|
@@ -59878,7 +59474,7 @@ var fsWriteTool = defineTool({
|
|
|
59878
59474
|
}),
|
|
59879
59475
|
async execute(args, ctx) {
|
|
59880
59476
|
try {
|
|
59881
|
-
const absPath =
|
|
59477
|
+
const absPath = resolve61(ctx.workingDirectory, args.path);
|
|
59882
59478
|
await writeFile44(absPath, args.content, "utf-8");
|
|
59883
59479
|
return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
|
|
59884
59480
|
} catch (error) {
|
|
@@ -59898,7 +59494,7 @@ var fsExistsTool = defineTool({
|
|
|
59898
59494
|
path: external_exports.string().describe("Path to check")
|
|
59899
59495
|
}),
|
|
59900
59496
|
async execute(args, ctx) {
|
|
59901
|
-
const absPath =
|
|
59497
|
+
const absPath = resolve61(ctx.workingDirectory, args.path);
|
|
59902
59498
|
try {
|
|
59903
59499
|
await access7(absPath);
|
|
59904
59500
|
const stats = await stat8(absPath);
|
|
@@ -59926,23 +59522,23 @@ var batchImportTool = defineTool({
|
|
|
59926
59522
|
}),
|
|
59927
59523
|
async execute(args, ctx) {
|
|
59928
59524
|
try {
|
|
59929
|
-
const filePath =
|
|
59930
|
-
const content = await
|
|
59525
|
+
const filePath = resolve61(ctx.workingDirectory, args.project);
|
|
59526
|
+
const content = await readFile44(filePath, "utf-8");
|
|
59931
59527
|
const data = JSON.parse(content);
|
|
59932
59528
|
const project = Project.fromJSON(data);
|
|
59933
|
-
const dirPath =
|
|
59529
|
+
const dirPath = resolve61(ctx.workingDirectory, args.directory);
|
|
59934
59530
|
const filterExts = args.filter ? args.filter.split(",").map((e) => e.trim().toLowerCase()) : null;
|
|
59935
59531
|
const imageDuration = args.imageDuration ?? 5;
|
|
59936
59532
|
const recursive = args.recursive ?? false;
|
|
59937
59533
|
const mediaFiles = [];
|
|
59938
59534
|
const scanDir = async (dir) => {
|
|
59939
|
-
const entries = await
|
|
59535
|
+
const entries = await readdir7(dir, { withFileTypes: true });
|
|
59940
59536
|
for (const entry of entries) {
|
|
59941
59537
|
const entryPath = join29(dir, entry.name);
|
|
59942
59538
|
if (entry.isDirectory() && recursive) {
|
|
59943
59539
|
await scanDir(entryPath);
|
|
59944
59540
|
} else if (entry.isFile()) {
|
|
59945
|
-
const ext =
|
|
59541
|
+
const ext = extname14(entry.name).toLowerCase();
|
|
59946
59542
|
const matchesFilter = !filterExts || filterExts.includes(ext);
|
|
59947
59543
|
if (matchesFilter && isMediaFile(entryPath)) mediaFiles.push(entryPath);
|
|
59948
59544
|
}
|
|
@@ -59955,7 +59551,7 @@ var batchImportTool = defineTool({
|
|
|
59955
59551
|
mediaFiles.sort();
|
|
59956
59552
|
const addedSources = [];
|
|
59957
59553
|
for (const mediaFile of mediaFiles) {
|
|
59958
|
-
const mediaName =
|
|
59554
|
+
const mediaName = basename16(mediaFile);
|
|
59959
59555
|
const mediaType = detectMediaType(mediaFile);
|
|
59960
59556
|
let duration = imageDuration;
|
|
59961
59557
|
if (mediaType !== "image") {
|
|
@@ -59998,8 +59594,8 @@ var batchConcatTool = defineTool({
|
|
|
59998
59594
|
}),
|
|
59999
59595
|
async execute(args, ctx) {
|
|
60000
59596
|
try {
|
|
60001
|
-
const filePath =
|
|
60002
|
-
const content = await
|
|
59597
|
+
const filePath = resolve61(ctx.workingDirectory, args.project);
|
|
59598
|
+
const content = await readFile44(filePath, "utf-8");
|
|
60003
59599
|
const data = JSON.parse(content);
|
|
60004
59600
|
const project = Project.fromJSON(data);
|
|
60005
59601
|
const sourceIds = args.sourceIds ?? [];
|
|
@@ -60069,8 +59665,8 @@ var batchApplyEffectTool = defineTool({
|
|
|
60069
59665
|
}),
|
|
60070
59666
|
async execute(args, ctx) {
|
|
60071
59667
|
try {
|
|
60072
|
-
const filePath =
|
|
60073
|
-
const content = await
|
|
59668
|
+
const filePath = resolve61(ctx.workingDirectory, args.project);
|
|
59669
|
+
const content = await readFile44(filePath, "utf-8");
|
|
60074
59670
|
const data = JSON.parse(content);
|
|
60075
59671
|
const project = Project.fromJSON(data);
|
|
60076
59672
|
const clipIds = args.clipIds ?? [];
|
|
@@ -60125,7 +59721,7 @@ var timelineClearTool = defineTool({
|
|
|
60125
59721
|
async execute(args, ctx) {
|
|
60126
59722
|
try {
|
|
60127
59723
|
const filePath = await resolveTimelineFile(args.project, ctx.workingDirectory);
|
|
60128
|
-
const content = await
|
|
59724
|
+
const content = await readFile44(filePath, "utf-8");
|
|
60129
59725
|
const data = JSON.parse(content);
|
|
60130
59726
|
const project = Project.fromJSON(data);
|
|
60131
59727
|
const what = args.what ?? "clips";
|
|
@@ -60202,7 +59798,7 @@ var projectSetTool = defineTool({
|
|
|
60202
59798
|
async execute(args, ctx) {
|
|
60203
59799
|
try {
|
|
60204
59800
|
const filePath = await resolveTimelineFile(args.projectPath, ctx.workingDirectory);
|
|
60205
|
-
const content = await
|
|
59801
|
+
const content = await readFile44(filePath, "utf-8");
|
|
60206
59802
|
const data = JSON.parse(content);
|
|
60207
59803
|
const project = Project.fromJSON(data);
|
|
60208
59804
|
const updates = [];
|
|
@@ -60284,15 +59880,15 @@ var projectSaveTool = defineTool({
|
|
|
60284
59880
|
projectPath: external_exports.string().optional().describe("Timeline file or directory (uses current agent timeline if omitted)")
|
|
60285
59881
|
}),
|
|
60286
59882
|
async execute(args, ctx) {
|
|
60287
|
-
const
|
|
60288
|
-
if (!
|
|
59883
|
+
const path = args.projectPath ?? ctx.agent?.projectPath ?? null;
|
|
59884
|
+
if (!path) {
|
|
60289
59885
|
return {
|
|
60290
59886
|
success: false,
|
|
60291
59887
|
error: "No project path specified and no project in context. Open one with project_open first."
|
|
60292
59888
|
};
|
|
60293
59889
|
}
|
|
60294
59890
|
try {
|
|
60295
|
-
const filePath = await resolveTimelineFile(
|
|
59891
|
+
const filePath = await resolveTimelineFile(path, ctx.workingDirectory);
|
|
60296
59892
|
const { project, absPath } = await loadProject(filePath, "");
|
|
60297
59893
|
await saveProject(absPath, project);
|
|
60298
59894
|
return {
|
|
@@ -60361,7 +59957,7 @@ var mediaInfoTool = defineTool({
|
|
|
60361
59957
|
}),
|
|
60362
59958
|
async execute(args, ctx) {
|
|
60363
59959
|
try {
|
|
60364
|
-
const absPath =
|
|
59960
|
+
const absPath = resolve61(ctx.workingDirectory, args.path);
|
|
60365
59961
|
const { stdout } = await execSafe(
|
|
60366
59962
|
"ffprobe",
|
|
60367
59963
|
["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", absPath],
|
|
@@ -60450,10 +60046,10 @@ var mediaCompressTool = defineTool({
|
|
|
60450
60046
|
}),
|
|
60451
60047
|
async execute(args, ctx) {
|
|
60452
60048
|
try {
|
|
60453
|
-
const absInput =
|
|
60049
|
+
const absInput = resolve61(ctx.workingDirectory, args.input);
|
|
60454
60050
|
const ext = args.input.split(".").pop() || "mp4";
|
|
60455
60051
|
const baseName = args.input.replace(/\.[^/.]+$/, "");
|
|
60456
|
-
const outputPath = args.output ?
|
|
60052
|
+
const outputPath = args.output ? resolve61(ctx.workingDirectory, args.output) : resolve61(ctx.workingDirectory, `${baseName}-compressed.${ext}`);
|
|
60457
60053
|
const crfValues = { low: 28, medium: 23, high: 18 };
|
|
60458
60054
|
const crf = crfValues[args.quality ?? "medium"];
|
|
60459
60055
|
await execSafe(
|
|
@@ -60476,8 +60072,8 @@ var mediaCompressTool = defineTool({
|
|
|
60476
60072
|
],
|
|
60477
60073
|
{ maxBuffer: 50 * 1024 * 1024 }
|
|
60478
60074
|
);
|
|
60479
|
-
const inputBuf = await
|
|
60480
|
-
const outputBuf = await
|
|
60075
|
+
const inputBuf = await readFile44(absInput);
|
|
60076
|
+
const outputBuf = await readFile44(outputPath);
|
|
60481
60077
|
const inputSize = inputBuf.length;
|
|
60482
60078
|
const outputSize = outputBuf.length;
|
|
60483
60079
|
const reduction = (inputSize - outputSize) / inputSize * 100;
|
|
@@ -60513,8 +60109,8 @@ var mediaConvertTool = defineTool({
|
|
|
60513
60109
|
}),
|
|
60514
60110
|
async execute(args, ctx) {
|
|
60515
60111
|
try {
|
|
60516
|
-
const absInput =
|
|
60517
|
-
const absOutput =
|
|
60112
|
+
const absInput = resolve61(ctx.workingDirectory, args.input);
|
|
60113
|
+
const absOutput = resolve61(ctx.workingDirectory, args.output);
|
|
60518
60114
|
const codecMap = {
|
|
60519
60115
|
h264: "libx264",
|
|
60520
60116
|
h265: "libx265",
|
|
@@ -60567,11 +60163,11 @@ var mediaConcatTool = defineTool({
|
|
|
60567
60163
|
};
|
|
60568
60164
|
}
|
|
60569
60165
|
try {
|
|
60570
|
-
const absOutput =
|
|
60166
|
+
const absOutput = resolve61(ctx.workingDirectory, args.output);
|
|
60571
60167
|
if (args.reencode) {
|
|
60572
60168
|
const ffmpegArgs = [];
|
|
60573
60169
|
for (const i of args.inputs) {
|
|
60574
|
-
ffmpegArgs.push("-i",
|
|
60170
|
+
ffmpegArgs.push("-i", resolve61(ctx.workingDirectory, i));
|
|
60575
60171
|
}
|
|
60576
60172
|
const filterComplex = args.inputs.map((_, i) => `[${i}:v][${i}:a]`).join("");
|
|
60577
60173
|
ffmpegArgs.push(
|
|
@@ -60586,8 +60182,8 @@ var mediaConcatTool = defineTool({
|
|
|
60586
60182
|
);
|
|
60587
60183
|
await execSafe("ffmpeg", ffmpegArgs, { maxBuffer: 100 * 1024 * 1024 });
|
|
60588
60184
|
} else {
|
|
60589
|
-
const tempList =
|
|
60590
|
-
const listContent = args.inputs.map((i) => `file '${
|
|
60185
|
+
const tempList = resolve61(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
|
|
60186
|
+
const listContent = args.inputs.map((i) => `file '${resolve61(ctx.workingDirectory, i)}'`).join("\n");
|
|
60591
60187
|
await writeFile44(tempList, listContent, "utf-8");
|
|
60592
60188
|
try {
|
|
60593
60189
|
await execSafe(
|
|
@@ -61117,7 +60713,7 @@ var guideTool = defineTool({
|
|
|
61117
60713
|
var guideTools = [guideTool];
|
|
61118
60714
|
|
|
61119
60715
|
// src/tools/manifest/status.ts
|
|
61120
|
-
import { resolve as
|
|
60716
|
+
import { resolve as resolve62 } from "node:path";
|
|
61121
60717
|
init_status_jobs();
|
|
61122
60718
|
var PROJECT_DIR_DESCRIPTION5 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
|
|
61123
60719
|
var statusJobTool = defineTool({
|
|
@@ -61135,7 +60731,7 @@ var statusJobTool = defineTool({
|
|
|
61135
60731
|
output: external_exports.string().optional().describe("Download result media to this path when complete.")
|
|
61136
60732
|
}),
|
|
61137
60733
|
async execute(args, ctx) {
|
|
61138
|
-
const projectDir = args.projectDir ?
|
|
60734
|
+
const projectDir = args.projectDir ? resolve62(ctx.workingDirectory, args.projectDir) : findProjectRoot(ctx.workingDirectory);
|
|
61139
60735
|
const record = await readJobRecord(args.jobId, projectDir);
|
|
61140
60736
|
if (!record) return { success: false, error: `Job not found: ${args.jobId}` };
|
|
61141
60737
|
const result = args.refresh === false ? makeJobStatusResult(record, {
|
|
@@ -61144,7 +60740,7 @@ var statusJobTool = defineTool({
|
|
|
61144
60740
|
warnings: []
|
|
61145
60741
|
}) : await refreshJobRecord(record, {
|
|
61146
60742
|
wait: args.wait,
|
|
61147
|
-
output: args.output ?
|
|
60743
|
+
output: args.output ? resolve62(ctx.workingDirectory, args.output) : void 0,
|
|
61148
60744
|
workingDirectory: ctx.workingDirectory
|
|
61149
60745
|
});
|
|
61150
60746
|
return {
|
|
@@ -61169,7 +60765,7 @@ var statusProjectTool = defineTool({
|
|
|
61169
60765
|
refresh: external_exports.boolean().optional().describe("Refresh active supported jobs before summarizing. Default false.")
|
|
61170
60766
|
}),
|
|
61171
60767
|
async execute(args, ctx) {
|
|
61172
|
-
const projectDir = args.projectDir ?
|
|
60768
|
+
const projectDir = args.projectDir ? resolve62(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
61173
60769
|
const result = await inspectProjectStatus(projectDir, { refresh: args.refresh === true });
|
|
61174
60770
|
return {
|
|
61175
60771
|
success: true,
|