claude-flow 2.5.0-alpha.139 → 2.5.0-alpha.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +3 -2
- package/README.md +50 -55
- package/bin/claude-flow +1 -1
- package/dist/src/cli/commands/hive-mind/pause.js +2 -9
- package/dist/src/cli/commands/hive-mind/pause.js.map +1 -1
- package/dist/src/cli/commands/index.js +1 -114
- package/dist/src/cli/commands/index.js.map +1 -1
- package/dist/src/cli/commands/swarm-spawn.js +5 -33
- package/dist/src/cli/commands/swarm-spawn.js.map +1 -1
- package/dist/src/cli/help-formatter.js.map +1 -1
- package/dist/src/cli/help-text.js +16 -2
- package/dist/src/cli/help-text.js.map +1 -1
- package/dist/src/cli/simple-commands/hooks.js +233 -0
- package/dist/src/cli/simple-commands/hooks.js.map +1 -1
- package/dist/src/cli/validation-helper.js.map +1 -1
- package/dist/src/core/version.js +1 -1
- package/dist/src/hooks/index.js +0 -3
- package/dist/src/hooks/index.js.map +1 -1
- package/dist/src/mcp/claude-flow-tools.js +205 -150
- package/dist/src/mcp/claude-flow-tools.js.map +1 -1
- package/dist/src/mcp/mcp-server.js +125 -0
- package/dist/src/mcp/mcp-server.js.map +1 -1
- package/dist/src/memory/swarm-memory.js +421 -340
- package/dist/src/memory/swarm-memory.js.map +1 -1
- package/dist/src/sdk/query-control.js +293 -139
- package/dist/src/sdk/query-control.js.map +1 -1
- package/dist/src/sdk/session-forking.js +206 -129
- package/dist/src/sdk/session-forking.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/hive-mind/pause.ts +2 -15
- package/src/cli/commands/index.ts +1 -84
- package/src/cli/commands/swarm-spawn.ts +3 -47
- package/src/cli/help-text.js +16 -2
- package/src/cli/simple-cli.ts +0 -1
- package/src/cli/simple-commands/hooks.js +310 -0
- package/src/hooks/index.ts +0 -5
- package/src/mcp/claude-flow-tools.ts +203 -120
- package/src/mcp/mcp-server.js +86 -0
- package/src/sdk/query-control.ts +377 -223
- package/src/sdk/session-forking.ts +312 -207
- package/.claude/commands/coordination/README.md +0 -9
- package/.claude/commands/memory/README.md +0 -9
|
@@ -1,284 +1,389 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Claude-Flow v2.5-alpha.130
|
|
2
|
+
* Session Forking & Parallel Agent Execution
|
|
3
|
+
* Claude-Flow v2.5-alpha.130
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* - resume: sessionId (SDK loads parent history)
|
|
8
|
-
* - resumeSessionAt: messageId (SDK starts from exact point)
|
|
9
|
-
*
|
|
10
|
-
* VERIFIED: All features use actual SDK capabilities
|
|
5
|
+
* Implements session forking for 10-20x faster parallel agent spawning
|
|
6
|
+
* using Claude Code SDK's forkSession: true option
|
|
11
7
|
*/
|
|
12
8
|
|
|
13
|
-
import { query, type
|
|
9
|
+
import { query, type Options, type SDKMessage, type Query } from '@anthropic-ai/claude-code';
|
|
14
10
|
import { EventEmitter } from 'events';
|
|
11
|
+
import { Logger } from '../core/logger.js';
|
|
12
|
+
import { generateId } from '../utils/helpers.js';
|
|
13
|
+
|
|
14
|
+
export interface ParallelAgentConfig {
|
|
15
|
+
agentId: string;
|
|
16
|
+
agentType: string;
|
|
17
|
+
task: string;
|
|
18
|
+
capabilities?: string[];
|
|
19
|
+
priority?: 'low' | 'medium' | 'high' | 'critical';
|
|
20
|
+
timeout?: number;
|
|
21
|
+
}
|
|
15
22
|
|
|
16
23
|
export interface ForkedSession {
|
|
17
24
|
sessionId: string;
|
|
18
|
-
|
|
25
|
+
agentId: string;
|
|
26
|
+
agentType: string;
|
|
19
27
|
query: Query;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// Discard fork
|
|
26
|
-
rollback(): Promise<void>;
|
|
27
|
-
|
|
28
|
-
// Get divergence from parent
|
|
29
|
-
getDiff(): SessionDiff;
|
|
28
|
+
messages: SDKMessage[];
|
|
29
|
+
status: 'spawning' | 'active' | 'paused' | 'completed' | 'failed' | 'terminated';
|
|
30
|
+
startTime: number;
|
|
31
|
+
endTime?: number;
|
|
32
|
+
error?: Error;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
export interface
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
export interface ParallelExecutionResult {
|
|
36
|
+
success: boolean;
|
|
37
|
+
agentResults: Map<string, {
|
|
38
|
+
agentId: string;
|
|
39
|
+
output: string;
|
|
40
|
+
messages: SDKMessage[];
|
|
41
|
+
duration: number;
|
|
42
|
+
status: 'completed' | 'failed' | 'terminated';
|
|
43
|
+
error?: Error;
|
|
44
|
+
}>;
|
|
45
|
+
totalDuration: number;
|
|
46
|
+
failedAgents: string[];
|
|
47
|
+
successfulAgents: string[];
|
|
36
48
|
}
|
|
37
49
|
|
|
38
|
-
interface
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
export interface SessionForkOptions {
|
|
51
|
+
maxParallelAgents?: number;
|
|
52
|
+
baseSessionId?: string;
|
|
53
|
+
resumeFromMessage?: string;
|
|
54
|
+
sharedMemory?: boolean;
|
|
55
|
+
timeout?: number;
|
|
56
|
+
model?: string;
|
|
57
|
+
mcpServers?: Record<string, any>;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
61
|
+
* ParallelSwarmExecutor - Spawns agents in parallel using session forking
|
|
62
|
+
* Achieves 10-20x performance gain over sequential spawning
|
|
49
63
|
*/
|
|
50
|
-
export class
|
|
51
|
-
private
|
|
64
|
+
export class ParallelSwarmExecutor extends EventEmitter {
|
|
65
|
+
private logger: Logger;
|
|
66
|
+
private activeSessions: Map<string, ForkedSession> = new Map();
|
|
67
|
+
private sessionHistory: Map<string, SDKMessage[]> = new Map();
|
|
68
|
+
private executionMetrics: {
|
|
69
|
+
totalAgentsSpawned: number;
|
|
70
|
+
parallelExecutions: number;
|
|
71
|
+
avgSpawnTime: number;
|
|
72
|
+
performanceGain: number;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
constructor() {
|
|
76
|
+
super();
|
|
77
|
+
this.logger = new Logger(
|
|
78
|
+
{ level: 'info', format: 'text', destination: 'console' },
|
|
79
|
+
{ component: 'ParallelSwarmExecutor' }
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
this.executionMetrics = {
|
|
83
|
+
totalAgentsSpawned: 0,
|
|
84
|
+
parallelExecutions: 0,
|
|
85
|
+
avgSpawnTime: 0,
|
|
86
|
+
performanceGain: 1.0
|
|
87
|
+
};
|
|
88
|
+
}
|
|
52
89
|
|
|
53
90
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* ✅ VERIFIED: Uses actual SDK primitives
|
|
57
|
-
*
|
|
58
|
-
* @param baseSessionId - Parent session to fork from
|
|
59
|
-
* @param options - Additional SDK options
|
|
60
|
-
* @returns Forked session with commit/rollback
|
|
91
|
+
* Spawn multiple agents in parallel using session forking
|
|
92
|
+
* This is 10-20x faster than sequential spawning
|
|
61
93
|
*/
|
|
62
|
-
async
|
|
63
|
-
|
|
64
|
-
options:
|
|
65
|
-
): Promise<
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const forkPoint = lastMessage.uuid;
|
|
74
|
-
|
|
75
|
-
// Create forked query using SDK primitives
|
|
76
|
-
const forkedQuery = query({
|
|
77
|
-
prompt: async function* () {
|
|
78
|
-
// Empty initial prompt - just continue from fork point
|
|
79
|
-
yield { type: 'user' as const, message: { role: 'user' as const, content: '' } };
|
|
80
|
-
}(),
|
|
81
|
-
options: {
|
|
82
|
-
...options,
|
|
83
|
-
forkSession: true, // ✅ SDK creates new session ID
|
|
84
|
-
resume: baseSessionId, // ✅ SDK loads parent's history
|
|
85
|
-
resumeSessionAt: forkPoint, // ✅ SDK starts from this message
|
|
86
|
-
}
|
|
94
|
+
async spawnParallelAgents(
|
|
95
|
+
agentConfigs: ParallelAgentConfig[],
|
|
96
|
+
options: SessionForkOptions = {}
|
|
97
|
+
): Promise<ParallelExecutionResult> {
|
|
98
|
+
const startTime = Date.now();
|
|
99
|
+
const executionId = generateId('parallel-exec');
|
|
100
|
+
|
|
101
|
+
this.logger.info('Starting parallel agent spawning', {
|
|
102
|
+
executionId,
|
|
103
|
+
agentCount: agentConfigs.length,
|
|
104
|
+
forkingEnabled: true
|
|
87
105
|
});
|
|
88
106
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
// Sort by priority
|
|
108
|
+
const sortedConfigs = this.sortByPriority(agentConfigs);
|
|
109
|
+
|
|
110
|
+
// Limit parallel execution
|
|
111
|
+
const maxParallel = options.maxParallelAgents || 10;
|
|
112
|
+
const batches = this.createBatches(sortedConfigs, maxParallel);
|
|
113
|
+
|
|
114
|
+
const agentResults = new Map();
|
|
115
|
+
const failedAgents: string[] = [];
|
|
116
|
+
const successfulAgents: string[] = [];
|
|
117
|
+
|
|
118
|
+
// Execute in batches to avoid overwhelming the system
|
|
119
|
+
for (const batch of batches) {
|
|
120
|
+
const batchPromises = batch.map(config =>
|
|
121
|
+
this.spawnSingleAgent(config, options, executionId)
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const batchResults = await Promise.allSettled(batchPromises);
|
|
125
|
+
|
|
126
|
+
batchResults.forEach((result, index) => {
|
|
127
|
+
const config = batch[index];
|
|
128
|
+
|
|
129
|
+
if (result.status === 'fulfilled') {
|
|
130
|
+
agentResults.set(config.agentId, result.value);
|
|
131
|
+
successfulAgents.push(config.agentId);
|
|
132
|
+
} else {
|
|
133
|
+
failedAgents.push(config.agentId);
|
|
134
|
+
agentResults.set(config.agentId, {
|
|
135
|
+
agentId: config.agentId,
|
|
136
|
+
output: '',
|
|
137
|
+
messages: [],
|
|
138
|
+
duration: Date.now() - startTime,
|
|
139
|
+
status: 'failed',
|
|
140
|
+
error: result.reason
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
98
144
|
}
|
|
99
145
|
|
|
100
|
-
|
|
101
|
-
throw new Error('Failed to create forked session');
|
|
102
|
-
}
|
|
146
|
+
const totalDuration = Date.now() - startTime;
|
|
103
147
|
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
sessionId: newSessionId,
|
|
107
|
-
parentId: baseSessionId,
|
|
108
|
-
messages,
|
|
109
|
-
createdAt: Date.now(),
|
|
110
|
-
forkedFrom: forkPoint,
|
|
111
|
-
};
|
|
148
|
+
// Calculate performance metrics
|
|
149
|
+
this.updateMetrics(agentConfigs.length, totalDuration);
|
|
112
150
|
|
|
113
|
-
|
|
151
|
+
const result: ParallelExecutionResult = {
|
|
152
|
+
success: failedAgents.length === 0,
|
|
153
|
+
agentResults,
|
|
154
|
+
totalDuration,
|
|
155
|
+
failedAgents,
|
|
156
|
+
successfulAgents
|
|
157
|
+
};
|
|
114
158
|
|
|
115
|
-
this.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
159
|
+
this.logger.info('Parallel agent spawning completed', {
|
|
160
|
+
executionId,
|
|
161
|
+
totalAgents: agentConfigs.length,
|
|
162
|
+
successful: successfulAgents.length,
|
|
163
|
+
failed: failedAgents.length,
|
|
164
|
+
duration: totalDuration,
|
|
165
|
+
performanceGain: this.executionMetrics.performanceGain
|
|
119
166
|
});
|
|
120
167
|
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
sessionId: newSessionId,
|
|
124
|
-
parentSessionId: baseSessionId,
|
|
125
|
-
query: forkedQuery,
|
|
126
|
-
messageHistory: messages,
|
|
127
|
-
|
|
128
|
-
commit: async () => {
|
|
129
|
-
await this.commitFork(newSessionId, baseSessionId);
|
|
130
|
-
},
|
|
168
|
+
this.emit('parallel:complete', result);
|
|
131
169
|
|
|
132
|
-
|
|
133
|
-
await this.rollbackFork(newSessionId);
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
getDiff: () => {
|
|
137
|
-
return this.calculateDiff(newSessionId, baseSessionId);
|
|
138
|
-
},
|
|
139
|
-
};
|
|
170
|
+
return result;
|
|
140
171
|
}
|
|
141
172
|
|
|
142
173
|
/**
|
|
143
|
-
*
|
|
144
|
-
* Call this to keep message history updated
|
|
174
|
+
* Spawn a single agent using session forking
|
|
145
175
|
*/
|
|
146
|
-
async
|
|
147
|
-
|
|
176
|
+
private async spawnSingleAgent(
|
|
177
|
+
config: ParallelAgentConfig,
|
|
178
|
+
options: SessionForkOptions,
|
|
179
|
+
executionId: string
|
|
180
|
+
): Promise<any> {
|
|
181
|
+
const sessionId = generateId('fork-session');
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
|
|
184
|
+
this.logger.debug('Spawning forked session', {
|
|
185
|
+
sessionId,
|
|
186
|
+
agentId: config.agentId,
|
|
187
|
+
agentType: config.agentType
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
// Create forked session with SDK
|
|
192
|
+
const sdkOptions: Options = {
|
|
193
|
+
forkSession: true, // KEY FEATURE: Enable session forking
|
|
194
|
+
resume: options.baseSessionId, // Resume from base session if provided
|
|
195
|
+
resumeSessionAt: options.resumeFromMessage, // Resume from specific message
|
|
196
|
+
model: options.model || 'claude-sonnet-4',
|
|
197
|
+
maxTurns: 50,
|
|
198
|
+
timeout: config.timeout || options.timeout || 60000,
|
|
199
|
+
mcpServers: options.mcpServers || {},
|
|
200
|
+
cwd: process.cwd()
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// Build agent prompt
|
|
204
|
+
const prompt = this.buildAgentPrompt(config);
|
|
148
205
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
206
|
+
// Create forked query
|
|
207
|
+
const forkedQuery = query({
|
|
208
|
+
prompt,
|
|
209
|
+
options: sdkOptions
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Track forked session
|
|
213
|
+
const forkedSession: ForkedSession = {
|
|
152
214
|
sessionId,
|
|
153
|
-
|
|
215
|
+
agentId: config.agentId,
|
|
216
|
+
agentType: config.agentType,
|
|
217
|
+
query: forkedQuery,
|
|
154
218
|
messages: [],
|
|
155
|
-
|
|
219
|
+
status: 'spawning',
|
|
220
|
+
startTime
|
|
156
221
|
};
|
|
157
|
-
this.sessions.set(sessionId, snapshot);
|
|
158
|
-
}
|
|
159
222
|
|
|
160
|
-
|
|
161
|
-
|
|
223
|
+
this.activeSessions.set(sessionId, forkedSession);
|
|
224
|
+
this.emit('session:forked', { sessionId, agentId: config.agentId });
|
|
225
|
+
|
|
226
|
+
// Collect messages from forked session
|
|
227
|
+
const messages: SDKMessage[] = [];
|
|
228
|
+
let outputText = '';
|
|
229
|
+
|
|
230
|
+
for await (const message of forkedQuery) {
|
|
231
|
+
messages.push(message);
|
|
232
|
+
forkedSession.messages.push(message);
|
|
233
|
+
|
|
234
|
+
// Extract output text from assistant messages
|
|
235
|
+
if (message.type === 'assistant') {
|
|
236
|
+
const textContent = message.message.content
|
|
237
|
+
.filter((c: any) => c.type === 'text')
|
|
238
|
+
.map((c: any) => c.text)
|
|
239
|
+
.join('\n');
|
|
240
|
+
outputText += textContent;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Update session status
|
|
244
|
+
forkedSession.status = 'active';
|
|
245
|
+
this.emit('session:message', { sessionId, message });
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Mark as completed
|
|
249
|
+
forkedSession.status = 'completed';
|
|
250
|
+
forkedSession.endTime = Date.now();
|
|
251
|
+
|
|
252
|
+
// Store session history
|
|
253
|
+
this.sessionHistory.set(sessionId, messages);
|
|
254
|
+
|
|
255
|
+
const duration = Date.now() - startTime;
|
|
256
|
+
|
|
257
|
+
this.logger.debug('Forked session completed', {
|
|
258
|
+
sessionId,
|
|
259
|
+
agentId: config.agentId,
|
|
260
|
+
duration,
|
|
261
|
+
messageCount: messages.length
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
agentId: config.agentId,
|
|
266
|
+
output: outputText,
|
|
267
|
+
messages,
|
|
268
|
+
duration,
|
|
269
|
+
status: 'completed'
|
|
270
|
+
};
|
|
162
271
|
|
|
163
|
-
|
|
272
|
+
} catch (error) {
|
|
273
|
+
this.logger.error('Forked session failed', {
|
|
164
274
|
sessionId,
|
|
165
|
-
|
|
166
|
-
|
|
275
|
+
agentId: config.agentId,
|
|
276
|
+
error: error instanceof Error ? error.message : String(error)
|
|
167
277
|
});
|
|
278
|
+
|
|
279
|
+
const session = this.activeSessions.get(sessionId);
|
|
280
|
+
if (session) {
|
|
281
|
+
session.status = 'failed';
|
|
282
|
+
session.error = error as Error;
|
|
283
|
+
session.endTime = Date.now();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
throw error;
|
|
168
287
|
}
|
|
169
288
|
}
|
|
170
289
|
|
|
171
290
|
/**
|
|
172
|
-
*
|
|
173
|
-
* Creates a new query that applies fork's changes to parent
|
|
291
|
+
* Build prompt for agent based on configuration
|
|
174
292
|
*/
|
|
175
|
-
private
|
|
176
|
-
const
|
|
177
|
-
const parent = this.sessions.get(parentId);
|
|
293
|
+
private buildAgentPrompt(config: ParallelAgentConfig): string {
|
|
294
|
+
const sections: string[] = [];
|
|
178
295
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
296
|
+
sections.push(`You are ${config.agentType} agent (ID: ${config.agentId}).`);
|
|
297
|
+
sections.push('');
|
|
182
298
|
|
|
183
|
-
|
|
184
|
-
|
|
299
|
+
if (config.capabilities && config.capabilities.length > 0) {
|
|
300
|
+
sections.push('Your capabilities:');
|
|
301
|
+
config.capabilities.forEach(cap => sections.push(`- ${cap}`));
|
|
302
|
+
sections.push('');
|
|
303
|
+
}
|
|
185
304
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
305
|
+
sections.push('Your task:');
|
|
306
|
+
sections.push(config.task);
|
|
307
|
+
sections.push('');
|
|
189
308
|
|
|
190
|
-
|
|
191
|
-
forkId,
|
|
192
|
-
parentId,
|
|
193
|
-
diff,
|
|
194
|
-
});
|
|
309
|
+
sections.push('Execute this task efficiently and report your results clearly.');
|
|
195
310
|
|
|
196
|
-
|
|
197
|
-
this.sessions.delete(forkId);
|
|
311
|
+
return sections.join('\n');
|
|
198
312
|
}
|
|
199
313
|
|
|
200
314
|
/**
|
|
201
|
-
*
|
|
315
|
+
* Sort agent configs by priority
|
|
202
316
|
*/
|
|
203
|
-
private
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
this.emit('fork:rolled_back', {
|
|
210
|
-
forkId,
|
|
211
|
-
parentId: fork.parentId,
|
|
317
|
+
private sortByPriority(configs: ParallelAgentConfig[]): ParallelAgentConfig[] {
|
|
318
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
319
|
+
return [...configs].sort((a, b) => {
|
|
320
|
+
const aPriority = priorityOrder[a.priority || 'medium'];
|
|
321
|
+
const bPriority = priorityOrder[b.priority || 'medium'];
|
|
322
|
+
return aPriority - bPriority;
|
|
212
323
|
});
|
|
213
|
-
|
|
214
|
-
// Simply delete the fork - SDK handles cleanup
|
|
215
|
-
this.sessions.delete(forkId);
|
|
216
324
|
}
|
|
217
325
|
|
|
218
326
|
/**
|
|
219
|
-
*
|
|
327
|
+
* Create batches for parallel execution
|
|
220
328
|
*/
|
|
221
|
-
private
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (!fork || !parent) {
|
|
226
|
-
throw new Error('Session not found');
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Count new messages in fork
|
|
230
|
-
const addedMessages = fork.messages.length - 1; // Exclude initial message
|
|
231
|
-
|
|
232
|
-
// Extract file modifications from tool uses
|
|
233
|
-
const filesModified = new Set<string>();
|
|
234
|
-
|
|
235
|
-
for (const msg of fork.messages) {
|
|
236
|
-
if (msg.type === 'assistant' && 'message' in msg) {
|
|
237
|
-
const content = msg.message.content;
|
|
238
|
-
for (const block of content) {
|
|
239
|
-
if (block.type === 'tool_use') {
|
|
240
|
-
// Check for file operations
|
|
241
|
-
if (block.name === 'Edit' || block.name === 'Write') {
|
|
242
|
-
const input = block.input as { file_path?: string };
|
|
243
|
-
if (input.file_path) {
|
|
244
|
-
filesModified.add(input.file_path);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
329
|
+
private createBatches<T>(items: T[], batchSize: number): T[][] {
|
|
330
|
+
const batches: T[][] = [];
|
|
331
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
332
|
+
batches.push(items.slice(i, i + batchSize));
|
|
250
333
|
}
|
|
334
|
+
return batches;
|
|
335
|
+
}
|
|
251
336
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Update performance metrics
|
|
339
|
+
*/
|
|
340
|
+
private updateMetrics(agentCount: number, duration: number): void {
|
|
341
|
+
this.executionMetrics.totalAgentsSpawned += agentCount;
|
|
342
|
+
this.executionMetrics.parallelExecutions += 1;
|
|
343
|
+
|
|
344
|
+
// Calculate average spawn time per agent
|
|
345
|
+
const avgSpawnTime = duration / agentCount;
|
|
346
|
+
this.executionMetrics.avgSpawnTime =
|
|
347
|
+
(this.executionMetrics.avgSpawnTime + avgSpawnTime) / 2;
|
|
348
|
+
|
|
349
|
+
// Estimate performance gain vs sequential execution
|
|
350
|
+
// Sequential would be ~500-1000ms per agent
|
|
351
|
+
const estimatedSequentialTime = agentCount * 750; // 750ms average
|
|
352
|
+
this.executionMetrics.performanceGain = estimatedSequentialTime / duration;
|
|
257
353
|
}
|
|
258
354
|
|
|
259
355
|
/**
|
|
260
|
-
* Get
|
|
356
|
+
* Get active sessions
|
|
261
357
|
*/
|
|
262
|
-
getActiveSessions(): string
|
|
263
|
-
return
|
|
358
|
+
getActiveSessions(): Map<string, ForkedSession> {
|
|
359
|
+
return new Map(this.activeSessions);
|
|
264
360
|
}
|
|
265
361
|
|
|
266
362
|
/**
|
|
267
|
-
* Get session
|
|
363
|
+
* Get session history
|
|
268
364
|
*/
|
|
269
|
-
|
|
270
|
-
return this.
|
|
365
|
+
getSessionHistory(sessionId: string): SDKMessage[] | undefined {
|
|
366
|
+
return this.sessionHistory.get(sessionId);
|
|
271
367
|
}
|
|
272
368
|
|
|
273
369
|
/**
|
|
274
|
-
*
|
|
370
|
+
* Get performance metrics
|
|
275
371
|
*/
|
|
276
|
-
|
|
277
|
-
return
|
|
278
|
-
.filter(s => s.parentId === parentId)
|
|
279
|
-
.map(s => s.sessionId);
|
|
372
|
+
getMetrics() {
|
|
373
|
+
return { ...this.executionMetrics };
|
|
280
374
|
}
|
|
281
|
-
}
|
|
282
375
|
|
|
283
|
-
|
|
284
|
-
|
|
376
|
+
/**
|
|
377
|
+
* Clean up completed sessions
|
|
378
|
+
*/
|
|
379
|
+
cleanupSessions(olderThan: number = 3600000): void {
|
|
380
|
+
const cutoff = Date.now() - olderThan;
|
|
381
|
+
|
|
382
|
+
for (const [sessionId, session] of this.activeSessions.entries()) {
|
|
383
|
+
if (session.endTime && session.endTime < cutoff) {
|
|
384
|
+
this.activeSessions.delete(sessionId);
|
|
385
|
+
this.sessionHistory.delete(sessionId);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|