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 new` — create an application, prerequisites checked first.

use crate::doctor;
use crate::error::CliError;
use crate::scaffold::{self, GitInit, NewOptions};

/// Creates a new application after checking every prerequisite tool, so a
/// missing tool surfaces here — the earliest, most fixable moment — instead
/// of at first build.
///
/// # Errors
///
/// Refuses on missing prerequisites (with install links), invalid names,
/// existing targets, and any generation failure.
pub fn new(name: &str) -> Result<(), CliError> {
    doctor::require(doctor::NEW_PREREQUISITES, "frame new")?;
    doctor::warn_if_chrome_missing();
    let target_parent =
        std::env::current_dir().map_err(|source| CliError::CurrentDir { source })?;
    let path = scaffold::generate(&NewOptions {
        name: name.to_owned(),
        target_parent,
    })?;
    println!("created {}", path.display());
    // Initialise a git repository and make the initial commit — unless the new
    // tree is already inside an existing work tree (a monorepo or an
    // already-versioned directory), in which case nesting a second repository
    // would be a surprise, so we leave it alone and say so.
    match scaffold::init_repo(&path)? {
        GitInit::Initialized => println!("initialized a git repository with an initial commit"),
        GitInit::SkippedInsideExistingRepo => {
            println!("inside an existing git repository; left version control untouched");
        }
        GitInit::SkippedGitMissing => {
            println!("git is not installed; created the application without version control");
        }
    }
    println!();
    println!("  cd {name}");
    println!("  frame run    # build it and serve it");
    println!("  frame test   # prove it end to end, real browser included");
    Ok(())
}