Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:04:14 +08:00
commit 70c36b5eff
248 changed files with 47482 additions and 0 deletions

View File

@@ -0,0 +1,318 @@
# Inquirer Patterns Skill
Comprehensive interactive prompt patterns for building CLI tools with rich user input capabilities.
## Overview
This skill provides templates, examples, and utilities for implementing interactive CLI prompts in both **Node.js** (using `inquirer`) and **Python** (using `questionary`). It covers all major prompt types with validation, conditional logic, and real-world examples.
## Prompt Types Covered
### 1. Text Input
- Simple string input
- Email, URL, and path validation
- Numeric input with range validation
- Multi-line text
### 2. List Selection
- Single choice from options
- Categorized options with separators
- Options with descriptions and shortcuts
- Dynamic choices based on context
### 3. Checkbox
- Multiple selections
- Pre-selected defaults
- Grouped options
- Validation (min/max selections)
### 4. Password
- Hidden input with mask characters
- Password confirmation
- Strength validation
- API key and token input
### 5. Autocomplete
- Type-ahead search
- Fuzzy matching
- Large option lists
- Dynamic filtering
### 6. Conditional Questions
- Skip logic based on answers
- Dynamic question flow
- Branching paths
- Context-dependent validation
## Directory Structure
```
inquirer-patterns/
├── SKILL.md # Main skill documentation
├── README.md # This file
├── templates/
│ ├── nodejs/
│ │ ├── text-prompt.js # Text input examples
│ │ ├── list-prompt.js # List selection examples
│ │ ├── checkbox-prompt.js # Checkbox examples
│ │ ├── password-prompt.js # Password/secure input
│ │ ├── autocomplete-prompt.js # Autocomplete examples
│ │ ├── conditional-prompt.js # Conditional logic
│ │ └── comprehensive-example.js # Complete wizard
│ └── python/
│ ├── text_prompt.py
│ ├── list_prompt.py
│ ├── checkbox_prompt.py
│ ├── password_prompt.py
│ ├── autocomplete_prompt.py
│ └── conditional_prompt.py
├── scripts/
│ ├── install-nodejs-deps.sh # Install Node.js packages
│ ├── install-python-deps.sh # Install Python packages
│ ├── validate-prompts.sh # Validate skill structure
│ └── generate-prompt.sh # Generate boilerplate code
└── examples/
├── nodejs/
│ └── project-init-wizard.js # Full project setup wizard
└── python/
└── project_init_wizard.py # Full project setup wizard
```
## Quick Start
### Node.js
1. **Install dependencies:**
```bash
./scripts/install-nodejs-deps.sh
```
2. **Run an example:**
```bash
node templates/nodejs/text-prompt.js
node templates/nodejs/comprehensive-example.js
```
3. **Generate boilerplate:**
```bash
./scripts/generate-prompt.sh --type checkbox --lang js --output my-prompt.js
```
### Python
1. **Install dependencies:**
```bash
./scripts/install-python-deps.sh
```
2. **Run an example:**
```bash
python3 templates/python/text_prompt.py
python3 templates/python/conditional_prompt.py
```
3. **Generate boilerplate:**
```bash
./scripts/generate-prompt.sh --type list --lang py --output my_prompt.py
```
## Key Features
### Validation Patterns
All templates include comprehensive validation examples:
- **Required fields**: Ensure input is not empty
- **Format validation**: Email, URL, regex patterns
- **Range validation**: Numeric min/max values
- **Custom validation**: Business logic rules
- **Cross-field validation**: Compare multiple answers
### Error Handling
Examples demonstrate proper error handling:
- Graceful Ctrl+C handling
- TTY detection for non-interactive environments
- User-friendly error messages
- Validation feedback
### Best Practices
Templates follow CLI best practices:
- Clear, descriptive prompts
- Sensible defaults
- Keyboard shortcuts
- Progressive disclosure
- Accessibility considerations
## Usage Examples
### Text Input with Validation
**Node.js:**
```javascript
import inquirer from 'inquirer';
const answer = await inquirer.prompt([{
type: 'input',
name: 'email',
message: 'Enter your email:',
validate: (input) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(input) || 'Invalid email address';
}
}]);
```
**Python:**
```python
import questionary
email = questionary.text(
"Enter your email:",
validate=lambda text: bool(re.match(r'^[^\s@]+@[^\s@]+\.[^\s@]+$', text))
or "Invalid email address"
).ask()
```
### Conditional Questions
**Node.js:**
```javascript
const answers = await inquirer.prompt([
{
type: 'confirm',
name: 'useDatabase',
message: 'Use database?',
default: true
},
{
type: 'list',
name: 'dbType',
message: 'Database type:',
choices: ['PostgreSQL', 'MySQL', 'MongoDB'],
when: (answers) => answers.useDatabase
}
]);
```
**Python:**
```python
use_database = questionary.confirm("Use database?", default=True).ask()
if use_database:
db_type = questionary.select(
"Database type:",
choices=['PostgreSQL', 'MySQL', 'MongoDB']
).ask()
```
### Multiple Selections
**Node.js:**
```javascript
const answers = await inquirer.prompt([{
type: 'checkbox',
name: 'features',
message: 'Select features:',
choices: ['Auth', 'Database', 'API Docs', 'Testing'],
validate: (choices) => choices.length > 0 || 'Select at least one'
}]);
```
**Python:**
```python
features = questionary.checkbox(
"Select features:",
choices=['Auth', 'Database', 'API Docs', 'Testing'],
validate=lambda c: len(c) > 0 or "Select at least one"
).ask()
```
## Validation
Run the validation script to check skill structure:
```bash
./scripts/validate-prompts.sh
```
This checks:
- ✅ SKILL.md structure and frontmatter
- ✅ Required templates exist
- ✅ Scripts are executable
- ✅ No hardcoded secrets
- ✅ Basic syntax validation
## Dependencies
### Node.js
- `inquirer@^9.0.0` - Core prompting library
- `inquirer-autocomplete-prompt@^3.0.0` - Autocomplete support
- `chalk@^5.0.0` - Terminal colors (optional)
### Python
- `questionary>=2.0.0` - Core prompting library
- `prompt_toolkit>=3.0.0` - Terminal UI toolkit
- `colorama` - Windows color support (optional)
## Real-World Use Cases
### Project Initialization
See `examples/nodejs/project-init-wizard.js` and `examples/python/project_init_wizard.py` for complete project setup wizards.
### Configuration Management
Templates show how to build interactive config generators for:
- Database connections
- API credentials
- Deployment settings
- Feature flags
- CI/CD pipelines
### Interactive Installers
Examples demonstrate building user-friendly installers with:
- Dependency selection
- Environment setup
- Credential collection
- Validation and verification
## Troubleshooting
### Node.js: "Error [ERR_REQUIRE_ESM]"
**Solution**: Use `import` instead of `require`, or add `"type": "module"` to package.json
### Python: "No module named 'questionary'"
**Solution**: Run `./scripts/install-python-deps.sh` or `pip install questionary`
### Autocomplete not working
**Solution**: Install the autocomplete plugin:
- Node.js: `npm install inquirer-autocomplete-prompt`
- Python: Built into questionary
### Terminal rendering issues
**Solution**: Ensure terminal supports ANSI escape codes. On Windows, install `colorama`.
## Contributing
When adding new patterns:
1. Add template to both `templates/nodejs/` and `templates/python/`
2. Include comprehensive validation examples
3. Add real-world usage examples
4. Update this README
5. Run validation: `./scripts/validate-prompts.sh`
## License
Part of the CLI Builder plugin.
## Resources
- **Inquirer.js**: https://github.com/SBoudrias/Inquirer.js
- **Questionary**: https://github.com/tmbo/questionary
- **Prompt Toolkit**: https://github.com/prompt-toolkit/python-prompt-toolkit
- **CLI Best Practices**: https://clig.dev/
---
**Created**: 2025
**Maintained by**: CLI Builder Plugin
**Skill Version**: 1.0.0

View File

@@ -0,0 +1,453 @@
---
name: inquirer-patterns
description: Interactive prompt patterns for CLI tools with text, list, checkbox, password, autocomplete, and conditional questions. Use when building CLIs with user input, creating interactive prompts, implementing questionnaires, or when user mentions inquirer, prompts, interactive input, CLI questions, user prompts.
allowed-tools: Read, Write, Bash
---
# Inquirer Patterns
Comprehensive interactive prompt patterns for building CLI tools with rich user input capabilities. Provides templates for text, list, checkbox, password, autocomplete, and conditional questions in both Node.js and Python.
## Instructions
### When Building Interactive CLI Prompts
1. **Identify prompt type needed:**
- Text input: Simple string input
- List selection: Single choice from options
- Checkbox: Multiple selections
- Password: Secure input (hidden)
- Autocomplete: Type-ahead suggestions
- Conditional: Questions based on previous answers
2. **Choose language:**
- **Node.js**: Use templates in `templates/nodejs/`
- **Python**: Use templates in `templates/python/`
3. **Select appropriate template:**
- `text-prompt.js/py` - Basic text input
- `list-prompt.js/py` - Single selection list
- `checkbox-prompt.js/py` - Multiple selections
- `password-prompt.js/py` - Secure password input
- `autocomplete-prompt.js/py` - Type-ahead suggestions
- `conditional-prompt.js/py` - Dynamic questions based on answers
- `comprehensive-example.js/py` - All patterns combined
4. **Install required dependencies:**
- **Node.js**: Run `scripts/install-nodejs-deps.sh`
- **Python**: Run `scripts/install-python-deps.sh`
5. **Test prompts:**
- Use examples in `examples/nodejs/` or `examples/python/`
- Run validation script: `scripts/validate-prompts.sh`
6. **Customize for your CLI:**
- Copy relevant template sections
- Modify questions, choices, validation
- Add custom conditional logic
### Node.js Implementation
**Library**: `inquirer` (v9.x)
**Installation**:
```bash
npm install inquirer
```
**Basic Usage**:
```javascript
import inquirer from 'inquirer';
const answers = await inquirer.prompt([
{
type: 'input',
name: 'username',
message: 'Enter your username:',
validate: (input) => input.length > 0 || 'Username required'
}
]);
console.log(`Hello, ${answers.username}!`);
```
### Python Implementation
**Library**: `questionary` (v2.x)
**Installation**:
```bash
pip install questionary
```
**Basic Usage**:
```python
import questionary
username = questionary.text(
"Enter your username:",
validate=lambda text: len(text) > 0 or "Username required"
).ask()
print(f"Hello, {username}!")
```
## Available Templates
### Node.js Templates (`templates/nodejs/`)
1. **text-prompt.js** - Text input with validation
2. **list-prompt.js** - Single selection from list
3. **checkbox-prompt.js** - Multiple selections
4. **password-prompt.js** - Secure password input with confirmation
5. **autocomplete-prompt.js** - Type-ahead with fuzzy search
6. **conditional-prompt.js** - Dynamic questions based on answers
7. **comprehensive-example.js** - Complete CLI questionnaire
### Python Templates (`templates/python/`)
1. **text_prompt.py** - Text input with validation
2. **list_prompt.py** - Single selection from list
3. **checkbox_prompt.py** - Multiple selections
4. **password_prompt.py** - Secure password input with confirmation
5. **autocomplete_prompt.py** - Type-ahead with fuzzy search
6. **conditional_prompt.py** - Dynamic questions based on answers
7. **comprehensive_example.py** - Complete CLI questionnaire
## Prompt Types Reference
### Text Input
- **Use for**: Names, emails, URLs, paths, free-form text
- **Features**: Validation, default values, transform
- **Node.js**: `{ type: 'input' }`
- **Python**: `questionary.text()`
### List Selection
- **Use for**: Single choice from predefined options
- **Features**: Arrow key navigation, search filtering
- **Node.js**: `{ type: 'list' }`
- **Python**: `questionary.select()`
### Checkbox
- **Use for**: Multiple selections from options
- **Features**: Space to toggle, Enter to confirm
- **Node.js**: `{ type: 'checkbox' }`
- **Python**: `questionary.checkbox()`
### Password
- **Use for**: Sensitive input (credentials, tokens)
- **Features**: Hidden input, confirmation, validation
- **Node.js**: `{ type: 'password' }`
- **Python**: `questionary.password()`
### Autocomplete
- **Use for**: Large option lists with search
- **Features**: Type-ahead, fuzzy matching, suggestions
- **Node.js**: `inquirer-autocomplete-prompt` plugin
- **Python**: `questionary.autocomplete()`
### Conditional Questions
- **Use for**: Dynamic forms based on previous answers
- **Features**: Skip logic, dependent questions, branching
- **Node.js**: `when` property in question config
- **Python**: Conditional logic with if statements
## Validation Patterns
### Email Validation
```javascript
// Node.js
validate: (input) => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(input) || 'Invalid email address';
}
```
```python
# Python
def validate_email(text):
import re
regex = r'^[^\s@]+@[^\s@]+\.[^\s@]+$'
return bool(re.match(regex, text)) or "Invalid email address"
questionary.text("Email:", validate=validate_email).ask()
```
### Non-Empty Validation
```javascript
// Node.js
validate: (input) => input.length > 0 || 'This field is required'
```
```python
# Python
questionary.text("Name:", validate=lambda t: len(t) > 0 or "Required").ask()
```
### Numeric Range Validation
```javascript
// Node.js
validate: (input) => {
const num = parseInt(input);
return (num >= 1 && num <= 100) || 'Enter number between 1-100';
}
```
```python
# Python
def validate_range(text):
try:
num = int(text)
return 1 <= num <= 100 or "Enter number between 1-100"
except ValueError:
return "Invalid number"
questionary.text("Number:", validate=validate_range).ask()
```
## Examples
### Example 1: Project Initialization Wizard
**Use case**: Interactive CLI for scaffolding new projects
```javascript
// Node.js - See examples/nodejs/project-init.js
const answers = await inquirer.prompt([
{
type: 'input',
name: 'projectName',
message: 'Project name:',
validate: (input) => /^[a-z0-9-]+$/.test(input) || 'Invalid project name'
},
{
type: 'list',
name: 'framework',
message: 'Choose framework:',
choices: ['React', 'Vue', 'Angular', 'Svelte']
},
{
type: 'checkbox',
name: 'features',
message: 'Select features:',
choices: ['TypeScript', 'ESLint', 'Prettier', 'Testing']
}
]);
```
```python
# Python - See examples/python/project_init.py
import questionary
project_name = questionary.text(
"Project name:",
validate=lambda t: bool(re.match(r'^[a-z0-9-]+$', t)) or "Invalid name"
).ask()
framework = questionary.select(
"Choose framework:",
choices=['React', 'Vue', 'Angular', 'Svelte']
).ask()
features = questionary.checkbox(
"Select features:",
choices=['TypeScript', 'ESLint', 'Prettier', 'Testing']
).ask()
```
### Example 2: Conditional Question Flow
**Use case**: Dynamic questions based on previous answers
```javascript
// Node.js - See examples/nodejs/conditional-flow.js
const questions = [
{
type: 'confirm',
name: 'useDatabase',
message: 'Use database?',
default: true
},
{
type: 'list',
name: 'dbType',
message: 'Database type:',
choices: ['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite'],
when: (answers) => answers.useDatabase
},
{
type: 'input',
name: 'dbHost',
message: 'Database host:',
default: 'localhost',
when: (answers) => answers.useDatabase && answers.dbType !== 'SQLite'
}
];
```
```python
# Python - See examples/python/conditional_flow.py
use_database = questionary.confirm("Use database?", default=True).ask()
if use_database:
db_type = questionary.select(
"Database type:",
choices=['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite']
).ask()
if db_type != 'SQLite':
db_host = questionary.text(
"Database host:",
default="localhost"
).ask()
```
### Example 3: Password with Confirmation
**Use case**: Secure password input with validation and confirmation
```javascript
// Node.js - See examples/nodejs/password-confirm.js
const answers = await inquirer.prompt([
{
type: 'password',
name: 'password',
message: 'Enter password:',
validate: (input) => input.length >= 8 || 'Password must be 8+ characters'
},
{
type: 'password',
name: 'confirmPassword',
message: 'Confirm password:',
validate: (input, answers) => {
return input === answers.password || 'Passwords do not match';
}
}
]);
```
```python
# Python - See examples/python/password_confirm.py
password = questionary.password(
"Enter password:",
validate=lambda t: len(t) >= 8 or "Password must be 8+ characters"
).ask()
confirm = questionary.password(
"Confirm password:",
validate=lambda t: t == password or "Passwords do not match"
).ask()
```
## Scripts
### Install Dependencies
**Node.js**:
```bash
./scripts/install-nodejs-deps.sh
# Installs: inquirer, inquirer-autocomplete-prompt
```
**Python**:
```bash
./scripts/install-python-deps.sh
# Installs: questionary, prompt_toolkit
```
### Validate Prompts
```bash
./scripts/validate-prompts.sh [nodejs|python]
# Tests all templates and examples
```
### Generate Prompt Code
```bash
./scripts/generate-prompt.sh --type [text|list|checkbox|password] --lang [js|py]
# Generates boilerplate prompt code
```
## Best Practices
1. **Always validate user input** - Prevent invalid data early
2. **Provide clear messages** - Use descriptive prompt text
3. **Set sensible defaults** - Reduce friction for common cases
4. **Use conditional logic** - Skip irrelevant questions
5. **Group related questions** - Keep context together
6. **Handle Ctrl+C gracefully** - Catch interrupts and exit cleanly
7. **Test interactively** - Run examples to verify UX
8. **Provide help text** - Add descriptions for complex prompts
## Common Patterns
### CLI Configuration Generator
```javascript
const config = await inquirer.prompt([
{ type: 'input', name: 'appName', message: 'App name:' },
{ type: 'input', name: 'version', message: 'Version:', default: '1.0.0' },
{ type: 'list', name: 'env', message: 'Environment:', choices: ['dev', 'prod'] },
{ type: 'confirm', name: 'debug', message: 'Enable debug?', default: false }
]);
```
### Multi-Step Installation Wizard
```python
# Step 1: Choose components
components = questionary.checkbox(
"Select components:",
choices=['Core', 'CLI', 'Web UI', 'API']
).ask()
# Step 2: Configure each component
for component in components:
print(f"\nConfiguring {component}...")
# Component-specific questions
```
### Error Recovery
```javascript
try {
const answers = await inquirer.prompt(questions);
// Process answers
} catch (error) {
if (error.isTtyError) {
console.error('Prompt could not be rendered in this environment');
} else {
console.error('User interrupted prompt');
}
process.exit(1);
}
```
## Requirements
- **Node.js**: v14+ with ESM support
- **Python**: 3.7+ with pip
- **Dependencies**:
- Node.js: `inquirer@^9.0.0`, `inquirer-autocomplete-prompt@^3.0.0`
- Python: `questionary@^2.0.0`, `prompt_toolkit@^3.0.0`
## Troubleshooting
### Node.js Issues
**Problem**: `Error [ERR_REQUIRE_ESM]`
**Solution**: Use `import` instead of `require`, or add `"type": "module"` to package.json
**Problem**: Autocomplete not working
**Solution**: Install `inquirer-autocomplete-prompt` plugin
### Python Issues
**Problem**: No module named 'questionary'
**Solution**: Run `pip install questionary`
**Problem**: Prompt rendering issues
**Solution**: Ensure terminal supports ANSI escape codes
---
**Purpose**: Provide reusable interactive prompt patterns for CLI development
**Load when**: Building CLIs with user input, creating interactive questionnaires, implementing wizards

