fix(hooks): distinguish EPERM from ESRCH in PID liveness check

Cursor Bugbot caught a contradiction with the stated design: the bare
`catch` after `process.kill(owner, 0)` was treating EPERM (process exists
but owned by another user) the same as ESRCH (process gone), which would
evict a live slot whenever the lock dir straddled user boundaries.

Inspect the error code: ESRCH → dead, evict; EPERM → still alive, keep
the slot; anything else → assume alive (be conservative under unexpected
failure rather than over-evict).

Applied to all three hook variants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
abhigyantrumio 2026-05-12 20:00:51 +05:30
parent e11077b35b
commit 5bacf5a4b6
3 changed files with 27 additions and 6 deletions

View file

@ -248,8 +248,15 @@ function acquireHookSlot(gitNexusDir) {
try {
process.kill(owner, 0);
isLive = true;
} catch {
/* ESRCH (or EPERM under cross-user) — treat as dead */
} catch (e) {
// ESRCH = process gone → treat as dead. EPERM = process exists
// but owned by another user (cross-user lock dir) → still alive,
// keep the slot. Anything else: be conservative, assume alive.
if (e && e.code === 'ESRCH') {
isLive = false;
} else {
isLive = true;
}
}
}
}

View file

@ -278,8 +278,15 @@ function acquireHookSlot(gitNexusDir) {
try {
process.kill(owner, 0);
isLive = true;
} catch {
/* ESRCH (or EPERM under cross-user) — treat as dead */
} catch (e) {
// ESRCH = process gone → treat as dead. EPERM = process exists
// but owned by another user (cross-user lock dir) → still alive,
// keep the slot. Anything else: be conservative, assume alive.
if (e && e.code === 'ESRCH') {
isLive = false;
} else {
isLive = true;
}
}
}
}

View file

@ -248,8 +248,15 @@ function acquireHookSlot(gitNexusDir) {
try {
process.kill(owner, 0);
isLive = true;
} catch {
/* ESRCH (or EPERM under cross-user) — treat as dead */
} catch (e) {
// ESRCH = process gone → treat as dead. EPERM = process exists
// but owned by another user (cross-user lock dir) → still alive,
// keep the slot. Anything else: be conservative, assume alive.
if (e && e.code === 'ESRCH') {
isLive = false;
} else {
isLive = true;
}
}
}
}