agentstatedeveloper_cli/commands/
architecture.rs1use anyhow::Result;
10use clap::Args;
11use serde_json::Value;
12
13use agentstatedeveloper_core::{Engine, architecture_overview};
14
15use crate::config::Config;
16
17#[derive(Debug, Args)]
18pub struct ArchitectureArgs {
19 #[arg(long)]
21 pub agent: bool,
22
23 #[arg(long, default_value = "12")]
25 pub top: usize,
26}
27
28pub fn run(cfg: &Config, args: ArchitectureArgs) -> Result<()> {
29 let engine = Engine::open_sqlite(&cfg.db_path)?;
30 let out = architecture_overview(&engine, args.top);
31
32 if args.agent {
33 println!("{}", serde_json::to_string_pretty(&out)?);
34 return Ok(());
35 }
36 print_human(&out);
37 Ok(())
38}
39
40fn print_human(out: &Value) {
41 println!(
42 "Architecture overview — {} ({} symbols)",
43 out["repo_id"].as_str().unwrap_or("?"),
44 out["symbols"].as_u64().unwrap_or(0)
45 );
46 let row = |label: &str, items: &Value| {
47 if let Some(arr) = items.as_array() {
48 let parts: Vec<String> = arr
49 .iter()
50 .map(|e| {
51 let name = e
52 .get("name")
53 .or_else(|| e.get("layer"))
54 .and_then(|v| v.as_str())
55 .unwrap_or("?");
56 format!("{} ({})", name, e["symbols"].as_u64().unwrap_or(0))
57 })
58 .collect();
59 println!(" {label}: {}", parts.join(", "));
60 }
61 };
62 row("languages", &out["languages"]);
63 row("layers", &out["layers"]);
64 row("packages", &out["packages"]);
65
66 if let Some(cl) = out["clusters"].as_array() {
67 if !cl.is_empty() {
68 println!(" clusters (call-graph communities):");
69 for c in cl.iter().take(8) {
70 println!(
71 " {:>4} symbols {} (repr: {})",
72 c["size"].as_u64().unwrap_or(0),
73 c["package"].as_str().unwrap_or("?"),
74 c["representative"].as_str().unwrap_or("?")
75 );
76 }
77 }
78 }
79
80 let inbound = out["routes"]["inbound"]
81 .as_array()
82 .cloned()
83 .unwrap_or_default();
84 println!(
85 " routes: {} inbound, {} outbound consumers",
86 inbound.len(),
87 out["routes"]["outbound_consumers"].as_u64().unwrap_or(0)
88 );
89 for r in inbound.iter().take(10) {
90 println!(
91 " {} ({})",
92 r["contract"].as_str().unwrap_or("?"),
93 r["qname"].as_str().unwrap_or("?")
94 );
95 }
96
97 if let Some(hs) = out["hotspots"].as_array() {
98 println!(" hotspots (call-graph degree):");
99 for h in hs.iter().take(10) {
100 println!(
101 " {:>3} {} ({})",
102 h["degree"].as_u64().unwrap_or(0),
103 h["qname"].as_str().unwrap_or("?"),
104 h["file"].as_str().unwrap_or("?")
105 );
106 }
107 }
108}