diff --git a/tmux-host/healthcheck.sh b/tmux-host/healthcheck.sh index 2ed9299..fe9a537 100755 --- a/tmux-host/healthcheck.sh +++ b/tmux-host/healthcheck.sh @@ -8,12 +8,13 @@ # del lab-agent ya esta configurado) -- nunca se intenta "arreglar" # la red del host desde aca, eso puede ser un problema de # hardware/BIOS fuera del alcance del contenedor. -# b) Existencia de la sesion tmux "lab". Si no existe (crash, o el -# contenedor se acaba de recrear), SI se recrea automaticamente -- -# es solo recuperar el propio entorno de trabajo, no tocar -# infraestructura externa. Al recrearla tambien se lanza `claude` -# adentro (ver launch_claude_in_session) -- una sesion recreada sin -# esto es un shell pelado, no "el entorno de trabajo". +# b) Existencia de cada sesion tmux en SESSIONS (ver mas abajo -- hoy +# "lab" y "cloud-practice"). Si no existe (crash, o el contenedor +# se acaba de recrear), SI se recrea automaticamente -- es solo +# recuperar el propio entorno de trabajo, no tocar infraestructura +# externa. Al recrearla tambien se lanza `claude` adentro (ver +# launch_claude_in_session) -- una sesion recreada sin esto es un +# shell pelado, no "el entorno de trabajo". # # Todo evento (chequeo ok, falla, accion tomada) queda en LOG_FILE, que # vive bajo /DATA (persistente, sobrevive a recrear el contenedor) y no @@ -24,7 +25,15 @@ set -uo pipefail WORKDIR="/DATA/AppData/k3d-lab-v3/lab-cruzcloud" -SESSION="lab" +# Cada entrada: "nombre-sesion:workdir". "cloud-practice" agregada +# 2026-09-20 (ver ADR 0012, practica multi-cloud) -- vive en un +# subdirectorio de WORKDIR (repo platform-multicloud ya clonado ahi), +# asi que el mismo wait_for_workdir() de abajo (que solo espera por el +# WORKDIR padre) ya cubre el caso de arranque en frio para las dos. +SESSIONS=( + "lab:${WORKDIR}" + "cloud-practice:${WORKDIR}/platform-multicloud" +) LOG_DIR="/DATA/AppData/k3d-lab-v3/tmux-host/logs" LOG_FILE="${LOG_DIR}/health.log" # Reusa el mismo canal de Telegram que ya configuro scripts/lab-agent/ -- @@ -105,6 +114,7 @@ check_network() { } launch_claude_in_session() { + local session="$1" # El pane recien creado tarda un instante en tener su shell listo para # recibir input -- un send-keys inmediato a veces se pierde. 1s alcanza # sobrado para un shell interactivo local (no depende de red). @@ -113,47 +123,53 @@ launch_claude_in_session() { # controlable remotamente en claude.ai (confirmado en vivo 2026-09-20 -- # sin la flag, "remoteEnabled" queda en false para siempre porque nadie # la pide). El nombre de sesion remota usa el hostname del contenedor - # (ZimaOS) como prefijo por defecto. + # (ZimaOS) como prefijo por defecto -- con 2 sesiones corriendo + # "claude --remote-control" a la vez, cada una aparece como una sesion + # remota distinta en claude.ai (mismo prefijo de host, pero cada una + # con su propio ID de sesion real). # --continue (-c): retoma la conversacion mas reciente en WORKDIR en vez # de arrancar una sesion en blanco cada vez que se recrea el pane (reinicio # del NAS, crash del contenedor, etc). Si no hay conversacion previa en el # directorio, el propio CLI arranca una nueva sin error. - if tmux send-keys -t "$SESSION" "claude --remote-control --continue" Enter 2>>"$LOG_FILE"; then - log "TMUX: 'claude --remote-control --continue' lanzado dentro de la sesion recien creada" + if tmux send-keys -t "$session" "claude --remote-control --continue" Enter 2>>"$LOG_FILE"; then + log "TMUX: 'claude --remote-control --continue' lanzado dentro de la sesion '${session}' recien creada" else - log "TMUX: ERROR al lanzar 'claude --remote-control --continue' dentro de la sesion recien creada" + log "TMUX: ERROR al lanzar 'claude --remote-control --continue' dentro de la sesion '${session}' recien creada" fi } check_tmux_session() { - if tmux has-session -t "$SESSION" 2>/dev/null; then - log "TMUX: sesion '${SESSION}' ok" + local session="$1" workdir="$2" + if tmux has-session -t "$session" 2>/dev/null; then + log "TMUX: sesion '${session}' ok" return fi - if [[ ! -d "$WORKDIR" ]]; then - # No se crea sobre un WORKDIR ausente (quedaria posicionada en /). Se + if [[ ! -d "$workdir" ]]; then + # No se crea sobre un workdir ausente (quedaria posicionada en /). Se # reintenta en el proximo ciclo -- ver STARTUP_MOUNT_WAIT_MAX_SEC arriba # para el caso especifico de arranque en frio del host. - log "TMUX: sesion '${SESSION}' no existe y ${WORKDIR} tampoco -- no se crea esta vuelta, se reintenta en el proximo ciclo (${INTERVAL_SEC}s)." + log "TMUX: sesion '${session}' no existe y ${workdir} tampoco -- no se crea esta vuelta, se reintenta en el proximo ciclo (${INTERVAL_SEC}s)." return fi - log "TMUX: sesion '${SESSION}' no existe -- recreando en ${WORKDIR}" - if tmux new-session -d -s "$SESSION" -c "$WORKDIR" 2>>"$LOG_FILE"; then - log "TMUX: sesion '${SESSION}' recreada exitosamente" + log "TMUX: sesion '${session}' no existe -- recreando en ${workdir}" + if tmux new-session -d -s "$session" -c "$workdir" 2>>"$LOG_FILE"; then + log "TMUX: sesion '${session}' recreada exitosamente" # Una sesion recreada sin esto es un shell vacio hasta que alguien # entre a mano y escriba "claude" -- exactamente el gotcha reportado # tras el reinicio completo del NAS del 2026-09-18/19: la sesion SI se # recreaba sola (confirmado en el log de ese arranque), pero Claude # Code nunca arrancaba adentro. - launch_claude_in_session + launch_claude_in_session "$session" else - log "TMUX: ERROR al recrear la sesion '${SESSION}'" + log "TMUX: ERROR al recrear la sesion '${session}'" fi } log "=== healthcheck inicio (intervalo=${INTERVAL_SEC}s) ===" while true; do check_network - check_tmux_session + for entry in "${SESSIONS[@]}"; do + check_tmux_session "${entry%%:*}" "${entry#*:}" + done sleep "$INTERVAL_SEC" done