code_healer 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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +70 -0
  3. data/GEM_SUMMARY.md +307 -0
  4. data/README.md +281 -0
  5. data/code_healer.gemspec +77 -0
  6. data/config/code_healer.yml.example +104 -0
  7. data/docs/INSTALLATION.md +439 -0
  8. data/examples/basic_usage.rb +160 -0
  9. data/exe/code_healer-setup +7 -0
  10. data/lib/code_healer/application_job.rb +7 -0
  11. data/lib/code_healer/business_context_analyzer.rb +464 -0
  12. data/lib/code_healer/business_context_loader.rb +273 -0
  13. data/lib/code_healer/business_context_manager.rb +297 -0
  14. data/lib/code_healer/business_logic_generator.rb +94 -0
  15. data/lib/code_healer/business_rule_applier.rb +54 -0
  16. data/lib/code_healer/claude_code_evolution_handler.rb +224 -0
  17. data/lib/code_healer/claude_error_monitor.rb +48 -0
  18. data/lib/code_healer/config_manager.rb +275 -0
  19. data/lib/code_healer/context_aware_prompt_builder.rb +153 -0
  20. data/lib/code_healer/core.rb +513 -0
  21. data/lib/code_healer/error_handler.rb +141 -0
  22. data/lib/code_healer/evolution_job.rb +99 -0
  23. data/lib/code_healer/global_handler.rb +130 -0
  24. data/lib/code_healer/healing_job.rb +167 -0
  25. data/lib/code_healer/mcp.rb +108 -0
  26. data/lib/code_healer/mcp_prompts.rb +111 -0
  27. data/lib/code_healer/mcp_server.rb +389 -0
  28. data/lib/code_healer/mcp_tools.rb +2364 -0
  29. data/lib/code_healer/pull_request_creator.rb +143 -0
  30. data/lib/code_healer/setup.rb +390 -0
  31. data/lib/code_healer/simple_evolution.rb +737 -0
  32. data/lib/code_healer/simple_global_handler.rb +122 -0
  33. data/lib/code_healer/simple_healer.rb +515 -0
  34. data/lib/code_healer/terminal_integration.rb +87 -0
  35. data/lib/code_healer/usage_analyzer.rb +92 -0
  36. data/lib/code_healer/version.rb +5 -0
  37. data/lib/code_healer.rb +67 -0
  38. metadata +411 -0
