mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-15 03:32:43 +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
|
cfg.WorkDir = defaultWorkdir
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle worktree mode: create a new git worktree and update cfg.WorkDir
|
// Handle worktree mode: check DO_WORKTREE_DIR env var first, then create if needed
|
||||||
if taskSpec.Worktree {
|
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)
|
paths, err := createWorktreeFn(cfg.WorkDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.ExitCode = 1
|
result.ExitCode = 1
|
||||||
|
|||||||
@@ -41,10 +41,15 @@ This creates `.claude/do.{task_id}.local.md` with:
|
|||||||
|
|
||||||
## Worktree Mode
|
## 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
|
```bash
|
||||||
# With worktree mode enabled
|
# With worktree mode enabled - codeagent-wrapper will use DO_WORKTREE_DIR automatically
|
||||||
codeagent-wrapper --worktree --agent develop - . <<'EOF'
|
codeagent-wrapper --worktree --agent develop - . <<'EOF'
|
||||||
...
|
...
|
||||||
EOF
|
EOF
|
||||||
@@ -60,7 +65,7 @@ workdir: .
|
|||||||
EOF
|
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
|
## Loop State Management
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import secrets
|
import secrets
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -20,6 +21,34 @@ def die(msg: str):
|
|||||||
print(f"❌ {msg}", file=sys.stderr)
|
print(f"❌ {msg}", file=sys.stderr)
|
||||||
sys.exit(1)
|
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():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Creates (or overwrites) project state file: .claude/do.local.md"
|
description="Creates (or overwrites) project state file: .claude/do.local.md"
|
||||||
@@ -50,6 +79,11 @@ def main():
|
|||||||
|
|
||||||
os.makedirs(state_dir, exist_ok=True)
|
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)
|
phase_name = phase_name_for(1)
|
||||||
|
|
||||||
content = f"""---
|
content = f"""---
|
||||||
@@ -59,6 +93,7 @@ phase_name: "{phase_name}"
|
|||||||
max_phases: {max_phases}
|
max_phases: {max_phases}
|
||||||
completion_promise: "{completion_promise}"
|
completion_promise: "{completion_promise}"
|
||||||
use_worktree: {str(use_worktree).lower()}
|
use_worktree: {str(use_worktree).lower()}
|
||||||
|
worktree_dir: "{worktree_dir}"
|
||||||
---
|
---
|
||||||
|
|
||||||
# do loop state
|
# do loop state
|
||||||
@@ -80,6 +115,9 @@ use_worktree: {str(use_worktree).lower()}
|
|||||||
print(f"completion_promise: {completion_promise}")
|
print(f"completion_promise: {completion_promise}")
|
||||||
print(f"use_worktree: {use_worktree}")
|
print(f"use_worktree: {use_worktree}")
|
||||||
print(f"export DO_TASK_ID={task_id}")
|
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__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user