@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.
Files changed (29) hide show
  1. package/dist/commands/_shared/scene-inspect.d.ts +0 -1
  2. package/dist/commands/_shared/scene-render.d.ts +3 -9
  3. package/dist/commands/ai-analyze.d.ts +1 -3
  4. package/dist/commands/ai-helpers.d.ts +0 -8
  5. package/dist/commands/ai-image.d.ts +0 -6
  6. package/dist/commands/edit/lottie-overlay.d.ts +76 -0
  7. package/dist/commands/edit/motion-overlay.d.ts +6 -1
  8. package/dist/commands/generate.d.ts +0 -2
  9. package/dist/commands/output.d.ts +0 -3
  10. package/dist/commands/sanitize.d.ts +0 -5
  11. package/dist/commands/validate.d.ts +0 -11
  12. package/dist/config/index.d.ts +0 -9
  13. package/dist/index.js +1197 -1603
  14. package/dist/pipeline/executor.d.ts +0 -1
  15. package/dist/pipeline/renderers/chrome.d.ts +3 -4
  16. package/dist/tools/manifest/index.js +817 -1221
  17. package/dist/utils/audio.d.ts +0 -10
  18. package/dist/utils/input-validation.d.ts +0 -5
  19. package/dist/utils/remotion.d.ts +0 -14
  20. package/dist/utils/tty.d.ts +0 -8
  21. package/package.json +4 -6
  22. package/dist/pipeline/renderers/html-clips.d.ts +0 -19
  23. package/dist/pipeline/renderers/html-runtime.d.ts +0 -6
  24. package/dist/pipeline/renderers/html-template.d.ts +0 -2
  25. package/dist/pipeline/renderers/hyperframes.d.ts +0 -7
  26. package/dist/pipeline/renderers/project-builder.d.ts +0 -7
  27. package/dist/pipeline/renderers/types.d.ts +0 -39
  28. /package/dist/{pipeline/renderers/__tests__/html-template.test.d.ts → commands/edit/lottie-overlay.integration.test.d.ts} +0 -0
  29. /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((resolve64) => setTimeout(resolve64, ms));
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((resolve64, reject) => {
2046
- const timer = setTimeout(resolve64, ms);
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 path2;
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
- path2 = "/videos/extensions";
2531
+ path = "/videos/extensions";
2532
2532
  body.duration = Math.round(Math.min(10, Math.max(2, request.durationSec ?? 6)));
2533
2533
  } else {
2534
- path2 = "/videos/edits";
2534
+ path = "/videos/edits";
2535
2535
  }
2536
2536
  } else {
2537
- path2 = "/videos/generations";
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}${path2}`, {
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(path2, init) {
3105
- return providerRequest(this.speechProvider, `${this.baseUrl}${path2}`, {
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: readFile44 } = await import("node:fs/promises");
3373
- const { join: join30, resolve: resolve64 } = await import("node:path");
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 = resolve64(baseDir, "node_modules", "kokoro-js");
3376
- const pkg = JSON.parse(await readFile44(join30(pkgDir, "package.json"), "utf-8"));
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: readFile44, writeFile: writeFile45, mkdir: mkdir27 } = await import("node:fs/promises");
3392
- const { join: join30, resolve: resolve64 } = await import("node:path");
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 = resolve64(base, "node_modules", "@huggingface", "transformers");
3396
- const ortDistDir = resolve64(base, "node_modules", "onnxruntime-web", "dist");
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 readFile44(join30(cacheRoot, encodeURIComponent(String(key)))));
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(resolve64) {
3721
- resolve64(value);
3720
+ return value instanceof P ? value : new P(function(resolve63) {
3721
+ resolve63(value);
3722
3722
  });
3723
3723
  }
3724
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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(resolve64) {
3826
- resolve64(value);
3825
+ return value instanceof P ? value : new P(function(resolve63) {
3826
+ resolve63(value);
3827
3827
  });
3828
3828
  }
3829
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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(resolve64) {
3953
- resolve64(value);
3952
+ return value instanceof P ? value : new P(function(resolve63) {
3953
+ resolve63(value);
3954
3954
  });
3955
3955
  }
3956
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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, path2, defaultPath) {
4016
- if (path2) {
4017
- return `/${path2.replace(/^\/+/, "")}`;
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((resolve64) => setTimeout(resolve64, ms));
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(resolve64) {
4078
- resolve64(value);
4077
+ return value instanceof P ? value : new P(function(resolve63) {
4078
+ resolve63(value);
4079
4079
  });
4080
4080
  }
4081
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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(resolve64) {
4305
- resolve64(value);
4304
+ return value instanceof P ? value : new P(function(resolve63) {
4305
+ resolve63(value);
4306
4306
  });
4307
4307
  }
4308
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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 path2 = ((_b = options.path) !== null && _b !== void 0 ? _b : "").replace(/^\//, "").replace(/\/{2,}/, "/");
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}${path2}${queryParams}`;
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}/${path2}`;
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(resolve64) {
4412
- resolve64(value);
4411
+ return value instanceof P ? value : new P(function(resolve63) {
4412
+ resolve63(value);
4413
4413
  });
4414
4414
  }
4415
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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(resolve64) {
4760
- resolve64(value);
4759
+ return value instanceof P ? value : new P(function(resolve63) {
4760
+ resolve63(value);
4761
4761
  });
4762
4762
  }
4763
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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(resolve64) {
4819
- resolve64(value);
4818
+ return value instanceof P ? value : new P(function(resolve63) {
4819
+ resolve63(value);
4820
4820
  });
4821
4821
  }
4822
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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((resolve64, reject) => {
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
- resolve64((_a2 = this.currentData) !== null && _a2 !== void 0 ? _a2 : {});
5082
+ resolve63((_a2 = this.currentData) !== null && _a2 !== void 0 ? _a2 : {});
5083
5083
  });
5084
5084
  this.on("done", (data) => {
5085
5085
  this.streamClosed = true;
5086
- resolve64(data);
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((resolve64) => setTimeout(resolve64, 16)));
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(resolve64) {
5157
- resolve64(value);
5156
+ return value instanceof P ? value : new P(function(resolve63) {
5157
+ resolve63(value);
5158
5158
  });
5159
5159
  }
5160
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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((resolve64, reject) => {
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
- resolve64(requestStatus);
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(resolve64) {
7305
- resolve64(value);
7304
+ return value instanceof P ? value : new P(function(resolve63) {
7305
+ resolve63(value);
7306
7306
  });
7307
7307
  }
7308
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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: path2 }) {
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, path2, "/realtime")) !== null && _a !== void 0 ? _a : "";
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: path2,
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, path2, "/realtime")) !== null && _a !== void 0 ? _a : "";
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: path2 }));
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(resolve64) {
7650
- resolve64(value);
7649
+ return value instanceof P ? value : new P(function(resolve63) {
7650
+ resolve63(value);
7651
7651
  });
7652
7652
  }
7653
- return new (P || (P = Promise))(function(resolve64, reject) {
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 ? resolve64(result.value) : adopt(result.value).then(fulfilled, rejected);
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 path2 = Array.isArray(fieldError.loc) ? fieldError.loc.join(".") : "body";
7872
- return `${path2}: ${fieldError.msg ?? fieldError.type ?? "invalid"}`;
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(path2, body, token) {
8462
- const response = await providerRequest(this.id, `${this.baseUrl}${path2}`, {
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((resolve64) => setTimeout(resolve64, ms));
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 path2 = __require("path");
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 = path2.resolve(process.cwd(), ".env.vault");
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] === "~" ? path2.join(os2.homedir(), envPath.slice(1)) : envPath;
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 = path2.resolve(process.cwd(), ".env");
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 path3 of optionPaths) {
12324
+ for (const path2 of optionPaths) {
12325
12325
  try {
12326
- const parsed = DotenvModule.parse(fs.readFileSync(path3, { encoding }));
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 ${path3} ${e.message}`);
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 relative12 = path2.relative(process.cwd(), filePath);
12344
- shortPaths.push(relative12);
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, path2) {
13041
- const ctrl = callVisitor(key, node, visitor, path2);
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, path2, ctrl);
13044
- return visit_(key, ctrl, visitor, path2);
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
- path2 = Object.freeze(path2.concat(node));
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, path2);
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
- path2 = Object.freeze(path2.concat(node));
13062
- const ck = visit_("key", node.key, visitor, path2);
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, path2);
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, path2) {
13089
- const ctrl = await callVisitor(key, node, visitor, path2);
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, path2, ctrl);
13092
- return visitAsync_(key, ctrl, visitor, path2);
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
- path2 = Object.freeze(path2.concat(node));
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, path2);
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
- path2 = Object.freeze(path2.concat(node));
13110
- const ck = await visitAsync_("key", node.key, visitor, path2);
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, path2);
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, path2) {
13142
+ function callVisitor(key, node, visitor, path) {
13143
13143
  if (typeof visitor === "function")
13144
- return visitor(key, node, path2);
13144
+ return visitor(key, node, path);
13145
13145
  if (identity.isMap(node))
13146
- return visitor.Map?.(key, node, path2);
13146
+ return visitor.Map?.(key, node, path);
13147
13147
  if (identity.isSeq(node))
13148
- return visitor.Seq?.(key, node, path2);
13148
+ return visitor.Seq?.(key, node, path);
13149
13149
  if (identity.isPair(node))
13150
- return visitor.Pair?.(key, node, path2);
13150
+ return visitor.Pair?.(key, node, path);
13151
13151
  if (identity.isScalar(node))
13152
- return visitor.Scalar?.(key, node, path2);
13152
+ return visitor.Scalar?.(key, node, path);
13153
13153
  if (identity.isAlias(node))
13154
- return visitor.Alias?.(key, node, path2);
13154
+ return visitor.Alias?.(key, node, path);
13155
13155
  return void 0;
13156
13156
  }
13157
- function replaceNode(key, path2, node) {
13158
- const parent = path2[path2.length - 1];
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, path2, value) {
13766
+ function collectionFromPath(schema, path, value) {
13767
13767
  let v = value;
13768
- for (let i = path2.length - 1; i >= 0; --i) {
13769
- const k = path2[i];
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 = (path2) => path2 == null || typeof path2 === "object" && !!path2[Symbol.iterator]().next().done;
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(path2, value) {
13819
- if (isEmptyPath(path2))
13818
+ addIn(path, value) {
13819
+ if (isEmptyPath(path))
13820
13820
  this.add(value);
13821
13821
  else {
13822
- const [key, ...rest] = path2;
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(path2) {
13837
- const [key, ...rest] = path2;
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(path2, keepScalar) {
13852
- const [key, ...rest] = path2;
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(path2) {
13871
- const [key, ...rest] = path2;
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(path2, value) {
13882
- const [key, ...rest] = path2;
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(path2, value) {
16386
+ addIn(path, value) {
16387
16387
  if (assertCollection(this.contents))
16388
- this.contents.addIn(path2, value);
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(path2) {
16464
- if (Collection.isEmptyPath(path2)) {
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(path2) : false;
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(path2, keepScalar) {
16486
- if (Collection.isEmptyPath(path2))
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(path2, keepScalar) : void 0;
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(path2) {
16500
- if (Collection.isEmptyPath(path2))
16499
+ hasIn(path) {
16500
+ if (Collection.isEmptyPath(path))
16501
16501
  return this.contents !== void 0;
16502
- return identity.isCollection(this.contents) ? this.contents.hasIn(path2) : false;
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(path2, value) {
16520
- if (Collection.isEmptyPath(path2)) {
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(path2), value);
16523
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path), value);
16524
16524
  } else if (assertCollection(this.contents)) {
16525
- this.contents.setIn(path2, value);
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, path2) => {
18477
+ visit.itemAtPath = (cst, path) => {
18478
18478
  let item = cst;
18479
- for (const [field, index] of path2) {
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, path2) => {
18489
- const parent = visit.itemAtPath(cst, path2.slice(0, -1));
18490
- const field = path2[path2.length - 1][0];
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(path2, item, visitor) {
18497
- let ctrl = visitor(item, path2);
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(path2.concat([[field, i]])), token.items[i], visitor);
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, path2);
18515
+ ctrl = ctrl(item, path);
18516
18516
  }
18517
18517
  }
18518
- return typeof ctrl === "function" ? ctrl(item, path2) : ctrl;
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(path2) {
20340
+ async function fileExists(path) {
20351
20341
  try {
20352
- await access(path2);
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(path2) {
20406
- if (!await fileExists(path2)) return null;
20395
+ async function readConfigFile(path) {
20396
+ if (!await fileExists(path)) return null;
20407
20397
  try {
20408
- const content = await readFile(path2, "utf-8");
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(path2, error);
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 path2 = getConfigPath(scope, options.cwd);
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(path2, content, "utf-8");
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
- async function updateProviderKey(providerKey, apiKey, options = {}) {
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(path2, cause) {
20490
+ constructor(path, cause) {
20514
20491
  const detail = cause instanceof Error ? cause.message : String(cause);
20515
- super(`Failed to read VibeFrame config at ${path2}: ${detail}`);
20492
+ super(`Failed to read VibeFrame config at ${path}: ${detail}`);
20516
20493
  this.name = "ConfigFileError";
20517
- this.path = path2;
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((resolve64) => {
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
- resolve64(input);
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
- resolve64(answer);
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(path2) {
23427
- return { success: false, error: `File not found: ${path2}`, code: "NOT_FOUND", exitCode: 3 /* NOT_FOUND */, retryable: false };
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(path2, fallback2) {
23895
- return MIME_TYPES[path2.toLowerCase().split(".").pop() ?? ""] ?? fallback2;
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 path2 = join(projectDir, assetMetadataPath(kind, beatId));
24167
- if (!existsSync(path2)) return null;
24143
+ const path = join(projectDir, assetMetadataPath(kind, beatId));
24144
+ if (!existsSync(path)) return null;
24168
24145
  try {
24169
- const parsed = JSON.parse(readFileSync(path2, "utf-8"));
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(path2, report) {
24401
- await writeFile5(path2, JSON.stringify(report, null, 2) + "\n", "utf-8");
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 path2 = join3(dir, sceneFilename(order, beatId));
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
- path2,
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: path2 };
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 path2 = jobRecordPath(record.id, record.projectDir);
25460
- const tmp = `${path2}.${randomUUID2()}.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, path2);
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 path2 = jobRecordPath(id, project);
25468
- if (!existsSync3(path2)) return null;
25469
- return parseJobRecord(await readFile5(path2, "utf-8"));
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, path2) {
26197
- const rel = relative(resolve6(projectDir), resolve6(path2));
26198
- if (!rel || rel.startsWith("..")) return path2;
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(path2) {
26178
+ async function readJson(path) {
26202
26179
  try {
26203
- return JSON.parse(await readFile5(path2, "utf-8"));
26180
+ return JSON.parse(await readFile5(path, "utf-8"));
26204
26181
  } catch {
26205
26182
  return null;
26206
26183
  }
26207
26184
  }
26208
- async function statOrNull(path2) {
26185
+ async function statOrNull(path) {
26209
26186
  try {
26210
- return await stat(path2);
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((resolve64) => setTimeout(resolve64, ms));
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 path2 = __require("node:path");
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 = path2.resolve(baseDir, baseName);
28956
+ const localBin = path.resolve(baseDir, baseName);
28980
28957
  if (fs.existsSync(localBin)) return localBin;
28981
- if (sourceExt.includes(path2.extname(baseName))) return void 0;
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 = path2.resolve(
29000
- path2.dirname(resolvedScriptPath),
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 = path2.basename(
28984
+ const legacyName = path.basename(
29008
28985
  this._scriptPath,
29009
- path2.extname(this._scriptPath)
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(path2.extname(executableFile));
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 = path2.basename(filename, path2.extname(filename));
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(path3) {
29875
- if (path3 === void 0) return this._executableDir;
29876
- this._executableDir = path3;
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(path2, buffer) {
30534
- const wanted = EXTENSION_FORMATS[extname2(path2).toLowerCase()];
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(path2, buffer);
30514
+ await writeFile10(path, buffer);
30538
30515
  return;
30539
30516
  }
30540
- const source = `${path2}.source.${actual === "jpeg" ? "jpg" : actual}`;
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", path2]);
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(path2) {
30580
- const absPath = resolve10(process.cwd(), path2);
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(path2, "image/png") };
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(path2, options) {
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(path2));
31319
- const name = basename3(path2);
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
- (path2) => !isExternalRef(path2) && !pathExists3(opts.projectDir, path2)
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, path2] of narrationEntries) {
33198
+ for (const [beatIndex, path] of narrationEntries) {
33222
33199
  narrationInputIndex.set(beatIndex, sources.length + narrationInputIndex.size);
33223
- args.push("-i", path2);
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 path2 of paths) {
34516
- if (existsSync20(join16(projectDir, path2))) return path2;
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(path2, cwd = process.cwd()) {
34595
- rejectControlChars(path2);
34596
- if (isAbsolute5(path2)) {
34597
- return resolve26(path2);
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, path2);
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 "${path2}" escapes the working directory. Use a path within "${cwd}".`
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, path2] of charResult.paths) characterPaths.set(name, path2);
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 path2 = `compositions/scene-${beatId}.html`;
36907
- const exists = existsSync22(join17(projectDir, path2));
36908
- if (result.stageReports?.compose.status === "failed") return { path: path2, exists, status: "failed" };
36909
- if (result.phase === "needs-author" && !exists) return { path: path2, exists, status: "needs-author" };
36910
- if (exists) return { path: path2, exists, status: "exists" };
36911
- if (result.stageReports?.compose.status === "skipped") return { path: path2, exists, status: "skipped" };
36912
- return { path: path2, exists, status: "needs-author" };
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(path2) {
40184
- this.filePath = path2;
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/pipeline/renderers/html-clips.ts
41178
- function relAsset(url) {
41179
- const basename19 = url.split("/").pop() ?? url;
41180
- return `assets/${basename19}`;
41181
- }
41182
- function numberParam(value, fallback2) {
41183
- const n = typeof value === "number" ? value : Number(value);
41184
- return Number.isFinite(n) ? n : fallback2;
41185
- }
41186
- function boolParam(value, fallback2) {
41187
- if (typeof value === "boolean") return value;
41188
- if (value === "true") return true;
41189
- if (value === "false") return false;
41190
- return fallback2;
41191
- }
41192
- function lottieOverlayParams(clip) {
41193
- const fx = clip.effects.find(
41194
- (effect) => effect.type === "custom" && effect.params.kind === "motion-overlay"
41195
- );
41196
- const rawPosition = String(fx?.params.position ?? "full");
41197
- const position = [
41198
- "full",
41199
- "center",
41200
- "top-left",
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
- position,
41207
- scale: Math.max(0.01, Math.min(2, numberParam(fx?.params.scale, position === "full" ? 1 : 0.25))),
41208
- opacity: Math.max(0, Math.min(1, numberParam(fx?.params.opacity, 1))),
41209
- loop: boolParam(fx?.params.loop, true)
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 lottieInnerStyle(params) {
41213
- const base = [
41214
- "position:absolute",
41215
- "pointer-events:none",
41216
- `opacity:${params.opacity}`
41217
- ];
41218
- if (params.position === "full") {
41219
- return [...base, "inset:0", "width:100%", "height:100%"].join(";");
41220
- }
41221
- const size = `${params.scale * 100}%`;
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 buildClipRuntimeData(state) {
41269
- return state.clips.map((clip) => ({
41270
- id: clip.id,
41271
- startTime: clip.startTime,
41272
- duration: clip.duration,
41273
- effects: clip.effects
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
- var init_html_clips = __esm({
41277
- "src/pipeline/renderers/html-clips.ts"() {
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: #000; }
41383
- #root { position: relative; width: ${width}px; height: ${height}px; }
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
- ${lottieRuntime}</head><body>
41387
- <div id="root" data-composition-id="main" data-start="0" data-duration="${duration}" data-width="${width}" data-height="${height}">
41388
- ${clipMarkup}
41389
- </div>
41390
- <script>
41391
- ${script}
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
- async function copyLottieRuntime(tempDir) {
41233
+ function vendorPaths() {
41441
41234
  const require2 = createRequire(import.meta.url);
41442
- const wcPkgPath = require2.resolve("@lottiefiles/dotlottie-wc/package.json");
41443
- const wcDistDir = path.join(path.dirname(wcPkgPath), "dist");
41444
- const webEntry = require2.resolve("@lottiefiles/dotlottie-web");
41445
- const wasmSrc = path.join(path.dirname(webEntry), "dotlottie-player.wasm");
41446
- const vendorDir = path.join(tempDir, "vendor");
41447
- const wcDest = path.join(vendorDir, "dotlottie-wc");
41448
- await mkdir19(wcDest, { recursive: true });
41449
- for (const file of await readdir4(wcDistDir)) {
41450
- if (file.endsWith(".map") || file.endsWith(".d.ts")) continue;
41451
- await copyFile5(path.join(wcDistDir, file), path.join(wcDest, file));
41452
- }
41453
- await copyFile5(wasmSrc, path.join(vendorDir, "dotlottie-player.wasm"));
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 resolveSourceUrl(url, baseDir) {
41456
- if (url.startsWith("file://")) return url.slice(7);
41457
- if (path.isAbsolute(url)) return url;
41458
- if (baseDir) return path.resolve(baseDir, url);
41459
- return path.resolve(process.cwd(), url);
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
- var init_project_builder = __esm({
41462
- "src/pipeline/renderers/project-builder.ts"() {
41463
- "use strict";
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
- // src/pipeline/renderers/hyperframes.ts
41469
- function createHyperframesBackend() {
41470
- return {
41471
- name: "hyperframes",
41472
- async preflight() {
41473
- return preflightChrome();
41474
- },
41475
- async render(options) {
41476
- const pre = await this.preflight();
41477
- if (!pre.ok) return { success: false, error: pre.reason };
41478
- const { buildTempProject: buildTempProject2 } = await Promise.resolve().then(() => (init_project_builder(), project_builder_exports));
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: `Failed to build temp project: ${err instanceof Error ? err.message : String(err)}`
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
- const config2 = {
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
- function aspectToResolution(ratio) {
41526
- switch (ratio) {
41527
- case "16:9":
41528
- return { width: 1920, height: 1080 };
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
- function qualityToCrf2(quality = "standard") {
41540
- return quality === "draft" ? 28 : quality === "high" ? 18 : 23;
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 existsSync36 } from "node:fs";
41558
- import { basename as basename10, dirname as dirname16, extname as extname8, resolve as resolve37 } from "node:path";
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 = resolve37(process.cwd(), videoPath);
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 = extname8(options.asset).toLowerCase();
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 = resolve37(process.cwd(), options.videoPath);
41688
- if (!existsSync36(absVideo)) return { success: false, error: `Video file not found: ${absVideo}` };
41689
- const outputPath = options.output ? resolve37(process.cwd(), options.output) : defaultOverlayOutput(options.videoPath);
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 = resolve37(process.cwd(), options.asset);
41692
- if (!existsSync36(absAsset)) return { success: false, error: `Lottie asset not found: ${absAsset}` };
41693
- const [videoDuration, size] = await Promise.all([
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
- const requestedDuration = options.duration ?? Math.max(0.1, videoDuration - start);
41699
- const overlayDuration = Math.min(requestedDuration, Math.max(0.1, videoDuration - start));
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
- const scale = Math.max(0.01, Math.min(2, numberOption(options.scale, position === "full" ? 1 : 0.25)));
41702
- const opacity = Math.max(0, Math.min(1, numberOption(options.opacity, 1)));
41703
- const loop = options.loop ?? true;
41704
- await mkdir20(dirname16(outputPath), { recursive: true });
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
- fps: 30,
41722
- quality: "standard",
41723
- format: "mp4",
41724
- workers: 1
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) return { success: false, error: result2.error ?? "Lottie overlay render failed" };
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(dirname16(outputPath), { recursive: true });
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
- exitWithError(apiError(result.error ?? "Motion overlay failed", true));
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
- init_hyperframes();
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 readFile26 } from "node:fs/promises";
41857
- import { existsSync as existsSync37 } from "node:fs";
41858
- function numberedPath(path2, n) {
41859
- const dot = path2.lastIndexOf(".");
41860
- return dot > path2.lastIndexOf("/") ? `${path2.slice(0, dot)}-${n}${path2.slice(dot)}` : `${path2}-${n}`;
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((path2) => readImageInput(path2)));
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 (!existsSync37(videoPath)) {
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 readFile26(videoPath);
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 (!existsSync37(outputPath)) {
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 resolve38 } from "node:path";
42003
- import { readFile as readFile27, writeFile as writeFile28 } from "node:fs/promises";
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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, `-${aspect.replace(":", "x")}$1`);
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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), output) : absPath.replace(/(\.[^.]+)$/, `-${scale}x$1`);
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: resolve38(process.cwd(), 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 = resolve38(process.cwd(), videoPath);
42275
- const gradeOutputPath = options.output ? resolve38(process.cwd(), options.output) : absPath2.replace(/(\.[^.]+)$/, "-graded$1");
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 = resolve38(process.cwd(), videoPath);
42302
- const outputPath = options.output ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-graded$1");
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: resolve38(process.cwd(), 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 = resolve38(process.cwd(), videoPath);
42346
- const outputPath = options.output ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-overlay$1");
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: resolve38(process.cwd(), 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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
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 ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, "-ramped$1");
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: resolve38(process.cwd(), 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 = resolve38(process.cwd(), videoPath);
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 readFile27(framePath);
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 ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
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 = resolve38(process.cwd(), options.keyframes);
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 ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-${options.aspect.replace(":", "x")}$1`);
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) => resolve38(process.cwd(), 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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
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 = resolve38(process.cwd(), videoPath);
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 ? resolve38(process.cwd(), options.output) : absPath.replace(/(\.[^.]+)$/, `-upscaled-${scale}x$1`);
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 readFile28 } from "node:fs/promises";
42907
- import { extname as extname9, resolve as resolve40 } from "node:path";
42908
- import { existsSync as existsSync39 } from "node:fs";
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 = resolve40(process.cwd(), options.source);
42922
- if (!existsSync39(absPath)) {
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 readFile28(absPath);
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 = extname9(source).toLowerCase();
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 = resolve40(process.cwd(), source);
42990
- if (!existsSync39(absPath)) {
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 readFile28(absPath);
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 = resolve40(process.cwd(), source);
43025
- if (!existsSync39(absPath)) {
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 readFile28(absPath);
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 readFile31, rename as rename4 } from "node:fs/promises";
43162
- import { resolve as resolve43 } from "node:path";
43163
- import { existsSync as existsSync41 } from "node:fs";
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 = resolve43(process.cwd(), videoPath);
43195
- if (!existsSync41(absVideoPath)) {
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 = resolve43(process.cwd(), storyboardPath);
43208
- if (existsSync41(absStoryboardPath)) {
43209
- const content = await readFile31(absStoryboardPath, "utf-8");
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 readFile31(absVideoPath);
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 ? resolve43(process.cwd(), options.outputPath) : absVideoPath.replace(/(\.[^.]+)$/, "-reviewed$1");
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 readFile31(result.outputPath);
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 resolve46 } from "node:path";
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 = resolve46(process.cwd(), options.output || "sound-effect.mp3");
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((resolve64) => {
43085
+ return new Promise((resolve63) => {
43494
43086
  rl.question(question, (answer) => {
43495
43087
  rl.close();
43496
- resolve64(answer);
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 dirname18, extname as extname10 } from "node:path";
43513
- async function writeAudioFile(path2, bytes, container) {
43514
- await mkdir22(dirname18(path2), { recursive: true });
43515
- const wanted = extname10(path2).toLowerCase();
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(path2, bytes);
43109
+ await writeFile32(path, bytes);
43518
43110
  return;
43519
43111
  }
43520
- const source = `${path2}.source.${container}`;
43112
+ const source = `${path}.source.${container}`;
43521
43113
  await writeFile32(source, bytes);
43522
43114
  try {
43523
- await execSafe("ffmpeg", ["-y", "-loglevel", "error", "-i", source, path2]);
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 resolve47 } from "node:path";
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 = resolve47(process.cwd(), options.output || `narration.${tts.audioExtension}`);
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 resolve48, dirname as dirname19, basename as basename14, extname as extname11 } from "node:path";
43630
- import { existsSync as existsSync43 } from "node:fs";
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 = resolve48(process.cwd(), options.bestFrame);
43642
- if (!existsSync43(absVideoPath)) {
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 = basename14(options.bestFrame, extname11(options.bestFrame));
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: resolve48(process.cwd(), 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 = resolve48(process.cwd(), options.output);
43722
- await mkdir23(dirname19(outputPath), { recursive: true });
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 = resolve48(process.cwd(), options.output);
43753
- await mkdir23(dirname19(outputPath), { recursive: true });
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 path2 of result.outputPaths) console.log(source_default.green(`Saved to: ${path2}`));
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 resolve49 } from "node:path";
45015
- import { readFile as readFile33 } from "node:fs/promises";
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 readFile33(resolve49(process.cwd(), options.image));
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 resolve50 } from "node:path";
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 = resolve50(process.cwd(), output);
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 readFile38, writeFile as writeFile38 } from "node:fs/promises";
46371
- import { resolve as resolve55, basename as basename16 } from "node:path";
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 = resolve55(process.cwd(), options.videoPath);
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 = resolve55(process.cwd(), options.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 = resolve55(process.cwd(), options.mediaPath);
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 = resolve55(process.cwd(), options.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 = resolve55(process.cwd(), options.audioPath);
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 = resolve55(process.cwd(), options.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 = resolve55(process.cwd(), videoPath);
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 = resolve55(process.cwd(), options.output);
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 = resolve55(process.cwd(), options.project);
46615
- const content = await readFile38(projectPath, "utf-8");
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: basename16(absPath),
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 = resolve55(process.cwd(), mediaPath);
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 = resolve55(process.cwd(), options.output);
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 = resolve55(process.cwd(), audioPath);
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 = resolve55(process.cwd(), options.output);
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: path2, errorMaps, issueData } = params;
47309
- const fullPath = [...path2, ...issueData.path || []];
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, path2, key) {
47015
+ constructor(parent, value, path, key) {
47426
47016
  this._cachedPath = [];
47427
47017
  this.parent = parent;
47428
47018
  this.data = value;
47429
- this._path = path2;
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(path2) {
50981
- const explicit = EXPLICIT_COMMAND_METADATA[path2];
50570
+ function productSurfaceForCommandPath(path) {
50571
+ const explicit = EXPLICIT_COMMAND_METADATA[path];
50982
50572
  if (explicit) return explicit;
50983
- if (path2.startsWith("timeline.")) {
50573
+ if (path.startsWith("timeline.")) {
50984
50574
  return { surface: "advanced", note: "Power tool for low-level timeline JSON edits." };
50985
50575
  }
50986
- if (path2.startsWith("batch.")) {
50576
+ if (path.startsWith("batch.")) {
50987
50577
  return { surface: "advanced", note: "Power tool for bulk timeline/media operations." };
50988
50578
  }
50989
- if (path2.startsWith("media.")) {
50579
+ if (path.startsWith("media.")) {
50990
50580
  return { surface: "advanced", note: "Script utility for media metadata." };
50991
50581
  }
50992
- if (path2.startsWith("detect.")) return { surface: "public" };
50993
- if (path2.startsWith("export.")) {
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 (path2.startsWith("fs.")) {
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
- const writeRecord = async (patch) => {
51070
- if (!record) return;
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
- try {
51077
- await writeJobRecord(record);
51078
- } catch {
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 resolve39, dirname as dirname17, basename as basename11 } from "node:path";
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 existsSync38 } from "node:fs";
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 = resolve39(tmpdir4(), `vf-ac-${Date.now()}`);
53574
+ const tmpAudioDir = resolve38(tmpdir4(), `vf-ac-${Date.now()}`);
53982
53575
  await mkdir21(tmpAudioDir, { recursive: true });
53983
- const audioPath = resolve39(tmpAudioDir, "audio.wav");
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 = resolve39(process.cwd(), outputPath);
54011
- const outDir = dirname17(absOutputPath);
54012
- if (!existsSync38(outDir)) {
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 = resolve39(tmpAudioDir, "captions.ass");
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: basename11(videoPath)
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: basename11(videoPath),
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) return { success: false, error: result.error ?? "Motion overlay failed" };
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 resolve45 } from "node:path";
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 readFile29, writeFile as writeFile30 } from "node:fs/promises";
54560
- import { resolve as resolve41 } from "node:path";
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 = resolve41(process.cwd(), options.projectPath);
54566
- const content = await readFile29(filePath, "utf-8");
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 existsSync40 } from "node:fs";
54604
- import { readdir as readdir5, readFile as readFile30, stat as stat5 } from "node:fs/promises";
54605
- import { basename as basename12, isAbsolute as isAbsolute7, join as join23, relative as relative10, resolve as resolve42 } from "node:path";
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 = resolve42(opts.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 (!existsSync40(projectDir) || !await isDirectory(projectDir)) {
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, path2] of Object.entries(coreFiles)) {
54642
- checks.files[name] = existsSync40(path2);
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 readFile30(coreFiles.storyboard, "utf-8");
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 readFile30(coreFiles.design, "utf-8");
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 = existsSync40(compositionsDir) ? new Set(await listHtmlBasenames(compositionsDir)) : /* @__PURE__ */ new Set();
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 ? resolve42(process.cwd(), opts.outputPath) : defaultReviewReportPath(projectDir);
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 readFile30(reportPath, "utf-8"));
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 = isAbsolute7(opts.value) ? opts.value : resolve42(opts.projectDir, opts.value);
55081
- if (existsSync40(abs)) return;
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 path2 = typeof opts.asset?.path === "string" ? opts.asset.path : typeof opts.asset?.sourcePath === "string" ? opts.asset.sourcePath : `${opts.kind}:${opts.beatId ?? "unknown"}`;
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(path2);
54698
+ opts.checks.assets.stale.push(path);
55103
54699
  } else {
55104
- opts.checks.assets.unknownFreshness.push(path2);
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(path2) {
54750
+ async function isDirectory(path) {
55155
54751
  try {
55156
- return (await stat5(path2)).isDirectory();
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 readdir5(dir, { withFileTypes: true });
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 existsSync42 } from "node:fs";
55176
- import { readdir as readdir6, readFile as readFile32, stat as stat6 } from "node:fs/promises";
55177
- import { basename as basename13, isAbsolute as isAbsolute8, join as join24, relative as relative11, resolve as resolve44 } from "node:path";
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 = resolve44(opts.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 ? resolve44(process.cwd(), opts.outputPath) : defaultReviewReportPath(projectDir) : void 0;
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 = resolve44(opts.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 = resolve44(projectDir);
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) => existsSync42(join24(root, 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(path2) {
55739
- const text = await readTextIfExists(path2);
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 ? resolve44(process.cwd(), opts.outputPath) : defaultReviewReportPath(projectDir);
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 (existsSync42(join24(projectDir, "build-report.json"))) reports.push("build-report.json");
55802
- if (existsSync42(join24(projectDir, "render-report.json"))) reports.push("render-report.json");
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 = resolve44(process.cwd(), explicit);
55815
- return existsSync42(candidate) ? candidate : null;
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 (existsSync42(renderReportPath)) {
55414
+ if (existsSync41(renderReportPath)) {
55819
55415
  try {
55820
- const report = JSON.parse(await readFile32(renderReportPath, "utf-8"));
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 && existsSync42(candidate)) return 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 && existsSync42(reportPath)) {
55426
+ if (!beatId && existsSync41(reportPath)) {
55831
55427
  try {
55832
- const report = JSON.parse(await readFile32(reportPath, "utf-8"));
55428
+ const report = JSON.parse(await readFile33(reportPath, "utf-8"));
55833
55429
  const candidate = resolveReportedPath(projectDir, report.outputPath);
55834
- if (candidate && existsSync42(candidate)) return candidate;
55430
+ if (candidate && existsSync41(candidate)) return candidate;
55835
55431
  } catch {
55836
55432
  }
55837
55433
  }
55838
55434
  const rendersDir = join24(projectDir, "renders");
55839
- if (!existsSync42(rendersDir)) return null;
55840
- const entries = await readdir6(rendersDir, { withFileTypes: true });
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 existsSync42(storyboardPath) ? storyboardPath : null;
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 (!existsSync42(reportPath)) return void 0;
55466
+ if (!existsSync41(reportPath)) return void 0;
55871
55467
  try {
55872
- const report = JSON.parse(await readFile32(reportPath, "utf-8"));
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 (!existsSync42(reportPath)) return [];
55481
+ if (!existsSync41(reportPath)) return [];
55886
55482
  try {
55887
- const report = JSON.parse(await readFile32(reportPath, "utf-8"));
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(path2) {
55951
- if (!existsSync42(path2)) return null;
55546
+ async function readTextIfExists(path) {
55547
+ if (!existsSync41(path)) return null;
55952
55548
  try {
55953
- return await readFile32(path2, "utf-8");
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(path2) {
56051
- return relative11(process.cwd(), path2) || basename13(path2);
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 isAbsolute8(value) ? value : resolve44(projectDir, value);
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 ? resolve45(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve45(ctx.workingDirectory, args.outputPath) : void 0,
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 ? resolve45(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve45(ctx.workingDirectory, args.videoPath) : void 0,
56129
- outputPath: args.outputPath ? resolve45(ctx.workingDirectory, args.outputPath) : void 0,
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 ? resolve45(ctx.workingDirectory, args.videoPath) : void 0,
56151
- outputPath: args.outputPath ? resolve45(ctx.workingDirectory, args.outputPath) : void 0,
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 existsSync45 } from "node:fs";
56580
- import { readFile as readFile35, writeFile as writeFile36 } from "node:fs/promises";
56581
- import { resolve as resolve52 } from "node:path";
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 existsSync44 } from "node:fs";
56587
- import { readFile as readFile34, writeFile as writeFile35 } from "node:fs/promises";
56588
- import { join as join25, resolve as resolve51 } from "node:path";
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 = resolve51(opts.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 (!existsSync44(storyboardPath)) {
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(path2) {
56889
- if (!existsSync44(path2)) return null;
56890
- return readFile34(path2, "utf-8");
56484
+ async function readOptionalText(path) {
56485
+ if (!existsSync43(path)) return null;
56486
+ return readFile35(path, "utf-8");
56891
56487
  }
56892
- async function readOptionalJsonText(path2) {
56893
- if (!existsSync44(path2)) return null;
56488
+ async function readOptionalJsonText(path) {
56489
+ if (!existsSync43(path)) return null;
56894
56490
  try {
56895
- const parsed = JSON.parse(await readFile34(path2, "utf-8"));
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 path2 = resolve52(projectDir, "STORYBOARD.md");
56941
- if (!existsSync45(path2)) return null;
56942
- return { path: path2, markdown: await readFile35(path2, "utf-8") };
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 ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 ? resolve52(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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 existsSync46 } from "node:fs";
57200
- import { readFile as readFile36 } from "node:fs/promises";
57201
- import { resolve as resolve53, join as join26 } from "node:path";
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 ? resolve53(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
57217
- const path2 = join26(projectDir, "DESIGN.md");
57218
- if (!existsSync46(path2)) return { success: false, error: `DESIGN.md not found in ${projectDir}` };
57219
- const md = await readFile36(path2, "utf-8");
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 readFile37, writeFile as writeFile37, mkdir as mkdir24 } from "node:fs/promises";
57246
- import { resolve as resolve54, dirname as dirname20, basename as basename15, extname as extname12 } from "node:path";
57247
- import { existsSync as existsSync47 } from "node:fs";
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 = resolve54(process.cwd(), options.media);
57279
- if (!existsSync47(absPath)) {
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 = extname12(absPath).toLowerCase();
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 readFile37(absPath);
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 && existsSync47(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 = resolve54(process.cwd(), options.output);
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: basename15(absPath),
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 = resolve54(process.cwd(), options.project);
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 = resolve54(process.cwd(), options.video);
57478
- if (!existsSync47(absPath)) {
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 readFile37(absPath);
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 ? resolve54(process.cwd(), options.outputDir) : dirname20(absPath);
57602
- if (options.outputDir && !existsSync47(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 = basename15(absPath, extname12(absPath));
57612
- const outputPath = resolve54(outputDir, `${baseName}-short-${i + 1}.mp4`);
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 resolve56 } from "node:path";
57681
- import { readFile as readFile39, writeFile as writeFile39, mkdir as mkdir25 } from "node:fs/promises";
57682
- import { existsSync as existsSync48 } from "node:fs";
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 resolve56(outputDir, params.output);
57387
+ return resolve55(outputDir, params.output);
57792
57388
  }
57793
- return resolve56(outputDir, defaultName);
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 numberParam2(value) {
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: numberParam2(params.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: numberParam2(params.duration),
57475
+ duration: numberParam(params.duration),
57880
57476
  ratio: stringParam(params.ratio),
57881
- seed: numberParam2(params.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: resolve56(outputDir, projectRel),
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: resolve56(outputDir, projectRel),
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 = resolve56(process.cwd(), filePath);
58080
- if (!existsSync48(absPath)) {
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 readFile39(absPath, "utf-8");
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 = resolve56(process.cwd(), options.outputDir || `${manifest2.name}-output`);
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 = resolve56(outputDir, CHECKPOINT_FILE);
58106
- if (existsSync48(checkpointPath)) {
58107
- const checkpointContent = await readFile39(checkpointPath, "utf-8");
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
- resolve56(outputDir, CHECKPOINT_FILE),
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 basename17, resolve as resolve57 } from "node:path";
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 readFile40, writeFile as writeFile41 } from "node:fs/promises";
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 readFile40(absPath, "utf-8");
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 === "." ? basename17(ctx.workingDirectory) : basename17(resolve57(ctx.workingDirectory, 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 = resolve57(ctx.workingDirectory, args.outputPath);
58164
+ outputPath = resolve56(ctx.workingDirectory, args.outputPath);
58569
58165
  } else {
58570
- const dirPath = resolve57(ctx.workingDirectory, args.name);
58166
+ const dirPath = resolve56(ctx.workingDirectory, args.name);
58571
58167
  await mkdir26(dirPath, { recursive: true });
58572
- outputPath = resolve57(dirPath, TIMELINE_FILENAME);
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 = resolve57(ctx.workingDirectory, args.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 resolve59 } from "node:path";
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 readdir7, readFile as readFile41, stat as stat7 } from "node:fs/promises";
58878
- import { existsSync as existsSync49 } from "node:fs";
58879
- import { join as join28, resolve as resolve58 } from "node:path";
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 = resolve58(opts.workspaceDir ?? ".");
58882
- if (!existsSync49(workspaceDir)) {
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 readdir7(workspaceDir, { withFileTypes: true });
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 (!existsSync49(join28(projectDir, "STORYBOARD.md"))) continue;
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 readdir7(dir, { withFileTypes: true });
58507
+ const entries = await readdir6(dir, { withFileTypes: true });
58912
58508
  return entries.filter(
58913
- (e) => e.isDirectory() && existsSync49(join28(dir, e.name, "STORYBOARD.md"))
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 readFile41(reportPath, "utf-8"));
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 readdir7(rendersDir);
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 ? resolve59(ctx.workingDirectory, args.dir) : ctx.workingDirectory
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 = resolve59(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
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 resolve61 } from "node:path";
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 readFile42, access as access6 } from "node:fs/promises";
59080
- import { resolve as resolve60 } from "node:path";
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 readFile42(filePath, "utf-8");
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 = resolve60(process.cwd(), outputPath);
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((resolve64, reject) => {
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
- resolve64();
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 = resolve61(ctx.workingDirectory, args.projectPath);
59732
- const outputPath = resolve61(ctx.workingDirectory, args.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 readFile43, writeFile as writeFile44, readdir as readdir8, stat as stat8, access as access7, unlink as unlink2 } from "node:fs/promises";
59750
- import { resolve as resolve62, join as join29, basename as basename18, extname as extname13 } from "node:path";
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 = extname13(filePath).toLowerCase();
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(extname13(filePath).toLowerCase());
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 = resolve62(ctx.workingDirectory, dirPath);
59824
- const entries = await readdir8(absPath, { withFileTypes: true });
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 = resolve62(ctx.workingDirectory, args.path);
59857
- const content = await readFile43(absPath, "utf-8");
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 = resolve62(ctx.workingDirectory, args.path);
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 = resolve62(ctx.workingDirectory, args.path);
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 = resolve62(ctx.workingDirectory, args.project);
59930
- const content = await readFile43(filePath, "utf-8");
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 = resolve62(ctx.workingDirectory, args.directory);
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 readdir8(dir, { withFileTypes: true });
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 = extname13(entry.name).toLowerCase();
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 = basename18(mediaFile);
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 = resolve62(ctx.workingDirectory, args.project);
60002
- const content = await readFile43(filePath, "utf-8");
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 = resolve62(ctx.workingDirectory, args.project);
60073
- const content = await readFile43(filePath, "utf-8");
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 readFile43(filePath, "utf-8");
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 readFile43(filePath, "utf-8");
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 path2 = args.projectPath ?? ctx.agent?.projectPath ?? null;
60288
- if (!path2) {
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(path2, ctx.workingDirectory);
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 = resolve62(ctx.workingDirectory, args.path);
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 = resolve62(ctx.workingDirectory, args.input);
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 ? resolve62(ctx.workingDirectory, args.output) : resolve62(ctx.workingDirectory, `${baseName}-compressed.${ext}`);
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 readFile43(absInput);
60480
- const outputBuf = await readFile43(outputPath);
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 = resolve62(ctx.workingDirectory, args.input);
60517
- const absOutput = resolve62(ctx.workingDirectory, args.output);
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 = resolve62(ctx.workingDirectory, args.output);
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", resolve62(ctx.workingDirectory, 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 = resolve62(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
60590
- const listContent = args.inputs.map((i) => `file '${resolve62(ctx.workingDirectory, i)}'`).join("\n");
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 resolve63 } from "node:path";
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 ? resolve63(ctx.workingDirectory, args.projectDir) : findProjectRoot(ctx.workingDirectory);
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 ? resolve63(ctx.workingDirectory, args.output) : void 0,
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 ? resolve63(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
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,