Skip to content

Commit 7133c39

Browse files
fix(cli): expose render debug mode
Adds the render --debug CLI flag, forwards it through Docker/local render paths, and captures full producer debug artifacts from pipeline start.
1 parent 4961e4e commit 7133c39

5 files changed

Lines changed: 57 additions & 8 deletions

File tree

packages/cli/src/commands/render.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,21 @@ describe("renderLocal browser GPU config", () => {
252252
expect(producerState.createdJobs[0]?.videoFrameFormat).toBe("png");
253253
});
254254

255+
it("forwards debug mode to createRenderJob", async () => {
256+
await renderLocal("/tmp/project", "/tmp/out.mp4", {
257+
fps: { num: 30, den: 1 },
258+
quality: "standard",
259+
format: "mp4",
260+
gpu: false,
261+
browserGpuMode: "software",
262+
hdrMode: "auto",
263+
quiet: true,
264+
debug: true,
265+
});
266+
267+
expect(producerState.createdJobs[0]?.debug).toBe(true);
268+
});
269+
255270
it("omits variables from createRenderJob when not provided", async () => {
256271
await renderLocal("/tmp/project", "/tmp/out.mp4", {
257272
fps: { num: 30, den: 1 },

packages/cli/src/commands/render.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,12 @@ export default defineCommand({
241241
description: "Suppress verbose output",
242242
default: false,
243243
},
244+
debug: {
245+
type: "boolean",
246+
description:
247+
"Write full render diagnostics and keep intermediate artifacts under the producer .debug directory.",
248+
default: false,
249+
},
244250
strict: {
245251
type: "boolean",
246252
description: "Fail render on lint errors",
@@ -548,6 +554,7 @@ export default defineCommand({
548554
const browserGpuArg = args["browser-gpu"];
549555
const browserGpuMode = resolveBrowserGpuForCli(useDocker, browserGpuArg);
550556
const quiet = args.quiet ?? false;
557+
const debug = args.debug ?? false;
551558
const batchJson = args.json ?? false;
552559
const effectiveQuiet = quiet || (batchPath != null && batchJson);
553560
const strictAll = args["strict-all"] ?? false;
@@ -763,6 +770,7 @@ export default defineCommand({
763770
pageNavigationTimeoutMs,
764771
protocolTimeout,
765772
playerReadyTimeout,
773+
debug,
766774
exitAfterComplete: false,
767775
throwOnError: true,
768776
skipFeedback: true,
@@ -815,6 +823,7 @@ export default defineCommand({
815823
videoBitrate,
816824
videoFrameFormat,
817825
quiet,
826+
debug,
818827
variables,
819828
entryFile,
820829
outputResolution,
@@ -840,6 +849,7 @@ export default defineCommand({
840849
videoFrameFormat,
841850
quiet,
842851
browserPath,
852+
debug,
843853
variables,
844854
entryFile,
845855
outputResolution,
@@ -876,6 +886,7 @@ interface RenderOptions {
876886
videoBitrate?: string;
877887
videoFrameFormat?: VideoFrameFormat;
878888
quiet: boolean;
889+
debug?: boolean;
879890
browserPath?: string;
880891
variables?: Record<string, unknown>;
881892
entryFile?: string;
@@ -1124,6 +1135,7 @@ async function renderDocker(
11241135
entryFile: options.entryFile,
11251136
outputResolution: options.outputResolution,
11261137
pageSideCompositing: options.pageSideCompositing,
1138+
debug: options.debug,
11271139
pageNavigationTimeoutMs: options.pageNavigationTimeoutMs,
11281140
},
11291141
});
@@ -1206,7 +1218,7 @@ export async function renderLocal(
12061218

12071219
const startTime = Date.now();
12081220
const logger = createRenderTelemetryLogger(
1209-
producer.createConsoleLogger?.("info") ?? createNoopProducerLogger(),
1221+
producer.createConsoleLogger?.(options.debug ? "debug" : "info") ?? createNoopProducerLogger(),
12101222
);
12111223

12121224
const job = producer.createRenderJob({
@@ -1233,6 +1245,7 @@ export async function renderLocal(
12331245
variables: options.variables,
12341246
entryFile: options.entryFile,
12351247
outputResolution: options.outputResolution,
1248+
debug: options.debug,
12361249
});
12371250

12381251
const onProgress = options.quiet

packages/cli/src/utils/dockerRunArgs.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ describe("buildDockerRunArgs", () => {
171171
videoBitrate: undefined,
172172
videoFrameFormat: "png",
173173
quiet: true,
174+
debug: true,
174175
entryFile: "compositions/intro.html",
175176
},
176177
});
@@ -188,6 +189,7 @@ describe("buildDockerRunArgs", () => {
188189
expect(args).toContain("--video-frame-format");
189190
expect(args).toContain("png");
190191
expect(args).toContain("--quiet");
192+
expect(args).toContain("--debug");
191193
expect(args).toContain("--gpu");
192194
expect(args).toContain("--no-browser-gpu");
193195
expect(args).toContain("--hdr");
@@ -352,6 +354,18 @@ describe("buildDockerRunArgs", () => {
352354
expect(args).toContain("--no-page-side-compositing");
353355
});
354356

357+
it("keeps Docker debug artifacts under the mounted output directory", () => {
358+
const args = buildDockerRunArgs({
359+
...FIXED_INPUT,
360+
options: { ...BASE, debug: true },
361+
});
362+
const envIdx = args.indexOf("PRODUCER_RENDERS_DIR=/output/renders");
363+
const imageIdx = args.indexOf(FIXED_INPUT.imageTag);
364+
expect(envIdx).toBeGreaterThan(-1);
365+
expect(envIdx).toBeLessThan(imageIdx);
366+
expect(args).toContain("--debug");
367+
});
368+
355369
it("omits --no-page-side-compositing when pageSideCompositing is not explicitly false", () => {
356370
const args = buildDockerRunArgs({ ...FIXED_INPUT, options: BASE });
357371
expect(args).not.toContain("--no-page-side-compositing");

packages/cli/src/utils/dockerRunArgs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export interface DockerRenderOptions {
5050
videoBitrate?: string;
5151
videoFrameFormat?: "auto" | "jpg" | "png";
5252
quiet: boolean;
53+
debug?: boolean;
5354
variables?: Record<string, unknown>;
5455
entryFile?: string;
5556
/** Output resolution preset (e.g. "landscape-4k"). Forwarded as `--resolution`. */
@@ -109,6 +110,10 @@ export function buildDockerRunArgs(input: DockerRunArgsInput): string[] {
109110
`${projectDir}:/project:ro`,
110111
"-v",
111112
`${outputDir}:/output`,
113+
// Keep debug artifacts on the mounted host output path. The producer roots
114+
// `.debug` at dirname(PRODUCER_RENDERS_DIR), so `/output/renders` maps to
115+
// `/output/.debug/<job id>` instead of a disposable container path.
116+
...(options.debug ? ["-e", "PRODUCER_RENDERS_DIR=/output/renders"] : []),
112117
imageTag,
113118
"/project",
114119
"--output",
@@ -128,6 +133,7 @@ export function buildDockerRunArgs(input: DockerRunArgsInput): string[] {
128133
? ["--video-frame-format", options.videoFrameFormat]
129134
: []),
130135
...(options.quiet ? ["--quiet"] : []),
136+
...(options.debug ? ["--debug"] : []),
131137
...(options.gpu ? ["--gpu"] : []),
132138
...(options.browserGpu ? [] : ["--no-browser-gpu"]),
133139
...(options.hdrMode === "force-hdr" ? ["--hdr"] : []),

packages/producer/src/services/renderOrchestrator.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,14 @@ export async function executeRenderJob(
914914
assertNotAborted();
915915
assertConfiguredFfmpegBinariesExist();
916916

917+
if (!existsSync(workDir)) mkdirSync(workDir, { recursive: true });
918+
919+
if (job.config.debug) {
920+
const logPath = join(workDir, "render.log");
921+
restoreLogger = installDebugLogger(logPath, log);
922+
log.info("[Render] Debug artifacts enabled", { workDir, logPath });
923+
}
924+
917925
log.info("[Render] Pipeline started", {
918926
platform: process.platform,
919927
arch: process.arch,
@@ -939,13 +947,6 @@ export async function executeRenderJob(
939947
requestedWorkers: job.config.workers ?? "auto",
940948
});
941949

942-
if (!existsSync(workDir)) mkdirSync(workDir, { recursive: true });
943-
944-
if (job.config.debug) {
945-
const logPath = join(workDir, "render.log");
946-
restoreLogger = installDebugLogger(logPath, log);
947-
}
948-
949950
const entryFile = job.config.entryFile || "index.html";
950951
let htmlPath = join(projectDir, entryFile);
951952
if (!existsSync(htmlPath)) {

0 commit comments

Comments
 (0)