8 points par GN⁺ 2025-11-13 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • Le texte souligne la complexité et les limites de l’architecture actuelle des terminaux et propose un concept de terminal de nouvelle génération qui réunit autrement l’entrée, la sortie et le contrôle des processus
  • En prenant Jupyter Notebook comme modèle, il explore la possibilité de mettre en œuvre une interface interactive avec rendu d’images, relance des commandes, sortie modifiable et éditeur intégré
  • À travers les exemples de Warp et iTerm2, il décrit concrètement l’intégration poussée entre shell et terminal (shell integration), la gestion des processus de longue durée et les fonctions de séparation/reprise de session
  • En s’appuyant sur le suivi de flux de données (dataflow tracking) et la persistance (persistence), il imagine des fonctions étendues comme l’undo/redo des commandes, la relance automatique et le terminal collaboratif
  • Il présente une stratégie de construction progressive faisant évoluer le système de CLI transactionnelle → sessions persistantes → RPC structurée → frontend de type Jupyter

Structure de base d’un terminal

  • Un terminal se compose de quatre éléments : émulateur de terminal, terminal virtuel (PTY), shell et groupe de processus
    • L’émulateur de terminal est le programme qui affiche une structure en grille à l’écran
    • Le PTY est un état interne du noyau, chargé de transmettre les entrées au groupe de processus et de convertir les signaux
    • Le shell joue le rôle d’une boucle d’événements qui lit et analyse l’entrée puis crée les processus
    • Les processus interagissent avec les éléments ci-dessus via leurs entrées et sorties
  • L’entrée n’est pas un simple texte : elle inclut des signaux, tandis que la sortie est composée de séquences d’échappement ANSI exprimant le formatage

Imaginer un meilleur terminal

  • Le terminal actuel a de nombreuses limites fonctionnelles, ce qui réduit son extensibilité et son interactivité
  • Jupyter Notebook offre des fonctions impossibles dans un émulateur VT100 traditionnel
    • Rendu d’images en haute résolution
    • Bouton « réexécuter depuis le début » qui remplace une sortie passée sans en ajouter une nouvelle
    • « Vues » permettant de réécrire sur place le code source et la sortie (par exemple afficher du Markdown comme source ou comme HTML rendu)
    • Éditeur intégré avec coloration syntaxique, onglets, panneaux et prise en charge de la souris
  • Mais l’idée d’un notebook Jupyter utilisant le shell comme noyau se heurte à plusieurs problèmes
    • Le shell reçoit les commandes d’un seul bloc, ce qui fait que la complétion par tabulation, la coloration syntaxique et les suggestions automatiques ne fonctionnent pas
    • Problème de gestion des processus de longue durée : Jupyter exécute par défaut jusqu’à la fin de la cellule ; on peut annuler, mais pas suspendre, reprendre, interagir ni voir les processus en cours d’exécution
    • Le bouton « réexécuter la cellule » peut créer des problèmes d’état sur la machine (surtout si la commande contient quelque chose comme rm -rf)
    • L’annulation et la réexécution ne fonctionnent pas

