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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +70 -0
- data/GEM_SUMMARY.md +307 -0
- data/README.md +281 -0
- data/code_healer.gemspec +77 -0
- data/config/code_healer.yml.example +104 -0
- data/docs/INSTALLATION.md +439 -0
- data/examples/basic_usage.rb +160 -0
- data/exe/code_healer-setup +7 -0
- data/lib/code_healer/application_job.rb +7 -0
- data/lib/code_healer/business_context_analyzer.rb +464 -0
- data/lib/code_healer/business_context_loader.rb +273 -0
- data/lib/code_healer/business_context_manager.rb +297 -0
- data/lib/code_healer/business_logic_generator.rb +94 -0
- data/lib/code_healer/business_rule_applier.rb +54 -0
- data/lib/code_healer/claude_code_evolution_handler.rb +224 -0
- data/lib/code_healer/claude_error_monitor.rb +48 -0
- data/lib/code_healer/config_manager.rb +275 -0
- data/lib/code_healer/context_aware_prompt_builder.rb +153 -0
- data/lib/code_healer/core.rb +513 -0
- data/lib/code_healer/error_handler.rb +141 -0
- data/lib/code_healer/evolution_job.rb +99 -0
- data/lib/code_healer/global_handler.rb +130 -0
- data/lib/code_healer/healing_job.rb +167 -0
- data/lib/code_healer/mcp.rb +108 -0
- data/lib/code_healer/mcp_prompts.rb +111 -0
- data/lib/code_healer/mcp_server.rb +389 -0
- data/lib/code_healer/mcp_tools.rb +2364 -0
- data/lib/code_healer/pull_request_creator.rb +143 -0
- data/lib/code_healer/setup.rb +390 -0
- data/lib/code_healer/simple_evolution.rb +737 -0
- data/lib/code_healer/simple_global_handler.rb +122 -0
- data/lib/code_healer/simple_healer.rb +515 -0
- data/lib/code_healer/terminal_integration.rb +87 -0
- data/lib/code_healer/usage_analyzer.rb +92 -0
- data/lib/code_healer/version.rb +5 -0
- data/lib/code_healer.rb +67 -0
- metadata +411 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodeHealer
|
4
|
+
# MCP Prompt for error fixing workflow
|
5
|
+
class ErrorFixPrompt < MCP::Prompt
|
6
|
+
prompt_name "error_fix_workflow"
|
7
|
+
description "Complete workflow for analyzing and fixing errors with context awareness"
|
8
|
+
arguments [
|
9
|
+
MCP::Prompt::Argument.new(
|
10
|
+
name: "error_type",
|
11
|
+
description: "Type of error to fix",
|
12
|
+
required: true
|
13
|
+
),
|
14
|
+
MCP::Prompt::Argument.new(
|
15
|
+
name: "error_message",
|
16
|
+
description: "Error message details",
|
17
|
+
required: true
|
18
|
+
),
|
19
|
+
MCP::Prompt::Argument.new(
|
20
|
+
name: "class_name",
|
21
|
+
description: "Class where error occurred",
|
22
|
+
required: true
|
23
|
+
),
|
24
|
+
MCP::Prompt::Argument.new(
|
25
|
+
name: "method_name",
|
26
|
+
description: "Method where error occurred",
|
27
|
+
required: true
|
28
|
+
)
|
29
|
+
]
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def template(args, server_context:)
|
33
|
+
context = server_context[:codebase_context]
|
34
|
+
|
35
|
+
MCP::Prompt::Result.new(
|
36
|
+
description: "Error Fix Workflow for #{args['class_name']}##{args['method_name']}",
|
37
|
+
messages: [
|
38
|
+
MCP::Prompt::Message.new(
|
39
|
+
role: "system",
|
40
|
+
content: MCP::Content::Text.new(build_system_prompt(args, context))
|
41
|
+
),
|
42
|
+
MCP::Prompt::Message.new(
|
43
|
+
role: "user",
|
44
|
+
content: MCP::Content::Text.new(build_user_prompt(args, context))
|
45
|
+
),
|
46
|
+
MCP::Prompt::Message.new(
|
47
|
+
role: "assistant",
|
48
|
+
content: MCP::Content::Text.new(build_assistant_response(args, context))
|
49
|
+
)
|
50
|
+
]
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def build_system_prompt(args, context)
|
57
|
+
<<~PROMPT
|
58
|
+
You are an expert Ruby developer and code evolution specialist. You have access to a comprehensive error analysis and code generation system.
|
59
|
+
|
60
|
+
Your role is to:
|
61
|
+
1. Analyze errors with rich context
|
62
|
+
2. Generate intelligent, production-ready fixes
|
63
|
+
3. Validate fixes against business requirements
|
64
|
+
4. Provide recommendations for testing and monitoring
|
65
|
+
|
66
|
+
Available tools:
|
67
|
+
- ErrorAnalysisTool: Analyzes errors with context
|
68
|
+
- CodeFixTool: Generates intelligent code fixes
|
69
|
+
- ContextAnalysisTool: Validates fixes and provides recommendations
|
70
|
+
|
71
|
+
Business Context:
|
72
|
+
- Project Type: #{context[:project_type]}
|
73
|
+
- Business Domain: #{context[:business_domain]}
|
74
|
+
- Coding Standards: #{context[:coding_standards]}
|
75
|
+
- Common Patterns: #{context[:common_patterns]}
|
76
|
+
PROMPT
|
77
|
+
end
|
78
|
+
|
79
|
+
def build_user_prompt(args, context)
|
80
|
+
<<~PROMPT
|
81
|
+
Please analyze and fix the following error:
|
82
|
+
|
83
|
+
Error Type: #{args['error_type']}
|
84
|
+
Error Message: #{args['error_message']}
|
85
|
+
Class: #{args['class_name']}
|
86
|
+
Method: #{args['method_name']}
|
87
|
+
|
88
|
+
Please provide:
|
89
|
+
1. Error analysis with severity and impact assessment
|
90
|
+
2. Intelligent code fix that addresses the specific error
|
91
|
+
3. Validation of the fix against business requirements
|
92
|
+
4. Recommendations for testing and monitoring
|
93
|
+
PROMPT
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_assistant_response(args, context)
|
97
|
+
<<~RESPONSE
|
98
|
+
I'll help you analyze and fix this error using our intelligent evolution system.
|
99
|
+
|
100
|
+
Let me start by analyzing the error with rich context, then generate an intelligent fix, and finally validate it against our business requirements.
|
101
|
+
|
102
|
+
This workflow will ensure the fix is:
|
103
|
+
- Context-aware and business-appropriate
|
104
|
+
- Production-ready with proper error handling
|
105
|
+
- Validated for syntax, performance, and security
|
106
|
+
- Accompanied by testing and monitoring recommendations
|
107
|
+
RESPONSE
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,389 @@
|
|
1
|
+
require_relative 'mcp_tools'
|
2
|
+
require_relative 'mcp_prompts'
|
3
|
+
|
4
|
+
module CodeHealer
|
5
|
+
class McpServer
|
6
|
+
class << self
|
7
|
+
def initialize_server
|
8
|
+
puts "🤖 Initializing MCP Server for intelligent evolution..."
|
9
|
+
|
10
|
+
# Load context and business rules
|
11
|
+
@codebase_context = load_codebase_context
|
12
|
+
@business_rules = load_business_rules
|
13
|
+
|
14
|
+
# Initialize MCP server with tools (simplified for now)
|
15
|
+
@server = CodeHealer::MCP::Server.new(
|
16
|
+
name: "code_healer_server",
|
17
|
+
version: "1.0.0",
|
18
|
+
tools: [
|
19
|
+
ErrorAnalysisTool,
|
20
|
+
CodeFixTool,
|
21
|
+
ContextAnalysisTool
|
22
|
+
],
|
23
|
+
server_context: {
|
24
|
+
codebase_context: @codebase_context,
|
25
|
+
business_rules: @business_rules
|
26
|
+
}
|
27
|
+
)
|
28
|
+
|
29
|
+
puts "✅ MCP Server initialized successfully with tools"
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_codebase_context(class_name, method_name)
|
33
|
+
# Get rich context for a class and method
|
34
|
+
{
|
35
|
+
class_info: analyze_class(class_name),
|
36
|
+
method_info: analyze_method(class_name, method_name),
|
37
|
+
dependencies: find_dependencies(class_name),
|
38
|
+
business_context: get_business_context(class_name),
|
39
|
+
evolution_history: get_evolution_history(class_name, method_name),
|
40
|
+
similar_patterns: find_similar_patterns(class_name, method_name),
|
41
|
+
markdown_requirements: load_business_requirements_from_markdown
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def analyze_error(error, context)
|
46
|
+
puts "🧠 MCP analyzing error: #{error.class} - #{error.message}"
|
47
|
+
|
48
|
+
# Extract class and method names from context
|
49
|
+
class_name = context[:class_name] || 'UnknownClass'
|
50
|
+
method_name = context[:method_name] || 'unknown_method'
|
51
|
+
|
52
|
+
# Use MCP tool to analyze error
|
53
|
+
if defined?(ErrorAnalysisTool)
|
54
|
+
result = ErrorAnalysisTool.call(
|
55
|
+
error_type: error.class.name,
|
56
|
+
error_message: error.message,
|
57
|
+
class_name: class_name,
|
58
|
+
method_name: method_name,
|
59
|
+
server_context: { codebase_context: context }
|
60
|
+
)
|
61
|
+
|
62
|
+
puts "✅ MCP analysis complete"
|
63
|
+
# Parse the JSON response from MCP tool
|
64
|
+
JSON.parse(result.content.first[:text])
|
65
|
+
else
|
66
|
+
puts "⚠️ ErrorAnalysisTool not available, using fallback analysis"
|
67
|
+
# Fallback analysis
|
68
|
+
{
|
69
|
+
severity: 'medium',
|
70
|
+
impact: 'moderate',
|
71
|
+
root_cause: 'division by zero',
|
72
|
+
suggested_fixes: ['add_zero_division_check', 'add_input_validation'],
|
73
|
+
risks: 'low'
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def generate_contextual_fix(error, analysis, context)
|
79
|
+
puts "🧠 MCP generating contextual fix..."
|
80
|
+
|
81
|
+
# Extract class and method names from context
|
82
|
+
class_name = context[:class_name] || 'UnknownClass'
|
83
|
+
method_name = context[:method_name] || 'unknown_method'
|
84
|
+
|
85
|
+
puts "🔍 Debug: class_name = #{class_name}, method_name = #{method_name}"
|
86
|
+
|
87
|
+
# Use MCP tool to generate fix
|
88
|
+
if defined?(CodeFixTool)
|
89
|
+
result = CodeFixTool.call(
|
90
|
+
error_type: error.class.name,
|
91
|
+
error_message: error.message,
|
92
|
+
class_name: class_name,
|
93
|
+
method_name: method_name,
|
94
|
+
analysis: analysis,
|
95
|
+
context: context,
|
96
|
+
server_context: {
|
97
|
+
codebase_context: @codebase_context,
|
98
|
+
business_rules: @business_rules
|
99
|
+
}
|
100
|
+
)
|
101
|
+
|
102
|
+
puts "✅ MCP generated intelligent fix"
|
103
|
+
# Parse the JSON response from MCP tool
|
104
|
+
JSON.parse(result.content.first[:text])
|
105
|
+
else
|
106
|
+
puts "⚠️ CodeFixTool not available, using fallback fix generation"
|
107
|
+
# Fallback fix generation
|
108
|
+
generate_fallback_fix(error, class_name, method_name)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def generate_fallback_fix(error, class_name, method_name)
|
115
|
+
case error.class.name
|
116
|
+
when 'ZeroDivisionError'
|
117
|
+
{
|
118
|
+
fix_type: 'input_validation',
|
119
|
+
code: "def #{method_name}(a, b)\n return 0 if b == 0\n a / b\nend",
|
120
|
+
description: "Added zero division check",
|
121
|
+
risk_level: 'low'
|
122
|
+
}
|
123
|
+
when 'NoMethodError'
|
124
|
+
{
|
125
|
+
fix_type: 'nil_check',
|
126
|
+
code: "def #{method_name}(items)\n return 0 if items.nil? || items.empty?\n items.sum { |item| item[:price] * item[:quantity] }\nend",
|
127
|
+
description: "Added nil and empty checks",
|
128
|
+
risk_level: 'low'
|
129
|
+
}
|
130
|
+
else
|
131
|
+
{
|
132
|
+
fix_type: 'error_handling',
|
133
|
+
code: "def #{method_name}(*args)\n begin\n # Original implementation\n super\n rescue => e\n Rails.logger.error(\"Error in #{method_name}: \#{e.message}\")\n raise e\n end\nend",
|
134
|
+
description: "Added error handling wrapper",
|
135
|
+
risk_level: 'medium'
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def load_codebase_context
|
141
|
+
business_context_file = Rails.root.join('config', 'business_context.yml')
|
142
|
+
|
143
|
+
if File.exist?(business_context_file)
|
144
|
+
YAML.load_file(business_context_file)
|
145
|
+
else
|
146
|
+
# Fallback to default context
|
147
|
+
{
|
148
|
+
project_type: 'Rails Application',
|
149
|
+
business_domain: 'Self-Evolving System',
|
150
|
+
coding_standards: {
|
151
|
+
error_handling: 'comprehensive',
|
152
|
+
logging: 'detailed',
|
153
|
+
validation: 'strict',
|
154
|
+
performance: 'optimized'
|
155
|
+
},
|
156
|
+
common_patterns: {
|
157
|
+
calculator_operations: {
|
158
|
+
divide: 'should handle zero division gracefully',
|
159
|
+
multiply: 'should handle overflow',
|
160
|
+
add: 'should handle type conversion'
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def load_business_rules
|
168
|
+
# Load from YAML config
|
169
|
+
business_context_file = Rails.root.join('config', 'business_context.yml')
|
170
|
+
yaml_rules = {}
|
171
|
+
|
172
|
+
# Also load from business requirements documents
|
173
|
+
markdown_rules = load_business_requirements_from_markdown
|
174
|
+
|
175
|
+
# Prefer only markdown-derived requirements
|
176
|
+
yaml_rules.merge(markdown_rules)
|
177
|
+
end
|
178
|
+
|
179
|
+
def load_business_requirements_from_markdown
|
180
|
+
requirements = {}
|
181
|
+
|
182
|
+
# Look for business requirements in various locations
|
183
|
+
search_paths = [
|
184
|
+
'business_requirements',
|
185
|
+
'docs/business_requirements',
|
186
|
+
'requirements',
|
187
|
+
'docs/requirements'
|
188
|
+
]
|
189
|
+
|
190
|
+
search_paths.each do |path|
|
191
|
+
if Dir.exist?(path)
|
192
|
+
Dir.glob("#{path}/**/*.md").each do |file|
|
193
|
+
content = File.read(file)
|
194
|
+
# Simply include the content without rigid pattern matching
|
195
|
+
requirements['markdown_requirements'] ||= []
|
196
|
+
requirements['markdown_requirements'] << {
|
197
|
+
file: file,
|
198
|
+
content: content.strip
|
199
|
+
}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
requirements
|
205
|
+
end
|
206
|
+
|
207
|
+
def analyze_class(class_name)
|
208
|
+
{
|
209
|
+
name: class_name,
|
210
|
+
type: determine_class_type(class_name),
|
211
|
+
responsibilities: analyze_class_responsibilities(class_name),
|
212
|
+
complexity: calculate_class_complexity(class_name),
|
213
|
+
test_coverage: get_test_coverage(class_name),
|
214
|
+
documentation: get_documentation_status(class_name)
|
215
|
+
}
|
216
|
+
end
|
217
|
+
|
218
|
+
def analyze_method(class_name, method_name)
|
219
|
+
{
|
220
|
+
name: method_name,
|
221
|
+
signature: get_method_signature(class_name, method_name),
|
222
|
+
complexity: calculate_method_complexity(class_name, method_name),
|
223
|
+
usage_patterns: analyze_usage_patterns(class_name, method_name),
|
224
|
+
performance: analyze_performance_characteristics(class_name, method_name),
|
225
|
+
error_prone_areas: identify_error_prone_areas(class_name, method_name)
|
226
|
+
}
|
227
|
+
end
|
228
|
+
|
229
|
+
def find_dependencies(class_name)
|
230
|
+
{
|
231
|
+
models: find_model_dependencies(class_name),
|
232
|
+
services: find_service_dependencies(class_name),
|
233
|
+
external_apis: find_external_api_dependencies(class_name),
|
234
|
+
database: find_database_dependencies(class_name),
|
235
|
+
gems: find_gem_dependencies(class_name)
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
def get_business_context(class_name)
|
240
|
+
{
|
241
|
+
domain: determine_business_domain(class_name),
|
242
|
+
criticality: assess_business_criticality(class_name),
|
243
|
+
regulatory_requirements: identify_regulatory_requirements(class_name),
|
244
|
+
sla_requirements: get_sla_requirements(class_name),
|
245
|
+
user_impact: assess_user_impact(class_name)
|
246
|
+
}
|
247
|
+
end
|
248
|
+
|
249
|
+
def get_evolution_history(class_name, method_name)
|
250
|
+
{
|
251
|
+
previous_evolutions: get_previous_evolutions(class_name, method_name),
|
252
|
+
success_rate: calculate_evolution_success_rate(class_name, method_name),
|
253
|
+
common_patterns: identify_common_evolution_patterns(class_name, method_name),
|
254
|
+
performance_impact: analyze_historical_performance_impact(class_name, method_name)
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
def find_similar_patterns(class_name, method_name)
|
259
|
+
{
|
260
|
+
similar_methods: find_similar_methods(class_name, method_name),
|
261
|
+
similar_errors: find_similar_errors(class_name, method_name),
|
262
|
+
best_practices: find_best_practices(class_name, method_name),
|
263
|
+
anti_patterns: identify_anti_patterns(class_name, method_name)
|
264
|
+
}
|
265
|
+
end
|
266
|
+
|
267
|
+
# Helper methods (simplified for brevity)
|
268
|
+
def determine_class_type(class_name)
|
269
|
+
if class_name.include?('Controller')
|
270
|
+
'controller'
|
271
|
+
elsif class_name.include?('Service')
|
272
|
+
'service'
|
273
|
+
elsif class_name.include?('Model')
|
274
|
+
'model'
|
275
|
+
else
|
276
|
+
'utility'
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def analyze_class_responsibilities(class_name)
|
281
|
+
['data_processing', 'business_logic', 'error_handling']
|
282
|
+
end
|
283
|
+
|
284
|
+
def calculate_class_complexity(class_name)
|
285
|
+
rand(1..10)
|
286
|
+
end
|
287
|
+
|
288
|
+
def get_test_coverage(class_name)
|
289
|
+
rand(0..100)
|
290
|
+
end
|
291
|
+
|
292
|
+
def get_documentation_status(class_name)
|
293
|
+
['well_documented', 'partially_documented', 'undocumented'].sample
|
294
|
+
end
|
295
|
+
|
296
|
+
def get_method_signature(class_name, method_name)
|
297
|
+
"def #{method_name}(*args, **kwargs, &block)"
|
298
|
+
end
|
299
|
+
|
300
|
+
def calculate_method_complexity(class_name, method_name)
|
301
|
+
rand(1..5)
|
302
|
+
end
|
303
|
+
|
304
|
+
def analyze_usage_patterns(class_name, method_name)
|
305
|
+
['frequently_called', 'rarely_called', 'critical_path'].sample
|
306
|
+
end
|
307
|
+
|
308
|
+
def analyze_performance_characteristics(class_name, method_name)
|
309
|
+
['fast', 'moderate', 'slow'].sample
|
310
|
+
end
|
311
|
+
|
312
|
+
def identify_error_prone_areas(class_name, method_name)
|
313
|
+
['input_validation', 'external_dependencies', 'data_processing'].sample
|
314
|
+
end
|
315
|
+
|
316
|
+
def find_model_dependencies(class_name)
|
317
|
+
[]
|
318
|
+
end
|
319
|
+
|
320
|
+
def find_service_dependencies(class_name)
|
321
|
+
[]
|
322
|
+
end
|
323
|
+
|
324
|
+
def find_external_api_dependencies(class_name)
|
325
|
+
[]
|
326
|
+
end
|
327
|
+
|
328
|
+
def find_database_dependencies(class_name)
|
329
|
+
[]
|
330
|
+
end
|
331
|
+
|
332
|
+
def find_gem_dependencies(class_name)
|
333
|
+
[]
|
334
|
+
end
|
335
|
+
|
336
|
+
def determine_business_domain(class_name)
|
337
|
+
['finance', 'ecommerce', 'user_management', 'data_processing'].sample
|
338
|
+
end
|
339
|
+
|
340
|
+
def assess_business_criticality(class_name)
|
341
|
+
['high', 'medium', 'low'].sample
|
342
|
+
end
|
343
|
+
|
344
|
+
def identify_regulatory_requirements(class_name)
|
345
|
+
[]
|
346
|
+
end
|
347
|
+
|
348
|
+
def get_sla_requirements(class_name)
|
349
|
+
'99.9%'
|
350
|
+
end
|
351
|
+
|
352
|
+
def assess_user_impact(class_name)
|
353
|
+
['high', 'medium', 'low'].sample
|
354
|
+
end
|
355
|
+
|
356
|
+
def get_previous_evolutions(class_name, method_name)
|
357
|
+
[]
|
358
|
+
end
|
359
|
+
|
360
|
+
def calculate_evolution_success_rate(class_name, method_name)
|
361
|
+
rand(0.7..1.0)
|
362
|
+
end
|
363
|
+
|
364
|
+
def identify_common_evolution_patterns(class_name, method_name)
|
365
|
+
[]
|
366
|
+
end
|
367
|
+
|
368
|
+
def analyze_historical_performance_impact(class_name, method_name)
|
369
|
+
'improved'
|
370
|
+
end
|
371
|
+
|
372
|
+
def find_similar_methods(class_name, method_name)
|
373
|
+
[]
|
374
|
+
end
|
375
|
+
|
376
|
+
def find_similar_errors(class_name, method_name)
|
377
|
+
[]
|
378
|
+
end
|
379
|
+
|
380
|
+
def find_best_practices(class_name, method_name)
|
381
|
+
[]
|
382
|
+
end
|
383
|
+
|
384
|
+
def identify_anti_patterns(class_name, method_name)
|
385
|
+
[]
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|