1use crate::agent::registry::AgentOverride;
2use crate::client::permissions::PermissionMode;
3use crate::session::scoping::find_git_root;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::path::Path;
7
8#[derive(Debug, Deserialize, Serialize, Default, Clone)]
9pub struct AcpCliConfig {
10 pub default_agent: Option<String>,
11 pub default_permissions: Option<PermissionMode>,
12 pub timeout: Option<u64>,
13 pub format: Option<String>,
14 pub agents: Option<HashMap<String, AgentOverride>>,
15}
16
17impl AcpCliConfig {
18 pub fn load() -> Self {
20 dirs::home_dir()
21 .map(|h| h.join(".acp-cli").join("config.json"))
22 .map(Self::load_from)
23 .unwrap_or_default()
24 }
25
26 pub fn load_project(cwd: &Path) -> Self {
29 find_git_root(cwd)
30 .map(|root| root.join(".acp-cli.json"))
31 .map(Self::load_from)
32 .unwrap_or_default()
33 }
34
35 pub fn load_from(path: impl AsRef<Path>) -> Self {
36 std::fs::read_to_string(path.as_ref())
37 .ok()
38 .and_then(|s| serde_json::from_str(&s).ok())
39 .unwrap_or_default()
40 }
41
42 pub fn merge(self, project: AcpCliConfig) -> AcpCliConfig {
44 AcpCliConfig {
45 default_agent: project.default_agent.or(self.default_agent),
46 default_permissions: project.default_permissions.or(self.default_permissions),
47 timeout: project.timeout.or(self.timeout),
48 format: project.format.or(self.format),
49 agents: match (self.agents, project.agents) {
50 (Some(mut base), Some(proj)) => {
51 base.extend(proj);
52 Some(base)
53 }
54 (base, proj) => proj.or(base),
55 },
56 }
57 }
58}