@awiki/dsh-plugin 0.2.0-rc.4 → 0.2.0

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/README.md CHANGED
@@ -20,9 +20,10 @@ TypeScript SDK `identity.json`; create a new Rust-backed identity after upgradin
20
20
  - Open the top-left AWiki account menu to sign out locally without deleting the encrypted identity or message database; **Resume** restores the same DID and Handle, including across DSH restarts.
21
21
  - Reuse that identity across the root Agent and its subagents.
22
22
  - Direct-message and existing-group conversation lists, unread counts, latest-message previews, and persisted display names.
23
- - Text messages plus one attachment per message, with image previews and SHA verification.
23
+ - Text messages plus one attachment per message, with Enter-to-send, Shift+Enter line breaks, optimistic sending bubbles, image previews, and SHA verification.
24
24
  - A draggable circular launcher, adaptive popup placement, dark mode, and remembered active conversation.
25
25
  - User-triggered AI summaries for up to 50 recent or unread messages, kept only in runtime memory with explicit stale, retry, copy, and source-navigation states.
26
+ - OTP registration keeps the verification form visible and disables resend with a visible server-directed cooldown countdown.
26
27
  - An AWiki page in DSH Settings for a durable, validated default Handle domain.
27
28
  - A typed second confirmation in the Settings danger zone before permanently clearing local AWiki identity, key, token, registration-draft, and message-index state.
28
29
  - Five approval-aware Agent tools: identity status, conversations, history, text send, and attachment send.
package/README.zh.md CHANGED
@@ -14,9 +14,10 @@ Rust 身份。
14
14
  - 点击 AWiki 面板左上角图标可打开账户菜单;普通退出只锁定本机会话,不删除加密身份或消息数据库,重新进入及重启 DSH 后仍恢复同一个 DID 和 Handle。
15
15
  - 注册失败时保留手机号、Handle、验证码和本机待注册密钥;注册未开放、验证码状态失效和提交冲突会给出对应的安全处理提示。
16
16
  - 私聊和已有群聊列表、未读角标、最新消息预览、时间更新与昵称持久化。
17
- - 文本和单附件消息,支持图片预览、附件说明与 SHA 校验。
17
+ - 文本和单附件消息;Enter 发送、Shift+Enter 换行,发送中立即显示带 loading 动画的乐观气泡,并支持图片预览、附件说明与 SHA 校验。
18
18
  - 圆形可拖动入口、自适应四角弹窗、深色模式和当前会话记忆。
19
19
  - 用户点击后才生成的 AI 对话总结:最多处理 50 条最近或未读消息,按会话保留本次运行期缓存,并支持过期提示、重试、复制与跳转原消息。
20
+ - OTP 注册会保留验证码输入表单,并按服务端返回的冷却时间显示重发倒计时、禁用提前重发。
20
21
  - 在 DSH 设置中提供 AWiki 页面,可持久化修改并校验默认 Handle 域名。
21
22
  - 在设置页危险区域中,经输入确认词的二次确认后,永久清空本机 AWiki 身份、密钥、令牌、注册草稿和消息索引。
22
23
  - 五个受 Harness 审批约束的 Agent 工具:身份、会话、历史、文本发送、附件发送。
package/lib/client.js CHANGED
@@ -5452,6 +5452,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5452
5452
  disposed = false;
5453
5453
  polling = false;
5454
5454
  unreadAtOpen = /* @__PURE__ */ new Map();
5455
+ summaryBaselines = /* @__PURE__ */ new Map();
5455
5456
  /** @param remote - generated Host Remote namespace. */
5456
5457
  constructor(remote) {
5457
5458
  this.remote = remote;
@@ -5475,6 +5476,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5475
5476
  error: "AWiki 插件已卸载"
5476
5477
  };
5477
5478
  this.close();
5479
+ this.summaryBaselines.clear();
5478
5480
  const generation = this.generation;
