Class: EnhanceSwarm::AgentReviewer

Inherits:
Object
  • Object
show all
Defined in:
lib/enhance_swarm/agent_reviewer.rb

Class Method Summary collapse

Class Method Details

.categorize_tasks(review, results) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/enhance_swarm/agent_reviewer.rb', line 184

def self.categorize_tasks(review, results)
  review[:task_progress].each do |task, status|
    task_info = {
      task: task,
      worktree: review[:path],
      branch: review[:branch],
      status: status,
      last_activity: review[:last_activity]
    }

    case status
    when 'completed'
      results[:completed_tasks] << task_info
    when 'in_progress'
      results[:active_tasks] << task_info
    when 'blocked'
      results[:blocked_tasks] << task_info
    end
  end
end

.detect_issues(path, review) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/enhance_swarm/agent_reviewer.rb', line 130

def self.detect_issues(path, review)
  issues = []
  
  # Check for merge conflicts
  if review[:files_changed].any? { |f| f.start_with?('UU ') }
    issues << 'merge conflicts detected'
  end
  
  # Check for untracked important files
  untracked = review[:files_changed].select { |f| f.start_with?('?? ') }
  if untracked.any? { |f| f.include?('.rb') || f.include?('.js') || f.include?('.py') }
    issues << 'untracked source files'
  end

  # Check disk space
  begin
    stat = File.statvfs(path)
    free_gb = (stat.bavail * stat.frsize) / (1024 * 1024 * 1024)
    issues << "low disk space (#{free_gb}GB)" if free_gb < 1
  rescue
    # Not all platforms support statvfs
  end

  issues
end

.determine_worktree_status(review) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
# File 'lib/enhance_swarm/agent_reviewer.rb', line 118

def self.determine_worktree_status(review)
  return 'stale' if review[:last_activity] && review[:last_activity] < (Time.now - 3600) # 1 hour

  if review[:files_changed].any?
    'active'
  elsif review[:commits].any?
    'completed'
  else
    'initialized'
  end
end

.extract_task_progress(path) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/enhance_swarm/agent_reviewer.rb', line 156

def self.extract_task_progress(path)
  progress = {}
  
  # Look for task files
  task_files = Dir.glob(File.join(path, '.claude', 'tasks', '*.md'))
  task_files.each do |file|
    begin
      content = File.read(file)
      task_name = File.basename(file, '.md')
      
      # Simple progress extraction
      if content.include?('✅') || content.include?('completed')
        progress[task_name] = 'completed'
      elsif content.include?('🔄') || content.include?('in progress')
        progress[task_name] = 'in_progress'
      elsif content.include?('❌') || content.include?('blocked')
        progress[task_name] = 'blocked'
      else
        progress[task_name] = 'pending'
      end
    rescue
      # Ignore file read errors
    end
  end
  
  progress
end

.format_duration(seconds) ⇒ Object



273
274
275
276
277
278
279
280
281
# File 'lib/enhance_swarm/agent_reviewer.rb', line 273

def self.format_duration(seconds)
  if seconds < 60
    "#{seconds.to_i}s"
  elsif seconds < 3600
    "#{(seconds / 60).to_i}m"
  else
    "#{(seconds / 3600).to_i}h"
  end
end

.generate_summary(results) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
# File 'lib/enhance_swarm/agent_reviewer.rb', line 205

def self.generate_summary(results)
  {
    total_worktrees: results[:worktrees].count,
    active_worktrees: results[:worktrees].count { |w| w[:status] == 'active' },
    stale_worktrees: results[:worktrees].count { |w| w[:status] == 'stale' },
    completed_tasks: results[:completed_tasks].count,
    active_tasks: results[:active_tasks].count,
    blocked_tasks: results[:blocked_tasks].count,
    total_issues: results[:worktrees].sum { |w| w[:issues].count }
  }
end

.list_swarm_worktreesObject



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/enhance_swarm/agent_reviewer.rb', line 38

def self.list_swarm_worktrees
  output = CommandExecutor.execute('git', 'worktree', 'list', '--porcelain')
  worktrees = []
  current_worktree = {}

  output.split("\n").each do |line|
    case line
    when /^worktree (.+)/
      current_worktree[:path] = $1
    when /^branch (.+)/
      current_worktree[:branch] = $1
    when /^HEAD (.+)/
      current_worktree[:head] = $1
    when ''
      if current_worktree[:path]&.include?('swarm/')
        worktrees << current_worktree.dup
      end
      current_worktree.clear
    end
  end

  # Don't forget the last one
  if current_worktree[:path]&.include?('swarm/')
    worktrees << current_worktree
  end

  worktrees
