steer/cli/
args.rs

1use clap::{Parser, Subcommand};
2use std::path::PathBuf;
3use steer_core::api::Model;
4use strum::IntoEnumIterator;
5
6// Wrapper to implement clap::ValueEnum for Model
7#[derive(Debug, Clone, Copy)]
8pub struct ModelArg(pub Model);
9
10impl From<ModelArg> for Model {
11    fn from(arg: ModelArg) -> Self {
12        arg.0
13    }
14}
15
16impl clap::ValueEnum for ModelArg {
17    fn value_variants<'a>() -> &'a [Self] {
18        use once_cell::sync::Lazy;
19        static VARIANTS: Lazy<Vec<ModelArg>> = Lazy::new(|| Model::iter().map(ModelArg).collect());
20        &VARIANTS
21    }
22
23    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
24        let s: &'static str = self.0.into();
25        let mut pv = clap::builder::PossibleValue::new(s);
26
27        // Add all aliases from the Model enum
28        for alias in self.0.aliases() {
29            pv = pv.alias(alias);
30        }
31
32        Some(pv)
33    }
34}
35
36/// An AI-powered agent and CLI tool that assists with software engineering tasks.
37#[derive(Parser)]
38#[command(version, about, long_about = None, author)]
39pub struct Cli {
40    /// Resume an existing session instead of starting a new one (local or remote modes)
41    #[arg(long)]
42    pub session: Option<String>,
43    /// Optional directory to work in
44    #[arg(short, long)]
45    pub directory: Option<std::path::PathBuf>,
46
47    /// Model to use
48    #[arg(short, long, value_enum, default_value_t = ModelArg(Model::default()))]
49    pub model: ModelArg,
50
51    /// Connect to a remote gRPC server instead of running locally
52    #[arg(long)]
53    pub remote: Option<String>,
54
55    /// Custom system prompt to use instead of the default
56    #[arg(long)]
57    pub system_prompt: Option<String>,
58
59    /// Path to the session database file (defaults to ~/.steer/sessions.db)
60    #[arg(long, env = "STEER_SESSION_DB", hide = true)]
61    pub session_db: Option<PathBuf>,
62
63    /// Path to session configuration file (TOML format) for new sessions
64    #[arg(long)]
65    pub session_config: Option<PathBuf>,
66
67    /// Theme to use for the TUI (defaults to "default")
68    #[arg(long)]
69    pub theme: Option<String>,
70
71    /// Force the welcome/setup flow to run (for testing)
72    #[arg(long, hide = true)]
73    pub force_setup: bool,
74
75    /// Subcommands
76    #[command(subcommand)]
77    pub command: Option<Commands>,
78}
79
80#[derive(Subcommand, Clone)]
81pub enum Commands {
82    /// Launch the interactive terminal UI (default)
83    Tui {
84        /// Connect to a remote gRPC server (overrides global --remote)
85        #[arg(long)]
86        remote: Option<String>,
87        /// Path to session configuration file (TOML format) for new sessions (overrides global)
88        #[arg(long)]
89        session_config: Option<PathBuf>,
90        /// Theme to use for the TUI (overrides global)
91        #[arg(long)]
92        theme: Option<String>,
93        /// Force the welcome/setup flow to run (for testing)
94        #[arg(long, hide = true)]
95        force_setup: bool,
96    },
97    /// Manage user preferences
98    Preferences {
99        #[command(subcommand)]
100        action: PreferencesCommands,
101    },
102    /// Run in headless mode
103    Headless {
104        /// Model to use
105        #[arg(long)]
106        model: Option<ModelArg>,
107
108        /// JSON file containing a Vec<Message> to use. If not provided, reads prompt from stdin.
109        #[arg(long)]
110        messages_json: Option<PathBuf>,
111
112        /// Session ID to run in (if not provided, creates a new ephemeral session)
113        #[arg(long)]
114        session: Option<String>,
115
116        /// Path to session configuration file (TOML format) for new sessions
117        #[arg(long)]
118        session_config: Option<PathBuf>,
119
120        /// Custom system prompt to use instead of the default
121        #[arg(long)]
122        system_prompt: Option<String>,
123
124        /// Connect to a remote gRPC server (overrides global --remote)
125        #[arg(long)]
126        remote: Option<String>,
127    },
128    /// Start the gRPC server
129    Server {
130        /// Port to listen on
131        #[arg(long, default_value = "50051")]
132        port: u16,
133
134        /// Bind address
135        #[arg(long, default_value = "127.0.0.1")]
136        bind: String,
137    },
138    /// Session management commands
139    Session {
140        #[command(subcommand)]
141        session_command: SessionCommands,
142    },
143    /// Show a notification (internal use only)
144    #[clap(hide = true)]
145    Notify {
146        #[clap(long)]
147        title: String,
148        #[clap(long)]
149        message: String,
150        #[clap(long)]
151        sound: Option<String>,
152    },
153}
154
155#[derive(Subcommand, Clone)]
156pub enum PreferencesCommands {
157    /// Show current preferences
158    Show,
159    /// Edit preferences file in default editor
160    Edit,
161    /// Reset preferences to defaults
162    Reset,
163}
164
165#[derive(Subcommand, Clone)]
166pub enum SessionCommands {
167    /// List all sessions
168    List {
169        /// Show only active sessions
170        #[arg(long)]
171        active: bool,
172        /// Limit number of sessions to show
173        #[arg(long, default_value = "20")]
174        limit: u32,
175    },
176    /// Create a new session
177    Create {
178        /// Path to session configuration file (TOML format)
179        #[arg(long)]
180        session_config: Option<PathBuf>,
181        /// Session metadata (key=value pairs, comma-separated)
182        #[arg(long)]
183        metadata: Option<String>,
184        /// Custom system prompt to use instead of the default
185        #[arg(long)]
186        system_prompt: Option<String>,
187    },
188    /// Delete a session
189    Delete {
190        /// Session ID to delete
191        session_id: String,
192        /// Force deletion without confirmation
193        #[arg(long)]
194        force: bool,
195    },
196    /// Show session details
197    Show {
198        /// Session ID to show
199        session_id: String,
200    },
201}