5479
5481
  this.publish({
5480
5482
  ...INITIAL_VIEW,
@@ -5525,6 +5527,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5525
5527
  this.close();
5526
5528
  this.conversationsCursor = void 0;
5527
5529
  this.historyCursor = void 0;
5530
+ this.summaryBaselines.clear();
5528
5531
  this.publish({
5529
5532
  ...INITIAL_VIEW,
5530
5533
  status: "ready",
@@ -5771,6 +5774,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5771
5774
  stale: false,
5772
5775
  result: result.value
5773
5776
  });
5777
+ const latestSentAt = Math.max(result.value.range.endedAt, ...this.view.messages.map((message) => message.sentAt));
5778
+ const messageIdsAtLatest = new Set(this.view.messages.filter((message) => message.sentAt === latestSentAt).map((message) => message.id));
5779
+ if (result.value.range.endedAt === latestSentAt) messageIdsAtLatest.add(result.value.range.lastMessageId);
5780
+ this.summaryBaselines.set(conversationId, {
5781
+ latestSentAt,
5782
+ messageIdsAtLatest
5783
+ });
5774
5784
  return result;
5775
5785
  }
5776
5786
  /** Expand or collapse one cached summary without another model call. */
@@ -5872,6 +5882,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5872
5882
  this.conversationsCursor = void 0;
5873
5883
  this.historyCursor = void 0;
5874
5884
  this.unreadAtOpen.clear();
5885
+ this.summaryBaselines.clear();
5875
5886
  this.publish({
5876
5887
  ...INITIAL_VIEW,
5877
5888
  status: "ready"
@@ -5929,7 +5940,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5929
5940
  ...this.view,
5930
5941
  messages,
5931
5942
  historyHasMore: result.value.hasMore && result.value.nextCursor !== void 0,
5932
- summaries: this.staleSummaries(conversationId, messages)
5943
+ summaries: older ? this.view.summaries : this.staleSummaries(conversationId, result.value.items)
5933
5944
  });
5934
5945
  return {
5935
5946
  ok: true,
@@ -5945,13 +5956,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5945
5956
  if (selected === null || !this.current(generation)) return;
5946
5957
  const result = await call(() => this.remote.getHistory({ conversationId: selected }));
5947
5958
  if (!this.current(generation) || !result.ok || this.view.selectedConversationId !== selected) return;
5959
+ const existingIds = new Set(this.view.messages.map((message) => message.id));
5960
+ const incoming = result.value.items.filter((message) => !existingIds.has(message.id));
5948
5961
  const messages = appendUnique(this.view.messages, result.value.items, (value) => value.id);
5949
5962
  const added = messages.length - this.view.messages.length;
5950
5963
  if (added > 0 && (this.unreadAtOpen.get(selected) ?? 0) > 0) this.unreadAtOpen.set(selected, (this.unreadAtOpen.get(selected) ?? 0) + added);
5951
5964
  this.publish({
5952
5965
  ...this.view,
5953
5966
  messages,
5954
- summaries: this.staleSummaries(selected, messages)
5967
+ summaries: this.staleSummaries(selected, incoming)
5955
5968
  });
5956
5969
  } finally {
5957
5970
  this.polling = false;
@@ -5978,12 +5991,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5978
5991
  return result;
5979
5992
  }
5980
5993
  appendMessage(message) {
5994
+ const isNew = !this.view.messages.some((current) => current.id === message.id);
5981
5995
  const messages = appendUnique(this.view.messages, [message], (value) => value.id);
5982
5996
  if ((this.unreadAtOpen.get(message.conversationId) ?? 0) > 0 && messages.length > this.view.messages.length) this.unreadAtOpen.set(message.conversationId, (this.unreadAtOpen.get(message.conversationId) ?? 0) + 1);
5983
5997
  this.publish({
5984
5998
  ...this.view,
5985
5999
  messages,
5986
- summaries: this.staleSummaries(message.conversationId, messages),
6000
+ summaries: isNew ? this.markSummaryStale(message.conversationId) : this.view.summaries,
5987
6001
  error: null
5988
6002
  });
5989
6003
  }
@@ -5999,7 +6013,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5999
6013
  staleSummaries(conversationId, messages) {
6000
6014
  const summary = this.view.summaries[conversationId];
6001
6015
  if (summary?.status !== "success" || summary.result === void 0 || summary.stale) return this.view.summaries;
6002
- if (!messages.some((message) => message.sentAt > summary.result.range.endedAt)) return this.view.summaries;
6016
+ const baseline = this.summaryBaselines.get(conversationId) ?? {
6017
+ latestSentAt: summary.result.range.endedAt,
6018
+ messageIdsAtLatest: /* @__PURE__ */ new Set([summary.result.range.lastMessageId])
6019
+ };
6020
+ if (!messages.some((message) => message.sentAt > baseline.latestSentAt || message.sentAt === baseline.latestSentAt && !baseline.messageIdsAtLatest.has(message.id))) return this.view.summaries;
6021
+ return this.markSummaryStale(conversationId);
6022
+ }
6023
+ markSummaryStale(conversationId) {
6024
+ const summary = this.view.summaries[conversationId];
6025
+ if (summary?.status !== "success" || summary.stale) return this.view.summaries;
6003
6026
  return Object.freeze({
6004
6027
  ...this.view.summaries,
6005
6028
  [conversationId]: Object.freeze({
@@ -6147,7 +6170,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6147
6170
  }
6148
6171
  //#endregion
6149
6172
  //#region \0dsh-awiki-css:AwikiOverlay.module.css.mjs
6150
- const css$1 = ".EtEeYG_trigger{z-index:2;border:1px solid var(--dsw-alias-border-l2);width:48px;height:48px;color:var(--dsw-alias-brand-primary);box-shadow:var(--dsw-shadow-lv2);cursor:grab;font:inherit;touch-action:none;user-select:none;background:#fff;border-radius:50%;place-items:center;padding:0;display:grid;position:fixed;overflow:visible}.EtEeYG_trigger:hover{box-shadow:var(--dsw-shadow-lv3);background:#fff}.EtEeYG_trigger:active,.EtEeYG_trigger[data-dragging]{cursor:grabbing}.EtEeYG_launcherIcon{object-fit:cover;pointer-events:none;border-radius:50%;width:100%;height:100%;display:block}.EtEeYG_unreadBadge{border:2px solid var(--dsw-alias-bg-base);background:var(--dsw-alias-state-error-primary);color:#fff;box-sizing:border-box;pointer-events:none;border-radius:10px;place-items:center;min-width:20px;height:20px;padding:0 5px;font-size:11px;font-weight:600;line-height:16px;display:grid;position:absolute;top:-5px;right:-5px}.EtEeYG_trigger:focus-visible,.EtEeYG_drawer button:focus-visible,.EtEeYG_drawer input:focus-visible,.EtEeYG_drawer textarea:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.EtEeYG_drawer{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);z-index:1;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:min(720px,100vw - 80px);min-width:min(360px,100vw - 80px);height:min(720px,100vh - 16px);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3);border-radius:16px;flex-direction:column;display:flex;position:fixed;overflow:hidden}.EtEeYG_drawerHeader{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;touch-action:none;user-select:none;flex:none;align-items:center;gap:8px;height:58px;padding:0 14px 0 18px;display:flex}.EtEeYG_drawerHeader[data-dragging]{cursor:grabbing}.EtEeYG_drawerHeader>div{flex:1;align-items:center;gap:8px;display:flex}.EtEeYG_drawerHeader h2{margin:0;font-size:16px;line-height:24px}.EtEeYG_drawerHeader button,.EtEeYG_back{cursor:pointer;width:32px;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:9px;place-items:center;padding:0;display:grid}.EtEeYG_drawerHeader button:hover,.EtEeYG_back:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_centerState,.EtEeYG_registration,.EtEeYG_threadEmpty{text-align:center;color:var(--dsw-alias-label-secondary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:14px;padding:32px;display:flex}.EtEeYG_centerState p{overflow-wrap:anywhere;max-width:420px;margin:0}.EtEeYG_registration{box-sizing:border-box;align-items:stretch;width:min(360px,100%);margin:0 auto}.EtEeYG_registration h3{text-align:center;color:var(--dsw-alias-label-primary);margin:0}.EtEeYG_registration>p{margin:0;font-size:13px;line-height:20px}.EtEeYG_registrationIcon{background:var(--dsw-alias-interactive-bg-active);width:48px;height:48px;color:var(--dsw-alias-brand-primary);border-radius:50%;align-self:center;place-items:center;display:grid}.EtEeYG_registration label{text-align:left;color:var(--dsw-alias-label-secondary);gap:6px;font-size:13px;line-height:20px;display:grid}.EtEeYG_registration input,.EtEeYG_fileDraft input,.EtEeYG_composeRow textarea{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);width:100%;color:var(--dsw-alias-label-primary);font:inherit;border-radius:10px}.EtEeYG_registration input{height:40px;padding:0 12px}.EtEeYG_primary,.EtEeYG_more,.EtEeYG_fileDraft button{background:var(--dsw-alias-button-primary-fill);min-height:36px;color:var(--dsw-alias-label-primary-inverted);cursor:pointer;font:inherit;border:0;border-radius:10px;padding:0 14px}.EtEeYG_primary:hover,.EtEeYG_fileDraft button:hover{background:var(--dsw-alias-button-primary-hover)}.EtEeYG_primary:disabled,.EtEeYG_fileDraft button:disabled{opacity:.5;cursor:default}.EtEeYG_secondary{border:1px solid var(--dsw-alias-border-l2);min-height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;background:0 0;border-radius:10px;padding:0 14px}.EtEeYG_secondary:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_composeBackdrop{background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 72%, transparent);place-items:center;padding:24px;display:grid;position:absolute;inset:58px 0 0}.EtEeYG_composeCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);width:min(360px,100%);box-shadow:var(--dsw-shadow-lv3);border-radius:14px;gap:12px;padding:20px;display:grid}.EtEeYG_composeCard h3{margin:0;font-size:16px;line-height:24px}.EtEeYG_composeCard p{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:20px}.EtEeYG_composeCard label{color:var(--dsw-alias-label-secondary);gap:6px;font-size:13px;line-height:20px;display:grid}.EtEeYG_composeCard input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:40px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:10px;padding:0 12px}.EtEeYG_composeActions{justify-content:flex-end;gap:8px;display:flex}.EtEeYG_logoutWarning{color:var(--dsw-alias-label-secondary);gap:8px;font-size:13px;line-height:20px;display:grid}.EtEeYG_logoutWarning p{margin:0}.EtEeYG_logoutConfirm{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.EtEeYG_linkButton{color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border:0}.EtEeYG_notice{color:var(--dsw-alias-state-success-primary);text-align:center}.EtEeYG_chat{flex:1;grid-template-columns:240px minmax(0,1fr);min-height:0;display:grid}.EtEeYG_roster{border-right:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);flex-direction:column;min-width:0;display:flex}.EtEeYG_identityCard{background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;gap:2px;margin:14px;padding:12px;display:flex}.EtEeYG_identityNameRow{align-items:center;min-width:0;min-height:24px;display:flex}.EtEeYG_identityName{min-width:0;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:text;background:0 0;border:0;flex:1;padding:0;font-size:16px;font-weight:600;line-height:24px;overflow:hidden}.EtEeYG_identityName:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:4px}.EtEeYG_identityEdit{width:24px;height:24px;color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;visibility:hidden;background:0 0;border:0;border-radius:6px;flex:none;place-items:center;margin-left:4px;padding:0;transition:opacity .12s;display:grid}.EtEeYG_identityNameRow:hover .EtEeYG_identityEdit,.EtEeYG_identityNameRow:focus-within .EtEeYG_identityEdit{opacity:1;visibility:visible}.EtEeYG_identityEdit:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_identityEditor{flex:1;align-items:center;gap:4px;min-width:0;display:flex}.EtEeYG_identityEditor input{border:1px solid var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1);min-width:0;height:28px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:7px;outline:none;flex:1;padding:0 8px;font-size:13px}.EtEeYG_identityEditor button{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_identityEditor button:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_identityEditor button:disabled,.EtEeYG_identityName:disabled{cursor:default;opacity:.5}.EtEeYG_identityEdit:disabled{cursor:default}.EtEeYG_identityHandle{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:16px;overflow:hidden}.EtEeYG_identityStatus{color:var(--dsw-alias-state-success-primary);margin-top:4px;font-size:12px;line-height:18px}.EtEeYG_identityError{color:var(--dsw-alias-state-error-primary);margin-top:4px;font-size:11px;line-height:16px}.EtEeYG_identityCard i{background:var(--dsw-alias-state-success-primary);border-radius:50%;width:6px;height:6px;margin-right:5px;display:inline-block}.EtEeYG_rosterTitle{color:var(--dsw-alias-label-tertiary);padding:4px 16px 8px;font-size:12px;line-height:18px}.EtEeYG_conversationList{flex:1;min-height:0;padding:0 8px;overflow:auto}.EtEeYG_conversationRow{width:100%;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:10px;align-items:center;gap:10px;padding:9px;display:flex}.EtEeYG_conversationRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_conversationRow[data-active]{background:var(--dsw-alias-interactive-bg-active)}.EtEeYG_avatar{background:var(--dsw-alias-interactive-bg-active);width:34px;height:34px;color:var(--dsw-alias-brand-primary);border-radius:50%;flex:none;place-items:center;font-size:12px;line-height:18px;display:grid;position:relative;overflow:visible}.EtEeYG_conversationUnreadBadge{border:2px solid var(--dsw-alias-bg-layer-2);background:var(--dsw-alias-state-error-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-inverted);box-sizing:border-box;pointer-events:none;border-radius:9px;place-items:center;padding:0 4px;font-size:10px;font-weight:600;line-height:14px;display:grid;position:absolute;top:-6px;right:-7px}.EtEeYG_conversationText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.EtEeYG_conversationHeader{align-items:center;gap:8px;min-width:0;display:flex}.EtEeYG_conversationHeader strong{flex:1;min-width:0}.EtEeYG_conversationTime{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;font-weight:400;line-height:16px}.EtEeYG_conversationText strong,.EtEeYG_conversationText small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_conversationText strong{font-size:13px;line-height:20px}.EtEeYG_conversationText small{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.EtEeYG_more{background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-secondary);margin:8px}.EtEeYG_more:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_thread{flex-direction:column;min-width:0;min-height:0;display:flex}.EtEeYG_threadHeader{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;align-items:center;gap:8px;height:56px;padding:0 14px;display:flex}.EtEeYG_threadTitle{flex-direction:column;flex:1;min-width:0;display:flex}.EtEeYG_threadTitle strong,.EtEeYG_threadTitle small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_threadHeader small{color:var(--dsw-alias-label-tertiary)}.EtEeYG_summaryTrigger{min-height:30px;color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:8px;flex:none;align-items:center;gap:5px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.EtEeYG_summaryTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryTrigger:disabled{cursor:default;opacity:.7}.EtEeYG_summaryTrigger[aria-expanded=true]>svg:last-child{transform:rotate(180deg)}.EtEeYG_summaryTrigger>svg:first-child{flex:none}.EtEeYG_summaryPanel{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-height:0;max-height:min(220px,33%);color:var(--dsw-alias-label-primary);border-radius:10px;flex:0 33%;margin:8px 10px 0;overflow:hidden}.EtEeYG_summaryPanel[data-collapsed]{flex-basis:auto;max-height:42px}.EtEeYG_summaryHeader{border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:9px;min-height:38px;padding:0 8px 0 12px;display:flex}.EtEeYG_summaryHeader>span{color:var(--dsw-alias-brand-primary);align-items:center;gap:6px;display:flex}.EtEeYG_summaryHeader>span strong{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}.EtEeYG_summaryHeader>small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:11px;line-height:16px;overflow:hidden}.EtEeYG_summaryHeader>button{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:7px;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_summaryHeader>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryCollapsed{width:100%;min-height:40px;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:0 10px 0 12px;display:grid}.EtEeYG_summaryCollapsed:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryCollapsed>span{color:var(--dsw-alias-brand-primary);align-items:center;gap:6px;font-size:12px;font-weight:600;display:flex}.EtEeYG_summaryCollapsed>small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_summaryCollapsed>em{color:var(--dsw-alias-state-warn-label);white-space:nowrap;font-size:11px;font-style:normal}.EtEeYG_summaryLoading{min-height:88px;color:var(--dsw-alias-brand-primary);justify-content:center;align-items:center;gap:10px;padding:16px;display:flex}.EtEeYG_summaryLoading>svg,.EtEeYG_summaryTrigger:disabled>svg:first-child{animation:1s linear infinite EtEeYG_summary-spin}.EtEeYG_summaryLoading>span{flex-direction:column;gap:2px;display:flex}.EtEeYG_summaryLoading strong{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}.EtEeYG_summaryLoading small{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.EtEeYG_summaryError{min-height:58px;color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;padding:12px;font-size:12px;line-height:18px;display:flex}.EtEeYG_summaryError>span{overflow-wrap:anywhere;min-width:0}.EtEeYG_summaryError button,.EtEeYG_summaryStale button{border:1px solid var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;background:0 0;border-radius:7px;flex:none;align-items:center;gap:5px;padding:0 8px;font-size:11px;display:flex}.EtEeYG_summaryError button:hover,.EtEeYG_summaryStale button:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryStale{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-state-warn-label);justify-content:space-between;align-items:center;gap:10px;padding:6px 10px;font-size:11px;line-height:16px;display:flex}.EtEeYG_summaryBody{gap:10px;max-height:118px;padding:10px 12px;display:grid;overflow:auto}.EtEeYG_summarySection h4{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;margin:0 0 4px;font-size:12px;line-height:18px;display:flex}.EtEeYG_summarySection h4>svg{color:var(--dsw-alias-label-secondary);flex:none}.EtEeYG_summarySection ul{color:var(--dsw-alias-label-secondary);gap:2px;margin:0;padding-left:18px;font-size:11px;line-height:17px;display:grid}.EtEeYG_summarySection li{overflow-wrap:anywhere;padding-left:1px}.EtEeYG_summarySection p{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:17px}.EtEeYG_summarySection b{color:var(--dsw-alias-label-primary);font-weight:500}.EtEeYG_summaryActions{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:auto 1fr auto auto;align-items:center;gap:4px;min-height:34px;padding:0 8px;display:grid}.EtEeYG_summaryActions button{min-height:26px;color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:6px;align-items:center;gap:5px;padding:0 6px;font-size:11px;line-height:16px;display:flex}.EtEeYG_summaryActions button:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryPrivacy{border-top:1px solid var(--dsw-alias-border-l1);min-height:28px;color:var(--dsw-alias-label-tertiary);align-items:center;gap:6px;padding:0 10px;font-size:10px;line-height:15px;display:flex}.EtEeYG_summaryPrivacy svg{flex:none}.EtEeYG_summaryCopyError{color:var(--dsw-alias-state-error-primary);padding:4px 10px;font-size:10px;line-height:15px}@keyframes EtEeYG_summary-spin{to{transform:rotate(360deg)}}.EtEeYG_back{display:none}.EtEeYG_history{flex-direction:column;flex:1;gap:12px;min-height:0;padding:16px;display:flex;overflow:auto}.EtEeYG_message{align-self:flex-start;max-width:min(78%,420px)}.EtEeYG_message[data-outgoing]{align-self:flex-end}.EtEeYG_messageMeta{color:var(--dsw-alias-label-tertiary);justify-content:space-between;gap:10px;margin-bottom:3px;font-size:11px;line-height:16px;display:flex}.EtEeYG_message p,.EtEeYG_attachment{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;border-radius:12px;margin:0;padding:9px 11px;line-height:20px}.EtEeYG_message[data-outgoing] p,.EtEeYG_message[data-outgoing] .EtEeYG_attachment{background:var(--dsw-alias-interactive-bg-active)}.EtEeYG_attachment{cursor:pointer;font:inherit;text-align:left;align-items:center;gap:12px;display:flex}.EtEeYG_attachment span{flex-direction:column;min-width:0;display:flex}.EtEeYG_attachment strong{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_attachment small{color:var(--dsw-alias-label-tertiary)}.EtEeYG_attachment:disabled{cursor:default}.EtEeYG_imageAttachment{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);width:280px;max-width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;text-align:left;border-radius:12px;margin:0;padding:0;display:block;overflow:hidden}.EtEeYG_imageAttachment img{background:var(--dsw-alias-bg-layer-1);object-fit:contain;width:100%;max-height:280px;display:block}.EtEeYG_imageAttachment span{grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:0 10px;padding:7px 9px;display:grid}.EtEeYG_imageAttachment strong{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_imageAttachment small{color:var(--dsw-alias-label-tertiary);grid-column:1}.EtEeYG_imageAttachment svg{grid-area:1/2/span 2}.EtEeYG_message .EtEeYG_caption{color:var(--dsw-alias-label-secondary);background:0 0;margin-top:4px;padding:4px 8px;font-size:12px}.EtEeYG_inlineError{color:var(--dsw-alias-state-error-primary);margin-top:4px;display:block}.EtEeYG_empty{color:var(--dsw-alias-label-tertiary);text-align:center;margin:auto;padding:20px}.EtEeYG_composer{border-top:1px solid var(--dsw-alias-border-l1);flex:none;gap:8px;padding:10px 14px 14px;display:grid}.EtEeYG_filePicker{border:1px solid var(--dsw-alias-border-l2);width:32px;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:50%;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_filePicker:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_filePicker:disabled{opacity:.45;cursor:default}.EtEeYG_fileInput{display:none}.EtEeYG_composeInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;gap:6px;min-width:0;padding:9px 10px 8px;display:grid}.EtEeYG_composeInput:focus-within{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.EtEeYG_composeInput textarea{resize:none;background:0 0;border:0;border-radius:0;outline:0;min-width:0;min-height:42px;padding:0}.EtEeYG_composeInput textarea:focus-visible{outline:0}.EtEeYG_composeActions{justify-content:space-between;align-items:center;min-height:32px;display:flex}.EtEeYG_filePreview{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;align-items:center;gap:8px;width:min(240px,100% - 8px);min-height:36px;padding:5px 28px 5px 8px;display:flex;position:relative}.EtEeYG_filePreview[data-image]{width:72px;height:72px;min-height:0;padding:0}.EtEeYG_filePreview img{object-fit:cover;border-radius:9px;width:72px;height:72px;display:block}.EtEeYG_filePreviewIcon{color:var(--dsw-alias-label-secondary);flex:none;place-items:center;display:grid}.EtEeYG_filePreviewName{min-width:0;color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.EtEeYG_removeFile{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-button-floating-fill);width:22px;height:22px;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv1);cursor:pointer;border-radius:50%;place-items:center;padding:0;display:grid;position:absolute;top:-7px;right:-7px}.EtEeYG_removeFile:hover{background:var(--dsw-alias-button-floating-hover)}.EtEeYG_send{background:var(--dsw-alias-button-primary-fill);width:32px;height:32px;color:var(--dsw-alias-label-primary-inverted);cursor:pointer;border:0;border-radius:50%;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_send:disabled{opacity:.45;cursor:default}.EtEeYG_error{background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;flex:none;padding:8px 14px;font-size:12px;line-height:18px}.EtEeYG_pending{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);box-shadow:var(--dsw-shadow-lv2);border-radius:9px;padding:7px 10px;font-size:12px;line-height:18px;position:absolute;bottom:14px;right:14px}@media (width<=620px){.EtEeYG_trigger span{display:none}.EtEeYG_trigger{justify-content:center;width:36px;padding:0}.EtEeYG_drawer{width:calc(100vw - 56px);min-width:0}.EtEeYG_chat{grid-template-columns:1fr}.EtEeYG_thread{display:none}.EtEeYG_thread[data-visible]{display:flex}.EtEeYG_roster[data-hidden]{display:none}.EtEeYG_back{display:grid}.EtEeYG_summaryPanel{max-height:min(190px,33%);margin-left:8px;margin-right:8px}.EtEeYG_summaryTrigger>span{display:none}.EtEeYG_summaryTrigger{justify-content:center;width:30px;padding:0}.EtEeYG_summaryTrigger>svg:last-child{display:none}}@media (prefers-reduced-motion:reduce){.EtEeYG_drawer{scroll-behavior:auto}.EtEeYG_summaryLoading>svg,.EtEeYG_summaryTrigger:disabled>svg:first-child{animation:none}}";
6173
+ const css$1 = ".EtEeYG_trigger{z-index:2;border:1px solid var(--dsw-alias-border-l2);width:48px;height:48px;color:var(--dsw-alias-brand-primary);box-shadow:var(--dsw-shadow-lv2);cursor:grab;font:inherit;touch-action:none;user-select:none;background:#fff;border-radius:50%;place-items:center;padding:0;display:grid;position:fixed;overflow:visible}.EtEeYG_trigger:hover{box-shadow:var(--dsw-shadow-lv3);background:#fff}.EtEeYG_trigger:active,.EtEeYG_trigger[data-dragging]{cursor:grabbing}.EtEeYG_launcherIcon{object-fit:cover;pointer-events:none;border-radius:50%;width:100%;height:100%;display:block}.EtEeYG_unreadBadge{border:2px solid var(--dsw-alias-bg-base);background:var(--dsw-alias-state-error-primary);color:#fff;box-sizing:border-box;pointer-events:none;border-radius:10px;place-items:center;min-width:20px;height:20px;padding:0 5px;font-size:11px;font-weight:600;line-height:16px;display:grid;position:absolute;top:-5px;right:-5px}.EtEeYG_trigger:focus-visible,.EtEeYG_drawer button:focus-visible,.EtEeYG_drawer input:focus-visible,.EtEeYG_drawer textarea:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.EtEeYG_drawer{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);z-index:1;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:min(720px,100vw - 80px);min-width:min(360px,100vw - 80px);height:min(720px,100vh - 16px);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3);border-radius:16px;flex-direction:column;display:flex;position:fixed;overflow:hidden}.EtEeYG_drawerHeader{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;touch-action:none;user-select:none;flex:none;align-items:center;gap:8px;height:58px;padding:0 14px 0 18px;display:flex}.EtEeYG_drawerHeader[data-dragging]{cursor:grabbing}.EtEeYG_drawerHeader>div{flex:1;align-items:center;gap:8px;display:flex}.EtEeYG_drawerHeader h2{margin:0;font-size:16px;line-height:24px}.EtEeYG_drawerHeader button,.EtEeYG_back{cursor:pointer;width:32px;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:9px;place-items:center;padding:0;display:grid}.EtEeYG_drawerHeader button:hover,.EtEeYG_back:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_centerState,.EtEeYG_registration,.EtEeYG_threadEmpty{text-align:center;color:var(--dsw-alias-label-secondary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:14px;padding:32px;display:flex}.EtEeYG_centerState p{overflow-wrap:anywhere;max-width:420px;margin:0}.EtEeYG_registration{box-sizing:border-box;align-items:stretch;width:min(360px,100%);margin:0 auto}.EtEeYG_registration h3{text-align:center;color:var(--dsw-alias-label-primary);margin:0}.EtEeYG_registration>p{margin:0;font-size:13px;line-height:20px}.EtEeYG_registrationIcon{background:var(--dsw-alias-interactive-bg-active);width:48px;height:48px;color:var(--dsw-alias-brand-primary);border-radius:50%;align-self:center;place-items:center;display:grid}.EtEeYG_registration label{text-align:left;color:var(--dsw-alias-label-secondary);gap:6px;font-size:13px;line-height:20px;display:grid}.EtEeYG_registration input,.EtEeYG_fileDraft input,.EtEeYG_composeRow textarea{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);width:100%;color:var(--dsw-alias-label-primary);font:inherit;border-radius:10px}.EtEeYG_registration input{height:40px;padding:0 12px}.EtEeYG_primary,.EtEeYG_more,.EtEeYG_fileDraft button{background:var(--dsw-alias-button-primary-fill);min-height:36px;color:var(--dsw-alias-label-primary-inverted);cursor:pointer;font:inherit;border:0;border-radius:10px;padding:0 14px}.EtEeYG_primary:hover,.EtEeYG_fileDraft button:hover{background:var(--dsw-alias-button-primary-hover)}.EtEeYG_primary:disabled,.EtEeYG_fileDraft button:disabled{opacity:.5;cursor:default}.EtEeYG_secondary{border:1px solid var(--dsw-alias-border-l2);min-height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;background:0 0;border-radius:10px;padding:0 14px}.EtEeYG_secondary:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_composeBackdrop{background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 72%, transparent);place-items:center;padding:24px;display:grid;position:absolute;inset:58px 0 0}.EtEeYG_composeCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);width:min(360px,100%);box-shadow:var(--dsw-shadow-lv3);border-radius:14px;gap:12px;padding:20px;display:grid}.EtEeYG_composeCard h3{margin:0;font-size:16px;line-height:24px}.EtEeYG_composeCard p{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:20px}.EtEeYG_composeCard label{color:var(--dsw-alias-label-secondary);gap:6px;font-size:13px;line-height:20px;display:grid}.EtEeYG_composeCard input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:40px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:10px;padding:0 12px}.EtEeYG_composeActions{justify-content:flex-end;gap:8px;display:flex}.EtEeYG_logoutWarning{color:var(--dsw-alias-label-secondary);gap:8px;font-size:13px;line-height:20px;display:grid}.EtEeYG_logoutWarning p{margin:0}.EtEeYG_logoutConfirm{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.EtEeYG_linkButton{color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border:0}.EtEeYG_notice{color:var(--dsw-alias-state-success-primary);text-align:center}.EtEeYG_chat{flex:1;grid-template-columns:240px minmax(0,1fr);min-height:0;display:grid}.EtEeYG_roster{border-right:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);flex-direction:column;min-width:0;display:flex}.EtEeYG_identityCard{background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;gap:2px;margin:14px;padding:12px;display:flex}.EtEeYG_identityNameRow{align-items:center;min-width:0;min-height:24px;display:flex}.EtEeYG_identityName{min-width:0;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:text;background:0 0;border:0;flex:1;padding:0;font-size:16px;font-weight:600;line-height:24px;overflow:hidden}.EtEeYG_identityName:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:4px}.EtEeYG_identityEdit{width:24px;height:24px;color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;visibility:hidden;background:0 0;border:0;border-radius:6px;flex:none;place-items:center;margin-left:4px;padding:0;transition:opacity .12s;display:grid}.EtEeYG_identityNameRow:hover .EtEeYG_identityEdit,.EtEeYG_identityNameRow:focus-within .EtEeYG_identityEdit{opacity:1;visibility:visible}.EtEeYG_identityEdit:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_identityEditor{flex:1;align-items:center;gap:4px;min-width:0;display:flex}.EtEeYG_identityEditor input{border:1px solid var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1);min-width:0;height:28px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:7px;outline:none;flex:1;padding:0 8px;font-size:13px}.EtEeYG_identityEditor button{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_identityEditor button:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_identityEditor button:disabled,.EtEeYG_identityName:disabled{cursor:default;opacity:.5}.EtEeYG_identityEdit:disabled{cursor:default}.EtEeYG_identityHandle{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:16px;overflow:hidden}.EtEeYG_identityStatus{color:var(--dsw-alias-state-success-primary);margin-top:4px;font-size:12px;line-height:18px}.EtEeYG_identityError{color:var(--dsw-alias-state-error-primary);margin-top:4px;font-size:11px;line-height:16px}.EtEeYG_identityCard i{background:var(--dsw-alias-state-success-primary);border-radius:50%;width:6px;height:6px;margin-right:5px;display:inline-block}.EtEeYG_rosterTitle{color:var(--dsw-alias-label-tertiary);padding:4px 16px 8px;font-size:12px;line-height:18px}.EtEeYG_conversationList{flex:1;min-height:0;padding:0 8px;overflow:auto}.EtEeYG_conversationRow{width:100%;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:10px;align-items:center;gap:10px;padding:9px;display:flex}.EtEeYG_conversationRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_conversationRow[data-active]{background:var(--dsw-alias-interactive-bg-active)}.EtEeYG_avatar{background:var(--dsw-alias-interactive-bg-active);width:34px;height:34px;color:var(--dsw-alias-brand-primary);border-radius:50%;flex:none;place-items:center;font-size:12px;line-height:18px;display:grid;position:relative;overflow:visible}.EtEeYG_conversationUnreadBadge{border:2px solid var(--dsw-alias-bg-layer-2);background:var(--dsw-alias-state-error-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-inverted);box-sizing:border-box;pointer-events:none;border-radius:9px;place-items:center;padding:0 4px;font-size:10px;font-weight:600;line-height:14px;display:grid;position:absolute;top:-6px;right:-7px}.EtEeYG_conversationText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.EtEeYG_conversationHeader{align-items:center;gap:8px;min-width:0;display:flex}.EtEeYG_conversationHeader strong{flex:1;min-width:0}.EtEeYG_conversationTime{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;font-weight:400;line-height:16px}.EtEeYG_conversationText strong,.EtEeYG_conversationText small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_conversationText strong{font-size:13px;line-height:20px}.EtEeYG_conversationText small{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.EtEeYG_more{background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-secondary);margin:8px}.EtEeYG_more:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_thread{flex-direction:column;min-width:0;min-height:0;display:flex}.EtEeYG_threadHeader{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;align-items:center;gap:8px;height:56px;padding:0 14px;display:flex}.EtEeYG_threadTitle{flex-direction:column;flex:1;min-width:0;display:flex}.EtEeYG_threadTitle strong,.EtEeYG_threadTitle small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_threadHeader small{color:var(--dsw-alias-label-tertiary)}.EtEeYG_summaryTrigger{min-height:30px;color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:8px;flex:none;align-items:center;gap:5px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.EtEeYG_summaryTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryTrigger:disabled{cursor:default;opacity:.7}.EtEeYG_summaryTrigger[aria-expanded=true]>svg:last-child{transform:rotate(180deg)}.EtEeYG_summaryTrigger>svg:first-child{flex:none}.EtEeYG_summaryPanel{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-height:0;max-height:min(220px,33%);color:var(--dsw-alias-label-primary);border-radius:10px;flex:0 33%;margin:8px 10px 0;overflow:hidden}.EtEeYG_summaryPanel[data-collapsed]{flex-basis:auto;max-height:42px}.EtEeYG_summaryHeader{border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:9px;min-height:38px;padding:0 8px 0 12px;display:flex}.EtEeYG_summaryHeader>span{color:var(--dsw-alias-brand-primary);align-items:center;gap:6px;display:flex}.EtEeYG_summaryHeader>span strong{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}.EtEeYG_summaryHeader>small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:11px;line-height:16px;overflow:hidden}.EtEeYG_summaryHeader>button{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:7px;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_summaryHeader>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryCollapsed{width:100%;min-height:40px;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:0 10px 0 12px;display:grid}.EtEeYG_summaryCollapsed:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryCollapsed>span{color:var(--dsw-alias-brand-primary);align-items:center;gap:6px;font-size:12px;font-weight:600;display:flex}.EtEeYG_summaryCollapsed>small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_summaryCollapsed>em{color:var(--dsw-alias-state-warn-label);white-space:nowrap;font-size:11px;font-style:normal}.EtEeYG_summaryLoading{min-height:88px;color:var(--dsw-alias-brand-primary);justify-content:center;align-items:center;gap:10px;padding:16px;display:flex}.EtEeYG_summaryLoading>svg,.EtEeYG_summaryTrigger:disabled>svg:first-child{animation:1s linear infinite EtEeYG_summary-spin}.EtEeYG_summaryLoading>span{flex-direction:column;gap:2px;display:flex}.EtEeYG_summaryLoading strong{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}.EtEeYG_summaryLoading small{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.EtEeYG_summaryError{min-height:58px;color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;padding:12px;font-size:12px;line-height:18px;display:flex}.EtEeYG_summaryError>span{overflow-wrap:anywhere;min-width:0}.EtEeYG_summaryError button,.EtEeYG_summaryStale button{border:1px solid var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;background:0 0;border-radius:7px;flex:none;align-items:center;gap:5px;padding:0 8px;font-size:11px;display:flex}.EtEeYG_summaryError button:hover,.EtEeYG_summaryStale button:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryStale{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-state-warn-label);justify-content:space-between;align-items:center;gap:10px;padding:6px 10px;font-size:11px;line-height:16px;display:flex}.EtEeYG_summaryBody{gap:10px;max-height:118px;padding:10px 12px;display:grid;overflow:auto}.EtEeYG_summarySection h4{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;margin:0 0 4px;font-size:12px;line-height:18px;display:flex}.EtEeYG_summarySection h4>svg{color:var(--dsw-alias-label-secondary);flex:none}.EtEeYG_summarySection ul{color:var(--dsw-alias-label-secondary);gap:2px;margin:0;padding-left:18px;font-size:11px;line-height:17px;display:grid}.EtEeYG_summarySection li{overflow-wrap:anywhere;padding-left:1px}.EtEeYG_summarySection p{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:17px}.EtEeYG_summarySection b{color:var(--dsw-alias-label-primary);font-weight:500}.EtEeYG_summaryActions{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:auto 1fr auto auto;align-items:center;gap:4px;min-height:34px;padding:0 8px;display:grid}.EtEeYG_summaryActions button{min-height:26px;color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:6px;align-items:center;gap:5px;padding:0 6px;font-size:11px;line-height:16px;display:flex}.EtEeYG_summaryActions button:hover{background:var(--dsw-alias-interactive-bg-hover)}.EtEeYG_summaryPrivacy{border-top:1px solid var(--dsw-alias-border-l1);min-height:28px;color:var(--dsw-alias-label-tertiary);align-items:center;gap:6px;padding:0 10px;font-size:10px;line-height:15px;display:flex}.EtEeYG_summaryPrivacy svg{flex:none}.EtEeYG_summaryCopyError{color:var(--dsw-alias-state-error-primary);padding:4px 10px;font-size:10px;line-height:15px}@keyframes EtEeYG_summary-spin{to{transform:rotate(360deg)}}.EtEeYG_back{display:none}.EtEeYG_history{flex-direction:column;flex:1;gap:12px;min-height:0;padding:16px;display:flex;overflow:auto}.EtEeYG_message{align-self:flex-start;max-width:min(78%,420px)}.EtEeYG_message[data-outgoing]{align-self:flex-end}.EtEeYG_messageMeta{color:var(--dsw-alias-label-tertiary);justify-content:space-between;gap:10px;margin-bottom:3px;font-size:11px;line-height:16px;display:flex}.EtEeYG_message p,.EtEeYG_attachment{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;border-radius:12px;margin:0;padding:9px 11px;line-height:20px}.EtEeYG_message[data-outgoing] p,.EtEeYG_message[data-outgoing] .EtEeYG_attachment{background:var(--dsw-alias-interactive-bg-active)}.EtEeYG_pendingMessage{grid-template-columns:auto minmax(0,1fr);align-self:flex-end;align-items:end;gap:7px;max-width:min(78%,420px);display:grid}.EtEeYG_pendingMessageSpinner{color:var(--dsw-alias-label-tertiary);margin-bottom:12px;animation:1s linear infinite EtEeYG_summary-spin}.EtEeYG_pendingMessageContent{opacity:.82;min-width:0}.EtEeYG_pendingMessageContent>p,.EtEeYG_pendingAttachment{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;border-radius:12px;margin:0;padding:9px 11px;line-height:20px}.EtEeYG_pendingAttachment{align-items:center;gap:9px;display:flex}.EtEeYG_pendingAttachment>svg{color:var(--dsw-alias-label-secondary);flex:none}.EtEeYG_pendingAttachment span{flex-direction:column;min-width:0;display:flex}.EtEeYG_pendingAttachment strong{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_pendingAttachment small{color:var(--dsw-alias-label-tertiary)}.EtEeYG_pendingMessageContent>.EtEeYG_pendingCaption{color:var(--dsw-alias-label-secondary);background:0 0;border:0;margin-top:4px;padding:4px 8px;font-size:12px}.EtEeYG_attachment{cursor:pointer;font:inherit;text-align:left;align-items:center;gap:12px;display:flex}.EtEeYG_attachment span{flex-direction:column;min-width:0;display:flex}.EtEeYG_attachment strong{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_attachment small{color:var(--dsw-alias-label-tertiary)}.EtEeYG_attachment:disabled{cursor:default}.EtEeYG_imageAttachment{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);width:280px;max-width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;text-align:left;border-radius:12px;margin:0;padding:0;display:block;overflow:hidden}.EtEeYG_imageAttachment img{background:var(--dsw-alias-bg-layer-1);object-fit:contain;width:100%;max-height:280px;display:block}.EtEeYG_imageAttachment span{grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:0 10px;padding:7px 9px;display:grid}.EtEeYG_imageAttachment strong{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.EtEeYG_imageAttachment small{color:var(--dsw-alias-label-tertiary);grid-column:1}.EtEeYG_imageAttachment svg{grid-area:1/2/span 2}.EtEeYG_message .EtEeYG_caption{color:var(--dsw-alias-label-secondary);background:0 0;margin-top:4px;padding:4px 8px;font-size:12px}.EtEeYG_inlineError{color:var(--dsw-alias-state-error-primary);margin-top:4px;display:block}.EtEeYG_empty{color:var(--dsw-alias-label-tertiary);text-align:center;margin:auto;padding:20px}.EtEeYG_composer{border-top:1px solid var(--dsw-alias-border-l1);flex:none;gap:8px;padding:10px 14px 14px;display:grid}.EtEeYG_filePicker{border:1px solid var(--dsw-alias-border-l2);width:32px;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:50%;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_filePicker:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.EtEeYG_filePicker:disabled{opacity:.45;cursor:default}.EtEeYG_fileInput{display:none}.EtEeYG_composeInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;gap:6px;min-width:0;padding:9px 10px 8px;display:grid}.EtEeYG_composeInput:focus-within{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.EtEeYG_composeInput textarea{resize:none;background:0 0;border:0;border-radius:0;outline:0;min-width:0;min-height:42px;padding:0}.EtEeYG_composeInput textarea:focus-visible{outline:0}.EtEeYG_composeActions{justify-content:space-between;align-items:center;min-height:32px;display:flex}.EtEeYG_filePreview{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;align-items:center;gap:8px;width:min(240px,100% - 8px);min-height:36px;padding:5px 28px 5px 8px;display:flex;position:relative}.EtEeYG_filePreview[data-image]{width:72px;height:72px;min-height:0;padding:0}.EtEeYG_filePreview img{object-fit:cover;border-radius:9px;width:72px;height:72px;display:block}.EtEeYG_filePreviewIcon{color:var(--dsw-alias-label-secondary);flex:none;place-items:center;display:grid}.EtEeYG_filePreviewName{min-width:0;color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.EtEeYG_removeFile{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-button-floating-fill);width:22px;height:22px;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv1);cursor:pointer;border-radius:50%;place-items:center;padding:0;display:grid;position:absolute;top:-7px;right:-7px}.EtEeYG_removeFile:hover{background:var(--dsw-alias-button-floating-hover)}.EtEeYG_send{background:var(--dsw-alias-button-primary-fill);width:32px;height:32px;color:var(--dsw-alias-label-primary-inverted);cursor:pointer;border:0;border-radius:50%;flex:none;place-items:center;padding:0;display:grid}.EtEeYG_send:disabled{opacity:.45;cursor:default}.EtEeYG_error{background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;flex:none;padding:8px 14px;font-size:12px;line-height:18px}.EtEeYG_pending{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);box-shadow:var(--dsw-shadow-lv2);border-radius:9px;padding:7px 10px;font-size:12px;line-height:18px;position:absolute;bottom:14px;right:14px}@media (width<=620px){.EtEeYG_trigger span{display:none}.EtEeYG_trigger{justify-content:center;width:36px;padding:0}.EtEeYG_drawer{width:calc(100vw - 56px);min-width:0}.EtEeYG_chat{grid-template-columns:1fr}.EtEeYG_thread{display:none}.EtEeYG_thread[data-visible]{display:flex}.EtEeYG_roster[data-hidden]{display:none}.EtEeYG_back{display:grid}.EtEeYG_summaryPanel{max-height:min(190px,33%);margin-left:8px;margin-right:8px}.EtEeYG_summaryTrigger>span{display:none}.EtEeYG_summaryTrigger{justify-content:center;width:30px;padding:0}.EtEeYG_summaryTrigger>svg:last-child{display:none}}@media (prefers-reduced-motion:reduce){.EtEeYG_drawer{scroll-behavior:auto}.EtEeYG_summaryLoading>svg,.EtEeYG_summaryTrigger:disabled>svg:first-child,.EtEeYG_pendingMessageSpinner{animation:none}}";
6151
6174
  const tagId$1 = "@awiki/dsh-plugin/AwikiOverlay.module.css";
6152
6175
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
6153
6176
  const tag = document.createElement("style");
@@ -6205,6 +6228,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6205
6228
  "more": "EtEeYG_more",
6206
6229
  "notice": "EtEeYG_notice",
6207
6230
  "pending": "EtEeYG_pending",
6231
+ "pendingAttachment": "EtEeYG_pendingAttachment",
6232
+ "pendingCaption": "EtEeYG_pendingCaption",
6233
+ "pendingMessage": "EtEeYG_pendingMessage",
6234
+ "pendingMessageContent": "EtEeYG_pendingMessageContent",
6235
+ "pendingMessageSpinner": "EtEeYG_pendingMessageSpinner",
6208
6236
  "primary": "EtEeYG_primary",
6209
6237
  "registration": "EtEeYG_registration",
6210
6238
  "registrationIcon": "EtEeYG_registrationIcon",
@@ -6347,14 +6375,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6347
6375
  const [otp, setOtp] = (0, react.useState)("");
6348
6376
  const [otpSent, setOtpSent] = (0, react.useState)(false);
6349
6377
  const [notice, setNotice] = (0, react.useState)(null);
6378
+ const [retryDeadline, setRetryDeadline] = (0, react.useState)(null);
6379
+ const [retrySeconds, setRetrySeconds] = (0, react.useState)(0);
6380
+ (0, react.useEffect)(() => {
6381
+ if (retryDeadline === null) return;
6382
+ const update = () => {
6383
+ const remaining = Math.max(0, Math.ceil((retryDeadline - Date.now()) / 1e3));
6384
+ setRetrySeconds(remaining);
6385
+ if (remaining === 0) setRetryDeadline(null);
6386
+ };
6387
+ update();
6388
+ const timer = setInterval(update, 250);
6389
+ return () => {
6390
+ clearInterval(timer);
6391
+ };
6392
+ }, [retryDeadline]);
6350
6393
  const requestOtp = async () => {
6351
6394
  const result = await props.sendRegistrationOtp({
6352
6395
  handle: handle.trim(),
6353
6396
  phone: phone.trim()
6354
6397
  });
6355
6398
  if (!result.ok) return;
6399
+ const cooldownSeconds = Math.max(0, Math.ceil(result.value.retryAfterSeconds));
6356
6400
  setOtpSent(true);
6357
- setNotice(`验证码已发送;${result.value.retryAfterSeconds} 秒后可重新获取。`);
6401
+ setRetryDeadline(Date.now() + cooldownSeconds * 1e3);
6402
+ setRetrySeconds(cooldownSeconds);
6403
+ setNotice(`验证码已发送;${cooldownSeconds} 秒后可重新获取。`);
6358
6404
  };
6359
6405
  const register = async () => {
6360
6406
  /* v8 ignore next -- the registration action is rendered only after an OTP challenge starts. */
@@ -6419,13 +6465,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6419
6465
  (0, react_jsx_runtime.jsx)("button", {
6420
6466
  type: "button",
6421
6467
  className: _dsh_awiki_css_AwikiOverlay_module_css_default.linkButton,
6422
- disabled: props.pending,
6468
+ disabled: props.pending || retrySeconds > 0,
6423
6469
  onClick: () => {
6424
- setOtpSent(false);
6425
- setOtp("");
6426
- setNotice(null);
6470
+ requestOtp();
6427
6471
  },
6428
- children: "重新获取验证码"
6472
+ children: retrySeconds > 0 ? `${retrySeconds} 秒后重新获取` : "重新获取验证码"
6429
6473
  })
6430
6474
  ] }),
6431
6475
  notice !== null && (0, react_jsx_runtime.jsx)("p", {
@@ -6731,6 +6775,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6731
6775
  ]
6732
6776
  });
6733
6777
  }
6778
+ /** Render one optimistic outgoing bubble while the Host confirms delivery. */
6779
+ function PendingMessageRow(props) {
6780
+ return (0, react_jsx_runtime.jsxs)("div", {
6781
+ className: _dsh_awiki_css_AwikiOverlay_module_css_default.pendingMessage,
6782
+ role: "status",
6783
+ "aria-live": "polite",
6784
+ "aria-label": "消息发送中",
6785
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, {
6786
+ className: _dsh_awiki_css_AwikiOverlay_module_css_default.pendingMessageSpinner,
6787
+ size: 14
6788
+ }), (0, react_jsx_runtime.jsxs)("div", {
6789
+ className: _dsh_awiki_css_AwikiOverlay_module_css_default.pendingMessageContent,
6790
+ children: [(0, react_jsx_runtime.jsxs)("div", {
6791
+ className: _dsh_awiki_css_AwikiOverlay_module_css_default.messageMeta,
6792
+ children: [(0, react_jsx_runtime.jsx)("span", { children: "我" }), (0, react_jsx_runtime.jsx)("time", { children: time(props.draft.startedAt) })]
6793
+ }), props.draft.content.kind === "text" ? (0, react_jsx_runtime.jsx)("p", { children: props.draft.content.text }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
6794
+ className: _dsh_awiki_css_AwikiOverlay_module_css_default.pendingAttachment,
6795
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPaperclipOutline16, { size: 16 }), (0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsx)("strong", { children: props.draft.content.fileName }), (0, react_jsx_runtime.jsxs)("small", { children: [props.draft.content.size, " 字节"] })] })]
6796
+ }), props.draft.content.caption !== void 0 && (0, react_jsx_runtime.jsx)("p", {
6797
+ className: _dsh_awiki_css_AwikiOverlay_module_css_default.pendingCaption,
6798
+ children: props.draft.content.caption
6799
+ })] })]
6800
+ })]
6801
+ });
6802
+ }
6734
6803
  function summaryRangeLabel(summary) {
6735
6804
  const scope = summary.range.kind === "unread" ? "未读以来" : "最近消息";
6736
6805
  const formatter = new Intl.DateTimeFormat("zh-CN", {
@@ -6900,16 +6969,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6900
6969
  const { view } = props;
6901
6970
  const [text, setText] = (0, react.useState)("");
6902
6971
  const [file, setFile] = (0, react.useState)(null);
6972
+ const [sendingDraft, setSendingDraft] = (0, react.useState)(null);
6903
6973
  const [previewUrl, setPreviewUrl] = (0, react.useState)(null);
6904
6974
  const [fileError, setFileError] = (0, react.useState)(null);
6905
6975
  const input = (0, react.useRef)(null);
6906
6976
  const history = (0, react.useRef)(null);
6907
6977
  const previousConversationId = (0, react.useRef)(null);
6978
+ const selectedConversationId = (0, react.useRef)(view.selectedConversationId);
6908
6979
  const conversationAwaitingBottom = (0, react.useRef)(null);
6909
6980
  const pendingInitialImages = (0, react.useRef)(/* @__PURE__ */ new Set());
6910
6981
  const selected = view.conversations.find((value) => value.id === view.selectedConversationId);
6911
6982
  const summary = selected === void 0 ? void 0 : view.summaries[selected.id];
6912
6983
  const summaryPanelId = (0, react.useId)();
6984
+ selectedConversationId.current = view.selectedConversationId;
6985
+ const visibleSendingDraft = sendingDraft?.conversationId === view.selectedConversationId ? sendingDraft : null;
6913
6986
  (0, react.useLayoutEffect)(() => {
6914
6987
  const conversationId = view.selectedConversationId;
6915
6988
  if (conversationId !== previousConversationId.current) {
@@ -6922,6 +6995,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6922
6995
  history.current.scrollTop = history.current.scrollHeight;
6923
6996
  if (pendingInitialImages.current.size === 0) conversationAwaitingBottom.current = null;
6924
6997
  }, [view.messages, view.selectedConversationId]);
6998
+ (0, react.useLayoutEffect)(() => {
6999
+ if (visibleSendingDraft === null || history.current === null) return;
7000
+ history.current.scrollTop = history.current.scrollHeight;
7001
+ }, [visibleSendingDraft]);
6925
7002
  const scrollAfterInitialImage = (messageId) => {
6926
7003
  if (selected === void 0 || conversationAwaitingBottom.current !== selected.id) return;
6927
7004
  if (!pendingInitialImages.current.delete(messageId)) return;
@@ -6957,11 +7034,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6957
7034
  if (input.current !== null) input.current.value = "";
6958
7035
  };
6959
7036
  const sendMessage = async () => {
7037
+ if (sendingDraft !== null || view.selectedConversationId === null) return;
6960
7038
  const draft = text.trim();
7039
+ const conversationId = view.selectedConversationId;
6961
7040
  if (file === null) {
6962
7041
  /* v8 ignore next -- the only invocation control is disabled while both text and attachment are empty. */
6963
7042
  if (draft === "") return;
6964
- if ((await props.sendText(draft)).ok) setText("");
7043
+ setSendingDraft({
7044
+ conversationId,
7045
+ startedAt: Date.now(),
7046
+ content: {
7047
+ kind: "text",
7048
+ text: draft
7049
+ }
7050
+ });
7051
+ setText("");
7052
+ const result = await props.sendText(draft);
7053
+ setSendingDraft(null);
7054
+ if (!result.ok && selectedConversationId.current === conversationId) setText(draft);
6965
7055
  return;
6966
7056
  }
6967
7057
  if (file.size > view.attachmentMaxBytes) {
@@ -6969,15 +7059,30 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6969
7059
  return;
6970
7060
  }
6971
7061
  setFileError(null);
6972
- const bytesBase64 = await fileToBase64(file);
6973
- if ((await props.sendAttachment({
6974
- fileName: file.name,
6975
- mimeType: file.type || "application/octet-stream",
7062
+ const selectedFile = file;
7063
+ const bytesBase64 = await fileToBase64(selectedFile);
7064
+ setSendingDraft({
7065
+ conversationId,
7066
+ startedAt: Date.now(),
7067
+ content: {
7068
+ kind: "attachment",
7069
+ fileName: selectedFile.name,
7070
+ size: selectedFile.size,
7071
+ ...draft === "" ? {} : { caption: draft }
7072
+ }
7073
+ });
7074
+ clearFile();
7075
+ setText("");
7076
+ const result = await props.sendAttachment({
7077
+ fileName: selectedFile.name,
7078
+ mimeType: selectedFile.type || "application/octet-stream",
6976
7079
  bytesBase64,
6977
7080
  ...draft === "" ? {} : { caption: draft }
6978
- })).ok) {
6979
- clearFile();
6980
- setText("");
7081
+ });
7082
+ setSendingDraft(null);
7083
+ if (!result.ok && selectedConversationId.current === conversationId) {
7084
+ setFile(selectedFile);
7085
+ setText(draft);
6981
7086
  }
6982
7087
  };
6983
7088
  return (0, react_jsx_runtime.jsxs)("div", {
@@ -7091,7 +7196,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7091
7196
  download: props.downloadAttachment,
7092
7197
  onImageLoad: scrollAfterInitialImage
7093
7198
  }, message.id)),
7094
- view.messages.length === 0 && (0, react_jsx_runtime.jsx)("p", {
7199
+ visibleSendingDraft !== null && (0, react_jsx_runtime.jsx)(PendingMessageRow, { draft: visibleSendingDraft }),
7200
+ view.messages.length === 0 && visibleSendingDraft === null && (0, react_jsx_runtime.jsx)("p", {
7095
7201
  className: _dsh_awiki_css_AwikiOverlay_module_css_default.empty,
7096
7202
  children: "暂无消息。"
7097
7203
  })
@@ -7135,6 +7241,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7135
7241
  onChange: (event) => {
7136
7242
  setText(event.target.value);
7137
7243
  },
7244
+ onKeyDown: (event) => {
7245
+ if (event.key !== "Enter" || event.shiftKey || event.nativeEvent.isComposing) return;
7246
+ event.preventDefault();
7247
+ if (view.pending === null && sendingDraft === null && (file !== null || text.trim() !== "")) sendMessage();
7248
+ },
7138
7249
  placeholder: "输入消息",
7139
7250
  rows: 2
7140
7251
  }),
@@ -7148,7 +7259,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7148
7259
  type: "button",
7149
7260
  className: _dsh_awiki_css_AwikiOverlay_module_css_default.filePicker,
7150
7261
  "aria-label": "添加附件",
7151
- disabled: view.pending !== null,
7262
+ disabled: view.pending !== null || sendingDraft !== null,
7152
7263
  onClick: () => {
7153
7264
  input.current?.click();
7154
7265
  },
@@ -7169,7 +7280,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7169
7280
  type: "button",
7170
7281
  className: _dsh_awiki_css_AwikiOverlay_module_css_default.send,
7171
7282
  "aria-label": "发送消息",
7172
- disabled: view.pending !== null || file === null && text.trim() === "",
7283
+ disabled: view.pending !== null || sendingDraft !== null || file === null && text.trim() === "",
7173
7284
  onClick: () => {
7174
7285
  sendMessage();
7175
7286
  },
@@ -7683,7 +7794,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7683
7794
  role: "alert",
7684
7795
  children: view.error
7685
7796
  }),
7686
- view.pending !== null && (0, react_jsx_runtime.jsxs)("div", {
7797
+ view.pending !== null && view.pending !== "发送消息" && view.pending !== "发送附件" && (0, react_jsx_runtime.jsxs)("div", {
7687
7798
  className: _dsh_awiki_css_AwikiOverlay_module_css_default.pending,
7688
7799
  role: "status",
7689
7800
  children: [view.pending, "…"]