3 puntos por GN⁺ 2 시간 전 | 1 comentarios | Compartir por WhatsApp
  • La suposición de que las apps de terminal, por estar basadas en texto, son accesibles por naturaleza se rompe con las TUI modernas, y frameworks como Ink, Bubble Tea y tcell pueden crear un entorno más hostil para usuarios de lectores de pantalla
  • La CLI acumula la salida como un flujo lineal de stdin/stdout en orden temporal, pero una TUI trata la terminal como una cuadrícula 2D de celdas de caracteres, lo que dificulta que los lectores de pantalla sigan el flujo
  • gemini-cli puede hacer que Ink vuelva a dibujar el árbol de componentes de React sobre la cuadrícula de la terminal, moviendo el cursor entre spinner, temporizador e historial de conversación, lo que puede provocar lecturas repetidas, crashes y retrasos de entrada en Speakup y NVDA
  • Herramientas antiguas como nano, vim, menuconfig e Irssi reducen el ruido de actualizaciones de coordenadas y minimizan la interferencia con la línea de entrada mediante ocultación del cursor, foco en una sola columna y uso de la región de desplazamiento de VT100
  • Para crear herramientas de terminal accesibles, hay que evitar frameworks de UI declarativos que tratan la terminal como un lienzo y el redibujado agresivo, y garantizar un comportamiento más cercano a flujos CLI simples y lineales

El malentendido de que “como es texto, es accesible”

  • La suposición de que las aplicaciones que se ejecutan en la terminal son accesibles por naturaleza no coincide con el entorno real de uso
  • La expectativa de que un lector de pantalla pueda interpretar fácilmente texto ASCII puro porque no hay gráficos, DOM complejo ni canvas WebGL se rompe en las TUI modernas
  • Frameworks de interfaz de terminal como Ink (JS/React), Bubble Tea (Go) y tcell buscan mejorar la experiencia del desarrollador (DX), pero para usuarios con discapacidad visual pueden crear un entorno más hostil
  • En muchos casos, una TUI moderna resulta peor en accesibilidad que una interfaz gráfica mal implementada

Diferencias estructurales entre CLI y TUI

  • CLI: flujo lineal

    • Una CLI funciona sobre stdin/stdout; al ingresar un comando, el resultado se agrega debajo y el cursor baja
    • Como la salida es lineal y se acumula en orden temporal, encaja bien con lectores de pantalla a nivel de kernel como Speakup
  • TUI: cuadrícula 2D

    • Una TUI trata la ventana de la terminal no como un flujo de texto, sino como una cuadrícula 2D donde cada celda de carácter se usa como si fuera un píxel
    • Al renunciar al flujo temporal y priorizar la disposición espacial, se vuelve una estructura difícil de seguir para los lectores de pantalla

Problemas que se hacen visibles en gemini-cli

  • gemini-cli es una herramienta escrita con Node.js y el framework Ink, y por fuera parece una interfaz de chat simple
  • Internamente, Ink intenta ajustar un árbol de componentes de React a la cuadrícula de la terminal
  • Al usarlo con Speakup (Linux) o NVDA (Windows), la aplicación no solo falla de manera simple, sino que también le lanza al lector de pantalla un flujo constante de cosas para leer
  • Una pantalla que funciona como un lienzo reactivo

    • Como el framework trata la pantalla como un lienzo reactivo, cada actualización provoca un redibujado
    • Cuando la IA está “pensando”, mueve el cursor de hardware a la posición del temporizador para actualizar el spinner o el tiempo transcurrido, escribe el nuevo tiempo y luego lo regresa a la posición original
    • Para un usuario vidente es un movimiento instantáneo que pasa desapercibido, pero para un usuario de lector de pantalla suena repetidamente como “Responding... Time elapsed 1s... Responding... Time elapsed 2s...”
    • A medida que el cursor salta momentáneamente entre el indicador de estado, el spinner y el historial de conversación, Speakup intenta leer lo que haya debajo del cursor en ese instante
    • Como resultado, las actualizaciones del temporizador y fragmentos de la conversación se mezclan, dificultando concentrarse en lo que realmente se está escribiendo
  • Inestabilidad con NVDA y al pegar texto

    • En Windows, si se abre una terminal con NVDA, se conecta por SSH a un equipo Linux y luego se entra a una sesión de screen para pegar texto, NVDA puede crashear de inmediato o el sistema puede volverse muy inestable
    • Cada vez que se escribe un carácter o se pega texto, el estado de la aplicación cambia y el framework decide que debe volver a renderizar la interfaz
    • Si el historial de conversación forma parte del estado, intenta redibujar o recalcular de inmediato el layout de miles de líneas de texto
    • Cuantos más mensajes haya en la conversación, más seguido ocurre este problema
    • Ni siquiera la combinación Insert+5, pensada para evitar anuncios de contenido dinámico, logra esquivarlo
  • Bucle de retraso en la entrada

    • Cuando un framework como Ink corre en un entorno de un solo hilo como Node.js, la degradación de rendimiento empeora a medida que crece el historial
    • Si se pega un bloque grande de texto, hay que calcular diferencias sobre miles de líneas
    • El sistema se ocupa calculando cómo redibujar la pantalla y el procesamiento de entrada se retrasa
    • Incluso al presionar una sola tecla, puede haber que esperar hasta 10 segundos para que el carácter vuelva a mostrarse

