Skip to content

fix(terminal): a real shell layer — lists, pipelines and redirections (THI-353) - #389

Merged
thierryvm merged 2 commits into
mainfrom
fix/thi-353-redirections
Sep 24, 2026
Merged

thierryvm merged 2 commits into
mainfrom
fix/thi-353-redirections

Conversation

@thierryvm

@thierryvm thierryvm commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Why

THI-353, step 3 — the last 3 cases of the ratchet. The engine only knew echo > file and two-stage pipes split on every | character:

  • ls fichier-inexistant 2> erreurs.txt (the stderr lesson) still printed the error in red and wrote nothing;
  • ls | tee ma-liste.txt never wrote the file;
  • chmod +x script.sh && ./script.sh, cited by the lessons, ran as one broken command;
  • grep "a|b" f was cut in two.

What

  • shellSyntax.ts (pure parser): quote-aware ; && || | and redirections > >> 2> 2>&1 >&2 &> <, PowerShell *> and 2>$null. Escaped operators stay literal (find … \;), Windows paths keep their backslashes.
  • runLine / runPipeline: stdout and stderr are routed separately (screen, next command, file, /dev/null / $null), in the order they are written (> f 2>&1 differs from 2>&1 > f, like bash). Targets are opened before the command runs (a missing directory stops that command). && / || use the status of the last command of the pipeline. Pipeline stages run in a subshell: only files persist. The history records the line once.
  • Plain commands keep the historical path character for character (isPlainCommand → runSimple(state, line)).
  • Filters reading stdin: wc, grep -v/-c, sort -k/-n/-r, head, tail, uniq -c, tee -a, Tee-Object, Out-File, Set-Content, Add-Content, Out-Null, Measure-Object, Select-Object, Sort-Object, Select-String, findstr, Stop-Process.
  • ls into a pipe or a file writes one name per line, like a real ls — found in the browser check: ls | wc -l and Get-ChildItem | Measure-Object counted 1. ls -1 added.
  • Get-Item (PowerShell): the item, or Cannot find path '…' because it does not exist.
  • Coloured lines (success, e.g. git log) are standard output: they now travel through pipes (the old pipe dropped them).

Ratchet KNOWN_DESYNCS: 3 → 0. Lesson theory replay (757 commands): 0 regression, 23 more examples now match.

Gates

  • test-runner: type-check ✅ lint ✅, 2614 pass; the 3 failures are the known Supabase integration timeouts under full-suite load (28/28 when run alone)
  • New src/test/shellLayer.test.ts (48 tests) written first and seen red on main (31 failing); engine tests for every new command in terminalEngine.test.ts
  • Build ✅
  • Chrome (local, Windows + Linux, desktop and 390 px): 2> leaves no red line and fills the file, Tee-Object shows and writes, Measure-Object counts 3 items, && / || / ; behave like bash, 0 horizontal overflow
  • feature-dev:code-reviewer: running, findings addressed in follow-up commits

Refs THI-353

🤖 Generated with Claude Code

Résumé par Sourcery

Implémentation d’une véritable couche d’exécution shell pour les commandes composées, les pipelines et la redirection des flux dans les terminaux Unix et PowerShell.

Nouvelles fonctionnalités :

  • Ajout d’une couche shell prenant en charge les guillemets, les listes de commandes, les pipelines, l’entrée standard et les redirections ordonnées de la sortie et des erreurs dans les environnements Unix et PowerShell.
  • Prise en charge des commandes Unix et PowerShell courantes filtrant l’entrée standard, notamment le comptage, le filtrage, le tri, la sélection, la duplication vers une sortie (tee), la redirection du contenu et la gestion des processus.
  • Ajout du comportement Get-Item de PowerShell pour les chemins existants et inexistants.

