shell-mirror 1.5.41 → 1.5.43
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 +6 -0
- package/package.json +1 -1
- package/public/app/dashboard.js +77 -28
- package/public/app/terminal.js +55 -0
package/mac-agent/agent.js
CHANGED
|
@@ -146,6 +146,12 @@ class SessionManager {
|
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
+
// Send initial prompt after terminal is ready
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
// Send a newline to trigger the shell prompt
|
|
152
|
+
terminal.write('\n');
|
|
153
|
+
}, 500);
|
|
154
|
+
|
|
149
155
|
terminal.on('exit', (code) => {
|
|
150
156
|
logToFile(`[SESSION] Terminal process exited for session ${sessionId} with code ${code}`);
|
|
151
157
|
session.status = 'crashed';
|
package/package.json
CHANGED
package/public/app/dashboard.js
CHANGED
|
@@ -82,30 +82,8 @@ class ShellMirrorDashboard {
|
|
|
82
82
|
if (agentsData.success && agentsData.data && agentsData.data.agents) {
|
|
83
83
|
this.agents = agentsData.data.agents;
|
|
84
84
|
|
|
85
|
-
//
|
|
86
|
-
this.
|
|
87
|
-
if (agent.onlineStatus === 'online') {
|
|
88
|
-
// Mock sessions for online agents
|
|
89
|
-
this.agentSessions[agent.agentId] = [
|
|
90
|
-
{
|
|
91
|
-
id: `ses_${Date.now()}_main`,
|
|
92
|
-
name: 'Main Terminal',
|
|
93
|
-
lastActivity: Date.now() - 5 * 60 * 1000, // 5 minutes ago
|
|
94
|
-
createdAt: Date.now() - 2 * 60 * 60 * 1000, // 2 hours ago
|
|
95
|
-
status: 'active',
|
|
96
|
-
connectedClients: 0
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
id: `ses_${Date.now()}_debug`,
|
|
100
|
-
name: 'Debug Server',
|
|
101
|
-
lastActivity: Date.now() - 15 * 60 * 1000, // 15 minutes ago
|
|
102
|
-
createdAt: Date.now() - 1 * 60 * 60 * 1000, // 1 hour ago
|
|
103
|
-
status: 'active',
|
|
104
|
-
connectedClients: 0
|
|
105
|
-
}
|
|
106
|
-
];
|
|
107
|
-
}
|
|
108
|
-
});
|
|
85
|
+
// Load session data from localStorage (persisted from terminal connections)
|
|
86
|
+
this.loadSessionsFromStorage();
|
|
109
87
|
}
|
|
110
88
|
|
|
111
89
|
// TODO: Load session history when API is available
|
|
@@ -214,10 +192,10 @@ class ShellMirrorDashboard {
|
|
|
214
192
|
</div>
|
|
215
193
|
<div class="agent-actions">
|
|
216
194
|
<button class="btn-connect" onclick="dashboard.connectToAgent('${agent.agentId}')">
|
|
217
|
-
New Session
|
|
195
|
+
${sessionCount > 0 ? 'Resume Session' : 'New Session'}
|
|
218
196
|
</button>
|
|
219
197
|
${sessionCount > 0 ? `<button class="btn-sessions" onclick="dashboard.showAgentSessions('${agent.agentId}')">
|
|
220
|
-
|
|
198
|
+
All Sessions
|
|
221
199
|
</button>` : ''}
|
|
222
200
|
</div>
|
|
223
201
|
</div>
|
|
@@ -435,13 +413,40 @@ class ShellMirrorDashboard {
|
|
|
435
413
|
|
|
436
414
|
// Action handlers
|
|
437
415
|
async connectToAgent(agentId) {
|
|
438
|
-
|
|
416
|
+
console.log('[DASHBOARD] 🔍 DEBUG: connectToAgent called with agentId:', agentId);
|
|
417
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Current agentSessions:', this.agentSessions);
|
|
418
|
+
|
|
419
|
+
// Check if there are existing sessions for this agent
|
|
420
|
+
const sessions = this.agentSessions[agentId] || [];
|
|
421
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Sessions for agent:', sessions);
|
|
422
|
+
|
|
423
|
+
const activeSessions = sessions.filter(s => s.status === 'active');
|
|
424
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Active sessions:', activeSessions);
|
|
425
|
+
|
|
426
|
+
if (activeSessions.length > 0) {
|
|
427
|
+
// Reconnect to the most recently active session
|
|
428
|
+
const mostRecentSession = activeSessions.reduce((latest, session) =>
|
|
429
|
+
session.lastActivity > latest.lastActivity ? session : latest
|
|
430
|
+
);
|
|
431
|
+
console.log(`[DASHBOARD] ✅ Reconnecting to existing session: ${mostRecentSession.id}`);
|
|
432
|
+
window.location.href = `/app/terminal.html?agent=${agentId}&session=${mostRecentSession.id}`;
|
|
433
|
+
} else {
|
|
434
|
+
// No existing sessions, create new one
|
|
435
|
+
console.log(`[DASHBOARD] 🆕 Creating new session for agent: ${agentId}`);
|
|
436
|
+
window.location.href = `/app/terminal.html?agent=${agentId}`;
|
|
437
|
+
}
|
|
439
438
|
}
|
|
440
439
|
|
|
441
440
|
async connectToSession(agentId, sessionId) {
|
|
442
441
|
window.location.href = `/app/terminal.html?agent=${agentId}&session=${sessionId}`;
|
|
443
442
|
}
|
|
444
443
|
|
|
444
|
+
async createNewSession(agentId) {
|
|
445
|
+
// Force creation of new session by not passing session parameter
|
|
446
|
+
console.log(`[DASHBOARD] Creating new session for agent: ${agentId}`);
|
|
447
|
+
window.location.href = `/app/terminal.html?agent=${agentId}`;
|
|
448
|
+
}
|
|
449
|
+
|
|
445
450
|
startNewSession() {
|
|
446
451
|
// Get first available agent for new session
|
|
447
452
|
const activeAgents = this.agents.filter(agent => {
|
|
@@ -488,7 +493,7 @@ class ShellMirrorDashboard {
|
|
|
488
493
|
${sessionsList}
|
|
489
494
|
</div>
|
|
490
495
|
<div class="sessions-modal-actions">
|
|
491
|
-
<button class="btn-primary" onclick="dashboard.
|
|
496
|
+
<button class="btn-primary" onclick="dashboard.createNewSession('${agentId}')">
|
|
492
497
|
+ Create New Session
|
|
493
498
|
</button>
|
|
494
499
|
</div>
|
|
@@ -530,6 +535,50 @@ class ShellMirrorDashboard {
|
|
|
530
535
|
return `${days}d ago`;
|
|
531
536
|
}
|
|
532
537
|
|
|
538
|
+
// Session storage management
|
|
539
|
+
loadSessionsFromStorage() {
|
|
540
|
+
try {
|
|
541
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Loading sessions from localStorage');
|
|
542
|
+
const storedSessions = localStorage.getItem('shell-mirror-sessions');
|
|
543
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Raw stored sessions:', storedSessions);
|
|
544
|
+
|
|
545
|
+
if (storedSessions) {
|
|
546
|
+
const sessionData = JSON.parse(storedSessions);
|
|
547
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Parsed session data:', sessionData);
|
|
548
|
+
|
|
549
|
+
// Filter out old sessions (older than 24 hours)
|
|
550
|
+
const now = Date.now();
|
|
551
|
+
const maxAge = 24 * 60 * 60 * 1000; // 24 hours
|
|
552
|
+
|
|
553
|
+
Object.keys(sessionData).forEach(agentId => {
|
|
554
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Processing agent:', agentId);
|
|
555
|
+
const allSessions = sessionData[agentId];
|
|
556
|
+
console.log('[DASHBOARD] 🔍 DEBUG: All sessions for agent:', allSessions);
|
|
557
|
+
|
|
558
|
+
const validSessions = allSessions.filter(session => {
|
|
559
|
+
const age = now - session.lastActivity;
|
|
560
|
+
const isValid = age < maxAge;
|
|
561
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Session', session.id, 'age:', age, 'valid:', isValid);
|
|
562
|
+
return isValid;
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
console.log('[DASHBOARD] 🔍 DEBUG: Valid sessions for agent:', validSessions);
|
|
566
|
+
|
|
567
|
+
if (validSessions.length > 0) {
|
|
568
|
+
this.agentSessions[agentId] = validSessions;
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
console.log('[DASHBOARD] ✅ Loaded sessions from storage:', this.agentSessions);
|
|
573
|
+
} else {
|
|
574
|
+
console.log('[DASHBOARD] ⚠️ No stored sessions found in localStorage');
|
|
575
|
+
}
|
|
576
|
+
} catch (error) {
|
|
577
|
+
console.error('[DASHBOARD] ❌ Error loading sessions from storage:', error);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
|
|
533
582
|
showAgentInstructions() {
|
|
534
583
|
// TODO: Show modal with agent setup instructions
|
|
535
584
|
alert('Agent setup instructions coming soon!');
|
package/public/app/terminal.js
CHANGED
|
@@ -84,10 +84,14 @@ window.addEventListener('load', () => {
|
|
|
84
84
|
const agentId = urlParams.get('agent');
|
|
85
85
|
const sessionId = urlParams.get('session');
|
|
86
86
|
|
|
87
|
+
console.log('[CLIENT] 🔍 DEBUG: URL params - agent:', agentId, 'session:', sessionId);
|
|
88
|
+
console.log('[CLIENT] 🔍 DEBUG: Full URL:', window.location.href);
|
|
89
|
+
|
|
87
90
|
if (agentId) {
|
|
88
91
|
AGENT_ID = agentId;
|
|
89
92
|
SELECTED_AGENT = { id: agentId, agentId: agentId };
|
|
90
93
|
requestedSessionId = sessionId; // Store for session request
|
|
94
|
+
console.log('[CLIENT] 🔍 DEBUG: Set requestedSessionId to:', requestedSessionId);
|
|
91
95
|
console.log('[CLIENT] 🔗 Connecting to agent:', agentId, sessionId ? `session: ${sessionId}` : '(new session)');
|
|
92
96
|
startConnection();
|
|
93
97
|
} else {
|
|
@@ -174,6 +178,8 @@ async function initialize() {
|
|
|
174
178
|
|
|
175
179
|
// Build session request
|
|
176
180
|
let sessionRequest = null;
|
|
181
|
+
console.log('[CLIENT] 🔍 DEBUG: Building session request, requestedSessionId:', requestedSessionId);
|
|
182
|
+
|
|
177
183
|
if (requestedSessionId) {
|
|
178
184
|
sessionRequest = { sessionId: requestedSessionId };
|
|
179
185
|
console.log(`[CLIENT] 🎯 Requesting existing session: ${requestedSessionId}`);
|
|
@@ -221,9 +227,13 @@ async function initialize() {
|
|
|
221
227
|
isNewSession: nextData.isNewSession || false
|
|
222
228
|
};
|
|
223
229
|
console.log('[CLIENT] 📋 Session assigned:', currentSession);
|
|
230
|
+
console.log('[CLIENT] 🔍 Agent ID for storage:', AGENT_ID);
|
|
224
231
|
|
|
225
232
|
// Update UI to show session info
|
|
226
233
|
updateSessionDisplay();
|
|
234
|
+
|
|
235
|
+
// Save session info to localStorage for dashboard
|
|
236
|
+
saveSessionToLocalStorage(AGENT_ID, currentSession);
|
|
227
237
|
}
|
|
228
238
|
|
|
229
239
|
if (nextData.availableSessions) {
|
|
@@ -679,6 +689,9 @@ function handleSessionMessage(message) {
|
|
|
679
689
|
updateSessionDisplay();
|
|
680
690
|
term.clear(); // Clear terminal for new session
|
|
681
691
|
console.log('[CLIENT] ✅ Switched to session:', currentSession);
|
|
692
|
+
|
|
693
|
+
// Save updated session info
|
|
694
|
+
saveSessionToLocalStorage(AGENT_ID, currentSession);
|
|
682
695
|
break;
|
|
683
696
|
case 'session-ended':
|
|
684
697
|
term.write(`\r\n\x1b[31m❌ Session ended: ${message.reason}\x1b[0m\r\n`);
|
|
@@ -694,4 +707,46 @@ function handleSessionMessage(message) {
|
|
|
694
707
|
term.write(`\r\n\x1b[31m❌ Error: ${message.message}\x1b[0m\r\n`);
|
|
695
708
|
break;
|
|
696
709
|
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Session storage helper
|
|
713
|
+
function saveSessionToLocalStorage(agentId, sessionInfo) {
|
|
714
|
+
try {
|
|
715
|
+
console.log('[CLIENT] 🔍 DEBUG: Saving session to localStorage');
|
|
716
|
+
console.log('[CLIENT] 🔍 DEBUG: AgentID:', agentId);
|
|
717
|
+
console.log('[CLIENT] 🔍 DEBUG: SessionInfo:', sessionInfo);
|
|
718
|
+
|
|
719
|
+
const storedSessions = localStorage.getItem('shell-mirror-sessions');
|
|
720
|
+
console.log('[CLIENT] 🔍 DEBUG: Current stored sessions:', storedSessions);
|
|
721
|
+
|
|
722
|
+
let sessionData = storedSessions ? JSON.parse(storedSessions) : {};
|
|
723
|
+
|
|
724
|
+
if (!sessionData[agentId]) {
|
|
725
|
+
sessionData[agentId] = [];
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Remove existing session with same ID
|
|
729
|
+
sessionData[agentId] = sessionData[agentId].filter(s => s.id !== sessionInfo.id);
|
|
730
|
+
|
|
731
|
+
// Add updated session info
|
|
732
|
+
const sessionToStore = {
|
|
733
|
+
id: sessionInfo.id,
|
|
734
|
+
name: sessionInfo.name,
|
|
735
|
+
lastActivity: Date.now(),
|
|
736
|
+
createdAt: sessionInfo.createdAt || Date.now(),
|
|
737
|
+
status: 'active'
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
sessionData[agentId].push(sessionToStore);
|
|
741
|
+
|
|
742
|
+
localStorage.setItem('shell-mirror-sessions', JSON.stringify(sessionData));
|
|
743
|
+
console.log('[CLIENT] 💾 Session saved to storage:', sessionToStore);
|
|
744
|
+
console.log('[CLIENT] 🔍 DEBUG: Final stored data:', JSON.stringify(sessionData));
|
|
745
|
+
|
|
746
|
+
// Verify the save worked
|
|
747
|
+
const verification = localStorage.getItem('shell-mirror-sessions');
|
|
748
|
+
console.log('[CLIENT] ✅ DEBUG: Verification read:', verification);
|
|
749
|
+
} catch (error) {
|
|
750
|
+
console.error('[CLIENT] ❌ Error saving session to storage:', error);
|
|
751
|
+
}
|
|
697
752
|
}
|