#!/usr/bin/env bash # detect_fleet_context — detecta de forma robusta si el proceso actual corre # dentro de una sesion tmux de una flota FleetView, derivando el socket y la # sesion de la variable de entorno $TMUX (senal fiable) en vez de depender de # $FLEET_SOCKET (que a veces viene vacia en el entorno de un claude resumido o # relanzado, aunque ese claude SI viva en una window de la flota). # # Por que $TMUX y no $FLEET_SOCKET: # launch_fleetclaude exporta FLEET_SOCKET/FLEET_SESSION con `tmux # set-environment -g`. Esa variable solo llega a los procesos que tmux arranca # DESPUES de setearla; un claude relanzado o resumido a mano puede no heredarla # y entonces $FLEET_SOCKET queda vacia. En cambio, todo proceso que corre # dentro de tmux tiene SIEMPRE $TMUX seteada, con el formato: # /tmp/tmux-/,, # De ahi se extrae el socket (basename del path antes de la primera coma) y, # con `tmux -L display-message -p '#{session_name}'`, la sesion # actual. Eso identifica el contexto fleet sin depender de $FLEET_SOCKET. # # Salida: JSON en stdout con los campos: # in_fleet : true|false — heuristica de "estoy en una flota" (ver criterio). # in_tmux : true|false — estoy dentro de tmux (basta para lanzar una window). # socket : nombre del socket tmux derivado ("" si no hay). # session : nombre de la sesion tmux actual ("" si no se resuelve). # source : "tmux" | "fleet_socket" | "none" — de donde se derivo el contexto. # # Criterio de "flota reconocible" (in_fleet): estar en tmux (in_tmux) Y que se # cumpla al menos uno, de mas fiable a menos: # 1. el socket o la sesion casan el patron de flota (contienen "fleet"), o # 2. existe una window llamada "fleetview" (la TUI de la flota), o # 3. la sesion tiene >= 2 windows (una flota agrupa varios agentes en windows). # Es heuristico a proposito: para LANZAR un ejecutor basta con in_tmux (lanzar # una window en cualquier tmux es mejor que caer a una kitty suelta); in_fleet es # la senal semantica que consume el hook del orquestador y la doctrina. # # Funcion IMPURA: lee el entorno y consulta el servidor tmux (display-message, # list-windows). No modifica estado. Degrada limpio: si tmux no esta o falla # cualquier consulta, devuelve los campos que pueda y nunca aborta con error. set -euo pipefail IFS=$' \t\n' detect_fleet_context() { local socket="" session="" source="none" local in_tmux="false" in_fleet="false" if [[ -n "${TMUX:-}" ]]; then in_tmux="true" source="tmux" # $TMUX = /tmp/tmux-/,, # Socket = basename del path antes de la primera coma. local tmux_path="${TMUX%%,*}" socket="$(basename "$tmux_path" 2>/dev/null || true)" # Sesion actual: tmux resuelve el cliente via $TMUX. -L fija el socket. if command -v tmux >/dev/null 2>&1 && [[ -n "$socket" ]]; then session="$(tmux -L "$socket" display-message -p '#{session_name}' 2>/dev/null || true)" fi # Fallback de sesion si display-message no resolvio nada. [[ -z "$session" ]] && session="${FLEET_SESSION:-$socket}" elif [[ -n "${FLEET_SOCKET:-}" ]]; then # No estamos en tmux pero hay FLEET_SOCKET exportada: usarla como ultimo # recurso (un claude que perdio $TMUX pero conserva la env del perfil). in_tmux="false" source="fleet_socket" socket="${FLEET_SOCKET}" session="${FLEET_SESSION:-$socket}" fi # Heuristica in_fleet: solo tiene sentido si estamos en tmux. if [[ "$in_tmux" == "true" && -n "$socket" ]]; then local sl="${socket,,}" sesl="${session,,}" if [[ "$sl" == *fleet* || "$sesl" == *fleet* ]]; then in_fleet="true" elif command -v tmux >/dev/null 2>&1; then # Construir el target de sesion sin trucos de expansion fragiles. local -a tgt=() [[ -n "$session" ]] && tgt=(-t "$session") # window "fleetview" presente => flota. if tmux -L "$socket" list-windows "${tgt[@]}" \ -F '#{window_name}' 2>/dev/null | grep -qx 'fleetview'; then in_fleet="true" else # >= 2 windows => agrupacion tipo flota. local nwin nwin="$(tmux -L "$socket" list-windows "${tgt[@]}" \ -F x 2>/dev/null | wc -l | tr -d ' ')" [[ "${nwin:-0}" -ge 2 ]] && in_fleet="true" fi fi fi # JSON sin dependencias (jq/python no requeridos: este es el detector base). printf '{"in_fleet":%s,"in_tmux":%s,"socket":"%s","session":"%s","source":"%s"}\n' \ "$in_fleet" "$in_tmux" "$socket" "$session" "$source" return 0 } # Permitir ejecutar el archivo directamente (no solo como funcion sourced). if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then detect_fleet_context "$@" fi