mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-28 09:23:05 +08:00
fix(executor): unset CLAUDECODE env to prevent nested session rejection
Claude Code v2.1.41+ sets CLAUDECODE=1 in all child Bash processes and rejects startup when the variable is present. When codeagent-wrapper spawns `claude -p` as a subprocess, it inherits this variable and gets blocked with "cannot be launched inside another Claude Code session". Add UnsetEnv method to commandRunner interface and strip CLAUDECODE before spawning the claude backend. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,11 @@ func (f *fakeCmd) SetEnv(env map[string]string) {
|
||||
}
|
||||
}
|
||||
func (f *fakeCmd) Process() processHandle { return nil }
|
||||
func (f *fakeCmd) UnsetEnv(keys ...string) {
|
||||
for _, k := range keys {
|
||||
delete(f.env, k)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvInjection_LogsToStderrAndMasksKey(t *testing.T) {
|
||||
// Arrange ~/.codeagent/models.json via HOME override.
|
||||
|
||||
@@ -113,6 +113,7 @@ type commandRunner interface {
|
||||
SetStderr(io.Writer)
|
||||
SetDir(string)
|
||||
SetEnv(env map[string]string)
|
||||
UnsetEnv(keys ...string)
|
||||
Process() processHandle
|
||||
}
|
||||
|
||||
@@ -221,6 +222,33 @@ func (r *realCmd) SetEnv(env map[string]string) {
|
||||
r.cmd.Env = out
|
||||
}
|
||||
|
||||
func (r *realCmd) UnsetEnv(keys ...string) {
|
||||
if r == nil || r.cmd == nil || len(keys) == 0 {
|
||||
return
|
||||
}
|
||||
// If cmd.Env is nil, Go inherits all parent env vars.
|
||||
// Populate explicitly so we can selectively remove keys.
|
||||
if r.cmd.Env == nil {
|
||||
r.cmd.Env = os.Environ()
|
||||
}
|
||||
drop := make(map[string]struct{}, len(keys))
|
||||
for _, k := range keys {
|
||||
drop[k] = struct{}{}
|
||||
}
|
||||
filtered := make([]string, 0, len(r.cmd.Env))
|
||||
for _, kv := range r.cmd.Env {
|
||||
idx := strings.IndexByte(kv, '=')
|
||||
name := kv
|
||||
if idx >= 0 {
|
||||
name = kv[:idx]
|
||||
}
|
||||
if _, ok := drop[name]; !ok {
|
||||
filtered = append(filtered, kv)
|
||||
}
|
||||
}
|
||||
r.cmd.Env = filtered
|
||||
}
|
||||
|
||||
func (r *realCmd) Process() processHandle {
|
||||
if r == nil || r.cmd == nil || r.cmd.Process == nil {
|
||||
return nil
|
||||
@@ -1126,6 +1154,13 @@ 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" {
|
||||
cmd.UnsetEnv("CLAUDECODE")
|
||||
}
|
||||
|
||||
// For backends that don't support -C flag (claude, gemini), set working directory via cmd.Dir
|
||||
// Codex passes workdir via -C flag, so we skip setting Dir for it to avoid conflicts
|
||||
if cfg.Mode != "resume" && commandName != "codex" && cfg.WorkDir != "" {
|
||||
|
||||
Reference in New Issue
Block a user