sam-coder-cli 1.0.29 → 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.
@@ -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
- try {
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.sessionId = sessionId;
793
- this.isHost = false;
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 === this.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.once('session_joined', onSessionJoined);
810
- this.once('error', onError);
817
+ this.on('session_joined', onSessionJoined);
818
+ this.on('error', onError);
811
819
 
812
820
  this.send({
813
821
  type: 'join_session',
814
- sessionId: this.sessionId,
815
- clientInfo: {
816
- name: this.name,
817
- role: this.role,
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
- const session = this.sessions.get(sessionId);
267
-
268
- if (!session) {
269
- ws.send(JSON.stringify({
270
- type: 'error',
271
- message: 'Session not found'
272
- }));
273
- return;
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
- if (Object.keys(session.clients).length >= 4) {
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
- this.server.listen(this.port, () => {
351
- console.log(`Multiplayer server running on ws://localhost:${this.port}`);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sam-coder-cli",
3
- "version": "1.0.29",
3
+ "version": "1.0.30",
4
4
  "description": "SAM-CODER: An animated command-line AI assistant with agency capabilities.",
5
5
  "main": "bin/agi-cli.js",
6
6
  "bin": {