@sparkleideas/ruv-swarm 1.0.18-patch.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 (87) hide show
  1. package/README.md +1565 -0
  2. package/bin/ruv-swarm-clean.js +1872 -0
  3. package/bin/ruv-swarm-memory.js +119 -0
  4. package/bin/ruv-swarm-secure-heartbeat.js +1549 -0
  5. package/bin/ruv-swarm-secure.js +1689 -0
  6. package/package.json +221 -0
  7. package/src/agent.ts +342 -0
  8. package/src/benchmark.js +267 -0
  9. package/src/claude-flow-enhanced.js +839 -0
  10. package/src/claude-integration/advanced-commands.js +561 -0
  11. package/src/claude-integration/core.js +112 -0
  12. package/src/claude-integration/docs.js +1548 -0
  13. package/src/claude-integration/env-template.js +39 -0
  14. package/src/claude-integration/index.js +209 -0
  15. package/src/claude-integration/remote.js +408 -0
  16. package/src/cli-diagnostics.js +364 -0
  17. package/src/cognitive-pattern-evolution.js +1317 -0
  18. package/src/daa-cognition.js +977 -0
  19. package/src/daa-service.d.ts +298 -0
  20. package/src/daa-service.js +1116 -0
  21. package/src/diagnostics.js +533 -0
  22. package/src/errors.js +528 -0
  23. package/src/github-coordinator/README.md +193 -0
  24. package/src/github-coordinator/claude-hooks.js +162 -0
  25. package/src/github-coordinator/gh-cli-coordinator.js +260 -0
  26. package/src/hooks/cli.js +82 -0
  27. package/src/hooks/index.js +1900 -0
  28. package/src/index-enhanced.d.ts +371 -0
  29. package/src/index-enhanced.js +734 -0
  30. package/src/index.d.ts +287 -0
  31. package/src/index.js +405 -0
  32. package/src/index.ts +457 -0
  33. package/src/logger.js +182 -0
  34. package/src/logging-config.js +179 -0
  35. package/src/mcp-daa-tools.js +735 -0
  36. package/src/mcp-tools-benchmarks.js +328 -0
  37. package/src/mcp-tools-enhanced.js +2863 -0
  38. package/src/memory-config.js +42 -0
  39. package/src/meta-learning-framework.js +1359 -0
  40. package/src/neural-agent.js +830 -0
  41. package/src/neural-coordination-protocol.js +1363 -0
  42. package/src/neural-models/README.md +118 -0
  43. package/src/neural-models/autoencoder.js +543 -0
  44. package/src/neural-models/base.js +269 -0
  45. package/src/neural-models/cnn.js +497 -0
  46. package/src/neural-models/gnn.js +447 -0
  47. package/src/neural-models/gru.js +536 -0
  48. package/src/neural-models/index.js +273 -0
  49. package/src/neural-models/lstm.js +551 -0
  50. package/src/neural-models/neural-presets-complete.js +1306 -0
  51. package/src/neural-models/presets/graph.js +392 -0
  52. package/src/neural-models/presets/index.js +279 -0
  53. package/src/neural-models/presets/nlp.js +328 -0
  54. package/src/neural-models/presets/timeseries.js +368 -0
  55. package/src/neural-models/presets/vision.js +387 -0
  56. package/src/neural-models/resnet.js +534 -0
  57. package/src/neural-models/transformer.js +515 -0
  58. package/src/neural-models/vae.js +489 -0
  59. package/src/neural-network-manager.js +1938 -0
  60. package/src/neural-network.ts +296 -0
  61. package/src/neural.js +574 -0
  62. package/src/performance-benchmarks.js +898 -0
  63. package/src/performance.js +458 -0
  64. package/src/persistence-pooled.js +695 -0
  65. package/src/persistence.js +480 -0
  66. package/src/schemas.js +864 -0
  67. package/src/security.js +218 -0
  68. package/src/singleton-container.js +183 -0
  69. package/src/sqlite-pool.js +587 -0
  70. package/src/sqlite-worker.js +141 -0
  71. package/src/types.ts +164 -0
  72. package/src/utils.ts +286 -0
  73. package/src/wasm-loader.js +601 -0
  74. package/src/wasm-loader2.js +404 -0
  75. package/src/wasm-memory-optimizer.js +783 -0
  76. package/src/wasm-types.d.ts +63 -0
  77. package/wasm/README.md +347 -0
  78. package/wasm/neuro-divergent.wasm +0 -0
  79. package/wasm/package.json +18 -0
  80. package/wasm/ruv-fann.wasm +0 -0
  81. package/wasm/ruv_swarm_simd.wasm +0 -0
  82. package/wasm/ruv_swarm_wasm.d.ts +391 -0
  83. package/wasm/ruv_swarm_wasm.js +2164 -0
  84. package/wasm/ruv_swarm_wasm_bg.wasm +0 -0
  85. package/wasm/ruv_swarm_wasm_bg.wasm.d.ts +123 -0
  86. package/wasm/wasm-bindings-loader.mjs +435 -0
  87. package/wasm/wasm-updates.md +684 -0
