feat: spawn de ejecutores en la flota tmux (flow 0012, gap 1 cerrado)
- spawn_fleet_agent (bash/functions/infra): lanza un Claude como window de la sesion tmux de un perfil fleet (no kitty suelta), con --skill para arrancar en un modo (ej. /orquestador), --prompt-file para ejecutores autocontenidos, y --role para marcar el goal.json via mark_claude_role. Asi ejecutores y orquestador viven en la flota, visibles en fleetview y conmutables con /fleet focus. - skill /orquestador: paso 2 ahora prefiere spawn_fleet_agent sobre kitty cuando se opera dentro de un perfil fleet ($FLEET_SOCKET seteado); tabla de funciones del grupo actualizada. Validado en vivo: el orquestador arranca en la flota fleet2 en modo (MODO ORQUESTADOR activo), role=orchestrator marcado, pinneado arriba en la TUI; los 9 ejecutores existentes intactos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env bash
|
||||
# spawn_fleet_agent — lanza un Claude como window nueva dentro de la sesion tmux
|
||||
# de un perfil FleetView (socket aislado), opcionalmente en modo orquestador
|
||||
# (skill embebida) y marcado con un role en su goal.json.
|
||||
#
|
||||
# Es la forma de que un ejecutor —o el propio orquestador— VIVA en la flota tmux
|
||||
# (visible en la TUI fleetview, conmutable con /fleet focus), en vez de en una
|
||||
# kitty suelta. Reemplaza a launch_claude_agent_kitty cuando se opera dentro de
|
||||
# un perfil fleet ya montado.
|
||||
#
|
||||
# Funcion IMPURA: crea procesos (tmux window + claude) y, si se pide --role,
|
||||
# marca el goal.json del nuevo Claude via mark_claude_role (en background, porque
|
||||
# el sessionId no existe hasta que Claude escribe sessions/<PID>.json).
|
||||
set -euo pipefail
|
||||
IFS=$' \t\n'
|
||||
|
||||
spawn_fleet_agent() {
|
||||
local socket="" session="" cwd="" prompt_file="" skill="" role="" title="claude"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--socket) shift; socket="${1:-}" ;;
|
||||
--session) shift; session="${1:-}" ;;
|
||||
--cwd) shift; cwd="${1:-}" ;;
|
||||
--prompt-file) shift; prompt_file="${1:-}" ;;
|
||||
--skill) shift; skill="${1:-}" ;;
|
||||
--role) shift; role="${1:-}" ;;
|
||||
--title) shift; title="${1:-claude}" ;;
|
||||
-h|--help)
|
||||
cat <<'USAGE'
|
||||
Uso: spawn_fleet_agent --socket <s> --session <s> --cwd <dir> [opciones]
|
||||
|
||||
Lanza un Claude como window nueva en la sesion tmux <session> del socket <socket>
|
||||
(un perfil FleetView ya montado). Imprime el window_id creado.
|
||||
|
||||
Opciones:
|
||||
--prompt-file <f> Primer prompt del Claude = contenido del archivo (prompt
|
||||
autocontenido del ejecutor). El cat lo hace el shell del
|
||||
pane, asi que admite prompts multi-linea.
|
||||
--skill <name> Primer prompt = "/<name>" (invoca un skill al arrancar, ej.
|
||||
--skill orquestador para arrancar en modo orquestador).
|
||||
--role <r> Marca el goal.json del nuevo Claude: orchestrator|executor
|
||||
(via mark_claude_role, en background). Sin esto, executor
|
||||
implicito.
|
||||
--title <t> Nombre de la window tmux. Default: claude.
|
||||
|
||||
Ejemplos:
|
||||
# Orquestador en la flota actual:
|
||||
spawn_fleet_agent --socket fleet2 --session fleet2 --cwd ~/fn_registry \
|
||||
--skill orquestador --role orchestrator --title orquestador
|
||||
# Ejecutor con tarea autocontenida:
|
||||
spawn_fleet_agent --socket fleet2 --session fleet2 --cwd ~/fn_registry \
|
||||
--prompt-file /tmp/orq_health.md --title "kanban-health"
|
||||
USAGE
|
||||
return 0 ;;
|
||||
*)
|
||||
echo "spawn_fleet_agent: opcion desconocida '$1' (usa -h)" >&2
|
||||
return 2 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
[[ -z "$socket" || -z "$session" ]] && {
|
||||
echo "spawn_fleet_agent: --socket y --session son obligatorios" >&2
|
||||
return 2
|
||||
}
|
||||
[[ -z "$cwd" ]] && cwd="$PWD"
|
||||
|
||||
command -v tmux >/dev/null 2>&1 || {
|
||||
echo "spawn_fleet_agent: tmux no esta instalado" >&2
|
||||
return 1
|
||||
}
|
||||
if ! tmux -L "$socket" has-session -t "$session" 2>/dev/null; then
|
||||
echo "spawn_fleet_agent: la sesion '$session' no existe en el socket '$socket' (lanza la flota primero)" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Window nueva detached + claude. send-keys con exec para que el pane_pid sea
|
||||
# el de claude (no el del shell), necesario para mark_claude_role.
|
||||
local win_pane win_id
|
||||
win_pane=$(tmux -L "$socket" new-window -d -t "$session" -n "$title" -c "$cwd" -P -F '#{pane_id}')
|
||||
|
||||
if [[ -n "$skill" ]]; then
|
||||
# Skill como primer prompt: "/<skill>". Claude Code lo interpreta como
|
||||
# invocacion de slash command al arrancar.
|
||||
tmux -L "$socket" send-keys -t "$win_pane" \
|
||||
"exec claude --dangerously-skip-permissions '/$skill'" C-m
|
||||
elif [[ -n "$prompt_file" ]]; then
|
||||
[[ -f "$prompt_file" ]] || {
|
||||
echo "spawn_fleet_agent: --prompt-file '$prompt_file' no existe" >&2
|
||||
return 1
|
||||
}
|
||||
# El cat lo ejecuta el shell del pane: admite prompts multi-linea.
|
||||
tmux -L "$socket" send-keys -t "$win_pane" \
|
||||
"exec claude --dangerously-skip-permissions \"\$(cat $(printf '%q' "$prompt_file"))\"" C-m
|
||||
else
|
||||
tmux -L "$socket" send-keys -t "$win_pane" \
|
||||
"exec claude --dangerously-skip-permissions" C-m
|
||||
fi
|
||||
|
||||
# Marcar role en background (no-fatal). El sleep da tiempo a que el `exec
|
||||
# claude` reemplace al shell antes de leer el pane_pid; mark_claude_role luego
|
||||
# espera a que aparezca sessions/<PID>.json para resolver el sessionId.
|
||||
if [[ -n "$role" ]]; then
|
||||
local repo_root fn_bin
|
||||
repo_root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel 2>/dev/null || echo "${FN_REGISTRY_ROOT:-$HOME/fn_registry}")"
|
||||
fn_bin="$repo_root/fn"
|
||||
if [[ -x "$fn_bin" ]]; then
|
||||
( sleep 1
|
||||
pid=$(tmux -L "$socket" display-message -p -t "$win_pane" '#{pane_pid}' 2>/dev/null || true)
|
||||
[[ -n "$pid" ]] && "$fn_bin" run mark_claude_role "$pid" "$role" >/dev/null 2>&1
|
||||
) >/dev/null 2>&1 &
|
||||
disown 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
win_id=$(tmux -L "$socket" display-message -p -t "$win_pane" '#{window_id}' 2>/dev/null || true)
|
||||
echo "$win_id"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Permitir ejecutar el archivo directamente (no solo como funcion sourced).
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
spawn_fleet_agent "$@"
|
||||
fi
|
||||
Reference in New Issue
Block a user