claude-flow 3.5.54 → 3.5.56

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.5.54",
3
+ "version": "3.5.56",
4
4
  "description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -330,7 +330,7 @@ export async function benchmarkPretrainPipeline(config) {
330
330
  id: `pattern-${i}`,
331
331
  type: 'code-structure',
332
332
  embedding: embeddings[i],
333
- confidence: 0.85 + Math.random() * 0.1,
333
+ confidence: embeddings[i] ? 1.0 : 0, // real: has embedding = confident
334
334
  }));
335
335
  return { files: files.length, patterns: patterns.length };
336
336
  };
@@ -69,24 +69,25 @@ const getCommand = {
69
69
  ],
70
70
  action: async (ctx) => {
71
71
  const key = ctx.flags.key || ctx.args[0];
72
- // Default config values (loaded from actual config when available)
73
- const configValues = {
74
- 'version': '3.0.0',
75
- 'v3Mode': true,
76
- 'swarm.topology': 'hybrid',
77
- 'swarm.maxAgents': 15,
78
- 'swarm.autoScale': true,
79
- 'memory.backend': 'hybrid',
80
- 'memory.cacheSize': 256,
81
- 'mcp.transport': 'stdio',
82
- 'agents.defaultType': 'coder',
83
- 'agents.maxConcurrent': 15
84
- };
85
72
  if (!key) {
86
- // Show all config
73
+ // Show all config from actual config file (fall back to defaults)
74
+ const config = configManager.getConfig(ctx.cwd);
75
+ const flatEntries = {};
76
+ const flatten = (obj, prefix = '') => {
77
+ for (const [k, v] of Object.entries(obj)) {
78
+ const fullKey = prefix ? `${prefix}.${k}` : k;
79
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
80
+ flatten(v, fullKey);
81
+ }
82
+ else {
83
+ flatEntries[fullKey] = v;
84
+ }
85
+ }
86
+ };
87
+ flatten(config);
87
88
  if (ctx.flags.format === 'json') {
88
- output.printJson(configValues);
89
- return { success: true, data: configValues };
89
+ output.printJson(flatEntries);
90
+ return { success: true, data: flatEntries };
90
91
  }
91
92
  output.writeln();
92
93
  output.writeln(output.bold('Current Configuration'));
@@ -96,11 +97,11 @@ const getCommand = {
96
97
  { key: 'key', header: 'Key', width: 25 },
97
98
  { key: 'value', header: 'Value', width: 30 }
98
99
  ],
99
- data: Object.entries(configValues).map(([k, v]) => ({ key: k, value: String(v) }))
100
+ data: Object.entries(flatEntries).map(([k, v]) => ({ key: k, value: String(v) }))
100
101
  });
101
- return { success: true, data: configValues };
102
+ return { success: true, data: flatEntries };
102
103
  }
103
- const value = configValues[key];
104
+ const value = configManager.get(ctx.cwd, key);
104
105
  if (value === undefined) {
105
106
  output.printError(`Configuration key not found: ${key}`);
106
107
  return { success: false, exitCode: 1 };
@@ -187,12 +188,83 @@ const providersCommand = {
187
188
  }
188
189
  ],
