@vibeframe/mcp-server 0.112.1 → 0.113.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -126
- package/dist/index.js +1919 -693
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -192,8 +192,8 @@ var init_api_keys = __esm({
|
|
|
192
192
|
envVar: "OPENAI_API_KEY",
|
|
193
193
|
label: "OpenAI",
|
|
194
194
|
showInSetup: true,
|
|
195
|
-
setupDescription: "gpt-image-2 image gen ($, default since v0.56), Whisper transcribe, Agent",
|
|
196
|
-
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
195
|
+
setupDescription: "gpt-image-2 image gen ($, default since v0.56), gpt-4o-mini-tts narration, Whisper transcribe, Agent",
|
|
196
|
+
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
197
197
|
envExampleUrl: "https://platform.openai.com/api-keys",
|
|
198
198
|
keyFormat: { prefix: /^sk-/, example: "sk-..." }
|
|
199
199
|
});
|
|
@@ -2300,8 +2300,8 @@ var init_openai = __esm({
|
|
|
2300
2300
|
id: "openai",
|
|
2301
2301
|
label: "OpenAI",
|
|
2302
2302
|
apiKey: "openai",
|
|
2303
|
-
kinds: ["llm", "image", "transcription"],
|
|
2304
|
-
resolverPriority: { image: 1 },
|
|
2303
|
+
kinds: ["llm", "image", "transcription", "speech"],
|
|
2304
|
+
resolverPriority: { image: 1, speech: 2 },
|
|
2305
2305
|
commandsUnlocked: [
|
|
2306
2306
|
"agent -p openai",
|
|
2307
2307
|
"generate image -p openai",
|
|
@@ -4723,39 +4723,83 @@ var init_elevenlabs = __esm({
|
|
|
4723
4723
|
});
|
|
4724
4724
|
|
|
4725
4725
|
// ../ai-providers/dist/kokoro/KokoroProvider.js
|
|
4726
|
-
async function
|
|
4726
|
+
async function loadKokoroRuntime() {
|
|
4727
4727
|
if (factoryOverride)
|
|
4728
|
-
return factoryOverride;
|
|
4728
|
+
return { factory: factoryOverride, device: "cpu" };
|
|
4729
4729
|
try {
|
|
4730
4730
|
const mod = await import("kokoro-js");
|
|
4731
|
-
return mod.KokoroTTS;
|
|
4731
|
+
return { factory: mod.KokoroTTS, device: "cpu" };
|
|
4732
4732
|
} catch (err) {
|
|
4733
|
-
const
|
|
4734
|
-
if (
|
|
4735
|
-
return
|
|
4733
|
+
const workspace = await loadKokoroFromWorkspace();
|
|
4734
|
+
if (workspace)
|
|
4735
|
+
return { factory: workspace, device: "cpu" };
|
|
4736
|
+
const bundled = await loadBundledKokoroRuntime();
|
|
4737
|
+
if (bundled)
|
|
4738
|
+
return bundled;
|
|
4736
4739
|
throw mapKokoroImportError(err);
|
|
4737
4740
|
}
|
|
4738
4741
|
}
|
|
4739
4742
|
async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
4740
4743
|
try {
|
|
4741
4744
|
const { readFile: readFile46 } = await import("node:fs/promises");
|
|
4742
|
-
const { join:
|
|
4745
|
+
const { join: join44, resolve: resolve80 } = await import("node:path");
|
|
4743
4746
|
const { pathToFileURL } = await import("node:url");
|
|
4744
4747
|
const pkgDir = resolve80(baseDir, "node_modules", "kokoro-js");
|
|
4745
|
-
const pkg = JSON.parse(await readFile46(
|
|
4748
|
+
const pkg = JSON.parse(await readFile46(join44(pkgDir, "package.json"), "utf-8"));
|
|
4746
4749
|
const entry = pkg.exports?.node?.import ?? pkg.exports?.default ?? pkg.module ?? pkg.main;
|
|
4747
4750
|
if (!entry)
|
|
4748
4751
|
return null;
|
|
4749
|
-
const mod = await import(pathToFileURL(
|
|
4752
|
+
const mod = await import(pathToFileURL(join44(pkgDir, entry)).href);
|
|
4750
4753
|
return mod.KokoroTTS ?? null;
|
|
4751
4754
|
} catch {
|
|
4752
4755
|
return null;
|
|
4753
4756
|
}
|
|
4754
4757
|
}
|
|
4758
|
+
async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUNTIME) {
|
|
4759
|
+
const base = runtimeDir?.trim();
|
|
4760
|
+
if (!base)
|
|
4761
|
+
return null;
|
|
4762
|
+
try {
|
|
4763
|
+
const { readFile: readFile46, writeFile: writeFile53, mkdir: mkdir30 } = await import("node:fs/promises");
|
|
4764
|
+
const { join: join44, resolve: resolve80 } = await import("node:path");
|
|
4765
|
+
const { pathToFileURL } = await import("node:url");
|
|
4766
|
+
const { homedir: homedir8 } = await import("node:os");
|
|
4767
|
+
const transformersDir = resolve80(base, "node_modules", "@huggingface", "transformers");
|
|
4768
|
+
const ortDistDir = resolve80(base, "node_modules", "onnxruntime-web", "dist");
|
|
4769
|
+
const transformers = await import(pathToFileURL(join44(transformersDir, "dist", "transformers.web.js")).href);
|
|
4770
|
+
const cacheRoot = join44(homedir8(), ".cache", "vibeframe", "models");
|
|
4771
|
+
transformers.env.allowLocalModels = false;
|
|
4772
|
+
transformers.env.useCustomCache = true;
|
|
4773
|
+
transformers.env.customCache = {
|
|
4774
|
+
async match(key2) {
|
|
4775
|
+
try {
|
|
4776
|
+
return new Response(await readFile46(join44(cacheRoot, encodeURIComponent(String(key2)))));
|
|
4777
|
+
} catch {
|
|
4778
|
+
return void 0;
|
|
4779
|
+
}
|
|
4780
|
+
},
|
|
4781
|
+
async put(key2, response) {
|
|
4782
|
+
try {
|
|
4783
|
+
const buf = Buffer.from(await response.arrayBuffer());
|
|
4784
|
+
await mkdir30(cacheRoot, { recursive: true });
|
|
4785
|
+
await writeFile53(join44(cacheRoot, encodeURIComponent(String(key2))), buf);
|
|
4786
|
+
} catch {
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
};
|
|
4790
|
+
transformers.env.backends.onnx.wasm.wasmPaths = pathToFileURL(ortDistDir + "/").href;
|
|
4791
|
+
const factory = await loadKokoroFromWorkspace(base);
|
|
4792
|
+
if (!factory)
|
|
4793
|
+
return null;
|
|
4794
|
+
return { factory, device: "cpu" };
|
|
4795
|
+
} catch {
|
|
4796
|
+
return null;
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4755
4799
|
function mapKokoroImportError(err) {
|
|
4756
4800
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
4757
4801
|
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
|
|
4758
|
-
return new Error("Local Kokoro TTS is unavailable:
|
|
4802
|
+
return new Error("Local Kokoro TTS is unavailable: kokoro-js could not be loaded from the npm install, the workspace node_modules, or the bundled extension runtime. Set OPENAI_API_KEY or ELEVENLABS_API_KEY to use a cloud voice instead (ttsProvider: openai / elevenlabs), or install the engine locally with `npm i kokoro-js` in your workspace folder.");
|
|
4759
4803
|
}
|
|
4760
4804
|
return err instanceof Error ? err : new Error(String(err));
|
|
4761
4805
|
}
|
|
@@ -4763,10 +4807,12 @@ function loadModel(progress) {
|
|
|
4763
4807
|
if (modelPromise)
|
|
4764
4808
|
return modelPromise;
|
|
4765
4809
|
modelPromise = (async () => {
|
|
4766
|
-
const
|
|
4767
|
-
|
|
4810
|
+
const runtime = await loadKokoroRuntime();
|
|
4811
|
+
const override = process.env.VIBE_ONNX_DEVICE;
|
|
4812
|
+
const device = override === "cpu" || override === "wasm" ? override : runtime.device;
|
|
4813
|
+
return runtime.factory.from_pretrained(KOKORO_MODEL_ID, {
|
|
4768
4814
|
dtype: "q8",
|
|
4769
|
-
device
|
|
4815
|
+
device,
|
|
4770
4816
|
progress_callback: progress ? (raw2) => progress(normaliseEvent(raw2)) : void 0
|
|
4771
4817
|
});
|
|
4772
4818
|
})().catch((err) => {
|
|
@@ -4850,7 +4896,7 @@ var init_kokoro = __esm({
|
|
|
4850
4896
|
label: "Kokoro (local)",
|
|
4851
4897
|
apiKey: null,
|
|
4852
4898
|
kinds: ["speech"],
|
|
4853
|
-
resolverPriority: { speech:
|
|
4899
|
+
resolverPriority: { speech: 3 }
|
|
4854
4900
|
});
|
|
4855
4901
|
}
|
|
4856
4902
|
});
|
|
@@ -5122,12 +5168,119 @@ var init_openai_image = __esm({
|
|
|
5122
5168
|
}
|
|
5123
5169
|
});
|
|
5124
5170
|
|
|
5171
|
+
// ../ai-providers/dist/openai-tts/OpenAiTtsProvider.js
|
|
5172
|
+
var OPENAI_TTS_VOICES, DEFAULT_VOICE, DEFAULT_MODEL2, TTS_429_MAX_RETRIES2, TTS_429_RETRY_DELAY_MS2, OpenAiTtsProvider, openaiTtsProvider;
|
|
5173
|
+
var init_OpenAiTtsProvider = __esm({
|
|
5174
|
+
"../ai-providers/dist/openai-tts/OpenAiTtsProvider.js"() {
|
|
5175
|
+
"use strict";
|
|
5176
|
+
OPENAI_TTS_VOICES = [
|
|
5177
|
+
"alloy",
|
|
5178
|
+
"ash",
|
|
5179
|
+
"ballad",
|
|
5180
|
+
"cedar",
|
|
5181
|
+
"coral",
|
|
5182
|
+
"echo",
|
|
5183
|
+
"fable",
|
|
5184
|
+
"marin",
|
|
5185
|
+
"nova",
|
|
5186
|
+
"onyx",
|
|
5187
|
+
"sage",
|
|
5188
|
+
"shimmer",
|
|
5189
|
+
"verse"
|
|
5190
|
+
];
|
|
5191
|
+
DEFAULT_VOICE = "marin";
|
|
5192
|
+
DEFAULT_MODEL2 = "gpt-4o-mini-tts";
|
|
5193
|
+
TTS_429_MAX_RETRIES2 = 1;
|
|
5194
|
+
TTS_429_RETRY_DELAY_MS2 = 2e3;
|
|
5195
|
+
OpenAiTtsProvider = class {
|
|
5196
|
+
constructor() {
|
|
5197
|
+
this.id = "openai";
|
|
5198
|
+
this.name = "OpenAI TTS";
|
|
5199
|
+
this.description = "OpenAI cloud text-to-speech (gpt-4o-mini-tts)";
|
|
5200
|
+
this.capabilities = ["text-to-speech"];
|
|
5201
|
+
this.isAvailable = true;
|
|
5202
|
+
this.baseUrl = "https://api.openai.com/v1";
|
|
5203
|
+
}
|
|
5204
|
+
async initialize(config4) {
|
|
5205
|
+
this.apiKey = config4.apiKey;
|
|
5206
|
+
if (config4.baseUrl) {
|
|
5207
|
+
this.baseUrl = config4.baseUrl;
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
isConfigured() {
|
|
5211
|
+
return !!this.apiKey;
|
|
5212
|
+
}
|
|
5213
|
+
async textToSpeech(text, options = {}) {
|
|
5214
|
+
if (!this.apiKey) {
|
|
5215
|
+
return { success: false, error: "OpenAI API key not configured" };
|
|
5216
|
+
}
|
|
5217
|
+
const voice = (options.voice ?? DEFAULT_VOICE).toLowerCase();
|
|
5218
|
+
if (!OPENAI_TTS_VOICES.includes(voice)) {
|
|
5219
|
+
return {
|
|
5220
|
+
success: false,
|
|
5221
|
+
error: `Unknown OpenAI voice "${options.voice}". Available voices: ${OPENAI_TTS_VOICES.join(", ")}.`
|
|
5222
|
+
};
|
|
5223
|
+
}
|
|
5224
|
+
try {
|
|
5225
|
+
let response;
|
|
5226
|
+
for (let attempt = 0; ; attempt++) {
|
|
5227
|
+
response = await fetch(`${this.baseUrl}/audio/speech`, {
|
|
5228
|
+
method: "POST",
|
|
5229
|
+
headers: {
|
|
5230
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
5231
|
+
"Content-Type": "application/json"
|
|
5232
|
+
},
|
|
5233
|
+
body: JSON.stringify({
|
|
5234
|
+
model: options.model ?? DEFAULT_MODEL2,
|
|
5235
|
+
input: text,
|
|
5236
|
+
voice,
|
|
5237
|
+
response_format: "mp3",
|
|
5238
|
+
...options.speed !== void 0 && { speed: options.speed },
|
|
5239
|
+
...options.instructions !== void 0 && { instructions: options.instructions }
|
|
5240
|
+
})
|
|
5241
|
+
});
|
|
5242
|
+
if (response.status === 429 && attempt < TTS_429_MAX_RETRIES2) {
|
|
5243
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, TTS_429_RETRY_DELAY_MS2 * (attempt + 1)));
|
|
5244
|
+
continue;
|
|
5245
|
+
}
|
|
5246
|
+
break;
|
|
5247
|
+
}
|
|
5248
|
+
if (!response.ok) {
|
|
5249
|
+
const error = await response.text();
|
|
5250
|
+
return { success: false, error: `OpenAI TTS failed: ${error}` };
|
|
5251
|
+
}
|
|
5252
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
5253
|
+
return {
|
|
5254
|
+
success: true,
|
|
5255
|
+
audioBuffer: Buffer.from(arrayBuffer),
|
|
5256
|
+
characterCount: text.length
|
|
5257
|
+
};
|
|
5258
|
+
} catch (error) {
|
|
5259
|
+
return {
|
|
5260
|
+
success: false,
|
|
5261
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
5262
|
+
};
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
};
|
|
5266
|
+
openaiTtsProvider = new OpenAiTtsProvider();
|
|
5267
|
+
}
|
|
5268
|
+
});
|
|
5269
|
+
|
|
5270
|
+
// ../ai-providers/dist/openai-tts/index.js
|
|
5271
|
+
var init_openai_tts = __esm({
|
|
5272
|
+
"../ai-providers/dist/openai-tts/index.js"() {
|
|
5273
|
+
"use strict";
|
|
5274
|
+
init_OpenAiTtsProvider();
|
|
5275
|
+
}
|
|
5276
|
+
});
|
|
5277
|
+
|
|
5125
5278
|
// ../ai-providers/dist/runway/RunwayProvider.js
|
|
5126
|
-
var
|
|
5279
|
+
var DEFAULT_MODEL3, RunwayProvider, runwayProvider;
|
|
5127
5280
|
var init_RunwayProvider = __esm({
|
|
5128
5281
|
"../ai-providers/dist/runway/RunwayProvider.js"() {
|
|
5129
5282
|
"use strict";
|
|
5130
|
-
|
|
5283
|
+
DEFAULT_MODEL3 = "gen4.5";
|
|
5131
5284
|
RunwayProvider = class _RunwayProvider {
|
|
5132
5285
|
constructor() {
|
|
5133
5286
|
this.id = "runway";
|
|
@@ -5170,7 +5323,7 @@ var init_RunwayProvider = __esm({
|
|
|
5170
5323
|
"1:1": "960:960"
|
|
5171
5324
|
};
|
|
5172
5325
|
const apiRatio = ratioMap[options?.aspectRatio || "16:9"] || "1280:720";
|
|
5173
|
-
const model = options?.model ||
|
|
5326
|
+
const model = options?.model || DEFAULT_MODEL3;
|
|
5174
5327
|
if (!options?.referenceImage && model !== "gen4.5") {
|
|
5175
5328
|
return {
|
|
5176
5329
|
id: "",
|
|
@@ -5432,11 +5585,11 @@ var init_runway = __esm({
|
|
|
5432
5585
|
|
|
5433
5586
|
// ../ai-providers/dist/kling/KlingProvider.js
|
|
5434
5587
|
import { createHmac } from "node:crypto";
|
|
5435
|
-
var
|
|
5588
|
+
var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
|
|
5436
5589
|
var init_KlingProvider = __esm({
|
|
5437
5590
|
"../ai-providers/dist/kling/KlingProvider.js"() {
|
|
5438
5591
|
"use strict";
|
|
5439
|
-
|
|
5592
|
+
DEFAULT_MODEL4 = "kling-v2-5-turbo";
|
|
5440
5593
|
STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3", "kling-v3-omni"];
|
|
5441
5594
|
KlingProvider = class {
|
|
5442
5595
|
constructor() {
|
|
@@ -5499,7 +5652,7 @@ var init_KlingProvider = __esm({
|
|
|
5499
5652
|
}
|
|
5500
5653
|
try {
|
|
5501
5654
|
const token = this.generateToken();
|
|
5502
|
-
const model = options?.model ||
|
|
5655
|
+
const model = options?.model || DEFAULT_MODEL4;
|
|
5503
5656
|
let mode = options?.mode || "std";
|
|
5504
5657
|
if (!STD_MODE_MODELS.includes(model) && mode === "std") {
|
|
5505
5658
|
mode = "pro";
|
|
@@ -5870,11 +6023,11 @@ var init_kling = __esm({
|
|
|
5870
6023
|
});
|
|
5871
6024
|
|
|
5872
6025
|
// ../ai-providers/dist/grok/GrokProvider.js
|
|
5873
|
-
var
|
|
6026
|
+
var DEFAULT_MODEL5, GrokProvider, grokProvider;
|
|
5874
6027
|
var init_GrokProvider = __esm({
|
|
5875
6028
|
"../ai-providers/dist/grok/GrokProvider.js"() {
|
|
5876
6029
|
"use strict";
|
|
5877
|
-
|
|
6030
|
+
DEFAULT_MODEL5 = "grok-imagine-video";
|
|
5878
6031
|
GrokProvider = class {
|
|
5879
6032
|
constructor() {
|
|
5880
6033
|
this.id = "grok";
|
|
@@ -6041,7 +6194,7 @@ var init_GrokProvider = __esm({
|
|
|
6041
6194
|
try {
|
|
6042
6195
|
const duration = Math.round(Math.min(15, Math.max(1, options?.duration || 5)));
|
|
6043
6196
|
const body = {
|
|
6044
|
-
model:
|
|
6197
|
+
model: DEFAULT_MODEL5,
|
|
6045
6198
|
prompt: prompt3,
|
|
6046
6199
|
duration,
|
|
6047
6200
|
aspect_ratio: options?.aspectRatio || "16:9"
|
|
@@ -10307,6 +10460,19 @@ var require_src = __commonJS({
|
|
|
10307
10460
|
});
|
|
10308
10461
|
|
|
10309
10462
|
// ../ai-providers/dist/fal/FalProvider.js
|
|
10463
|
+
function estimateSeedanceVideoCostUsd(opts) {
|
|
10464
|
+
const shortSide = SEEDANCE_SHORT_SIDE[opts.resolution ?? "720p"] ?? 720;
|
|
10465
|
+
const [a2, b2] = (opts.aspectRatio ?? "16:9").split(":").map(Number);
|
|
10466
|
+
const ratioFactor = a2 > 0 && b2 > 0 ? Math.max(a2, b2) / Math.min(a2, b2) : 16 / 9;
|
|
10467
|
+
const longSide = Math.round(shortSide * ratioFactor);
|
|
10468
|
+
const tokensPerSecond = shortSide * longSide * 24 / 1024;
|
|
10469
|
+
let usdPerSecond = tokensPerSecond / 1e3 * SEEDANCE_USD_PER_1K_TOKENS;
|
|
10470
|
+
if (opts.fast && shortSide <= 720)
|
|
10471
|
+
usdPerSecond *= SEEDANCE_FAST_FACTOR;
|
|
10472
|
+
if (opts.hasVideoReference)
|
|
10473
|
+
usdPerSecond *= SEEDANCE_VIDEO_REF_FACTOR;
|
|
10474
|
+
return Number((usdPerSecond * Math.max(0, opts.durationSec)).toFixed(2));
|
|
10475
|
+
}
|
|
10310
10476
|
function formatFalError(error) {
|
|
10311
10477
|
if (!(error instanceof Error))
|
|
10312
10478
|
return String(error);
|
|
@@ -10416,7 +10582,7 @@ function normaliseDuration(value) {
|
|
|
10416
10582
|
return "auto";
|
|
10417
10583
|
return Math.max(4, Math.min(15, Math.round(value)));
|
|
10418
10584
|
}
|
|
10419
|
-
var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, ENDPOINT_REFERENCE_TO_VIDEO, DEFAULT_VARIANT, VALID_RESOLUTIONS, VALID_ASPECTS, FalProvider, falProvider;
|
|
10585
|
+
var import_client, ENDPOINT_TEXT_TO_VIDEO, ENDPOINT_IMAGE_TO_VIDEO, ENDPOINT_REFERENCE_TO_VIDEO, DEFAULT_VARIANT, VALID_RESOLUTIONS, VALID_ASPECTS, SEEDANCE_USD_PER_1K_TOKENS, SEEDANCE_FAST_FACTOR, SEEDANCE_VIDEO_REF_FACTOR, SEEDANCE_SHORT_SIDE, FalProvider, falProvider;
|
|
10420
10586
|
var init_FalProvider = __esm({
|
|
10421
10587
|
"../ai-providers/dist/fal/FalProvider.js"() {
|
|
10422
10588
|
"use strict";
|
|
@@ -10436,6 +10602,10 @@ var init_FalProvider = __esm({
|
|
|
10436
10602
|
DEFAULT_VARIANT = "seedance-2.0";
|
|
10437
10603
|
VALID_RESOLUTIONS = ["480p", "720p", "1080p"];
|
|
10438
10604
|
VALID_ASPECTS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "auto"];
|
|
10605
|
+
SEEDANCE_USD_PER_1K_TOKENS = 0.014;
|
|
10606
|
+
SEEDANCE_FAST_FACTOR = 0.8;
|
|
10607
|
+
SEEDANCE_VIDEO_REF_FACTOR = 0.6;
|
|
10608
|
+
SEEDANCE_SHORT_SIDE = { "480p": 480, "720p": 720, "1080p": 1080 };
|
|
10439
10609
|
FalProvider = class {
|
|
10440
10610
|
constructor() {
|
|
10441
10611
|
this.id = "seedance";
|
|
@@ -11248,9 +11418,11 @@ __export(dist_exports, {
|
|
|
11248
11418
|
KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
|
|
11249
11419
|
KlingProvider: () => KlingProvider,
|
|
11250
11420
|
KokoroProvider: () => KokoroProvider,
|
|
11421
|
+
OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
|
|
11251
11422
|
OllamaProvider: () => OllamaProvider,
|
|
11252
11423
|
OpenAIImageProvider: () => OpenAIImageProvider,
|
|
11253
11424
|
OpenAIProvider: () => OpenAIProvider,
|
|
11425
|
+
OpenAiTtsProvider: () => OpenAiTtsProvider,
|
|
11254
11426
|
ReplicateProvider: () => ReplicateProvider,
|
|
11255
11427
|
RunwayProvider: () => RunwayProvider,
|
|
11256
11428
|
WhisperProvider: () => WhisperProvider,
|
|
@@ -11258,6 +11430,7 @@ __export(dist_exports, {
|
|
|
11258
11430
|
defineApiKey: () => defineApiKey,
|
|
11259
11431
|
defineProvider: () => defineProvider,
|
|
11260
11432
|
elevenLabsProvider: () => elevenLabsProvider,
|
|
11433
|
+
estimateSeedanceVideoCostUsd: () => estimateSeedanceVideoCostUsd,
|
|
11261
11434
|
falProvider: () => falProvider,
|
|
11262
11435
|
geminiProvider: () => geminiProvider,
|
|
11263
11436
|
getAllApiKeys: () => getAllApiKeys,
|
|
@@ -11274,9 +11447,12 @@ __export(dist_exports, {
|
|
|
11274
11447
|
isGeminiTextModelAlias: () => isGeminiTextModelAlias,
|
|
11275
11448
|
klingProvider: () => klingProvider,
|
|
11276
11449
|
kokoroProvider: () => kokoroProvider,
|
|
11450
|
+
loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
|
|
11451
|
+
loadKokoroFromWorkspace: () => loadKokoroFromWorkspace,
|
|
11277
11452
|
ollamaProvider: () => ollamaProvider,
|
|
11278
11453
|
openaiImageProvider: () => openaiImageProvider,
|
|
11279
11454
|
openaiProvider: () => openaiProvider,
|
|
11455
|
+
openaiTtsProvider: () => openaiTtsProvider,
|
|
11280
11456
|
providerRegistry: () => providerRegistry,
|
|
11281
11457
|
replicateProvider: () => replicateProvider,
|
|
11282
11458
|
resolveGeminiTextModel: () => resolveGeminiTextModel,
|
|
@@ -11299,6 +11475,7 @@ var init_dist = __esm({
|
|
|
11299
11475
|
init_elevenlabs();
|
|
11300
11476
|
init_kokoro();
|
|
11301
11477
|
init_openai_image();
|
|
11478
|
+
init_openai_tts();
|
|
11302
11479
|
init_runway();
|
|
11303
11480
|
init_kling();
|
|
11304
11481
|
init_grok();
|
|
@@ -24060,7 +24237,534 @@ var init_build_asset_metadata = __esm({
|
|
|
24060
24237
|
}
|
|
24061
24238
|
});
|
|
24062
24239
|
|
|
24240
|
+
// ../cli/src/commands/_shared/review-report.ts
|
|
24241
|
+
import { writeFile as writeFile6 } from "node:fs/promises";
|
|
24242
|
+
import { join as join2, resolve as resolve5 } from "node:path";
|
|
24243
|
+
function statusFromIssues(issues) {
|
|
24244
|
+
if (issues.some((issue) => issue.severity === "error")) return "fail";
|
|
24245
|
+
if (issues.some((issue) => issue.severity === "warning")) return "warn";
|
|
24246
|
+
return "pass";
|
|
24247
|
+
}
|
|
24248
|
+
function scoreIssues(issues) {
|
|
24249
|
+
let score = 100;
|
|
24250
|
+
for (const issue of issues) {
|
|
24251
|
+
if (issue.severity === "error") score -= 25;
|
|
24252
|
+
else if (issue.severity === "warning") score -= 8;
|
|
24253
|
+
else score -= 2;
|
|
24254
|
+
}
|
|
24255
|
+
return Math.max(0, Math.min(100, score));
|
|
24256
|
+
}
|
|
24257
|
+
function uniqueRetryWith(items) {
|
|
24258
|
+
return [
|
|
24259
|
+
...new Set(items.filter((item) => typeof item === "string" && item.length > 0))
|
|
24260
|
+
];
|
|
24261
|
+
}
|
|
24262
|
+
function commandReviewAction(command3, opts) {
|
|
24263
|
+
const classified = classifyReviewCommand(command3);
|
|
24264
|
+
return stripUndefined({
|
|
24265
|
+
id: actionId("command", command3),
|
|
24266
|
+
kind: "command",
|
|
24267
|
+
label: opts.label ?? command3,
|
|
24268
|
+
command: command3,
|
|
24269
|
+
fixOwner: opts.fixOwner ?? classified.fixOwner,
|
|
24270
|
+
costTier: opts.costTier ?? classified.costTier,
|
|
24271
|
+
safeToAutoRun: opts.safeToAutoRun ?? classified.safeToAutoRun,
|
|
24272
|
+
requiresConfirmation: opts.requiresConfirmation ?? classified.requiresConfirmation,
|
|
24273
|
+
reason: opts.reason,
|
|
24274
|
+
sourceIssueCodes: uniqueStrings(opts.sourceIssueCodes ?? [])
|
|
24275
|
+
});
|
|
24276
|
+
}
|
|
24277
|
+
function agentReviewAction(opts) {
|
|
24278
|
+
return stripUndefined({
|
|
24279
|
+
id: actionId("agent", opts.agentPrompt),
|
|
24280
|
+
kind: "agent",
|
|
24281
|
+
label: opts.label,
|
|
24282
|
+
agentPrompt: opts.agentPrompt,
|
|
24283
|
+
fixOwner: "host-agent",
|
|
24284
|
+
costTier: "unknown",
|
|
24285
|
+
safeToAutoRun: false,
|
|
24286
|
+
requiresConfirmation: false,
|
|
24287
|
+
reason: opts.reason,
|
|
24288
|
+
sourceIssueCodes: uniqueStrings(opts.sourceIssueCodes ?? [])
|
|
24289
|
+
});
|
|
24290
|
+
}
|
|
24291
|
+
function manualReviewAction(opts) {
|
|
24292
|
+
return stripUndefined({
|
|
24293
|
+
id: actionId("manual", opts.label),
|
|
24294
|
+
kind: "manual",
|
|
24295
|
+
label: opts.label,
|
|
24296
|
+
fixOwner: opts.fixOwner ?? "host-agent",
|
|
24297
|
+
costTier: "unknown",
|
|
24298
|
+
safeToAutoRun: false,
|
|
24299
|
+
requiresConfirmation: false,
|
|
24300
|
+
reason: opts.reason,
|
|
24301
|
+
sourceIssueCodes: uniqueStrings(opts.sourceIssueCodes ?? [])
|
|
24302
|
+
});
|
|
24303
|
+
}
|
|
24304
|
+
function reviewActionsFromRetryWith(retryWith, sourceIssueCodes = []) {
|
|
24305
|
+
return normalizeReviewActions(
|
|
24306
|
+
retryWith.map((item) => {
|
|
24307
|
+
if (/^codex\s+/i.test(item)) {
|
|
24308
|
+
return agentReviewAction({
|
|
24309
|
+
label: "Ask the host agent to fix review issues",
|
|
24310
|
+
agentPrompt: item,
|
|
24311
|
+
reason: "The review report contains host-agent-owned issues.",
|
|
24312
|
+
sourceIssueCodes
|
|
24313
|
+
});
|
|
24314
|
+
}
|
|
24315
|
+
return commandReviewAction(item, {
|
|
24316
|
+
reason: "Backward-compatible retryWith command.",
|
|
24317
|
+
sourceIssueCodes
|
|
24318
|
+
});
|
|
24319
|
+
})
|
|
24320
|
+
);
|
|
24321
|
+
}
|
|
24322
|
+
function normalizeReviewActions(actions) {
|
|
24323
|
+
const merged = /* @__PURE__ */ new Map();
|
|
24324
|
+
for (const action of actions) {
|
|
24325
|
+
const key2 = [action.kind, action.command ?? action.agentPrompt ?? action.label].join("\0");
|
|
24326
|
+
const existing = merged.get(key2);
|
|
24327
|
+
if (!existing) {
|
|
24328
|
+
merged.set(key2, {
|
|
24329
|
+
...action,
|
|
24330
|
+
sourceIssueCodes: uniqueStrings(action.sourceIssueCodes ?? [])
|
|
24331
|
+
});
|
|
24332
|
+
continue;
|
|
24333
|
+
}
|
|
24334
|
+
merged.set(key2, {
|
|
24335
|
+
...existing,
|
|
24336
|
+
safeToAutoRun: existing.safeToAutoRun && action.safeToAutoRun,
|
|
24337
|
+
requiresConfirmation: existing.requiresConfirmation || action.requiresConfirmation,
|
|
24338
|
+
sourceIssueCodes: uniqueStrings([
|
|
24339
|
+
...existing.sourceIssueCodes ?? [],
|
|
24340
|
+
...action.sourceIssueCodes ?? []
|
|
24341
|
+
])
|
|
24342
|
+
});
|
|
24343
|
+
}
|
|
24344
|
+
return [...merged.values()].map(
|
|
24345
|
+
(action) => stripUndefined({
|
|
24346
|
+
...action,
|
|
24347
|
+
sourceIssueCodes: action.sourceIssueCodes && action.sourceIssueCodes.length > 0 ? action.sourceIssueCodes : void 0
|
|
24348
|
+
})
|
|
24349
|
+
);
|
|
24350
|
+
}
|
|
24351
|
+
function deriveNextReviewActions(opts) {
|
|
24352
|
+
return normalizeReviewActions([
|
|
24353
|
+
...opts.issues.flatMap((issue) => issue.actions ?? []),
|
|
24354
|
+
...reviewActionsFromRetryWith(opts.retryWith)
|
|
24355
|
+
]);
|
|
24356
|
+
}
|
|
24357
|
+
function fixOwnerForIssue(issue) {
|
|
24358
|
+
if (issue.fixOwner) return issue.fixOwner;
|
|
24359
|
+
if (issue.code.startsWith("AI_REVIEW_")) return "host-agent";
|
|
24360
|
+
if (issue.code.startsWith("STORYBOARD_")) return "host-agent";
|
|
24361
|
+
if (issue.code === "PROJECT_NOT_FOUND" || issue.code === "MISSING_STORYBOARD" || issue.code === "BEAT_NOT_FOUND" || issue.code === "MISSING_DESIGN") {
|
|
24362
|
+
return "host-agent";
|
|
24363
|
+
}
|
|
24364
|
+
return "vibe";
|
|
24365
|
+
}
|
|
24366
|
+
function normalizeReviewIssues(issues, opts) {
|
|
24367
|
+
const fallbackOwner = typeof opts === "string" ? opts : opts?.fallbackOwner;
|
|
24368
|
+
const projectDir = typeof opts === "string" ? void 0 : opts?.projectDir;
|
|
24369
|
+
return issues.map((issue) => {
|
|
24370
|
+
const normalized = {
|
|
24371
|
+
...issue,
|
|
24372
|
+
fixOwner: issue.fixOwner ?? fallbackOwner ?? fixOwnerForIssue(issue)
|
|
24373
|
+
};
|
|
24374
|
+
const actions = normalizeReviewActions([
|
|
24375
|
+
...issue.actions ?? [],
|
|
24376
|
+
...projectDir ? defaultActionsForIssue(normalized, projectDir) : []
|
|
24377
|
+
]);
|
|
24378
|
+
return stripUndefined({
|
|
24379
|
+
...normalized,
|
|
24380
|
+
actions: actions.length > 0 ? actions : void 0
|
|
24381
|
+
});
|
|
24382
|
+
});
|
|
24383
|
+
}
|
|
24384
|
+
function summarizeReviewIssues(issues) {
|
|
24385
|
+
const normalized = normalizeReviewIssues(issues);
|
|
24386
|
+
return {
|
|
24387
|
+
issueCount: normalized.length,
|
|
24388
|
+
errorCount: normalized.filter((issue) => issue.severity === "error").length,
|
|
24389
|
+
warningCount: normalized.filter((issue) => issue.severity === "warning").length,
|
|
24390
|
+
infoCount: normalized.filter((issue) => issue.severity === "info").length,
|
|
24391
|
+
fixOwners: {
|
|
24392
|
+
vibe: normalized.filter((issue) => issue.fixOwner === "vibe").length,
|
|
24393
|
+
hostAgent: normalized.filter((issue) => issue.fixOwner === "host-agent").length
|
|
24394
|
+
}
|
|
24395
|
+
};
|
|
24396
|
+
}
|
|
24397
|
+
function buildReviewReport(opts) {
|
|
24398
|
+
const retryWith = uniqueRetryWith(opts.retryWith);
|
|
24399
|
+
const issues = normalizeReviewIssues(opts.issues, {
|
|
24400
|
+
projectDir: opts.project,
|
|
24401
|
+
retryWith
|
|
24402
|
+
});
|
|
24403
|
+
return stripUndefined({
|
|
24404
|
+
schemaVersion: "1",
|
|
24405
|
+
kind: "review",
|
|
24406
|
+
project: resolve5(opts.project),
|
|
24407
|
+
mode: opts.mode,
|
|
24408
|
+
beat: opts.beat,
|
|
24409
|
+
status: opts.status,
|
|
24410
|
+
score: opts.score,
|
|
24411
|
+
issues,
|
|
24412
|
+
summary: summarizeReviewIssues(issues),
|
|
24413
|
+
nextActions: deriveNextReviewActions({ issues, retryWith, projectDir: opts.project }),
|
|
24414
|
+
retryWith,
|
|
24415
|
+
sourceReports: opts.sourceReports ?? [],
|
|
24416
|
+
reportPath: opts.reportPath
|
|
24417
|
+
});
|
|
24418
|
+
}
|
|
24419
|
+
function defaultReviewReportPath(projectDir) {
|
|
24420
|
+
return join2(resolve5(projectDir), "review-report.json");
|
|
24421
|
+
}
|
|
24422
|
+
async function writeReviewReport(path14, report) {
|
|
24423
|
+
await writeFile6(path14, JSON.stringify(report, null, 2) + "\n", "utf-8");
|
|
24424
|
+
}
|
|
24425
|
+
function stripUndefined(value) {
|
|
24426
|
+
return Object.fromEntries(Object.entries(value).filter(([, v2]) => v2 !== void 0));
|
|
24427
|
+
}
|
|
24428
|
+
function defaultActionsForIssue(issue, projectDir) {
|
|
24429
|
+
const code = issue.code;
|
|
24430
|
+
const beat = issue.beatId ?? issue.scene;
|
|
24431
|
+
const beatFlag = beat ? ` --beat ${beat}` : "";
|
|
24432
|
+
const sourceIssueCodes = [code];
|
|
24433
|
+
if (code === "PROJECT_NOT_FOUND" || code === "MISSING_STORYBOARD") {
|
|
24434
|
+
return [
|
|
24435
|
+
commandReviewAction(`vibe init ${projectDir} --from "<brief>" --json`, {
|
|
24436
|
+
label: "Initialize the project from a brief",
|
|
24437
|
+
fixOwner: "host-agent",
|
|
24438
|
+
reason: "The project cannot be inspected until the core project files exist.",
|
|
24439
|
+
sourceIssueCodes
|
|
24440
|
+
})
|
|
24441
|
+
];
|
|
24442
|
+
}
|
|
24443
|
+
if (code === "MISSING_DESIGN" || code === "DESIGN_PLACEHOLDER_FIELD") {
|
|
24444
|
+
return [
|
|
24445
|
+
manualReviewAction({
|
|
24446
|
+
label: "Create or complete DESIGN.md",
|
|
24447
|
+
reason: "Visual direction needs host-agent or human input before VibeFrame can repair it.",
|
|
24448
|
+
sourceIssueCodes
|
|
24449
|
+
})
|
|
24450
|
+
];
|
|
24451
|
+
}
|
|
24452
|
+
if (code === "BEAT_NOT_FOUND" || code.startsWith("STORYBOARD_")) {
|
|
24453
|
+
const actions = [
|
|
24454
|
+
commandReviewAction(`vibe storyboard validate ${projectDir} --json`, {
|
|
24455
|
+
label: "Validate the storyboard",
|
|
24456
|
+
fixOwner: "host-agent",
|
|
24457
|
+
reason: "The storyboard issue needs structured validation before editing.",
|
|
24458
|
+
sourceIssueCodes
|
|
24459
|
+
})
|
|
24460
|
+
];
|
|
24461
|
+
if (code === "STORYBOARD_PLACEHOLDER_CUE") {
|
|
24462
|
+
actions.push(
|
|
24463
|
+
commandReviewAction(
|
|
24464
|
+
`vibe storyboard revise ${projectDir} --from "<make cues concrete>" --dry-run --json`,
|
|
24465
|
+
{
|
|
24466
|
+
label: "Preview a storyboard revision",
|
|
24467
|
+
fixOwner: "host-agent",
|
|
24468
|
+
reason: "Placeholder cues should be revised into concrete video intent.",
|
|
24469
|
+
sourceIssueCodes
|
|
24470
|
+
}
|
|
24471
|
+
)
|
|
24472
|
+
);
|
|
24473
|
+
}
|
|
24474
|
+
return actions;
|
|
24475
|
+
}
|
|
24476
|
+
if (code === "MISSING_ROOT_COMPOSITION" || code === "ROOT_SYNC_CHECK_FAILED") {
|
|
24477
|
+
return [
|
|
24478
|
+
commandReviewAction(`vibe build ${projectDir} --stage sync --json`, {
|
|
24479
|
+
label: "Sync the project root composition",
|
|
24480
|
+
reason: "The root composition is missing or could not be verified.",
|
|
24481
|
+
sourceIssueCodes
|
|
24482
|
+
})
|
|
24483
|
+
];
|
|
24484
|
+
}
|
|
24485
|
+
if (code.startsWith("ROOT_")) {
|
|
24486
|
+
return issue.fixOwner === "host-agent" ? [
|
|
24487
|
+
agentReviewAction({
|
|
24488
|
+
label: "Repair the root composition shell",
|
|
24489
|
+
agentPrompt: "Fix host-agent-owned root composition issues from review-report.json",
|
|
24490
|
+
reason: "The root composition cannot be repaired deterministically.",
|
|
24491
|
+
sourceIssueCodes
|
|
24492
|
+
})
|
|
24493
|
+
] : [
|
|
24494
|
+
commandReviewAction(`vibe scene repair ${projectDir} --json`, {
|
|
24495
|
+
label: "Repair deterministic scene/root issues",
|
|
24496
|
+
reason: "The root composition has deterministic sync issues.",
|
|
24497
|
+
sourceIssueCodes
|
|
24498
|
+
}),
|
|
24499
|
+
commandReviewAction(`vibe build ${projectDir} --stage sync --json`, {
|
|
24500
|
+
label: "Resync root composition after repair",
|
|
24501
|
+
reason: "The root composition should be synced after deterministic repair.",
|
|
24502
|
+
sourceIssueCodes
|
|
24503
|
+
})
|
|
24504
|
+
];
|
|
24505
|
+
}
|
|
24506
|
+
if (code === "MISSING_COMPOSITION") {
|
|
24507
|
+
return [
|
|
24508
|
+
commandReviewAction(`vibe build ${projectDir}${beatFlag} --stage compose --json`, {
|
|
24509
|
+
label: beat ? `Compose beat ${beat}` : "Compose missing scenes",
|
|
24510
|
+
reason: "Missing scene compositions must be generated or authored before render.",
|
|
24511
|
+
sourceIssueCodes
|
|
24512
|
+
})
|
|
24513
|
+
];
|
|
24514
|
+
}
|
|
24515
|
+
if (code === "MISSING_BUILD_REPORT") {
|
|
24516
|
+
return [
|
|
24517
|
+
commandReviewAction(`vibe build ${projectDir} --dry-run --json`, {
|
|
24518
|
+
label: "Preview the build plan",
|
|
24519
|
+
reason: "A dry-run build report is needed before choosing a paid or mutating build step.",
|
|
24520
|
+
sourceIssueCodes
|
|
24521
|
+
})
|
|
24522
|
+
];
|
|
24523
|
+
}
|
|
24524
|
+
if (code === "BUILD_REPORT_BEAT_MISSING") {
|
|
24525
|
+
return [
|
|
24526
|
+
commandReviewAction(`vibe build ${projectDir}${beatFlag} --stage sync --json`, {
|
|
24527
|
+
label: beat ? `Sync build report for beat ${beat}` : "Sync the build report",
|
|
24528
|
+
reason: "The build report does not include the inspected beat.",
|
|
24529
|
+
sourceIssueCodes
|
|
24530
|
+
})
|
|
24531
|
+
];
|
|
24532
|
+
}
|
|
24533
|
+
if (code === "MALFORMED_BUILD_REPORT") {
|
|
24534
|
+
return [
|
|
24535
|
+
commandReviewAction(`vibe build ${projectDir} --json`, {
|
|
24536
|
+
label: "Regenerate the build report",
|
|
24537
|
+
reason: "The existing build report cannot be parsed.",
|
|
24538
|
+
sourceIssueCodes
|
|
24539
|
+
})
|
|
24540
|
+
];
|
|
24541
|
+
}
|
|
24542
|
+
if (code === "MISSING_REPORTED_ASSET" || code === "STALE_ASSET" || code === "UNKNOWN_ASSET_FRESHNESS") {
|
|
24543
|
+
return [
|
|
24544
|
+
commandReviewAction(`vibe build ${projectDir}${beatFlag} --stage assets --force --json`, {
|
|
24545
|
+
label: beat ? `Regenerate assets for beat ${beat}` : "Regenerate stale or missing assets",
|
|
24546
|
+
reason: "Asset generation may call providers, so the host should confirm first.",
|
|
24547
|
+
sourceIssueCodes
|
|
24548
|
+
})
|
|
24549
|
+
];
|
|
24550
|
+
}
|
|
24551
|
+
if (code === "MUSIC_CUE_NOT_READY") {
|
|
24552
|
+
return [
|
|
24553
|
+
commandReviewAction(`vibe build ${projectDir}${beatFlag} --stage assets --json`, {
|
|
24554
|
+
label: beat ? `Generate music for beat ${beat}` : "Generate missing music assets",
|
|
24555
|
+
reason: "Music generation may call providers, so the host should confirm first.",
|
|
24556
|
+
sourceIssueCodes
|
|
24557
|
+
}),
|
|
24558
|
+
commandReviewAction(`vibe build ${projectDir} --stage sync --json`, {
|
|
24559
|
+
label: "Sync music into the root composition",
|
|
24560
|
+
reason: "Generated music needs root composition wiring.",
|
|
24561
|
+
sourceIssueCodes
|
|
24562
|
+
})
|
|
24563
|
+
];
|
|
24564
|
+
}
|
|
24565
|
+
if (code.startsWith("SCENE_LINT_")) {
|
|
24566
|
+
return [
|
|
24567
|
+
commandReviewAction(`vibe scene repair ${projectDir} --json`, {
|
|
24568
|
+
label: "Repair deterministic scene lint issues",
|
|
24569
|
+
reason: "Scene lint reported an issue VibeFrame may be able to repair mechanically.",
|
|
24570
|
+
sourceIssueCodes
|
|
24571
|
+
})
|
|
24572
|
+
];
|
|
24573
|
+
}
|
|
24574
|
+
if (code === "RENDER_NOT_FOUND" || code === "EMPTY_RENDER") {
|
|
24575
|
+
return [
|
|
24576
|
+
commandReviewAction(
|
|
24577
|
+
beat ? `vibe render ${projectDir} --beat ${beat} --json` : `vibe render ${projectDir} --json`,
|
|
24578
|
+
{
|
|
24579
|
+
label: beat ? `Render beat ${beat}` : "Render the project",
|
|
24580
|
+
reason: "A render file is required before render inspection can pass.",
|
|
24581
|
+
sourceIssueCodes
|
|
24582
|
+
}
|
|
24583
|
+
)
|
|
24584
|
+
];
|
|
24585
|
+
}
|
|
24586
|
+
if (code === "NO_AUDIO_STREAM" || code === "DURATION_DRIFT") {
|
|
24587
|
+
return [
|
|
24588
|
+
commandReviewAction(`vibe build ${projectDir}${beatFlag} --stage sync --json`, {
|
|
24589
|
+
label: beat ? `Sync timing/audio for beat ${beat}` : "Sync timing and audio wiring",
|
|
24590
|
+
reason: "The render output no longer matches synced project state.",
|
|
24591
|
+
sourceIssueCodes
|
|
24592
|
+
}),
|
|
24593
|
+
commandReviewAction(
|
|
24594
|
+
beat ? `vibe render ${projectDir} --beat ${beat} --json` : `vibe render ${projectDir} --json`,
|
|
24595
|
+
{
|
|
24596
|
+
label: beat ? `Rerender beat ${beat}` : "Rerender the project",
|
|
24597
|
+
reason: "The render should be regenerated after sync repair.",
|
|
24598
|
+
sourceIssueCodes
|
|
24599
|
+
}
|
|
24600
|
+
)
|
|
24601
|
+
];
|
|
24602
|
+
}
|
|
24603
|
+
if (code === "BLACK_FRAME_SEGMENT") {
|
|
24604
|
+
return issue.fixOwner === "host-agent" ? [
|
|
24605
|
+
agentReviewAction({
|
|
24606
|
+
label: beat ? `Fix black frames in beat ${beat}` : "Fix black frame segment",
|
|
24607
|
+
agentPrompt: "Fix black-frame issues from review-report.json, then rerender.",
|
|
24608
|
+
reason: "The issue likely needs scene, storyboard, or visual cue changes.",
|
|
24609
|
+
sourceIssueCodes
|
|
24610
|
+
})
|
|
24611
|
+
] : [
|
|
24612
|
+
commandReviewAction(`vibe scene repair ${projectDir} --json`, {
|
|
24613
|
+
label: "Repair deterministic scene timing",
|
|
24614
|
+
reason: "Black frames outside a specific beat may be recoverable with scene repair.",
|
|
24615
|
+
sourceIssueCodes
|
|
24616
|
+
})
|
|
24617
|
+
];
|
|
24618
|
+
}
|
|
24619
|
+
if (code === "STATIC_FRAME_SEGMENT") {
|
|
24620
|
+
return [
|
|
24621
|
+
agentReviewAction({
|
|
24622
|
+
label: beat ? `Add motion to beat ${beat}` : "Fix static visual hold",
|
|
24623
|
+
agentPrompt: "Fix static-frame issues from review-report.json, then rerender.",
|
|
24624
|
+
reason: "Static segments usually need creative scene, storyboard, or asset changes.",
|
|
24625
|
+
sourceIssueCodes
|
|
24626
|
+
})
|
|
24627
|
+
];
|
|
24628
|
+
}
|
|
24629
|
+
if (code === "LONG_SILENCE") {
|
|
24630
|
+
return issue.fixOwner === "host-agent" ? [
|
|
24631
|
+
agentReviewAction({
|
|
24632
|
+
label: beat ? `Fix long silence in beat ${beat}` : "Fix long silence",
|
|
24633
|
+
agentPrompt: "Fix long-silence issues from review-report.json, then rerender.",
|
|
24634
|
+
reason: "The beat duration, narration, or music cue needs host-agent judgment.",
|
|
24635
|
+
sourceIssueCodes
|
|
24636
|
+
})
|
|
24637
|
+
] : [
|
|
24638
|
+
commandReviewAction(`vibe build ${projectDir}${beatFlag} --stage sync --json`, {
|
|
24639
|
+
label: beat ? `Sync audio for beat ${beat}` : "Sync audio wiring",
|
|
24640
|
+
reason: "The silence may be caused by stale narration or music wiring.",
|
|
24641
|
+
sourceIssueCodes
|
|
24642
|
+
})
|
|
24643
|
+
];
|
|
24644
|
+
}
|
|
24645
|
+
if (code.startsWith("AI_REVIEW_")) {
|
|
24646
|
+
return [
|
|
24647
|
+
agentReviewAction({
|
|
24648
|
+
label: "Fix AI review findings",
|
|
24649
|
+
agentPrompt: "Fix host-agent-owned AI review issues from review-report.json, then rerender.",
|
|
24650
|
+
reason: "AI review findings require storyboard, design, or composition judgment.",
|
|
24651
|
+
sourceIssueCodes
|
|
24652
|
+
})
|
|
24653
|
+
];
|
|
24654
|
+
}
|
|
24655
|
+
if (code === "FFPROBE_UNAVAILABLE" || code === "FFMPEG_UNAVAILABLE") {
|
|
24656
|
+
return [
|
|
24657
|
+
manualReviewAction({
|
|
24658
|
+
label: "Install FFmpeg and rerun inspection",
|
|
24659
|
+
reason: "Local media inspection depends on ffmpeg/ffprobe being available.",
|
|
24660
|
+
fixOwner: "host-agent",
|
|
24661
|
+
sourceIssueCodes
|
|
24662
|
+
})
|
|
24663
|
+
];
|
|
24664
|
+
}
|
|
24665
|
+
if (code === "FFPROBE_FAILED" || code === "NO_VIDEO_STREAM") {
|
|
24666
|
+
return [
|
|
24667
|
+
commandReviewAction(
|
|
24668
|
+
beat ? `vibe render ${projectDir} --beat ${beat} --json` : `vibe render ${projectDir} --json`,
|
|
24669
|
+
{
|
|
24670
|
+
label: beat ? `Rerender beat ${beat}` : "Rerender the project",
|
|
24671
|
+
reason: "The rendered media could not be probed as a valid video.",
|
|
24672
|
+
sourceIssueCodes
|
|
24673
|
+
}
|
|
24674
|
+
)
|
|
24675
|
+
];
|
|
24676
|
+
}
|
|
24677
|
+
if (code === "ASPECT_MISMATCH") {
|
|
24678
|
+
return [
|
|
24679
|
+
manualReviewAction({
|
|
24680
|
+
label: "Check project aspect and render settings",
|
|
24681
|
+
reason: "Aspect mismatches can come from either config intent or render settings.",
|
|
24682
|
+
fixOwner: issue.fixOwner,
|
|
24683
|
+
sourceIssueCodes
|
|
24684
|
+
})
|
|
24685
|
+
];
|
|
24686
|
+
}
|
|
24687
|
+
return [];
|
|
24688
|
+
}
|
|
24689
|
+
function classifyReviewCommand(command3) {
|
|
24690
|
+
const lower = command3.trim().toLowerCase();
|
|
24691
|
+
if (lower.startsWith("vibe status ")) return safe("free");
|
|
24692
|
+
if (lower.startsWith("vibe scene repair")) return safe("free");
|
|
24693
|
+
if (lower.startsWith("vibe storyboard validate") || lower.startsWith("vibe storyboard get") || lower.startsWith("vibe storyboard list")) {
|
|
24694
|
+
return safe("free", "host-agent");
|
|
24695
|
+
}
|
|
24696
|
+
if (lower.startsWith("vibe inspect project")) return safe("free");
|
|
24697
|
+
if (lower.startsWith("vibe inspect render")) {
|
|
24698
|
+
if (lower.includes("--ai")) return unsafe("low");
|
|
24699
|
+
return safe("free");
|
|
24700
|
+
}
|
|
24701
|
+
if (lower.startsWith("vibe render ")) return safe("free");
|
|
24702
|
+
if (lower.startsWith("vibe build ")) {
|
|
24703
|
+
if (lower.includes("--dry-run")) return safe("free");
|
|
24704
|
+
if (lower.includes("--stage sync") || lower.includes("--stage render")) return safe("free");
|
|
24705
|
+
return unsafe("unknown");
|
|
24706
|
+
}
|
|
24707
|
+
if (lower.startsWith("vibe generate video") || lower.startsWith("vibe edit fill-gaps") || lower.startsWith("vibe remix ")) {
|
|
24708
|
+
return unsafe("very-high");
|
|
24709
|
+
}
|
|
24710
|
+
if (lower.startsWith("vibe storyboard revise")) return unsafe("unknown", "host-agent");
|
|
24711
|
+
return unsafe("unknown");
|
|
24712
|
+
}
|
|
24713
|
+
function safe(costTier, fixOwner = "vibe") {
|
|
24714
|
+
return { fixOwner, costTier, safeToAutoRun: true, requiresConfirmation: false };
|
|
24715
|
+
}
|
|
24716
|
+
function unsafe(costTier, fixOwner = "vibe") {
|
|
24717
|
+
return { fixOwner, costTier, safeToAutoRun: false, requiresConfirmation: true };
|
|
24718
|
+
}
|
|
24719
|
+
function actionId(kind3, value) {
|
|
24720
|
+
const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 80);
|
|
24721
|
+
return `${kind3}:${slug || "action"}`;
|
|
24722
|
+
}
|
|
24723
|
+
function uniqueStrings(items) {
|
|
24724
|
+
return [
|
|
24725
|
+
...new Set(items.filter((item) => typeof item === "string" && item.length > 0))
|
|
24726
|
+
];
|
|
24727
|
+
}
|
|
24728
|
+
var init_review_report = __esm({
|
|
24729
|
+
"../cli/src/commands/_shared/review-report.ts"() {
|
|
24730
|
+
"use strict";
|
|
24731
|
+
}
|
|
24732
|
+
});
|
|
24733
|
+
|
|
24063
24734
|
// ../cli/src/commands/_shared/storyboard-parse.ts
|
|
24735
|
+
function resolveCharacters(frontmatter) {
|
|
24736
|
+
const pool = frontmatter?.characters;
|
|
24737
|
+
if (!pool || typeof pool !== "object") return [];
|
|
24738
|
+
const resolved = [];
|
|
24739
|
+
for (const [name, spec] of Object.entries(pool)) {
|
|
24740
|
+
if (typeof spec === "string") {
|
|
24741
|
+
const prompt3 = spec.trim();
|
|
24742
|
+
if (prompt3) resolved.push({ name, prompt: prompt3 });
|
|
24743
|
+
continue;
|
|
24744
|
+
}
|
|
24745
|
+
if (spec && typeof spec === "object") {
|
|
24746
|
+
const image = typeof spec.image === "string" ? spec.image.trim() : "";
|
|
24747
|
+
if (image) {
|
|
24748
|
+
resolved.push({ name, imagePath: image });
|
|
24749
|
+
continue;
|
|
24750
|
+
}
|
|
24751
|
+
const description = typeof spec.description === "string" ? spec.description.trim() : "";
|
|
24752
|
+
if (description) resolved.push({ name, prompt: description });
|
|
24753
|
+
}
|
|
24754
|
+
}
|
|
24755
|
+
return resolved;
|
|
24756
|
+
}
|
|
24757
|
+
function beatCharacterNames(cues) {
|
|
24758
|
+
const raw2 = cues?.characters;
|
|
24759
|
+
if (typeof raw2 === "string") {
|
|
24760
|
+
const name = raw2.trim();
|
|
24761
|
+
return name ? [name] : [];
|
|
24762
|
+
}
|
|
24763
|
+
if (Array.isArray(raw2)) {
|
|
24764
|
+
return raw2.filter((v2) => typeof v2 === "string" && v2.trim().length > 0).map((v2) => v2.trim());
|
|
24765
|
+
}
|
|
24766
|
+
return [];
|
|
24767
|
+
}
|
|
24064
24768
|
function parseStoryboard(md) {
|
|
24065
24769
|
const normalized = md.replace(/\r\n/g, "\n");
|
|
24066
24770
|
const { frontmatter, remaining } = extractProjectFrontmatter(normalized);
|
|
@@ -24173,28 +24877,28 @@ var init_storyboard_parse = __esm({
|
|
|
24173
24877
|
// ../cli/src/commands/_shared/status-jobs.ts
|
|
24174
24878
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
24175
24879
|
import { existsSync as existsSync2, statSync } from "node:fs";
|
|
24176
|
-
import { copyFile, mkdir as mkdir3, readFile as readFile4, readdir, stat, writeFile as
|
|
24177
|
-
import { dirname as dirname3, join as
|
|
24880
|
+
import { copyFile, mkdir as mkdir3, readFile as readFile4, readdir, stat, writeFile as writeFile7 } from "node:fs/promises";
|
|
24881
|
+
import { dirname as dirname3, join as join3, parse as parse2, relative, resolve as resolve6 } from "node:path";
|
|
24178
24882
|
function isLocalJob(record) {
|
|
24179
24883
|
return record.jobType === "build" || record.jobType === "render";
|
|
24180
24884
|
}
|
|
24181
24885
|
function findProjectRoot(start = process.cwd()) {
|
|
24182
|
-
let dir =
|
|
24886
|
+
let dir = resolve6(start);
|
|
24183
24887
|
try {
|
|
24184
24888
|
if (existsSync2(dir) && statSync(dir).isFile()) dir = dirname3(dir);
|
|
24185
24889
|
} catch {
|
|
24186
24890
|
}
|
|
24187
24891
|
for (; ; ) {
|
|
24188
|
-
if (existsSync2(
|
|
24892
|
+
if (existsSync2(join3(dir, "vibe.config.json")) || existsSync2(join3(dir, "STORYBOARD.md"))) {
|
|
24189
24893
|
return dir;
|
|
24190
24894
|
}
|
|
24191
24895
|
const parent = dirname3(dir);
|
|
24192
|
-
if (parent === dir) return
|
|
24896
|
+
if (parent === dir) return resolve6(start);
|
|
24193
24897
|
dir = parent;
|
|
24194
24898
|
}
|
|
24195
24899
|
}
|
|
24196
24900
|
function jobsDir(projectDir) {
|
|
24197
|
-
return
|
|
24901
|
+
return join3(resolve6(projectDir), ".vibeframe", "jobs");
|
|
24198
24902
|
}
|
|
24199
24903
|
function normalizeJobStatus(status) {
|
|
24200
24904
|
const value = String(status ?? "").toLowerCase();
|
|
@@ -24208,10 +24912,10 @@ function normalizeJobStatus(status) {
|
|
|
24208
24912
|
}
|
|
24209
24913
|
function createJobRecord(opts) {
|
|
24210
24914
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
24211
|
-
const projectDir =
|
|
24915
|
+
const projectDir = resolve6(
|
|
24212
24916
|
opts.projectDir ?? findProjectRoot(opts.workingDirectory ?? process.cwd())
|
|
24213
24917
|
);
|
|
24214
|
-
const workingDirectory =
|
|
24918
|
+
const workingDirectory = resolve6(opts.workingDirectory ?? process.cwd());
|
|
24215
24919
|
const id = opts.id ?? makeJobId(opts.providerTaskId, now);
|
|
24216
24920
|
const base = {
|
|
24217
24921
|
schemaVersion: "1",
|
|
@@ -24246,7 +24950,7 @@ function createJobRecord(opts) {
|
|
|
24246
24950
|
message: opts.message
|
|
24247
24951
|
};
|
|
24248
24952
|
base.retryWith = retryWithForJob(base);
|
|
24249
|
-
return
|
|
24953
|
+
return stripUndefined2(base);
|
|
24250
24954
|
}
|
|
24251
24955
|
async function createAndWriteJobRecord(opts) {
|
|
24252
24956
|
const record = createJobRecord(opts);
|
|
@@ -24256,15 +24960,15 @@ async function createAndWriteJobRecord(opts) {
|
|
|
24256
24960
|
async function writeJobRecord(record) {
|
|
24257
24961
|
const dir = jobsDir(record.projectDir);
|
|
24258
24962
|
await mkdir3(dir, { recursive: true });
|
|
24259
|
-
await
|
|
24963
|
+
await writeFile7(
|
|
24260
24964
|
jobRecordPath(record.id, record.projectDir),
|
|
24261
|
-
JSON.stringify(
|
|
24965
|
+
JSON.stringify(stripUndefined2(record), null, 2) + "\n",
|
|
24262
24966
|
"utf-8"
|
|
24263
24967
|
);
|
|
24264
24968
|
}
|
|
24265
24969
|
async function readJobRecord(jobId, projectDir) {
|
|
24266
24970
|
const id = normalizeJobId(jobId);
|
|
24267
|
-
const project =
|
|
24971
|
+
const project = resolve6(projectDir ?? findProjectRoot());
|
|
24268
24972
|
const path14 = jobRecordPath(id, project);
|
|
24269
24973
|
if (!existsSync2(path14)) return null;
|
|
24270
24974
|
return parseJobRecord(await readFile4(path14, "utf-8"));
|
|
@@ -24277,7 +24981,7 @@ async function listJobRecords(projectDir) {
|
|
|
24277
24981
|
for (const entry of entries2) {
|
|
24278
24982
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
24279
24983
|
try {
|
|
24280
|
-
const parsed = parseJobRecord(await readFile4(
|
|
24984
|
+
const parsed = parseJobRecord(await readFile4(join3(dir, entry.name), "utf-8"));
|
|
24281
24985
|
if (parsed) records.push(parsed);
|
|
24282
24986
|
} catch {
|
|
24283
24987
|
}
|
|
@@ -24371,9 +25075,9 @@ async function refreshLocalJobRecord(record, opts) {
|
|
|
24371
25075
|
const heartbeatAge = record.heartbeatAt ? Date.now() - new Date(record.heartbeatAt).getTime() : Number.POSITIVE_INFINITY;
|
|
24372
25076
|
const orphaned = !isPidAlive(record.pid) || heartbeatAge > LOCAL_JOB_ORPHAN_AFTER_MS;
|
|
24373
25077
|
if (orphaned) {
|
|
24374
|
-
const hint = `The process that ran this ${record.jobType} job is gone. Check ${
|
|
25078
|
+
const hint = `The process that ran this ${record.jobType} job is gone. Check ${join3(record.projectDir, record.jobType === "render" ? "render-report.json" : "build-report.json")} \u2014 the work may have completed before the process exited.`;
|
|
24375
25079
|
warnings.push(hint);
|
|
24376
|
-
updated =
|
|
25080
|
+
updated = stripUndefined2({
|
|
24377
25081
|
...record,
|
|
24378
25082
|
status: "unknown",
|
|
24379
25083
|
error: record.error ?? hint,
|
|
@@ -24390,7 +25094,7 @@ async function refreshLocalJobRecord(record, opts) {
|
|
|
24390
25094
|
});
|
|
24391
25095
|
}
|
|
24392
25096
|
async function inspectProjectStatus(projectDirArg, opts = {}) {
|
|
24393
|
-
const project =
|
|
25097
|
+
const project = resolve6(projectDirArg);
|
|
24394
25098
|
const warnings = [];
|
|
24395
25099
|
let records = await listJobRecords(project);
|
|
24396
25100
|
if (opts.refresh) {
|
|
@@ -24420,6 +25124,10 @@ async function inspectProjectStatus(projectDirArg, opts = {}) {
|
|
|
24420
25124
|
...review?.retryWith ?? [],
|
|
24421
25125
|
...workflow.retryWith
|
|
24422
25126
|
];
|
|
25127
|
+
const nextActions = normalizeReviewActions([
|
|
25128
|
+
...review?.nextActions ?? [],
|
|
25129
|
+
...reviewActionsFromRetryWith([...build?.retryWith ?? [], ...workflow.retryWith])
|
|
25130
|
+
]);
|
|
24423
25131
|
return {
|
|
24424
25132
|
schemaVersion: "1",
|
|
24425
25133
|
kind: "project",
|
|
@@ -24431,11 +25139,12 @@ async function inspectProjectStatus(projectDirArg, opts = {}) {
|
|
|
24431
25139
|
review,
|
|
24432
25140
|
jobs,
|
|
24433
25141
|
warnings,
|
|
25142
|
+
nextActions,
|
|
24434
25143
|
retryWith: unique(retryWith)
|
|
24435
25144
|
};
|
|
24436
25145
|
}
|
|
24437
25146
|
function summarizeJob(record) {
|
|
24438
|
-
return
|
|
25147
|
+
return stripUndefined2({
|
|
24439
25148
|
id: record.id,
|
|
24440
25149
|
jobType: record.jobType,
|
|
24441
25150
|
status: record.status,
|
|
@@ -24459,7 +25168,7 @@ function retryWithForJob(record) {
|
|
|
24459
25168
|
]);
|
|
24460
25169
|
}
|
|
24461
25170
|
function makeJobStatusResult(record, opts) {
|
|
24462
|
-
return
|
|
25171
|
+
return stripUndefined2({
|
|
24463
25172
|
schemaVersion: "1",
|
|
24464
25173
|
kind: "job",
|
|
24465
25174
|
id: record.id,
|
|
@@ -24483,7 +25192,7 @@ function jobProgress(record) {
|
|
|
24483
25192
|
if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
|
|
24484
25193
|
if (record.progress === void 0 && !record.providerStatus) return void 0;
|
|
24485
25194
|
}
|
|
24486
|
-
return
|
|
25195
|
+
return stripUndefined2({
|
|
24487
25196
|
percent: record.progress,
|
|
24488
25197
|
phase: record.stage ?? record.providerStatus ?? statusPhase(record.status),
|
|
24489
25198
|
providerStatus: record.providerStatus ?? record.message
|
|
@@ -24493,7 +25202,7 @@ function jobResult(record) {
|
|
|
24493
25202
|
if (!record.resultUrl && !record.outputPath && !record.cachePath && !record.error && !record.resultPayload) {
|
|
24494
25203
|
return null;
|
|
24495
25204
|
}
|
|
24496
|
-
return
|
|
25205
|
+
return stripUndefined2({
|
|
24497
25206
|
url: record.resultUrl,
|
|
24498
25207
|
outputPath: record.outputPath,
|
|
24499
25208
|
cachePath: record.cachePath,
|
|
@@ -24529,7 +25238,7 @@ function normalizeJobId(jobId) {
|
|
|
24529
25238
|
return id;
|
|
24530
25239
|
}
|
|
24531
25240
|
function jobRecordPath(jobId, projectDir) {
|
|
24532
|
-
return
|
|
25241
|
+
return join3(jobsDir(projectDir), `${normalizeJobId(jobId)}.json`);
|
|
24533
25242
|
}
|
|
24534
25243
|
function parseJobRecord(raw2) {
|
|
24535
25244
|
const parsed = JSON.parse(raw2);
|
|
@@ -24554,11 +25263,11 @@ function updateRecordFromProvider(record, result) {
|
|
|
24554
25263
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24555
25264
|
};
|
|
24556
25265
|
next.retryWith = retryWithForJob(next);
|
|
24557
|
-
return
|
|
25266
|
+
return stripUndefined2(next);
|
|
24558
25267
|
}
|
|
24559
25268
|
function resolveRefreshOutput(record, opts) {
|
|
24560
|
-
if (opts.output) return
|
|
24561
|
-
return record.outputPath ?
|
|
25269
|
+
if (opts.output) return resolve6(opts.workingDirectory ?? process.cwd(), opts.output);
|
|
25270
|
+
return record.outputPath ? resolve6(record.outputPath) : void 0;
|
|
24562
25271
|
}
|
|
24563
25272
|
function liveSupport(record) {
|
|
24564
25273
|
if (record.jobType === "generate-video" && (record.provider === "grok" || record.provider === "runway" || record.provider === "kling" || record.provider === "veo")) {
|
|
@@ -24583,7 +25292,7 @@ async function downloadUrl(url, outputPath) {
|
|
|
24583
25292
|
if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`);
|
|
24584
25293
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
24585
25294
|
await mkdir3(dirname3(outputPath), { recursive: true });
|
|
24586
|
-
await
|
|
25295
|
+
await writeFile7(outputPath, buffer);
|
|
24587
25296
|
return outputPath;
|
|
24588
25297
|
}
|
|
24589
25298
|
async function maybeCacheOutput(record) {
|
|
@@ -24615,7 +25324,7 @@ async function maybeWriteCompletedAssetMetadata(record) {
|
|
|
24615
25324
|
}
|
|
24616
25325
|
}
|
|
24617
25326
|
async function refreshBuildReportFromJobs(projectDir, records) {
|
|
24618
|
-
const reportPath =
|
|
25327
|
+
const reportPath = join3(projectDir, "build-report.json");
|
|
24619
25328
|
const report = await readJson(reportPath);
|
|
24620
25329
|
if (!report || !Array.isArray(report.beats)) return;
|
|
24621
25330
|
let changed = false;
|
|
@@ -24643,7 +25352,7 @@ async function refreshBuildReportFromJobs(projectDir, records) {
|
|
|
24643
25352
|
if (kind3 === "music" && record.assetOptions && typeof record.assetOptions.duration === "number") {
|
|
24644
25353
|
nested.durationSec = record.assetOptions.duration;
|
|
24645
25354
|
}
|
|
24646
|
-
beatRecord[kind3] =
|
|
25355
|
+
beatRecord[kind3] = stripUndefined2(nested);
|
|
24647
25356
|
beatRecord[`${kind3}Path`] = outputPath;
|
|
24648
25357
|
beatRecord[`${kind3}Status`] = "generated";
|
|
24649
25358
|
beatRecord[`${kind3}JobId`] = record.id;
|
|
@@ -24663,17 +25372,17 @@ async function refreshBuildReportFromJobs(projectDir, records) {
|
|
|
24663
25372
|
}
|
|
24664
25373
|
if (!changed) return;
|
|
24665
25374
|
try {
|
|
24666
|
-
await
|
|
25375
|
+
await writeFile7(reportPath, JSON.stringify(stripUndefined2(report), null, 2) + "\n", "utf-8");
|
|
24667
25376
|
} catch {
|
|
24668
25377
|
}
|
|
24669
25378
|
}
|
|
24670
25379
|
async function readBuildSummary(projectDir) {
|
|
24671
|
-
const reportPath =
|
|
25380
|
+
const reportPath = join3(projectDir, "build-report.json");
|
|
24672
25381
|
const report = await readJson(reportPath);
|
|
24673
25382
|
if (!report) return null;
|
|
24674
25383
|
const info = await statOrNull(reportPath);
|
|
24675
25384
|
const beatSummary = projectBeatReadinessFromUnknown(report.beatSummary);
|
|
24676
|
-
return
|
|
25385
|
+
return stripUndefined2({
|
|
24677
25386
|
reportPath,
|
|
24678
25387
|
kind: typeof report.kind === "string" ? report.kind : void 0,
|
|
24679
25388
|
success: typeof report.success === "boolean" ? report.success : void 0,
|
|
@@ -24691,7 +25400,7 @@ async function readBuildSummary(projectDir) {
|
|
|
24691
25400
|
});
|
|
24692
25401
|
}
|
|
24693
25402
|
async function readReviewSummary(projectDir) {
|
|
24694
|
-
const reportPath =
|
|
25403
|
+
const reportPath = join3(projectDir, "review-report.json");
|
|
24695
25404
|
const report = await readJson(reportPath);
|
|
24696
25405
|
if (!report) return null;
|
|
24697
25406
|
const info = await statOrNull(reportPath);
|
|
@@ -24699,7 +25408,7 @@ async function readReviewSummary(projectDir) {
|
|
|
24699
25408
|
const summary = report.summary && typeof report.summary === "object" ? report.summary : {};
|
|
24700
25409
|
const fixOwners = summary.fixOwners && typeof summary.fixOwners === "object" ? summary.fixOwners : {};
|
|
24701
25410
|
const computedFixOwners = countIssueFixOwners(issues);
|
|
24702
|
-
return
|
|
25411
|
+
return stripUndefined2({
|
|
24703
25412
|
reportPath,
|
|
24704
25413
|
kind: typeof report.kind === "string" ? report.kind : void 0,
|
|
24705
25414
|
mode: typeof report.mode === "string" ? report.mode : void 0,
|
|
@@ -24724,9 +25433,44 @@ async function readReviewSummary(projectDir) {
|
|
|
24724
25433
|
},
|
|
24725
25434
|
sourceReports: stringArray(report.sourceReports),
|
|
24726
25435
|
updatedAt: info?.mtime.toISOString(),
|
|
25436
|
+
nextActions: reviewActionsFromUnknown(report.nextActions),
|
|
24727
25437
|
retryWith: stringArray(report.retryWith)
|
|
24728
25438
|
});
|
|
24729
25439
|
}
|
|
25440
|
+
function reviewActionsFromUnknown(value) {
|
|
25441
|
+
if (!Array.isArray(value)) return [];
|
|
25442
|
+
return value.flatMap((item) => {
|
|
25443
|
+
if (!item || typeof item !== "object") return [];
|
|
25444
|
+
const record = item;
|
|
25445
|
+
const kind3 = stringEnum(record.kind, ["command", "agent", "manual"]);
|
|
25446
|
+
const fixOwner = stringEnum(record.fixOwner, ["vibe", "host-agent"]);
|
|
25447
|
+
const costTier = stringEnum(record.costTier, [
|
|
25448
|
+
"free",
|
|
25449
|
+
"low",
|
|
25450
|
+
"high",
|
|
25451
|
+
"very-high",
|
|
25452
|
+
"unknown"
|
|
25453
|
+
]);
|
|
25454
|
+
if (!kind3 || !fixOwner || !costTier || typeof record.id !== "string" || typeof record.label !== "string" || typeof record.safeToAutoRun !== "boolean" || typeof record.requiresConfirmation !== "boolean" || typeof record.reason !== "string") {
|
|
25455
|
+
return [];
|
|
25456
|
+
}
|
|
25457
|
+
return [
|
|
25458
|
+
stripUndefined2({
|
|
25459
|
+
id: record.id,
|
|
25460
|
+
kind: kind3,
|
|
25461
|
+
label: record.label,
|
|
25462
|
+
command: typeof record.command === "string" ? record.command : void 0,
|
|
25463
|
+
agentPrompt: typeof record.agentPrompt === "string" ? record.agentPrompt : void 0,
|
|
25464
|
+
fixOwner,
|
|
25465
|
+
costTier,
|
|
25466
|
+
safeToAutoRun: record.safeToAutoRun,
|
|
25467
|
+
requiresConfirmation: record.requiresConfirmation,
|
|
25468
|
+
reason: record.reason,
|
|
25469
|
+
sourceIssueCodes: stringArray(record.sourceIssueCodes)
|
|
25470
|
+
})
|
|
25471
|
+
];
|
|
25472
|
+
});
|
|
25473
|
+
}
|
|
24730
25474
|
function summarizeJobs(records) {
|
|
24731
25475
|
return {
|
|
24732
25476
|
total: records.length,
|
|
@@ -24745,7 +25489,7 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
24745
25489
|
if (fromBeats) return fromBeats;
|
|
24746
25490
|
if (build.beats) return augmentBeatReadinessFromJobs(build.beats, records, report?.jobs);
|
|
24747
25491
|
}
|
|
24748
|
-
const storyboardPath =
|
|
25492
|
+
const storyboardPath = join3(projectDir, "STORYBOARD.md");
|
|
24749
25493
|
if (!existsSync2(storyboardPath)) {
|
|
24750
25494
|
return { total: 0, assetsReady: 0, compositionsReady: 0, needsAuthor: [] };
|
|
24751
25495
|
}
|
|
@@ -24754,7 +25498,7 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
24754
25498
|
const needsAuthor = [];
|
|
24755
25499
|
let compositionsReady = 0;
|
|
24756
25500
|
for (const beat of parsed.beats) {
|
|
24757
|
-
if (existsSync2(
|
|
25501
|
+
if (existsSync2(join3(projectDir, "compositions", `scene-${beat.id}.html`))) {
|
|
24758
25502
|
compositionsReady += 1;
|
|
24759
25503
|
} else {
|
|
24760
25504
|
needsAuthor.push(beat.id);
|
|
@@ -24772,7 +25516,7 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
24772
25516
|
}
|
|
24773
25517
|
function deriveProjectWorkflow(opts) {
|
|
24774
25518
|
const retryWith = [];
|
|
24775
|
-
const hasStoryboard = existsSync2(
|
|
25519
|
+
const hasStoryboard = existsSync2(join3(opts.project, "STORYBOARD.md"));
|
|
24776
25520
|
if (!hasStoryboard && !opts.build) {
|
|
24777
25521
|
retryWith.push(`vibe init ${opts.project} --from "<brief>" --json`);
|
|
24778
25522
|
return { status: "empty", currentStage: "init", retryWith };
|
|
@@ -24868,7 +25612,7 @@ function beatReadinessFromBuildBeats(projectDir, beats, records = [], reportJobs
|
|
|
24868
25612
|
if (buildBeatAssetsReady(record) || (id ? buildBeatJobsReady(id, records, reportJobs) : false))
|
|
24869
25613
|
assetsReady += 1;
|
|
24870
25614
|
const compositionPath = typeof record.compositionPath === "string" ? record.compositionPath : id ? `compositions/scene-${id}.html` : void 0;
|
|
24871
|
-
if (compositionPath && existsSync2(
|
|
25615
|
+
if (compositionPath && existsSync2(resolve6(projectDir, compositionPath))) {
|
|
24872
25616
|
compositionsReady += 1;
|
|
24873
25617
|
} else if (id) {
|
|
24874
25618
|
needsAuthor.push(id);
|
|
@@ -24938,6 +25682,9 @@ function numberOr(fallback2, value) {
|
|
|
24938
25682
|
function stringArray(value) {
|
|
24939
25683
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.length > 0) : [];
|
|
24940
25684
|
}
|
|
25685
|
+
function stringEnum(value, allowed) {
|
|
25686
|
+
return typeof value === "string" && allowed.includes(value) ? value : void 0;
|
|
25687
|
+
}
|
|
24941
25688
|
function isActiveStatus(status) {
|
|
24942
25689
|
return status === "queued" || status === "running";
|
|
24943
25690
|
}
|
|
@@ -24967,7 +25714,7 @@ function assetKindForJob(record) {
|
|
|
24967
25714
|
return void 0;
|
|
24968
25715
|
}
|
|
24969
25716
|
function projectRelativePath(projectDir, path14) {
|
|
24970
|
-
const rel = relative(
|
|
25717
|
+
const rel = relative(resolve6(projectDir), resolve6(path14));
|
|
24971
25718
|
if (!rel || rel.startsWith("..")) return path14;
|
|
24972
25719
|
return rel.replace(/\\/g, "/");
|
|
24973
25720
|
}
|
|
@@ -24985,7 +25732,7 @@ async function statOrNull(path14) {
|
|
|
24985
25732
|
return null;
|
|
24986
25733
|
}
|
|
24987
25734
|
}
|
|
24988
|
-
function
|
|
25735
|
+
function stripUndefined2(value) {
|
|
24989
25736
|
return Object.fromEntries(Object.entries(value).filter(([, v2]) => v2 !== void 0));
|
|
24990
25737
|
}
|
|
24991
25738
|
function unique(items) {
|
|
@@ -25003,6 +25750,7 @@ var init_status_jobs = __esm({
|
|
|
25003
25750
|
init_ai_video();
|
|
25004
25751
|
init_music_status();
|
|
25005
25752
|
init_build_asset_metadata();
|
|
25753
|
+
init_review_report();
|
|
25006
25754
|
init_storyboard_parse();
|
|
25007
25755
|
LOCAL_JOB_ORPHAN_AFTER_MS = 9e4;
|
|
25008
25756
|
}
|
|
@@ -25011,7 +25759,7 @@ var init_status_jobs = __esm({
|
|
|
25011
25759
|
// ../cli/src/commands/_shared/project-config.ts
|
|
25012
25760
|
import { existsSync as existsSync3 } from "node:fs";
|
|
25013
25761
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
25014
|
-
import { resolve as
|
|
25762
|
+
import { resolve as resolve7 } from "node:path";
|
|
25015
25763
|
function defaultProjectConfig(opts) {
|
|
25016
25764
|
return {
|
|
25017
25765
|
schemaVersion: "1",
|
|
@@ -25062,9 +25810,9 @@ function projectConfigJson(opts) {
|
|
|
25062
25810
|
return JSON.stringify(defaultProjectConfig(opts), null, 2) + "\n";
|
|
25063
25811
|
}
|
|
25064
25812
|
async function readProjectConfig(projectDir) {
|
|
25065
|
-
const dir =
|
|
25066
|
-
const canonicalPath =
|
|
25067
|
-
const legacyPath =
|
|
25813
|
+
const dir = resolve7(projectDir);
|
|
25814
|
+
const canonicalPath = resolve7(dir, VIBE_CONFIG_FILENAME);
|
|
25815
|
+
const legacyPath = resolve7(dir, LEGACY_VIBE_PROJECT_FILENAME);
|
|
25068
25816
|
if (existsSync3(canonicalPath)) {
|
|
25069
25817
|
try {
|
|
25070
25818
|
const raw2 = await readFile5(canonicalPath, "utf-8");
|
|
@@ -25127,8 +25875,8 @@ var init_project_config = __esm({
|
|
|
25127
25875
|
});
|
|
25128
25876
|
|
|
25129
25877
|
// ../cli/src/commands/_shared/scene-project.ts
|
|
25130
|
-
import { mkdir as mkdir4, readFile as readFile6, writeFile as
|
|
25131
|
-
import { resolve as
|
|
25878
|
+
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile8, access as access3 } from "node:fs/promises";
|
|
25879
|
+
import { resolve as resolve8, basename as basename2 } from "node:path";
|
|
25132
25880
|
function aspectToDims(aspect) {
|
|
25133
25881
|
return ASPECT_DIMS[aspect];
|
|
25134
25882
|
}
|
|
@@ -25426,6 +26174,43 @@ vibe host setup all --write # write project/app config
|
|
|
25426
26174
|
vibe host doctor all --json # verify readiness
|
|
25427
26175
|
\`\`\`
|
|
25428
26176
|
|
|
26177
|
+
## Native host goal loop
|
|
26178
|
+
|
|
26179
|
+
For long-running work, use Codex Goal mode, Claude Code \`/goal\`, or the
|
|
26180
|
+
host's equivalent as the outer loop. VibeFrame should not run a competing
|
|
26181
|
+
project-level goal loop; it provides \`--json\` commands, dry runs, cost caps,
|
|
26182
|
+
\`build-report.json\`, \`review-report.json\`, \`nextActions\`, \`safeToAutoRun\`,
|
|
26183
|
+
\`requiresConfirmation\`, \`fixOwner\`, deterministic repair, and render
|
|
26184
|
+
inspection for the host agent to reason over.
|
|
26185
|
+
|
|
26186
|
+
Copy-paste examples:
|
|
26187
|
+
|
|
26188
|
+
\`\`\`text
|
|
26189
|
+
/goal Build this VibeFrame project into renders/final.mp4. Use --json for every
|
|
26190
|
+
vibe command, run --dry-run before paid operations, use --max-cost 5 for builds
|
|
26191
|
+
unless the user sets another budget, read build-report.json and
|
|
26192
|
+
review-report.json before deciding the next action, prefer nextActions before
|
|
26193
|
+
guessing, run only safeToAutoRun:true actions automatically, and ask before
|
|
26194
|
+
requiresConfirmation:true actions. Treat retryWith as the compatibility
|
|
26195
|
+
fallback, fixOwner:"vibe" as CLI repair work, and fixOwner:"host-agent" as
|
|
26196
|
+
STORYBOARD.md, DESIGN.md, or composition edits.
|
|
26197
|
+
Stop only when renders/final.mp4 exists, duration and aspect ratio match the
|
|
26198
|
+
brief, inspect render --cheap has no errors, any AI review score is >= 90 when AI review is requested, and every
|
|
26199
|
+
remaining host-agent issue is fixed, accepted with rationale, or reported as
|
|
26200
|
+
blocked.
|
|
26201
|
+
\`\`\`
|
|
26202
|
+
|
|
26203
|
+
\`\`\`text
|
|
26204
|
+
/goal Finish this VibeFrame render using Claude Code goal mode as the outer
|
|
26205
|
+
loop. Use vibe context/schema when unsure, --json everywhere, dry-run before
|
|
26206
|
+
paid operations, budget cap via --max-cost 5, nextActions before guessing,
|
|
26207
|
+
build-report.json/review-report.json as loop state, and safeToAutoRun,
|
|
26208
|
+
requiresConfirmation, and fixOwner to decide between vibe scene repair and
|
|
26209
|
+
host-agent edits. Stop only after final MP4,
|
|
26210
|
+
target duration/aspect ratio, clean render inspection, any AI review score >= 90 when AI review is requested, and
|
|
26211
|
+
no unresolved unacknowledged host-agent issues.
|
|
26212
|
+
\`\`\`
|
|
26213
|
+
|
|
25429
26214
|
## Skills \u2014 USE THESE FIRST
|
|
25430
26215
|
|
|
25431
26216
|
@SKILL.md
|
|
@@ -25529,35 +26314,35 @@ tmp/
|
|
|
25529
26314
|
`;
|
|
25530
26315
|
}
|
|
25531
26316
|
function describeSceneScaffold(opts) {
|
|
25532
|
-
const dir =
|
|
26317
|
+
const dir = resolve8(opts.dir);
|
|
25533
26318
|
const profile = opts.profile ?? "full";
|
|
25534
26319
|
const groups = {
|
|
25535
26320
|
authoring: [
|
|
25536
|
-
|
|
25537
|
-
|
|
25538
|
-
|
|
25539
|
-
|
|
25540
|
-
|
|
26321
|
+
resolve8(dir, "STORYBOARD.md"),
|
|
26322
|
+
resolve8(dir, "DESIGN.md"),
|
|
26323
|
+
resolve8(dir, VIBE_CONFIG_FILENAME),
|
|
26324
|
+
resolve8(dir, "vibe.project.yaml"),
|
|
26325
|
+
resolve8(dir, ".gitignore")
|
|
25541
26326
|
],
|
|
25542
26327
|
render: [],
|
|
25543
26328
|
agent: []
|
|
25544
26329
|
};
|
|
25545
26330
|
if (profile === "full") {
|
|
25546
26331
|
groups.render = [
|
|
25547
|
-
|
|
25548
|
-
|
|
25549
|
-
|
|
25550
|
-
|
|
25551
|
-
|
|
25552
|
-
|
|
26332
|
+
resolve8(dir, "index.html"),
|
|
26333
|
+
resolve8(dir, "compositions"),
|
|
26334
|
+
resolve8(dir, "assets"),
|
|
26335
|
+
resolve8(dir, "renders"),
|
|
26336
|
+
resolve8(dir, "hyperframes.json"),
|
|
26337
|
+
resolve8(dir, "meta.json")
|
|
25553
26338
|
];
|
|
25554
26339
|
}
|
|
25555
26340
|
if (profile === "agent" || profile === "full") {
|
|
25556
26341
|
groups.agent = [
|
|
25557
|
-
|
|
25558
|
-
|
|
25559
|
-
|
|
25560
|
-
|
|
26342
|
+
resolve8(dir, "AGENTS.md"),
|
|
26343
|
+
resolve8(dir, "SKILL.md"),
|
|
26344
|
+
resolve8(dir, "references"),
|
|
26345
|
+
resolve8(dir, "CLAUDE.md")
|
|
25561
26346
|
];
|
|
25562
26347
|
}
|
|
25563
26348
|
return groups;
|
|
@@ -25571,7 +26356,7 @@ async function pathExists(p2) {
|
|
|
25571
26356
|
}
|
|
25572
26357
|
}
|
|
25573
26358
|
async function scaffoldSceneProject(opts) {
|
|
25574
|
-
const dir =
|
|
26359
|
+
const dir = resolve8(opts.dir);
|
|
25575
26360
|
const name = opts.name ?? basename2(dir);
|
|
25576
26361
|
const aspect = opts.aspect ?? "16:9";
|
|
25577
26362
|
const duration = opts.duration ?? 10;
|
|
@@ -25579,103 +26364,103 @@ async function scaffoldSceneProject(opts) {
|
|
|
25579
26364
|
const profile = opts.profile ?? "full";
|
|
25580
26365
|
await mkdir4(dir, { recursive: true });
|
|
25581
26366
|
if (profile === "full") {
|
|
25582
|
-
await mkdir4(
|
|
25583
|
-
await mkdir4(
|
|
25584
|
-
await mkdir4(
|
|
26367
|
+
await mkdir4(resolve8(dir, "compositions"), { recursive: true });
|
|
26368
|
+
await mkdir4(resolve8(dir, "assets"), { recursive: true });
|
|
26369
|
+
await mkdir4(resolve8(dir, "renders"), { recursive: true });
|
|
25585
26370
|
}
|
|
25586
26371
|
const created = [];
|
|
25587
26372
|
const skipped2 = [];
|
|
25588
26373
|
const merged = [];
|
|
25589
26374
|
if (profile === "full") {
|
|
25590
|
-
const hfPath =
|
|
26375
|
+
const hfPath = resolve8(dir, "hyperframes.json");
|
|
25591
26376
|
const hfDefaults = buildHyperframesConfig();
|
|
25592
26377
|
if (await pathExists(hfPath)) {
|
|
25593
26378
|
const existingRaw = await readFile6(hfPath, "utf-8");
|
|
25594
26379
|
const existing = JSON.parse(existingRaw);
|
|
25595
26380
|
const mergedConfig = mergeHyperframesConfig(existing, hfDefaults);
|
|
25596
|
-
await
|
|
26381
|
+
await writeFile8(hfPath, JSON.stringify(mergedConfig, null, 2) + "\n", "utf-8");
|
|
25597
26382
|
merged.push(hfPath);
|
|
25598
26383
|
} else {
|
|
25599
|
-
await
|
|
26384
|
+
await writeFile8(hfPath, JSON.stringify(hfDefaults, null, 2) + "\n", "utf-8");
|
|
25600
26385
|
created.push(hfPath);
|
|
25601
26386
|
}
|
|
25602
|
-
const metaPath =
|
|
26387
|
+
const metaPath = resolve8(dir, "meta.json");
|
|
25603
26388
|
if (await pathExists(metaPath)) {
|
|
25604
26389
|
skipped2.push(metaPath);
|
|
25605
26390
|
} else {
|
|
25606
|
-
await
|
|
26391
|
+
await writeFile8(
|
|
25607
26392
|
metaPath,
|
|
25608
26393
|
JSON.stringify(buildHyperframesMeta(name, now), null, 2) + "\n",
|
|
25609
26394
|
"utf-8"
|
|
25610
26395
|
);
|
|
25611
26396
|
created.push(metaPath);
|
|
25612
26397
|
}
|
|
25613
|
-
const rootPath =
|
|
26398
|
+
const rootPath = resolve8(dir, "index.html");
|
|
25614
26399
|
if (await pathExists(rootPath)) {
|
|
25615
26400
|
skipped2.push(rootPath);
|
|
25616
26401
|
} else {
|
|
25617
|
-
await
|
|
26402
|
+
await writeFile8(rootPath, buildEmptyRootHtml({ aspect, duration }), "utf-8");
|
|
25618
26403
|
created.push(rootPath);
|
|
25619
26404
|
}
|
|
25620
26405
|
}
|
|
25621
|
-
const vibeConfigJsonPath =
|
|
26406
|
+
const vibeConfigJsonPath = resolve8(dir, VIBE_CONFIG_FILENAME);
|
|
25622
26407
|
if (await pathExists(vibeConfigJsonPath)) {
|
|
25623
26408
|
skipped2.push(vibeConfigJsonPath);
|
|
25624
26409
|
} else {
|
|
25625
|
-
await
|
|
26410
|
+
await writeFile8(vibeConfigJsonPath, projectConfigJson({ name, aspect }), "utf-8");
|
|
25626
26411
|
created.push(vibeConfigJsonPath);
|
|
25627
26412
|
}
|
|
25628
|
-
const vibePath =
|
|
26413
|
+
const vibePath = resolve8(dir, "vibe.project.yaml");
|
|
25629
26414
|
if (await pathExists(vibePath)) {
|
|
25630
26415
|
skipped2.push(vibePath);
|
|
25631
26416
|
} else {
|
|
25632
26417
|
const cfg = { ...defaultVibeProjectConfig(name), aspect };
|
|
25633
|
-
await
|
|
26418
|
+
await writeFile8(vibePath, (0, import_yaml4.stringify)(cfg), "utf-8");
|
|
25634
26419
|
created.push(vibePath);
|
|
25635
26420
|
}
|
|
25636
26421
|
if (profile === "agent" || profile === "full") {
|
|
25637
|
-
const agentsPath =
|
|
26422
|
+
const agentsPath = resolve8(dir, "AGENTS.md");
|
|
25638
26423
|
if (await pathExists(agentsPath)) {
|
|
25639
26424
|
skipped2.push(agentsPath);
|
|
25640
26425
|
} else {
|
|
25641
|
-
await
|
|
26426
|
+
await writeFile8(agentsPath, buildProjectAgentsMd(name), "utf-8");
|
|
25642
26427
|
created.push(agentsPath);
|
|
25643
26428
|
}
|
|
25644
|
-
const claudePath =
|
|
26429
|
+
const claudePath = resolve8(dir, "CLAUDE.md");
|
|
25645
26430
|
if (await pathExists(claudePath)) {
|
|
25646
26431
|
const existing = await readFile6(claudePath, "utf-8");
|
|
25647
26432
|
if (existing.includes("@AGENTS.md")) {
|
|
25648
26433
|
skipped2.push(claudePath);
|
|
25649
26434
|
} else {
|
|
25650
|
-
await
|
|
26435
|
+
await writeFile8(claudePath, `@AGENTS.md
|
|
25651
26436
|
|
|
25652
26437
|
${existing}`, "utf-8");
|
|
25653
26438
|
merged.push(claudePath);
|
|
25654
26439
|
}
|
|
25655
26440
|
} else {
|
|
25656
|
-
await
|
|
26441
|
+
await writeFile8(claudePath, buildProjectClaudeMd(name), "utf-8");
|
|
25657
26442
|
created.push(claudePath);
|
|
25658
26443
|
}
|
|
25659
26444
|
}
|
|
25660
|
-
const designPath =
|
|
26445
|
+
const designPath = resolve8(dir, "DESIGN.md");
|
|
25661
26446
|
if (await pathExists(designPath)) {
|
|
25662
26447
|
skipped2.push(designPath);
|
|
25663
26448
|
} else {
|
|
25664
|
-
await
|
|
26449
|
+
await writeFile8(designPath, buildDesignMd({ name, style: opts.visualStyle }), "utf-8");
|
|
25665
26450
|
created.push(designPath);
|
|
25666
26451
|
}
|
|
25667
|
-
const storyboardPath =
|
|
26452
|
+
const storyboardPath = resolve8(dir, "STORYBOARD.md");
|
|
25668
26453
|
if (await pathExists(storyboardPath)) {
|
|
25669
26454
|
skipped2.push(storyboardPath);
|
|
25670
26455
|
} else {
|
|
25671
|
-
await
|
|
26456
|
+
await writeFile8(storyboardPath, buildStoryboardMd(name, duration), "utf-8");
|
|
25672
26457
|
created.push(storyboardPath);
|
|
25673
26458
|
}
|
|
25674
|
-
const gitignorePath =
|
|
26459
|
+
const gitignorePath = resolve8(dir, ".gitignore");
|
|
25675
26460
|
if (await pathExists(gitignorePath)) {
|
|
25676
26461
|
skipped2.push(gitignorePath);
|
|
25677
26462
|
} else {
|
|
25678
|
-
await
|
|
26463
|
+
await writeFile8(gitignorePath, buildSceneGitignore(), "utf-8");
|
|
25679
26464
|
created.push(gitignorePath);
|
|
25680
26465
|
}
|
|
25681
26466
|
return { created, skipped: skipped2, merged, groups: describeSceneScaffold({ dir, profile }) };
|
|
@@ -28714,10 +29499,22 @@ var init_esm = __esm({
|
|
|
28714
29499
|
|
|
28715
29500
|
// ../cli/src/commands/_shared/tts-resolve.ts
|
|
28716
29501
|
async function resolveTtsProvider(preferred = "auto") {
|
|
28717
|
-
|
|
29502
|
+
let choice = preferred;
|
|
29503
|
+
if (choice === "auto") {
|
|
29504
|
+
if (await getConfiguredApiKey("ELEVENLABS_API_KEY")) {
|
|
29505
|
+
choice = "elevenlabs";
|
|
29506
|
+
} else if (await getConfiguredApiKey("OPENAI_API_KEY")) {
|
|
29507
|
+
choice = "openai";
|
|
29508
|
+
} else {
|
|
29509
|
+
choice = "kokoro";
|
|
29510
|
+
}
|
|
29511
|
+
}
|
|
28718
29512
|
if (choice === "elevenlabs") {
|
|
28719
29513
|
return buildElevenLabs();
|
|
28720
29514
|
}
|
|
29515
|
+
if (choice === "openai") {
|
|
29516
|
+
return buildOpenAi();
|
|
29517
|
+
}
|
|
28721
29518
|
return buildKokoro();
|
|
28722
29519
|
}
|
|
28723
29520
|
async function buildElevenLabs() {
|
|
@@ -28733,6 +29530,19 @@ async function buildElevenLabs() {
|
|
|
28733
29530
|
});
|
|
28734
29531
|
return { provider: "elevenlabs", audioExtension: "mp3", call };
|
|
28735
29532
|
}
|
|
29533
|
+
async function buildOpenAi() {
|
|
29534
|
+
const key2 = await getApiKey("OPENAI_API_KEY", "OpenAI");
|
|
29535
|
+
if (!key2) {
|
|
29536
|
+
throw new TtsKeyMissingError("openai");
|
|
29537
|
+
}
|
|
29538
|
+
const provider = new OpenAiTtsProvider();
|
|
29539
|
+
await provider.initialize({ apiKey: key2 });
|
|
29540
|
+
const call = async (text, opts) => provider.textToSpeech(text, {
|
|
29541
|
+
voice: opts?.voice,
|
|
29542
|
+
speed: opts?.speed
|
|
29543
|
+
});
|
|
29544
|
+
return { provider: "openai", audioExtension: "mp3", call };
|
|
29545
|
+
}
|
|
28736
29546
|
async function buildKokoro() {
|
|
28737
29547
|
const provider = new KokoroProvider();
|
|
28738
29548
|
await provider.initialize({});
|
|
@@ -28745,11 +29555,11 @@ async function buildKokoro() {
|
|
|
28745
29555
|
}
|
|
28746
29556
|
function parseTtsProviderName(value) {
|
|
28747
29557
|
if (!value) return "auto";
|
|
28748
|
-
if (value === "auto" || value === "elevenlabs" || value === "kokoro") {
|
|
29558
|
+
if (value === "auto" || value === "elevenlabs" || value === "openai" || value === "kokoro") {
|
|
28749
29559
|
return value;
|
|
28750
29560
|
}
|
|
28751
29561
|
throw new Error(
|
|
28752
|
-
`Invalid --tts: ${value}. Valid: auto, elevenlabs, kokoro.`
|
|
29562
|
+
`Invalid --tts: ${value}. Valid: auto, elevenlabs, openai, kokoro.`
|
|
28753
29563
|
);
|
|
28754
29564
|
}
|
|
28755
29565
|
var TtsKeyMissingError;
|
|
@@ -28761,7 +29571,7 @@ var init_tts_resolve = __esm({
|
|
|
28761
29571
|
TtsKeyMissingError = class extends Error {
|
|
28762
29572
|
constructor(provider) {
|
|
28763
29573
|
super(
|
|
28764
|
-
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
29574
|
+
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : provider === "openai" ? "OpenAI API key required (OPENAI_API_KEY). Run 'vibe setup', set OPENAI_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
28765
29575
|
);
|
|
28766
29576
|
this.provider = provider;
|
|
28767
29577
|
this.name = "TtsKeyMissingError";
|
|
@@ -32900,7 +33710,7 @@ var require_util = __commonJS({
|
|
|
32900
33710
|
return path14;
|
|
32901
33711
|
});
|
|
32902
33712
|
exports.normalize = normalize3;
|
|
32903
|
-
function
|
|
33713
|
+
function join44(aRoot, aPath) {
|
|
32904
33714
|
if (aRoot === "") {
|
|
32905
33715
|
aRoot = ".";
|
|
32906
33716
|
}
|
|
@@ -32932,7 +33742,7 @@ var require_util = __commonJS({
|
|
|
32932
33742
|
}
|
|
32933
33743
|
return joined;
|
|
32934
33744
|
}
|
|
32935
|
-
exports.join =
|
|
33745
|
+
exports.join = join44;
|
|
32936
33746
|
exports.isAbsolute = function(aPath) {
|
|
32937
33747
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
32938
33748
|
};
|
|
@@ -33146,7 +33956,7 @@ var require_util = __commonJS({
|
|
|
33146
33956
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
33147
33957
|
}
|
|
33148
33958
|
}
|
|
33149
|
-
sourceURL =
|
|
33959
|
+
sourceURL = join44(urlGenerate(parsed), sourceURL);
|
|
33150
33960
|
}
|
|
33151
33961
|
return normalize3(sourceURL);
|
|
33152
33962
|
}
|
|
@@ -34586,8 +35396,8 @@ var require_source_map = __commonJS({
|
|
|
34586
35396
|
var require_previous_map = __commonJS({
|
|
34587
35397
|
"../../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/previous-map.js"(exports, module) {
|
|
34588
35398
|
"use strict";
|
|
34589
|
-
var { existsSync: existsSync67, readFileSync:
|
|
34590
|
-
var { dirname: dirname33, join:
|
|
35399
|
+
var { existsSync: existsSync67, readFileSync: readFileSync13 } = __require("fs");
|
|
35400
|
+
var { dirname: dirname33, join: join44 } = __require("path");
|
|
34591
35401
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
34592
35402
|
function fromBase64(str2) {
|
|
34593
35403
|
if (Buffer) {
|
|
@@ -34651,7 +35461,7 @@ var require_previous_map = __commonJS({
|
|
|
34651
35461
|
this.root = dirname33(path14);
|
|
34652
35462
|
if (existsSync67(path14)) {
|
|
34653
35463
|
this.mapFile = path14;
|
|
34654
|
-
return
|
|
35464
|
+
return readFileSync13(path14, "utf-8").toString().trim();
|
|
34655
35465
|
}
|
|
34656
35466
|
}
|
|
34657
35467
|
loadMap(file, prev) {
|
|
@@ -34685,7 +35495,7 @@ var require_previous_map = __commonJS({
|
|
|
34685
35495
|
return this.decodeInline(this.annotation);
|
|
34686
35496
|
} else if (this.annotation) {
|
|
34687
35497
|
let map3 = this.annotation;
|
|
34688
|
-
if (file) map3 =
|
|
35498
|
+
if (file) map3 = join44(dirname33(file), map3);
|
|
34689
35499
|
return this.loadFile(map3);
|
|
34690
35500
|
}
|
|
34691
35501
|
}
|
|
@@ -82140,14 +82950,14 @@ var require_re = __commonJS({
|
|
|
82140
82950
|
return value;
|
|
82141
82951
|
};
|
|
82142
82952
|
var createToken = (name, value, isGlobal) => {
|
|
82143
|
-
const
|
|
82953
|
+
const safe2 = makeSafeRegex(value);
|
|
82144
82954
|
const index = R2++;
|
|
82145
82955
|
debug9(name, index, value);
|
|
82146
82956
|
t2[name] = index;
|
|
82147
82957
|
src[index] = value;
|
|
82148
|
-
safeSrc[index] =
|
|
82958
|
+
safeSrc[index] = safe2;
|
|
82149
82959
|
re2[index] = new RegExp(value, isGlobal ? "g" : void 0);
|
|
82150
|
-
safeRe[index] = new RegExp(
|
|
82960
|
+
safeRe[index] = new RegExp(safe2, isGlobal ? "g" : void 0);
|
|
82151
82961
|
};
|
|
82152
82962
|
createToken("NUMERICIDENTIFIER", "0|[1-9]\\d*");
|
|
82153
82963
|
createToken("NUMERICIDENTIFIERLOOSE", "\\d+");
|
|
@@ -93314,7 +94124,7 @@ var require_util3 = __commonJS({
|
|
|
93314
94124
|
return path14;
|
|
93315
94125
|
}
|
|
93316
94126
|
exports.normalize = normalize3;
|
|
93317
|
-
function
|
|
94127
|
+
function join44(aRoot, aPath) {
|
|
93318
94128
|
if (aRoot === "") {
|
|
93319
94129
|
aRoot = ".";
|
|
93320
94130
|
}
|
|
@@ -93346,7 +94156,7 @@ var require_util3 = __commonJS({
|
|
|
93346
94156
|
}
|
|
93347
94157
|
return joined;
|
|
93348
94158
|
}
|
|
93349
|
-
exports.join =
|
|
94159
|
+
exports.join = join44;
|
|
93350
94160
|
exports.isAbsolute = function(aPath) {
|
|
93351
94161
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
93352
94162
|
};
|
|
@@ -93519,7 +94329,7 @@ var require_util3 = __commonJS({
|
|
|
93519
94329
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
93520
94330
|
}
|
|
93521
94331
|
}
|
|
93522
|
-
sourceURL =
|
|
94332
|
+
sourceURL = join44(urlGenerate(parsed), sourceURL);
|
|
93523
94333
|
}
|
|
93524
94334
|
return normalize3(sourceURL);
|
|
93525
94335
|
}
|
|
@@ -95321,7 +96131,7 @@ var require_escodegen = __commonJS({
|
|
|
95321
96131
|
function noEmptySpace() {
|
|
95322
96132
|
return space ? space : " ";
|
|
95323
96133
|
}
|
|
95324
|
-
function
|
|
96134
|
+
function join44(left3, right3) {
|
|
95325
96135
|
var leftSource, rightSource, leftCharCode, rightCharCode;
|
|
95326
96136
|
leftSource = toSourceNodeWhenNeeded(left3).toString();
|
|
95327
96137
|
if (leftSource.length === 0) {
|
|
@@ -95652,8 +96462,8 @@ var require_escodegen = __commonJS({
|
|
|
95652
96462
|
} else {
|
|
95653
96463
|
result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
|
|
95654
96464
|
}
|
|
95655
|
-
result =
|
|
95656
|
-
result = [
|
|
96465
|
+
result = join44(result, operator);
|
|
96466
|
+
result = [join44(
|
|
95657
96467
|
result,
|
|
95658
96468
|
that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
|
|
95659
96469
|
), ")"];
|
|
@@ -95796,11 +96606,11 @@ var require_escodegen = __commonJS({
|
|
|
95796
96606
|
var result, fragment;
|
|
95797
96607
|
result = ["class"];
|
|
95798
96608
|
if (stmt.id) {
|
|
95799
|
-
result =
|
|
96609
|
+
result = join44(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
|
|
95800
96610
|
}
|
|
95801
96611
|
if (stmt.superClass) {
|
|
95802
|
-
fragment =
|
|
95803
|
-
result =
|
|
96612
|
+
fragment = join44("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
|
|
96613
|
+
result = join44(result, fragment);
|
|
95804
96614
|
}
|
|
95805
96615
|
result.push(space);
|
|
95806
96616
|
result.push(this.generateStatement(stmt.body, S_TFFT));
|
|
@@ -95813,9 +96623,9 @@ var require_escodegen = __commonJS({
|
|
|
95813
96623
|
return escapeDirective(stmt.directive) + this.semicolon(flags);
|
|
95814
96624
|
},
|
|
95815
96625
|
DoWhileStatement: function(stmt, flags) {
|
|
95816
|
-
var result =
|
|
96626
|
+
var result = join44("do", this.maybeBlock(stmt.body, S_TFFF));
|
|
95817
96627
|
result = this.maybeBlockSuffix(stmt.body, result);
|
|
95818
|
-
return
|
|
96628
|
+
return join44(result, [
|
|
95819
96629
|
"while" + space + "(",
|
|
95820
96630
|
this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
|
|
95821
96631
|
")" + this.semicolon(flags)
|
|
@@ -95851,11 +96661,11 @@ var require_escodegen = __commonJS({
|
|
|
95851
96661
|
ExportDefaultDeclaration: function(stmt, flags) {
|
|
95852
96662
|
var result = ["export"], bodyFlags;
|
|
95853
96663
|
bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
|
|
95854
|
-
result =
|
|
96664
|
+
result = join44(result, "default");
|
|
95855
96665
|
if (isStatement(stmt.declaration)) {
|
|
95856
|
-
result =
|
|
96666
|
+
result = join44(result, this.generateStatement(stmt.declaration, bodyFlags));
|
|
95857
96667
|
} else {
|
|
95858
|
-
result =
|
|
96668
|
+
result = join44(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
|
|
95859
96669
|
}
|
|
95860
96670
|
return result;
|
|
95861
96671
|
},
|
|
@@ -95863,15 +96673,15 @@ var require_escodegen = __commonJS({
|
|
|
95863
96673
|
var result = ["export"], bodyFlags, that = this;
|
|
95864
96674
|
bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
|
|
95865
96675
|
if (stmt.declaration) {
|
|
95866
|
-
return
|
|
96676
|
+
return join44(result, this.generateStatement(stmt.declaration, bodyFlags));
|
|
95867
96677
|
}
|
|
95868
96678
|
if (stmt.specifiers) {
|
|
95869
96679
|
if (stmt.specifiers.length === 0) {
|
|
95870
|
-
result =
|
|
96680
|
+
result = join44(result, "{" + space + "}");
|
|
95871
96681
|
} else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
|
|
95872
|
-
result =
|
|
96682
|
+
result = join44(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
|
|
95873
96683
|
} else {
|
|
95874
|
-
result =
|
|
96684
|
+
result = join44(result, "{");
|
|
95875
96685
|
withIndent(function(indent2) {
|
|
95876
96686
|
var i2, iz;
|
|
95877
96687
|
result.push(newline);
|
|
@@ -95889,7 +96699,7 @@ var require_escodegen = __commonJS({
|
|
|
95889
96699
|
result.push(base + "}");
|
|
95890
96700
|
}
|
|
95891
96701
|
if (stmt.source) {
|
|
95892
|
-
result =
|
|
96702
|
+
result = join44(result, [
|
|
95893
96703
|
"from" + space,
|
|
95894
96704
|
// ModuleSpecifier
|
|
95895
96705
|
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
|
|
@@ -95977,7 +96787,7 @@ var require_escodegen = __commonJS({
|
|
|
95977
96787
|
];
|
|
95978
96788
|
cursor = 0;
|
|
95979
96789
|
if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
|
|
95980
|
-
result =
|
|
96790
|
+
result = join44(result, [
|
|
95981
96791
|
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
|
|
95982
96792
|
]);
|
|
95983
96793
|
++cursor;
|
|
@@ -95987,7 +96797,7 @@ var require_escodegen = __commonJS({
|
|
|
95987
96797
|
result.push(",");
|
|
95988
96798
|
}
|
|
95989
96799
|
if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
|
|
95990
|
-
result =
|
|
96800
|
+
result = join44(result, [
|
|
95991
96801
|
space,
|
|
95992
96802
|
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
|
|
95993
96803
|
]);
|
|
@@ -96016,7 +96826,7 @@ var require_escodegen = __commonJS({
|
|
|
96016
96826
|
}
|
|
96017
96827
|
}
|
|
96018
96828
|
}
|
|
96019
|
-
result =
|
|
96829
|
+
result = join44(result, [
|
|
96020
96830
|
"from" + space,
|
|
96021
96831
|
// ModuleSpecifier
|
|
96022
96832
|
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
|
|
@@ -96070,7 +96880,7 @@ var require_escodegen = __commonJS({
|
|
|
96070
96880
|
return result;
|
|
96071
96881
|
},
|
|
96072
96882
|
ThrowStatement: function(stmt, flags) {
|
|
96073
|
-
return [
|
|
96883
|
+
return [join44(
|
|
96074
96884
|
"throw",
|
|
96075
96885
|
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
|
|
96076
96886
|
), this.semicolon(flags)];
|
|
@@ -96081,7 +96891,7 @@ var require_escodegen = __commonJS({
|
|
|
96081
96891
|
result = this.maybeBlockSuffix(stmt.block, result);
|
|
96082
96892
|
if (stmt.handlers) {
|
|
96083
96893
|
for (i2 = 0, iz = stmt.handlers.length; i2 < iz; ++i2) {
|
|
96084
|
-
result =
|
|
96894
|
+
result = join44(result, this.generateStatement(stmt.handlers[i2], S_TFFF));
|
|
96085
96895
|
if (stmt.finalizer || i2 + 1 !== iz) {
|
|
96086
96896
|
result = this.maybeBlockSuffix(stmt.handlers[i2].body, result);
|
|
96087
96897
|
}
|
|
@@ -96089,7 +96899,7 @@ var require_escodegen = __commonJS({
|
|
|
96089
96899
|
} else {
|
|
96090
96900
|
guardedHandlers = stmt.guardedHandlers || [];
|
|
96091
96901
|
for (i2 = 0, iz = guardedHandlers.length; i2 < iz; ++i2) {
|
|
96092
|
-
result =
|
|
96902
|
+
result = join44(result, this.generateStatement(guardedHandlers[i2], S_TFFF));
|
|
96093
96903
|
if (stmt.finalizer || i2 + 1 !== iz) {
|
|
96094
96904
|
result = this.maybeBlockSuffix(guardedHandlers[i2].body, result);
|
|
96095
96905
|
}
|
|
@@ -96097,13 +96907,13 @@ var require_escodegen = __commonJS({
|
|
|
96097
96907
|
if (stmt.handler) {
|
|
96098
96908
|
if (Array.isArray(stmt.handler)) {
|
|
96099
96909
|
for (i2 = 0, iz = stmt.handler.length; i2 < iz; ++i2) {
|
|
96100
|
-
result =
|
|
96910
|
+
result = join44(result, this.generateStatement(stmt.handler[i2], S_TFFF));
|
|
96101
96911
|
if (stmt.finalizer || i2 + 1 !== iz) {
|
|
96102
96912
|
result = this.maybeBlockSuffix(stmt.handler[i2].body, result);
|
|
96103
96913
|
}
|
|
96104
96914
|
}
|
|
96105
96915
|
} else {
|
|
96106
|
-
result =
|
|
96916
|
+
result = join44(result, this.generateStatement(stmt.handler, S_TFFF));
|
|
96107
96917
|
if (stmt.finalizer) {
|
|
96108
96918
|
result = this.maybeBlockSuffix(stmt.handler.body, result);
|
|
96109
96919
|
}
|
|
@@ -96111,7 +96921,7 @@ var require_escodegen = __commonJS({
|
|
|
96111
96921
|
}
|
|
96112
96922
|
}
|
|
96113
96923
|
if (stmt.finalizer) {
|
|
96114
|
-
result =
|
|
96924
|
+
result = join44(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
|
|
96115
96925
|
}
|
|
96116
96926
|
return result;
|
|
96117
96927
|
},
|
|
@@ -96145,7 +96955,7 @@ var require_escodegen = __commonJS({
|
|
|
96145
96955
|
withIndent(function() {
|
|
96146
96956
|
if (stmt.test) {
|
|
96147
96957
|
result = [
|
|
96148
|
-
|
|
96958
|
+
join44("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
|
|
96149
96959
|
":"
|
|
96150
96960
|
];
|
|
96151
96961
|
} else {
|
|
@@ -96193,9 +97003,9 @@ var require_escodegen = __commonJS({
|
|
|
96193
97003
|
result.push(this.maybeBlock(stmt.consequent, S_TFFF));
|
|
96194
97004
|
result = this.maybeBlockSuffix(stmt.consequent, result);
|
|
96195
97005
|
if (stmt.alternate.type === Syntax.IfStatement) {
|
|
96196
|
-
result =
|
|
97006
|
+
result = join44(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
|
|
96197
97007
|
} else {
|
|
96198
|
-
result =
|
|
97008
|
+
result = join44(result, join44("else", this.maybeBlock(stmt.alternate, bodyFlags)));
|
|
96199
97009
|
}
|
|
96200
97010
|
} else {
|
|
96201
97011
|
result.push(this.maybeBlock(stmt.consequent, bodyFlags));
|
|
@@ -96296,7 +97106,7 @@ var require_escodegen = __commonJS({
|
|
|
96296
97106
|
},
|
|
96297
97107
|
ReturnStatement: function(stmt, flags) {
|
|
96298
97108
|
if (stmt.argument) {
|
|
96299
|
-
return [
|
|
97109
|
+
return [join44(
|
|
96300
97110
|
"return",
|
|
96301
97111
|
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
|
|
96302
97112
|
), this.semicolon(flags)];
|
|
@@ -96385,14 +97195,14 @@ var require_escodegen = __commonJS({
|
|
|
96385
97195
|
if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
|
|
96386
97196
|
result = [fragment, noEmptySpace(), expr.operator];
|
|
96387
97197
|
} else {
|
|
96388
|
-
result =
|
|
97198
|
+
result = join44(fragment, expr.operator);
|
|
96389
97199
|
}
|
|
96390
97200
|
fragment = this.generateExpression(expr.right, rightPrecedence, flags);
|
|
96391
97201
|
if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
|
|
96392
97202
|
result.push(noEmptySpace());
|
|
96393
97203
|
result.push(fragment);
|
|
96394
97204
|
} else {
|
|
96395
|
-
result =
|
|
97205
|
+
result = join44(result, fragment);
|
|
96396
97206
|
}
|
|
96397
97207
|
if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
|
|
96398
97208
|
return ["(", result, ")"];
|
|
@@ -96432,7 +97242,7 @@ var require_escodegen = __commonJS({
|
|
|
96432
97242
|
var result, length, i2, iz, itemFlags;
|
|
96433
97243
|
length = expr["arguments"].length;
|
|
96434
97244
|
itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
|
|
96435
|
-
result =
|
|
97245
|
+
result = join44(
|
|
96436
97246
|
"new",
|
|
96437
97247
|
this.generateExpression(expr.callee, Precedence.New, itemFlags)
|
|
96438
97248
|
);
|
|
@@ -96482,11 +97292,11 @@ var require_escodegen = __commonJS({
|
|
|
96482
97292
|
var result, fragment, rightCharCode, leftSource, leftCharCode;
|
|
96483
97293
|
fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
|
|
96484
97294
|
if (space === "") {
|
|
96485
|
-
result =
|
|
97295
|
+
result = join44(expr.operator, fragment);
|
|
96486
97296
|
} else {
|
|
96487
97297
|
result = [expr.operator];
|
|
96488
97298
|
if (expr.operator.length > 2) {
|
|
96489
|
-
result =
|
|
97299
|
+
result = join44(result, fragment);
|
|
96490
97300
|
} else {
|
|
96491
97301
|
leftSource = toSourceNodeWhenNeeded(result).toString();
|
|
96492
97302
|
leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
|
|
@@ -96509,7 +97319,7 @@ var require_escodegen = __commonJS({
|
|
|
96509
97319
|
result = "yield";
|
|
96510
97320
|
}
|
|
96511
97321
|
if (expr.argument) {
|
|
96512
|
-
result =
|
|
97322
|
+
result = join44(
|
|
96513
97323
|
result,
|
|
96514
97324
|
this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
|
|
96515
97325
|
);
|
|
@@ -96517,7 +97327,7 @@ var require_escodegen = __commonJS({
|
|
|
96517
97327
|
return parenthesize(result, Precedence.Yield, precedence);
|
|
96518
97328
|
},
|
|
96519
97329
|
AwaitExpression: function(expr, precedence, flags) {
|
|
96520
|
-
var result =
|
|
97330
|
+
var result = join44(
|
|
96521
97331
|
expr.all ? "await*" : "await",
|
|
96522
97332
|
this.generateExpression(expr.argument, Precedence.Await, E_TTT)
|
|
96523
97333
|
);
|
|
@@ -96600,11 +97410,11 @@ var require_escodegen = __commonJS({
|
|
|
96600
97410
|
var result, fragment;
|
|
96601
97411
|
result = ["class"];
|
|
96602
97412
|
if (expr.id) {
|
|
96603
|
-
result =
|
|
97413
|
+
result = join44(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
|
|
96604
97414
|
}
|
|
96605
97415
|
if (expr.superClass) {
|
|
96606
|
-
fragment =
|
|
96607
|
-
result =
|
|
97416
|
+
fragment = join44("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
|
|
97417
|
+
result = join44(result, fragment);
|
|
96608
97418
|
}
|
|
96609
97419
|
result.push(space);
|
|
96610
97420
|
result.push(this.generateStatement(expr.body, S_TFFT));
|
|
@@ -96619,7 +97429,7 @@ var require_escodegen = __commonJS({
|
|
|
96619
97429
|
}
|
|
96620
97430
|
if (expr.kind === "get" || expr.kind === "set") {
|
|
96621
97431
|
fragment = [
|
|
96622
|
-
|
|
97432
|
+
join44(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
|
|
96623
97433
|
this.generateFunctionBody(expr.value)
|
|
96624
97434
|
];
|
|
96625
97435
|
} else {
|
|
@@ -96629,7 +97439,7 @@ var require_escodegen = __commonJS({
|
|
|
96629
97439
|
this.generateFunctionBody(expr.value)
|
|
96630
97440
|
];
|
|
96631
97441
|
}
|
|
96632
|
-
return
|
|
97442
|
+
return join44(result, fragment);
|
|
96633
97443
|
},
|
|
96634
97444
|
Property: function(expr, precedence, flags) {
|
|
96635
97445
|
if (expr.kind === "get" || expr.kind === "set") {
|
|
@@ -96824,7 +97634,7 @@ var require_escodegen = __commonJS({
|
|
|
96824
97634
|
for (i2 = 0, iz = expr.blocks.length; i2 < iz; ++i2) {
|
|
96825
97635
|
fragment = that.generateExpression(expr.blocks[i2], Precedence.Sequence, E_TTT);
|
|
96826
97636
|
if (i2 > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
|
|
96827
|
-
result =
|
|
97637
|
+
result = join44(result, fragment);
|
|
96828
97638
|
} else {
|
|
96829
97639
|
result.push(fragment);
|
|
96830
97640
|
}
|
|
@@ -96832,13 +97642,13 @@ var require_escodegen = __commonJS({
|
|
|
96832
97642
|
});
|
|
96833
97643
|
}
|
|
96834
97644
|
if (expr.filter) {
|
|
96835
|
-
result =
|
|
97645
|
+
result = join44(result, "if" + space);
|
|
96836
97646
|
fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
|
|
96837
|
-
result =
|
|
97647
|
+
result = join44(result, ["(", fragment, ")"]);
|
|
96838
97648
|
}
|
|
96839
97649
|
if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
|
|
96840
97650
|
fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
|
|
96841
|
-
result =
|
|
97651
|
+
result = join44(result, fragment);
|
|
96842
97652
|
}
|
|
96843
97653
|
result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
|
|
96844
97654
|
return result;
|
|
@@ -96854,8 +97664,8 @@ var require_escodegen = __commonJS({
|
|
|
96854
97664
|
} else {
|
|
96855
97665
|
fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
|
|
96856
97666
|
}
|
|
96857
|
-
fragment =
|
|
96858
|
-
fragment =
|
|
97667
|
+
fragment = join44(fragment, expr.of ? "of" : "in");
|
|
97668
|
+
fragment = join44(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
|
|
96859
97669
|
return ["for" + space + "(", fragment, ")"];
|
|
96860
97670
|
},
|
|
96861
97671
|
SpreadElement: function(expr, precedence, flags) {
|
|
@@ -118146,17 +118956,17 @@ var init_cliui = __esm({
|
|
|
118146
118956
|
});
|
|
118147
118957
|
|
|
118148
118958
|
// ../../node_modules/.pnpm/escalade@3.2.0/node_modules/escalade/sync/index.mjs
|
|
118149
|
-
import { dirname as dirname4, resolve as
|
|
118959
|
+
import { dirname as dirname4, resolve as resolve10 } from "path";
|
|
118150
118960
|
import { readdirSync, statSync as statSync2 } from "fs";
|
|
118151
118961
|
function sync_default(start, callback) {
|
|
118152
|
-
let dir =
|
|
118962
|
+
let dir = resolve10(".", start);
|
|
118153
118963
|
let tmp, stats = statSync2(dir);
|
|
118154
118964
|
if (!stats.isDirectory()) {
|
|
118155
118965
|
dir = dirname4(dir);
|
|
118156
118966
|
}
|
|
118157
118967
|
while (true) {
|
|
118158
118968
|
tmp = callback(dir, readdirSync(dir));
|
|
118159
|
-
if (tmp) return
|
|
118969
|
+
if (tmp) return resolve10(dir, tmp);
|
|
118160
118970
|
dir = dirname4(tmp = dir);
|
|
118161
118971
|
if (tmp === dir) break;
|
|
118162
118972
|
}
|
|
@@ -119122,7 +119932,7 @@ var init_yargs_parser = __esm({
|
|
|
119122
119932
|
|
|
119123
119933
|
// ../../node_modules/.pnpm/yargs-parser@21.1.1/node_modules/yargs-parser/build/lib/index.js
|
|
119124
119934
|
import { format } from "util";
|
|
119125
|
-
import { normalize, resolve as
|
|
119935
|
+
import { normalize, resolve as resolve11 } from "path";
|
|
119126
119936
|
import { readFileSync as readFileSync3 } from "fs";
|
|
119127
119937
|
var _a3, _b, _c, minNodeVersion, nodeVersion, env2, parser, yargsParser, lib_default;
|
|
119128
119938
|
var init_lib2 = __esm({
|
|
@@ -119145,7 +119955,7 @@ var init_lib2 = __esm({
|
|
|
119145
119955
|
},
|
|
119146
119956
|
format,
|
|
119147
119957
|
normalize,
|
|
119148
|
-
resolve:
|
|
119958
|
+
resolve: resolve11,
|
|
119149
119959
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
119150
119960
|
// we can exercise all the lines below:
|
|
119151
119961
|
require: (path14) => {
|
|
@@ -119212,19 +120022,19 @@ var init_yerror = __esm({
|
|
|
119212
120022
|
});
|
|
119213
120023
|
|
|
119214
120024
|
// ../../node_modules/.pnpm/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js
|
|
119215
|
-
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as
|
|
120025
|
+
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile9 } from "fs";
|
|
119216
120026
|
import { format as format2 } from "util";
|
|
119217
|
-
import { resolve as
|
|
120027
|
+
import { resolve as resolve12 } from "path";
|
|
119218
120028
|
var node_default;
|
|
119219
120029
|
var init_node = __esm({
|
|
119220
120030
|
"../../node_modules/.pnpm/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js"() {
|
|
119221
120031
|
node_default = {
|
|
119222
120032
|
fs: {
|
|
119223
120033
|
readFileSync: readFileSync4,
|
|
119224
|
-
writeFile:
|
|
120034
|
+
writeFile: writeFile9
|
|
119225
120035
|
},
|
|
119226
120036
|
format: format2,
|
|
119227
|
-
resolve:
|
|
120037
|
+
resolve: resolve12,
|
|
119228
120038
|
exists: (file) => {
|
|
119229
120039
|
try {
|
|
119230
120040
|
return statSync3(file).isFile();
|
|
@@ -119419,7 +120229,7 @@ import { notStrictEqual, strictEqual } from "assert";
|
|
|
119419
120229
|
import { inspect } from "util";
|
|
119420
120230
|
import { readFileSync as readFileSync5 } from "fs";
|
|
119421
120231
|
import { fileURLToPath } from "url";
|
|
119422
|
-
import { basename as basename3, dirname as dirname5, extname as extname2, relative as relative2, resolve as
|
|
120232
|
+
import { basename as basename3, dirname as dirname5, extname as extname2, relative as relative2, resolve as resolve13 } from "path";
|
|
119423
120233
|
var REQUIRE_ERROR, REQUIRE_DIRECTORY_ERROR, __dirname2, mainFilename, esm_default;
|
|
119424
120234
|
var init_esm2 = __esm({
|
|
119425
120235
|
"../../node_modules/.pnpm/yargs@17.7.2/node_modules/yargs/lib/platform-shims/esm.mjs"() {
|
|
@@ -119460,7 +120270,7 @@ var init_esm2 = __esm({
|
|
|
119460
120270
|
dirname: dirname5,
|
|
119461
120271
|
extname: extname2,
|
|
119462
120272
|
relative: relative2,
|
|
119463
|
-
resolve:
|
|
120273
|
+
resolve: resolve13
|
|
119464
120274
|
},
|
|
119465
120275
|
process: {
|
|
119466
120276
|
argv: () => process.argv,
|
|
@@ -119482,7 +120292,7 @@ var init_esm2 = __esm({
|
|
|
119482
120292
|
return [...str2].length;
|
|
119483
120293
|
},
|
|
119484
120294
|
y18n: y18n_default({
|
|
119485
|
-
directory:
|
|
120295
|
+
directory: resolve13(__dirname2, "../../../locales"),
|
|
119486
120296
|
updateFiles: false
|
|
119487
120297
|
})
|
|
119488
120298
|
};
|
|
@@ -123257,9 +124067,9 @@ async function getConnectionTransport(options) {
|
|
|
123257
124067
|
throw new Error("Could not detect required browser platform");
|
|
123258
124068
|
}
|
|
123259
124069
|
const { convertPuppeteerChannelToBrowsersChannel: convertPuppeteerChannelToBrowsersChannel3 } = await Promise.resolve().then(() => (init_LaunchOptions(), LaunchOptions_exports));
|
|
123260
|
-
const { join:
|
|
124070
|
+
const { join: join44 } = await import("node:path");
|
|
123261
124071
|
const userDataDir = resolveDefaultUserDataDir4(Browser5.CHROME, platform, convertPuppeteerChannelToBrowsersChannel3(options.channel));
|
|
123262
|
-
const portPath =
|
|
124072
|
+
const portPath = join44(userDataDir, "DevToolsActivePort");
|
|
123263
124073
|
try {
|
|
123264
124074
|
const fileContent = await environment.value.fs.promises.readFile(portPath, "ascii");
|
|
123265
124075
|
const [rawPort, rawPath] = fileContent.split("\n").map((line) => {
|
|
@@ -123582,7 +124392,7 @@ var init_PipeTransport = __esm({
|
|
|
123582
124392
|
// ../../node_modules/.pnpm/puppeteer-core@24.41.0/node_modules/puppeteer-core/lib/esm/puppeteer/node/BrowserLauncher.js
|
|
123583
124393
|
import { existsSync as existsSync5 } from "node:fs";
|
|
123584
124394
|
import { tmpdir } from "node:os";
|
|
123585
|
-
import { join as
|
|
124395
|
+
import { join as join5 } from "node:path";
|
|
123586
124396
|
var BrowserLauncher;
|
|
123587
124397
|
var init_BrowserLauncher = __esm({
|
|
123588
124398
|
"../../node_modules/.pnpm/puppeteer-core@24.41.0/node_modules/puppeteer-core/lib/esm/puppeteer/node/BrowserLauncher.js"() {
|
|
@@ -123702,7 +124512,7 @@ var init_BrowserLauncher = __esm({
|
|
|
123702
124512
|
if (logs.includes("Failed to create a ProcessSingleton for your profile directory") || // On Windows we will not get logs due to the singleton process
|
|
123703
124513
|
// handover. See
|
|
123704
124514
|
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/process_singleton_win.cc;l=46;drc=fc7952f0422b5073515a205a04ec9c3a1ae81658
|
|
123705
|
-
process.platform === "win32" && existsSync5(
|
|
124515
|
+
process.platform === "win32" && existsSync5(join5(launchArgs.userDataDir, "lockfile"))) {
|
|
123706
124516
|
throw new Error(`The browser is already running for ${launchArgs.userDataDir}. Use a different \`userDataDir\` or stop the running browser first.`);
|
|
123707
124517
|
}
|
|
123708
124518
|
if (logs.includes("Missing X server") && options.headless === false) {
|
|
@@ -123833,7 +124643,7 @@ var init_BrowserLauncher = __esm({
|
|
|
123833
124643
|
* @internal
|
|
123834
124644
|
*/
|
|
123835
124645
|
getProfilePath() {
|
|
123836
|
-
return
|
|
124646
|
+
return join5(this.puppeteer.configuration.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
|
|
123837
124647
|
}
|
|
123838
124648
|
/**
|
|
123839
124649
|
* @internal
|
|
@@ -292488,7 +293298,7 @@ ${newComment.split("\n").map((c2) => ` * ${c2}`).join("\n")}
|
|
|
292488
293298
|
}
|
|
292489
293299
|
}
|
|
292490
293300
|
return result;
|
|
292491
|
-
function
|
|
293301
|
+
function escapeRegExp5(str2) {
|
|
292492
293302
|
return str2.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
|
|
292493
293303
|
}
|
|
292494
293304
|
function getTodoCommentsRegExp() {
|
|
@@ -292496,7 +293306,7 @@ ${newComment.split("\n").map((c2) => ` * ${c2}`).join("\n")}
|
|
|
292496
293306
|
const multiLineCommentStart = /(?:\/\*+\s*)/.source;
|
|
292497
293307
|
const anyNumberOfSpacesAndAsterisksAtStartOfLine = /(?:^(?:\s|\*)*)/.source;
|
|
292498
293308
|
const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")";
|
|
292499
|
-
const literals = "(?:" + map3(descriptors, (d2) => "(" +
|
|
293309
|
+
const literals = "(?:" + map3(descriptors, (d2) => "(" + escapeRegExp5(d2.text) + ")").join("|") + ")";
|
|
292500
293310
|
const endOfLineOrEndOfComment = /(?:$|\*\/)/.source;
|
|
292501
293311
|
const messageRemainder = /(?:.*?)/.source;
|
|
292502
293312
|
const messagePortion = "(" + literals + messageRemainder + ")";
|
|
@@ -340329,7 +341139,7 @@ var require_dist15 = __commonJS({
|
|
|
340329
341139
|
|
|
340330
341140
|
// ../../node_modules/.pnpm/puppeteer@24.41.0_typescript@5.9.3/node_modules/puppeteer/lib/esm/puppeteer/getConfiguration.js
|
|
340331
341141
|
import { homedir as homedir3 } from "node:os";
|
|
340332
|
-
import { join as
|
|
341142
|
+
import { join as join6 } from "node:path";
|
|
340333
341143
|
function getBooleanEnvVar(name) {
|
|
340334
341144
|
const env4 = process.env[name];
|
|
340335
341145
|
if (env4 === void 0) {
|
|
@@ -340409,7 +341219,7 @@ var init_getConfiguration = __esm({
|
|
|
340409
341219
|
configuration2.firefox = getBrowserSetting("firefox", configuration2, {
|
|
340410
341220
|
skipDownload: true
|
|
340411
341221
|
});
|
|
340412
|
-
configuration2.cacheDirectory = process.env["PUPPETEER_CACHE_DIR"] ?? configuration2.cacheDirectory ??
|
|
341222
|
+
configuration2.cacheDirectory = process.env["PUPPETEER_CACHE_DIR"] ?? configuration2.cacheDirectory ?? join6(homedir3(), ".cache", "puppeteer");
|
|
340413
341223
|
configuration2.temporaryDirectory = process.env["PUPPETEER_TMP_DIR"] ?? configuration2.temporaryDirectory;
|
|
340414
341224
|
configuration2.experiments ??= {};
|
|
340415
341225
|
return configuration2;
|
|
@@ -340737,7 +341547,7 @@ import { readdirSync as readdirSync2, statSync as statSync4 } from "fs";
|
|
|
340737
341547
|
import { format as format3 } from "util";
|
|
340738
341548
|
import { normalize as normalize2, resolve as resolve32 } from "path";
|
|
340739
341549
|
import { readFileSync as readFileSync22 } from "fs";
|
|
340740
|
-
import { readFileSync as readFileSync32, statSync as statSync22, writeFile as
|
|
341550
|
+
import { readFileSync as readFileSync32, statSync as statSync22, writeFile as writeFile10 } from "fs";
|
|
340741
341551
|
import { format as format22 } from "util";
|
|
340742
341552
|
import { resolve as resolve42 } from "path";
|
|
340743
341553
|
import { notStrictEqual as notStrictEqual2, strictEqual as strictEqual2 } from "assert";
|
|
@@ -340795,7 +341605,7 @@ import { join as join8 } from "path";
|
|
|
340795
341605
|
import { spawn as spawn7 } from "child_process";
|
|
340796
341606
|
import { createWriteStream as createWriteStream22, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
340797
341607
|
import { createHash as createHash3 } from "crypto";
|
|
340798
|
-
import { join as
|
|
341608
|
+
import { join as join72, extname as extname22 } from "path";
|
|
340799
341609
|
import { Readable } from "stream";
|
|
340800
341610
|
import { finished } from "stream/promises";
|
|
340801
341611
|
import { promises as fs72 } from "fs";
|
|
@@ -350883,7 +351693,7 @@ async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
|
350883
351693
|
mkdirSync4(destDir, { recursive: true });
|
|
350884
351694
|
}
|
|
350885
351695
|
const filename = getFilenameFromUrl(url);
|
|
350886
|
-
const localPath =
|
|
351696
|
+
const localPath = join72(destDir, filename);
|
|
350887
351697
|
if (existsSync7(localPath)) {
|
|
350888
351698
|
downloadPathCache.set(url, localPath);
|
|
350889
351699
|
return localPath;
|
|
@@ -398898,14 +399708,14 @@ ${sourceUrlComment}
|
|
|
398898
399708
|
return value;
|
|
398899
399709
|
};
|
|
398900
399710
|
var createToken = (name, value, isGlobal) => {
|
|
398901
|
-
const
|
|
399711
|
+
const safe2 = makeSafeRegex(value);
|
|
398902
399712
|
const index = R2++;
|
|
398903
399713
|
debug62(name, index, value);
|
|
398904
399714
|
t2[name] = index;
|
|
398905
399715
|
src[index] = value;
|
|
398906
|
-
safeSrc[index] =
|
|
399716
|
+
safeSrc[index] = safe2;
|
|
398907
399717
|
re2[index] = new RegExp(value, isGlobal ? "g" : void 0);
|
|
398908
|
-
safeRe[index] = new RegExp(
|
|
399718
|
+
safeRe[index] = new RegExp(safe2, isGlobal ? "g" : void 0);
|
|
398909
399719
|
};
|
|
398910
399720
|
createToken("NUMERICIDENTIFIER", "0|[1-9]\\d*");
|
|
398911
399721
|
createToken("NUMERICIDENTIFIERLOOSE", "\\d+");
|
|
@@ -433132,7 +433942,7 @@ If you think this is a bug, please report it on the Puppeteer issue tracker.`;
|
|
|
433132
433942
|
node_default2 = {
|
|
433133
433943
|
fs: {
|
|
433134
433944
|
readFileSync: readFileSync32,
|
|
433135
|
-
writeFile:
|
|
433945
|
+
writeFile: writeFile10
|
|
433136
433946
|
},
|
|
433137
433947
|
format: format22,
|
|
433138
433948
|
resolve: resolve42,
|
|
@@ -450055,14 +450865,14 @@ ${right22.raw}`)
|
|
|
450055
450865
|
});
|
|
450056
450866
|
|
|
450057
450867
|
// ../cli/src/commands/_shared/scene-lint.ts
|
|
450058
|
-
import { readdir as readdir4, readFile as readFile7, writeFile as
|
|
450868
|
+
import { readdir as readdir4, readFile as readFile7, writeFile as writeFile11, stat as stat2 } from "node:fs/promises";
|
|
450059
450869
|
import { existsSync as existsSync18 } from "node:fs";
|
|
450060
|
-
import { resolve as
|
|
450870
|
+
import { resolve as resolve15, relative as relative4, join as join18 } from "node:path";
|
|
450061
450871
|
async function discoverSceneFiles(opts) {
|
|
450062
|
-
const projectDir =
|
|
450063
|
-
const rootAbs =
|
|
450872
|
+
const projectDir = resolve15(opts.projectDir);
|
|
450873
|
+
const rootAbs = resolve15(projectDir, opts.rootRel ?? "index.html");
|
|
450064
450874
|
const root2 = existsSync18(rootAbs) ? rootAbs : null;
|
|
450065
|
-
const compsDir =
|
|
450875
|
+
const compsDir = resolve15(projectDir, "compositions");
|
|
450066
450876
|
const subs = [];
|
|
450067
450877
|
if (existsSync18(compsDir)) {
|
|
450068
450878
|
await collectHtmlRecursive(compsDir, subs);
|
|
@@ -450148,7 +450958,7 @@ function addClipClassToTimedElements(html) {
|
|
|
450148
450958
|
});
|
|
450149
450959
|
}
|
|
450150
450960
|
async function runProjectLint(opts) {
|
|
450151
|
-
const projectDir =
|
|
450961
|
+
const projectDir = resolve15(opts.projectDir);
|
|
450152
450962
|
const { root: root2, subs } = await discoverSceneFiles({ projectDir, rootRel: opts.rootRel });
|
|
450153
450963
|
const files = [];
|
|
450154
450964
|
const fixed = [];
|
|
@@ -450172,7 +450982,7 @@ async function runProjectLint(opts) {
|
|
|
450172
450982
|
if (opts.fix && findings.length > 0) {
|
|
450173
450983
|
const { html: nextHtml, fixedCodes } = applyMechanicalFixes(html, findings);
|
|
450174
450984
|
if (fixedCodes.length > 0) {
|
|
450175
|
-
await
|
|
450985
|
+
await writeFile11(abs, nextHtml, "utf-8");
|
|
450176
450986
|
fixed.push({ file: rel, codes: fixedCodes });
|
|
450177
450987
|
const reLinted = runHyperframeLint({ ...prepared, html: nextHtml });
|
|
450178
450988
|
files.push({
|
|
@@ -450209,7 +451019,7 @@ async function runProjectLint(opts) {
|
|
|
450209
451019
|
};
|
|
450210
451020
|
}
|
|
450211
451021
|
async function rootExists(projectDir, rootRel = "index.html") {
|
|
450212
|
-
const abs =
|
|
451022
|
+
const abs = resolve15(projectDir, rootRel);
|
|
450213
451023
|
try {
|
|
450214
451024
|
const s2 = await stat2(abs);
|
|
450215
451025
|
return s2.isFile();
|
|
@@ -469209,12 +470019,12 @@ var init_dist3 = __esm({
|
|
|
469209
470019
|
|
|
469210
470020
|
// ../cli/src/commands/_shared/root-sync.ts
|
|
469211
470021
|
import { existsSync as existsSync23 } from "node:fs";
|
|
469212
|
-
import { readFile as readFile8, writeFile as
|
|
469213
|
-
import { join as join23, resolve as
|
|
470022
|
+
import { readFile as readFile8, writeFile as writeFile13 } from "node:fs/promises";
|
|
470023
|
+
import { join as join23, resolve as resolve17 } from "node:path";
|
|
469214
470024
|
async function createRootSyncPlan(opts) {
|
|
469215
|
-
const projectDir =
|
|
470025
|
+
const projectDir = resolve17(opts.projectDir);
|
|
469216
470026
|
const rootRel = opts.rootRel ?? "index.html";
|
|
469217
|
-
const rootPath =
|
|
470027
|
+
const rootPath = resolve17(projectDir, rootRel);
|
|
469218
470028
|
if (!existsSync23(rootPath)) {
|
|
469219
470029
|
return { rootPath, rootRel, exists: false, changed: false, fixCodes: [], issues: [] };
|
|
469220
470030
|
}
|
|
@@ -469272,11 +470082,11 @@ async function createProjectRootSyncPlan(opts) {
|
|
|
469272
470082
|
}
|
|
469273
470083
|
async function syncRootComposition(opts) {
|
|
469274
470084
|
const plan = await createRootSyncPlan(opts);
|
|
469275
|
-
if (plan.nextHtml) await
|
|
470085
|
+
if (plan.nextHtml) await writeFile13(plan.rootPath, plan.nextHtml, "utf-8");
|
|
469276
470086
|
return plan;
|
|
469277
470087
|
}
|
|
469278
470088
|
async function loadProjectRootSyncBeats(projectDir) {
|
|
469279
|
-
const root2 =
|
|
470089
|
+
const root2 = resolve17(projectDir);
|
|
469280
470090
|
const storyboardPath = join23(root2, "STORYBOARD.md");
|
|
469281
470091
|
if (!existsSync23(storyboardPath)) return [];
|
|
469282
470092
|
const parsed = parseStoryboard(await readFile8(storyboardPath, "utf-8"));
|
|
@@ -469353,7 +470163,7 @@ async function resolveSyncedBeatDuration(opts) {
|
|
|
469353
470163
|
}
|
|
469354
470164
|
}
|
|
469355
470165
|
async function resolveProjectBeatDurations(projectDir) {
|
|
469356
|
-
const root2 =
|
|
470166
|
+
const root2 = resolve17(projectDir);
|
|
469357
470167
|
const beats = await loadProjectRootSyncBeats(root2);
|
|
469358
470168
|
const durations = /* @__PURE__ */ new Map();
|
|
469359
470169
|
for (const beat of beats) {
|
|
@@ -469602,8 +470412,8 @@ __export(compose_scenes_skills_exports, {
|
|
|
469602
470412
|
});
|
|
469603
470413
|
import { createHash as createHash5 } from "node:crypto";
|
|
469604
470414
|
import { existsSync as existsSync24, mkdirSync as mkdirSync12 } from "node:fs";
|
|
469605
|
-
import { mkdir as mkdir9, readFile as readFile9, writeFile as
|
|
469606
|
-
import { dirname as dirname13, join as join24, resolve as
|
|
470415
|
+
import { mkdir as mkdir9, readFile as readFile9, writeFile as writeFile14 } from "node:fs/promises";
|
|
470416
|
+
import { dirname as dirname13, join as join24, resolve as resolve18 } from "node:path";
|
|
469607
470417
|
function buildSystemPrompt(ctx) {
|
|
469608
470418
|
return `You are a Hyperframes composition author. The skill content below
|
|
469609
470419
|
defines the framework rules, motion principles, and quality standards.
|
|
@@ -469696,7 +470506,15 @@ ${finalDurationBullet}
|
|
|
469696
470506
|
itself. For multi-phase beats, drive phase changes with GSAP \`autoAlpha\`
|
|
469697
470507
|
inside full-window clips: animate phase A out (\`autoAlpha: 0\`), then
|
|
469698
470508
|
phase B in, on the same timeline.
|
|
469699
|
-
- If \`assets/
|
|
470509
|
+
- If \`assets/video-${ctx.beat.id}.mp4\` exists, it is an AI-generated clip for
|
|
470510
|
+
this beat \u2014 use it as the FULL-FRAME visual and prefer it over any backdrop
|
|
470511
|
+
image or CSS. Put one full-bleed \`<video>\` inside a full-window \`.clip\`:
|
|
470512
|
+
\`<video src="assets/video-${ctx.beat.id}.mp4" data-start="0" data-duration="${BEAT_DURATION}" data-media-start="0" muted playsinline style="width:100%;height:100%;object-fit:cover"></video>\`
|
|
470513
|
+
Use the exact path (no \`./\` or \`../\`). The framework seeks the clip to each
|
|
470514
|
+
timeline frame, so do NOT add transform tweens to the \`<video>\` or its
|
|
470515
|
+
ancestors; layer text/motion graphics on top instead.
|
|
470516
|
+
- If \`assets/backdrop-${ctx.beat.id}.png\` exists (and no video clip above),
|
|
470517
|
+
use that local file as the
|
|
469700
470518
|
full-frame visual backdrop. The exact path string is
|
|
469701
470519
|
\`assets/backdrop-${ctx.beat.id}.png\`; do NOT prefix it with \`../\` or \`./\`
|
|
469702
470520
|
because fragments are mounted from the project root.
|
|
@@ -469863,7 +470681,7 @@ async function composeBeatHtml(ctx, overrides) {
|
|
|
469863
470681
|
const html = extractHtml(result.text);
|
|
469864
470682
|
try {
|
|
469865
470683
|
mkdirSync12(cacheDir, { recursive: true });
|
|
469866
|
-
await
|
|
470684
|
+
await writeFile14(cachePath, html, "utf-8");
|
|
469867
470685
|
} catch {
|
|
469868
470686
|
}
|
|
469869
470687
|
const costUsd = result.inputTokens / 1e6 * settings.costPerMTokIn + result.outputTokens / 1e6 * settings.costPerMTokOut;
|
|
@@ -469962,9 +470780,9 @@ async function resolveComposerConfigAware(explicit, cwd) {
|
|
|
469962
470780
|
return resolveComposer();
|
|
469963
470781
|
}
|
|
469964
470782
|
async function executeComposeScenesWithSkills(params, outputDir, overrides) {
|
|
469965
|
-
const projectRoot = params.project ?
|
|
469966
|
-
const designPath =
|
|
469967
|
-
const storyboardPath =
|
|
470783
|
+
const projectRoot = params.project ? resolve18(outputDir, params.project) : resolve18(outputDir);
|
|
470784
|
+
const designPath = resolve18(projectRoot, params.design ?? "DESIGN.md");
|
|
470785
|
+
const storyboardPath = resolve18(projectRoot, params.storyboard ?? "STORYBOARD.md");
|
|
469968
470786
|
if (!existsSync24(designPath)) {
|
|
469969
470787
|
return { success: false, error: `DESIGN.md not found at ${designPath}` };
|
|
469970
470788
|
}
|
|
@@ -470022,7 +470840,7 @@ async function executeComposeScenesWithSkills(params, outputDir, overrides) {
|
|
|
470022
470840
|
);
|
|
470023
470841
|
const compositionPath = join24(compositionsDir, `scene-${beat.id}.html`);
|
|
470024
470842
|
await mkdir9(dirname13(compositionPath), { recursive: true });
|
|
470025
|
-
await
|
|
470843
|
+
await writeFile14(compositionPath, result.html, "utf-8");
|
|
470026
470844
|
if (result.cached) {
|
|
470027
470845
|
onProgress({
|
|
470028
470846
|
type: "beat-cached",
|
|
@@ -470225,9 +471043,9 @@ var init_compose_scenes_skills = __esm({
|
|
|
470225
471043
|
// ../cli/src/commands/_shared/compose-prompts.ts
|
|
470226
471044
|
import { existsSync as existsSync25 } from "node:fs";
|
|
470227
471045
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
470228
|
-
import { join as join25, relative as relative6, resolve as
|
|
471046
|
+
import { join as join25, relative as relative6, resolve as resolve19 } from "node:path";
|
|
470229
471047
|
async function getComposePrompts(opts) {
|
|
470230
|
-
const projectDir =
|
|
471048
|
+
const projectDir = resolve19(opts.projectDir);
|
|
470231
471049
|
const designPath = join25(projectDir, "DESIGN.md");
|
|
470232
471050
|
const storyboardPath = join25(projectDir, "STORYBOARD.md");
|
|
470233
471051
|
const skillPath = join25(projectDir, "SKILL.md");
|
|
@@ -470354,7 +471172,7 @@ var init_compose_prompts = __esm({
|
|
|
470354
471172
|
// ../cli/src/commands/_shared/sub-comp-duration-sync.ts
|
|
470355
471173
|
import { existsSync as existsSync27 } from "node:fs";
|
|
470356
471174
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
470357
|
-
import { join as join27, resolve as
|
|
471175
|
+
import { join as join27, resolve as resolve21 } from "node:path";
|
|
470358
471176
|
function syncSubCompositionDurationHtml(html, beatId, newDurationSec, fileRel) {
|
|
470359
471177
|
const compositionId = `scene-${beatId}`;
|
|
470360
471178
|
const file = fileRel ?? `compositions/${compositionId}.html`;
|
|
@@ -470442,7 +471260,7 @@ function rewriteTimelineConst(html, oldDurationSec, newDurationSec) {
|
|
|
470442
471260
|
return { html, rewritten: false, needsManualFix };
|
|
470443
471261
|
}
|
|
470444
471262
|
async function createSubCompDurationSyncPlans(opts) {
|
|
470445
|
-
const projectDir =
|
|
471263
|
+
const projectDir = resolve21(opts.projectDir);
|
|
470446
471264
|
const results = [];
|
|
470447
471265
|
for (const beat of opts.beats) {
|
|
470448
471266
|
const fileRel = `compositions/scene-${beat.id}.html`;
|
|
@@ -470477,88 +471295,6 @@ var init_sub_comp_duration_sync = __esm({
|
|
|
470477
471295
|
}
|
|
470478
471296
|
});
|
|
470479
471297
|
|
|
470480
|
-
// ../cli/src/commands/_shared/review-report.ts
|
|
470481
|
-
import { writeFile as writeFile15 } from "node:fs/promises";
|
|
470482
|
-
import { join as join28, resolve as resolve21 } from "node:path";
|
|
470483
|
-
function statusFromIssues(issues) {
|
|
470484
|
-
if (issues.some((issue) => issue.severity === "error")) return "fail";
|
|
470485
|
-
if (issues.some((issue) => issue.severity === "warning")) return "warn";
|
|
470486
|
-
return "pass";
|
|
470487
|
-
}
|
|
470488
|
-
function scoreIssues(issues) {
|
|
470489
|
-
let score = 100;
|
|
470490
|
-
for (const issue of issues) {
|
|
470491
|
-
if (issue.severity === "error") score -= 25;
|
|
470492
|
-
else if (issue.severity === "warning") score -= 8;
|
|
470493
|
-
else score -= 2;
|
|
470494
|
-
}
|
|
470495
|
-
return Math.max(0, Math.min(100, score));
|
|
470496
|
-
}
|
|
470497
|
-
function uniqueRetryWith(items) {
|
|
470498
|
-
return [
|
|
470499
|
-
...new Set(items.filter((item) => typeof item === "string" && item.length > 0))
|
|
470500
|
-
];
|
|
470501
|
-
}
|
|
470502
|
-
function fixOwnerForIssue(issue) {
|
|
470503
|
-
if (issue.fixOwner) return issue.fixOwner;
|
|
470504
|
-
if (issue.code.startsWith("AI_REVIEW_")) return "host-agent";
|
|
470505
|
-
if (issue.code.startsWith("STORYBOARD_")) return "host-agent";
|
|
470506
|
-
if (issue.code === "PROJECT_NOT_FOUND" || issue.code === "MISSING_STORYBOARD" || issue.code === "BEAT_NOT_FOUND" || issue.code === "MISSING_DESIGN") {
|
|
470507
|
-
return "host-agent";
|
|
470508
|
-
}
|
|
470509
|
-
return "vibe";
|
|
470510
|
-
}
|
|
470511
|
-
function normalizeReviewIssues(issues, fallbackOwner) {
|
|
470512
|
-
return issues.map((issue) => ({
|
|
470513
|
-
...issue,
|
|
470514
|
-
fixOwner: issue.fixOwner ?? fallbackOwner ?? fixOwnerForIssue(issue)
|
|
470515
|
-
}));
|
|
470516
|
-
}
|
|
470517
|
-
function summarizeReviewIssues(issues) {
|
|
470518
|
-
const normalized = normalizeReviewIssues(issues);
|
|
470519
|
-
return {
|
|
470520
|
-
issueCount: normalized.length,
|
|
470521
|
-
errorCount: normalized.filter((issue) => issue.severity === "error").length,
|
|
470522
|
-
warningCount: normalized.filter((issue) => issue.severity === "warning").length,
|
|
470523
|
-
infoCount: normalized.filter((issue) => issue.severity === "info").length,
|
|
470524
|
-
fixOwners: {
|
|
470525
|
-
vibe: normalized.filter((issue) => issue.fixOwner === "vibe").length,
|
|
470526
|
-
hostAgent: normalized.filter((issue) => issue.fixOwner === "host-agent").length
|
|
470527
|
-
}
|
|
470528
|
-
};
|
|
470529
|
-
}
|
|
470530
|
-
function buildReviewReport(opts) {
|
|
470531
|
-
const issues = normalizeReviewIssues(opts.issues);
|
|
470532
|
-
return stripUndefined2({
|
|
470533
|
-
schemaVersion: "1",
|
|
470534
|
-
kind: "review",
|
|
470535
|
-
project: resolve21(opts.project),
|
|
470536
|
-
mode: opts.mode,
|
|
470537
|
-
beat: opts.beat,
|
|
470538
|
-
status: opts.status,
|
|
470539
|
-
score: opts.score,
|
|
470540
|
-
issues,
|
|
470541
|
-
summary: summarizeReviewIssues(issues),
|
|
470542
|
-
retryWith: uniqueRetryWith(opts.retryWith),
|
|
470543
|
-
sourceReports: opts.sourceReports ?? [],
|
|
470544
|
-
reportPath: opts.reportPath
|
|
470545
|
-
});
|
|
470546
|
-
}
|
|
470547
|
-
function defaultReviewReportPath(projectDir) {
|
|
470548
|
-
return join28(resolve21(projectDir), "review-report.json");
|
|
470549
|
-
}
|
|
470550
|
-
async function writeReviewReport(path14, report) {
|
|
470551
|
-
await writeFile15(path14, JSON.stringify(report, null, 2) + "\n", "utf-8");
|
|
470552
|
-
}
|
|
470553
|
-
function stripUndefined2(value) {
|
|
470554
|
-
return Object.fromEntries(Object.entries(value).filter(([, v2]) => v2 !== void 0));
|
|
470555
|
-
}
|
|
470556
|
-
var init_review_report = __esm({
|
|
470557
|
-
"../cli/src/commands/_shared/review-report.ts"() {
|
|
470558
|
-
"use strict";
|
|
470559
|
-
}
|
|
470560
|
-
});
|
|
470561
|
-
|
|
470562
471298
|
// ../cli/src/commands/_shared/scene-repair.ts
|
|
470563
471299
|
import { readFile as readFile13, writeFile as writeFile16 } from "node:fs/promises";
|
|
470564
471300
|
import { relative as relative7, resolve as resolve23 } from "node:path";
|
|
@@ -470685,16 +471421,307 @@ var init_scene_repair = __esm({
|
|
|
470685
471421
|
}
|
|
470686
471422
|
});
|
|
470687
471423
|
|
|
471424
|
+
// ../cli/src/commands/_shared/storyboard-edit.ts
|
|
471425
|
+
function validateStoryboardMarkdown(markdown) {
|
|
471426
|
+
const parsed = parseStoryboard(markdown);
|
|
471427
|
+
const sections = splitBeatSections(markdown);
|
|
471428
|
+
const issues = [];
|
|
471429
|
+
if (parsed.beats.length === 0) {
|
|
471430
|
+
issues.push({
|
|
471431
|
+
severity: "error",
|
|
471432
|
+
code: "NO_BEATS",
|
|
471433
|
+
message: "STORYBOARD.md must contain at least one `## Beat ...` heading."
|
|
471434
|
+
});
|
|
471435
|
+
}
|
|
471436
|
+
const seen = /* @__PURE__ */ new Map();
|
|
471437
|
+
for (const beat of parsed.beats) {
|
|
471438
|
+
seen.set(beat.id, (seen.get(beat.id) ?? 0) + 1);
|
|
471439
|
+
}
|
|
471440
|
+
for (const [id, count] of seen.entries()) {
|
|
471441
|
+
if (count > 1) {
|
|
471442
|
+
issues.push({
|
|
471443
|
+
severity: "error",
|
|
471444
|
+
code: "DUPLICATE_BEAT_ID",
|
|
471445
|
+
beatId: id,
|
|
471446
|
+
message: `Beat id "${id}" appears ${count} times. Beat ids must be unique.`
|
|
471447
|
+
});
|
|
471448
|
+
}
|
|
471449
|
+
}
|
|
471450
|
+
for (const section of sections) {
|
|
471451
|
+
const cueBlock = readLeadingCueBlock(section.body);
|
|
471452
|
+
if (cueBlock?.error) {
|
|
471453
|
+
issues.push({
|
|
471454
|
+
severity: "error",
|
|
471455
|
+
code: "MALFORMED_CUE_YAML",
|
|
471456
|
+
beatId: section.id,
|
|
471457
|
+
message: `Beat "${section.id}" has malformed YAML cues: ${cueBlock.error}`
|
|
471458
|
+
});
|
|
471459
|
+
}
|
|
471460
|
+
}
|
|
471461
|
+
const characterPool = new Set(
|
|
471462
|
+
Object.keys(
|
|
471463
|
+
parsed.frontmatter?.characters ?? {}
|
|
471464
|
+
)
|
|
471465
|
+
);
|
|
471466
|
+
for (const beat of parsed.beats) {
|
|
471467
|
+
const cues = beat.cues ?? {};
|
|
471468
|
+
for (const [key2, value] of Object.entries(cues)) {
|
|
471469
|
+
if (!ALLOWED_CUE_KEYS.has(key2)) {
|
|
471470
|
+
issues.push({
|
|
471471
|
+
severity: "warning",
|
|
471472
|
+
code: "UNKNOWN_CUE",
|
|
471473
|
+
beatId: beat.id,
|
|
471474
|
+
message: `Beat "${beat.id}" uses unknown cue "${key2}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`
|
|
471475
|
+
});
|
|
471476
|
+
continue;
|
|
471477
|
+
}
|
|
471478
|
+
if (key2 === "characters") {
|
|
471479
|
+
const validShape = typeof value === "string" || Array.isArray(value) && value.every((v2) => typeof v2 === "string");
|
|
471480
|
+
if (!validShape) {
|
|
471481
|
+
issues.push({
|
|
471482
|
+
severity: "error",
|
|
471483
|
+
code: "INVALID_CHARACTERS_VALUE",
|
|
471484
|
+
beatId: beat.id,
|
|
471485
|
+
message: `Beat "${beat.id}" cue "characters" must be a character name or a list of names.`
|
|
471486
|
+
});
|
|
471487
|
+
continue;
|
|
471488
|
+
}
|
|
471489
|
+
for (const name of beatCharacterNames({ characters: value })) {
|
|
471490
|
+
if (!characterPool.has(name)) {
|
|
471491
|
+
issues.push({
|
|
471492
|
+
severity: "warning",
|
|
471493
|
+
code: "UNKNOWN_CHARACTER",
|
|
471494
|
+
beatId: beat.id,
|
|
471495
|
+
message: `Beat "${beat.id}" references character "${name}" not defined in the frontmatter \`characters:\` pool.`
|
|
471496
|
+
});
|
|
471497
|
+
}
|
|
471498
|
+
}
|
|
471499
|
+
continue;
|
|
471500
|
+
}
|
|
471501
|
+
if (key2 === "duration") {
|
|
471502
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
471503
|
+
issues.push({
|
|
471504
|
+
severity: "error",
|
|
471505
|
+
code: "INVALID_DURATION",
|
|
471506
|
+
beatId: beat.id,
|
|
471507
|
+
message: `Beat "${beat.id}" cue "duration" must be a positive number of seconds.`
|
|
471508
|
+
});
|
|
471509
|
+
}
|
|
471510
|
+
continue;
|
|
471511
|
+
}
|
|
471512
|
+
if (STRING_CUE_KEYS.has(key2) && typeof value !== "string") {
|
|
471513
|
+
issues.push({
|
|
471514
|
+
severity: "error",
|
|
471515
|
+
code: "INVALID_CUE_VALUE",
|
|
471516
|
+
beatId: beat.id,
|
|
471517
|
+
message: `Beat "${beat.id}" cue "${key2}" must be a string.`
|
|
471518
|
+
});
|
|
471519
|
+
}
|
|
471520
|
+
}
|
|
471521
|
+
}
|
|
471522
|
+
for (const beat of parsed.beats) {
|
|
471523
|
+
if (beat.duration !== void 0 && beat.duration > MAX_RECOMMENDED_BEAT_SEC) {
|
|
471524
|
+
issues.push({
|
|
471525
|
+
severity: "warning",
|
|
471526
|
+
code: "BEAT_DURATION_TOO_LONG",
|
|
471527
|
+
beatId: beat.id,
|
|
471528
|
+
message: `Beat "${beat.id}" is ${beat.duration}s \u2014 beats longer than ${MAX_RECOMMENDED_BEAT_SEC}s render static and overstuffed. Split it into 6-15s beats (a 90s video should have 6-8 beats).`
|
|
471529
|
+
});
|
|
471530
|
+
}
|
|
471531
|
+
}
|
|
471532
|
+
return {
|
|
471533
|
+
ok: !issues.some((i2) => i2.severity === "error"),
|
|
471534
|
+
beats: parsed.beats,
|
|
471535
|
+
issues
|
|
471536
|
+
};
|
|
471537
|
+
}
|
|
471538
|
+
function getStoryboardBeat(markdown, beatId) {
|
|
471539
|
+
return parseStoryboard(markdown).beats.find((beat) => beat.id === beatId) ?? null;
|
|
471540
|
+
}
|
|
471541
|
+
function upsertStoryboardBeat(markdown, opts) {
|
|
471542
|
+
const beatId = normalizeBeatId(opts.beatId);
|
|
471543
|
+
const sections = splitBeatSections(markdown);
|
|
471544
|
+
const existing = sections.find((section2) => section2.id === beatId);
|
|
471545
|
+
const cues = storyboardCuesFromInput(opts);
|
|
471546
|
+
if (existing) {
|
|
471547
|
+
let next = markdown;
|
|
471548
|
+
for (const [key2, value] of Object.entries(cues)) {
|
|
471549
|
+
next = setStoryboardCue(next, { beatId, key: key2, value });
|
|
471550
|
+
}
|
|
471551
|
+
return { markdown: next, action: "updated" };
|
|
471552
|
+
}
|
|
471553
|
+
const section = buildStoryboardBeatSection({ ...opts, beatId, cues });
|
|
471554
|
+
if (sections.length > 0 && isStarterStoryboard(markdown)) {
|
|
471555
|
+
const global3 = markdown.slice(0, sections[0].start).trimEnd();
|
|
471556
|
+
return {
|
|
471557
|
+
markdown: `${global3}
|
|
471558
|
+
|
|
471559
|
+
${section}`,
|
|
471560
|
+
action: "replaced-starter"
|
|
471561
|
+
};
|
|
471562
|
+
}
|
|
471563
|
+
const prefix = markdown.trimEnd();
|
|
471564
|
+
return {
|
|
471565
|
+
markdown: `${prefix}${prefix ? "\n\n" : ""}${section}`,
|
|
471566
|
+
action: "appended"
|
|
471567
|
+
};
|
|
471568
|
+
}
|
|
471569
|
+
function setStoryboardCue(markdown, opts) {
|
|
471570
|
+
const section = findBeatSection(markdown, opts.beatId);
|
|
471571
|
+
if (!section) {
|
|
471572
|
+
throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
471573
|
+
}
|
|
471574
|
+
if (!ALLOWED_CUE_KEYS.has(opts.key)) {
|
|
471575
|
+
throw new Error(`Unsupported cue "${opts.key}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`);
|
|
471576
|
+
}
|
|
471577
|
+
const cue = readLeadingCueBlock(section.body);
|
|
471578
|
+
if (cue?.error) {
|
|
471579
|
+
throw new Error(`Cannot edit malformed YAML cues for beat "${opts.beatId}": ${cue.error}`);
|
|
471580
|
+
}
|
|
471581
|
+
const cues = cue?.value ? { ...cue.value } : {};
|
|
471582
|
+
if (opts.unset) {
|
|
471583
|
+
delete cues[opts.key];
|
|
471584
|
+
} else {
|
|
471585
|
+
cues[opts.key] = normalizeCueValue(opts.key, opts.value);
|
|
471586
|
+
}
|
|
471587
|
+
const remainingBody = cue ? section.body.slice(cue.full.length).replace(/^\s*\n/, "") : section.body.replace(/^\s*\n/, "");
|
|
471588
|
+
const cueBlock = Object.keys(cues).length > 0 ? "```yaml\n" + (0, import_yaml5.stringify)(cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
471589
|
+
const nextBody = cueBlock + remainingBody.trimStart();
|
|
471590
|
+
const nextSection = section.raw.slice(0, section.headingEnd - section.start) + "\n\n" + nextBody.trimEnd() + "\n";
|
|
471591
|
+
return markdown.slice(0, section.start) + nextSection + markdown.slice(section.end);
|
|
471592
|
+
}
|
|
471593
|
+
function moveStoryboardBeat(markdown, opts) {
|
|
471594
|
+
if (opts.beatId === opts.afterBeatId) return markdown;
|
|
471595
|
+
const sections = splitBeatSections(markdown);
|
|
471596
|
+
const movingIndex = sections.findIndex((section) => section.id === opts.beatId);
|
|
471597
|
+
if (movingIndex === -1) throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
471598
|
+
const afterIndex = sections.findIndex((section) => section.id === opts.afterBeatId);
|
|
471599
|
+
if (afterIndex === -1) throw new Error(`Beat "${opts.afterBeatId}" not found.`);
|
|
471600
|
+
const global3 = sections.length > 0 ? markdown.slice(0, sections[0].start) : markdown;
|
|
471601
|
+
const chunks = sections.map((section) => section.raw);
|
|
471602
|
+
const [moving] = chunks.splice(movingIndex, 1);
|
|
471603
|
+
const adjustedAfterIndex = movingIndex < afterIndex ? afterIndex - 1 : afterIndex;
|
|
471604
|
+
chunks.splice(adjustedAfterIndex + 1, 0, moving);
|
|
471605
|
+
return global3 + normalizeBeatChunks(chunks);
|
|
471606
|
+
}
|
|
471607
|
+
function normalizeBeatChunks(chunks) {
|
|
471608
|
+
return chunks.map((chunk) => chunk.trim()).filter(Boolean).join("\n\n") + "\n";
|
|
471609
|
+
}
|
|
471610
|
+
function normalizeBeatId(id) {
|
|
471611
|
+
return deriveBeatId(id);
|
|
471612
|
+
}
|
|
471613
|
+
function storyboardCuesFromInput(opts) {
|
|
471614
|
+
const cues = {};
|
|
471615
|
+
if (opts.duration !== void 0) cues.duration = opts.duration;
|
|
471616
|
+
if (opts.narration && opts.narration.trim()) cues.narration = opts.narration.trim();
|
|
471617
|
+
if (opts.backdrop && opts.backdrop.trim()) cues.backdrop = opts.backdrop.trim();
|
|
471618
|
+
return cues;
|
|
471619
|
+
}
|
|
471620
|
+
function buildStoryboardBeatSection(opts) {
|
|
471621
|
+
const title = normalizeTitle(opts.title ?? humanizeBeatId(opts.beatId));
|
|
471622
|
+
const cueBlock = Object.keys(opts.cues).length > 0 ? "```yaml\n" + (0, import_yaml5.stringify)(opts.cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
471623
|
+
const body = opts.body?.trim() || "Scene created with `vibe scene add`. Edit this body if the build flow should recompose it.";
|
|
471624
|
+
return `## Beat ${opts.beatId} - ${title}
|
|
471625
|
+
|
|
471626
|
+
${cueBlock}${body.trimEnd()}
|
|
471627
|
+
`;
|
|
471628
|
+
}
|
|
471629
|
+
function normalizeTitle(value) {
|
|
471630
|
+
return value.replace(/\s+/g, " ").trim() || "Scene";
|
|
471631
|
+
}
|
|
471632
|
+
function humanizeBeatId(id) {
|
|
471633
|
+
return id.split(/[-_]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ") || "Scene";
|
|
471634
|
+
}
|
|
471635
|
+
function isStarterStoryboard(markdown) {
|
|
471636
|
+
const parsed = parseStoryboard(markdown);
|
|
471637
|
+
if (parsed.beats.length !== 3) return false;
|
|
471638
|
+
const ids = parsed.beats.map((beat) => beat.id);
|
|
471639
|
+
if (ids.join(",") !== "hook,proof,close") return false;
|
|
471640
|
+
return markdown.includes("Introduce the promise in one crisp sentence.") && markdown.includes("Show the mechanism or proof point that makes the promise believable.") && markdown.includes("Close with the action the viewer should remember.");
|
|
471641
|
+
}
|
|
471642
|
+
function normalizeCueValue(key2, value) {
|
|
471643
|
+
if (key2 === "duration") {
|
|
471644
|
+
const n2 = typeof value === "number" ? value : Number.parseFloat(String(value ?? ""));
|
|
471645
|
+
if (!Number.isFinite(n2) || n2 <= 0) {
|
|
471646
|
+
throw new Error("Cue duration must be a positive number.");
|
|
471647
|
+
}
|
|
471648
|
+
return n2;
|
|
471649
|
+
}
|
|
471650
|
+
if (typeof value !== "string") return value;
|
|
471651
|
+
return value.trim();
|
|
471652
|
+
}
|
|
471653
|
+
function splitBeatSections(markdown) {
|
|
471654
|
+
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
471655
|
+
const headings = [];
|
|
471656
|
+
HEADING_RE2.lastIndex = 0;
|
|
471657
|
+
let match2;
|
|
471658
|
+
while ((match2 = HEADING_RE2.exec(normalized)) !== null) {
|
|
471659
|
+
headings.push({ start: match2.index, end: match2.index + match2[0].length, line: match2[1].trim() });
|
|
471660
|
+
}
|
|
471661
|
+
return headings.map((heading, index) => {
|
|
471662
|
+
const end = index + 1 < headings.length ? headings[index + 1].start : normalized.length;
|
|
471663
|
+
return {
|
|
471664
|
+
id: deriveBeatId(heading.line),
|
|
471665
|
+
heading: heading.line,
|
|
471666
|
+
start: heading.start,
|
|
471667
|
+
headingEnd: heading.end,
|
|
471668
|
+
end,
|
|
471669
|
+
raw: normalized.slice(heading.start, end),
|
|
471670
|
+
body: normalized.slice(heading.end, end).trim()
|
|
471671
|
+
};
|
|
471672
|
+
});
|
|
471673
|
+
}
|
|
471674
|
+
function findBeatSection(markdown, beatId) {
|
|
471675
|
+
return splitBeatSections(markdown).find((section) => section.id === beatId) ?? null;
|
|
471676
|
+
}
|
|
471677
|
+
function readLeadingCueBlock(body) {
|
|
471678
|
+
const match2 = body.match(LEADING_CUE_RE);
|
|
471679
|
+
if (!match2) return null;
|
|
471680
|
+
try {
|
|
471681
|
+
const parsed = (0, import_yaml5.parse)(match2[2]);
|
|
471682
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
471683
|
+
return { full: match2[0], error: "cue block must parse to a YAML object" };
|
|
471684
|
+
}
|
|
471685
|
+
return { full: match2[0], value: parsed };
|
|
471686
|
+
} catch (error) {
|
|
471687
|
+
return { full: match2[0], error: error instanceof Error ? error.message : String(error) };
|
|
471688
|
+
}
|
|
471689
|
+
}
|
|
471690
|
+
var import_yaml5, STORYBOARD_CUE_KEYS, HEADING_RE2, LEADING_CUE_RE, ALLOWED_CUE_KEYS, STRING_CUE_KEYS, MAX_RECOMMENDED_BEAT_SEC;
|
|
471691
|
+
var init_storyboard_edit = __esm({
|
|
471692
|
+
"../cli/src/commands/_shared/storyboard-edit.ts"() {
|
|
471693
|
+
"use strict";
|
|
471694
|
+
import_yaml5 = __toESM(require_dist3(), 1);
|
|
471695
|
+
init_storyboard_parse();
|
|
471696
|
+
STORYBOARD_CUE_KEYS = [
|
|
471697
|
+
"duration",
|
|
471698
|
+
"narration",
|
|
471699
|
+
"backdrop",
|
|
471700
|
+
"video",
|
|
471701
|
+
"motion",
|
|
471702
|
+
"voice",
|
|
471703
|
+
"music",
|
|
471704
|
+
"asset",
|
|
471705
|
+
"characters"
|
|
471706
|
+
];
|
|
471707
|
+
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
471708
|
+
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
471709
|
+
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
471710
|
+
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "motion", "voice", "music", "asset"]);
|
|
471711
|
+
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
471712
|
+
}
|
|
471713
|
+
});
|
|
471714
|
+
|
|
470688
471715
|
// ../cli/src/pipeline/renderers/chrome.ts
|
|
470689
471716
|
import { existsSync as existsSync29 } from "node:fs";
|
|
470690
471717
|
import { homedir as homedir7 } from "node:os";
|
|
470691
|
-
import { join as
|
|
471718
|
+
import { join as join28 } from "node:path";
|
|
470692
471719
|
function findChrome() {
|
|
470693
471720
|
const candidates = [
|
|
470694
471721
|
process.env.HYPERFRAMES_CHROME_PATH,
|
|
470695
471722
|
process.env.CHROME_PATH,
|
|
470696
471723
|
// puppeteer auto-downloaded headless shell
|
|
470697
|
-
|
|
471724
|
+
join28(
|
|
470698
471725
|
homedir7(),
|
|
470699
471726
|
".cache",
|
|
470700
471727
|
"puppeteer",
|
|
@@ -470987,7 +472014,7 @@ __export(scene_render_exports, {
|
|
|
470987
472014
|
import { execFile as execFile2 } from "node:child_process";
|
|
470988
472015
|
import { existsSync as existsSync30 } from "node:fs";
|
|
470989
472016
|
import { mkdir as mkdir12, readFile as readFile16, stat as stat3, writeFile as writeFile18 } from "node:fs/promises";
|
|
470990
|
-
import { resolve as resolve27, relative as relative9, dirname as dirname16, basename as basename7, join as
|
|
472017
|
+
import { resolve as resolve27, relative as relative9, dirname as dirname16, basename as basename7, join as join29, isAbsolute as isAbsolute3 } from "node:path";
|
|
470991
472018
|
import { promisify as promisify2 } from "node:util";
|
|
470992
472019
|
function qualityToCrf(quality = "standard") {
|
|
470993
472020
|
return quality === "draft" ? 28 : quality === "high" ? 18 : 23;
|
|
@@ -471075,7 +472102,7 @@ async function executeSceneRender(opts = {}) {
|
|
|
471075
472102
|
}
|
|
471076
472103
|
let autoSyncApplied = false;
|
|
471077
472104
|
let autoSyncWarning;
|
|
471078
|
-
if (!opts.beatId && existsSync30(
|
|
472105
|
+
if (!opts.beatId && existsSync30(join29(projectDir, "STORYBOARD.md"))) {
|
|
471079
472106
|
try {
|
|
471080
472107
|
const rootPlan = await createProjectRootSyncPlan({ projectDir });
|
|
471081
472108
|
const subPlans = await createSubCompDurationSyncPlans({
|
|
@@ -471252,7 +472279,7 @@ async function safeStat(p2) {
|
|
|
471252
472279
|
}
|
|
471253
472280
|
async function prepareBeatRenderRoot(opts) {
|
|
471254
472281
|
const root2 = `.vibeframe/tmp/render-beat-${sanitizeFileSegment(opts.beatId)}.html`;
|
|
471255
|
-
const reportPath =
|
|
472282
|
+
const reportPath = join29(opts.projectDir, "build-report.json");
|
|
471256
472283
|
const retryWith = [
|
|
471257
472284
|
`vibe build ${opts.projectDir} --beat ${opts.beatId} --stage sync --json`
|
|
471258
472285
|
];
|
|
@@ -471336,8 +472363,8 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
471336
472363
|
durationSec,
|
|
471337
472364
|
narrationPath
|
|
471338
472365
|
});
|
|
471339
|
-
await mkdir12(dirname16(
|
|
471340
|
-
await writeFile18(
|
|
472366
|
+
await mkdir12(dirname16(join29(opts.projectDir, root2)), { recursive: true });
|
|
472367
|
+
await writeFile18(join29(opts.projectDir, root2), html, "utf-8");
|
|
471341
472368
|
return {
|
|
471342
472369
|
success: true,
|
|
471343
472370
|
root: root2,
|
|
@@ -471401,7 +472428,7 @@ function reportedBeatAssetPaths(beat) {
|
|
|
471401
472428
|
]);
|
|
471402
472429
|
}
|
|
471403
472430
|
async function writeRenderReport(projectDir, result) {
|
|
471404
|
-
const reportPath =
|
|
472431
|
+
const reportPath = join29(projectDir, "render-report.json");
|
|
471405
472432
|
try {
|
|
471406
472433
|
await writeFile18(
|
|
471407
472434
|
reportPath,
|
|
@@ -471598,6 +472625,7 @@ var init_build_asset_reference = __esm({
|
|
|
471598
472625
|
EXTENSIONS = {
|
|
471599
472626
|
narration: [".mp3", ".wav", ".m4a"],
|
|
471600
472627
|
backdrop: [".png", ".jpg", ".jpeg", ".webp"],
|
|
472628
|
+
character: [".png", ".jpg", ".jpeg", ".webp"],
|
|
471601
472629
|
video: [".mp4", ".mov", ".webm"],
|
|
471602
472630
|
music: [".mp3", ".wav", ".m4a"]
|
|
471603
472631
|
};
|
|
@@ -471635,6 +472663,16 @@ function backdropCacheDescriptor(opts) {
|
|
|
471635
472663
|
ext: "png"
|
|
471636
472664
|
});
|
|
471637
472665
|
}
|
|
472666
|
+
function characterCacheDescriptor(opts) {
|
|
472667
|
+
return cacheAssetDescriptor("character", {
|
|
472668
|
+
name: opts.name,
|
|
472669
|
+
cue: opts.cue,
|
|
472670
|
+
provider: opts.provider,
|
|
472671
|
+
quality: opts.quality,
|
|
472672
|
+
size: opts.size,
|
|
472673
|
+
ext: "png"
|
|
472674
|
+
});
|
|
472675
|
+
}
|
|
471638
472676
|
function imageRatioForSize(size) {
|
|
471639
472677
|
switch (size) {
|
|
471640
472678
|
case "1024x1024":
|
|
@@ -471654,6 +472692,8 @@ function videoCacheDescriptor(opts) {
|
|
|
471654
472692
|
provider: opts.provider,
|
|
471655
472693
|
duration: normalizeVideoDuration(opts.duration),
|
|
471656
472694
|
ratio: "16:9",
|
|
472695
|
+
// Omit when empty so existing (character-less) clips keep their cache key.
|
|
472696
|
+
characters: opts.characters && opts.characters.length > 0 ? opts.characters : void 0,
|
|
471657
472697
|
ext: "mp4"
|
|
471658
472698
|
});
|
|
471659
472699
|
}
|
|
@@ -471706,212 +472746,10 @@ var init_build_backdrop_prompt = __esm({
|
|
|
471706
472746
|
}
|
|
471707
472747
|
});
|
|
471708
472748
|
|
|
471709
|
-
// ../cli/src/commands/_shared/storyboard-edit.ts
|
|
471710
|
-
function validateStoryboardMarkdown(markdown) {
|
|
471711
|
-
const parsed = parseStoryboard(markdown);
|
|
471712
|
-
const sections = splitBeatSections(markdown);
|
|
471713
|
-
const issues = [];
|
|
471714
|
-
if (parsed.beats.length === 0) {
|
|
471715
|
-
issues.push({
|
|
471716
|
-
severity: "error",
|
|
471717
|
-
code: "NO_BEATS",
|
|
471718
|
-
message: "STORYBOARD.md must contain at least one `## Beat ...` heading."
|
|
471719
|
-
});
|
|
471720
|
-
}
|
|
471721
|
-
const seen = /* @__PURE__ */ new Map();
|
|
471722
|
-
for (const beat of parsed.beats) {
|
|
471723
|
-
seen.set(beat.id, (seen.get(beat.id) ?? 0) + 1);
|
|
471724
|
-
}
|
|
471725
|
-
for (const [id, count] of seen.entries()) {
|
|
471726
|
-
if (count > 1) {
|
|
471727
|
-
issues.push({
|
|
471728
|
-
severity: "error",
|
|
471729
|
-
code: "DUPLICATE_BEAT_ID",
|
|
471730
|
-
beatId: id,
|
|
471731
|
-
message: `Beat id "${id}" appears ${count} times. Beat ids must be unique.`
|
|
471732
|
-
});
|
|
471733
|
-
}
|
|
471734
|
-
}
|
|
471735
|
-
for (const section of sections) {
|
|
471736
|
-
const cueBlock = readLeadingCueBlock(section.body);
|
|
471737
|
-
if (cueBlock?.error) {
|
|
471738
|
-
issues.push({
|
|
471739
|
-
severity: "error",
|
|
471740
|
-
code: "MALFORMED_CUE_YAML",
|
|
471741
|
-
beatId: section.id,
|
|
471742
|
-
message: `Beat "${section.id}" has malformed YAML cues: ${cueBlock.error}`
|
|
471743
|
-
});
|
|
471744
|
-
}
|
|
471745
|
-
}
|
|
471746
|
-
for (const beat of parsed.beats) {
|
|
471747
|
-
const cues = beat.cues ?? {};
|
|
471748
|
-
for (const [key2, value] of Object.entries(cues)) {
|
|
471749
|
-
if (!ALLOWED_CUE_KEYS.has(key2)) {
|
|
471750
|
-
issues.push({
|
|
471751
|
-
severity: "warning",
|
|
471752
|
-
code: "UNKNOWN_CUE",
|
|
471753
|
-
beatId: beat.id,
|
|
471754
|
-
message: `Beat "${beat.id}" uses unknown cue "${key2}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`
|
|
471755
|
-
});
|
|
471756
|
-
continue;
|
|
471757
|
-
}
|
|
471758
|
-
if (key2 === "duration") {
|
|
471759
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
471760
|
-
issues.push({
|
|
471761
|
-
severity: "error",
|
|
471762
|
-
code: "INVALID_DURATION",
|
|
471763
|
-
beatId: beat.id,
|
|
471764
|
-
message: `Beat "${beat.id}" cue "duration" must be a positive number of seconds.`
|
|
471765
|
-
});
|
|
471766
|
-
}
|
|
471767
|
-
continue;
|
|
471768
|
-
}
|
|
471769
|
-
if (STRING_CUE_KEYS.has(key2) && typeof value !== "string") {
|
|
471770
|
-
issues.push({
|
|
471771
|
-
severity: "error",
|
|
471772
|
-
code: "INVALID_CUE_VALUE",
|
|
471773
|
-
beatId: beat.id,
|
|
471774
|
-
message: `Beat "${beat.id}" cue "${key2}" must be a string.`
|
|
471775
|
-
});
|
|
471776
|
-
}
|
|
471777
|
-
}
|
|
471778
|
-
}
|
|
471779
|
-
for (const beat of parsed.beats) {
|
|
471780
|
-
if (beat.duration !== void 0 && beat.duration > MAX_RECOMMENDED_BEAT_SEC) {
|
|
471781
|
-
issues.push({
|
|
471782
|
-
severity: "warning",
|
|
471783
|
-
code: "BEAT_DURATION_TOO_LONG",
|
|
471784
|
-
beatId: beat.id,
|
|
471785
|
-
message: `Beat "${beat.id}" is ${beat.duration}s \u2014 beats longer than ${MAX_RECOMMENDED_BEAT_SEC}s render static and overstuffed. Split it into 6-15s beats (a 90s video should have 6-8 beats).`
|
|
471786
|
-
});
|
|
471787
|
-
}
|
|
471788
|
-
}
|
|
471789
|
-
return {
|
|
471790
|
-
ok: !issues.some((i2) => i2.severity === "error"),
|
|
471791
|
-
beats: parsed.beats,
|
|
471792
|
-
issues
|
|
471793
|
-
};
|
|
471794
|
-
}
|
|
471795
|
-
function getStoryboardBeat(markdown, beatId) {
|
|
471796
|
-
return parseStoryboard(markdown).beats.find((beat) => beat.id === beatId) ?? null;
|
|
471797
|
-
}
|
|
471798
|
-
function setStoryboardCue(markdown, opts) {
|
|
471799
|
-
const section = findBeatSection(markdown, opts.beatId);
|
|
471800
|
-
if (!section) {
|
|
471801
|
-
throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
471802
|
-
}
|
|
471803
|
-
if (!ALLOWED_CUE_KEYS.has(opts.key)) {
|
|
471804
|
-
throw new Error(`Unsupported cue "${opts.key}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`);
|
|
471805
|
-
}
|
|
471806
|
-
const cue = readLeadingCueBlock(section.body);
|
|
471807
|
-
if (cue?.error) {
|
|
471808
|
-
throw new Error(`Cannot edit malformed YAML cues for beat "${opts.beatId}": ${cue.error}`);
|
|
471809
|
-
}
|
|
471810
|
-
const cues = cue?.value ? { ...cue.value } : {};
|
|
471811
|
-
if (opts.unset) {
|
|
471812
|
-
delete cues[opts.key];
|
|
471813
|
-
} else {
|
|
471814
|
-
cues[opts.key] = normalizeCueValue(opts.key, opts.value);
|
|
471815
|
-
}
|
|
471816
|
-
const remainingBody = cue ? section.body.slice(cue.full.length).replace(/^\s*\n/, "") : section.body.replace(/^\s*\n/, "");
|
|
471817
|
-
const cueBlock = Object.keys(cues).length > 0 ? "```yaml\n" + (0, import_yaml5.stringify)(cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
471818
|
-
const nextBody = cueBlock + remainingBody.trimStart();
|
|
471819
|
-
const nextSection = section.raw.slice(0, section.headingEnd - section.start) + "\n\n" + nextBody.trimEnd() + "\n";
|
|
471820
|
-
return markdown.slice(0, section.start) + nextSection + markdown.slice(section.end);
|
|
471821
|
-
}
|
|
471822
|
-
function moveStoryboardBeat(markdown, opts) {
|
|
471823
|
-
if (opts.beatId === opts.afterBeatId) return markdown;
|
|
471824
|
-
const sections = splitBeatSections(markdown);
|
|
471825
|
-
const movingIndex = sections.findIndex((section) => section.id === opts.beatId);
|
|
471826
|
-
if (movingIndex === -1) throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
471827
|
-
const afterIndex = sections.findIndex((section) => section.id === opts.afterBeatId);
|
|
471828
|
-
if (afterIndex === -1) throw new Error(`Beat "${opts.afterBeatId}" not found.`);
|
|
471829
|
-
const global3 = sections.length > 0 ? markdown.slice(0, sections[0].start) : markdown;
|
|
471830
|
-
const chunks = sections.map((section) => section.raw);
|
|
471831
|
-
const [moving] = chunks.splice(movingIndex, 1);
|
|
471832
|
-
const adjustedAfterIndex = movingIndex < afterIndex ? afterIndex - 1 : afterIndex;
|
|
471833
|
-
chunks.splice(adjustedAfterIndex + 1, 0, moving);
|
|
471834
|
-
return global3 + normalizeBeatChunks(chunks);
|
|
471835
|
-
}
|
|
471836
|
-
function normalizeBeatChunks(chunks) {
|
|
471837
|
-
return chunks.map((chunk) => chunk.trim()).filter(Boolean).join("\n\n") + "\n";
|
|
471838
|
-
}
|
|
471839
|
-
function normalizeCueValue(key2, value) {
|
|
471840
|
-
if (key2 === "duration") {
|
|
471841
|
-
const n2 = typeof value === "number" ? value : Number.parseFloat(String(value ?? ""));
|
|
471842
|
-
if (!Number.isFinite(n2) || n2 <= 0) {
|
|
471843
|
-
throw new Error("Cue duration must be a positive number.");
|
|
471844
|
-
}
|
|
471845
|
-
return n2;
|
|
471846
|
-
}
|
|
471847
|
-
if (typeof value !== "string") return value;
|
|
471848
|
-
return value.trim();
|
|
471849
|
-
}
|
|
471850
|
-
function splitBeatSections(markdown) {
|
|
471851
|
-
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
471852
|
-
const headings = [];
|
|
471853
|
-
HEADING_RE2.lastIndex = 0;
|
|
471854
|
-
let match2;
|
|
471855
|
-
while ((match2 = HEADING_RE2.exec(normalized)) !== null) {
|
|
471856
|
-
headings.push({ start: match2.index, end: match2.index + match2[0].length, line: match2[1].trim() });
|
|
471857
|
-
}
|
|
471858
|
-
return headings.map((heading, index) => {
|
|
471859
|
-
const end = index + 1 < headings.length ? headings[index + 1].start : normalized.length;
|
|
471860
|
-
return {
|
|
471861
|
-
id: deriveBeatId(heading.line),
|
|
471862
|
-
heading: heading.line,
|
|
471863
|
-
start: heading.start,
|
|
471864
|
-
headingEnd: heading.end,
|
|
471865
|
-
end,
|
|
471866
|
-
raw: normalized.slice(heading.start, end),
|
|
471867
|
-
body: normalized.slice(heading.end, end).trim()
|
|
471868
|
-
};
|
|
471869
|
-
});
|
|
471870
|
-
}
|
|
471871
|
-
function findBeatSection(markdown, beatId) {
|
|
471872
|
-
return splitBeatSections(markdown).find((section) => section.id === beatId) ?? null;
|
|
471873
|
-
}
|
|
471874
|
-
function readLeadingCueBlock(body) {
|
|
471875
|
-
const match2 = body.match(LEADING_CUE_RE);
|
|
471876
|
-
if (!match2) return null;
|
|
471877
|
-
try {
|
|
471878
|
-
const parsed = (0, import_yaml5.parse)(match2[2]);
|
|
471879
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
471880
|
-
return { full: match2[0], error: "cue block must parse to a YAML object" };
|
|
471881
|
-
}
|
|
471882
|
-
return { full: match2[0], value: parsed };
|
|
471883
|
-
} catch (error) {
|
|
471884
|
-
return { full: match2[0], error: error instanceof Error ? error.message : String(error) };
|
|
471885
|
-
}
|
|
471886
|
-
}
|
|
471887
|
-
var import_yaml5, STORYBOARD_CUE_KEYS, HEADING_RE2, LEADING_CUE_RE, ALLOWED_CUE_KEYS, STRING_CUE_KEYS, MAX_RECOMMENDED_BEAT_SEC;
|
|
471888
|
-
var init_storyboard_edit = __esm({
|
|
471889
|
-
"../cli/src/commands/_shared/storyboard-edit.ts"() {
|
|
471890
|
-
"use strict";
|
|
471891
|
-
import_yaml5 = __toESM(require_dist3(), 1);
|
|
471892
|
-
init_storyboard_parse();
|
|
471893
|
-
STORYBOARD_CUE_KEYS = [
|
|
471894
|
-
"duration",
|
|
471895
|
-
"narration",
|
|
471896
|
-
"backdrop",
|
|
471897
|
-
"video",
|
|
471898
|
-
"motion",
|
|
471899
|
-
"voice",
|
|
471900
|
-
"music",
|
|
471901
|
-
"asset"
|
|
471902
|
-
];
|
|
471903
|
-
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
471904
|
-
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
471905
|
-
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
471906
|
-
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "motion", "voice", "music", "asset"]);
|
|
471907
|
-
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
471908
|
-
}
|
|
471909
|
-
});
|
|
471910
|
-
|
|
471911
472749
|
// ../cli/src/commands/_shared/build-plan.ts
|
|
471912
472750
|
import { existsSync as existsSync33 } from "node:fs";
|
|
471913
472751
|
import { readFile as readFile17 } from "node:fs/promises";
|
|
471914
|
-
import { dirname as dirname17, join as
|
|
472752
|
+
import { dirname as dirname17, join as join30, resolve as resolve29 } from "node:path";
|
|
471915
472753
|
function backdropCostUsd(quality) {
|
|
471916
472754
|
return quality === "hd" ? 0.2 : 0.05;
|
|
471917
472755
|
}
|
|
@@ -471920,7 +472758,7 @@ async function createBuildPlan(opts) {
|
|
|
471920
472758
|
loadPlanEnv(projectDir);
|
|
471921
472759
|
const stage = opts.stage ?? "all";
|
|
471922
472760
|
const config4 = await readProjectConfig(projectDir);
|
|
471923
|
-
const storyboardPath =
|
|
472761
|
+
const storyboardPath = join30(projectDir, "STORYBOARD.md");
|
|
471924
472762
|
const warnings = [];
|
|
471925
472763
|
const retryWith = [];
|
|
471926
472764
|
const providerResolution = [];
|
|
@@ -471979,7 +472817,7 @@ async function createBuildPlan(opts) {
|
|
|
471979
472817
|
const imageQuality = opts.imageQuality ?? config4.config.build.imageQuality ?? "hd";
|
|
471980
472818
|
const imageSize2 = opts.imageSize ?? config4.config.build.imageSize ?? "1536x1024";
|
|
471981
472819
|
const imageRatio = imageRatioForSize(imageSize2);
|
|
471982
|
-
const needsComposer = includeCompose && mode !== "agent" && sourceBeats.some((beat) => !existsSync33(
|
|
472820
|
+
const needsComposer = includeCompose && mode !== "agent" && sourceBeats.some((beat) => !existsSync33(join30(projectDir, `compositions/scene-${beat.id}.html`)));
|
|
471983
472821
|
const resolved = await resolvePlanProviders({
|
|
471984
472822
|
projectDir,
|
|
471985
472823
|
config: config4,
|
|
@@ -472016,13 +472854,13 @@ async function createBuildPlan(opts) {
|
|
|
472016
472854
|
const backdropCue = backdropPrompt ?? backdropReference?.raw;
|
|
472017
472855
|
const videoCue = videoPrompt ?? videoReference?.raw;
|
|
472018
472856
|
const musicCue = musicPrompt ?? musicReference?.raw;
|
|
472019
|
-
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : 0;
|
|
472857
|
+
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : resolved.narration.resolved === "openai" ? OPENAI_NARRATION_COST_USD : 0;
|
|
472020
472858
|
const narrationCache = narrationText && !narrationReference ? narrationCacheDescriptor({
|
|
472021
472859
|
beatId: beat.id,
|
|
472022
472860
|
cue: narrationText,
|
|
472023
472861
|
provider: resolved.narration.resolved,
|
|
472024
472862
|
voice,
|
|
472025
|
-
ext: resolved.narration.resolved === "
|
|
472863
|
+
ext: resolved.narration.resolved === "kokoro" ? "wav" : "mp3"
|
|
472026
472864
|
}) : null;
|
|
472027
472865
|
const backdropCache = augmentedBackdropPrompt && !backdropReference ? backdropCacheDescriptor({
|
|
472028
472866
|
beatId: beat.id,
|
|
@@ -472083,7 +472921,11 @@ async function createBuildPlan(opts) {
|
|
|
472083
472921
|
reference: videoReference,
|
|
472084
472922
|
projectDir,
|
|
472085
472923
|
force: opts.force,
|
|
472086
|
-
cost:
|
|
472924
|
+
cost: resolved.video.resolved === "seedance" || resolved.video.resolved === "fal" ? estimateSeedanceVideoCostUsd({
|
|
472925
|
+
durationSec: normalizeVideoDuration(beat.duration),
|
|
472926
|
+
resolution: "720p",
|
|
472927
|
+
aspectRatio: "16:9"
|
|
472928
|
+
}) : VIDEO_COST_USD,
|
|
472087
472929
|
active: includeAssets
|
|
472088
472930
|
}) : null;
|
|
472089
472931
|
const music = musicCue && !opts.skipMusic ? assetPlan({
|
|
@@ -472100,7 +472942,7 @@ async function createBuildPlan(opts) {
|
|
|
472100
472942
|
active: includeAssets
|
|
472101
472943
|
}) : null;
|
|
472102
472944
|
const compositionPath = `compositions/scene-${beat.id}.html`;
|
|
472103
|
-
const compositionExists = existsSync33(
|
|
472945
|
+
const compositionExists = existsSync33(join30(projectDir, compositionPath));
|
|
472104
472946
|
for (const asset of [narration, backdrop, video, music]) {
|
|
472105
472947
|
if (!asset) continue;
|
|
472106
472948
|
if (asset.referenceError) {
|
|
@@ -472167,7 +473009,7 @@ async function createBuildPlan(opts) {
|
|
|
472167
473009
|
}
|
|
472168
473010
|
}
|
|
472169
473011
|
const validationOk = !validationIssues.some((issue) => issue.severity === "error");
|
|
472170
|
-
if (!existsSync33(
|
|
473012
|
+
if (!existsSync33(join30(projectDir, config4.config.composition.entry))) {
|
|
472171
473013
|
missing.add("root-composition");
|
|
472172
473014
|
if (validationOk) retryWith.push(`vibe build ${projectDir} --stage sync --json`);
|
|
472173
473015
|
}
|
|
@@ -472194,6 +473036,21 @@ async function createBuildPlan(opts) {
|
|
|
472194
473036
|
retryWith.push(skipCommand);
|
|
472195
473037
|
}
|
|
472196
473038
|
}
|
|
473039
|
+
if (validationOk && includeAssets && !opts.skipVideo) {
|
|
473040
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
473041
|
+
for (const beat of sourceBeats) {
|
|
473042
|
+
for (const name of beatCharacterNames(beat.cues)) referenced.add(name);
|
|
473043
|
+
}
|
|
473044
|
+
if (referenced.size > 0) {
|
|
473045
|
+
const toGenerate = resolveCharacters(parsed.frontmatter).filter(
|
|
473046
|
+
(c2) => referenced.has(c2.name) && c2.prompt && (opts.force || !existsSync33(join30(projectDir, `assets/character-${c2.name}.png`)))
|
|
473047
|
+
);
|
|
473048
|
+
if (toGenerate.length > 0) {
|
|
473049
|
+
estimatedCostUsd += toGenerate.length * backdropCostUsd(opts.imageQuality ?? "hd");
|
|
473050
|
+
missing.add("assets");
|
|
473051
|
+
}
|
|
473052
|
+
}
|
|
473053
|
+
}
|
|
472197
473054
|
return finalizeBuildPlan({
|
|
472198
473055
|
projectDir,
|
|
472199
473056
|
config: config4,
|
|
@@ -472299,8 +473156,8 @@ function assetPlan(opts) {
|
|
|
472299
473156
|
reason: ready ? "referenced-asset" : "invalid-reference"
|
|
472300
473157
|
};
|
|
472301
473158
|
}
|
|
472302
|
-
const canonicalExists = existsSync33(
|
|
472303
|
-
const cacheHit = opts.cache ? existsSync33(
|
|
473159
|
+
const canonicalExists = existsSync33(join30(opts.projectDir, opts.path));
|
|
473160
|
+
const cacheHit = opts.cache ? existsSync33(join30(opts.projectDir, opts.cache.path)) : false;
|
|
472304
473161
|
const freshness = assetFreshnessFromMetadata({
|
|
472305
473162
|
projectDir: opts.projectDir,
|
|
472306
473163
|
kind: opts.kind,
|
|
@@ -472440,17 +473297,20 @@ function providerInput(opts) {
|
|
|
472440
473297
|
async function resolveNarrationProvider(input3, projectDir) {
|
|
472441
473298
|
const requested = input3.value.toLowerCase();
|
|
472442
473299
|
const hasElevenLabs = Boolean(await getApiKeyFromConfig("elevenlabs", { cwd: projectDir }));
|
|
472443
|
-
const
|
|
473300
|
+
const hasOpenAi = Boolean(await getApiKeyFromConfig("openai", { cwd: projectDir }));
|
|
473301
|
+
const resolved = requested === "elevenlabs" ? "elevenlabs" : requested === "openai" ? "openai" : requested === "kokoro" ? "kokoro" : hasElevenLabs ? "elevenlabs" : hasOpenAi ? "openai" : "kokoro";
|
|
473302
|
+
const requiresKey = resolved !== "kokoro";
|
|
473303
|
+
const hasKey = resolved === "elevenlabs" ? hasElevenLabs : resolved === "openai" ? hasOpenAi : true;
|
|
472444
473304
|
return {
|
|
472445
473305
|
kind: "narration",
|
|
472446
473306
|
requested: input3.requested,
|
|
472447
473307
|
resolved,
|
|
472448
473308
|
source: input3.source,
|
|
472449
|
-
requiresKey
|
|
472450
|
-
configured:
|
|
472451
|
-
...
|
|
472452
|
-
...
|
|
472453
|
-
retryWith:
|
|
473309
|
+
requiresKey,
|
|
473310
|
+
configured: hasKey,
|
|
473311
|
+
...requiresKey ? { configKey: resolved } : {},
|
|
473312
|
+
...requiresKey && !hasKey ? { missingKey: providerEnvVar(resolved) } : {},
|
|
473313
|
+
retryWith: requiresKey && !hasKey ? ["vibe setup --full"] : []
|
|
472454
473314
|
};
|
|
472455
473315
|
}
|
|
472456
473316
|
async function keyedProviderResolution(opts, projectDir) {
|
|
@@ -472494,7 +473354,7 @@ async function firstConfiguredComposer(projectDir) {
|
|
|
472494
473354
|
}
|
|
472495
473355
|
function firstExisting2(projectDir, paths) {
|
|
472496
473356
|
for (const path14 of paths) {
|
|
472497
|
-
if (existsSync33(
|
|
473357
|
+
if (existsSync33(join30(projectDir, path14))) return path14;
|
|
472498
473358
|
}
|
|
472499
473359
|
return null;
|
|
472500
473360
|
}
|
|
@@ -472535,18 +473395,18 @@ function unique3(items) {
|
|
|
472535
473395
|
return [...new Set(items.filter((item) => item.length > 0))];
|
|
472536
473396
|
}
|
|
472537
473397
|
function loadPlanEnv(projectDir) {
|
|
472538
|
-
(0, import_dotenv2.config)({ path:
|
|
473398
|
+
(0, import_dotenv2.config)({ path: join30(projectDir, ".env"), quiet: true });
|
|
472539
473399
|
(0, import_dotenv2.config)({ path: resolve29(process.cwd(), ".env"), quiet: true });
|
|
472540
473400
|
let dir = process.cwd();
|
|
472541
473401
|
while (dir !== dirname17(dir)) {
|
|
472542
|
-
if (existsSync33(
|
|
472543
|
-
(0, import_dotenv2.config)({ path:
|
|
473402
|
+
if (existsSync33(join30(dir, "pnpm-workspace.yaml"))) {
|
|
473403
|
+
(0, import_dotenv2.config)({ path: join30(dir, ".env"), quiet: true });
|
|
472544
473404
|
return;
|
|
472545
473405
|
}
|
|
472546
473406
|
dir = dirname17(dir);
|
|
472547
473407
|
}
|
|
472548
473408
|
}
|
|
472549
|
-
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
473409
|
+
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, OPENAI_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
472550
473410
|
var init_build_plan = __esm({
|
|
472551
473411
|
"../cli/src/commands/_shared/build-plan.ts"() {
|
|
472552
473412
|
"use strict";
|
|
@@ -472555,6 +473415,7 @@ var init_build_plan = __esm({
|
|
|
472555
473415
|
init_schema();
|
|
472556
473416
|
init_build_asset_reference();
|
|
472557
473417
|
init_build_cache();
|
|
473418
|
+
init_dist();
|
|
472558
473419
|
init_build_asset_metadata();
|
|
472559
473420
|
init_build_backdrop_prompt();
|
|
472560
473421
|
init_composer_resolve();
|
|
@@ -472564,6 +473425,7 @@ var init_build_plan = __esm({
|
|
|
472564
473425
|
VIDEO_COST_USD = 5;
|
|
472565
473426
|
MUSIC_COST_USD = 0.5;
|
|
472566
473427
|
ELEVENLABS_NARRATION_COST_USD = 0.05;
|
|
473428
|
+
OPENAI_NARRATION_COST_USD = 0.01;
|
|
472567
473429
|
COMPOSE_COST_USD = 0.06;
|
|
472568
473430
|
SUPPORTED_BUILD_IMAGE_PROVIDERS = ["openai", "gemini", "grok"];
|
|
472569
473431
|
}
|
|
@@ -472886,9 +473748,9 @@ __export(scene_build_exports, {
|
|
|
472886
473748
|
executeSceneBuild: () => executeSceneBuild,
|
|
472887
473749
|
resolveSceneBuildMode: () => resolveSceneBuildMode
|
|
472888
473750
|
});
|
|
472889
|
-
import { existsSync as existsSync35 } from "node:fs";
|
|
473751
|
+
import { existsSync as existsSync35, readFileSync as readFileSync12 } from "node:fs";
|
|
472890
473752
|
import { copyFile as copyFile4, mkdir as mkdir13, readFile as readFile18, writeFile as writeFile20 } from "node:fs/promises";
|
|
472891
|
-
import { dirname as dirname18, join as
|
|
473753
|
+
import { dirname as dirname18, join as join31, resolve as resolve33 } from "node:path";
|
|
472892
473754
|
async function executeSceneBuild(opts) {
|
|
472893
473755
|
const startedAt = Date.now();
|
|
472894
473756
|
const projectDir = resolve33(opts.projectDir);
|
|
@@ -472900,7 +473762,7 @@ async function executeSceneBuild(opts) {
|
|
|
472900
473762
|
const warnings = [];
|
|
472901
473763
|
const retryWith = [];
|
|
472902
473764
|
let sceneRepair = skippedSceneRepairSummary();
|
|
472903
|
-
const storyboardPath =
|
|
473765
|
+
const storyboardPath = join31(projectDir, "STORYBOARD.md");
|
|
472904
473766
|
const buildPlan = await createBuildPlan({
|
|
472905
473767
|
projectDir,
|
|
472906
473768
|
stage: selectedStage,
|
|
@@ -473053,8 +473915,32 @@ async function executeSceneBuild(opts) {
|
|
|
473053
473915
|
const voice = opts.voice ?? parsed.frontmatter?.voice;
|
|
473054
473916
|
let beatOutcomes = collectExistingBeatOutcomes(parsed.beats, projectDir);
|
|
473055
473917
|
let pendingJobs = [];
|
|
473918
|
+
let characterCostUsd = 0;
|
|
473056
473919
|
if (shouldRunStage(selectedStage, "assets")) {
|
|
473057
473920
|
onProgress({ type: "phase-start", phase: "primitives" });
|
|
473921
|
+
const characterPaths = /* @__PURE__ */ new Map();
|
|
473922
|
+
if (!(opts.skipVideo ?? false)) {
|
|
473923
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
473924
|
+
for (const beat of activeBeats) {
|
|
473925
|
+
for (const name of beatCharacterNames(beat.cues)) referenced.add(name);
|
|
473926
|
+
}
|
|
473927
|
+
if (referenced.size > 0) {
|
|
473928
|
+
const charResult = await buildCharacters(
|
|
473929
|
+
resolveCharacters(parsed.frontmatter).filter((c2) => referenced.has(c2.name)),
|
|
473930
|
+
{
|
|
473931
|
+
projectDir,
|
|
473932
|
+
imageProvider,
|
|
473933
|
+
imageSize: opts.imageSize ?? "1536x1024",
|
|
473934
|
+
imageQuality: opts.imageQuality ?? "hd",
|
|
473935
|
+
force: opts.force ?? false,
|
|
473936
|
+
onProgress
|
|
473937
|
+
}
|
|
473938
|
+
);
|
|
473939
|
+
for (const [name, path14] of charResult.paths) characterPaths.set(name, path14);
|
|
473940
|
+
characterCostUsd = charResult.costUsd;
|
|
473941
|
+
warnings.push(...charResult.failures);
|
|
473942
|
+
}
|
|
473943
|
+
}
|
|
473058
473944
|
const primitiveResults = await mapWithConcurrency(
|
|
473059
473945
|
activeBeats,
|
|
473060
473946
|
BEAT_PRIMITIVES_CONCURRENCY,
|
|
@@ -473072,7 +473958,8 @@ async function executeSceneBuild(opts) {
|
|
|
473072
473958
|
skipVideo: opts.skipVideo ?? false,
|
|
473073
473959
|
skipMusic: opts.skipMusic ?? false,
|
|
473074
473960
|
force: opts.force ?? false,
|
|
473075
|
-
onProgress
|
|
473961
|
+
onProgress,
|
|
473962
|
+
characterPaths
|
|
473076
473963
|
})
|
|
473077
473964
|
);
|
|
473078
473965
|
beatOutcomes = primitiveResults.map((result) => result.outcome);
|
|
@@ -473081,10 +473968,7 @@ async function executeSceneBuild(opts) {
|
|
|
473081
473968
|
(beat) => beat.narrationStatus === "failed" || beat.backdropStatus === "failed" || beat.videoStatus === "failed" || beat.musicStatus === "failed"
|
|
473082
473969
|
);
|
|
473083
473970
|
stageReports.assets.status = assetFailed ? "failed" : pendingJobs.length > 0 ? "pending-jobs" : "done";
|
|
473084
|
-
stageReports.assets.costUsd = estimateActualAssetCost(
|
|
473085
|
-
beatOutcomes,
|
|
473086
|
-
opts.imageQuality ?? "hd"
|
|
473087
|
-
);
|
|
473971
|
+
stageReports.assets.costUsd = estimateActualAssetCost(beatOutcomes, opts.imageQuality ?? "hd") + characterCostUsd;
|
|
473088
473972
|
stageReports.assets.retryWith = pendingJobs.map(
|
|
473089
473973
|
(job) => `vibe status job ${job.id} --project ${projectDir} --json`
|
|
473090
473974
|
);
|
|
@@ -473160,9 +474044,9 @@ async function executeSceneBuild(opts) {
|
|
|
473160
474044
|
let composeData;
|
|
473161
474045
|
if (shouldRunStage(selectedStage, "compose")) {
|
|
473162
474046
|
if (mode === "agent") {
|
|
473163
|
-
const compositionsDir =
|
|
474047
|
+
const compositionsDir = join31(projectDir, "compositions");
|
|
473164
474048
|
const missingBeats = activeBeats.filter(
|
|
473165
|
-
(b2) => !existsSync35(
|
|
474049
|
+
(b2) => !existsSync35(join31(compositionsDir, `scene-${b2.id}.html`))
|
|
473166
474050
|
);
|
|
473167
474051
|
if (missingBeats.length > 0) {
|
|
473168
474052
|
const plan = await getComposePrompts({ projectDir, beatId: opts.beatId });
|
|
@@ -473249,6 +474133,18 @@ async function executeSceneBuild(opts) {
|
|
|
473249
474133
|
stageReports.compose.status = "skipped";
|
|
473250
474134
|
}
|
|
473251
474135
|
if (stageReports.compose.status === "done") {
|
|
474136
|
+
for (const beat of activeBeats) {
|
|
474137
|
+
const videoRel = `assets/video-${beat.id}.mp4`;
|
|
474138
|
+
const compositionAbs = join31(projectDir, "compositions", `scene-${beat.id}.html`);
|
|
474139
|
+
if (!existsSync35(join31(projectDir, videoRel)) || !existsSync35(compositionAbs)) continue;
|
|
474140
|
+
const html = readFileSync12(compositionAbs, "utf-8");
|
|
474141
|
+
if (!html.includes(videoRel)) {
|
|
474142
|
+
warnings.push(
|
|
474143
|
+
`Beat "${beat.id}" has a generated clip (${videoRel}) but its composition does not reference it, so the clip will not appear. Recompose the beat.`
|
|
474144
|
+
);
|
|
474145
|
+
retryWith.push(`vibe build ${projectDir} --beat ${beat.id} --stage compose --force --json`);
|
|
474146
|
+
}
|
|
474147
|
+
}
|
|
473252
474148
|
const repair = await runBuildSceneRepair(projectDir, "compose", false);
|
|
473253
474149
|
sceneRepair = mergeSceneRepairSummaries(sceneRepair, repair);
|
|
473254
474150
|
applySceneRepairToStage(stageReports.compose, repair);
|
|
@@ -473298,7 +474194,7 @@ async function executeSceneBuild(opts) {
|
|
|
473298
474194
|
});
|
|
473299
474195
|
}
|
|
473300
474196
|
if (shouldRunStage(selectedStage, "sync")) {
|
|
473301
|
-
if (!existsSync35(
|
|
474197
|
+
if (!existsSync35(join31(projectDir, "index.html"))) {
|
|
473302
474198
|
await scaffoldSceneProject({
|
|
473303
474199
|
dir: projectDir,
|
|
473304
474200
|
name: projectDir.split(/[\\/]/).filter(Boolean).pop(),
|
|
@@ -473557,7 +474453,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473557
474453
|
return {
|
|
473558
474454
|
status: "cached",
|
|
473559
474455
|
path: existingRel,
|
|
473560
|
-
durationSec: await safeAudioDuration(
|
|
474456
|
+
durationSec: await safeAudioDuration(join31(ctx.projectDir, existingRel)),
|
|
473561
474457
|
provider: metadata?.provider,
|
|
473562
474458
|
cachePath: metadata?.cachePath,
|
|
473563
474459
|
cacheKey: metadata?.cacheKey,
|
|
@@ -473581,9 +474477,9 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473581
474477
|
voice,
|
|
473582
474478
|
ext: resolution.audioExtension
|
|
473583
474479
|
});
|
|
473584
|
-
const cacheAbs =
|
|
474480
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
473585
474481
|
const rel = `assets/narration-${beat.id}.${resolution.audioExtension}`;
|
|
473586
|
-
const abs =
|
|
474482
|
+
const abs = join31(ctx.projectDir, rel);
|
|
473587
474483
|
if (existingRel && !ctx.force && isFreshCanonicalAsset({
|
|
473588
474484
|
projectDir: ctx.projectDir,
|
|
473589
474485
|
kind: "narration",
|
|
@@ -473597,7 +474493,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473597
474493
|
return {
|
|
473598
474494
|
status: "cached",
|
|
473599
474495
|
path: existingRel,
|
|
473600
|
-
durationSec: await safeAudioDuration(
|
|
474496
|
+
durationSec: await safeAudioDuration(join31(ctx.projectDir, existingRel)),
|
|
473601
474497
|
provider: resolution.provider,
|
|
473602
474498
|
cachePath: cache.path,
|
|
473603
474499
|
cacheKey: cache.key,
|
|
@@ -473669,6 +474565,120 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473669
474565
|
freshness: "fresh"
|
|
473670
474566
|
};
|
|
473671
474567
|
}
|
|
474568
|
+
function characterSheetPrompt(name, description) {
|
|
474569
|
+
return [
|
|
474570
|
+
`Character turnaround reference sheet of an original fictional character named ${name}: ${description}.`,
|
|
474571
|
+
"Show three full-body views side by side on one clean canvas \u2014 front view, side profile, and back view \u2014",
|
|
474572
|
+
"with identical outfit, hairstyle, hair color, and body proportions across all three views.",
|
|
474573
|
+
"Plain light-grey studio background, even neutral lighting, no props.",
|
|
474574
|
+
"Photorealistic digital character, professional concept-art character sheet layout."
|
|
474575
|
+
].join(" ");
|
|
474576
|
+
}
|
|
474577
|
+
async function buildCharacters(characters, ctx) {
|
|
474578
|
+
const paths = /* @__PURE__ */ new Map();
|
|
474579
|
+
const failures = [];
|
|
474580
|
+
let costUsd = 0;
|
|
474581
|
+
const size = ctx.imageSize ?? "1536x1024";
|
|
474582
|
+
for (const character of characters) {
|
|
474583
|
+
if (character.imagePath) {
|
|
474584
|
+
if (existsSync35(join31(ctx.projectDir, character.imagePath))) {
|
|
474585
|
+
paths.set(character.name, character.imagePath);
|
|
474586
|
+
ctx.onProgress({ type: "character-cached", name: character.name, path: character.imagePath });
|
|
474587
|
+
} else {
|
|
474588
|
+
const error = `character "${character.name}" image not found: ${character.imagePath}`;
|
|
474589
|
+
failures.push(error);
|
|
474590
|
+
ctx.onProgress({ type: "character-failed", name: character.name, error });
|
|
474591
|
+
}
|
|
474592
|
+
continue;
|
|
474593
|
+
}
|
|
474594
|
+
if (!character.prompt) continue;
|
|
474595
|
+
const prompt3 = characterSheetPrompt(character.name, character.prompt);
|
|
474596
|
+
const rel = `assets/character-${character.name}.png`;
|
|
474597
|
+
const abs = join31(ctx.projectDir, rel);
|
|
474598
|
+
const metadataOptions = { quality: ctx.imageQuality, size };
|
|
474599
|
+
const cache = characterCacheDescriptor({
|
|
474600
|
+
name: character.name,
|
|
474601
|
+
cue: prompt3,
|
|
474602
|
+
provider: ctx.imageProvider,
|
|
474603
|
+
quality: ctx.imageQuality,
|
|
474604
|
+
size
|
|
474605
|
+
});
|
|
474606
|
+
if (existsSync35(abs) && !ctx.force) {
|
|
474607
|
+
const metadata = readAssetMetadata(ctx.projectDir, "character", character.name);
|
|
474608
|
+
if (!metadata || isFreshCanonicalAsset({
|
|
474609
|
+
projectDir: ctx.projectDir,
|
|
474610
|
+
kind: "character",
|
|
474611
|
+
beatId: character.name,
|
|
474612
|
+
cue: prompt3,
|
|
474613
|
+
provider: ctx.imageProvider,
|
|
474614
|
+
options: metadataOptions,
|
|
474615
|
+
cacheKey: cache.key
|
|
474616
|
+
})) {
|
|
474617
|
+
paths.set(character.name, rel);
|
|
474618
|
+
ctx.onProgress({ type: "character-cached", name: character.name, path: rel });
|
|
474619
|
+
continue;
|
|
474620
|
+
}
|
|
474621
|
+
}
|
|
474622
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474623
|
+
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474624
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474625
|
+
await copyFile4(cacheAbs, abs);
|
|
474626
|
+
await writeAssetMetadata({
|
|
474627
|
+
projectDir: ctx.projectDir,
|
|
474628
|
+
kind: "character",
|
|
474629
|
+
beatId: character.name,
|
|
474630
|
+
cue: prompt3,
|
|
474631
|
+
provider: ctx.imageProvider,
|
|
474632
|
+
options: metadataOptions,
|
|
474633
|
+
cacheKey: cache.key,
|
|
474634
|
+
canonicalPath: rel,
|
|
474635
|
+
cachePath: cache.path
|
|
474636
|
+
});
|
|
474637
|
+
paths.set(character.name, rel);
|
|
474638
|
+
ctx.onProgress({ type: "character-cached", name: character.name, path: rel });
|
|
474639
|
+
continue;
|
|
474640
|
+
}
|
|
474641
|
+
const generated = await generateBackdropImage(
|
|
474642
|
+
prompt3,
|
|
474643
|
+
{
|
|
474644
|
+
projectDir: ctx.projectDir,
|
|
474645
|
+
imageProvider: ctx.imageProvider,
|
|
474646
|
+
imageSize: size,
|
|
474647
|
+
imageQuality: ctx.imageQuality
|
|
474648
|
+
},
|
|
474649
|
+
imageRatioForSize(size)
|
|
474650
|
+
);
|
|
474651
|
+
if (!generated.success) {
|
|
474652
|
+
failures.push(`character "${character.name}": ${generated.error}`);
|
|
474653
|
+
ctx.onProgress({ type: "character-failed", name: character.name, error: generated.error });
|
|
474654
|
+
continue;
|
|
474655
|
+
}
|
|
474656
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474657
|
+
await writeFile20(abs, generated.buffer);
|
|
474658
|
+
await mkdir13(dirname18(cacheAbs), { recursive: true });
|
|
474659
|
+
await writeFile20(cacheAbs, generated.buffer);
|
|
474660
|
+
await writeAssetMetadata({
|
|
474661
|
+
projectDir: ctx.projectDir,
|
|
474662
|
+
kind: "character",
|
|
474663
|
+
beatId: character.name,
|
|
474664
|
+
cue: prompt3,
|
|
474665
|
+
provider: ctx.imageProvider,
|
|
474666
|
+
options: metadataOptions,
|
|
474667
|
+
cacheKey: cache.key,
|
|
474668
|
+
canonicalPath: rel,
|
|
474669
|
+
cachePath: cache.path
|
|
474670
|
+
});
|
|
474671
|
+
costUsd += backdropCostUsd(ctx.imageQuality);
|
|
474672
|
+
paths.set(character.name, rel);
|
|
474673
|
+
ctx.onProgress({
|
|
474674
|
+
type: "character-generated",
|
|
474675
|
+
name: character.name,
|
|
474676
|
+
path: rel,
|
|
474677
|
+
provider: ctx.imageProvider
|
|
474678
|
+
});
|
|
474679
|
+
}
|
|
474680
|
+
return { paths, costUsd: Number(costUsd.toFixed(2)), failures };
|
|
474681
|
+
}
|
|
473672
474682
|
async function dispatchBackdrop(beat, ctx) {
|
|
473673
474683
|
const reference = assetReferenceForBeat(ctx.projectDir, "backdrop", beat);
|
|
473674
474684
|
if (reference) return referencePrimitiveOutcome("backdrop", beat, ctx, reference);
|
|
@@ -473676,7 +474686,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
473676
474686
|
if (!cue) return { status: "no-cue" };
|
|
473677
474687
|
const prompt3 = augmentBackdropPrompt(cue);
|
|
473678
474688
|
const rel = `assets/backdrop-${beat.id}.png`;
|
|
473679
|
-
const abs =
|
|
474689
|
+
const abs = join31(ctx.projectDir, rel);
|
|
473680
474690
|
const size = ctx.imageSize ?? "1536x1024";
|
|
473681
474691
|
const ratio = imageRatioForSize(size);
|
|
473682
474692
|
const metadataOptions = { quality: ctx.imageQuality, size, ratio };
|
|
@@ -473712,7 +474722,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
473712
474722
|
};
|
|
473713
474723
|
}
|
|
473714
474724
|
}
|
|
473715
|
-
const cacheAbs =
|
|
474725
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
473716
474726
|
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
473717
474727
|
await mkdir13(dirname18(abs), { recursive: true });
|
|
473718
474728
|
await copyFile4(cacheAbs, abs);
|
|
@@ -473838,13 +474848,16 @@ async function dispatchVideo(beat, ctx) {
|
|
|
473838
474848
|
if (reference) return referencePrimitiveOutcome("video", beat, ctx, reference);
|
|
473839
474849
|
const prompt3 = stringOrUndefined4(beat.cues?.video);
|
|
473840
474850
|
if (!prompt3) return { status: "no-cue" };
|
|
474851
|
+
const characterRefsRel = beatCharacterNames(beat.cues).map((name) => ctx.characterPaths?.get(name)).filter((p2) => typeof p2 === "string");
|
|
474852
|
+
const characterRefsAbs = characterRefsRel.map((p2) => join31(ctx.projectDir, p2));
|
|
473841
474853
|
const rel = `assets/video-${beat.id}.mp4`;
|
|
473842
|
-
const abs =
|
|
474854
|
+
const abs = join31(ctx.projectDir, rel);
|
|
473843
474855
|
const cache = videoCacheDescriptor({
|
|
473844
474856
|
beatId: beat.id,
|
|
473845
474857
|
cue: prompt3,
|
|
473846
474858
|
provider: ctx.videoProvider,
|
|
473847
|
-
duration: normalizeVideoDuration(beat.duration)
|
|
474859
|
+
duration: normalizeVideoDuration(beat.duration),
|
|
474860
|
+
characters: characterRefsRel
|
|
473848
474861
|
});
|
|
473849
474862
|
const metadataPath = assetMetadataPath("video", beat.id);
|
|
473850
474863
|
if (existsSync35(abs) && !ctx.force) {
|
|
@@ -473870,7 +474883,7 @@ async function dispatchVideo(beat, ctx) {
|
|
|
473870
474883
|
};
|
|
473871
474884
|
}
|
|
473872
474885
|
}
|
|
473873
|
-
const cacheAbs =
|
|
474886
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
473874
474887
|
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
473875
474888
|
await mkdir13(dirname18(abs), { recursive: true });
|
|
473876
474889
|
await copyFile4(cacheAbs, abs);
|
|
@@ -473904,6 +474917,7 @@ async function dispatchVideo(beat, ctx) {
|
|
|
473904
474917
|
ratio: "16:9",
|
|
473905
474918
|
output: abs,
|
|
473906
474919
|
wait: false,
|
|
474920
|
+
refImages: characterRefsAbs.length > 0 ? characterRefsAbs : void 0,
|
|
473907
474921
|
apiKey: await apiKeyForVideoProvider(ctx.videoProvider, ctx.projectDir)
|
|
473908
474922
|
});
|
|
473909
474923
|
if (!result.success || !result.taskId) {
|
|
@@ -473979,7 +474993,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
473979
474993
|
const prompt3 = stringOrUndefined4(beat.cues?.music);
|
|
473980
474994
|
if (!prompt3) return { status: "no-cue" };
|
|
473981
474995
|
const rel = `assets/music-${beat.id}.mp3`;
|
|
473982
|
-
const abs =
|
|
474996
|
+
const abs = join31(ctx.projectDir, rel);
|
|
473983
474997
|
const duration = normalizeMusicDuration(beat.duration);
|
|
473984
474998
|
const cache = musicCacheDescriptor({
|
|
473985
474999
|
beatId: beat.id,
|
|
@@ -474012,7 +475026,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
474012
475026
|
};
|
|
474013
475027
|
}
|
|
474014
475028
|
}
|
|
474015
|
-
const cacheAbs =
|
|
475029
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474016
475030
|
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474017
475031
|
await mkdir13(dirname18(abs), { recursive: true });
|
|
474018
475032
|
await copyFile4(cacheAbs, abs);
|
|
@@ -474123,12 +475137,12 @@ async function dispatchMusic(beat, ctx) {
|
|
|
474123
475137
|
};
|
|
474124
475138
|
}
|
|
474125
475139
|
function loadSceneBuildEnv(projectDir) {
|
|
474126
|
-
(0, import_dotenv3.config)({ path:
|
|
475140
|
+
(0, import_dotenv3.config)({ path: join31(projectDir, ".env"), quiet: true });
|
|
474127
475141
|
(0, import_dotenv3.config)({ path: resolve33(process.cwd(), ".env"), quiet: true });
|
|
474128
475142
|
let dir = process.cwd();
|
|
474129
475143
|
while (dir !== dirname18(dir)) {
|
|
474130
|
-
if (existsSync35(
|
|
474131
|
-
(0, import_dotenv3.config)({ path:
|
|
475144
|
+
if (existsSync35(join31(dir, "pnpm-workspace.yaml"))) {
|
|
475145
|
+
(0, import_dotenv3.config)({ path: join31(dir, ".env"), quiet: true });
|
|
474132
475146
|
return;
|
|
474133
475147
|
}
|
|
474134
475148
|
dir = dirname18(dir);
|
|
@@ -474272,7 +475286,13 @@ function estimateActualAssetCost(outcomes, imageQuality) {
|
|
|
474272
475286
|
for (const outcome of outcomes) {
|
|
474273
475287
|
if (outcome.narrationStatus === "generated") cost += 0.05;
|
|
474274
475288
|
if (outcome.backdropStatus === "generated") cost += backdropCostUsd(imageQuality);
|
|
474275
|
-
if (outcome.videoStatus === "generated" || outcome.videoStatus === "pending")
|
|
475289
|
+
if (outcome.videoStatus === "generated" || outcome.videoStatus === "pending") {
|
|
475290
|
+
cost += outcome.videoProvider === "seedance" || outcome.videoProvider === "fal" ? estimateSeedanceVideoCostUsd({
|
|
475291
|
+
durationSec: normalizeVideoDuration(outcome.sceneDurationSec),
|
|
475292
|
+
resolution: "720p",
|
|
475293
|
+
aspectRatio: "16:9"
|
|
475294
|
+
}) : 5;
|
|
475295
|
+
}
|
|
474276
475296
|
if (outcome.musicStatus === "generated" || outcome.musicStatus === "pending") cost += 0.5;
|
|
474277
475297
|
}
|
|
474278
475298
|
return Number(cost.toFixed(2));
|
|
@@ -474337,7 +475357,7 @@ function mergeBeatOutcomes(base, updates) {
|
|
|
474337
475357
|
}
|
|
474338
475358
|
function firstExisting3(projectDir, relPaths) {
|
|
474339
475359
|
for (const rel of relPaths) {
|
|
474340
|
-
if (existsSync35(
|
|
475360
|
+
if (existsSync35(join31(projectDir, rel))) return rel;
|
|
474341
475361
|
}
|
|
474342
475362
|
return null;
|
|
474343
475363
|
}
|
|
@@ -474368,7 +475388,7 @@ async function apiKeyForVideoProvider(provider, projectDir) {
|
|
|
474368
475388
|
return getApiKeyFromConfig(providerKey, { cwd: projectDir });
|
|
474369
475389
|
}
|
|
474370
475390
|
async function finalizeBuildResult(projectDir, startedAt, result) {
|
|
474371
|
-
const reportPath =
|
|
475391
|
+
const reportPath = join31(projectDir, "build-report.json");
|
|
474372
475392
|
if (result.stageReports) {
|
|
474373
475393
|
for (const report of Object.values(result.stageReports)) {
|
|
474374
475394
|
if (report.status === "pending") report.status = "skipped";
|
|
@@ -474527,7 +475547,7 @@ function normalizeReportDuration(value) {
|
|
|
474527
475547
|
}
|
|
474528
475548
|
function buildReportComposition(projectDir, result, beatId) {
|
|
474529
475549
|
const path14 = `compositions/scene-${beatId}.html`;
|
|
474530
|
-
const exists = existsSync35(
|
|
475550
|
+
const exists = existsSync35(join31(projectDir, path14));
|
|
474531
475551
|
const written = composeWrittenEntry(result, beatId);
|
|
474532
475552
|
if (written) {
|
|
474533
475553
|
return {
|
|
@@ -474584,7 +475604,7 @@ function summarizeBuildBeats(projectDir, beats) {
|
|
|
474584
475604
|
let compositionsReady = 0;
|
|
474585
475605
|
for (const beat of beats) {
|
|
474586
475606
|
if (beatAssetsReady(beat)) assetsReady += 1;
|
|
474587
|
-
const compositionPath =
|
|
475607
|
+
const compositionPath = join31(projectDir, "compositions", `scene-${beat.beatId}.html`);
|
|
474588
475608
|
if (existsSync35(compositionPath)) {
|
|
474589
475609
|
compositionsReady += 1;
|
|
474590
475610
|
} else {
|
|
@@ -475240,7 +476260,7 @@ var init_silence_cut = __esm({
|
|
|
475240
476260
|
// ../cli/src/commands/_shared/edit/jump-cut.ts
|
|
475241
476261
|
import { existsSync as existsSync38 } from "node:fs";
|
|
475242
476262
|
import { readFile as readFile21, writeFile as writeFile22, mkdir as mkdir14 } from "node:fs/promises";
|
|
475243
|
-
import { join as
|
|
476263
|
+
import { join as join33 } from "node:path";
|
|
475244
476264
|
async function transcribeWithWords(audioPath, apiKey, language) {
|
|
475245
476265
|
const audioBuffer = await readFile21(audioPath);
|
|
475246
476266
|
const audioBlob = new Blob([audioBuffer]);
|
|
@@ -475320,7 +476340,7 @@ async function executeJumpCut(options) {
|
|
|
475320
476340
|
try {
|
|
475321
476341
|
const tmpDir = `/tmp/vibe_jumpcut_${Date.now()}`;
|
|
475322
476342
|
await mkdir14(tmpDir, { recursive: true });
|
|
475323
|
-
const audioPath =
|
|
476343
|
+
const audioPath = join33(tmpDir, "audio.wav");
|
|
475324
476344
|
try {
|
|
475325
476345
|
await execSafe(
|
|
475326
476346
|
"ffmpeg",
|
|
@@ -475374,7 +476394,7 @@ async function executeJumpCut(options) {
|
|
|
475374
476394
|
const segmentPaths = [];
|
|
475375
476395
|
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
475376
476396
|
const seg = segments[i2];
|
|
475377
|
-
const segPath =
|
|
476397
|
+
const segPath = join33(tmpDir, `seg-${i2.toString().padStart(4, "0")}.ts`);
|
|
475378
476398
|
const duration = seg.end - seg.start;
|
|
475379
476399
|
await execSafe(
|
|
475380
476400
|
"ffmpeg",
|
|
@@ -475397,7 +476417,7 @@ async function executeJumpCut(options) {
|
|
|
475397
476417
|
segmentPaths.push(segPath);
|
|
475398
476418
|
}
|
|
475399
476419
|
const concatList = segmentPaths.map((p2) => `file '${p2}'`).join("\n");
|
|
475400
|
-
const listPath =
|
|
476420
|
+
const listPath = join33(tmpDir, "concat.txt");
|
|
475401
476421
|
await writeFile22(listPath, concatList);
|
|
475402
476422
|
await execSafe(
|
|
475403
476423
|
"ffmpeg",
|
|
@@ -475505,7 +476525,7 @@ __export(remotion_exports, {
|
|
|
475505
476525
|
});
|
|
475506
476526
|
import { writeFile as writeFile23, mkdir as mkdir15, rm as rm3, copyFile as copyFile5 } from "node:fs/promises";
|
|
475507
476527
|
import { existsSync as existsSync39 } from "node:fs";
|
|
475508
|
-
import { join as
|
|
476528
|
+
import { join as join34 } from "node:path";
|
|
475509
476529
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
475510
476530
|
import { createHash as createHash7 } from "node:crypto";
|
|
475511
476531
|
async function ensureRemotionInstalled() {
|
|
@@ -475524,7 +476544,7 @@ async function ensureRemotionInstalled() {
|
|
|
475524
476544
|
}
|
|
475525
476545
|
}
|
|
475526
476546
|
async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
475527
|
-
const dir =
|
|
476547
|
+
const dir = join34(tmpdir3(), `vibe_motion_${Date.now()}`);
|
|
475528
476548
|
await mkdir15(dir, { recursive: true });
|
|
475529
476549
|
const deps = {
|
|
475530
476550
|
remotion: REMOTION_VERSION,
|
|
@@ -475543,7 +476563,7 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
475543
476563
|
dependencies: deps
|
|
475544
476564
|
};
|
|
475545
476565
|
const packageJsonStr = JSON.stringify(packageJson, null, 2);
|
|
475546
|
-
await writeFile23(
|
|
476566
|
+
await writeFile23(join34(dir, "package.json"), packageJsonStr);
|
|
475547
476567
|
const tsconfig = {
|
|
475548
476568
|
compilerOptions: {
|
|
475549
476569
|
target: "ES2020",
|
|
@@ -475555,8 +476575,8 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
475555
476575
|
skipLibCheck: true
|
|
475556
476576
|
}
|
|
475557
476577
|
};
|
|
475558
|
-
await writeFile23(
|
|
475559
|
-
await writeFile23(
|
|
476578
|
+
await writeFile23(join34(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
476579
|
+
await writeFile23(join34(dir, "Component.tsx"), componentCode);
|
|
475560
476580
|
const rootCode = `import { registerRoot, Composition } from "remotion";
|
|
475561
476581
|
import { ${componentName} } from "./Component";
|
|
475562
476582
|
|
|
@@ -475575,14 +476595,14 @@ const Root = () => {
|
|
|
475575
476595
|
|
|
475576
476596
|
registerRoot(Root);
|
|
475577
476597
|
`;
|
|
475578
|
-
await writeFile23(
|
|
476598
|
+
await writeFile23(join34(dir, "Root.tsx"), rootCode);
|
|
475579
476599
|
const depsHash = createHash7("md5").update(packageJsonStr).digest("hex").slice(0, 12);
|
|
475580
|
-
const cacheMarker =
|
|
475581
|
-
const cachedModules =
|
|
476600
|
+
const cacheMarker = join34(REMOTION_CACHE_DIR, `.deps-${depsHash}`);
|
|
476601
|
+
const cachedModules = join34(REMOTION_CACHE_DIR, "node_modules");
|
|
475582
476602
|
if (existsSync39(cacheMarker) && existsSync39(cachedModules)) {
|
|
475583
476603
|
const { symlink } = await import("node:fs/promises");
|
|
475584
476604
|
try {
|
|
475585
|
-
await symlink(cachedModules,
|
|
476605
|
+
await symlink(cachedModules, join34(dir, "node_modules"), "dir");
|
|
475586
476606
|
} catch {
|
|
475587
476607
|
await this_npmInstall(dir);
|
|
475588
476608
|
}
|
|
@@ -475590,12 +476610,12 @@ registerRoot(Root);
|
|
|
475590
476610
|
await this_npmInstall(dir);
|
|
475591
476611
|
try {
|
|
475592
476612
|
await mkdir15(REMOTION_CACHE_DIR, { recursive: true });
|
|
475593
|
-
await writeFile23(
|
|
475594
|
-
if (existsSync39(
|
|
476613
|
+
await writeFile23(join34(REMOTION_CACHE_DIR, "package.json"), packageJsonStr);
|
|
476614
|
+
if (existsSync39(join34(dir, "node_modules"))) {
|
|
475595
476615
|
const { rename: rename7, symlink } = await import("node:fs/promises");
|
|
475596
|
-
await rename7(
|
|
476616
|
+
await rename7(join34(dir, "node_modules"), cachedModules).catch(() => {
|
|
475597
476617
|
});
|
|
475598
|
-
await symlink(cachedModules,
|
|
476618
|
+
await symlink(cachedModules, join34(dir, "node_modules"), "dir").catch(() => {
|
|
475599
476619
|
});
|
|
475600
476620
|
await writeFile23(cacheMarker, depsHash);
|
|
475601
476621
|
}
|
|
@@ -475632,7 +476652,7 @@ async function renderMotion(options) {
|
|
|
475632
476652
|
}
|
|
475633
476653
|
);
|
|
475634
476654
|
try {
|
|
475635
|
-
const entryPoint =
|
|
476655
|
+
const entryPoint = join34(dir, "Root.tsx");
|
|
475636
476656
|
const { execFile: execFile3 } = await import("node:child_process");
|
|
475637
476657
|
const { promisify: promisify3 } = await import("node:util");
|
|
475638
476658
|
const execFileAsync3 = promisify3(execFile3);
|
|
@@ -475765,10 +476785,10 @@ async function renderWithEmbeddedImage(options) {
|
|
|
475765
476785
|
}
|
|
475766
476786
|
);
|
|
475767
476787
|
try {
|
|
475768
|
-
const publicDir =
|
|
476788
|
+
const publicDir = join34(dir, "public");
|
|
475769
476789
|
await mkdir15(publicDir, { recursive: true });
|
|
475770
|
-
await copyFile5(options.imagePath,
|
|
475771
|
-
const entryPoint =
|
|
476790
|
+
await copyFile5(options.imagePath, join34(publicDir, options.imageFileName));
|
|
476791
|
+
const entryPoint = join34(dir, "Root.tsx");
|
|
475772
476792
|
const mp4Out = options.outputPath.replace(/\.\w+$/, ".mp4");
|
|
475773
476793
|
const { execFile: execFileImg } = await import("node:child_process");
|
|
475774
476794
|
const { promisify: promisifyImg } = await import("node:util");
|
|
@@ -475829,10 +476849,10 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
475829
476849
|
}
|
|
475830
476850
|
);
|
|
475831
476851
|
try {
|
|
475832
|
-
const publicDir =
|
|
476852
|
+
const publicDir = join34(dir, "public");
|
|
475833
476853
|
await mkdir15(publicDir, { recursive: true });
|
|
475834
|
-
await copyFile5(options.videoPath,
|
|
475835
|
-
const entryPoint =
|
|
476854
|
+
await copyFile5(options.videoPath, join34(publicDir, options.videoFileName));
|
|
476855
|
+
const entryPoint = join34(dir, "Root.tsx");
|
|
475836
476856
|
const mp4VideoOnly = options.outputPath.replace(/\.\w+$/, "_video_only.mp4");
|
|
475837
476857
|
const { execFile: execFileVid } = await import("node:child_process");
|
|
475838
476858
|
const { promisify: promisifyVid } = await import("node:util");
|
|
@@ -476248,14 +477268,14 @@ var init_remotion = __esm({
|
|
|
476248
477268
|
"use strict";
|
|
476249
477269
|
init_exec_safe();
|
|
476250
477270
|
REMOTION_VERSION = "4.0.447";
|
|
476251
|
-
REMOTION_CACHE_DIR =
|
|
477271
|
+
REMOTION_CACHE_DIR = join34(tmpdir3(), "vibe_remotion_cache");
|
|
476252
477272
|
}
|
|
476253
477273
|
});
|
|
476254
477274
|
|
|
476255
477275
|
// ../cli/src/commands/_shared/edit/caption.ts
|
|
476256
477276
|
import { existsSync as existsSync40 } from "node:fs";
|
|
476257
477277
|
import { readFile as readFile22, writeFile as writeFile24, mkdir as mkdir16 } from "node:fs/promises";
|
|
476258
|
-
import { dirname as dirname20, basename as basename9, extname as extname7, join as
|
|
477278
|
+
import { dirname as dirname20, basename as basename9, extname as extname7, join as join35 } from "node:path";
|
|
476259
477279
|
function getCaptionForceStyle(style, fontSize, fontColor, position) {
|
|
476260
477280
|
const alignment = position === "top" ? 8 : position === "center" ? 5 : 2;
|
|
476261
477281
|
const marginV = position === "center" ? 0 : 30;
|
|
@@ -476302,8 +477322,8 @@ async function executeCaption(options) {
|
|
|
476302
477322
|
try {
|
|
476303
477323
|
const tmpDir = `/tmp/vibe_caption_${Date.now()}`;
|
|
476304
477324
|
await mkdir16(tmpDir, { recursive: true });
|
|
476305
|
-
const audioPath =
|
|
476306
|
-
const srtPath =
|
|
477325
|
+
const audioPath = join35(tmpDir, "audio.wav");
|
|
477326
|
+
const srtPath = join35(tmpDir, "captions.srt");
|
|
476307
477327
|
try {
|
|
476308
477328
|
await execSafe(
|
|
476309
477329
|
"ffmpeg",
|
|
@@ -476372,7 +477392,7 @@ async function executeCaption(options) {
|
|
|
476372
477392
|
const remotionErr = await ensureRemotionInstalled2();
|
|
476373
477393
|
if (remotionErr) {
|
|
476374
477394
|
const outputDir2 = dirname20(outputPath);
|
|
476375
|
-
const outputSrtPath2 =
|
|
477395
|
+
const outputSrtPath2 = join35(
|
|
476376
477396
|
outputDir2,
|
|
476377
477397
|
basename9(outputPath, extname7(outputPath)) + ".srt"
|
|
476378
477398
|
);
|
|
@@ -476411,7 +477431,7 @@ SRT saved to: ${outputSrtPath2}` };
|
|
|
476411
477431
|
});
|
|
476412
477432
|
if (!renderResult.success) {
|
|
476413
477433
|
const outputDir2 = dirname20(outputPath);
|
|
476414
|
-
const outputSrtPath2 =
|
|
477434
|
+
const outputSrtPath2 = join35(
|
|
476415
477435
|
outputDir2,
|
|
476416
477436
|
basename9(outputPath, extname7(outputPath)) + ".srt"
|
|
476417
477437
|
);
|
|
@@ -476424,7 +477444,7 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
476424
477444
|
}
|
|
476425
477445
|
}
|
|
476426
477446
|
const outputDir = dirname20(outputPath);
|
|
476427
|
-
const outputSrtPath =
|
|
477447
|
+
const outputSrtPath = join35(
|
|
476428
477448
|
outputDir,
|
|
476429
477449
|
basename9(outputPath, extname7(outputPath)) + ".srt"
|
|
476430
477450
|
);
|
|
@@ -484392,10 +485412,18 @@ Examples:
|
|
|
484392
485412
|
options.ratio = "16:9";
|
|
484393
485413
|
}
|
|
484394
485414
|
if (options.dryRun) {
|
|
485415
|
+
const costUsd = provider === "seedance" || provider === "fal" ? estimateSeedanceVideoCostUsd({
|
|
485416
|
+
durationSec: Number(options.duration) || 5,
|
|
485417
|
+
resolution: options.resolution,
|
|
485418
|
+
aspectRatio: options.ratio,
|
|
485419
|
+
fast: options.seedanceModel === "fast",
|
|
485420
|
+
hasVideoReference: Boolean(options.refVideos)
|
|
485421
|
+
}) : void 0;
|
|
484395
485422
|
outputSuccess({
|
|
484396
485423
|
command: "generate video",
|
|
484397
485424
|
startedAt,
|
|
484398
485425
|
dryRun: true,
|
|
485426
|
+
costUsd,
|
|
484399
485427
|
data: {
|
|
484400
485428
|
params: {
|
|
484401
485429
|
prompt: prompt3,
|
|
@@ -486565,7 +487593,7 @@ function pickOutputPath(data) {
|
|
|
486565
487593
|
}
|
|
486566
487594
|
|
|
486567
487595
|
// ../cli/src/tools/_shared/elicit.ts
|
|
486568
|
-
var NARRATION_CHOICES = ["kokoro", "elevenlabs"];
|
|
487596
|
+
var NARRATION_CHOICES = ["kokoro", "openai", "elevenlabs"];
|
|
486569
487597
|
var BACKDROP_CHOICES = ["skip", "openai"];
|
|
486570
487598
|
function planBuildElicitation(args) {
|
|
486571
487599
|
const assetsWillRun = args.stage === void 0 || args.stage === "all" || args.stage === "assets";
|
|
@@ -486580,8 +487608,9 @@ function planBuildElicitation(args) {
|
|
|
486580
487608
|
description: "Which TTS engine narrates the video?",
|
|
486581
487609
|
enum: [...NARRATION_CHOICES],
|
|
486582
487610
|
enumNames: [
|
|
486583
|
-
"Kokoro \u2014 free, runs
|
|
486584
|
-
"
|
|
487611
|
+
"Kokoro \u2014 free, runs on this machine (first use downloads a ~90 MB voice model; slower)",
|
|
487612
|
+
"OpenAI \u2014 fast cloud voice, uses your OpenAI API key (~$0.02 per video)",
|
|
487613
|
+
"ElevenLabs \u2014 premium cloud voices, uses your ElevenLabs credits"
|
|
486585
487614
|
]
|
|
486586
487615
|
};
|
|
486587
487616
|
required.push("narration");
|
|
@@ -486844,6 +487873,9 @@ function clean(text) {
|
|
|
486844
487873
|
function humanise(id) {
|
|
486845
487874
|
return id.split(/[-_]+/).filter(Boolean).map((w2) => w2.charAt(0).toUpperCase() + w2.slice(1)).join(" ");
|
|
486846
487875
|
}
|
|
487876
|
+
function sceneCompositionId(beatId) {
|
|
487877
|
+
return `scene-${beatId}`;
|
|
487878
|
+
}
|
|
486847
487879
|
function slugifySceneName(name) {
|
|
486848
487880
|
const normalised = name.normalize("NFKD").replace(/[̀-ͯ]/g, "");
|
|
486849
487881
|
const slug = normalised.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -486881,10 +487913,16 @@ function fitKineticFontSize(words) {
|
|
|
486881
487913
|
function kenBurnsTween(scope, dur, endScale = 1.08) {
|
|
486882
487914
|
return `tl.fromTo('${scope} .backdrop', { scale: 1.0 }, { scale: ${endScale}, duration: ${dur.toFixed(2)}, ease: 'none' }, 0);`;
|
|
486883
487915
|
}
|
|
487916
|
+
function backdropMotionTweens(scope, dur, hasImage, endScale = 1.08) {
|
|
487917
|
+
const sweep = hasImage ? "" : `
|
|
487918
|
+
tl.fromTo('${scope} .ambient-sweep', { xPercent: -75, opacity: 0.18 }, { xPercent: 75, opacity: 0.62, duration: ${dur.toFixed(2)}, ease: 'sine.inOut' }, 0);`;
|
|
487919
|
+
return `${kenBurnsTween(scope, dur, endScale)}${sweep}`;
|
|
487920
|
+
}
|
|
486884
487921
|
function buildPreset(input3) {
|
|
486885
487922
|
const id = input3.id;
|
|
486886
487923
|
const scope = `[data-composition-id="${id}"]`;
|
|
486887
|
-
const
|
|
487924
|
+
const displayId = input3.beatId ?? id;
|
|
487925
|
+
const headline = clean(input3.headline) || humanise(displayId);
|
|
486888
487926
|
const subhead = clean(input3.subhead);
|
|
486889
487927
|
const kicker = clean(input3.kicker);
|
|
486890
487928
|
const dur = input3.duration;
|
|
@@ -486907,8 +487945,17 @@ function buildPreset(input3) {
|
|
|
486907
487945
|
position: absolute;
|
|
486908
487946
|
inset: 0;
|
|
486909
487947
|
background: radial-gradient(ellipse at center, #1a1a2e 0%, #000 70%);
|
|
487948
|
+
overflow: hidden;
|
|
487949
|
+
}
|
|
487950
|
+
${scope} .ambient-sweep {
|
|
487951
|
+
position: absolute;
|
|
487952
|
+
inset: -22%;
|
|
487953
|
+
display: block;
|
|
487954
|
+
background: linear-gradient(115deg, rgba(255,255,255,0) 20%, rgba(0,201,255,0.34) 48%, rgba(142,45,226,0.26) 58%, rgba(255,255,255,0) 78%);
|
|
487955
|
+
filter: blur(12px);
|
|
487956
|
+
transform: rotate(8deg);
|
|
486910
487957
|
}`;
|
|
486911
|
-
const backdropMarkup = `<div class="backdrop"></div>`;
|
|
487958
|
+
const backdropMarkup = hasImage ? `<div class="backdrop"></div>` : `<div class="backdrop"><div class="ambient-sweep"></div></div>`;
|
|
486912
487959
|
switch (input3.preset) {
|
|
486913
487960
|
case "simple": {
|
|
486914
487961
|
const transcript = input3.transcript;
|
|
@@ -486940,7 +487987,7 @@ function buildPreset(input3) {
|
|
|
486940
487987
|
body: `${backdropMarkup}
|
|
486941
487988
|
<div class="caption" id="caption">${captionInner}</div>`,
|
|
486942
487989
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
486943
|
-
${
|
|
487990
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
486944
487991
|
${captionTween}`
|
|
486945
487992
|
};
|
|
486946
487993
|
}
|
|
@@ -486979,12 +488026,12 @@ function buildPreset(input3) {
|
|
|
486979
488026
|
// scene's own fade-in handles the visual transition. Backdrop
|
|
486980
488027
|
// Ken-Burns fills what used to be 80% dead static frame.
|
|
486981
488028
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
486982
|
-
${
|
|
488029
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
486983
488030
|
tl.from('${scope} #headline', { opacity: 0, scale: 0.92, duration: 0.55, ease: 'power3.out' }, 0.05);`
|
|
486984
488031
|
};
|
|
486985
488032
|
}
|
|
486986
488033
|
case "explainer": {
|
|
486987
|
-
const k2 = kicker || humanise(
|
|
488034
|
+
const k2 = kicker || humanise(displayId).toUpperCase();
|
|
486988
488035
|
const sub = subhead || "";
|
|
486989
488036
|
const transcript = input3.transcript;
|
|
486990
488037
|
const useWordSync = !!(transcript && transcript.length > 0 && sub);
|
|
@@ -487026,7 +488073,7 @@ function buildPreset(input3) {
|
|
|
487026
488073
|
<div class="subtitle" id="subtitle">${subtitleInner}</div>` : ""}
|
|
487027
488074
|
</div>`,
|
|
487028
488075
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487029
|
-
${
|
|
488076
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
487030
488077
|
tl.from('${scope} #kicker', { opacity: 0, y: 16, duration: 0.4, ease: 'power2.out' }, 0.1);
|
|
487031
488078
|
tl.from('${scope} #title', { opacity: 0, y: 60, duration: 0.7, ease: 'power3.out' }, 0.25);
|
|
487032
488079
|
${subtitleTween}`
|
|
@@ -487067,12 +488114,12 @@ function buildPreset(input3) {
|
|
|
487067
488114
|
body: `${backdropMarkup}
|
|
487068
488115
|
<div class="kinetic">${wordSpans}</div>`,
|
|
487069
488116
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487070
|
-
${
|
|
488117
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
487071
488118
|
${tweens}`
|
|
487072
488119
|
};
|
|
487073
488120
|
}
|
|
487074
488121
|
case "product-shot": {
|
|
487075
|
-
const label = kicker || humanise(
|
|
488122
|
+
const label = kicker || humanise(displayId);
|
|
487076
488123
|
const headlineFontPx = fitFontSize(headline, 72, 40, 50);
|
|
487077
488124
|
return {
|
|
487078
488125
|
css: `${scope} {
|
|
@@ -487106,7 +488153,7 @@ function buildPreset(input3) {
|
|
|
487106
488153
|
<div class="product-headline" id="headline">${esc(headline)}</div>${subhead ? `
|
|
487107
488154
|
<div class="product-sub" id="subhead">${esc(subhead)}</div>` : ""}`,
|
|
487108
488155
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487109
|
-
|
|
488156
|
+
${backdropMotionTweens(scope, dur, hasImage, 1.12)}
|
|
487110
488157
|
tl.from('${scope} #label', { opacity: 0, x: -30, duration: 0.5, ease: 'power3.out' }, 0.2);
|
|
487111
488158
|
tl.from('${scope} #headline', { opacity: 0, y: 40, duration: 0.6, ease: 'power3.out' }, 0.4);${subhead ? `
|
|
487112
488159
|
tl.from('${scope} #subhead', { opacity: 0, y: 20, duration: 0.5, ease: 'power3.out' }, 0.65);` : ""}`
|
|
@@ -487171,9 +488218,10 @@ function emitSceneHtml(input3) {
|
|
|
487171
488218
|
if (input3.width <= 0 || input3.height <= 0) {
|
|
487172
488219
|
throw new Error(`Invalid canvas dims: ${input3.width}x${input3.height}`);
|
|
487173
488220
|
}
|
|
487174
|
-
const
|
|
488221
|
+
const beatId = input3.id;
|
|
488222
|
+
const id = sceneCompositionId(beatId);
|
|
487175
488223
|
const dur = Number(input3.duration.toFixed(3));
|
|
487176
|
-
const parts = buildPreset({ ...input3, id, duration: dur });
|
|
488224
|
+
const parts = buildPreset({ ...input3, id, beatId, duration: dur });
|
|
487177
488225
|
const audioBlock = input3.audioPath ? `
|
|
487178
488226
|
<audio
|
|
487179
488227
|
id="narration"
|
|
@@ -487189,7 +488237,7 @@ function emitSceneHtml(input3) {
|
|
|
487189
488237
|
${lottieLayer.markup}` : "";
|
|
487190
488238
|
const lottieScript = lottieLayer ? `
|
|
487191
488239
|
${lottieLayer.script}` : "";
|
|
487192
|
-
return `<template id="
|
|
488240
|
+
return `<template id="${id}-template">
|
|
487193
488241
|
<div data-composition-id="${id}" data-start="0" data-duration="${dur}" data-width="${input3.width}" data-height="${input3.height}">
|
|
487194
488242
|
<style>
|
|
487195
488243
|
${parts.css}
|
|
@@ -487225,8 +488273,9 @@ function buildClipReference(opts) {
|
|
|
487225
488273
|
const duration = Number(opts.duration.toFixed(3));
|
|
487226
488274
|
const track = opts.trackIndex ?? 1;
|
|
487227
488275
|
const src = opts.src ?? `compositions/scene-${opts.id}.html`;
|
|
488276
|
+
const compositionId = sceneCompositionId(opts.id);
|
|
487228
488277
|
const zIndex = Math.max(1, 1e6 - Math.floor(start * 1e3));
|
|
487229
|
-
return `<div class="clip" data-composition-id="${esc(
|
|
488278
|
+
return `<div class="clip" data-composition-id="${esc(compositionId)}" data-composition-src="${esc(src)}" data-start="${start}" data-duration="${duration}" data-track-index="${track}" style="z-index: ${zIndex};"></div>`;
|
|
487230
488279
|
}
|
|
487231
488280
|
function insertClipIntoRoot(rootHtml, clip) {
|
|
487232
488281
|
const clipDiv = buildClipReference(clip);
|
|
@@ -487270,9 +488319,9 @@ init_agent_host_detect();
|
|
|
487270
488319
|
// ../cli/src/commands/_shared/install-skill.ts
|
|
487271
488320
|
init_bundle_content();
|
|
487272
488321
|
init_bundle();
|
|
487273
|
-
import { mkdir as mkdir8, writeFile as
|
|
488322
|
+
import { mkdir as mkdir8, writeFile as writeFile12 } from "node:fs/promises";
|
|
487274
488323
|
import { existsSync as existsSync21 } from "node:fs";
|
|
487275
|
-
import { dirname as dirname12, join as join21, relative as relative5, resolve as
|
|
488324
|
+
import { dirname as dirname12, join as join21, relative as relative5, resolve as resolve16 } from "node:path";
|
|
487276
488325
|
function universalFiles() {
|
|
487277
488326
|
return [
|
|
487278
488327
|
{ relPath: "SKILL.md", content: SKILL_MD },
|
|
@@ -487322,7 +488371,7 @@ function selectHostFiles(hosts) {
|
|
|
487322
488371
|
return out;
|
|
487323
488372
|
}
|
|
487324
488373
|
async function installHyperframesSkill(opts) {
|
|
487325
|
-
const projectDir =
|
|
488374
|
+
const projectDir = resolve16(opts.projectDir);
|
|
487326
488375
|
const force = opts.force ?? false;
|
|
487327
488376
|
const dryRun = opts.dryRun ?? false;
|
|
487328
488377
|
const files = [...universalFiles(), ...selectHostFiles(opts.hosts)];
|
|
@@ -487347,7 +488396,7 @@ async function installHyperframesSkill(opts) {
|
|
|
487347
488396
|
continue;
|
|
487348
488397
|
}
|
|
487349
488398
|
await mkdir8(dirname12(absPath), { recursive: true });
|
|
487350
|
-
await
|
|
488399
|
+
await writeFile12(absPath, file.content, "utf-8");
|
|
487351
488400
|
actions.push({ path: file.relPath, status: "wrote", bytes });
|
|
487352
488401
|
}
|
|
487353
488402
|
return {
|
|
@@ -487372,10 +488421,10 @@ init_scene_lint();
|
|
|
487372
488421
|
init_storyboard_parse();
|
|
487373
488422
|
init_root_sync();
|
|
487374
488423
|
import { existsSync as existsSync26 } from "node:fs";
|
|
487375
|
-
import { mkdir as mkdir10, readFile as readFile11, writeFile as
|
|
487376
|
-
import { join as join26, resolve as
|
|
488424
|
+
import { mkdir as mkdir10, readFile as readFile11, writeFile as writeFile15 } from "node:fs/promises";
|
|
488425
|
+
import { join as join26, resolve as resolve20 } from "node:path";
|
|
487377
488426
|
async function executeSceneSubmit(opts) {
|
|
487378
|
-
const projectDir =
|
|
488427
|
+
const projectDir = resolve20(opts.projectDir);
|
|
487379
488428
|
const beatId = opts.beatId.trim();
|
|
487380
488429
|
const scenePath = `compositions/scene-${beatId}.html`;
|
|
487381
488430
|
const base = {
|
|
@@ -487467,7 +488516,7 @@ async function executeSceneSubmit(opts) {
|
|
|
487467
488516
|
}
|
|
487468
488517
|
const absPath = join26(projectDir, scenePath);
|
|
487469
488518
|
await mkdir10(join26(projectDir, "compositions"), { recursive: true });
|
|
487470
|
-
await
|
|
488519
|
+
await writeFile15(absPath, html.endsWith("\n") ? html : `${html}
|
|
487471
488520
|
`, "utf-8");
|
|
487472
488521
|
return {
|
|
487473
488522
|
...base,
|
|
@@ -487482,6 +488531,8 @@ async function executeSceneSubmit(opts) {
|
|
|
487482
488531
|
|
|
487483
488532
|
// ../cli/src/commands/scene.ts
|
|
487484
488533
|
init_scene_repair();
|
|
488534
|
+
init_root_sync();
|
|
488535
|
+
init_storyboard_edit();
|
|
487485
488536
|
function validateDuration(value) {
|
|
487486
488537
|
const n2 = parseFloat(value);
|
|
487487
488538
|
if (!Number.isFinite(n2) || n2 <= 0 || n2 > 3600) {
|
|
@@ -487784,11 +488835,14 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
487784
488835
|
).option("-d, --duration <sec>", "Explicit scene duration in seconds (overrides narration audio)").option(
|
|
487785
488836
|
"--visuals <prompt>",
|
|
487786
488837
|
"Image prompt \u2014 generates assets/scene-<id>.png via the configured image provider"
|
|
487787
|
-
).option("--headline <text>", "Visible headline (defaults to the humanised scene name)").option("--kicker <text>", "Small label above the headline (explainer / product-shot)").option("--insert-into <path>", "Root composition file to update", "index.html").option("--project <dir>", "Project directory", ".").option(
|
|
488838
|
+
).option("--headline <text>", "Visible headline (defaults to the humanised scene name)").option("--kicker <text>", "Small label above the headline (explainer / product-shot)").option("--insert-into <path>", "Root composition file to update", "index.html").option("--project <dir>", "Project directory", ".").option(
|
|
488839
|
+
"--no-storyboard",
|
|
488840
|
+
"Do not sync STORYBOARD.md; insert this scene directly into the root composition only"
|
|
488841
|
+
).option("--image-provider <name>", "Image provider: gemini, openai", "gemini").option(
|
|
487788
488842
|
"--tts <provider>",
|
|
487789
|
-
"TTS provider: auto, elevenlabs, kokoro (default auto \u2014
|
|
488843
|
+
"TTS provider: auto, elevenlabs, openai, kokoro (default auto \u2014 ElevenLabs key > OpenAI key > Kokoro local)",
|
|
487790
488844
|
"auto"
|
|
487791
|
-
).option("--voice <id>", "Voice id (ElevenLabs name/id, or Kokoro id like af_heart
|
|
488845
|
+
).option("--voice <id>", "Voice id (ElevenLabs name/id, OpenAI voice like marin, or Kokoro id like af_heart)").option(
|
|
487792
488846
|
"--no-audio",
|
|
487793
488847
|
"Skip TTS even when --narration is provided (useful for tests/agent dry runs)"
|
|
487794
488848
|
).option("--no-image", "Skip image generation even when --visuals is provided").option(
|
|
@@ -487853,6 +488907,7 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
487853
488907
|
kicker: options.kicker,
|
|
487854
488908
|
project: options.project,
|
|
487855
488909
|
insertInto: options.insertInto,
|
|
488910
|
+
syncStoryboard: options.storyboard !== false,
|
|
487856
488911
|
imageProvider: options.imageProvider,
|
|
487857
488912
|
tts,
|
|
487858
488913
|
audio: options.audio,
|
|
@@ -487880,6 +488935,7 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
487880
488935
|
kicker: options.kicker,
|
|
487881
488936
|
projectDir: options.project,
|
|
487882
488937
|
insertInto: options.insertInto,
|
|
488938
|
+
syncStoryboard: options.storyboard !== false,
|
|
487883
488939
|
imageProvider: options.imageProvider,
|
|
487884
488940
|
tts,
|
|
487885
488941
|
voice: options.voice,
|
|
@@ -487919,6 +488975,13 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
487919
488975
|
if (result.audioPath) console.log(source_default.green(" +"), result.audioPath);
|
|
487920
488976
|
if (result.imagePath) console.log(source_default.green(" +"), result.imagePath);
|
|
487921
488977
|
if (result.transcriptPath) console.log(source_default.green(" +"), result.transcriptPath);
|
|
488978
|
+
if (result.storyboardPath && result.storyboardSynced) {
|
|
488979
|
+
console.log(
|
|
488980
|
+
result.storyboardAction === "updated" ? source_default.yellow(" ~") : source_default.green(" +"),
|
|
488981
|
+
result.storyboardPath,
|
|
488982
|
+
source_default.dim(`(${result.storyboardAction})`)
|
|
488983
|
+
);
|
|
488984
|
+
}
|
|
487922
488985
|
console.log(source_default.yellow(" ~"), result.rootPath, source_default.dim("(updated)"));
|
|
487923
488986
|
console.log();
|
|
487924
488987
|
console.log(source_default.bold.cyan("Composition"));
|
|
@@ -487965,6 +489028,21 @@ async function loadVibeProjectConfig(projectDir) {
|
|
|
487965
489028
|
}
|
|
487966
489029
|
};
|
|
487967
489030
|
}
|
|
489031
|
+
function escapeRegExp3(value) {
|
|
489032
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
489033
|
+
}
|
|
489034
|
+
function readClipStart(rootHtml, beatId) {
|
|
489035
|
+
const compositionId = sceneCompositionId(beatId);
|
|
489036
|
+
const match2 = rootHtml.match(
|
|
489037
|
+
new RegExp(
|
|
489038
|
+
`<div\\s+class="clip"[^>]*\\bdata-composition-id="${escapeRegExp3(compositionId)}"[^>]*\\bdata-start="([\\d.]+)"`,
|
|
489039
|
+
"i"
|
|
489040
|
+
)
|
|
489041
|
+
);
|
|
489042
|
+
if (!match2) return void 0;
|
|
489043
|
+
const start = Number.parseFloat(match2[1]);
|
|
489044
|
+
return Number.isFinite(start) ? start : void 0;
|
|
489045
|
+
}
|
|
487968
489046
|
async function resolveNarrationText(value) {
|
|
487969
489047
|
if (!value) return void 0;
|
|
487970
489048
|
const looksLikePath = /\.[a-z]{2,4}$/i.test(value) || value.includes("/") || value.includes("\\");
|
|
@@ -487991,6 +489069,7 @@ async function executeSceneAdd(opts) {
|
|
|
487991
489069
|
const id = slugifySceneName(opts.name);
|
|
487992
489070
|
const sceneRel = `compositions/scene-${id}.html`;
|
|
487993
489071
|
const scenePath = resolve24(projectDir, sceneRel);
|
|
489072
|
+
const storyboardAbsPath = resolve24(projectDir, "STORYBOARD.md");
|
|
487994
489073
|
const errResult = (error) => ({
|
|
487995
489074
|
success: false,
|
|
487996
489075
|
id,
|
|
@@ -488049,7 +489128,7 @@ async function executeSceneAdd(opts) {
|
|
|
488049
489128
|
throw error;
|
|
488050
489129
|
}
|
|
488051
489130
|
opts.onProgress?.(
|
|
488052
|
-
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads ~
|
|
489131
|
+
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads a ~90MB model)..." : resolution.provider === "openai" ? "Generating narration with OpenAI (gpt-4o-mini-tts)..." : "Generating narration with ElevenLabs..."
|
|
488053
489132
|
);
|
|
488054
489133
|
const tts = await resolution.call(narrationText, {
|
|
488055
489134
|
voice: opts.voice,
|
|
@@ -488210,6 +489289,27 @@ async function executeSceneAdd(opts) {
|
|
|
488210
489289
|
duration = fallback2;
|
|
488211
489290
|
}
|
|
488212
489291
|
duration = Number(duration.toFixed(2));
|
|
489292
|
+
let storyboardPath;
|
|
489293
|
+
let storyboardSynced = false;
|
|
489294
|
+
let storyboardAction = "skipped";
|
|
489295
|
+
const shouldSyncStoryboard = opts.syncStoryboard !== false && await pathExists2(storyboardAbsPath);
|
|
489296
|
+
if (shouldSyncStoryboard) {
|
|
489297
|
+
opts.onProgress?.("Syncing STORYBOARD.md...");
|
|
489298
|
+
const before2 = await readFile14(storyboardAbsPath, "utf-8");
|
|
489299
|
+
const synced = upsertStoryboardBeat(before2, {
|
|
489300
|
+
beatId: id,
|
|
489301
|
+
title: opts.headline,
|
|
489302
|
+
duration,
|
|
489303
|
+
narration: narrationText && !opts.skipAudio ? narrationText : void 0,
|
|
489304
|
+
backdrop: opts.visuals && !opts.skipImage ? opts.visuals : void 0
|
|
489305
|
+
});
|
|
489306
|
+
if (synced.markdown !== before2) {
|
|
489307
|
+
await writeFile17(storyboardAbsPath, synced.markdown, "utf-8");
|
|
489308
|
+
}
|
|
489309
|
+
storyboardPath = relative8(process.cwd(), storyboardAbsPath) || storyboardAbsPath;
|
|
489310
|
+
storyboardSynced = true;
|
|
489311
|
+
storyboardAction = synced.action;
|
|
489312
|
+
}
|
|
488213
489313
|
opts.onProgress?.("Emitting scene HTML...");
|
|
488214
489314
|
const sceneHtml = emitSceneHtml({
|
|
488215
489315
|
id,
|
|
@@ -488228,11 +489328,24 @@ async function executeSceneAdd(opts) {
|
|
|
488228
489328
|
await mkdir11(dirname14(scenePath), { recursive: true });
|
|
488229
489329
|
await writeFile17(scenePath, sceneHtml, "utf-8");
|
|
488230
489330
|
opts.onProgress?.("Updating root composition...");
|
|
488231
|
-
|
|
488232
|
-
|
|
488233
|
-
|
|
488234
|
-
|
|
488235
|
-
|
|
489331
|
+
let start = 0;
|
|
489332
|
+
if (storyboardSynced) {
|
|
489333
|
+
const syncPlan = await syncRootComposition({
|
|
489334
|
+
projectDir,
|
|
489335
|
+
rootRel,
|
|
489336
|
+
beats: await loadProjectRootSyncBeats(projectDir)
|
|
489337
|
+
});
|
|
489338
|
+
const blockingIssue = syncPlan.issues.find((issue) => issue.severity === "error");
|
|
489339
|
+
if (blockingIssue) return errResult(blockingIssue.message);
|
|
489340
|
+
const rootHtmlAfterSync = await readFile14(rootPath, "utf-8");
|
|
489341
|
+
start = readClipStart(rootHtmlAfterSync, id) ?? 0;
|
|
489342
|
+
} else {
|
|
489343
|
+
start = nextSceneStart(rootHtmlBefore, SCENE_OVERLAP_SECONDS);
|
|
489344
|
+
const existingClipCount = (rootHtmlBefore.match(/<div\s+class="clip"/g) || []).length;
|
|
489345
|
+
const trackIndex = existingClipCount % 2 + 1;
|
|
489346
|
+
const updated = insertClipIntoRoot(rootHtmlBefore, { id, start, duration, trackIndex });
|
|
489347
|
+
await writeFile17(rootPath, updated, "utf-8");
|
|
489348
|
+
}
|
|
488236
489349
|
const transcriptAbsPath = transcriptRelPath ? resolve24(projectDir, transcriptRelPath) : void 0;
|
|
488237
489350
|
return {
|
|
488238
489351
|
success: true,
|
|
@@ -488245,6 +489358,9 @@ async function executeSceneAdd(opts) {
|
|
|
488245
489358
|
audioPath: audioAbsPath ? relative8(process.cwd(), audioAbsPath) || audioAbsPath : void 0,
|
|
488246
489359
|
imagePath: imageAbsPath ? relative8(process.cwd(), imageAbsPath) || imageAbsPath : void 0,
|
|
488247
489360
|
lottiePath: lottieAbsPath ? relative8(process.cwd(), lottieAbsPath) || lottieAbsPath : void 0,
|
|
489361
|
+
storyboardPath,
|
|
489362
|
+
storyboardSynced,
|
|
489363
|
+
storyboardAction,
|
|
488248
489364
|
transcriptPath: transcriptAbsPath ? relative8(process.cwd(), transcriptAbsPath) || transcriptAbsPath : void 0,
|
|
488249
489365
|
transcriptWordCount
|
|
488250
489366
|
};
|
|
@@ -488542,6 +489658,9 @@ var sceneAddSchema = z2.object({
|
|
|
488542
489658
|
kicker: z2.string().optional().describe("Small label above the headline (used by 'explainer' and 'product-shot' presets)."),
|
|
488543
489659
|
projectDir: z2.string().optional().describe(PROJECT_DIR_DESCRIPTION),
|
|
488544
489660
|
insertInto: z2.string().optional().describe("Root composition file (relative to projectDir). Default 'index.html'."),
|
|
489661
|
+
syncStoryboard: z2.boolean().optional().describe(
|
|
489662
|
+
"Sync STORYBOARD.md when present, then rebuild root refs from it. Default true; set false for root-only insertion."
|
|
489663
|
+
),
|
|
488545
489664
|
imageProvider: z2.enum(["gemini", "openai"]).optional().describe("Image provider for visuals. Default 'gemini'."),
|
|
488546
489665
|
voice: z2.string().optional().describe("ElevenLabs voice id or name."),
|
|
488547
489666
|
skipAudio: z2.boolean().optional().describe("Skip TTS even if narration is provided."),
|
|
@@ -488554,7 +489673,7 @@ var sceneAddTool = defineTool({
|
|
|
488554
489673
|
cost: "low",
|
|
488555
489674
|
title: "Add Scene from Preset",
|
|
488556
489675
|
annotations: { readOnly: false, openWorld: true },
|
|
488557
|
-
description: "Add a single scene to an existing scene project. Optionally generates narration audio (ElevenLabs) and/or a backdrop image (Gemini/OpenAI), then emits compositions/scene-<id>.html with a paused GSAP timeline and
|
|
489676
|
+
description: "Add a single scene to an existing scene project. Optionally generates narration audio (ElevenLabs) and/or a backdrop image (Gemini/OpenAI), then emits compositions/scene-<id>.html with a paused GSAP timeline. By default, syncs STORYBOARD.md and rebuilds root refs from it; set syncStoryboard:false for root-only insertion. Use skipAudio:true and skipImage:true for text-only scenes that need no API calls.",
|
|
488558
489677
|
schema: sceneAddSchema,
|
|
488559
489678
|
async execute(args, ctx) {
|
|
488560
489679
|
const projectDir = args.projectDir ? resolve34(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
@@ -488568,6 +489687,7 @@ var sceneAddTool = defineTool({
|
|
|
488568
489687
|
kicker: args.kicker,
|
|
488569
489688
|
projectDir,
|
|
488570
489689
|
insertInto: args.insertInto,
|
|
489690
|
+
syncStoryboard: args.syncStoryboard,
|
|
488571
489691
|
imageProvider: args.imageProvider,
|
|
488572
489692
|
voice: args.voice,
|
|
488573
489693
|
skipAudio: args.skipAudio,
|
|
@@ -488586,6 +489706,9 @@ var sceneAddTool = defineTool({
|
|
|
488586
489706
|
];
|
|
488587
489707
|
if (result.audioPath) lines.push(` audio: ${result.audioPath}`);
|
|
488588
489708
|
if (result.imagePath) lines.push(` image: ${result.imagePath}`);
|
|
489709
|
+
if (result.storyboardPath && result.storyboardSynced) {
|
|
489710
|
+
lines.push(` story: ${result.storyboardPath} (${result.storyboardAction})`);
|
|
489711
|
+
}
|
|
488589
489712
|
return {
|
|
488590
489713
|
success: true,
|
|
488591
489714
|
data: {
|
|
@@ -488596,7 +489719,10 @@ var sceneAddTool = defineTool({
|
|
|
488596
489719
|
scenePath: result.scenePath,
|
|
488597
489720
|
rootPath: result.rootPath,
|
|
488598
489721
|
audioPath: result.audioPath,
|
|
488599
|
-
imagePath: result.imagePath
|
|
489722
|
+
imagePath: result.imagePath,
|
|
489723
|
+
storyboardPath: result.storyboardPath,
|
|
489724
|
+
storyboardSynced: result.storyboardSynced,
|
|
489725
|
+
storyboardAction: result.storyboardAction
|
|
488600
489726
|
},
|
|
488601
489727
|
humanLines: lines
|
|
488602
489728
|
};
|
|
@@ -488809,7 +489935,9 @@ var sceneBuildSchema = z2.object({
|
|
|
488809
489935
|
skipVideo: z2.boolean().optional().describe("Skip video generation for every beat (use existing MP4 assets if present)."),
|
|
488810
489936
|
skipMusic: z2.boolean().optional().describe("Skip music generation for every beat (use existing audio assets if present)."),
|
|
488811
489937
|
skipRender: z2.boolean().optional().describe("Stop after compose \u2014 produces compositions/*.html but no final MP4."),
|
|
488812
|
-
ttsProvider: z2.enum(["auto", "elevenlabs", "kokoro"]).optional().describe(
|
|
489938
|
+
ttsProvider: z2.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe(
|
|
489939
|
+
"TTS provider override. Default 'auto' (elevenlabs key > openai key > local kokoro)."
|
|
489940
|
+
),
|
|
488813
489941
|
voice: z2.string().optional().describe("TTS voice id (provider-specific)."),
|
|
488814
489942
|
imageProvider: z2.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2)."),
|
|
488815
489943
|
videoProvider: z2.enum(["seedance", "grok", "kling", "runway", "veo"]).optional().describe("Video provider for per-beat video cues. Default seedance."),
|
|
@@ -490029,7 +491157,7 @@ init_root_sync();
|
|
|
490029
491157
|
init_review_report();
|
|
490030
491158
|
import { existsSync as existsSync56 } from "node:fs";
|
|
490031
491159
|
import { readdir as readdir6, readFile as readFile31, stat as stat5 } from "node:fs/promises";
|
|
490032
|
-
import { basename as basename14, isAbsolute as isAbsolute7, join as
|
|
491160
|
+
import { basename as basename14, isAbsolute as isAbsolute7, join as join37, relative as relative13, resolve as resolve50 } from "node:path";
|
|
490033
491161
|
async function inspectProject(opts) {
|
|
490034
491162
|
const projectDir = resolve50(opts.projectDir);
|
|
490035
491163
|
const issues = [];
|
|
@@ -490058,12 +491186,12 @@ async function inspectProject(opts) {
|
|
|
490058
491186
|
);
|
|
490059
491187
|
}
|
|
490060
491188
|
const coreFiles = {
|
|
490061
|
-
storyboard:
|
|
490062
|
-
design:
|
|
490063
|
-
config:
|
|
490064
|
-
legacyConfig:
|
|
490065
|
-
buildReport:
|
|
490066
|
-
root:
|
|
491189
|
+
storyboard: join37(projectDir, "STORYBOARD.md"),
|
|
491190
|
+
design: join37(projectDir, "DESIGN.md"),
|
|
491191
|
+
config: join37(projectDir, "vibe.config.json"),
|
|
491192
|
+
legacyConfig: join37(projectDir, "vibe.project.yaml"),
|
|
491193
|
+
buildReport: join37(projectDir, "build-report.json"),
|
|
491194
|
+
root: join37(projectDir, "index.html")
|
|
490067
491195
|
};
|
|
490068
491196
|
for (const [name, path14] of Object.entries(coreFiles)) {
|
|
490069
491197
|
checks.files[name] = existsSync56(path14);
|
|
@@ -490147,7 +491275,7 @@ async function inspectProject(opts) {
|
|
|
490147
491275
|
});
|
|
490148
491276
|
retryWith.push(`vibe build ${projectDir} --stage sync --json`);
|
|
490149
491277
|
}
|
|
490150
|
-
const compositionsDir =
|
|
491278
|
+
const compositionsDir = join37(projectDir, "compositions");
|
|
490151
491279
|
const existingComps = existsSync56(compositionsDir) ? new Set(await listHtmlBasenames(compositionsDir)) : /* @__PURE__ */ new Set();
|
|
490152
491280
|
checks.compositions.expected = inspectedBeatIds.length;
|
|
490153
491281
|
for (const beatId of inspectedBeatIds) {
|
|
@@ -490155,12 +491283,12 @@ async function inspectProject(opts) {
|
|
|
490155
491283
|
if (existingComps.has(file)) {
|
|
490156
491284
|
checks.compositions.found++;
|
|
490157
491285
|
} else {
|
|
490158
|
-
checks.compositions.missing.push(
|
|
491286
|
+
checks.compositions.missing.push(join37("compositions", file));
|
|
490159
491287
|
issues.push({
|
|
490160
491288
|
severity: "error",
|
|
490161
491289
|
code: "MISSING_COMPOSITION",
|
|
490162
491290
|
message: `Composition for beat "${beatId}" is missing.`,
|
|
490163
|
-
file:
|
|
491291
|
+
file: join37("compositions", file),
|
|
490164
491292
|
scene: beatId,
|
|
490165
491293
|
beatId,
|
|
490166
491294
|
suggestedFix: "Run `vibe build --stage compose --json`."
|
|
@@ -490222,7 +491350,7 @@ async function inspectProject(opts) {
|
|
|
490222
491350
|
try {
|
|
490223
491351
|
const lint = await runProjectLint({ projectDir });
|
|
490224
491352
|
const lintFiles = opts.beatId ? lint.files.filter(
|
|
490225
|
-
(file) => file.file === "index.html" || file.file ===
|
|
491353
|
+
(file) => file.file === "index.html" || file.file === join37("compositions", `scene-${opts.beatId}.html`)
|
|
490226
491354
|
) : lint.files;
|
|
490227
491355
|
const lintCounts = countLintFindings(lintFiles);
|
|
490228
491356
|
checks.lint = {
|
|
@@ -490258,7 +491386,11 @@ async function inspectProject(opts) {
|
|
|
490258
491386
|
);
|
|
490259
491387
|
}
|
|
490260
491388
|
function makeProjectResult(projectDir, issues, checks, retryWith, beatId) {
|
|
490261
|
-
const
|
|
491389
|
+
const normalizedRetryWith = uniqueRetryWith(retryWith);
|
|
491390
|
+
const normalizedIssues = normalizeReviewIssues(issues, {
|
|
491391
|
+
projectDir,
|
|
491392
|
+
retryWith: normalizedRetryWith
|
|
491393
|
+
});
|
|
490262
491394
|
const status = statusFromIssues(normalizedIssues);
|
|
490263
491395
|
return {
|
|
490264
491396
|
schemaVersion: "1",
|
|
@@ -490270,9 +491402,14 @@ function makeProjectResult(projectDir, issues, checks, retryWith, beatId) {
|
|
|
490270
491402
|
score: scoreIssues(normalizedIssues),
|
|
490271
491403
|
issues: normalizedIssues,
|
|
490272
491404
|
summary: summarizeReviewIssues(normalizedIssues),
|
|
491405
|
+
nextActions: deriveNextReviewActions({
|
|
491406
|
+
issues: normalizedIssues,
|
|
491407
|
+
retryWith: normalizedRetryWith,
|
|
491408
|
+
projectDir
|
|
491409
|
+
}),
|
|
490273
491410
|
sourceReports: projectSourceReports(checks),
|
|
490274
491411
|
checks,
|
|
490275
|
-
retryWith:
|
|
491412
|
+
retryWith: normalizedRetryWith
|
|
490276
491413
|
};
|
|
490277
491414
|
}
|
|
490278
491415
|
function storyboardPlaceholderIssues(storyboard) {
|
|
@@ -490592,7 +491729,7 @@ init_storyboard_parse();
|
|
|
490592
491729
|
init_review_report();
|
|
490593
491730
|
import { existsSync as existsSync57 } from "node:fs";
|
|
490594
491731
|
import { readdir as readdir7, readFile as readFile32, stat as stat6 } from "node:fs/promises";
|
|
490595
|
-
import { basename as basename15, isAbsolute as isAbsolute8, join as
|
|
491732
|
+
import { basename as basename15, isAbsolute as isAbsolute8, join as join38, relative as relative14, resolve as resolve51 } from "node:path";
|
|
490596
491733
|
var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([".mp4", ".mov", ".webm", ".m4v"]);
|
|
490597
491734
|
var DEFAULT_AI_MODEL = "flash";
|
|
490598
491735
|
var BLACK_FRAME_MIN_DURATION_SEC = 1;
|
|
@@ -490824,6 +491961,8 @@ async function inspectRender(opts) {
|
|
|
490824
491961
|
severity: "error",
|
|
490825
491962
|
code: "RENDER_NOT_FOUND",
|
|
490826
491963
|
message: opts.beatId ? `No rendered video was found for beat "${opts.beatId}". Pass --video or render the beat first.` : "No rendered video was found. Pass --video or render the project first.",
|
|
491964
|
+
beatId: opts.beatId,
|
|
491965
|
+
scene: opts.beatId,
|
|
490827
491966
|
suggestedFix: opts.beatId ? "Run `vibe render <project> --beat <id> --json`." : "Run `vibe build --stage render --json` or `vibe render --json`."
|
|
490828
491967
|
});
|
|
490829
491968
|
retryWith.push(
|
|
@@ -490846,6 +491985,8 @@ async function inspectRender(opts) {
|
|
|
490846
491985
|
code: "EMPTY_RENDER",
|
|
490847
491986
|
message: "Rendered video file is empty.",
|
|
490848
491987
|
file: displayPath(videoPath),
|
|
491988
|
+
beatId: opts.beatId,
|
|
491989
|
+
scene: opts.beatId,
|
|
490849
491990
|
suggestedFix: opts.beatId ? "Render again with `vibe render --beat <id> --json`." : "Render again with `vibe render --json`."
|
|
490850
491991
|
});
|
|
490851
491992
|
retryWith.push(
|
|
@@ -490855,6 +491996,8 @@ async function inspectRender(opts) {
|
|
|
490855
491996
|
const beatTimings = await beatTimingsFromBuildReport(projectDir, opts.beatId);
|
|
490856
491997
|
const expectedDurationSec = beatTimings.length > 0 ? Number(beatTimings.reduce((sum, beat) => sum + beat.sceneDurationSec, 0).toFixed(3)) : await expectedDurationFromBuildReport(projectDir, opts.beatId);
|
|
490857
491998
|
if (expectedDurationSec !== void 0) checks.expectedDurationSec = expectedDurationSec;
|
|
491999
|
+
const expectedAudio = await renderExpectsAudio(projectDir, opts.beatId);
|
|
492000
|
+
checks.expectedAudio = expectedAudio;
|
|
490858
492001
|
if (!commandExists("ffprobe")) {
|
|
490859
492002
|
issues.push({
|
|
490860
492003
|
severity: "error",
|
|
@@ -490880,7 +492023,7 @@ async function inspectRender(opts) {
|
|
|
490880
492023
|
file: displayPath(videoPath)
|
|
490881
492024
|
});
|
|
490882
492025
|
}
|
|
490883
|
-
if (!audioStream) {
|
|
492026
|
+
if (!audioStream && expectedAudio) {
|
|
490884
492027
|
issues.push({
|
|
490885
492028
|
severity: "warning",
|
|
490886
492029
|
code: "NO_AUDIO_STREAM",
|
|
@@ -491085,8 +492228,86 @@ async function inspectRender(opts) {
|
|
|
491085
492228
|
);
|
|
491086
492229
|
return maybeWriteRenderReport(projectDir, opts, result);
|
|
491087
492230
|
}
|
|
492231
|
+
async function renderExpectsAudio(projectDir, beatId) {
|
|
492232
|
+
const root2 = resolve51(projectDir);
|
|
492233
|
+
const rootHtml = await readTextIfExists(join38(root2, "index.html"));
|
|
492234
|
+
if (rootHtml && rootHtmlExpectsAudio(rootHtml, beatId)) return true;
|
|
492235
|
+
const buildReport = await readJsonIfExists(join38(root2, "build-report.json"));
|
|
492236
|
+
if (buildReportExpectsAudio(buildReport, beatId)) return true;
|
|
492237
|
+
const storyboard = await readTextIfExists(join38(root2, "STORYBOARD.md"));
|
|
492238
|
+
if (!storyboard) return false;
|
|
492239
|
+
try {
|
|
492240
|
+
const parsed = parseStoryboard(storyboard);
|
|
492241
|
+
const beats = beatId ? parsed.beats.filter((beat) => beat.id === beatId) : parsed.beats;
|
|
492242
|
+
return beats.some(
|
|
492243
|
+
(beat) => [
|
|
492244
|
+
`assets/narration-${beat.id}.mp3`,
|
|
492245
|
+
`assets/narration-${beat.id}.wav`,
|
|
492246
|
+
`assets/music-${beat.id}.mp3`,
|
|
492247
|
+
`assets/music-${beat.id}.wav`
|
|
492248
|
+
].some((asset) => existsSync57(join38(root2, asset)))
|
|
492249
|
+
);
|
|
492250
|
+
} catch {
|
|
492251
|
+
return false;
|
|
492252
|
+
}
|
|
492253
|
+
}
|
|
492254
|
+
function rootHtmlExpectsAudio(html, beatId) {
|
|
492255
|
+
const audioTags = html.match(/<audio\b[^>]*>/gi) ?? [];
|
|
492256
|
+
if (!beatId) return audioTags.length > 0;
|
|
492257
|
+
const escaped = escapeRegExp4(beatId);
|
|
492258
|
+
const beatAudioRe = new RegExp(
|
|
492259
|
+
`(id="(?:narration|music)-${escaped}"|src="[^"]*(?:narration|music)-${escaped}\\.(?:mp3|wav)")`,
|
|
492260
|
+
"i"
|
|
492261
|
+
);
|
|
492262
|
+
return audioTags.some((tag) => beatAudioRe.test(tag));
|
|
492263
|
+
}
|
|
492264
|
+
function buildReportExpectsAudio(report, beatId) {
|
|
492265
|
+
if (!report || typeof report !== "object") return false;
|
|
492266
|
+
const beats = Array.isArray(report.beats) ? report.beats ?? [] : [];
|
|
492267
|
+
const selected = beatId === void 0 ? beats : beats.filter((beat) => {
|
|
492268
|
+
if (!beat || typeof beat !== "object") return false;
|
|
492269
|
+
return beat.id === beatId;
|
|
492270
|
+
});
|
|
492271
|
+
return selected.some((beat) => beatReportExpectsAudio(beat));
|
|
492272
|
+
}
|
|
492273
|
+
function beatReportExpectsAudio(beat) {
|
|
492274
|
+
if (!beat || typeof beat !== "object") return false;
|
|
492275
|
+
const record = beat;
|
|
492276
|
+
if (typeof record.narrationPath === "string" && record.narrationPath.length > 0) return true;
|
|
492277
|
+
if (typeof record.musicPath === "string" && record.musicPath.length > 0) return true;
|
|
492278
|
+
if (parseOptionalNumber2(record.narrationDurationSec) !== void 0) return true;
|
|
492279
|
+
const narration = record.narration;
|
|
492280
|
+
if (narration && typeof narration === "object") {
|
|
492281
|
+
const n2 = narration;
|
|
492282
|
+
if (typeof n2.path === "string" && n2.path.length > 0) return true;
|
|
492283
|
+
if (parseOptionalNumber2(n2.durationSec) !== void 0) return true;
|
|
492284
|
+
}
|
|
492285
|
+
const music = record.music;
|
|
492286
|
+
if (music && typeof music === "object") {
|
|
492287
|
+
const m2 = music;
|
|
492288
|
+
if (typeof m2.path === "string" && m2.path.length > 0) return true;
|
|
492289
|
+
if (parseOptionalNumber2(m2.durationSec) !== void 0) return true;
|
|
492290
|
+
}
|
|
492291
|
+
return false;
|
|
492292
|
+
}
|
|
492293
|
+
async function readJsonIfExists(path14) {
|
|
492294
|
+
const text = await readTextIfExists(path14);
|
|
492295
|
+
if (!text) return null;
|
|
492296
|
+
try {
|
|
492297
|
+
return JSON.parse(text);
|
|
492298
|
+
} catch {
|
|
492299
|
+
return null;
|
|
492300
|
+
}
|
|
492301
|
+
}
|
|
492302
|
+
function escapeRegExp4(value) {
|
|
492303
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
492304
|
+
}
|
|
491088
492305
|
function makeRenderResult(projectDir, opts, videoPath, issues, checks, retryWith, score) {
|
|
491089
|
-
const
|
|
492306
|
+
const normalizedRetryWith = uniqueRetryWith(retryWith);
|
|
492307
|
+
const normalizedIssues = normalizeReviewIssues(issues, {
|
|
492308
|
+
projectDir,
|
|
492309
|
+
retryWith: normalizedRetryWith
|
|
492310
|
+
});
|
|
491090
492311
|
const status = statusFromIssues(normalizedIssues);
|
|
491091
492312
|
return {
|
|
491092
492313
|
schemaVersion: "1",
|
|
@@ -491099,9 +492320,14 @@ function makeRenderResult(projectDir, opts, videoPath, issues, checks, retryWith
|
|
|
491099
492320
|
score,
|
|
491100
492321
|
issues: normalizedIssues,
|
|
491101
492322
|
summary: summarizeReviewIssues(normalizedIssues),
|
|
492323
|
+
nextActions: deriveNextReviewActions({
|
|
492324
|
+
issues: normalizedIssues,
|
|
492325
|
+
retryWith: normalizedRetryWith,
|
|
492326
|
+
projectDir
|
|
492327
|
+
}),
|
|
491102
492328
|
sourceReports: renderSourceReports(projectDir, videoPath, checks),
|
|
491103
492329
|
checks,
|
|
491104
|
-
retryWith:
|
|
492330
|
+
retryWith: normalizedRetryWith
|
|
491105
492331
|
};
|
|
491106
492332
|
}
|
|
491107
492333
|
async function maybeWriteRenderReport(projectDir, opts, result) {
|
|
@@ -491127,8 +492353,8 @@ async function maybeWriteRenderReport(projectDir, opts, result) {
|
|
|
491127
492353
|
}
|
|
491128
492354
|
function renderSourceReports(projectDir, videoPath, checks) {
|
|
491129
492355
|
const reports = [];
|
|
491130
|
-
if (existsSync57(
|
|
491131
|
-
if (existsSync57(
|
|
492356
|
+
if (existsSync57(join38(projectDir, "build-report.json"))) reports.push("build-report.json");
|
|
492357
|
+
if (existsSync57(join38(projectDir, "render-report.json"))) reports.push("render-report.json");
|
|
491132
492358
|
if (videoPath) reports.push(displayPath(videoPath));
|
|
491133
492359
|
if (checks.durationSec !== void 0 || checks.width !== void 0 || checks.height !== void 0) {
|
|
491134
492360
|
reports.push("ffprobe");
|
|
@@ -491143,7 +492369,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491143
492369
|
const candidate = resolve51(process.cwd(), explicit);
|
|
491144
492370
|
return existsSync57(candidate) ? candidate : null;
|
|
491145
492371
|
}
|
|
491146
|
-
const renderReportPath =
|
|
492372
|
+
const renderReportPath = join38(projectDir, "render-report.json");
|
|
491147
492373
|
if (existsSync57(renderReportPath)) {
|
|
491148
492374
|
try {
|
|
491149
492375
|
const report = JSON.parse(await readFile32(renderReportPath, "utf-8"));
|
|
@@ -491155,7 +492381,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491155
492381
|
} catch {
|
|
491156
492382
|
}
|
|
491157
492383
|
}
|
|
491158
|
-
const reportPath =
|
|
492384
|
+
const reportPath = join38(projectDir, "build-report.json");
|
|
491159
492385
|
if (!beatId && existsSync57(reportPath)) {
|
|
491160
492386
|
try {
|
|
491161
492387
|
const report = JSON.parse(await readFile32(reportPath, "utf-8"));
|
|
@@ -491164,7 +492390,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491164
492390
|
} catch {
|
|
491165
492391
|
}
|
|
491166
492392
|
}
|
|
491167
|
-
const rendersDir =
|
|
492393
|
+
const rendersDir = join38(projectDir, "renders");
|
|
491168
492394
|
if (!existsSync57(rendersDir)) return null;
|
|
491169
492395
|
const entries2 = await readdir7(rendersDir, { withFileTypes: true });
|
|
491170
492396
|
const candidates = [];
|
|
@@ -491173,7 +492399,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491173
492399
|
const ext = entry.name.slice(entry.name.lastIndexOf(".")).toLowerCase();
|
|
491174
492400
|
if (!VIDEO_EXTENSIONS.has(ext)) continue;
|
|
491175
492401
|
if (beatId && !entry.name.includes(sanitizeFileSegment2(beatId))) continue;
|
|
491176
|
-
const full =
|
|
492402
|
+
const full = join38(rendersDir, entry.name);
|
|
491177
492403
|
const info = await stat6(full);
|
|
491178
492404
|
candidates.push({ path: full, mtimeMs: info.mtimeMs });
|
|
491179
492405
|
}
|
|
@@ -491191,11 +492417,11 @@ async function runAiRenderReview(projectDir, videoPath, model) {
|
|
|
491191
492417
|
});
|
|
491192
492418
|
}
|
|
491193
492419
|
function resolveStoryboardPath(projectDir) {
|
|
491194
|
-
const storyboardPath =
|
|
492420
|
+
const storyboardPath = join38(projectDir, "STORYBOARD.md");
|
|
491195
492421
|
return existsSync57(storyboardPath) ? storyboardPath : null;
|
|
491196
492422
|
}
|
|
491197
492423
|
async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
491198
|
-
const reportPath =
|
|
492424
|
+
const reportPath = join38(projectDir, "build-report.json");
|
|
491199
492425
|
if (!existsSync57(reportPath)) return void 0;
|
|
491200
492426
|
try {
|
|
491201
492427
|
const report = JSON.parse(await readFile32(reportPath, "utf-8"));
|
|
@@ -491210,7 +492436,7 @@ async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
|
491210
492436
|
}
|
|
491211
492437
|
}
|
|
491212
492438
|
async function beatTimingsFromBuildReport(projectDir, beatId) {
|
|
491213
|
-
const reportPath =
|
|
492439
|
+
const reportPath = join38(projectDir, "build-report.json");
|
|
491214
492440
|
if (!existsSync57(reportPath)) return [];
|
|
491215
492441
|
try {
|
|
491216
492442
|
const report = JSON.parse(await readFile32(reportPath, "utf-8"));
|
|
@@ -491239,17 +492465,17 @@ async function beatTimingsFromBuildReport(projectDir, beatId) {
|
|
|
491239
492465
|
}
|
|
491240
492466
|
async function buildRenderReviewProjectContext(projectDir) {
|
|
491241
492467
|
const parts = [];
|
|
491242
|
-
const storyboard = await readTextIfExists(
|
|
492468
|
+
const storyboard = await readTextIfExists(join38(projectDir, "STORYBOARD.md"));
|
|
491243
492469
|
if (storyboard) {
|
|
491244
492470
|
parts.push(`STORYBOARD.md:
|
|
491245
492471
|
${truncateText(storyboard, 4e3)}`);
|
|
491246
492472
|
parts.push(`Storyboard beat cue summary:
|
|
491247
492473
|
${storyboardBeatCueSummary(storyboard)}`);
|
|
491248
492474
|
}
|
|
491249
|
-
const design = await readTextIfExists(
|
|
492475
|
+
const design = await readTextIfExists(join38(projectDir, "DESIGN.md"));
|
|
491250
492476
|
if (design) parts.push(`DESIGN.md:
|
|
491251
492477
|
${truncateText(design, 4e3)}`);
|
|
491252
|
-
const buildReport = await readTextIfExists(
|
|
492478
|
+
const buildReport = await readTextIfExists(join38(projectDir, "build-report.json"));
|
|
491253
492479
|
if (buildReport) parts.push(`build-report.json:
|
|
491254
492480
|
${truncateText(buildReport, 6e3)}`);
|
|
491255
492481
|
const timings = await beatTimingsFromBuildReport(projectDir);
|
|
@@ -492108,7 +493334,7 @@ init_storyboard_edit();
|
|
|
492108
493334
|
// ../cli/src/commands/_shared/storyboard-revise.ts
|
|
492109
493335
|
import { existsSync as existsSync59 } from "node:fs";
|
|
492110
493336
|
import { readFile as readFile35, writeFile as writeFile42 } from "node:fs/promises";
|
|
492111
|
-
import { join as
|
|
493337
|
+
import { join as join39, resolve as resolve64 } from "node:path";
|
|
492112
493338
|
|
|
492113
493339
|
// ../cli/src/agent/adapters/index.ts
|
|
492114
493340
|
init_openai3();
|
|
@@ -492155,7 +493381,7 @@ init_storyboard_parse();
|
|
|
492155
493381
|
init_storyboard_edit();
|
|
492156
493382
|
async function executeStoryboardRevision(opts) {
|
|
492157
493383
|
const projectDir = resolve64(opts.projectDir);
|
|
492158
|
-
const storyboardPath =
|
|
493384
|
+
const storyboardPath = join39(projectDir, "STORYBOARD.md");
|
|
492159
493385
|
const retryWith = [`vibe storyboard revise ${projectDir} --from "<request>" --dry-run --json`];
|
|
492160
493386
|
if (!existsSync59(storyboardPath)) {
|
|
492161
493387
|
return failureResult({
|
|
@@ -492390,8 +493616,8 @@ function diffChangedBeats(before2, after2) {
|
|
|
492390
493616
|
return ids.filter((id) => JSON.stringify(beforeBeats.get(id) ?? null) !== JSON.stringify(afterBeats.get(id) ?? null));
|
|
492391
493617
|
}
|
|
492392
493618
|
async function readRevisionContext(projectDir) {
|
|
492393
|
-
const designMd = await readOptionalText(
|
|
492394
|
-
const buildReportJson = await readOptionalJsonText(
|
|
493619
|
+
const designMd = await readOptionalText(join39(projectDir, "DESIGN.md"));
|
|
493620
|
+
const buildReportJson = await readOptionalJsonText(join39(projectDir, "build-report.json"));
|
|
492395
493621
|
return { designMd, buildReportJson };
|
|
492396
493622
|
}
|
|
492397
493623
|
async function readOptionalText(path14) {
|
|
@@ -492652,7 +493878,7 @@ var planTool = defineTool({
|
|
|
492652
493878
|
skipBackdrop: z7.boolean().optional().describe("Don't include backdrop image generation in the plan."),
|
|
492653
493879
|
skipVideo: z7.boolean().optional().describe("Don't include video generation in the plan."),
|
|
492654
493880
|
skipMusic: z7.boolean().optional().describe("Don't include music generation in the plan."),
|
|
492655
|
-
ttsProvider: z7.enum(["auto", "elevenlabs", "kokoro"]).optional().describe("TTS provider override."),
|
|
493881
|
+
ttsProvider: z7.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe("TTS provider override."),
|
|
492656
493882
|
voice: z7.string().optional().describe("Voice id."),
|
|
492657
493883
|
imageProvider: z7.string().optional().describe("Image provider override."),
|
|
492658
493884
|
imageQuality: z7.enum(["standard", "hd"]).optional().describe("Image quality override."),
|
|
@@ -492706,7 +493932,7 @@ var storyboardTools = [
|
|
|
492706
493932
|
// ../cli/src/tools/manifest/remix.ts
|
|
492707
493933
|
import { writeFile as writeFile48 } from "node:fs/promises";
|
|
492708
493934
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
492709
|
-
import { join as
|
|
493935
|
+
import { join as join40 } from "node:path";
|
|
492710
493936
|
import { z as z8 } from "zod";
|
|
492711
493937
|
|
|
492712
493938
|
// ../cli/src/commands/ai-script-pipeline.ts
|
|
@@ -494440,7 +495666,7 @@ var pipelineRunTool = defineTool({
|
|
|
494440
495666
|
let resolvedPath = args.pipelinePath;
|
|
494441
495667
|
let tempPath;
|
|
494442
495668
|
if (args.pipelineYaml) {
|
|
494443
|
-
tempPath =
|
|
495669
|
+
tempPath = join40(tmpdir6(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
|
|
494444
495670
|
await writeFile48(tempPath, args.pipelineYaml, "utf-8");
|
|
494445
495671
|
resolvedPath = tempPath;
|
|
494446
495672
|
}
|
|
@@ -494972,7 +496198,7 @@ init_engine();
|
|
|
494972
496198
|
init_storyboard_parse();
|
|
494973
496199
|
import { readdir as readdir8, readFile as readFile42, stat as stat7 } from "node:fs/promises";
|
|
494974
496200
|
import { existsSync as existsSync65 } from "node:fs";
|
|
494975
|
-
import { join as
|
|
496201
|
+
import { join as join41, resolve as resolve71 } from "node:path";
|
|
494976
496202
|
async function executeProjectList(opts = {}) {
|
|
494977
496203
|
const workspaceDir = resolve71(opts.workspaceDir ?? ".");
|
|
494978
496204
|
if (!existsSync65(workspaceDir)) {
|
|
@@ -494992,11 +496218,11 @@ async function executeProjectList(opts = {}) {
|
|
|
494992
496218
|
if (entry.name === "node_modules") continue;
|
|
494993
496219
|
if (entry.name.startsWith(".")) continue;
|
|
494994
496220
|
if (entry.name.startsWith("_")) {
|
|
494995
|
-
archivedCount += await countProjects(
|
|
496221
|
+
archivedCount += await countProjects(join41(workspaceDir, entry.name));
|
|
494996
496222
|
continue;
|
|
494997
496223
|
}
|
|
494998
|
-
const projectDir =
|
|
494999
|
-
if (!existsSync65(
|
|
496224
|
+
const projectDir = join41(workspaceDir, entry.name);
|
|
496225
|
+
if (!existsSync65(join41(projectDir, "STORYBOARD.md"))) continue;
|
|
495000
496226
|
projects.push(await describeProject(entry.name, projectDir));
|
|
495001
496227
|
}
|
|
495002
496228
|
projects.sort((a2, b2) => b2.updatedAt.localeCompare(a2.updatedAt));
|
|
@@ -495006,7 +496232,7 @@ async function countProjects(dir) {
|
|
|
495006
496232
|
try {
|
|
495007
496233
|
const entries2 = await readdir8(dir, { withFileTypes: true });
|
|
495008
496234
|
return entries2.filter(
|
|
495009
|
-
(e2) => e2.isDirectory() && existsSync65(
|
|
496235
|
+
(e2) => e2.isDirectory() && existsSync65(join41(dir, e2.name, "STORYBOARD.md"))
|
|
495010
496236
|
).length;
|
|
495011
496237
|
} catch {
|
|
495012
496238
|
return 0;
|
|
@@ -495017,7 +496243,7 @@ async function describeProject(name, projectDir) {
|
|
|
495017
496243
|
let storyboardDurationSec = 0;
|
|
495018
496244
|
const timestamps = [];
|
|
495019
496245
|
try {
|
|
495020
|
-
const storyboardPath =
|
|
496246
|
+
const storyboardPath = join41(projectDir, "STORYBOARD.md");
|
|
495021
496247
|
const parsed = parseStoryboard(await readFile42(storyboardPath, "utf-8"));
|
|
495022
496248
|
beats = parsed.beats.length;
|
|
495023
496249
|
storyboardDurationSec = Number(
|
|
@@ -495029,7 +496255,7 @@ async function describeProject(name, projectDir) {
|
|
|
495029
496255
|
let buildStatus;
|
|
495030
496256
|
let buildUpdatedAt;
|
|
495031
496257
|
try {
|
|
495032
|
-
const reportPath =
|
|
496258
|
+
const reportPath = join41(projectDir, "build-report.json");
|
|
495033
496259
|
const report = JSON.parse(await readFile42(reportPath, "utf-8"));
|
|
495034
496260
|
buildStatus = report.status ?? report.phase;
|
|
495035
496261
|
buildUpdatedAt = report.updatedAt;
|
|
@@ -495038,12 +496264,12 @@ async function describeProject(name, projectDir) {
|
|
|
495038
496264
|
}
|
|
495039
496265
|
let latestRender;
|
|
495040
496266
|
try {
|
|
495041
|
-
const rendersDir =
|
|
496267
|
+
const rendersDir = join41(projectDir, "renders");
|
|
495042
496268
|
const files = await readdir8(rendersDir);
|
|
495043
496269
|
let newest;
|
|
495044
496270
|
for (const file of files) {
|
|
495045
496271
|
if (!/\.(mp4|webm|mov)$/i.test(file)) continue;
|
|
495046
|
-
const { mtimeMs } = await stat7(
|
|
496272
|
+
const { mtimeMs } = await stat7(join41(rendersDir, file));
|
|
495047
496273
|
if (!newest || mtimeMs > newest.mtimeMs) newest = { file, mtimeMs };
|
|
495048
496274
|
}
|
|
495049
496275
|
if (newest) {
|
|
@@ -496054,7 +497280,7 @@ var exportTools = [exportVideoTool];
|
|
|
496054
497280
|
|
|
496055
497281
|
// ../cli/src/tools/manifest/agent-only.ts
|
|
496056
497282
|
import { readFile as readFile44, writeFile as writeFile52, readdir as readdir9, stat as stat8, access as access7, unlink as unlink7 } from "node:fs/promises";
|
|
496057
|
-
import { resolve as resolve76, join as
|
|
497283
|
+
import { resolve as resolve76, join as join43, basename as basename21, extname as extname14 } from "node:path";
|
|
496058
497284
|
import { z as z13 } from "zod";
|
|
496059
497285
|
init_engine();
|
|
496060
497286
|
init_exec_safe();
|
|
@@ -496133,7 +497359,7 @@ var fsListTool = defineTool({
|
|
|
496133
497359
|
const results = [];
|
|
496134
497360
|
for (const entry of entries2) {
|
|
496135
497361
|
if (args.pattern && !matchPattern(entry.name, args.pattern)) continue;
|
|
496136
|
-
const fullPath =
|
|
497362
|
+
const fullPath = join43(absPath, entry.name);
|
|
496137
497363
|
const stats = await stat8(fullPath);
|
|
496138
497364
|
if (entry.isDirectory()) {
|
|
496139
497365
|
results.push(`[DIR] ${entry.name}/`);
|
|
@@ -496246,7 +497472,7 @@ var batchImportTool = defineTool({
|
|
|
496246
497472
|
const scanDir = async (dir) => {
|
|
496247
497473
|
const entries2 = await readdir9(dir, { withFileTypes: true });
|
|
496248
497474
|
for (const entry of entries2) {
|
|
496249
|
-
const entryPath =
|
|
497475
|
+
const entryPath = join43(dir, entry.name);
|
|
496250
497476
|
if (entry.isDirectory() && recursive) {
|
|
496251
497477
|
await scanDir(entryPath);
|
|
496252
497478
|
} else if (entry.isFile()) {
|
|
@@ -498289,7 +499515,7 @@ function buildServerInstructions(cwd = resolveServerWorkspaceRoot()) {
|
|
|
498289
499515
|
"When creating projects with init, use a project name or workspace-relative path under the workspace root.",
|
|
498290
499516
|
"Do not create projects in /tmp, /home/claude, /workspace, or other synthetic roots unless the user explicitly asks.",
|
|
498291
499517
|
"Before high or very-high cost provider work, run a dry-run or plan when available and ask the user to confirm provider spend.",
|
|
498292
|
-
"When the user's request leaves them unspecified, ask the user before building instead of silently picking defaults: narration provider (kokoro = free
|
|
499518
|
+
"When the user's request leaves them unspecified, ask the user before building instead of silently picking defaults: narration provider (kokoro = free, runs locally, first use downloads a ~90 MB voice model and synthesis is slower; openai = fast cloud voice using the OpenAI API key, roughly $0.02 per video; elevenlabs = premium cloud voices using ElevenLabs credits), backdrop image generation (paid; skipping is free), and visual style (list options via scene_list_styles). Present the choices and wait for the answer.",
|
|
498293
499519
|
"Narration and backdrop choices are independent \u2014 kokoro narration with OpenAI backdrops is a common combination. Pass each answer explicitly to build (ttsProvider plus skipBackdrop/imageProvider); never let one choice imply the other."
|
|
498294
499520
|
].join("\n");
|
|
498295
499521
|
}
|
|
@@ -498316,7 +499542,7 @@ var server2 = new Server(
|
|
|
498316
499542
|
{
|
|
498317
499543
|
name: "vibeframe",
|
|
498318
499544
|
// Stamped with the package version by build.js at bundle time.
|
|
498319
|
-
version: "0.
|
|
499545
|
+
version: "0.113.2"
|
|
498320
499546
|
},
|
|
498321
499547
|
{
|
|
498322
499548
|
capabilities: {
|