Repository navigation
Conversation
The native PTY is only closed inside Terminal.kill(), so a process that exits on its own leaked file descriptors and threads (about +4 fds and +2 threads per PTY). Release it from the exit handler, guarded by exitAt because releasing can emit onExit again synchronously. Also simplify the timeout kill path and inline clearAllSessions.
|
Thanks for re-running the CI, @shekohex. The only red check is I don't think this change causes it. The same commit passes every check in my fork ( So it looks like a slow runner pushing that test past 500 ms, and a re-run should clear it. If it keeps showing up, I can send a separate small PR that raises that timeout instead of mixing it into this one. |
Summary
A PTY whose process exits on its own keeps its native handles open. Every exited session leaks four file descriptors and two threads, and clearing the session afterwards does not release them. This PR releases the native PTY from the exit handler.
In plain terms: when a command started through the plugin finishes by itself, the plugin used to leave some operating system resources open for it until OpenCode shut down. After many short commands those leftovers pile up. Now the plugin lets them go as soon as the command ends. Nothing changes in what users see.
Cause
bun-pty0.4.10 closes the native handle (bun_pty_close) only insideTerminal.kill(). When the child exits by itself, the read loop reports the exit but never reacheskill(), so the handle stays open.SessionLifecycleManagercalledkill()only when the plugin itself ended the process.Changes
onExitcallssession.process.kill()after it records the status, exit code, signal andexitAt.Terminal.kill()firesonExitagain synchronously, so the handler returns early whenexitAtis already set. That keeps the real exit code and a single exit callback.kill()instead of repeating its body, andclearAllSessionsloses its one-line private wrapper.Validation
Six PTYs running
true, counting/proc/self/fdand/proc/self/taskentries of the plugin process:The new test starts a real PTY (
sh -c 'exit 3'). On main it fails becausekillis never called. Here it passes with onekillcall, statusexited, exit code 3 and one exit callback. Removing theexitAtguard makes it fail with twokillcalls.bun testovertest/*.test.ts, without the live and npm-pack suites, gives 185 passing.bun run typecheck,bun run lintandbunx biome format .are clean. I did not run the Playwright e2e suite locally.Diff
Production: -8 lines (+13/-21), all in
src/plugin/pty/session-lifecycle.ts.Tests: +21 lines, one new file (
test/session-lifecycle.test.ts).