#!/usr/bin/env node /** * Impeccable CLI * * Usage: * npx impeccable detect [file-or-dir-or-url...] * npx impeccable ignores * npx impeccable help|install|update * npx impeccable --help */ import { readFileSync, existsSync } from 'node:fs'; import { join, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { printUsage } from './usage.mjs'; 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]; if (!command || command === '--help' || command === '-h') { printUsage(); process.exit(0); } if (command === '--version' || command === '-v') { const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf8')); console.log(pkg.version); process.exit(0); } if (command === 'detect') { process.argv = [process.argv[0], process.argv[1], ...args.slice(1)]; const { detectCli } = await import('../engine/detect-antipatterns.mjs'); await detectCli(); } else if (command === 'ignores' || command === 'ignore') { const { run } = await import('./commands/ignores.mjs'); await run(args.slice(1)); } else if (command === 'skills') { const { run } = await import('./commands/skills.mjs'); await run(args.slice(1)); } else if (SKILL_COMMANDS.has(command)) { const { run } = await import('./commands/skills.mjs'); await run(args); } 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 if (command === 'init') { // The follow-up mistake from issue #472: `/impeccable init` belongs in an AI // coding agent's chat, and a user who typed it into their shell is likely to // retry it here as `npx impeccable init`. console.error(`"init" is not a CLI command. Type /impeccable init in your AI coding agent's chat (Claude Code, Cursor, Codex, ...), not in this terminal.`); process.exit(1); } 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); } } main().catch(error => { if (error?.code === 'IMPECCABLE_PROMPT_ABORT') { console.log('\nAborted.'); process.exit(130); } console.error(error?.message || error); process.exit(1); });