Skip to main content

ralph_workflow/cli/handlers/
dry_run.rs

1//! Dry run command handler.
2//!
3//! This module provides validation of Ralph setup without running any agents.
4
5use crate::checkpoint::{checkpoint_exists_with_workspace, load_checkpoint_with_workspace};
6use crate::config::Config;
7use crate::files::validate_prompt_md_with_workspace;
8use crate::language_detector::detect_stack_summary;
9use crate::logger::Logger;
10use crate::workspace::Workspace;
11use std::path::Path;
12
13/// Handle --dry-run command.
14///
15/// Validates the setup without running any agents:
16/// - Checks PROMPT.md exists and has required sections
17/// - Validates agent configuration
18/// - Reports detected project stack
19/// - Shows checkpoint status if available
20///
21/// # Arguments
22///
23/// * `logger` - Logger for status output
24/// * `_colors` - Color configuration (unused but kept for API consistency)
25/// * `config` - The current Ralph configuration
26/// * `developer_agent` - Name of the developer agent
27/// * `reviewer_agent` - Name of the reviewer agent
28/// * `repo_root` - Path to the repository root
29/// * `workspace` - Workspace for explicit file operations
30///
31/// # Returns
32///
33/// Returns `Ok(())` if validation passes, or an error if PROMPT.md validation fails.
34///
35/// # Errors
36///
37/// Returns error if the operation fails.
38pub fn handle_dry_run(
39    logger: &Logger,
40    _colors: crate::logger::Colors,
41    config: &Config,
42    developer_agent: &str,
43    reviewer_agent: &str,
44    repo_root: &Path,
45    workspace: &dyn Workspace,
46) -> anyhow::Result<()> {
47    logger.header("DRY RUN: Validation", crate::logger::Colors::cyan);
48
49    // Validate PROMPT.md using the utility function
50    // Dry run is non-interactive by definition
51    let validation =
52        validate_prompt_md_with_workspace(workspace, config.behavior.strict_validation, false);
53
54    // Report errors first
55    for err in &validation.errors {
56        logger.error(err);
57    }
58
59    // Report warnings
60    for warn in &validation.warnings {
61        logger.warn(&format!("{warn} (recommended)"));
62    }
63
64    // Bail if validation failed
65    if !validation.is_valid() {
66        anyhow::bail!("Dry run failed: PROMPT.md validation errors");
67    }
68
69    // Report successes
70    if validation.has_goal {
71        logger.success("PROMPT.md has Goal section");
72    }
73    if validation.has_acceptance {
74        logger.success("PROMPT.md has acceptance checks section");
75    }
76    if validation.is_perfect() {
77        logger.success("PROMPT.md validation passed with no warnings");
78    }
79
80    logger.success(&format!("Developer agent: {developer_agent}"));
81    logger.success(&format!("Reviewer agent: {reviewer_agent}"));
82    logger.success(&format!("Developer iterations: {}", config.developer_iters));
83    logger.success(&format!("Reviewer passes: {}", config.reviewer_reviews));
84
85    // Check for checkpoint
86    if checkpoint_exists_with_workspace(workspace) {
87        logger.info("Checkpoint found - can resume with --resume");
88        if let Ok(Some(cp)) = load_checkpoint_with_workspace(workspace) {
89            logger.info(&format!("  Phase: {}", cp.phase));
90            logger.info(&format!("  Progress: {}", cp.description()));
91            logger.info(&format!("  Saved at: {}", cp.timestamp));
92        }
93    }
94
95    // Detect stack - use the convenience function for simple display
96    logger.success(&format!(
97        "Detected stack: {}",
98        detect_stack_summary(repo_root)
99    ));
100
101    logger.success("Dry run validation complete");
102    Ok(())
103}