code_healer 0.1.3 โ†’ 0.1.6

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.
@@ -0,0 +1,296 @@
1
+ require 'fileutils'
2
+ require 'securerandom'
3
+
4
+ module CodeHealer
5
+ # Manages isolated healing workspaces for safe code evolution
6
+ class HealingWorkspaceManager
7
+ class << self
8
+ def create_healing_workspace(repo_path, branch_name = nil)
9
+ puts "๐Ÿฅ [WORKSPACE] Starting workspace creation..."
10
+ puts "๐Ÿฅ [WORKSPACE] Repo path: #{repo_path}"
11
+ puts "๐Ÿฅ [WORKSPACE] Branch name: #{branch_name || 'current'}"
12
+
13
+ config = CodeHealer::ConfigManager.code_heal_directory_config
14
+ puts "๐Ÿฅ [WORKSPACE] Raw config: #{config.inspect}"
15
+
16
+ base_path = config['path'] || config[:path] || '/tmp/code_healer_workspaces'
17
+ puts "๐Ÿฅ [WORKSPACE] Base heal dir: #{base_path}"
18
+
19
+ # Create unique workspace directory
20
+ workspace_id = "healing_#{Time.now.to_i}_#{SecureRandom.hex(4)}"
21
+ workspace_path = File.join(base_path, workspace_id)
22
+
23
+ puts "๐Ÿฅ [WORKSPACE] Workspace ID: #{workspace_id}"
24
+ puts "๐Ÿฅ [WORKSPACE] Full workspace path: #{workspace_path}"
25
+
26
+ begin
27
+ puts "๐Ÿฅ [WORKSPACE] Creating base directory..."
28
+ # Ensure code heal directory exists
29
+ FileUtils.mkdir_p(base_path)
30
+ puts "๐Ÿฅ [WORKSPACE] Base directory created/verified: #{base_path}"
31
+
32
+ # Clone current branch to workspace
33
+ strategy = clone_strategy
34
+ puts "๐Ÿฅ [WORKSPACE] Clone strategy: #{strategy}"
35
+
36
+ if strategy == "branch"
37
+ puts "๐Ÿฅ [WORKSPACE] Using branch-only cloning..."
38
+ clone_current_branch(repo_path, workspace_path, branch_name)
39
+ else
40
+ puts "๐Ÿฅ [WORKSPACE] Using full repo cloning..."
41
+ clone_full_repo(repo_path, workspace_path, branch_name)
42
+ end
43
+
44
+ puts "๐Ÿฅ [WORKSPACE] Workspace creation completed successfully!"
45
+ puts "๐Ÿฅ [WORKSPACE] Final workspace path: #{workspace_path}"
46
+ puts "๐Ÿฅ [WORKSPACE] Workspace contents: #{Dir.entries(workspace_path).join(', ')}"
47
+ workspace_path
48
+ rescue => e
49
+ puts "โŒ Failed to create healing workspace: #{e.message}"
50
+ cleanup_workspace(workspace_path) if Dir.exist?(workspace_path)
51
+ raise e
52
+ end
53
+ end
54
+
55
+ def apply_fixes_in_workspace(workspace_path, fixes, class_name, method_name)
56
+ puts "๐Ÿ”ง [WORKSPACE] Starting fix application..."
57
+ puts "๐Ÿ”ง [WORKSPACE] Workspace: #{workspace_path}"
58
+ puts "๐Ÿ”ง [WORKSPACE] Class: #{class_name}, Method: #{method_name}"
59
+ puts "๐Ÿ”ง [WORKSPACE] Fixes to apply: #{fixes.inspect}"
60
+
61
+ begin
62
+ puts "๐Ÿ”ง [WORKSPACE] Processing #{fixes.length} fixes..."
63
+ # Apply each fix to the workspace
64
+ fixes.each_with_index do |fix, index|
65
+ puts "๐Ÿ”ง [WORKSPACE] Processing fix #{index + 1}: #{fix.inspect}"
66
+ file_path = File.join(workspace_path, fix[:file_path])
67
+ puts "๐Ÿ”ง [WORKSPACE] Target file: #{file_path}"
68
+ puts "๐Ÿ”ง [WORKSPACE] File exists: #{File.exist?(file_path)}"
69
+
70
+ next unless File.exist?(file_path)
71
+
72
+ puts "๐Ÿ”ง [WORKSPACE] Creating backup..."
73
+ # Backup original file
74
+ backup_file(file_path)
75
+
76
+ puts "๐Ÿ”ง [WORKSPACE] Applying fix to file..."
77
+ # Apply the fix
78
+ apply_fix_to_file(file_path, fix[:new_code], class_name, method_name)
79
+ end
80
+
81
+ puts "โœ… Fixes applied successfully in workspace"
82
+ true
83
+ rescue => e
84
+ puts "โŒ Failed to apply fixes in workspace: #{e.message}"
85
+ false
86
+ end
87
+ end
88
+
89
+ def test_fixes_in_workspace(workspace_path)
90
+ config = CodeHealer::ConfigManager.code_heal_directory_config
91
+
92
+ puts "๐Ÿงช Testing fixes in workspace: #{workspace_path}"
93
+
94
+ begin
95
+ # Change to workspace directory
96
+ Dir.chdir(workspace_path) do
97
+ # Run basic syntax check
98
+ syntax_check = system("ruby -c #{find_ruby_files.join(' ')} 2>/dev/null")
99
+ return false unless syntax_check
100
+
101
+ # Run tests if available
102
+ if File.exist?('Gemfile')
103
+ bundle_check = system("bundle check >/dev/null 2>&1")
104
+ return false unless bundle_check
105
+
106
+ # Run tests if RSpec is available
107
+ if File.exist?('spec') || File.exist?('test')
108
+ test_result = system("bundle exec rspec --dry-run >/dev/null 2>&1") ||
109
+ system("bundle exec rake test:prepare >/dev/null 2>&1")
110
+ puts "๐Ÿงช Test preparation: #{test_result ? 'โœ…' : 'โš ๏ธ'}"
111
+ end
112
+ end
113
+
114
+ puts "โœ… Workspace validation passed"
115
+ true
116
+ end
117
+ rescue => e
118
+ puts "โŒ Workspace validation failed: #{e.message}"
119
+ false
120
+ end
121
+ end
122
+
123
+ def merge_fixes_back(repo_path, workspace_path, branch_name)
124
+ puts "๐Ÿ”„ Merging fixes back to main repository"
125
+
126
+ begin
127
+ # Create healing branch in main repo
128
+ Dir.chdir(repo_path) do
129
+ # Ensure we're on the target branch
130
+ system("git checkout #{branch_name}")
131
+ system("git pull origin #{branch_name}")
132
+
133
+ # Create healing branch
134
+ healing_branch = "code-healer-fix-#{Time.now.to_i}"
135
+ system("git checkout -b #{healing_branch}")
136
+
137
+ # Copy fixed files from workspace
138
+ copy_fixed_files(workspace_path, repo_path)
139
+
140
+ # Commit changes
141
+ system("git add .")
142
+ commit_message = "Fix applied by CodeHealer: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
143
+ system("git commit -m '#{commit_message}'")
144
+
145
+ # Push branch
146
+ system("git push origin #{healing_branch}")
147
+
148
+ puts "โœ… Healing branch created: #{healing_branch}"
149
+ healing_branch
150
+ end
151
+ rescue => e
152
+ puts "โŒ Failed to merge fixes back: #{e.message}"
153
+ nil
154
+ end
155
+ end
156
+
157
+ def cleanup_workspace(workspace_path)
158
+ puts "๐Ÿงน [WORKSPACE] Starting workspace cleanup..."
159
+ puts "๐Ÿงน [WORKSPACE] Target: #{workspace_path}"
160
+ puts "๐Ÿงน [WORKSPACE] Exists: #{Dir.exist?(workspace_path)}"
161
+
162
+ return unless Dir.exist?(workspace_path)
163
+
164
+ puts "๐Ÿงน [WORKSPACE] Removing workspace directory..."
165
+ FileUtils.rm_rf(workspace_path)
166
+ puts "๐Ÿงน [WORKSPACE] Workspace cleanup completed"
167
+ puts "๐Ÿงน [WORKSPACE] Directory still exists: #{Dir.exist?(workspace_path)}"
168
+ end
169
+
170
+ def cleanup_expired_workspaces
171
+ config = CodeHealer::ConfigManager.code_heal_directory_config
172
+ auto_cleanup = config['auto_cleanup']
173
+ auto_cleanup = config[:auto_cleanup] if auto_cleanup.nil?
174
+ return unless auto_cleanup
175
+
176
+ puts "๐Ÿงน Cleaning up expired healing workspaces"
177
+
178
+ base_path = config['path'] || config[:path] || '/tmp/code_healer_workspaces'
179
+ Dir.glob(File.join(base_path, "healing_*")).each do |workspace_path|
180
+ next unless Dir.exist?(workspace_path)
181
+
182
+ # Check if workspace is expired
183
+ hours = config['cleanup_after_hours'] || config[:cleanup_after_hours]
184
+ hours = hours.to_i if hours
185
+ if workspace_expired?(workspace_path, hours)
186
+ cleanup_workspace(workspace_path)
187
+ end
188
+ end
189
+ end
190
+
191
+ private
192
+
193
+ def clone_strategy
194
+ cfg = CodeHealer::ConfigManager.code_heal_directory_config
195
+ cfg['clone_strategy'] || cfg[:clone_strategy] || "branch"
196
+ end
197
+
198
+ def clone_current_branch(repo_path, workspace_path, branch_name)
199
+ puts "๐ŸŒฟ [WORKSPACE] Starting branch cloning..."
200
+ Dir.chdir(repo_path) do
201
+ current_branch = branch_name || `git branch --show-current`.strip
202
+ puts "๐ŸŒฟ [WORKSPACE] Current branch: #{current_branch}"
203
+ puts "๐ŸŒฟ [WORKSPACE] Executing: git clone --single-branch --branch #{current_branch} #{repo_path} #{workspace_path}"
204
+
205
+ # Clone only the current branch
206
+ result = system("git clone --single-branch --branch #{current_branch} #{repo_path} #{workspace_path}")
207
+ puts "๐ŸŒฟ [WORKSPACE] Clone result: #{result ? 'SUCCESS' : 'FAILED'}"
208
+
209
+ if result
210
+ puts "๐ŸŒฟ [WORKSPACE] Removing .git to avoid conflicts..."
211
+ # Remove .git to avoid conflicts
212
+ FileUtils.rm_rf(File.join(workspace_path, '.git'))
213
+ puts "๐ŸŒฟ [WORKSPACE] .git removed successfully"
214
+ else
215
+ puts "๐ŸŒฟ [WORKSPACE] Clone failed, checking workspace..."
216
+ puts "๐ŸŒฟ [WORKSPACE] Workspace exists: #{Dir.exist?(workspace_path)}"
217
+ puts "๐ŸŒฟ [WORKSPACE] Workspace contents: #{Dir.exist?(workspace_path) ? Dir.entries(workspace_path).join(', ') : 'N/A'}"
218
+ end
219
+ end
220
+ end
221
+
222
+ def clone_full_repo(repo_path, workspace_path, branch_name)
223
+ puts "๐ŸŒฟ [WORKSPACE] Starting full repo cloning..."
224
+ Dir.chdir(repo_path) do
225
+ current_branch = branch_name || `git branch --show-current`.strip
226
+ puts "๐ŸŒฟ [WORKSPACE] Target branch: #{current_branch}"
227
+ puts "๐ŸŒฟ [WORKSPACE] Executing: git clone #{repo_path} #{workspace_path}"
228
+
229
+ # Clone full repo
230
+ result = system("git clone #{repo_path} #{workspace_path}")
231
+ puts "๐ŸŒฟ [WORKSPACE] Clone result: #{result ? 'SUCCESS' : 'FAILED'}"
232
+
233
+ if result
234
+ puts "๐ŸŒฟ [WORKSPACE] Switching to branch: #{current_branch}"
235
+ # Switch to specific branch
236
+ Dir.chdir(workspace_path) do
237
+ checkout_result = system("git checkout #{current_branch}")
238
+ puts "๐ŸŒฟ [WORKSPACE] Checkout result: #{checkout_result ? 'SUCCESS' : 'FAILED'}"
239
+ end
240
+ else
241
+ puts "๐ŸŒฟ [WORKSPACE] Full repo clone failed"
242
+ end
243
+ end
244
+ end
245
+
246
+ def backup_file(file_path)
247
+ backup_path = "#{file_path}.code_healer_backup"
248
+ FileUtils.cp(file_path, backup_path)
249
+ end
250
+
251
+ def apply_fix_to_file(file_path, new_code, class_name, method_name)
252
+ content = File.read(file_path)
253
+
254
+ # Find and replace the method
255
+ method_pattern = /def\s+#{Regexp.escape(method_name)}\s*\([^)]*\)(.*?)end/m
256
+ if content.match(method_pattern)
257
+ content.gsub!(method_pattern, new_code)
258
+ File.write(file_path, content)
259
+ puts "โœ… Applied fix to #{File.basename(file_path)}##{method_name}"
260
+ else
261
+ puts "โš ๏ธ Could not find method #{method_name} in #{File.basename(file_path)}"
262
+ end
263
+ end
264
+
265
+ def find_ruby_files
266
+ Dir.glob("**/*.rb")
267
+ end
268
+
269
+ def copy_fixed_files(workspace_path, repo_path)
270
+ # Copy all Ruby files from workspace to repo
271
+ Dir.glob(File.join(workspace_path, "**/*.rb")).each do |workspace_file|
272
+ relative_path = workspace_file.sub(workspace_path + "/", "")
273
+ repo_file = File.join(repo_path, relative_path)
274
+
275
+ if File.exist?(repo_file)
276
+ FileUtils.cp(workspace_file, repo_file)
277
+ puts "๐Ÿ“ Copied fixed file: #{relative_path}"
278
+ end
279
+ end
280
+ end
281
+
282
+ def workspace_expired?(workspace_path, hours)
283
+ return false unless hours && hours > 0
284
+
285
+ # Extract timestamp from workspace name
286
+ if workspace_path =~ /healing_(\d+)/
287
+ timestamp = $1.to_i
288
+ age_hours = (Time.now.to_i - timestamp) / 3600
289
+ age_hours > hours
290
+ else
291
+ false
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end
@@ -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
- puts "โœ… Added 'code_healer' to Gemfile"
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
@@ -153,6 +258,40 @@ puts "๐ŸŒฟ Git Branch Configuration:"
153
258
  branch_prefix = ask_for_input("Enter branch prefix for healing branches (default: evolve):", default: "evolve")
