enhance_swarm 2.0.0 → 2.1.1

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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/CLAUDE.md +164 -0
  3. data/.claude/MCP.md +117 -0
  4. data/.claude/PERSONAS.md +114 -0
  5. data/.claude/RULES.md +221 -0
  6. data/.enhance_swarm/logs/general_output.log +0 -404
  7. data/.enhance_swarm.yml +33 -0
  8. data/CHANGELOG.md +71 -0
  9. data/PRODUCTION_INSTALL_TEST.md +117 -0
  10. data/README.md +129 -3
  11. data/lib/enhance_swarm/agent_spawner.rb +218 -12
  12. data/lib/enhance_swarm/cli.rb +130 -1
  13. data/lib/enhance_swarm/task_coordinator.rb +363 -86
  14. data/lib/enhance_swarm/version.rb +1 -1
  15. metadata +14 -97
  16. data/PRODUCTION_TEST_LOG.md +0 -502
  17. data/debug_agent_spawner.rb +0 -99
  18. data/debug_cli_spawn.rb +0 -95
  19. data/debug_fixes.rb +0 -209
  20. data/debug_script_execution.rb +0 -124
  21. data/debug_session_issue.rb +0 -87
  22. data/debug_spawn.rb +0 -113
  23. data/debug_spawn_step_by_step.rb +0 -190
  24. data/debug_worktree.rb +0 -77
  25. data/enhance_swarm-0.1.1.gem +0 -0
  26. data/enhance_swarm-1.0.0.gem +0 -0
  27. data/final_validation_test.rb +0 -199
  28. data/setup.sh +0 -86
  29. data/test_blog_app/.enhance_swarm/archives/session_1751187575_e119ea73_20250629_105935.json +0 -16
  30. data/test_blog_app/.enhance_swarm/archives/session_1751187637_7fda97dd_20250629_110037.json +0 -32
  31. data/test_blog_app/.enhance_swarm/archives/session_1751190527_4c99147e_20250629_114847.json +0 -32
  32. data/test_blog_app/.enhance_swarm/archives/session_1751190541_8dc83406_20250629_114901.json +0 -16
  33. data/test_blog_app/.ruby-version +0 -1
  34. data/test_blog_app/Gemfile +0 -18
  35. data/test_blog_app/Gemfile.lock +0 -206
  36. data/test_blog_app/README.md +0 -24
  37. data/test_blog_app/Rakefile +0 -6
  38. data/test_blog_app/app/assets/images/.keep +0 -0
  39. data/test_blog_app/app/assets/stylesheets/application.css +0 -10
  40. data/test_blog_app/app/controllers/application_controller.rb +0 -4
  41. data/test_blog_app/app/controllers/concerns/.keep +0 -0
  42. data/test_blog_app/app/helpers/application_helper.rb +0 -2
  43. data/test_blog_app/app/models/application_record.rb +0 -3
  44. data/test_blog_app/app/models/concerns/.keep +0 -0
  45. data/test_blog_app/app/views/layouts/application.html.erb +0 -27
  46. data/test_blog_app/app/views/pwa/manifest.json.erb +0 -22
  47. data/test_blog_app/app/views/pwa/service-worker.js +0 -26
  48. data/test_blog_app/bin/dev +0 -2
  49. data/test_blog_app/bin/rails +0 -4
  50. data/test_blog_app/bin/rake +0 -4
  51. data/test_blog_app/bin/setup +0 -34
  52. data/test_blog_app/config/application.rb +0 -42
  53. data/test_blog_app/config/boot.rb +0 -3
  54. data/test_blog_app/config/credentials.yml.enc +0 -1
  55. data/test_blog_app/config/database.yml +0 -32
  56. data/test_blog_app/config/environment.rb +0 -5
  57. data/test_blog_app/config/environments/development.rb +0 -51
  58. data/test_blog_app/config/environments/production.rb +0 -67
  59. data/test_blog_app/config/environments/test.rb +0 -42
  60. data/test_blog_app/config/initializers/assets.rb +0 -7
  61. data/test_blog_app/config/initializers/content_security_policy.rb +0 -25
  62. data/test_blog_app/config/initializers/filter_parameter_logging.rb +0 -8
  63. data/test_blog_app/config/initializers/inflections.rb +0 -16
  64. data/test_blog_app/config/locales/en.yml +0 -31
  65. data/test_blog_app/config/master.key +0 -1
  66. data/test_blog_app/config/puma.rb +0 -38
  67. data/test_blog_app/config/routes.rb +0 -14
  68. data/test_blog_app/config.ru +0 -6
  69. data/test_blog_app/db/seeds.rb +0 -9
  70. data/test_blog_app/lib/tasks/.keep +0 -0
  71. data/test_blog_app/log/.keep +0 -0
  72. data/test_blog_app/public/400.html +0 -114
  73. data/test_blog_app/public/404.html +0 -114
  74. data/test_blog_app/public/406-unsupported-browser.html +0 -114
  75. data/test_blog_app/public/422.html +0 -114
  76. data/test_blog_app/public/500.html +0 -114
  77. data/test_blog_app/public/icon.png +0 -0
  78. data/test_blog_app/public/icon.svg +0 -3
  79. data/test_blog_app/public/robots.txt +0 -1
  80. data/test_blog_app/script/.keep +0 -0
  81. data/test_blog_app/storage/.keep +0 -0
  82. data/test_blog_app/test/controllers/.keep +0 -0
  83. data/test_blog_app/test/fixtures/files/.keep +0 -0
  84. data/test_blog_app/test/helpers/.keep +0 -0
  85. data/test_blog_app/test/integration/.keep +0 -0
  86. data/test_blog_app/test/models/.keep +0 -0
  87. data/test_blog_app/test/test_helper.rb +0 -15
  88. data/test_blog_app/test_enhance_swarm_e2e.rb +0 -244
  89. data/test_blog_app/test_realistic_workflow.rb +0 -292
  90. data/test_blog_app/tmp/.keep +0 -0
  91. data/test_blog_app/tmp/pids/.keep +0 -0
  92. data/test_blog_app/tmp/storage/.keep +0 -0
  93. data/test_blog_app/vendor/.keep +0 -0
  94. data/test_builtin_functionality.rb +0 -121
  95. data/test_complete_system.rb +0 -267
  96. data/test_core_components.rb +0 -156
  97. data/test_real_claude_integration.rb +0 -285
  98. data/test_security.rb +0 -150
  99. data/test_smart_defaults.rb +0 -155
  100. data/test_task_integration.rb +0 -173
  101. data/test_web_ui.rb +0 -245
  102. data/web/assets/css/main.css +0 -645
  103. data/web/assets/js/kanban.js +0 -499
  104. data/web/assets/js/main.js +0 -525
  105. data/web/templates/dashboard.html.erb +0 -226
  106. data/web/templates/kanban.html.erb +0 -193
