Repository navigation
[patch] Drop a reused handler's leftover partial line at the start of each run - #110
Merged
Merged
Conversation
A run that was cancelled or whose callback threw never reached Complete,
so LineOutputHandler kept its partial line and glued it onto the next
run's first line ("partial" + "hello" -> "partialhello"). RunAsync now
calls a new internal OutputHandler.Reset before starting the process, and
LineOutputHandler discards both buffers there.
Fixes #93
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C9H64dhbitTL25J7BebFyE
|
This was referenced Oct 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes #93
Problem
LineOutputHandlerkeeps unterminated text inoutputBuffer/errorBuffer, and onlyComplete()clears it.RunAsyncreachesComplete()only when a run succeeds. A run that was cancelled, or whose callback threw, left its partial line in the buffer, and reusing the handler glued that text onto the next run's first line. The issue's repro gives["partialhello"]instead of["hello"].Change
internal virtual void Reset()onOutputHandler, a no-op by default.RunAsynccalls it before it starts the process.LineOutputHandler.Reset()discards both buffers, including a trailing CR still waiting for a possible LF. A cancelled run's partial line isn't a real line, so it's dropped rather than delivered. The buffers are replaced rather than cleared, so a delivery still finishing from the old run can't touch the new run's buffer. That's whyoutputBuffer/errorBufferare no longerreadonly.Abandoned readers, the issue's second point: I added a regression test where an orphaned descendant keeps the cancelled run's stdout open and writes to it while the next run is going. It passes with only the
Resetchange, because disposing the cancelled run'sAsyncProcessStreamReaderalready ends that read, so the late write never reaches the handler. I tried a per-reader "abandoned" flag as well. No test failed without it, so I left it out to keep the change minimal.Tests
Three new tests in
RunCommandTests. They needshand are inconclusive on Windows, like the existing shell-dependent tests:ReusedLineOutputHandlerShouldDropTheLineACancelledRunLeftUnfinished: the issue's repro. Cancel afterprintf partialarrives, then reuse the handler forecho hello, and expecthello.ReusedLineOutputHandlerShouldDropTheLineARunWhoseCallbackThrewLeftUnfinished: same, except the first run fails because the stderr callback throws.AbandonedReaderShouldNotDeliverIntoALaterRunOnTheSameHandler: an orphan writeslateinto the cancelled run's pipe while the next run is going, and the next run still sees onlyhello.Checked locally (Linux, net10.0):
Reset()call removed, all 3 new tests fail.🤖 Generated with Claude Code
https://claude.ai/code/session_01C9H64dhbitTL25J7BebFyE
Generated by Claude Code