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 Execute(commands::ExecuteArgs),
41 Validate(commands::ValidateArgs),
43 List,
45 Init(commands::InitArgs),
47 Inspect(commands::InspectArgs),
49 Setup,
51 Config(ConfigArgs),
53 #[cfg(feature = "slack")]
55 Slack(SlackArgs),
56 Version,
58}
59
60#[derive(Args)]
61pub struct ConfigArgs {
62 #[command(subcommand)]
63 command: ConfigCommand,
64}
65
66#[derive(Subcommand)]
67enum ConfigCommand {
68 Show,
70 Init,
72 Set {
74 key: String,
76 value: String,
78 },
79 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 {
95 #[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}