partiri-cli 0.2.0

Partiri CLI — Deploy and manage services on Partiri Cloud
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(
    name = "partiri",
    version,
    about = "Deploy and manage services on Partiri Cloud",
    long_about = None,
)]
pub struct Cli {
    /// Emit machine-readable JSON output to stdout (errors as JSON to stderr).
    #[arg(long, short = 'j', global = true)]
    pub json: bool,
    /// Skip confirmation prompts on destructive operations.
    #[arg(long, short = 'y', global = true)]
    pub yes: bool,
    /// Never prompt; error if a required value is missing. Auto-enabled when stdin is not a TTY.
    #[arg(long = "no-input", global = true)]
    pub no_input: bool,
    #[command(subcommand)]
    pub command: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
    /// Configure your Partiri API key
    Auth {
        /// Set the API key directly (mutually exclusive with --key-stdin).
        #[arg(long, value_name = "KEY", conflicts_with = "key_stdin")]
        key: Option<String>,
        /// Read the API key from stdin (single line, trimmed).
        #[arg(long = "key-stdin")]
        key_stdin: bool,
        /// Overwrite an existing key without confirmation.
        #[arg(long)]
        force: bool,
    },
    /// Create .partiri.jsonc. Interactive wizard by default; pass --template for a non-interactive scaffold.
    Init {
        /// Skip the wizard and write a commented `.partiri.jsonc` template that the agent (or human) fills in by hand.
        #[arg(long)]
        template: bool,
    },
    /// Validate the local .partiri.jsonc config file
    Validate {
        /// Also run live API checks: UUIDs exist, region/pod pairing, repo/registry reachability,
        /// and (when applicable) the health-check URL.
        #[arg(long)]
        remote: bool,
    },
    /// Service management
    #[command(subcommand)]
    Service(ServiceCommands),
    /// Project management
    #[command(subcommand)]
    Projects(ProjectCommands),
    /// Service discovery (list services in a project)
    #[command(subcommand)]
    Services(ServicesCommands),
    /// Agent helpers — guide, schema, templates, capabilities, doctor, context, etc.
    #[command(subcommand)]
    Llm(LlmCommands),
    /// Workspace management
    #[command(subcommand)]
    Workspaces(WorkspaceCommands),
    /// Region discovery
    #[command(subcommand)]
    Regions(RegionCommands),
    /// Compute pod discovery
    #[command(subcommand)]
    Pods(PodCommands),
    /// Install or remove the Partiri MCP server in AI tools
    #[command(subcommand)]
    Mcp(McpCommands),
}

#[derive(Subcommand)]
pub enum RegionCommands {
    /// List regions available in a workspace
    List {
        /// Workspace UUID.
        #[arg(long, value_name = "UUID")]
        workspace: String,
    },
}

#[derive(Subcommand)]
pub enum PodCommands {
    /// List compute pods available in a workspace
    List {
        /// Workspace UUID.
        #[arg(long, value_name = "UUID")]
        workspace: String,
    },
}

#[derive(Subcommand)]
pub enum McpCommands {
    /// Install the Partiri MCP server into an AI tool
    Install {
        /// Target client (claude-desktop, claude-code, cursor, vscode, copilot-cli, windsurf)
        #[arg(long)]
        client: Option<String>,
    },
    /// Remove the Partiri MCP server from an AI tool
    Uninstall {
        /// Target client (claude-desktop, claude-code, cursor, vscode, copilot-cli, windsurf)
        #[arg(long)]
        client: Option<String>,
    },
}

