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.
20///
21/// # Errors
22///
23/// Returns error if the operation fails.
24pub fn handle_smart_init_with<R: ConfigEnvironment>(
25    template_arg: Option<&str>,
26    force: bool,
27    colors: Colors,
28    env: &R,
29) -> anyhow::Result<bool> {
30    let config_path = env
31        .unified_config_path()
32        .ok_or_else(|| anyhow::anyhow!("Cannot determine config directory (no home directory)"))?;
33    let prompt_path = env.prompt_path();
34    handle_smart_init_at_paths_with_env(
35        template_arg,
36        force,
37        colors,
38        &config_path,
39        &prompt_path,
40        env,
41    )
42}
43
44/// Handle the smart `--init` flag using the default path resolver.
45///
46/// This is a convenience wrapper that uses [`RealConfigEnvironment`] internally.
47///
48/// # Errors
49///
50/// Returns error if the operation fails.
51pub fn handle_smart_init(
52    template_arg: Option<&str>,
53    force: bool,
54    colors: Colors,
55) -> anyhow::Result<bool> {
56    handle_smart_init_with(template_arg, force, colors, &RealConfigEnvironment)
57}
58
59fn handle_smart_init_at_paths_with_env<R: ConfigEnvironment>(
60    template_arg: Option<&str>,
61    force: bool,
62    colors: Colors,
63    config_path: &std::path::Path,
64    prompt_path: &Path,
65    env: &R,
66) -> anyhow::Result<bool> {
67    let config_exists = env.file_exists(config_path);
68    let prompt_exists = env.file_exists(prompt_path);
69
70    // If a template name is provided (non-empty), treat it as --init <template>
71    if let Some(template_name) = template_arg {
72        if !template_name.is_empty() {
73            return handle_init_template_arg_at_path_with_env(
74                template_name,
75                prompt_path,
76                force,
77                colors,
78                env,
79            );
80        }
81        // Empty string means --init was used without a value, fall through to smart inference
82    }
83
84    // No template provided - use smart inference based on current state
85    handle_init_state_inference_with_env(
86        config_path,
87        prompt_path,
88        config_exists,
89        prompt_exists,
90        force,
91        colors,
92        env,
93    )
94}