You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(tools): wait for pipe readers before reaping detached bash shells (#716)
## Summary
Detaching a streaming bash command to the background — chat `ctrl+b`, or
directexec `!cmd &` — could truncate its trailing output. The
pipe-reader goroutines drain the command's `stdout`/`stderr` into the
shared shell buffer, but the live `*exec.Cmd` was handed to the
`jobs.Supervisor`, whose `shellJob.Run` called `cmd.Wait()` in a
separate goroutine with no coordination. Per `os/exec`, `Wait` closes
the pipes on process exit, so output still buffered in the pipe at exit
was lost. The `time.Sleep(20ms)` band-aid ran at detach time, unrelated
to exit time, so it never addressed the race.
## Fix
`shellJob.Run` now waits for the pipe readers to reach EOF before
`cmd.Wait()`, mirroring the already-correct foreground path (`wg.Wait()`
then `cmd.Wait()`). The wait `select`s on `ctx.Done()` so
`WindStop`/`Stop()` can't wedge if a grandchild holds the pipe open (a
detached shell has no timeout). Both detach callers thread a
readers-done channel through `DetachToBackground`.
- `internal/domain/shell.go` — `ReadersDone` on `BackgroundShell`;
widened `DetachToBackground`
- `internal/services/background_shell_service.go` — store `readersDone`
on the shell
- `internal/services/jobs/shell_job.go` — cancellable readers-done wait
before `cmd.Wait()`
- `internal/agent/tools/bash.go`, `internal/services/directexec/bash.go`
— pass the signal; drop the 20ms sleep
- regenerated `fake_background_shell_service.go`
## Testing
- Two regression tests in `shell_job_test.go`: ordering (Run parks until
the readers drain, even after the process has exited) and the
cancellable escape (`WindStop` still reaps when the readers never
signal). Confirmed the latter deadlocks without the `ctx.Done()` case.
- `task build`, `go test -race` on the affected packages, full `task
test`, and `task lint` (0 issues) — all clean.
Closes#696
0 commit comments