shell-mirror 1.5.106 → 1.5.108
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 +29 -4
- package/package.json +1 -1
- package/public/app/terminal.html +1 -1
- package/public/app/terminal.js +43 -14
package/mac-agent/agent.js
CHANGED
|
@@ -980,16 +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
|
|
|
992
|
-
|
|
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
|
+
|
|
1014
|
+
// Send immediate heartbeat to update dashboard
|
|
1015
|
+
sendHeartbeat();
|
|
1016
|
+
|
|
1017
|
+
logToFile(`[AGENT] ✅ Session closed: ${closingSessionId}`);
|
|
993
1018
|
}
|
|
994
1019
|
} catch (err) {
|
|
995
1020
|
logToFile(`[AGENT] Error parsing data channel message: ${err.message}`);
|
package/package.json
CHANGED
package/public/app/terminal.html
CHANGED
package/public/app/terminal.js
CHANGED
|
@@ -1080,10 +1080,16 @@ function closeSession(sessionId, event) {
|
|
|
1080
1080
|
function doCloseSession(sessionId) {
|
|
1081
1081
|
console.log('[CLIENT] 🗑️ Closing session:', sessionId);
|
|
1082
1082
|
|
|
1083
|
-
//
|
|
1083
|
+
// Remove from available sessions
|
|
1084
|
+
const remainingSessions = availableSessions.filter(s => s.id !== sessionId);
|
|
1085
|
+
const isClosingCurrentSession = currentSession && currentSession.id === sessionId;
|
|
1086
|
+
const nextSession = isClosingCurrentSession && remainingSessions.length > 0 ? remainingSessions[0] : null;
|
|
1087
|
+
|
|
1088
|
+
// Send close request to agent (with auto-switch if closing active session)
|
|
1084
1089
|
const closeMessage = {
|
|
1085
1090
|
type: 'close_session',
|
|
1086
|
-
sessionId: sessionId
|
|
1091
|
+
sessionId: sessionId,
|
|
1092
|
+
switchToSessionId: nextSession ? nextSession.id : null // Atomic close + switch
|
|
1087
1093
|
};
|
|
1088
1094
|
|
|
1089
1095
|
if (dataChannel && dataChannel.readyState === 'open') {
|
|
@@ -1092,16 +1098,25 @@ function doCloseSession(sessionId) {
|
|
|
1092
1098
|
ws.send(JSON.stringify(closeMessage));
|
|
1093
1099
|
}
|
|
1094
1100
|
|
|
1095
|
-
//
|
|
1096
|
-
availableSessions =
|
|
1101
|
+
// Update local state
|
|
1102
|
+
availableSessions = remainingSessions;
|
|
1097
1103
|
|
|
1098
|
-
// If closing current session,
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1101
|
-
|
|
1104
|
+
// If closing current session, update UI immediately
|
|
1105
|
+
if (isClosingCurrentSession) {
|
|
1106
|
+
// Clear terminal IMMEDIATELY to prevent garbage from closed session
|
|
1107
|
+
term.clear();
|
|
1108
|
+
|
|
1109
|
+
if (nextSession) {
|
|
1110
|
+
// Update currentSession IMMEDIATELY so renderTabs shows correct active tab
|
|
1111
|
+
currentSession = {
|
|
1112
|
+
id: nextSession.id,
|
|
1113
|
+
name: nextSession.name || 'Terminal Session'
|
|
1114
|
+
};
|
|
1115
|
+
// Update URL
|
|
1116
|
+
updateUrlWithSession(nextSession.id);
|
|
1117
|
+
// Note: Agent will send session-switched with buffered output
|
|
1102
1118
|
} else {
|
|
1103
1119
|
currentSession = null;
|
|
1104
|
-
term.clear();
|
|
1105
1120
|
term.write('\r\n\x1b[33mSession closed. Click + to create a new session.\x1b[0m\r\n');
|
|
1106
1121
|
}
|
|
1107
1122
|
}
|
|
@@ -1249,14 +1264,28 @@ function handleSessionMessage(message) {
|
|
|
1249
1264
|
term.focus();
|
|
1250
1265
|
break;
|
|
1251
1266
|
case 'session-ended':
|
|
1252
|
-
|
|
1253
|
-
if (message.
|
|
1254
|
-
term.write(
|
|
1267
|
+
// Only show if this is for the current session (ignore closed session messages)
|
|
1268
|
+
if (!message.sessionId || (currentSession && message.sessionId === currentSession.id)) {
|
|
1269
|
+
term.write(`\r\n\x1b[31m❌ Session ended: ${message.reason}\x1b[0m\r\n`);
|
|
1270
|
+
if (message.code) {
|
|
1271
|
+
term.write(`Exit code: ${message.code}\r\n`);
|
|
1272
|
+
}
|
|
1255
1273
|
}
|
|
1256
1274
|
break;
|
|
1257
1275
|
case 'session-terminated':
|
|
1258
|
-
|
|
1259
|
-
|
|
1276
|
+
// Only show if this is for the current session (ignore closed session messages)
|
|
1277
|
+
if (!message.sessionId || (currentSession && message.sessionId === currentSession.id)) {
|
|
1278
|
+
term.write(`\r\n\x1b[31m❌ Session terminated\x1b[0m\r\n`);
|
|
1279
|
+
term.write('🔄 Click Dashboard to start a new session\r\n');
|
|
1280
|
+
}
|
|
1281
|
+
break;
|
|
1282
|
+
case 'session-closed':
|
|
1283
|
+
console.log('[CLIENT] ✅ Session closed confirmed:', message.sessionId);
|
|
1284
|
+
// Update available sessions from server response
|
|
1285
|
+
if (message.availableSessions) {
|
|
1286
|
+
availableSessions = message.availableSessions;
|
|
1287
|
+
renderTabs();
|
|
1288
|
+
}
|
|
1260
1289
|
break;
|
|
1261
1290
|
case 'error':
|
|
1262
1291
|
term.write(`\r\n\x1b[31m❌ Error: ${message.message}\x1b[0m\r\n`);
|