Codex Live Session
Arquitectura
Codex trabaja dentro de la única sesión tmux "aeos-dev". El servicio ttyd adjunta un cliente web de solo lectura a esa sesión y escucha exclusivamente en "127.0.0.1:7681". Nginx publica el transporte HTTP y WebSocket bajo "/development/terminal/live/", mientras Spring Boot sirve la página "/development/terminal".
Codex -> tmux aeos-dev -> ttyd solo lectura -> Nginx -> /development/terminal
No existe escritorio gráfico, X11, VNC ni acceso directo a ttyd desde la red. La opción "--writable" de ttyd no se utiliza.
Componentes instalados
- tmux 3.3a-3, instalado desde Debian 12 mediante APT.
- ttyd 1.7.7, binario oficial x86_64 instalado en /usr/local/bin/ttyd después de verificar SHA256SUMS.
La dependencia nativa libevent-core-2.1-7 es instalada automáticamente por APT para tmux. No se instala ningún escritorio, servidor gráfico o servicio de escritorio remoto.
Funcionamiento
"aeos-dev.service" ejecuta un script idempotente al arrancar. Si la sesión exacta "aeos-dev" existe, la reutiliza; si no existe, crea una sola sesión con "/opt/esp-platform/repo" como directorio de trabajo. tmux mantiene la sesión aunque no haya clientes conectados.
"esp-platform-ttyd.service" depende de la sesión y ejecuta ttyd como el usuario "codex". El navegador solo recibe la salida de terminal y no puede escribir, pegar, enviar teclas ni interrumpir procesos.
Conexión
La vista HTTPS normal está disponible en:
https://iot.aeizoon.com/development/terminal
Para trabajar desde SSH dentro de la misma sesión:
tmux attach-session -t aeos-dev
Para salir sin detenerla, use la secuencia tmux "Ctrl+B", seguida de "D".
Operación
Comprobar o recrear la sesión si falta, sin duplicarla:
sudo systemctl restart aeos-dev.service
Reiniciar la publicación web sin detener tmux:
sudo systemctl restart esp-platform-ttyd.service
Consultar estado y logs:
systemctl status aeos-dev.service esp-platform-ttyd.service
journalctl -u esp-platform-ttyd.service -n 100 --no-pager
Verificación
tmux list-sessions
systemctl is-active aeos-dev.service esp-platform-ttyd.service nginx
ss -ltnp | grep 7681
curl -I http://127.0.0.1:7681/development/terminal/live/
curl -I http://127.0.0.1:88/development/terminal
Debe existir exactamente una sesión "aeos-dev"; ttyd debe escuchar solo en "127.0.0.1:7681"; la página debe responder a través de Nginx. El servicio ttyd no debe contener "--writable" ni "-W".
Configuración versionada
- "scripts/ensure-aeos-dev-session.sh": creación idempotente de la sesión.
- "infrastructure/systemd/aeos-dev.service": persistencia tras reinicio.
- "infrastructure/systemd/esp-platform-ttyd.service": ttyd de solo lectura.
- "infrastructure/nginx/codex-live-session.conf": proxy WebSocket.
Los archivos efectivos se instalan en "/etc/systemd/system/" y en el sitio Nginx de ESP Platform. Los cambios se realizan primero en el repositorio y después se despliegan.
Política de redimensionado
La sesión utiliza la política global "window-size largest" de tmux 3.3a y mantiene "aggressive-resize off". Con varios clientes conectados, la ventana toma las dimensiones del cliente más grande; una conexión SSH de 80x24 no puede reducir la vista web.
ttyd fija "fontSize=18" y "lineHeight=1.35". El navegador permanece en modo de solo lectura porque ttyd no se inicia con "--writable" ni "-W". El cliente tmux no usa "attach-session -r": tmux 3.3a excluye los clientes de solo lectura del cálculo de tamaño y eso impediría que la vista web aportase sus dimensiones a "window-size largest".
La página reajusta xterm.js tras la carga del iframe, una recreación del terminal, cambios del contenedor, cambios de pantalla completa y redimensionados de la ventana. Se usa "ResizeObserver", con dos reintentos cortos después de cada evento; no existe un bucle periódico de redimensionado.
Durante una caída del WebSocket la vista puede mostrar temporalmente el estado de desconexión. Al reabrirse la conexión, ttyd conserva o recrea el terminal y el observador vuelve a ajustarlo al contenedor.
Para verificar la política:
tmux show-window-options -g | grep -E 'window-size|aggressive-resize'
tmux list-clients -F '#{client_tty} #{client_width}x#{client_height} readonly=#{client_readonly}'
tmux list-windows -F '#{session_name} #{window_index} #{window_width}x#{window_height}'
