Files
arboretum/packages/server/src/core/dialog-classifier.ts
Johan LEROY 65ef616867
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
chore(typo): retire tous les tirets cadratins/demi-cadratins + garde CI
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).
2026-07-17 16:44:00 +02:00

47 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;
}