c252f24f1d61d0efa83b883f71efa3c4123c2b6d
A replaced turn is killed but dies asynchronously, so its proc.exited fired long after the replacement was registered under the same sessionKey — and then ran the whole completion path against it: emitted "OpenCode exited with code 143", which the sidecar commits to chat_session_events so a false failure became permanent history, then deleted the replacement from `running`. That blinded the new Live panel, made the stop button a no-op and orphaned a process nothing could reach. Mark the handle before killing it, retire it silently, and identity-check the delete — a superseded turn does not own that key any more. Two leaks in the same family, found while fixing it. An early return would not have been enough: both watchdogs call finish, so the armed 10-minute hardTimer would have fired an error at whichever turn held the key by then. And handleLine had no `done` guard, so stdout still draining from the killed process was emitted under the replacement key. Reproduced before fixing. The lifecycle tests need no real opencode — RunnerConfig.bin takes a shell script that sleeps. The control test pins that an ordinary non-zero exit still reports an error, so the guard cannot overreach. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Description
No description provided
42 MiB
Languages
TypeScript
90.9%
Shell
4.7%
JavaScript
4.1%
CSS
0.2%
HTML
0.1%