Skip to main content

ralph_workflow/cli/init/
smart_init.rs

1/// Handle the smart `--init` flag with a custom path resolver.
2///
3/// This function intelligently determines what the user wants to initialize:
4/// - If a value is provided and matches a known template name -> create PROMPT.md
5/// - If config doesn't exist and no template specified -> create config
6/// - If config exists but PROMPT.md doesn't -> prompt to create PROMPT.md
7/// - If both exist -> show helpful message about what's already set up
8///
9/// # Arguments
10///
11/// * `template_arg` - Optional template name from `--init=TEMPLATE`
12/// * `force` - If true, overwrite existing PROMPT.md without prompting
13/// * `colors` - Terminal color configuration for output
14/// * `env` - Path resolver for determining config file locations
15///
16/// # Returns
17///
18/// Returns `Ok(true)` if the flag was handled (program should exit after),
19/// or `Ok(false)` if not handled, or an error if initialization failed.
20pub fn handle_smart_init_with<R: ConfigEnvironment>(
21    template_arg: Option<&str>,
22    force: bool,
23    colors: Colors,
24    env: &R,
25) -> anyhow::Result<bool> {
26    let config_path = env
27        .unified_config_path()
28        .ok_or_else(|| anyhow::anyhow!("Cannot determine config directory (no home directory)"))?;
29    let prompt_path = env.prompt_path();
30    handle_smart_init_at_paths_with_env(
31        template_arg,
32        force,
33        colors,
34        &config_path,
35        &prompt_path,
36        env,
37    )
38}
39
40/// Handle the smart `--init` flag using the default path resolver.
41///
42/// This is a convenience wrapper that uses [`RealConfigEnvironment`] internally.
43pub fn handle_smart_init(
44    template_arg: Option<&str>,
45    force: bool,
46    colors: Colors,
47) -> anyhow::Result<bool> {
48    handle_smart_init_with(template_arg, force, colors, &RealConfigEnvironment)
49}
50
51fn handle_smart_init_at_paths_with_env<R: ConfigEnvironment>(
52    template_arg: Option<&str>,
53    force: bool,
54    colors: Colors,
55    config_path: &std::path::Path,
56    prompt_path: &Path,
57    env: &R,
58) -> anyhow::Result<bool> {
59    let config_exists = env.file_exists(config_path);
60    let prompt_exists = env.file_exists(prompt_path);
61
62    // If a template name is provided (non-empty), treat it as --init <template>
63    if let Some(template_name) = template_arg {
64        if !template_name.is_empty() {
65            return handle_init_template_arg_at_path_with_env(
66                template_name,
67                prompt_path,
68                force,
69                colors,
70                env,
71            );
72        }
73        // Empty string means --init was used without a value, fall through to smart inference
74    }
75
76    // No template provided - use smart inference based on current state
77    handle_init_state_inference_with_env(
78        config_path,
79        prompt_path,
80        config_exists,
81        prompt_exists,
82        force,
83        colors,
84        env,
85    )
86}
87
88/// Handle --init when both config and PROMPT.md exist.
89fn handle_init_both_exist(
90    config_path: &std::path::Path,
91    prompt_path: &Path,
92    force: bool,
93    colors: Colors,
94) -> bool {
95    // If force is set, show that they can use --force-overwrite to overwrite
96    if force {
97        println!(
98            "{}Note:{} --force-overwrite has no effect when not specifying a Work Guide.",
99            colors.yellow(),
100            colors.reset()
101        );
102        println!("Use: ralph --init <work-guide> --force-overwrite  to overwrite PROMPT.md");
103        println!();
104    }
105
106    println!("{}Setup complete!{}", colors.green(), colors.reset());
107    println!();
108    println!(
109        "  Config: {}{}{}",
110        colors.dim(),
111        config_path.display(),
112        colors.reset()
113    );
114    println!(
115        "  PROMPT: {}{}{}",
116        colors.dim(),
117        prompt_path.display(),
118        colors.reset()
119    );
120    println!();
121    println!("You're ready to run Ralph:");
122    println!("  ralph \"your commit message\"");
123    println!();
124    println!("Other commands:");
125    println!("  ralph --list-work-guides   # Show all Work Guides");
126    println!("  ralph --init <work-guide> --force-overwrite  # Overwrite PROMPT.md");
127    true
128}