mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-11 03:23:50 +08:00
fix(do): reuse worktree across phases via DO_WORKTREE_DIR env var
Previously, each codeagent-wrapper --worktree call created a new worktree, causing multiple worktrees per /do task (one per phase). Changes: - setup-do.py: create worktree at initialization, export DO_WORKTREE_DIR - executor.go: check DO_WORKTREE_DIR first, reuse if set - SKILL.md: update documentation for new behavior Generated with SWE-Agent.ai Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
This commit is contained in:
@@ -941,8 +941,13 @@ func RunCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
|
||||
cfg.WorkDir = defaultWorkdir
|
||||
}
|
||||
|
||||
// Handle worktree mode: create a new git worktree and update cfg.WorkDir
|
||||
if taskSpec.Worktree {
|
||||
// Handle worktree mode: check DO_WORKTREE_DIR env var first, then create if needed
|
||||
if worktreeDir := os.Getenv("DO_WORKTREE_DIR"); worktreeDir != "" {
|
||||
// Use existing worktree from /do setup
|
||||
cfg.WorkDir = worktreeDir
|
||||
logInfo(fmt.Sprintf("Using existing worktree from DO_WORKTREE_DIR: %s", worktreeDir))
|
||||
} else if taskSpec.Worktree {
|
||||
// Create new worktree (backward compatibility for standalone --worktree usage)
|
||||
paths, err := createWorktreeFn(cfg.WorkDir)
|
||||
if err != nil {
|
||||
result.ExitCode = 1
|
||||
|
||||
@@ -41,10 +41,15 @@ This creates `.claude/do.{task_id}.local.md` with:
|
||||
|
||||
## Worktree Mode
|
||||
|
||||
When `use_worktree: true` in state file, ALL `codeagent-wrapper` calls that modify code MUST include `--worktree`:
|
||||
When `use_worktree: true` in state file:
|
||||
- The worktree is created once during initialization (setup-do.py)
|
||||
- The worktree path is stored in `worktree_dir` frontmatter field
|
||||
- Environment variable `DO_WORKTREE_DIR` is exported for codeagent-wrapper to use
|
||||
- ALL `codeagent-wrapper` calls that modify code MUST include `--worktree` flag
|
||||
- codeagent-wrapper detects `DO_WORKTREE_DIR` and reuses the existing worktree instead of creating new ones
|
||||
|
||||
```bash
|
||||
# With worktree mode enabled
|
||||
# With worktree mode enabled - codeagent-wrapper will use DO_WORKTREE_DIR automatically
|
||||
codeagent-wrapper --worktree --agent develop - . <<'EOF'
|
||||
...
|
||||
EOF
|
||||
@@ -60,7 +65,7 @@ workdir: .
|
||||
EOF
|
||||
```
|
||||
|
||||
The `--worktree` flag tells codeagent-wrapper to create/use a worktree internally. Read-only agents (code-explorer, code-architect, code-reviewer) do NOT need `--worktree`.
|
||||
The `--worktree` flag tells codeagent-wrapper to use worktree mode. When `DO_WORKTREE_DIR` is set, it reuses that directory; otherwise it creates a new worktree (backward compatibility). Read-only agents (code-explorer, code-architect, code-reviewer) do NOT need `--worktree`.
|
||||
|
||||
## Loop State Management
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import argparse
|
||||
import os
|
||||
import secrets
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
@@ -20,6 +21,34 @@ def die(msg: str):
|
||||
print(f"❌ {msg}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_worktree(project_dir: str, task_id: str) -> str:
|
||||
"""Create a git worktree for the task. Returns the worktree directory path."""
|
||||
# Get git root
|
||||
result = subprocess.run(
|
||||
["git", "-C", project_dir, "rev-parse", "--show-toplevel"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
die(f"Not a git repository: {project_dir}")
|
||||
git_root = result.stdout.strip()
|
||||
|
||||
# Calculate paths
|
||||
worktree_dir = os.path.join(git_root, ".worktrees", f"do-{task_id}")
|
||||
branch_name = f"do/{task_id}"
|
||||
|
||||
# Create worktree with new branch
|
||||
result = subprocess.run(
|
||||
["git", "-C", git_root, "worktree", "add", "-b", branch_name, worktree_dir],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
die(f"Failed to create worktree: {result.stderr}")
|
||||
|
||||
return worktree_dir
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Creates (or overwrites) project state file: .claude/do.local.md"
|
||||
@@ -50,6 +79,11 @@ def main():
|
||||
|
||||
os.makedirs(state_dir, exist_ok=True)
|
||||
|
||||
# Create worktree if requested (before writing state file)
|
||||
worktree_dir = ""
|
||||
if use_worktree:
|
||||
worktree_dir = create_worktree(project_dir, task_id)
|
||||
|
||||
phase_name = phase_name_for(1)
|
||||
|
||||
content = f"""---
|
||||
@@ -59,6 +93,7 @@ phase_name: "{phase_name}"
|
||||
max_phases: {max_phases}
|
||||
completion_promise: "{completion_promise}"
|
||||
use_worktree: {str(use_worktree).lower()}
|
||||
worktree_dir: "{worktree_dir}"
|
||||
---
|
||||
|
||||
# do loop state
|
||||
@@ -80,6 +115,9 @@ use_worktree: {str(use_worktree).lower()}
|
||||
print(f"completion_promise: {completion_promise}")
|
||||
print(f"use_worktree: {use_worktree}")
|
||||
print(f"export DO_TASK_ID={task_id}")
|
||||
if worktree_dir:
|
||||
print(f"worktree_dir: {worktree_dir}")
|
||||
print(f"export DO_WORKTREE_DIR={worktree_dir}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user