Comment cela pourrait-il fonctionner ?

  • Intégration du shell (Shell Integration)

    • Le terminal Warp met en place une intégration native entre le terminal et le shell
      • Le terminal comprend le début et la fin de chaque commande, sa sortie et les entrées utilisateur
      • L’implémentation s’appuie sur une fonction standard (DCS personnalisé)
    • iTerm2 permet aussi une approche similaire avec les codes d’échappement OSC 133
      • Navigation entre les commandes via un seul raccourci clavier
      • Notifications à la fin d’une commande
      • Affichage de la commande actuelle en « overlay » quand sa sortie sort de l’écran
  • Gestion des processus de longue durée

    • Interagir :
      • Interagir avec un processus de longue durée nécessite une communication bidirectionnelle
        • Exemples de TUI : top, gdb, vim
        • Jupyter est bien conçu pour des sorties interactives pouvant être modifiées et mises à jour
      • Fonction attendue du terminal : fournir en permanence une « cellule de saisie libre »
        • Le processus interactif s’exécute en haut de la fenêtre, avec une cellule de saisie en bas
    • Suspendre :
      • La « suspension » d’un processus est appelée job control
      • On peut s’attendre à ce qu’un terminal moderne affiche en permanence et visuellement les processus suspendus ou en arrière-plan
        • À la manière d’IntelliJ qui affiche « indexation en cours... » dans une barre de tâches en bas
    • Se déconnecter : il existe trois approches pour séparer puis restaurer une session
      • Tmux / Zellij / Screen : insertion d’un émulateur de terminal supplémentaire entre l’émulateur et le programme. Le serveur possède le PTY, rend la sortie et le client l’affiche dans le véritable émulateur de terminal. Le client peut se détacher, se reconnecter ou permettre plusieurs connexions simultanées. iTerm peut agir comme son propre client en contournant le client tmux et en communiquant directement avec le serveur
      • Mosh : alternative à SSH. Permet de se reconnecter à une session terminal après une coupure réseau. Le serveur exécute une machine à états et rejoue côté client les différences incrémentales du viewport. Le multiplexage et le scrollback sont supposés être gérés par l’émulateur de terminal. Comme le client s’exécute réellement du côté réseau, l’édition locale de ligne est immédiate
      • alden/shpool/dtach/abduco/diss : ne gèrent côté client/serveur que la séparation et la reprise de session, sans réseau ni scrollback, et sans émulateur de terminal intégré. Ils offrent un niveau de découplage plus élevé que tmux et mosh
  • Réexécution et retour en arrière

    • La solution repose sur le suivi des flux de données
    • pluto.jl l’illustre aujourd’hui en se connectant au compilateur Julia
      • Met à jour en temps réel les cellules dépendant des cellules précédentes
      • Ne met pas à jour une cellule si ses dépendances n’ont pas changé
      • Sorte de Jupyter proche d’un tableur, qui ne réexécute le code qu’en cas de besoin
    • Généralisation via la persistance orthogonale (orthogonal persistence)
      • Isoler les processus dans des sandboxes, tracer toutes les E/S et empêcher les comportements « trop étranges » tant qu’ils ne communiquent pas avec d’autres processus dans la sandbox
      • On peut alors traiter un processus comme une fonction pure de ses entrées, ces entrées étant « l’ensemble du système de fichiers, toutes les variables d’environnement et toutes les propriétés du processus »

Fonctions dérivées

  • Nécessite un frontend Jupyter :
    • Runbooks (en pratique, constructibles uniquement avec Jupyter et des primitives PTY)
    • Personnalisation du terminal avec du CSS standard, sans langage maison bizarre ni codes couleur ANSI
    • Recherche de commandes par sortie ou horodatage : on peut chercher dans toute la sortie de la session courante ou dans l’historique de toutes les commandes, mais sans filtres intelligents et sans persistance de la sortie entre les sessions
  • Nécessite l’intégration du shell :
    • Horodatage et durée d’exécution de chaque commande
    • Édition locale de ligne même au-delà des frontières réseau
    • IntelliSense pour les commandes shell sans devoir appuyer sur Tab, avec rendu intégré au terminal
  • Nécessite le suivi en sandbox :
    • Toutes les fonctions du suivi en sandbox : terminal collaboratif, requête des fichiers modifiés par une commande, asciinema modifiable à l’exécution, suivi de systèmes de build
    • Extension de la recherche intelligente pour interroger aussi l’état du disque au moment de l’exécution de la commande
    • Extension de l’annulation/réexécution à un modèle de branches comparable à git (emacs undo-tree le prend déjà en charge), avec plusieurs « vues » de l’arbre de processus
    • Grâce au modèle undo-tree et au sandboxing, il devient possible de donner à un LLM l’accès à un projet et d’en exécuter plusieurs en parallèle, sans qu’ils écrasent mutuellement leur état, tout en pouvant inspecter, modifier et enregistrer plus tard leur travail sous forme de runbook
    • En production, un terminal qui inspecte uniquement l’état existant sans affecter l’état de la machine

