sam-coder-cli 1.0.29 → 1.0.31
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/bin/multiplayer-client.js +24 -18
- package/bin/multiplayer-server.js +47 -37
- package/package.json +1 -1
|
@@ -779,44 +779,50 @@ class MultiplayerClient extends EventEmitter {
|
|
|
779
779
|
if (!sessionId) {
|
|
780
780
|
throw new Error('Session ID is required');
|
|
781
781
|
}
|
|
782
|
-
|
|
783
782
|
if (!this.connected) {
|
|
784
|
-
|
|
785
|
-
await this.connect();
|
|
786
|
-
} catch (error) {
|
|
787
|
-
throw new Error(`Failed to connect to server: ${error.message}`);
|
|
788
|
-
}
|
|
783
|
+
await this.connect();
|
|
789
784
|
}
|
|
790
785
|
|
|
791
786
|
return new Promise((resolve, reject) => {
|
|
792
|
-
this.
|
|
793
|
-
|
|
787
|
+
if (!this.ws) {
|
|
788
|
+
reject(new Error('Not connected to server'));
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
const timeout = setTimeout(() => {
|
|
793
|
+
this.off('session_joined', onSessionJoined);
|
|
794
|
+
this.off('error', onError);
|
|
795
|
+
reject(new Error('Session join timed out'));
|
|
796
|
+
}, 10000); // 10 second timeout
|
|
794
797
|
|
|
795
798
|
const onSessionJoined = (data) => {
|
|
796
|
-
if (data.sessionId ===
|
|
799
|
+
if (data.sessionId === sessionId) {
|
|
800
|
+
clearTimeout(timeout);
|
|
801
|
+
this.sessionId = sessionId;
|
|
802
|
+
this.isHost = data.isHost || false;
|
|
803
|
+
this.emit('session_joined', data);
|
|
797
804
|
this.off('session_joined', onSessionJoined);
|
|
798
805
|
this.off('error', onError);
|
|
799
|
-
resolve();
|
|
806
|
+
resolve(data);
|
|
800
807
|
}
|
|
801
808
|
};
|
|
802
809
|
|
|
803
810
|
const onError = (error) => {
|
|
811
|
+
clearTimeout(timeout);
|
|
804
812
|
this.off('session_joined', onSessionJoined);
|
|
805
813
|
this.off('error', onError);
|
|
806
814
|
reject(error);
|
|
807
815
|
};
|
|
808
816
|
|
|
809
|
-
this.
|
|
810
|
-
this.
|
|
817
|
+
this.on('session_joined', onSessionJoined);
|
|
818
|
+
this.on('error', onError);
|
|
811
819
|
|
|
812
820
|
this.send({
|
|
813
821
|
type: 'join_session',
|
|
814
|
-
sessionId:
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
model: this.model
|
|
819
|
-
}
|
|
822
|
+
sessionId: sessionId,
|
|
823
|
+
clientId: this.clientId,
|
|
824
|
+
name: this.name,
|
|
825
|
+
role: this.role
|
|
820
826
|
});
|
|
821
827
|
});
|
|
822
828
|
}
|
|
@@ -263,17 +263,23 @@ class MultiplayerServer {
|
|
|
263
263
|
handleJoinSession(ws, data) {
|
|
264
264
|
const { sessionId } = data;
|
|
265
265
|
const clientId = data.clientId || uuid.v4();
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (!
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
266
|
+
|
|
267
|
+
// If session doesn't exist, create it (this allows for reconnection)
|
|
268
|
+
if (!this.sessions.has(sessionId)) {
|
|
269
|
+
console.log(`Session ${sessionId} not found, creating new session`);
|
|
270
|
+
this.sessions.set(sessionId, {
|
|
271
|
+
id: sessionId,
|
|
272
|
+
clients: {},
|
|
273
|
+
createdAt: new Date().toISOString(),
|
|
274
|
+
hostId: clientId, // First joiner becomes host if session didn't exist
|
|
275
|
+
tasks: []
|
|
276
|
+
});
|
|
274
277
|
}
|
|
275
278
|
|
|
276
|
-
|
|
279
|
+
const session = this.sessions.get(sessionId);
|
|
280
|
+
|
|
281
|
+
// Check if session is full (max 4 agents)
|
|
282
|
+
if (Object.keys(session.clients).length >= 4 && !session.clients[clientId]) {
|
|
277
283
|
ws.send(JSON.stringify({
|
|
278
284
|
type: 'error',
|
|
279
285
|
message: 'Session is full (max 4 agents)'
|
|
@@ -292,45 +298,37 @@ class MultiplayerServer {
|
|
|
292
298
|
isHost: session.hostId === clientId,
|
|
293
299
|
name: data.name || existingClient?.name || `Agent-${clientId.substr(0, 4)}`,
|
|
294
300
|
role: data.role || existingClient?.role || 'Assistant',
|
|
295
|
-
model: data.model || existingClient?.model || 'default'
|
|
301
|
+
model: data.model || existingClient?.model || 'default',
|
|
302
|
+
joinedAt: new Date().toISOString(),
|
|
303
|
+
lastSeen: new Date().toISOString()
|
|
296
304
|
};
|
|
297
305
|
|
|
306
|
+
// Add client to session
|
|
307
|
+
session.clients[clientId] = clientInfo;
|
|
298
308
|
this.clients.set(ws, clientInfo);
|
|
299
|
-
session.clients[clientId] = true;
|
|
300
|
-
|
|
301
|
-
// Get all client infos for the session
|
|
302
|
-
const sessionClients = Array.from(this.clients.values())
|
|
303
|
-
.filter(c => c.sessionId === sessionId)
|
|
304
|
-
.map(({ id, name, role, isHost }) => ({
|
|
305
|
-
id,
|
|
306
|
-
name,
|
|
307
|
-
role,
|
|
308
|
-
isHost
|
|
309
|
-
}));
|
|
310
309
|
|
|
311
|
-
// Send
|
|
310
|
+
// Send session joined confirmation
|
|
312
311
|
ws.send(JSON.stringify({
|
|
313
312
|
type: 'session_joined',
|
|
314
313
|
sessionId,
|
|
315
314
|
clientId,
|
|
315
|
+
clientInfo,
|
|
316
316
|
isHost: clientInfo.isHost,
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
.
|
|
317
|
+
sessionInfo: {
|
|
318
|
+
id: session.id,
|
|
319
|
+
createdAt: session.createdAt,
|
|
320
|
+
clientCount: Object.keys(session.clients).length,
|
|
321
|
+
hostId: session.hostId
|
|
322
|
+
}
|
|
321
323
|
}));
|
|
322
324
|
|
|
323
|
-
// Notify other clients
|
|
325
|
+
// Notify other clients in the session
|
|
324
326
|
this.broadcastToSession(sessionId, {
|
|
325
327
|
type: 'agent_joined',
|
|
326
328
|
clientId,
|
|
327
|
-
clientInfo
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
role: clientInfo.role,
|
|
331
|
-
isHost: clientInfo.isHost
|
|
332
|
-
}
|
|
333
|
-
}, ws);
|
|
329
|
+
clientInfo,
|
|
330
|
+
timestamp: new Date().toISOString()
|
|
331
|
+
}, clientId);
|
|
334
332
|
}
|
|
335
333
|
|
|
336
334
|
broadcastToSession(sessionId, message, excludeClientId = null) {
|
|
@@ -340,15 +338,27 @@ class MultiplayerServer {
|
|
|
340
338
|
const messageStr = JSON.stringify(message);
|
|
341
339
|
|
|
342
340
|
Object.entries(session.clients).forEach(([id, client]) => {
|
|
343
|
-
if (id !== excludeClientId && client.ws.readyState === WebSocket.OPEN) {
|
|
341
|
+
if (id !== excludeClientId && client.ws && client.ws.readyState === WebSocket.OPEN) {
|
|
344
342
|
client.ws.send(messageStr);
|
|
345
343
|
}
|
|
346
344
|
});
|
|
347
345
|
}
|
|
348
346
|
|
|
349
347
|
start() {
|
|
350
|
-
|
|
351
|
-
|
|
348
|
+
return new Promise((resolve, reject) => {
|
|
349
|
+
this.httpServer = http.createServer();
|
|
350
|
+
this.wss = new WebSocket.Server({ server: this.httpServer });
|
|
351
|
+
this.setupEventHandlers();
|
|
352
|
+
|
|
353
|
+
this.httpServer.on('error', (error) => {
|
|
354
|
+
console.error(chalk.red('HTTP server error:'), error);
|
|
355
|
+
reject(error);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
this.httpServer.listen(this.port, () => {
|
|
359
|
+
console.log(chalk.green(`Multiplayer server started on port ${this.port}`));
|
|
360
|
+
resolve(this.port);
|
|
361
|
+
});
|
|
352
362
|
});
|
|
353
363
|
}
|
|
354
364
|
}
|