tachyon-types 0.1.0

Shared myko entity and command types for the tachyon Ansible runner.
Documentation
use std::collections::HashMap;

use myko_macros::myko_item;
use serde::{Deserialize, Serialize};
use ts_rs::TS;

use crate::PlaybookId;

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")]
pub enum RunStatus {
    /// Admitted to the queue but not yet started: waiting for a lease on every
    /// resource it targets. Promoted to `Running` by the admission step.
    Queued,
    #[default]
    Running,
    Completed,
    Failed,
    Cancelled,
}

myko::register_ts_export!(RunStatus);

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")]
pub struct HostStats {
    pub ok: u32,
    pub changed: u32,
    pub failed: u32,
    pub skipped: u32,
    pub unreachable: u32,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub last_failure: Option<HostFailure>,
}

myko::register_ts_export!(HostStats);

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")]
pub struct HostFailure {
    pub task: String,
    pub message: String,
    pub seq: u64,
}

myko::register_ts_export!(HostFailure);

#[myko_item]
pub struct Run {
    pub playbook_id: PlaybookId,
    pub status: RunStatus,
    pub started_at: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub finished_at: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub exit_code: Option<i32>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extra_vars: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<String>,
    /// Inventory groups this run targets (derived from `limit` at submission).
    /// The lease queue serializes runs whose resources overlap. `#[serde(default)]`
    /// keeps older persisted runs (written before the queue existed) loadable.
    #[serde(default)]
    pub resources: Vec<String>,
    #[serde(default)]
    pub host_stats: HashMap<String, HostStats>,
    /// Server-stamped identity of the WS connection that launched this run —
    /// actor attribution (a human via the UI, an agent via MCP). `#[myko_client_id]`
    /// stamps it on emit; `#[serde(default)]` keeps runs persisted before this
    /// field existed loadable.
    ///
    /// NOTE: live only — the SQLite projection does not yet store this column, so
    /// it resets to `None` on restart. Durable persistence (schema column +
    /// insert/select) is a tracked follow-up.
    #[myko_client_id]
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub client_id: Option<String>,
}