claude-opencode-viewer 2.6.42 → 2.6.44
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 +26 -28
- package/index.html +85 -50
- package/package.json +1 -1
- package/server.js +3 -2
package/index-pc.html
CHANGED
|
@@ -2262,29 +2262,28 @@
|
|
|
2262
2262
|
var bar = document.getElementById('git-diff-bar');
|
|
2263
2263
|
if (diffBarVisible) {
|
|
2264
2264
|
bar.classList.add('visible');
|
|
2265
|
-
|
|
2265
|
+
if (cachedGitStatus) {
|
|
2266
|
+
diffChanges = cachedGitStatus.changes || [];
|
|
2267
|
+
document.getElementById('git-diff-count').textContent = diffChanges.length;
|
|
2268
|
+
renderDiffFileList();
|
|
2269
|
+
} else if (gitStatusLoading) {
|
|
2270
|
+
document.getElementById('git-diff-file-list').innerHTML = '<div class="git-diff-loading">正在查询 git status...</div>';
|
|
2271
|
+
document.getElementById('git-diff-count').textContent = '...';
|
|
2272
|
+
} else {
|
|
2273
|
+
document.getElementById('git-diff-file-list').innerHTML = '<div class="git-diff-loading" style="color:#666;">点击刷新加载</div>';
|
|
2274
|
+
}
|
|
2266
2275
|
} else {
|
|
2267
2276
|
bar.classList.remove('visible');
|
|
2268
2277
|
diffSelectedFile = null;
|
|
2269
2278
|
}
|
|
2270
2279
|
}
|
|
2271
2280
|
|
|
2272
|
-
function loadGitStatus(
|
|
2281
|
+
function loadGitStatus() {
|
|
2273
2282
|
var fileList = document.getElementById('git-diff-file-list');
|
|
2274
|
-
|
|
2275
|
-
if (cachedGitStatus && !forceRefresh) {
|
|
2276
|
-
diffChanges = cachedGitStatus.changes || [];
|
|
2277
|
-
document.getElementById('git-diff-count').textContent = diffChanges.length;
|
|
2278
|
-
renderDiffFileList();
|
|
2279
|
-
return;
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
fileList.innerHTML = '<div class="git-diff-loading">' + (forceRefresh ? '正在刷新...' : '正在查询 git status...') + '</div>';
|
|
2283
|
+
fileList.innerHTML = '<div class="git-diff-loading">正在刷新...</div>';
|
|
2283
2284
|
document.getElementById('git-diff-count').textContent = '...';
|
|
2284
|
-
|
|
2285
|
-
if (gitStatusLoading && !forceRefresh) return;
|
|
2286
2285
|
gitStatusLoading = true;
|
|
2287
|
-
|
|
2286
|
+
cachedGitStatus = null;
|
|
2288
2287
|
|
|
2289
2288
|
fetch(basePath + '/api/git-status')
|
|
2290
2289
|
.then(function(r) { return r.json(); })
|
|
@@ -2426,7 +2425,7 @@
|
|
|
2426
2425
|
document.getElementById('close-diff').addEventListener('click', toggleDiffBar);
|
|
2427
2426
|
document.getElementById('refresh-diff').addEventListener('click', function(e) {
|
|
2428
2427
|
e.stopPropagation();
|
|
2429
|
-
loadGitStatus(
|
|
2428
|
+
loadGitStatus();
|
|
2430
2429
|
// 重置 diff 内容区
|
|
2431
2430
|
diffSelectedFile = null;
|
|
2432
2431
|
document.getElementById('git-diff-content-area').innerHTML =
|
|
@@ -2448,7 +2447,14 @@
|
|
|
2448
2447
|
var bar = document.getElementById('docs-bar');
|
|
2449
2448
|
if (docsBarVisible) {
|
|
2450
2449
|
bar.classList.add('visible');
|
|
2451
|
-
|
|
2450
|
+
if (cachedDocs) {
|
|
2451
|
+
renderDocsList(cachedDocs);
|
|
2452
|
+
} else if (docsLoading) {
|
|
2453
|
+
document.getElementById('docs-file-list').innerHTML = '<div class="docs-loading">正在查询文档...</div>';
|
|
2454
|
+
document.getElementById('docs-count').textContent = '...';
|
|
2455
|
+
} else {
|
|
2456
|
+
document.getElementById('docs-file-list').innerHTML = '<div class="docs-loading" style="color:#666;">点击刷新加载</div>';
|
|
2457
|
+
}
|
|
2452
2458
|
} else {
|
|
2453
2459
|
bar.classList.remove('visible');
|
|
2454
2460
|
docsSelectedFile = null;
|
|
@@ -2484,20 +2490,12 @@
|
|
|
2484
2490
|
});
|
|
2485
2491
|
}
|
|
2486
2492
|
|
|
2487
|
-
function loadDocs(
|
|
2493
|
+
function loadDocs() {
|
|
2488
2494
|
var fileList = document.getElementById('docs-file-list');
|
|
2489
|
-
|
|
2490
|
-
if (cachedDocs && !forceRefresh) {
|
|
2491
|
-
renderDocsList(cachedDocs);
|
|
2492
|
-
return;
|
|
2493
|
-
}
|
|
2494
|
-
|
|
2495
|
-
fileList.innerHTML = '<div class="docs-loading">' + (forceRefresh ? '正在刷新...' : '正在查询文档...') + '</div>';
|
|
2495
|
+
fileList.innerHTML = '<div class="docs-loading">正在刷新...</div>';
|
|
2496
2496
|
document.getElementById('docs-count').textContent = '...';
|
|
2497
|
-
|
|
2498
|
-
if (docsLoading && !forceRefresh) return;
|
|
2499
2497
|
docsLoading = true;
|
|
2500
|
-
|
|
2498
|
+
cachedDocs = null;
|
|
2501
2499
|
|
|
2502
2500
|
fetch(basePath + '/api/docs')
|
|
2503
2501
|
.then(function(r) { return r.json(); })
|
|
@@ -2533,7 +2531,7 @@
|
|
|
2533
2531
|
document.getElementById('close-docs').addEventListener('click', toggleDocsBar);
|
|
2534
2532
|
document.getElementById('refresh-docs').addEventListener('click', function(e) {
|
|
2535
2533
|
e.stopPropagation();
|
|
2536
|
-
loadDocs(
|
|
2534
|
+
loadDocs();
|
|
2537
2535
|
docsSelectedFile = null;
|
|
2538
2536
|
document.getElementById('docs-content-area').innerHTML =
|
|
2539
2537
|
'<div class="docs-placeholder">' +
|
package/index.html
CHANGED
|
@@ -4,7 +4,33 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
|
6
6
|
<title>Claude OpenCode Viewer</title>
|
|
7
|
-
<
|
|
7
|
+
<style id="loading-style">
|
|
8
|
+
@keyframes loading-dots {
|
|
9
|
+
0% { content: ''; }
|
|
10
|
+
25% { content: '.'; }
|
|
11
|
+
50% { content: '..'; }
|
|
12
|
+
75% { content: '...'; }
|
|
13
|
+
}
|
|
14
|
+
#loading-overlay {
|
|
15
|
+
position: fixed;
|
|
16
|
+
top: 0; left: 0; right: 0; bottom: 0;
|
|
17
|
+
background: #0a0a0a;
|
|
18
|
+
color: #ccc;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
font-size: 16px;
|
|
23
|
+
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
|
|
24
|
+
letter-spacing: 1px;
|
|
25
|
+
z-index: 99999;
|
|
26
|
+
}
|
|
27
|
+
#loading-overlay::after {
|
|
28
|
+
content: '';
|
|
29
|
+
animation: loading-dots 1.2s steps(4, end) infinite;
|
|
30
|
+
}
|
|
31
|
+
#loading-overlay.hidden { display: none !important; }
|
|
32
|
+
</style>
|
|
33
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.min.css" media="print" onload="this.media='all'">
|
|
8
34
|
<style>
|
|
9
35
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
10
36
|
html, body { margin: 0; padding: 0; overflow: hidden; }
|
|
@@ -359,19 +385,6 @@
|
|
|
359
385
|
background: #0a0a0a;
|
|
360
386
|
position: relative;
|
|
361
387
|
}
|
|
362
|
-
#loading-overlay {
|
|
363
|
-
position: fixed;
|
|
364
|
-
top: 0; left: 0; right: 0; bottom: 0;
|
|
365
|
-
background: #0a0a0a;
|
|
366
|
-
color: #888;
|
|
367
|
-
display: flex;
|
|
368
|
-
align-items: center;
|
|
369
|
-
justify-content: center;
|
|
370
|
-
font-size: 15px;
|
|
371
|
-
z-index: 9999;
|
|
372
|
-
}
|
|
373
|
-
#loading-overlay.hidden { display: none; }
|
|
374
|
-
|
|
375
388
|
#terminal {
|
|
376
389
|
flex: 1;
|
|
377
390
|
overflow: hidden;
|
|
@@ -857,7 +870,7 @@
|
|
|
857
870
|
</head>
|
|
858
871
|
<body>
|
|
859
872
|
<!-- 参考 cc-viewer 的 App.jsx 行 1315-1607: 完整的移动端布局结构 -->
|
|
860
|
-
<div id="loading-overlay"
|
|
873
|
+
<div id="loading-overlay">正在初始化</div>
|
|
861
874
|
<div id="layout">
|
|
862
875
|
<div id="header">
|
|
863
876
|
<div style="display: flex; gap: 4px; align-items: center; overflow-x: auto; flex: 1; min-width: 0;">
|
|
@@ -1587,6 +1600,7 @@
|
|
|
1587
1600
|
ws = new WebSocket(proto + '//' + location.host + basePath + '/ws');
|
|
1588
1601
|
|
|
1589
1602
|
ws.onopen = function() {
|
|
1603
|
+
setLoadingText('正在连接服务');
|
|
1590
1604
|
resize();
|
|
1591
1605
|
rebindTouchScroll();
|
|
1592
1606
|
};
|
|
@@ -1599,9 +1613,24 @@
|
|
|
1599
1613
|
};
|
|
1600
1614
|
|
|
1601
1615
|
var loadingOverlay = document.getElementById('loading-overlay');
|
|
1602
|
-
|
|
1616
|
+
var loadingShowTime = Date.now();
|
|
1617
|
+
var loadingMinMs = 600;
|
|
1618
|
+
var loadingHideTimer = null;
|
|
1619
|
+
function setLoadingText(text) {
|
|
1603
1620
|
if (loadingOverlay && !loadingOverlay.classList.contains('hidden')) {
|
|
1621
|
+
loadingOverlay.textContent = text;
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
function hideLoading() {
|
|
1625
|
+
if (!loadingOverlay || loadingOverlay.classList.contains('hidden')) return;
|
|
1626
|
+
if (loadingHideTimer) return; // 已在等待中
|
|
1627
|
+
var elapsed = Date.now() - loadingShowTime;
|
|
1628
|
+
if (elapsed >= loadingMinMs) {
|
|
1604
1629
|
loadingOverlay.classList.add('hidden');
|
|
1630
|
+
} else {
|
|
1631
|
+
loadingHideTimer = setTimeout(function() {
|
|
1632
|
+
loadingOverlay.classList.add('hidden');
|
|
1633
|
+
}, loadingMinMs - elapsed);
|
|
1605
1634
|
}
|
|
1606
1635
|
}
|
|
1607
1636
|
|
|
@@ -1621,12 +1650,25 @@
|
|
|
1621
1650
|
}
|
|
1622
1651
|
}
|
|
1623
1652
|
else if (msg.type === 'state') {
|
|
1653
|
+
// 重连时清掉旧终端内容(如"连接断开"提示)
|
|
1654
|
+
if (writeTimer) { cancelAnimationFrame(writeTimer); writeTimer = null; }
|
|
1655
|
+
writeBuffer = '';
|
|
1656
|
+
term.reset();
|
|
1657
|
+
term.clear();
|
|
1658
|
+
// 同步模式 UI
|
|
1659
|
+
if (msg.mode) {
|
|
1660
|
+
currentMode = msg.mode;
|
|
1661
|
+
modeSelect.value = msg.mode;
|
|
1662
|
+
}
|
|
1624
1663
|
if (msg.running) {
|
|
1664
|
+
setLoadingText('正在连接');
|
|
1665
|
+
hideLoading();
|
|
1625
1666
|
preloadData();
|
|
1626
1667
|
}
|
|
1627
1668
|
// 服务端还没启动进程时,查最近会话并自动恢复
|
|
1628
1669
|
if (!msg.running && !mobileInitSent) {
|
|
1629
1670
|
mobileInitSent = true;
|
|
1671
|
+
setLoadingText('正在查询会话');
|
|
1630
1672
|
fetch('/api/last-sessions')
|
|
1631
1673
|
.then(function(r) { return r.json(); })
|
|
1632
1674
|
.then(function(data) {
|
|
@@ -1641,6 +1683,7 @@
|
|
|
1641
1683
|
claudeProject = cl.project;
|
|
1642
1684
|
}
|
|
1643
1685
|
currentMode = mode;
|
|
1686
|
+
setLoadingText('正在启动 ' + (mode === 'claude' ? 'Claude' : 'OpenCode'));
|
|
1644
1687
|
ws.send(JSON.stringify({ type: 'init', mode: mode, sessionId: sessionId || null }));
|
|
1645
1688
|
})
|
|
1646
1689
|
.catch(function() {
|
|
@@ -1663,13 +1706,6 @@
|
|
|
1663
1706
|
writeBuffer = '';
|
|
1664
1707
|
term.clear();
|
|
1665
1708
|
}
|
|
1666
|
-
else if (msg.type === 'state') {
|
|
1667
|
-
if (msg.mode) {
|
|
1668
|
-
currentMode = msg.mode;
|
|
1669
|
-
modeSelect.value = msg.mode;
|
|
1670
|
-
modeIndicator.textContent = msg.mode === 'claude' ? 'Claude' : 'OpenCode';
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
1709
|
else if (msg.type === 'restored') {
|
|
1674
1710
|
// 会话恢复成功,清除所有残留
|
|
1675
1711
|
if (writeTimer) { cancelAnimationFrame(writeTimer); writeTimer = null; }
|
|
@@ -2517,31 +2553,30 @@
|
|
|
2517
2553
|
var bar = document.getElementById('git-diff-bar');
|
|
2518
2554
|
if (diffBarVisible) {
|
|
2519
2555
|
bar.classList.add('visible');
|
|
2520
|
-
|
|
2556
|
+
if (cachedGitStatus) {
|
|
2557
|
+
diffChanges = cachedGitStatus.changes || [];
|
|
2558
|
+
document.getElementById('git-diff-count').textContent = diffChanges.length;
|
|
2559
|
+
renderDiffFileList();
|
|
2560
|
+
} else if (gitStatusLoading) {
|
|
2561
|
+
document.getElementById('git-diff-file-list').innerHTML = '<div class="git-diff-loading">正在查询 git status...</div>';
|
|
2562
|
+
document.getElementById('git-diff-count').textContent = '...';
|
|
2563
|
+
} else {
|
|
2564
|
+
document.getElementById('git-diff-file-list').innerHTML = '<div class="git-diff-loading" style="color:#666;">点击刷新加载</div>';
|
|
2565
|
+
}
|
|
2521
2566
|
} else {
|
|
2522
2567
|
bar.classList.remove('visible');
|
|
2523
2568
|
diffSelectedFile = null;
|
|
2524
2569
|
}
|
|
2525
2570
|
}
|
|
2526
2571
|
|
|
2527
|
-
function loadGitStatus(
|
|
2572
|
+
function loadGitStatus() {
|
|
2528
2573
|
var fileList = document.getElementById('git-diff-file-list');
|
|
2529
2574
|
|
|
2530
|
-
|
|
2531
|
-
if (cachedGitStatus && !forceRefresh) {
|
|
2532
|
-
diffChanges = cachedGitStatus.changes || [];
|
|
2533
|
-
document.getElementById('git-diff-count').textContent = diffChanges.length;
|
|
2534
|
-
renderDiffFileList();
|
|
2535
|
-
return;
|
|
2536
|
-
}
|
|
2537
|
-
|
|
2538
|
-
// 正在加载中或需要发起请求
|
|
2539
|
-
fileList.innerHTML = '<div class="git-diff-loading">' + (forceRefresh ? '正在刷新...' : '正在查询 git status...') + '</div>';
|
|
2575
|
+
fileList.innerHTML = '<div class="git-diff-loading">正在刷新...</div>';
|
|
2540
2576
|
document.getElementById('git-diff-count').textContent = '...';
|
|
2541
2577
|
|
|
2542
|
-
if (gitStatusLoading && !forceRefresh) return; // 预加载进行中,等它完成
|
|
2543
2578
|
gitStatusLoading = true;
|
|
2544
|
-
|
|
2579
|
+
cachedGitStatus = null;
|
|
2545
2580
|
|
|
2546
2581
|
fetch(basePath + '/api/git-status')
|
|
2547
2582
|
.then(function(r) { return r.json(); })
|
|
@@ -2683,7 +2718,7 @@
|
|
|
2683
2718
|
document.getElementById('close-diff').addEventListener('click', toggleDiffBar);
|
|
2684
2719
|
document.getElementById('refresh-diff').addEventListener('click', function(e) {
|
|
2685
2720
|
e.stopPropagation();
|
|
2686
|
-
loadGitStatus(
|
|
2721
|
+
loadGitStatus();
|
|
2687
2722
|
// 重置 diff 内容区
|
|
2688
2723
|
diffSelectedFile = null;
|
|
2689
2724
|
document.getElementById('git-diff-content-area').innerHTML =
|
|
@@ -2705,7 +2740,14 @@
|
|
|
2705
2740
|
var bar = document.getElementById('docs-bar');
|
|
2706
2741
|
if (docsBarVisible) {
|
|
2707
2742
|
bar.classList.add('visible');
|
|
2708
|
-
|
|
2743
|
+
if (cachedDocs) {
|
|
2744
|
+
renderDocsList(cachedDocs);
|
|
2745
|
+
} else if (docsLoading) {
|
|
2746
|
+
document.getElementById('docs-file-list').innerHTML = '<div class="docs-loading">正在查询文档...</div>';
|
|
2747
|
+
document.getElementById('docs-count').textContent = '...';
|
|
2748
|
+
} else {
|
|
2749
|
+
document.getElementById('docs-file-list').innerHTML = '<div class="docs-loading" style="color:#666;">点击刷新加载</div>';
|
|
2750
|
+
}
|
|
2709
2751
|
} else {
|
|
2710
2752
|
bar.classList.remove('visible');
|
|
2711
2753
|
docsSelectedFile = null;
|
|
@@ -2741,21 +2783,14 @@
|
|
|
2741
2783
|
});
|
|
2742
2784
|
}
|
|
2743
2785
|
|
|
2744
|
-
function loadDocs(
|
|
2786
|
+
function loadDocs() {
|
|
2745
2787
|
var fileList = document.getElementById('docs-file-list');
|
|
2746
2788
|
|
|
2747
|
-
|
|
2748
|
-
if (cachedDocs && !forceRefresh) {
|
|
2749
|
-
renderDocsList(cachedDocs);
|
|
2750
|
-
return;
|
|
2751
|
-
}
|
|
2752
|
-
|
|
2753
|
-
fileList.innerHTML = '<div class="docs-loading">' + (forceRefresh ? '正在刷新...' : '正在查询文档...') + '</div>';
|
|
2789
|
+
fileList.innerHTML = '<div class="docs-loading">正在刷新...</div>';
|
|
2754
2790
|
document.getElementById('docs-count').textContent = '...';
|
|
2755
2791
|
|
|
2756
|
-
if (docsLoading && !forceRefresh) return;
|
|
2757
2792
|
docsLoading = true;
|
|
2758
|
-
|
|
2793
|
+
cachedDocs = null;
|
|
2759
2794
|
|
|
2760
2795
|
fetch(basePath + '/api/docs')
|
|
2761
2796
|
.then(function(r) { return r.json(); })
|
|
@@ -2791,7 +2826,7 @@
|
|
|
2791
2826
|
document.getElementById('close-docs').addEventListener('click', toggleDocsBar);
|
|
2792
2827
|
document.getElementById('refresh-docs').addEventListener('click', function(e) {
|
|
2793
2828
|
e.stopPropagation();
|
|
2794
|
-
loadDocs(
|
|
2829
|
+
loadDocs();
|
|
2795
2830
|
docsSelectedFile = null;
|
|
2796
2831
|
document.getElementById('docs-content-area').innerHTML =
|
|
2797
2832
|
'<div class="docs-placeholder">' +
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -295,6 +295,8 @@ async function spawnProcess(mode, sessionId = null) {
|
|
|
295
295
|
});
|
|
296
296
|
|
|
297
297
|
proc.onData((data) => {
|
|
298
|
+
// 忽略已被替换的旧进程输出
|
|
299
|
+
if (currentProcess !== proc) return;
|
|
298
300
|
outputBuffer += data;
|
|
299
301
|
if (outputBuffer.length > MAX_BUFFER) {
|
|
300
302
|
const rawStart = outputBuffer.length - MAX_BUFFER;
|
|
@@ -1216,8 +1218,7 @@ wssInst.on('connection', (ws, req) => {
|
|
|
1216
1218
|
outputBuffer = '';
|
|
1217
1219
|
try {
|
|
1218
1220
|
await spawnProcess(mode, msg.sessionId || null);
|
|
1219
|
-
ws.send(JSON.stringify({ type: '
|
|
1220
|
-
ws.send(JSON.stringify({ type: 'started', sessionId: msg.sessionId || null }));
|
|
1221
|
+
ws.send(JSON.stringify({ type: 'started', mode: currentMode, sessionId: msg.sessionId || null }));
|
|
1221
1222
|
} catch (e) {
|
|
1222
1223
|
LOG('[init] 启动失败:', e.message);
|
|
1223
1224
|
ws.send(JSON.stringify({ type: 'start-error', error: e.message }));
|