stop leaking the parent claude session into the one we spawn
pm2 inherits the environment of whoever ran pm2 start, so restarting this sidecar from inside a claude code terminal — which is how it is restarted most of the time — bakes that terminal's session into the daemon. right now this process is carrying CLAUDE_CODE_MESSAGING_SOCKET for an unrelated pid that has been alive for an hour and a half. three of these were already stripped; the rest arrived with 2.x and were never added. this is hygiene, not the fix for today's hang — a spawn was verified to succeed with the whole set present — but a child attaching to a stranger's ipc socket is not a failure anyone would recognise from the symptom. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,39 @@ function resolveClaudeBin(): string {
|
||||
const CLAUDE_BIN = resolveClaudeBin();
|
||||
console.log(`[claude] CLI resolved to ${CLAUDE_BIN}`);
|
||||
|
||||
/**
|
||||
* Variables the `claude` CLI injects to describe ITS OWN session, which must never reach a `claude` we
|
||||
* spawn ourselves.
|
||||
*
|
||||
* They arrive here by an ordinary accident: PM2 inherits the environment of whoever ran `pm2 start`, so
|
||||
* restarting this sidecar from inside a Claude Code terminal — which is how it is restarted most of the
|
||||
* time — bakes that terminal's session into the daemon. On 2026-08-14 this process was carrying
|
||||
* `CLAUDE_CODE_MESSAGING_SOCKET` for an unrelated PID that had been alive for an hour and a half.
|
||||
*
|
||||
* Only three of these were stripped before (`CLAUDECODE`, `CLAUDE_CODE_ENTRYPOINT`, `CLAUDE_CODE_SSE_PORT`);
|
||||
* the rest are newer and arrived with 2.x. Stripping them is hygiene rather than a fix — a spawn was
|
||||
* verified to succeed with the whole set present — but the failure it prevents is a child attaching to a
|
||||
* stranger's IPC socket, which would be extremely hard to recognise from the symptom.
|
||||
*/
|
||||
const NESTED_SESSION_ENV = [
|
||||
'CLAUDECODE',
|
||||
'CLAUDE_CODE_ENTRYPOINT',
|
||||
'CLAUDE_CODE_SSE_PORT',
|
||||
'CLAUDE_CODE_CHILD_SESSION',
|
||||
'CLAUDE_CODE_MESSAGING_SOCKET',
|
||||
'CLAUDE_CODE_MESSAGING_TOKEN',
|
||||
'CLAUDE_CODE_SESSION_ID',
|
||||
'CLAUDE_CODE_EXECPATH',
|
||||
'CLAUDE_PID',
|
||||
] as const;
|
||||
|
||||
/** `process.env` minus the parent session's fingerprint. */
|
||||
function envWithoutParentSession(): Record<string, string> {
|
||||
const out: Record<string, string> = { ...process.env } as Record<string, string>;
|
||||
for (const name of NESTED_SESSION_ENV) delete out[name];
|
||||
return out;
|
||||
}
|
||||
|
||||
// Capture original HOME before user-instance overrides it
|
||||
const HOST_HOME = process.env.HOME!;
|
||||
import { DATA_PATH } from '../../data-path';
|
||||
@@ -404,7 +437,7 @@ function createSession(params: ClaudeSpawnStreamingParams, onEvent: (event: Chat
|
||||
};
|
||||
|
||||
// Strip the nested-session guard vars so the SDK can spawn `claude` (mirrors the old spawn env clean).
|
||||
const { CLAUDECODE: _c, CLAUDE_CODE_ENTRYPOINT: _e, CLAUDE_CODE_SSE_PORT: _s, ...cleanEnv } = process.env;
|
||||
const cleanEnv = envWithoutParentSession();
|
||||
|
||||
const resumeId = getClaudeSession(sessionKey, params.userId) ?? params.resumeSessionId;
|
||||
const subModel = params.model?.split('/')[1];
|
||||
|
||||
Reference in New Issue
Block a user