Skip to main content

minion_engine/cli/
mod.rs

1mod commands;
2pub mod display;
3pub mod init_templates;
4mod setup;
5
6use clap::{Args, Parser, Subcommand};
7
8#[derive(Parser)]
9#[command(
10    name = "minion",
11    about = "AI Workflow Engine — orchestrate Claude Code CLI with YAML workflows",
12    version,
13    after_help = "\x1b[1mQuick start:\x1b[0m
14  cargo install minion-engine
15  minion setup
16  minion execute workflows/code-review.yaml -- 42
17
18\x1b[1mRequirements:\x1b[0m
19  • ANTHROPIC_API_KEY   — required for AI steps (chat, map)
20  • gh auth login       — required for GitHub-based workflows (GH_TOKEN auto-detected)
21  • Docker Desktop      — required for --sandbox mode (creates isolated containers)
22
23\x1b[1mExamples:\x1b[0m
24  minion execute workflows/code-review.yaml -- 42        Review PR #42 (sandbox on by default)
25  minion execute workflows/fix-issue.yaml -- 123         Fix issue #123
26  minion execute my-workflow.yaml --no-sandbox -- main   Run without Docker sandbox
27  minion list                                            List available workflows
28  minion init my-workflow --template code-review         Create a new workflow
29  minion setup                                           Interactive setup wizard
30  minion slack start                                     Start Slack bot (requires --features slack)"
31)]
32pub struct Cli {
33    #[command(subcommand)]
34    command: Command,
35}
36
37#[derive(Subcommand)]
38enum Command {
39    /// Run a workflow
40    Execute(commands::ExecuteArgs),
41    /// Validate a workflow YAML without running
42    Validate(commands::ValidateArgs),
43    /// List available workflows (current dir, ./workflows/, ~/.minion/workflows/)
44    List,
45    /// Create a new workflow from a template
46    Init(commands::InitArgs),
47    /// Inspect a workflow: show config, scopes, dependency graph and dry-run summary
48    Inspect(commands::InspectArgs),
49    /// Interactive setup wizard — configure API keys, Docker, and Slack integration
50    Setup,
51    /// Manage default configuration (model, provider, timeouts)
52    Config(ConfigArgs),
53    /// Slack bot integration (requires: cargo install minion-engine --features slack)
54    #[cfg(feature = "slack")]
55    Slack(SlackArgs),
56    /// Show version
57    Version,
58}
59
60#[derive(Args)]
61pub struct ConfigArgs {
62    #[command(subcommand)]
63    command: ConfigCommand,
64}
65
66#[derive(Subcommand)]
67enum ConfigCommand {
68    /// Show current effective configuration (embedded + user + project merged)
69    Show,
70    /// Create or edit user-level defaults (~/.minion/defaults.yaml)
71    Init,
72    /// Set a config value. Example: minion config set chat.model claude-opus-4-20250514
73    Set {
74        /// Config key in dot notation (e.g., chat.model, agent.model, global.timeout)
75        key: String,
76        /// Value to set
77        value: String,
78    },
79    /// Show where config files are located and which ones exist
80    Path,
81}
82
83#[cfg(feature = "slack")]
84#[derive(Args)]
85struct SlackArgs {
86    #[command(subcommand)]
87    command: SlackCommand,
88}
89
90#[cfg(feature = "slack")]
91#[derive(Subcommand)]
92enum SlackCommand {
93    /// Start the Slack bot server
94    Start {
95        /// Port to listen on (default: 9000)
96        #[arg(long, short, default_value = "9000")]
97        port: u16,
98    },
99}
100
101impl Cli {
102    pub async fn run(self) -> anyhow::Result<()> {
103        match self.command {
104            Command::Execute(args) => commands::execute(args).await,
105            Command::Validate(args) => commands::validate(args).await,
106            Command::List => commands::list().await,
107            Command::Init(args) => commands::init(args).await,
108            Command::Inspect(args) => commands::inspect(args).await,
109            Command::Setup => setup::run_setup().await,
110            Command::Config(args) => match args.command {
111                ConfigCommand::Show => commands::config_show().await,
112                ConfigCommand::Init => commands::config_init().await,
113                ConfigCommand::Set { key, value } => commands::config_set(&key, &value).await,
114                ConfigCommand::Path => commands::config_path().await,
115            },
116            #[cfg(feature = "slack")]
117            Command::Slack(args) => match args.command {
118                SlackCommand::Start { port } => crate::slack::start_server(port).await,
119            },
120            Command::Version => {
121                println!("minion {}", env!("CARGO_PKG_VERSION"));
122                Ok(())
123            }
124        }
125    }
126}