summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CLAUDE.md4
-rw-r--r--internal/executor/claude.go12
2 files changed, 9 insertions, 7 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index c895c3a..f35c5c5 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -114,9 +114,9 @@ When `agent.project_dir` is set:
4. On failure the sandbox is preserved and its path is returned in the error.
5. On BLOCKED (question written), the sandbox path is stored in `executions.sandbox_dir` so the resume execution can reuse it.
-> **Known bug:** Variable shadowing in `claude.go` `Run()` means the outer `sandboxDir` is never assigned (both `setupSandbox` calls use `:=` inside nested blocks). This causes: (a) `teardownSandbox` is never called — work is discarded, sandboxes accumulate in `/tmp`; (b) `BlockedError.SandboxDir` is always `""`, so resume clones a fresh sandbox and loses the agent's partial work. See [Known Bugs](#known-bugs).
+> ~~**Known bug:** Variable shadowing in `claude.go` `Run()` — fixed in github/main merge; both `setupSandbox` calls correctly use `=` (assign to outer `sandboxDir`).~~
-> **Known bug:** `teardownSandbox` hardcodes `origin/master` when rebasing on conflict. Repos using `main` will fail on concurrent push. See [Known Bugs](#known-bugs).
+> ~~**Known bug:** `teardownSandbox` hardcodes `origin/master` — fixed; now uses `git pull --rebase` with no branch arg, which follows the configured upstream from `git clone`.~~
### Task YAML Format
diff --git a/internal/executor/claude.go b/internal/executor/claude.go
index 3c87f26..7b70486 100644
--- a/internal/executor/claude.go
+++ b/internal/executor/claude.go
@@ -248,7 +248,7 @@ func setupSandbox(projectDir string, logger *slog.Logger) (string, error) {
// from mixed-owner .git/objects directories.
func teardownSandbox(projectDir, sandboxDir, startHEAD string, logger *slog.Logger, execRecord *storage.Execution) error {
// Automatically commit uncommitted changes.
- out, err := exec.Command("git", "-C", sandboxDir, "status", "--porcelain").Output()
+ out, err := exec.Command("git", gitSafe("-C", sandboxDir, "status", "--porcelain")...).Output()
if err != nil {
return fmt.Errorf("git status: %w", err)
}
@@ -327,16 +327,18 @@ func teardownSandbox(projectDir, sandboxDir, startHEAD string, logger *slog.Logg
}
// Push from sandbox → bare repo (sandbox's origin is the bare repo).
- if out, err := exec.Command("git", "-C", sandboxDir, "push", "origin", "HEAD").CombinedOutput(); err != nil {
+ if out, err := exec.Command("git", gitSafe("-C", sandboxDir, "push", "origin", "HEAD")...).CombinedOutput(); err != nil {
// If rejected due to concurrent push, fetch+rebase and retry once.
+ // Use `git pull --rebase` without explicit remote/branch so git uses the
+ // configured upstream (set by clone), handling both main- and master-based repos.
if strings.Contains(string(out), "fetch first") || strings.Contains(string(out), "non-fast-forward") {
logger.Info("push rejected (concurrent task); rebasing and retrying", "sandbox", sandboxDir)
- if out2, err2 := exec.Command("git", "-C", sandboxDir, "pull", "--rebase", "origin", "master").CombinedOutput(); err2 != nil {
+ if out2, err2 := exec.Command("git", gitSafe("-C", sandboxDir, "pull", "--rebase")...).CombinedOutput(); err2 != nil {
return fmt.Errorf("git rebase before retry push: %w\n%s", err2, out2)
}
// Re-capture commits after rebase (hashes might have changed)
execRecord.Commits = nil
- logOut, logErr = exec.Command("git", "-C", sandboxDir, "log", logRange, "--pretty=format:%H|%s").Output()
+ logOut, logErr = exec.Command("git", gitSafe("-C", sandboxDir, "log", logRange, "--pretty=format:%H|%s")...).Output()
if logErr == nil {
lines := strings.Split(strings.TrimSpace(string(logOut)), "\n")
for _, line := range lines {
@@ -350,7 +352,7 @@ func teardownSandbox(projectDir, sandboxDir, startHEAD string, logger *slog.Logg
}
}
- if out3, err3 := exec.Command("git", "-C", sandboxDir, "push", "origin", "HEAD").CombinedOutput(); err3 != nil {
+ if out3, err3 := exec.Command("git", gitSafe("-C", sandboxDir, "push", "origin", "HEAD")...).CombinedOutput(); err3 != nil {
return fmt.Errorf("git push to origin (after rebase): %w\n%s", err3, out3)
}
} else {