12 KiB
name, description, allowed-tools
| name | description | allowed-tools |
|---|---|---|
| Commander.js Patterns | Commander.js CLI framework patterns including Command class, options, arguments, nested subcommands, and Option class usage. Use when building Node.js CLIs, implementing Commander.js commands, creating TypeScript CLI tools, adding command options/arguments, or when user mentions Commander.js, CLI commands, command options, or nested subcommands. | Read, Write, Bash, Edit |
Commander.js Patterns Skill
Provides comprehensive Commander.js patterns, templates, and examples for building robust Node.js CLI applications with TypeScript support.
Overview
Commander.js is the complete solution for Node.js command-line interfaces. This skill provides battle-tested patterns for:
- Command class instantiation and configuration
- Options with flags, choices, and defaults
- Arguments (required, optional, variadic)
- Nested subcommands and command hierarchies
- Option class with advanced validation
- Action handlers and middleware
- Error handling and validation
Instructions
Basic Command Setup
-
Create program instance:
import { Command } from 'commander'; const program = new Command(); program .name('mycli') .description('CLI description') .version('1.0.0'); -
Add simple command:
program .command('init') .description('Initialize project') .action(() => { // Command logic }); -
Parse arguments:
program.parse();
Command with Options
Use options for named flags with values:
program
.command('deploy')
.description('Deploy application')
.option('-e, --env <environment>', 'target environment', 'dev')
.option('-f, --force', 'force deployment', false)
.option('-v, --verbose', 'verbose output')
.action((options) => {
console.log('Environment:', options.env);
console.log('Force:', options.force);
console.log('Verbose:', options.verbose);
});
Command with Arguments
Use arguments for positional parameters:
program
.command('deploy <environment>')
.description('Deploy to environment')
.argument('<environment>', 'target environment')
.argument('[region]', 'optional region', 'us-east-1')
.action((environment, region, options) => {
console.log(`Deploying to ${environment} in ${region}`);
});
Option Class Usage
For advanced option configuration:
import { Command, Option } from 'commander';
program
.command('deploy')
.addOption(
new Option('-m, --mode <mode>', 'deployment mode')
.choices(['fast', 'safe', 'rollback'])
.default('safe')
.makeOptionMandatory()
)
.addOption(
new Option('-r, --replicas <count>', 'replica count')
.argParser(parseInt)
.default(3)
)
.action((options) => {
console.log(`Mode: ${options.mode}, Replicas: ${options.replicas}`);
});
Nested Subcommands
Create command hierarchies:
const config = program
.command('config')
.description('Manage configuration');
config
.command('get <key>')
.description('Get config value')
.action((key) => {
console.log(`Config ${key}:`, getConfig(key));
});
config
.command('set <key> <value>')
.description('Set config value')
.action((key, value) => {
setConfig(key, value);
console.log(`✓ Set ${key} = ${value}`);
});
config
.command('list')
.description('List all config')
.action(() => {
console.log(getAllConfig());
});
Variadic Arguments
Accept multiple values:
program
.command('add <items...>')
.description('Add multiple items')
.action((items) => {
console.log('Adding items:', items);
});
// Usage: mycli add item1 item2 item3
Custom Argument Parsing
Transform argument values:
program
.command('wait <delay>')
.description('Wait for specified time')
.argument('<delay>', 'delay in seconds', parseFloat)
.action((delay) => {
console.log(`Waiting ${delay} seconds...`);
});
Global Options
Options available to all commands:
program
.option('-c, --config <path>', 'config file path')
.option('-v, --verbose', 'verbose output')
.option('--no-color', 'disable colors');
program
.command('deploy')
.action((options, command) => {
const globalOpts = command.parent?.opts();
console.log('Config:', globalOpts?.config);
console.log('Verbose:', globalOpts?.verbose);
});
Error Handling
program
.command('deploy <environment>')
.action((environment) => {
if (!['dev', 'staging', 'prod'].includes(environment)) {
throw new Error(`Invalid environment: ${environment}`);
}
// Deploy logic
});
program.exitOverride();
try {
program.parse();
} catch (err) {
console.error('Error:', err.message);
process.exit(1);
}
Available Scripts
- validate-commander-structure.sh: Validates Commander.js CLI structure and patterns
- generate-command.sh: Scaffolds new command with options and arguments
- generate-subcommand.sh: Creates nested subcommand structure
- test-commander-cli.sh: Tests CLI commands with various inputs
- extract-command-help.sh: Extracts help text from CLI for documentation
Templates
TypeScript Templates
- basic-commander.ts: Minimal Commander.js setup
- command-with-options.ts: Command with various option types
- command-with-arguments.ts: Command with required/optional arguments
- nested-subcommands.ts: Multi-level command hierarchy
- option-class-advanced.ts: Advanced Option class usage
- full-cli-example.ts: Complete CLI with all patterns
- commander-with-inquirer.ts: Interactive prompts integration
- commander-with-validation.ts: Input validation patterns
JavaScript Templates
- basic-commander.js: ES modules Commander.js setup
- commonjs-commander.js: CommonJS Commander.js setup
Configuration Templates
- tsconfig.commander.json: TypeScript config for Commander.js projects
- package.json.template: Package.json with Commander.js dependencies
Examples
- basic-usage.md: Simple CLI with 2-3 commands
- options-arguments-demo.md: Comprehensive options and arguments examples
- nested-commands-demo.md: Building command hierarchies
- advanced-option-class.md: Option class validation and parsing
- interactive-cli.md: Combining Commander.js with Inquirer.js
- error-handling-patterns.md: Robust error handling strategies
- testing-commander-cli.md: Unit and integration testing patterns
Commander.js Key Concepts
Command Class
new Command()
.name('cli-name')
.description('CLI description')
.version('1.0.0')
.command('subcommand')
Option Types
- Flag option:
-v, --verbose(boolean) - Value option:
-p, --port <port>(required value) - Optional value:
-p, --port [port](optional value) - Negatable:
--no-color(inverse boolean) - Variadic:
--files <files...>(multiple values)
Argument Types
- Required:
<name> - Optional:
[name] - Variadic:
<items...>or[items...]
Option Class Methods
.choices(['a', 'b', 'c']): Restrict to specific values.default(value): Set default value.argParser(fn): Custom parsing function.makeOptionMandatory(): Require option.conflicts(option): Mutually exclusive options.implies(option): Implies another option.env(name): Read from environment variable
Action Handler Signatures
// No arguments
.action(() => {})
// With options only
.action((options) => {})
// With arguments
.action((arg1, arg2, options) => {})
// With command reference
.action((options, command) => {})
Pattern Recipes
Pattern 1: Simple CLI with Subcommands
Use template: templates/basic-commander.ts
Pattern 2: CLI with Rich Options
Use template: templates/option-class-advanced.ts
Pattern 3: Interactive CLI
Use template: templates/commander-with-inquirer.ts
Pattern 4: CLI with Validation
Use template: templates/commander-with-validation.ts
Pattern 5: Multi-level Commands
Use template: templates/nested-subcommands.ts
Integration with Other Tools
With Inquirer.js (Interactive Prompts)
import inquirer from 'inquirer';
program
.command('setup')
.action(async () => {
const answers = await inquirer.prompt([
{ type: 'input', name: 'name', message: 'Project name:' },
{ type: 'list', name: 'template', message: 'Template:', choices: ['basic', 'advanced'] }
]);
// Use answers
});
With Chalk (Colored Output)
import chalk from 'chalk';
program
.command('deploy')
.action(() => {
console.log(chalk.green('✓ Deployment successful'));
console.log(chalk.red('✗ Deployment failed'));
});
With Ora (Spinners)
import ora from 'ora';
program
.command('build')
.action(async () => {
const spinner = ora('Building...').start();
await build();
spinner.succeed('Build complete');
});
Best Practices
- Use Option class for complex options: Provides better validation and type safety
- Keep action handlers thin: Delegate to separate functions
- Provide clear descriptions: Help users understand commands
- Set sensible defaults: Reduce required options
- Validate early: Check inputs before processing
- Handle errors gracefully: Provide helpful error messages
- Use TypeScript: Better type safety and IDE support
- Test thoroughly: Unit test commands and options
- Document examples: Show common usage patterns
- Version your CLI: Use semantic versioning
Common Patterns
Pattern: Config Command Group
const config = program.command('config');
config.command('get <key>').action(getConfig);
config.command('set <key> <value>').action(setConfig);
config.command('list').action(listConfig);
config.command('delete <key>').action(deleteConfig);
Pattern: CRUD Commands
program.command('create <name>').action(create);
program.command('read <id>').action(read);
program.command('update <id>').action(update);
program.command('delete <id>').action(deleteItem);
program.command('list').action(list);
Pattern: Deploy with Environments
program
.command('deploy')
.addOption(new Option('-e, --env <env>').choices(['dev', 'staging', 'prod']))
.option('-f, --force', 'force deployment')
.action(deploy);
Troubleshooting
Issue: Options not parsed
Solution: Ensure program.parse() is called
Issue: Arguments not received
Solution: Check action handler signature matches argument count
Issue: Subcommands not working
Solution: Verify subcommand is attached before parse()
Issue: TypeScript errors
Solution: Install @types/node and configure tsconfig
Issue: Help not showing
Solution: Commander.js auto-generates help from descriptions
Success Criteria
✅ Command structure follows Commander.js conventions ✅ Options and arguments properly typed ✅ Help text is clear and descriptive ✅ Error handling covers edge cases ✅ CLI tested with various inputs ✅ TypeScript compiles without errors ✅ Commands execute as expected
Related Skills
click-patterns- Python Click framework patternstyper-patterns- Python Typer framework patternsclap-patterns- Rust Clap framework patterns
Skill Type: Framework Patterns + Code Templates Language: TypeScript/JavaScript (Node.js) Framework: Commander.js v12+ Auto-invocation: Yes (via description matching)