feat(agent): conversation par paire + entrée médiée + pivot terminal/MCP

Coeur inter-agents consolidé et surface front réalignée sur la décision
"terminal natif PTY, pas d'UI chat" (Option 1).

Domaine
- nouveaux modules conversation, mailbox, input, fileguard (ports + types)
- orchestrator/profile/events étendus (conversation par paire, FIFO)

Application / Infrastructure
- orchestrator/service + context_guard : sérialisation FIFO par agent,
  garde RW mémoire/contexte, dispatch ask/reply
- adapters in-memory conversation / mailbox / input / fileguard
- registry session + lifecycle agent durcis (1 agent = 1 session vivante)
- outils MCP idea_* alignés sur le nouveau dispatch

Frontend
- MediatedInput + useAgentBusy : entrée utilisateur médiée par IdeA,
  terminal = vue sortie inchangée
- suppression de la vue chat structurée (AgentChatView) — abandonnée
- adapter input + ports mis à jour

Divers
- .ideai/ : mémoire projet + briefs de cadrage versionnés ;
  requests/ runtime ignoré ; agents projet réels (DevBackend/DevFrontend/QA)

Tests : Rust (domain/application/infrastructure/app-tauri) + front (346) verts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 07:33:04 +02:00
parent 5f45c22941
commit eca2ba95c4
61 changed files with 9491 additions and 2512 deletions

View File

@ -3,7 +3,11 @@
* {@link TerminalGateway} port (or a custom opener), and fits it to its container:
*
* - PTY output (gateway `onData`) → `term.write(bytes)`.
* - xterm `onData` (keystrokes) → `handle.write(bytes)`.
* - xterm `onData` (keystrokes) → `handle.write(bytes)` **only for a plain
* (non-agent) cell** (a raw shell). In **agent mode** (`agentMode`, lot F2,
* cadrage §4.2) keystrokes are NOT written to the PTY: input is mediated by
* IdeA through {@link MediatedInput}. The PTY **output** path stays live and
* INCHANGED in both modes (xterm is always the raw output view).
* - container resize (fit addon) → `handle.resize(rows, cols)`.
*
* Pure presentation: it only knows the port, never `invoke()`/`Channel`
@ -71,6 +75,15 @@ interface TerminalViewProps {
* reattach (the id is already known).
*/
onSessionId?: (sessionId: string) => void;
/**
* Agent mode (lot F2, cadrage §4.2). When `true` the cell hosts an agent, so
* keystrokes (`term.onData`) are **not** forwarded to the PTY — input is
* mediated by IdeA through {@link MediatedInput} rendered under the terminal.
* The PTY **output** stays live and unchanged (xterm remains the raw output
* view). When `false`/absent the cell is a plain shell: keystrokes go straight
* to the PTY (current behaviour). Defaults to `false`.
*/
agentMode?: boolean;
}
export function TerminalView({
@ -79,6 +92,7 @@ export function TerminalView({
reattach,
sessionId,
onSessionId,
agentMode = false,
}: TerminalViewProps) {
const { terminal } = useGateways();
const containerRef = useRef<HTMLDivElement | null>(null);
@ -100,6 +114,8 @@ export function TerminalView({
onSessionIdRef.current = onSessionId;
const terminalRef = useRef(terminal);
terminalRef.current = terminal;
const agentModeRef = useRef(agentMode);
agentModeRef.current = agentMode;
useEffect(() => {
const container = containerRef.current;
@ -135,9 +151,14 @@ export function TerminalView({
let handle: TerminalHandle | null = null;
const encoder = new TextEncoder();
// Buffer keystrokes that arrive before the PTY finished opening.
// Keystroke → PTY path. In **agent mode** (F2) keystrokes are mediated by
// IdeA (MediatedInput) and must NOT reach the PTY here; we drop them so the
// raw terminal is output-only for the human. In **plain mode** keystrokes go
// straight to the PTY (raw shell), buffering any that arrive before the PTY
// finished opening. The output path below is unchanged in both modes.
let pending = "";
const onKey = term.onData((data) => {
if (agentModeRef.current) return;
if (handle) void handle.write(encoder.encode(data));
else pending += data;
});