Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion mc/crates/mc-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,46 @@ fn main() -> Result<()> {
&config.provider_config,
cli.base_url.as_deref(),
cli.api_key.as_deref(),
)?;
);

let primary = match primary {
Ok(p) => p,
Err(e) => {
let err_str = format!("{e:?}"); // Debug format includes full chain
if err_str.contains("MC-E001")
|| err_str.contains("missing API key")
|| err_str.contains("MissingApiKey")
|| err_str.contains("API_KEY")
Comment on lines +220 to +223
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The check err_str.contains("API_KEY") is too broad. It will likely trigger the onboarding message for other errors, such as an invalid or expired key (e.g., [MC-E003] api error 401: Invalid API_KEY), which should be shown as a standard error to the user rather than a welcome message. Relying on the specific error code MC-E001 or the variant name MissingApiKey is more robust.

Suggested change
if err_str.contains("MC-E001")
|| err_str.contains("missing API key")
|| err_str.contains("MissingApiKey")
|| err_str.contains("API_KEY")
if err_str.contains("MC-E001")
|| err_str.contains("missing API key")
|| err_str.contains("MissingApiKey")

{
eprintln!();
eprintln!(" ╭─────────────────────────────────────────╮");
eprintln!(" │ Welcome to magic-code! 🚀 │");
eprintln!(" ╰─────────────────────────────────────────╯");
eprintln!();
eprintln!(" To get started, set an API key for your LLM provider:");
eprintln!();
eprintln!(" # Anthropic (default)");
eprintln!(" export ANTHROPIC_API_KEY=\"sk-ant-...\"");
eprintln!();
eprintln!(" # Or use another provider:");
eprintln!(" export OPENAI_API_KEY=\"sk-...\" # then: magic-code --provider openai");
eprintln!(" export GEMINI_API_KEY=\"...\" # then: magic-code --provider gemini");
eprintln!(
" export GROQ_API_KEY=\"gsk_...\" # then: magic-code --provider groq"
);
eprintln!(" export OPENROUTER_API_KEY=\"sk-or-...\" # then: magic-code --provider openrouter");
eprintln!();
eprintln!(" # Or use a local model (no API key needed):");
eprintln!(" magic-code --provider ollama --model llama3");
eprintln!();
eprintln!(" Add to ~/.bashrc or ~/.zshrc to persist.");
eprintln!(" Docs: https://github.com/kienbui1995/mc-code#install");
eprintln!();
Comment on lines +225 to +248
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This large block of eprintln! calls clutters the main function. Consider refactoring this onboarding message into a dedicated helper function to keep the high-level logic in main clean and focused.

std::process::exit(1);
Comment on lines +216 to +249
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Preserve machine-readable failures when --json is set.

--json is documented for automation/scripting, but this branch always prints a human-only banner and exits. That breaks callers expecting structured output on auth failures.

⚙️ Minimal guard
     let primary = match primary {
         Ok(p) => p,
         Err(e) => {
+            if cli.json {
+                return Err(e.into());
+            }
             let err_str = format!("{e:?}"); // Debug format includes full chain
             if err_str.contains("MC-E001")
                 || err_str.contains("missing API key")
                 || err_str.contains("MissingApiKey")
                 || err_str.contains("API_KEY")

}
return Err(e.into());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The call to .into() is redundant here because e is already an anyhow::Error and the function returns anyhow::Result<()>.

Suggested change
return Err(e.into());
return Err(e);

}
};

// Wrap with fallback provider if configured
let provider: Box<dyn mc_core::LlmProvider> =
Expand Down
Loading