pub fn new() -> (Self, AppReceiver) {
        let (primary_tx, primary_rx) = mpsc::unbounded_channel();
        let tick_sender = primary_tx.clone();
        tokio::spawn(async move {
            let mut interval = tokio::time::interval(FRAMERATE);
            loop {
                interval.tick().await;
                if tick_sender.send(Event::Tick).is_err() {
                    break;
                }
            }
        });
        (
            Self {
                primary: primary_tx,
            },
            AppReceiver {
                primary: primary_rx,
            },
        )
    }
Create a new channel for sending app events.

AppSender is meant to be held by the actual task runner
AppReceiver should be passed to `crate::tui::run_app`
crates/turborepo-ui/src/tui/handle.rs