Summary
On native Windows, a running background task records pidIdentity: null. The cancel command then refuses to stop the task and marks it as cancel_failed.
Reproduction
I ran a real background task through the companion CLI on Windows, with a prompt that starts node -e "setTimeout(() => {}, 120000)" and does not edit files:
node scripts/claude-companion.mjs task --background --write --json
While claude.exe and its Bash child were still running, the job state contained:
{
"status": "running",
"pid": 27956,
"pidIdentity": null
}
Cancelling it returned:
{
"status": "cancel_failed",
"note": "Refusing to cancel a stored process without a PID identity."
}
The process tree was still alive afterward and had to be terminated manually.
Root cause
getProcessIdentity() handles macOS separately and otherwise reads /proc/<pid>/stat. On Windows that resolves to a path such as D:\proc\<pid>\stat and fails with ENOENT. Callers treat identity collection as best-effort, so the job continues with a null identity, but cancellation deliberately requires one.
The Windows CI job currently runs the curated test:cross-platform list, which does not include tests/process.test.mjs. That test file also uses echo and cat as standalone executables, so it is not portable to native Windows yet.
Expected behavior
Windows jobs should store a stable process-birth identity and pass the same PID-reuse check used on the other platforms. tests/process.test.mjs should run in the Windows CI job.
Environment
- Windows 11
- Node.js 24.17.0
- cc-plugin-codex 1.5.0 (
19e5651)
- Claude Code 2.1.263
Summary
On native Windows, a running background task records
pidIdentity: null. The cancel command then refuses to stop the task and marks it ascancel_failed.Reproduction
I ran a real background task through the companion CLI on Windows, with a prompt that starts
node -e "setTimeout(() => {}, 120000)"and does not edit files:While
claude.exeand its Bash child were still running, the job state contained:{ "status": "running", "pid": 27956, "pidIdentity": null }Cancelling it returned:
{ "status": "cancel_failed", "note": "Refusing to cancel a stored process without a PID identity." }The process tree was still alive afterward and had to be terminated manually.
Root cause
getProcessIdentity()handles macOS separately and otherwise reads/proc/<pid>/stat. On Windows that resolves to a path such asD:\proc\<pid>\statand fails withENOENT. Callers treat identity collection as best-effort, so the job continues with a null identity, but cancellation deliberately requires one.The Windows CI job currently runs the curated
test:cross-platformlist, which does not includetests/process.test.mjs. That test file also usesechoandcatas standalone executables, so it is not portable to native Windows yet.Expected behavior
Windows jobs should store a stable process-birth identity and pass the same PID-reuse check used on the other platforms.
tests/process.test.mjsshould run in the Windows CI job.Environment
19e5651)