claude-flow 2.0.0-alpha.62 ā 2.0.0-alpha.63
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/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +54 -0
- package/.claude/commands/analysis/token-efficiency.md +2 -1
- package/.claude/commands/automation/self-healing.md +47 -2
- package/.claude/commands/automation/session-memory.md +39 -10
- package/.claude/commands/automation/smart-agents.md +36 -8
- package/.claude/commands/github/code-review-swarm.md +80 -15
- package/.claude/commands/github/github-modes.md +14 -14
- package/.claude/commands/github/issue-tracker.md +19 -16
- package/.claude/commands/github/multi-repo-swarm.md +114 -16
- package/.claude/commands/github/pr-manager.md +5 -4
- package/.claude/commands/github/project-board-sync.md +38 -5
- package/.claude/commands/github/release-manager.md +19 -19
- package/.claude/commands/github/release-swarm.md +102 -13
- package/.claude/commands/github/repo-architect.md +6 -6
- package/.claude/commands/github/swarm-issue.md +139 -17
- package/.claude/commands/github/swarm-pr.md +49 -15
- package/.claude/commands/github/sync-coordinator.md +33 -33
- package/.claude/commands/github/workflow-automation.md +37 -10
- package/.claude/commands/hooks/overview.md +2 -2
- package/.claude/commands/hooks/setup.md +7 -7
- package/.claude/commands/memory/neural.md +10 -5
- package/.claude/commands/memory/usage.md +9 -5
- package/.claude/commands/monitoring/agents.md +7 -5
- package/.claude/commands/monitoring/status.md +8 -5
- package/.claude/commands/optimization/auto-topology.md +13 -1
- package/.claude/commands/optimization/parallel-execution.md +7 -1
- package/.claude/commands/sparc/analyzer.md +28 -2
- package/.claude/commands/sparc/architect.md +27 -1
- package/.claude/commands/sparc/batch-executor.md +27 -1
- package/.claude/commands/sparc/coder.md +27 -1
- package/.claude/commands/sparc/debugger.md +27 -1
- package/.claude/commands/sparc/designer.md +27 -1
- package/.claude/commands/sparc/documenter.md +27 -1
- package/.claude/commands/sparc/innovator.md +27 -1
- package/.claude/commands/sparc/memory-manager.md +27 -1
- package/.claude/commands/sparc/optimizer.md +27 -1
- package/.claude/commands/sparc/orchestrator.md +106 -2
- package/.claude/commands/sparc/researcher.md +27 -1
- package/.claude/commands/sparc/reviewer.md +27 -1
- package/.claude/commands/sparc/sparc-modes.md +137 -5
- package/.claude/commands/sparc/swarm-coordinator.md +27 -1
- package/.claude/commands/sparc/tdd.md +27 -1
- package/.claude/commands/sparc/tester.md +27 -1
- package/.claude/commands/sparc/workflow-manager.md +27 -1
- package/.claude/commands/swarm/analysis.md +82 -5
- package/.claude/commands/swarm/development.md +83 -6
- package/.claude/commands/swarm/examples.md +141 -3
- package/.claude/commands/swarm/maintenance.md +92 -8
- package/.claude/commands/swarm/optimization.md +107 -9
- package/.claude/commands/swarm/research.md +126 -8
- package/.claude/commands/swarm/testing.md +121 -9
- package/.claude/commands/training/neural-patterns.md +27 -2
- package/.claude/commands/training/specialization.md +13 -3
- package/.claude/commands/workflows/development.md +43 -4
- package/.claude/commands/workflows/research.md +26 -2
- package/README.md +8 -0
- package/bin/claude-flow +1 -1
- package/dist/cli/simple-commands/hive-mind/mcp-wrapper.d.ts +66 -0
- package/dist/cli/simple-commands/hive-mind/mcp-wrapper.d.ts.map +1 -1
- package/dist/cli/simple-commands/hive-mind/mcp-wrapper.js +220 -2
- package/dist/cli/simple-commands/hive-mind/mcp-wrapper.js.map +1 -1
- package/dist/cli/simple-commands/hive-mind.d.ts.map +1 -1
- package/dist/cli/simple-commands/hive-mind.js +83 -5
- package/dist/cli/simple-commands/hive-mind.js.map +1 -1
- package/dist/memory/fallback-store.d.ts +1 -0
- package/dist/memory/fallback-store.d.ts.map +1 -1
- package/dist/memory/fallback-store.js +25 -3
- package/dist/memory/fallback-store.js.map +1 -1
- package/dist/memory/sqlite-store.d.ts +34 -0
- package/dist/memory/sqlite-store.d.ts.map +1 -0
- package/dist/memory/sqlite-store.js +2 -3
- package/dist/memory/sqlite-store.js.map +1 -1
- package/dist/memory/sqlite-wrapper.d.ts +38 -0
- package/dist/memory/sqlite-wrapper.d.ts.map +1 -0
- package/dist/memory/sqlite-wrapper.js +157 -0
- package/dist/memory/sqlite-wrapper.js.map +1 -0
- package/package.json +1 -1
- package/src/api/claude-api-errors.ts +248 -0
- package/src/api/claude-client-enhanced.ts +616 -0
- package/src/api/claude-client.ts +282 -14
- package/src/cli/help-text.js +2 -1
- package/src/cli/simple-commands/coordination.js +73 -49
- package/src/cli/simple-commands/hive-mind/auto-save-middleware.js +6 -6
- package/src/cli/simple-commands/hive-mind/mcp-wrapper.js +327 -8
- package/src/cli/simple-commands/hive-mind/session-manager.js +330 -108
- package/src/cli/simple-commands/hive-mind.js +192 -11
- package/src/cli/simple-commands/init/claude-commands/optimized-slash-commands.js +53 -28
- package/src/cli/simple-commands/init/claude-commands/slash-commands.js +36 -14
- package/src/cli/simple-commands/init/claude-commands/sparc-commands.js +107 -30
- package/src/cli/simple-commands/init/copy-revised-templates.js +175 -0
- package/src/cli/simple-commands/init/index.js +156 -235
- package/src/cli/simple-commands/init/template-copier.js +583 -0
- package/src/cli/simple-commands/init/templates/coordination.md +16 -0
- package/src/cli/simple-commands/init/templates/memory-bank.md +16 -0
- package/src/cli/simple-commands/init/templates/settings.json.enhanced +35 -0
- package/src/cli/simple-commands/init/templates/sparc-modes.js +634 -23
- package/src/hive-mind/core/DatabaseManager.ts +75 -16
- package/src/memory/backends/sqlite.ts +21 -3
- package/src/memory/fallback-store.js +35 -3
- package/src/memory/sqlite-store.js +2 -3
- package/src/memory/sqlite-wrapper.js +173 -0
package/src/api/claude-client.ts
CHANGED
|
@@ -7,6 +7,19 @@ import { EventEmitter } from 'events';
|
|
|
7
7
|
import { ILogger } from '../core/logger.js';
|
|
8
8
|
import { ConfigManager } from '../config/config-manager.js';
|
|
9
9
|
import { getErrorMessage } from '../utils/error-handler.js';
|
|
10
|
+
import {
|
|
11
|
+
ClaudeAPIError,
|
|
12
|
+
ClaudeInternalServerError,
|
|
13
|
+
ClaudeServiceUnavailableError,
|
|
14
|
+
ClaudeRateLimitError,
|
|
15
|
+
ClaudeTimeoutError,
|
|
16
|
+
ClaudeNetworkError,
|
|
17
|
+
ClaudeAuthenticationError,
|
|
18
|
+
ClaudeValidationError,
|
|
19
|
+
HealthCheckResult,
|
|
20
|
+
getUserFriendlyError,
|
|
21
|
+
} from './claude-api-errors.js';
|
|
22
|
+
import { circuitBreaker, CircuitBreaker } from '../utils/helpers.js';
|
|
10
23
|
|
|
11
24
|
export interface ClaudeAPIConfig {
|
|
12
25
|
apiKey: string;
|
|
@@ -20,6 +33,13 @@ export interface ClaudeAPIConfig {
|
|
|
20
33
|
timeout?: number;
|
|
21
34
|
retryAttempts?: number;
|
|
22
35
|
retryDelay?: number;
|
|
36
|
+
// Enhanced error handling options
|
|
37
|
+
enableHealthCheck?: boolean;
|
|
38
|
+
healthCheckInterval?: number;
|
|
39
|
+
circuitBreakerThreshold?: number;
|
|
40
|
+
circuitBreakerTimeout?: number;
|
|
41
|
+
circuitBreakerResetTimeout?: number;
|
|
42
|
+
retryJitter?: boolean;
|
|
23
43
|
}
|
|
24
44
|
|
|
25
45
|
export type ClaudeModel =
|
|
@@ -105,6 +125,9 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
105
125
|
private defaultModel: ClaudeModel = 'claude-3-sonnet-20240229';
|
|
106
126
|
private defaultTemperature: number = 0.7;
|
|
107
127
|
private defaultMaxTokens: number = 4096;
|
|
128
|
+
private circuitBreaker: CircuitBreaker;
|
|
129
|
+
private lastHealthCheck?: HealthCheckResult;
|
|
130
|
+
private healthCheckTimer?: NodeJS.Timeout;
|
|
108
131
|
|
|
109
132
|
constructor(logger: ILogger, configManager: ConfigManager, config?: Partial<ClaudeAPIConfig>) {
|
|
110
133
|
super();
|
|
@@ -113,6 +136,18 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
113
136
|
|
|
114
137
|
// Load config from environment and merge with provided config
|
|
115
138
|
this.config = this.loadConfiguration(config);
|
|
139
|
+
|
|
140
|
+
// Initialize circuit breaker for API reliability
|
|
141
|
+
this.circuitBreaker = circuitBreaker('claude-api', {
|
|
142
|
+
threshold: this.config.circuitBreakerThreshold || 5,
|
|
143
|
+
timeout: this.config.circuitBreakerTimeout || 60000,
|
|
144
|
+
resetTimeout: this.config.circuitBreakerResetTimeout || 300000,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Start health check if enabled
|
|
148
|
+
if (this.config.enableHealthCheck) {
|
|
149
|
+
this.startHealthCheck();
|
|
150
|
+
}
|
|
116
151
|
}
|
|
117
152
|
|
|
118
153
|
/**
|
|
@@ -132,6 +167,13 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
132
167
|
timeout: 60000, // 60 seconds
|
|
133
168
|
retryAttempts: 3,
|
|
134
169
|
retryDelay: 1000,
|
|
170
|
+
// Enhanced error handling defaults
|
|
171
|
+
enableHealthCheck: false,
|
|
172
|
+
healthCheckInterval: 300000, // 5 minutes
|
|
173
|
+
circuitBreakerThreshold: 5,
|
|
174
|
+
circuitBreakerTimeout: 60000,
|
|
175
|
+
circuitBreakerResetTimeout: 300000,
|
|
176
|
+
retryJitter: true,
|
|
135
177
|
};
|
|
136
178
|
|
|
137
179
|
// Load from environment variables
|
|
@@ -173,23 +215,23 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
173
215
|
*/
|
|
174
216
|
private validateConfiguration(config: ClaudeAPIConfig): void {
|
|
175
217
|
if (!config.apiKey) {
|
|
176
|
-
throw new
|
|
218
|
+
throw new ClaudeAuthenticationError('Claude API key is required. Set ANTHROPIC_API_KEY environment variable.');
|
|
177
219
|
}
|
|
178
220
|
|
|
179
221
|
if (config.temperature !== undefined) {
|
|
180
222
|
if (config.temperature < 0 || config.temperature > 1) {
|
|
181
|
-
throw new
|
|
223
|
+
throw new ClaudeValidationError('Temperature must be between 0 and 1');
|
|
182
224
|
}
|
|
183
225
|
}
|
|
184
226
|
|
|
185
227
|
if (config.topP !== undefined) {
|
|
186
228
|
if (config.topP < 0 || config.topP > 1) {
|
|
187
|
-
throw new
|
|
229
|
+
throw new ClaudeValidationError('Top-p must be between 0 and 1');
|
|
188
230
|
}
|
|
189
231
|
}
|
|
190
232
|
|
|
191
233
|
if (config.maxTokens !== undefined && (config.maxTokens < 1 || config.maxTokens > 100000)) {
|
|
192
|
-
throw new
|
|
234
|
+
throw new ClaudeValidationError('Max tokens must be between 1 and 100000');
|
|
193
235
|
}
|
|
194
236
|
}
|
|
195
237
|
|
|
@@ -256,7 +298,7 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
256
298
|
* Send a non-streaming request
|
|
257
299
|
*/
|
|
258
300
|
private async sendRequest(request: ClaudeRequest): Promise<ClaudeResponse> {
|
|
259
|
-
let lastError:
|
|
301
|
+
let lastError: ClaudeAPIError | undefined;
|
|
260
302
|
|
|
261
303
|
for (let attempt = 0; attempt < (this.config.retryAttempts || 3); attempt++) {
|
|
262
304
|
try {
|
|
@@ -277,8 +319,16 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
277
319
|
clearTimeout(timeout);
|
|
278
320
|
|
|
279
321
|
if (!response.ok) {
|
|
280
|
-
const
|
|
281
|
-
|
|
322
|
+
const errorText = await response.text();
|
|
323
|
+
let errorData: any;
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
errorData = JSON.parse(errorText);
|
|
327
|
+
} catch {
|
|
328
|
+
errorData = { message: errorText };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
throw this.createAPIError(response.status, errorData);
|
|
282
332
|
}
|
|
283
333
|
|
|
284
334
|
const data = (await response.json()) as ClaudeResponse;
|
|
@@ -293,21 +343,31 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
293
343
|
this.emit('response', data);
|
|
294
344
|
return data;
|
|
295
345
|
} catch (error) {
|
|
296
|
-
lastError = error
|
|
346
|
+
lastError = this.transformError(error);
|
|
347
|
+
|
|
348
|
+
// Don't retry non-retryable errors
|
|
349
|
+
if (!lastError.retryable) {
|
|
350
|
+
this.handleError(lastError);
|
|
351
|
+
throw lastError;
|
|
352
|
+
}
|
|
353
|
+
|
|
297
354
|
this.logger.warn(
|
|
298
355
|
`Claude API request failed (attempt ${attempt + 1}/${this.config.retryAttempts})`,
|
|
299
356
|
{
|
|
300
|
-
error:
|
|
357
|
+
error: lastError.message,
|
|
358
|
+
statusCode: lastError.statusCode,
|
|
359
|
+
retryable: lastError.retryable,
|
|
301
360
|
},
|
|
302
361
|
);
|
|
303
362
|
|
|
304
363
|
if (attempt < (this.config.retryAttempts || 3) - 1) {
|
|
305
|
-
|
|
364
|
+
const delay = this.calculateRetryDelay(attempt, lastError);
|
|
365
|
+
await this.delay(delay);
|
|
306
366
|
}
|
|
307
367
|
}
|
|
308
368
|
}
|
|
309
369
|
|
|
310
|
-
this.
|
|
370
|
+
this.handleError(lastError!);
|
|
311
371
|
throw lastError;
|
|
312
372
|
}
|
|
313
373
|
|
|
@@ -331,12 +391,20 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
331
391
|
});
|
|
332
392
|
|
|
333
393
|
if (!response.ok) {
|
|
334
|
-
const
|
|
335
|
-
|
|
394
|
+
const errorText = await response.text();
|
|
395
|
+
let errorData: any;
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
errorData = JSON.parse(errorText);
|
|
399
|
+
} catch {
|
|
400
|
+
errorData = { message: errorText };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
throw this.createAPIError(response.status, errorData);
|
|
336
404
|
}
|
|
337
405
|
|
|
338
406
|
if (!response.body) {
|
|
339
|
-
throw new
|
|
407
|
+
throw new ClaudeAPIError('Response body is null');
|
|
340
408
|
}
|
|
341
409
|
const reader = response.body.getReader();
|
|
342
410
|
const decoder = new TextDecoder();
|
|
@@ -365,6 +433,18 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
365
433
|
}
|
|
366
434
|
}
|
|
367
435
|
}
|
|
436
|
+
} catch (error) {
|
|
437
|
+
clearTimeout(timeout);
|
|
438
|
+
|
|
439
|
+
// Handle abort/timeout
|
|
440
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
441
|
+
throw new ClaudeTimeoutError(
|
|
442
|
+
'Request timed out',
|
|
443
|
+
this.config.timeout || 60000,
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
throw error;
|
|
368
448
|
} finally {
|
|
369
449
|
clearTimeout(timeout);
|
|
370
450
|
}
|
|
@@ -485,4 +565,192 @@ export class ClaudeAPIClient extends EventEmitter {
|
|
|
485
565
|
private delay(ms: number): Promise<void> {
|
|
486
566
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
487
567
|
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Start periodic health checks
|
|
571
|
+
*/
|
|
572
|
+
private startHealthCheck(): void {
|
|
573
|
+
this.performHealthCheck(); // Initial check
|
|
574
|
+
|
|
575
|
+
this.healthCheckTimer = setInterval(
|
|
576
|
+
() => this.performHealthCheck(),
|
|
577
|
+
this.config.healthCheckInterval || 300000,
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Perform a health check on the API
|
|
583
|
+
*/
|
|
584
|
+
async performHealthCheck(): Promise<HealthCheckResult> {
|
|
585
|
+
const startTime = Date.now();
|
|
586
|
+
|
|
587
|
+
try {
|
|
588
|
+
const controller = new AbortController();
|
|
589
|
+
const timeout = setTimeout(() => controller.abort(), 10000); // 10 second timeout
|
|
590
|
+
|
|
591
|
+
const response = await fetch(this.config.apiUrl || '', {
|
|
592
|
+
method: 'POST',
|
|
593
|
+
headers: {
|
|
594
|
+
'Content-Type': 'application/json',
|
|
595
|
+
'anthropic-version': '2023-06-01',
|
|
596
|
+
'x-api-key': this.config.apiKey,
|
|
597
|
+
},
|
|
598
|
+
body: JSON.stringify({
|
|
599
|
+
model: this.config.model,
|
|
600
|
+
messages: [{ role: 'user', content: 'Hi' }],
|
|
601
|
+
max_tokens: 1,
|
|
602
|
+
}),
|
|
603
|
+
signal: controller.signal,
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
clearTimeout(timeout);
|
|
607
|
+
|
|
608
|
+
const latency = Date.now() - startTime;
|
|
609
|
+
const healthy = response.ok || response.status === 429; // Rate limit is still "healthy"
|
|
610
|
+
|
|
611
|
+
this.lastHealthCheck = {
|
|
612
|
+
healthy,
|
|
613
|
+
latency,
|
|
614
|
+
error: healthy ? undefined : `Status: ${response.status}`,
|
|
615
|
+
timestamp: new Date(),
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
this.logger.debug('Claude API health check completed', this.lastHealthCheck);
|
|
619
|
+
this.emit('health_check', this.lastHealthCheck);
|
|
620
|
+
|
|
621
|
+
return this.lastHealthCheck;
|
|
622
|
+
} catch (error) {
|
|
623
|
+
const latency = Date.now() - startTime;
|
|
624
|
+
|
|
625
|
+
this.lastHealthCheck = {
|
|
626
|
+
healthy: false,
|
|
627
|
+
latency,
|
|
628
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
629
|
+
timestamp: new Date(),
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
this.logger.warn('Claude API health check failed', this.lastHealthCheck);
|
|
633
|
+
this.emit('health_check', this.lastHealthCheck);
|
|
634
|
+
|
|
635
|
+
return this.lastHealthCheck;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Get last health check result
|
|
641
|
+
*/
|
|
642
|
+
getHealthStatus(): HealthCheckResult | undefined {
|
|
643
|
+
return this.lastHealthCheck;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Create appropriate error based on status code
|
|
648
|
+
*/
|
|
649
|
+
private createAPIError(statusCode: number, errorData: any): ClaudeAPIError {
|
|
650
|
+
const message = errorData.error?.message || errorData.message || 'Unknown error';
|
|
651
|
+
|
|
652
|
+
switch (statusCode) {
|
|
653
|
+
case 400:
|
|
654
|
+
return new ClaudeValidationError(message, errorData);
|
|
655
|
+
case 401:
|
|
656
|
+
case 403:
|
|
657
|
+
return new ClaudeAuthenticationError(message, errorData);
|
|
658
|
+
case 429:
|
|
659
|
+
const retryAfter = errorData.error?.retry_after;
|
|
660
|
+
return new ClaudeRateLimitError(message, retryAfter, errorData);
|
|
661
|
+
case 500:
|
|
662
|
+
return new ClaudeInternalServerError(message, errorData);
|
|
663
|
+
case 503:
|
|
664
|
+
return new ClaudeServiceUnavailableError(message, errorData);
|
|
665
|
+
default:
|
|
666
|
+
return new ClaudeAPIError(message, statusCode, statusCode >= 500, errorData);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Transform generic errors to Claude API errors
|
|
672
|
+
*/
|
|
673
|
+
private transformError(error: unknown): ClaudeAPIError {
|
|
674
|
+
if (error instanceof ClaudeAPIError) {
|
|
675
|
+
return error;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (error instanceof Error) {
|
|
679
|
+
// Network errors
|
|
680
|
+
if (error.message.includes('fetch failed') || error.message.includes('ECONNREFUSED')) {
|
|
681
|
+
return new ClaudeNetworkError(error.message);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Timeout errors
|
|
685
|
+
if (error.name === 'AbortError' || error.message.includes('timeout')) {
|
|
686
|
+
return new ClaudeTimeoutError(error.message, this.config.timeout || 60000);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return new ClaudeAPIError(
|
|
691
|
+
error instanceof Error ? error.message : String(error),
|
|
692
|
+
undefined,
|
|
693
|
+
true, // Assume unknown errors are retryable
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Calculate retry delay with exponential backoff and jitter
|
|
699
|
+
*/
|
|
700
|
+
private calculateRetryDelay(attempt: number, error: ClaudeAPIError): number {
|
|
701
|
+
// If rate limit error with retry-after header, use that
|
|
702
|
+
if (error instanceof ClaudeRateLimitError && error.retryAfter) {
|
|
703
|
+
return error.retryAfter * 1000; // Convert to milliseconds
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const baseDelay = this.config.retryDelay || 1000;
|
|
707
|
+
const maxDelay = 30000; // 30 seconds max
|
|
708
|
+
|
|
709
|
+
// Exponential backoff: delay = baseDelay * (2 ^ attempt)
|
|
710
|
+
let delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
711
|
+
|
|
712
|
+
// Add jitter to prevent thundering herd
|
|
713
|
+
if (this.config.retryJitter) {
|
|
714
|
+
const jitter = Math.random() * 0.3 * delay; // Up to 30% jitter
|
|
715
|
+
delay = delay + jitter;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
return Math.floor(delay);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Handle errors with user-friendly messages and logging
|
|
723
|
+
*/
|
|
724
|
+
private handleError(error: ClaudeAPIError): void {
|
|
725
|
+
const errorInfo = getUserFriendlyError(error);
|
|
726
|
+
|
|
727
|
+
this.logger.error(`${errorInfo.title}: ${errorInfo.message}`, {
|
|
728
|
+
error: error.message,
|
|
729
|
+
code: error.code,
|
|
730
|
+
statusCode: error.statusCode,
|
|
731
|
+
retryable: error.retryable,
|
|
732
|
+
details: error.details,
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
// Log suggestions in debug mode
|
|
736
|
+
if (this.logger.level === 'debug' && errorInfo.suggestions.length > 0) {
|
|
737
|
+
this.logger.debug('Suggestions to resolve the issue:', errorInfo.suggestions);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
this.emit('error', {
|
|
741
|
+
error,
|
|
742
|
+
userFriendly: errorInfo,
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Clean up resources
|
|
748
|
+
*/
|
|
749
|
+
destroy(): void {
|
|
750
|
+
if (this.healthCheckTimer) {
|
|
751
|
+
clearInterval(this.healthCheckTimer);
|
|
752
|
+
this.healthCheckTimer = undefined;
|
|
753
|
+
}
|
|
754
|
+
this.removeAllListeners();
|
|
755
|
+
}
|
|
488
756
|
}
|
package/src/cli/help-text.js
CHANGED
|
@@ -458,7 +458,8 @@ SWARM-INIT OPTIONS:
|
|
|
458
458
|
|
|
459
459
|
AGENT-SPAWN OPTIONS:
|
|
460
460
|
--type <type> Agent type (default: general)
|
|
461
|
-
Options: coordinator, developer, researcher,
|
|
461
|
+
Options: coordinator, coder, developer, researcher, analyst, analyzer,
|
|
462
|
+
tester, architect, reviewer, optimizer, general
|
|
462
463
|
--name <name> Custom agent name (auto-generated if not provided)
|
|
463
464
|
--swarm-id <id> Target swarm for agent coordination
|
|
464
465
|
--capabilities <cap> Custom capabilities specification
|
|
@@ -56,69 +56,87 @@ async function swarmInitCommand(subArgs, flags) {
|
|
|
56
56
|
|
|
57
57
|
// Check if ruv-swarm is available
|
|
58
58
|
const isAvailable = await checkRuvSwarmAvailable();
|
|
59
|
+
|
|
60
|
+
if (isAvailable) {
|
|
61
|
+
try {
|
|
62
|
+
console.log(`\nš Initializing real swarm with ruv-swarm...`);
|
|
63
|
+
|
|
64
|
+
// Use real ruv-swarm initialization
|
|
65
|
+
const swarmResult = await callRuvSwarmMCP('swarm_init', {
|
|
66
|
+
swarmId: swarmId,
|
|
67
|
+
topology: topology,
|
|
68
|
+
maxAgents: maxAgents,
|
|
69
|
+
strategy: strategy,
|
|
70
|
+
timestamp: Date.now(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (swarmResult.success) {
|
|
74
|
+
printSuccess(`ā
Swarm coordination initialized successfully`);
|
|
75
|
+
|
|
76
|
+
console.log(`\nšÆ COORDINATION SETUP COMPLETE:`);
|
|
77
|
+
console.log(` š Swarm: ${swarmId}`);
|
|
78
|
+
console.log(` šļø Topology: ${topology}`);
|
|
79
|
+
console.log(` š Capacity: ${maxAgents} agents`);
|
|
80
|
+
console.log(` š¾ Memory: ${swarmResult.memoryStatus || 'Active'}`);
|
|
81
|
+
console.log(` š Channels: ${swarmResult.communicationChannels || 'Established'}`);
|
|
82
|
+
console.log(` š Performance: ${swarmResult.expectedPerformance || 'Optimized'}`);
|
|
83
|
+
} else {
|
|
84
|
+
printError(`Swarm initialization failed: ${swarmResult.error || 'Unknown error'}`);
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
printError(`Swarm initialization failed: ${err.message}`);
|
|
88
|
+
console.log('Falling back to local coordination...');
|
|
89
|
+
isAvailable = false; // Trigger fallback
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
59
93
|
if (!isAvailable) {
|
|
60
|
-
|
|
61
|
-
|
|
94
|
+
// Fallback: Initialize coordination without ruv-swarm
|
|
95
|
+
console.log(`\nš Initializing local swarm coordination...`);
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
97
|
+
|
|
98
|
+
printSuccess(`ā
Local swarm coordination initialized successfully`);
|
|
99
|
+
|
|
100
|
+
console.log(`\nšÆ COORDINATION SETUP COMPLETE:`);
|
|
101
|
+
console.log(` š Swarm: ${swarmId}`);
|
|
102
|
+
console.log(` šļø Topology: ${topology}`);
|
|
103
|
+
console.log(` š Capacity: ${maxAgents} agents`);
|
|
104
|
+
console.log(` š¾ Memory: Local (in-memory)`);
|
|
105
|
+
console.log(` š Channels: Local coordination`);
|
|
106
|
+
console.log(` š Performance: Standard`);
|
|
107
|
+
console.log(` ā ļø Note: Using local coordination (ruv-swarm not available)`);
|
|
62
108
|
}
|
|
63
109
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
strategy: strategy,
|
|
73
|
-
timestamp: Date.now(),
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (swarmResult.success) {
|
|
77
|
-
printSuccess(`ā
Swarm coordination initialized successfully`);
|
|
78
|
-
|
|
79
|
-
console.log(`\nšÆ COORDINATION SETUP COMPLETE:`);
|
|
80
|
-
console.log(` š Swarm: ${swarmId}`);
|
|
81
|
-
console.log(` šļø Topology: ${topology}`);
|
|
82
|
-
console.log(` š Capacity: ${maxAgents} agents`);
|
|
83
|
-
console.log(` š¾ Memory: ${swarmResult.memoryStatus || 'Active'}`);
|
|
84
|
-
console.log(` š Channels: ${swarmResult.communicationChannels || 'Established'}`);
|
|
85
|
-
console.log(` š Performance: ${swarmResult.expectedPerformance || 'Optimized'}`);
|
|
86
|
-
|
|
87
|
-
console.log(`\nš NEXT STEPS:`);
|
|
88
|
-
console.log(
|
|
89
|
-
` 1. Spawn agents: claude-flow coordination agent-spawn --type <type> --swarm-id ${swarmId}`,
|
|
90
|
-
);
|
|
91
|
-
console.log(
|
|
92
|
-
` 2. Orchestrate tasks: claude-flow coordination task-orchestrate --task "<description>" --swarm-id ${swarmId}`,
|
|
93
|
-
);
|
|
94
|
-
console.log(` 3. Monitor swarm: claude-flow monitoring swarm-monitor --swarm-id ${swarmId}`);
|
|
95
|
-
} else {
|
|
96
|
-
printError(`Swarm initialization failed: ${swarmResult.error || 'Unknown error'}`);
|
|
97
|
-
}
|
|
98
|
-
} catch (err) {
|
|
99
|
-
printError(`Swarm initialization failed: ${err.message}`);
|
|
100
|
-
console.log('Check ruv-swarm installation and try again.');
|
|
101
|
-
}
|
|
110
|
+
console.log(`\nš NEXT STEPS:`);
|
|
111
|
+
console.log(
|
|
112
|
+
` 1. Spawn agents: claude-flow coordination agent-spawn --type <type> --swarm-id ${swarmId}`,
|
|
113
|
+
);
|
|
114
|
+
console.log(
|
|
115
|
+
` 2. Orchestrate tasks: claude-flow coordination task-orchestrate --task "<description>" --swarm-id ${swarmId}`,
|
|
116
|
+
);
|
|
117
|
+
console.log(` 3. Monitor swarm: claude-flow monitoring swarm-monitor --swarm-id ${swarmId}`);
|
|
102
118
|
}
|
|
103
119
|
|
|
104
120
|
async function agentSpawnCommand(subArgs, flags) {
|
|
105
121
|
const options = flags;
|
|
106
|
-
|
|
107
|
-
const agentName = options.name || `${agentType}-${generateId('agent')}`;
|
|
122
|
+
let agentType = options.type || subArgs[1] || 'general';
|
|
108
123
|
const swarmId = options['swarm-id'] || options.swarmId;
|
|
109
124
|
const capabilities = options.capabilities || null;
|
|
110
125
|
|
|
111
|
-
console.log(`š¤ Spawning coordinated agent...`);
|
|
112
|
-
console.log(`š·ļø Agent type: ${agentType}`);
|
|
113
|
-
console.log(`š Agent name: ${agentName}`);
|
|
114
|
-
if (swarmId) console.log(`š Target swarm: ${swarmId}`);
|
|
115
|
-
|
|
116
126
|
// Validate agent type
|
|
117
|
-
const validTypes = ['coordinator', 'coder', 'researcher', 'analyst', 'tester', 'general'];
|
|
127
|
+
const validTypes = ['coordinator', 'coder', 'developer', 'researcher', 'analyst', 'analyzer', 'tester', 'architect', 'reviewer', 'optimizer', 'general'];
|
|
118
128
|
if (!validTypes.includes(agentType)) {
|
|
119
129
|
printWarning(`ā ļø Unknown agent type '${agentType}'. Using 'general' instead.`);
|
|
130
|
+
agentType = 'general'; // Actually change the type to general
|
|
120
131
|
}
|
|
121
132
|
|
|
133
|
+
const agentName = options.name || `${agentType}-${generateId('agent')}`;
|
|
134
|
+
|
|
135
|
+
console.log(`š¤ Spawning coordinated agent...`);
|
|
136
|
+
console.log(`š·ļø Agent type: ${agentType}`);
|
|
137
|
+
console.log(`š Agent name: ${agentName}`);
|
|
138
|
+
if (swarmId) console.log(`š Target swarm: ${swarmId}`);
|
|
139
|
+
|
|
122
140
|
// Simulate agent spawning process
|
|
123
141
|
console.log(`\nš Initializing agent coordination protocols...`);
|
|
124
142
|
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
@@ -207,10 +225,15 @@ async function taskOrchestrateCommand(subArgs, flags) {
|
|
|
207
225
|
function getAgentCapabilities(type) {
|
|
208
226
|
const capabilities = {
|
|
209
227
|
coordinator: 'Task orchestration, agent management, workflow coordination',
|
|
228
|
+
coder: 'Code implementation, debugging, technical development',
|
|
210
229
|
developer: 'Code implementation, debugging, technical development',
|
|
211
230
|
researcher: 'Information gathering, analysis, documentation',
|
|
231
|
+
analyst: 'Data analysis, performance monitoring, metrics',
|
|
212
232
|
analyzer: 'Data analysis, performance monitoring, metrics',
|
|
213
233
|
tester: 'Quality assurance, test automation, validation',
|
|
234
|
+
architect: 'System design, architecture planning, technical strategy',
|
|
235
|
+
reviewer: 'Code review, quality assessment, best practices',
|
|
236
|
+
optimizer: 'Performance optimization, efficiency improvement, bottleneck analysis',
|
|
214
237
|
general: 'Multi-purpose coordination and development',
|
|
215
238
|
};
|
|
216
239
|
return capabilities[type] || capabilities.general;
|
|
@@ -236,7 +259,8 @@ SWARM-INIT OPTIONS:
|
|
|
236
259
|
|
|
237
260
|
AGENT-SPAWN OPTIONS:
|
|
238
261
|
--type <type> Agent type (default: general)
|
|
239
|
-
Options: coordinator, developer, researcher,
|
|
262
|
+
Options: coordinator, coder, developer, researcher, analyst, analyzer,
|
|
263
|
+
tester, architect, reviewer, optimizer, general
|
|
240
264
|
--name <name> Custom agent name (auto-generated if not provided)
|
|
241
265
|
--swarm-id <id> Target swarm for agent coordination
|
|
242
266
|
--capabilities <cap> Custom capabilities specification
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
import { HiveMindSessionManager } from './session-manager.js';
|
|
7
7
|
|
|
8
8
|
export class AutoSaveMiddleware {
|
|
9
|
-
constructor(sessionId, saveInterval = 30000) {
|
|
9
|
+
constructor(sessionId, sessionManager, saveInterval = 30000) {
|
|
10
10
|
this.sessionId = sessionId;
|
|
11
11
|
this.saveInterval = saveInterval;
|
|
12
|
-
this.sessionManager =
|
|
12
|
+
this.sessionManager = sessionManager; // Use provided session manager
|
|
13
13
|
this.saveTimer = null;
|
|
14
14
|
this.pendingChanges = [];
|
|
15
15
|
this.isActive = false;
|
|
@@ -178,7 +178,7 @@ export class AutoSaveMiddleware {
|
|
|
178
178
|
|
|
179
179
|
// Update session progress
|
|
180
180
|
if (completionPercentage > 0) {
|
|
181
|
-
this.sessionManager.updateSessionProgress(this.sessionId, completionPercentage);
|
|
181
|
+
await this.sessionManager.updateSessionProgress(this.sessionId, completionPercentage);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
// Log all changes as session events
|
|
@@ -278,7 +278,7 @@ export class AutoSaveMiddleware {
|
|
|
278
278
|
this.childProcesses.clear();
|
|
279
279
|
|
|
280
280
|
// Stop the session if it's still active
|
|
281
|
-
const session = this.sessionManager.getSession(this.sessionId);
|
|
281
|
+
const session = await this.sessionManager.getSession(this.sessionId);
|
|
282
282
|
if (session && (session.status === 'active' || session.status === 'paused')) {
|
|
283
283
|
await this.sessionManager.stopSession(this.sessionId);
|
|
284
284
|
}
|
|
@@ -296,9 +296,9 @@ export class AutoSaveMiddleware {
|
|
|
296
296
|
/**
|
|
297
297
|
* Create auto-save middleware for a session
|
|
298
298
|
*/
|
|
299
|
-
export function createAutoSaveMiddleware(sessionId, options = {}) {
|
|
299
|
+
export function createAutoSaveMiddleware(sessionId, sessionManager, options = {}) {
|
|
300
300
|
const saveInterval = options.saveInterval || 30000; // Default 30 seconds
|
|
301
|
-
const middleware = new AutoSaveMiddleware(sessionId, saveInterval);
|
|
301
|
+
const middleware = new AutoSaveMiddleware(sessionId, sessionManager, saveInterval);
|
|
302
302
|
|
|
303
303
|
if (options.autoStart !== false) {
|
|
304
304
|
middleware.start();
|