Files
gh-geoffjay-claude-plugins-…/commands/cli-enhance.md
2025-11-29 18:28:10 +08:00

675 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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