Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate interactive command-line prompts using Inquirer.js with validation, conditional logic, and custom renderers. Creates user-friendly input collection flows for CLI applications.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 69% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 106% | 0% |
Generate interactive CLI prompts using Inquirer.js with comprehensive validation, conditional flows, and custom formatting.
Invoke this skill when you need to:
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | flowName | string | Yes | Name of the prompt flow | | prompts | array | Yes | List of prompt definitions | | typescript | boolean | No | Generate TypeScript types (default: true) | | validation | boolean | No | Include validation helpers (default: true) |
json{ "prompts": [ { "type": "input", "name": "projectName", "message": "What is your project name?", "default": "my-project", "validate": { "required": true, "pattern": "^[a-z][a-z0-9-]*$", "message": "Project name must be lowercase with hyphens" } }, { "type": "list", "name": "template", "message": "Select a template:", "choices": [ { "name": "React + TypeScript", "value": "react-ts" }, { "name": "Vue + TypeScript", "value": "vue-ts" }, { "name": "Node.js + Express", "value": "node-express" } ] }, { "type": "checkbox", "name": "features", "message": "Select features to include:", "choices": ["ESLint", "Prettier", "Husky", "Jest", "Docker"], "when": "answers.template !== 'node-express'" }, { "type": "confirm", "name": "installDeps", "message": "Install dependencies now?", "default": true } ] }
prompts/
├── <flowName>/
│ ├── index.ts # Main prompt flow
│ ├── types.ts # TypeScript interfaces
│ ├── validators.ts # Validation functions
│ ├── formatters.ts # Custom formatters
│ └── README.md # Usage documentationtypescriptimport { input, select, checkbox, confirm } from '@inquirer/prompts'; import { validateProjectName, validatePort } from './validators'; import type { ProjectConfig } from './types'; export async function createProjectPrompt(): Promise<ProjectConfig> { // Project name const projectName = await input({ message: 'What is your project name?', default: 'my-project', validate: validateProjectName, }); // Template selection const template = await select({ message: 'Select a template:', choices: [ { name: 'React + TypeScript', value: 'react-ts' }, { name: 'Vue + TypeScript', value: 'vue-ts' }, { name: 'Node.js + Express', value: 'node-express' }, ], }); // Conditional features (not shown for node-express) let features: string[] = []; if (template !== 'node-express') { features = await checkbox({ message: 'Select features to include:', choices: [ { name: 'ESLint', value: 'eslint', checked: true }, { name: 'Prettier', value: 'prettier', checked: true }, { name: 'Husky', value: 'husky' }, { name: 'Jest', value: 'jest' }, { name: 'Docker', value: 'docker' }, ], }); } // Confirmation const installDeps = await confirm({ message: 'Install dependencies now?', default: true, }); return { projectName, template, features, installDeps, }; }
typescript/** * Configuration collected from create-project prompts */ export interface ProjectConfig { /** Project name (lowercase, hyphens allowed) */ projectName: string; /** Selected project template */ template: 'react-ts' | 'vue-ts' | 'node-express'; /** Selected optional features */ features: Array<'eslint' | 'prettier' | 'husky' | 'jest' | 'docker'>; /** Whether to install dependencies */ installDeps: boolean; } /** * Template metadata for display */ export interface TemplateChoice { name: string; value: ProjectConfig['template']; description?: string; }
typescript/** * Validate project name format * - Must start with lowercase letter * - Only lowercase letters, numbers, and hyphens * - Max 50 characters */ export function validateProjectName(value: string): string | true { if (!value.trim()) { return 'Project name is required'; } if (!/^[a-z][a-z0-9-]*$/.test(value)) { return 'Project name must start with a letter and contain only lowercase letters, numbers, and hyphens'; } if (value.length > 50) { return 'Project name must be 50 characters or less'; } return true; } /** * Validate port number */ export function validatePort(value: string): string | true { const port = parseInt(value, 10); if (isNaN(port)) { return 'Port must be a number'; } if (port < 1024 || port > 65535) { return 'Port must be between 1024 and 65535'; } return true; } /** * Validate URL format */ export function validateUrl(value: string): string | true { try { new URL(value); return true; } catch { return 'Please enter a valid URL'; } } /** * Create async validator that checks for conflicts */ export function createConflictValidator( checkFn: (value: string) => Promise<boolean> ): (value: string) => Promise<string | true> { return async (value: string) => { const exists = await checkFn(value); if (exists) { return `"${value}" already exists`; } return true; }; }
typescriptimport chalk from 'chalk'; /** * Format project name for display */ export function formatProjectName(value: string): string { return chalk.cyan(value); } /** * Format feature list for summary */ export function formatFeatures(features: string[]): string { if (features.length === 0) { return chalk.dim('None selected'); } return features.map(f => chalk.green(`+ ${f}`)).join('\n'); } /** * Format configuration summary */ export function formatSummary(config: ProjectConfig): string { return ` ${chalk.bold('Project Configuration:')} ${chalk.dim('Name:')} ${formatProjectName(config.projectName)} ${chalk.dim('Template:')} ${config.template} ${chalk.dim('Features:')} ${formatFeatures(config.features).split('\n').map(l => ' ' + l).join('\n')} ${chalk.dim('Install:')} ${config.installDeps ? chalk.green('Yes') : chalk.yellow('No')} `; }
| Type | Description | Use Case | |------|-------------|----------| | input | Single-line text | Names, values | | password | Hidden input | Secrets, tokens | | number | Numeric input | Ports, counts | | confirm | Yes/No | Confirmations | | select | Single choice list | Options | | checkbox | Multiple choice | Features | | expand | Abbreviated choices | Quick actions | | editor | Multi-line editor | Long text | | search | Searchable list | Large lists | | rawlist | Numbered list | Indexed options |
typescriptvalidate: (value) => value.trim() ? true : 'This field is required'
typescriptvalidate: (value) => /^[a-z-]+$/.test(value) || 'Invalid format'
typescriptvalidate: async (value) => { const exists = await checkExists(value); return exists ? 'Already exists' : true; }
typescriptvalidate: (value, answers) => { if (answers.type === 'advanced' && !value) { return 'Required for advanced mode'; } return true; }
typescript{ type: 'input', name: 'apiKey', message: 'Enter API key:', when: (answers) => answers.useExternalApi }
typescriptconst prompts = basePrompts.filter(p => { if (p.name === 'advanced' && !options.showAdvanced) { return false; } return true; });
Other measured skills in the registry, with their headline benchmark lift.