From 0b2576b6bb6989375ff98a723529ec17e5ce5f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Sun, 29 Mar 2026 11:02:23 +0000 Subject: [PATCH] fix(cli): suppress ANSI escape codes in non-TTY progress output renderProgress() was writing \r\x1b[2K escape codes even when stdout is not a TTY, corrupting output for CI pipelines and AI agents. Now writes clean text lines at 10% intervals when not a TTY. Reproducer: cd my-video npx hyperframes render --output out.mp4 2>&1 | cat # Output contained raw escape codes: \x1b[2K --- packages/cli/src/ui/progress.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/ui/progress.ts b/packages/cli/src/ui/progress.ts index f4aa4c3e4..02ef9bff7 100644 --- a/packages/cli/src/ui/progress.ts +++ b/packages/cli/src/ui/progress.ts @@ -2,7 +2,19 @@ import { c } from "./colors.js"; const { stdout } = process; +let lastPrintedThreshold = -1; + export function renderProgress(percent: number, stage: string, row?: number): void { + // Non-TTY: write clean lines at 10% intervals, skip bar computation entirely + if (!stdout.isTTY) { + const rounded = Math.round(percent); + if ((rounded % 10 === 0 || rounded === 100) && rounded !== lastPrintedThreshold) { + lastPrintedThreshold = rounded; + stdout.write(` ${rounded}% ${stage}\n`); + } + return; + } + const width = 25; const filled = Math.floor(percent / (100 / width)); const empty = width - filled; @@ -10,7 +22,7 @@ export function renderProgress(percent: number, stage: string, row?: number): vo const line = ` ${bar} ${c.bold(String(Math.round(percent)) + "%")} ${c.dim(stage)}`; - if (row !== undefined && stdout.isTTY) { + if (row !== undefined) { stdout.write(`\x1b[${row};1H\x1b[2K${line}`); } else { stdout.write(`\r\x1b[2K${line}`);