code_healer 0.1.24 โ 0.1.32
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 +4 -4
- data/CHANGELOG.md +46 -0
- data/lib/code_healer/claude_code_evolution_handler.rb +141 -53
- data/lib/code_healer/config_manager.rb +16 -23
- data/lib/code_healer/core.rb +36 -25
- data/lib/code_healer/healing_job.rb +33 -29
- data/lib/code_healer/healing_workspace_manager.rb +132 -118
- data/lib/code_healer/mcp_server.rb +8 -7
- data/lib/code_healer/presentation_logger.rb +114 -0
- data/lib/code_healer/setup.rb +9 -45
- data/lib/code_healer/version.rb +1 -1
- metadata +3 -2
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'sidekiq'
|
2
2
|
require 'open3'
|
3
|
+
require_relative 'presentation_logger'
|
3
4
|
|
4
5
|
module CodeHealer
|
5
6
|
class HealingJob
|
@@ -8,15 +9,15 @@ module CodeHealer
|
|
8
9
|
sidekiq_options retry: 3, backtrace: true, queue: 'evolution'
|
9
10
|
|
10
11
|
def perform(*args)
|
11
|
-
|
12
|
-
|
12
|
+
start_time = Time.now
|
13
|
+
PresentationLogger.section("CodeHealer โ Healing Job")
|
13
14
|
|
14
|
-
|
15
15
|
# Support both legacy and new invocation styles
|
16
16
|
error, class_name, method_name, evolution_method, backtrace = parse_args(args)
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
PresentationLogger.kv("Error", "#{error.class}: #{error.message}")
|
18
|
+
PresentationLogger.kv("Target", "#{class_name}##{method_name}")
|
19
|
+
PresentationLogger.kv("Strategy", evolution_method)
|
20
|
+
PresentationLogger.backtrace(backtrace)
|
20
21
|
|
21
22
|
# Track start metric
|
22
23
|
healing_id = MetricsCollector.generate_healing_id
|
@@ -30,13 +31,13 @@ module CodeHealer
|
|
30
31
|
)
|
31
32
|
MetricsCollector.track_error_occurrence(healing_id, Time.current)
|
32
33
|
|
33
|
-
|
34
|
+
PresentationLogger.success("Healing started for #{class_name}##{method_name}")
|
34
35
|
|
35
|
-
|
36
|
+
PresentationLogger.step("Creating isolated healing workspace")
|
36
37
|
# Create isolated healing workspace
|
37
38
|
workspace_path = create_healing_workspace(class_name, method_name)
|
38
39
|
MetricsCollector.track_workspace_creation(healing_id, workspace_path)
|
39
|
-
|
40
|
+
PresentationLogger.kv("Workspace", workspace_path)
|
40
41
|
|
41
42
|
ai_time_ms = nil
|
42
43
|
git_time_ms = nil
|
@@ -46,7 +47,7 @@ module CodeHealer
|
|
46
47
|
failure_reason = nil
|
47
48
|
|
48
49
|
begin
|
49
|
-
|
50
|
+
PresentationLogger.step("Applying fixes in isolated environment")
|
50
51
|
# Apply fixes in isolated environment
|
51
52
|
ai_started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
52
53
|
success = apply_fixes_in_workspace(workspace_path, error, class_name, method_name, evolution_method)
|
@@ -83,17 +84,18 @@ module CodeHealer
|
|
83
84
|
false # pr_created
|
84
85
|
)
|
85
86
|
overall_success = true
|
86
|
-
|
87
|
+
PresentationLogger.success("Fixes applied and validated")
|
88
|
+
PresentationLogger.kv("Branch", healing_branch)
|
87
89
|
else
|
88
90
|
overall_success = false
|
89
91
|
failure_reason ||= 'healing_branch_creation_failed'
|
90
|
-
|
92
|
+
PresentationLogger.warn("Fixes applied and tested, but merge failed")
|
91
93
|
end
|
92
94
|
else
|
93
95
|
overall_success = false
|
94
96
|
syntax_valid = false
|
95
97
|
failure_reason ||= 'workspace_tests_failed_or_syntax_error'
|
96
|
-
|
98
|
+
PresentationLogger.warn("Fixes applied but validation failed; skipping merge")
|
97
99
|
end
|
98
100
|
else
|
99
101
|
overall_success = false
|
@@ -105,7 +107,7 @@ module CodeHealer
|
|
105
107
|
ai_provider_for(evolution_method),
|
106
108
|
failure_reason
|
107
109
|
)
|
108
|
-
|
110
|
+
PresentationLogger.error("Failed to apply fixes in workspace")
|
109
111
|
end
|
110
112
|
ensure
|
111
113
|
# Persist timing metrics if captured
|
@@ -122,10 +124,12 @@ module CodeHealer
|
|
122
124
|
cleanup_workspace(workspace_path)
|
123
125
|
end
|
124
126
|
|
125
|
-
|
127
|
+
total_time = ((Time.now - start_time) * 1000).round
|
128
|
+
timing = "#{total_time}ms total"
|
129
|
+
PresentationLogger.outcome(success: overall_success, branch: healing_branch, pr_url: nil, reason: failure_reason, timing: timing)
|
126
130
|
rescue => e
|
127
|
-
|
128
|
-
|
131
|
+
PresentationLogger.error("Evolution Job Failed: #{e.message}")
|
132
|
+
PresentationLogger.detail("Backtrace: #{Array(e.backtrace).first(5).join("\n")}")
|
129
133
|
raise e # Re-raise to trigger Sidekiq retry
|
130
134
|
end
|
131
135
|
|
@@ -222,7 +226,7 @@ module CodeHealer
|
|
222
226
|
end
|
223
227
|
|
224
228
|
def create_healing_workspace(class_name, method_name)
|
225
|
-
|
229
|
+
PresentationLogger.detail("Preparing workspace for #{class_name}##{method_name}")
|
226
230
|
|
227
231
|
# Create persistent workspace and checkout to target branch
|
228
232
|
workspace_path = CodeHealer::HealingWorkspaceManager.create_healing_workspace(
|
@@ -230,12 +234,12 @@ module CodeHealer
|
|
230
234
|
CodeHealer::ConfigManager.pr_target_branch # Use configured target branch
|
231
235
|
)
|
232
236
|
|
233
|
-
|
237
|
+
PresentationLogger.detail("Workspace ready: #{workspace_path}")
|
234
238
|
workspace_path
|
235
239
|
end
|
236
240
|
|
237
241
|
def apply_fixes_in_workspace(workspace_path, error, class_name, method_name, evolution_method)
|
238
|
-
|
242
|
+
PresentationLogger.detail("Applying fixes in workspace #{workspace_path}")
|
239
243
|
|
240
244
|
case evolution_method
|
241
245
|
when 'claude_code_terminal'
|
@@ -251,13 +255,13 @@ module CodeHealer
|
|
251
255
|
end
|
252
256
|
handle_api_evolution_in_workspace(workspace_path, error, class_name, method_name)
|
253
257
|
else
|
254
|
-
|
258
|
+
PresentationLogger.error("Unknown evolution method: #{evolution_method}")
|
255
259
|
false
|
256
260
|
end
|
257
261
|
end
|
258
262
|
|
259
263
|
def handle_claude_code_evolution_in_workspace(workspace_path, error, class_name, method_name)
|
260
|
-
|
264
|
+
PresentationLogger.step("Claude Code Terminal evolution")
|
261
265
|
|
262
266
|
# Change to workspace directory for Claude Code operations
|
263
267
|
Dir.chdir(workspace_path) do
|
@@ -266,17 +270,17 @@ module CodeHealer
|
|
266
270
|
)
|
267
271
|
|
268
272
|
if success
|
269
|
-
|
273
|
+
PresentationLogger.success("Claude evolution succeeded")
|
270
274
|
true
|
271
275
|
else
|
272
|
-
|
276
|
+
PresentationLogger.error("Claude evolution failed")
|
273
277
|
false
|
274
278
|
end
|
275
279
|
end
|
276
280
|
end
|
277
281
|
|
278
282
|
def handle_api_evolution_in_workspace(workspace_path, error, class_name, method_name)
|
279
|
-
|
283
|
+
PresentationLogger.step("OpenAI API evolution")
|
280
284
|
|
281
285
|
# Load business context for API evolution
|
282
286
|
business_context = CodeHealer::BusinessContextManager.get_context_for_error(
|
@@ -286,7 +290,7 @@ module CodeHealer
|
|
286
290
|
# Optionally record business context used
|
287
291
|
# MetricsCollector.track_business_context(healing_id, business_context) # healing_id not accessible here
|
288
292
|
|
289
|
-
|
293
|
+
PresentationLogger.detail("Business context loaded for API evolution")
|
290
294
|
|
291
295
|
# Change to workspace directory for API operations
|
292
296
|
Dir.chdir(workspace_path) do
|
@@ -295,10 +299,10 @@ module CodeHealer
|
|
295
299
|
)
|
296
300
|
|
297
301
|
if success
|
298
|
-
|
302
|
+
PresentationLogger.success("API evolution succeeded")
|
299
303
|
true
|
300
304
|
else
|
301
|
-
|
305
|
+
PresentationLogger.error("API evolution failed")
|
302
306
|
false
|
303
307
|
end
|
304
308
|
end
|
@@ -307,7 +311,7 @@ module CodeHealer
|
|
307
311
|
def cleanup_workspace(workspace_path)
|
308
312
|
return unless workspace_path && Dir.exist?(workspace_path)
|
309
313
|
|
310
|
-
|
314
|
+
PresentationLogger.step("Cleaning up workspace")
|
311
315
|
CodeHealer::HealingWorkspaceManager.cleanup_workspace(workspace_path)
|
312
316
|
end
|
313
317
|
|