View File

@@ -0,0 +1,93 @@
/**
* Example: Complete Project Initialization Wizard
*
* Demonstrates combining multiple prompt types to create
* a comprehensive CLI tool for project setup
*/
import inquirer from 'inquirer';
async function projectInitWizard() {
console.log('\n╔════════════════════════════════════════╗');
console.log('║ 🚀 Project Initialization Wizard 🚀 ║');
console.log('╚════════════════════════════════════════╝\n');
const config = await inquirer.prompt([
// Project basics
{
type: 'input',
name: 'name',
message: 'Project name:',
validate: (input) => {
if (!/^[a-z0-9-]+$/.test(input)) {
return 'Use lowercase letters, numbers, and hyphens only';
}
return true;
}
},
{
type: 'input',
name: 'description',
message: 'Description:',
validate: (input) => input.length > 0 || 'Description required'
},
{
type: 'list',
name: 'language',
message: 'Programming language:',
choices: ['TypeScript', 'JavaScript', 'Python', 'Go', 'Rust']
},
{
type: 'list',
name: 'framework',
message: 'Framework:',
choices: (answers) => {
const frameworks = {
TypeScript: ['Next.js', 'Nest.js', 'Express', 'Fastify'],
JavaScript: ['React', 'Vue', 'Express', 'Koa'],
Python: ['FastAPI', 'Django', 'Flask'],
Go: ['Gin', 'Echo', 'Fiber'],
Rust: ['Actix', 'Rocket', 'Axum']
};
return frameworks[answers.language] || ['None'];
}
},
{
type: 'checkbox',
name: 'features',
message: 'Select features:',
choices: [
{ name: 'Database', value: 'database', checked: true },
{ name: 'Authentication', value: 'auth' },
{ name: 'API Documentation', value: 'docs' },
{ name: 'Testing', value: 'testing', checked: true },
{ name: 'Logging', value: 'logging', checked: true }
]
},
{
type: 'confirm',
name: 'useDocker',
message: 'Use Docker?',
default: true
},
{
type: 'confirm',
name: 'setupCI',
message: 'Setup CI/CD?',
default: true
}
]);
console.log('\n✅ Configuration complete!\n');
console.log(JSON.stringify(config, null, 2));
return config;
}
if (import.meta.url === `file://${process.argv[1]}`) {
projectInitWizard()
.then(() => process.exit(0))
.catch(console.error);
}
export { projectInitWizard };

View File

@@ -0,0 +1,100 @@
"""
Example: Complete Project Initialization Wizard
Demonstrates combining multiple prompt types to create
a comprehensive CLI tool for project setup
"""
import questionary
from questionary import Choice
import json
def project_init_wizard():
"""Complete project initialization wizard"""
print('\n╔════════════════════════════════════════╗')
print('║ 🚀 Project Initialization Wizard 🚀 ║')
print('╚════════════════════════════════════════╝\n')
# Project basics
name = questionary.text(
"Project name:",
validate=lambda text: (
text and text.replace('-', '').isalnum()
or "Use lowercase letters, numbers, and hyphens only"
)
).ask()
description = questionary.text(
"Description:",
validate=lambda text: len(text) > 0 or "Description required"
).ask()
# Language selection
language = questionary.select(
"Programming language:",
choices=['TypeScript', 'JavaScript', 'Python', 'Go', 'Rust']
).ask()
# Framework selection (based on language)
frameworks = {
'TypeScript': ['Next.js', 'Nest.js', 'Express', 'Fastify'],
'JavaScript': ['React', 'Vue', 'Express', 'Koa'],
'Python': ['FastAPI', 'Django', 'Flask'],
'Go': ['Gin', 'Echo', 'Fiber'],
'Rust': ['Actix', 'Rocket', 'Axum']
}
framework = questionary.select(
"Framework:",
choices=frameworks.get(language, ['None'])
).ask()
# Feature selection
features = questionary.checkbox(
"Select features:",
choices=[
Choice('Database', value='database', checked=True),
Choice('Authentication', value='auth'),
Choice('API Documentation', value='docs'),
Choice('Testing', value='testing', checked=True),
Choice('Logging', value='logging', checked=True)
]
).ask()
# Docker
use_docker = questionary.confirm(
"Use Docker?",
default=True
).ask()
# CI/CD
setup_ci = questionary.confirm(
"Setup CI/CD?",
default=True
).ask()
# Build configuration object
config = {
'name': name,
'description': description,
'language': language,
'framework': framework,
'features': features,
'useDocker': use_docker,
'setupCI': setup_ci
}
print('\n✅ Configuration complete!\n')
print(json.dumps(config, indent=2))
return config
if __name__ == "__main__":
try:
project_init_wizard()
except KeyboardInterrupt:
print("\n\n❌ Cancelled by user")
exit(1)

View File

@@ -0,0 +1,423 @@
#!/bin/bash
# generate-prompt.sh
# Generate boilerplate prompt code for Node.js or Python
set -e
# Default values
PROMPT_TYPE=""
LANGUAGE=""
OUTPUT_FILE=""
# Color codes
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Usage information
usage() {
echo "Usage: $0 --type <prompt-type> --lang <language> [--output <file>]"
echo
echo "Options:"
echo " --type Prompt type: text, list, checkbox, password, autocomplete, conditional"
echo " --lang Language: js (Node.js) or py (Python)"
echo " --output Output file path (optional)"
echo
echo "Examples:"
echo " $0 --type text --lang js --output my-prompt.js"
echo " $0 --type checkbox --lang py"
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--type)
PROMPT_TYPE="$2"
shift 2
;;
--lang)
LANGUAGE="$2"
shift 2
;;
--output)
OUTPUT_FILE="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1"
usage
;;
esac
done
# Validate arguments
if [ -z "$PROMPT_TYPE" ] || [ -z "$LANGUAGE" ]; then
echo "Error: --type and --lang are required"
usage
fi
# Validate prompt type
VALID_TYPES=("text" "list" "checkbox" "password" "autocomplete" "conditional")
if [[ ! " ${VALID_TYPES[@]} " =~ " ${PROMPT_TYPE} " ]]; then
echo "Error: Invalid prompt type '$PROMPT_TYPE'"
echo "Valid types: ${VALID_TYPES[*]}"
exit 1
fi
# Validate language
if [ "$LANGUAGE" != "js" ] && [ "$LANGUAGE" != "py" ]; then
echo "Error: Language must be 'js' or 'py'"
exit 1
fi
# Set default output file if not specified
if [ -z "$OUTPUT_FILE" ]; then
if [ "$LANGUAGE" == "js" ]; then
OUTPUT_FILE="${PROMPT_TYPE}-prompt.js"
else
OUTPUT_FILE="${PROMPT_TYPE}_prompt.py"
fi
fi
echo -e "${BLUE}🔧 Generating $PROMPT_TYPE prompt for $LANGUAGE...${NC}"
echo
# Generate Node.js code
if [ "$LANGUAGE" == "js" ]; then
case $PROMPT_TYPE in
text)
cat > "$OUTPUT_FILE" << 'EOF'
import inquirer from 'inquirer';
async function textPrompt() {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'fieldName',
message: 'Enter value:',
validate: (input) => input.length > 0 || 'This field is required'
}
]);
console.log('Answer:', answers.fieldName);
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
textPrompt().then(() => process.exit(0)).catch(console.error);
}
export { textPrompt };
EOF
;;
list)
cat > "$OUTPUT_FILE" << 'EOF'
import inquirer from 'inquirer';
async function listPrompt() {
const answers = await inquirer.prompt([
{
type: 'list',
name: 'selection',
message: 'Choose an option:',
choices: ['Option 1', 'Option 2', 'Option 3']
}
]);
console.log('Selected:', answers.selection);
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
listPrompt().then(() => process.exit(0)).catch(console.error);
}
export { listPrompt };
EOF
;;
checkbox)
cat > "$OUTPUT_FILE" << 'EOF'
import inquirer from 'inquirer';
async function checkboxPrompt() {
const answers = await inquirer.prompt([
{
type: 'checkbox',
name: 'selections',
message: 'Select options:',
choices: ['Option 1', 'Option 2', 'Option 3'],
validate: (choices) => choices.length > 0 || 'Select at least one option'
}
]);
console.log('Selected:', answers.selections);
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
checkboxPrompt().then(() => process.exit(0)).catch(console.error);
}
export { checkboxPrompt };
EOF
;;
password)
cat > "$OUTPUT_FILE" << 'EOF'
import inquirer from 'inquirer';
async function passwordPrompt() {
const answers = await inquirer.prompt([
{
type: 'password',
name: 'password',
message: 'Enter password:',
mask: '*',
validate: (input) => input.length >= 8 || 'Password must be at least 8 characters'
},
{
type: 'password',
name: 'confirm',
message: 'Confirm password:',
mask: '*',
validate: (input, answers) => input === answers.password || 'Passwords do not match'
}
]);
console.log('Password set successfully');
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
passwordPrompt().then(() => process.exit(0)).catch(console.error);
}
export { passwordPrompt };
EOF
;;
autocomplete)
cat > "$OUTPUT_FILE" << 'EOF'
import inquirer from 'inquirer';
import inquirerAutocomplete from 'inquirer-autocomplete-prompt';
inquirer.registerPrompt('autocomplete', inquirerAutocomplete);
const choices = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5'];
function searchChoices(input) {
if (!input) return choices;
return choices.filter(choice => choice.toLowerCase().includes(input.toLowerCase()));
}
async function autocompletePrompt() {
const answers = await inquirer.prompt([
{
type: 'autocomplete',
name: 'selection',
message: 'Search for an option:',
source: (answersSoFar, input) => Promise.resolve(searchChoices(input))
}
]);
console.log('Selected:', answers.selection);
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
autocompletePrompt().then(() => process.exit(0)).catch(console.error);
}
export { autocompletePrompt };
EOF
;;
conditional)
cat > "$OUTPUT_FILE" << 'EOF'
import inquirer from 'inquirer';
async function conditionalPrompt() {
const answers = await inquirer.prompt([
{
type: 'confirm',
name: 'continue',
message: 'Do you want to continue?',
default: true
},
{
type: 'input',
name: 'details',
message: 'Enter details:',
when: (answers) => answers.continue,
validate: (input) => input.length > 0 || 'Details required'
}
]);
console.log('Answers:', answers);
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
conditionalPrompt().then(() => process.exit(0)).catch(console.error);
}
export { conditionalPrompt };
EOF
;;
esac
fi
# Generate Python code
if [ "$LANGUAGE" == "py" ]; then
case $PROMPT_TYPE in
text)
cat > "$OUTPUT_FILE" << 'EOF'
import questionary
def text_prompt():
answer = questionary.text(
"Enter value:",
validate=lambda text: len(text) > 0 or "This field is required"
).ask()
print(f"Answer: {answer}")
return answer
if __name__ == "__main__":
text_prompt()
EOF
;;
list)
cat > "$OUTPUT_FILE" << 'EOF'
import questionary
def list_prompt():
answer = questionary.select(
"Choose an option:",
choices=['Option 1', 'Option 2', 'Option 3']
).ask()
print(f"Selected: {answer}")
return answer
if __name__ == "__main__":
list_prompt()
EOF
;;
checkbox)
cat > "$OUTPUT_FILE" << 'EOF'
import questionary
def checkbox_prompt():
answers = questionary.checkbox(
"Select options:",
choices=['Option 1', 'Option 2', 'Option 3'],
validate=lambda choices: len(choices) > 0 or "Select at least one option"
).ask()
print(f"Selected: {answers}")
return answers
if __name__ == "__main__":
checkbox_prompt()
EOF
;;
password)
cat > "$OUTPUT_FILE" << 'EOF'
import questionary
def password_prompt():
password = questionary.password(
"Enter password:",
validate=lambda text: len(text) >= 8 or "Password must be at least 8 characters"
).ask()
confirm = questionary.password(
"Confirm password:",
validate=lambda text: text == password or "Passwords do not match"
).ask()
print("Password set successfully")
return password
if __name__ == "__main__":
password_prompt()
EOF
;;
autocomplete)
cat > "$OUTPUT_FILE" << 'EOF'
import questionary
def autocomplete_prompt():
choices = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5']
answer = questionary.autocomplete(
"Search for an option:",
choices=choices
).ask()
print(f"Selected: {answer}")
return answer
if __name__ == "__main__":
autocomplete_prompt()
EOF
;;
conditional)
cat > "$OUTPUT_FILE" << 'EOF'
import questionary
def conditional_prompt():
continue_prompt = questionary.confirm(
"Do you want to continue?",
default=True
).ask()
details = None
if continue_prompt:
details = questionary.text(
"Enter details:",
validate=lambda text: len(text) > 0 or "Details required"
).ask()
result = {
'continue': continue_prompt,
'details': details
}
print(f"Answers: {result}")
return result
if __name__ == "__main__":
conditional_prompt()
EOF
;;
esac
fi
# Make Python files executable
if [ "$LANGUAGE" == "py" ]; then
chmod +x "$OUTPUT_FILE"
fi
echo -e "${GREEN}✅ Generated: $OUTPUT_FILE${NC}"
echo
echo -e "${YELLOW}📝 Next steps:${NC}"
echo " 1. Edit the generated file to customize your prompt"
if [ "$LANGUAGE" == "js" ]; then
echo " 2. Run: node $OUTPUT_FILE"
else
echo " 2. Run: python3 $OUTPUT_FILE"
fi
echo
echo -e "${BLUE}💡 Tip: Check out the templates directory for more advanced examples${NC}"

View File

@@ -0,0 +1,72 @@
#!/bin/bash
# install-nodejs-deps.sh
# Install Node.js dependencies for inquirer patterns
set -e
echo "📦 Installing Node.js dependencies for inquirer patterns..."
echo
# Check if npm is installed
if ! command -v npm &> /dev/null; then
echo "❌ Error: npm is not installed"
echo "Please install Node.js and npm first"
exit 1
fi
# Check Node.js version
NODE_VERSION=$(node --version | cut -d'v' -f2 | cut -d'.' -f1)
if [ "$NODE_VERSION" -lt 14 ]; then
echo "⚠️ Warning: Node.js 14 or higher is recommended"
echo "Current version: $(node --version)"
fi
# Create package.json if it doesn't exist
if [ ! -f "package.json" ]; then
echo "📝 Creating package.json..."
cat > package.json << 'EOF'
{
"name": "inquirer-patterns-examples",
"version": "1.0.0",
"description": "Interactive prompt patterns for CLI tools",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["inquirer", "cli", "prompts", "interactive"],
"author": "",
"license": "MIT"
}
EOF
echo "✅ package.json created"
fi
# Install core dependencies
echo "📥 Installing inquirer..."
npm install inquirer@^9.0.0
echo "📥 Installing inquirer-autocomplete-prompt..."
npm install inquirer-autocomplete-prompt@^3.0.0
# Optional: Install chalk for colored output
echo "📥 Installing chalk (optional, for colored output)..."
npm install chalk@^5.0.0
echo
echo "✅ All Node.js dependencies installed successfully!"
echo
echo "📚 Installed packages:"
echo " - inquirer@^9.0.0"
echo " - inquirer-autocomplete-prompt@^3.0.0"
echo " - chalk@^5.0.0"
echo
echo "🚀 You can now run the examples:"
echo " node templates/nodejs/text-prompt.js"
echo " node templates/nodejs/list-prompt.js"
echo " node templates/nodejs/checkbox-prompt.js"
echo " node templates/nodejs/password-prompt.js"
echo " node templates/nodejs/autocomplete-prompt.js"
echo " node templates/nodejs/conditional-prompt.js"
echo " node templates/nodejs/comprehensive-example.js"
echo

