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).
47 lines
2.1 KiB
TypeScript
47 lines
2.1 KiB
TypeScript
// Typage de dialogue à partir de l'écran reconstruit (ScreenReader) : fonctions PURES.
|
||
// L'écran sert à TYPER le dialogue et extraire ses options ; l'état (waiting vrai/faux) vient du
|
||
// registre (source primaire). Tolérant aux variations de rendu inter-versions (texte aplati + regex).
|
||
import type { DialogKind, DialogOption } from '@arboretum/shared';
|
||
|
||
export interface ClassifiedDialog {
|
||
kind: DialogKind;
|
||
options: DialogOption[];
|
||
}
|
||
|
||
// Option numérotée, éventuellement préfixée du curseur ❯ : « ❯ 1. Yes », « 2) No »…
|
||
const OPTION_RE = /^\s*(❯)?\s*(\d+)[.)]\s+(.*\S)\s*$/;
|
||
|
||
export function parseOptions(lines: string[]): DialogOption[] {
|
||
const out: DialogOption[] = [];
|
||
for (const line of lines) {
|
||
const m = OPTION_RE.exec(line);
|
||
if (m && m[2] && m[3]) out.push({ n: Number(m[2]), label: m[3].trim(), selected: Boolean(m[1]) });
|
||
}
|
||
return out;
|
||
}
|
||
|
||
/**
|
||
* Retourne le dialogue typé visible à l'écran, ou null si aucun. `trust` et `question` priment sur
|
||
* `permission` (un écran AskUserQuestion contient aussi « Esc to cancel »). Un écran numéroté non
|
||
* typé est traité en `permission` générique (best-effort, le fallback reste le terminal web).
|
||
*/
|
||
export function classifyDialog(lines: string[]): ClassifiedDialog | null {
|
||
const text = lines.join('\n');
|
||
const flat = text.replace(/\s+/g, '').toLowerCase();
|
||
const options = parseOptions(lines);
|
||
|
||
const isTrust = flat.includes('trust') && (text.includes('❯') || flat.includes('entertoconfirm') || flat.includes('trustthisfolder'));
|
||
const isQuestion = flat.includes('entertoselect') || flat.includes('tonavigate') || text.includes('↑/↓');
|
||
const isPermission = flat.includes('doyouwant') || flat.includes('esctocancel') || flat.includes('tabtoamend');
|
||
const isPlan = flat.includes('readytocode') || flat.includes('wouldyouliketoproceed');
|
||
|
||
let kind: DialogKind | null = null;
|
||
if (isTrust) kind = 'trust';
|
||
else if (isQuestion) kind = 'question';
|
||
else if (isPlan) kind = 'plan';
|
||
else if (isPermission) kind = 'permission';
|
||
else if (options.length > 0) kind = 'permission';
|
||
|
||
return kind ? { kind, options } : null;
|
||
}
|