Error-handling gaps (OpenCode adversarial review of PR #1)
Surfaced by an OpenCode adversarial self-review, triaged by Claude Code. These cause silent failures in teardown/logging paths.
12. session-lifecycle-hook.mjs — handleSessionEnd teardown ordering
cleanupSessionJobs and teardownServerSession run before clearServerSession. If either throws, clearServerSession never runs → stale server.json; the next SessionStart/ensureServer wastes time health-checking a dead server. Run clearServerSession in a finally, or reorder/guard each step.
13. stop-review-gate-hook.mjs — runStopReview detached grandchild survives timeout
spawnSync(..., { timeout }) runs the task subcommand, which spawns opencode serve with detached: true. On timeout, spawnSync kills the parent but the detached grandchild (separate process group) keeps running on a random port. Track and kill the grandchild, or start it in the same killable group.
14. opencode-companion.mjs — handleCancel logs to possibly-undefined job.logFile
Uses job.logFile from partial-patch upsertJob state; if never written, appendLogLine(undefined, …) silently skips, losing the interrupt/cancellation log lines. Resolve the log path defensively or assert it.
15. lib/opencode-server.mjs — subscribeEvents onOpen throw leaks reader lock
options.onOpen?.() — if the callback throws synchronously, the error propagates before the finally reader.releaseLock(), leaking the ReadableStream reader lock (and possibly the socket). Guard the onOpen call.
Ref: PR #1.
Error-handling gaps (OpenCode adversarial review of PR #1)
Surfaced by an OpenCode adversarial self-review, triaged by Claude Code. These cause silent failures in teardown/logging paths.
12.
session-lifecycle-hook.mjs—handleSessionEndteardown orderingcleanupSessionJobsandteardownServerSessionrun beforeclearServerSession. If either throws,clearServerSessionnever runs → staleserver.json; the nextSessionStart/ensureServerwastes time health-checking a dead server. RunclearServerSessionin afinally, or reorder/guard each step.13.
stop-review-gate-hook.mjs—runStopReviewdetached grandchild survives timeoutspawnSync(..., { timeout })runs thetasksubcommand, which spawnsopencode servewithdetached: true. On timeout,spawnSynckills the parent but the detached grandchild (separate process group) keeps running on a random port. Track and kill the grandchild, or start it in the same killable group.14.
opencode-companion.mjs—handleCancellogs to possibly-undefinedjob.logFileUses
job.logFilefrom partial-patchupsertJobstate; if never written,appendLogLine(undefined, …)silently skips, losing the interrupt/cancellation log lines. Resolve the log path defensively or assert it.15.
lib/opencode-server.mjs—subscribeEventsonOpenthrow leaks reader lockoptions.onOpen?.()— if the callback throws synchronously, the error propagates before thefinallyreader.releaseLock(), leaking theReadableStreamreader lock (and possibly the socket). Guard theonOpencall.Ref: PR #1.