Initial commit
This commit is contained in:
435
skills/commander-patterns/SKILL.md
Normal file
435
skills/commander-patterns/SKILL.md
Normal file
@@ -0,0 +1,435 @@
|
||||
---
|
||||
name: Commander.js Patterns
|
||||
description: 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.
|
||||
allowed-tools: 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
|
||||
|
||||
1. **Create program instance:**
|
||||
```typescript
|
||||
import { Command } from 'commander';
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
.name('mycli')
|
||||
.description('CLI description')
|
||||
.version('1.0.0');
|
||||
```
|
||||
|
||||
2. **Add simple command:**
|
||||
```typescript
|
||||
program
|
||||
.command('init')
|
||||
.description('Initialize project')
|
||||
.action(() => {
|
||||
// Command logic
|
||||
});
|
||||
```
|
||||
|
||||
3. **Parse arguments:**
|
||||
```typescript
|
||||
program.parse();
|
||||
```
|
||||
|
||||
### Command with Options
|
||||
|
||||
Use options for named flags with values:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
```typescript
|
||||
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
|
||||
```typescript
|
||||
// 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)
|
||||
```typescript
|
||||
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)
|
||||
```typescript
|
||||
import chalk from 'chalk';
|
||||
|
||||
program
|
||||
.command('deploy')
|
||||
.action(() => {
|
||||
console.log(chalk.green('✓ Deployment successful'));
|
||||
console.log(chalk.red('✗ Deployment failed'));
|
||||
});
|
||||
```
|
||||
|
||||
### With Ora (Spinners)
|
||||
```typescript
|
||||
import ora from 'ora';
|
||||
|
||||
program
|
||||
.command('build')
|
||||
.action(async () => {
|
||||
const spinner = ora('Building...').start();
|
||||
await build();
|
||||
spinner.succeed('Build complete');
|
||||
});
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Option class for complex options**: Provides better validation and type safety
|
||||
2. **Keep action handlers thin**: Delegate to separate functions
|
||||
3. **Provide clear descriptions**: Help users understand commands
|
||||
4. **Set sensible defaults**: Reduce required options
|
||||
5. **Validate early**: Check inputs before processing
|
||||
6. **Handle errors gracefully**: Provide helpful error messages
|
||||
7. **Use TypeScript**: Better type safety and IDE support
|
||||
8. **Test thoroughly**: Unit test commands and options
|
||||
9. **Document examples**: Show common usage patterns
|
||||
10. **Version your CLI**: Use semantic versioning
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern: Config Command Group
|
||||
```typescript
|
||||
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
|
||||
```typescript
|
||||
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
|
||||
```typescript
|
||||
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 patterns
|
||||
- `typer-patterns` - Python Typer framework patterns
|
||||
- `clap-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)
|
||||
Reference in New Issue
Block a user