1use clap::ValueEnum;
19
20use crate::{contracts, reports};
21
22#[derive(Clone, Copy, Debug, ValueEnum)]
23#[clap(rename_all = "snake_case")]
24pub enum StatusArg {
25 Draft,
27 Todo,
29 Doing,
31 Done,
33 Rejected,
35}
36
37#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
38#[clap(rename_all = "snake_case")]
39pub enum QueueShowFormat {
40 Json,
42 Compact,
44}
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
47#[clap(rename_all = "snake_case")]
48pub enum QueueListFormat {
49 Compact,
51 Long,
53 Json,
55}
56
57#[derive(Clone, Copy, Debug, ValueEnum)]
58#[clap(rename_all = "snake_case")]
59pub enum QueueReportFormat {
60 Text,
62 Json,
64}
65
66#[derive(Clone, Copy, Debug, ValueEnum)]
67#[clap(rename_all = "snake_case")]
68pub enum QueueExportFormat {
69 Csv,
71 Tsv,
73 Json,
75 Md,
77 Gh,
79}
80
81#[derive(Clone, Copy, Debug, ValueEnum)]
83#[clap(rename_all = "snake_case")]
84pub enum QueueImportFormat {
85 Csv,
87 Tsv,
89 Json,
91}
92
93#[derive(Clone, Copy, Debug, ValueEnum)]
98#[clap(rename_all = "snake_case")]
99pub enum QueueSortBy {
100 Priority,
102}
103
104impl std::fmt::Display for QueueSortBy {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 match self {
107 QueueSortBy::Priority => f.write_str("priority"),
108 }
109 }
110}
111
112#[derive(Clone, Copy, Debug, ValueEnum)]
117#[clap(rename_all = "snake_case")]
118pub enum QueueListSortBy {
119 Priority,
121 CreatedAt,
123 UpdatedAt,
125 StartedAt,
127 ScheduledStart,
129 Status,
131 Title,
133}
134
135impl std::fmt::Display for QueueListSortBy {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 match self {
138 QueueListSortBy::Priority => f.write_str("priority"),
139 QueueListSortBy::CreatedAt => f.write_str("created_at"),
140 QueueListSortBy::UpdatedAt => f.write_str("updated_at"),
141 QueueListSortBy::StartedAt => f.write_str("started_at"),
142 QueueListSortBy::ScheduledStart => f.write_str("scheduled_start"),
143 QueueListSortBy::Status => f.write_str("status"),
144 QueueListSortBy::Title => f.write_str("title"),
145 }
146 }
147}
148
149#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
150pub enum QueueSortOrder {
151 Ascending,
152 Descending,
153}
154
155impl QueueSortOrder {
156 pub(crate) fn is_descending(self) -> bool {
157 matches!(self, QueueSortOrder::Descending)
158 }
159}
160
161impl std::fmt::Display for QueueSortOrder {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 match self {
164 QueueSortOrder::Ascending => f.write_str("ascending"),
165 QueueSortOrder::Descending => f.write_str("descending"),
166 }
167 }
168}
169
170impl From<StatusArg> for contracts::TaskStatus {
171 fn from(value: StatusArg) -> Self {
172 match value {
173 StatusArg::Draft => contracts::TaskStatus::Draft,
174 StatusArg::Todo => contracts::TaskStatus::Todo,
175 StatusArg::Doing => contracts::TaskStatus::Doing,
176 StatusArg::Done => contracts::TaskStatus::Done,
177 StatusArg::Rejected => contracts::TaskStatus::Rejected,
178 }
179 }
180}
181
182impl From<QueueReportFormat> for reports::ReportFormat {
183 fn from(value: QueueReportFormat) -> Self {
184 match value {
185 QueueReportFormat::Text => reports::ReportFormat::Text,
186 QueueReportFormat::Json => reports::ReportFormat::Json,
187 }
188 }
189}
190
191pub(crate) fn task_eta_display(
201 resolved: &crate::config::Resolved,
202 calculator: &crate::eta_calculator::EtaCalculator,
203 task: &crate::contracts::Task,
204) -> String {
205 use crate::contracts::TaskStatus;
206 use crate::eta_calculator::format_eta;
207 use crate::runner::resolve_agent_settings;
208
209 if !matches!(task.status, TaskStatus::Draft | TaskStatus::Todo) {
211 return "n/a".to_string();
212 }
213
214 let empty_cli_patch = crate::contracts::RunnerCliOptionsPatch::default();
216 let settings = match resolve_agent_settings(
217 None, None, None, &empty_cli_patch,
221 task.agent.as_ref(),
222 &resolved.config.agent,
223 ) {
224 Ok(s) => s,
225 Err(_) => return "n/a".to_string(),
226 };
227
228 let phase_count = resolved.config.agent.phases.unwrap_or(3);
229
230 match calculator.estimate_new_task_total(
232 settings.runner.as_str(),
233 settings.model.as_str(),
234 phase_count,
235 ) {
236 Some(estimate) => format_eta(estimate.remaining),
237 None => "n/a".to_string(),
238 }
239}