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.
- package/mac-agent/agent.js +15 -0
- package/package.json +1 -1
- package/public/app/terminal.html +1 -27
- package/public/app/terminal.js +53 -33
package/mac-agent/agent.js
CHANGED
|
@@ -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
package/public/app/terminal.html
CHANGED
|
@@ -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
|
|
370
|
+
<span class="btn-text">Dashboard</span>
|
|
397
371
|
</a>
|
|
398
372
|
</div>
|
|
399
373
|
</div>
|
package/public/app/terminal.js
CHANGED
|
@@ -153,24 +153,7 @@ const chunkAssembler = {
|
|
|
153
153
|
|
|
154
154
|
// Connection status management
|
|
155
155
|
function updateConnectionStatus(status) {
|
|
156
|
-
|
|
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)
|
|
932
|
+
if (!tabBar) {
|
|
933
|
+
console.warn('[CLIENT] â ī¸ session-tab-bar element not found');
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
940
936
|
|
|
941
|
-
//
|
|
942
|
-
|
|
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 (
|
|
948
|
-
tabsHTML =
|
|
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
|
-
|
|
955
|
-
<span class="session-tab-
|
|
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
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
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) {
|