Skip to main content

lean_ctx/cli/
init_cmd.rs

1use crate::hooks::to_bash_compatible_path;
2
3pub(crate) fn quiet_enabled() -> bool {
4    matches!(std::env::var("LEAN_CTX_QUIET"), Ok(v) if v.trim() == "1")
5}
6
7macro_rules! qprintln {
8    ($($t:tt)*) => {
9        if !quiet_enabled() {
10            println!($($t)*);
11        }
12    };
13}
14
15pub fn cmd_init(args: &[String]) {
16    let global = args.iter().any(|a| a == "--global" || a == "-g");
17    let dry_run = args.iter().any(|a| a == "--dry-run");
18    let no_hook = args.iter().any(|a| a == "--no-shell-hook")
19        || crate::core::config::Config::load().shell_hook_disabled_effective();
20
21    let agents: Vec<&str> = args
22        .windows(2)
23        .filter(|w| w[0] == "--agent")
24        .map(|w| w[1].as_str())
25        .collect();
26
27    if !agents.is_empty() {
28        for agent_name in &agents {
29            crate::hooks::install_agent_hook(agent_name, global);
30            if let Err(e) = crate::setup::configure_agent_mcp(agent_name) {
31                eprintln!("MCP config for '{agent_name}' not updated: {e}");
32            }
33        }
34        if !global {
35            crate::hooks::install_project_rules();
36        }
37        qprintln!("\nRun 'lean-ctx gain' after using some commands to see your savings.");
38        return;
39    }
40
41    let eval_shell = args
42        .iter()
43        .find(|a| matches!(a.as_str(), "bash" | "zsh" | "fish" | "powershell" | "pwsh"));
44    if let Some(shell) = eval_shell {
45        if !global {
46            super::shell_init::print_hook_stdout(shell);
47            return;
48        }
49    }
50
51    let shell_name = std::env::var("SHELL").unwrap_or_default();
52    let is_zsh = shell_name.contains("zsh");
53    let is_fish = shell_name.contains("fish");
54    let is_powershell = cfg!(windows) && shell_name.is_empty();
55
56    let binary = crate::core::portable_binary::resolve_portable_binary();
57
58    if dry_run {
59        let rc = if is_powershell {
60            "Documents/PowerShell/Microsoft.PowerShell_profile.ps1".to_string()
61        } else if is_fish {
62            "~/.config/fish/config.fish".to_string()
63        } else if is_zsh {
64            "~/.zshrc".to_string()
65        } else {
66            "~/.bashrc".to_string()
67        };
68        qprintln!("\nlean-ctx init --dry-run\n");
69        qprintln!("  Would modify:  {rc}");
70        qprintln!("  Would backup:  {rc}.lean-ctx.bak");
71        qprintln!("  Would alias:   git npm pnpm yarn cargo docker docker-compose kubectl");
72        qprintln!("                 gh pip pip3 ruff go golangci-lint eslint prettier tsc");
73        qprintln!("                 curl wget php composer (24 commands + k)");
74        let data_dir = crate::core::data_dir::lean_ctx_data_dir().map_or_else(
75            |_| "~/.config/lean-ctx/".to_string(),
76            |p| p.to_string_lossy().to_string(),
77        );
78        qprintln!("  Would create:  {data_dir}");
79        qprintln!("  Binary:        {binary}");
80        qprintln!("\n  Safety: aliases auto-fallback to original command if lean-ctx is removed.");
81        qprintln!("\n  Run without --dry-run to apply.");
82        return;
83    }
84
85    if no_hook {
86        qprintln!("Shell hook disabled (--no-shell-hook or shell_hook_disabled config).");
87        qprintln!("MCP tools remain active. Set LEAN_CTX_NO_HOOK=1 to disable at runtime.");
88    } else if is_powershell {
89        super::shell_init::init_powershell(&binary);
90    } else {
91        let bash_binary = to_bash_compatible_path(&binary);
92        if is_fish {
93            super::shell_init::init_fish(&bash_binary);
94        } else {
95            super::shell_init::init_posix(is_zsh, &bash_binary);
96        }
97    }
98
99    if let Ok(lean_dir) = crate::core::data_dir::lean_ctx_data_dir() {
100        if !lean_dir.exists() {
101            let _ = std::fs::create_dir_all(&lean_dir);
102            qprintln!("Created {}", lean_dir.display());
103        }
104    }
105
106    let rc = if is_powershell {
107        "$PROFILE"
108    } else if is_fish {
109        "config.fish"
110    } else if is_zsh {
111        ".zshrc"
112    } else {
113        ".bashrc"
114    };
115
116    qprintln!("\nlean-ctx init complete (24 aliases installed)");
117    qprintln!();
118    qprintln!("  Disable temporarily:  lean-ctx-off");
119    qprintln!("  Re-enable:            lean-ctx-on");
120    qprintln!("  Check status:         lean-ctx-status");
121    qprintln!("  Full uninstall:       lean-ctx uninstall");
122    qprintln!("  Diagnose issues:      lean-ctx doctor");
123    qprintln!("  Preview changes:      lean-ctx init --global --dry-run");
124    qprintln!();
125    if is_powershell {
126        qprintln!("  Restart PowerShell or run: . {rc}");
127    } else {
128        qprintln!("  Restart your shell or run: source ~/{rc}");
129    }
130    qprintln!();
131    qprintln!("For AI tool integration: lean-ctx init --agent <tool>");
132    qprintln!("  Supported: aider, amazonq, amp, antigravity, claude, cline, codex, copilot,");
133    qprintln!("    crush, cursor, emacs, gemini, hermes, jetbrains, kiro, neovim, opencode,");
134    qprintln!("    pi, qwen, roo, sublime, trae, verdent, windsurf");
135}
136
137pub fn cmd_init_quiet(args: &[String]) {
138    std::env::set_var("LEAN_CTX_QUIET", "1");
139    cmd_init(args);
140    std::env::remove_var("LEAN_CTX_QUIET");
141}