shell-mirror 1.5.87 → 1.5.89

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": "shell-mirror",
3
- "version": "1.5.87",
3
+ "version": "1.5.89",
4
4
  "description": "Access your Mac shell from any device securely. Perfect for mobile coding with Claude Code CLI, Gemini CLI, and any shell tool.",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -349,12 +349,18 @@ body {
349
349
  /* Agent Items */
350
350
  .agent-item {
351
351
  display: flex;
352
- justify-content: space-between;
353
- align-items: center;
352
+ flex-direction: column;
354
353
  padding: 16px 0;
355
354
  border-bottom: 1px solid #f0f0f0;
356
355
  }
357
356
 
357
+ .agent-header {
358
+ display: flex;
359
+ justify-content: space-between;
360
+ align-items: center;
361
+ width: 100%;
362
+ }
363
+
358
364
  .agent-item:last-child {
359
365
  border-bottom: none;
360
366
  }
@@ -406,6 +412,115 @@ body {
406
412
  font-weight: 500;
407
413
  }
408
414
 
415
+ /* Inline Session List Styles */
416
+ .agent-sessions-inline {
417
+ margin-top: 12px;
418
+ padding-top: 12px;
419
+ border-top: 1px solid #eee;
420
+ width: 100%;
421
+ }
422
+
423
+ .sessions-label {
424
+ font-size: 0.8rem;
425
+ color: #666;
426
+ font-weight: 500;
427
+ margin-bottom: 8px;
428
+ }
429
+
430
+ .sessions-list {
431
+ margin-bottom: 10px;
432
+ }
433
+
434
+ .inline-session-item {
435
+ display: flex;
436
+ align-items: center;
437
+ gap: 10px;
438
+ padding: 10px 12px;
439
+ margin-bottom: 6px;
440
+ background: #f8f9fa;
441
+ border-radius: 8px;
442
+ border: 1px solid #eee;
443
+ transition: all 0.2s ease;
444
+ }
445
+
446
+ .inline-session-item:hover {
447
+ background: #fff;
448
+ border-color: #4285f4;
449
+ }
450
+
451
+ .session-status-dot {
452
+ width: 8px;
453
+ height: 8px;
454
+ border-radius: 50%;
455
+ flex-shrink: 0;
456
+ }
457
+
458
+ .session-status-dot.active {
459
+ background: #34a853;
460
+ }
461
+
462
+ .session-status-dot.crashed {
463
+ background: #ea4335;
464
+ }
465
+
466
+ .session-name {
467
+ font-weight: 500;
468
+ color: #333;
469
+ flex: 1;
470
+ font-size: 0.9rem;
471
+ }
472
+
473
+ .session-activity {
474
+ font-size: 0.75rem;
475
+ color: #888;
476
+ margin-right: 8px;
477
+ }
478
+
479
+ .btn-session-connect {
480
+ background: #4285f4;
481
+ color: white;
482
+ border: none;
483
+ border-radius: 6px;
484
+ padding: 6px 14px;
485
+ font-size: 0.8rem;
486
+ font-weight: 500;
487
+ cursor: pointer;
488
+ transition: all 0.2s ease;
489
+ }
490
+
491
+ .btn-session-connect:hover {
492
+ background: #3367d6;
493
+ transform: translateY(-1px);
494
+ }
495
+
496
+ .btn-new-session {
497
+ background: #fff;
498
+ color: #4285f4;
499
+ border: 1px dashed #4285f4;
500
+ border-radius: 8px;
501
+ padding: 10px 16px;
502
+ font-size: 0.85rem;
503
+ font-weight: 500;
504
+ cursor: pointer;
505
+ width: 100%;
506
+ transition: all 0.2s ease;
507
+ }
508
+
509
+ .btn-new-session:hover {
510
+ background: #f0f7ff;
511
+ border-style: solid;
512
+ }
513
+
514
+ .agent-offline-message {
515
+ margin-top: 12px;
516
+ padding: 10px;
517
+ background: #f5f5f5;
518
+ border-radius: 6px;
519
+ color: #999;
520
+ font-size: 0.85rem;
521
+ text-align: center;
522
+ }
523
+
409
524
  .agent-actions {
410
525
  display: flex;
411
526
  gap: 8px;
@@ -751,12 +866,33 @@ body {
751
866
  align-items: flex-start;
752
867
  gap: 12px;
753
868
  }
754
-
869
+
755
870
  .session-details {
756
871
  align-items: flex-start;
757
872
  flex-direction: row;
758
873
  gap: 12px;
759
874
  }
875
+
876
+ /* Mobile inline session styles */
877
+ .inline-session-item {
878
+ flex-wrap: wrap;
879
+ gap: 8px;
880
+ }
881
+
882
+ .session-name {
883
+ flex-basis: calc(100% - 30px);
884
+ }
885
+
886
+ .session-activity {
887
+ order: 3;
888
+ flex-basis: 50%;
889
+ margin-right: 0;
890
+ }
891
+
892
+ .btn-session-connect {
893
+ order: 4;
894
+ padding: 8px 16px;
895
+ }
760
896
  }
761
897
 
762
898
  /* Modal Styles */
@@ -566,26 +566,48 @@ class ShellMirrorDashboard {
566
566
  ? this.formatPreciseLastSeen(agent.timeSinceLastSeen)
567
567
  : this.formatLastSeen(agent.lastSeen);
568
568
 
569
+ // Build inline session list
570
+ const sessionsHtml = sessions.map(session => {
571
+ const sessionStatus = session.status === 'active' ? 'active' : 'crashed';
572
+ const activityText = this.formatLastActivity(session.lastActivity);
573
+ return `
574
+ <div class="inline-session-item">
575
+ <span class="session-status-dot ${sessionStatus}"></span>
576
+ <span class="session-name">${session.name}</span>
577
+ <span class="session-activity">${activityText}</span>
578
+ <button class="btn-session-connect" onclick="dashboard.connectToSession('${agent.agentId}', '${session.id}')">
579
+ Connect
580
+ </button>
581
+ </div>
582
+ `;
583
+ }).join('');
584
+
569
585
  return `
570
586
  <div class="agent-item ${!isConnectable ? 'agent-offline' : ''}">
571
- <div class="agent-info">
572
- <div class="agent-name">${agent.machineName || agent.agentId}</div>
573
- <div class="agent-status ${agent.status}">
574
- ${statusIcon} ${statusText}
587
+ <div class="agent-header">
588
+ <div class="agent-info">
589
+ <div class="agent-name">${agent.machineName || agent.agentId}</div>
590
+ <div class="agent-status ${agent.status}">
591
+ ${statusIcon} ${statusText}
592
+ </div>
593
+ <div class="agent-last-seen">Last seen: ${lastSeenText}</div>
575
594
  </div>
576
- <div class="agent-last-seen">Last seen: ${lastSeenText}</div>
577
- ${sessionCount > 0 ? `<div class="agent-sessions">${sessionCount} active session${sessionCount !== 1 ? 's' : ''}</div>` : ''}
578
595
  </div>
579
- <div class="agent-actions">
580
- <button class="btn-connect ${!isConnectable ? 'btn-disabled' : ''}"
581
- onclick="dashboard.connectToAgent('${agent.agentId}')"
582
- ${!isConnectable ? 'disabled' : ''}>
583
- ${!isConnectable ? 'Offline' : sessionCount > 0 ? 'Resume Session' : 'New Session'}
596
+ ${isConnectable ? `
597
+ <div class="agent-sessions-inline">
598
+ ${sessionCount > 0 ? `
599
+ <div class="sessions-label">Sessions (${sessionCount})</div>
600
+ <div class="sessions-list">
601
+ ${sessionsHtml}
602
+ </div>
603
+ ` : ''}
604
+ <button class="btn-new-session" onclick="dashboard.createNewSession('${agent.agentId}')">
605
+ + New Session
584
606
  </button>
585
- ${sessionCount > 0 && isConnectable ? `<button class="btn-sessions" onclick="dashboard.showAgentSessions('${agent.agentId}')">
586
- All Sessions
587
- </button>` : ''}
588
607
  </div>
608
+ ` : `
609
+ <div class="agent-offline-message">Agent offline</div>
610
+ `}
589
611
  </div>
590
612
  `;
591
613
  }).join('');
