feat(infra): agent_launch_worktree + agent_cleanup_worktree Go fns
Two Go functions in functions/infra/ for orchestrating headless Claude agents inside isolated git worktrees: - AgentLaunchWorktree(cfg): creates worktree off master, spawns claude -p in background, redirects stdout/stderr to LogPath. Falls back to echo stub when claude binary missing (CI/test friendly). ResetIfExists support for re-runs. - AgentCleanupWorktree(repo, branch, path, pid): SIGTERM with 1s grace then SIGKILL, git worktree remove --force, git branch -D. Best-effort: only errors when all three steps fail (idempotent cleanup-twice). Promotes inline bash from .claude/skills/parallel-fix-issues/ and fn-orquestador to first-class registry functions. Closes issue 0115. Capability group: agents.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: agent_cleanup_worktree
|
||||
kind: function
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "func AgentCleanupWorktree(repoRoot, branch, worktreePath string, pid int) error"
|
||||
description: "Tear-down de un worktree creado por agent_launch_worktree_go_infra: manda SIGTERM al PID (espera 1s, luego SIGKILL si sigue vivo), corre `git worktree remove --force` y `git branch -D` (best-effort cada uno). Devuelve error SOLO si los tres pasos fallan — fallos individuales son esperados (cleanup doble, rama ya borrada, etc.). PID=0 desactiva el kill (util cuando el proceso ya murio o nunca arranco). Linux/Darwin: usa syscall.Kill. Windows: la funcion compila pero el kill nunca hace nada porque syscall.Kill no existe alli — documentar como skip."
|
||||
tags: [agents, worktree, cleanup, git, kill]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: ["fmt", "os/exec", "strings", "syscall", "time"]
|
||||
params:
|
||||
- name: repoRoot
|
||||
desc: "path absoluto al repo principal (el que tiene el worktree registrado)."
|
||||
- name: branch
|
||||
desc: "nombre de la rama a borrar (ej. auto/0115-foo). Vacio = skip."
|
||||
- name: worktreePath
|
||||
desc: "path absoluto al worktree a eliminar. Vacio = skip."
|
||||
- name: pid
|
||||
desc: "PID de claude o 0 para saltarse el kill (proceso ya muerto / nunca arranco)."
|
||||
output: "error nil cuando al menos uno de los tres pasos (kill, worktree remove, branch -D) tuvo exito o se salto. error no-nil solo si los tres fallaron — incluye los tres mensajes para diagnostico."
|
||||
tested: true
|
||||
tests:
|
||||
- "removes worktree dir and branch after launch"
|
||||
- "tolerates missing worktree/branch (cleanup called twice)"
|
||||
test_file_path: "functions/infra/agent_cleanup_worktree_test.go"
|
||||
file_path: "functions/infra/agent_cleanup_worktree.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
err := infra.AgentCleanupWorktree(
|
||||
"/home/lucas/fn_registry",
|
||||
"auto/0115-worktree-launcher-fn",
|
||||
"/home/lucas/fn_registry/worktrees/0115-worktree-launcher-fn",
|
||||
12345, // PID devuelto por AgentLaunchWorktree
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("cleanup partial failure: %v", err)
|
||||
}
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Tras terminar (o abortar) un run lanzado con `agent_launch_worktree_go_infra`. Tambien util en defers de tests para garantizar limpieza: `defer infra.AgentCleanupWorktree(repo, branch, wt, res.PID)`. Si el run sigue corriendo y solo quieres parar el proceso sin tocar git, llama tu mismo a `syscall.Kill(pid, syscall.SIGTERM)` — esta funcion hace mas que eso.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Best-effort por diseño**: cleanup doble no es error. Es deliberado para que `agent_runner_api` pueda llamarla en abort handlers sin meter el sistema en bucle.
|
||||
- **SIGTERM grace 1s**: si claude tarda mas de 1s en cerrar limpiamente, se mata con SIGKILL — los buffers del log pueden quedar parcialmente escritos. Si necesitas mas grace, fork la funcion.
|
||||
- **Windows**: `syscall.Kill` no existe en Windows. El codigo compila pero salta el kill silenciosamente. Para Windows real, swap `syscall.Kill` por `os.Process.Kill()` (requiere abrir el proceso primero con `os.FindProcess`).
|
||||
- **Branch en HEAD del repo principal**: si la rama a borrar es la checked-out branch del repo principal, `git branch -D` falla — pero como worktree elimino ya su HEAD, en la practica nunca pasa con ramas `auto/*`.
|
||||
- **Worktree con cambios sin commitear**: `--force` los descarta. Si necesitas preservar trabajo, commitea y push antes de llamar.
|
||||
Reference in New Issue
Block a user