@@ -0,0 +1,143 @@
1
+ require 'octokit'
2
+
3
+ module CodeHealer
4
+ class PullRequestCreator
5
+ class << self
6
+ def create_pull_request(branch_name, class_name, method_name, error, fix_description, file_path)
7
+ puts "🔍 PR Creation Debug:"
8
+ puts " - Auto create PR: #{ConfigManager.auto_create_pr?}"
9
+ puts " - PR enabled: #{ConfigManager.pull_request_settings['enabled']}"
10
+
11
+ return false unless ConfigManager.auto_create_pr?
12
+ return false unless ConfigManager.pull_request_settings['enabled']
13
+
14
+ begin
15
+ client = create_github_client
16
+ if client.nil?
17
+ puts "❌ Failed to create GitHub client - GitHub token not configured"
18
+ puts "💡 To enable PR creation, set GITHUB_TOKEN in your .env file"
19
+ puts " Run: ./setup_github_token.sh"
20
+ return false
21
+ end
22
+
23
+ title = generate_title(class_name, method_name, error)
24
+ body = generate_body(class_name, method_name, error, fix_description, file_path)
25
+ labels = ConfigManager.pull_request_settings['labels'] || []
26
+
27
+ puts "Creating pull request for branch: #{branch_name}"
28
+
29
+ # Get target branch from configuration
30
+ target_branch = ConfigManager.pr_target_branch || 'main'
31
+ puts "📋 Target branch for PR: #{target_branch}"
32
+
33
+ pr = client.create_pull_request(
34
+ repository_name,
35
+ target_branch,
36
+ branch_name,
37
+ title,
38
+ body,
39
+ labels: labels
40
+ )
41
+
42
+ puts "✅ Pull request created successfully!"
43
+ puts "🔗 PR URL: #{pr.html_url}"
44
+
45
+ # Store PR info for tracking
46
+ store_pr_info(pr.number, branch_name, class_name, method_name, error)
47
+
48
+ return pr.html_url
49
+ rescue => e
50
+ puts "❌ Failed to create pull request: #{e.message}"
51
+ Rails.logger.error "Pull request creation failed: #{e.message}"
52
+ return false
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def create_github_client
59
+ # Try environment variable first
60
+ token = ENV['GITHUB_TOKEN']
61
+
62
+ # Fallback to Rails credentials
63
+ if token.nil? && defined?(Rails.application.credentials)
64
+ token = Rails.application.credentials.dig(:github, :token)
65
+ end
66
+
67
+ return nil unless token
68
+
69
+ Octokit::Client.new(access_token: token)
70
+ rescue => e
71
+ puts "❌ Failed to create GitHub client: #{e.message}"
72
+ nil
73
+ end
74
+
75
+ def repository_name
76
+ # Extract from git remote
77
+ remote_url = `git config --get remote.origin.url`.strip
78
+ if remote_url =~ /github\.com[:\/]([^\/]+\/[^\/]+?)(?:\.git)?$/
79
+ $1
80
+ else
81
+ 'deepan-g2/patchbot' # fallback
82
+ end
83
+ end
84
+
85
+ def generate_title(class_name, method_name, error)
86
+ template = ConfigManager.pull_request_settings['title_template'] ||
87
+ 'Fix \{class_name\}##\{method_name\}: Handle \{error_type\}'
88
+
89
+ template.gsub('\{class_name\}', class_name.to_s)
90
+ .gsub('\{method_name\}', method_name.to_s)
91
+ .gsub('\{error_type\}', error.class.name.to_s)
92
+ end
93
+
94
+ def generate_body(class_name, method_name, error, fix_description, file_path)
95
+ template = ConfigManager.pull_request_settings['body_template'] || default_body_template
96
+
97
+ template.gsub('{class_name}', class_name.to_s)
98
+ .gsub('{method_name}', method_name.to_s)
99
+ .gsub('{error_type}', error.class.name.to_s)
100
+ .gsub('{error_message}', error.message.to_s)
101
+ .gsub('{file_path}', file_path.to_s)
102
+ .gsub('{fix_description}', fix_description.to_s)
103
+ end
104
+
105
+ def default_body_template
106
+ # Simple string with placeholders - no interpolation
107
+ '## Auto-generated fix for {error_type}
108
+
109
+ **Error:** {error_message}
110
+ **Method:** {class_name}##{method_name}
111
+ **File:** {file_path}
112
+
113
+ ### Changes Made:
114
+ {fix_description}
115
+
116
+ ### Testing:
117
+ - [x] Error case handled gracefully
118
+ - [x] Normal functionality preserved
119
+ - [x] Tests generated automatically
120
+
121
+ Generated by Self-Evolving Ruby System 🤖'
122
+ end
123
+
124
+ def store_pr_info(pr_number, branch_name, class_name, method_name, error)
125
+ # Store PR information for tracking
126
+ pr_info = {
127
+ pr_number: pr_number,
128
+ branch_name: branch_name,
129
+ class_name: class_name,
130
+ method_name: method_name,
131
+ error_type: error.class.name,
132
+ created_at: Time.current,
133
+ status: 'open'
134
+ }
135
+
136
+ # Could store in database or cache
137
+ Rails.cache.write("pr_#{pr_number}", pr_info, expires_in: 30.days)
138
+
139
+ puts "📊 PR ##{pr_number} stored for tracking"
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,390 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # CodeHealer Interactive Setup Script
5
+ # This script helps users configure CodeHealer in their Rails applications
6
+
7
+ require 'fileutils'
8
+ require 'yaml'
9
+ require 'optparse'
10
+
11
+ # Parse command line options
12
+ options = {}
13
+ OptionParser.new do |opts|
14
+ opts.banner = "Usage: code_healer-setup [options]"
15
+
16
+ opts.on("-h", "--help", "Show this help message") do
17
+ puts opts
18
+ puts
19
+ puts "🏥 CodeHealer Setup Script"
20
+ puts "This script helps you configure CodeHealer for your Rails application."
21
+ puts
22
+ puts "Examples:"
23
+ puts " code_healer-setup # Interactive setup"
24
+ puts " code_healer-setup --help # Show this help"
25
+ puts " code_healer-setup --dry-run # Show what would be created"
26
+ puts
27
+ exit 0
28
+ end
29
+
30
+ opts.on("--dry-run", "Show what would be created without making changes") do
31
+ options[:dry_run] = true
32
+ end
33
+
34
+ opts.on("--version", "Show version information") do
35
+ puts "CodeHealer Setup Script v1.0.0"
36
+ exit 0
37
+ end
38
+ end.parse!
39
+
40
+ # Helper methods for user interaction
41
+ def ask_for_input(prompt, default: nil)
42
+ print "#{prompt} "
43
+ input = gets.chomp.strip
44
+
45
+ if input.empty? && default
46
+ puts "Using default: #{default}"
47
+ return default
48
+ end
49
+
50
+ input
51
+ end
52
+
53
+ def ask_for_yes_no(prompt, default: true)
54
+ print "#{prompt} (#{default ? 'Y/n' : 'y/N'}) "
55
+ input = gets.chomp.strip.downcase
56
+
57
+ case input
58
+ when 'y', 'yes'
59
+ true
60
+ when 'n', 'no'
61
+ false
62
+ when ''
63
+ default
64
+ else
65
+ puts "Please enter 'y' or 'n'"
66
+ ask_for_yes_no(prompt, default)
67
+ end
68
+ end
69
+
70
+ def create_file_with_content(file_path, content, dry_run: false)
71
+ if dry_run
72
+ puts "📝 Would create #{file_path}"
73
+ puts " Content preview:"
74
+ puts " " + content.lines.first.strip + "..."
75
+ return
76
+ end
77
+
78
+ FileUtils.mkdir_p(File.dirname(file_path))
79
+ File.write(file_path, content)
80
+ puts "✅ Created #{file_path}"
81
+ end
82
+
83
+ def file_exists?(file_path)
84
+ File.exist?(file_path)
85
+ end
86
+
87
+ def read_file_content(file_path)
88
+ File.read(file_path) if file_exists?(file_path)
89
+ end
90
+
91
+ # Main setup logic
92
+ puts "🏥 Welcome to CodeHealer Setup! 🚀"
93
+ puts "=" * 50
94
+ puts "This will help you configure CodeHealer for your Rails application."
95
+ puts
96
+
97
+ # Check if we're in a Rails app
98
+ unless file_exists?('Gemfile') && file_exists?('config/application.rb')
99
+ puts "❌ Error: This doesn't appear to be a Rails application."
100
+ puts "Please run this script from your Rails application root directory."
101
+ exit 1
102
+ end
103
+
104
+ puts "✅ Rails application detected!"
105
+ puts
106
+
107
+ # Step 1: Add to Gemfile
108
+ puts "📦 Step 1: Adding CodeHealer to Gemfile..."
109
+ gemfile_path = 'Gemfile'
110
+ gemfile_content = read_file_content(gemfile_path)
111
+
112
+ if gemfile_content.include?("gem 'code_healer'")
113
+ puts "✅ CodeHealer already in Gemfile"
114
+ else
115
+ # Add the gem to the Gemfile
116
+ new_gemfile_content = gemfile_content + "\n# CodeHealer - AI-powered code healing\ngem 'code_healer'\n"
117
+
118
+ if options[:dry_run]
119
+ puts "📝 Would add 'code_healer' to Gemfile"
120
+ else
121
+ File.write(gemfile_path, new_gemfile_content)
122
+ puts "✅ Added 'code_healer' to Gemfile"
123
+ end
124
+ end
125
+
126
+ puts
127
+
128
+ # Step 2: Configuration Setup
129
+ puts "🔧 Step 2: Configuration Setup"
130
+ puts
131
+
132
+ # OpenAI Configuration
133
+ puts "🤖 OpenAI Configuration:"
134
+ puts "You'll need an OpenAI API key for AI-powered code healing."
135
+ puts "Get one at: https://platform.openai.com/api-keys"
136
+ puts
137
+
138
+ openai_key = ask_for_input("Enter your OpenAI API key (or press Enter to skip for now):")
139
+
140
+ # GitHub Configuration
141
+ puts
142
+ puts "🐙 GitHub Configuration:"
143
+ puts "You'll need a GitHub personal access token for Git operations."
144
+ puts "Get one at: https://github.com/settings/tokens"
145
+ puts
146
+
147
+ github_token = ask_for_input("Enter your GitHub personal access token (or press Enter to skip for now):")
148
+ github_repo = ask_for_input("Enter your GitHub repository (username/repo):")
149
+
150
+ # Git Branch Configuration
151
+ puts
152
+ puts "🌿 Git Branch Configuration:"
153
+ branch_prefix = ask_for_input("Enter branch prefix for healing branches (default: evolve):", default: "evolve")
154
+ pr_target_branch = ask_for_input("Enter target branch for pull requests (default: main):", default: "main")
155
+
156
+ # Business Context
157
+ puts
158
+ puts "💼 Business Context Setup:"
159
+ create_business_context = ask_for_yes_no("Would you like to create a business context file?", default: true)
160
+
161
+ # Evolution Strategy Configuration
162
+ puts
163
+ puts "🧠 Evolution Strategy Configuration:"
164
+ puts "Choose how CodeHealer should fix your code:"
165
+ puts "1. API - Use OpenAI API (recommended for most users)"
166
+ puts "2. Claude Code Terminal - Use local Claude installation"
167
+ puts "3. Hybrid - Try Claude first, fallback to API"
168
+ puts
169
+
170
+ evolution_method = ask_for_input("Enter evolution method (1/2/3 or api/claude/hybrid):", default: "api")
171
+ evolution_method = case evolution_method.downcase
172
+ when "1", "api"
173
+ "api"
174
+ when "2", "claude"
175
+ "claude_code_terminal"
176
+ when "3", "hybrid"
177
+ "hybrid"
178
+ else
179
+ "api"
180
+ end
181
+
182
+ fallback_to_api = ask_for_yes_no("Fallback to API if Claude Code fails?", default: true)
183
+
184
+ # Create configuration files
185
+ puts
186
+ puts "📝 Step 3: Creating Configuration Files"
187
+ puts
188
+
189
+ # Create actual .env file (will be ignored by git)
190
+ env_content = <<~ENV
191
+ # CodeHealer Configuration
192
+ # OpenAI Configuration
193
+ OPENAI_API_KEY=#{openai_key}
194
+
195
+ # GitHub Configuration
196
+ GITHUB_TOKEN=#{github_token}
197
+ GITHUB_REPOSITORY=#{github_repo}
198
+
199
+ # Optional: Redis Configuration
200
+ REDIS_URL=redis://localhost:6379/0
201
+ ENV
202
+
203
+ create_file_with_content('.env', env_content, dry_run: options[:dry_run])
204
+
205
+ # Create code_healer.yml
206
+ config_content = <<~YAML
207
+ # CodeHealer Configuration
208
+ enabled: true
209
+
210
+ # Allowed classes for healing (customize as needed)
211
+ allowed_classes:
212
+ - User
213
+ - Order
214
+ - PaymentProcessor
215
+ - OrderProcessor
216
+
217
+ # Excluded classes (never touch these)
218
+ excluded_classes:
219
+ - ApplicationController
220
+ - ApplicationRecord
221
+ - ApplicationJob
222
+ - ApplicationMailer
223
+ - ApplicationHelper
224
+
225
+ # Allowed error types for healing
226
+ allowed_error_types:
227
+ - ZeroDivisionError
228
+ - NoMethodError
229
+ - ArgumentError
230
+ - TypeError
231
+ - NameError
232
+ - ValidationError
233
+
234
+ # Evolution Strategy Configuration
235
+ evolution_strategy:
236
+ method: #{evolution_method} # Options: api, claude_code_terminal, hybrid
237
+ fallback_to_api: #{fallback_to_api} # If Claude Code fails, fall back to API
238
+
239
+ # Claude Code Terminal Configuration
240
+ claude_code:
241
+ enabled: #{evolution_method == 'claude_code_terminal' || evolution_method == 'hybrid'}
242
+ timeout: 300 # Timeout in seconds
243
+ max_file_changes: 10
244
+ include_tests: true
245
+ command_template: "claude --print '{prompt}' --output-format text --permission-mode acceptEdits --allowedTools Edit"
246
+ business_context_sources:
247
+ - "config/business_rules.yml"
248
+ - "docs/business_logic.md"
249
+ - "spec/business_context_specs.rb"
250
+
251
+ # Business Context Configuration
252
+ business_context:
253
+ enabled: true
254
+ sources:
255
+ - "docs/business_rules.md"
256
+
257
+ # OpenAI API configuration
258
+ api:
259
+ provider: openai
260
+ model: gpt-4
261
+ max_tokens: 2000
262
+ temperature: 0.1
263
+
264
+ # Git operations
265
+ git:
266
+ auto_commit: true
267
+ auto_push: true
268
+ branch_prefix: "#{branch_prefix}"
269
+ commit_message_template: 'Fix {{class_name}}\#\#{{method_name}}: {{error_type}}'
270
+ pr_target_branch: "#{pr_target_branch}"
271
+
272
+ # Pull Request Configuration
273
+ pull_request:
274
+ enabled: true
275
+ auto_create: true
276
+ labels:
277
+ - "auto-fix"
278
+ - "self-evolving"
279
+ - "bug-fix"
280
+
281
+ # Safety Configuration
282
+ safety:
283
+ backup_before_evolution: true
284
+ rollback_on_syntax_error: true
285
+
286
+ # Evolution Limits
287
+ max_evolutions_per_day: 10
288
+
289
+ # Notification Configuration (optional)
290
+ notifications:
291
+ enabled: false
292
+ slack_webhook: ""
293
+ email_notifications: false
294
+
295
+ # Performance Configuration
296
+ performance:
297
+ max_concurrent_healing: 3
298
+ healing_timeout: 300
299
+ retry_attempts: 3
300
+ YAML
301
+
302
+ create_file_with_content('config/code_healer.yml', config_content, dry_run: options[:dry_run])
303
+
304
+ # Create business context file if requested
305
+ if create_business_context
306
+ business_context_content = <<~MARKDOWN
307
+ # Business Rules and Context
308
+
309
+ ## Error Handling
310
+ - All errors should be logged for audit purposes
311
+ - User-facing errors should be user-friendly
312
+ - Critical errors should trigger alerts
313
+
314
+ ## Data Validation
315
+ - All user inputs must be validated
316
+ - Business rules must be enforced
317
+ - Invalid data should be rejected with clear messages
318
+
319
+ ## Security
320
+ - Authentication required for sensitive operations
321
+ - Input sanitization mandatory
322
+ - Rate limiting for API endpoints
323
+
324
+ ## Business Logic
325
+ - Follow domain-specific business rules
326
+ - Maintain data consistency
327
+ - Log all business-critical operations
328
+ MARKDOWN
329
+
330
+ create_file_with_content('docs/business_rules.md', business_context_content, dry_run: options[:dry_run])
331
+ end
332
+
333
+ # Create Sidekiq configuration
334
+ puts
335
+ puts "⚡ Step 4: Sidekiq Configuration"
336
+ puts
337
+
338
+ sidekiq_config_content = <<~YAML
339
+ :concurrency: 5
340
+ :queues:
341
+ - [healing, 2]
342
+ - [default, 1]
343
+
344
+ :redis:
345
+ :url: <%= ENV['REDIS_URL'] || 'redis://localhost:6379/0' %>
346
+
347
+ :logfile: log/sidekiq.log
348
+ :pidfile: tmp/pids/sidekiq.pid
349
+ YAML
350
+
351
+ create_file_with_content('config/sidekiq.yml', sidekiq_config_content, dry_run: options[:dry_run])
352
+
353
+ # Final instructions
354
+ puts
355
+ if options[:dry_run]
356
+ puts "🔍 Dry Run Complete! 🔍"
357
+ puts "=" * 50
358
+ puts "This is what would be created. Run without --dry-run to actually create the files."
359
+ else
360
+ puts "🎉 Setup Complete! 🎉"
361
+ puts "=" * 50
362
+ puts "Next steps:"
363
+ puts "1. Install dependencies: bundle install"
364
+ puts "2. Start Redis: redis-server"
365
+ puts "3. Start Sidekiq: bundle exec sidekiq"
366
+ puts "4. Start your Rails server: rails s"
367
+ puts
368
+ puts "🔒 Security Notes:"
369
+ puts " - .env file contains your actual API keys and is ignored by git"
370
+ puts " - .env.example is safe to commit and shows the required format"
371
+ puts " - Never commit .env files with real secrets to version control"
372
+ puts
373
+ puts "⚙️ Configuration:"
374
+ puts " - code_healer.yml contains comprehensive settings with sensible defaults"
375
+ puts " - Customize the configuration file as needed for your project"
376
+ puts " - All features are pre-configured and ready to use"
377
+ puts
378
+ puts "🌍 Environment Variables:"
379
+ puts " - Add 'gem \"dotenv-rails\"' to your Gemfile for automatic .env loading"
380
+ puts " - Or export variables manually: export GITHUB_TOKEN=your_token"
381
+ puts " - Or load .env file in your application.rb: load '.env' if File.exist?('.env')"
382
+ puts
383
+ puts "CodeHealer will now automatically detect and heal errors in your application!"
384
+ end
385
+
386
+ puts
387
+ puts "📚 For more information, visit: https://github.com/deepan-g2/code-healer"
388
+ puts "📧 Support: support@code-healer.com"
389
+ puts
390
+ puts "Happy coding! 🚀"