Compare commits

..

6 Commits

Author SHA1 Message Date
swe-agent[bot]
ff301507fe test: Fix tests for ClaudeBackend default --dangerously-skip-permissions
- Update TestClaudeBuildArgs_ModesAndPermissions expectations
- Update TestBackendBuildArgs_ClaudeBackend expectations
- Update TestClaudeBackendBuildArgs_OutputValidation expectations
- Update version tests to expect 5.2.2

ClaudeBackend now defaults to adding --dangerously-skip-permissions
for automation workflows.

Generated with swe-agent-bot

Co-Authored-By: swe-agent-bot <agent@swe-agent.ai>
2025-12-13 21:53:38 +08:00
swe-agent[bot]
93b72eba42 chore(v5.2.2): Bump version and clean up documentation
- Update version to 5.2.2 in README.md, README_CN.md, and codeagent-wrapper/main.go
- Remove non-existent documentation links from README.md (architecture.md, GITHUB-WORKFLOW.md, enterprise-workflow-ideas.md)
- Add coverage.out to .gitignore

Generated with swe-agent-bot

Co-Authored-By: swe-agent-bot <agent@swe-agent.ai>
2025-12-13 21:43:49 +08:00
swe-agent[bot]
b01758e7e1 fix codeagent backend claude no auto 2025-12-13 21:42:17 +08:00
swe-agent[bot]
c51b38c671 fix install.py dev fail 2025-12-13 21:41:55 +08:00
swe-agent[bot]
b227fee225 fix codeagent claude and gemini root dir 2025-12-13 16:56:53 +08:00
swe-agent[bot]
2b7569335b update readme 2025-12-13 15:29:12 +08:00
10 changed files with 70 additions and 38 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@
.pytest_cache .pytest_cache
__pycache__ __pycache__
.coverage .coverage
coverage.out

View File