154
259
  pr_target_branch = ask_for_input("Enter target branch for pull requests (default: main):", default: "main")
155
260
 
261
+ # Code Heal Directory Configuration
262
+ puts
263
+ puts "๐Ÿฅ Code Heal Directory Configuration:"
264
+ puts "This directory will store isolated copies of your code for safe healing."
265
+ puts "CodeHealer will clone your current branch here before making fixes."
266
+ puts
267
+
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
+
292
+ auto_cleanup = ask_for_yes_no("Automatically clean up healing workspaces after use?", default: true)
293
+ cleanup_after_hours = ask_for_input("Clean up workspaces after how many hours? (default: 24):", default: "24")
294
+
156
295
  # Business Context
157
296
  puts
158
297
  puts "๐Ÿ’ผ Business Context Setup:"
@@ -187,12 +326,12 @@ puts "๐Ÿ“ Step 3: Creating Configuration Files"
187
326
  puts
188
327
 
189
328
  # Create actual .env file (will be ignored by git)
190
- env_content = <<~ENV
329
+ env_content = <<~ENV
191
330
  # CodeHealer Configuration
192
- # OpenAI Configuration
331
+ # OpenAI Configuration
193
332
  OPENAI_API_KEY=#{openai_key}
194
-
195
- # GitHub Configuration
333
+
334
+ # GitHub Configuration
196
335
  GITHUB_TOKEN=#{github_token}
