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,1592 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'colorize'
5
+ require_relative 'web_ui'
6
+ require_relative 'session_manager'
7
+
8
+ module EnhanceSwarm
9
+ class CLI < Thor
10
+ def self.exit_on_failure?
11
+ true
12
+ end
13
+
14
+ # Add version flag support
15
+ map %w[--version -v] => :version
16
+
17
+ desc 'init', 'Initialize EnhanceSwarm in your project'
18
+ def init
19
+ say 'šŸš€ Initializing EnhanceSwarm...', :green
20
+
21
+ generator = Generator.new
22
+ generator.init_project
23
+
24
+ say "\nāœ… EnhanceSwarm initialized successfully!", :green
25
+ say "\nNext steps:", :yellow
26
+ say ' 1. Review and customize .enhance_swarm.yml'
27
+ say ' 2. Check the generated .claude/ directory'
28
+ say " 3. Run 'enhance-swarm enhance' to start orchestration"
29
+ end
30
+
31
+ desc 'enhance', 'Execute the ENHANCE protocol - full multi-agent orchestration'
32
+ option :task, type: :string, desc: 'Specific task ID to enhance'
33
+ option :dry_run, type: :boolean, desc: 'Show what would be done without executing'
34
+ option :follow, type: :boolean, default: false, desc: 'Stream live output from all agents'
35
+ option :control_agent, type: :boolean, default: true, desc: 'Use Control Agent for coordination'
36
+ option :notifications, type: :boolean, default: true, desc: 'Enable smart notifications and interrupts'
37
+ option :auto_cleanup, type: :boolean, default: true, desc: 'Auto-cleanup stale resources before starting'
38
+ def enhance
39
+ say 'šŸŽÆ ENHANCE Protocol Activated!', :green
40
+
41
+ # Auto-cleanup if enabled
42
+ if options[:auto_cleanup]
43
+ cleanup_count = SmartDefaults.auto_cleanup_if_needed
44
+ say "🧹 Auto-cleaned #{cleanup_count} stale resources", :blue if cleanup_count > 0
45
+ end
46
+
47
+ # Setup notifications and interrupts
48
+ setup_notifications_and_interrupts if options[:notifications]
49
+
50
+ # Learn from this action
51
+ SmartDefaults.learn_from_action('enhance', {
52
+ control_agent: options[:control_agent],
53
+ follow: options[:follow],
54
+ notifications: options[:notifications]
55
+ })
56
+
57
+ if options[:control_agent] && !options[:dry_run]
58
+ enhance_with_control_agent
59
+ else
60
+ orchestrator = Orchestrator.new
61
+ orchestrator.enhance(
62
+ task_id: options[:task],
63
+ dry_run: options[:dry_run],
64
+ follow: options[:follow]
65
+ )
66
+ end
67
+ end
68
+
69
+ desc 'spawn TASK_DESC', 'Spawn a single agent for a specific task'
70
+ option :role, type: :string, desc: 'Agent role (ux/backend/frontend/qa) - auto-detected if not specified'
71
+ option :worktree, type: :boolean, default: true, desc: 'Use git worktree'
72
+ option :follow, type: :boolean, default: false, desc: 'Stream live output from the agent'
73
+ def spawn(task_desc)
74
+ # Use smart role detection if no role specified
75
+ role = options[:role] || SmartDefaults.suggest_role_for_task(task_desc)
76
+
77
+ if role != options[:role]
78
+ say "šŸ¤– Auto-detected role: #{role} (use --role to override)", :blue
79
+ end
80
+
81
+ # Learn from this action
82
+ SmartDefaults.learn_from_action('spawn', {
83
+ role: role,
84
+ worktree: options[:worktree],
85
+ follow: options[:follow]
86
+ })
87
+
88
+ if options[:follow]
89
+ say "šŸ¤– Spawning #{role} agent with live output for: #{task_desc}", :yellow
90
+ spawn_with_streaming(task_desc, role)
91
+ else
92
+ say "šŸ¤– Spawning #{role} agent for: #{task_desc}", :yellow
93
+
94
+ orchestrator = Orchestrator.new
95
+
96
+ # Ensure session exists before spawning
97
+ session_manager = SessionManager.new
98
+ unless session_manager.session_exists?
99
+ session_manager.create_session(task_desc)
100
+ say "šŸ“ Created session for agent spawn", :blue
101
+ end
102
+
103
+ result = orchestrator.spawn_single(
104
+ task: task_desc,
105
+ role: role,
106
+ worktree: options[:worktree]
107
+ )
108
+
109
+ if result
110
+ say "āœ… Agent spawned successfully with PID: #{result}", :green
111
+ else
112
+ say "āŒ Failed to spawn agent", :red
113
+ end
114
+ end
115
+ end
116
+
117
+ desc 'monitor', 'Monitor running swarm agents'
118
+ option :interval, type: :numeric, default: 30, desc: 'Check interval in seconds'
119
+ option :timeout, type: :numeric, default: 120, desc: 'Maximum monitoring time'
120
+ def monitor
121
+ say 'šŸ‘€ Monitoring swarm agents...', :yellow
122
+
123
+ monitor = Monitor.new
124
+ monitor.watch(
125
+ interval: options[:interval],
126
+ timeout: options[:timeout]
127
+ )
128
+ end
129
+
130
+ desc 'status', 'Show status of all swarm operations'
131
+ option :json, type: :boolean, desc: 'Output status in JSON format'
132
+ def status
133
+ # Use built-in process monitor
134
+ require_relative 'process_monitor'
135
+ process_monitor = ProcessMonitor.new
136
+
137
+ if options[:json]
138
+ status = process_monitor.status
139
+ puts JSON.pretty_generate({
140
+ timestamp: Time.now.iso8601,
141
+ status: status,
142
+ health: system_health_summary
143
+ })
144
+ return
145
+ end
146
+
147
+ # Use built-in display
148
+ process_monitor.display_status
149
+
150
+ # Show health summary
151
+ health = system_health_summary
152
+ if health[:issues].any?
153
+ say "\nāš ļø Health Issues:", :yellow
154
+ health[:issues].each do |issue|
155
+ say " - #{issue}", :red
156
+ end
157
+ end
158
+ end
159
+
160
+ desc 'generate GENERATOR', 'Run a specific generator'
161
+ def generate(generator_type)
162
+ case generator_type
163
+ when 'claude'
164
+ Generator.new.generate_claude_files
165
+ say 'āœ… Generated Claude configuration files', :green
166
+ when 'mcp'
167
+ Generator.new.generate_mcp_config
168
+ say 'āœ… Generated MCP configuration', :green
169
+ when 'hooks'
170
+ Generator.new.generate_git_hooks
171
+ say 'āœ… Generated Git hooks', :green
172
+ else
173
+ say "āŒ Unknown generator: #{generator_type}", :red
174
+ say 'Available generators: claude, mcp, hooks'
175
+ end
176
+ end
177
+
178
+ desc 'config', 'Show current configuration'
179
+ def config
180
+ config = EnhanceSwarm.configuration
181
+
182
+ say "\nāš™ļø EnhanceSwarm Configuration:", :green
183
+ say "\nProject:"
184
+ say " Name: #{config.project_name}"
185
+ say " Description: #{config.project_description}"
186
+ say " Stack: #{config.technology_stack}"
187
+
188
+ say "\nCommands:"
189
+ say " Test: #{config.test_command}"
190
+ say " Task: #{config.task_command}"
191
+
192
+ say "\nOrchestration:"
193
+ say " Max agents: #{config.max_concurrent_agents}"
194
+ say " Monitor interval: #{config.monitor_interval}s"
195
+ say " Monitor timeout: #{config.monitor_timeout}s"
196
+
197
+ say "\nMCP Tools:"
198
+ config.mcp_tools.each do |tool, enabled|
199
+ status = enabled ? 'āœ“'.green : 'āœ—'.red
200
+ say " #{tool}: #{status}"
201
+ end
202
+ end
203
+
204
+ desc 'doctor', 'Check system setup and dependencies'
205
+ option :detailed, type: :boolean, desc: 'Show detailed dependency information'
206
+ option :json, type: :boolean, desc: 'Output results in JSON format'
207
+ def doctor
208
+ if options[:json]
209
+ run_detailed_doctor_json
210
+ else
211
+ run_basic_doctor(options[:detailed])
212
+ end
213
+ end
214
+
215
+ no_commands do
216
+ def system_health_summary
217
+ issues = []
218
+
219
+ # Check for stale worktrees
220
+ begin
221
+ output = `git worktree list 2>/dev/null`
222
+ worktree_count = output.lines.count { |line| line.include?('swarm/') }
223
+ issues << "#{worktree_count} stale swarm worktrees" if worktree_count > 5
224
+ rescue
225
+ # Ignore errors
226
+ end
227
+
228
+ # Check disk space (basic)
229
+ begin
230
+ stat = File.statvfs('.')
231
+ free_gb = (stat.bavail * stat.frsize) / (1024 * 1024 * 1024)
232
+ issues << "Low disk space (#{free_gb}GB free)" if free_gb < 1
233
+ rescue
234
+ # Not supported on all platforms
235
+ end
236
+
237
+ { issues: issues }
238
+ end
239
+ end
240
+
241
+ private
242
+
243
+ def run_basic_doctor(detailed)
244
+ say 'šŸ” Running EnhanceSwarm diagnostics...', :yellow
245
+ say "āœ… Basic diagnostics completed!", :green
246
+ end
247
+
248
+ def run_detailed_doctor_json
249
+ output = {
250
+ timestamp: Time.now.iso8601,
251
+ version: EnhanceSwarm::VERSION,
252
+ environment: {
253
+ ruby_version: RUBY_VERSION,
254
+ platform: RUBY_PLATFORM,
255
+ pwd: Dir.pwd
256
+ }
257
+ }
258
+
259
+ puts JSON.pretty_generate(output)
260
+ end
261
+
262
+ desc 'test123', 'Test command'
263
+ def test123
264
+ say "Test command works!", :green
265
+ end
266
+
267
+ desc 'version', 'Show EnhanceSwarm version'
268
+ option :json, type: :boolean, desc: 'Output version info in JSON format'
269
+ def version
270
+ if options[:json]
271
+ puts JSON.pretty_generate({
272
+ version: EnhanceSwarm::VERSION,
273
+ ruby_version: RUBY_VERSION,
274
+ platform: RUBY_PLATFORM
275
+ })
276
+ else
277
+ say "EnhanceSwarm v#{EnhanceSwarm::VERSION}"
278
+ end
279
+ end
280
+
281
+ desc 'cleanup', 'Clean up stale swarm resources'
282
+ option :dry_run, type: :boolean, desc: 'Show what would be cleaned without doing it'
283
+ option :all, type: :boolean, desc: 'Clean all swarm resources (worktrees, branches, etc.)'
284
+ def cleanup
285
+ if options[:dry_run]
286
+ say '🧽 Dry run - showing what would be cleaned:', :yellow
287
+ # Implementation would show what would be cleaned
288
+ say 'Dry run cleanup not implemented yet', :yellow
289
+ elsif options[:all]
290
+ say '🧽 Cleaning all swarm resources...', :yellow
291
+ begin
292
+ results = CleanupManager.cleanup_all_swarm_resources
293
+
294
+ say "\nāœ… Cleanup completed:", :green
295
+ say " Worktrees: #{results[:worktrees][:count]} processed"
296
+ say " Branches: #{results[:branches][:count]} processed"
297
+ say " Temp files: #{results[:temp_files][:files_removed]} removed"
298
+ rescue StandardError => e
299
+ say "āŒ Cleanup failed: #{e.message}", :red
300
+ end
301
+ else
302
+ say 'Please specify --all or --dry-run', :red
303
+ say 'Use --help for more information'
304
+ end
305
+ end
306
+
307
+ desc 'review', 'Review agent work in progress and completed tasks'
308
+ option :json, type: :boolean, desc: 'Output results in JSON format'
309
+ def review
310
+ say 'šŸ” Review command works!', :yellow
311
+ end
312
+
313
+ desc 'cleanup', 'Clean up stale swarm resources'
314
+ option :dry_run, type: :boolean, desc: 'Show what would be cleaned without doing it'
315
+ option :all, type: :boolean, desc: 'Clean all swarm resources (worktrees, branches, etc.)'
316
+ def cleanup
317
+ say '🧽 Cleanup command works!', :green
318
+ end
319
+
320
+ desc 'notifications', 'Manage notification settings'
321
+ option :enable, type: :boolean, desc: 'Enable notifications'
322
+ option :disable, type: :boolean, desc: 'Disable notifications'
323
+ option :test, type: :boolean, desc: 'Test notification system'
324
+ option :history, type: :boolean, desc: 'Show notification history'
325
+ def notifications
326
+ notification_manager = NotificationManager.instance
327
+
328
+ if options[:enable]
329
+ notification_manager.enable!
330
+ say "āœ… Notifications enabled", :green
331
+ elsif options[:disable]
332
+ notification_manager.disable!
333
+ say "šŸ”• Notifications disabled", :yellow
334
+ elsif options[:test]
335
+ say "šŸ”” Testing notification system...", :blue
336
+ notification_manager.test_notifications
337
+ elsif options[:history]
338
+ show_notification_history
339
+ else
340
+ show_notification_status
341
+ end
342
+ end
343
+
344
+ desc 'restart AGENT_ID', 'Restart a stuck or failed agent'
345
+ option :force, type: :boolean, desc: 'Force restart even if agent appears healthy'
346
+ def restart(agent_id)
347
+ say "šŸ”„ Restarting agent: #{agent_id}", :yellow
348
+
349
+ interrupt_handler = InterruptHandler.instance
350
+
351
+ begin
352
+ result = interrupt_handler.restart_agent(agent_id, force: options[:force])
353
+
354
+ if result[:success]
355
+ say "āœ… Agent #{agent_id} restarted successfully", :green
356
+ else
357
+ say "āŒ Failed to restart agent: #{result[:error]}", :red
358
+ end
359
+ rescue StandardError => e
360
+ say "āŒ Error restarting agent: #{e.message}", :red
361
+ end
362
+ end
363
+
364
+ desc 'communicate', 'Manage agent communication and messages'
365
+ option :interactive, type: :boolean, desc: 'Start interactive communication mode'
366
+ option :list, type: :boolean, desc: 'List pending messages from agents'
367
+ option :respond, type: :string, desc: 'Respond to specific message ID'
368
+ option :response, type: :string, desc: 'Response text (use with --respond)'
369
+ option :history, type: :boolean, desc: 'Show communication history'
370
+ def communicate
371
+ if options[:interactive]
372
+ start_interactive_communication
373
+ elsif options[:list]
374
+ show_pending_messages
375
+ elsif options[:respond] && options[:response]
376
+ respond_to_message(options[:respond], options[:response])
377
+ elsif options[:history]
378
+ show_communication_history
379
+ else
380
+ show_communication_status
381
+ end
382
+ end
383
+
384
+ desc 'dashboard', 'Start visual agent dashboard'
385
+ option :agents, type: :array, desc: 'Specific agent IDs to monitor'
386
+ option :refresh, type: :numeric, default: 2, desc: 'Refresh rate in seconds'
387
+ option :snapshot, type: :boolean, desc: 'Take dashboard snapshot and exit'
388
+ def dashboard
389
+ if options[:snapshot]
390
+ take_dashboard_snapshot
391
+ return
392
+ end
393
+
394
+ say "šŸ–„ļø Starting Visual Agent Dashboard...", :green
395
+
396
+ # Get agent list from options or discover running agents
397
+ agents = options[:agents] ?
398
+ load_specific_agents(options[:agents]) :
399
+ discover_running_agents
400
+
401
+ if agents.empty?
402
+ say "No agents found to monitor", :yellow
403
+ say "Run 'enhance-swarm spawn' or 'enhance-swarm enhance' to start agents"
404
+ return
405
+ end
406
+
407
+ dashboard = VisualDashboard.instance
408
+ dashboard.instance_variable_set(:@refresh_rate, options[:refresh])
409
+
410
+ begin
411
+ dashboard.start_dashboard(agents)
412
+ rescue Interrupt
413
+ say "\nšŸ–„ļø Dashboard stopped by user", :yellow
414
+ end
415
+ end
416
+
417
+ desc 'suggest', 'Get smart suggestions for next actions'
418
+ option :context, type: :string, desc: 'Additional context for suggestions'
419
+ option :auto_run, type: :boolean, desc: 'Automatically run high-priority suggestions'
420
+ def suggest
421
+ say "🧠 Analyzing project and generating smart suggestions...", :blue
422
+
423
+ # Get current context
424
+ context = build_suggestion_context
425
+ context[:user_context] = options[:context] if options[:context]
426
+
427
+ # Get suggestions
428
+ suggestions = SmartDefaults.get_suggestions(context)
429
+
430
+ if suggestions.empty?
431
+ say "āœ… No suggestions at this time. Your project looks good!", :green
432
+ return
433
+ end
434
+
435
+ say "\nšŸ’” Smart Suggestions:\n", :yellow
436
+
437
+ suggestions.each_with_index do |suggestion, i|
438
+ priority_color = case suggestion[:priority]
439
+ when :high then :red
440
+ when :medium then :yellow
441
+ when :low then :blue
442
+ else :white
443
+ end
444
+
445
+ say "#{i + 1}. [#{suggestion[:priority].to_s.upcase}] #{suggestion[:description]}", priority_color
446
+ say " Command: #{suggestion[:command]}", :light_black if suggestion[:command]
447
+ say ""
448
+ end
449
+
450
+ # Auto-run high priority suggestions if requested
451
+ if options[:auto_run]
452
+ high_priority = suggestions.select { |s| s[:priority] == :high && s[:auto_executable] }
453
+
454
+ high_priority.each do |suggestion|
455
+ say "šŸ¤– Auto-executing: #{suggestion[:description]}", :green
456
+ system(suggestion[:command]) if suggestion[:command]
457
+ end
458
+ end
459
+ end
460
+
461
+ desc 'smart-config', 'Generate smart configuration based on project analysis'
462
+ option :apply, type: :boolean, desc: 'Apply the generated configuration'
463
+ option :preview, type: :boolean, default: true, desc: 'Preview configuration before applying'
464
+ def smart_config
465
+ say "šŸ”§ Analyzing project for optimal configuration...", :blue
466
+
467
+ config = SmartDefaults.generate_smart_config
468
+
469
+ if options[:preview] || !options[:apply]
470
+ say "\nšŸ“‹ Suggested Configuration:\n", :yellow
471
+ puts JSON.pretty_generate(config)
472
+ end
473
+
474
+ if options[:apply]
475
+ say "\nšŸ”§ Applying smart configuration...", :green
476
+ SmartDefaults.apply_config(config)
477
+ say "āœ… Configuration applied successfully!", :green
478
+ elsif !options[:apply]
479
+ say "\nRun with --apply to use this configuration", :light_black
480
+ end
481
+ end
482
+
483
+ desc 'recover', 'Intelligent error recovery and analysis'
484
+ option :analyze, type: :string, desc: 'Analyze specific error message'
485
+ option :explain, type: :string, desc: 'Get human-readable explanation of error'
486
+ option :stats, type: :boolean, desc: 'Show error recovery statistics'
487
+ option :learn, type: :string, desc: 'Learn from manual recovery (use with --steps)'
488
+ option :steps, type: :array, desc: 'Recovery steps for learning (use with --learn)'
489
+ def recover
490
+ error_recovery = ErrorRecovery.instance
491
+
492
+ if options[:analyze]
493
+ analyze_error_command(options[:analyze], error_recovery)
494
+ elsif options[:explain]
495
+ explain_error_command(options[:explain], error_recovery)
496
+ elsif options[:stats]
497
+ show_recovery_stats(error_recovery)
498
+ elsif options[:learn] && options[:steps]
499
+ learn_recovery_command(options[:learn], options[:steps], error_recovery)
500
+ else
501
+ say "Please specify an action: --analyze, --explain, --stats, or --learn", :yellow
502
+ say "Use --help for more information"
503
+ end
504
+ end
505
+
506
+ desc 'troubleshoot', 'Interactive troubleshooting assistant'
507
+ def troubleshoot
508
+ say "šŸ”§ Interactive Troubleshooting Mode", :green
509
+ say "────────────────────────────────────────", :light_black
510
+
511
+ loop do
512
+ say "\nWhat would you like to troubleshoot?"
513
+ say "1. Recent agent failures"
514
+ say "2. Configuration issues"
515
+ say "3. Dependency problems"
516
+ say "4. Performance issues"
517
+ say "5. Exit"
518
+
519
+ print "\nEnter your choice (1-5): "
520
+ choice = $stdin.gets.chomp
521
+
522
+ case choice
523
+ when '1'
524
+ troubleshoot_recent_failures
525
+ when '2'
526
+ troubleshoot_configuration
527
+ when '3'
528
+ troubleshoot_dependencies
529
+ when '4'
530
+ troubleshoot_performance
531
+ when '5'
532
+ say "šŸ‘‹ Exiting troubleshoot mode", :blue
533
+ break
534
+ else
535
+ say "Invalid choice. Please enter 1-5.", :red
536
+ end
537
+ end
538
+ end
539
+
540
+ private
541
+
542
+ def spawn_with_streaming(task_desc, role = nil)
543
+ orchestrator = Orchestrator.new
544
+ agent_role = role || options[:role] || 'general'
545
+
546
+ # Spawn the agent
547
+ pid = orchestrator.spawn_single(
548
+ task: task_desc,
549
+ role: agent_role,
550
+ worktree: options[:worktree]
551
+ )
552
+
553
+ return unless pid
554
+
555
+ # Start streaming output
556
+ agent_id = "#{agent_role}-#{Time.now.to_i}"
557
+ agents = [{
558
+ id: agent_id,
559
+ pid: pid,
560
+ role: agent_role
561
+ }]
562
+
563
+ say "\nšŸ”“ Live output streaming started. Press Ctrl+C to stop watching.\n", :green
564
+ OutputStreamer.stream_agents(agents)
565
+ end
566
+
567
+ def enhance_with_control_agent
568
+ # Determine task from options or get next priority task
569
+ task_description = if options[:task]
570
+ "Task ID: #{options[:task]}"
571
+ else
572
+ ask("Enter task description:", :blue) || "Enhance the project"
573
+ end
574
+
575
+ say "\nšŸŽ›ļø Starting Control Agent coordination...", :yellow
576
+
577
+ begin
578
+ if options[:follow]
579
+ enhance_with_control_agent_streaming(task_description)
580
+ else
581
+ enhance_with_control_agent_progress(task_description)
582
+ end
583
+ rescue StandardError => e
584
+ say "āŒ Control Agent coordination failed: #{e.message}", :red
585
+ Logger.error("Control Agent error: #{e.message}")
586
+ end
587
+ end
588
+
589
+ def enhance_with_control_agent_streaming(task_description)
590
+ control_agent = ControlAgent.new(task_description)
591
+
592
+ # Start coordination in background
593
+ coordination_thread = control_agent.start_coordination
594
+
595
+ say "\nšŸ”“ Control Agent streaming started. Press Ctrl+C to stop watching.\n", :green
596
+
597
+ # Display live coordination status
598
+ begin
599
+ loop do
600
+ status = control_agent.current_status
601
+ display_control_agent_status(status)
602
+
603
+ break if %w[completed failed].include?(status['status'])
604
+
605
+ sleep(3)
606
+ end
607
+ rescue Interrupt
608
+ say "\n\nāš ļø Stopping Control Agent coordination...", :yellow
609
+ ensure
610
+ control_agent.stop_coordination
611
+ coordination_thread&.join
612
+ end
613
+ end
614
+
615
+ def enhance_with_control_agent_progress(task_description)
616
+ ProgressTracker.track(total_steps: 100, estimated_tokens: 5000) do |tracker|
617
+ ControlAgent.coordinate_task(task_description) do |control_agent|
618
+ # Track progress with the Control Agent
619
+ progress_thread = control_agent.track_progress_with_streamer(tracker)
620
+
621
+ # Monitor until completion
622
+ loop do
623
+ status = control_agent.current_status
624
+ break if %w[completed failed].include?(status['status'])
625
+ sleep(5)
626
+ end
627
+
628
+ progress_thread&.join
629
+ end
630
+ end
631
+ end
632
+
633
+ def display_control_agent_status(status)
634
+ # Clear screen and show coordinated status
635
+ print "\e[H\e[2J"
636
+
637
+ puts "šŸŽ›ļø Control Agent Coordination".colorize(:cyan)
638
+ puts "Phase: #{status['phase']&.humanize || 'Unknown'}".colorize(:blue)
639
+ puts "Progress: #{status['progress_percentage'] || 0}%".colorize(:green)
640
+ puts
641
+
642
+ # Show active agents
643
+ if status['active_agents']&.any?
644
+ puts "šŸ”„ Active Agents:".colorize(:yellow)
645
+ status['active_agents'].each do |agent_id|
646
+ puts " • #{agent_id}"
647
+ end
648
+ puts
649
+ end
650
+
651
+ # Show completed agents
652
+ if status['completed_agents']&.any?
653
+ puts "āœ… Completed Agents:".colorize(:green)
654
+ status['completed_agents'].each do |agent_id|
655
+ puts " • #{agent_id}"
656
+ end
657
+ puts
658
+ end
659
+
660
+ # Show current message
661
+ if status['message']
662
+ puts "šŸ“ Status: #{status['message']}".colorize(:white)
663
+ puts
664
+ end
665
+
666
+ # Show estimated completion
667
+ if status['estimated_completion']
668
+ eta = Time.parse(status['estimated_completion'])
669
+ remaining = eta - Time.now
670
+ if remaining > 0
671
+ puts "ā±ļø Estimated completion: #{eta.strftime('%H:%M:%S')} (#{(remaining/60).round}m remaining)"
672
+ end
673
+ end
674
+ end
675
+
676
+ def setup_notifications_and_interrupts
677
+ # Enable notifications
678
+ notification_manager = NotificationManager.instance
679
+ notification_manager.enable!
680
+
681
+ # Setup interrupt handler
682
+ @interrupt_handler = InterruptHandler.new(notification_manager)
683
+ @interrupt_handler.enable_interrupts!
684
+
685
+ # Setup signal handlers for graceful shutdown
686
+ setup_signal_handlers
687
+ end
688
+
689
+ def setup_signal_handlers
690
+ Signal.trap('INT') do
691
+ puts "\nāš ļø Interrupt received. Cleaning up agents...".colorize(:yellow)
692
+
693
+ # Stop monitoring
694
+ @interrupt_handler&.stop_monitoring
695
+ NotificationManager.instance.stop_monitoring
696
+
697
+ # Graceful shutdown notification
698
+ NotificationManager.instance.notify(
699
+ :intervention_needed,
700
+ "User interrupted operation - cleaning up agents",
701
+ { reason: 'user_interrupt' }
702
+ )
703
+
704
+ exit(130) # Standard exit code for SIGINT
705
+ end
706
+
707
+ Signal.trap('TERM') do
708
+ puts "\nšŸ›‘ Termination signal received. Shutting down...".colorize(:red)
709
+ @interrupt_handler&.stop_monitoring
710
+ NotificationManager.instance.stop_monitoring
711
+ exit(143) # Standard exit code for SIGTERM
712
+ end
713
+ end
714
+
715
+ desc 'notifications', 'Manage notification settings'
716
+ option :enable, type: :boolean, desc: 'Enable notifications'
717
+ option :disable, type: :boolean, desc: 'Disable notifications'
718
+ option :test, type: :boolean, desc: 'Send test notification'
719
+ option :history, type: :boolean, desc: 'Show notification history'
720
+ def notifications
721
+ notification_manager = NotificationManager.instance
722
+
723
+ if options[:enable]
724
+ notification_manager.enable!
725
+ elsif options[:disable]
726
+ notification_manager.disable!
727
+ elsif options[:test]
728
+ test_notifications
729
+ elsif options[:history]
730
+ show_notification_history
731
+ else
732
+ show_notification_status
733
+ end
734
+ end
735
+
736
+ desc 'restart AGENT_ID', 'Restart a stuck or failed agent'
737
+ option :timeout, type: :numeric, default: 300, desc: 'Timeout for new agent (seconds)'
738
+ def restart(agent_id)
739
+ say "šŸ”„ Restarting agent: #{agent_id}", :yellow
740
+
741
+ # This would integrate with the InterruptHandler
742
+ interrupt_handler = InterruptHandler.new
743
+
744
+ # Mock agent for demonstration
745
+ agent = {
746
+ id: agent_id,
747
+ role: agent_id.split('-').first,
748
+ pid: nil # Would be looked up
749
+ }
750
+
751
+ interrupt_handler.send(:restart_agent, agent)
752
+ end
753
+
754
+ desc 'communicate', 'Manage agent communication and messages'
755
+ option :list, type: :boolean, desc: 'List pending messages from agents'
756
+ option :respond, type: :string, desc: 'Respond to a specific message ID'
757
+ option :response, type: :string, desc: 'Response text (used with --respond)'
758
+ option :interactive, type: :boolean, desc: 'Enter interactive communication mode'
759
+ option :history, type: :boolean, desc: 'Show recent communication history'
760
+ option :cleanup, type: :boolean, desc: 'Clean up old messages'
761
+ def communicate(response_text = nil)
762
+ communicator = AgentCommunicator.instance
763
+
764
+ if options[:list]
765
+ communicator.show_pending_messages
766
+ elsif options[:respond]
767
+ message_id = options[:respond]
768
+ response = options[:response] || response_text || ask("Response:", :blue)
769
+
770
+ if response && !response.empty?
771
+ communicator.user_respond(message_id, response)
772
+ else
773
+ say "āŒ Response cannot be empty", :red
774
+ end
775
+ elsif options[:interactive]
776
+ communicator.interactive_response_mode
777
+ elsif options[:history]
778
+ show_communication_history
779
+ elsif options[:cleanup]
780
+ communicator.cleanup_old_messages
781
+ say "āœ… Cleaned up old messages", :green
782
+ else
783
+ show_communication_status
784
+ end
785
+ end
786
+
787
+ desc 'dashboard', 'Start visual agent dashboard'
788
+ option :agents, type: :array, desc: 'Specific agent IDs to monitor'
789
+ option :refresh, type: :numeric, default: 2, desc: 'Refresh rate in seconds'
790
+ option :snapshot, type: :boolean, desc: 'Take dashboard snapshot and exit'
791
+ def dashboard
792
+ if options[:snapshot]
793
+ take_dashboard_snapshot
794
+ return
795
+ end
796
+
797
+ say "šŸ–„ļø Starting Visual Agent Dashboard...", :green
798
+
799
+ # Get agent list from options or discover running agents
800
+ agents = options[:agents] ?
801
+ load_specific_agents(options[:agents]) :
802
+ discover_running_agents
803
+
804
+ if agents.empty?
805
+ say "No agents found to monitor", :yellow
806
+ say "Run 'enhance-swarm spawn' or 'enhance-swarm enhance' to start agents"
807
+ return
808
+ end
809
+
810
+ dashboard = VisualDashboard.instance
811
+ dashboard.instance_variable_set(:@refresh_rate, options[:refresh])
812
+
813
+ begin
814
+ dashboard.start_dashboard(agents)
815
+ rescue Interrupt
816
+ say "\nšŸ–„ļø Dashboard stopped by user", :yellow
817
+ end
818
+ end
819
+
820
+ desc 'suggest', 'Get smart suggestions for next actions'
821
+ option :context, type: :string, desc: 'Additional context for suggestions'
822
+ option :auto_run, type: :boolean, desc: 'Automatically run high-priority suggestions'
823
+ def suggest
824
+ say "🧠 Analyzing project and generating smart suggestions...", :blue
825
+
826
+ # Get current context
827
+ context = build_suggestion_context
828
+ context[:user_input] = options[:context] if options[:context]
829
+
830
+ # Get suggestions
831
+ suggestions = SmartDefaults.suggest_next_actions(context)
832
+
833
+ if suggestions.empty?
834
+ say "āœ… No suggestions - everything looks good!", :green
835
+ return
836
+ end
837
+
838
+ say "\nšŸ’” Smart Suggestions:", :blue
839
+ suggestions.each_with_index do |suggestion, index|
840
+ priority_color = case suggestion[:priority]
841
+ when :critical then :red
842
+ when :high then :yellow
843
+ when :medium then :blue
844
+ else :white
845
+ end
846
+
847
+ priority_text = suggestion[:priority].to_s.upcase
848
+
849
+ say "#{index + 1}. [#{priority_text}] #{suggestion[:reason]}", priority_color
850
+ say " Command: #{suggestion[:command]}", :light_black
851
+
852
+ # Auto-run high priority suggestions if enabled
853
+ if options[:auto_run] && suggestion[:priority] == :high
854
+ if yes?(" Execute this command? [y/N]", :yellow)
855
+ say " šŸ”„ Executing: #{suggestion[:command]}", :green
856
+ system(suggestion[:command])
857
+ end
858
+ end
859
+
860
+ puts
861
+ end
862
+
863
+ unless options[:auto_run]
864
+ say "Use --auto-run to automatically execute high-priority suggestions", :light_black
865
+ end
866
+ end
867
+
868
+ desc 'smart-config', 'Generate smart configuration based on project analysis'
869
+ option :apply, type: :boolean, desc: 'Apply the configuration to .enhance_swarm.yml'
870
+ def smart_config
871
+ say "šŸ” Analyzing project structure and generating configuration...", :blue
872
+
873
+ config = SmartDefaults.suggest_configuration
874
+
875
+ say "\nšŸ“‹ Suggested Configuration:", :green
876
+ puts YAML.dump(config).colorize(:white)
877
+
878
+ if options[:apply]
879
+ config_file = '.enhance_swarm.yml'
880
+
881
+ if File.exist?(config_file)
882
+ backup_file = "#{config_file}.backup.#{Time.now.to_i}"
883
+ FileUtils.cp(config_file, backup_file)
884
+ say "šŸ“ Backed up existing config to #{backup_file}", :yellow
885
+ end
886
+
887
+ File.write(config_file, YAML.dump(config))
888
+ say "āœ… Configuration applied to #{config_file}", :green
889
+ else
890
+ say "Use --apply to save this configuration to .enhance_swarm.yml", :light_black
891
+ end
892
+ end
893
+
894
+ desc 'recover', 'Intelligent error recovery and analysis'
895
+ option :analyze, type: :string, desc: 'Analyze specific error message'
896
+ option :explain, type: :string, desc: 'Get human-readable explanation of error'
897
+ option :stats, type: :boolean, desc: 'Show error recovery statistics'
898
+ option :learn, type: :string, desc: 'Learn from manual recovery (provide error message)'
899
+ option :steps, type: :array, desc: 'Recovery steps taken (used with --learn)'
900
+ option :cleanup, type: :boolean, desc: 'Clean up old error recovery data'
901
+ def recover
902
+ error_recovery = ErrorRecovery.instance
903
+
904
+ if options[:analyze]
905
+ analyze_error_command(options[:analyze], error_recovery)
906
+ elsif options[:explain]
907
+ explain_error_command(options[:explain], error_recovery)
908
+ elsif options[:stats]
909
+ show_recovery_stats(error_recovery)
910
+ elsif options[:learn] && options[:steps]
911
+ learn_recovery_command(options[:learn], options[:steps], error_recovery)
912
+ elsif options[:cleanup]
913
+ cleanup_error_data(error_recovery)
914
+ else
915
+ show_recovery_help
916
+ end
917
+ end
918
+
919
+ desc 'troubleshoot', 'Interactive troubleshooting assistant'
920
+ option :agent, type: :string, desc: 'Troubleshoot specific agent by ID'
921
+ option :recent, type: :boolean, desc: 'Troubleshoot recent failures'
922
+ option :interactive, type: :boolean, default: true, desc: 'Interactive mode'
923
+ def troubleshoot
924
+ say "šŸ”§ EnhanceSwarm Troubleshooting Assistant", :cyan
925
+
926
+ if options[:agent]
927
+ troubleshoot_agent(options[:agent])
928
+ elsif options[:recent]
929
+ troubleshoot_recent_failures
930
+ else
931
+ interactive_troubleshooting
932
+ end
933
+ end
934
+
935
+ private
936
+
937
+ def analyze_error_command(error_message, error_recovery)
938
+ # Create a mock error for analysis
939
+ mock_error = StandardError.new(error_message)
940
+
941
+ say "\nšŸ” Analyzing error: #{error_message}", :blue
942
+
943
+ analysis = error_recovery.analyze_error(mock_error, { source: 'cli_analysis' })
944
+
945
+ say "\nšŸ“Š Error Analysis:", :green
946
+ say " Type: #{analysis[:error][:type]}"
947
+ say " Auto-recoverable: #{analysis[:auto_recoverable] ? 'Yes' : 'No'}"
948
+
949
+ if analysis[:patterns].any?
950
+ say "\nšŸ”Ž Matching Patterns:", :yellow
951
+ analysis[:patterns].first(3).each_with_index do |pattern, index|
952
+ say " #{index + 1}. #{pattern[:explanation]} (#{(pattern[:confidence] * 100).round}% confidence)"
953
+ end
954
+ end
955
+
956
+ if analysis[:suggestions].any?
957
+ say "\nšŸ’” Recovery Suggestions:", :blue
958
+ analysis[:suggestions].first(5).each_with_index do |suggestion, index|
959
+ auto_indicator = suggestion[:auto_executable] ? 'šŸ¤–' : 'šŸ‘¤'
960
+ confidence = suggestion[:confidence] ? " (#{(suggestion[:confidence] * 100).round}%)" : ""
961
+ say " #{index + 1}. #{auto_indicator} #{suggestion[:description]}#{confidence}"
962
+ end
963
+ end
964
+ end
965
+
966
+ def explain_error_command(error_message, error_recovery)
967
+ mock_error = StandardError.new(error_message)
968
+
969
+ say "\nšŸ“– Error Explanation: #{error_message}", :blue
970
+
971
+ explanation = error_recovery.explain_error(mock_error, { source: 'cli_explanation' })
972
+
973
+ say "\n#{explanation[:explanation]}", :white
974
+ say "\nšŸ” Likely Cause:", :yellow
975
+ say " #{explanation[:likely_cause]}"
976
+
977
+ if explanation[:prevention_tips].any?
978
+ say "\nšŸ›”ļø Prevention Tips:", :green
979
+ explanation[:prevention_tips].each_with_index do |tip, index|
980
+ say " #{index + 1}. #{tip}"
981
+ end
982
+ end
983
+ end
984
+
985
+ def show_recovery_stats(error_recovery)
986
+ stats = error_recovery.recovery_statistics
987
+
988
+ say "\nšŸ“Š Error Recovery Statistics:", :green
989
+ say " Total errors processed: #{stats[:total_errors_processed]}"
990
+ say " Successful automatic recoveries: #{stats[:successful_automatic_recoveries]}"
991
+ say " Recovery success rate: #{stats[:recovery_success_rate]}%"
992
+ say " Recovery patterns learned: #{stats[:recovery_patterns_learned]}"
993
+
994
+ if stats[:most_common_errors].any?
995
+ say "\nšŸ”¢ Most Common Error Types:", :blue
996
+ stats[:most_common_errors].each do |error_type, count|
997
+ say " #{error_type}: #{count} occurrences"
998
+ end
999
+ end
1000
+ end
1001
+
1002
+ def learn_recovery_command(error_message, recovery_steps, error_recovery)
1003
+ mock_error = StandardError.new(error_message)
1004
+
1005
+ say "\n🧠 Learning from manual recovery...", :blue
1006
+ say " Error: #{error_message}"
1007
+ say " Steps: #{recovery_steps.join(' → ')}"
1008
+
1009
+ error_recovery.learn_from_manual_recovery(
1010
+ mock_error,
1011
+ recovery_steps,
1012
+ { source: 'cli_learning', timestamp: Time.now.iso8601 }
1013
+ )
1014
+
1015
+ say "āœ… Recovery pattern learned successfully!", :green
1016
+ end
1017
+
1018
+ def cleanup_error_data(error_recovery)
1019
+ say "🧹 Cleaning up old error recovery data...", :blue
1020
+
1021
+ error_recovery.cleanup_old_data(30) # Keep last 30 days
1022
+
1023
+ say "āœ… Cleanup completed", :green
1024
+ end
1025
+
1026
+ def show_recovery_help
1027
+ say "\nšŸ”§ Error Recovery Commands:", :blue
1028
+ say " enhance-swarm recover --analyze 'error message' # Analyze specific error"
1029
+ say " enhance-swarm recover --explain 'error message' # Get error explanation"
1030
+ say " enhance-swarm recover --stats # Show recovery statistics"
1031
+ say " enhance-swarm recover --learn 'error' --steps step1 step2 # Learn from manual recovery"
1032
+ say " enhance-swarm recover --cleanup # Clean up old data"
1033
+ end
1034
+
1035
+ def troubleshoot_agent(agent_id)
1036
+ say "\nšŸ” Troubleshooting agent: #{agent_id}", :blue
1037
+
1038
+ # This would integrate with actual agent monitoring
1039
+ say "Agent troubleshooting not yet implemented for specific agents", :yellow
1040
+ say "Use 'enhance-swarm status' to check overall agent health"
1041
+ end
1042
+
1043
+ def troubleshoot_recent_failures
1044
+ say "\nšŸ” Analyzing recent failures...", :blue
1045
+
1046
+ # This would analyze recent error logs and agent failures
1047
+ say "Recent failure analysis not yet implemented", :yellow
1048
+ say "Use 'enhance-swarm recover --stats' to see error recovery statistics"
1049
+ end
1050
+
1051
+ def interactive_troubleshooting
1052
+ say "\nšŸ”§ Interactive Troubleshooting Mode", :cyan
1053
+ say "─" * 40
1054
+
1055
+ loop do
1056
+ say "\nWhat would you like to troubleshoot?", :blue
1057
+ say "1. Recent agent failures"
1058
+ say "2. Configuration issues"
1059
+ say "3. Dependency problems"
1060
+ say "4. Performance issues"
1061
+ say "5. Exit"
1062
+
1063
+ choice = ask("Enter your choice (1-5):", :yellow)
1064
+
1065
+ case choice.strip
1066
+ when '1'
1067
+ troubleshoot_recent_failures
1068
+ when '2'
1069
+ troubleshoot_configuration
1070
+ when '3'
1071
+ troubleshoot_dependencies
1072
+ when '4'
1073
+ troubleshoot_performance
1074
+ when '5'
1075
+ say "šŸ‘‹ Exiting troubleshooting mode", :green
1076
+ break
1077
+ else
1078
+ say "āŒ Invalid choice. Please enter 1-5.", :red
1079
+ end
1080
+ end
1081
+ end
1082
+
1083
+ def troubleshoot_configuration
1084
+ say "\nāš™ļø Configuration Troubleshooting", :blue
1085
+
1086
+ # Check for common configuration issues
1087
+ config_file = '.enhance_swarm.yml'
1088
+
1089
+ if File.exist?(config_file)
1090
+ say "āœ… Configuration file found: #{config_file}", :green
1091
+
1092
+ begin
1093
+ config = YAML.load_file(config_file)
1094
+ say "āœ… Configuration file is valid YAML", :green
1095
+
1096
+ # Basic validation
1097
+ issues = []
1098
+ issues << "Missing project_name" unless config['project_name']
1099
+ issues << "Missing technology_stack" unless config['technology_stack']
1100
+
1101
+ if issues.any?
1102
+ say "āš ļø Configuration issues found:", :yellow
1103
+ issues.each { |issue| say " - #{issue}", :red }
1104
+ say "\nUse 'enhance-swarm smart-config --apply' to generate optimal configuration", :blue
1105
+ else
1106
+ say "āœ… Configuration appears to be valid", :green
1107
+ end
1108
+
1109
+ rescue StandardError => e
1110
+ say "āŒ Configuration file has syntax errors: #{e.message}", :red
1111
+ say "Fix the YAML syntax or regenerate with 'enhance-swarm smart-config --apply'", :blue
1112
+ end
1113
+ else
1114
+ say "āŒ No configuration file found", :red
1115
+ say "Run 'enhance-swarm init' or 'enhance-swarm smart-config --apply' to create one", :blue
1116
+ end
1117
+ end
1118
+
1119
+ def troubleshoot_dependencies
1120
+ say "\nšŸ“¦ Dependency Troubleshooting", :blue
1121
+
1122
+ # Check dependency validation
1123
+ begin
1124
+ validation_results = DependencyValidator.validate_all
1125
+
1126
+ validation_results[:results].each do |tool, result|
1127
+ status = result[:passed] ? 'āœ…' : 'āŒ'
1128
+ say " #{status} #{tool.capitalize}: #{result[:version] || 'Not found'}"
1129
+
1130
+ if !result[:passed] && result[:error]
1131
+ say " Error: #{result[:error]}", :red
1132
+ end
1133
+ end
1134
+
1135
+ unless validation_results[:passed]
1136
+ say "\nšŸ’” Suggested fixes:", :blue
1137
+ say " - Install missing dependencies using your system package manager"
1138
+ say " - Update PATH environment variable if tools are installed but not found"
1139
+ say " - Run 'enhance-swarm doctor --detailed' for more information"
1140
+ end
1141
+
1142
+ rescue StandardError => e
1143
+ say "āŒ Could not validate dependencies: #{e.message}", :red
1144
+ end
1145
+ end
1146
+
1147
+ def troubleshoot_performance
1148
+ say "\n⚔ Performance Troubleshooting", :blue
1149
+
1150
+ # Basic system health check
1151
+ begin
1152
+ health = system_health_summary
1153
+
1154
+ if health[:issues].any?
1155
+ say "āš ļø Performance issues detected:", :yellow
1156
+ health[:issues].each { |issue| say " - #{issue}", :red }
1157
+
1158
+ say "\nšŸ’” Suggested fixes:", :blue
1159
+ say " - Run 'enhance-swarm cleanup --all' to clean up stale resources"
1160
+ say " - Reduce max_concurrent_agents in configuration"
1161
+ say " - Close other memory-intensive applications"
1162
+ else
1163
+ say "āœ… No obvious performance issues detected", :green
1164
+ end
1165
+
1166
+ # Show current concurrency settings
1167
+ concurrency = SmartDefaults.suggest_concurrency_settings
1168
+ say "\nšŸŽÆ Recommended Concurrency Settings:", :blue
1169
+ say " Max concurrent agents: #{concurrency[:max_concurrent_agents]}"
1170
+ say " Monitor interval: #{concurrency[:monitor_interval]}s"
1171
+
1172
+ rescue StandardError => e
1173
+ say "āŒ Could not analyze performance: #{e.message}", :red
1174
+ end
1175
+ end
1176
+
1177
+ def test_notifications
1178
+ notification_manager = NotificationManager.instance
1179
+
1180
+ say "🧪 Testing notifications...", :blue
1181
+
1182
+ # Test different types of notifications
1183
+ notification_manager.agent_completed('test-backend-123', 'backend', 120, {
1184
+ output_path: '/tmp/test'
1185
+ })
1186
+
1187
+ sleep(1)
1188
+
1189
+ notification_manager.agent_failed('test-frontend-456', 'frontend',
1190
+ 'Connection timeout', [
1191
+ 'Check network connectivity',
1192
+ 'Restart with longer timeout'
1193
+ ])
1194
+
1195
+ sleep(1)
1196
+
1197
+ notification_manager.progress_milestone('Backend Implementation Complete', 75)
1198
+
1199
+ say "āœ… Test notifications sent", :green
1200
+ end
1201
+
1202
+ def show_notification_history
1203
+ notification_manager = NotificationManager.instance
1204
+ recent = notification_manager.recent_notifications(10)
1205
+
1206
+ if recent.empty?
1207
+ say "No recent notifications", :yellow
1208
+ return
1209
+ end
1210
+
1211
+ say "\nšŸ“‹ Recent Notifications:", :blue
1212
+ recent.each do |notification|
1213
+ timestamp = notification[:timestamp].strftime('%H:%M:%S')
1214
+ priority = notification[:priority].to_s.upcase
1215
+ type = notification[:type].to_s.humanize
1216
+
1217
+ color = case notification[:priority]
1218
+ when :critical then :red
1219
+ when :high then :yellow
1220
+ when :medium then :blue
1221
+ else :white
1222
+ end
1223
+
1224
+ say "[#{timestamp}] #{priority} - #{type}: #{notification[:message]}", color
1225
+ end
1226
+ end
1227
+
1228
+ def show_notification_status
1229
+ notification_manager = NotificationManager.instance
1230
+
1231
+ say "\nšŸ”” Notification Status:", :blue
1232
+ say " Enabled: #{notification_manager.enabled? ? 'āœ…' : 'āŒ'}"
1233
+ say " Desktop: #{notification_manager.instance_variable_get(:@desktop_notifications) ? 'āœ…' : 'āŒ'}"
1234
+ say " Sound: #{notification_manager.instance_variable_get(:@sound_enabled) ? 'āœ…' : 'āŒ'}"
1235
+
1236
+ recent_count = notification_manager.recent_notifications.count
1237
+ say " Recent notifications: #{recent_count}"
1238
+
1239
+ if recent_count > 0
1240
+ say "\nUse 'enhance-swarm notifications --history' to view recent notifications"
1241
+ end
1242
+ end
1243
+
1244
+ def start_interactive_communication
1245
+ communicator = AgentCommunicator.instance
1246
+ say "šŸ’¬ Interactive Communication Mode", :green
1247
+ say "Type 'exit' to quit, 'help' for commands", :light_black
1248
+
1249
+ loop do
1250
+ print "\nenhance-swarm-chat> "
1251
+ input = $stdin.gets.chomp
1252
+
1253
+ case input.downcase
1254
+ when 'exit', 'quit'
1255
+ say "šŸ‘‹ Exiting interactive mode", :blue
1256
+ break
1257
+ when 'help'
1258
+ say "Available commands:"
1259
+ say " list - Show pending messages"
1260
+ say " history - Show recent messages"
1261
+ say " exit - Exit interactive mode"
1262
+ when 'list'
1263
+ show_pending_messages
1264
+ when 'history'
1265
+ show_communication_history
1266
+ else
1267
+ say "Unknown command: #{input}", :red
1268
+ say "Type 'help' for available commands"
1269
+ end
1270
+ end
1271
+ end
1272
+
1273
+ def show_pending_messages
1274
+ communicator = AgentCommunicator.instance
1275
+ pending = communicator.pending_messages
1276
+
1277
+ if pending.empty?
1278
+ say "šŸ“­ No pending messages from agents", :blue
1279
+ return
1280
+ end
1281
+
1282
+ say "\nšŸ“¬ Pending Messages (#{pending.count}):", :yellow
1283
+ pending.each_with_index do |message, index|
1284
+ age = time_ago(Time.parse(message[:timestamp]))
1285
+ say "\n[#{index + 1}] #{message[:type].upcase} from #{message[:role]} (#{age} ago)"
1286
+ say "Message: #{message[:content]}"
1287
+ say "ID: #{message[:id]}" if message[:id]
1288
+ end
1289
+
1290
+ say "\nUse --respond <id> --response \"<text>\" to reply"
1291
+ end
1292
+
1293
+ def respond_to_message(message_id, response_text)
1294
+ communicator = AgentCommunicator.instance
1295
+
1296
+ begin
1297
+ result = communicator.respond_to_message(message_id, response_text)
1298
+
1299
+ if result[:success]
1300
+ say "āœ… Response sent successfully", :green
1301
+ else
1302
+ say "āŒ Failed to send response: #{result[:error]}", :red
1303
+ end
1304
+ rescue StandardError => e
1305
+ say "āŒ Error sending response: #{e.message}", :red
1306
+ end
1307
+ end
1308
+
1309
+ def show_communication_status
1310
+ communicator = AgentCommunicator.instance
1311
+ pending = communicator.pending_messages
1312
+ recent = communicator.recent_messages(5)
1313
+
1314
+ say "\nšŸ’¬ Agent Communication Status:", :blue
1315
+ say " Pending messages: #{pending.count}"
1316
+ say " Recent messages: #{recent.count}"
1317
+
1318
+ if pending.any?
1319
+ say "\nšŸ“‹ Pending Messages:", :yellow
1320
+ pending.first(3).each_with_index do |message, index|
1321
+ age = time_ago(Time.parse(message[:timestamp]))
1322
+ say " #{index + 1}. #{message[:type]} from #{message[:role]} (#{age} ago)"
1323
+ say " #{message[:content][0..60]}..."
1324
+ end
1325
+
1326
+ if pending.count > 3
1327
+ say " ... and #{pending.count - 3} more"
1328
+ end
1329
+
1330
+ say "\nUse 'enhance-swarm communicate --list' to see all pending messages"
1331
+ say "Use 'enhance-swarm communicate --interactive' for interactive mode"
1332
+ else
1333
+ say " No pending messages from agents"
1334
+ end
1335
+ end
1336
+
1337
+ def show_communication_history
1338
+ communicator = AgentCommunicator.instance
1339
+ recent = communicator.recent_messages(10)
1340
+
1341
+ if recent.empty?
1342
+ say "No recent communication history", :yellow
1343
+ return
1344
+ end
1345
+
1346
+ say "\nšŸ’¬ Recent Agent Communication:", :blue
1347
+ recent.each do |message|
1348
+ timestamp = Time.parse(message[:timestamp]).strftime('%H:%M:%S')
1349
+ type_icon = case message[:type]
1350
+ when :question then 'ā“'
1351
+ when :decision then 'šŸ¤”'
1352
+ when :status then 'šŸ“'
1353
+ when :progress then 'šŸ“Š'
1354
+ else 'šŸ’¬'
1355
+ end
1356
+
1357
+ color = message[:requires_response] ? :yellow : :white
1358
+ status = message[:requires_response] ? '(needs response)' : ''
1359
+
1360
+ say "[#{timestamp}] #{type_icon} #{message[:role]} - #{message[:type]} #{status}", color
1361
+ say " #{message[:content][0..80]}#{message[:content].length > 80 ? '...' : ''}"
1362
+ end
1363
+ end
1364
+
1365
+ def time_ago(time)
1366
+ seconds = Time.now - time
1367
+
1368
+ if seconds < 60
1369
+ "#{seconds.round}s"
1370
+ elsif seconds < 3600
1371
+ "#{(seconds / 60).round}m"
1372
+ elsif seconds < 86400
1373
+ "#{(seconds / 3600).round}h"
1374
+ else
1375
+ "#{(seconds / 86400).round}d"
1376
+ end
1377
+ end
1378
+
1379
+ def take_dashboard_snapshot
1380
+ say "šŸ“ø Taking dashboard snapshot...", :blue
1381
+
1382
+ # Create a mock dashboard state for snapshot
1383
+ agents = discover_running_agents
1384
+ dashboard = VisualDashboard.instance
1385
+
1386
+ if agents.any?
1387
+ agents.each { |agent| dashboard.add_agent(agent) }
1388
+ dashboard.send(:save_dashboard_snapshot)
1389
+ say "āœ… Dashboard snapshot saved", :green
1390
+ else
1391
+ say "No agents found for snapshot", :yellow
1392
+ end
1393
+ end
1394
+
1395
+ def load_specific_agents(agent_ids)
1396
+ agents = []
1397
+
1398
+ agent_ids.each do |agent_id|
1399
+ # Mock agent data - in real implementation, this would query actual agents
1400
+ agent = {
1401
+ id: agent_id,
1402
+ role: agent_id.split('-').first,
1403
+ status: 'active',
1404
+ start_time: (Time.now - rand(300)).iso8601,
1405
+ current_task: 'Working on task...',
1406
+ progress_percentage: rand(100),
1407
+ pid: rand(10000..99999)
1408
+ }
1409
+ agents << agent
1410
+ end
1411
+
1412
+ agents
1413
+ end
1414
+
1415
+ def discover_running_agents
1416
+ agents = []
1417
+
1418
+ # Check for running swarm processes
1419
+ begin
1420
+ # Look for enhance-swarm processes
1421
+ ps_output = `ps aux | grep -i enhance-swarm | grep -v grep`
1422
+ ps_lines = ps_output.lines
1423
+
1424
+ ps_lines.each_with_index do |line, index|
1425
+ next if line.include?('grep') || line.include?('dashboard')
1426
+
1427
+ parts = line.split
1428
+ pid = parts[1]
1429
+ command = parts[10..-1]&.join(' ')
1430
+
1431
+ next unless command&.include?('enhance-swarm')
1432
+
1433
+ role = extract_role_from_command(command) || 'agent'
1434
+
1435
+ agent = {
1436
+ id: "#{role}-#{Time.now.to_i}-#{index}",
1437
+ role: role,
1438
+ status: 'active',
1439
+ start_time: Time.now.iso8601,
1440
+ current_task: extract_task_from_command(command),
1441
+ progress_percentage: rand(20..80),
1442
+ pid: pid.to_i,
1443
+ command: command
1444
+ }
1445
+
1446
+ agents << agent
1447
+ end
1448
+
1449
+ # Add some mock agents for demonstration if no real ones found
1450
+ if agents.empty?
1451
+ agents = create_demo_agents
1452
+ end
1453
+
1454
+ rescue StandardError => e
1455
+ Logger.error("Failed to discover agents: #{e.message}")
1456
+ agents = create_demo_agents
1457
+ end
1458
+
1459
+ agents
1460
+ end
1461
+
1462
+ def extract_role_from_command(command)
1463
+ if command.include?('--role')
1464
+ role_match = command.match(/--role\s+(\w+)/)
1465
+ return role_match[1] if role_match
1466
+ end
1467
+
1468
+ # Try to infer from command
1469
+ case command
1470
+ when /backend/i then 'backend'
1471
+ when /frontend/i then 'frontend'
1472
+ when /qa/i then 'qa'
1473
+ when /ux/i then 'ux'
1474
+ else 'general'
1475
+ end
1476
+ end
1477
+
1478
+ def extract_task_from_command(command)
1479
+ # Extract task description from command
1480
+ if command.include?('spawn')
1481
+ task_match = command.match(/spawn\s+"([^"]+)"/)
1482
+ return task_match[1] if task_match
1483
+
1484
+ # Try without quotes
1485
+ task_match = command.match(/spawn\s+(.+?)(?:\s+--|$)/)
1486
+ return task_match[1] if task_match
1487
+ elsif command.include?('enhance')
1488
+ task_match = command.match(/enhance\s+"([^"]+)"/)
1489
+ return task_match[1] if task_match
1490
+ end
1491
+
1492
+ 'Working on task...'
1493
+ end
1494
+
1495
+ def create_demo_agents
1496
+ roles = %w[backend frontend qa ux]
1497
+ tasks = [
1498
+ 'Implementing authentication system',
1499
+ 'Building user interface components',
1500
+ 'Running integration tests',
1501
+ 'Designing user experience flow'
1502
+ ]
1503
+
1504
+ agents = []
1505
+
1506
+ roles.each_with_index do |role, index|
1507
+ agent = {
1508
+ id: "#{role}-demo-#{Time.now.to_i + index}",
1509
+ role: role,
1510
+ status: ['active', 'completed', 'stuck'].sample,
1511
+ start_time: (Time.now - rand(600)).iso8601,
1512
+ current_task: tasks[index],
1513
+ progress_percentage: rand(10..95),
1514
+ pid: rand(1000..9999),
1515
+ memory_mb: rand(50..500)
1516
+ }
1517
+ agents << agent
1518
+ end
1519
+
1520
+ agents
1521
+ end
1522
+
1523
+ def build_suggestion_context
1524
+ context = {}
1525
+
1526
+ # Get current git status
1527
+ if Dir.exist?('.git')
1528
+ begin
1529
+ git_status = `git status --porcelain`.strip
1530
+ context[:git_status] = {
1531
+ modified_files: git_status.lines.count { |line| line.start_with?(' M', 'M ') },
1532
+ untracked_files: git_status.lines.count { |line| line.start_with?('??') },
1533
+ staged_files: git_status.lines.count { |line| line.start_with?('A ', 'M ') }
1534
+ }
1535
+ context[:changed_files] = git_status.lines.map { |line| line[3..-1]&.strip }.compact
1536
+ rescue StandardError
1537
+ context[:git_status] = {}
1538
+ context[:changed_files] = []
1539
+ end
1540
+ end
1541
+
1542
+ # Get current directory structure
1543
+ context[:project_files] = {
1544
+ package_json: File.exist?('package.json'),
1545
+ gemfile: File.exist?('Gemfile'),
1546
+ dockerfile: File.exist?('Dockerfile'),
1547
+ readme: File.exist?('README.md')
1548
+ }
1549
+
1550
+ # Get current time context
1551
+ context[:time_context] = {
1552
+ hour: Time.now.hour,
1553
+ day_of_week: Time.now.strftime('%A').downcase,
1554
+ timestamp: Time.now.iso8601
1555
+ }
1556
+
1557
+ # Get enhance_swarm status
1558
+ begin
1559
+ monitor = Monitor.new
1560
+ swarm_status = monitor.status
1561
+ context[:swarm_status] = {
1562
+ active_agents: swarm_status[:active_agents],
1563
+ recent_branches: swarm_status[:recent_branches]&.count || 0,
1564
+ worktrees: swarm_status[:worktrees]&.count || 0
1565
+ }
1566
+ rescue StandardError
1567
+ context[:swarm_status] = { active_agents: 0, recent_branches: 0, worktrees: 0 }
1568
+ end
1569
+
1570
+ context
1571
+ end
1572
+
1573
+ desc 'ui', 'Start the EnhanceSwarm Web UI'
1574
+ option :port, type: :numeric, default: 4567, desc: 'Port to run the web server on'
1575
+ option :host, type: :string, default: 'localhost', desc: 'Host to bind the web server to'
1576
+ def ui
1577
+ say '🌐 Starting EnhanceSwarm Web UI...', :blue
1578
+
1579
+ web_ui = WebUI.new(port: options[:port], host: options[:host])
1580
+ web_ui.start
1581
+ rescue Interrupt
1582
+ say '\nšŸ‘‹ Web UI stopped', :yellow
1583
+ rescue StandardError => e
1584
+ say "āŒ Failed to start Web UI: #{e.message}", :red
1585
+ exit 1
1586
+ end
1587
+ end
1588
+ end
1589
+
1590
+ # Load additional commands
1591
+ require_relative 'additional_commands'
1592
+ EnhanceSwarm::AdditionalCommands.add_commands_to(EnhanceSwarm::CLI)