feat(cli): add --composition flag to render specific compositions (#631)

* feat(cli): add --composition flag to render specific compositions

Expose the existing entryFile config in the producer through
a new --composition / -c CLI flag. This lets users render
individual composition files without restructuring their project:

  hyperframes render -c compositions/intro.html -o intro.mp4

The flag validates the file exists before starting the render,
threads through both local and Docker render paths, and is
documented in the CLI help, examples, and docs.

* fix(cli): address PR review — path traversal guard, forward tests, tripwire

- Add path-containment check mirroring hyperframeLint.ts: reject
  --composition paths that escape the project directory
- Normalize leading ./ from composition paths for clean render plan output
- Improve error message: suggest .html file path instead of compositions command
- Add description note about <template> sub-composition constraint
- Add render.test.ts: entryFile forwarded to createRenderJob (forward + omit)
- Update dockerRunArgs tripwire test with entryFile coverage
This commit is contained in:
Miguel Ángel
2026-05-07 01:17:39 +02:00
committed by GitHub
parent a7a6648852
commit 0e0a0e40d0
5 changed files with 94 additions and 4 deletions
@@ -161,6 +161,7 @@ describe("buildDockerRunArgs", () => {
crf: 16,
videoBitrate: undefined,
quiet: true,
entryFile: "compositions/intro.html",
},
});
// Each value must reach the container exactly once. If a future option
@@ -176,6 +177,8 @@ describe("buildDockerRunArgs", () => {
expect(args).toContain("--gpu");
expect(args).toContain("--no-browser-gpu");
expect(args).toContain("--hdr");
expect(args).toContain("--composition");
expect(args).toContain("compositions/intro.html");
});
it("forwards --video-bitrate to the container when set", () => {
@@ -210,4 +213,19 @@ describe("buildDockerRunArgs", () => {
});
expect(args).not.toContain("--variables");
});
it("forwards --composition to the container when entryFile is set", () => {
const args = buildDockerRunArgs({
...FIXED_INPUT,
options: { ...BASE, entryFile: "compositions/intro.html" },
});
const idx = args.indexOf("--composition");
expect(idx).toBeGreaterThan(-1);
expect(args[idx + 1]).toBe("compositions/intro.html");
});
it("omits --composition when entryFile is not set", () => {
const args = buildDockerRunArgs({ ...FIXED_INPUT, options: BASE });
expect(args).not.toContain("--composition");
});
});