3294128271
When a background subagent emits [ALL BACKGROUND TASKS COMPLETE], the plugin queues a parent-wake that ultimately calls dispatchInternalPrompt against the parent session. If the user submits a new prompt inside the ~250 ms post-dispatch hold window, both writes land on the same OpenCode session-storage file at the same instant. OpenCode's @parcel/watcher (which the plugin itself does not depend on, but does indirectly trigger) batches those events into a TSFN callback and dispatches them into a JS env that the renderer has just torn down because the session view re-mounted around the user's new message -> napi_fatal_error / SIGABRT on macOS arm64. Removing the plugin removes the parent-wake, which is why removing OmO eliminates the crash. Mitigation: - Before flushPendingParentWake calls dispatchInternalPrompt, inspect the parent session's message tail. If the most recent message is a user message added inside PARENT_WAKE_USER_MESSAGE_IN_PROGRESS_WINDOW_MS (default 2_000 ms), reschedule instead of dispatching. The user's own prompt will drive the model; queued notifications will be re-flushed on the next idle. - Best-effort unref() of the long-lived pending-retry and dispatched- wake bookkeeping setTimeouts. They previously pinned the host event loop and prolonged the teardown window during which the watcher race can fire. The new option userMessageInProgressWindowMs is wired through BackgroundManager via a module-level constant and is independently testable. Regression test parent-wake-user-message-race.test.ts covers: - fresh user message -> dispatch deferred - latest message is assistant -> dispatch proceeds - user message older than window -> dispatch proceeds - window=0 disables the guard This is a surface-level mitigation of the most-likely root cause from the audit; a deeper fix (singleton guard against plugin double-instantiation under @opencode-ai/plugin@local reload, dispose lifecycle for OpenCode plugin reload) is out of scope here.