cc-viewer 1.4.13 → 1.4.15

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/dist/index.html CHANGED
@@ -6,7 +6,7 @@
6
6
  <title>Claude Code Viewer</title>
7
7
  <link rel="icon" href="/favicon.ico?v=1">
8
8
  <link rel="shortcut icon" href="/favicon.ico?v=1">
9
- <script type="module" crossorigin src="/assets/index-B3PatjPN.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-DQNfFa0l.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="/assets/index-ADbGFOYO.css">
11
11
  </head>
12
12
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-viewer",
3
- "version": "1.4.13",
3
+ "version": "1.4.15",
4
4
  "description": "Claude Code Logger visualization management tool",
5
5
  "license": "MIT",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -998,6 +998,25 @@ async function setupTerminalWebSocket(httpServer) {
998
998
 
999
999
  const wss = new WebSocketServer({ noServer: true });
1000
1000
 
1001
+ // 多客户端共享 PTY 的尺寸冲突解决:
1002
+ // 移动端优先——只要有移动端在线,PTY 始终使用移动端尺寸,
1003
+ // PC 端的 resize 仅存储不生效,避免宽屏尺寸导致移动端乱码。
1004
+ // PC 端显示窄输出但完全可读,移动端永远不会乱码。
1005
+ let activeWs = null; // 当前活跃的 WebSocket 连接
1006
+ const clientSizes = new Map(); // ws → { cols, rows }
1007
+ const mobileClients = new Set(); // 移动端连接集合
1008
+
1009
+ // 找到一个在线的移动端并返回其尺寸
1010
+ const getMobileSize = () => {
1011
+ for (const mws of mobileClients) {
1012
+ if (mws.readyState === 1) {
1013
+ const size = clientSizes.get(mws);
1014
+ if (size) return size;
1015
+ }
1016
+ }
1017
+ return null;
1018
+ };
1019
+
1001
1020
  httpServer.on('upgrade', (req, socket, head) => {
1002
1021
  const pathname = new URL(req.url, `http://${req.headers.host}`).pathname;
1003
1022
  if (pathname === '/ws/terminal') {
@@ -1039,9 +1058,33 @@ async function setupTerminalWebSocket(httpServer) {
1039
1058
  try {
1040
1059
  const msg = JSON.parse(raw.toString());
1041
1060
  if (msg.type === 'input') {
1061
+ // 发送 input 的客户端成为活跃客户端
1062
+ if (activeWs !== ws) {
1063
+ activeWs = ws;
1064
+ // 切换活跃客户端时,如果有移动端在线则保持移动端尺寸,
1065
+ // 否则切换到新活跃客户端的尺寸
1066
+ const mSize = getMobileSize();
1067
+ if (mSize) {
1068
+ resizePty(mSize.cols, mSize.rows);
1069
+ } else {
1070
+ const size = clientSizes.get(ws);
1071
+ if (size) {
1072
+ resizePty(size.cols, size.rows);
1073
+ }
1074
+ }
1075
+ }
1042
1076
  writeToPty(msg.data);
1043
1077
  } else if (msg.type === 'resize') {
1044
- resizePty(msg.cols, msg.rows);
1078
+ // 存储该客户端的尺寸
1079
+ clientSizes.set(ws, { cols: msg.cols, rows: msg.rows });
1080
+ if (msg.mobile) mobileClients.add(ws);
1081
+ // 移动端 resize 始终生效;PC 端仅在无移动端时生效
1082
+ if (msg.mobile) {
1083
+ resizePty(msg.cols, msg.rows);
1084
+ } else if (mobileClients.size === 0 && (activeWs === ws || activeWs === null)) {
1085
+ activeWs = ws;
1086
+ resizePty(msg.cols, msg.rows);
1087
+ }
1045
1088
  }
1046
1089
  } catch {}
1047
1090
  });
@@ -1049,6 +1092,25 @@ async function setupTerminalWebSocket(httpServer) {
1049
1092
  ws.on('close', () => {
1050
1093
  removeDataListener();
1051
1094
  removeExitListener();
1095
+ clientSizes.delete(ws);
1096
+ mobileClients.delete(ws);
1097
+ if (activeWs === ws) {
1098
+ // 活跃客户端断开,将控制权交给剩余的某个客户端
1099
+ activeWs = null;
1100
+ // 优先使用移动端尺寸,无移动端则用剩余客户端尺寸
1101
+ const mSize = getMobileSize();
1102
+ if (mSize) {
1103
+ resizePty(mSize.cols, mSize.rows);
1104
+ } else {
1105
+ for (const [remainWs, size] of clientSizes) {
1106
+ if (remainWs.readyState === 1) {
1107
+ activeWs = remainWs;
1108
+ resizePty(size.cols, size.rows);
1109
+ break;
1110
+ }
1111
+ }
1112
+ }
1113
+ }
1052
1114
  });
1053
1115
  });
1054
1116
  } catch (err) {