claude-flow 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.
- package/LICENSE +21 -0
- package/README.md +612 -0
- package/bin/claude-flow +0 -0
- package/bin/claude-flow-simple +0 -0
- package/bin/claude-flow-typecheck +0 -0
- package/deno.json +84 -0
- package/package.json +45 -0
- package/scripts/check-links.ts +274 -0
- package/scripts/check-performance-regression.ts +168 -0
- package/scripts/claude-sparc.sh +562 -0
- package/scripts/coverage-report.ts +692 -0
- package/scripts/demo-task-system.ts +224 -0
- package/scripts/install.js +72 -0
- package/scripts/test-batch-tasks.ts +29 -0
- package/scripts/test-coordination-features.ts +238 -0
- package/scripts/test-mcp.ts +251 -0
- package/scripts/test-runner.ts +571 -0
- package/scripts/validate-examples.ts +288 -0
- package/src/cli/cli-core.ts +273 -0
- package/src/cli/commands/agent.ts +83 -0
- package/src/cli/commands/config.ts +442 -0
- package/src/cli/commands/help.ts +765 -0
- package/src/cli/commands/index.ts +963 -0
- package/src/cli/commands/mcp.ts +191 -0
- package/src/cli/commands/memory.ts +74 -0
- package/src/cli/commands/monitor.ts +403 -0
- package/src/cli/commands/session.ts +595 -0
- package/src/cli/commands/start.ts +156 -0
- package/src/cli/commands/status.ts +345 -0
- package/src/cli/commands/task.ts +79 -0
- package/src/cli/commands/workflow.ts +763 -0
- package/src/cli/completion.ts +553 -0
- package/src/cli/formatter.ts +310 -0
- package/src/cli/index.ts +211 -0
- package/src/cli/main.ts +23 -0
- package/src/cli/repl.ts +1050 -0
- package/src/cli/simple-cli.js +211 -0
- package/src/cli/simple-cli.ts +211 -0
- package/src/coordination/README.md +400 -0
- package/src/coordination/advanced-scheduler.ts +487 -0
- package/src/coordination/circuit-breaker.ts +366 -0
- package/src/coordination/conflict-resolution.ts +490 -0
- package/src/coordination/dependency-graph.ts +475 -0
- package/src/coordination/index.ts +63 -0
- package/src/coordination/manager.ts +460 -0
- package/src/coordination/messaging.ts +290 -0
- package/src/coordination/metrics.ts +585 -0
- package/src/coordination/resources.ts +322 -0
- package/src/coordination/scheduler.ts +390 -0
- package/src/coordination/work-stealing.ts +224 -0
- package/src/core/config.ts +627 -0
- package/src/core/event-bus.ts +186 -0
- package/src/core/json-persistence.ts +183 -0
- package/src/core/logger.ts +262 -0
- package/src/core/orchestrator-fixed.ts +312 -0
- package/src/core/orchestrator.ts +1234 -0
- package/src/core/persistence.ts +276 -0
- package/src/mcp/auth.ts +438 -0
- package/src/mcp/claude-flow-tools.ts +1280 -0
- package/src/mcp/load-balancer.ts +510 -0
- package/src/mcp/router.ts +240 -0
- package/src/mcp/server.ts +548 -0
- package/src/mcp/session-manager.ts +418 -0
- package/src/mcp/tools.ts +180 -0
- package/src/mcp/transports/base.ts +21 -0
- package/src/mcp/transports/http.ts +457 -0
- package/src/mcp/transports/stdio.ts +254 -0
- package/src/memory/backends/base.ts +22 -0
- package/src/memory/backends/markdown.ts +283 -0
- package/src/memory/backends/sqlite.ts +329 -0
- package/src/memory/cache.ts +238 -0
- package/src/memory/indexer.ts +238 -0
- package/src/memory/manager.ts +572 -0
- package/src/terminal/adapters/base.ts +29 -0
- package/src/terminal/adapters/native.ts +504 -0
- package/src/terminal/adapters/vscode.ts +340 -0
- package/src/terminal/manager.ts +308 -0
- package/src/terminal/pool.ts +271 -0
- package/src/terminal/session.ts +250 -0
- package/src/terminal/vscode-bridge.ts +242 -0
- package/src/utils/errors.ts +231 -0
- package/src/utils/helpers.ts +476 -0
- package/src/utils/types.ts +493 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics and monitoring for coordination performance
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ILogger } from '../core/logger.ts';
|
|
6
|
+
import { IEventBus } from '../core/event-bus.ts';
|
|
7
|
+
import { SystemEvents } from '../utils/types.ts';
|
|
8
|
+
|
|
9
|
+
export interface CoordinationMetrics {
|
|
10
|
+
timestamp: Date;
|
|
11
|
+
|
|
12
|
+
// Task metrics
|
|
13
|
+
taskMetrics: {
|
|
14
|
+
totalTasks: number;
|
|
15
|
+
activeTasks: number;
|
|
16
|
+
completedTasks: number;
|
|
17
|
+
failedTasks: number;
|
|
18
|
+
cancelledTasks: number;
|
|
19
|
+
avgTaskDuration: number;
|
|
20
|
+
taskThroughput: number; // tasks/minute
|
|
21
|
+
tasksByPriority: Record<string, number>;
|
|
22
|
+
tasksByType: Record<string, number>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Agent metrics
|
|
26
|
+
agentMetrics: {
|
|
27
|
+
totalAgents: number;
|
|
28
|
+
activeAgents: number;
|
|
29
|
+
idleAgents: number;
|
|
30
|
+
busyAgents: number;
|
|
31
|
+
agentUtilization: number; // percentage
|
|
32
|
+
avgTasksPerAgent: number;
|
|
33
|
+
agentsByType: Record<string, number>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Resource metrics
|
|
37
|
+
resourceMetrics: {
|
|
38
|
+
totalResources: number;
|
|
39
|
+
lockedResources: number;
|
|
40
|
+
freeResources: number;
|
|
41
|
+
resourceUtilization: number; // percentage
|
|
42
|
+
avgLockDuration: number;
|
|
43
|
+
lockContention: number; // waiting requests
|
|
44
|
+
deadlockCount: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Coordination metrics
|
|
48
|
+
coordinationMetrics: {
|
|
49
|
+
messagesSent: number;
|
|
50
|
+
messagesReceived: number;
|
|
51
|
+
messageLatency: number; // avg ms
|
|
52
|
+
conflictsDetected: number;
|
|
53
|
+
conflictsResolved: number;
|
|
54
|
+
workStealingEvents: number;
|
|
55
|
+
circuitBreakerTrips: number;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Performance metrics
|
|
59
|
+
performanceMetrics: {
|
|
60
|
+
coordinationLatency: number; // avg ms
|
|
61
|
+
schedulingLatency: number; // avg ms
|
|
62
|
+
memoryUsage: number; // MB
|
|
63
|
+
cpuUsage: number; // percentage
|
|
64
|
+
errorRate: number; // errors/minute
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface MetricsSample {
|
|
69
|
+
timestamp: Date;
|
|
70
|
+
metric: string;
|
|
71
|
+
value: number;
|
|
72
|
+
tags?: Record<string, string>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Metrics collector for coordination system
|
|
77
|
+
*/
|
|
78
|
+
export class CoordinationMetricsCollector {
|
|
79
|
+
private samples: MetricsSample[] = [];
|
|
80
|
+
private taskStartTimes = new Map<string, Date>();
|
|
81
|
+
private messageStartTimes = new Map<string, Date>();
|
|
82
|
+
private lockStartTimes = new Map<string, Date>();
|
|
83
|
+
private collectionInterval?: number;
|
|
84
|
+
|
|
85
|
+
// Counters
|
|
86
|
+
private counters = {
|
|
87
|
+
totalTasks: 0,
|
|
88
|
+
completedTasks: 0,
|
|
89
|
+
failedTasks: 0,
|
|
90
|
+
cancelledTasks: 0,
|
|
91
|
+
messagesSent: 0,
|
|
92
|
+
messagesReceived: 0,
|
|
93
|
+
conflictsDetected: 0,
|
|
94
|
+
conflictsResolved: 0,
|
|
95
|
+
workStealingEvents: 0,
|
|
96
|
+
circuitBreakerTrips: 0,
|
|
97
|
+
deadlockCount: 0,
|
|
98
|
+
errors: 0,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Gauges
|
|
102
|
+
private gauges = {
|
|
103
|
+
activeTasks: 0,
|
|
104
|
+
activeAgents: 0,
|
|
105
|
+
idleAgents: 0,
|
|
106
|
+
busyAgents: 0,
|
|
107
|
+
lockedResources: 0,
|
|
108
|
+
freeResources: 0,
|
|
109
|
+
lockContention: 0,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Histograms (for calculating averages)
|
|
113
|
+
private histograms = {
|
|
114
|
+
taskDurations: [] as number[],
|
|
115
|
+
messageDurations: [] as number[],
|
|
116
|
+
lockDurations: [] as number[],
|
|
117
|
+
coordinationLatencies: [] as number[],
|
|
118
|
+
schedulingLatencies: [] as number[],
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
constructor(
|
|
122
|
+
private logger: ILogger,
|
|
123
|
+
private eventBus: IEventBus,
|
|
124
|
+
private collectionIntervalMs = 30000, // 30 seconds
|
|
125
|
+
) {
|
|
126
|
+
this.setupEventHandlers();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Start metrics collection
|
|
131
|
+
*/
|
|
132
|
+
start(): void {
|
|
133
|
+
this.logger.info('Starting coordination metrics collection');
|
|
134
|
+
|
|
135
|
+
this.collectionInterval = setInterval(() => {
|
|
136
|
+
this.collectMetrics();
|
|
137
|
+
}, this.collectionIntervalMs);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Stop metrics collection
|
|
142
|
+
*/
|
|
143
|
+
stop(): void {
|
|
144
|
+
if (this.collectionInterval) {
|
|
145
|
+
clearInterval(this.collectionInterval);
|
|
146
|
+
delete this.collectionInterval;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.logger.info('Stopped coordination metrics collection');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Record a metric sample
|
|
154
|
+
*/
|
|
155
|
+
recordMetric(metric: string, value: number, tags?: Record<string, string>): void {
|
|
156
|
+
const sample: MetricsSample = {
|
|
157
|
+
timestamp: new Date(),
|
|
158
|
+
metric,
|
|
159
|
+
value,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
if (tags !== undefined) {
|
|
163
|
+
sample.tags = tags;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.samples.push(sample);
|
|
167
|
+
|
|
168
|
+
// Keep only last 10000 samples to prevent memory bloat
|
|
169
|
+
if (this.samples.length > 10000) {
|
|
170
|
+
this.samples = this.samples.slice(-5000);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get current metrics snapshot
|
|
176
|
+
*/
|
|
177
|
+
getCurrentMetrics(): CoordinationMetrics {
|
|
178
|
+
const now = new Date();
|
|
179
|
+
const minuteAgo = new Date(now.getTime() - 60000);
|
|
180
|
+
|
|
181
|
+
// Calculate throughput (items per minute)
|
|
182
|
+
const recentSamples = this.samples.filter(s => s.timestamp >= minuteAgo);
|
|
183
|
+
const taskCompletions = recentSamples.filter(s => s.metric === 'task.completed').length;
|
|
184
|
+
const errorCount = recentSamples.filter(s => s.metric === 'error').length;
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
timestamp: now,
|
|
188
|
+
|
|
189
|
+
taskMetrics: {
|
|
190
|
+
totalTasks: this.counters.totalTasks,
|
|
191
|
+
activeTasks: this.gauges.activeTasks,
|
|
192
|
+
completedTasks: this.counters.completedTasks,
|
|
193
|
+
failedTasks: this.counters.failedTasks,
|
|
194
|
+
cancelledTasks: this.counters.cancelledTasks,
|
|
195
|
+
avgTaskDuration: this.average(this.histograms.taskDurations),
|
|
196
|
+
taskThroughput: taskCompletions,
|
|
197
|
+
tasksByPriority: this.getTasksByPriority(),
|
|
198
|
+
tasksByType: this.getTasksByType(),
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
agentMetrics: {
|
|
202
|
+
totalAgents: this.gauges.activeAgents + this.gauges.idleAgents,
|
|
203
|
+
activeAgents: this.gauges.activeAgents,
|
|
204
|
+
idleAgents: this.gauges.idleAgents,
|
|
205
|
+
busyAgents: this.gauges.busyAgents,
|
|
206
|
+
agentUtilization: this.calculateAgentUtilization(),
|
|
207
|
+
avgTasksPerAgent: this.calculateAvgTasksPerAgent(),
|
|
208
|
+
agentsByType: this.getAgentsByType(),
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
resourceMetrics: {
|
|
212
|
+
totalResources: this.gauges.lockedResources + this.gauges.freeResources,
|
|
213
|
+
lockedResources: this.gauges.lockedResources,
|
|
214
|
+
freeResources: this.gauges.freeResources,
|
|
215
|
+
resourceUtilization: this.calculateResourceUtilization(),
|
|
216
|
+
avgLockDuration: this.average(this.histograms.lockDurations),
|
|
217
|
+
lockContention: this.gauges.lockContention,
|
|
218
|
+
deadlockCount: this.counters.deadlockCount,
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
coordinationMetrics: {
|
|
222
|
+
messagesSent: this.counters.messagesSent,
|
|
223
|
+
messagesReceived: this.counters.messagesReceived,
|
|
224
|
+
messageLatency: this.average(this.histograms.messageDurations),
|
|
225
|
+
conflictsDetected: this.counters.conflictsDetected,
|
|
226
|
+
conflictsResolved: this.counters.conflictsResolved,
|
|
227
|
+
workStealingEvents: this.counters.workStealingEvents,
|
|
228
|
+
circuitBreakerTrips: this.counters.circuitBreakerTrips,
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
performanceMetrics: {
|
|
232
|
+
coordinationLatency: this.average(this.histograms.coordinationLatencies),
|
|
233
|
+
schedulingLatency: this.average(this.histograms.schedulingLatencies),
|
|
234
|
+
memoryUsage: this.getMemoryUsage(),
|
|
235
|
+
cpuUsage: this.getCpuUsage(),
|
|
236
|
+
errorRate: errorCount,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get metric history for a specific metric
|
|
243
|
+
*/
|
|
244
|
+
getMetricHistory(metric: string, since?: Date): MetricsSample[] {
|
|
245
|
+
const cutoff = since || new Date(Date.now() - 3600000); // 1 hour ago
|
|
246
|
+
|
|
247
|
+
return this.samples.filter(s =>
|
|
248
|
+
s.metric === metric && s.timestamp >= cutoff
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get top metrics by value
|
|
254
|
+
*/
|
|
255
|
+
getTopMetrics(limit = 10): Array<{ metric: string; value: number; timestamp: Date }> {
|
|
256
|
+
const recent = this.samples.filter(s =>
|
|
257
|
+
s.timestamp >= new Date(Date.now() - 300000) // 5 minutes
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const byMetric = new Map<string, number>();
|
|
261
|
+
const timestamps = new Map<string, Date>();
|
|
262
|
+
|
|
263
|
+
for (const sample of recent) {
|
|
264
|
+
byMetric.set(sample.metric, (byMetric.get(sample.metric) || 0) + sample.value);
|
|
265
|
+
timestamps.set(sample.metric, sample.timestamp);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return Array.from(byMetric.entries())
|
|
269
|
+
.sort((a, b) => b[1] - a[1])
|
|
270
|
+
.slice(0, limit)
|
|
271
|
+
.map(([metric, value]) => ({
|
|
272
|
+
metric,
|
|
273
|
+
value,
|
|
274
|
+
timestamp: timestamps.get(metric)!,
|
|
275
|
+
}));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Set up event handlers to collect metrics
|
|
280
|
+
*/
|
|
281
|
+
private setupEventHandlers(): void {
|
|
282
|
+
// Task events
|
|
283
|
+
this.eventBus.on(SystemEvents.TASK_CREATED, () => {
|
|
284
|
+
this.counters.totalTasks++;
|
|
285
|
+
this.recordMetric('task.created', 1);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
this.eventBus.on(SystemEvents.TASK_STARTED, (data: any) => {
|
|
289
|
+
this.taskStartTimes.set(data.taskId, new Date());
|
|
290
|
+
this.gauges.activeTasks++;
|
|
291
|
+
this.recordMetric('task.started', 1);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
this.eventBus.on(SystemEvents.TASK_COMPLETED, (data: any) => {
|
|
295
|
+
this.counters.completedTasks++;
|
|
296
|
+
this.gauges.activeTasks = Math.max(0, this.gauges.activeTasks - 1);
|
|
297
|
+
|
|
298
|
+
const startTime = this.taskStartTimes.get(data.taskId);
|
|
299
|
+
if (startTime) {
|
|
300
|
+
const duration = new Date().getTime() - startTime.getTime();
|
|
301
|
+
this.histograms.taskDurations.push(duration);
|
|
302
|
+
this.taskStartTimes.delete(data.taskId);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
this.recordMetric('task.completed', 1);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
this.eventBus.on(SystemEvents.TASK_FAILED, (data: any) => {
|
|
309
|
+
this.counters.failedTasks++;
|
|
310
|
+
this.gauges.activeTasks = Math.max(0, this.gauges.activeTasks - 1);
|
|
311
|
+
this.taskStartTimes.delete(data.taskId);
|
|
312
|
+
this.recordMetric('task.failed', 1);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
this.eventBus.on(SystemEvents.TASK_CANCELLED, (data: any) => {
|
|
316
|
+
this.counters.cancelledTasks++;
|
|
317
|
+
this.gauges.activeTasks = Math.max(0, this.gauges.activeTasks - 1);
|
|
318
|
+
this.taskStartTimes.delete(data.taskId);
|
|
319
|
+
this.recordMetric('task.cancelled', 1);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Agent events
|
|
323
|
+
this.eventBus.on(SystemEvents.AGENT_SPAWNED, () => {
|
|
324
|
+
this.gauges.activeAgents++;
|
|
325
|
+
this.recordMetric('agent.spawned', 1);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
this.eventBus.on(SystemEvents.AGENT_TERMINATED, () => {
|
|
329
|
+
this.gauges.activeAgents = Math.max(0, this.gauges.activeAgents - 1);
|
|
330
|
+
this.recordMetric('agent.terminated', 1);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
this.eventBus.on(SystemEvents.AGENT_IDLE, () => {
|
|
334
|
+
this.gauges.idleAgents++;
|
|
335
|
+
this.gauges.busyAgents = Math.max(0, this.gauges.busyAgents - 1);
|
|
336
|
+
this.recordMetric('agent.idle', 1);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
this.eventBus.on(SystemEvents.AGENT_ACTIVE, () => {
|
|
340
|
+
this.gauges.busyAgents++;
|
|
341
|
+
this.gauges.idleAgents = Math.max(0, this.gauges.idleAgents - 1);
|
|
342
|
+
this.recordMetric('agent.active', 1);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Resource events
|
|
346
|
+
this.eventBus.on(SystemEvents.RESOURCE_ACQUIRED, (data: any) => {
|
|
347
|
+
this.lockStartTimes.set(data.resourceId, new Date());
|
|
348
|
+
this.gauges.lockedResources++;
|
|
349
|
+
this.gauges.freeResources = Math.max(0, this.gauges.freeResources - 1);
|
|
350
|
+
this.recordMetric('resource.acquired', 1);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
this.eventBus.on(SystemEvents.RESOURCE_RELEASED, (data: any) => {
|
|
354
|
+
this.gauges.freeResources++;
|
|
355
|
+
this.gauges.lockedResources = Math.max(0, this.gauges.lockedResources - 1);
|
|
356
|
+
|
|
357
|
+
const startTime = this.lockStartTimes.get(data.resourceId);
|
|
358
|
+
if (startTime) {
|
|
359
|
+
const duration = new Date().getTime() - startTime.getTime();
|
|
360
|
+
this.histograms.lockDurations.push(duration);
|
|
361
|
+
this.lockStartTimes.delete(data.resourceId);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
this.recordMetric('resource.released', 1);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// Deadlock events
|
|
368
|
+
this.eventBus.on(SystemEvents.DEADLOCK_DETECTED, () => {
|
|
369
|
+
this.counters.deadlockCount++;
|
|
370
|
+
this.recordMetric('deadlock.detected', 1);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Message events
|
|
374
|
+
this.eventBus.on(SystemEvents.MESSAGE_SENT, (data: any) => {
|
|
375
|
+
this.counters.messagesSent++;
|
|
376
|
+
this.messageStartTimes.set(data.message.id, new Date());
|
|
377
|
+
this.recordMetric('message.sent', 1);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
this.eventBus.on(SystemEvents.MESSAGE_RECEIVED, (data: any) => {
|
|
381
|
+
this.counters.messagesReceived++;
|
|
382
|
+
|
|
383
|
+
const startTime = this.messageStartTimes.get(data.message.id);
|
|
384
|
+
if (startTime) {
|
|
385
|
+
const duration = new Date().getTime() - startTime.getTime();
|
|
386
|
+
this.histograms.messageDurations.push(duration);
|
|
387
|
+
this.messageStartTimes.delete(data.message.id);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
this.recordMetric('message.received', 1);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Conflict events
|
|
394
|
+
this.eventBus.on('conflict:resource', () => {
|
|
395
|
+
this.counters.conflictsDetected++;
|
|
396
|
+
this.recordMetric('conflict.detected', 1);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
this.eventBus.on('conflict:resolved', () => {
|
|
400
|
+
this.counters.conflictsResolved++;
|
|
401
|
+
this.recordMetric('conflict.resolved', 1);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Work stealing events
|
|
405
|
+
this.eventBus.on('workstealing:request', () => {
|
|
406
|
+
this.counters.workStealingEvents++;
|
|
407
|
+
this.recordMetric('workstealing.event', 1);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Circuit breaker events
|
|
411
|
+
this.eventBus.on('circuitbreaker:state-change', (data: any) => {
|
|
412
|
+
if (data.to === 'open') {
|
|
413
|
+
this.counters.circuitBreakerTrips++;
|
|
414
|
+
this.recordMetric('circuitbreaker.trip', 1);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Error events
|
|
419
|
+
this.eventBus.on(SystemEvents.SYSTEM_ERROR, () => {
|
|
420
|
+
this.counters.errors++;
|
|
421
|
+
this.recordMetric('error', 1);
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Collect comprehensive metrics
|
|
427
|
+
*/
|
|
428
|
+
private collectMetrics(): void {
|
|
429
|
+
const metrics = this.getCurrentMetrics();
|
|
430
|
+
|
|
431
|
+
// Emit metrics event
|
|
432
|
+
this.eventBus.emit('metrics:coordination', metrics);
|
|
433
|
+
|
|
434
|
+
// Log summary
|
|
435
|
+
this.logger.debug('Coordination metrics collected', {
|
|
436
|
+
activeTasks: metrics.taskMetrics.activeTasks,
|
|
437
|
+
activeAgents: metrics.agentMetrics.activeAgents,
|
|
438
|
+
lockedResources: metrics.resourceMetrics.lockedResources,
|
|
439
|
+
taskThroughput: metrics.taskMetrics.taskThroughput,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Calculate average from array of numbers
|
|
445
|
+
*/
|
|
446
|
+
private average(values: number[]): number {
|
|
447
|
+
if (values.length === 0) return 0;
|
|
448
|
+
return values.reduce((sum, val) => sum + val, 0) / values.length;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Get tasks grouped by priority
|
|
453
|
+
*/
|
|
454
|
+
private getTasksByPriority(): Record<string, number> {
|
|
455
|
+
const priorities = ['low', 'medium', 'high', 'critical'];
|
|
456
|
+
const result: Record<string, number> = {};
|
|
457
|
+
|
|
458
|
+
for (const priority of priorities) {
|
|
459
|
+
result[priority] = this.samples.filter(s =>
|
|
460
|
+
s.metric === 'task.created' && s.tags?.priority === priority
|
|
461
|
+
).length;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Get tasks grouped by type
|
|
469
|
+
*/
|
|
470
|
+
private getTasksByType(): Record<string, number> {
|
|
471
|
+
const types = new Set<string>();
|
|
472
|
+
|
|
473
|
+
for (const sample of this.samples) {
|
|
474
|
+
if (sample.metric === 'task.created' && sample.tags?.type) {
|
|
475
|
+
types.add(sample.tags.type);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const result: Record<string, number> = {};
|
|
480
|
+
for (const type of types) {
|
|
481
|
+
result[type] = this.samples.filter(s =>
|
|
482
|
+
s.metric === 'task.created' && s.tags?.type === type
|
|
483
|
+
).length;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return result;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Get agents grouped by type
|
|
491
|
+
*/
|
|
492
|
+
private getAgentsByType(): Record<string, number> {
|
|
493
|
+
const types = new Set<string>();
|
|
494
|
+
|
|
495
|
+
for (const sample of this.samples) {
|
|
496
|
+
if (sample.metric === 'agent.spawned' && sample.tags?.type) {
|
|
497
|
+
types.add(sample.tags.type);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const result: Record<string, number> = {};
|
|
502
|
+
for (const type of types) {
|
|
503
|
+
result[type] = this.samples.filter(s =>
|
|
504
|
+
s.metric === 'agent.spawned' && s.tags?.type === type
|
|
505
|
+
).length;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Calculate agent utilization percentage
|
|
513
|
+
*/
|
|
514
|
+
private calculateAgentUtilization(): number {
|
|
515
|
+
const totalAgents = this.gauges.activeAgents + this.gauges.idleAgents;
|
|
516
|
+
if (totalAgents === 0) return 0;
|
|
517
|
+
return (this.gauges.busyAgents / totalAgents) * 100;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Calculate average tasks per agent
|
|
522
|
+
*/
|
|
523
|
+
private calculateAvgTasksPerAgent(): number {
|
|
524
|
+
const totalAgents = this.gauges.activeAgents + this.gauges.idleAgents;
|
|
525
|
+
if (totalAgents === 0) return 0;
|
|
526
|
+
return this.gauges.activeTasks / totalAgents;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Calculate resource utilization percentage
|
|
531
|
+
*/
|
|
532
|
+
private calculateResourceUtilization(): number {
|
|
533
|
+
const totalResources = this.gauges.lockedResources + this.gauges.freeResources;
|
|
534
|
+
if (totalResources === 0) return 0;
|
|
535
|
+
return (this.gauges.lockedResources / totalResources) * 100;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Get current memory usage in MB
|
|
540
|
+
*/
|
|
541
|
+
private getMemoryUsage(): number {
|
|
542
|
+
if (typeof process !== 'undefined' && process.memoryUsage) {
|
|
543
|
+
return process.memoryUsage().heapUsed / 1024 / 1024;
|
|
544
|
+
}
|
|
545
|
+
return 0;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Get current CPU usage percentage
|
|
550
|
+
*/
|
|
551
|
+
private getCpuUsage(): number {
|
|
552
|
+
if (typeof process !== 'undefined' && process.cpuUsage) {
|
|
553
|
+
const usage = process.cpuUsage();
|
|
554
|
+
return (usage.user + usage.system) / 1000000; // Convert to seconds
|
|
555
|
+
}
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Clear all metrics data
|
|
561
|
+
*/
|
|
562
|
+
clearMetrics(): void {
|
|
563
|
+
this.samples = [];
|
|
564
|
+
this.taskStartTimes.clear();
|
|
565
|
+
this.messageStartTimes.clear();
|
|
566
|
+
this.lockStartTimes.clear();
|
|
567
|
+
|
|
568
|
+
// Reset counters
|
|
569
|
+
for (const key in this.counters) {
|
|
570
|
+
(this.counters as any)[key] = 0;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// Reset gauges
|
|
574
|
+
for (const key in this.gauges) {
|
|
575
|
+
(this.gauges as any)[key] = 0;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Clear histograms
|
|
579
|
+
for (const key in this.histograms) {
|
|
580
|
+
(this.histograms as any)[key] = [];
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
this.logger.info('Coordination metrics cleared');
|
|
584
|
+
}
|
|
585
|
+
}
|