Por qué las herramientas antiguas sí funcionan

  • Herramientas como nano, vim y menuconfig no se usan porque sean siempre perfectas en accesibilidad
  • La clave es que estas herramientas pueden ocultar completamente el cursor o reducir el ruido generado por el seguimiento de la posición del cursor
  • nano y vim: ocultar el cursor

    • Si nano se ejecuta con opciones que muestran la posición del cursor, como --constantshow, o si se usa vim sin cierta configuración, la usabilidad puede romperse
    • Cuando el cursor es visible y el seguimiento está activado, Speakup prioriza las actualizaciones de posición del cursor por encima del eco de caracteres
    • Si el usuario escribe “a”, en vez de oír “a” puede oír “Column 2”, y si escribe “b”, puede oír “Column 3”
    • Estas herramientas antiguas pueden configurarse para suprimir el cursor visual o las actualizaciones de la barra de estado, permitiendo que el lector de pantalla dependa del flujo de entrada de caracteres y no de las actualizaciones de coordenadas
    • Los frameworks modernos por lo general no ofrecen un modo “no-cursor” o “headless”, y asumen que el cursor visual es obligatorio
  • menuconfig: foco en una sola columna

    • El menuconfig del kernel de Linux funciona porque mantiene estrictamente el foco en una sola columna
    • Aunque tiene bordes y títulos, el área activa es una lista vertical, y el cursor se mantiene fijo en esa lista
    • El cursor no se mueve a la esquina inferior derecha para actualizar un reloj y luego a la esquina superior izquierda para actualizar un título
    • La complejidad espacial se mantiene baja, por lo que el lector de pantalla no pierde el rumbo
  • Irssi: uso de la región de desplazamiento

    • Irssi no es accesible por casualidad, sino que es una herramienta de chat que desde hace más de 20 años aprovecha la región de desplazamiento de VT100 mediante un motor de renderizado personalizado
    • Cuando llega un mensaje nuevo, le indica al driver de la terminal que “defina las filas 1 a 23 como región de desplazamiento”
    • Luego envía la orden de “desplazar hacia arriba”, la terminal mueve el contenido hacia arriba y después dibuja el texto nuevo en la parte inferior de esa región
    • Este método minimiza la interferencia con la línea de entrada
    • En vez de reescribir manualmente todos los caracteres de la pantalla, se apoya en capacidades de hardware de la terminal
    • Los frameworks modernos ignoran estas capacidades de hardware y optan por calcular diferencias de estado de pantalla para reescribir caracteres, lo que cuesta más cómputo y es hostil para la accesibilidad

Problemas en cómo se gestionan los issues de gemini-cli

  • Google y los mantenedores de gemini-cli parecen preocuparse por la accesibilidad, pero en el repositorio se están dejando de lado regresiones importantes de accesibilidad
  • Regresiones de accesibilidad como Issue #3435 e Issue #11305 no tienen discusión, hoja de ruta ni corrección
  • Issue #1553 era un issue para rastrear este tipo de fallas de accesibilidad, pero no se resolvió y un bot lo cerró automáticamente
  • El bot cerró el issue con una frase genérica diciendo que no había actividad reciente y que se estaba administrando el backlog
  • Cerrar reportes de accesibilidad porque los mantenedores no los tocaron durante meses no es orden: es esconder evidencia
  • Se transmite la señal de que, si un bug se ignora el tiempo suficiente, deja de existir, mientras que el software real sigue siendo inutilizable para usuarios con discapacidad visual
  • Puede que mejoren los indicadores de “Closed Issues” del proyecto, pero los problemas de accesibilidad siguen sin resolverse

