Skip to main content

agent_procs/tui/
mod.rs

1//! Terminal UI for real-time process monitoring.
2//!
3//! The TUI connects to a running daemon session and displays a split-pane
4//! layout: a process list on the left and streaming output on the right.
5//! It polls status every 2 seconds and streams output via `Logs --follow`.
6//!
7//! See [`app`] for state management, [`input`] for keybindings, and
8//! [`ui`] for rendering.
9
10pub mod app;
11pub mod disk_log_reader;
12pub mod event_loop;
13pub mod input;
14pub mod ui;
15
16use crate::cli;
17use app::App;
18use crossterm::{
19    event::{DisableMouseCapture, EnableMouseCapture},
20    execute,
21    terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
22};
23use ratatui::prelude::*;
24use std::io;
25
26pub async fn run(session: &str) -> i32 {
27    // Verify daemon is running
28    if cli::connect(session, false).await.is_err() {
29        eprintln!(
30            "error: no daemon running for session '{}'. Start processes first.",
31            session
32        );
33        return 1;
34    }
35
36    // Set up terminal
37    if let Err(e) = enable_raw_mode() {
38        eprintln!("error: failed to enable raw mode: {}", e);
39        return 1;
40    }
41    let mut stdout = io::stdout();
42    if let Err(e) = execute!(stdout, EnterAlternateScreen, EnableMouseCapture) {
43        let _ = disable_raw_mode();
44        eprintln!("error: failed to enter alternate screen: {}", e);
45        return 1;
46    }
47
48    // Install panic hook to restore terminal
49    let original_hook = std::panic::take_hook();
50    std::panic::set_hook(Box::new(move |panic_info| {
51        let _ = disable_raw_mode();
52        let _ = execute!(io::stdout(), DisableMouseCapture, LeaveAlternateScreen);
53        original_hook(panic_info);
54    }));
55
56    let mut terminal = match Terminal::new(CrosstermBackend::new(stdout)) {
57        Ok(t) => t,
58        Err(e) => {
59            let _ = disable_raw_mode();
60            let _ = execute!(io::stdout(), LeaveAlternateScreen);
61            eprintln!("error: failed to initialize terminal: {}", e);
62            return 1;
63        }
64    };
65    let mut app = App::new();
66
67    // Initialize disk readers and load recent history into hot buffer
68    event_loop::init_disk_readers(session, &mut app);
69
70    // Create event loop and spawn background tasks
71    let mut event_loop = event_loop::TuiEventLoop::new(session);
72    event_loop.spawn_background_tasks();
73
74    // Run the main event loop
75    event_loop.run(&mut terminal, &mut app).await;
76
77    // Restore terminal
78    let _ = disable_raw_mode();
79    let _ = execute!(
80        terminal.backend_mut(),
81        DisableMouseCapture,
82        LeaveAlternateScreen
83    );
84    0
85}