netsky 0.1.3

netsky CLI: the viable system launcher and subcommand dispatcher
Documentation
//! `netsky down` — tear down agent0 + clones. Leaves agentinfinity + ticker alone.

use netsky_sh::tmux;

pub fn run() -> netsky_core::Result<()> {
    let targets = agent_sessions();
    if targets.is_empty() {
        println!("[netsky down] no agent sessions running");
        return Ok(());
    }
    for name in &targets {
        tmux::kill_session(name)?;
        println!("[netsky down] killed '{name}'");
    }
    Ok(())
}

/// List `agent0`, `agent1`, ..., `agentN` sessions currently running.
/// Excludes `agentinfinity` and anything else.
fn agent_sessions() -> Vec<String> {
    tmux::list_sessions()
        .into_iter()
        .filter(|n| is_agent_session(n))
        .collect()
}

fn is_agent_session(name: &str) -> bool {
    let rest = match name.strip_prefix(netsky_core::consts::CLONE_PREFIX) {
        Some(r) => r,
        None => return false,
    };
    !rest.is_empty() && rest.chars().all(|c| c.is_ascii_digit())
}

#[cfg(test)]
mod tests {
    use super::is_agent_session;

    #[test]
    fn matches_agent_sessions_only() {
        assert!(is_agent_session("agent0"));
        assert!(is_agent_session("agent5"));
        assert!(is_agent_session("agent42"));
        assert!(!is_agent_session("agentinfinity"));
        assert!(!is_agent_session("agent"));
        assert!(!is_agent_session("agentfoo"));
        assert!(!is_agent_session("foo"));
        assert!(!is_agent_session("netsky-ticker"));
    }
}