shell-mirror 1.5.39 → 1.5.40
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/mac-agent/agent.js +15 -0
- package/package.json +1 -1
- package/public/app/dashboard.js +19 -0
- package/public/app/terminal.html +28 -2
- package/public/app/terminal.js +32 -1
package/mac-agent/agent.js
CHANGED
|
@@ -212,6 +212,11 @@ async function createPeerConnection(clientId) {
|
|
|
212
212
|
};
|
|
213
213
|
|
|
214
214
|
peerConnection.oniceconnectionstatechange = () => {
|
|
215
|
+
if (!peerConnection) {
|
|
216
|
+
logToFile('[AGENT] ⚠️ ICE connection state change after peerConnection was closed');
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
215
220
|
logToFile(`[AGENT] 📊 ICE connection state changed: ${peerConnection.iceConnectionState}`);
|
|
216
221
|
logToFile(`[AGENT] 📊 ICE gathering state: ${peerConnection.iceGatheringState}`);
|
|
217
222
|
|
|
@@ -243,6 +248,11 @@ async function createPeerConnection(clientId) {
|
|
|
243
248
|
};
|
|
244
249
|
|
|
245
250
|
peerConnection.onconnectionstatechange = () => {
|
|
251
|
+
if (!peerConnection) {
|
|
252
|
+
logToFile('[AGENT] ⚠️ Connection state change after peerConnection was closed');
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
246
256
|
logToFile(`[AGENT] 📡 Connection state changed: ${peerConnection.connectionState}`);
|
|
247
257
|
|
|
248
258
|
switch (peerConnection.connectionState) {
|
|
@@ -268,6 +278,11 @@ async function createPeerConnection(clientId) {
|
|
|
268
278
|
};
|
|
269
279
|
|
|
270
280
|
peerConnection.onicegatheringstatechange = () => {
|
|
281
|
+
if (!peerConnection) {
|
|
282
|
+
logToFile('[AGENT] ⚠️ ICE gathering state change after peerConnection was closed');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
271
286
|
logToFile(`[AGENT] 🔍 ICE gathering state changed: ${peerConnection.iceGatheringState}`);
|
|
272
287
|
|
|
273
288
|
switch (peerConnection.iceGatheringState) {
|
package/package.json
CHANGED
package/public/app/dashboard.js
CHANGED
|
@@ -20,6 +20,7 @@ class ShellMirrorDashboard {
|
|
|
20
20
|
this.user = authStatus.user;
|
|
21
21
|
await this.loadDashboardData();
|
|
22
22
|
this.renderAuthenticatedDashboard();
|
|
23
|
+
this.startAutoRefresh(); // Start auto-refresh for authenticated users
|
|
23
24
|
} else {
|
|
24
25
|
this.renderUnauthenticatedDashboard();
|
|
25
26
|
}
|
|
@@ -31,6 +32,24 @@ class ShellMirrorDashboard {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
startAutoRefresh() {
|
|
36
|
+
// Refresh agent data every 30 seconds to detect disconnected agents
|
|
37
|
+
this.refreshInterval = setInterval(async () => {
|
|
38
|
+
if (this.isAuthenticated) {
|
|
39
|
+
await this.loadDashboardData();
|
|
40
|
+
// Only re-render the agents section to avoid full page flash
|
|
41
|
+
this.updateAgentsDisplay();
|
|
42
|
+
}
|
|
43
|
+
}, 30000);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
updateAgentsDisplay() {
|
|
47
|
+
const agentsCard = document.querySelector('.dashboard-card');
|
|
48
|
+
if (agentsCard) {
|
|
49
|
+
agentsCard.innerHTML = this.renderActiveAgents();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
34
53
|
showLoading() {
|
|
35
54
|
document.getElementById('loading-overlay').style.display = 'flex';
|
|
36
55
|
}
|
package/public/app/terminal.html
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
.back-to-dashboard {
|
|
36
36
|
position: fixed;
|
|
37
37
|
top: 20px;
|
|
38
|
-
|
|
38
|
+
right: 20px;
|
|
39
39
|
background: rgba(66, 133, 244, 0.9);
|
|
40
40
|
color: white;
|
|
41
41
|
border: none;
|
|
@@ -55,11 +55,37 @@
|
|
|
55
55
|
background: rgba(51, 103, 214, 0.9);
|
|
56
56
|
transform: translateY(-1px);
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/* Connection Status Indicator */
|
|
60
|
+
.connection-status {
|
|
61
|
+
width: 8px;
|
|
62
|
+
height: 8px;
|
|
63
|
+
border-radius: 50%;
|
|
64
|
+
background: #ff4444;
|
|
65
|
+
margin-right: 4px;
|
|
66
|
+
transition: all 0.3s ease;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.connection-status.connected {
|
|
70
|
+
background: #44ff44;
|
|
71
|
+
box-shadow: 0 0 8px rgba(68, 255, 68, 0.5);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.connection-status.connecting {
|
|
75
|
+
background: #ffaa44;
|
|
76
|
+
animation: pulse 1.5s ease-in-out infinite alternate;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@keyframes pulse {
|
|
80
|
+
from { opacity: 1; }
|
|
81
|
+
to { opacity: 0.4; }
|
|
82
|
+
}
|
|
58
83
|
</style>
|
|
59
84
|
</head>
|
|
60
85
|
<body>
|
|
61
86
|
<!-- Back to Dashboard Button -->
|
|
62
|
-
<a href="/app/dashboard.html" class="back-to-dashboard">
|
|
87
|
+
<a href="/app/dashboard.html" class="back-to-dashboard" id="dashboard-btn">
|
|
88
|
+
<div class="connection-status" id="connection-status"></div>
|
|
63
89
|
<span>←</span>
|
|
64
90
|
<span>Dashboard</span>
|
|
65
91
|
</a>
|
package/public/app/terminal.js
CHANGED
|
@@ -50,6 +50,26 @@ let AGENT_ID;
|
|
|
50
50
|
let CLIENT_ID;
|
|
51
51
|
let SELECTED_AGENT; // Store full agent data including WebSocket URL
|
|
52
52
|
|
|
53
|
+
// Connection status management
|
|
54
|
+
function updateConnectionStatus(status) {
|
|
55
|
+
const statusElement = document.getElementById('connection-status');
|
|
56
|
+
if (!statusElement) return;
|
|
57
|
+
|
|
58
|
+
statusElement.className = 'connection-status';
|
|
59
|
+
switch(status) {
|
|
60
|
+
case 'connecting':
|
|
61
|
+
statusElement.classList.add('connecting');
|
|
62
|
+
break;
|
|
63
|
+
case 'connected':
|
|
64
|
+
statusElement.classList.add('connected');
|
|
65
|
+
break;
|
|
66
|
+
case 'disconnected':
|
|
67
|
+
default:
|
|
68
|
+
// Default red styling already applied
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
53
73
|
// Check for agent parameter and connect directly
|
|
54
74
|
window.addEventListener('load', () => {
|
|
55
75
|
loadVersionInfo();
|
|
@@ -97,6 +117,7 @@ async function loadVersionInfo() {
|
|
|
97
117
|
|
|
98
118
|
|
|
99
119
|
function startConnection() {
|
|
120
|
+
updateConnectionStatus('connecting');
|
|
100
121
|
connectContainer.style.display = 'none';
|
|
101
122
|
terminalContainer.style.display = 'block';
|
|
102
123
|
term.open(document.getElementById('terminal'));
|
|
@@ -346,25 +367,31 @@ async function createPeerConnection() {
|
|
|
346
367
|
break;
|
|
347
368
|
case 'connected':
|
|
348
369
|
console.log('[CLIENT] ✅ WebRTC connection established!');
|
|
370
|
+
updateConnectionStatus('connected');
|
|
349
371
|
break;
|
|
350
372
|
case 'completed':
|
|
351
373
|
console.log('[CLIENT] ✅ ICE connection completed successfully!');
|
|
374
|
+
updateConnectionStatus('connected');
|
|
352
375
|
break;
|
|
353
376
|
case 'failed':
|
|
354
377
|
console.log('[CLIENT] ❌ ICE connection failed - no viable candidates');
|
|
355
378
|
console.log('[CLIENT] 💡 Troubleshooting: This may be due to firewall/NAT issues or blocked STUN servers');
|
|
379
|
+
updateConnectionStatus('disconnected');
|
|
356
380
|
term.write('\r\n\r\n❌ Connection failed: Network connectivity issues\r\n');
|
|
357
381
|
term.write('💡 This may be due to:\r\n');
|
|
358
382
|
term.write(' • Firewall blocking WebRTC traffic\r\n');
|
|
359
383
|
term.write(' • Corporate network restrictions\r\n');
|
|
360
384
|
term.write(' • STUN/TURN servers unreachable\r\n');
|
|
361
|
-
term.write('
|
|
385
|
+
term.write(' • Agent may have crashed or disconnected\r\n');
|
|
386
|
+
term.write('\r\n🔄 Click Dashboard to return and try another agent\r\n');
|
|
362
387
|
break;
|
|
363
388
|
case 'disconnected':
|
|
364
389
|
console.log('[CLIENT] ⚠️ ICE connection disconnected');
|
|
390
|
+
updateConnectionStatus('disconnected');
|
|
365
391
|
break;
|
|
366
392
|
case 'closed':
|
|
367
393
|
console.log('[CLIENT] 🔐 ICE connection closed');
|
|
394
|
+
updateConnectionStatus('disconnected');
|
|
368
395
|
break;
|
|
369
396
|
}
|
|
370
397
|
};
|
|
@@ -440,12 +467,16 @@ function setupDataChannel() {
|
|
|
440
467
|
|
|
441
468
|
dataChannel.onclose = () => {
|
|
442
469
|
console.log('[CLIENT] Data channel closed.');
|
|
470
|
+
updateConnectionStatus('disconnected');
|
|
443
471
|
term.write('\r\n\r\n\x1b[31m❌ Terminal session ended.\x1b[0m\r\n');
|
|
472
|
+
term.write('🔄 Click Dashboard to return and start a new session\r\n');
|
|
444
473
|
};
|
|
445
474
|
|
|
446
475
|
dataChannel.onerror = (error) => {
|
|
447
476
|
console.error('[CLIENT] Data channel error:', error);
|
|
477
|
+
updateConnectionStatus('disconnected');
|
|
448
478
|
term.write('\r\n\r\n\x1b[31m❌ Data channel error occurred.\x1b[0m\r\n');
|
|
479
|
+
term.write('🔄 Click Dashboard to return and try again\r\n');
|
|
449
480
|
};
|
|
450
481
|
|
|
451
482
|
term.onData((data) => {
|