From 09180b9ddf649896bfacd15937e3207aa39eb7a7 Mon Sep 17 00:00:00 2001 From: Destin Moss Date: Wed, 17 Jun 2026 14:14:43 -0700 Subject: [PATCH] fix(pty): strip inherited Claude Code session env before spawning child CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When YouCoded is launched from inside a Claude Code session (e.g. running `bash scripts/run-dev.sh` from the Bash tool, or any terminal that is itself a CC session), the Electron process inherits CLAUDECODE=1, CLAUDE_CODE_CHILD_SESSION=1, CLAUDE_CODE_SESSION_ID=, etc. pty-worker spread `...process.env` into the spawned `claude`, so the child believed it was a NESTED/child session. Nested interactive Claude Code does NOT write a top-level transcript to ~/.claude/projects//.jsonl. Since the TranscriptWatcher is the sole source of chat-view state, the chat view stayed permanently empty — even though the terminal/PTY showed output normally and hooks still fired. The built app was unaffected only because it's normally launched from a clean Windows env. Strip the CC session-identity markers from the child env so every session we spawn is a clean top-level session regardless of how YouCoded itself was launched. Verified equivalent: relaunching dev with these vars unset (`env -u ...`) restored chat-view transcript capture. Co-Authored-By: Claude Opus 4.8 (1M context) --- desktop/src/main/pty-worker.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/desktop/src/main/pty-worker.js b/desktop/src/main/pty-worker.js index e308ae4b..ca3f6781 100644 --- a/desktop/src/main/pty-worker.js +++ b/desktop/src/main/pty-worker.js @@ -215,13 +215,34 @@ process.on('message', (msg) => { // Resolve full path — node-pty on Windows needs it (no shell lookup) const shell = resolveCommand(msg.command || 'claude'); const args = msg.args || []; + // Fix: strip Claude Code's own session-identity env vars before spawning + // the child CLI. When YouCoded itself is launched from inside a Claude Code + // session (e.g. `bash scripts/run-dev.sh` run from the Bash tool, or any + // terminal that is itself a CC session), the Electron process inherits + // CLAUDECODE=1, CLAUDE_CODE_CHILD_SESSION=1, CLAUDE_CODE_SESSION_ID=, + // etc. Passing those down makes the spawned `claude` believe it is a + // NESTED/child session — and nested interactive CC does NOT write a + // top-level transcript to ~/.claude/projects//.jsonl. With no + // transcript file, the TranscriptWatcher (the sole source of chat-view + // state) has nothing to read, so chat view stays permanently empty even + // though the terminal/PTY shows output normally and hooks still fire. + // Stripping these makes every session we spawn a clean top-level session + // regardless of how YouCoded itself was launched. + // See docs/PITFALLS.md → "Local Dev & Launch Environment". + const childEnv = { ...process.env }; + delete childEnv.CLAUDECODE; + delete childEnv.CLAUDE_CODE_CHILD_SESSION; + delete childEnv.CLAUDE_CODE_SESSION_ID; + delete childEnv.CLAUDE_CODE_ENTRYPOINT; + delete childEnv.CLAUDE_CODE_EXECPATH; + delete childEnv.CLAUDE_EFFORT; ptyProcess = pty.spawn(shell, args, { name: 'xterm-256color', cols: msg.cols || 120, rows: msg.rows || 30, cwd: msg.cwd || require('os').homedir(), env: { - ...process.env, + ...childEnv, // Pass our session ID so hook scripts can include it in payloads CLAUDE_DESKTOP_SESSION_ID: msg.sessionId || '', // Pass the unique pipe name so relay.js connects to the right instance