@wendongfly/myhi 1.3.164 → 1.3.166
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/chat.html +46 -10
- package/dist/index.html +67 -0
- package/dist/index.js +1 -1
- package/dist/index.min.js +39 -39
- package/package.json +1 -1
package/dist/chat.html
CHANGED
|
@@ -1528,16 +1528,32 @@
|
|
|
1528
1528
|
const t = text.trimStart();
|
|
1529
1529
|
if (t.startsWith('This session is being continued from a previous conversation')) return 'compact';
|
|
1530
1530
|
if (t.startsWith('[Request interrupted by user')) return 'interrupt'; // 含 "...for tool use" 变体
|
|
1531
|
+
// claude 本地 slash 命令注入的合成 user 事件(1.3.165):命令回显与免责声明——
|
|
1532
|
+
// 发 /context 这类本地命令时 claude 会在流里回 <command-name> 回显 + <local-command-caveat> 说明
|
|
1533
|
+
if (t.startsWith('<command-name>')) return 'command';
|
|
1534
|
+
if (t.startsWith('<local-command-caveat>') || t.startsWith('Caveat:')) return 'caveat';
|
|
1535
|
+
if (t.startsWith('<system-reminder>') || t.startsWith('<local-command-stdout>')) return 'noise';
|
|
1531
1536
|
return null;
|
|
1532
1537
|
}
|
|
1533
1538
|
|
|
1534
1539
|
function buildSyntheticUserEl(content) {
|
|
1535
1540
|
const el = document.createElement('div');
|
|
1536
|
-
|
|
1541
|
+
const kind = syntheticUserKind(content);
|
|
1542
|
+
if (kind === 'interrupt') {
|
|
1537
1543
|
el.className = 'msg msg-status';
|
|
1538
1544
|
el.textContent = '— ⏹ 请求已中断 —';
|
|
1539
1545
|
return el;
|
|
1540
1546
|
}
|
|
1547
|
+
if (kind === 'command') {
|
|
1548
|
+
// 本地命令回显:状态行显示执行了什么命令(用户自己发的命令已有气泡,这是 claude 的回显)
|
|
1549
|
+
el.className = 'msg msg-status';
|
|
1550
|
+
const name = (content.match(/<command-name>([^<]*)<\/command-name>/) || [])[1] || '命令';
|
|
1551
|
+
el.textContent = `— ⌘ ${name} —`;
|
|
1552
|
+
return el;
|
|
1553
|
+
}
|
|
1554
|
+
if (kind === 'caveat' || kind === 'noise') {
|
|
1555
|
+
return null; // 给模型看的免责声明/系统提醒/命令输出回显,对用户是纯噪音,不渲染
|
|
1556
|
+
}
|
|
1541
1557
|
el.className = 'msg msg-synthetic';
|
|
1542
1558
|
const head = document.createElement('div');
|
|
1543
1559
|
head.className = 'syn-head';
|
|
@@ -2248,9 +2264,27 @@
|
|
|
2248
2264
|
break;
|
|
2249
2265
|
// 服务端主动发起的消息(自动接力发出的草稿)—— 渲染成用户气泡,
|
|
2250
2266
|
// 跟你自己按回车发出来的长得一样,能看见原文而不只是一行系统提示。
|
|
2251
|
-
|
|
2252
|
-
|
|
2267
|
+
// claude 注入的合成 user 事件(压缩摘要/中断/本地命令回显与免责声明)不是用户发言:
|
|
2268
|
+
// 新 CLI 下这类事件带顶层 content,必须分类分流,否则长成蓝色用户气泡(1.3.165)。
|
|
2269
|
+
case 'user': {
|
|
2270
|
+
// 只有字符串 content 才可能是真人/草稿发言;claude 原生 user 事件带数组 content
|
|
2271
|
+
// (tool_result 块)不是用户说话,别渲染成气泡
|
|
2272
|
+
if (msg.content && typeof msg.content === 'string') {
|
|
2273
|
+
endStream();
|
|
2274
|
+
const kind = syntheticUserKind(msg.content);
|
|
2275
|
+
if (kind === 'compact' || kind === 'interrupt') {
|
|
2276
|
+
const sel = buildSyntheticUserEl(msg.content);
|
|
2277
|
+
if (sel) { chatArea.appendChild(sel); trimMessages(); scrollToBottom(); }
|
|
2278
|
+
} else if (kind === 'command') {
|
|
2279
|
+
const sel = buildSyntheticUserEl(msg.content);
|
|
2280
|
+
if (sel) addStatusMessage(sel.textContent);
|
|
2281
|
+
} else if (!kind) {
|
|
2282
|
+
addInputMessage(msg.content);
|
|
2283
|
+
}
|
|
2284
|
+
// caveat/noise:纯噪音,不渲染
|
|
2285
|
+
}
|
|
2253
2286
|
break;
|
|
2287
|
+
}
|
|
2254
2288
|
case 'assistant':
|
|
2255
2289
|
removeThinking();
|
|
2256
2290
|
if (msg.message?.usage) {
|
|
@@ -2402,11 +2436,12 @@
|
|
|
2402
2436
|
endStream(); // 每条历史消息都是独立的,不要流式合并
|
|
2403
2437
|
if (subaRoute(msg)) continue; // 子代理内部历史消息归入对应面板
|
|
2404
2438
|
if (msg.type === 'user' && msg.content) {
|
|
2405
|
-
// claude
|
|
2406
|
-
|
|
2407
|
-
|
|
2439
|
+
// claude 注入的合成消息(压缩摘要/中断/命令回显/免责声明)渲染成系统状态行或不渲染,不长成用户发言
|
|
2440
|
+
const sel = buildSyntheticUserEl(msg.content);
|
|
2441
|
+
if (sel) {
|
|
2442
|
+
chatArea.appendChild(sel);
|
|
2408
2443
|
trimMessages(); scrollToBottom();
|
|
2409
|
-
} else {
|
|
2444
|
+
} else if (!syntheticUserKind(msg.content)) {
|
|
2410
2445
|
addInputMessage(msg.content);
|
|
2411
2446
|
}
|
|
2412
2447
|
} else if (msg.type === 'assistant' && msg.message?.content) {
|
|
@@ -2490,9 +2525,10 @@
|
|
|
2490
2525
|
const frag = document.createDocumentFragment();
|
|
2491
2526
|
for (const msg of d.messages) {
|
|
2492
2527
|
if (msg.type === 'user' && msg.content) {
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2528
|
+
const sel = buildSyntheticUserEl(msg.content);
|
|
2529
|
+
if (sel) {
|
|
2530
|
+
frag.appendChild(sel);
|
|
2531
|
+
} else if (!syntheticUserKind(msg.content)) {
|
|
2496
2532
|
const el = document.createElement('div');
|
|
2497
2533
|
el.className = 'msg msg-input';
|
|
2498
2534
|
el.innerHTML = `<div><div class="bubble">${escHtml(msg.content)}</div><div class="meta">${msg.timestamp ? new Date(msg.timestamp).toLocaleString('zh-CN') : ''}</div></div>`;
|
package/dist/index.html
CHANGED
|
@@ -462,6 +462,7 @@
|
|
|
462
462
|
<button id="appearance-btn" onclick="openAppearance()" title="外观" style="background:none;border:1px solid var(--border);color:var(--muted);font-size:0.75rem;padding:0.3rem 0.55rem;border-radius:6px;cursor:pointer;width:auto">🎨</button>
|
|
463
463
|
<button id="doctor-btn" onclick="openDoctor()" style="background:none;border:1px solid var(--border);color:var(--muted);font-size:0.75rem;padding:0.3rem 0.6rem;border-radius:6px;cursor:pointer;width:auto">🩺 体检</button>
|
|
464
464
|
<button id="usage-btn" onclick="showUsage()" style="background:none;border:1px solid var(--border);color:var(--muted);font-size:0.75rem;padding:0.3rem 0.6rem;border-radius:6px;cursor:pointer;width:auto">用量</button>
|
|
465
|
+
<button id="passwd-btn" onclick="openPasswdSheet()" title="修改我的密码" style="display:none;background:none;border:1px solid var(--border);color:var(--muted);font-size:0.75rem;padding:0.3rem 0.6rem;border-radius:6px;cursor:pointer;width:auto">🔑 改密码</button>
|
|
465
466
|
<button id="logout-btn" onclick="doLogout()" style="display:none;background:none;border:1px solid var(--border);color:var(--muted);font-size:0.75rem;padding:0.3rem 0.6rem;border-radius:6px;cursor:pointer;width:auto">退出</button>
|
|
466
467
|
<div id="conn-dot"></div>
|
|
467
468
|
</div>
|
|
@@ -530,6 +531,31 @@
|
|
|
530
531
|
<button onclick="closeNoteSheet()" style="width:100%;background:var(--bg,var(--bg));color:var(--muted,var(--muted));border:1px solid var(--border,var(--border));border-radius:10px;padding:0.65rem;font-size:0.85rem;cursor:pointer;margin-top:0.5rem">取消</button>
|
|
531
532
|
</div>
|
|
532
533
|
|
|
534
|
+
<!-- 修改密码 sheet(成员用户自助改密;管理员改密码在 /admin) -->
|
|
535
|
+
<div id="passwd-backdrop" onclick="closePasswdSheet()" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.55);z-index:30"></div>
|
|
536
|
+
<div id="passwd-sheet" style="display:none;position:fixed;left:0;right:0;bottom:0;z-index:31;background:var(--surface);border-radius:16px 16px 0 0;padding:1rem 1rem calc(1rem + env(safe-area-inset-bottom));max-height:88vh;overflow-y:auto">
|
|
537
|
+
<div class="sheet-handle"></div>
|
|
538
|
+
<div class="sheet-title">🔑 修改我的密码</div>
|
|
539
|
+
<div style="font-size:0.7rem;color:var(--muted);line-height:1.55;margin-bottom:0.6rem">
|
|
540
|
+
需要验证原密码才能修改;新密码不能与其他用户的密码重复,至少 4 位。改完当前登录保持有效,下次登录用新密码。
|
|
541
|
+
</div>
|
|
542
|
+
<div class="field">
|
|
543
|
+
<label>原密码</label>
|
|
544
|
+
<input type="password" id="pw-old" autocomplete="current-password" style="width:100%;box-sizing:border-box;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);padding:0.6rem;font-size:0.85rem">
|
|
545
|
+
</div>
|
|
546
|
+
<div class="field">
|
|
547
|
+
<label>新密码</label>
|
|
548
|
+
<input type="password" id="pw-new" autocomplete="new-password" style="width:100%;box-sizing:border-box;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);padding:0.6rem;font-size:0.85rem">
|
|
549
|
+
</div>
|
|
550
|
+
<div class="field">
|
|
551
|
+
<label>确认新密码</label>
|
|
552
|
+
<input type="password" id="pw-new2" autocomplete="new-password" style="width:100%;box-sizing:border-box;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);padding:0.6rem;font-size:0.85rem">
|
|
553
|
+
</div>
|
|
554
|
+
<div id="pw-msg" style="font-size:0.75rem;color:var(--red);margin:0 0 0.4rem;min-height:1rem"></div>
|
|
555
|
+
<button onclick="submitPasswd()" style="width:100%;background:#d29922;color:#1a1a1a;border:none;border-radius:10px;padding:0.75rem;font-size:0.9rem;font-weight:700;cursor:pointer">确认修改</button>
|
|
556
|
+
<button onclick="closePasswdSheet()" style="width:100%;background:var(--bg);color:var(--muted);border:1px solid var(--border);border-radius:10px;padding:0.65rem;font-size:0.85rem;cursor:pointer;margin-top:0.5rem">取消</button>
|
|
557
|
+
</div>
|
|
558
|
+
|
|
533
559
|
<!-- Create sheet -->
|
|
534
560
|
<div id="sheet-backdrop" onclick="closeSheet()"></div>
|
|
535
561
|
<div id="sheet">
|
|
@@ -633,6 +659,10 @@
|
|
|
633
659
|
document.getElementById('user-name').textContent = data.name;
|
|
634
660
|
document.getElementById('logout-btn').style.display = '';
|
|
635
661
|
}
|
|
662
|
+
// 成员用户(users.json 登录)才显示自助改密入口;管理员改密码在 /admin
|
|
663
|
+
if (data.hasUsers && data.role === 'operator') {
|
|
664
|
+
document.getElementById('passwd-btn').style.display = '';
|
|
665
|
+
}
|
|
636
666
|
if (data.dir) {
|
|
637
667
|
_userDir = data.dir;
|
|
638
668
|
// 默认填入绑定目录,隐藏盘符栏,保留最近目录
|
|
@@ -699,6 +729,43 @@
|
|
|
699
729
|
}
|
|
700
730
|
}
|
|
701
731
|
|
|
732
|
+
// ── 修改密码(成员用户自助)────────────────────────────
|
|
733
|
+
window.openPasswdSheet = function() {
|
|
734
|
+
document.getElementById('pw-old').value = '';
|
|
735
|
+
document.getElementById('pw-new').value = '';
|
|
736
|
+
document.getElementById('pw-new2').value = '';
|
|
737
|
+
document.getElementById('pw-msg').textContent = '';
|
|
738
|
+
document.getElementById('passwd-backdrop').style.display = 'block';
|
|
739
|
+
document.getElementById('passwd-sheet').style.display = 'block';
|
|
740
|
+
document.getElementById('pw-old').focus();
|
|
741
|
+
};
|
|
742
|
+
window.closePasswdSheet = function() {
|
|
743
|
+
document.getElementById('passwd-backdrop').style.display = 'none';
|
|
744
|
+
document.getElementById('passwd-sheet').style.display = 'none';
|
|
745
|
+
};
|
|
746
|
+
window.submitPasswd = async function() {
|
|
747
|
+
const msg = document.getElementById('pw-msg');
|
|
748
|
+
const oldPw = document.getElementById('pw-old').value;
|
|
749
|
+
const newPw = document.getElementById('pw-new').value;
|
|
750
|
+
const newPw2 = document.getElementById('pw-new2').value;
|
|
751
|
+
msg.style.color = 'var(--red)';
|
|
752
|
+
if (!oldPw) { msg.textContent = '请输入原密码'; return; }
|
|
753
|
+
if (newPw.length < 4) { msg.textContent = '新密码至少 4 位'; return; }
|
|
754
|
+
if (newPw !== newPw2) { msg.textContent = '两次输入的新密码不一致'; return; }
|
|
755
|
+
if (newPw === oldPw) { msg.textContent = '新密码不能与原密码相同'; return; }
|
|
756
|
+
try {
|
|
757
|
+
const r = await fetch('/api/user/password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ oldPassword: oldPw, newPassword: newPw }) });
|
|
758
|
+
const d = await r.json();
|
|
759
|
+
if (d.ok) {
|
|
760
|
+
msg.style.color = 'var(--green, #3fb950)';
|
|
761
|
+
msg.textContent = '✓ 密码已修改,下次登录请用新密码';
|
|
762
|
+
setTimeout(closePasswdSheet, 1500);
|
|
763
|
+
} else {
|
|
764
|
+
msg.textContent = d.error || '修改失败';
|
|
765
|
+
}
|
|
766
|
+
} catch { msg.textContent = '连接失败'; }
|
|
767
|
+
};
|
|
768
|
+
|
|
702
769
|
function doLogout() {
|
|
703
770
|
if (!confirm('确定退出登录?')) return;
|
|
704
771
|
fetch('/logout', { method: 'POST' }).finally(() => {
|