Corrections de bugs :

  • Routage correct de stdout et stderr vers les écrans, les pipelines, les fichiers et les périphériques nuls, y compris la duplication des descripteurs dépendante de l’ordre.
  • Conservation des opérateurs shell entre guillemets et échappés, des chemins Windows, de la sortie colorée des commandes et d’une seule entrée d’historique pour les commandes composées.
  • Production, par ls et les listes de répertoires PowerShell, d’une sortie orientée ligne lorsqu’elles sont utilisées avec des pipelines ou des fichiers.
  • Élimination de toutes les désynchronisations détectées de fidélité des leçons pour les scénarios shell ciblés.

Améliorations :

  • Conservation du chemin d’exécution existant pour les commandes simples, tout en activant la sémantique shell pour les commandes composées.
  • Garantie que l’exécution des pipelines préserve les modifications du système de fichiers tout en isolant les autres états des sous-shells.

Tests :

  • Ajout d’une couverture complète des analyseurs et de l’exécution shell pour les redirections, les pipelines, les listes de commandes, les filtres, les cmdlets PowerShell et la fidélité des leçons.
  • Extension des tests du moteur de terminal pour les commandes PowerShell basées sur des objets, les filtres Unix et la sortie colorée à travers les pipelines.
Original summary in English

Résumé par Sourcery

Implémentation d’une couche d’exécution shell prenant en charge la composition réaliste des commandes, le routage des flux, les pipelines et les redirections dans les terminaux Unix et PowerShell.

Nouvelles fonctionnalités :

  • Ajout de l’analyse et de l’exécution shell pour les listes de commandes entre guillemets, les pipelines, l’entrée standard et les redirections ordonnées de la sortie standard et de la sortie d’erreur dans les terminaux Unix et PowerShell.
  • Prise en charge des filtres Unix sensibles à l’entrée standard et des applets de commande de pipeline PowerShell, notamment le comptage, le filtrage, le tri, la sélection, la duplication des flux, la redirection du contenu et la gestion des processus.
  • Ajout du comportement PowerShell de Get-Item pour les chemins existants et inexistants.

Corrections de bugs :

  • Routage correct de la sortie et des erreurs des commandes vers les écrans, les pipelines, les fichiers et les périphériques nuls, tout en préservant l’ordre des redirections.
  • Préservation des opérateurs shell entre guillemets et échappés, des chemins Windows, de la sortie colorée et d’une seule entrée d’historique pour les commandes composées.
  • Production de sorties orientées ligne pour les listes de répertoires dans les pipelines et les fichiers, et suppression des désynchronisations ciblées de fidélité des leçons.

Améliorations :

  • Conservation du chemin d’exécution existant pour les commandes simples, tout en appliquant la sémantique shell aux commandes composées et aux pipelines.
  • Isolation des changements d’état de chaque étape du pipeline tout en préservant les écritures dans le système de fichiers.

Tests :

  • Ajout d’une couverture complète de l’analyseur et de l’exécution shell pour les listes, les pipelines, les redirections, les filtres, les applets de commande PowerShell et le comportement des statuts des commandes.
  • Extension des tests du moteur de terminal pour les pipelines d’objets, les filtres Unix et la sortie colorée transitant par les pipelines.
Original summary in English

Summary by Sourcery

Implement a shell execution layer that supports realistic command composition, stream routing, pipelines, and redirections in Unix and PowerShell terminals.

New Features:

  • Add shell parsing and execution for quoted command lists, pipelines, stdin, and ordered stdout/stderr redirections across Unix and PowerShell terminals.
  • Support stdin-aware Unix filters and PowerShell pipeline cmdlets, including counting, filtering, sorting, selection, teeing, content redirection, and process handling.
  • Add PowerShell Get-Item behavior for existing and missing paths.

Bug Fixes:

  • Correctly route command output and errors through screens, pipelines, files, and null devices while preserving redirection order.
  • Preserve quoted and escaped shell operators, Windows paths, colored output, and single-entry history for compound commands.
  • Make directory listings produce line-oriented output in pipelines and files, and eliminate the targeted lesson-fidelity desynchronizations.

Enhancements:

  • Retain the existing execution path for plain commands while applying shell semantics to compound commands and pipelines.
  • Isolate pipeline-stage state changes while preserving filesystem writes.

