harn-cli 0.7.58

CLI for the Harn programming language — run, test, REPL, format, and lint
Documentation
use std::net::SocketAddr;
use std::path::PathBuf;

use clap::{Args, Subcommand, ValueEnum};

#[derive(Debug, Args)]
pub(crate) struct ServeArgs {
    #[command(subcommand)]
    pub command: ServeCommand,
}

#[derive(Debug, Subcommand)]
pub(crate) enum ServeCommand {
    /// Serve a .harn agent over stdio using ACP.
    Acp(ServeAcpArgs),
    /// Serve a .harn agent over HTTP using A2A.
    A2a(A2aServeArgs),
    /// Serve a `.harn` file as an MCP server. Exposes either exported
    /// `pub fn` entrypoints (recommended) or, when the script registers
    /// tools/resources/prompts via `mcp_tools(...)` / `mcp_resource(...)`
    /// / `mcp_prompt(...)`, that script-driven surface.
    Mcp(ServeMcpArgs),
}

#[derive(Debug, Args)]
pub(crate) struct ServeAcpArgs {
    /// Static API keys accepted by the ACP authenticate method.
    #[arg(long = "api-key", env = "HARN_SERVE_API_KEY", value_delimiter = ',')]
    pub api_key: Vec<String>,
    /// Shared secret for HMAC authentication through the ACP authenticate method.
    #[arg(long = "hmac-secret", env = "HARN_SERVE_HMAC_SECRET")]
    pub hmac_secret: Option<String>,
    /// Path to the .harn file to serve.
    pub file: String,
}

#[derive(Debug, Args)]
pub(crate) struct A2aServeArgs {
    /// Port to bind the A2A server to.
    #[arg(long, default_value_t = 8080)]
    pub port: u16,
    /// Public URL advertised in the A2A agent card.
    #[arg(long = "public-url", env = "HARN_SERVE_A2A_PUBLIC_URL")]
    pub public_url: Option<String>,
    /// Static API keys accepted via `Authorization: Bearer` or `X-API-Key`.
    #[arg(long = "api-key", env = "HARN_SERVE_API_KEY", value_delimiter = ',')]
    pub api_key: Vec<String>,
    /// Shared secret for HMAC request signing.
    #[arg(long = "hmac-secret", env = "HARN_SERVE_HMAC_SECRET")]
    pub hmac_secret: Option<String>,
    /// Shared secret used to attach an HS256 signature to the agent card.
    #[arg(long = "card-signing-secret", env = "HARN_SERVE_A2A_CARD_SECRET")]
    pub card_signing_secret: Option<String>,
    /// TLS listener mode. Supplying both `--cert` and `--key` implies `pem`.
    #[arg(long = "tls", value_enum, default_value_t = ServeTlsMode::Plain)]
    pub tls: ServeTlsMode,
    /// PEM-encoded certificate chain for in-process HTTPS termination.
    #[arg(long, env = "HARN_SERVE_CERT", value_name = "PATH")]
    pub cert: Option<PathBuf>,
    /// PEM-encoded private key for in-process HTTPS termination.
    #[arg(long, env = "HARN_SERVE_KEY", value_name = "PATH")]
    pub key: Option<PathBuf>,
    /// Path to the .harn file to serve.
    pub file: String,
}

#[derive(Debug, Args)]
pub(crate) struct ServeMcpArgs {
    /// Transport to expose for MCP clients.
    #[arg(long, value_enum, default_value_t = McpServeTransport::Stdio)]
    pub transport: McpServeTransport,
    /// Socket address to bind when serving over HTTP.
    #[arg(
        long,
        env = "HARN_SERVE_MCP_BIND",
        default_value = "127.0.0.1:8765",
        value_name = "ADDR"
    )]
    pub bind: SocketAddr,
    /// Streamable HTTP endpoint path.
    #[arg(long, default_value = "/mcp", value_name = "PATH")]
    pub path: String,
    /// Legacy SSE endpoint path for older MCP clients.
    #[arg(long = "sse-path", default_value = "/sse", value_name = "PATH")]
    pub sse_path: String,
    /// Legacy SSE POST endpoint path for older MCP clients.
    #[arg(
        long = "messages-path",
        default_value = "/messages",
        value_name = "PATH"
    )]
    pub messages_path: String,
    /// Static API keys accepted over HTTP via `Authorization: Bearer` or `X-API-Key`.
    #[arg(long = "api-key", env = "HARN_SERVE_API_KEY", value_delimiter = ',')]
    pub api_key: Vec<String>,
    /// Shared secret for HMAC request signing on HTTP transports.
    #[arg(long = "hmac-secret", env = "HARN_SERVE_HMAC_SECRET")]
    pub hmac_secret: Option<String>,
    /// TLS listener mode. Supplying both `--cert` and `--key` implies `pem`.
    #[arg(long = "tls", value_enum, default_value_t = ServeTlsMode::Plain)]
    pub tls: ServeTlsMode,
    /// PEM-encoded certificate chain for in-process HTTPS termination.
    #[arg(long, env = "HARN_SERVE_CERT", value_name = "PATH")]
    pub cert: Option<PathBuf>,
    /// PEM-encoded private key for in-process HTTPS termination.
    #[arg(long, env = "HARN_SERVE_KEY", value_name = "PATH")]
    pub key: Option<PathBuf>,
    /// Optional Server Card JSON to advertise (MCP v2.1). Path to a
    /// `.json` file OR an inline JSON string. The card is embedded in
    /// the `initialize` response's `serverInfo.card` field AND exposed
    /// as a static resource at `well-known://mcp-card`.
    #[arg(long = "card", value_name = "PATH_OR_JSON")]
    pub card: Option<String>,
    /// Path to the `.harn` file whose exported `pub fn` entrypoints are
    /// served. Scripts that instead call `mcp_tools(registry)` /
    /// `mcp_resource(...)` / `mcp_prompt(...)` are detected and served
    /// via the script-driven surface.
    pub file: String,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum McpServeTransport {
    Stdio,
    Http,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum ServeTlsMode {
    Plain,
    Edge,
    SelfSignedDev,
    Pem,
}