fix: keep codex redraws off pty batch path (#3992)

This commit is contained in:
Neil 2026-05-30 23:06:13 -07:00 committed by GitHub
parent 5e7d097682
commit dd1b28ba2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 1 deletions

View File

@ -3266,6 +3266,40 @@ describe('registerPtyHandlers', () => {
}
})
it('sends larger ANSI redraws immediately after terminal input', async () => {
vi.useFakeTimers()
const mockProc = createMockProc()
spawnMock.mockReturnValue(mockProc.proc)
try {
registerPtyHandlers(mainWindow as never)
const spawnResult = (await handlers.get('pty:spawn')!(null, {
cols: 80,
rows: 24,
cwd: '/tmp'
})) as { id: string }
const writeListener = getPtyWriteListener()
writeListener(null, {
id: spawnResult.id,
data: 'a'
})
mainWindow.webContents.send.mockClear()
const redraw = `\x1b[2J\x1b[H${'codex composer redraw '.repeat(80)}`
mockProc.emitData(redraw)
expect(mainWindow.webContents.send).toHaveBeenCalledWith('pty:data', {
id: spawnResult.id,
data: redraw
})
vi.advanceTimersByTime(8)
expect(mainWindow.webContents.send).toHaveBeenCalledTimes(1)
} finally {
vi.useRealTimers()
}
})
it('batches combined pending output that exceeds the interactive size limit', async () => {
vi.useFakeTimers()
const mockProc = createMockProc()

View File

@ -946,12 +946,23 @@ export function registerPtyHandlers(
// large output and non-interactive output must still use the batcher.
const INTERACTIVE_OUTPUT_WINDOW_MS = 100
const INTERACTIVE_OUTPUT_MAX_CHARS = 1024
const INTERACTIVE_REDRAW_MAX_CHARS = PTY_BATCH_FLUSH_CHUNK_CHARS
const BACKGROUND_OUTPUT_INPUT_QUIET_MS = 50
const BACKGROUND_OUTPUT_MAX_INPUT_HOLD_MS = 250
let lastRendererInputAt = Number.NEGATIVE_INFINITY
let lastRendererInputPtyId: string | null = null
let backgroundFlushHeldSince: number | null = null
function isLikelyInteractiveRedraw(data: string): boolean {
if (data.length <= INTERACTIVE_OUTPUT_MAX_CHARS) {
return true
}
// Why: Codex-style TUIs can repaint more than 1 KB per keypress. ANSI
// control redraws are still latency-sensitive, while plain command output
// should stay on the throughput batch path.
return data.length <= INTERACTIVE_REDRAW_MAX_CHARS && data.includes('\x1b[')
}
function getChunkStartSeq(endSeq: number | undefined, data: string): number | undefined {
return typeof endSeq === 'number' ? Math.max(0, endSeq - data.length) : undefined
}
@ -1176,7 +1187,7 @@ export function registerPtyHandlers(
const nextData = pending.data
const lastInputAt = lastInputAtByPty.get(payload.id)
const isInteractiveOutput =
nextData.length <= INTERACTIVE_OUTPUT_MAX_CHARS &&
isLikelyInteractiveRedraw(nextData) &&
lastInputAt !== undefined &&
performance.now() - lastInputAt <= INTERACTIVE_OUTPUT_WINDOW_MS
if (isInteractiveOutput) {