From 828b75c76dc6ec9a684a9df2638618b6023a6b7f Mon Sep 17 00:00:00 2001 From: yushen Date: Tue, 24 Mar 2026 17:37:52 +0800 Subject: [PATCH] fix(daemon): resolve codex app-server deadlock after turn completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The codex backend spawns a long-running app-server process that doesn't exit after completing a turn. The lifecycle goroutine was waiting on <-readerDone which blocks on scanner.Scan() until stdout closes — but stdout never closes because the process stays alive. This caused the entire poll loop to freeze, preventing any further task processing. Fix: explicitly close stdin and cancel the context after the turn completes, which terminates the codex process and unblocks the reader. Co-Authored-By: Claude Opus 4.6 (1M context) --- server/pkg/agent/codex.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/pkg/agent/codex.go b/server/pkg/agent/codex.go index 97a67a89..a0b9376d 100644 --- a/server/pkg/agent/codex.go +++ b/server/pkg/agent/codex.go @@ -205,6 +205,12 @@ func (b *codexBackend) Execute(ctx context.Context, prompt string, opts ExecOpti b.cfg.Logger.Printf("[codex] finished pid=%d status=%s duration=%s", cmd.Process.Pid, finalStatus, duration.Round(time.Millisecond)) + // Close stdin and cancel context to signal the app-server to exit. + // Without this, the long-running codex process keeps stdout open and + // the reader goroutine blocks forever on scanner.Scan(). + stdin.Close() + cancel() + // Wait for the reader goroutine to finish so all output is accumulated. <-readerDone