Skip to main content

chub_cli/commands/
profile.rs

1use clap::{Args, Subcommand};
2use owo_colors::OwoColorize;
3
4use chub_core::team::profiles;
5
6use crate::output;
7
8#[derive(Args)]
9pub struct ProfileArgs {
10    #[command(subcommand)]
11    command: ProfileCommand,
12}
13
14#[derive(Subcommand)]
15pub enum ProfileCommand {
16    /// Activate a profile for this session
17    Use(ProfileUseArgs),
18    /// List available profiles
19    List,
20    /// Show the currently active profile
21    Current,
22}
23
24#[derive(Args)]
25pub struct ProfileUseArgs {
26    /// Profile name (or "none" to clear)
27    name: String,
28}
29
30pub fn run(args: ProfileArgs, json: bool) {
31    match args.command {
32        ProfileCommand::Use(use_args) => run_use(use_args, json),
33        ProfileCommand::List => run_list(json),
34        ProfileCommand::Current => run_current(json),
35    }
36}
37
38fn run_use(args: ProfileUseArgs, json: bool) {
39    let name = if args.name == "none" || args.name == "off" || args.name == "clear" {
40        None
41    } else {
42        Some(args.name.as_str())
43    };
44
45    match profiles::set_active_profile(name) {
46        Ok(()) => {
47            if json {
48                println!(
49                    "{}",
50                    serde_json::json!({
51                        "status": "ok",
52                        "profile": name,
53                    })
54                );
55            } else if let Some(n) = name {
56                output::success(&format!("Profile set to: {}", n.bold()));
57                // Show resolved profile info
58                if let Ok(resolved) = profiles::resolve_profile(n) {
59                    if !resolved.pins.is_empty() {
60                        eprintln!("  Pins: {}", resolved.pins.join(", ").dimmed());
61                    }
62                    if !resolved.context.is_empty() {
63                        eprintln!("  Context: {}", resolved.context.join(", ").dimmed());
64                    }
65                    if !resolved.rules.is_empty() {
66                        eprintln!("  Rules: {} rule(s)", resolved.rules.len());
67                    }
68                }
69            } else {
70                output::success("Profile cleared.");
71            }
72        }
73        Err(e) => {
74            output::error(&e.to_string(), json);
75            std::process::exit(1);
76        }
77    }
78}
79
80fn run_list(json: bool) {
81    let profiles = profiles::list_profiles();
82    let active = profiles::get_active_profile();
83
84    if json {
85        let items: Vec<serde_json::Value> = profiles
86            .iter()
87            .map(|(name, desc)| {
88                serde_json::json!({
89                    "name": name,
90                    "description": desc,
91                    "active": active.as_deref() == Some(name.as_str()),
92                })
93            })
94            .collect();
95        println!(
96            "{}",
97            serde_json::to_string_pretty(&serde_json::json!({
98                "profiles": items,
99                "active": active,
100            }))
101            .unwrap_or_default()
102        );
103    } else {
104        if profiles.is_empty() {
105            eprintln!(
106                "{}",
107                "No profiles found. Create profiles in .chub/profiles/".dimmed()
108            );
109            return;
110        }
111        eprintln!("{}", "Available profiles:\n".bold());
112        for (name, desc) in &profiles {
113            let marker = if active.as_deref() == Some(name.as_str()) {
114                " *".green().to_string()
115            } else {
116                String::new()
117            };
118            eprintln!("  {}{}", name.bold(), marker);
119            if let Some(d) = desc {
120                eprintln!("    {}", d.dimmed());
121            }
122        }
123    }
124}
125
126fn run_current(json: bool) {
127    let active = profiles::get_active_profile();
128
129    if json {
130        println!("{}", serde_json::json!({ "profile": active }));
131    } else {
132        match active {
133            Some(name) => {
134                eprintln!("Active profile: {}", name.bold());
135                if let Ok(resolved) = profiles::resolve_profile(&name) {
136                    if let Some(desc) = &resolved.description {
137                        eprintln!("  {}", desc.dimmed());
138                    }
139                    if !resolved.pins.is_empty() {
140                        eprintln!("  Pins: {}", resolved.pins.join(", "));
141                    }
142                    if !resolved.context.is_empty() {
143                        eprintln!("  Context: {}", resolved.context.join(", "));
144                    }
145                    eprintln!("  Rules: {}", resolved.rules.len());
146                }
147            }
148            None => eprintln!("{}", "No active profile.".dimmed()),
149        }
150    }
151}