Some checks failed
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
CI / Build & test (Node 22) (push) Has been cancelled
Deploy site (production) / build-and-deploy (push) Successful in 20s
Remplace les 547 tirets cadratins (U+2014) et demi-cadratins (U+2013) des fichiers versionnés par la ponctuation contextuelle adaptée (point médian, deux-points, virgule, parenthèses ; tiret simple pour les plages), sur 122 fichiers (appli, vitrine, doc, tests, workflows, scripts). Ajoute le job CI « lint-dashes » (git grep -P) qui échoue si un tiret cadratin/demi-cadratin réapparaît, hors logo binaire et captures brutes du terminal (fidélité des fixtures de détection de dialogue).
46 lines
1.8 KiB
TypeScript
46 lines
1.8 KiB
TypeScript
// Reconstruction d'écran via @xterm/headless : terminal headless PERSISTANT par session, alimenté
|
|
// incrémentalement par le flux PTY. Remplace le strip ANSI naïf (qui « mange les espaces » et casse
|
|
// la détection des dialogues, verdict S1/S3). Aucune dépendance DOM (usage Node).
|
|
import { createRequire } from 'node:module';
|
|
import type { Terminal as XtermTerminal } from '@xterm/headless';
|
|
|
|
// @xterm/headless est publié en CommonJS : sous Node ESM natif l'import nommé échoue
|
|
// (cjs-module-lexer ne détecte pas l'export). On charge via require, typé par l'import type.
|
|
const require = createRequire(import.meta.url);
|
|
const { Terminal } = require('@xterm/headless') as { Terminal: typeof XtermTerminal };
|
|
|
|
export class ScreenReader {
|
|
private readonly term: XtermTerminal;
|
|
|
|
constructor(cols = 120, rows = 40) {
|
|
this.term = new Terminal({ cols, rows, scrollback: 0, allowProposedApi: true });
|
|
}
|
|
|
|
/**
|
|
* Alimente le terminal avec un chunk PTY brut (la frontière UTF-8 et les séquences ANSI coupées
|
|
* sont gérées par xterm). La promesse se résout quand le chunk a été parsé (snapshot fiable ensuite).
|
|
*/
|
|
feed(chunk: Uint8Array | string): Promise<void> {
|
|
return new Promise((resolve) => this.term.write(chunk as Uint8Array, resolve));
|
|
}
|
|
|
|
resize(cols: number, rows: number): void {
|
|
this.term.resize(cols, rows);
|
|
}
|
|
|
|
/** Lignes visibles du viewport courant, espaces préservés (trim à droite uniquement). */
|
|
snapshotLines(): string[] {
|
|
const buf = this.term.buffer.active;
|
|
const lines: string[] = [];
|
|
for (let y = 0; y < this.term.rows; y++) {
|
|
const line = buf.getLine(buf.baseY + y);
|
|
lines.push(line ? line.translateToString(true) : '');
|
|
}
|
|
return lines;
|
|
}
|
|
|
|
dispose(): void {
|
|
this.term.dispose();
|
|
}
|
|
}
|