appydave-tools 0.74.0 → 0.74.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/bin/dam +16 -16
- data/bin/zsh_history.rb +2 -14
- data/docs/architecture/cli/cli-pattern-comparison.md +147 -17
- data/docs/architecture/cli/cli-patterns.md +311 -18
- data/docs/architecture/cli/pattern-4-delegated-cli.md +1058 -0
- data/lib/appydave/tools/dam/project_listing.rb +2 -12
- data/lib/appydave/tools/jump/cli.rb +0 -8
- data/lib/appydave/tools/jump/commands/generate.rb +0 -4
- data/lib/appydave/tools/jump/formatters/table_formatter.rb +0 -2
- data/lib/appydave/tools/jump/search.rb +0 -2
- data/lib/appydave/tools/version.rb +1 -1
- data/lib/appydave/tools.rb +3 -2
- data/package.json +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef8315540ea80d07de1a6eba6733c1be84e21caaa4251dbb60e9a2207abf9758
|
|
4
|
+
data.tar.gz: 3a386ab9c8b399ceca1056f20fae6543bc534ddf37a7d104363acc09ad694e48
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70af1beaa0539e9a71ffb1e4435ffe1afad1da73cfbbe4f16c780110684975fdbf3de5602e7cc5b9bd226404158d0f24aee5126186b3821235b782508bc9150b
|
|
7
|
+
data.tar.gz: 6e06cc27ccebd7d49ba9831f3e9f1345f96bc0ffce681fc56be6a08799a32d828b8c68e32633d74a99b397a1a7bde699c89a5077745439ccbc9f3c8cf3e2af2e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [0.74.0](https://github.com/appydave/appydave-tools/compare/v0.73.0...v0.74.0) (2025-12-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add auto-regenerate aliases after jump CRUD operations ([0fe21d7](https://github.com/appydave/appydave-tools/commit/0fe21d72c4af492ebebf75645683dd49b9a2fe52))
|
|
7
|
+
|
|
1
8
|
# [0.73.0](https://github.com/appydave/appydave-tools/compare/v0.72.0...v0.73.0) (2025-12-18)
|
|
2
9
|
|
|
3
10
|
|
data/bin/dam
CHANGED
|
@@ -35,7 +35,7 @@ class VatCLI
|
|
|
35
35
|
}
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
# rubocop:disable Metrics/
|
|
38
|
+
# rubocop:disable Metrics/MethodLength
|
|
39
39
|
def run
|
|
40
40
|
command, *args = ARGV
|
|
41
41
|
|
|
@@ -78,12 +78,12 @@ class VatCLI
|
|
|
78
78
|
exit 1
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
|
-
# rubocop:enable Metrics/
|
|
81
|
+
# rubocop:enable Metrics/MethodLength
|
|
82
82
|
|
|
83
83
|
private
|
|
84
84
|
|
|
85
85
|
# Show help information
|
|
86
|
-
# rubocop:disable Metrics/
|
|
86
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
87
87
|
def help_command(args)
|
|
88
88
|
topic = args[0]
|
|
89
89
|
|
|
@@ -126,7 +126,7 @@ class VatCLI
|
|
|
126
126
|
puts "Run 'dam help' for general help."
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
|
-
# rubocop:enable Metrics/
|
|
129
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
130
130
|
|
|
131
131
|
# List brands and projects
|
|
132
132
|
def list_command(args)
|
|
@@ -463,7 +463,7 @@ class VatCLI
|
|
|
463
463
|
end
|
|
464
464
|
|
|
465
465
|
# Parse S3 command arguments
|
|
466
|
-
# rubocop:disable Metrics/
|
|
466
|
+
# rubocop:disable Metrics/MethodLength
|
|
467
467
|
def parse_s3_args(args, command)
|
|
468
468
|
dry_run = args.include?('--dry-run')
|
|
469
469
|
force = args.include?('--force')
|
|
@@ -508,7 +508,7 @@ class VatCLI
|
|
|
508
508
|
|
|
509
509
|
{ brand: brand_key, project: project_id, dry_run: dry_run, force: force }
|
|
510
510
|
end
|
|
511
|
-
# rubocop:enable Metrics/
|
|
511
|
+
# rubocop:enable Metrics/MethodLength
|
|
512
512
|
|
|
513
513
|
def valid_brand?(brand_key)
|
|
514
514
|
Appydave::Tools::Configuration::Config.configure
|
|
@@ -520,7 +520,7 @@ class VatCLI
|
|
|
520
520
|
# Mutates the matched_projects hash to add :local_status key
|
|
521
521
|
# @param matched_projects [Hash] Map of project_id => S3 data
|
|
522
522
|
# @param brand_key [String] Brand key (e.g., 'appydave', 'ss')
|
|
523
|
-
# rubocop:disable Metrics/
|
|
523
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
524
524
|
def add_local_sync_status!(matched_projects, brand_key)
|
|
525
525
|
matched_projects.each do |project_id, data|
|
|
526
526
|
project_path = Appydave::Tools::Dam::Config.project_path(brand_key, project_id)
|
|
@@ -551,7 +551,7 @@ class VatCLI
|
|
|
551
551
|
end
|
|
552
552
|
end
|
|
553
553
|
end
|
|
554
|
-
# rubocop:enable Metrics/
|
|
554
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
555
555
|
|
|
556
556
|
# Format local sync status for display
|
|
557
557
|
# @param status [Symbol] :synced, :no_files, :partial, :no_project
|
|
@@ -660,7 +660,7 @@ class VatCLI
|
|
|
660
660
|
true
|
|
661
661
|
end
|
|
662
662
|
|
|
663
|
-
# rubocop:disable Metrics/MethodLength
|
|
663
|
+
# rubocop:disable Metrics/MethodLength
|
|
664
664
|
def display_s3_files(files, brand_key, project_id, shareable)
|
|
665
665
|
brand_display = Appydave::Tools::Dam::Config.expand_brand(brand_key)
|
|
666
666
|
|
|
@@ -721,7 +721,7 @@ class VatCLI
|
|
|
721
721
|
|
|
722
722
|
puts ''
|
|
723
723
|
end
|
|
724
|
-
# rubocop:enable Metrics/MethodLength
|
|
724
|
+
# rubocop:enable Metrics/MethodLength
|
|
725
725
|
|
|
726
726
|
# Help text methods
|
|
727
727
|
# rubocop:disable Metrics/MethodLength
|
|
@@ -1402,7 +1402,7 @@ class VatCLI
|
|
|
1402
1402
|
exit 1
|
|
1403
1403
|
end
|
|
1404
1404
|
|
|
1405
|
-
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
1405
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
1406
1406
|
def scan_single_brand_s3(brand_arg)
|
|
1407
1407
|
puts "🔄 Scanning S3 for #{brand_arg}..."
|
|
1408
1408
|
puts ''
|
|
@@ -1495,10 +1495,10 @@ class VatCLI
|
|
|
1495
1495
|
puts " • Manifest: #{manifest_path}"
|
|
1496
1496
|
puts ''
|
|
1497
1497
|
end
|
|
1498
|
-
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
1498
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
1499
1499
|
|
|
1500
1500
|
# Display S3 scan results in table format
|
|
1501
|
-
# rubocop:disable Metrics/MethodLength, Metrics/
|
|
1501
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Style/FormatStringToken
|
|
1502
1502
|
def display_s3_scan_table(matched_projects, orphaned_projects, bucket, prefix, region)
|
|
1503
1503
|
puts '✅ S3 Projects Report'
|
|
1504
1504
|
puts ''
|
|
@@ -1540,9 +1540,9 @@ class VatCLI
|
|
|
1540
1540
|
puts " #{console_url}"
|
|
1541
1541
|
end
|
|
1542
1542
|
end
|
|
1543
|
-
# rubocop:enable Metrics/MethodLength, Metrics/
|
|
1543
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Style/FormatStringToken
|
|
1544
1544
|
|
|
1545
|
-
# rubocop:disable Metrics/MethodLength
|
|
1545
|
+
# rubocop:disable Metrics/MethodLength
|
|
1546
1546
|
def scan_all_brands_s3
|
|
1547
1547
|
Appydave::Tools::Configuration::Config.configure
|
|
1548
1548
|
brands_config = Appydave::Tools::Configuration::Config.brands
|
|
@@ -1583,7 +1583,7 @@ class VatCLI
|
|
|
1583
1583
|
puts ''
|
|
1584
1584
|
puts "Total brands scanned: #{successful.size}/#{results.size}"
|
|
1585
1585
|
end
|
|
1586
|
-
# rubocop:enable Metrics/MethodLength
|
|
1586
|
+
# rubocop:enable Metrics/MethodLength
|
|
1587
1587
|
|
|
1588
1588
|
# Format bytes in human-readable format
|
|
1589
1589
|
# rubocop:disable Style/FormatStringToken
|
data/bin/zsh_history.rb
CHANGED
|
@@ -20,7 +20,6 @@ class ZshHistoryCLI
|
|
|
20
20
|
}
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
24
23
|
def run
|
|
25
24
|
command = ARGV[0]
|
|
26
25
|
|
|
@@ -65,7 +64,6 @@ class ZshHistoryCLI
|
|
|
65
64
|
exit 1
|
|
66
65
|
end
|
|
67
66
|
end
|
|
68
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
69
67
|
|
|
70
68
|
private
|
|
71
69
|
|
|
@@ -73,7 +71,7 @@ class ZshHistoryCLI
|
|
|
73
71
|
# HELP COMMAND
|
|
74
72
|
# ============================================================
|
|
75
73
|
|
|
76
|
-
# rubocop:disable Metrics/
|
|
74
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
77
75
|
def help_command(args)
|
|
78
76
|
topic = args[0]
|
|
79
77
|
|
|
@@ -110,9 +108,8 @@ class ZshHistoryCLI
|
|
|
110
108
|
puts ' zsh_history help workflow # Typical usage workflow'
|
|
111
109
|
end
|
|
112
110
|
end
|
|
113
|
-
# rubocop:enable Metrics/
|
|
111
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
114
112
|
|
|
115
|
-
# rubocop:disable Metrics/MethodLength
|
|
116
113
|
def show_main_help
|
|
117
114
|
puts <<~HELP
|
|
118
115
|
ZSH History - Parse, filter, and manage shell history
|
|
@@ -493,13 +490,11 @@ class ZshHistoryCLI
|
|
|
493
490
|
- ^ anchors to start of command
|
|
494
491
|
HELP
|
|
495
492
|
end
|
|
496
|
-
# rubocop:enable Metrics/MethodLength
|
|
497
493
|
|
|
498
494
|
# ============================================================
|
|
499
495
|
# SHOW COMMAND
|
|
500
496
|
# ============================================================
|
|
501
497
|
|
|
502
|
-
# rubocop:disable Metrics/AbcSize
|
|
503
498
|
def show_command(args)
|
|
504
499
|
options = parse_common_options(args)
|
|
505
500
|
|
|
@@ -526,13 +521,11 @@ class ZshHistoryCLI
|
|
|
526
521
|
|
|
527
522
|
write_output(output, options[:output])
|
|
528
523
|
end
|
|
529
|
-
# rubocop:enable Metrics/AbcSize
|
|
530
524
|
|
|
531
525
|
# ============================================================
|
|
532
526
|
# PURGE COMMAND
|
|
533
527
|
# ============================================================
|
|
534
528
|
|
|
535
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
536
529
|
def purge_command(args)
|
|
537
530
|
options = parse_common_options(args)
|
|
538
531
|
|
|
@@ -568,13 +561,11 @@ class ZshHistoryCLI
|
|
|
568
561
|
formatter.write_history(commands_to_write, options[:history_path])
|
|
569
562
|
end
|
|
570
563
|
end
|
|
571
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
572
564
|
|
|
573
565
|
# ============================================================
|
|
574
566
|
# STATS COMMAND
|
|
575
567
|
# ============================================================
|
|
576
568
|
|
|
577
|
-
# rubocop:disable Metrics/AbcSize
|
|
578
569
|
def stats_command(args)
|
|
579
570
|
options = parse_common_options(args)
|
|
580
571
|
|
|
@@ -602,7 +593,6 @@ class ZshHistoryCLI
|
|
|
602
593
|
formatter = Appydave::Tools::ZshHistory::Formatter.new
|
|
603
594
|
puts formatter.format_stats(result.stats, date_range: date_range)
|
|
604
595
|
end
|
|
605
|
-
# rubocop:enable Metrics/AbcSize
|
|
606
596
|
|
|
607
597
|
# ============================================================
|
|
608
598
|
# SEARCH COMMAND
|
|
@@ -789,7 +779,6 @@ class ZshHistoryCLI
|
|
|
789
779
|
# OPTION PARSING
|
|
790
780
|
# ============================================================
|
|
791
781
|
|
|
792
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
793
782
|
def parse_common_options(args)
|
|
794
783
|
options = {
|
|
795
784
|
days: nil,
|
|
@@ -839,7 +828,6 @@ class ZshHistoryCLI
|
|
|
839
828
|
parser.parse!(args)
|
|
840
829
|
options
|
|
841
830
|
end
|
|
842
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
843
831
|
end
|
|
844
832
|
|
|
845
833
|
# Run CLI
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Quick reference for choosing the right pattern when creating new CLI tools.
|
|
4
4
|
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
AppyDave Tools uses **four CLI patterns**, each optimized for different scales:
|
|
8
|
+
|
|
9
|
+
- **Pattern 1**: 1 operation - Simple, linear
|
|
10
|
+
- **Pattern 2**: 2-5 commands - Inline routing
|
|
11
|
+
- **Pattern 3**: 6-9 commands - BaseAction (shared validation)
|
|
12
|
+
- **Pattern 4**: 10+ commands - Delegated CLI (testable)
|
|
13
|
+
|
|
5
14
|
## Visual Comparison
|
|
6
15
|
|
|
7
16
|
```
|
|
@@ -68,20 +77,59 @@ Quick reference for choosing the right pattern when creating new CLI tools.
|
|
|
68
77
|
│ │
|
|
69
78
|
│ Examples: youtube_manager │
|
|
70
79
|
└─────────────────────────────────────────────────────────────────────┘
|
|
80
|
+
|
|
81
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
82
|
+
│ PATTERN 4: DELEGATED CLI CLASS │
|
|
83
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
84
|
+
│ │
|
|
85
|
+
│ bin/tool.rb ──────────────┐ │
|
|
86
|
+
│ (30 lines) │ │
|
|
87
|
+
│ cli = CLI.new │ │
|
|
88
|
+
│ exit(cli.run(ARGV)) │ │
|
|
89
|
+
│ │ │
|
|
90
|
+
│ lib/tools/tool/ ◄─────────┘ │
|
|
91
|
+
│ ├── cli.rb (Full CLI class - 400+ lines) │
|
|
92
|
+
│ │ ├── def run(args) (Entry point with case/when) │
|
|
93
|
+
│ │ ├── run_search (Command dispatcher) │
|
|
94
|
+
│ │ ├── run_add (Command dispatcher) │
|
|
95
|
+
│ │ └── run_remove (Command dispatcher) │
|
|
96
|
+
│ │ │
|
|
97
|
+
│ ├── search.rb (Business logic) │
|
|
98
|
+
│ ├── crud.rb (Business logic) │
|
|
99
|
+
│ └── config.rb (Configuration) │
|
|
100
|
+
│ │
|
|
101
|
+
│ spec/tools/tool/ │
|
|
102
|
+
│ ├── cli_spec.rb (Test CLI behavior!) │
|
|
103
|
+
│ ├── search_spec.rb (Business logic tests) │
|
|
104
|
+
│ └── crud_spec.rb (Business logic tests) │
|
|
105
|
+
│ │
|
|
106
|
+
│ Characteristics: │
|
|
107
|
+
│ • 10+ commands - Scales excellently │
|
|
108
|
+
│ • CLI is testable (RSpec with mocks) │
|
|
109
|
+
│ • Dependency injection (config, output, validators) │
|
|
110
|
+
│ • Exit codes (0-4 for different errors) │
|
|
111
|
+
│ • Professional-grade architecture │
|
|
112
|
+
│ │
|
|
113
|
+
│ Example: jump (10 commands, 29-line bin/, 400+ line lib/cli.rb) │
|
|
114
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
71
115
|
```
|
|
72
116
|
|
|
73
117
|
## Decision Matrix
|
|
74
118
|
|
|
75
|
-
| Criteria | Pattern 1 | Pattern 2 | Pattern 3 |
|
|
76
|
-
|
|
77
|
-
| **Number of commands** | 1 | 2-5 | 6+ |
|
|
78
|
-
| **Complexity** | Low | Medium | High |
|
|
79
|
-
| **Setup time** | Fast | Medium | Slower |
|
|
80
|
-
| **Scalability** | ❌ | ⚠️ | ✅ |
|
|
81
|
-
| **
|
|
82
|
-
| **
|
|
83
|
-
| **
|
|
84
|
-
| **
|
|
119
|
+
| Criteria | Pattern 1 | Pattern 2 | Pattern 3 | Pattern 4 |
|
|
120
|
+
|----------|-----------|-----------|-----------|-----------|
|
|
121
|
+
| **Number of commands** | 1 | 2-5 | 6-9 | 10+ |
|
|
122
|
+
| **Complexity** | Low | Medium | High | High |
|
|
123
|
+
| **Setup time** | Fast | Medium | Slower | Slower |
|
|
124
|
+
| **Scalability** | ❌ | ⚠️ | ✅ | ✅✅ |
|
|
125
|
+
| **Testable CLI** | N/A | ❌ | ❌ | ✅ |
|
|
126
|
+
| **Consistency enforcement** | N/A | ❌ | ✅ | ⚠️ |
|
|
127
|
+
| **Easy to understand** | ✅ | ✅ | ⚠️ | ⚠️ |
|
|
128
|
+
| **Shared validation** | N/A | ❌ | ✅ | ⚠️ |
|
|
129
|
+
| **Commands share logic** | N/A | ⚠️ | ✅ | ⚠️ |
|
|
130
|
+
| **Exit codes** | ⚠️ | ⚠️ | ⚠️ | ✅ |
|
|
131
|
+
| **Dependency injection** | ❌ | ❌ | ❌ | ✅ |
|
|
132
|
+
| **Professional-grade** | Simple only | Medium tools | ✅ | ✅✅ |
|
|
85
133
|
|
|
86
134
|
Legend:
|
|
87
135
|
- ✅ Excellent fit
|
|
@@ -125,17 +173,48 @@ lib/appydave/tools/youtube_manager/
|
|
|
125
173
|
Total: 6+ files (2 commands)
|
|
126
174
|
```
|
|
127
175
|
|
|
176
|
+
### Pattern 4 (jump)
|
|
177
|
+
```
|
|
178
|
+
bin/jump.rb 1 file (30 lines!)
|
|
179
|
+
lib/appydave/tools/jump/
|
|
180
|
+
├── cli.rb 1 file (400+ lines)
|
|
181
|
+
├── config.rb 1 file
|
|
182
|
+
├── search.rb 1 file
|
|
183
|
+
├── crud.rb 1 file
|
|
184
|
+
├── validators/
|
|
185
|
+
│ └── path_validator.rb 1 file
|
|
186
|
+
├── formatters/
|
|
187
|
+
│ ├── table_formatter.rb 3 files
|
|
188
|
+
│ ├── json_formatter.rb
|
|
189
|
+
│ └── paths_formatter.rb
|
|
190
|
+
└── generators/
|
|
191
|
+
└── aliases_generator.rb 1 file
|
|
192
|
+
────────────────────────────────────────────
|
|
193
|
+
Total: 10+ files (10 commands)
|
|
194
|
+
```
|
|
195
|
+
|
|
128
196
|
## Code Volume Comparison
|
|
129
197
|
|
|
130
|
-
For a tool with
|
|
198
|
+
### For a tool with 2 commands (get, update):
|
|
131
199
|
|
|
132
200
|
| Pattern | Lines of Code | Files | Boilerplate |
|
|
133
201
|
|---------|---------------|-------|-------------|
|
|
134
202
|
| Pattern 1 | N/A | N/A | Not applicable |
|
|
135
203
|
| Pattern 2 | ~150 LOC | 3 | Low |
|
|
136
204
|
| Pattern 3 | ~200 LOC | 6 | Medium |
|
|
205
|
+
| Pattern 4 | ~250 LOC | 4 | Medium |
|
|
206
|
+
|
|
207
|
+
**Recommendation:** Use Pattern 2 for 2-5 commands
|
|
137
208
|
|
|
138
|
-
|
|
209
|
+
### For a tool with 10 commands:
|
|
210
|
+
|
|
211
|
+
| Pattern | bin/ LOC | lib/ LOC | Total LOC | Files |
|
|
212
|
+
|---------|----------|----------|-----------|-------|
|
|
213
|
+
| Pattern 2 | 800-1600 | 500 | 1300-2100 | 11 |
|
|
214
|
+
| Pattern 3 | 80 | 2000+ | 2080+ | 21+ |
|
|
215
|
+
| Pattern 4 | 30 | 1500+ | 1530+ | 10+ |
|
|
216
|
+
|
|
217
|
+
**Recommendation:** Use Pattern 4 for 10+ commands (cleaner, testable)
|
|
139
218
|
|
|
140
219
|
## When to Refactor Between Patterns
|
|
141
220
|
|
|
@@ -145,13 +224,32 @@ For a tool with **2 commands** (get, update):
|
|
|
145
224
|
**Effort:** Medium - Requires restructuring bin/ file
|
|
146
225
|
|
|
147
226
|
### Pattern 2 → Pattern 3
|
|
148
|
-
**Trigger:**
|
|
149
|
-
- Command count reaches 6
|
|
227
|
+
**Trigger:**
|
|
228
|
+
- Command count reaches 6-9
|
|
150
229
|
- Commands share significant validation logic
|
|
151
230
|
- Need consistent error handling across commands
|
|
231
|
+
- Don't need CLI testing
|
|
152
232
|
|
|
153
233
|
**Effort:** Medium-High - Create BaseAction, convert methods to Action classes
|
|
154
234
|
|
|
235
|
+
### Pattern 2 → Pattern 4
|
|
236
|
+
**Trigger:**
|
|
237
|
+
- Command count reaches 10+
|
|
238
|
+
- bin/ file exceeds 500 lines
|
|
239
|
+
- Want to test CLI behavior
|
|
240
|
+
- Building professional-grade tool
|
|
241
|
+
|
|
242
|
+
**Effort:** Medium - Move CLI class to lib/, add dependency injection, create CLI tests
|
|
243
|
+
|
|
244
|
+
### Pattern 3 → Pattern 4
|
|
245
|
+
**Trigger:**
|
|
246
|
+
- Want to test CLI behavior (exit codes, output)
|
|
247
|
+
- Need dependency injection for testing
|
|
248
|
+
- Commands growing beyond 10+
|
|
249
|
+
- BaseAction pattern feels constraining
|
|
250
|
+
|
|
251
|
+
**Effort:** Medium - Convert Actions to methods in CLI class, add dependency injection
|
|
252
|
+
|
|
155
253
|
## Real-World Examples
|
|
156
254
|
|
|
157
255
|
### Pattern 1: gpt_context
|
|
@@ -196,6 +294,38 @@ For a tool with **2 commands** (get, update):
|
|
|
196
294
|
- Future commands: `delete`, `upload`, `list`, `analyze`
|
|
197
295
|
- Shared pattern: authorize → validate → execute → report
|
|
198
296
|
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### Pattern 4: jump
|
|
300
|
+
**Purpose:** Manage development folder locations
|
|
301
|
+
|
|
302
|
+
**Commands:** 10
|
|
303
|
+
- `search` - Fuzzy search locations
|
|
304
|
+
- `get` - Get by exact key
|
|
305
|
+
- `list` - List all locations
|
|
306
|
+
- `add` - Add new location
|
|
307
|
+
- `update` - Update existing location
|
|
308
|
+
- `remove` - Remove location
|
|
309
|
+
- `validate` - Validate paths exist
|
|
310
|
+
- `report` - Generate reports
|
|
311
|
+
- `generate` - Generate shell aliases
|
|
312
|
+
- `info` - Show configuration info
|
|
313
|
+
|
|
314
|
+
**Why Pattern 4?**
|
|
315
|
+
- 10 commands - Too many for Pattern 2/3
|
|
316
|
+
- Want to test CLI behavior (exit codes, output formatting)
|
|
317
|
+
- Professional development tool (needs dependency injection)
|
|
318
|
+
- Complex CLI logic (400+ lines in lib/cli.rb)
|
|
319
|
+
- Multiple output formatters (table, json, paths)
|
|
320
|
+
- Comprehensive help system
|
|
321
|
+
|
|
322
|
+
**Key benefits:**
|
|
323
|
+
- ✅ Full RSpec test coverage of CLI behavior
|
|
324
|
+
- ✅ Mock config, validators in tests
|
|
325
|
+
- ✅ Test exit codes (0 = success, 1-4 = different errors)
|
|
326
|
+
- ✅ Thin bin/ wrapper (29 lines)
|
|
327
|
+
- ✅ Professional-grade architecture
|
|
328
|
+
|
|
199
329
|
## Anti-Patterns to Avoid
|
|
200
330
|
|
|
201
331
|
### ❌ Don't: Mix patterns
|
|
@@ -271,8 +401,8 @@ When migrating an existing tool or creating a new one:
|
|
|
271
401
|
- [ ] Implement business logic in `lib/`
|
|
272
402
|
- [ ] Add `# frozen_string_literal: true`
|
|
273
403
|
- [ ] No `require` statements in `lib/` (except Ruby stdlib)
|
|
274
|
-
- [ ] No CLI code in `lib/` classes
|
|
275
|
-
- [ ] Write RSpec tests for business logic
|
|
404
|
+
- [ ] No CLI code in `lib/` classes (except Pattern 4: CLI in lib/cli.rb)
|
|
405
|
+
- [ ] Write RSpec tests for business logic (Pattern 4: also test CLI class)
|
|
276
406
|
- [ ] Register in `appydave-tools.gemspec`
|
|
277
407
|
- [ ] Document in `CLAUDE.md`
|
|
278
408
|
- [ ] Create `_doc.md` in module directory
|
|
@@ -281,4 +411,4 @@ When migrating an existing tool or creating a new one:
|
|
|
281
411
|
|
|
282
412
|
---
|
|
283
413
|
|
|
284
|
-
**Last updated:** 2025-
|
|
414
|
+
**Last updated:** 2025-02-04
|