@@ -1,3 +1,5 @@
[中文](README_CN.md) [English](README.md)
# Claude Code Multi-Agent Workflow System # Claude Code Multi-Agent Workflow System
[![Run in Smithery](https://smithery.ai/badge/skills/cexll)](https://smithery.ai/skills?ns=cexll&utm_source=github&utm_medium=badge) [![Run in Smithery](https://smithery.ai/badge/skills/cexll)](https://smithery.ai/skills?ns=cexll&utm_source=github&utm_medium=badge)
@@ -5,7 +7,7 @@
[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![Claude Code](https://img.shields.io/badge/Claude-Code-blue)](https://claude.ai/code) [![Claude Code](https://img.shields.io/badge/Claude-Code-blue)](https://claude.ai/code)
[![Version](https://img.shields.io/badge/Version-5.2-green)](https://github.com/cexll/myclaude) [![Version](https://img.shields.io/badge/Version-5.2.2-green)](https://github.com/cexll/myclaude)
> AI-powered development automation with multi-backend execution (Codex/Claude/Gemini) > AI-powered development automation with multi-backend execution (Codex/Claude/Gemini)
@@ -318,13 +320,10 @@ python3 install.py --module dev --force
## Documentation ## Documentation
### Core Guides ### Core Guides
- **[Architecture Overview](docs/architecture.md)** - System architecture and component design
- **[Codeagent-Wrapper Guide](docs/CODEAGENT-WRAPPER.md)** - Multi-backend execution wrapper - **[Codeagent-Wrapper Guide](docs/CODEAGENT-WRAPPER.md)** - Multi-backend execution wrapper
- **[GitHub Workflow Guide](docs/GITHUB-WORKFLOW.md)** - Issue-to-PR automation
- **[Hooks Documentation](docs/HOOKS.md)** - Custom hooks and automation - **[Hooks Documentation](docs/HOOKS.md)** - Custom hooks and automation
### Additional Resources ### Additional Resources
- **[Enterprise Workflow Ideas](docs/enterprise-workflow-ideas.md)** - Advanced patterns and best practices
- **[Installation Log](install.log)** - Installation history and troubleshooting - **[Installation Log](install.log)** - Installation history and troubleshooting
--- ---

View File

@@ -2,7 +2,7 @@
[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![Claude Code](https://img.shields.io/badge/Claude-Code-blue)](https://claude.ai/code) [![Claude Code](https://img.shields.io/badge/Claude-Code-blue)](https://claude.ai/code)
[![Version](https://img.shields.io/badge/Version-5.2-green)](https://github.com/cexll/myclaude) [![Version](https://img.shields.io/badge/Version-5.2.2-green)](https://github.com/cexll/myclaude)
> AI 驱动的开发自动化 - 多后端执行架构 (Codex/Claude/Gemini) > AI 驱动的开发自动化 - 多后端执行架构 (Codex/Claude/Gemini)

View File

@@ -29,26 +29,20 @@ func (ClaudeBackend) BuildArgs(cfg *Config, targetArg string) []string {
if cfg == nil { if cfg == nil {
return nil return nil
} }
args := []string{"-p"} args := []string{"-p", "--dangerously-skip-permissions"}
// Only skip permissions when explicitly requested // Only skip permissions when explicitly requested
if cfg.SkipPermissions { // if cfg.SkipPermissions {
args = append(args, "--dangerously-skip-permissions") // args = append(args, "--dangerously-skip-permissions")
} // }
workdir := cfg.WorkDir
if workdir == "" {
workdir = defaultWorkdir
}
if cfg.Mode == "resume" { if cfg.Mode == "resume" {
if cfg.SessionID != "" { if cfg.SessionID != "" {
// Claude CLI uses -r <session_id> for resume. // Claude CLI uses -r <session_id> for resume.
args = append(args, "-r", cfg.SessionID) args = append(args, "-r", cfg.SessionID)
} }
} else {
args = append(args, "-C", workdir)
} }
// Note: claude CLI doesn't support -C flag; workdir set via cmd.Dir
args = append(args, "--output-format", "stream-json", "--verbose", targetArg) args = append(args, "--output-format", "stream-json", "--verbose", targetArg)
@@ -67,18 +61,12 @@ func (GeminiBackend) BuildArgs(cfg *Config, targetArg string) []string {
} }
args := []string{"-o", "stream-json", "-y"} args := []string{"-o", "stream-json", "-y"}
workdir := cfg.WorkDir
if workdir == "" {
workdir = defaultWorkdir
}
if cfg.Mode == "resume" { if cfg.Mode == "resume" {
if cfg.SessionID != "" { if cfg.SessionID != "" {
args = append(args, "-r", cfg.SessionID) args = append(args, "-r", cfg.SessionID)
} }
} else {
args = append(args, "-C", workdir)
} }
// Note: gemini CLI doesn't support -C flag; workdir set via cmd.Dir
args = append(args, "-p", targetArg) args = append(args, "-p", targetArg)

View File

@@ -11,7 +11,7 @@ func TestClaudeBuildArgs_ModesAndPermissions(t *testing.T) {
t.Run("new mode uses workdir without skip by default", func(t *testing.T) { t.Run("new mode uses workdir without skip by default", func(t *testing.T) {
cfg := &Config{Mode: "new", WorkDir: "/repo"} cfg := &Config{Mode: "new", WorkDir: "/repo"}
got := backend.BuildArgs(cfg, "todo") got := backend.BuildArgs(cfg, "todo")
want := []string{"-p", "-C", "/repo", "--output-format", "stream-json", "--verbose", "todo"} want := []string{"-p", "--dangerously-skip-permissions", "--output-format", "stream-json", "--verbose", "todo"}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Fatalf("got %v, want %v", got, want) t.Fatalf("got %v, want %v", got, want)
} }
@@ -20,7 +20,7 @@ func TestClaudeBuildArgs_ModesAndPermissions(t *testing.T) {
t.Run("new mode opt-in skip permissions with default workdir", func(t *testing.T) { t.Run("new mode opt-in skip permissions with default workdir", func(t *testing.T) {
cfg := &Config{Mode: "new", SkipPermissions: true} cfg := &Config{Mode: "new", SkipPermissions: true}
got := backend.BuildArgs(cfg, "-") got := backend.BuildArgs(cfg, "-")
want := []string{"-p", "--dangerously-skip-permissions", "-C", defaultWorkdir, "--output-format", "stream-json", "--verbose", "-"} want := []string{"-p", "--dangerously-skip-permissions", "--output-format", "stream-json", "--verbose", "-"}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Fatalf("got %v, want %v", got, want) t.Fatalf("got %v, want %v", got, want)
} }
@@ -29,7 +29,7 @@ func TestClaudeBuildArgs_ModesAndPermissions(t *testing.T) {
t.Run("resume mode uses session id and omits workdir", func(t *testing.T) { t.Run("resume mode uses session id and omits workdir", func(t *testing.T) {
cfg := &Config{Mode: "resume", SessionID: "sid-123", WorkDir: "/ignored"} cfg := &Config{Mode: "resume", SessionID: "sid-123", WorkDir: "/ignored"}
got := backend.BuildArgs(cfg, "resume-task") got := backend.BuildArgs(cfg, "resume-task")
want := []string{"-p", "-r", "sid-123", "--output-format", "stream-json", "--verbose", "resume-task"} want := []string{"-p", "--dangerously-skip-permissions", "-r", "sid-123", "--output-format", "stream-json", "--verbose", "resume-task"}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Fatalf("got %v, want %v", got, want) t.Fatalf("got %v, want %v", got, want)
} }
@@ -38,7 +38,7 @@ func TestClaudeBuildArgs_ModesAndPermissions(t *testing.T) {
t.Run("resume mode without session still returns base flags", func(t *testing.T) { t.Run("resume mode without session still returns base flags", func(t *testing.T) {
cfg := &Config{Mode: "resume", WorkDir: "/ignored"} cfg := &Config{Mode: "resume", WorkDir: "/ignored"}
got := backend.BuildArgs(cfg, "follow-up") got := backend.BuildArgs(cfg, "follow-up")
want := []string{"-p", "--output-format", "stream-json", "--verbose", "follow-up"} want := []string{"-p", "--dangerously-skip-permissions", "--output-format", "stream-json", "--verbose", "follow-up"}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Fatalf("got %v, want %v", got, want) t.Fatalf("got %v, want %v", got, want)
} }
@@ -56,7 +56,7 @@ func TestClaudeBuildArgs_GeminiAndCodexModes(t *testing.T) {
backend := GeminiBackend{} backend := GeminiBackend{}
cfg := &Config{Mode: "new", WorkDir: "/workspace"} cfg := &Config{Mode: "new", WorkDir: "/workspace"}
got := backend.BuildArgs(cfg, "task") got := backend.BuildArgs(cfg, "task")
want := []string{"-o", "stream-json", "-y", "-C", "/workspace", "-p", "task"} want := []string{"-o", "stream-json", "-y", "-p", "task"}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Fatalf("got %v, want %v", got, want) t.Fatalf("got %v, want %v", got, want)
} }

View File

@@ -23,6 +23,7 @@ type commandRunner interface {
StdoutPipe() (io.ReadCloser, error) StdoutPipe() (io.ReadCloser, error)
StdinPipe() (io.WriteCloser, error) StdinPipe() (io.WriteCloser, error)
SetStderr(io.Writer) SetStderr(io.Writer)
SetDir(string)
Process() processHandle Process() processHandle
} }
@@ -72,6 +73,12 @@ func (r *realCmd) SetStderr(w io.Writer) {
} }
} }
func (r *realCmd) SetDir(dir string) {
if r.cmd != nil {
r.cmd.Dir = dir
}
}
func (r *realCmd) Process() processHandle { func (r *realCmd) Process() processHandle {
if r == nil || r.cmd == nil || r.cmd.Process == nil { if r == nil || r.cmd == nil || r.cmd.Process == nil {
return nil return nil
@@ -577,6 +584,12 @@ func runCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
cmd := newCommandRunner(ctx, commandName, codexArgs...) cmd := newCommandRunner(ctx, commandName, codexArgs...)
// 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 != "" {
cmd.SetDir(cfg.WorkDir)
}
stderrWriters := []io.Writer{stderrBuf} stderrWriters := []io.Writer{stderrBuf}
if stderrLogger != nil { if stderrLogger != nil {
stderrWriters = append(stderrWriters, stderrLogger) stderrWriters = append(stderrWriters, stderrLogger)

View File

@@ -117,6 +117,7 @@ func (f *execFakeRunner) StdinPipe() (io.WriteCloser, error) {
return &writeCloserStub{}, nil return &writeCloserStub{}, nil
} }
func (f *execFakeRunner) SetStderr(io.Writer) {} func (f *execFakeRunner) SetStderr(io.Writer) {}
func (f *execFakeRunner) SetDir(string) {}
func (f *execFakeRunner) Process() processHandle { func (f *execFakeRunner) Process() processHandle {
if f.process != nil { if f.process != nil {
return f.process return f.process

View File

@@ -14,7 +14,7 @@ import (
) )
const ( const (
version = "5.2.0" version = "5.2.2"
defaultWorkdir = "." defaultWorkdir = "."
defaultTimeout = 7200 // seconds defaultTimeout = 7200 // seconds
codexLogLineLimit = 1000 codexLogLineLimit = 1000

View File

@@ -250,6 +250,10 @@ func (d *drainBlockingCmd) SetStderr(w io.Writer) {
d.inner.SetStderr(w) d.inner.SetStderr(w)
} }
func (d *drainBlockingCmd) SetDir(dir string) {
d.inner.SetDir(dir)
}
func (d *drainBlockingCmd) Process() processHandle { func (d *drainBlockingCmd) Process() processHandle {
return d.inner.Process() return d.inner.Process()
} }
@@ -504,6 +508,8 @@ func (f *fakeCmd) SetStderr(w io.Writer) {
f.stderr = w f.stderr = w
} }
func (f *fakeCmd) SetDir(string) {}
func (f *fakeCmd) Process() processHandle { func (f *fakeCmd) Process() processHandle {
if f == nil { if f == nil {
return nil return nil
@@ -1371,7 +1377,7 @@ func TestBackendBuildArgs_ClaudeBackend(t *testing.T) {
backend := ClaudeBackend{} backend := ClaudeBackend{}
cfg := &Config{Mode: "new", WorkDir: defaultWorkdir} cfg := &Config{Mode: "new", WorkDir: defaultWorkdir}
got := backend.BuildArgs(cfg, "todo") got := backend.BuildArgs(cfg, "todo")
want := []string{"-p", "-C", defaultWorkdir, "--output-format", "stream-json", "--verbose", "todo"} want := []string{"-p", "--dangerously-skip-permissions", "--output-format", "stream-json", "--verbose", "todo"}
if len(got) != len(want) { if len(got) != len(want) {
t.Fatalf("length mismatch") t.Fatalf("length mismatch")
} }
@@ -1392,7 +1398,7 @@ func TestClaudeBackendBuildArgs_OutputValidation(t *testing.T) {
target := "ensure-flags" target := "ensure-flags"
args := backend.BuildArgs(cfg, target) args := backend.BuildArgs(cfg, target)
expectedPrefix := []string{"-p", "--output-format", "stream-json", "--verbose"} expectedPrefix := []string{"-p", "--dangerously-skip-permissions", "--output-format", "stream-json", "--verbose"}
if len(args) != len(expectedPrefix)+1 { if len(args) != len(expectedPrefix)+1 {
t.Fatalf("args length=%d, want %d", len(args), len(expectedPrefix)+1) t.Fatalf("args length=%d, want %d", len(args), len(expectedPrefix)+1)
@@ -1411,7 +1417,7 @@ func TestBackendBuildArgs_GeminiBackend(t *testing.T) {
backend := GeminiBackend{} backend := GeminiBackend{}
cfg := &Config{Mode: "new"} cfg := &Config{Mode: "new"}
got := backend.BuildArgs(cfg, "task") got := backend.BuildArgs(cfg, "task")
want := []string{"-o", "stream-json", "-y", "-C", defaultWorkdir, "-p", "task"} want := []string{"-o", "stream-json", "-y", "-p", "task"}
if len(got) != len(want) { if len(got) != len(want) {
t.Fatalf("length mismatch") t.Fatalf("length mismatch")
} }
@@ -2684,7 +2690,7 @@ func TestVersionFlag(t *testing.T) {
t.Errorf("exit = %d, want 0", code) t.Errorf("exit = %d, want 0", code)
} }
}) })
want := "codeagent-wrapper version 5.2.0\n" want := "codeagent-wrapper version 5.2.2\n"
if output != want { if output != want {
t.Fatalf("output = %q, want %q", output, want) t.Fatalf("output = %q, want %q", output, want)
} }
@@ -2698,7 +2704,7 @@ func TestVersionShortFlag(t *testing.T) {
t.Errorf("exit = %d, want 0", code) t.Errorf("exit = %d, want 0", code)
} }
}) })
want := "codeagent-wrapper version 5.2.0\n" want := "codeagent-wrapper version 5.2.2\n"
if output != want { if output != want {
t.Fatalf("output = %q, want %q", output, want) t.Fatalf("output = %q, want %q", output, want)
} }
@@ -2712,7 +2718,7 @@ func TestVersionLegacyAlias(t *testing.T) {
t.Errorf("exit = %d, want 0", code) t.Errorf("exit = %d, want 0", code)
} }
}) })
want := "codex-wrapper version 5.2.0\n" want := "codex-wrapper version 5.2.2\n"
if output != want { if output != want {
t.Fatalf("output = %q, want %q", output, want) t.Fatalf("output = %q, want %q", output, want)
} }

View File

@@ -20,9 +20,33 @@
}, },
{ {
"type": "copy_file", "type": "copy_file",
"source": "skills/codex/SKILL.md", "source": "skills/codeagent/SKILL.md",
"target": "skills/codex/SKILL.md", "target": "skills/codeagent/SKILL.md",
"description": "Install codex skill" "description": "Install codeagent skill"
},
{
"type": "copy_file",
"source": "skills/product-requirements/SKILL.md",
"target": "skills/product-requirements/SKILL.md",
"description": "Install product-requirements skill"
},
{
"type": "copy_file",
"source": "skills/prototype-prompt-generator/SKILL.md",
"target": "skills/prototype-prompt-generator/SKILL.md",
"description": "Install prototype-prompt-generator skill"
},
{
"type": "copy_file",
"source": "skills/prototype-prompt-generator/references/prompt-structure.md",
"target": "skills/prototype-prompt-generator/references/prompt-structure.md",
"description": "Install prototype-prompt-generator prompt structure reference"
},
{
"type": "copy_file",
"source": "skills/prototype-prompt-generator/references/design-systems.md",
"target": "skills/prototype-prompt-generator/references/design-systems.md",
"description": "Install prototype-prompt-generator design systems reference"
}, },
{ {
"type": "run_command", "type": "run_command",