code_healer 0.1.5 โ 0.1.7
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 +15 -1
- data/lib/code_healer/healing_workspace_manager.rb +11 -4
- data/lib/code_healer/setup.rb +187 -57
- data/lib/code_healer/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb4a7ded404d0efca6e6e111b0186cc2bdeaef8a6eaf4041fd9799fcc447d044
|
4
|
+
data.tar.gz: 95f4317a52fa36bc1aae2923d497a01c282486de0680548a5e80ff1f15ff6468
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad4af34d619b3d1361a61b5dd5e7a285bb9cdc399b72d200209a84ce565f2e7740917878684e4b094254ba3fbc858765e4dc2af2a3d425dd8d343a71e180477e
|
7
|
+
data.tar.gz: 89b963d38d992791a738ff3ab91716939e39a1e8b84d056574bc6ffae504d66e6c192306ba28f5671efeec54967fa0eefca044e17121538055875a91875f4dbd
|
data/CHANGELOG.md
CHANGED
@@ -5,7 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
-
## [0.1.
|
8
|
+
## [0.1.7] - 2025-01-14
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
- **Git operations in isolated healing workspace** - Preserved .git directory during cloning for proper Git operations
|
12
|
+
- **Branch creation and commit operations** now work correctly in the isolated workspace
|
13
|
+
- **Workspace cleanup** properly removes .git directory to prevent conflicts
|
14
|
+
|
15
|
+
## [0.1.6] - 2025-01-14
|
16
|
+
|
17
|
+
### Added
|
18
|
+
- **Code heal directory permission validation** during interactive setup
|
19
|
+
- **Repository access testing** to ensure the directory can clone and push to the target repo
|
20
|
+
- **Write permission verification** for the code heal directory
|
21
|
+
- **Automatic directory creation** if it doesn't exist
|
22
|
+
- **Comprehensive error messages** with troubleshooting tips for permission issues
|
9
23
|
|
10
24
|
### Fixed
|
11
25
|
- **Duplicate HealingJob class definition** that was preventing isolated healing workspace system from working
|
@@ -161,6 +161,13 @@ module CodeHealer
|
|
161
161
|
|
162
162
|
return unless Dir.exist?(workspace_path)
|
163
163
|
|
164
|
+
# Remove .git directory first to avoid conflicts
|
165
|
+
git_dir = File.join(workspace_path, '.git')
|
166
|
+
if Dir.exist?(git_dir)
|
167
|
+
puts "๐งน [WORKSPACE] Removing .git directory to prevent conflicts..."
|
168
|
+
FileUtils.rm_rf(git_dir)
|
169
|
+
end
|
170
|
+
|
164
171
|
puts "๐งน [WORKSPACE] Removing workspace directory..."
|
165
172
|
FileUtils.rm_rf(workspace_path)
|
166
173
|
puts "๐งน [WORKSPACE] Workspace cleanup completed"
|
@@ -207,10 +214,9 @@ module CodeHealer
|
|
207
214
|
puts "๐ฟ [WORKSPACE] Clone result: #{result ? 'SUCCESS' : 'FAILED'}"
|
208
215
|
|
209
216
|
if result
|
210
|
-
puts "๐ฟ [WORKSPACE]
|
211
|
-
#
|
212
|
-
|
213
|
-
puts "๐ฟ [WORKSPACE] .git removed successfully"
|
217
|
+
puts "๐ฟ [WORKSPACE] Git repository preserved for healing operations"
|
218
|
+
# Keep .git for Git operations during healing
|
219
|
+
# We'll clean it up later in cleanup_workspace
|
214
220
|
else
|
215
221
|
puts "๐ฟ [WORKSPACE] Clone failed, checking workspace..."
|
216
222
|
puts "๐ฟ [WORKSPACE] Workspace exists: #{Dir.exist?(workspace_path)}"
|
@@ -237,6 +243,7 @@ module CodeHealer
|
|
237
243
|
checkout_result = system("git checkout #{current_branch}")
|
238
244
|
puts "๐ฟ [WORKSPACE] Checkout result: #{checkout_result ? 'SUCCESS' : 'FAILED'}"
|
239
245
|
end
|
246
|
+
puts "๐ฟ [WORKSPACE] Git repository preserved for healing operations"
|
240
247
|
else
|
241
248
|
puts "๐ฟ [WORKSPACE] Full repo clone failed"
|
242
249
|
end
|
data/lib/code_healer/setup.rb
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
require 'fileutils'
|
8
8
|
require 'yaml'
|
9
9
|
require 'optparse'
|
10
|
+
require 'octokit'
|
10
11
|
|
11
12
|
# Parse command line options
|
12
13
|
options = {}
|
@@ -88,6 +89,109 @@ def read_file_content(file_path)
|
|
88
89
|
File.read(file_path) if file_exists?(file_path)
|
89
90
|
end
|
90
91
|
|
92
|
+
def normalize_repository_url(repository_input, github_token = nil)
|
93
|
+
return nil if repository_input.nil?
|
94
|
+
input = repository_input.strip
|
95
|
+
return nil if input.empty?
|
96
|
+
|
97
|
+
# If it's already a URL, return as-is
|
98
|
+
if input.include?('://')
|
99
|
+
return input
|
100
|
+
end
|
101
|
+
|
102
|
+
# Build HTTPS URL from owner/repo
|
103
|
+
base = "https://github.com/#{input}.git"
|
104
|
+
return base if github_token.nil? || github_token.strip.empty?
|
105
|
+
|
106
|
+
# Embed token for validation clone only (do not log the token)
|
107
|
+
"https://#{github_token}@github.com/#{input}.git"
|
108
|
+
end
|
109
|
+
|
110
|
+
# Permission validation method
|
111
|
+
def validate_code_heal_directory_permissions(directory_path, repository_url, github_token = nil)
|
112
|
+
puts " ๐ Checking directory: #{directory_path}"
|
113
|
+
|
114
|
+
# Check if directory exists or can be created
|
115
|
+
begin
|
116
|
+
if Dir.exist?(directory_path)
|
117
|
+
puts " โ
Directory exists"
|
118
|
+
else
|
119
|
+
puts " ๐จ Creating directory..."
|
120
|
+
Dir.mkdir(directory_path)
|
121
|
+
puts " โ
Directory created successfully"
|
122
|
+
end
|
123
|
+
rescue => e
|
124
|
+
puts " โ Cannot create directory: #{e.message}"
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check write permissions
|
129
|
+
begin
|
130
|
+
test_file = File.join(directory_path, '.permission_test')
|
131
|
+
File.write(test_file, 'test')
|
132
|
+
File.delete(test_file)
|
133
|
+
puts " โ
Write permissions verified"
|
134
|
+
rescue => e
|
135
|
+
puts " โ Write permission failed: #{e.message}"
|
136
|
+
return false
|
137
|
+
end
|
138
|
+
|
139
|
+
# If we have a token and a repo, verify push permissions via GitHub API
|
140
|
+
if github_token && !github_token.strip.empty? && repository_url && !repository_url.strip.empty?
|
141
|
+
begin
|
142
|
+
client = Octokit::Client.new(access_token: github_token)
|
143
|
+
repo_full_name = if repository_url.include?('github.com')
|
144
|
+
path = repository_url.split('github.com/').last.to_s
|
145
|
+
path.sub(/\.git\z/, '')
|
146
|
+
else
|
147
|
+
repository_url
|
148
|
+
end
|
149
|
+
repo = client.repository(repo_full_name)
|
150
|
+
perms = (repo.respond_to?(:permissions) ? repo.permissions : repo[:permissions]) || {}
|
151
|
+
can_push = perms[:push] == true || perms['push'] == true
|
152
|
+
if can_push
|
153
|
+
puts " โ
GitHub token has push permission to #{repo_full_name}"
|
154
|
+
else
|
155
|
+
puts " โ ๏ธ GitHub token does not have push permission to #{repo_full_name}"
|
156
|
+
end
|
157
|
+
rescue => e
|
158
|
+
puts " โ ๏ธ Could not verify push permission via GitHub API: #{e.message}"
|
159
|
+
end
|
160
|
+
else
|
161
|
+
puts " โ ๏ธ Skipping GitHub push-permission check (missing token or repository)"
|
162
|
+
end
|
163
|
+
|
164
|
+
# Check if we can clone the repository (read access)
|
165
|
+
puts " ๐ Testing repository access..."
|
166
|
+
begin
|
167
|
+
require 'git'
|
168
|
+
require 'fileutils'
|
169
|
+
|
170
|
+
# Create a temporary test directory
|
171
|
+
test_dir = File.join(directory_path, 'test_clone_' + Time.now.to_i.to_s)
|
172
|
+
|
173
|
+
# Try to clone the repository
|
174
|
+
puts " ๐ฅ Attempting to clone repository..."
|
175
|
+
# Avoid printing token in logs
|
176
|
+
safe_url = repository_url.to_s.gsub(/:\/\/[A-Za-z0-9_\-]+@/, '://***@')
|
177
|
+
# Perform clone
|
178
|
+
Git.clone(repository_url, test_dir, depth: 1)
|
179
|
+
|
180
|
+
# Clean up test clone
|
181
|
+
FileUtils.rm_rf(test_dir)
|
182
|
+
puts " โ
Repository access verified (#{safe_url})"
|
183
|
+
|
184
|
+
return true
|
185
|
+
rescue => e
|
186
|
+
puts " โ Repository access failed: #{e.message}"
|
187
|
+
puts " ๐ก Make sure:"
|
188
|
+
puts " - Your GitHub token has repo access"
|
189
|
+
puts " - The repository URL is correct (e.g., https://github.com/owner/repo.git or owner/repo)"
|
190
|
+
puts " - You have network access to GitHub"
|
191
|
+
return false
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
91
195
|
# Main setup logic
|
92
196
|
puts "๐ฅ Welcome to CodeHealer Setup! ๐"
|
93
197
|
puts "=" * 50
|
@@ -119,7 +223,7 @@ else
|
|
119
223
|
puts "๐ Would add 'code_healer' to Gemfile"
|
120
224
|
else
|
121
225
|
File.write(gemfile_path, new_gemfile_content)
|
122
|
-
|
226
|
+
puts "โ
Added 'code_healer' to Gemfile"
|
123
227
|
end
|
124
228
|
end
|
125
229
|
|
@@ -145,7 +249,8 @@ puts "Get one at: https://github.com/settings/tokens"
|
|
145
249
|
puts
|
146
250
|
|
147
251
|
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):")
|
252
|
+
github_repo = ask_for_input("Enter your GitHub repository (username/repo or full URL):")
|
253
|
+
github_repo_url = normalize_repository_url(github_repo, github_token)
|
149
254
|
|
150
255
|
# Git Branch Configuration
|
151
256
|
puts
|
@@ -161,6 +266,29 @@ puts "CodeHealer will clone your current branch here before making fixes."
|
|
161
266
|
puts
|
162
267
|
|
163
268
|
code_heal_directory = ask_for_input("Enter code heal directory path (default: /tmp/code_healer_workspaces):", default: "/tmp/code_healer_workspaces")
|
269
|
+
|
270
|
+
# Validate code heal directory permissions
|
271
|
+
puts "๐ Validating code heal directory permissions..."
|
272
|
+
if github_repo_url && !github_repo_url.strip.empty?
|
273
|
+
if validate_code_heal_directory_permissions(code_heal_directory, github_repo_url, github_token)
|
274
|
+
puts "โ
Code heal directory permissions validated successfully!"
|
275
|
+
else
|
276
|
+
puts "โ Code heal directory permission validation failed!"
|
277
|
+
puts "Please ensure the directory has proper write permissions and can access the repository."
|
278
|
+
code_heal_directory = ask_for_input("Enter a different code heal directory path:", default: "/tmp/code_healer_workspaces")
|
279
|
+
|
280
|
+
# Retry validation
|
281
|
+
if validate_code_heal_directory_permissions(code_heal_directory, github_repo_url, github_token)
|
282
|
+
puts "โ
Code heal directory permissions validated successfully!"
|
283
|
+
else
|
284
|
+
puts "โ ๏ธ Permission validation failed again. You may need to fix permissions manually."
|
285
|
+
end
|
286
|
+
end
|
287
|
+
else
|
288
|
+
puts "โ ๏ธ Skipping repository access validation (no repository URL provided)"
|
289
|
+
puts " Directory permissions will be validated when you run the actual setup"
|
290
|
+
end
|
291
|
+
|
164
292
|
auto_cleanup = ask_for_yes_no("Automatically clean up healing workspaces after use?", default: true)
|
165
293
|
cleanup_after_hours = ask_for_input("Clean up workspaces after how many hours? (default: 24):", default: "24")
|
166
294
|
|
@@ -198,12 +326,12 @@ puts "๐ Step 3: Creating Configuration Files"
|
|
198
326
|
puts
|
199
327
|
|
200
328
|
# Create actual .env file (will be ignored by git)
|
201
|
-
env_content = <<~ENV
|
329
|
+
env_content = <<~ENV
|
202
330
|
# CodeHealer Configuration
|
203
|
-
|
331
|
+
# OpenAI Configuration
|
204
332
|
OPENAI_API_KEY=#{openai_key}
|
205
|
-
|
206
|
-
|
333
|
+
|
334
|
+
# GitHub Configuration
|
207
335
|
GITHUB_TOKEN=#{github_token}
|
208
336
|
GITHUB_REPOSITORY=#{github_repo}
|
209
337
|
|
@@ -214,81 +342,81 @@ ENV
|
|
214
342
|
create_file_with_content('.env', env_content, dry_run: options[:dry_run])
|
215
343
|
|
216
344
|
# Create code_healer.yml
|
217
|
-
config_content = <<~YAML
|
218
|
-
|
219
|
-
|
220
|
-
|
345
|
+
config_content = <<~YAML
|
346
|
+
# CodeHealer Configuration
|
347
|
+
enabled: true
|
348
|
+
|
221
349
|
# Allowed classes for healing (customize as needed)
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
350
|
+
allowed_classes:
|
351
|
+
- User
|
352
|
+
- Order
|
353
|
+
- PaymentProcessor
|
226
354
|
- OrderProcessor
|
227
|
-
|
355
|
+
|
228
356
|
# Excluded classes (never touch these)
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
357
|
+
excluded_classes:
|
358
|
+
- ApplicationController
|
359
|
+
- ApplicationRecord
|
360
|
+
- ApplicationJob
|
361
|
+
- ApplicationMailer
|
234
362
|
- ApplicationHelper
|
235
|
-
|
236
|
-
|
237
|
-
|
363
|
+
|
364
|
+
# Allowed error types for healing
|
365
|
+
allowed_error_types:
|
238
366
|
- ZeroDivisionError
|
239
367
|
- NoMethodError
|
240
|
-
|
368
|
+
- ArgumentError
|
241
369
|
- TypeError
|
242
|
-
|
243
|
-
|
244
|
-
|
370
|
+
- NameError
|
371
|
+
- ValidationError
|
372
|
+
|
245
373
|
# Evolution Strategy Configuration
|
246
|
-
|
374
|
+
evolution_strategy:
|
247
375
|
method: #{evolution_method} # Options: api, claude_code_terminal, hybrid
|
248
376
|
fallback_to_api: #{fallback_to_api} # If Claude Code fails, fall back to API
|
249
|
-
|
377
|
+
|
250
378
|
# Claude Code Terminal Configuration
|
251
|
-
|
379
|
+
claude_code:
|
252
380
|
enabled: #{evolution_method == 'claude_code_terminal' || evolution_method == 'hybrid'}
|
253
381
|
timeout: 300 # Timeout in seconds
|
254
|
-
|
255
|
-
|
382
|
+
max_file_changes: 10
|
383
|
+
include_tests: true
|
256
384
|
command_template: "claude --print '{prompt}' --output-format text --permission-mode acceptEdits --allowedTools Edit"
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
385
|
+
business_context_sources:
|
386
|
+
- "config/business_rules.yml"
|
387
|
+
- "docs/business_logic.md"
|
388
|
+
- "spec/business_context_specs.rb"
|
389
|
+
|
262
390
|
# Business Context Configuration
|
263
|
-
|
264
|
-
|
391
|
+
business_context:
|
392
|
+
enabled: true
|
265
393
|
sources:
|
266
394
|
- "docs/business_rules.md"
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
395
|
+
|
396
|
+
# OpenAI API configuration
|
397
|
+
api:
|
398
|
+
provider: openai
|
271
399
|
model: gpt-4
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
400
|
+
max_tokens: 2000
|
401
|
+
temperature: 0.1
|
402
|
+
|
403
|
+
# Git operations
|
404
|
+
git:
|
405
|
+
auto_commit: true
|
406
|
+
auto_push: true
|
279
407
|
branch_prefix: "#{branch_prefix}"
|
280
408
|
commit_message_template: 'Fix {{class_name}}\#\#{{method_name}}: {{error_type}}'
|
281
409
|
pr_target_branch: "#{pr_target_branch}"
|
282
410
|
|
283
411
|
# Pull Request Configuration
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
412
|
+
pull_request:
|
413
|
+
enabled: true
|
414
|
+
auto_create: true
|
415
|
+
labels:
|
416
|
+
- "auto-fix"
|
289
417
|
- "self-evolving"
|
290
|
-
|
291
|
-
|
418
|
+
- "bug-fix"
|
419
|
+
|
292
420
|
# Safety Configuration
|
293
421
|
safety:
|
294
422
|
backup_before_evolution: true
|
@@ -369,6 +497,8 @@ YAML
|
|
369
497
|
|
370
498
|
create_file_with_content('config/sidekiq.yml', sidekiq_config_content, dry_run: options[:dry_run])
|
371
499
|
|
500
|
+
# Permission validation method moved to top of file
|
501
|
+
|
372
502
|
# Final instructions
|
373
503
|
puts
|
374
504
|
if options[:dry_run]
|
data/lib/code_healer/version.rb
CHANGED