Agente local: ícono y popup de instalación
El ícono del agente (robot con un punto de estado, en el header del funcionario, desde md) abre un popup con el estado real del agente y cómo instalarlo. Funciona también con el agente desconectado.
Piezas
| Pieza | Archivo | Qué hace |
|---|---|---|
| Conexión en vivo | src/features/signing/agent/agent-store.ts | WebSocket al agente (NEXT_PUBLIC_SGD_AGENT_WS_URL), health_check al conectar y cada 20 s. El snapshot añade checking y error; checkAgentNow() pide una comprobación inmediata (o reintenta la conexión sin esperar los 5 s) |
| Estado listo para mostrar | src/features/signing/agent/use-agent-view.ts | useAgentView() une la conexión con la versión publicada y devuelve un solo estado: checking, connected, update, disconnected o error. También detectOs() y isNewerVersion() |
| Versión e instaladores | src/app/api/agent/release/route.ts | GET /api/agent/release consulta la versión vigente al backend (GET /api/public/agent/release, servidor a servidor) y normaliza la respuesta: windowsInstallerUrl, installScriptUrl y linuxAssetsPublished / macAssetsPublished; no expone la URL del backend ni errores remotos |
| Popup | src/features/signing/components/agent-dialog.tsx | AgentDialog (Dialog del SGD) con el estado y las pestañas Windows / macOS / Linux |
| Carpeta de documentos | DocumentsFolderRow en agent-dialog.tsx (usa PathRow, ui/path-row.tsx) + documentsPath y openDocumentsFolder() en agent-store.ts | Con el agente conectado muestra documents_path (lo que informa el agente en el health check; el SGD no escribe ninguna ruta) con dos botones del mismo alto (36 px): copiar la ruta y «Abrir», que envía open_folder (raíz del árbol de documentos) y el agente abre el Explorador. Si la carpeta aún no existe (not_found) avisa con un mensaje claro. Desconectado, no aparece. El nombre de la carpeta lo decide el agente (documents.path de su config.json; vacío = Documentossgd-agent) |
| Ícono del header | src/components/user/user-header.tsx | Abre el popup; su punto y su etiqueta salen del mismo useAgentView() |
| Bloque de comando | src/components/ui/command-block.tsx | CommandBlock: comando con ajuste de línea y «Copiar comando» (reutilizable) |
| Pestañas con línea | src/components/ui/tabs.tsx + .sgd-tabs-line en globals.css | TabsList variant="line" |
Origen de los datos (administrado en el SGD)
No hay URL ni versión escritas en el código, ni variables de entorno para esto: AGENT_RELEASE_URL, AGENT_WINDOWS_INSTALLER_URL y AGENT_INSTALL_SCRIPT_URL se retiraron. La versión vigente y sus archivos se administran en /admin/agente-local (backend Go, módulo agent).
| Ruta | Quién la llama | Qué devuelve |
|---|---|---|
GET /api/public/agent/release | GET /api/agent/release de la app (servidor a servidor, API_URL) | Versión vigente sin datos internos (nada de FileID): hasWindowsInstaller, hasInstallScript, hasLinuxAssets y hasMacAssets |
GET /api/agent/release | El popup (navegador) | windowsInstallerUrl, installScriptUrl y linuxAssetsPublished / macAssetsPublished, siempre apuntando al origen de la app (/api/public/agent/*, /agent/install.sh) |
hasLinuxAssets es «al menos un binario de Linux (amd64 o arm64) y su script»; hasMacAssets lo mismo para macOS. El comando curl -fsSL <origen>/agent/install.sh | bash es uno solo para los dos sistemas (el bootstrap detecta el sistema operativo), así que cada pestaña decide con esas banderas si su comando sirve de verdad: sin binario o sin script de ese sistema, el comando fallaría con 404 y no se ofrece.
Si falta alguno, el popup lo dice («el comando de instalación aparecerá aquí cuando se publique el enlace») en lugar de inventar un valor.
Estados (los mismos en el ícono y en el popup)
| Estado | Cuándo | Punto del ícono | Popup |
|---|---|---|---|
checking | Conectando o con una comprobación manual en curso | azul (info) | «Comprobando» |
connected | Health check correcto y sin actualización conocida | verde | «Conectado», Versión instalada: vX. «Es la última versión» solo si se pudo consultar la publicación y coincide; si no, «No se pudo comprobar si hay actualizaciones» o «Este servidor no publica la versión más reciente» |
update | La versión publicada es mayor que la instalada | ámbar | «Actualización disponible», vX instalada → vY disponible |
disconnected | No se pudo abrir la conexión | rojo | «Desconectado» y cómo instalarlo |
error | La conexión abrió pero el health check falló | rojo | «Error de comprobación» con el motivo |
Contenido y comportamiento
-
Carpeta de documentos por sistema operativo: la fila va dentro de la pestaña del sistema del agente conectado (
platformdel health check,agentOsOf()), que lleva un punto verde de «agente conectado en este equipo»; en las otras pestañas solo hay una nota («El agente conectado en este equipo es el de Windows; su carpeta de documentos se muestra en esa pestaña…») y sin agente ninguna pestaña la muestra. No hay rutas escritas en el código para ningún sistema. -
Carpeta de documentos (agente conectado o con actualización disponible): fila con ícono, «Carpeta de documentos», la ruta en monoespaciado y, a la derecha, un botón cuadrado de 36 px para copiar la ruta (avisa «Ruta copiada», el ícono pasa a ✓ dos segundos y el portapapeles recibe la ruta completa) y «Abrir» (nombre accesible «Abrir carpeta de documentos»). Pie del popup con «Cerrar» (devuelve el foco al ícono del agente).
-
Cabecera compacta: el nombre («Agente Trámite-Doc», como en la referencia) con el estado al costado (
Badgesoft,role="status") y una sola línea debajo con la versión instalada (DialogDescription; «Es la última versión» solo si se comprobó; «No se pudo comprobar si hay actualizaciones» si la publicación falló). No hay botón de comprobación: al abrir el popup se hace uncheckAgentNow()y se recarga la versión publicada, y el agente se vuelve a comprobar solo (latido de 20 s; reconexión cada 5 s). -
Pestañas (Radix Tabs, flechas del teclado): solo la activa lleva el subrayado de 3 px; el hover es un fondo suave y el foco un contorno visible. La inicial es el sistema que informa el agente conectado (
platform) o, sin agente, el del navegador; se puede cambiar. -
Windows: botón «Descargar {archivo}» (
<a download>, el nombre se deduce de la URL publicada) y cuatro pasos, incluida la advertencia de SmartScreen. Sin enlace publicado el botón se ve igual pero deshabilitado, con el motivo debajo. Tras el primer clic el botón se bloquea 6 segundos (queda como enlace conaria-disabled, dice «Descarga iniciada…» y avisa «La descarga puede tardar unos segundos. No hace falta pulsar de nuevo.»): el navegador tarda en empezar y no avisa cuándo lo hace, y así no se baja el instalador varias veces; los clics durante el bloqueo se ignoran sin cancelar la descarga que ya arrancó. -
macOS / Linux:
CommandBlock: recuadro con el comando y, a la derecha dentro del recuadro, el ícono de copiar (con tooltip y nombre accesible). Copiar pone en el portapapeles el comando original completo en una sola línea, muestra «Comando copiado» (notificación del sistema y el ícono cambia a una marca un momento) y no cierra el popup; si el portapapeles se niega se usa el método clásico y, si también falla, se avisa. El comando se muestra solo en el sistema cuyos binarios y script están publicados (linuxAssetsPublished/macAssetsPublished); en el otro el recuadro se ve igual, con el texto «aparecerá aquí cuando se publique el enlace» y el ícono de copiar deshabilitado. -
Tamaño:
max-w-[34rem]dentro delDialogcompartido: el cuerpo es la única zona con scroll, el comando se ajusta (break-all) y no ensancha el modal; cierre con la «X» compartida, Escape y clic exterior; el foco vuelve al ícono.
Verificación hecha
Chrome real (CDP) montando el layout del dashboard con WebSocket del agente y /api/agent/release simulados (el ícono del header y el popup reales): conectado con última versión; actualización disponible; desconectado; comprobación al abrir; error de health check; publicación caída; servidor sin configuración; pestañas por teclado; copiar (con el portapapeles real: el comando completo en una línea); Escape y retorno del foco; 390 × 700, 1024 × 500 y modo oscuro sin scroll horizontal y con axe sin violaciones. La ruta /api/agent/release se probó con un servidor local de latest.json (válido, JSON roto, caído, URL no http, sin variables).
Contrato por sistema (16/10/2026, sin repetir la verificación en navegador): con la publicación real de /admin/agente-local (solo Linux y el .exe de Windows subidos), GET /api/public/agent/release devuelve hasInstallScript: true junto con hasLinuxAssets: true y hasMacAssets: false, y GET /api/agent/release los propaga como linuxAssetsPublished: true / macAssetsPublished: false; con eso la pestaña macOS queda en el texto de pendiente y la Linux con el comando. go build ./... y go vet sin errores; ESLint sin errores y tsc --noEmit sin errores.
Pendiente / no verificado
- Agente real: no había
sgd-agentinstalado; el estado conectado y la versión se simularon con el protocolo documentado enserver/AGENT_API.md. - Instaladores y comandos: los pasos de cada sistema vienen de la referencia (versión anterior del SGD); Linux (
systemd,sudo) y el comando del popup se comprobaron de punta a punta con el binario publicado en un contenedor Ubuntu 24.04 sin agente previo (16/10/2026). macOS no se comprobó en un Mac real: falta confirmar los pasos (contraseña, Gatekeeper). Los binarios y scripts se publican desde/admin/agente-localen cada entorno;linuxAssetsPublished/macAssetsPublishedhabilitan el comando de cada sistema. - macOS sin publicar: sus binarios requieren compilarse en un equipo Mac, así que la pestaña macOS muestra el estado de pendiente hasta que se suban el binario y
install-macos.sh. - Nombre del instalador de Windows: el botón usa el nombre deducido de la URL del endpoint (
fileNameOf), no el del archivo subido en/admin/agente-local. - Arquitectura dentro de un sistema: la bandera es por sistema (cualquier arquitectura + script); con solo
linux-arm64publicado, un Linux amd64 vería el comando y la descarga fallaría. Afinar por arquitectura queda pendiente. - En pantallas menores a
mdel ícono del agente no se muestra (el header lo oculta junto con las notificaciones); el popup no es accesible desde ahí. - En desarrollo, React Strict Mode abre y cierra la primera conexión; la real tarda hasta 5 s en aparecer (comportamiento previo del store, no ocurre en producción).
- Lector de pantalla, Firefox y Safari sin probar.