Summary
When a tracked job's worker process dies between SessionStart and SessionEnd (crash, OOM, SIGKILL, parent detached), the job record stays status: "running" for the rest of the session. buildStatusSnapshot and enrichJob in plugins/opencode/scripts/lib/job-control.mjs never probe process.kill(pid, 0) — they only read the stored status field.
Cleanup today only happens in plugins/opencode/scripts/session-lifecycle-hook.mjs:27-44, which runs on SessionEnd. During the session itself, /opencode:status and /opencode:result can display rows whose PIDs are long dead.
Repro
- Start a background task via
/opencode:rescue --background.
kill -9 the background worker PID.
/opencode:status still shows the job as running.
Suggested fix
In enrichJob (or buildStatusSnapshot), for any job.status === "running" with a job.pid, probe with process.kill(pid, 0). On ESRCH, downgrade to failed + errorMessage: "Worker process exited without updating job status." and persist via upsertJob.
Upstream reference
Derived from openai/codex-plugin-cc#164.
Summary
When a tracked job's worker process dies between
SessionStartandSessionEnd(crash, OOM, SIGKILL, parent detached), the job record staysstatus: "running"for the rest of the session.buildStatusSnapshotandenrichJobinplugins/opencode/scripts/lib/job-control.mjsnever probeprocess.kill(pid, 0)— they only read the storedstatusfield.Cleanup today only happens in
plugins/opencode/scripts/session-lifecycle-hook.mjs:27-44, which runs onSessionEnd. During the session itself,/opencode:statusand/opencode:resultcan display rows whose PIDs are long dead.Repro
/opencode:rescue --background.kill -9the background worker PID./opencode:statusstill shows the job asrunning.Suggested fix
In
enrichJob(orbuildStatusSnapshot), for anyjob.status === "running"with ajob.pid, probe withprocess.kill(pid, 0). OnESRCH, downgrade tofailed+errorMessage: "Worker process exited without updating job status."and persist viaupsertJob.Upstream reference
Derived from openai/codex-plugin-cc#164.