Skip to main content

ralph/cli/queue/
stats.rs

1//! Queue stats subcommand.
2//!
3//! Responsibilities:
4//! - Print task statistics (completion rate, avg duration, tag breakdown).
5//! - Include execution-history-based ETA estimates when available.
6//!
7//! Not handled:
8//! - Task execution or runner behavior.
9//! - Queue mutations.
10//!
11//! Invariants/assumptions:
12//! - Queue files are loaded and validated before reporting.
13//! - Execution history ETA is based on config defaults (runner, model, phases).
14
15use anyhow::Result;
16use clap::Args;
17use std::path::Path;
18
19use crate::cli::load_and_validate_queues_read_only;
20use crate::config::Resolved;
21use crate::queue;
22use crate::reports;
23
24use super::QueueReportFormat;
25
26/// Arguments for `ralph queue stats`.
27#[derive(Args)]
28pub struct QueueStatsArgs {
29    /// Filter by tag (repeatable, case-insensitive).
30    #[arg(long)]
31    pub tag: Vec<String>,
32
33    /// Output format.
34    #[arg(long, value_enum, default_value_t = QueueReportFormat::Text)]
35    pub format: QueueReportFormat,
36
37    /// Suppress size warning output.
38    #[arg(long, short)]
39    pub quiet: bool,
40}
41
42pub(crate) fn handle(resolved: &Resolved, args: QueueStatsArgs) -> Result<()> {
43    let (queue_file, done_file) = load_and_validate_queues_read_only(resolved, true)?;
44
45    // Check queue size and print warning if needed
46    if !args.quiet {
47        let size_threshold =
48            queue::size_threshold_or_default(resolved.config.queue.size_warning_threshold_kb);
49        let count_threshold =
50            queue::count_threshold_or_default(resolved.config.queue.task_count_warning_threshold);
51        if let Ok(result) = queue::check_queue_size(
52            &resolved.queue_path,
53            queue_file.tasks.len(),
54            size_threshold,
55            count_threshold,
56        ) {
57            queue::print_size_warning_if_needed(&result, args.quiet);
58        }
59    }
60
61    let done_ref = done_file
62        .as_ref()
63        .filter(|d| !d.tasks.is_empty() || resolved.done_path.exists());
64
65    // Get file size for display
66    let file_size_kb = std::fs::metadata(&resolved.queue_path)
67        .map(|m| m.len() / 1024)
68        .unwrap_or(0);
69
70    // Cache directory for execution history
71    let cache_dir: Option<&Path> = Some(&resolved.repo_root.join(".ralph/cache"));
72
73    reports::print_stats(
74        &queue_file,
75        done_ref,
76        &args.tag,
77        args.format.into(),
78        file_size_kb,
79        &resolved.config.agent,
80        cache_dir,
81    )?;
82    Ok(())
83}