use std::io::IsTerminal; use crate::auth; use crate::mcp; use crate::mcp::config::McpBindSource; use anyhow::Result; use clap::{ArgMatches, Args, Command, FromArgMatches}; #[derive(Args)] pub struct InitArgs { /// 跳过交互选择,直接使用扫码方式接入 #[arg(long)] pub noninteractive: bool, /// 扫码时不自动在浏览器打开二维码页面 #[arg(long = "no-open")] pub no_open: bool, } pub fn build_init_cmd() -> Command { InitArgs::augment_args(Command::new("init").about("初始化企业微信机器人配置")) .disable_help_flag(true) } /// Handle the `init` subcommand: prompt for bot credentials, persist them, and verify via MCP config fetch. pub async fn handle_init_cmd(matches: &ArgMatches) -> Result<()> { let args = InitArgs::from_arg_matches(matches)?; if !args.noninteractive && !std::io::stderr().is_terminal() { anyhow::bail!( "当前环境不支持交互式操作,请使用 --noninteractive 参数:\n {} init --noninteractive", env!("CARGO_BIN_NAME") ); } cliclack::intro("企业微信机器人初始化")?; let (bot, bind_source) = if args.noninteractive { (init_qrcode(args.no_open).await?, McpBindSource::Qrcode) } else { let method: &str = cliclack::select("请选择企微机器人接入方式:") .item("qrcode", "扫码接入(推荐)", "") .item("manual", "手动输入 Bot ID 和 Secret", "") .interact()?; match method { "qrcode" => (init_qrcode(args.no_open).await?, McpBindSource::Qrcode), _ => (init_manual().await?, McpBindSource::Interactive), } }; auth::set_bot_info(&bot)?; verify_and_finish(bind_source).await } /// 扫码接入流程 async fn init_qrcode(no_open: bool) -> Result { auth::scan_qrcode_for_bot(no_open).await } /// 手动输入 Bot ID 和 Secret async fn init_manual() -> Result { let bot_id: String = cliclack::input("企业微信机器人 Bot ID") .placeholder("请输入企业微信机器人ID") .interact()?; let bot_secret: String = cliclack::password("企业微信机器人 Secret") .mask('*') .interact()?; Ok(auth::Bot::new(bot_id, bot_secret)) } /// 验证凭证并完成初始化 async fn verify_and_finish(bind_source: McpBindSource) -> Result<()> { let spinner = cliclack::spinner(); spinner.start("正在验证企业微信机器人凭证..."); if let Err(e) = mcp::config::fetch_mcp_config(bind_source).await { spinner.stop("企业微信机器人凭证验证失败"); let mut output_errmsg: String = "验证企业微信机器人凭证失败".to_owned(); match &e { mcp::error::FetchMcpConfigError::Api(resp) => { if let Some(ref msg) = resp.errmsg { if !msg.is_empty() { output_errmsg = msg.clone(); } } } mcp::error::FetchMcpConfigError::Http(http_err) => { output_errmsg = format!("{} HTTP返回状态码 {}", output_errmsg, http_err.status); } mcp::error::FetchMcpConfigError::Other(other_err) => { output_errmsg = other_err.to_string(); } } // Credentials invalid or server unreachable — rollback auth::clear_bot_info(); mcp::config::clear_mcp_config(); cliclack::outro("初始化失败 ❌")?; anyhow::bail!(output_errmsg); } spinner.stop("企业微信机器人凭证验证成功"); cliclack::outro("初始化完成 ✅")?; Ok(()) }