use crate::models::*; use crate::search::MemoryIndex; use crate::store::Store; use std::collections::HashMap; use std::path::PathBuf; use std::sync::RwLock; pub struct MemoryState { pub base_dir: PathBuf, pub graph: Store, pub search_index: RwLock, pub ledger: Store>, pub sticky: Store>, pub tasks: Store>, pub snippets: Store>, pub adrs: Store>, pub prefs: Store>, pub error_fixes: Store>, pub pinned_files: Store>, pub session_summaries: Store>, pub handoff_memos: Store>, pub env_fingerprints: Store>, pub env_requirements: Store>, pub milestones: Store>, pub environments: Store>, pub pr_checklists: Store>, pub tech_debts: Store>, pub gates: Store>, pub context_workspaces: Store>, pub activity_tx: tokio::sync::broadcast::Sender, } impl MemoryState { pub fn deduplicate(input: &mut Vec) { let mut keys = std::collections::HashSet::new(); input.retain(|entry| keys.insert(entry.clone())); } pub fn broadcast_activity(&self, message: &str) { let payload = serde_json::json!({ "type": "activity", "data": message }) .to_string(); let _ = self.activity_tx.send(payload); } pub fn get_full_graph(&self) -> KnowledgeGraph { self.graph.read() } pub fn read_graph(&self, f: F) -> R where F: FnOnce(&KnowledgeGraph) -> R, { self.graph.read_with(f) } pub fn modify_graph(&self, update_fn: F) { self.graph.modify(update_fn); } pub async fn rebuild_index(&self) { if let Ok(new_idx) = MemoryIndex::new(&self.base_dir) { let entities = self.graph.read().entities.values().cloned().collect(); let tasks = self.tasks.read().clone(); let snippets = self.snippets.read().clone(); let adrs = self.adrs.read().clone(); let handle = new_idx.index_batch(entities, tasks, snippets, adrs); let _ = handle.await; let _ = new_idx.commit().await; if let Ok(mut w) = self.search_index.write() { *w = new_idx; } } } }