use super::Refusal;
use crate::core::entity::AgentLink;
#[derive(Debug, Clone, PartialEq)]
pub enum Request {
Focus { pane: String },
}
pub fn agent_for<'a>(agents: &'a [AgentLink], identifier: &str) -> Option<&'a AgentLink> {
agents
.iter()
.filter(|a| {
a.issue
.as_deref()
.is_some_and(|i| i.eq_ignore_ascii_case(identifier))
})
.min_by_key(|a| a.status.rank())
}
pub fn jump(agents: &[AgentLink], identifier: &str, herdr: bool) -> Result<Request, Refusal> {
if !herdr {
return Err(Refusal::NeedsHerdr);
}
let agent =
agent_for(agents, identifier).ok_or_else(|| Refusal::NoAgentOn(identifier.into()))?;
Ok(Request::Focus {
pane: agent.pane.clone(),
})
}
#[cfg(test)]
mod tests {
use super::*;
fn agents() -> Vec<AgentLink> {
serde_json::from_str(
r#"[
{"pane":"w1:p1","agent":"claude","status":"working","issue":"ENG-42"},
{"pane":"w2:p1","agent":"codex","status":"blocked","issue":"eng-42"},
{"pane":"w3:p1","agent":"claude","status":"idle"}]"#,
)
.unwrap()
}
#[test]
fn the_agent_waiting_for_you_is_shown_before_the_one_at_work() {
assert_eq!(agent_for(&agents(), "ENG-42").unwrap().pane, "w2:p1");
}
#[test]
fn an_issue_nobody_works_on_has_no_agent() {
assert!(agent_for(&agents(), "ENG-7").is_none());
}
#[test]
fn jumping_focuses_that_agents_pane() {
assert_eq!(
jump(&agents(), "ENG-42", true),
Ok(Request::Focus {
pane: "w2:p1".into()
})
);
}
#[test]
fn jumping_to_an_issue_nobody_works_on_says_so() {
assert_eq!(
jump(&agents(), "ENG-7", true),
Err(Refusal::NoAgentOn("ENG-7".into()))
);
}
#[test]
fn jumping_needs_herdr() {
assert_eq!(jump(&agents(), "ENG-42", false), Err(Refusal::NeedsHerdr));
}
}