CLI: more RPC conversions, delete obsolete commands
- cmd_health: use graph_health RPC - cmd_topology: new command using graph_topology RPC - cmd_status: use graph_topology RPC (type counts folded into topology) - cmd_run_agent: query resolution via memory_query RPC - Delete cmd_bulk_rename (one-time migration, obsolete) - Delete cmd_replay_queue, cmd_digest_links (unconscious agents handle) - format_topology_header: add type counts, takes &Store now Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
1f6bfb5915
commit
2ab4aef19f
6 changed files with 58 additions and 173 deletions
116
src/cli/admin.rs
116
src/cli/admin.rs
|
|
@ -61,73 +61,6 @@ pub fn cmd_init() -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_bulk_rename(from: &str, to: &str, apply: bool) -> Result<(), String> {
|
||||
let mut store = store::Store::load()?;
|
||||
|
||||
// Find all keys that need renaming
|
||||
let renames: Vec<(String, String)> = store.nodes.keys()
|
||||
.filter(|k| k.contains(from))
|
||||
.map(|k| (k.clone(), k.replace(from, to)))
|
||||
.collect();
|
||||
|
||||
// Check for collisions
|
||||
let existing: std::collections::HashSet<&String> = store.nodes.keys().collect();
|
||||
let mut collisions = 0;
|
||||
for (old, new) in &renames {
|
||||
if existing.contains(new) && old != new {
|
||||
eprintln!("COLLISION: {} -> {} (target exists)", old, new);
|
||||
collisions += 1;
|
||||
}
|
||||
}
|
||||
|
||||
println!("Bulk rename '{}' -> '{}'", from, to);
|
||||
println!(" Keys to rename: {}", renames.len());
|
||||
println!(" Collisions: {}", collisions);
|
||||
|
||||
if collisions > 0 {
|
||||
return Err(format!("{} collisions — aborting", collisions));
|
||||
}
|
||||
|
||||
if !apply {
|
||||
// Show a sample
|
||||
for (old, new) in renames.iter().take(10) {
|
||||
println!(" {} -> {}", old, new);
|
||||
}
|
||||
if renames.len() > 10 {
|
||||
println!(" ... and {} more", renames.len() - 10);
|
||||
}
|
||||
println!("\nDry run. Use --apply to execute.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Apply renames using rename_node() which properly appends to capnp logs.
|
||||
// Process in batches to avoid holding the lock too long.
|
||||
let mut renamed_count = 0;
|
||||
let mut errors = 0;
|
||||
let total = renames.len();
|
||||
for (i, (old_key, new_key)) in renames.iter().enumerate() {
|
||||
match store.rename_node(old_key, new_key) {
|
||||
Ok(()) => renamed_count += 1,
|
||||
Err(e) => {
|
||||
eprintln!(" RENAME ERROR: {} -> {}: {}", old_key, new_key, e);
|
||||
errors += 1;
|
||||
}
|
||||
}
|
||||
if (i + 1) % 1000 == 0 {
|
||||
println!(" {}/{} ({} errors)", i + 1, total, errors);
|
||||
}
|
||||
}
|
||||
store.save()?;
|
||||
println!("Renamed {} nodes ({} errors).", renamed_count, errors);
|
||||
|
||||
// Run fsck to verify
|
||||
println!("\nRunning fsck...");
|
||||
drop(store);
|
||||
cmd_fsck()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_fsck() -> Result<(), String> {
|
||||
let mut store = store::Store::load()?;
|
||||
|
||||
|
|
@ -396,10 +329,20 @@ pub fn cmd_dedup(apply: bool) -> Result<(), String> {
|
|||
}
|
||||
|
||||
pub fn cmd_health() -> Result<(), String> {
|
||||
let store = store::Store::load()?;
|
||||
let g = store.build_graph();
|
||||
let report = crate::graph::health_report(&g, &store);
|
||||
print!("{}", report);
|
||||
let result = crate::mcp_server::memory_rpc(
|
||||
"graph_health",
|
||||
serde_json::json!({}),
|
||||
).map_err(|e| e.to_string())?;
|
||||
print!("{}", result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_topology() -> Result<(), String> {
|
||||
let result = crate::mcp_server::memory_rpc(
|
||||
"graph_topology",
|
||||
serde_json::json!({}),
|
||||
).map_err(|e| e.to_string())?;
|
||||
print!("{}", result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -480,31 +423,10 @@ pub fn cmd_export(files: &[String], export_all: bool) -> Result<(), String> {
|
|||
}
|
||||
|
||||
pub fn cmd_status() -> Result<(), String> {
|
||||
// TUI moved to consciousness binary (F4 unconscious screen)
|
||||
|
||||
let store = crate::store::Store::load()?;
|
||||
let g = store.build_graph();
|
||||
|
||||
let mut type_counts = std::collections::HashMap::new();
|
||||
for node in store.nodes.values() {
|
||||
*type_counts.entry(format!("{:?}", node.node_type)).or_insert(0usize) += 1;
|
||||
}
|
||||
let mut types: Vec<_> = type_counts.iter().collect();
|
||||
types.sort_by_key(|(_, c)| std::cmp::Reverse(**c));
|
||||
|
||||
println!("Nodes: {} Relations: {}", store.nodes.len(), store.relations.len());
|
||||
print!("Types:");
|
||||
for (t, c) in &types {
|
||||
let label = match t.as_str() {
|
||||
"Semantic" => "semantic",
|
||||
"EpisodicSession" | "EpisodicDaily" | "EpisodicWeekly" | "EpisodicMonthly"
|
||||
=> "episodic",
|
||||
_ => t,
|
||||
};
|
||||
print!(" {}={}", label, c);
|
||||
}
|
||||
println!();
|
||||
println!("Graph edges: {} Communities: {}",
|
||||
g.edge_count(), g.community_count());
|
||||
let result = crate::mcp_server::memory_rpc(
|
||||
"graph_topology",
|
||||
serde_json::json!({}),
|
||||
).map_err(|e| e.to_string())?;
|
||||
print!("{}", result);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// cli/agent.rs — agent subcommand handlers
|
||||
|
||||
use crate::store;
|
||||
use crate::subconscious::digest;
|
||||
|
||||
pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option<&str>, dry_run: bool, _local: bool, state_dir: Option<&str>) -> Result<(), String> {
|
||||
// Mark as agent so tool calls (e.g. poc-memory render) don't
|
||||
|
|
@ -19,19 +18,22 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
|
|||
unsafe { std::env::set_var("POC_MEMORY_DRY_RUN", "1"); }
|
||||
}
|
||||
|
||||
let mut store = store::Store::load()?;
|
||||
|
||||
// Resolve targets: explicit --target, --query, or agent's default query
|
||||
let resolved_targets: Vec<String> = if !target.is_empty() {
|
||||
target.to_vec()
|
||||
} else if let Some(q) = query {
|
||||
let graph = store.build_graph();
|
||||
let stages = crate::query_parser::parse_stages(q)?;
|
||||
let results = crate::search::run_query(&stages, vec![], &graph, &store, false, count);
|
||||
if results.is_empty() {
|
||||
// Use RPC to resolve query
|
||||
let result = crate::mcp_server::memory_rpc(
|
||||
"memory_query",
|
||||
serde_json::json!({"query": format!("{} | limit:{}", q, count)}),
|
||||
).map_err(|e| e.to_string())?;
|
||||
let keys: Vec<String> = result.lines()
|
||||
.filter(|l| !l.is_empty() && *l != "no results")
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
if keys.is_empty() {
|
||||
return Err(format!("query returned no results: {}", q));
|
||||
}
|
||||
let keys: Vec<String> = results.into_iter().map(|(k, _)| k).collect();
|
||||
println!("[{}] query matched {} nodes", agent, keys.len());
|
||||
keys
|
||||
} else {
|
||||
|
|
@ -41,7 +43,7 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
|
|||
if !resolved_targets.is_empty() {
|
||||
for (i, key) in resolved_targets.iter().enumerate() {
|
||||
println!("[{}] [{}/{}] {}", agent, i + 1, resolved_targets.len(), key);
|
||||
if i > 0 { store = store::Store::load()?; }
|
||||
let mut store = store::Store::load()?;
|
||||
if let Err(e) = crate::agent::oneshot::run_one_agent(
|
||||
&mut store, agent, count, Some(&[key.clone()]),
|
||||
) {
|
||||
|
|
@ -50,6 +52,7 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
|
|||
}
|
||||
} else {
|
||||
// Local execution (--local, --debug, dry-run, or daemon unavailable)
|
||||
let mut store = store::Store::load()?;
|
||||
crate::agent::oneshot::run_one_agent(
|
||||
&mut store, agent, count, None,
|
||||
)?;
|
||||
|
|
@ -57,37 +60,3 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_replay_queue(count: usize) -> Result<(), String> {
|
||||
let store = store::Store::load()?;
|
||||
let queue = crate::neuro::replay_queue(&store, count);
|
||||
println!("Replay queue ({} items):", queue.len());
|
||||
for (i, item) in queue.iter().enumerate() {
|
||||
println!(" {:2}. [{:.3}] {:>10} {} (interval={}d, emotion={:.1}, spectral={:.1})",
|
||||
i + 1, item.priority, item.classification, item.key,
|
||||
item.interval_days, item.emotion, item.outlier_score);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_digest_links(do_apply: bool) -> Result<(), String> {
|
||||
let store = store::Store::load()?;
|
||||
let links = digest::parse_all_digest_links(&store);
|
||||
drop(store);
|
||||
println!("Found {} unique links from digest nodes", links.len());
|
||||
|
||||
if !do_apply {
|
||||
for (i, link) in links.iter().enumerate() {
|
||||
println!(" {:3}. {} → {}", i + 1, link.source, link.target);
|
||||
if !link.reason.is_empty() {
|
||||
println!(" ({})", &link.reason[..link.reason.floor_char_boundary(link.reason.len().min(80))]);
|
||||
}
|
||||
}
|
||||
println!("\nTo apply: poc-memory digest-links --apply");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut store = store::Store::load()?;
|
||||
let (applied, skipped, fallbacks) = digest::apply_digest_links(&mut store, &links);
|
||||
println!("\nApplied: {} ({} file-level fallbacks) Skipped: {}", applied, fallbacks, skipped);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue