Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:28:10 +08:00
commit cc8f6e6dfa
15 changed files with 6805 additions and 0 deletions

674
commands/cli-enhance.md Normal file
View File

@@ -0,0 +1,674 @@
---
name: cli-enhance
description: Add features to existing CLI applications like colors, progress bars, shell completions, and better error messages
---
# CLI Enhance Command
Add modern CLI features to an existing Rust CLI application, including colors, progress bars, interactive prompts, shell completions, and beautiful error messages.
## Arguments
- `$1` - Feature to add: "colors", "progress", "prompts", "completions", "errors", "config", "logging", or "all" (required)
- `$2` - Path to project directory (optional, defaults to current directory)
## Usage
```bash
# Add all enhancements
/cli-enhance all
# Add specific feature
/cli-enhance colors
/cli-enhance progress
/cli-enhance completions
# Enhance specific project
/cli-enhance colors /path/to/my-cli
```
## Available Enhancements
### 1. Colors and Styling
Add semantic colors to CLI output using owo-colors.
**What Gets Added:**
- Dependency: `owo-colors`
- Dependency: `supports-color` (for detection)
- Color module with semantic helpers
- NO_COLOR environment variable support
- Terminal capability detection
**Example Implementation:**
```rust
// src/colors.rs
use owo_colors::{OwoColorize, Stream};
pub fn success(message: &str) {
println!(
"{} {}",
"".if_supports_color(Stream::Stdout, |text| text.green().bold()),
message
);
}
pub fn error(message: &str) {
eprintln!(
"{} {}",
"".if_supports_color(Stream::Stderr, |text| text.red().bold()),
message
);
}
pub fn warning(message: &str) {
println!(
"{} {}",
"".if_supports_color(Stream::Stdout, |text| text.yellow().bold()),
message
);
}
pub fn info(message: &str) {
println!(
"{} {}",
"".if_supports_color(Stream::Stdout, |text| text.blue().bold()),
message
);
}
pub fn supports_color() -> bool {
use supports_color::Stream as ColorStream;
supports_color::on(ColorStream::Stdout).is_some()
}
```
**Usage in Code:**
```rust
use crate::colors;
colors::success("Build completed!");
colors::error("Failed to read file");
colors::warning("Configuration incomplete");
colors::info("Processing 10 files");
```
### 2. Progress Bars and Spinners
Add visual feedback for long-running operations using indicatif.
**What Gets Added:**
- Dependency: `indicatif`
- Progress module with common patterns
- Spinner for indeterminate operations
- Progress bars with custom styling
- Multi-progress for parallel tasks
**Example Implementation:**
```rust
// src/progress.rs
use indicatif::{ProgressBar, ProgressStyle, MultiProgress, HumanDuration};
use std::time::Duration;
pub fn create_progress_bar(total: u64) -> ProgressBar {
let pb = ProgressBar::new(total);
pb.set_style(
ProgressStyle::default_bar()
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
.unwrap()
.progress_chars("#>-")
);
pb
}
pub fn create_spinner(message: &str) -> ProgressBar {
let spinner = ProgressBar::new_spinner();
spinner.set_style(
ProgressStyle::default_spinner()
.template("{spinner:.green} {msg}")
.unwrap()
.tick_strings(&["", "", "", "", "", "", "", "", "", ""])
);
spinner.set_message(message.to_string());
spinner
}
pub fn create_multi_progress() -> MultiProgress {
MultiProgress::new()
}
```
**Usage in Code:**
```rust
use crate::progress;
// Progress bar for known total
let pb = progress::create_progress_bar(100);
for i in 0..100 {
// Do work
pb.inc(1);
}
pb.finish_with_message("Complete!");
// Spinner for unknown duration
let spinner = progress::create_spinner("Processing...");
// Do work
spinner.finish_with_message("Done!");
```
### 3. Interactive Prompts
Add user-friendly interactive prompts using dialoguer.
**What Gets Added:**
- Dependency: `dialoguer`
- Prompts module with common patterns
- Confirmation prompts
- Text input with validation
- Selection menus
- Multi-select options
**Example Implementation:**
```rust
// src/prompts.rs
use dialoguer::{
Confirm, Input, Select, MultiSelect, Password,
theme::ColorfulTheme
};
use anyhow::Result;
pub fn confirm(prompt: &str, default: bool) -> Result<bool> {
Ok(Confirm::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.default(default)
.interact()?)
}
pub fn input(prompt: &str, default: Option<String>) -> Result<String> {
let mut input = Input::with_theme(&ColorfulTheme::default())
.with_prompt(prompt);
if let Some(d) = default {
input = input.default(d);
}
Ok(input.interact_text()?)
}
pub fn select<T: ToString>(prompt: &str, items: &[T]) -> Result<usize> {
Ok(Select::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.items(items)
.interact()?)
}
pub fn multi_select<T: ToString>(prompt: &str, items: &[T]) -> Result<Vec<usize>> {
Ok(MultiSelect::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.items(items)
.interact()?)
}
pub fn password(prompt: &str, confirm: bool) -> Result<String> {
if confirm {
Ok(Password::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.with_confirmation("Confirm password", "Passwords don't match")
.interact()?)
} else {
Ok(Password::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.interact()?)
}
}
```
**Usage in Code:**
```rust
use crate::prompts;
// Confirmation
if prompts::confirm("Continue with deployment?", false)? {
deploy()?;
}
// Text input
let name = prompts::input("Project name", Some("my-project".to_string()))?;
// Selection
let envs = vec!["dev", "staging", "production"];
let idx = prompts::select("Select environment", &envs)?;
```
### 4. Shell Completions
Add shell completion generation support.
**What Gets Added:**
- Dependency: `clap_complete`
- Completion generation command
- Support for bash, zsh, fish, powershell
- Installation instructions
**Example Implementation:**
```rust
// src/completions.rs
use clap::CommandFactory;
use clap_complete::{generate, Generator, Shell};
use std::io;
pub fn generate_completions<G: Generator>(gen: G) {
let mut cmd = crate::cli::Cli::command();
generate(gen, &mut cmd, cmd.get_name().to_string(), &mut io::stdout());
}
pub fn print_install_instructions(shell: Shell) {
match shell {
Shell::Bash => {
eprintln!("To install completions, add to ~/.bashrc:");
eprintln!(" eval \"$(myapp --generate bash)\"");
}
Shell::Zsh => {
eprintln!("To install completions, add to ~/.zshrc:");
eprintln!(" eval \"$(myapp --generate zsh)\"");
}
Shell::Fish => {
eprintln!("To install completions:");
eprintln!(" myapp --generate fish | source");
eprintln!(" Or save to: ~/.config/fish/completions/myapp.fish");
}
Shell::PowerShell => {
eprintln!("To install completions, add to $PROFILE:");
eprintln!(" Invoke-Expression (& myapp --generate powershell)");
}
_ => {}
}
}
```
**Add to CLI:**
```rust
// src/cli.rs
use clap::{Parser, ValueEnum};
#[derive(Parser)]
pub struct Cli {
/// Generate shell completions
#[arg(long = "generate", value_enum)]
pub generate: Option<Shell>,
// ... other fields
}
#[derive(ValueEnum, Clone)]
pub enum Shell {
Bash,
Zsh,
Fish,
PowerShell,
}
```
### 5. Beautiful Error Messages
Upgrade error handling with miette for rich diagnostics.
**What Gets Added:**
- Dependency: `miette` with `fancy` feature
- Structured error types
- Source code snippets in errors
- Help text and suggestions
- Error URLs
**Example Implementation:**
```rust
// src/error.rs
use miette::{Diagnostic, SourceSpan};
use thiserror::Error;
#[derive(Error, Debug, Diagnostic)]
#[error("Configuration error")]
#[diagnostic(
code(config::invalid),
url("https://example.com/docs/config"),
help("Check your configuration file syntax")
)]
pub struct ConfigError {
#[source_code]
pub src: String,
#[label("this field is invalid")]
pub span: SourceSpan,
#[help]
pub advice: Option<String>,
}
#[derive(Error, Debug, Diagnostic)]
pub enum AppError {
#[error("File not found: {path}")]
#[diagnostic(
code(app::file_not_found),
help("Check that the file exists and you have permission to read it")
)]
FileNotFound {
path: String,
},
#[error("Build failed")]
#[diagnostic(
code(app::build_failed),
help("Run with -vv for detailed logs")
)]
BuildFailed {
#[source]
source: anyhow::Error,
},
}
```
**Update main.rs:**
```rust
fn main() -> miette::Result<()> {
miette::set_panic_hook();
// Rest of application
}
```
### 6. Configuration Management
Add comprehensive configuration system.
**What Gets Added:**
- Dependency: `config`
- Dependency: `serde`
- Dependency: `toml`
- Dependency: `directories`
- Config module with precedence handling
- XDG directory support
- Environment variable support
**Example Implementation:**
```rust
// src/config.rs
use config::{Config as ConfigBuilder, Environment, File};
use directories::ProjectDirs;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use anyhow::Result;
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
pub general: General,
pub features: Features,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct General {
pub log_level: String,
pub timeout: u64,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Features {
pub colors: bool,
pub progress: bool,
}
impl Config {
pub fn load(cli_config: Option<PathBuf>) -> Result<Self> {
let mut builder = ConfigBuilder::builder()
.set_default("general.log_level", "info")?
.set_default("general.timeout", 30)?
.set_default("features.colors", true)?
.set_default("features.progress", true)?;
// Load from standard locations
if let Some(proj_dirs) = ProjectDirs::from("com", "example", "myapp") {
let config_dir = proj_dirs.config_dir();
builder = builder
.add_source(File::from(config_dir.join("config.toml")).required(false));
}
// Override with CLI-specified config
if let Some(path) = cli_config {
builder = builder.add_source(File::from(path));
}
// Environment variables override everything
builder = builder.add_source(
Environment::with_prefix("MYAPP")
.separator("_")
.try_parsing(true)
);
Ok(builder.build()?.try_deserialize()?)
}
pub fn write_default(path: &PathBuf) -> Result<()> {
let default = Config {
general: General {
log_level: "info".to_string(),
timeout: 30,
},
features: Features {
colors: true,
progress: true,
},
};
let toml = toml::to_string_pretty(&default)?;
std::fs::write(path, toml)?;
Ok(())
}
}
```
### 7. Structured Logging
Add tracing-based structured logging.
**What Gets Added:**
- Dependency: `tracing`
- Dependency: `tracing-subscriber`
- Logging module with verbosity support
- Structured logging macros
**Example Implementation:**
```rust
// src/logging.rs
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
use anyhow::Result;
pub fn setup(verbosity: u8) -> Result<()> {
let level = match verbosity {
0 => "error",
1 => "warn",
2 => "info",
3 => "debug",
_ => "trace",
};
let env_filter = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new(level))?;
tracing_subscriber::registry()
.with(fmt::layer().with_target(false).with_level(true))
.with(env_filter)
.init();
Ok(())
}
```
**Usage:**
```rust
use tracing::{info, warn, error, debug};
info!("Starting build process");
debug!("Configuration: {:?}", config);
warn!("Using default value for missing field");
error!("Build failed: {}", error);
```
## Workflow
When you invoke this command:
1. **Analyze Current Project**
- Detect existing dependencies
- Identify CLI framework (Clap version)
- Check for existing features
- Find integration points
2. **Add Dependencies**
- Update Cargo.toml with new dependencies
- Add appropriate feature flags
- Ensure version compatibility
3. **Generate Code**
- Create new modules for features
- Add helper functions and patterns
- Integrate with existing code
4. **Update Existing Code**
- Replace println! with colored output
- Add progress bars to long operations
- Upgrade error types
- Add completion generation to CLI
5. **Add Documentation**
- Document new features in README
- Add inline code documentation
- Provide usage examples
6. **Verify Integration**
- Run cargo check
- Run tests
- Test new features
7. **Generate Report**
- List added features
- Show usage examples
- Provide next steps
## Example Output
```
✓ Analyzed project structure
✓ Added dependencies to Cargo.toml
✓ Created colors module (src/colors.rs)
✓ Created progress module (src/progress.rs)
✓ Created prompts module (src/prompts.rs)
✓ Updated CLI for completions
✓ Upgraded error types with miette
✓ Updated 15 call sites with new features
✓ Added documentation
Enhancements Applied Successfully!
Added Features:
• Colors and styling (owo-colors)
• Progress bars and spinners (indicatif)
• Interactive prompts (dialoguer)
• Shell completions (bash, zsh, fish, powershell)
• Beautiful error messages (miette)
New Dependencies:
owo-colors = "4"
indicatif = "0.17"
dialoguer = "0.11"
clap_complete = "4"
miette = { version = "7", features = ["fancy"] }
Files Modified:
• Cargo.toml (dependencies added)
• src/lib.rs (modules exported)
• src/cli.rs (completion flag added)
• src/main.rs (error handler updated)
Files Created:
• src/colors.rs
• src/progress.rs
• src/prompts.rs
• src/completions.rs
Updated Code Locations:
• src/commands/build.rs (added progress bar)
• src/commands/init.rs (added prompts)
• src/error.rs (upgraded to miette)
Usage Examples:
Colors:
use crate::colors;
colors::success("Build completed!");
colors::error("Failed to read file");
Progress:
use crate::progress;
let pb = progress::create_progress_bar(100);
pb.inc(1);
pb.finish_with_message("Done!");
Prompts:
use crate::prompts;
if prompts::confirm("Continue?", true)? {
// do something
}
Completions:
myapp --generate bash > /etc/bash_completion.d/myapp
myapp --generate zsh > ~/.zfunc/_myapp
Next Steps:
1. Review generated code
2. Test new features: cargo run
3. Update documentation if needed
4. Commit changes: git add . && git commit
```
## Implementation
Use the appropriate **rust-cli-developer** agents:
```
Use Task tool with subagent_type="rust-cli-developer:cli-ux-specialist"
for colors, progress, and prompts
Use Task tool with subagent_type="rust-cli-developer:cli-architect"
for configuration and logging
Use Task tool with subagent_type="rust-cli-developer:clap-expert"
for shell completions integration
```
## Notes
- Enhancements are additive and non-destructive
- Existing code is updated carefully to maintain functionality
- Dependencies are added with compatible versions
- All changes are tested before completion
- Documentation is updated to reflect new features
- Backward compatibility is maintained where possible