197
336
  GITHUB_REPOSITORY=#{github_repo}
198
337
 
@@ -203,81 +342,81 @@ ENV
203
342
  create_file_with_content('.env', env_content, dry_run: options[:dry_run])
204
343
 
205
344
  # Create code_healer.yml
206
- config_content = <<~YAML
207
- # CodeHealer Configuration
208
- enabled: true
209
-
345
+ config_content = <<~YAML
346
+ # CodeHealer Configuration
347
+ enabled: true
348
+
210
349
  # Allowed classes for healing (customize as needed)
211
- allowed_classes:
212
- - User
213
- - Order
214
- - PaymentProcessor
350
+ allowed_classes:
351
+ - User
352
+ - Order
353
+ - PaymentProcessor
215
354
  - OrderProcessor
216
-
355
+
217
356
  # Excluded classes (never touch these)
218
- excluded_classes:
219
- - ApplicationController
220
- - ApplicationRecord
221
- - ApplicationJob
222
- - ApplicationMailer
357
+ excluded_classes:
358
+ - ApplicationController
359
+ - ApplicationRecord
360
+ - ApplicationJob
361
+ - ApplicationMailer
223
362
  - ApplicationHelper
224
-
225
- # Allowed error types for healing
226
- allowed_error_types:
363
+
364
+ # Allowed error types for healing
365
+ allowed_error_types:
227
366
  - ZeroDivisionError
