diff --git a/src/hippocampus/memory_search.rs b/src/hippocampus/memory_search.rs index 942d4c7..6bad4d3 100644 --- a/src/hippocampus/memory_search.rs +++ b/src/hippocampus/memory_search.rs @@ -8,7 +8,7 @@ use std::collections::HashSet; use std::fs; use std::fs::File; use std::io::Write; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::process::Command; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -19,49 +19,7 @@ fn now_secs() -> u64 { /// Max bytes per context chunk (hook output limit is ~10K chars) const CHUNK_SIZE: usize = 9000; -pub struct Session { - pub session_id: String, - pub transcript_path: String, - pub hook_event: String, - pub state_dir: PathBuf, -} - -impl Session { - pub fn from_json(input: &str) -> Option { - let state_dir = PathBuf::from("/tmp/claude-memory-search"); - fs::create_dir_all(&state_dir).ok(); - - let json: serde_json::Value = serde_json::from_str(input).ok()?; - let session_id = json["session_id"].as_str().unwrap_or("").to_string(); - if session_id.is_empty() { return None; } - let transcript_path = json["transcript_path"].as_str().unwrap_or("").to_string(); - let hook_event = json["hook_event_name"].as_str().unwrap_or("").to_string(); - - Some(Session { session_id, transcript_path, hook_event, state_dir }) - } - - pub fn path(&self, prefix: &str) -> PathBuf { - self.state_dir.join(format!("{}-{}", prefix, self.session_id)) - } - - /// Load from POC_SESSION_ID environment variable - pub fn from_env() -> Option { - let session_id = std::env::var("POC_SESSION_ID").ok()?; - if session_id.is_empty() { return None; } - let state_dir = PathBuf::from("/tmp/claude-memory-search"); - Some(Session { - session_id, - transcript_path: String::new(), - hook_event: String::new(), - state_dir, - }) - } - - /// Get the seen set for this session - pub fn seen(&self) -> HashSet { - load_seen(&self.state_dir, &self.session_id) - } -} +pub use crate::session::Session; /// Run the hook logic on parsed JSON input. Returns output to inject. pub fn run_hook(input: &str) -> String { @@ -148,7 +106,7 @@ fn parse_seen_line(line: &str) -> &str { line.split_once('\t').map(|(_, key)| key).unwrap_or(line) } -fn load_seen(dir: &Path, session_id: &str) -> HashSet { +pub fn load_seen(dir: &Path, session_id: &str) -> HashSet { let path = dir.join(format!("seen-{}", session_id)); if path.exists() { fs::read_to_string(&path) diff --git a/src/lib.rs b/src/lib.rs index ca31d64..236fdfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,9 @@ pub mod subconscious; // Unified configuration pub mod config; +// Session state +pub mod session; + // Shared utilities pub mod util; diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 0000000..139060b --- /dev/null +++ b/src/session.rs @@ -0,0 +1,52 @@ +// session.rs — Session state for ambient hooks and agent interactions +// +// Tracks per-session state (seen set, state directory) across hook +// invocations. Created from hook JSON input or POC_SESSION_ID env var. + +use std::collections::HashSet; +use std::fs; +use std::path::PathBuf; + +pub struct Session { + pub session_id: String, + pub transcript_path: String, + pub hook_event: String, + pub state_dir: PathBuf, +} + +impl Session { + pub fn from_json(input: &str) -> Option { + let state_dir = PathBuf::from("/tmp/claude-memory-search"); + fs::create_dir_all(&state_dir).ok(); + + let json: serde_json::Value = serde_json::from_str(input).ok()?; + let session_id = json["session_id"].as_str().unwrap_or("").to_string(); + if session_id.is_empty() { return None; } + let transcript_path = json["transcript_path"].as_str().unwrap_or("").to_string(); + let hook_event = json["hook_event_name"].as_str().unwrap_or("").to_string(); + + Some(Session { session_id, transcript_path, hook_event, state_dir }) + } + + pub fn path(&self, prefix: &str) -> PathBuf { + self.state_dir.join(format!("{}-{}", prefix, self.session_id)) + } + + /// Load from POC_SESSION_ID environment variable + pub fn from_env() -> Option { + let session_id = std::env::var("POC_SESSION_ID").ok()?; + if session_id.is_empty() { return None; } + let state_dir = PathBuf::from("/tmp/claude-memory-search"); + Some(Session { + session_id, + transcript_path: String::new(), + hook_event: String::new(), + state_dir, + }) + } + + /// Get the seen set for this session + pub fn seen(&self) -> HashSet { + super::hippocampus::memory_search::load_seen(&self.state_dir, &self.session_id) + } +}