#[derive(Subcommand)]
pub enum ServiceCommands {
    /// Register the service on Partiri and update .partiri.jsonc
    Create,
    /// Pull an existing service and save it as .partiri.jsonc
    Pull,
    /// Push local config changes to the existing service
    Push,
    /// Show current service metrics and recent jobs
    Metrics,
    /// Show the last 35 log lines from the past hour
    Logs,
    /// List jobs for this service
    Jobs,
    /// Trigger a deploy job
    Deploy,
    /// Pause the service
    Pause,
    /// Resume a paused service
    Unpause,
    /// Kill the service (requires confirmation)
    Kill,
    /// Fill in workspace, project, region and pod UUIDs (interactive when no flags are passed)
    Link {
        /// New workspace UUID. Requires --project.
        #[arg(long, value_name = "UUID")]
        workspace: Option<String>,
        /// New project UUID. Required when --workspace changes.
        #[arg(long, value_name = "UUID")]
        project: Option<String>,
        /// New region UUID. Requires --pod.
        #[arg(long, value_name = "UUID")]
        region: Option<String>,
        /// New compute pod UUID. Required when --region changes.
        #[arg(long, value_name = "UUID")]
        pod: Option<String>,
        /// Set fk_service_secret to this token UUID.
        #[arg(long, value_name = "UUID", conflicts_with = "clear_token")]
        token: Option<String>,
        /// Clear fk_service_secret.
        #[arg(long)]
        clear_token: bool,
    },
    /// Link an authentication token to this service (for private repositories or registries)
    Token {
        /// Set fk_service_secret to this token UUID.
        #[arg(long, value_name = "UUID", conflicts_with = "clear")]
        secret: Option<String>,
        /// Clear fk_service_secret on this service.
        #[arg(long)]
        clear: bool,
    },
}

#[derive(Subcommand)]
pub enum ProjectCommands {
    /// List all projects in a workspace
    List {
        /// Workspace UUID to list projects for. Required when you belong to more than one workspace.
        #[arg(long, value_name = "UUID")]
        workspace: Option<String>,
    },
    /// Create a new project in a workspace
    Create {
        /// Workspace UUID. Required when you belong to more than one workspace.
        #[arg(long, value_name = "UUID")]
        workspace: Option<String>,
        /// Project name.
        #[arg(long, value_name = "NAME")]
        name: Option<String>,
        /// Environment (`dev`, `staging`, or `prod`).
        #[arg(long, value_name = "ENV")]
        environment: Option<String>,
    },
}

#[derive(Subcommand)]
pub enum WorkspaceCommands {
    /// List all workspaces
    List,
}

#[derive(Subcommand)]
pub enum ServicesCommands {
    /// List services in a project
    List {
        /// Project UUID.
        #[arg(long, value_name = "UUID")]
        project: String,
    },
}

#[derive(Subcommand)]
pub enum LlmCommands {
    /// Print the embedded agent guide (LLM.md).
    Guide,
    /// JSON schema of .partiri.jsonc.
    Schema,
    /// Print a pre-filled .partiri.jsonc template (does not write to disk).
    Template {
        /// `webservice` (default), `static`, or `private-service`.
        #[arg(long)]
        deploy_type: Option<String>,
        /// `node` (default), `rust`, `python`, `go`, `ruby`, `elixir`, `php`, `jvm`, `dotnet`, `cpp`, `static`, `registry`.
        #[arg(long)]
        runtime: Option<String>,
        /// `repo` (default) or `registry`.
        #[arg(long)]
        source: Option<String>,
    },
    /// Print worked examples for common deployment shapes.
    Examples,
    /// Emit the entire CLI tree as JSON.
    Capabilities,
    /// Catalog of every error code the CLI emits.
    Errors,
    /// Deep help for one command (e.g. `partiri llm explain validate`).
    Explain {
        /// The command path. Multi-word values like "service deploy" must be quoted.
        command: String,
    },
    /// Auth state and identity (single API call to /workspaces).
    Whoami,
    /// Environment-level diagnostic.
    Doctor,
    /// Full nested workspace tree in one call.
    Context {
        /// Limit to one workspace (cheaper).
        #[arg(long, value_name = "UUID")]
        workspace: Option<String>,
    },
    /// Suggest the next command for the current `.partiri.jsonc` state.
    Next,
}