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}