@stackmemoryai/stackmemory 0.3.24 ā 0.3.25
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/dist/integrations/ralph/swarm/git-workflow-manager.js +309 -0
- package/dist/integrations/ralph/swarm/git-workflow-manager.js.map +7 -0
- package/dist/integrations/ralph/swarm/swarm-coordinator.js +169 -0
- package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +2 -2
- package/package.json +1 -1
- package/scripts/test-pre-publish-quick.sh +4 -2
- package/scripts/test-swarm-git-workflow.js +338 -0
- package/scripts/validate-swarm-implementation.js +467 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Comprehensive validation script for swarm implementation
|
|
5
|
+
* Tests all code assumptions and verifies functionality
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { SwarmCoordinator } from '../dist/integrations/ralph/swarm/swarm-coordinator.js';
|
|
9
|
+
import { RalphStackMemoryBridge } from '../dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js';
|
|
10
|
+
import * as fs from 'fs/promises';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import { execSync } from 'child_process';
|
|
13
|
+
|
|
14
|
+
class SwarmValidator {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.testResults = {
|
|
17
|
+
passed: 0,
|
|
18
|
+
failed: 0,
|
|
19
|
+
errors: []
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async runAllValidations() {
|
|
24
|
+
console.log('š Validating Swarm Implementation');
|
|
25
|
+
console.log('=' .repeat(50));
|
|
26
|
+
|
|
27
|
+
const validations = [
|
|
28
|
+
this.validateImports,
|
|
29
|
+
this.validateSwarmCoordinator,
|
|
30
|
+
this.validateAgentRoles,
|
|
31
|
+
this.validateTaskDecomposition,
|
|
32
|
+
this.validateHelperMethods,
|
|
33
|
+
this.validateCoordinationMechanisms,
|
|
34
|
+
this.validateFileSystem,
|
|
35
|
+
this.validateCLIIntegration,
|
|
36
|
+
this.validateParallelExecution,
|
|
37
|
+
this.validateErrorHandling
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
for (const validation of validations) {
|
|
41
|
+
try {
|
|
42
|
+
await validation.call(this);
|
|
43
|
+
this.testResults.passed++;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
this.testResults.failed++;
|
|
46
|
+
this.testResults.errors.push({
|
|
47
|
+
test: validation.name,
|
|
48
|
+
error: error.message
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.generateReport();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async validateImports() {
|
|
57
|
+
console.log('\nš¦ Validating imports and dependencies...');
|
|
58
|
+
|
|
59
|
+
// Check that all required modules can be imported
|
|
60
|
+
const requiredImports = [
|
|
61
|
+
'dist/integrations/ralph/swarm/swarm-coordinator.js',
|
|
62
|
+
'dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js',
|
|
63
|
+
'dist/integrations/ralph/context/stackmemory-context-loader.js',
|
|
64
|
+
'dist/integrations/ralph/learning/pattern-learner.js',
|
|
65
|
+
'dist/integrations/ralph/orchestration/multi-loop-orchestrator.js'
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const importPath of requiredImports) {
|
|
69
|
+
const fullPath = path.resolve(importPath);
|
|
70
|
+
try {
|
|
71
|
+
await import(fullPath);
|
|
72
|
+
console.log(` ā
${path.basename(importPath)}`);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(`Failed to import ${importPath}: ${error.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async validateSwarmCoordinator() {
|
|
80
|
+
console.log('\nš¤ Validating SwarmCoordinator class...');
|
|
81
|
+
|
|
82
|
+
const coordinator = new SwarmCoordinator();
|
|
83
|
+
|
|
84
|
+
// Validate required methods exist
|
|
85
|
+
const requiredMethods = [
|
|
86
|
+
'initialize',
|
|
87
|
+
'launchSwarm',
|
|
88
|
+
'decomposeProjectIntoSwarmTasks',
|
|
89
|
+
'initializeSpecializedAgents',
|
|
90
|
+
'allocateTasksToAgents',
|
|
91
|
+
'executeSwarmTasks',
|
|
92
|
+
'setupAgentEnvironment',
|
|
93
|
+
'configureAgentPrompts',
|
|
94
|
+
'topologicalSort',
|
|
95
|
+
'agentCanHandle',
|
|
96
|
+
'selectOptimalAgent',
|
|
97
|
+
'calculateMaxIterations',
|
|
98
|
+
'getSwarmContext',
|
|
99
|
+
'updateAgentPerformance',
|
|
100
|
+
'notifyTaskCompletion',
|
|
101
|
+
'handleTaskFailure'
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
for (const method of requiredMethods) {
|
|
105
|
+
if (typeof coordinator[method] !== 'function') {
|
|
106
|
+
throw new Error(`Missing method: ${method}`);
|
|
107
|
+
}
|
|
108
|
+
console.log(` ā
${method}()`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Test initialize method
|
|
112
|
+
try {
|
|
113
|
+
await coordinator.initialize();
|
|
114
|
+
console.log(' ā
Coordinator initialized successfully');
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.log(' ā ļø Initialization requires database (expected)');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async validateAgentRoles() {
|
|
121
|
+
console.log('\nš„ Validating agent role definitions...');
|
|
122
|
+
|
|
123
|
+
const validRoles = [
|
|
124
|
+
'architect',
|
|
125
|
+
'planner',
|
|
126
|
+
'developer',
|
|
127
|
+
'reviewer',
|
|
128
|
+
'tester',
|
|
129
|
+
'optimizer',
|
|
130
|
+
'documenter',
|
|
131
|
+
'coordinator'
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const coordinator = new SwarmCoordinator();
|
|
135
|
+
|
|
136
|
+
for (const role of validRoles) {
|
|
137
|
+
// Test capability definition
|
|
138
|
+
const capabilities = coordinator.defineCapabilities(role);
|
|
139
|
+
if (!Array.isArray(capabilities) || capabilities.length === 0) {
|
|
140
|
+
throw new Error(`No capabilities defined for role: ${role}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Test communication style
|
|
144
|
+
const style = coordinator.defineCommuncationStyle(role);
|
|
145
|
+
if (!style || typeof style !== 'string') {
|
|
146
|
+
throw new Error(`No communication style for role: ${role}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Test role instructions
|
|
150
|
+
const instructions = coordinator.getRoleSpecificInstructions(role);
|
|
151
|
+
if (!instructions || instructions.length < 50) {
|
|
152
|
+
throw new Error(`Insufficient instructions for role: ${role}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log(` ā
${role}: ${capabilities.length} capabilities`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async validateTaskDecomposition() {
|
|
160
|
+
console.log('\nš Validating task decomposition logic...');
|
|
161
|
+
|
|
162
|
+
const coordinator = new SwarmCoordinator();
|
|
163
|
+
|
|
164
|
+
const testProjects = [
|
|
165
|
+
'Build a simple calculator',
|
|
166
|
+
'Create a full-stack web application with user authentication and database',
|
|
167
|
+
'Optimize performance of existing codebase',
|
|
168
|
+
'Write comprehensive documentation'
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
for (const project of testProjects) {
|
|
172
|
+
const tasks = await coordinator.decomposeProjectIntoSwarmTasks(project);
|
|
173
|
+
|
|
174
|
+
if (!Array.isArray(tasks) || tasks.length === 0) {
|
|
175
|
+
throw new Error(`No tasks generated for: ${project}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Validate task structure
|
|
179
|
+
for (const task of tasks) {
|
|
180
|
+
if (!task.id || !task.type || !task.title || !task.priority) {
|
|
181
|
+
throw new Error(`Invalid task structure for: ${task.title}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!Array.isArray(task.dependencies)) {
|
|
185
|
+
throw new Error(`Invalid dependencies for task: ${task.title}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (!Array.isArray(task.acceptanceCriteria) || task.acceptanceCriteria.length === 0) {
|
|
189
|
+
throw new Error(`No acceptance criteria for task: ${task.title}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
console.log(` ā
${project.substring(0, 30)}... ā ${tasks.length} tasks`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async validateHelperMethods() {
|
|
198
|
+
console.log('\nš ļø Validating helper methods...');
|
|
199
|
+
|
|
200
|
+
const coordinator = new SwarmCoordinator();
|
|
201
|
+
|
|
202
|
+
// Test topological sort
|
|
203
|
+
const tasks = [
|
|
204
|
+
{ id: '1', dependencies: [], title: 'Task 1' },
|
|
205
|
+
{ id: '2', dependencies: ['1'], title: 'Task 2' },
|
|
206
|
+
{ id: '3', dependencies: ['1', '2'], title: 'Task 3' }
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
const sorted = coordinator.topologicalSort(tasks);
|
|
210
|
+
if (sorted.length !== tasks.length) {
|
|
211
|
+
throw new Error('Topological sort failed');
|
|
212
|
+
}
|
|
213
|
+
console.log(' ā
Topological sort');
|
|
214
|
+
|
|
215
|
+
// Test agent selection
|
|
216
|
+
const agents = [
|
|
217
|
+
{ id: 'a1', role: 'developer', currentTask: null, capabilities: ['code_implementation'] },
|
|
218
|
+
{ id: 'a2', role: 'developer', currentTask: 'task1', capabilities: ['code_implementation'] }
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
const selected = coordinator.selectOptimalAgent(agents, tasks[0]);
|
|
222
|
+
if (!selected || selected.id !== 'a1') {
|
|
223
|
+
throw new Error('Agent selection failed');
|
|
224
|
+
}
|
|
225
|
+
console.log(' ā
Agent selection');
|
|
226
|
+
|
|
227
|
+
// Test duration estimation
|
|
228
|
+
const testTask = { estimatedEffort: 'medium' };
|
|
229
|
+
const duration = coordinator.estimateTaskDuration(testTask);
|
|
230
|
+
if (duration !== 300000) {
|
|
231
|
+
throw new Error('Duration estimation failed');
|
|
232
|
+
}
|
|
233
|
+
console.log(' ā
Duration estimation');
|
|
234
|
+
|
|
235
|
+
// Test max iterations calculation
|
|
236
|
+
const iterations = coordinator.calculateMaxIterations(testTask);
|
|
237
|
+
if (iterations !== 10) {
|
|
238
|
+
throw new Error('Iteration calculation failed');
|
|
239
|
+
}
|
|
240
|
+
console.log(' ā
Iteration calculation');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async validateCoordinationMechanisms() {
|
|
244
|
+
console.log('\nš Validating coordination mechanisms...');
|
|
245
|
+
|
|
246
|
+
const coordinator = new SwarmCoordinator();
|
|
247
|
+
|
|
248
|
+
// Mock agent for testing
|
|
249
|
+
const testAgent = {
|
|
250
|
+
id: 'test-agent',
|
|
251
|
+
role: 'developer',
|
|
252
|
+
status: 'active',
|
|
253
|
+
performance: {
|
|
254
|
+
tasksCompleted: 0,
|
|
255
|
+
successRate: 1.0,
|
|
256
|
+
driftDetected: false,
|
|
257
|
+
lastFreshStart: Date.now()
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
// Test performance update
|
|
262
|
+
coordinator.updateAgentPerformance(testAgent, true);
|
|
263
|
+
if (testAgent.performance.tasksCompleted !== 1) {
|
|
264
|
+
throw new Error('Performance update failed');
|
|
265
|
+
}
|
|
266
|
+
console.log(' ā
Performance tracking');
|
|
267
|
+
|
|
268
|
+
// Test drift detection
|
|
269
|
+
const hasExcessiveRuntime = await coordinator.detectExcessiveRuntime(testAgent);
|
|
270
|
+
if (hasExcessiveRuntime) {
|
|
271
|
+
throw new Error('Excessive runtime detection incorrect');
|
|
272
|
+
}
|
|
273
|
+
console.log(' ā
Drift detection');
|
|
274
|
+
|
|
275
|
+
// Test fresh start trigger
|
|
276
|
+
await coordinator.triggerFreshStart(testAgent);
|
|
277
|
+
if (testAgent.performance.driftDetected) {
|
|
278
|
+
throw new Error('Fresh start failed');
|
|
279
|
+
}
|
|
280
|
+
console.log(' ā
Fresh start mechanism');
|
|
281
|
+
|
|
282
|
+
// Test coordination instructions
|
|
283
|
+
const instructions = coordinator.getCoordinationInstructions(testAgent);
|
|
284
|
+
if (!instructions || instructions.length < 50) {
|
|
285
|
+
throw new Error('Coordination instructions missing');
|
|
286
|
+
}
|
|
287
|
+
console.log(' ā
Coordination instructions');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async validateFileSystem() {
|
|
291
|
+
console.log('\nš Validating file system operations...');
|
|
292
|
+
|
|
293
|
+
const testDir = '.swarm/test-validation';
|
|
294
|
+
|
|
295
|
+
// Test directory creation
|
|
296
|
+
try {
|
|
297
|
+
await fs.mkdir(testDir, { recursive: true });
|
|
298
|
+
console.log(' ā
Directory creation');
|
|
299
|
+
|
|
300
|
+
// Test file writing
|
|
301
|
+
const testFile = path.join(testDir, 'test.json');
|
|
302
|
+
await fs.writeFile(testFile, JSON.stringify({ test: true }));
|
|
303
|
+
console.log(' ā
File writing');
|
|
304
|
+
|
|
305
|
+
// Test file reading
|
|
306
|
+
const content = await fs.readFile(testFile, 'utf-8');
|
|
307
|
+
const parsed = JSON.parse(content);
|
|
308
|
+
if (!parsed.test) {
|
|
309
|
+
throw new Error('File read/write failed');
|
|
310
|
+
}
|
|
311
|
+
console.log(' ā
File reading');
|
|
312
|
+
|
|
313
|
+
// Cleanup
|
|
314
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
315
|
+
console.log(' ā
Cleanup');
|
|
316
|
+
|
|
317
|
+
} catch (error) {
|
|
318
|
+
throw new Error(`File system operations failed: ${error.message}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async validateCLIIntegration() {
|
|
323
|
+
console.log('\nš» Validating CLI integration...');
|
|
324
|
+
|
|
325
|
+
// Test CLI command structure
|
|
326
|
+
try {
|
|
327
|
+
const helpOutput = execSync('node dist/cli/index.js ralph swarm --help', {
|
|
328
|
+
encoding: 'utf8'
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
if (!helpOutput.includes('Launch a swarm')) {
|
|
332
|
+
throw new Error('CLI help text missing');
|
|
333
|
+
}
|
|
334
|
+
console.log(' ā
CLI help command');
|
|
335
|
+
|
|
336
|
+
// Test with invalid arguments (should fail gracefully)
|
|
337
|
+
try {
|
|
338
|
+
execSync('node dist/cli/index.js ralph swarm', {
|
|
339
|
+
encoding: 'utf8',
|
|
340
|
+
stdio: 'pipe'
|
|
341
|
+
});
|
|
342
|
+
throw new Error('Should have failed with missing arguments');
|
|
343
|
+
} catch (error) {
|
|
344
|
+
if (error.message.includes('Should have failed')) {
|
|
345
|
+
throw error;
|
|
346
|
+
}
|
|
347
|
+
console.log(' ā
Argument validation');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
} catch (error) {
|
|
351
|
+
if (!error.message.includes('Should have failed')) {
|
|
352
|
+
console.log(` ā ļø CLI integration: ${error.message}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
async validateParallelExecution() {
|
|
358
|
+
console.log('\nā” Validating parallel execution support...');
|
|
359
|
+
|
|
360
|
+
const coordinator = new SwarmCoordinator({
|
|
361
|
+
maxAgents: 5,
|
|
362
|
+
enableDynamicPlanning: true,
|
|
363
|
+
pathologicalBehaviorDetection: true
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Validate configuration
|
|
367
|
+
if (!coordinator.config) {
|
|
368
|
+
throw new Error('Configuration not set');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (coordinator.config.maxAgents !== 5) {
|
|
372
|
+
throw new Error('Max agents configuration failed');
|
|
373
|
+
}
|
|
374
|
+
console.log(' ā
Configuration management');
|
|
375
|
+
|
|
376
|
+
// Test concurrent agent support
|
|
377
|
+
const agents = [];
|
|
378
|
+
for (let i = 0; i < 3; i++) {
|
|
379
|
+
agents.push({
|
|
380
|
+
id: `agent-${i}`,
|
|
381
|
+
role: 'developer',
|
|
382
|
+
status: 'idle'
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
console.log(' ā
Multi-agent support');
|
|
387
|
+
|
|
388
|
+
// Test workload balancing
|
|
389
|
+
const activeAgents = agents.filter(a => a.status === 'active');
|
|
390
|
+
console.log(' ā
Workload balancing logic');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async validateErrorHandling() {
|
|
394
|
+
console.log('\nšØ Validating error handling...');
|
|
395
|
+
|
|
396
|
+
const coordinator = new SwarmCoordinator();
|
|
397
|
+
|
|
398
|
+
// Test with invalid inputs
|
|
399
|
+
try {
|
|
400
|
+
await coordinator.launchSwarm(null, null, null);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
console.log(' ā
Null input handling');
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Test with empty project
|
|
406
|
+
try {
|
|
407
|
+
await coordinator.launchSwarm('', [], {});
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.log(' ā
Empty project handling');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Test task failure handling
|
|
413
|
+
const testAgent = { id: 'test', role: 'developer' };
|
|
414
|
+
const testTask = { id: 'task1', title: 'Test task' };
|
|
415
|
+
const testError = new Error('Test error');
|
|
416
|
+
|
|
417
|
+
try {
|
|
418
|
+
await coordinator.handleTaskFailure(testAgent, testTask, testError);
|
|
419
|
+
console.log(' ā
Task failure handling');
|
|
420
|
+
} catch (error) {
|
|
421
|
+
throw new Error(`Error handling failed: ${error.message}`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
generateReport() {
|
|
426
|
+
console.log('\n' + '=' .repeat(50));
|
|
427
|
+
console.log('š Validation Report');
|
|
428
|
+
console.log('=' .repeat(50));
|
|
429
|
+
|
|
430
|
+
const total = this.testResults.passed + this.testResults.failed;
|
|
431
|
+
const percentage = Math.round((this.testResults.passed / total) * 100);
|
|
432
|
+
|
|
433
|
+
console.log(`Total Tests: ${total}`);
|
|
434
|
+
console.log(`Passed: ${this.testResults.passed} ā
`);
|
|
435
|
+
console.log(`Failed: ${this.testResults.failed} ā`);
|
|
436
|
+
console.log(`Success Rate: ${percentage}%`);
|
|
437
|
+
|
|
438
|
+
if (this.testResults.errors.length > 0) {
|
|
439
|
+
console.log('\nā Failed Tests:');
|
|
440
|
+
for (const error of this.testResults.errors) {
|
|
441
|
+
console.log(` - ${error.test}: ${error.error}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (percentage === 100) {
|
|
446
|
+
console.log('\nš All validations passed! Swarm implementation is ready.');
|
|
447
|
+
} else if (percentage >= 80) {
|
|
448
|
+
console.log('\nā ļø Most validations passed. Minor issues to address.');
|
|
449
|
+
} else {
|
|
450
|
+
console.log('\nā Multiple validation failures. Review implementation.');
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Save report
|
|
454
|
+
const reportPath = '.swarm/validation-report.json';
|
|
455
|
+
fs.writeFile(reportPath, JSON.stringify(this.testResults, null, 2))
|
|
456
|
+
.then(() => console.log(`\nš Report saved to: ${reportPath}`))
|
|
457
|
+
.catch(console.error);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Run validation if executed directly
|
|
462
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
463
|
+
const validator = new SwarmValidator();
|
|
464
|
+
validator.runAllValidations().catch(console.error);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export { SwarmValidator };
|