@wendongfly/myhi 1.3.88 → 1.3.90
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/dist/admin.html +53 -0
- package/dist/chat.html +68 -2
- package/dist/index.js +1 -1
- package/dist/index.min.js +5 -3
- package/package.json +1 -1
package/dist/admin.html
CHANGED
|
@@ -76,6 +76,17 @@
|
|
|
76
76
|
</div>
|
|
77
77
|
<div id="op-msg" class="status-msg" style="display:none"></div>
|
|
78
78
|
|
|
79
|
+
<!-- Claude Code 版本 + 升级 -->
|
|
80
|
+
<div class="ver-card">
|
|
81
|
+
<div style="font-size:0.8rem;color:#8b949e">Claude Code 版本</div>
|
|
82
|
+
<div class="ver-big" id="cl-cur">--</div>
|
|
83
|
+
<div class="ver-sub" id="cl-latest"></div>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="actions">
|
|
86
|
+
<button class="btn-up" id="btn-cl-up" onclick="doClaudeUpgrade()" disabled>已是最新</button>
|
|
87
|
+
</div>
|
|
88
|
+
<div id="cl-msg" class="status-msg" style="display:none"></div>
|
|
89
|
+
|
|
79
90
|
<!-- 在线用户 -->
|
|
80
91
|
<div class="card">
|
|
81
92
|
<h3>在线用户</h3>
|
|
@@ -219,6 +230,26 @@ async function refresh() {
|
|
|
219
230
|
btn.disabled = true; btn.classList.remove('glow'); btn.textContent = '已是最新';
|
|
220
231
|
}
|
|
221
232
|
|
|
233
|
+
// Claude Code 版本(独立端点)
|
|
234
|
+
try {
|
|
235
|
+
const cr = await fetch('/api/claude/version', { headers: H() });
|
|
236
|
+
if (cr.ok) {
|
|
237
|
+
const cd = await cr.json();
|
|
238
|
+
document.getElementById('cl-cur').textContent = cd.current ? ('v' + cd.current) : '未检测到';
|
|
239
|
+
const clBtn = document.getElementById('btn-cl-up');
|
|
240
|
+
if (cd.upgrade?.running) {
|
|
241
|
+
document.getElementById('cl-latest').innerHTML = '<span style="color:#58a6ff">升级中...</span>';
|
|
242
|
+
clBtn.disabled = true; clBtn.textContent = '升级中...';
|
|
243
|
+
} else if (cd.updateAvailable) {
|
|
244
|
+
document.getElementById('cl-latest').innerHTML = '最新版本: <b>v' + cd.latest + '</b>';
|
|
245
|
+
clBtn.disabled = false; clBtn.classList.add('glow'); clBtn.textContent = '升级到 v' + cd.latest;
|
|
246
|
+
} else {
|
|
247
|
+
document.getElementById('cl-latest').innerHTML = '<span style="color:#3fb950">已是最新版本</span>';
|
|
248
|
+
clBtn.disabled = true; clBtn.classList.remove('glow'); clBtn.textContent = '已是最新';
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} catch {}
|
|
252
|
+
|
|
222
253
|
// 在线用户
|
|
223
254
|
const ouEl = document.getElementById('online-users');
|
|
224
255
|
if (!d.onlineUsers?.length) {
|
|
@@ -327,6 +358,28 @@ async function doUpgrade() {
|
|
|
327
358
|
} catch { msg.textContent = '连接失败'; btn.disabled = false; btn.textContent = '重试'; }
|
|
328
359
|
}
|
|
329
360
|
|
|
361
|
+
async function doClaudeUpgrade() {
|
|
362
|
+
const btn = document.getElementById('btn-cl-up'), msg = document.getElementById('cl-msg');
|
|
363
|
+
if (!confirm('升级 Claude Code?\nmyhi 会用 npm --include=optional 装全平台二进制,避免占位符坑。\n不影响正在跑的会话,升级后新查询生效。')) return;
|
|
364
|
+
btn.disabled = true; btn.textContent = '升级中...'; msg.className = 'status-msg'; msg.textContent = '正在下载安装(~260MB,可能几分钟)...'; msg.style.display = '';
|
|
365
|
+
try {
|
|
366
|
+
const r = await fetch('/api/claude/update', { method: 'POST', headers: H() });
|
|
367
|
+
const d = await r.json();
|
|
368
|
+
if (!d.ok) { msg.textContent = '失败: ' + (d.error||''); btn.disabled = false; btn.textContent = '重试'; return; }
|
|
369
|
+
const poll = setInterval(async () => {
|
|
370
|
+
try {
|
|
371
|
+
const sr = await fetch('/api/claude/update-status', { headers: H() });
|
|
372
|
+
const s = await sr.json();
|
|
373
|
+
if (!s.running) {
|
|
374
|
+
clearInterval(poll);
|
|
375
|
+
if (s.ok) { msg.textContent = '已升级到 v' + s.version; setTimeout(refresh, 500); }
|
|
376
|
+
else { msg.textContent = '失败: ' + (s.error||''); btn.disabled = false; btn.textContent = '重试'; }
|
|
377
|
+
}
|
|
378
|
+
} catch {}
|
|
379
|
+
}, 4000);
|
|
380
|
+
} catch { msg.textContent = '连接失败'; btn.disabled = false; btn.textContent = '重试'; }
|
|
381
|
+
}
|
|
382
|
+
|
|
330
383
|
async function doRestart() {
|
|
331
384
|
if (!confirm('确定重启?')) return;
|
|
332
385
|
const msg = document.getElementById('op-msg');
|
package/dist/chat.html
CHANGED
|
@@ -291,6 +291,7 @@
|
|
|
291
291
|
<span id="control-badge" class="readonly" style="display:none">只读</span>
|
|
292
292
|
<span id="viewer-count" class="sb-item"></span>
|
|
293
293
|
<span id="update-badge" style="display:none;color:#d29922;cursor:pointer" onclick="doUpdate()">⬆ 有更新</span>
|
|
294
|
+
<span id="claude-update-badge" style="display:none;color:#58a6ff;cursor:pointer" onclick="doClaudeUpdate()">⬆ claude</span>
|
|
294
295
|
</div>
|
|
295
296
|
|
|
296
297
|
<div id="chat-area"></div>
|
|
@@ -885,10 +886,22 @@
|
|
|
885
886
|
scrollToBottom();
|
|
886
887
|
}
|
|
887
888
|
|
|
889
|
+
// 连续重复的同一条状态不再一行行堆,折叠成「— xxx — ×N」。
|
|
890
|
+
// 任何会反复触发的状态(自动重启、上传失败、控制权变更…)都不会再刷屏。
|
|
888
891
|
function addStatusMessage(text) {
|
|
889
892
|
endStream(); endToolGroup();
|
|
893
|
+
const last = chatArea.lastElementChild;
|
|
894
|
+
if (last && last.classList.contains('msg-status') && last.dataset.statusText === text) {
|
|
895
|
+
const n = (parseInt(last.dataset.statusCount, 10) || 1) + 1;
|
|
896
|
+
last.dataset.statusCount = String(n);
|
|
897
|
+
last.textContent = '— ' + text + ' — ×' + n;
|
|
898
|
+
scrollToBottom();
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
890
901
|
const msg = document.createElement('div');
|
|
891
902
|
msg.className = 'msg msg-status';
|
|
903
|
+
msg.dataset.statusText = text;
|
|
904
|
+
msg.dataset.statusCount = '1';
|
|
892
905
|
msg.textContent = '— ' + text + ' —';
|
|
893
906
|
chatArea.appendChild(msg);
|
|
894
907
|
trimMessages();
|
|
@@ -1496,11 +1509,17 @@
|
|
|
1496
1509
|
socket.on('error', ({ message }) => { showOverlay('错误: ' + message, true); });
|
|
1497
1510
|
|
|
1498
1511
|
// 控制权事件
|
|
1512
|
+
// 只有「别人抢走了」才值得往聊天区写一行。自己拿到 / 自己释放属于日常动作,
|
|
1513
|
+
// 右上角徽标(控制中 / 获取控制)已经把状态说清楚了,再刷消息就是噪音——
|
|
1514
|
+
// 之前正是这两条把长会话刷成了满屏「你已获取控制权 / 控制权已释放」。
|
|
1515
|
+
let lastControlHolder = null;
|
|
1499
1516
|
socket.on('control-changed', ({ sessionId, holder, holderName }) => {
|
|
1500
1517
|
if (sessionId !== SESSION_ID) return;
|
|
1501
1518
|
updateControlUI(holder === socket.id, holderName);
|
|
1502
|
-
if (holder
|
|
1503
|
-
|
|
1519
|
+
if (holder && holder !== socket.id && holder !== lastControlHolder) {
|
|
1520
|
+
addStatusMessage(`${holderName || '其他用户'} 获取了控制权`);
|
|
1521
|
+
}
|
|
1522
|
+
lastControlHolder = holder || null;
|
|
1504
1523
|
});
|
|
1505
1524
|
socket.on('control-denied', ({ reason }) => addStatusMessage('无法获取控制: ' + reason));
|
|
1506
1525
|
socket.on('kicked', ({ reason }) => { addStatusMessage(reason || '你已被管理员踢出'); setTimeout(() => location.href = '/', 2000); });
|
|
@@ -3541,6 +3560,53 @@
|
|
|
3541
3560
|
badge.style.color = '#d29922';
|
|
3542
3561
|
}
|
|
3543
3562
|
};
|
|
3563
|
+
|
|
3564
|
+
// ── Claude Code 版本检查 & 升级 ──────────────────────
|
|
3565
|
+
let _claudeInfo = null;
|
|
3566
|
+
(async function checkClaudeUpdate() {
|
|
3567
|
+
try {
|
|
3568
|
+
const resp = await fetch('/api/claude/version');
|
|
3569
|
+
if (resp.ok) {
|
|
3570
|
+
_claudeInfo = await resp.json();
|
|
3571
|
+
const b = document.getElementById('claude-update-badge');
|
|
3572
|
+
if (_claudeInfo.upgrade?.running) {
|
|
3573
|
+
b.textContent = '⬆ claude 升级中...'; b.style.color = '#8b949e'; b.style.display = '';
|
|
3574
|
+
} else if (_claudeInfo.updateAvailable) {
|
|
3575
|
+
b.textContent = `⬆ claude ${_claudeInfo.latest}`; b.style.color = '#58a6ff'; b.style.display = '';
|
|
3576
|
+
} else {
|
|
3577
|
+
b.style.display = 'none';
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
} catch {}
|
|
3581
|
+
setTimeout(checkClaudeUpdate, 10 * 60 * 1000);
|
|
3582
|
+
})();
|
|
3583
|
+
|
|
3584
|
+
window.doClaudeUpdate = async function() {
|
|
3585
|
+
if (!_claudeInfo?.updateAvailable) return;
|
|
3586
|
+
if (!confirm(`升级 Claude Code?\n当前: ${_claudeInfo.current}\n最新: ${_claudeInfo.latest}\n\nmyhi 会用 npm --include=optional 装全平台二进制,避免占位符坑。不影响正在跑的会话,升级后新查询生效。`)) return;
|
|
3587
|
+
const b = document.getElementById('claude-update-badge');
|
|
3588
|
+
b.textContent = '⬆ claude 升级中...'; b.style.color = '#8b949e';
|
|
3589
|
+
try {
|
|
3590
|
+
const resp = await fetch('/api/claude/update', { method: 'POST' });
|
|
3591
|
+
const data = await resp.json();
|
|
3592
|
+
if (!data.ok) { addStatusMessage('claude 升级失败:' + (data.error || '未知')); b.textContent = '⬆ claude 失败'; b.style.color = '#f85149'; return; }
|
|
3593
|
+
addStatusMessage(data.message || 'claude 升级中...');
|
|
3594
|
+
const poll = setInterval(async () => {
|
|
3595
|
+
try {
|
|
3596
|
+
const r = await fetch('/api/claude/update-status');
|
|
3597
|
+
const s = await r.json();
|
|
3598
|
+
if (!s.running) {
|
|
3599
|
+
clearInterval(poll);
|
|
3600
|
+
if (s.ok) { addStatusMessage('Claude Code 已升级到 ' + s.version); b.style.display = 'none'; }
|
|
3601
|
+
else { addStatusMessage('claude 升级失败:\n' + (s.error || '未知')); b.textContent = '⬆ claude 失败'; b.style.color = '#f85149'; }
|
|
3602
|
+
}
|
|
3603
|
+
} catch {}
|
|
3604
|
+
}, 4000);
|
|
3605
|
+
} catch (e) {
|
|
3606
|
+
addStatusMessage('claude 升级失败: ' + e.message);
|
|
3607
|
+
b.textContent = `⬆ claude ${_claudeInfo.latest}`; b.style.color = '#58a6ff';
|
|
3608
|
+
}
|
|
3609
|
+
};
|
|
3544
3610
|
</script>
|
|
3545
3611
|
</body>
|
|
3546
3612
|
</html>
|