bot-forge 1.0.2

Rust CLI for installing agent skills and developer tools from configurable forms.
Documentation
//! Public preview and execution-result contracts.
//!
//! These presentation-neutral DTOs are shared by execution, CLI output, final report persistence,
//! and library callers. Serialized enum names are machine-output contracts.

use std::path::PathBuf;

use serde::Serialize;

use crate::model::{Agent, RegistryEntry};

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
/// Detection and installation status for one configured tool.
pub struct ToolStatus {
    /// Canonical component name.
    pub name: String,
    /// Optional human-readable component name.
    pub display_name: Option<String>,
    /// Whether interactive selection may omit the tool.
    pub optional: bool,
    /// Whether configured detection currently succeeds.
    pub installed: bool,
    /// Detected version text, when the check produces one.
    pub version: Option<String>,
    /// Version offered by the current configuration, when it is comparable.
    pub required_version: Option<String>,
    /// Whether the detected version is older than the configured offered version.
    pub outdated: bool,
    /// Whether the configuration supplies an installation backend.
    pub installable: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
/// Detection and installation status for one configured skill and agent.
pub struct SkillStatus {
    /// Canonical skill name.
    pub name: String,
    /// Optional human-readable skill name.
    pub display_name: Option<String>,
    /// Whether interactive selection may omit the skill.
    pub optional: bool,
    /// Agent whose destination was inspected.
    pub agent: Agent,
    /// Existing agent skill directory, when available.
    pub agent_dir: Option<PathBuf>,
    /// Whether the skill payload already exists at the destination.
    pub installed: bool,
    /// Whether the configuration supplies a non-empty source.
    pub installable: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
/// Presentation-neutral detection snapshot produced before execution.
pub struct InstallPreview {
    /// Tool statuses in canonical configuration order.
    pub tools: Vec<ToolStatus>,
    /// Skill statuses in canonical skill-and-agent order.
    pub skills: Vec<SkillStatus>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
/// Final execution result, committed registry entries, and post-install detection state.
pub struct InstallReport {
    /// Registry entries committed by this run.
    pub entries: Vec<RegistryEntry>,
    /// Detection state observed after execution.
    pub final_preview: InstallPreview,
    /// Per-tool outcomes in plan order.
    pub tools: Vec<ToolInstallResult>,
    /// Aggregate run outcome.
    pub outcome: InstallOutcome,
    /// End-to-end run duration in milliseconds.
    pub duration_ms: u128,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
/// Result of processing one tool during an installation run.
pub enum ToolInstallOutcome {
    /// Detection showed the requested tool was already installed.
    AlreadyPresent,
    /// Installation and verification completed successfully.
    Installed,
    /// Processing stopped in response to cancellation.
    Cancelled,
    /// Installation ran but the configured verification did not succeed.
    VerificationFailed,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
/// Named per-tool outcome included in [`InstallReport`].
pub struct ToolInstallResult {
    /// Canonical component name.
    pub name: String,
    /// Terminal tool outcome.
    pub outcome: ToolInstallOutcome,
    /// Optional diagnostic or status detail.
    pub message: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
/// Aggregate terminal state of an installation run.
pub enum InstallOutcome {
    /// Every selected operation reached an accepted terminal state.
    Success,
    /// The run stopped in response to cancellation.
    Cancelled,
    /// At least one selected operation failed.
    Failed,
}

impl InstallPreview {
    /// Return tools that are not currently detected as installed.
    pub fn missing_tools(&self) -> Vec<&ToolStatus> {
        self.tools
            .iter()
            .filter(|status| !status.installed)
            .collect()
    }

    /// Return missing skills that have an installable agent destination.
    pub fn missing_skills(&self) -> Vec<&SkillStatus> {
        self.skills
            .iter()
            .filter(|status| !status.installed && status.installable)
            .collect()
    }
}