Skip to main content

agentmux_srv/
srv_info.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! What srv tells a UI about the machine it runs on: sent as the `srvinfo`
5//! event on every WebSocket connect (`server/websocket.rs`). A UI shows these
6//! names and builds paths from the home directory, and the paths have to be
7//! srv's, which is only the same machine as the UI's when the UI is the
8//! desktop app.
9
10use std::sync::OnceLock;
11
12/// The account-wide AgentMux root (`~/.agentmux`, or its override) as it was
13/// when srv started. Read before startup sets `AGENTMUX_DATA_HOME` to the data
14/// directory (`bootstrap/stores.rs`), after which the same resolver answers
15/// with the data directory instead.
16static HOME_DIR: OnceLock<Option<String>> = OnceLock::new();
17
18/// Record the AgentMux root. Call first thing in `main`, before anything
19/// changes the environment.
20pub fn capture_home_dir() {
21    let _ = HOME_DIR.set(
22        agentmux_common::data_paths::agentmux_root()
23            .ok()
24            .map(|p| p.to_string_lossy().into_owned()),
25    );
26}
27
28/// The account-wide AgentMux root captured at startup (`capture_home_dir`).
29pub fn agentmux_home() -> Option<std::path::PathBuf> {
30    HOME_DIR.get().cloned().flatten().map(std::path::PathBuf::from)
31}
32
33/// The `srvinfo` event: srv's version, and the machine it runs on.
34#[derive(Debug, Clone, serde::Serialize, ts_rs::TS)]
35#[ts(export, export_to = "../../../frontend/types/rpc/")]
36#[serde(rename_all = "camelCase")]
37pub struct SrvInfo {
38    pub version: String,
39    /// srv's OS, as `process.platform` names it (`darwin`, `win32`, `linux`).
40    pub platform: String,
41    pub user_name: String,
42    pub host_name: String,
43    /// The account-wide AgentMux root on srv's machine (`~/.agentmux`, or its override).
44    pub home_dir: Option<String>,
45}
46
47/// The `data` of the `srvinfo` event.
48pub fn srv_info(version: &str, host_name: &str) -> SrvInfo {
49    SrvInfo {
50        version: version.to_string(),
51        platform: agentmux_common::platform_name::platform_name().to_string(),
52        user_name: whoami::username(),
53        host_name: host_name.to_string(),
54        home_dir: HOME_DIR.get().cloned().flatten(),
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn srv_info_names_the_machine_and_the_version() {
64        let info = serde_json::to_value(srv_info("1.2.3", "box")).unwrap();
65        assert_eq!(info["version"], "1.2.3");
66        assert_eq!(info["hostName"], "box");
67        assert_eq!(
68            info["platform"],
69            agentmux_common::platform_name::platform_name()
70        );
71        assert_eq!(info["userName"], whoami::username());
72        assert!(info.get("homeDir").is_some());
73    }
74}