Tests:

  • Add comprehensive parser and shell execution coverage for lists, pipelines, redirections, filters, PowerShell cmdlets, and command status behavior.
  • Extend terminal engine tests for object pipelines, Unix filters, and colored output flowing through pipelines.

… (THI-353)

The engine only knew `echo > file` and two-stage pipes split on every `|`.
`ls fichier 2> erreurs.txt` printed the error anyway, `tee` wrote nothing,
and `chmod +x x && ./x`, cited by the lessons, ran as one broken command.

- shellSyntax.ts: quote-aware parsing of `;` `&&` `||` `|` and redirections
  `>` `>>` `2>` `2>&1` `>&2` `&>` `<` (PowerShell `*>`, `2>$null`)
- runLine / runPipeline: stdout and stderr routed separately (screen, next
  command, file, /dev/null), targets opened before the command runs, pipeline
  stages in a subshell (only files persist), history records the line once
- runFilter: wc, grep -v/-c, sort -k/-n/-r, head, tail, uniq -c, tee -a,
  Tee-Object, Out-File, Set/Add-Content, Out-Null, Measure-Object,
  Select-Object, Sort-Object, Select-String, findstr, Stop-Process
- ls writes one name per line into a pipe or a file, like a real ls
  (`ls | wc -l` counted 1); `ls -1` added
- Get-Item (PowerShell)
- KNOWN_DESYNCS ratchet: 3 -> 0

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@vercel

vercel Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
terminal-learning Ready Ready Preview Sep 24, 2026 11:36am UTC

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @thierryvm, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 2 days and 7 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 24, 2026

Copy link
Copy Markdown

Guide du réviseur

Construit une véritable couche shell autour du moteur de terminal : un analyseur prenant en charge les guillemets alimente le routage ordonné de stdout/stderr, les pipelines à plusieurs étapes, les listes de commandes conditionnelles, les filtres stdin et les équivalents PowerShell, tout en préservant le chemin d’exécution des commandes simples et en ajoutant une couverture complète des régressions.

Diagramme de séquence pour l’exécution des pipelines et des redirections

sequenceDiagram
    participant User
    participant Engine as processCommand
    participant Parser as parseCommandLine
    participant Runner as runPipeline
    participant Command as runSimple or runFilter
    participant FS as Virtual filesystem
    participant Screen

    User->>Engine: Enter command line
    Engine->>Parser: parseCommandLine(line, env)
    Parser-->>Engine: Lists, stages, redirects
    Engine->>Runner: runPipeline(state, stages, env)
    Runner->>FS: Open redirection targets
    Runner->>Command: Execute stage with stdin
    Command-->>Runner: stdout and stderr lines
    Runner->>FS: Write redirected file output
    Runner->>Command: Pass stdout to next stage
    Runner->>Screen: Route screen output and errors
    Runner-->>Engine: Pipeline status and state
    Engine-->>User: Display output
Loading

Modifications au niveau des fichiers

Modification Détails Fichiers
Introduit un analyseur shell prenant en charge les guillemets et les caractères d’échappement pour les listes de commandes, les pipelines et les redirections ordonnées dans les syntaxes Unix et PowerShell.
  • Tokenise les opérateurs protégés sans séparer le contenu entre guillemets ou échappé.
  • Analyse ;, &&, `
Remplace la gestion ponctuelle des pipes et des redirections d’echo par une couche d’exécution shell prenant en charge les flux.
  • Achemine indépendamment stdout et stderr vers l’écran, le pipeline, des fichiers ou des périphériques nuls, tout en préservant l’ordre des redirections et en ouvrant les cibles avant l’exécution.
  • Exécute des pipelines et des listes de longueur arbitraire avec le statut de la dernière étape pour &&/`
Ajoute la prise en charge de la recherche d’éléments PowerShell ainsi que les diagnostics attendus pour les chemins manquants.
  • Implémente la résolution des chemins et l’affichage des éléments pour Get-Item/gi.
  • Enregistre la commande dans l’ensemble de commandes Windows et renvoie des erreurs au format PowerShell pour les éléments manquants.
