# Actualización del propio ejecutable

> HTML: https://remote.ivjn.us/docs/es/self-update/

La CLI y el agente independiente pueden actualizar su propio ejecutable desde el sitio de publicación en Windows x64/arm64, Linux x64/arm64 (compilaciones glibc y musl estáticas), macOS Apple Silicon y FreeBSD/NetBSD x64/arm64:

```sh
remote-cli update self --check
remote-cli update self
remote-agent update self --check
remote-agent update self
```

| Plataforma | Archivo de versión | Reinicio tras un `remote-agent update self` puntual |
| --- | --- | --- |
| Windows x64 / arm64 | `remote-windows-x64.zip` / `remote-windows-arm64.zip` | Tarea programada `RemoteAgent`, después reinicio del proceso |
| Linux glibc x64 / arm64 | `remote-linux-x64.tar.gz` / `remote-linux-arm64.tar.gz` | Unidad systemd de sistema o de usuario, OpenRC, después reinicio del proceso |
| Linux musl x64 / arm64 | `remote-linux-musl-x64.tar.gz` / `remote-linux-musl-arm64.tar.gz` | Igual que Linux glibc |
| macOS Apple Silicon | `remote-macos-arm64.tar.gz` | LaunchAgent `us.ivjn.remote-agent` |
| FreeBSD / NetBSD x64 / arm64 | `remote-freebsd-*.tar.gz` / `remote-netbsd-*.tar.gz` | rc.d `remote_agent` de `remote-agent install --system`; si no, reinicio manual |

El actualizador conserva la biblioteca C del ejecutable en uso: una compilación musl solo instala el archivo musl y una glibc solo el archivo glibc. OpenWrt sigue usando opkg/apk incluso en x64/arm64: sus paquetes no incluyen el actualizador por archivo, y un archivo musl que se ejecuta en un host con `/etc/openwrt_release` rechaza la autoactualización. Una plataforma solo se actualiza si su archivo figura en el manifiesto; las instalaciones compiladas antes de que se admitiera esa plataforma deben reemplazarse manualmente una vez.

No se necesita iniciar sesión ni configurar un dispositivo.

Para una primera instalación del agente, con binario, configuración privada e inicio automático del sistema, utiliza preferentemente `remote-agent install` / `remote-agent uninstall` en Linux, macOS y Windows; consulta [platforms.md](/docs/es/platform-installation.md). Ese comando no necesita acceso a la red y el emparejamiento se realiza por separado. Una vez instalado un binario que incluya `install`, las siguientes actualizaciones pueden usar `update self` o la actualización automática donde esté disponible.

`--check` compara el SHA-256 del ejecutable en el manifiesto sin descargar el archivo. Si faltan esos metadatos, descarga y verifica el archivo. Los hashes distinguen compilaciones con la misma versión; la comprobación no modifica la instalación. La instalación rechaza versiones anteriores y verifica versión, tamaño y hash del ejecutable.

