// cli/agent.rs — agent subcommand handlers use crate::agent::tools::memory; use crate::store; pub async 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 // pollute the user's seen set as a side effect // SAFETY: single-threaded at this point (CLI startup, before any agent work) unsafe { std::env::set_var("POC_AGENT", "1"); } // Override agent output/state directory if specified if let Some(dir) = state_dir { std::fs::create_dir_all(dir).map_err(|e| format!("create state dir: {}", e))?; unsafe { std::env::set_var("POC_AGENT_OUTPUT_DIR", dir); } } if dry_run { unsafe { std::env::set_var("POC_MEMORY_DRY_RUN", "1"); } } // Resolve targets: explicit --target, --query, or agent's default query let resolved_targets: Vec = if !target.is_empty() { target.to_vec() } else if let Some(q) = query { // Resolve query via typed API let q_str = format!("{} | limit:{}", q, count); let result = memory::memory_query(None, &q_str, None).await .map_err(|e| e.to_string())?; let keys: Vec = 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)); } println!("[{}] query matched {} nodes", agent, keys.len()); keys } else { vec![] // use agent's built-in query }; if !resolved_targets.is_empty() { for (i, key) in resolved_targets.iter().enumerate() { println!("[{}] [{}/{}] {}", agent, i + 1, resolved_targets.len(), key); let mut store = store::Store::load()?; if let Err(e) = crate::agent::oneshot::run_one_agent( &mut store, agent, count, Some(&[key.clone()]), ).await { println!("[{}] ERROR on {}: {}", agent, key, e); } } } 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, ).await?; } Ok(()) }