feat(infra): kill_fleet_agent — cierre dirigido de un ejecutor de la flota (auto-kill)
Cierra UN ejecutor por sessionId (exacto/prefijo) o PID: SIGTERM al proceso claude (cierre limpio, recuperable con --resume) + kill-window de su window tmux. Lo usa el orquestador para liberar el slot idle de cada ejecutor en cuanto verifica que su DoD-contrato esta met. Guards: NO mata a un role=orchestrator (leido del goal.json) ni a la sesion que invoca (PID propio por ancestros /proc). --dry-run para inspeccionar sin tocar nada. Overrides FN_FLEET_* para tests. Tag grupo orchestration. Tests: 17 asserts (golden por sessionId/PID/prefijo, guards orchestrator/self rc=3, errores rc=2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: kill_fleet_agent
|
||||
kind: function
|
||||
lang: bash
|
||||
domain: infra
|
||||
version: 1.0.0
|
||||
purity: impure
|
||||
signature: "kill_fleet_agent <sessionId|PID> [--socket <s>] [--dry-run]"
|
||||
description: "Cierre limpio y dirigido de UN ejecutor de la flota tmux. Dado un sessionId (exacto o prefijo) o un PID, manda SIGTERM al proceso claude del ejecutor (cierre limpio, recuperable con claude --resume) y cierra su window tmux (kill-window) en el socket del perfil FleetView. Lo usa el orquestador para liberar el slot idle de cada ejecutor en cuanto verifica que su DoD-contrato esta met. Guards de seguridad: NUNCA mata a un agente con role=orchestrator (leido de su goal.json) ni a la sesion que invoca la funcion (resuelve su propio PID de claude por los ancestros de /proc). Por defecto EJECUTA; --dry-run imprime el plan sin tocar nada. Es el cierre dirigido a UN agente, frente a reboot_all_claudes que opera sobre toda la flota."
|
||||
tags: [fleet, claude-fleet, orchestration, tmux, kill, infra]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
error_type: error_go_core
|
||||
file_path: "bash/functions/infra/kill_fleet_agent.sh"
|
||||
tested: true
|
||||
tests:
|
||||
- "golden: ejecutor por sessionId, PID y prefijo se resuelve y dry-run imprime el plan"
|
||||
- "guard: matar un role=orchestrator devuelve rc=3 y se niega"
|
||||
- "guard: matar la sesion actual (self) devuelve rc=3 y se niega"
|
||||
- "error: target no resuelto rc=2; sin target rc=2"
|
||||
test_file_path: "bash/functions/infra/kill_fleet_agent_test.sh"
|
||||
params:
|
||||
- name: target
|
||||
desc: "Primer arg posicional: sessionId del ejecutor (exacto o prefijo) o su PID (todo digitos). Por PID se lee sessions/<pid>.json para el sessionId; por sessionId se busca en sessions/*.json el que case y su archivo da el PID."
|
||||
- name: --socket
|
||||
desc: "Socket tmux del perfil FleetView donde vive la window. Default: $FLEET_SOCKET, o 'fleet' si no esta seteada."
|
||||
- name: --dry-run
|
||||
desc: "Imprime el plan (PID, sessionId, role, window, accion) y NO mata el proceso ni cierra la window. Sin esto, ejecuta."
|
||||
output: "Imprime una linea de plan con PID, sessionId, role, socket y window resueltos, seguida de la accion ejecutada (SIGTERM + kill-window) o, con --dry-run, de DRY-RUN. Exit 0 ok/dry-run; 2 uso incorrecto o target no resuelto a PID; 3 guard (target es un orchestrator o la sesion actual)."
|
||||
---
|
||||
|
||||
# kill_fleet_agent
|
||||
|
||||
Cierra de forma dirigida UN ejecutor de la flota tmux: SIGTERM al proceso `claude` (cierre limpio, recuperable con `claude --resume <sessionId>`) más `kill-window` de su window en el socket del perfil FleetView. Es la pieza que el orquestador usa para **liberar el slot idle** de cada ejecutor en cuanto verifica que su DoD-contrato está `met` — sin esto, los ejecutores terminados se acumulan en reposo en la flota.
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
# Cerrar un ejecutor por sessionId (el orquestador lo llama tras verificar `met`):
|
||||
./fn run kill_fleet_agent 32945650-a4e1-472b-90c9-5b38ef60a463 --socket "$FLEET_SOCKET"
|
||||
|
||||
# Por prefijo de sessionId, en el socket por defecto ($FLEET_SOCKET o "fleet"):
|
||||
./fn run kill_fleet_agent 32945650
|
||||
|
||||
# Ver el plan sin matar nada (PID, sessionId, role, window, accion):
|
||||
./fn run kill_fleet_agent 48213 --dry-run
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Úsala desde el modo orquestador justo después de que el verificador independiente devuelva `met` sobre un ejecutor: ciérralo para que no quede ocupando un slot idle en la flota. Resuelve el target por sessionId (exacto o prefijo) o por PID, comprueba los guards y manda SIGTERM + cierra la window. Es el cierre dirigido a **un** agente; para reiniciar/parar **toda** la flota usa `reboot_all_claudes` (con `--exclude-current`). Nunca uses `pkill`/`killall claude` (te matas a ti mismo, el orquestador).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Impura y destructiva**: manda SIGTERM y cierra una window tmux. Por defecto EJECUTA (es el caso de uso del bot: cerrar un ejecutor ya verificado `met`); usa `--dry-run` para inspeccionar antes.
|
||||
- **Guard anti-orquestador**: si el goal.json del target tiene `role=orchestrator`, rehúsa con exit 3. Evita decapitar la flota por error. El `role` se lee de `~/.claude/goals/<sessionId>.json` (lo escribe `mark_claude_role`).
|
||||
- **Guard anti-self**: resuelve el PID de `claude` de la sesión actual subiendo por los ancestros de `/proc`; si el target coincide, rehúsa con exit 3 ("No me suicido"). Es el equivalente dirigido de la regla "nunca `pkill claude`".
|
||||
- **Resolución de la window**: usa `tmux -L <socket> list-panes -a` y casa `pane_pid == PID`. Funciona porque `spawn_fleet_agent` arranca el ejecutor con `exec claude`, así el `pane_pid` ES el PID de claude. Si no hay socket/tmux, la window queda "(no resuelta)" y solo se manda el SIGTERM (best-effort, no falla).
|
||||
- **SIGTERM, no SIGKILL**: cierre limpio para que Claude Code persista su sesión; el trabajo se puede retomar con `claude --resume <sessionId>`.
|
||||
- **Requiere `jq`** para leer los JSON de sessions/goals.
|
||||
- **Overrides de entorno solo para tests**: `FN_FLEET_SESSIONS_DIR`, `FN_FLEET_GOALS_DIR` y `FN_FLEET_SELF_PID` redirigen los directorios y fuerzan el PID propio; no usarlos en operación normal.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
(v1.0.0 — sin cambios todavía.)
|
||||
Reference in New Issue
Block a user