src/app/data/commands/windows.ts
Étend la couverture automatisée des nouvelles sémantiques shell et des intégrations de commandes.
  • Ajoute des tests pour l’analyseur, les redirections, les pipelines, les listes, l’historique, les filtres Unix et les cmdlets PowerShell.
  • Ajoute des tests de régression pour Get-Item, les filtres tenant compte des tableaux, les commandes de contenu, la recherche sensible à la casse, le tri et la sortie colorée via des pipes.
  • Supprime les trois désynchronisations connues des leçons.
src/test/shellLayer.test.ts
src/test/terminalEngine.test.ts
src/test/lessonFidelity.test.ts

Conseils et commandes

Interagir avec Sourcery

  • Déclencher une nouvelle revue : commentez @sourcery-ai review sur la pull request.
  • Poursuivre les discussions : répondez directement aux commentaires de revue de Sourcery.
  • Générer une issue GitHub à partir d’un commentaire de revue : demandez à Sourcery de créer une issue à partir d’un commentaire de revue en y répondant. Vous pouvez également répondre à un commentaire de revue avec @sourcery-ai issue pour créer une issue à partir de celui-ci.
  • Générer un titre de pull request : écrivez @sourcery-ai n’importe où dans le titre de la pull request pour générer un titre à tout moment. Vous pouvez également commenter @sourcery-ai title sur la pull request pour générer (ou régénérer) le titre à tout moment.
  • Générer un résumé de pull request : écrivez @sourcery-ai summary n’importe où dans le corps de la pull request pour générer un résumé de PR à tout moment, exactement à l’endroit souhaité. Vous pouvez également commenter @sourcery-ai summary sur la pull request pour générer (ou régénérer) le résumé à tout moment.
  • Générer le guide du réviseur : commentez @sourcery-ai guide sur la pull request pour générer (ou régénérer) le guide du réviseur à tout moment.
  • Résoudre tous les commentaires de Sourcery : commentez @sourcery-ai resolve sur la pull request pour résoudre tous les commentaires de Sourcery. Utile si vous avez déjà traité tous les commentaires et ne souhaitez plus les voir.
  • Ignorer toutes les revues de Sourcery : commentez @sourcery-ai dismiss sur la pull request pour ignorer toutes les revues existantes de Sourcery. Particulièrement utile si vous souhaitez repartir de zéro avec une nouvelle revue — n’oubliez pas de commenter @sourcery-ai review pour déclencher une nouvelle revue !

Personnaliser votre expérience

Accédez à votre tableau de bord pour :

  • Activer ou désactiver des fonctionnalités de revue, telles que le résumé de pull request généré par Sourcery, le guide du réviseur, etc.
  • Modifier la langue de la revue.
  • Ajouter, supprimer ou modifier des instructions de revue personnalisées.
  • Ajuster d’autres paramètres de revue.

Obtenir de l’aide

Original review guide in English

Reviewer's Guide

Builds a real shell layer around the terminal engine: a quote-aware parser feeds ordered stdout/stderr routing, multi-stage pipelines, conditional command lists, stdin filters, and PowerShell equivalents, while preserving the plain-command path and adding comprehensive regression coverage.

Sequence diagram for pipeline and redirection execution

sequenceDiagram
    participant User
    participant Engine as processCommand
    participant Parser as parseCommandLine
    participant Runner as runPipeline
    participant Command as runSimple or runFilter
    participant FS as Virtual filesystem
    participant Screen

    User->>Engine: Enter command line
    Engine->>Parser: parseCommandLine(line, env)
    Parser-->>Engine: Lists, stages, redirects
    Engine->>Runner: runPipeline(state, stages, env)
    Runner->>FS: Open redirection targets
    Runner->>Command: Execute stage with stdin
    Command-->>Runner: stdout and stderr lines
    Runner->>FS: Write redirected file output
    Runner->>Command: Pass stdout to next stage
    Runner->>Screen: Route screen output and errors
    Runner-->>Engine: Pipeline status and state
    Engine-->>User: Display output