447
commands/cli-review.md Normal file
View File

@@ -0,0 +1,447 @@
---
name: cli-review
description: Review Rust CLI applications for UX, error handling, testing, and cross-platform compatibility
---
# CLI Review Command
Comprehensively review a Rust CLI application for code quality, user experience, error handling, testing coverage, and cross-platform compatibility.
## Arguments
- `$1` - Path to project directory (optional, defaults to current directory)
- `--focus` - Specific area to focus on: "ux", "errors", "tests", "config", "perf", or "all" (optional, default: "all")
## Usage
```bash
# Review current directory
/cli-review
# Review specific project
/cli-review /path/to/my-cli
# Focus on specific area
/cli-review --focus ux
/cli-review --focus errors
/cli-review --focus tests
```
## Review Areas
### 1. Argument Design & CLI Interface
**Checks:**
- [ ] Argument naming follows conventions (kebab-case)
- [ ] Short and long forms provided where appropriate
- [ ] Help text is clear and descriptive
- [ ] Defaults are sensible and documented
- [ ] Mutually exclusive args use proper groups
- [ ] Required args are clearly marked
- [ ] Value names are descriptive (FILE, PORT, URL)
- [ ] Global options work with all subcommands
- [ ] Version information is present
**Example Issues:**
```
❌ Issue: Unclear argument name
File: src/cli.rs:15
Found: #[arg(short, long)]
pub x: String,
Recommendation: Use descriptive names
#[arg(short, long, value_name = "FILE")]
pub input_file: PathBuf,
```
### 2. Help Text Quality
**Checks:**
- [ ] Command-level help is present
- [ ] All arguments have descriptions
- [ ] Long help provides examples
- [ ] Help text uses active voice
- [ ] Complex options have detailed explanations
- [ ] Examples section shows common usage
- [ ] After-help provides additional resources
**Example Issues:**
```
❌ Issue: Missing help text
File: src/cli.rs:23
Found: #[arg(short, long)]
pub verbose: bool,
Recommendation: Add descriptive help
/// Enable verbose output with detailed logging
#[arg(short, long)]
pub verbose: bool,
```
### 3. Error Messages
**Checks:**
- [ ] Errors explain what went wrong
- [ ] Errors suggest how to fix the problem
- [ ] File paths are displayed in error messages
- [ ] Using miette or similar for rich diagnostics
- [ ] Error types are well-structured (thiserror)
- [ ] Context is added at each error level
- [ ] Exit codes are meaningful and documented
- [ ] Errors go to stderr, not stdout
**Example Issues:**
```
❌ Issue: Unhelpful error message
File: src/commands/build.rs:42
Found: bail!("Build failed");
Recommendation: Provide context and solutions
bail!(
"Build failed: {}\n\n\
Possible causes:\n\
- Missing dependencies\n\
- Invalid configuration\n\
Try: cargo check",
source
);
```
### 4. User Experience
**Checks:**
- [ ] Progress indicators for long operations
- [ ] Colors used semantically (red=error, green=success)
- [ ] NO_COLOR environment variable respected
- [ ] Interactive prompts have --yes flag alternative
- [ ] Destructive operations require confirmation
- [ ] Output is well-formatted (tables, lists)
- [ ] Supports both human and machine-readable output
- [ ] Verbosity levels work correctly (-v, -vv, -vvv)
**Example Issues:**
```
⚠ Warning: Missing progress indicator
File: src/commands/download.rs:30
Found: Long-running download operation without feedback
Recommendation: Add progress bar
use indicatif::{ProgressBar, ProgressStyle};
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()...);
```
### 5. Configuration Management
**Checks:**
- [ ] Config file support implemented
- [ ] Environment variables supported
- [ ] Precedence is correct (defaults < file < env < CLI)
- [ ] Config file locations follow XDG spec
- [ ] Command to generate default config
- [ ] Config validation on load
- [ ] Sensitive data from env vars only
- [ ] Config errors are helpful
**Example Issues:**
```
❌ Issue: No environment variable support
File: src/config.rs:15
Found: Config only loaded from file
Recommendation: Support env vars
#[arg(long, env = "MYAPP_DATABASE_URL")]
pub database_url: String,
```
### 6. Cross-Platform Compatibility
**Checks:**
- [ ] Path handling uses std::path, not string concat
- [ ] File permissions checked before use
- [ ] Line endings handled correctly (CRLF vs LF)
- [ ] Platform-specific code properly cfg-gated
- [ ] Terminal width detection
- [ ] Color support detection
- [ ] Signal handling (Ctrl+C)
- [ ] Tests run on all platforms in CI
**Example Issues:**
```
❌ Issue: Hardcoded path separator
File: src/utils.rs:10
Found: let path = format!("{}/{}", dir, file);
Recommendation: Use Path::join
let path = Path::new(dir).join(file);
```
### 7. Testing Coverage
**Checks:**
- [ ] Integration tests present (assert_cmd)
- [ ] Help output tested
- [ ] Error cases tested
- [ ] Exit codes verified
- [ ] Config loading tested
- [ ] Environment variable handling tested
- [ ] Snapshot tests for output (insta)
- [ ] Cross-platform tests in CI
**Example Issues:**
```
⚠ Warning: No integration tests found
Expected: tests/integration.rs or tests/cli_tests.rs
Recommendation: Add integration tests
See: https://rust-cli.github.io/book/tutorial/testing.html
```
### 8. Performance
**Checks:**
- [ ] Startup time is reasonable (< 100ms for --help)
- [ ] Binary size is optimized
- [ ] Lazy loading for heavy dependencies
- [ ] Streaming for large files
- [ ] Async runtime only when needed
- [ ] Proper buffering for I/O
## Review Output Format
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CLI Review Report: my-cli
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Overall Rating: B+ (Good)
Summary:
✓ 23 checks passed
⚠ 5 warnings
❌ 3 issues found
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Issues Found
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
❌ CRITICAL: Missing error context
File: src/commands/build.rs:42
Line: return Err(e.into());
Problem: Errors are not wrapped with context
Impact: Users won't understand what failed
Recommendation:
return Err(e)
.context("Failed to build project")
.context("Check build configuration");
Priority: High
Effort: Low
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ WARNING: No progress indicator
File: src/commands/download.rs:55
Problem: Long operation without user feedback
Impact: Poor user experience, appears frozen
Recommendation:
Add indicatif progress bar for downloads
Priority: Medium
Effort: Low
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Strengths
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ Well-structured CLI with clear subcommands
✓ Good use of Clap derive API
✓ Proper error types with thiserror
✓ Configuration management implemented
✓ Cross-platform path handling
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Recommendations
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Priority: HIGH
1. Add error context to all error paths
2. Implement integration tests
3. Add --help examples section
Priority: MEDIUM
4. Add progress indicators for long operations
5. Implement shell completion generation
6. Add NO_COLOR support
Priority: LOW
7. Optimize binary size with strip = true
8. Add benchmarks for performance testing
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Detailed Metrics
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Code Quality: ████████░░ 80%
Error Handling: ██████░░░░ 60%
User Experience: ███████░░░ 70%
Testing: ████░░░░░░ 40%
Documentation: ████████░░ 80%
Cross-Platform: █████████░ 90%
Binary Size: 2.1 MB (Good)
Startup Time: 45ms (Excellent)
Test Coverage: 45% (Needs Improvement)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Next Steps
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Address critical issues (3 found)
2. Review and fix warnings (5 found)
3. Improve test coverage to >70%
4. Add missing documentation
Run with specific focus:
/cli-review --focus errors
/cli-review --focus ux
/cli-review --focus tests
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
## Workflow
When you invoke this command:
1. **Analyze Project Structure**
- Identify CLI framework (Clap, structopt, etc.)
- Locate main entry point and command definitions
- Map out module structure
2. **Review CLI Interface**
- Parse CLI definitions
- Check argument naming and documentation
- Verify help text quality
- Test help output
3. **Analyze Error Handling**
- Review error types
- Check error message quality
- Verify proper context addition
- Test error scenarios
4. **Check User Experience**
- Look for progress indicators
- Review color usage
- Check interactive prompts
- Verify output formatting
5. **Examine Configuration**
- Review config loading
- Check precedence implementation
- Verify env var support
- Test config validation
6. **Test Cross-Platform Support**
- Review path handling
- Check platform-specific code
- Verify CI configuration
- Test on different platforms
7. **Assess Testing**
- Count integration tests
- Check test coverage
- Review test quality
- Identify missing tests
8. **Generate Report**
- Compile findings
- Prioritize issues
- Provide recommendations
- Calculate metrics
## Implementation
Use the **rust-cli-developer** agents to perform the review:
```
Use Task tool with subagent_type="rust-cli-developer:cli-ux-specialist"
for UX and error message review
Use Task tool with subagent_type="rust-cli-developer:cli-testing-expert"
for test coverage analysis
Use Task tool with subagent_type="rust-cli-developer:cli-architect"
for architecture and cross-platform review
Use Task tool with subagent_type="rust-cli-developer:clap-expert"
for CLI interface review
```
## Focus Options
### UX Focus
Reviews only user experience aspects:
- Color usage
- Progress indicators
- Interactive prompts
- Output formatting
- Error messages
### Errors Focus
Reviews only error handling:
- Error types
- Error messages
- Context addition
- Exit codes
- Recovery strategies
### Tests Focus
Reviews only testing:
- Integration tests
- Test coverage
- Test quality
- Missing test scenarios
- CI configuration
### Config Focus
Reviews only configuration:
- Config loading
- Precedence
- Environment variables
- Validation
- Documentation
### Performance Focus
Reviews only performance:
- Startup time
- Binary size
- Memory usage
- I/O efficiency
- Async usage
## Notes
- Review is non-destructive (read-only analysis)
- Generates actionable recommendations
- Prioritizes issues by impact and effort
- Provides code examples for fixes
- Can be run in CI for automated checks

