@shykaruu/jarvis-brain 0.4.2 → 0.4.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shykaruu/jarvis-brain",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "J.A.R.V.I.S. — Just A Rather Very Intelligent System. An always-on autonomous AI daemon.",
5
5
  "module": "src/daemon/index.ts",
6
6
  "type": "module",
@@ -363,10 +363,10 @@ test('WebSocketServer - WebSocket allowed with auth cookie', async () => {
363
363
  }
364
364
  });
365
365
 
366
- test('WebSocketServer - sidecar websocket accepts /sidecar path with bearer auth', async () => {
367
- const authServer = new WebSocketServer(3156);
368
- authServer.setSidecarManager({
369
- async validateToken(token: string) {
366
+ test('WebSocketServer - sidecar websocket accepts /sidecar path with bearer auth', async () => {
367
+ const authServer = new WebSocketServer(3156);
368
+ authServer.setSidecarManager({
369
+ async validateToken(token: string) {
370
370
  if (token === 'sidecar-token') {
371
371
  return { sid: 'sidecar-123' } as any;
372
372
  }
@@ -377,23 +377,31 @@ test('WebSocketServer - sidecar websocket accepts /sidecar path with bearer auth
377
377
  } as any);
378
378
  authServer.start();
379
379
 
380
- try {
381
- const ws = new WebSocket('ws://localhost:3156/sidecar', {
382
- headers: { Authorization: 'Bearer sidecar-token' },
383
- } as any);
384
-
385
- const connected = await new Promise<boolean>((resolve) => {
386
- ws.onopen = () => resolve(true);
387
- ws.onerror = () => resolve(false);
388
- setTimeout(() => resolve(false), 2000);
389
- });
390
-
391
- expect(connected).toBe(true);
392
- ws.close();
393
- await new Promise((resolve) => setTimeout(resolve, 100));
394
- } finally {
395
- authServer.stop();
396
- }
380
+ try {
381
+ const ws = new WebSocket('ws://localhost:3156/sidecar', {
382
+ headers: { Authorization: 'Bearer sidecar-token' },
383
+ } as any);
384
+ const received: any[] = [];
385
+
386
+ const connected = await new Promise<boolean>((resolve) => {
387
+ ws.onopen = () => resolve(true);
388
+ ws.onerror = () => resolve(false);
389
+ setTimeout(() => resolve(false), 2000);
390
+ });
391
+
392
+ expect(connected).toBe(true);
393
+ ws.onmessage = (e) => {
394
+ if (typeof e.data === 'string') {
395
+ received.push(JSON.parse(e.data));
396
+ }
397
+ };
398
+ await new Promise((resolve) => setTimeout(resolve, 200));
399
+ expect(received.some(msg => msg.type === 'sidecar_ready')).toBe(true);
400
+ ws.close();
401
+ await new Promise((resolve) => setTimeout(resolve, 100));
402
+ } finally {
403
+ authServer.stop();
404
+ }
397
405
  });
398
406
 
399
407
  test('WebSocketServer - sendToClient unicasts JSON', async () => {
@@ -428,7 +428,7 @@ export class WebSocketServer {
428
428
  // Limit individual WS messages to 16 MB (defense against abusive HMR payloads)
429
429
  maxPayloadLength: 16 * 1024 * 1024,
430
430
 
431
- open(ws) {
431
+ open(ws) {
432
432
  // HMR proxy WebSocket — bridge to dev server
433
433
  const proxyTarget = (ws.data as any)?.proxy_target as string | undefined;
434
434
  if (proxyTarget) {
@@ -448,11 +448,21 @@ export class WebSocketServer {
448
448
  return;
449
449
  }
450
450
 
451
- const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
452
- if (sidecarId && self.sidecarManager) {
453
- self.sidecarManager.handleSidecarConnect(ws, sidecarId);
454
- return;
455
- }
451
+ const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
452
+ if (sidecarId && self.sidecarManager) {
453
+ self.sidecarManager.handleSidecarConnect(ws, sidecarId);
454
+ try {
455
+ ws.send(JSON.stringify({
456
+ type: 'sidecar_ready',
457
+ sidecar_id: sidecarId,
458
+ timestamp: Date.now(),
459
+ }));
460
+ } catch (error) {
461
+ console.error('[WebSocketServer] Failed to send sidecar_ready frame:', error);
462
+ try { ws.close(); } catch { /* ignore */ }
463
+ }
464
+ return;
465
+ }
456
466
 
457
467
  self.clients.add(ws);
458
468
  console.log('[WebSocketServer] Client connected. Total clients:', self.clients.size);
@@ -518,7 +528,7 @@ export class WebSocketServer {
518
528
  }
519
529
  },
520
530
 
521
- close(ws) {
531
+ close(ws, code, reason) {
522
532
  // HMR proxy cleanup
523
533
  const proxyUpstream = (ws.data as any)?._proxyUpstream as WebSocket | undefined;
524
534
  if (proxyUpstream) {
@@ -526,11 +536,12 @@ export class WebSocketServer {
526
536
  return;
527
537
  }
528
538
 
529
- const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
530
- if (sidecarId && self.sidecarManager) {
531
- self.sidecarManager.handleSidecarDisconnect(sidecarId);
532
- return;
533
- }
539
+ const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
540
+ if (sidecarId && self.sidecarManager) {
541
+ console.log(`[WebSocketServer] Sidecar socket closed: ${sidecarId} (${code}${reason ? `, ${reason}` : ''})`);
542
+ self.sidecarManager.handleSidecarDisconnect(sidecarId);
543
+ return;
544
+ }
534
545
 
535
546
  self.clients.delete(ws);
536
547
  console.log('[WebSocketServer] Client disconnected. Total clients:', self.clients.size);
@@ -422,20 +422,29 @@ export class SidecarManager implements Service {
422
422
  if (typeof message === 'string') {
423
423
  try {
424
424
  const parsed = JSON.parse(message);
425
- if (parsed.type === 'register') {
426
- const record = this.getSidecar(sidecarId);
427
- this.registerConnection({
428
- id: sidecarId,
425
+ if (parsed.type === 'register') {
426
+ const record = this.getSidecar(sidecarId);
427
+ this.registerConnection({
428
+ id: sidecarId,
429
429
  name: record?.name ?? parsed.hostname ?? sidecarId,
430
430
  hostname: parsed.hostname ?? 'unknown',
431
431
  os: parsed.os ?? 'unknown',
432
432
  platform: parsed.platform ?? 'unknown',
433
433
  capabilities: parsed.capabilities ?? [],
434
- unavailableCapabilities: parsed.unavailable_capabilities ?? [],
435
- connectedAt: new Date(),
436
- });
437
- return;
438
- }
434
+ unavailableCapabilities: parsed.unavailable_capabilities ?? [],
435
+ connectedAt: new Date(),
436
+ });
437
+ try {
438
+ ws.send(JSON.stringify({
439
+ type: 'sidecar_registered',
440
+ sidecar_id: sidecarId,
441
+ timestamp: Date.now(),
442
+ }));
443
+ } catch (error) {
444
+ console.warn(`[SidecarManager] Failed to send registration ack to ${sidecarId}:`, error);
445
+ }
446
+ return;
447
+ }
439
448
  if (parsed.type === 'capabilities_update') {
440
449
  this.updateCapabilities(sidecarId, parsed.capabilities ?? [], parsed.unavailable_capabilities ?? []);
441
450
  return;