fix(domain,infrastructure,web-server,app-tauri,frontend): TUI native noire — route PTY explicite et replay du scrollback pré-attach sans perte — #360 (QA verte)

This commit is contained in:
2026-09-16 19:08:01 +02:00
parent a833af0fb5
commit 355a482fee
8 changed files with 220 additions and 13 deletions

View File

@ -1318,8 +1318,14 @@ pub async fn open_terminal(
// stream is a blocking iterator, so it runs on a dedicated OS thread; it
// ends when the PTY hits EOF (process exit) or this attach is superseded.
let handle = PtyHandle { session_id };
match state.pty_port.subscribe_output(&handle) {
Ok(stream) => {
match state.pty_port.subscribe_output_with_scrollback(&handle) {
Ok((scrollback, stream)) => {
// The child can paint its initial screen before this command has
// finished wiring the Tauri channel. Replay that retained prefix
// before the live pump so a one-shot TUI draw is never lost.
if !scrollback.is_empty() {
let _ = state.pty_bridge.send_output(&session_id, scrollback);
}
let bridge: std::sync::Arc<PtyBridge> = std::sync::Arc::clone(&state.pty_bridge);
std::thread::spawn(move || {
for chunk in stream {
@ -2654,8 +2660,14 @@ pub async fn launch_agent(
// The stream is a blocking iterator; it runs on a dedicated OS thread and
// ends when the PTY hits EOF or this attach is superseded.
let handle = PtyHandle { session_id };
match state.pty_port.subscribe_output(&handle) {
Ok(stream) => {
match state.pty_port.subscribe_output_with_scrollback(&handle) {
Ok((scrollback, stream)) => {
// Launching a CLI performs substantial setup after the process
// starts. Its first full-screen draw may therefore predate the
// frontend channel; replay the atomic pre-attach snapshot first.
if !scrollback.is_empty() {
let _ = state.pty_bridge.send_output(&session_id, scrollback);
}
let bridge: std::sync::Arc<PtyBridge> = std::sync::Arc::clone(&state.pty_bridge);
// Captured for the level-2 tap (moved into the pump thread).
let service = std::sync::Arc::clone(&state.session_limit_service);