Skip to main content

routa_core/acp/
paths.rs

1//! ACP installation paths management.
2//!
3//! Manages directory structure for locally installed ACP agents:
4//!   - Base directory: `{data_dir}/acp-agents/`
5//!   - Agent binaries: `{base}/{agentId}/{version}/`
6//!   - Downloads: `{base}/.downloads/{agentId}/{version}/`
7//!   - Runtimes: `{base}/.runtimes/{runtime}/{version}/`
8//!   - Icons: `{base}/.icons/`
9//!   - Registry cache: `{base}/registry.json`
10//!   - Installed state: `{base}/installed.json`
11
12use std::path::PathBuf;
13
14/// ACP paths manager for local agent installation.
15#[derive(Debug, Clone)]
16pub struct AcpPaths {
17    base_dir: PathBuf,
18}
19
20impl AcpPaths {
21    /// Create a new AcpPaths instance using the system data directory.
22    pub fn new() -> Self {
23        let base_dir = dirs::data_local_dir()
24            .unwrap_or_else(|| PathBuf::from("."))
25            .join("acp-agents");
26        Self { base_dir }
27    }
28
29    /// Create AcpPaths with a custom base directory (for testing).
30    pub fn with_base_dir(base_dir: PathBuf) -> Self {
31        Self { base_dir }
32    }
33
34    /// Get the base directory for all ACP agent data.
35    pub fn base_dir(&self) -> &PathBuf {
36        &self.base_dir
37    }
38
39    /// Get the directory for a specific agent.
40    pub fn agent_dir(&self, agent_id: &str) -> PathBuf {
41        self.base_dir.join(agent_id)
42    }
43
44    /// Get the directory for a specific agent version.
45    pub fn agent_version_dir(&self, agent_id: &str, version: &str) -> PathBuf {
46        self.agent_dir(agent_id).join(version)
47    }
48
49    /// Get the downloads directory.
50    pub fn downloads_dir(&self) -> PathBuf {
51        self.base_dir.join(".downloads")
52    }
53
54    /// Get the download directory for a specific agent version.
55    pub fn agent_download_dir(&self, agent_id: &str, version: &str) -> PathBuf {
56        self.downloads_dir().join(agent_id).join(version)
57    }
58
59    /// Get the runtimes directory.
60    pub fn runtimes_dir(&self) -> PathBuf {
61        self.base_dir.join(".runtimes")
62    }
63
64    /// Get the directory for a specific runtime.
65    pub fn runtime_dir(&self, runtime: &str, version: &str) -> PathBuf {
66        self.runtimes_dir().join(runtime).join(version)
67    }
68
69    /// Get the icons directory.
70    pub fn icons_dir(&self) -> PathBuf {
71        self.base_dir.join(".icons")
72    }
73
74    /// Get the path to the registry cache file.
75    pub fn registry_cache_path(&self) -> PathBuf {
76        self.base_dir.join("registry.json")
77    }
78
79    /// Get the path to the installed agents state file.
80    pub fn installed_state_path(&self) -> PathBuf {
81        self.base_dir.join("installed.json")
82    }
83
84    /// Ensure all required directories exist.
85    pub fn ensure_directories(&self) -> std::io::Result<()> {
86        std::fs::create_dir_all(&self.base_dir)?;
87        std::fs::create_dir_all(self.downloads_dir())?;
88        std::fs::create_dir_all(self.runtimes_dir())?;
89        std::fs::create_dir_all(self.icons_dir())?;
90        Ok(())
91    }
92
93    /// Get the current platform target string.
94    /// Returns format like "darwin-aarch64", "darwin-x86_64", "linux-x86_64", etc.
95    pub fn current_platform() -> String {
96        let os = std::env::consts::OS;
97        let arch = std::env::consts::ARCH;
98
99        let os_name = match os {
100            "macos" => "darwin",
101            "linux" => "linux",
102            "windows" => "windows",
103            other => other,
104        };
105
106        format!("{os_name}-{arch}")
107    }
108}
109
110impl Default for AcpPaths {
111    fn default() -> Self {
112        Self::new()
113    }
114}