[BUG] VS Code extension (macOS): liveness check spawns `ps` by bare name ~34×/min per window → 6 failed PATH spawns per call, dominant idle process churn
Summary
On macOS, the VS Code extension's process liveness check spawns ps by bare name roughly 34 times per minute per window, even when the window is idle. Because Node/libuv resolves a bare command by trying each PATH entry in turn, and ps lives in /bin (7th entry in a typical Homebrew + ~/.local/bin PATH), every call produces 6 failed spawn attempts plus 1 real one. With 6–7 windows open this is the dominant source of process churn on an otherwise idle machine (~250 short-lived processes per 10 seconds, all night).
Environment
- Claude Code VS Code extension
anthropic.claude-code-2.1.292-darwin-arm64(running in Cursor 3.23.12) - macOS 26.6.2 (Apple Silicon)
PATHseen by the extension host's children (14 entries):~/.local/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:…
Where it comes from
extension.js:
function _F($){ /* … */ return new Promise((J)=>{Uc1.execFile("ps",["-o","lstart=","-p",String($)],{cwd:void 0,timeout:1000,env:{...process.env,LC_ALL:"C",TZ:"UTC"},windowsHide:!0}, /* … */ )}) }
called from closedProcessStillRuns(…).
Measurement
sudo eslogger exec fork for 60 s on a machine with 6 Cursor windows:
- 5,818 forks in 60 s; 2,519 (43%) were forked by the extension hosts.
- Of those, 2,136 never reached
exec. For every extension host, the ratio (forks without exec) / (forks with exec) was exactly 6.0 — one failedposix_spawnperPATHentry before/bin. - Idle windows: each extension host ran
ps -o lstart= -p <pid>exactly 34 times per minute → 34 × 7 = 238 process creations per minute per window. - The bundled
claudebinary also runsps -o lstart= -p <pid>(136×/min across sessions in the same capture).
Workaround
Putting a symlink to /bin/ps in the first PATH entry (ln -s /bin/ps ~/.local/bin/ps) makes the first lookup hit and removes the 6 failed spawns per call.
Suggested fix
- Call
/bin/psby absolute path on darwin (it is always there), and/or - Cache the start time per PID (it never changes for a given PID), or poll less often when the window is idle.