@@ -1052,46 +1074,6 @@ class ShellMirrorDashboard {
1052
1074
  }
1053
1075
  }
1054
1076
 
1055
- showAgentSessions(agentId) {
1056
- const sessions = this.agentSessions[agentId] || [];
1057
- const agent = this.agents.find(a => a.agentId === agentId);
1058
- const agentName = agent ? (agent.machineName || agent.agentId) : agentId;
1059
-
1060
- if (sessions.length === 0) {
1061
- alert(`No active sessions found for ${agentName}`);
1062
- return;
1063
- }
1064
-
1065
- // Create session list modal
1066
- const sessionsList = sessions.map(session => `
1067
- <div class="session-list-item" onclick="dashboard.connectToSession('${agentId}', '${session.id}')">
1068
- <div class="session-list-info">
1069
- <div class="session-list-name">${session.name}</div>
1070
- <div class="session-list-details">
1071
- <span class="session-list-id">${session.id.substring(0, 8)}...</span>
1072
- <span class="session-list-activity">Last activity: ${this.formatLastActivity(session.lastActivity)}</span>
1073
- </div>
1074
- </div>
1075
- <div class="session-list-status ${session.status}">${session.status}</div>
1076
- </div>
1077
- `).join('');
1078
-
1079
- // Show modal with sessions
1080
- this.showModal(`Sessions on ${agentName}`, `
1081
- <div class="sessions-modal-content">
1082
- <p>Active terminal sessions (${sessions.length}):</p>
1083
- <div class="session-list">
1084
- ${sessionsList}
1085
- </div>
1086
- <div class="sessions-modal-actions">
1087
- <button class="btn-primary" onclick="dashboard.createNewSession('${agentId}')">
1088
- + Create New Session
1089
- </button>
1090
- </div>
1091
- </div>
1092
- `);
1093
- }
1094
-
1095
1077
  showModal(title, content) {
1096
1078
  // Create modal overlay
1097
1079
  const modalOverlay = document.createElement('div');