diff --git a/agent/src/collectors/nixos.rs b/agent/src/collectors/nixos.rs index ddbd3a5..7db6aa2 100644 --- a/agent/src/collectors/nixos.rs +++ b/agent/src/collectors/nixos.rs @@ -46,6 +46,23 @@ impl NixOSCollector { Ok(clean_version) } + /// Get agent hash from binary path + fn get_agent_hash(&self) -> Result> { + // Get the path of the current executable + let exe_path = std::env::current_exe()?; + let exe_str = exe_path.to_string_lossy(); + + // Extract Nix store hash from path like /nix/store/fn804fh332mp8gz06qawminpj20xl25h-cm-dashboard-0.1.0/bin/cm-dashboard-agent + if let Some(store_path) = exe_str.strip_prefix("/nix/store/") { + if let Some(dash_pos) = store_path.find('-') { + return Ok(store_path[..dash_pos].to_string()); + } + } + + // Fallback to "unknown" if not in Nix store + Ok("unknown".to_string()) + } + /// Get currently active users fn get_active_users(&self) -> Result, Box> { let output = Command::new("who").output()?; @@ -131,6 +148,31 @@ impl Collector for NixOSCollector { } } + // Collect agent hash + match self.get_agent_hash() { + Ok(hash) => { + metrics.push(Metric { + name: "system_agent_hash".to_string(), + value: MetricValue::String(hash), + unit: None, + description: Some("Agent Nix store hash".to_string()), + status: Status::Ok, + timestamp, + }); + } + Err(e) => { + debug!("Failed to get agent hash: {}", e); + metrics.push(Metric { + name: "system_agent_hash".to_string(), + value: MetricValue::String("unknown".to_string()), + unit: None, + description: Some("Agent hash (failed to detect)".to_string()), + status: Status::Unknown, + timestamp, + }); + } + } + debug!("Collected {} NixOS metrics", metrics.len()); Ok(metrics) } diff --git a/dashboard/src/ui/mod.rs b/dashboard/src/ui/mod.rs index ef91b34..dcf9e8a 100644 --- a/dashboard/src/ui/mod.rs +++ b/dashboard/src/ui/mod.rs @@ -119,7 +119,7 @@ impl TuiApp { // Add NixOS metrics - using exact matching for build display fix let nixos_metrics: Vec<&Metric> = all_metrics .iter() - .filter(|m| m.name == "system_nixos_build" || m.name == "system_active_users") + .filter(|m| m.name == "system_nixos_build" || m.name == "system_active_users" || m.name == "system_agent_hash") .copied() .collect(); system_metrics.extend(nixos_metrics); diff --git a/dashboard/src/ui/widgets/system.rs b/dashboard/src/ui/widgets/system.rs index f86a125..a45a0ba 100644 --- a/dashboard/src/ui/widgets/system.rs +++ b/dashboard/src/ui/widgets/system.rs @@ -16,6 +16,7 @@ pub struct SystemWidget { // NixOS information nixos_build: Option, active_users: Option, + agent_hash: Option, // CPU metrics cpu_load_1min: Option, @@ -64,6 +65,7 @@ impl SystemWidget { Self { nixos_build: None, active_users: None, + agent_hash: None, cpu_load_1min: None, cpu_load_5min: None, cpu_load_15min: None, @@ -313,6 +315,11 @@ impl Widget for SystemWidget { self.active_users = Some(users.clone()); } } + "system_agent_hash" => { + if let MetricValue::String(hash) = &metric.value { + self.agent_hash = Some(hash.clone()); + } + } // CPU metrics "cpu_load_1min" => { @@ -397,6 +404,11 @@ impl Widget for SystemWidget { Span::styled(format!("Active users: {}", users_text), Typography::secondary()) ])); + let agent_hash_text = self.agent_hash.as_deref().unwrap_or("unknown"); + lines.push(Line::from(vec![ + Span::styled(format!("Agent Hash: {}", agent_hash_text), Typography::secondary()) + ])); + // CPU section lines.push(Line::from(vec![ Span::styled("CPU:", Typography::widget_title())