View File

@@ -0,0 +1,65 @@
#!/bin/bash
# install-python-deps.sh
# Install Python dependencies for questionary patterns
set -e
echo "📦 Installing Python dependencies for questionary patterns..."
echo
# Check if python3 is installed
if ! command -v python3 &> /dev/null; then
echo "❌ Error: python3 is not installed"
echo "Please install Python 3.7 or higher first"
exit 1
fi
# Check Python version
PYTHON_VERSION=$(python3 --version | cut -d' ' -f2 | cut -d'.' -f1,2)
MAJOR=$(echo $PYTHON_VERSION | cut -d'.' -f1)
MINOR=$(echo $PYTHON_VERSION | cut -d'.' -f2)
if [ "$MAJOR" -lt 3 ] || ([ "$MAJOR" -eq 3 ] && [ "$MINOR" -lt 7 ]); then
echo "⚠️ Warning: Python 3.7 or higher is recommended"
echo "Current version: $(python3 --version)"
fi
# Check if pip is installed
if ! command -v pip3 &> /dev/null; then
echo "❌ Error: pip3 is not installed"
echo "Please install pip3 first"
exit 1
fi
# Upgrade pip
echo "🔄 Upgrading pip..."
python3 -m pip install --upgrade pip
# Install core dependencies
echo "📥 Installing questionary..."
pip3 install "questionary>=2.0.0"
echo "📥 Installing prompt_toolkit..."
pip3 install "prompt_toolkit>=3.0.0"
# Optional: Install colorama for colored output on Windows
echo "📥 Installing colorama (optional, for Windows support)..."
pip3 install colorama
echo
echo "✅ All Python dependencies installed successfully!"
echo
echo "📚 Installed packages:"
echo " - questionary>=2.0.0"
echo " - prompt_toolkit>=3.0.0"
echo " - colorama"
echo
echo "🚀 You can now run the examples:"
echo " python3 templates/python/text_prompt.py"
echo " python3 templates/python/list_prompt.py"
echo " python3 templates/python/checkbox_prompt.py"
echo " python3 templates/python/password_prompt.py"
echo " python3 templates/python/autocomplete_prompt.py"
echo " python3 templates/python/conditional_prompt.py"
echo

View File

@@ -0,0 +1,206 @@
#!/bin/bash
# validate-prompts.sh
# Validate prompt templates and check for common issues
set -e
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ERRORS=0
WARNINGS=0
echo "🔍 Validating inquirer-patterns skill..."
echo
# Color codes
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
error() {
echo -e "${RED}❌ ERROR: $1${NC}"
((ERRORS++))
}
warning() {
echo -e "${YELLOW}⚠️ WARNING: $1${NC}"
((WARNINGS++))
}
success() {
echo -e "${GREEN}$1${NC}"
}
# Check SKILL.md exists
echo "📄 Checking SKILL.md..."
if [ ! -f "$SKILL_DIR/SKILL.md" ]; then
error "SKILL.md not found"
else
success "SKILL.md exists"
# Check frontmatter starts at line 1
FIRST_LINE=$(head -n 1 "$SKILL_DIR/SKILL.md")
if [ "$FIRST_LINE" != "---" ]; then
error "SKILL.md frontmatter must start at line 1"
else
success "Frontmatter starts at line 1"
fi
# Check for required frontmatter fields
if ! grep -q "^name:" "$SKILL_DIR/SKILL.md"; then
error "Missing 'name' field in frontmatter"
else
success "Frontmatter has 'name' field"
fi
if ! grep -q "^description:" "$SKILL_DIR/SKILL.md"; then
error "Missing 'description' field in frontmatter"
else
success "Frontmatter has 'description' field"
fi
# Check for "Use when" context
if ! grep -qi "use when" "$SKILL_DIR/SKILL.md"; then
warning "Missing 'Use when' trigger context in description"
else
success "'Use when' context found"
fi
fi
echo
# Check Node.js templates
echo "📁 Checking Node.js templates..."
NODEJS_DIR="$SKILL_DIR/templates/nodejs"
if [ ! -d "$NODEJS_DIR" ]; then
error "Node.js templates directory not found"
else
success "Node.js templates directory exists"
REQUIRED_NODEJS_TEMPLATES=(
"text-prompt.js"
"list-prompt.js"
"checkbox-prompt.js"
"password-prompt.js"
"autocomplete-prompt.js"
"conditional-prompt.js"
"comprehensive-example.js"
)
for template in "${REQUIRED_NODEJS_TEMPLATES[@]}"; do
if [ ! -f "$NODEJS_DIR/$template" ]; then
error "Missing Node.js template: $template"
else
# Check for basic syntax
if ! grep -q "import inquirer from 'inquirer'" "$NODEJS_DIR/$template"; then
if ! grep -q "inquirer" "$NODEJS_DIR/$template"; then
warning "$template might be missing inquirer import"
fi
fi
success "Node.js template exists: $template"
fi
done
fi
echo
# Check Python templates
echo "📁 Checking Python templates..."
PYTHON_DIR="$SKILL_DIR/templates/python"
if [ ! -d "$PYTHON_DIR" ]; then
error "Python templates directory not found"
else
success "Python templates directory exists"
REQUIRED_PYTHON_TEMPLATES=(
"text_prompt.py"
"list_prompt.py"
"checkbox_prompt.py"
"password_prompt.py"
"autocomplete_prompt.py"
"conditional_prompt.py"
)
for template in "${REQUIRED_PYTHON_TEMPLATES[@]}"; do
if [ ! -f "$PYTHON_DIR/$template" ]; then
error "Missing Python template: $template"
else
# Check for basic syntax
if ! grep -q "import questionary" "$PYTHON_DIR/$template"; then
warning "$template might be missing questionary import"
fi
success "Python template exists: $template"
fi
done
fi
echo
# Check scripts
echo "📁 Checking scripts..."
SCRIPTS_DIR="$SKILL_DIR/scripts"
REQUIRED_SCRIPTS=(
"install-nodejs-deps.sh"
"install-python-deps.sh"
"validate-prompts.sh"
"generate-prompt.sh"
)
for script in "${REQUIRED_SCRIPTS[@]}"; do
if [ ! -f "$SCRIPTS_DIR/$script" ]; then
error "Missing script: $script"
else
if [ ! -x "$SCRIPTS_DIR/$script" ]; then
warning "Script not executable: $script"
else
success "Script exists and is executable: $script"
fi
fi
done
echo
# Check for hardcoded API keys or secrets (security check)
echo "🔒 Security check: Scanning for hardcoded secrets..."
# Patterns to search for
SECRET_PATTERNS=(
"sk-[a-zA-Z0-9]{32,}"
"pk-[a-zA-Z0-9]{32,}"
"AIza[0-9A-Za-z_-]{35}"
"password.*=.*['\"][^'\"]{8,}['\"]"
)
SECRETS_FOUND=0
for pattern in "${SECRET_PATTERNS[@]}"; do
if grep -rE "$pattern" "$SKILL_DIR/templates" 2>/dev/null | grep -v "your_.*_key_here" | grep -v "example" > /dev/null; then
error "Potential hardcoded secret found matching pattern: $pattern"
((SECRETS_FOUND++))
fi
done
if [ $SECRETS_FOUND -eq 0 ]; then
success "No hardcoded secrets found"
fi
echo
# Summary
echo "═══════════════════════════════════════════════════════════"
echo "Validation Summary"
echo "═══════════════════════════════════════════════════════════"
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
echo -e "${GREEN}✅ All validations passed!${NC}"
exit 0
elif [ $ERRORS -eq 0 ]; then
echo -e "${YELLOW}⚠️ Validation passed with $WARNINGS warning(s)${NC}"
exit 0
else
echo -e "${RED}❌ Validation failed with $ERRORS error(s) and $WARNINGS warning(s)${NC}"
exit 1
fi

View File

@@ -0,0 +1,259 @@
/**
* Autocomplete Prompt Template
*
* Use for: Large option lists with search
* Features: Type-ahead, fuzzy matching, suggestions
*
* Note: Requires inquirer-autocomplete-prompt plugin
* Install: npm install inquirer-autocomplete-prompt
*/
import inquirer from 'inquirer';
import inquirerAutocomplete from 'inquirer-autocomplete-prompt';
// Register the autocomplete prompt type
inquirer.registerPrompt('autocomplete', inquirerAutocomplete);
// Example: Countries list for autocomplete
const countries = [
'Afghanistan', 'Albania', 'Algeria', 'Andorra', 'Angola',
'Argentina', 'Armenia', 'Australia', 'Austria', 'Azerbaijan',
'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus',
'Belgium', 'Belize', 'Benin', 'Bhutan', 'Bolivia',
'Brazil', 'Brunei', 'Bulgaria', 'Burkina Faso', 'Burundi',
'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Chad',
'Chile', 'China', 'Colombia', 'Comoros', 'Congo',
'Costa Rica', 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic',
'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic',
'Ecuador', 'Egypt', 'El Salvador', 'Estonia', 'Ethiopia',
'Fiji', 'Finland', 'France', 'Gabon', 'Gambia',
'Georgia', 'Germany', 'Ghana', 'Greece', 'Grenada',
'Guatemala', 'Guinea', 'Guyana', 'Haiti', 'Honduras',
'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran',
'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica',
'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kuwait',
'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia',
'Libya', 'Lithuania', 'Luxembourg', 'Madagascar', 'Malawi',
'Malaysia', 'Maldives', 'Mali', 'Malta', 'Mexico',
'Moldova', 'Monaco', 'Mongolia', 'Morocco', 'Mozambique',
'Myanmar', 'Namibia', 'Nepal', 'Netherlands', 'New Zealand',
'Nicaragua', 'Niger', 'Nigeria', 'Norway', 'Oman',
'Pakistan', 'Panama', 'Paraguay', 'Peru', 'Philippines',
'Poland', 'Portugal', 'Qatar', 'Romania', 'Russia',
'Rwanda', 'Saudi Arabia', 'Senegal', 'Serbia', 'Singapore',
'Slovakia', 'Slovenia', 'Somalia', 'South Africa', 'South Korea',
'Spain', 'Sri Lanka', 'Sudan', 'Sweden', 'Switzerland',
'Syria', 'Taiwan', 'Tanzania', 'Thailand', 'Togo',
'Tunisia', 'Turkey', 'Uganda', 'Ukraine', 'United Arab Emirates',
'United Kingdom', 'United States', 'Uruguay', 'Uzbekistan',
'Venezuela', 'Vietnam', 'Yemen', 'Zambia', 'Zimbabwe'
];
// Example: NPM packages for autocomplete
const popularPackages = [
'express', 'react', 'vue', 'angular', 'next', 'nuxt',
'axios', 'lodash', 'moment', 'dayjs', 'uuid', 'dotenv',
'typescript', 'eslint', 'prettier', 'jest', 'mocha', 'chai',
'webpack', 'vite', 'rollup', 'babel', 'esbuild',
'socket.io', 'redis', 'mongodb', 'mongoose', 'sequelize',
'prisma', 'typeorm', 'knex', 'pg', 'mysql2',
'bcrypt', 'jsonwebtoken', 'passport', 'helmet', 'cors',
'multer', 'sharp', 'puppeteer', 'playwright', 'cheerio'
];
// Fuzzy search function
function fuzzySearch(input, choices) {
if (!input) return choices;
const searchTerm = input.toLowerCase();
return choices.filter(choice => {
const item = typeof choice === 'string' ? choice : choice.name;
return item.toLowerCase().includes(searchTerm);
});
}
async function autocompletePromptExample() {
const answers = await inquirer.prompt([
{
type: 'autocomplete',
name: 'country',
message: 'Select your country:',
source: (answersSoFar, input) => {
return Promise.resolve(fuzzySearch(input, countries));
},
pageSize: 10
},
{
type: 'autocomplete',
name: 'package',
message: 'Search for an npm package:',
source: (answersSoFar, input) => {
const filtered = fuzzySearch(input, popularPackages);
return Promise.resolve(filtered);
},
pageSize: 8,
validate: (input) => {
return input.length > 0 || 'Please select a package';
}
},
{
type: 'autocomplete',
name: 'city',
message: 'Select city:',
source: async (answersSoFar, input) => {
// Example: Cities based on selected country
const citiesByCountry = {
'United States': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'],
'United Kingdom': ['London', 'Manchester', 'Birmingham', 'Glasgow', 'Liverpool'],
'Canada': ['Toronto', 'Vancouver', 'Montreal', 'Calgary', 'Ottawa'],
'Australia': ['Sydney', 'Melbourne', 'Brisbane', 'Perth', 'Adelaide'],
'Germany': ['Berlin', 'Munich', 'Hamburg', 'Frankfurt', 'Cologne']
};
const cities = citiesByCountry[answersSoFar.country] || ['Capital City', 'Major City'];
return fuzzySearch(input, cities);
},
when: (answers) => ['United States', 'United Kingdom', 'Canada', 'Australia', 'Germany'].includes(answers.country)
}
]);
console.log('\n✅ Selections:');
console.log(JSON.stringify(answers, null, 2));
return answers;
}
// Example: Framework/Library search
async function frameworkSearchExample() {
const frameworks = [
{ name: 'React - UI library by Facebook', value: 'react' },
{ name: 'Vue.js - Progressive JavaScript framework', value: 'vue' },
{ name: 'Angular - Platform for building web apps', value: 'angular' },
{ name: 'Svelte - Cybernetically enhanced web apps', value: 'svelte' },
{ name: 'Next.js - React framework with SSR', value: 'next' },
{ name: 'Nuxt.js - Vue.js framework with SSR', value: 'nuxt' },
{ name: 'Remix - Full stack web framework', value: 'remix' },
{ name: 'SvelteKit - Svelte framework', value: 'sveltekit' },
{ name: 'Express - Fast Node.js web framework', value: 'express' },
{ name: 'Fastify - Fast and low overhead web framework', value: 'fastify' },
{ name: 'NestJS - Progressive Node.js framework', value: 'nestjs' },
{ name: 'Koa - Expressive middleware for Node.js', value: 'koa' }
];
const answer = await inquirer.prompt([
{
type: 'autocomplete',
name: 'framework',
message: 'Search for a framework:',
source: (answersSoFar, input) => {
const filtered = fuzzySearch(input, frameworks);
return Promise.resolve(filtered);
},
pageSize: 10
}
]);
console.log(`\n✅ Selected: ${answer.framework}`);
return answer;
}
// Example: Command search with categories
async function commandSearchExample() {
const commands = [
{ name: '📦 install - Install dependencies', value: 'install' },
{ name: '🚀 start - Start development server', value: 'start' },
{ name: '🏗️ build - Build for production', value: 'build' },
{ name: '🧪 test - Run tests', value: 'test' },
{ name: '🔍 lint - Check code quality', value: 'lint' },
{ name: '✨ format - Format code', value: 'format' },
{ name: '📝 generate - Generate files', value: 'generate' },
{ name: '🔄 update - Update dependencies', value: 'update' },
{ name: '🧹 clean - Clean build artifacts', value: 'clean' },
{ name: '🚢 deploy - Deploy application', value: 'deploy' },
{ name: '📊 analyze - Analyze bundle size', value: 'analyze' },
{ name: '🐛 debug - Start debugger', value: 'debug' }
];
const answer = await inquirer.prompt([
{
type: 'autocomplete',
name: 'command',
message: 'Search for a command:',
source: (answersSoFar, input) => {
return Promise.resolve(fuzzySearch(input, commands));
},
pageSize: 12
}
]);
console.log(`\n✅ Running: ${answer.command}`);
return answer;
}
// Example: Dynamic API search (simulated)
async function apiSearchExample() {
console.log('\n🔍 API Endpoint Search\n');
const answer = await inquirer.prompt([
{
type: 'autocomplete',
name: 'endpoint',
message: 'Search API endpoints:',
source: async (answersSoFar, input) => {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 100));
const endpoints = [
{ name: 'GET /users - List all users', value: '/users' },
{ name: 'GET /users/:id - Get user by ID', value: '/users/:id' },
{ name: 'POST /users - Create new user', value: '/users' },
{ name: 'PUT /users/:id - Update user', value: '/users/:id' },
{ name: 'DELETE /users/:id - Delete user', value: '/users/:id' },
{ name: 'GET /posts - List all posts', value: '/posts' },
{ name: 'GET /posts/:id - Get post by ID', value: '/posts/:id' },
{ name: 'POST /posts - Create new post', value: '/posts' },
{ name: 'GET /comments - List comments', value: '/comments' },
{ name: 'POST /auth/login - User login', value: '/auth/login' },
{ name: 'POST /auth/register - User registration', value: '/auth/register' },
{ name: 'POST /auth/logout - User logout', value: '/auth/logout' }
];
return fuzzySearch(input, endpoints);
},
pageSize: 10
}
]);
console.log(`\n✅ Selected endpoint: ${answer.endpoint}`);
return answer;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
(async () => {
console.log('=== Autocomplete Examples ===\n');
console.log('1. Country & Package Selection');
await autocompletePromptExample();
console.log('\n2. Framework Search');
await frameworkSearchExample();
console.log('\n3. Command Search');
await commandSearchExample();
console.log('\n4. API Endpoint Search');
await apiSearchExample();
process.exit(0);
})().catch((error) => {
if (error.isTtyError) {
console.error('❌ Prompt could not be rendered in this environment');
} else {
console.error('❌ User interrupted prompt');
}
process.exit(1);
});
}
export { autocompletePromptExample, frameworkSearchExample, commandSearchExample, apiSearchExample };

