diff --git a/src/user/event_loop.rs b/src/user/event_loop.rs index fe8f309..e1998f8 100644 --- a/src/user/event_loop.rs +++ b/src/user/event_loop.rs @@ -18,6 +18,29 @@ use crate::user::ui_channel::{self, UiMessage}; pub use crate::mind::MindCommand; +// ── Slash commands ───────────────────────────────────────────── + +struct SlashCommand { + name: &'static str, + help: &'static str, +} + +fn commands() -> Vec { + vec![ + SlashCommand { name: "/quit", help: "Exit consciousness" }, + SlashCommand { name: "/new", help: "Start fresh session (saves current)" }, + SlashCommand { name: "/save", help: "Save session to disk" }, + SlashCommand { name: "/retry", help: "Re-run last turn" }, + SlashCommand { name: "/model", help: "Show/switch model (/model )" }, + SlashCommand { name: "/score", help: "Score memory importance" }, + SlashCommand { name: "/dmn", help: "Show DMN state" }, + SlashCommand { name: "/sleep", help: "Put DMN to sleep" }, + SlashCommand { name: "/wake", help: "Wake DMN to foraging" }, + SlashCommand { name: "/pause", help: "Full stop — no autonomous ticks (Ctrl+P)" }, + SlashCommand { name: "/help", help: "Show this help" }, + ] +} + /// Top-level entry point — creates Mind and UI, wires them together. pub async fn start(cli: crate::user::CliArgs) -> Result<()> { let (config, _figment) = crate::config::load_session(&cli)?; @@ -34,7 +57,6 @@ pub async fn start(cli: crate::user::CliArgs) -> Result<()> { let shared_context = mind.agent.lock().await.shared_context.clone(); let shared_active_tools = mind.agent.lock().await.active_tools.clone(); - let turn_watch = mind.turn_watch(); let mut result = Ok(()); tokio_scoped::scope(|s| { @@ -48,7 +70,7 @@ pub async fn start(cli: crate::user::CliArgs) -> Result<()> { s.spawn(async { result = run( tui::App::new(String::new(), shared_context, shared_active_tools), - &mind.agent, &mind.shared, turn_watch, mind_tx, ui_tx, ui_rx, + &mind, mind_tx, ui_tx, ui_rx, ).await; }); }); @@ -56,21 +78,8 @@ pub async fn start(cli: crate::user::CliArgs) -> Result<()> { } fn send_help(ui_tx: &ui_channel::UiSender) { - let commands = &[ - ("/quit", "Exit consciousness"), - ("/new", "Start fresh session (saves current)"), - ("/save", "Save session to disk"), - ("/retry", "Re-run last turn"), - ("/model", "Show/switch model (/model )"), - ("/score", "Score memory importance"), - ("/dmn", "Show DMN state"), - ("/sleep", "Put DMN to sleep"), - ("/wake", "Wake DMN to foraging"), - ("/pause", "Full stop — no autonomous ticks (Ctrl+P)"), - ("/help", "Show this help"), - ]; - for (name, desc) in commands { - let _ = ui_tx.send(UiMessage::Info(format!(" {:12} {}", name, desc))); + for cmd in &commands() { + let _ = ui_tx.send(UiMessage::Info(format!(" {:12} {}", cmd.name, cmd.help))); } let _ = ui_tx.send(UiMessage::Info(String::new())); let _ = ui_tx.send(UiMessage::Info( @@ -257,13 +266,14 @@ fn diff_mind_state( pub async fn run( mut app: tui::App, - agent: &Arc>, - shared_mind: &crate::mind::SharedMindState, - turn_watch: tokio::sync::watch::Receiver, + mind: &crate::mind::Mind, mind_tx: tokio::sync::mpsc::UnboundedSender, ui_tx: ui_channel::UiSender, mut ui_rx: ui_channel::UiReceiver, ) -> Result<()> { + let agent = &mind.agent; + let shared_mind = &mind.shared; + let turn_watch = mind.turn_watch(); // UI-owned state let mut idle_state = crate::thalamus::idle::State::new(); idle_state.load(); @@ -450,11 +460,9 @@ pub async fn run( } _ => { let mut s = shared_mind.lock().unwrap(); - let n = s.clone(); + diff_mind_state(&s, &prev_mind, &ui_tx, &mut dirty); s.input.push(input); - drop(s); - diff_mind_state(&n, &prev_mind, &ui_tx, &mut dirty); - prev_mind = n; + prev_mind = s.clone(); } } }