enhance_swarm 1.0.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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.enhance_swarm/agent_scripts/frontend_agent.md +39 -0
  3. data/.enhance_swarm/user_patterns.json +37 -0
  4. data/CHANGELOG.md +184 -0
  5. data/LICENSE +21 -0
  6. data/PRODUCTION_TEST_LOG.md +502 -0
  7. data/README.md +905 -0
  8. data/Rakefile +28 -0
  9. data/USAGE_EXAMPLES.md +477 -0
  10. data/examples/enhance_workflow.md +346 -0
  11. data/examples/rails_project.md +253 -0
  12. data/exe/enhance-swarm +30 -0
  13. data/lib/enhance_swarm/additional_commands.rb +299 -0
  14. data/lib/enhance_swarm/agent_communicator.rb +460 -0
  15. data/lib/enhance_swarm/agent_reviewer.rb +283 -0
  16. data/lib/enhance_swarm/agent_spawner.rb +462 -0
  17. data/lib/enhance_swarm/cleanup_manager.rb +245 -0
  18. data/lib/enhance_swarm/cli.rb +1592 -0
  19. data/lib/enhance_swarm/command_executor.rb +78 -0
  20. data/lib/enhance_swarm/configuration.rb +324 -0
  21. data/lib/enhance_swarm/control_agent.rb +307 -0
  22. data/lib/enhance_swarm/dependency_validator.rb +195 -0
  23. data/lib/enhance_swarm/error_recovery.rb +785 -0
  24. data/lib/enhance_swarm/generator.rb +194 -0
  25. data/lib/enhance_swarm/interrupt_handler.rb +512 -0
  26. data/lib/enhance_swarm/logger.rb +106 -0
  27. data/lib/enhance_swarm/mcp_integration.rb +85 -0
  28. data/lib/enhance_swarm/monitor.rb +28 -0
  29. data/lib/enhance_swarm/notification_manager.rb +444 -0
  30. data/lib/enhance_swarm/orchestrator.rb +313 -0
  31. data/lib/enhance_swarm/output_streamer.rb +281 -0
  32. data/lib/enhance_swarm/process_monitor.rb +266 -0
  33. data/lib/enhance_swarm/progress_tracker.rb +215 -0
  34. data/lib/enhance_swarm/project_analyzer.rb +612 -0
  35. data/lib/enhance_swarm/resource_manager.rb +177 -0
  36. data/lib/enhance_swarm/retry_handler.rb +40 -0
  37. data/lib/enhance_swarm/session_manager.rb +247 -0
  38. data/lib/enhance_swarm/signal_handler.rb +95 -0
  39. data/lib/enhance_swarm/smart_defaults.rb +708 -0
  40. data/lib/enhance_swarm/task_integration.rb +150 -0
  41. data/lib/enhance_swarm/task_manager.rb +174 -0
  42. data/lib/enhance_swarm/version.rb +5 -0
  43. data/lib/enhance_swarm/visual_dashboard.rb +555 -0
  44. data/lib/enhance_swarm/web_ui.rb +211 -0
  45. data/lib/enhance_swarm.rb +69 -0
  46. data/setup.sh +86 -0
  47. data/sig/enhance_swarm.rbs +4 -0
  48. data/templates/claude/CLAUDE.md +160 -0
  49. data/templates/claude/MCP.md +117 -0
  50. data/templates/claude/PERSONAS.md +114 -0
  51. data/templates/claude/RULES.md +221 -0
  52. data/test_builtin_functionality.rb +121 -0
  53. data/test_core_components.rb +156 -0
  54. data/test_real_claude_integration.rb +285 -0
  55. data/test_security.rb +150 -0
  56. data/test_smart_defaults.rb +155 -0
  57. data/test_task_integration.rb +173 -0
  58. data/test_web_ui.rb +245 -0
  59. data/web/assets/css/main.css +645 -0
  60. data/web/assets/js/kanban.js +499 -0
  61. data/web/assets/js/main.js +525 -0
  62. data/web/templates/dashboard.html.erb +226 -0
  63. data/web/templates/kanban.html.erb +193 -0
  64. metadata +293 -0
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'shellwords'
5
+ require 'timeout'
6
+
7
+ module EnhanceSwarm
8
+ class CommandExecutor
9
+ class CommandError < StandardError
10
+ attr_reader :exit_status, :stderr
11
+
12
+ def initialize(message, exit_status: nil, stderr: nil)
13
+ super(message)
14
+ @exit_status = exit_status
15
+ @stderr = stderr
16
+ end
17
+ end
18
+
19
+ def self.execute(command, *args, timeout: 30, input: nil)
20
+ # Sanitize command and arguments
21
+ safe_command = sanitize_command(command)
22
+ safe_args = args.map { |arg| sanitize_argument(arg) }
23
+
24
+ begin
25
+ Timeout.timeout(timeout) do
26
+ stdout, stderr, status = Open3.capture3(safe_command, *safe_args,
27
+ stdin_data: input)
28
+
29
+ unless status.success?
30
+ raise CommandError.new(
31
+ "Command failed: #{safe_command} #{safe_args.join(' ')}",
32
+ exit_status: status.exitstatus,
33
+ stderr: stderr
34
+ )
35
+ end
36
+
37
+ stdout.strip
38
+ end
39
+ rescue Timeout::Error
40
+ raise CommandError.new("Command timed out after #{timeout} seconds")
41
+ rescue Errno::ENOENT
42
+ raise CommandError.new("Command not found: #{safe_command}")
43
+ end
44
+ end
45
+
46
+ def self.execute_async(command, *args)
47
+ safe_command = sanitize_command(command)
48
+ safe_args = args.map { |arg| sanitize_argument(arg) }
49
+
50
+ begin
51
+ pid = Process.spawn(safe_command, *safe_args)
52
+ Process.detach(pid)
53
+ pid
54
+ rescue Errno::ENOENT
55
+ raise CommandError.new("Command not found: #{safe_command}")
56
+ end
57
+ end
58
+
59
+ def self.command_available?(command)
60
+ execute('which', command, timeout: 5)
61
+ true
62
+ rescue CommandError
63
+ false
64
+ end
65
+
66
+ def self.sanitize_command(command)
67
+ # Only allow alphanumeric, dash, underscore, and slash
68
+ raise ArgumentError, "Invalid command: #{command}" unless command.match?(%r{\A[a-zA-Z0-9_\-/]+\z})
69
+
70
+ command
71
+ end
72
+
73
+ def self.sanitize_argument(arg)
74
+ # Convert to string and escape shell metacharacters
75
+ Shellwords.escape(arg.to_s)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,324 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'psych'
4
+ require_relative 'project_analyzer'
5
+
6
+ module EnhanceSwarm
7
+ class Configuration
8
+ attr_accessor :project_name, :project_description, :technology_stack,
9
+ :test_command, :task_command, :task_move_command,
10
+ :code_standards, :important_notes,
11
+ :max_concurrent_agents, :monitor_interval,
12
+ :monitor_timeout, :worktree_enabled,
13
+ :mcp_tools, :gemini_enabled, :desktop_commander_enabled,
14
+ :max_memory_mb, :max_disk_mb
15
+
16
+ def initialize
17
+ # Apply smart defaults from project analysis if no config exists
18
+ if config_file_exists?
19
+ apply_hardcoded_defaults
20
+ load_from_file
21
+ else
22
+ apply_smart_defaults
23
+ end
24
+ end
25
+
26
+ def to_h
27
+ {
28
+ project: {
29
+ name: @project_name,
30
+ description: @project_description,
31
+ technology_stack: @technology_stack
32
+ },
33
+ commands: {
34
+ test: @test_command,
35
+ task: @task_command,
36
+ task_move: @task_move_command
37
+ },
38
+ orchestration: {
39
+ max_concurrent_agents: @max_concurrent_agents,
40
+ monitor_interval: @monitor_interval,
41
+ monitor_timeout: @monitor_timeout,
42
+ worktree_enabled: @worktree_enabled
43
+ },
44
+ mcp: {
45
+ tools: @mcp_tools,
46
+ gemini_enabled: @gemini_enabled,
47
+ desktop_commander_enabled: @desktop_commander_enabled
48
+ },
49
+ standards: {
50
+ code: @code_standards,
51
+ notes: @important_notes
52
+ }
53
+ }
54
+ end
55
+
56
+ def save!
57
+ File.write(config_file_path, Psych.dump(to_h))
58
+ end
59
+
60
+ private
61
+
62
+ def apply_hardcoded_defaults
63
+ # Project defaults
64
+ @project_name = 'Project'
65
+ @project_description = 'A project managed by EnhanceSwarm'
66
+ @technology_stack = 'Ruby on Rails'
67
+
68
+ # Commands
69
+ @test_command = 'bundle exec rails test'
70
+ @task_command = 'bundle exec swarm-tasks'
71
+ @task_move_command = 'bundle exec swarm-tasks move'
72
+
73
+ # Standards
74
+ @code_standards = default_code_standards
75
+ @important_notes = []
76
+
77
+ # Orchestration settings
78
+ @max_concurrent_agents = 4
79
+ @monitor_interval = 30
80
+ @monitor_timeout = 120 # 2 minutes max per monitoring session
81
+ @worktree_enabled = true
82
+
83
+ # Resource limits
84
+ @max_memory_mb = 2048 # 2GB max memory for all agents
85
+ @max_disk_mb = 1024 # 1GB max disk usage
86
+
87
+ # MCP settings
88
+ @mcp_tools = {
89
+ context7: true,
90
+ sequential: true,
91
+ magic_ui: true,
92
+ puppeteer: true
93
+ }
94
+ @gemini_enabled = true
95
+ @desktop_commander_enabled = true
96
+ end
97
+
98
+ def apply_smart_defaults
99
+ Logger.info("No configuration file found, applying smart defaults based on project analysis")
100
+
101
+ # Analyze the current project
102
+ analyzer = ProjectAnalyzer.new
103
+ analyzer.analyze
104
+ smart_defaults = analyzer.generate_smart_defaults
105
+
106
+ # Apply smart defaults with fallbacks
107
+ @project_name = smart_defaults[:project_name] || File.basename(Dir.pwd)
108
+ @project_description = smart_defaults[:project_description] || 'A project managed by EnhanceSwarm'
109
+ @technology_stack = smart_defaults[:technology_stack]&.join(', ') || 'Multiple Technologies'
110
+
111
+ # Smart command detection
112
+ @test_command = smart_defaults[:test_command] || detect_test_command_fallback
113
+ @task_command = 'bundle exec swarm-tasks'
114
+ @task_move_command = 'bundle exec swarm-tasks move'
115
+
116
+ # Code standards based on project type
117
+ @code_standards = generate_smart_code_standards(analyzer.analysis_results[:project_type])
118
+ @important_notes = generate_smart_notes(analyzer.analysis_results)
119
+
120
+ # Orchestration settings based on project size
121
+ @max_concurrent_agents = smart_defaults[:max_concurrent_agents] || 3
122
+ @monitor_interval = 30
123
+ @monitor_timeout = 120
124
+ @worktree_enabled = true
125
+
126
+ # MCP settings - enable all by default for smart detection
127
+ @mcp_tools = {
128
+ context7: true,
129
+ sequential: true,
130
+ magic_ui: analyzer.analysis_results[:frontend_framework] ? true : false,
131
+ puppeteer: analyzer.analysis_results[:testing_framework]&.any? { |f| f.include?('Cypress') || f.include?('Playwright') } || false
132
+ }
133
+ @gemini_enabled = true
134
+ @desktop_commander_enabled = smart_defaults[:has_documentation] || false
135
+
136
+ Logger.info("Applied smart defaults for #{@project_name} (#{@technology_stack})")
137
+ end
138
+
139
+ def detect_test_command_fallback
140
+ return 'bundle exec rspec' if File.exist?('spec')
141
+ return 'bundle exec rails test' if File.exist?('test')
142
+ return 'npm test' if File.exist?('package.json')
143
+ return 'pytest' if File.exist?('pytest.ini') || File.exist?('conftest.py')
144
+
145
+ 'echo "No test command configured"'
146
+ end
147
+
148
+ def generate_smart_code_standards(project_type)
149
+ base_standards = [
150
+ 'Follow framework conventions',
151
+ 'Write tests for all new features',
152
+ 'Use clear, descriptive naming'
153
+ ]
154
+
155
+ case project_type
156
+ when 'rails'
157
+ base_standards + [
158
+ 'Use service objects for business logic',
159
+ 'Keep controllers thin',
160
+ 'Use strong validations in models'
161
+ ]
162
+ when 'react', 'vue', 'angular', 'nextjs'
163
+ base_standards + [
164
+ 'Use functional components with hooks',
165
+ 'Implement proper state management',
166
+ 'Optimize for performance and accessibility'
167
+ ]
168
+ when 'django', 'flask'
169
+ base_standards + [
170
+ 'Follow MVC patterns',
171
+ 'Use proper authentication and authorization',
172
+ 'Implement comprehensive API documentation'
173
+ ]
174
+ else
175
+ base_standards + [
176
+ 'Maintain consistent code style',
177
+ 'Document complex logic',
178
+ 'Use version control best practices'
179
+ ]
180
+ end
181
+ end
182
+
183
+ def generate_smart_notes(analysis_results)
184
+ notes = []
185
+
186
+ if analysis_results[:documentation]&.dig(:has_docs)
187
+ notes << "Project has documentation in #{analysis_results[:documentation][:primary_path]} - consider this context for changes"
188
+ end
189
+
190
+ if analysis_results[:testing_framework]&.any?
191
+ frameworks = analysis_results[:testing_framework].join(', ')
192
+ notes << "Testing framework(s) detected: #{frameworks} - ensure new features include tests"
193
+ end
194
+
195
+ if analysis_results[:deployment]&.any?
196
+ deployments = analysis_results[:deployment].join(', ')
197
+ notes << "Deployment configurations found: #{deployments} - consider deployment impact for changes"
198
+ end
199
+
200
+ if analysis_results[:database]&.any?
201
+ databases = analysis_results[:database].join(', ')
202
+ notes << "Database(s) in use: #{databases} - consider data migration needs"
203
+ end
204
+
205
+ notes
206
+ end
207
+
208
+ def config_file_path
209
+ File.join(EnhanceSwarm.root, '.enhance_swarm.yml')
210
+ end
211
+
212
+ def config_file_exists?
213
+ File.exist?(config_file_path)
214
+ end
215
+
216
+ def load_from_file
217
+ config = Psych.safe_load(File.read(config_file_path), permitted_classes: [Symbol])
218
+
219
+ # Project settings with validation
220
+ @project_name = validate_string(config.dig('project', 'name')) || @project_name
221
+ @project_description = validate_string(config.dig('project', 'description')) || @project_description
222
+ @technology_stack = validate_string(config.dig('project', 'technology_stack')) || @technology_stack
223
+
224
+ # Commands with validation
225
+ @test_command = validate_command(config.dig('commands', 'test')) || @test_command
226
+ @task_command = validate_command(config.dig('commands', 'task')) || @task_command
227
+ @task_move_command = validate_command(config.dig('commands', 'task_move')) || @task_move_command
228
+
229
+ # Orchestration with validation
230
+ @max_concurrent_agents = validate_positive_integer(config.dig('orchestration',
231
+ 'max_concurrent_agents')) || @max_concurrent_agents
232
+ @monitor_interval = validate_positive_integer(config.dig('orchestration',
233
+ 'monitor_interval')) || @monitor_interval
234
+ @monitor_timeout = validate_positive_integer(config.dig('orchestration', 'monitor_timeout')) || @monitor_timeout
235
+ @worktree_enabled = config.dig('orchestration', 'worktree_enabled') != false
236
+
237
+ # MCP
238
+ @mcp_tools = validate_hash(config.dig('mcp', 'tools')) || @mcp_tools
239
+ @gemini_enabled = config.dig('mcp', 'gemini_enabled') != false
240
+ @desktop_commander_enabled = config.dig('mcp', 'desktop_commander_enabled') != false
241
+
242
+ # Standards
243
+ @code_standards = validate_array(config.dig('standards', 'code')) || @code_standards
244
+ @important_notes = validate_array(config.dig('standards', 'notes')) || @important_notes
245
+ rescue Psych::SyntaxError => e
246
+ puts "Configuration file has invalid YAML syntax: #{e.message}"
247
+ # Use defaults
248
+ rescue StandardError => e
249
+ puts "Error loading configuration: #{e.message}"
250
+ # Use defaults
251
+ end
252
+
253
+ def default_code_standards
254
+ [
255
+ 'Follow framework conventions',
256
+ 'Use service objects for business logic',
257
+ 'Keep controllers thin',
258
+ 'Write tests for all new features',
259
+ 'Use strong validations in models'
260
+ ]
261
+ end
262
+
263
+ # Validation methods
264
+ def validate_string(value)
265
+ return nil unless value.is_a?(String)
266
+
267
+ # Remove dangerous characters
268
+ sanitized = value.gsub(/[`$\\;|&]/, '').strip
269
+ sanitized.empty? ? nil : sanitized
270
+ end
271
+
272
+ def validate_command(value)
273
+ return nil unless value.is_a?(String)
274
+
275
+ # Only allow safe command characters
276
+ sanitized = value.gsub(/[;|&`$\\]/, '').strip
277
+ return nil if sanitized.empty?
278
+
279
+ # Check for common dangerous patterns but allow 'exec' in normal contexts
280
+ dangerous_patterns = [/\brm\s+-rf/, /\|\s*sh\b/, /\beval\s*\(/, /\bexec\s*\(/]
281
+ dangerous_patterns.each do |pattern|
282
+ return nil if sanitized.match?(pattern)
283
+ end
284
+
285
+ sanitized
286
+ end
287
+
288
+ def validate_positive_integer(value)
289
+ return nil unless value.is_a?(Integer) || (value.is_a?(String) && value.match?(/\A\d+\z/))
290
+
291
+ int_value = value.to_i
292
+ int_value.positive? ? int_value : nil
293
+ end
294
+
295
+ def validate_array(value)
296
+ return nil unless value.is_a?(Array)
297
+
298
+ # Validate each element as a string
299
+ validated = value.map { |item| validate_string(item) }.compact
300
+ validated.empty? ? nil : validated
301
+ end
302
+
303
+ def validate_hash(value)
304
+ return nil unless value.is_a?(Hash)
305
+
306
+ # Ensure all keys are strings or symbols and values are safe
307
+ validated = {}
308
+ value.each do |k, v|
309
+ next unless k.is_a?(String) || k.is_a?(Symbol)
310
+
311
+ validated[k] = case v
312
+ when String
313
+ validate_string(v)
314
+ when TrueClass, FalseClass
315
+ v
316
+ when Integer
317
+ validate_positive_integer(v)
318
+ end
319
+ end
320
+
321
+ validated.empty? ? nil : validated
322
+ end
323
+ end
324
+ end
@@ -0,0 +1,307 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'tempfile'
5
+
6
+ module EnhanceSwarm
7
+ class ControlAgent
8
+ attr_reader :task, :config, :status, :worker_agents, :start_time
9
+
10
+ def initialize(task_description, config = nil)
11
+ @task = task_description
12
+ @config = config || EnhanceSwarm.configuration
13
+ @status = 'initializing'
14
+ @worker_agents = {}
15
+ @start_time = Time.now
16
+ @communication_file = create_communication_file
17
+ @control_process = nil
18
+ end
19
+
20
+ def start_coordination
21
+ Logger.info("Starting Control Agent for task: #{@task}")
22
+ @status = 'starting'
23
+
24
+ # Spawn the Control Agent as a Claude process
25
+ spawn_control_agent
26
+
27
+ # Monitor and coordinate
28
+ coordinate_agents
29
+ end
30
+
31
+ def stop_coordination
32
+ Logger.info("Stopping Control Agent coordination")
33
+ @status = 'stopping'
34
+
35
+ # Terminate control agent process
36
+ if @control_process
37
+ begin
38
+ Process.kill('TERM', @control_process)
39
+ Process.wait(@control_process)
40
+ rescue Errno::ESRCH, Errno::ECHILD
41
+ # Process already terminated
42
+ end
43
+ end
44
+
45
+ # Cleanup
46
+ cleanup_resources
47
+ end
48
+
49
+ def current_status
50
+ return default_status unless File.exist?(@communication_file)
51
+
52
+ begin
53
+ content = File.read(@communication_file)
54
+ return default_status if content.strip.empty?
55
+
56
+ # Parse the latest status update from Control Agent
57
+ lines = content.split("\n").reject(&:empty?)
58
+ latest_status = lines.last
59
+
60
+ JSON.parse(latest_status)
61
+ rescue JSON::ParserError, StandardError => e
62
+ Logger.warn("Failed to parse control agent status: #{e.message}")
63
+ default_status
64
+ end
65
+ end
66
+
67
+ def worker_agent_summary
68
+ status = current_status
69
+ {
70
+ total: status['active_agents'].length + status['completed_agents'].length,
71
+ active: status['active_agents'].length,
72
+ completed: status['completed_agents'].length,
73
+ progress: status['progress_percentage'] || 0,
74
+ phase: status['phase'] || 'unknown',
75
+ estimated_completion: status['estimated_completion']
76
+ }
77
+ end
78
+
79
+ private
80
+
81
+ def spawn_control_agent
82
+ prompt = build_control_agent_prompt
83
+
84
+ # Create a temporary prompt file
85
+ prompt_file = Tempfile.new(['control_prompt', '.txt'])
86
+ prompt_file.write(prompt)
87
+ prompt_file.close
88
+
89
+ begin
90
+ # Spawn Control Agent using claude command
91
+ @control_process = RetryHandler.with_retry(max_retries: 2) do
92
+ CommandExecutor.execute_async(
93
+ 'claude',
94
+ '--role=control',
95
+ '--file', prompt_file.path,
96
+ '--output', @communication_file,
97
+ '--continuous'
98
+ )
99
+ end
100
+
101
+ Logger.info("Control Agent spawned with PID: #{@control_process}")
102
+ @status = 'coordinating'
103
+
104
+ rescue RetryHandler::RetryError, CommandExecutor::CommandError => e
105
+ Logger.error("Failed to spawn Control Agent: #{e.message}")
106
+ @status = 'failed'
107
+ raise
108
+ ensure
109
+ prompt_file.unlink
110
+ end
111
+ end
112
+
113
+ def coordinate_agents
114
+ coordination_thread = Thread.new do
115
+ while @status == 'coordinating'
116
+ begin
117
+ # Read latest status from Control Agent
118
+ agent_status = current_status
119
+
120
+ # Update our internal state
121
+ update_worker_agents(agent_status)
122
+
123
+ # Check if coordination is complete
124
+ if agent_status['status'] == 'completed'
125
+ @status = 'completed'
126
+ break
127
+ elsif agent_status['status'] == 'failed'
128
+ @status = 'failed'
129
+ break
130
+ end
131
+
132
+ sleep(5) # Check every 5 seconds
133
+
134
+ rescue StandardError => e
135
+ Logger.error("Control Agent coordination error: #{e.message}")
136
+ sleep(10) # Back off on errors
137
+ end
138
+ end
139
+
140
+ Logger.info("Control Agent coordination finished with status: #{@status}")
141
+ end
142
+
143
+ coordination_thread
144
+ end
145
+
146
+ def update_worker_agents(agent_status)
147
+ # Track active agents
148
+ agent_status['active_agents']&.each do |agent_id|
149
+ unless @worker_agents[agent_id]
150
+ @worker_agents[agent_id] = {
151
+ id: agent_id,
152
+ status: 'active',
153
+ start_time: Time.now
154
+ }
155
+ end
156
+ end
157
+
158
+ # Track completed agents
159
+ agent_status['completed_agents']&.each do |agent_id|
160
+ if @worker_agents[agent_id]
161
+ @worker_agents[agent_id][:status] = 'completed'
162
+ @worker_agents[agent_id][:completion_time] = Time.now
163
+ end
164
+ end
165
+ end
166
+
167
+ def build_control_agent_prompt
168
+ <<~PROMPT
169
+ AUTONOMOUS CONTROL AGENT - MULTI-AGENT COORDINATION
170
+
171
+ TASK: #{@task}
172
+
173
+ YOUR ROLE: You are a Control Agent responsible for coordinating multiple worker agents to complete this task efficiently. You have full autonomous authority to make decisions and spawn agents.
174
+
175
+ CAPABILITIES:
176
+ 1. Spawn worker agents using: claude-swarm start --role=<role> -p "<specific_task>"
177
+ 2. Monitor progress via git commands: git status, git log, git diff
178
+ 3. Analyze file changes and commits to understand progress
179
+ 4. Make handoff decisions based on dependencies and completion status
180
+ 5. Coordinate timing to prevent conflicts
181
+
182
+ WORKER AGENT ROLES:
183
+ - backend: Models, APIs, database, business logic, migrations, services
184
+ - frontend: Controllers, views, JavaScript, CSS, user interface, forms
185
+ - ux: User experience design, templates, layouts, styling, wireframes
186
+ - qa: Testing, specs, edge cases, quality assurance, validation
187
+
188
+ COORDINATION STRATEGY:
189
+ 1. Analyze the task to determine which roles are needed
190
+ 2. Identify dependencies (typically: backend → frontend → qa)
191
+ 3. Spawn agents in dependency order
192
+ 4. Monitor their progress via git commits and file changes
193
+ 5. Signal next agent when prerequisites are met
194
+ 6. Handle conflicts and coordination issues
195
+
196
+ COMMUNICATION PROTOCOL:
197
+ You MUST output status updates in JSON format to #{@communication_file}
198
+ Update every 30 seconds with current status.
199
+
200
+ Required JSON format:
201
+ {
202
+ "status": "coordinating|completed|failed",
203
+ "phase": "analysis|backend_implementation|frontend_integration|qa_validation|completion",
204
+ "active_agents": ["agent-id-1", "agent-id-2"],
205
+ "completed_agents": ["agent-id-3"],
206
+ "failed_agents": [],
207
+ "progress_percentage": 45,
208
+ "estimated_completion": "2025-06-28T20:30:00Z",
209
+ "message": "Backend agent completed auth model, starting frontend integration",
210
+ "next_actions": ["spawn_frontend_agent", "monitor_integration_conflicts"],
211
+ "dependencies_met": ["backend_models_complete"],
212
+ "blocking_issues": []
213
+ }
214
+
215
+ CRITICAL INSTRUCTIONS:
216
+ 1. You have FULL PERMISSION to execute commands and spawn agents
217
+ 2. Work directory: #{Dir.pwd}
218
+ 3. Start immediately by analyzing the task and creating an execution plan
219
+ 4. Spawn the first agent(s) based on dependencies
220
+ 5. Continuously monitor and coordinate until task completion
221
+ 6. Handle errors gracefully and retry failed operations
222
+ 7. Ensure all agents complete successfully before marking task complete
223
+
224
+ PROJECT CONTEXT:
225
+ - Technology stack: #{Array(@config.technology_stack).join(', ')}
226
+ - Test command: #{@config.test_command}
227
+ - Project type: #{@config.project_name}
228
+
229
+ BEGIN COORDINATION NOW.
230
+ PROMPT
231
+ end
232
+
233
+ def create_communication_file
234
+ # Create a temporary file for Control Agent communication
235
+ temp_file = Tempfile.new(['control_agent_status', '.json'])
236
+ temp_file.close
237
+ temp_file.path
238
+ end
239
+
240
+ def default_status
241
+ {
242
+ 'status' => @status,
243
+ 'phase' => 'initializing',
244
+ 'active_agents' => [],
245
+ 'completed_agents' => [],
246
+ 'failed_agents' => [],
247
+ 'progress_percentage' => 0,
248
+ 'message' => 'Control Agent initializing...',
249
+ 'estimated_completion' => nil
250
+ }
251
+ end
252
+
253
+ def cleanup_resources
254
+ # Clean up communication file
255
+ File.unlink(@communication_file) if File.exist?(@communication_file)
256
+ rescue StandardError => e
257
+ Logger.warn("Failed to cleanup Control Agent resources: #{e.message}")
258
+ end
259
+
260
+ # Class methods for easy usage
261
+ def self.coordinate_task(task_description, config: nil)
262
+ control_agent = new(task_description, config)
263
+
264
+ begin
265
+ coordination_thread = control_agent.start_coordination
266
+
267
+ # Return control agent for monitoring
268
+ yield control_agent if block_given?
269
+
270
+ # Wait for coordination to complete
271
+ coordination_thread.join if coordination_thread
272
+
273
+ control_agent.current_status
274
+ ensure
275
+ control_agent.stop_coordination
276
+ end
277
+ end
278
+
279
+ # Enhanced progress tracking integration
280
+ def track_progress_with_streamer(streamer = nil)
281
+ return unless streamer
282
+
283
+ Thread.new do
284
+ while @status == 'coordinating'
285
+ status = current_status
286
+
287
+ # Update progress tracker
288
+ progress = status['progress_percentage'] || 0
289
+ message = status['message'] || 'Coordinating agents...'
290
+
291
+ streamer.set_progress(progress,
292
+ message: message,
293
+ operation: 'control_coordination',
294
+ details: {
295
+ phase: status['phase'],
296
+ active_agents: status['active_agents']&.length || 0,
297
+ completed_agents: status['completed_agents']&.length || 0
298
+ })
299
+
300
+ break if %w[completed failed].include?(status['status'])
301
+
302
+ sleep(2)
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end