shell-mirror 1.5.107 → 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 +26 -4
- package/package.json +1 -1
- package/public/app/terminal.html +1 -1
- package/public/app/terminal.js +28 -16
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
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,25 +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
|
-
|
|
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) {
|
|
1101
1110
|
// Update currentSession IMMEDIATELY so renderTabs shows correct active tab
|
|
1102
|
-
const nextSession = availableSessions[0];
|
|
1103
1111
|
currentSession = {
|
|
1104
1112
|
id: nextSession.id,
|
|
1105
1113
|
name: nextSession.name || 'Terminal Session'
|
|
1106
1114
|
};
|
|
1107
|
-
// Tell agent to switch (will send session-switched confirmation)
|
|
1108
|
-
switchToSession(nextSession.id);
|
|
1109
1115
|
// Update URL
|
|
1110
1116
|
updateUrlWithSession(nextSession.id);
|
|
1117
|
+
// Note: Agent will send session-switched with buffered output
|
|
1111
1118
|
} else {
|
|
1112
1119
|
currentSession = null;
|
|
1113
|
-
term.clear();
|
|
1114
1120
|
term.write('\r\n\x1b[33mSession closed. Click + to create a new session.\x1b[0m\r\n');
|
|
1115
1121
|
}
|
|
1116
1122
|
}
|
|
@@ -1258,14 +1264,20 @@ function handleSessionMessage(message) {
|
|
|
1258
1264
|
term.focus();
|
|
1259
1265
|
break;
|
|
1260
1266
|
case 'session-ended':
|
|
1261
|
-
|
|
1262
|
-
if (message.
|
|
1263
|
-
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
|
+
}
|
|
1264
1273
|
}
|
|
1265
1274
|
break;
|
|
1266
1275
|
case 'session-terminated':
|
|
1267
|
-
|
|
1268
|
-
|
|
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
|
+
}
|
|
1269
1281
|
break;
|
|
1270
1282
|
case 'session-closed':
|
|
1271
1283
|
console.log('[CLIENT] ✅ Session closed confirmed:', message.sessionId);
|