Skip to main content

ralph_workflow/app/runner/pipeline_execution/entry_points/
main.rs

1// Main entry point functions for the pipeline.
2//
3// This module contains:
4// - run: Main application entry point
5// - run_with_config: Test-only entry point with pre-built Config
6// - run_with_config_and_resolver: Test-only entry point with custom path resolver
7// - run_with_config_and_handlers: Test-only entry point with both handlers
8// - RunWithHandlersParams: Parameters for test entry points
9
10/// Main application entry point.
11///
12/// Orchestrates the entire Ralph pipeline:
13/// 1. Configuration initialization
14/// 2. Agent validation
15/// 3. Plumbing commands (if requested)
16/// 4. Development phase
17/// 5. Review & fix phase
18/// 6. Final validation
19/// 7. Commit phase
20///
21/// # Arguments
22///
23/// * `args` - The parsed CLI arguments
24/// * `executor` - Process executor for external process execution
25///
26/// # Returns
27///
28/// Returns `Ok(())` on success or an error if any phase fails.
29pub fn run(args: Args, executor: std::sync::Arc<dyn ProcessExecutor>) -> anyhow::Result<()> {
30    let colors = Colors::new();
31    let logger = Logger::new(colors);
32
33    // Set working directory first if override is provided
34    // This ensures all subsequent operations (including config init) use the correct directory
35    if let Some(ref override_dir) = args.working_dir_override {
36        std::env::set_current_dir(override_dir)?;
37    }
38
39    // Initialize configuration and agent registry
40    let Some(init_result) = initialize_config(&args, colors, &logger)? else {
41        return Ok(()); // Early exit (--init/--init-global)
42    };
43
44    let config_init::ConfigInitResult {
45        config,
46        registry,
47        config_path,
48        config_sources,
49    } = init_result;
50
51    // Resolve required agent names
52    let validated = resolve_required_agents(&config)?;
53    let developer_agent = validated.developer_agent;
54    let reviewer_agent = validated.reviewer_agent;
55
56    // Handle listing commands (these can run without git repo)
57    if handle_listing_commands(&args, &registry, colors) {
58        return Ok(());
59    }
60
61    // Handle --diagnose
62    if args.recovery.diagnose {
63        let diagnose_workspace = crate::workspace::WorkspaceFs::new(
64            std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
65        );
66        handle_diagnose(
67            colors,
68            &config,
69            &registry,
70            &config_path,
71            &config_sources,
72            &*executor,
73            &diagnose_workspace,
74        );
75        return Ok(());
76    }
77
78    // Validate agent chains
79    validate_agent_chains(&registry, colors);
80
81    // Create effect handler for production operations
82    let mut handler = effect_handler::RealAppEffectHandler::new();
83
84    // Get repo root early for workspace creation (needed by plumbing commands)
85    // This uses the same logic as setup_working_dir_via_handler but captures the repo_root.
86    let early_repo_root =
87        discover_repo_root_for_workspace(args.working_dir_override.as_deref(), &mut handler)?;
88
89    // Create workspace for plumbing commands (and later for the full pipeline)
90    let workspace: std::sync::Arc<dyn crate::workspace::Workspace> =
91        std::sync::Arc::new(crate::workspace::WorkspaceFs::new(early_repo_root));
92
93    // Handle plumbing commands with workspace support
94    if handle_plumbing_commands(
95        &args,
96        &logger,
97        colors,
98        &mut handler,
99        Some(workspace.as_ref()),
100    )? {
101        return Ok(());
102    }
103
104    // Validate agents and set up git repo and PROMPT.md
105    // Note: repo_root is discovered again here (same as early_repo_root) but also
106    // does additional setup like PROMPT.md creation that plumbing commands don't need
107    let Some(repo_root) = validate_and_setup_agents(
108        AgentSetupParams {
109            config: &config,
110            registry: &registry,
111            developer_agent: &developer_agent,
112            reviewer_agent: &reviewer_agent,
113            config_path: &config_path,
114            colors,
115            logger: &logger,
116            working_dir_override: args.working_dir_override.as_deref(),
117        },
118        &mut handler,
119    )?
120    else {
121        return Ok(());
122    };
123
124    // Prepare pipeline context or exit early
125    // Note: Reuse workspace created earlier (same repo root)
126    (prepare_pipeline_or_exit(PipelinePreparationParams {
127        args,
128        config,
129        registry,
130        developer_agent,
131        reviewer_agent,
132        repo_root,
133        logger,
134        colors,
135        executor,
136        handler: &mut handler,
137        workspace,
138    })?)
139    .map_or_else(|| Ok(()), |ctx| run_pipeline(&ctx))
140}
141