use super::*;
pub(crate) fn resolve_teammate_routing(
dirs: &[ProjectDir],
name: &str,
team: &str,
) -> Result<String> {
let mut hits: std::collections::BTreeSet<String> = std::collections::BTreeSet::new();
for pd in dirs {
for top in top_level_jsonls(&pd.dir) {
for id in crate::subagent::teammate_ids_by_routing(&top, name, team)? {
hits.insert(id);
}
}
}
let ids: Vec<String> = hits.into_iter().collect();
match ids.as_slice() {
[one] => Ok(one.clone()),
[] => bail!(
"no teammate `{name}@{team}` under the resolved target(s) — `@<name>@<team>` is a \
teammate's ROUTING form (what the official SendMessage addresses): a name, `@`, \
its team, both matched EXACTLY (case included). List the teammates in scope with \
`csift agents <session> --shape teammate` and read the `routing:` field, or \
target the transcript id `a<Name>-<hex>` directly."
),
many => bail!(
"`@{name}@{team}` is AMBIGUOUS: {} teammates in scope share that routing id ({}). \
The routing form CAN collide (two same-named teammates in one team share it); the \
transcript id never does — target one of those directly.",
many.len(),
many.join(", ")
),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn routing_form_grammar_accepts_name_at_team_only() {
assert!(is_teammate_routing_id("Relay@harbor"));
assert!(is_teammate_routing_id("P1-engine@region_two"));
assert!(is_teammate_routing_id("a@b"));
assert_eq!(
split_teammate_routing_id("Relay@harbor"),
Some(("Relay", "harbor"))
);
assert_eq!(
split_teammate_routing_id("P1-engine@region_two"),
Some(("P1-engine", "region_two"))
);
}
#[test]
fn routing_form_grammar_rejects_every_other_at_target_shape() {
assert!(!is_teammate_routing_id("main"));
assert!(!is_teammate_routing_id("trap:CrimsonWillowFen5180"));
assert!(!is_teammate_routing_id(
"00000000-0000-4000-8000-000000000001"
));
assert!(!is_teammate_routing_id("13d9645a"));
assert!(!is_teammate_routing_id("aRelay-0123456789abcdef"));
assert!(!is_teammate_routing_id("-Users-dev-Projects-relay"));
assert!(!is_teammate_routing_id("@harbor"));
assert!(!is_teammate_routing_id("Relay@"));
assert!(!is_teammate_routing_id("Relay@har@bor"));
assert!(!is_teammate_routing_id("Relay team@harbor"));
assert!(!is_teammate_routing_id("Relay@har.bor"));
assert!(split_teammate_routing_id("Relay").is_none());
}
}