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.
- checksums.yaml +7 -0
- data/.enhance_swarm/agent_scripts/frontend_agent.md +39 -0
- data/.enhance_swarm/user_patterns.json +37 -0
- data/CHANGELOG.md +184 -0
- data/LICENSE +21 -0
- data/PRODUCTION_TEST_LOG.md +502 -0
- data/README.md +905 -0
- data/Rakefile +28 -0
- data/USAGE_EXAMPLES.md +477 -0
- data/examples/enhance_workflow.md +346 -0
- data/examples/rails_project.md +253 -0
- data/exe/enhance-swarm +30 -0
- data/lib/enhance_swarm/additional_commands.rb +299 -0
- data/lib/enhance_swarm/agent_communicator.rb +460 -0
- data/lib/enhance_swarm/agent_reviewer.rb +283 -0
- data/lib/enhance_swarm/agent_spawner.rb +462 -0
- data/lib/enhance_swarm/cleanup_manager.rb +245 -0
- data/lib/enhance_swarm/cli.rb +1592 -0
- data/lib/enhance_swarm/command_executor.rb +78 -0
- data/lib/enhance_swarm/configuration.rb +324 -0
- data/lib/enhance_swarm/control_agent.rb +307 -0
- data/lib/enhance_swarm/dependency_validator.rb +195 -0
- data/lib/enhance_swarm/error_recovery.rb +785 -0
- data/lib/enhance_swarm/generator.rb +194 -0
- data/lib/enhance_swarm/interrupt_handler.rb +512 -0
- data/lib/enhance_swarm/logger.rb +106 -0
- data/lib/enhance_swarm/mcp_integration.rb +85 -0
- data/lib/enhance_swarm/monitor.rb +28 -0
- data/lib/enhance_swarm/notification_manager.rb +444 -0
- data/lib/enhance_swarm/orchestrator.rb +313 -0
- data/lib/enhance_swarm/output_streamer.rb +281 -0
- data/lib/enhance_swarm/process_monitor.rb +266 -0
- data/lib/enhance_swarm/progress_tracker.rb +215 -0
- data/lib/enhance_swarm/project_analyzer.rb +612 -0
- data/lib/enhance_swarm/resource_manager.rb +177 -0
- data/lib/enhance_swarm/retry_handler.rb +40 -0
- data/lib/enhance_swarm/session_manager.rb +247 -0
- data/lib/enhance_swarm/signal_handler.rb +95 -0
- data/lib/enhance_swarm/smart_defaults.rb +708 -0
- data/lib/enhance_swarm/task_integration.rb +150 -0
- data/lib/enhance_swarm/task_manager.rb +174 -0
- data/lib/enhance_swarm/version.rb +5 -0
- data/lib/enhance_swarm/visual_dashboard.rb +555 -0
- data/lib/enhance_swarm/web_ui.rb +211 -0
- data/lib/enhance_swarm.rb +69 -0
- data/setup.sh +86 -0
- data/sig/enhance_swarm.rbs +4 -0
- data/templates/claude/CLAUDE.md +160 -0
- data/templates/claude/MCP.md +117 -0
- data/templates/claude/PERSONAS.md +114 -0
- data/templates/claude/RULES.md +221 -0
- data/test_builtin_functionality.rb +121 -0
- data/test_core_components.rb +156 -0
- data/test_real_claude_integration.rb +285 -0
- data/test_security.rb +150 -0
- data/test_smart_defaults.rb +155 -0
- data/test_task_integration.rb +173 -0
- data/test_web_ui.rb +245 -0
- data/web/assets/css/main.css +645 -0
- data/web/assets/js/kanban.js +499 -0
- data/web/assets/js/main.js +525 -0
- data/web/templates/dashboard.html.erb +226 -0
- data/web/templates/kanban.html.erb +193 -0
- 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)
|