P3-B: claude-adapter — états fins busy/waiting/idle

Détection de l'état fin d'une session claude et du dialogue en cours, pour
savoir « quelle session attend une réponse ». Source primaire = registre
~/.claude/sessions (stable) ; l'écran reconstruit via @xterm/headless TYPE le
dialogue (trust/permission/question/plan) et couvre le cas Trust (avant registre).

- dép: @xterm/headless ^6.0.0 (aligné sur @xterm/xterm du front).
- core/screen-reader.ts: terminal headless persistant par session, alimenté
  par le flux PTY ; snapshotLines() préserve les espaces (bat le strip ANSI naïf).
- core/dialog-classifier.ts: typage pur (texte aplati + regex tolérante inter-
  versions) + extraction des options numérotées (❯ = sélection).
- core/claude-adapter.ts: SessionActivityTracker par session (registre + écran
  → activity + dialog), évaluation débouncée sur output + poll registre léger,
  émission sur changement effectif uniquement.
- shared: SessionSummary += activity?/waitingFor?/dialog? (optionnels, additif).
- pty-manager: tracker instancié pour claude, feed dans handleOutput, summarize
  enrichi, resize propagé, dispose à l'exit.
- web: composant SessionStateBadge (busy/waiting/idle colorés) réutilisable.
- tests: screen-reader + classifier sur fixtures réelles S3 (perm-write/ask/
  trust), claude-adapter (machine à états). 159 verts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Johan LEROY
2026-06-12 18:39:38 +02:00
parent bad1230a21
commit 33a41e7a30
13 changed files with 421 additions and 10 deletions

View File

@@ -68,6 +68,21 @@ export type SessionSource =
/** Statut brut tel qu'écrit par le CLI dans ~/.claude/sessions (interprété finement en P3). */
export type SessionRegistryStatus = 'busy' | 'idle' | 'waiting';
// ---- États fins de session (P3-B, claude-adapter) ----
/** busy = Claude traite ; waiting = bloqué sur un dialogue ; idle = prêt pour une instruction. */
export type SessionActivity = 'busy' | 'waiting' | 'idle';
export type DialogKind = 'trust' | 'permission' | 'question' | 'plan';
export interface DialogOption {
n: number;
label: string;
selected: boolean;
}
export interface SessionDialog {
kind: DialogKind;
waitingFor: string | null;
options: DialogOption[];
}
export interface SessionSummary {
id: string;
cwd: string;
@@ -92,6 +107,12 @@ export interface SessionSummary {
attachable: boolean;
/** statut brut du registre ~/.claude/sessions (P2) ; interprété finement en P3 (claude-adapter). */
registryStatus: SessionRegistryStatus | null;
// ---- P3-B : états fins (optionnels, remplis par le claude-adapter) ----
/** absent/null = inconnu (bash, démarrage, historique). */
activity?: SessionActivity | null;
waitingFor?: string | null;
/** dialogue typé en cours (présent quand activity === 'waiting'). */
dialog?: SessionDialog | null;
}
// ---- Worktrees & repos (P3) ----

File diff suppressed because one or more lines are too long