@@ -0,0 +1,193 @@
1
+ # GitHub Coordinator for ruv-swarm
2
+
3
+ Simple GitHub-based coordination for multiple Claude Code swarms working on the same repository.
4
+
5
+ ## Quick Start
6
+
7
+ ### Option 1: GitHub CLI (Recommended)
8
+
9
+ The simplest approach uses the GitHub CLI (`gh`) that you already have:
10
+
11
+ ```bash
12
+ # Install gh CLI if not already installed
13
+ # https://cli.github.com/
14
+
15
+ # Use the coordinator
16
+ npx ruv-swarm github-coordinate
17
+
18
+ # Or use directly in your swarm
19
+ const GHCoordinator = require('./gh-cli-coordinator');
20
+ const coordinator = new GHCoordinator({
21
+ owner: 'ruvnet',
22
+ repo: 'ruv-FANN'
23
+ });
24
+
25
+ # Get available tasks
26
+ const tasks = await coordinator.getAvailableTasks();
27
+
28
+ # Claim a task
29
+ await coordinator.claimTask('my-swarm-id', issueNumber);
30
+
31
+ # Update progress
32
+ await coordinator.updateTaskProgress('my-swarm-id', issueNumber, 'Working on authentication...');
33
+ ```
34
+
35
+ ### Option 2: Claude Code Hooks
36
+
37
+ Add automatic GitHub coordination to your Claude Code sessions:
38
+
39
+ 1. Add to `.claude/settings.json`:
40
+ ```json
41
+ {
42
+ "hooks": {
43
+ "pre-task": "npx ruv-swarm hook github pre-task",
44
+ "post-edit": "npx ruv-swarm hook github post-edit",
45
+ "post-task": "npx ruv-swarm hook github post-task"
46
+ }
47
+ }
48
+ ```
49
+
50
+ 2. Set environment variables:
51
+ ```bash
52
+ export GITHUB_OWNER=ruvnet
53
+ export GITHUB_REPO=ruv-FANN
54
+ export CLAUDE_SWARM_ID=my-swarm-123 # Optional, auto-generated if not set
55
+ ```
56
+
57
+ 3. Now Claude Code will automatically:
58
+ - Claim GitHub issues when starting tasks
59
+ - Update issues with progress
60
+ - Release issues when done
61
+
62
+ ### Option 3: GitHub MCP Server
63
+
64
+ If you have a GitHub MCP server, you can use it directly:
65
+
66
+ ```javascript
67
+ // Use GitHub MCP tools
68
+ mcp__github__issues_list({ state: 'open', labels: ['swarm-available'] })
69
+ mcp__github__issues_update({ number: 123, labels: ['swarm-claimed'] })
70
+ mcp__github__issues_comment({ number: 123, body: 'Progress update...' })
71
+ ```
72
+
73
+ ## How It Works
74
+
75
+ ### Task Coordination via GitHub Labels
76
+
77
+ The system uses GitHub labels to coordinate work:
78
+
79
+ - `swarm-available` - Tasks ready to be claimed
80
+ - `swarm-{id}` - Task claimed by a specific swarm
81
+ - `swarm-conflict` - Multiple swarms trying to work on same area
82
+
83
+ ### Workflow
84
+
85
+ 1. **Task Discovery**: Swarms check for open issues without swarm labels
86
+ 2. **Task Claiming**: Add a `swarm-{id}` label to claim an issue
87
+ 3. **Progress Updates**: Post comments with progress updates
88
+ 4. **Task Completion**: Remove label or close issue when done
89
+
90
+ ### Conflict Prevention
91
+
92
+ - Each swarm has a unique ID
93
+ - Issues can only have one `swarm-*` label
94
+ - Comments show which swarm is working on what
95
+ - Dashboard shows all active swarms and their tasks
96
+
97
+ ## Examples
98
+
99
+ ### Basic Coordination
100
+
101
+ ```javascript
102
+ // Initialize coordinator
103
+ const coordinator = new GHCoordinator({
104
+ owner: 'ruvnet',
105
+ repo: 'ruv-FANN',
106
+ labelPrefix: 'swarm-' // default
107
+ });
108
+
109
+ // Get coordination status
110
+ const status = await coordinator.getCoordinationStatus();
111
+ console.log(`${status.swarmTasks} tasks being worked on`);
112
+ console.log(`${status.availableTasks} tasks available`);
113
+
114
+ // Show swarm assignments
115
+ for (const [swarmId, tasks] of Object.entries(status.swarmStatus)) {
116
+ console.log(`Swarm ${swarmId} is working on:`);
117
+ tasks.forEach(task => console.log(` - #${task.number}: ${task.title}`));
118
+ }
119
+ ```
120
+
121
+ ### With Claude Code Integration
122
+
123
+ When using the hooks, Claude Code will automatically coordinate:
124
+
125
+ ```bash
126
+ # Start a task - automatically claims related GitHub issue
127
+ claude> Can you fix the authentication bug?
128
+ 🎯 Pre-task: Looking for GitHub issues related to: fix authentication bug
129
+ ✅ Claimed GitHub issue #123: Fix JWT token validation
130
+
131
+ # Make changes - automatically updates issue
132
+ claude> [edits auth.js]
133
+ 📝 Updated GitHub issue #123 with edit progress
134
+
135
+ # Complete task - automatically updates/releases issue
136
+ claude> I've fixed the authentication issue
137
+ ✅ Task Completed on GitHub issue #123
138
+ ```
139
+
140
+ ### Manual Coordination Commands
141
+
142
+ ```bash
143
+ # Check coordination status
144
+ npx ruv-swarm github status
145
+
146
+ # List available tasks
147
+ npx ruv-swarm github tasks --available
148
+
149
+ # Claim a specific task
150
+ npx ruv-swarm github claim 123
151
+
152
+ # Release a task
153
+ npx ruv-swarm github release 123
154
+
155
+ # Show dashboard URLs
156
+ npx ruv-swarm github dashboard
157
+ ```
158
+
159
+ ## Configuration
160
+
161
+ ### Environment Variables
162
+
163
+ - `GITHUB_OWNER` - Repository owner
164
+ - `GITHUB_REPO` - Repository name
165
+ - `GITHUB_TOKEN` - Personal access token (optional, uses gh CLI auth)
166
+ - `CLAUDE_SWARM_ID` - Unique swarm identifier
167
+
168
+ ### Label Configuration
169
+
170
+ Customize the label prefix in the coordinator:
171
+
172
+ ```javascript
173
+ const coordinator = new GHCoordinator({
174
+ labelPrefix: 'ai-swarm-' // Use custom prefix
175
+ });
176
+ ```
177
+
178
+ ## Benefits
179
+
180
+ 1. **Simple**: Uses existing GitHub features (labels, comments)
181
+ 2. **Visible**: All coordination visible in GitHub UI
182
+ 3. **No Extra Infrastructure**: Just needs `gh` CLI
183
+ 4. **Conflict-Free**: Labels prevent duplicate work
184
+ 5. **Auditable**: Full history in GitHub
185
+
186
+ ## Limitations
187
+
188
+ - Requires GitHub CLI or API access
189
+ - Limited to GitHub's rate limits
190
+ - Basic conflict detection (label-based)
191
+ - No real-time updates (polling-based)
192
+
193
+ For more advanced coordination, consider using the full GitHubCoordinator with a database backend or a dedicated MCP server.
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Claude Code Hooks for GitHub Coordination
3
+ * Automatically coordinates swarm activities with GitHub
4
+ */
5
+
6
+ const GHCoordinator = require('./gh-cli-coordinator');
7
+ // const fs = require('fs').promises; // Unused - will be used in future implementation
8
+ const path = require('path');
9
+
10
+ class ClaudeGitHubHooks {
11
+ constructor(options = {}) {
12
+ this.coordinator = new GHCoordinator(options);
13
+ this.swarmId = options.swarmId || this.generateSwarmId();
14
+ this.activeTask = null;
15
+ }
16
+
17
+ generateSwarmId() {
18
+ // Generate swarm ID from environment or random
19
+ return process.env.CLAUDE_SWARM_ID || `claude-${Date.now().toString(36)}`;
20
+ }
21
+
22
+ /**
23
+ * Pre-task hook: Claim a GitHub issue before starting work
24
+ */
25
+ async preTask(taskDescription) {
26
+ console.log(`🎯 Pre-task: Looking for GitHub issues related to: ${taskDescription}`);
27
+
28
+ try {
29
+ // Search for related issues
30
+ const tasks = await this.coordinator.getAvailableTasks({ state: 'open' });
31
+
32
+ // Find best matching task (simple keyword matching for now)
33
+ const keywords = taskDescription.toLowerCase().split(' ');
34
+ const matchedTask = tasks.find(task => {
35
+ const taskText = `${task.title} ${task.body || ''}`.toLowerCase();
36
+ return keywords.some(keyword => taskText.includes(keyword));
37
+ });
38
+
39
+ if (matchedTask) {
40
+ const claimed = await this.coordinator.claimTask(this.swarmId, matchedTask.number);
41
+ if (claimed) {
42
+ this.activeTask = matchedTask.number;
43
+ console.log(`✅ Claimed GitHub issue #${matchedTask.number}: ${matchedTask.title}`);
44
+ return { claimed: true, issue: matchedTask.number };
45
+ }
46
+ }
47
+
48
+ console.log('ℹ️ No matching GitHub issue found, proceeding without claim');
49
+ return { claimed: false };
50
+ } catch (error) {
51
+ console.error('❌ Pre-task hook error:', error.message);
52
+ return { error: error.message };
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Post-edit hook: Update GitHub issue with progress
58
+ */
59
+ async postEdit(filePath, changes) {
60
+ if (!this.activeTask) {
61
+ return;
62
+ }
63
+
64
+ try {
65
+ const message = `Updated \`${path.basename(filePath)}\`\n\n${changes.summary || 'File modified'}`;
66
+ await this.coordinator.updateTaskProgress(this.swarmId, this.activeTask, message);
67
+ console.log(`📝 Updated GitHub issue #${this.activeTask} with edit progress`);
68
+ } catch (error) {
69
+ console.error('❌ Post-edit hook error:', error.message);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Post-task hook: Complete or release the GitHub issue
75
+ */
76
+ async postTask(taskId, result) {
77
+ if (!this.activeTask) {
78
+ return;
79
+ }
80
+
81
+ try {
82
+ if (result.completed) {
83
+ const message = `✅ **Task Completed**\n\n${result.summary || 'Task completed successfully'}`;
84
+ await this.coordinator.updateTaskProgress(this.swarmId, this.activeTask, message);
85
+
86
+ // Option to auto-close issue (disabled by default)
87
+ if (result.autoClose) {
88
+ console.log(`🏁 Closing GitHub issue #${this.activeTask}`);
89
+ // Use gh CLI to close issue
90
+ }
91
+ } else {
92
+ await this.coordinator.releaseTask(this.swarmId, this.activeTask);
93
+ console.log(`🔓 Released GitHub issue #${this.activeTask}`);
94
+ }
95
+
96
+ this.activeTask = null;
97
+ } catch (error) {
98
+ console.error('❌ Post-task hook error:', error.message);
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Conflict detection hook
104
+ */
105
+ async detectConflicts() {
106
+ try {
107
+ const status = await this.coordinator.getCoordinationStatus();
108
+
109
+ // Check if multiple swarms are working on similar files
110
+ // const conflicts = []; // Unused - will be used in future implementation
111
+
112
+ // Simple conflict detection based on swarm count
113
+ if (Object.keys(status.swarmStatus).length > 1) {
114
+ console.log('⚠️ Multiple swarms detected, checking for conflicts...');
115
+
116
+ // More sophisticated conflict detection could be added here
117
+ // For now, just warn about multiple active swarms
118
+ return {
119
+ hasConflicts: false,
120
+ warningCount: Object.keys(status.swarmStatus).length - 1,
121
+ message: 'Multiple swarms active, coordinate through GitHub issues',
122
+ };
123
+ }
124
+
125
+ return { hasConflicts: false };
126
+ } catch (error) {
127
+ console.error('❌ Conflict detection error:', error.message);
128
+ return { error: error.message };
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Get coordination dashboard URL
134
+ */
135
+ async getDashboardUrl() {
136
+ const baseUrl = `https://github.com/${this.coordinator.config.owner}/${this.coordinator.config.repo}`;
137
+ return {
138
+ issues: `${baseUrl}/issues?q=is:issue+is:open+label:${this.coordinator.config.labelPrefix}${this.swarmId}`,
139
+ allSwarms: `${baseUrl}/issues?q=is:issue+is:open+label:${this.coordinator.config.labelPrefix}`,
140
+ board: `${baseUrl}/projects`,
141
+ };
142
+ }
143
+ }
144
+
145
+ // Hook registration for Claude Code
146
+ async function registerHooks() {
147
+ const hooks = new ClaudeGitHubHooks({
148
+ owner: process.env.GITHUB_OWNER || 'ruvnet',
149
+ repo: process.env.GITHUB_REPO || 'ruv-FANN',
150
+ });
151
+
152
+ // Register with Claude Code's hook system
153
+ return {
154
+ 'pre-task': (args) => hooks.preTask(args.description),
155
+ 'post-edit': (args) => hooks.postEdit(args.file, args.changes),
156
+ 'post-task': (args) => hooks.postTask(args.taskId, args.result),
157
+ 'check-conflicts': () => hooks.detectConflicts(),
158
+ 'get-dashboard': () => hooks.getDashboardUrl(),
159
+ };
160
+ }
161
+
162
+ module.exports = { ClaudeGitHubHooks, registerHooks };
@@ -0,0 +1,260 @@
1
+ /**
2
+ * GitHub CLI-based Coordinator for @sparkleideas/ruv-swarm
3
+ * Uses gh CLI for all GitHub operations - simpler and more reliable
4
+ */
5
+
6
+ const { execSync } = require('child_process');
7
+ const fs = require('fs').promises;
8
+ const path = require('path');
9
+ const Database = require('better-sqlite3');
10
+
11
+ class GHCoordinator {
12
+ constructor(options = {}) {
13
+ this.config = {
14
+ owner: options.owner || process.env.GITHUB_OWNER,
15
+ repo: options.repo || process.env.GITHUB_REPO,
16
+ dbPath: options.dbPath || path.join(__dirname, '..', '..', 'data', 'gh-coordinator.db'),
17
+ labelPrefix: options.labelPrefix || 'swarm-',
18
+ ...options,
19
+ };
20
+
21
+ this.db = null;
22
+ this.initialize();
23
+ }
24
+
25
+ async initialize() {
26
+ // Check if gh CLI is available
27
+ try {
28
+ execSync('gh --version', { stdio: 'ignore' });
29
+ } catch {
30
+ throw new Error('GitHub CLI (gh) is not installed. Install it from https://cli.github.com/');
31
+ }
32
+
33
+ // Setup database for local coordination state
34
+ await this.setupDatabase();
35
+ }
36
+
37
+ async setupDatabase() {
38
+ const dataDir = path.dirname(this.config.dbPath);
39
+ await fs.mkdir(dataDir, { recursive: true });
40
+
41
+ this.db = new Database(this.config.dbPath);
42
+ this.db.exec(`
43
+ CREATE TABLE IF NOT EXISTS swarm_tasks (
44
+ issue_number INTEGER PRIMARY KEY,
45
+ swarm_id TEXT,
46
+ locked_at INTEGER,
47
+ lock_expires INTEGER
48
+ );
49
+
50
+ CREATE TABLE IF NOT EXISTS swarm_registry (
51
+ swarm_id TEXT PRIMARY KEY,
52
+ user TEXT,
53
+ capabilities TEXT,
54
+ last_seen INTEGER DEFAULT (strftime('%s', 'now'))
55
+ );
56
+ `);
57
+ }
58
+
59
+ /**
60
+ * Get available tasks from GitHub issues
61
+ */
62
+ async getAvailableTasks(filters = {}) {
63
+ let cmd = `gh issue list --repo ${this.config.owner}/${this.config.repo} --json number,title,labels,assignees,state,body --limit 100`;
64
+
65
+ if (filters.label) {
66
+ cmd += ` --label "${filters.label}"`;
67
+ }
68
+ if (filters.state) {
69
+ cmd += ` --state ${filters.state}`;
70
+ }
71
+
72
+ const output = execSync(cmd, { encoding: 'utf8' });
73
+ const issues = JSON.parse(output);
74
+
75
+ // Filter out already assigned tasks
76
+ const availableIssues = issues.filter(issue => {
77
+ // Check if issue has swarm assignment label
78
+ const hasSwarmLabel = issue.labels.some(l => l.name.startsWith(this.config.labelPrefix));
79
+ // Check if issue is assigned
80
+ const isAssigned = issue.assignees.length > 0;
81
+
82
+ return !hasSwarmLabel && !isAssigned;
83
+ });
84
+
85
+ return availableIssues;
86
+ }
87
+
88
+ /**
89
+ * Claim a task for a swarm
90
+ */
91
+ async claimTask(swarmId, issueNumber) {
92
+ try {
93
+ // Add swarm label to issue
94
+ const label = `${this.config.labelPrefix}${swarmId}`;
95
+ execSync(`gh issue edit ${issueNumber} --repo ${this.config.owner}/${this.config.repo} --add-label "${label}"`, { stdio: 'ignore' });
96
+
97
+ // Add comment to issue
98
+ const comment = `🐝 Task claimed by swarm: ${swarmId}\n\nThis task is being worked on by an automated swarm agent. Updates will be posted as progress is made.`;
99
+ execSync(`gh issue comment ${issueNumber} --repo ${this.config.owner}/${this.config.repo} --body "${comment}"`, { stdio: 'ignore' });
100
+
101
+ // Record in local database
102
+ this.db.prepare(`
103
+ INSERT OR REPLACE INTO swarm_tasks (issue_number, swarm_id, locked_at, lock_expires)
104
+ VALUES (?, ?, strftime('%s', 'now'), strftime('%s', 'now', '+1 hour'))
105
+ `).run(issueNumber, swarmId);
106
+
107
+ return true;
108
+ } catch (error) {
109
+ console.error(`Failed to claim task ${issueNumber}:`, error.message);
110
+ return false;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Release a task
116
+ */
117
+ async releaseTask(swarmId, issueNumber) {
118
+ try {
119
+ const label = `${this.config.labelPrefix}${swarmId}`;
120
+ execSync(`gh issue edit ${issueNumber} --repo ${this.config.owner}/${this.config.repo} --remove-label "${label}"`, { stdio: 'ignore' });
121
+
122
+ this.db.prepare('DELETE FROM swarm_tasks WHERE issue_number = ?').run(issueNumber);
123
+ return true;
124
+ } catch (error) {
125
+ console.error(`Failed to release task ${issueNumber}:`, error.message);
126
+ return false;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Update task progress
132
+ */
133
+ async updateTaskProgress(swarmId, issueNumber, message) {
134
+ try {
135
+ const comment = `🔄 **Progress Update from swarm ${swarmId}**\n\n${message}`;
136
+ execSync(`gh issue comment ${issueNumber} --repo ${this.config.owner}/${this.config.repo} --body "${comment}"`, { stdio: 'ignore' });
137
+ return true;
138
+ } catch (error) {
139
+ console.error(`Failed to update task ${issueNumber}:`, error.message);
140
+ return false;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Create a task allocation PR
146
+ */
147
+ async createAllocationPR(allocations) {
148
+ const branch = `swarm-allocation-${Date.now()}`;
149
+
150
+ // Create allocation file
151
+ const allocationContent = {
152
+ timestamp: new Date().toISOString(),
153
+ allocations,
154
+ };
155
+
156
+ const allocationPath = '.github/swarm-allocations.json';
157
+ await fs.writeFile(allocationPath, JSON.stringify(allocationContent, null, 2));
158
+
159
+ // Create PR using gh CLI
160
+ try {
161
+ execSync(`git checkout -b ${branch}`, { stdio: 'ignore' });
162
+ execSync(`git add ${allocationPath}`, { stdio: 'ignore' });
163
+ execSync('git commit -m "Update swarm task allocations"', { stdio: 'ignore' });
164
+ execSync(`git push origin ${branch}`, { stdio: 'ignore' });
165
+
166
+ const prBody = `## Swarm Task Allocation Update
167
+
168
+ This PR updates the task allocation for active swarms.
169
+
170
+ ### Allocations:
171
+ ${allocations.map(a => `- Issue #${a.issue}: Assigned to swarm ${a.swarm_id}`).join('\n')}
172
+
173
+ This is an automated update from the swarm coordinator.`;
174
+
175
+ const output = execSync(`gh pr create --repo ${this.config.owner}/${this.config.repo} --title "Update swarm task allocations" --body "${prBody}" --base main --head ${branch}`, { encoding: 'utf8' });
176
+
177
+ return output.trim();
178
+ } catch (error) {
179
+ console.error('Failed to create allocation PR:', error.message);
180
+ return null;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Get swarm coordination status
186
+ */
187
+ async getCoordinationStatus() {
188
+ // Get issues with swarm labels
189
+ const cmd = `gh issue list --repo ${this.config.owner}/${this.config.repo} --json number,title,labels,assignees --limit 100`;
190
+ const output = execSync(cmd, { encoding: 'utf8' });
191
+ const issues = JSON.parse(output);
192
+
193
+ const swarmTasks = issues.filter(issue =>
194
+ issue.labels.some(l => l.name.startsWith(this.config.labelPrefix)),
195
+ );
196
+
197
+ // Group by swarm
198
+ const swarmStatus = {};
199
+ swarmTasks.forEach(issue => {
200
+ const swarmLabel = issue.labels.find(l => l.name.startsWith(this.config.labelPrefix));
201
+ if (swarmLabel) {
202
+ const swarmId = swarmLabel.name.replace(this.config.labelPrefix, '');
203
+ if (!swarmStatus[swarmId]) {
204
+ swarmStatus[swarmId] = [];
205
+ }
206
+ swarmStatus[swarmId].push({
207
+ number: issue.number,
208
+ title: issue.title,
209
+ });
210
+ }
211
+ });
212
+
213
+ return {
214
+ totalIssues: issues.length,
215
+ swarmTasks: swarmTasks.length,
216
+ availableTasks: issues.length - swarmTasks.length,
217
+ swarmStatus,
218
+ };
219
+ }
220
+
221
+ /**
222
+ * Clean up stale locks
223
+ */
224
+ async cleanupStaleLocks() {
225
+ const staleTasks = this.db.prepare(`
226
+ SELECT issue_number, swarm_id FROM swarm_tasks
227
+ WHERE lock_expires < strftime('%s', 'now')
228
+ `).all();
229
+
230
+ for (const task of staleTasks) {
231
+ await this.releaseTask(task.swarm_id, task.issue_number);
232
+ }
233
+
234
+ return staleTasks.length;
235
+ }
236
+ }
237
+
238
+ // Example usage with gh CLI - commented out to avoid no-unused-vars warning
239
+ // async function example() {
240
+ // const coordinator = new GHCoordinator({
241
+ // owner: 'ruvnet',
242
+ // repo: 'ruv-FANN',
243
+ // });
244
+ //
245
+ // // Get available tasks
246
+ // const tasks = await coordinator.getAvailableTasks({ state: 'open' });
247
+ // console.log(`Found ${tasks.length} available tasks`);
248
+ //
249
+ // // Claim a task for a swarm
250
+ // if (tasks.length > 0) {
251
+ // const claimed = await coordinator.claimTask('swarm-123', tasks[0].number);
252
+ // console.log(`Claimed task #${tasks[0].number}: ${claimed}`);
253
+ // }
254
+ //
255
+ // // Get coordination status
256
+ // const status = await coordinator.getCoordinationStatus();
257
+ // console.log('Coordination status:', status);
258
+ // }
259
+
260
+ module.exports = GHCoordinator;
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CLI handler for @sparkleideas/ruv-swarm hooks
5
+ * Usage: npx @sparkleideas/ruv-swarm hook <type> [options]
6
+ */
7
+
8
+ import { handleHook } from './index.js';
9
+
10
+ async function main() {
11
+ const args = process.argv.slice(2);
12
+
13
+ // Skip if not a hook command
14
+ if (args[0] !== 'hook') {
15
+ return;
16
+ }
17
+
18
+ const [, hookType] = args;
19
+ const options = parseArgs(args.slice(2));
20
+
21
+ try {
22
+ const result = await handleHook(hookType, options);
23
+
24
+ // Output JSON response for Claude Code to parse
25
+ console.log(JSON.stringify(result, null, 2));
26
+
27
+ // Exit with appropriate code
28
+ if (result.continue === false) {
29
+ process.exit(2); // Blocking error
30
+ } else {
31
+ process.exit(0); // Success
32
+ }
33
+ } catch (error) {
34
+ console.error(JSON.stringify({
35
+ continue: true,
36
+ error: error.message,
37
+ stack: process.env.DEBUG ? error.stack : undefined,
38
+ }));
39
+ process.exit(1); // Non-blocking error
40
+ }
41
+ }
42
+
43
+ function parseArgs(args) {
44
+ const options = {};
45
+
46
+ for (let i = 0; i < args.length; i++) {
47
+ const arg = args[i];
48
+
49
+ if (arg.startsWith('--')) {
50
+ const key = arg.substring(2);
51
+
52
+ // Check if next arg is a value or another flag
53
+ if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
54
+ // Next arg is the value
55
+ options[toCamelCase(key)] = args[i + 1];
56
+ i++; // Skip the value in next iteration
57
+ } else {
58
+ // Boolean flag
59
+ options[toCamelCase(key)] = true;
60
+ }
61
+ } else if (!args[i - 1]?.startsWith('--')) {
62
+ // Positional argument
63
+ if (!options._) {
64
+ options._ = [];
65
+ }
66
+ options._.push(arg);
67
+ }
68
+ }
69
+
70
+ return options;
71
+ }
72
+
73
+ function toCamelCase(str) {
74
+ return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
75
+ }
76
+
77
+ // Run if called directly
78
+ if (import.meta.url === `file://${process.argv[1]}`) {
79
+ main().catch(console.error);
80
+ }
81
+
82
+ export { main };