View File

@@ -0,0 +1,140 @@
/**
* Checkbox Prompt Template
*
* Use for: Multiple selections from options
* Features: Space to toggle, Enter to confirm
*/
import inquirer from 'inquirer';
async function checkboxPromptExample() {
const answers = await inquirer.prompt([
{
type: 'checkbox',
name: 'features',
message: 'Select features to include:',
choices: [
'Authentication',
'Authorization',
'Database Integration',
'API Documentation',
'Testing Suite',
'CI/CD Pipeline',
'Monitoring',
'Logging'
],
validate: (choices) => {
if (choices.length === 0) {
return 'You must select at least one feature';
}
return true;
}
},
{
type: 'checkbox',
name: 'tools',
message: 'Select development tools:',
choices: [
{ name: 'ESLint (Linting)', value: 'eslint', checked: true },
{ name: 'Prettier (Formatting)', value: 'prettier', checked: true },
{ name: 'Jest (Testing)', value: 'jest' },
{ name: 'Husky (Git Hooks)', value: 'husky' },
{ name: 'TypeDoc (Documentation)', value: 'typedoc' },
{ name: 'Webpack (Bundling)', value: 'webpack' }
]
},
{
type: 'checkbox',
name: 'plugins',
message: 'Select plugins to install:',
choices: [
new inquirer.Separator('=== Essential ==='),
{ name: 'dotenv - Environment variables', value: 'dotenv', checked: true },
{ name: 'axios - HTTP client', value: 'axios', checked: true },
new inquirer.Separator('=== Utilities ==='),
{ name: 'lodash - Utility functions', value: 'lodash' },
{ name: 'dayjs - Date manipulation', value: 'dayjs' },
{ name: 'uuid - Unique IDs', value: 'uuid' },
new inquirer.Separator('=== Validation ==='),
{ name: 'joi - Schema validation', value: 'joi' },
{ name: 'zod - TypeScript-first validation', value: 'zod' },
new inquirer.Separator('=== Advanced ==='),
{ name: 'bull - Job queues', value: 'bull' },
{ name: 'socket.io - WebSockets', value: 'socket.io' }
],
pageSize: 15,
validate: (choices) => {
if (choices.length > 10) {
return 'Please select no more than 10 plugins to avoid bloat';
}
return true;
}
},
{
type: 'checkbox',
name: 'permissions',
message: 'Grant the following permissions:',
choices: [
{ name: '📁 Read files', value: 'read', checked: true },
{ name: '✏️ Write files', value: 'write' },
{ name: '🗑️ Delete files', value: 'delete' },
{ name: '🌐 Network access', value: 'network', checked: true },
{ name: '🖥️ System commands', value: 'system' },
{ name: '🔒 Keychain access', value: 'keychain' }
],
validate: (choices) => {
if (choices.includes('delete') && !choices.includes('write')) {
return 'Delete permission requires write permission';
}
return true;
}
},
{
type: 'checkbox',
name: 'environments',
message: 'Select deployment environments:',
choices: [
{ name: 'Development', value: 'dev', checked: true },
{ name: 'Staging', value: 'staging' },
{ name: 'Production', value: 'prod' },
{ name: 'Testing', value: 'test', checked: true }
],
validate: (choices) => {
if (!choices.includes('dev')) {
return 'Development environment is required';
}
if (choices.includes('prod') && !choices.includes('staging')) {
return 'Staging environment is recommended before production';
}
return true;
}
}
]);
console.log('\n✅ Selected options:');
console.log(JSON.stringify(answers, null, 2));
// Example: Process selections
console.log('\n📦 Installing selected features...');
answers.features.forEach(feature => {
console.log(` - ${feature}`);
});
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
checkboxPromptExample()
.then(() => process.exit(0))
.catch((error) => {
if (error.isTtyError) {
console.error('❌ Prompt could not be rendered in this environment');
} else {
console.error('❌ User interrupted prompt');
}
process.exit(1);
});
}
export { checkboxPromptExample };

View File

@@ -0,0 +1,456 @@
/**
* Comprehensive CLI Example
*
* Complete project initialization wizard combining all prompt types:
* - Text input with validation
* - List selections
* - Checkbox selections
* - Password input
* - Autocomplete (optional)
* - Conditional logic
*/
import inquirer from 'inquirer';
async function projectInitWizard() {
console.log(`
╔═══════════════════════════════════════════════════════════╗
║ ║
║ 🚀 Project Initialization Wizard 🚀 ║
║ ║
╚═══════════════════════════════════════════════════════════╝
`);
const config = await inquirer.prompt([
// === PROJECT BASICS ===
{
type: 'input',
name: 'projectName',
message: '📦 Project name:',
validate: (input) => {
if (input.length === 0) return 'Project name is required';
if (!/^[a-z0-9-_]+$/.test(input)) {
return 'Use lowercase letters, numbers, hyphens, and underscores only';
}
if (input.length < 3) return 'Project name must be at least 3 characters';
return true;
},
transformer: (input) => input.toLowerCase()
},
{
type: 'input',
name: 'description',
message: '📝 Project description:',
validate: (input) => input.length > 0 || 'Description is required'
},
{
type: 'input',
name: 'version',
message: '🏷️ Initial version:',
default: '0.1.0',
validate: (input) => {
return /^\d+\.\d+\.\d+$/.test(input) || 'Use semantic versioning (e.g., 0.1.0)';
}
},
{
type: 'input',
name: 'author',
message: '👤 Author name:',
default: process.env.USER || ''
},
{
type: 'input',
name: 'email',
message: '📧 Author email:',
validate: (input) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(input) || 'Invalid email address';
}
},
{
type: 'list',
name: 'license',
message: '📜 License:',
choices: ['MIT', 'Apache-2.0', 'GPL-3.0', 'BSD-3-Clause', 'ISC', 'Unlicensed'],
default: 'MIT'
},
// === TECHNOLOGY STACK ===
{
type: 'list',
name: 'projectType',
message: '🛠️ Project type:',
choices: [
'Web Application',
'CLI Tool',
'API/Backend',
'Library/Package',
'Desktop Application',
'Mobile Application'
]
},
{
type: 'list',
name: 'language',
message: '💻 Programming language:',
choices: [
{ name: 'TypeScript (Recommended)', value: 'typescript', short: 'TS' },
{ name: 'JavaScript', value: 'javascript', short: 'JS' },
{ name: 'Python', value: 'python', short: 'Py' },
{ name: 'Go', value: 'go', short: 'Go' },
{ name: 'Rust', value: 'rust', short: 'Rust' }
]
},
{
type: 'list',
name: 'framework',
message: '🎨 Framework/Runtime:',
choices: (answers) => {
const frameworks = {
typescript: ['Next.js', 'Remix', 'Nest.js', 'Express', 'Fastify', 'Node.js'],
javascript: ['React', 'Vue', 'Svelte', 'Express', 'Fastify', 'Node.js'],
python: ['FastAPI', 'Django', 'Flask', 'Tornado', 'Sanic'],
go: ['Gin', 'Echo', 'Fiber', 'Standard library'],
rust: ['Actix', 'Rocket', 'Axum', 'Warp']
};
return frameworks[answers.language] || ['None'];
}
},
// === FEATURES & TOOLS ===
{
type: 'checkbox',
name: 'features',
message: '✨ Select features:',
choices: (answers) => {
const baseFeatures = [
{ name: 'Environment variables (.env)', value: 'env', checked: true },
{ name: 'Configuration management', value: 'config', checked: true },
{ name: 'Logging', value: 'logging', checked: true },
{ name: 'Error handling', value: 'error-handling', checked: true }
];
if (answers.projectType === 'Web Application' || answers.projectType === 'API/Backend') {
baseFeatures.push(
{ name: 'Authentication', value: 'auth' },
{ name: 'Database integration', value: 'database' },
{ name: 'API documentation', value: 'api-docs' },
{ name: 'CORS handling', value: 'cors' }
);
}
if (answers.projectType === 'CLI Tool') {
baseFeatures.push(
{ name: 'Command-line arguments parser', value: 'cli-parser', checked: true },
{ name: 'Interactive prompts', value: 'prompts', checked: true },
{ name: 'Progress bars', value: 'progress' }
);
}
return baseFeatures;
},
validate: (choices) => choices.length > 0 || 'Select at least one feature'
},
{
type: 'checkbox',
name: 'devTools',
message: '🔧 Development tools:',
choices: (answers) => {
const tools = [];
if (['typescript', 'javascript'].includes(answers.language)) {
tools.push(
{ name: 'ESLint - Linting', value: 'eslint', checked: true },
{ name: 'Prettier - Code formatting', value: 'prettier', checked: true },
{ name: 'Husky - Git hooks', value: 'husky' },
{ name: 'Jest - Testing framework', value: 'jest', checked: true },
{ name: 'TypeDoc/JSDoc - Documentation', value: 'docs' }
);
} else if (answers.language === 'python') {
tools.push(
{ name: 'Black - Code formatting', value: 'black', checked: true },
{ name: 'Flake8 - Linting', value: 'flake8', checked: true },
{ name: 'mypy - Type checking', value: 'mypy' },
{ name: 'pytest - Testing framework', value: 'pytest', checked: true },
{ name: 'Sphinx - Documentation', value: 'sphinx' }
);
}
return tools;
},
default: ['eslint', 'prettier', 'jest']
},
// === DATABASE CONFIGURATION ===
{
type: 'confirm',
name: 'useDatabase',
message: '🗄️ Use database?',
default: (answers) => {
return answers.features.includes('database') ||
['Web Application', 'API/Backend'].includes(answers.projectType);
},
when: (answers) => ['Web Application', 'API/Backend', 'CLI Tool'].includes(answers.projectType)
},
{
type: 'list',
name: 'databaseType',
message: '📊 Database type:',
choices: [
{ name: '🐘 PostgreSQL (Relational)', value: 'postgresql' },
{ name: '🐬 MySQL (Relational)', value: 'mysql' },
{ name: '🍃 MongoDB (Document)', value: 'mongodb' },
{ name: '⚡ Redis (Key-Value)', value: 'redis' },
{ name: '📁 SQLite (Embedded)', value: 'sqlite' },
{ name: '🔥 Supabase (PostgreSQL + APIs)', value: 'supabase' }
],
when: (answers) => answers.useDatabase
},
{
type: 'list',
name: 'databaseORM',
message: '🔗 ORM/Database client:',
choices: (answers) => {
const orms = {
typescript: {
postgresql: ['Prisma', 'TypeORM', 'Kysely', 'Drizzle'],
mysql: ['Prisma', 'TypeORM', 'Kysely', 'Drizzle'],
mongodb: ['Mongoose', 'Prisma', 'TypeORM'],
sqlite: ['Prisma', 'TypeORM', 'Better-SQLite3'],
supabase: ['Supabase Client', 'Prisma']
},
python: {
postgresql: ['SQLAlchemy', 'Django ORM', 'Tortoise ORM'],
mysql: ['SQLAlchemy', 'Django ORM', 'Tortoise ORM'],
mongodb: ['Motor', 'PyMongo', 'MongoEngine'],
sqlite: ['SQLAlchemy', 'Django ORM']
}
};
const lang = answers.language;
const db = answers.databaseType;
return orms[lang]?.[db] || ['None'];
},
when: (answers) => answers.useDatabase && answers.databaseType !== 'redis'
},
// === TESTING CONFIGURATION ===
{
type: 'confirm',
name: 'setupTesting',
message: '🧪 Setup testing?',
default: true
},
{
type: 'checkbox',
name: 'testTypes',
message: '🔬 Test types:',
choices: [
{ name: 'Unit tests', value: 'unit', checked: true },
{ name: 'Integration tests', value: 'integration', checked: true },
{ name: 'E2E tests', value: 'e2e' },
{ name: 'Performance tests', value: 'performance' }
],
when: (answers) => answers.setupTesting
},
// === CI/CD CONFIGURATION ===
{
type: 'confirm',
name: 'setupCICD',
message: '⚙️ Setup CI/CD?',
default: true
},
{
type: 'list',
name: 'cicdProvider',
message: '🔄 CI/CD provider:',
choices: ['GitHub Actions', 'GitLab CI', 'CircleCI', 'Jenkins', 'None'],
when: (answers) => answers.setupCICD
},
// === DEPLOYMENT CONFIGURATION ===
{
type: 'confirm',
name: 'setupDeployment',
message: '🚀 Setup deployment?',
default: (answers) => answers.projectType !== 'Library/Package'
},
{
type: 'list',
name: 'deploymentPlatform',
message: '☁️ Deployment platform:',
choices: (answers) => {
if (answers.projectType === 'Web Application') {
return ['Vercel', 'Netlify', 'AWS', 'Google Cloud', 'Azure', 'Self-hosted'];
} else if (answers.projectType === 'API/Backend') {
return ['AWS', 'Google Cloud', 'Azure', 'DigitalOcean', 'Heroku', 'Self-hosted'];
} else if (answers.projectType === 'CLI Tool') {
return ['npm', 'PyPI', 'Homebrew', 'Binary releases', 'Docker'];
}
return ['AWS', 'Google Cloud', 'Azure', 'Self-hosted'];
},
when: (answers) => answers.setupDeployment
},
{
type: 'confirm',
name: 'useDocker',
message: '🐳 Use Docker?',
default: true,
when: (answers) => {
return answers.setupDeployment &&
!['Vercel', 'Netlify'].includes(answers.deploymentPlatform);
}
},
// === MONITORING & OBSERVABILITY ===
{
type: 'confirm',
name: 'setupMonitoring',
message: '📊 Setup monitoring & observability?',
default: (answers) => answers.projectType !== 'Library/Package'
},
{
type: 'checkbox',
name: 'monitoringTools',
message: '📈 Monitoring tools:',
choices: [
{ name: 'Sentry - Error tracking', value: 'sentry' },
{ name: 'DataDog - Full observability', value: 'datadog' },
{ name: 'Prometheus - Metrics', value: 'prometheus' },
{ name: 'Grafana - Dashboards', value: 'grafana' },
{ name: 'New Relic - APM', value: 'newrelic' }
],
when: (answers) => answers.setupMonitoring
},
// === DOCUMENTATION ===
{
type: 'confirm',
name: 'generateDocs',
message: '📚 Generate documentation?',
default: true
},
{
type: 'checkbox',
name: 'docTypes',
message: '📖 Documentation types:',
choices: [
{ name: 'README.md', value: 'readme', checked: true },
{ name: 'API documentation', value: 'api', checked: true },
{ name: 'Contributing guidelines', value: 'contributing' },
{ name: 'Code of conduct', value: 'coc' },
{ name: 'Changelog', value: 'changelog', checked: true }
],
when: (answers) => answers.generateDocs
},
// === SECURITY ===
{
type: 'confirm',
name: 'securitySetup',
message: '🔒 Setup security features?',
default: true,
when: (answers) => ['Web Application', 'API/Backend'].includes(answers.projectType)
},
{
type: 'checkbox',
name: 'securityFeatures',
message: '🛡️ Security features:',
choices: [
{ name: 'Dependency scanning', value: 'dep-scan', checked: true },
{ name: 'Secret scanning', value: 'secret-scan', checked: true },
{ name: 'HTTPS enforcement', value: 'https' },
{ name: 'Rate limiting', value: 'rate-limit' },
{ name: 'Input validation', value: 'validation', checked: true },
{ name: 'Security headers', value: 'headers' }
],
when: (answers) => answers.securitySetup
},
// === FINAL CONFIRMATION ===
{
type: 'confirm',
name: 'confirm',
message: '✅ Initialize project with these settings?',
default: true
}
]);
if (!config.confirm) {
console.log('\n❌ Project initialization cancelled.\n');
return null;
}
// Display configuration summary
console.log('\n' + '═'.repeat(60));
console.log('📋 PROJECT CONFIGURATION SUMMARY');
console.log('═'.repeat(60) + '\n');
console.log(`📦 Project: ${config.projectName} v${config.version}`);
console.log(`📝 Description: ${config.description}`);
console.log(`👤 Author: ${config.author} <${config.email}>`);
console.log(`📜 License: ${config.license}\n`);
console.log(`💻 Language: ${config.language}`);
console.log(`🎨 Framework: ${config.framework}`);
console.log(`🛠️ Type: ${config.projectType}\n`);
if (config.useDatabase) {
console.log(`🗄️ Database: ${config.databaseType}`);
if (config.databaseORM) {
console.log(`🔗 ORM: ${config.databaseORM}\n`);
}
}
if (config.features.length > 0) {
console.log(`✨ Features: ${config.features.join(', ')}`);
}
if (config.devTools.length > 0) {
console.log(`🔧 Dev Tools: ${config.devTools.join(', ')}\n`);
}
if (config.setupDeployment) {
console.log(`🚀 Deployment: ${config.deploymentPlatform}`);
if (config.useDocker) console.log(`🐳 Docker: Enabled`);
}
if (config.setupCICD) {
console.log(`⚙️ CI/CD: ${config.cicdProvider}`);
}
console.log('\n' + '═'.repeat(60) + '\n');
console.log('🎉 Configuration complete! Initializing project...\n');
// Here you would actually create the project files
// This is just a demonstration
return config;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
projectInitWizard()
.then((config) => {
if (config) {
console.log('✅ Project initialized successfully!\n');
console.log('Next steps:');
console.log(` 1. cd ${config.projectName}`);
console.log(' 2. Install dependencies');
console.log(' 3. Start development');
}
process.exit(0);
})
.catch((error) => {
if (error.isTtyError) {
console.error('❌ Prompt could not be rendered in this environment');
} else {
console.error('❌ User interrupted prompt');
}
process.exit(1);
});
}
export { projectInitWizard };

