fb76b53c17
El orquestador identificaba cada agente por el campo tmux_window (@N), pero el window_id de tmux cambia cuando un pane entra/sale de windows (el focus de la flota usa break-pane + join-pane, que recrean windows). El pane_id (%N) en cambio es estable durante toda la vida del pane: es el identificador correcto. - claude_fleet.go: nuevo campo ClaudeFleet.PaneID `json:"pane_id"`. Se mantiene TmuxWindow (lo necesita el focus internamente); esto AÑADE pane_id, no lo reemplaza. - resolve_pane_ids.go (+ .md, .go test): nueva función del registry ResolvePaneIDs(socket, pids) -> map[pid]pane_id. Lista los panes del socket (tmux -L <socket> list-panes -a) y para cada PID sube por el árbol de procesos (PPID en /proc) hasta dar con un pane_pid. Reutiliza runTmux y procPPID del paquete infra. Best-effort: tmux/socket caído o PID sin pane -> "" sin crash. Núcleo testeable con inyección de la salida tmux y del resolvedor de PPID. - list_claude_fleet.go: ListClaudeFleet() puebla PaneID resolviendo cada PID vivo contra $FLEET_SOCKET (default "fleet"). Solo la entrada pública lo hace; ListClaudeFleetFrom() queda intacta (cero coste tmux en tests y en el bucle de render de fleetview). Tag de grupo: orchestration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.7 KiB
5.7 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path, notes
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | params | output | tested | tests | test_file_path | file_path | notes | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| list_claude_fleet | function | go | infra | 1.0.0 | impure | func ListClaudeFleetFrom(claudeDir string) ([]ClaudeFleet, error) | func ListClaudeFleet() ([]ClaudeFleet, error) | Lista la flota de procesos Claude Code de la maquina local (Linux). Escanea ~/.claude/sessions/*.json, cruza cada PID vivo contra /proc para validar liveness (anti-PID-reciclado via procStart == campo 22 de /proc/<pid>/stat), une el goal/phase de ~/.claude/goals/<sessionId>.json, extrae KITTY_PID del environ y deriva los campos de display (Target, Rename). Devuelve todas las sesiones ordenadas por status (idle, waiting, busy, otro) y por updatedAt desc; el caller filtra por Alive. Pieza de datos de la app TUI fleetview. |
|
|
|
|
false | error_go_core |
|
Slice de ClaudeFleet (claude_fleet_go_infra), una entrada por sesion con JSON parseable en sessions/. Cada entrada lleva PID, KittyPID, SessionID, Rename, Target, Goal, Phase, Status, Cwd, TmuxWindow (""), PaneID, Alive y UpdatedAt. ListClaudeFleet() puebla PaneID ("%N", identificador estable del pane) cruzando cada PID vivo con los panes del socket $FLEET_SOCKET (default "fleet") via resolve_pane_ids_go_infra; ListClaudeFleetFrom() deja PaneID "" (no hace tmux). Ordenado por rango de status y luego por UpdatedAt descendente. Devuelve slice vacio (sin error) si la carpeta sessions/ no existe; error si no se puede leer la carpeta por otra causa. | true |
|
functions/infra/list_claude_fleet_test.go | functions/infra/list_claude_fleet.go | Misma fuente de verdad que reboot_all_claudes_bash_infra (~/.claude/sessions/<PID>.json de Claude Code 2.1.x: pid, sessionId, cwd, procStart, status, updatedAt). Solo LEE y valida — no relanza ni mata nada. La validacion anti-PID-reciclado replica la del bash (procStart del JSON vs campo 22 de /proc/<pid>/stat) pero parseando de forma robusta el comm (campo 2 entre parentesis, que puede contener espacios y ')'): se toma lo que hay tras el ULTIMO ')' y starttime es el indice 19 de ese resto. TmuxWindow queda "" (se rellena en una fase posterior). Build tag //go:build !windows (depende de /proc, no portable a Windows). |
Ejemplo
package main
import (
"fmt"
"fn-registry/functions/infra"
)
func main() {
fleet, err := infra.ListClaudeFleet() // escanea ~/.claude
if err != nil {
panic(err)
}
for _, c := range fleet {
if !c.Alive {
continue // el caller filtra las sesiones muertas
}
fmt.Printf("[%s] %-20s pid=%d kitty=%d %s\n",
c.Status, c.Rename, c.PID, c.KittyPID, c.Target)
}
}
// Variante testeable: escanea un directorio arbitrario (fixtures en tests).
fleet, _ := infra.ListClaudeFleetFrom("/home/enmanuel/.claude")
fmt.Println(len(fleet), "sesiones conocidas")
Cuando usarla
Cuando necesites enumerar las sesiones de Claude Code vivas en la maquina local para mostrarlas, monitorizarlas o actuar sobre ellas (TUI fleetview, dashboards, automatizaciones). Da el join PID -> sessionId -> cwd -> goal/phase ya resuelto y validado contra /proc, en lugar de reimplementarlo a mano cada vez. Usa ListClaudeFleetFrom en tests (inyectando un directorio con fixtures) y ListClaudeFleet en runtime real.
Gotchas
- Impura: lee el filesystem y /proc. No es determinista entre llamadas (las sesiones nacen y mueren). Solo lectura — nunca mata ni relanza procesos.
- Anti-PID-reciclado.
Alivesolo es true si el proceso existe Y su starttime (campo 22 de/proc/<pid>/stat) coincide con elprocStartdel JSON. Un JSON huerfano cuyo PID fue reasignado a otro proceso se marcaAlive=falseaunque ese PID este vivo. Si el JSON no traeprocStart, basta con que el proceso exista. - Parseo del
commen /proc//stat. El campo 2 (comm) va entre parentesis y puede contener espacios y el caracter ')'. La funcion parsea tomando lo que hay tras el ULTIMO ')'; un split ingenuo por espacios daria un starttime equivocado. - /proc no es portable. Build tag
//go:build !windows; depende de/proc/<pid>/staty/proc/<pid>/environ(Linux). En macOS/BSD no funciona tal cual. - environ ilegible -> KittyPID=0. Si
/proc/<pid>/environno es legible (permisos, proceso de otro usuario, o el proceso ya murio entre el ReadDir y el ReadFile)KittyPIDcae a 0 sin error. Tambien es 0 legitimamente cuando claude no corre bajo kitty (ej. tmux remoto). - Devuelve TODAS las sesiones con JSON parseable, vivas o muertas. El caller decide filtrar por
Alive. Archivos no-.jsony JSON corrupto se ignoran silenciosamente. - TmuxWindow siempre "". Esta funcion no resuelve el window_id (@N); lo rellena el consumidor (fleetview) cuando lo necesita para el focus.
- PaneID lo puebla solo
ListClaudeFleet(), noListClaudeFleetFrom(). La variante con directorio (usada en tests y en bucles de render calientes) no llama a tmux: dejaPaneID"". La publica resuelve el pane_id ("%N") contra$FLEET_SOCKET(default "fleet") viaresolve_pane_ids_go_infra. Si el socket no existe o tmux no responde, todos losPaneIDquedan "" sin error. El pane_id es estable de por vida del pane (inmune a los swaps de window que mueve el focus), a diferencia deTmuxWindow.