@vibeframe/mcp-server 0.114.0 → 0.115.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1102 -855
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4871,11 +4871,11 @@ async function loadKokoroRuntime() {
|
|
|
4871
4871
|
}
|
|
4872
4872
|
async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
4873
4873
|
try {
|
|
4874
|
-
const { readFile:
|
|
4874
|
+
const { readFile: readFile48 } = await import("node:fs/promises");
|
|
4875
4875
|
const { join: join78, resolve: resolve85 } = await import("node:path");
|
|
4876
4876
|
const { pathToFileURL: pathToFileURL2 } = await import("node:url");
|
|
4877
4877
|
const pkgDir = resolve85(baseDir, "node_modules", "kokoro-js");
|
|
4878
|
-
const pkg = JSON.parse(await
|
|
4878
|
+
const pkg = JSON.parse(await readFile48(join78(pkgDir, "package.json"), "utf-8"));
|
|
4879
4879
|
const entry = pkg.exports?.node?.import ?? pkg.exports?.default ?? pkg.module ?? pkg.main;
|
|
4880
4880
|
if (!entry)
|
|
4881
4881
|
return null;
|
|
@@ -4890,7 +4890,7 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4890
4890
|
if (!base2)
|
|
4891
4891
|
return null;
|
|
4892
4892
|
try {
|
|
4893
|
-
const { readFile:
|
|
4893
|
+
const { readFile: readFile48, writeFile: writeFile51, mkdir: mkdir30 } = await import("node:fs/promises");
|
|
4894
4894
|
const { join: join78, resolve: resolve85 } = await import("node:path");
|
|
4895
4895
|
const { pathToFileURL: pathToFileURL2 } = await import("node:url");
|
|
4896
4896
|
const { homedir: homedir8 } = await import("node:os");
|
|
@@ -4903,7 +4903,7 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4903
4903
|
transformers.env.customCache = {
|
|
4904
4904
|
async match(key2) {
|
|
4905
4905
|
try {
|
|
4906
|
-
return new Response(await
|
|
4906
|
+
return new Response(await readFile48(join78(cacheRoot, encodeURIComponent(String(key2)))));
|
|
4907
4907
|
} catch {
|
|
4908
4908
|
return void 0;
|
|
4909
4909
|
}
|
|
@@ -4911,8 +4911,8 @@ async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUN
|
|
|
4911
4911
|
async put(key2, response) {
|
|
4912
4912
|
try {
|
|
4913
4913
|
const buf = Buffer.from(await response.arrayBuffer());
|
|
4914
|
-
await
|
|
4915
|
-
await
|
|
4914
|
+
await mkdir30(cacheRoot, { recursive: true });
|
|
4915
|
+
await writeFile51(join78(cacheRoot, encodeURIComponent(String(key2))), buf);
|
|
4916
4916
|
} catch {
|
|
4917
4917
|
}
|
|
4918
4918
|
}
|
|
@@ -21945,12 +21945,29 @@ function parseBeatDuration(body) {
|
|
|
21945
21945
|
const n2 = parseFloat(valueMatch[1]);
|
|
21946
21946
|
return Number.isFinite(n2) && n2 > 0 ? n2 : void 0;
|
|
21947
21947
|
}
|
|
21948
|
-
var import_yaml3, HEADING_RE, BEAT_PREFIX_RE, DURATION_SUBSECTION_RE, DURATION_VALUE_RE, BEAT_CUES_RE;
|
|
21948
|
+
var import_yaml3, STORYBOARD_CUE_KEYS, HEADING_RE, BEAT_PREFIX_RE, DURATION_SUBSECTION_RE, DURATION_VALUE_RE, BEAT_CUES_RE;
|
|
21949
21949
|
var init_storyboard_parse = __esm({
|
|
21950
21950
|
"../cli/src/commands/_shared/storyboard-parse.ts"() {
|
|
21951
21951
|
"use strict";
|
|
21952
21952
|
import_yaml3 = __toESM(require_dist3(), 1);
|
|
21953
21953
|
init_frontmatter();
|
|
21954
|
+
STORYBOARD_CUE_KEYS = [
|
|
21955
|
+
"duration",
|
|
21956
|
+
"narration",
|
|
21957
|
+
"backdrop",
|
|
21958
|
+
"video",
|
|
21959
|
+
"keyframe",
|
|
21960
|
+
"motion",
|
|
21961
|
+
"voice",
|
|
21962
|
+
"music",
|
|
21963
|
+
"asset",
|
|
21964
|
+
"characters",
|
|
21965
|
+
"eyebrow",
|
|
21966
|
+
"title",
|
|
21967
|
+
"caption",
|
|
21968
|
+
"kicker",
|
|
21969
|
+
"sub"
|
|
21970
|
+
];
|
|
21954
21971
|
HEADING_RE = /^##\s+(.+?)\s*$/gm;
|
|
21955
21972
|
BEAT_PREFIX_RE = /^Beat\s+(.+?)\s+(?:—|:|-)\s+(.+)$/i;
|
|
21956
21973
|
DURATION_SUBSECTION_RE = /###\s+Beat\s+duration\s*\n([\s\S]*?)(?=\n###\s|\n##\s|$)/i;
|
|
@@ -21959,22 +21976,509 @@ var init_storyboard_parse = __esm({
|
|
|
21959
21976
|
}
|
|
21960
21977
|
});
|
|
21961
21978
|
|
|
21979
|
+
// ../cli/src/commands/_shared/storyboard-edit.ts
|
|
21980
|
+
function validateStoryboardMarkdown(markdown) {
|
|
21981
|
+
const parsed = parseStoryboard(markdown);
|
|
21982
|
+
const sections = splitBeatSections(markdown);
|
|
21983
|
+
const issues = [];
|
|
21984
|
+
if (parsed.beats.length === 0) {
|
|
21985
|
+
issues.push({
|
|
21986
|
+
severity: "error",
|
|
21987
|
+
code: "NO_BEATS",
|
|
21988
|
+
message: "STORYBOARD.md must contain at least one `## Beat ...` heading."
|
|
21989
|
+
});
|
|
21990
|
+
}
|
|
21991
|
+
const seen = /* @__PURE__ */ new Map();
|
|
21992
|
+
for (const beat of parsed.beats) {
|
|
21993
|
+
seen.set(beat.id, (seen.get(beat.id) ?? 0) + 1);
|
|
21994
|
+
}
|
|
21995
|
+
for (const [id, count] of seen.entries()) {
|
|
21996
|
+
if (count > 1) {
|
|
21997
|
+
issues.push({
|
|
21998
|
+
severity: "error",
|
|
21999
|
+
code: "DUPLICATE_BEAT_ID",
|
|
22000
|
+
beatId: id,
|
|
22001
|
+
message: `Beat id "${id}" appears ${count} times. Beat ids must be unique.`
|
|
22002
|
+
});
|
|
22003
|
+
}
|
|
22004
|
+
}
|
|
22005
|
+
for (const section of sections) {
|
|
22006
|
+
const cueBlock = readLeadingCueBlock(section.body);
|
|
22007
|
+
if (cueBlock?.error) {
|
|
22008
|
+
issues.push({
|
|
22009
|
+
severity: "error",
|
|
22010
|
+
code: "MALFORMED_CUE_YAML",
|
|
22011
|
+
beatId: section.id,
|
|
22012
|
+
message: `Beat "${section.id}" has malformed YAML cues: ${cueBlock.error}`
|
|
22013
|
+
});
|
|
22014
|
+
}
|
|
22015
|
+
}
|
|
22016
|
+
const characterPool = new Set(
|
|
22017
|
+
Object.keys(
|
|
22018
|
+
parsed.frontmatter?.characters ?? {}
|
|
22019
|
+
)
|
|
22020
|
+
);
|
|
22021
|
+
for (const beat of parsed.beats) {
|
|
22022
|
+
const cues = beat.cues ?? {};
|
|
22023
|
+
for (const [key2, value] of Object.entries(cues)) {
|
|
22024
|
+
if (!ALLOWED_CUE_KEYS.has(key2)) {
|
|
22025
|
+
issues.push({
|
|
22026
|
+
severity: "warning",
|
|
22027
|
+
code: "UNKNOWN_CUE",
|
|
22028
|
+
beatId: beat.id,
|
|
22029
|
+
message: `Beat "${beat.id}" uses unknown cue "${key2}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`
|
|
22030
|
+
});
|
|
22031
|
+
continue;
|
|
22032
|
+
}
|
|
22033
|
+
if (key2 === "characters") {
|
|
22034
|
+
const validShape = typeof value === "string" || Array.isArray(value) && value.every((v4) => typeof v4 === "string");
|
|
22035
|
+
if (!validShape) {
|
|
22036
|
+
issues.push({
|
|
22037
|
+
severity: "error",
|
|
22038
|
+
code: "INVALID_CHARACTERS_VALUE",
|
|
22039
|
+
beatId: beat.id,
|
|
22040
|
+
message: `Beat "${beat.id}" cue "characters" must be a character name or a list of names.`
|
|
22041
|
+
});
|
|
22042
|
+
continue;
|
|
22043
|
+
}
|
|
22044
|
+
for (const name of beatCharacterNames({ characters: value })) {
|
|
22045
|
+
if (!characterPool.has(name)) {
|
|
22046
|
+
issues.push({
|
|
22047
|
+
severity: "warning",
|
|
22048
|
+
code: "UNKNOWN_CHARACTER",
|
|
22049
|
+
beatId: beat.id,
|
|
22050
|
+
message: `Beat "${beat.id}" references character "${name}" not defined in the frontmatter \`characters:\` pool.`
|
|
22051
|
+
});
|
|
22052
|
+
}
|
|
22053
|
+
}
|
|
22054
|
+
continue;
|
|
22055
|
+
}
|
|
22056
|
+
if (key2 === "duration") {
|
|
22057
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
22058
|
+
issues.push({
|
|
22059
|
+
severity: "error",
|
|
22060
|
+
code: "INVALID_DURATION",
|
|
22061
|
+
beatId: beat.id,
|
|
22062
|
+
message: `Beat "${beat.id}" cue "duration" must be a positive number of seconds.`
|
|
22063
|
+
});
|
|
22064
|
+
}
|
|
22065
|
+
continue;
|
|
22066
|
+
}
|
|
22067
|
+
if (STRING_CUE_KEYS.has(key2) && typeof value !== "string") {
|
|
22068
|
+
issues.push({
|
|
22069
|
+
severity: "error",
|
|
22070
|
+
code: "INVALID_CUE_VALUE",
|
|
22071
|
+
beatId: beat.id,
|
|
22072
|
+
message: `Beat "${beat.id}" cue "${key2}" must be a string.`
|
|
22073
|
+
});
|
|
22074
|
+
}
|
|
22075
|
+
}
|
|
22076
|
+
}
|
|
22077
|
+
for (const beat of parsed.beats) {
|
|
22078
|
+
if (beat.duration !== void 0 && beat.duration > MAX_RECOMMENDED_BEAT_SEC) {
|
|
22079
|
+
issues.push({
|
|
22080
|
+
severity: "warning",
|
|
22081
|
+
code: "BEAT_DURATION_TOO_LONG",
|
|
22082
|
+
beatId: beat.id,
|
|
22083
|
+
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).`
|
|
22084
|
+
});
|
|
22085
|
+
}
|
|
22086
|
+
}
|
|
22087
|
+
return {
|
|
22088
|
+
ok: !issues.some((i3) => i3.severity === "error"),
|
|
22089
|
+
beats: parsed.beats,
|
|
22090
|
+
issues
|
|
22091
|
+
};
|
|
22092
|
+
}
|
|
22093
|
+
function getStoryboardBeat(markdown, beatId) {
|
|
22094
|
+
return parseStoryboard(markdown).beats.find((beat) => beat.id === beatId) ?? null;
|
|
22095
|
+
}
|
|
22096
|
+
function upsertStoryboardBeat(markdown, opts) {
|
|
22097
|
+
const beatId = normalizeBeatId(opts.beatId);
|
|
22098
|
+
const sections = splitBeatSections(markdown);
|
|
22099
|
+
const existing = sections.find((section2) => section2.id === beatId);
|
|
22100
|
+
const cues = storyboardCuesFromInput(opts);
|
|
22101
|
+
if (existing) {
|
|
22102
|
+
let next = markdown;
|
|
22103
|
+
for (const [key2, value] of Object.entries(cues)) {
|
|
22104
|
+
next = setStoryboardCue(next, { beatId, key: key2, value });
|
|
22105
|
+
}
|
|
22106
|
+
return { markdown: next, action: "updated" };
|
|
22107
|
+
}
|
|
22108
|
+
const section = buildStoryboardBeatSection({ ...opts, beatId, cues });
|
|
22109
|
+
if (sections.length > 0 && isStarterStoryboard(markdown)) {
|
|
22110
|
+
const global3 = markdown.slice(0, sections[0].start).trimEnd();
|
|
22111
|
+
return {
|
|
22112
|
+
markdown: `${global3}
|
|
22113
|
+
|
|
22114
|
+
${section}`,
|
|
22115
|
+
action: "replaced-starter"
|
|
22116
|
+
};
|
|
22117
|
+
}
|
|
22118
|
+
const prefix = markdown.trimEnd();
|
|
22119
|
+
return {
|
|
22120
|
+
markdown: `${prefix}${prefix ? "\n\n" : ""}${section}`,
|
|
22121
|
+
action: "appended"
|
|
22122
|
+
};
|
|
22123
|
+
}
|
|
22124
|
+
function setStoryboardCue(markdown, opts) {
|
|
22125
|
+
const section = findBeatSection(markdown, opts.beatId);
|
|
22126
|
+
if (!section) {
|
|
22127
|
+
throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
22128
|
+
}
|
|
22129
|
+
if (!ALLOWED_CUE_KEYS.has(opts.key)) {
|
|
22130
|
+
throw new Error(`Unsupported cue "${opts.key}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`);
|
|
22131
|
+
}
|
|
22132
|
+
const cue = readLeadingCueBlock(section.body);
|
|
22133
|
+
if (cue?.error) {
|
|
22134
|
+
throw new Error(`Cannot edit malformed YAML cues for beat "${opts.beatId}": ${cue.error}`);
|
|
22135
|
+
}
|
|
22136
|
+
const cues = cue?.value ? { ...cue.value } : {};
|
|
22137
|
+
if (opts.unset) {
|
|
22138
|
+
delete cues[opts.key];
|
|
22139
|
+
} else {
|
|
22140
|
+
cues[opts.key] = normalizeCueValue(opts.key, opts.value);
|
|
22141
|
+
}
|
|
22142
|
+
const remainingBody = cue ? section.body.slice(cue.full.length).replace(/^\s*\n/, "") : section.body.replace(/^\s*\n/, "");
|
|
22143
|
+
const cueBlock = Object.keys(cues).length > 0 ? "```yaml\n" + (0, import_yaml4.stringify)(cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
22144
|
+
const nextBody = cueBlock + remainingBody.trimStart();
|
|
22145
|
+
const nextSection = section.raw.slice(0, section.headingEnd - section.start) + "\n\n" + nextBody.trimEnd() + "\n";
|
|
22146
|
+
return markdown.slice(0, section.start) + nextSection + markdown.slice(section.end);
|
|
22147
|
+
}
|
|
22148
|
+
function moveStoryboardBeat(markdown, opts) {
|
|
22149
|
+
if (opts.beatId === opts.afterBeatId) return markdown;
|
|
22150
|
+
const sections = splitBeatSections(markdown);
|
|
22151
|
+
const movingIndex = sections.findIndex((section) => section.id === opts.beatId);
|
|
22152
|
+
if (movingIndex === -1) throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
22153
|
+
const afterIndex = sections.findIndex((section) => section.id === opts.afterBeatId);
|
|
22154
|
+
if (afterIndex === -1) throw new Error(`Beat "${opts.afterBeatId}" not found.`);
|
|
22155
|
+
const global3 = sections.length > 0 ? markdown.slice(0, sections[0].start) : markdown;
|
|
22156
|
+
const chunks = sections.map((section) => section.raw);
|
|
22157
|
+
const [moving] = chunks.splice(movingIndex, 1);
|
|
22158
|
+
const adjustedAfterIndex = movingIndex < afterIndex ? afterIndex - 1 : afterIndex;
|
|
22159
|
+
chunks.splice(adjustedAfterIndex + 1, 0, moving);
|
|
22160
|
+
return global3 + normalizeBeatChunks(chunks);
|
|
22161
|
+
}
|
|
22162
|
+
function normalizeBeatChunks(chunks) {
|
|
22163
|
+
return chunks.map((chunk) => chunk.trim()).filter(Boolean).join("\n\n") + "\n";
|
|
22164
|
+
}
|
|
22165
|
+
function normalizeBeatId(id) {
|
|
22166
|
+
return deriveBeatId(id);
|
|
22167
|
+
}
|
|
22168
|
+
function storyboardCuesFromInput(opts) {
|
|
22169
|
+
const cues = {};
|
|
22170
|
+
if (opts.duration !== void 0) cues.duration = opts.duration;
|
|
22171
|
+
if (opts.narration && opts.narration.trim()) cues.narration = opts.narration.trim();
|
|
22172
|
+
if (opts.backdrop && opts.backdrop.trim()) cues.backdrop = opts.backdrop.trim();
|
|
22173
|
+
return cues;
|
|
22174
|
+
}
|
|
22175
|
+
function buildStoryboardBeatSection(opts) {
|
|
22176
|
+
const title = normalizeTitle(opts.title ?? humanizeBeatId(opts.beatId));
|
|
22177
|
+
const cueBlock = Object.keys(opts.cues).length > 0 ? "```yaml\n" + (0, import_yaml4.stringify)(opts.cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
22178
|
+
const body = opts.body?.trim() || "Scene created with `vibe scene add`. Edit this body if the build flow should recompose it.";
|
|
22179
|
+
return `## Beat ${opts.beatId} - ${title}
|
|
22180
|
+
|
|
22181
|
+
${cueBlock}${body.trimEnd()}
|
|
22182
|
+
`;
|
|
22183
|
+
}
|
|
22184
|
+
function normalizeTitle(value) {
|
|
22185
|
+
return value.replace(/\s+/g, " ").trim() || "Scene";
|
|
22186
|
+
}
|
|
22187
|
+
function humanizeBeatId(id) {
|
|
22188
|
+
return id.split(/[-_]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ") || "Scene";
|
|
22189
|
+
}
|
|
22190
|
+
function isStarterStoryboard(markdown) {
|
|
22191
|
+
const parsed = parseStoryboard(markdown);
|
|
22192
|
+
if (parsed.beats.length !== 3) return false;
|
|
22193
|
+
const ids = parsed.beats.map((beat) => beat.id);
|
|
22194
|
+
if (ids.join(",") !== "hook,proof,close") return false;
|
|
22195
|
+
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.");
|
|
22196
|
+
}
|
|
22197
|
+
function normalizeCueValue(key2, value) {
|
|
22198
|
+
if (key2 === "duration") {
|
|
22199
|
+
const n2 = typeof value === "number" ? value : Number.parseFloat(String(value ?? ""));
|
|
22200
|
+
if (!Number.isFinite(n2) || n2 <= 0) {
|
|
22201
|
+
throw new Error("Cue duration must be a positive number.");
|
|
22202
|
+
}
|
|
22203
|
+
return n2;
|
|
22204
|
+
}
|
|
22205
|
+
if (typeof value !== "string") return value;
|
|
22206
|
+
return value.trim();
|
|
22207
|
+
}
|
|
22208
|
+
function splitBeatSections(markdown) {
|
|
22209
|
+
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
22210
|
+
const headings = [];
|
|
22211
|
+
HEADING_RE2.lastIndex = 0;
|
|
22212
|
+
let match2;
|
|
22213
|
+
while ((match2 = HEADING_RE2.exec(normalized)) !== null) {
|
|
22214
|
+
headings.push({ start: match2.index, end: match2.index + match2[0].length, line: match2[1].trim() });
|
|
22215
|
+
}
|
|
22216
|
+
return headings.map((heading, index) => {
|
|
22217
|
+
const end = index + 1 < headings.length ? headings[index + 1].start : normalized.length;
|
|
22218
|
+
return {
|
|
22219
|
+
id: deriveBeatId(heading.line),
|
|
22220
|
+
heading: heading.line,
|
|
22221
|
+
start: heading.start,
|
|
22222
|
+
headingEnd: heading.end,
|
|
22223
|
+
end,
|
|
22224
|
+
raw: normalized.slice(heading.start, end),
|
|
22225
|
+
body: normalized.slice(heading.end, end).trim()
|
|
22226
|
+
};
|
|
22227
|
+
});
|
|
22228
|
+
}
|
|
22229
|
+
function findBeatSection(markdown, beatId) {
|
|
22230
|
+
return splitBeatSections(markdown).find((section) => section.id === beatId) ?? null;
|
|
22231
|
+
}
|
|
22232
|
+
function readLeadingCueBlock(body) {
|
|
22233
|
+
const match2 = body.match(LEADING_CUE_RE);
|
|
22234
|
+
if (!match2) return null;
|
|
22235
|
+
try {
|
|
22236
|
+
const parsed = (0, import_yaml4.parse)(match2[2]);
|
|
22237
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
22238
|
+
return { full: match2[0], error: "cue block must parse to a YAML object" };
|
|
22239
|
+
}
|
|
22240
|
+
return { full: match2[0], value: parsed };
|
|
22241
|
+
} catch (error) {
|
|
22242
|
+
return { full: match2[0], error: error instanceof Error ? error.message : String(error) };
|
|
22243
|
+
}
|
|
22244
|
+
}
|
|
22245
|
+
var import_yaml4, HEADING_RE2, LEADING_CUE_RE, ALLOWED_CUE_KEYS, STRING_CUE_KEYS, MAX_RECOMMENDED_BEAT_SEC;
|
|
22246
|
+
var init_storyboard_edit = __esm({
|
|
22247
|
+
"../cli/src/commands/_shared/storyboard-edit.ts"() {
|
|
22248
|
+
"use strict";
|
|
22249
|
+
import_yaml4 = __toESM(require_dist3(), 1);
|
|
22250
|
+
init_storyboard_parse();
|
|
22251
|
+
init_storyboard_parse();
|
|
22252
|
+
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
22253
|
+
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
22254
|
+
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
22255
|
+
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "keyframe", "motion", "voice", "music", "asset", "eyebrow", "title", "caption", "kicker", "sub"]);
|
|
22256
|
+
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
22257
|
+
}
|
|
22258
|
+
});
|
|
22259
|
+
|
|
22260
|
+
// ../cli/src/commands/_shared/storyboard-source.ts
|
|
22261
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
22262
|
+
import { mkdir as mkdir3, readdir, readFile as readFile4, rename, rm, writeFile as writeFile6 } from "node:fs/promises";
|
|
22263
|
+
import { basename, join as join3 } from "node:path";
|
|
22264
|
+
function sceneFileFrom(dir, filename) {
|
|
22265
|
+
const stem = filename.replace(/\.mdx?$/i, "");
|
|
22266
|
+
const match2 = stem.match(ORDER_PREFIX_RE);
|
|
22267
|
+
const order = match2 ? Number.parseInt(match2[1], 10) : null;
|
|
22268
|
+
const idSource = match2 ? match2[2] : stem;
|
|
22269
|
+
return { id: deriveBeatId(idSource), path: join3(dir, filename), filename, order };
|
|
22270
|
+
}
|
|
22271
|
+
async function listSceneFiles(projectDir) {
|
|
22272
|
+
const dir = join3(projectDir, SCENES_DIRNAME);
|
|
22273
|
+
if (!existsSync2(dir)) return [];
|
|
22274
|
+
const entries2 = await readdir(dir, { withFileTypes: true });
|
|
22275
|
+
const files = entries2.filter((e2) => e2.isFile() && /\.mdx?$/i.test(e2.name) && !e2.name.startsWith("_")).map((e2) => sceneFileFrom(dir, e2.name));
|
|
22276
|
+
return files.sort((a4, b4) => {
|
|
22277
|
+
if (a4.order !== null && b4.order !== null) return a4.order - b4.order;
|
|
22278
|
+
if (a4.order !== null) return -1;
|
|
22279
|
+
if (b4.order !== null) return 1;
|
|
22280
|
+
return a4.filename.localeCompare(b4.filename);
|
|
22281
|
+
});
|
|
22282
|
+
}
|
|
22283
|
+
function detectStoryboardLayout(projectDir, sceneCount) {
|
|
22284
|
+
if (sceneCount > 0) return "bundle";
|
|
22285
|
+
if (existsSync2(join3(projectDir, STORYBOARD_FILENAME))) return "single";
|
|
22286
|
+
return "missing";
|
|
22287
|
+
}
|
|
22288
|
+
function humanise(id) {
|
|
22289
|
+
return id.split(/[-_]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ") || "Scene";
|
|
22290
|
+
}
|
|
22291
|
+
function sceneToBeatSection(scene, contents) {
|
|
22292
|
+
const { data: data2, body } = extractFrontmatter(contents);
|
|
22293
|
+
const cues = { ...data2 ?? {} };
|
|
22294
|
+
delete cues.type;
|
|
22295
|
+
const cueBlock = Object.keys(cues).length > 0 ? "```yaml\n" + (0, import_yaml5.stringify)(cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
22296
|
+
const prose = body.trim();
|
|
22297
|
+
return `## Beat ${scene.id} - ${humanise(scene.id)}
|
|
22298
|
+
|
|
22299
|
+
${cueBlock}${prose}
|
|
22300
|
+
`;
|
|
22301
|
+
}
|
|
22302
|
+
async function loadStoryboard(projectDir) {
|
|
22303
|
+
const storyboardPath = join3(projectDir, STORYBOARD_FILENAME);
|
|
22304
|
+
const scenes = await listSceneFiles(projectDir);
|
|
22305
|
+
const layout = detectStoryboardLayout(projectDir, scenes.length);
|
|
22306
|
+
if (layout === "missing") {
|
|
22307
|
+
return { layout, markdown: "", scenes: [], storyboardPath, strayBeatIds: [] };
|
|
22308
|
+
}
|
|
22309
|
+
const head = existsSync2(storyboardPath) ? await readFile4(storyboardPath, "utf-8") : "";
|
|
22310
|
+
if (layout === "single") {
|
|
22311
|
+
return { layout, markdown: head, scenes: [], storyboardPath, strayBeatIds: [] };
|
|
22312
|
+
}
|
|
22313
|
+
const headingAt = head.search(FIRST_HEADING_RE);
|
|
22314
|
+
const strayBeatIds = headingAt === -1 ? [] : parseStoryboard(head.slice(headingAt)).beats.map((b4) => b4.id);
|
|
22315
|
+
const preamble = headingAt === -1 ? head : head.slice(0, headingAt);
|
|
22316
|
+
const sections = await Promise.all(
|
|
22317
|
+
scenes.map(async (scene) => sceneToBeatSection(scene, await readFile4(scene.path, "utf-8")))
|
|
22318
|
+
);
|
|
22319
|
+
const prefix = preamble.trimEnd();
|
|
22320
|
+
return {
|
|
22321
|
+
layout,
|
|
22322
|
+
markdown: `${prefix}${prefix ? "\n\n" : ""}${sections.join("\n")}`,
|
|
22323
|
+
scenes,
|
|
22324
|
+
storyboardPath,
|
|
22325
|
+
strayBeatIds
|
|
22326
|
+
};
|
|
22327
|
+
}
|
|
22328
|
+
async function loadStoryboardMarkdown(projectDir) {
|
|
22329
|
+
return (await loadStoryboard(projectDir)).markdown;
|
|
22330
|
+
}
|
|
22331
|
+
function sceneFilename(order, id) {
|
|
22332
|
+
const width = order >= 100 ? 3 : 2;
|
|
22333
|
+
return `${String(order).padStart(width, "0")}-${basename(id)}.md`;
|
|
22334
|
+
}
|
|
22335
|
+
function beatToSceneFile(beat, order) {
|
|
22336
|
+
const cues = { type: "Scene", ...beat.cues ?? {} };
|
|
22337
|
+
if (cues.duration === void 0 && beat.duration !== void 0) {
|
|
22338
|
+
cues.duration = beat.duration;
|
|
22339
|
+
}
|
|
22340
|
+
const front = (0, import_yaml5.stringify)(cues, { lineWidth: 0 }).trimEnd();
|
|
22341
|
+
const body = beat.body.trim();
|
|
22342
|
+
return {
|
|
22343
|
+
path: `${SCENES_DIRNAME}/${sceneFilename(order, beat.id)}`,
|
|
22344
|
+
contents: `---
|
|
22345
|
+
${front}
|
|
22346
|
+
---
|
|
22347
|
+
|
|
22348
|
+
${body}
|
|
22349
|
+
`
|
|
22350
|
+
};
|
|
22351
|
+
}
|
|
22352
|
+
function planMigration(markdown) {
|
|
22353
|
+
const parsed = parseStoryboard(markdown);
|
|
22354
|
+
const data2 = extractFrontmatter(markdown).data ?? {};
|
|
22355
|
+
const scenes = parsed.beats.map((beat, index) => beatToSceneFile(beat, index + 1));
|
|
22356
|
+
const frontBlock = Object.keys(data2).length > 0 ? `---
|
|
22357
|
+
${(0, import_yaml5.stringify)(data2, { lineWidth: 0 }).trimEnd()}
|
|
22358
|
+
---
|
|
22359
|
+
|
|
22360
|
+
` : "";
|
|
22361
|
+
const prose = parsed.global.trim();
|
|
22362
|
+
const note = "Scenes live in `scenes/`, one file per scene, and play in filename order.";
|
|
22363
|
+
const storyboardBody = [prose, note].filter(Boolean).join("\n\n");
|
|
22364
|
+
return {
|
|
22365
|
+
scenes,
|
|
22366
|
+
storyboard: {
|
|
22367
|
+
path: STORYBOARD_FILENAME,
|
|
22368
|
+
contents: `${frontBlock}${storyboardBody}
|
|
22369
|
+
`
|
|
22370
|
+
},
|
|
22371
|
+
beatIds: parsed.beats.map((beat) => beat.id)
|
|
22372
|
+
};
|
|
22373
|
+
}
|
|
22374
|
+
async function writeMigration(projectDir, plan2) {
|
|
22375
|
+
await mkdir3(join3(projectDir, SCENES_DIRNAME), { recursive: true });
|
|
22376
|
+
for (const file of plan2.scenes) {
|
|
22377
|
+
await writeFile6(join3(projectDir, file.path), file.contents, "utf-8");
|
|
22378
|
+
}
|
|
22379
|
+
await writeFile6(join3(projectDir, plan2.storyboard.path), plan2.storyboard.contents, "utf-8");
|
|
22380
|
+
}
|
|
22381
|
+
async function writeStoryboardAsBundle(projectDir, markdown) {
|
|
22382
|
+
const plan2 = planMigration(markdown);
|
|
22383
|
+
await writeMigration(projectDir, plan2);
|
|
22384
|
+
return plan2;
|
|
22385
|
+
}
|
|
22386
|
+
function strayBeatIssues(strayBeatIds) {
|
|
22387
|
+
return strayBeatIds.map((beatId) => ({
|
|
22388
|
+
severity: "error",
|
|
22389
|
+
code: "STRAY_BEATS_IN_STORYBOARD",
|
|
22390
|
+
beatId,
|
|
22391
|
+
message: `STORYBOARD.md still contains a "## Beat ${beatId}" section, but this project uses scenes/. That heading is ignored. Move it to scenes/ as its own file, or delete it from STORYBOARD.md.`
|
|
22392
|
+
}));
|
|
22393
|
+
}
|
|
22394
|
+
async function upsertScene(projectDir, opts) {
|
|
22395
|
+
const beatId = deriveBeatId(opts.beatId);
|
|
22396
|
+
const dir = join3(projectDir, SCENES_DIRNAME);
|
|
22397
|
+
await mkdir3(dir, { recursive: true });
|
|
22398
|
+
const cues = {};
|
|
22399
|
+
if (opts.duration !== void 0) cues.duration = opts.duration;
|
|
22400
|
+
if (opts.narration?.trim()) cues.narration = opts.narration.trim();
|
|
22401
|
+
if (opts.backdrop?.trim()) cues.backdrop = opts.backdrop.trim();
|
|
22402
|
+
if (opts.title?.trim()) cues.title = opts.title.trim();
|
|
22403
|
+
const scenes = await listSceneFiles(projectDir);
|
|
22404
|
+
const existing = scenes.find((s2) => s2.id === beatId);
|
|
22405
|
+
if (existing) {
|
|
22406
|
+
const raw2 = await readFile4(existing.path, "utf-8");
|
|
22407
|
+
const { data: data2, body: body2 } = extractFrontmatter(raw2);
|
|
22408
|
+
const merged = { type: "Scene", ...data2 ?? {}, ...cues };
|
|
22409
|
+
const nextBody = opts.body?.trim() || body2.trim();
|
|
22410
|
+
await writeFile6(
|
|
22411
|
+
existing.path,
|
|
22412
|
+
`---
|
|
22413
|
+
${(0, import_yaml5.stringify)(merged, { lineWidth: 0 }).trimEnd()}
|
|
22414
|
+
---
|
|
22415
|
+
|
|
22416
|
+
${nextBody}
|
|
22417
|
+
`,
|
|
22418
|
+
"utf-8"
|
|
22419
|
+
);
|
|
22420
|
+
return { action: "updated", path: existing.path };
|
|
22421
|
+
}
|
|
22422
|
+
const starter = scenes.length > 0 && isStarterStoryboard((await loadStoryboard(projectDir)).markdown);
|
|
22423
|
+
if (starter) {
|
|
22424
|
+
for (const scene of scenes) await rm(scene.path);
|
|
22425
|
+
}
|
|
22426
|
+
const order = starter ? 1 : scenes.length + 1;
|
|
22427
|
+
const path16 = join3(dir, sceneFilename(order, beatId));
|
|
22428
|
+
const front = { type: "Scene", ...cues };
|
|
22429
|
+
const body = opts.body?.trim() || "Scene created with `vibe scene add`. Edit this body if the build flow should recompose it.";
|
|
22430
|
+
await writeFile6(
|
|
22431
|
+
path16,
|
|
22432
|
+
`---
|
|
22433
|
+
${(0, import_yaml5.stringify)(front, { lineWidth: 0 }).trimEnd()}
|
|
22434
|
+
---
|
|
22435
|
+
|
|
22436
|
+
${body}
|
|
22437
|
+
`,
|
|
22438
|
+
"utf-8"
|
|
22439
|
+
);
|
|
22440
|
+
return { action: starter ? "replaced-starter" : "appended", path: path16 };
|
|
22441
|
+
}
|
|
22442
|
+
async function rewriteBundleFromMarkdown(projectDir, markdown) {
|
|
22443
|
+
const plan2 = planMigration(markdown);
|
|
22444
|
+
const keep = new Set(plan2.scenes.map((file) => basename(file.path)));
|
|
22445
|
+
for (const scene of await listSceneFiles(projectDir)) {
|
|
22446
|
+
if (!keep.has(scene.filename)) await rm(scene.path);
|
|
22447
|
+
}
|
|
22448
|
+
await writeMigration(projectDir, plan2);
|
|
22449
|
+
return plan2;
|
|
22450
|
+
}
|
|
22451
|
+
var import_yaml5, SCENES_DIRNAME, STORYBOARD_FILENAME, ORDER_PREFIX_RE, FIRST_HEADING_RE;
|
|
22452
|
+
var init_storyboard_source = __esm({
|
|
22453
|
+
"../cli/src/commands/_shared/storyboard-source.ts"() {
|
|
22454
|
+
"use strict";
|
|
22455
|
+
import_yaml5 = __toESM(require_dist3(), 1);
|
|
22456
|
+
init_frontmatter();
|
|
22457
|
+
init_storyboard_parse();
|
|
22458
|
+
init_storyboard_edit();
|
|
22459
|
+
SCENES_DIRNAME = "scenes";
|
|
22460
|
+
STORYBOARD_FILENAME = "STORYBOARD.md";
|
|
22461
|
+
ORDER_PREFIX_RE = /^(\d+)[-_.]\s*(.+)$/;
|
|
22462
|
+
FIRST_HEADING_RE = /^## .*/m;
|
|
22463
|
+
}
|
|
22464
|
+
});
|
|
22465
|
+
|
|
21962
22466
|
// ../cli/src/commands/_shared/status-jobs.ts
|
|
21963
22467
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
21964
|
-
import { existsSync as
|
|
21965
|
-
import { copyFile, mkdir as
|
|
21966
|
-
import { dirname as dirname3, join as
|
|
22468
|
+
import { existsSync as existsSync3, statSync } from "node:fs";
|
|
22469
|
+
import { copyFile, mkdir as mkdir4, readFile as readFile5, readdir as readdir2, rename as rename2, stat, writeFile as writeFile7 } from "node:fs/promises";
|
|
22470
|
+
import { dirname as dirname3, join as join4, parse as parse2, relative, resolve as resolve5 } from "node:path";
|
|
21967
22471
|
function isLocalJob(record) {
|
|
21968
22472
|
return record.jobType === "build" || record.jobType === "render";
|
|
21969
22473
|
}
|
|
21970
22474
|
function findProjectRoot(start = process.cwd()) {
|
|
21971
22475
|
let dir = resolve5(start);
|
|
21972
22476
|
try {
|
|
21973
|
-
if (
|
|
22477
|
+
if (existsSync3(dir) && statSync(dir).isFile()) dir = dirname3(dir);
|
|
21974
22478
|
} catch {
|
|
21975
22479
|
}
|
|
21976
22480
|
for (; ; ) {
|
|
21977
|
-
if (
|
|
22481
|
+
if (existsSync3(join4(dir, "vibe.config.json")) || existsSync3(join4(dir, "STORYBOARD.md"))) {
|
|
21978
22482
|
return dir;
|
|
21979
22483
|
}
|
|
21980
22484
|
const parent = dirname3(dir);
|
|
@@ -21983,7 +22487,7 @@ function findProjectRoot(start = process.cwd()) {
|
|
|
21983
22487
|
}
|
|
21984
22488
|
}
|
|
21985
22489
|
function jobsDir(projectDir) {
|
|
21986
|
-
return
|
|
22490
|
+
return join4(resolve5(projectDir), ".vibeframe", "jobs");
|
|
21987
22491
|
}
|
|
21988
22492
|
function normalizeJobStatus(status) {
|
|
21989
22493
|
const value = String(status ?? "").toLowerCase();
|
|
@@ -22044,28 +22548,28 @@ async function createAndWriteJobRecord(opts) {
|
|
|
22044
22548
|
}
|
|
22045
22549
|
async function writeJobRecord(record) {
|
|
22046
22550
|
const dir = jobsDir(record.projectDir);
|
|
22047
|
-
await
|
|
22551
|
+
await mkdir4(dir, { recursive: true });
|
|
22048
22552
|
const path16 = jobRecordPath(record.id, record.projectDir);
|
|
22049
22553
|
const tmp = `${path16}.${randomUUID2()}.tmp`;
|
|
22050
|
-
await
|
|
22051
|
-
await
|
|
22554
|
+
await writeFile7(tmp, JSON.stringify(stripUndefined2(record), null, 2) + "\n", "utf-8");
|
|
22555
|
+
await rename2(tmp, path16);
|
|
22052
22556
|
}
|
|
22053
22557
|
async function readJobRecord(jobId, projectDir) {
|
|
22054
22558
|
const id = normalizeJobId(jobId);
|
|
22055
22559
|
const project = resolve5(projectDir ?? findProjectRoot());
|
|
22056
22560
|
const path16 = jobRecordPath(id, project);
|
|
22057
|
-
if (!
|
|
22058
|
-
return parseJobRecord(await
|
|
22561
|
+
if (!existsSync3(path16)) return null;
|
|
22562
|
+
return parseJobRecord(await readFile5(path16, "utf-8"));
|
|
22059
22563
|
}
|
|
22060
22564
|
async function listJobRecords(projectDir) {
|
|
22061
22565
|
const dir = jobsDir(projectDir);
|
|
22062
|
-
if (!
|
|
22063
|
-
const entries2 = await
|
|
22566
|
+
if (!existsSync3(dir)) return [];
|
|
22567
|
+
const entries2 = await readdir2(dir, { withFileTypes: true });
|
|
22064
22568
|
const records = [];
|
|
22065
22569
|
for (const entry of entries2) {
|
|
22066
22570
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
22067
22571
|
try {
|
|
22068
|
-
const parsed = parseJobRecord(await
|
|
22572
|
+
const parsed = parseJobRecord(await readFile5(join4(dir, entry.name), "utf-8"));
|
|
22069
22573
|
if (parsed) records.push(parsed);
|
|
22070
22574
|
} catch {
|
|
22071
22575
|
}
|
|
@@ -22092,7 +22596,7 @@ async function refreshJobRecord(record, opts = {}) {
|
|
|
22092
22596
|
try {
|
|
22093
22597
|
if (record.jobType === "generate-video") {
|
|
22094
22598
|
const output3 = resolveRefreshOutput(record, opts);
|
|
22095
|
-
if (output3) await
|
|
22599
|
+
if (output3) await mkdir4(dirname3(output3), { recursive: true });
|
|
22096
22600
|
const result = await executeVideoStatus({
|
|
22097
22601
|
taskId: record.providerTaskId,
|
|
22098
22602
|
provider: record.provider,
|
|
@@ -22159,7 +22663,7 @@ async function refreshLocalJobRecord(record, opts) {
|
|
|
22159
22663
|
const heartbeatAge = record.heartbeatAt ? Date.now() - new Date(record.heartbeatAt).getTime() : Number.POSITIVE_INFINITY;
|
|
22160
22664
|
const orphaned = !isPidAlive(record.pid) || heartbeatAge > LOCAL_JOB_ORPHAN_AFTER_MS;
|
|
22161
22665
|
if (orphaned) {
|
|
22162
|
-
const hint = `The process that ran this ${record.jobType} job is gone. Check ${
|
|
22666
|
+
const hint = `The process that ran this ${record.jobType} job is gone. Check ${join4(record.projectDir, record.jobType === "render" ? "render-report.json" : "build-report.json")} \u2014 the work may have completed before the process exited.`;
|
|
22163
22667
|
warnings.push(hint);
|
|
22164
22668
|
updated = stripUndefined2({
|
|
22165
22669
|
...record,
|
|
@@ -22322,7 +22826,7 @@ function normalizeJobId(jobId) {
|
|
|
22322
22826
|
return id;
|
|
22323
22827
|
}
|
|
22324
22828
|
function jobRecordPath(jobId, projectDir) {
|
|
22325
|
-
return
|
|
22829
|
+
return join4(jobsDir(projectDir), `${normalizeJobId(jobId)}.json`);
|
|
22326
22830
|
}
|
|
22327
22831
|
function parseJobRecord(raw2) {
|
|
22328
22832
|
const parsed = JSON.parse(raw2);
|
|
@@ -22375,21 +22879,21 @@ async function downloadUrl(url, outputPath) {
|
|
|
22375
22879
|
const response = await fetch(url);
|
|
22376
22880
|
if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`);
|
|
22377
22881
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
22378
|
-
await
|
|
22379
|
-
await
|
|
22882
|
+
await mkdir4(dirname3(outputPath), { recursive: true });
|
|
22883
|
+
await writeFile7(outputPath, buffer);
|
|
22380
22884
|
return outputPath;
|
|
22381
22885
|
}
|
|
22382
22886
|
async function maybeCacheOutput(record) {
|
|
22383
22887
|
if (record.status !== "completed" || !record.outputPath || !record.cachePath) return;
|
|
22384
22888
|
try {
|
|
22385
|
-
await
|
|
22889
|
+
await mkdir4(dirname3(record.cachePath), { recursive: true });
|
|
22386
22890
|
await copyFile(record.outputPath, record.cachePath);
|
|
22387
22891
|
} catch {
|
|
22388
22892
|
}
|
|
22389
22893
|
}
|
|
22390
22894
|
async function maybeWriteCompletedAssetMetadata(record) {
|
|
22391
22895
|
const kind3 = assetKindForJob(record);
|
|
22392
|
-
if (record.status !== "completed" || !kind3 || !record.beatId || !record.assetCue || !record.cacheKey || !record.outputPath || !
|
|
22896
|
+
if (record.status !== "completed" || !kind3 || !record.beatId || !record.assetCue || !record.cacheKey || !record.outputPath || !existsSync3(record.outputPath)) {
|
|
22393
22897
|
return;
|
|
22394
22898
|
}
|
|
22395
22899
|
try {
|
|
@@ -22408,7 +22912,7 @@ async function maybeWriteCompletedAssetMetadata(record) {
|
|
|
22408
22912
|
}
|
|
22409
22913
|
}
|
|
22410
22914
|
async function refreshBuildReportFromJobs(projectDir, records) {
|
|
22411
|
-
const reportPath =
|
|
22915
|
+
const reportPath = join4(projectDir, "build-report.json");
|
|
22412
22916
|
const report = await readJson(reportPath);
|
|
22413
22917
|
if (!report || !Array.isArray(report.beats)) return;
|
|
22414
22918
|
let changed = false;
|
|
@@ -22456,12 +22960,12 @@ async function refreshBuildReportFromJobs(projectDir, records) {
|
|
|
22456
22960
|
}
|
|
22457
22961
|
if (!changed) return;
|
|
22458
22962
|
try {
|
|
22459
|
-
await
|
|
22963
|
+
await writeFile7(reportPath, JSON.stringify(stripUndefined2(report), null, 2) + "\n", "utf-8");
|
|
22460
22964
|
} catch {
|
|
22461
22965
|
}
|
|
22462
22966
|
}
|
|
22463
22967
|
async function readBuildSummary(projectDir) {
|
|
22464
|
-
const reportPath =
|
|
22968
|
+
const reportPath = join4(projectDir, "build-report.json");
|
|
22465
22969
|
const report = await readJson(reportPath);
|
|
22466
22970
|
if (!report) return null;
|
|
22467
22971
|
const info = await statOrNull(reportPath);
|
|
@@ -22484,7 +22988,7 @@ async function readBuildSummary(projectDir) {
|
|
|
22484
22988
|
});
|
|
22485
22989
|
}
|
|
22486
22990
|
async function readReviewSummary(projectDir) {
|
|
22487
|
-
const reportPath =
|
|
22991
|
+
const reportPath = join4(projectDir, "review-report.json");
|
|
22488
22992
|
const report = await readJson(reportPath);
|
|
22489
22993
|
if (!report) return null;
|
|
22490
22994
|
const info = await statOrNull(reportPath);
|
|
@@ -22573,16 +23077,16 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
22573
23077
|
if (fromBeats) return fromBeats;
|
|
22574
23078
|
if (build.beats) return augmentBeatReadinessFromJobs(build.beats, records, report?.jobs);
|
|
22575
23079
|
}
|
|
22576
|
-
const storyboardPath =
|
|
22577
|
-
if (!
|
|
23080
|
+
const storyboardPath = join4(projectDir, "STORYBOARD.md");
|
|
23081
|
+
if (!existsSync3(storyboardPath)) {
|
|
22578
23082
|
return { total: 0, assetsReady: 0, compositionsReady: 0, needsAuthor: [] };
|
|
22579
23083
|
}
|
|
22580
23084
|
try {
|
|
22581
|
-
const parsed = parseStoryboard(await
|
|
23085
|
+
const parsed = parseStoryboard(await loadStoryboardMarkdown(projectDir));
|
|
22582
23086
|
const needsAuthor = [];
|
|
22583
23087
|
let compositionsReady = 0;
|
|
22584
23088
|
for (const beat of parsed.beats) {
|
|
22585
|
-
if (
|
|
23089
|
+
if (existsSync3(join4(projectDir, "compositions", `scene-${beat.id}.html`))) {
|
|
22586
23090
|
compositionsReady += 1;
|
|
22587
23091
|
} else {
|
|
22588
23092
|
needsAuthor.push(beat.id);
|
|
@@ -22600,7 +23104,7 @@ async function readProjectBeatReadiness(projectDir, build, records) {
|
|
|
22600
23104
|
}
|
|
22601
23105
|
function deriveProjectWorkflow(opts) {
|
|
22602
23106
|
const retryWith = [];
|
|
22603
|
-
const hasStoryboard =
|
|
23107
|
+
const hasStoryboard = existsSync3(join4(opts.project, "STORYBOARD.md"));
|
|
22604
23108
|
if (!hasStoryboard && !opts.build) {
|
|
22605
23109
|
retryWith.push(`vibe init ${opts.project} --from "<brief>" --json`);
|
|
22606
23110
|
return { status: "empty", currentStage: "init", retryWith };
|
|
@@ -22696,7 +23200,7 @@ function beatReadinessFromBuildBeats(projectDir, beats, records = [], reportJobs
|
|
|
22696
23200
|
if (buildBeatAssetsReady(record) || (id ? buildBeatJobsReady(id, records, reportJobs) : false))
|
|
22697
23201
|
assetsReady += 1;
|
|
22698
23202
|
const compositionPath = typeof record.compositionPath === "string" ? record.compositionPath : id ? `compositions/scene-${id}.html` : void 0;
|
|
22699
|
-
if (compositionPath &&
|
|
23203
|
+
if (compositionPath && existsSync3(resolve5(projectDir, compositionPath))) {
|
|
22700
23204
|
compositionsReady += 1;
|
|
22701
23205
|
} else if (id) {
|
|
22702
23206
|
needsAuthor.push(id);
|
|
@@ -22804,7 +23308,7 @@ function projectRelativePath(projectDir, path16) {
|
|
|
22804
23308
|
}
|
|
22805
23309
|
async function readJson(path16) {
|
|
22806
23310
|
try {
|
|
22807
|
-
return JSON.parse(await
|
|
23311
|
+
return JSON.parse(await readFile5(path16, "utf-8"));
|
|
22808
23312
|
} catch {
|
|
22809
23313
|
return null;
|
|
22810
23314
|
}
|
|
@@ -22836,13 +23340,14 @@ var init_status_jobs = __esm({
|
|
|
22836
23340
|
init_build_asset_metadata();
|
|
22837
23341
|
init_review_report();
|
|
22838
23342
|
init_storyboard_parse();
|
|
23343
|
+
init_storyboard_source();
|
|
22839
23344
|
LOCAL_JOB_ORPHAN_AFTER_MS = 9e4;
|
|
22840
23345
|
}
|
|
22841
23346
|
});
|
|
22842
23347
|
|
|
22843
23348
|
// ../cli/src/commands/_shared/project-config.ts
|
|
22844
|
-
import { existsSync as
|
|
22845
|
-
import { readFile as
|
|
23349
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
23350
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
22846
23351
|
import { resolve as resolve6 } from "node:path";
|
|
22847
23352
|
function defaultProjectConfig(opts) {
|
|
22848
23353
|
return {
|
|
@@ -22899,9 +23404,9 @@ async function readProjectConfig(projectDir) {
|
|
|
22899
23404
|
const dir = resolve6(projectDir);
|
|
22900
23405
|
const canonicalPath = resolve6(dir, VIBE_CONFIG_FILENAME);
|
|
22901
23406
|
const legacyPath = resolve6(dir, LEGACY_VIBE_PROJECT_FILENAME);
|
|
22902
|
-
if (
|
|
23407
|
+
if (existsSync4(canonicalPath)) {
|
|
22903
23408
|
try {
|
|
22904
|
-
const raw2 = await
|
|
23409
|
+
const raw2 = await readFile6(canonicalPath, "utf-8");
|
|
22905
23410
|
const parsed = JSON.parse(raw2);
|
|
22906
23411
|
const name = typeof parsed.name === "string" && parsed.name ? parsed.name : dir.split(/[\\/]/).filter(Boolean).pop() ?? "video";
|
|
22907
23412
|
const fallback2 = defaultProjectConfig({
|
|
@@ -22919,10 +23424,10 @@ async function readProjectConfig(projectDir) {
|
|
|
22919
23424
|
} catch {
|
|
22920
23425
|
}
|
|
22921
23426
|
}
|
|
22922
|
-
if (
|
|
23427
|
+
if (existsSync4(legacyPath)) {
|
|
22923
23428
|
try {
|
|
22924
|
-
const raw2 = await
|
|
22925
|
-
const legacy = (0,
|
|
23429
|
+
const raw2 = await readFile6(legacyPath, "utf-8");
|
|
23430
|
+
const legacy = (0, import_yaml6.parse)(raw2);
|
|
22926
23431
|
const name = legacy?.name ?? dir.split(/[\\/]/).filter(Boolean).pop() ?? "video";
|
|
22927
23432
|
const config4 = defaultProjectConfig({
|
|
22928
23433
|
name,
|
|
@@ -22954,19 +23459,19 @@ async function readProjectConfig(projectDir) {
|
|
|
22954
23459
|
legacy: false
|
|
22955
23460
|
};
|
|
22956
23461
|
}
|
|
22957
|
-
var
|
|
23462
|
+
var import_yaml6, VIBE_CONFIG_FILENAME, LEGACY_VIBE_PROJECT_FILENAME;
|
|
22958
23463
|
var init_project_config = __esm({
|
|
22959
23464
|
"../cli/src/commands/_shared/project-config.ts"() {
|
|
22960
23465
|
"use strict";
|
|
22961
|
-
|
|
23466
|
+
import_yaml6 = __toESM(require_dist3(), 1);
|
|
22962
23467
|
VIBE_CONFIG_FILENAME = "vibe.config.json";
|
|
22963
23468
|
LEGACY_VIBE_PROJECT_FILENAME = "vibe.project.yaml";
|
|
22964
23469
|
}
|
|
22965
23470
|
});
|
|
22966
23471
|
|
|
22967
23472
|
// ../cli/src/commands/_shared/scene-project.ts
|
|
22968
|
-
import { mkdir as
|
|
22969
|
-
import { resolve as resolve7, basename } from "node:path";
|
|
23473
|
+
import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile8, access as access3 } from "node:fs/promises";
|
|
23474
|
+
import { resolve as resolve7, basename as basename2 } from "node:path";
|
|
22970
23475
|
function isSceneKind(value) {
|
|
22971
23476
|
return VALID_SCENE_KINDS.includes(value);
|
|
22972
23477
|
}
|
|
@@ -23313,15 +23818,25 @@ media in \`references/\`; older VibeFrame versions vendored composition rules
|
|
|
23313
23818
|
there, and current installs keep the rules under \`.agents/skills/hyperframes/\`
|
|
23314
23819
|
via \`vibe scene install-skill\`.
|
|
23315
23820
|
|
|
23316
|
-
|
|
23317
|
-
|
|
23821
|
+
Scenes live in \`scenes/\`, one file per scene, and play in filename order.
|
|
23822
|
+
Each scene is a markdown file whose frontmatter carries its cues:
|
|
23318
23823
|
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
|
|
23322
|
-
narration: "
|
|
23323
|
-
|
|
23324
|
-
|
|
23824
|
+
---
|
|
23825
|
+
type: Scene
|
|
23826
|
+
duration: 5
|
|
23827
|
+
narration: "One crisp sentence."
|
|
23828
|
+
backdrop: "Clean editorial background plate, generous negative space"
|
|
23829
|
+
---
|
|
23830
|
+
|
|
23831
|
+
Direction prose for this scene goes in the body.
|
|
23832
|
+
|
|
23833
|
+
When a scene should reuse a local file, give the cue a project-relative path
|
|
23834
|
+
instead of a prompt:
|
|
23835
|
+
|
|
23836
|
+
backdrop: "media/product-shot.png" # existing still image
|
|
23837
|
+
video: "media/broll.mp4" # existing video/B-roll
|
|
23838
|
+
narration: "media/voice.wav" # existing recorded narration
|
|
23839
|
+
asset: "media/logo.png" # generic local asset reference
|
|
23325
23840
|
|
|
23326
23841
|
Use text cues when you want VibeFrame to generate an asset. Use path cues
|
|
23327
23842
|
when you want VibeFrame to reuse a local file. Avoid absolute paths or parent
|
|
@@ -23561,17 +24076,17 @@ async function pathExists(p2) {
|
|
|
23561
24076
|
}
|
|
23562
24077
|
async function scaffoldSceneProject(opts) {
|
|
23563
24078
|
const dir = resolve7(opts.dir);
|
|
23564
|
-
const name = opts.name ??
|
|
24079
|
+
const name = opts.name ?? basename2(dir);
|
|
23565
24080
|
const aspect = opts.aspect ?? "16:9";
|
|
23566
24081
|
const duration = opts.duration ?? 10;
|
|
23567
24082
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
23568
24083
|
const profile = opts.profile ?? "full";
|
|
23569
24084
|
const kind3 = opts.kind ?? DEFAULT_SCENE_KIND;
|
|
23570
|
-
await
|
|
24085
|
+
await mkdir5(dir, { recursive: true });
|
|
23571
24086
|
if (profile === "full") {
|
|
23572
|
-
await
|
|
23573
|
-
await
|
|
23574
|
-
await
|
|
24087
|
+
await mkdir5(resolve7(dir, "compositions"), { recursive: true });
|
|
24088
|
+
await mkdir5(resolve7(dir, "assets"), { recursive: true });
|
|
24089
|
+
await mkdir5(resolve7(dir, "renders"), { recursive: true });
|
|
23575
24090
|
}
|
|
23576
24091
|
const created = [];
|
|
23577
24092
|
const skipped2 = [];
|
|
@@ -23580,20 +24095,20 @@ async function scaffoldSceneProject(opts) {
|
|
|
23580
24095
|
const hfPath = resolve7(dir, "hyperframes.json");
|
|
23581
24096
|
const hfDefaults = buildHyperframesConfig();
|
|
23582
24097
|
if (await pathExists(hfPath)) {
|
|
23583
|
-
const existingRaw = await
|
|
24098
|
+
const existingRaw = await readFile7(hfPath, "utf-8");
|
|
23584
24099
|
const existing = JSON.parse(existingRaw);
|
|
23585
24100
|
const mergedConfig = mergeHyperframesConfig(existing, hfDefaults);
|
|
23586
|
-
await
|
|
24101
|
+
await writeFile8(hfPath, JSON.stringify(mergedConfig, null, 2) + "\n", "utf-8");
|
|
23587
24102
|
merged.push(hfPath);
|
|
23588
24103
|
} else {
|
|
23589
|
-
await
|
|
24104
|
+
await writeFile8(hfPath, JSON.stringify(hfDefaults, null, 2) + "\n", "utf-8");
|
|
23590
24105
|
created.push(hfPath);
|
|
23591
24106
|
}
|
|
23592
24107
|
const metaPath = resolve7(dir, "meta.json");
|
|
23593
24108
|
if (await pathExists(metaPath)) {
|
|
23594
24109
|
skipped2.push(metaPath);
|
|
23595
24110
|
} else {
|
|
23596
|
-
await
|
|
24111
|
+
await writeFile8(
|
|
23597
24112
|
metaPath,
|
|
23598
24113
|
JSON.stringify(buildHyperframesMeta(name, now), null, 2) + "\n",
|
|
23599
24114
|
"utf-8"
|
|
@@ -23604,7 +24119,7 @@ async function scaffoldSceneProject(opts) {
|
|
|
23604
24119
|
if (await pathExists(rootPath)) {
|
|
23605
24120
|
skipped2.push(rootPath);
|
|
23606
24121
|
} else {
|
|
23607
|
-
await
|
|
24122
|
+
await writeFile8(rootPath, buildEmptyRootHtml({ aspect, duration }), "utf-8");
|
|
23608
24123
|
created.push(rootPath);
|
|
23609
24124
|
}
|
|
23610
24125
|
}
|
|
@@ -23612,7 +24127,7 @@ async function scaffoldSceneProject(opts) {
|
|
|
23612
24127
|
if (await pathExists(vibeConfigJsonPath)) {
|
|
23613
24128
|
skipped2.push(vibeConfigJsonPath);
|
|
23614
24129
|
} else {
|
|
23615
|
-
await
|
|
24130
|
+
await writeFile8(vibeConfigJsonPath, projectConfigJson({ name, aspect, kind: kind3 }), "utf-8");
|
|
23616
24131
|
created.push(vibeConfigJsonPath);
|
|
23617
24132
|
}
|
|
23618
24133
|
if (profile === "agent" || profile === "full") {
|
|
@@ -23620,22 +24135,22 @@ async function scaffoldSceneProject(opts) {
|
|
|
23620
24135
|
if (await pathExists(agentsPath)) {
|
|
23621
24136
|
skipped2.push(agentsPath);
|
|
23622
24137
|
} else {
|
|
23623
|
-
await
|
|
24138
|
+
await writeFile8(agentsPath, buildProjectAgentsMd(name), "utf-8");
|
|
23624
24139
|
created.push(agentsPath);
|
|
23625
24140
|
}
|
|
23626
24141
|
const claudePath = resolve7(dir, "CLAUDE.md");
|
|
23627
24142
|
if (await pathExists(claudePath)) {
|
|
23628
|
-
const existing = await
|
|
24143
|
+
const existing = await readFile7(claudePath, "utf-8");
|
|
23629
24144
|
if (existing.includes("@AGENTS.md")) {
|
|
23630
24145
|
skipped2.push(claudePath);
|
|
23631
24146
|
} else {
|
|
23632
|
-
await
|
|
24147
|
+
await writeFile8(claudePath, `@AGENTS.md
|
|
23633
24148
|
|
|
23634
24149
|
${existing}`, "utf-8");
|
|
23635
24150
|
merged.push(claudePath);
|
|
23636
24151
|
}
|
|
23637
24152
|
} else {
|
|
23638
|
-
await
|
|
24153
|
+
await writeFile8(claudePath, buildProjectClaudeMd(name), "utf-8");
|
|
23639
24154
|
created.push(claudePath);
|
|
23640
24155
|
}
|
|
23641
24156
|
}
|
|
@@ -23643,21 +24158,22 @@ ${existing}`, "utf-8");
|
|
|
23643
24158
|
if (await pathExists(designPath)) {
|
|
23644
24159
|
skipped2.push(designPath);
|
|
23645
24160
|
} else {
|
|
23646
|
-
await
|
|
24161
|
+
await writeFile8(designPath, buildDesignMd({ name, style: opts.visualStyle }), "utf-8");
|
|
23647
24162
|
created.push(designPath);
|
|
23648
24163
|
}
|
|
23649
24164
|
const storyboardPath = resolve7(dir, "STORYBOARD.md");
|
|
23650
24165
|
if (await pathExists(storyboardPath)) {
|
|
23651
24166
|
skipped2.push(storyboardPath);
|
|
23652
24167
|
} else {
|
|
23653
|
-
await
|
|
24168
|
+
const plan2 = await writeStoryboardAsBundle(dir, buildStoryboardMd(name, duration));
|
|
23654
24169
|
created.push(storyboardPath);
|
|
24170
|
+
for (const file of plan2.scenes) created.push(resolve7(dir, file.path));
|
|
23655
24171
|
}
|
|
23656
24172
|
const scriptPath = resolve7(dir, "SCRIPT.md");
|
|
23657
24173
|
if (await pathExists(scriptPath)) {
|
|
23658
24174
|
skipped2.push(scriptPath);
|
|
23659
24175
|
} else {
|
|
23660
|
-
await
|
|
24176
|
+
await writeFile8(scriptPath, buildScriptMd(name, kind3), "utf-8");
|
|
23661
24177
|
created.push(scriptPath);
|
|
23662
24178
|
}
|
|
23663
24179
|
if (kindHasCast(kind3)) {
|
|
@@ -23665,7 +24181,7 @@ ${existing}`, "utf-8");
|
|
|
23665
24181
|
if (await pathExists(charactersPath)) {
|
|
23666
24182
|
skipped2.push(charactersPath);
|
|
23667
24183
|
} else {
|
|
23668
|
-
await
|
|
24184
|
+
await writeFile8(charactersPath, buildCharactersMd(name), "utf-8");
|
|
23669
24185
|
created.push(charactersPath);
|
|
23670
24186
|
}
|
|
23671
24187
|
}
|
|
@@ -23673,7 +24189,7 @@ ${existing}`, "utf-8");
|
|
|
23673
24189
|
if (await pathExists(gitignorePath)) {
|
|
23674
24190
|
skipped2.push(gitignorePath);
|
|
23675
24191
|
} else {
|
|
23676
|
-
await
|
|
24192
|
+
await writeFile8(gitignorePath, buildSceneGitignore(), "utf-8");
|
|
23677
24193
|
created.push(gitignorePath);
|
|
23678
24194
|
}
|
|
23679
24195
|
return { created, skipped: skipped2, merged, groups: describeSceneScaffold({ dir, profile }) };
|
|
@@ -23682,6 +24198,7 @@ var VALID_SCENE_KINDS, DEFAULT_SCENE_KIND, ASPECT_DIMS;
|
|
|
23682
24198
|
var init_scene_project = __esm({
|
|
23683
24199
|
"../cli/src/commands/_shared/scene-project.ts"() {
|
|
23684
24200
|
"use strict";
|
|
24201
|
+
init_storyboard_source();
|
|
23685
24202
|
init_project_config();
|
|
23686
24203
|
VALID_SCENE_KINDS = [
|
|
23687
24204
|
"cinema",
|
|
@@ -35218,7 +35735,7 @@ var require_source_map = __commonJS({
|
|
|
35218
35735
|
var require_previous_map = __commonJS({
|
|
35219
35736
|
"../../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/previous-map.js"(exports, module) {
|
|
35220
35737
|
"use strict";
|
|
35221
|
-
var { existsSync:
|
|
35738
|
+
var { existsSync: existsSync86, readFileSync: readFileSync23 } = __require("fs");
|
|
35222
35739
|
var { dirname: dirname40, join: join78 } = __require("path");
|
|
35223
35740
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
35224
35741
|
function fromBase64(str2) {
|
|
@@ -35281,7 +35798,7 @@ var require_previous_map = __commonJS({
|
|
|
35281
35798
|
}
|
|
35282
35799
|
loadFile(path16) {
|
|
35283
35800
|
this.root = dirname40(path16);
|
|
35284
|
-
if (
|
|
35801
|
+
if (existsSync86(path16)) {
|
|
35285
35802
|
this.mapFile = path16;
|
|
35286
35803
|
return readFileSync23(path16, "utf-8").toString().trim();
|
|
35287
35804
|
}
|
|
@@ -87270,7 +87787,7 @@ var require_yauzl = __commonJS({
|
|
|
87270
87787
|
// ../../node_modules/.pnpm/@puppeteer+browsers@3.0.6_yauzl@2.10.0/node_modules/@puppeteer/browsers/lib/fileUtil.js
|
|
87271
87788
|
import { spawnSync, spawn, execFile as execFile2 } from "node:child_process";
|
|
87272
87789
|
import { constants as constants2, createReadStream, createWriteStream as createWriteStream2 } from "node:fs";
|
|
87273
|
-
import { mkdir as
|
|
87790
|
+
import { mkdir as mkdir7, readdir as readdir4, symlink as symlink2 } from "node:fs/promises";
|
|
87274
87791
|
import * as path9 from "node:path";
|
|
87275
87792
|
import { Stream, Writable as Writable2 } from "node:stream";
|
|
87276
87793
|
import { pipeline } from "node:stream/promises";
|
|
@@ -87280,12 +87797,12 @@ async function unpackArchive(archivePath, folderPath) {
|
|
|
87280
87797
|
folderPath = path9.resolve(process.cwd(), folderPath);
|
|
87281
87798
|
}
|
|
87282
87799
|
if (archivePath.endsWith(".zip")) {
|
|
87283
|
-
await
|
|
87800
|
+
await mkdir7(folderPath, { recursive: true });
|
|
87284
87801
|
await extractZip(archivePath, folderPath);
|
|
87285
87802
|
} else if (archivePath.endsWith(".tar.bz2")) {
|
|
87286
87803
|
await extractTar(archivePath, folderPath, "bzip2");
|
|
87287
87804
|
} else if (archivePath.endsWith(".dmg")) {
|
|
87288
|
-
await
|
|
87805
|
+
await mkdir7(folderPath);
|
|
87289
87806
|
await installDMG(archivePath, folderPath);
|
|
87290
87807
|
} else if (archivePath.endsWith(".exe")) {
|
|
87291
87808
|
const result = spawnSync(archivePath, [`/ExtractDir=${folderPath}`], {
|
|
@@ -87374,7 +87891,7 @@ async function installDMG(dmgPath, folderPath) {
|
|
|
87374
87891
|
}
|
|
87375
87892
|
const mountPath = volumes[0];
|
|
87376
87893
|
try {
|
|
87377
|
-
const fileNames = await
|
|
87894
|
+
const fileNames = await readdir4(mountPath);
|
|
87378
87895
|
const appName = fileNames.find((item) => {
|
|
87379
87896
|
return typeof item === "string" && item.endsWith(".app");
|
|
87380
87897
|
});
|
|
@@ -87473,10 +87990,10 @@ async function extractZipEntry(zipFile, entry, folderPath) {
|
|
|
87473
87990
|
const mode = unixMode === 0 ? isDirectory2 ? 493 : 420 : unixMode & 511;
|
|
87474
87991
|
const destination = path9.join(folderPath, entry.fileName);
|
|
87475
87992
|
if (isDirectory2) {
|
|
87476
|
-
await
|
|
87993
|
+
await mkdir7(destination, { recursive: true, mode });
|
|
87477
87994
|
return;
|
|
87478
87995
|
}
|
|
87479
|
-
await
|
|
87996
|
+
await mkdir7(path9.dirname(destination), { recursive: true });
|
|
87480
87997
|
const readStream = await promisify2(zipFile.openReadStream.bind(zipFile))(entry);
|
|
87481
87998
|
if (isSymlink) {
|
|
87482
87999
|
const chunks = [];
|
|
@@ -87643,8 +88160,8 @@ var init_ProgressBar = __esm({
|
|
|
87643
88160
|
// ../../node_modules/.pnpm/@puppeteer+browsers@3.0.6_yauzl@2.10.0/node_modules/@puppeteer/browsers/lib/install.js
|
|
87644
88161
|
import assert3 from "node:assert";
|
|
87645
88162
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
87646
|
-
import { existsSync as
|
|
87647
|
-
import { mkdir as
|
|
88163
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
|
|
88164
|
+
import { mkdir as mkdir8, unlink } from "node:fs/promises";
|
|
87648
88165
|
import os6 from "node:os";
|
|
87649
88166
|
import path10 from "node:path";
|
|
87650
88167
|
function debugTime(label) {
|
|
@@ -87696,8 +88213,8 @@ async function installWithProviders(options) {
|
|
|
87696
88213
|
continue;
|
|
87697
88214
|
}
|
|
87698
88215
|
debugInstall?.(`Successfully got URL from ${provider.getName()}: ${url}`);
|
|
87699
|
-
if (!
|
|
87700
|
-
await
|
|
88216
|
+
if (!existsSync5(browserRoot)) {
|
|
88217
|
+
await mkdir8(browserRoot, { recursive: true });
|
|
87701
88218
|
}
|
|
87702
88219
|
return await installUrl(url, options, provider);
|
|
87703
88220
|
} catch (err) {
|
|
@@ -87728,7 +88245,7 @@ async function installDeps(installedBrowser) {
|
|
|
87728
88245
|
return;
|
|
87729
88246
|
}
|
|
87730
88247
|
const depsPath = path10.join(path10.dirname(installedBrowser.executablePath), "deb.deps");
|
|
87731
|
-
if (!
|
|
88248
|
+
if (!existsSync5(depsPath)) {
|
|
87732
88249
|
debugInstall?.(`deb.deps file was not found at ${depsPath}`);
|
|
87733
88250
|
return;
|
|
87734
88251
|
}
|
|
@@ -87769,14 +88286,14 @@ async function installUrl(url, options, provider) {
|
|
|
87769
88286
|
const cache = new Cache(options.cacheDir);
|
|
87770
88287
|
const browserRoot = cache.browserRoot(options.browser);
|
|
87771
88288
|
const archivePath = path10.join(browserRoot, `${options.buildId}-${fileName}`);
|
|
87772
|
-
if (!
|
|
87773
|
-
await
|
|
88289
|
+
if (!existsSync5(browserRoot)) {
|
|
88290
|
+
await mkdir8(browserRoot, { recursive: true });
|
|
87774
88291
|
}
|
|
87775
88292
|
if (options.expectedHash) {
|
|
87776
88293
|
debugInstall?.(`Using provided checksum for ${fileName}: ${options.expectedHash}`);
|
|
87777
88294
|
}
|
|
87778
88295
|
if (!options.unpack) {
|
|
87779
|
-
if (
|
|
88296
|
+
if (existsSync5(archivePath)) {
|
|
87780
88297
|
return archivePath;
|
|
87781
88298
|
}
|
|
87782
88299
|
debugInstall?.(`Downloading binary from ${url}`);
|
|
@@ -87797,8 +88314,8 @@ async function installUrl(url, options, provider) {
|
|
|
87797
88314
|
cache.writeExecutablePath(options.browser, options.platform, options.buildId, relativeExecutablePath7);
|
|
87798
88315
|
}
|
|
87799
88316
|
try {
|
|
87800
|
-
if (
|
|
87801
|
-
if (!
|
|
88317
|
+
if (existsSync5(outputPath)) {
|
|
88318
|
+
if (!existsSync5(installedBrowser.executablePath)) {
|
|
87802
88319
|
throw new Error(`The browser folder (${outputPath}) exists but the executable (${installedBrowser.executablePath}) is missing`);
|
|
87803
88320
|
}
|
|
87804
88321
|
await runSetup(installedBrowser);
|
|
@@ -87807,7 +88324,7 @@ async function installUrl(url, options, provider) {
|
|
|
87807
88324
|
}
|
|
87808
88325
|
return installedBrowser;
|
|
87809
88326
|
}
|
|
87810
|
-
if (!
|
|
88327
|
+
if (!existsSync5(archivePath)) {
|
|
87811
88328
|
debugInstall?.(`Downloading binary from ${url}`);
|
|
87812
88329
|
try {
|
|
87813
88330
|
debugTime("download");
|
|
@@ -87836,7 +88353,7 @@ async function installUrl(url, options, provider) {
|
|
|
87836
88353
|
}
|
|
87837
88354
|
return installedBrowser;
|
|
87838
88355
|
} finally {
|
|
87839
|
-
if (
|
|
88356
|
+
if (existsSync5(archivePath)) {
|
|
87840
88357
|
await unlink(archivePath);
|
|
87841
88358
|
}
|
|
87842
88359
|
}
|
|
@@ -87847,7 +88364,7 @@ async function runSetup(installedBrowser) {
|
|
|
87847
88364
|
debugTime("permissions");
|
|
87848
88365
|
const browserDir = path10.dirname(installedBrowser.executablePath);
|
|
87849
88366
|
const setupExePath = path10.join(browserDir, "setup.exe");
|
|
87850
|
-
if (!
|
|
88367
|
+
if (!existsSync5(setupExePath)) {
|
|
87851
88368
|
return;
|
|
87852
88369
|
}
|
|
87853
88370
|
spawnSync2(path10.join(browserDir, "setup.exe"), [`--configure-browser-in-directory=` + browserDir], {
|
|
@@ -89611,7 +90128,7 @@ var init_process_argv = __esm({
|
|
|
89611
90128
|
});
|
|
89612
90129
|
|
|
89613
90130
|
// ../../node_modules/.pnpm/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js
|
|
89614
|
-
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as
|
|
90131
|
+
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile9 } from "fs";
|
|
89615
90132
|
import { format as format2 } from "util";
|
|
89616
90133
|
import { resolve as resolve12 } from "path";
|
|
89617
90134
|
var node_default;
|
|
@@ -89620,7 +90137,7 @@ var init_node = __esm({
|
|
|
89620
90137
|
node_default = {
|
|
89621
90138
|
fs: {
|
|
89622
90139
|
readFileSync: readFileSync4,
|
|
89623
|
-
writeFile:
|
|
90140
|
+
writeFile: writeFile9
|
|
89624
90141
|
},
|
|
89625
90142
|
format: format2,
|
|
89626
90143
|
resolve: resolve12,
|
|
@@ -89841,7 +90358,7 @@ var require_get_caller_file = __commonJS({
|
|
|
89841
90358
|
import { notStrictEqual, strictEqual } from "assert";
|
|
89842
90359
|
import { inspect } from "util";
|
|
89843
90360
|
import { fileURLToPath } from "url";
|
|
89844
|
-
import { basename as
|
|
90361
|
+
import { basename as basename4, dirname as dirname7, extname as extname2, relative as relative3, resolve as resolve13, join as join7 } from "path";
|
|
89845
90362
|
import { createRequire as createRequire2 } from "node:module";
|
|
89846
90363
|
import { readFileSync as readFileSync5, readdirSync as readdirSync2 } from "node:fs";
|
|
89847
90364
|
var import_get_caller_file, __dirname2, mainFilename, require3, esm_default;
|
|
@@ -89873,12 +90390,12 @@ var init_esm2 = __esm({
|
|
|
89873
90390
|
mainFilename: mainFilename || process.cwd(),
|
|
89874
90391
|
Parser: lib_default,
|
|
89875
90392
|
path: {
|
|
89876
|
-
basename:
|
|
90393
|
+
basename: basename4,
|
|
89877
90394
|
dirname: dirname7,
|
|
89878
90395
|
extname: extname2,
|
|
89879
90396
|
relative: relative3,
|
|
89880
90397
|
resolve: resolve13,
|
|
89881
|
-
join:
|
|
90398
|
+
join: join7
|
|
89882
90399
|
},
|
|
89883
90400
|
process: {
|
|
89884
90401
|
argv: () => process.argv,
|
|
@@ -94128,9 +94645,9 @@ var init_PipeTransport = __esm({
|
|
|
94128
94645
|
});
|
|
94129
94646
|
|
|
94130
94647
|
// ../../node_modules/.pnpm/puppeteer-core@25.3.0_yauzl@2.10.0/node_modules/puppeteer-core/lib/puppeteer/node/BrowserLauncher.js
|
|
94131
|
-
import { existsSync as
|
|
94648
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
94132
94649
|
import { tmpdir } from "node:os";
|
|
94133
|
-
import { join as
|
|
94650
|
+
import { join as join8 } from "node:path";
|
|
94134
94651
|
function getBrowserTypeDisplayName(browserType) {
|
|
94135
94652
|
switch (browserType) {
|
|
94136
94653
|
case Browser3.FIREFOX:
|
|
@@ -94187,7 +94704,7 @@ var init_BrowserLauncher = __esm({
|
|
|
94187
94704
|
...options,
|
|
94188
94705
|
protocol
|
|
94189
94706
|
});
|
|
94190
|
-
if (!
|
|
94707
|
+
if (!existsSync6(launchArgs.executablePath)) {
|
|
94191
94708
|
throw new Error(`Browser was not found at the configured executablePath (${launchArgs.executablePath})`);
|
|
94192
94709
|
}
|
|
94193
94710
|
const usePipe = launchArgs.args.includes("--remote-debugging-pipe");
|
|
@@ -94264,7 +94781,7 @@ var init_BrowserLauncher = __esm({
|
|
|
94264
94781
|
const logs = browserProcess.getRecentLogs().join("\n");
|
|
94265
94782
|
if (logs.includes("Failed to create a ProcessSingleton for your profile directory") || // On Windows we will not get logs due to the singleton process handover. See
|
|
94266
94783
|
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/process_singleton_win.cc;l=46;drc=fc7952f0422b5073515a205a04ec9c3a1ae81658
|
|
94267
|
-
process.platform === "win32" &&
|
|
94784
|
+
process.platform === "win32" && existsSync6(join8(launchArgs.userDataDir, "lockfile"))) {
|
|
94268
94785
|
throw new Error(`The browser is already running for ${launchArgs.userDataDir}. Use a different \`userDataDir\` or stop the running browser first.`);
|
|
94269
94786
|
}
|
|
94270
94787
|
if (logs.includes("Missing X server") && options.headless === false) {
|
|
@@ -94395,7 +94912,7 @@ var init_BrowserLauncher = __esm({
|
|
|
94395
94912
|
*/
|
|
94396
94913
|
async getProfilePath() {
|
|
94397
94914
|
const config4 = await this.puppeteer.configuration();
|
|
94398
|
-
return
|
|
94915
|
+
return join8(config4.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
|
|
94399
94916
|
}
|
|
94400
94917
|
/**
|
|
94401
94918
|
* @internal
|
|
@@ -94404,7 +94921,7 @@ var init_BrowserLauncher = __esm({
|
|
|
94404
94921
|
const config4 = await this.puppeteer.configuration();
|
|
94405
94922
|
let executablePath4 = config4.executablePath;
|
|
94406
94923
|
if (executablePath4) {
|
|
94407
|
-
if (validatePath && !
|
|
94924
|
+
if (validatePath && !existsSync6(executablePath4)) {
|
|
94408
94925
|
throw new Error(`Tried to find the browser at the configured path (${executablePath4}), but no executable was found.`);
|
|
94409
94926
|
}
|
|
94410
94927
|
return executablePath4;
|
|
@@ -94429,7 +94946,7 @@ var init_BrowserLauncher = __esm({
|
|
|
94429
94946
|
browser: browserType,
|
|
94430
94947
|
buildId: browserVersion
|
|
94431
94948
|
});
|
|
94432
|
-
if (validatePath && !
|
|
94949
|
+
if (validatePath && !existsSync6(executablePath4)) {
|
|
94433
94950
|
const configVersion = config4?.[this.browser]?.version;
|
|
94434
94951
|
if (configVersion) {
|
|
94435
94952
|
throw new Error(`Tried to find the browser at the configured path (${executablePath4}) for version ${configVersion}, but no executable was found.`);
|
|
@@ -94447,7 +94964,7 @@ For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides
|
|
|
94447
94964
|
|
|
94448
94965
|
// ../../node_modules/.pnpm/puppeteer-core@25.3.0_yauzl@2.10.0/node_modules/puppeteer-core/lib/puppeteer/node/util/fs.js
|
|
94449
94966
|
import fs6 from "node:fs";
|
|
94450
|
-
async function
|
|
94967
|
+
async function rm4(path16) {
|
|
94451
94968
|
await fs6.promises.rm(path16, rmOptions);
|
|
94452
94969
|
}
|
|
94453
94970
|
var rmOptions;
|
|
@@ -94577,7 +95094,7 @@ var init_ChromeLauncher = __esm({
|
|
|
94577
95094
|
async cleanUserDataDir(path16, opts) {
|
|
94578
95095
|
if (opts.isTemp) {
|
|
94579
95096
|
try {
|
|
94580
|
-
await
|
|
95097
|
+
await rm4(path16);
|
|
94581
95098
|
} catch (error) {
|
|
94582
95099
|
debugError?.(error);
|
|
94583
95100
|
throw error;
|
|
@@ -94693,7 +95210,7 @@ var init_ChromeLauncher = __esm({
|
|
|
94693
95210
|
|
|
94694
95211
|
// ../../node_modules/.pnpm/puppeteer-core@25.3.0_yauzl@2.10.0/node_modules/puppeteer-core/lib/puppeteer/node/FirefoxLauncher.js
|
|
94695
95212
|
import fs7 from "node:fs";
|
|
94696
|
-
import { rename as
|
|
95213
|
+
import { rename as rename3, unlink as unlink2, mkdtemp as mkdtemp2 } from "node:fs/promises";
|
|
94697
95214
|
import os9 from "node:os";
|
|
94698
95215
|
import path13 from "node:path";
|
|
94699
95216
|
var FirefoxLauncher;
|
|
@@ -94781,7 +95298,7 @@ var init_FirefoxLauncher = __esm({
|
|
|
94781
95298
|
async cleanUserDataDir(userDataDir, opts) {
|
|
94782
95299
|
if (opts.isTemp) {
|
|
94783
95300
|
try {
|
|
94784
|
-
await
|
|
95301
|
+
await rm4(userDataDir);
|
|
94785
95302
|
} catch (error) {
|
|
94786
95303
|
debugError?.(error);
|
|
94787
95304
|
throw error;
|
|
@@ -94795,7 +95312,7 @@ var init_FirefoxLauncher = __esm({
|
|
|
94795
95312
|
if (fs7.existsSync(prefsBackupPath)) {
|
|
94796
95313
|
const prefsPath = path13.join(userDataDir, file);
|
|
94797
95314
|
await unlink2(prefsPath);
|
|
94798
|
-
await
|
|
95315
|
+
await rename3(prefsBackupPath, prefsPath);
|
|
94799
95316
|
}
|
|
94800
95317
|
}));
|
|
94801
95318
|
for (const result of results) {
|
|
@@ -95800,7 +96317,7 @@ var require_src2 = __commonJS({
|
|
|
95800
96317
|
|
|
95801
96318
|
// ../../node_modules/.pnpm/puppeteer@25.3.0_yauzl@2.10.0/node_modules/puppeteer/lib/puppeteer/getConfiguration.js
|
|
95802
96319
|
import { homedir as homedir3 } from "node:os";
|
|
95803
|
-
import { join as
|
|
96320
|
+
import { join as join9 } from "node:path";
|
|
95804
96321
|
function getBooleanEnvVar(name) {
|
|
95805
96322
|
const env4 = process.env[name];
|
|
95806
96323
|
if (env4 === void 0) {
|
|
@@ -95887,7 +96404,7 @@ var init_getConfiguration = __esm({
|
|
|
95887
96404
|
configuration.firefox = getBrowserSetting("firefox", configuration, {
|
|
95888
96405
|
skipDownload: true
|
|
95889
96406
|
});
|
|
95890
|
-
configuration.cacheDirectory = process.env["PUPPETEER_CACHE_DIR"] ?? configuration.cacheDirectory ??
|
|
96407
|
+
configuration.cacheDirectory = process.env["PUPPETEER_CACHE_DIR"] ?? configuration.cacheDirectory ?? join9(homedir3(), ".cache", "puppeteer");
|
|
95891
96408
|
configuration.temporaryDirectory = process.env["PUPPETEER_TMP_DIR"] ?? configuration.temporaryDirectory;
|
|
95892
96409
|
configuration.experiments ??= {};
|
|
95893
96410
|
return configuration;
|
|
@@ -96246,7 +96763,7 @@ import { pipeline as pipeline2 } from "node:stream/promises";
|
|
|
96246
96763
|
import { promisify as promisify3 } from "node:util";
|
|
96247
96764
|
import assert32 from "node:assert";
|
|
96248
96765
|
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
96249
|
-
import { existsSync as
|
|
96766
|
+
import { existsSync as existsSync7, readFileSync as readFileSync22 } from "node:fs";
|
|
96250
96767
|
import { mkdir as mkdir32, unlink as unlink3 } from "node:fs/promises";
|
|
96251
96768
|
import os52 from "node:os";
|
|
96252
96769
|
import path102 from "node:path";
|
|
@@ -96256,7 +96773,7 @@ import { format as format3 } from "util";
|
|
|
96256
96773
|
import { normalize as normalize2, resolve as resolve52 } from "path";
|
|
96257
96774
|
import { readFileSync as readFileSync32 } from "fs";
|
|
96258
96775
|
import { createRequire as createRequire3 } from "node:module";
|
|
96259
|
-
import { readFileSync as readFileSync42, statSync as statSync22, writeFile as
|
|
96776
|
+
import { readFileSync as readFileSync42, statSync as statSync22, writeFile as writeFile10 } from "fs";
|
|
96260
96777
|
import { format as format22 } from "util";
|
|
96261
96778
|
import { resolve as resolve62 } from "path";
|
|
96262
96779
|
import { notStrictEqual as notStrictEqual2, strictEqual as strictEqual2 } from "assert";
|
|
@@ -96279,7 +96796,7 @@ import { mkdtemp as mkdtemp3 } from "node:fs/promises";
|
|
|
96279
96796
|
import os72 from "node:os";
|
|
96280
96797
|
import path122 from "node:path";
|
|
96281
96798
|
import fs72 from "node:fs";
|
|
96282
|
-
import { rename as
|
|
96799
|
+
import { rename as rename4, unlink as unlink22, mkdtemp as mkdtemp22 } from "node:fs/promises";
|
|
96283
96800
|
import os82 from "node:os";
|
|
96284
96801
|
import path132 from "node:path";
|
|
96285
96802
|
import { spawn as spawn32, spawnSync as spawnSync32 } from "node:child_process";
|
|
@@ -96302,7 +96819,7 @@ import { spawn as spawn5 } from "child_process";
|
|
|
96302
96819
|
import { spawn as spawn6 } from "child_process";
|
|
96303
96820
|
import { readFileSync as readFileSync62 } from "fs";
|
|
96304
96821
|
import { extname as extname22 } from "path";
|
|
96305
|
-
import { copyFileSync, existsSync as
|
|
96822
|
+
import { copyFileSync, existsSync as existsSync72, mkdirSync as mkdirSync2, readdirSync as readdirSync4, statSync as statSync32, writeFileSync as writeFileSync2 } from "fs";
|
|
96306
96823
|
import { join as join102, dirname as dirname72, extname as extname32 } from "path";
|
|
96307
96824
|
import { spawn as spawn7 } from "child_process";
|
|
96308
96825
|
import { once } from "events";
|
|
@@ -96310,7 +96827,7 @@ import { existsSync as existsSync8, mkdirSync as mkdirSync3, statSync as statSyn
|
|
|
96310
96827
|
import { dirname as dirname82 } from "path";
|
|
96311
96828
|
import { createWriteStream as createWriteStream32, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
|
|
96312
96829
|
import { createHash as createHash22 } from "crypto";
|
|
96313
|
-
import { join as
|
|
96830
|
+
import { join as join112, extname as extname4 } from "path";
|
|
96314
96831
|
import { Readable as Readable22 } from "stream";
|
|
96315
96832
|
import { finished } from "stream/promises";
|
|
96316
96833
|
import { createHash as createHash32, randomUUID as randomUUID3 } from "node:crypto";
|
|
@@ -96413,7 +96930,7 @@ import {
|
|
|
96413
96930
|
renameSync as renameSync3,
|
|
96414
96931
|
rmSync as rmSync5
|
|
96415
96932
|
} from "node:fs";
|
|
96416
|
-
import { basename as
|
|
96933
|
+
import { basename as basename52, dirname as dirname12, extname as extname7, join as join222, resolve as resolve132 } from "node:path";
|
|
96417
96934
|
import { join as join23 } from "node:path";
|
|
96418
96935
|
import { createHash as createHash5 } from "node:crypto";
|
|
96419
96936
|
import { join as join29 } from "node:path";
|
|
@@ -106982,7 +107499,7 @@ async function installWithProviders2(options) {
|
|
|
106982
107499
|
continue;
|
|
106983
107500
|
}
|
|
106984
107501
|
debugInstall2?.(`Successfully got URL from ${provider.getName()}: ${url}`);
|
|
106985
|
-
if (!
|
|
107502
|
+
if (!existsSync7(browserRoot)) {
|
|
106986
107503
|
await mkdir32(browserRoot, { recursive: true });
|
|
106987
107504
|
}
|
|
106988
107505
|
return await installUrl2(url, options, provider);
|
|
@@ -107014,7 +107531,7 @@ async function installDeps2(installedBrowser) {
|
|
|
107014
107531
|
return;
|
|
107015
107532
|
}
|
|
107016
107533
|
const depsPath = path102.join(path102.dirname(installedBrowser.executablePath), "deb.deps");
|
|
107017
|
-
if (!
|
|
107534
|
+
if (!existsSync7(depsPath)) {
|
|
107018
107535
|
debugInstall2?.(`deb.deps file was not found at ${depsPath}`);
|
|
107019
107536
|
return;
|
|
107020
107537
|
}
|
|
@@ -107055,14 +107572,14 @@ async function installUrl2(url, options, provider) {
|
|
|
107055
107572
|
const cache = new Cache2(options.cacheDir);
|
|
107056
107573
|
const browserRoot = cache.browserRoot(options.browser);
|
|
107057
107574
|
const archivePath = path102.join(browserRoot, `${options.buildId}-${fileName}`);
|
|
107058
|
-
if (!
|
|
107575
|
+
if (!existsSync7(browserRoot)) {
|
|
107059
107576
|
await mkdir32(browserRoot, { recursive: true });
|
|
107060
107577
|
}
|
|
107061
107578
|
if (options.expectedHash) {
|
|
107062
107579
|
debugInstall2?.(`Using provided checksum for ${fileName}: ${options.expectedHash}`);
|
|
107063
107580
|
}
|
|
107064
107581
|
if (!options.unpack) {
|
|
107065
|
-
if (
|
|
107582
|
+
if (existsSync7(archivePath)) {
|
|
107066
107583
|
return archivePath;
|
|
107067
107584
|
}
|
|
107068
107585
|
debugInstall2?.(`Downloading binary from ${url}`);
|
|
@@ -107083,8 +107600,8 @@ async function installUrl2(url, options, provider) {
|
|
|
107083
107600
|
cache.writeExecutablePath(options.browser, options.platform, options.buildId, relativeExecutablePath62);
|
|
107084
107601
|
}
|
|
107085
107602
|
try {
|
|
107086
|
-
if (
|
|
107087
|
-
if (!
|
|
107603
|
+
if (existsSync7(outputPath)) {
|
|
107604
|
+
if (!existsSync7(installedBrowser.executablePath)) {
|
|
107088
107605
|
throw new Error(`The browser folder (${outputPath}) exists but the executable (${installedBrowser.executablePath}) is missing`);
|
|
107089
107606
|
}
|
|
107090
107607
|
await runSetup2(installedBrowser);
|
|
@@ -107093,7 +107610,7 @@ async function installUrl2(url, options, provider) {
|
|
|
107093
107610
|
}
|
|
107094
107611
|
return installedBrowser;
|
|
107095
107612
|
}
|
|
107096
|
-
if (!
|
|
107613
|
+
if (!existsSync7(archivePath)) {
|
|
107097
107614
|
debugInstall2?.(`Downloading binary from ${url}`);
|
|
107098
107615
|
try {
|
|
107099
107616
|
debugTime2("download");
|
|
@@ -107122,7 +107639,7 @@ async function installUrl2(url, options, provider) {
|
|
|
107122
107639
|
}
|
|
107123
107640
|
return installedBrowser;
|
|
107124
107641
|
} finally {
|
|
107125
|
-
if (
|
|
107642
|
+
if (existsSync7(archivePath)) {
|
|
107126
107643
|
await unlink3(archivePath);
|
|
107127
107644
|
}
|
|
107128
107645
|
}
|
|
@@ -107133,7 +107650,7 @@ async function runSetup2(installedBrowser) {
|
|
|
107133
107650
|
debugTime2("permissions");
|
|
107134
107651
|
const browserDir = path102.dirname(installedBrowser.executablePath);
|
|
107135
107652
|
const setupExePath = path102.join(browserDir, "setup.exe");
|
|
107136
|
-
if (!
|
|
107653
|
+
if (!existsSync7(setupExePath)) {
|
|
107137
107654
|
return;
|
|
107138
107655
|
}
|
|
107139
107656
|
spawnSync22(path102.join(browserDir, "setup.exe"), [`--configure-browser-in-directory=` + browserDir], {
|
|
@@ -108832,7 +109349,7 @@ function getBrowserTypeDisplayName2(browserType) {
|
|
|
108832
109349
|
return browserType;
|
|
108833
109350
|
}
|
|
108834
109351
|
}
|
|
108835
|
-
async function
|
|
109352
|
+
async function rm5(path142) {
|
|
108836
109353
|
await fs62.promises.rm(path142, rmOptions2);
|
|
108837
109354
|
}
|
|
108838
109355
|
function getFeatures2(flag, options = []) {
|
|
@@ -114040,7 +114557,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
|
|
|
114040
114557
|
async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config22) {
|
|
114041
114558
|
const startTime = Date.now();
|
|
114042
114559
|
const outputDir = dirname72(outputPath);
|
|
114043
|
-
if (!
|
|
114560
|
+
if (!existsSync72(outputDir)) mkdirSync2(outputDir, { recursive: true });
|
|
114044
114561
|
const files = readdirSync4(framesDir).filter((f2) => f2.match(/\.(jpg|jpeg|png)$/i));
|
|
114045
114562
|
const frameCount = files.length;
|
|
114046
114563
|
if (frameCount === 0) {
|
|
@@ -114086,7 +114603,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
|
|
|
114086
114603
|
)
|
|
114087
114604
|
};
|
|
114088
114605
|
}
|
|
114089
|
-
const fileSize =
|
|
114606
|
+
const fileSize = existsSync72(outputPath) ? statSync32(outputPath).size : 0;
|
|
114090
114607
|
return {
|
|
114091
114608
|
success: true,
|
|
114092
114609
|
outputPath,
|
|
@@ -114111,7 +114628,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
114111
114628
|
const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
|
|
114112
114629
|
const chunkCount = Math.ceil(files.length / chunkSize);
|
|
114113
114630
|
const chunkDir = join102(dirname72(outputPath), "chunk-encode");
|
|
114114
|
-
if (!
|
|
114631
|
+
if (!existsSync72(chunkDir)) mkdirSync2(chunkDir, { recursive: true });
|
|
114115
114632
|
const chunkPaths = [];
|
|
114116
114633
|
for (let i3 = 0; i3 < chunkCount; i3++) {
|
|
114117
114634
|
if (signal?.aborted) {
|
|
@@ -114199,7 +114716,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
114199
114716
|
error: concatResult.error
|
|
114200
114717
|
};
|
|
114201
114718
|
}
|
|
114202
|
-
const fileSize =
|
|
114719
|
+
const fileSize = existsSync72(outputPath) ? statSync32(outputPath).size : 0;
|
|
114203
114720
|
return {
|
|
114204
114721
|
success: true,
|
|
114205
114722
|
outputPath,
|
|
@@ -114210,7 +114727,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
114210
114727
|
}
|
|
114211
114728
|
async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config22, fps) {
|
|
114212
114729
|
const outputDir = dirname72(outputPath);
|
|
114213
|
-
if (!
|
|
114730
|
+
if (!existsSync72(outputDir)) mkdirSync2(outputDir, { recursive: true });
|
|
114214
114731
|
const isWebm = outputPath.endsWith(".webm");
|
|
114215
114732
|
const isMov = outputPath.endsWith(".mov");
|
|
114216
114733
|
const shouldCopyAudio = isWebm ? false : await shouldCopyAacSidecar(audioPath, config22);
|
|
@@ -114716,7 +115233,7 @@ async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
|
114716
115233
|
mkdirSync4(destDir, { recursive: true });
|
|
114717
115234
|
}
|
|
114718
115235
|
const filename = getFilenameFromUrl(url);
|
|
114719
|
-
const localPath =
|
|
115236
|
+
const localPath = join112(destDir, filename);
|
|
114720
115237
|
if (existsSync9(localPath)) {
|
|
114721
115238
|
downloadPathCache.set(url, localPath);
|
|
114722
115239
|
return localPath;
|
|
@@ -123899,7 +124416,7 @@ function composeSignal(signal, deadlineAtMs) {
|
|
|
123899
124416
|
function createSiblingTransactionDirectory(destination) {
|
|
123900
124417
|
const parent = dirname12(destination);
|
|
123901
124418
|
const extension2 = extname7(destination);
|
|
123902
|
-
const stem = extension2 ?
|
|
124419
|
+
const stem = extension2 ? basename52(destination, extension2) : basename52(destination);
|
|
123903
124420
|
return mkdtempSync2(join222(parent, `.${stem}.hf-transaction-`));
|
|
123904
124421
|
}
|
|
123905
124422
|
function assertReadableNonEmptyFile(path142) {
|
|
@@ -247165,7 +247682,7 @@ If you think this is a bug, please report it on the Puppeteer issue tracker.`;
|
|
|
247165
247682
|
node_default2 = {
|
|
247166
247683
|
fs: {
|
|
247167
247684
|
readFileSync: readFileSync42,
|
|
247168
|
-
writeFile:
|
|
247685
|
+
writeFile: writeFile10
|
|
247169
247686
|
},
|
|
247170
247687
|
format: format22,
|
|
247171
247688
|
resolve: resolve62,
|
|
@@ -250761,7 +251278,7 @@ For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides
|
|
|
250761
251278
|
async cleanUserDataDir(path142, opts) {
|
|
250762
251279
|
if (opts.isTemp) {
|
|
250763
251280
|
try {
|
|
250764
|
-
await
|
|
251281
|
+
await rm5(path142);
|
|
250765
251282
|
} catch (error) {
|
|
250766
251283
|
debugError2?.(error);
|
|
250767
251284
|
throw error;
|
|
@@ -250958,7 +251475,7 @@ For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides
|
|
|
250958
251475
|
async cleanUserDataDir(userDataDir, opts) {
|
|
250959
251476
|
if (opts.isTemp) {
|
|
250960
251477
|
try {
|
|
250961
|
-
await
|
|
251478
|
+
await rm5(userDataDir);
|
|
250962
251479
|
} catch (error) {
|
|
250963
251480
|
debugError2?.(error);
|
|
250964
251481
|
throw error;
|
|
@@ -250972,7 +251489,7 @@ For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides
|
|
|
250972
251489
|
if (fs72.existsSync(prefsBackupPath)) {
|
|
250973
251490
|
const prefsPath = path132.join(userDataDir, file);
|
|
250974
251491
|
await unlink22(prefsPath);
|
|
250975
|
-
await
|
|
251492
|
+
await rename4(prefsBackupPath, prefsPath);
|
|
250976
251493
|
}
|
|
250977
251494
|
}));
|
|
250978
251495
|
for (const result of results) {
|
|
@@ -266625,7 +267142,7 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
|
266625
267142
|
this.fileSystem = fileSystem;
|
|
266626
267143
|
this.destinationPath = resolve132(destinationPath);
|
|
266627
267144
|
this.transactionDirectory = createSiblingTransactionDirectory(this.destinationPath);
|
|
266628
|
-
this.stagingPath = join222(this.transactionDirectory,
|
|
267145
|
+
this.stagingPath = join222(this.transactionDirectory, basename52(this.destinationPath));
|
|
266629
267146
|
this.backupPath = join222(this.transactionDirectory, "backup");
|
|
266630
267147
|
}
|
|
266631
267148
|
destinationPath;
|
|
@@ -267495,7 +268012,7 @@ Check that each file referenced by data-composition-src contains valid HTML with
|
|
|
267495
268012
|
});
|
|
267496
268013
|
|
|
267497
268014
|
// ../cli/src/commands/_shared/scene-lint.ts
|
|
267498
|
-
import { readdir as
|
|
268015
|
+
import { readdir as readdir6, readFile as readFile9, writeFile as writeFile11, stat as stat4 } from "node:fs/promises";
|
|
267499
268016
|
import { existsSync as existsSync38 } from "node:fs";
|
|
267500
268017
|
import { resolve as resolve21, relative as relative5, join as join53 } from "node:path";
|
|
267501
268018
|
async function discoverSceneFiles(opts) {
|
|
@@ -267511,7 +268028,7 @@ async function discoverSceneFiles(opts) {
|
|
|
267511
268028
|
return { root: root2, subs };
|
|
267512
268029
|
}
|
|
267513
268030
|
async function collectHtmlRecursive(dir, into) {
|
|
267514
|
-
const entries2 = await
|
|
268031
|
+
const entries2 = await readdir6(dir, { withFileTypes: true });
|
|
267515
268032
|
for (const entry of entries2) {
|
|
267516
268033
|
const full = join53(dir, entry.name);
|
|
267517
268034
|
if (entry.isDirectory()) {
|
|
@@ -267597,7 +268114,7 @@ async function runProjectLint(opts) {
|
|
|
267597
268114
|
for (const sub of subs) targets.push({ abs: sub, isSub: true });
|
|
267598
268115
|
for (const { abs, isSub } of targets) {
|
|
267599
268116
|
const rel = relative5(projectDir, abs) || abs;
|
|
267600
|
-
const html = await
|
|
268117
|
+
const html = await readFile9(abs, "utf-8");
|
|
267601
268118
|
const prepared = {
|
|
267602
268119
|
html,
|
|
267603
268120
|
entryFile: rel,
|
|
@@ -267612,7 +268129,7 @@ async function runProjectLint(opts) {
|
|
|
267612
268129
|
if (opts.fix && findings.length > 0) {
|
|
267613
268130
|
const { html: nextHtml, fixedCodes } = applyMechanicalFixes(html, findings);
|
|
267614
268131
|
if (fixedCodes.length > 0) {
|
|
267615
|
-
await
|
|
268132
|
+
await writeFile11(abs, nextHtml, "utf-8");
|
|
267616
268133
|
fixed.push({ file: rel, codes: fixedCodes });
|
|
267617
268134
|
const reLinted = await runHyperframeLint({ ...prepared, html: nextHtml });
|
|
267618
268135
|
files.push({
|
|
@@ -268213,7 +268730,7 @@ var init_compose_beat_prompt = __esm({
|
|
|
268213
268730
|
|
|
268214
268731
|
// ../cli/src/commands/_shared/root-sync.ts
|
|
268215
268732
|
import { existsSync as existsSync40 } from "node:fs";
|
|
268216
|
-
import { readFile as
|
|
268733
|
+
import { readFile as readFile10, writeFile as writeFile12 } from "node:fs/promises";
|
|
268217
268734
|
import { join as join55, resolve as resolve24 } from "node:path";
|
|
268218
268735
|
async function createRootSyncPlan(opts) {
|
|
268219
268736
|
const projectDir = resolve24(opts.projectDir);
|
|
@@ -268222,7 +268739,7 @@ async function createRootSyncPlan(opts) {
|
|
|
268222
268739
|
if (!existsSync40(rootPath)) {
|
|
268223
268740
|
return { rootPath, rootRel, exists: false, changed: false, fixCodes: [], issues: [] };
|
|
268224
268741
|
}
|
|
268225
|
-
const html = await
|
|
268742
|
+
const html = await readFile10(rootPath, "utf-8");
|
|
268226
268743
|
if (opts.beats.length === 0) {
|
|
268227
268744
|
return { rootPath, rootRel, exists: true, changed: false, fixCodes: [], issues: [] };
|
|
268228
268745
|
}
|
|
@@ -268276,14 +268793,14 @@ async function createProjectRootSyncPlan(opts) {
|
|
|
268276
268793
|
}
|
|
268277
268794
|
async function syncRootComposition(opts) {
|
|
268278
268795
|
const plan2 = await createRootSyncPlan(opts);
|
|
268279
|
-
if (plan2.nextHtml) await
|
|
268796
|
+
if (plan2.nextHtml) await writeFile12(plan2.rootPath, plan2.nextHtml, "utf-8");
|
|
268280
268797
|
return plan2;
|
|
268281
268798
|
}
|
|
268282
268799
|
async function loadProjectRootSyncBeats(projectDir) {
|
|
268283
268800
|
const root2 = resolve24(projectDir);
|
|
268284
268801
|
const storyboardPath = join55(root2, "STORYBOARD.md");
|
|
268285
268802
|
if (!existsSync40(storyboardPath)) return [];
|
|
268286
|
-
const parsed = parseStoryboard(await
|
|
268803
|
+
const parsed = parseStoryboard(await loadStoryboardMarkdown(root2));
|
|
268287
268804
|
const reportBeats = await readBuildReportBeats(root2);
|
|
268288
268805
|
return parsed.beats.map((beat) => {
|
|
268289
268806
|
const reportBeat = reportBeats.find((item) => item.id === beat.id);
|
|
@@ -268511,7 +269028,7 @@ async function readBuildReportBeats(projectDir) {
|
|
|
268511
269028
|
const reportPath = join55(projectDir, "build-report.json");
|
|
268512
269029
|
if (!existsSync40(reportPath)) return [];
|
|
268513
269030
|
try {
|
|
268514
|
-
const report = JSON.parse(await
|
|
269031
|
+
const report = JSON.parse(await readFile10(reportPath, "utf-8"));
|
|
268515
269032
|
return Array.isArray(report.beats) ? report.beats : [];
|
|
268516
269033
|
} catch {
|
|
268517
269034
|
return [];
|
|
@@ -268541,6 +269058,7 @@ var init_root_sync = __esm({
|
|
|
268541
269058
|
"use strict";
|
|
268542
269059
|
init_audio();
|
|
268543
269060
|
init_storyboard_parse();
|
|
269061
|
+
init_storyboard_source();
|
|
268544
269062
|
ROOT_SYNC_FIX_CODES = {
|
|
268545
269063
|
clipRefs: "root_clip_refs_synced",
|
|
268546
269064
|
duration: "root_duration_synced",
|
|
@@ -268553,13 +269071,13 @@ var init_root_sync = __esm({
|
|
|
268553
269071
|
|
|
268554
269072
|
// ../cli/src/commands/_shared/transcribe-narration.ts
|
|
268555
269073
|
import { existsSync as existsSync41 } from "node:fs";
|
|
268556
|
-
import { readFile as
|
|
269074
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
268557
269075
|
import { join as join56 } from "node:path";
|
|
268558
269076
|
async function transcribeNarrationWords(audioAbsPath, opts) {
|
|
268559
269077
|
try {
|
|
268560
269078
|
const whisper = new WhisperProvider();
|
|
268561
269079
|
await whisper.initialize({ apiKey: opts.apiKey });
|
|
268562
|
-
const audioBytes = await
|
|
269080
|
+
const audioBytes = await readFile11(audioAbsPath);
|
|
268563
269081
|
const audioBlob = new Blob([new Uint8Array(audioBytes)]);
|
|
268564
269082
|
const transcript = await whisper.transcribe(audioBlob, void 0, {
|
|
268565
269083
|
granularity: "word",
|
|
@@ -268580,7 +269098,7 @@ async function readBeatTranscript(projectDir, beatId) {
|
|
|
268580
269098
|
const abs = join56(projectDir, beatTranscriptRelPath(beatId));
|
|
268581
269099
|
if (!existsSync41(abs)) return void 0;
|
|
268582
269100
|
try {
|
|
268583
|
-
const parsed = JSON.parse(await
|
|
269101
|
+
const parsed = JSON.parse(await readFile11(abs, "utf-8"));
|
|
268584
269102
|
if (!Array.isArray(parsed)) return void 0;
|
|
268585
269103
|
const words = parsed.filter(
|
|
268586
269104
|
(w4) => typeof w4 === "object" && w4 !== null && typeof w4.text === "string" && Number.isFinite(w4.start) && Number.isFinite(w4.end)
|
|
@@ -268599,7 +269117,6 @@ var init_transcribe_narration = __esm({
|
|
|
268599
269117
|
|
|
268600
269118
|
// ../cli/src/commands/_shared/compose-prompts.ts
|
|
268601
269119
|
import { existsSync as existsSync43 } from "node:fs";
|
|
268602
|
-
import { readFile as readFile11 } from "node:fs/promises";
|
|
268603
269120
|
import { join as join57, relative as relative6, resolve as resolve25 } from "node:path";
|
|
268604
269121
|
async function getComposePrompts(opts) {
|
|
268605
269122
|
const projectDir = resolve25(opts.projectDir);
|
|
@@ -268633,7 +269150,7 @@ async function getComposePrompts(opts) {
|
|
|
268633
269150
|
`Hyperframes composition rules are not installed \u2014 you will be authoring without them in context. Run \`vibe scene install-skill\` (or \`${HYPERFRAMES_SKILL_INSTALL_COMMAND}\`) first.`
|
|
268634
269151
|
);
|
|
268635
269152
|
}
|
|
268636
|
-
const storyboardMd = await
|
|
269153
|
+
const storyboardMd = await loadStoryboardMarkdown(projectDir);
|
|
268637
269154
|
const parsed = parseStoryboard(storyboardMd);
|
|
268638
269155
|
if (parsed.beats.length === 0) {
|
|
268639
269156
|
return baseError(`STORYBOARD.md has no \`## Beat \u2026\` headings.`);
|
|
@@ -268714,7 +269231,8 @@ function buildInstructions(args) {
|
|
|
268714
269231
|
if (args.compositionRef) {
|
|
268715
269232
|
lines.push(`2b. Read \`${args.compositionRef}\` for the project STRUCTURAL contract (layout system, GSAP timeline conventions, element/track rules) \u2014 a HARD-GATE parallel to DESIGN.md; every composition must satisfy it.`);
|
|
268716
269233
|
}
|
|
268717
|
-
lines.push(`3. For each beat in the \`beats\` array below, author HTML at \`outputPath\` matching the \`userPrompt\`. The beat \`body\` carries the narrative
|
|
269234
|
+
lines.push(`3. For each beat in the \`beats\` array below, author HTML at \`outputPath\` matching the \`userPrompt\`. The beat \`body\` carries the narrative intent; \`cues\` carries machine-readable per-beat overrides (${STORYBOARD_CUE_KEYS.join(", ")}).`);
|
|
269235
|
+
lines.push(` The \`motion\` cue, when present, is the animation direction for this beat - treat it as binding on how elements enter, hold, and leave, the same way \`narration\` is binding on the audio.`);
|
|
268718
269236
|
lines.push(`3b. Use each beat's \`finalDurationSec\` (narration-synced) for \`data-duration\` and timeline anchors when present \u2014 NOT the storyboard \`duration\`, which is only the minimum. Scenes composed at the storyboard duration end early and render black tails.`);
|
|
268719
269237
|
lines.push(`3c. Never give inner \`.clip\` elements a non-zero \`data-start\` \u2014 the renderer does not toggle internal clip visibility inside sub-compositions, so phased clips render all phases at once (overlapping text). Use full-window clips and GSAP autoAlpha phase transitions instead. Also keep beats 6-15s; split anything longer in the storyboard first.`);
|
|
268720
269238
|
lines.push(`3d. If your environment cannot write files (e.g. Claude Desktop / MCP-only hosts), author each beat's HTML and submit it with the \`scene_submit\` tool (beat id + html). It validates with the same Hyperframes lint and writes the file for you; on lint errors it returns the findings without writing \u2014 fix and resubmit.`);
|
|
@@ -268734,6 +269252,7 @@ var init_compose_prompts = __esm({
|
|
|
268734
269252
|
"../cli/src/commands/_shared/compose-prompts.ts"() {
|
|
268735
269253
|
"use strict";
|
|
268736
269254
|
init_storyboard_parse();
|
|
269255
|
+
init_storyboard_source();
|
|
268737
269256
|
init_compose_beat_prompt();
|
|
268738
269257
|
init_root_sync();
|
|
268739
269258
|
init_install_skill();
|
|
@@ -268743,7 +269262,7 @@ var init_compose_prompts = __esm({
|
|
|
268743
269262
|
|
|
268744
269263
|
// ../cli/src/commands/_shared/sub-comp-duration-sync.ts
|
|
268745
269264
|
import { existsSync as existsSync45 } from "node:fs";
|
|
268746
|
-
import { readFile as
|
|
269265
|
+
import { readFile as readFile12 } from "node:fs/promises";
|
|
268747
269266
|
import { join as join59, resolve as resolve27 } from "node:path";
|
|
268748
269267
|
function syncSubCompositionDurationHtml(html, beatId, newDurationSec, fileRel) {
|
|
268749
269268
|
const compositionId = `scene-${beatId}`;
|
|
@@ -268844,7 +269363,7 @@ async function createSubCompDurationSyncPlans(opts) {
|
|
|
268844
269363
|
narrationPath: beat.narrationPath,
|
|
268845
269364
|
sceneDurationSec: beat.sceneDurationSec
|
|
268846
269365
|
});
|
|
268847
|
-
const html = await
|
|
269366
|
+
const html = await readFile12(filePath, "utf-8");
|
|
268848
269367
|
const outcome = syncSubCompositionDurationHtml(html, beat.id, newDurationSec, fileRel);
|
|
268849
269368
|
results.push({ ...outcome, file: fileRel, beatId: beat.id });
|
|
268850
269369
|
}
|
|
@@ -268868,7 +269387,7 @@ var init_sub_comp_duration_sync = __esm({
|
|
|
268868
269387
|
});
|
|
268869
269388
|
|
|
268870
269389
|
// ../cli/src/commands/_shared/scene-repair.ts
|
|
268871
|
-
import { readFile as
|
|
269390
|
+
import { readFile as readFile13, writeFile as writeFile14 } from "node:fs/promises";
|
|
268872
269391
|
import { relative as relative7, resolve as resolve28 } from "node:path";
|
|
268873
269392
|
async function executeSceneRepair(opts) {
|
|
268874
269393
|
const projectDir = resolve28(opts.projectDir);
|
|
@@ -268888,7 +269407,7 @@ async function executeSceneRepair(opts) {
|
|
|
268888
269407
|
if (dryRun) {
|
|
268889
269408
|
wouldFix.push(item);
|
|
268890
269409
|
} else {
|
|
268891
|
-
await
|
|
269410
|
+
await writeFile14(rootSync.rootPath, rootSync.nextHtml, "utf-8");
|
|
268892
269411
|
fixed.push(item);
|
|
268893
269412
|
}
|
|
268894
269413
|
} else if (rootSync.issues.length > 0) {
|
|
@@ -268904,7 +269423,7 @@ async function executeSceneRepair(opts) {
|
|
|
268904
269423
|
if (dryRun) {
|
|
268905
269424
|
wouldFix.push(item);
|
|
268906
269425
|
} else {
|
|
268907
|
-
await
|
|
269426
|
+
await writeFile14(resolve28(projectDir, plan2.file), plan2.nextHtml, "utf-8");
|
|
268908
269427
|
fixed.push(item);
|
|
268909
269428
|
}
|
|
268910
269429
|
}
|
|
@@ -268913,7 +269432,7 @@ async function executeSceneRepair(opts) {
|
|
|
268913
269432
|
}
|
|
268914
269433
|
for (const target of targets) {
|
|
268915
269434
|
const rel = relative7(projectDir, target.abs) || target.abs;
|
|
268916
|
-
const html = await
|
|
269435
|
+
const html = await readFile13(target.abs, "utf-8");
|
|
268917
269436
|
const findings = await lintHtml(html, rel, target.isSub);
|
|
268918
269437
|
const { html: nextHtml, fixedCodes } = applyMechanicalFixes(html, findings);
|
|
268919
269438
|
if (fixedCodes.length > 0) {
|
|
@@ -268921,7 +269440,7 @@ async function executeSceneRepair(opts) {
|
|
|
268921
269440
|
if (dryRun) {
|
|
268922
269441
|
wouldFix.push(item);
|
|
268923
269442
|
} else {
|
|
268924
|
-
await
|
|
269443
|
+
await writeFile14(target.abs, nextHtml, "utf-8");
|
|
268925
269444
|
fixed.push(item);
|
|
268926
269445
|
}
|
|
268927
269446
|
files.push({
|
|
@@ -268993,303 +269512,6 @@ var init_scene_repair = __esm({
|
|
|
268993
269512
|
}
|
|
268994
269513
|
});
|
|
268995
269514
|
|
|
268996
|
-
// ../cli/src/commands/_shared/storyboard-edit.ts
|
|
268997
|
-
function validateStoryboardMarkdown(markdown) {
|
|
268998
|
-
const parsed = parseStoryboard(markdown);
|
|
268999
|
-
const sections = splitBeatSections(markdown);
|
|
269000
|
-
const issues = [];
|
|
269001
|
-
if (parsed.beats.length === 0) {
|
|
269002
|
-
issues.push({
|
|
269003
|
-
severity: "error",
|
|
269004
|
-
code: "NO_BEATS",
|
|
269005
|
-
message: "STORYBOARD.md must contain at least one `## Beat ...` heading."
|
|
269006
|
-
});
|
|
269007
|
-
}
|
|
269008
|
-
const seen = /* @__PURE__ */ new Map();
|
|
269009
|
-
for (const beat of parsed.beats) {
|
|
269010
|
-
seen.set(beat.id, (seen.get(beat.id) ?? 0) + 1);
|
|
269011
|
-
}
|
|
269012
|
-
for (const [id, count] of seen.entries()) {
|
|
269013
|
-
if (count > 1) {
|
|
269014
|
-
issues.push({
|
|
269015
|
-
severity: "error",
|
|
269016
|
-
code: "DUPLICATE_BEAT_ID",
|
|
269017
|
-
beatId: id,
|
|
269018
|
-
message: `Beat id "${id}" appears ${count} times. Beat ids must be unique.`
|
|
269019
|
-
});
|
|
269020
|
-
}
|
|
269021
|
-
}
|
|
269022
|
-
for (const section of sections) {
|
|
269023
|
-
const cueBlock = readLeadingCueBlock(section.body);
|
|
269024
|
-
if (cueBlock?.error) {
|
|
269025
|
-
issues.push({
|
|
269026
|
-
severity: "error",
|
|
269027
|
-
code: "MALFORMED_CUE_YAML",
|
|
269028
|
-
beatId: section.id,
|
|
269029
|
-
message: `Beat "${section.id}" has malformed YAML cues: ${cueBlock.error}`
|
|
269030
|
-
});
|
|
269031
|
-
}
|
|
269032
|
-
}
|
|
269033
|
-
const characterPool = new Set(
|
|
269034
|
-
Object.keys(
|
|
269035
|
-
parsed.frontmatter?.characters ?? {}
|
|
269036
|
-
)
|
|
269037
|
-
);
|
|
269038
|
-
for (const beat of parsed.beats) {
|
|
269039
|
-
const cues = beat.cues ?? {};
|
|
269040
|
-
for (const [key2, value] of Object.entries(cues)) {
|
|
269041
|
-
if (!ALLOWED_CUE_KEYS.has(key2)) {
|
|
269042
|
-
issues.push({
|
|
269043
|
-
severity: "warning",
|
|
269044
|
-
code: "UNKNOWN_CUE",
|
|
269045
|
-
beatId: beat.id,
|
|
269046
|
-
message: `Beat "${beat.id}" uses unknown cue "${key2}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`
|
|
269047
|
-
});
|
|
269048
|
-
continue;
|
|
269049
|
-
}
|
|
269050
|
-
if (key2 === "characters") {
|
|
269051
|
-
const validShape = typeof value === "string" || Array.isArray(value) && value.every((v4) => typeof v4 === "string");
|
|
269052
|
-
if (!validShape) {
|
|
269053
|
-
issues.push({
|
|
269054
|
-
severity: "error",
|
|
269055
|
-
code: "INVALID_CHARACTERS_VALUE",
|
|
269056
|
-
beatId: beat.id,
|
|
269057
|
-
message: `Beat "${beat.id}" cue "characters" must be a character name or a list of names.`
|
|
269058
|
-
});
|
|
269059
|
-
continue;
|
|
269060
|
-
}
|
|
269061
|
-
for (const name of beatCharacterNames({ characters: value })) {
|
|
269062
|
-
if (!characterPool.has(name)) {
|
|
269063
|
-
issues.push({
|
|
269064
|
-
severity: "warning",
|
|
269065
|
-
code: "UNKNOWN_CHARACTER",
|
|
269066
|
-
beatId: beat.id,
|
|
269067
|
-
message: `Beat "${beat.id}" references character "${name}" not defined in the frontmatter \`characters:\` pool.`
|
|
269068
|
-
});
|
|
269069
|
-
}
|
|
269070
|
-
}
|
|
269071
|
-
continue;
|
|
269072
|
-
}
|
|
269073
|
-
if (key2 === "duration") {
|
|
269074
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
269075
|
-
issues.push({
|
|
269076
|
-
severity: "error",
|
|
269077
|
-
code: "INVALID_DURATION",
|
|
269078
|
-
beatId: beat.id,
|
|
269079
|
-
message: `Beat "${beat.id}" cue "duration" must be a positive number of seconds.`
|
|
269080
|
-
});
|
|
269081
|
-
}
|
|
269082
|
-
continue;
|
|
269083
|
-
}
|
|
269084
|
-
if (STRING_CUE_KEYS.has(key2) && typeof value !== "string") {
|
|
269085
|
-
issues.push({
|
|
269086
|
-
severity: "error",
|
|
269087
|
-
code: "INVALID_CUE_VALUE",
|
|
269088
|
-
beatId: beat.id,
|
|
269089
|
-
message: `Beat "${beat.id}" cue "${key2}" must be a string.`
|
|
269090
|
-
});
|
|
269091
|
-
}
|
|
269092
|
-
}
|
|
269093
|
-
}
|
|
269094
|
-
for (const beat of parsed.beats) {
|
|
269095
|
-
if (beat.duration !== void 0 && beat.duration > MAX_RECOMMENDED_BEAT_SEC) {
|
|
269096
|
-
issues.push({
|
|
269097
|
-
severity: "warning",
|
|
269098
|
-
code: "BEAT_DURATION_TOO_LONG",
|
|
269099
|
-
beatId: beat.id,
|
|
269100
|
-
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).`
|
|
269101
|
-
});
|
|
269102
|
-
}
|
|
269103
|
-
}
|
|
269104
|
-
return {
|
|
269105
|
-
ok: !issues.some((i3) => i3.severity === "error"),
|
|
269106
|
-
beats: parsed.beats,
|
|
269107
|
-
issues
|
|
269108
|
-
};
|
|
269109
|
-
}
|
|
269110
|
-
function getStoryboardBeat(markdown, beatId) {
|
|
269111
|
-
return parseStoryboard(markdown).beats.find((beat) => beat.id === beatId) ?? null;
|
|
269112
|
-
}
|
|
269113
|
-
function upsertStoryboardBeat(markdown, opts) {
|
|
269114
|
-
const beatId = normalizeBeatId(opts.beatId);
|
|
269115
|
-
const sections = splitBeatSections(markdown);
|
|
269116
|
-
const existing = sections.find((section2) => section2.id === beatId);
|
|
269117
|
-
const cues = storyboardCuesFromInput(opts);
|
|
269118
|
-
if (existing) {
|
|
269119
|
-
let next = markdown;
|
|
269120
|
-
for (const [key2, value] of Object.entries(cues)) {
|
|
269121
|
-
next = setStoryboardCue(next, { beatId, key: key2, value });
|
|
269122
|
-
}
|
|
269123
|
-
return { markdown: next, action: "updated" };
|
|
269124
|
-
}
|
|
269125
|
-
const section = buildStoryboardBeatSection({ ...opts, beatId, cues });
|
|
269126
|
-
if (sections.length > 0 && isStarterStoryboard(markdown)) {
|
|
269127
|
-
const global3 = markdown.slice(0, sections[0].start).trimEnd();
|
|
269128
|
-
return {
|
|
269129
|
-
markdown: `${global3}
|
|
269130
|
-
|
|
269131
|
-
${section}`,
|
|
269132
|
-
action: "replaced-starter"
|
|
269133
|
-
};
|
|
269134
|
-
}
|
|
269135
|
-
const prefix = markdown.trimEnd();
|
|
269136
|
-
return {
|
|
269137
|
-
markdown: `${prefix}${prefix ? "\n\n" : ""}${section}`,
|
|
269138
|
-
action: "appended"
|
|
269139
|
-
};
|
|
269140
|
-
}
|
|
269141
|
-
function setStoryboardCue(markdown, opts) {
|
|
269142
|
-
const section = findBeatSection(markdown, opts.beatId);
|
|
269143
|
-
if (!section) {
|
|
269144
|
-
throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
269145
|
-
}
|
|
269146
|
-
if (!ALLOWED_CUE_KEYS.has(opts.key)) {
|
|
269147
|
-
throw new Error(`Unsupported cue "${opts.key}". Supported cues: ${STORYBOARD_CUE_KEYS.join(", ")}.`);
|
|
269148
|
-
}
|
|
269149
|
-
const cue = readLeadingCueBlock(section.body);
|
|
269150
|
-
if (cue?.error) {
|
|
269151
|
-
throw new Error(`Cannot edit malformed YAML cues for beat "${opts.beatId}": ${cue.error}`);
|
|
269152
|
-
}
|
|
269153
|
-
const cues = cue?.value ? { ...cue.value } : {};
|
|
269154
|
-
if (opts.unset) {
|
|
269155
|
-
delete cues[opts.key];
|
|
269156
|
-
} else {
|
|
269157
|
-
cues[opts.key] = normalizeCueValue(opts.key, opts.value);
|
|
269158
|
-
}
|
|
269159
|
-
const remainingBody = cue ? section.body.slice(cue.full.length).replace(/^\s*\n/, "") : section.body.replace(/^\s*\n/, "");
|
|
269160
|
-
const cueBlock = Object.keys(cues).length > 0 ? "```yaml\n" + (0, import_yaml5.stringify)(cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
269161
|
-
const nextBody = cueBlock + remainingBody.trimStart();
|
|
269162
|
-
const nextSection = section.raw.slice(0, section.headingEnd - section.start) + "\n\n" + nextBody.trimEnd() + "\n";
|
|
269163
|
-
return markdown.slice(0, section.start) + nextSection + markdown.slice(section.end);
|
|
269164
|
-
}
|
|
269165
|
-
function moveStoryboardBeat(markdown, opts) {
|
|
269166
|
-
if (opts.beatId === opts.afterBeatId) return markdown;
|
|
269167
|
-
const sections = splitBeatSections(markdown);
|
|
269168
|
-
const movingIndex = sections.findIndex((section) => section.id === opts.beatId);
|
|
269169
|
-
if (movingIndex === -1) throw new Error(`Beat "${opts.beatId}" not found.`);
|
|
269170
|
-
const afterIndex = sections.findIndex((section) => section.id === opts.afterBeatId);
|
|
269171
|
-
if (afterIndex === -1) throw new Error(`Beat "${opts.afterBeatId}" not found.`);
|
|
269172
|
-
const global3 = sections.length > 0 ? markdown.slice(0, sections[0].start) : markdown;
|
|
269173
|
-
const chunks = sections.map((section) => section.raw);
|
|
269174
|
-
const [moving] = chunks.splice(movingIndex, 1);
|
|
269175
|
-
const adjustedAfterIndex = movingIndex < afterIndex ? afterIndex - 1 : afterIndex;
|
|
269176
|
-
chunks.splice(adjustedAfterIndex + 1, 0, moving);
|
|
269177
|
-
return global3 + normalizeBeatChunks(chunks);
|
|
269178
|
-
}
|
|
269179
|
-
function normalizeBeatChunks(chunks) {
|
|
269180
|
-
return chunks.map((chunk) => chunk.trim()).filter(Boolean).join("\n\n") + "\n";
|
|
269181
|
-
}
|
|
269182
|
-
function normalizeBeatId(id) {
|
|
269183
|
-
return deriveBeatId(id);
|
|
269184
|
-
}
|
|
269185
|
-
function storyboardCuesFromInput(opts) {
|
|
269186
|
-
const cues = {};
|
|
269187
|
-
if (opts.duration !== void 0) cues.duration = opts.duration;
|
|
269188
|
-
if (opts.narration && opts.narration.trim()) cues.narration = opts.narration.trim();
|
|
269189
|
-
if (opts.backdrop && opts.backdrop.trim()) cues.backdrop = opts.backdrop.trim();
|
|
269190
|
-
return cues;
|
|
269191
|
-
}
|
|
269192
|
-
function buildStoryboardBeatSection(opts) {
|
|
269193
|
-
const title = normalizeTitle(opts.title ?? humanizeBeatId(opts.beatId));
|
|
269194
|
-
const cueBlock = Object.keys(opts.cues).length > 0 ? "```yaml\n" + (0, import_yaml5.stringify)(opts.cues, { lineWidth: 0 }).trimEnd() + "\n```\n\n" : "";
|
|
269195
|
-
const body = opts.body?.trim() || "Scene created with `vibe scene add`. Edit this body if the build flow should recompose it.";
|
|
269196
|
-
return `## Beat ${opts.beatId} - ${title}
|
|
269197
|
-
|
|
269198
|
-
${cueBlock}${body.trimEnd()}
|
|
269199
|
-
`;
|
|
269200
|
-
}
|
|
269201
|
-
function normalizeTitle(value) {
|
|
269202
|
-
return value.replace(/\s+/g, " ").trim() || "Scene";
|
|
269203
|
-
}
|
|
269204
|
-
function humanizeBeatId(id) {
|
|
269205
|
-
return id.split(/[-_]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ") || "Scene";
|
|
269206
|
-
}
|
|
269207
|
-
function isStarterStoryboard(markdown) {
|
|
269208
|
-
const parsed = parseStoryboard(markdown);
|
|
269209
|
-
if (parsed.beats.length !== 3) return false;
|
|
269210
|
-
const ids = parsed.beats.map((beat) => beat.id);
|
|
269211
|
-
if (ids.join(",") !== "hook,proof,close") return false;
|
|
269212
|
-
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.");
|
|
269213
|
-
}
|
|
269214
|
-
function normalizeCueValue(key2, value) {
|
|
269215
|
-
if (key2 === "duration") {
|
|
269216
|
-
const n2 = typeof value === "number" ? value : Number.parseFloat(String(value ?? ""));
|
|
269217
|
-
if (!Number.isFinite(n2) || n2 <= 0) {
|
|
269218
|
-
throw new Error("Cue duration must be a positive number.");
|
|
269219
|
-
}
|
|
269220
|
-
return n2;
|
|
269221
|
-
}
|
|
269222
|
-
if (typeof value !== "string") return value;
|
|
269223
|
-
return value.trim();
|
|
269224
|
-
}
|
|
269225
|
-
function splitBeatSections(markdown) {
|
|
269226
|
-
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
269227
|
-
const headings = [];
|
|
269228
|
-
HEADING_RE2.lastIndex = 0;
|
|
269229
|
-
let match2;
|
|
269230
|
-
while ((match2 = HEADING_RE2.exec(normalized)) !== null) {
|
|
269231
|
-
headings.push({ start: match2.index, end: match2.index + match2[0].length, line: match2[1].trim() });
|
|
269232
|
-
}
|
|
269233
|
-
return headings.map((heading, index) => {
|
|
269234
|
-
const end = index + 1 < headings.length ? headings[index + 1].start : normalized.length;
|
|
269235
|
-
return {
|
|
269236
|
-
id: deriveBeatId(heading.line),
|
|
269237
|
-
heading: heading.line,
|
|
269238
|
-
start: heading.start,
|
|
269239
|
-
headingEnd: heading.end,
|
|
269240
|
-
end,
|
|
269241
|
-
raw: normalized.slice(heading.start, end),
|
|
269242
|
-
body: normalized.slice(heading.end, end).trim()
|
|
269243
|
-
};
|
|
269244
|
-
});
|
|
269245
|
-
}
|
|
269246
|
-
function findBeatSection(markdown, beatId) {
|
|
269247
|
-
return splitBeatSections(markdown).find((section) => section.id === beatId) ?? null;
|
|
269248
|
-
}
|
|
269249
|
-
function readLeadingCueBlock(body) {
|
|
269250
|
-
const match2 = body.match(LEADING_CUE_RE);
|
|
269251
|
-
if (!match2) return null;
|
|
269252
|
-
try {
|
|
269253
|
-
const parsed = (0, import_yaml5.parse)(match2[2]);
|
|
269254
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
269255
|
-
return { full: match2[0], error: "cue block must parse to a YAML object" };
|
|
269256
|
-
}
|
|
269257
|
-
return { full: match2[0], value: parsed };
|
|
269258
|
-
} catch (error) {
|
|
269259
|
-
return { full: match2[0], error: error instanceof Error ? error.message : String(error) };
|
|
269260
|
-
}
|
|
269261
|
-
}
|
|
269262
|
-
var import_yaml5, STORYBOARD_CUE_KEYS, HEADING_RE2, LEADING_CUE_RE, ALLOWED_CUE_KEYS, STRING_CUE_KEYS, MAX_RECOMMENDED_BEAT_SEC;
|
|
269263
|
-
var init_storyboard_edit = __esm({
|
|
269264
|
-
"../cli/src/commands/_shared/storyboard-edit.ts"() {
|
|
269265
|
-
"use strict";
|
|
269266
|
-
import_yaml5 = __toESM(require_dist3(), 1);
|
|
269267
|
-
init_storyboard_parse();
|
|
269268
|
-
STORYBOARD_CUE_KEYS = [
|
|
269269
|
-
"duration",
|
|
269270
|
-
"narration",
|
|
269271
|
-
"backdrop",
|
|
269272
|
-
"video",
|
|
269273
|
-
"keyframe",
|
|
269274
|
-
"motion",
|
|
269275
|
-
"voice",
|
|
269276
|
-
"music",
|
|
269277
|
-
"asset",
|
|
269278
|
-
"characters",
|
|
269279
|
-
"eyebrow",
|
|
269280
|
-
"title",
|
|
269281
|
-
"caption",
|
|
269282
|
-
"kicker",
|
|
269283
|
-
"sub"
|
|
269284
|
-
];
|
|
269285
|
-
HEADING_RE2 = /^##\s+(.+?)\s*$/gm;
|
|
269286
|
-
LEADING_CUE_RE = /^(\s*)```ya?ml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/;
|
|
269287
|
-
ALLOWED_CUE_KEYS = new Set(STORYBOARD_CUE_KEYS);
|
|
269288
|
-
STRING_CUE_KEYS = /* @__PURE__ */ new Set(["narration", "backdrop", "video", "keyframe", "motion", "voice", "music", "asset", "eyebrow", "title", "caption", "kicker", "sub"]);
|
|
269289
|
-
MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
269290
|
-
}
|
|
269291
|
-
});
|
|
269292
|
-
|
|
269293
269515
|
// ../cli/src/pipeline/renderers/chrome.ts
|
|
269294
269516
|
import { existsSync as existsSync47 } from "node:fs";
|
|
269295
269517
|
import { homedir as homedir7 } from "node:os";
|
|
@@ -269365,7 +269587,7 @@ var init_ffmpeg_gate = __esm({
|
|
|
269365
269587
|
});
|
|
269366
269588
|
|
|
269367
269589
|
// ../cli/src/commands/_shared/scene-audio-scan.ts
|
|
269368
|
-
import { readFile as
|
|
269590
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
269369
269591
|
import { resolve as resolve30 } from "node:path";
|
|
269370
269592
|
function parseRootClips(rootHtml) {
|
|
269371
269593
|
const clips = [];
|
|
@@ -269406,7 +269628,7 @@ function makeFsCompositionReader(projectDir) {
|
|
|
269406
269628
|
return async (compositionSrcRel) => {
|
|
269407
269629
|
const abs = resolve30(projectDir, compositionSrcRel);
|
|
269408
269630
|
try {
|
|
269409
|
-
return await
|
|
269631
|
+
return await readFile15(abs, "utf-8");
|
|
269410
269632
|
} catch {
|
|
269411
269633
|
return null;
|
|
269412
269634
|
}
|
|
@@ -269472,7 +269694,7 @@ var init_scene_audio_scan = __esm({
|
|
|
269472
269694
|
});
|
|
269473
269695
|
|
|
269474
269696
|
// ../cli/src/commands/_shared/scene-audio-mux.ts
|
|
269475
|
-
import { rename as
|
|
269697
|
+
import { rename as rename5, unlink as unlink4 } from "node:fs/promises";
|
|
269476
269698
|
import { resolve as resolve31, dirname as dirname25, extname as extname10, basename as basename7 } from "node:path";
|
|
269477
269699
|
function buildAudioMuxFilter(audios) {
|
|
269478
269700
|
if (audios.length === 0) return null;
|
|
@@ -269581,7 +269803,7 @@ async function muxAudioIntoVideo(opts) {
|
|
|
269581
269803
|
error: `ffmpeg mux failed: ${msg}`
|
|
269582
269804
|
};
|
|
269583
269805
|
}
|
|
269584
|
-
await
|
|
269806
|
+
await rename5(tmpPath, opts.videoPath);
|
|
269585
269807
|
return {
|
|
269586
269808
|
success: true,
|
|
269587
269809
|
outputPath: opts.videoPath,
|
|
@@ -269597,7 +269819,7 @@ var init_scene_audio_mux = __esm({
|
|
|
269597
269819
|
|
|
269598
269820
|
// ../cli/src/commands/_shared/scene-assemble.ts
|
|
269599
269821
|
import { existsSync as existsSync48 } from "node:fs";
|
|
269600
|
-
import { readFile as
|
|
269822
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
269601
269823
|
import { resolve as resolve32, isAbsolute as isAbsolute7 } from "node:path";
|
|
269602
269824
|
async function executeSceneAssemble(opts) {
|
|
269603
269825
|
const projectDir = resolve32(opts.projectDir);
|
|
@@ -269628,7 +269850,7 @@ async function executeSceneAssemble(opts) {
|
|
|
269628
269850
|
let audioMuxWarning;
|
|
269629
269851
|
try {
|
|
269630
269852
|
opts.onProgress?.(0.1, "Scanning audio");
|
|
269631
|
-
const rootHtml = await
|
|
269853
|
+
const rootHtml = await readFile16(rootPath, "utf-8");
|
|
269632
269854
|
const audios = await scanSceneAudio({ projectDir, rootHtml });
|
|
269633
269855
|
audioCount = audios.length;
|
|
269634
269856
|
if (audios.length > 0) {
|
|
@@ -269682,7 +269904,7 @@ __export(scene_render_exports, {
|
|
|
269682
269904
|
});
|
|
269683
269905
|
import { execFile as execFile4 } from "node:child_process";
|
|
269684
269906
|
import { existsSync as existsSync49 } from "node:fs";
|
|
269685
|
-
import { mkdir as
|
|
269907
|
+
import { mkdir as mkdir12, readFile as readFile17, stat as stat5, writeFile as writeFile16 } from "node:fs/promises";
|
|
269686
269908
|
import { resolve as resolve33, relative as relative9, dirname as dirname26, basename as basename8, join as join61, isAbsolute as isAbsolute8 } from "node:path";
|
|
269687
269909
|
import { promisify as promisify4 } from "node:util";
|
|
269688
269910
|
function qualityToCrf(quality = "standard") {
|
|
@@ -269828,7 +270050,7 @@ async function executeSceneRender(opts = {}) {
|
|
|
269828
270050
|
}
|
|
269829
270051
|
const projectName = projectConfig.config.name;
|
|
269830
270052
|
const outputPath = opts.output ? resolve33(projectDir, opts.output) : defaultOutputPath({ projectDir, projectName, format: opts.format, beatId: opts.beatId });
|
|
269831
|
-
await
|
|
270053
|
+
await mkdir12(dirname26(outputPath), { recursive: true });
|
|
269832
270054
|
const config4 = buildRenderConfig({
|
|
269833
270055
|
fps: opts.fps,
|
|
269834
270056
|
quality: opts.quality,
|
|
@@ -269955,7 +270177,7 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
269955
270177
|
}
|
|
269956
270178
|
let report;
|
|
269957
270179
|
try {
|
|
269958
|
-
report = JSON.parse(await
|
|
270180
|
+
report = JSON.parse(await readFile17(reportPath, "utf-8"));
|
|
269959
270181
|
} catch (error) {
|
|
269960
270182
|
return {
|
|
269961
270183
|
success: false,
|
|
@@ -270024,8 +270246,8 @@ async function prepareBeatRenderRoot(opts) {
|
|
|
270024
270246
|
durationSec,
|
|
270025
270247
|
narrationPath
|
|
270026
270248
|
});
|
|
270027
|
-
await
|
|
270028
|
-
await
|
|
270249
|
+
await mkdir12(dirname26(join61(opts.projectDir, root2)), { recursive: true });
|
|
270250
|
+
await writeFile16(join61(opts.projectDir, root2), html, "utf-8");
|
|
270029
270251
|
return {
|
|
270030
270252
|
success: true,
|
|
270031
270253
|
root: root2,
|
|
@@ -270091,7 +270313,7 @@ function reportedBeatAssetPaths(beat) {
|
|
|
270091
270313
|
async function writeRenderReport(projectDir, result) {
|
|
270092
270314
|
const reportPath = join61(projectDir, "render-report.json");
|
|
270093
270315
|
try {
|
|
270094
|
-
await
|
|
270316
|
+
await writeFile16(
|
|
270095
270317
|
reportPath,
|
|
270096
270318
|
JSON.stringify(
|
|
270097
270319
|
{
|
|
@@ -270254,7 +270476,7 @@ function validateDesignMarkdown(md) {
|
|
|
270254
270476
|
const fm = raw2.match(DESIGN_FRONTMATTER_RE);
|
|
270255
270477
|
if (fm) {
|
|
270256
270478
|
try {
|
|
270257
|
-
const parsed = (0,
|
|
270479
|
+
const parsed = (0, import_yaml7.parse)(fm[1]);
|
|
270258
270480
|
if (!isPlainObject5(parsed)) {
|
|
270259
270481
|
issues.push({
|
|
270260
270482
|
severity: "warning",
|
|
@@ -270295,11 +270517,11 @@ function validateDesignMarkdown(md) {
|
|
|
270295
270517
|
}
|
|
270296
270518
|
return issues;
|
|
270297
270519
|
}
|
|
270298
|
-
var
|
|
270520
|
+
var import_yaml7, DESIGN_FRONTMATTER_RE, SECTION_RE, HEX_RE;
|
|
270299
270521
|
var init_design_parse = __esm({
|
|
270300
270522
|
"../cli/src/commands/_shared/design-parse.ts"() {
|
|
270301
270523
|
"use strict";
|
|
270302
|
-
|
|
270524
|
+
import_yaml7 = __toESM(require_dist3(), 1);
|
|
270303
270525
|
init_frontmatter();
|
|
270304
270526
|
DESIGN_FRONTMATTER_RE = /^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/;
|
|
270305
270527
|
SECTION_RE = /^##\s+(.+?)\s*$/gm;
|
|
@@ -270309,21 +270531,21 @@ var init_design_parse = __esm({
|
|
|
270309
270531
|
|
|
270310
270532
|
// ../cli/src/commands/_shared/compose-aivideo.ts
|
|
270311
270533
|
import { existsSync as existsSync50 } from "node:fs";
|
|
270312
|
-
import { mkdir as
|
|
270534
|
+
import { mkdir as mkdir13, readFile as readFile18, writeFile as writeFile17 } from "node:fs/promises";
|
|
270313
270535
|
import { join as join63, resolve as resolve34 } from "node:path";
|
|
270314
270536
|
function headingDescriptor(heading) {
|
|
270315
270537
|
const stripped = heading.replace(/^\s*beat\s+/i, "");
|
|
270316
270538
|
const m2 = stripped.match(/^[A-Za-z0-9][\w-]*(?:\s*[—:]\s*|\s+-\s+)(.+)$/);
|
|
270317
270539
|
const desc = clean2(m2 ? m2[1] : stripped);
|
|
270318
|
-
return /\s/.test(desc) || !/[-_]/.test(desc) ? desc :
|
|
270540
|
+
return /\s/.test(desc) || !/[-_]/.test(desc) ? desc : humanise3(desc);
|
|
270319
270541
|
}
|
|
270320
|
-
function
|
|
270542
|
+
function humanise3(id) {
|
|
270321
270543
|
return id.split(/[-_\s]+/).filter(Boolean).map((w4) => w4.charAt(0).toUpperCase() + w4.slice(1)).join(" ");
|
|
270322
270544
|
}
|
|
270323
270545
|
function beatOverlayText(beat) {
|
|
270324
270546
|
const cues = beat.cues ?? {};
|
|
270325
270547
|
const descriptor = headingDescriptor(beat.heading);
|
|
270326
|
-
const idHuman =
|
|
270548
|
+
const idHuman = humanise3(beat.id);
|
|
270327
270549
|
const titleCue = clean2(cues.title);
|
|
270328
270550
|
const title = titleCue || descriptor || idHuman;
|
|
270329
270551
|
const kickerCue = clean2(
|
|
@@ -270459,8 +270681,7 @@ async function composeAiVideo(opts) {
|
|
|
270459
270681
|
if (!commandExists("ffmpeg")) {
|
|
270460
270682
|
throw new Error("ffmpeg not found in PATH \u2014 required to concatenate AI-video clips.");
|
|
270461
270683
|
}
|
|
270462
|
-
const
|
|
270463
|
-
const md = await readFile19(storyboardPath, "utf-8");
|
|
270684
|
+
const md = await loadStoryboardMarkdown(projectDir);
|
|
270464
270685
|
const beats = parseStoryboard(md).beats;
|
|
270465
270686
|
if (beats.length === 0) throw new Error("STORYBOARD.md has no beats to compose.");
|
|
270466
270687
|
const tokens = opts.tokens ?? await loadProjectTokens(projectDir);
|
|
@@ -270473,7 +270694,7 @@ async function composeAiVideo(opts) {
|
|
|
270473
270694
|
}
|
|
270474
270695
|
clipRels.push(rel);
|
|
270475
270696
|
}
|
|
270476
|
-
await
|
|
270697
|
+
await mkdir13(join63(projectDir, "assets"), { recursive: true });
|
|
270477
270698
|
const bgRel = "assets/bg-full.mp4";
|
|
270478
270699
|
const concatArgs = buildBgConcatArgs(
|
|
270479
270700
|
clipRels.map((r2) => join63(projectDir, r2)),
|
|
@@ -270481,7 +270702,7 @@ async function composeAiVideo(opts) {
|
|
|
270481
270702
|
);
|
|
270482
270703
|
await execSafe("ffmpeg", concatArgs, { timeout: 6e5 });
|
|
270483
270704
|
const totalDurationSec = await probeDurationSec(join63(projectDir, bgRel));
|
|
270484
|
-
await
|
|
270705
|
+
await mkdir13(join63(projectDir, "compositions"), { recursive: true });
|
|
270485
270706
|
const sceneFiles = [];
|
|
270486
270707
|
for (let i3 = 0; i3 < beats.length; i3++) {
|
|
270487
270708
|
const beat = beats[i3];
|
|
@@ -270498,12 +270719,12 @@ async function composeAiVideo(opts) {
|
|
|
270498
270719
|
isLast: i3 === beats.length - 1
|
|
270499
270720
|
});
|
|
270500
270721
|
const rel = `compositions/scene-${beat.id}.html`;
|
|
270501
|
-
await
|
|
270722
|
+
await writeFile17(join63(projectDir, rel), html, "utf-8");
|
|
270502
270723
|
sceneFiles.push(rel);
|
|
270503
270724
|
}
|
|
270504
270725
|
const indexPath = join63(projectDir, "index.html");
|
|
270505
|
-
const next = existsSync50(indexPath) ? injectBgVideo(await
|
|
270506
|
-
await
|
|
270726
|
+
const next = existsSync50(indexPath) ? injectBgVideo(await readFile18(indexPath, "utf-8"), bgRel, totalDurationSec) : buildRootShell(tokens, bgRel, totalDurationSec);
|
|
270727
|
+
await writeFile17(indexPath, next, "utf-8");
|
|
270507
270728
|
return { bgVideoRel: bgRel, sceneFiles, totalDurationSec, beats: beats.length };
|
|
270508
270729
|
}
|
|
270509
270730
|
function buildRootShell(tokens, bgRel, totalDuration) {
|
|
@@ -270554,7 +270775,7 @@ async function loadProjectTokens(projectDir) {
|
|
|
270554
270775
|
const designPath = join63(projectDir, "DESIGN.md");
|
|
270555
270776
|
if (!existsSync50(designPath)) return DEFAULT_AIVIDEO_TOKENS;
|
|
270556
270777
|
try {
|
|
270557
|
-
return extractDesignTokens(await
|
|
270778
|
+
return extractDesignTokens(await readFile18(designPath, "utf-8"));
|
|
270558
270779
|
} catch {
|
|
270559
270780
|
return DEFAULT_AIVIDEO_TOKENS;
|
|
270560
270781
|
}
|
|
@@ -270613,6 +270834,7 @@ var init_compose_aivideo = __esm({
|
|
|
270613
270834
|
"use strict";
|
|
270614
270835
|
init_exec_safe();
|
|
270615
270836
|
init_storyboard_parse();
|
|
270837
|
+
init_storyboard_source();
|
|
270616
270838
|
init_design_parse();
|
|
270617
270839
|
BG_VIDEO_TRACK = 9;
|
|
270618
270840
|
DEFAULT_AIVIDEO_TOKENS = {
|
|
@@ -270906,7 +271128,6 @@ var init_composer_resolve = __esm({
|
|
|
270906
271128
|
|
|
270907
271129
|
// ../cli/src/commands/_shared/build-plan.ts
|
|
270908
271130
|
import { existsSync as existsSync53 } from "node:fs";
|
|
270909
|
-
import { readFile as readFile20 } from "node:fs/promises";
|
|
270910
271131
|
import { dirname as dirname27, join as join64, resolve as resolve36 } from "node:path";
|
|
270911
271132
|
function backdropCostUsd(quality) {
|
|
270912
271133
|
return quality === "hd" ? 0.2 : 0.05;
|
|
@@ -270958,9 +271179,13 @@ async function createBuildPlan(opts) {
|
|
|
270958
271179
|
validation: validation4
|
|
270959
271180
|
});
|
|
270960
271181
|
}
|
|
270961
|
-
const
|
|
271182
|
+
const loaded = await loadStoryboard(projectDir);
|
|
271183
|
+
const storyboardMd = loaded.markdown;
|
|
270962
271184
|
const validation3 = validateStoryboardMarkdown(storyboardMd);
|
|
270963
|
-
const validationIssues = [
|
|
271185
|
+
const validationIssues = [
|
|
271186
|
+
...strayBeatIssues(loaded.strayBeatIds),
|
|
271187
|
+
...validation3.issues
|
|
271188
|
+
];
|
|
270964
271189
|
const parsed = parseStoryboard(storyboardMd);
|
|
270965
271190
|
let sourceBeats = parsed.beats;
|
|
270966
271191
|
if (opts.beat) {
|
|
@@ -271618,6 +271843,7 @@ var init_build_plan = __esm({
|
|
|
271618
271843
|
init_build_backdrop_prompt();
|
|
271619
271844
|
init_composer_resolve();
|
|
271620
271845
|
init_storyboard_parse();
|
|
271846
|
+
init_storyboard_source();
|
|
271621
271847
|
init_project_config();
|
|
271622
271848
|
init_scene_project();
|
|
271623
271849
|
init_storyboard_edit();
|
|
@@ -271661,7 +271887,7 @@ var init_validate = __esm({
|
|
|
271661
271887
|
|
|
271662
271888
|
// ../cli/src/commands/generate/music.ts
|
|
271663
271889
|
import { resolve as resolve38 } from "node:path";
|
|
271664
|
-
import { writeFile as
|
|
271890
|
+
import { writeFile as writeFile18 } from "node:fs/promises";
|
|
271665
271891
|
import { existsSync as existsSync54 } from "node:fs";
|
|
271666
271892
|
async function executeMusic(options) {
|
|
271667
271893
|
try {
|
|
@@ -271684,7 +271910,7 @@ async function executeMusic(options) {
|
|
|
271684
271910
|
return { success: false, error: result2.error || "Music generation failed" };
|
|
271685
271911
|
}
|
|
271686
271912
|
const outputPath2 = resolve38(process.cwd(), options.output || "music.mp3");
|
|
271687
|
-
await
|
|
271913
|
+
await writeFile18(outputPath2, result2.audioBuffer);
|
|
271688
271914
|
return { success: true, outputPath: outputPath2, provider: "elevenlabs", duration: duration2 };
|
|
271689
271915
|
}
|
|
271690
271916
|
const apiKey = await getConfiguredApiKey("REPLICATE_API_TOKEN");
|
|
@@ -271718,7 +271944,7 @@ async function executeMusic(options) {
|
|
|
271718
271944
|
return { success: false, error: "Failed to download generated audio" };
|
|
271719
271945
|
const audioBuffer = Buffer.from(await response.arrayBuffer());
|
|
271720
271946
|
const outputPath = resolve38(process.cwd(), options.output || "music.mp3");
|
|
271721
|
-
await
|
|
271947
|
+
await writeFile18(outputPath, audioBuffer);
|
|
271722
271948
|
return { success: true, outputPath, provider: "replicate", duration };
|
|
271723
271949
|
} catch (error) {
|
|
271724
271950
|
return {
|
|
@@ -271782,7 +272008,7 @@ function registerMusicCommand(parent) {
|
|
|
271782
272008
|
exitWithError(apiError(result.error || "Music generation failed", true));
|
|
271783
272009
|
}
|
|
271784
272010
|
const outputPath = resolve38(process.cwd(), options.output);
|
|
271785
|
-
await
|
|
272011
|
+
await writeFile18(outputPath, result.audioBuffer);
|
|
271786
272012
|
spinner2.succeed(source_default.green("Music generated successfully"));
|
|
271787
272013
|
if (isJsonMode()) {
|
|
271788
272014
|
outputSuccess({
|
|
@@ -271868,7 +272094,7 @@ function registerMusicCommand(parent) {
|
|
|
271868
272094
|
}
|
|
271869
272095
|
const audioBuffer = Buffer.from(await response.arrayBuffer());
|
|
271870
272096
|
const outputPath = resolve38(process.cwd(), options.output);
|
|
271871
|
-
await
|
|
272097
|
+
await writeFile18(outputPath, audioBuffer);
|
|
271872
272098
|
spinner2.succeed(source_default.green("Music generated successfully"));
|
|
271873
272099
|
if (isJsonMode()) {
|
|
271874
272100
|
outputSuccess({
|
|
@@ -271946,7 +272172,7 @@ __export(scene_build_exports, {
|
|
|
271946
272172
|
resolveSceneBuildMode: () => resolveSceneBuildMode
|
|
271947
272173
|
});
|
|
271948
272174
|
import { existsSync as existsSync55, readFileSync as readFileSync21 } from "node:fs";
|
|
271949
|
-
import { copyFile as copyFile4, mkdir as
|
|
272175
|
+
import { copyFile as copyFile4, mkdir as mkdir14, readFile as readFile19, rm as rm6, writeFile as writeFile19 } from "node:fs/promises";
|
|
271950
272176
|
import { dirname as dirname28, join as join65, resolve as resolve39 } from "node:path";
|
|
271951
272177
|
function readProjectKindSync(projectDir) {
|
|
271952
272178
|
try {
|
|
@@ -272033,7 +272259,7 @@ async function executeSceneBuild(opts) {
|
|
|
272033
272259
|
if (!buildPlan.validation.ok) {
|
|
272034
272260
|
let invalidBeats = [];
|
|
272035
272261
|
if (existsSync55(storyboardPath)) {
|
|
272036
|
-
invalidBeats = parseStoryboard(await
|
|
272262
|
+
invalidBeats = parseStoryboard(await loadStoryboardMarkdown(projectDir)).beats;
|
|
272037
272263
|
}
|
|
272038
272264
|
return finishBuildResult({
|
|
272039
272265
|
success: false,
|
|
@@ -272071,7 +272297,7 @@ async function executeSceneBuild(opts) {
|
|
|
272071
272297
|
totalLatencyMs: Date.now() - startedAt
|
|
272072
272298
|
});
|
|
272073
272299
|
}
|
|
272074
|
-
const storyboardMd = await
|
|
272300
|
+
const storyboardMd = await loadStoryboardMarkdown(projectDir);
|
|
272075
272301
|
const parsed = parseStoryboard(storyboardMd);
|
|
272076
272302
|
if (parsed.beats.length === 0) {
|
|
272077
272303
|
return finishBuildResult({
|
|
@@ -272730,7 +272956,7 @@ async function dispatchNarration(beat, ctx) {
|
|
|
272730
272956
|
};
|
|
272731
272957
|
}
|
|
272732
272958
|
if (existsSync55(cacheAbs) && !ctx.force) {
|
|
272733
|
-
await
|
|
272959
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
272734
272960
|
await copyFile4(cacheAbs, abs);
|
|
272735
272961
|
await writeAssetMetadata({
|
|
272736
272962
|
projectDir: ctx.projectDir,
|
|
@@ -272761,14 +272987,14 @@ async function dispatchNarration(beat, ctx) {
|
|
|
272761
272987
|
ctx.onProgress({ type: "narration-failed", beatId: beat.id, error });
|
|
272762
272988
|
return { status: "failed", error };
|
|
272763
272989
|
}
|
|
272764
|
-
await
|
|
272765
|
-
await
|
|
272990
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
272991
|
+
await writeFile19(abs, result.audioBuffer);
|
|
272766
272992
|
for (const otherExt of ["mp3", "wav"]) {
|
|
272767
272993
|
const sibling = join65(ctx.projectDir, `assets/narration-${beat.id}.${otherExt}`);
|
|
272768
|
-
if (sibling !== abs && existsSync55(sibling)) await
|
|
272994
|
+
if (sibling !== abs && existsSync55(sibling)) await rm6(sibling, { force: true });
|
|
272769
272995
|
}
|
|
272770
|
-
await
|
|
272771
|
-
await
|
|
272996
|
+
await mkdir14(dirname28(cacheAbs), { recursive: true });
|
|
272997
|
+
await writeFile19(cacheAbs, result.audioBuffer);
|
|
272772
272998
|
await writeAssetMetadata({
|
|
272773
272999
|
projectDir: ctx.projectDir,
|
|
272774
273000
|
kind: "narration",
|
|
@@ -272824,8 +273050,8 @@ async function dispatchTranscript(beat, narrationPath, narrationFresh, ctx) {
|
|
|
272824
273050
|
return "skipped";
|
|
272825
273051
|
}
|
|
272826
273052
|
try {
|
|
272827
|
-
await
|
|
272828
|
-
await
|
|
273053
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273054
|
+
await writeFile19(abs, JSON.stringify(words, null, 2), "utf-8");
|
|
272829
273055
|
} catch (err) {
|
|
272830
273056
|
ctx.onProgress({
|
|
272831
273057
|
type: "transcript-skipped",
|
|
@@ -272912,7 +273138,7 @@ async function buildCharacters(characters, ctx) {
|
|
|
272912
273138
|
}
|
|
272913
273139
|
const cacheAbs = join65(ctx.projectDir, cache.path);
|
|
272914
273140
|
if (existsSync55(cacheAbs) && !ctx.force) {
|
|
272915
|
-
await
|
|
273141
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
272916
273142
|
await copyFile4(cacheAbs, abs);
|
|
272917
273143
|
await writeAssetMetadata({
|
|
272918
273144
|
projectDir: ctx.projectDir,
|
|
@@ -272944,10 +273170,10 @@ async function buildCharacters(characters, ctx) {
|
|
|
272944
273170
|
ctx.onProgress({ type: "character-failed", name: character.name, error: generated.error });
|
|
272945
273171
|
continue;
|
|
272946
273172
|
}
|
|
272947
|
-
await
|
|
272948
|
-
await
|
|
272949
|
-
await
|
|
272950
|
-
await
|
|
273173
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273174
|
+
await writeFile19(abs, generated.buffer);
|
|
273175
|
+
await mkdir14(dirname28(cacheAbs), { recursive: true });
|
|
273176
|
+
await writeFile19(cacheAbs, generated.buffer);
|
|
272951
273177
|
await writeAssetMetadata({
|
|
272952
273178
|
projectDir: ctx.projectDir,
|
|
272953
273179
|
kind: "character",
|
|
@@ -273015,7 +273241,7 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
273015
273241
|
}
|
|
273016
273242
|
const cacheAbs = join65(ctx.projectDir, cache.path);
|
|
273017
273243
|
if (existsSync55(cacheAbs) && !ctx.force) {
|
|
273018
|
-
await
|
|
273244
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273019
273245
|
await copyFile4(cacheAbs, abs);
|
|
273020
273246
|
await writeAssetMetadata({
|
|
273021
273247
|
projectDir: ctx.projectDir,
|
|
@@ -273045,11 +273271,11 @@ async function dispatchBackdrop(beat, ctx) {
|
|
|
273045
273271
|
ctx.onProgress({ type: "backdrop-failed", beatId: beat.id, error });
|
|
273046
273272
|
return { status: "failed", error };
|
|
273047
273273
|
}
|
|
273048
|
-
await
|
|
273274
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273049
273275
|
const buffer = generated.buffer;
|
|
273050
|
-
await
|
|
273051
|
-
await
|
|
273052
|
-
await
|
|
273276
|
+
await writeFile19(abs, buffer);
|
|
273277
|
+
await mkdir14(dirname28(cacheAbs), { recursive: true });
|
|
273278
|
+
await writeFile19(cacheAbs, buffer);
|
|
273053
273279
|
await writeAssetMetadata({
|
|
273054
273280
|
projectDir: ctx.projectDir,
|
|
273055
273281
|
kind: "backdrop",
|
|
@@ -273175,7 +273401,7 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
273175
273401
|
}
|
|
273176
273402
|
const cacheAbs = join65(ctx.projectDir, cache.path);
|
|
273177
273403
|
if (existsSync55(cacheAbs) && !ctx.force) {
|
|
273178
|
-
await
|
|
273404
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273179
273405
|
await copyFile4(cacheAbs, abs);
|
|
273180
273406
|
await writeAssetMetadata({
|
|
273181
273407
|
projectDir: ctx.projectDir,
|
|
@@ -273193,7 +273419,7 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
273193
273419
|
const sheetBuffers = [];
|
|
273194
273420
|
for (const relPath of characterRefsRel) {
|
|
273195
273421
|
const sheetAbs = join65(ctx.projectDir, relPath);
|
|
273196
|
-
if (existsSync55(sheetAbs)) sheetBuffers.push(await
|
|
273422
|
+
if (existsSync55(sheetAbs)) sheetBuffers.push(await readFile19(sheetAbs));
|
|
273197
273423
|
}
|
|
273198
273424
|
const imgCtx = {
|
|
273199
273425
|
projectDir: ctx.projectDir,
|
|
@@ -273204,10 +273430,10 @@ async function ensureKeyframe(beat, ctx, keyframeCue, characterRefsRel) {
|
|
|
273204
273430
|
const identityLock = "Keep the EXACT same person and face as the reference image(s): identical facial features (eyes, nose shape, jawline), skin tone and complexion, hairstyle, hair color, and wardrobe. Do not restyle or change the face. Change only the scene, pose, framing, and lighting. ";
|
|
273205
273431
|
const generated = sheetBuffers.length > 0 ? await editKeyframeImage(`${identityLock}${keyframeCue}`, sheetBuffers, imgCtx, ratio) : await generateBackdropImage(keyframeCue, imgCtx, ratio);
|
|
273206
273432
|
if (!generated.success) return { status: "failed", error: generated.error };
|
|
273207
|
-
await
|
|
273208
|
-
await
|
|
273209
|
-
await
|
|
273210
|
-
await
|
|
273433
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273434
|
+
await writeFile19(abs, generated.buffer);
|
|
273435
|
+
await mkdir14(dirname28(cacheAbs), { recursive: true });
|
|
273436
|
+
await writeFile19(cacheAbs, generated.buffer);
|
|
273211
273437
|
await writeAssetMetadata({
|
|
273212
273438
|
projectDir: ctx.projectDir,
|
|
273213
273439
|
kind: "keyframe",
|
|
@@ -273301,7 +273527,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
273301
273527
|
}
|
|
273302
273528
|
const cacheAbs = join65(ctx.projectDir, cache.path);
|
|
273303
273529
|
if (existsSync55(cacheAbs) && !ctx.force) {
|
|
273304
|
-
await
|
|
273530
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273305
273531
|
await copyFile4(cacheAbs, abs);
|
|
273306
273532
|
await writeAssetMetadata({
|
|
273307
273533
|
projectDir: ctx.projectDir,
|
|
@@ -273356,7 +273582,7 @@ async function dispatchVideo(beat, ctx, keyframe) {
|
|
|
273356
273582
|
return { status: "failed", error };
|
|
273357
273583
|
}
|
|
273358
273584
|
if (result.status === "completed" && existsSync55(abs)) {
|
|
273359
|
-
await
|
|
273585
|
+
await mkdir14(dirname28(cacheAbs), { recursive: true });
|
|
273360
273586
|
await copyFile4(abs, cacheAbs);
|
|
273361
273587
|
await writeAssetMetadata({
|
|
273362
273588
|
projectDir: ctx.projectDir,
|
|
@@ -273458,7 +273684,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
273458
273684
|
}
|
|
273459
273685
|
const cacheAbs = join65(ctx.projectDir, cache.path);
|
|
273460
273686
|
if (existsSync55(cacheAbs) && !ctx.force) {
|
|
273461
|
-
await
|
|
273687
|
+
await mkdir14(dirname28(abs), { recursive: true });
|
|
273462
273688
|
await copyFile4(cacheAbs, abs);
|
|
273463
273689
|
await writeAssetMetadata({
|
|
273464
273690
|
projectDir: ctx.projectDir,
|
|
@@ -273536,7 +273762,7 @@ async function dispatchMusic(beat, ctx) {
|
|
|
273536
273762
|
ctx.onProgress({ type: "music-failed", beatId: beat.id, error });
|
|
273537
273763
|
return { status: "failed", error };
|
|
273538
273764
|
}
|
|
273539
|
-
await
|
|
273765
|
+
await mkdir14(dirname28(cacheAbs), { recursive: true });
|
|
273540
273766
|
await copyFile4(abs, cacheAbs);
|
|
273541
273767
|
await writeAssetMetadata({
|
|
273542
273768
|
projectDir: ctx.projectDir,
|
|
@@ -273836,7 +274062,7 @@ async function finalizeBuildResult(projectDir, startedAt, result) {
|
|
|
273836
274062
|
totalLatencyMs: Date.now() - startedAt
|
|
273837
274063
|
};
|
|
273838
274064
|
try {
|
|
273839
|
-
await
|
|
274065
|
+
await writeFile19(
|
|
273840
274066
|
reportPath,
|
|
273841
274067
|
JSON.stringify(toBuildReport(projectDir, withMeta), null, 2) + "\n",
|
|
273842
274068
|
"utf-8"
|
|
@@ -274074,6 +274300,7 @@ var init_scene_build = __esm({
|
|
|
274074
274300
|
init_transcribe_narration();
|
|
274075
274301
|
init_scene_render();
|
|
274076
274302
|
init_storyboard_parse();
|
|
274303
|
+
init_storyboard_source();
|
|
274077
274304
|
init_scene_project();
|
|
274078
274305
|
init_build_plan();
|
|
274079
274306
|
init_build_asset_reference();
|
|
@@ -274200,7 +274427,7 @@ __export(ai_audio_exports, {
|
|
|
274200
274427
|
executeVoiceClone: () => executeVoiceClone
|
|
274201
274428
|
});
|
|
274202
274429
|
import { resolve as resolve41, dirname as dirname29, basename as basename9, extname as extname12 } from "node:path";
|
|
274203
|
-
import { readFile as
|
|
274430
|
+
import { readFile as readFile20, writeFile as writeFile20 } from "node:fs/promises";
|
|
274204
274431
|
import { existsSync as existsSync56 } from "node:fs";
|
|
274205
274432
|
async function executeTranscribe(options) {
|
|
274206
274433
|
const { audioPath, language, output: output3, format: format4, apiKey } = options;
|
|
@@ -274211,7 +274438,7 @@ async function executeTranscribe(options) {
|
|
|
274211
274438
|
if (!existsSync56(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
274212
274439
|
const whisper = new WhisperProvider();
|
|
274213
274440
|
await whisper.initialize({ apiKey: key2 });
|
|
274214
|
-
const audioBuffer = await
|
|
274441
|
+
const audioBuffer = await readFile20(absPath);
|
|
274215
274442
|
const audioBlob = new Blob([audioBuffer]);
|
|
274216
274443
|
const result = await whisper.transcribe(audioBlob, language);
|
|
274217
274444
|
if (result.status === "failed") {
|
|
@@ -274222,7 +274449,7 @@ async function executeTranscribe(options) {
|
|
|
274222
274449
|
outputPath = resolve41(process.cwd(), output3);
|
|
274223
274450
|
const fmt = detectFormat(output3, format4);
|
|
274224
274451
|
const content = formatTranscript(result, fmt);
|
|
274225
|
-
await
|
|
274452
|
+
await writeFile20(outputPath, content, "utf-8");
|
|
274226
274453
|
}
|
|
274227
274454
|
return {
|
|
274228
274455
|
success: true,
|
|
@@ -274242,7 +274469,7 @@ async function executeIsolate(options) {
|
|
|
274242
274469
|
if (!key2) return { success: false, error: "ELEVENLABS_API_KEY required" };
|
|
274243
274470
|
const absPath = resolve41(process.cwd(), audioPath);
|
|
274244
274471
|
if (!existsSync56(absPath)) return { success: false, error: `File not found: ${absPath}` };
|
|
274245
|
-
const audioBuffer = await
|
|
274472
|
+
const audioBuffer = await readFile20(absPath);
|
|
274246
274473
|
const elevenlabs = new ElevenLabsProvider();
|
|
274247
274474
|
await elevenlabs.initialize({ apiKey: key2 });
|
|
274248
274475
|
const result = await elevenlabs.isolateVocals(audioBuffer);
|
|
@@ -274250,7 +274477,7 @@ async function executeIsolate(options) {
|
|
|
274250
274477
|
return { success: false, error: result.error || "Audio isolation failed" };
|
|
274251
274478
|
}
|
|
274252
274479
|
const outputPath = resolve41(process.cwd(), output3);
|
|
274253
|
-
await
|
|
274480
|
+
await writeFile20(outputPath, result.audioBuffer);
|
|
274254
274481
|
return { success: true, outputPath };
|
|
274255
274482
|
} catch (error) {
|
|
274256
274483
|
return { success: false, error: `Audio isolation failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -274268,7 +274495,7 @@ async function executeVoiceClone(options) {
|
|
|
274268
274495
|
for (const samplePath of samplePaths) {
|
|
274269
274496
|
const absPath = resolve41(process.cwd(), samplePath);
|
|
274270
274497
|
if (!existsSync56(absPath)) return { success: false, error: `File not found: ${samplePath}` };
|
|
274271
|
-
const buffer = await
|
|
274498
|
+
const buffer = await readFile20(absPath);
|
|
274272
274499
|
audioBuffers.push(buffer);
|
|
274273
274500
|
}
|
|
274274
274501
|
const elevenlabs = new ElevenLabsProvider();
|
|
@@ -274306,7 +274533,7 @@ async function executeDub(options) {
|
|
|
274306
274533
|
}
|
|
274307
274534
|
const whisper = new WhisperProvider();
|
|
274308
274535
|
await whisper.initialize({ apiKey: openaiKey });
|
|
274309
|
-
const audioBuffer = await
|
|
274536
|
+
const audioBuffer = await readFile20(audioPath);
|
|
274310
274537
|
const audioBlob = new Blob([audioBuffer]);
|
|
274311
274538
|
const transcriptResult = await whisper.transcribe(audioBlob, source3);
|
|
274312
274539
|
if (transcriptResult.status === "failed" || !transcriptResult.segments) {
|
|
@@ -274361,7 +274588,7 @@ ${segmentTexts}`,
|
|
|
274361
274588
|
translated: translatedSegments[i3]?.text || s2.text
|
|
274362
274589
|
}))
|
|
274363
274590
|
};
|
|
274364
|
-
await
|
|
274591
|
+
await writeFile20(timingPath, JSON.stringify(timingData, null, 2));
|
|
274365
274592
|
}
|
|
274366
274593
|
return {
|
|
274367
274594
|
success: true,
|
|
@@ -274384,7 +274611,7 @@ ${segmentTexts}`,
|
|
|
274384
274611
|
const outputExt = isVideo ? ".mp3" : extname12(absPath);
|
|
274385
274612
|
const defaultOutputPath2 = resolve41(dirname29(absPath), `${basename9(absPath, extname12(absPath))}-${language}${outputExt}`);
|
|
274386
274613
|
const finalOutputPath = resolve41(process.cwd(), output3 || defaultOutputPath2);
|
|
274387
|
-
await
|
|
274614
|
+
await writeFile20(finalOutputPath, combinedBuffer);
|
|
274388
274615
|
if (isVideo && audioPath !== absPath) {
|
|
274389
274616
|
try {
|
|
274390
274617
|
const { unlink: unlink6 } = await import("node:fs/promises");
|
|
@@ -274449,7 +274676,7 @@ var init_ai_audio = __esm({
|
|
|
274449
274676
|
|
|
274450
274677
|
// ../cli/src/commands/_shared/edit/silence-cut.ts
|
|
274451
274678
|
import { existsSync as existsSync57 } from "node:fs";
|
|
274452
|
-
import { readFile as
|
|
274679
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
274453
274680
|
async function detectSilencePeriods(videoPath, noiseThreshold, minDuration) {
|
|
274454
274681
|
const totalDuration = await getVideoDuration(videoPath);
|
|
274455
274682
|
const { stdout, stderr } = await execSafe(
|
|
@@ -274499,7 +274726,7 @@ async function detectSilencePeriodsWithGemini(videoPath, minDuration, options) {
|
|
|
274499
274726
|
}
|
|
274500
274727
|
const gemini = new GeminiProvider();
|
|
274501
274728
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
274502
|
-
const videoBuffer = await
|
|
274729
|
+
const videoBuffer = await readFile21(videoPath);
|
|
274503
274730
|
const modelId = options.model ? resolveGeminiTextModel(options.model) : void 0;
|
|
274504
274731
|
const prompt3 = `Analyze this video and identify all silent or dead segments where there is NO meaningful content.
|
|
274505
274732
|
|
|
@@ -274684,10 +274911,10 @@ var init_silence_cut = __esm({
|
|
|
274684
274911
|
|
|
274685
274912
|
// ../cli/src/commands/_shared/edit/jump-cut.ts
|
|
274686
274913
|
import { existsSync as existsSync58 } from "node:fs";
|
|
274687
|
-
import { readFile as
|
|
274914
|
+
import { readFile as readFile23, writeFile as writeFile21, mkdir as mkdir15 } from "node:fs/promises";
|
|
274688
274915
|
import { join as join66 } from "node:path";
|
|
274689
274916
|
async function transcribeWithWords(audioPath, apiKey, language) {
|
|
274690
|
-
const audioBuffer = await
|
|
274917
|
+
const audioBuffer = await readFile23(audioPath);
|
|
274691
274918
|
const audioBlob = new Blob([audioBuffer]);
|
|
274692
274919
|
const formData = new FormData();
|
|
274693
274920
|
formData.append("file", audioBlob, "audio.wav");
|
|
@@ -274764,7 +274991,7 @@ async function executeJumpCut(options) {
|
|
|
274764
274991
|
}
|
|
274765
274992
|
try {
|
|
274766
274993
|
const tmpDir = `/tmp/vibe_jumpcut_${Date.now()}`;
|
|
274767
|
-
await
|
|
274994
|
+
await mkdir15(tmpDir, { recursive: true });
|
|
274768
274995
|
const audioPath = join66(tmpDir, "audio.wav");
|
|
274769
274996
|
try {
|
|
274770
274997
|
await execSafe(
|
|
@@ -274843,7 +275070,7 @@ async function executeJumpCut(options) {
|
|
|
274843
275070
|
}
|
|
274844
275071
|
const concatList = segmentPaths.map((p2) => `file '${p2}'`).join("\n");
|
|
274845
275072
|
const listPath = join66(tmpDir, "concat.txt");
|
|
274846
|
-
await
|
|
275073
|
+
await writeFile21(listPath, concatList);
|
|
274847
275074
|
await execSafe(
|
|
274848
275075
|
"ffmpeg",
|
|
274849
275076
|
[
|
|
@@ -274870,8 +275097,8 @@ async function executeJumpCut(options) {
|
|
|
274870
275097
|
};
|
|
274871
275098
|
} finally {
|
|
274872
275099
|
try {
|
|
274873
|
-
const { rm:
|
|
274874
|
-
await
|
|
275100
|
+
const { rm: rm10 } = await import("node:fs/promises");
|
|
275101
|
+
await rm10(tmpDir, { recursive: true, force: true });
|
|
274875
275102
|
} catch {
|
|
274876
275103
|
}
|
|
274877
275104
|
}
|
|
@@ -274948,7 +275175,7 @@ __export(remotion_exports, {
|
|
|
274948
275175
|
wrapComponentWithImage: () => wrapComponentWithImage,
|
|
274949
275176
|
wrapComponentWithVideo: () => wrapComponentWithVideo
|
|
274950
275177
|
});
|
|
274951
|
-
import { writeFile as
|
|
275178
|
+
import { writeFile as writeFile23, mkdir as mkdir16, rm as rm7, copyFile as copyFile5 } from "node:fs/promises";
|
|
274952
275179
|
import { existsSync as existsSync59 } from "node:fs";
|
|
274953
275180
|
import { join as join67 } from "node:path";
|
|
274954
275181
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
@@ -274970,7 +275197,7 @@ async function ensureRemotionInstalled() {
|
|
|
274970
275197
|
}
|
|
274971
275198
|
async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
274972
275199
|
const dir = join67(tmpdir9(), `vibe_motion_${Date.now()}`);
|
|
274973
|
-
await
|
|
275200
|
+
await mkdir16(dir, { recursive: true });
|
|
274974
275201
|
const deps = {
|
|
274975
275202
|
remotion: REMOTION_VERSION,
|
|
274976
275203
|
"@remotion/cli": REMOTION_VERSION,
|
|
@@ -274988,7 +275215,7 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
274988
275215
|
dependencies: deps
|
|
274989
275216
|
};
|
|
274990
275217
|
const packageJsonStr = JSON.stringify(packageJson, null, 2);
|
|
274991
|
-
await
|
|
275218
|
+
await writeFile23(join67(dir, "package.json"), packageJsonStr);
|
|
274992
275219
|
const tsconfig = {
|
|
274993
275220
|
compilerOptions: {
|
|
274994
275221
|
target: "ES2020",
|
|
@@ -275000,8 +275227,8 @@ async function scaffoldRemotionProject(componentCode, componentName, opts) {
|
|
|
275000
275227
|
skipLibCheck: true
|
|
275001
275228
|
}
|
|
275002
275229
|
};
|
|
275003
|
-
await
|
|
275004
|
-
await
|
|
275230
|
+
await writeFile23(join67(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
275231
|
+
await writeFile23(join67(dir, "Component.tsx"), componentCode);
|
|
275005
275232
|
const rootCode = `import { registerRoot, Composition } from "remotion";
|
|
275006
275233
|
import { ${componentName} } from "./Component";
|
|
275007
275234
|
|
|
@@ -275020,7 +275247,7 @@ const Root = () => {
|
|
|
275020
275247
|
|
|
275021
275248
|
registerRoot(Root);
|
|
275022
275249
|
`;
|
|
275023
|
-
await
|
|
275250
|
+
await writeFile23(join67(dir, "Root.tsx"), rootCode);
|
|
275024
275251
|
const depsHash = createHash11("md5").update(packageJsonStr).digest("hex").slice(0, 12);
|
|
275025
275252
|
const cacheMarker = join67(REMOTION_CACHE_DIR, `.deps-${depsHash}`);
|
|
275026
275253
|
const cachedModules = join67(REMOTION_CACHE_DIR, "node_modules");
|
|
@@ -275034,15 +275261,15 @@ registerRoot(Root);
|
|
|
275034
275261
|
} else {
|
|
275035
275262
|
await this_npmInstall(dir);
|
|
275036
275263
|
try {
|
|
275037
|
-
await
|
|
275038
|
-
await
|
|
275264
|
+
await mkdir16(REMOTION_CACHE_DIR, { recursive: true });
|
|
275265
|
+
await writeFile23(join67(REMOTION_CACHE_DIR, "package.json"), packageJsonStr);
|
|
275039
275266
|
if (existsSync59(join67(dir, "node_modules"))) {
|
|
275040
|
-
const { rename:
|
|
275041
|
-
await
|
|
275267
|
+
const { rename: rename7, symlink: symlink4 } = await import("node:fs/promises");
|
|
275268
|
+
await rename7(join67(dir, "node_modules"), cachedModules).catch(() => {
|
|
275042
275269
|
});
|
|
275043
275270
|
await symlink4(cachedModules, join67(dir, "node_modules"), "dir").catch(() => {
|
|
275044
275271
|
});
|
|
275045
|
-
await
|
|
275272
|
+
await writeFile23(cacheMarker, depsHash);
|
|
275046
275273
|
}
|
|
275047
275274
|
} catch {
|
|
275048
275275
|
}
|
|
@@ -275142,7 +275369,7 @@ async function renderMotion(options) {
|
|
|
275142
275369
|
stderr: ${stderr}` : ""}`);
|
|
275143
275370
|
return { success: false, error: `Remotion render failed: ${msg}` };
|
|
275144
275371
|
} finally {
|
|
275145
|
-
await
|
|
275372
|
+
await rm7(dir, { recursive: true, force: true }).catch(() => {
|
|
275146
275373
|
});
|
|
275147
275374
|
}
|
|
275148
275375
|
}
|
|
@@ -275211,7 +275438,7 @@ async function renderWithEmbeddedImage(options) {
|
|
|
275211
275438
|
);
|
|
275212
275439
|
try {
|
|
275213
275440
|
const publicDir = join67(dir, "public");
|
|
275214
|
-
await
|
|
275441
|
+
await mkdir16(publicDir, { recursive: true });
|
|
275215
275442
|
await copyFile5(options.imagePath, join67(publicDir, options.imageFileName));
|
|
275216
275443
|
const entryPoint = join67(dir, "Root.tsx");
|
|
275217
275444
|
const mp4Out = options.outputPath.replace(/\.\w+$/, ".mp4");
|
|
@@ -275234,7 +275461,7 @@ async function renderWithEmbeddedImage(options) {
|
|
|
275234
275461
|
const msg = error instanceof Error ? error.message : String(error);
|
|
275235
275462
|
return { success: false, error: `Remotion image embed render failed: ${msg}` };
|
|
275236
275463
|
} finally {
|
|
275237
|
-
await
|
|
275464
|
+
await rm7(dir, { recursive: true, force: true }).catch(() => {
|
|
275238
275465
|
});
|
|
275239
275466
|
}
|
|
275240
275467
|
}
|
|
@@ -275275,7 +275502,7 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
275275
275502
|
);
|
|
275276
275503
|
try {
|
|
275277
275504
|
const publicDir = join67(dir, "public");
|
|
275278
|
-
await
|
|
275505
|
+
await mkdir16(publicDir, { recursive: true });
|
|
275279
275506
|
await copyFile5(options.videoPath, join67(publicDir, options.videoFileName));
|
|
275280
275507
|
const entryPoint = join67(dir, "Root.tsx");
|
|
275281
275508
|
const mp4VideoOnly = options.outputPath.replace(/\.\w+$/, "_video_only.mp4");
|
|
@@ -275311,14 +275538,14 @@ async function renderWithEmbeddedVideo(options) {
|
|
|
275311
275538
|
"-shortest",
|
|
275312
275539
|
mp4Out
|
|
275313
275540
|
], { timeout: 12e4 });
|
|
275314
|
-
await
|
|
275541
|
+
await rm7(mp4VideoOnly, { force: true }).catch(() => {
|
|
275315
275542
|
});
|
|
275316
275543
|
return { success: true, outputPath: mp4Out };
|
|
275317
275544
|
} catch (error) {
|
|
275318
275545
|
const msg = error instanceof Error ? error.message : String(error);
|
|
275319
275546
|
return { success: false, error: `Remotion video embed render failed: ${msg}` };
|
|
275320
275547
|
} finally {
|
|
275321
|
-
await
|
|
275548
|
+
await rm7(dir, { recursive: true, force: true }).catch(() => {
|
|
275322
275549
|
});
|
|
275323
275550
|
}
|
|
275324
275551
|
}
|
|
@@ -275699,7 +275926,7 @@ var init_remotion = __esm({
|
|
|
275699
275926
|
|
|
275700
275927
|
// ../cli/src/commands/_shared/edit/caption.ts
|
|
275701
275928
|
import { existsSync as existsSync60 } from "node:fs";
|
|
275702
|
-
import { readFile as
|
|
275929
|
+
import { readFile as readFile24, writeFile as writeFile24, mkdir as mkdir17 } from "node:fs/promises";
|
|
275703
275930
|
import { dirname as dirname30, basename as basename10, extname as extname13, join as join68 } from "node:path";
|
|
275704
275931
|
function getCaptionForceStyle(style, fontSize, fontColor, position) {
|
|
275705
275932
|
const alignment = position === "top" ? 8 : position === "center" ? 5 : 2;
|
|
@@ -275746,7 +275973,7 @@ async function executeCaption(options) {
|
|
|
275746
275973
|
}
|
|
275747
275974
|
try {
|
|
275748
275975
|
const tmpDir = `/tmp/vibe_caption_${Date.now()}`;
|
|
275749
|
-
await
|
|
275976
|
+
await mkdir17(tmpDir, { recursive: true });
|
|
275750
275977
|
const audioPath = join68(tmpDir, "audio.wav");
|
|
275751
275978
|
const srtPath = join68(tmpDir, "captions.srt");
|
|
275752
275979
|
try {
|
|
@@ -275769,7 +275996,7 @@ async function executeCaption(options) {
|
|
|
275769
275996
|
);
|
|
275770
275997
|
const whisper = new WhisperProvider();
|
|
275771
275998
|
await whisper.initialize({ apiKey: openaiKey });
|
|
275772
|
-
const audioBuffer = await
|
|
275999
|
+
const audioBuffer = await readFile24(audioPath);
|
|
275773
276000
|
const audioBlob = new Blob([audioBuffer]);
|
|
275774
276001
|
const transcriptResult = await whisper.transcribe(audioBlob, language);
|
|
275775
276002
|
if (transcriptResult.status === "failed" || !transcriptResult.segments || transcriptResult.segments.length === 0) {
|
|
@@ -275779,7 +276006,7 @@ async function executeCaption(options) {
|
|
|
275779
276006
|
};
|
|
275780
276007
|
}
|
|
275781
276008
|
const srtContent = formatSRT(transcriptResult.segments);
|
|
275782
|
-
await
|
|
276009
|
+
await writeFile24(srtPath, srtContent);
|
|
275783
276010
|
const { width, height } = await getVideoResolution(videoPath);
|
|
275784
276011
|
const fontSize = customFontSize || Math.round(height / 18);
|
|
275785
276012
|
let hasSubtitles = false;
|
|
@@ -275821,7 +276048,7 @@ async function executeCaption(options) {
|
|
|
275821
276048
|
outputDir2,
|
|
275822
276049
|
basename10(outputPath, extname13(outputPath)) + ".srt"
|
|
275823
276050
|
);
|
|
275824
|
-
await
|
|
276051
|
+
await writeFile24(outputSrtPath2, srtContent);
|
|
275825
276052
|
return { success: false, error: `${remotionErr}
|
|
275826
276053
|
SRT saved to: ${outputSrtPath2}` };
|
|
275827
276054
|
}
|
|
@@ -275860,7 +276087,7 @@ SRT saved to: ${outputSrtPath2}` };
|
|
|
275860
276087
|
outputDir2,
|
|
275861
276088
|
basename10(outputPath, extname13(outputPath)) + ".srt"
|
|
275862
276089
|
);
|
|
275863
|
-
await
|
|
276090
|
+
await writeFile24(outputSrtPath2, srtContent);
|
|
275864
276091
|
return {
|
|
275865
276092
|
success: false,
|
|
275866
276093
|
error: `${renderResult.error}
|
|
@@ -275873,7 +276100,7 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
275873
276100
|
outputDir,
|
|
275874
276101
|
basename10(outputPath, extname13(outputPath)) + ".srt"
|
|
275875
276102
|
);
|
|
275876
|
-
await
|
|
276103
|
+
await writeFile24(outputSrtPath, srtContent);
|
|
275877
276104
|
return {
|
|
275878
276105
|
success: true,
|
|
275879
276106
|
outputPath,
|
|
@@ -275882,8 +276109,8 @@ SRT saved to: ${outputSrtPath2}`
|
|
|
275882
276109
|
};
|
|
275883
276110
|
} finally {
|
|
275884
276111
|
try {
|
|
275885
|
-
const { rm:
|
|
275886
|
-
await
|
|
276112
|
+
const { rm: rm10 } = await import("node:fs/promises");
|
|
276113
|
+
await rm10(tmpDir, { recursive: true, force: true });
|
|
275887
276114
|
} catch {
|
|
275888
276115
|
}
|
|
275889
276116
|
}
|
|
@@ -276044,7 +276271,7 @@ var init_fade = __esm({
|
|
|
276044
276271
|
|
|
276045
276272
|
// ../cli/src/commands/_shared/edit/translate-srt.ts
|
|
276046
276273
|
import { existsSync as existsSync64 } from "node:fs";
|
|
276047
|
-
import { readFile as
|
|
276274
|
+
import { readFile as readFile25, writeFile as writeFile25 } from "node:fs/promises";
|
|
276048
276275
|
async function executeTranslateSrt(options) {
|
|
276049
276276
|
const {
|
|
276050
276277
|
srtPath,
|
|
@@ -276058,7 +276285,7 @@ async function executeTranslateSrt(options) {
|
|
|
276058
276285
|
return { success: false, error: `SRT file not found: ${srtPath}` };
|
|
276059
276286
|
}
|
|
276060
276287
|
try {
|
|
276061
|
-
const srtContent = await
|
|
276288
|
+
const srtContent = await readFile25(srtPath, "utf-8");
|
|
276062
276289
|
const segments = parseSRT(srtContent);
|
|
276063
276290
|
if (segments.length === 0) {
|
|
276064
276291
|
return { success: false, error: "No subtitle segments found in SRT file" };
|
|
@@ -276148,7 +276375,7 @@ ${textsToTranslate}`;
|
|
|
276148
276375
|
}
|
|
276149
276376
|
}
|
|
276150
276377
|
const translatedSrt = formatSRT(translatedSegments);
|
|
276151
|
-
await
|
|
276378
|
+
await writeFile25(outputPath, translatedSrt);
|
|
276152
276379
|
return {
|
|
276153
276380
|
success: true,
|
|
276154
276381
|
outputPath,
|
|
@@ -277312,7 +277539,7 @@ var init_project_resolver = __esm({
|
|
|
277312
277539
|
|
|
277313
277540
|
// ../cli/src/commands/_shared/execute-fill-gaps.ts
|
|
277314
277541
|
import { existsSync as existsSync67 } from "node:fs";
|
|
277315
|
-
import { readFile as
|
|
277542
|
+
import { readFile as readFile26, writeFile as writeFile26, mkdir as mkdir18, rename as renameFs } from "node:fs/promises";
|
|
277316
277543
|
import { resolve as resolve46, dirname as dirname31 } from "node:path";
|
|
277317
277544
|
function detectVideoGaps(videoClips, totalDuration) {
|
|
277318
277545
|
const gaps = [];
|
|
@@ -277369,7 +277596,7 @@ function analyzeGapFillability(gaps, videoClips, sources) {
|
|
|
277369
277596
|
}
|
|
277370
277597
|
async function uploadFrameToImgbb(framePath, imgbbApiKey) {
|
|
277371
277598
|
try {
|
|
277372
|
-
const frameBuffer = await
|
|
277599
|
+
const frameBuffer = await readFile26(framePath);
|
|
277373
277600
|
const frameBase64 = frameBuffer.toString("base64");
|
|
277374
277601
|
const formData = new FormData();
|
|
277375
277602
|
formData.append("key", imgbbApiKey);
|
|
@@ -277401,7 +277628,7 @@ async function executeFillGaps(options) {
|
|
|
277401
277628
|
humanLines
|
|
277402
277629
|
};
|
|
277403
277630
|
}
|
|
277404
|
-
const content = await
|
|
277631
|
+
const content = await readFile26(filePath, "utf-8");
|
|
277405
277632
|
const data2 = JSON.parse(content);
|
|
277406
277633
|
const project = Project.fromJSON(data2);
|
|
277407
277634
|
const clips = project.getClips().sort((a4, b4) => a4.startTime - b4.startTime);
|
|
@@ -277530,7 +277757,7 @@ async function executeFillGaps(options) {
|
|
|
277530
277757
|
const projectDir = dirname31(filePath);
|
|
277531
277758
|
const footageDir = options.dir ? resolve46(process.cwd(), options.dir) : resolve46(projectDir, "footage");
|
|
277532
277759
|
if (!existsSync67(footageDir)) {
|
|
277533
|
-
await
|
|
277760
|
+
await mkdir18(footageDir, { recursive: true });
|
|
277534
277761
|
}
|
|
277535
277762
|
humanLines.push("Generating AI Videos");
|
|
277536
277763
|
const imgbbApiKey = options.imgbbApiKey || await getApiKey("IMGBB_API_KEY", "imgbb", void 0);
|
|
@@ -277624,7 +277851,7 @@ async function executeFillGaps(options) {
|
|
|
277624
277851
|
const videoPath = resolve46(footageDir, videoFileName);
|
|
277625
277852
|
onProgress("Downloading generated video...");
|
|
277626
277853
|
const videoBuffer = await downloadVideo(finalResult.videoUrl);
|
|
277627
|
-
await
|
|
277854
|
+
await writeFile26(videoPath, videoBuffer);
|
|
277628
277855
|
generatedDuration = finalResult.duration || parseInt(klingDuration);
|
|
277629
277856
|
generatedVideos.push(videoPath);
|
|
277630
277857
|
humanLines.push(` Generated: ${videoFileName} (${generatedDuration}s)`);
|
|
@@ -277694,11 +277921,11 @@ async function executeFillGaps(options) {
|
|
|
277694
277921
|
`gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-seg${segmentIndex}.mp4`
|
|
277695
277922
|
);
|
|
277696
277923
|
const segVideoBuffer = await downloadVideo(segFinalResult.videoUrl);
|
|
277697
|
-
await
|
|
277924
|
+
await writeFile26(segVideoPath, segVideoBuffer);
|
|
277698
277925
|
const concatListPath = resolve46(footageDir, `concat-${gap.start.toFixed(2)}.txt`);
|
|
277699
277926
|
const concatList = generatedVideos.map((v4) => `file '${v4}'`).join("\n") + `
|
|
277700
277927
|
file '${segVideoPath}'`;
|
|
277701
|
-
await
|
|
277928
|
+
await writeFile26(concatListPath, concatList);
|
|
277702
277929
|
const concatOutputPath = resolve46(
|
|
277703
277930
|
footageDir,
|
|
277704
277931
|
`gap-fill-${gap.start.toFixed(2)}-${gap.end.toFixed(2)}-merged.mp4`
|
|
@@ -277756,7 +277983,7 @@ file '${segVideoPath}'`;
|
|
|
277756
277983
|
let outputPath = filePath;
|
|
277757
277984
|
if (generatedCount > 0) {
|
|
277758
277985
|
outputPath = options.output ? resolve46(process.cwd(), options.output) : filePath;
|
|
277759
|
-
await
|
|
277986
|
+
await writeFile26(outputPath, JSON.stringify(project.toJSON(), null, 2));
|
|
277760
277987
|
humanLines.push(`\u2714 Filled ${generatedCount} gap(s) with AI-generated video`);
|
|
277761
277988
|
humanLines.push(`Project saved: ${outputPath}`);
|
|
277762
277989
|
} else {
|
|
@@ -277850,7 +278077,7 @@ __export(ai_motion_exports, {
|
|
|
277850
278077
|
});
|
|
277851
278078
|
import { resolve as resolve47 } from "node:path";
|
|
277852
278079
|
import { existsSync as existsSync68 } from "node:fs";
|
|
277853
|
-
import { readFile as
|
|
278080
|
+
import { readFile as readFile27, writeFile as writeFile27 } from "node:fs/promises";
|
|
277854
278081
|
async function getOptionalGoogleApiKey() {
|
|
277855
278082
|
const configKey = await getApiKeyFromConfig("google");
|
|
277856
278083
|
if (configKey) return configKey;
|
|
@@ -277897,7 +278124,7 @@ async function executeMotion(options) {
|
|
|
277897
278124
|
};
|
|
277898
278125
|
}
|
|
277899
278126
|
const imagePath = resolve47(process.cwd(), options.image);
|
|
277900
|
-
const imageBuffer = await
|
|
278127
|
+
const imageBuffer = await readFile27(imagePath);
|
|
277901
278128
|
const gemini = new GeminiProvider();
|
|
277902
278129
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
277903
278130
|
const analysisResult = await gemini.analyzeImage(
|
|
@@ -277934,7 +278161,7 @@ Use this image analysis to inform the color palette, typography placement, and o
|
|
|
277934
278161
|
}
|
|
277935
278162
|
if (geminiApiKey) {
|
|
277936
278163
|
const videoPath = resolve47(process.cwd(), options.video);
|
|
277937
|
-
const videoBuffer = await
|
|
278164
|
+
const videoBuffer = await readFile27(videoPath);
|
|
277938
278165
|
const gemini = new GeminiProvider();
|
|
277939
278166
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
277940
278167
|
const analysisPrompt = options.understandingPrompt || `Analyze this video for motion graphics composition. Return concise production guidance:
|
|
@@ -277968,7 +278195,7 @@ Use this video understanding to place motion graphics in safe zones, match the c
|
|
|
277968
278195
|
if (!existsSync68(tsxPath)) {
|
|
277969
278196
|
return { success: false, error: `TSX file not found: ${tsxPath}` };
|
|
277970
278197
|
}
|
|
277971
|
-
const existingCode = await
|
|
278198
|
+
const existingCode = await readFile27(tsxPath, "utf-8");
|
|
277972
278199
|
if (useGemini) {
|
|
277973
278200
|
const gemini = new GeminiProvider();
|
|
277974
278201
|
await gemini.initialize({ apiKey });
|
|
@@ -278020,7 +278247,7 @@ Use this video understanding to place motion graphics in safe zones, match the c
|
|
|
278020
278247
|
const defaultOutput = options.video || options.image ? "motion-output.mp4" : options.render ? "motion.webm" : "motion.tsx";
|
|
278021
278248
|
const outputPath = resolve47(process.cwd(), options.output || defaultOutput);
|
|
278022
278249
|
const codePath = outputPath.replace(/\.\w+$/, ".tsx");
|
|
278023
|
-
await
|
|
278250
|
+
await writeFile27(codePath, component.code, "utf-8");
|
|
278024
278251
|
const shouldRender = options.render || !!options.video || !!options.image;
|
|
278025
278252
|
if (!shouldRender) {
|
|
278026
278253
|
return { success: true, codePath, componentName: component.name };
|
|
@@ -278499,7 +278726,7 @@ __export(project_builder_exports, {
|
|
|
278499
278726
|
buildTempProject: () => buildTempProject,
|
|
278500
278727
|
resolveSourceUrl: () => resolveSourceUrl
|
|
278501
278728
|
});
|
|
278502
|
-
import { mkdtemp as mkdtemp5, mkdir as
|
|
278729
|
+
import { mkdtemp as mkdtemp5, mkdir as mkdir19, copyFile as copyFile6, writeFile as writeFile28, rm as rm8, readdir as readdir7 } from "node:fs/promises";
|
|
278503
278730
|
import { existsSync as existsSync69 } from "node:fs";
|
|
278504
278731
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
278505
278732
|
import { createRequire as createRequire4 } from "node:module";
|
|
@@ -278507,7 +278734,7 @@ import * as path15 from "node:path";
|
|
|
278507
278734
|
async function buildTempProject(state, projectFileDir) {
|
|
278508
278735
|
const dir = await mkdtemp5(path15.join(tmpdir10(), "vibeframe-hf-"));
|
|
278509
278736
|
const assetsDir = path15.join(dir, "assets");
|
|
278510
|
-
await
|
|
278737
|
+
await mkdir19(assetsDir, { recursive: true });
|
|
278511
278738
|
const copied = /* @__PURE__ */ new Map();
|
|
278512
278739
|
for (const source3 of state.sources) {
|
|
278513
278740
|
if (copied.has(source3.id)) continue;
|
|
@@ -278523,10 +278750,10 @@ async function buildTempProject(state, projectFileDir) {
|
|
|
278523
278750
|
await copyLottieRuntime(dir);
|
|
278524
278751
|
}
|
|
278525
278752
|
const html = generateCompositionHtml(state);
|
|
278526
|
-
await
|
|
278753
|
+
await writeFile28(path15.join(dir, "index.html"), html, "utf-8");
|
|
278527
278754
|
return {
|
|
278528
278755
|
dir,
|
|
278529
|
-
cleanup: () =>
|
|
278756
|
+
cleanup: () => rm8(dir, { recursive: true, force: true })
|
|
278530
278757
|
};
|
|
278531
278758
|
}
|
|
278532
278759
|
async function copyLottieRuntime(tempDir) {
|
|
@@ -278537,8 +278764,8 @@ async function copyLottieRuntime(tempDir) {
|
|
|
278537
278764
|
const wasmSrc = path15.join(path15.dirname(webEntry), "dotlottie-player.wasm");
|
|
278538
278765
|
const vendorDir = path15.join(tempDir, "vendor");
|
|
278539
278766
|
const wcDest = path15.join(vendorDir, "dotlottie-wc");
|
|
278540
|
-
await
|
|
278541
|
-
for (const file of await
|
|
278767
|
+
await mkdir19(wcDest, { recursive: true });
|
|
278768
|
+
for (const file of await readdir7(wcDistDir)) {
|
|
278542
278769
|
if (file.endsWith(".map") || file.endsWith(".d.ts")) continue;
|
|
278543
278770
|
await copyFile6(path15.join(wcDistDir, file), path15.join(wcDest, file));
|
|
278544
278771
|
}
|
|
@@ -278645,7 +278872,7 @@ __export(motion_overlay_exports, {
|
|
|
278645
278872
|
executeMotionOverlay: () => executeMotionOverlay,
|
|
278646
278873
|
registerMotionOverlayCommand: () => registerMotionOverlayCommand
|
|
278647
278874
|
});
|
|
278648
|
-
import { mkdir as
|
|
278875
|
+
import { mkdir as mkdir20 } from "node:fs/promises";
|
|
278649
278876
|
import { existsSync as existsSync70 } from "node:fs";
|
|
278650
278877
|
import { basename as basename13, dirname as dirname33, extname as extname15, resolve as resolve49 } from "node:path";
|
|
278651
278878
|
function normalizeUnderstand2(value) {
|
|
@@ -278793,7 +279020,7 @@ async function executeMotionOverlay(options) {
|
|
|
278793
279020
|
const scale = Math.max(0.01, Math.min(2, numberOption(options.scale, position === "full" ? 1 : 0.25)));
|
|
278794
279021
|
const opacity = Math.max(0, Math.min(1, numberOption(options.opacity, 1)));
|
|
278795
279022
|
const loop = options.loop ?? true;
|
|
278796
|
-
await
|
|
279023
|
+
await mkdir20(dirname33(outputPath), { recursive: true });
|
|
278797
279024
|
const backend = createHyperframesBackend();
|
|
278798
279025
|
const result2 = await backend.render({
|
|
278799
279026
|
projectState: buildLottieTimelineState({
|
|
@@ -278819,7 +279046,7 @@ async function executeMotionOverlay(options) {
|
|
|
278819
279046
|
return { success: true, outputPath, provider: "lottie" };
|
|
278820
279047
|
}
|
|
278821
279048
|
const duration = options.duration ?? await ffprobeDuration(absVideo).catch(() => void 0);
|
|
278822
|
-
await
|
|
279049
|
+
await mkdir20(dirname33(outputPath), { recursive: true });
|
|
278823
279050
|
const result = await executeMotion({
|
|
278824
279051
|
description: options.description.trim(),
|
|
278825
279052
|
video: absVideo,
|
|
@@ -278948,7 +279175,7 @@ __export(edit_cmd_exports, {
|
|
|
278948
279175
|
executeUpscale: () => executeUpscale
|
|
278949
279176
|
});
|
|
278950
279177
|
import { resolve as resolve50, dirname as dirname34 } from "node:path";
|
|
278951
|
-
import { readFile as
|
|
279178
|
+
import { readFile as readFile28, writeFile as writeFile29, mkdir as mkdir21 } from "node:fs/promises";
|
|
278952
279179
|
async function executeGrade(options) {
|
|
278953
279180
|
const { videoPath, style, preset: preset3, output: output3, analyzeOnly, apiKey } = options;
|
|
278954
279181
|
try {
|
|
@@ -278989,7 +279216,7 @@ async function executeSpeedRamp(options) {
|
|
|
278989
279216
|
await execSafe("ffmpeg", ["-i", absPath, "-vn", "-acodec", "libmp3lame", "-q:a", "2", tempAudio, "-y"]);
|
|
278990
279217
|
const whisper = new WhisperProvider();
|
|
278991
279218
|
await whisper.initialize({ apiKey: openaiKey });
|
|
278992
|
-
const audioBuffer = await
|
|
279219
|
+
const audioBuffer = await readFile28(tempAudio);
|
|
278993
279220
|
const transcript = await whisper.transcribe(new Blob([audioBuffer]), language);
|
|
278994
279221
|
try {
|
|
278995
279222
|
const { unlink: unlink6 } = await import("node:fs/promises");
|
|
@@ -279383,7 +279610,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
279383
279610
|
spinner2.text = "Transcribing audio...";
|
|
279384
279611
|
const whisper = new WhisperProvider();
|
|
279385
279612
|
await whisper.initialize({ apiKey: openaiApiKey });
|
|
279386
|
-
const audioBuffer = await
|
|
279613
|
+
const audioBuffer = await readFile28(tempAudio);
|
|
279387
279614
|
const audioBlob = new Blob([audioBuffer]);
|
|
279388
279615
|
const transcript = await whisper.transcribe(audioBlob, options.language);
|
|
279389
279616
|
if (!transcript.segments || transcript.segments.length === 0) {
|
|
@@ -279516,7 +279743,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
279516
279743
|
for (let i3 = 1; i3 <= numKeyframes && i3 <= 30; i3++) {
|
|
279517
279744
|
const framePath = `${tempDir}/frame-${i3.toString().padStart(4, "0")}.jpg`;
|
|
279518
279745
|
try {
|
|
279519
|
-
const frameBuffer = await
|
|
279746
|
+
const frameBuffer = await readFile28(framePath);
|
|
279520
279747
|
const frameBase64 = frameBuffer.toString("base64");
|
|
279521
279748
|
const result = await claude.analyzeFrameForReframe(frameBase64, options.aspect, {
|
|
279522
279749
|
focusMode: options.focus,
|
|
@@ -279576,7 +279803,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
279576
279803
|
console.log();
|
|
279577
279804
|
if (options.keyframes) {
|
|
279578
279805
|
const keyframesPath = resolve50(process.cwd(), options.keyframes);
|
|
279579
|
-
await
|
|
279806
|
+
await writeFile29(keyframesPath, JSON.stringify(cropKeyframes, null, 2));
|
|
279580
279807
|
console.log(source_default.green(`Keyframes saved to: ${keyframesPath}`));
|
|
279581
279808
|
}
|
|
279582
279809
|
if (options.analyzeOnly) {
|
|
@@ -279645,7 +279872,7 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
279645
279872
|
const imageBuffers = [];
|
|
279646
279873
|
for (const imagePath of imagePaths) {
|
|
279647
279874
|
const absPath = resolve50(process.cwd(), imagePath);
|
|
279648
|
-
const buffer = await
|
|
279875
|
+
const buffer = await readFile28(absPath);
|
|
279649
279876
|
imageBuffers.push(buffer);
|
|
279650
279877
|
}
|
|
279651
279878
|
let result;
|
|
@@ -279695,14 +279922,14 @@ Run 'vibe schema edit.<command>' for structured parameter info.
|
|
|
279695
279922
|
const img = result.images[0];
|
|
279696
279923
|
const outputPath = resolve50(process.cwd(), options.output);
|
|
279697
279924
|
const saveImage = async () => {
|
|
279698
|
-
await
|
|
279925
|
+
await mkdir21(dirname34(outputPath), { recursive: true });
|
|
279699
279926
|
if (img.base64) {
|
|
279700
279927
|
const buffer = Buffer.from(img.base64, "base64");
|
|
279701
|
-
await
|
|
279928
|
+
await writeFile29(outputPath, buffer);
|
|
279702
279929
|
} else if (img.url) {
|
|
279703
279930
|
const resp = await fetch(img.url);
|
|
279704
279931
|
const arrayBuf = await resp.arrayBuffer();
|
|
279705
|
-
await
|
|
279932
|
+
await writeFile29(outputPath, Buffer.from(arrayBuf));
|
|
279706
279933
|
}
|
|
279707
279934
|
};
|
|
279708
279935
|
const resultModel = result.model;
|
|
@@ -279922,8 +280149,8 @@ __export(ai_image_exports, {
|
|
|
279922
280149
|
executeThumbnailBestFrame: () => executeThumbnailBestFrame
|
|
279923
280150
|
});
|
|
279924
280151
|
import { resolve as resolve53, dirname as dirname36 } from "node:path";
|
|
279925
|
-
import { readFile as
|
|
279926
|
-
import { existsSync as
|
|
280152
|
+
import { readFile as readFile29, writeFile as writeFile31, mkdir as mkdir24 } from "node:fs/promises";
|
|
280153
|
+
import { existsSync as existsSync73 } from "node:fs";
|
|
279927
280154
|
async function executeImageGenerate(options) {
|
|
279928
280155
|
const {
|
|
279929
280156
|
prompt: prompt3,
|
|
@@ -279965,8 +280192,8 @@ async function executeImageGenerate(options) {
|
|
|
279965
280192
|
return { success: false, error: "No image data available" };
|
|
279966
280193
|
}
|
|
279967
280194
|
outputPath = resolve53(process.cwd(), output3);
|
|
279968
|
-
await
|
|
279969
|
-
await
|
|
280195
|
+
await mkdir24(dirname36(outputPath), { recursive: true });
|
|
280196
|
+
await writeFile31(outputPath, buffer);
|
|
279970
280197
|
}
|
|
279971
280198
|
return {
|
|
279972
280199
|
success: true,
|
|
@@ -280000,8 +280227,8 @@ async function executeImageGenerate(options) {
|
|
|
280000
280227
|
const img = result.images[0];
|
|
280001
280228
|
if (img.base64) {
|
|
280002
280229
|
outputPath = resolve53(process.cwd(), output3);
|
|
280003
|
-
await
|
|
280004
|
-
await
|
|
280230
|
+
await mkdir24(dirname36(outputPath), { recursive: true });
|
|
280231
|
+
await writeFile31(outputPath, Buffer.from(img.base64, "base64"));
|
|
280005
280232
|
}
|
|
280006
280233
|
}
|
|
280007
280234
|
return {
|
|
@@ -280036,8 +280263,8 @@ async function executeImageGenerate(options) {
|
|
|
280036
280263
|
return { success: false, error: "No image data available" };
|
|
280037
280264
|
}
|
|
280038
280265
|
outputPath = resolve53(process.cwd(), output3);
|
|
280039
|
-
await
|
|
280040
|
-
await
|
|
280266
|
+
await mkdir24(dirname36(outputPath), { recursive: true });
|
|
280267
|
+
await writeFile31(outputPath, buffer);
|
|
280041
280268
|
}
|
|
280042
280269
|
return {
|
|
280043
280270
|
success: true,
|
|
@@ -280067,10 +280294,10 @@ async function executeGeminiEdit(options) {
|
|
|
280067
280294
|
const imageBuffers = [];
|
|
280068
280295
|
for (const imagePath of imagePaths) {
|
|
280069
280296
|
const absPath = resolve53(process.cwd(), imagePath);
|
|
280070
|
-
if (!
|
|
280297
|
+
if (!existsSync73(absPath)) {
|
|
280071
280298
|
return { success: false, error: `Image not found: ${absPath}` };
|
|
280072
280299
|
}
|
|
280073
|
-
const buffer = await
|
|
280300
|
+
const buffer = await readFile29(absPath);
|
|
280074
280301
|
imageBuffers.push(buffer);
|
|
280075
280302
|
}
|
|
280076
280303
|
const gemini = new GeminiProvider();
|
|
@@ -280095,8 +280322,8 @@ async function executeGeminiEdit(options) {
|
|
|
280095
280322
|
let outputPath;
|
|
280096
280323
|
if (img.base64) {
|
|
280097
280324
|
outputPath = resolve53(process.cwd(), output3);
|
|
280098
|
-
await
|
|
280099
|
-
await
|
|
280325
|
+
await mkdir24(dirname36(outputPath), { recursive: true });
|
|
280326
|
+
await writeFile31(outputPath, Buffer.from(img.base64, "base64"));
|
|
280100
280327
|
}
|
|
280101
280328
|
return {
|
|
280102
280329
|
success: true,
|
|
@@ -280115,7 +280342,7 @@ async function executeThumbnailBestFrame(options) {
|
|
|
280115
280342
|
model = "flash",
|
|
280116
280343
|
apiKey
|
|
280117
280344
|
} = options;
|
|
280118
|
-
if (!
|
|
280345
|
+
if (!existsSync73(videoPath)) {
|
|
280119
280346
|
return { success: false, error: `Video not found: ${videoPath}` };
|
|
280120
280347
|
}
|
|
280121
280348
|
if (!commandExists("ffmpeg")) {
|
|
@@ -280128,7 +280355,7 @@ async function executeThumbnailBestFrame(options) {
|
|
|
280128
280355
|
try {
|
|
280129
280356
|
const gemini = new GeminiProvider();
|
|
280130
280357
|
await gemini.initialize({ apiKey: googleKey });
|
|
280131
|
-
const videoData = await
|
|
280358
|
+
const videoData = await readFile29(videoPath);
|
|
280132
280359
|
const analysisPrompt = prompt3 || 'Analyze this video and find the single best frame for a thumbnail. Look for frames that are visually striking, well-composed, emotionally engaging, and representative of the video content. Avoid blurry frames, transitions, or dark scenes. Return ONLY a JSON object: {"timestamp": <seconds as number>, "reason": "<brief explanation>"}';
|
|
280133
280360
|
const modelId = resolveGeminiTextModel(model);
|
|
280134
280361
|
const result = await gemini.analyzeVideo(videoData, analysisPrompt, {
|
|
@@ -280149,7 +280376,7 @@ async function executeThumbnailBestFrame(options) {
|
|
|
280149
280376
|
reason = reasonMatch[1];
|
|
280150
280377
|
}
|
|
280151
280378
|
await execSafe("ffmpeg", ["-ss", String(timestamp), "-i", videoPath, "-frames:v", "1", "-q:v", "2", outputPath, "-y"], { timeout: 6e4, maxBuffer: 50 * 1024 * 1024 });
|
|
280152
|
-
if (!
|
|
280379
|
+
if (!existsSync73(outputPath)) {
|
|
280153
280380
|
return { success: false, error: "FFmpeg failed to extract frame" };
|
|
280154
280381
|
}
|
|
280155
280382
|
return {
|
|
@@ -280180,9 +280407,9 @@ __export(ai_analyze_exports, {
|
|
|
280180
280407
|
executeGeminiVideo: () => executeGeminiVideo,
|
|
280181
280408
|
registerAnalyzeCommands: () => registerAnalyzeCommands
|
|
280182
280409
|
});
|
|
280183
|
-
import { readFile as
|
|
280410
|
+
import { readFile as readFile30 } from "node:fs/promises";
|
|
280184
280411
|
import { extname as extname16, resolve as resolve54 } from "node:path";
|
|
280185
|
-
import { existsSync as
|
|
280412
|
+
import { existsSync as existsSync74 } from "node:fs";
|
|
280186
280413
|
async function executeGeminiVideo(options) {
|
|
280187
280414
|
try {
|
|
280188
280415
|
const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
|
|
@@ -280196,10 +280423,10 @@ async function executeGeminiVideo(options) {
|
|
|
280196
280423
|
videoData = options.source;
|
|
280197
280424
|
} else {
|
|
280198
280425
|
const absPath = resolve54(process.cwd(), options.source);
|
|
280199
|
-
if (!
|
|
280426
|
+
if (!existsSync74(absPath)) {
|
|
280200
280427
|
return { success: false, error: `File not found: ${absPath}` };
|
|
280201
280428
|
}
|
|
280202
|
-
videoData = await
|
|
280429
|
+
videoData = await readFile30(absPath);
|
|
280203
280430
|
}
|
|
280204
280431
|
const gemini = new GeminiProvider();
|
|
280205
280432
|
await gemini.initialize({ apiKey });
|
|
@@ -280264,10 +280491,10 @@ async function executeAnalyze(options) {
|
|
|
280264
280491
|
imageBuffer = Buffer.from(await response.arrayBuffer());
|
|
280265
280492
|
} else {
|
|
280266
280493
|
const absPath = resolve54(process.cwd(), source3);
|
|
280267
|
-
if (!
|
|
280494
|
+
if (!existsSync74(absPath)) {
|
|
280268
280495
|
return { success: false, error: `File not found: ${absPath}` };
|
|
280269
280496
|
}
|
|
280270
|
-
imageBuffer = await
|
|
280497
|
+
imageBuffer = await readFile30(absPath);
|
|
280271
280498
|
}
|
|
280272
280499
|
const result2 = await gemini.analyzeImage(imageBuffer, options.prompt, {
|
|
280273
280500
|
model: modelId,
|
|
@@ -280299,10 +280526,10 @@ async function executeAnalyze(options) {
|
|
|
280299
280526
|
videoData = Buffer.from(await response.arrayBuffer());
|
|
280300
280527
|
} else {
|
|
280301
280528
|
const absPath = resolve54(process.cwd(), source3);
|
|
280302
|
-
if (!
|
|
280529
|
+
if (!existsSync74(absPath)) {
|
|
280303
280530
|
return { success: false, error: `File not found: ${absPath}` };
|
|
280304
280531
|
}
|
|
280305
|
-
videoData = await
|
|
280532
|
+
videoData = await readFile30(absPath);
|
|
280306
280533
|
}
|
|
280307
280534
|
const result = await gemini.analyzeVideo(videoData, options.prompt, {
|
|
280308
280535
|
model: modelId,
|
|
@@ -280435,9 +280662,9 @@ var ai_review_exports = {};
|
|
|
280435
280662
|
__export(ai_review_exports, {
|
|
280436
280663
|
executeReview: () => executeReview
|
|
280437
280664
|
});
|
|
280438
|
-
import { readFile as
|
|
280665
|
+
import { readFile as readFile34, rename as rename6 } from "node:fs/promises";
|
|
280439
280666
|
import { resolve as resolve57 } from "node:path";
|
|
280440
|
-
import { existsSync as
|
|
280667
|
+
import { existsSync as existsSync76 } from "node:fs";
|
|
280441
280668
|
function parseReviewFeedback(response) {
|
|
280442
280669
|
let cleaned = response.trim();
|
|
280443
280670
|
if (cleaned.startsWith("```json")) {
|
|
@@ -280469,7 +280696,7 @@ async function executeReview(options) {
|
|
|
280469
280696
|
model = "flash"
|
|
280470
280697
|
} = options;
|
|
280471
280698
|
const absVideoPath = resolve57(process.cwd(), videoPath);
|
|
280472
|
-
if (!
|
|
280699
|
+
if (!existsSync76(absVideoPath)) {
|
|
280473
280700
|
return { success: false, error: `Video not found: ${absVideoPath}` };
|
|
280474
280701
|
}
|
|
280475
280702
|
const apiKey = process.env.GOOGLE_API_KEY || await getApiKey("GOOGLE_API_KEY", "Google");
|
|
@@ -280482,8 +280709,8 @@ async function executeReview(options) {
|
|
|
280482
280709
|
let storyboardContext = "";
|
|
280483
280710
|
if (storyboardPath) {
|
|
280484
280711
|
const absStoryboardPath = resolve57(process.cwd(), storyboardPath);
|
|
280485
|
-
if (
|
|
280486
|
-
const content = await
|
|
280712
|
+
if (existsSync76(absStoryboardPath)) {
|
|
280713
|
+
const content = await readFile34(absStoryboardPath, "utf-8");
|
|
280487
280714
|
storyboardContext = `
|
|
280488
280715
|
|
|
280489
280716
|
Original storyboard for reference:
|
|
@@ -280525,7 +280752,7 @@ ${projectContext}` : "";
|
|
|
280525
280752
|
Score each category 1-10. Prefer beatIssues when you can map a problem to a storyboard beat or timestamp. Use the exact beatId values from the storyboard or beat timing summary, and include timeRange in seconds for every localized finding. In particular, flag narration/visual mismatches, overly static holds, and audio-visual sync problems as beatIssues. Use category issue arrays only for problems that cannot be localized to a beat. For fixable issues, provide an FFmpeg filter in autoFixable. Be specific and practical.${storyboardContext}${extraProjectContext}`;
|
|
280526
280753
|
const gemini = new GeminiProvider();
|
|
280527
280754
|
await gemini.initialize({ apiKey });
|
|
280528
|
-
const videoData = await
|
|
280755
|
+
const videoData = await readFile34(absVideoPath);
|
|
280529
280756
|
const analysisResult = await gemini.analyzeVideo(videoData, reviewPrompt, {
|
|
280530
280757
|
model: modelId
|
|
280531
280758
|
});
|
|
@@ -280572,7 +280799,7 @@ Score each category 1-10. Prefer beatIssues when you can map a problem to a stor
|
|
|
280572
280799
|
if (currentInput !== absVideoPath) {
|
|
280573
280800
|
const finalOutput = outputBase;
|
|
280574
280801
|
try {
|
|
280575
|
-
await
|
|
280802
|
+
await rename6(currentInput, finalOutput);
|
|
280576
280803
|
result.outputPath = finalOutput;
|
|
280577
280804
|
} catch {
|
|
280578
280805
|
result.outputPath = currentInput;
|
|
@@ -280580,7 +280807,7 @@ Score each category 1-10. Prefer beatIssues when you can map a problem to a stor
|
|
|
280580
280807
|
}
|
|
280581
280808
|
}
|
|
280582
280809
|
if (verify && result.outputPath) {
|
|
280583
|
-
const verifyVideoData = await
|
|
280810
|
+
const verifyVideoData = await readFile34(result.outputPath);
|
|
280584
280811
|
const verifyResult = await gemini.analyzeVideo(
|
|
280585
280812
|
verifyVideoData,
|
|
280586
280813
|
'Rate this video overall quality on a scale of 1-10. Return ONLY a JSON object: {"score": <number>}',
|
|
@@ -280611,7 +280838,7 @@ var init_ai_review = __esm({
|
|
|
280611
280838
|
|
|
280612
280839
|
// ../cli/src/commands/generate/sound-effect.ts
|
|
280613
280840
|
import { resolve as resolve60 } from "node:path";
|
|
280614
|
-
import { writeFile as
|
|
280841
|
+
import { writeFile as writeFile34 } from "node:fs/promises";
|
|
280615
280842
|
async function executeSoundEffect(options) {
|
|
280616
280843
|
try {
|
|
280617
280844
|
const apiKey = await getConfiguredApiKey("ELEVENLABS_API_KEY");
|
|
@@ -280636,7 +280863,7 @@ async function executeSoundEffect(options) {
|
|
|
280636
280863
|
process.cwd(),
|
|
280637
280864
|
options.output || "sound-effect.mp3"
|
|
280638
280865
|
);
|
|
280639
|
-
await
|
|
280866
|
+
await writeFile34(outputPath, result.audioBuffer);
|
|
280640
280867
|
return { success: true, outputPath };
|
|
280641
280868
|
} catch (error) {
|
|
280642
280869
|
return {
|
|
@@ -280688,7 +280915,7 @@ function registerSoundEffectCommand(parent) {
|
|
|
280688
280915
|
);
|
|
280689
280916
|
}
|
|
280690
280917
|
const outputPath = resolve60(process.cwd(), options.output);
|
|
280691
|
-
await
|
|
280918
|
+
await writeFile34(outputPath, result.audioBuffer);
|
|
280692
280919
|
spinner2.succeed(source_default.green("Sound effect generated"));
|
|
280693
280920
|
if (isJsonMode()) {
|
|
280694
280921
|
outputSuccess({
|
|
@@ -280855,7 +281082,7 @@ var init_tty = __esm({
|
|
|
280855
281082
|
|
|
280856
281083
|
// ../cli/src/commands/generate/speech.ts
|
|
280857
281084
|
import { resolve as resolve61 } from "node:path";
|
|
280858
|
-
import { writeFile as
|
|
281085
|
+
import { writeFile as writeFile35 } from "node:fs/promises";
|
|
280859
281086
|
async function executeSpeech(options) {
|
|
280860
281087
|
try {
|
|
280861
281088
|
const apiKey = await getConfiguredApiKey("ELEVENLABS_API_KEY");
|
|
@@ -280873,7 +281100,7 @@ async function executeSpeech(options) {
|
|
|
280873
281100
|
return { success: false, error: result.error || "TTS generation failed" };
|
|
280874
281101
|
}
|
|
280875
281102
|
const outputPath = resolve61(process.cwd(), options.output || "output.mp3");
|
|
280876
|
-
await
|
|
281103
|
+
await writeFile35(outputPath, result.audioBuffer);
|
|
280877
281104
|
return { success: true, outputPath, characterCount: result.characterCount };
|
|
280878
281105
|
} catch (error) {
|
|
280879
281106
|
return {
|
|
@@ -280947,8 +281174,8 @@ var init_speech = __esm({
|
|
|
280947
281174
|
|
|
280948
281175
|
// ../cli/src/commands/generate/thumbnail.ts
|
|
280949
281176
|
import { resolve as resolve63, dirname as dirname37, basename as basename17, extname as extname17 } from "node:path";
|
|
280950
|
-
import { existsSync as
|
|
280951
|
-
import { writeFile as
|
|
281177
|
+
import { existsSync as existsSync78 } from "node:fs";
|
|
281178
|
+
import { writeFile as writeFile36, mkdir as mkdir25 } from "node:fs/promises";
|
|
280952
281179
|
function registerThumbnailCommand(parent) {
|
|
280953
281180
|
parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").action(async (description, options) => {
|
|
280954
281181
|
const startedAt = Date.now();
|
|
@@ -280959,7 +281186,7 @@ function registerThumbnailCommand(parent) {
|
|
|
280959
281186
|
}
|
|
280960
281187
|
if (options.bestFrame) {
|
|
280961
281188
|
const absVideoPath = resolve63(process.cwd(), options.bestFrame);
|
|
280962
|
-
if (!
|
|
281189
|
+
if (!existsSync78(absVideoPath)) {
|
|
280963
281190
|
exitWithError(notFoundError(absVideoPath));
|
|
280964
281191
|
}
|
|
280965
281192
|
if (!commandExists("ffmpeg")) {
|
|
@@ -281039,8 +281266,8 @@ function registerThumbnailCommand(parent) {
|
|
|
281039
281266
|
throw new Error("No image data available");
|
|
281040
281267
|
}
|
|
281041
281268
|
outputPath = resolve63(process.cwd(), options.output);
|
|
281042
|
-
await
|
|
281043
|
-
await
|
|
281269
|
+
await mkdir25(dirname37(outputPath), { recursive: true });
|
|
281270
|
+
await writeFile36(outputPath, buffer);
|
|
281044
281271
|
}
|
|
281045
281272
|
outputSuccess({
|
|
281046
281273
|
command: "generate thumbnail",
|
|
@@ -281070,8 +281297,8 @@ function registerThumbnailCommand(parent) {
|
|
|
281070
281297
|
throw new Error("No image data available");
|
|
281071
281298
|
}
|
|
281072
281299
|
const outputPath = resolve63(process.cwd(), options.output);
|
|
281073
|
-
await
|
|
281074
|
-
await
|
|
281300
|
+
await mkdir25(dirname37(outputPath), { recursive: true });
|
|
281301
|
+
await writeFile36(outputPath, buffer);
|
|
281075
281302
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
281076
281303
|
} catch {
|
|
281077
281304
|
saveSpinner.fail(source_default.red("Failed to save thumbnail"));
|
|
@@ -281099,7 +281326,7 @@ var init_thumbnail = __esm({
|
|
|
281099
281326
|
|
|
281100
281327
|
// ../cli/src/commands/generate/video-extend.ts
|
|
281101
281328
|
import { resolve as resolve64 } from "node:path";
|
|
281102
|
-
import { writeFile as
|
|
281329
|
+
import { writeFile as writeFile37 } from "node:fs/promises";
|
|
281103
281330
|
function registerVideoExtendCommand(parent) {
|
|
281104
281331
|
parent.command("video-extend", { hidden: true }).description("Extend video duration (Kling by video ID, Veo by operation name)").argument("<id>", "Kling video ID or Veo operation name").option("-p, --provider <provider>", "Provider: kling, veo", "kling").option("-k, --api-key <key>", "API key (KLING_API_KEY or GOOGLE_API_KEY)").option("-o, --output <path>", "Output file path").option("--prompt <text>", "Continuation prompt").option("-d, --duration <sec>", "Duration: 5 or 10 (Kling), 4/6/8 (Veo)", "5").option("--negative <prompt>", "Negative prompt (what to avoid, Kling only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast", "3.1").option("--no-wait", "Start extension and return task ID without waiting").option("--dry-run", "Preview parameters without executing").action(async (id, options) => {
|
|
281105
281332
|
const startedAt = Date.now();
|
|
@@ -281176,7 +281403,7 @@ function registerVideoExtendCommand(parent) {
|
|
|
281176
281403
|
if (options.output && finalResult.videoUrl) {
|
|
281177
281404
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
281178
281405
|
outputPath = resolve64(process.cwd(), options.output);
|
|
281179
|
-
await
|
|
281406
|
+
await writeFile37(outputPath, buffer);
|
|
281180
281407
|
}
|
|
281181
281408
|
outputSuccess({
|
|
281182
281409
|
command: "generate video-extend",
|
|
@@ -281204,7 +281431,7 @@ function registerVideoExtendCommand(parent) {
|
|
|
281204
281431
|
try {
|
|
281205
281432
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
281206
281433
|
const outputPath = resolve64(process.cwd(), options.output);
|
|
281207
|
-
await
|
|
281434
|
+
await writeFile37(outputPath, buffer);
|
|
281208
281435
|
downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
281209
281436
|
} catch (err) {
|
|
281210
281437
|
downloadSpinner.fail(
|
|
@@ -281265,7 +281492,7 @@ function registerVideoExtendCommand(parent) {
|
|
|
281265
281492
|
if (options.output && finalResult.videoUrl) {
|
|
281266
281493
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
281267
281494
|
outputPath = resolve64(process.cwd(), options.output);
|
|
281268
|
-
await
|
|
281495
|
+
await writeFile37(outputPath, buffer);
|
|
281269
281496
|
}
|
|
281270
281497
|
outputSuccess({
|
|
281271
281498
|
command: "generate video-extend",
|
|
@@ -281290,7 +281517,7 @@ function registerVideoExtendCommand(parent) {
|
|
|
281290
281517
|
try {
|
|
281291
281518
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
281292
281519
|
const outputPath = resolve64(process.cwd(), options.output);
|
|
281293
|
-
await
|
|
281520
|
+
await writeFile37(outputPath, buffer);
|
|
281294
281521
|
downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
281295
281522
|
} catch (err) {
|
|
281296
281523
|
downloadSpinner.fail(
|
|
@@ -281414,7 +281641,7 @@ var init_openai_image2 = __esm({
|
|
|
281414
281641
|
// ../cli/src/commands/generate/image.ts
|
|
281415
281642
|
import { resolve as resolve65, dirname as dirname38 } from "node:path";
|
|
281416
281643
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
281417
|
-
import { writeFile as
|
|
281644
|
+
import { writeFile as writeFile38, mkdir as mkdir26 } from "node:fs/promises";
|
|
281418
281645
|
function registerImageCommand(parent) {
|
|
281419
281646
|
parent.command("image").alias("img").description("Generate image using AI (Gemini, OpenAI gpt-image, Grok, or Runway)").argument("[prompt]", "Image description prompt (interactive if omitted)").option(
|
|
281420
281647
|
"-p, --provider <provider>",
|
|
@@ -281551,8 +281778,8 @@ Examples:
|
|
|
281551
281778
|
} else {
|
|
281552
281779
|
throw new Error("No image data available");
|
|
281553
281780
|
}
|
|
281554
|
-
await
|
|
281555
|
-
await
|
|
281781
|
+
await mkdir26(dirname38(outputPath), { recursive: true });
|
|
281782
|
+
await writeFile38(outputPath, buffer);
|
|
281556
281783
|
}
|
|
281557
281784
|
outputSuccess({
|
|
281558
281785
|
command: "generate image",
|
|
@@ -281598,8 +281825,8 @@ Examples:
|
|
|
281598
281825
|
throw new Error("No image data available");
|
|
281599
281826
|
}
|
|
281600
281827
|
const outputPath = resolve65(process.cwd(), options.output);
|
|
281601
|
-
await
|
|
281602
|
-
await
|
|
281828
|
+
await mkdir26(dirname38(outputPath), { recursive: true });
|
|
281829
|
+
await writeFile38(outputPath, buffer);
|
|
281603
281830
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
281604
281831
|
} catch (err) {
|
|
281605
281832
|
saveSpinner.fail(
|
|
@@ -281673,8 +281900,8 @@ Examples:
|
|
|
281673
281900
|
if (outputPath && result.images.length > 0) {
|
|
281674
281901
|
const img = result.images[0];
|
|
281675
281902
|
const buffer = Buffer.from(img.base64, "base64");
|
|
281676
|
-
await
|
|
281677
|
-
await
|
|
281903
|
+
await mkdir26(dirname38(outputPath), { recursive: true });
|
|
281904
|
+
await writeFile38(outputPath, buffer);
|
|
281678
281905
|
}
|
|
281679
281906
|
outputSuccess({
|
|
281680
281907
|
command: "generate image",
|
|
@@ -281706,8 +281933,8 @@ Examples:
|
|
|
281706
281933
|
const img = result.images[0];
|
|
281707
281934
|
const buffer = Buffer.from(img.base64, "base64");
|
|
281708
281935
|
const outputPath = resolve65(process.cwd(), options.output);
|
|
281709
|
-
await
|
|
281710
|
-
await
|
|
281936
|
+
await mkdir26(dirname38(outputPath), { recursive: true });
|
|
281937
|
+
await writeFile38(outputPath, buffer);
|
|
281711
281938
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
281712
281939
|
} catch (err) {
|
|
281713
281940
|
saveSpinner.fail(
|
|
@@ -281766,8 +281993,8 @@ Examples:
|
|
|
281766
281993
|
} else {
|
|
281767
281994
|
throw new Error("No image data available");
|
|
281768
281995
|
}
|
|
281769
|
-
await
|
|
281770
|
-
await
|
|
281996
|
+
await mkdir26(dirname38(outputPath), { recursive: true });
|
|
281997
|
+
await writeFile38(outputPath, buffer);
|
|
281771
281998
|
}
|
|
281772
281999
|
outputSuccess({
|
|
281773
282000
|
command: "generate image",
|
|
@@ -281807,8 +282034,8 @@ Examples:
|
|
|
281807
282034
|
throw new Error("No image data available");
|
|
281808
282035
|
}
|
|
281809
282036
|
const outputPath = resolve65(process.cwd(), options.output);
|
|
281810
|
-
await
|
|
281811
|
-
await
|
|
282037
|
+
await mkdir26(dirname38(outputPath), { recursive: true });
|
|
282038
|
+
await writeFile38(outputPath, buffer);
|
|
281812
282039
|
saveSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
281813
282040
|
} catch (err) {
|
|
281814
282041
|
saveSpinner.fail(
|
|
@@ -282838,7 +283065,7 @@ var init_dist5 = __esm({
|
|
|
282838
283065
|
|
|
282839
283066
|
// ../cli/src/commands/generate/video.ts
|
|
282840
283067
|
import { resolve as resolve66 } from "node:path";
|
|
282841
|
-
import { readFile as
|
|
283068
|
+
import { readFile as readFile36, writeFile as writeFile39 } from "node:fs/promises";
|
|
282842
283069
|
function registerVideoCommand(parent) {
|
|
282843
283070
|
parent.command("video").alias("vid").description("Generate video using AI (Seedance, Grok, Kling, Runway, Veo, or Gemini Omni)").argument("[prompt]", "Text prompt describing the video (interactive if omitted)").option(
|
|
282844
283071
|
"-p, --provider <provider>",
|
|
@@ -282950,7 +283177,7 @@ Examples:
|
|
|
282950
283177
|
let isImageToVideo = false;
|
|
282951
283178
|
if (options.image) {
|
|
282952
283179
|
const imagePath = resolve66(process.cwd(), options.image);
|
|
282953
|
-
const imageBuffer = await
|
|
283180
|
+
const imageBuffer = await readFile36(imagePath);
|
|
282954
283181
|
const ext = options.image.toLowerCase().split(".").pop();
|
|
282955
283182
|
const mimeTypes = {
|
|
282956
283183
|
jpg: "image/jpeg",
|
|
@@ -283192,7 +283419,7 @@ Examples:
|
|
|
283192
283419
|
let lastFrame;
|
|
283193
283420
|
if (options.lastFrame) {
|
|
283194
283421
|
const lastFramePath = resolve66(process.cwd(), options.lastFrame);
|
|
283195
|
-
const lastFrameBuffer = await
|
|
283422
|
+
const lastFrameBuffer = await readFile36(lastFramePath);
|
|
283196
283423
|
const ext = options.lastFrame.toLowerCase().split(".").pop();
|
|
283197
283424
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
283198
283425
|
lastFrame = `data:${mimeType};base64,${lastFrameBuffer.toString("base64")}`;
|
|
@@ -283202,7 +283429,7 @@ Examples:
|
|
|
283202
283429
|
refImages = [];
|
|
283203
283430
|
for (const refPath of options.refImages.slice(0, 3)) {
|
|
283204
283431
|
const absRefPath = resolve66(process.cwd(), refPath);
|
|
283205
|
-
const refBuffer = await
|
|
283432
|
+
const refBuffer = await readFile36(absRefPath);
|
|
283206
283433
|
const ext = refPath.toLowerCase().split(".").pop();
|
|
283207
283434
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
283208
283435
|
refImages.push({ base64: refBuffer.toString("base64"), mimeType });
|
|
@@ -283334,7 +283561,7 @@ Examples:
|
|
|
283334
283561
|
if (seedanceEndImagePath && seedanceReferences.length === 0) {
|
|
283335
283562
|
try {
|
|
283336
283563
|
const absEndImagePath = resolve66(process.cwd(), seedanceEndImagePath);
|
|
283337
|
-
const endImageBuffer = await
|
|
283564
|
+
const endImageBuffer = await readFile36(absEndImagePath);
|
|
283338
283565
|
const ext = seedanceEndImagePath.toLowerCase().split(".").pop();
|
|
283339
283566
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
283340
283567
|
const uploadHost = await resolveUploadHost();
|
|
@@ -283390,7 +283617,7 @@ Examples:
|
|
|
283390
283617
|
if (options.output && finalResult.videoUrl) {
|
|
283391
283618
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
283392
283619
|
outputPath = resolve66(process.cwd(), options.output);
|
|
283393
|
-
await
|
|
283620
|
+
await writeFile39(outputPath, buffer);
|
|
283394
283621
|
}
|
|
283395
283622
|
outputSuccess({
|
|
283396
283623
|
command: "generate video",
|
|
@@ -283418,7 +283645,7 @@ Examples:
|
|
|
283418
283645
|
try {
|
|
283419
283646
|
const buffer = await downloadVideo(finalResult.videoUrl, apiKey);
|
|
283420
283647
|
const outputPath = resolve66(process.cwd(), options.output);
|
|
283421
|
-
await
|
|
283648
|
+
await writeFile39(outputPath, buffer);
|
|
283422
283649
|
downloadSpinner.succeed(source_default.green(`Saved to: ${outputPath}`));
|
|
283423
283650
|
} catch (err) {
|
|
283424
283651
|
downloadSpinner.fail(
|
|
@@ -283461,7 +283688,7 @@ async function fileInputToUrlOrDataUri2(input3, fallbackMimeType) {
|
|
|
283461
283688
|
return input3;
|
|
283462
283689
|
}
|
|
283463
283690
|
const absPath = resolve66(process.cwd(), input3);
|
|
283464
|
-
const buffer = await
|
|
283691
|
+
const buffer = await readFile36(absPath);
|
|
283465
283692
|
return `data:${mimeTypeForPath2(input3, fallbackMimeType)};base64,${buffer.toString("base64")}`;
|
|
283466
283693
|
}
|
|
283467
283694
|
function mimeTypeForPath2(path16, fallback2) {
|
|
@@ -283542,7 +283769,7 @@ var init_sanitize = __esm({
|
|
|
283542
283769
|
|
|
283543
283770
|
// ../cli/src/commands/generate/storyboard.ts
|
|
283544
283771
|
import { resolve as resolve67 } from "node:path";
|
|
283545
|
-
import { writeFile as
|
|
283772
|
+
import { writeFile as writeFile40 } from "node:fs/promises";
|
|
283546
283773
|
async function executeStoryboard(options) {
|
|
283547
283774
|
const { content, duration, creativity = "low", output: output3, apiKey } = options;
|
|
283548
283775
|
try {
|
|
@@ -283561,7 +283788,7 @@ async function executeStoryboard(options) {
|
|
|
283561
283788
|
let outputPath;
|
|
283562
283789
|
if (output3) {
|
|
283563
283790
|
outputPath = resolve67(process.cwd(), output3);
|
|
283564
|
-
await
|
|
283791
|
+
await writeFile40(outputPath, JSON.stringify(segments, null, 2), "utf-8");
|
|
283565
283792
|
}
|
|
283566
283793
|
return { success: true, segments, segmentCount: segments.length, outputPath };
|
|
283567
283794
|
} catch (error) {
|
|
@@ -302590,7 +302817,7 @@ __export(detect_exports, {
|
|
|
302590
302817
|
executeDetectScenes: () => executeDetectScenes,
|
|
302591
302818
|
executeDetectSilence: () => executeDetectSilence
|
|
302592
302819
|
});
|
|
302593
|
-
import { readFile as
|
|
302820
|
+
import { readFile as readFile41, writeFile as writeFile44 } from "node:fs/promises";
|
|
302594
302821
|
import { resolve as resolve73, basename as basename20 } from "node:path";
|
|
302595
302822
|
async function executeDetectScenes(options) {
|
|
302596
302823
|
try {
|
|
@@ -302629,7 +302856,7 @@ async function executeDetectScenes(options) {
|
|
|
302629
302856
|
}));
|
|
302630
302857
|
if (options.outputPath) {
|
|
302631
302858
|
const outputPath = resolve73(process.cwd(), options.outputPath);
|
|
302632
|
-
await
|
|
302859
|
+
await writeFile44(outputPath, JSON.stringify({ source: absPath, totalDuration, threshold, scenes: result }, null, 2), "utf-8");
|
|
302633
302860
|
}
|
|
302634
302861
|
return { success: true, scenes: result, totalDuration };
|
|
302635
302862
|
} catch (error) {
|
|
@@ -302676,7 +302903,7 @@ async function executeDetectSilence(options) {
|
|
|
302676
302903
|
}
|
|
302677
302904
|
if (options.outputPath) {
|
|
302678
302905
|
const outputPath = resolve73(process.cwd(), options.outputPath);
|
|
302679
|
-
await
|
|
302906
|
+
await writeFile44(outputPath, JSON.stringify({ source: absPath, silences }, null, 2), "utf-8");
|
|
302680
302907
|
}
|
|
302681
302908
|
return { success: true, silences };
|
|
302682
302909
|
} catch (error) {
|
|
@@ -302725,7 +302952,7 @@ async function executeDetectBeats(options) {
|
|
|
302725
302952
|
}
|
|
302726
302953
|
if (options.outputPath) {
|
|
302727
302954
|
const outputPath = resolve73(process.cwd(), options.outputPath);
|
|
302728
|
-
await
|
|
302955
|
+
await writeFile44(outputPath, JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2), "utf-8");
|
|
302729
302956
|
}
|
|
302730
302957
|
return { success: true, beats, beatCount: beats.length };
|
|
302731
302958
|
} catch (error) {
|
|
@@ -302829,12 +303056,12 @@ var init_detect = __esm({
|
|
|
302829
303056
|
duration: (i3 < scenes.length - 1 ? scenes[i3 + 1].timestamp : totalDuration) - s2.timestamp
|
|
302830
303057
|
}))
|
|
302831
303058
|
};
|
|
302832
|
-
await
|
|
303059
|
+
await writeFile44(outputPath, JSON.stringify(result, null, 2), "utf-8");
|
|
302833
303060
|
console.log(source_default.green(`Saved to: ${outputPath}`));
|
|
302834
303061
|
}
|
|
302835
303062
|
if (options.project) {
|
|
302836
303063
|
const projectPath = resolve73(process.cwd(), options.project);
|
|
302837
|
-
const content = await
|
|
303064
|
+
const content = await readFile41(projectPath, "utf-8");
|
|
302838
303065
|
const data2 = JSON.parse(content);
|
|
302839
303066
|
const project = Project.fromJSON(data2);
|
|
302840
303067
|
let source3 = project.getSources().find((s2) => s2.url === absPath);
|
|
@@ -302859,7 +303086,7 @@ var init_detect = __esm({
|
|
|
302859
303086
|
sourceEndOffset: end
|
|
302860
303087
|
});
|
|
302861
303088
|
}
|
|
302862
|
-
await
|
|
303089
|
+
await writeFile44(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
302863
303090
|
console.log(source_default.green(`Added ${scenes.length} clips to project`));
|
|
302864
303091
|
}
|
|
302865
303092
|
} catch (error) {
|
|
@@ -302941,7 +303168,7 @@ var init_detect = __esm({
|
|
|
302941
303168
|
console.log();
|
|
302942
303169
|
if (options.output) {
|
|
302943
303170
|
const outputPath = resolve73(process.cwd(), options.output);
|
|
302944
|
-
await
|
|
303171
|
+
await writeFile44(
|
|
302945
303172
|
outputPath,
|
|
302946
303173
|
JSON.stringify({ source: absPath, silences }, null, 2),
|
|
302947
303174
|
"utf-8"
|
|
@@ -303026,7 +303253,7 @@ var init_detect = __esm({
|
|
|
303026
303253
|
console.log();
|
|
303027
303254
|
if (options.output) {
|
|
303028
303255
|
const outputPath = resolve73(process.cwd(), options.output);
|
|
303029
|
-
await
|
|
303256
|
+
await writeFile44(
|
|
303030
303257
|
outputPath,
|
|
303031
303258
|
JSON.stringify({ source: absPath, beatCount: beats.length, beats }, null, 2),
|
|
303032
303259
|
"utf-8"
|
|
@@ -303620,7 +303847,7 @@ init_scene_project();
|
|
|
303620
303847
|
init_project_config();
|
|
303621
303848
|
init_cost_tier();
|
|
303622
303849
|
import { resolve as resolve29, relative as relative8, dirname as dirname24 } from "node:path";
|
|
303623
|
-
import { mkdir as
|
|
303850
|
+
import { mkdir as mkdir11, readFile as readFile14, writeFile as writeFile15, access as access4, copyFile as copyFile3 } from "node:fs/promises";
|
|
303624
303851
|
import { existsSync as existsSync46 } from "node:fs";
|
|
303625
303852
|
|
|
303626
303853
|
// ../cli/src/commands/_shared/scene-html-emit.ts
|
|
@@ -303646,7 +303873,7 @@ function esc(text) {
|
|
|
303646
303873
|
function clean(text) {
|
|
303647
303874
|
return (text ?? "").replace(/\s+/g, " ").trim();
|
|
303648
303875
|
}
|
|
303649
|
-
function
|
|
303876
|
+
function humanise2(id) {
|
|
303650
303877
|
return id.split(/[-_]+/).filter(Boolean).map((w4) => w4.charAt(0).toUpperCase() + w4.slice(1)).join(" ");
|
|
303651
303878
|
}
|
|
303652
303879
|
function sceneCompositionId(beatId) {
|
|
@@ -303698,7 +303925,7 @@ function buildPreset(input3) {
|
|
|
303698
303925
|
const id = input3.id;
|
|
303699
303926
|
const scope = `[data-composition-id="${id}"]`;
|
|
303700
303927
|
const displayId = input3.beatId ?? id;
|
|
303701
|
-
const headline = clean(input3.headline) ||
|
|
303928
|
+
const headline = clean(input3.headline) || humanise2(displayId);
|
|
303702
303929
|
const subhead = clean(input3.subhead);
|
|
303703
303930
|
const kicker = clean(input3.kicker);
|
|
303704
303931
|
const dur = input3.duration;
|
|
@@ -303807,7 +304034,7 @@ function buildPreset(input3) {
|
|
|
303807
304034
|
};
|
|
303808
304035
|
}
|
|
303809
304036
|
case "explainer": {
|
|
303810
|
-
const k2 = kicker ||
|
|
304037
|
+
const k2 = kicker || humanise2(displayId).toUpperCase();
|
|
303811
304038
|
const sub = subhead || "";
|
|
303812
304039
|
const transcript = input3.transcript;
|
|
303813
304040
|
const useWordSync = !!(transcript && transcript.length > 0 && sub);
|
|
@@ -303895,7 +304122,7 @@ function buildPreset(input3) {
|
|
|
303895
304122
|
};
|
|
303896
304123
|
}
|
|
303897
304124
|
case "product-shot": {
|
|
303898
|
-
const label = kicker ||
|
|
304125
|
+
const label = kicker || humanise2(displayId);
|
|
303899
304126
|
const headlineFontPx = fitFontSize(headline, 72, 40, 50);
|
|
303900
304127
|
return {
|
|
303901
304128
|
css: `${scope} {
|
|
@@ -304097,9 +304324,10 @@ init_transcribe_narration();
|
|
|
304097
304324
|
// ../cli/src/commands/_shared/scene-submit.ts
|
|
304098
304325
|
init_scene_lint();
|
|
304099
304326
|
init_storyboard_parse();
|
|
304327
|
+
init_storyboard_source();
|
|
304100
304328
|
init_root_sync();
|
|
304101
304329
|
import { existsSync as existsSync44 } from "node:fs";
|
|
304102
|
-
import { mkdir as
|
|
304330
|
+
import { mkdir as mkdir10, writeFile as writeFile13 } from "node:fs/promises";
|
|
304103
304331
|
import { join as join58, resolve as resolve26 } from "node:path";
|
|
304104
304332
|
async function executeSceneSubmit(opts) {
|
|
304105
304333
|
const projectDir = resolve26(opts.projectDir);
|
|
@@ -304122,7 +304350,7 @@ async function executeSceneSubmit(opts) {
|
|
|
304122
304350
|
error: `STORYBOARD.md not found at ${storyboardPath}. Run \`vibe init <dir>\` first.`
|
|
304123
304351
|
};
|
|
304124
304352
|
}
|
|
304125
|
-
const parsed = parseStoryboard(await
|
|
304353
|
+
const parsed = parseStoryboard(await loadStoryboardMarkdown(projectDir));
|
|
304126
304354
|
const beat = parsed.beats.find((b4) => b4.id === beatId);
|
|
304127
304355
|
if (!beat) {
|
|
304128
304356
|
const available = parsed.beats.map((b4) => b4.id).join(", ") || "(none)";
|
|
@@ -304193,8 +304421,8 @@ async function executeSceneSubmit(opts) {
|
|
|
304193
304421
|
return { ...base2, success: true };
|
|
304194
304422
|
}
|
|
304195
304423
|
const absPath = join58(projectDir, scenePath);
|
|
304196
|
-
await
|
|
304197
|
-
await
|
|
304424
|
+
await mkdir10(join58(projectDir, "compositions"), { recursive: true });
|
|
304425
|
+
await writeFile13(absPath, html.endsWith("\n") ? html : `${html}
|
|
304198
304426
|
`, "utf-8");
|
|
304199
304427
|
return {
|
|
304200
304428
|
...base2,
|
|
@@ -304211,6 +304439,7 @@ async function executeSceneSubmit(opts) {
|
|
|
304211
304439
|
init_scene_repair();
|
|
304212
304440
|
init_root_sync();
|
|
304213
304441
|
init_storyboard_edit();
|
|
304442
|
+
init_storyboard_source();
|
|
304214
304443
|
function validateDuration(value) {
|
|
304215
304444
|
const n2 = parseFloat(value);
|
|
304216
304445
|
if (!Number.isFinite(n2) || n2 <= 0 || n2 > 3600) {
|
|
@@ -304387,7 +304616,7 @@ sceneCommand.command("submit").description(
|
|
|
304387
304616
|
}
|
|
304388
304617
|
html = Buffer.concat(chunks).toString("utf-8");
|
|
304389
304618
|
} else if (options.file) {
|
|
304390
|
-
html = await
|
|
304619
|
+
html = await readFile14(resolve29(String(options.file)), "utf-8");
|
|
304391
304620
|
} else {
|
|
304392
304621
|
exitWithError(
|
|
304393
304622
|
usageError(
|
|
@@ -304718,7 +304947,7 @@ async function resolveNarrationText(value) {
|
|
|
304718
304947
|
if (!value) return void 0;
|
|
304719
304948
|
const looksLikePath = /\.[a-z]{2,4}$/i.test(value) || value.includes("/") || value.includes("\\");
|
|
304720
304949
|
if (looksLikePath && existsSync46(value)) {
|
|
304721
|
-
return (await
|
|
304950
|
+
return (await readFile14(value, "utf-8")).trim();
|
|
304722
304951
|
}
|
|
304723
304952
|
return value.trim();
|
|
304724
304953
|
}
|
|
@@ -304759,7 +304988,7 @@ async function executeSceneAdd(opts) {
|
|
|
304759
304988
|
if (!opts.force && await pathExists2(scenePath)) {
|
|
304760
304989
|
return errResult(`Scene already exists: ${sceneRel}. Re-run with --force to overwrite.`);
|
|
304761
304990
|
}
|
|
304762
|
-
const rootHtmlBefore = await
|
|
304991
|
+
const rootHtmlBefore = await readFile14(rootPath, "utf-8");
|
|
304763
304992
|
let dims = readRootDims(rootHtmlBefore);
|
|
304764
304993
|
if (!dims) {
|
|
304765
304994
|
const cfg2 = await loadVibeProjectConfig(projectDir);
|
|
@@ -304783,7 +305012,7 @@ async function executeSceneAdd(opts) {
|
|
|
304783
305012
|
}
|
|
304784
305013
|
audioRelPath = `assets/narration-${id}.${ext}`;
|
|
304785
305014
|
audioAbsPath = resolve29(projectDir, audioRelPath);
|
|
304786
|
-
await
|
|
305015
|
+
await mkdir11(dirname24(audioAbsPath), { recursive: true });
|
|
304787
305016
|
await copyFile3(sourceAbs, audioAbsPath);
|
|
304788
305017
|
try {
|
|
304789
305018
|
narrationDuration = await getAudioDuration(audioAbsPath);
|
|
@@ -304816,8 +305045,8 @@ async function executeSceneAdd(opts) {
|
|
|
304816
305045
|
}
|
|
304817
305046
|
audioRelPath = `assets/narration-${id}.${resolution.audioExtension}`;
|
|
304818
305047
|
audioAbsPath = resolve29(projectDir, audioRelPath);
|
|
304819
|
-
await
|
|
304820
|
-
await
|
|
305048
|
+
await mkdir11(dirname24(audioAbsPath), { recursive: true });
|
|
305049
|
+
await writeFile15(audioAbsPath, tts.audioBuffer);
|
|
304821
305050
|
try {
|
|
304822
305051
|
narrationDuration = await getAudioDuration(audioAbsPath);
|
|
304823
305052
|
} catch {
|
|
@@ -304842,7 +305071,7 @@ async function executeSceneAdd(opts) {
|
|
|
304842
305071
|
if (words.length > 0) {
|
|
304843
305072
|
transcriptRelPath = beatTranscriptRelPath(id);
|
|
304844
305073
|
const transcriptAbs = resolve29(projectDir, transcriptRelPath);
|
|
304845
|
-
await
|
|
305074
|
+
await writeFile15(transcriptAbs, JSON.stringify(words, null, 2), "utf-8");
|
|
304846
305075
|
transcriptWordCount = words.length;
|
|
304847
305076
|
transcriptWords = words;
|
|
304848
305077
|
} else {
|
|
@@ -304879,7 +305108,7 @@ async function executeSceneAdd(opts) {
|
|
|
304879
305108
|
const img = imageResult.images[0];
|
|
304880
305109
|
imageRelPath = `assets/scene-${id}.png`;
|
|
304881
305110
|
imageAbsPath = resolve29(projectDir, imageRelPath);
|
|
304882
|
-
await
|
|
305111
|
+
await mkdir11(dirname24(imageAbsPath), { recursive: true });
|
|
304883
305112
|
let buffer;
|
|
304884
305113
|
if (img.base64) {
|
|
304885
305114
|
buffer = Buffer.from(img.base64, "base64");
|
|
@@ -304889,7 +305118,7 @@ async function executeSceneAdd(opts) {
|
|
|
304889
305118
|
} else {
|
|
304890
305119
|
return errResult("OpenAI returned no image data");
|
|
304891
305120
|
}
|
|
304892
|
-
await
|
|
305121
|
+
await writeFile15(imageAbsPath, buffer);
|
|
304893
305122
|
} else {
|
|
304894
305123
|
const googleKey = await getApiKey("GOOGLE_API_KEY", "Google");
|
|
304895
305124
|
if (!googleKey) {
|
|
@@ -304906,9 +305135,9 @@ async function executeSceneAdd(opts) {
|
|
|
304906
305135
|
}
|
|
304907
305136
|
imageRelPath = `assets/scene-${id}.png`;
|
|
304908
305137
|
imageAbsPath = resolve29(projectDir, imageRelPath);
|
|
304909
|
-
await
|
|
305138
|
+
await mkdir11(dirname24(imageAbsPath), { recursive: true });
|
|
304910
305139
|
const buffer = Buffer.from(imageResult.images[0].base64, "base64");
|
|
304911
|
-
await
|
|
305140
|
+
await writeFile15(imageAbsPath, buffer);
|
|
304912
305141
|
}
|
|
304913
305142
|
}
|
|
304914
305143
|
let lottieRelPath;
|
|
@@ -304925,7 +305154,7 @@ async function executeSceneAdd(opts) {
|
|
|
304925
305154
|
}
|
|
304926
305155
|
lottieRelPath = `assets/lottie-${id}.${ext}`;
|
|
304927
305156
|
lottieAbsPath = resolve29(projectDir, lottieRelPath);
|
|
304928
|
-
await
|
|
305157
|
+
await mkdir11(dirname24(lottieAbsPath), { recursive: true });
|
|
304929
305158
|
await copyFile3(sourceAbs, lottieAbsPath);
|
|
304930
305159
|
lottieInput = {
|
|
304931
305160
|
src: lottieRelPath,
|
|
@@ -304956,21 +305185,29 @@ async function executeSceneAdd(opts) {
|
|
|
304956
305185
|
let storyboardAction = "skipped";
|
|
304957
305186
|
const shouldSyncStoryboard = opts.syncStoryboard !== false && await pathExists2(storyboardAbsPath);
|
|
304958
305187
|
if (shouldSyncStoryboard) {
|
|
304959
|
-
|
|
304960
|
-
const before2 = await readFile15(storyboardAbsPath, "utf-8");
|
|
304961
|
-
const synced = upsertStoryboardBeat(before2, {
|
|
305188
|
+
const upsert = {
|
|
304962
305189
|
beatId: id,
|
|
304963
305190
|
title: opts.headline,
|
|
304964
305191
|
duration,
|
|
304965
305192
|
narration: narrationText && !opts.skipAudio ? narrationText : void 0,
|
|
304966
305193
|
backdrop: opts.visuals && !opts.skipImage ? opts.visuals : void 0
|
|
304967
|
-
}
|
|
304968
|
-
if (
|
|
304969
|
-
|
|
305194
|
+
};
|
|
305195
|
+
if ((await loadStoryboard(projectDir)).layout === "bundle") {
|
|
305196
|
+
opts.onProgress?.("Syncing scenes/...");
|
|
305197
|
+
const synced = await upsertScene(projectDir, upsert);
|
|
305198
|
+
storyboardPath = relative8(process.cwd(), synced.path) || synced.path;
|
|
305199
|
+
storyboardAction = synced.action;
|
|
305200
|
+
} else {
|
|
305201
|
+
opts.onProgress?.("Syncing STORYBOARD.md...");
|
|
305202
|
+
const before2 = await readFile14(storyboardAbsPath, "utf-8");
|
|
305203
|
+
const synced = upsertStoryboardBeat(before2, upsert);
|
|
305204
|
+
if (synced.markdown !== before2) {
|
|
305205
|
+
await writeFile15(storyboardAbsPath, synced.markdown, "utf-8");
|
|
305206
|
+
}
|
|
305207
|
+
storyboardPath = relative8(process.cwd(), storyboardAbsPath) || storyboardAbsPath;
|
|
305208
|
+
storyboardAction = synced.action;
|
|
304970
305209
|
}
|
|
304971
|
-
storyboardPath = relative8(process.cwd(), storyboardAbsPath) || storyboardAbsPath;
|
|
304972
305210
|
storyboardSynced = true;
|
|
304973
|
-
storyboardAction = synced.action;
|
|
304974
305211
|
}
|
|
304975
305212
|
opts.onProgress?.("Emitting scene HTML...");
|
|
304976
305213
|
const sceneHtml = emitSceneHtml({
|
|
@@ -304987,8 +305224,8 @@ async function executeSceneAdd(opts) {
|
|
|
304987
305224
|
transcript: transcriptWords,
|
|
304988
305225
|
lottie: lottieInput
|
|
304989
305226
|
});
|
|
304990
|
-
await
|
|
304991
|
-
await
|
|
305227
|
+
await mkdir11(dirname24(scenePath), { recursive: true });
|
|
305228
|
+
await writeFile15(scenePath, sceneHtml, "utf-8");
|
|
304992
305229
|
opts.onProgress?.("Updating root composition...");
|
|
304993
305230
|
let start = 0;
|
|
304994
305231
|
if (storyboardSynced) {
|
|
@@ -304999,14 +305236,14 @@ async function executeSceneAdd(opts) {
|
|
|
304999
305236
|
});
|
|
305000
305237
|
const blockingIssue = syncPlan.issues.find((issue) => issue.severity === "error");
|
|
305001
305238
|
if (blockingIssue) return errResult(blockingIssue.message);
|
|
305002
|
-
const rootHtmlAfterSync = await
|
|
305239
|
+
const rootHtmlAfterSync = await readFile14(rootPath, "utf-8");
|
|
305003
305240
|
start = readClipStart(rootHtmlAfterSync, id) ?? 0;
|
|
305004
305241
|
} else {
|
|
305005
305242
|
start = nextSceneStart(rootHtmlBefore, SCENE_OVERLAP_SECONDS);
|
|
305006
305243
|
const existingClipCount = (rootHtmlBefore.match(/<div\s+class="clip"/g) || []).length;
|
|
305007
305244
|
const trackIndex = existingClipCount % 2 + 1;
|
|
305008
305245
|
const updated = insertClipIntoRoot(rootHtmlBefore, { id, start, duration, trackIndex });
|
|
305009
|
-
await
|
|
305246
|
+
await writeFile15(rootPath, updated, "utf-8");
|
|
305010
305247
|
}
|
|
305011
305248
|
const transcriptAbsPath = transcriptRelPath ? resolve29(projectDir, transcriptRelPath) : void 0;
|
|
305012
305249
|
return {
|
|
@@ -306037,7 +306274,7 @@ init_api_key();
|
|
|
306037
306274
|
init_exec_safe();
|
|
306038
306275
|
init_remotion();
|
|
306039
306276
|
import { resolve as resolve51, dirname as dirname35, basename as basename14 } from "node:path";
|
|
306040
|
-
import { writeFile as
|
|
306277
|
+
import { writeFile as writeFile30, mkdir as mkdir23, rm as rm9 } from "node:fs/promises";
|
|
306041
306278
|
import { existsSync as existsSync71 } from "node:fs";
|
|
306042
306279
|
import { tmpdir as tmpdir11 } from "node:os";
|
|
306043
306280
|
var ASS_STYLES = ["karaoke-sweep", "typewriter"];
|
|
@@ -306189,7 +306426,7 @@ async function executeAnimatedCaption(options) {
|
|
|
306189
306426
|
}
|
|
306190
306427
|
const effectiveFontSize = fontSize ?? Math.round(height * 0.04);
|
|
306191
306428
|
const tmpAudioDir = resolve51(tmpdir11(), `vf-ac-${Date.now()}`);
|
|
306192
|
-
await
|
|
306429
|
+
await mkdir23(tmpAudioDir, { recursive: true });
|
|
306193
306430
|
const audioPath = resolve51(tmpAudioDir, "audio.wav");
|
|
306194
306431
|
await execSafe("ffmpeg", [
|
|
306195
306432
|
"-y",
|
|
@@ -306206,13 +306443,13 @@ async function executeAnimatedCaption(options) {
|
|
|
306206
306443
|
], { timeout: 12e4 });
|
|
306207
306444
|
const apiKey = await getApiKey("OPENAI_API_KEY", "OpenAI");
|
|
306208
306445
|
if (!apiKey) {
|
|
306209
|
-
await
|
|
306446
|
+
await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
306210
306447
|
});
|
|
306211
306448
|
return { success: false, error: "OPENAI_API_KEY required for Whisper transcription. Run 'vibe setup' or set OPENAI_API_KEY in .env" };
|
|
306212
306449
|
}
|
|
306213
306450
|
const transcript = await transcribeWithWords(audioPath, apiKey, language);
|
|
306214
306451
|
if (!transcript.words || transcript.words.length === 0) {
|
|
306215
|
-
await
|
|
306452
|
+
await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
306216
306453
|
});
|
|
306217
306454
|
return { success: false, error: "No words detected in transcription" };
|
|
306218
306455
|
}
|
|
@@ -306220,7 +306457,7 @@ async function executeAnimatedCaption(options) {
|
|
|
306220
306457
|
const absOutputPath = resolve51(process.cwd(), outputPath);
|
|
306221
306458
|
const outDir = dirname35(absOutputPath);
|
|
306222
306459
|
if (!existsSync71(outDir)) {
|
|
306223
|
-
await
|
|
306460
|
+
await mkdir23(outDir, { recursive: true });
|
|
306224
306461
|
}
|
|
306225
306462
|
if (tier === "ass") {
|
|
306226
306463
|
const assContent = generateASS(
|
|
@@ -306229,7 +306466,7 @@ async function executeAnimatedCaption(options) {
|
|
|
306229
306466
|
{ highlightColor, fontSize: effectiveFontSize, position, width, height }
|
|
306230
306467
|
);
|
|
306231
306468
|
const assPath = resolve51(tmpAudioDir, "captions.ass");
|
|
306232
|
-
await
|
|
306469
|
+
await writeFile30(assPath, assContent, "utf-8");
|
|
306233
306470
|
const escapedAssPath = assPath.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
|
|
306234
306471
|
await execSafe("ffmpeg", [
|
|
306235
306472
|
"-y",
|
|
@@ -306266,12 +306503,12 @@ async function executeAnimatedCaption(options) {
|
|
|
306266
306503
|
outputPath: absOutputPath
|
|
306267
306504
|
});
|
|
306268
306505
|
if (!renderResult.success) {
|
|
306269
|
-
await
|
|
306506
|
+
await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
306270
306507
|
});
|
|
306271
306508
|
return { success: false, error: renderResult.error };
|
|
306272
306509
|
}
|
|
306273
306510
|
}
|
|
306274
|
-
await
|
|
306511
|
+
await rm9(tmpAudioDir, { recursive: true, force: true }).catch(() => {
|
|
306275
306512
|
});
|
|
306276
306513
|
return {
|
|
306277
306514
|
success: true,
|
|
@@ -306766,14 +307003,14 @@ init_ai_analyze();
|
|
|
306766
307003
|
init_dist();
|
|
306767
307004
|
init_engine();
|
|
306768
307005
|
init_ai_helpers();
|
|
306769
|
-
import { readFile as
|
|
307006
|
+
import { readFile as readFile31, writeFile as writeFile33 } from "node:fs/promises";
|
|
306770
307007
|
import { resolve as resolve55 } from "node:path";
|
|
306771
307008
|
async function executeSuggestEdit(options) {
|
|
306772
307009
|
try {
|
|
306773
307010
|
const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY;
|
|
306774
307011
|
if (!apiKey) return { success: false, error: "GOOGLE_API_KEY required for suggest" };
|
|
306775
307012
|
const filePath = resolve55(process.cwd(), options.projectPath);
|
|
306776
|
-
const content = await
|
|
307013
|
+
const content = await readFile31(filePath, "utf-8");
|
|
306777
307014
|
const data2 = JSON.parse(content);
|
|
306778
307015
|
const project = Project.fromJSON(data2);
|
|
306779
307016
|
const gemini = new GeminiProvider();
|
|
@@ -306784,7 +307021,7 @@ async function executeSuggestEdit(options) {
|
|
|
306784
307021
|
const first3 = suggestions[0];
|
|
306785
307022
|
const applied = applySuggestion(project, first3);
|
|
306786
307023
|
if (applied) {
|
|
306787
|
-
await
|
|
307024
|
+
await writeFile33(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
306788
307025
|
return {
|
|
306789
307026
|
success: true,
|
|
306790
307027
|
suggestions,
|
|
@@ -306810,8 +307047,8 @@ init_project_config();
|
|
|
306810
307047
|
init_scene_lint();
|
|
306811
307048
|
init_root_sync();
|
|
306812
307049
|
init_review_report();
|
|
306813
|
-
import { existsSync as
|
|
306814
|
-
import { readdir as
|
|
307050
|
+
import { existsSync as existsSync75 } from "node:fs";
|
|
307051
|
+
import { readdir as readdir8, readFile as readFile33, stat as stat7 } from "node:fs/promises";
|
|
306815
307052
|
import { basename as basename15, isAbsolute as isAbsolute12, join as join70, relative as relative13, resolve as resolve56 } from "node:path";
|
|
306816
307053
|
async function inspectProject(opts) {
|
|
306817
307054
|
const projectDir = resolve56(opts.projectDir);
|
|
@@ -306826,7 +307063,7 @@ async function inspectProject(opts) {
|
|
|
306826
307063
|
assets: { checked: 0, missing: [], stale: [], unknownFreshness: [] },
|
|
306827
307064
|
rootSync: { ok: null, issueCount: 0, issues: [] }
|
|
306828
307065
|
};
|
|
306829
|
-
if (!
|
|
307066
|
+
if (!existsSync75(projectDir) || !await isDirectory(projectDir)) {
|
|
306830
307067
|
issues.push({
|
|
306831
307068
|
severity: "error",
|
|
306832
307069
|
code: "PROJECT_NOT_FOUND",
|
|
@@ -306849,7 +307086,7 @@ async function inspectProject(opts) {
|
|
|
306849
307086
|
root: join70(projectDir, "index.html")
|
|
306850
307087
|
};
|
|
306851
307088
|
for (const [name, path16] of Object.entries(coreFiles)) {
|
|
306852
|
-
checks.files[name] =
|
|
307089
|
+
checks.files[name] = existsSync75(path16);
|
|
306853
307090
|
}
|
|
306854
307091
|
let beatIds = [];
|
|
306855
307092
|
let inspectedBeatIds = [];
|
|
@@ -306863,7 +307100,7 @@ async function inspectProject(opts) {
|
|
|
306863
307100
|
});
|
|
306864
307101
|
retryWith.push(`vibe init ${projectDir} --from "<brief>" --json`);
|
|
306865
307102
|
} else {
|
|
306866
|
-
const storyboard = await
|
|
307103
|
+
const storyboard = await readFile33(coreFiles.storyboard, "utf-8");
|
|
306867
307104
|
const validation3 = validateStoryboardMarkdown(storyboard);
|
|
306868
307105
|
storyboardBeats = validation3.beats;
|
|
306869
307106
|
beatIds = validation3.beats.map((beat) => beat.id);
|
|
@@ -306905,7 +307142,7 @@ async function inspectProject(opts) {
|
|
|
306905
307142
|
suggestedFix: "Create DESIGN.md or rerun `vibe init --from` in a new project."
|
|
306906
307143
|
});
|
|
306907
307144
|
} else {
|
|
306908
|
-
const design = await
|
|
307145
|
+
const design = await readFile33(coreFiles.design, "utf-8");
|
|
306909
307146
|
for (const issue of designPlaceholderIssues(design)) {
|
|
306910
307147
|
issues.push(issue);
|
|
306911
307148
|
}
|
|
@@ -306931,7 +307168,7 @@ async function inspectProject(opts) {
|
|
|
306931
307168
|
retryWith.push(`vibe build ${projectDir} --stage sync --json`);
|
|
306932
307169
|
}
|
|
306933
307170
|
const compositionsDir = join70(projectDir, "compositions");
|
|
306934
|
-
const existingComps =
|
|
307171
|
+
const existingComps = existsSync75(compositionsDir) ? new Set(await listHtmlBasenames(compositionsDir)) : /* @__PURE__ */ new Set();
|
|
306935
307172
|
checks.compositions.expected = inspectedBeatIds.length;
|
|
306936
307173
|
for (const beatId of inspectedBeatIds) {
|
|
306937
307174
|
const file = `scene-${beatId}.html`;
|
|
@@ -307151,7 +307388,7 @@ function projectSourceReports(checks) {
|
|
|
307151
307388
|
async function inspectBuildReport(projectDir, reportPath, beatId, checks, issues, retryWith, storyboardBeats) {
|
|
307152
307389
|
checks.buildReport.exists = true;
|
|
307153
307390
|
try {
|
|
307154
|
-
const report = JSON.parse(await
|
|
307391
|
+
const report = JSON.parse(await readFile33(reportPath, "utf-8"));
|
|
307155
307392
|
if (typeof report.outputPath === "string") checks.buildReport.outputPath = report.outputPath;
|
|
307156
307393
|
const reportBeats = report.beats ?? [];
|
|
307157
307394
|
const selectedReportBeats = reportBeats.filter((item) => !beatId || item.id === beatId);
|
|
@@ -307288,7 +307525,7 @@ function inspectReportedAsset(opts) {
|
|
|
307288
307525
|
opts.checks.assets.checked++;
|
|
307289
307526
|
if (isExternalRef2(opts.value)) return;
|
|
307290
307527
|
const abs = isAbsolute12(opts.value) ? opts.value : resolve56(opts.projectDir, opts.value);
|
|
307291
|
-
if (
|
|
307528
|
+
if (existsSync75(abs)) return;
|
|
307292
307529
|
opts.checks.assets.missing.push(opts.value);
|
|
307293
307530
|
opts.issues.push({
|
|
307294
307531
|
severity: "warning",
|
|
@@ -307369,7 +307606,7 @@ async function isDirectory(path16) {
|
|
|
307369
307606
|
}
|
|
307370
307607
|
}
|
|
307371
307608
|
async function listHtmlBasenames(dir) {
|
|
307372
|
-
const entries2 = await
|
|
307609
|
+
const entries2 = await readdir8(dir, { withFileTypes: true });
|
|
307373
307610
|
return entries2.filter((entry) => entry.isFile() && entry.name.endsWith(".html")).map((entry) => entry.name);
|
|
307374
307611
|
}
|
|
307375
307612
|
function isExternalRef2(value) {
|
|
@@ -307382,8 +307619,8 @@ init_exec_safe();
|
|
|
307382
307619
|
init_project_config();
|
|
307383
307620
|
init_storyboard_parse();
|
|
307384
307621
|
init_review_report();
|
|
307385
|
-
import { existsSync as
|
|
307386
|
-
import { readdir as
|
|
307622
|
+
import { existsSync as existsSync77 } from "node:fs";
|
|
307623
|
+
import { readdir as readdir9, readFile as readFile35, stat as stat8 } from "node:fs/promises";
|
|
307387
307624
|
import { basename as basename16, isAbsolute as isAbsolute13, join as join71, relative as relative14, resolve as resolve58 } from "node:path";
|
|
307388
307625
|
var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([".mp4", ".mov", ".webm", ".m4v"]);
|
|
307389
307626
|
var DEFAULT_AI_MODEL = "flash";
|
|
@@ -307900,7 +308137,7 @@ async function renderExpectsAudio(projectDir, beatId) {
|
|
|
307900
308137
|
`assets/narration-${beat.id}.wav`,
|
|
307901
308138
|
`assets/music-${beat.id}.mp3`,
|
|
307902
308139
|
`assets/music-${beat.id}.wav`
|
|
307903
|
-
].some((asset) =>
|
|
308140
|
+
].some((asset) => existsSync77(join71(root2, asset)))
|
|
307904
308141
|
);
|
|
307905
308142
|
} catch {
|
|
307906
308143
|
return false;
|
|
@@ -308008,8 +308245,8 @@ async function maybeWriteRenderReport(projectDir, opts, result) {
|
|
|
308008
308245
|
}
|
|
308009
308246
|
function renderSourceReports(projectDir, videoPath, checks) {
|
|
308010
308247
|
const reports = [];
|
|
308011
|
-
if (
|
|
308012
|
-
if (
|
|
308248
|
+
if (existsSync77(join71(projectDir, "build-report.json"))) reports.push("build-report.json");
|
|
308249
|
+
if (existsSync77(join71(projectDir, "render-report.json"))) reports.push("render-report.json");
|
|
308013
308250
|
if (videoPath) reports.push(displayPath(videoPath));
|
|
308014
308251
|
if (checks.durationSec !== void 0 || checks.width !== void 0 || checks.height !== void 0) {
|
|
308015
308252
|
reports.push("ffprobe");
|
|
@@ -308022,32 +308259,32 @@ function renderSourceReports(projectDir, videoPath, checks) {
|
|
|
308022
308259
|
async function resolveRenderVideoPath(projectDir, explicit, beatId) {
|
|
308023
308260
|
if (explicit) {
|
|
308024
308261
|
const candidate = resolve58(process.cwd(), explicit);
|
|
308025
|
-
return
|
|
308262
|
+
return existsSync77(candidate) ? candidate : null;
|
|
308026
308263
|
}
|
|
308027
308264
|
const renderReportPath = join71(projectDir, "render-report.json");
|
|
308028
|
-
if (
|
|
308265
|
+
if (existsSync77(renderReportPath)) {
|
|
308029
308266
|
try {
|
|
308030
|
-
const report = JSON.parse(await
|
|
308267
|
+
const report = JSON.parse(await readFile35(renderReportPath, "utf-8"));
|
|
308031
308268
|
const reportBeat = typeof report.beat === "string" ? report.beat : null;
|
|
308032
308269
|
if (!beatId && reportBeat === null || beatId && reportBeat === beatId) {
|
|
308033
308270
|
const candidate = resolveReportedPath(projectDir, report.outputPath);
|
|
308034
|
-
if (candidate &&
|
|
308271
|
+
if (candidate && existsSync77(candidate)) return candidate;
|
|
308035
308272
|
}
|
|
308036
308273
|
} catch {
|
|
308037
308274
|
}
|
|
308038
308275
|
}
|
|
308039
308276
|
const reportPath = join71(projectDir, "build-report.json");
|
|
308040
|
-
if (!beatId &&
|
|
308277
|
+
if (!beatId && existsSync77(reportPath)) {
|
|
308041
308278
|
try {
|
|
308042
|
-
const report = JSON.parse(await
|
|
308279
|
+
const report = JSON.parse(await readFile35(reportPath, "utf-8"));
|
|
308043
308280
|
const candidate = resolveReportedPath(projectDir, report.outputPath);
|
|
308044
|
-
if (candidate &&
|
|
308281
|
+
if (candidate && existsSync77(candidate)) return candidate;
|
|
308045
308282
|
} catch {
|
|
308046
308283
|
}
|
|
308047
308284
|
}
|
|
308048
308285
|
const rendersDir = join71(projectDir, "renders");
|
|
308049
|
-
if (!
|
|
308050
|
-
const entries2 = await
|
|
308286
|
+
if (!existsSync77(rendersDir)) return null;
|
|
308287
|
+
const entries2 = await readdir9(rendersDir, { withFileTypes: true });
|
|
308051
308288
|
const candidates = [];
|
|
308052
308289
|
for (const entry of entries2) {
|
|
308053
308290
|
if (!entry.isFile()) continue;
|
|
@@ -308073,13 +308310,13 @@ async function runAiRenderReview(projectDir, videoPath, model) {
|
|
|
308073
308310
|
}
|
|
308074
308311
|
function resolveStoryboardPath(projectDir) {
|
|
308075
308312
|
const storyboardPath = join71(projectDir, "STORYBOARD.md");
|
|
308076
|
-
return
|
|
308313
|
+
return existsSync77(storyboardPath) ? storyboardPath : null;
|
|
308077
308314
|
}
|
|
308078
308315
|
async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
308079
308316
|
const reportPath = join71(projectDir, "build-report.json");
|
|
308080
|
-
if (!
|
|
308317
|
+
if (!existsSync77(reportPath)) return void 0;
|
|
308081
308318
|
try {
|
|
308082
|
-
const report = JSON.parse(await
|
|
308319
|
+
const report = JSON.parse(await readFile35(reportPath, "utf-8"));
|
|
308083
308320
|
const beats = beatId ? (report.beats ?? []).filter((beat) => beat.id === beatId) : report.beats ?? [];
|
|
308084
308321
|
const durations = beats.map(
|
|
308085
308322
|
(beat) => parseOptionalNumber2(beat.sceneDurationSec) ?? parseOptionalNumber2(beat.narration?.sceneDurationSec)
|
|
@@ -308092,9 +308329,9 @@ async function expectedDurationFromBuildReport(projectDir, beatId) {
|
|
|
308092
308329
|
}
|
|
308093
308330
|
async function beatTimingsFromBuildReport(projectDir, beatId) {
|
|
308094
308331
|
const reportPath = join71(projectDir, "build-report.json");
|
|
308095
|
-
if (!
|
|
308332
|
+
if (!existsSync77(reportPath)) return [];
|
|
308096
308333
|
try {
|
|
308097
|
-
const report = JSON.parse(await
|
|
308334
|
+
const report = JSON.parse(await readFile35(reportPath, "utf-8"));
|
|
308098
308335
|
const source3 = report.beats ?? [];
|
|
308099
308336
|
const selected = beatId ? source3.filter((beat) => beat.id === beatId) : source3;
|
|
308100
308337
|
let cursor = 0;
|
|
@@ -308158,9 +308395,9 @@ function storyboardBeatCueSummary(storyboard) {
|
|
|
308158
308395
|
}
|
|
308159
308396
|
}
|
|
308160
308397
|
async function readTextIfExists(path16) {
|
|
308161
|
-
if (!
|
|
308398
|
+
if (!existsSync77(path16)) return null;
|
|
308162
308399
|
try {
|
|
308163
|
-
return await
|
|
308400
|
+
return await readFile35(path16, "utf-8");
|
|
308164
308401
|
} catch {
|
|
308165
308402
|
return null;
|
|
308166
308403
|
}
|
|
@@ -308782,16 +309019,16 @@ var generateTools = [
|
|
|
308782
309019
|
];
|
|
308783
309020
|
|
|
308784
309021
|
// ../cli/src/tools/manifest/storyboard.ts
|
|
308785
|
-
import { existsSync as
|
|
308786
|
-
import { readFile as
|
|
309022
|
+
import { existsSync as existsSync80 } from "node:fs";
|
|
309023
|
+
import { readFile as readFile38, writeFile as writeFile42 } from "node:fs/promises";
|
|
308787
309024
|
import { resolve as resolve69 } from "node:path";
|
|
308788
309025
|
import { z as z9 } from "zod";
|
|
308789
309026
|
init_storyboard_parse();
|
|
308790
309027
|
init_storyboard_edit();
|
|
308791
309028
|
|
|
308792
309029
|
// ../cli/src/commands/_shared/storyboard-revise.ts
|
|
308793
|
-
import { existsSync as
|
|
308794
|
-
import { readFile as
|
|
309030
|
+
import { existsSync as existsSync79 } from "node:fs";
|
|
309031
|
+
import { readFile as readFile37, writeFile as writeFile41 } from "node:fs/promises";
|
|
308795
309032
|
import { join as join73, resolve as resolve68 } from "node:path";
|
|
308796
309033
|
|
|
308797
309034
|
// ../cli/src/agent/adapters/index.ts
|
|
@@ -308841,12 +309078,13 @@ async function createAdapter(provider) {
|
|
|
308841
309078
|
init_composer_resolve();
|
|
308842
309079
|
init_project_config();
|
|
308843
309080
|
init_storyboard_parse();
|
|
309081
|
+
init_storyboard_source();
|
|
308844
309082
|
init_storyboard_edit();
|
|
308845
309083
|
async function executeStoryboardRevision(opts) {
|
|
308846
309084
|
const projectDir = resolve68(opts.projectDir);
|
|
308847
309085
|
const storyboardPath = join73(projectDir, "STORYBOARD.md");
|
|
308848
309086
|
const retryWith = [`vibe storyboard revise ${projectDir} --from "<request>" --dry-run --json`];
|
|
308849
|
-
if (!
|
|
309087
|
+
if (!existsSync79(storyboardPath)) {
|
|
308850
309088
|
return failureResult({
|
|
308851
309089
|
projectDir,
|
|
308852
309090
|
storyboardPath,
|
|
@@ -308856,7 +309094,8 @@ async function executeStoryboardRevision(opts) {
|
|
|
308856
309094
|
retryWith: [`vibe init ${projectDir} --from "<brief>" --json`]
|
|
308857
309095
|
});
|
|
308858
309096
|
}
|
|
308859
|
-
const
|
|
309097
|
+
const loaded = await loadStoryboard(projectDir);
|
|
309098
|
+
const currentStoryboard = loaded.markdown;
|
|
308860
309099
|
const projectConfig = await readProjectConfig(projectDir);
|
|
308861
309100
|
const explicitComposer = opts.composer ?? projectConfig.config.providers.composer ?? void 0;
|
|
308862
309101
|
let provider = explicitComposer ?? "claude";
|
|
@@ -308955,7 +309194,11 @@ async function executeStoryboardRevision(opts) {
|
|
|
308955
309194
|
}
|
|
308956
309195
|
const storyboardMd = normalizeMarkdown(payload.storyboardMd);
|
|
308957
309196
|
if (!opts.dryRun) {
|
|
308958
|
-
|
|
309197
|
+
if (loaded.layout === "bundle") {
|
|
309198
|
+
await rewriteBundleFromMarkdown(projectDir, storyboardMd);
|
|
309199
|
+
} else {
|
|
309200
|
+
await writeFile41(storyboardPath, storyboardMd, "utf-8");
|
|
309201
|
+
}
|
|
308959
309202
|
}
|
|
308960
309203
|
const changedBeats = unique5([...diffChangedBeats(currentStoryboard, storyboardMd), ...payload.changedBeats]);
|
|
308961
309204
|
return stripUndefined4({
|
|
@@ -308990,7 +309233,10 @@ function revisionMessages(opts) {
|
|
|
308990
309233
|
"Return exactly one JSON object, with no markdown fence and no prose outside JSON.",
|
|
308991
309234
|
"The JSON object must have: storyboardMd string, summary string, changedBeats string[], warnings string[].",
|
|
308992
309235
|
"Preserve existing frontmatter, beat ids, cue YAML keys, and useful prose unless the user asks to change structure.",
|
|
308993
|
-
|
|
309236
|
+
// Rendered from the SSOT: this list used to be a hand-typed subset of 8,
|
|
309237
|
+
// so a revise pass could silently drop `characters`, `keyframe`, and the
|
|
309238
|
+
// lower-third cues it had never been told about.
|
|
309239
|
+
`Keep cue YAML valid. Allowed cue keys are ${STORYBOARD_CUE_KEYS.join(", ")}.`,
|
|
308994
309240
|
"If a target duration is supplied, every beat must have a positive duration cue and durations must sum to that target.",
|
|
308995
309241
|
"Aim for 6-15 seconds per beat and never exceed ~15s \u2014 long beats render as static, overstuffed scenes. A 90-second video should have 6-8 beats."
|
|
308996
309242
|
].join("\n");
|
|
@@ -309084,13 +309330,13 @@ async function readRevisionContext(projectDir) {
|
|
|
309084
309330
|
return { designMd, buildReportJson };
|
|
309085
309331
|
}
|
|
309086
309332
|
async function readOptionalText(path16) {
|
|
309087
|
-
if (!
|
|
309088
|
-
return
|
|
309333
|
+
if (!existsSync79(path16)) return null;
|
|
309334
|
+
return readFile37(path16, "utf-8");
|
|
309089
309335
|
}
|
|
309090
309336
|
async function readOptionalJsonText(path16) {
|
|
309091
|
-
if (!
|
|
309337
|
+
if (!existsSync79(path16)) return null;
|
|
309092
309338
|
try {
|
|
309093
|
-
const parsed = JSON.parse(await
|
|
309339
|
+
const parsed = JSON.parse(await readFile37(path16, "utf-8"));
|
|
309094
309340
|
return JSON.stringify(parsed, null, 2);
|
|
309095
309341
|
} catch {
|
|
309096
309342
|
return null;
|
|
@@ -309135,8 +309381,8 @@ var projectDirSchema = z9.object({
|
|
|
309135
309381
|
});
|
|
309136
309382
|
async function readStoryboard(projectDir) {
|
|
309137
309383
|
const path16 = resolve69(projectDir, "STORYBOARD.md");
|
|
309138
|
-
if (!
|
|
309139
|
-
return { path: path16, markdown: await
|
|
309384
|
+
if (!existsSync80(path16)) return null;
|
|
309385
|
+
return { path: path16, markdown: await readFile38(path16, "utf-8") };
|
|
309140
309386
|
}
|
|
309141
309387
|
var storyboardListTool = defineTool({
|
|
309142
309388
|
name: "storyboard_list",
|
|
@@ -309249,7 +309495,7 @@ var storyboardSetTool = defineTool({
|
|
|
309249
309495
|
value,
|
|
309250
309496
|
unset: args.unset
|
|
309251
309497
|
});
|
|
309252
|
-
await
|
|
309498
|
+
await writeFile42(file.path, next, "utf-8");
|
|
309253
309499
|
return {
|
|
309254
309500
|
success: true,
|
|
309255
309501
|
data: { beat: args.beat, key: args.key },
|
|
@@ -309281,7 +309527,7 @@ var storyboardMoveTool = defineTool({
|
|
|
309281
309527
|
beatId: args.beat,
|
|
309282
309528
|
afterBeatId: args.after
|
|
309283
309529
|
});
|
|
309284
|
-
await
|
|
309530
|
+
await writeFile42(file.path, next, "utf-8");
|
|
309285
309531
|
return {
|
|
309286
309532
|
success: true,
|
|
309287
309533
|
data: { beat: args.beat, after: args.after },
|
|
@@ -309393,8 +309639,8 @@ var storyboardTools = [
|
|
|
309393
309639
|
];
|
|
309394
309640
|
|
|
309395
309641
|
// ../cli/src/tools/manifest/design.ts
|
|
309396
|
-
import { existsSync as
|
|
309397
|
-
import { readFile as
|
|
309642
|
+
import { existsSync as existsSync81 } from "node:fs";
|
|
309643
|
+
import { readFile as readFile39 } from "node:fs/promises";
|
|
309398
309644
|
import { resolve as resolve70, join as join74 } from "node:path";
|
|
309399
309645
|
import { z as z10 } from "zod";
|
|
309400
309646
|
init_design_parse();
|
|
@@ -309413,8 +309659,8 @@ var designValidateTool = defineTool({
|
|
|
309413
309659
|
async execute(args, ctx) {
|
|
309414
309660
|
const projectDir = args.projectDir ? resolve70(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
309415
309661
|
const path16 = join74(projectDir, "DESIGN.md");
|
|
309416
|
-
if (!
|
|
309417
|
-
const md = await
|
|
309662
|
+
if (!existsSync81(path16)) return { success: false, error: `DESIGN.md not found in ${projectDir}` };
|
|
309663
|
+
const md = await readFile39(path16, "utf-8");
|
|
309418
309664
|
const issues = validateDesignMarkdown(md);
|
|
309419
309665
|
const design = parseDesign(md);
|
|
309420
309666
|
const ok = !issues.some((issue) => issue.severity === "error");
|
|
@@ -309435,15 +309681,15 @@ var designValidateTool = defineTool({
|
|
|
309435
309681
|
var designTools = [designValidateTool];
|
|
309436
309682
|
|
|
309437
309683
|
// ../cli/src/tools/manifest/remix.ts
|
|
309438
|
-
import { writeFile as
|
|
309684
|
+
import { writeFile as writeFile46 } from "node:fs/promises";
|
|
309439
309685
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
309440
309686
|
import { join as join75 } from "node:path";
|
|
309441
309687
|
import { z as z11 } from "zod";
|
|
309442
309688
|
|
|
309443
309689
|
// ../cli/src/commands/ai-highlights.ts
|
|
309444
|
-
import { readFile as
|
|
309690
|
+
import { readFile as readFile40, writeFile as writeFile43, mkdir as mkdir27 } from "node:fs/promises";
|
|
309445
309691
|
import { resolve as resolve71, dirname as dirname39, basename as basename19, extname as extname18 } from "node:path";
|
|
309446
|
-
import { existsSync as
|
|
309692
|
+
import { existsSync as existsSync82 } from "node:fs";
|
|
309447
309693
|
init_dist();
|
|
309448
309694
|
init_engine();
|
|
309449
309695
|
init_api_key();
|
|
@@ -309474,7 +309720,7 @@ function filterHighlights(highlights, options) {
|
|
|
309474
309720
|
async function executeHighlights(options) {
|
|
309475
309721
|
try {
|
|
309476
309722
|
const absPath = resolve71(process.cwd(), options.media);
|
|
309477
|
-
if (!
|
|
309723
|
+
if (!existsSync82(absPath)) {
|
|
309478
309724
|
return { success: false, highlights: [], totalDuration: 0, totalHighlightDuration: 0, error: `File not found: ${absPath}` };
|
|
309479
309725
|
}
|
|
309480
309726
|
const ext = extname18(absPath).toLowerCase();
|
|
@@ -309493,7 +309739,7 @@ async function executeHighlights(options) {
|
|
|
309493
309739
|
sourceDuration = await ffprobeDuration(absPath);
|
|
309494
309740
|
const gemini = new GeminiProvider();
|
|
309495
309741
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
309496
|
-
const videoBuffer = await
|
|
309742
|
+
const videoBuffer = await readFile40(absPath);
|
|
309497
309743
|
const criteriaText = options.criteria === "all" || !options.criteria ? "emotional, informative, and funny moments" : `${options.criteria} moments`;
|
|
309498
309744
|
const durationText = targetDuration ? `Target a total highlight duration of ${targetDuration} seconds.` : "";
|
|
309499
309745
|
const countText = maxCount ? `Find up to ${maxCount} highlights.` : "";
|
|
@@ -309587,10 +309833,10 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
309587
309833
|
}
|
|
309588
309834
|
const whisper = new WhisperProvider();
|
|
309589
309835
|
await whisper.initialize({ apiKey: openaiApiKey });
|
|
309590
|
-
const audioBuffer = await
|
|
309836
|
+
const audioBuffer = await readFile40(audioPath);
|
|
309591
309837
|
const audioBlob = new Blob([audioBuffer]);
|
|
309592
309838
|
const transcriptResult = await whisper.transcribe(audioBlob, options.language);
|
|
309593
|
-
if (tempAudioPath &&
|
|
309839
|
+
if (tempAudioPath && existsSync82(tempAudioPath)) {
|
|
309594
309840
|
const { unlink: unlinkFile } = await import("node:fs/promises");
|
|
309595
309841
|
await unlinkFile(tempAudioPath).catch(() => {
|
|
309596
309842
|
});
|
|
@@ -309622,7 +309868,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
309622
309868
|
};
|
|
309623
309869
|
if (options.output) {
|
|
309624
309870
|
const outputPath = resolve71(process.cwd(), options.output);
|
|
309625
|
-
await
|
|
309871
|
+
await writeFile43(outputPath, JSON.stringify({
|
|
309626
309872
|
sourceFile: absPath,
|
|
309627
309873
|
totalDuration: sourceDuration,
|
|
309628
309874
|
criteria: options.criteria || "all",
|
|
@@ -309657,7 +309903,7 @@ Analyze both what is SHOWN (visual cues, actions, expressions) and what is SAID
|
|
|
309657
309903
|
}
|
|
309658
309904
|
}
|
|
309659
309905
|
const projectPath = resolve71(process.cwd(), options.project);
|
|
309660
|
-
await
|
|
309906
|
+
await writeFile43(projectPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
309661
309907
|
extractResult.projectPath = projectPath;
|
|
309662
309908
|
}
|
|
309663
309909
|
return extractResult;
|
|
@@ -309677,7 +309923,7 @@ async function executeAutoShorts(options) {
|
|
|
309677
309923
|
return { success: false, shorts: [], error: "FFmpeg not found" };
|
|
309678
309924
|
}
|
|
309679
309925
|
const absPath = resolve71(process.cwd(), options.video);
|
|
309680
|
-
if (!
|
|
309926
|
+
if (!existsSync82(absPath)) {
|
|
309681
309927
|
return { success: false, shorts: [], error: `File not found: ${absPath}` };
|
|
309682
309928
|
}
|
|
309683
309929
|
const targetDuration = options.duration ?? 60;
|
|
@@ -309690,7 +309936,7 @@ async function executeAutoShorts(options) {
|
|
|
309690
309936
|
}
|
|
309691
309937
|
const gemini = new GeminiProvider();
|
|
309692
309938
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
309693
|
-
const videoBuffer = await
|
|
309939
|
+
const videoBuffer = await readFile40(absPath);
|
|
309694
309940
|
const geminiPrompt = `Analyze this video to find the BEST moments for short-form vertical video content (TikTok, YouTube Shorts, Instagram Reels).
|
|
309695
309941
|
|
|
309696
309942
|
Find ${shortCount * 3} potential clips that are ${targetDuration} seconds or shorter each.
|
|
@@ -309767,7 +310013,7 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
309767
310013
|
await execSafe("ffmpeg", ["-i", absPath, "-vn", "-acodec", "libmp3lame", "-q:a", "2", tempAudio, "-y"]);
|
|
309768
310014
|
const whisper = new WhisperProvider();
|
|
309769
310015
|
await whisper.initialize({ apiKey: openaiApiKey });
|
|
309770
|
-
const audioBuffer = await
|
|
310016
|
+
const audioBuffer = await readFile40(tempAudio);
|
|
309771
310017
|
const audioBlob = new Blob([audioBuffer]);
|
|
309772
310018
|
const transcript = await whisper.transcribe(audioBlob, options.language);
|
|
309773
310019
|
try {
|
|
@@ -309805,8 +310051,8 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
309805
310051
|
};
|
|
309806
310052
|
}
|
|
309807
310053
|
const outputDir = options.outputDir ? resolve71(process.cwd(), options.outputDir) : dirname39(absPath);
|
|
309808
|
-
if (options.outputDir && !
|
|
309809
|
-
await
|
|
310054
|
+
if (options.outputDir && !existsSync82(outputDir)) {
|
|
310055
|
+
await mkdir27(outputDir, { recursive: true });
|
|
309810
310056
|
}
|
|
309811
310057
|
const result = {
|
|
309812
310058
|
success: true,
|
|
@@ -309882,10 +310128,10 @@ Analyze both VISUALS (expressions, actions, scene changes) and AUDIO (speech, re
|
|
|
309882
310128
|
}
|
|
309883
310129
|
|
|
309884
310130
|
// ../cli/src/pipeline/executor.ts
|
|
309885
|
-
var
|
|
310131
|
+
var import_yaml8 = __toESM(require_dist3(), 1);
|
|
309886
310132
|
import { resolve as resolve74 } from "node:path";
|
|
309887
|
-
import { readFile as
|
|
309888
|
-
import { existsSync as
|
|
310133
|
+
import { readFile as readFile42, writeFile as writeFile45, mkdir as mkdir28 } from "node:fs/promises";
|
|
310134
|
+
import { existsSync as existsSync83 } from "node:fs";
|
|
309889
310135
|
|
|
309890
310136
|
// ../cli/src/pipeline/resolver.ts
|
|
309891
310137
|
function resolveStepParams(params, completedSteps) {
|
|
@@ -310275,11 +310521,11 @@ async function ensureActionsRegistered() {
|
|
|
310275
310521
|
}
|
|
310276
310522
|
async function loadPipeline(filePath) {
|
|
310277
310523
|
const absPath = resolve74(process.cwd(), filePath);
|
|
310278
|
-
if (!
|
|
310524
|
+
if (!existsSync83(absPath)) {
|
|
310279
310525
|
throw new Error(`Pipeline file not found: ${absPath}`);
|
|
310280
310526
|
}
|
|
310281
|
-
const content = await
|
|
310282
|
-
const manifest2 = (0,
|
|
310527
|
+
const content = await readFile42(absPath, "utf-8");
|
|
310528
|
+
const manifest2 = (0, import_yaml8.parse)(content);
|
|
310283
310529
|
if (!manifest2.name) throw new Error("Pipeline missing 'name' field");
|
|
310284
310530
|
if (!manifest2.steps || !Array.isArray(manifest2.steps)) throw new Error("Pipeline missing 'steps' array");
|
|
310285
310531
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -310295,15 +310541,15 @@ var CHECKPOINT_FILE = ".pipeline-state.yaml";
|
|
|
310295
310541
|
async function executePipeline(manifest2, options = {}) {
|
|
310296
310542
|
await ensureActionsRegistered();
|
|
310297
310543
|
const outputDir = resolve74(process.cwd(), options.outputDir || `${manifest2.name}-output`);
|
|
310298
|
-
await
|
|
310544
|
+
await mkdir28(outputDir, { recursive: true });
|
|
310299
310545
|
const completedSteps = /* @__PURE__ */ new Map();
|
|
310300
310546
|
const results = [];
|
|
310301
310547
|
const startTime = Date.now();
|
|
310302
310548
|
if (options.resume) {
|
|
310303
310549
|
const checkpointPath = resolve74(outputDir, CHECKPOINT_FILE);
|
|
310304
|
-
if (
|
|
310305
|
-
const checkpointContent = await
|
|
310306
|
-
const checkpoint = (0,
|
|
310550
|
+
if (existsSync83(checkpointPath)) {
|
|
310551
|
+
const checkpointContent = await readFile42(checkpointPath, "utf-8");
|
|
310552
|
+
const checkpoint = (0, import_yaml8.parse)(checkpointContent);
|
|
310307
310553
|
for (const cs of checkpoint.completedSteps) {
|
|
310308
310554
|
completedSteps.set(cs.id, {
|
|
310309
310555
|
id: cs.id,
|
|
@@ -310420,9 +310666,9 @@ async function executePipeline(manifest2, options = {}) {
|
|
|
310420
310666
|
data: s2.data
|
|
310421
310667
|
}))
|
|
310422
310668
|
};
|
|
310423
|
-
await
|
|
310669
|
+
await writeFile45(
|
|
310424
310670
|
resolve74(outputDir, CHECKPOINT_FILE),
|
|
310425
|
-
(0,
|
|
310671
|
+
(0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
|
|
310426
310672
|
"utf-8"
|
|
310427
310673
|
);
|
|
310428
310674
|
} else {
|
|
@@ -310575,7 +310821,7 @@ var pipelineRunTool = defineTool({
|
|
|
310575
310821
|
let tempPath;
|
|
310576
310822
|
if (args.pipelineYaml) {
|
|
310577
310823
|
tempPath = join75(tmpdir12(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
|
|
310578
|
-
await
|
|
310824
|
+
await writeFile46(tempPath, args.pipelineYaml, "utf-8");
|
|
310579
310825
|
resolvedPath = tempPath;
|
|
310580
310826
|
}
|
|
310581
310827
|
try {
|
|
@@ -310712,7 +310958,7 @@ var detectTools = [
|
|
|
310712
310958
|
|
|
310713
310959
|
// ../cli/src/tools/manifest/timeline.ts
|
|
310714
310960
|
import { z as z13 } from "zod";
|
|
310715
|
-
import { mkdir as
|
|
310961
|
+
import { mkdir as mkdir29, writeFile as writeFile48 } from "node:fs/promises";
|
|
310716
310962
|
import { basename as basename21, resolve as resolve75 } from "node:path";
|
|
310717
310963
|
init_engine();
|
|
310718
310964
|
init_project_resolver();
|
|
@@ -310720,15 +310966,15 @@ init_project_resolver();
|
|
|
310720
310966
|
// ../cli/src/tools/manifest/_project-io.ts
|
|
310721
310967
|
init_engine();
|
|
310722
310968
|
init_project_resolver();
|
|
310723
|
-
import { readFile as
|
|
310969
|
+
import { readFile as readFile43, writeFile as writeFile47 } from "node:fs/promises";
|
|
310724
310970
|
async function loadProject(projectPath, cwd) {
|
|
310725
310971
|
const absPath = await resolveTimelineFile(projectPath, cwd);
|
|
310726
|
-
const content = await
|
|
310972
|
+
const content = await readFile43(absPath, "utf-8");
|
|
310727
310973
|
const data2 = JSON.parse(content);
|
|
310728
310974
|
return { project: Project.fromJSON(data2), absPath };
|
|
310729
310975
|
}
|
|
310730
310976
|
async function saveProject(absPath, project) {
|
|
310731
|
-
await
|
|
310977
|
+
await writeFile47(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
310732
310978
|
}
|
|
310733
310979
|
|
|
310734
310980
|
// ../cli/src/tools/manifest/timeline.ts
|
|
@@ -310768,10 +311014,10 @@ var timelineCreateTool = defineTool({
|
|
|
310768
311014
|
outputPath = resolve75(ctx.workingDirectory, args.outputPath);
|
|
310769
311015
|
} else {
|
|
310770
311016
|
const dirPath = resolve75(ctx.workingDirectory, args.name);
|
|
310771
|
-
await
|
|
311017
|
+
await mkdir29(dirPath, { recursive: true });
|
|
310772
311018
|
outputPath = resolve75(dirPath, TIMELINE_FILENAME);
|
|
310773
311019
|
}
|
|
310774
|
-
await
|
|
311020
|
+
await writeFile48(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
310775
311021
|
return {
|
|
310776
311022
|
success: true,
|
|
310777
311023
|
data: { name: projectName, outputPath },
|
|
@@ -311069,17 +311315,18 @@ var timelineTools = [
|
|
|
311069
311315
|
// ../cli/src/tools/manifest/project.ts
|
|
311070
311316
|
import { z as z14 } from "zod";
|
|
311071
311317
|
import { resolve as resolve77 } from "node:path";
|
|
311072
|
-
import { writeFile as
|
|
311318
|
+
import { writeFile as writeFile49 } from "node:fs/promises";
|
|
311073
311319
|
init_engine();
|
|
311074
311320
|
|
|
311075
311321
|
// ../cli/src/commands/_shared/project-list.ts
|
|
311076
311322
|
init_storyboard_parse();
|
|
311077
|
-
|
|
311078
|
-
import {
|
|
311323
|
+
init_storyboard_source();
|
|
311324
|
+
import { readdir as readdir10, readFile as readFile44, stat as stat9 } from "node:fs/promises";
|
|
311325
|
+
import { existsSync as existsSync84 } from "node:fs";
|
|
311079
311326
|
import { join as join76, resolve as resolve76 } from "node:path";
|
|
311080
311327
|
async function executeProjectList(opts = {}) {
|
|
311081
311328
|
const workspaceDir = resolve76(opts.workspaceDir ?? ".");
|
|
311082
|
-
if (!
|
|
311329
|
+
if (!existsSync84(workspaceDir)) {
|
|
311083
311330
|
return {
|
|
311084
311331
|
success: false,
|
|
311085
311332
|
workspaceDir,
|
|
@@ -311088,7 +311335,7 @@ async function executeProjectList(opts = {}) {
|
|
|
311088
311335
|
error: `Workspace directory not found: ${workspaceDir}`
|
|
311089
311336
|
};
|
|
311090
311337
|
}
|
|
311091
|
-
const entries2 = await
|
|
311338
|
+
const entries2 = await readdir10(workspaceDir, { withFileTypes: true });
|
|
311092
311339
|
const projects = [];
|
|
311093
311340
|
let archivedCount = 0;
|
|
311094
311341
|
for (const entry of entries2) {
|
|
@@ -311100,7 +311347,7 @@ async function executeProjectList(opts = {}) {
|
|
|
311100
311347
|
continue;
|
|
311101
311348
|
}
|
|
311102
311349
|
const projectDir = join76(workspaceDir, entry.name);
|
|
311103
|
-
if (!
|
|
311350
|
+
if (!existsSync84(join76(projectDir, "STORYBOARD.md"))) continue;
|
|
311104
311351
|
projects.push(await describeProject(entry.name, projectDir));
|
|
311105
311352
|
}
|
|
311106
311353
|
projects.sort((a4, b4) => b4.updatedAt.localeCompare(a4.updatedAt));
|
|
@@ -311108,9 +311355,9 @@ async function executeProjectList(opts = {}) {
|
|
|
311108
311355
|
}
|
|
311109
311356
|
async function countProjects(dir) {
|
|
311110
311357
|
try {
|
|
311111
|
-
const entries2 = await
|
|
311358
|
+
const entries2 = await readdir10(dir, { withFileTypes: true });
|
|
311112
311359
|
return entries2.filter(
|
|
311113
|
-
(e2) => e2.isDirectory() &&
|
|
311360
|
+
(e2) => e2.isDirectory() && existsSync84(join76(dir, e2.name, "STORYBOARD.md"))
|
|
311114
311361
|
).length;
|
|
311115
311362
|
} catch {
|
|
311116
311363
|
return 0;
|
|
@@ -311122,7 +311369,7 @@ async function describeProject(name, projectDir) {
|
|
|
311122
311369
|
const timestamps = [];
|
|
311123
311370
|
try {
|
|
311124
311371
|
const storyboardPath = join76(projectDir, "STORYBOARD.md");
|
|
311125
|
-
const parsed = parseStoryboard(await
|
|
311372
|
+
const parsed = parseStoryboard(await loadStoryboardMarkdown(projectDir));
|
|
311126
311373
|
beats = parsed.beats.length;
|
|
311127
311374
|
storyboardDurationSec = Number(
|
|
311128
311375
|
parsed.beats.reduce((sum, beat) => sum + (beat.duration ?? 0), 0).toFixed(2)
|
|
@@ -311134,7 +311381,7 @@ async function describeProject(name, projectDir) {
|
|
|
311134
311381
|
let buildUpdatedAt;
|
|
311135
311382
|
try {
|
|
311136
311383
|
const reportPath = join76(projectDir, "build-report.json");
|
|
311137
|
-
const report = JSON.parse(await
|
|
311384
|
+
const report = JSON.parse(await readFile44(reportPath, "utf-8"));
|
|
311138
311385
|
buildStatus = report.status ?? report.phase;
|
|
311139
311386
|
buildUpdatedAt = report.updatedAt;
|
|
311140
311387
|
timestamps.push((await stat9(reportPath)).mtimeMs);
|
|
@@ -311143,7 +311390,7 @@ async function describeProject(name, projectDir) {
|
|
|
311143
311390
|
let latestRender;
|
|
311144
311391
|
try {
|
|
311145
311392
|
const rendersDir = join76(projectDir, "renders");
|
|
311146
|
-
const files = await
|
|
311393
|
+
const files = await readdir10(rendersDir);
|
|
311147
311394
|
let newest;
|
|
311148
311395
|
for (const file of files) {
|
|
311149
311396
|
if (!/\.(mp4|webm|mov)$/i.test(file)) continue;
|
|
@@ -311226,7 +311473,7 @@ var projectCreateTool = defineTool({
|
|
|
311226
311473
|
const outputPath = resolve77(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
|
|
311227
311474
|
const project = new Project(args.name);
|
|
311228
311475
|
if (args.fps) project.setFrameRate(args.fps);
|
|
311229
|
-
await
|
|
311476
|
+
await writeFile49(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
311230
311477
|
return {
|
|
311231
311478
|
success: true,
|
|
311232
311479
|
data: { name: args.name, outputPath },
|
|
@@ -311277,7 +311524,7 @@ import { resolve as resolve79 } from "node:path";
|
|
|
311277
311524
|
init_engine();
|
|
311278
311525
|
init_exec_safe();
|
|
311279
311526
|
init_project_resolver();
|
|
311280
|
-
import { readFile as
|
|
311527
|
+
import { readFile as readFile45, access as access6 } from "node:fs/promises";
|
|
311281
311528
|
import { resolve as resolve78 } from "node:path";
|
|
311282
311529
|
import { spawn as spawn9 } from "node:child_process";
|
|
311283
311530
|
async function getMediaDuration(filePath, mediaType, defaultImageDuration = 5) {
|
|
@@ -311348,7 +311595,7 @@ async function runExport(projectPath, outputPath, options = {}) {
|
|
|
311348
311595
|
};
|
|
311349
311596
|
}
|
|
311350
311597
|
const filePath = await resolveTimelineFile(projectPath);
|
|
311351
|
-
const content = await
|
|
311598
|
+
const content = await readFile45(filePath, "utf-8");
|
|
311352
311599
|
const data2 = JSON.parse(content);
|
|
311353
311600
|
const project = Project.fromJSON(data2);
|
|
311354
311601
|
const summary = project.getSummary();
|
|
@@ -311947,7 +312194,7 @@ var exportVideoTool = defineTool({
|
|
|
311947
312194
|
var exportTools = [exportVideoTool];
|
|
311948
312195
|
|
|
311949
312196
|
// ../cli/src/tools/manifest/agent-only.ts
|
|
311950
|
-
import { readFile as
|
|
312197
|
+
import { readFile as readFile46, writeFile as writeFile50, readdir as readdir11, stat as stat10, access as access7, unlink as unlink5 } from "node:fs/promises";
|
|
311951
312198
|
import { resolve as resolve80, join as join77, basename as basename23, extname as extname19 } from "node:path";
|
|
311952
312199
|
import { z as z16 } from "zod";
|
|
311953
312200
|
init_engine();
|
|
@@ -312023,7 +312270,7 @@ var fsListTool = defineTool({
|
|
|
312023
312270
|
const dirPath = args.path ?? ".";
|
|
312024
312271
|
try {
|
|
312025
312272
|
const absPath = resolve80(ctx.workingDirectory, dirPath);
|
|
312026
|
-
const entries2 = await
|
|
312273
|
+
const entries2 = await readdir11(absPath, { withFileTypes: true });
|
|
312027
312274
|
const results = [];
|
|
312028
312275
|
for (const entry of entries2) {
|
|
312029
312276
|
if (args.pattern && !matchPattern(entry.name, args.pattern)) continue;
|
|
@@ -312056,7 +312303,7 @@ var fsReadTool = defineTool({
|
|
|
312056
312303
|
async execute(args, ctx) {
|
|
312057
312304
|
try {
|
|
312058
312305
|
const absPath = resolve80(ctx.workingDirectory, args.path);
|
|
312059
|
-
const content = await
|
|
312306
|
+
const content = await readFile46(absPath, "utf-8");
|
|
312060
312307
|
const maxLength = 4e3;
|
|
312061
312308
|
const truncated = content.length > maxLength;
|
|
312062
312309
|
const output3 = truncated ? content.substring(0, maxLength) + "\n... (truncated)" : content;
|
|
@@ -312081,7 +312328,7 @@ var fsWriteTool = defineTool({
|
|
|
312081
312328
|
async execute(args, ctx) {
|
|
312082
312329
|
try {
|
|
312083
312330
|
const absPath = resolve80(ctx.workingDirectory, args.path);
|
|
312084
|
-
await
|
|
312331
|
+
await writeFile50(absPath, args.content, "utf-8");
|
|
312085
312332
|
return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
|
|
312086
312333
|
} catch (error) {
|
|
312087
312334
|
return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -312129,7 +312376,7 @@ var batchImportTool = defineTool({
|
|
|
312129
312376
|
async execute(args, ctx) {
|
|
312130
312377
|
try {
|
|
312131
312378
|
const filePath = resolve80(ctx.workingDirectory, args.project);
|
|
312132
|
-
const content = await
|
|
312379
|
+
const content = await readFile46(filePath, "utf-8");
|
|
312133
312380
|
const data2 = JSON.parse(content);
|
|
312134
312381
|
const project = Project.fromJSON(data2);
|
|
312135
312382
|
const dirPath = resolve80(ctx.workingDirectory, args.directory);
|
|
@@ -312138,7 +312385,7 @@ var batchImportTool = defineTool({
|
|
|
312138
312385
|
const recursive = args.recursive ?? false;
|
|
312139
312386
|
const mediaFiles = [];
|
|
312140
312387
|
const scanDir = async (dir) => {
|
|
312141
|
-
const entries2 = await
|
|
312388
|
+
const entries2 = await readdir11(dir, { withFileTypes: true });
|
|
312142
312389
|
for (const entry of entries2) {
|
|
312143
312390
|
const entryPath = join77(dir, entry.name);
|
|
312144
312391
|
if (entry.isDirectory() && recursive) {
|
|
@@ -312167,7 +312414,7 @@ var batchImportTool = defineTool({
|
|
|
312167
312414
|
const source3 = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
|
|
312168
312415
|
addedSources.push({ id: source3.id, name: mediaName, type: mediaType });
|
|
312169
312416
|
}
|
|
312170
|
-
await
|
|
312417
|
+
await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
312171
312418
|
return {
|
|
312172
312419
|
success: true,
|
|
312173
312420
|
data: { count: addedSources.length, sources: addedSources },
|
|
@@ -312201,7 +312448,7 @@ var batchConcatTool = defineTool({
|
|
|
312201
312448
|
async execute(args, ctx) {
|
|
312202
312449
|
try {
|
|
312203
312450
|
const filePath = resolve80(ctx.workingDirectory, args.project);
|
|
312204
|
-
const content = await
|
|
312451
|
+
const content = await readFile46(filePath, "utf-8");
|
|
312205
312452
|
const data2 = JSON.parse(content);
|
|
312206
312453
|
const project = Project.fromJSON(data2);
|
|
312207
312454
|
const sourceIds = args.sourceIds ?? [];
|
|
@@ -312237,7 +312484,7 @@ var batchConcatTool = defineTool({
|
|
|
312237
312484
|
createdClips.push({ id: clip.id, sourceName: source3.name, startTime: currentTime, duration: source3.duration });
|
|
312238
312485
|
currentTime += source3.duration + gap;
|
|
312239
312486
|
}
|
|
312240
|
-
await
|
|
312487
|
+
await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
312241
312488
|
const totalDuration = currentTime - gap - startTime;
|
|
312242
312489
|
return {
|
|
312243
312490
|
success: true,
|
|
@@ -312272,7 +312519,7 @@ var batchApplyEffectTool = defineTool({
|
|
|
312272
312519
|
async execute(args, ctx) {
|
|
312273
312520
|
try {
|
|
312274
312521
|
const filePath = resolve80(ctx.workingDirectory, args.project);
|
|
312275
|
-
const content = await
|
|
312522
|
+
const content = await readFile46(filePath, "utf-8");
|
|
312276
312523
|
const data2 = JSON.parse(content);
|
|
312277
312524
|
const project = Project.fromJSON(data2);
|
|
312278
312525
|
const clipIds = args.clipIds ?? [];
|
|
@@ -312300,7 +312547,7 @@ var batchApplyEffectTool = defineTool({
|
|
|
312300
312547
|
});
|
|
312301
312548
|
if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
|
|
312302
312549
|
}
|
|
312303
|
-
await
|
|
312550
|
+
await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
312304
312551
|
return {
|
|
312305
312552
|
success: true,
|
|
312306
312553
|
data: { applied: appliedEffects.length, effectType: args.effectType },
|
|
@@ -312327,7 +312574,7 @@ var timelineClearTool = defineTool({
|
|
|
312327
312574
|
async execute(args, ctx) {
|
|
312328
312575
|
try {
|
|
312329
312576
|
const filePath = await resolveTimelineFile(args.project, ctx.workingDirectory);
|
|
312330
|
-
const content = await
|
|
312577
|
+
const content = await readFile46(filePath, "utf-8");
|
|
312331
312578
|
const data2 = JSON.parse(content);
|
|
312332
312579
|
const project = Project.fromJSON(data2);
|
|
312333
312580
|
const what = args.what ?? "clips";
|
|
@@ -312369,7 +312616,7 @@ var timelineClearTool = defineTool({
|
|
|
312369
312616
|
removed.sources++;
|
|
312370
312617
|
}
|
|
312371
312618
|
}
|
|
312372
|
-
await
|
|
312619
|
+
await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
312373
312620
|
const parts = [];
|
|
312374
312621
|
if (removed.clips > 0) parts.push(`${removed.clips} clips`);
|
|
312375
312622
|
if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
|
|
@@ -312404,7 +312651,7 @@ var projectSetTool = defineTool({
|
|
|
312404
312651
|
async execute(args, ctx) {
|
|
312405
312652
|
try {
|
|
312406
312653
|
const filePath = await resolveTimelineFile(args.projectPath, ctx.workingDirectory);
|
|
312407
|
-
const content = await
|
|
312654
|
+
const content = await readFile46(filePath, "utf-8");
|
|
312408
312655
|
const data2 = JSON.parse(content);
|
|
312409
312656
|
const project = Project.fromJSON(data2);
|
|
312410
312657
|
const updates = [];
|
|
@@ -312420,7 +312667,7 @@ var projectSetTool = defineTool({
|
|
|
312420
312667
|
project.setFrameRate(args.fps);
|
|
312421
312668
|
updates.push(`Frame Rate: ${args.fps} fps`);
|
|
312422
312669
|
}
|
|
312423
|
-
await
|
|
312670
|
+
await writeFile50(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
|
|
312424
312671
|
return {
|
|
312425
312672
|
success: true,
|
|
312426
312673
|
data: { updates },
|
|
@@ -312678,8 +312925,8 @@ var mediaCompressTool = defineTool({
|
|
|
312678
312925
|
],
|
|
312679
312926
|
{ maxBuffer: 50 * 1024 * 1024 }
|
|
312680
312927
|
);
|
|
312681
|
-
const inputBuf = await
|
|
312682
|
-
const outputBuf = await
|
|
312928
|
+
const inputBuf = await readFile46(absInput);
|
|
312929
|
+
const outputBuf = await readFile46(outputPath);
|
|
312683
312930
|
const inputSize = inputBuf.length;
|
|
312684
312931
|
const outputSize = outputBuf.length;
|
|
312685
312932
|
const reduction = (inputSize - outputSize) / inputSize * 100;
|
|
@@ -312790,7 +313037,7 @@ var mediaConcatTool = defineTool({
|
|
|
312790
313037
|
} else {
|
|
312791
313038
|
const tempList = resolve80(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
|
|
312792
313039
|
const listContent = args.inputs.map((i3) => `file '${resolve80(ctx.workingDirectory, i3)}'`).join("\n");
|
|
312793
|
-
await
|
|
313040
|
+
await writeFile50(tempList, listContent, "utf-8");
|
|
312794
313041
|
try {
|
|
312795
313042
|
await execSafe(
|
|
312796
313043
|
"ffmpeg",
|
|
@@ -313703,7 +313950,7 @@ async function handleToolCall(name, args, extra) {
|
|
|
313703
313950
|
|
|
313704
313951
|
// src/resources/index.ts
|
|
313705
313952
|
init_engine();
|
|
313706
|
-
import { readFile as
|
|
313953
|
+
import { readFile as readFile47 } from "node:fs/promises";
|
|
313707
313954
|
import { resolve as resolve83 } from "node:path";
|
|
313708
313955
|
var resources = [
|
|
313709
313956
|
{
|
|
@@ -313740,7 +313987,7 @@ var resources = [
|
|
|
313740
313987
|
var currentProjectPath = process.env.VIBE_PROJECT_PATH || null;
|
|
313741
313988
|
async function loadProject2(projectPath) {
|
|
313742
313989
|
const absPath = resolve83(process.cwd(), projectPath);
|
|
313743
|
-
const content = await
|
|
313990
|
+
const content = await readFile47(absPath, "utf-8");
|
|
313744
313991
|
const data2 = JSON.parse(content);
|
|
313745
313992
|
return Project.fromJSON(data2);
|
|
313746
313993
|
}
|
|
@@ -314132,14 +314379,14 @@ This creates a music video-style edit where cuts happen in rhythm with the music
|
|
|
314132
314379
|
}
|
|
314133
314380
|
|
|
314134
314381
|
// src/instructions.ts
|
|
314135
|
-
import { existsSync as
|
|
314382
|
+
import { existsSync as existsSync85, mkdirSync as mkdirSync23 } from "node:fs";
|
|
314136
314383
|
import { delimiter as delimiter2, isAbsolute as isAbsolute14, resolve as resolve84 } from "node:path";
|
|
314137
314384
|
var DEFAULT_EXTRA_PATH_DIRS = process.platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin", "/opt/local/bin"] : ["/usr/local/bin"];
|
|
314138
314385
|
function ensureSystemPath(env4 = process.env, extraDirs = DEFAULT_EXTRA_PATH_DIRS) {
|
|
314139
314386
|
const current = (env4.PATH ?? "").split(delimiter2).filter(Boolean);
|
|
314140
314387
|
const added = [];
|
|
314141
314388
|
for (const dir of extraDirs) {
|
|
314142
|
-
if (!current.includes(dir) &&
|
|
314389
|
+
if (!current.includes(dir) && existsSync85(dir)) {
|
|
314143
314390
|
current.push(dir);
|
|
314144
314391
|
added.push(dir);
|
|
314145
314392
|
}
|
|
@@ -314242,7 +314489,7 @@ function handleCliFlags(argv, version2) {
|
|
|
314242
314489
|
}
|
|
314243
314490
|
|
|
314244
314491
|
// src/index.ts
|
|
314245
|
-
if (handleCliFlags(process.argv.slice(2), "0.
|
|
314492
|
+
if (handleCliFlags(process.argv.slice(2), "0.115.0")) {
|
|
314246
314493
|
process.exit(0);
|
|
314247
314494
|
}
|
|
314248
314495
|
console.log = (...args) => console.error(...args);
|
|
@@ -314255,7 +314502,7 @@ var server = new Server(
|
|
|
314255
314502
|
{
|
|
314256
314503
|
name: "vibeframe",
|
|
314257
314504
|
// Stamped with the package version by build.js at bundle time.
|
|
314258
|
-
version: "0.
|
|
314505
|
+
version: "0.115.0"
|
|
314259
314506
|
},
|
|
314260
314507
|
{
|
|
314261
314508
|
capabilities: {
|