clay-server 3.8.1 → 4.0.0-beta.10

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.
Files changed (222) hide show
  1. package/lib/ask-user-mcp-server.js +5 -119
  2. package/lib/background-task-timing.js +105 -0
  3. package/lib/builtin-mates.js +6 -6
  4. package/lib/claude-hook-installer.js +15 -0
  5. package/lib/clay-history-mcp-server.js +62 -297
  6. package/lib/daemon.js +23 -1
  7. package/lib/debate-model-selection.js +119 -0
  8. package/lib/home-debate-tool-policy.js +164 -0
  9. package/lib/home-response-notifications.js +26 -0
  10. package/lib/knowledge-import.js +436 -0
  11. package/lib/knowledge-record-store.js +188 -0
  12. package/lib/knowledge-search.js +224 -0
  13. package/lib/mate-creation-mcp-server.js +55 -0
  14. package/lib/mate-knowledge-mcp-server.js +151 -0
  15. package/lib/mate-knowledge-migration.js +283 -0
  16. package/lib/mate-knowledge-service.js +488 -0
  17. package/lib/mate-knowledge-sync.js +482 -0
  18. package/lib/mate-ready-creation.js +95 -0
  19. package/lib/mates.js +2 -0
  20. package/lib/notes.js +2 -1
  21. package/lib/project-ask-user.js +64 -0
  22. package/lib/project-capsule-catalog.js +101 -0
  23. package/lib/project-connection.js +17 -0
  24. package/lib/project-debate-proposal.js +133 -17
  25. package/lib/project-debate.js +214 -110
  26. package/lib/project-delegated-follow-up.js +84 -0
  27. package/lib/project-delegated-session.js +53 -0
  28. package/lib/project-filesystem.js +7 -9
  29. package/lib/project-knowledge.js +23 -0
  30. package/lib/project-logs-comments.js +137 -0
  31. package/lib/project-logs-mcp-server.js +290 -0
  32. package/lib/project-logs-query.js +167 -0
  33. package/lib/project-logs-root.js +67 -0
  34. package/lib/project-logs-schema.js +259 -0
  35. package/lib/project-logs-service.js +357 -0
  36. package/lib/project-logs-snapshot.js +202 -0
  37. package/lib/project-logs-store.js +498 -0
  38. package/lib/project-logs-versioning.js +128 -0
  39. package/lib/project-logs.js +347 -0
  40. package/lib/project-mate-creation-proposal.js +120 -0
  41. package/lib/project-mate-interaction.js +14 -0
  42. package/lib/project-mate-knowledge.js +110 -0
  43. package/lib/project-memory.js +36 -7
  44. package/lib/project-models.js +157 -32
  45. package/lib/project-session-notes.js +2 -2
  46. package/lib/project-session-pair.js +8 -8
  47. package/lib/project-sessions.js +66 -51
  48. package/lib/project-vendor-login.js +414 -0
  49. package/lib/project-worker-proposal.js +25 -25
  50. package/lib/project-workspace-query.js +144 -0
  51. package/lib/project.js +433 -102
  52. package/lib/public/app.js +109 -48
  53. package/lib/public/css/avatar-imprints.css +0 -1
  54. package/lib/public/css/base.css +4 -0
  55. package/lib/public/css/capsule-ui.css +389 -0
  56. package/lib/public/css/command-palette.css +306 -6
  57. package/lib/public/css/home-capsule-library.css +243 -0
  58. package/lib/public/css/home-capsule-source.css +192 -0
  59. package/lib/public/css/home-debate-live.css +146 -0
  60. package/lib/public/css/home-debate-planning.css +125 -0
  61. package/lib/public/css/home-debates-archive.css +281 -0
  62. package/lib/public/css/home-hub.css +896 -405
  63. package/lib/public/css/home-mate-creation.css +34 -0
  64. package/lib/public/css/home-mate-model-picker.css +131 -0
  65. package/lib/public/css/home-mate-settings.css +344 -0
  66. package/lib/public/css/home-session-actions.css +265 -0
  67. package/lib/public/css/home-sidebar.css +667 -0
  68. package/lib/public/css/icon-strip.css +1 -2
  69. package/lib/public/css/input.css +79 -25
  70. package/lib/public/css/mates.css +7 -34
  71. package/lib/public/css/pane.css +1 -1
  72. package/lib/public/css/playbook.css +0 -80
  73. package/lib/public/css/project-logs.css +234 -0
  74. package/lib/public/css/scheduler.css +1 -1
  75. package/lib/public/css/sticky-notes.css +53 -117
  76. package/lib/public/css/tui-attention.css +0 -44
  77. package/lib/public/css/workspace-assignment.css +45 -0
  78. package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
  79. package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
  80. package/lib/public/index.html +96 -74
  81. package/lib/public/modules/app-connection.js +100 -5
  82. package/lib/public/modules/app-dm.js +43 -160
  83. package/lib/public/modules/app-home-hub.js +328 -585
  84. package/lib/public/modules/app-message-cards.js +242 -0
  85. package/lib/public/modules/app-message-router.js +84 -0
  86. package/lib/public/modules/app-messages.js +124 -38
  87. package/lib/public/modules/app-notifications.js +8 -119
  88. package/lib/public/modules/app-panels.js +43 -2
  89. package/lib/public/modules/app-projects.js +9 -1
  90. package/lib/public/modules/app-rendering.js +21 -602
  91. package/lib/public/modules/avatar-imprint.js +11 -8
  92. package/lib/public/modules/background-tasks-ui.js +139 -16
  93. package/lib/public/modules/chat-bubble-renderer.js +152 -0
  94. package/lib/public/modules/chat-render-runtime.js +198 -0
  95. package/lib/public/modules/command-palette.js +225 -436
  96. package/lib/public/modules/dm-render.js +82 -0
  97. package/lib/public/modules/home-capsule-creation-intent.js +31 -0
  98. package/lib/public/modules/home-capsule-library.js +146 -0
  99. package/lib/public/modules/home-capsule-source.js +383 -0
  100. package/lib/public/modules/home-chat-identity.js +35 -0
  101. package/lib/public/modules/home-chat-scroll.js +77 -0
  102. package/lib/public/modules/home-chat-stream-state.js +34 -0
  103. package/lib/public/modules/home-composer-focus.js +25 -0
  104. package/lib/public/modules/home-conversations-sheet.js +179 -0
  105. package/lib/public/modules/home-debate-activity.js +48 -0
  106. package/lib/public/modules/home-debate-controls.js +295 -0
  107. package/lib/public/modules/home-debate-launch.js +41 -0
  108. package/lib/public/modules/home-debate-live.js +284 -0
  109. package/lib/public/modules/home-debate-models.js +73 -0
  110. package/lib/public/modules/home-debate-planning.js +335 -0
  111. package/lib/public/modules/home-debates-archive.js +279 -0
  112. package/lib/public/modules/home-dock-resize.js +74 -0
  113. package/lib/public/modules/home-dock.js +446 -0
  114. package/lib/public/modules/home-mate-chat.js +496 -0
  115. package/lib/public/modules/home-mate-creation.js +109 -0
  116. package/lib/public/modules/home-mate-model-picker.js +281 -0
  117. package/lib/public/modules/home-mate-selection.js +38 -0
  118. package/lib/public/modules/home-mate-settings-menu.js +131 -0
  119. package/lib/public/modules/home-mate-settings.js +383 -0
  120. package/lib/public/modules/home-session-actions.js +373 -0
  121. package/lib/public/modules/home-session-model-confirmation.js +13 -0
  122. package/lib/public/modules/home-shell.js +9 -0
  123. package/lib/public/modules/home-sidebar-chat-list.js +63 -0
  124. package/lib/public/modules/home-sidebar.js +165 -0
  125. package/lib/public/modules/home-sub-surface.js +19 -0
  126. package/lib/public/modules/home-surface-boot.js +68 -0
  127. package/lib/public/modules/home-surface.js +141 -0
  128. package/lib/public/modules/home-tools.js +271 -0
  129. package/lib/public/modules/markdown.js +50 -2
  130. package/lib/public/modules/mate-management.js +86 -0
  131. package/lib/public/modules/mate-sidebar.js +0 -8
  132. package/lib/public/modules/mate-wizard.js +0 -7
  133. package/lib/public/modules/mention.js +17 -19
  134. package/lib/public/modules/pane-bridge.js +9 -0
  135. package/lib/public/modules/profile.js +4 -5
  136. package/lib/public/modules/project-logs-ambient.js +238 -0
  137. package/lib/public/modules/project-logs-render.js +359 -0
  138. package/lib/public/modules/project-logs.js +328 -0
  139. package/lib/public/modules/project-settings.js +34 -28
  140. package/lib/public/modules/project-switcher.js +11 -5
  141. package/lib/public/modules/project-workspace-assignment.js +23 -0
  142. package/lib/public/modules/scheduler.js +17 -3
  143. package/lib/public/modules/search-clay-chat.js +402 -0
  144. package/lib/public/modules/server-settings.js +14 -12
  145. package/lib/public/modules/session-actions.js +1 -1
  146. package/lib/public/modules/sidebar-mates.js +56 -552
  147. package/lib/public/modules/sidebar-mobile.js +12 -73
  148. package/lib/public/modules/sidebar-presence.js +37 -0
  149. package/lib/public/modules/sidebar-sessions.js +25 -1
  150. package/lib/public/modules/split-pair-ui.js +13 -13
  151. package/lib/public/modules/split-view.js +7 -0
  152. package/lib/public/modules/sticky-notes.js +106 -53
  153. package/lib/public/modules/tool-input-composition.js +48 -0
  154. package/lib/public/modules/tool-llm-status.js +167 -0
  155. package/lib/public/modules/tool-palette.js +76 -4
  156. package/lib/public/modules/tool-renderer-advanced.js +285 -0
  157. package/lib/public/modules/tool-renderer-chart.js +158 -0
  158. package/lib/public/modules/tool-renderer-semantics.js +35 -0
  159. package/lib/public/modules/tool-renderer.js +464 -0
  160. package/lib/public/modules/tool-runtime.js +309 -0
  161. package/lib/public/modules/tool-ui-evaluator.js +97 -0
  162. package/lib/public/modules/tool-ui-tree.js +21 -0
  163. package/lib/public/modules/tui-attention.js +10 -0
  164. package/lib/public/modules/user-settings.js +16 -23
  165. package/lib/public/modules/vendor-login.js +287 -0
  166. package/lib/public/modules/worker-proposal.js +2 -2
  167. package/lib/public/modules/workspace-assignment-card.js +149 -0
  168. package/lib/public/modules/workspace-assignment-routing.js +4 -0
  169. package/lib/public/style.css +14 -2
  170. package/lib/runtime-env.js +65 -0
  171. package/lib/sdk-bridge.js +120 -32
  172. package/lib/sdk-message-processor.js +34 -13
  173. package/lib/server-home-capsule-creation.js +36 -0
  174. package/lib/server-home-chat-events.js +287 -0
  175. package/lib/server-home-chat.js +518 -0
  176. package/lib/server-home-clay-entry.js +65 -0
  177. package/lib/server-home-clay-session-links.js +26 -0
  178. package/lib/server-home-debate-planning.js +214 -0
  179. package/lib/server-home-debates.js +137 -0
  180. package/lib/server-home-mate-creation.js +261 -0
  181. package/lib/server-home-models.js +241 -0
  182. package/lib/server-home-preferences.js +61 -0
  183. package/lib/server-mates.js +37 -0
  184. package/lib/server-tools.js +377 -0
  185. package/lib/server.js +166 -59
  186. package/lib/session-pair-mcp-server.js +6 -6
  187. package/lib/sessions.js +22 -4
  188. package/lib/tool-capsule-source.js +142 -0
  189. package/lib/tool-control-mcp-server.js +126 -0
  190. package/lib/tool-llm.js +48 -0
  191. package/lib/tool-storage.js +77 -0
  192. package/lib/tool-ui-spec-advanced.js +82 -0
  193. package/lib/tool-ui-spec.js +261 -0
  194. package/lib/tools-registry.js +286 -0
  195. package/lib/users-home-dock-preferences.js +77 -0
  196. package/lib/users-home-surface-preferences.js +99 -0
  197. package/lib/users-preferences.js +4 -7
  198. package/lib/users.js +12 -0
  199. package/lib/whats-new-content.js +3 -3
  200. package/lib/workspace-assignment-service.js +420 -0
  201. package/lib/workspace-query-mcp-server.js +154 -0
  202. package/lib/workspace-query-service.js +492 -0
  203. package/lib/ws-schema.js +107 -12
  204. package/lib/yoke/adapters/acp.js +2 -1
  205. package/lib/yoke/adapters/antigravity.js +2 -1
  206. package/lib/yoke/adapters/claude-worker.js +11 -4
  207. package/lib/yoke/adapters/claude.js +141 -46
  208. package/lib/yoke/adapters/codex.js +79 -11
  209. package/lib/yoke/adapters/kiro.js +2 -1
  210. package/lib/yoke/claude-user-input.js +38 -0
  211. package/lib/yoke/codex-app-server.js +20 -2
  212. package/lib/yoke/codex-background-tasks.js +8 -2
  213. package/lib/yoke/codex-user-input.js +64 -0
  214. package/lib/yoke/complete-once.js +164 -0
  215. package/lib/yoke/index.js +5 -1
  216. package/lib/yoke/interface.js +19 -0
  217. package/lib/yoke/mcp-bridge-server.js +2 -6
  218. package/lib/yoke/user-input.js +254 -0
  219. package/package.json +4 -3
  220. package/lib/public/css/home-chat.css +0 -380
  221. package/lib/public/modules/home-chat.js +0 -438
  222. package/lib/server-clay-home.js +0 -245
