📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
---
|
||||
name: which-tool
|
||||
description: This skill should be used when choosing CLI tools, a tool seems slow, or when "best tool", "which tool", or "tool alternatives" are mentioned.
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# Use the Best Tool
|
||||
|
||||
Select optimal CLI tools → graceful fallback → research when needed.
|
||||
|
||||
<when_to_use>
|
||||
|
||||
- Choosing which tool for file search, content search, JSON processing
|
||||
- Tool taking unexpectedly long for task size
|
||||
- User expresses frustration with current tool
|
||||
- Task could be done more elegantly
|
||||
- Need to verify tool availability before recommending
|
||||
|
||||
NOT for: tasks where tool choice is predetermined, simple one-line commands
|
||||
|
||||
</when_to_use>
|
||||
|
||||
<detection>
|
||||
|
||||
Run detection script before selecting tools:
|
||||
|
||||
```bash
|
||||
bun /Users/mg/Developer/outfitter/agents/outfitter/skills/which-tool/scripts/index.ts
|
||||
```
|
||||
|
||||
Parse output to determine:
|
||||
- Available modern tools
|
||||
- Missing tools that could enhance workflow
|
||||
- System context (OS, package managers)
|
||||
|
||||
Cache results per session — no need to re-run unless tool availability changes.
|
||||
|
||||
</detection>
|
||||
|
||||
<selection>
|
||||
|
||||
Map task to best available tool:
|
||||
|
||||
| Task | Preferred | Fallback | Legacy | Notes |
|
||||
|------|-----------|----------|--------|-------|
|
||||
| Find files by name | `fd` | - | `find` | fd: faster, better defaults |
|
||||
| Search file contents | `rg` | - | `grep` | rg: respects .gitignore, faster |
|
||||
| AST-aware code search | `sg` | `rg` | `grep` | sg: structure-aware queries |
|
||||
| Process JSON | `jq` | - | `python`/`node` | jq: domain-specific language |
|
||||
| View file with syntax | `bat` | - | `cat` | bat: syntax highlighting, git diff |
|
||||
| List directory | `eza` | - | `ls` | eza: modern output, icons |
|
||||
| View git diff | `delta` | - | `git diff` | delta: side-by-side, syntax highlighting |
|
||||
| Navigate directories | `zoxide` | - | `cd` | zoxide: frecency-based jumping |
|
||||
| Fuzzy select | `fzf` | - | - | fzf: interactive filtering |
|
||||
| HTTP requests | `httpie` | - | `curl` | httpie: human-friendly syntax |
|
||||
|
||||
Selection algorithm:
|
||||
1. Check detection results for preferred tool
|
||||
2. If available → use with optimal flags
|
||||
3. If unavailable → check fallback column
|
||||
4. If no fallback → use legacy with best-effort flags
|
||||
5. Note gap if preferred tool would significantly improve workflow
|
||||
|
||||
</selection>
|
||||
|
||||
<fallback>
|
||||
|
||||
When preferred tool unavailable:
|
||||
|
||||
**Minor improvement** (preferred 10–30% better):
|
||||
- Use next best option silently
|
||||
- Don't interrupt workflow
|
||||
|
||||
**Significant improvement** (preferred 2x+ better):
|
||||
- Use fallback
|
||||
- Surface suggestion: `◇ Alternative: {TOOL} would be {BENEFIT} — install with {COMMAND}`
|
||||
- Continue without blocking
|
||||
|
||||
**Critical gap** (task extremely tedious with fallback):
|
||||
- Surface suggestion: `◆ Caution: {TOOL} recommended for this task — {FALLBACK} will be slow/limited`
|
||||
- Offer choice: install now, proceed anyway, defer task
|
||||
|
||||
Never block on missing tools — graceful degradation always.
|
||||
|
||||
</fallback>
|
||||
|
||||
<research>
|
||||
|
||||
Trigger research when:
|
||||
- Tool taking 3x+ longer than expected for task size
|
||||
- User explicitly asks for better approach
|
||||
- Task seems like it should have specialized tool
|
||||
- Current tool missing critical feature
|
||||
- New tool category needed (not in selection table)
|
||||
|
||||
Research workflow:
|
||||
1. Search for `{TASK} CLI tool 2025` or `{TASK} CLI tool 2024`
|
||||
2. Check GitHub trending in relevant category
|
||||
3. Evaluate candidates:
|
||||
- Speed: benchmarks vs existing tools
|
||||
- Ergonomics: default behavior, output format
|
||||
- Maintenance: last commit, issue response time
|
||||
- Install: complexity, dependencies
|
||||
- Compatibility: OS support, integration
|
||||
|
||||
Present findings:
|
||||
- Tool name + one-line description
|
||||
- Key advantages over current approach
|
||||
- Installation command
|
||||
- Usage example for current task
|
||||
- Trade-offs or caveats
|
||||
|
||||
If research yields strong candidate → add to selection table for future reference.
|
||||
|
||||
</research>
|
||||
|
||||
<workflow>
|
||||
|
||||
Standard flow:
|
||||
|
||||
1. **Receive task** → categorize task type (find files, search content, process data)
|
||||
2. **Check detection** → run script if not yet run this session
|
||||
3. **Select tool** → use selection table + detection results
|
||||
4. **Execute** → run command with optimal flags
|
||||
5. **Evaluate** → if slow/frustrating → trigger research
|
||||
|
||||
Research flow:
|
||||
|
||||
1. **Trigger identified** → surface to user with `△ This seems slow — research alternatives?`
|
||||
2. **User confirms** → web search for modern tools
|
||||
3. **Evaluate candidates** → speed, ergonomics, maintenance
|
||||
4. **Present findings** → tool + advantages + install + example
|
||||
5. **Update knowledge** → add to selection table if strong fit
|
||||
|
||||
</workflow>
|
||||
|
||||
<examples>
|
||||
|
||||
**Scenario: Search for authentication code**
|
||||
|
||||
Task: Find all files containing "authentication"
|
||||
Detection: rg available
|
||||
Selection: Use `rg` over `grep`
|
||||
|
||||
```bash
|
||||
rg "authentication" --type ts --type js
|
||||
```
|
||||
|
||||
**Scenario: Find config files**
|
||||
|
||||
Task: Find all YAML files in project
|
||||
Detection: fd available
|
||||
Selection: Use `fd` over `find`
|
||||
|
||||
```bash
|
||||
fd -e yaml -e yml
|
||||
```
|
||||
|
||||
**Scenario: Process API response**
|
||||
|
||||
Task: Extract specific fields from JSON
|
||||
Detection: jq unavailable
|
||||
Fallback: Use node/python
|
||||
Suggestion: `◇ Alternative: jq would simplify this — install with brew install jq`
|
||||
|
||||
```bash
|
||||
node -e "console.log(JSON.parse(require('fs').readFileSync(0, 'utf-8')).field)"
|
||||
```
|
||||
|
||||
</examples>
|
||||
|
||||
<rules>
|
||||
|
||||
ALWAYS:
|
||||
- Run detection script before recommending specific tools
|
||||
- Use selection table to map task to best available tool
|
||||
- Provide fallback when suggesting tools that might not be installed
|
||||
- Surface suggestions for significant improvements (2x+ better)
|
||||
- Trigger research when tool underperforms expectations
|
||||
|
||||
NEVER:
|
||||
- Assume a tool is installed without checking detection results
|
||||
- Block workflow on missing non-essential tools
|
||||
- Recommend abandonware or unmaintained tools
|
||||
- Use legacy tools when modern alternatives are available
|
||||
- Skip fallback strategy when preferred tool missing
|
||||
|
||||
</rules>
|
||||
|
||||
<references>
|
||||
|
||||
- [tool-catalog.md](references/tool-catalog.md) — comprehensive tool documentation
|
||||
- [alternatives.md](references/alternatives.md) — how to research new tools
|
||||
- [detection-script.md](references/detection-script.md) — detection script implementation
|
||||
|
||||
</references>
|
||||
@@ -0,0 +1,454 @@
|
||||
# Tool Upgrade Example: grep → ripgrep
|
||||
|
||||
Worked example showing the research stage triggered by slow performance.
|
||||
|
||||
## Scenario
|
||||
|
||||
User is searching a large codebase for authentication-related code. The `grep` command is taking unexpectedly long.
|
||||
|
||||
## Initial Context
|
||||
|
||||
```bash
|
||||
# User's command
|
||||
grep -r "authentication" .
|
||||
|
||||
# Observed behavior
|
||||
# ... hanging for 30+ seconds
|
||||
# ... eventually returns results mixed with noise from node_modules, .git, etc.
|
||||
```
|
||||
|
||||
## Stage 1: Trigger Detection
|
||||
|
||||
### Performance Trigger
|
||||
|
||||
**Observation:**
|
||||
- Command taking 30+ seconds on ~50k files
|
||||
- Task size suggests this should be much faster
|
||||
- User likely to repeat this search frequently
|
||||
|
||||
**Trigger evaluation:**
|
||||
|
||||
```
|
||||
Performance: ◆◆ CRITICAL
|
||||
- 30s for recursive text search is very slow
|
||||
- Blocking workflow
|
||||
- Repeated operation (common in development)
|
||||
|
||||
Context:
|
||||
- Large codebase (50k files)
|
||||
- Likely contains ignored directories (node_modules, .git)
|
||||
- User needs fast iteration on searches
|
||||
|
||||
Decision: TRIGGER RESEARCH
|
||||
```
|
||||
|
||||
### Surface to User
|
||||
|
||||
```
|
||||
△ This search is taking a long time (30s). The codebase size suggests a faster tool would help significantly. Research alternatives?
|
||||
```
|
||||
|
||||
**User response:** "Yes, please"
|
||||
|
||||
## Stage 2: Research
|
||||
|
||||
### Step 1: Search for Candidates
|
||||
|
||||
**Query:** "fast code search CLI tool 2024"
|
||||
|
||||
**Sources checked:**
|
||||
1. GitHub search: `site:github.com grep alternative rust stars:>1000`
|
||||
2. awesome-cli-apps: Command-line tools > Search
|
||||
3. modern-unix list: Text search category
|
||||
|
||||
**Candidates found:**
|
||||
|
||||
| Tool | Language | Stars | Description |
|
||||
|------|----------|-------|-------------|
|
||||
| ripgrep (rg) | Rust | 40k | Fast recursive search, respects .gitignore |
|
||||
| ag (the silver searcher) | C | 25k | Fast grep alternative |
|
||||
| ugrep | C++ | 3k | Advanced grep with better regex |
|
||||
|
||||
### Step 2: Initial Evaluation
|
||||
|
||||
**ripgrep (rg):**
|
||||
- Speed: ★★★ (Rust, parallel, optimized)
|
||||
- Ergonomics: ★★★ (smart defaults, colored output)
|
||||
- Maintenance: ★★★ (active, recent commits, responsive maintainer)
|
||||
- Install: ★★★ (brew, apt, cargo all available)
|
||||
- Adoption: ★★★ (40k stars, used by VS Code)
|
||||
|
||||
**ag:**
|
||||
- Speed: ★★ (faster than grep, but slower than rg)
|
||||
- Ergonomics: ★★ (good defaults)
|
||||
- Maintenance: ★ (less active recently)
|
||||
- Install: ★★★ (widely available)
|
||||
- Adoption: ★★ (mature, but being superseded)
|
||||
|
||||
**ugrep:**
|
||||
- Speed: ★★★ (comparable to rg)
|
||||
- Ergonomics: ★★ (powerful but complex)
|
||||
- Maintenance: ★★ (active, but smaller team)
|
||||
- Install: ★★ (less widely packaged)
|
||||
- Adoption: ★ (smaller community)
|
||||
|
||||
**Decision:** Focus on `ripgrep` - best overall scores, especially speed + maintenance + adoption.
|
||||
|
||||
### Step 3: Hands-On Testing
|
||||
|
||||
**Installation:**
|
||||
|
||||
```bash
|
||||
brew install ripgrep
|
||||
```
|
||||
|
||||
**Test 1: Basic search**
|
||||
|
||||
```bash
|
||||
# Compare with current command
|
||||
time grep -r "authentication" .
|
||||
# Result: 28.4s real
|
||||
|
||||
time rg "authentication"
|
||||
# Result: 0.8s real
|
||||
|
||||
# Performance gain: 35× faster
|
||||
```
|
||||
|
||||
**Test 2: Output quality**
|
||||
|
||||
```bash
|
||||
rg "authentication"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
src/auth/login.ts
|
||||
42:export async function authenticate(credentials: Credentials) {
|
||||
45: const result = await authService.authenticate(credentials);
|
||||
|
||||
src/auth/middleware.ts
|
||||
12:// Authentication middleware
|
||||
15:export function requireAuthentication(req: Request) {
|
||||
|
||||
tests/auth.test.ts
|
||||
8:describe('authentication', () => {
|
||||
```
|
||||
|
||||
**Observations:**
|
||||
- Colored output with syntax highlighting ✓
|
||||
- Line numbers by default ✓
|
||||
- File grouping ✓
|
||||
- Clean, readable format ✓
|
||||
- Automatically skipped node_modules, .git ✓
|
||||
|
||||
**Test 3: Edge cases**
|
||||
|
||||
```bash
|
||||
# Error handling
|
||||
rg "pattern" nonexistent-directory
|
||||
# Error: No files were searched (stderr)
|
||||
# Clear, actionable error ✓
|
||||
|
||||
# Large binary files
|
||||
rg "text" binary-file.bin
|
||||
# Automatically skips binary files ✓
|
||||
|
||||
# Complex patterns
|
||||
rg "auth\w+" --type ts
|
||||
# Regex works, type filtering works ✓
|
||||
```
|
||||
|
||||
**Test 4: Integration**
|
||||
|
||||
```bash
|
||||
# Pipe to other commands
|
||||
rg "TODO" --files-with-matches | wc -l
|
||||
# Works in pipeline ✓
|
||||
|
||||
# Script compatibility
|
||||
if rg "pattern" file.txt > /dev/null; then
|
||||
echo "Found"
|
||||
fi
|
||||
# Exit codes work correctly ✓
|
||||
```
|
||||
|
||||
### Step 4: Compatibility Check
|
||||
|
||||
**Drop-in replacement viability:**
|
||||
|
||||
```bash
|
||||
# Can we alias grep → rg?
|
||||
# Mostly yes, but flags differ
|
||||
|
||||
# Common grep flags vs rg equivalents:
|
||||
grep -r → rg (default recursive)
|
||||
grep -i → rg -i (same)
|
||||
grep -v → rg -v (same)
|
||||
grep -l → rg -l or --files-with-matches (same concept)
|
||||
grep -n → rg -n (same, but rg shows by default)
|
||||
|
||||
# Verdict: Similar enough for most use cases
|
||||
# May need to update some scripts with specific grep flags
|
||||
```
|
||||
|
||||
## Stage 3: Evaluation Summary
|
||||
|
||||
### Performance Analysis
|
||||
|
||||
**Benchmark results:**
|
||||
|
||||
```
|
||||
Task: Search 50k files for "authentication"
|
||||
|
||||
grep -r: 28.4s
|
||||
ripgrep: 0.8s
|
||||
|
||||
Speed gain: 35× faster
|
||||
Time saved: 27.6s per search
|
||||
|
||||
If user runs 10 searches/day:
|
||||
Daily savings: 4.6 minutes
|
||||
Weekly savings: 23 minutes
|
||||
Annual savings: 20 hours
|
||||
```
|
||||
|
||||
**Conclusion:** Massive performance improvement.
|
||||
|
||||
### Benefits vs Trade-offs
|
||||
|
||||
**Benefits:**
|
||||
1. **Speed**: 35× faster on this codebase
|
||||
2. **Smart defaults**: Respects .gitignore (cleaner results)
|
||||
3. **Better output**: Colored, grouped, line numbers
|
||||
4. **Binary handling**: Automatically skips binary files
|
||||
5. **Regex**: PCRE2 support (more powerful patterns)
|
||||
6. **Type filtering**: `--type ts` for language-specific searches
|
||||
|
||||
**Trade-offs:**
|
||||
1. **Different flags**: Some grep flags have different names
|
||||
2. **Muscle memory**: Need to learn rg-specific options
|
||||
3. **POSIX compatibility**: Regex flavor differs from POSIX grep
|
||||
|
||||
**Verdict:** Benefits massively outweigh trade-offs.
|
||||
|
||||
### Confidence Assessment
|
||||
|
||||
**Adoption:** ✓ HIGH
|
||||
- 40k+ GitHub stars
|
||||
- Used by major projects (VS Code, GitHub search)
|
||||
- Active community and development
|
||||
|
||||
**Maintenance:** ✓ HIGH
|
||||
- Last commit: 2 weeks ago
|
||||
- Responsive maintainer (burntsushi)
|
||||
- Clear roadmap and changelog
|
||||
|
||||
**Installation:** ✓ HIGH
|
||||
- `brew install ripgrep` works
|
||||
- Also available via apt, cargo, chocolatey
|
||||
- Binary releases for all platforms
|
||||
|
||||
**Quality:** ✓ HIGH
|
||||
- Extensive test suite
|
||||
- Well-documented
|
||||
- Proven in production
|
||||
|
||||
**Overall Confidence:** HIGH
|
||||
|
||||
## Stage 4: Recommendation
|
||||
|
||||
### Presentation to User
|
||||
|
||||
```
|
||||
Found: ripgrep (rg) — Fast line-oriented recursive search tool
|
||||
|
||||
Performance:
|
||||
- 35× faster than grep on this codebase
|
||||
- Searched 50k files in 0.8s vs 28.4s with grep -r
|
||||
- Saves ~4 minutes per day with typical search patterns
|
||||
|
||||
Benefits:
|
||||
- Respects .gitignore automatically (no node_modules noise)
|
||||
- Colored output with syntax highlighting
|
||||
- Line numbers and file grouping by default
|
||||
- Automatic binary file detection
|
||||
- Advanced regex support (PCRE2)
|
||||
- Type filtering (--type ts, --type rust, etc.)
|
||||
|
||||
Installation:
|
||||
```bash
|
||||
brew install ripgrep
|
||||
```
|
||||
|
||||
Example (replaces your current command):
|
||||
|
||||
```bash
|
||||
# Instead of: grep -r "authentication" .
|
||||
rg "authentication"
|
||||
|
||||
# With type filtering
|
||||
rg "authentication" --type ts
|
||||
|
||||
# Case insensitive
|
||||
rg -i "authentication"
|
||||
```
|
||||
|
||||
Trade-offs:
|
||||
- Some flag differences from grep (e.g., -r is default, not needed)
|
||||
- Different regex flavor (PCRE2 vs POSIX) - rarely an issue
|
||||
|
||||
Confidence: HIGH
|
||||
- 40k+ GitHub stars, widely adopted
|
||||
- Used as search backend in VS Code and GitHub
|
||||
- Active maintenance by respected developer
|
||||
- Drop-in for 95% of grep use cases
|
||||
|
||||
Recommend: INSTALL
|
||||
|
||||
Want me to also add a shell alias to ease transition?
|
||||
|
||||
```
|
||||
|
||||
### User Response Options
|
||||
|
||||
**Option 1: User accepts immediately**
|
||||
```
|
||||
|
||||
User: "Yes, install it and set up the alias"
|
||||
|
||||
Agent:
|
||||
|
||||
```bash
|
||||
# Verify installation
|
||||
command -v rg
|
||||
# /opt/homebrew/bin/rg ✓
|
||||
|
||||
# Add to ~/.zshrc
|
||||
echo "alias grep='rg'" >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
|
||||
# Test
|
||||
grep "authentication"
|
||||
# Works! Using ripgrep now.
|
||||
```
|
||||
|
||||
Done. You're now using ripgrep when you type `grep`.
|
||||
The original grep is still available as `command grep` if needed.
|
||||
|
||||
```
|
||||
|
||||
**Option 2: User wants to try first**
|
||||
```
|
||||
|
||||
User: "Let me try it for a while before aliasing"
|
||||
|
||||
Agent: Great approach. Try these commands:
|
||||
|
||||
```bash
|
||||
# Your current search
|
||||
rg "authentication"
|
||||
|
||||
# Limit to TypeScript files
|
||||
rg "authentication" --type ts
|
||||
|
||||
# Show context (3 lines before/after)
|
||||
rg "authentication" -C 3
|
||||
|
||||
# List files with matches only
|
||||
rg "authentication" --files-with-matches
|
||||
```
|
||||
|
||||
After a few days, if you like it, run:
|
||||
|
||||
```bash
|
||||
echo "alias grep='rg'" >> ~/.zshrc
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
**Option 3: User declines**
|
||||
```
|
||||
|
||||
User: "I'll stick with grep for now"
|
||||
|
||||
Agent: Understood. I'll note that ripgrep is available if you
|
||||
change your mind. For now, I'll continue using grep.
|
||||
|
||||
[Internal note: rg available but user prefers grep - respect preference]
|
||||
|
||||
```
|
||||
|
||||
## Stage 5: Outcome
|
||||
|
||||
### Result: INSTALL accepted
|
||||
|
||||
```bash
|
||||
# Installation confirmed
|
||||
rg --version
|
||||
# ripgrep 14.1.0
|
||||
|
||||
# Updated shell config with alias
|
||||
grep --version
|
||||
# ripgrep 14.1.0 (aliased)
|
||||
|
||||
# User runs same search
|
||||
grep "authentication"
|
||||
# 0.8s (was 28.4s)
|
||||
|
||||
# Success metrics
|
||||
Speed improvement: 35×
|
||||
User satisfaction: High (immediate feedback: "Wow, much faster!")
|
||||
Workflow impact: Positive (cleaner output, faster iteration)
|
||||
```
|
||||
|
||||
### Follow-up Actions
|
||||
|
||||
1. **Update tool catalog**: Added rg to preferred tools list
|
||||
2. **Detection script**: Ensure script checks for rg availability
|
||||
3. **Future searches**: Use rg by default on this system
|
||||
4. **User education**: Mentioned --type flag for language-specific searches
|
||||
|
||||
### Lessons Learned
|
||||
|
||||
**What worked:**
|
||||
- Clear performance measurement (28.4s → 0.8s)
|
||||
- Real-world testing on user's actual codebase
|
||||
- Showing immediate benefit (cleaner results, no node_modules noise)
|
||||
- Offering trial period option
|
||||
|
||||
**What could improve:**
|
||||
- Could have shown advanced features (--stats, --json output)
|
||||
- Could have mentioned integration with fzf for interactive search
|
||||
- Could have demonstrated multi-line search patterns
|
||||
|
||||
### Long-term Impact
|
||||
|
||||
**2 weeks later:**
|
||||
- User now using rg for all searches
|
||||
- Discovered `--stats` flag, using for codebase metrics
|
||||
- Shared rg with team, 3 other developers adopted it
|
||||
- User asks about other modern tools (triggered tool-catalog review)
|
||||
|
||||
**Conclusion:** Successful upgrade with measurable productivity gain.
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
This example demonstrates:
|
||||
|
||||
1. **Clear trigger identification**: Performance >3× worse than expected
|
||||
2. **Structured research**: GitHub search → evaluation → hands-on testing
|
||||
3. **Quantified benefits**: 35× speedup, concrete time savings
|
||||
4. **Confidence assessment**: Multiple factors (adoption, maintenance, quality)
|
||||
5. **Flexible recommendation**: Offer installation with fallback options
|
||||
6. **User respect**: Allow trial period, respect if declined
|
||||
7. **Measurable outcome**: Confirm improvement, track adoption
|
||||
|
||||
**Pattern for future tool upgrades:**
|
||||
|
||||
```
|
||||
Trigger → Research → Evaluate → Test → Recommend → Install → Verify → Follow-up
|
||||
```
|
||||
@@ -0,0 +1,673 @@
|
||||
# Researching Tool Alternatives
|
||||
|
||||
Guide for discovering and evaluating modern CLI tools when current tools underperform.
|
||||
|
||||
## When to Research
|
||||
|
||||
### Performance Triggers
|
||||
|
||||
Research alternatives when you observe:
|
||||
|
||||
- **Slow execution**: Command takes >5 seconds on typical workload
|
||||
- **Resource spikes**: High CPU/memory usage for simple operations
|
||||
- **Blocking behavior**: Tool blocks the terminal for extended periods
|
||||
- **Scale issues**: Performance degrades significantly with file count or size
|
||||
- **3x+ slower than expected**: Tool taking much longer than task size suggests
|
||||
|
||||
### Ergonomic Triggers
|
||||
|
||||
Consider alternatives when:
|
||||
|
||||
- **Complex syntax**: Requiring frequent man page lookups for basic operations
|
||||
- **Poor defaults**: Always passing the same flags to get desired behavior
|
||||
- **Missing features**: Workarounds needed for common tasks
|
||||
- **Error messages**: Cryptic or unhelpful output on failure
|
||||
- **Repeated complex command chains**: Same multi-tool pipeline used frequently
|
||||
|
||||
### Maintenance Triggers
|
||||
|
||||
Look for replacements when:
|
||||
|
||||
- **Unmaintained**: No updates in 2+ years, open issues piling up
|
||||
- **Deprecated**: Tool documentation marks it as legacy
|
||||
- **Security issues**: Known vulnerabilities without patches
|
||||
- **Compatibility**: Broken on modern OS/architecture
|
||||
|
||||
### User Signal Triggers
|
||||
|
||||
Always research when:
|
||||
|
||||
- Explicit request: "Is there a better way to do this?"
|
||||
- Frustration indicators: "This is taking forever", "Why is this so slow?"
|
||||
- Performance complaints about specific tool
|
||||
- User asks about alternatives or modern equivalents
|
||||
|
||||
### Context Triggers
|
||||
|
||||
Consider research for:
|
||||
|
||||
- **New categories**: Task type not in current tool catalog
|
||||
- **Building automation**: Tool will run frequently, performance matters
|
||||
- **New environment setup**: Opportunity to establish good defaults
|
||||
- **Cross-tool integration**: Multiple tools could be replaced by one
|
||||
|
||||
## Where to Look
|
||||
|
||||
### Primary Sources
|
||||
|
||||
#### 1. GitHub Search
|
||||
|
||||
**Search patterns**:
|
||||
|
||||
```
|
||||
site:github.com {category} rust OR go language:Rust OR language:Go stars:>1000
|
||||
site:github.com {category} CLI tool stars:>500
|
||||
site:github.com modern {legacy-tool} alternative
|
||||
```
|
||||
|
||||
**Examples**:
|
||||
|
||||
```
|
||||
site:github.com file search rust language:Rust stars:>1000
|
||||
site:github.com grep alternative rust language:Rust stars:>1000
|
||||
site:github.com modern ls replacement stars:>500
|
||||
```
|
||||
|
||||
**Why GitHub:**
|
||||
- Active development visible (commit history)
|
||||
- Star count indicates adoption and community validation
|
||||
- Issues/PRs show maintenance quality
|
||||
- README usually has benchmarks and comparisons
|
||||
|
||||
#### 2. Curated Lists
|
||||
|
||||
**awesome-cli-apps**: <https://github.com/agarrharr/awesome-cli-apps>
|
||||
- Categorized by function
|
||||
- Curated for quality
|
||||
- Regularly updated
|
||||
|
||||
**modern-unix**: <https://github.com/ibraheemdev/modern-unix>
|
||||
- Specifically Unix tool replacements
|
||||
- Focus on performance and ergonomics
|
||||
- Comparison with legacy tools
|
||||
|
||||
**awesome-tuis**: <https://github.com/rothgar/awesome-tuis>
|
||||
- Terminal UI applications
|
||||
- Interactive tools
|
||||
- Well-maintained list
|
||||
|
||||
**Why curated lists:**
|
||||
- Pre-filtered for quality
|
||||
- Organized by category
|
||||
- Community-vetted
|
||||
|
||||
#### 3. Language-Specific Ecosystems
|
||||
|
||||
**Rust CLI Working Group**:
|
||||
- <https://rust-cli.github.io/book/>
|
||||
- <https://lib.rs/command-line-utilities>
|
||||
|
||||
**Go CLI Tools**:
|
||||
- <https://github.com/avelino/awesome-go#command-line>
|
||||
|
||||
**Why language ecosystems:**
|
||||
- Rust tools often fastest (native performance, zero-cost abstractions)
|
||||
- Go tools good balance (fast, easy distribution, single binary)
|
||||
- Language communities maintain tool lists
|
||||
|
||||
### Secondary Sources
|
||||
|
||||
#### Hacker News
|
||||
|
||||
**Search patterns**:
|
||||
|
||||
```
|
||||
site:news.ycombinator.com {tool} alternative
|
||||
site:news.ycombinator.com modern {category} tools
|
||||
site:news.ycombinator.com CLI productivity
|
||||
```
|
||||
|
||||
**Why HN:**
|
||||
- Real-world usage discussions
|
||||
- Trade-off analysis from practitioners
|
||||
- Early visibility into trending tools
|
||||
- Critical perspectives, not just hype
|
||||
|
||||
#### Reddit Communities
|
||||
|
||||
**r/commandline** - Dedicated CLI tool discussions
|
||||
**r/rust** - Rust-based CLI tools (often performance-focused)
|
||||
**r/golang** - Go-based tools
|
||||
**r/programming** - General tool discussions
|
||||
|
||||
**Why Reddit:**
|
||||
- User reviews and experiences
|
||||
- Comparison threads
|
||||
- Common pain points surfaced
|
||||
|
||||
#### Tool Comparison Sites
|
||||
|
||||
**AlternativeTo**: <https://alternativeto.net>
|
||||
- User ratings
|
||||
- Feature comparison matrices
|
||||
- Platform availability
|
||||
|
||||
**Why comparison sites:**
|
||||
- Side-by-side feature lists
|
||||
- Community ratings
|
||||
- Discover tools you didn't know existed
|
||||
|
||||
### Research Workflow
|
||||
|
||||
**Query progression**:
|
||||
1. `{TASK} CLI tool 2025` or `{TASK} CLI tool 2024`
|
||||
2. `best {TASK} command line tool`
|
||||
3. `modern alternative to {LEGACY_TOOL}`
|
||||
4. `{LANGUAGE} {TASK} CLI` (try rust first, then go)
|
||||
|
||||
**Initial filtering**:
|
||||
- Published/updated within last 2 years
|
||||
- Active development (commits within 6 months)
|
||||
- Community traction (GitHub stars >500 for niche, >1000 for common tools)
|
||||
- Clear documentation and examples
|
||||
- Available in package managers
|
||||
|
||||
## Evaluation Criteria
|
||||
|
||||
Evaluate candidates across these dimensions:
|
||||
|
||||
### 1. Speed (Weight: High - 40%)
|
||||
|
||||
**Measure:**
|
||||
- Benchmarks on representative workload
|
||||
- Compare with legacy tool on same task
|
||||
- Check scaling behavior (10 files vs 10,000 files)
|
||||
- Startup time (matters for frequently-run commands)
|
||||
|
||||
**Thresholds:**
|
||||
- **2× faster**: Consider if other benefits exist
|
||||
- **5× faster**: Strong candidate, likely worth adoption
|
||||
- **10× faster**: High priority upgrade, significant productivity gain
|
||||
|
||||
**How to benchmark:**
|
||||
|
||||
```bash
|
||||
# Quick comparison with time
|
||||
time {old-tool} args
|
||||
time {new-tool} args
|
||||
|
||||
# Statistical benchmark with hyperfine
|
||||
hyperfine '{old-tool} args' '{new-tool} args'
|
||||
|
||||
# Test scaling
|
||||
hyperfine --parameter-scan num 10 10000 '{tool} args'
|
||||
```
|
||||
|
||||
### 2. Ergonomics (Weight: Medium-High - 30%)
|
||||
|
||||
**Evaluate:**
|
||||
- **Syntax simplicity**: Can you remember it without docs?
|
||||
- **Defaults**: Do common operations require flags?
|
||||
- **Output quality**: Readable, informative, well-formatted?
|
||||
- **Error messages**: Clear, actionable, helpful suggestions?
|
||||
- **Composability**: Works well in pipes and scripts?
|
||||
|
||||
**Good indicators:**
|
||||
- Colored output by default
|
||||
- Smart defaults (respects .gitignore, etc.)
|
||||
- Short, memorable command names
|
||||
- Built-in help that's actually helpful (`--help` is clear)
|
||||
- Intuitive flag names
|
||||
|
||||
**Red flags:**
|
||||
- Complex syntax requiring constant reference
|
||||
- Poor error messages ("error" with no context)
|
||||
- Unexpected default behavior
|
||||
- Verbose flags only (no short forms)
|
||||
|
||||
### 3. Maintenance (Weight: High - 20%)
|
||||
|
||||
**Check repository health:**
|
||||
- **Last commit**: <6 months is active, <3 months is excellent
|
||||
- **Issue response time**: Maintainer engagement (check recent issues)
|
||||
- **Release cadence**: Regular releases, not constant churn
|
||||
- **Contributor count**: Not single-maintainer ghost projects
|
||||
- **Organization backing**: Company/org-backed often more stable
|
||||
|
||||
**Red flags:**
|
||||
- Archived repository
|
||||
- 100+ open issues with no maintainer responses
|
||||
- Last release >2 years ago
|
||||
- Single maintainer who's gone MIA
|
||||
- Major bugs unaddressed
|
||||
|
||||
**Green flags:**
|
||||
- Active CI/CD
|
||||
- Regular security updates
|
||||
- Responsive to community
|
||||
- Clear governance or roadmap
|
||||
|
||||
### 4. Installation Complexity (Weight: Medium - 10%)
|
||||
|
||||
**Assess ease of installation:**
|
||||
- Available in major package managers (brew, apt, cargo, dnf)
|
||||
- Binary releases for major platforms (Linux, macOS, Windows)
|
||||
- Dependency count (fewer is better)
|
||||
- Binary size (under 50MB is reasonable for most tools)
|
||||
|
||||
**Scoring:**
|
||||
- **Excellent**: `brew install`, `apt install`, or `cargo install`
|
||||
- **Good**: Binary releases on GitHub, one-liner install script
|
||||
- **Acceptable**: Build from source with standard toolchain
|
||||
- **Poor**: Complex build requirements, many dependencies
|
||||
- **Deal-breaker**: Requires specific versions of rare dependencies
|
||||
|
||||
### 5. Adoption (Weight: Medium - Points to maturity)
|
||||
|
||||
**Indicators of healthy adoption:**
|
||||
- GitHub stars (>1k is good, >5k is excellent, >10k is widely adopted)
|
||||
- Used by major projects (check GitHub dependents)
|
||||
- Mentioned in blog posts, tool lists, conference talks
|
||||
- Active community (Discord, discussions, Stack Overflow questions)
|
||||
- Production usage stories
|
||||
|
||||
**Why adoption matters:**
|
||||
- More usage → more bugs found and fixed
|
||||
- Better documentation and examples
|
||||
- Higher probability of long-term maintenance
|
||||
- Easier to find help when stuck
|
||||
|
||||
### 6. Compatibility (Weight: Medium-Low - Important for drop-in replacements)
|
||||
|
||||
**Check replacement viability:**
|
||||
- **Drop-in replacement**: Can alias old command to new? (`alias cat=bat`)
|
||||
- **POSIX compliance**: Matters for portable scripts
|
||||
- **Output format**: Parseable by downstream tools?
|
||||
- **Configuration**: Reads old tool's config files?
|
||||
- **Flags**: Similar enough for muscle memory transfer?
|
||||
|
||||
**Examples:**
|
||||
|
||||
```bash
|
||||
# Safe drop-in replacements
|
||||
alias cat=bat # Generally yes (bat mimics cat behavior)
|
||||
alias ls=eza # Yes (eza designed as ls replacement)
|
||||
alias grep=rg # Mostly (different flags, but core usage similar)
|
||||
|
||||
# Risky drop-ins
|
||||
alias sed=sd # No (sd is simpler, not full sed replacement)
|
||||
alias awk=... # No good modern replacement (awk is unique)
|
||||
```
|
||||
|
||||
## Testing Workflow
|
||||
|
||||
### Stage 1: Quick Evaluation (5 minutes)
|
||||
|
||||
**Install in isolated way:**
|
||||
|
||||
```bash
|
||||
# Prefer cargo for isolated testing (doesn't require sudo)
|
||||
cargo install {tool}
|
||||
|
||||
# Or homebrew
|
||||
brew install {tool}
|
||||
```
|
||||
|
||||
**Basic functionality check:**
|
||||
|
||||
```bash
|
||||
# Check help output
|
||||
{tool} --help
|
||||
|
||||
# Test basic operation
|
||||
{tool} {simple-task}
|
||||
|
||||
# Quick benchmark
|
||||
hyperfine '{old-tool} args' '{new-tool} args'
|
||||
```
|
||||
|
||||
**Decision point:** If not obviously better (2×+ speed or significantly better UX), stop here.
|
||||
|
||||
### Stage 2: Real-World Testing (15 minutes)
|
||||
|
||||
**Test on actual project workloads:**
|
||||
|
||||
```bash
|
||||
# Test on current project
|
||||
cd ~/Developer/current-project
|
||||
{new-tool} {typical-task}
|
||||
|
||||
# Test on large directory
|
||||
cd ~/Developer # or another large directory tree
|
||||
{new-tool} {typical-task}
|
||||
|
||||
# Test common variations
|
||||
{new-tool} {variant-1}
|
||||
{new-tool} {variant-2}
|
||||
{new-tool} {variant-3}
|
||||
|
||||
# Test error handling
|
||||
{new-tool} nonexistent-file
|
||||
{new-tool} --invalid-flag
|
||||
{new-tool} {edge-case}
|
||||
```
|
||||
|
||||
**Evaluate results:**
|
||||
- Does output format work for your needs?
|
||||
- Are error messages helpful?
|
||||
- Any surprising behavior?
|
||||
- Performance consistent across different inputs?
|
||||
|
||||
**Decision point:** If issues found, check GitHub issues. If widespread problems or dealbreaker bugs, stop.
|
||||
|
||||
### Stage 3: Integration Testing (10 minutes)
|
||||
|
||||
**Check fit with existing workflow:**
|
||||
|
||||
```bash
|
||||
# Pipe compatibility
|
||||
{new-tool} args | other-command
|
||||
other-command | {new-tool} args
|
||||
|
||||
# Script compatibility
|
||||
# - Create small test script using new tool
|
||||
# - Verify behavior matches expectations
|
||||
|
||||
# Shell integration
|
||||
# - Tab completion working?
|
||||
# - Any shell-specific issues? (zsh vs bash)
|
||||
# - Works from different directories?
|
||||
|
||||
# Alias trial
|
||||
alias {old}={new}
|
||||
# Use normally for a few minutes
|
||||
# Pay attention to muscle memory friction
|
||||
```
|
||||
|
||||
**Decision point:** Integration issues are often deal-breakers for drop-in replacements. If tool doesn't fit workflow smoothly, consider fallback strategy or skip.
|
||||
|
||||
### Testing Checklist
|
||||
|
||||
- [ ] Installs cleanly
|
||||
- [ ] Help text is clear
|
||||
- [ ] Basic operation works as expected
|
||||
- [ ] Performance is measurably better (if speed is goal)
|
||||
- [ ] Output format is acceptable
|
||||
- [ ] Error messages are helpful
|
||||
- [ ] Works in pipes/scripts
|
||||
- [ ] No showstopper bugs on current project
|
||||
- [ ] Integrates smoothly with existing workflow
|
||||
- [ ] Documentation is adequate
|
||||
|
||||
## Recommendation Format
|
||||
|
||||
When presenting tool findings to user:
|
||||
|
||||
### Template
|
||||
|
||||
```
|
||||
Found: {TOOL_NAME} — {one-line description}
|
||||
|
||||
Performance:
|
||||
- {benchmark result, e.g., "8× faster than find on this codebase"}
|
||||
- {specific improvement, e.g., "searched 10k files in 0.2s vs 2.1s"}
|
||||
|
||||
Benefits:
|
||||
- {key advantage 1}
|
||||
- {key advantage 2}
|
||||
- {key advantage 3}
|
||||
|
||||
Installation:
|
||||
```bash
|
||||
{install command}
|
||||
```
|
||||
|
||||
Trade-offs:
|
||||
- {any downsides, or "None identified"}
|
||||
|
||||
Confidence: {HIGH/MEDIUM/LOW}
|
||||
- HIGH: Widely adopted, clear win, drop-in replacement
|
||||
- MEDIUM: Good but niche, or requires workflow changes
|
||||
- LOW: Bleeding edge, or significant compatibility concerns
|
||||
|
||||
Recommend: {INSTALL/TRY/SKIP}
|
||||
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
|
||||
Found: ripgrep (rg) — Fast line-oriented search tool
|
||||
|
||||
Performance:
|
||||
- 15× faster than grep on this codebase
|
||||
- Searched 50k files in 0.3s vs 4.5s with grep -r
|
||||
|
||||
Benefits:
|
||||
- Respects .gitignore by default (no node_modules noise)
|
||||
- Colored output with line numbers
|
||||
- Better regex support (PCRE2)
|
||||
- Automatic binary file detection
|
||||
|
||||
Installation:
|
||||
|
||||
```bash
|
||||
brew install ripgrep
|
||||
```
|
||||
|
||||
Trade-offs:
|
||||
- Different flags than grep (muscle memory adjustment)
|
||||
- Recursive by default (explicit -r not needed)
|
||||
|
||||
Confidence: HIGH
|
||||
- 40k+ GitHub stars
|
||||
- Used by major projects (VS Code search backend)
|
||||
- Drop-in for most grep use cases
|
||||
|
||||
Recommend: INSTALL
|
||||
|
||||
```
|
||||
|
||||
## When to Recommend Installation
|
||||
|
||||
### Recommend: INSTALL
|
||||
|
||||
User should install when ALL of these are true:
|
||||
|
||||
- **Clear performance win** (5×+ faster) OR **significantly better ergonomics**
|
||||
- **No significant downsides** (compatible, well-maintained)
|
||||
- **Easy installation** (brew/apt/cargo available)
|
||||
- **High confidence** in quality (mature, adopted, maintained)
|
||||
|
||||
**Action:**
|
||||
- Include install command in response
|
||||
- Offer to add shell alias if appropriate
|
||||
- Provide example usage for current task
|
||||
|
||||
### Recommend: TRY
|
||||
|
||||
User might try when:
|
||||
|
||||
- **Moderate improvement** (2-5× faster or notable UX improvement)
|
||||
- **Specialized use case** (benefits specific workflows)
|
||||
- **Learning curve exists** (different paradigm or syntax)
|
||||
- **Medium confidence** (newer tool, smaller community, or niche)
|
||||
|
||||
**Action:**
|
||||
- Explain benefits clearly
|
||||
- Provide test command to evaluate
|
||||
- Let user decide based on their priorities
|
||||
- Offer to help with adoption if they choose to try
|
||||
|
||||
### Recommend: SKIP
|
||||
|
||||
Don't recommend when ANY of these are true:
|
||||
|
||||
- **Marginal improvement** (<2× faster, minimal UX gain)
|
||||
- **Installation complexity** (build from source, many dependencies)
|
||||
- **Maintenance concerns** (abandoned, single maintainer MIA, security issues)
|
||||
- **Low confidence** (alpha quality, breaking changes, major bugs)
|
||||
- **User constraints** (no install access, strict portability requirements)
|
||||
|
||||
**Action:**
|
||||
- Use fallback tool without mentioning limitation
|
||||
- Or briefly note why skipping: "Evaluated {TOOL} but marginal improvement doesn't justify installation"
|
||||
- Document finding for future reference if tool matures
|
||||
|
||||
## Fallback Strategy
|
||||
|
||||
Always maintain fallback support in scripts and automation:
|
||||
|
||||
### Pattern 1: Check-then-run
|
||||
|
||||
```bash
|
||||
if command -v rg &> /dev/null; then
|
||||
rg pattern
|
||||
else
|
||||
grep -r pattern .
|
||||
fi
|
||||
```
|
||||
|
||||
### Pattern 2: Function Wrapper
|
||||
|
||||
```bash
|
||||
search() {
|
||||
if command -v rg &> /dev/null; then
|
||||
rg "$@"
|
||||
else
|
||||
grep -r "$@" .
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: Conditional Alias
|
||||
|
||||
```bash
|
||||
# In shell config (.zshrc, .bashrc)
|
||||
if command -v bat &> /dev/null; then
|
||||
alias cat='bat --style=plain --paging=never'
|
||||
fi
|
||||
|
||||
if command -v eza &> /dev/null; then
|
||||
alias ls='eza'
|
||||
alias l='eza -l'
|
||||
alias la='eza -la'
|
||||
fi
|
||||
```
|
||||
|
||||
**Why fallback matters:**
|
||||
|
||||
- Scripts work on systems without modern tools installed
|
||||
- Shared code doesn't break for other developers
|
||||
- Graceful degradation in CI/CD environments
|
||||
- Portable across different environments
|
||||
|
||||
## Example Research Session
|
||||
|
||||
**Trigger**: User searching large codebase, `grep` taking 30+ seconds
|
||||
|
||||
**Search query**: "fast code search CLI tool 2024"
|
||||
|
||||
**Candidates found**:
|
||||
1. ripgrep (rg) — Rust-based, 10-100x faster than grep
|
||||
2. The Silver Searcher (ag) — C-based, 3-5x faster than grep
|
||||
3. ugrep — C++ with advanced regex, similar speed to rg
|
||||
|
||||
**Initial evaluation**:
|
||||
|
||||
| Tool | Speed | Ergonomics | Maintenance | Install |
|
||||
|------|-------|------------|-------------|---------|
|
||||
| rg | ★★★ | ★★★ | ★★★ | ★★★ |
|
||||
| ag | ★★ | ★★ | ★ | ★★★ |
|
||||
| ugrep | ★★★ | ★★ | ★★ | ★★ |
|
||||
|
||||
**Hands-on test**:
|
||||
|
||||
```bash
|
||||
brew install ripgrep
|
||||
|
||||
# Current: grep -r "pattern" . (30s)
|
||||
time grep -r "authentication" .
|
||||
# Result: 28.4s
|
||||
|
||||
# New: rg "pattern" (default recursive)
|
||||
time rg "authentication"
|
||||
# Result: 0.8s
|
||||
|
||||
# Edge case: large binary files
|
||||
rg "pattern" # Automatically skips binaries
|
||||
grep -r "pattern" . # Hangs on binaries unless -I flag
|
||||
```
|
||||
|
||||
**Findings**:
|
||||
|
||||
```
|
||||
Found: ripgrep (rg) — Recursive line-oriented search tool
|
||||
|
||||
Advantages:
|
||||
- 35x faster than grep on this codebase (0.8s vs 28s)
|
||||
- Respects .gitignore automatically (fewer false matches)
|
||||
- Colorized output with line numbers by default
|
||||
- Automatically skips binary files
|
||||
|
||||
Install:
|
||||
brew install ripgrep
|
||||
|
||||
Example (current task):
|
||||
rg "authentication" --type ts
|
||||
|
||||
Trade-offs:
|
||||
- Different flag syntax than grep (learning curve)
|
||||
- Regex flavor differs slightly (PCRE2 vs POSIX)
|
||||
|
||||
Recommendation: ★ ADOPT — 35x speedup justifies one-time learning cost
|
||||
```
|
||||
|
||||
## Tool Discovery Resources
|
||||
|
||||
### Curated Lists
|
||||
|
||||
- [awesome-cli-apps](https://github.com/agarrharr/awesome-cli-apps)
|
||||
- [modern-unix](https://github.com/ibraheemdev/modern-unix)
|
||||
- [Rust CLI tools](https://lib.rs/command-line-utilities)
|
||||
- [Go CLI tools](https://github.com/avelino/awesome-go#command-line)
|
||||
|
||||
### Communities
|
||||
|
||||
- r/commandline — CLI tool discussions
|
||||
- r/rust — Rust-based tools (often fastest)
|
||||
- r/golang — Go-based tools (good balance)
|
||||
- Lobsters CLI tag — <https://lobste.rs/t/cli>
|
||||
|
||||
### Benchmarking Tools
|
||||
|
||||
When comparing performance:
|
||||
|
||||
```bash
|
||||
# hyperfine - statistical benchmarking
|
||||
brew install hyperfine
|
||||
hyperfine '{COMMAND_1}' '{COMMAND_2}'
|
||||
|
||||
# time - quick comparison
|
||||
time {COMMAND}
|
||||
|
||||
# perf - detailed profiling (Linux)
|
||||
perf stat {COMMAND}
|
||||
```
|
||||
|
||||
## Updating Tool Catalog
|
||||
|
||||
When research yields strong candidate:
|
||||
|
||||
1. Add to main selection table in SKILL.md
|
||||
2. Document in tool-catalog.md with:
|
||||
- Purpose
|
||||
- Key features
|
||||
- Installation
|
||||
- Common usage
|
||||
- Performance notes
|
||||
3. Update detection script to check for new tool
|
||||
4. Add to any relevant workflow examples
|
||||
|
||||
Keep tool catalog current — revisit every 6 months to prune abandoned tools and add emerging ones.
|
||||
@@ -0,0 +1,146 @@
|
||||
# Detection Script Implementation
|
||||
|
||||
The detection script identifies available CLI tools on the system.
|
||||
|
||||
## Purpose
|
||||
|
||||
Before recommending specific tools, check what's actually installed. Prevents suggesting unavailable tools and enables graceful fallback.
|
||||
|
||||
## Location
|
||||
|
||||
```
|
||||
outfitter/skills/which-tool/scripts/index.ts
|
||||
```
|
||||
|
||||
## Expected Output Format
|
||||
|
||||
```json
|
||||
{
|
||||
"available": {
|
||||
"find_files": ["fd", "find"],
|
||||
"search_content": ["rg", "grep"],
|
||||
"ast_search": ["sg"],
|
||||
"process_json": ["jq"],
|
||||
"view_file": ["bat", "cat"],
|
||||
"list_dir": ["eza", "ls"],
|
||||
"git_diff": ["delta", "git"],
|
||||
"navigate": ["zoxide", "cd"],
|
||||
"fuzzy_select": ["fzf"],
|
||||
"http": ["httpie", "curl"]
|
||||
},
|
||||
"missing": ["sg", "delta", "zoxide"],
|
||||
"system": {
|
||||
"os": "darwin",
|
||||
"platform": "arm64",
|
||||
"package_managers": ["brew"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Details
|
||||
|
||||
The script should:
|
||||
|
||||
1. **Check tool availability** using `which` or `command -v`
|
||||
2. **Categorize by task type** (find_files, search_content, etc.)
|
||||
3. **Detect package managers** for installation suggestions
|
||||
4. **Return structured JSON** for easy parsing
|
||||
|
||||
Example detection check:
|
||||
|
||||
```typescript
|
||||
async function checkTool(name: string): Promise<boolean> {
|
||||
try {
|
||||
const proc = Bun.spawn(['which', name], {
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
});
|
||||
|
||||
const exitCode = await proc.exited;
|
||||
return exitCode === 0;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage in Skill
|
||||
|
||||
```bash
|
||||
# Run detection
|
||||
bun /Users/mg/Developer/outfitter/agents/outfitter/skills/which-tool/scripts/index.ts
|
||||
|
||||
# Parse results
|
||||
DETECTION_RESULTS=$(bun /path/to/script)
|
||||
```
|
||||
|
||||
Agent parses JSON to determine:
|
||||
- Which preferred tools are available
|
||||
- Which tasks need fallback
|
||||
- What to suggest installing for significant improvements
|
||||
|
||||
## Caching Strategy
|
||||
|
||||
Run once per session:
|
||||
- First tool selection → run detection, cache results
|
||||
- Subsequent selections → use cached results
|
||||
- Detection refresh → only if tool installation occurs mid-session
|
||||
|
||||
## Tools to Check
|
||||
|
||||
### Core Tools (check these)
|
||||
|
||||
**File operations**:
|
||||
- fd (preferred) / find (fallback)
|
||||
- bat (preferred) / cat (fallback)
|
||||
- eza (preferred) / ls (fallback)
|
||||
|
||||
**Search**:
|
||||
- rg (preferred) / grep (fallback)
|
||||
- sg (preferred for AST) / rg (fallback)
|
||||
|
||||
**Data processing**:
|
||||
- jq (preferred) / node/python (fallback)
|
||||
|
||||
**Version control**:
|
||||
- delta (preferred) / git diff (fallback)
|
||||
|
||||
**Navigation**:
|
||||
- zoxide (preferred) / cd (fallback)
|
||||
- fzf (no direct fallback)
|
||||
|
||||
**Network**:
|
||||
- httpie (preferred) / curl (fallback)
|
||||
|
||||
### Package Managers (detect for install suggestions)
|
||||
|
||||
**macOS**:
|
||||
- brew (primary)
|
||||
- port (alternative)
|
||||
|
||||
**Linux**:
|
||||
- apt (Debian/Ubuntu)
|
||||
- dnf (Fedora/RHEL)
|
||||
- pacman (Arch)
|
||||
- zypper (openSUSE)
|
||||
|
||||
**Cross-platform**:
|
||||
- cargo (Rust tools: rg, fd, bat, etc.)
|
||||
- npm (JavaScript tools)
|
||||
- pipx (Python tools)
|
||||
|
||||
## Error Handling
|
||||
|
||||
Script should:
|
||||
- Never fail/throw — return partial results if some checks fail
|
||||
- Log warnings for unexpected errors
|
||||
- Provide empty arrays for unavailable categories
|
||||
- Always return valid JSON
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential additions:
|
||||
- Version checking (some tools require minimum version)
|
||||
- Performance profiling (measure actual tool speed)
|
||||
- Configuration detection (is tool already configured?)
|
||||
- Integration checking (shell aliases, git config)
|
||||
@@ -0,0 +1,610 @@
|
||||
# Tool Catalog
|
||||
|
||||
Recommended modern CLI tools organized by category. Each entry includes usage, installation, and rationale.
|
||||
|
||||
## Search Tools
|
||||
|
||||
### fd
|
||||
|
||||
**Category:** search
|
||||
**Replaces:** find
|
||||
**Description:** Fast, user-friendly file finder with smart defaults
|
||||
|
||||
#### Why upgrade?
|
||||
|
||||
- 8× faster than find on large directories
|
||||
- Ignores `.gitignore` and hidden files by default
|
||||
- Colored output with syntax highlighting
|
||||
- Simpler, more intuitive syntax
|
||||
- Parallel directory traversal
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
fd pattern # Find files matching pattern
|
||||
fd -e ts # Find all .ts files
|
||||
fd -e ts -x wc -l # Count lines in each .ts file
|
||||
fd -H config # Include hidden files
|
||||
fd -I node_modules # Include ignored files
|
||||
fd pattern src/ # Search in specific directory
|
||||
fd '^test.*\.ts$' # Regex pattern
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install fd` |
|
||||
| Cargo | `cargo install fd-find` |
|
||||
| apt | `apt install fd-find` |
|
||||
| dnf | `dnf install fd-find` |
|
||||
|
||||
[GitHub](https://github.com/sharkdp/fd)
|
||||
|
||||
---
|
||||
|
||||
### ripgrep (rg)
|
||||
|
||||
**Category:** search
|
||||
**Replaces:** grep, ack, ag (the silver searcher)
|
||||
**Description:** Line-oriented search tool that recursively searches the current directory
|
||||
|
||||
#### Why upgrade?
|
||||
|
||||
- 10–100× faster than grep/ack/ag
|
||||
- Respects `.gitignore` by default
|
||||
- Automatic binary file detection
|
||||
- Better defaults (recursive, colored, line numbers)
|
||||
- Supports .ignore files for custom exclusions
|
||||
- Fast PCRE2 regex engine
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
rg pattern # Search current directory
|
||||
rg -i pattern # Case-insensitive search
|
||||
rg -t ts pattern # Search only TypeScript files
|
||||
rg -T tests pattern # Exclude tests directory
|
||||
rg 'fn \w+' -r 'function $0' # Search and replace preview
|
||||
rg pattern --files-with-matches # Show only filenames
|
||||
rg -C 3 pattern # Show 3 lines of context
|
||||
rg --hidden pattern # Include hidden files
|
||||
rg --no-ignore pattern # Include ignored files
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install ripgrep` |
|
||||
| Cargo | `cargo install ripgrep` |
|
||||
| apt | `apt install ripgrep` |
|
||||
| dnf | `dnf install ripgrep` |
|
||||
|
||||
[GitHub](https://github.com/BurntSushi/ripgrep)
|
||||
|
||||
---
|
||||
|
||||
### ast-grep (sg)
|
||||
|
||||
**Category:** search
|
||||
**Replaces:** (no direct legacy equivalent)
|
||||
**Description:** Code structural search and rewrite tool using AST patterns
|
||||
|
||||
#### Why use it?
|
||||
|
||||
- Language-aware pattern matching (not just text)
|
||||
- Understands code structure and semantics
|
||||
- Prevents false positives from string matches
|
||||
- Supports 20+ languages
|
||||
- Fast native performance (Rust)
|
||||
- Pattern-based refactoring capabilities
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
sg -p 'console.log($$$)' # Find all console.log calls
|
||||
sg -p 'if ($A) { $B }' --lang ts # Find if statements
|
||||
sg scan # Run configured rules
|
||||
sg --pattern '$A == null' --rewrite '$A === null' # Refactor
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install ast-grep` |
|
||||
| Cargo | `cargo install ast-grep` |
|
||||
| npm | `npm install -g @ast-grep/cli` |
|
||||
|
||||
[GitHub](https://github.com/ast-grep/ast-grep) | [Docs](https://ast-grep.github.io/)
|
||||
|
||||
---
|
||||
|
||||
## JSON Tools
|
||||
|
||||
### jq
|
||||
|
||||
**Category:** json
|
||||
**Replaces:** (no direct legacy equivalent)
|
||||
**Description:** Command-line JSON processor with query language
|
||||
|
||||
#### Why use it?
|
||||
|
||||
- Parse, filter, and transform JSON from CLI
|
||||
- Powerful query syntax
|
||||
- Handles streaming JSON
|
||||
- Colored output
|
||||
- Widely adopted standard
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
cat data.json | jq '.' # Pretty-print JSON
|
||||
jq '.items[] | .name' # Extract all names from items array
|
||||
jq 'select(.status == "active")' # Filter objects
|
||||
jq '.[] | {name, email}' # Transform shape
|
||||
jq -r '.token' # Raw output (no quotes)
|
||||
curl api.com/data | jq '.results[0]' # Parse API response
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install jq` |
|
||||
| apt | `apt install jq` |
|
||||
| dnf | `dnf install jq` |
|
||||
|
||||
[GitHub](https://github.com/jqlang/jq) | [Docs](https://jqlang.github.io/jq/)
|
||||
|
||||
---
|
||||
|
||||
## File Viewers
|
||||
|
||||
### bat
|
||||
|
||||
**Category:** viewers
|
||||
**Replaces:** cat
|
||||
**Description:** Cat clone with syntax highlighting and git integration
|
||||
|
||||
#### Why upgrade?
|
||||
|
||||
- Syntax highlighting for 200+ languages
|
||||
- Git gutter showing changes
|
||||
- Automatic paging for long files
|
||||
- Line numbers by default
|
||||
- Non-printable character visualization
|
||||
- Integrates with other tools (fzf, rg)
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
bat README.md # View file with syntax highlighting
|
||||
bat -n file.ts # Show line numbers
|
||||
bat --style=plain file.txt # Disable decorations
|
||||
bat -A file.sh # Show non-printable characters
|
||||
bat -d file.js # Show git diff
|
||||
bat file1.ts file2.ts # View multiple files
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install bat` |
|
||||
| Cargo | `cargo install bat` |
|
||||
| apt | `apt install bat` |
|
||||
| dnf | `dnf install bat` |
|
||||
|
||||
[GitHub](https://github.com/sharkdp/bat)
|
||||
|
||||
---
|
||||
|
||||
### eza
|
||||
|
||||
**Category:** viewers
|
||||
**Replaces:** ls, exa
|
||||
**Description:** Modern ls replacement with better defaults and git awareness
|
||||
|
||||
#### Why upgrade?
|
||||
|
||||
- Colored output by default
|
||||
- Git status integration
|
||||
- Tree view built-in
|
||||
- Icons support (with nerdfont)
|
||||
- Better permission display
|
||||
- Maintained fork of unmaintained exa
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
eza # List files (colored)
|
||||
eza -l # Long format
|
||||
eza -la # Include hidden files
|
||||
eza -T # Tree view
|
||||
eza -lh --git # Show git status
|
||||
eza --sort=modified # Sort by modification time
|
||||
eza --icons # Show file icons
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install eza` |
|
||||
| Cargo | `cargo install eza` |
|
||||
| apt | `apt install eza` |
|
||||
| dnf | `dnf install eza` |
|
||||
|
||||
[GitHub](https://github.com/eza-community/eza)
|
||||
|
||||
---
|
||||
|
||||
### git-delta
|
||||
|
||||
**Category:** viewers
|
||||
**Replaces:** git diff
|
||||
**Description:** Syntax-highlighting pager for git, diff, and grep output
|
||||
|
||||
#### Why upgrade?
|
||||
|
||||
- Side-by-side diff view
|
||||
- Syntax highlighting in diffs
|
||||
- Line numbers
|
||||
- Better moved code detection
|
||||
- Integrates with bat themes
|
||||
- Works with git, diff output, and grep
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
# Configure git to use delta
|
||||
git config --global core.pager delta
|
||||
git config --global interactive.diffFilter "delta --color-only"
|
||||
|
||||
# Then use git normally
|
||||
git diff # Now uses delta
|
||||
git show # Syntax-highlighted commits
|
||||
git log -p # Beautiful patch logs
|
||||
git blame # Enhanced blame view
|
||||
|
||||
# Direct usage
|
||||
diff -u file1 file2 | delta
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install git-delta` |
|
||||
| Cargo | `cargo install git-delta` |
|
||||
| apt | `apt install git-delta` |
|
||||
| dnf | `dnf install git-delta` |
|
||||
|
||||
[GitHub](https://github.com/dandavison/delta)
|
||||
|
||||
---
|
||||
|
||||
## Navigation Tools
|
||||
|
||||
### zoxide
|
||||
|
||||
**Category:** navigation
|
||||
**Replaces:** cd with manual path typing
|
||||
**Description:** Smarter cd command that learns your habits
|
||||
|
||||
#### Why upgrade?
|
||||
|
||||
- Jump to frequently used directories with partial names
|
||||
- Frecency algorithm (frequency + recency)
|
||||
- Works across all shells
|
||||
- Interactive selection with fzf integration
|
||||
- No manual bookmarking needed
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
# After installation, use 'z' instead of 'cd'
|
||||
z proj # Jump to ~/Developer/projects
|
||||
z doc agents # Jump to ~/Documents/agents
|
||||
zi # Interactive directory selection
|
||||
z - # Go to previous directory
|
||||
zoxide query proj # Query without jumping
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install zoxide` |
|
||||
| Cargo | `cargo install zoxide` |
|
||||
| apt | `apt install zoxide` |
|
||||
|
||||
**Post-install:** Add to shell config:
|
||||
|
||||
```bash
|
||||
# ~/.zshrc or ~/.bashrc
|
||||
eval "$(zoxide init zsh)" # for zsh
|
||||
eval "$(zoxide init bash)" # for bash
|
||||
```
|
||||
|
||||
[GitHub](https://github.com/ajeetdsouza/zoxide)
|
||||
|
||||
---
|
||||
|
||||
### fzf
|
||||
|
||||
**Category:** navigation
|
||||
**Replaces:** manual history search, manual file selection
|
||||
**Description:** General-purpose fuzzy finder for command-line
|
||||
|
||||
#### Why use it?
|
||||
|
||||
- Interactive fuzzy search for any list
|
||||
- Fast C implementation
|
||||
- Integrates with shell history, files, git
|
||||
- Pipe any command output to fzf
|
||||
- Preview window support
|
||||
- Used by many other tools
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
# Basic fuzzy finding
|
||||
fzf # Search files in current dir
|
||||
history | fzf # Search command history
|
||||
|
||||
# With preview
|
||||
fzf --preview 'bat {}' # Preview files with bat
|
||||
|
||||
# Shell integration (after install)
|
||||
Ctrl-R # Search command history
|
||||
Ctrl-T # Search files
|
||||
Alt-C # Change directory
|
||||
|
||||
# Pipe integration
|
||||
git branch | fzf | xargs git checkout # Interactive branch checkout
|
||||
ps aux | fzf | awk '{print $2}' | xargs kill # Interactive process kill
|
||||
|
||||
# With other tools
|
||||
rg pattern | fzf # Fuzzy search through grep results
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install fzf` |
|
||||
| apt | `apt install fzf` |
|
||||
| dnf | `dnf install fzf` |
|
||||
|
||||
**Post-install:** Enable key bindings:
|
||||
|
||||
```bash
|
||||
# macOS with Homebrew
|
||||
$(brew --prefix)/opt/fzf/install
|
||||
```
|
||||
|
||||
[GitHub](https://github.com/junegunn/fzf)
|
||||
|
||||
---
|
||||
|
||||
## HTTP Tools
|
||||
|
||||
### httpie
|
||||
|
||||
**Category:** http
|
||||
**Replaces:** curl (for API testing)
|
||||
**Description:** Human-friendly HTTP client for testing APIs
|
||||
|
||||
#### Why upgrade?
|
||||
|
||||
- Simpler syntax than curl
|
||||
- JSON support by default
|
||||
- Syntax highlighting
|
||||
- Formatted output
|
||||
- Session support
|
||||
- File upload support
|
||||
- Better error messages
|
||||
|
||||
#### Typical usage
|
||||
|
||||
```bash
|
||||
# GET request
|
||||
http GET api.example.com/users
|
||||
|
||||
# POST JSON (automatic content-type)
|
||||
http POST api.example.com/users name=John email=john@example.com
|
||||
|
||||
# Headers
|
||||
http GET api.example.com/users Authorization:"Bearer token"
|
||||
|
||||
# Download file
|
||||
http --download example.com/file.zip
|
||||
|
||||
# Upload file
|
||||
http POST api.example.com/upload < file.json
|
||||
|
||||
# Form data
|
||||
http --form POST api.example.com/form name=John file@photo.jpg
|
||||
|
||||
# Sessions (save auth)
|
||||
http --session=user1 POST api.example.com/login username=user1
|
||||
http --session=user1 GET api.example.com/profile # Reuses auth
|
||||
```
|
||||
|
||||
#### Installation
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Homebrew | `brew install httpie` |
|
||||
| pip | `pip install httpie` |
|
||||
| apt | `apt install httpie` |
|
||||
| dnf | `dnf install httpie` |
|
||||
|
||||
[GitHub](https://github.com/httpie/cli) | [Docs](https://httpie.io/docs/cli)
|
||||
|
||||
---
|
||||
|
||||
## Tool Comparison Matrix
|
||||
|
||||
Quick reference for choosing between tools:
|
||||
|
||||
| Task | Legacy | Modern | Speed Gain |
|
||||
|------|--------|--------|------------|
|
||||
| Find files | find | fd | 8× |
|
||||
| Search text | grep | ripgrep | 10–100× |
|
||||
| Search code structure | - | ast-grep | N/A |
|
||||
| Parse JSON | - | jq | N/A |
|
||||
| View files | cat | bat | Similar |
|
||||
| List files | ls | eza | Similar |
|
||||
| Git diffs | git diff | git-delta | Similar |
|
||||
| Navigate dirs | cd | zoxide | 10× fewer keystrokes |
|
||||
| Fuzzy search | - | fzf | N/A |
|
||||
| HTTP requests | curl | httpie | Similar |
|
||||
|
||||
**Speed Gain:** Approximate performance improvement or ergonomic benefit
|
||||
|
||||
---
|
||||
|
||||
## Installation Bundles
|
||||
|
||||
Install all recommended tools at once:
|
||||
|
||||
### Homebrew (macOS/Linux)
|
||||
|
||||
```bash
|
||||
brew install \
|
||||
fd \
|
||||
ripgrep \
|
||||
ast-grep \
|
||||
jq \
|
||||
bat \
|
||||
eza \
|
||||
git-delta \
|
||||
zoxide \
|
||||
fzf \
|
||||
httpie
|
||||
|
||||
# Post-install configuration
|
||||
eval "$(zoxide init zsh)"
|
||||
$(brew --prefix)/opt/fzf/install
|
||||
git config --global core.pager delta
|
||||
```
|
||||
|
||||
### Cargo (Cross-platform)
|
||||
|
||||
```bash
|
||||
cargo install \
|
||||
fd-find \
|
||||
ripgrep \
|
||||
bat \
|
||||
eza \
|
||||
git-delta \
|
||||
zoxide \
|
||||
ast-grep
|
||||
|
||||
# jq, fzf, httpie still need system package manager
|
||||
```
|
||||
|
||||
### apt (Debian/Ubuntu)
|
||||
|
||||
```bash
|
||||
sudo apt install \
|
||||
fd-find \
|
||||
ripgrep \
|
||||
bat \
|
||||
eza \
|
||||
git-delta \
|
||||
zoxide \
|
||||
fzf \
|
||||
jq \
|
||||
httpie
|
||||
|
||||
# ast-grep may need cargo or npm
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Shell Aliases
|
||||
|
||||
Recommended aliases to maintain muscle memory:
|
||||
|
||||
```bash
|
||||
# ~/.zshrc or ~/.bashrc
|
||||
|
||||
# Optional: alias old commands to new ones
|
||||
alias cat='bat'
|
||||
alias ls='eza'
|
||||
alias find='fd'
|
||||
alias grep='rg'
|
||||
|
||||
# Or: keep old names, add shortcuts for new tools
|
||||
alias l='eza -l'
|
||||
alias la='eza -la'
|
||||
alias lt='eza -T'
|
||||
alias rg='rg --hidden'
|
||||
```
|
||||
|
||||
**Recommendation:** Start with shortcuts, not full aliases. Keeps old commands working on systems without these tools.
|
||||
|
||||
---
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### fzf + ripgrep + bat
|
||||
|
||||
Interactive search with preview:
|
||||
|
||||
```bash
|
||||
rg --files | fzf --preview 'bat --color=always {}'
|
||||
```
|
||||
|
||||
### fd + fzf
|
||||
|
||||
Find and preview files:
|
||||
|
||||
```bash
|
||||
fd -t f | fzf --preview 'bat --color=always {}'
|
||||
```
|
||||
|
||||
### httpie + jq
|
||||
|
||||
API testing with formatted output:
|
||||
|
||||
```bash
|
||||
http GET api.example.com/users | jq '.[] | {name, email}'
|
||||
```
|
||||
|
||||
### zoxide + eza
|
||||
|
||||
Quick navigation with listing:
|
||||
|
||||
```bash
|
||||
z() {
|
||||
cd "$(zoxide query "$@")" && eza -la
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## When to Fall Back
|
||||
|
||||
Use legacy tools when:
|
||||
|
||||
- Working on systems where installation requires admin access
|
||||
- Scripting for maximum portability (POSIX compliance)
|
||||
- Tool-specific features not available in modern equivalent
|
||||
- Embedded/minimal environments without package manager
|
||||
|
||||
In automation/scripts:
|
||||
|
||||
```bash
|
||||
# Check if modern tool exists, fall back gracefully
|
||||
if command -v fd &> /dev/null; then
|
||||
fd pattern
|
||||
else
|
||||
find . -name "*pattern*"
|
||||
fi
|
||||
```
|
||||
@@ -0,0 +1,138 @@
|
||||
# Tool Checker Scripts
|
||||
|
||||
Checks for modern CLI tools and provides installation guidance.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Check all tools (text output)
|
||||
bun scripts/index.ts
|
||||
|
||||
# Check specific category
|
||||
bun scripts/index.ts --category search
|
||||
bun scripts/index.ts -c viewers
|
||||
|
||||
# JSON output
|
||||
bun scripts/index.ts --format json
|
||||
bun scripts/index.ts -f json
|
||||
|
||||
# Combine options
|
||||
bun scripts/index.ts -c navigation -f json
|
||||
```
|
||||
|
||||
## Categories
|
||||
|
||||
- `search` - fd, ripgrep, ast-grep
|
||||
- `json` - jq
|
||||
- `viewers` - bat, eza, delta
|
||||
- `navigation` - zoxide, fzf
|
||||
- `http` - httpie
|
||||
|
||||
## Output Formats
|
||||
|
||||
### Text (default)
|
||||
|
||||
```
|
||||
◆ Available Tools
|
||||
|
||||
search
|
||||
✓ fd 10.2.0 — Fast file finder (replaces find)
|
||||
✓ rg 14.1.0 — Fast code search (replaces grep)
|
||||
✗ sg — AST-aware code search and refactoring
|
||||
→ brew install ast-grep
|
||||
|
||||
◇ Summary: 2/3 tools available
|
||||
```
|
||||
|
||||
### JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"search": [
|
||||
{
|
||||
"name": "fd",
|
||||
"command": "fd",
|
||||
"category": "search",
|
||||
"available": true,
|
||||
"version": "fd 10.2.0",
|
||||
"replaces": "find",
|
||||
"description": "Fast file finder",
|
||||
"install": {
|
||||
"brew": "brew install fd",
|
||||
"cargo": "cargo install fd-find",
|
||||
"apt": "apt install fd-find",
|
||||
"url": "https://github.com/sharkdp/fd"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
scripts/
|
||||
├── index.ts # Entry point - CLI arg parsing and orchestration
|
||||
├── types.ts # Shared TypeScript types
|
||||
├── utils.ts # Tool detection utilities
|
||||
└── checkers/
|
||||
├── search.ts # fd, rg, sg
|
||||
├── json.ts # jq
|
||||
├── viewers.ts # bat, eza, delta
|
||||
├── navigation.ts # z, fzf
|
||||
└── http.ts # http (httpie)
|
||||
```
|
||||
|
||||
Each checker module exports a function that returns `Promise<ToolCheckResult[]>`.
|
||||
|
||||
## Adding New Tools
|
||||
|
||||
1. Add tool definition to appropriate checker module:
|
||||
|
||||
```typescript
|
||||
{
|
||||
name: "tool-name",
|
||||
command: "actual-command",
|
||||
category: "category",
|
||||
replaces: "legacy-tool", // optional
|
||||
description: "One-line description",
|
||||
install: {
|
||||
brew: "brew install tool-name",
|
||||
cargo: "cargo install tool-name", // optional
|
||||
apt: "apt install tool-name", // optional
|
||||
url: "https://github.com/org/repo",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
2. Tool is automatically checked and included in results.
|
||||
|
||||
## Adding New Categories
|
||||
|
||||
1. Add category to `types.ts`:
|
||||
|
||||
```typescript
|
||||
export type Category = "search" | "json" | "viewers" | "navigation" | "http" | "new-category";
|
||||
```
|
||||
|
||||
2. Create checker module `checkers/new-category.ts`:
|
||||
|
||||
```typescript
|
||||
import type { ToolCheckResult } from "../types.ts";
|
||||
import { checkTool } from "../utils.ts";
|
||||
|
||||
export async function checkNewCategoryTools(): Promise<ToolCheckResult[]> {
|
||||
// ... implementation
|
||||
}
|
||||
```
|
||||
|
||||
3. Import and register in `index.ts`:
|
||||
|
||||
```typescript
|
||||
import { checkNewCategoryTools } from "./checkers/new-category.ts";
|
||||
|
||||
const CHECKERS: Record<Category, CheckerFunction> = {
|
||||
// ...
|
||||
"new-category": checkNewCategoryTools,
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { ToolCheckResult } from "../types.ts";
|
||||
import { checkTool } from "../utils.ts";
|
||||
|
||||
/**
|
||||
* Checks availability of HTTP client tools (httpie).
|
||||
* @returns Array of tool check results for HTTP category
|
||||
*/
|
||||
export async function checkHttpTools(): Promise<ToolCheckResult[]> {
|
||||
const tools = [
|
||||
{
|
||||
name: "httpie",
|
||||
command: "http",
|
||||
category: "http",
|
||||
replaces: "curl",
|
||||
description: "Human-friendly HTTP client for testing APIs",
|
||||
install: {
|
||||
brew: "brew install httpie",
|
||||
apt: "apt install httpie",
|
||||
url: "https://httpie.io/",
|
||||
},
|
||||
},
|
||||
] as const;
|
||||
|
||||
const results = await Promise.all(
|
||||
tools.map(async (tool) => {
|
||||
const { available, version } = await checkTool(tool.command);
|
||||
return {
|
||||
...tool,
|
||||
available,
|
||||
version,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return results;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { ToolCheckResult } from "../types.ts";
|
||||
import { checkTool } from "../utils.ts";
|
||||
|
||||
/**
|
||||
* Checks availability of JSON processing tools (jq).
|
||||
* @returns Array of tool check results for JSON category
|
||||
*/
|
||||
export async function checkJsonTools(): Promise<ToolCheckResult[]> {
|
||||
const tools = [
|
||||
{
|
||||
name: "jq",
|
||||
command: "jq",
|
||||
category: "json",
|
||||
description: "JSON processor and query language",
|
||||
install: {
|
||||
brew: "brew install jq",
|
||||
apt: "apt install jq",
|
||||
url: "https://jqlang.github.io/jq/",
|
||||
},
|
||||
},
|
||||
] as const;
|
||||
|
||||
const results = await Promise.all(
|
||||
tools.map(async (tool) => {
|
||||
const { available, version } = await checkTool(tool.command);
|
||||
return {
|
||||
...tool,
|
||||
available,
|
||||
version,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return results;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { ToolCheckResult } from "../types.ts";
|
||||
import { checkTool } from "../utils.ts";
|
||||
|
||||
/**
|
||||
* Checks availability of navigation tools (zoxide, fzf).
|
||||
* @returns Array of tool check results for navigation category
|
||||
*/
|
||||
export async function checkNavigationTools(): Promise<ToolCheckResult[]> {
|
||||
const tools = [
|
||||
{
|
||||
name: "zoxide",
|
||||
command: "z",
|
||||
category: "navigation",
|
||||
replaces: "cd",
|
||||
description: "Smart directory jumper that learns your habits",
|
||||
install: {
|
||||
brew: "brew install zoxide",
|
||||
cargo: "cargo install zoxide",
|
||||
apt: "apt install zoxide",
|
||||
url: "https://github.com/ajeetdsouza/zoxide",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fzf",
|
||||
command: "fzf",
|
||||
category: "navigation",
|
||||
description: "Fuzzy finder for files, commands, and more",
|
||||
install: {
|
||||
brew: "brew install fzf",
|
||||
apt: "apt install fzf",
|
||||
url: "https://github.com/junegunn/fzf",
|
||||
},
|
||||
},
|
||||
] as const;
|
||||
|
||||
const results = await Promise.all(
|
||||
tools.map(async (tool) => {
|
||||
const { available, version } = await checkTool(tool.command);
|
||||
return {
|
||||
...tool,
|
||||
available,
|
||||
version,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return results;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { ToolCheckResult } from "../types.ts";
|
||||
import { checkTool } from "../utils.ts";
|
||||
|
||||
/**
|
||||
* Checks availability of search-related CLI tools (fd, ripgrep, ast-grep).
|
||||
* @returns Array of tool check results for search category
|
||||
*/
|
||||
export async function checkSearchTools(): Promise<ToolCheckResult[]> {
|
||||
const tools = [
|
||||
{
|
||||
name: "fd",
|
||||
command: "fd",
|
||||
category: "search",
|
||||
replaces: "find",
|
||||
description: "Fast file finder",
|
||||
install: {
|
||||
brew: "brew install fd",
|
||||
cargo: "cargo install fd-find",
|
||||
apt: "apt install fd-find",
|
||||
url: "https://github.com/sharkdp/fd",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ripgrep",
|
||||
command: "rg",
|
||||
category: "search",
|
||||
replaces: "grep",
|
||||
description: "Fast code search",
|
||||
install: {
|
||||
brew: "brew install ripgrep",
|
||||
cargo: "cargo install ripgrep",
|
||||
apt: "apt install ripgrep",
|
||||
url: "https://github.com/BurntSushi/ripgrep",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ast-grep",
|
||||
command: "sg",
|
||||
category: "search",
|
||||
description: "AST-aware code search and refactoring",
|
||||
install: {
|
||||
brew: "brew install ast-grep",
|
||||
cargo: "cargo install ast-grep",
|
||||
apt: "npm install -g @ast-grep/cli",
|
||||
url: "https://github.com/ast-grep/ast-grep",
|
||||
},
|
||||
},
|
||||
] as const;
|
||||
|
||||
const results = await Promise.all(
|
||||
tools.map(async (tool) => {
|
||||
const { available, version } = await checkTool(tool.command);
|
||||
return {
|
||||
...tool,
|
||||
available,
|
||||
version,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return results;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import type { ToolCheckResult } from "../types.ts";
|
||||
import { checkTool } from "../utils.ts";
|
||||
|
||||
/**
|
||||
* Checks availability of file viewer tools (bat, eza, delta).
|
||||
* @returns Array of tool check results for viewers category
|
||||
*/
|
||||
export async function checkViewerTools(): Promise<ToolCheckResult[]> {
|
||||
const tools = [
|
||||
{
|
||||
name: "bat",
|
||||
command: "bat",
|
||||
category: "viewers",
|
||||
replaces: "cat",
|
||||
description: "cat with syntax highlighting and git integration",
|
||||
install: {
|
||||
brew: "brew install bat",
|
||||
cargo: "cargo install bat",
|
||||
apt: "apt install bat",
|
||||
url: "https://github.com/sharkdp/bat",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eza",
|
||||
command: "eza",
|
||||
category: "viewers",
|
||||
replaces: "ls",
|
||||
description: "Modern ls replacement with colors and icons",
|
||||
install: {
|
||||
brew: "brew install eza",
|
||||
cargo: "cargo install eza",
|
||||
apt: "apt install eza",
|
||||
url: "https://github.com/eza-community/eza",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delta",
|
||||
command: "delta",
|
||||
category: "viewers",
|
||||
replaces: "diff",
|
||||
description: "Better git diff pager with syntax highlighting",
|
||||
install: {
|
||||
brew: "brew install git-delta",
|
||||
cargo: "cargo install git-delta",
|
||||
apt: "apt install git-delta",
|
||||
url: "https://github.com/dandavison/delta",
|
||||
},
|
||||
},
|
||||
] as const;
|
||||
|
||||
const results = await Promise.all(
|
||||
tools.map(async (tool) => {
|
||||
const { available, version } = await checkTool(tool.command);
|
||||
return {
|
||||
...tool,
|
||||
available,
|
||||
version,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return results;
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import { parseArgs } from "node:util";
|
||||
import type { Category, OutputFormat, ToolCheckResult } from "./types.ts";
|
||||
import { checkSearchTools } from "./checkers/search.ts";
|
||||
import { checkJsonTools } from "./checkers/json.ts";
|
||||
import { checkViewerTools } from "./checkers/viewers.ts";
|
||||
import { checkNavigationTools } from "./checkers/navigation.ts";
|
||||
import { checkHttpTools } from "./checkers/http.ts";
|
||||
|
||||
/**
|
||||
* Function signature for tool category checkers.
|
||||
*/
|
||||
interface CheckerFunction {
|
||||
(): Promise<ToolCheckResult[]>;
|
||||
}
|
||||
|
||||
const CHECKERS: Record<Category, CheckerFunction> = {
|
||||
search: checkSearchTools,
|
||||
json: checkJsonTools,
|
||||
viewers: checkViewerTools,
|
||||
navigation: checkNavigationTools,
|
||||
http: checkHttpTools,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse command-line arguments
|
||||
*/
|
||||
function parseCliArgs() {
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
category: {
|
||||
type: "string",
|
||||
short: "c",
|
||||
},
|
||||
format: {
|
||||
type: "string",
|
||||
short: "f",
|
||||
default: "text",
|
||||
},
|
||||
},
|
||||
strict: true,
|
||||
allowPositionals: false,
|
||||
});
|
||||
|
||||
const category = values.category as Category | undefined;
|
||||
const format = (values.format || "text") as OutputFormat;
|
||||
|
||||
// Validate category if provided
|
||||
if (category && !Object.keys(CHECKERS).includes(category)) {
|
||||
console.error(
|
||||
`Invalid category: ${category}. Valid categories: ${Object.keys(CHECKERS).join(", ")}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Validate format
|
||||
if (format !== "json" && format !== "text") {
|
||||
console.error(`Invalid format: ${format}. Valid formats: json, text`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return { category, format };
|
||||
}
|
||||
|
||||
/**
|
||||
* Run checkers based on category filter
|
||||
*/
|
||||
async function runCheckers(
|
||||
category?: Category,
|
||||
): Promise<Map<Category, ToolCheckResult[]>> {
|
||||
const categoriesToRun = category
|
||||
? [category]
|
||||
: (Object.keys(CHECKERS) as Category[]);
|
||||
|
||||
const results = await Promise.allSettled(
|
||||
categoriesToRun.map(async (cat) => {
|
||||
const checker = CHECKERS[cat];
|
||||
const tools = await checker();
|
||||
return { category: cat, tools };
|
||||
}),
|
||||
);
|
||||
|
||||
const toolsByCategory = new Map<Category, ToolCheckResult[]>();
|
||||
|
||||
for (const result of results) {
|
||||
if (result.status === "fulfilled") {
|
||||
toolsByCategory.set(result.value.category, result.value.tools);
|
||||
} else {
|
||||
console.error(`Error checking tools: ${result.reason}`);
|
||||
}
|
||||
}
|
||||
|
||||
return toolsByCategory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format results as JSON
|
||||
*/
|
||||
function formatJson(toolsByCategory: Map<Category, ToolCheckResult[]>): string {
|
||||
const output: Record<string, ToolCheckResult[]> = {};
|
||||
|
||||
for (const [category, tools] of toolsByCategory) {
|
||||
output[category] = tools;
|
||||
}
|
||||
|
||||
return JSON.stringify(output, null, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format results as human-readable text
|
||||
*/
|
||||
function formatText(toolsByCategory: Map<Category, ToolCheckResult[]>): string {
|
||||
const lines: string[] = ["◆ Available Tools", ""];
|
||||
|
||||
let totalTools = 0;
|
||||
let availableTools = 0;
|
||||
|
||||
for (const [category, tools] of toolsByCategory) {
|
||||
lines.push(` ${category}`);
|
||||
|
||||
for (const tool of tools) {
|
||||
totalTools++;
|
||||
if (tool.available) {
|
||||
availableTools++;
|
||||
const versionStr = tool.version ? ` ${tool.version}` : "";
|
||||
const replacesStr = tool.replaces ? ` (replaces ${tool.replaces})` : "";
|
||||
lines.push(
|
||||
` ✓ ${tool.name}${versionStr} — ${tool.description}${replacesStr}`,
|
||||
);
|
||||
} else {
|
||||
lines.push(` ✗ ${tool.name} — ${tool.description}`);
|
||||
// Show installation hint (prefer brew, then cargo, then apt)
|
||||
const installCmd =
|
||||
tool.install.brew || tool.install.cargo || tool.install.apt;
|
||||
if (installCmd) {
|
||||
lines.push(` → ${installCmd}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lines.push("");
|
||||
}
|
||||
|
||||
lines.push(`◇ Summary: ${availableTools}/${totalTools} tools available`);
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point
|
||||
*/
|
||||
async function main() {
|
||||
const { category, format } = parseCliArgs();
|
||||
|
||||
const toolsByCategory = await runCheckers(category);
|
||||
|
||||
const output =
|
||||
format === "json"
|
||||
? formatJson(toolsByCategory)
|
||||
: formatText(toolsByCategory);
|
||||
|
||||
console.log(output);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error("Fatal error:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Result of checking a CLI tool's availability and version.
|
||||
*/
|
||||
export interface ToolCheckResult {
|
||||
/** Tool display name */
|
||||
name: string;
|
||||
/** Command used to invoke the tool */
|
||||
command: string;
|
||||
/** Tool category for grouping */
|
||||
category: string;
|
||||
/** Whether the tool is available in PATH */
|
||||
available: boolean;
|
||||
/** Version string if available */
|
||||
version?: string;
|
||||
/** Standard tool this replaces (e.g., fd replaces find) */
|
||||
replaces?: string;
|
||||
/** Human-readable description */
|
||||
description: string;
|
||||
/** Installation instructions by package manager */
|
||||
install: {
|
||||
brew?: string;
|
||||
cargo?: string;
|
||||
apt?: string;
|
||||
url: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool categories for grouping related tools.
|
||||
*/
|
||||
export type Category = "search" | "json" | "viewers" | "navigation" | "http";
|
||||
|
||||
/**
|
||||
* Output format for tool check results.
|
||||
*/
|
||||
export type OutputFormat = "json" | "text";
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Checks if a command-line tool is available and gets its version.
|
||||
* @param cmd - Command name to check in PATH
|
||||
* @returns Object with availability status and optional version string
|
||||
*/
|
||||
export async function checkTool(
|
||||
cmd: string,
|
||||
): Promise<{ available: boolean; version?: string }> {
|
||||
try {
|
||||
// Check if command exists
|
||||
const whichProc = Bun.spawn(["which", cmd], {
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
const exitCode = await whichProc.exited;
|
||||
|
||||
if (exitCode !== 0) {
|
||||
return { available: false };
|
||||
}
|
||||
|
||||
// Try to get version
|
||||
try {
|
||||
const versionProc = Bun.spawn([cmd, "--version"], {
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
const versionOut = await new Response(versionProc.stdout).text();
|
||||
await versionProc.exited;
|
||||
|
||||
// Extract first line and trim
|
||||
const version = versionOut.split("\n")[0]?.trim();
|
||||
return { available: true, version };
|
||||
} catch {
|
||||
// Tool exists but --version failed, still mark as available
|
||||
return { available: true };
|
||||
}
|
||||
} catch {
|
||||
return { available: false };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user