Commit Graph

11 Commits

Author SHA1 Message Date
MoerAI dd68f324d0 fix(background-agent): add OMO_DISABLE_PROCESS_CLEANUP env opt-out for global handlers (fixes #3856)
Currently `registerManagerForCleanup` unconditionally installs global `uncaughtException` and `unhandledRejection` listeners that call `process.exit(1)` after cleanup. For users who load the plugin but never run background-agent tasks, these handlers turn transient streaming errors (e.g. undici `UND_ERR_SOCKET` mid-stream resets from `api.githubcopilot.com`) into a full process kill — opencode dies after every flaky response.

Add an `OMO_DISABLE_PROCESS_CLEANUP` env var (accepts 1/true/yes/on, case-insensitive) that skips just the error-event registration. Signal handlers (SIGINT/SIGTERM/SIGBREAK/beforeExit/exit) remain installed so graceful shutdown of any in-flight cleanup targets still runs. This is the lowest-risk near-term mitigation suggested in the issue (option #2): users opting in pay the cost of unhandled rejections themselves, but no longer lose their session to a transient socket reset.

Verification: 6 new test cases cover env-var precedence (set/unset, truthy/falsy values), signal-handler preservation, and behavior under `uncaughtException`. All 20 tests in process-cleanup.test.ts pass. Typecheck clean. Manual QA confirms env-var detection works end-to-end.
2026-05-11 18:43:40 +09:00
YeonGyu-Kim 32fab88d68 fix(process-cleanup): add test seam to prevent process.exitCode contaminating bun runner
scheduleForcedExit() sets process.exitCode which taints the bun test runner's
own exit code for the entire suite. This caused CI to fail even though all
tests passed individually.

Fix:
- Add __disableScheduledForcedExitForTesting / __enableScheduledForcedExitForTesting
  seams to skip scheduleForcedExit() during tests
- beforeEach disables forced exit; afterEach re-enables
- The 'fallback exit timer' test explicitly re-enables to verify setTimeout/clearTimeout
- Remove process.exitCode and exitSpy assertions that required forced exit to be active
  (shutdown call counts are sufficient to verify behavior)
2026-05-05 19:04:40 +09:00
YeonGyu-Kim ad535cd29d fix(process-cleanup): isolate test and avoid checking process.exitCode directly
The test file modifies process.exitCode and emits process signals which can
leak into bun test's exit code. Add:
1. mock.module() sentinel to route to isolated batch (following abort-with-timeout.test.ts pattern)
2. Global afterAll() hook that resets process.exitCode = 0 before test runner checks it
3. Remove direct checks of process.exitCode in assertions - only check that process.exit() was called with the right code via spy

This ensures bun test exits with code 0 even after tests verify process.exit behavior.

Fixes #3792
2026-05-05 05:15:59 +09:00
YeonGyu-Kim 45452a039c Merge pull request #3731 from yizhifengye/fix/process-cleanup-infinite-loop-epipe
fix(background-agent): detach error listener before running body to s…
2026-05-05 04:24:01 +09:00
auyua9 875fffb7d1 fix(background): exit after fatal cleanup 2026-05-01 16:04:03 +08:00
yizhifengye 49c2a40251 fix(background-agent): detach error listener before running body to stop re-entrant log loop
When shutdown() itself emitted uncaughtException (e.g. EPIPE while closing
a broken pipe), the error listener re-entered itself, re-logged, re-ran
cleanup, and threw EPIPE again. The 6 s forced-exit timer could not fire
because every re-entry stalled the event loop with fresh synchronous work.

Users hit this after v3.17.5 and observed 100+ GB of log lines written to
disk within minutes, with one confirmed report of a 157 GB log file filling
the filesystem.

Detaching the listener with process.off() before running log() + handler()
breaks the loop at the first re-emit: the second event has no listener to
invoke, and the first invocation's scheduleForcedExit() proceeds normally.
2026-04-30 14:47:09 +08:00
YeonGyu-Kim aa79284dc5 fix(background-agent): reset process.exitCode to 0 between cleanup tests
CI test suite exited 1 despite 0 failing tests because process-cleanup.test.ts
assertions left process.exitCode=1 in place. The afterEach hook only reset to
originalExitCode (which starts undefined), not 0, so Bun picked up exitCode=1
on shutdown and reported the shared batch as failing.

Explicitly set process.exitCode = 0 in beforeEach and afterEach so each test
starts and ends with a clean exit state.
2026-04-18 19:57:26 +09:00
YeonGyu-Kim b9d2acdcf9 fix(background-agent): run manager cleanup on uncaughtException and unhandledRejection
Signal handlers covered SIGINT/SIGTERM/SIGBREAK/beforeExit/exit, but a
synchronous throw or a top-level rejected promise terminated the process
without letting TmuxSessionManager (or any other registered manager) run
its shutdown hook. That reliably left orphan tmux panes after an opencode
crash.

Added registration for uncaughtException and unhandledRejection that fan
out through the existing cleanupAll() path, set process.exitCode = 1,
and arm the same 6 second forced-exit guard we use for signals. Test
helpers hold process-level spies so the new tests do not leak listeners
between runs.
2026-04-18 19:32:04 +09:00
YeonGyu-Kim 7d6f47bf3d fix: resolve process-cleanup signal delay and hashline_edit tool name mismatch 2026-03-31 16:59:04 -07:00
YeonGyu-Kim d1e5bd63c1 fix: address Oracle + Cubic review feedback for background-agent refactoring
- Revert getMessageDir to original join(MESSAGE_STORAGE, sessionID) behavior
- Fix dead subagentSessions.delete by capturing previousSessionID before tryFallbackRetry
- Add .unref() to process cleanup setTimeout to prevent 6s hang on Ctrl-C
- Add missing isUnstableAgent to fallback retry input mapping
- Fix process-cleanup tests to use exit listener instead of SIGINT at index 0
- Swap test filenames in compaction-aware-message-resolver to exercise skip logic correctly
2026-02-22 12:14:26 +09:00
YeonGyu-Kim 8d66d5641a test(background-agent): add unit tests for extracted modules
Add 104 new tests across 4 test files:
- error-classifier.test.ts (80 tests): isRecord, isAbortedSessionError, getErrorText, extractErrorName, extractErrorMessage, getSessionErrorMessage
- fallback-retry-handler.test.ts (19 tests): retry logic, fallback chain, concurrency release, session abort, queue management
- process-cleanup.test.ts (7 tests): signal registration, multi-manager shutdown, cleanup on unregister
- compaction-aware-message-resolver.test.ts (13 tests): compaction agent detection, message resolution with temp dirs (pre-existing, verified)

Total background-agent tests: 161 -> 265 (104 new, 0 regressions)
2026-02-22 11:59:06 +09:00