frame-cli 0.3.0

CLI for Frame — five intention-verbs over one application: frame new scaffolds it, frame run serves it, frame test proves it (real browser included), frame check verifies it statically, frame doctor walks the prerequisites
Documentation
//! `frame host` — boot a frame host from an explicit config file.
//!
//! The operations-facing home of what the standalone `frame-host` binary
//! does: same library, same config contract, one CLI. An application
//! directory wants `frame run`; this subcommand exists for estates that
//! deploy a config file against pre-built assets.

use std::path::Path;

use frame_host::FrameConfig;

use crate::error::CliError;

/// Boots the full frame host stack from the named config and serves until a
/// shutdown signal.
///
/// # Errors
///
/// Surfaces the host's own typed failure from config loading, boot,
/// serving, or ordered shutdown.
pub fn host(config: &Path) -> Result<(), CliError> {
    // Load the config through the host's own loader (the one parser every verb
    // shares) and probe its EXPLICITLY-stated sockets before boot, so a port
    // collision fails with actionable guidance naming the frame.toml key rather
    // than a bare bind error mid-boot. A portless config has nothing to probe.
    // `frame_host::run` re-reads the same file; the double read is a cheap price
    // for the earlier, clearer refusal.
    let loaded = FrameConfig::load(config).map_err(|source| CliError::Config {
        path: config.to_path_buf(),
        source: Box::new(source),
    })?;
    crate::preflight::ensure_ports_available(&loaded)?;
    let cli = frame_host::Cli {
        config: config.to_path_buf(),
    };
    frame_host::run(&cli).map_err(|source| CliError::Host {
        source: Box::new(source),
    })
}