diff --git a/server/src/service/gateway/io.rs b/server/src/service/gateway/io.rs index 8eaae0e8..f1f2b08f 100644 --- a/server/src/service/gateway/io.rs +++ b/server/src/service/gateway/io.rs @@ -422,7 +422,16 @@ pub fn spawn_gateway_bot( use tokio::sync::{broadcast, mpsc}; let (watcher_tx, _) = broadcast::channel(16); - let (_perm_tx, perm_rx) = mpsc::unbounded_channel(); + let (perm_tx, perm_rx) = mpsc::unbounded_channel(); + // Keep the sender alive for the gateway's lifetime so the matrix bot's + // `permission_listener` task doesn't exit immediately with + // "perm_rx channel closed". Previously `_perm_tx` was dropped when + // `spawn_gateway_bot` returned, closing the channel before the + // listener could even register. Story 898 (sled→gateway WS uplink) + // will eventually wire in a real sender; for now the leak keeps the + // channel open with no senders writing to it, matching the original + // intent of "listener watches forever, waiting for requests". + std::mem::forget(perm_tx); let perm_rx = std::sync::Arc::new(tokio::sync::Mutex::new(perm_rx)); let (shutdown_tx, shutdown_rx) = @@ -431,18 +440,36 @@ pub fn spawn_gateway_bot( let agents = std::sync::Arc::new(AgentPool::new(port, watcher_tx.clone())); + // Read the gateway's bot.toml so display_name, ambient_rooms, and + // permission_timeout_secs are honoured (matches the standard-mode + // initialisation in main.rs). Previously this path hardcoded + // `bot_name = "Assistant"` regardless of bot.toml's display_name, + // breaking @-addressing for users who configured a different name. + let bot_cfg = crate::chat::transport::matrix::BotConfig::load(config_dir); + let services = std::sync::Arc::new(Services { project_root: config_dir.to_path_buf(), status: agents.status_broadcaster(), agents, - bot_name: "Assistant".to_string(), + bot_name: bot_cfg + .as_ref() + .and_then(|c| c.display_name.clone()) + .unwrap_or_else(|| "Assistant".to_string()), bot_user_id: String::new(), - ambient_rooms: std::sync::Arc::new(std::sync::Mutex::new(std::collections::HashSet::new())), + ambient_rooms: std::sync::Arc::new(std::sync::Mutex::new( + bot_cfg + .as_ref() + .map(|c| c.ambient_rooms.iter().cloned().collect()) + .unwrap_or_default(), + )), perm_rx, pending_perm_replies: std::sync::Arc::new(tokio::sync::Mutex::new( std::collections::HashMap::new(), )), - permission_timeout_secs: 120, + permission_timeout_secs: bot_cfg + .as_ref() + .map(|c| c.permission_timeout_secs) + .unwrap_or(120), }); let timer_store = std::sync::Arc::new(crate::service::timer::TimerStore::load(