View File

@@ -0,0 +1,460 @@
/**
* Conditional Prompt Template
*
* Use for: Dynamic forms based on previous answers
* Features: Skip logic, dependent questions, branching
*/
import inquirer from 'inquirer';
async function conditionalPromptExample() {
const answers = await inquirer.prompt([
{
type: 'confirm',
name: 'useDatabase',
message: 'Do you want to use a database?',
default: true
},
{
type: 'list',
name: 'databaseType',
message: 'Select database type:',
choices: ['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite', 'Redis'],
when: (answers) => answers.useDatabase
},
{
type: 'input',
name: 'databaseHost',
message: 'Database host:',
default: 'localhost',
when: (answers) => {
return answers.useDatabase && answers.databaseType !== 'SQLite';
}
},
{
type: 'input',
name: 'databasePort',
message: 'Database port:',
default: (answers) => {
const ports = {
'PostgreSQL': '5432',
'MySQL': '3306',
'MongoDB': '27017',
'Redis': '6379'
};
return ports[answers.databaseType] || '5432';
},
when: (answers) => {
return answers.useDatabase && answers.databaseType !== 'SQLite';
}
},
{
type: 'input',
name: 'databaseName',
message: 'Database name:',
when: (answers) => answers.useDatabase,
validate: (input) => input.length > 0 || 'Database name required'
},
{
type: 'confirm',
name: 'useAuthentication',
message: 'Do you want to use authentication?',
default: true,
when: (answers) => answers.useDatabase
},
{
type: 'input',
name: 'databaseUsername',
message: 'Database username:',
when: (answers) => answers.useDatabase && answers.useAuthentication,
validate: (input) => input.length > 0 || 'Username required'
},
{
type: 'password',
name: 'databasePassword',
message: 'Database password:',
mask: '*',
when: (answers) => answers.useDatabase && answers.useAuthentication
},
{
type: 'confirm',
name: 'useSSL',
message: 'Use SSL connection?',
default: false,
when: (answers) => {
return answers.useDatabase &&
answers.databaseType !== 'SQLite' &&
answers.databaseHost !== 'localhost';
}
},
{
type: 'input',
name: 'sslCertPath',
message: 'Path to SSL certificate:',
when: (answers) => answers.useSSL,
validate: (input) => input.length > 0 || 'SSL certificate path required'
}
]);
console.log('\n✅ Configuration:');
console.log(JSON.stringify(answers, null, 2));
return answers;
}
// Example: Deployment configuration wizard
async function deploymentWizard() {
console.log('\n🚀 Deployment Configuration Wizard\n');
const config = await inquirer.prompt([
{
type: 'list',
name: 'environment',
message: 'Select deployment environment:',
choices: ['Development', 'Staging', 'Production']
},
{
type: 'confirm',
name: 'useDocker',
message: 'Deploy using Docker?',
default: true
},
{
type: 'input',
name: 'dockerImage',
message: 'Docker image name:',
when: (answers) => answers.useDocker,
default: 'myapp:latest',
validate: (input) => /^[a-z0-9-_/:.]+$/.test(input) || 'Invalid Docker image name'
},
{
type: 'list',
name: 'registry',
message: 'Container registry:',
choices: ['Docker Hub', 'GitHub Container Registry', 'AWS ECR', 'Google Artifact Registry'],
when: (answers) => answers.useDocker
},
{
type: 'list',
name: 'platform',
message: 'Deployment platform:',
choices: ['AWS', 'Google Cloud', 'Azure', 'DigitalOcean', 'Vercel', 'Netlify', 'Self-hosted']
},
{
type: 'list',
name: 'awsService',
message: 'AWS service:',
choices: ['ECS', 'EKS', 'Lambda', 'Elastic Beanstalk', 'EC2'],
when: (answers) => answers.platform === 'AWS'
},
{
type: 'list',
name: 'gcpService',
message: 'Google Cloud service:',
choices: ['Cloud Run', 'GKE', 'App Engine', 'Compute Engine'],
when: (answers) => answers.platform === 'Google Cloud'
},
{
type: 'confirm',
name: 'autoScale',
message: 'Enable auto-scaling?',
default: true,
when: (answers) => {
const scalableServices = ['ECS', 'EKS', 'Cloud Run', 'GKE'];
return scalableServices.includes(answers.awsService) ||
scalableServices.includes(answers.gcpService);
}
},
{
type: 'input',
name: 'minInstances',
message: 'Minimum instances:',
default: '1',
when: (answers) => answers.autoScale,
validate: (input) => {
const num = parseInt(input);
return num > 0 || 'Must be at least 1';
}
},
{
type: 'input',
name: 'maxInstances',
message: 'Maximum instances:',
default: '10',
when: (answers) => answers.autoScale,
validate: (input, answers) => {
const num = parseInt(input);
const min = parseInt(answers.minInstances);
return num >= min || `Must be at least ${min}`;
}
},
{
type: 'confirm',
name: 'useCDN',
message: 'Use CDN for static assets?',
default: true,
when: (answers) => answers.environment === 'Production'
},
{
type: 'list',
name: 'cdnProvider',
message: 'CDN provider:',
choices: ['CloudFlare', 'AWS CloudFront', 'Google Cloud CDN', 'Azure CDN'],
when: (answers) => answers.useCDN
},
{
type: 'confirm',
name: 'setupMonitoring',
message: 'Setup monitoring?',
default: true
},
{
type: 'checkbox',
name: 'monitoringTools',
message: 'Select monitoring tools:',
choices: ['Prometheus', 'Grafana', 'Datadog', 'New Relic', 'Sentry'],
when: (answers) => answers.setupMonitoring,
validate: (choices) => choices.length > 0 || 'Select at least one tool'
}
]);
console.log('\n✅ Deployment configuration complete!');
console.log(JSON.stringify(config, null, 2));
return config;
}
// Example: Feature flag configuration
async function featureFlagWizard() {
console.log('\n🎛 Feature Flag Configuration\n');
const config = await inquirer.prompt([
{
type: 'input',
name: 'featureName',
message: 'Feature name:',
validate: (input) => /^[a-z-_]+$/.test(input) || 'Use lowercase, hyphens, underscores only'
},
{
type: 'confirm',
name: 'enabledByDefault',
message: 'Enabled by default?',
default: false
},
{
type: 'list',
name: 'rolloutStrategy',
message: 'Rollout strategy:',
choices: [
'All users',
'Percentage rollout',
'User targeting',
'Beta users only',
'Manual control'
]
},
{
type: 'input',
name: 'rolloutPercentage',
message: 'Rollout percentage (0-100):',
when: (answers) => answers.rolloutStrategy === 'Percentage rollout',
default: '10',
validate: (input) => {
const num = parseInt(input);
return (num >= 0 && num <= 100) || 'Must be between 0 and 100';
}
},
{
type: 'checkbox',
name: 'targetUserGroups',
message: 'Target user groups:',
choices: ['Beta testers', 'Premium users', 'Internal team', 'Early adopters', 'Specific regions'],
when: (answers) => answers.rolloutStrategy === 'User targeting',
validate: (choices) => choices.length > 0 || 'Select at least one group'
},
{
type: 'checkbox',
name: 'targetRegions',
message: 'Target regions:',
choices: ['North America', 'Europe', 'Asia Pacific', 'South America', 'Africa'],
when: (answers) => {
return answers.rolloutStrategy === 'User targeting' &&
answers.targetUserGroups.includes('Specific regions');
}
},
{
type: 'confirm',
name: 'enableMetrics',
message: 'Track feature usage metrics?',
default: true
},
{
type: 'checkbox',
name: 'metrics',
message: 'Select metrics to track:',
choices: [
'Usage count',
'User adoption rate',
'Performance impact',
'Error rate',
'User feedback'
],
when: (answers) => answers.enableMetrics
},
{
type: 'confirm',
name: 'addExpirationDate',
message: 'Set feature flag expiration?',
default: false
},
{
type: 'input',
name: 'expirationDate',
message: 'Expiration date (YYYY-MM-DD):',
when: (answers) => answers.addExpirationDate,
validate: (input) => {
const date = new Date(input);
if (isNaN(date.getTime())) return 'Invalid date format';
if (date < new Date()) return 'Date must be in the future';
return true;
}
}
]);
console.log('\n✅ Feature flag configured!');
console.log(JSON.stringify(config, null, 2));
return config;
}
// Example: CI/CD pipeline setup
async function cicdPipelineWizard() {
console.log('\n⚙ CI/CD Pipeline Configuration\n');
const config = await inquirer.prompt([
{
type: 'list',
name: 'provider',
message: 'CI/CD provider:',
choices: ['GitHub Actions', 'GitLab CI', 'CircleCI', 'Jenkins', 'Travis CI']
},
{
type: 'checkbox',
name: 'triggers',
message: 'Pipeline triggers:',
choices: [
'Push to main/master',
'Pull request',
'Tag creation',
'Manual trigger',
'Scheduled (cron)'
],
default: ['Push to main/master', 'Pull request']
},
{
type: 'input',
name: 'cronSchedule',
message: 'Cron schedule:',
when: (answers) => answers.triggers.includes('Scheduled (cron)'),
default: '0 2 * * *',
validate: (input) => {
// Basic cron validation
const parts = input.split(' ');
return parts.length === 5 || 'Invalid cron format (5 parts required)';
}
},
{
type: 'checkbox',
name: 'stages',
message: 'Pipeline stages:',
choices: ['Build', 'Test', 'Lint', 'Security scan', 'Deploy'],
default: ['Build', 'Test', 'Deploy'],
validate: (choices) => choices.length > 0 || 'Select at least one stage'
},
{
type: 'checkbox',
name: 'testTypes',
message: 'Test types to run:',
choices: ['Unit tests', 'Integration tests', 'E2E tests', 'Performance tests'],
when: (answers) => answers.stages.includes('Test')
},
{
type: 'checkbox',
name: 'securityTools',
message: 'Security scanning tools:',
choices: ['Snyk', 'Dependabot', 'SonarQube', 'OWASP Dependency Check'],
when: (answers) => answers.stages.includes('Security scan')
},
{
type: 'checkbox',
name: 'deployEnvironments',
message: 'Deployment environments:',
choices: ['Development', 'Staging', 'Production'],
when: (answers) => answers.stages.includes('Deploy'),
default: ['Staging', 'Production']
},
{
type: 'confirm',
name: 'requireApproval',
message: 'Require manual approval for production?',
default: true,
when: (answers) => {
return answers.stages.includes('Deploy') &&
answers.deployEnvironments?.includes('Production');
}
},
{
type: 'confirm',
name: 'enableNotifications',
message: 'Enable build notifications?',
default: true
},
{
type: 'checkbox',
name: 'notificationChannels',
message: 'Notification channels:',
choices: ['Email', 'Slack', 'Discord', 'Microsoft Teams'],
when: (answers) => answers.enableNotifications
}
]);
console.log('\n✅ CI/CD pipeline configured!');
console.log(JSON.stringify(config, null, 2));
return config;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
(async () => {
console.log('=== Conditional Prompt Examples ===\n');
console.log('1. Database Configuration');
await conditionalPromptExample();
console.log('\n2. Deployment Wizard');
await deploymentWizard();
console.log('\n3. Feature Flag Configuration');
await featureFlagWizard();
console.log('\n4. CI/CD Pipeline Setup');
await cicdPipelineWizard();
process.exit(0);
})().catch((error) => {
if (error.isTtyError) {
console.error('❌ Prompt could not be rendered in this environment');
} else {
console.error('❌ User interrupted prompt');
}
process.exit(1);
});
}
export {
conditionalPromptExample,
deploymentWizard,
featureFlagWizard,
cicdPipelineWizard
};

View File

@@ -0,0 +1,104 @@
/**
* List Selection Prompt Template
*
* Use for: Single choice from predefined options
* Features: Arrow key navigation, search filtering
*/
import inquirer from 'inquirer';
async function listPromptExample() {
const answers = await inquirer.prompt([
{
type: 'list',
name: 'framework',
message: 'Choose your preferred framework:',
choices: [
'React',
'Vue',
'Angular',
'Svelte',
'Next.js',
'Nuxt.js'
],
default: 'React'
},
{
type: 'list',
name: 'language',
message: 'Choose programming language:',
choices: [
{ name: 'JavaScript', value: 'js' },
{ name: 'TypeScript', value: 'ts' },
{ name: 'Python', value: 'py' },
{ name: 'Ruby', value: 'rb' },
{ name: 'Go', value: 'go' }
],
default: 'ts'
},
{
type: 'list',
name: 'packageManager',
message: 'Choose package manager:',
choices: [
{ name: 'npm (Node Package Manager)', value: 'npm', short: 'npm' },
{ name: 'yarn (Fast, reliable package manager)', value: 'yarn', short: 'yarn' },
{ name: 'pnpm (Fast, disk space efficient)', value: 'pnpm', short: 'pnpm' },
{ name: 'bun (All-in-one toolkit)', value: 'bun', short: 'bun' }
]
},
{
type: 'list',
name: 'environment',
message: 'Select deployment environment:',
choices: [
new inquirer.Separator('--- Cloud Platforms ---'),
'AWS',
'Google Cloud',
'Azure',
new inquirer.Separator('--- Serverless ---'),
'Vercel',
'Netlify',
'Cloudflare Workers',
new inquirer.Separator('--- Self-hosted ---'),
'Docker',
'Kubernetes'
]
},
{
type: 'list',
name: 'database',
message: 'Choose database:',
choices: [
{ name: '🐘 PostgreSQL (Relational)', value: 'postgresql' },
{ name: '🐬 MySQL (Relational)', value: 'mysql' },
{ name: '🍃 MongoDB (Document)', value: 'mongodb' },
{ name: '⚡ Redis (Key-Value)', value: 'redis' },
{ name: '📊 SQLite (Embedded)', value: 'sqlite' },
{ name: '🔥 Supabase (PostgreSQL + APIs)', value: 'supabase' }
],
pageSize: 10
}
]);
console.log('\n✅ Selections:');
console.log(JSON.stringify(answers, null, 2));
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
listPromptExample()
.then(() => process.exit(0))
.catch((error) => {
if (error.isTtyError) {
console.error('❌ Prompt could not be rendered in this environment');
} else {
console.error('❌ User interrupted prompt');
}
process.exit(1);
});
}
export { listPromptExample };

View File