end


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/enhance_swarm/agent_reviewer.rb', line 217

def self.print_review_report(results)
  puts "=== Agent Work Review ==="
  puts "Time: #{Time.parse(results[:timestamp]).strftime('%Y-%m-%d %H:%M:%S')}"
  puts
  
  summary = results[:summary]
  puts "📊 Summary:"
  puts "  Total worktrees: #{summary[:total_worktrees]}"
  puts "  Active: #{summary[:active_worktrees]}".colorize(:green)
  puts "  Stale: #{summary[:stale_worktrees]}".colorize(:yellow)
  puts
  
  puts "📋 Tasks:"
  puts "  Completed: #{summary[:completed_tasks]}".colorize(:green)
  puts "  Active: #{summary[:active_tasks]}".colorize(:blue)
  puts "  Blocked: #{summary[:blocked_tasks]}".colorize(:red)
  puts

  if results[:completed_tasks].any?
    puts "✅ Recently Completed:"
    results[:completed_tasks].each do |task|
      puts "  #{task[:task]} (#{task[:worktree]})"
    end
    puts
  end

  if results[:active_tasks].any?
    puts "🔄 Currently Active:"
    results[:active_tasks].each do |task|
      age = Time.now - task[:last_activity]
      puts "  #{task[:task]} (#{format_duration(age)} ago)"
    end
    puts
  end

  if results[:blocked_tasks].any?
    puts "❌ Blocked Tasks:"
    results[:blocked_tasks].each do |task|
      puts "  #{task[:task]} (#{task[:worktree]})".colorize(:red)
    end
    puts
  end

  # Show issues
  issues = results[:worktrees].flat_map { |w| w[:issues] }
  if issues.any?
    puts "⚠️  Issues Found:"
    issues.each { |issue| puts "  - #{issue}".colorize(:yellow) }
    puts
  end

  if summary[:stale_worktrees] > 0
    puts "💡 Suggestion: Run 'enhance-swarm cleanup --all' to clean stale worktrees"
  end
end

.review_all_workObject



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/enhance_swarm/agent_reviewer.rb', line 8

def self.review_all_work
  results = {
    timestamp: Time.now.iso8601,
    worktrees: [],
    completed_tasks: [],
    active_tasks: [],
    blocked_tasks: [],
    summary: {}
  }

  begin
    worktrees = list_swarm_worktrees
    Logger.info("Found #{worktrees.count} swarm worktrees to review")

    worktrees.each do |worktree|
      review = review_worktree(worktree)
      results[:worktrees] << review
      
      categorize_tasks(review, results)
    end

    results[:summary] = generate_summary(results)
    results
  rescue StandardError => e
    Logger.error("Failed to review agent work: #{e.message}")
    results[:error] = e.message
    results
  end
end

.review_worktree(worktree) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/enhance_swarm/agent_reviewer.rb', line 67

def self.review_worktree(worktree)
  review = {
    path: worktree[:path],
    branch: worktree[:branch],
    last_activity: nil,
    status: 'unknown',
    files_changed: [],
    commits: [],
    task_progress: {},
    issues: []
  }

  begin
    Dir.chdir(worktree[:path]) do
      # Get last activity
      begin
        last_commit = CommandExecutor.execute('git', 'log', '-1', '--format=%ci')
        review[:last_activity] = Time.parse(last_commit.strip)
      rescue
        review[:last_activity] = File.mtime(worktree[:path])
      end

      # Check status
      git_status = CommandExecutor.execute('git', 'status', '--porcelain')
      review[:files_changed] = git_status.split("\n").map(&:strip).reject(&:empty?)
      
      # Get recent commits
      begin
        commits_output = CommandExecutor.execute('git', 'log', '--oneline', '-5')
        review[:commits] = commits_output.split("\n").map(&:strip).reject(&:empty?)
      rescue
        # No commits yet
      end

      # Determine status
      review[:status] = determine_worktree_status(review)
      
      # Check for issues
      review[:issues] = detect_issues(worktree[:path], review)
      
      # Look for task progress indicators
      review[:task_progress] = extract_task_progress(worktree[:path])
    end
  rescue StandardError => e
    review[:status] = 'error'
    review[:issues] << "Failed to review: #{e.message}"
  end

  review
end