shell-mirror 1.5.107 → 1.5.109
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 +26 -4
- package/package.json +1 -1
- package/public/app/terminal.html +3 -7
- package/public/app/terminal.js +31 -23
package/mac-agent/agent.js
CHANGED
|
@@ -980,19 +980,41 @@ function setupDataChannel(clientId) {
|
|
|
980
980
|
// Handle session closure request from client
|
|
981
981
|
logToFile(`[AGENT] Client ${clientId} closing session ${message.sessionId}`);
|
|
982
982
|
|
|
983
|
-
|
|
983
|
+
// Get remaining sessions BEFORE termination
|
|
984
|
+
const closingSessionId = message.sessionId;
|
|
985
|
+
sessionManager.terminateSession(closingSessionId);
|
|
986
|
+
|
|
987
|
+
const remainingSessions = sessionManager.getAllSessions();
|
|
984
988
|
|
|
985
989
|
// Send confirmation with updated session list
|
|
986
990
|
dataChannel.send(JSON.stringify({
|
|
987
991
|
type: 'session-closed',
|
|
988
|
-
sessionId:
|
|
989
|
-
availableSessions:
|
|
992
|
+
sessionId: closingSessionId,
|
|
993
|
+
availableSessions: remainingSessions
|
|
990
994
|
}));
|
|
991
995
|
|
|
996
|
+
// If client requested auto-switch to next session, do it atomically
|
|
997
|
+
if (message.switchToSessionId && remainingSessions.find(s => s.id === message.switchToSessionId)) {
|
|
998
|
+
logToFile(`[AGENT] Auto-switching client to session ${message.switchToSessionId}`);
|
|
999
|
+
if (sessionManager.connectClientToSession(clientId, message.switchToSessionId)) {
|
|
1000
|
+
const newSession = sessionManager.getSession(message.switchToSessionId);
|
|
1001
|
+
dataChannel.send(JSON.stringify({
|
|
1002
|
+
type: 'session-switched',
|
|
1003
|
+
sessionId: message.switchToSessionId,
|
|
1004
|
+
sessionName: newSession.name
|
|
1005
|
+
}));
|
|
1006
|
+
// Send buffered output
|
|
1007
|
+
const bufferedOutput = newSession.buffer.getAll();
|
|
1008
|
+
if (bufferedOutput) {
|
|
1009
|
+
sendLargeMessage(dataChannel, { type: 'output', data: bufferedOutput }, '[AGENT]');
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
992
1014
|
// Send immediate heartbeat to update dashboard
|
|
993
1015
|
sendHeartbeat();
|
|
994
1016
|
|
|
995
|
-
logToFile(`[AGENT] ✅ Session closed: ${
|
|
1017
|
+
logToFile(`[AGENT] ✅ Session closed: ${closingSessionId}`);
|
|
996
1018
|
}
|
|
997
1019
|
} catch (err) {
|
|
998
1020
|
logToFile(`[AGENT] Error parsing data channel message: ${err.message}`);
|
package/package.json
CHANGED
package/public/app/terminal.html
CHANGED
|
@@ -176,12 +176,8 @@
|
|
|
176
176
|
font-weight: 600;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
.session-tab-
|
|
180
|
-
|
|
181
|
-
border: none;
|
|
182
|
-
color: inherit;
|
|
183
|
-
font: inherit;
|
|
184
|
-
cursor: pointer;
|
|
179
|
+
.session-tab-name {
|
|
180
|
+
flex: 1;
|
|
185
181
|
padding: 2px 4px;
|
|
186
182
|
}
|
|
187
183
|
|
|
@@ -576,6 +572,6 @@
|
|
|
576
572
|
}
|
|
577
573
|
</script>
|
|
578
574
|
|
|
579
|
-
<script src="/app/terminal.js?v=1.5.
|
|
575
|
+
<script src="/app/terminal.js?v=1.5.93"></script>
|
|
580
576
|
</body>
|
|
581
577
|
</html>
|
package/public/app/terminal.js
CHANGED
|
@@ -1030,13 +1030,9 @@ function renderTabs() {
|
|
|
1030
1030
|
: `color: ${color.muted};`;
|
|
1031
1031
|
|
|
1032
1032
|
return `
|
|
1033
|
-
<div class="session-tab ${isActive ? 'active' : ''}" style="${tabStyle}" title="${displayName}" data-color-index="${sessionColorMap[session.id]}">
|
|
1034
|
-
<
|
|
1035
|
-
|
|
1036
|
-
style="${textStyle}">
|
|
1037
|
-
<span class="session-tab-name">${displayName}</span>
|
|
1038
|
-
</button>
|
|
1039
|
-
<button class="session-tab-close" onclick="closeSession('${session.id}', event)" title="Close session" style="color: ${isActive ? color.text : color.muted}">×</button>
|
|
1033
|
+
<div class="session-tab ${isActive ? 'active' : ''}" style="${tabStyle}; cursor: pointer;" title="${displayName}" data-color-index="${sessionColorMap[session.id]}" onclick="switchToSession('${session.id}')">
|
|
1034
|
+
<span class="session-tab-name" style="${textStyle}">${displayName}</span>
|
|
1035
|
+
<button class="session-tab-close" onclick="event.stopPropagation(); closeSession('${session.id}', event)" title="Close session" style="color: ${isActive ? color.text : color.muted}">×</button>
|
|
1040
1036
|
</div>
|
|
1041
1037
|
`;
|
|
1042
1038
|
}).join('');
|
|
@@ -1080,10 +1076,16 @@ function closeSession(sessionId, event) {
|
|
|
1080
1076
|
function doCloseSession(sessionId) {
|
|
1081
1077
|
console.log('[CLIENT] 🗑️ Closing session:', sessionId);
|
|
1082
1078
|
|
|
1083
|
-
//
|
|
1079
|
+
// Remove from available sessions
|
|
1080
|
+
const remainingSessions = availableSessions.filter(s => s.id !== sessionId);
|
|
1081
|
+
const isClosingCurrentSession = currentSession && currentSession.id === sessionId;
|
|
1082
|
+
const nextSession = isClosingCurrentSession && remainingSessions.length > 0 ? remainingSessions[0] : null;
|
|
1083
|
+
|
|
1084
|
+
// Send close request to agent (with auto-switch if closing active session)
|
|
1084
1085
|
const closeMessage = {
|
|
1085
1086
|
type: 'close_session',
|
|
1086
|
-
sessionId: sessionId
|
|
1087
|
+
sessionId: sessionId,
|
|
1088
|
+
switchToSessionId: nextSession ? nextSession.id : null // Atomic close + switch
|
|
1087
1089
|
};
|
|
1088
1090
|
|
|
1089
1091
|
if (dataChannel && dataChannel.readyState === 'open') {
|
|
@@ -1092,25 +1094,25 @@ function doCloseSession(sessionId) {
|
|
|
1092
1094
|
ws.send(JSON.stringify(closeMessage));
|
|
1093
1095
|
}
|
|
1094
1096
|
|
|
1095
|
-
//
|
|
1096
|
-
availableSessions =
|
|
1097
|
+
// Update local state
|
|
1098
|
+
availableSessions = remainingSessions;
|
|
1097
1099
|
|
|
1098
|
-
// If closing current session,
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1100
|
+
// If closing current session, update UI immediately
|
|
1101
|
+
if (isClosingCurrentSession) {
|
|
1102
|
+
// Clear terminal IMMEDIATELY to prevent garbage from closed session
|
|
1103
|
+
term.clear();
|
|
1104
|
+
|
|
1105
|
+
if (nextSession) {
|
|
1101
1106
|
// Update currentSession IMMEDIATELY so renderTabs shows correct active tab
|
|
1102
|
-
const nextSession = availableSessions[0];
|
|
1103
1107
|
currentSession = {
|
|
1104
1108
|
id: nextSession.id,
|
|
1105
1109
|
name: nextSession.name || 'Terminal Session'
|
|
1106
1110
|
};
|
|
1107
|
-
// Tell agent to switch (will send session-switched confirmation)
|
|
1108
|
-
switchToSession(nextSession.id);
|
|
1109
1111
|
// Update URL
|
|
1110
1112
|
updateUrlWithSession(nextSession.id);
|
|
1113
|
+
// Note: Agent will send session-switched with buffered output
|
|
1111
1114
|
} else {
|
|
1112
1115
|
currentSession = null;
|
|
1113
|
-
term.clear();
|
|
1114
1116
|
term.write('\r\n\x1b[33mSession closed. Click + to create a new session.\x1b[0m\r\n');
|
|
1115
1117
|
}
|
|
1116
1118
|
}
|
|
@@ -1258,14 +1260,20 @@ function handleSessionMessage(message) {
|
|
|
1258
1260
|
term.focus();
|
|
1259
1261
|
break;
|
|
1260
1262
|
case 'session-ended':
|
|
1261
|
-
|
|
1262
|
-
if (message.
|
|
1263
|
-
term.write(
|
|
1263
|
+
// Only show if this is for the current session (ignore closed session messages)
|
|
1264
|
+
if (!message.sessionId || (currentSession && message.sessionId === currentSession.id)) {
|
|
1265
|
+
term.write(`\r\n\x1b[31m❌ Session ended: ${message.reason}\x1b[0m\r\n`);
|
|
1266
|
+
if (message.code) {
|
|
1267
|
+
term.write(`Exit code: ${message.code}\r\n`);
|
|
1268
|
+
}
|
|
1264
1269
|
}
|
|
1265
1270
|
break;
|
|
1266
1271
|
case 'session-terminated':
|
|
1267
|
-
|
|
1268
|
-
|
|
1272
|
+
// Only show if this is for the current session (ignore closed session messages)
|
|
1273
|
+
if (!message.sessionId || (currentSession && message.sessionId === currentSession.id)) {
|
|
1274
|
+
term.write(`\r\n\x1b[31m❌ Session terminated\x1b[0m\r\n`);
|
|
1275
|
+
term.write('🔄 Click Dashboard to start a new session\r\n');
|
|
1276
|
+
}
|
|
1269
1277
|
break;
|
|
1270
1278
|
case 'session-closed':
|
|
1271
1279
|
console.log('[CLIENT] ✅ Session closed confirmed:', message.sessionId);
|