Skip to content

fix(core): report process exit before stdio close#29476

Closed
YOMXXX wants to merge 1 commit into
anomalyco:devfrom
YOMXXX:fix/shell-exit-stuck-reader
Closed

fix(core): report process exit before stdio close#29476
YOMXXX wants to merge 1 commit into
anomalyco:devfrom
YOMXXX:fix/shell-exit-stuck-reader

Conversation

@YOMXXX
Copy link
Copy Markdown

@YOMXXX YOMXXX commented May 27, 2026

Issue for this PR

Closes #29294

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

The cross-spawn process handle used close to complete exitCode/isRunning/kill. If a command exited while a detached descendant still held the stdout pipe open, close could be delayed indefinitely and the shell tool stayed running.

This changes the process signal to complete on the child exit event, with close only kept as a fallback if it fires first. The shell tool now waits for its output reader to drain after exit, but only for a short bounded window, so normal output is preserved while inherited pipes can no longer wedge the tool forever.

How did you verify your code works?

TDD check:

  • Before the fix, PATH="$HOME/.bun/bin:$PATH" bun test test/effect/cross-spawn-spawner.test.ts -t "returns exit code before inherited stdout pipe closes" failed by timing out after 5000ms.
  • After the fix, the same regression test passed.

From packages/core:

  • PATH="$HOME/.bun/bin:$PATH" bun test test/effect/cross-spawn-spawner.test.ts - 25 pass, 0 fail
  • PATH="$HOME/.bun/bin:$PATH" bun typecheck - passed

From packages/opencode:

  • PATH="$HOME/.bun/bin:$PATH" bun test test/tool/shell.test.ts -t "returns when command exits before inherited stdout closes" - passed
  • PATH="$HOME/.bun/bin:$PATH" bun test test/tool/shell.test.ts - 24 pass, 0 fail
  • PATH="$HOME/.bun/bin:$PATH" bun typecheck - passed

From the repo root:

  • PATH="$HOME/.bun/bin:$PATH" bunx prettier --check packages/core/src/cross-spawn-spawner.ts packages/core/test/effect/cross-spawn-spawner.test.ts packages/opencode/src/tool/shell.ts packages/opencode/test/tool/shell.test.ts - passed
  • git diff --check - passed
  • PATH="$HOME/.bun/bin:$PATH" .husky/pre-push - failed in unrelated @opencode-ai/console-support typecheck because local dependencies/generated files are missing (@solidjs/*, solid-js/jsx-runtime, vite, and generated @opencode-ai/console-core/* schema modules). @opencode-ai/core:typecheck and opencode:typecheck completed before that failure.

Screenshots / recordings

Not a UI rendering change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

I found a highly related PR:

PR #29108: fix(core): resolve spawn on exit not close to avoid bg-child hang
#29108

This PR appears to be addressing the same underlying issue - preventing background child process hangs by completing on the exit event rather than waiting for close. This is directly related to the current PR #29476 which also changes process signal completion from close to exit.

The other results (PRs #29378, #29340) are related to stdio flushing/draining but address different contexts (export/CLI exit) rather than the core spawn behavior.

@YOMXXX
Copy link
Copy Markdown
Author

YOMXXX commented May 27, 2026

Verified against #29108 in an isolated worktree: it covers the same root cause and the full shell tool test suite passes there. Closing this duplicate to avoid splitting review across two PRs.\n\nThe only extra coverage I had here was a core-level regression for handle.exitCode resolving before inherited stdout closes; maintainers can lift that idea if useful.

@YOMXXX YOMXXX closed this May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

shell tool stays status=running indefinitely after subprocess exits — pipe FD leak in spawn

1 participant