cli.rs

  1use clap::{Parser, Subcommand};
  2
  3#[derive(Parser)]
  4#[command(name = "td", version, about = "Todo tracker for AI agents")]
  5pub struct Cli {
  6    /// Output JSON
  7    #[arg(short = 'j', long = "json", global = true)]
  8    pub json: bool,
  9
 10    #[command(subcommand)]
 11    pub command: Command,
 12}
 13
 14#[derive(Subcommand)]
 15pub enum Command {
 16    /// Initialize .td directory
 17    Init {
 18        /// Add .td/ to .gitignore
 19        #[arg(long)]
 20        stealth: bool,
 21    },
 22
 23    /// Create a new task
 24    #[command(visible_alias = "add")]
 25    Create {
 26        /// Task title
 27        title: Option<String>,
 28
 29        /// Priority (low, medium, high)
 30        #[arg(short, long, default_value = "medium")]
 31        priority: String,
 32
 33        /// Effort (low, medium, high)
 34        #[arg(short, long, default_value = "medium")]
 35        effort: String,
 36
 37        /// Task type
 38        #[arg(short = 't', long = "type", default_value = "task")]
 39        task_type: String,
 40
 41        /// Description
 42        #[arg(short = 'd', long = "desc")]
 43        desc: Option<String>,
 44
 45        /// Parent task ID (creates a subtask)
 46        #[arg(long)]
 47        parent: Option<String>,
 48
 49        /// Labels (comma-separated)
 50        #[arg(short, long)]
 51        labels: Option<String>,
 52    },
 53
 54    /// List tasks
 55    #[command(visible_alias = "ls")]
 56    List {
 57        /// Filter by status
 58        #[arg(short, long)]
 59        status: Option<String>,
 60
 61        /// Filter by priority (low, medium, high)
 62        #[arg(short, long)]
 63        priority: Option<String>,
 64
 65        /// Filter by effort (low, medium, high)
 66        #[arg(short, long)]
 67        effort: Option<String>,
 68
 69        /// Filter by label
 70        #[arg(short, long)]
 71        label: Option<String>,
 72    },
 73
 74    /// Show task details
 75    Show {
 76        /// Task ID
 77        id: String,
 78    },
 79
 80    /// Update a task
 81    Update {
 82        /// Task ID
 83        id: String,
 84
 85        /// Set status
 86        #[arg(short, long)]
 87        status: Option<String>,
 88
 89        /// Set priority (low, medium, high)
 90        #[arg(short, long)]
 91        priority: Option<String>,
 92
 93        /// Set effort (low, medium, high)
 94        #[arg(short, long)]
 95        effort: Option<String>,
 96
 97        /// Set title
 98        #[arg(short = 't', long)]
 99        title: Option<String>,
100
101        /// Set description
102        #[arg(short = 'd', long = "desc")]
103        desc: Option<String>,
104    },
105
106    /// Mark task(s) as closed
107    #[command(visible_alias = "close")]
108    Done {
109        /// Task IDs
110        #[arg(required = true)]
111        ids: Vec<String>,
112    },
113
114    /// Reopen task(s)
115    Reopen {
116        /// Task IDs
117        #[arg(required = true)]
118        ids: Vec<String>,
119    },
120
121    /// Manage dependencies / blockers
122    Dep {
123        #[command(subcommand)]
124        action: DepAction,
125    },
126
127    /// Manage labels
128    Label {
129        #[command(subcommand)]
130        action: LabelAction,
131    },
132
133    /// Search tasks by title or description
134    Search {
135        /// Search query
136        query: String,
137    },
138
139    /// Show tasks with no open blockers
140    Ready,
141
142    /// Recommend next task(s) to work on
143    Next {
144        /// Scoring strategy: impact (default) or effort
145        #[arg(short, long, default_value = "impact")]
146        mode: String,
147
148        /// Show signal breakdown and equation
149        #[arg(short, long)]
150        verbose: bool,
151
152        /// Maximum number of results
153        #[arg(short = 'n', long = "limit", default_value = "5")]
154        limit: usize,
155    },
156
157    /// Show task statistics (always JSON)
158    Stats,
159
160    /// Vacuum the database
161    Compact,
162
163    /// Export tasks to JSONL (one JSON object per line)
164    Export,
165
166    /// Import tasks from a JSONL file
167    Import {
168        /// Path to JSONL file (- for stdin)
169        file: String,
170    },
171
172    /// Install the agent skill file (SKILL.md)
173    Skill {
174        /// Skills directory (writes managing-tasks-with-td/SKILL.md inside)
175        #[arg(long)]
176        dir: Option<String>,
177    },
178}
179
180#[derive(Subcommand)]
181pub enum DepAction {
182    /// Add a dependency (child is blocked by parent)
183    Add {
184        /// Task that is blocked
185        child: String,
186        /// Task that blocks it
187        parent: String,
188    },
189    /// Remove a dependency
190    Rm {
191        /// Task that was blocked
192        child: String,
193        /// Task that was blocking
194        parent: String,
195    },
196    /// Show child tasks
197    Tree {
198        /// Parent task ID
199        id: String,
200    },
201}
202
203#[derive(Subcommand)]
204pub enum LabelAction {
205    /// Add a label to a task
206    Add {
207        /// Task ID
208        id: String,
209        /// Label to add
210        label: String,
211    },
212    /// Remove a label from a task
213    Rm {
214        /// Task ID
215        id: String,
216        /// Label to remove
217        label: String,
218    },
219    /// List labels on a task
220    List {
221        /// Task ID
222        id: String,
223    },
224    /// List all distinct labels
225    ListAll,
226}