Skip to main content

mars_agents/config/migrations/
link.rs

1//! Link normalization and legacy compatibility.
2//!
3//! Backward-compatible migration facade over live `config::targets`.
4
5/// Canonical read-time view of one `settings.targets` / `managed_root` entry.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct NormalizedLink {
8    pub target: String,
9    pub harness: Option<String>,
10}
11
12pub fn normalize_link(raw: &str) -> NormalizedLink {
13    let link = crate::config::targets::normalize_link(raw);
14    NormalizedLink {
15        target: link.target,
16        harness: link.harness.map(|harness| harness.to_string()),
17    }
18}
19
20pub fn normalized_targets<'a>(links: impl IntoIterator<Item = &'a str>) -> Vec<String> {
21    crate::config::targets::normalized_targets(links)
22}
23
24pub fn linked_harnesses<'a>(links: impl IntoIterator<Item = &'a str>) -> Vec<String> {
25    crate::config::targets::linked_harnesses(links)
26}
27
28#[cfg(test)]
29mod tests {
30    use super::*;
31
32    #[test]
33    fn normalizes_harness_name_and_legacy_path_form() {
34        assert_eq!(
35            normalize_link("codex"),
36            NormalizedLink {
37                target: ".codex".to_string(),
38                harness: Some("codex".to_string()),
39            }
40        );
41        assert_eq!(
42            normalize_link(".codex"),
43            NormalizedLink {
44                target: ".codex".to_string(),
45                harness: Some("codex".to_string()),
46            }
47        );
48    }
49
50    #[test]
51    fn normalizes_agents_as_generic_target() {
52        assert_eq!(
53            normalize_link("agents"),
54            NormalizedLink {
55                target: ".agents".to_string(),
56                harness: None,
57            }
58        );
59        assert_eq!(
60            normalize_link(".agents"),
61            NormalizedLink {
62                target: ".agents".to_string(),
63                harness: None,
64            }
65        );
66    }
67
68    #[test]
69    fn dot_prefixes_unknown_bare_names_as_generic_targets() {
70        assert_eq!(
71            normalize_link("foo"),
72            NormalizedLink {
73                target: ".foo".to_string(),
74                harness: None,
75            }
76        );
77    }
78
79    #[test]
80    fn extracts_linked_harnesses_from_legacy_target_paths() {
81        let targets = [".codex", ".claude", ".agents", "foo"];
82        assert_eq!(
83            linked_harnesses(targets.iter().copied()),
84            vec!["codex".to_string(), "claude".to_string()]
85        );
86    }
87}