pub async fn run_app(
    tasks: Vec<String>,
    receiver: AppReceiver,
    color_config: ColorConfig,
    repo_root: &AbsoluteSystemPathBuf,
    scrollback_len: u64,
) -> Result<(), Error> {
    let mut terminal = startup(color_config)?;
    let size = terminal.size()?;
    let preferences = PreferenceLoader::new(repo_root);

    let mut app: App<Box<dyn io::Write + Send>> =
        App::new(size.height, size.width, tasks, preferences, scrollback_len);
    let (crossterm_tx, crossterm_rx) = mpsc::channel(1024);
    input::start_crossterm_stream(crossterm_tx);

    let (result, callback) =
        match run_app_inner(&mut terminal, &mut app, receiver, crossterm_rx).await {
            Ok(callback) => (Ok(()), callback),
            Err(err) => {
                debug!("tui shutting down: {err}");
                (Err(err), None)
            }
        };

    cleanup(terminal, app, callback)?;

    result
}
Handle the rendering of the `App` widget based on events received by
`receiver`
crates/turborepo-ui/src/tui/app.rs