use serde::{Deserialize, Serialize};
use crate::shutai::{Declared, Shutai};
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum Yurai {
#[default]
Unknown,
Human,
Automation { label: Option<String> },
}
impl Yurai {
#[must_use]
pub fn from_shutai(s: &Shutai) -> Self {
match s.declared() {
Declared::Unknown => Self::Unknown,
Declared::Human => Self::Human,
Declared::Agent { label } | Declared::Reconciler { label } => Self::Automation {
label: label.clone(),
},
}
}
#[must_use]
pub const fn is_automation(&self) -> bool {
matches!(self, Self::Automation { .. })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn an_undeclared_connection_stamps_unknown_not_human() {
let s = Shutai::from_peer_uid(501);
assert_eq!(
Yurai::from_shutai(&s),
Yurai::Unknown,
"assuming human would make freio silently skip a pane it was \
pressed to stop"
);
assert!(!Yurai::from_shutai(&s).is_automation());
}
#[test]
fn an_agent_connection_stamps_automation_with_its_label() {
let s = Shutai::from_peer_uid(501).declaring(Declared::Agent {
label: Some("claude-code".into()),
});
assert_eq!(
Yurai::from_shutai(&s),
Yurai::Automation {
label: Some("claude-code".into())
}
);
assert!(Yurai::from_shutai(&s).is_automation());
}
#[test]
fn a_reconciler_is_automation_too() {
let s = Shutai::from_peer_uid(501).declaring(Declared::Reconciler {
label: Some("ghost-sweeper".into()),
});
assert!(
Yurai::from_shutai(&s).is_automation(),
"a reconciler drives the terminal without a human — freio must \
reach it"
);
}
#[test]
fn a_human_connection_is_not_automation() {
let s = Shutai::from_peer_uid(501).declaring(Declared::Human);
assert_eq!(Yurai::from_shutai(&s), Yurai::Human);
assert!(!Yurai::from_shutai(&s).is_automation());
}
#[test]
fn the_default_is_unknown_so_legacy_records_stay_honest() {
assert_eq!(Yurai::default(), Yurai::Unknown);
}
}