fix(dry-balance): fixed bench progress staircasing in raw-mode tty
- Anchored each redraw at column 0 and terminated rows with CRLF instead of bare LF. - Capped each line to terminal width so wrapping cannot desync the cursor-up. - Threaded stdout/stderr columns into the progress sink.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
- Fixed duplicate file entries in grouped outputs for `find`, `search`, `ast_grep`, `ast_edit`, and `lsp` diagnostics when the same path appeared multiple times
|
||||
- Fixed search, grep, and edit output rendering so repeated directory group blank-line boundaries no longer break nested path/link reconstruction
|
||||
- Fixed `omp dry-balance --bench` flooding the terminal with staircased, duplicated spinner/status lines (and an indented summary) when the tty has ONLCR/OPOST disabled (raw mode). The interactive progress region separated rows with a bare LF and repositioned with a column-preserving `\x1b[<n>A` cursor-up, both of which only land at column 0 when the terminal translates LF→CRLF; with that translation off, every 80 ms redraw cascaded down and to the right into scrollback. The live region now carriage-returns before every cleared row, terminates each row with CRLF, and caps each row to the terminal width so a wrapped line cannot desync the cursor-up from the logical line count.
|
||||
|
||||
## [15.10.0] - 2026-06-06
|
||||
|
||||
|
||||
@@ -152,6 +152,8 @@ export interface DryBalanceDependencies {
|
||||
now?: () => number;
|
||||
stdoutIsTTY?: boolean;
|
||||
stderrIsTTY?: boolean;
|
||||
stdoutColumns?: number;
|
||||
stderrColumns?: number;
|
||||
}
|
||||
|
||||
type DryBalanceAttemptResult =
|
||||
@@ -310,10 +312,11 @@ function renderBenchStatusLine(
|
||||
}
|
||||
}
|
||||
|
||||
function createBenchProgressSink(
|
||||
export function createBenchProgressSink(
|
||||
total: number,
|
||||
write: (text: string) => void,
|
||||
interactive: boolean,
|
||||
columns: number,
|
||||
): DryBalanceBenchProgressSink {
|
||||
const statuses: DryBalanceBenchProgressStatus[] = Array.from({ length: total }, () => ({ state: "waiting" }));
|
||||
if (!interactive) {
|
||||
@@ -333,13 +336,21 @@ function createBenchProgressSink(
|
||||
let frame = 0;
|
||||
let lineCount = 0;
|
||||
let timer: NodeJS.Timeout | undefined;
|
||||
const width = Number.isFinite(columns) && columns > 0 ? Math.trunc(columns) : 80;
|
||||
const render = (): void => {
|
||||
const lines = [
|
||||
chalk.bold("bench requests"),
|
||||
...statuses.map((status, index) => renderBenchStatusLine(status, index, total, frame)),
|
||||
];
|
||||
if (lineCount > 0) write(`\x1b[${lineCount}A`);
|
||||
write(`${lines.map(line => `\x1b[2K${line}`).join("\n")}\n`);
|
||||
// Anchor every redraw at column 0 and terminate each row with CRLF: a
|
||||
// bare `\n` only returns to column 0 when the tty performs ONLCR
|
||||
// translation, which is off whenever the terminal is in raw mode — there
|
||||
// the old column-preserving cursor-up staircased each frame into
|
||||
// scrollback. Cap each line to the terminal width so a wrapped row never
|
||||
// desyncs the `\x1b[<n>A` cursor-up from the logical line count.
|
||||
const move = lineCount > 0 ? `\x1b[${lineCount}A` : "";
|
||||
const body = lines.map(line => `\x1b[2K${truncateToWidth(line, width)}`).join("\r\n");
|
||||
write(`${move}\r${body}\r\n`);
|
||||
lineCount = lines.length;
|
||||
};
|
||||
render();
|
||||
@@ -792,7 +803,10 @@ export async function runDryBalanceCommand(
|
||||
const progressInteractive = command.flags.json
|
||||
? (deps.stderrIsTTY ?? process.stderr.isTTY === true)
|
||||
: (deps.stdoutIsTTY ?? process.stdout.isTTY === true);
|
||||
progress = createBenchProgressSink(targets.length, progressWrite, progressInteractive);
|
||||
const progressColumns = command.flags.json
|
||||
? (deps.stderrColumns ?? process.stderr.columns ?? 80)
|
||||
: (deps.stdoutColumns ?? process.stdout.columns ?? 80);
|
||||
progress = createBenchProgressSink(targets.length, progressWrite, progressInteractive, progressColumns);
|
||||
benchResults = await runBenchTargets(model, targets, randomSessionId, progress, streamFn, now);
|
||||
results = targets.map(target =>
|
||||
target.ok ? { ok: true, account: target.account } : { ok: false, reason: target.error },
|
||||
|
||||
Reference in New Issue
Block a user