228
367
  - NoMethodError
229
- - ArgumentError
368
+ - ArgumentError
230
369
  - TypeError
231
- - NameError
232
- - ValidationError
233
-
370
+ - NameError
371
+ - ValidationError
372
+
234
373
  # Evolution Strategy Configuration
235
- evolution_strategy:
374
+ evolution_strategy:
236
375
  method: #{evolution_method} # Options: api, claude_code_terminal, hybrid
237
376
  fallback_to_api: #{fallback_to_api} # If Claude Code fails, fall back to API
238
-
377
+
239
378
  # Claude Code Terminal Configuration
240
- claude_code:
379
+ claude_code:
241
380
  enabled: #{evolution_method == 'claude_code_terminal' || evolution_method == 'hybrid'}
242
381
  timeout: 300 # Timeout in seconds
243
- max_file_changes: 10
244
- include_tests: true
382
+ max_file_changes: 10
383
+ include_tests: true
245
384
  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
-
385
+ business_context_sources:
386
+ - "config/business_rules.yml"
387
+ - "docs/business_logic.md"
388
+ - "spec/business_context_specs.rb"
389
+
251
390
  # Business Context Configuration
252
- business_context:
253
- enabled: true
391
+ business_context:
392
+ enabled: true
254
393
  sources:
255
394
  - "docs/business_rules.md"