271
commands/cli-scaffold.md Normal file
View File

@@ -0,0 +1,271 @@
---
name: cli-scaffold
description: Scaffold new Rust CLI projects with Clap, error handling, logging, and testing setup
---
# CLI Scaffold Command
Scaffold a new Rust CLI application with best practices, proper structure, and all necessary dependencies configured.
## Arguments
- `$1` - Project name (required)
- `$2` - Project type: "simple", "subcommands", or "plugin" (optional, default: "simple")
## Usage
```bash
# Create a simple single-command CLI
/cli-scaffold my-cli simple
# Create a CLI with subcommands
/cli-scaffold my-cli subcommands
# Create a CLI with plugin architecture
/cli-scaffold my-cli plugin
```
## What Gets Created
The scaffold creates a complete Rust CLI project with:
### Dependencies
- **clap** (v4+) with derive feature for argument parsing
- **anyhow** for error handling in application code
- **thiserror** for library error types
- **miette** for beautiful error messages with diagnostics
- **tracing** + **tracing-subscriber** for structured logging
- **config** for configuration management
- **directories** for XDG directory support
- **serde** for configuration serialization
### Project Structure
```
my-cli/
├── Cargo.toml
├── src/
│ ├── main.rs # Entry point
│ ├── lib.rs # Library interface
│ ├── cli.rs # CLI definitions
│ ├── commands/ # Command implementations
│ │ └── mod.rs
│ ├── config.rs # Configuration management
│ ├── error.rs # Error types
│ └── logging.rs # Logging setup
├── tests/
│ └── integration.rs # Integration tests
├── config/
│ └── default.toml # Default configuration
└── README.md
```
### Features
1. **Clean architecture** - Library-first design, thin CLI wrapper
2. **Error handling** - miette for beautiful diagnostics, structured errors
3. **Logging** - Tracing with verbosity levels (-v, -vv, -vvv)
4. **Configuration** - TOML config with precedence (defaults < file < env < CLI)
5. **Testing** - Integration tests with assert_cmd pre-configured
6. **Shell completions** - Built-in completion generation
7. **Cross-platform** - Works on Windows, macOS, Linux
## Workflow
When you invoke this command:
1. **Gather Information**
- Confirm project name
- Select project type if not provided
- Ask about optional features (async support, additional crates)
2. **Create Project Structure**
- Run `cargo init` to create base project
- Set up directory structure (src/, tests/, config/)
- Create all necessary source files
3. **Configure Dependencies**
- Add all required dependencies to Cargo.toml
- Configure features appropriately
- Set up dev-dependencies for testing
4. **Generate Source Files**
- Create main.rs with proper error handling
- Set up lib.rs with module exports
- Create cli.rs with Clap definitions
- Generate command modules based on project type
- Set up error types with miette
- Configure logging with tracing
- Create configuration management code
5. **Add Testing Infrastructure**
- Create integration test file
- Add example tests for CLI commands
- Configure assert_cmd and assert_fs
6. **Documentation**
- Generate README.md with usage examples
- Add inline documentation to code
- Include configuration examples
7. **Finalize**
- Run `cargo check` to verify setup
- Run `cargo test` to ensure tests pass
- Display next steps to user
## Project Type Details
### Simple CLI
Single command application with arguments and flags.
**Example:**
```rust
// src/cli.rs
use clap::Parser;
#[derive(Parser)]
#[command(name = "my-cli")]
#[command(version, about, long_about = None)]
pub struct Cli {
/// Input file
#[arg(short, long)]
pub input: PathBuf,
/// Verbosity level
#[arg(short, long, action = clap::ArgAction::Count)]
pub verbose: u8,
}
```
### Subcommands CLI
Application with multiple subcommands (like git, cargo).
**Example:**
```rust
// src/cli.rs
use clap::{Parser, Subcommand};
#[derive(Parser)]
pub struct Cli {
#[arg(short, long, global = true, action = clap::ArgAction::Count)]
pub verbose: u8,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand)]
pub enum Command {
Init { name: String },
Build { release: bool },
Test { filter: Option<String> },
}
```
### Plugin-based CLI
Extensible architecture with plugin system.
**Features:**
- Plugin trait definition
- Plugin registry
- Dynamic plugin loading
- Plugin command routing
## Example Output
After running `/cli-scaffold my-cli subcommands`, you'll see:
```
✓ Created project structure
✓ Configured dependencies
✓ Generated source files
✓ Set up testing infrastructure
✓ Created documentation
Successfully scaffolded 'my-cli'!
Project structure:
my-cli/
├── Cargo.toml
├── src/
│ ├── main.rs
│ ├── lib.rs
│ ├── cli.rs
│ ├── commands/
│ │ ├── mod.rs
│ │ ├── init.rs
│ │ ├── build.rs
│ │ └── test.rs
│ ├── config.rs
│ ├── error.rs
│ └── logging.rs
├── tests/
│ └── integration.rs
└── README.md
Next steps:
cd my-cli
cargo build
cargo test
cargo run -- --help
Features included:
• Clap v4+ for argument parsing
• miette for beautiful error messages
• tracing for structured logging
• Configuration management (TOML)
• Integration tests with assert_cmd
• Shell completion generation
To add your logic:
1. Edit src/commands/*.rs to implement commands
2. Add tests in tests/integration.rs
3. Update config/default.toml if needed
Documentation:
• See README.md for usage examples
• Run with --help to see all options
• Use RUST_LOG=debug for detailed logs
```
## Additional Options
You can customize the scaffold with these options:
- `--async` - Add tokio runtime for async operations
- `--database` - Add sqlx for database support
- `--http` - Add reqwest for HTTP client functionality
- `--template <name>` - Use a custom template
## Implementation
Use the **rust-cli-developer** agent (any of the specialized agents as needed) to:
1. Validate inputs and gather requirements
2. Generate the complete project structure
3. Create all source files with proper implementations
4. Set up testing and documentation
5. Verify the project builds and tests pass
Invoke the agent with:
```
Use Task tool with subagent_type="rust-cli-developer:cli-architect"
```
The agent will handle all the implementation details and ensure the scaffolded project follows best practices for Rust CLI applications.
## Notes
- Projects are created in the current directory
- Will fail if directory already exists (safety check)
- Generated code includes inline documentation
- All dependencies use latest stable versions
- Cross-platform compatibility is ensured
- Follows Rust API guidelines

