aider-ruby 0.1.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.
data/bin/aider-ruby ADDED
@@ -0,0 +1,320 @@
1
+ #!/usr/bin/env ruby
2
+ require 'thor'
3
+ require_relative '../lib/aider_ruby'
4
+
5
+ class AiderRubyCLI < Thor
6
+ desc 'execute MESSAGE', 'Execute aider with a message'
7
+ option :model, aliases: :m, desc: 'Model to use'
8
+ option :files, aliases: :f, type: :array, desc: 'Files to edit'
9
+ option :read, aliases: :r, type: :array, desc: 'Read-only files'
10
+ option :config, aliases: :c, desc: 'Config file path'
11
+ option :env_file, desc: 'Environment file path'
12
+ option :verbose, aliases: :v, type: :boolean, desc: 'Verbose output'
13
+ option :dry_run, type: :boolean, desc: 'Dry run mode'
14
+ option :yes_always, type: :boolean, desc: 'Always say yes'
15
+ option :conventions, desc: 'Conventions file path'
16
+ option :edit_format, desc: 'Edit format (whole, diff, diff-fenced)'
17
+ option :reasoning_effort, desc: 'Reasoning effort (low, medium, high)'
18
+ option :thinking_tokens, desc: 'Thinking tokens budget'
19
+ option :use_temperature, type: :boolean, desc: 'Use temperature sampling'
20
+ option :use_system_prompt, type: :boolean, desc: 'Use system prompt'
21
+ option :use_repo_map, type: :boolean, desc: 'Use repository map'
22
+ def execute(message)
23
+ client = create_client
24
+ result = client.execute(message, cli_options)
25
+ puts result
26
+ end
27
+
28
+ desc 'interactive', 'Start aider in interactive mode'
29
+ option :model, aliases: :m, desc: 'Model to use'
30
+ option :files, aliases: :f, type: :array, desc: 'Files to edit'
31
+ option :read, aliases: :r, type: :array, desc: 'Read-only files'
32
+ option :config, aliases: :c, desc: 'Config file path'
33
+ option :env_file, desc: 'Environment file path'
34
+ option :verbose, aliases: :v, type: :boolean, desc: 'Verbose output'
35
+ def interactive
36
+ client = create_client
37
+ client.interactive(cli_options)
38
+ end
39
+
40
+ desc 'from_file MESSAGE_FILE', 'Execute aider with a message file'
41
+ option :model, aliases: :m, desc: 'Model to use'
42
+ option :files, aliases: :f, type: :array, desc: 'Files to edit'
43
+ option :read, aliases: :r, type: :array, desc: 'Read-only files'
44
+ option :config, aliases: :c, desc: 'Config file path'
45
+ option :env_file, desc: 'Environment file path'
46
+ option :verbose, aliases: :v, type: :boolean, desc: 'Verbose output'
47
+ def from_file(message_file)
48
+ client = create_client
49
+ result = client.execute_from_file(message_file, cli_options)
50
+ puts result
51
+ end
52
+
53
+ desc 'apply FILE', 'Apply changes from a file'
54
+ option :model, aliases: :m, desc: 'Model to use'
55
+ option :files, aliases: :f, type: :array, desc: 'Files to edit'
56
+ option :read, aliases: :r, type: :array, desc: 'Read-only files'
57
+ option :config, aliases: :c, desc: 'Config file path'
58
+ option :env_file, desc: 'Environment file path'
59
+ option :verbose, aliases: :v, type: :boolean, desc: 'Verbose output'
60
+ def apply(file)
61
+ client = create_client
62
+ result = client.apply_changes(file, cli_options)
63
+ puts result
64
+ end
65
+
66
+ desc 'repo_map', 'Show repository map'
67
+ option :model, aliases: :m, desc: 'Model to use'
68
+ option :config, aliases: :c, desc: 'Config file path'
69
+ option :env_file, desc: 'Environment file path'
70
+ def repo_map
71
+ client = create_client
72
+ result = client.show_repo_map(cli_options)
73
+ puts result
74
+ end
75
+
76
+ desc 'prompts', 'Show system prompts'
77
+ option :model, aliases: :m, desc: 'Model to use'
78
+ option :config, aliases: :c, desc: 'Config file path'
79
+ option :env_file, desc: 'Environment file path'
80
+ def prompts
81
+ client = create_client
82
+ result = client.show_prompts(cli_options)
83
+ puts result
84
+ end
85
+
86
+ desc 'models [PROVIDER]', 'List available models'
87
+ def models(provider = nil)
88
+ if provider
89
+ models = AiderRuby::Models.list_models(provider)
90
+ puts "Models for #{provider}:"
91
+ models.each { |model| puts " - #{model}" }
92
+ else
93
+ puts 'Available providers:'
94
+ AiderRuby::Models.list_providers.each do |prov|
95
+ puts " #{prov}:"
96
+ AiderRuby::Models.list_models(prov).each { |model| puts " - #{model}" }
97
+ end
98
+ end
99
+ end
100
+
101
+ desc 'model_info MODEL', 'Show information about a model'
102
+ def model_info(model)
103
+ info = AiderRuby::Models.model_info(model)
104
+ if info
105
+ puts "Model: #{info[:name]}"
106
+ puts "Provider: #{info[:provider]}"
107
+ puts "Reasoning: #{info[:reasoning]}"
108
+ puts "Vision: #{info[:vision]}"
109
+ puts "Context Window: #{info[:context_window]} tokens"
110
+ puts 'Cost per 1M tokens:'
111
+ puts " Input: $#{info[:cost_per_token][:input]}"
112
+ puts " Output: $#{info[:cost_per_token][:output]}"
113
+ else
114
+ puts "Model '#{model}' not found"
115
+ end
116
+ end
117
+
118
+ desc 'recommended', 'Show recommended models'
119
+ def recommended
120
+ puts 'Recommended models:'
121
+ AiderRuby::Models.recommended_models.each do |category, model|
122
+ puts " #{category.to_s.gsub('_', ' ').capitalize}: #{model}"
123
+ end
124
+ end
125
+
126
+ desc 'check_update', 'Check for aider updates'
127
+ def check_update
128
+ client = create_client
129
+ result = client.check_update
130
+ puts result
131
+ end
132
+
133
+ desc 'upgrade', 'Upgrade aider'
134
+ def upgrade
135
+ client = create_client
136
+ result = client.upgrade
137
+ puts result
138
+ end
139
+
140
+ desc 'config', 'Show current configuration'
141
+ option :config, aliases: :c, desc: 'Config file path'
142
+ option :env_file, desc: 'Environment file path'
143
+ def config
144
+ client = create_client
145
+ puts 'Current configuration:'
146
+ puts JSON.pretty_generate(client.config.to_h)
147
+ end
148
+
149
+ desc 'task TYPE DESCRIPTION', 'Execute a specific type of task'
150
+ option :model, aliases: :m, desc: 'Model to use'
151
+ option :files, aliases: :f, type: :array, desc: 'Files to edit'
152
+ option :read, aliases: :r, type: :array, desc: 'Read-only files'
153
+ option :config, aliases: :c, desc: 'Config file path'
154
+ option :env_file, desc: 'Environment file path'
155
+ option :verbose, aliases: :v, type: :boolean, desc: 'Verbose output'
156
+ def task(type, description)
157
+ client = create_client
158
+ executor = AiderRuby::TaskExecutor.new(client)
159
+
160
+ case type
161
+ when 'coding'
162
+ result = executor.execute_coding_task(description, options[:files] || [], cli_options)
163
+ when 'refactoring'
164
+ result = executor.execute_refactoring_task(description, options[:files] || [], cli_options)
165
+ when 'debugging'
166
+ result = executor.execute_debugging_task(description, options[:files] || [], cli_options)
167
+ when 'documentation'
168
+ result = executor.execute_documentation_task(description, options[:files] || [], cli_options)
169
+ when 'test_generation'
170
+ result = executor.execute_test_generation_task(description, options[:files] || [], cli_options)
171
+ else
172
+ puts "Unknown task type: #{type}"
173
+ puts 'Available types: coding, refactoring, debugging, documentation, test_generation'
174
+ exit 1
175
+ end
176
+
177
+ puts result
178
+ end
179
+
180
+ desc 'history', 'Show task history'
181
+ option :type, desc: 'Filter by task type'
182
+ option :status, desc: 'Filter by status'
183
+ option :since, desc: 'Filter by date (YYYY-MM-DD)'
184
+ def history
185
+ client = create_client
186
+ executor = AiderRuby::TaskExecutor.new(client)
187
+
188
+ filter = {}
189
+ filter[:type] = options[:type].to_sym if options[:type]
190
+ filter[:status] = options[:status].to_sym if options[:status]
191
+ filter[:since] = Date.parse(options[:since]) if options[:since]
192
+
193
+ tasks = executor.get_task_history(filter)
194
+
195
+ if tasks.empty?
196
+ puts 'No tasks found'
197
+ else
198
+ tasks.each do |task|
199
+ puts "ID: #{task[:id]}"
200
+ puts "Type: #{task[:type]}"
201
+ puts "Status: #{task[:status]}"
202
+ puts "Description: #{task[:description]}"
203
+ puts "Created: #{task[:created_at]}"
204
+ puts '---'
205
+ end
206
+ end
207
+ end
208
+
209
+ desc 'version', 'Show version information'
210
+ def version
211
+ puts "AiderRuby version: #{AiderRuby::VERSION}"
212
+ end
213
+
214
+ desc 'conventions FILE', 'Load coding conventions from a file'
215
+ option :model, aliases: :m, desc: 'Model to use'
216
+ option :files, aliases: :f, type: :array, desc: 'Files to edit'
217
+ option :read, aliases: :r, type: :array, desc: 'Read-only files'
218
+ option :config, aliases: :c, desc: 'Config file path'
219
+ option :env_file, desc: 'Environment file path'
220
+ option :verbose, aliases: :v, type: :boolean, desc: 'Verbose output'
221
+ def conventions(file)
222
+ client = create_client
223
+ client.conventions_file(file)
224
+ puts "Conventions file '#{file}' loaded successfully"
225
+ end
226
+
227
+ desc 'edit_format FORMAT', 'Set edit format (whole, diff, diff-fenced)'
228
+ option :model, aliases: :m, desc: 'Model to use'
229
+ option :files, aliases: :f, type: :array, desc: 'Files to edit'
230
+ option :read, aliases: :r, type: :array, desc: 'Read-only files'
231
+ option :config, aliases: :c, desc: 'Config file path'
232
+ option :env_file, desc: 'Environment file path'
233
+ option :verbose, aliases: :v, type: :boolean, desc: 'Verbose output'
234
+ def edit_format(format)
235
+ client = create_client
236
+
237
+ case format
238
+ when 'whole'
239
+ client.edit_format_whole(true)
240
+ when 'diff'
241
+ client.edit_format_diff(true)
242
+ when 'diff-fenced'
243
+ client.edit_format_diff_fenced(true)
244
+ else
245
+ puts "Unknown edit format: #{format}"
246
+ puts 'Available formats: whole, diff, diff-fenced'
247
+ exit 1
248
+ end
249
+
250
+ puts "Edit format set to: #{format}"
251
+ end
252
+
253
+ desc 'reasoning_settings', 'Show reasoning model settings'
254
+ def reasoning_settings
255
+ puts 'Reasoning Model Settings:'
256
+ puts ' reasoning_effort: low, medium, high'
257
+ puts ' thinking_tokens: number of tokens (e.g., 1000, 1k, 8k)'
258
+ puts ' reasoning_tag: XML tag for reasoning output (e.g., think)'
259
+ puts ''
260
+ puts 'Example usage:'
261
+ puts ' aider-ruby execute "task" --reasoning-effort high --thinking-tokens 8k'
262
+ end
263
+
264
+ private
265
+
266
+ def create_client
267
+ client_options = {}
268
+
269
+ # Load config file if specified
270
+ AiderRuby::Config::Configuration.load_from_file(options[:config]) if options[:config]
271
+
272
+ # Load env file if specified
273
+ AiderRuby::Config::Configuration.load_from_env_file(options[:env_file]) if options[:env_file]
274
+
275
+ # Set model if specified
276
+ client_options[:model] = options[:model] if options[:model]
277
+
278
+ client = AiderRuby::Client::Client.new(client_options)
279
+
280
+ # Add files
281
+ (options[:files] || []).each { |file| client.add_file(file) }
282
+ (options[:read] || []).each { |file| client.add_read_only_file(file) }
283
+
284
+ # Set conventions if specified
285
+ client.conventions_file(options[:conventions]) if options[:conventions]
286
+
287
+ # Set edit format if specified
288
+ case options[:edit_format]
289
+ when 'whole'
290
+ client.edit_format_whole(true)
291
+ when 'diff'
292
+ client.edit_format_diff(true)
293
+ when 'diff-fenced'
294
+ client.edit_format_diff_fenced(true)
295
+ end
296
+
297
+ # Set reasoning settings if specified
298
+ client.reasoning_effort(options[:reasoning_effort]) if options[:reasoning_effort]
299
+ client.thinking_tokens(options[:thinking_tokens]) if options[:thinking_tokens]
300
+
301
+ # Set advanced model settings if specified
302
+ client.use_temperature(options[:use_temperature]) if options.key?(:use_temperature)
303
+ client.use_system_prompt(options[:use_system_prompt]) if options.key?(:use_system_prompt)
304
+ client.use_repo_map(options[:use_repo_map]) if options.key?(:use_repo_map)
305
+
306
+ client
307
+ end
308
+
309
+ def cli_options
310
+ {
311
+ config_file: options[:config],
312
+ env_file: options[:env_file],
313
+ verbose: options[:verbose],
314
+ dry_run: options[:dry_run],
315
+ yes_always: options[:yes_always]
316
+ }.compact
317
+ end
318
+ end
319
+
320
+ AiderRubyCLI.start(ARGV)