// memory-search CLI — thin wrapper around poc_memory::memory_search // // --hook: run hook logic (for debugging; poc-hook calls the library directly) // no args: show seen set for current session use clap::Parser; use std::fs; use std::io::{self, Read, Write}; const STASH_PATH: &str = "/tmp/claude-memory-search/last-input.json"; #[derive(Parser)] #[command(name = "memory-search")] struct Args { /// Run hook logic (reads JSON from stdin or stash file) #[arg(long)] hook: bool, } fn show_seen() { let input = match fs::read_to_string(STASH_PATH) { Ok(s) => s, Err(_) => { eprintln!("No session state available"); return; } }; let Some(session) = poc_memory::memory_search::Session::from_json(&input) else { eprintln!("No session state available"); return; }; println!("Session: {}", session.session_id); if let Ok(cookie) = fs::read_to_string(&session.path("cookie")) { println!("Cookie: {}", cookie.trim()); } match fs::read_to_string(&session.path("compaction")) { Ok(s) => { let offset: u64 = s.trim().parse().unwrap_or(0); let ts = poc_memory::transcript::compaction_timestamp(&session.transcript_path, offset); match ts { Some(t) => println!("Last compaction: offset {} ({})", offset, t), None => println!("Last compaction: offset {}", offset), } } Err(_) => println!("Last compaction: none detected"), } let pending = fs::read_dir(&session.path("chunks")).ok() .map(|d| d.flatten().count()).unwrap_or(0); if pending > 0 { println!("Pending chunks: {}", pending); } for (label, suffix) in [("Current seen set", ""), ("Previous seen set (pre-compaction)", "-prev")] { let path = session.state_dir.join(format!("seen{}-{}", suffix, session.session_id)); let content = fs::read_to_string(&path).unwrap_or_default(); let lines: Vec<&str> = content.lines().filter(|s| !s.is_empty()).collect(); if lines.is_empty() { continue; } println!("\n{} ({}):", label, lines.len()); for line in &lines { println!(" {}", line); } } } fn main() { let args = Args::parse(); if args.hook { // Read from stdin if piped, otherwise from stash let input = { let mut buf = String::new(); io::stdin().read_to_string(&mut buf).ok(); if buf.trim().is_empty() { fs::read_to_string(STASH_PATH).unwrap_or_default() } else { let _ = fs::create_dir_all("/tmp/claude-memory-search"); let _ = fs::write(STASH_PATH, &buf); buf } }; let output = poc_memory::memory_search::run_hook(&input); print!("{}", output); } else { show_seen() } }