1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
use clap::{Args, Subcommand};
#[derive(Subcommand, Debug)]
pub enum CaseCommand {
/// Create a new case and return its stable UID/ref.
Create(CaseCreateArgs),
/// List compact active case locators.
List,
/// Show a case's case.md (active or archived) without changing workspace state.
Show {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
},
/// Add a message to this existing case.
Add {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Message id to add.
message_id: String,
/// Short summary for this message in the case.
#[arg(long)]
summary: Option<String>,
/// Why this message belongs in this case; required by default.
#[arg(long)]
reason: Option<String>,
},
/// Move this case to another group.
Move {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Destination group.
group: String,
},
/// Rename this active case's human-readable name without changing its UID.
Rename {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// New human-readable case name.
#[arg(long)]
name: String,
/// Why this name better represents the case; required by default.
#[arg(long)]
reason: Option<String>,
},
/// Show or edit active case notes.
Notes {
#[command(subcommand)]
action: CaseNotesAction,
},
/// Archive this active case.
Archive {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Why this case is ready to archive; required by default.
#[arg(long)]
reason: Option<String>,
},
/// Reopen this case as active work without changing its tags.
Reopen {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Why this case should be reopened; required by default.
#[arg(long)]
reason: Option<String>,
},
/// Add a case organization tag.
Tag {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Case organization tag.
tag: String,
/// Why this tag is useful; required by default.
#[arg(long)]
reason: Option<String>,
},
/// Remove a case organization tag.
Untag {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Case organization tag.
tag: String,
/// Why this tag should be removed; required by default.
#[arg(long)]
reason: Option<String>,
},
/// Create, edit, validate, queue, or remove local case drafts.
Draft {
#[command(subcommand)]
action: CaseDraftAction,
},
/// Merge another case into this case.
Merge {
/// Primary case ref.
case_ref: String,
/// Case ref to merge into the primary case.
other_case_ref: String,
/// Why these cases should be merged; required by default.
#[arg(long)]
reason: Option<String>,
},
}
#[derive(Args, Debug, Clone)]
pub struct CaseCreateArgs {
/// Human-readable case name used in case.md and the directory suffix.
#[arg(long)]
pub name: String,
/// Destination group. Defaults to the configured default group.
#[arg(long)]
pub group: Option<String>,
/// Optional first message to add to the case.
#[arg(long)]
pub message: Option<String>,
/// Short summary for the first message.
#[arg(long)]
pub summary: Option<String>,
/// Why this case is being created.
#[arg(long)]
pub reason: Option<String>,
}
#[derive(Subcommand, Debug)]
pub enum CaseNotesAction {
/// Show notes markdown.
Show {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
},
/// Append text to notes markdown.
Append {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Markdown text to append.
#[arg(long)]
text: String,
},
/// Replace notes markdown with text.
Replace {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Markdown text to write.
#[arg(long)]
text: String,
},
}
#[derive(Subcommand, Debug)]
pub enum CaseDraftAction {
/// Scaffold a new outbound draft (not a reply) in this case.
New {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Recipient address. Repeatable.
#[arg(long = "to", required = true)]
to: Vec<String>,
/// Cc address. Repeatable.
#[arg(long = "cc")]
cc: Vec<String>,
/// Draft subject.
#[arg(long)]
subject: String,
/// Draft body text.
#[arg(long, conflicts_with = "body_file")]
body: Option<String>,
/// Path to a file whose contents become the draft body.
#[arg(long = "body-file")]
body_file: Option<String>,
},
/// Scaffold a reply draft to a message, prefilled and quoting the original.
Reply {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Message id in this case to reply to.
message_id: String,
/// Draft body text. Replaces the default reply template when provided.
#[arg(long, conflicts_with = "body_file")]
body: Option<String>,
/// Path to a file whose contents become the draft body.
#[arg(long = "body-file")]
body_file: Option<String>,
/// Reply to all original recipients (To and Cc), not just the sender.
#[arg(long)]
all: bool,
},
/// Change an existing editable draft in place.
Change {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Draft markdown file under the case drafts directory.
draft_name: String,
/// Replacement subject.
#[arg(long)]
subject: Option<String>,
/// Replacement To list. Repeatable; when provided it replaces all To recipients.
#[arg(long = "to")]
to: Vec<String>,
/// Replacement Cc list. Repeatable; when provided it replaces all Cc recipients.
#[arg(long = "cc", conflicts_with = "clear_cc")]
cc: Vec<String>,
/// Clear all Cc recipients.
#[arg(long)]
clear_cc: bool,
/// Replacement draft body text.
#[arg(long, conflicts_with = "body_file")]
body: Option<String>,
/// Path to a file whose contents replace the draft body.
#[arg(long = "body-file")]
body_file: Option<String>,
},
/// Show an existing draft in a review-friendly JSON shape.
Show {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Draft markdown file under the case drafts directory.
draft_name: String,
},
/// Validate a draft under the case drafts directory.
Validate {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Draft markdown file under the case drafts directory.
draft_name: String,
},
/// Queue this draft to be saved to the remote Drafts mailbox.
Save {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Draft markdown file under the case drafts directory.
draft_name: String,
},
/// Queue this draft to be sent and recorded in the case after push succeeds.
Send {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Draft markdown file under the case drafts directory.
draft_name: String,
},
/// Copy or reference a file and add it to a draft's attachments.
Attach {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Draft markdown file under the case drafts directory.
draft_name: String,
/// Local file path to attach.
path: String,
},
/// Remove a local draft and any queued outbound item for it.
Remove {
/// Case ref: cYYYYMMDDNNN or cYYYYMMDDNNN-any-suffix.
case_ref: String,
/// Draft markdown file under the case drafts directory.
draft_name: String,
/// Why this draft should be removed; required by default.
#[arg(long)]
reason: Option<String>,
},
}