gempilot 0.2.0
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 +7 -0
- data/.claude/skills/using-command-kit/SKILL.md +119 -0
- data/.claude/skills/using-command-kit/cli-example.rb +84 -0
- data/.claude/skills/using-command-kit/generator-pattern.rb +62 -0
- data/.rspec +3 -0
- data/.rubocop.yml +281 -0
- data/.ruby-version +1 -0
- data/CLAUDE.md +45 -0
- data/LICENSE.txt +21 -0
- data/README.md +140 -0
- data/Rakefile +44 -0
- data/data/templates/gem/Gemfile.erb +23 -0
- data/data/templates/gem/LICENSE.txt.erb +21 -0
- data/data/templates/gem/README.md.erb +25 -0
- data/data/templates/gem/Rakefile.erb +36 -0
- data/data/templates/gem/bin/console.erb +7 -0
- data/data/templates/gem/bin/setup.erb +5 -0
- data/data/templates/gem/dotfiles/github/workflows/ci.yml.erb +33 -0
- data/data/templates/gem/dotfiles/gitignore +11 -0
- data/data/templates/gem/dotfiles/rubocop.yml.erb +209 -0
- data/data/templates/gem/dotfiles/ruby-version.erb +1 -0
- data/data/templates/gem/exe/gem_name.erb +3 -0
- data/data/templates/gem/gemspec.erb +27 -0
- data/data/templates/gem/lib/gem_name/version.rb.erb +7 -0
- data/data/templates/gem/lib/gem_name.rb.erb +16 -0
- data/data/templates/gem/lib/gem_name_extension.rb.erb +20 -0
- data/data/templates/gem/rspec.erb +3 -0
- data/data/templates/gem/spec/gem_name_spec.rb.erb +5 -0
- data/data/templates/gem/spec/spec_helper.rb.erb +10 -0
- data/data/templates/gem/spec/zeitwerk_spec.rb.erb +5 -0
- data/data/templates/gem/test/gem_name_test.rb.erb +7 -0
- data/data/templates/gem/test/test_helper.rb.erb +7 -0
- data/data/templates/gem/test/zeitwerk_test.rb.erb +9 -0
- data/data/templates/new/.keep +0 -0
- data/data/templates/new/command.rb.erb +15 -0
- data/docs/command_kit_comparison.md +249 -0
- data/docs/command_kit_reference.md +517 -0
- data/docs/plans/2026-02-18-gempilot-add-command.md +718 -0
- data/docs/superpowers/plans/2026-04-01-rubocop-new-config.md +838 -0
- data/docs/superpowers/plans/2026-04-06-dogfood-inflectable.md +659 -0
- data/docs/superpowers/plans/2026-04-06-inflection-tests-and-erb-rename.md +166 -0
- data/docs/superpowers/plans/2026-04-06-integrate-version-tools.md +162 -0
- data/docs/superpowers/plans/2026-04-06-new-readme.md +185 -0
- data/docs/version-management-redesign.md +44 -0
- data/exe/gempilot +12 -0
- data/issues.rec +77 -0
- data/lib/core_ext/string/inflection_methods.rb +68 -0
- data/lib/core_ext/string/refinements/inflectable.rb +15 -0
- data/lib/gempilot/cli/command.rb +17 -0
- data/lib/gempilot/cli/commands/bump.rb +49 -0
- data/lib/gempilot/cli/commands/console.rb +38 -0
- data/lib/gempilot/cli/commands/create.rb +183 -0
- data/lib/gempilot/cli/commands/destroy.rb +136 -0
- data/lib/gempilot/cli/commands/new.rb +226 -0
- data/lib/gempilot/cli/commands/release.rb +40 -0
- data/lib/gempilot/cli/gem_builder.rb +105 -0
- data/lib/gempilot/cli/gem_context.rb +40 -0
- data/lib/gempilot/cli/generator.rb +90 -0
- data/lib/gempilot/cli.rb +19 -0
- data/lib/gempilot/github_release.rb +30 -0
- data/lib/gempilot/project/version.rb +39 -0
- data/lib/gempilot/project.rb +111 -0
- data/lib/gempilot/strict_shell.rb +18 -0
- data/lib/gempilot/version.rb +3 -0
- data/lib/gempilot/version_tag.rb +53 -0
- data/lib/gempilot/version_task.rb +108 -0
- data/lib/gempilot.rb +17 -0
- data/notes.md +31 -0
- metadata +165 -0
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require_relative "../command"
|
|
2
|
+
|
|
3
|
+
module <%= @gem_module %>
|
|
4
|
+
class CLI
|
|
5
|
+
module Commands
|
|
6
|
+
class <%= @command_name %> < Command
|
|
7
|
+
description "TODO: describe the <%= @command_file_name %> command"
|
|
8
|
+
|
|
9
|
+
def run
|
|
10
|
+
puts "TODO: implement <%= @command_file_name %>"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Gempilot vs Ronin: CommandKit Usage Comparison
|
|
2
|
+
|
|
3
|
+
## How Gempilot Uses CommandKit
|
|
4
|
+
|
|
5
|
+
### Current Usage (after restructuring)
|
|
6
|
+
|
|
7
|
+
| CommandKit Module | Used? | Where |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `CommandKit::Commands` | Yes | `Gempilot::CLI` - top-level command dispatcher |
|
|
10
|
+
| `CommandKit::Commands::AutoLoad` | Yes | `Gempilot::CLI` - auto-discovers commands from `cli/commands/` |
|
|
11
|
+
| `CommandKit::Options::Version` | Yes | `Gempilot::CLI` - `--version` flag |
|
|
12
|
+
| `CommandKit::Command` | Yes | `Gempilot::CLI::Command` - base class for all commands |
|
|
13
|
+
| `CommandKit::Colors` | Yes | `Gempilot::CLI::Command` and `Gempilot::CLI::Generator` |
|
|
14
|
+
| `CommandKit::FileUtils` | Yes | `Gempilot::CLI::Generator` - `erb()` method |
|
|
15
|
+
| `CommandKit::Options` | Yes | `Commands::New` - all option definitions (implicit via Command) |
|
|
16
|
+
| `CommandKit::Arguments` | Yes | `Commands::New` - `gem_name` argument (implicit via Command) |
|
|
17
|
+
| `CommandKit::Inflector` | **No** | Hand-rolled `inflect_module` in `Commands::New` instead |
|
|
18
|
+
| `CommandKit::Interactive` | **No** | Not included in base Command |
|
|
19
|
+
| `CommandKit::Description` | Yes | `Commands::New` - `description "Create a new gem"` |
|
|
20
|
+
| `CommandKit::Usage` | Yes | `Commands::New` - `usage "[options] GEM_NAME"` |
|
|
21
|
+
| `CommandKit::Printing` | Yes | Implicit via Command |
|
|
22
|
+
| `CommandKit::Printing::Indent` | **No** | |
|
|
23
|
+
| `CommandKit::Printing::Fields` | **No** | |
|
|
24
|
+
| `CommandKit::Printing::Lists` | **No** | |
|
|
25
|
+
| `CommandKit::Printing::Tables` | **No** | |
|
|
26
|
+
| `CommandKit::Terminal` | **No** | |
|
|
27
|
+
| `CommandKit::Pager` | **No** | |
|
|
28
|
+
| `CommandKit::OS` | **No** | |
|
|
29
|
+
| `CommandKit::XDG` | **No** | |
|
|
30
|
+
| `CommandKit::BugReport` | **No** | |
|
|
31
|
+
| `CommandKit::Help::Man` | **No** | |
|
|
32
|
+
| `CommandKit::Edit` | **No** | |
|
|
33
|
+
| `CommandKit::Examples` | **No** | No examples defined on any command |
|
|
34
|
+
| `CommandKit::ExceptionHandler` | Yes | Implicit via Command |
|
|
35
|
+
|
|
36
|
+
### What Gempilot Hand-Rolls Instead of Using CommandKit
|
|
37
|
+
|
|
38
|
+
1. **Inflector** - `Commands::New#inflect_module` (line 113-115) does:
|
|
39
|
+
```ruby
|
|
40
|
+
def inflect_module(name)
|
|
41
|
+
name.split(/[-_]/).map(&:capitalize).join
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
Should use `CommandKit::Inflector.camelize(name)` which handles the same transformation plus edge cases (e.g., `/` to `::` for nested modules).
|
|
45
|
+
|
|
46
|
+
2. **Generator module** - `Gempilot::CLI::Generator` reimplements ronin-core's Generator pattern. This is intentional (own implementation, no ronin-core dependency), but it duplicates logic that `CommandKit::FileUtils` already partly provides (`erb` method). The Generator adds `print_action`, `mkdir`, `cp`, `sh`, `touch`, `chmod` wrappers with colored output.
|
|
47
|
+
|
|
48
|
+
3. **Shell execution** - `Gempilot::Commands#sh` uses a custom `Runner` class with PTY/Open3 pipeline for command execution. The Generator module has its own simpler `sh` that calls `system()`. Two different shell execution paths exist.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## How Ronin Uses CommandKit (Reference Implementation)
|
|
53
|
+
|
|
54
|
+
### Module Usage
|
|
55
|
+
|
|
56
|
+
| CommandKit Module | Used? | Where |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `CommandKit::Commands` | Yes | `Ronin::CLI` |
|
|
59
|
+
| `CommandKit::Commands::AutoLoad` | Yes | `Ronin::CLI`, `Commands::New`, and many others |
|
|
60
|
+
| `CommandKit::Options::Version` | Yes | `Ronin::CLI` |
|
|
61
|
+
| `CommandKit::Command` | Yes (via ronin-core) | `Core::CLI::Command` base class |
|
|
62
|
+
| `CommandKit::Colors` | Yes | `Core::CLI::Generator`, syntax highlighting |
|
|
63
|
+
| `CommandKit::FileUtils` | Yes | `Core::CLI::Generator` |
|
|
64
|
+
| `CommandKit::Options` | Yes | Every command |
|
|
65
|
+
| `CommandKit::Arguments` | Yes | Every command |
|
|
66
|
+
| `CommandKit::Interactive` | **No** | Not used in ronin itself |
|
|
67
|
+
| `CommandKit::Description` | Yes | Every command |
|
|
68
|
+
| `CommandKit::Usage` | Yes | Every command |
|
|
69
|
+
| `CommandKit::Examples` | Yes | Most commands have examples |
|
|
70
|
+
| `CommandKit::Printing` | Yes | Implicit via Command |
|
|
71
|
+
| `CommandKit::Printing::Indent` | Yes | Output formatting |
|
|
72
|
+
| `CommandKit::Printing::Tables` | Yes | Database query output |
|
|
73
|
+
| `CommandKit::Terminal` | Yes | Width-aware output |
|
|
74
|
+
| `CommandKit::Pager` | Yes | Long output paging |
|
|
75
|
+
| `CommandKit::OS` | Yes | OS-specific behavior |
|
|
76
|
+
| `CommandKit::BugReport` | Yes | `Core::CLI::Command` base class |
|
|
77
|
+
| `CommandKit::Help::Man` | Yes | Every command has `man_page` |
|
|
78
|
+
| `CommandKit::Inflector` | Yes | Used internally for command name derivation |
|
|
79
|
+
|
|
80
|
+
### Ronin Patterns Worth Adopting
|
|
81
|
+
|
|
82
|
+
1. **Every command has `examples`** - Ronin defines usage examples on almost every command:
|
|
83
|
+
```ruby
|
|
84
|
+
examples [
|
|
85
|
+
'project foo',
|
|
86
|
+
'script foo.rb'
|
|
87
|
+
]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
2. **`bug_report_url` on base command** - Set once, inherited everywhere:
|
|
91
|
+
```ruby
|
|
92
|
+
class Command < Core::CLI::Command
|
|
93
|
+
bug_report_url 'https://github.com/ronin-rb/ronin/issues/new'
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
3. **Man pages** - Every command declares `man_page 'ronin-command.1'` for full documentation.
|
|
98
|
+
|
|
99
|
+
4. **Nested AutoLoad** - The `new` command is itself a Commands container with AutoLoad:
|
|
100
|
+
```ruby
|
|
101
|
+
class New < Command
|
|
102
|
+
include CommandKit::Commands::AutoLoad.new(
|
|
103
|
+
dir: "#{__dir__}/new",
|
|
104
|
+
namespace: "#{self}"
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
This allows `ronin new project`, `ronin new script`, etc. Each subcommand is a separate file in `commands/new/`.
|
|
109
|
+
|
|
110
|
+
5. **Core::CLI::Generator** builds on CommandKit::FileUtils - It adds `template_dir`, `print_action`, and wrappers for `mkdir`, `cp`, `erb`, `chmod`, `sh`. Gempilot's Generator follows this pattern.
|
|
111
|
+
|
|
112
|
+
6. **Consistent use of Inflector** - Ronin never hand-rolls string case conversion.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Side-by-Side: CLI Entry Points
|
|
117
|
+
|
|
118
|
+
### Gempilot
|
|
119
|
+
```ruby
|
|
120
|
+
# lib/gempilot/cli.rb
|
|
121
|
+
class Gempilot::CLI
|
|
122
|
+
include CommandKit::Commands
|
|
123
|
+
include CommandKit::Commands::AutoLoad.new(
|
|
124
|
+
dir: "#{__dir__}/cli/commands",
|
|
125
|
+
namespace: "#{self}::Commands"
|
|
126
|
+
)
|
|
127
|
+
include CommandKit::Options::Version
|
|
128
|
+
|
|
129
|
+
command_name "gempilot"
|
|
130
|
+
version Gempilot::VERSION
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Ronin
|
|
135
|
+
```ruby
|
|
136
|
+
# lib/ronin/cli.rb
|
|
137
|
+
class Ronin::CLI
|
|
138
|
+
include CommandKit::Commands
|
|
139
|
+
include CommandKit::Commands::AutoLoad.new(
|
|
140
|
+
dir: "#{__dir__}/cli/commands",
|
|
141
|
+
namespace: "#{self}::Commands"
|
|
142
|
+
)
|
|
143
|
+
include CommandKit::Options::Version
|
|
144
|
+
include Core::CLI::Help::Banner
|
|
145
|
+
|
|
146
|
+
command_name 'ronin'
|
|
147
|
+
version Ronin::VERSION
|
|
148
|
+
|
|
149
|
+
command_aliases['enc'] = 'encode'
|
|
150
|
+
command_aliases['dec'] = 'decode'
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Verdict:** Nearly identical. Gempilot follows the pattern correctly. Ronin adds `command_aliases` and a help banner, both nice touches.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Side-by-Side: Generator Commands
|
|
159
|
+
|
|
160
|
+
### Gempilot - `Commands::New`
|
|
161
|
+
```ruby
|
|
162
|
+
class New < Command
|
|
163
|
+
include Generator
|
|
164
|
+
|
|
165
|
+
template_dir File.join(Gempilot::ROOT, "data", "templates", "gem")
|
|
166
|
+
|
|
167
|
+
option :summary, value: { type: String }, desc: "Gem summary"
|
|
168
|
+
option :test, value: { type: { "minitest" => :minitest, "rspec" => :rspec }, default: :minitest }, desc: "Test framework"
|
|
169
|
+
argument :gem_name, required: true, desc: "Name of the gem"
|
|
170
|
+
|
|
171
|
+
def run(gem_name)
|
|
172
|
+
@gem_name = gem_name
|
|
173
|
+
@module_name = inflect_module(gem_name)
|
|
174
|
+
mkdir gem_name
|
|
175
|
+
erb "gemspec.erb", "#{gem_name}/#{gem_name}.gemspec"
|
|
176
|
+
# ...
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Ronin - `Commands::New::Project`
|
|
182
|
+
```ruby
|
|
183
|
+
class Project < Command
|
|
184
|
+
include Core::CLI::Generator
|
|
185
|
+
|
|
186
|
+
template_dir File.join(ROOT, 'data', 'templates', 'project')
|
|
187
|
+
|
|
188
|
+
option :git, desc: 'Initializes a git repo'
|
|
189
|
+
option :ruby_version, value: { type: String, usage: 'VERSION', default: RUBY_VERSION }, desc: '...'
|
|
190
|
+
argument :path, required: true, desc: 'The directory to create'
|
|
191
|
+
|
|
192
|
+
description 'Creates a new Ruby project directory'
|
|
193
|
+
man_page 'ronin-new-project.1'
|
|
194
|
+
|
|
195
|
+
def run(path)
|
|
196
|
+
@project_name = File.basename(path)
|
|
197
|
+
@ruby_version = options[:ruby_version]
|
|
198
|
+
mkdir path
|
|
199
|
+
erb 'Gemfile.erb', File.join(path, 'Gemfile')
|
|
200
|
+
# ...
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Verdict:** Same pattern. Gempilot's version is correct. Ronin adds `man_page` declaration and uses `usage:` on option values for better help output.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Grading: Gempilot's Idiomatic Use of CommandKit
|
|
210
|
+
|
|
211
|
+
### Grade: **B+**
|
|
212
|
+
|
|
213
|
+
Gempilot's restructured codebase follows the command_kit patterns well. The CLI entry, base command, AutoLoad, option/argument definitions, and Generator module all match the Ronin reference closely.
|
|
214
|
+
|
|
215
|
+
### What Earns the Grade
|
|
216
|
+
|
|
217
|
+
**Done right:**
|
|
218
|
+
- CLI with `Commands` + `AutoLoad` - textbook implementation
|
|
219
|
+
- Base `Command` class with `Colors` - follows the pattern
|
|
220
|
+
- Generator module following ronin-core's design
|
|
221
|
+
- Option definitions with `value:` Hash, proper types
|
|
222
|
+
- Argument definitions with `required: true`
|
|
223
|
+
- `template_dir` class method pattern
|
|
224
|
+
- `description` and `usage` on commands
|
|
225
|
+
- ERB templates with instance variable binding
|
|
226
|
+
- Executable entry point: thin `CLI.start`
|
|
227
|
+
|
|
228
|
+
**Holding it back from A:**
|
|
229
|
+
|
|
230
|
+
1. **`CommandKit::Inflector` not used** - Hand-rolled `inflect_module` instead of `Inflector.camelize`. This is specifically called out in CLAUDE.md issue #2.
|
|
231
|
+
|
|
232
|
+
2. **No `CommandKit::Interactive`** - CLAUDE.md issue #1 asks for interactive prompting when arguments are missing. `CommandKit::Interactive` provides `ask`, `ask_yes_or_no`, `ask_multiple_choice` - exactly what's needed.
|
|
233
|
+
|
|
234
|
+
3. **No `examples` on any command** - Ronin defines examples on every command. Gempilot defines none. Easy win for help output.
|
|
235
|
+
|
|
236
|
+
4. **No `bug_report_url`** - Low effort, high value for user experience.
|
|
237
|
+
|
|
238
|
+
5. **Two shell execution paths** - `Generator#sh` (uses `system`) and `Commands#sh` / `Runner` (uses Open3 pipeline with PTY). Should converge.
|
|
239
|
+
|
|
240
|
+
6. **`CommandMapper` integration unclear** - `CommandMappers::Bundle` is a 1091-line DSL that's not wired into any command yet. The `Commands::New#run` calls `sh 'bundle', 'install'` directly instead of using the typed DSL.
|
|
241
|
+
|
|
242
|
+
### What Would Make It an A
|
|
243
|
+
|
|
244
|
+
1. Replace `inflect_module` with `CommandKit::Inflector.camelize`
|
|
245
|
+
2. Include `CommandKit::Interactive` in base Command, use it for missing-argument prompting
|
|
246
|
+
3. Add `examples` to `Commands::New`
|
|
247
|
+
4. Add `bug_report_url` to base Command
|
|
248
|
+
5. Wire `CommandMappers::Bundle` into the `new` command for `bundle install` / `bundle config` operations
|
|
249
|
+
6. Add `CommandKit::Printing::Indent` for structured output during generation
|