tix/cli/cli_cycle_schedule.rs
1#[allow(clippy::wildcard_imports)]
2use super::*;
3
4#[derive(Subcommand)]
5pub enum CycleCommand {
6 Create {
7 #[arg(long)]
8 name: Option<String>,
9 #[arg(long)]
10 description: Option<String>,
11 #[arg(long = "start-date")]
12 start_date: Option<String>,
13 #[arg(long = "due-date")]
14 due_date: Option<String>,
15 },
16 List,
17 Edit {
18 #[arg(long)]
19 name: String,
20 #[arg(long = "new-name")]
21 new_name: Option<String>,
22 #[arg(long)]
23 description: Option<String>,
24 #[arg(long = "start-date")]
25 start_date: Option<String>,
26 #[arg(long = "due-date")]
27 due_date: Option<String>,
28 },
29 Delete {
30 #[arg(long)]
31 name: String,
32 #[arg(long)]
33 yes: bool,
34 },
35 /// Manage repeating cycle schedules (`[cycle_schedules.<id>]`)
36 ///
37 /// A schedule is a stable id (the registry key) with a mutable display name;
38 /// generated cycle instances are ordinary cycle records this family creates
39 /// idempotently from the schedule's definition. Detection is read-only; every
40 /// mutation requires `--confirm`.
41 Schedule {
42 #[command(subcommand)]
43 command: CycleScheduleCommand,
44 },
45}
46
47/// The `tix cycle schedule` subcommands (mission
48/// `repeating-cycle-schedules-01M3C7W1`, WP06).
49///
50/// The surface contract's spelling (`contracts/cli-surface.md`): a schedule
51/// namespace under `tix cycle`, with stable-ID selectors, explicit date/timezone
52/// context and confirmed mutations. This enum is a thin adapter — the schedule
53/// record, the read model, evaluation, generation and the lifecycle all live in
54/// `crate::cycle_schedule`; nothing here re-derives a cadence, a cursor or a
55/// History entry.
56#[derive(Debug, Clone, Subcommand)]
57pub enum CycleScheduleCommand {
58 /// List schedules, one tab-separated row per schedule
59 ///
60 /// Columns: `id`, `name`, `state`, `cadence`, `duration`, `start_date`,
61 /// `look_ahead`, `next_sequence`, `generated`.
62 List,
63 /// Show one schedule: identity, cadence, duration, cursor and its instances
64 Show {
65 /// Stable schedule id, or its unique display name
66 #[arg(value_name = "SCHEDULE")]
67 schedule: String,
68 },
69 /// Define a new repeating schedule; validated before persistence, requires `--confirm`
70 Create(CycleScheduleCreateArgs),
71 /// Change a schedule's fields, keeping its stable id; requires `--confirm`
72 ///
73 /// Only the flags you name change; the rest of the record (including its
74 /// generation cursor and preserved metadata) is carried over.
75 Edit {
76 /// Stable schedule id, or its unique display name
77 #[arg(value_name = "SCHEDULE")]
78 schedule: String,
79 #[command(flatten)]
80 args: CycleScheduleEditArgs,
81 /// Confirm the change without prompting
82 #[arg(long)]
83 confirm: bool,
84 },
85 /// Delete a schedule's registry entry; requires `--confirm`
86 ///
87 /// The generated cycles it created and their snapshots are **not** deleted:
88 /// they keep their schedule reference, which then reads as a diagnosable
89 /// missing schedule, so nothing is destroyed by deleting a definition.
90 Delete {
91 /// Stable schedule id, or its unique display name
92 #[arg(value_name = "SCHEDULE")]
93 schedule: String,
94 /// Confirm the deletion without prompting
95 #[arg(long)]
96 confirm: bool,
97 },
98 /// Report ended/due/look-ahead warnings, read-only
99 ///
100 /// Prints the warnings and the explicit decisions each accepts. It writes
101 /// nothing: no file, no cursor move, no History entry.
102 Detect {
103 /// Evaluate against this `YYYY-MM-DD` date instead of today
104 #[arg(long, value_name = "YYYY-MM-DD")]
105 date: Option<String>,
106 },
107 /// Create the schedule's future cycles; idempotent, requires `--confirm`
108 ///
109 /// A repeated call under the same stable keys is a no-op, never a duplicate.
110 Generate {
111 /// Stable schedule id, or its unique display name
112 #[arg(value_name = "SCHEDULE")]
113 schedule: String,
114 /// Generate every candidate whose start date is on or before this date
115 #[arg(long, value_name = "YYYY-MM-DD")]
116 through: Option<String>,
117 /// Confirm the generation without prompting
118 #[arg(long)]
119 confirm: bool,
120 },
121 /// Close an instance: capture its immutable snapshot and mark it closed
122 Close {
123 /// Stable schedule id, or its unique display name
124 #[arg(value_name = "SCHEDULE")]
125 schedule: String,
126 #[command(flatten)]
127 args: CycleScheduleReasonArgs,
128 },
129 /// Reopen a closed instance: restore `active` and append one History event
130 ///
131 /// The closed cycle's capacity snapshot is **not** rewritten: it stays the
132 /// immutable evidence the close captured, and the appended `cycle_reopened`
133 /// event names it. Reopening an open instance is a no-op, and the action
134 /// requires both a reason and the instance it names.
135 Reopen {
136 /// Stable schedule id, or its unique display name
137 #[arg(value_name = "SCHEDULE")]
138 schedule: String,
139 #[command(flatten)]
140 args: CycleScheduleReasonArgs,
141 },
142 /// Push an instance's due date out by a cadence period
143 Extend {
144 /// Stable schedule id, or its unique display name
145 #[arg(value_name = "SCHEDULE")]
146 schedule: String,
147 #[command(flatten)]
148 args: CycleScheduleExtendArgs,
149 },
150 /// Record a sequence as skipped so it is never regenerated
151 Skip {
152 /// Stable schedule id, or its unique display name
153 #[arg(value_name = "SCHEDULE")]
154 schedule: String,
155 #[command(flatten)]
156 args: CycleScheduleReasonArgs,
157 },
158 /// Pause a schedule and its non-terminal instances
159 Pause {
160 /// Stable schedule id, or its unique display name
161 #[arg(value_name = "SCHEDULE")]
162 schedule: String,
163 #[command(flatten)]
164 args: CycleScheduleLifecycleArgs,
165 },
166 /// Resume a paused schedule and its instances
167 Resume {
168 /// Stable schedule id, or its unique display name
169 #[arg(value_name = "SCHEDULE")]
170 schedule: String,
171 #[command(flatten)]
172 args: CycleScheduleLifecycleArgs,
173 },
174 /// Re-derive every future instance's dates from the schedule's definition
175 AdjustFuture {
176 /// Stable schedule id, or its unique display name
177 #[arg(value_name = "SCHEDULE")]
178 schedule: String,
179 #[command(flatten)]
180 args: CycleScheduleReasonArgs,
181 },
182 /// Close a warning without deciding anything; nothing is written
183 Ignore {
184 /// Stable schedule id, or its unique display name
185 #[arg(value_name = "SCHEDULE")]
186 schedule: String,
187 #[command(flatten)]
188 args: CycleScheduleLifecycleArgs,
189 },
190}
191
192/// The flags that define a schedule (`tix cycle schedule create`).
193#[derive(Debug, Clone, Args)]
194pub struct CycleScheduleCreateArgs {
195 /// Stable schedule id (letters, digits, `-`, `_`, `:`); never reused
196 #[arg(long, value_name = "ID")]
197 pub id: String,
198 /// Display label, unique case-insensitively within the registry
199 #[arg(long, value_name = "NAME")]
200 pub name: String,
201 /// Cadence family: `daily`, `weekly`, `monthly` or `interval`
202 ///
203 /// `interval` is the family that carries `--unit`; the other three are the
204 /// calendar-step families and refuse a unit.
205 #[arg(long, value_name = "KIND")]
206 pub cadence: String,
207 /// How many cadence units between cycle starts (1-1000; absent means 1)
208 #[arg(long, value_name = "N")]
209 pub interval: Option<u32>,
210 /// The unit an `interval` cadence counts in: `days`, `weeks`, `months`
211 #[arg(long, value_name = "UNIT")]
212 pub unit: Option<String>,
213 /// How long one cycle lasts, as a positive count
214 #[arg(long, value_name = "N")]
215 pub duration: u32,
216 /// The duration's unit: `days`, `weeks`, `months`
217 #[arg(long = "duration-unit", value_name = "UNIT")]
218 pub duration_unit: String,
219 /// The schedule's stable anchor, a `YYYY-MM-DD` calendar date
220 #[arg(long = "start-date", value_name = "YYYY-MM-DD")]
221 pub start_date: String,
222 /// Fixed UTC offset the schedule is expressed in: `UTC` or `±HH:MM`
223 ///
224 /// `allow_hyphen_values` so a west-of-UTC offset (`-05:00`) reaches the
225 /// validator instead of being swallowed by clap as an unknown flag.
226 #[arg(long, value_name = "TZ", allow_hyphen_values = true)]
227 pub timezone: String,
228 /// How many future cycles to consider beyond the current one (0 when absent)
229 #[arg(long = "look-ahead", value_name = "N")]
230 pub look_ahead: Option<u32>,
231 /// Confirm the creation without prompting
232 #[arg(long)]
233 pub confirm: bool,
234}
235
236/// What `tix cycle schedule edit` may change. Every field is optional; only the
237/// named ones change, so a partial edit keeps the rest of the record.
238#[derive(Debug, Clone, Args)]
239pub struct CycleScheduleEditArgs {
240 /// New display label
241 #[arg(long, value_name = "NAME")]
242 pub name: Option<String>,
243 /// New cadence family: `daily`, `weekly`, `monthly` or `interval`
244 #[arg(long, value_name = "KIND")]
245 pub cadence: Option<String>,
246 /// New cadence interval (1-1000)
247 #[arg(long, value_name = "N")]
248 pub interval: Option<u32>,
249 /// New cadence unit (only meaningful for the `interval` family)
250 #[arg(long, value_name = "UNIT")]
251 pub unit: Option<String>,
252 /// New duration count
253 #[arg(long, value_name = "N")]
254 pub duration: Option<u32>,
255 /// New duration unit
256 #[arg(long = "duration-unit", value_name = "UNIT")]
257 pub duration_unit: Option<String>,
258 /// New anchor date, `YYYY-MM-DD`
259 #[arg(long = "start-date", value_name = "YYYY-MM-DD")]
260 pub start_date: Option<String>,
261 /// New timezone: `UTC` or `±HH:MM` (`allow_hyphen_values` for `-05:00`)
262 #[arg(long, value_name = "TZ", allow_hyphen_values = true)]
263 pub timezone: Option<String>,
264 /// New look-ahead count
265 #[arg(long = "look-ahead", value_name = "N")]
266 pub look_ahead: Option<u32>,
267}
268
269/// The flags every `tix cycle schedule` lifecycle action shares.
270#[derive(Debug, Clone, Args)]
271pub struct CycleScheduleLifecycleArgs {
272 /// Target instance, `<schedule-id>:<sequence>` (e.g. `cs-sprint:000001`)
273 #[arg(long, value_name = "CYCLE")]
274 pub cycle: Option<String>,
275 /// Select the instance by its start date, `YYYY-MM-DD`
276 #[arg(long, value_name = "YYYY-MM-DD")]
277 pub from: Option<String>,
278 /// Confirm the action without prompting
279 #[arg(long)]
280 pub confirm: bool,
281}
282
283/// The lifecycle flags plus the reason the recording actions require.
284#[derive(Debug, Clone, Args)]
285pub struct CycleScheduleReasonArgs {
286 #[command(flatten)]
287 pub lifecycle: CycleScheduleLifecycleArgs,
288 /// Why; recorded in the instance's History
289 #[arg(long, value_name = "TEXT")]
290 pub reason: Option<String>,
291}
292
293/// `tix cycle schedule extend`'s flags: the reason plus the period count.
294#[derive(Debug, Clone, Args)]
295pub struct CycleScheduleExtendArgs {
296 #[command(flatten)]
297 pub reason: CycleScheduleReasonArgs,
298 /// How many cadence periods to extend by; the shared lifecycle supports 1
299 #[arg(long, value_name = "N")]
300 pub by: Option<u32>,
301}