use std::os::unix::process::CommandExt;
use std::process::Command;
use netsky_core::agent::AgentId;
use netsky_core::consts::{AGENTINFINITY_NAME, TICKER_SESSION, TMUX_BIN};
use netsky_sh::tmux;
pub fn run(target: &str) -> netsky_core::Result<()> {
let session = resolve_target(target)?;
if !tmux::has_session(&session) {
netsky_core::bail!(
"tmux session '{session}' is not up.\n\
hint: `netsky up` brings the constellation up, or `netsky agent <N>` spawns one."
);
}
let inside_tmux = std::env::var_os("TMUX").is_some();
let subcmd = if inside_tmux {
"switch-client"
} else {
"attach-session"
};
let err = Command::new(TMUX_BIN).args([subcmd, "-t", &session]).exec();
Err(netsky_core::anyhow!("failed to exec tmux: {err}"))
}
fn resolve_target(target: &str) -> netsky_core::Result<String> {
let t = target.trim();
if t.is_empty() {
netsky_core::bail!("missing target — try `netsky attach 0` or `netsky attach infinity`");
}
match t {
"infinity" | "inf" => Ok(AGENTINFINITY_NAME.to_string()),
"ticker" => Ok(TICKER_SESSION.to_string()),
s => match s.parse::<u32>() {
Ok(n) => Ok(AgentId::from_number(n).name()),
Err(_) => netsky_core::bail!(
"unrecognized target '{target}' — expected 0..N, `infinity`, `inf`, or `ticker`"
),
},
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolves_numbers() {
assert_eq!(resolve_target("0").unwrap(), "agent0");
assert_eq!(resolve_target("7").unwrap(), "agent7");
assert_eq!(resolve_target(" 3 ").unwrap(), "agent3");
}
#[test]
fn resolves_aliases() {
assert_eq!(resolve_target("infinity").unwrap(), "agentinfinity");
assert_eq!(resolve_target("inf").unwrap(), "agentinfinity");
assert_eq!(resolve_target("ticker").unwrap(), "netsky-ticker");
}
#[test]
fn rejects_nonsense() {
assert!(resolve_target("").is_err());
assert!(resolve_target(" ").is_err());
assert!(resolve_target("agent0").is_err());
assert!(resolve_target("-1").is_err());
assert!(resolve_target("xyz").is_err());
}
}