From 11b58e6b0b519d30f9a1d47e66b71da6a7f4f83c Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sun, 12 Apr 2026 21:54:34 -0400 Subject: [PATCH] cli: convert simple commands to use memory_rpc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commands now forward to daemon (or fallback to local store): - query → memory_query - journal tail → journal_tail - graph link-set → memory_link_set - graph link-add → memory_link_add - weight-set → memory_weight_set - node rename → memory_rename Removes ~50 lines of duplicated store access code. Co-Authored-By: Proof of Concept --- src/cli/graph.rs | 34 +++++++++------------------ src/cli/journal.rs | 57 ++++++---------------------------------------- src/cli/misc.rs | 9 +++++--- src/cli/node.rs | 21 ++++++++--------- 4 files changed, 34 insertions(+), 87 deletions(-) diff --git a/src/cli/graph.rs b/src/cli/graph.rs index 3b2e3d9..84c508e 100644 --- a/src/cli/graph.rs +++ b/src/cli/graph.rs @@ -153,35 +153,23 @@ pub fn cmd_link(key: &[String]) -> Result<(), String> { &format!("neighbors('{}') | select strength,clustering_coefficient", resolved)) } -pub fn cmd_link_add(source: &str, target: &str, reason: &[String]) -> Result<(), String> { +pub fn cmd_link_add(source: &str, target: &str, _reason: &[String]) -> Result<(), String> { super::check_dry_run(); - let mut store = store::Store::load()?; - let source = store.resolve_key(source)?; - let target = store.resolve_key(target)?; - let reason = reason.join(" "); - - match store.add_link(&source, &target, "manual") { - Ok(strength) => { - store.save()?; - println!("Linked: {} → {} (strength={:.2}, {})", source, target, strength, reason); - } - Err(msg) if msg.contains("already exists") => { - println!("Link already exists: {} ↔ {}", source, target); - } - Err(e) => return Err(e), - } + let result = crate::mcp_server::memory_rpc( + "memory_link_add", + serde_json::json!({"source": source, "target": target}), + ).map_err(|e| e.to_string())?; + println!("{}", result); Ok(()) } pub fn cmd_link_set(source: &str, target: &str, strength: f32) -> Result<(), String> { super::check_dry_run(); - let mut store = store::Store::load()?; - let source = store.resolve_key(source)?; - let target = store.resolve_key(target)?; - - let old = store.set_link_strength(&source, &target, strength)?; - println!("Set: {} ↔ {} strength {:.2} → {:.2}", source, target, old, strength); - store.save()?; + let result = crate::mcp_server::memory_rpc( + "memory_link_set", + serde_json::json!({"source": source, "target": target, "strength": strength}), + ).map_err(|e| e.to_string())?; + println!("{}", result); Ok(()) } diff --git a/src/cli/journal.rs b/src/cli/journal.rs index 67da9e3..4a413ee 100644 --- a/src/cli/journal.rs +++ b/src/cli/journal.rs @@ -90,39 +90,14 @@ pub fn find_current_transcript() -> Option { newest.map(|(_, p)| p.to_string_lossy().to_string()) } -fn journal_tail_query(store: &crate::store::Store, query: &str, n: usize, full: bool) -> Result<(), String> { - let graph = store.build_graph(); - let stages = crate::query_parser::parse_stages(query)?; - let results = crate::search::run_query(&stages, vec![], &graph, store, false, n); - - // Query sorts desc and limits, so reverse to show oldest-to-newest - for (key, _score) in results.into_iter().rev() { - let Some(node) = store.nodes.get(&key) else { continue }; - let ts = if node.created_at > 0 { - crate::store::format_datetime(node.created_at) - } else if node.timestamp > 0 { - crate::store::format_datetime(node.timestamp) - } else { - node.key.clone() - }; - let title = extract_title(&node.content); - if full { - println!("--- [{}] {} ---\n{}\n", ts, title, node.content); - } else { - println!("[{}] {}", ts, title); - } - } - Ok(()) -} - pub fn cmd_journal_tail(n: usize, full: bool, level: u8) -> Result<(), String> { - let store = crate::store::Store::load()?; - - let query = format!("all | type:{} | sort:timestamp | limit:{}", - match level { 0 => "episodic", 1 => "daily", 2 => "weekly", _ => "monthly" }, - n - ); - journal_tail_query(&store, &query, n, full) + let format = if full { "full" } else { "compact" }; + let result = crate::mcp_server::memory_rpc( + "journal_tail", + serde_json::json!({"count": n, "level": level, "format": format}), + ).map_err(|e| e.to_string())?; + print!("{}", result); + Ok(()) } pub fn cmd_journal_write(name: &str, text: &[String]) -> Result<(), String> { @@ -163,21 +138,3 @@ pub fn cmd_journal_write(name: &str, text: &[String]) -> Result<(), String> { Ok(()) } - -fn extract_title(content: &str) -> String { - let date_re = regex::Regex::new(r"(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2})").unwrap(); - for line in content.lines() { - let stripped = line.trim(); - if stripped.is_empty() { continue; } - if date_re.is_match(stripped) && stripped.len() < 25 { continue; } - if let Some(h) = stripped.strip_prefix("## ") { - return h.to_string(); - } else if let Some(h) = stripped.strip_prefix("# ") { - return h.to_string(); - } else { - return crate::util::truncate(stripped, 67, "..."); - } - } - String::from("(untitled)") -} - diff --git a/src/cli/misc.rs b/src/cli/misc.rs index 890d8ab..9cfc399 100644 --- a/src/cli/misc.rs +++ b/src/cli/misc.rs @@ -203,9 +203,12 @@ pub fn cmd_query(expr: &[String]) -> Result<(), String> { } let query_str = expr.join(" "); - let store = crate::store::Store::load()?; - let graph = store.build_graph(); - crate::query_parser::run_query(&store, &graph, &query_str) + let result = crate::mcp_server::memory_rpc( + "memory_query", + serde_json::json!({"query": query_str}), + ).map_err(|e| e.to_string())?; + print!("{}", result); + Ok(()) } pub fn get_group_content(group: &crate::config::ContextGroup, store: &crate::store::Store, cfg: &crate::config::Config) -> Vec<(String, String)> { diff --git a/src/cli/node.rs b/src/cli/node.rs index 6fee11b..7219d88 100644 --- a/src/cli/node.rs +++ b/src/cli/node.rs @@ -85,11 +85,11 @@ pub fn cmd_not_useful(key: &str) -> Result<(), String> { pub fn cmd_weight_set(key: &str, weight: f32) -> Result<(), String> { super::check_dry_run(); - let mut store = store::Store::load()?; - let resolved = store.resolve_key(key)?; - let (old, new) = store.set_weight(&resolved, weight)?; - println!("Weight: {} {:.2} → {:.2}", resolved, old, new); - store.save()?; + let result = crate::mcp_server::memory_rpc( + "memory_weight_set", + serde_json::json!({"key": key, "weight": weight}), + ).map_err(|e| e.to_string())?; + println!("{}", result); Ok(()) } @@ -171,13 +171,12 @@ pub fn cmd_node_delete(key: &[String]) -> Result<(), String> { } pub fn cmd_node_rename(old_key: &str, new_key: &str) -> Result<(), String> { - // args are positional, always valid if present super::check_dry_run(); - let mut store = store::Store::load()?; - let old_resolved = store.resolve_key(old_key)?; - store.rename_node(&old_resolved, new_key)?; - store.save()?; - println!("Renamed '{}' → '{}'", old_resolved, new_key); + let result = crate::mcp_server::memory_rpc( + "memory_rename", + serde_json::json!({"old_key": old_key, "new_key": new_key}), + ).map_err(|e| e.to_string())?; + println!("{}", result); Ok(()) }