@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.
- package/README.md +1565 -0
- package/bin/ruv-swarm-clean.js +1872 -0
- package/bin/ruv-swarm-memory.js +119 -0
- package/bin/ruv-swarm-secure-heartbeat.js +1549 -0
- package/bin/ruv-swarm-secure.js +1689 -0
- package/package.json +221 -0
- package/src/agent.ts +342 -0
- package/src/benchmark.js +267 -0
- package/src/claude-flow-enhanced.js +839 -0
- package/src/claude-integration/advanced-commands.js +561 -0
- package/src/claude-integration/core.js +112 -0
- package/src/claude-integration/docs.js +1548 -0
- package/src/claude-integration/env-template.js +39 -0
- package/src/claude-integration/index.js +209 -0
- package/src/claude-integration/remote.js +408 -0
- package/src/cli-diagnostics.js +364 -0
- package/src/cognitive-pattern-evolution.js +1317 -0
- package/src/daa-cognition.js +977 -0
- package/src/daa-service.d.ts +298 -0
- package/src/daa-service.js +1116 -0
- package/src/diagnostics.js +533 -0
- package/src/errors.js +528 -0
- package/src/github-coordinator/README.md +193 -0
- package/src/github-coordinator/claude-hooks.js +162 -0
- package/src/github-coordinator/gh-cli-coordinator.js +260 -0
- package/src/hooks/cli.js +82 -0
- package/src/hooks/index.js +1900 -0
- package/src/index-enhanced.d.ts +371 -0
- package/src/index-enhanced.js +734 -0
- package/src/index.d.ts +287 -0
- package/src/index.js +405 -0
- package/src/index.ts +457 -0
- package/src/logger.js +182 -0
- package/src/logging-config.js +179 -0
- package/src/mcp-daa-tools.js +735 -0
- package/src/mcp-tools-benchmarks.js +328 -0
- package/src/mcp-tools-enhanced.js +2863 -0
- package/src/memory-config.js +42 -0
- package/src/meta-learning-framework.js +1359 -0
- package/src/neural-agent.js +830 -0
- package/src/neural-coordination-protocol.js +1363 -0
- package/src/neural-models/README.md +118 -0
- package/src/neural-models/autoencoder.js +543 -0
- package/src/neural-models/base.js +269 -0
- package/src/neural-models/cnn.js +497 -0
- package/src/neural-models/gnn.js +447 -0
- package/src/neural-models/gru.js +536 -0
- package/src/neural-models/index.js +273 -0
- package/src/neural-models/lstm.js +551 -0
- package/src/neural-models/neural-presets-complete.js +1306 -0
- package/src/neural-models/presets/graph.js +392 -0
- package/src/neural-models/presets/index.js +279 -0
- package/src/neural-models/presets/nlp.js +328 -0
- package/src/neural-models/presets/timeseries.js +368 -0
- package/src/neural-models/presets/vision.js +387 -0
- package/src/neural-models/resnet.js +534 -0
- package/src/neural-models/transformer.js +515 -0
- package/src/neural-models/vae.js +489 -0
- package/src/neural-network-manager.js +1938 -0
- package/src/neural-network.ts +296 -0
- package/src/neural.js +574 -0
- package/src/performance-benchmarks.js +898 -0
- package/src/performance.js +458 -0
- package/src/persistence-pooled.js +695 -0
- package/src/persistence.js +480 -0
- package/src/schemas.js +864 -0
- package/src/security.js +218 -0
- package/src/singleton-container.js +183 -0
- package/src/sqlite-pool.js +587 -0
- package/src/sqlite-worker.js +141 -0
- package/src/types.ts +164 -0
- package/src/utils.ts +286 -0
- package/src/wasm-loader.js +601 -0
- package/src/wasm-loader2.js +404 -0
- package/src/wasm-memory-optimizer.js +783 -0
- package/src/wasm-types.d.ts +63 -0
- package/wasm/README.md +347 -0
- package/wasm/neuro-divergent.wasm +0 -0
- package/wasm/package.json +18 -0
- package/wasm/ruv-fann.wasm +0 -0
- package/wasm/ruv_swarm_simd.wasm +0 -0
- package/wasm/ruv_swarm_wasm.d.ts +391 -0
- package/wasm/ruv_swarm_wasm.js +2164 -0
- package/wasm/ruv_swarm_wasm_bg.wasm +0 -0
- package/wasm/ruv_swarm_wasm_bg.wasm.d.ts +123 -0
- package/wasm/wasm-bindings-loader.mjs +435 -0
- package/wasm/wasm-updates.md +684 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RuvSwarm - WASM-based swarm orchestration with cognitive diversity
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
SwarmOptions,
|
|
7
|
+
SwarmState,
|
|
8
|
+
SwarmTopology,
|
|
9
|
+
SwarmEventEmitter,
|
|
10
|
+
SwarmEvent,
|
|
11
|
+
AgentConfig,
|
|
12
|
+
Task,
|
|
13
|
+
TaskStatus,
|
|
14
|
+
Message,
|
|
15
|
+
MessageType,
|
|
16
|
+
SwarmMetrics,
|
|
17
|
+
Connection,
|
|
18
|
+
WasmModule,
|
|
19
|
+
} from './types';
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
generateId,
|
|
23
|
+
validateSwarmOptions,
|
|
24
|
+
formatMetrics,
|
|
25
|
+
recommendTopology,
|
|
26
|
+
priorityToNumber,
|
|
27
|
+
} from './utils';
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
BaseAgent,
|
|
31
|
+
createAgent,
|
|
32
|
+
AgentPool,
|
|
33
|
+
} from './agent';
|
|
34
|
+
|
|
35
|
+
export * from './types';
|
|
36
|
+
export * from './utils';
|
|
37
|
+
export * from './agent';
|
|
38
|
+
export * from './neural-network';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Main RuvSwarm class for orchestrating swarm operations
|
|
42
|
+
*/
|
|
43
|
+
export class RuvSwarm implements SwarmEventEmitter {
|
|
44
|
+
private options: Required<SwarmOptions>;
|
|
45
|
+
private state: SwarmState;
|
|
46
|
+
private agentPool: AgentPool;
|
|
47
|
+
private eventHandlers: Map<SwarmEvent, Set<(data: any) => void>>;
|
|
48
|
+
private wasmModule?: WasmModule;
|
|
49
|
+
private swarmId?: number;
|
|
50
|
+
private isInitialized: boolean = false;
|
|
51
|
+
|
|
52
|
+
constructor(options: SwarmOptions = {}) {
|
|
53
|
+
const errors = validateSwarmOptions(options);
|
|
54
|
+
if (errors.length > 0) {
|
|
55
|
+
throw new Error(`Invalid swarm options: ${errors.join(', ')}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.options = {
|
|
59
|
+
topology: options.topology || 'mesh',
|
|
60
|
+
maxAgents: options.maxAgents || 10,
|
|
61
|
+
connectionDensity: options.connectionDensity || 0.5,
|
|
62
|
+
syncInterval: options.syncInterval || 1000,
|
|
63
|
+
wasmPath: options.wasmPath || './wasm/ruv_swarm_wasm.js',
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
this.agentPool = new AgentPool();
|
|
67
|
+
this.eventHandlers = new Map();
|
|
68
|
+
|
|
69
|
+
this.state = {
|
|
70
|
+
agents: new Map(),
|
|
71
|
+
tasks: new Map(),
|
|
72
|
+
topology: this.options.topology,
|
|
73
|
+
connections: [],
|
|
74
|
+
metrics: {
|
|
75
|
+
totalTasks: 0,
|
|
76
|
+
completedTasks: 0,
|
|
77
|
+
failedTasks: 0,
|
|
78
|
+
averageCompletionTime: 0,
|
|
79
|
+
agentUtilization: new Map(),
|
|
80
|
+
throughput: 0,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Initialize the swarm with WASM module
|
|
87
|
+
*/
|
|
88
|
+
async init(): Promise<void> {
|
|
89
|
+
if (this.isInitialized) {
|
|
90
|
+
throw new Error('Swarm is already initialized');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Load WASM module
|
|
95
|
+
if (typeof window !== 'undefined') {
|
|
96
|
+
// Browser environment
|
|
97
|
+
const wasmModule = await import(this.options.wasmPath);
|
|
98
|
+
await wasmModule.default();
|
|
99
|
+
this.wasmModule = wasmModule as any;
|
|
100
|
+
} else {
|
|
101
|
+
// Node.js environment
|
|
102
|
+
console.log('WASM support in Node.js - using pure JS implementation');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Initialize swarm in WASM if available
|
|
106
|
+
if (this.wasmModule) {
|
|
107
|
+
await this.wasmModule.init();
|
|
108
|
+
this.swarmId = this.wasmModule.createSwarm(this.options);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.isInitialized = true;
|
|
112
|
+
this.startSyncLoop();
|
|
113
|
+
|
|
114
|
+
this.emit('swarm:initialized', { options: this.options });
|
|
115
|
+
} catch (error) {
|
|
116
|
+
throw new Error(`Failed to initialize swarm: ${error}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Static factory method for easy initialization
|
|
122
|
+
*/
|
|
123
|
+
static async create(options?: SwarmOptions): Promise<RuvSwarm> {
|
|
124
|
+
const swarm = new RuvSwarm(options);
|
|
125
|
+
await swarm.init();
|
|
126
|
+
return swarm;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Add an agent to the swarm
|
|
131
|
+
*/
|
|
132
|
+
addAgent(config: AgentConfig): string {
|
|
133
|
+
if (!this.isInitialized) {
|
|
134
|
+
throw new Error('Swarm must be initialized before adding agents');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (this.state.agents.size >= this.options.maxAgents) {
|
|
138
|
+
throw new Error(`Maximum agent limit (${this.options.maxAgents}) reached`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const agent = createAgent(config);
|
|
142
|
+
this.state.agents.set(agent.id, agent);
|
|
143
|
+
this.agentPool.addAgent(agent);
|
|
144
|
+
|
|
145
|
+
// Add to WASM if available
|
|
146
|
+
if (this.wasmModule && this.swarmId !== undefined) {
|
|
147
|
+
const wasmAgentId = this.wasmModule.addAgent(this.swarmId, config);
|
|
148
|
+
(agent as BaseAgent).setWasmAgentId(wasmAgentId);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Create connections based on topology
|
|
152
|
+
this.updateConnections(agent.id);
|
|
153
|
+
|
|
154
|
+
this.emit('agent:added', { agentId: agent.id, config });
|
|
155
|
+
|
|
156
|
+
return agent.id;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Remove an agent from the swarm
|
|
161
|
+
*/
|
|
162
|
+
removeAgent(agentId: string): void {
|
|
163
|
+
const agent = this.state.agents.get(agentId);
|
|
164
|
+
if (!agent) {
|
|
165
|
+
throw new Error(`Agent ${agentId} not found`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (agent.state.status === 'busy') {
|
|
169
|
+
throw new Error(`Cannot remove busy agent ${agentId}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.state.agents.delete(agentId);
|
|
173
|
+
this.agentPool.removeAgent(agentId);
|
|
174
|
+
|
|
175
|
+
// Remove connections
|
|
176
|
+
this.state.connections = this.state.connections.filter(
|
|
177
|
+
conn => conn.from !== agentId && conn.to !== agentId,
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
this.emit('agent:removed', { agentId });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Submit a task to the swarm
|
|
185
|
+
*/
|
|
186
|
+
async submitTask(task: Omit<Task, 'id' | 'status'>): Promise<string> {
|
|
187
|
+
if (!this.isInitialized) {
|
|
188
|
+
throw new Error('Swarm must be initialized before submitting tasks');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const fullTask: Task = {
|
|
192
|
+
...task,
|
|
193
|
+
id: generateId('task'),
|
|
194
|
+
status: 'pending',
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
this.state.tasks.set(fullTask.id, fullTask);
|
|
198
|
+
this.state.metrics.totalTasks++;
|
|
199
|
+
|
|
200
|
+
this.emit('task:created', { task: fullTask });
|
|
201
|
+
|
|
202
|
+
// Assign to WASM if available
|
|
203
|
+
if (this.wasmModule && this.swarmId !== undefined) {
|
|
204
|
+
this.wasmModule.assignTask(this.swarmId, fullTask);
|
|
205
|
+
} else {
|
|
206
|
+
// Use JS implementation
|
|
207
|
+
await this.assignTask(fullTask);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return fullTask.id;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get the current state of a task
|
|
215
|
+
*/
|
|
216
|
+
getTaskStatus(taskId: string): Task | undefined {
|
|
217
|
+
return this.state.tasks.get(taskId);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get all tasks with a specific status
|
|
222
|
+
*/
|
|
223
|
+
getTasksByStatus(status: TaskStatus): Task[] {
|
|
224
|
+
return Array.from(this.state.tasks.values()).filter(task => task.status === status);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get current swarm metrics
|
|
229
|
+
*/
|
|
230
|
+
getMetrics(): SwarmMetrics {
|
|
231
|
+
return { ...this.state.metrics };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Get formatted metrics string
|
|
236
|
+
*/
|
|
237
|
+
getFormattedMetrics(): string {
|
|
238
|
+
return formatMetrics(this.state.metrics);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Event emitter implementation
|
|
243
|
+
*/
|
|
244
|
+
on(event: SwarmEvent, handler: (data: any) => void): void {
|
|
245
|
+
if (!this.eventHandlers.has(event)) {
|
|
246
|
+
this.eventHandlers.set(event, new Set());
|
|
247
|
+
}
|
|
248
|
+
this.eventHandlers.get(event)!.add(handler);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
off(event: SwarmEvent, handler: (data: any) => void): void {
|
|
252
|
+
const handlers = this.eventHandlers.get(event);
|
|
253
|
+
if (handlers) {
|
|
254
|
+
handlers.delete(handler);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
emit(event: SwarmEvent, data: any): void {
|
|
259
|
+
const handlers = this.eventHandlers.get(event);
|
|
260
|
+
if (handlers) {
|
|
261
|
+
handlers.forEach(handler => {
|
|
262
|
+
try {
|
|
263
|
+
handler(data);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error(`Error in event handler for ${event}:`, error);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Shutdown the swarm
|
|
273
|
+
*/
|
|
274
|
+
async destroy(): Promise<void> {
|
|
275
|
+
if (!this.isInitialized) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Cancel any pending tasks
|
|
280
|
+
for (const task of this.state.tasks.values()) {
|
|
281
|
+
if (task.status === 'pending' || task.status === 'in_progress') {
|
|
282
|
+
task.status = 'failed';
|
|
283
|
+
task.error = new Error('Swarm shutdown');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Destroy WASM resources
|
|
288
|
+
if (this.wasmModule && this.swarmId !== undefined) {
|
|
289
|
+
this.wasmModule.destroy(this.swarmId);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
this.isInitialized = false;
|
|
293
|
+
this.emit('swarm:destroyed', {});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Private methods
|
|
298
|
+
*/
|
|
299
|
+
|
|
300
|
+
private async assignTask(task: Task): Promise<void> {
|
|
301
|
+
// Find suitable agent based on task requirements
|
|
302
|
+
const agent = this.agentPool.getAvailableAgent();
|
|
303
|
+
|
|
304
|
+
if (!agent) {
|
|
305
|
+
// No available agents, queue the task
|
|
306
|
+
console.log(`No available agents for task ${task.id}, queuing...`);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
task.status = 'assigned';
|
|
311
|
+
task.assignedAgents = [agent.id];
|
|
312
|
+
|
|
313
|
+
this.emit('task:assigned', { taskId: task.id, agentId: agent.id });
|
|
314
|
+
|
|
315
|
+
// Send task assignment message
|
|
316
|
+
const message: Message = {
|
|
317
|
+
id: generateId('msg'),
|
|
318
|
+
from: 'swarm',
|
|
319
|
+
to: agent.id,
|
|
320
|
+
type: 'task_assignment',
|
|
321
|
+
payload: task,
|
|
322
|
+
timestamp: Date.now(),
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
await agent.communicate(message);
|
|
326
|
+
|
|
327
|
+
// Execute task
|
|
328
|
+
try {
|
|
329
|
+
task.status = 'in_progress';
|
|
330
|
+
const startTime = Date.now();
|
|
331
|
+
|
|
332
|
+
const result = await agent.execute(task);
|
|
333
|
+
|
|
334
|
+
task.status = 'completed';
|
|
335
|
+
task.result = result;
|
|
336
|
+
|
|
337
|
+
const executionTime = Date.now() - startTime;
|
|
338
|
+
this.updateMetrics(true, executionTime);
|
|
339
|
+
|
|
340
|
+
this.emit('task:completed', { taskId: task.id, result });
|
|
341
|
+
|
|
342
|
+
} catch (error) {
|
|
343
|
+
task.status = 'failed';
|
|
344
|
+
task.error = error as Error;
|
|
345
|
+
|
|
346
|
+
this.updateMetrics(false, 0);
|
|
347
|
+
|
|
348
|
+
this.emit('task:failed', { taskId: task.id, error });
|
|
349
|
+
} finally {
|
|
350
|
+
this.agentPool.releaseAgent(agent.id);
|
|
351
|
+
|
|
352
|
+
// Check for pending tasks
|
|
353
|
+
const pendingTasks = this.getTasksByStatus('pending');
|
|
354
|
+
if (pendingTasks.length > 0) {
|
|
355
|
+
// Sort by priority
|
|
356
|
+
pendingTasks.sort((a, b) => priorityToNumber(b.priority) - priorityToNumber(a.priority));
|
|
357
|
+
await this.assignTask(pendingTasks[0]);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
private updateConnections(newAgentId: string): void {
|
|
363
|
+
const agents = Array.from(this.state.agents.keys());
|
|
364
|
+
|
|
365
|
+
switch (this.options.topology) {
|
|
366
|
+
case 'mesh':
|
|
367
|
+
// Connect to all other agents
|
|
368
|
+
for (const agentId of agents) {
|
|
369
|
+
if (agentId !== newAgentId) {
|
|
370
|
+
this.state.connections.push({
|
|
371
|
+
from: newAgentId,
|
|
372
|
+
to: agentId,
|
|
373
|
+
weight: 1,
|
|
374
|
+
type: 'coordination',
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
break;
|
|
379
|
+
|
|
380
|
+
case 'hierarchical':
|
|
381
|
+
// Connect to parent/children based on position
|
|
382
|
+
if (agents.length > 1) {
|
|
383
|
+
const parentIndex = Math.floor((agents.indexOf(newAgentId) - 1) / 2);
|
|
384
|
+
if (parentIndex >= 0) {
|
|
385
|
+
this.state.connections.push({
|
|
386
|
+
from: newAgentId,
|
|
387
|
+
to: agents[parentIndex],
|
|
388
|
+
weight: 1,
|
|
389
|
+
type: 'control',
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
394
|
+
|
|
395
|
+
case 'distributed':
|
|
396
|
+
// Random connections based on density
|
|
397
|
+
const numConnections = Math.floor(agents.length * this.options.connectionDensity);
|
|
398
|
+
const shuffled = agents.filter(id => id !== newAgentId).sort(() => Math.random() - 0.5);
|
|
399
|
+
for (let i = 0; i < Math.min(numConnections, shuffled.length); i++) {
|
|
400
|
+
this.state.connections.push({
|
|
401
|
+
from: newAgentId,
|
|
402
|
+
to: shuffled[i],
|
|
403
|
+
weight: Math.random(),
|
|
404
|
+
type: 'data',
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private updateMetrics(success: boolean, executionTime: number): void {
|
|
412
|
+
if (success) {
|
|
413
|
+
this.state.metrics.completedTasks++;
|
|
414
|
+
} else {
|
|
415
|
+
this.state.metrics.failedTasks++;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Update average completion time
|
|
419
|
+
if (success && executionTime > 0) {
|
|
420
|
+
const totalCompleted = this.state.metrics.completedTasks;
|
|
421
|
+
const currentAvg = this.state.metrics.averageCompletionTime;
|
|
422
|
+
this.state.metrics.averageCompletionTime =
|
|
423
|
+
(currentAvg * (totalCompleted - 1) + executionTime) / totalCompleted;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Update throughput (tasks per second)
|
|
427
|
+
// This is a simplified calculation - in production, use a sliding window
|
|
428
|
+
const totalProcessed = this.state.metrics.completedTasks + this.state.metrics.failedTasks;
|
|
429
|
+
const elapsedSeconds = (Date.now() - this.startTime) / 1000;
|
|
430
|
+
this.state.metrics.throughput = totalProcessed / elapsedSeconds;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
private startTime: number = Date.now();
|
|
434
|
+
|
|
435
|
+
private startSyncLoop(): void {
|
|
436
|
+
setInterval(() => {
|
|
437
|
+
if (this.wasmModule && this.swarmId !== undefined) {
|
|
438
|
+
// Sync state with WASM
|
|
439
|
+
const wasmState = this.wasmModule.getState(this.swarmId);
|
|
440
|
+
// Update local state as needed
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Update agent utilization metrics
|
|
444
|
+
for (const agent of this.state.agents.values()) {
|
|
445
|
+
this.state.metrics.agentUtilization.set(
|
|
446
|
+
agent.id,
|
|
447
|
+
agent.state.status === 'busy' ? 1 : 0,
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
}, this.options.syncInterval);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Default export for convenience
|
|
456
|
+
*/
|
|
457
|
+
export default RuvSwarm;
|
package/src/logger.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger module for @sparkleideas/ruv-swarm with comprehensive logging capabilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
|
|
7
|
+
export class Logger {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.name = options.name || '@sparkleideas/ruv-swarm';
|
|
10
|
+
this.level = options.level || 'INFO';
|
|
11
|
+
this.enableStderr = options.enableStderr !== false;
|
|
12
|
+
this.enableFile = options.enableFile || false;
|
|
13
|
+
this.formatJson = options.formatJson || false;
|
|
14
|
+
this.logDir = options.logDir || './logs';
|
|
15
|
+
this.metadata = options.metadata || {};
|
|
16
|
+
this.correlationId = null;
|
|
17
|
+
this.operations = new Map();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
setCorrelationId(id) {
|
|
21
|
+
this.correlationId = id || randomUUID();
|
|
22
|
+
return this.correlationId;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getCorrelationId() {
|
|
26
|
+
return this.correlationId;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_log(level, message, data = {}) {
|
|
30
|
+
const timestamp = new Date().toISOString();
|
|
31
|
+
const prefix = this.correlationId ? `[${this.correlationId}] ` : '';
|
|
32
|
+
|
|
33
|
+
const logEntry = {
|
|
34
|
+
timestamp,
|
|
35
|
+
level,
|
|
36
|
+
name: this.name,
|
|
37
|
+
message,
|
|
38
|
+
correlationId: this.correlationId,
|
|
39
|
+
...this.metadata,
|
|
40
|
+
...data
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
if (this.formatJson) {
|
|
44
|
+
const output = JSON.stringify(logEntry);
|
|
45
|
+
if (this.enableStderr) {
|
|
46
|
+
console.error(output);
|
|
47
|
+
} else {
|
|
48
|
+
console.log(output);
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
const output = `${prefix}[${level}] ${message}`;
|
|
52
|
+
if (this.enableStderr) {
|
|
53
|
+
console.error(output, Object.keys(data).length > 0 ? data : '');
|
|
54
|
+
} else {
|
|
55
|
+
console.log(output, Object.keys(data).length > 0 ? data : '');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
info(message, data = {}) {
|
|
61
|
+
this._log('INFO', message, data);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
warn(message, data = {}) {
|
|
65
|
+
this._log('WARN', message, data);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
error(message, data = {}) {
|
|
69
|
+
this._log('ERROR', message, data);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
debug(message, data = {}) {
|
|
73
|
+
if (this.level === 'DEBUG' || process.env.DEBUG) {
|
|
74
|
+
this._log('DEBUG', message, data);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
trace(message, data = {}) {
|
|
79
|
+
if (this.level === 'TRACE' || process.env.DEBUG) {
|
|
80
|
+
this._log('TRACE', message, data);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
success(message, data = {}) {
|
|
85
|
+
this._log('SUCCESS', message, data);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fatal(message, data = {}) {
|
|
89
|
+
this._log('FATAL', message, data);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
startOperation(operationName) {
|
|
93
|
+
const operationId = randomUUID();
|
|
94
|
+
this.operations.set(operationId, {
|
|
95
|
+
name: operationName,
|
|
96
|
+
startTime: Date.now()
|
|
97
|
+
});
|
|
98
|
+
this.debug(`Starting operation: ${operationName}`, { operationId });
|
|
99
|
+
return operationId;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
endOperation(operationId, success = true, data = {}) {
|
|
103
|
+
const operation = this.operations.get(operationId);
|
|
104
|
+
if (operation) {
|
|
105
|
+
const duration = Date.now() - operation.startTime;
|
|
106
|
+
this.debug(`Operation ${success ? 'completed' : 'failed'}: ${operation.name}`, {
|
|
107
|
+
operationId,
|
|
108
|
+
duration,
|
|
109
|
+
success,
|
|
110
|
+
...data
|
|
111
|
+
});
|
|
112
|
+
this.operations.delete(operationId);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
logConnection(event, sessionId, data = {}) {
|
|
117
|
+
this.info(`Connection ${event}`, {
|
|
118
|
+
sessionId,
|
|
119
|
+
event,
|
|
120
|
+
...data
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
logMcp(direction, method, data = {}) {
|
|
125
|
+
this.debug(`MCP ${direction}: ${method}`, {
|
|
126
|
+
direction,
|
|
127
|
+
method,
|
|
128
|
+
...data
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
logMemoryUsage(context) {
|
|
133
|
+
const memUsage = process.memoryUsage();
|
|
134
|
+
this.debug(`Memory usage - ${context}`, {
|
|
135
|
+
rss: Math.round(memUsage.rss / 1024 / 1024) + 'MB',
|
|
136
|
+
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024) + 'MB',
|
|
137
|
+
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024) + 'MB',
|
|
138
|
+
external: Math.round(memUsage.external / 1024 / 1024) + 'MB'
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getConnectionMetrics() {
|
|
143
|
+
return {
|
|
144
|
+
correlationId: this.correlationId,
|
|
145
|
+
activeOperations: this.operations.size,
|
|
146
|
+
uptime: process.uptime()
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Static methods for backward compatibility
|
|
151
|
+
static info(message, ...args) {
|
|
152
|
+
const logger = new Logger();
|
|
153
|
+
logger.info(message, ...args);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static warn(message, ...args) {
|
|
157
|
+
const logger = new Logger();
|
|
158
|
+
logger.warn(message, ...args);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static error(message, ...args) {
|
|
162
|
+
const logger = new Logger();
|
|
163
|
+
logger.error(message, ...args);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
static debug(message, ...args) {
|
|
167
|
+
const logger = new Logger();
|
|
168
|
+
logger.debug(message, ...args);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static success(message, ...args) {
|
|
172
|
+
const logger = new Logger();
|
|
173
|
+
logger.success(message, ...args);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static trace(message, ...args) {
|
|
177
|
+
const logger = new Logger();
|
|
178
|
+
logger.trace(message, ...args);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export default Logger;
|