From 890868abe5524e13a2382889b24901e459e7ccce Mon Sep 17 00:00:00 2001 From: "INFRAGISTICS\\IPetrov" Date: Tue, 7 Apr 2026 14:04:45 +0300 Subject: [PATCH 1/3] fix(cli): improve error handling and error readability for all commands --- CHANGELOG.md | 8 ++++++++ packages/cli/bin/execute.js | 5 ++++- packages/cli/lib/cli.ts | 22 ++++++++++++++++++---- spec/unit/cli-spec.ts | 22 ++++++++++++++++++++-- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 481f00a0a..d4f788f30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ This is a major release that introduces the **Ignite UI CLI MCP Server** as a ne --- +### Bug Fixes + +* **CLI error handling:** added `.fail()` handler to yargs to gracefully handle command validation errors (e.g., missing required subcommands) instead of showing raw stack traces +* **Unknown command detection:** running `ig ` now prints an error message and available commands instead of silently falling through to the step-by-step interactive mode +* **Unhandled promise rejection:** added `.catch()` in the CLI entry point to catch and display unexpected errors cleanly + +--- + ### New: Ignite UI CLI MCP Server A new Model Context Protocol (MCP) server that provides AI assistants with Ignite UI documentation search, API reference lookup, and CLI scaffolding capabilities across four frameworks: Angular, React, Blazor, and Web Components. diff --git a/packages/cli/bin/execute.js b/packages/cli/bin/execute.js index 16f0b3f84..43c51591e 100755 --- a/packages/cli/bin/execute.js +++ b/packages/cli/bin/execute.js @@ -19,5 +19,8 @@ resolve("igniteui-cli", { basedir: process.cwd() }, function (err, res) { } else { cli = require("../lib/cli"); } - cli.run(args); + cli.run(args).catch(function (err) { + console.error("Error: " + (err.message || err)); + process.exit(1); + }); }); diff --git a/packages/cli/lib/cli.ts b/packages/cli/lib/cli.ts index 9ab0b7661..426962261 100644 --- a/packages/cli/lib/cli.ts +++ b/packages/cli/lib/cli.ts @@ -83,6 +83,15 @@ export async function run(args = null) { false // setting this to `true` is supposed to exec the middleware after parsing and before arg validation // but in reality it also does not trigger the command's handler (╯°□°)╯︵ ┻━┻ ) + .fail((msg, err, yargs) => { + if (msg) { + Util.error(msg, "red"); + yargs.showHelp(); + } + if (err) { + Util.error(err.message, "red"); + } + }) .help().alias("help", "h") .parseAsync( args, // the args to parse to argv @@ -121,10 +130,15 @@ export async function run(args = null) { App.testMode = !!argv.testMode; if (!helpRequest && !ALL_COMMANDS.has(command?.toString())) { - Util.log("Starting Step by step mode.", "green"); - Util.log("For available commands, stop this execution and use --help.", "green"); - const prompts = new PromptSession(templateManager); - prompts.start(); + if (command) { + Util.error(`Unknown command: "${command}"`, "red"); + yargsModule.showHelp(); + } else { + Util.log("Starting Step by step mode.", "green"); + Util.log("For available commands, stop this execution and use --help.", "green"); + const prompts = new PromptSession(templateManager); + prompts.start(); + } } } ); diff --git a/spec/unit/cli-spec.ts b/spec/unit/cli-spec.ts index 8a936f123..1f04e7bbb 100644 --- a/spec/unit/cli-spec.ts +++ b/spec/unit/cli-spec.ts @@ -54,15 +54,33 @@ describe("Unit - Cli.ts", () => { await run.run("list"); expect(list.handler).toHaveBeenCalled(); }); - it("Should fire properly - fallback to default", async () => { + it("Should fire properly - fallback to default with no args", async () => { spyOn(Util , "log"); spyOn(GoogleAnalytics, "post"); spyOn(PromptSession.prototype, "start"); - await run.run("Nonexistent command"); + await run.run(""); // expected console output: expect(Util.log).toHaveBeenCalledWith("Starting Step by step mode.", "green"); expect(Util.log).toHaveBeenCalledWith("For available commands, stop this execution and use --help.", "green"); expect(PromptSession.prototype.start).toHaveBeenCalled(); }); + it("Should show error for unknown command", async () => { + spyOn(Util , "log"); + spyOn(Util , "error"); + spyOn(GoogleAnalytics, "post"); + spyOn(PromptSession.prototype, "start"); + await run.run("nonexistent"); + + expect(Util.error).toHaveBeenCalledWith(`Unknown command: "nonexistent"`, "red"); + expect(PromptSession.prototype.start).not.toHaveBeenCalled(); + }); + it("Should gracefully handle subcommand validation errors", async () => { + spyOn(Util , "log"); + spyOn(Util , "error"); + spyOn(GoogleAnalytics, "post"); + await run.run("generate"); + + expect(Util.error).toHaveBeenCalledWith("Please select command", "red"); + }); }); From 1f0d11b8eb0a99009476f380ca719210e7d3061d Mon Sep 17 00:00:00 2001 From: "INFRAGISTICS\\IPetrov" Date: Tue, 7 Apr 2026 14:13:11 +0300 Subject: [PATCH 2/3] chore: bug fix text moved --- CHANGELOG.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4f788f30..f4f3ac8b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,6 @@ This is a major release that introduces the **Ignite UI CLI MCP Server** as a ne --- -### Bug Fixes - -* **CLI error handling:** added `.fail()` handler to yargs to gracefully handle command validation errors (e.g., missing required subcommands) instead of showing raw stack traces -* **Unknown command detection:** running `ig ` now prints an error message and available commands instead of silently falling through to the step-by-step interactive mode -* **Unhandled promise rejection:** added `.catch()` in the CLI entry point to catch and display unexpected errors cleanly - ---- - ### New: Ignite UI CLI MCP Server A new Model Context Protocol (MCP) server that provides AI assistants with Ignite UI documentation search, API reference lookup, and CLI scaffolding capabilities across four frameworks: Angular, React, Blazor, and Web Components. @@ -91,6 +83,9 @@ A comprehensive modernization of all Angular templates to align with Angular v21 * **ci:** mark `Util.sanitizeShellArg(x)` as command injection sanitizer for CodeQL ([#1524](https://github.com/IgniteUI/igniteui-cli/pull/1524)) * **deps:** bump minimatch, ajv, immutable, and lodash ([#1549](https://github.com/IgniteUI/igniteui-cli/pull/1549)) * **deps:** bump flatted ([#1559](https://github.com/IgniteUI/igniteui-cli/pull/1559)) +* **CLI error handling:** added `.fail()` handler to yargs to gracefully handle command validation errors (e.g., missing required subcommands) instead of showing raw stack traces ([#1614](https://github.com/IgniteUI/igniteui-cli/pull/1614)) +* **Unknown command detection:** running `ig ` now prints an error message and available commands instead of silently falling through to the step-by-step interactive mode ([#1614](https://github.com/IgniteUI/igniteui-cli/pull/1614)) +* **Unhandled promise rejection:** added `.catch()` in the CLI entry point to catch and display unexpected errors cleanly ([#1614](https://github.com/IgniteUI/igniteui-cli/pull/1614)) --- From 9f7ad90640178226bf6bbcd75b5563d1b9169db2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:21:23 +0000 Subject: [PATCH 3/3] fix(cli): consolidate fail() handler message and set exitCode=1 for errors Agent-Logs-Url: https://github.com/IgniteUI/igniteui-cli/sessions/9e5da6c9-348d-43b7-8bc9-e0b558ebbab3 Co-authored-by: ivanvpetrov <110455887+ivanvpetrov@users.noreply.github.com> --- packages/cli/lib/cli.ts | 10 +++++----- spec/unit/cli-spec.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/cli/lib/cli.ts b/packages/cli/lib/cli.ts index 426962261..d4aa9cd53 100644 --- a/packages/cli/lib/cli.ts +++ b/packages/cli/lib/cli.ts @@ -84,12 +84,11 @@ export async function run(args = null) { // but in reality it also does not trigger the command's handler (╯°□°)╯︵ ┻━┻ ) .fail((msg, err, yargs) => { - if (msg) { - Util.error(msg, "red"); + const message = err?.message ?? msg; + if (message) { + Util.error(message, "red"); yargs.showHelp(); - } - if (err) { - Util.error(err.message, "red"); + process.exitCode = 1; } }) .help().alias("help", "h") @@ -131,6 +130,7 @@ export async function run(args = null) { if (!helpRequest && !ALL_COMMANDS.has(command?.toString())) { if (command) { + process.exitCode = 1; Util.error(`Unknown command: "${command}"`, "red"); yargsModule.showHelp(); } else { diff --git a/spec/unit/cli-spec.ts b/spec/unit/cli-spec.ts index 1f04e7bbb..225d26c32 100644 --- a/spec/unit/cli-spec.ts +++ b/spec/unit/cli-spec.ts @@ -58,7 +58,7 @@ describe("Unit - Cli.ts", () => { spyOn(Util , "log"); spyOn(GoogleAnalytics, "post"); spyOn(PromptSession.prototype, "start"); - await run.run(""); + await run.run([]); // expected console output: expect(Util.log).toHaveBeenCalledWith("Starting Step by step mode.", "green");