claude-opencode-viewer 2.6.5 → 2.6.6
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/bin/cov.js +2 -0
- package/index-pc.html +75 -9
- package/package.json +1 -1
- package/server.js +33 -5
package/bin/cov.js
CHANGED
|
@@ -42,6 +42,7 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
42
42
|
║ 用法: ║
|
|
43
43
|
║ cov 在当前目录启动服务(端口7008) ║
|
|
44
44
|
║ cov --pc PC端随机端口启动(19200-19220) ║
|
|
45
|
+
║ cov --pc --https PC端HTTPS模式启动 ║
|
|
45
46
|
║ cov --port <端口号> 指定端口启动 ║
|
|
46
47
|
║ cov [路径] 在指定目录启动服务 ║
|
|
47
48
|
║ cov --help, -h 显示此帮助信息 ║
|
|
@@ -85,6 +86,7 @@ for (const arg of args) {
|
|
|
85
86
|
const port = getPort();
|
|
86
87
|
const serverArgs = [SERVER_PATH, String(port)];
|
|
87
88
|
if (args.includes('--pc')) serverArgs.push('--pc');
|
|
89
|
+
if (args.includes('--https')) serverArgs.push('--https');
|
|
88
90
|
const server = spawn(process.execPath, serverArgs, {
|
|
89
91
|
stdio: 'inherit',
|
|
90
92
|
cwd: process.cwd(),
|
package/index-pc.html
CHANGED
|
@@ -559,6 +559,59 @@
|
|
|
559
559
|
display: block;
|
|
560
560
|
}
|
|
561
561
|
|
|
562
|
+
#copy-popup {
|
|
563
|
+
display: none;
|
|
564
|
+
position: fixed;
|
|
565
|
+
top: 50%;
|
|
566
|
+
left: 50%;
|
|
567
|
+
transform: translate(-50%, -50%);
|
|
568
|
+
background: #1a1a1a;
|
|
569
|
+
border: 1px solid #444;
|
|
570
|
+
border-radius: 8px;
|
|
571
|
+
padding: 16px;
|
|
572
|
+
z-index: 10000;
|
|
573
|
+
max-width: 80vw;
|
|
574
|
+
max-height: 60vh;
|
|
575
|
+
}
|
|
576
|
+
#copy-popup.show {
|
|
577
|
+
display: flex;
|
|
578
|
+
flex-direction: column;
|
|
579
|
+
gap: 10px;
|
|
580
|
+
}
|
|
581
|
+
#copy-popup textarea {
|
|
582
|
+
width: 500px;
|
|
583
|
+
max-width: 70vw;
|
|
584
|
+
height: 120px;
|
|
585
|
+
background: #0a0a0a;
|
|
586
|
+
color: #ccc;
|
|
587
|
+
border: 1px solid #333;
|
|
588
|
+
border-radius: 4px;
|
|
589
|
+
padding: 8px;
|
|
590
|
+
font-family: Menlo, Monaco, monospace;
|
|
591
|
+
font-size: 12px;
|
|
592
|
+
resize: vertical;
|
|
593
|
+
}
|
|
594
|
+
#copy-popup .popup-actions {
|
|
595
|
+
display: flex;
|
|
596
|
+
justify-content: flex-end;
|
|
597
|
+
gap: 8px;
|
|
598
|
+
}
|
|
599
|
+
#copy-popup button {
|
|
600
|
+
padding: 6px 16px;
|
|
601
|
+
border: none;
|
|
602
|
+
border-radius: 4px;
|
|
603
|
+
cursor: pointer;
|
|
604
|
+
font-size: 13px;
|
|
605
|
+
}
|
|
606
|
+
#copy-popup .btn-copy {
|
|
607
|
+
background: #2563eb;
|
|
608
|
+
color: #fff;
|
|
609
|
+
}
|
|
610
|
+
#copy-popup .btn-close {
|
|
611
|
+
background: #333;
|
|
612
|
+
color: #ccc;
|
|
613
|
+
}
|
|
614
|
+
|
|
562
615
|
/* Git Diff 面板 */
|
|
563
616
|
#git-diff-bar {
|
|
564
617
|
display: none;
|
|
@@ -929,6 +982,14 @@
|
|
|
929
982
|
</div>
|
|
930
983
|
|
|
931
984
|
<div id="copy-toast">已复制</div>
|
|
985
|
+
<div id="copy-popup">
|
|
986
|
+
<div style="color:#ccc;font-size:13px;">剪贴板写入需要 HTTPS,请手动复制:</div>
|
|
987
|
+
<textarea id="copy-popup-text" readonly></textarea>
|
|
988
|
+
<div class="popup-actions">
|
|
989
|
+
<button class="btn-copy" onclick="document.getElementById('copy-popup-text').select();document.execCommand('copy');document.getElementById('copy-popup').classList.remove('show');">选中并复制</button>
|
|
990
|
+
<button class="btn-close" onclick="document.getElementById('copy-popup').classList.remove('show');">关闭</button>
|
|
991
|
+
</div>
|
|
992
|
+
</div>
|
|
932
993
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.min.js"></script>
|
|
933
994
|
<script>
|
|
934
995
|
(function() {
|
|
@@ -973,21 +1034,17 @@
|
|
|
973
1034
|
if (idx === -1) return false;
|
|
974
1035
|
var b64 = data.substring(idx + 1);
|
|
975
1036
|
if (!b64 || b64 === '?') return false;
|
|
1037
|
+
if (isBufferReplay) return true;
|
|
976
1038
|
try {
|
|
977
1039
|
var text = atob(b64);
|
|
978
1040
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
979
1041
|
navigator.clipboard.writeText(text).then(function() {
|
|
980
|
-
|
|
1042
|
+
showCopyToast();
|
|
1043
|
+
}).catch(function() {
|
|
1044
|
+
showCopyPopup(text);
|
|
981
1045
|
});
|
|
982
1046
|
} else {
|
|
983
|
-
|
|
984
|
-
ta.value = text;
|
|
985
|
-
ta.style.cssText = 'position:fixed;left:-9999px;top:-9999px';
|
|
986
|
-
document.body.appendChild(ta);
|
|
987
|
-
ta.select();
|
|
988
|
-
document.execCommand('copy');
|
|
989
|
-
document.body.removeChild(ta);
|
|
990
|
-
if (!isBufferReplay) showCopyToast();
|
|
1047
|
+
showCopyPopup(text);
|
|
991
1048
|
}
|
|
992
1049
|
} catch (e) {}
|
|
993
1050
|
return true;
|
|
@@ -1905,6 +1962,15 @@
|
|
|
1905
1962
|
showCopyToast();
|
|
1906
1963
|
}
|
|
1907
1964
|
|
|
1965
|
+
function showCopyPopup(text) {
|
|
1966
|
+
var popup = document.getElementById('copy-popup');
|
|
1967
|
+
var ta = document.getElementById('copy-popup-text');
|
|
1968
|
+
ta.value = text;
|
|
1969
|
+
popup.classList.add('show');
|
|
1970
|
+
ta.focus();
|
|
1971
|
+
ta.select();
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1908
1974
|
function showCopyToast() {
|
|
1909
1975
|
var toast = document.getElementById('copy-toast');
|
|
1910
1976
|
toast.classList.add('show');
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
|
-
import {
|
|
3
|
+
import { createServer as createHttpsServer } from 'node:https';
|
|
4
|
+
import { existsSync, createReadStream, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
4
5
|
import { join, dirname } from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { networkInterfaces, platform, arch, homedir } from 'node:os';
|
|
@@ -16,6 +17,27 @@ process.title = 'claude-opencode-viewer';
|
|
|
16
17
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const PORT = parseInt(process.argv[2]) || 7008;
|
|
18
19
|
const IS_PC = process.argv.includes('--pc');
|
|
20
|
+
const USE_HTTPS = process.argv.includes('--https');
|
|
21
|
+
|
|
22
|
+
// 自签名证书生成
|
|
23
|
+
function getOrCreateCert() {
|
|
24
|
+
const certDir = join(homedir(), '.cov-certs');
|
|
25
|
+
const keyPath = join(certDir, 'key.pem');
|
|
26
|
+
const certPath = join(certDir, 'cert.pem');
|
|
27
|
+
|
|
28
|
+
if (existsSync(keyPath) && existsSync(certPath)) {
|
|
29
|
+
return { key: readFileSync(keyPath), cert: readFileSync(certPath) };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log('🔐 首次使用 HTTPS,生成自签名证书...');
|
|
33
|
+
mkdirSync(certDir, { recursive: true });
|
|
34
|
+
execSync(
|
|
35
|
+
`openssl req -x509 -newkey rsa:2048 -keyout "${keyPath}" -out "${certPath}" -days 365 -nodes -subj "/CN=cov-self-signed"`,
|
|
36
|
+
{ stdio: 'pipe' }
|
|
37
|
+
);
|
|
38
|
+
console.log(`📁 证书已保存到 ${certDir}`);
|
|
39
|
+
return { key: readFileSync(keyPath), cert: readFileSync(certPath) };
|
|
40
|
+
}
|
|
19
41
|
|
|
20
42
|
// OpenCode 数据库路径(支持环境变量覆盖,自动检测 /halo 环境)
|
|
21
43
|
const OPENCODE_DB_PATH = process.env.OPENCODE_DB_PATH || join(
|
|
@@ -407,7 +429,7 @@ function getSessionMessages(sessionId) {
|
|
|
407
429
|
}
|
|
408
430
|
}
|
|
409
431
|
|
|
410
|
-
const
|
|
432
|
+
const requestHandler = async (req, res) => {
|
|
411
433
|
if (req.url === '/' || req.url === '/index.html') {
|
|
412
434
|
res.writeHead(200, {
|
|
413
435
|
'Content-Type': 'text/html; charset=utf-8',
|
|
@@ -557,7 +579,11 @@ const server = createServer(async (req, res) => {
|
|
|
557
579
|
|
|
558
580
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
559
581
|
res.end('Not Found');
|
|
560
|
-
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
const server = USE_HTTPS
|
|
585
|
+
? createHttpsServer(getOrCreateCert(), requestHandler)
|
|
586
|
+
: createServer(requestHandler);
|
|
561
587
|
|
|
562
588
|
const wss = new WebSocketServer({ server, path: '/ws' });
|
|
563
589
|
|
|
@@ -740,11 +766,13 @@ wss.on('connection', (ws, req) => {
|
|
|
740
766
|
|
|
741
767
|
server.listen(PORT, '0.0.0.0', async () => {
|
|
742
768
|
const ip = getLocalIp();
|
|
769
|
+
const proto = USE_HTTPS ? 'https' : 'http';
|
|
743
770
|
console.log('\n' + '='.repeat(50));
|
|
744
771
|
console.log('✅ Claude OpenCode Viewer 已启动');
|
|
745
772
|
console.log('='.repeat(50));
|
|
746
|
-
console.log(`🖥️
|
|
747
|
-
console.log(`📱
|
|
773
|
+
console.log(`🖥️ 本地访问:${proto}://127.0.0.1:${PORT}`);
|
|
774
|
+
console.log(`📱 手机访问:${proto}://${ip}:${PORT}`);
|
|
775
|
+
if (USE_HTTPS) console.log('🔐 HTTPS 模式(首次访问需信任自签名证书)');
|
|
748
776
|
console.log('='.repeat(50));
|
|
749
777
|
console.log('\n按 Ctrl+C 停止服务\n');
|
|
750
778
|
|