@@ -0,0 +1,208 @@
/**
* Password Prompt Template
*
* Use for: Sensitive input (credentials, tokens)
* Features: Hidden input, confirmation, validation
*/
import inquirer from 'inquirer';
async function passwordPromptExample() {
const answers = await inquirer.prompt([
{
type: 'password',
name: 'password',
message: 'Enter your password:',
mask: '*',
validate: (input) => {
if (input.length < 8) {
return 'Password must be at least 8 characters';
}
if (!/[A-Z]/.test(input)) {
return 'Password must contain at least one uppercase letter';
}
if (!/[a-z]/.test(input)) {
return 'Password must contain at least one lowercase letter';
}
if (!/[0-9]/.test(input)) {
return 'Password must contain at least one number';
}
if (!/[!@#$%^&*(),.?":{}|<>]/.test(input)) {
return 'Password must contain at least one special character';
}
return true;
}
},
{
type: 'password',
name: 'confirmPassword',
message: 'Confirm your password:',
mask: '*',
validate: (input, answers) => {
if (input !== answers.password) {
return 'Passwords do not match';
}
return true;
}
},
{
type: 'password',
name: 'apiKey',
message: 'Enter your API key:',
mask: '•',
validate: (input) => {
if (input.length === 0) {
return 'API key is required';
}
// Example: Validate API key format (e.g., sk-...)
if (!input.startsWith('sk-') && !input.startsWith('pk-')) {
return 'API key must start with "sk-" or "pk-"';
}
if (input.length < 32) {
return 'API key appears to be too short';
}
return true;
}
},
{
type: 'password',
name: 'oldPassword',
message: 'Enter your old password (for password change):',
mask: '*',
when: (answers) => {
// Only ask for old password if changing password
return answers.password && answers.confirmPassword;
},
validate: (input) => {
if (input.length === 0) {
return 'Old password is required';
}
// In real app, you'd verify against stored password
return true;
}
},
{
type: 'password',
name: 'encryptionKey',
message: 'Enter encryption key (optional):',
mask: '#',
validate: (input) => {
if (input.length === 0) return true; // Optional
if (input.length < 16) {
return 'Encryption key must be at least 16 characters';
}
return true;
}
}
]);
// Don't log actual passwords!
console.log('\n✅ Credentials received (not displayed for security)');
console.log('Password strength:', calculatePasswordStrength(answers.password));
console.log('API key format:', answers.apiKey.substring(0, 6) + '...');
// In real app, you'd:
// - Hash the password before storing
// - Encrypt the API key
// - Store securely (not in plain text)
return {
passwordHash: hashPassword(answers.password),
apiKeyEncrypted: encryptApiKey(answers.apiKey)
};
}
// Helper function to calculate password strength
function calculatePasswordStrength(password) {
let strength = 0;
if (password.length >= 8) strength++;
if (password.length >= 12) strength++;
if (/[a-z]/.test(password)) strength++;
if (/[A-Z]/.test(password)) strength++;
if (/[0-9]/.test(password)) strength++;
if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) strength++;
const levels = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong', 'Very Strong'];
return levels[Math.min(strength, levels.length - 1)];
}
// Placeholder for password hashing (use bcrypt in production)
function hashPassword(password) {
return `[HASHED:${password.length}_chars]`;
}
// Placeholder for API key encryption (use proper encryption in production)
function encryptApiKey(apiKey) {
return `[ENCRYPTED:${apiKey.substring(0, 6)}...]`;
}
// Example: Secure credential storage
async function securePasswordExample() {
console.log('\n🔐 Secure Password Setup\n');
const credentials = await inquirer.prompt([
{
type: 'input',
name: 'username',
message: 'Username:',
validate: (input) => input.length > 0 || 'Username required'
},
{
type: 'password',
name: 'password',
message: 'Password:',
mask: '*',
validate: (input) => {
const issues = [];
if (input.length < 12) issues.push('at least 12 characters');
if (!/[A-Z]/.test(input)) issues.push('an uppercase letter');
if (!/[a-z]/.test(input)) issues.push('a lowercase letter');
if (!/[0-9]/.test(input)) issues.push('a number');
if (!/[!@#$%^&*]/.test(input)) issues.push('a special character (!@#$%^&*)');
if (issues.length > 0) {
return `Password must contain: ${issues.join(', ')}`;
}
return true;
}
},
{
type: 'password',
name: 'confirm',
message: 'Confirm password:',
mask: '*',
validate: (input, answers) => {
return input === answers.password || 'Passwords do not match';
}
},
{
type: 'confirm',
name: 'remember',
message: 'Remember credentials? (stored securely)',
default: false
}
]);
console.log(`\n✅ Account created for: ${credentials.username}`);
console.log(`🔒 Password strength: ${calculatePasswordStrength(credentials.password)}`);
return credentials;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
passwordPromptExample()
.then(() => securePasswordExample())
.then(() => process.exit(0))
.catch((error) => {
if (error.isTtyError) {
console.error('❌ Prompt could not be rendered in this environment');
} else {
console.error('❌ User interrupted prompt');
}
process.exit(1);
});
}
export { passwordPromptExample, securePasswordExample };

View File

@@ -0,0 +1,105 @@
/**
* Text Input Prompt Template
*
* Use for: Names, emails, URLs, paths, free-form text
* Features: Validation, default values, transform
*/
import inquirer from 'inquirer';
async function textPromptExample() {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'username',
message: 'Enter your username:',
default: '',
validate: (input) => {
if (input.length === 0) {
return 'Username is required';
}
if (input.length < 3) {
return 'Username must be at least 3 characters';
}
if (!/^[a-zA-Z0-9_-]+$/.test(input)) {
return 'Username can only contain letters, numbers, hyphens, and underscores';
}
return true;
},
transformer: (input) => {
return input.toLowerCase();
}
},
{
type: 'input',
name: 'email',
message: 'Enter your email:',
validate: (input) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(input) || 'Invalid email address';
}
},
{
type: 'input',
name: 'website',
message: 'Enter your website (optional):',
default: '',
validate: (input) => {
if (input.length === 0) return true; // Optional field
const urlRegex = /^https?:\/\/.+/;
return urlRegex.test(input) || 'Must be a valid URL (http:// or https://)';
}
},
{
type: 'input',
name: 'age',
message: 'Enter your age:',
validate: (input) => {
const age = parseInt(input);
if (isNaN(age)) {
return 'Please enter a valid number';
}
if (age < 18) {
return 'You must be at least 18 years old';
}
if (age > 120) {
return 'Please enter a realistic age';
}
return true;
},
filter: (input) => parseInt(input)
},
{
type: 'input',
name: 'bio',
message: 'Enter a short bio:',
validate: (input) => {
if (input.length > 200) {
return 'Bio must be 200 characters or less';
}
return true;
}
}
]);
console.log('\n✅ Answers received:');
console.log(JSON.stringify(answers, null, 2));
return answers;
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
textPromptExample()
.then(() => process.exit(0))
.catch((error) => {
if (error.isTtyError) {
console.error('❌ Prompt could not be rendered in this environment');
} else {
console.error('❌ User interrupted prompt');
}
process.exit(1);
});
}
export { textPromptExample };

View File

