diff --git a/codeagent-wrapper/internal/executor/env_stderr_test.go b/codeagent-wrapper/internal/executor/env_stderr_test.go index 2af7439..cfd2504 100644 --- a/codeagent-wrapper/internal/executor/env_stderr_test.go +++ b/codeagent-wrapper/internal/executor/env_stderr_test.go @@ -125,6 +125,9 @@ func TestEnvInjection_LogsToStderrAndMasksKey(t *testing.T) { if cmd.env["ANTHROPIC_API_KEY"] != apiKey { t.Fatalf("ANTHROPIC_API_KEY=%q, want %q", cmd.env["ANTHROPIC_API_KEY"], apiKey) } + if cmd.env["CLAUDE_CODE_TMPDIR"] == "" { + t.Fatalf("expected CLAUDE_CODE_TMPDIR to be set for nested claude, got empty") + } if !strings.Contains(got, "Env: ANTHROPIC_BASE_URL="+baseURL) { t.Fatalf("stderr missing base URL env log; stderr=%q", got) @@ -132,4 +135,7 @@ func TestEnvInjection_LogsToStderrAndMasksKey(t *testing.T) { if !strings.Contains(got, "Env: ANTHROPIC_API_KEY=eyJh****test") { t.Fatalf("stderr missing masked API key log; stderr=%q", got) } + if !strings.Contains(got, "CLAUDE_CODE_TMPDIR: ") { + t.Fatalf("stderr missing CLAUDE_CODE_TMPDIR log; stderr=%q", got) + } } diff --git a/codeagent-wrapper/internal/executor/executor.go b/codeagent-wrapper/internal/executor/executor.go index 1f95301..d1e79aa 100644 --- a/codeagent-wrapper/internal/executor/executor.go +++ b/codeagent-wrapper/internal/executor/executor.go @@ -1154,10 +1154,23 @@ func RunCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe injectTempEnv(cmd) - // Claude Code sets CLAUDECODE=1 in its child processes. If we don't - // remove it, the spawned `claude -p` detects the variable and refuses - // to start ("cannot be launched inside another Claude Code session"). if commandName == "claude" { + // Claude 2.1.45+ calls Nz7() on startup to clean its tasks directory, + // which deletes the parent session's *.output files and causes "(no output)". + // Assign each nested claude its own isolated tmpdir so it only cleans its own files. + nestedTmpDir, err := os.MkdirTemp("", fmt.Sprintf("cc-nested-%d-", os.Getpid())) + if err != nil { + logWarnFn("Failed to create isolated CLAUDE_CODE_TMPDIR: " + err.Error()) + } else { + cmd.SetEnv(map[string]string{"CLAUDE_CODE_TMPDIR": nestedTmpDir}) + defer os.RemoveAll(nestedTmpDir) //nolint:errcheck + logInfoFn("CLAUDE_CODE_TMPDIR: " + nestedTmpDir) + fmt.Fprintln(os.Stderr, " CLAUDE_CODE_TMPDIR: "+nestedTmpDir) + } + + // Claude Code sets CLAUDECODE=1 in its child processes. If we don't + // remove it, the spawned `claude -p` detects the variable and refuses + // to start ("cannot be launched inside another Claude Code session"). cmd.UnsetEnv("CLAUDECODE") }