256
-
257
- # OpenAI API configuration
258
- api:
259
- provider: openai
395
+
396
+ # OpenAI API configuration
397
+ api:
398
+ provider: openai
260
399
  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
400
+ max_tokens: 2000
401
+ temperature: 0.1
402
+
403
+ # Git operations
404
+ git:
405
+ auto_commit: true
406
+ auto_push: true
268
407
  branch_prefix: "#{branch_prefix}"
269
408
  commit_message_template: 'Fix {{class_name}}\#\#{{method_name}}: {{error_type}}'
270
409
  pr_target_branch: "#{pr_target_branch}"
271
410
 
272
411
  # Pull Request Configuration
273
- pull_request:
274
- enabled: true
275
- auto_create: true
276
- labels:
277
- - "auto-fix"
412
+ pull_request:
413
+ enabled: true
414
+ auto_create: true
415
+ labels:
416
+ - "auto-fix"
278
417
  - "self-evolving"
279
- - "bug-fix"
280
-
418
+ - "bug-fix"
419
+
281
420
  # Safety Configuration
282
421
  safety:
283
422
  backup_before_evolution: true
@@ -297,6 +436,14 @@ config_content = <<~YAML
297
436
  max_concurrent_healing: 3
298
437
  healing_timeout: 300
299
438
  retry_attempts: 3
