[PR #12718] fix(cli): handle SIGHUP to prevent orphaned processes on terminal close #14337

Open
opened 2026-02-16 18:19:08 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/12718

State: open
Merged: No


What does this PR do?

Fixes #10563, relates to #11225, #11527

When a terminal tab/window is closed, the OS sends SIGHUP to the process group. OpenCode has no SIGHUP handler, so the process ignores it and stays alive as an orphan under launchd (PPID=1), consuming memory indefinitely.

This adds SIGHUP and SIGTERM handlers to all long-running entry points:

  • index.ts: Safety net with 3s timeout fallback (covers all commands)
  • thread.ts: Graceful worker shutdown before exit (TUI mode)
  • worker.ts: Shutdown + ppid polling to detect parent death (safety net for SIGKILL)
  • attach.ts: Exit on signal (opencode attach mode)
  • serve.ts: Exit on signal (opencode serve mode)

The layered approach works like this: command-specific handlers do graceful cleanup and exit immediately, while the index.ts safety net force-exits after 3s if a command-specific handler hangs.

How did you verify your code works?

  • All 897 existing tests pass, 0 regressions
  • tsc --noEmit passes with no type errors
  • Added signal handling tests that spawn actual opencode serve, send SIGHUP/SIGTERM, and verify graceful exit (exit code 0 vs 129 without fix)
  • Manual test: start opencode, note PID, send kill -HUP <pid>, confirm process exits
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/12718 **State:** open **Merged:** No --- ### What does this PR do? Fixes #10563, relates to #11225, #11527 When a terminal tab/window is closed, the OS sends SIGHUP to the process group. OpenCode has no SIGHUP handler, so the process ignores it and stays alive as an orphan under launchd (PPID=1), consuming memory indefinitely. This adds SIGHUP and SIGTERM handlers to all long-running entry points: - **index.ts**: Safety net with 3s timeout fallback (covers all commands) - **thread.ts**: Graceful worker shutdown before exit (TUI mode) - **worker.ts**: Shutdown + ppid polling to detect parent death (safety net for SIGKILL) - **attach.ts**: Exit on signal (`opencode attach` mode) - **serve.ts**: Exit on signal (`opencode serve` mode) The layered approach works like this: command-specific handlers do graceful cleanup and exit immediately, while the index.ts safety net force-exits after 3s if a command-specific handler hangs. ### How did you verify your code works? - All 897 existing tests pass, 0 regressions - `tsc --noEmit` passes with no type errors - Added signal handling tests that spawn actual `opencode serve`, send SIGHUP/SIGTERM, and verify graceful exit (exit code 0 vs 129 without fix) - Manual test: start opencode, note PID, send `kill -HUP <pid>`, confirm process exits
yindo added the pull-request label 2026-02-16 18:19:08 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#14337