diff --git a/src/cli/node.rs b/src/cli/node.rs index ba01e11..7b4fcd5 100644 --- a/src/cli/node.rs +++ b/src/cli/node.rs @@ -3,53 +3,46 @@ // render, write, node-delete, node-rename, history, list-keys, // list-edges, dump-json, lookup-bump, lookups. +use crate::agent::tools::memory; use crate::store; -pub fn cmd_weight_set(key: &str, weight: f32) -> Result<(), String> { +pub async fn cmd_weight_set(key: &str, weight: f32) -> Result<(), String> { super::check_dry_run(); - let result = crate::mcp_server::memory_rpc( - "memory_weight_set", - serde_json::json!({"key": key, "weight": weight}), - ).map_err(|e| e.to_string())?; + let result = memory::weight_set(None, key, weight).await + .map_err(|e| e.to_string())?; println!("{}", result); Ok(()) } -pub fn cmd_node_delete(key: &[String]) -> Result<(), String> { +pub async fn cmd_node_delete(key: &[String]) -> Result<(), String> { if key.is_empty() { return Err("node-delete requires a key".into()); } super::check_dry_run(); let key = key.join(" "); - let result = crate::mcp_server::memory_rpc( - "memory_delete", - serde_json::json!({"key": key}), - ).map_err(|e| e.to_string())?; + let result = memory::delete(None, &key).await + .map_err(|e| e.to_string())?; println!("{}", result); Ok(()) } -pub fn cmd_node_rename(old_key: &str, new_key: &str) -> Result<(), String> { +pub async fn cmd_node_rename(old_key: &str, new_key: &str) -> Result<(), String> { super::check_dry_run(); - 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())?; + let result = memory::rename(None, old_key, new_key).await + .map_err(|e| e.to_string())?; println!("{}", result); Ok(()) } -pub fn cmd_render(key: &[String]) -> Result<(), String> { +pub async fn cmd_render(key: &[String]) -> Result<(), String> { if key.is_empty() { return Err("render requires a key".into()); } let key = key.join(" "); let bare = store::strip_md_suffix(&key); - let rendered = crate::mcp_server::memory_rpc( - "memory_render", - serde_json::json!({"key": bare}), - ).map_err(|e| e.to_string())?; + let rendered = memory::render(None, &bare, None).await + .map_err(|e| e.to_string())?; print!("{}", rendered); // Mark as seen if we're inside a Claude session (not an agent subprocess — @@ -73,20 +66,18 @@ pub fn cmd_render(key: &[String]) -> Result<(), String> { Ok(()) } -pub fn cmd_history(key: &[String], full: bool) -> Result<(), String> { +pub async fn cmd_history(key: &[String], full: bool) -> Result<(), String> { if key.is_empty() { return Err("history requires a key".into()); } let key = key.join(" "); - let result = crate::mcp_server::memory_rpc( - "memory_history", - serde_json::json!({"key": key, "full": full}), - ).map_err(|e| e.to_string())?; + let result = memory::history(None, &key, Some(full)).await + .map_err(|e| e.to_string())?; print!("{}", result); Ok(()) } -pub fn cmd_write(key: &[String]) -> Result<(), String> { +pub async fn cmd_write(key: &[String]) -> Result<(), String> { if key.is_empty() { return Err("write requires a key (reads content from stdin)".into()); } @@ -100,25 +91,21 @@ pub fn cmd_write(key: &[String]) -> Result<(), String> { } super::check_dry_run(); - let result = crate::mcp_server::memory_rpc( - "memory_write", - serde_json::json!({"key": key, "content": content}), - ).map_err(|e| e.to_string())?; + let result = memory::write(None, &key, &content).await + .map_err(|e| e.to_string())?; println!("{}", result); Ok(()) } -pub fn cmd_edit(key: &[String]) -> Result<(), String> { +pub async fn cmd_edit(key: &[String]) -> Result<(), String> { if key.is_empty() { return Err("edit requires a key".into()); } let key = key.join(" "); - // Get raw content via RPC - let content = crate::mcp_server::memory_rpc( - "memory_render", - serde_json::json!({"key": key, "raw": true}), - ).unwrap_or_default(); + // Get raw content + let content = memory::render(None, &key, Some(true)).await + .unwrap_or_default(); let tmp = std::env::temp_dir().join(format!("poc-memory-edit-{}.md", key.replace('/', "_"))); std::fs::write(&tmp, &content) @@ -149,42 +136,36 @@ pub fn cmd_edit(key: &[String]) -> Result<(), String> { } super::check_dry_run(); - let result = crate::mcp_server::memory_rpc( - "memory_write", - serde_json::json!({"key": key, "content": new_content}), - ).map_err(|e| e.to_string())?; + let result = memory::write(None, &key, &new_content).await + .map_err(|e| e.to_string())?; println!("{}", result); Ok(()) } -pub fn cmd_search(keys: &[String]) -> Result<(), String> { +pub async fn cmd_search(keys: &[String]) -> Result<(), String> { if keys.is_empty() { return Err("search requires seed keys".into()); } - let result = crate::mcp_server::memory_rpc( - "memory_search", - serde_json::json!({"keys": keys}), - ).map_err(|e| e.to_string())?; + let result = memory::search(None, keys.to_vec(), None, None, None, None).await + .map_err(|e| e.to_string())?; print!("{}", result); Ok(()) } -pub fn cmd_query(expr: &[String]) -> Result<(), String> { +pub async fn cmd_query(expr: &[String]) -> Result<(), String> { if expr.is_empty() { return Err("query requires an expression (try: poc-memory query --help)".into()); } let query_str = expr.join(" "); - let result = crate::mcp_server::memory_rpc( - "memory_query", - serde_json::json!({"query": query_str}), - ).map_err(|e| e.to_string())?; + let result = memory::query(None, &query_str, None).await + .map_err(|e| e.to_string())?; print!("{}", result); Ok(()) } -/// Get group content via RPC (handles daemon or local fallback) -pub fn get_group_content(group: &crate::config::ContextGroup, cfg: &crate::config::Config) -> Vec<(String, String)> { +/// Get group content (handles daemon or local fallback) +pub async fn get_group_content(group: &crate::config::ContextGroup, cfg: &crate::config::Config) -> Vec<(String, String)> { match group.source { crate::config::ContextSource::Journal => { // Query for recent journal entries @@ -192,26 +173,21 @@ pub fn get_group_content(group: &crate::config::ContextGroup, cfg: &crate::confi let query = format!("all | type:episodic | age:<{} | sort:timestamp | limit:{}", window, cfg.journal_max); - let keys_str = match crate::mcp_server::memory_rpc( - "memory_query", - serde_json::json!({"query": query}), - ) { + let keys_str = match memory::query(None, &query, None).await { Ok(s) => s, Err(_) => return vec![], }; // Parse keys (one per line) and render each - keys_str.lines() - .filter(|k| !k.is_empty() && *k != "no results") - .filter_map(|key| { - let content = crate::mcp_server::memory_rpc( - "memory_render", - serde_json::json!({"key": key, "raw": true}), - ).ok()?; - if content.trim().is_empty() { return None; } - Some((key.to_string(), content)) - }) - .collect() + let mut results = Vec::new(); + for key in keys_str.lines().filter(|k| !k.is_empty() && *k != "no results") { + if let Ok(content) = memory::render(None, key, Some(true)).await { + if !content.trim().is_empty() { + results.push((key.to_string(), content)); + } + } + } + results } crate::config::ContextSource::File => { group.keys.iter().filter_map(|key| { @@ -221,19 +197,20 @@ pub fn get_group_content(group: &crate::config::ContextGroup, cfg: &crate::confi }).collect() } crate::config::ContextSource::Store => { - group.keys.iter().filter_map(|key| { - let content = crate::mcp_server::memory_rpc( - "memory_render", - serde_json::json!({"key": key, "raw": true}), - ).ok()?; - if content.trim().is_empty() { return None; } - Some((key.clone(), content.trim().to_string())) - }).collect() + let mut results = Vec::new(); + for key in &group.keys { + if let Ok(content) = memory::render(None, key, Some(true)).await { + if !content.trim().is_empty() { + results.push((key.clone(), content.trim().to_string())); + } + } + } + results } } } -pub fn cmd_load_context(stats: bool) -> Result<(), String> { +pub async fn cmd_load_context(stats: bool) -> Result<(), String> { let cfg = crate::config::get(); if stats { @@ -243,7 +220,7 @@ pub fn cmd_load_context(stats: bool) -> Result<(), String> { println!("{}", "-".repeat(42)); for group in &cfg.context_groups { - let entries = get_group_content(group, &cfg); + let entries = get_group_content(group, &cfg).await; let words: usize = entries.iter() .map(|(_, c)| c.split_whitespace().count()) .sum(); @@ -261,7 +238,7 @@ pub fn cmd_load_context(stats: bool) -> Result<(), String> { println!("=== MEMORY SYSTEM ({}) ===", cfg.assistant_name); for group in &cfg.context_groups { - let entries = get_group_content(group, &cfg); + let entries = get_group_content(group, &cfg).await; if !entries.is_empty() && group.source == crate::config::ContextSource::Journal { println!("--- recent journal entries ({}/{}) ---", entries.len(), cfg.journal_max); diff --git a/src/main.rs b/src/main.rs index 990a62b..86a31de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -384,43 +384,43 @@ fn print_help() { // ── Dispatch ───────────────────────────────────────────────────────── trait Run { - fn run(self) -> Result<(), String>; + async fn run(self) -> Result<(), String>; } impl Run for Command { - fn run(self) -> Result<(), String> { + async fn run(self) -> Result<(), String> { match self { - Self::Search { keys } => cli::node::cmd_search(&keys), - Self::Render { key } => cli::node::cmd_render(&key), - Self::Write { key } => cli::node::cmd_write(&key), - Self::Edit { key } => cli::node::cmd_edit(&key), - Self::History { full, key } => cli::node::cmd_history(&key, full), + Self::Search { keys } => cli::node::cmd_search(&keys).await, + Self::Render { key } => cli::node::cmd_render(&key).await, + Self::Write { key } => cli::node::cmd_write(&key).await, + Self::Edit { key } => cli::node::cmd_edit(&key).await, + Self::History { full, key } => cli::node::cmd_history(&key, full).await, Self::Tail { n, full, provenance, all_versions } => cli::journal::cmd_tail(n, full, provenance.as_deref(), !all_versions), Self::Status => cli::admin::cmd_status(), - Self::Query { expr } => cli::node::cmd_query(&expr), - Self::WeightSet { key, weight } => cli::node::cmd_weight_set(&key, weight), - Self::Node(sub) => sub.run(), - Self::Journal(sub) => sub.run(), - Self::GraphCmd(sub) => sub.run(), - Self::Agent(sub) => sub.run(), - Self::Admin(sub) => sub.run(), + Self::Query { expr } => cli::node::cmd_query(&expr).await, + Self::WeightSet { key, weight } => cli::node::cmd_weight_set(&key, weight).await, + Self::Node(sub) => sub.run().await, + Self::Journal(sub) => sub.run().await, + Self::GraphCmd(sub) => sub.run().await, + Self::Agent(sub) => sub.run().await, + Self::Admin(sub) => sub.run().await, // mcp-schema moved to consciousness-mcp binary } } } impl Run for NodeCmd { - fn run(self) -> Result<(), String> { + async fn run(self) -> Result<(), String> { match self { - Self::Delete { key } => cli::node::cmd_node_delete(&key), - Self::Rename { old_key, new_key } => cli::node::cmd_node_rename(&old_key, &new_key), + Self::Delete { key } => cli::node::cmd_node_delete(&key).await, + Self::Rename { old_key, new_key } => cli::node::cmd_node_rename(&old_key, &new_key).await, } } } impl Run for JournalCmd { - fn run(self) -> Result<(), String> { + async fn run(self) -> Result<(), String> { match self { Self::Write { name, text } => cli::journal::cmd_journal_write(&name, &text), Self::Tail { n, full, level } => cli::journal::cmd_journal_tail(n, full, level), @@ -429,7 +429,7 @@ impl Run for JournalCmd { } impl Run for GraphCmd { - fn run(self) -> Result<(), String> { + async fn run(self) -> Result<(), String> { match self { Self::Link { key } => cli::graph::cmd_link(&key), Self::LinkAdd { source, target, reason } @@ -446,7 +446,7 @@ impl Run for GraphCmd { } impl Run for AgentCmd { - fn run(self) -> Result<(), String> { + async fn run(self) -> Result<(), String> { match self { Self::Run { agent, count, target, query, dry_run, local, state_dir } => cli::agent::cmd_run_agent(&agent, count, &target, query.as_deref(), dry_run, local, state_dir.as_deref()), @@ -455,7 +455,7 @@ impl Run for AgentCmd { } impl Run for AdminCmd { - fn run(self) -> Result<(), String> { + async fn run(self) -> Result<(), String> { match self { Self::Init => cli::admin::cmd_init(), Self::Health => cli::admin::cmd_health(), @@ -465,7 +465,7 @@ impl Run for AdminCmd { Self::DailyCheck => cli::admin::cmd_daily_check(), Self::Import { files } => cli::admin::cmd_import(&files), Self::Export { files, all } => cli::admin::cmd_export(&files, all), - Self::LoadContext { stats } => cli::node::cmd_load_context(stats), + Self::LoadContext { stats } => cli::node::cmd_load_context(stats).await, Self::MigrateTranscriptProgress => { let mut store = store::Store::load()?; let count = store.migrate_transcript_progress()?; @@ -496,7 +496,7 @@ async fn main() { let cli = Cli::parse(); - if let Err(e) = cli.command.run() { + if let Err(e) = cli.command.run().await { eprintln!("Error: {}", e); process::exit(1); } diff --git a/src/subconscious/defs.rs b/src/subconscious/defs.rs index d084cab..ce2b07c 100644 --- a/src/subconscious/defs.rs +++ b/src/subconscious/defs.rs @@ -303,7 +303,12 @@ fn resolve( let mut keys = Vec::new(); for group in &cfg.context_groups { if !group.agent { continue; } - let entries = crate::cli::node::get_group_content(group, &cfg); + // Bridge sync→async using block_in_place (same as resolve_tool) + let entries = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on( + crate::cli::node::get_group_content(group, &cfg) + ) + }); for (key, content) in entries { use std::fmt::Write; writeln!(text, "--- {} ({}) ---", key, group.label).ok();