//! Matrix bot integration for Story Kit. //! //! When a `.story_kit/bot.toml` file is present with `enabled = true`, the //! server spawns a Matrix bot that: //! //! 1. Connects to the configured homeserver and joins the configured room. //! 2. Listens for messages from other users in the room. //! 3. Passes each message to Claude Code (the same provider as the web UI), //! which has native access to Story Kit MCP tools. //! 4. Posts Claude Code's response back to the room. //! //! The bot is optional — if `bot.toml` is missing or `enabled = false`, the //! server starts normally with no Matrix connection. //! //! Multi-room support: configure `room_ids = ["!room1:…", "!room2:…"]` in //! `bot.toml`. Each room maintains its own independent conversation history. mod bot; pub mod commands; mod config; pub mod delete; pub mod htop; pub mod notifications; pub use config::BotConfig; use crate::agents::AgentPool; use crate::http::context::PermissionForward; use crate::io::watcher::WatcherEvent; use std::path::Path; use std::sync::Arc; use tokio::sync::{Mutex as TokioMutex, broadcast, mpsc}; /// Attempt to start the Matrix bot. /// /// Reads the bot configuration from `.story_kit/bot.toml`. If the file is /// absent or `enabled = false`, this function returns immediately without /// spawning anything — the server continues normally. /// /// When the bot is enabled, a notification listener is also spawned that /// posts stage-transition messages to all configured rooms whenever a work /// item moves between pipeline stages. /// /// `perm_rx` is the permission-request receiver shared with the MCP /// `prompt_permission` tool. The bot locks it during active chat sessions /// to surface permission prompts to the Matrix room and relay user decisions. /// /// Must be called from within a Tokio runtime context (e.g., from `main`). pub fn spawn_bot( project_root: &Path, watcher_tx: broadcast::Sender, perm_rx: Arc>>, agents: Arc, ) { let config = match BotConfig::load(project_root) { Some(c) => c, None => { crate::slog!("[matrix-bot] bot.toml absent or disabled; Matrix integration skipped"); return; } }; crate::slog!( "[matrix-bot] Starting Matrix bot → homeserver={} rooms={:?}", config.homeserver, config.effective_room_ids() ); let root = project_root.to_path_buf(); let watcher_rx = watcher_tx.subscribe(); tokio::spawn(async move { if let Err(e) = bot::run_bot(config, root, watcher_rx, perm_rx, agents).await { crate::slog!("[matrix-bot] Fatal error: {e}"); } }); }