@wendongfly/myhi 1.3.166 → 1.3.168

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
@@ -3205,16 +3205,12 @@
3205
3205
  if (workState !== 'idle') {
3206
3206
  (async () => {
3207
3207
  try {
3208
- const r = await fetch('/api/inbox', {
3209
- method: 'POST', headers: { 'Content-Type': 'application/json' },
3210
- body: JSON.stringify({ text: prompt, sessionId: SESSION_ID, source: 'busy' }),
3211
- });
3212
- const d = await r.json();
3208
+ const d = await postDraft({ text: prompt, sessionId: SESSION_ID, source: 'busy' });
3213
3209
  if (d.error) { addStatusMessage('存草稿失败: ' + d.error); return; }
3214
3210
  _draftTipDismissed = false;
3215
3211
  await refreshInbox();
3216
3212
  addStatusMessage('📥 AI 正在跑,已把「重读 ' + p + '」存进草稿,干完自动接上');
3217
- } catch (e) { addStatusMessage('存草稿失败: ' + e.message); }
3213
+ } catch (e) { addStatusMessage('存草稿失败: ' + draftErrMsg(e)); }
3218
3214
  })();
3219
3215
  return;
3220
3216
  }
@@ -4034,6 +4030,29 @@
4034
4030
  let _inboxCache = { drafts: [], counts: {} };
4035
4031
  let _draftTipDismissed = false;
4036
4032
 
4033
+ // 存草稿统一走这里:网络层失败(Failed to fetch,多为连接被复用竞争/瞬时断连)
4034
+ // 自动重试一次;clientKey 让服务端去重,重试不会记两条。
4035
+ async function postDraft(body) {
4036
+ body.clientKey = (crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`);
4037
+ let lastErr;
4038
+ for (let i = 0; i < 2; i++) {
4039
+ try {
4040
+ const r = await fetch('/api/inbox', {
4041
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
4042
+ body: JSON.stringify(body),
4043
+ });
4044
+ return await r.json();
4045
+ } catch (e) {
4046
+ lastErr = e;
4047
+ if (!i) await new Promise((res) => setTimeout(res, 400));
4048
+ }
4049
+ }
4050
+ throw lastErr;
4051
+ }
4052
+ function draftErrMsg(e) {
4053
+ return e.message === 'Failed to fetch' ? '网络连接中断(重试仍失败)' : e.message;
4054
+ }
4055
+
4037
4056
  async function refreshInbox(silent = true) {
4038
4057
  try {
4039
4058
  const r = await fetch('/api/inbox');
@@ -4187,15 +4206,11 @@
4187
4206
  const text = ta.value.trim();
4188
4207
  if (!text && !_inboxNewImage) { addStatusMessage('写点什么或加张图再记'); return; }
4189
4208
  try {
4190
- const r = await fetch('/api/inbox', {
4191
- method: 'POST', headers: { 'Content-Type': 'application/json' },
4192
- body: JSON.stringify({
4193
- text, sessionId: SESSION_ID, source: 'manual',
4194
- autoSend: document.getElementById('inbox-new-autosend').checked,
4195
- images: _inboxNewImage ? [_inboxNewImage] : [],
4196
- }),
4209
+ const d = await postDraft({
4210
+ text, sessionId: SESSION_ID, source: 'manual',
4211
+ autoSend: document.getElementById('inbox-new-autosend').checked,
4212
+ images: _inboxNewImage ? [_inboxNewImage] : [],
4197
4213
  });
4198
- const d = await r.json();
4199
4214
  if (d.error) { addStatusMessage('存草稿失败: ' + d.error); return; }
4200
4215
  ta.value = '';
4201
4216
  clearInboxNewImage();
@@ -4203,7 +4218,7 @@
4203
4218
  await refreshInbox();
4204
4219
  renderInbox();
4205
4220
  } catch (e) {
4206
- addStatusMessage('存草稿失败: ' + e.message);
4221
+ addStatusMessage('存草稿失败: ' + draftErrMsg(e));
4207
4222
  }
4208
4223
  };
4209
4224
 
@@ -4219,10 +4234,7 @@
4219
4234
  files: _pendingFile ? [{ path: _pendingFile.path, name: _pendingFile.name }] : [],
4220
4235
  };
4221
4236
  try {
4222
- const r = await fetch('/api/inbox', {
4223
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body),
4224
- });
4225
- const d = await r.json();
4237
+ const d = await postDraft(body);
4226
4238
  if (d.error) { addStatusMessage('存草稿失败: ' + d.error); return false; }
4227
4239
  cmdInput.value = '';
4228
4240
  cmdInput.style.height = 'auto';
@@ -4236,7 +4248,7 @@
4236
4248
  : '📥 已存进草稿');
4237
4249
  return true;
4238
4250
  } catch (e) {
4239
- addStatusMessage('存草稿失败: ' + e.message);
4251
+ addStatusMessage('存草稿失败: ' + draftErrMsg(e));
4240
4252
  return false;
4241
4253
  }
4242
4254
  };
package/dist/index.html CHANGED
@@ -81,6 +81,28 @@
81
81
  #conn-dot.on { background: var(--green); box-shadow: 0 0 6px var(--green); }
82
82
  #conn-dot.off { background: var(--red); }
83
83
 
84
+ /* 顶栏右侧按钮组:空间不够时整组换行,但按钮自身永不收缩——
85
+ 否则中文标签被挤成一字一行竖排(手机端反馈「不美观」的主因) */
86
+ .hd-actions {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: 0.6rem;
90
+ flex-wrap: wrap;
91
+ justify-content: flex-end;
92
+ }
93
+ .hd-btn {
94
+ background: none; border: 1px solid var(--border); color: var(--muted);
95
+ font-size: 0.75rem; padding: 0.3rem 0.6rem; border-radius: 6px; cursor: pointer;
96
+ width: auto; white-space: nowrap; flex-shrink: 0;
97
+ }
98
+ /* 手机(≤540px):藏用户名、文字标签只留图标,一行放下且不憋屈 */
99
+ @media (max-width: 540px) {
100
+ #user-name { display: none; }
101
+ .hd-actions { gap: 0.4rem; }
102
+ .hd-btn { padding: 0.32rem 0.48rem; }
103
+ .hd-btn .hd-txt { display: none; }
104
+ }
105
+
84
106
  /* ── Session list ── */
85
107
  #list {
86
108
  flex: 1;
@@ -456,14 +478,14 @@
456
478
  <div id="app">
457
479
  <div id="header">
458
480
  <div class="logo">my<span>hi</span></div>
459
- <div style="display:flex;align-items:center;gap:0.6rem">
481
+ <div class="hd-actions">
460
482
  <span id="user-name" style="font-size:0.8rem;color:var(--muted)"></span>
461
- <button id="grid-btn" onclick="location.href='/grid'" title="分屏工作台(多任务并排)" 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>
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
- <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
- <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>
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>
483
+ <button id="grid-btn" class="hd-btn" onclick="location.href='/grid'" title="分屏工作台(多任务并排)">▦ 分屏</button>
484
+ <button id="appearance-btn" class="hd-btn" onclick="openAppearance()" title="外观">🎨</button>
485
+ <button id="doctor-btn" class="hd-btn" onclick="openDoctor()" title="会话体检">🩺<span class="hd-txt"> 体检</span></button>
486
+ <button id="usage-btn" class="hd-btn" onclick="showUsage()" title="用量">📊<span class="hd-txt"> 用量</span></button>
487
+ <button id="passwd-btn" class="hd-btn" onclick="openPasswdSheet()" title="修改我的密码" style="display:none">🔑<span class="hd-txt"> 改密码</span></button>
488
+ <button id="logout-btn" class="hd-btn" onclick="doLogout()" style="display:none">退出</button>
467
489
  <div id="conn-dot"></div>
468
490
  </div>
469
491
  </div>
@@ -1158,20 +1180,31 @@
1158
1180
  if (!sid) { alert('请选择归属任务'); return; }
1159
1181
  if (!text && !_notePendingImage) { alert('写点什么或传张图'); return; }
1160
1182
  try {
1161
- const r = await fetch('/api/inbox', {
1162
- method: 'POST', headers: { 'Content-Type': 'application/json' },
1163
- body: JSON.stringify({
1164
- text, sessionId: sid, source: 'home',
1165
- autoSend: document.getElementById('note-autosend').checked,
1166
- images: _notePendingImage ? [{ path: _notePendingImage.path, name: '图片' }] : [],
1167
- }),
1168
- });
1169
- const d = await r.json();
1183
+ // 网络层失败自动重试一次;clientKey 让服务端去重,重试不会记两条
1184
+ const clientKey = (crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`);
1185
+ let d;
1186
+ for (let i = 0; i < 2; i++) {
1187
+ try {
1188
+ const r = await fetch('/api/inbox', {
1189
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
1190
+ body: JSON.stringify({
1191
+ text, sessionId: sid, source: 'home', clientKey,
1192
+ autoSend: document.getElementById('note-autosend').checked,
1193
+ images: _notePendingImage ? [{ path: _notePendingImage.path, name: '图片' }] : [],
1194
+ }),
1195
+ });
1196
+ d = await r.json();
1197
+ break;
1198
+ } catch (e) {
1199
+ if (i) throw e;
1200
+ await new Promise((res) => setTimeout(res, 400));
1201
+ }
1202
+ }
1170
1203
  if (d.error) { alert('存草稿失败:' + d.error); return; }
1171
1204
  closeNoteSheet();
1172
1205
  refreshDraftCounts();
1173
1206
  } catch (e) {
1174
- alert('存草稿失败:' + e.message);
1207
+ alert('存草稿失败:' + (e.message === 'Failed to fetch' ? '网络连接中断(重试仍失败)' : e.message));
1175
1208
  }
1176
1209
  };
1177
1210