shell-mirror 1.5.123 → 1.5.125

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.123",
3
+ "version": "1.5.125",
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": {
@@ -363,7 +363,7 @@
363
363
  <p>Connecting to terminal...</p>
364
364
  </div>
365
365
  <div id="terminal-container">
366
- <div class="session-header" id="session-header" style="display: none;">
366
+ <div class="session-header" id="session-header">
367
367
  <!-- Connection Status Indicator -->
368
368
  <div class="connection-status" id="connection-status"></div>
369
369
 
@@ -56,6 +56,10 @@ let currentSession = null;
56
56
  let availableSessions = [];
57
57
  let requestedSessionId = null; // For connecting to specific session from URL
58
58
 
59
+ // Connection status messaging
60
+ let connectionStatusMessage = 'Connecting to agent...';
61
+ let connectionTimeoutWarning = null;
62
+
59
63
  // Chunk reassembly for large messages
60
64
  const chunkAssembler = {
61
65
  activeChunks: new Map(),
@@ -166,6 +170,30 @@ function updateConnectionStatus(status) {
166
170
  // else: disconnected (default red)
167
171
  }
168
172
 
173
+ // Set connection status message (shown in tab bar when no sessions)
174
+ function setConnectionMessage(message, writeToTerminal = true) {
175
+ connectionStatusMessage = message;
176
+ console.log('[CLIENT] 📢 Connection message:', message);
177
+
178
+ // Update the tab bar display
179
+ updateSessionDisplay();
180
+
181
+ // Optionally write to terminal for visibility
182
+ if (writeToTerminal && term) {
183
+ term.write(`\r\n\x1b[36m${message}\x1b[0m\r\n`); // Cyan color
184
+ }
185
+ }
186
+
187
+ // Clear connection timeout warnings (called when connection succeeds)
188
+ function clearConnectionTimeouts() {
189
+ if (connectionTimeoutWarning) {
190
+ clearTimeout(connectionTimeoutWarning.timeout10s);
191
+ clearTimeout(connectionTimeoutWarning.timeout30s);
192
+ connectionTimeoutWarning = null;
193
+ console.log('[CLIENT] ✅ Connection timeout warnings cleared');
194
+ }
195
+ }
196
+
169
197
  // Cleanup timer for chunk assembler
170
198
  setInterval(() => {
171
199
  chunkAssembler.cleanup();
@@ -243,7 +271,13 @@ function startConnection() {
243
271
  connectContainer.style.display = 'none';
244
272
  terminalContainer.classList.add('show');
245
273
  term.open(document.getElementById('terminal'));
246
-
274
+
275
+ // Show initial connection message
276
+ setConnectionMessage('🔗 Connecting to agent...', true);
277
+
278
+ // Initialize session display (shows header with connection status even before session exists)
279
+ updateSessionDisplay();
280
+
247
281
  // Track terminal session start in Google Analytics
248
282
  if (typeof sendGAEvent === 'function') {
249
283
  sendGAEvent('terminal_session_start', {
@@ -259,6 +293,26 @@ function startConnection() {
259
293
  fitAddon.fit();
260
294
  term.focus(); // Ensure cursor is visible even before connection
261
295
  }, 100);
296
+
297
+ // Set up connection timeout warnings
298
+ const timeout10s = setTimeout(() => {
299
+ if (!currentSession) {
300
+ setConnectionMessage('⏱️ Taking longer than usual... Please wait', true);
301
+ term.write('\r\n\x1b[33m⏱️ Connection is taking longer than expected...\x1b[0m\r\n');
302
+ }
303
+ }, 10000);
304
+
305
+ const timeout30s = setTimeout(() => {
306
+ if (!currentSession) {
307
+ setConnectionMessage('⚠️ Connection very slow - Agent may be offline', true);
308
+ term.write('\x1b[33m⚠️ Still trying to connect. The agent may be offline or unreachable.\x1b[0m\r\n');
309
+ term.write('\x1b[36m💡 Tip: Check the agent status on the Dashboard\x1b[0m\r\n');
310
+ }
311
+ }, 30000);
312
+
313
+ // Store timeout IDs so they can be cleared on successful connection
314
+ connectionTimeoutWarning = { timeout10s, timeout30s };
315
+
262
316
  initialize();
263
317
  }
264
318
 
@@ -272,17 +326,20 @@ async function initialize() {
272
326
 
273
327
  if (directConnectionSuccess) {
274
328
  console.log('[CLIENT] ✅ Direct connection established - no server needed!');
329
+ setConnectionMessage('✅ Connected via local network!', true);
275
330
  return;
276
331
  }
277
-
332
+
278
333
  console.log('[CLIENT] ⚠️ Direct connection failed, falling back to WebRTC signaling...');
334
+ setConnectionMessage('🌐 Attempting WebRTC connection...', true);
279
335
  await initializeWebRTCSignaling();
280
336
  }
281
337
 
282
338
  async function tryDirectConnection() {
283
339
  console.log('[CLIENT] 🔗 Attempting direct connection to agent...');
284
340
  updateConnectionStatus('connecting');
285
-
341
+ setConnectionMessage('🔍 Trying direct connection to local network...', true);
342
+
286
343
  // Get agent data from API to find local connection details
287
344
  try {
288
345
  const response = await fetch('/php-backend/api/agents-list.php', {
@@ -391,6 +448,10 @@ function setupDirectConnection(directWs) {
391
448
  case 'session_created':
392
449
  console.log('[CLIENT] ✅ Direct session created:', data.sessionId);
393
450
 
451
+ // Clear connection timeout warnings
452
+ clearConnectionTimeouts();
453
+ setConnectionMessage('✅ Session created successfully!', false);
454
+
394
455
  // Update current session
395
456
  currentSession = {
396
457
  id: data.sessionId,
@@ -567,6 +628,10 @@ async function initializeWebRTCSignaling() {
567
628
 
568
629
  // Handle session assignment from agent
569
630
  if (nextData.sessionId) {
631
+ // Clear connection timeout warnings
632
+ clearConnectionTimeouts();
633
+ setConnectionMessage('✅ Session connected!', false);
634
+
570
635
  currentSession = {
571
636
  id: nextData.sessionId,
572
637
  name: nextData.sessionName || 'Terminal Session',
@@ -574,7 +639,7 @@ async function initializeWebRTCSignaling() {
574
639
  };
575
640
  console.log('[CLIENT] 📋 Session assigned:', currentSession);
576
641
  console.log('[CLIENT] 🔍 Agent ID for storage:', AGENT_ID);
577
-
642
+
578
643
  // Update UI to show session info
579
644
  updateSessionDisplay();
580
645
 
@@ -790,6 +855,7 @@ async function createPeerConnection() {
790
855
  console.log('[CLIENT] ❌ ICE connection failed - no viable candidates');
791
856
  console.log('[CLIENT] 💡 Troubleshooting: This may be due to firewall/NAT issues or blocked STUN servers');
792
857
  updateConnectionStatus('disconnected');
858
+ setConnectionMessage('❌ Unable to connect - Agent may be offline', false);
793
859
  term.write('\r\n\r\n❌ Connection failed: Network connectivity issues\r\n');
794
860
  term.write('💡 This may be due to:\r\n');
795
861
  term.write(' • Firewall blocking WebRTC traffic\r\n');
@@ -955,14 +1021,14 @@ function updateSessionDisplay() {
955
1021
  return;
956
1022
  }
957
1023
 
958
- if (currentSession) {
959
- sessionHeader.style.display = 'flex';
960
-
961
- // Update tabs
962
- console.log('[CLIENT] 📋 Rendering tabs, availableSessions:', availableSessions);
963
- renderTabs();
1024
+ // Always render tabs (they will show appropriate state even if no sessions)
1025
+ console.log('[CLIENT] 📋 Rendering tabs, availableSessions:', availableSessions, 'currentSession:', currentSession);
1026
+ renderTabs();
964
1027
 
1028
+ if (currentSession) {
965
1029
  console.log('[CLIENT] 📋 Session display updated:', currentSession);
1030
+ } else {
1031
+ console.log('[CLIENT] 📋 No current session - showing connection state only');
966
1032
  }
967
1033
  }
968
1034
 
@@ -1036,10 +1102,13 @@ function renderTabs() {
1036
1102
  </div>
1037
1103
  `;
1038
1104
  }).join('');
1039
- }
1040
1105
 
1041
- // Add new session button
1042
- tabsHTML += '<button class="session-tab-new" onclick="createNewSession()" title="New Session">+</button>';
1106
+ // Add new session button only when we have sessions
1107
+ tabsHTML += '<button class="session-tab-new" onclick="createNewSession()" title="New Session">+</button>';
1108
+ } else {
1109
+ // No sessions - show connection status message
1110
+ tabsHTML = `<div style="color: #888; font-size: 0.85rem; padding: 6px 12px;">${connectionStatusMessage}</div>`;
1111
+ }
1043
1112
 
1044
1113
  tabBar.innerHTML = tabsHTML;
1045
1114
  console.log('[CLIENT] ✅ Tabs rendered:', sessionsToRender.length, 'tabs');