La fuente predeterminada es `https://r2.ivjn.us`, el dominio público R2 que aloja `downloads/`. `--source https://your-mirror.example/releases` selecciona un espejo de confianza con el mismo `downloads/manifest.json` y la misma estructura de archivos. GitHub Releases ([versiones de mbcc2006/remote-control](/#downloads)) publica los mismos tipos de archivos de escritorio como canal **adicional**. No sustituye la estructura del sitio y la actualización sigue usando `r2.ivjn.us` salvo que `--source` apunte a un espejo que sirva `downloads/manifest.json`. Solo se acepta HTTPS, se rechazan las redirecciones y no se envía ningún token de cuenta. El nombre del archivo se elige según el sistema operativo y la arquitectura actuales; se verifican tamaño y SHA-256 contra el manifiesto HTTPS y solo se extrae la entrada exacta del ejecutable. Antes de confiar en el manifiesto, los clientes de escritorio verifican `downloads/manifest.json.sig` con claves públicas Ed25519 integradas. Una firma ausente, bytes modificados o claves desconocidas impiden la actualización. Los espejos deben servir el manifiesto firmado y la firma sin cambios; publique la firma antes de distribuir clientes que la exijan.

Antes de instalar, el nuevo ejecutable debe superar una comprobación `--version` con tiempo limitado. Un archivo `.update.lock` junto al ejecutable serializa las actualizaciones y se vuelve a comprobar el ejecutable actual para detectar sustituciones simultáneas. Solo se modifican el ejecutable y sus archivos de actualización o copia de seguridad; se conservan IDs, credenciales y configuraciones.

En macOS, el ejecutable descargado también debe superar `codesign --verify --strict` antes de comprobar la versión. La sustitución conserva la firma publicada y sus bytes, de modo que las siguientes comparaciones de hashes sean estables.

El ejecutable anterior se conserva como `<executable>.previous`. Si hace falta, detén el agente y restaura ese archivo en la ruta original. En Windows, el ejecutable cargado se renombra a la copia de seguridad antes de instalar el nuevo; si falla la instalación, se restaura el nombre original.

Tras un `remote-agent update self` exitoso, sin `--check`, el actualizador intenta reiniciar el agente en ejecución para cargar el nuevo ejecutable: en Linux (glibc y musl) ejecuta `systemctl restart remote-agent`, luego `systemctl --user restart remote-agent` y, si existe `/etc/init.d/remote-agent`, `rc-service remote-agent restart` (OpenRC); si nada de eso está disponible, reinicia con SIGTERM otros demonios `remote-agent` con sus argumentos anteriores. En Windows (x64 y arm64) reinicia la tarea programada `RemoteAgent`, con alternativa a nivel de proceso. En FreeBSD/NetBSD ejecuta el script rc.d `remote_agent restart` instalado por `remote-agent install --system` y, si no existe, indica que hace falta un reinicio manual. Si el proceso que se actualiza es el propio demonio (argumentos distintos de `update self`), hace `exec` del nuevo ejecutable en Unix (conservando el PID para los supervisores) o inicia un reemplazo desvinculado en Windows. `remote-cli update self` nunca reinicia un agente. Las líneas de estado indican si el reinicio usó systemd, OpenRC, rc.d, una tarea programada, un proceso nuevo o no pudo realizarse (la actualización en sí sigue siendo correcta). Ejecútelo con los permisos del propietario de la instalación; el actualizador no eleva privilegios. Las líneas de comando registradas durante el reinicio ocultan los valores de `--token`. Si un agente de Windows anterior sigue ejecutándose desde la copia de seguridad, reinícielo antes de volver a actualizar.

## Actualización automática del daemon de escritorio

Mientras el daemon Agent está en ejecución, y no en una operación puntual `update self`, **consulta periódicamente** el mismo manifiesto web y aplica una actualización si el hash del binario publicado `remote-agent` es diferente. Valores predeterminados:

- **Activada de forma predeterminada** en las compilaciones de escritorio compatibles: Windows x64/arm64, Linux x64/arm64 glibc y musl, macOS arm64, FreeBSD y NetBSD x64/arm64.
- Se desactiva con `REMOTE_AUTO_UPDATE=0`, también `false` / `no` / `off`, con `"auto_update": false` en JSON o con `--auto-update false` en la CLI.
- Primera comprobación unos 90 segundos después del inicio; después, aproximadamente cada 12 horas, no en cada latido.
- Registra el progreso claramente y **nunca** envía el token del dispositivo a la CDN de actualizaciones.
- OpenWrt (incluido un archivo musl en un host OpenWrt) omite la actualización automática de escritorio; Android usa su propia ruta OTA. Las arquitecturas sin correspondencia, como Mac Intel o ARM de 32 bits, devuelven un error de archivo de versión inexistente y no pueden actualizarse automáticamente.

## Actualización remota del operador al dispositivo

Los operadores con una sesión normal de dispositivo, con la misma ACL que `OpenExec`, pueden solicitar a un dispositivo conectado que compruebe o aplique una actualización.

Protocolo JSON de WebSocket:

- `OperatorUp::update_device` `{ session_id, device_id, check_only, source? }`.
- Exchange → `DeviceDown::update_req`.
- Dispositivo → `DeviceUp::update_status` / `OperatorDown::update_status` progresivos con `phase`:
  `checking` | `downloading` | `applying` | `up_to_date` | `available` | `applied` | `error`.

Consola: en el detalle del dispositivo, **Comprobar actualizaciones** / **Enviar actualización**.

CLI, siguiendo el mismo patrón que otras operaciones de sesión:

```sh
remote-cli device update <device_id> --check
remote-cli device update <device_id>
remote-cli device update <device_id> --source https://r2.ivjn.us
```

Cuando LAN está activada, el control LAN traduce `update_device` igual que los demás mensajes open-* de `OperatorUp`.

Los agentes de OpenWrt y otras plataformas no compatibles devuelven una fase `error` clara en lugar de instalar un artefacto incorrecto. Windows arm64, Linux musl, macOS Apple Silicon y FreeBSD/NetBSD usan la misma ruta de archivo de escritorio que Windows x64 y Linux glibc.

## OTA del agente Android

El APK del agente Android, `remote-agent-android.apk` en el sitio, puede actualizarse desde el mismo manifiesto HTTPS.

Abre **Ajustes → Comprobar actualizaciones** en el agente para una comprobación manual. Se descarga y verifica el APK; si hay una actualización, se requiere otra confirmación antes de abrir el instalador de Android.

- Descarga el APK, verifica **bytes + sha256** y compara `versionCode` y el nombre del paquete con la aplicación instalada. Las recompilaciones de la misma versión con distinto hash también pueden instalarse.
- Instala mediante `PackageInstaller`. La aplicación declara `REQUEST_INSTALL_PACKAGES`; en la primera OTA puede ser necesario permitir «instalar aplicaciones desconocidas» para Remote Agent en los ajustes del sistema y confirmar después la interfaz del instalador.
- Al iniciar la instalación se devuelve `available` con un mensaje de instalación pendiente, en lugar de `applied`. El callback privado del instalador abre la confirmación del sistema. Las solicitudes repetidas para el mismo APK pendiente reutilizan la sesión; las sesiones fallidas u obsoletas se abandonan. Confirma la versión y el hash instalados cuando el agente vuelva a conectarse.
- La comprobación automática sigue un intervalo parecido mientras `AgentService` está en ejecución.
- El agente nativo gestiona `update_req` remoto e invoca el puente de control del APK con `action: ota_update`.
- El almacenamiento privado de la aplicación, incluido el ID y token, se conserva al sustituir el paquete. `MY_PACKAGE_REPLACED` sigue reiniciando la conexión cuando está habilitada.

Rust Agent/CLI/Exchange, extensión del navegador, aplicaciones Android y consola web comparten la versión 0.1.27. Incremente las versiones juntas; Android versionCode es 30. Ejecute `python scripts/check-release-versions.py` antes de crear los paquetes.

## Actualizaciones de la consola Android

La consola nativa tiene su propio botón **Ajustes → Comprobar actualizaciones**, disponible antes y después de iniciar sesión. Lee el manifiesto público sin credenciales de cuenta y compara la compilación instalada con el `versionCode` publicado. Si el manifiesto no incluye metadatos de compilación y las versiones comerciales coinciden, ofrece una descarga sin afirmar que la aplicación esté actualizada.

**Descargar instalador** abre el APK del sitio en el navegador; termina la instalación mediante la confirmación de Android. Esto actualiza la consola del teléfono actual. Los controles de actualización del detalle de un dispositivo siguen dirigidos a ese dispositivo remoto.

## «Comprobar actualizaciones» en la consola: flujo unificado

El detalle del dispositivo conserva una sola acción «Comprobar actualizaciones», que primero envía `update_device { check_only: true }`:

- `up_to_date` → muestra «Ya está en la última versión x.y.z».
- `available` → muestra «Actual → última (tamaño)» y permite elegir «Enviar actualización / Más tarde». Tras confirmar, envía `check_only: false` y muestra el progreso y el resultado.
- Si Android devuelve «Installation pending …» después del envío, indica que se debe confirmar la instalación en el dispositivo.
- Para dispositivos desconectados o de navegador muestra directamente el motivo; para plataformas no compatibles, «Este dispositivo no admite actualizaciones remotas».

Los mensajes de resultado incluyen `current <版本>` y `size <字节> bytes`.

Consulta también `docs/watchdog.md` del repositorio para el watchdog opcional de actividad: `--watchdog`, `REMOTE_WATCHDOG=1`.

El diagnóstico de Android muestra el último resultado de actualización automática y su fecha incluso sin READ_LOGS. Los mensajes fijos distinguen estado HTTP, DNS, tiempo de espera, TLS, manifiesto, tamaño/hash del APK y permiso de instalación. El mismo mensaje seguro se escribe en logcat con la etiqueta RemoteAgentOTA; los registros completos siguen requiriendo READ_LOGS. No se copian URL, rutas ni credenciales de las excepciones.