592
commands/cli-test.md Normal file
View File

@@ -0,0 +1,592 @@
---
name: cli-test
description: Generate comprehensive tests for Rust CLI applications including integration, snapshot, and property-based tests
---
# CLI Test Command
Generate comprehensive test suites for Rust CLI applications, including integration tests, snapshot tests for output, and property-based tests for input validation.
## Arguments
- `$1` - Test type: "integration", "snapshot", "property", or "all" (required)
- `$2` - Path to project directory (optional, defaults to current directory)
- `--command <name>` - Specific command to test (optional)
## Usage
```bash
# Generate all test types
/cli-test all
# Generate integration tests only
/cli-test integration
# Generate snapshot tests for specific command
/cli-test snapshot --command build
# Generate property-based tests
/cli-test property
# Test specific project
/cli-test all /path/to/my-cli
```
## Test Types
### 1. Integration Tests
Tests that run the actual CLI binary with different arguments and verify output, exit codes, and side effects.
**Generated Tests:**
```rust
// tests/integration_tests.rs
use assert_cmd::Command;
use assert_fs::prelude::*;
use predicates::prelude::*;
fn cmd() -> Command {
Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap()
}
#[test]
fn test_help_flag() {
cmd().arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Usage:"));
}
#[test]
fn test_version_flag() {
cmd().arg("--version")
.assert()
.success()
.stdout(predicate::str::contains(env!("CARGO_PKG_VERSION")));
}
#[test]
fn test_invalid_argument() {
cmd().arg("--invalid")
.assert()
.failure()
.stderr(predicate::str::contains("unexpected argument"));
}
#[test]
fn test_missing_required_arg() {
cmd().arg("build")
.assert()
.failure()
.stderr(predicate::str::contains("required arguments"));
}
#[test]
fn test_command_with_file_io() -> Result<(), Box<dyn std::error::Error>> {
let temp = assert_fs::TempDir::new()?;
let input = temp.child("input.txt");
input.write_str("test content")?;
let output = temp.child("output.txt");
cmd()
.arg("process")
.arg(input.path())
.arg("--output")
.arg(output.path())
.assert()
.success();
output.assert(predicate::path::exists());
output.assert(predicate::str::contains("TEST CONTENT"));
temp.close()?;
Ok(())
}
#[test]
fn test_exit_code_config_error() {
cmd()
.arg("--config")
.arg("/nonexistent/config.toml")
.assert()
.code(2)
.failure();
}
#[test]
fn test_env_var_override() -> Result<(), Box<dyn std::error::Error>> {
cmd()
.env("MYAPP_PORT", "9000")
.arg("config")
.arg("show")
.assert()
.success()
.stdout(predicate::str::contains("9000"));
Ok(())
}
```
### 2. Snapshot Tests
Tests that capture and compare command output to saved snapshots, useful for help text, formatted output, and error messages.
**Generated Tests:**
```rust
// tests/snapshots.rs
use assert_cmd::Command;
use insta::{assert_snapshot, with_settings};
fn cmd() -> Command {
Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap()
}
#[test]
fn test_help_output() {
let output = cmd()
.arg("--help")
.output()
.unwrap();
assert_snapshot!(String::from_utf8_lossy(&output.stdout));
}
#[test]
fn test_command_help() {
let output = cmd()
.arg("build")
.arg("--help")
.output()
.unwrap();
assert_snapshot!("build_help", String::from_utf8_lossy(&output.stdout));
}
#[test]
fn test_version_output() {
let output = cmd()
.arg("--version")
.output()
.unwrap();
assert_snapshot!(String::from_utf8_lossy(&output.stdout));
}
#[test]
fn test_error_message_format() {
let output = cmd()
.arg("build")
.arg("--invalid-option")
.output()
.unwrap();
assert_snapshot!(String::from_utf8_lossy(&output.stderr));
}
#[test]
fn test_formatted_output_with_filters() {
let output = cmd()
.arg("status")
.output()
.unwrap();
let stdout = String::from_utf8_lossy(&output.stdout);
// Filter out timestamps and dynamic data
with_settings!({
filters => vec![
(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}", "[TIMESTAMP]"),
(r"Duration: \d+ms", "Duration: [TIME]"),
(r"/[^\s]+/([^/\s]+)", "/path/to/$1"),
]
}, {
assert_snapshot!(stdout);
});
}
#[test]
fn test_table_output() -> Result<(), Box<dyn std::error::Error>> {
let output = cmd()
.arg("list")
.output()?;
with_settings!({
filters => vec![
(r"\d{4}-\d{2}-\d{2}", "[DATE]"),
]
}, {
assert_snapshot!(String::from_utf8_lossy(&output.stdout));
});
Ok(())
}
```
### 3. Property-Based Tests
Tests that verify CLI behavior across a wide range of inputs using property-based testing.
**Generated Tests:**
```rust
// tests/property_tests.rs
use assert_cmd::Command;
use proptest::prelude::*;
fn cmd() -> Command {
Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap()
}
proptest! {
#[test]
fn test_port_validation(port in 0u16..=65535) {
let result = cmd()
.arg("--port")
.arg(port.to_string())
.arg("validate")
.output()
.unwrap();
if (1024..=65535).contains(&port) {
assert!(result.status.success(),
"Port {} should be valid", port);
} else {
assert!(!result.status.success(),
"Port {} should be invalid", port);
}
}
#[test]
fn test_string_input_handling(s in "\\PC{0,100}") {
// CLI should handle any valid Unicode string without panicking
let result = cmd()
.arg("--name")
.arg(&s)
.arg("test")
.output();
// Should not panic, even if it returns an error
assert!(result.is_ok());
}
#[test]
fn test_file_path_handling(
parts in prop::collection::vec("[a-zA-Z0-9_-]{1,10}", 1..5)
) {
let path = parts.join("/");
let _result = cmd()
.arg("--path")
.arg(&path)
.output()
.unwrap();
// Should handle various path structures without panicking
}
#[test]
fn test_numeric_range_validation(n in -1000i32..1000i32) {
let result = cmd()
.arg("--count")
.arg(n.to_string())
.output()
.unwrap();
if n >= 0 {
assert!(result.status.success() ||
String::from_utf8_lossy(&result.stderr).contains("out of range"),
"Non-negative number should be handled");
} else {
assert!(!result.status.success(),
"Negative number should be rejected");
}
}
#[test]
fn test_list_argument(items in prop::collection::vec("[a-z]{3,8}", 0..10)) {
let result = cmd()
.arg("process")
.args(&items)
.output()
.unwrap();
// Should handle 0 to many items
assert!(result.status.success() || result.status.code() == Some(3));
}
}
```
### 4. Interactive Prompt Tests
Tests for interactive CLI features.
**Generated Tests:**
```rust
// tests/interactive_tests.rs
use assert_cmd::Command;
#[test]
fn test_confirmation_prompt_yes() -> Result<(), Box<dyn std::error::Error>> {
cmd()
.arg("delete")
.arg("resource")
.write_stdin("yes\n")
.assert()
.success()
.stdout(predicate::str::contains("Deleted"));
Ok(())
}
#[test]
fn test_confirmation_prompt_no() -> Result<(), Box<dyn std::error::Error>> {
cmd()
.arg("delete")
.arg("resource")
.write_stdin("no\n")
.assert()
.success()
.stdout(predicate::str::contains("Cancelled"));
Ok(())
}
#[test]
fn test_yes_flag_skips_prompt() -> Result<(), Box<dyn std::error::Error>> {
cmd()
.arg("delete")
.arg("resource")
.arg("--yes")
.assert()
.success()
.stdout(predicate::str::contains("Deleted"));
Ok(())
}
#[test]
fn test_non_interactive_mode() -> Result<(), Box<dyn std::error::Error>> {
cmd()
.arg("delete")
.env("CI", "true")
.assert()
.failure()
.stderr(predicate::str::contains("non-interactive"));
Ok(())
}
```
### 5. Cross-Platform Tests
Platform-specific tests for compatibility.
**Generated Tests:**
```rust
// tests/cross_platform_tests.rs
use assert_cmd::Command;
#[test]
#[cfg(target_os = "windows")]
fn test_windows_paths() -> Result<(), Box<dyn std::error::Error>> {
cmd()
.arg("--path")
.arg(r"C:\Users\test\file.txt")
.assert()
.success();
Ok(())
}
#[test]
#[cfg(not(target_os = "windows"))]
fn test_unix_paths() -> Result<(), Box<dyn std::error::Error>> {
cmd()
.arg("--path")
.arg("/home/test/file.txt")
.assert()
.success();
Ok(())
}
#[test]
fn test_cross_platform_path_handling() -> Result<(), Box<dyn std::error::Error>> {
let temp = assert_fs::TempDir::new()?;
let file = temp.child("test.txt");
file.write_str("content")?;
cmd()
.arg("process")
.arg(file.path())
.assert()
.success();
temp.close()?;
Ok(())
}
#[test]
#[cfg(target_os = "windows")]
fn test_windows_line_endings() -> Result<(), Box<dyn std::error::Error>> {
let temp = assert_fs::TempDir::new()?;
let input = temp.child("input.txt");
input.write_str("line1\r\nline2\r\nline3")?;
cmd()
.arg("process")
.arg(input.path())
.assert()
.success();
temp.close()?;
Ok(())
}
```
## Test Organization
Generated tests are organized into separate files:
```
tests/
├── integration_tests.rs # Basic integration tests
├── snapshots.rs # Snapshot tests
├── property_tests.rs # Property-based tests
├── interactive_tests.rs # Interactive prompt tests
├── cross_platform_tests.rs # Platform-specific tests
└── snapshots/ # Saved snapshots (insta)
├── snapshots__help_output.snap
├── snapshots__build_help.snap
└── ...
```
## Dependencies Added
```toml
[dev-dependencies]
assert_cmd = "2"
assert_fs = "1"
predicates = "3"
insta = "1"
proptest = "1"
```
## Workflow
When you invoke this command:
1. **Analyze CLI Structure**
- Parse CLI definitions (Clap structure)
- Identify commands and subcommands
- Extract argument definitions
- Find file I/O operations
2. **Generate Test Structure**
- Create test directory if needed
- Set up test modules
- Add necessary dependencies
3. **Generate Tests Based on Type**
- **Integration**: Tests for each command, success/failure paths
- **Snapshot**: Capture help text, error messages, formatted output
- **Property**: Input validation, edge cases
- **Interactive**: Prompt handling, --yes flag
- **Cross-platform**: Path handling, line endings
4. **Create Test Fixtures**
- Sample input files
- Config files for testing
- Expected output files
5. **Generate Helper Functions**
- Command builder helper
- Common assertions
- Fixture setup/teardown
6. **Verify Tests**
- Run generated tests
- Ensure they pass
- Report any issues
7. **Generate Documentation**
- Add comments explaining tests
- Document test organization
- Provide examples of adding more tests
## Example Output
```
✓ Analyzed CLI structure
✓ Found 3 commands: init, build, test
✓ Generated integration tests (12 tests)
✓ Generated snapshot tests (8 tests)
✓ Generated property-based tests (5 tests)
✓ Generated interactive tests (4 tests)
✓ Generated cross-platform tests (6 tests)
✓ Added test dependencies to Cargo.toml
✓ Created test fixtures
Test Suite Generated Successfully!
Files created:
tests/integration_tests.rs (12 tests)
tests/snapshots.rs (8 tests)
tests/property_tests.rs (5 tests)
tests/interactive_tests.rs (4 tests)
tests/cross_platform_tests.rs (6 tests)
Total: 35 tests
Run tests:
cargo test
Run specific test file:
cargo test --test integration_tests
Update snapshots (if needed):
cargo insta review
Coverage:
• All CLI commands tested
• Success and failure paths covered
• Help text snapshots captured
• Input validation tested
• Cross-platform compatibility verified
Next steps:
1. Review generated tests
2. Run: cargo test
3. Add custom test cases as needed
4. Update snapshots: cargo insta review
```
## Implementation
Use the **rust-cli-developer:cli-testing-expert** agent to:
1. Analyze the CLI structure
2. Generate appropriate tests
3. Set up test infrastructure
4. Create fixtures and helpers
5. Verify tests run correctly
Invoke with:
```
Use Task tool with subagent_type="rust-cli-developer:cli-testing-expert"
```
## Notes
- Generated tests are starting points; customize as needed
- Snapshot tests require manual review on first run
- Property tests may need adjustment for specific domains
- Interactive tests require stdin support
- Cross-platform tests should run in CI on multiple platforms
- Tests are non-destructive and use temporary directories