cli: convert write/delete/journal-write to use memory_rpc

- cmd_write → memory_write RPC
- cmd_node_delete → new memory_delete MCP tool + RPC
- cmd_journal_write → journal_new RPC

Removes validate_inline_refs and find_current_transcript
(now handled server-side or not needed).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-12 22:15:53 -04:00
parent 7842b6fc8b
commit 366b17163d
3 changed files with 37 additions and 121 deletions

View file

@ -71,11 +71,11 @@ pub fn cmd_node_delete(key: &[String]) -> Result<(), String> {
}
super::check_dry_run();
let key = key.join(" ");
let mut store = store::Store::load()?;
let resolved = store.resolve_key(&key)?;
store.delete_node(&resolved)?;
store.save()?;
println!("Deleted '{}'", resolved);
let result = crate::mcp_server::memory_rpc(
"memory_delete",
serde_json::json!({"key": key}),
).map_err(|e| e.to_string())?;
println!("{}", result);
Ok(())
}
@ -130,48 +130,6 @@ pub fn cmd_render(key: &[String]) -> Result<(), String> {
Ok(())
}
/// Check content for common inline reference problems:
/// - `poc-memory render key` embedded in content (render artifact, should be just `key`)
/// - `→ something` where something doesn't parse as a valid key
/// - `key` referencing a node that doesn't exist
fn validate_inline_refs(content: &str, store: &store::Store) -> Vec<String> {
let mut warnings = Vec::new();
for line in content.lines() {
// Check for render commands embedded in content
if line.contains("poc-memory render ") && !line.starts_with(" ") {
// Skip lines that look like CLI documentation/examples
if !line.contains("CLI") && !line.contains("equivalent") && !line.contains("tool") {
warnings.push(format!(
"render command in content (should be just `key`): {}",
line.chars().take(80).collect::<String>(),
));
}
}
// Check → references
if let Some(rest) = line.trim().strip_prefix("") {
// Extract the key (may be backtick-quoted)
let key = rest.trim().trim_matches('`').trim();
if !key.is_empty() && !store.nodes.contains_key(key) {
// Might be a poc-memory render artifact
if let Some(k) = key.strip_prefix("poc-memory render ") {
warnings.push(format!(
"render artifact in → reference (use `{}` not `poc-memory render {}`)", k, k,
));
} else if key.contains(' ') {
warnings.push(format!(
"→ reference doesn't look like a key: → {}", key,
));
}
// Don't warn about missing keys — the target might be created later
}
}
}
warnings
}
pub fn cmd_history(key: &[String], full: bool) -> Result<(), String> {
if key.is_empty() {
return Err("history requires a key".into());
@ -245,7 +203,7 @@ pub fn cmd_write(key: &[String]) -> Result<(), String> {
if key.is_empty() {
return Err("write requires a key (reads content from stdin)".into());
}
let raw_key = key.join(" ");
let key = key.join(" ");
let mut content = String::new();
std::io::Read::read_to_string(&mut std::io::stdin(), &mut content)
.map_err(|e| format!("read stdin: {}", e))?;
@ -255,25 +213,11 @@ pub fn cmd_write(key: &[String]) -> Result<(), String> {
}
super::check_dry_run();
let mut store = store::Store::load()?;
let key = store.resolve_key(&raw_key).unwrap_or(raw_key);
// Validate inline references: warn about render commands embedded
// in content (should be just `key`) and broken references.
let warnings = validate_inline_refs(&content, &store);
for w in &warnings {
eprintln!("warning: {}", w);
}
let result = store.upsert(&key, &content)?;
match result {
"unchanged" => println!("No change: '{}'", key),
"updated" => println!("Updated '{}' (v{})", key, store.nodes[&key].version),
_ => println!("Created '{}'", key),
}
if result != "unchanged" {
store.save()?;
}
let result = crate::mcp_server::memory_rpc(
"memory_write",
serde_json::json!({"key": key, "content": content}),
).map_err(|e| e.to_string())?;
println!("{}", result);
Ok(())
}