@@ -5,13 +5,15 @@ import { store } from './store.js';
5
5
  import { getWs } from './ws-ref.js';
6
6
  import { getMessagesEl, getInputEl } from './dom-refs.js';
7
7
  import { userAvatarUrl, mateAvatarUrl } from './avatar.js';
8
+ import { buildDmMessage, buildDmTypingIndicator } from './dm-render.js';
8
9
  import { connect } from './app-connection.js';
9
10
  import { resetClientState, renderProjectList, getCachedProjects } from './app-projects.js';
10
11
  import { scrollToBottom } from './app-rendering.js';
11
12
  import { autoResize } from './input.js';
12
13
  import { showDebateSticky } from './app-debate-ui.js';
13
14
  import { updateDmBadge, setCurrentDmUser, closeDmUserPicker } from './sidebar-mates.js';
14
- import { hideHomeHub } from './app-home-hub.js';
15
+ import { hideHomeHub, showHomeHub } from './app-home-hub.js';
16
+ import { openHomeChat } from './home-mate-chat.js';
15
17
  import { hideNotes } from './sticky-notes.js';
16
18
  import { showMateSidebar, hideMateSidebar } from './mate-sidebar.js';
17
19
  import { hideKnowledge } from './mate-knowledge.js';
@@ -72,6 +74,17 @@ export function initDm() {
72
74
  }