@@ -1,525 +0,0 @@
1
- // EnhanceSwarm Web UI JavaScript
2
-
3
- // Global state
4
- window.EnhanceSwarm = {
5
- status: {},
6
- tasks: {},
7
- agents: [],
8
- config: {},
9
- refreshInterval: null
10
- };
11
-
12
- // API helper functions
13
- async function apiRequest(endpoint, options = {}) {
14
- try {
15
- const response = await fetch(endpoint, {
16
- headers: {
17
- 'Content-Type': 'application/json',
18
- ...options.headers
19
- },
20
- ...options
21
- });
22
-
23
- if (!response.ok) {
24
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
25
- }
26
-
27
- return await response.json();
28
- } catch (error) {
29
- console.error('API request failed:', error);
30
- showNotification('API request failed: ' + error.message, 'error');
31
- throw error;
32
- }
33
- }
34
-
35
- // Dashboard functions
36
- async function initializeDashboard() {
37
- try {
38
- await Promise.all([
39
- loadStatus(),
40
- loadConfig(),
41
- loadProjectInfo()
42
- ]);
43
-
44
- updateDashboard();
45
- } catch (error) {
46
- console.error('Failed to initialize dashboard:', error);
47
- showNotification('Failed to load dashboard data', 'error');
48
- }
49
- }
50
-
51
- async function loadStatus() {
52
- try {
53
- const status = await apiRequest('/api/status');
54
- window.EnhanceSwarm.status = status;
55
- return status;
56
- } catch (error) {
57
- console.error('Failed to load status:', error);
58
- return {};
59
- }
60
- }
61
-
62
- async function loadTasks() {
63
- try {
64
- const tasks = await apiRequest('/api/tasks');
65
- window.EnhanceSwarm.tasks = tasks;
66
- return tasks;
67
- } catch (error) {
68
- console.error('Failed to load tasks:', error);
69
- return { tasks: [], folders: [] };
70
- }
71
- }
72
-
73
- async function loadConfig() {
74
- try {
75
- const config = await apiRequest('/api/config');
76
- window.EnhanceSwarm.config = config;
77
- return config;
78
- } catch (error) {
79
- console.error('Failed to load config:', error);
80
- return {};
81
- }
82
- }
83
-
84
- async function loadProjectInfo() {
85
- try {
86
- const projectInfo = await apiRequest('/api/project/analyze');
87
- window.EnhanceSwarm.projectInfo = projectInfo;
88
- return projectInfo;
89
- } catch (error) {
90
- console.error('Failed to load project info:', error);
91
- return {};
92
- }
93
- }
94
-
95
- function updateDashboard() {
96
- updateStatusOverview();
97
- updateActiveAgents();
98
- updateRecentTasks();
99
- updateSystemHealth();
100
- updateProjectInfo();
101
- }
102
-
103
- function updateStatusOverview() {
104
- const status = window.EnhanceSwarm.status;
105
-
106
- // Session status
107
- const sessionStatus = document.getElementById('session-status');
108
- if (sessionStatus) {
109
- const icon = sessionStatus.querySelector('i');
110
- const value = sessionStatus.querySelector('.status-value');
111
-
112
- if (status.session_exists) {
113
- icon.className = 'fas fa-circle';
114
- icon.style.color = '#27ae60';
115
- value.textContent = 'Active';
116
- } else {
117
- icon.className = 'fas fa-circle';
118
- icon.style.color = '#7f8c8d';
119
- value.textContent = 'Inactive';
120
- }
121
- }
122
-
123
- // Agents status
124
- const agentsStatus = document.getElementById('agents-status');
125
- if (agentsStatus) {
126
- const value = agentsStatus.querySelector('.status-value');
127
- value.textContent = status.active_agents || 0;
128
- }
129
-
130
- // Tasks status
131
- const tasksStatus = document.getElementById('tasks-status');
132
- if (tasksStatus) {
133
- const value = tasksStatus.querySelector('.status-value');
134
- const tasks = window.EnhanceSwarm.tasks;
135
- value.textContent = tasks.tasks ? tasks.tasks.length : 0;
136
- }
137
- }
138
-
139
- function updateActiveAgents() {
140
- const container = document.getElementById('active-agents-list');
141
- if (!container) return;
142
-
143
- const status = window.EnhanceSwarm.status;
144
-
145
- if (!status.agents || status.agents.length === 0) {
146
- container.innerHTML = '<div class="text-center text-secondary">No active agents</div>';
147
- return;
148
- }
149
-
150
- const activeAgents = status.agents.filter(agent => agent.status === 'running');
151
-
152
- if (activeAgents.length === 0) {
153
- container.innerHTML = '<div class="text-center text-secondary">No active agents</div>';
154
- return;
155
- }
156
-
157
- container.innerHTML = activeAgents.map(agent => `
158
- <div class="agent-item">
159
- <div class="agent-icon">
160
- <i class="fas fa-robot" style="color: #27ae60;"></i>
161
- </div>
162
- <div class="agent-info">
163
- <div class="agent-role">${agent.role.toUpperCase()}</div>
164
- <div class="agent-details">PID: ${agent.pid} | Runtime: ${calculateRuntime(agent.start_time)}</div>
165
- </div>
166
- </div>
167
- `).join('');
168
- }
169
-
170
- function updateRecentTasks() {
171
- const container = document.getElementById('recent-tasks-list');
172
- if (!container) return;
173
-
174
- const tasks = window.EnhanceSwarm.tasks;
175
-
176
- if (!tasks.tasks || tasks.tasks.length === 0) {
177
- container.innerHTML = '<div class="text-center text-secondary">No tasks found</div>';
178
- return;
179
- }
180
-
181
- const recentTasks = tasks.tasks.slice(0, 5);
182
-
183
- container.innerHTML = recentTasks.map(task => `
184
- <div class="task-item">
185
- <div class="task-title">${task.title || 'Untitled Task'}</div>
186
- <div class="task-status">${task.status || 'unknown'}</div>
187
- </div>
188
- `).join('');
189
- }
190
-
191
- function updateSystemHealth() {
192
- const container = document.getElementById('system-health');
193
- if (!container) return;
194
-
195
- const config = window.EnhanceSwarm.config;
196
- const status = window.EnhanceSwarm.status;
197
-
198
- const healthItems = [
199
- {
200
- name: 'Configuration',
201
- status: Object.keys(config).length > 0 ? 'healthy' : 'warning',
202
- message: Object.keys(config).length > 0 ? 'Loaded' : 'No config found'
203
- },
204
- {
205
- name: 'Task Management',
206
- status: window.EnhanceSwarm.tasks.swarm_tasks_available ? 'healthy' : 'warning',
207
- message: window.EnhanceSwarm.tasks.swarm_tasks_available ? 'Available' : 'Limited functionality'
208
- },
209
- {
210
- name: 'Agent System',
211
- status: status.session_exists ? 'healthy' : 'inactive',
212
- message: status.session_exists ? 'Session active' : 'No active session'
213
- }
214
- ];
215
-
216
- container.innerHTML = healthItems.map(item => `
217
- <div class="health-item">
218
- <div class="health-icon">
219
- <i class="fas fa-${item.status === 'healthy' ? 'check-circle' : item.status === 'warning' ? 'exclamation-triangle' : 'times-circle'}"
220
- style="color: ${item.status === 'healthy' ? '#27ae60' : item.status === 'warning' ? '#f39c12' : '#e74c3c'};"></i>
221
- </div>
222
- <div class="health-info">
223
- <div class="health-name">${item.name}</div>
224
- <div class="health-message">${item.message}</div>
225
- </div>
226
- </div>
227
- `).join('');
228
- }
229
-
230
- function updateProjectInfo() {
231
- const container = document.getElementById('project-info');
232
- if (!container) return;
233
-
234
- const projectInfo = window.EnhanceSwarm.projectInfo;
235
-
236
- if (!projectInfo || !projectInfo.analysis) {
237
- container.innerHTML = '<div class="text-center text-secondary">No project analysis available</div>';
238
- return;
239
- }
240
-
241
- const analysis = projectInfo.analysis;
242
-
243
- container.innerHTML = `
244
- <div class="project-detail">
245
- <strong>Type:</strong> ${analysis.project_type || 'Unknown'}
246
- </div>
247
- <div class="project-detail">
248
- <strong>Stack:</strong> ${analysis.technology_stack ? analysis.technology_stack.join(', ') : 'Not detected'}
249
- </div>
250
- <div class="project-detail">
251
- <strong>Testing:</strong> ${analysis.testing_framework ? analysis.testing_framework.join(', ') : 'None detected'}
252
- </div>
253
- <div class="project-detail">
254
- <strong>Documentation:</strong> ${analysis.documentation && analysis.documentation.has_docs ? 'Available' : 'None found'}
255
- </div>
256
- `;
257
- }
258
-
259
- // Agent management
260
- async function spawnAgent() {
261
- openModal('spawn-agent-modal');
262
- }
263
-
264
- async function submitSpawnAgent(formData) {
265
- try {
266
- const result = await apiRequest('/api/agents/spawn', {
267
- method: 'POST',
268
- body: JSON.stringify(formData)
269
- });
270
-
271
- if (result.success) {
272
- showNotification(`${formData.role.charAt(0).toUpperCase() + formData.role.slice(1)} agent spawned successfully (PID: ${result.pid})`, 'success');
273
- closeModal('spawn-agent-modal');
274
- await refreshData();
275
- } else {
276
- throw new Error(result.message);
277
- }
278
- } catch (error) {
279
- showNotification('Failed to spawn agent: ' + error.message, 'error');
280
- }
281
- }
282
-
283
- // Quick actions
284
- async function enhanceProject() {
285
- showNotification('Starting project enhancement...', 'info');
286
- // This would trigger the enhance protocol
287
- // For now, just show a message
288
- setTimeout(() => {
289
- showNotification('Enhancement protocol would be triggered here', 'info');
290
- }, 1000);
291
- }
292
-
293
- async function analyzeProject() {
294
- showNotification('Analyzing project...', 'info');
295
- try {
296
- await loadProjectInfo();
297
- updateProjectInfo();
298
- showNotification('Project analysis completed', 'success');
299
- } catch (error) {
300
- showNotification('Project analysis failed: ' + error.message, 'error');
301
- }
302
- }
303
-
304
- function viewMonitoring() {
305
- window.location.href = '/agents';
306
- }
307
-
308
- function setupTasks() {
309
- window.location.href = '/kanban';
310
- }
311
-
312
- // Utility functions
313
- function calculateRuntime(startTime) {
314
- if (!startTime) return 'Unknown';
315
-
316
- try {
317
- const start = new Date(startTime);
318
- const now = new Date();
319
- const diff = Math.floor((now - start) / 1000);
320
-
321
- if (diff < 60) return `${diff}s`;
322
- if (diff < 3600) return `${Math.floor(diff / 60)}m`;
323
- return `${Math.floor(diff / 3600)}h`;
324
- } catch (error) {
325
- return 'Unknown';
326
- }
327
- }
328
-
329
- function formatDate(dateString) {
330
- if (!dateString) return 'Unknown';
331
-
332
- try {
333
- const date = new Date(dateString);
334
- return date.toLocaleString();
335
- } catch (error) {
336
- return 'Unknown';
337
- }
338
- }
339
-
340
- // Modal management
341
- function openModal(modalId) {
342
- const modal = document.getElementById(modalId);
343
- if (modal) {
344
- modal.classList.add('show');
345
- document.body.style.overflow = 'hidden';
346
- }
347
- }
348
-
349
- function closeModal(modalId) {
350
- const modal = document.getElementById(modalId);
351
- if (modal) {
352
- modal.classList.remove('show');
353
- document.body.style.overflow = '';
354
- }
355
- }
356
-
357
- // Click outside modal to close
358
- document.addEventListener('click', function(event) {
359
- if (event.target.classList.contains('modal')) {
360
- closeModal(event.target.id);
361
- }
362
- });
363
-
364
- // Escape key to close modal
365
- document.addEventListener('keydown', function(event) {
366
- if (event.key === 'Escape') {
367
- const openModal = document.querySelector('.modal.show');
368
- if (openModal) {
369
- closeModal(openModal.id);
370
- }
371
- }
372
- });
373
-
374
- // Form handling
375
- document.addEventListener('submit', function(event) {
376
- if (event.target.id === 'spawn-agent-form') {
377
- event.preventDefault();
378
-
379
- const formData = new FormData(event.target);
380
- const data = {
381
- role: formData.get('role'),
382
- task: formData.get('task'),
383
- worktree: formData.get('worktree') === 'on'
384
- };
385
-
386
- submitSpawnAgent(data);
387
- }
388
- });
389
-
390
- // Notifications
391
- function showNotification(message, type = 'info') {
392
- // Create notification element
393
- const notification = document.createElement('div');
394
- notification.className = `notification notification-${type}`;
395
- notification.innerHTML = `
396
- <div class="notification-content">
397
- <i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i>
398
- <span>${message}</span>
399
- </div>
400
- <button class="notification-close" onclick="this.parentElement.remove()">
401
- <i class="fas fa-times"></i>
402
- </button>
403
- `;
404
-
405
- // Add to page
406
- let container = document.getElementById('notification-container');
407
- if (!container) {
408
- container = document.createElement('div');
409
- container.id = 'notification-container';
410
- container.style.cssText = `
411
- position: fixed;
412
- top: 20px;
413
- right: 20px;
414
- z-index: 10000;
415
- max-width: 400px;
416
- `;
417
- document.body.appendChild(container);
418
- }
419
-
420
- container.appendChild(notification);
421
-
422
- // Auto remove after 5 seconds
423
- setTimeout(() => {
424
- if (notification.parentElement) {
425
- notification.remove();
426
- }
427
- }, 5000);
428
- }
429
-
430
- // Auto refresh
431
- function startAutoRefresh() {
432
- // Refresh every 30 seconds
433
- window.EnhanceSwarm.refreshInterval = setInterval(async () => {
434
- try {
435
- await Promise.all([
436
- loadStatus(),
437
- loadTasks()
438
- ]);
439
- updateDashboard();
440
- } catch (error) {
441
- console.error('Auto refresh failed:', error);
442
- }
443
- }, 30000);
444
- }
445
-
446
- function stopAutoRefresh() {
447
- if (window.EnhanceSwarm.refreshInterval) {
448
- clearInterval(window.EnhanceSwarm.refreshInterval);
449
- window.EnhanceSwarm.refreshInterval = null;
450
- }
451
- }
452
-
453
- async function refreshData() {
454
- try {
455
- await Promise.all([
456
- loadStatus(),
457
- loadTasks(),
458
- loadConfig()
459
- ]);
460
- updateDashboard();
461
- showNotification('Data refreshed', 'success');
462
- } catch (error) {
463
- showNotification('Failed to refresh data', 'error');
464
- }
465
- }
466
-
467
- // Add notification styles to head
468
- const notificationStyles = `
469
- .notification {
470
- background: white;
471
- border-radius: 8px;
472
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
473
- margin-bottom: 10px;
474
- padding: 16px;
475
- display: flex;
476
- justify-content: space-between;
477
- align-items: center;
478
- animation: slideInRight 0.3s ease;
479
- }
480
-
481
- .notification-success { border-left: 4px solid #27ae60; }
482
- .notification-error { border-left: 4px solid #e74c3c; }
483
- .notification-info { border-left: 4px solid #3498db; }
484
-
485
- .notification-content {
486
- display: flex;
487
- align-items: center;
488
- }
489
-
490
- .notification-content i {
491
- margin-right: 8px;
492
- font-size: 18px;
493
- }
494
-
495
- .notification-success .notification-content i { color: #27ae60; }
496
- .notification-error .notification-content i { color: #e74c3c; }
497
- .notification-info .notification-content i { color: #3498db; }
498
-
499
- .notification-close {
500
- background: none;
501
- border: none;
502
- cursor: pointer;
503
- color: #7f8c8d;
504
- padding: 4px;
505
- }
506
-
507
- .notification-close:hover {
508
- color: #2c3e50;
509
- }
510
-
511
- @keyframes slideInRight {
512
- from {
513
- transform: translateX(100%);
514
- opacity: 0;
515
- }
516
- to {
517
- transform: translateX(0);
518
- opacity: 1;
519
- }
520
- }
521
- `;
522
-
523
- const styleSheet = document.createElement('style');
524
- styleSheet.textContent = notificationStyles;
525
- document.head.appendChild(styleSheet);