From 8d51dbae12369c453cbc69e8f0e179adfec077c8 Mon Sep 17 00:00:00 2001 From: Prateek Date: Sun, 1 Mar 2026 20:22:14 +0530 Subject: [PATCH] fix: guard ps cache callbacks against stale overwrites The .then() and catch callbacks in getCachedProcessList() could clobber a newer in-flight cache entry if the TTL expired and a new request replaced psCache while the old one was still pending. Both now check `psCache?.promise === promise` before writing. Co-Authored-By: Claude Opus 4.6 --- packages/plugins/agent-claude-code/src/index.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/plugins/agent-claude-code/src/index.ts b/packages/plugins/agent-claude-code/src/index.ts index 29df8dc01..db8b475ee 100644 --- a/packages/plugins/agent-claude-code/src/index.ts +++ b/packages/plugins/agent-claude-code/src/index.ts @@ -408,12 +408,15 @@ async function getCachedProcessList(): Promise { return psCache.output; } - // Cache miss or expired — start a single `ps` call and share the promise + // Cache miss or expired — start a single `ps` call and share the promise. + // Guard both callbacks so they only update psCache if it still belongs to + // this request — a newer request may have replaced it while we were waiting. const promise = execFileAsync("ps", ["-eo", "pid,tty,args"], { timeout: 5_000, }).then(({ stdout }) => { - // Resolve: store output, clear promise - psCache = { output: stdout, timestamp: Date.now() }; + if (psCache?.promise === promise) { + psCache = { output: stdout, timestamp: Date.now() }; + } return stdout; }); @@ -423,8 +426,11 @@ async function getCachedProcessList(): Promise { try { return await promise; } catch { - // On failure, clear cache so the next caller retries - psCache = null; + // On failure, clear cache so the next caller retries — but only if + // psCache still points to this request (avoid clobbering a newer entry) + if (psCache?.promise === promise) { + psCache = null; + } return ""; } }