73
75
 
74
76
  export function openDm(targetUserId, opts) {
77
+ var mates = store.get('cachedMatesList') || [];
78
+ var isMateTarget = typeof targetUserId === "string" && targetUserId.indexOf("mate_") === 0;
79
+ for (var i = 0; i < mates.length && !isMateTarget; i++) {
80
+ if (mates[i] && mates[i].id === targetUserId) isMateTarget = true;
81
+ }
82
+ if (isMateTarget) {
83
+ if (store.get('projectMateDmsEnabled') === false) return;
84
+ showHomeHub();
85
+ openHomeChat(targetUserId);
86
+ return;
87
+ }
75
88
  var ws = getWs();
76
89
  if (!ws || ws.readyState !== 1) return;
77
90
  // Persist DM state for refresh recovery
@@ -138,6 +151,12 @@ function showMateOnboarding(callback) {
138
151
 
139
152
  export function enterDmMode(key, targetUser, messages) {
140
153
  console.log("[DEBUG enterDmMode] key=" + key, "isMate=" + (targetUser && targetUser.isMate), "messages=" + (messages ? messages.length : 0));
154
+ if (targetUser && targetUser.isMate) {
155
+ if (store.get('projectMateDmsEnabled') === false) return;
156
+ showHomeHub();
157
+ openHomeChat(targetUser.id);
158
+ return;
159
+ }
141
160
  var s = store.snap();
142
161
  // Clean up previous DM/mate state before entering new one
143
162
  if (s.dmMode) {
@@ -163,20 +182,6 @@ export function enterDmMode(key, targetUser, messages) {
163
182
 
164
183
  store.set({ dmMode: true, dmKey: key, dmTargetUser: targetUser });
165
184
 
166
- // Notify server of active mate DM (server-side presence tracking)
167
- // IMPORTANT: set_mate_dm must go to the MAIN project, not a mate project WS.
168
- // When switching between mates, ws points to the current mate project,
169
- // so we defer sending set_mate_dm until we reconnect to the main project's context.
170
- // The server will also receive it via the mate project's onDmMessage handler,
171
- // but the presence should only be stored on the main project slug.
172
- if (targetUser && targetUser.isMate) {
173
- var ws = getWs();
174
- // Send to the current WS only if it's the main project (not another mate)
175
- if (!store.get('mateProjectSlug') && ws && ws.readyState === 1) {
176
- try { ws.send(JSON.stringify({ type: "set_mate_dm", mateId: targetUser.id })); } catch(e) {}
177
- }
178
- }
179
-
180
185
  // Clear unread for this user
181
186
  if (targetUser) {
182
187
  store.get('dmUnread')[targetUser.id] = 0;
@@ -380,76 +385,23 @@ export function exitDmMode(skipProjectSwitch) {
380
385
 
381
386
  export function handleMateCreatedInApp(mate, msg) {
382
387
  if (!mate) return;
383
- var newMates = store.get('cachedMatesList').concat([mate]);
388
+ var newMates = (store.get('cachedMatesList') || []).filter(function (existing) { return existing && existing.id !== mate.id; }).concat([mate]);
384
389
  var updates = { cachedMatesList: newMates };
385
390
  if (msg && msg.availableBuiltins) updates.cachedAvailableBuiltins = msg.availableBuiltins;
386
391
  if (msg && msg.dmFavorites) updates.cachedDmFavorites = msg.dmFavorites;
387
392
  store.set(updates);
388
393
  // renderUserStrip is handled by the store subscriber
389
394
  // Built-in mates handle their own onboarding via CLAUDE.md, skip auto-interview
390
- if (!mate.builtinKey) {
395
+ if (!mate.builtinKey && !(msg && msg.interviewComplete === true)) {
391
396
  store.set({ pendingMateInterview: mate });
392
397
  }
393
- openDm(mate.id);
394
- }
395
-
396
- export function renderAvailableBuiltins(builtins) {
397
- // Append deleted built-in mates to the mates list in the picker
398
- var matesList = document.querySelector(".dm-mates-list");
399
- if (!matesList) return;
400
- if (!builtins || builtins.length === 0) return;
401
-
402
- for (var i = 0; i < builtins.length; i++) {
403
- (function (b) {
404
- var item = document.createElement("div");
405
- item.className = "dm-user-picker-item dm-user-picker-builtin-item";
406
- item.style.opacity = "0.5";
407
-
408
- var av = document.createElement("img");
409
- av.className = "dm-user-picker-avatar";
410
- av.src = b.avatarCustom || "";
411
- av.alt = b.displayName;
412
- item.appendChild(av);
413
-
414
- var nameWrap = document.createElement("div");
415
- nameWrap.style.cssText = "flex:1;min-width:0;";
416
- var nameEl = document.createElement("span");
417
- nameEl.className = "dm-user-picker-name";
418
- nameEl.textContent = b.displayName;
419
- nameWrap.appendChild(nameEl);
420
- var bioEl = document.createElement("div");
421
- bioEl.style.cssText = "font-size:11px;color:var(--text-dimmer);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;";
422
- bioEl.textContent = "Deleted";
423
- nameWrap.appendChild(bioEl);
424
- item.appendChild(nameWrap);
425
-
426
- var addBtn = document.createElement("button");
427
- addBtn.style.cssText = "border:none;background:none;cursor:pointer;padding:2px 6px;color:var(--accent, #6366f1);font-size:12px;font-weight:600;";
428
- addBtn.textContent = "+ Add";
429
- addBtn.title = "Re-add " + b.displayName;
430
- addBtn.addEventListener("click", function (e) {
431
- e.stopPropagation();
432
- var ws = getWs();
433
- if (ws && ws.readyState === 1) {
434
- ws.send(JSON.stringify({ type: "mate_readd_builtin", builtinKey: b.key }));
435
- }
436
- closeDmUserPicker();
437
- });
438
- item.appendChild(addBtn);
439
-
440
- item.addEventListener("click", function () {
441
- var ws = getWs();
442
- if (ws && ws.readyState === 1) {
443
- ws.send(JSON.stringify({ type: "mate_readd_builtin", builtinKey: b.key }));
444
- }
445
- closeDmUserPicker();
446
- });
447
-
448
- matesList.appendChild(item);
449
- })(builtins[i]);
398
+ if (!(msg && msg.interviewComplete === true)) {
399
+ showHomeHub();
400
+ openHomeChat(mate.id);
450
401
  }
451
402
  }
452
403
 
404
+
453
405
  export function buildMateInterviewPrompt(mate) {
454
406
  var sd = mate.seedData || {};
455
407
  var parts = [];
@@ -536,78 +488,20 @@ export function appendDmMessage(msg) {
536
488
  var s = store.snap();
537
489
  if (s.dmMode) s.dmMessageCache.push(msg);
538
490
  var isMe = msg.from === s.myUserId;
539
- var d = new Date(msg.ts);
540
- var timeStr = d.getHours().toString().padStart(2, "0") + ":" + d.getMinutes().toString().padStart(2, "0");
541
-
542
491
  var messagesEl = getMessagesEl();
543
- // Check if we can compact (same sender as previous, within 5 min)
544
- var prev = messagesEl.lastElementChild;
545
- var compact = false;
546
- if (prev && prev.dataset.from === msg.from) {
547
- var prevTs = parseInt(prev.dataset.ts || "0", 10);
548
- if (msg.ts - prevTs < 300000) compact = true;
549
- }
550
-
551
- var div = document.createElement("div");
552
- div.className = "dm-msg" + (compact ? " dm-msg-compact" : "");
553
- div.dataset.from = msg.from;
554
- div.dataset.ts = msg.ts;
555
-
556
- if (compact) {
557
- // Compact: just hover-time + text, no avatar/name
558
- var hoverTime = document.createElement("span");
559
- hoverTime.className = "dm-msg-hover-time";
560
- hoverTime.textContent = timeStr;
561
- div.appendChild(hoverTime);
562
-
563
- var body = document.createElement("div");
564
- body.className = "dm-msg-body";
565
- body.textContent = msg.text;
566
- div.appendChild(body);
567
- } else {
568
- // Full: avatar + header(name, time) + text
569
- var avatar = document.createElement("img");
570
- avatar.className = "dm-msg-avatar";
571
- if (isMe) {
572
- var myUser = s.cachedAllUsers.find(function (u) { return u.id === s.myUserId; });
573
- avatar.src = userAvatarUrl(myUser || { id: s.myUserId }, 36);
574
- } else if (s.dmTargetUser) {
575
- avatar.src = userAvatarUrl(s.dmTargetUser, 36);
576
- }
577
- div.appendChild(avatar);
578
-
579
- var content = document.createElement("div");
580
- content.className = "dm-msg-content";
581
-
582
- var header = document.createElement("div");
583
- header.className = "dm-msg-header";
584
-
585
- var name = document.createElement("span");
586
- name.className = "dm-msg-name";
587
- if (isMe) {
588
- var mu = s.cachedAllUsers.find(function (u) { return u.id === s.myUserId; });
589
- name.textContent = mu ? mu.displayName : "Me";
590
- } else {
591
- name.textContent = s.dmTargetUser ? s.dmTargetUser.displayName : "User";
592
- }
593
- header.appendChild(name);
594
-
595
- var time = document.createElement("span");
596
- time.className = "dm-msg-time";
597
- time.textContent = timeStr;
598
- header.appendChild(time);
599
-
600
- content.appendChild(header);
601
-
602
- var body = document.createElement("div");
603
- body.className = "dm-msg-body";
604
- body.textContent = msg.text;
605
- content.appendChild(body);
606
-
607
- div.appendChild(content);
608
- }
609
-
610
- messagesEl.appendChild(div);
492
+ var myUser = s.cachedAllUsers.find(function (user) { return user.id === s.myUserId; });
493
+ var avatarUrl = isMe
494
+ ? userAvatarUrl(myUser || { id: s.myUserId }, 36)
495
+ : (s.dmTargetUser ? userAvatarUrl(s.dmTargetUser, 36) : "");
496
+ var displayName = isMe
497
+ ? (myUser ? myUser.displayName : "Me")
498
+ : (s.dmTargetUser ? s.dmTargetUser.displayName : "User");
499
+ messagesEl.appendChild(buildDmMessage(msg, {
500
+ container: messagesEl,
501
+ isMe: isMe,
502
+ avatarUrl: avatarUrl,
503
+ displayName: displayName,
504
+ }));
611
505
  }
612
506
 
613
507
  export function showDmTypingIndicator(typing) {
@@ -620,22 +514,11 @@ export function showDmTypingIndicator(typing) {
620
514
  var dmTargetUser = store.get('dmTargetUser');
621
515
  if (!dmTargetUser) return;
622
516
 
623
- var div = document.createElement("div");
624
- div.id = "dm-typing-indicator";
625
- div.className = "dm-msg dm-typing-indicator";
626
-
627
- var avatar = document.createElement("img");
628
- avatar.className = "dm-msg-avatar";
629
- avatar.src = userAvatarUrl(dmTargetUser, 36);
630
- div.appendChild(avatar);
631
-
632
- var dots = document.createElement("div");
633
- dots.className = "dm-typing-dots";
634
- dots.innerHTML = "<span></span><span></span><span></span>";
635
- div.appendChild(dots);
636
-
637
517
  var messagesEl = getMessagesEl();
638
- messagesEl.appendChild(div);
518
+ messagesEl.appendChild(buildDmTypingIndicator({
519
+ id: "dm-typing-indicator",
520
+ avatarUrl: userAvatarUrl(dmTargetUser, 36),
521
+ }));
639
522
  scrollToBottom();
640
523
 
641
524
  // Auto-hide after 5s in case stop signal is missed