439
+
440
+ # Code Heal Directory Configuration
441
+ code_heal_directory:
442
+ path: "#{code_heal_directory}"
443
+ auto_cleanup: #{auto_cleanup}
444
+ cleanup_after_hours: #{cleanup_after_hours}
445
+ max_workspaces: 10
446
+ clone_strategy: "branch" # Options: branch, full_repo
300
447
  YAML
301
448
 
302
449
  create_file_with_content('config/code_healer.yml', config_content, dry_run: options[:dry_run])
@@ -350,6 +497,8 @@ YAML
350
497
 
351
498
  create_file_with_content('config/sidekiq.yml', sidekiq_config_content, dry_run: options[:dry_run])
352
499
 
500
+ # Permission validation method moved to top of file
501
+
353
502
  # Final instructions
354
503
  puts
355
504
  if options[:dry_run]
@@ -366,14 +515,19 @@ else
366
515
  puts "4. Start your Rails server: rails s"
367
516
  puts
368
517
  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"
518
+ puts " - .env file contains your actual API keys and is ignored by git"
519
+ puts " - .env.example is safe to commit and shows the required format"
520
+ puts " - Never commit .env files with real secrets to version control"
521
+ puts
522
+ puts "๐Ÿฅ Code Heal Directory:"
523
+ puts " - Your code will be cloned to: #{code_heal_directory}"
524
+ puts " - This ensures safe, isolated healing without affecting your running server"
525
+ puts " - Workspaces are automatically cleaned up after #{cleanup_after_hours} hours"
526
+ puts
527
+ puts "โš™๏ธ Configuration:"
528
+ puts " - code_healer.yml contains comprehensive settings with sensible defaults"
529
+ puts " - Customize the configuration file as needed for your project"
530
+ puts " - All features are pre-configured and ready to use"
377
531
  puts
378
532
  puts "๐ŸŒ Environment Variables:"
379
533
  puts " - Add 'gem \"dotenv-rails\"' to your Gemfile for automatic .env loading"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CodeHealer
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.6"
5
5
  end
data/lib/code_healer.rb CHANGED
@@ -21,6 +21,7 @@ autoload :BusinessContextManager, "code_healer/business_context_manager"
21
21
  autoload :ClaudeCodeEvolutionHandler, "code_healer/claude_code_evolution_handler"
22
22
  autoload :SimpleHealer, "code_healer/simple_healer"
23
23
  autoload :HealingJob, "code_healer/healing_job"
24
+ autoload :HealingWorkspaceManager, "code_healer/healing_workspace_manager"
24
25
  autoload :PullRequestCreator, "code_healer/pull_request_creator"
25
26
  autoload :McpServer, "code_healer/mcp_server"
26
27
  autoload :McpTools, "code_healer/mcp_tools"