| name | node-cli |
| description | Build a Node.js CLI tool with Commander.js, interactive prompts, colored terminal output, and pnpm packaging. Use when creating a command-line interface for a Node.js project. Triggers include "CLI tool", "command line", "Commander.js", "terminal interface", "interactive prompts", or any task requiring a Node.js CLI. |
node-cli
Scaffold and build Node.js CLI tools with Commander.js, interactive prompts, and formatted terminal output.
When to Use
- Adding a CLI interface to an existing Node.js project
- Creating a standalone CLI tool distributed via npm
- Building an interactive terminal wizard
- Adding colored output and progress indicators to a script
Prerequisites
Quick Start
mkdir my-cli && cd my-cli
pnpm init
pnpm add commander @inquirer/prompts chalk
Package Setup
package.json:
{
"name": "my-cli",
"version": "1.0.0",
"type": "module",
"bin": {
"my-cli": "./dist/cli.js"
},
"scripts": {
"build": "tsc",
"dev": "tsx src/cli.ts",
"typecheck": "tsc --noEmit",
"lint": "eslint src"
}
}
Commander.js Pattern
import { Command } from 'commander';
const program = new Command();
program
.name('my-cli')
.description('Tool description')
.version('1.0.0');
program
.command('generate')
.description('Generate something')
.option('--domain <name>', 'Domain name')
.option('--output <file>', 'Output file', 'output.conf')
.action(async (opts) => {
});
program.parse();
Interactive Prompts with @inquirer/prompts
import { input, select, confirm, checkbox } from '@inquirer/prompts';
const domain = await input({
message: 'Server name:',
default: 'example.com',
});
const serverType = await select({
message: 'Server type:',
choices: [
{ value: 'proxy', name: 'Reverse Proxy' },
{ value: 'static', name: 'Static Files' },
],
});
const ssl = await confirm({
message: 'Enable SSL?',
default: true,
});
Colored Terminal Output
Use a log.ts utility. Do not use raw ANSI codes in business logic.
const c = {
green: (s: string) => `\x1b[32m${s}\x1b[0m`,
red: (s: string) => `\x1b[31m${s}\x1b[0m`,
yellow: (s: string) => `\x1b[33m${s}\x1b[0m`,
cyan: (s: string) => `\x1b[36m\x1b[4m${s}\x1b[0m`,
dim: (s: string) => `\x1b[2m${s}\x1b[0m`,
bold: (s: string) => `\x1b[1m${s}\x1b[0m`,
};
export const log = {
ok: (msg: string) => console.log(`${c.green('ok')} ${msg}`),
info: (: , : ) => .(),
: .(),
: .(),
: c.(p),
};
Standard Output Format
tool-name v1.0.0
ok operation completed
-- label value
-- file ./output.conf
Press Ctrl+C to exit.
Rules:
ok in green for success
-- in dim for metadata/info lines
x in red for errors
* in yellow for warnings
- Labels right-padded with spaces to align values
- File paths in cyan with underline
Distribution
To publish as a global npm package:
pnpm build
npm publish --access public
Users install with:
npm install -g my-cli
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "dist",
"strict": true,
"noUncheckedIndexedAccess": true
},
"include": ["src"]
}
Dependencies
| Package | Purpose |
|---|
commander | Argument parsing, subcommands, help generation |
@inquirer/prompts | Interactive prompts (input, select, confirm, checkbox) |
tsx | Run TypeScript directly in development |
typescript | TypeScript compiler |