shell-mirror 1.5.98 → 1.5.99
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 +11 -1
- package/package.json +1 -1
- package/public/app/dashboard.js +9 -1
- package/public/app/terminal.html +77 -0
- package/public/app/terminal.js +13 -3
package/mac-agent/agent.js
CHANGED
|
@@ -423,10 +423,20 @@ let heartbeatInterval;
|
|
|
423
423
|
|
|
424
424
|
async function sendHeartbeat() {
|
|
425
425
|
try {
|
|
426
|
+
// Get full session list for dashboard display
|
|
427
|
+
const sessionList = sessionManager.getAllSessions().map(session => ({
|
|
428
|
+
id: session.id,
|
|
429
|
+
name: session.name,
|
|
430
|
+
lastActivity: session.lastActivity,
|
|
431
|
+
createdAt: session.createdAt,
|
|
432
|
+
status: session.status
|
|
433
|
+
}));
|
|
434
|
+
|
|
426
435
|
const heartbeatData = JSON.stringify({
|
|
427
436
|
agentId: AGENT_ID,
|
|
428
437
|
timestamp: Date.now(),
|
|
429
|
-
activeSessions:
|
|
438
|
+
activeSessions: sessionList.length,
|
|
439
|
+
sessions: sessionList, // Full session list for dashboard
|
|
430
440
|
localPort: process.env.LOCAL_PORT || 8080,
|
|
431
441
|
capabilities: ['webrtc', 'direct_websocket']
|
|
432
442
|
});
|
package/package.json
CHANGED
package/public/app/dashboard.js
CHANGED
|
@@ -422,11 +422,19 @@ class ShellMirrorDashboard {
|
|
|
422
422
|
if (agentsData.success && agentsData.data && agentsData.data.agents) {
|
|
423
423
|
this.agents = agentsData.data.agents;
|
|
424
424
|
|
|
425
|
+
// Populate agentSessions from API response (sessions are sent via agent heartbeat)
|
|
426
|
+
this.agentSessions = {};
|
|
427
|
+
this.agents.forEach(agent => {
|
|
428
|
+
if (agent.sessions && agent.sessions.length > 0) {
|
|
429
|
+
this.agentSessions[agent.agentId] = agent.sessions;
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
425
433
|
// Don't load stale sessions from localStorage - only show live sessions from agents
|
|
426
|
-
// Sessions will be populated via WebSocket updates from connected agents
|
|
427
434
|
localStorage.removeItem('shell-mirror-sessions'); // Clear any stale data
|
|
428
435
|
} else {
|
|
429
436
|
this.agents = [];
|
|
437
|
+
this.agentSessions = {};
|
|
430
438
|
}
|
|
431
439
|
|
|
432
440
|
// TODO: Load session history when API is available
|
package/public/app/terminal.html
CHANGED
|
@@ -499,9 +499,86 @@
|
|
|
499
499
|
if (event.target === modal) {
|
|
500
500
|
closeHelpModal();
|
|
501
501
|
}
|
|
502
|
+
const closeModal = document.getElementById('close-session-modal');
|
|
503
|
+
if (event.target === closeModal) {
|
|
504
|
+
hideCloseSessionModal();
|
|
505
|
+
}
|
|
502
506
|
});
|
|
503
507
|
</script>
|
|
504
508
|
|
|
509
|
+
<!-- Close Session Confirmation Modal -->
|
|
510
|
+
<div id="close-session-modal" style="display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.85); align-items: center; justify-content: center; z-index: 20000;">
|
|
511
|
+
<div style="background: #2a2a2a; border-radius: 12px; max-width: 400px; width: 90%; overflow: hidden; border: 1px solid #444; box-shadow: 0 10px 40px rgba(0,0,0,0.5);">
|
|
512
|
+
<!-- Header -->
|
|
513
|
+
<div style="padding: 20px 24px; border-bottom: 1px solid #444; display: flex; justify-content: space-between; align-items: center;">
|
|
514
|
+
<h3 style="margin: 0; font-size: 1.1rem; color: #fff;">Close Session?</h3>
|
|
515
|
+
<button onclick="hideCloseSessionModal()" style="background: none; border: none; font-size: 1.5rem; cursor: pointer; padding: 0; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; border-radius: 50%; color: #888;">×</button>
|
|
516
|
+
</div>
|
|
517
|
+
|
|
518
|
+
<!-- Content -->
|
|
519
|
+
<div style="padding: 24px;">
|
|
520
|
+
<div style="display: flex; align-items: center; gap: 16px; margin-bottom: 20px;">
|
|
521
|
+
<div style="font-size: 2.5rem;">🗑️</div>
|
|
522
|
+
<div>
|
|
523
|
+
<div id="close-session-name" style="font-size: 1.1rem; color: #fff; font-weight: 500; margin-bottom: 4px;">Session 1</div>
|
|
524
|
+
<div id="close-session-duration" style="font-size: 0.85rem; color: #888;">Duration: 5 minutes</div>
|
|
525
|
+
</div>
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
<p style="color: #bbb; margin: 0 0 24px 0; font-size: 0.9rem; line-height: 1.5;">
|
|
529
|
+
This will terminate the terminal session. Any running processes will be stopped.
|
|
530
|
+
</p>
|
|
531
|
+
|
|
532
|
+
<!-- Buttons -->
|
|
533
|
+
<div style="display: flex; gap: 12px; justify-content: flex-end;">
|
|
534
|
+
<button onclick="hideCloseSessionModal()" style="padding: 10px 20px; background: #444; color: #fff; border: none; border-radius: 6px; cursor: pointer; font-size: 0.9rem; transition: background 0.2s;">Cancel</button>
|
|
535
|
+
<button id="confirm-close-session-btn" onclick="confirmCloseSession()" style="padding: 10px 20px; background: #dc3545; color: #fff; border: none; border-radius: 6px; cursor: pointer; font-size: 0.9rem; font-weight: 500; transition: background 0.2s;">Close Session</button>
|
|
536
|
+
</div>
|
|
537
|
+
</div>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
<script>
|
|
542
|
+
// Close Session Modal Functions
|
|
543
|
+
let pendingCloseSessionId = null;
|
|
544
|
+
|
|
545
|
+
function showCloseSessionModal(sessionId, sessionName, createdAt) {
|
|
546
|
+
pendingCloseSessionId = sessionId;
|
|
547
|
+
|
|
548
|
+
// Calculate duration
|
|
549
|
+
const duration = createdAt ? formatDuration(Date.now() - createdAt) : 'Unknown';
|
|
550
|
+
|
|
551
|
+
document.getElementById('close-session-name').textContent = sessionName || 'Session';
|
|
552
|
+
document.getElementById('close-session-duration').textContent = `Duration: ${duration}`;
|
|
553
|
+
document.getElementById('close-session-modal').style.display = 'flex';
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function hideCloseSessionModal() {
|
|
557
|
+
document.getElementById('close-session-modal').style.display = 'none';
|
|
558
|
+
pendingCloseSessionId = null;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function confirmCloseSession() {
|
|
562
|
+
if (pendingCloseSessionId) {
|
|
563
|
+
// Call the actual close function from terminal.js
|
|
564
|
+
doCloseSession(pendingCloseSessionId);
|
|
565
|
+
}
|
|
566
|
+
hideCloseSessionModal();
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function formatDuration(ms) {
|
|
570
|
+
const seconds = Math.floor(ms / 1000);
|
|
571
|
+
const minutes = Math.floor(seconds / 60);
|
|
572
|
+
const hours = Math.floor(minutes / 60);
|
|
573
|
+
const days = Math.floor(hours / 24);
|
|
574
|
+
|
|
575
|
+
if (days > 0) return `${days}d ${hours % 24}h`;
|
|
576
|
+
if (hours > 0) return `${hours}h ${minutes % 60}m`;
|
|
577
|
+
if (minutes > 0) return `${minutes} minute${minutes !== 1 ? 's' : ''}`;
|
|
578
|
+
return `${seconds} second${seconds !== 1 ? 's' : ''}`;
|
|
579
|
+
}
|
|
580
|
+
</script>
|
|
581
|
+
|
|
505
582
|
<script src="/app/terminal.js?v=1.5.88"></script>
|
|
506
583
|
</body>
|
|
507
584
|
</html>
|
package/public/app/terminal.js
CHANGED
|
@@ -1025,17 +1025,27 @@ function updateUrlWithSession(sessionId) {
|
|
|
1025
1025
|
console.log('[CLIENT] 📍 URL updated with session:', sessionId);
|
|
1026
1026
|
}
|
|
1027
1027
|
|
|
1028
|
-
// Close a session with confirmation
|
|
1028
|
+
// Close a session with confirmation - shows custom modal
|
|
1029
1029
|
function closeSession(sessionId, event) {
|
|
1030
1030
|
event.stopPropagation(); // Don't trigger tab switch
|
|
1031
1031
|
|
|
1032
1032
|
const session = availableSessions.find(s => s.id === sessionId);
|
|
1033
1033
|
const sessionName = session?.name || 'this session';
|
|
1034
|
+
const createdAt = session?.createdAt || null;
|
|
1034
1035
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1036
|
+
// Show custom modal instead of browser confirm()
|
|
1037
|
+
if (typeof showCloseSessionModal === 'function') {
|
|
1038
|
+
showCloseSessionModal(sessionId, sessionName, createdAt);
|
|
1039
|
+
} else {
|
|
1040
|
+
// Fallback to native confirm if modal not available
|
|
1041
|
+
if (confirm(`Close "${sessionName}"?\n\nThis will terminate the terminal session.`)) {
|
|
1042
|
+
doCloseSession(sessionId);
|
|
1043
|
+
}
|
|
1037
1044
|
}
|
|
1045
|
+
}
|
|
1038
1046
|
|
|
1047
|
+
// Actually close the session (called from modal confirmation)
|
|
1048
|
+
function doCloseSession(sessionId) {
|
|
1039
1049
|
console.log('[CLIENT] 🗑️ Closing session:', sessionId);
|
|
1040
1050
|
|
|
1041
1051
|
// Send close request to agent
|