diff --git a/Cargo.toml b/Cargo.toml index e6f60c7..1066b08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,10 @@ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls- [build-dependencies] capnpc = "0.20" +[lib] +name = "poc_memory" +path = "src/lib.rs" + [[bin]] name = "poc-memory" path = "src/main.rs" diff --git a/src/bin/memory-search.rs b/src/bin/memory-search.rs index db3924b..48e8bdf 100644 --- a/src/bin/memory-search.rs +++ b/src/bin/memory-search.rs @@ -7,6 +7,8 @@ // Reads JSON from stdin (Claude Code UserPromptSubmit hook format), // outputs results for injection into the conversation. +use poc_memory::search; +use poc_memory::store; use std::collections::HashSet; use std::fs; use std::io::{self, Read, Write}; @@ -76,24 +78,24 @@ fn main() { } } - let query = extract_query_terms(prompt, 3); + let query = search::extract_query_terms(prompt, 3); if query.is_empty() { return; } - let output = Command::new("poc-memory") - .args(["search", &query]) - .output(); - - let search_output = match output { - Ok(o) if o.status.success() => String::from_utf8_lossy(&o.stdout).to_string(), - _ => return, + let store = match store::Store::load() { + Ok(s) => s, + Err(_) => return, }; - if search_output.trim().is_empty() { + let results = search::search(&query, &store); + if results.is_empty() { return; } + // Format results like poc-memory search output + let search_output = search::format_results(&results); + let cookie = fs::read_to_string(&cookie_path).unwrap_or_default().trim().to_string(); let seen = load_seen(&state_dir, session_id); @@ -128,27 +130,6 @@ fn main() { cleanup_stale_files(&state_dir, Duration::from_secs(86400)); } -fn extract_query_terms(text: &str, max_terms: usize) -> String { - const STOP_WORDS: &[&str] = &[ - "the", "a", "an", "is", "are", "was", "were", "do", "does", "did", - "have", "has", "had", "will", "would", "could", "should", "can", - "may", "might", "shall", "been", "being", "to", "of", "in", "for", - "on", "with", "at", "by", "from", "as", "but", "or", "and", "not", - "no", "if", "then", "than", "that", "this", "it", "its", "my", - "your", "our", "we", "you", "i", "me", "he", "she", "they", "them", - "what", "how", "why", "when", "where", "about", "just", "let", - "want", "tell", "show", "think", "know", "see", "look", "make", - "get", "go", "some", "any", "all", "very", "really", "also", "too", - "so", "up", "out", "here", "there", - ]; - - text.to_lowercase() - .split(|c: char| !c.is_alphanumeric()) - .filter(|w| !w.is_empty() && w.len() > 2 && !STOP_WORDS.contains(w)) - .take(max_terms) - .collect::>() - .join(" ") -} fn extract_key_from_line(line: &str) -> Option { let after_bracket = line.find("] ")?; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ae56baf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,28 @@ +// poc-memory library — shared modules for all binaries +// +// Re-exports modules so that memory-search and other binaries +// can call library functions directly instead of shelling out. + +pub mod config; +pub mod store; +pub mod util; +pub mod llm; +pub mod digest; +pub mod audit; +pub mod enrich; +pub mod consolidate; +pub mod graph; +pub mod search; +pub mod similarity; +pub mod migrate; +pub mod neuro; +pub mod query; +pub mod spectral; +pub mod lookups; +pub mod daemon; +pub mod fact_mine; +pub mod knowledge; + +pub mod memory_capnp { + include!(concat!(env!("OUT_DIR"), "/schema/memory_capnp.rs")); +} diff --git a/src/search.rs b/src/search.rs index 8eedbf0..8f41302 100644 --- a/src/search.rs +++ b/src/search.rs @@ -139,3 +139,18 @@ pub fn extract_query_terms(text: &str, max_terms: usize) -> String { .collect::>() .join(" ") } + +/// Format search results as text lines (for hook consumption). +pub fn format_results(results: &[SearchResult]) -> String { + let mut out = String::new(); + for (i, r) in results.iter().enumerate().take(5) { + let marker = if r.is_direct { "→" } else { " " }; + out.push_str(&format!("{}{:2}. [{:.2}/{:.2}] {}", + marker, i + 1, r.activation, r.activation, r.key)); + out.push('\n'); + if let Some(ref snippet) = r.snippet { + out.push_str(&format!(" {}\n", snippet)); + } + } + out +} diff --git a/src/util.rs b/src/util.rs index 550cc8b..27cf53a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -6,7 +6,7 @@ use std::fs; use std::path::PathBuf; /// Ensure a subdirectory of the memory dir exists and return its path. -pub(crate) fn memory_subdir(name: &str) -> Result { +pub fn memory_subdir(name: &str) -> Result { let dir = store::memory_dir().join(name); fs::create_dir_all(&dir) .map_err(|e| format!("create {}: {}", dir.display(), e))?;