diff --git a/tmux-host/healthcheck.sh b/tmux-host/healthcheck.sh index c90183c..ea540d0 100755 --- a/tmux-host/healthcheck.sh +++ b/tmux-host/healthcheck.sh @@ -11,7 +11,9 @@ # 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. +# 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 @@ -31,13 +33,42 @@ LOG_FILE="${LOG_DIR}/health.log" LAB_AGENT_ENV="${WORKDIR}/scripts/lab-agent/lab-agent.env" NETWORK_CHECK_URL="https://gitea.cruzcloud.net/" INTERVAL_SEC="${HEALTHCHECK_INTERVAL_SEC:-1800}" +# Cuanto esperar, SOLO al arrancar, a que WORKDIR este disponible antes de +# tocarlo. Tras un `docker restart` normal el host y sus mounts ya estaban +# arriba; tras un reinicio COMPLETO del NAS (corte de luz), Docker puede +# arrancar este contenedor antes de que /media/HDD-Storage termine de +# montarse en el host -- y WORKDIR llega a el via el symlink absoluto +# /DATA/AppData -> /media/HDD-Storage/AppData (ver el gotcha del symlink en +# docs-portal/docs/arquitectura/sesion-tmux-persistente.md). Sin esta +# espera, `mkdir -p "$LOG_DIR"` de mas abajo fallaba en silencio (set -u sin +# -e) y ese arranque quedaba SIN NINGUN rastro en el log -- asi se paso por +# alto originalmente el gotcha de "no lanzo claude" reportado 2026-09-19. +STARTUP_MOUNT_WAIT_MAX_SEC="${STARTUP_MOUNT_WAIT_MAX_SEC:-120}" +STARTUP_MOUNT_WAIT_STEP_SEC=5 -mkdir -p "$LOG_DIR" +wait_for_workdir() { + local waited=0 + while [[ ! -d "$WORKDIR" ]] && [[ "$waited" -lt "$STARTUP_MOUNT_WAIT_MAX_SEC" ]]; do + sleep "$STARTUP_MOUNT_WAIT_STEP_SEC" + waited=$((waited + STARTUP_MOUNT_WAIT_STEP_SEC)) + done + echo "$waited" +} + +STARTUP_WAITED_SEC="$(wait_for_workdir)" + +mkdir -p "$LOG_DIR" 2>/dev/null || true log() { - echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG_FILE" + echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG_FILE" 2>/dev/null || true } +if [[ ! -d "$WORKDIR" ]]; then + log "ARRANQUE: ERROR -- ${WORKDIR} sigue sin existir tras esperar ${STARTUP_MOUNT_WAIT_MAX_SEC}s. El mount de /DATA o /media/HDD-Storage del host no esta listo; revisar fuera del contenedor." +elif [[ "$STARTUP_WAITED_SEC" -gt 0 ]]; then + log "ARRANQUE: ${WORKDIR} tardo ${STARTUP_WAITED_SEC}s en estar disponible (probable reinicio completo del host reordenando el montaje de /DATA)." +fi + notify_telegram() { local title="$1" message="$2" if [[ ! -f "$LAB_AGENT_ENV" ]]; then @@ -73,14 +104,39 @@ check_network() { fi } +launch_claude_in_session() { + # 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). + sleep 1 + if tmux send-keys -t "$SESSION" "claude" Enter 2>>"$LOG_FILE"; then + log "TMUX: 'claude' lanzado dentro de la sesion recien creada" + else + log "TMUX: ERROR al lanzar 'claude' dentro de la sesion recien creada" + fi +} + check_tmux_session() { 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 + # 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)." + 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" + # 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 else log "TMUX: ERROR al recrear la sesion '${SESSION}'" fi