cotis-cli 0.1.0-alpha

Plugin host for Cotis build, check, and run routines
Documentation
use clap::{Args, Parser, Subcommand};
use clap_complete::Shell;

#[derive(Parser)]
#[command(
    name = "cotis-cli",
    version,
    author,
    about = "Install, update, and run Cotis routine plugins (cdylib host).",
    long_about = "cotis-cli manages dynamic-library routine plugins: install from a local Cargo project, \
crates.io, or GitHub releases, then run them with arguments passed after `--`.",
    arg_required_else_help = true,
    propagate_version = true,
    after_long_help = COMPLETIONS_HINT,
)]
pub struct CotisCli {
    /// Enable debug-level logging (default is info).
    #[arg(short, long, global = true)]
    pub verbose: bool,

    /// Allow replacing an existing install in the cache.
    #[arg(
        long,
        short = 'f',
        global = true,
        visible_alias = "fo",
        help = "Overwrite files if this routine (and version) is already installed (legacy long: --fo)"
    )]
    pub overwrite: bool,

    #[command(subcommand)]
    pub command: Commands,
}

const COMPLETIONS_HINT: &str =
    "Shell completions: cotis-cli completions <SHELL> (bash, elvish, fish, powershell, zsh).";

#[derive(Subcommand)]
pub enum Commands {
    /// Install a routine from `path:`, `crate:`, or `gh:`.
    #[command(after_long_help = EXAMPLES_INSTALL)]
    Install(InstallArgs),

    /// Reinstall using the same sources as `install` (always overwrites existing files).
    #[command(alias = "reinstall", after_long_help = EXAMPLES_INSTALL)]
    Update(InstallArgs),

    /// Run an installed routine; arguments after `--` are passed to the plugin.
    #[command(after_long_help = EXAMPLES_RUN)]
    Run(RunArgs),

    /// Same as `run` (kept for compatibility).
    #[command(hide = true)]
    Build(RunArgs),

    /// List installed routine names.
    List,

    /// Remove a routine and all installed versions under its cache directory.
    Remove(RemoveArgs),

    /// Print JSON plugin descriptor from an installed routine.
    Info(InfoArgs),

    /// Print help text exported by the routine plugin.
    #[command(name = "help-routine", visible_alias = "routine-help")]
    HelpRoutine(InfoArgs),

    /// Write a shell completion script to stdout (redirect to a file or eval as appropriate for your shell).
    Completions {
        #[arg(value_enum)]
        shell: Shell,
    },
}

const EXAMPLES_INSTALL: &str = "Examples:\n  cotis-cli install path:C:\\proj\\my-routine\n  cotis-cli install crate:my-routine@0.2.0\n  cotis-cli install gh:org/repo@latest my-alias";

const EXAMPLES_RUN: &str = "Examples:\n  cotis-cli run my_routine -- --output ./dist\n  cotis-cli run my_routine@1.0.0 -- --flag\n\nTip: `cotis-cli list` shows installed names; for custom shell completion you can complete the first argument from that list.";

#[derive(Args, Clone)]
pub struct InstallArgs {
    /// `path:<dir>` / `crate:<name>@<version>` / `gh:<owner>/<repo>@<tag|latest>`
    pub spec: Option<String>,

    /// Optional routine name (mainly for `path:` and `gh:` installs).
    pub alias: Option<String>,

    /// Cdylib Rust target name (artifact stem). Overrides `cargo metadata` detection for `path:` / `crate:` builds.
    #[arg(
        long = "cdylib-name",
        visible_alias = "dll-name",
        value_name = "NAME",
        help = "Built cdylib stem (e.g. my_plugin); default: from cargo metadata. A trailing .dll, .so, or .dylib is stripped"
    )]
    pub cdylib_name: Option<String>,
}

#[derive(Args, Clone)]
pub struct RunArgs {
    /// Routine name, or `name@version` to pin a version.
    pub routine: Option<String>,

    #[arg(
        trailing_var_arg = true,
        allow_hyphen_values = true,
        help = "Arguments forwarded to the routine (use `--` before flags meant for the plugin)"
    )]
    pub passthrough: Vec<String>,
}

#[derive(Args, Clone)]
pub struct RemoveArgs {
    /// Routine name (directory under the routines cache).
    pub routine: Option<String>,
}

#[derive(Args, Clone)]
pub struct InfoArgs {
    /// Routine name or `name@version`.
    pub spec: Option<String>,
}