Conclusión para crear herramientas de terminal accesibles

  • Si realmente importa la accesibilidad en aplicaciones para terminal, hay que dejar de usar frameworks de UI declarativos que tratan la terminal como un lienzo
  • El stack TUI “moderno” está optimizado para que al desarrollador le resulte fácil escribir código al estilo React, sacrificando la capacidad de la máquina para renderizar texto de manera eficiente
  • Si una aplicación no garantiza que el usuario pueda ocultar el cursor, o depende de redibujados agresivos para mostrar spinners y temporizadores, entonces es una herramienta inaccesible
  • Para usuarios con discapacidad visual, un flujo CLI simple y lineal es mucho mejor que una TUI “inteligente” que introduce retrasos, no deja de hablar y dispersa el cursor por toda la pantalla

1 comentarios

 
GN⁺ 2 시간 전
Comentarios en Lobste.rs
  • Este artículo, como muchas otras entradas de blog, tiene un fuerte olor a redacción asistida por IA
    A los LLM les encantan títulos de este estilo: “The Architectural Flaw”, “The Lag Loop”, “Why The ‘Old Guard’ Works”, “The Lost Art of Scrolling Regions”, “The ‘Stale Bot’ excuse: A Case Study in Neglect”

    • Desde el título ya se lee como contenido producido en masa por IA. El tema en sí es novedoso, así que quizá reportarlo como spam fue excesivo, pero 1) ya no soporto más ese mismo estilo repetido por todas partes y 2) hasta me hace dudar de la precisión del contenido
      Podría haber sido una excelente entrada de blog, pero si parece que el autor solo le lanzó un esquema a ChatGPT y lo dejó ahí, eso perjudica tanto a lectores como al autor
    • Una de las cosas que más odio de la escritura con LLM es eso de escribir “The <algo que no es en absoluto un concepto establecido>” como si fuera un concepto formal
      Lo mismo pasa cuando llaman “clásico” a un problema muy específico y de una sola ocasión
  • Es realmente deprimente. En resumen, sí existen TUI accesibles como Irssi, pero los frameworks TUI modernos ignoran esos precedentes y dependen de diffing de cuadrículas y movimiento del cursor
    Los lectores de pantalla leen el contenido de la posición a la que se mueve el cursor, así que el resultado termina siendo caótico o genera una cantidad enorme de spam de lectura

  • Tengo dudas de que la explicación técnica aquí sea completamente correcta
    En particular, Ink durante mucho tiempo no soportó en absoluto renderizado incremental, y la mayoría de las apps que usan Ink todavía no lo activan. Incluso ese renderizado incremental es basado en líneas, así que en realidad no mueve el cursor a la posición exacta del temporizador
    Gemini CLI requiere usar el búfer alternativo para activar el renderizado incremental, y eso se desactiva cuando está activado el modo amigable con lectores de pantalla integrado. La documentación de esa opción está aquí
    Además, rich/textual de Python suele ser mucho más rápido que Ink incluso sobre un lenguaje más lento y mayormente de un solo hilo. Hacer diff de miles de líneas no necesariamente es tan lento, ni algo que deba tardar 10 segundos
    No dudo que la experiencia de usuario sea frustrante y esté rota, pero parece posible que la causa exacta propuesta sea una alucinación de LLM o se base en información incompleta. El renderizado incremental de Ink, incluso cuando está activado, no funciona como se describe
    En la práctica, es más probable que el redibujado completo de pantalla confunda a los lectores de pantalla, y que el redibujado por líneas haga que se vuelvan a leer fragmentos arbitrarios y cortados de texto que no tienen relación con el cambio

  • No es justo culpar solo a las TUI
    El verdadero problema es que el soporte de accesibilidad es pésimo en casi toda la pila
    Primero, la mayoría de los emuladores de terminal con renderizado por GPU no usan en absoluto las API de accesibilidad del sistema. Si el texto se renderiza en la GPU, las herramientas de accesibilidad no pueden “leerlo” y solo parece una imagen. Kitty, Alacritty y WezTerm entran en esta categoría. Mi terminal, Ghostty, sí puede leerse mediante la API de accesibilidad en macOS, y iTerm2 y Terminal.app también
    Segundo, no existe ninguna secuencia de terminal ni movimiento estandarizado para que una TUI transmita información de accesibilidad al emulador de terminal. Hace falta algo equivalente a anotaciones tipo ARIA para celdas de terminal, spans y regiones, pero no hay intentos de eso. Aunque una TUI maneje bien el cursor, el problema igual va a aparecer en muchos casos de uso
    Por ejemplo, en Ghostty hemos estado trabajando en integrar OSC133 con la API de accesibilidad para exponer cada prompt de shell, entrada y comando como elementos estructuralmente significativos en lugar de simples cajas de texto. Eso demuestra que la especificación del terminal, la TUI y el emulador de terminal tienen que encajar juntos
    Toda la pila está podrida, y casi nadie está intentando arreglarla de verdad. Yo también solo hago lo mejor que puedo con tiempo limitado, pero este es un tema enorme que hasta requiere política de ecosistema, así que es difícil de abarcar
    Como bonus, la realidad tan genial como terrible es que la IA sí está ayudando a mejorar la accesibilidad aquí. Muchas herramientas de IA usan o abusan de las API de accesibilidad para leer listas de ventanas y realizar entradas. Por eso más apps han empezado a tomarse mucho más en serio la integración de accesibilidad por los casos de uso de IA

    • El terminal de verdad se está convirtiendo en un navegador pequeño
  • Me molesta todos los días que Claude Code y gemini-cli no estén basados en readline
    Metieron algunas teclas parecidas, pero falta toda la larga cola de atajos readline conocidos
    Anthropic podría admitir que fue un error decidir “hay que hacerlo como desarrollo web” y volver a empezar con readline
    Es incorrecto pensar que la experiencia de desarrollo familiar para quienes crean estas herramientas importa más que la experiencia de usuario familiar para quienes las usan

    • Entiendo que gran parte de este problema se debe a que Ink en la práctica se conforma con ser un backend de renderizado y no ofrece widgets de entrada
      En realidad casi no hay soluciones populares de terceros bien mantenidas. Si necesitas una caja de entrada flexible, tienes que construirla tú mismo desde cero
      Contrasta con el excelente widget Input de Textual o con OpenTUI, otra librería del ecosistema JS
    • ¿readline no tiene licencia GNU? ¿Al fin alguien hizo una versión que no sea GPL?
      No me gustan los LLM, así que personalmente una UI mala me parece una ventaja, pero puede que haya alguna razón para no usar readline
  • Me parece que editores de terminal como kakoune y helix tendrían difícil pasar los criterios de accesibilidad a menos que usen el truco de “ocultar el cursor”
    Aun así, probablemente no serían tan accesibles como VS Code
    Fuera de VS Code, ¿qué IDE-lite o IDE multiplataforma accesible hay? No me gusta la actitud cada vez más hostil de VS Code. Tal vez podrían ser los IDE de JetBrains

    • Está emacspeak, que ofrece una interfaz muy accesible para Emacs
      La desventaja es que, aunque Emacs en sí es multiplataforma, emacspeak puede tener cierta dependencia de Linux por el TTS. O quizá no. Nunca lo he probado en Windows
    • Primero hay que preguntar accesibilidad para quién. Si es para personas sordas, entonces debe ofrecer texto en el idioma local y lengua de señas local. En Estados Unidos, normalmente sería ASL
      Si es accesibilidad para personas ciegas, entonces hace falta emacspeak o las herramientas de accesibilidad para personas con discapacidad visual de la plataforma
      La accesibilidad es un espectro, no una casilla para marcar
  • Links tiene un modo de terminal braille aparte, que reemplaza los elementos de GUI falsos por un menú de pantalla completa más simple y también cambia la navegación con flechas a navegación por líneas
    Otro caso interesante es edbrowse. Es un navegador en modo texto creado por Karl Dahlke, que es ciego, y a diferencia de los navegadores web en modo texto más populares, no usa una TUI sino una interfaz de línea de comandos estilo ed

  • Si es el framework Ink, probablemente esa sea la razón por la que el CLI usa 100% de CPU, se queda colgado para siempre y sigue redibujando historiales largos de chat. Una lástima