sam-coder-cli 1.0.15 → 1.0.17

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.
@@ -235,59 +235,61 @@ class MultiplayerClient extends EventEmitter {
235
235
  this.clients = [];
236
236
  this.currentTask = null;
237
237
  this.taskQueue = [];
238
+ this.pendingTasks = new Map();
239
+ this.taskResults = new Map();
238
240
  this.rl = options.rl || readline.createInterface({
239
241
  input: process.stdin,
240
242
  output: process.stdout
241
243
  });
244
+
245
+ // Bind methods
246
+ this.processTaskQueue = this.processTaskQueue.bind(this);
247
+ this.completeTask = this.completeTask.bind(this);
242
248
  }
243
249
 
244
250
  async connect() {
245
251
  try {
246
- // Ensure server is running and get the correct URL
247
- const url = new URL(this.serverUrl);
248
- const serverPort = url.port || 8080;
249
- this.serverUrl = await ensureServerRunning(serverPort);
252
+ // Ensure server is running
253
+ this.serverUrl = await ensureServerRunning(this.port);
250
254
 
251
- return new Promise((resolve, reject) => {
252
- this.ws = new WebSocket(this.serverUrl);
253
-
254
- this.ws.on('open', () => {
255
- this.connected = true;
256
- // Send client info immediately after connection
257
- this.send({
258
- type: 'client_info',
259
- clientInfo: {
260
- name: this.name || `Agent-${Math.random().toString(36).substr(2, 4)}`,
261
- role: this.role || 'Assistant',
262
- model: this.model || 'default'
263
- }
264
- });
265
- this.emit('connected');
266
- resolve();
267
- });
268
-
269
- this.ws.on('message', (data) => {
270
- try {
271
- const message = JSON.parse(data);
272
- this.handleMessage(message);
273
- } catch (error) {
274
- console.error('Error parsing message:', error);
275
- }
276
- });
277
-
278
- this.ws.on('close', () => {
279
- this.connected = false;
280
- this.emit('disconnected');
281
- });
255
+ this.ws = new WebSocket(this.serverUrl);
256
+
257
+ this.ws.on('open', () => {
258
+ this.connected = true;
259
+ this.emit('connected');
260
+ console.log(chalk.green('āœ… Connected to multiplayer server'));
282
261
 
283
- this.ws.on('error', (error) => {
284
- this.connected = false;
285
- reject(error);
262
+ // Send client info immediately after connection
263
+ this.updateClientInfo({
264
+ name: this.name,
265
+ role: this.role,
266
+ model: this.model
286
267
  });
287
268
  });
269
+
270
+ this.ws.on('message', (data) => {
271
+ try {
272
+ const message = JSON.parse(data);
273
+ this.handleMessage(message);
274
+ } catch (error) {
275
+ console.error('Error parsing message:', error);
276
+ }
277
+ });
278
+
279
+ this.ws.on('close', () => {
280
+ this.connected = false;
281
+ this.emit('disconnected');
282
+ console.log(chalk.yellow('\nšŸ”Œ Disconnected from multiplayer server'));
283
+ });
284
+
285
+ this.ws.on('error', (error) => {
286
+ console.error('WebSocket error:', error);
287
+ this.emit('error', error);
288
+ });
289
+
288
290
  } catch (error) {
289
- console.error('Failed to start multiplayer server:', error);
290
- throw error;
291
+ console.error('Failed to connect to server:', error);
292
+ this.emit('error', error);
291
293
  }
292
294
  }
293
295
 
@@ -398,13 +400,22 @@ class MultiplayerClient extends EventEmitter {
398
400
  this.emit('work_updated', message);
399
401
  }
400
402
 
401
- handleTaskAssigned(task) {
402
- console.log(`\n New task assigned: ${task.prompt}`);
403
- console.log(`Type: ${task.taskType} | Assigned by: ${this.getClientName(task.assignedBy)}\n`);
403
+ async handleTaskAssigned(task) {
404
+ console.log(chalk.magenta(`\nšŸ“‹ New Task: ${task.prompt}`));
405
+ console.log(chalk.dim(`Type: ${task.taskType} | Assigned by: ${this.getClientName(task.assignedBy)}\n`));
406
+
407
+ // Store task in pending tasks
408
+ this.pendingTasks.set(task.id, {
409
+ ...task,
410
+ status: 'pending',
411
+ assignedAt: new Date().toISOString()
412
+ });
404
413
 
405
- // Add to task queue
406
- this.taskQueue.push(task);
407
- this.processTaskQueue();
414
+ // Add to task queue if it's assigned to this client or to all
415
+ if (!task.assignedTo || task.assignedTo === this.clientId) {
416
+ this.taskQueue.push(task);
417
+ this.processTaskQueue();
418
+ }
408
419
 
409
420
  this.emit('task_assigned', task);
410
421
  }
@@ -413,68 +424,196 @@ class MultiplayerClient extends EventEmitter {
413
424
  if (this.currentTask || this.taskQueue.length === 0) return;
414
425
 
415
426
  this.currentTask = this.taskQueue.shift();
427
+ const taskId = this.currentTask.id;
416
428
 
417
429
  try {
418
- // Simulate working on the task
419
- console.log(`\n Working on task: ${this.currentTask.prompt}`);
430
+ // Update task status to in-progress
431
+ this.pendingTasks.set(taskId, {
432
+ ...this.pendingTasks.get(taskId),
433
+ status: 'in_progress',
434
+ startedAt: new Date().toISOString()
435
+ });
436
+
437
+ // Notify others about task progress
438
+ this.send({
439
+ type: 'task_progress',
440
+ sessionId: this.sessionId,
441
+ taskId,
442
+ status: 'in_progress',
443
+ progress: 0,
444
+ timestamp: new Date().toISOString()
445
+ });
446
+
447
+ console.log(chalk.blue(`\nšŸ”„ [${this.role}] Working on: ${this.currentTask.prompt}`));
420
448
 
421
- // Here you would integrate with your AI to process the task
422
- // For now, we'll just simulate work
423
- await new Promise(resolve => setTimeout(resolve, 2000));
449
+ // Process the task using the completeTask method
450
+ const completedTask = await this.completeTask(taskId);
424
451
 
425
- const result = {
426
- taskId: this.currentTask.id,
427
- result: `Completed task: ${this.currentTask.prompt}`,
452
+ if (completedTask) {
453
+ // Task completed successfully
454
+ this.send({
455
+ type: 'task_progress',
456
+ sessionId: this.sessionId,
457
+ taskId,
458
+ status: 'completed',
459
+ progress: 100,
460
+ timestamp: new Date().toISOString()
461
+ });
462
+
463
+ console.log(chalk.green(`\nāœ… [${this.role}] Completed task: ${this.currentTask.prompt}`));
464
+ }
465
+ if (this.taskQueue.length > 0) {
466
+ this.processTaskQueue();
467
+ }
468
+ } catch (error) {
469
+ console.error('Error processing task:', error);
470
+ this.send({
471
+ type: 'task_failed',
472
+ sessionId: this.sessionId,
473
+ taskId,
474
+ error: error.message,
428
475
  timestamp: new Date().toISOString()
476
+ });
477
+ } finally {
478
+ this.currentTask = null;
479
+ }
480
+ }
481
+
482
+ async completeTask(taskId) {
483
+ const task = this.pendingTasks.get(taskId);
484
+ if (!task) {
485
+ console.error('Task not found:', taskId);
486
+ return null;
487
+ }
488
+
489
+ try {
490
+ // Process the task using the same logic as the normal mode
491
+ const { processQuery } = require('./agi-cli');
492
+ const result = await processQuery(task.prompt, [], this.model);
493
+
494
+ // Update task status
495
+ const completedTask = {
496
+ ...task,
497
+ status: 'completed',
498
+ completedAt: new Date().toISOString(),
499
+ result: typeof result === 'string' ? result : JSON.stringify(result, null, 2)
429
500
  };
430
501
 
431
- // Send result back to server
502
+ this.pendingTasks.set(taskId, completedTask);
503
+ this.taskResults.set(taskId, completedTask.result);
504
+
505
+ // Notify server and other clients
432
506
  this.send({
433
- type: 'task_result',
507
+ type: 'task_completed',
434
508
  sessionId: this.sessionId,
435
- taskId: this.currentTask.id,
436
- result: result.result,
437
- timestamp: result.timestamp
509
+ taskId,
510
+ result: completedTask.result,
511
+ timestamp: new Date().toISOString()
438
512
  });
439
513
 
440
- console.log(` Completed task: ${this.currentTask.prompt}`);
514
+ console.log(chalk.green(`\nāœ… [${this.role}] Completed: ${task.prompt}`));
515
+ this.emit('task_completed', completedTask);
441
516
 
517
+ return completedTask;
442
518
  } catch (error) {
443
- console.error('Error processing task:', error);
444
- } finally {
445
- this.currentTask = null;
446
- // Process next task if available
447
- if (this.taskQueue.length > 0) {
448
- this.processTaskQueue();
449
- }
519
+ console.error('Error completing task:', error);
520
+
521
+ // Update task with error status
522
+ const failedTask = {
523
+ ...task,
524
+ status: 'failed',
525
+ completedAt: new Date().toISOString(),
526
+ error: error.message
527
+ };
528
+
529
+ this.pendingTasks.set(taskId, failedTask);
530
+ this.emit('task_failed', { taskId, error: error.message });
531
+
532
+ return null;
450
533
  }
451
534
  }
452
535
 
453
536
  handleTaskCompleted(data) {
454
- console.log(`\n Task completed by all agents!`);
455
- console.log(`Task: ${this.tasks.get(data.taskId)?.prompt || 'Unknown task'}`);
456
- console.log('Results:');
537
+ const task = this.pendingTasks.get(data.taskId);
538
+ if (!task) {
539
+ console.error('Task not found for completion:', data.taskId);
540
+ return;
541
+ }
457
542
 
458
- data.results.forEach(result => {
459
- console.log(`- ${this.getClientName(result.clientId)}: ${result.result}`);
460
- });
543
+ console.log(chalk.green(`\nāœ… Task completed by all agents!`));
544
+ console.log(chalk.blue(`Task: ${task.prompt || 'Unknown task'}`));
461
545
 
462
- this.emit('task_completed', data);
546
+ if (data.results && data.results.length > 0) {
547
+ console.log(chalk.cyan('Results:'));
548
+ data.results.forEach(result => {
549
+ console.log(chalk.yellow(`- ${this.getClientName(result.clientId) || 'Unknown'}:`));
550
+ console.log(result.result);
551
+ });
552
+ } else if (data.result) {
553
+ console.log(chalk.cyan('Result:'));
554
+ console.log(data.result);
555
+ }
556
+
557
+ // Update the task with the final result
558
+ const completedTask = {
559
+ ...task,
560
+ status: 'completed',
561
+ completedAt: new Date().toISOString(),
562
+ result: data.result || 'No result provided'
563
+ };
564
+
565
+ this.pendingTasks.set(data.taskId, completedTask);
566
+ this.taskResults.set(data.taskId, completedTask.result);
567
+
568
+ this.emit('task_completed', completedTask);
463
569
  }
464
570
 
465
- updateWork(work) {
571
+ async updateWork(work) {
466
572
  const workItem = {
573
+ id: uuidv4(),
467
574
  ...work,
468
575
  clientId: this.clientId,
469
- status: work.status || 'in_progress',
470
- timestamp: new Date().toISOString()
576
+ clientName: this.name,
577
+ timestamp: new Date().toISOString(),
578
+ status: work.status || 'in_progress'
471
579
  };
472
-
580
+
581
+ this.workHistory.push(workItem);
582
+
583
+ // Keep only the last 10 work items
584
+ if (this.workHistory.length > 10) {
585
+ this.workHistory = this.workHistory.slice(-10);
586
+ }
587
+
473
588
  this.send({
474
589
  type: 'work_update',
475
590
  sessionId: this.sessionId,
476
- work: workUpdate
591
+ ...workItem
477
592
  });
593
+
594
+ this.emit('work_updated', workItem);
595
+ return workItem;
596
+ }
597
+
598
+ async updateClientInfo(updates) {
599
+ // Update local client info
600
+ Object.assign(this, updates);
601
+
602
+ // Notify server about the update
603
+ if (this.connected) {
604
+ this.send({
605
+ type: 'client_update',
606
+ sessionId: this.sessionId,
607
+ clientId: this.clientId,
608
+ updates: {
609
+ name: this.name,
610
+ role: this.role,
611
+ model: this.model,
612
+ updatedAt: new Date().toISOString()
613
+ },
614
+ timestamp: new Date().toISOString()
615
+ });
616
+ }
478
617
  }
479
618
 
480
619
  assignTask(task, assigneeClientId) {
@@ -505,6 +644,12 @@ class MultiplayerClient extends EventEmitter {
505
644
  this.ws.close();
506
645
  }
507
646
  }
647
+
648
+ getClientName(clientId) {
649
+ if (!clientId) return 'Unknown';
650
+ const client = this.clients.find(c => c.clientId === clientId || c.id === clientId);
651
+ return client ? (client.name || client.clientInfo?.name || 'Unknown') : 'Unknown';
652
+ }
508
653
  }
509
654
 
510
655
  module.exports = MultiplayerClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sam-coder-cli",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "SAM-CODER: An animated command-line AI assistant with agency capabilities.",
5
5
  "main": "bin/agi-cli.js",
6
6
  "bin": {