mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-09 03:09:30 +08:00
fix(codeagent-wrapper): propagate SkipPermissions to parallel tasks (#113)
Parallel task execution was not inheriting the --skip-permissions flag, causing permission prompts to appear for parallel tasks while single tasks worked correctly. Changes: - Add SkipPermissions field to TaskSpec struct - Parse skip_permissions/skip-permissions in parallel task config - Inherit SkipPermissions from CLI args to parallel tasks - Pass SkipPermissions when creating task Config in executor Generated with SWE-Agent.ai Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
This commit is contained in:
@@ -46,6 +46,7 @@ type TaskSpec struct {
|
||||
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
||||
Agent string `json:"agent,omitempty"`
|
||||
PromptFile string `json:"prompt_file,omitempty"`
|
||||
SkipPermissions bool `json:"skip_permissions,omitempty"`
|
||||
Mode string `json:"-"`
|
||||
UseStdin bool `json:"-"`
|
||||
Context context.Context `json:"-"`
|
||||
@@ -201,6 +202,12 @@ func parseParallelConfig(data []byte) (*ParallelConfig, error) {
|
||||
case "agent":
|
||||
agentSpecified = true
|
||||
task.Agent = value
|
||||
case "skip_permissions", "skip-permissions":
|
||||
if value == "" {
|
||||
task.SkipPermissions = true
|
||||
continue
|
||||
}
|
||||
task.SkipPermissions = parseBoolFlag(value, false)
|
||||
case "dependencies":
|
||||
for _, dep := range strings.Split(value, ",") {
|
||||
dep = strings.TrimSpace(dep)
|
||||
|
||||
@@ -815,6 +815,7 @@ func runCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
|
||||
WorkDir: taskSpec.WorkDir,
|
||||
Model: taskSpec.Model,
|
||||
ReasoningEffort: taskSpec.ReasoningEffort,
|
||||
SkipPermissions: taskSpec.SkipPermissions,
|
||||
Backend: defaultBackendName,
|
||||
}
|
||||
|
||||
|
||||
@@ -625,6 +625,27 @@ func TestExecutorRunCodexTaskWithContext(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("claudeSkipPermissionsPropagatesFromTaskSpec", func(t *testing.T) {
|
||||
t.Setenv("CODEAGENT_SKIP_PERMISSIONS", "false")
|
||||
var gotArgs []string
|
||||
newCommandRunner = func(ctx context.Context, name string, args ...string) commandRunner {
|
||||
gotArgs = append([]string(nil), args...)
|
||||
return &execFakeRunner{
|
||||
stdout: newReasonReadCloser(`{"type":"item.completed","item":{"type":"agent_message","text":"ok"}}`),
|
||||
process: &execFakeProcess{pid: 15},
|
||||
}
|
||||
}
|
||||
|
||||
_ = closeLogger()
|
||||
res := runCodexTaskWithContext(context.Background(), TaskSpec{ID: "task-skip", Task: "payload", WorkDir: ".", SkipPermissions: true}, ClaudeBackend{}, nil, false, false, 1)
|
||||
if res.ExitCode != 0 || res.Error != "" {
|
||||
t.Fatalf("unexpected result: %+v", res)
|
||||
}
|
||||
if !slices.Contains(gotArgs, "--dangerously-skip-permissions") {
|
||||
t.Fatalf("expected --dangerously-skip-permissions in args, got %v", gotArgs)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("missingMessage", func(t *testing.T) {
|
||||
newCommandRunner = func(ctx context.Context, name string, args ...string) commandRunner {
|
||||
return &execFakeRunner{
|
||||
|
||||
@@ -177,6 +177,7 @@ func run() (exitCode int) {
|
||||
backendName := defaultBackendName
|
||||
model := ""
|
||||
fullOutput := false
|
||||
skipPermissions := envFlagEnabled("CODEAGENT_SKIP_PERMISSIONS")
|
||||
var extras []string
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
@@ -214,13 +215,19 @@ func run() (exitCode int) {
|
||||
return 1
|
||||
}
|
||||
model = value
|
||||
case arg == "--skip-permissions", arg == "--dangerously-skip-permissions":
|
||||
skipPermissions = true
|
||||
case strings.HasPrefix(arg, "--skip-permissions="):
|
||||
skipPermissions = parseBoolFlag(strings.TrimPrefix(arg, "--skip-permissions="), skipPermissions)
|
||||
case strings.HasPrefix(arg, "--dangerously-skip-permissions="):
|
||||
skipPermissions = parseBoolFlag(strings.TrimPrefix(arg, "--dangerously-skip-permissions="), skipPermissions)
|
||||
default:
|
||||
extras = append(extras, arg)
|
||||
}
|
||||
}
|
||||
|
||||
if len(extras) > 0 {
|
||||
fmt.Fprintln(os.Stderr, "ERROR: --parallel reads its task configuration from stdin; only --backend, --model and --full-output are allowed.")
|
||||
fmt.Fprintln(os.Stderr, "ERROR: --parallel reads its task configuration from stdin; only --backend, --model, --full-output and --skip-permissions are allowed.")
|
||||
fmt.Fprintln(os.Stderr, "Usage examples:")
|
||||
fmt.Fprintf(os.Stderr, " %s --parallel < tasks.txt\n", name)
|
||||
fmt.Fprintf(os.Stderr, " echo '...' | %s --parallel\n", name)
|
||||
@@ -257,6 +264,7 @@ func run() (exitCode int) {
|
||||
if strings.TrimSpace(cfg.Tasks[i].Model) == "" && model != "" {
|
||||
cfg.Tasks[i].Model = model
|
||||
}
|
||||
cfg.Tasks[i].SkipPermissions = cfg.Tasks[i].SkipPermissions || skipPermissions
|
||||
}
|
||||
|
||||
timeoutSec := resolveTimeout()
|
||||
@@ -436,6 +444,7 @@ func run() (exitCode int) {
|
||||
SessionID: cfg.SessionID,
|
||||
Model: cfg.Model,
|
||||
ReasoningEffort: cfg.ReasoningEffort,
|
||||
SkipPermissions: cfg.SkipPermissions,
|
||||
UseStdin: useStdin,
|
||||
}
|
||||
|
||||
|
||||
@@ -1587,6 +1587,26 @@ do something`
|
||||
}
|
||||
}
|
||||
|
||||
func TestParallelParseConfig_SkipPermissions(t *testing.T) {
|
||||
input := `---TASK---
|
||||
id: task-1
|
||||
skip_permissions: true
|
||||
---CONTENT---
|
||||
do something`
|
||||
|
||||
cfg, err := parseParallelConfig([]byte(input))
|
||||
if err != nil {
|
||||
t.Fatalf("parseParallelConfig() unexpected error: %v", err)
|
||||
}
|
||||
if len(cfg.Tasks) != 1 {
|
||||
t.Fatalf("expected 1 task, got %d", len(cfg.Tasks))
|
||||
}
|
||||
task := cfg.Tasks[0]
|
||||
if !task.SkipPermissions {
|
||||
t.Fatalf("SkipPermissions = %v, want true", task.SkipPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParallelParseConfig_EmptySessionID(t *testing.T) {
|
||||
input := `---TASK---
|
||||
id: task-1
|
||||
@@ -4014,6 +4034,30 @@ do two`)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("parallelSkipPermissions", func(t *testing.T) {
|
||||
defer resetTestHooks()
|
||||
cleanupHook = func() {}
|
||||
cleanupLogsFn = func() (CleanupStats, error) { return CleanupStats{}, nil }
|
||||
t.Setenv("CODEAGENT_SKIP_PERMISSIONS", "false")
|
||||
|
||||
runCodexTaskFn = func(task TaskSpec, timeout int) TaskResult {
|
||||
if !task.SkipPermissions {
|
||||
return TaskResult{TaskID: task.ID, ExitCode: 1, Error: "SkipPermissions not propagated"}
|
||||
}
|
||||
return TaskResult{TaskID: task.ID, ExitCode: 0, Message: "ok"}
|
||||
}
|
||||
|
||||
stdinReader = strings.NewReader(`---TASK---
|
||||
id: only
|
||||
backend: claude
|
||||
---CONTENT---
|
||||
do one`)
|
||||
os.Args = []string{"codeagent-wrapper", "--parallel", "--skip-permissions"}
|
||||
if code := run(); code != 0 {
|
||||
t.Fatalf("run exit = %d, want 0", code)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("parallelErrors", func(t *testing.T) {
|
||||
defer resetTestHooks()
|
||||
cleanupLogsFn = func() (CleanupStats, error) { return CleanupStats{}, nil }
|
||||
|
||||
Reference in New Issue
Block a user