@vibeframe/mcp-server 0.113.0 → 0.113.3
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 +131 -120
- package/dist/index.js +1852 -660
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4742,14 +4742,14 @@ async function loadKokoroRuntime() {
|
|
|
4742
4742
|
async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
4743
4743
|
try {
|
|
4744
4744
|
const { readFile: readFile46 } = await import("node:fs/promises");
|
|
4745
|
-
const { join:
|
|
4745
|
+
const { join: join44, resolve: resolve80 } = await import("node:path");
|
|
4746
4746
|
const { pathToFileURL } = await import("node:url");
|
|
4747
4747
|
const pkgDir = resolve80(baseDir, "node_modules", "kokoro-js");
|
|
4748
|
-
const pkg = JSON.parse(await readFile46(
|
|
4748
|
+
const pkg = JSON.parse(await readFile46(join44(pkgDir, "package.json"), "utf-8"));
|
|
4749
4749
|
const entry = pkg.exports?.node?.import ?? pkg.exports?.default ?? pkg.module ?? pkg.main;
|
|
4750
4750
|
if (!entry)
|
|
4751
4751
|
return null;
|
|
4752
|
-
const mod = await import(pathToFileURL(
|
|
4752
|
+
const mod = await import(pathToFileURL(join44(pkgDir, entry)).href);
|
|
4753
4753
|
return mod.KokoroTTS ?? null;
|
|
4754
4754
|
} catch {
|
|
4755
4755
|
return null;
|
|
@@ -4761,19 +4761,19 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4761
4761
|
return null;
|
|
4762
4762
|
try {
|
|
4763
4763
|
const { readFile: readFile46, writeFile: writeFile53, mkdir: mkdir30 } = await import("node:fs/promises");
|
|
4764
|
-
const { join:
|
|
4764
|
+
const { join: join44, resolve: resolve80 } = await import("node:path");
|
|
4765
4765
|
const { pathToFileURL } = await import("node:url");
|
|
4766
4766
|
const { homedir: homedir8 } = await import("node:os");
|
|
4767
4767
|
const transformersDir = resolve80(base, "node_modules", "@huggingface", "transformers");
|
|
4768
4768
|
const ortDistDir = resolve80(base, "node_modules", "onnxruntime-web", "dist");
|
|
4769
|
-
const transformers = await import(pathToFileURL(
|
|
4770
|
-
const cacheRoot =
|
|
4769
|
+
const transformers = await import(pathToFileURL(join44(transformersDir, "dist", "transformers.web.js")).href);
|
|
4770
|
+
const cacheRoot = join44(homedir8(), ".cache", "vibeframe", "models");
|
|
4771
4771
|
transformers.env.allowLocalModels = false;
|
|
4772
4772
|
transformers.env.useCustomCache = true;
|
|
4773
4773
|
transformers.env.customCache = {
|
|
4774
4774
|
async match(key2) {
|
|
4775
4775
|
try {
|
|
4776
|
-
return new Response(await readFile46(
|
|
4776
|
+
return new Response(await readFile46(join44(cacheRoot, encodeURIComponent(String(key2)))));
|
|
4777
4777
|
} catch {
|
|
4778
4778
|
return void 0;
|
|
4779
4779
|
}
|
|
@@ -4782,7 +4782,7 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4782
4782
|
try {
|
|
4783
4783
|
const buf = Buffer.from(await response.arrayBuffer());
|
|
4784
4784
|
await mkdir30(cacheRoot, { recursive: true });
|
|
4785
|
-
await writeFile53(
|
|
4785
|
+
await writeFile53(join44(cacheRoot, encodeURIComponent(String(key2))), buf);
|
|
4786
4786
|
} catch {
|
|
4787
4787
|
}
|
|
4788
4788
|
}
|
|
@@ -10460,6 +10460,19 @@ var require_src = __commonJS({
|
|
|
10460
10460
|
});
|
|
10461
10461
|
|
|
10462
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
|
+
}
|
|
10463
10476
|
function formatFalError(error) {
|
|
10464
10477
|
if (!(error instanceof Error))
|
|
10465
10478
|
return String(error);
|
|
@@ -10569,7 +10582,7 @@ function normaliseDuration(value) {
|
|
|
10569
10582
|
return "auto";
|
|
10570
10583
|
return Math.max(4, Math.min(15, Math.round(value)));
|
|
10571
10584
|
}
|
|
10572
|
-
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;
|
|
10573
10586
|
var init_FalProvider = __esm({
|
|
10574
10587
|
"../ai-providers/dist/fal/FalProvider.js"() {
|
|
10575
10588
|
"use strict";
|
|
@@ -10589,6 +10602,10 @@ var init_FalProvider = __esm({
|
|
|
10589
10602
|
DEFAULT_VARIANT = "seedance-2.0";
|
|
10590
10603
|
VALID_RESOLUTIONS = ["480p", "720p", "1080p"];
|
|
10591
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 };
|
|
10592
10609
|
FalProvider = class {
|
|
10593
10610
|
constructor() {
|
|
10594
10611
|
this.id = "seedance";
|
|
@@ -11413,6 +11430,7 @@ __export(dist_exports, {
|
|
|
11413
11430
|
defineApiKey: () => defineApiKey,
|
|
11414
11431
|
defineProvider: () => defineProvider,
|
|
11415
11432
|
elevenLabsProvider: () => elevenLabsProvider,
|
|
11433
|
+
estimateSeedanceVideoCostUsd: () => estimateSeedanceVideoCostUsd,
|
|
11416
11434
|
falProvider: () => falProvider,
|
|
11417
11435
|
geminiProvider: () => geminiProvider,
|
|
11418
11436
|
getAllApiKeys: () => getAllApiKeys,
|
|
@@ -24219,7 +24237,534 @@ var init_build_asset_metadata = __esm({
|
|
|
24219
24237
|
}
|
|
24220
24238
|
});
|
|
24221
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
|
+
|
|
24222
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
|
+
}
|
|
24223
24768
|
function parseStoryboard(md) {
|
|
24224
24769
|
const normalized = md.replace(/\r\n/g, "\n");
|
|
24225
24770
|
const { frontmatter, remaining } = extractProjectFrontmatter(normalized);
|
|
@@ -24332,28 +24877,28 @@ var init_storyboard_parse = __esm({
|
|
|
24332
24877
|
// ../cli/src/commands/_shared/status-jobs.ts
|
|
24333
24878
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
24334
24879
|
import { existsSync as existsSync2, statSync } from "node:fs";
|
|
24335
|
-
import { copyFile, mkdir as mkdir3, readFile as readFile4, readdir, stat, writeFile as
|
|
24336
|
-
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";
|
|
24337
24882
|
function isLocalJob(record) {
|
|
24338
24883
|
return record.jobType === "build" || record.jobType === "render";
|
|
24339
24884
|
}
|
|
24340
24885
|
function findProjectRoot(start = process.cwd()) {
|
|
24341
|
-
let dir =
|
|
24886
|
+
let dir = resolve6(start);
|
|
24342
24887
|
try {
|
|
24343
24888
|
if (existsSync2(dir) && statSync(dir).isFile()) dir = dirname3(dir);
|
|
24344
24889
|
} catch {
|
|
24345
24890
|
}
|
|
24346
24891
|
for (; ; ) {
|
|
24347
|
-
if (existsSync2(
|
|
24892
|
+
if (existsSync2(join3(dir, "vibe.config.json")) || existsSync2(join3(dir, "STORYBOARD.md"))) {
|
|
24348
24893
|
return dir;
|
|
24349
24894
|
}
|
|
24350
24895
|
const parent = dirname3(dir);
|
|
24351
|
-
if (parent === dir) return
|
|
24896
|
+
if (parent === dir) return resolve6(start);
|
|
24352
24897
|
dir = parent;
|
|
24353
24898
|
}
|
|
24354
24899
|
}
|
|
24355
24900
|
function jobsDir(projectDir) {
|
|
24356
|
-
return
|
|
24901
|
+
return join3(resolve6(projectDir), ".vibeframe", "jobs");
|
|
24357
24902
|
}
|
|
24358
24903
|
function normalizeJobStatus(status) {
|
|
24359
24904
|
const value = String(status ?? "").toLowerCase();
|
|
@@ -24367,10 +24912,10 @@ function normalizeJobStatus(status) {
|
|
|
24367
24912
|
}
|
|
24368
24913
|
function createJobRecord(opts) {
|
|
24369
24914
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
24370
|
-
const projectDir =
|
|
24915
|
+
const projectDir = resolve6(
|
|
24371
24916
|
opts.projectDir ?? findProjectRoot(opts.workingDirectory ?? process.cwd())
|
|
24372
24917
|
);
|
|
24373
|
-
const workingDirectory =
|
|
24918
|
+
const workingDirectory = resolve6(opts.workingDirectory ?? process.cwd());
|
|
24374
24919
|
const id = opts.id ?? makeJobId(opts.providerTaskId, now);
|
|
24375
24920
|
const base = {
|
|
24376
24921
|
schemaVersion: "1",
|
|
@@ -24405,7 +24950,7 @@ function createJobRecord(opts) {
|
|
|
24405
24950
|
message: opts.message
|
|
24406
24951
|
};
|
|
24407
24952
|
base.retryWith = retryWithForJob(base);
|
|
24408
|
-
return
|
|
24953
|
+
return stripUndefined2(base);
|
|
24409
24954
|
}
|
|
24410
24955
|
async function createAndWriteJobRecord(opts) {
|
|
24411
24956
|
const record = createJobRecord(opts);
|
|
@@ -24415,15 +24960,15 @@ async function createAndWriteJobRecord(opts) {
|
|
|
24415
24960
|
async function writeJobRecord(record) {
|
|
24416
24961
|
const dir = jobsDir(record.projectDir);
|
|
24417
24962
|
await mkdir3(dir, { recursive: true });
|
|
24418
|
-
await
|
|
24963
|
+
await writeFile7(
|
|
24419
24964
|
jobRecordPath(record.id, record.projectDir),
|
|
24420
|
-
JSON.stringify(
|
|
24965
|
+
JSON.stringify(stripUndefined2(record), null, 2) + "\n",
|
|
24421
24966
|
"utf-8"
|
|
24422
24967
|
);
|
|
24423
24968
|
}
|
|
24424
24969
|
async function readJobRecord(jobId, projectDir) {
|
|
24425
24970
|
const id = normalizeJobId(jobId);
|
|
24426
|
-
const project =
|
|
24971
|
+
const project = resolve6(projectDir ?? findProjectRoot());
|
|
24427
24972
|
const path14 = jobRecordPath(id, project);
|
|
24428
24973
|
if (!existsSync2(path14)) return null;
|
|
24429
24974
|
return parseJobRecord(await readFile4(path14, "utf-8"));
|
|
@@ -24436,7 +24981,7 @@ async function listJobRecords(projectDir) {
|
|
|
24436
24981
|
for (const entry of entries2) {
|
|
24437
24982
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
24438
24983
|
try {
|
|
24439
|
-
const parsed = parseJobRecord(await readFile4(
|
|
24984
|
+
const parsed = parseJobRecord(await readFile4(join3(dir, entry.name), "utf-8"));
|
|
24440
24985
|
if (parsed) records.push(parsed);
|
|
24441
24986
|
} catch {
|
|
24442
24987
|
}
|
|
@@ -24530,9 +25075,9 @@ async function refreshLocalJobRecord(record, opts) {
|
|
|
24530
25075
|
const heartbeatAge = record.heartbeatAt ? Date.now() - new Date(record.heartbeatAt).getTime() : Number.POSITIVE_INFINITY;
|
|
24531
25076
|
const orphaned = !isPidAlive(record.pid) || heartbeatAge > LOCAL_JOB_ORPHAN_AFTER_MS;
|
|
24532
25077
|
if (orphaned) {
|
|
24533
|
-
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.`;
|
|
24534
25079
|
warnings.push(hint);
|
|
24535
|
-
updated =
|
|
25080
|
+
updated = stripUndefined2({
|
|
24536
25081
|
...record,
|
|
24537
25082
|
status: "unknown",
|
|
24538
25083
|
error: record.error ?? hint,
|
|
@@ -24549,7 +25094,7 @@ async function refreshLocalJobRecord(record, opts) {
|
|
|
24549
25094
|
});
|
|
24550
25095
|
}
|
|
24551
25096
|
async function inspectProjectStatus(projectDirArg, opts = {}) {
|
|
24552
|
-
const project =
|
|
25097
|
+
const project = resolve6(projectDirArg);
|
|
24553
25098
|
const warnings = [];
|
|
24554
25099
|
let records = await listJobRecords(project);
|
|
24555
25100
|
if (opts.refresh) {
|
|
@@ -24579,6 +25124,10 @@ async function inspectProjectStatus(projectDirArg, opts = {}) {
|
|
|
24579
25124
|
...review?.retryWith ?? [],
|
|
24580
25125
|
...workflow.retryWith
|
|
24581
25126
|
];
|
|
25127
|
+
const nextActions = normalizeReviewActions([
|
|
25128
|
+
...review?.nextActions ?? [],
|
|
25129
|
+
...reviewActionsFromRetryWith([...build?.retryWith ?? [], ...workflow.retryWith])
|
|
25130
|
+
]);
|
|
24582
25131
|
return {
|
|
24583
25132
|
schemaVersion: "1",
|
|
24584
25133
|
kind: "project",
|
|
@@ -24590,11 +25139,12 @@ async function inspectProjectStatus(projectDirArg, opts = {}) {
|
|
|
24590
25139
|
review,
|
|
24591
25140
|
jobs,
|
|
24592
25141
|
warnings,
|
|
25142
|
+
nextActions,
|
|
24593
25143
|
retryWith: unique(retryWith)
|
|
24594
25144
|
};
|
|
24595
25145
|
}
|
|
24596
25146
|
function summarizeJob(record) {
|
|
24597
|
-
return
|
|
25147
|
+
return stripUndefined2({
|
|
24598
25148
|
id: record.id,
|
|
24599
25149
|
jobType: record.jobType,
|
|
24600
25150
|
status: record.status,
|
|
@@ -24618,7 +25168,7 @@ function retryWithForJob(record) {
|
|
|
24618
25168
|
]);
|
|
24619
25169
|
}
|
|
24620
25170
|
function makeJobStatusResult(record, opts) {
|
|
24621
|
-
return
|
|
25171
|
+
return stripUndefined2({
|
|
24622
25172
|
schemaVersion: "1",
|
|
24623
25173
|
kind: "job",
|
|
24624
25174
|
id: record.id,
|
|
@@ -24642,7 +25192,7 @@ function jobProgress(record) {
|
|
|
24642
25192
|
if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
|
|
24643
25193
|
if (record.progress === void 0 && !record.providerStatus) return void 0;
|
|
24644
25194
|
}
|
|
24645
|
-
return
|
|
25195
|
+
return stripUndefined2({
|
|
24646
25196
|
percent: record.progress,
|
|
24647
25197
|
phase: record.stage ?? record.providerStatus ?? statusPhase(record.status),
|
|
24648
25198
|
providerStatus: record.providerStatus ?? record.message
|
|
@@ -24652,7 +25202,7 @@ function jobResult(record) {
|
|
|
24652
25202
|
if (!record.resultUrl && !record.outputPath && !record.cachePath && !record.error && !record.resultPayload) {
|
|
24653
25203
|
return null;
|
|
24654
25204
|
}
|
|
24655
|
-
return
|
|
25205
|
+
return stripUndefined2({
|
|
24656
25206
|
url: record.resultUrl,
|
|
24657
25207
|
outputPath: record.outputPath,
|
|
24658
25208
|
cachePath: record.cachePath,
|
|
@@ -24688,7 +25238,7 @@ function normalizeJobId(jobId) {
|
|
|
24688
25238
|
return id;
|
|
24689
25239
|
}
|
|
24690
25240
|
function jobRecordPath(jobId, projectDir) {
|
|
24691
|
-
return
|
|
25241
|
+
return join3(jobsDir(projectDir), `${normalizeJobId(jobId)}.json`);
|
|
24692
25242
|
}
|
|
24693
25243
|
function parseJobRecord(raw2) {
|
|
24694
25244
|
const parsed = JSON.parse(raw2);
|
|
@@ -24713,11 +25263,11 @@ function updateRecordFromProvider(record, result) {
|
|
|
24713
25263
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24714
25264
|
};
|
|
24715
25265
|
next.retryWith = retryWithForJob(next);
|
|
24716
|
-
return
|
|
25266
|
+
return stripUndefined2(next);
|
|
24717
25267
|
}
|
|
24718
25268
|
function resolveRefreshOutput(record, opts) {
|
|
24719
|
-
if (opts.output) return
|
|
24720
|
-
return record.outputPath ?
|
|
25269
|
+
if (opts.output) return resolve6(opts.workingDirectory ?? process.cwd(), opts.output);
|
|
25270
|
+
return record.outputPath ? resolve6(record.outputPath) : void 0;
|
|
24721
25271
|
}
|
|
24722
25272
|
function liveSupport(record) {
|
|
24723
25273
|
if (record.jobType === "generate-video" && (record.provider === "grok" || record.provider === "runway" || record.provider === "kling" || record.provider === "veo")) {
|
|
@@ -24742,7 +25292,7 @@ async function downloadUrl(url, outputPath) {
|
|
|
24742
25292
|
if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`);
|
|
24743
25293
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
24744
25294
|
await mkdir3(dirname3(outputPath), { recursive: true });
|
|
24745
|
-
await
|
|
25295
|
+
await writeFile7(outputPath, buffer);
|
|
24746
25296
|
return outputPath;
|
|
24747
25297
|
}
|
|
24748
25298
|
async function maybeCacheOutput(record) {
|
|
@@ -24774,7 +25324,7 @@ async function maybeWriteCompletedAssetMetadata(record) {
|
|
|
24774
25324
|
}
|
|
24775
25325
|
}
|
|
24776
25326
|
async function refreshBuildReportFromJobs(projectDir, records) {
|
|
24777
|
-
const reportPath =
|
|
25327
|
+
const reportPath = join3(projectDir, "build-report.json");
|
|
24778
25328
|
const report = await readJson(reportPath);
|
|
24779
25329
|
if (!report || !Array.isArray(report.beats)) return;
|
|
24780
25330
|
let changed = false;
|
|
@@ -24802,7 +25352,7 @@ async function refreshBuildReportFromJobs(projectDir, records) {
|
|
|
24802
25352
|
if (kind3 === "music" && record.assetOptions && typeof record.assetOptions.duration === "number") {
|
|
24803
25353
|
nested.durationSec = record.assetOptions.duration;
|
|
24804
25354
|
}
|
|
24805
|
-
beatRecord[kind3] =
|
|
25355
|
+
beatRecord[kind3] = stripUndefined2(nested);
|
|
24806
25356
|
beatRecord[`${kind3}Path`] = outputPath;
|
|
24807
25357
|
beatRecord[`${kind3}Status`] = "generated";
|
|
24808
25358
|
beatRecord[`${kind3}JobId`] = record.id;
|
|
@@ -24822,17 +25372,17 @@ async function refreshBuildReportFromJobs(projectDir, records) {
|
|
|
24822
25372
|
}
|
|
24823
25373
|
if (!changed) return;
|
|
24824
25374
|
try {
|
|
24825
|
-
await
|
|
25375
|
+
await writeFile7(reportPath, JSON.stringify(stripUndefined2(report), null, 2) + "\n", "utf-8");
|
|
24826
25376
|
} catch {
|
|
24827
25377
|
}
|
|
24828
25378
|
}
|
|
24829
25379
|
async function readBuildSummary(projectDir) {
|
|
24830
|
-
const reportPath =
|
|
25380
|
+
const reportPath = join3(projectDir, "build-report.json");
|
|
24831
25381
|
const report = await readJson(reportPath);
|
|
24832
25382
|
if (!report) return null;
|
|
24833
25383
|
const info = await statOrNull(reportPath);
|
|
24834
25384
|
const beatSummary = projectBeatReadinessFromUnknown(report.beatSummary);
|
|
24835
|
-
return
|
|
25385
|
+
return stripUndefined2({
|
|
24836
25386
|
reportPath,
|
|
24837
25387
|
kind: typeof report.kind === "string" ? report.kind : void 0,
|
|
24838
25388
|
success: typeof report.success === "boolean" ? report.success : void 0,
|
|
@@ -24850,7 +25400,7 @@ async function readBuildSummary(projectDir) {
|
|
|
24850
25400
|
});
|
|
24851
25401
|
}
|
|
24852
25402
|
async function readReviewSummary(projectDir) {
|
|
24853
|
-
const reportPath =
|
|
25403
|
+
const reportPath = join3(projectDir, "review-report.json");
|
|
24854
25404
|
const report = await readJson(reportPath);
|
|
24855
25405
|
if (!report) return null;
|
|
24856
25406
|
const info = await statOrNull(reportPath);
|
|
@@ -24858,7 +25408,7 @@ async function readReviewSummary(projectDir) {
|
|
|
24858
25408
|
const summary = report.summary && typeof report.summary === "object" ? report.summary : {};
|
|
24859
25409
|
const fixOwners = summary.fixOwners && typeof summary.fixOwners === "object" ? summary.fixOwners : {};
|
|
24860
25410
|
const computedFixOwners = countIssueFixOwners(issues);
|
|
24861
|
-
return
|
|
25411
|
+
return stripUndefined2({
|
|
24862
25412
|
reportPath,
|
|
24863
25413
|
kind: typeof report.kind === "string" ? report.kind : void 0,
|
|
24864
25414
|
mode: typeof report.mode === "string" ? report.mode : void 0,
|
|
@@ -24883,9 +25433,44 @@ async function readReviewSummary(projectDir) {
|
|
|
24883
25433
|
},
|
|
24884
25434
|
sourceReports: stringArray(report.sourceReports),
|
|
24885
25435
|
updatedAt: info?.mtime.toISOString(),
|
|
25436
|
+
nextActions: reviewActionsFromUnknown(report.nextActions),
|
|
24886
25437
|
retryWith: stringArray(report.retryWith)
|
|
24887
25438
|
});
|
|
24888
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
|
+
}
|
|
24889
25474
|
function summarizeJobs(records) {
|
|
24890
25475
|
return {
|
|
24891
25476
|
total: records.length,
|
|
@@ -24904,7 +25489,7 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
24904
25489
|
if (fromBeats) return fromBeats;
|
|
24905
25490
|
if (build.beats) return augmentBeatReadinessFromJobs(build.beats, records, report?.jobs);
|
|
24906
25491
|
}
|
|
24907
|
-
const storyboardPath =
|
|
25492
|
+
const storyboardPath = join3(projectDir, "STORYBOARD.md");
|
|
24908
25493
|
if (!existsSync2(storyboardPath)) {
|
|
24909
25494
|
return { total: 0, assetsReady: 0, compositionsReady: 0, needsAuthor: [] };
|
|
24910
25495
|
}
|
|
@@ -24913,7 +25498,7 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
24913
25498
|
const needsAuthor = [];
|
|
24914
25499
|
let compositionsReady = 0;
|
|
24915
25500
|
for (const beat of parsed.beats) {
|
|
24916
|
-
if (existsSync2(
|
|
25501
|
+
if (existsSync2(join3(projectDir, "compositions", `scene-${beat.id}.html`))) {
|
|
24917
25502
|
compositionsReady += 1;
|
|
24918
25503
|
} else {
|
|
24919
25504
|
needsAuthor.push(beat.id);
|
|
@@ -24931,7 +25516,7 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
24931
25516
|
}
|
|
24932
25517
|
function deriveProjectWorkflow(opts) {
|
|
24933
25518
|
const retryWith = [];
|
|
24934
|
-
const hasStoryboard = existsSync2(
|
|
25519
|
+
const hasStoryboard = existsSync2(join3(opts.project, "STORYBOARD.md"));
|
|
24935
25520
|
if (!hasStoryboard && !opts.build) {
|
|
24936
25521
|
retryWith.push(`vibe init ${opts.project} --from "<brief>" --json`);
|
|
24937
25522
|
return { status: "empty", currentStage: "init", retryWith };
|
|
@@ -25027,7 +25612,7 @@ function beatReadinessFromBuildBeats(projectDir, beats, records = [], reportJobs
|
|
|
25027
25612
|
if (buildBeatAssetsReady(record) || (id ? buildBeatJobsReady(id, records, reportJobs) : false))
|
|
25028
25613
|
assetsReady += 1;
|
|
25029
25614
|
const compositionPath = typeof record.compositionPath === "string" ? record.compositionPath : id ? `compositions/scene-${id}.html` : void 0;
|
|
25030
|
-
if (compositionPath && existsSync2(
|
|
25615
|
+
if (compositionPath && existsSync2(resolve6(projectDir, compositionPath))) {
|
|
25031
25616
|
compositionsReady += 1;
|
|
25032
25617
|
} else if (id) {
|
|
25033
25618
|
needsAuthor.push(id);
|
|
@@ -25097,6 +25682,9 @@ function numberOr(fallback2, value) {
|
|
|
25097
25682
|
function stringArray(value) {
|
|
25098
25683
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.length > 0) : [];
|
|
25099
25684
|
}
|
|
25685
|
+
function stringEnum(value, allowed) {
|
|
25686
|
+
return typeof value === "string" && allowed.includes(value) ? value : void 0;
|
|
25687
|
+
}
|
|
25100
25688
|
function isActiveStatus(status) {
|
|
25101
25689
|
return status === "queued" || status === "running";
|
|
25102
25690
|
}
|
|
@@ -25126,7 +25714,7 @@ function assetKindForJob(record) {
|
|
|
25126
25714
|
return void 0;
|
|
25127
25715
|
}
|
|
25128
25716
|
function projectRelativePath(projectDir, path14) {
|
|
25129
|
-
const rel = relative(
|
|
25717
|
+
const rel = relative(resolve6(projectDir), resolve6(path14));
|
|
25130
25718
|
if (!rel || rel.startsWith("..")) return path14;
|
|
25131
25719
|
return rel.replace(/\\/g, "/");
|
|
25132
25720
|
}
|
|
@@ -25144,7 +25732,7 @@ async function statOrNull(path14) {
|
|
|
25144
25732
|
return null;
|
|
25145
25733
|
}
|
|
25146
25734
|
}
|
|
25147
|
-
function
|
|
25735
|
+
function stripUndefined2(value) {
|
|
25148
25736
|
return Object.fromEntries(Object.entries(value).filter(([, v2]) => v2 !== void 0));
|
|
25149
25737
|
}
|
|
25150
25738
|
function unique(items) {
|
|
@@ -25162,6 +25750,7 @@ var init_status_jobs = __esm({
|
|
|
25162
25750
|
init_ai_video();
|
|
25163
25751
|
init_music_status();
|
|
25164
25752
|
init_build_asset_metadata();
|
|
25753
|
+
init_review_report();
|
|
25165
25754
|
init_storyboard_parse();
|
|
25166
25755
|
LOCAL_JOB_ORPHAN_AFTER_MS = 9e4;
|
|
25167
25756
|
}
|
|
@@ -25170,7 +25759,7 @@ var init_status_jobs = __esm({
|
|
|
25170
25759
|
// ../cli/src/commands/_shared/project-config.ts
|
|
25171
25760
|
import { existsSync as existsSync3 } from "node:fs";
|
|
25172
25761
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
25173
|
-
import { resolve as
|
|
25762
|
+
import { resolve as resolve7 } from "node:path";
|
|
25174
25763
|
function defaultProjectConfig(opts) {
|
|
25175
25764
|
return {
|
|
25176
25765
|
schemaVersion: "1",
|
|
@@ -25221,9 +25810,9 @@ function projectConfigJson(opts) {
|
|
|
25221
25810
|
return JSON.stringify(defaultProjectConfig(opts), null, 2) + "\n";
|
|
25222
25811
|
}
|
|
25223
25812
|
async function readProjectConfig(projectDir) {
|
|
25224
|
-
const dir =
|
|
25225
|
-
const canonicalPath =
|
|
25226
|
-
const legacyPath =
|
|
25813
|
+
const dir = resolve7(projectDir);
|
|
25814
|
+
const canonicalPath = resolve7(dir, VIBE_CONFIG_FILENAME);
|
|
25815
|
+
const legacyPath = resolve7(dir, LEGACY_VIBE_PROJECT_FILENAME);
|
|
25227
25816
|
if (existsSync3(canonicalPath)) {
|
|
25228
25817
|
try {
|
|
25229
25818
|
const raw2 = await readFile5(canonicalPath, "utf-8");
|
|
@@ -25286,8 +25875,8 @@ var init_project_config = __esm({
|
|
|
25286
25875
|
});
|
|
25287
25876
|
|
|
25288
25877
|
// ../cli/src/commands/_shared/scene-project.ts
|
|
25289
|
-
import { mkdir as mkdir4, readFile as readFile6, writeFile as
|
|
25290
|
-
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";
|
|
25291
25880
|
function aspectToDims(aspect) {
|
|
25292
25881
|
return ASPECT_DIMS[aspect];
|
|
25293
25882
|
}
|
|
@@ -25585,6 +26174,43 @@ vibe host setup all --write # write project/app config
|
|
|
25585
26174
|
vibe host doctor all --json # verify readiness
|
|
25586
26175
|
\`\`\`
|
|
25587
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
|
+
|
|
25588
26214
|
## Skills \u2014 USE THESE FIRST
|
|
25589
26215
|
|
|
25590
26216
|
@SKILL.md
|
|
@@ -25688,35 +26314,35 @@ tmp/
|
|
|
25688
26314
|
`;
|
|
25689
26315
|
}
|
|
25690
26316
|
function describeSceneScaffold(opts) {
|
|
25691
|
-
const dir =
|
|
26317
|
+
const dir = resolve8(opts.dir);
|
|
25692
26318
|
const profile = opts.profile ?? "full";
|
|
25693
26319
|
const groups = {
|
|
25694
26320
|
authoring: [
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
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")
|
|
25700
26326
|
],
|
|
25701
26327
|
render: [],
|
|
25702
26328
|
agent: []
|
|
25703
26329
|
};
|
|
25704
26330
|
if (profile === "full") {
|
|
25705
26331
|
groups.render = [
|
|
25706
|
-
|
|
25707
|
-
|
|
25708
|
-
|
|
25709
|
-
|
|
25710
|
-
|
|
25711
|
-
|
|
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")
|
|
25712
26338
|
];
|
|
25713
26339
|
}
|
|
25714
26340
|
if (profile === "agent" || profile === "full") {
|
|
25715
26341
|
groups.agent = [
|
|
25716
|
-
|
|
25717
|
-
|
|
25718
|
-
|
|
25719
|
-
|
|
26342
|
+
resolve8(dir, "AGENTS.md"),
|
|
26343
|
+
resolve8(dir, "SKILL.md"),
|
|
26344
|
+
resolve8(dir, "references"),
|
|
26345
|
+
resolve8(dir, "CLAUDE.md")
|
|
25720
26346
|
];
|
|
25721
26347
|
}
|
|
25722
26348
|
return groups;
|
|
@@ -25730,7 +26356,7 @@ async function pathExists(p2) {
|
|
|
25730
26356
|
}
|
|
25731
26357
|
}
|
|
25732
26358
|
async function scaffoldSceneProject(opts) {
|
|
25733
|
-
const dir =
|
|
26359
|
+
const dir = resolve8(opts.dir);
|
|
25734
26360
|
const name = opts.name ?? basename2(dir);
|
|
25735
26361
|
const aspect = opts.aspect ?? "16:9";
|
|
25736
26362
|
const duration = opts.duration ?? 10;
|
|
@@ -25738,103 +26364,103 @@ async function scaffoldSceneProject(opts) {
|
|
|
25738
26364
|
const profile = opts.profile ?? "full";
|
|
25739
26365
|
await mkdir4(dir, { recursive: true });
|
|
25740
26366
|
if (profile === "full") {
|
|
25741
|
-
await mkdir4(
|
|
25742
|
-
await mkdir4(
|
|
25743
|
-
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 });
|
|
25744
26370
|
}
|
|
25745
26371
|
const created = [];
|
|
25746
26372
|
const skipped2 = [];
|
|
25747
26373
|
const merged = [];
|
|
25748
26374
|
if (profile === "full") {
|
|
25749
|
-
const hfPath =
|
|
26375
|
+
const hfPath = resolve8(dir, "hyperframes.json");
|
|
25750
26376
|
const hfDefaults = buildHyperframesConfig();
|
|
25751
26377
|
if (await pathExists(hfPath)) {
|
|
25752
26378
|
const existingRaw = await readFile6(hfPath, "utf-8");
|
|
25753
26379
|
const existing = JSON.parse(existingRaw);
|
|
25754
26380
|
const mergedConfig = mergeHyperframesConfig(existing, hfDefaults);
|
|
25755
|
-
await
|
|
26381
|
+
await writeFile8(hfPath, JSON.stringify(mergedConfig, null, 2) + "\n", "utf-8");
|
|
25756
26382
|
merged.push(hfPath);
|
|
25757
26383
|
} else {
|
|
25758
|
-
await
|
|
26384
|
+
await writeFile8(hfPath, JSON.stringify(hfDefaults, null, 2) + "\n", "utf-8");
|
|
25759
26385
|
created.push(hfPath);
|
|
25760
26386
|
}
|
|
25761
|
-
const metaPath =
|
|
26387
|
+
const metaPath = resolve8(dir, "meta.json");
|
|
25762
26388
|
if (await pathExists(metaPath)) {
|
|
25763
26389
|
skipped2.push(metaPath);
|
|
25764
26390
|
} else {
|
|
25765
|
-
await
|
|
26391
|
+
await writeFile8(
|
|
25766
26392
|
metaPath,
|
|
25767
26393
|
JSON.stringify(buildHyperframesMeta(name, now), null, 2) + "\n",
|
|
25768
26394
|
"utf-8"
|
|
25769
26395
|
);
|
|
25770
26396
|
created.push(metaPath);
|
|
25771
26397
|
}
|
|
25772
|
-
const rootPath =
|
|
26398
|
+
const rootPath = resolve8(dir, "index.html");
|
|
25773
26399
|
if (await pathExists(rootPath)) {
|
|
25774
26400
|
skipped2.push(rootPath);
|
|
25775
26401
|
} else {
|
|
25776
|
-
await
|
|
26402
|
+
await writeFile8(rootPath, buildEmptyRootHtml({ aspect, duration }), "utf-8");
|
|
25777
26403
|
created.push(rootPath);
|
|
25778
26404
|
}
|
|
25779
26405
|
}
|
|
25780
|
-
const vibeConfigJsonPath =
|
|
26406
|
+
const vibeConfigJsonPath = resolve8(dir, VIBE_CONFIG_FILENAME);
|
|
25781
26407
|
if (await pathExists(vibeConfigJsonPath)) {
|
|
25782
26408
|
skipped2.push(vibeConfigJsonPath);
|
|
25783
26409
|
} else {
|
|
25784
|
-
await
|
|
26410
|
+
await writeFile8(vibeConfigJsonPath, projectConfigJson({ name, aspect }), "utf-8");
|
|
25785
26411
|
created.push(vibeConfigJsonPath);
|
|
25786
26412
|
}
|
|
25787
|
-
const vibePath =
|
|
26413
|
+
const vibePath = resolve8(dir, "vibe.project.yaml");
|
|
25788
26414
|
if (await pathExists(vibePath)) {
|
|
25789
26415
|
skipped2.push(vibePath);
|
|
25790
26416
|
} else {
|
|
25791
26417
|
const cfg = { ...defaultVibeProjectConfig(name), aspect };
|
|
25792
|
-
await
|
|
26418
|
+
await writeFile8(vibePath, (0, import_yaml4.stringify)(cfg), "utf-8");
|
|
25793
26419
|
created.push(vibePath);
|
|
25794
26420
|
}
|
|
25795
26421
|
if (profile === "agent" || profile === "full") {
|
|
25796
|
-
const agentsPath =
|
|
26422
|
+
const agentsPath = resolve8(dir, "AGENTS.md");
|
|
25797
26423
|
if (await pathExists(agentsPath)) {
|
|
25798
26424
|
skipped2.push(agentsPath);
|
|
25799
26425
|
} else {
|
|
25800
|
-
await
|
|
26426
|
+
await writeFile8(agentsPath, buildProjectAgentsMd(name), "utf-8");
|
|
25801
26427
|
created.push(agentsPath);
|
|
25802
26428
|
}
|
|
25803
|
-
const claudePath =
|
|
26429
|
+
const claudePath = resolve8(dir, "CLAUDE.md");
|
|
25804
26430
|
if (await pathExists(claudePath)) {
|
|
25805
26431
|
const existing = await readFile6(claudePath, "utf-8");
|
|
25806
26432
|
if (existing.includes("@AGENTS.md")) {
|
|
25807
26433
|
skipped2.push(claudePath);
|
|
25808
26434
|
} else {
|
|
25809
|
-
await
|
|
26435
|
+
await writeFile8(claudePath, `@AGENTS.md
|
|
25810
26436
|
|
|
25811
26437
|
${existing}`, "utf-8");
|
|
25812
26438
|
merged.push(claudePath);
|
|
25813
26439
|
}
|
|
25814
26440
|
} else {
|
|
25815
|
-
await
|
|
26441
|
+
await writeFile8(claudePath, buildProjectClaudeMd(name), "utf-8");
|
|
25816
26442
|
created.push(claudePath);
|
|
25817
26443
|
}
|
|
25818
26444
|
}
|
|
25819
|
-
const designPath =
|
|
26445
|
+
const designPath = resolve8(dir, "DESIGN.md");
|
|
25820
26446
|
if (await pathExists(designPath)) {
|
|
25821
26447
|
skipped2.push(designPath);
|
|
25822
26448
|
} else {
|
|
25823
|
-
await
|
|
26449
|
+
await writeFile8(designPath, buildDesignMd({ name, style: opts.visualStyle }), "utf-8");
|
|
25824
26450
|
created.push(designPath);
|
|
25825
26451
|
}
|
|
25826
|
-
const storyboardPath =
|
|
26452
|
+
const storyboardPath = resolve8(dir, "STORYBOARD.md");
|
|
25827
26453
|
if (await pathExists(storyboardPath)) {
|
|
25828
26454
|
skipped2.push(storyboardPath);
|
|
25829
26455
|
} else {
|
|
25830
|
-
await
|
|
26456
|
+
await writeFile8(storyboardPath, buildStoryboardMd(name, duration), "utf-8");
|
|
25831
26457
|
created.push(storyboardPath);
|
|
25832
26458
|
}
|
|
25833
|
-
const gitignorePath =
|
|
26459
|
+
const gitignorePath = resolve8(dir, ".gitignore");
|
|
25834
26460
|
if (await pathExists(gitignorePath)) {
|
|
25835
26461
|
skipped2.push(gitignorePath);
|
|
25836
26462
|
} else {
|
|
25837
|
-
await
|
|
26463
|
+
await writeFile8(gitignorePath, buildSceneGitignore(), "utf-8");
|
|
25838
26464
|
created.push(gitignorePath);
|
|
25839
26465
|
}
|
|
25840
26466
|
return { created, skipped: skipped2, merged, groups: describeSceneScaffold({ dir, profile }) };
|
|
@@ -33084,7 +33710,7 @@ var require_util = __commonJS({
|
|
|
33084
33710
|
return path14;
|
|
33085
33711
|
});
|
|
33086
33712
|
exports.normalize = normalize3;
|
|
33087
|
-
function
|
|
33713
|
+
function join44(aRoot, aPath) {
|
|
33088
33714
|
if (aRoot === "") {
|
|
33089
33715
|
aRoot = ".";
|
|
33090
33716
|
}
|
|
@@ -33116,7 +33742,7 @@ var require_util = __commonJS({
|
|
|
33116
33742
|
}
|
|
33117
33743
|
return joined;
|
|
33118
33744
|
}
|
|
33119
|
-
exports.join =
|
|
33745
|
+
exports.join = join44;
|
|
33120
33746
|
exports.isAbsolute = function(aPath) {
|
|
33121
33747
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
33122
33748
|
};
|
|
@@ -33330,7 +33956,7 @@ var require_util = __commonJS({
|
|
|
33330
33956
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
33331
33957
|
}
|
|
33332
33958
|
}
|
|
33333
|
-
sourceURL =
|
|
33959
|
+
sourceURL = join44(urlGenerate(parsed), sourceURL);
|
|
33334
33960
|
}
|
|
33335
33961
|
return normalize3(sourceURL);
|
|
33336
33962
|
}
|
|
@@ -34770,8 +35396,8 @@ var require_source_map = __commonJS({
|
|
|
34770
35396
|
var require_previous_map = __commonJS({
|
|
34771
35397
|
"../../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/previous-map.js"(exports, module) {
|
|
34772
35398
|
"use strict";
|
|
34773
|
-
var { existsSync: existsSync67, readFileSync:
|
|
34774
|
-
var { dirname: dirname33, join:
|
|
35399
|
+
var { existsSync: existsSync67, readFileSync: readFileSync13 } = __require("fs");
|
|
35400
|
+
var { dirname: dirname33, join: join44 } = __require("path");
|
|
34775
35401
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
34776
35402
|
function fromBase64(str2) {
|
|
34777
35403
|
if (Buffer) {
|
|
@@ -34835,7 +35461,7 @@ var require_previous_map = __commonJS({
|
|
|
34835
35461
|
this.root = dirname33(path14);
|
|
34836
35462
|
if (existsSync67(path14)) {
|
|
34837
35463
|
this.mapFile = path14;
|
|
34838
|
-
return
|
|
35464
|
+
return readFileSync13(path14, "utf-8").toString().trim();
|
|
34839
35465
|
}
|
|
34840
35466
|
}
|
|
34841
35467
|
loadMap(file, prev) {
|
|
@@ -34869,7 +35495,7 @@ var require_previous_map = __commonJS({
|
|
|
34869
35495
|
return this.decodeInline(this.annotation);
|
|
34870
35496
|
} else if (this.annotation) {
|
|
34871
35497
|
let map3 = this.annotation;
|
|
34872
|
-
if (file) map3 =
|
|
35498
|
+
if (file) map3 = join44(dirname33(file), map3);
|
|
34873
35499
|
return this.loadFile(map3);
|
|
34874
35500
|
}
|
|
34875
35501
|
}
|
|
@@ -82324,14 +82950,14 @@ var require_re = __commonJS({
|
|
|
82324
82950
|
return value;
|
|
82325
82951
|
};
|
|
82326
82952
|
var createToken = (name, value, isGlobal) => {
|
|
82327
|
-
const
|
|
82953
|
+
const safe2 = makeSafeRegex(value);
|
|
82328
82954
|
const index = R2++;
|
|
82329
82955
|
debug9(name, index, value);
|
|
82330
82956
|
t2[name] = index;
|
|
82331
82957
|
src[index] = value;
|
|
82332
|
-
safeSrc[index] =
|
|
82958
|
+
safeSrc[index] = safe2;
|
|
82333
82959
|
re2[index] = new RegExp(value, isGlobal ? "g" : void 0);
|
|
82334
|
-
safeRe[index] = new RegExp(
|
|
82960
|
+
safeRe[index] = new RegExp(safe2, isGlobal ? "g" : void 0);
|
|
82335
82961
|
};
|
|
82336
82962
|
createToken("NUMERICIDENTIFIER", "0|[1-9]\\d*");
|
|
82337
82963
|
createToken("NUMERICIDENTIFIERLOOSE", "\\d+");
|
|
@@ -93498,7 +94124,7 @@ var require_util3 = __commonJS({
|
|
|
93498
94124
|
return path14;
|
|
93499
94125
|
}
|
|
93500
94126
|
exports.normalize = normalize3;
|
|
93501
|
-
function
|
|
94127
|
+
function join44(aRoot, aPath) {
|
|
93502
94128
|
if (aRoot === "") {
|
|
93503
94129
|
aRoot = ".";
|
|
93504
94130
|
}
|
|
@@ -93530,7 +94156,7 @@ var require_util3 = __commonJS({
|
|
|
93530
94156
|
}
|
|
93531
94157
|
return joined;
|
|
93532
94158
|
}
|
|
93533
|
-
exports.join =
|
|
94159
|
+
exports.join = join44;
|
|
93534
94160
|
exports.isAbsolute = function(aPath) {
|
|
93535
94161
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
93536
94162
|
};
|
|
@@ -93703,7 +94329,7 @@ var require_util3 = __commonJS({
|
|
|
93703
94329
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
93704
94330
|
}
|
|
93705
94331
|
}
|
|
93706
|
-
sourceURL =
|
|
94332
|
+
sourceURL = join44(urlGenerate(parsed), sourceURL);
|
|
93707
94333
|
}
|
|
93708
94334
|
return normalize3(sourceURL);
|
|
93709
94335
|
}
|
|
@@ -95505,7 +96131,7 @@ var require_escodegen = __commonJS({
|
|
|
95505
96131
|
function noEmptySpace() {
|
|
95506
96132
|
return space ? space : " ";
|
|
95507
96133
|
}
|
|
95508
|
-
function
|
|
96134
|
+
function join44(left3, right3) {
|
|
95509
96135
|
var leftSource, rightSource, leftCharCode, rightCharCode;
|
|
95510
96136
|
leftSource = toSourceNodeWhenNeeded(left3).toString();
|
|
95511
96137
|
if (leftSource.length === 0) {
|
|
@@ -95836,8 +96462,8 @@ var require_escodegen = __commonJS({
|
|
|
95836
96462
|
} else {
|
|
95837
96463
|
result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
|
|
95838
96464
|
}
|
|
95839
|
-
result =
|
|
95840
|
-
result = [
|
|
96465
|
+
result = join44(result, operator);
|
|
96466
|
+
result = [join44(
|
|
95841
96467
|
result,
|
|
95842
96468
|
that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
|
|
95843
96469
|
), ")"];
|
|
@@ -95980,11 +96606,11 @@ var require_escodegen = __commonJS({
|
|
|
95980
96606
|
var result, fragment;
|
|
95981
96607
|
result = ["class"];
|
|
95982
96608
|
if (stmt.id) {
|
|
95983
|
-
result =
|
|
96609
|
+
result = join44(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
|
|
95984
96610
|
}
|
|
95985
96611
|
if (stmt.superClass) {
|
|
95986
|
-
fragment =
|
|
95987
|
-
result =
|
|
96612
|
+
fragment = join44("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
|
|
96613
|
+
result = join44(result, fragment);
|
|
95988
96614
|
}
|
|
95989
96615
|
result.push(space);
|
|
95990
96616
|
result.push(this.generateStatement(stmt.body, S_TFFT));
|
|
@@ -95997,9 +96623,9 @@ var require_escodegen = __commonJS({
|
|
|
95997
96623
|
return escapeDirective(stmt.directive) + this.semicolon(flags);
|
|
95998
96624
|
},
|
|
95999
96625
|
DoWhileStatement: function(stmt, flags) {
|
|
96000
|
-
var result =
|
|
96626
|
+
var result = join44("do", this.maybeBlock(stmt.body, S_TFFF));
|
|
96001
96627
|
result = this.maybeBlockSuffix(stmt.body, result);
|
|
96002
|
-
return
|
|
96628
|
+
return join44(result, [
|
|
96003
96629
|
"while" + space + "(",
|
|
96004
96630
|
this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
|
|
96005
96631
|
")" + this.semicolon(flags)
|
|
@@ -96035,11 +96661,11 @@ var require_escodegen = __commonJS({
|
|
|
96035
96661
|
ExportDefaultDeclaration: function(stmt, flags) {
|
|
96036
96662
|
var result = ["export"], bodyFlags;
|
|
96037
96663
|
bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
|
|
96038
|
-
result =
|
|
96664
|
+
result = join44(result, "default");
|
|
96039
96665
|
if (isStatement(stmt.declaration)) {
|
|
96040
|
-
result =
|
|
96666
|
+
result = join44(result, this.generateStatement(stmt.declaration, bodyFlags));
|
|
96041
96667
|
} else {
|
|
96042
|
-
result =
|
|
96668
|
+
result = join44(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
|
|
96043
96669
|
}
|
|
96044
96670
|
return result;
|
|
96045
96671
|
},
|
|
@@ -96047,15 +96673,15 @@ var require_escodegen = __commonJS({
|
|
|
96047
96673
|
var result = ["export"], bodyFlags, that = this;
|
|
96048
96674
|
bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
|
|
96049
96675
|
if (stmt.declaration) {
|
|
96050
|
-
return
|
|
96676
|
+
return join44(result, this.generateStatement(stmt.declaration, bodyFlags));
|
|
96051
96677
|
}
|
|
96052
96678
|
if (stmt.specifiers) {
|
|
96053
96679
|
if (stmt.specifiers.length === 0) {
|
|
96054
|
-
result =
|
|
96680
|
+
result = join44(result, "{" + space + "}");
|
|
96055
96681
|
} else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
|
|
96056
|
-
result =
|
|
96682
|
+
result = join44(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
|
|
96057
96683
|
} else {
|
|
96058
|
-
result =
|
|
96684
|
+
result = join44(result, "{");
|
|
96059
96685
|
withIndent(function(indent2) {
|
|
96060
96686
|
var i2, iz;
|
|
96061
96687
|
result.push(newline);
|
|
@@ -96073,7 +96699,7 @@ var require_escodegen = __commonJS({
|
|
|
96073
96699
|
result.push(base + "}");
|
|
96074
96700
|
}
|
|
96075
96701
|
if (stmt.source) {
|
|
96076
|
-
result =
|
|
96702
|
+
result = join44(result, [
|
|
96077
96703
|
"from" + space,
|
|
96078
96704
|
// ModuleSpecifier
|
|
96079
96705
|
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
|
|
@@ -96161,7 +96787,7 @@ var require_escodegen = __commonJS({
|
|
|
96161
96787
|
];
|
|
96162
96788
|
cursor = 0;
|
|
96163
96789
|
if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
|
|
96164
|
-
result =
|
|
96790
|
+
result = join44(result, [
|
|
96165
96791
|
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
|
|
96166
96792
|
]);
|
|
96167
96793
|
++cursor;
|
|
@@ -96171,7 +96797,7 @@ var require_escodegen = __commonJS({
|
|
|
96171
96797
|
result.push(",");
|
|
96172
96798
|
}
|
|
96173
96799
|
if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
|
|
96174
|
-
result =
|
|
96800
|
+
result = join44(result, [
|
|
96175
96801
|
space,
|
|
96176
96802
|
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
|
|
96177
96803
|
]);
|
|
@@ -96200,7 +96826,7 @@ var require_escodegen = __commonJS({
|
|
|
96200
96826
|
}
|
|
96201
96827
|
}
|
|
96202
96828
|
}
|
|
96203
|
-
result =
|
|
96829
|
+
result = join44(result, [
|
|
96204
96830
|
"from" + space,
|
|
96205
96831
|
// ModuleSpecifier
|
|
96206
96832
|
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
|
|
@@ -96254,7 +96880,7 @@ var require_escodegen = __commonJS({
|
|
|
96254
96880
|
return result;
|
|
96255
96881
|
},
|
|
96256
96882
|
ThrowStatement: function(stmt, flags) {
|
|
96257
|
-
return [
|
|
96883
|
+
return [join44(
|
|
96258
96884
|
"throw",
|
|
96259
96885
|
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
|
|
96260
96886
|
), this.semicolon(flags)];
|
|
@@ -96265,7 +96891,7 @@ var require_escodegen = __commonJS({
|
|
|
96265
96891
|
result = this.maybeBlockSuffix(stmt.block, result);
|
|
96266
96892
|
if (stmt.handlers) {
|
|
96267
96893
|
for (i2 = 0, iz = stmt.handlers.length; i2 < iz; ++i2) {
|
|
96268
|
-
result =
|
|
96894
|
+
result = join44(result, this.generateStatement(stmt.handlers[i2], S_TFFF));
|
|
96269
96895
|
if (stmt.finalizer || i2 + 1 !== iz) {
|
|
96270
96896
|
result = this.maybeBlockSuffix(stmt.handlers[i2].body, result);
|
|
96271
96897
|
}
|
|
@@ -96273,7 +96899,7 @@ var require_escodegen = __commonJS({
|
|
|
96273
96899
|
} else {
|
|
96274
96900
|
guardedHandlers = stmt.guardedHandlers || [];
|
|
96275
96901
|
for (i2 = 0, iz = guardedHandlers.length; i2 < iz; ++i2) {
|
|
96276
|
-
result =
|
|
96902
|
+
result = join44(result, this.generateStatement(guardedHandlers[i2], S_TFFF));
|
|
96277
96903
|
if (stmt.finalizer || i2 + 1 !== iz) {
|
|
96278
96904
|
result = this.maybeBlockSuffix(guardedHandlers[i2].body, result);
|
|
96279
96905
|
}
|
|
@@ -96281,13 +96907,13 @@ var require_escodegen = __commonJS({
|
|
|
96281
96907
|
if (stmt.handler) {
|
|
96282
96908
|
if (Array.isArray(stmt.handler)) {
|
|
96283
96909
|
for (i2 = 0, iz = stmt.handler.length; i2 < iz; ++i2) {
|
|
96284
|
-
result =
|
|
96910
|
+
result = join44(result, this.generateStatement(stmt.handler[i2], S_TFFF));
|
|
96285
96911
|
if (stmt.finalizer || i2 + 1 !== iz) {
|
|
96286
96912
|
result = this.maybeBlockSuffix(stmt.handler[i2].body, result);
|
|
96287
96913
|
}
|
|
96288
96914
|
}
|
|
96289
96915
|
} else {
|
|
96290
|
-
result =
|
|
96916
|
+
result = join44(result, this.generateStatement(stmt.handler, S_TFFF));
|
|
96291
96917
|
if (stmt.finalizer) {
|
|
96292
96918
|
result = this.maybeBlockSuffix(stmt.handler.body, result);
|
|
96293
96919
|
}
|
|
@@ -96295,7 +96921,7 @@ var require_escodegen = __commonJS({
|
|
|
96295
96921
|
}
|
|
96296
96922
|
}
|
|
96297
96923
|
if (stmt.finalizer) {
|
|
96298
|
-
result =
|
|
96924
|
+
result = join44(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
|
|
96299
96925
|
}
|
|
96300
96926
|
return result;
|
|
96301
96927
|
},
|
|
@@ -96329,7 +96955,7 @@ var require_escodegen = __commonJS({
|
|
|
96329
96955
|
withIndent(function() {
|
|
96330
96956
|
if (stmt.test) {
|
|
96331
96957
|
result = [
|
|
96332
|
-
|
|
96958
|
+
join44("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
|
|
96333
96959
|
":"
|
|
96334
96960
|
];
|
|
96335
96961
|
} else {
|
|
@@ -96377,9 +97003,9 @@ var require_escodegen = __commonJS({
|
|
|
96377
97003
|
result.push(this.maybeBlock(stmt.consequent, S_TFFF));
|
|
96378
97004
|
result = this.maybeBlockSuffix(stmt.consequent, result);
|
|
96379
97005
|
if (stmt.alternate.type === Syntax.IfStatement) {
|
|
96380
|
-
result =
|
|
97006
|
+
result = join44(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
|
|
96381
97007
|
} else {
|
|
96382
|
-
result =
|
|
97008
|
+
result = join44(result, join44("else", this.maybeBlock(stmt.alternate, bodyFlags)));
|
|
96383
97009
|
}
|
|
96384
97010
|
} else {
|
|
96385
97011
|
result.push(this.maybeBlock(stmt.consequent, bodyFlags));
|
|
@@ -96480,7 +97106,7 @@ var require_escodegen = __commonJS({
|
|
|
96480
97106
|
},
|
|
96481
97107
|
ReturnStatement: function(stmt, flags) {
|
|
96482
97108
|
if (stmt.argument) {
|
|
96483
|
-
return [
|
|
97109
|
+
return [join44(
|
|
96484
97110
|
"return",
|
|
96485
97111
|
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
|
|
96486
97112
|
), this.semicolon(flags)];
|
|
@@ -96569,14 +97195,14 @@ var require_escodegen = __commonJS({
|
|
|
96569
97195
|
if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
|
|
96570
97196
|
result = [fragment, noEmptySpace(), expr.operator];
|
|
96571
97197
|
} else {
|
|
96572
|
-
result =
|
|
97198
|
+
result = join44(fragment, expr.operator);
|
|
96573
97199
|
}
|
|
96574
97200
|
fragment = this.generateExpression(expr.right, rightPrecedence, flags);
|
|
96575
97201
|
if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
|
|
96576
97202
|
result.push(noEmptySpace());
|
|
96577
97203
|
result.push(fragment);
|
|
96578
97204
|
} else {
|
|
96579
|
-
result =
|
|
97205
|
+
result = join44(result, fragment);
|
|
96580
97206
|
}
|
|
96581
97207
|
if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
|
|
96582
97208
|
return ["(", result, ")"];
|
|
@@ -96616,7 +97242,7 @@ var require_escodegen = __commonJS({
|
|
|
96616
97242
|
var result, length, i2, iz, itemFlags;
|
|
96617
97243
|
length = expr["arguments"].length;
|
|
96618
97244
|
itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
|
|
96619
|
-
result =
|
|
97245
|
+
result = join44(
|
|
96620
97246
|
"new",
|
|
96621
97247
|
this.generateExpression(expr.callee, Precedence.New, itemFlags)
|
|
96622
97248
|
);
|
|
@@ -96666,11 +97292,11 @@ var require_escodegen = __commonJS({
|
|
|
96666
97292
|
var result, fragment, rightCharCode, leftSource, leftCharCode;
|
|
96667
97293
|
fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
|
|
96668
97294
|
if (space === "") {
|
|
96669
|
-
result =
|
|
97295
|
+
result = join44(expr.operator, fragment);
|
|
96670
97296
|
} else {
|
|
96671
97297
|
result = [expr.operator];
|
|
96672
97298
|
if (expr.operator.length > 2) {
|
|
96673
|
-
result =
|
|
97299
|
+
result = join44(result, fragment);
|
|
96674
97300
|
} else {
|
|
96675
97301
|
leftSource = toSourceNodeWhenNeeded(result).toString();
|
|
96676
97302
|
leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
|
|
@@ -96693,7 +97319,7 @@ var require_escodegen = __commonJS({
|
|
|
96693
97319
|
result = "yield";
|
|
96694
97320
|
}
|
|
96695
97321
|
if (expr.argument) {
|
|
96696
|
-
result =
|
|
97322
|
+
result = join44(
|
|
96697
97323
|
result,
|
|
96698
97324
|
this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
|
|
96699
97325
|
);
|
|
@@ -96701,7 +97327,7 @@ var require_escodegen = __commonJS({
|
|
|
96701
97327
|
return parenthesize(result, Precedence.Yield, precedence);
|
|
96702
97328
|
},
|
|
96703
97329
|
AwaitExpression: function(expr, precedence, flags) {
|
|
96704
|
-
var result =
|
|
97330
|
+
var result = join44(
|
|
96705
97331
|
expr.all ? "await*" : "await",
|
|
96706
97332
|
this.generateExpression(expr.argument, Precedence.Await, E_TTT)
|
|
96707
97333
|
);
|
|
@@ -96784,11 +97410,11 @@ var require_escodegen = __commonJS({
|
|
|
96784
97410
|
var result, fragment;
|
|
96785
97411
|
result = ["class"];
|
|
96786
97412
|
if (expr.id) {
|
|
96787
|
-
result =
|
|
97413
|
+
result = join44(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
|
|
96788
97414
|
}
|
|
96789
97415
|
if (expr.superClass) {
|
|
96790
|
-
fragment =
|
|
96791
|
-
result =
|
|
97416
|
+
fragment = join44("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
|
|
97417
|
+
result = join44(result, fragment);
|
|
96792
97418
|
}
|
|
96793
97419
|
result.push(space);
|
|
96794
97420
|
result.push(this.generateStatement(expr.body, S_TFFT));
|
|
@@ -96803,7 +97429,7 @@ var require_escodegen = __commonJS({
|
|
|
96803
97429
|
}
|
|
96804
97430
|
if (expr.kind === "get" || expr.kind === "set") {
|
|
96805
97431
|
fragment = [
|
|
96806
|
-
|
|
97432
|
+
join44(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
|
|
96807
97433
|
this.generateFunctionBody(expr.value)
|
|
96808
97434
|
];
|
|
96809
97435
|
} else {
|
|
@@ -96813,7 +97439,7 @@ var require_escodegen = __commonJS({
|
|
|
96813
97439
|
this.generateFunctionBody(expr.value)
|
|
96814
97440
|
];
|
|
96815
97441
|
}
|
|
96816
|
-
return
|
|
97442
|
+
return join44(result, fragment);
|
|
96817
97443
|
},
|
|
96818
97444
|
Property: function(expr, precedence, flags) {
|
|
96819
97445
|
if (expr.kind === "get" || expr.kind === "set") {
|
|
@@ -97008,7 +97634,7 @@ var require_escodegen = __commonJS({
|
|
|
97008
97634
|
for (i2 = 0, iz = expr.blocks.length; i2 < iz; ++i2) {
|
|
97009
97635
|
fragment = that.generateExpression(expr.blocks[i2], Precedence.Sequence, E_TTT);
|
|
97010
97636
|
if (i2 > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
|
|
97011
|
-
result =
|
|
97637
|
+
result = join44(result, fragment);
|
|
97012
97638
|
} else {
|
|
97013
97639
|
result.push(fragment);
|
|
97014
97640
|
}
|
|
@@ -97016,13 +97642,13 @@ var require_escodegen = __commonJS({
|
|
|
97016
97642
|
});
|
|
97017
97643
|
}
|
|
97018
97644
|
if (expr.filter) {
|
|
97019
|
-
result =
|
|
97645
|
+
result = join44(result, "if" + space);
|
|
97020
97646
|
fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
|
|
97021
|
-
result =
|
|
97647
|
+
result = join44(result, ["(", fragment, ")"]);
|
|
97022
97648
|
}
|
|
97023
97649
|
if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
|
|
97024
97650
|
fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
|
|
97025
|
-
result =
|
|
97651
|
+
result = join44(result, fragment);
|
|
97026
97652
|
}
|
|
97027
97653
|
result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
|
|
97028
97654
|
return result;
|
|
@@ -97038,8 +97664,8 @@ var require_escodegen = __commonJS({
|
|
|
97038
97664
|
} else {
|
|
97039
97665
|
fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
|
|
97040
97666
|
}
|
|
97041
|
-
fragment =
|
|
97042
|
-
fragment =
|
|
97667
|
+
fragment = join44(fragment, expr.of ? "of" : "in");
|
|
97668
|
+
fragment = join44(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
|
|
97043
97669
|
return ["for" + space + "(", fragment, ")"];
|
|
97044
97670
|
},
|
|
97045
97671
|
SpreadElement: function(expr, precedence, flags) {
|
|
@@ -118330,17 +118956,17 @@ var init_cliui = __esm({
|
|
|
118330
118956
|
});
|
|
118331
118957
|
|
|
118332
118958
|
// ../../node_modules/.pnpm/escalade@3.2.0/node_modules/escalade/sync/index.mjs
|
|
118333
|
-
import { dirname as dirname4, resolve as
|
|
118959
|
+
import { dirname as dirname4, resolve as resolve10 } from "path";
|
|
118334
118960
|
import { readdirSync, statSync as statSync2 } from "fs";
|
|
118335
118961
|
function sync_default(start, callback) {
|
|
118336
|
-
let dir =
|
|
118962
|
+
let dir = resolve10(".", start);
|
|
118337
118963
|
let tmp, stats = statSync2(dir);
|
|
118338
118964
|
if (!stats.isDirectory()) {
|
|
118339
118965
|
dir = dirname4(dir);
|
|
118340
118966
|
}
|
|
118341
118967
|
while (true) {
|
|
118342
118968
|
tmp = callback(dir, readdirSync(dir));
|
|
118343
|
-
if (tmp) return
|
|
118969
|
+
if (tmp) return resolve10(dir, tmp);
|
|
118344
118970
|
dir = dirname4(tmp = dir);
|
|
118345
118971
|
if (tmp === dir) break;
|
|
118346
118972
|
}
|
|
@@ -119306,7 +119932,7 @@ var init_yargs_parser = __esm({
|
|
|
119306
119932
|
|
|
119307
119933
|
// ../../node_modules/.pnpm/yargs-parser@21.1.1/node_modules/yargs-parser/build/lib/index.js
|
|
119308
119934
|
import { format } from "util";
|
|
119309
|
-
import { normalize, resolve as
|
|
119935
|
+
import { normalize, resolve as resolve11 } from "path";
|
|
119310
119936
|
import { readFileSync as readFileSync3 } from "fs";
|
|
119311
119937
|
var _a3, _b, _c, minNodeVersion, nodeVersion, env2, parser, yargsParser, lib_default;
|
|
119312
119938
|
var init_lib2 = __esm({
|
|
@@ -119329,7 +119955,7 @@ var init_lib2 = __esm({
|
|
|
119329
119955
|
},
|
|
119330
119956
|
format,
|
|
119331
119957
|
normalize,
|
|
119332
|
-
resolve:
|
|
119958
|
+
resolve: resolve11,
|
|
119333
119959
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
119334
119960
|
// we can exercise all the lines below:
|
|
119335
119961
|
require: (path14) => {
|
|
@@ -119396,19 +120022,19 @@ var init_yerror = __esm({
|
|
|
119396
120022
|
});
|
|
119397
120023
|
|
|
119398
120024
|
// ../../node_modules/.pnpm/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js
|
|
119399
|
-
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as
|
|
120025
|
+
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile9 } from "fs";
|
|
119400
120026
|
import { format as format2 } from "util";
|
|
119401
|
-
import { resolve as
|
|
120027
|
+
import { resolve as resolve12 } from "path";
|
|
119402
120028
|
var node_default;
|
|
119403
120029
|
var init_node = __esm({
|
|
119404
120030
|
"../../node_modules/.pnpm/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js"() {
|
|
119405
120031
|
node_default = {
|
|
119406
120032
|
fs: {
|
|
119407
120033
|
readFileSync: readFileSync4,
|
|
119408
|
-
writeFile:
|
|
120034
|
+
writeFile: writeFile9
|
|
119409
120035
|
},
|
|
119410
120036
|
format: format2,
|
|
119411
|
-
resolve:
|
|
120037
|
+
resolve: resolve12,
|
|
119412
120038
|
exists: (file) => {
|
|
119413
120039
|
try {
|
|
119414
120040
|
return statSync3(file).isFile();
|
|
@@ -119603,7 +120229,7 @@ import { notStrictEqual, strictEqual } from "assert";
|
|
|
119603
120229
|
import { inspect } from "util";
|
|
119604
120230
|
import { readFileSync as readFileSync5 } from "fs";
|
|
119605
120231
|
import { fileURLToPath } from "url";
|
|
119606
|
-
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";
|
|
119607
120233
|
var REQUIRE_ERROR, REQUIRE_DIRECTORY_ERROR, __dirname2, mainFilename, esm_default;
|
|
119608
120234
|
var init_esm2 = __esm({
|
|
119609
120235
|
"../../node_modules/.pnpm/yargs@17.7.2/node_modules/yargs/lib/platform-shims/esm.mjs"() {
|
|
@@ -119644,7 +120270,7 @@ var init_esm2 = __esm({
|
|
|
119644
120270
|
dirname: dirname5,
|
|
119645
120271
|
extname: extname2,
|
|
119646
120272
|
relative: relative2,
|
|
119647
|
-
resolve:
|
|
120273
|
+
resolve: resolve13
|
|
119648
120274
|
},
|
|
119649
120275
|
process: {
|
|
119650
120276
|
argv: () => process.argv,
|
|
@@ -119666,7 +120292,7 @@ var init_esm2 = __esm({
|
|
|
119666
120292
|
return [...str2].length;
|
|
119667
120293
|
},
|
|
119668
120294
|
y18n: y18n_default({
|
|
119669
|
-
directory:
|
|
120295
|
+
directory: resolve13(__dirname2, "../../../locales"),
|
|
119670
120296
|
updateFiles: false
|
|
119671
120297
|
})
|
|
119672
120298
|
};
|
|
@@ -123441,9 +124067,9 @@ async function getConnectionTransport(options) {
|
|
|
123441
124067
|
throw new Error("Could not detect required browser platform");
|
|
123442
124068
|
}
|
|
123443
124069
|
const { convertPuppeteerChannelToBrowsersChannel: convertPuppeteerChannelToBrowsersChannel3 } = await Promise.resolve().then(() => (init_LaunchOptions(), LaunchOptions_exports));
|
|
123444
|
-
const { join:
|
|
124070
|
+
const { join: join44 } = await import("node:path");
|
|
123445
124071
|
const userDataDir = resolveDefaultUserDataDir4(Browser5.CHROME, platform, convertPuppeteerChannelToBrowsersChannel3(options.channel));
|
|
123446
|
-
const portPath =
|
|
124072
|
+
const portPath = join44(userDataDir, "DevToolsActivePort");
|
|
123447
124073
|
try {
|
|
123448
124074
|
const fileContent = await environment.value.fs.promises.readFile(portPath, "ascii");
|
|
123449
124075
|
const [rawPort, rawPath] = fileContent.split("\n").map((line) => {
|
|
@@ -123766,7 +124392,7 @@ var init_PipeTransport = __esm({
|
|
|
123766
124392
|
// ../../node_modules/.pnpm/puppeteer-core@24.41.0/node_modules/puppeteer-core/lib/esm/puppeteer/node/BrowserLauncher.js
|
|
123767
124393
|
import { existsSync as existsSync5 } from "node:fs";
|
|
123768
124394
|
import { tmpdir } from "node:os";
|
|
123769
|
-
import { join as
|
|
124395
|
+
import { join as join5 } from "node:path";
|
|
123770
124396
|
var BrowserLauncher;
|
|
123771
124397
|
var init_BrowserLauncher = __esm({
|
|
123772
124398
|
"../../node_modules/.pnpm/puppeteer-core@24.41.0/node_modules/puppeteer-core/lib/esm/puppeteer/node/BrowserLauncher.js"() {
|
|
@@ -123886,7 +124512,7 @@ var init_BrowserLauncher = __esm({
|
|
|
123886
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
|
|
123887
124513
|
// handover. See
|
|
123888
124514
|
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/process_singleton_win.cc;l=46;drc=fc7952f0422b5073515a205a04ec9c3a1ae81658
|
|
123889
|
-
process.platform === "win32" && existsSync5(
|
|
124515
|
+
process.platform === "win32" && existsSync5(join5(launchArgs.userDataDir, "lockfile"))) {
|
|
123890
124516
|
throw new Error(`The browser is already running for ${launchArgs.userDataDir}. Use a different \`userDataDir\` or stop the running browser first.`);
|
|
123891
124517
|
}
|
|
123892
124518
|
if (logs.includes("Missing X server") && options.headless === false) {
|
|
@@ -124017,7 +124643,7 @@ var init_BrowserLauncher = __esm({
|
|
|
124017
124643
|
* @internal
|
|
124018
124644
|
*/
|
|
124019
124645
|
getProfilePath() {
|
|
124020
|
-
return
|
|
124646
|
+
return join5(this.puppeteer.configuration.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
|
|
124021
124647
|
}
|
|
124022
124648
|
/**
|
|
124023
124649
|
* @internal
|
|
@@ -292672,7 +293298,7 @@ ${newComment.split("\n").map((c2) => ` * ${c2}`).join("\n")}
|
|
|
292672
293298
|
}
|
|
292673
293299
|
}
|
|
292674
293300
|
return result;
|
|
292675
|
-
function
|
|
293301
|
+
function escapeRegExp5(str2) {
|
|
292676
293302
|
return str2.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
|
|
292677
293303
|
}
|
|
292678
293304
|
function getTodoCommentsRegExp() {
|
|
@@ -292680,7 +293306,7 @@ ${newComment.split("\n").map((c2) => ` * ${c2}`).join("\n")}
|
|
|
292680
293306
|
const multiLineCommentStart = /(?:\/\*+\s*)/.source;
|
|
292681
293307
|
const anyNumberOfSpacesAndAsterisksAtStartOfLine = /(?:^(?:\s|\*)*)/.source;
|
|
292682
293308
|
const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")";
|
|
292683
|
-
const literals = "(?:" + map3(descriptors, (d2) => "(" +
|
|
293309
|
+
const literals = "(?:" + map3(descriptors, (d2) => "(" + escapeRegExp5(d2.text) + ")").join("|") + ")";
|
|
292684
293310
|
const endOfLineOrEndOfComment = /(?:$|\*\/)/.source;
|
|
292685
293311
|
const messageRemainder = /(?:.*?)/.source;
|
|
292686
293312
|
const messagePortion = "(" + literals + messageRemainder + ")";
|
|
@@ -340513,7 +341139,7 @@ var require_dist15 = __commonJS({
|
|
|
340513
341139
|
|
|
340514
341140
|
// ../../node_modules/.pnpm/puppeteer@24.41.0_typescript@5.9.3/node_modules/puppeteer/lib/esm/puppeteer/getConfiguration.js
|
|
340515
341141
|
import { homedir as homedir3 } from "node:os";
|
|
340516
|
-
import { join as
|
|
341142
|
+
import { join as join6 } from "node:path";
|
|
340517
341143
|
function getBooleanEnvVar(name) {
|
|
340518
341144
|
const env4 = process.env[name];
|
|
340519
341145
|
if (env4 === void 0) {
|
|
@@ -340593,7 +341219,7 @@ var init_getConfiguration = __esm({
|
|
|
340593
341219
|
configuration2.firefox = getBrowserSetting("firefox", configuration2, {
|
|
340594
341220
|
skipDownload: true
|
|
340595
341221
|
});
|
|
340596
|
-
configuration2.cacheDirectory = process.env["PUPPETEER_CACHE_DIR"] ?? configuration2.cacheDirectory ??
|
|
341222
|
+
configuration2.cacheDirectory = process.env["PUPPETEER_CACHE_DIR"] ?? configuration2.cacheDirectory ?? join6(homedir3(), ".cache", "puppeteer");
|
|
340597
341223
|
configuration2.temporaryDirectory = process.env["PUPPETEER_TMP_DIR"] ?? configuration2.temporaryDirectory;
|
|
340598
341224
|
configuration2.experiments ??= {};
|
|
340599
341225
|
return configuration2;
|
|
@@ -340921,7 +341547,7 @@ import { readdirSync as readdirSync2, statSync as statSync4 } from "fs";
|
|
|
340921
341547
|
import { format as format3 } from "util";
|
|
340922
341548
|
import { normalize as normalize2, resolve as resolve32 } from "path";
|
|
340923
341549
|
import { readFileSync as readFileSync22 } from "fs";
|
|
340924
|
-
import { readFileSync as readFileSync32, statSync as statSync22, writeFile as
|
|
341550
|
+
import { readFileSync as readFileSync32, statSync as statSync22, writeFile as writeFile10 } from "fs";
|
|
340925
341551
|
import { format as format22 } from "util";
|
|
340926
341552
|
import { resolve as resolve42 } from "path";
|
|
340927
341553
|
import { notStrictEqual as notStrictEqual2, strictEqual as strictEqual2 } from "assert";
|
|
@@ -340979,7 +341605,7 @@ import { join as join8 } from "path";
|
|
|
340979
341605
|
import { spawn as spawn7 } from "child_process";
|
|
340980
341606
|
import { createWriteStream as createWriteStream22, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
340981
341607
|
import { createHash as createHash3 } from "crypto";
|
|
340982
|
-
import { join as
|
|
341608
|
+
import { join as join72, extname as extname22 } from "path";
|
|
340983
341609
|
import { Readable } from "stream";
|
|
340984
341610
|
import { finished } from "stream/promises";
|
|
340985
341611
|
import { promises as fs72 } from "fs";
|
|
@@ -351067,7 +351693,7 @@ async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
|
351067
351693
|
mkdirSync4(destDir, { recursive: true });
|
|
351068
351694
|
}
|
|
351069
351695
|
const filename = getFilenameFromUrl(url);
|
|
351070
|
-
const localPath =
|
|
351696
|
+
const localPath = join72(destDir, filename);
|
|
351071
351697
|
if (existsSync7(localPath)) {
|
|
351072
351698
|
downloadPathCache.set(url, localPath);
|
|
351073
351699
|
return localPath;
|
|
@@ -399082,14 +399708,14 @@ ${sourceUrlComment}
|
|
|
399082
399708
|
return value;
|
|
399083
399709
|
};
|
|
399084
399710
|
var createToken = (name, value, isGlobal) => {
|
|
399085
|
-
const
|
|
399711
|
+
const safe2 = makeSafeRegex(value);
|
|
399086
399712
|
const index = R2++;
|
|
399087
399713
|
debug62(name, index, value);
|
|
399088
399714
|
t2[name] = index;
|
|
399089
399715
|
src[index] = value;
|
|
399090
|
-
safeSrc[index] =
|
|
399716
|
+
safeSrc[index] = safe2;
|
|
399091
399717
|
re2[index] = new RegExp(value, isGlobal ? "g" : void 0);
|
|
399092
|
-
safeRe[index] = new RegExp(
|
|
399718
|
+
safeRe[index] = new RegExp(safe2, isGlobal ? "g" : void 0);
|
|
399093
399719
|
};
|
|
399094
399720
|
createToken("NUMERICIDENTIFIER", "0|[1-9]\\d*");
|
|
399095
399721
|
createToken("NUMERICIDENTIFIERLOOSE", "\\d+");
|
|
@@ -433316,7 +433942,7 @@ If you think this is a bug, please report it on the Puppeteer issue tracker.`;
|
|
|
433316
433942
|
node_default2 = {
|
|
433317
433943
|
fs: {
|
|
433318
433944
|
readFileSync: readFileSync32,
|
|
433319
|
-
writeFile:
|
|
433945
|
+
writeFile: writeFile10
|
|
433320
433946
|
},
|
|
433321
433947
|
format: format22,
|
|
433322
433948
|
resolve: resolve42,
|
|
@@ -450239,14 +450865,14 @@ ${right22.raw}`)
|
|
|
450239
450865
|
});
|
|
450240
450866
|
|
|
450241
450867
|
// ../cli/src/commands/_shared/scene-lint.ts
|
|
450242
|
-
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";
|
|
450243
450869
|
import { existsSync as existsSync18 } from "node:fs";
|
|
450244
|
-
import { resolve as
|
|
450870
|
+
import { resolve as resolve15, relative as relative4, join as join18 } from "node:path";
|
|
450245
450871
|
async function discoverSceneFiles(opts) {
|
|
450246
|
-
const projectDir =
|
|
450247
|
-
const rootAbs =
|
|
450872
|
+
const projectDir = resolve15(opts.projectDir);
|
|
450873
|
+
const rootAbs = resolve15(projectDir, opts.rootRel ?? "index.html");
|
|
450248
450874
|
const root2 = existsSync18(rootAbs) ? rootAbs : null;
|
|
450249
|
-
const compsDir =
|
|
450875
|
+
const compsDir = resolve15(projectDir, "compositions");
|
|
450250
450876
|
const subs = [];
|
|
450251
450877
|
if (existsSync18(compsDir)) {
|
|
450252
450878
|
await collectHtmlRecursive(compsDir, subs);
|
|
@@ -450332,7 +450958,7 @@ function addClipClassToTimedElements(html) {
|
|
|
450332
450958
|
});
|
|
450333
450959
|
}
|
|
450334
450960
|
async function runProjectLint(opts) {
|
|
450335
|
-
const projectDir =
|
|
450961
|
+
const projectDir = resolve15(opts.projectDir);
|
|
450336
450962
|
const { root: root2, subs } = await discoverSceneFiles({ projectDir, rootRel: opts.rootRel });
|
|
450337
450963
|
const files = [];
|
|
450338
450964
|
const fixed = [];
|
|
@@ -450356,7 +450982,7 @@ async function runProjectLint(opts) {
|
|
|
450356
450982
|
if (opts.fix && findings.length > 0) {
|
|
450357
450983
|
const { html: nextHtml, fixedCodes } = applyMechanicalFixes(html, findings);
|
|
450358
450984
|
if (fixedCodes.length > 0) {
|
|
450359
|
-
await
|
|
450985
|
+
await writeFile11(abs, nextHtml, "utf-8");
|
|
450360
450986
|
fixed.push({ file: rel, codes: fixedCodes });
|
|
450361
450987
|
const reLinted = runHyperframeLint({ ...prepared, html: nextHtml });
|
|
450362
450988
|
files.push({
|
|
@@ -450393,7 +451019,7 @@ async function runProjectLint(opts) {
|
|
|
450393
451019
|
};
|
|
450394
451020
|
}
|
|
450395
451021
|
async function rootExists(projectDir, rootRel = "index.html") {
|
|
450396
|
-
const abs =
|
|
451022
|
+
const abs = resolve15(projectDir, rootRel);
|
|
450397
451023
|
try {
|
|
450398
451024
|
const s2 = await stat2(abs);
|
|
450399
451025
|
return s2.isFile();
|
|
@@ -469393,12 +470019,12 @@ var init_dist3 = __esm({
|
|
|
469393
470019
|
|
|
469394
470020
|
// ../cli/src/commands/_shared/root-sync.ts
|
|
469395
470021
|
import { existsSync as existsSync23 } from "node:fs";
|
|
469396
|
-
import { readFile as readFile8, writeFile as
|
|
469397
|
-
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";
|
|
469398
470024
|
async function createRootSyncPlan(opts) {
|
|
469399
|
-
const projectDir =
|
|
470025
|
+
const projectDir = resolve17(opts.projectDir);
|
|
469400
470026
|
const rootRel = opts.rootRel ?? "index.html";
|
|
469401
|
-
const rootPath =
|
|
470027
|
+
const rootPath = resolve17(projectDir, rootRel);
|
|
469402
470028
|
if (!existsSync23(rootPath)) {
|
|
469403
470029
|
return { rootPath, rootRel, exists: false, changed: false, fixCodes: [], issues: [] };
|
|
469404
470030
|
}
|
|
@@ -469456,11 +470082,11 @@ async function createProjectRootSyncPlan(opts) {
|
|
|
469456
470082
|
}
|
|
469457
470083
|
async function syncRootComposition(opts) {
|
|
469458
470084
|
const plan = await createRootSyncPlan(opts);
|
|
469459
|
-
if (plan.nextHtml) await
|
|
470085
|
+
if (plan.nextHtml) await writeFile13(plan.rootPath, plan.nextHtml, "utf-8");
|
|
469460
470086
|
return plan;
|
|
469461
470087
|
}
|
|
469462
470088
|
async function loadProjectRootSyncBeats(projectDir) {
|
|
469463
|
-
const root2 =
|
|
470089
|
+
const root2 = resolve17(projectDir);
|
|
469464
470090
|
const storyboardPath = join23(root2, "STORYBOARD.md");
|
|
469465
470091
|
if (!existsSync23(storyboardPath)) return [];
|
|
469466
470092
|
const parsed = parseStoryboard(await readFile8(storyboardPath, "utf-8"));
|
|
@@ -469537,7 +470163,7 @@ async function resolveSyncedBeatDuration(opts) {
|
|
|
469537
470163
|
}
|
|
469538
470164
|
}
|
|
469539
470165
|
async function resolveProjectBeatDurations(projectDir) {
|
|
469540
|
-
const root2 =
|
|
470166
|
+
const root2 = resolve17(projectDir);
|
|
469541
470167
|
const beats = await loadProjectRootSyncBeats(root2);
|
|
469542
470168
|
const durations = /* @__PURE__ */ new Map();
|
|
469543
470169
|
for (const beat of beats) {
|
|
@@ -469786,8 +470412,8 @@ __export(compose_scenes_skills_exports, {
|
|
|
469786
470412
|
});
|
|
469787
470413
|
import { createHash as createHash5 } from "node:crypto";
|
|
469788
470414
|
import { existsSync as existsSync24, mkdirSync as mkdirSync12 } from "node:fs";
|
|
469789
|
-
import { mkdir as mkdir9, readFile as readFile9, writeFile as
|
|
469790
|
-
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";
|
|
469791
470417
|
function buildSystemPrompt(ctx) {
|
|
469792
470418
|
return `You are a Hyperframes composition author. The skill content below
|
|
469793
470419
|
defines the framework rules, motion principles, and quality standards.
|
|
@@ -469880,7 +470506,15 @@ ${finalDurationBullet}
|
|
|
469880
470506
|
itself. For multi-phase beats, drive phase changes with GSAP \`autoAlpha\`
|
|
469881
470507
|
inside full-window clips: animate phase A out (\`autoAlpha: 0\`), then
|
|
469882
470508
|
phase B in, on the same timeline.
|
|
469883
|
-
- 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
|
|
469884
470518
|
full-frame visual backdrop. The exact path string is
|
|
469885
470519
|
\`assets/backdrop-${ctx.beat.id}.png\`; do NOT prefix it with \`../\` or \`./\`
|
|
469886
470520
|
because fragments are mounted from the project root.
|
|
@@ -470047,7 +470681,7 @@ async function composeBeatHtml(ctx, overrides) {
|
|
|
470047
470681
|
const html = extractHtml(result.text);
|
|
470048
470682
|
try {
|
|
470049
470683
|
mkdirSync12(cacheDir, { recursive: true });
|
|
470050
|
-
await
|
|
470684
|
+
await writeFile14(cachePath, html, "utf-8");
|
|
470051
470685
|
} catch {
|
|
470052
470686
|
}
|
|
470053
470687
|
const costUsd = result.inputTokens / 1e6 * settings.costPerMTokIn + result.outputTokens / 1e6 * settings.costPerMTokOut;
|
|
@@ -470146,9 +470780,9 @@ async function resolveComposerConfigAware(explicit, cwd) {
|
|
|
470146
470780
|
return resolveComposer();
|
|
470147
470781
|
}
|
|
470148
470782
|
async function executeComposeScenesWithSkills(params, outputDir, overrides) {
|
|
470149
|
-
const projectRoot = params.project ?
|
|
470150
|
-
const designPath =
|
|
470151
|
-
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");
|
|
470152
470786
|
if (!existsSync24(designPath)) {
|
|
470153
470787
|
return { success: false, error: `DESIGN.md not found at ${designPath}` };
|
|
470154
470788
|
}
|
|
@@ -470206,7 +470840,7 @@ async function executeComposeScenesWithSkills(params, outputDir, overrides) {
|
|
|
470206
470840
|
);
|
|
470207
470841
|
const compositionPath = join24(compositionsDir, `scene-${beat.id}.html`);
|
|
470208
470842
|
await mkdir9(dirname13(compositionPath), { recursive: true });
|
|
470209
|
-
await
|
|
470843
|
+
await writeFile14(compositionPath, result.html, "utf-8");
|
|
470210
470844
|
if (result.cached) {
|
|
470211
470845
|
onProgress({
|
|
470212
470846
|
type: "beat-cached",
|
|
@@ -470409,9 +471043,9 @@ var init_compose_scenes_skills = __esm({
|
|
|
470409
471043
|
// ../cli/src/commands/_shared/compose-prompts.ts
|
|
470410
471044
|
import { existsSync as existsSync25 } from "node:fs";
|
|
470411
471045
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
470412
|
-
import { join as join25, relative as relative6, resolve as
|
|
471046
|
+
import { join as join25, relative as relative6, resolve as resolve19 } from "node:path";
|
|
470413
471047
|
async function getComposePrompts(opts) {
|
|
470414
|
-
const projectDir =
|
|
471048
|
+
const projectDir = resolve19(opts.projectDir);
|
|
470415
471049
|
const designPath = join25(projectDir, "DESIGN.md");
|
|
470416
471050
|
const storyboardPath = join25(projectDir, "STORYBOARD.md");
|
|
470417
471051
|
const skillPath = join25(projectDir, "SKILL.md");
|
|
@@ -470538,7 +471172,7 @@ var init_compose_prompts = __esm({
|
|
|
470538
471172
|
// ../cli/src/commands/_shared/sub-comp-duration-sync.ts
|
|
470539
471173
|
import { existsSync as existsSync27 } from "node:fs";
|
|
470540
471174
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
470541
|
-
import { join as join27, resolve as
|
|
471175
|
+
import { join as join27, resolve as resolve21 } from "node:path";
|
|
470542
471176
|
function syncSubCompositionDurationHtml(html, beatId, newDurationSec, fileRel) {
|
|
470543
471177
|
const compositionId = `scene-${beatId}`;
|
|
470544
471178
|
const file = fileRel ?? `compositions/${compositionId}.html`;
|
|
@@ -470626,7 +471260,7 @@ function rewriteTimelineConst(html, oldDurationSec, newDurationSec) {
|
|
|
470626
471260
|
return { html, rewritten: false, needsManualFix };
|
|
470627
471261
|
}
|
|
470628
471262
|
async function createSubCompDurationSyncPlans(opts) {
|
|
470629
|
-
const projectDir =
|
|
471263
|
+
const projectDir = resolve21(opts.projectDir);
|
|
470630
471264
|
const results = [];
|
|
470631
471265
|
for (const beat of opts.beats) {
|
|
470632
471266
|
const fileRel = `compositions/scene-${beat.id}.html`;
|
|
@@ -470661,88 +471295,6 @@ var init_sub_comp_duration_sync = __esm({
|
|
|
470661
471295
|
}
|
|
470662
471296
|
});
|
|
470663
471297
|
|
|
470664
|
-
// ../cli/src/commands/_shared/review-report.ts
|
|
470665
|
-
import { writeFile as writeFile15 } from "node:fs/promises";
|
|
470666
|
-
import { join as join28, resolve as resolve21 } from "node:path";
|
|
470667
|
-
function statusFromIssues(issues) {
|
|
470668
|
-
if (issues.some((issue) => issue.severity === "error")) return "fail";
|
|
470669
|
-
if (issues.some((issue) => issue.severity === "warning")) return "warn";
|
|
470670
|
-
return "pass";
|
|
470671
|
-
}
|
|
470672
|
-
function scoreIssues(issues) {
|
|
470673
|
-
let score = 100;
|
|
470674
|
-
for (const issue of issues) {
|
|
470675
|
-
if (issue.severity === "error") score -= 25;
|
|
470676
|
-
else if (issue.severity === "warning") score -= 8;
|
|
470677
|
-
else score -= 2;
|
|
470678
|
-
}
|
|
470679
|
-
return Math.max(0, Math.min(100, score));
|
|
470680
|
-
}
|
|
470681
|
-
function uniqueRetryWith(items) {
|
|
470682
|
-
return [
|
|
470683
|
-
...new Set(items.filter((item) => typeof item === "string" && item.length > 0))
|
|
470684
|
-
];
|
|
470685
|
-
}
|
|
470686
|
-
function fixOwnerForIssue(issue) {
|
|
470687
|
-
if (issue.fixOwner) return issue.fixOwner;
|
|
470688
|
-
if (issue.code.startsWith("AI_REVIEW_")) return "host-agent";
|
|
470689
|
-
if (issue.code.startsWith("STORYBOARD_")) return "host-agent";
|
|
470690
|
-
if (issue.code === "PROJECT_NOT_FOUND" || issue.code === "MISSING_STORYBOARD" || issue.code === "BEAT_NOT_FOUND" || issue.code === "MISSING_DESIGN") {
|
|
470691
|
-
return "host-agent";
|
|
470692
|
-
}
|
|
470693
|
-
return "vibe";
|
|
470694
|
-
}
|
|
470695
|
-
function normalizeReviewIssues(issues, fallbackOwner) {
|
|
470696
|
-
return issues.map((issue) => ({
|
|
470697
|
-
...issue,
|
|
470698
|
-
fixOwner: issue.fixOwner ?? fallbackOwner ?? fixOwnerForIssue(issue)
|
|
470699
|
-
}));
|
|
470700
|
-
}
|
|
470701
|
-
function summarizeReviewIssues(issues) {
|
|
470702
|
-
const normalized = normalizeReviewIssues(issues);
|
|
470703
|
-
return {
|
|
470704
|
-
issueCount: normalized.length,
|
|
470705
|
-
errorCount: normalized.filter((issue) => issue.severity === "error").length,
|
|
470706
|
-
warningCount: normalized.filter((issue) => issue.severity === "warning").length,
|
|
470707
|
-
infoCount: normalized.filter((issue) => issue.severity === "info").length,
|
|
470708
|
-
fixOwners: {
|
|
470709
|
-
vibe: normalized.filter((issue) => issue.fixOwner === "vibe").length,
|
|
470710
|
-
hostAgent: normalized.filter((issue) => issue.fixOwner === "host-agent").length
|
|
470711
|
-
}
|
|
470712
|
-
};
|
|
470713
|
-
}
|
|
470714
|
-
function buildReviewReport(opts) {
|
|
470715
|
-
const issues = normalizeReviewIssues(opts.issues);
|
|
470716
|
-
return stripUndefined2({
|
|
470717
|
-
schemaVersion: "1",
|
|
470718
|
-
kind: "review",
|
|
470719
|
-
project: resolve21(opts.project),
|
|
470720
|
-
mode: opts.mode,
|
|
470721
|
-
beat: opts.beat,
|
|
470722
|
-
status: opts.status,
|
|
470723
|
-
score: opts.score,
|
|
470724
|
-
issues,
|
|
470725
|
-
summary: summarizeReviewIssues(issues),
|
|
470726
|
-
retryWith: uniqueRetryWith(opts.retryWith),
|
|
470727
|
-
sourceReports: opts.sourceReports ?? [],
|
|
470728
|
-
reportPath: opts.reportPath
|
|
470729
|
-
});
|
|
470730
|
-
}
|
|
470731
|
-
function defaultReviewReportPath(projectDir) {
|
|
470732
|
-
return join28(resolve21(projectDir), "review-report.json");
|
|
470733
|
-
}
|
|
470734
|
-
async function writeReviewReport(path14, report) {
|
|
470735
|
-
await writeFile15(path14, JSON.stringify(report, null, 2) + "\n", "utf-8");
|
|
470736
|
-
}
|
|
470737
|
-
function stripUndefined2(value) {
|
|
470738
|
-
return Object.fromEntries(Object.entries(value).filter(([, v2]) => v2 !== void 0));
|
|
470739
|
-
}
|
|
470740
|
-
var init_review_report = __esm({
|
|
470741
|
-
"../cli/src/commands/_shared/review-report.ts"() {
|
|
470742
|
-
"use strict";
|
|
470743
|
-
}
|
|
470744
|
-
});
|
|
470745
|
-
|
|
470746
471298
|
// ../cli/src/commands/_shared/scene-repair.ts
|
|
470747
471299
|
import { readFile as readFile13, writeFile as writeFile16 } from "node:fs/promises";
|
|
470748
471300
|
import { relative as relative7, resolve as resolve23 } from "node:path";
|
|
@@ -470869,16 +471421,308 @@ var init_scene_repair = __esm({
|
|
|
470869
471421
|
}
|
|
470870
471422
|
});
|
|
470871
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
|
+
"keyframe",
|
|
471702
|
+
"motion",
|
|
471703
|
+
"voice",
|
|
471704
|
+
"music",
|
|
471705
|
+
"asset",
|
|
471706
|
+
"characters"
|
|
471707
|
+
];
|
|
471708
|
+
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
471709
|
+
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
471710
|
+
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
471711
|
+
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "keyframe", "motion", "voice", "music", "asset"]);
|
|
471712
|
+
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
471713
|
+
}
|
|
471714
|
+
});
|
|
471715
|
+
|
|
470872
471716
|
// ../cli/src/pipeline/renderers/chrome.ts
|
|
470873
471717
|
import { existsSync as existsSync29 } from "node:fs";
|
|
470874
471718
|
import { homedir as homedir7 } from "node:os";
|
|
470875
|
-
import { join as
|
|
471719
|
+
import { join as join28 } from "node:path";
|
|
470876
471720
|
function findChrome() {
|
|
470877
471721
|
const candidates = [
|
|
470878
471722
|
process.env.HYPERFRAMES_CHROME_PATH,
|
|
470879
471723
|
process.env.CHROME_PATH,
|
|
470880
471724
|
// puppeteer auto-downloaded headless shell
|
|
470881
|
-
|
|
471725
|
+
join28(
|
|
470882
471726
|
homedir7(),
|
|
470883
471727
|
".cache",
|
|
470884
471728
|
"puppeteer",
|
|
@@ -471171,7 +472015,7 @@ __export(scene_render_exports, {
|
|
|
471171
472015
|
import { execFile as execFile2 } from "node:child_process";
|
|
471172
472016
|
import { existsSync as existsSync30 } from "node:fs";
|
|
471173
472017
|
import { mkdir as mkdir12, readFile as readFile16, stat as stat3, writeFile as writeFile18 } from "node:fs/promises";
|
|
471174
|
-
import { resolve as resolve27, relative as relative9, dirname as dirname16, basename as basename7, join as
|
|
472018
|
+
import { resolve as resolve27, relative as relative9, dirname as dirname16, basename as basename7, join as join29, isAbsolute as isAbsolute3 } from "node:path";
|
|
471175
472019
|
import { promisify as promisify2 } from "node:util";
|
|
471176
472020
|
function qualityToCrf(quality = "standard") {
|
|
471177
472021
|
return quality === "draft" ? 28 : quality === "high" ? 18 : 23;
|
|
@@ -471259,7 +472103,7 @@ async function executeSceneRender(opts = {}) {
|
|
|
471259
472103
|
}
|
|
471260
472104
|
let autoSyncApplied = false;
|
|
471261
472105
|
let autoSyncWarning;
|
|
471262
|
-
if (!opts.beatId && existsSync30(
|
|
472106
|
+
if (!opts.beatId && existsSync30(join29(projectDir, "STORYBOARD.md"))) {
|
|
471263
472107
|
try {
|
|
471264
472108
|
const rootPlan = await createProjectRootSyncPlan({ projectDir });
|
|
471265
472109
|
const subPlans = await createSubCompDurationSyncPlans({
|
|
@@ -471436,7 +472280,7 @@ async function safeStat(p2) {
|
|
|
471436
472280
|
}
|
|
471437
472281
|
async function prepareBeatRenderRoot(opts) {
|
|
471438
472282
|
const root2 = `.vibeframe/tmp/render-beat-${sanitizeFileSegment(opts.beatId)}.html`;
|
|
471439
|
-
const reportPath =
|
|
472283
|
+
const reportPath = join29(opts.projectDir, "build-report.json");
|
|
471440
472284
|
const retryWith = [
|
|
471441
472285
|
`vibe build ${opts.projectDir} --beat ${opts.beatId} --stage sync --json`
|
|
471442
472286
|
];
|
|
@@ -471520,8 +472364,8 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
471520
472364
|
durationSec,
|
|
471521
472365
|
narrationPath
|
|
471522
472366
|
});
|
|
471523
|
-
await mkdir12(dirname16(
|
|
471524
|
-
await writeFile18(
|
|
472367
|
+
await mkdir12(dirname16(join29(opts.projectDir, root2)), { recursive: true });
|
|
472368
|
+
await writeFile18(join29(opts.projectDir, root2), html, "utf-8");
|
|
471525
472369
|
return {
|
|
471526
472370
|
success: true,
|
|
471527
472371
|
root: root2,
|
|
@@ -471585,7 +472429,7 @@ function reportedBeatAssetPaths(beat) {
|
|
|
471585
472429
|
]);
|
|
471586
472430
|
}
|
|
471587
472431
|
async function writeRenderReport(projectDir, result) {
|
|
471588
|
-
const reportPath =
|
|
472432
|
+
const reportPath = join29(projectDir, "render-report.json");
|
|
471589
472433
|
try {
|
|
471590
472434
|
await writeFile18(
|
|
471591
472435
|
reportPath,
|
|
@@ -471782,6 +472626,8 @@ var init_build_asset_reference = __esm({
|
|
|
471782
472626
|
EXTENSIONS = {
|
|
471783
472627
|
narration: [".mp3", ".wav", ".m4a"],
|
|
471784
472628
|
backdrop: [".png", ".jpg", ".jpeg", ".webp"],
|
|
472629
|
+
character: [".png", ".jpg", ".jpeg", ".webp"],
|
|
472630
|
+
keyframe: [".png", ".jpg", ".jpeg", ".webp"],
|
|
471785
472631
|
video: [".mp4", ".mov", ".webm"],
|
|
471786
472632
|
music: [".mp3", ".wav", ".m4a"]
|
|
471787
472633
|
};
|
|
@@ -471819,6 +472665,28 @@ function backdropCacheDescriptor(opts) {
|
|
|
471819
472665
|
ext: "png"
|
|
471820
472666
|
});
|
|
471821
472667
|
}
|
|
472668
|
+
function characterCacheDescriptor(opts) {
|
|
472669
|
+
return cacheAssetDescriptor("character", {
|
|
472670
|
+
name: opts.name,
|
|
472671
|
+
cue: opts.cue,
|
|
472672
|
+
provider: opts.provider,
|
|
472673
|
+
quality: opts.quality,
|
|
472674
|
+
size: opts.size,
|
|
472675
|
+
ext: "png"
|
|
472676
|
+
});
|
|
472677
|
+
}
|
|
472678
|
+
function keyframeCacheDescriptor(opts) {
|
|
472679
|
+
return cacheAssetDescriptor("keyframe", {
|
|
472680
|
+
beatId: opts.beatId,
|
|
472681
|
+
cue: opts.cue,
|
|
472682
|
+
provider: opts.provider,
|
|
472683
|
+
quality: opts.quality,
|
|
472684
|
+
size: opts.size,
|
|
472685
|
+
ratio: opts.ratio,
|
|
472686
|
+
characters: opts.characters && opts.characters.length > 0 ? opts.characters : void 0,
|
|
472687
|
+
ext: "png"
|
|
472688
|
+
});
|
|
472689
|
+
}
|
|
471822
472690
|
function imageRatioForSize(size) {
|
|
471823
472691
|
switch (size) {
|
|
471824
472692
|
case "1024x1024":
|
|
@@ -471838,6 +472706,10 @@ function videoCacheDescriptor(opts) {
|
|
|
471838
472706
|
provider: opts.provider,
|
|
471839
472707
|
duration: normalizeVideoDuration(opts.duration),
|
|
471840
472708
|
ratio: "16:9",
|
|
472709
|
+
// Omit when empty so existing (character-less) clips keep their cache key.
|
|
472710
|
+
characters: opts.characters && opts.characters.length > 0 ? opts.characters : void 0,
|
|
472711
|
+
// Omit when absent so existing (non-keyframe) clips keep their cache key.
|
|
472712
|
+
keyframe: opts.keyframe || void 0,
|
|
471841
472713
|
ext: "mp4"
|
|
471842
472714
|
});
|
|
471843
472715
|
}
|
|
@@ -471890,212 +472762,10 @@ var init_build_backdrop_prompt = __esm({
|
|
|
471890
472762
|
}
|
|
471891
472763
|
});
|
|
471892
472764
|
|
|
471893
|
-
// ../cli/src/commands/_shared/storyboard-edit.ts
|
|
471894
|
-
function validateStoryboardMarkdown(markdown) {
|
|
471895
|
-
const parsed = parseStoryboard(markdown);
|
|
471896
|
-
const sections = splitBeatSections(markdown);
|
|
471897
|
-
const issues = [];
|
|
471898
|
-
if (parsed.beats.length === 0) {
|
|
471899
|
-
issues.push({
|
|
471900
|
-
severity: "error",
|
|
471901
|
-
code: "NO_BEATS",
|
|
471902
|
-
message: "STORYBOARD.md must contain at least one `## Beat ...` heading."
|
|
471903
|
-
});
|
|
471904
|
-
}
|
|
471905
|
-
const seen = /* @__PURE__ */ new Map();
|
|
471906
|
-
for (const beat of parsed.beats) {
|
|
471907
|
-
seen.set(beat.id, (seen.get(beat.id) ?? 0) + 1);
|
|
471908
|
-
}
|
|
471909
|
-
for (const [id, count] of seen.entries()) {
|
|
471910
|
-
if (count > 1) {
|
|
471911
|
-
issues.push({
|
|
471912
|
-
severity: "error",
|
|
471913
|
-
code: "DUPLICATE_BEAT_ID",
|
|
471914
|
-
beatId: id,
|
|
471915
|
-
message: `Beat id "${id}" appears ${count} times. Beat ids must be unique.`
|
|
471916
|
-
});
|
|
471917
|
-
}
|
|
471918
|
-
}
|
|
471919
|
-
for (const section of sections) {
|
|
471920
|
-
const cueBlock = readLeadingCueBlock(section.body);
|
|
471921
|
-
if (cueBlock?.error) {
|
|
471922
|
-
issues.push({
|
|
471923
|
-
severity: "error",
|
|
471924
|
-
code: "MALFORMED_CUE_YAML",
|
|
471925
|
-
beatId: section.id,
|
|
471926
|
-
message: `Beat "${section.id}" has malformed YAML cues: ${cueBlock.error}`
|
|
471927
|
-
});
|
|
471928
|
-
}
|
|
471929
|
-
}
|
|
471930
|
-
for (const beat of parsed.beats) {
|
|
471931
|
-
const cues = beat.cues ?? {};
|
|
471932
|
-
for (const [key2, value] of Object.entries(cues)) {
|
|
471933
|
-
if (!ALLOWED_CUE_KEYS.has(key2)) {
|
|
471934
|
-
issues.push({
|
|
471935
|
-
severity: "warning",
|
|
471936
|
-
code: "UNKNOWN_CUE",
|
|
471937
|
-
beatId: beat.id,
|
|
471938
|
-
message: `Beat "${beat.id}" uses unknown cue "${key2}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`
|
|
471939
|
-
});
|
|
471940
|
-
continue;
|
|
471941
|
-
}
|
|
471942
|
-
if (key2 === "duration") {
|
|
471943
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
471944
|
-
issues.push({
|
|
471945
|
-
severity: "error",
|
|
471946
|
-
code: "INVALID_DURATION",
|
|
471947
|
-
beatId: beat.id,
|
|
471948
|
-
message: `Beat "${beat.id}" cue "duration" must be a positive number of seconds.`
|
|
471949
|
-
});
|
|
471950
|
-
}
|
|
471951
|
-
continue;
|
|
471952
|
-
}
|
|
471953
|
-
if (STRING_CUE_KEYS.has(key2) && typeof value !== "string") {
|
|
471954
|
-
issues.push({
|
|
471955
|
-
severity: "error",
|
|
471956
|
-
code: "INVALID_CUE_VALUE",
|
|
471957
|
-
beatId: beat.id,
|
|
471958
|
-
message: `Beat "${beat.id}" cue "${key2}" must be a string.`
|
|
471959
|
-
});
|
|
471960
|
-
}
|
|
471961
|
-
}
|
|
471962
|
-
}
|
|
471963
|
-
for (const beat of parsed.beats) {
|
|
471964
|
-
if (beat.duration !== void 0 && beat.duration > MAX_RECOMMENDED_BEAT_SEC) {
|
|
471965
|
-
issues.push({
|
|
471966
|
-
severity: "warning",
|
|
471967
|
-
code: "BEAT_DURATION_TOO_LONG",
|
|
471968
|
-
beatId: beat.id,
|
|
471969
|
-
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).`
|
|
471970
|
-
});
|
|
471971
|
-
}
|
|
471972
|
-
}
|
|
471973
|
-
return {
|
|
471974
|
-
ok: !issues.some((i2) => i2.severity === "error"),
|
|
471975
|
-
beats: parsed.beats,
|
|
471976
|
-
issues
|
|
471977
|
-
};
|
|
471978
|
-
}
|
|
471979
|
-
function getStoryboardBeat(markdown, beatId) {
|
|
471980
|
-
return parseStoryboard(markdown).beats.find((beat) => beat.id === beatId) ?? null;
|
|
471981
|
-
}
|
|
471982
|
-
function setStoryboardCue(markdown, opts) {
|
|
471983
|
-
const section = findBeatSection(markdown, opts.beatId);
|
|
471984
|
-
if (!section) {
|
|
471985
|
-
throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
471986
|
-
}
|
|
471987
|
-
if (!ALLOWED_CUE_KEYS.has(opts.key)) {
|
|
471988
|
-
throw new Error(`Unsupported cue "${opts.key}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`);
|
|
471989
|
-
}
|
|
471990
|
-
const cue = readLeadingCueBlock(section.body);
|
|
471991
|
-
if (cue?.error) {
|
|
471992
|
-
throw new Error(`Cannot edit malformed YAML cues for beat "${opts.beatId}": ${cue.error}`);
|
|
471993
|
-
}
|
|
471994
|
-
const cues = cue?.value ? { ...cue.value } : {};
|
|
471995
|
-
if (opts.unset) {
|
|
471996
|
-
delete cues[opts.key];
|
|
471997
|
-
} else {
|
|
471998
|
-
cues[opts.key] = normalizeCueValue(opts.key, opts.value);
|
|
471999
|
-
}
|
|
472000
|
-
const remainingBody = cue ? section.body.slice(cue.full.length).replace(/^\s*\n/, "") : section.body.replace(/^\s*\n/, "");
|
|
472001
|
-
const cueBlock = Object.keys(cues).length > 0 ? "```yaml\n" + (0, import_yaml5.stringify)(cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
472002
|
-
const nextBody = cueBlock + remainingBody.trimStart();
|
|
472003
|
-
const nextSection = section.raw.slice(0, section.headingEnd - section.start) + "\n\n" + nextBody.trimEnd() + "\n";
|
|
472004
|
-
return markdown.slice(0, section.start) + nextSection + markdown.slice(section.end);
|
|
472005
|
-
}
|
|
472006
|
-
function moveStoryboardBeat(markdown, opts) {
|
|
472007
|
-
if (opts.beatId === opts.afterBeatId) return markdown;
|
|
472008
|
-
const sections = splitBeatSections(markdown);
|
|
472009
|
-
const movingIndex = sections.findIndex((section) => section.id === opts.beatId);
|
|
472010
|
-
if (movingIndex === -1) throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
472011
|
-
const afterIndex = sections.findIndex((section) => section.id === opts.afterBeatId);
|
|
472012
|
-
if (afterIndex === -1) throw new Error(`Beat "${opts.afterBeatId}" not found.`);
|
|
472013
|
-
const global3 = sections.length > 0 ? markdown.slice(0, sections[0].start) : markdown;
|
|
472014
|
-
const chunks = sections.map((section) => section.raw);
|
|
472015
|
-
const [moving] = chunks.splice(movingIndex, 1);
|
|
472016
|
-
const adjustedAfterIndex = movingIndex < afterIndex ? afterIndex - 1 : afterIndex;
|
|
472017
|
-
chunks.splice(adjustedAfterIndex + 1, 0, moving);
|
|
472018
|
-
return global3 + normalizeBeatChunks(chunks);
|
|
472019
|
-
}
|
|
472020
|
-
function normalizeBeatChunks(chunks) {
|
|
472021
|
-
return chunks.map((chunk) => chunk.trim()).filter(Boolean).join("\n\n") + "\n";
|
|
472022
|
-
}
|
|
472023
|
-
function normalizeCueValue(key2, value) {
|
|
472024
|
-
if (key2 === "duration") {
|
|
472025
|
-
const n2 = typeof value === "number" ? value : Number.parseFloat(String(value ?? ""));
|
|
472026
|
-
if (!Number.isFinite(n2) || n2 <= 0) {
|
|
472027
|
-
throw new Error("Cue duration must be a positive number.");
|
|
472028
|
-
}
|
|
472029
|
-
return n2;
|
|
472030
|
-
}
|
|
472031
|
-
if (typeof value !== "string") return value;
|
|
472032
|
-
return value.trim();
|
|
472033
|
-
}
|
|
472034
|
-
function splitBeatSections(markdown) {
|
|
472035
|
-
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
472036
|
-
const headings = [];
|
|
472037
|
-
HEADING_RE2.lastIndex = 0;
|
|
472038
|
-
let match2;
|
|
472039
|
-
while ((match2 = HEADING_RE2.exec(normalized)) !== null) {
|
|
472040
|
-
headings.push({ start: match2.index, end: match2.index + match2[0].length, line: match2[1].trim() });
|
|
472041
|
-
}
|
|
472042
|
-
return headings.map((heading, index) => {
|
|
472043
|
-
const end = index + 1 < headings.length ? headings[index + 1].start : normalized.length;
|
|
472044
|
-
return {
|
|
472045
|
-
id: deriveBeatId(heading.line),
|
|
472046
|
-
heading: heading.line,
|
|
472047
|
-
start: heading.start,
|
|
472048
|
-
headingEnd: heading.end,
|
|
472049
|
-
end,
|
|
472050
|
-
raw: normalized.slice(heading.start, end),
|
|
472051
|
-
body: normalized.slice(heading.end, end).trim()
|
|
472052
|
-
};
|
|
472053
|
-
});
|
|
472054
|
-
}
|
|
472055
|
-
function findBeatSection(markdown, beatId) {
|
|
472056
|
-
return splitBeatSections(markdown).find((section) => section.id === beatId) ?? null;
|
|
472057
|
-
}
|
|
472058
|
-
function readLeadingCueBlock(body) {
|
|
472059
|
-
const match2 = body.match(LEADING_CUE_RE);
|
|
472060
|
-
if (!match2) return null;
|
|
472061
|
-
try {
|
|
472062
|
-
const parsed = (0, import_yaml5.parse)(match2[2]);
|
|
472063
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
472064
|
-
return { full: match2[0], error: "cue block must parse to a YAML object" };
|
|
472065
|
-
}
|
|
472066
|
-
return { full: match2[0], value: parsed };
|
|
472067
|
-
} catch (error) {
|
|
472068
|
-
return { full: match2[0], error: error instanceof Error ? error.message : String(error) };
|
|
472069
|
-
}
|
|
472070
|
-
}
|
|
472071
|
-
var import_yaml5, STORYBOARD_CUE_KEYS, HEADING_RE2, LEADING_CUE_RE, ALLOWED_CUE_KEYS, STRING_CUE_KEYS, MAX_RECOMMENDED_BEAT_SEC;
|
|
472072
|
-
var init_storyboard_edit = __esm({
|
|
472073
|
-
"../cli/src/commands/_shared/storyboard-edit.ts"() {
|
|
472074
|
-
"use strict";
|
|
472075
|
-
import_yaml5 = __toESM(require_dist3(), 1);
|
|
472076
|
-
init_storyboard_parse();
|
|
472077
|
-
STORYBOARD_CUE_KEYS = [
|
|
472078
|
-
"duration",
|
|
472079
|
-
"narration",
|
|
472080
|
-
"backdrop",
|
|
472081
|
-
"video",
|
|
472082
|
-
"motion",
|
|
472083
|
-
"voice",
|
|
472084
|
-
"music",
|
|
472085
|
-
"asset"
|
|
472086
|
-
];
|
|
472087
|
-
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
472088
|
-
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
472089
|
-
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
472090
|
-
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "motion", "voice", "music", "asset"]);
|
|
472091
|
-
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
472092
|
-
}
|
|
472093
|
-
});
|
|
472094
|
-
|
|
472095
472765
|
// ../cli/src/commands/_shared/build-plan.ts
|
|
472096
472766
|
import { existsSync as existsSync33 } from "node:fs";
|
|
472097
472767
|
import { readFile as readFile17 } from "node:fs/promises";
|
|
472098
|
-
import { dirname as dirname17, join as
|
|
472768
|
+
import { dirname as dirname17, join as join30, resolve as resolve29 } from "node:path";
|
|
472099
472769
|
function backdropCostUsd(quality) {
|
|
472100
472770
|
return quality === "hd" ? 0.2 : 0.05;
|
|
472101
472771
|
}
|
|
@@ -472104,7 +472774,7 @@ async function createBuildPlan(opts) {
|
|
|
472104
472774
|
loadPlanEnv(projectDir);
|
|
472105
472775
|
const stage = opts.stage ?? "all";
|
|
472106
472776
|
const config4 = await readProjectConfig(projectDir);
|
|
472107
|
-
const storyboardPath =
|
|
472777
|
+
const storyboardPath = join30(projectDir, "STORYBOARD.md");
|
|
472108
472778
|
const warnings = [];
|
|
472109
472779
|
const retryWith = [];
|
|
472110
472780
|
const providerResolution = [];
|
|
@@ -472163,7 +472833,7 @@ async function createBuildPlan(opts) {
|
|
|
472163
472833
|
const imageQuality = opts.imageQuality ?? config4.config.build.imageQuality ?? "hd";
|
|
472164
472834
|
const imageSize2 = opts.imageSize ?? config4.config.build.imageSize ?? "1536x1024";
|
|
472165
472835
|
const imageRatio = imageRatioForSize(imageSize2);
|
|
472166
|
-
const needsComposer = includeCompose && mode !== "agent" && sourceBeats.some((beat) => !existsSync33(
|
|
472836
|
+
const needsComposer = includeCompose && mode !== "agent" && sourceBeats.some((beat) => !existsSync33(join30(projectDir, `compositions/scene-${beat.id}.html`)));
|
|
472167
472837
|
const resolved = await resolvePlanProviders({
|
|
472168
472838
|
projectDir,
|
|
472169
472839
|
config: config4,
|
|
@@ -472190,6 +472860,7 @@ async function createBuildPlan(opts) {
|
|
|
472190
472860
|
const backdropPrompt = stringOrUndefined3(cue.backdrop);
|
|
472191
472861
|
const augmentedBackdropPrompt = backdropPrompt ? augmentBackdropPrompt(backdropPrompt) : null;
|
|
472192
472862
|
const videoPrompt = stringOrUndefined3(cue.video);
|
|
472863
|
+
const keyframePrompt = stringOrUndefined3(cue.keyframe);
|
|
472193
472864
|
const musicPrompt = stringOrUndefined3(cue.music);
|
|
472194
472865
|
const genericReference = resolveGenericAssetReference(projectDir, cue.asset);
|
|
472195
472866
|
const narrationReference = resolveTypedAssetReference(projectDir, "narration", cue.narration);
|
|
@@ -472198,7 +472869,7 @@ async function createBuildPlan(opts) {
|
|
|
472198
472869
|
const musicReference = resolveTypedAssetReference(projectDir, "music", cue.music) ?? (!musicPrompt && genericReference?.kind === "music" ? genericReference : null);
|
|
472199
472870
|
const narrationCue = narrationText ?? narrationReference?.raw;
|
|
472200
472871
|
const backdropCue = backdropPrompt ?? backdropReference?.raw;
|
|
472201
|
-
const videoCue = videoPrompt ?? videoReference?.raw;
|
|
472872
|
+
const videoCue = videoPrompt ?? videoReference?.raw ?? keyframePrompt;
|
|
472202
472873
|
const musicCue = musicPrompt ?? musicReference?.raw;
|
|
472203
472874
|
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : resolved.narration.resolved === "openai" ? OPENAI_NARRATION_COST_USD : 0;
|
|
472204
472875
|
const narrationCache = narrationText && !narrationReference ? narrationCacheDescriptor({
|
|
@@ -472216,11 +472887,12 @@ async function createBuildPlan(opts) {
|
|
|
472216
472887
|
size: imageSize2,
|
|
472217
472888
|
ratio: imageRatio
|
|
472218
472889
|
}) : null;
|
|
472219
|
-
const videoCache = videoPrompt && !videoReference ? videoCacheDescriptor({
|
|
472890
|
+
const videoCache = (videoPrompt || keyframePrompt) && !videoReference ? videoCacheDescriptor({
|
|
472220
472891
|
beatId: beat.id,
|
|
472221
|
-
cue: videoPrompt,
|
|
472892
|
+
cue: videoPrompt ?? keyframePrompt,
|
|
472222
472893
|
provider: resolved.video.resolved,
|
|
472223
|
-
duration: beat.duration
|
|
472894
|
+
duration: beat.duration,
|
|
472895
|
+
keyframe: keyframePrompt
|
|
472224
472896
|
}) : null;
|
|
472225
472897
|
const musicCache = musicPrompt && !musicReference ? musicCacheDescriptor({
|
|
472226
472898
|
beatId: beat.id,
|
|
@@ -472267,7 +472939,11 @@ async function createBuildPlan(opts) {
|
|
|
472267
472939
|
reference: videoReference,
|
|
472268
472940
|
projectDir,
|
|
472269
472941
|
force: opts.force,
|
|
472270
|
-
cost:
|
|
472942
|
+
cost: resolved.video.resolved === "seedance" || resolved.video.resolved === "fal" ? estimateSeedanceVideoCostUsd({
|
|
472943
|
+
durationSec: normalizeVideoDuration(beat.duration),
|
|
472944
|
+
resolution: "720p",
|
|
472945
|
+
aspectRatio: "16:9"
|
|
472946
|
+
}) : VIDEO_COST_USD,
|
|
472271
472947
|
active: includeAssets
|
|
472272
472948
|
}) : null;
|
|
472273
472949
|
const music = musicCue && !opts.skipMusic ? assetPlan({
|
|
@@ -472284,7 +472960,7 @@ async function createBuildPlan(opts) {
|
|
|
472284
472960
|
active: includeAssets
|
|
472285
472961
|
}) : null;
|
|
472286
472962
|
const compositionPath = `compositions/scene-${beat.id}.html`;
|
|
472287
|
-
const compositionExists = existsSync33(
|
|
472963
|
+
const compositionExists = existsSync33(join30(projectDir, compositionPath));
|
|
472288
472964
|
for (const asset of [narration, backdrop, video, music]) {
|
|
472289
472965
|
if (!asset) continue;
|
|
472290
472966
|
if (asset.referenceError) {
|
|
@@ -472311,6 +472987,12 @@ async function createBuildPlan(opts) {
|
|
|
472311
472987
|
if (backdrop?.willGenerate && isSupportedBuildImageProvider(resolved.image.resolved))
|
|
472312
472988
|
noteProviderNeed(resolved.image, "Backdrop generation");
|
|
472313
472989
|
if (video?.willGenerate) noteProviderNeed(resolved.video, "Video generation");
|
|
472990
|
+
if (keyframePrompt && video?.willGenerate) {
|
|
472991
|
+
estimatedCostUsd += backdropCostUsd(imageQuality);
|
|
472992
|
+
providers.add(resolved.image.resolved);
|
|
472993
|
+
if (isSupportedBuildImageProvider(resolved.image.resolved))
|
|
472994
|
+
noteProviderNeed(resolved.image, "Keyframe generation");
|
|
472995
|
+
}
|
|
472314
472996
|
if (music?.willGenerate) noteProviderNeed(resolved.music, "Music generation");
|
|
472315
472997
|
if (!compositionExists) missing.add("compositions");
|
|
472316
472998
|
if (includeCompose && !compositionExists && mode !== "agent") {
|
|
@@ -472351,7 +473033,7 @@ async function createBuildPlan(opts) {
|
|
|
472351
473033
|
}
|
|
472352
473034
|
}
|
|
472353
473035
|
const validationOk = !validationIssues.some((issue) => issue.severity === "error");
|
|
472354
|
-
if (!existsSync33(
|
|
473036
|
+
if (!existsSync33(join30(projectDir, config4.config.composition.entry))) {
|
|
472355
473037
|
missing.add("root-composition");
|
|
472356
473038
|
if (validationOk) retryWith.push(`vibe build ${projectDir} --stage sync --json`);
|
|
472357
473039
|
}
|
|
@@ -472378,6 +473060,21 @@ async function createBuildPlan(opts) {
|
|
|
472378
473060
|
retryWith.push(skipCommand);
|
|
472379
473061
|
}
|
|
472380
473062
|
}
|
|
473063
|
+
if (validationOk && includeAssets && !opts.skipVideo) {
|
|
473064
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
473065
|
+
for (const beat of sourceBeats) {
|
|
473066
|
+
for (const name of beatCharacterNames(beat.cues)) referenced.add(name);
|
|
473067
|
+
}
|
|
473068
|
+
if (referenced.size > 0) {
|
|
473069
|
+
const toGenerate = resolveCharacters(parsed.frontmatter).filter(
|
|
473070
|
+
(c2) => referenced.has(c2.name) && c2.prompt && (opts.force || !existsSync33(join30(projectDir, `assets/character-${c2.name}.png`)))
|
|
473071
|
+
);
|
|
473072
|
+
if (toGenerate.length > 0) {
|
|
473073
|
+
estimatedCostUsd += toGenerate.length * backdropCostUsd(opts.imageQuality ?? "hd");
|
|
473074
|
+
missing.add("assets");
|
|
473075
|
+
}
|
|
473076
|
+
}
|
|
473077
|
+
}
|
|
472381
473078
|
return finalizeBuildPlan({
|
|
472382
473079
|
projectDir,
|
|
472383
473080
|
config: config4,
|
|
@@ -472483,8 +473180,8 @@ function assetPlan(opts) {
|
|
|
472483
473180
|
reason: ready ? "referenced-asset" : "invalid-reference"
|
|
472484
473181
|
};
|
|
472485
473182
|
}
|
|
472486
|
-
const canonicalExists = existsSync33(
|
|
472487
|
-
const cacheHit = opts.cache ? existsSync33(
|
|
473183
|
+
const canonicalExists = existsSync33(join30(opts.projectDir, opts.path));
|
|
473184
|
+
const cacheHit = opts.cache ? existsSync33(join30(opts.projectDir, opts.cache.path)) : false;
|
|
472488
473185
|
const freshness = assetFreshnessFromMetadata({
|
|
472489
473186
|
projectDir: opts.projectDir,
|
|
472490
473187
|
kind: opts.kind,
|
|
@@ -472681,7 +473378,7 @@ async function firstConfiguredComposer(projectDir) {
|
|
|
472681
473378
|
}
|
|
472682
473379
|
function firstExisting2(projectDir, paths) {
|
|
472683
473380
|
for (const path14 of paths) {
|
|
472684
|
-
if (existsSync33(
|
|
473381
|
+
if (existsSync33(join30(projectDir, path14))) return path14;
|
|
472685
473382
|
}
|
|
472686
473383
|
return null;
|
|
472687
473384
|
}
|
|
@@ -472722,12 +473419,12 @@ function unique3(items) {
|
|
|
472722
473419
|
return [...new Set(items.filter((item) => item.length > 0))];
|
|
472723
473420
|
}
|
|
472724
473421
|
function loadPlanEnv(projectDir) {
|
|
472725
|
-
(0, import_dotenv2.config)({ path:
|
|
473422
|
+
(0, import_dotenv2.config)({ path: join30(projectDir, ".env"), quiet: true });
|
|
472726
473423
|
(0, import_dotenv2.config)({ path: resolve29(process.cwd(), ".env"), quiet: true });
|
|
472727
473424
|
let dir = process.cwd();
|
|
472728
473425
|
while (dir !== dirname17(dir)) {
|
|
472729
|
-
if (existsSync33(
|
|
472730
|
-
(0, import_dotenv2.config)({ path:
|
|
473426
|
+
if (existsSync33(join30(dir, "pnpm-workspace.yaml"))) {
|
|
473427
|
+
(0, import_dotenv2.config)({ path: join30(dir, ".env"), quiet: true });
|
|
472731
473428
|
return;
|
|
472732
473429
|
}
|
|
472733
473430
|
dir = dirname17(dir);
|
|
@@ -472742,6 +473439,7 @@ var init_build_plan = __esm({
|
|
|
472742
473439
|
init_schema();
|
|
472743
473440
|
init_build_asset_reference();
|
|
472744
473441
|
init_build_cache();
|
|
473442
|
+
init_dist();
|
|
472745
473443
|
init_build_asset_metadata();
|
|
472746
473444
|
init_build_backdrop_prompt();
|
|
472747
473445
|
init_composer_resolve();
|
|
@@ -473074,9 +473772,9 @@ __export(scene_build_exports, {
|
|
|
473074
473772
|
executeSceneBuild: () => executeSceneBuild,
|
|
473075
473773
|
resolveSceneBuildMode: () => resolveSceneBuildMode
|
|
473076
473774
|
});
|
|
473077
|
-
import { existsSync as existsSync35 } from "node:fs";
|
|
473775
|
+
import { existsSync as existsSync35, readFileSync as readFileSync12 } from "node:fs";
|
|
473078
473776
|
import { copyFile as copyFile4, mkdir as mkdir13, readFile as readFile18, writeFile as writeFile20 } from "node:fs/promises";
|
|
473079
|
-
import { dirname as dirname18, join as
|
|
473777
|
+
import { dirname as dirname18, join as join31, resolve as resolve33 } from "node:path";
|
|
473080
473778
|
async function executeSceneBuild(opts) {
|
|
473081
473779
|
const startedAt = Date.now();
|
|
473082
473780
|
const projectDir = resolve33(opts.projectDir);
|
|
@@ -473088,7 +473786,7 @@ async function executeSceneBuild(opts) {
|
|
|
473088
473786
|
const warnings = [];
|
|
473089
473787
|
const retryWith = [];
|
|
473090
473788
|
let sceneRepair = skippedSceneRepairSummary();
|
|
473091
|
-
const storyboardPath =
|
|
473789
|
+
const storyboardPath = join31(projectDir, "STORYBOARD.md");
|
|
473092
473790
|
const buildPlan = await createBuildPlan({
|
|
473093
473791
|
projectDir,
|
|
473094
473792
|
stage: selectedStage,
|
|
@@ -473241,8 +473939,32 @@ async function executeSceneBuild(opts) {
|
|
|
473241
473939
|
const voice = opts.voice ?? parsed.frontmatter?.voice;
|
|
473242
473940
|
let beatOutcomes = collectExistingBeatOutcomes(parsed.beats, projectDir);
|
|
473243
473941
|
let pendingJobs = [];
|
|
473942
|
+
let characterCostUsd = 0;
|
|
473244
473943
|
if (shouldRunStage(selectedStage, "assets")) {
|
|
473245
473944
|
onProgress({ type: "phase-start", phase: "primitives" });
|
|
473945
|
+
const characterPaths = /* @__PURE__ */ new Map();
|
|
473946
|
+
if (!(opts.skipVideo ?? false)) {
|
|
473947
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
473948
|
+
for (const beat of activeBeats) {
|
|
473949
|
+
for (const name of beatCharacterNames(beat.cues)) referenced.add(name);
|
|
473950
|
+
}
|
|
473951
|
+
if (referenced.size > 0) {
|
|
473952
|
+
const charResult = await buildCharacters(
|
|
473953
|
+
resolveCharacters(parsed.frontmatter).filter((c2) => referenced.has(c2.name)),
|
|
473954
|
+
{
|
|
473955
|
+
projectDir,
|
|
473956
|
+
imageProvider,
|
|
473957
|
+
imageSize: opts.imageSize ?? "1536x1024",
|
|
473958
|
+
imageQuality: opts.imageQuality ?? "hd",
|
|
473959
|
+
force: opts.force ?? false,
|
|
473960
|
+
onProgress
|
|
473961
|
+
}
|
|
473962
|
+
);
|
|
473963
|
+
for (const [name, path14] of charResult.paths) characterPaths.set(name, path14);
|
|
473964
|
+
characterCostUsd = charResult.costUsd;
|
|
473965
|
+
warnings.push(...charResult.failures);
|
|
473966
|
+
}
|
|
473967
|
+
}
|
|
473246
473968
|
const primitiveResults = await mapWithConcurrency(
|
|
473247
473969
|
activeBeats,
|
|
473248
473970
|
BEAT_PRIMITIVES_CONCURRENCY,
|
|
@@ -473260,7 +473982,8 @@ async function executeSceneBuild(opts) {
|
|
|
473260
473982
|
skipVideo: opts.skipVideo ?? false,
|
|
473261
473983
|
skipMusic: opts.skipMusic ?? false,
|
|
473262
473984
|
force: opts.force ?? false,
|
|
473263
|
-
onProgress
|
|
473985
|
+
onProgress,
|
|
473986
|
+
characterPaths
|
|
473264
473987
|
})
|
|
473265
473988
|
);
|
|
473266
473989
|
beatOutcomes = primitiveResults.map((result) => result.outcome);
|
|
@@ -473269,10 +473992,7 @@ async function executeSceneBuild(opts) {
|
|
|
473269
473992
|
(beat) => beat.narrationStatus === "failed" || beat.backdropStatus === "failed" || beat.videoStatus === "failed" || beat.musicStatus === "failed"
|
|
473270
473993
|
);
|
|
473271
473994
|
stageReports.assets.status = assetFailed ? "failed" : pendingJobs.length > 0 ? "pending-jobs" : "done";
|
|
473272
|
-
stageReports.assets.costUsd = estimateActualAssetCost(
|
|
473273
|
-
beatOutcomes,
|
|
473274
|
-
opts.imageQuality ?? "hd"
|
|
473275
|
-
);
|
|
473995
|
+
stageReports.assets.costUsd = estimateActualAssetCost(beatOutcomes, opts.imageQuality ?? "hd") + characterCostUsd;
|
|
473276
473996
|
stageReports.assets.retryWith = pendingJobs.map(
|
|
473277
473997
|
(job) => `vibe status job ${job.id} --project ${projectDir} --json`
|
|
473278
473998
|
);
|
|
@@ -473348,9 +474068,9 @@ async function executeSceneBuild(opts) {
|
|
|
473348
474068
|
let composeData;
|
|
473349
474069
|
if (shouldRunStage(selectedStage, "compose")) {
|
|
473350
474070
|
if (mode === "agent") {
|
|
473351
|
-
const compositionsDir =
|
|
474071
|
+
const compositionsDir = join31(projectDir, "compositions");
|
|
473352
474072
|
const missingBeats = activeBeats.filter(
|
|
473353
|
-
(b2) => !existsSync35(
|
|
474073
|
+
(b2) => !existsSync35(join31(compositionsDir, `scene-${b2.id}.html`))
|
|
473354
474074
|
);
|
|
473355
474075
|
if (missingBeats.length > 0) {
|
|
473356
474076
|
const plan = await getComposePrompts({ projectDir, beatId: opts.beatId });
|
|
@@ -473437,6 +474157,18 @@ async function executeSceneBuild(opts) {
|
|
|
473437
474157
|
stageReports.compose.status = "skipped";
|
|
473438
474158
|
}
|
|
473439
474159
|
if (stageReports.compose.status === "done") {
|
|
474160
|
+
for (const beat of activeBeats) {
|
|
474161
|
+
const videoRel = `assets/video-${beat.id}.mp4`;
|
|
474162
|
+
const compositionAbs = join31(projectDir, "compositions", `scene-${beat.id}.html`);
|
|
474163
|
+
if (!existsSync35(join31(projectDir, videoRel)) || !existsSync35(compositionAbs)) continue;
|
|
474164
|
+
const html = readFileSync12(compositionAbs, "utf-8");
|
|
474165
|
+
if (!html.includes(videoRel)) {
|
|
474166
|
+
warnings.push(
|
|
474167
|
+
`Beat "${beat.id}" has a generated clip (${videoRel}) but its composition does not reference it, so the clip will not appear. Recompose the beat.`
|
|
474168
|
+
);
|
|
474169
|
+
retryWith.push(`vibe build ${projectDir} --beat ${beat.id} --stage compose --force --json`);
|
|
474170
|
+
}
|
|
474171
|
+
}
|
|
473440
474172
|
const repair = await runBuildSceneRepair(projectDir, "compose", false);
|
|
473441
474173
|
sceneRepair = mergeSceneRepairSummaries(sceneRepair, repair);
|
|
473442
474174
|
applySceneRepairToStage(stageReports.compose, repair);
|
|
@@ -473486,7 +474218,7 @@ async function executeSceneBuild(opts) {
|
|
|
473486
474218
|
});
|
|
473487
474219
|
}
|
|
473488
474220
|
if (shouldRunStage(selectedStage, "sync")) {
|
|
473489
|
-
if (!existsSync35(
|
|
474221
|
+
if (!existsSync35(join31(projectDir, "index.html"))) {
|
|
473490
474222
|
await scaffoldSceneProject({
|
|
473491
474223
|
dir: projectDir,
|
|
473492
474224
|
name: projectDir.split(/[\\/]/).filter(Boolean).pop(),
|
|
@@ -473671,6 +474403,8 @@ async function buildBeatPrimitives(beat, ctx) {
|
|
|
473671
474403
|
videoMetadataPath: video.metadataPath,
|
|
473672
474404
|
videoFreshness: video.freshness,
|
|
473673
474405
|
videoSourcePath: video.sourcePath,
|
|
474406
|
+
keyframeStatus: video.keyframeStatus,
|
|
474407
|
+
keyframePath: video.keyframePath,
|
|
473674
474408
|
musicStatus: music.status,
|
|
473675
474409
|
musicPath: music.path,
|
|
473676
474410
|
musicJobId: music.job?.id,
|
|
@@ -473745,7 +474479,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473745
474479
|
return {
|
|
473746
474480
|
status: "cached",
|
|
473747
474481
|
path: existingRel,
|
|
473748
|
-
durationSec: await safeAudioDuration(
|
|
474482
|
+
durationSec: await safeAudioDuration(join31(ctx.projectDir, existingRel)),
|
|
473749
474483
|
provider: metadata?.provider,
|
|
473750
474484
|
cachePath: metadata?.cachePath,
|
|
473751
474485
|
cacheKey: metadata?.cacheKey,
|
|
@@ -473769,9 +474503,9 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473769
474503
|
voice,
|
|
473770
474504
|
ext: resolution.audioExtension
|
|
473771
474505
|
});
|
|
473772
|
-
const cacheAbs =
|
|
474506
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
473773
474507
|
const rel = `assets/narration-${beat.id}.${resolution.audioExtension}`;
|
|
473774
|
-
const abs =
|
|
474508
|
+
const abs = join31(ctx.projectDir, rel);
|
|
473775
474509
|
if (existingRel && !ctx.force && isFreshCanonicalAsset({
|
|
473776
474510
|
projectDir: ctx.projectDir,
|
|
473777
474511
|
kind: "narration",
|
|
@@ -473785,7 +474519,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473785
474519
|
return {
|
|
473786
474520
|
status: "cached",
|
|
473787
474521
|
path: existingRel,
|
|
473788
|
-
durationSec: await safeAudioDuration(
|
|
474522
|
+
durationSec: await safeAudioDuration(join31(ctx.projectDir, existingRel)),
|
|
473789
474523
|
provider: resolution.provider,
|
|
473790
474524
|
cachePath: cache.path,
|
|
473791
474525
|
cacheKey: cache.key,
|
|
@@ -473857,6 +474591,120 @@ async function dispatchNarration(beat, ctx) {
|
|
|
473857
474591
|
freshness: "fresh"
|
|
473858
474592
|
};
|
|
473859
474593
|
}
|
|
474594
|
+
function characterSheetPrompt(name, description) {
|
|
474595
|
+
return [
|
|
474596
|
+
`Character turnaround reference sheet of an original fictional character named ${name}: ${description}.`,
|
|
474597
|
+
"Show three full-body views side by side on one clean canvas \u2014 front view, side profile, and back view \u2014",
|
|
474598
|
+
"with identical outfit, hairstyle, hair color, and body proportions across all three views.",
|
|
474599
|
+
"Plain light-grey studio background, even neutral lighting, no props.",
|
|
474600
|
+
"Photorealistic digital character, professional concept-art character sheet layout."
|
|
474601
|
+
].join(" ");
|
|
474602
|
+
}
|
|
474603
|
+
async function buildCharacters(characters, ctx) {
|
|
474604
|
+
const paths = /* @__PURE__ */ new Map();
|
|
474605
|
+
const failures = [];
|
|
474606
|
+
let costUsd = 0;
|
|
474607
|
+
const size = ctx.imageSize ?? "1536x1024";
|
|
474608
|
+
for (const character of characters) {
|
|
474609
|
+
if (character.imagePath) {
|
|
474610
|
+
if (existsSync35(join31(ctx.projectDir, character.imagePath))) {
|
|
474611
|
+
paths.set(character.name, character.imagePath);
|
|
474612
|
+
ctx.onProgress({ type: "character-cached", name: character.name, path: character.imagePath });
|
|
474613
|
+
} else {
|
|
474614
|
+
const error = `character "${character.name}" image not found: ${character.imagePath}`;
|
|
474615
|
+
failures.push(error);
|
|
474616
|
+
ctx.onProgress({ type: "character-failed", name: character.name, error });
|
|
474617
|
+
}
|
|
474618
|
+
continue;
|
|
474619
|
+
}
|
|
474620
|
+
if (!character.prompt) continue;
|
|
474621
|
+
const prompt3 = characterSheetPrompt(character.name, character.prompt);
|
|
474622
|
+
const rel = `assets/character-${character.name}.png`;
|
|
474623
|
+
const abs = join31(ctx.projectDir, rel);
|
|
474624
|
+
const metadataOptions = { quality: ctx.imageQuality, size };
|
|
474625
|
+
const cache = characterCacheDescriptor({
|
|
474626
|
+
name: character.name,
|
|
474627
|
+
cue: prompt3,
|
|
474628
|
+
provider: ctx.imageProvider,
|
|
474629
|
+
quality: ctx.imageQuality,
|
|
474630
|
+
size
|
|
474631
|
+
});
|
|
474632
|
+
if (existsSync35(abs) && !ctx.force) {
|
|
474633
|
+
const metadata = readAssetMetadata(ctx.projectDir, "character", character.name);
|
|
474634
|
+
if (!metadata || isFreshCanonicalAsset({
|
|
474635
|
+
projectDir: ctx.projectDir,
|
|
474636
|
+
kind: "character",
|
|
474637
|
+
beatId: character.name,
|
|
474638
|
+
cue: prompt3,
|
|
474639
|
+
provider: ctx.imageProvider,
|
|
474640
|
+
options: metadataOptions,
|
|
474641
|
+
cacheKey: cache.key
|
|
474642
|
+
})) {
|
|
474643
|
+
paths.set(character.name, rel);
|
|
474644
|
+
ctx.onProgress({ type: "character-cached", name: character.name, path: rel });
|
|
474645
|
+
continue;
|
|
474646
|
+
}
|
|
474647
|
+
}
|
|
474648
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474649
|
+
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474650
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474651
|
+
await copyFile4(cacheAbs, abs);
|
|
474652
|
+
await writeAssetMetadata({
|
|
474653
|
+
projectDir: ctx.projectDir,
|
|
474654
|
+
kind: "character",
|
|
474655
|
+
beatId: character.name,
|
|
474656
|
+
cue: prompt3,
|
|
474657
|
+
provider: ctx.imageProvider,
|
|
474658
|
+
options: metadataOptions,
|
|
474659
|
+
cacheKey: cache.key,
|
|
474660
|
+
canonicalPath: rel,
|
|
474661
|
+
cachePath: cache.path
|
|
474662
|
+
});
|
|
474663
|
+
paths.set(character.name, rel);
|
|
474664
|
+
ctx.onProgress({ type: "character-cached", name: character.name, path: rel });
|
|
474665
|
+
continue;
|
|
474666
|
+
}
|
|
474667
|
+
const generated = await generateBackdropImage(
|
|
474668
|
+
prompt3,
|
|
474669
|
+
{
|
|
474670
|
+
projectDir: ctx.projectDir,
|
|
474671
|
+
imageProvider: ctx.imageProvider,
|
|
474672
|
+
imageSize: size,
|
|
474673
|
+
imageQuality: ctx.imageQuality
|
|
474674
|
+
},
|
|
474675
|
+
imageRatioForSize(size)
|
|
474676
|
+
);
|
|
474677
|
+
if (!generated.success) {
|
|
474678
|
+
failures.push(`character "${character.name}": ${generated.error}`);
|
|
474679
|
+
ctx.onProgress({ type: "character-failed", name: character.name, error: generated.error });
|
|
474680
|
+
continue;
|
|
474681
|
+
}
|
|
474682
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474683
|
+
await writeFile20(abs, generated.buffer);
|
|
474684
|
+
await mkdir13(dirname18(cacheAbs), { recursive: true });
|
|
474685
|
+
await writeFile20(cacheAbs, generated.buffer);
|
|
474686
|
+
await writeAssetMetadata({
|
|
474687
|
+
projectDir: ctx.projectDir,
|
|
474688
|
+
kind: "character",
|
|
474689
|
+
beatId: character.name,
|
|
474690
|
+
cue: prompt3,
|
|
474691
|
+
provider: ctx.imageProvider,
|
|
474692
|
+
options: metadataOptions,
|
|
474693
|
+
cacheKey: cache.key,
|
|
474694
|
+
canonicalPath: rel,
|
|
474695
|
+
cachePath: cache.path
|
|
474696
|
+
});
|
|
474697
|
+
costUsd += backdropCostUsd(ctx.imageQuality);
|
|
474698
|
+
paths.set(character.name, rel);
|
|
474699
|
+
ctx.onProgress({
|
|
474700
|
+
type: "character-generated",
|
|
474701
|
+
name: character.name,
|
|
474702
|
+
path: rel,
|
|
474703
|
+
provider: ctx.imageProvider
|
|
474704
|
+
});
|
|
474705
|
+
}
|
|
474706
|
+
return { paths, costUsd: Number(costUsd.toFixed(2)), failures };
|
|
474707
|
+
}
|
|
473860
474708
|
async function dispatchBackdrop(beat, ctx) {
|
|
473861
474709
|
const reference = assetReferenceForBeat(ctx.projectDir, "backdrop", beat);
|
|
473862
474710
|
if (reference) return referencePrimitiveOutcome("backdrop", beat, ctx, reference);
|
|
@@ -473864,7 +474712,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
473864
474712
|
if (!cue) return { status: "no-cue" };
|
|
473865
474713
|
const prompt3 = augmentBackdropPrompt(cue);
|
|
473866
474714
|
const rel = `assets/backdrop-${beat.id}.png`;
|
|
473867
|
-
const abs =
|
|
474715
|
+
const abs = join31(ctx.projectDir, rel);
|
|
473868
474716
|
const size = ctx.imageSize ?? "1536x1024";
|
|
473869
474717
|
const ratio = imageRatioForSize(size);
|
|
473870
474718
|
const metadataOptions = { quality: ctx.imageQuality, size, ratio };
|
|
@@ -473900,7 +474748,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
473900
474748
|
};
|
|
473901
474749
|
}
|
|
473902
474750
|
}
|
|
473903
|
-
const cacheAbs =
|
|
474751
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
473904
474752
|
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
473905
474753
|
await mkdir13(dirname18(abs), { recursive: true });
|
|
473906
474754
|
await copyFile4(cacheAbs, abs);
|
|
@@ -474001,6 +474849,112 @@ async function generateBackdropImage(prompt3, ctx, ratio) {
|
|
|
474001
474849
|
});
|
|
474002
474850
|
return imageBufferFromResult(result);
|
|
474003
474851
|
}
|
|
474852
|
+
async function editKeyframeImage(prompt3, sheetBuffers, ctx, ratio) {
|
|
474853
|
+
loadSceneBuildEnv(ctx.projectDir);
|
|
474854
|
+
const keyInfo = imageProviderKeyInfo(ctx.imageProvider);
|
|
474855
|
+
const apiKey = await getApiKeyFromConfig(keyInfo.configKey, { cwd: ctx.projectDir }) ?? process.env[keyInfo.envVar] ?? "";
|
|
474856
|
+
if (!apiKey) {
|
|
474857
|
+
return {
|
|
474858
|
+
success: false,
|
|
474859
|
+
error: `${keyInfo.envVar} not set \u2014 cannot generate keyframe with ${ctx.imageProvider}`
|
|
474860
|
+
};
|
|
474861
|
+
}
|
|
474862
|
+
if (ctx.imageProvider === "openai") {
|
|
474863
|
+
const provider2 = new OpenAIImageProvider();
|
|
474864
|
+
await provider2.initialize({ apiKey });
|
|
474865
|
+
const result2 = await provider2.editImage(sheetBuffers, prompt3);
|
|
474866
|
+
return imageBufferFromResult(result2);
|
|
474867
|
+
}
|
|
474868
|
+
if (ctx.imageProvider === "gemini") {
|
|
474869
|
+
const provider2 = new GeminiProvider();
|
|
474870
|
+
await provider2.initialize({ apiKey });
|
|
474871
|
+
const result2 = await provider2.editImage(sheetBuffers, prompt3, {
|
|
474872
|
+
model: "flash",
|
|
474873
|
+
aspectRatio: ratio
|
|
474874
|
+
});
|
|
474875
|
+
return imageBufferFromResult(result2);
|
|
474876
|
+
}
|
|
474877
|
+
const provider = new GrokProvider();
|
|
474878
|
+
await provider.initialize({ apiKey });
|
|
474879
|
+
const result = await provider.editImage(sheetBuffers[0], prompt3, { aspectRatio: ratio });
|
|
474880
|
+
return imageBufferFromResult(result);
|
|
474881
|
+
}
|
|
474882
|
+
async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
474883
|
+
const rel = `assets/keyframe-${beat.id}.png`;
|
|
474884
|
+
const abs = join31(ctx.projectDir, rel);
|
|
474885
|
+
const size = ctx.imageSize ?? "1536x1024";
|
|
474886
|
+
const ratio = imageRatioForSize(size);
|
|
474887
|
+
const metadataOptions = { quality: ctx.imageQuality, size, ratio };
|
|
474888
|
+
const cache = keyframeCacheDescriptor({
|
|
474889
|
+
beatId: beat.id,
|
|
474890
|
+
cue: keyframeCue,
|
|
474891
|
+
provider: ctx.imageProvider,
|
|
474892
|
+
quality: ctx.imageQuality,
|
|
474893
|
+
size,
|
|
474894
|
+
ratio,
|
|
474895
|
+
characters: characterRefsRel
|
|
474896
|
+
});
|
|
474897
|
+
if (existsSync35(abs) && !ctx.force) {
|
|
474898
|
+
const metadata = readAssetMetadata(ctx.projectDir, "keyframe", beat.id);
|
|
474899
|
+
if (!metadata || isFreshCanonicalAsset({
|
|
474900
|
+
projectDir: ctx.projectDir,
|
|
474901
|
+
kind: "keyframe",
|
|
474902
|
+
beatId: beat.id,
|
|
474903
|
+
cue: keyframeCue,
|
|
474904
|
+
provider: ctx.imageProvider,
|
|
474905
|
+
options: metadataOptions,
|
|
474906
|
+
cacheKey: cache.key
|
|
474907
|
+
})) {
|
|
474908
|
+
return { status: "cached", rel };
|
|
474909
|
+
}
|
|
474910
|
+
}
|
|
474911
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474912
|
+
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474913
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474914
|
+
await copyFile4(cacheAbs, abs);
|
|
474915
|
+
await writeAssetMetadata({
|
|
474916
|
+
projectDir: ctx.projectDir,
|
|
474917
|
+
kind: "keyframe",
|
|
474918
|
+
beatId: beat.id,
|
|
474919
|
+
cue: keyframeCue,
|
|
474920
|
+
provider: ctx.imageProvider,
|
|
474921
|
+
options: metadataOptions,
|
|
474922
|
+
cacheKey: cache.key,
|
|
474923
|
+
canonicalPath: rel,
|
|
474924
|
+
cachePath: cache.path
|
|
474925
|
+
});
|
|
474926
|
+
return { status: "cached", rel };
|
|
474927
|
+
}
|
|
474928
|
+
const sheetBuffers = [];
|
|
474929
|
+
for (const relPath of characterRefsRel) {
|
|
474930
|
+
const sheetAbs = join31(ctx.projectDir, relPath);
|
|
474931
|
+
if (existsSync35(sheetAbs)) sheetBuffers.push(await readFile18(sheetAbs));
|
|
474932
|
+
}
|
|
474933
|
+
const imgCtx = {
|
|
474934
|
+
projectDir: ctx.projectDir,
|
|
474935
|
+
imageProvider: ctx.imageProvider,
|
|
474936
|
+
imageSize: size,
|
|
474937
|
+
imageQuality: ctx.imageQuality
|
|
474938
|
+
};
|
|
474939
|
+
const generated = sheetBuffers.length > 0 ? await editKeyframeImage(keyframeCue, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
|
|
474940
|
+
if (!generated.success) return { status: "failed", error: generated.error };
|
|
474941
|
+
await mkdir13(dirname18(abs), { recursive: true });
|
|
474942
|
+
await writeFile20(abs, generated.buffer);
|
|
474943
|
+
await mkdir13(dirname18(cacheAbs), { recursive: true });
|
|
474944
|
+
await writeFile20(cacheAbs, generated.buffer);
|
|
474945
|
+
await writeAssetMetadata({
|
|
474946
|
+
projectDir: ctx.projectDir,
|
|
474947
|
+
kind: "keyframe",
|
|
474948
|
+
beatId: beat.id,
|
|
474949
|
+
cue: keyframeCue,
|
|
474950
|
+
provider: ctx.imageProvider,
|
|
474951
|
+
options: metadataOptions,
|
|
474952
|
+
cacheKey: cache.key,
|
|
474953
|
+
canonicalPath: rel,
|
|
474954
|
+
cachePath: cache.path
|
|
474955
|
+
});
|
|
474956
|
+
return { status: "generated", rel };
|
|
474957
|
+
}
|
|
474004
474958
|
async function imageBufferFromResult(result) {
|
|
474005
474959
|
const image = result.images?.[0];
|
|
474006
474960
|
if (!result.success || !image) {
|
|
@@ -474024,15 +474978,22 @@ function imageProviderKeyInfo(provider) {
|
|
|
474024
474978
|
async function dispatchVideo(beat, ctx) {
|
|
474025
474979
|
const reference = assetReferenceForBeat(ctx.projectDir, "video", beat);
|
|
474026
474980
|
if (reference) return referencePrimitiveOutcome("video", beat, ctx, reference);
|
|
474027
|
-
const
|
|
474981
|
+
const keyframeCue = stringOrUndefined4(beat.cues?.keyframe);
|
|
474982
|
+
const prompt3 = stringOrUndefined4(beat.cues?.video) ?? keyframeCue;
|
|
474028
474983
|
if (!prompt3) return { status: "no-cue" };
|
|
474984
|
+
const characterRefsRel = beatCharacterNames(beat.cues).map((name) => ctx.characterPaths?.get(name)).filter((p2) => typeof p2 === "string");
|
|
474985
|
+
const characterRefsAbs = characterRefsRel.map((p2) => join31(ctx.projectDir, p2));
|
|
474029
474986
|
const rel = `assets/video-${beat.id}.mp4`;
|
|
474030
|
-
const abs =
|
|
474987
|
+
const abs = join31(ctx.projectDir, rel);
|
|
474031
474988
|
const cache = videoCacheDescriptor({
|
|
474032
474989
|
beatId: beat.id,
|
|
474033
474990
|
cue: prompt3,
|
|
474034
474991
|
provider: ctx.videoProvider,
|
|
474035
|
-
duration: normalizeVideoDuration(beat.duration)
|
|
474992
|
+
duration: normalizeVideoDuration(beat.duration),
|
|
474993
|
+
// Keyframe mode keys the clip to the keyframe prompt; refs feed the keyframe,
|
|
474994
|
+
// not the clip directly.
|
|
474995
|
+
characters: keyframeCue ? void 0 : characterRefsRel,
|
|
474996
|
+
keyframe: keyframeCue
|
|
474036
474997
|
});
|
|
474037
474998
|
const metadataPath = assetMetadataPath("video", beat.id);
|
|
474038
474999
|
if (existsSync35(abs) && !ctx.force) {
|
|
@@ -474058,7 +475019,7 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474058
475019
|
};
|
|
474059
475020
|
}
|
|
474060
475021
|
}
|
|
474061
|
-
const cacheAbs =
|
|
475022
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474062
475023
|
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474063
475024
|
await mkdir13(dirname18(abs), { recursive: true });
|
|
474064
475025
|
await copyFile4(cacheAbs, abs);
|
|
@@ -474085,6 +475046,19 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474085
475046
|
};
|
|
474086
475047
|
}
|
|
474087
475048
|
loadSceneBuildEnv(ctx.projectDir);
|
|
475049
|
+
let keyframeStatus;
|
|
475050
|
+
let keyframeRel;
|
|
475051
|
+
let keyframeImageAbs;
|
|
475052
|
+
if (keyframeCue) {
|
|
475053
|
+
const kf = await ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel);
|
|
475054
|
+
if (kf.status === "failed") {
|
|
475055
|
+
ctx.onProgress({ type: "video-failed", beatId: beat.id, error: kf.error });
|
|
475056
|
+
return { status: "failed", error: kf.error };
|
|
475057
|
+
}
|
|
475058
|
+
keyframeStatus = kf.status;
|
|
475059
|
+
keyframeRel = kf.rel;
|
|
475060
|
+
keyframeImageAbs = join31(ctx.projectDir, kf.rel);
|
|
475061
|
+
}
|
|
474088
475062
|
const result = await executeVideoGenerate({
|
|
474089
475063
|
prompt: prompt3,
|
|
474090
475064
|
provider: ctx.videoProvider,
|
|
@@ -474092,6 +475066,10 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474092
475066
|
ratio: "16:9",
|
|
474093
475067
|
output: abs,
|
|
474094
475068
|
wait: false,
|
|
475069
|
+
// Keyframe mode → single init frame (image-to-video); otherwise character
|
|
475070
|
+
// reference-to-video.
|
|
475071
|
+
image: keyframeImageAbs,
|
|
475072
|
+
refImages: keyframeImageAbs ? void 0 : characterRefsAbs.length > 0 ? characterRefsAbs : void 0,
|
|
474095
475073
|
apiKey: await apiKeyForVideoProvider(ctx.videoProvider, ctx.projectDir)
|
|
474096
475074
|
});
|
|
474097
475075
|
if (!result.success || !result.taskId) {
|
|
@@ -474126,14 +475104,16 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474126
475104
|
cachePath: cache.path,
|
|
474127
475105
|
cacheKey: cache.key,
|
|
474128
475106
|
metadataPath,
|
|
474129
|
-
freshness: "fresh"
|
|
475107
|
+
freshness: "fresh",
|
|
475108
|
+
keyframeStatus,
|
|
475109
|
+
keyframePath: keyframeRel
|
|
474130
475110
|
};
|
|
474131
475111
|
}
|
|
474132
475112
|
const job = await createAndWriteJobRecord({
|
|
474133
475113
|
jobType: "generate-video",
|
|
474134
475114
|
provider: result.provider ?? ctx.videoProvider,
|
|
474135
475115
|
providerTaskId: result.taskId,
|
|
474136
|
-
providerTaskType: "text2video",
|
|
475116
|
+
providerTaskType: keyframeImageAbs ? "image2video" : "text2video",
|
|
474137
475117
|
status: "running",
|
|
474138
475118
|
projectDir: ctx.projectDir,
|
|
474139
475119
|
workingDirectory: ctx.projectDir,
|
|
@@ -474158,7 +475138,9 @@ async function dispatchVideo(beat, ctx) {
|
|
|
474158
475138
|
provider: job.provider,
|
|
474159
475139
|
cachePath: cache.path,
|
|
474160
475140
|
cacheKey: cache.key,
|
|
474161
|
-
metadataPath
|
|
475141
|
+
metadataPath,
|
|
475142
|
+
keyframeStatus,
|
|
475143
|
+
keyframePath: keyframeRel
|
|
474162
475144
|
};
|
|
474163
475145
|
}
|
|
474164
475146
|
async function dispatchMusic(beat, ctx) {
|
|
@@ -474167,7 +475149,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
474167
475149
|
const prompt3 = stringOrUndefined4(beat.cues?.music);
|
|
474168
475150
|
if (!prompt3) return { status: "no-cue" };
|
|
474169
475151
|
const rel = `assets/music-${beat.id}.mp3`;
|
|
474170
|
-
const abs =
|
|
475152
|
+
const abs = join31(ctx.projectDir, rel);
|
|
474171
475153
|
const duration = normalizeMusicDuration(beat.duration);
|
|
474172
475154
|
const cache = musicCacheDescriptor({
|
|
474173
475155
|
beatId: beat.id,
|
|
@@ -474200,7 +475182,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
474200
475182
|
};
|
|
474201
475183
|
}
|
|
474202
475184
|
}
|
|
474203
|
-
const cacheAbs =
|
|
475185
|
+
const cacheAbs = join31(ctx.projectDir, cache.path);
|
|
474204
475186
|
if (existsSync35(cacheAbs) && !ctx.force) {
|
|
474205
475187
|
await mkdir13(dirname18(abs), { recursive: true });
|
|
474206
475188
|
await copyFile4(cacheAbs, abs);
|
|
@@ -474311,12 +475293,12 @@ async function dispatchMusic(beat, ctx) {
|
|
|
474311
475293
|
};
|
|
474312
475294
|
}
|
|
474313
475295
|
function loadSceneBuildEnv(projectDir) {
|
|
474314
|
-
(0, import_dotenv3.config)({ path:
|
|
475296
|
+
(0, import_dotenv3.config)({ path: join31(projectDir, ".env"), quiet: true });
|
|
474315
475297
|
(0, import_dotenv3.config)({ path: resolve33(process.cwd(), ".env"), quiet: true });
|
|
474316
475298
|
let dir = process.cwd();
|
|
474317
475299
|
while (dir !== dirname18(dir)) {
|
|
474318
|
-
if (existsSync35(
|
|
474319
|
-
(0, import_dotenv3.config)({ path:
|
|
475300
|
+
if (existsSync35(join31(dir, "pnpm-workspace.yaml"))) {
|
|
475301
|
+
(0, import_dotenv3.config)({ path: join31(dir, ".env"), quiet: true });
|
|
474320
475302
|
return;
|
|
474321
475303
|
}
|
|
474322
475304
|
dir = dirname18(dir);
|
|
@@ -474460,7 +475442,14 @@ function estimateActualAssetCost(outcomes, imageQuality) {
|
|
|
474460
475442
|
for (const outcome of outcomes) {
|
|
474461
475443
|
if (outcome.narrationStatus === "generated") cost += 0.05;
|
|
474462
475444
|
if (outcome.backdropStatus === "generated") cost += backdropCostUsd(imageQuality);
|
|
474463
|
-
if (outcome.
|
|
475445
|
+
if (outcome.keyframeStatus === "generated") cost += backdropCostUsd(imageQuality);
|
|
475446
|
+
if (outcome.videoStatus === "generated" || outcome.videoStatus === "pending") {
|
|
475447
|
+
cost += outcome.videoProvider === "seedance" || outcome.videoProvider === "fal" ? estimateSeedanceVideoCostUsd({
|
|
475448
|
+
durationSec: normalizeVideoDuration(outcome.sceneDurationSec),
|
|
475449
|
+
resolution: "720p",
|
|
475450
|
+
aspectRatio: "16:9"
|
|
475451
|
+
}) : 5;
|
|
475452
|
+
}
|
|
474464
475453
|
if (outcome.musicStatus === "generated" || outcome.musicStatus === "pending") cost += 0.5;
|
|
474465
475454
|
}
|
|
474466
475455
|
return Number(cost.toFixed(2));
|
|
@@ -474525,7 +475514,7 @@ function mergeBeatOutcomes(base, updates) {
|
|
|
474525
475514
|
}
|
|
474526
475515
|
function firstExisting3(projectDir, relPaths) {
|
|
474527
475516
|
for (const rel of relPaths) {
|
|
474528
|
-
if (existsSync35(
|
|
475517
|
+
if (existsSync35(join31(projectDir, rel))) return rel;
|
|
474529
475518
|
}
|
|
474530
475519
|
return null;
|
|
474531
475520
|
}
|
|
@@ -474556,7 +475545,7 @@ async function apiKeyForVideoProvider(provider, projectDir) {
|
|
|
474556
475545
|
return getApiKeyFromConfig(providerKey, { cwd: projectDir });
|
|
474557
475546
|
}
|
|
474558
475547
|
async function finalizeBuildResult(projectDir, startedAt, result) {
|
|
474559
|
-
const reportPath =
|
|
475548
|
+
const reportPath = join31(projectDir, "build-report.json");
|
|
474560
475549
|
if (result.stageReports) {
|
|
474561
475550
|
for (const report of Object.values(result.stageReports)) {
|
|
474562
475551
|
if (report.status === "pending") report.status = "skipped";
|
|
@@ -474715,7 +475704,7 @@ function normalizeReportDuration(value) {
|
|
|
474715
475704
|
}
|
|
474716
475705
|
function buildReportComposition(projectDir, result, beatId) {
|
|
474717
475706
|
const path14 = `compositions/scene-${beatId}.html`;
|
|
474718
|
-
const exists = existsSync35(
|
|
475707
|
+
const exists = existsSync35(join31(projectDir, path14));
|
|
474719
475708
|
const written = composeWrittenEntry(result, beatId);
|
|
474720
475709
|
if (written) {
|
|
474721
475710
|
return {
|
|
@@ -474772,7 +475761,7 @@ function summarizeBuildBeats(projectDir, beats) {
|
|
|
474772
475761
|
let compositionsReady = 0;
|
|
474773
475762
|
for (const beat of beats) {
|
|
474774
475763
|
if (beatAssetsReady(beat)) assetsReady += 1;
|
|
474775
|
-
const compositionPath =
|
|
475764
|
+
const compositionPath = join31(projectDir, "compositions", `scene-${beat.beatId}.html`);
|
|
474776
475765
|
if (existsSync35(compositionPath)) {
|
|
474777
475766
|
compositionsReady += 1;
|
|
474778
475767
|
} else {
|
|
@@ -475428,7 +476417,7 @@ var init_silence_cut = __esm({
|
|
|
475428
476417
|
// ../cli/src/commands/_shared/edit/jump-cut.ts
|
|
475429
476418
|
import { existsSync as existsSync38 } from "node:fs";
|
|
475430
476419
|
import { readFile as readFile21, writeFile as writeFile22, mkdir as mkdir14 } from "node:fs/promises";
|
|
475431
|
-
import { join as
|
|
476420
|
+
import { join as join33 } from "node:path";
|
|
475432
476421
|
async function transcribeWithWords(audioPath, apiKey, language) {
|
|
475433
476422
|
const audioBuffer = await readFile21(audioPath);
|
|
475434
476423
|
const audioBlob = new Blob([audioBuffer]);
|
|
@@ -475508,7 +476497,7 @@ async function executeJumpCut(options) {
|
|
|
475508
476497
|
try {
|
|
475509
476498
|
const tmpDir = `/tmp/vibe_jumpcut_${Date.now()}`;
|
|
475510
476499
|
await mkdir14(tmpDir, { recursive: true });
|
|
475511
|
-
const audioPath =
|
|
476500
|
+
const audioPath = join33(tmpDir, "audio.wav");
|
|
475512
476501
|
try {
|
|
475513
476502
|
await execSafe(
|
|
475514
476503
|
"ffmpeg",
|
|
@@ -475562,7 +476551,7 @@ async function executeJumpCut(options) {
|
|
|
475562
476551
|
const segmentPaths = [];
|
|
475563
476552
|
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
475564
476553
|
const seg = segments[i2];
|
|
475565
|
-
const segPath =
|
|
476554
|
+
const segPath = join33(tmpDir, `seg-${i2.toString().padStart(4, "0")}.ts`);
|
|
475566
476555
|
const duration = seg.end - seg.start;
|
|
475567
476556
|
await execSafe(
|
|
475568
476557
|
"ffmpeg",
|
|
@@ -475585,7 +476574,7 @@ async function executeJumpCut(options) {
|
|
|
475585
476574
|
segmentPaths.push(segPath);
|
|
475586
476575
|
}
|
|
475587
476576
|
const concatList = segmentPaths.map((p2) => `file '${p2}'`).join("\n");
|
|
475588
|
-
const listPath =
|
|
476577
|
+
const listPath = join33(tmpDir, "concat.txt");
|
|
475589
476578
|
await writeFile22(listPath, concatList);
|
|
475590
476579
|
await execSafe(
|
|
475591
476580
|
"ffmpeg",
|
|
@@ -475693,7 +476682,7 @@ __export(remotion_exports, {
|
|
|
475693
476682
|
});
|
|
475694
476683
|
import { writeFile as writeFile23, mkdir as mkdir15, rm as rm3, copyFile as copyFile5 } from "node:fs/promises";
|
|
475695
476684
|
import { existsSync as existsSync39 } from "node:fs";
|
|
475696
|
-
import { join as
|
|
476685
|
+
import { join as join34 } from "node:path";
|
|
475697
476686
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
475698
476687
|
import { createHash as createHash7 } from "node:crypto";
|
|
475699
476688
|
async function ensureRemotionInstalled() {
|
|
@@ -475712,7 +476701,7 @@ async function ensureRemotionInstalled() {
|
|
|
475712
476701
|
}
|
|
475713
476702
|
}
|
|
475714
476703
|
async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
475715
|
-
const dir =
|
|
476704
|
+
const dir = join34(tmpdir3(), `vibe_motion_${Date.now()}`);
|
|
475716
476705
|
await mkdir15(dir, { recursive: true });
|
|
475717
476706
|
const deps = {
|
|
475718
476707
|
remotion: REMOTION_VERSION,
|
|
@@ -475731,7 +476720,7 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
475731
476720
|
dependencies: deps
|
|
475732
476721
|
};
|
|
475733
476722
|
const packageJsonStr = JSON.stringify(packageJson, null, 2);
|
|
475734
|
-
await writeFile23(
|
|
476723
|
+
await writeFile23(join34(dir, "package.json"), packageJsonStr);
|
|
475735
476724
|
const tsconfig = {
|
|
475736
476725
|
compilerOptions: {
|
|
475737
476726
|
target: "ES2020",
|
|
@@ -475743,8 +476732,8 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
475743
476732
|
skipLibCheck: true
|
|
475744
476733
|
}
|
|
475745
476734
|
};
|
|
475746
|
-
await writeFile23(
|
|
475747
|
-
await writeFile23(
|
|
476735
|
+
await writeFile23(join34(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
476736
|
+
await writeFile23(join34(dir, "Component.tsx"), componentCode);
|
|
475748
476737
|
const rootCode = `import { registerRoot, Composition } from "remotion";
|
|
475749
476738
|
import { ${componentName} } from "./Component";
|
|
475750
476739
|
|
|
@@ -475763,14 +476752,14 @@ const Root = () => {
|
|
|
475763
476752
|
|
|
475764
476753
|
registerRoot(Root);
|
|
475765
476754
|
`;
|
|
475766
|
-
await writeFile23(
|
|
476755
|
+
await writeFile23(join34(dir, "Root.tsx"), rootCode);
|
|
475767
476756
|
const depsHash = createHash7("md5").update(packageJsonStr).digest("hex").slice(0, 12);
|
|
475768
|
-
const cacheMarker =
|
|
475769
|
-
const cachedModules =
|
|
476757
|
+
const cacheMarker = join34(REMOTION_CACHE_DIR, `.deps-${depsHash}`);
|
|
476758
|
+
const cachedModules = join34(REMOTION_CACHE_DIR, "node_modules");
|
|
475770
476759
|
if (existsSync39(cacheMarker) && existsSync39(cachedModules)) {
|
|
475771
476760
|
const { symlink } = await import("node:fs/promises");
|
|
475772
476761
|
try {
|
|
475773
|
-
await symlink(cachedModules,
|
|
476762
|
+
await symlink(cachedModules, join34(dir, "node_modules"), "dir");
|
|
475774
476763
|
} catch {
|
|
475775
476764
|
await this_npmInstall(dir);
|
|
475776
476765
|
}
|
|
@@ -475778,12 +476767,12 @@ registerRoot(Root);
|
|
|
475778
476767
|
await this_npmInstall(dir);
|
|
475779
476768
|
try {
|
|
475780
476769
|
await mkdir15(REMOTION_CACHE_DIR, { recursive: true });
|
|
475781
|
-
await writeFile23(
|
|
475782
|
-
if (existsSync39(
|
|
476770
|
+
await writeFile23(join34(REMOTION_CACHE_DIR, "package.json"), packageJsonStr);
|
|
476771
|
+
if (existsSync39(join34(dir, "node_modules"))) {
|
|
475783
476772
|
const { rename: rename7, symlink } = await import("node:fs/promises");
|
|
475784
|
-
await rename7(
|
|
476773
|
+
await rename7(join34(dir, "node_modules"), cachedModules).catch(() => {
|
|
475785
476774
|
});
|
|
475786
|
-
await symlink(cachedModules,
|
|
476775
|
+
await symlink(cachedModules, join34(dir, "node_modules"), "dir").catch(() => {
|
|
475787
476776
|
});
|
|
475788
476777
|
await writeFile23(cacheMarker, depsHash);
|
|
475789
476778
|
}
|
|
@@ -475820,7 +476809,7 @@ async function renderMotion(options) {
|
|
|
475820
476809
|
}
|
|
475821
476810
|
);
|
|
475822
476811
|
try {
|
|
475823
|
-
const entryPoint =
|
|
476812
|
+
const entryPoint = join34(dir, "Root.tsx");
|
|
475824
476813
|
const { execFile: execFile3 } = await import("node:child_process");
|
|
475825
476814
|
const { promisify: promisify3 } = await import("node:util");
|
|
475826
476815
|
const execFileAsync3 = promisify3(execFile3);
|
|
@@ -475953,10 +476942,10 @@ async function renderWithEmbeddedImage(options) {
|
|
|
475953
476942
|
}
|
|
475954
476943
|
);
|
|
475955
476944
|
try {
|
|
475956
|
-
const publicDir =
|
|
476945
|
+
const publicDir = join34(dir, "public");
|
|
475957
476946
|
await mkdir15(publicDir, { recursive: true });
|
|
475958
|
-
await copyFile5(options.imagePath,
|
|
475959
|
-
const entryPoint =
|
|
476947
|
+
await copyFile5(options.imagePath, join34(publicDir, options.imageFileName));
|
|
476948
|
+
const entryPoint = join34(dir, "Root.tsx");
|
|
475960
476949
|
const mp4Out = options.outputPath.replace(/\.\w+$/, ".mp4");
|
|
475961
476950
|
const { execFile: execFileImg } = await import("node:child_process");
|
|
475962
476951
|
const { promisify: promisifyImg } = await import("node:util");
|
|
@@ -476017,10 +477006,10 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
476017
477006
|
}
|
|
476018
477007
|
);
|
|
476019
477008
|
try {
|
|
476020
|
-
const publicDir =
|
|
477009
|
+
const publicDir = join34(dir, "public");
|
|
476021
477010
|
await mkdir15(publicDir, { recursive: true });
|
|
476022
|
-
await copyFile5(options.videoPath,
|
|
476023
|
-
const entryPoint =
|
|
477011
|
+
await copyFile5(options.videoPath, join34(publicDir, options.videoFileName));
|
|
477012
|
+
const entryPoint = join34(dir, "Root.tsx");
|
|
476024
477013
|
const mp4VideoOnly = options.outputPath.replace(/\.\w+$/, "_video_only.mp4");
|
|
476025
477014
|
const { execFile: execFileVid } = await import("node:child_process");
|
|
476026
477015
|
const { promisify: promisifyVid } = await import("node:util");
|
|
@@ -476436,14 +477425,14 @@ var init_remotion = __esm({
|
|
|
476436
477425
|
"use strict";
|
|
476437
477426
|
init_exec_safe();
|
|
476438
477427
|
REMOTION_VERSION = "4.0.447";
|
|
476439
|
-
REMOTION_CACHE_DIR =
|
|
477428
|
+
REMOTION_CACHE_DIR = join34(tmpdir3(), "vibe_remotion_cache");
|
|
476440
477429
|
}
|
|
476441
477430
|
});
|
|
476442
477431
|
|
|
476443
477432
|
// ../cli/src/commands/_shared/edit/caption.ts
|
|
476444
477433
|
import { existsSync as existsSync40 } from "node:fs";
|
|
476445
477434
|
import { readFile as readFile22, writeFile as writeFile24, mkdir as mkdir16 } from "node:fs/promises";
|
|
476446
|
-
import { dirname as dirname20, basename as basename9, extname as extname7, join as
|
|
477435
|
+
import { dirname as dirname20, basename as basename9, extname as extname7, join as join35 } from "node:path";
|
|
476447
477436
|
function getCaptionForceStyle(style, fontSize, fontColor, position) {
|
|
476448
477437
|
const alignment = position === "top" ? 8 : position === "center" ? 5 : 2;
|
|
476449
477438
|
const marginV = position === "center" ? 0 : 30;
|
|
@@ -476490,8 +477479,8 @@ async function executeCaption(options) {
|
|
|
476490
477479
|
try {
|
|
476491
477480
|
const tmpDir = `/tmp/vibe_caption_${Date.now()}`;
|
|
476492
477481
|
await mkdir16(tmpDir, { recursive: true });
|
|
476493
|
-
const audioPath =
|
|
476494
|
-
const srtPath =
|
|
477482
|
+
const audioPath = join35(tmpDir, "audio.wav");
|
|
477483
|
+
const srtPath = join35(tmpDir, "captions.srt");
|
|
476495
477484
|
try {
|
|
476496
477485
|
await execSafe(
|
|
476497
477486
|
"ffmpeg",
|
|
@@ -476560,7 +477549,7 @@ async function executeCaption(options) {
|
|
|
476560
477549
|
const remotionErr = await ensureRemotionInstalled2();
|
|
476561
477550
|
if (remotionErr) {
|
|
476562
477551
|
const outputDir2 = dirname20(outputPath);
|
|
476563
|
-
const outputSrtPath2 =
|
|
477552
|
+
const outputSrtPath2 = join35(
|
|
476564
477553
|
outputDir2,
|
|
476565
477554
|
basename9(outputPath, extname7(outputPath)) + ".srt"
|
|
476566
477555
|
);
|
|
@@ -476599,7 +477588,7 @@ SRT saved to: ${outputSrtPath2}` };
|
|
|
476599
477588
|
});
|
|
476600
477589
|
if (!renderResult.success) {
|
|
476601
477590
|
const outputDir2 = dirname20(outputPath);
|
|
476602
|
-
const outputSrtPath2 =
|
|
477591
|
+
const outputSrtPath2 = join35(
|
|
476603
477592
|
outputDir2,
|
|
476604
477593
|
basename9(outputPath, extname7(outputPath)) + ".srt"
|
|
476605
477594
|
);
|
|
@@ -476612,7 +477601,7 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
476612
477601
|
}
|
|
476613
477602
|
}
|
|
476614
477603
|
const outputDir = dirname20(outputPath);
|
|
476615
|
-
const outputSrtPath =
|
|
477604
|
+
const outputSrtPath = join35(
|
|
476616
477605
|
outputDir,
|
|
476617
477606
|
basename9(outputPath, extname7(outputPath)) + ".srt"
|
|
476618
477607
|
);
|
|
@@ -484580,10 +485569,18 @@ Examples:
|
|
|
484580
485569
|
options.ratio = "16:9";
|
|
484581
485570
|
}
|
|
484582
485571
|
if (options.dryRun) {
|
|
485572
|
+
const costUsd = provider === "seedance" || provider === "fal" ? estimateSeedanceVideoCostUsd({
|
|
485573
|
+
durationSec: Number(options.duration) || 5,
|
|
485574
|
+
resolution: options.resolution,
|
|
485575
|
+
aspectRatio: options.ratio,
|
|
485576
|
+
fast: options.seedanceModel === "fast",
|
|
485577
|
+
hasVideoReference: Boolean(options.refVideos)
|
|
485578
|
+
}) : void 0;
|
|
484583
485579
|
outputSuccess({
|
|
484584
485580
|
command: "generate video",
|
|
484585
485581
|
startedAt,
|
|
484586
485582
|
dryRun: true,
|
|
485583
|
+
costUsd,
|
|
484587
485584
|
data: {
|
|
484588
485585
|
params: {
|
|
484589
485586
|
prompt: prompt3,
|
|
@@ -487033,6 +488030,9 @@ function clean(text) {
|
|
|
487033
488030
|
function humanise(id) {
|
|
487034
488031
|
return id.split(/[-_]+/).filter(Boolean).map((w2) => w2.charAt(0).toUpperCase() + w2.slice(1)).join(" ");
|
|
487035
488032
|
}
|
|
488033
|
+
function sceneCompositionId(beatId) {
|
|
488034
|
+
return `scene-${beatId}`;
|
|
488035
|
+
}
|
|
487036
488036
|
function slugifySceneName(name) {
|
|
487037
488037
|
const normalised = name.normalize("NFKD").replace(/[̀-ͯ]/g, "");
|
|
487038
488038
|
const slug = normalised.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -487070,10 +488070,16 @@ function fitKineticFontSize(words) {
|
|
|
487070
488070
|
function kenBurnsTween(scope, dur, endScale = 1.08) {
|
|
487071
488071
|
return `tl.fromTo('${scope} .backdrop', { scale: 1.0 }, { scale: ${endScale}, duration: ${dur.toFixed(2)}, ease: 'none' }, 0);`;
|
|
487072
488072
|
}
|
|
488073
|
+
function backdropMotionTweens(scope, dur, hasImage, endScale = 1.08) {
|
|
488074
|
+
const sweep = hasImage ? "" : `
|
|
488075
|
+
tl.fromTo('${scope} .ambient-sweep', { xPercent: -75, opacity: 0.18 }, { xPercent: 75, opacity: 0.62, duration: ${dur.toFixed(2)}, ease: 'sine.inOut' }, 0);`;
|
|
488076
|
+
return `${kenBurnsTween(scope, dur, endScale)}${sweep}`;
|
|
488077
|
+
}
|
|
487073
488078
|
function buildPreset(input3) {
|
|
487074
488079
|
const id = input3.id;
|
|
487075
488080
|
const scope = `[data-composition-id="${id}"]`;
|
|
487076
|
-
const
|
|
488081
|
+
const displayId = input3.beatId ?? id;
|
|
488082
|
+
const headline = clean(input3.headline) || humanise(displayId);
|
|
487077
488083
|
const subhead = clean(input3.subhead);
|
|
487078
488084
|
const kicker = clean(input3.kicker);
|
|
487079
488085
|
const dur = input3.duration;
|
|
@@ -487096,8 +488102,17 @@ function buildPreset(input3) {
|
|
|
487096
488102
|
position: absolute;
|
|
487097
488103
|
inset: 0;
|
|
487098
488104
|
background: radial-gradient(ellipse at center, #1a1a2e 0%, #000 70%);
|
|
488105
|
+
overflow: hidden;
|
|
488106
|
+
}
|
|
488107
|
+
${scope} .ambient-sweep {
|
|
488108
|
+
position: absolute;
|
|
488109
|
+
inset: -22%;
|
|
488110
|
+
display: block;
|
|
488111
|
+
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%);
|
|
488112
|
+
filter: blur(12px);
|
|
488113
|
+
transform: rotate(8deg);
|
|
487099
488114
|
}`;
|
|
487100
|
-
const backdropMarkup = `<div class="backdrop"></div>`;
|
|
488115
|
+
const backdropMarkup = hasImage ? `<div class="backdrop"></div>` : `<div class="backdrop"><div class="ambient-sweep"></div></div>`;
|
|
487101
488116
|
switch (input3.preset) {
|
|
487102
488117
|
case "simple": {
|
|
487103
488118
|
const transcript = input3.transcript;
|
|
@@ -487129,7 +488144,7 @@ function buildPreset(input3) {
|
|
|
487129
488144
|
body: `${backdropMarkup}
|
|
487130
488145
|
<div class="caption" id="caption">${captionInner}</div>`,
|
|
487131
488146
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487132
|
-
${
|
|
488147
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
487133
488148
|
${captionTween}`
|
|
487134
488149
|
};
|
|
487135
488150
|
}
|
|
@@ -487168,12 +488183,12 @@ function buildPreset(input3) {
|
|
|
487168
488183
|
// scene's own fade-in handles the visual transition. Backdrop
|
|
487169
488184
|
// Ken-Burns fills what used to be 80% dead static frame.
|
|
487170
488185
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487171
|
-
${
|
|
488186
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
487172
488187
|
tl.from('${scope} #headline', { opacity: 0, scale: 0.92, duration: 0.55, ease: 'power3.out' }, 0.05);`
|
|
487173
488188
|
};
|
|
487174
488189
|
}
|
|
487175
488190
|
case "explainer": {
|
|
487176
|
-
const k2 = kicker || humanise(
|
|
488191
|
+
const k2 = kicker || humanise(displayId).toUpperCase();
|
|
487177
488192
|
const sub = subhead || "";
|
|
487178
488193
|
const transcript = input3.transcript;
|
|
487179
488194
|
const useWordSync = !!(transcript && transcript.length > 0 && sub);
|
|
@@ -487215,7 +488230,7 @@ function buildPreset(input3) {
|
|
|
487215
488230
|
<div class="subtitle" id="subtitle">${subtitleInner}</div>` : ""}
|
|
487216
488231
|
</div>`,
|
|
487217
488232
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487218
|
-
${
|
|
488233
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
487219
488234
|
tl.from('${scope} #kicker', { opacity: 0, y: 16, duration: 0.4, ease: 'power2.out' }, 0.1);
|
|
487220
488235
|
tl.from('${scope} #title', { opacity: 0, y: 60, duration: 0.7, ease: 'power3.out' }, 0.25);
|
|
487221
488236
|
${subtitleTween}`
|
|
@@ -487256,12 +488271,12 @@ function buildPreset(input3) {
|
|
|
487256
488271
|
body: `${backdropMarkup}
|
|
487257
488272
|
<div class="kinetic">${wordSpans}</div>`,
|
|
487258
488273
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487259
|
-
${
|
|
488274
|
+
${backdropMotionTweens(scope, dur, hasImage)}
|
|
487260
488275
|
${tweens}`
|
|
487261
488276
|
};
|
|
487262
488277
|
}
|
|
487263
488278
|
case "product-shot": {
|
|
487264
|
-
const label = kicker || humanise(
|
|
488279
|
+
const label = kicker || humanise(displayId);
|
|
487265
488280
|
const headlineFontPx = fitFontSize(headline, 72, 40, 50);
|
|
487266
488281
|
return {
|
|
487267
488282
|
css: `${scope} {
|
|
@@ -487295,7 +488310,7 @@ function buildPreset(input3) {
|
|
|
487295
488310
|
<div class="product-headline" id="headline">${esc(headline)}</div>${subhead ? `
|
|
487296
488311
|
<div class="product-sub" id="subhead">${esc(subhead)}</div>` : ""}`,
|
|
487297
488312
|
timeline: `${crossfadeTweens(scope, dur)}
|
|
487298
|
-
|
|
488313
|
+
${backdropMotionTweens(scope, dur, hasImage, 1.12)}
|
|
487299
488314
|
tl.from('${scope} #label', { opacity: 0, x: -30, duration: 0.5, ease: 'power3.out' }, 0.2);
|
|
487300
488315
|
tl.from('${scope} #headline', { opacity: 0, y: 40, duration: 0.6, ease: 'power3.out' }, 0.4);${subhead ? `
|
|
487301
488316
|
tl.from('${scope} #subhead', { opacity: 0, y: 20, duration: 0.5, ease: 'power3.out' }, 0.65);` : ""}`
|
|
@@ -487360,9 +488375,10 @@ function emitSceneHtml(input3) {
|
|
|
487360
488375
|
if (input3.width <= 0 || input3.height <= 0) {
|
|
487361
488376
|
throw new Error(`Invalid canvas dims: ${input3.width}x${input3.height}`);
|
|
487362
488377
|
}
|
|
487363
|
-
const
|
|
488378
|
+
const beatId = input3.id;
|
|
488379
|
+
const id = sceneCompositionId(beatId);
|
|
487364
488380
|
const dur = Number(input3.duration.toFixed(3));
|
|
487365
|
-
const parts = buildPreset({ ...input3, id, duration: dur });
|
|
488381
|
+
const parts = buildPreset({ ...input3, id, beatId, duration: dur });
|
|
487366
488382
|
const audioBlock = input3.audioPath ? `
|
|
487367
488383
|
<audio
|
|
487368
488384
|
id="narration"
|
|
@@ -487378,7 +488394,7 @@ function emitSceneHtml(input3) {
|
|
|
487378
488394
|
${lottieLayer.markup}` : "";
|
|
487379
488395
|
const lottieScript = lottieLayer ? `
|
|
487380
488396
|
${lottieLayer.script}` : "";
|
|
487381
|
-
return `<template id="
|
|
488397
|
+
return `<template id="${id}-template">
|
|
487382
488398
|
<div data-composition-id="${id}" data-start="0" data-duration="${dur}" data-width="${input3.width}" data-height="${input3.height}">
|
|
487383
488399
|
<style>
|
|
487384
488400
|
${parts.css}
|
|
@@ -487414,8 +488430,9 @@ function buildClipReference(opts) {
|
|
|
487414
488430
|
const duration = Number(opts.duration.toFixed(3));
|
|
487415
488431
|
const track = opts.trackIndex ?? 1;
|
|
487416
488432
|
const src = opts.src ?? `compositions/scene-${opts.id}.html`;
|
|
488433
|
+
const compositionId = sceneCompositionId(opts.id);
|
|
487417
488434
|
const zIndex = Math.max(1, 1e6 - Math.floor(start * 1e3));
|
|
487418
|
-
return `<div class="clip" data-composition-id="${esc(
|
|
488435
|
+
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>`;
|
|
487419
488436
|
}
|
|
487420
488437
|
function insertClipIntoRoot(rootHtml, clip) {
|
|
487421
488438
|
const clipDiv = buildClipReference(clip);
|
|
@@ -487459,9 +488476,9 @@ init_agent_host_detect();
|
|
|
487459
488476
|
// ../cli/src/commands/_shared/install-skill.ts
|
|
487460
488477
|
init_bundle_content();
|
|
487461
488478
|
init_bundle();
|
|
487462
|
-
import { mkdir as mkdir8, writeFile as
|
|
488479
|
+
import { mkdir as mkdir8, writeFile as writeFile12 } from "node:fs/promises";
|
|
487463
488480
|
import { existsSync as existsSync21 } from "node:fs";
|
|
487464
|
-
import { dirname as dirname12, join as join21, relative as relative5, resolve as
|
|
488481
|
+
import { dirname as dirname12, join as join21, relative as relative5, resolve as resolve16 } from "node:path";
|
|
487465
488482
|
function universalFiles() {
|
|
487466
488483
|
return [
|
|
487467
488484
|
{ relPath: "SKILL.md", content: SKILL_MD },
|
|
@@ -487511,7 +488528,7 @@ function selectHostFiles(hosts) {
|
|
|
487511
488528
|
return out;
|
|
487512
488529
|
}
|
|
487513
488530
|
async function installHyperframesSkill(opts) {
|
|
487514
|
-
const projectDir =
|
|
488531
|
+
const projectDir = resolve16(opts.projectDir);
|
|
487515
488532
|
const force = opts.force ?? false;
|
|
487516
488533
|
const dryRun = opts.dryRun ?? false;
|
|
487517
488534
|
const files = [...universalFiles(), ...selectHostFiles(opts.hosts)];
|
|
@@ -487536,7 +488553,7 @@ async function installHyperframesSkill(opts) {
|
|
|
487536
488553
|
continue;
|
|
487537
488554
|
}
|
|
487538
488555
|
await mkdir8(dirname12(absPath), { recursive: true });
|
|
487539
|
-
await
|
|
488556
|
+
await writeFile12(absPath, file.content, "utf-8");
|
|
487540
488557
|
actions.push({ path: file.relPath, status: "wrote", bytes });
|
|
487541
488558
|
}
|
|
487542
488559
|
return {
|
|
@@ -487561,10 +488578,10 @@ init_scene_lint();
|
|
|
487561
488578
|
init_storyboard_parse();
|
|
487562
488579
|
init_root_sync();
|
|
487563
488580
|
import { existsSync as existsSync26 } from "node:fs";
|
|
487564
|
-
import { mkdir as mkdir10, readFile as readFile11, writeFile as
|
|
487565
|
-
import { join as join26, resolve as
|
|
488581
|
+
import { mkdir as mkdir10, readFile as readFile11, writeFile as writeFile15 } from "node:fs/promises";
|
|
488582
|
+
import { join as join26, resolve as resolve20 } from "node:path";
|
|
487566
488583
|
async function executeSceneSubmit(opts) {
|
|
487567
|
-
const projectDir =
|
|
488584
|
+
const projectDir = resolve20(opts.projectDir);
|
|
487568
488585
|
const beatId = opts.beatId.trim();
|
|
487569
488586
|
const scenePath = `compositions/scene-${beatId}.html`;
|
|
487570
488587
|
const base = {
|
|
@@ -487656,7 +488673,7 @@ async function executeSceneSubmit(opts) {
|
|
|
487656
488673
|
}
|
|
487657
488674
|
const absPath = join26(projectDir, scenePath);
|
|
487658
488675
|
await mkdir10(join26(projectDir, "compositions"), { recursive: true });
|
|
487659
|
-
await
|
|
488676
|
+
await writeFile15(absPath, html.endsWith("\n") ? html : `${html}
|
|
487660
488677
|
`, "utf-8");
|
|
487661
488678
|
return {
|
|
487662
488679
|
...base,
|
|
@@ -487671,6 +488688,8 @@ async function executeSceneSubmit(opts) {
|
|
|
487671
488688
|
|
|
487672
488689
|
// ../cli/src/commands/scene.ts
|
|
487673
488690
|
init_scene_repair();
|
|
488691
|
+
init_root_sync();
|
|
488692
|
+
init_storyboard_edit();
|
|
487674
488693
|
function validateDuration(value) {
|
|
487675
488694
|
const n2 = parseFloat(value);
|
|
487676
488695
|
if (!Number.isFinite(n2) || n2 <= 0 || n2 > 3600) {
|
|
@@ -487973,7 +488992,10 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
487973
488992
|
).option("-d, --duration <sec>", "Explicit scene duration in seconds (overrides narration audio)").option(
|
|
487974
488993
|
"--visuals <prompt>",
|
|
487975
488994
|
"Image prompt \u2014 generates assets/scene-<id>.png via the configured image provider"
|
|
487976
|
-
).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(
|
|
488995
|
+
).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(
|
|
488996
|
+
"--no-storyboard",
|
|
488997
|
+
"Do not sync STORYBOARD.md; insert this scene directly into the root composition only"
|
|
488998
|
+
).option("--image-provider <name>", "Image provider: gemini, openai", "gemini").option(
|
|
487977
488999
|
"--tts <provider>",
|
|
487978
489000
|
"TTS provider: auto, elevenlabs, openai, kokoro (default auto \u2014 ElevenLabs key > OpenAI key > Kokoro local)",
|
|
487979
489001
|
"auto"
|
|
@@ -488042,6 +489064,7 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
488042
489064
|
kicker: options.kicker,
|
|
488043
489065
|
project: options.project,
|
|
488044
489066
|
insertInto: options.insertInto,
|
|
489067
|
+
syncStoryboard: options.storyboard !== false,
|
|
488045
489068
|
imageProvider: options.imageProvider,
|
|
488046
489069
|
tts,
|
|
488047
489070
|
audio: options.audio,
|
|
@@ -488069,6 +489092,7 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
488069
489092
|
kicker: options.kicker,
|
|
488070
489093
|
projectDir: options.project,
|
|
488071
489094
|
insertInto: options.insertInto,
|
|
489095
|
+
syncStoryboard: options.storyboard !== false,
|
|
488072
489096
|
imageProvider: options.imageProvider,
|
|
488073
489097
|
tts,
|
|
488074
489098
|
voice: options.voice,
|
|
@@ -488108,6 +489132,13 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
488108
489132
|
if (result.audioPath) console.log(source_default.green(" +"), result.audioPath);
|
|
488109
489133
|
if (result.imagePath) console.log(source_default.green(" +"), result.imagePath);
|
|
488110
489134
|
if (result.transcriptPath) console.log(source_default.green(" +"), result.transcriptPath);
|
|
489135
|
+
if (result.storyboardPath && result.storyboardSynced) {
|
|
489136
|
+
console.log(
|
|
489137
|
+
result.storyboardAction === "updated" ? source_default.yellow(" ~") : source_default.green(" +"),
|
|
489138
|
+
result.storyboardPath,
|
|
489139
|
+
source_default.dim(`(${result.storyboardAction})`)
|
|
489140
|
+
);
|
|
489141
|
+
}
|
|
488111
489142
|
console.log(source_default.yellow(" ~"), result.rootPath, source_default.dim("(updated)"));
|
|
488112
489143
|
console.log();
|
|
488113
489144
|
console.log(source_default.bold.cyan("Composition"));
|
|
@@ -488154,6 +489185,21 @@ async function loadVibeProjectConfig(projectDir) {
|
|
|
488154
489185
|
}
|
|
488155
489186
|
};
|
|
488156
489187
|
}
|
|
489188
|
+
function escapeRegExp3(value) {
|
|
489189
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
489190
|
+
}
|
|
489191
|
+
function readClipStart(rootHtml, beatId) {
|
|
489192
|
+
const compositionId = sceneCompositionId(beatId);
|
|
489193
|
+
const match2 = rootHtml.match(
|
|
489194
|
+
new RegExp(
|
|
489195
|
+
`<div\\s+class="clip"[^>]*\\bdata-composition-id="${escapeRegExp3(compositionId)}"[^>]*\\bdata-start="([\\d.]+)"`,
|
|
489196
|
+
"i"
|
|
489197
|
+
)
|
|
489198
|
+
);
|
|
489199
|
+
if (!match2) return void 0;
|
|
489200
|
+
const start = Number.parseFloat(match2[1]);
|
|
489201
|
+
return Number.isFinite(start) ? start : void 0;
|
|
489202
|
+
}
|
|
488157
489203
|
async function resolveNarrationText(value) {
|
|
488158
489204
|
if (!value) return void 0;
|
|
488159
489205
|
const looksLikePath = /\.[a-z]{2,4}$/i.test(value) || value.includes("/") || value.includes("\\");
|
|
@@ -488180,6 +489226,7 @@ async function executeSceneAdd(opts) {
|
|
|
488180
489226
|
const id = slugifySceneName(opts.name);
|
|
488181
489227
|
const sceneRel = `compositions/scene-${id}.html`;
|
|
488182
489228
|
const scenePath = resolve24(projectDir, sceneRel);
|
|
489229
|
+
const storyboardAbsPath = resolve24(projectDir, "STORYBOARD.md");
|
|
488183
489230
|
const errResult = (error) => ({
|
|
488184
489231
|
success: false,
|
|
488185
489232
|
id,
|
|
@@ -488399,6 +489446,27 @@ async function executeSceneAdd(opts) {
|
|
|
488399
489446
|
duration = fallback2;
|
|
488400
489447
|
}
|
|
488401
489448
|
duration = Number(duration.toFixed(2));
|
|
489449
|
+
let storyboardPath;
|
|
489450
|
+
let storyboardSynced = false;
|
|
489451
|
+
let storyboardAction = "skipped";
|
|
489452
|
+
const shouldSyncStoryboard = opts.syncStoryboard !== false && await pathExists2(storyboardAbsPath);
|
|
489453
|
+
if (shouldSyncStoryboard) {
|
|
489454
|
+
opts.onProgress?.("Syncing STORYBOARD.md...");
|
|
489455
|
+
const before2 = await readFile14(storyboardAbsPath, "utf-8");
|
|
489456
|
+
const synced = upsertStoryboardBeat(before2, {
|
|
489457
|
+
beatId: id,
|
|
489458
|
+
title: opts.headline,
|
|
489459
|
+
duration,
|
|
489460
|
+
narration: narrationText && !opts.skipAudio ? narrationText : void 0,
|
|
489461
|
+
backdrop: opts.visuals && !opts.skipImage ? opts.visuals : void 0
|
|
489462
|
+
});
|
|
489463
|
+
if (synced.markdown !== before2) {
|
|
489464
|
+
await writeFile17(storyboardAbsPath, synced.markdown, "utf-8");
|
|
489465
|
+
}
|
|
489466
|
+
storyboardPath = relative8(process.cwd(), storyboardAbsPath) || storyboardAbsPath;
|
|
489467
|
+
storyboardSynced = true;
|
|
489468
|
+
storyboardAction = synced.action;
|
|
489469
|
+
}
|
|
488402
489470
|
opts.onProgress?.("Emitting scene HTML...");
|
|
488403
489471
|
const sceneHtml = emitSceneHtml({
|
|
488404
489472
|
id,
|
|
@@ -488417,11 +489485,24 @@ async function executeSceneAdd(opts) {
|
|
|
488417
489485
|
await mkdir11(dirname14(scenePath), { recursive: true });
|
|
488418
489486
|
await writeFile17(scenePath, sceneHtml, "utf-8");
|
|
488419
489487
|
opts.onProgress?.("Updating root composition...");
|
|
488420
|
-
|
|
488421
|
-
|
|
488422
|
-
|
|
488423
|
-
|
|
488424
|
-
|
|
489488
|
+
let start = 0;
|
|
489489
|
+
if (storyboardSynced) {
|
|
489490
|
+
const syncPlan = await syncRootComposition({
|
|
489491
|
+
projectDir,
|
|
489492
|
+
rootRel,
|
|
489493
|
+
beats: await loadProjectRootSyncBeats(projectDir)
|
|
489494
|
+
});
|
|
489495
|
+
const blockingIssue = syncPlan.issues.find((issue) => issue.severity === "error");
|
|
489496
|
+
if (blockingIssue) return errResult(blockingIssue.message);
|
|
489497
|
+
const rootHtmlAfterSync = await readFile14(rootPath, "utf-8");
|
|
489498
|
+
start = readClipStart(rootHtmlAfterSync, id) ?? 0;
|
|
489499
|
+
} else {
|
|
489500
|
+
start = nextSceneStart(rootHtmlBefore, SCENE_OVERLAP_SECONDS);
|
|
489501
|
+
const existingClipCount = (rootHtmlBefore.match(/<div\s+class="clip"/g) || []).length;
|
|
489502
|
+
const trackIndex = existingClipCount % 2 + 1;
|
|
489503
|
+
const updated = insertClipIntoRoot(rootHtmlBefore, { id, start, duration, trackIndex });
|
|
489504
|
+
await writeFile17(rootPath, updated, "utf-8");
|
|
489505
|
+
}
|
|
488425
489506
|
const transcriptAbsPath = transcriptRelPath ? resolve24(projectDir, transcriptRelPath) : void 0;
|
|
488426
489507
|
return {
|
|
488427
489508
|
success: true,
|
|
@@ -488434,6 +489515,9 @@ async function executeSceneAdd(opts) {
|
|
|
488434
489515
|
audioPath: audioAbsPath ? relative8(process.cwd(), audioAbsPath) || audioAbsPath : void 0,
|
|
488435
489516
|
imagePath: imageAbsPath ? relative8(process.cwd(), imageAbsPath) || imageAbsPath : void 0,
|
|
488436
489517
|
lottiePath: lottieAbsPath ? relative8(process.cwd(), lottieAbsPath) || lottieAbsPath : void 0,
|
|
489518
|
+
storyboardPath,
|
|
489519
|
+
storyboardSynced,
|
|
489520
|
+
storyboardAction,
|
|
488437
489521
|
transcriptPath: transcriptAbsPath ? relative8(process.cwd(), transcriptAbsPath) || transcriptAbsPath : void 0,
|
|
488438
489522
|
transcriptWordCount
|
|
488439
489523
|
};
|
|
@@ -488731,6 +489815,9 @@ var sceneAddSchema = z2.object({
|
|
|
488731
489815
|
kicker: z2.string().optional().describe("Small label above the headline (used by 'explainer' and 'product-shot' presets)."),
|
|
488732
489816
|
projectDir: z2.string().optional().describe(PROJECT_DIR_DESCRIPTION),
|
|
488733
489817
|
insertInto: z2.string().optional().describe("Root composition file (relative to projectDir). Default 'index.html'."),
|
|
489818
|
+
syncStoryboard: z2.boolean().optional().describe(
|
|
489819
|
+
"Sync STORYBOARD.md when present, then rebuild root refs from it. Default true; set false for root-only insertion."
|
|
489820
|
+
),
|
|
488734
489821
|
imageProvider: z2.enum(["gemini", "openai"]).optional().describe("Image provider for visuals. Default 'gemini'."),
|
|
488735
489822
|
voice: z2.string().optional().describe("ElevenLabs voice id or name."),
|
|
488736
489823
|
skipAudio: z2.boolean().optional().describe("Skip TTS even if narration is provided."),
|
|
@@ -488743,7 +489830,7 @@ var sceneAddTool = defineTool({
|
|
|
488743
489830
|
cost: "low",
|
|
488744
489831
|
title: "Add Scene from Preset",
|
|
488745
489832
|
annotations: { readOnly: false, openWorld: true },
|
|
488746
|
-
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
|
|
489833
|
+
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.",
|
|
488747
489834
|
schema: sceneAddSchema,
|
|
488748
489835
|
async execute(args, ctx) {
|
|
488749
489836
|
const projectDir = args.projectDir ? resolve34(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
@@ -488757,6 +489844,7 @@ var sceneAddTool = defineTool({
|
|
|
488757
489844
|
kicker: args.kicker,
|
|
488758
489845
|
projectDir,
|
|
488759
489846
|
insertInto: args.insertInto,
|
|
489847
|
+
syncStoryboard: args.syncStoryboard,
|
|
488760
489848
|
imageProvider: args.imageProvider,
|
|
488761
489849
|
voice: args.voice,
|
|
488762
489850
|
skipAudio: args.skipAudio,
|
|
@@ -488775,6 +489863,9 @@ var sceneAddTool = defineTool({
|
|
|
488775
489863
|
];
|
|
488776
489864
|
if (result.audioPath) lines.push(` audio: ${result.audioPath}`);
|
|
488777
489865
|
if (result.imagePath) lines.push(` image: ${result.imagePath}`);
|
|
489866
|
+
if (result.storyboardPath && result.storyboardSynced) {
|
|
489867
|
+
lines.push(` story: ${result.storyboardPath} (${result.storyboardAction})`);
|
|
489868
|
+
}
|
|
488778
489869
|
return {
|
|
488779
489870
|
success: true,
|
|
488780
489871
|
data: {
|
|
@@ -488785,7 +489876,10 @@ var sceneAddTool = defineTool({
|
|
|
488785
489876
|
scenePath: result.scenePath,
|
|
488786
489877
|
rootPath: result.rootPath,
|
|
488787
489878
|
audioPath: result.audioPath,
|
|
488788
|
-
imagePath: result.imagePath
|
|
489879
|
+
imagePath: result.imagePath,
|
|
489880
|
+
storyboardPath: result.storyboardPath,
|
|
489881
|
+
storyboardSynced: result.storyboardSynced,
|
|
489882
|
+
storyboardAction: result.storyboardAction
|
|
488789
489883
|
},
|
|
488790
489884
|
humanLines: lines
|
|
488791
489885
|
};
|
|
@@ -490220,7 +491314,7 @@ init_root_sync();
|
|
|
490220
491314
|
init_review_report();
|
|
490221
491315
|
import { existsSync as existsSync56 } from "node:fs";
|
|
490222
491316
|
import { readdir as readdir6, readFile as readFile31, stat as stat5 } from "node:fs/promises";
|
|
490223
|
-
import { basename as basename14, isAbsolute as isAbsolute7, join as
|
|
491317
|
+
import { basename as basename14, isAbsolute as isAbsolute7, join as join37, relative as relative13, resolve as resolve50 } from "node:path";
|
|
490224
491318
|
async function inspectProject(opts) {
|
|
490225
491319
|
const projectDir = resolve50(opts.projectDir);
|
|
490226
491320
|
const issues = [];
|
|
@@ -490249,12 +491343,12 @@ async function inspectProject(opts) {
|
|
|
490249
491343
|
);
|
|
490250
491344
|
}
|
|
490251
491345
|
const coreFiles = {
|
|
490252
|
-
storyboard:
|
|
490253
|
-
design:
|
|
490254
|
-
config:
|
|
490255
|
-
legacyConfig:
|
|
490256
|
-
buildReport:
|
|
490257
|
-
root:
|
|
491346
|
+
storyboard: join37(projectDir, "STORYBOARD.md"),
|
|
491347
|
+
design: join37(projectDir, "DESIGN.md"),
|
|
491348
|
+
config: join37(projectDir, "vibe.config.json"),
|
|
491349
|
+
legacyConfig: join37(projectDir, "vibe.project.yaml"),
|
|
491350
|
+
buildReport: join37(projectDir, "build-report.json"),
|
|
491351
|
+
root: join37(projectDir, "index.html")
|
|
490258
491352
|
};
|
|
490259
491353
|
for (const [name, path14] of Object.entries(coreFiles)) {
|
|
490260
491354
|
checks.files[name] = existsSync56(path14);
|
|
@@ -490338,7 +491432,7 @@ async function inspectProject(opts) {
|
|
|
490338
491432
|
});
|
|
490339
491433
|
retryWith.push(`vibe build ${projectDir} --stage sync --json`);
|
|
490340
491434
|
}
|
|
490341
|
-
const compositionsDir =
|
|
491435
|
+
const compositionsDir = join37(projectDir, "compositions");
|
|
490342
491436
|
const existingComps = existsSync56(compositionsDir) ? new Set(await listHtmlBasenames(compositionsDir)) : /* @__PURE__ */ new Set();
|
|
490343
491437
|
checks.compositions.expected = inspectedBeatIds.length;
|
|
490344
491438
|
for (const beatId of inspectedBeatIds) {
|
|
@@ -490346,12 +491440,12 @@ async function inspectProject(opts) {
|
|
|
490346
491440
|
if (existingComps.has(file)) {
|
|
490347
491441
|
checks.compositions.found++;
|
|
490348
491442
|
} else {
|
|
490349
|
-
checks.compositions.missing.push(
|
|
491443
|
+
checks.compositions.missing.push(join37("compositions", file));
|
|
490350
491444
|
issues.push({
|
|
490351
491445
|
severity: "error",
|
|
490352
491446
|
code: "MISSING_COMPOSITION",
|
|
490353
491447
|
message: `Composition for beat "${beatId}" is missing.`,
|
|
490354
|
-
file:
|
|
491448
|
+
file: join37("compositions", file),
|
|
490355
491449
|
scene: beatId,
|
|
490356
491450
|
beatId,
|
|
490357
491451
|
suggestedFix: "Run `vibe build --stage compose --json`."
|
|
@@ -490413,7 +491507,7 @@ async function inspectProject(opts) {
|
|
|
490413
491507
|
try {
|
|
490414
491508
|
const lint = await runProjectLint({ projectDir });
|
|
490415
491509
|
const lintFiles = opts.beatId ? lint.files.filter(
|
|
490416
|
-
(file) => file.file === "index.html" || file.file ===
|
|
491510
|
+
(file) => file.file === "index.html" || file.file === join37("compositions", `scene-${opts.beatId}.html`)
|
|
490417
491511
|
) : lint.files;
|
|
490418
491512
|
const lintCounts = countLintFindings(lintFiles);
|
|
490419
491513
|
checks.lint = {
|
|
@@ -490449,7 +491543,11 @@ async function inspectProject(opts) {
|
|
|
490449
491543
|
);
|
|
490450
491544
|
}
|
|
490451
491545
|
function makeProjectResult(projectDir, issues, checks, retryWith, beatId) {
|
|
490452
|
-
const
|
|
491546
|
+
const normalizedRetryWith = uniqueRetryWith(retryWith);
|
|
491547
|
+
const normalizedIssues = normalizeReviewIssues(issues, {
|
|
491548
|
+
projectDir,
|
|
491549
|
+
retryWith: normalizedRetryWith
|
|
491550
|
+
});
|
|
490453
491551
|
const status = statusFromIssues(normalizedIssues);
|
|
490454
491552
|
return {
|
|
490455
491553
|
schemaVersion: "1",
|
|
@@ -490461,9 +491559,14 @@ function makeProjectResult(projectDir, issues, checks, retryWith, beatId) {
|
|
|
490461
491559
|
score: scoreIssues(normalizedIssues),
|
|
490462
491560
|
issues: normalizedIssues,
|
|
490463
491561
|
summary: summarizeReviewIssues(normalizedIssues),
|
|
491562
|
+
nextActions: deriveNextReviewActions({
|
|
491563
|
+
issues: normalizedIssues,
|
|
491564
|
+
retryWith: normalizedRetryWith,
|
|
491565
|
+
projectDir
|
|
491566
|
+
}),
|
|
490464
491567
|
sourceReports: projectSourceReports(checks),
|
|
490465
491568
|
checks,
|
|
490466
|
-
retryWith:
|
|
491569
|
+
retryWith: normalizedRetryWith
|
|
490467
491570
|
};
|
|
490468
491571
|
}
|
|
490469
491572
|
function storyboardPlaceholderIssues(storyboard) {
|
|
@@ -490783,7 +491886,7 @@ init_storyboard_parse();
|
|
|
490783
491886
|
init_review_report();
|
|
490784
491887
|
import { existsSync as existsSync57 } from "node:fs";
|
|
490785
491888
|
import { readdir as readdir7, readFile as readFile32, stat as stat6 } from "node:fs/promises";
|
|
490786
|
-
import { basename as basename15, isAbsolute as isAbsolute8, join as
|
|
491889
|
+
import { basename as basename15, isAbsolute as isAbsolute8, join as join38, relative as relative14, resolve as resolve51 } from "node:path";
|
|
490787
491890
|
var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([".mp4", ".mov", ".webm", ".m4v"]);
|
|
490788
491891
|
var DEFAULT_AI_MODEL = "flash";
|
|
490789
491892
|
var BLACK_FRAME_MIN_DURATION_SEC = 1;
|
|
@@ -491015,6 +492118,8 @@ async function inspectRender(opts) {
|
|
|
491015
492118
|
severity: "error",
|
|
491016
492119
|
code: "RENDER_NOT_FOUND",
|
|
491017
492120
|
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.",
|
|
492121
|
+
beatId: opts.beatId,
|
|
492122
|
+
scene: opts.beatId,
|
|
491018
492123
|
suggestedFix: opts.beatId ? "Run `vibe render <project> --beat <id> --json`." : "Run `vibe build --stage render --json` or `vibe render --json`."
|
|
491019
492124
|
});
|
|
491020
492125
|
retryWith.push(
|
|
@@ -491037,6 +492142,8 @@ async function inspectRender(opts) {
|
|
|
491037
492142
|
code: "EMPTY_RENDER",
|
|
491038
492143
|
message: "Rendered video file is empty.",
|
|
491039
492144
|
file: displayPath(videoPath),
|
|
492145
|
+
beatId: opts.beatId,
|
|
492146
|
+
scene: opts.beatId,
|
|
491040
492147
|
suggestedFix: opts.beatId ? "Render again with `vibe render --beat <id> --json`." : "Render again with `vibe render --json`."
|
|
491041
492148
|
});
|
|
491042
492149
|
retryWith.push(
|
|
@@ -491046,6 +492153,8 @@ async function inspectRender(opts) {
|
|
|
491046
492153
|
const beatTimings = await beatTimingsFromBuildReport(projectDir, opts.beatId);
|
|
491047
492154
|
const expectedDurationSec = beatTimings.length > 0 ? Number(beatTimings.reduce((sum, beat) => sum + beat.sceneDurationSec, 0).toFixed(3)) : await expectedDurationFromBuildReport(projectDir, opts.beatId);
|
|
491048
492155
|
if (expectedDurationSec !== void 0) checks.expectedDurationSec = expectedDurationSec;
|
|
492156
|
+
const expectedAudio = await renderExpectsAudio(projectDir, opts.beatId);
|
|
492157
|
+
checks.expectedAudio = expectedAudio;
|
|
491049
492158
|
if (!commandExists("ffprobe")) {
|
|
491050
492159
|
issues.push({
|
|
491051
492160
|
severity: "error",
|
|
@@ -491071,7 +492180,7 @@ async function inspectRender(opts) {
|
|
|
491071
492180
|
file: displayPath(videoPath)
|
|
491072
492181
|
});
|
|
491073
492182
|
}
|
|
491074
|
-
if (!audioStream) {
|
|
492183
|
+
if (!audioStream && expectedAudio) {
|
|
491075
492184
|
issues.push({
|
|
491076
492185
|
severity: "warning",
|
|
491077
492186
|
code: "NO_AUDIO_STREAM",
|
|
@@ -491276,8 +492385,86 @@ async function inspectRender(opts) {
|
|
|
491276
492385
|
);
|
|
491277
492386
|
return maybeWriteRenderReport(projectDir, opts, result);
|
|
491278
492387
|
}
|
|
492388
|
+
async function renderExpectsAudio(projectDir, beatId) {
|
|
492389
|
+
const root2 = resolve51(projectDir);
|
|
492390
|
+
const rootHtml = await readTextIfExists(join38(root2, "index.html"));
|
|
492391
|
+
if (rootHtml && rootHtmlExpectsAudio(rootHtml, beatId)) return true;
|
|
492392
|
+
const buildReport = await readJsonIfExists(join38(root2, "build-report.json"));
|
|
492393
|
+
if (buildReportExpectsAudio(buildReport, beatId)) return true;
|
|
492394
|
+
const storyboard = await readTextIfExists(join38(root2, "STORYBOARD.md"));
|
|
492395
|
+
if (!storyboard) return false;
|
|
492396
|
+
try {
|
|
492397
|
+
const parsed = parseStoryboard(storyboard);
|
|
492398
|
+
const beats = beatId ? parsed.beats.filter((beat) => beat.id === beatId) : parsed.beats;
|
|
492399
|
+
return beats.some(
|
|
492400
|
+
(beat) => [
|
|
492401
|
+
`assets/narration-${beat.id}.mp3`,
|
|
492402
|
+
`assets/narration-${beat.id}.wav`,
|
|
492403
|
+
`assets/music-${beat.id}.mp3`,
|
|
492404
|
+
`assets/music-${beat.id}.wav`
|
|
492405
|
+
].some((asset) => existsSync57(join38(root2, asset)))
|
|
492406
|
+
);
|
|
492407
|
+
} catch {
|
|
492408
|
+
return false;
|
|
492409
|
+
}
|
|
492410
|
+
}
|
|
492411
|
+
function rootHtmlExpectsAudio(html, beatId) {
|
|
492412
|
+
const audioTags = html.match(/<audio\b[^>]*>/gi) ?? [];
|
|
492413
|
+
if (!beatId) return audioTags.length > 0;
|
|
492414
|
+
const escaped = escapeRegExp4(beatId);
|
|
492415
|
+
const beatAudioRe = new RegExp(
|
|
492416
|
+
`(id="(?:narration|music)-${escaped}"|src="[^"]*(?:narration|music)-${escaped}\\.(?:mp3|wav)")`,
|
|
492417
|
+
"i"
|
|
492418
|
+
);
|
|
492419
|
+
return audioTags.some((tag) => beatAudioRe.test(tag));
|
|
492420
|
+
}
|
|
492421
|
+
function buildReportExpectsAudio(report, beatId) {
|
|
492422
|
+
if (!report || typeof report !== "object") return false;
|
|
492423
|
+
const beats = Array.isArray(report.beats) ? report.beats ?? [] : [];
|
|
492424
|
+
const selected = beatId === void 0 ? beats : beats.filter((beat) => {
|
|
492425
|
+
if (!beat || typeof beat !== "object") return false;
|
|
492426
|
+
return beat.id === beatId;
|
|
492427
|
+
});
|
|
492428
|
+
return selected.some((beat) => beatReportExpectsAudio(beat));
|
|
492429
|
+
}
|
|
492430
|
+
function beatReportExpectsAudio(beat) {
|
|
492431
|
+
if (!beat || typeof beat !== "object") return false;
|
|
492432
|
+
const record = beat;
|
|
492433
|
+
if (typeof record.narrationPath === "string" && record.narrationPath.length > 0) return true;
|
|
492434
|
+
if (typeof record.musicPath === "string" && record.musicPath.length > 0) return true;
|
|
492435
|
+
if (parseOptionalNumber2(record.narrationDurationSec) !== void 0) return true;
|
|
492436
|
+
const narration = record.narration;
|
|
492437
|
+
if (narration && typeof narration === "object") {
|
|
492438
|
+
const n2 = narration;
|
|
492439
|
+
if (typeof n2.path === "string" && n2.path.length > 0) return true;
|
|
492440
|
+
if (parseOptionalNumber2(n2.durationSec) !== void 0) return true;
|
|
492441
|
+
}
|
|
492442
|
+
const music = record.music;
|
|
492443
|
+
if (music && typeof music === "object") {
|
|
492444
|
+
const m2 = music;
|
|
492445
|
+
if (typeof m2.path === "string" && m2.path.length > 0) return true;
|
|
492446
|
+
if (parseOptionalNumber2(m2.durationSec) !== void 0) return true;
|
|
492447
|
+
}
|
|
492448
|
+
return false;
|
|
492449
|
+
}
|
|
492450
|
+
async function readJsonIfExists(path14) {
|
|
492451
|
+
const text = await readTextIfExists(path14);
|
|
492452
|
+
if (!text) return null;
|
|
492453
|
+
try {
|
|
492454
|
+
return JSON.parse(text);
|
|
492455
|
+
} catch {
|
|
492456
|
+
return null;
|
|
492457
|
+
}
|
|
492458
|
+
}
|
|
492459
|
+
function escapeRegExp4(value) {
|
|
492460
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
492461
|
+
}
|
|
491279
492462
|
function makeRenderResult(projectDir, opts, videoPath, issues, checks, retryWith, score) {
|
|
491280
|
-
const
|
|
492463
|
+
const normalizedRetryWith = uniqueRetryWith(retryWith);
|
|
492464
|
+
const normalizedIssues = normalizeReviewIssues(issues, {
|
|
492465
|
+
projectDir,
|
|
492466
|
+
retryWith: normalizedRetryWith
|
|
492467
|
+
});
|
|
491281
492468
|
const status = statusFromIssues(normalizedIssues);
|
|
491282
492469
|
return {
|
|
491283
492470
|
schemaVersion: "1",
|
|
@@ -491290,9 +492477,14 @@ function makeRenderResult(projectDir, opts, videoPath, issues, checks, retryWith
|
|
|
491290
492477
|
score,
|
|
491291
492478
|
issues: normalizedIssues,
|
|
491292
492479
|
summary: summarizeReviewIssues(normalizedIssues),
|
|
492480
|
+
nextActions: deriveNextReviewActions({
|
|
492481
|
+
issues: normalizedIssues,
|
|
492482
|
+
retryWith: normalizedRetryWith,
|
|
492483
|
+
projectDir
|
|
492484
|
+
}),
|
|
491293
492485
|
sourceReports: renderSourceReports(projectDir, videoPath, checks),
|
|
491294
492486
|
checks,
|
|
491295
|
-
retryWith:
|
|
492487
|
+
retryWith: normalizedRetryWith
|
|
491296
492488
|
};
|
|
491297
492489
|
}
|
|
491298
492490
|
async function maybeWriteRenderReport(projectDir, opts, result) {
|
|
@@ -491318,8 +492510,8 @@ async function maybeWriteRenderReport(projectDir, opts, result) {
|
|
|
491318
492510
|
}
|
|
491319
492511
|
function renderSourceReports(projectDir, videoPath, checks) {
|
|
491320
492512
|
const reports = [];
|
|
491321
|
-
if (existsSync57(
|
|
491322
|
-
if (existsSync57(
|
|
492513
|
+
if (existsSync57(join38(projectDir, "build-report.json"))) reports.push("build-report.json");
|
|
492514
|
+
if (existsSync57(join38(projectDir, "render-report.json"))) reports.push("render-report.json");
|
|
491323
492515
|
if (videoPath) reports.push(displayPath(videoPath));
|
|
491324
492516
|
if (checks.durationSec !== void 0 || checks.width !== void 0 || checks.height !== void 0) {
|
|
491325
492517
|
reports.push("ffprobe");
|
|
@@ -491334,7 +492526,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491334
492526
|
const candidate = resolve51(process.cwd(), explicit);
|
|
491335
492527
|
return existsSync57(candidate) ? candidate : null;
|
|
491336
492528
|
}
|
|
491337
|
-
const renderReportPath =
|
|
492529
|
+
const renderReportPath = join38(projectDir, "render-report.json");
|
|
491338
492530
|
if (existsSync57(renderReportPath)) {
|
|
491339
492531
|
try {
|
|
491340
492532
|
const report = JSON.parse(await readFile32(renderReportPath, "utf-8"));
|
|
@@ -491346,7 +492538,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491346
492538
|
} catch {
|
|
491347
492539
|
}
|
|
491348
492540
|
}
|
|
491349
|
-
const reportPath =
|
|
492541
|
+
const reportPath = join38(projectDir, "build-report.json");
|
|
491350
492542
|
if (!beatId && existsSync57(reportPath)) {
|
|
491351
492543
|
try {
|
|
491352
492544
|
const report = JSON.parse(await readFile32(reportPath, "utf-8"));
|
|
@@ -491355,7 +492547,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491355
492547
|
} catch {
|
|
491356
492548
|
}
|
|
491357
492549
|
}
|
|
491358
|
-
const rendersDir =
|
|
492550
|
+
const rendersDir = join38(projectDir, "renders");
|
|
491359
492551
|
if (!existsSync57(rendersDir)) return null;
|
|
491360
492552
|
const entries2 = await readdir7(rendersDir, { withFileTypes: true });
|
|
491361
492553
|
const candidates = [];
|
|
@@ -491364,7 +492556,7 @@ async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
|
491364
492556
|
const ext = entry.name.slice(entry.name.lastIndexOf(".")).toLowerCase();
|
|
491365
492557
|
if (!VIDEO_EXTENSIONS.has(ext)) continue;
|
|
491366
492558
|
if (beatId && !entry.name.includes(sanitizeFileSegment2(beatId))) continue;
|
|
491367
|
-
const full =
|
|
492559
|
+
const full = join38(rendersDir, entry.name);
|
|
491368
492560
|
const info = await stat6(full);
|
|
491369
492561
|
candidates.push({ path: full, mtimeMs: info.mtimeMs });
|
|
491370
492562
|
}
|
|
@@ -491382,11 +492574,11 @@ async function runAiRenderReview(projectDir, videoPath, model) {
|
|
|
491382
492574
|
});
|
|
491383
492575
|
}
|
|
491384
492576
|
function resolveStoryboardPath(projectDir) {
|
|
491385
|
-
const storyboardPath =
|
|
492577
|
+
const storyboardPath = join38(projectDir, "STORYBOARD.md");
|
|
491386
492578
|
return existsSync57(storyboardPath) ? storyboardPath : null;
|
|
491387
492579
|
}
|
|
491388
492580
|
async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
491389
|
-
const reportPath =
|
|
492581
|
+
const reportPath = join38(projectDir, "build-report.json");
|
|
491390
492582
|
if (!existsSync57(reportPath)) return void 0;
|
|
491391
492583
|
try {
|
|
491392
492584
|
const report = JSON.parse(await readFile32(reportPath, "utf-8"));
|
|
@@ -491401,7 +492593,7 @@ async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
|
491401
492593
|
}
|
|
491402
492594
|
}
|
|
491403
492595
|
async function beatTimingsFromBuildReport(projectDir, beatId) {
|
|
491404
|
-
const reportPath =
|
|
492596
|
+
const reportPath = join38(projectDir, "build-report.json");
|
|
491405
492597
|
if (!existsSync57(reportPath)) return [];
|
|
491406
492598
|
try {
|
|
491407
492599
|
const report = JSON.parse(await readFile32(reportPath, "utf-8"));
|
|
@@ -491430,17 +492622,17 @@ async function beatTimingsFromBuildReport(projectDir, beatId) {
|
|
|
491430
492622
|
}
|
|
491431
492623
|
async function buildRenderReviewProjectContext(projectDir) {
|
|
491432
492624
|
const parts = [];
|
|
491433
|
-
const storyboard = await readTextIfExists(
|
|
492625
|
+
const storyboard = await readTextIfExists(join38(projectDir, "STORYBOARD.md"));
|
|
491434
492626
|
if (storyboard) {
|
|
491435
492627
|
parts.push(`STORYBOARD.md:
|
|
491436
492628
|
${truncateText(storyboard, 4e3)}`);
|
|
491437
492629
|
parts.push(`Storyboard beat cue summary:
|
|
491438
492630
|
${storyboardBeatCueSummary(storyboard)}`);
|
|
491439
492631
|
}
|
|
491440
|
-
const design = await readTextIfExists(
|
|
492632
|
+
const design = await readTextIfExists(join38(projectDir, "DESIGN.md"));
|
|
491441
492633
|
if (design) parts.push(`DESIGN.md:
|
|
491442
492634
|
${truncateText(design, 4e3)}`);
|
|
491443
|
-
const buildReport = await readTextIfExists(
|
|
492635
|
+
const buildReport = await readTextIfExists(join38(projectDir, "build-report.json"));
|
|
491444
492636
|
if (buildReport) parts.push(`build-report.json:
|
|
491445
492637
|
${truncateText(buildReport, 6e3)}`);
|
|
491446
492638
|
const timings = await beatTimingsFromBuildReport(projectDir);
|
|
@@ -492299,7 +493491,7 @@ init_storyboard_edit();
|
|
|
492299
493491
|
// ../cli/src/commands/_shared/storyboard-revise.ts
|
|
492300
493492
|
import { existsSync as existsSync59 } from "node:fs";
|
|
492301
493493
|
import { readFile as readFile35, writeFile as writeFile42 } from "node:fs/promises";
|
|
492302
|
-
import { join as
|
|
493494
|
+
import { join as join39, resolve as resolve64 } from "node:path";
|
|
492303
493495
|
|
|
492304
493496
|
// ../cli/src/agent/adapters/index.ts
|
|
492305
493497
|
init_openai3();
|
|
@@ -492346,7 +493538,7 @@ init_storyboard_parse();
|
|
|
492346
493538
|
init_storyboard_edit();
|
|
492347
493539
|
async function executeStoryboardRevision(opts) {
|
|
492348
493540
|
const projectDir = resolve64(opts.projectDir);
|
|
492349
|
-
const storyboardPath =
|
|
493541
|
+
const storyboardPath = join39(projectDir, "STORYBOARD.md");
|
|
492350
493542
|
const retryWith = [`vibe storyboard revise ${projectDir} --from "<request>" --dry-run --json`];
|
|
492351
493543
|
if (!existsSync59(storyboardPath)) {
|
|
492352
493544
|
return failureResult({
|
|
@@ -492581,8 +493773,8 @@ function diffChangedBeats(before2, after2) {
|
|
|
492581
493773
|
return ids.filter((id) => JSON.stringify(beforeBeats.get(id) ?? null) !== JSON.stringify(afterBeats.get(id) ?? null));
|
|
492582
493774
|
}
|
|
492583
493775
|
async function readRevisionContext(projectDir) {
|
|
492584
|
-
const designMd = await readOptionalText(
|
|
492585
|
-
const buildReportJson = await readOptionalJsonText(
|
|
493776
|
+
const designMd = await readOptionalText(join39(projectDir, "DESIGN.md"));
|
|
493777
|
+
const buildReportJson = await readOptionalJsonText(join39(projectDir, "build-report.json"));
|
|
492586
493778
|
return { designMd, buildReportJson };
|
|
492587
493779
|
}
|
|
492588
493780
|
async function readOptionalText(path14) {
|
|
@@ -492897,7 +494089,7 @@ var storyboardTools = [
|
|
|
492897
494089
|
// ../cli/src/tools/manifest/remix.ts
|
|
492898
494090
|
import { writeFile as writeFile48 } from "node:fs/promises";
|
|
492899
494091
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
492900
|
-
import { join as
|
|
494092
|
+
import { join as join40 } from "node:path";
|
|
492901
494093
|
import { z as z8 } from "zod";
|
|
492902
494094
|
|
|
492903
494095
|
// ../cli/src/commands/ai-script-pipeline.ts
|
|
@@ -494631,7 +495823,7 @@ var pipelineRunTool = defineTool({
|
|
|
494631
495823
|
let resolvedPath = args.pipelinePath;
|
|
494632
495824
|
let tempPath;
|
|
494633
495825
|
if (args.pipelineYaml) {
|
|
494634
|
-
tempPath =
|
|
495826
|
+
tempPath = join40(tmpdir6(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
|
|
494635
495827
|
await writeFile48(tempPath, args.pipelineYaml, "utf-8");
|
|
494636
495828
|
resolvedPath = tempPath;
|
|
494637
495829
|
}
|
|
@@ -495163,7 +496355,7 @@ init_engine();
|
|
|
495163
496355
|
init_storyboard_parse();
|
|
495164
496356
|
import { readdir as readdir8, readFile as readFile42, stat as stat7 } from "node:fs/promises";
|
|
495165
496357
|
import { existsSync as existsSync65 } from "node:fs";
|
|
495166
|
-
import { join as
|
|
496358
|
+
import { join as join41, resolve as resolve71 } from "node:path";
|
|
495167
496359
|
async function executeProjectList(opts = {}) {
|
|
495168
496360
|
const workspaceDir = resolve71(opts.workspaceDir ?? ".");
|
|
495169
496361
|
if (!existsSync65(workspaceDir)) {
|
|
@@ -495183,11 +496375,11 @@ async function executeProjectList(opts = {}) {
|
|
|
495183
496375
|
if (entry.name === "node_modules") continue;
|
|
495184
496376
|
if (entry.name.startsWith(".")) continue;
|
|
495185
496377
|
if (entry.name.startsWith("_")) {
|
|
495186
|
-
archivedCount += await countProjects(
|
|
496378
|
+
archivedCount += await countProjects(join41(workspaceDir, entry.name));
|
|
495187
496379
|
continue;
|
|
495188
496380
|
}
|
|
495189
|
-
const projectDir =
|
|
495190
|
-
if (!existsSync65(
|
|
496381
|
+
const projectDir = join41(workspaceDir, entry.name);
|
|
496382
|
+
if (!existsSync65(join41(projectDir, "STORYBOARD.md"))) continue;
|
|
495191
496383
|
projects.push(await describeProject(entry.name, projectDir));
|
|
495192
496384
|
}
|
|
495193
496385
|
projects.sort((a2, b2) => b2.updatedAt.localeCompare(a2.updatedAt));
|
|
@@ -495197,7 +496389,7 @@ async function countProjects(dir) {
|
|
|
495197
496389
|
try {
|
|
495198
496390
|
const entries2 = await readdir8(dir, { withFileTypes: true });
|
|
495199
496391
|
return entries2.filter(
|
|
495200
|
-
(e2) => e2.isDirectory() && existsSync65(
|
|
496392
|
+
(e2) => e2.isDirectory() && existsSync65(join41(dir, e2.name, "STORYBOARD.md"))
|
|
495201
496393
|
).length;
|
|
495202
496394
|
} catch {
|
|
495203
496395
|
return 0;
|
|
@@ -495208,7 +496400,7 @@ async function describeProject(name, projectDir) {
|
|
|
495208
496400
|
let storyboardDurationSec = 0;
|
|
495209
496401
|
const timestamps = [];
|
|
495210
496402
|
try {
|
|
495211
|
-
const storyboardPath =
|
|
496403
|
+
const storyboardPath = join41(projectDir, "STORYBOARD.md");
|
|
495212
496404
|
const parsed = parseStoryboard(await readFile42(storyboardPath, "utf-8"));
|
|
495213
496405
|
beats = parsed.beats.length;
|
|
495214
496406
|
storyboardDurationSec = Number(
|
|
@@ -495220,7 +496412,7 @@ async function describeProject(name, projectDir) {
|
|
|
495220
496412
|
let buildStatus;
|
|
495221
496413
|
let buildUpdatedAt;
|
|
495222
496414
|
try {
|
|
495223
|
-
const reportPath =
|
|
496415
|
+
const reportPath = join41(projectDir, "build-report.json");
|
|
495224
496416
|
const report = JSON.parse(await readFile42(reportPath, "utf-8"));
|
|
495225
496417
|
buildStatus = report.status ?? report.phase;
|
|
495226
496418
|
buildUpdatedAt = report.updatedAt;
|
|
@@ -495229,12 +496421,12 @@ async function describeProject(name, projectDir) {
|
|
|
495229
496421
|
}
|
|
495230
496422
|
let latestRender;
|
|
495231
496423
|
try {
|
|
495232
|
-
const rendersDir =
|
|
496424
|
+
const rendersDir = join41(projectDir, "renders");
|
|
495233
496425
|
const files = await readdir8(rendersDir);
|
|
495234
496426
|
let newest;
|
|
495235
496427
|
for (const file of files) {
|
|
495236
496428
|
if (!/\.(mp4|webm|mov)$/i.test(file)) continue;
|
|
495237
|
-
const { mtimeMs } = await stat7(
|
|
496429
|
+
const { mtimeMs } = await stat7(join41(rendersDir, file));
|
|
495238
496430
|
if (!newest || mtimeMs > newest.mtimeMs) newest = { file, mtimeMs };
|
|
495239
496431
|
}
|
|
495240
496432
|
if (newest) {
|
|
@@ -496245,7 +497437,7 @@ var exportTools = [exportVideoTool];
|
|
|
496245
497437
|
|
|
496246
497438
|
// ../cli/src/tools/manifest/agent-only.ts
|
|
496247
497439
|
import { readFile as readFile44, writeFile as writeFile52, readdir as readdir9, stat as stat8, access as access7, unlink as unlink7 } from "node:fs/promises";
|
|
496248
|
-
import { resolve as resolve76, join as
|
|
497440
|
+
import { resolve as resolve76, join as join43, basename as basename21, extname as extname14 } from "node:path";
|
|
496249
497441
|
import { z as z13 } from "zod";
|
|
496250
497442
|
init_engine();
|
|
496251
497443
|
init_exec_safe();
|
|
@@ -496324,7 +497516,7 @@ var fsListTool = defineTool({
|
|
|
496324
497516
|
const results = [];
|
|
496325
497517
|
for (const entry of entries2) {
|
|
496326
497518
|
if (args.pattern && !matchPattern(entry.name, args.pattern)) continue;
|
|
496327
|
-
const fullPath =
|
|
497519
|
+
const fullPath = join43(absPath, entry.name);
|
|
496328
497520
|
const stats = await stat8(fullPath);
|
|
496329
497521
|
if (entry.isDirectory()) {
|
|
496330
497522
|
results.push(`[DIR] ${entry.name}/`);
|
|
@@ -496437,7 +497629,7 @@ var batchImportTool = defineTool({
|
|
|
496437
497629
|
const scanDir = async (dir) => {
|
|
496438
497630
|
const entries2 = await readdir9(dir, { withFileTypes: true });
|
|
496439
497631
|
for (const entry of entries2) {
|
|
496440
|
-
const entryPath =
|
|
497632
|
+
const entryPath = join43(dir, entry.name);
|
|
496441
497633
|
if (entry.isDirectory() && recursive) {
|
|
496442
497634
|
await scanDir(entryPath);
|
|
496443
497635
|
} else if (entry.isFile()) {
|
|
@@ -498507,7 +499699,7 @@ var server2 = new Server(
|
|
|
498507
499699
|
{
|
|
498508
499700
|
name: "vibeframe",
|
|
498509
499701
|
// Stamped with the package version by build.js at bundle time.
|
|
498510
|
-
version: "0.113.
|
|
499702
|
+
version: "0.113.3"
|
|
498511
499703
|
},
|
|
498512
499704
|
{
|
|
498513
499705
|
capabilities: {
|