netsky 0.2.0

netsky CLI: the viable system launcher and subcommand dispatcher
Documentation
//! `netsky agentinfinity` — idempotently spawn the watchdog tmux session.
//!
//! Clears the readiness marker before spawn so the marker transitions
//! empty → present during agentinfinity's own startup (its final boot
//! step touches the marker; `netsky agentinit` polls for it). Ticker +
//! launchd integration is triggered by the caller (typically `netsky
//! up`) via the respective subcommands.

use std::fs;
use std::process::Command;

use netsky_core::agent::AgentId;
use netsky_core::consts::{AGENTINFINITY_LISTENER_WINDOW, AGENTINFINITY_NAME, NETSKY_BIN};
use netsky_core::paths::{agentinfinity_ready_marker, ensure_state_dir};
use netsky_core::spawn::{self, SpawnOptions, SpawnOutcome};

pub fn run() -> netsky_core::Result<()> {
    let agent = AgentId::Agentinfinity;
    if spawn::is_up(agent) {
        ensure_listener_window()?;
        println!(
            "[agentinfinity] session '{}' already up; skipping spawn",
            agent
        );
        return Ok(());
    }

    ensure_state_dir()?;
    let marker = agentinfinity_ready_marker();
    if marker.exists() {
        fs::remove_file(&marker).ok();
    }

    let cwd = std::env::current_dir()?;
    let opts = SpawnOptions::defaults_for(agent, cwd);
    match spawn::spawn(agent, &opts)? {
        SpawnOutcome::Spawned => {
            ensure_listener_window()?;
            println!(
                "[agentinfinity] spawned '{}' ({})",
                agent,
                opts.runtime.describe()
            );
        }
        SpawnOutcome::AlreadyUp => {
            ensure_listener_window()?;
            println!("[agentinfinity] already up (race)");
        }
    }
    Ok(())
}

fn ensure_listener_window() -> netsky_core::Result<()> {
    let windows = Command::new("tmux")
        .args([
            "list-windows",
            "-t",
            AGENTINFINITY_NAME,
            "-F",
            "#{window_name}",
        ])
        .output()?;
    if windows.status.success()
        && String::from_utf8_lossy(&windows.stdout)
            .lines()
            .any(|line| line.trim() == AGENTINFINITY_LISTENER_WINDOW)
    {
        return Ok(());
    }

    let status = Command::new("tmux")
        .args([
            "new-window",
            "-d",
            "-t",
            AGENTINFINITY_NAME,
            "-n",
            AGENTINFINITY_LISTENER_WINDOW,
            &format!("{NETSKY_BIN} watchdog listen"),
        ])
        .status()?;
    if !status.success() {
        netsky_core::bail!("failed to start agentinfinity listener window");
    }
    Ok(())
}