storyforge 0.7.4 → 0.8.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.
|
@@ -135,11 +135,11 @@ var require_p_limit = __commonJS({
|
|
|
135
135
|
// src/bridge-poller.ts
|
|
136
136
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
137
137
|
import * as crypto from "crypto";
|
|
138
|
-
import * as
|
|
138
|
+
import * as fs11 from "fs";
|
|
139
139
|
|
|
140
140
|
// ../pipeline/src/clip-render/render-chunk.ts
|
|
141
|
-
import * as
|
|
142
|
-
import * as
|
|
141
|
+
import * as fs10 from "fs";
|
|
142
|
+
import * as path11 from "path";
|
|
143
143
|
|
|
144
144
|
// ../../node_modules/zod/v3/external.js
|
|
145
145
|
var external_exports = {};
|
|
@@ -619,8 +619,8 @@ function getErrorMap() {
|
|
|
619
619
|
|
|
620
620
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
621
621
|
var makeIssue = (params) => {
|
|
622
|
-
const { data, path:
|
|
623
|
-
const fullPath = [...
|
|
622
|
+
const { data, path: path12, errorMaps, issueData } = params;
|
|
623
|
+
const fullPath = [...path12, ...issueData.path || []];
|
|
624
624
|
const fullIssue = {
|
|
625
625
|
...issueData,
|
|
626
626
|
path: fullPath
|
|
@@ -736,11 +736,11 @@ var errorUtil;
|
|
|
736
736
|
|
|
737
737
|
// ../../node_modules/zod/v3/types.js
|
|
738
738
|
var ParseInputLazyPath = class {
|
|
739
|
-
constructor(parent, value,
|
|
739
|
+
constructor(parent, value, path12, key) {
|
|
740
740
|
this._cachedPath = [];
|
|
741
741
|
this.parent = parent;
|
|
742
742
|
this.data = value;
|
|
743
|
-
this._path =
|
|
743
|
+
this._path = path12;
|
|
744
744
|
this._key = key;
|
|
745
745
|
}
|
|
746
746
|
get path() {
|
|
@@ -5345,7 +5345,8 @@ var ENGINE_FALLBACK_CHAIN = {
|
|
|
5345
5345
|
hyperframes: "remotion",
|
|
5346
5346
|
"stock+remotion": "remotion",
|
|
5347
5347
|
manim: "remotion",
|
|
5348
|
-
remotion: null
|
|
5348
|
+
remotion: null,
|
|
5349
|
+
"documentary-v2": "gemini+remotion"
|
|
5349
5350
|
};
|
|
5350
5351
|
function nextFallback(engine) {
|
|
5351
5352
|
return ENGINE_FALLBACK_CHAIN[engine] ?? null;
|
|
@@ -6082,6 +6083,81 @@ var renderStockRemotion = async (shot, ctx) => {
|
|
|
6082
6083
|
}
|
|
6083
6084
|
};
|
|
6084
6085
|
|
|
6086
|
+
// ../pipeline/src/clip-render/engines/documentary-v2.ts
|
|
6087
|
+
import * as fs8 from "fs";
|
|
6088
|
+
import * as path9 from "path";
|
|
6089
|
+
var renderDocumentaryV2 = async (shot, ctx) => {
|
|
6090
|
+
if (ctx.signal?.aborted) throw new Error("aborted");
|
|
6091
|
+
if (!shot.prompt) {
|
|
6092
|
+
throw new Error(
|
|
6093
|
+
`documentary-v2: shot.prompt must be the path to a CompositionV2Data JSON file (shot ${shot.id})`
|
|
6094
|
+
);
|
|
6095
|
+
}
|
|
6096
|
+
ctx.progress.emit({ phase: "preparing", shotId: shot.id });
|
|
6097
|
+
let data;
|
|
6098
|
+
if (shot.prompt.trimStart().startsWith("{")) {
|
|
6099
|
+
data = JSON.parse(shot.prompt);
|
|
6100
|
+
} else {
|
|
6101
|
+
if (!fs8.existsSync(shot.prompt)) {
|
|
6102
|
+
throw new Error(`documentary-v2: CompositionV2Data file not found: ${shot.prompt}`);
|
|
6103
|
+
}
|
|
6104
|
+
data = JSON.parse(fs8.readFileSync(shot.prompt, "utf8"));
|
|
6105
|
+
}
|
|
6106
|
+
const durationFrames = data.totalDurationFrames > 0 ? data.totalDurationFrames : Math.max(1, Math.round(shot.durationSec * ctx.fps));
|
|
6107
|
+
const remotion = requireRemotionRoot();
|
|
6108
|
+
const cacheRel = path9.posix.join("clip-render-cache", ctx.chunkId);
|
|
6109
|
+
const cacheAbs = path9.join(remotion.cwd, "public", cacheRel);
|
|
6110
|
+
fs8.mkdirSync(cacheAbs, { recursive: true });
|
|
6111
|
+
for (const scene of data.scenes) {
|
|
6112
|
+
for (const layer of scene.layers) {
|
|
6113
|
+
if (!layer.assetPath) continue;
|
|
6114
|
+
if (path9.isAbsolute(layer.assetPath) && fs8.existsSync(layer.assetPath)) {
|
|
6115
|
+
const filename = path9.basename(layer.assetPath);
|
|
6116
|
+
const destAbs = path9.join(cacheAbs, filename);
|
|
6117
|
+
if (!fs8.existsSync(destAbs)) {
|
|
6118
|
+
fs8.copyFileSync(layer.assetPath, destAbs);
|
|
6119
|
+
}
|
|
6120
|
+
layer.assetPath = path9.posix.join(cacheRel, filename);
|
|
6121
|
+
}
|
|
6122
|
+
}
|
|
6123
|
+
}
|
|
6124
|
+
const propsPath = path9.join(ctx.tmpDir, "remotion", `${shot.id}_dv2_props.json`);
|
|
6125
|
+
fs8.mkdirSync(path9.dirname(propsPath), { recursive: true });
|
|
6126
|
+
fs8.writeFileSync(propsPath, JSON.stringify({ compositionData: data }, null, 2));
|
|
6127
|
+
ctx.progress.emit({
|
|
6128
|
+
phase: "rendering",
|
|
6129
|
+
shotId: shot.id,
|
|
6130
|
+
framesRendered: 0,
|
|
6131
|
+
totalFrames: durationFrames
|
|
6132
|
+
});
|
|
6133
|
+
const r = await runCmd(
|
|
6134
|
+
"npx",
|
|
6135
|
+
[
|
|
6136
|
+
"remotion",
|
|
6137
|
+
"render",
|
|
6138
|
+
remotion.entry,
|
|
6139
|
+
"DocumentaryV2",
|
|
6140
|
+
"--props",
|
|
6141
|
+
propsPath,
|
|
6142
|
+
"--output",
|
|
6143
|
+
ctx.sceneOutPath,
|
|
6144
|
+
"--concurrency",
|
|
6145
|
+
"4"
|
|
6146
|
+
],
|
|
6147
|
+
{ timeoutMs: 6e5, signal: ctx.signal, cwd: remotion.cwd }
|
|
6148
|
+
);
|
|
6149
|
+
if (r.code !== 0) {
|
|
6150
|
+
const tail = r.stderr.split("\n").slice(-8).join(" ").slice(0, 400);
|
|
6151
|
+
throw new Error(`documentary-v2 render failed (code ${r.code}): ${tail}`);
|
|
6152
|
+
}
|
|
6153
|
+
ctx.progress.emit({
|
|
6154
|
+
phase: "rendering",
|
|
6155
|
+
shotId: shot.id,
|
|
6156
|
+
framesRendered: durationFrames,
|
|
6157
|
+
totalFrames: durationFrames
|
|
6158
|
+
});
|
|
6159
|
+
};
|
|
6160
|
+
|
|
6085
6161
|
// ../pipeline/src/clip-render/engines/index.ts
|
|
6086
6162
|
var ENGINE_ADAPTERS = {
|
|
6087
6163
|
"gemini+remotion": renderGeminiRemotion,
|
|
@@ -6091,7 +6167,8 @@ var ENGINE_ADAPTERS = {
|
|
|
6091
6167
|
"remotion": renderRemotion,
|
|
6092
6168
|
"stock+remotion": renderStockRemotion,
|
|
6093
6169
|
"hyperframes": renderHyperframes,
|
|
6094
|
-
"remotion+htmlcanvas": renderRemotionHtmlCanvas
|
|
6170
|
+
"remotion+htmlcanvas": renderRemotionHtmlCanvas,
|
|
6171
|
+
"documentary-v2": renderDocumentaryV2
|
|
6095
6172
|
};
|
|
6096
6173
|
var MANIM_ENGINES = /* @__PURE__ */ new Set([
|
|
6097
6174
|
"manim",
|
|
@@ -6103,11 +6180,11 @@ function isManimEngine(engine) {
|
|
|
6103
6180
|
}
|
|
6104
6181
|
|
|
6105
6182
|
// ../pipeline/src/clip-render/fs-layout.ts
|
|
6106
|
-
import * as
|
|
6107
|
-
import * as
|
|
6183
|
+
import * as fs9 from "fs";
|
|
6184
|
+
import * as path10 from "path";
|
|
6108
6185
|
function resolveProjectRoot(projectSlug, callerOutputDir) {
|
|
6109
6186
|
if (callerOutputDir && callerOutputDir.length > 0) {
|
|
6110
|
-
if (!
|
|
6187
|
+
if (!path10.isAbsolute(callerOutputDir)) {
|
|
6111
6188
|
throw new Error(
|
|
6112
6189
|
`clip-render: spec.outputDir must be absolute, got "${callerOutputDir}"`
|
|
6113
6190
|
);
|
|
@@ -6117,41 +6194,41 @@ function resolveProjectRoot(projectSlug, callerOutputDir) {
|
|
|
6117
6194
|
if (!projectSlug || /[/\\]/.test(projectSlug)) {
|
|
6118
6195
|
throw new Error(`clip-render: invalid projectSlug "${projectSlug}"`);
|
|
6119
6196
|
}
|
|
6120
|
-
return
|
|
6197
|
+
return path10.resolve(process.cwd(), "forge-renders", projectSlug);
|
|
6121
6198
|
}
|
|
6122
6199
|
function chunkPaths(projectSlug, chunkId, callerOutputDir) {
|
|
6123
6200
|
if (!chunkId || /[/\\]/.test(chunkId)) {
|
|
6124
6201
|
throw new Error(`clip-render: invalid chunkId "${chunkId}"`);
|
|
6125
6202
|
}
|
|
6126
6203
|
const root = resolveProjectRoot(projectSlug, callerOutputDir);
|
|
6127
|
-
const tmpDir =
|
|
6204
|
+
const tmpDir = path10.join(root, ".tmp", chunkId);
|
|
6128
6205
|
return {
|
|
6129
6206
|
root,
|
|
6130
|
-
finalClipPath:
|
|
6207
|
+
finalClipPath: path10.join(root, "clips", `${chunkId}.mp4`),
|
|
6131
6208
|
tmpDir,
|
|
6132
|
-
scenesDir:
|
|
6133
|
-
manimDir:
|
|
6134
|
-
remotionDir:
|
|
6135
|
-
hyperframesDir:
|
|
6136
|
-
progressLogPath:
|
|
6209
|
+
scenesDir: path10.join(tmpDir, "scenes"),
|
|
6210
|
+
manimDir: path10.join(tmpDir, "manim"),
|
|
6211
|
+
remotionDir: path10.join(tmpDir, "remotion"),
|
|
6212
|
+
hyperframesDir: path10.join(tmpDir, "hyperframes"),
|
|
6213
|
+
progressLogPath: path10.join(root, "progress.json")
|
|
6137
6214
|
};
|
|
6138
6215
|
}
|
|
6139
6216
|
function ensureChunkDirs(paths) {
|
|
6140
6217
|
for (const dir of [
|
|
6141
|
-
|
|
6218
|
+
path10.dirname(paths.finalClipPath),
|
|
6142
6219
|
paths.tmpDir,
|
|
6143
6220
|
paths.scenesDir,
|
|
6144
6221
|
paths.manimDir,
|
|
6145
6222
|
paths.remotionDir,
|
|
6146
6223
|
paths.hyperframesDir
|
|
6147
6224
|
]) {
|
|
6148
|
-
|
|
6225
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
6149
6226
|
}
|
|
6150
6227
|
}
|
|
6151
6228
|
function appendProgress(progressLogPath, event) {
|
|
6152
6229
|
try {
|
|
6153
|
-
|
|
6154
|
-
|
|
6230
|
+
fs9.mkdirSync(path10.dirname(progressLogPath), { recursive: true });
|
|
6231
|
+
fs9.appendFileSync(progressLogPath, JSON.stringify(event) + "\n");
|
|
6155
6232
|
} catch {
|
|
6156
6233
|
}
|
|
6157
6234
|
}
|
|
@@ -6254,10 +6331,10 @@ async function renderChunk(spec, opts = {}) {
|
|
|
6254
6331
|
await renderWithEngine(spec, engine, paths, fps, tracker, opts);
|
|
6255
6332
|
tracker.emit({ phase: "compositing", percent: 85 });
|
|
6256
6333
|
const scenePaths = spec.shots.map((s) => sceneOutPath(paths, s));
|
|
6257
|
-
const concatTarget =
|
|
6334
|
+
const concatTarget = path11.join(paths.tmpDir, `${spec.chunkId}_video.mp4`);
|
|
6258
6335
|
await concatScenes(scenePaths, concatTarget, { signal: opts.signal });
|
|
6259
6336
|
if (opts.signal?.aborted) throw new Error("aborted");
|
|
6260
|
-
const audioAvailable = !!spec.audioPath &&
|
|
6337
|
+
const audioAvailable = !!spec.audioPath && fs10.existsSync(spec.audioPath);
|
|
6261
6338
|
if (audioAvailable) {
|
|
6262
6339
|
tracker.emit({ phase: "muxing", percent: 95 });
|
|
6263
6340
|
await muxAudio(concatTarget, spec.audioPath, paths.finalClipPath, {
|
|
@@ -6269,7 +6346,7 @@ async function renderChunk(spec, opts = {}) {
|
|
|
6269
6346
|
} else {
|
|
6270
6347
|
warnings.push("no audioPath in spec \u2014 wrote silent clip");
|
|
6271
6348
|
}
|
|
6272
|
-
|
|
6349
|
+
fs10.copyFileSync(concatTarget, paths.finalClipPath);
|
|
6273
6350
|
}
|
|
6274
6351
|
tracker.emit({ phase: "done", percent: 100 });
|
|
6275
6352
|
const renderTimeMs2 = (opts.now ?? Date.now)() - startedAt;
|
|
@@ -6308,7 +6385,7 @@ async function renderChunk(spec, opts = {}) {
|
|
|
6308
6385
|
};
|
|
6309
6386
|
}
|
|
6310
6387
|
function sceneOutPath(paths, shot) {
|
|
6311
|
-
return
|
|
6388
|
+
return path11.join(paths.scenesDir, `${shot.id}.mp4`);
|
|
6312
6389
|
}
|
|
6313
6390
|
function abortedResult(spec, engine, fallbackDepth, startedAt, now) {
|
|
6314
6391
|
return {
|
|
@@ -6341,7 +6418,7 @@ async function renderWithEngine(spec, engine, paths, fps, tracker, opts) {
|
|
|
6341
6418
|
progress: tracker,
|
|
6342
6419
|
resolvedEngine: engine
|
|
6343
6420
|
};
|
|
6344
|
-
|
|
6421
|
+
fs10.mkdirSync(path11.dirname(ctx.sceneOutPath), { recursive: true });
|
|
6345
6422
|
const release = opts.acquireManimSlot ? await opts.acquireManimSlot() : void 0;
|
|
6346
6423
|
try {
|
|
6347
6424
|
tracker.emit({
|
|
@@ -6353,7 +6430,7 @@ async function renderWithEngine(spec, engine, paths, fps, tracker, opts) {
|
|
|
6353
6430
|
} finally {
|
|
6354
6431
|
release?.();
|
|
6355
6432
|
}
|
|
6356
|
-
if (!
|
|
6433
|
+
if (!fs10.existsSync(ctx.sceneOutPath)) {
|
|
6357
6434
|
throw new Error(
|
|
6358
6435
|
`engine ${engine} produced no output at ${ctx.sceneOutPath} for shot ${shot.id}`
|
|
6359
6436
|
);
|
|
@@ -6537,8 +6614,8 @@ var BridgePoller = class {
|
|
|
6537
6614
|
if (!/^[a-z][a-z0-9-]*$/i.test(name)) return { available: false, path: null };
|
|
6538
6615
|
const r = spawnSync("which", [name], { encoding: "utf-8", timeout: 2e3 });
|
|
6539
6616
|
if (r.status !== 0) return { available: false, path: null };
|
|
6540
|
-
const
|
|
6541
|
-
return { available: !!
|
|
6617
|
+
const path12 = (r.stdout ?? "").trim();
|
|
6618
|
+
return { available: !!path12, path: path12 || null };
|
|
6542
6619
|
}
|
|
6543
6620
|
async heartbeat() {
|
|
6544
6621
|
if (this.stopped) return;
|
|
@@ -6759,13 +6836,36 @@ var BridgePoller = class {
|
|
|
6759
6836
|
onProgress,
|
|
6760
6837
|
signal: cancelController.signal
|
|
6761
6838
|
});
|
|
6839
|
+
const specByChunk = new Map(payload.specs.map((s) => [s.chunkId, s]));
|
|
6840
|
+
const uploadOutcomes = [];
|
|
6841
|
+
for (const r of result.results) {
|
|
6842
|
+
if (!r.ok || !r.outputPath) continue;
|
|
6843
|
+
const spec = specByChunk.get(r.chunkId);
|
|
6844
|
+
if (!spec) continue;
|
|
6845
|
+
const upload = await this.uploadClipToStorj(jobId, payload.projectId, spec, r);
|
|
6846
|
+
uploadOutcomes.push({ chunkId: r.chunkId, ...upload });
|
|
6847
|
+
void this.postRenderProgress(jobId, payload.projectId, {
|
|
6848
|
+
chunkId: r.chunkId,
|
|
6849
|
+
phase: upload.ok ? "done" : "error",
|
|
6850
|
+
percent: upload.ok ? 100 : 95,
|
|
6851
|
+
elapsedMs: r.renderTimeMs,
|
|
6852
|
+
resolvedEngine: r.engine,
|
|
6853
|
+
storjKey: upload.storjKey,
|
|
6854
|
+
outputPath: r.outputPath,
|
|
6855
|
+
error: upload.ok ? void 0 : `upload failed: ${upload.error ?? "unknown"}`,
|
|
6856
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
6857
|
+
});
|
|
6858
|
+
}
|
|
6762
6859
|
const okCount = result.results.filter((r) => r.ok).length;
|
|
6860
|
+
const uploadedCount = uploadOutcomes.filter((u) => u.ok).length;
|
|
6763
6861
|
const summary = {
|
|
6764
6862
|
kind: "render-clips",
|
|
6765
|
-
ok: result.ok,
|
|
6863
|
+
ok: result.ok && uploadedCount === okCount,
|
|
6766
6864
|
total: result.results.length,
|
|
6767
6865
|
succeeded: okCount,
|
|
6768
6866
|
failed: result.results.length - okCount,
|
|
6867
|
+
uploaded: uploadedCount,
|
|
6868
|
+
uploadFailed: uploadOutcomes.filter((u) => !u.ok).length,
|
|
6769
6869
|
totalRenderTimeMs: result.totalRenderTimeMs,
|
|
6770
6870
|
observedPeakConcurrency: result.observedPeakConcurrency
|
|
6771
6871
|
};
|
|
@@ -6776,6 +6876,48 @@ var BridgePoller = class {
|
|
|
6776
6876
|
this.renderCancelControllers.delete(jobId);
|
|
6777
6877
|
}
|
|
6778
6878
|
}
|
|
6879
|
+
/**
|
|
6880
|
+
* POST a rendered clip to /api/cli-bridge/upload-clip as multipart
|
|
6881
|
+
* form data. The endpoint uploads the binary to Storj, inserts a
|
|
6882
|
+
* `clips` table row, and returns the storj_key. Best-effort — a
|
|
6883
|
+
* failed upload is recorded as a warning and the chunk's progress
|
|
6884
|
+
* event reports phase='error' but doesn't take down the whole batch.
|
|
6885
|
+
*/
|
|
6886
|
+
async uploadClipToStorj(bridgeJobId, projectId, spec, result) {
|
|
6887
|
+
try {
|
|
6888
|
+
const fs12 = await import("fs/promises");
|
|
6889
|
+
const stat = await fs12.stat(result.outputPath);
|
|
6890
|
+
if (!stat.isFile() || stat.size === 0) {
|
|
6891
|
+
return { ok: false, error: `local clip empty or missing at ${result.outputPath}` };
|
|
6892
|
+
}
|
|
6893
|
+
const buf = await fs12.readFile(result.outputPath);
|
|
6894
|
+
const durationFrames = Math.max(1, Math.round(result.durationSec * 30));
|
|
6895
|
+
const form = new FormData();
|
|
6896
|
+
form.append("bridgeJobId", bridgeJobId);
|
|
6897
|
+
form.append("chunkId", result.chunkId);
|
|
6898
|
+
form.append("engine", result.engine);
|
|
6899
|
+
form.append("aspect", spec.aspect);
|
|
6900
|
+
form.append("durationSec", String(result.durationSec));
|
|
6901
|
+
form.append("durationFrames", String(durationFrames));
|
|
6902
|
+
form.append("file", new Blob([new Uint8Array(buf)], { type: "video/mp4" }), `${result.chunkId}.mp4`);
|
|
6903
|
+
const resp = await fetch(`${this.baseUrl}/api/cli-bridge/upload-clip`, {
|
|
6904
|
+
method: "POST",
|
|
6905
|
+
headers: { Authorization: `Bearer ${this.token}` },
|
|
6906
|
+
body: form,
|
|
6907
|
+
signal: AbortSignal.timeout(5 * 6e4)
|
|
6908
|
+
});
|
|
6909
|
+
const text = await resp.text().catch(() => "");
|
|
6910
|
+
if (!resp.ok) {
|
|
6911
|
+
return { ok: false, error: `HTTP ${resp.status}: ${text.slice(0, 300)}` };
|
|
6912
|
+
}
|
|
6913
|
+
const parsed = text ? JSON.parse(text) : {};
|
|
6914
|
+
log.info(`[bridge] uploaded ${result.chunkId.slice(0, 8)} -> ${parsed.storjKey ?? "(no key)"}`);
|
|
6915
|
+
void projectId;
|
|
6916
|
+
return { ok: true, storjKey: parsed.storjKey };
|
|
6917
|
+
} catch (err) {
|
|
6918
|
+
return { ok: false, error: err.message };
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6779
6921
|
/** POST a single RenderProgress event to /api/render-progress. */
|
|
6780
6922
|
async postRenderProgress(bridgeJobId, projectId, event) {
|
|
6781
6923
|
try {
|
|
@@ -6813,9 +6955,9 @@ var BridgePoller = class {
|
|
|
6813
6955
|
error: `stitch-final job requires @forge/pipeline/stitch (not installed): ${err.message}`
|
|
6814
6956
|
};
|
|
6815
6957
|
}
|
|
6816
|
-
const
|
|
6817
|
-
const projectRoot =
|
|
6818
|
-
const clipsDir =
|
|
6958
|
+
const path12 = await import("path");
|
|
6959
|
+
const projectRoot = path12.resolve(process.cwd(), "forge-renders", payload.projectSlug);
|
|
6960
|
+
const clipsDir = path12.join(projectRoot, "clips");
|
|
6819
6961
|
const publish = async (phase, eventPayload) => {
|
|
6820
6962
|
try {
|
|
6821
6963
|
await fetch(`${this.baseUrl}/api/cli-bridge/stitch-event`, {
|
|
@@ -6841,7 +6983,7 @@ var BridgePoller = class {
|
|
|
6841
6983
|
projectSlug: payload.projectSlug,
|
|
6842
6984
|
clipsDir,
|
|
6843
6985
|
chunkOrder: payload.chunkOrder ?? [],
|
|
6844
|
-
masterAudioPath:
|
|
6986
|
+
masterAudioPath: path12.isAbsolute(masterAudioRel) ? masterAudioRel : path12.join(projectRoot, masterAudioRel),
|
|
6845
6987
|
outputDir: projectRoot,
|
|
6846
6988
|
aspect: payload.aspect,
|
|
6847
6989
|
skipTransitions: payload.skipTransitions,
|
|
@@ -7025,10 +7167,10 @@ function collectImagesFromCodexStdout(stdout, maxCount) {
|
|
|
7025
7167
|
for (const p of paths) {
|
|
7026
7168
|
if (images.length >= maxCount) break;
|
|
7027
7169
|
try {
|
|
7028
|
-
const stat =
|
|
7170
|
+
const stat = fs11.statSync(p);
|
|
7029
7171
|
if (!stat.isFile() || stat.size <= 0) continue;
|
|
7030
7172
|
images.push({
|
|
7031
|
-
base64:
|
|
7173
|
+
base64: fs11.readFileSync(p).toString("base64"),
|
|
7032
7174
|
mimeType: mimeTypeForPath(p),
|
|
7033
7175
|
model: "codex-cli:imagegen"
|
|
7034
7176
|
});
|
package/dist/index.js
CHANGED
|
@@ -1615,7 +1615,7 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
|
|
|
1615
1615
|
return "0.0.0";
|
|
1616
1616
|
})();
|
|
1617
1617
|
void (async () => {
|
|
1618
|
-
const { BridgePoller } = await import("./bridge-poller-
|
|
1618
|
+
const { BridgePoller } = await import("./bridge-poller-HA7G7ILD.js");
|
|
1619
1619
|
const poller = new BridgePoller({ baseUrl: bridgeUrl, token: bridgeToken, clientVersion: `storyforge ${pkgVersion}` });
|
|
1620
1620
|
poller.start();
|
|
1621
1621
|
})();
|
|
@@ -1992,7 +1992,7 @@ async function installRenderersCommand(opts = {}) {
|
|
|
1992
1992
|
}
|
|
1993
1993
|
|
|
1994
1994
|
// src/index.ts
|
|
1995
|
-
var VERSION = "0.7.
|
|
1995
|
+
var VERSION = "0.7.5";
|
|
1996
1996
|
var HELP = `
|
|
1997
1997
|
storyforge \u2014 local bridge for the Forge video production web app
|
|
1998
1998
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storyforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "StoryForge — local bridge for the Forge video production web app. Parallel clip-render orchestrator (Remotion 4 + Manim + HyperFrames + ffmpeg) + final video stitcher + dependency doctor.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|