- Señala la complejidad y las limitaciones de la estructura tradicional de la terminal, y propone un concepto de terminal de nueva generación que reintegra entrada, salida y control de procesos
- Toma a Jupyter Notebook como modelo para explorar la posibilidad de implementar una interfaz interactiva, con renderizado de imágenes, reejecución de comandos, salida editable y editor integrado
- A través de los casos de Warp e iTerm2, explica de forma concreta la integración profunda entre shell y terminal (shell integration), la gestión de procesos de larga duración y las funciones de separación y recuperación de sesiones
- Sobre la base del seguimiento de flujo de datos (dataflow tracking) y la persistencia, plantea funciones extendidas como undo/redo de comandos, reejecución automática y terminales colaborativas
- Presenta una estrategia de construcción gradual que avanza por etapas desde CLI transaccional → sesiones persistentes → RPC estructurado → frontend tipo Jupyter
Estructura básica de la terminal
- Una terminal se compone de cuatro elementos: emulador de terminal, terminal virtual (PTY), shell y grupo de procesos
- El emulador de terminal es el programa que renderiza una estructura de cuadrícula en pantalla
- El PTY es un estado interno del kernel que transmite la entrada al grupo de procesos y se encarga de convertir señales (
signal)
- El shell actúa como un bucle de eventos que lee y parsea la entrada y crea procesos
- Los procesos interactúan con los componentes anteriores a través de entrada y salida
- La entrada no es solo texto simple, sino que incluye señales (
signal), y la salida está compuesta por secuencias de escape ANSI que expresan el formato
Una visión de una terminal mejor
- La terminal actual tiene muchas restricciones funcionales, por lo que carece de extensibilidad e interactividad
- Jupyter Notebook ofrece funciones imposibles en un emulador VT100 tradicional
- Renderizado de imágenes en alta resolución
- Un botón de “volver a ejecutar desde el principio” que reemplaza salidas anteriores sin agregarlas
- Una “vista” que permite reescribir en el mismo lugar el código fuente y la salida (por ejemplo, mostrar Markdown como fuente o como HTML renderizado)
- Un editor integrado con resaltado de sintaxis, pestañas, paneles y soporte para mouse
- Sin embargo, la idea de un notebook de Jupyter que usa el shell como kernel enfrenta varios problemas
- El shell recibe los comandos de una sola vez, así que no funcionan el autocompletado con tab, el resaltado de sintaxis ni las sugerencias automáticas
- Problemas para manejar procesos de larga duración: Jupyter, por defecto, ejecuta hasta que la celda termina; se puede cancelar, pero no es posible pausar, reanudar, interactuar ni ver procesos en ejecución
- El botón de “volver a ejecutar la celda” puede causar problemas con el estado de la computadora, especialmente si incluye comandos como
rm -rf
- Undo/redo no funciona
¿Cómo podría funcionar esto?
-
Integración con el shell (Shell Integration)
- La terminal Warp construye una integración nativa entre la terminal y el shell
- La terminal entiende el inicio y final de cada comando, su salida y la entrada del usuario
- Está implementado usando funciones estándar (DCS personalizado)
- iTerm2 también puede usar un enfoque similar con códigos de escape OSC 133
- Navegación entre comandos con una sola tecla rápida
- Notificaciones al completarse un comando
- Si la salida se sale de la pantalla, muestra el comando actual como una “superposición”
-
Gestión de procesos de larga duración
- Interacción (
interacting):
- Para interactuar con procesos de larga duración se necesita comunicación bidireccional
- Ejemplos de TUI:
top, gdb, vim
- Jupyter destaca por su diseño de salida interactiva que puede modificarse y actualizarse
- Función esperada de la terminal: ofrecer siempre una “celda de entrada libre”
- El proceso interactivo se ejecuta en la parte superior de la ventana y abajo se ofrece una celda de entrada
- Suspensión (
suspending):
- “Pausar” un proceso se conoce como control de trabajos (job control)
- Se esperaría que una terminal moderna muestre una indicación visual persistente de procesos suspendidos y en segundo plano
- Similar a cómo IntelliJ muestra “Indexando...” en la barra inferior de tareas
- Desconexión (
disconnecting): existen tres enfoques para separar y recuperar sesiones
- Tmux / Zellij / Screen: insertan un emulador de terminal adicional entre el emulador de terminal y el programa. El servidor posee el PTY y renderiza la salida, mientras que el cliente muestra la salida en el emulador de terminal real. Permite separar clientes, reconectarlos y conectar múltiples clientes al mismo tiempo. iTerm funciona como su propio cliente que evita el cliente de tmux y se comunica directamente con el servidor
- Mosh: reemplazo de SSH. Permite reconectarse a una sesión de terminal tras una caída de red. Ejecuta una máquina de estados en el servidor y reproduce en el cliente las diferencias incrementales del viewport. Se espera que la multiplexación y el scrollback los maneje el emulador de terminal. Como el cliente realmente corre del lado de la red, la edición de línea local es inmediata
- alden/shpool/dtach/abduco/diss: solo manejan la separación y reanudación de sesiones con un modelo cliente/servidor; no incluyen red, scrollback ni su propio emulador de terminal. Tienen un nivel de separación más alto que tmux y mosh
-
Reejecución y reversión
- La solución es el seguimiento del flujo de datos
- pluto.jl ya lo implementa hoy al conectarse al compilador de Julia
- Actualiza en tiempo real las celdas que dependen de celdas anteriores
- No actualiza una celda si sus dependencias no cambiaron
- Es como un Jupyter parecido a una hoja de cálculo, que solo vuelve a ejecutar código cuando hace falta
- Generalización mediante persistencia ortogonal (orthogonal persistence)
- Se aíslan los procesos en sandbox y se rastrea todo el I/O, evitando cosas “demasiado raras” siempre que no se comuniquen con otros procesos dentro del sandbox
- Hace posible tratar un proceso como una función pura de su entrada, donde la entrada es “todo el sistema de archivos, todas las variables de entorno y todas las propiedades del proceso”
Funciones derivadas
- Se necesita un frontend de Jupyter:
- Runbooks (en realidad se pueden construir solo con primitivas de Jupyter y PTY)
- Personalización de la terminal usando CSS normal, sin lenguajes personalizados extraños ni códigos de color ANSI
- Búsqueda de comandos por salida o marcas de tiempo: hoy se puede buscar en toda la salida de la sesión actual o en el historial de entradas de comandos, pero no hay filtros inteligentes y la salida no persiste entre sesiones
- Se necesita integración con el shell:
- Marca de tiempo y tiempo de ejecución de cada comando
- Edición de línea local incluso a través de fronteras de red
- IntelliSense para comandos del shell sin necesidad de presionar tab, con renderizado integrado en la terminal
- Se necesita rastreo del sandbox:
- Todas las funciones del rastreo del sandbox: terminales colaborativas, consulta de archivos modificados por un comando, asciinema editable en tiempo de ejecución y seguimiento de sistemas de build
- Extender la búsqueda inteligente para que también busque en el estado del disco al momento de ejecutar el comando
- Extender undo/redo con un modelo de ramas similar a git (emacs undo-tree ya lo soporta), ofreciendo varias “vistas” del árbol de procesos
- Mediante el modelo undo-tree y el sandboxing, sería posible dar acceso del proyecto a un LLM y ejecutar varios en paralelo al mismo tiempo, sin que sobrescriban el estado entre sí, revisando y editando su trabajo, y guardándolo más tarde como un runbook reutilizable
- Una terminal que solo inspecciona el estado existente en producción sin afectar el estado de la máquina
Estrategia de construcción por etapas
-
Etapa 1: semántica transaccional (transactional semantics)
- Al rediseñar la terminal, empezar por el emulador es un enfoque equivocado
- Los usuarios desarrollan apego al emulador y a sus configuraciones, apariencia y key bindings
- El costo de cambiar de emulador es alto
- La forma correcta es empezar en la capa CLI
- Los programas CLI son fáciles de instalar y ejecutar, y el costo de cambio es muy bajo
- Se pueden usar de forma puntual sin cambiar todo el flujo de trabajo
- Escribir una CLI que implemente semántica transaccional para la terminal
- Una interfaz como
transaction [start|rollback|commit]
- Todo lo ejecutado después de
start se puede deshacer
- Solo con esto ya se puede construir todo un negocio
-
Etapa 2: sesiones persistentes (Persistent Sessions)
- Una vez obtenida la semántica transaccional, separar la persistencia de tmux y mosh
- Para obtener persistencia del PTY es necesario introducir un modelo cliente/servidor
- El kernel asume que ambos lados del PTY estarán siempre conectados
- Puede implementarse de forma simple usando un comando como alden o una librería similar, sin afectar al emulador de terminal ni a los programas que corren dentro de la sesión PTY
- Para obtener scrollback, el servidor guarda indefinidamente la entrada y salida y las reproduce cuando el cliente se reconecta
- El emulador de terminal ofrece scrollback nativo tratándolo como cualquier otra salida
- Se puede reproducir y reanudar desde un punto arbitrario
- Requiere parsear códigos de escape ANSI, pero es factible con suficiente trabajo
- Para reanudar la red al estilo mosh, usar Eternal TCP (podría construirse sobre QUIC para mejorar la eficiencia)
- Separar la persistencia del PTY de la persistencia de la conexión de red
- Eternal TCP es una optimización pura: puede construirse encima de un script bash que ejecute en bucle
ssh host eternal-pty attach
- En este punto, como en tmux, múltiples clientes pueden conectarse a una sola sesión de terminal, mientras que la gestión de ventanas sigue a cargo del emulador
- Si se quiere gestión de ventanas integrada, el emulador de terminal puede usar un protocolo como tmux -CC, igual que iTerm
- Todas las partes de esta etapa pueden desarrollarse en paralelo e independientemente de la semántica transaccional, pero no bastan para construir un negocio
-
Etapa 3: RPC estructurado
- Depende del modelo cliente/servidor
- Si el servidor media entre el emulador de terminal y el cliente, se pueden implementar funciones como etiquetar I/O con metadatos
- Es posible añadir marcas de tiempo a todos los datos
- Es posible distinguir entre entrada y salida
- xterm.js funciona de una manera similar
- Combinado con integración con el shell, permite distinguir en la capa de datos entre el prompt del shell y la salida del programa
- Se obtiene un registro estructurado de la sesión de terminal
- Reproducir logs como grabaciones al estilo asciinema
- Transformar prompts del shell sin volver a ejecutar todos los comandos
- Importarlos a Jupyter Notebook o Atuin Desktop
- Guardar comandos y volver a ejecutarlos después como scripts
- La terminal se convierte en datos
-
Etapa 4: frontend similar a Jupyter
- Es la primera etapa en que se toca el emulador de terminal, y deliberadamente la última
- Porque el costo de cambio es el más alto
- Aprovechar todas las funciones construidas para ofrecer una buena UI
- La CLI
transaction ya no haría falta, salvo que se quieran transacciones anidadas
- Toda la sesión de terminal comienza por defecto como una transacción
- Como ya se combinaron todas las piezas, se pueden ofrecer todas las funciones derivadas mencionadas arriba
Conclusión
- Se espera que esta arquitectura sea audaz, ambiciosa y que tome hasta unos 10 años construirla por completo
- Habrá que avanzar paso a paso con paciencia
- Se espera que este texto inspire a alguien a empezar a construirlo por su cuenta
Aún no hay comentarios.