agentstatedeveloper_cli/commands/
read.rs1use anyhow::Result;
5use clap::Args;
6use serde_json::json;
7
8use agentstatedeveloper_core::{
9 AsgEffectStore, AsgIndexStore, AsgLedgerStore, EffectStore, Engine, IndexStore, LedgerStore,
10};
11
12use crate::commands::graph::build_id_map;
13use crate::config::Config;
14
15#[derive(Debug, Args)]
16pub struct ReadArgs {
17 pub qname: String,
19
20 #[arg(long, default_value = "10")]
27 pub limit: usize,
28
29 #[arg(long)]
33 pub full: bool,
34}
35
36pub fn run(cfg: &Config, args: ReadArgs) -> Result<()> {
37 let engine = Engine::open_sqlite(&cfg.db_path)?;
38
39 let index_store = AsgIndexStore::from_engine(&engine);
40 let effect_store = AsgEffectStore::from_engine(&engine);
41 let ledger_store = AsgLedgerStore::from_engine(&engine);
42
43 let symbol = index_store
44 .get_symbol_by_qname(&engine.ref_name, &args.qname)?
45 .ok_or_else(|| anyhow::anyhow!("symbol not found: {}", args.qname))?;
46
47 let effects = effect_store.get_effects(&engine.ref_name, &symbol.symbol_id)?;
48 let mut ledger = ledger_store.list_entries(&engine.ref_name, &symbol.symbol_id)?;
49 ledger.truncate(5);
50
51 let callee_ids = index_store.get_callees(&engine.ref_name, &symbol.symbol_id)?;
53 let caller_ids = index_store.get_callers(&engine.ref_name, &symbol.symbol_id)?;
54
55 let id_map = build_id_map(&engine);
56
57 let resolve = |ids: Vec<String>| -> Vec<serde_json::Value> {
58 ids.iter()
59 .map(|id| {
60 if let Some(s) = id_map.get(id) {
61 json!({ "qname": s.qname, "file": s.file, "line": s.start.line })
62 } else {
63 json!({ "symbol_id": id })
64 }
65 })
66 .collect()
67 };
68
69 let mut callers = resolve(caller_ids);
70 let mut callees = resolve(callee_ids);
71
72 if !args.full {
82 if callers.len() > args.limit {
83 let keep = args.limit.saturating_sub(1);
86 let extra = callers.len() - keep;
87 callers.truncate(keep);
88 callers.push(json!({ "truncated": extra }));
89 }
90 if callees.len() > args.limit {
91 let keep = args.limit.saturating_sub(1);
92 let extra = callees.len() - keep;
93 callees.truncate(keep);
94 callees.push(json!({ "truncated": extra }));
95 }
96 }
97 let effects_json = effects
98 .as_ref()
99 .map(|e| serde_json::to_value(e).unwrap_or(serde_json::Value::Null));
100
101 let qid = crate::commands::brief::query_id("read", &[&args.qname]);
102
103 if cfg.brief {
104 let mut out = crate::commands::brief::brief_read(
105 &symbol,
106 &callers,
107 &callees,
108 effects_json.as_ref(),
109 ledger.len(),
110 );
111 if let serde_json::Value::Object(ref mut m) = out {
112 m.insert("query_id".into(), serde_json::Value::String(qid));
113 }
114 println!("{}", serde_json::to_string_pretty(&out)?);
115 return Ok(());
116 }
117
118 let out = json!({
119 "symbol": symbol,
120 "callers": callers,
121 "callees": callees,
122 "effects": effects,
123 "ledger": ledger,
124 "query_id": qid,
125 });
126 println!("{}", serde_json::to_string_pretty(&out)?);
127 Ok(())
128}