Actualizar un servidor con el agente en una carpeta NO estandar terminaba en
verde y lo dejaba con la version anterior. Todo el camino de Windows
identificaba al agente por NOMBRE, mientras que lo unico que se actualiza se
identifica por RUTA; en cuanto las dos no coincidian, nada fallaba y nada
cambiaba.
- Se alinea la tarea programada con el binario instalado. `Start-ScheduledTask`
ejecuta la ruta registrada en su accion, no el -Prefix: si difieren, se copiaba
el binario nuevo en un sitio y se arrancaba el viejo del otro. Ahora se
reapunta conservando disparador, principal, ajustes y argumentos; si no se
puede corregir, FALLA — arrancar a sabiendas el binario anterior es peor.
- La confirmacion de arranque mira la RUTA del proceso. Un agente viejo que
nunca se detuvo satisfacia igual de bien un `Get-Process -Name`. Si la ruta no
es legible (un proceso de SYSTEM no la expone sin elevacion) se acepta por
nombre y se avisa, en vez de revertir una actualizacion correcta por falta de
informacion.
- Corregido Merge-EnvFile con un config\.env de UNA linea: al asignar la salida
de un `if`, PowerShell desenrolla un array de un elemento a escalar, asi que
$lines.Count reventaba con Set-StrictMode y la siembra abortaba la instalacion.
Nuevo scripts/emular-actualizacion-windows.ps1: monta un agente falso (un .exe
real que se queda vivo), una instalacion en una carpeta y una tarea apuntando a
otra, corre el instalador y dice si la actualizacion surtio efecto. Sin elevacion
y sin tocar la instalacion real de la maquina. Es lo que destapo los dos
defectos: contra el instalador anterior reproduce el sintoma exacto —codigo de
salida 0 y "El agente esta corriendo con el binario nuevo" sobre un servidor
intacto— y contra este confirma que ya surte efecto, sin tocar la tarea cuando
ya estaba bien.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
install.sh recibió la maquinaria de actualización segura y install.ps1 nunca
recibió el equivalente. La asimetría se notaba en producción: actualizar desde
el PANEL dejaba el servidor sin agente.
- -UpdateInPlace: actualiza conservando la tarea y la configuración, sin correr
el bootstrap (una segunda instancia purga el Temp\ de la que está viva).
- No se interrumpe una restauración en curso: sale con 75 (EX_TEMPFAIL), que el
PANEL traduce a "reintenta luego". Windows no tenía esta guarda y una
reinstalación a destiempo dejaba el respaldo vetado y la base en SINGLE_USER.
- Respaldo del binario anterior y reversión automática si el nuevo no arranca.
- Rearranque garantizado en TODOS los modos: la detención corría siempre, pero
solo -Service volvía a arrancar algo.
- Espera de liberación del .exe de 5s a 30s con reintentos de la copia.
- Se distingue "no es administrador" de "es administrador con el token filtrado
por UAC", que es lo que recibe una sesión de OpenSSH. Se veían idénticos y el
remedio es el opuesto.
Y --headless deja de ser un no-op en Windows: _ensure_qt_platform() salía de
inmediato en win32, así que la tarea ONSTART arrancaba como SYSTEM en la sesión 0
con el plugin Qt 'windows' intentando crear una ventana real. En Linux el unit
fija QT_QPA_PLATFORM=offscreen por fuera, y esa asimetría escondió el defecto.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>