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    /// Show task statistics (always JSON)
143    Stats,
144
145    /// Vacuum the database
146    Compact,
147
148    /// Export tasks to JSONL (one JSON object per line)
149    Export,
150
151    /// Import tasks from a JSONL file
152    Import {
153        /// Path to JSONL file (- for stdin)
154        file: String,
155    },
156
157    /// Install the agent skill file (SKILL.md)
158    Skill {
159        /// Skills directory (writes managing-tasks-with-td/SKILL.md inside)
160        #[arg(long)]
161        dir: Option<String>,
162    },
163}
164
165#[derive(Subcommand)]
166pub enum DepAction {
167    /// Add a dependency (child is blocked by parent)
168    Add {
169        /// Task that is blocked
170        child: String,
171        /// Task that blocks it
172        parent: String,
173    },
174    /// Remove a dependency
175    Rm {
176        /// Task that was blocked
177        child: String,
178        /// Task that was blocking
179        parent: String,
180    },
181    /// Show child tasks
182    Tree {
183        /// Parent task ID
184        id: String,
185    },
186}
187
188#[derive(Subcommand)]
189pub enum LabelAction {
190    /// Add a label to a task
191    Add {
192        /// Task ID
193        id: String,
194        /// Label to add
195        label: String,
196    },
197    /// Remove a label from a task
198    Rm {
199        /// Task ID
200        id: String,
201        /// Label to remove
202        label: String,
203    },
204    /// List labels on a task
205    List {
206        /// Task ID
207        id: String,
208    },
209    /// List all distinct labels
210    ListAll,
211}