Loading

File-Level Changes

Change Details Files
Introduces a quote- and escape-aware shell parser for command lists, pipelines, and ordered redirections across Unix and PowerShell syntax.
  • Tokenizes protected operators without splitting quoted or escaped content.
  • Parses ;, &&, `
Replaces ad hoc pipe and echo-redirection handling with a stream-aware shell execution layer.
  • Routes stdout and stderr independently to the screen, pipeline, files, or null devices, preserving redirection order and opening targets before execution.
  • Executes arbitrary-length pipelines and lists with last-stage status for &&/`
Adds PowerShell item lookup support and expected missing-path diagnostics.
  • Implements Get-Item/gi path resolution and item output.
  • Registers the command in the Windows command set and returns PowerShell-style errors for missing items.
src/app/data/commands/windows.ts
Expands automated coverage for the new shell semantics and command integrations.
  • Adds parser, redirection, pipeline, list, history, Unix filter, and PowerShell cmdlet tests.
  • Adds regression tests for Get-Item, table-aware filters, content commands, case-sensitive matching, sorting, and colored output through pipes.
  • Removes the three known lesson desynchronizations.
src/test/shellLayer.test.ts
src/test/terminalEngine.test.ts
src/test/lessonFidelity.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

…, pipeline subshells

- A command that does not read stdin runs normally after a pipe
  (`echo x | mkdir d` created nothing, `echo hi | pwd` printed "hi")
- `claude` after a pipe explains that Claude Code is not simulated (info,
  not a red line); sed / awk / cut / tr / xargs say they are not simulated
  yet and let the text through
- CommandOutput.status: grep, Select-String and findstr exit 1 without a
  match, so `grep x f || echo repli` works
- Every command of a pipeline starts from the caller's cwd and variables;
  only files are shared (`cd documents | tee out.txt` wrote into documents/)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@thierryvm

Copy link
Copy Markdown
Owner Author

Review follow-ups (c263b50) — feature-dev:code-reviewer returned FIX FIRST with 3 findings; all fixed, each with a test seen red first:

  1. A command that does not read stdin now runs after a pipe (echo hi | mkdir test, echo hi | whoami). claude after a pipe explains it is not simulated (info line); sed/awk/cut/tr/xargs say they are not simulated yet and let the text through.
  2. CommandOutput.status: grep / Select-String / findstr exit 1 without a match, so grep x f || echo repli works.
  3. Every pipeline command starts from the caller's cwd and variables (cd documents | tee out.txt no longer writes into documents/).

Final checks on c263b50: CI green; browser census on the preview 198/198 desktop (and 198/198 at 390 px on the first commit); lesson theory replay (757 commands) 0 regression; Chrome (local): all three fixes behave like bash.

@thierryvm
thierryvm merged commit 3fad891 into main Sep 24, 2026
4 checks passed
@thierryvm
thierryvm deleted the fix/thi-353-redirections branch September 24, 2026 11:42
thierryvm added a commit that referenced this pull request Sep 24, 2026
…manent replay (THI-353) (#391)

- Replay every terminal session shown in a lesson code block through the
  engine, from the lesson's starting state, in each environment
  (src/test/lessonTheory.test.ts). Known gaps are a shrink-only ratchet
  (lessonTheoryGaps.ts, 174 entries), plus a ceiling on lessons that show
  bash to Windows learners (39).
- Fix 13 lesson examples whose output did not match (ls -l, ls -a,
  grep -n, wc, chmod, chown, apt, stderr, Windows ping) and give the PATH
  and git init lessons a single block per environment.
- ls -l size comes from the content bytes, like wc -c.
- $env:X = "..." expands $env:Y inside double quotes (PowerShell).
- git init prints C:/Users/user/... on Windows, like Git for Windows.
- CHANGELOG and STORY: catch up #389 and #390, add this change.

Co-authored-by: Claude Opus 5.5 <[email protected]>

This branch was successfully deployed

1 active deployment
Preview — c263b506 Deployed Sep 24, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant