@wendongfly/myhi 1.0.57 → 1.0.59

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 CHANGED
@@ -224,14 +224,14 @@
224
224
  <div id="status-bar">
225
225
  <span class="sb-item" id="work-status"><span class="sb-dot idle"></span> 空闲</span>
226
226
  <span id="mode-badge" onclick="switchMode()">默认</span>
227
- <span id="control-badge" class="readonly" onclick="toggleControl()">只读</span>
227
+ <span id="control-badge" class="readonly" style="display:none">只读</span>
228
228
  <span id="viewer-count" class="sb-item"></span>
229
229
  </div>
230
230
 
231
231
  <div id="chat-area"></div>
232
232
 
233
233
  <div id="input-area">
234
- <div id="readonly-overlay">只读模式 — 点击状态栏"获取控制"开始输入</div>
234
+ <div id="readonly-overlay" style="display:none"></div>
235
235
  <div id="input-box">
236
236
  <div id="img-preview">
237
237
  <img id="img-preview-thumb" src="" alt="">
@@ -340,36 +340,46 @@
340
340
  try {
341
341
  const res = await fetch('/api/usage');
342
342
  const data = await res.json();
343
- let html = '<div style="padding:1.25rem;max-width:500px">';
344
- html += '<h3 style="margin:0 0 1rem;font-size:1rem">Claude 用量统计</h3>';
343
+ const C = 'style="margin-bottom:1rem;padding:0.8rem 1rem;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:10px"';
344
+ const H = 'style="font-size:0.9rem;font-weight:700;margin-bottom:0.5rem;color:#e6edf3"';
345
+ const T = 'style="font-size:0.82rem;color:#b1bac4;line-height:1.6"';
346
+ let html = '<div style="padding:1.5rem">';
347
+ html += '<h3 style="margin:0 0 1.2rem;font-size:1.1rem;color:#fff;text-align:center">Claude 用量统计</h3>';
345
348
  if (data.rateLimit) {
346
349
  const rl = data.rateLimit;
347
350
  const remaining = Math.max(0, Math.ceil((new Date(rl.resetsAt * 1000) - Date.now()) / 60000));
348
- html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
349
- html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">5小时窗口</div>';
350
- html += `<div style="font-size:0.8rem;color:var(--muted)">状态: ${rl.status === 'allowed' ? ' 正常' : ' 受限'} 重置: ${remaining}分钟后</div></div>`;
351
+ const statusColor = rl.status === 'allowed' ? '#3fb950' : '#f85149';
352
+ html += `<div ${C}><div ${H}>5小时窗口</div>`;
353
+ html += `<div ${T}><span style="color:${statusColor};font-weight:600">${rl.status === 'allowed' ? ' 正常' : ' 受限'}</span> 重置: ${remaining} 分钟后</div></div>`;
354
+ } else {
355
+ html += `<div ${C}><div ${H}>5小时窗口</div><div ${T}>发送 Agent 消息后可查看</div></div>`;
351
356
  }
352
357
  if (data.sevenDay) {
353
358
  const s = data.sevenDay;
354
- html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
355
- html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">近7天</div>';
356
- html += `<div style="font-size:0.8rem;color:var(--muted)">消息: ${s.messageCount.toLocaleString()} 会话: ${s.sessionCount} 工具: ${s.toolCallCount.toLocaleString()}</div></div>`;
359
+ html += `<div ${C}><div ${H}>近 7 天</div>`;
360
+ html += `<div ${T}>消息 <b style="color:#e6edf3">${s.messageCount.toLocaleString()}</b> 会话 <b style="color:#e6edf3">${s.sessionCount}</b> 工具调用 <b style="color:#e6edf3">${s.toolCallCount.toLocaleString()}</b></div></div>`;
357
361
  }
358
362
  if (data.activeSessions?.length) {
359
- html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
360
- html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">当前会话</div>';
363
+ html += `<div ${C}><div ${H}>当前活跃会话</div>`;
361
364
  for (const s of data.activeSessions) {
362
365
  if (!s.usage) continue;
363
- html += `<div style="font-size:0.8rem;color:var(--muted)">${s.title}: ${s.usage.queryCount}次, $${s.usage.totalCostUSD.toFixed(4)}</div>`;
366
+ html += `<div ${T}>${s.title} <b style="color:#e6edf3">${s.usage.queryCount}</b> 次查询 <b style="color:#e6edf3">$${s.usage.totalCostUSD.toFixed(4)}</b></div>`;
364
367
  }
365
368
  html += '</div>';
366
369
  }
367
- html += '<button onclick="this.parentElement.parentElement.remove()" style="margin-top:0.5rem;width:100%;padding:0.6rem;background:var(--accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:0.85rem">关闭</button></div>';
370
+ if (data.totalStats) {
371
+ const t = data.totalStats;
372
+ html += `<div ${C}><div ${H}>累计(截至 ${t.lastComputedDate || '未知'})</div>`;
373
+ html += `<div ${T}>总会话 <b style="color:#e6edf3">${t.totalSessions}</b> 总消息 <b style="color:#e6edf3">${t.totalMessages?.toLocaleString()}</b></div>`;
374
+ if (t.modelUsage) { for (const [m, u] of Object.entries(t.modelUsage)) { if (u.outputTokens > 0) html += `<div style="font-size:0.75rem;color:#8b949e;margin-top:0.3rem">${m.replace(/claude-/,'').replace(/-\d{8}$/,'')} 输入 ${(u.inputTokens/1000).toFixed(0)}K 输出 ${(u.outputTokens/1000).toFixed(0)}K</div>`; } }
375
+ html += '</div>';
376
+ }
377
+ html += '<button onclick="this.parentElement.parentElement.remove()" style="margin-top:0.8rem;width:100%;padding:0.7rem;background:#7c3aed;color:#fff;border:none;border-radius:10px;cursor:pointer;font-size:0.9rem;font-weight:600">关闭</button></div>';
368
378
  const overlay = document.createElement('div');
369
- overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:999;display:flex;align-items:center;justify-content:center';
379
+ overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.6);z-index:999;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px)';
370
380
  overlay.onclick = (e) => { if (e.target === overlay) overlay.remove(); };
371
381
  const box = document.createElement('div');
372
- box.style.cssText = 'background:var(--surface);border-radius:16px;max-height:80vh;overflow-y:auto;width:90%;max-width:400px';
382
+ box.style.cssText = 'background:#161b22;border:1px solid rgba(255,255,255,0.12);border-radius:16px;max-height:80vh;overflow-y:auto;width:90%;max-width:420px;box-shadow:0 16px 48px rgba(0,0,0,0.4)';
373
383
  box.innerHTML = html;
374
384
  overlay.appendChild(box);
375
385
  document.body.appendChild(overlay);
@@ -1354,7 +1364,7 @@
1354
1364
  };
1355
1365
  function selectModel(m) {
1356
1366
  closeModelSheet();
1357
- if (!isController) { addStatusMessage('请先获取控制权'); return; }
1367
+ if (!isController) { if (canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID }); else { addStatusMessage('其他用户控制中'); return; } }
1358
1368
  if (currentSession?.mode === 'agent') {
1359
1369
  // Agent 模式:通过命令设置
1360
1370
  cmdInput.value = '/model ' + m.id;
@@ -1374,7 +1384,7 @@
1374
1384
 
1375
1385
  // ── 恢复会话 ──────────────────────────────────
1376
1386
  window.openResumeSheet = async function() {
1377
- if (!isController) { addStatusMessage('请先获取控制权'); return; }
1387
+ if (!isController) { if (canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID }); else { addStatusMessage('其他用户控制中'); return; } }
1378
1388
  const list = document.getElementById('resume-list');
1379
1389
  list.innerHTML = '<div style="text-align:center;padding:1rem;color:#8b949e">加载中...</div>';
1380
1390
  document.getElementById('resume-sheet').classList.add('open');
@@ -1422,7 +1432,7 @@
1422
1432
 
1423
1433
  // ── 压缩对话 ──────────────────────────────────
1424
1434
  window.doCompact = function() {
1425
- if (!isController) { addStatusMessage('请先获取控制权'); return; }
1435
+ if (!isController) { if (canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID }); else { addStatusMessage('其他用户控制中'); return; } }
1426
1436
  if (currentSession?.mode === 'agent') {
1427
1437
  cmdInput.value = '/compact';
1428
1438
  sendCommand();
package/dist/index.html CHANGED
@@ -529,73 +529,46 @@
529
529
  try {
530
530
  const res = await fetch('/api/usage');
531
531
  const data = await res.json();
532
- let html = '<div style="padding:1.25rem;max-width:500px">';
533
- html += '<h3 style="margin:0 0 1rem;font-size:1rem">Claude 用量统计</h3>';
534
-
535
- // 5小时限额
532
+ const C = 'style="margin-bottom:1rem;padding:0.8rem 1rem;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:10px"';
533
+ const H = 'style="font-size:0.9rem;font-weight:700;margin-bottom:0.5rem;color:#e6edf3"';
534
+ const T = 'style="font-size:0.82rem;color:#b1bac4;line-height:1.6"';
535
+ let html = '<div style="padding:1.5rem">';
536
+ html += '<h3 style="margin:0 0 1.2rem;font-size:1.1rem;color:#fff;text-align:center">Claude 用量统计</h3>';
536
537
  if (data.rateLimit) {
537
538
  const rl = data.rateLimit;
538
- const resetTime = new Date(rl.resetsAt * 1000);
539
- const remaining = Math.max(0, Math.ceil((resetTime - Date.now()) / 60000));
540
- html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
541
- html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">5小时窗口</div>';
542
- html += `<div style="font-size:0.8rem;color:var(--muted)">状态: ${rl.status === 'allowed' ? '✓ 正常' : '⚠ 受限'}</div>`;
543
- html += `<div style="font-size:0.8rem;color:var(--muted)">重置时间: ${remaining} 分钟后</div>`;
544
- html += '</div>';
539
+ const remaining = Math.max(0, Math.ceil((new Date(rl.resetsAt * 1000) - Date.now()) / 60000));
540
+ const statusColor = rl.status === 'allowed' ? '#3fb950' : '#f85149';
541
+ html += `<div ${C}><div ${H}>5小时窗口</div>`;
542
+ html += `<div ${T}><span style="color:${statusColor};font-weight:600">${rl.status === 'allowed' ? '● 正常' : '● 受限'}</span> 重置: ${remaining} 分钟后</div></div>`;
545
543
  } else {
546
- html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
547
- html += '<div style="font-size:0.85rem;color:var(--muted)">5小时窗口: 发送一条 Agent 消息后可查看</div></div>';
544
+ html += `<div ${C}><div ${H}>5小时窗口</div><div ${T}>发送 Agent 消息后可查看</div></div>`;
548
545
  }
549
-
550
- // 7天用量
551
546
  if (data.sevenDay) {
552
547
  const s = data.sevenDay;
553
- html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
554
- html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">近7天</div>';
555
- html += `<div style="font-size:0.8rem;color:var(--muted)">消息: ${s.messageCount.toLocaleString()}</div>`;
556
- html += `<div style="font-size:0.8rem;color:var(--muted)">会话: ${s.sessionCount}</div>`;
557
- html += `<div style="font-size:0.8rem;color:var(--muted)">工具调用: ${s.toolCallCount.toLocaleString()}</div>`;
558
- html += '</div>';
548
+ html += `<div ${C}><div ${H}>近 7 天</div>`;
549
+ html += `<div ${T}>消息 <b style="color:#e6edf3">${s.messageCount.toLocaleString()}</b> 会话 <b style="color:#e6edf3">${s.sessionCount}</b> 工具调用 <b style="color:#e6edf3">${s.toolCallCount.toLocaleString()}</b></div></div>`;
559
550
  }
560
-
561
- // 活跃会话用量
562
551
  if (data.activeSessions?.length) {
563
- html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
564
- html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">当前会话</div>';
552
+ html += `<div ${C}><div ${H}>当前活跃会话</div>`;
565
553
  for (const s of data.activeSessions) {
566
554
  if (!s.usage) continue;
567
- const u = s.usage;
568
- html += `<div style="font-size:0.8rem;color:var(--muted);margin-top:0.3rem">${s.title}: ${u.queryCount}次查询, $${u.totalCostUSD.toFixed(4)}</div>`;
555
+ html += `<div ${T}>${s.title} <b style="color:#e6edf3">${s.usage.queryCount}</b> 次查询 <b style="color:#e6edf3">$${s.usage.totalCostUSD.toFixed(4)}</b></div>`;
569
556
  }
570
557
  html += '</div>';
571
558
  }
572
-
573
- // 累计总量
574
559
  if (data.totalStats) {
575
560
  const t = data.totalStats;
576
- html += '<div style="padding:0.8rem;background:var(--bg);border-radius:8px">';
577
- html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">累计(截至 ' + (t.lastComputedDate || '未知') + ')</div>';
578
- html += `<div style="font-size:0.8rem;color:var(--muted)">总会话: ${t.totalSessions}</div>`;
579
- html += `<div style="font-size:0.8rem;color:var(--muted)">总消息: ${t.totalMessages?.toLocaleString()}</div>`;
580
- if (t.modelUsage) {
581
- for (const [model, u] of Object.entries(t.modelUsage)) {
582
- if (u.outputTokens > 0) {
583
- const shortName = model.replace(/claude-/, '').replace(/-\d{8}$/, '');
584
- html += `<div style="font-size:0.75rem;color:var(--muted);margin-top:0.2rem">${shortName}: 输入${(u.inputTokens/1000).toFixed(0)}K 输出${(u.outputTokens/1000).toFixed(0)}K</div>`;
585
- }
586
- }
587
- }
561
+ html += `<div ${C}><div ${H}>累计(截至 ${t.lastComputedDate || '未知'})</div>`;
562
+ html += `<div ${T}>总会话 <b style="color:#e6edf3">${t.totalSessions}</b> 总消息 <b style="color:#e6edf3">${t.totalMessages?.toLocaleString()}</b></div>`;
563
+ if (t.modelUsage) { for (const [m, u] of Object.entries(t.modelUsage)) { if (u.outputTokens > 0) html += `<div style="font-size:0.75rem;color:#8b949e;margin-top:0.3rem">${m.replace(/claude-/,'').replace(/-\d{8}$/,'')} 输入 ${(u.inputTokens/1000).toFixed(0)}K 输出 ${(u.outputTokens/1000).toFixed(0)}K</div>`; } }
588
564
  html += '</div>';
589
565
  }
590
-
591
- html += '<button onclick="this.parentElement.parentElement.remove()" style="margin-top:1rem;width:100%;padding:0.6rem;background:var(--accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:0.85rem">关闭</button>';
592
- html += '</div>';
593
-
566
+ html += '<button onclick="this.parentElement.parentElement.remove()" style="margin-top:0.8rem;width:100%;padding:0.7rem;background:#7c3aed;color:#fff;border:none;border-radius:10px;cursor:pointer;font-size:0.9rem;font-weight:600">关闭</button></div>';
594
567
  const overlay = document.createElement('div');
595
- overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:999;display:flex;align-items:center;justify-content:center';
568
+ overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.6);z-index:999;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px)';
596
569
  overlay.onclick = (e) => { if (e.target === overlay) overlay.remove(); };
597
570
  const box = document.createElement('div');
598
- box.style.cssText = 'background:var(--surface);border-radius:16px;max-height:80vh;overflow-y:auto;width:90%;max-width:400px';
571
+ box.style.cssText = 'background:#161b22;border:1px solid rgba(255,255,255,0.12);border-radius:16px;max-height:80vh;overflow-y:auto;width:90%;max-width:420px;box-shadow:0 16px 48px rgba(0,0,0,0.4)';
599
572
  box.innerHTML = html;
600
573
  overlay.appendChild(box);
601
574
  document.body.appendChild(overlay);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wendongfly/myhi",
3
- "version": "1.0.57",
3
+ "version": "1.0.59",
4
4
  "description": "Web-based terminal sharing with chat UI — control your terminal from phone via LAN/Tailscale",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",