sam-coder-cli 1.0.25 → 1.0.27

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/agi-cli.js CHANGED
@@ -752,11 +752,17 @@ async function start() {
752
752
 
753
753
  // Check for server mode
754
754
  if (process.argv.includes('--server')) {
755
- const MultiplayerServer = require('./multiplayer-server');
756
- const server = new MultiplayerServer(8080);
757
- server.start();
758
- console.log('Multiplayer server started on ws://localhost:8080');
759
- return;
755
+ try {
756
+ const port = parseInt(process.argv[process.argv.indexOf('--port') + 1]) || 8080;
757
+ const MultiplayerServer = require('./multiplayer-server');
758
+ const server = new MultiplayerServer(port);
759
+ await server.start();
760
+ console.log(`Multiplayer server started on ws://localhost:${server.port}`);
761
+ return;
762
+ } catch (error) {
763
+ console.error('Failed to start multiplayer server:', error.message);
764
+ process.exit(1);
765
+ }
760
766
  }
761
767
 
762
768
  try {
@@ -1,6 +1,34 @@
1
1
  const WebSocket = require('ws');
2
2
  const http = require('http');
3
+ const net = require('net');
3
4
  const uuid = require('uuid');
5
+ const chalk = require('chalk');
6
+
7
+ async function findAvailablePort(startPort = 8080, maxAttempts = 10) {
8
+ let port = startPort;
9
+ let attempts = 0;
10
+
11
+ while (attempts < maxAttempts) {
12
+ const inUse = await new Promise((resolve) => {
13
+ const server = net.createServer()
14
+ .once('error', () => resolve(true))
15
+ .once('listening', () => {
16
+ server.close();
17
+ resolve(false);
18
+ })
19
+ .listen(port);
20
+ });
21
+
22
+ if (!inUse) {
23
+ return port;
24
+ }
25
+
26
+ port++;
27
+ attempts++;
28
+ }
29
+
30
+ throw new Error(`Could not find an available port after ${maxAttempts} attempts`);
31
+ }
4
32
 
5
33
  class MultiplayerServer {
6
34
  constructor(port = 8080) {
@@ -8,34 +36,109 @@ class MultiplayerServer {
8
36
  this.sessions = new Map();
9
37
  this.clients = new Map();
10
38
  this.tasks = new Map();
11
- this.server = new WebSocket.Server({ port });
12
- this.setupEventHandlers();
39
+ this.httpServer = null;
40
+ this.wss = null;
41
+ }
42
+
43
+ async start() {
44
+ try {
45
+ this.port = await findAvailablePort(this.port);
46
+
47
+ // Create HTTP server
48
+ this.httpServer = http.createServer();
49
+
50
+ // Create WebSocket server
51
+ this.wss = new WebSocket.Server({ server: this.httpServer });
52
+
53
+ // Setup event handlers
54
+ this.setupEventHandlers();
55
+
56
+ // Start listening
57
+ return new Promise((resolve, reject) => {
58
+ this.httpServer.on('error', (error) => {
59
+ console.error(chalk.red('HTTP server error:'), error);
60
+ reject(error);
61
+ });
62
+
63
+ this.httpServer.listen(this.port, () => {
64
+ console.log(chalk.green(`Multiplayer server started on port ${this.port}`));
65
+ resolve(this.port);
66
+ });
67
+ });
68
+ } catch (error) {
69
+ console.error(chalk.red('Failed to start multiplayer server:'), error.message);
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ static async startAsChildProcess(port = 8080) {
75
+ const { spawn } = require('child_process');
76
+ const serverProcess = spawn('node', [__filename, '--port', port.toString()], {
77
+ detached: true,
78
+ stdio: 'inherit',
79
+ windowsHide: true
80
+ });
81
+
82
+ serverProcess.on('error', (error) => {
83
+ console.error('Failed to start server process:', error);
84
+ });
85
+
86
+ serverProcess.unref();
87
+ console.log(`Multiplayer server starting on port ${port}...`);
88
+ return serverProcess;
13
89
  }
14
90
 
15
91
  setupEventHandlers() {
16
- this.server.on('connection', (ws) => {
92
+ if (!this.wss) {
93
+ throw new Error('WebSocket server not initialized');
94
+ }
95
+
96
+ this.wss.on('connection', (ws) => {
17
97
  let clientId = uuid.v4();
18
98
  let sessionId = null;
19
99
  let clientInfo = {};
20
100
 
21
- ws.on('message', (message) => {
22
- this.handleMessage(ws, message);
101
+ // Store client
102
+ this.clients.set(clientId, { ws, clientInfo });
103
+
104
+ ws.on('message', (data) => {
105
+ try {
106
+ const message = typeof data === 'string' ? JSON.parse(data) : data;
107
+ this.handleMessage(ws, clientId, message);
108
+ } catch (error) {
109
+ console.error('Error processing message:', error);
110
+ }
23
111
  });
24
112
 
25
113
  ws.on('close', () => {
114
+ // Remove client from any session
26
115
  if (sessionId && this.sessions.has(sessionId)) {
27
116
  const session = this.sessions.get(sessionId);
28
- delete session.clients[clientId];
29
- this.broadcastToSession(sessionId, {
30
- type: 'agent_left',
31
- clientId,
32
- clientInfo
33
- });
34
-
35
- if (Object.keys(session.clients).length === 0) {
36
- this.sessions.delete(sessionId);
117
+ if (session && session.clients) {
118
+ delete session.clients[clientId];
119
+
120
+ // Notify other clients
121
+ this.broadcastToSession(sessionId, {
122
+ type: 'agent_left',
123
+ clientId,
124
+ clientInfo,
125
+ timestamp: new Date().toISOString()
126
+ }, clientId);
127
+
128
+ // Clean up empty sessions
129
+ if (Object.keys(session.clients).length === 0) {
130
+ this.sessions.delete(sessionId);
131
+ console.log(`Session ${sessionId} ended (no clients)`);
132
+ }
37
133
  }
38
134
  }
135
+
136
+ // Remove client from clients map
137
+ this.clients.delete(clientId);
138
+ });
139
+
140
+ ws.on('error', (error) => {
141
+ console.error('WebSocket error:', error);
39
142
  });
40
143
  });
41
144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sam-coder-cli",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "SAM-CODER: An animated command-line AI assistant with agency capabilities.",
5
5
  "main": "bin/agi-cli.js",
6
6
  "bin": {