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 +2 -1
- package/package.json +1 -1
- package/server.js +31 -7
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
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
|
-
//
|
|
1527
|
-
currentMode = '
|
|
1550
|
+
// PC端默认进入 Qoder 模式
|
|
1551
|
+
currentMode = 'qoder';
|
|
1528
1552
|
try {
|
|
1529
|
-
await spawnProcess('
|
|
1530
|
-
LOG('[startup]
|
|
1553
|
+
await spawnProcess('qoder');
|
|
1554
|
+
LOG('[startup] Qoder 已启动');
|
|
1531
1555
|
} catch (e) {
|
|
1532
|
-
LOG('[startup]
|
|
1556
|
+
LOG('[startup] Qoder 启动失败:', e.message);
|
|
1533
1557
|
}
|
|
1534
1558
|
} else {
|
|
1535
1559
|
// 延迟启动:等待 PC 客户端发送 init 消息后再 spawn 进程
|