claude-opencode-viewer 2.6.54 → 2.6.55

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/index-pc.html CHANGED
@@ -959,6 +959,7 @@
959
959
  <option value="" disabled selected hidden>--</option>
960
960
  <option value="opencode">OpenCode</option>
961
961
  <option value="claude">Claude</option>
962
+ <option value="qoder">Qoder</option>
962
963
  <option value="shell">Shell</option>
963
964
  </select>
964
965
  </div>
@@ -1679,7 +1680,7 @@
1679
1680
  currentMode = mode;
1680
1681
  modeSelect.value = mode;
1681
1682
  document.getElementById('mode-label').textContent = '';
1682
- var label = mode === 'claude' ? 'Claude' : mode === 'shell' ? 'Shell' : 'OpenCode';
1683
+ var label = mode === 'claude' ? 'Claude' : mode === 'shell' ? 'Shell' : mode === 'qoder' ? 'Qoder' : 'OpenCode';
1683
1684
  var initOv = document.getElementById('init-overlay');
1684
1685
  initOv.textContent = '正在启动 ' + label + (sessionId ? '(恢复会话)' : '');
1685
1686
  initOv.classList.add('visible');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-opencode-viewer",
3
- "version": "2.6.54",
3
+ "version": "2.6.55",
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
@@ -91,6 +91,7 @@ let ptyModule = null;
91
91
  let claudeProcess = null;
92
92
  let opencodeProcess = null;
93
93
  let shellProcess = null;
94
+ let qoderProcess = null;
94
95
  let currentProcess = null;
95
96
  let outputBuffer = '';
96
97
  const dataListeners = [];
@@ -248,6 +249,10 @@ async function spawnProcess(mode, sessionId = null) {
248
249
  command = process.env.SHELL || (existsSync('/bin/zsh') ? '/bin/zsh' : '/bin/bash');
249
250
  args = ['-l']; // 登录 shell,加载 PATH/alias
250
251
  LOG(`[shell] 启动 shell: ${command} ${args.join(' ')}`);
252
+ } else if (mode === 'qoder') {
253
+ command = findCommand('qodercli');
254
+ args = [];
255
+ LOG(`[qoder] 启动 qodercli: ${command}`);
251
256
  } else {
252
257
  const t2 = Date.now();
253
258
  command = findCommand('opencode');
@@ -345,6 +350,9 @@ async function spawnProcess(mode, sessionId = null) {
345
350
  if (shellProcess === proc) {
346
351
  shellProcess = null;
347
352
  }
353
+ if (qoderProcess === proc) {
354
+ qoderProcess = null;
355
+ }
348
356
  // 已被替换的旧进程或切换中的进程,不通知前端
349
357
  if (isSwitching || currentProcess !== null) return;
350
358
  exitListeners.forEach(cb => cb(exitCode || 0));
@@ -367,6 +375,14 @@ async function spawnProcess(mode, sessionId = null) {
367
375
  } catch {}
368
376
  }
369
377
  shellProcess = proc;
378
+ } else if (mode === 'qoder') {
379
+ if (qoderProcess && qoderProcess !== proc && qoderProcess.pid) {
380
+ try {
381
+ LOG(`[spawnProcess] 清理旧 qoder 进程 PID: ${qoderProcess.pid}`);
382
+ killProcessTree(qoderProcess);
383
+ } catch {}
384
+ }
385
+ qoderProcess = proc;
370
386
  } else {
371
387
  if (opencodeProcess && opencodeProcess !== proc && opencodeProcess.pid) {
372
388
  try {
@@ -387,7 +403,7 @@ async function spawnProcess(mode, sessionId = null) {
387
403
  }
388
404
 
389
405
  currentProcess = proc;
390
- const modeLabel = mode === 'claude' ? 'Claude Code' : mode === 'shell' ? 'Shell' : 'OpenCode';
406
+ const modeLabel = mode === 'claude' ? 'Claude Code' : mode === 'shell' ? 'Shell' : mode === 'qoder' ? 'Qoder' : 'OpenCode';
391
407
  LOG(`[claude-opencode-viewer] ${modeLabel} 已启动 (PID: ${proc.pid})`);
392
408
  return proc;
393
409
  }
@@ -427,6 +443,14 @@ async function switchMode(newMode) {
427
443
  LOG('[switchMode] 杀死 shell 进程失败:', e.message);
428
444
  }
429
445
  shellProcess = null;
446
+ } else if (currentMode === 'qoder' && qoderProcess) {
447
+ try {
448
+ LOG(`[switchMode] 杀死 qoder 进程 PID: ${qoderProcess.pid}`);
449
+ killProcessTree(qoderProcess);
450
+ } catch (e) {
451
+ LOG('[switchMode] 杀死 qoder 进程失败:', e.message);
452
+ }
453
+ qoderProcess = null;
430
454
  }
431
455
  currentProcess = null;
432
456
 
@@ -1260,7 +1284,7 @@ wssInst.on('connection', (ws, req) => {
1260
1284
  // 进程已退出时,自动重新启动(参考 cc-viewer 逻辑)
1261
1285
  // 模式切换/新建会话期间不触发 respawn
1262
1286
  // shell 模式不自动 respawn,避免用户输入 exit 后又被重新拉起
1263
- if (!currentProcess && !isSwitching && currentMode !== 'shell') {
1287
+ if (!currentProcess && !isSwitching && currentMode !== 'shell' && currentMode !== 'qoder') {
1264
1288
  try {
1265
1289
  LOG(`[respawn] 进程已退出,自动重新启动 ${currentMode}`);
1266
1290
  outputBuffer = '';
@@ -1523,13 +1547,13 @@ function startServer() {
1523
1547
  cleanupOrphanProcesses();
1524
1548
 
1525
1549
  if (INIT_SHELL) {
1526
- // --shell 模式:启动时直接进入 shell,跳过启动对话框
1527
- currentMode = 'shell';
1550
+ // PC端默认进入 Qoder 模式
1551
+ currentMode = 'qoder';
1528
1552
  try {
1529
- await spawnProcess('shell');
1530
- LOG('[startup] Shell 已启动');
1553
+ await spawnProcess('qoder');
1554
+ LOG('[startup] Qoder 已启动');
1531
1555
  } catch (e) {
1532
- LOG('[startup] Shell 启动失败:', e.message);
1556
+ LOG('[startup] Qoder 启动失败:', e.message);
1533
1557
  }
1534
1558
  } else {
1535
1559
  // 延迟启动:等待 PC 客户端发送 init 消息后再 spawn 进程