claude-opencode-viewer 2.6.20 → 2.6.22

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.
Files changed (3) hide show
  1. package/index-pc.html +9 -1
  2. package/package.json +1 -1
  3. package/server.js +39 -26
package/index-pc.html CHANGED
@@ -848,10 +848,18 @@
848
848
  }
849
849
 
850
850
  // PC端尺寸计算
851
+ var resizeRetryCount = 0;
851
852
  function resize() {
852
853
  var container = document.getElementById('terminal');
853
854
  var cellDims = getCellDims();
854
- if (!cellDims) return;
855
+ if (!cellDims) {
856
+ if (resizeRetryCount < 10) {
857
+ resizeRetryCount++;
858
+ setTimeout(resize, 200);
859
+ }
860
+ return;
861
+ }
862
+ resizeRetryCount = 0;
855
863
  var charW = cellDims.width;
856
864
  var charH = cellDims.height;
857
865
  var availW = container.clientWidth;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-opencode-viewer",
3
- "version": "2.6.20",
3
+ "version": "2.6.22",
4
4
  "description": "A unified terminal viewer for Claude Code and OpenCode with seamless switching",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -16,7 +16,7 @@ process.title = 'claude-opencode-viewer';
16
16
 
17
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
18
  const IS_PC = process.argv.includes('--pc');
19
- let PORT = parseInt(process.argv[2]) || (IS_PC ? 19200 : 7008);
19
+ const PORT = parseInt(process.argv[2]) || 7008;
20
20
  const USE_HTTPS = process.argv.includes('--https');
21
21
  const JSON_OUTPUT = process.argv.includes('--json');
22
22
 
@@ -162,6 +162,26 @@ function findCommand(cmd) {
162
162
  return cmd;
163
163
  }
164
164
 
165
+ function killProcessTree(proc) {
166
+ if (!proc || !proc.pid) return;
167
+ const pid = proc.pid;
168
+ // 1. 尝试杀整个进程组(负 PID)
169
+ try { process.kill(-pid, 'SIGTERM'); } catch {}
170
+ // 2. 杀 pty 进程本身
171
+ try { proc.kill(); } catch {}
172
+ // 3. 1秒后检查,如果还活着就 SIGKILL 强杀
173
+ setTimeout(() => {
174
+ try {
175
+ process.kill(-pid, 0); // 检查进程组是否还在
176
+ process.kill(-pid, 'SIGKILL');
177
+ } catch {}
178
+ try {
179
+ process.kill(pid, 0);
180
+ process.kill(pid, 'SIGKILL');
181
+ } catch {}
182
+ }, 1000);
183
+ }
184
+
165
185
  async function spawnProcess(mode, sessionId = null) {
166
186
  const pty = await getPty();
167
187
  fixSpawnHelperPermissions();
@@ -245,7 +265,7 @@ async function spawnProcess(mode, sessionId = null) {
245
265
  if (claudeProcess && claudeProcess !== proc && claudeProcess.pid) {
246
266
  try {
247
267
  console.log(`[spawnProcess] 清理旧 claude 进程 PID: ${claudeProcess.pid}`);
248
- claudeProcess.kill();
268
+ killProcessTree(claudeProcess);
249
269
  } catch {}
250
270
  }
251
271
  claudeProcess = proc;
@@ -253,7 +273,7 @@ async function spawnProcess(mode, sessionId = null) {
253
273
  if (opencodeProcess && opencodeProcess !== proc && opencodeProcess.pid) {
254
274
  try {
255
275
  console.log(`[spawnProcess] 清理旧 opencode 进程 PID: ${opencodeProcess.pid}`);
256
- opencodeProcess.kill();
276
+ killProcessTree(opencodeProcess);
257
277
  } catch {}
258
278
  }
259
279
  opencodeProcess = proc;
@@ -287,7 +307,7 @@ async function switchMode(newMode) {
287
307
  if (currentMode === 'claude' && claudeProcess) {
288
308
  try {
289
309
  console.log(`[switchMode] 杀死 claude 进程 PID: ${claudeProcess.pid}`);
290
- claudeProcess.kill();
310
+ killProcessTree(claudeProcess);
291
311
  } catch (e) {
292
312
  console.log('[switchMode] 杀死 claude 进程失败:', e.message);
293
313
  }
@@ -295,7 +315,7 @@ async function switchMode(newMode) {
295
315
  } else if (currentMode === 'opencode' && opencodeProcess) {
296
316
  try {
297
317
  console.log(`[switchMode] 杀死 opencode 进程 PID: ${opencodeProcess.pid}`);
298
- opencodeProcess.kill();
318
+ killProcessTree(opencodeProcess);
299
319
  } catch (e) {
300
320
  console.log('[switchMode] 杀死 opencode 进程失败:', e.message);
301
321
  }
@@ -701,7 +721,7 @@ wssInst.on('connection', (ws, req) => {
701
721
  const sid = currentSessionId;
702
722
  try {
703
723
  if (opencodeProcess) {
704
- opencodeProcess.kill();
724
+ killProcessTree(opencodeProcess);
705
725
  opencodeProcess = null;
706
726
  currentProcess = null;
707
727
  }
@@ -797,7 +817,7 @@ wssInst.on('connection', (ws, req) => {
797
817
  if (opencodeProcess) {
798
818
  try {
799
819
  console.log(`[restore] 杀死当前进程 PID: ${opencodeProcess.pid}`);
800
- opencodeProcess.kill();
820
+ killProcessTree(opencodeProcess);
801
821
  } catch (e) {
802
822
  console.log('[restore] 杀死进程失败:', e.message);
803
823
  }
@@ -843,11 +863,11 @@ wssInst.on('connection', (ws, req) => {
843
863
  currentSessionId = null; // 立即清除旧会话 ID
844
864
 
845
865
  if (mode === 'opencode' && opencodeProcess) {
846
- try { opencodeProcess.kill(); } catch {}
866
+ try { killProcessTree(opencodeProcess); } catch {}
847
867
  opencodeProcess = null;
848
868
  currentProcess = null;
849
869
  } else if (mode === 'claude' && claudeProcess) {
850
- try { claudeProcess.kill(); } catch {}
870
+ try { killProcessTree(claudeProcess); } catch {}
851
871
  claudeProcess = null;
852
872
  currentProcess = null;
853
873
  }
@@ -920,15 +940,15 @@ wssInst.on('connection', (ws, req) => {
920
940
 
921
941
  createServerAndWss();
922
942
 
923
- process.on('SIGINT', () => process.exit(0));
924
- process.on('SIGTERM', () => process.exit(0));
925
-
926
- // 端口范围,用于端口冲突重试
927
- const PORT_MIN = IS_PC ? 19200 : 7008;
928
- const PORT_MAX = IS_PC ? 19220 : 7028;
929
- const MAX_PORT_RETRIES = 20;
943
+ function cleanupAndExit() {
944
+ if (claudeProcess) killProcessTree(claudeProcess);
945
+ if (opencodeProcess) killProcessTree(opencodeProcess);
946
+ setTimeout(() => process.exit(0), 500);
947
+ }
948
+ process.on('SIGINT', cleanupAndExit);
949
+ process.on('SIGTERM', cleanupAndExit);
930
950
 
931
- function startServer(retries = 0) {
951
+ function startServer() {
932
952
  server.listen(PORT, '0.0.0.0', async () => {
933
953
  const ip = getLocalIp();
934
954
  const proto = USE_HTTPS ? 'https' : 'http';
@@ -966,15 +986,8 @@ function startServer(retries = 0) {
966
986
  });
967
987
 
968
988
  server.on('error', (err) => {
969
- if (err.code === 'EADDRINUSE' && retries < MAX_PORT_RETRIES) {
970
- const oldPort = PORT;
971
- PORT = PORT >= PORT_MAX ? PORT_MIN : PORT + 1;
972
- console.error(`[port] ${oldPort} 已占用,尝试 ${PORT} (${retries + 1}/${MAX_PORT_RETRIES})`);
973
- createServerAndWss();
974
- startServer(retries + 1);
975
- } else {
976
- console.error(`启动失败: ${err.message}`);
977
- process.exit(1);
989
+ console.error(`启动失败: ${err.message}`);
990
+ process.exit(1);
978
991
  }
979
992
  });
980
993
  }