Stratégie de construction par étapes

  • Étape 1 : sémantique transactionnelle (transactional semantics)

    • Commencer la refonte du terminal par l’émulateur de terminal est une mauvaise approche
      • Les utilisateurs sont attachés à leur émulateur ainsi qu’à sa configuration, son apparence et ses raccourcis clavier
      • Le coût de changement d’émulateur est élevé
    • Il vaut mieux commencer à la couche CLI
      • Les programmes CLI sont faciles à installer et à exécuter, avec un coût de changement très faible
      • On peut les utiliser ponctuellement sans changer tout le workflow
    • Écrire une CLI mettant en œuvre une sémantique transactionnelle pour le terminal
      • Interface du type transaction [start|rollback|commit]
      • Tout ce qui est exécuté après start peut être annulé
      • Rien qu’avec cela, on peut déjà bâtir toute une activité
  • Étape 2 : sessions persistantes (Persistent Sessions)

    • Une fois la sémantique transactionnelle obtenue, séparer la persistance de tmux et de mosh
    • Pour obtenir la persistance du PTY, il faut adopter un modèle client/serveur
      • Le noyau suppose que les deux côtés du PTY seront toujours connectés
      • Une mise en œuvre simple est possible via une commande comme alden ou une bibliothèque similaire, sans affecter l’émulateur de terminal ni les programmes exécutés dans la session PTY
    • Pour obtenir le scrollback, le serveur stocke indéfiniment les entrées/sorties puis les rejoue lors de la reconnexion du client
      • L’émulateur de terminal fournit un scrollback natif traité comme n’importe quelle autre sortie
      • La relecture et la reprise sont possibles depuis n’importe quel point de départ
      • Cela nécessite l’analyse des séquences d’échappement ANSI, mais reste faisable avec suffisamment de travail
    • Pour une reprise réseau façon mosh, utiliser Eternal TCP (éventuellement construit sur QUIC pour gagner en efficacité)
      • Séparer la persistance du PTY de celle de la connexion réseau
      • Eternal TCP est une simple optimisation : on peut construire cela au-dessus d’un script bash qui exécute en boucle ssh host eternal-pty attach
    • À ce stade, comme avec tmux, plusieurs clients peuvent se connecter à une même session terminal, tandis que la gestion des fenêtres reste du ressort de l’émulateur
      • Pour une gestion intégrée des fenêtres, l’émulateur pourrait utiliser un protocole comme tmux -CC à la manière d’iTerm
    • Toutes les parties de cette étape peuvent être réalisées en parallèle, indépendamment de la sémantique transactionnelle, mais cela ne suffit pas encore pour bâtir l’activité
  • Étape 3 : RPC structurée

    • Repose sur le modèle client/serveur
    • Si un serveur s’interpose entre l’émulateur de terminal et le client, on peut implémenter des fonctions comme le taggage des E/S avec des métadonnées
      • Il devient possible d’ajouter un horodatage à toutes les données
      • De distinguer les entrées des sorties
      • xterm.js fonctionne de manière similaire
    • Combiné à l’intégration du shell, cela permet de distinguer au niveau des données l’invite du shell de la sortie du programme
    • On obtient un journal structuré de la session terminal
      • Relecture du journal comme un enregistrement à la manière d’asciinema
      • Transformation de l’invite du shell sans réexécuter toutes les commandes
      • Import dans Jupyter Notebook ou Atuin Desktop
      • Sauvegarde de commandes pour les réexécuter plus tard sous forme de script
      • Le terminal devient de la donnée
  • Étape 4 : frontend de type Jupyter

    • C’est la première étape qui touche réellement à l’émulateur de terminal, et c’est volontairement la dernière
      • Car c’est là que le coût de changement est le plus élevé
    • Fournir une bonne UI en exploitant toutes les fonctions construites auparavant
    • La CLI transaction n’est alors plus nécessaire, sauf si l’on veut des transactions imbriquées
      • Toute la session terminal démarre par défaut comme une transaction
    • Comme tous les éléments ont été réunis, toutes les fonctions dérivées mentionnées plus haut deviennent disponibles

Conclusion

  • Cette architecture est audacieuse, ambitieuse et devrait demander jusqu’à environ 10 ans pour être entièrement construite
  • Il faut avancer avec patience, étape par étape
  • L’auteur espère que ce texte inspirera quelqu’un à commencer à la construire lui-même

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.