mi6_cli/commands/
disable.rs

1//! Disable command - remove mi6 hooks from AI coding frameworks.
2
3use anyhow::{Context, Result};
4
5use mi6_core::{FrameworkAdapter, FrameworkResolutionMode, resolve_frameworks};
6
7use crate::display::StderrColors;
8
9/// Options for the disable command
10pub struct DisableOptions {
11    /// Frameworks to disable (empty = all that have mi6 enabled)
12    pub frameworks: Vec<String>,
13    /// Remove from project config instead of global
14    pub local: bool,
15    /// Remove from project local config
16    pub settings_local: bool,
17    /// Print what would be removed without modifying files
18    pub print: bool,
19}
20
21/// Run the disable command.
22pub fn run_disable(opts: DisableOptions) -> Result<()> {
23    let colors = StderrColors::new();
24
25    // Resolve which frameworks to disable (auto-detect enabled hooks if none specified)
26    let mode = FrameworkResolutionMode::Active {
27        local: opts.local,
28        settings_local: opts.settings_local,
29    };
30    let adapters =
31        resolve_frameworks(&opts.frameworks, Some(mode)).map_err(|e| anyhow::anyhow!("{}", e))?;
32
33    for adapter in adapters {
34        disable_framework(adapter, &opts, &colors)?;
35    }
36
37    Ok(())
38}
39
40/// Disable mi6 for a single framework
41fn disable_framework(
42    adapter: &dyn FrameworkAdapter,
43    opts: &DisableOptions,
44    colors: &StderrColors,
45) -> Result<()> {
46    // Check if mi6 is enabled for this framework
47    if !adapter.has_mi6_hooks(opts.local, opts.settings_local) {
48        eprintln!(
49            "{}mi6 is not enabled for {}{}",
50            colors.yellow,
51            adapter.name(),
52            colors.reset
53        );
54        return Ok(());
55    }
56
57    let settings_path = adapter
58        .settings_path(opts.local, opts.settings_local)
59        .context("failed to determine settings path")?;
60
61    if opts.print {
62        eprintln!(
63            "{}Would disable{} mi6 for {}{}{}:",
64            colors.cyan,
65            colors.reset,
66            colors.bold,
67            adapter.name(),
68            colors.reset
69        );
70        // For plugin-based frameworks, show plugin directory; otherwise show settings file
71        if adapter.name() == "claude" {
72            eprintln!("  Would remove plugin: {}", settings_path.display());
73        } else {
74            eprintln!("  Would modify: {}", settings_path.display());
75        }
76    } else {
77        eprintln!("Disabling mi6 for {}...", adapter.name());
78
79        // Use uninstall_hooks which handles both config-based and plugin-based frameworks
80        let uninstall_result = adapter
81            .uninstall_hooks(opts.local, opts.settings_local)
82            .context("failed to uninstall hooks")?;
83
84        // Display each command that was run with done indicator
85        for cmd in &uninstall_result.commands_run {
86            eprintln!(
87                "  Running: {}{}{}... {}done{}",
88                colors.bold_white, cmd, colors.reset, colors.bold_green, colors.reset
89            );
90        }
91
92        if adapter.name() == "claude" {
93            // Show plugin directory for Claude
94            eprintln!(
95                "  Removing plugin from: {}{}{}... {}done{}",
96                colors.bold_white,
97                settings_path.display(),
98                colors.reset,
99                colors.bold_green,
100                colors.reset
101            );
102        } else {
103            eprintln!(
104                "  Removing hooks from: {}{}{}... {}done{}",
105                colors.bold_white,
106                settings_path.display(),
107                colors.reset,
108                colors.bold_green,
109                colors.reset
110            );
111        }
112    }
113
114    Ok(())
115}
116
117/// Disable mi6 hooks for a single framework silently (no output).
118///
119/// Used by the uninstall command when disabling all frameworks.
120pub fn disable_framework_silent(adapter: &dyn FrameworkAdapter) -> Result<()> {
121    // Use uninstall_hooks which handles both config-based and plugin-based frameworks
122    adapter
123        .uninstall_hooks(false, false)
124        .context("failed to uninstall hooks")?;
125    Ok(())
126}