189
190
  action: async (ctx) => {
190
- const providers = [
191
+ const defaultProviders = [
191
192
  { name: 'anthropic', model: 'claude-3-5-sonnet-20241022', priority: 1, enabled: true, status: 'Active' },
192
193
  { name: 'openrouter', model: 'claude-3.5-sonnet', priority: 2, enabled: false, status: 'Disabled' },
193
194
  { name: 'ollama', model: 'llama3.2', priority: 3, enabled: false, status: 'Disabled' },
194
195
  { name: 'gemini', model: 'gemini-2.0-flash', priority: 4, enabled: false, status: 'Disabled' }
195
196
  ];
197
+ // Handle mutation flags
198
+ const addProvider = ctx.flags.add;
199
+ const removeProvider = ctx.flags.remove;
200
+ const enableProvider = ctx.flags.enable;
201
+ const disableProvider = ctx.flags.disable;
202
+ if (addProvider || removeProvider || enableProvider || disableProvider) {
203
+ // Read current providers from config
204
+ let currentProviders = configManager.get(ctx.cwd, 'providers') || [];
205
+ if (!Array.isArray(currentProviders))
206
+ currentProviders = [];
207
+ if (addProvider) {
208
+ const exists = currentProviders.some((p) => p.name === addProvider);
209
+ if (exists) {
210
+ output.printError(`Provider '${addProvider}' already exists`);
211
+ return { success: false, exitCode: 1 };
212
+ }
213
+ currentProviders.push({ name: addProvider, enabled: true, priority: currentProviders.length + 1 });
214
+ output.writeln(output.success(`Added provider: ${addProvider}`));
215
+ }
216
+ if (removeProvider) {
217
+ const before = currentProviders.length;
218
+ currentProviders = currentProviders.filter((p) => p.name !== removeProvider);
219
+ if (currentProviders.length === before) {
220
+ output.printError(`Provider '${removeProvider}' not found`);
221
+ return { success: false, exitCode: 1 };
222
+ }
223
+ output.writeln(output.success(`Removed provider: ${removeProvider}`));
224
+ }
225
+ if (enableProvider) {
226
+ const p = currentProviders.find((p) => p.name === enableProvider);
227
+ if (p) {
228
+ p.enabled = true;
229
+ output.writeln(output.success(`Enabled provider: ${enableProvider}`));
230
+ }
231
+ else {
232
+ output.printError(`Provider '${enableProvider}' not found`);
233
+ return { success: false, exitCode: 1 };
234
+ }
235
+ }
236
+ if (disableProvider) {
237
+ const p = currentProviders.find((p) => p.name === disableProvider);
238
+ if (p) {
239
+ p.enabled = false;
240
+ output.writeln(output.success(`Disabled provider: ${disableProvider}`));
241
+ }
242
+ else {
243
+ output.printError(`Provider '${disableProvider}' not found`);
244
+ return { success: false, exitCode: 1 };
245
+ }
246
+ }
247
+ try {
248
+ configManager.set(ctx.cwd, 'providers', currentProviders);
249
+ }
250
+ catch (err) {
251
+ const message = err instanceof Error ? err.message : String(err);
252
+ output.printError(`Failed to save providers: ${message}`);
253
+ return { success: false, exitCode: 1 };
254
+ }
255
+ return { success: true, data: currentProviders };
256
+ }
257
+ // Read providers from config, fall back to defaults
258
+ const configuredProviders = configManager.get(ctx.cwd, 'providers');
259
+ const providers = (Array.isArray(configuredProviders) && configuredProviders.length > 0)
260
+ ? configuredProviders.map((p, i) => ({
261
+ name: String(p.name || ''),
262
+ model: String(p.model || ''),
263
+ priority: Number(p.priority || i + 1),
264
+ enabled: p.enabled !== false,
265
+ status: p.enabled !== false ? 'Active' : 'Disabled',
266
+ }))
267
+ : defaultProviders;
196
268
  if (ctx.flags.format === 'json') {
197
269
  output.printJson(providers);
198
270
  return { success: true, data: providers };
@@ -237,49 +237,88 @@ const monitorCommand = {
237
237
  const format = ctx.flags?.format || 'dashboard';
238
238
  const watch = ctx.flags?.watch === true;
239
239
  const alerts = ctx.flags?.alerts !== false;
240
- // Default monitoring data (updated by real process stats when available)
240
+ // Gather real system metrics where possible
241
+ const os = await import('node:os');
242
+ const memUsage = process.memoryUsage();
243
+ const loadAvg = os.loadavg();
244
+ const totalMem = os.totalmem();
245
+ const freeMem = os.freemem();
246
+ const usedMemMB = Math.round((totalMem - freeMem) / 1024 / 1024);
247
+ const totalMemMB = Math.round(totalMem / 1024 / 1024);
248
+ // Try to read agent and task counts from local store files
249
+ let agentCount = 0;
250
+ let taskCounts = { running: 0, queued: 0, completed: 0, failed: 0 };
251
+ try {
252
+ const agentStorePath = resolve('.claude-flow/agents/store.json');
253
+ if (existsSync(agentStorePath)) {
254
+ const agentStore = JSON.parse(readFileSync(agentStorePath, 'utf-8'));
255
+ const agents = Array.isArray(agentStore) ? agentStore : Object.values(agentStore.agents || agentStore || {});
256
+ agentCount = agents.length;
257
+ }
258
+ }
259
+ catch { /* no agent store */ }
260
+ try {
261
+ const taskStorePath = resolve('.claude-flow/tasks/store.json');
262
+ if (existsSync(taskStorePath)) {
263
+ const taskStore = JSON.parse(readFileSync(taskStorePath, 'utf-8'));
264
+ const tasks = Array.isArray(taskStore) ? taskStore : Object.values(taskStore.tasks || taskStore || {});
265
+ for (const t of tasks) {
266
+ if (t.status === 'running')
267
+ taskCounts.running++;
268
+ else if (t.status === 'queued' || t.status === 'pending')
269
+ taskCounts.queued++;
270
+ else if (t.status === 'completed' || t.status === 'done')
271
+ taskCounts.completed++;
272
+ else if (t.status === 'failed' || t.status === 'error')
273
+ taskCounts.failed++;
274
+ }
275
+ }
276
+ }
277
+ catch { /* no task store */ }
241
278
  const metrics = {
242
279
  timestamp: new Date().toISOString(),
243
280
  system: {
244
- cpuUsage: Math.random() * 30 + 5,
245
- memoryUsed: Math.floor(Math.random() * 500) + 100,
246
- memoryTotal: 2048,
247
- uptime: Math.floor(Math.random() * 86400),
281
+ cpuLoadAvg1m: loadAvg[0] !== undefined ? parseFloat(loadAvg[0].toFixed(2)) : null,
282
+ cpuLoadAvg5m: loadAvg[1] !== undefined ? parseFloat(loadAvg[1].toFixed(2)) : null,
283
+ cpuCount: os.cpus().length,
284
+ memoryUsedMB: usedMemMB,
285
+ memoryTotalMB: totalMemMB,
286
+ processRssMB: Math.round(memUsage.rss / 1024 / 1024),
287
+ processHeapMB: Math.round(memUsage.heapUsed / 1024 / 1024),
288
+ uptime: Math.floor(process.uptime()),
248
289
  },
249
290
  agents: {
250
- active: Math.floor(Math.random() * 5),
251
- idle: Math.floor(Math.random() * 3),
252
- total: 0,
253
- poolSize: 10,
291
+ total: agentCount,
292
+ _note: agentCount === 0 ? 'No agent store found at .claude-flow/agents/store.json' : null,
254
293
  },
255
294
  tasks: {
256
- running: Math.floor(Math.random() * 3),
257
- queued: Math.floor(Math.random() * 5),
258
- completed: Math.floor(Math.random() * 100) + 50,
259
- failed: Math.floor(Math.random() * 5),
295
+ ...taskCounts,
296
+ _note: (taskCounts.running + taskCounts.queued + taskCounts.completed + taskCounts.failed) === 0
297
+ ? 'No task store found at .claude-flow/tasks/store.json' : null,
260
298
  },
261
299
  memory: {
262
- vectorCount: Math.floor(Math.random() * 10000) + 1000,
263
- indexSize: Math.floor(Math.random() * 50) + 10,
264
- cacheHitRate: Math.random() * 0.3 + 0.65,
265
- avgSearchTime: Math.random() * 5 + 1,
300
+ vectorCount: null,
301
+ indexSize: null,
302
+ cacheHitRate: null,
303
+ avgSearchTime: null,
304
+ _note: 'Memory service metrics not available from process monitor. Use "memory stats" command.',
266
305
  },
267
306
  network: {
268
- mcpConnections: Math.floor(Math.random() * 3) + 1,
269
- requestsPerMin: Math.floor(Math.random() * 100) + 20,
270
- avgLatency: Math.random() * 50 + 10,
307
+ mcpConnections: null,
308
+ requestsPerMin: null,
309
+ avgLatency: null,
310
+ _note: 'Network metrics not available from process monitor. Use "mcp status" command.',
271
311
  },
272
312
  };
273
- metrics.agents.total = metrics.agents.active + metrics.agents.idle;
274
313
  if (format === 'json') {
275
314
  console.log(JSON.stringify(metrics, null, 2));
276
315
  return { success: true, data: metrics };
277
316
  }
278
317
  if (format === 'compact') {
279
318
  console.log('\n📊 Process Monitor (compact)\n');
280
- console.log(`CPU: ${metrics.system.cpuUsage.toFixed(1)}% | Memory: ${metrics.system.memoryUsed}MB/${metrics.system.memoryTotal}MB`);
281
- console.log(`Agents: ${metrics.agents.active}/${metrics.agents.total} active | Tasks: ${metrics.tasks.running} running, ${metrics.tasks.queued} queued`);
282
- console.log(`Memory: ${metrics.memory.vectorCount} vectors | Cache: ${(metrics.memory.cacheHitRate * 100).toFixed(1)}%`);
319
+ const loadStr = metrics.system.cpuLoadAvg1m !== null ? `load ${metrics.system.cpuLoadAvg1m.toFixed(2)}` : 'n/a';
320
+ console.log(`CPU: ${loadStr} (${metrics.system.cpuCount} cores) | Memory: ${metrics.system.memoryUsedMB}MB/${metrics.system.memoryTotalMB}MB`);
321
+ console.log(`Agents: ${metrics.agents.total} total | Tasks: ${metrics.tasks.running} running, ${metrics.tasks.queued} queued`);
283
322
  return { success: true, data: metrics };
284
323
  }
285
324
  // Dashboard format
@@ -288,15 +327,17 @@ const monitorCommand = {
288
327
  console.log('╠══════════════════════════════════════════════════════════════╣');
289
328
  // System metrics
290
329
  console.log('║ SYSTEM ║');
291
- const cpuBar = '█'.repeat(Math.floor(metrics.system.cpuUsage / 5)) + '░'.repeat(20 - Math.floor(metrics.system.cpuUsage / 5));
292
- const memPercent = (metrics.system.memoryUsed / metrics.system.memoryTotal) * 100;
330
+ const cpuDisplay = metrics.system.cpuLoadAvg1m !== null ? metrics.system.cpuLoadAvg1m : 0;
331
+ const cpuPercent = Math.min(100, (cpuDisplay / (metrics.system.cpuCount || 1)) * 100);
332
+ const cpuBar = '█'.repeat(Math.floor(cpuPercent / 5)) + '░'.repeat(20 - Math.floor(cpuPercent / 5));
333
+ const memPercent = (metrics.system.memoryUsedMB / metrics.system.memoryTotalMB) * 100;
293
334
  const memBar = '█'.repeat(Math.floor(memPercent / 5)) + '░'.repeat(20 - Math.floor(memPercent / 5));
294
- console.log(`║ CPU: [${cpuBar}] ${metrics.system.cpuUsage.toFixed(1).padStart(5)}% ║`);
295
- console.log(`║ Memory: [${memBar}] ${metrics.system.memoryUsed}MB/${metrics.system.memoryTotal}MB ║`);
335
+ console.log(`║ CPU: [${cpuBar}] load ${cpuDisplay.toFixed(2).padStart(5)} ║`);
336
+ console.log(`║ Memory: [${memBar}] ${metrics.system.memoryUsedMB}MB/${metrics.system.memoryTotalMB}MB ║`);
296
337
  console.log('╠══════════════════════════════════════════════════════════════╣');
297
338
  // Agents
298
339
  console.log('║ AGENTS ║');
299
- console.log(`║ Active: ${metrics.agents.active.toString().padEnd(3)} Idle: ${metrics.agents.idle.toString().padEnd(3)} Pool: ${metrics.agents.poolSize.toString().padEnd(3)} ║`);
340
+ console.log(`║ Total: ${metrics.agents.total.toString().padEnd(5)} ║`);
300
341
  console.log('╠══════════════════════════════════════════════════════════════╣');
301
342
  // Tasks
302
343
  console.log('║ TASKS ║');
@@ -304,18 +345,16 @@ const monitorCommand = {
304
345
  console.log('╠══════════════════════════════════════════════════════════════╣');
305
346
  // Memory service
306
347
  console.log('║ MEMORY SERVICE ║');
307
- console.log(`║ Vectors: ${metrics.memory.vectorCount.toString().padEnd(7)} Index: ${metrics.memory.indexSize}MB ║`);
308
- console.log(`║ Cache Hit: ${(metrics.memory.cacheHitRate * 100).toFixed(1)}% Avg Search: ${metrics.memory.avgSearchTime.toFixed(2)}ms ║`);
348
+ console.log('║ Metrics not available. Use "memory stats" command. ║');
309
349
  console.log('╠══════════════════════════════════════════════════════════════╣');
310
350
  // Network
311
351
  console.log('║ NETWORK ║');
312
- console.log(`║ MCP Connections: ${metrics.network.mcpConnections} Requests/min: ${metrics.network.requestsPerMin.toString().padEnd(5)} ║`);
313
- console.log(`║ Avg Latency: ${metrics.network.avgLatency.toFixed(1)}ms ║`);
352
+ console.log('║ Metrics not available. Use "mcp status" command. ║');
314
353
  console.log('╚══════════════════════════════════════════════════════════════╝');
315
354
  if (alerts) {
316
355
  console.log('\n📢 Alerts:');
317
- if (metrics.system.cpuUsage > 80) {
318
- console.log(' ⚠️ High CPU usage detected');
356
+ if (cpuPercent > 80) {
357
+ console.log(' ⚠️ High CPU load detected');
319
358
  }
320
359
  if (memPercent > 80) {
321
360
  console.log(' ⚠️ High memory usage detected');
@@ -323,10 +362,7 @@ const monitorCommand = {
323
362
  if (metrics.tasks.failed > 10) {
324
363
  console.log(' ⚠️ Elevated task failure rate');
325
364
  }
326
- if (metrics.memory.cacheHitRate < 0.5) {
327
- console.log(' ⚠️ Low cache hit rate');
328
- }
329
- if (metrics.system.cpuUsage <= 80 && memPercent <= 80 && metrics.tasks.failed <= 10 && metrics.memory.cacheHitRate >= 0.5) {
365
+ if (cpuPercent <= 80 && memPercent <= 80 && metrics.tasks.failed <= 10) {
330
366
  console.log(' ✅ All systems nominal');
331
367
  }
332
368
  }
@@ -558,38 +594,56 @@ const logsCommand = {
558
594
  console.log(`\n📜 Process Logs (${source})\n`);
559
595
  console.log(` Level: ${level}+ | Lines: ${tail}${since ? ` | Since: ${since}` : ''}${grep ? ` | Filter: ${grep}` : ''}`);
560
596
  console.log('─'.repeat(70));
561
- // Default log entries (loaded from actual logs when available)
562
- const levels = ['debug', 'info', 'warn', 'error'];
597
+ // Read actual log files from .claude-flow/logs/ if they exist
598
+ const logsDir = resolve('.claude-flow/logs');
599
+ let logEntries = [];
563
600
  const levelIcons = {
564
601
  debug: '🔍',
565
602
  info: 'ℹ️ ',
566
603
  warn: '⚠️ ',
567
604
  error: '❌',
568
605
  };
569
- const sources = ['daemon', 'worker-task', 'worker-memory', 'coordinator'];
570
- const messages = [
571
- 'Processing task queue...',
572
- 'Agent spawned successfully',
573
- 'Memory index optimized',
574
- 'Configuration reloaded',
575
- 'MCP connection established',
576
- 'Task completed: 42ms',
577
- 'Cache hit rate: 87%',
578
- 'Swarm topology updated',
579
- 'Health check passed',
580
- 'Neural pattern learned',
581
- ];
606
+ const levels = ['debug', 'info', 'warn', 'error'];
582
607
  const minLevelIdx = levels.indexOf(level);
583
- const now = Date.now();
584
- for (let i = 0; i < Math.min(tail, 15); i++) {
585
- const logLevel = levels[Math.floor(Math.random() * (levels.length - minLevelIdx)) + minLevelIdx];
586
- const logSource = sources[Math.floor(Math.random() * sources.length)];
587
- const message = messages[Math.floor(Math.random() * messages.length)];
588
- const timestamp = new Date(now - (tail - i) * 1000 * 60).toISOString().substring(11, 23);
589
- if (grep && !message.toLowerCase().includes(grep.toLowerCase())) {
590
- continue;
608
+ if (existsSync(logsDir)) {
609
+ try {
610
+ const { readdirSync } = await import('node:fs');
611
+ const logFiles = readdirSync(logsDir)
612
+ .filter(f => f.endsWith('.log'))
613
+ .filter(f => source === 'all' || f.includes(source));
614
+ for (const file of logFiles) {
615
+ try {
616
+ const content = readFileSync(resolve(logsDir, file), 'utf-8');
617
+ const lines = content.split('\n').filter(l => l.trim());
618
+ for (const line of lines) {
619
+ // Filter by log level if detectable
620
+ const lineLower = line.toLowerCase();
621
+ const lineLevel = levels.find(l => lineLower.includes(`[${l}]`) || lineLower.includes(l));
622
+ if (lineLevel && levels.indexOf(lineLevel) < minLevelIdx)
623
+ continue;
624
+ if (grep && !lineLower.includes(grep.toLowerCase()))
625
+ continue;
626
+ logEntries.push(line);
627
+ }
628
+ }
629
+ catch { /* skip unreadable files */ }
630
+ }
631
+ }
632
+ catch { /* skip if dir unreadable */ }
633
+ }
634
+ if (logEntries.length === 0) {
635
+ console.log(' No log entries found.');
636
+ console.log(` Log directory: ${logsDir}`);
637
+ if (!existsSync(logsDir)) {
638
+ console.log(' (directory does not exist)');
639
+ }
640
+ }
641
+ else {
642
+ // Show the last N entries
643
+ const entriesToShow = logEntries.slice(-tail);
644
+ for (const entry of entriesToShow) {
645
+ console.log(entry);
591
646
  }
592
- console.log(`${timestamp} ${levelIcons[logLevel]} [${logSource.padEnd(14)}] ${message}`);
593
647
  }
594
648
  console.log('─'.repeat(70));
595
649
  if (follow) {
@@ -111,8 +111,8 @@ async function getSystemStatus() {
111
111
  performance: {
112
112
  cpuUsage: getProcessCpuUsage(),
113
113
  memoryUsage: getProcessMemoryUsage(),
114
- flashAttention: '2.8x speedup',
115
- searchSpeed: '150x faster'
114
+ flashAttention: 'not measured',
115
+ searchSpeed: 'not measured'
116
116
  }
117
117
  };
118
118
  }
@@ -457,8 +457,6 @@ export const agentTools = [
457
457
  const degradedAgents = agents.filter(a => a.health >= 0.3 && a.health < threshold);
458
458
  const unhealthyAgents = agents.filter(a => a.health < 0.3);
459
459
  const avgHealth = agents.length > 0 ? agents.reduce((sum, a) => sum + a.health, 0) / agents.length : 1;
460
- const avgCpu = agents.length > 0 ? 35 + Math.random() * 30 : 0; // Simulated CPU
461
- const avgMemory = avgHealth * 0.6; // Correlated with health
462
460
  return {
463
461
  // CLI expected fields
464
462
  agents: agents.map(a => {
@@ -468,19 +466,17 @@ export const agentTools = [
468
466
  type: a.agentType,
469
467
  health: a.health >= threshold ? 'healthy' : (a.health >= 0.3 ? 'degraded' : 'unhealthy'),
470
468
  uptime,
471
- memory: { used: Math.floor(256 * (1 - a.health * 0.3)), limit: 512 },
472
- cpu: 20 + Math.floor(a.health * 40),
473
469
  tasks: { active: a.taskCount > 0 ? 1 : 0, queued: 0, completed: a.taskCount, failed: 0 },
474
- latency: { avg: 50 + Math.floor((1 - a.health) * 100), p99: 150 + Math.floor((1 - a.health) * 200) },
475
- errors: { count: a.health < threshold ? 1 : 0 },
470
+ _note: 'Per-agent OS metrics not available use system_metrics for real CPU/memory',
476
471
  };
477
472
  }),
478
473
  overall: {
479
474
  healthy: healthyAgents.length,
480
475
  degraded: degradedAgents.length,
481
476
  unhealthy: unhealthyAgents.length,
482
- avgCpu,
483
- avgMemory,
477
+ cpu: null,
478
+ memory: null,
479
+ _note: 'Per-agent CPU/memory not available — use system_metrics for real OS-level stats',
484
480
  score: Math.round(avgHealth * 100),
485
481
  issues: unhealthyAgents.length,
486
482
  },
@@ -710,6 +710,21 @@ export const claimsTools = [
710
710
  }
711
711
  }
712
712
  }
713
+ // When not a dry run, execute the suggested moves
714
+ if (!dryRun) {
715
+ for (const suggestion of suggestions) {
716
+ const claim = store.claims[suggestion.issueId];
717
+ if (claim) {
718
+ const newOwner = parseClaimant(suggestion.to);
719
+ if (newOwner) {
720
+ claim.claimant = newOwner;
721
+ claim.statusChangedAt = new Date().toISOString();
722
+ store.claims[suggestion.issueId] = claim;
723
+ }
724
+ }
725
+ }
726
+ saveClaims(store);
727
+ }
713
728
  return {
714
729
  success: true,
715
730
  dryRun,
@@ -633,22 +633,29 @@ export const coordinationTools = [
633
633
  const activeNodes = nodes.filter(n => n.status === 'active');
634
634
  const metrics = {
635
635
  latency: {
636
- avg: 25 + Math.random() * 20,
637
- p50: 20 + Math.random() * 15,
638
- p95: 50 + Math.random() * 30,
639
- p99: 100 + Math.random() * 50,
636
+ avg: null,
637
+ p50: null,
638
+ p95: null,
639
+ p99: null,
640
640
  unit: 'ms',
641
+ _note: 'Real-time latency metrics not available — coordination is state-tracking only',
641
642
  },
642
643
  throughput: {
643
- current: Math.floor(Math.random() * 1000) + 500,
644
- peak: Math.floor(Math.random() * 2000) + 1000,
645
- avg: Math.floor(Math.random() * 800) + 400,
644
+ current: null,
645
+ peak: null,
646
+ avg: null,
646
647
  unit: 'ops/s',
648
+ _note: 'Real-time throughput metrics not available — coordination is state-tracking only',
647
649
  },
648
650
  availability: {
649
- uptime: 99.9 + Math.random() * 0.09,
651
+ uptime: null,
652
+ _note: 'Uptime not tracked — coordination store has no persistent start time',
650
653
  activeNodes: activeNodes.length,
651
654
  totalNodes: nodes.length,
655
+ syncCount: store.sync.syncCount,
656
+ lastSync: store.sync.lastSync,
657
+ conflicts: store.sync.conflicts,
658
+ pendingChanges: store.sync.pendingChanges,
652
659
  syncStatus: store.sync.conflicts === 0 ? 'healthy' : 'conflicts',
653
660
  },
654
661
  };