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,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'logger'
4
+
5
+ module EnhanceSwarm
6
+ class TaskIntegration
7
+ def initialize
8
+ @tasks_available = check_swarm_tasks_availability
9
+ end
10
+
11
+ def swarm_tasks_available?
12
+ @tasks_available
13
+ end
14
+
15
+ def list_tasks
16
+ return [] unless @tasks_available
17
+
18
+ begin
19
+ output = `bundle exec swarm-tasks list --format=json 2>/dev/null`
20
+ return [] if output.empty?
21
+
22
+ JSON.parse(output)
23
+ rescue JSON::ParserError, StandardError => e
24
+ Logger.warn("Failed to parse swarm-tasks output: #{e.message}")
25
+ []
26
+ end
27
+ end
28
+
29
+ def get_active_tasks
30
+ tasks = list_tasks
31
+ tasks.select { |task| task['status'] == 'active' || task['status'] == 'in_progress' }
32
+ end
33
+
34
+ def move_task(task_id, status)
35
+ return false unless @tasks_available
36
+
37
+ begin
38
+ result = `bundle exec swarm-tasks move #{task_id} #{status} 2>/dev/null`
39
+ $?.success?
40
+ rescue StandardError => e
41
+ Logger.error("Failed to move task #{task_id} to #{status}: #{e.message}")
42
+ false
43
+ end
44
+ end
45
+
46
+ def create_task(title, description = nil, priority = 'medium')
47
+ return false unless @tasks_available
48
+
49
+ begin
50
+ cmd = "bundle exec swarm-tasks create \"#{title}\""
51
+ cmd += " --description=\"#{description}\"" if description
52
+ cmd += " --priority=#{priority}"
53
+ cmd += " 2>/dev/null"
54
+
55
+ result = `#{cmd}`
56
+ $?.success?
57
+ rescue StandardError => e
58
+ Logger.error("Failed to create task: #{e.message}")
59
+ false
60
+ end
61
+ end
62
+
63
+ def get_task_folders
64
+ return [] unless @tasks_available
65
+
66
+ begin
67
+ # Look for tasks directory structure
68
+ tasks_dir = File.join(Dir.pwd, 'tasks')
69
+ return [] unless Dir.exist?(tasks_dir)
70
+
71
+ folders = []
72
+ Dir.glob(File.join(tasks_dir, '*')).each do |path|
73
+ next unless File.directory?(path)
74
+
75
+ folder_name = File.basename(path)
76
+ task_files = Dir.glob(File.join(path, '*.md')).length
77
+
78
+ folders << {
79
+ name: folder_name,
80
+ path: path,
81
+ task_count: task_files,
82
+ status: folder_name # todo, in_progress, done, etc.
83
+ }
84
+ end
85
+
86
+ folders
87
+ rescue StandardError => e
88
+ Logger.warn("Failed to analyze task folders: #{e.message}")
89
+ []
90
+ end
91
+ end
92
+
93
+ def get_kanban_data
94
+ {
95
+ swarm_tasks_available: @tasks_available,
96
+ tasks: list_tasks,
97
+ folders: get_task_folders,
98
+ active_tasks: get_active_tasks
99
+ }
100
+ end
101
+
102
+ def setup_task_management
103
+ return false unless @tasks_available
104
+
105
+ begin
106
+ # Initialize swarm-tasks if not already done
107
+ unless Dir.exist?(File.join(Dir.pwd, 'tasks'))
108
+ Logger.info("Initializing swarm-tasks for project")
109
+ `bundle exec swarm-tasks init 2>/dev/null`
110
+ end
111
+
112
+ # Create default task categories if they don't exist
113
+ default_folders = ['todo', 'in_progress', 'review', 'done']
114
+ tasks_dir = File.join(Dir.pwd, 'tasks')
115
+
116
+ default_folders.each do |folder|
117
+ folder_path = File.join(tasks_dir, folder)
118
+ unless Dir.exist?(folder_path)
119
+ FileUtils.mkdir_p(folder_path)
120
+ Logger.info("Created task folder: #{folder}")
121
+ end
122
+ end
123
+
124
+ true
125
+ rescue StandardError => e
126
+ Logger.error("Failed to setup task management: #{e.message}")
127
+ false
128
+ end
129
+ end
130
+
131
+ private
132
+
133
+ def check_swarm_tasks_availability
134
+ begin
135
+ # Check if swarm-tasks gem is available
136
+ require 'swarm_tasks'
137
+
138
+ # Check if swarm-tasks command is available
139
+ result = `bundle exec swarm-tasks --version 2>/dev/null`
140
+ $?.success?
141
+ rescue LoadError
142
+ Logger.warn("swarm-tasks gem not available - task management features limited")
143
+ false
144
+ rescue StandardError => e
145
+ Logger.warn("swarm-tasks not accessible: #{e.message}")
146
+ false
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'command_executor'
5
+
6
+ module EnhanceSwarm
7
+ class TaskManager
8
+ def initialize
9
+ @config = EnhanceSwarm.configuration
10
+ end
11
+
12
+ def next_priority_task
13
+ # Try to use swarm-tasks if available
14
+ if swarm_tasks_available?
15
+ list_swarm_tasks('backlog').first
16
+ else
17
+ # Fallback to simple file-based tasks
18
+ find_next_file_task
19
+ end
20
+ end
21
+
22
+ def find_task(task_id)
23
+ if swarm_tasks_available?
24
+ show_swarm_task(task_id)
25
+ else
26
+ find_file_task(task_id)
27
+ end
28
+ end
29
+
30
+ def move_task(task_id, state)
31
+ if swarm_tasks_available?
32
+ begin
33
+ CommandExecutor.execute(@config.task_command, 'move', task_id.to_s, state.to_s)
34
+ rescue CommandExecutor::CommandError => e
35
+ puts "Failed to move task: #{e.message}".colorize(:red)
36
+ false
37
+ end
38
+ else
39
+ puts 'Task management not configured. Please set up swarm-tasks.'.colorize(:yellow)
40
+ false
41
+ end
42
+ end
43
+
44
+ def list_tasks(state = 'all')
45
+ if swarm_tasks_available?
46
+ list_swarm_tasks(state)
47
+ else
48
+ list_file_tasks(state)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def swarm_tasks_available?
55
+ CommandExecutor.command_available?(@config.task_command.split.first)
56
+ rescue CommandExecutor::CommandError
57
+ false
58
+ end
59
+
60
+ def list_swarm_tasks(state)
61
+ output = CommandExecutor.execute(@config.task_command, 'list', state, '--json')
62
+ return [] if output.empty?
63
+
64
+ tasks = JSON.parse(output)
65
+ tasks.map do |task|
66
+ {
67
+ id: task['id'],
68
+ title: task['title'] || task['content'],
69
+ description: task['description'] || task['content'],
70
+ state: task['state'] || task['status'],
71
+ priority: task['priority'],
72
+ effort: task['effort'],
73
+ tags: task['tags'] || []
74
+ }
75
+ end
76
+ rescue CommandExecutor::CommandError, JSON::ParserError
77
+ []
78
+ end
79
+
80
+ def show_swarm_task(task_id)
81
+ output = CommandExecutor.execute(@config.task_command, 'show', task_id.to_s, '--json')
82
+ return nil if output.empty?
83
+
84
+ task = JSON.parse(output)
85
+ {
86
+ id: task['id'],
87
+ title: task['title'] || task['content'],
88
+ description: task['description'] || task['content'],
89
+ state: task['state'] || task['status'],
90
+ priority: task['priority'],
91
+ effort: task['effort'],
92
+ tags: task['tags'] || []
93
+ }
94
+ rescue CommandExecutor::CommandError, JSON::ParserError
95
+ nil
96
+ end
97
+
98
+ def find_next_file_task
99
+ # Simple file-based task system fallback
100
+ task_dir = File.join(EnhanceSwarm.root, 'tasks', 'backlog')
101
+ return nil unless Dir.exist?(task_dir)
102
+
103
+ task_files = Dir.glob(File.join(task_dir, '*.md')).sort
104
+ return nil if task_files.empty?
105
+
106
+ task_file = task_files.first
107
+ content = File.read(task_file)
108
+
109
+ {
110
+ id: File.basename(task_file, '.md'),
111
+ title: extract_title(content),
112
+ description: content,
113
+ state: 'backlog',
114
+ priority: 'medium',
115
+ effort: 4,
116
+ tags: []
117
+ }
118
+ end
119
+
120
+ def find_file_task(task_id)
121
+ %w[backlog active completed].each do |state|
122
+ task_file = File.join(EnhanceSwarm.root, 'tasks', state, "#{task_id}.md")
123
+ next unless File.exist?(task_file)
124
+
125
+ content = File.read(task_file)
126
+ return {
127
+ id: task_id,
128
+ title: extract_title(content),
129
+ description: content,
130
+ state: state,
131
+ priority: 'medium',
132
+ effort: 4,
133
+ tags: []
134
+ }
135
+ end
136
+ nil
137
+ end
138
+
139
+ def list_file_tasks(state)
140
+ tasks = []
141
+
142
+ states = state == 'all' ? %w[backlog active completed] : [state]
143
+
144
+ states.each do |s|
145
+ task_dir = File.join(EnhanceSwarm.root, 'tasks', s)
146
+ next unless Dir.exist?(task_dir)
147
+
148
+ Dir.glob(File.join(task_dir, '*.md')).each do |file|
149
+ content = File.read(file)
150
+ tasks << {
151
+ id: File.basename(file, '.md'),
152
+ title: extract_title(content),
153
+ description: content,
154
+ state: s,
155
+ priority: 'medium',
156
+ effort: 4,
157
+ tags: []
158
+ }
159
+ end
160
+ end
161
+
162
+ tasks
163
+ end
164
+
165
+ def extract_title(content)
166
+ # Try to extract first heading or first line
167
+ if (match = content.match(/^#\s+(.+)$/))
168
+ match[1]
169
+ else
170
+ content.lines.first&.strip || 'Untitled Task'
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EnhanceSwarm
4
+ VERSION = '1.0.0'
5
+ end