cellstate/commands/
status.rs1use crate::http;
8use crate::session::CliSession;
9use crate::ui;
10use console::style;
11use serde::Deserialize;
12
13#[derive(Debug, Deserialize)]
18struct HealthResponse {
19 status: String,
20 #[serde(default)]
21 version: Option<String>,
22}
23
24pub fn run_with_json(json: bool) -> anyhow::Result<()> {
29 let session = CliSession::load()?;
30 let base_url = session.effective_base_url(None);
31 let client = http::default_http_client(5)?;
32 let health_url = format!("{base_url}/health/live");
33
34 let (server_status, server_version) = match client.get(&health_url).send() {
35 Ok(r) if r.status().is_success() => {
36 let health: HealthResponse = r.json().unwrap_or_else(|_| HealthResponse {
37 status: "unknown".into(),
38 version: None,
39 });
40 (health.status, health.version)
41 }
42 _ => ("disconnected".into(), None),
43 };
44
45 let has_key = session.effective_api_key(None).is_some();
46
47 if json {
48 let out = serde_json::json!({
49 "scope": {
50 "tenant_id": session.tenant_id,
51 "agent_id": session.agent_id,
52 "trajectory_id": session.trajectory_id,
53 "scope_id": session.scope_id,
54 },
55 "server": {
56 "url": base_url,
57 "status": server_status,
58 "version": server_version,
59 },
60 "auth": has_key,
61 });
62 println!("{}", serde_json::to_string_pretty(&out).unwrap());
63 return Ok(());
64 }
65
66 ui::print_banner();
67
68 ui::section("Scope");
70 print_scope_field("Tenant", session.tenant_id.as_deref());
71 print_scope_field("Agent", session.agent_id.as_deref());
72 print_scope_field("Trajectory", session.trajectory_id.as_deref());
73 print_scope_field("Scope", session.scope_id.as_deref());
74
75 ui::section("Server");
77 ui::kv("URL", &base_url);
78
79 let status_str = match server_status.as_str() {
80 "ok" | "live" => format!("{}", style("connected").green()),
81 "degraded" => format!("{}", style("degraded").yellow()),
82 "disconnected" => {
83 ui::kv("Status", &format!("{}", style("disconnected").red()));
84 ui::info("Is CELLSTATE running? Try: cellstate start");
85 String::new()
86 }
87 _ => format!("{}", style(&server_status).red()),
88 };
89 if !status_str.is_empty() {
90 ui::kv("Status", &status_str);
91 }
92
93 if let Some(version) = &server_version {
94 ui::kv("Version", version);
95 }
96
97 if has_key {
99 ui::kv("Auth", &format!("{}", style("API key configured").green()));
100 } else {
101 ui::kv("Auth", &format!("{}", style("no API key").dim()));
102 }
103
104 println!();
105
106 Ok(())
107}
108
109fn print_scope_field(label: &str, value: Option<&str>) {
114 match value {
115 Some(v) => ui::kv(label, v),
116 None => ui::kv_missing(label),
117 }
118}