From f1e9b3df3ad3e6281c64c3315de3527bf7b6499a Mon Sep 17 00:00:00 2001 From: Abdul Wahab <32850166+abdulwahabone@users.noreply.github.com> Date: Sat, 20 Jun 2026 19:34:38 +0900 Subject: [PATCH] Fix: fail loudly on unknown CLI subcommands (#270) Unknown/mistyped CLI subcommands now print 'Unknown command' and exit non-zero instead of silently routing to the detector. Closes #266. Version bump and changelog entry deferred (batching). Co-Authored-By: abdulwahabone --- cli/bin/cli.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/cli/bin/cli.js b/cli/bin/cli.js index f47509ba9..2f10dea69 100755 --- a/cli/bin/cli.js +++ b/cli/bin/cli.js @@ -10,13 +10,24 @@ * npx impeccable --help */ -import { readFileSync } from 'node:fs'; -import { join, dirname } from 'node:path'; +import { readFileSync, existsSync } from 'node:fs'; +import { join, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const SKILL_COMMANDS = new Set(['help', 'install', 'link', 'update', 'check']); +// Is this a detect target (the `npx impeccable src/` shorthand) or a mistyped +// command? Flags, URLs, path-shaped args, and real files/dirs (e.g. an +// extension-less `Dockerfile`) are targets; anything else is an unknown command. +function looksLikeDetectTarget(arg) { + const isFlag = arg.startsWith('-'); + const isUrl = /^https?:\/\//i.test(arg); + const isPathShaped = arg.includes('/') || arg.includes('\\') || arg.includes('.'); + const isExistingPath = existsSync(resolve(arg)); + return isFlag || isUrl || isPathShaped || isExistingPath; +} + async function main() { const args = process.argv.slice(2); const command = args[0]; @@ -61,11 +72,16 @@ Compatibility: } else if (SKILL_COMMANDS.has(command)) { const { run } = await import('./commands/skills.mjs'); await run(args); - } else { + } else if (looksLikeDetectTarget(command)) { // Default: treat as detect arguments (allow `npx impeccable src/` shorthand) process.argv = [process.argv[0], process.argv[1], ...args]; const { detectCli } = await import('../engine/detect-antipatterns.mjs'); await detectCli(); + } else { + // An unknown bareword: a mistyped command (or an old cached version run + // against newer docs). Fail loudly instead of silently statting it as a path. + console.error(`Unknown command: "${command}"\n\nTo see a list of supported commands, run:\n impeccable --help`); + process.exit(1); } }