haematite-cli 0.21.0

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
//! Catalogue membership is fixed; the seat chooses the executable explicitly.

use std::path::{Path, PathBuf};

const IDS: [&str; 5] = ["claude-code", "codex", "gemini-cli", "opencode", "pi"];

pub(super) fn validate(id: &str) -> anyhow::Result<()> {
    anyhow::ensure!(
        IDS.contains(&id),
        "harness.id refused: expected {}",
        IDS.join(", ")
    );
    Ok(())
}

pub(super) fn executable(program: &Path) -> anyhow::Result<PathBuf> {
    if program.is_absolute() {
        return check(program);
    }
    anyhow::ensure!(
        program.components().count() == 1,
        "harness.program must be absolute or a bare executable name"
    );
    let path = std::env::var_os("PATH")
        .ok_or_else(|| anyhow::anyhow!("harness.program unavailable: PATH is absent"))?;
    for directory in std::env::split_paths(&path).filter(|directory| directory.is_absolute()) {
        let candidate = directory.join(program);
        if let Ok(candidate) = check(&candidate) {
            return Ok(candidate);
        }
    }
    anyhow::bail!("harness.program unavailable on the launch PATH")
}

fn check(path: &Path) -> anyhow::Result<PathBuf> {
    use std::os::unix::fs::PermissionsExt as _;
    let metadata = std::fs::metadata(path)
        .map_err(|error| anyhow::anyhow!("harness.program unavailable: {}", error.kind()))?;
    anyhow::ensure!(
        metadata.is_file() && metadata.permissions().mode() & 0o111 != 0,
        "harness.program is not an executable file"
    );
    Ok(path.to_path_buf())
}