sam-coder-cli 1.0.28 → 1.0.30
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 +33 -50
- 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,10 @@ 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
|
-
|
|
298
|
-
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
|
-
|
|
311
|
-
// Send welcome message with session info
|
|
312
|
-
ws.send(JSON.stringify({
|
|
313
|
-
type: 'session_joined',
|
|
314
|
-
sessionId,
|
|
315
|
-
clientId,
|
|
316
|
-
isHost: clientInfo.isHost,
|
|
317
|
-
clients: sessionClients,
|
|
318
|
-
workHistory: session.workHistory,
|
|
319
|
-
pendingTasks: Array.from(this.tasks.values())
|
|
320
|
-
.filter(t => t.sessionId === sessionId && t.status === 'in_progress')
|
|
321
|
-
}));
|
|
322
|
-
|
|
323
|
-
// Notify other clients
|
|
324
|
-
this.broadcastToSession(sessionId, {
|
|
325
|
-
type: 'agent_joined',
|
|
326
|
-
clientId,
|
|
327
|
-
clientInfo: {
|
|
328
|
-
id: clientId,
|
|
329
|
-
name: clientInfo.name,
|
|
330
|
-
role: clientInfo.role,
|
|
331
|
-
isHost: clientInfo.isHost
|
|
332
|
-
}
|
|
333
|
-
}, ws);
|
|
334
305
|
}
|
|
335
306
|
|
|
336
307
|
broadcastToSession(sessionId, message, excludeClientId = null) {
|
|
@@ -340,15 +311,27 @@ class MultiplayerServer {
|
|
|
340
311
|
const messageStr = JSON.stringify(message);
|
|
341
312
|
|
|
342
313
|
Object.entries(session.clients).forEach(([id, client]) => {
|
|
343
|
-
if (id !== excludeClientId && client.ws.readyState === WebSocket.OPEN) {
|
|
314
|
+
if (id !== excludeClientId && client.ws && client.ws.readyState === WebSocket.OPEN) {
|
|
344
315
|
client.ws.send(messageStr);
|
|
345
316
|
}
|
|
346
317
|
});
|
|
347
318
|
}
|
|
348
319
|
|
|
349
320
|
start() {
|
|
350
|
-
|
|
351
|
-
|
|
321
|
+
return new Promise((resolve, reject) => {
|
|
322
|
+
this.httpServer = http.createServer();
|
|
323
|
+
this.wss = new WebSocket.Server({ server: this.httpServer });
|
|
324
|
+
this.setupEventHandlers();
|
|
325
|
+
|
|
326
|
+
this.httpServer.on('error', (error) => {
|
|
327
|
+
console.error(chalk.red('HTTP server error:'), error);
|
|
328
|
+
reject(error);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
this.httpServer.listen(this.port, () => {
|
|
332
|
+
console.log(chalk.green(`Multiplayer server started on port ${this.port}`));
|
|
333
|
+
resolve(this.port);
|
|
334
|
+
});
|
|
352
335
|
});
|
|
353
336
|
}
|
|
354
337
|
}
|