fix: prepend claude CLI install paths to subprocess PATH (env-sanitizer)

Root cause: worker launched by Claude Desktop inherits a narrow PATH that
omits ~/.local/bin and ~/.bun/bin, so SDK subprocesses fail with
"Claude executable not found" — observations pile up in the queue but
are never processed, producing the "only my messages get recorded"
symptom that patching session reset logic could not fix.

env-sanitizer now prepends the common install locations (~/.local/bin,
~/.bun/bin, ~/bin, /opt/homebrew/bin, /usr/local/bin on Unix; matching
Windows locations) to PATH before spawning SDK subprocesses, so the
worker can locate the claude binary regardless of launch context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
JOUNGWOOK KWON
2026-04-20 13:30:23 +09:00
parent 70a537c3a7
commit d6ad6e29f0
3 changed files with 144 additions and 105 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+39
View File
@@ -12,6 +12,35 @@ export const ENV_PRESERVE = new Set([
'CLAUDE_CODE_GIT_BASH_PATH',
]);
/**
* Common user-install locations where the `claude` CLI binary may live.
* Claude Desktop spawns the worker without inheriting the user's shell profile
* PATH, so `~/.local/bin` and `~/.bun/bin` are frequently missing — which
* causes the SDK subprocess to fail with "Claude executable not found" and
* silently blocks all memory processing.
*
* We unconditionally prepend these paths (skipping ones already present) so
* the worker can locate `claude` regardless of how it was launched.
*/
function extraClaudePathLocations(env: NodeJS.ProcessEnv): string[] {
const home = env.HOME || env.USERPROFILE;
if (!home) return ['/opt/homebrew/bin', '/usr/local/bin'];
if (process.platform === 'win32') {
return [
`${home}\\AppData\\Local\\Programs\\claude`,
`${home}\\.bun\\bin`,
`${home}\\.local\\bin`
];
}
return [
`${home}/.local/bin`,
`${home}/.bun/bin`,
`${home}/bin`,
'/opt/homebrew/bin',
'/usr/local/bin'
];
}
export function sanitizeEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {
const sanitized: NodeJS.ProcessEnv = {};
@@ -23,5 +52,15 @@ export function sanitizeEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.Proces
sanitized[key] = value;
}
// Ensure PATH includes common locations where `claude` CLI is installed.
// See extraClaudePathLocations() for the rationale.
const sep = process.platform === 'win32' ? ';' : ':';
const currentPath = sanitized.PATH || sanitized.Path || '';
const existing = new Set(currentPath.split(sep).filter(Boolean));
const toPrepend = extraClaudePathLocations(env).filter(p => !existing.has(p));
if (toPrepend.length > 0) {
sanitized.PATH = [...toPrepend, currentPath].filter(Boolean).join(sep);
}
return sanitized;
}