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,737 @@
1
+ require 'git'
2
+ require_relative 'business_rule_applier'
3
+ require_relative 'business_context_analyzer'
4
+
5
+ module CodeHealer
6
+ class SimpleEvolution
7
+ def self.handle_error(error, class_name, method_name, file_path)
8
+ # Check if evolution is enabled and allowed
9
+ unless ConfigManager.enabled?
10
+ puts "Self-evolution is disabled"
11
+ return false
12
+ end
13
+
14
+ unless ConfigManager.can_evolve_class?(class_name)
15
+ puts "Class #{class_name} is not allowed to evolve"
16
+ return false
17
+ end
18
+
19
+ unless ConfigManager.can_handle_error?(error)
20
+ puts "Error type #{error.class.name} is not allowed to be handled"
21
+ return false
22
+ end
23
+
24
+ puts "\n=== Self-Evolution Triggered ==="
25
+ puts "Error: #{error.class} - #{error.message}"
26
+ puts "Class: #{class_name}"
27
+ puts "Method: #{method_name}"
28
+ puts "File: #{file_path}"
29
+
30
+ # Analyze the error and generate a fix
31
+ fix = generate_fix(error, class_name, method_name)
32
+
33
+ if fix
34
+ # Apply the fix
35
+ apply_fix(file_path, fix, class_name, method_name, error)
36
+ return true
37
+ else
38
+ puts "Could not generate fix for this error"
39
+ return false
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def self.repatch_evolved_class(class_name, file_path)
46
+ puts "🔄 Re-patching evolved class: #{class_name}"
47
+
48
+ begin
49
+ # Get the actual class object
50
+ klass = Object.const_get(class_name)
51
+
52
+ # Re-patch the class with error handling
53
+ klass.class_eval do
54
+ instance_methods(false).each do |method_name|
55
+ next if method_name == :initialize || method_name.to_s.start_with?('_')
56
+
57
+ original_method = instance_method(method_name)
58
+ remove_method(method_name)
59
+
60
+ define_method(method_name) do |*args, &block|
61
+ begin
62
+ original_method.bind(self).call(*args, &block)
63
+ rescue => e
64
+ puts "\n=== Error Caught in #{self.class.name}##{method_name} ==="
65
+ puts "Error: #{e.class} - #{e.message}"
66
+
67
+ # Handle the error with self-evolution
68
+ handle_console_error(e, self.class, method_name)
69
+ raise e
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ puts "✅ Successfully re-patched #{class_name} for error handling"
76
+ return true
77
+
78
+ rescue => e
79
+ puts "❌ Failed to re-patch #{class_name}: #{e.message}"
80
+ return false
81
+ end
82
+ end
83
+
84
+ def self.generate_fix(error, class_name, method_name)
85
+ case error
86
+ when ZeroDivisionError
87
+ generate_division_fix(class_name, method_name)
88
+ when NoMethodError
89
+ generate_method_fix(error, class_name, method_name)
90
+ else
91
+ nil
92
+ end
93
+ end
94
+
95
+ def self.generate_division_fix(class_name, method_name)
96
+ {
97
+ method_name: method_name,
98
+ new_code: <<~RUBY
99
+ def #{method_name}(a, b)
100
+ if b == 0
101
+ puts "Warning: Division by zero attempted. Returning 0."
102
+ return 0
103
+ end
104
+ a / b
105
+ end
106
+ RUBY
107
+ }
108
+ end
109
+
110
+ def self.generate_method_fix(error, class_name, method_name)
111
+ if error.message.include?('undefined method')
112
+ {
113
+ method_name: method_name,
114
+ new_code: <<~RUBY
115
+ def #{method_name}(a, b)
116
+ puts "Warning: Method #{method_name} called but not implemented. Returning 0."
117
+ return 0
118
+ end
119
+ RUBY
120
+ }
121
+ else
122
+ nil
123
+ end
124
+ end
125
+
126
+ def self.apply_fix(file_path, fix, class_name, method_name, error)
127
+ puts "Applying fix for #{class_name}##{method_name}..."
128
+
129
+ # Read current file
130
+ current_content = File.read(file_path)
131
+ puts "Current content length: #{current_content.length}"
132
+
133
+ # Get the new method code and clean it up
134
+ new_method_code = fix['new_code'] || fix[:new_code]
135
+ puts "Generated new method: #{new_method_code}"
136
+
137
+ # 🔧 APPLY BUSINESS RULES TO THE GENERATED CODE
138
+ if defined?(BusinessContextAnalyzer) && defined?(BusinessRuleApplier)
139
+ begin
140
+ puts "🔍 Getting business context for business rule application..."
141
+
142
+ # Get the file path for business context analysis
143
+ file_path_for_context = file_path
144
+
145
+ # Analyze business context
146
+ business_analysis = BusinessContextAnalyzer.analyze_error_for_business_context(
147
+ error, class_name, method_name, file_path_for_context
148
+ )
149
+
150
+ # Apply business rules to the generated code
151
+ new_method_code = BusinessRuleApplier.apply_business_rules_to_code(
152
+ business_analysis, new_method_code, error, class_name, method_name
153
+ )
154
+
155
+ puts "✅ Business rules applied to generated code"
156
+ rescue => e
157
+ puts "⚠️ Warning: Could not apply business rules: #{e.message}"
158
+ puts " Continuing with original generated code..."
159
+ end
160
+ else
161
+ puts "ℹ️ Business rule applier not available, using original generated code"
162
+ end
163
+
164
+ # Clean up the new method code - remove extra indentation
165
+ method_lines = new_method_code.strip.split("\n")
166
+ # Find the base indentation of the first line
167
+ base_indent = method_lines.first.match(/^(\s*)/)[1].length
168
+ # Remove the base indentation from all lines
169
+ cleaned_method_lines = method_lines.map do |line|
170
+ if line.strip.empty?
171
+ line
172
+ else
173
+ line_indent = line.match(/^(\s*)/)[1].length
174
+ if line_indent >= base_indent
175
+ line[base_indent..-1]
176
+ else
177
+ line
178
+ end
179
+ end
180
+ end
181
+ cleaned_method_code = cleaned_method_lines.join("\n")
182
+
183
+ # Use a simpler and more reliable method replacement approach
184
+ lines = current_content.split("\n")
185
+ new_lines = []
186
+ method_start_index = nil
187
+ method_indent = 0
188
+
189
+ # Find the method start
190
+ lines.each_with_index do |line, index|
191
+ if line.strip.start_with?("def #{fix['method_name'] || fix[:method_name]}")
192
+ method_start_index = index
193
+ method_indent = line.match(/^(\s*)/)[1].length
194
+ break
195
+ end
196
+ end
197
+
198
+ if method_start_index.nil?
199
+ puts "❌ Could not find method #{fix['method_name'] || fix[:method_name]} in file"
200
+ return false
201
+ end
202
+
203
+ # Find the method end using a simple approach
204
+ method_end_index = method_start_index
205
+ indent_level = method_indent
206
+
207
+ lines[method_start_index..-1].each_with_index do |line, relative_index|
208
+ actual_index = method_start_index + relative_index
209
+ current_indent = line.match(/^(\s*)/)[1].length
210
+
211
+ # Skip the method definition line
212
+ if relative_index == 0
213
+ next
214
+ end
215
+
216
+ # If we find an 'end' at the same or lower indentation level, we're done
217
+ if line.strip == 'end' && current_indent <= indent_level
218
+ method_end_index = actual_index
219
+ break
220
+ end
221
+
222
+ # If we find another method definition at the same level, we're done
223
+ if line.strip.start_with?('def ') && current_indent == indent_level
224
+ method_end_index = actual_index - 1
225
+ break
226
+ end
227
+ end
228
+
229
+ # Build the new content
230
+ new_lines = lines[0...method_start_index]
231
+
232
+ # Add the new method with proper indentation
233
+ method_indent_str = ' ' * method_indent
234
+ cleaned_method_lines.each do |method_line|
235
+ if method_line.strip.empty?
236
+ new_lines << method_line
237
+ else
238
+ new_lines << method_indent_str + method_line
239
+ end
240
+ end
241
+
242
+ # Add the rest of the file after the method
243
+ new_lines += lines[(method_end_index + 1)..-1]
244
+
245
+ new_content = new_lines.join("\n")
246
+ puts "New content length: #{new_content.length}"
247
+
248
+ # Validate syntax before applying
249
+ unless validate_syntax(new_content)
250
+ puts "❌ Syntax validation failed, reverting to original content"
251
+ return false
252
+ end
253
+
254
+ # Create Git branch
255
+ git_settings = ConfigManager.git_settings
256
+ branch_prefix = git_settings['branch_prefix'] || 'evolve'
257
+ branch_name = "#{branch_prefix}/#{class_name.downcase}-#{method_name}-#{Time.now.to_i}"
258
+ puts "Creating new branch: #{branch_name}"
259
+
260
+ begin
261
+ git = Git.open(Dir.pwd)
262
+
263
+ # Create and checkout new branch
264
+ git.branch(branch_name).checkout
265
+ puts "Created and checked out branch: #{branch_name}"
266
+
267
+ # Write the updated file
268
+ File.write(file_path, new_content)
269
+ puts "Updated file: #{file_path}"
270
+
271
+ # Reload the class to get the updated method
272
+ load file_path
273
+ puts "🔄 Class reloaded with updated method!"
274
+
275
+ # Re-patch the evolved class to restore error handling
276
+ repatch_evolved_class(class_name, file_path)
277
+
278
+ # Commit the changes
279
+ commit_template = (git_settings['commit_message_template'] || 'Fix {class_name}##{method_name}: {error_type}').to_s
280
+ commit_message = commit_template.gsub('{class_name}', class_name.to_s)
281
+ .gsub('{method_name}', method_name.to_s)
282
+ .gsub('{error_type}', error.class.name.to_s)
283
+
284
+ puts "Commit message: #{commit_message}"
285
+
286
+ git.add(file_path)
287
+ puts "Added file to git"
288
+
289
+ # Use a simpler commit approach
290
+ begin
291
+ git.commit(commit_message)
292
+ puts "Committed changes to branch: #{branch_name}"
293
+ rescue => commit_error
294
+ puts "Commit failed with message: #{commit_message}"
295
+ puts "Commit error: #{commit_error.message}"
296
+ # Try with a simpler message
297
+ git.commit("Fix #{class_name}##{method_name}: #{error.class.name}")
298
+ puts "Committed with fallback message"
299
+ end
300
+
301
+ # Push to remote if enabled
302
+ if git_settings['auto_push']
303
+ begin
304
+ git.push('origin', branch_name)
305
+ puts "Pushed to remote repository"
306
+
307
+ # Create pull request if enabled
308
+ if ConfigManager.auto_create_pr?
309
+ puts "🎯 Attempting to create pull request..."
310
+ fix_description = get_fix_description(error, method_name)
311
+ pr_url = CodeHealer::PullRequestCreator.create_pull_request(
312
+ branch_name,
313
+ class_name,
314
+ method_name,
315
+ error,
316
+ fix_description,
317
+ file_path
318
+ )
319
+ if pr_url
320
+ puts "✅ Pull request created successfully: #{pr_url}"
321
+ else
322
+ puts "❌ Pull request creation failed"
323
+ end
324
+ else
325
+ puts "📝 PR creation is disabled in configuration"
326
+ end
327
+ rescue => e
328
+ puts "Push failed (expected without remote): #{e.message}"
329
+ end
330
+ end
331
+
332
+ return true
333
+
334
+ rescue => e
335
+ puts "Git operations failed: #{e.message}"
336
+ return false
337
+ end
338
+ end
339
+
340
+ def self.get_fix_description(error, method_name)
341
+ case error
342
+ when ZeroDivisionError
343
+ "Added division by zero check to prevent crashes"
344
+ when NoMethodError
345
+ "Added method implementation with default return value"
346
+ when ArgumentError
347
+ "Added argument validation and error handling"
348
+ else
349
+ "Added error handling for #{error.class.name}"
350
+ end
351
+ end
352
+
353
+ def self.validate_syntax(content)
354
+ begin
355
+ # Try to parse the content as Ruby code
356
+ RubyVM::InstructionSequence.compile(content)
357
+ puts "✅ Syntax validation passed"
358
+ true
359
+ rescue SyntaxError => e
360
+ puts "❌ Syntax error: #{e.message}"
361
+ false
362
+ rescue => e
363
+ puts "❌ Validation error: #{e.message}"
364
+ false
365
+ end
366
+ end
367
+
368
+ # Intelligent MCP-powered error handler
369
+ def self.handle_error_with_mcp_intelligence(error, class_name, method_name, file_path, business_context = nil)
370
+ # Check if evolution is enabled and allowed
371
+ unless ConfigManager.enabled?
372
+ puts "Self-evolution is disabled"
373
+ return false
374
+ end
375
+
376
+ unless ConfigManager.can_evolve_class?(class_name)
377
+ puts "Class #{class_name} is not allowed to evolve"
378
+ return false
379
+ end
380
+
381
+ unless ConfigManager.can_handle_error?(error)
382
+ puts "Error type #{error.class.name} is not allowed to be handled"
383
+ return false
384
+ end
385
+
386
+ puts "\n=== MCP-Powered Self-Evolution Triggered ==="
387
+ puts "Error: #{error.class} - #{error.message}"
388
+ puts "Class: #{class_name}"
389
+ puts "Method: #{method_name}"
390
+ puts "File: #{file_path}"
391
+ puts "Business Context: #{business_context.inspect}" if business_context
392
+
393
+
394
+ # Initialize MCP server if not already done
395
+ MCPServer.initialize_server unless defined?(@mcp_initialized)
396
+ @mcp_initialized = true
397
+
398
+ # Get rich context from MCP, enhanced with business context if provided
399
+ puts "🧠 Getting codebase context from MCP..."
400
+ context = MCPServer.get_codebase_context(class_name, method_name)
401
+
402
+ # Enhance context with business context if provided
403
+ if business_context
404
+ puts "🧠 Enhancing context with business rules..."
405
+ context = context.merge({
406
+ 'business_context' => business_context
407
+ })
408
+ end
409
+
410
+ # Analyze error with MCP intelligence
411
+ puts "🧠 Analyzing error with MCP..."
412
+ analysis = MCPServer.analyze_error(error, context)
413
+
414
+ # Generate intelligent, contextual fix
415
+ puts "🧠 Generating intelligent fix with MCP..."
416
+ fix = MCPServer.generate_contextual_fix(error, analysis, context)
417
+
418
+ # Debug: Check what fix contains
419
+ puts "🔍 Debug: Fix result = #{fix.inspect}"
420
+
421
+ # Validate fix with MCP
422
+ puts "🔍 Validating fix with MCP..."
423
+ validation = MCPServer.validate_fix(fix, context)
424
+
425
+ unless validation['approved'] || validation[:approved]
426
+ puts "❌ MCP validation failed: #{validation['recommendations'] || validation[:recommendations]}"
427
+ return false
428
+ end
429
+
430
+ puts "✅ MCP validation passed with confidence: #{validation['confidence_score'] || validation[:confidence_score]}"
431
+
432
+ if fix
433
+ if ConfigManager.require_approval?
434
+ # Approval required - create PR but don't apply fix locally
435
+ puts "\n🔒 Approval Required - Creating PR for Review"
436
+ puts "=" * 50
437
+ puts "The intelligent fix will be applied only after PR is merged."
438
+ puts "Check the created PR for review and approval."
439
+
440
+ # Create PR without applying fix locally
441
+ create_pr_without_local_fix(file_path, fix, class_name, method_name, error)
442
+ return true
443
+ else
444
+ # No approval required - apply fix immediately
445
+ apply_fix(file_path, fix, class_name, method_name, error)
446
+ return true
447
+ end
448
+ else
449
+ puts "Could not generate intelligent fix for this error"
450
+ return false
451
+ end
452
+ end
453
+
454
+ # Approval-aware error handler (legacy)
455
+ def self.handle_error_with_approval(error, class_name, method_name, file_path)
456
+ # Check if evolution is enabled and allowed
457
+ unless ConfigManager.enabled?
458
+ puts "Self-evolution is disabled"
459
+ return false
460
+ end
461
+
462
+ unless ConfigManager.can_evolve_class?(class_name)
463
+ puts "Class #{class_name} is not allowed to evolve"
464
+ return false
465
+ end
466
+
467
+ unless ConfigManager.can_handle_error?(error)
468
+ puts "Error type #{error.class.name} is not allowed to be handled"
469
+ return false
470
+ end
471
+
472
+ puts "\n=== Self-Evolution Triggered ==="
473
+ puts "Error: #{error.class} - #{error.message}"
474
+ puts "Class: #{class_name}"
475
+ puts "Method: #{method_name}"
476
+ puts "File: #{file_path}"
477
+
478
+ # Analyze the error and generate a fix
479
+ fix = generate_fix(error, class_name, method_name)
480
+
481
+ if fix
482
+ if ConfigManager.require_approval?
483
+ # Approval required - create PR but don't apply fix locally
484
+ puts "\n🔒 Approval Required - Creating PR for Review"
485
+ puts "=" * 50
486
+ puts "The fix will be applied only after PR is merged."
487
+ puts "Check the created PR for review and approval."
488
+
489
+ # Create PR without applying fix locally
490
+ create_pr_without_local_fix(file_path, fix, class_name, method_name, error)
491
+ return true
492
+ else
493
+ # No approval required - apply fix immediately
494
+ apply_fix(file_path, fix, class_name, method_name, error)
495
+ return true
496
+ end
497
+ else
498
+ puts "Could not generate fix for this error"
499
+ return false
500
+ end
501
+ end
502
+
503
+ def self.create_pr_without_local_fix(file_path, fix, class_name, method_name, error)
504
+ puts "Creating PR for #{class_name}##{method_name}..."
505
+
506
+ # Create Git branch
507
+ git_settings = ConfigManager.git_settings
508
+ branch_prefix = git_settings['branch_prefix'] || 'evolve'
509
+ branch_name = "#{branch_prefix}/#{class_name.downcase}-#{method_name}-#{Time.now.to_i}"
510
+ puts "Creating new branch: #{branch_name}"
511
+
512
+ begin
513
+ git = Git.open(Dir.pwd)
514
+
515
+ # Store the original branch
516
+ original_branch = git.current_branch
517
+ puts "Original branch: #{original_branch}"
518
+
519
+ # Create and checkout new branch
520
+ git.branch(branch_name).checkout
521
+ puts "Created and checked out branch: #{branch_name}"
522
+
523
+ # Read current file content
524
+ current_content = File.read(file_path)
525
+
526
+ # Apply the fix to create the new content
527
+ lines = current_content.split("\n")
528
+ new_lines = []
529
+ in_method = false
530
+ method_indent = 0
531
+ skip_until_end = false
532
+
533
+ lines.each_with_index do |line, index|
534
+ if skip_until_end
535
+ if line.strip == 'end' && in_method
536
+ in_method = false
537
+ skip_until_end = false
538
+ # Add the new method content
539
+ new_lines.concat(fix[:new_code].strip.split("\n"))
540
+ end
541
+ next
542
+ end
543
+
544
+ if line.strip.start_with?("def #{fix[:method_name]}(")
545
+ in_method = true
546
+ method_indent = line.match(/^(\s*)/)[1].length
547
+ skip_until_end = true
548
+ next
549
+ end
550
+
551
+ new_lines << line
552
+ end
553
+
554
+ new_content = new_lines.join("\n")
555
+
556
+ # Write the updated file to the branch
557
+ File.write(file_path, new_content)
558
+ puts "Updated file in branch: #{file_path}"
559
+
560
+ # Use simple commit message
561
+ commit_message = "Fix #{method_name} method (requires approval)"
562
+
563
+ puts "Commit message: #{commit_message}"
564
+
565
+ git.add(file_path)
566
+ puts "Added file to git"
567
+
568
+ # Commit the changes
569
+ commit_success = false
570
+ begin
571
+ git.commit(commit_message)
572
+ puts "Committed changes to branch: #{branch_name}"
573
+ commit_success = true
574
+ rescue => commit_error
575
+ puts "Commit failed: #{commit_error.message}"
576
+ # Try using system git command as fallback
577
+ begin
578
+ system("git add #{file_path}")
579
+ system("git commit -m '#{commit_message}'")
580
+ if $?.success?
581
+ puts "Committed using system git command"
582
+ commit_success = true
583
+ else
584
+ puts "System git commit also failed"
585
+ end
586
+ rescue => system_error
587
+ puts "System git command failed: #{system_error.message}"
588
+ end
589
+ end
590
+
591
+ # Push to remote if enabled and commit was successful
592
+ push_success = false
593
+ if git_settings['auto_push'] && commit_success
594
+ begin
595
+ git.push('origin', branch_name)
596
+ puts "Pushed to remote repository"
597
+ push_success = true
598
+ rescue => e
599
+ puts "Git gem push failed: #{e.message}"
600
+ # Try using system git command as fallback
601
+ begin
602
+ system("git push origin #{branch_name}")
603
+ if $?.success?
604
+ puts "Pushed using system git command"
605
+ push_success = true
606
+ else
607
+ puts "System git push also failed"
608
+ end
609
+ rescue => system_error
610
+ puts "System git push failed: #{system_error.message}"
611
+ end
612
+ end
613
+ elsif !commit_success
614
+ puts "Push skipped - commit failed"
615
+ end
616
+
617
+ # Create pull request if enabled
618
+ if ConfigManager.auto_create_pr? && push_success
619
+ puts "🎯 Creating pull request for approval..."
620
+ fix_description = get_fix_description(error, method_name)
621
+ pr_url = PullRequestCreator.create_pull_request(
622
+ branch_name,
623
+ class_name,
624
+ method_name,
625
+ error,
626
+ fix_description,
627
+ file_path
628
+ )
629
+ if pr_url
630
+ puts "✅ Pull request created successfully: #{pr_url}"
631
+ puts "🔒 Fix will be applied only after PR is merged."
632
+ puts "📋 Review the PR and merge when ready."
633
+ else
634
+ puts "❌ Pull request creation failed"
635
+ end
636
+ elsif ConfigManager.auto_create_pr? && !push_success
637
+ puts "📝 PR creation skipped - push to remote failed"
638
+ else
639
+ puts "📝 PR creation is disabled in configuration"
640
+ end
641
+
642
+ # Switch back to original branch
643
+ git.checkout(original_branch)
644
+ puts "Switched back to original branch: #{original_branch}"
645
+
646
+ return true
647
+
648
+ rescue => e
649
+ puts "Git operations failed: #{e.message}"
650
+ return false
651
+ end
652
+ end
653
+
654
+ # Dedicated method for Git operations (used by Claude Code evolution)
655
+ def self.handle_git_operations_for_claude(error, class_name, method_name, file_path)
656
+ puts "🚀 Starting Git operations for Claude Code evolution..."
657
+
658
+ begin
659
+ git_settings = ConfigManager.git_settings
660
+ branch_prefix = git_settings['branch_prefix'] || 'evolve'
661
+ branch_name = "#{branch_prefix}/#{class_name.downcase}-#{method_name}-#{Time.now.to_i}"
662
+ puts "Creating new branch: #{branch_name}"
663
+
664
+ git = Git.open(Dir.pwd)
665
+
666
+ # Create and checkout new branch
667
+ git.branch(branch_name).checkout
668
+ puts "Created and checked out branch: #{branch_name}"
669
+
670
+ # Add all modified files (Claude Code may have modified multiple files)
671
+ git.add('.')
672
+ puts "Added all modified files to git"
673
+
674
+ # Commit the changes
675
+ commit_template = (git_settings['commit_message_template'] || 'Fix {class_name}##{method_name}: {error_type}').to_s
676
+ commit_message = commit_template.gsub('{class_name}', class_name.to_s)
677
+ .gsub('{method_name}', method_name.to_s)
678
+ .gsub('{error_type}', error.class.name.to_s)
679
+
680
+ puts "Commit message: #{commit_message}"
681
+
682
+ begin
683
+ git.commit(commit_message)
684
+ puts "Committed changes to branch: #{branch_name}"
685
+ rescue => commit_error
686
+ puts "Commit failed, trying fallback message..."
687
+ git.commit("Fix #{class_name}##{method_name}: #{error.class.name}")
688
+ puts "Committed with fallback message"
689
+ end
690
+
691
+ # Push to remote if enabled
692
+ if git_settings['auto_push']
693
+ begin
694
+ git.push('origin', branch_name)
695
+ puts "Pushed to remote repository"
696
+
697
+ # Create pull request if enabled
698
+ if ConfigManager.auto_create_pr?
699
+ puts "🎯 Attempting to create pull request..."
700
+ fix_description = get_fix_description(error, method_name)
701
+ pr_url = CodeHealer::PullRequestCreator.create_pull_request(
702
+ branch_name,
703
+ class_name,
704
+ method_name,
705
+ error,
706
+ fix_description,
707
+ file_path
708
+ )
709
+ if pr_url
710
+ puts "✅ Pull request created successfully: #{pr_url}"
711
+ return true
712
+ else
713
+ puts "❌ Pull request creation failed"
714
+ return false
715
+ end
716
+ else
717
+ puts "📝 PR creation is disabled in configuration"
718
+ return true
719
+ end
720
+ rescue => e
721
+ puts "Push failed: #{e.message}"
722
+ return false
723
+ end
724
+ else
725
+ puts "📝 Auto-push is disabled in configuration"
726
+ return true
727
+ end
728
+
729
+ rescue => e
730
+ puts "Git operations failed: #{e.message}"
731
+ return false
732
+ end
733
+ end
734
+ end
735
+ end
736
+
737
+ require_relative 'mcp_server'