Skip to main content

ralph/cli/queue/
aging.rs

1//! Queue aging subcommand.
2//!
3//! Responsibilities:
4//! - Handle `ralph queue aging` command to show task aging buckets.
5//!
6//! Not handled here:
7//! - Actual aging computation (see crate::reports::aging).
8//! - Output formatting.
9//!
10//! Invariants/assumptions:
11//! - Queue files are validated before processing.
12
13use anyhow::Result;
14use clap::Args;
15
16use crate::cli::load_and_validate_queues_read_only;
17use crate::config::Resolved;
18use crate::contracts::TaskStatus;
19use crate::reports;
20
21use super::{QueueReportFormat, StatusArg};
22
23/// Arguments for `ralph queue aging`.
24#[derive(Args)]
25#[command(
26    about = "Show task aging buckets to identify stale work",
27    after_long_help = "Examples:\n  ralph queue aging\n  ralph queue aging --format json\n  ralph queue aging --status todo --status doing\n  ralph queue aging --status doing"
28)]
29pub struct QueueAgingArgs {
30    /// Filter by status (repeatable). Default: todo, doing.
31    #[arg(long, value_enum)]
32    pub status: Vec<StatusArg>,
33
34    /// Output format.
35    #[arg(long, value_enum, default_value_t = QueueReportFormat::Text)]
36    pub format: QueueReportFormat,
37}
38
39pub(crate) fn handle(resolved: &Resolved, args: QueueAgingArgs) -> Result<()> {
40    let (queue_file, _done_file) = load_and_validate_queues_read_only(resolved, false)?;
41
42    let statuses: Vec<TaskStatus> = if args.status.is_empty() {
43        vec![TaskStatus::Todo, TaskStatus::Doing]
44    } else {
45        args.status.into_iter().map(Into::into).collect()
46    };
47
48    let thresholds = reports::AgingThresholds::from_queue_config(&resolved.config.queue)?;
49    reports::print_aging(&queue_file, &statuses, thresholds, args.format.into())?;
50    Ok(())
51}