@sparkleideas/ruv-swarm 1.0.18-patch.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1565 -0
- package/bin/ruv-swarm-clean.js +1872 -0
- package/bin/ruv-swarm-memory.js +119 -0
- package/bin/ruv-swarm-secure-heartbeat.js +1549 -0
- package/bin/ruv-swarm-secure.js +1689 -0
- package/package.json +221 -0
- package/src/agent.ts +342 -0
- package/src/benchmark.js +267 -0
- package/src/claude-flow-enhanced.js +839 -0
- package/src/claude-integration/advanced-commands.js +561 -0
- package/src/claude-integration/core.js +112 -0
- package/src/claude-integration/docs.js +1548 -0
- package/src/claude-integration/env-template.js +39 -0
- package/src/claude-integration/index.js +209 -0
- package/src/claude-integration/remote.js +408 -0
- package/src/cli-diagnostics.js +364 -0
- package/src/cognitive-pattern-evolution.js +1317 -0
- package/src/daa-cognition.js +977 -0
- package/src/daa-service.d.ts +298 -0
- package/src/daa-service.js +1116 -0
- package/src/diagnostics.js +533 -0
- package/src/errors.js +528 -0
- package/src/github-coordinator/README.md +193 -0
- package/src/github-coordinator/claude-hooks.js +162 -0
- package/src/github-coordinator/gh-cli-coordinator.js +260 -0
- package/src/hooks/cli.js +82 -0
- package/src/hooks/index.js +1900 -0
- package/src/index-enhanced.d.ts +371 -0
- package/src/index-enhanced.js +734 -0
- package/src/index.d.ts +287 -0
- package/src/index.js +405 -0
- package/src/index.ts +457 -0
- package/src/logger.js +182 -0
- package/src/logging-config.js +179 -0
- package/src/mcp-daa-tools.js +735 -0
- package/src/mcp-tools-benchmarks.js +328 -0
- package/src/mcp-tools-enhanced.js +2863 -0
- package/src/memory-config.js +42 -0
- package/src/meta-learning-framework.js +1359 -0
- package/src/neural-agent.js +830 -0
- package/src/neural-coordination-protocol.js +1363 -0
- package/src/neural-models/README.md +118 -0
- package/src/neural-models/autoencoder.js +543 -0
- package/src/neural-models/base.js +269 -0
- package/src/neural-models/cnn.js +497 -0
- package/src/neural-models/gnn.js +447 -0
- package/src/neural-models/gru.js +536 -0
- package/src/neural-models/index.js +273 -0
- package/src/neural-models/lstm.js +551 -0
- package/src/neural-models/neural-presets-complete.js +1306 -0
- package/src/neural-models/presets/graph.js +392 -0
- package/src/neural-models/presets/index.js +279 -0
- package/src/neural-models/presets/nlp.js +328 -0
- package/src/neural-models/presets/timeseries.js +368 -0
- package/src/neural-models/presets/vision.js +387 -0
- package/src/neural-models/resnet.js +534 -0
- package/src/neural-models/transformer.js +515 -0
- package/src/neural-models/vae.js +489 -0
- package/src/neural-network-manager.js +1938 -0
- package/src/neural-network.ts +296 -0
- package/src/neural.js +574 -0
- package/src/performance-benchmarks.js +898 -0
- package/src/performance.js +458 -0
- package/src/persistence-pooled.js +695 -0
- package/src/persistence.js +480 -0
- package/src/schemas.js +864 -0
- package/src/security.js +218 -0
- package/src/singleton-container.js +183 -0
- package/src/sqlite-pool.js +587 -0
- package/src/sqlite-worker.js +141 -0
- package/src/types.ts +164 -0
- package/src/utils.ts +286 -0
- package/src/wasm-loader.js +601 -0
- package/src/wasm-loader2.js +404 -0
- package/src/wasm-memory-optimizer.js +783 -0
- package/src/wasm-types.d.ts +63 -0
- package/wasm/README.md +347 -0
- package/wasm/neuro-divergent.wasm +0 -0
- package/wasm/package.json +18 -0
- package/wasm/ruv-fann.wasm +0 -0
- package/wasm/ruv_swarm_simd.wasm +0 -0
- package/wasm/ruv_swarm_wasm.d.ts +391 -0
- package/wasm/ruv_swarm_wasm.js +2164 -0
- package/wasm/ruv_swarm_wasm_bg.wasm +0 -0
- package/wasm/ruv_swarm_wasm_bg.wasm.d.ts +123 -0
- package/wasm/wasm-bindings-loader.mjs +435 -0
- package/wasm/wasm-updates.md +684 -0
|
@@ -0,0 +1,1900 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Hooks Implementation for @sparkleideas/ruv-swarm
|
|
3
|
+
* Provides automated coordination, formatting, and learning capabilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { promises as fs } from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { execSync } from 'child_process';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { SwarmPersistence } from '../persistence.js';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
|
|
15
|
+
class RuvSwarmHooks {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.sessionData = {
|
|
18
|
+
startTime: Date.now(),
|
|
19
|
+
operations: [],
|
|
20
|
+
agents: new Map(),
|
|
21
|
+
learnings: [],
|
|
22
|
+
metrics: {
|
|
23
|
+
tokensSaved: 0,
|
|
24
|
+
tasksCompleted: 0,
|
|
25
|
+
patternsImproved: 0,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Initialize persistence layer for cross-agent memory
|
|
30
|
+
this.persistence = null;
|
|
31
|
+
this.initializePersistence();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Initialize persistence layer with error handling
|
|
36
|
+
*/
|
|
37
|
+
async initializePersistence() {
|
|
38
|
+
try {
|
|
39
|
+
this.persistence = new SwarmPersistence();
|
|
40
|
+
console.log('🗄️ Hook persistence layer initialized');
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.warn('⚠️ Failed to initialize persistence layer:', error.message);
|
|
43
|
+
console.warn('⚠️ Operating in memory-only mode');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Main hook handler - routes to specific hook implementations
|
|
49
|
+
*/
|
|
50
|
+
async handleHook(hookType, args) {
|
|
51
|
+
try {
|
|
52
|
+
switch (hookType) {
|
|
53
|
+
// Pre-operation hooks
|
|
54
|
+
case 'pre-edit':
|
|
55
|
+
return await this.preEditHook(args);
|
|
56
|
+
case 'pre-bash':
|
|
57
|
+
return await this.preBashHook(args);
|
|
58
|
+
case 'pre-task':
|
|
59
|
+
return await this.preTaskHook(args);
|
|
60
|
+
case 'pre-search':
|
|
61
|
+
return await this.preSearchHook(args);
|
|
62
|
+
case 'pre-mcp':
|
|
63
|
+
return await this.preMcpHook(args);
|
|
64
|
+
|
|
65
|
+
// Post-operation hooks
|
|
66
|
+
case 'post-edit':
|
|
67
|
+
return await this.postEditHook(args);
|
|
68
|
+
case 'post-bash':
|
|
69
|
+
return await this.postBashHook(args);
|
|
70
|
+
case 'post-task':
|
|
71
|
+
return await this.postTaskHook(args);
|
|
72
|
+
case 'post-search':
|
|
73
|
+
return await this.postSearchHook(args);
|
|
74
|
+
case 'post-web-search':
|
|
75
|
+
return await this.postWebSearchHook(args);
|
|
76
|
+
case 'post-web-fetch':
|
|
77
|
+
return await this.postWebFetchHook(args);
|
|
78
|
+
|
|
79
|
+
// MCP-specific hooks
|
|
80
|
+
case 'mcp-swarm-initialized':
|
|
81
|
+
return await this.mcpSwarmInitializedHook(args);
|
|
82
|
+
case 'mcp-agent-spawned':
|
|
83
|
+
return await this.mcpAgentSpawnedHook(args);
|
|
84
|
+
case 'mcp-task-orchestrated':
|
|
85
|
+
return await this.mcpTaskOrchestratedHook(args);
|
|
86
|
+
case 'mcp-neural-trained':
|
|
87
|
+
return await this.mcpNeuralTrainedHook(args);
|
|
88
|
+
|
|
89
|
+
// System hooks
|
|
90
|
+
case 'notification':
|
|
91
|
+
return await this.notificationHook(args);
|
|
92
|
+
case 'session-end':
|
|
93
|
+
return await this.sessionEndHook(args);
|
|
94
|
+
case 'session-restore':
|
|
95
|
+
return await this.sessionRestoreHook(args);
|
|
96
|
+
case 'agent-complete':
|
|
97
|
+
return await this.agentCompleteHook(args);
|
|
98
|
+
|
|
99
|
+
default:
|
|
100
|
+
return { continue: true, reason: `Unknown hook type: ${hookType}` };
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error(`Hook error (${hookType}):`, error.message);
|
|
104
|
+
return {
|
|
105
|
+
continue: true,
|
|
106
|
+
error: error.message,
|
|
107
|
+
fallback: 'Hook error - continuing with default behavior',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Pre-search hook - Prepare cache and optimize search
|
|
114
|
+
*/
|
|
115
|
+
async preSearchHook(args) {
|
|
116
|
+
const { pattern } = args;
|
|
117
|
+
|
|
118
|
+
// Initialize search cache
|
|
119
|
+
if (!this.sessionData.searchCache) {
|
|
120
|
+
this.sessionData.searchCache = new Map();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check cache for similar patterns
|
|
124
|
+
const cachedResult = this.sessionData.searchCache.get(pattern);
|
|
125
|
+
if (cachedResult && Date.now() - cachedResult.timestamp < 300000) { // 5 min cache
|
|
126
|
+
return {
|
|
127
|
+
continue: true,
|
|
128
|
+
cached: true,
|
|
129
|
+
cacheHit: cachedResult.files.length,
|
|
130
|
+
metadata: { pattern, cached: true },
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
continue: true,
|
|
136
|
+
reason: 'Search prepared',
|
|
137
|
+
metadata: { pattern, cacheReady: true },
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Pre-MCP hook - Validate MCP tool state
|
|
143
|
+
*/
|
|
144
|
+
async preMcpHook(args) {
|
|
145
|
+
const { tool, params } = args;
|
|
146
|
+
|
|
147
|
+
// Parse params if string
|
|
148
|
+
const toolParams = typeof params === 'string' ? JSON.parse(params) : params;
|
|
149
|
+
|
|
150
|
+
// Validate swarm state for MCP operations
|
|
151
|
+
if (tool.includes('agent_spawn') || tool.includes('task_orchestrate')) {
|
|
152
|
+
const swarmStatus = await this.checkSwarmStatus();
|
|
153
|
+
if (!swarmStatus.initialized) {
|
|
154
|
+
return {
|
|
155
|
+
continue: true,
|
|
156
|
+
warning: 'Swarm not initialized - will be created automatically',
|
|
157
|
+
autoInit: true,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Track MCP operations
|
|
163
|
+
this.sessionData.operations.push({
|
|
164
|
+
type: 'mcp',
|
|
165
|
+
tool,
|
|
166
|
+
params: toolParams,
|
|
167
|
+
timestamp: Date.now(),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
continue: true,
|
|
172
|
+
reason: 'MCP tool validated',
|
|
173
|
+
metadata: { tool, state: 'ready' },
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Pre-edit hook - Ensure coordination before file modifications
|
|
179
|
+
*/
|
|
180
|
+
async preEditHook(args) {
|
|
181
|
+
const { file } = args;
|
|
182
|
+
|
|
183
|
+
// Determine file type and assign appropriate agent
|
|
184
|
+
const fileExt = path.extname(file);
|
|
185
|
+
const agentType = this.getAgentTypeForFile(fileExt);
|
|
186
|
+
|
|
187
|
+
// Check if swarm is initialized
|
|
188
|
+
const swarmStatus = await this.checkSwarmStatus();
|
|
189
|
+
if (!swarmStatus.initialized) {
|
|
190
|
+
return {
|
|
191
|
+
continue: false,
|
|
192
|
+
reason: 'Swarm not initialized - run mcp__ruv-swarm__swarm_init first',
|
|
193
|
+
suggestion: 'Initialize swarm with appropriate topology',
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Ensure appropriate agent exists
|
|
198
|
+
const agent = await this.ensureAgent(agentType);
|
|
199
|
+
|
|
200
|
+
// Record operation
|
|
201
|
+
this.sessionData.operations.push({
|
|
202
|
+
type: 'edit',
|
|
203
|
+
file,
|
|
204
|
+
agent: agent.id,
|
|
205
|
+
timestamp: Date.now(),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
continue: true,
|
|
210
|
+
reason: `${agentType} agent assigned for ${fileExt} file`,
|
|
211
|
+
metadata: {
|
|
212
|
+
agent_id: agent.id,
|
|
213
|
+
agent_type: agentType,
|
|
214
|
+
cognitive_pattern: agent.pattern,
|
|
215
|
+
readiness: agent.readiness,
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Pre-task hook - Auto-spawn agents and optimize topology
|
|
222
|
+
*/
|
|
223
|
+
async preTaskHook(args) {
|
|
224
|
+
const { description, autoSpawnAgents, optimizeTopology } = args;
|
|
225
|
+
|
|
226
|
+
// Analyze task complexity
|
|
227
|
+
const complexity = this.analyzeTaskComplexity(description);
|
|
228
|
+
|
|
229
|
+
// Determine optimal topology
|
|
230
|
+
const topology = optimizeTopology ? this.selectOptimalTopology(complexity) : 'mesh';
|
|
231
|
+
|
|
232
|
+
// Auto-spawn required agents
|
|
233
|
+
if (autoSpawnAgents) {
|
|
234
|
+
const requiredAgents = this.determineRequiredAgents(description, complexity);
|
|
235
|
+
for (const agentType of requiredAgents) {
|
|
236
|
+
await this.ensureAgent(agentType);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
continue: true,
|
|
242
|
+
reason: 'Task prepared with optimal configuration',
|
|
243
|
+
metadata: {
|
|
244
|
+
complexity,
|
|
245
|
+
topology,
|
|
246
|
+
agentsReady: true,
|
|
247
|
+
estimatedDuration: complexity.estimatedMinutes * 60000,
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Post-edit hook - Format and learn from edits
|
|
254
|
+
*/
|
|
255
|
+
async postEditHook(args) {
|
|
256
|
+
const { file, autoFormat, trainPatterns, updateGraph } = args;
|
|
257
|
+
const result = {
|
|
258
|
+
continue: true,
|
|
259
|
+
formatted: false,
|
|
260
|
+
training: null,
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// Auto-format if requested
|
|
264
|
+
if (autoFormat) {
|
|
265
|
+
const formatted = await this.autoFormatFile(file);
|
|
266
|
+
result.formatted = formatted.success;
|
|
267
|
+
result.formatDetails = formatted.details;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Train neural patterns
|
|
271
|
+
if (trainPatterns) {
|
|
272
|
+
const training = await this.trainPatternsFromEdit(file);
|
|
273
|
+
result.training = training;
|
|
274
|
+
this.sessionData.metrics.patternsImproved += training.improvement || 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Update knowledge graph if requested
|
|
278
|
+
if (updateGraph) {
|
|
279
|
+
await this.updateKnowledgeGraph(file, 'edit');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Update session data
|
|
283
|
+
this.sessionData.metrics.tokensSaved += 10; // Estimated savings
|
|
284
|
+
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Post-task hook - Analyze performance and update coordination
|
|
290
|
+
*/
|
|
291
|
+
async postTaskHook(args) {
|
|
292
|
+
const { taskId, analyzePerformance, updateCoordination } = args;
|
|
293
|
+
|
|
294
|
+
const performance = {
|
|
295
|
+
taskId,
|
|
296
|
+
completionTime: Date.now() - (this.sessionData.taskStartTimes?.get(taskId) || Date.now()),
|
|
297
|
+
agentsUsed: this.sessionData.taskAgents?.get(taskId) || [],
|
|
298
|
+
success: true,
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// Analyze performance
|
|
302
|
+
if (analyzePerformance) {
|
|
303
|
+
performance.analysis = {
|
|
304
|
+
efficiency: this.calculateEfficiency(performance),
|
|
305
|
+
bottlenecks: this.identifyBottlenecks(performance),
|
|
306
|
+
improvements: this.suggestImprovements(performance),
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Update coordination strategies
|
|
311
|
+
if (updateCoordination) {
|
|
312
|
+
this.updateCoordinationStrategy(performance);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
this.sessionData.metrics.tasksCompleted++;
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
continue: true,
|
|
319
|
+
performance,
|
|
320
|
+
metadata: { taskId, optimized: true },
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Post-web-search hook - Analyze results and update knowledge
|
|
326
|
+
*/
|
|
327
|
+
async postWebSearchHook(args) {
|
|
328
|
+
const { query, updateKnowledge } = args;
|
|
329
|
+
|
|
330
|
+
// Track search patterns
|
|
331
|
+
if (!this.sessionData.searchPatterns) {
|
|
332
|
+
this.sessionData.searchPatterns = new Map();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const patterns = this.extractSearchPatterns(query);
|
|
336
|
+
patterns.forEach(pattern => {
|
|
337
|
+
const count = this.sessionData.searchPatterns.get(pattern) || 0;
|
|
338
|
+
this.sessionData.searchPatterns.set(pattern, count + 1);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Update knowledge base
|
|
342
|
+
if (updateKnowledge) {
|
|
343
|
+
await this.updateKnowledgeBase('search', { query, patterns });
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
continue: true,
|
|
348
|
+
reason: 'Search analyzed and knowledge updated',
|
|
349
|
+
metadata: {
|
|
350
|
+
query,
|
|
351
|
+
patternsExtracted: patterns.length,
|
|
352
|
+
knowledgeUpdated: updateKnowledge,
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Post-web-fetch hook - Extract patterns and cache content
|
|
359
|
+
*/
|
|
360
|
+
async postWebFetchHook(args) {
|
|
361
|
+
const { url, extractPatterns, cacheContent } = args;
|
|
362
|
+
|
|
363
|
+
const result = {
|
|
364
|
+
continue: true,
|
|
365
|
+
patterns: [],
|
|
366
|
+
cached: false,
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// Extract patterns from URL
|
|
370
|
+
if (extractPatterns) {
|
|
371
|
+
result.patterns = this.extractUrlPatterns(url);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Cache content for future use
|
|
375
|
+
if (cacheContent) {
|
|
376
|
+
if (!this.sessionData.contentCache) {
|
|
377
|
+
this.sessionData.contentCache = new Map();
|
|
378
|
+
}
|
|
379
|
+
this.sessionData.contentCache.set(url, {
|
|
380
|
+
timestamp: Date.now(),
|
|
381
|
+
patterns: result.patterns,
|
|
382
|
+
});
|
|
383
|
+
result.cached = true;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Notification hook - Handle notifications with swarm status
|
|
391
|
+
*/
|
|
392
|
+
async notificationHook(args) {
|
|
393
|
+
const { message, level, withSwarmStatus, sendTelemetry, type, context, agentId } = args;
|
|
394
|
+
|
|
395
|
+
const notification = {
|
|
396
|
+
message,
|
|
397
|
+
level: level || 'info',
|
|
398
|
+
type: type || 'general',
|
|
399
|
+
context: context || {},
|
|
400
|
+
agentId: agentId || null,
|
|
401
|
+
timestamp: Date.now(),
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// Add swarm status if requested
|
|
405
|
+
if (withSwarmStatus) {
|
|
406
|
+
const status = await this.getSwarmStatus();
|
|
407
|
+
notification.swarmStatus = {
|
|
408
|
+
agents: status.agents?.size || 0,
|
|
409
|
+
activeTasks: status.activeTasks || 0,
|
|
410
|
+
health: status.health || 'unknown',
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Send telemetry if enabled
|
|
415
|
+
if (sendTelemetry && process.env.RUV_SWARM_TELEMETRY_ENABLED === 'true') {
|
|
416
|
+
this.sendTelemetry('notification', notification);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Store notification in both runtime memory AND persistent database
|
|
420
|
+
if (!this.sessionData.notifications) {
|
|
421
|
+
this.sessionData.notifications = [];
|
|
422
|
+
}
|
|
423
|
+
this.sessionData.notifications.push(notification);
|
|
424
|
+
|
|
425
|
+
// CRITICAL FIX: Also store in persistent database for cross-agent access
|
|
426
|
+
await this.storeNotificationInDatabase(notification);
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
continue: true,
|
|
430
|
+
notification,
|
|
431
|
+
handled: true,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Pre-bash hook - Validate commands before execution
|
|
437
|
+
*/
|
|
438
|
+
async preBashHook(args) {
|
|
439
|
+
const { command } = args;
|
|
440
|
+
|
|
441
|
+
// Safety checks
|
|
442
|
+
const safetyCheck = this.validateCommandSafety(command);
|
|
443
|
+
if (!safetyCheck.safe) {
|
|
444
|
+
return {
|
|
445
|
+
continue: false,
|
|
446
|
+
reason: safetyCheck.reason,
|
|
447
|
+
riskLevel: safetyCheck.riskLevel,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Check resource requirements
|
|
452
|
+
const resources = this.estimateCommandResources(command);
|
|
453
|
+
if (resources.requiresAgent) {
|
|
454
|
+
await this.ensureAgent(resources.agentType);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
continue: true,
|
|
459
|
+
reason: 'Command validated and resources available',
|
|
460
|
+
metadata: {
|
|
461
|
+
estimatedDuration: resources.duration,
|
|
462
|
+
requiresAgent: resources.requiresAgent,
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* MCP swarm initialized hook - Persist configuration
|
|
469
|
+
*/
|
|
470
|
+
async mcpSwarmInitializedHook(args) {
|
|
471
|
+
const { swarmId, topology, persistConfig, enableMonitoring } = args;
|
|
472
|
+
|
|
473
|
+
// Store swarm configuration
|
|
474
|
+
const swarmConfig = {
|
|
475
|
+
id: swarmId,
|
|
476
|
+
topology,
|
|
477
|
+
initialized: Date.now(),
|
|
478
|
+
monitoring: enableMonitoring,
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
// Persist configuration
|
|
482
|
+
if (persistConfig) {
|
|
483
|
+
const configDir = path.join(process.cwd(), '.@sparkleideas/ruv-swarm');
|
|
484
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
485
|
+
await fs.writeFile(
|
|
486
|
+
path.join(configDir, 'swarm-config.json'),
|
|
487
|
+
JSON.stringify(swarmConfig, null, 2),
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Initialize monitoring
|
|
492
|
+
if (enableMonitoring) {
|
|
493
|
+
this.sessionData.monitoring = {
|
|
494
|
+
swarmId,
|
|
495
|
+
startTime: Date.now(),
|
|
496
|
+
events: [],
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return {
|
|
501
|
+
continue: true,
|
|
502
|
+
reason: 'Swarm initialized and configured',
|
|
503
|
+
metadata: swarmConfig,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* MCP agent spawned hook - Update roster and train
|
|
509
|
+
*/
|
|
510
|
+
async mcpAgentSpawnedHook(args) {
|
|
511
|
+
const { agentId, type, updateRoster, trainSpecialization } = args;
|
|
512
|
+
|
|
513
|
+
// Update agent roster
|
|
514
|
+
if (updateRoster) {
|
|
515
|
+
const agent = {
|
|
516
|
+
id: agentId,
|
|
517
|
+
type,
|
|
518
|
+
specialization: this.getSpecializationForType(type),
|
|
519
|
+
spawned: Date.now(),
|
|
520
|
+
performance: { tasks: 0, successRate: 1.0 },
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
this.sessionData.agents.set(agentId, agent);
|
|
524
|
+
|
|
525
|
+
// Persist roster
|
|
526
|
+
const rosterPath = path.join(process.cwd(), '.@sparkleideas/ruv-swarm', 'agent-roster.json');
|
|
527
|
+
const roster = Array.from(this.sessionData.agents.values());
|
|
528
|
+
await fs.writeFile(rosterPath, JSON.stringify(roster, null, 2));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Train specialization patterns
|
|
532
|
+
if (trainSpecialization) {
|
|
533
|
+
const training = {
|
|
534
|
+
agentId,
|
|
535
|
+
type,
|
|
536
|
+
patterns: this.generateSpecializationPatterns(type),
|
|
537
|
+
confidence: 0.9 + Math.random() * 0.1,
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
this.sessionData.learnings.push(training);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return {
|
|
544
|
+
continue: true,
|
|
545
|
+
agentId,
|
|
546
|
+
type,
|
|
547
|
+
specialized: true,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* MCP task orchestrated hook - Monitor and optimize
|
|
553
|
+
*/
|
|
554
|
+
async mcpTaskOrchestratedHook(args) {
|
|
555
|
+
const { taskId, monitorProgress, optimizeDistribution } = args;
|
|
556
|
+
|
|
557
|
+
// Initialize task tracking
|
|
558
|
+
if (!this.sessionData.taskStartTimes) {
|
|
559
|
+
this.sessionData.taskStartTimes = new Map();
|
|
560
|
+
}
|
|
561
|
+
if (!this.sessionData.taskAgents) {
|
|
562
|
+
this.sessionData.taskAgents = new Map();
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
this.sessionData.taskStartTimes.set(taskId, Date.now());
|
|
566
|
+
|
|
567
|
+
// Monitor progress setup
|
|
568
|
+
if (monitorProgress) {
|
|
569
|
+
this.sessionData.taskMonitoring = this.sessionData.taskMonitoring || new Map();
|
|
570
|
+
this.sessionData.taskMonitoring.set(taskId, {
|
|
571
|
+
checkpoints: [],
|
|
572
|
+
resources: [],
|
|
573
|
+
bottlenecks: [],
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Optimize distribution
|
|
578
|
+
if (optimizeDistribution) {
|
|
579
|
+
const optimization = {
|
|
580
|
+
taskId,
|
|
581
|
+
strategy: 'load-balanced',
|
|
582
|
+
agentAllocation: this.optimizeAgentAllocation(taskId),
|
|
583
|
+
parallelization: this.calculateParallelization(taskId),
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
return {
|
|
587
|
+
continue: true,
|
|
588
|
+
taskId,
|
|
589
|
+
optimization,
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return {
|
|
594
|
+
continue: true,
|
|
595
|
+
taskId,
|
|
596
|
+
monitoring: monitorProgress,
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* MCP neural trained hook - Save improvements
|
|
602
|
+
*/
|
|
603
|
+
async mcpNeuralTrainedHook(args) {
|
|
604
|
+
const { improvement, saveWeights, updatePatterns } = args;
|
|
605
|
+
|
|
606
|
+
const result = {
|
|
607
|
+
continue: true,
|
|
608
|
+
improvement: parseFloat(improvement),
|
|
609
|
+
saved: false,
|
|
610
|
+
patternsUpdated: false,
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
// Save neural weights
|
|
614
|
+
if (saveWeights) {
|
|
615
|
+
const weightsDir = path.join(process.cwd(), '.@sparkleideas/ruv-swarm', 'neural-weights');
|
|
616
|
+
await fs.mkdir(weightsDir, { recursive: true });
|
|
617
|
+
|
|
618
|
+
const weightData = {
|
|
619
|
+
timestamp: Date.now(),
|
|
620
|
+
improvement,
|
|
621
|
+
weights: this.generateMockWeights(),
|
|
622
|
+
version: this.sessionData.learnings.length,
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
await fs.writeFile(
|
|
626
|
+
path.join(weightsDir, `weights-${Date.now()}.json`),
|
|
627
|
+
JSON.stringify(weightData, null, 2),
|
|
628
|
+
);
|
|
629
|
+
|
|
630
|
+
result.saved = true;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Update cognitive patterns
|
|
634
|
+
if (updatePatterns) {
|
|
635
|
+
this.sessionData.metrics.patternsImproved++;
|
|
636
|
+
|
|
637
|
+
const patternUpdate = {
|
|
638
|
+
timestamp: Date.now(),
|
|
639
|
+
improvement,
|
|
640
|
+
patterns: ['convergent', 'divergent', 'lateral'],
|
|
641
|
+
confidence: 0.85 + parseFloat(improvement),
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
this.sessionData.learnings.push(patternUpdate);
|
|
645
|
+
result.patternsUpdated = true;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return result;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Agent complete hook - Commit to git with detailed report
|
|
653
|
+
*/
|
|
654
|
+
async agentCompleteHook(args) {
|
|
655
|
+
const { agent, prompt, output, commitToGit, generateReport, pushToGithub } = args;
|
|
656
|
+
|
|
657
|
+
try {
|
|
658
|
+
const timestamp = new Date().toISOString();
|
|
659
|
+
const agentName = agent || 'Unknown Agent';
|
|
660
|
+
// const shortOutput = output ? `${output.substring(0, 500) }...` : 'No output';
|
|
661
|
+
|
|
662
|
+
// Generate detailed report
|
|
663
|
+
let reportPath = null;
|
|
664
|
+
if (generateReport) {
|
|
665
|
+
const reportDir = path.join(process.cwd(), '.@sparkleideas/ruv-swarm', 'agent-reports');
|
|
666
|
+
await fs.mkdir(reportDir, { recursive: true });
|
|
667
|
+
|
|
668
|
+
const sanitizedAgent = agentName.replace(/[^a-zA-Z0-9-]/g, '-').toLowerCase();
|
|
669
|
+
reportPath = path.join(reportDir, `${sanitizedAgent}-${Date.now()}.md`);
|
|
670
|
+
|
|
671
|
+
const report = `# Agent Completion Report: ${agentName}
|
|
672
|
+
|
|
673
|
+
## Metadata
|
|
674
|
+
- **Agent**: ${agentName}
|
|
675
|
+
- **Timestamp**: ${timestamp}
|
|
676
|
+
- **Session**: ${this.sessionData.sessionId || 'N/A'}
|
|
677
|
+
- **Duration**: ${this.formatDuration(Date.now() - this.sessionData.startTime)}
|
|
678
|
+
|
|
679
|
+
## Task Description
|
|
680
|
+
\`\`\`
|
|
681
|
+
${prompt || 'No prompt available'}
|
|
682
|
+
\`\`\`
|
|
683
|
+
|
|
684
|
+
## Output Summary
|
|
685
|
+
${output ? `### Key Accomplishments\n${ this.extractKeyPoints(output)}` : 'No output captured'}
|
|
686
|
+
|
|
687
|
+
## Performance Metrics
|
|
688
|
+
- **Total Operations**: ${this.sessionData.operations.length}
|
|
689
|
+
- **Files Modified**: ${this.getModifiedFilesCount()}
|
|
690
|
+
- **Efficiency Score**: ${this.calculateEfficiency({ completionTime: Date.now() - this.sessionData.startTime }).rating}
|
|
691
|
+
- **Tokens Saved**: ${this.sessionData.metrics.tokensSaved}
|
|
692
|
+
|
|
693
|
+
## Files Modified
|
|
694
|
+
${this.getModifiedFilesList()}
|
|
695
|
+
|
|
696
|
+
## Coordination Activity
|
|
697
|
+
- **Memory Operations**: ${this.sessionData.operations.filter(op => op.type === 'memory').length}
|
|
698
|
+
- **Hook Executions**: ${this.sessionData.operations.filter(op => op.type === 'hook').length}
|
|
699
|
+
- **Neural Training**: ${this.sessionData.metrics.patternsImproved} patterns improved
|
|
700
|
+
|
|
701
|
+
## Learnings & Patterns
|
|
702
|
+
${this.sessionData.learnings.length > 0 ? this.sessionData.learnings.map(l => `- ${l.type || 'General'}: ${l.description || JSON.stringify(l)}`).join('\n') : 'No specific learnings captured'}
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
*Generated by @sparkleideas/ruv-swarm agent coordination system*
|
|
706
|
+
`;
|
|
707
|
+
|
|
708
|
+
await fs.writeFile(reportPath, report);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Commit to git if requested
|
|
712
|
+
if (commitToGit) {
|
|
713
|
+
try {
|
|
714
|
+
// Check if we're in a git repo
|
|
715
|
+
execSync('git rev-parse --git-dir', { stdio: 'ignore' });
|
|
716
|
+
|
|
717
|
+
// Get git status
|
|
718
|
+
const status = execSync('git status --porcelain', { encoding: 'utf-8' });
|
|
719
|
+
|
|
720
|
+
if (status.trim()) {
|
|
721
|
+
// Stage changes
|
|
722
|
+
execSync('git add -A');
|
|
723
|
+
|
|
724
|
+
// Create detailed commit message
|
|
725
|
+
const commitMessage = `feat(${agentName.toLowerCase().replace(/[^a-z0-9]/g, '-')}): Complete agent task
|
|
726
|
+
|
|
727
|
+
Agent: ${agentName}
|
|
728
|
+
Timestamp: ${timestamp}
|
|
729
|
+
|
|
730
|
+
## Task Summary
|
|
731
|
+
${prompt ? `${prompt.split('\n')[0].substring(0, 100) }...` : 'No task description'}
|
|
732
|
+
|
|
733
|
+
## Achievements
|
|
734
|
+
${this.extractBulletPoints(output)}
|
|
735
|
+
|
|
736
|
+
## Metrics
|
|
737
|
+
- Operations: ${this.sessionData.operations.length}
|
|
738
|
+
- Files: ${this.getModifiedFilesCount()}
|
|
739
|
+
- Efficiency: ${this.calculateEfficiency({ completionTime: Date.now() - this.sessionData.startTime }).rating}
|
|
740
|
+
${reportPath ? `\n## Report\nDetailed report: ${path.relative(process.cwd(), reportPath)}` : ''}
|
|
741
|
+
|
|
742
|
+
🤖 Generated by @sparkleideas/ruv-swarm agent coordination
|
|
743
|
+
Co-Authored-By: ${agentName} <agent@ruv-swarm.ai>`;
|
|
744
|
+
|
|
745
|
+
// Commit using heredoc to handle complex messages
|
|
746
|
+
const commitCmd = `git commit -m "$(cat <<'EOF'
|
|
747
|
+
${commitMessage}
|
|
748
|
+
EOF
|
|
749
|
+
)"`;
|
|
750
|
+
execSync(commitCmd, { shell: '/bin/bash' });
|
|
751
|
+
|
|
752
|
+
// Log commit info
|
|
753
|
+
const commitHash = execSync('git rev-parse HEAD', { encoding: 'utf-8' }).trim();
|
|
754
|
+
console.log(`✅ Committed agent work: ${commitHash.substring(0, 7)}`);
|
|
755
|
+
|
|
756
|
+
// Push if requested and configured
|
|
757
|
+
if (pushToGithub && process.env.RUV_SWARM_AUTO_PUSH === 'true') {
|
|
758
|
+
console.log('📤 Pushing to GitHub...');
|
|
759
|
+
execSync('git push', { stdio: 'inherit' });
|
|
760
|
+
console.log('✅ Pushed to GitHub');
|
|
761
|
+
}
|
|
762
|
+
} else {
|
|
763
|
+
console.log('ℹ️ No changes to commit');
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
} catch (gitError) {
|
|
767
|
+
console.error('Git operation failed:', gitError.message);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Update telemetry
|
|
772
|
+
this.sendTelemetry('agent_complete', {
|
|
773
|
+
agent: agentName,
|
|
774
|
+
hasReport: generateReport,
|
|
775
|
+
hasCommit: commitToGit,
|
|
776
|
+
operationCount: this.sessionData.operations.length,
|
|
777
|
+
duration: Date.now() - this.sessionData.startTime,
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
return {
|
|
781
|
+
continue: true,
|
|
782
|
+
agent: agentName,
|
|
783
|
+
reportGenerated: generateReport,
|
|
784
|
+
reportPath: reportPath ? path.relative(process.cwd(), reportPath) : null,
|
|
785
|
+
committed: commitToGit,
|
|
786
|
+
duration: this.formatDuration(Date.now() - this.sessionData.startTime),
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
} catch (error) {
|
|
790
|
+
console.error('Agent complete hook error:', error);
|
|
791
|
+
return {
|
|
792
|
+
continue: true,
|
|
793
|
+
error: error.message,
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Extract key points from output
|
|
800
|
+
*/
|
|
801
|
+
extractKeyPoints(output) {
|
|
802
|
+
const lines = output.split('\n').filter(l => l.trim());
|
|
803
|
+
const keyPoints = [];
|
|
804
|
+
|
|
805
|
+
// Look for bullet points or numbered items
|
|
806
|
+
lines.forEach(line => {
|
|
807
|
+
if (line.match(/^[\-\*•]\s/) || line.match(/^\d+\.\s/)) {
|
|
808
|
+
keyPoints.push(line);
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// If no bullet points, take first few lines
|
|
813
|
+
if (keyPoints.length === 0) {
|
|
814
|
+
keyPoints.push(...lines.slice(0, 5));
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return keyPoints.slice(0, 10).join('\n');
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Extract bullet points for commit message
|
|
822
|
+
*/
|
|
823
|
+
extractBulletPoints(output) {
|
|
824
|
+
if (!output) {
|
|
825
|
+
return '- No specific achievements captured';
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
const points = this.extractKeyPoints(output)
|
|
829
|
+
.split('\n')
|
|
830
|
+
.slice(0, 5)
|
|
831
|
+
.map(p => `- ${p.replace(/^[\-\*•\d+\.\s]+/, '').trim()}`);
|
|
832
|
+
|
|
833
|
+
return points.length > 0 ? points.join('\n') : '- Task completed successfully';
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Get count of modified files
|
|
838
|
+
*/
|
|
839
|
+
getModifiedFilesCount() {
|
|
840
|
+
const fileOps = this.sessionData.operations.filter(op =>
|
|
841
|
+
['edit', 'write', 'create'].includes(op.type),
|
|
842
|
+
);
|
|
843
|
+
|
|
844
|
+
const uniqueFiles = new Set(fileOps.map(op => op.file).filter(Boolean));
|
|
845
|
+
return uniqueFiles.size;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Get list of modified files
|
|
850
|
+
*/
|
|
851
|
+
getModifiedFilesList() {
|
|
852
|
+
const fileOps = this.sessionData.operations.filter(op =>
|
|
853
|
+
['edit', 'write', 'create'].includes(op.type),
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
const fileMap = new Map();
|
|
857
|
+
fileOps.forEach(op => {
|
|
858
|
+
if (op.file) {
|
|
859
|
+
if (!fileMap.has(op.file)) {
|
|
860
|
+
fileMap.set(op.file, []);
|
|
861
|
+
}
|
|
862
|
+
fileMap.get(op.file).push(op.type);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
if (fileMap.size === 0) {
|
|
867
|
+
return 'No files modified';
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
return Array.from(fileMap.entries())
|
|
871
|
+
.map(([file, ops]) => `- ${file} (${[...new Set(ops)].join(', ')})`)
|
|
872
|
+
.join('\n');
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Session restore hook - Load previous state
|
|
877
|
+
*/
|
|
878
|
+
async sessionRestoreHook(args) {
|
|
879
|
+
const { loadMemory, loadAgents } = args;
|
|
880
|
+
|
|
881
|
+
const result = {
|
|
882
|
+
continue: true,
|
|
883
|
+
restored: {
|
|
884
|
+
memory: false,
|
|
885
|
+
agents: false,
|
|
886
|
+
metrics: false,
|
|
887
|
+
},
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
try {
|
|
891
|
+
const sessionDir = path.join(process.cwd(), '.@sparkleideas/ruv-swarm');
|
|
892
|
+
|
|
893
|
+
// Load memory state
|
|
894
|
+
if (loadMemory) {
|
|
895
|
+
const memoryPath = path.join(sessionDir, 'memory-state.json');
|
|
896
|
+
if (await fs.access(memoryPath).then(() => true).catch(() => false)) {
|
|
897
|
+
const memory = JSON.parse(await fs.readFile(memoryPath, 'utf-8'));
|
|
898
|
+
this.sessionData = { ...this.sessionData, ...memory };
|
|
899
|
+
result.restored.memory = true;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Load agent roster
|
|
904
|
+
if (loadAgents) {
|
|
905
|
+
const rosterPath = path.join(sessionDir, 'agent-roster.json');
|
|
906
|
+
if (await fs.access(rosterPath).then(() => true).catch(() => false)) {
|
|
907
|
+
const roster = JSON.parse(await fs.readFile(rosterPath, 'utf-8'));
|
|
908
|
+
roster.forEach(agent => {
|
|
909
|
+
this.sessionData.agents.set(agent.id, agent);
|
|
910
|
+
});
|
|
911
|
+
result.restored.agents = true;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// Load metrics
|
|
916
|
+
const metricsPath = path.join(sessionDir, 'session-metrics.json');
|
|
917
|
+
if (await fs.access(metricsPath).then(() => true).catch(() => false)) {
|
|
918
|
+
const metrics = JSON.parse(await fs.readFile(metricsPath, 'utf-8'));
|
|
919
|
+
this.sessionData.metrics = { ...this.sessionData.metrics, ...metrics };
|
|
920
|
+
result.restored.metrics = true;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
} catch (error) {
|
|
924
|
+
console.error('Session restore error:', error.message);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
return result;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Session end hook - Generate summary and persist state
|
|
932
|
+
*/
|
|
933
|
+
async sessionEndHook(args) {
|
|
934
|
+
const { generateSummary, saveMemory, exportMetrics } = args;
|
|
935
|
+
const sessionDir = path.join(process.cwd(), '.claude', 'sessions');
|
|
936
|
+
await fs.mkdir(sessionDir, { recursive: true });
|
|
937
|
+
|
|
938
|
+
const timestamp = new Date().toISOString().replace(/:/g, '-');
|
|
939
|
+
const results = {};
|
|
940
|
+
|
|
941
|
+
// Generate summary
|
|
942
|
+
if (generateSummary) {
|
|
943
|
+
const summary = this.generateSessionSummary();
|
|
944
|
+
const summaryPath = path.join(sessionDir, `${timestamp}-summary.md`);
|
|
945
|
+
await fs.writeFile(summaryPath, summary);
|
|
946
|
+
results.summary = summaryPath;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// Save memory state
|
|
950
|
+
if (saveMemory) {
|
|
951
|
+
const state = this.captureSwarmState();
|
|
952
|
+
const statePath = path.join(sessionDir, `${timestamp}-state.json`);
|
|
953
|
+
await fs.writeFile(statePath, JSON.stringify(state, null, 2));
|
|
954
|
+
results.state = statePath;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Export metrics
|
|
958
|
+
if (exportMetrics) {
|
|
959
|
+
const metrics = this.calculateSessionMetrics();
|
|
960
|
+
const metricsPath = path.join(sessionDir, `${timestamp}-metrics.json`);
|
|
961
|
+
await fs.writeFile(metricsPath, JSON.stringify(metrics, null, 2));
|
|
962
|
+
results.metrics = metricsPath;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
console.log('\n🎯 Session Summary:');
|
|
966
|
+
console.log(`Duration: ${this.formatDuration(Date.now() - this.sessionData.startTime)}`);
|
|
967
|
+
console.log(`Operations: ${this.sessionData.operations.length}`);
|
|
968
|
+
console.log(`Tokens Saved: ${this.sessionData.metrics.tokensSaved}`);
|
|
969
|
+
console.log(`Patterns Improved: ${this.sessionData.metrics.patternsImproved}`);
|
|
970
|
+
|
|
971
|
+
return {
|
|
972
|
+
continue: true,
|
|
973
|
+
files: results,
|
|
974
|
+
summary: {
|
|
975
|
+
duration: Date.now() - this.sessionData.startTime,
|
|
976
|
+
operations: this.sessionData.operations.length,
|
|
977
|
+
improvements: this.sessionData.metrics.patternsImproved,
|
|
978
|
+
},
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Helper methods
|
|
983
|
+
|
|
984
|
+
getAgentTypeForFile(extension) {
|
|
985
|
+
const mapping = {
|
|
986
|
+
'.js': 'coder',
|
|
987
|
+
'.ts': 'coder',
|
|
988
|
+
'.jsx': 'coder',
|
|
989
|
+
'.tsx': 'coder',
|
|
990
|
+
'.py': 'coder',
|
|
991
|
+
'.go': 'coder',
|
|
992
|
+
'.rs': 'coder',
|
|
993
|
+
'.md': 'researcher',
|
|
994
|
+
'.txt': 'researcher',
|
|
995
|
+
'.json': 'analyst',
|
|
996
|
+
'.yaml': 'analyst',
|
|
997
|
+
'.yml': 'analyst',
|
|
998
|
+
'.toml': 'analyst',
|
|
999
|
+
'.xml': 'analyst',
|
|
1000
|
+
'.sql': 'analyst',
|
|
1001
|
+
};
|
|
1002
|
+
return mapping[extension] || 'coordinator';
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
async checkSwarmStatus() {
|
|
1006
|
+
try {
|
|
1007
|
+
// Check if swarm is initialized via file or global state
|
|
1008
|
+
const statusFile = path.join(process.cwd(), '.@sparkleideas/ruv-swarm', 'status.json');
|
|
1009
|
+
const exists = await fs.access(statusFile).then(() => true).catch(() => false);
|
|
1010
|
+
|
|
1011
|
+
if (exists) {
|
|
1012
|
+
const status = JSON.parse(await fs.readFile(statusFile, 'utf-8'));
|
|
1013
|
+
return { initialized: true, ...status };
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
return { initialized: false };
|
|
1017
|
+
} catch (_error) {
|
|
1018
|
+
return { initialized: false };
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
async ensureAgent(type) {
|
|
1023
|
+
let agent = this.sessionData.agents.get(type);
|
|
1024
|
+
|
|
1025
|
+
if (!agent) {
|
|
1026
|
+
// Simulate agent creation
|
|
1027
|
+
agent = {
|
|
1028
|
+
id: `${type}-${Date.now()}`,
|
|
1029
|
+
type,
|
|
1030
|
+
pattern: this.getCognitivePattern(type),
|
|
1031
|
+
readiness: 0.95,
|
|
1032
|
+
created: Date.now(),
|
|
1033
|
+
};
|
|
1034
|
+
this.sessionData.agents.set(type, agent);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
return agent;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
getCognitivePattern(agentType) {
|
|
1041
|
+
const patterns = {
|
|
1042
|
+
coder: 'convergent',
|
|
1043
|
+
researcher: 'divergent',
|
|
1044
|
+
analyst: 'critical',
|
|
1045
|
+
coordinator: 'systems',
|
|
1046
|
+
architect: 'abstract',
|
|
1047
|
+
optimizer: 'lateral',
|
|
1048
|
+
};
|
|
1049
|
+
return patterns[agentType] || 'balanced';
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
async autoFormatFile(filePath) {
|
|
1053
|
+
const ext = path.extname(filePath);
|
|
1054
|
+
const formatters = {
|
|
1055
|
+
'.js': 'prettier --write',
|
|
1056
|
+
'.ts': 'prettier --write',
|
|
1057
|
+
'.jsx': 'prettier --write',
|
|
1058
|
+
'.tsx': 'prettier --write',
|
|
1059
|
+
'.json': 'prettier --write',
|
|
1060
|
+
'.md': 'prettier --write --prose-wrap always',
|
|
1061
|
+
'.py': 'black',
|
|
1062
|
+
'.go': 'gofmt -w',
|
|
1063
|
+
'.rs': 'rustfmt',
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
const formatter = formatters[ext];
|
|
1067
|
+
if (!formatter) {
|
|
1068
|
+
return { success: false, reason: 'No formatter configured for file type' };
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
try {
|
|
1072
|
+
execSync(`${formatter} "${filePath}"`, { stdio: 'pipe' });
|
|
1073
|
+
return { success: true, details: { formatter, fileType: ext } };
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
return { success: false, reason: error.message };
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
async trainPatternsFromEdit(filePath) {
|
|
1080
|
+
// Simulate neural pattern training
|
|
1081
|
+
const improvement = Math.random() * 0.05; // 0-5% improvement
|
|
1082
|
+
const confidence = 0.85 + Math.random() * 0.1; // 85-95% confidence
|
|
1083
|
+
|
|
1084
|
+
this.sessionData.learnings.push({
|
|
1085
|
+
file: filePath,
|
|
1086
|
+
timestamp: Date.now(),
|
|
1087
|
+
improvement,
|
|
1088
|
+
confidence,
|
|
1089
|
+
pattern: `edit_pattern_${ path.extname(filePath)}`,
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
return {
|
|
1093
|
+
pattern_updated: true,
|
|
1094
|
+
improvement: improvement.toFixed(3),
|
|
1095
|
+
confidence: confidence.toFixed(2),
|
|
1096
|
+
total_examples: this.sessionData.learnings.length,
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
validateCommandSafety(command) {
|
|
1101
|
+
const dangerousPatterns = [
|
|
1102
|
+
/rm\s+-rf\s+\//,
|
|
1103
|
+
/curl.*\|\s*bash/,
|
|
1104
|
+
/wget.*\|\s*sh/,
|
|
1105
|
+
/eval\s*\(/,
|
|
1106
|
+
/>\/dev\/null\s+2>&1/,
|
|
1107
|
+
];
|
|
1108
|
+
|
|
1109
|
+
for (const pattern of dangerousPatterns) {
|
|
1110
|
+
if (pattern.test(command)) {
|
|
1111
|
+
return {
|
|
1112
|
+
safe: false,
|
|
1113
|
+
reason: 'Command contains potentially dangerous pattern',
|
|
1114
|
+
riskLevel: 'high',
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
return { safe: true };
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
estimateCommandResources(command) {
|
|
1123
|
+
const resourceMap = {
|
|
1124
|
+
'npm test': { duration: 30000, requiresAgent: true, agentType: 'coordinator' },
|
|
1125
|
+
'npm run build': { duration: 60000, requiresAgent: true, agentType: 'optimizer' },
|
|
1126
|
+
'git': { duration: 1000, requiresAgent: false },
|
|
1127
|
+
'ls': { duration: 100, requiresAgent: false },
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
for (const [pattern, resources] of Object.entries(resourceMap)) {
|
|
1131
|
+
if (command.includes(pattern)) {
|
|
1132
|
+
return resources;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
return { duration: 5000, requiresAgent: false };
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
generateSessionSummary() {
|
|
1140
|
+
const duration = Date.now() - this.sessionData.startTime;
|
|
1141
|
+
const agentList = Array.from(this.sessionData.agents.values());
|
|
1142
|
+
|
|
1143
|
+
return `# @sparkleideas/ruv-swarm Session Summary
|
|
1144
|
+
Date: ${new Date().toISOString()}
|
|
1145
|
+
Duration: ${this.formatDuration(duration)}
|
|
1146
|
+
Token Reduction: ${this.sessionData.metrics.tokensSaved} tokens
|
|
1147
|
+
|
|
1148
|
+
## Swarm Activity
|
|
1149
|
+
- Active Agents: ${agentList.length} (${agentList.map(a => a.type).join(', ')})
|
|
1150
|
+
- Operations Performed: ${this.sessionData.operations.length}
|
|
1151
|
+
- Files Modified: ${new Set(this.sessionData.operations.map(o => o.file)).size}
|
|
1152
|
+
- Neural Improvements: ${this.sessionData.metrics.patternsImproved}
|
|
1153
|
+
|
|
1154
|
+
## Operations Breakdown
|
|
1155
|
+
${this.sessionData.operations.slice(-10).map(op =>
|
|
1156
|
+
`- ${new Date(op.timestamp).toLocaleTimeString()}: ${op.type} on ${op.file} (${op.agent})`,
|
|
1157
|
+
).join('\n')}
|
|
1158
|
+
|
|
1159
|
+
## Learning Highlights
|
|
1160
|
+
${this.sessionData.learnings.slice(-5).map(l =>
|
|
1161
|
+
`- Pattern "${l.pattern}" improved by ${(l.improvement * 100).toFixed(1)}% (confidence: ${l.confidence})`,
|
|
1162
|
+
).join('\n')}
|
|
1163
|
+
|
|
1164
|
+
## Performance Metrics
|
|
1165
|
+
- Average Operation Time: ${(duration / this.sessionData.operations.length / 1000).toFixed(1)}s
|
|
1166
|
+
- Token Efficiency: ${(this.sessionData.metrics.tokensSaved / this.sessionData.operations.length).toFixed(0)} tokens/operation
|
|
1167
|
+
- Learning Rate: ${(this.sessionData.metrics.patternsImproved / this.sessionData.operations.length).toFixed(2)} improvements/operation
|
|
1168
|
+
`;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
captureSwarmState() {
|
|
1172
|
+
return {
|
|
1173
|
+
session_id: `sess-${Date.now()}`,
|
|
1174
|
+
agents: Object.fromEntries(this.sessionData.agents),
|
|
1175
|
+
operations: this.sessionData.operations,
|
|
1176
|
+
learnings: this.sessionData.learnings,
|
|
1177
|
+
metrics: this.sessionData.metrics,
|
|
1178
|
+
timestamp: new Date().toISOString(),
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
calculateSessionMetrics() {
|
|
1183
|
+
const duration = Date.now() - this.sessionData.startTime;
|
|
1184
|
+
return {
|
|
1185
|
+
performance: {
|
|
1186
|
+
duration_ms: duration,
|
|
1187
|
+
operations_per_minute: (this.sessionData.operations.length / (duration / 60000)).toFixed(1),
|
|
1188
|
+
tokens_saved: this.sessionData.metrics.tokensSaved,
|
|
1189
|
+
efficiency_score: (this.sessionData.metrics.tokensSaved / this.sessionData.operations.length).toFixed(1),
|
|
1190
|
+
},
|
|
1191
|
+
learning: {
|
|
1192
|
+
patterns_improved: this.sessionData.metrics.patternsImproved,
|
|
1193
|
+
average_improvement: (this.sessionData.learnings.reduce((acc, l) => acc + l.improvement, 0) / this.sessionData.learnings.length).toFixed(3),
|
|
1194
|
+
confidence_average: (this.sessionData.learnings.reduce((acc, l) => acc + l.confidence, 0) / this.sessionData.learnings.length).toFixed(2),
|
|
1195
|
+
},
|
|
1196
|
+
agents: {
|
|
1197
|
+
total_spawned: this.sessionData.agents.size,
|
|
1198
|
+
by_type: Object.fromEntries(
|
|
1199
|
+
Array.from(this.sessionData.agents.values())
|
|
1200
|
+
.reduce((acc, agent) => {
|
|
1201
|
+
acc.set(agent.type, (acc.get(agent.type) || 0) + 1);
|
|
1202
|
+
return acc;
|
|
1203
|
+
}, new Map()),
|
|
1204
|
+
),
|
|
1205
|
+
},
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
formatDuration(ms) {
|
|
1210
|
+
const seconds = Math.floor(ms / 1000);
|
|
1211
|
+
const minutes = Math.floor(seconds / 60);
|
|
1212
|
+
const hours = Math.floor(minutes / 60);
|
|
1213
|
+
|
|
1214
|
+
if (hours > 0) {
|
|
1215
|
+
return `${hours}h ${minutes % 60}m`;
|
|
1216
|
+
} else if (minutes > 0) {
|
|
1217
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
1218
|
+
}
|
|
1219
|
+
return `${seconds}s`;
|
|
1220
|
+
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// Additional helper methods for optimization
|
|
1224
|
+
|
|
1225
|
+
analyzeTaskComplexity(description) {
|
|
1226
|
+
const keywords = {
|
|
1227
|
+
simple: ['fix', 'update', 'change', 'modify', 'rename'],
|
|
1228
|
+
medium: ['implement', 'create', 'add', 'integrate', 'refactor'],
|
|
1229
|
+
complex: ['architect', 'design', 'optimize', 'migrate', 'scale'],
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
const desc = description.toLowerCase();
|
|
1233
|
+
let complexity = 'simple';
|
|
1234
|
+
let score = 1;
|
|
1235
|
+
let estimatedMinutes = 5;
|
|
1236
|
+
|
|
1237
|
+
// Check for complex keywords
|
|
1238
|
+
if (keywords.complex.some(k => desc.includes(k))) {
|
|
1239
|
+
complexity = 'complex';
|
|
1240
|
+
score = 3;
|
|
1241
|
+
estimatedMinutes = 60;
|
|
1242
|
+
} else if (keywords.medium.some(k => desc.includes(k))) {
|
|
1243
|
+
complexity = 'medium';
|
|
1244
|
+
score = 2;
|
|
1245
|
+
estimatedMinutes = 30;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
// Adjust for multiple files or components
|
|
1249
|
+
const fileCount = (desc.match(/\b(files?|components?|modules?)\b/g) || []).length;
|
|
1250
|
+
if (fileCount > 1) {
|
|
1251
|
+
score += 0.5;
|
|
1252
|
+
estimatedMinutes *= 1.5;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
return {
|
|
1256
|
+
level: complexity,
|
|
1257
|
+
score,
|
|
1258
|
+
estimatedMinutes,
|
|
1259
|
+
requiresResearch: desc.includes('research') || desc.includes('analyze'),
|
|
1260
|
+
requiresTesting: desc.includes('test') || desc.includes('verify'),
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
selectOptimalTopology(complexity) {
|
|
1265
|
+
const topologyMap = {
|
|
1266
|
+
simple: 'star', // Centralized for simple tasks
|
|
1267
|
+
medium: 'mesh', // Flexible for medium complexity
|
|
1268
|
+
complex: 'hierarchical', // Structured for complex tasks
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
return topologyMap[complexity.level] || 'mesh';
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
determineRequiredAgents(description, complexity) {
|
|
1275
|
+
const agents = new Set(['coordinator']); // Always need a coordinator
|
|
1276
|
+
|
|
1277
|
+
const desc = description.toLowerCase();
|
|
1278
|
+
|
|
1279
|
+
// Add agents based on task keywords
|
|
1280
|
+
if (desc.includes('code') || desc.includes('implement') || desc.includes('fix')) {
|
|
1281
|
+
agents.add('coder');
|
|
1282
|
+
}
|
|
1283
|
+
if (desc.includes('research') || desc.includes('analyze') || desc.includes('investigate')) {
|
|
1284
|
+
agents.add('researcher');
|
|
1285
|
+
}
|
|
1286
|
+
if (desc.includes('data') || desc.includes('metrics') || desc.includes('performance')) {
|
|
1287
|
+
agents.add('analyst');
|
|
1288
|
+
}
|
|
1289
|
+
if (desc.includes('design') || desc.includes('architect') || desc.includes('structure')) {
|
|
1290
|
+
agents.add('architect');
|
|
1291
|
+
}
|
|
1292
|
+
if (desc.includes('optimize') || desc.includes('improve') || desc.includes('enhance')) {
|
|
1293
|
+
agents.add('optimizer');
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// Add more agents for complex tasks
|
|
1297
|
+
if (complexity.score >= 3) {
|
|
1298
|
+
agents.add('reviewer');
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
return Array.from(agents);
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
async updateKnowledgeGraph(file, operation) {
|
|
1305
|
+
if (!this.sessionData.knowledgeGraph) {
|
|
1306
|
+
this.sessionData.knowledgeGraph = {
|
|
1307
|
+
nodes: new Map(),
|
|
1308
|
+
edges: [],
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
const graph = this.sessionData.knowledgeGraph;
|
|
1313
|
+
|
|
1314
|
+
// Add or update node
|
|
1315
|
+
const nodeId = file;
|
|
1316
|
+
if (!graph.nodes.has(nodeId)) {
|
|
1317
|
+
graph.nodes.set(nodeId, {
|
|
1318
|
+
id: nodeId,
|
|
1319
|
+
type: this.getFileType(file),
|
|
1320
|
+
operations: [],
|
|
1321
|
+
lastModified: Date.now(),
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
const node = graph.nodes.get(nodeId);
|
|
1326
|
+
node.operations.push({
|
|
1327
|
+
type: operation,
|
|
1328
|
+
timestamp: Date.now(),
|
|
1329
|
+
agent: this.getCurrentAgent(),
|
|
1330
|
+
});
|
|
1331
|
+
node.lastModified = Date.now();
|
|
1332
|
+
|
|
1333
|
+
// Add edges for related files
|
|
1334
|
+
const relatedFiles = await this.findRelatedFiles(file);
|
|
1335
|
+
relatedFiles.forEach(related => {
|
|
1336
|
+
if (!graph.edges.find(e =>
|
|
1337
|
+
(e.from === nodeId && e.to === related) ||
|
|
1338
|
+
(e.from === related && e.to === nodeId),
|
|
1339
|
+
)) {
|
|
1340
|
+
graph.edges.push({
|
|
1341
|
+
from: nodeId,
|
|
1342
|
+
to: related,
|
|
1343
|
+
type: 'related',
|
|
1344
|
+
weight: 1,
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
calculateEfficiency(performance) {
|
|
1351
|
+
const baselineTime = 60000; // 1 minute baseline
|
|
1352
|
+
const efficiencyScore = Math.max(0, Math.min(1, baselineTime / performance.completionTime));
|
|
1353
|
+
|
|
1354
|
+
// Adjust for agent utilization
|
|
1355
|
+
const agentUtilization = performance.agentsUsed.length > 0 ?
|
|
1356
|
+
0.8 + (0.2 * Math.min(1, 3 / performance.agentsUsed.length)) : 0.5;
|
|
1357
|
+
|
|
1358
|
+
return {
|
|
1359
|
+
score: (efficiencyScore * agentUtilization).toFixed(2),
|
|
1360
|
+
timeEfficiency: efficiencyScore.toFixed(2),
|
|
1361
|
+
agentEfficiency: agentUtilization.toFixed(2),
|
|
1362
|
+
rating: efficiencyScore > 0.8 ? 'excellent' :
|
|
1363
|
+
efficiencyScore > 0.6 ? 'good' :
|
|
1364
|
+
efficiencyScore > 0.4 ? 'fair' : 'needs improvement',
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
identifyBottlenecks(performance) {
|
|
1369
|
+
const bottlenecks = [];
|
|
1370
|
+
|
|
1371
|
+
// Time-based bottlenecks
|
|
1372
|
+
if (performance.completionTime > 300000) { // > 5 minutes
|
|
1373
|
+
bottlenecks.push({
|
|
1374
|
+
type: 'time',
|
|
1375
|
+
severity: 'high',
|
|
1376
|
+
description: 'Task took longer than expected',
|
|
1377
|
+
recommendation: 'Consider breaking into smaller subtasks',
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
// Agent-based bottlenecks
|
|
1382
|
+
if (performance.agentsUsed.length === 1) {
|
|
1383
|
+
bottlenecks.push({
|
|
1384
|
+
type: 'coordination',
|
|
1385
|
+
severity: 'medium',
|
|
1386
|
+
description: 'Single agent used for complex task',
|
|
1387
|
+
recommendation: 'Spawn specialized agents for parallel work',
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// Resource bottlenecks
|
|
1392
|
+
if (this.sessionData.operations.length > 100) {
|
|
1393
|
+
bottlenecks.push({
|
|
1394
|
+
type: 'operations',
|
|
1395
|
+
severity: 'medium',
|
|
1396
|
+
description: 'High number of operations',
|
|
1397
|
+
recommendation: 'Optimize operation batching',
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
return bottlenecks;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
suggestImprovements(performance) {
|
|
1405
|
+
const improvements = [];
|
|
1406
|
+
const efficiency = this.calculateEfficiency(performance);
|
|
1407
|
+
|
|
1408
|
+
// Time improvements
|
|
1409
|
+
if (efficiency.timeEfficiency < 0.7) {
|
|
1410
|
+
improvements.push({
|
|
1411
|
+
area: 'execution_time',
|
|
1412
|
+
suggestion: 'Use parallel task execution',
|
|
1413
|
+
expectedImprovement: '30-50% time reduction',
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
// Coordination improvements
|
|
1418
|
+
if (efficiency.agentEfficiency < 0.8) {
|
|
1419
|
+
improvements.push({
|
|
1420
|
+
area: 'agent_coordination',
|
|
1421
|
+
suggestion: 'Implement specialized agent patterns',
|
|
1422
|
+
expectedImprovement: '20-30% efficiency gain',
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// Pattern improvements
|
|
1427
|
+
if (this.sessionData.learnings.length < 5) {
|
|
1428
|
+
improvements.push({
|
|
1429
|
+
area: 'learning',
|
|
1430
|
+
suggestion: 'Enable neural pattern training',
|
|
1431
|
+
expectedImprovement: 'Cumulative performance gains',
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
return improvements;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
updateCoordinationStrategy(performance) {
|
|
1439
|
+
const efficiency = this.calculateEfficiency(performance);
|
|
1440
|
+
|
|
1441
|
+
// Update strategy based on performance
|
|
1442
|
+
if (!this.sessionData.coordinationStrategy) {
|
|
1443
|
+
this.sessionData.coordinationStrategy = {
|
|
1444
|
+
current: 'balanced',
|
|
1445
|
+
history: [],
|
|
1446
|
+
adjustments: 0,
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
const strategy = this.sessionData.coordinationStrategy;
|
|
1451
|
+
strategy.history.push({
|
|
1452
|
+
timestamp: Date.now(),
|
|
1453
|
+
efficiency: efficiency.score,
|
|
1454
|
+
strategy: strategy.current,
|
|
1455
|
+
});
|
|
1456
|
+
|
|
1457
|
+
// Adjust strategy if needed
|
|
1458
|
+
if (parseFloat(efficiency.score) < 0.6) {
|
|
1459
|
+
strategy.current = 'adaptive';
|
|
1460
|
+
strategy.adjustments++;
|
|
1461
|
+
} else if (parseFloat(efficiency.score) > 0.9) {
|
|
1462
|
+
strategy.current = 'specialized';
|
|
1463
|
+
strategy.adjustments++;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
extractSearchPatterns(query) {
|
|
1468
|
+
const patterns = [];
|
|
1469
|
+
|
|
1470
|
+
// Extract file type patterns
|
|
1471
|
+
const fileTypes = query.match(/\.(js|ts|py|go|rs|md|json|yaml)\b/gi);
|
|
1472
|
+
if (fileTypes) {
|
|
1473
|
+
patterns.push(...fileTypes.map(ft => `filetype:${ft}`));
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// Extract function/class patterns
|
|
1477
|
+
const codePatterns = query.match(/\b(function|class|interface|struct|impl)\s+\w+/gi);
|
|
1478
|
+
if (codePatterns) {
|
|
1479
|
+
patterns.push(...codePatterns.map(cp => `code:${cp}`));
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
// Extract scope patterns
|
|
1483
|
+
const scopePatterns = query.match(/\b(src|test|lib|bin|docs?)\//gi);
|
|
1484
|
+
if (scopePatterns) {
|
|
1485
|
+
patterns.push(...scopePatterns.map(sp => `scope:${sp}`));
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
return patterns;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
async updateKnowledgeBase(type, data) {
|
|
1492
|
+
const kbPath = path.join(process.cwd(), '.@sparkleideas/ruv-swarm', 'knowledge-base.json');
|
|
1493
|
+
|
|
1494
|
+
// Load existing knowledge base
|
|
1495
|
+
let kb = {};
|
|
1496
|
+
try {
|
|
1497
|
+
if (await fs.access(kbPath).then(() => true).catch(() => false)) {
|
|
1498
|
+
kb = JSON.parse(await fs.readFile(kbPath, 'utf-8'));
|
|
1499
|
+
}
|
|
1500
|
+
} catch (_error) {
|
|
1501
|
+
kb = { searches: [], patterns: {}, insights: [] };
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// Update based on type
|
|
1505
|
+
if (type === 'search') {
|
|
1506
|
+
if (!kb.searches) {
|
|
1507
|
+
kb.searches = [];
|
|
1508
|
+
}
|
|
1509
|
+
kb.searches.push({
|
|
1510
|
+
query: data.query,
|
|
1511
|
+
patterns: data.patterns,
|
|
1512
|
+
timestamp: Date.now(),
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
// Update pattern frequency
|
|
1516
|
+
if (!kb.patterns) {
|
|
1517
|
+
kb.patterns = {};
|
|
1518
|
+
}
|
|
1519
|
+
data.patterns.forEach(pattern => {
|
|
1520
|
+
kb.patterns[pattern] = (kb.patterns[pattern] || 0) + 1;
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
// Keep only recent data
|
|
1525
|
+
if (kb.searches && kb.searches.length > 100) {
|
|
1526
|
+
kb.searches = kb.searches.slice(-100);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
// Save updated knowledge base
|
|
1530
|
+
await fs.mkdir(path.dirname(kbPath), { recursive: true });
|
|
1531
|
+
await fs.writeFile(kbPath, JSON.stringify(kb, null, 2));
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
extractUrlPatterns(url) {
|
|
1535
|
+
const patterns = [];
|
|
1536
|
+
|
|
1537
|
+
try {
|
|
1538
|
+
const urlObj = new URL(url);
|
|
1539
|
+
|
|
1540
|
+
// Domain pattern
|
|
1541
|
+
patterns.push(`domain:${urlObj.hostname}`);
|
|
1542
|
+
|
|
1543
|
+
// Path patterns
|
|
1544
|
+
const pathParts = urlObj.pathname.split('/').filter(p => p);
|
|
1545
|
+
if (pathParts.length > 0) {
|
|
1546
|
+
patterns.push(`path:/${pathParts[0]}`); // Top level path
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// Content type patterns
|
|
1550
|
+
if (urlObj.pathname.endsWith('.md')) {
|
|
1551
|
+
patterns.push('content:markdown');
|
|
1552
|
+
}
|
|
1553
|
+
if (urlObj.pathname.includes('docs')) {
|
|
1554
|
+
patterns.push('content:documentation');
|
|
1555
|
+
}
|
|
1556
|
+
if (urlObj.pathname.includes('api')) {
|
|
1557
|
+
patterns.push('content:api');
|
|
1558
|
+
}
|
|
1559
|
+
if (urlObj.pathname.includes('guide')) {
|
|
1560
|
+
patterns.push('content:guide');
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// Query patterns
|
|
1564
|
+
if (urlObj.search) {
|
|
1565
|
+
patterns.push('has:queryparams');
|
|
1566
|
+
}
|
|
1567
|
+
} catch (_error) {
|
|
1568
|
+
patterns.push('pattern:invalid-url');
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
return patterns;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
async getSwarmStatus() {
|
|
1575
|
+
try {
|
|
1576
|
+
const statusPath = path.join(process.cwd(), '.@sparkleideas/ruv-swarm', 'status.json');
|
|
1577
|
+
if (await fs.access(statusPath).then(() => true).catch(() => false)) {
|
|
1578
|
+
return JSON.parse(await fs.readFile(statusPath, 'utf-8'));
|
|
1579
|
+
}
|
|
1580
|
+
} catch (_error) {
|
|
1581
|
+
// Fallback to session data
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
return {
|
|
1585
|
+
agents: this.sessionData.agents,
|
|
1586
|
+
activeTasks: this.sessionData.operations.filter(op =>
|
|
1587
|
+
Date.now() - op.timestamp < 300000, // Last 5 minutes
|
|
1588
|
+
).length,
|
|
1589
|
+
health: 'operational',
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
sendTelemetry(event, data) {
|
|
1594
|
+
// In production, this would send to telemetry service
|
|
1595
|
+
// For now, just log to telemetry file
|
|
1596
|
+
const telemetryPath = path.join(process.cwd(), '.@sparkleideas/ruv-swarm', 'telemetry.jsonl');
|
|
1597
|
+
|
|
1598
|
+
const telemetryEvent = {
|
|
1599
|
+
event,
|
|
1600
|
+
data,
|
|
1601
|
+
timestamp: Date.now(),
|
|
1602
|
+
sessionId: this.sessionData.sessionId || 'unknown',
|
|
1603
|
+
version: '1.0.0',
|
|
1604
|
+
};
|
|
1605
|
+
|
|
1606
|
+
// Async write without blocking
|
|
1607
|
+
fs.appendFile(telemetryPath, `${JSON.stringify(telemetryEvent) }\n`).catch(() => { /* intentionally empty */ });
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// Helper methods for other functionality
|
|
1611
|
+
|
|
1612
|
+
getSpecializationForType(type) {
|
|
1613
|
+
const specializations = {
|
|
1614
|
+
researcher: ['literature-review', 'data-analysis', 'trend-identification'],
|
|
1615
|
+
coder: ['implementation', 'refactoring', 'optimization'],
|
|
1616
|
+
analyst: ['metrics', 'performance', 'data-visualization'],
|
|
1617
|
+
architect: ['system-design', 'api-design', 'database-schema'],
|
|
1618
|
+
coordinator: ['task-planning', 'resource-allocation', 'progress-tracking'],
|
|
1619
|
+
optimizer: ['performance-tuning', 'algorithm-optimization', 'resource-usage'],
|
|
1620
|
+
};
|
|
1621
|
+
return specializations[type] || ['general'];
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
generateSpecializationPatterns(type) {
|
|
1625
|
+
const patterns = {
|
|
1626
|
+
researcher: ['depth-first-search', 'breadth-first-search', 'citation-tracking'],
|
|
1627
|
+
coder: ['modular-design', 'error-handling', 'code-reuse'],
|
|
1628
|
+
analyst: ['statistical-analysis', 'trend-detection', 'anomaly-detection'],
|
|
1629
|
+
architect: ['layered-architecture', 'microservices', 'event-driven'],
|
|
1630
|
+
coordinator: ['dependency-tracking', 'parallel-execution', 'milestone-planning'],
|
|
1631
|
+
optimizer: ['bottleneck-identification', 'caching-strategies', 'lazy-loading'],
|
|
1632
|
+
};
|
|
1633
|
+
return patterns[type] || ['adaptive-learning'];
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
generateMockWeights() {
|
|
1637
|
+
// Generate mock neural network weights for demonstration
|
|
1638
|
+
return {
|
|
1639
|
+
layers: [
|
|
1640
|
+
{ neurons: 128, weights: Array(128).fill(0).map(() => Math.random() - 0.5) },
|
|
1641
|
+
{ neurons: 64, weights: Array(64).fill(0).map(() => Math.random() - 0.5) },
|
|
1642
|
+
{ neurons: 32, weights: Array(32).fill(0).map(() => Math.random() - 0.5) },
|
|
1643
|
+
],
|
|
1644
|
+
biases: Array(224).fill(0).map(() => Math.random() - 0.5),
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
optimizeAgentAllocation(_taskId) {
|
|
1649
|
+
// Simple load balancing algorithm
|
|
1650
|
+
const agents = Array.from(this.sessionData.agents.values());
|
|
1651
|
+
const allocation = {};
|
|
1652
|
+
|
|
1653
|
+
agents.forEach(agent => {
|
|
1654
|
+
// Allocate based on agent type and current load
|
|
1655
|
+
const load = this.sessionData.operations.filter(op =>
|
|
1656
|
+
op.agent === agent.id &&
|
|
1657
|
+
Date.now() - op.timestamp < 60000,
|
|
1658
|
+
).length;
|
|
1659
|
+
|
|
1660
|
+
allocation[agent.id] = {
|
|
1661
|
+
agent: agent.id,
|
|
1662
|
+
type: agent.type,
|
|
1663
|
+
currentLoad: load,
|
|
1664
|
+
capacity: Math.max(0, 10 - load), // Max 10 concurrent ops
|
|
1665
|
+
priority: load < 5 ? 'high' : 'normal',
|
|
1666
|
+
};
|
|
1667
|
+
});
|
|
1668
|
+
|
|
1669
|
+
return allocation;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
calculateParallelization(_taskId) {
|
|
1673
|
+
// Determine parallelization factor based on task and resources
|
|
1674
|
+
const agentCount = this.sessionData.agents.size;
|
|
1675
|
+
const complexity = this.sessionData.taskComplexity || { score: 2 };
|
|
1676
|
+
|
|
1677
|
+
return {
|
|
1678
|
+
factor: Math.min(agentCount, Math.ceil(complexity.score * 1.5)),
|
|
1679
|
+
strategy: agentCount > 3 ? 'distributed' : 'local',
|
|
1680
|
+
maxConcurrency: Math.min(agentCount * 2, 10),
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
getFileType(filePath) {
|
|
1685
|
+
const ext = path.extname(filePath);
|
|
1686
|
+
const typeMap = {
|
|
1687
|
+
'.js': 'javascript',
|
|
1688
|
+
'.ts': 'typescript',
|
|
1689
|
+
'.py': 'python',
|
|
1690
|
+
'.go': 'golang',
|
|
1691
|
+
'.rs': 'rust',
|
|
1692
|
+
'.json': 'config',
|
|
1693
|
+
'.yaml': 'config',
|
|
1694
|
+
'.yml': 'config',
|
|
1695
|
+
'.md': 'documentation',
|
|
1696
|
+
'.txt': 'text',
|
|
1697
|
+
};
|
|
1698
|
+
return typeMap[ext] || 'unknown';
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
getCurrentAgent() {
|
|
1702
|
+
// Get the most recently active agent
|
|
1703
|
+
const recentOps = this.sessionData.operations.slice(-10);
|
|
1704
|
+
const agentCounts = {};
|
|
1705
|
+
|
|
1706
|
+
recentOps.forEach(op => {
|
|
1707
|
+
if (op.agent) {
|
|
1708
|
+
agentCounts[op.agent] = (agentCounts[op.agent] || 0) + 1;
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
|
|
1712
|
+
const sorted = Object.entries(agentCounts).sort((a, b) => b[1] - a[1]);
|
|
1713
|
+
return sorted.length > 0 ? sorted[0][0] : 'coordinator';
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
async findRelatedFiles(filePath) {
|
|
1717
|
+
const related = [];
|
|
1718
|
+
const _baseName = path.basename(filePath, path.extname(filePath));
|
|
1719
|
+
// const dirName = path.dirname(filePath);
|
|
1720
|
+
|
|
1721
|
+
// Common related file patterns
|
|
1722
|
+
// const patterns = [
|
|
1723
|
+
// `${baseName}.test.*`, // Test files
|
|
1724
|
+
// `${baseName}.spec.*`, // Spec files
|
|
1725
|
+
// `test-${baseName}.*`, // Alternative test pattern
|
|
1726
|
+
// `${baseName}.d.ts`, // TypeScript definitions
|
|
1727
|
+
// `${baseName}.types.*`, // Type definitions
|
|
1728
|
+
// ];
|
|
1729
|
+
|
|
1730
|
+
// For now, return mock related files
|
|
1731
|
+
// In production, would use file system search
|
|
1732
|
+
if (filePath.endsWith('.js')) {
|
|
1733
|
+
related.push(filePath.replace('.js', '.test.js'));
|
|
1734
|
+
}
|
|
1735
|
+
if (filePath.endsWith('.ts')) {
|
|
1736
|
+
related.push(filePath.replace('.ts', '.test.ts'));
|
|
1737
|
+
related.push(filePath.replace('.ts', '.d.ts'));
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
return related.filter(f => f !== filePath);
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* 🔧 CRITICAL FIX: Store notification in database for cross-agent access
|
|
1745
|
+
*/
|
|
1746
|
+
async storeNotificationInDatabase(notification) {
|
|
1747
|
+
if (!this.persistence) {
|
|
1748
|
+
console.warn('⚠️ No persistence layer - notification stored in memory only');
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
try {
|
|
1753
|
+
// Store as agent memory with special hook prefix
|
|
1754
|
+
const agentId = notification.agentId || 'hook-system';
|
|
1755
|
+
const memoryKey = `notifications/${notification.type}/${Date.now()}`;
|
|
1756
|
+
|
|
1757
|
+
await this.persistence.storeAgentMemory(agentId, memoryKey, {
|
|
1758
|
+
type: notification.type,
|
|
1759
|
+
message: notification.message,
|
|
1760
|
+
context: notification.context,
|
|
1761
|
+
timestamp: notification.timestamp,
|
|
1762
|
+
source: 'hook-system',
|
|
1763
|
+
sessionId: this.getSessionId(),
|
|
1764
|
+
});
|
|
1765
|
+
|
|
1766
|
+
console.log(`📝 Notification stored in database: ${memoryKey}`);
|
|
1767
|
+
} catch (error) {
|
|
1768
|
+
console.error('❌ Failed to store notification in database:', error.message);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
/**
|
|
1773
|
+
* 🔧 CRITICAL FIX: Retrieve notifications from database for cross-agent access
|
|
1774
|
+
*/
|
|
1775
|
+
async getNotificationsFromDatabase(agentId = null, type = null) {
|
|
1776
|
+
if (!this.persistence) {
|
|
1777
|
+
return [];
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
try {
|
|
1781
|
+
const targetAgentId = agentId || 'hook-system';
|
|
1782
|
+
const memories = await this.persistence.getAllMemory(targetAgentId);
|
|
1783
|
+
|
|
1784
|
+
return memories
|
|
1785
|
+
.filter(memory => memory.key.startsWith('notifications/'))
|
|
1786
|
+
.filter(memory => !type || memory.value.type === type)
|
|
1787
|
+
.map(memory => memory.value)
|
|
1788
|
+
.sort((a, b) => b.timestamp - a.timestamp);
|
|
1789
|
+
} catch (error) {
|
|
1790
|
+
console.error('❌ Failed to retrieve notifications from database:', error.message);
|
|
1791
|
+
return [];
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* 🔧 CRITICAL FIX: Enhanced agent completion with database coordination
|
|
1797
|
+
*/
|
|
1798
|
+
async agentCompleteHook(args) {
|
|
1799
|
+
const { agentId, taskId, results, learnings } = args;
|
|
1800
|
+
|
|
1801
|
+
// Store completion in database for other agents to see
|
|
1802
|
+
if (this.persistence && agentId) {
|
|
1803
|
+
try {
|
|
1804
|
+
await this.persistence.storeAgentMemory(agentId, `completion/${taskId}`, {
|
|
1805
|
+
taskId,
|
|
1806
|
+
results,
|
|
1807
|
+
learnings,
|
|
1808
|
+
completedAt: Date.now(),
|
|
1809
|
+
source: 'agent-completion',
|
|
1810
|
+
});
|
|
1811
|
+
|
|
1812
|
+
// Update agent status in database
|
|
1813
|
+
await this.persistence.updateAgentStatus(agentId, 'completed');
|
|
1814
|
+
|
|
1815
|
+
console.log(`✅ Agent ${agentId} completion stored in database`);
|
|
1816
|
+
} catch (error) {
|
|
1817
|
+
console.error('❌ Failed to store agent completion:', error.message);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
// Store in runtime memory as before
|
|
1822
|
+
const agent = this.sessionData.agents.get(agentId);
|
|
1823
|
+
if (agent) {
|
|
1824
|
+
agent.lastCompletion = {
|
|
1825
|
+
taskId,
|
|
1826
|
+
results,
|
|
1827
|
+
learnings,
|
|
1828
|
+
timestamp: Date.now(),
|
|
1829
|
+
};
|
|
1830
|
+
agent.status = 'completed';
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
return {
|
|
1834
|
+
continue: true,
|
|
1835
|
+
stored: true,
|
|
1836
|
+
agent: agentId,
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/**
|
|
1841
|
+
* Get current session ID for coordination
|
|
1842
|
+
*/
|
|
1843
|
+
getSessionId() {
|
|
1844
|
+
if (!this._sessionId) {
|
|
1845
|
+
this._sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1846
|
+
}
|
|
1847
|
+
return this._sessionId;
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
/**
|
|
1851
|
+
* 🔧 CRITICAL FIX: Cross-agent memory retrieval for coordinated decisions
|
|
1852
|
+
*/
|
|
1853
|
+
async getSharedMemory(key, agentId = null) {
|
|
1854
|
+
// Check runtime memory first
|
|
1855
|
+
const runtimeValue = this.sessionData[key];
|
|
1856
|
+
|
|
1857
|
+
// Check database for persistent cross-agent memory
|
|
1858
|
+
if (this.persistence) {
|
|
1859
|
+
try {
|
|
1860
|
+
const targetAgentId = agentId || 'shared-memory';
|
|
1861
|
+
const memory = await this.persistence.getAgentMemory(targetAgentId, key);
|
|
1862
|
+
|
|
1863
|
+
if (memory) {
|
|
1864
|
+
console.log(`📖 Retrieved shared memory from database: ${key}`);
|
|
1865
|
+
return memory.value;
|
|
1866
|
+
}
|
|
1867
|
+
} catch (error) {
|
|
1868
|
+
console.error('❌ Failed to retrieve shared memory:', error.message);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
return runtimeValue;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
/**
|
|
1876
|
+
* 🔧 CRITICAL FIX: Cross-agent memory storage for coordinated decisions
|
|
1877
|
+
*/
|
|
1878
|
+
async setSharedMemory(key, value, agentId = null) {
|
|
1879
|
+
// Store in runtime memory
|
|
1880
|
+
this.sessionData[key] = value;
|
|
1881
|
+
|
|
1882
|
+
// Store in database for cross-agent access
|
|
1883
|
+
if (this.persistence) {
|
|
1884
|
+
try {
|
|
1885
|
+
const targetAgentId = agentId || 'shared-memory';
|
|
1886
|
+
await this.persistence.storeAgentMemory(targetAgentId, key, value);
|
|
1887
|
+
console.log(`📝 Stored shared memory in database: ${key}`);
|
|
1888
|
+
} catch (error) {
|
|
1889
|
+
console.error('❌ Failed to store shared memory:', error.message);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// Export singleton instance and its methods
|
|
1896
|
+
const hooksInstance = new RuvSwarmHooks();
|
|
1897
|
+
|
|
1898
|
+
export const handleHook = (hookType, options) => hooksInstance.handleHook(hookType, options);
|
|
1899
|
+
|
|
1900
|
+
export default hooksInstance;
|