Fix #1452: Piped sync child leaves colorizeStderr mid-line after the send confirm, so the next diagnostic line loses its severity colour - #1461
Conversation
…rizer can trust The wizard pipes `hyp sync` so it can read the child's words, which turns off the child's own painting; the parent's colorized stderr is then the only painter left. The send confirm ends without a newline and its answer is echoed by the tty, not by that stream, so `paintChunk`'s line-start gate left the next diagnostic plain. `colorizeStderr` gains `resyncLineStart`, and the echo calls it on the chunk that follows an unterminated one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…next chunk Review finding on the fix: the resync fired only before the next stderr chunk, so the commonest path was still left broken. A decline writes `sync cancelled` on stdout, which leaves the unterminated confirm as the child's last word on the piped stderr, and the parent's `colorizeStderr` then believed it was mid-line for the rest of the process: any later diagnostic (`hyp init: ...` from dispatch's error path, say) lost its severity colour. That is #1452 again, one step further out. The two sites now share one `settleLine`, called at the top of the data handler and again on `close`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Neutral review record - PR #1461Reviewed head: The change, as read
Findings1. (low, fixed) The wrap was resynced only before the next chunk, never when the child closed - leaving the commonest path broken. A decline writes Probe against the reviewed head: child stderr Fixed in 2. (low, accepted as-is) The resync's premise is narrower than its gate. The gate is "the previous chunk lacked a newline"; the premise it stands on is "a newline the tty echoed past the wrap", which holds only when that chunk was an answered prompt. One logical line split across two Probe: Left as-is, deliberately. A grep over Non-findings, checked and cleared
CPU and memory passNo concern. Per One pre-existing allocation, named for the record and not changed here: the proxy's Checks
|
# Conflicts: # src/core/cli/wizard/sync_now.js
`child.on('error')` was the one settle path that left `midLine` set, so a
run that ends there keeps the wrap mid-confirm for every later wizard
diagnostic - #1452 again, one path further out. The comment above `close`
already claimed every settle resynced; now all three do.
Neutral review record - PR #1461 (round 2)Reviewed head: Findings1. (low, fixed) child.on('error', (err) => done({ code: null, error: err instanceof Error ? err.message : 'spawn failed' }))Round 1 established that a settle which is the run's last word on this pipe has to resync the wrap, and fixed Not reachable with today's child: Node emits Fixed in Positive verification (committed tree, not a test run): 2. (low, accepted as-is, unchanged from round 1) The resync's gate is broader than its premise. The gate is "the previous chunk did not end in Impact is cosmetic and bounded: Non-findings, checked and cleared
CPU and memory pass (repo-mandated)No concern. Per stderr chunk the change costs one boolean assignment, one Nothing allocates per line, nothing buffers, there are no loops, and nothing grows with data volume or uptime. The pre-existing One pre-existing allocation, named for the record and not changed here: both proxy Checks
New head after this round: |
Neutral triage - PR #1461The review-round cap was reached with findings open. Triage at head
|
Ship risk:
|
Feature or issue
Since PR #1448 the wizard's sync step spawns
hyp syncwith a piped stderr, which turns off the child's own painting (useColoris false on a pipe), leaving the parent'scolorizeStderras the only painter. That wrap infers the cursor from its own writes, but the child's send confirm ends without a newline and the answer, plus the newline the tty echoes beside it, never passes through the wrap. The wrap therefore still believes it is mid-question when the child's next diagnostic arrives, andpaintChunk's line-start gate leaves it plain:hyp sync: nothing was sent - the sink driver is holding every tickreached the terminal red understdio: 'inherit'and unpainted afterwards. Reverting only thesrc/half of this branch reproduces it exactly, with the new wizard test asserting the redhyp sync:prefix and receiving the bare text.Solution
colorizeStderrgains a symbol-keyed hook andstyle.jsexportsresyncLineStart(stream), which tells a wrap the terminal is back at a line start. It is a no-op on an unwrapped stream, which is every stream that was not painting anyway.runSyncChildecho loop tracks whether the chunk it last relayed ended without a newline and resyncs before writing the next one, so the diagnostic that follows an answered confirm is classified again.src/files reverted to their pre-fix content the new wizard test fails on the missing SGR prefix and the style test file fails to load; with the fix restored all 42 tests in the two files pass. Fullnpm testandnpm run typecheckshow no new failures (the two hyparquet-pin test failures and thesquirrelingtype error are present on master without this branch).Code: +37 / -5 lines
Fixes #1452