shell-mirror 1.5.81 → 1.5.83

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.
@@ -910,6 +910,21 @@ function setupDataChannel(clientId) {
910
910
  sessionId: message.sessionId,
911
911
  sessionName: newSession.name
912
912
  }));
913
+
914
+ // Send buffered output for this session
915
+ const bufferedOutput = newSession.buffer.getAll();
916
+ if (bufferedOutput) {
917
+ logToFile(`[AGENT] 📤 Sending ${bufferedOutput.length} chars of buffered output for session switch`);
918
+ const success = sendLargeMessage(dataChannel, {
919
+ type: 'output',
920
+ data: bufferedOutput
921
+ }, '[AGENT]');
922
+ if (!success) {
923
+ logToFile('[AGENT] ❌ Failed to send buffered output');
924
+ }
925
+ } else {
926
+ logToFile('[AGENT] â„šī¸ No buffered output for switched session');
927
+ }
913
928
  } else {
914
929
  dataChannel.send(JSON.stringify({
915
930
  type: 'error',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shell-mirror",
3
- "version": "1.5.81",
3
+ "version": "1.5.83",
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": {
@@ -109,7 +109,6 @@
109
109
  gap: 8px;
110
110
  }
111
111
 
112
- /* Session Info Button */
113
112
  /* Session Tab Bar */
114
113
  .session-tab-bar {
115
114
  display: flex;
@@ -265,31 +264,6 @@
265
264
  #connect-container { padding: 2em; text-align: center; }
266
265
  #agent-id-input { font-size: 1.2em; padding: 8px; width: 400px; margin-bottom: 1em; }
267
266
  #connect-btn { font-size: 1.2em; padding: 10px 20px; }
268
-
269
- /* Connection Status Indicator */
270
- .connection-status {
271
- width: 8px;
272
- height: 8px;
273
- border-radius: 50%;
274
- background: #ff4444;
275
- margin-right: 4px;
276
- transition: all 0.3s ease;
277
- }
278
-
279
- .connection-status.connected {
280
- background: #44ff44;
281
- box-shadow: 0 0 8px rgba(68, 255, 68, 0.5);
282
- }
283
-
284
- .connection-status.connecting {
285
- background: #ffaa44;
286
- animation: pulse 1.5s ease-in-out infinite alternate;
287
- }
288
-
289
- @keyframes pulse {
290
- from { opacity: 1; }
291
- to { opacity: 0.4; }
292
- }
293
267
 
294
268
  /* Help Modal - Tab Navigation */
295
269
  .help-tabs {
@@ -393,7 +367,7 @@
393
367
  <span class="btn-text">Help</span>
394
368
  </button>
395
369
  <a href="/app/dashboard.html" class="header-btn dashboard-btn">
396
- <span>📊</span>
370
+ <span class="btn-text">Dashboard</span>
397
371
  </a>
398
372
  </div>
399
373
  </div>
@@ -153,24 +153,7 @@ const chunkAssembler = {
153
153
 
154
154
  // Connection status management
155
155
  function updateConnectionStatus(status) {
156
- const statusElement = document.getElementById('connection-status');
157
- if (!statusElement) return;
158
-
159
- statusElement.className = 'connection-status';
160
- switch(status) {
161
- case 'connecting':
162
- statusElement.classList.add('connecting');
163
- break;
164
- case 'connected':
165
- statusElement.classList.add('connected');
166
- break;
167
- case 'disconnected':
168
- default:
169
- // Default red styling already applied
170
- break;
171
- }
172
-
173
- // Update tab status indicators
156
+ // Update tab status indicators only (removed global connection-status element)
174
157
  if (currentSession) {
175
158
  renderTabs();
176
159
  }
@@ -564,6 +547,11 @@ async function initializeWebRTCSignaling() {
564
547
  if (nextData.availableSessions) {
565
548
  availableSessions = nextData.availableSessions;
566
549
  console.log('[CLIENT] 📚 Available sessions:', availableSessions);
550
+
551
+ // Re-render tabs with updated session list
552
+ if (currentSession) {
553
+ renderTabs();
554
+ }
567
555
  }
568
556
 
569
557
  console.log('[CLIENT] Received WebRTC offer from agent.');
@@ -923,11 +911,16 @@ function sendMessage(message) {
923
911
  // Session Management Functions
924
912
  function updateSessionDisplay() {
925
913
  const sessionHeader = document.getElementById('session-header');
914
+ if (!sessionHeader) {
915
+ console.warn('[CLIENT] âš ī¸ session-header element not found');
916
+ return;
917
+ }
926
918
 
927
919
  if (currentSession) {
928
920
  sessionHeader.style.display = 'flex';
929
921
 
930
922
  // Update tabs
923
+ console.log('[CLIENT] 📋 Rendering tabs, availableSessions:', availableSessions);
931
924
  renderTabs();
932
925
 
933
926
  console.log('[CLIENT] 📋 Session display updated:', currentSession);
@@ -936,42 +929,69 @@ function updateSessionDisplay() {
936
929
 
937
930
  function renderTabs() {
938
931
  const tabBar = document.getElementById('session-tab-bar');
939
- if (!tabBar) return;
932
+ if (!tabBar) {
933
+ console.warn('[CLIENT] âš ī¸ session-tab-bar element not found');
934
+ return;
935
+ }
940
936
 
941
- // Get connection status
942
- const connectionStatus = getConnectionStatus();
937
+ // Ensure we have sessions to display
938
+ let sessionsToRender = [];
939
+
940
+ if (availableSessions && availableSessions.length > 0) {
941
+ // Use availableSessions from agent
942
+ sessionsToRender = availableSessions;
943
+ } else if (currentSession) {
944
+ // Fallback: show at least the current session
945
+ sessionsToRender = [currentSession];
946
+ }
947
+
948
+ console.log('[CLIENT] 🎨 Rendering tabs:', {
949
+ sessionCount: sessionsToRender.length,
950
+ currentSession: currentSession?.id,
951
+ source: availableSessions?.length > 0 ? 'agent' : 'fallback'
952
+ });
943
953
 
944
954
  // Build tabs HTML
945
955
  let tabsHTML = '';
946
956
 
947
- if (availableSessions && availableSessions.length > 0) {
948
- tabsHTML = availableSessions.map(session => {
957
+ if (sessionsToRender.length > 0) {
958
+ tabsHTML = sessionsToRender.map(session => {
949
959
  const isActive = currentSession && session.id === currentSession.id;
960
+ const displayName = session.name || 'Terminal Session';
961
+ const status = getSessionStatus(session.id); // Per-session status
962
+
950
963
  return `
951
964
  <button class="session-tab ${isActive ? 'active' : ''}"
952
965
  onclick="switchToSession('${session.id}')"
953
- ${isActive ? 'disabled' : ''}>
954
- <span class="session-tab-status ${connectionStatus}"></span>
955
- <span class="session-tab-name">${session.name}</span>
966
+ ${isActive ? 'disabled' : ''}
967
+ title="${displayName}">
968
+ <span class="session-tab-status ${status}"></span>
969
+ <span class="session-tab-name">${displayName}</span>
956
970
  </button>
957
971
  `;
958
972
  }).join('');
959
973
  }
960
974
 
961
975
  // Add new session button
962
- tabsHTML += '<button class="session-tab-new" onclick="createNewSession()">+</button>';
976
+ tabsHTML += '<button class="session-tab-new" onclick="createNewSession()" title="New Session">+</button>';
963
977
 
964
978
  tabBar.innerHTML = tabsHTML;
979
+ console.log('[CLIENT] ✅ Tabs rendered:', sessionsToRender.length, 'tabs');
965
980
  }
966
981
 
967
- function getConnectionStatus() {
968
- if (dataChannel && dataChannel.readyState === 'open') {
969
- return 'connected';
970
- } else if (dataChannel && dataChannel.readyState === 'connecting') {
971
- return 'connecting';
972
- } else {
982
+ function getSessionStatus(sessionId) {
983
+ // Current/active session shows actual connection status
984
+ if (currentSession && sessionId === currentSession.id) {
985
+ if (dataChannel && dataChannel.readyState === 'open') {
986
+ return 'connected';
987
+ } else if (dataChannel && dataChannel.readyState === 'connecting') {
988
+ return 'connecting';
989
+ }
973
990
  return 'disconnected';
974
991
  }
992
+
993
+ // Inactive sessions show as disconnected (not currently connected)
994
+ return 'disconnected';
975
995
  }
976
996
 
977
997
  function formatLastActivity(timestamp) {