Skip to main content

auths_cli/commands/
error_lookup.rs

1use clap::{Parser, Subcommand};
2
3use crate::config::CliConfig;
4use crate::errors::registry;
5
6/// Look up error codes and their explanations.
7///
8/// Usage:
9/// ```ignore
10/// auths error show AUTHS-E3001
11/// auths error list
12/// ```
13#[derive(Parser, Debug, Clone)]
14#[command(
15    about = "Look up an error code or list all known codes",
16    after_help = "Examples:
17  auths error list          # List all known error codes
18  auths error show AUTHS-E3001  # Show details for a specific code
19  auths error AUTHS-E3001   # Short form (same as show)
20
21Related:
22  auths doctor  — Run health checks to diagnose issues
23  auths status  — Check your identity and device status"
24)]
25pub struct ErrorLookupCommand {
26    #[command(subcommand)]
27    pub subcommand: Option<ErrorSubcommand>,
28
29    /// The error code to look up (e.g. AUTHS-E3001). Deprecated: use `auths error show CODE`.
30    pub code: Option<String>,
31
32    /// List all known error codes. Deprecated: use `auths error list`.
33    #[arg(long)]
34    pub list: bool,
35}
36
37#[derive(Subcommand, Debug, Clone)]
38pub enum ErrorSubcommand {
39    /// List all known error codes
40    List,
41    /// Show explanation for an error code
42    Show { code: String },
43}
44
45impl ErrorLookupCommand {
46    pub fn execute(&self, ctx: &CliConfig) -> anyhow::Result<()> {
47        // Handle new subcommand path
48        if let Some(ref subcommand) = self.subcommand {
49            match subcommand {
50                ErrorSubcommand::List => return list_codes(ctx),
51                ErrorSubcommand::Show { code } => return explain_code(code, ctx),
52            }
53        }
54
55        // Handle legacy flag/positional path
56        if self.list {
57            return list_codes(ctx);
58        }
59
60        match &self.code {
61            Some(code) => explain_code(code, ctx),
62            None => {
63                // No subcommand, no flag, no code → show help
64                list_codes(ctx)
65            }
66        }
67    }
68}
69
70fn explain_code(code: &str, ctx: &CliConfig) -> anyhow::Result<()> {
71    let normalized = code.to_uppercase();
72
73    if ctx.is_json() {
74        match registry::explain(&normalized) {
75            Some(text) => {
76                let json = serde_json::json!({
77                    "code": normalized,
78                    "explanation": text,
79                });
80                println!("{}", serde_json::to_string_pretty(&json)?);
81            }
82            None => {
83                let json = serde_json::json!({
84                    "error": { "message": format!("Unknown error code: {normalized}") }
85                });
86                println!("{}", serde_json::to_string_pretty(&json)?);
87            }
88        }
89    } else {
90        match registry::explain(&normalized) {
91            Some(text) => println!("{text}"),
92            None => {
93                eprintln!("Unknown error code: {normalized}");
94                eprintln!();
95                // Provide helpful suggestion if they try to use the old --list flag
96                if normalized == "LIST" {
97                    eprintln!("Did you mean: auths error list");
98                } else {
99                    eprintln!("Run `auths error list` to see all known codes.");
100                }
101                std::process::exit(1);
102            }
103        }
104    }
105    Ok(())
106}
107
108fn list_codes(ctx: &CliConfig) -> anyhow::Result<()> {
109    let codes = registry::all_codes();
110
111    if ctx.is_json() {
112        let json = serde_json::json!({ "codes": codes });
113        println!("{}", serde_json::to_string_pretty(&json)?);
114    } else {
115        for code in codes {
116            println!("{code}");
117        }
118        eprintln!("\n{} error codes registered", codes.len());
119        eprintln!("Run `auths error show CODE` to see details for a specific code.");
120    }
121    Ok(())
122}