@@ -0,0 +1,361 @@
"""
Autocomplete Prompt Template
Use for: Large option lists with search
Features: Type-ahead, fuzzy matching, suggestions
"""
import questionary
from questionary import Choice
# Example: Countries list for autocomplete
COUNTRIES = [
'Afghanistan', 'Albania', 'Algeria', 'Andorra', 'Angola',
'Argentina', 'Armenia', 'Australia', 'Austria', 'Azerbaijan',
'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus',
'Belgium', 'Belize', 'Benin', 'Bhutan', 'Bolivia',
'Brazil', 'Brunei', 'Bulgaria', 'Burkina Faso', 'Burundi',
'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Chad',
'Chile', 'China', 'Colombia', 'Comoros', 'Congo',
'Costa Rica', 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic',
'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic',
'Ecuador', 'Egypt', 'El Salvador', 'Estonia', 'Ethiopia',
'Fiji', 'Finland', 'France', 'Gabon', 'Gambia',
'Georgia', 'Germany', 'Ghana', 'Greece', 'Grenada',
'Guatemala', 'Guinea', 'Guyana', 'Haiti', 'Honduras',
'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran',
'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica',
'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kuwait',
'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia',
'Libya', 'Lithuania', 'Luxembourg', 'Madagascar', 'Malawi',
'Malaysia', 'Maldives', 'Mali', 'Malta', 'Mexico',
'Moldova', 'Monaco', 'Mongolia', 'Morocco', 'Mozambique',
'Myanmar', 'Namibia', 'Nepal', 'Netherlands', 'New Zealand',
'Nicaragua', 'Niger', 'Nigeria', 'Norway', 'Oman',
'Pakistan', 'Panama', 'Paraguay', 'Peru', 'Philippines',
'Poland', 'Portugal', 'Qatar', 'Romania', 'Russia',
'Rwanda', 'Saudi Arabia', 'Senegal', 'Serbia', 'Singapore',
'Slovakia', 'Slovenia', 'Somalia', 'South Africa', 'South Korea',
'Spain', 'Sri Lanka', 'Sudan', 'Sweden', 'Switzerland',
'Syria', 'Taiwan', 'Tanzania', 'Thailand', 'Togo',
'Tunisia', 'Turkey', 'Uganda', 'Ukraine', 'United Arab Emirates',
'United Kingdom', 'United States', 'Uruguay', 'Uzbekistan',
'Venezuela', 'Vietnam', 'Yemen', 'Zambia', 'Zimbabwe'
]
# Example: Popular packages
POPULAR_PACKAGES = [
'express', 'react', 'vue', 'angular', 'next', 'nuxt',
'axios', 'lodash', 'moment', 'dayjs', 'uuid', 'dotenv',
'typescript', 'eslint', 'prettier', 'jest', 'mocha', 'chai',
'webpack', 'vite', 'rollup', 'babel', 'esbuild',
'socket.io', 'redis', 'mongodb', 'mongoose', 'sequelize',
'prisma', 'typeorm', 'knex', 'pg', 'mysql2',
'bcrypt', 'jsonwebtoken', 'passport', 'helmet', 'cors',
'multer', 'sharp', 'puppeteer', 'playwright', 'cheerio'
]
def autocomplete_prompt_example():
"""Example autocomplete prompts"""
print("\n🔍 Autocomplete Example\n")
# Country selection with autocomplete
country = questionary.autocomplete(
"Select your country:",
choices=COUNTRIES,
validate=lambda text: len(text) > 0 or "Please select a country"
).ask()
# Package selection
package = questionary.autocomplete(
"Search for an npm package:",
choices=POPULAR_PACKAGES
).ask()
# Cities based on country (conditional)
city = None
cities_by_country = {
'United States': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'],
'United Kingdom': ['London', 'Manchester', 'Birmingham', 'Glasgow', 'Liverpool'],
'Canada': ['Toronto', 'Vancouver', 'Montreal', 'Calgary', 'Ottawa'],
'Australia': ['Sydney', 'Melbourne', 'Brisbane', 'Perth', 'Adelaide'],
'Germany': ['Berlin', 'Munich', 'Hamburg', 'Frankfurt', 'Cologne']
}
if country in cities_by_country:
city = questionary.autocomplete(
"Select city:",
choices=cities_by_country[country]
).ask()
answers = {
'country': country,
'package': package,
'city': city
}
print("\n✅ Selections:")
import json
print(json.dumps(answers, indent=2))
return answers
def framework_search_example():
"""Example: Framework/library search with descriptions"""
print("\n🔎 Framework Search Example\n")
frameworks = [
'React - UI library by Facebook',
'Vue.js - Progressive JavaScript framework',
'Angular - Platform for building web apps',
'Svelte - Cybernetically enhanced web apps',
'Next.js - React framework with SSR',
'Nuxt.js - Vue.js framework with SSR',
'Remix - Full stack web framework',
'SvelteKit - Svelte framework',
'Express - Fast Node.js web framework',
'Fastify - Fast and low overhead web framework',
'NestJS - Progressive Node.js framework',
'Koa - Expressive middleware for Node.js'
]
framework = questionary.autocomplete(
"Search for a framework:",
choices=frameworks
).ask()
# Extract value (remove description)
framework_name = framework.split(' - ')[0] if ' - ' in framework else framework
print(f"\n✅ Selected: {framework_name}")
return {'framework': framework_name}
def command_search_example():
"""Example: Command search with emojis and categories"""
print("\n⌨️ Command Search Example\n")
commands = [
'📦 install - Install dependencies',
'🚀 start - Start development server',
'🏗️ build - Build for production',
'🧪 test - Run tests',
'🔍 lint - Check code quality',
'✨ format - Format code',
'📝 generate - Generate files',
'🔄 update - Update dependencies',
'🧹 clean - Clean build artifacts',
'🚢 deploy - Deploy application',
'📊 analyze - Analyze bundle size',
'🐛 debug - Start debugger'
]
command = questionary.autocomplete(
"Search for a command:",
choices=commands
).ask()
# Extract command name
command_name = command.split(' - ')[0].split(' ', 1)[1] if ' - ' in command else command
print(f"\n✅ Running: {command_name}")
return {'command': command_name}
def api_endpoint_search():
"""Example: API endpoint search"""
print("\n🔍 API Endpoint Search\n")
endpoints = [
'GET /users - List all users',
'GET /users/:id - Get user by ID',
'POST /users - Create new user',
'PUT /users/:id - Update user',
'DELETE /users/:id - Delete user',
'GET /posts - List all posts',
'GET /posts/:id - Get post by ID',
'POST /posts - Create new post',
'GET /comments - List comments',
'POST /auth/login - User login',
'POST /auth/register - User registration',
'POST /auth/logout - User logout'
]
endpoint = questionary.autocomplete(
"Search API endpoints:",
choices=endpoints
).ask()
# Extract endpoint path
endpoint_path = endpoint.split(' - ')[0] if ' - ' in endpoint else endpoint
print(f"\n✅ Selected endpoint: {endpoint_path}")
return {'endpoint': endpoint_path}
def technology_stack_selection():
"""Example: Building technology stack with multiple autocomplete prompts"""
print("\n🛠️ Technology Stack Selection\n")
# Programming languages
languages = [
'JavaScript', 'TypeScript', 'Python', 'Go', 'Rust',
'Java', 'C++', 'Ruby', 'PHP', 'Swift', 'Kotlin'
]
language = questionary.autocomplete(
"Choose programming language:",
choices=languages
).ask()
# Frameworks based on language
frameworks_by_language = {
'JavaScript': ['React', 'Vue', 'Angular', 'Svelte', 'Express', 'Fastify'],
'TypeScript': ['Next.js', 'Nest.js', 'Angular', 'Remix', 'tRPC'],
'Python': ['Django', 'Flask', 'FastAPI', 'Tornado', 'Sanic'],
'Go': ['Gin', 'Echo', 'Fiber', 'Chi', 'Gorilla'],
'Rust': ['Actix', 'Rocket', 'Axum', 'Warp', 'Tide'],
'Java': ['Spring', 'Micronaut', 'Quarkus', 'Vert.x'],
'Ruby': ['Ruby on Rails', 'Sinatra', 'Hanami']
}
framework_choices = frameworks_by_language.get(language, ['None'])
framework = questionary.autocomplete(
f"Choose {language} framework:",
choices=framework_choices
).ask()
# Databases
databases = [
'PostgreSQL', 'MySQL', 'MongoDB', 'Redis', 'SQLite',
'Cassandra', 'DynamoDB', 'CouchDB', 'Neo4j', 'InfluxDB'
]
database = questionary.autocomplete(
"Choose database:",
choices=databases
).ask()
# Cloud providers
cloud_providers = [
'AWS', 'Google Cloud', 'Azure', 'DigitalOcean',
'Heroku', 'Vercel', 'Netlify', 'Cloudflare'
]
cloud = questionary.autocomplete(
"Choose cloud provider:",
choices=cloud_providers
).ask()
stack = {
'language': language,
'framework': framework,
'database': database,
'cloud': cloud
}
print("\n✅ Technology Stack:")
import json
print(json.dumps(stack, indent=2))
return stack
def file_path_autocomplete():
"""Example: File path autocomplete (simulated)"""
print("\n📁 File Path Autocomplete Example\n")
# Common project directories
directories = [
'/home/user/projects/web-app',
'/home/user/projects/api-server',
'/home/user/projects/cli-tool',
'/var/www/html',
'/opt/applications',
'~/Documents/code',
'~/workspace/nodejs',
'~/workspace/python'
]
project_path = questionary.autocomplete(
"Select project directory:",
choices=directories
).ask()
# Common config files
config_files = [
'package.json',
'tsconfig.json',
'jest.config.js',
'webpack.config.js',
'.env',
'.gitignore',
'README.md',
'Dockerfile',
'docker-compose.yml'
]
config_file = questionary.autocomplete(
"Select config file:",
choices=config_files
).ask()
result = {
'projectPath': project_path,
'configFile': config_file
}
print("\n✅ Selected:")
import json
print(json.dumps(result, indent=2))
return result
def main():
"""Run autocomplete prompt examples"""
try:
print("=== Autocomplete Examples ===")
# Example 1: Basic autocomplete
autocomplete_prompt_example()
# Example 2: Framework search
framework_search_example()
# Example 3: Command search
command_search_example()
# Example 4: API endpoint search
api_endpoint_search()
# Example 5: Technology stack
technology_stack_selection()
# Example 6: File path autocomplete
file_path_autocomplete()
print("\n✅ Autocomplete examples complete!")
except KeyboardInterrupt:
print("\n\n❌ User interrupted prompt")
exit(1)
except Exception as e:
print(f"\n\n❌ Error: {e}")
exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,310 @@
"""
Checkbox Prompt Template
Use for: Multiple selections from options
Features: Space to toggle, Enter to confirm
"""
import questionary
from questionary import Choice, Separator, ValidationError, Validator
class MinimumChoicesValidator(Validator):
"""Validator to ensure minimum number of choices selected"""
def __init__(self, minimum=1, message=None):
self.minimum = minimum
self.message = message or f"You must select at least {minimum} option(s)"
def validate(self, document):
# document.text contains selected choices as list
if len(document.text) < self.minimum:
raise ValidationError(
message=self.message,
cursor_position=0
)
class MaximumChoicesValidator(Validator):
"""Validator to ensure maximum number of choices selected"""
def __init__(self, maximum=10, message=None):
self.maximum = maximum
self.message = message or f"Please select no more than {maximum} options"
def validate(self, document):
if len(document.text) > self.maximum:
raise ValidationError(
message=self.message,
cursor_position=0
)
def checkbox_prompt_example():
"""Example checkbox prompts"""
print("\n☑️ Checkbox Selection Example\n")
# Simple checkbox
features = questionary.checkbox(
"Select features to include:",
choices=[
'Authentication',
'Authorization',
'Database Integration',
'API Documentation',
'Testing Suite',
'CI/CD Pipeline',
'Monitoring',
'Logging'
],
validate=lambda choices: len(choices) > 0 or "You must select at least one feature"
).ask()
# Checkbox with default selections
dev_tools = questionary.checkbox(
"Select development tools:",
choices=[
Choice('ESLint (Linting)', value='eslint', checked=True),
Choice('Prettier (Formatting)', value='prettier', checked=True),
Choice('Jest (Testing)', value='jest'),
Choice('Husky (Git Hooks)', value='husky'),
Choice('TypeDoc (Documentation)', value='typedoc'),
Choice('Webpack (Bundling)', value='webpack')
]
).ask()
# Checkbox with separators and checked defaults
plugins = questionary.checkbox(
"Select plugins to install:",
choices=[
Separator('=== Essential ==='),
Choice('dotenv - Environment variables', value='dotenv', checked=True),
Choice('axios - HTTP client', value='axios', checked=True),
Separator('=== Utilities ==='),
Choice('lodash - Utility functions', value='lodash'),
Choice('dayjs - Date manipulation', value='dayjs'),
Choice('uuid - Unique IDs', value='uuid'),
Separator('=== Validation ==='),
Choice('joi - Schema validation', value='joi'),
Choice('zod - TypeScript-first validation', value='zod'),
Separator('=== Advanced ==='),
Choice('bull - Job queues', value='bull'),
Choice('socket.io - WebSockets', value='socket.io')
],
validate=MaximumChoicesValidator(maximum=10)
).ask()
# Checkbox with emojis
permissions = questionary.checkbox(
"Grant the following permissions:",
choices=[
Choice('📁 Read files', value='read', checked=True),
Choice('✏️ Write files', value='write'),
Choice('🗑️ Delete files', value='delete'),
Choice('🌐 Network access', value='network', checked=True),
Choice('🖥️ System commands', value='system'),
Choice('🔒 Keychain access', value='keychain')
]
).ask()
# Validate permissions logic
if 'delete' in permissions and 'write' not in permissions:
print("\n⚠️ Warning: Delete permission requires write permission")
permissions.append('write')
# Checkbox with validation
environments = questionary.checkbox(
"Select deployment environments:",
choices=[
Choice('Development', value='dev', checked=True),
Choice('Staging', value='staging'),
Choice('Production', value='prod'),
Choice('Testing', value='test', checked=True)
],
validate=lambda choices: (
'dev' in choices or "Development environment is required"
)
).ask()
# Additional validation
if 'prod' in environments and 'staging' not in environments:
print("\n⚠️ Warning: Staging environment is recommended before production")
answers = {
'features': features,
'devTools': dev_tools,
'plugins': plugins,
'permissions': permissions,
'environments': environments
}
print("\n✅ Selected options:")
import json
print(json.dumps(answers, indent=2))
# Example: Process selections
print("\n📦 Installing selected features...")
for feature in features:
print(f" - {feature}")
return answers
def grouped_checkbox_example():
"""Example with logically grouped checkboxes"""
print("\n📂 Grouped Checkbox Example\n")
security_features = questionary.checkbox(
"Select security features:",
choices=[
Separator('=== Authentication ==='),
Choice('JWT Tokens', value='jwt', checked=True),
Choice('OAuth 2.0', value='oauth'),
Choice('Session Management', value='session'),
Choice('Two-Factor Auth', value='2fa'),
Separator('=== Authorization ==='),
Choice('Role-Based Access Control', value='rbac', checked=True),
Choice('Permission System', value='permissions', checked=True),
Choice('API Key Management', value='api-keys'),
Separator('=== Security ==='),
Choice('Rate Limiting', value='rate-limit', checked=True),
Choice('CORS Configuration', value='cors', checked=True),
Choice('Input Sanitization', value='sanitization', checked=True),
Choice('SQL Injection Prevention', value='sql-prevent', checked=True),
Choice('XSS Protection', value='xss-protect', checked=True),
Separator('=== Encryption ==='),
Choice('Data Encryption at Rest', value='encrypt-rest'),
Choice('SSL/TLS', value='ssl', checked=True),
Choice('Password Hashing', value='hash', checked=True)
],
validate=MinimumChoicesValidator(minimum=3, message="Select at least 3 security features")
).ask()
print(f"\n✅ Selected {len(security_features)} security features")
return {'securityFeatures': security_features}
def dependent_checkbox_example():
"""Example with checkboxes that depend on previous selections"""
print("\n🔗 Dependent Checkbox Example\n")
# First checkbox: Select cloud providers
cloud_providers = questionary.checkbox(
"Select cloud providers:",
choices=[
Choice('☁️ AWS', value='aws'),
Choice('☁️ Google Cloud', value='gcp'),
Choice('☁️ Azure', value='azure'),
Choice('☁️ DigitalOcean', value='do')
],
validate=lambda c: len(c) > 0 or "Select at least one cloud provider"
).ask()
# Second checkbox: AWS services (only if AWS selected)
aws_services = []
if 'aws' in cloud_providers:
aws_services = questionary.checkbox(
"Select AWS services:",
choices=[
Choice('EC2 - Virtual Servers', value='ec2'),
Choice('Lambda - Serverless', value='lambda'),
Choice('S3 - Object Storage', value='s3', checked=True),
Choice('RDS - Databases', value='rds'),
Choice('CloudFront - CDN', value='cloudfront')
]
).ask()
# Third checkbox: GCP services (only if GCP selected)
gcp_services = []
if 'gcp' in cloud_providers:
gcp_services = questionary.checkbox(
"Select GCP services:",
choices=[
Choice('Compute Engine', value='compute'),
Choice('Cloud Functions', value='functions'),
Choice('Cloud Storage', value='storage', checked=True),
Choice('Cloud SQL', value='sql'),
Choice('Cloud CDN', value='cdn')
]
).ask()
result = {
'cloudProviders': cloud_providers,
'awsServices': aws_services,
'gcpServices': gcp_services
}
print("\n✅ Configuration complete:")
import json
print(json.dumps(result, indent=2))
return result
def conditional_validation_example():
"""Example with conditional validation logic"""
print("\n🔍 Conditional Validation Example\n")
database_features = questionary.checkbox(
"Select database features:",
choices=[
Choice('Connection Pooling', value='pool', checked=True),
Choice('Migrations', value='migrations', checked=True),
Choice('Transactions', value='transactions'),
Choice('Replication', value='replication'),
Choice('Sharding', value='sharding'),
Choice('Caching', value='caching')
]
).ask()
# Conditional logic: Sharding requires replication
if 'sharding' in database_features and 'replication' not in database_features:
print("\n⚠️ Sharding requires replication. Adding replication...")
database_features.append('replication')
# Conditional logic: Caching works best with pooling
if 'caching' in database_features and 'pool' not in database_features:
add_pooling = questionary.confirm(
"Caching works best with connection pooling. Add it?",
default=True
).ask()
if add_pooling:
database_features.append('pool')
print(f"\n✅ Selected {len(database_features)} database features")
return {'databaseFeatures': database_features}
def main():
"""Run checkbox prompt examples"""
try:
print("=== Checkbox Prompt Examples ===")
# Example 1: Basic checkbox selections
checkbox_prompt_example()
# Example 2: Grouped checkboxes
grouped_checkbox_example()
# Example 3: Dependent checkboxes
dependent_checkbox_example()
# Example 4: Conditional validation
conditional_validation_example()
print("\n✅ Checkbox examples complete!")
except KeyboardInterrupt:
print("\n\n❌ User interrupted prompt")
exit(1)
except Exception as e:
print(f"\n\n❌ Error: {e}")
exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,501 @@
"""
Conditional Prompt Template
Use for: Dynamic forms based on previous answers
Features: Skip logic, dependent questions, branching
"""
import questionary
from questionary import Choice, Separator
def conditional_prompt_example():
"""Example conditional prompts"""
print("\n🔀 Conditional Prompt Example\n")
# First question: Use database?
use_database = questionary.confirm(
"Do you want to use a database?",
default=True
).ask()
database_config = {}
if use_database:
# Database type
database_type = questionary.select(
"Select database type:",
choices=['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite', 'Redis']
).ask()
database_config['databaseType'] = database_type
# Host and port (not for SQLite)
if database_type != 'SQLite':
database_host = questionary.text(
"Database host:",
default="localhost"
).ask()
# Default ports based on database type
default_ports = {
'PostgreSQL': '5432',
'MySQL': '3306',
'MongoDB': '27017',
'Redis': '6379'
}
database_port = questionary.text(
"Database port:",
default=default_ports.get(database_type, '5432')
).ask()
database_config['host'] = database_host
database_config['port'] = database_port
# Database name
database_name = questionary.text(
"Database name:",
validate=lambda text: len(text) > 0 or "Database name required"
).ask()
database_config['databaseName'] = database_name
# Authentication
use_authentication = questionary.confirm(
"Do you want to use authentication?",
default=True
).ask()
if use_authentication:
database_username = questionary.text(
"Database username:",
validate=lambda text: len(text) > 0 or "Username required"
).ask()
database_password = questionary.password(
"Database password:"
).ask()
database_config['useAuthentication'] = True
database_config['username'] = database_username
# Don't store actual password in answers
# SSL (only for remote hosts)
if database_type != 'SQLite' and database_config.get('host') != 'localhost':
use_ssl = questionary.confirm(
"Use SSL connection?",
default=False
).ask()
if use_ssl:
ssl_cert_path = questionary.text(
"Path to SSL certificate:",
validate=lambda text: len(text) > 0 or "SSL certificate path required"
).ask()
database_config['useSSL'] = True
database_config['sslCertPath'] = ssl_cert_path
answers = {
'useDatabase': use_database,
'databaseConfig': database_config if use_database else None
}
print("\n✅ Configuration:")
import json
print(json.dumps(answers, indent=2))
return answers
def deployment_wizard():
"""Example: Deployment configuration wizard"""
print("\n🚀 Deployment Configuration Wizard\n")
# Environment
environment = questionary.select(
"Select deployment environment:",
choices=['Development', 'Staging', 'Production']
).ask()
config = {'environment': environment}
# Docker
use_docker = questionary.confirm(
"Deploy using Docker?",
default=True
).ask()
config['useDocker'] = use_docker
if use_docker:
docker_image = questionary.text(
"Docker image name:",
default="myapp:latest",
validate=lambda text: len(text) > 0 or "Docker image name required"
).ask()
config['dockerImage'] = docker_image
registry = questionary.select(
"Container registry:",
choices=[
'Docker Hub',
'GitHub Container Registry',
'AWS ECR',
'Google Artifact Registry'
]
).ask()
config['registry'] = registry
# Platform
platform = questionary.select(
"Deployment platform:",
choices=[
'AWS', 'Google Cloud', 'Azure',
'DigitalOcean', 'Vercel', 'Netlify', 'Self-hosted'
]
).ask()
config['platform'] = platform
# Platform-specific configuration
if platform == 'AWS':
aws_service = questionary.select(
"AWS service:",
choices=['ECS', 'EKS', 'Lambda', 'Elastic Beanstalk', 'EC2']
).ask()
config['awsService'] = aws_service
# Auto-scaling (only for certain services)
if aws_service in ['ECS', 'EKS']:
auto_scale = questionary.confirm(
"Enable auto-scaling?",
default=True
).ask()
config['autoScale'] = auto_scale
if auto_scale:
min_instances = questionary.text(
"Minimum instances:",
default="1",
validate=lambda text: text.isdigit() and int(text) > 0 or "Must be at least 1"
).ask()
max_instances = questionary.text(
"Maximum instances:",
default="10",
validate=lambda text: text.isdigit() and int(text) >= int(min_instances) or f"Must be at least {min_instances}"
).ask()
config['minInstances'] = int(min_instances)
config['maxInstances'] = int(max_instances)
elif platform == 'Google Cloud':
gcp_service = questionary.select(
"Google Cloud service:",
choices=['Cloud Run', 'GKE', 'App Engine', 'Compute Engine']
).ask()
config['gcpService'] = gcp_service
# CDN (only for production)
if environment == 'Production':
use_cdn = questionary.confirm(
"Use CDN for static assets?",
default=True
).ask()
config['useCDN'] = use_cdn
if use_cdn:
cdn_provider = questionary.select(
"CDN provider:",
choices=['CloudFlare', 'AWS CloudFront', 'Google Cloud CDN', 'Azure CDN']
).ask()
config['cdnProvider'] = cdn_provider
# Monitoring
setup_monitoring = questionary.confirm(
"Setup monitoring?",
default=True
).ask()
if setup_monitoring:
monitoring_tools = questionary.checkbox(
"Select monitoring tools:",
choices=['Prometheus', 'Grafana', 'Datadog', 'New Relic', 'Sentry'],
validate=lambda choices: len(choices) > 0 or "Select at least one tool"
).ask()
config['monitoringTools'] = monitoring_tools
print("\n✅ Deployment configuration complete!")
import json
print(json.dumps(config, indent=2))
return config
def feature_flag_wizard():
"""Example: Feature flag configuration"""
print("\n🎛️ Feature Flag Configuration\n")
# Feature name
feature_name = questionary.text(
"Feature name:",
validate=lambda text: text and text.replace('-', '').replace('_', '').islower() or "Use lowercase, hyphens, underscores only"
).ask()
# Enabled by default
enabled_by_default = questionary.confirm(
"Enabled by default?",
default=False
).ask()
config = {
'featureName': feature_name,
'enabledByDefault': enabled_by_default
}
# Rollout strategy
rollout_strategy = questionary.select(
"Rollout strategy:",
choices=[
'All users',
'Percentage rollout',
'User targeting',
'Beta users only',
'Manual control'
]
).ask()
config['rolloutStrategy'] = rollout_strategy
# Percentage rollout
if rollout_strategy == 'Percentage rollout':
rollout_percentage = questionary.text(
"Rollout percentage (0-100):",
default="10",
validate=lambda text: text.isdigit() and 0 <= int(text) <= 100 or "Must be between 0 and 100"
).ask()
config['rolloutPercentage'] = int(rollout_percentage)
# User targeting
if rollout_strategy == 'User targeting':
target_user_groups = questionary.checkbox(
"Target user groups:",
choices=[
'Beta testers',
'Premium users',
'Internal team',
'Early adopters',
'Specific regions'
],
validate=lambda choices: len(choices) > 0 or "Select at least one group"
).ask()
config['targetUserGroups'] = target_user_groups
# Specific regions
if 'Specific regions' in target_user_groups:
target_regions = questionary.checkbox(
"Target regions:",
choices=[
'North America',
'Europe',
'Asia Pacific',
'South America',
'Africa'
]
).ask()
config['targetRegions'] = target_regions
# Metrics
enable_metrics = questionary.confirm(
"Track feature usage metrics?",
default=True
).ask()
if enable_metrics:
metrics = questionary.checkbox(
"Select metrics to track:",
choices=[
'Usage count',
'User adoption rate',
'Performance impact',
'Error rate',
'User feedback'
]
).ask()
config['metrics'] = metrics
# Expiration
add_expiration_date = questionary.confirm(
"Set feature flag expiration?",
default=False
).ask()
if add_expiration_date:
expiration_date = questionary.text(
"Expiration date (YYYY-MM-DD):",
validate=lambda text: len(text) == 10 and text.count('-') == 2 or "Use format YYYY-MM-DD"
).ask()
config['expirationDate'] = expiration_date
print("\n✅ Feature flag configured!")
import json
print(json.dumps(config, indent=2))
return config
def cicd_pipeline_wizard():
"""Example: CI/CD pipeline setup"""
print("\n⚙️ CI/CD Pipeline Configuration\n")
# Provider
provider = questionary.select(
"CI/CD provider:",
choices=['GitHub Actions', 'GitLab CI', 'CircleCI', 'Jenkins', 'Travis CI']
).ask()
config = {'provider': provider}
# Triggers
triggers = questionary.checkbox(
"Pipeline triggers:",
choices=[
'Push to main/master',
'Pull request',
'Tag creation',
'Manual trigger',
'Scheduled (cron)'
],
default=['Push to main/master', 'Pull request']
).ask()
config['triggers'] = triggers
# Cron schedule
if 'Scheduled (cron)' in triggers:
cron_schedule = questionary.text(
"Cron schedule:",
default="0 2 * * *",
validate=lambda text: len(text.split()) == 5 or "Invalid cron format (5 parts required)"
).ask()
config['cronSchedule'] = cron_schedule
# Stages
stages = questionary.checkbox(
"Pipeline stages:",
choices=['Build', 'Test', 'Lint', 'Security scan', 'Deploy'],
default=['Build', 'Test', 'Deploy'],
validate=lambda choices: len(choices) > 0 or "Select at least one stage"
).ask()
config['stages'] = stages
# Test types
if 'Test' in stages:
test_types = questionary.checkbox(
"Test types to run:",
choices=[
'Unit tests',
'Integration tests',
'E2E tests',
'Performance tests'
]
).ask()
config['testTypes'] = test_types
# Security tools
if 'Security scan' in stages:
security_tools = questionary.checkbox(
"Security scanning tools:",
choices=['Snyk', 'Dependabot', 'SonarQube', 'OWASP Dependency Check']
).ask()
config['securityTools'] = security_tools
# Deploy environments
if 'Deploy' in stages:
deploy_environments = questionary.checkbox(
"Deployment environments:",
choices=['Development', 'Staging', 'Production'],
default=['Staging', 'Production']
).ask()
config['deployEnvironments'] = deploy_environments
# Approval for production
if 'Production' in deploy_environments:
require_approval = questionary.confirm(
"Require manual approval for production?",
default=True
).ask()
config['requireApproval'] = require_approval
# Notifications
enable_notifications = questionary.confirm(
"Enable build notifications?",
default=True
).ask()
if enable_notifications:
notification_channels = questionary.checkbox(
"Notification channels:",
choices=['Email', 'Slack', 'Discord', 'Microsoft Teams']
).ask()
config['notificationChannels'] = notification_channels
print("\n✅ CI/CD pipeline configured!")
import json
print(json.dumps(config, indent=2))
return config
def main():
"""Run conditional prompt examples"""
try:
print("=== Conditional Prompt Examples ===")
# Example 1: Database configuration
conditional_prompt_example()
# Example 2: Deployment wizard
deployment_wizard()
# Example 3: Feature flag configuration
feature_flag_wizard()
# Example 4: CI/CD pipeline setup
cicd_pipeline_wizard()
print("\n✅ Conditional prompt examples complete!")
except KeyboardInterrupt:
print("\n\n❌ User interrupted prompt")
exit(1)
except Exception as e:
print(f"\n\n❌ Error: {e}")
exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,221 @@
"""
List Selection Prompt Template
Use for: Single choice from predefined options
Features: Arrow key navigation, search filtering
"""
import questionary
from questionary import Choice, Separator
def list_prompt_example():
"""Example list selection prompts"""
print("\n📋 List Selection Example\n")
# Simple list
framework = questionary.select(
"Choose your preferred framework:",
choices=[
'React',
'Vue',
'Angular',
'Svelte',
'Next.js',
'Nuxt.js'
],
default='React'
).ask()
# List with values
language = questionary.select(
"Choose programming language:",
choices=[
Choice('JavaScript', value='js'),
Choice('TypeScript', value='ts'),
Choice('Python', value='py'),
Choice('Ruby', value='rb'),
Choice('Go', value='go')
],
default='ts'
).ask()
# List with descriptions
package_manager = questionary.select(
"Choose package manager:",
choices=[
Choice('npm - Node Package Manager', value='npm', shortcut_key='n'),
Choice('yarn - Fast, reliable package manager', value='yarn', shortcut_key='y'),
Choice('pnpm - Fast, disk space efficient', value='pnpm', shortcut_key='p'),
Choice('bun - All-in-one toolkit', value='bun', shortcut_key='b')
]
).ask()
# List with separators
environment = questionary.select(
"Select deployment environment:",
choices=[
Separator('--- Cloud Platforms ---'),
'AWS',
'Google Cloud',
'Azure',
Separator('--- Serverless ---'),
'Vercel',
'Netlify',
'Cloudflare Workers',
Separator('--- Self-hosted ---'),
'Docker',
'Kubernetes'
]
).ask()
# List with emojis and styling
database = questionary.select(
"Choose database:",
choices=[
Choice('🐘 PostgreSQL (Relational)', value='postgresql'),
Choice('🐬 MySQL (Relational)', value='mysql'),
Choice('🍃 MongoDB (Document)', value='mongodb'),
Choice('⚡ Redis (Key-Value)', value='redis'),
Choice('📊 SQLite (Embedded)', value='sqlite'),
Choice('🔥 Supabase (PostgreSQL + APIs)', value='supabase')
],
use_shortcuts=True,
use_arrow_keys=True
).ask()
answers = {
'framework': framework,
'language': language,
'packageManager': package_manager,
'environment': environment,
'database': database
}
print("\n✅ Selections:")
import json
print(json.dumps(answers, indent=2))
return answers
def dynamic_list_example():
"""Example with dynamic choices based on context"""
print("\n🔄 Dynamic List Example\n")
# First selection
project_type = questionary.select(
"Project type:",
choices=['Web Application', 'CLI Tool', 'API/Backend', 'Library']
).ask()
# Dynamic framework choices based on project type
framework_choices = {
'Web Application': ['React', 'Vue', 'Angular', 'Svelte', 'Next.js'],
'CLI Tool': ['Commander.js', 'Yargs', 'Click', 'Typer', 'Cobra'],
'API/Backend': ['Express', 'Fastify', 'Flask', 'FastAPI', 'Gin'],
'Library': ['TypeScript', 'JavaScript', 'Python', 'Go', 'Rust']
}
framework = questionary.select(
f"Choose framework for {project_type}:",
choices=framework_choices.get(project_type, ['None'])
).ask()
print(f"\n✅ Selected: {project_type} with {framework}")
return {'projectType': project_type, 'framework': framework}
def categorized_list_example():
"""Example with categorized options"""
print("\n📂 Categorized List Example\n")
cloud_service = questionary.select(
"Choose cloud service:",
choices=[
Separator('=== Compute ==='),
Choice('EC2 - Virtual Servers', value='ec2'),
Choice('Lambda - Serverless Functions', value='lambda'),
Choice('ECS - Container Service', value='ecs'),
Choice('EKS - Kubernetes Service', value='eks'),
Separator('=== Storage ==='),
Choice('S3 - Object Storage', value='s3'),
Choice('EBS - Block Storage', value='ebs'),
Choice('EFS - File System', value='efs'),
Separator('=== Database ==='),
Choice('RDS - Relational Database', value='rds'),
Choice('DynamoDB - NoSQL Database', value='dynamodb'),
Choice('ElastiCache - In-Memory Cache', value='elasticache'),
Separator('=== Other ==='),
Choice('CloudFront - CDN', value='cloudfront'),
Choice('Route53 - DNS', value='route53'),
Choice('SQS - Message Queue', value='sqs')
],
use_indicator=True
).ask()
print(f"\n✅ Selected: {cloud_service}")
return {'cloudService': cloud_service}
def numbered_list_example():
"""Example with numbered choices for easier selection"""
print("\n🔢 Numbered List Example\n")
languages = [
'Python', 'JavaScript', 'TypeScript', 'Go', 'Rust',
'Java', 'C++', 'Ruby', 'PHP', 'Swift'
]
# Add numbers to choices for easier reference
numbered_choices = [
Choice(f"{i+1}. {lang}", value=lang)
for i, lang in enumerate(languages)
]
language = questionary.select(
"Choose programming language:",
choices=numbered_choices,
use_shortcuts=False # Disable letter shortcuts when using numbers
).ask()
print(f"\n✅ Selected: {language}")
return {'language': language}
def main():
"""Run list prompt examples"""
try:
print("=== List Selection Examples ===")
# Example 1: Basic list selections
list_prompt_example()
# Example 2: Dynamic choices
dynamic_list_example()
# Example 3: Categorized options
categorized_list_example()
# Example 4: Numbered list
numbered_list_example()
print("\n✅ List selection examples complete!")
except KeyboardInterrupt:
print("\n\n❌ User interrupted prompt")
exit(1)
except Exception as e:
print(f"\n\n❌ Error: {e}")
exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,366 @@
"""
Password Prompt Template
Use for: Sensitive input (credentials, tokens)
Features: Hidden input, confirmation, validation
"""
import questionary
import re
from questionary import ValidationError, Validator
class PasswordStrengthValidator(Validator):
"""Validator for password strength requirements"""
def __init__(self, min_length=8, require_uppercase=True, require_lowercase=True,
require_digit=True, require_special=True):
self.min_length = min_length
self.require_uppercase = require_uppercase
self.require_lowercase = require_lowercase
self.require_digit = require_digit
self.require_special = require_special
def validate(self, document):
password = document.text
issues = []
if len(password) < self.min_length:
issues.append(f"at least {self.min_length} characters")
if self.require_uppercase and not re.search(r'[A-Z]', password):
issues.append("an uppercase letter")
if self.require_lowercase and not re.search(r'[a-z]', password):
issues.append("a lowercase letter")
if self.require_digit and not re.search(r'[0-9]', password):
issues.append("a number")
if self.require_special and not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
issues.append("a special character")
if issues:
raise ValidationError(
message=f"Password must contain: {', '.join(issues)}",
cursor_position=len(password)
)
class APIKeyValidator(Validator):
"""Validator for API key format"""
def validate(self, document):
api_key = document.text
if len(api_key) == 0:
raise ValidationError(
message="API key is required",
cursor_position=0
)
if not (api_key.startswith('sk-') or api_key.startswith('pk-')):
raise ValidationError(
message='API key must start with "sk-" or "pk-"',
cursor_position=len(api_key)
)
if len(api_key) < 32:
raise ValidationError(
message="API key appears to be too short",
cursor_position=len(api_key)
)
def calculate_password_strength(password):
"""Calculate password strength score"""
strength = 0
if len(password) >= 8:
strength += 1
if len(password) >= 12:
strength += 1
if re.search(r'[a-z]', password):
strength += 1
if re.search(r'[A-Z]', password):
strength += 1
if re.search(r'[0-9]', password):
strength += 1
if re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
strength += 1
levels = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong', 'Very Strong']
return levels[min(strength, len(levels) - 1)]
def password_prompt_example():
"""Example password prompts with validation"""
print("\n🔒 Password Prompt Example\n")
# Password with strength validation
password = questionary.password(
"Enter your password:",
validate=PasswordStrengthValidator(min_length=8)
).ask()
# Confirm password
confirm_password = questionary.password(
"Confirm your password:",
validate=lambda text: text == password or "Passwords do not match"
).ask()
print(f"\n✅ Password strength: {calculate_password_strength(password)}")
# API key input
api_key = questionary.password(
"Enter your API key:",
validate=APIKeyValidator()
).ask()
print(f"✅ API key format: {api_key[:6]}...")
# Optional encryption key
encryption_key = questionary.password(
"Enter encryption key (optional, press Enter to skip):",
validate=lambda text: len(text) == 0 or len(text) >= 16 or "Encryption key must be at least 16 characters"
).ask()
# Don't log actual passwords!
answers = {
'passwordSet': True,
'passwordStrength': calculate_password_strength(password),
'apiKeyPrefix': api_key[:6],
'encryptionKeySet': len(encryption_key) > 0
}
print("\n✅ Credentials received (not displayed for security)")
import json
print(json.dumps(answers, indent=2))
return answers
def secure_account_setup():
"""Example: Complete secure account setup"""
print("\n🔐 Secure Account Setup\n")
# Username
username = questionary.text(
"Username:",
validate=lambda text: len(text) > 0 or "Username required"
).ask()
# Strong password
print("\n📝 Password requirements:")
print(" • At least 12 characters")
print(" • Uppercase and lowercase letters")
print(" • Numbers")
print(" • Special characters (!@#$%^&*)")
print()
password = questionary.password(
"Password:",
validate=PasswordStrengthValidator(
min_length=12,
require_uppercase=True,
require_lowercase=True,
require_digit=True,
require_special=True
)
).ask()
# Confirm password
confirm = questionary.password(
"Confirm password:",
validate=lambda text: text == password or "Passwords do not match"
).ask()
# Optional: Remember credentials
remember = questionary.confirm(
"Remember credentials? (stored securely)",
default=False
).ask()
strength = calculate_password_strength(password)
print(f"\n✅ Account created for: {username}")
print(f"🔒 Password strength: {strength}")
if remember:
print("💾 Credentials will be stored securely")
return {
'username': username,
'passwordStrength': strength,
'remember': remember
}
def database_credentials_setup():
"""Example: Database connection credentials"""
print("\n🗄️ Database Credentials Setup\n")
# Database username
db_user = questionary.text(
"Database username:",
default="postgres",
validate=lambda text: len(text) > 0 or "Username required"
).ask()
# Database password
db_password = questionary.password(
"Database password:",
validate=lambda text: len(text) >= 8 or "Password must be at least 8 characters"
).ask()
# Admin password (if needed)
is_admin = questionary.confirm(
"Create admin user?",
default=False
).ask()
admin_password = None
if is_admin:
admin_password = questionary.password(
"Admin password:",
validate=PasswordStrengthValidator(min_length=12)
).ask()
admin_confirm = questionary.password(
"Confirm admin password:",
validate=lambda text: text == admin_password or "Passwords do not match"
).ask()
print(f"\n✅ Admin password strength: {calculate_password_strength(admin_password)}")
credentials = {
'dbUser': db_user,
'dbPasswordSet': True,
'adminConfigured': is_admin
}
print("\n✅ Database credentials configured")
import json
print(json.dumps(credentials, indent=2))
return credentials
def api_token_setup():
"""Example: API token and secret key setup"""
print("\n🔑 API Token Setup\n")
# API key
api_key = questionary.password(
"Enter API key:",
validate=lambda text: len(text) > 0 or "API key required"
).ask()
# Secret key
secret_key = questionary.password(
"Enter secret key:",
validate=lambda text: len(text) >= 32 or "Secret key must be at least 32 characters"
).ask()
# Webhook secret (optional)
use_webhooks = questionary.confirm(
"Configure webhook authentication?",
default=False
).ask()
webhook_secret = None
if use_webhooks:
webhook_secret = questionary.password(
"Webhook secret:",
validate=lambda text: len(text) >= 16 or "Webhook secret must be at least 16 characters"
).ask()
# Environment
environment = questionary.select(
"Environment:",
choices=['Development', 'Staging', 'Production']
).ask()
config = {
'apiKeySet': True,
'secretKeySet': True,
'webhookConfigured': use_webhooks,
'environment': environment
}
print("\n✅ API credentials configured")
print(f"Environment: {environment}")
return config
def password_change_flow():
"""Example: Password change with old password verification"""
print("\n🔄 Change Password\n")
# Old password (in real app, verify against stored hash)
old_password = questionary.password(
"Enter current password:",
validate=lambda text: len(text) > 0 or "Current password required"
).ask()
# New password
new_password = questionary.password(
"Enter new password:",
validate=PasswordStrengthValidator(min_length=8)
).ask()
# Ensure new password is different
if new_password == old_password:
print("\n❌ New password must be different from current password")
return password_change_flow()
# Confirm new password
confirm_password = questionary.password(
"Confirm new password:",
validate=lambda text: text == new_password or "Passwords do not match"
).ask()
print(f"\n✅ Password changed successfully")
print(f"🔒 New password strength: {calculate_password_strength(new_password)}")
return {'passwordChanged': True}
def main():
"""Run password prompt examples"""
try:
print("=== Password Prompt Examples ===")
# Example 1: Basic password prompts
password_prompt_example()
# Example 2: Secure account setup
secure_account_setup()
# Example 3: Database credentials
database_credentials_setup()
# Example 4: API token setup
api_token_setup()
# Example 5: Password change
password_change_flow()
print("\n✅ Password prompt examples complete!")
except KeyboardInterrupt:
print("\n\n❌ User interrupted prompt")
exit(1)
except Exception as e:
print(f"\n\n❌ Error: {e}")
exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,220 @@
"""
Text Input Prompt Template
Use for: Names, emails, URLs, paths, free-form text
Features: Validation, default values, transform
"""
import questionary
import re
from questionary import ValidationError, Validator
class UsernameValidator(Validator):
"""Validate username format"""
def validate(self, document):
text = document.text
if len(text) == 0:
raise ValidationError(
message='Username is required',
cursor_position=len(text)
)
if len(text) < 3:
raise ValidationError(
message='Username must be at least 3 characters',
cursor_position=len(text)
)
if not re.match(r'^[a-zA-Z0-9_-]+$', text):
raise ValidationError(
message='Username can only contain letters, numbers, hyphens, and underscores',
cursor_position=len(text)
)
class EmailValidator(Validator):
"""Validate email format"""
def validate(self, document):
text = document.text
email_regex = r'^[^\s@]+@[^\s@]+\.[^\s@]+$'
if not re.match(email_regex, text):
raise ValidationError(
message='Invalid email address',
cursor_position=len(text)
)
class URLValidator(Validator):
"""Validate URL format"""
def validate(self, document):
text = document.text
if len(text) == 0:
return # Optional field
url_regex = r'^https?://.+'
if not re.match(url_regex, text):
raise ValidationError(
message='Must be a valid URL (http:// or https://)',
cursor_position=len(text)
)
class AgeValidator(Validator):
"""Validate age range"""
def validate(self, document):
text = document.text
try:
age = int(text)
if age < 18:
raise ValidationError(
message='You must be at least 18 years old',
cursor_position=len(text)
)
if age > 120:
raise ValidationError(
message='Please enter a realistic age',
cursor_position=len(text)
)
except ValueError:
raise ValidationError(
message='Please enter a valid number',
cursor_position=len(text)
)
class BioValidator(Validator):
"""Validate bio length"""
def validate(self, document):
text = document.text
if len(text) > 200:
raise ValidationError(
message='Bio must be 200 characters or less',
cursor_position=len(text)
)
def text_prompt_example():
"""Example text input prompts with validation"""
print("\n📝 Text Input Example\n")
# Username input
username = questionary.text(
"Enter your username:",
validate=UsernameValidator
).ask()
# Email input
email = questionary.text(
"Enter your email:",
validate=EmailValidator
).ask()
# Website input (optional)
website = questionary.text(
"Enter your website (optional):",
default="",
validate=URLValidator
).ask()
# Age input with conversion
age_str = questionary.text(
"Enter your age:",
validate=AgeValidator
).ask()
age = int(age_str)
# Bio input
bio = questionary.text(
"Enter a short bio:",
validate=BioValidator,
multiline=False
).ask()
answers = {
'username': username.lower(),
'email': email,
'website': website,
'age': age,
'bio': bio
}
print("\n✅ Answers received:")
import json
print(json.dumps(answers, indent=2))
return answers
# Alternative: Using lambda validators
def lambda_validator_example():
"""Example using lambda validators for simpler cases"""
print("\n📝 Lambda Validator Example\n")
# Simple required field
name = questionary.text(
"Name:",
validate=lambda text: len(text) > 0 or "Name is required"
).ask()
# Email validation
email = questionary.text(
"Email:",
validate=lambda text: bool(re.match(r'^[^\s@]+@[^\s@]+\.[^\s@]+$', text)) or "Invalid email"
).ask()
# Numeric validation
port = questionary.text(
"Port number:",
default="8000",
validate=lambda text: text.isdigit() and 1 <= int(text) <= 65535 or "Invalid port (1-65535)"
).ask()
# Path validation
path = questionary.text(
"Project path:",
default="./my-project",
validate=lambda text: len(text) > 0 or "Path is required"
).ask()
answers = {
'name': name,
'email': email,
'port': int(port),
'path': path
}
print("\n✅ Answers received:")
import json
print(json.dumps(answers, indent=2))
return answers
def main():
"""Run text prompt examples"""
try:
print("=== Text Prompt Examples ===")
# Example 1: Class-based validators
text_prompt_example()
# Example 2: Lambda validators
lambda_validator_example()
print("\n✅ Text prompt examples complete!")
except KeyboardInterrupt:
print("\n\n❌ User interrupted prompt")
exit(1)
except Exception as e:
print(f"\n\n❌ Error: {e}")
exit(1)
if __name__ == "__main__":
main()