clay-server 3.8.1 → 4.0.0-beta.2
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/lib/ask-user-mcp-server.js +5 -119
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +1 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +4 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +1 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-memory.js +14 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +397 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +349 -102
- package/lib/public/app.js +85 -42
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +93 -74
- package/lib/public/modules/app-connection.js +10 -1
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +102 -37
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +158 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +7 -64
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +7 -6
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +13 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +10 -6
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +111 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +18 -3
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +93 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +73 -43
- package/lib/yoke/adapters/codex.js +40 -10
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +3 -2
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
// sidebar-mates.js - User/mate strip, DM picker, context menus, tooltips, presence
|
|
2
2
|
// Extracted from sidebar.js (PR-37)
|
|
3
3
|
|
|
4
|
-
import { userAvatarUrl
|
|
4
|
+
import { userAvatarUrl } from './avatar.js';
|
|
5
5
|
import { escapeHtml } from './utils.js';
|
|
6
6
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
7
|
-
import { showMateProfilePopover } from './profile.js';
|
|
8
7
|
import { store } from './store.js';
|
|
9
8
|
import { getWs } from './ws-ref.js';
|
|
10
9
|
import { closeProjectCtxMenu } from './sidebar-projects.js';
|
|
11
10
|
import { spawnDustParticles } from './sidebar.js';
|
|
12
11
|
import { openDm } from './app-dm.js';
|
|
13
|
-
import {
|
|
14
|
-
import { openUserSettings } from './user-settings.js';
|
|
15
|
-
import { getCachedProjects } from './app-projects.js';
|
|
12
|
+
import { showMateManagementMenu, closeMateManagementMenu } from './mate-management.js';
|
|
16
13
|
|
|
17
14
|
function sendWs(msg) {
|
|
18
15
|
var ws = getWs();
|
|
@@ -32,13 +29,33 @@ var cachedDmRemovedUsers = {};
|
|
|
32
29
|
var cachedMates = [];
|
|
33
30
|
var activeMentionMateIds = {};
|
|
34
31
|
|
|
32
|
+
export function getActiveMentionMateIds() {
|
|
33
|
+
return activeMentionMateIds;
|
|
34
|
+
}
|
|
35
|
+
|
|
35
36
|
export function setMentionActive(mateId, active) {
|
|
36
37
|
if (active) { activeMentionMateIds[mateId] = true; }
|
|
37
38
|
else { delete activeMentionMateIds[mateId]; }
|
|
39
|
+
notifyMentionListeners();
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export function clearAllMentionActive() {
|
|
41
43
|
activeMentionMateIds = {};
|
|
44
|
+
notifyMentionListeners();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Mates render on the home hub now, so their mention state has to reach a
|
|
48
|
+
// renderer that no longer owns it. Listeners are registered by app.js.
|
|
49
|
+
var mentionListeners = [];
|
|
50
|
+
|
|
51
|
+
export function onMentionActiveChange(listener) {
|
|
52
|
+
mentionListeners.push(listener);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function notifyMentionListeners() {
|
|
56
|
+
for (var i = 0; i < mentionListeners.length; i++) {
|
|
57
|
+
try { mentionListeners[i](); } catch (e) { /* listener must not break the strip */ }
|
|
58
|
+
}
|
|
42
59
|
}
|
|
43
60
|
var _lastUserStripJson = "";
|
|
44
61
|
|
|
@@ -79,10 +96,11 @@ export function showIconTooltip(el, text) {
|
|
|
79
96
|
});
|
|
80
97
|
}
|
|
81
98
|
|
|
82
|
-
export function showIconTooltipHtml(el, html) {
|
|
99
|
+
export function showIconTooltipHtml(el, html, options) {
|
|
83
100
|
hideIconTooltip();
|
|
101
|
+
options = options || {};
|
|
84
102
|
var tip = document.createElement("div");
|
|
85
|
-
tip.className = "icon-strip-tooltip";
|
|
103
|
+
tip.className = "icon-strip-tooltip" + (options.className ? " " + options.className : "");
|
|
86
104
|
tip.style.whiteSpace = "normal";
|
|
87
105
|
tip.style.maxWidth = "260px";
|
|
88
106
|
tip.innerHTML = html;
|
|
@@ -91,7 +109,14 @@ export function showIconTooltipHtml(el, html) {
|
|
|
91
109
|
|
|
92
110
|
requestAnimationFrame(function () {
|
|
93
111
|
var rect = el.getBoundingClientRect();
|
|
94
|
-
|
|
112
|
+
if (options.placement === "bottom") {
|
|
113
|
+
var left = rect.left + rect.width / 2 - tip.offsetWidth / 2;
|
|
114
|
+
left = Math.max(12, Math.min(left, window.innerWidth - tip.offsetWidth - 12));
|
|
115
|
+
tip.style.left = left + "px";
|
|
116
|
+
tip.style.top = (rect.bottom + 8) + "px";
|
|
117
|
+
} else {
|
|
118
|
+
tip.style.top = (rect.top + rect.height / 2 - tip.offsetHeight / 2) + "px";
|
|
119
|
+
}
|
|
95
120
|
tip.classList.add("visible");
|
|
96
121
|
});
|
|
97
122
|
}
|
|
@@ -109,6 +134,7 @@ export function closeUserCtxMenu() {
|
|
|
109
134
|
userCtxMenu = null;
|
|
110
135
|
}
|
|
111
136
|
document.removeEventListener("click", handleUserCtxOutsideClick, true);
|
|
137
|
+
closeMateManagementMenu();
|
|
112
138
|
}
|
|
113
139
|
|
|
114
140
|
function showUserCtxMenu(anchorEl, user) {
|
|
@@ -166,97 +192,17 @@ function handleUserCtxOutsideClick(e) {
|
|
|
166
192
|
}
|
|
167
193
|
}
|
|
168
194
|
|
|
169
|
-
function showMateCtxMenu(anchorEl, mate) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// Edit Profile item
|
|
180
|
-
var editItem = document.createElement("button");
|
|
181
|
-
editItem.className = "project-ctx-item";
|
|
182
|
-
editItem.innerHTML = iconHtml("edit-2") + " <span>Edit Profile</span>";
|
|
183
|
-
editItem.addEventListener("click", function (e) {
|
|
184
|
-
e.stopPropagation();
|
|
185
|
-
closeUserCtxMenu();
|
|
186
|
-
showMateProfilePopover(anchorEl, mate, function (updates) {
|
|
187
|
-
sendWs({ type: "mate_update", mateId: mate.id, updates: updates });
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
menu.appendChild(editItem);
|
|
191
|
-
|
|
192
|
-
var removeItem = document.createElement("button");
|
|
193
|
-
removeItem.className = "project-ctx-item";
|
|
194
|
-
removeItem.innerHTML = iconHtml("star-off") + " <span>Remove from favorites</span>";
|
|
195
|
-
removeItem.addEventListener("click", function (e) {
|
|
196
|
-
e.stopPropagation();
|
|
197
|
-
closeUserCtxMenu();
|
|
198
|
-
// Spawn dust particles at the mate icon position
|
|
199
|
-
var iconRect = anchorEl.getBoundingClientRect();
|
|
200
|
-
if (spawnDustParticles) spawnDustParticles(iconRect.left + iconRect.width / 2, iconRect.top + iconRect.height / 2);
|
|
201
|
-
sendWs({ type: "dm_remove_favorite", targetUserId: mate.id });
|
|
195
|
+
export function showMateCtxMenu(anchorEl, mate) {
|
|
196
|
+
showMateManagementMenu(anchorEl, mate, {
|
|
197
|
+
beforeOpen: function () {
|
|
198
|
+
closeUserCtxMenu();
|
|
199
|
+
if (closeProjectCtxMenu) closeProjectCtxMenu();
|
|
200
|
+
},
|
|
201
|
+
onRemoved: function () {
|
|
202
|
+
var iconRect = anchorEl.getBoundingClientRect();
|
|
203
|
+
if (spawnDustParticles) spawnDustParticles(iconRect.left + iconRect.width / 2, iconRect.top + iconRect.height / 2);
|
|
204
|
+
},
|
|
202
205
|
});
|
|
203
|
-
menu.appendChild(removeItem);
|
|
204
|
-
|
|
205
|
-
document.body.appendChild(menu);
|
|
206
|
-
userCtxMenu = menu;
|
|
207
|
-
refreshIcons();
|
|
208
|
-
|
|
209
|
-
requestAnimationFrame(function () {
|
|
210
|
-
var rect = anchorEl.getBoundingClientRect();
|
|
211
|
-
menu.style.position = "fixed";
|
|
212
|
-
menu.style.left = (rect.right + 6) + "px";
|
|
213
|
-
menu.style.top = rect.top + "px";
|
|
214
|
-
var menuRect = menu.getBoundingClientRect();
|
|
215
|
-
if (menuRect.right > window.innerWidth - 8) {
|
|
216
|
-
menu.style.left = (rect.left - menuRect.width - 6) + "px";
|
|
217
|
-
}
|
|
218
|
-
if (menuRect.bottom > window.innerHeight - 8) {
|
|
219
|
-
menu.style.top = (window.innerHeight - menuRect.height - 8) + "px";
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
setTimeout(function () {
|
|
224
|
-
document.addEventListener("click", handleUserCtxOutsideClick, true);
|
|
225
|
-
}, 0);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
var _lastSidebarPresenceIds = [];
|
|
229
|
-
export function renderSidebarPresence(onlineUsers) {
|
|
230
|
-
var container = document.getElementById("sidebar-presence");
|
|
231
|
-
if (!container) return;
|
|
232
|
-
if (!onlineUsers || onlineUsers.length < 2) {
|
|
233
|
-
if (_lastSidebarPresenceIds.length > 0) {
|
|
234
|
-
_lastSidebarPresenceIds = [];
|
|
235
|
-
container.innerHTML = "";
|
|
236
|
-
}
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
// Skip re-render if same users
|
|
240
|
-
var newIds = onlineUsers.map(function (u) { return u.id; }).sort();
|
|
241
|
-
if (newIds.length === _lastSidebarPresenceIds.length && newIds.every(function (id, i) { return id === _lastSidebarPresenceIds[i]; })) return;
|
|
242
|
-
_lastSidebarPresenceIds = newIds;
|
|
243
|
-
container.innerHTML = "";
|
|
244
|
-
var maxShow = 4;
|
|
245
|
-
for (var i = 0; i < Math.min(onlineUsers.length, maxShow); i++) {
|
|
246
|
-
var ou = onlineUsers[i];
|
|
247
|
-
var img = document.createElement("img");
|
|
248
|
-
img.className = "sidebar-presence-avatar";
|
|
249
|
-
img.src = presenceAvatarUrl(ou);
|
|
250
|
-
img.alt = ou.displayName;
|
|
251
|
-
img.dataset.tip = ou.displayName + " (@" + ou.username + ")";
|
|
252
|
-
container.appendChild(img);
|
|
253
|
-
}
|
|
254
|
-
if (onlineUsers.length > maxShow) {
|
|
255
|
-
var more = document.createElement("span");
|
|
256
|
-
more.className = "sidebar-presence-more";
|
|
257
|
-
more.textContent = "+" + (onlineUsers.length - maxShow);
|
|
258
|
-
container.appendChild(more);
|
|
259
|
-
}
|
|
260
206
|
}
|
|
261
207
|
|
|
262
208
|
// Presence avatar URL helper
|
|
@@ -365,135 +311,6 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
365
311
|
})(others[i]);
|
|
366
312
|
}
|
|
367
313
|
|
|
368
|
-
// Build mate project status lookup from project list
|
|
369
|
-
var mateProjectStatus = {};
|
|
370
|
-
var _projList = getCachedProjects() || [];
|
|
371
|
-
if (_projList.length) {
|
|
372
|
-
var allProjects = _projList;
|
|
373
|
-
for (var pi = 0; pi < allProjects.length; pi++) {
|
|
374
|
-
if (allProjects[pi].isMate) {
|
|
375
|
-
mateProjectStatus[allProjects[pi].slug] = allProjects[pi];
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Render mates: only favorited or unread, regardless of mode. Previously
|
|
381
|
-
// single-user mode short-circuited to "show all", which meant users who
|
|
382
|
-
// never engaged with Mates still saw 6 permanent avatars in the rail
|
|
383
|
-
// with no way to thin them out (#341). Applying the same filter as
|
|
384
|
-
// multi-user lets users curate the icon strip via favorites; the full
|
|
385
|
-
// mate list is still reachable from the DM picker.
|
|
386
|
-
var favoriteMates = cachedMates.filter(function (m) {
|
|
387
|
-
if (m.archived) return false;
|
|
388
|
-
// Clay is the host agent reachable only via the Home button — never
|
|
389
|
-
// shown alongside regular mates in the sidebar list.
|
|
390
|
-
if (m.builtinKey === "clay") return false;
|
|
391
|
-
if (cachedDmRemovedUsers[m.id]) return false;
|
|
392
|
-
if (cachedDmFavorites.indexOf(m.id) !== -1) return true;
|
|
393
|
-
if (cachedDmUnread[m.id] && cachedDmUnread[m.id] > 0) return true;
|
|
394
|
-
return false;
|
|
395
|
-
});
|
|
396
|
-
var sortedMates = favoriteMates.sort(function (a, b) {
|
|
397
|
-
var aBuiltin = a.builtinKey ? 1 : 0;
|
|
398
|
-
var bBuiltin = b.builtinKey ? 1 : 0;
|
|
399
|
-
if (aBuiltin !== bBuiltin) return bBuiltin - aBuiltin;
|
|
400
|
-
return (a.createdAt || 0) - (b.createdAt || 0);
|
|
401
|
-
});
|
|
402
|
-
for (var mi = 0; mi < sortedMates.length; mi++) {
|
|
403
|
-
(function (mate) {
|
|
404
|
-
var mp = mate.profile || {};
|
|
405
|
-
var mateSlug = "mate-" + mate.id;
|
|
406
|
-
var mateProj = mateProjectStatus[mateSlug] || {};
|
|
407
|
-
var isActive = mate.id === currentDmUserId;
|
|
408
|
-
var el = document.createElement("div");
|
|
409
|
-
el.className = "icon-strip-user icon-strip-mate";
|
|
410
|
-
el.dataset.userId = mate.id;
|
|
411
|
-
el.dataset.mateSlug = mateSlug;
|
|
412
|
-
if (isActive) el.classList.add("active");
|
|
413
|
-
|
|
414
|
-
// Pending permission shake
|
|
415
|
-
if (mateProj.pendingPermissions > 0 && !isActive) {
|
|
416
|
-
el.classList.add("has-pending-perm");
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
var pill = document.createElement("span");
|
|
420
|
-
pill.className = "icon-strip-pill";
|
|
421
|
-
el.appendChild(pill);
|
|
422
|
-
|
|
423
|
-
var avatar = document.createElement("img");
|
|
424
|
-
avatar.className = "icon-strip-user-avatar" + (mate.primary ? " icon-strip-primary-mate" : "");
|
|
425
|
-
avatar.src = mateAvatarUrl(mate, 34);
|
|
426
|
-
avatar.alt = mp.displayName || mate.name || "Mate";
|
|
427
|
-
var mateColor = (mp.avatarColor) || mate.avatarColor || "#5857fc";
|
|
428
|
-
avatar.style.background = mateColor + "30";
|
|
429
|
-
el.appendChild(avatar);
|
|
430
|
-
|
|
431
|
-
// Processing status dot (IO blink) - top-left
|
|
432
|
-
var statusDot = document.createElement("span");
|
|
433
|
-
statusDot.className = "icon-strip-status";
|
|
434
|
-
var isMentionActive = !!activeMentionMateIds[mate.id];
|
|
435
|
-
if (mateProj.isProcessing || isMentionActive) statusDot.classList.add("processing");
|
|
436
|
-
if (isMentionActive) el.classList.add("mention-active");
|
|
437
|
-
el.appendChild(statusDot);
|
|
438
|
-
|
|
439
|
-
// Mate badge (bot icon)
|
|
440
|
-
var mateBadge = document.createElement("span");
|
|
441
|
-
mateBadge.className = "icon-strip-user-mate-badge";
|
|
442
|
-
mateBadge.innerHTML = iconHtml("bot");
|
|
443
|
-
el.appendChild(mateBadge);
|
|
444
|
-
|
|
445
|
-
var badge = document.createElement("span");
|
|
446
|
-
badge.className = "icon-strip-user-badge";
|
|
447
|
-
badge.dataset.userId = mate.id;
|
|
448
|
-
el.appendChild(badge);
|
|
449
|
-
|
|
450
|
-
// Restore unread badge if cached
|
|
451
|
-
var unreadCount = cachedDmUnread[mate.id] || 0;
|
|
452
|
-
if (unreadCount > 0 && !isActive) {
|
|
453
|
-
badge.textContent = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
454
|
-
badge.classList.add("has-unread");
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Tooltip
|
|
458
|
-
var displayName = mp.displayName || mate.name || "New Mate";
|
|
459
|
-
var mateVendor = mate.vendor || "claude";
|
|
460
|
-
var vendorLabels = {
|
|
461
|
-
claude: "Claude Code",
|
|
462
|
-
codex: "OpenAI Codex",
|
|
463
|
-
antigravity: "Antigravity CLI",
|
|
464
|
-
opencode: "OpenCode",
|
|
465
|
-
kiro: "Kiro CLI",
|
|
466
|
-
};
|
|
467
|
-
el.addEventListener("mouseenter", function () {
|
|
468
|
-
var html = '<div style="font-weight:600">' + escapeHtml(displayName);
|
|
469
|
-
if (mate.primary) {
|
|
470
|
-
html += ' <span style="font-size:10px;font-weight:600;color:#00b894;background:rgba(0,184,148,0.1);padding:1px 5px;border-radius:3px;margin-left:4px">SYSTEM</span>';
|
|
471
|
-
}
|
|
472
|
-
html += '</div>';
|
|
473
|
-
if (mate.bio) {
|
|
474
|
-
html += '<div style="font-weight:400;font-size:12px;color:var(--text-secondary);margin-top:2px">' + escapeHtml(mate.bio) + '</div>';
|
|
475
|
-
}
|
|
476
|
-
var vendorLabel = vendorLabels[mateVendor] || mateVendor;
|
|
477
|
-
html += '<div style="font-size:11px;color:var(--text-dimmer);margin-top:3px">Powered by ' + escapeHtml(vendorLabel) + '</div>';
|
|
478
|
-
showIconTooltipHtml(el, html);
|
|
479
|
-
});
|
|
480
|
-
el.addEventListener("mouseleave", hideIconTooltip);
|
|
481
|
-
|
|
482
|
-
// Click: open DM with mate
|
|
483
|
-
el.addEventListener("click", function () {
|
|
484
|
-
if (openDm) openDm(mate.id);
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
// Right-click: context menu for mate
|
|
488
|
-
el.addEventListener("contextmenu", function (e) {
|
|
489
|
-
e.preventDefault();
|
|
490
|
-
e.stopPropagation();
|
|
491
|
-
showMateCtxMenu(el, mate);
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
container.appendChild(el);
|
|
495
|
-
})(sortedMates[mi]);
|
|
496
|
-
}
|
|
497
314
|
|
|
498
315
|
// Show container if we have mates even with no other users
|
|
499
316
|
if (cachedMates.length > 0) {
|
|
@@ -508,7 +325,7 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
508
325
|
e.stopPropagation();
|
|
509
326
|
toggleDmUserPicker(addBtn);
|
|
510
327
|
});
|
|
511
|
-
addBtn.addEventListener("mouseenter", function () { showIconTooltip(addBtn, "Add user
|
|
328
|
+
addBtn.addEventListener("mouseenter", function () { showIconTooltip(addBtn, "Add user"); });
|
|
512
329
|
addBtn.addEventListener("mouseleave", hideIconTooltip);
|
|
513
330
|
container.appendChild(addBtn);
|
|
514
331
|
refreshIcons();
|
|
@@ -525,17 +342,12 @@ function toggleDmUserPicker(anchorEl) {
|
|
|
525
342
|
picker.className = "dm-user-picker";
|
|
526
343
|
picker.id = "dm-user-picker";
|
|
527
344
|
|
|
528
|
-
// Mates enabled flag is consulted up here so the search input can drop
|
|
529
|
-
// mates from its placeholder copy when the section is hidden.
|
|
530
|
-
var matesEnabled = store.get('matesEnabled') !== false;
|
|
531
|
-
|
|
532
345
|
// Search input
|
|
533
346
|
var searchInput = document.createElement("input");
|
|
534
347
|
searchInput.className = "dm-user-picker-search";
|
|
535
348
|
searchInput.type = "text";
|
|
536
|
-
searchInput.placeholder =
|
|
537
|
-
|
|
538
|
-
: "Search users...";
|
|
349
|
+
searchInput.placeholder = "Search users...";
|
|
350
|
+
searchInput.setAttribute("aria-label", "Search users");
|
|
539
351
|
picker.appendChild(searchInput);
|
|
540
352
|
|
|
541
353
|
// User list element (appended later, after USERS label)
|
|
@@ -595,323 +407,15 @@ function toggleDmUserPicker(anchorEl) {
|
|
|
595
407
|
}
|
|
596
408
|
}
|
|
597
409
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
// matesListEl + renderMatesList are only used in the enabled layout.
|
|
609
|
-
// Declared up-front so the search handler can reference renderMatesList
|
|
610
|
-
// safely; renderMatesList stays a no-op in disabled mode.
|
|
611
|
-
var matesListEl = null;
|
|
612
|
-
var renderMatesList = function () {};
|
|
613
|
-
|
|
614
|
-
function renderMatesEnabledSection() {
|
|
615
|
-
var matesSectionLabel = document.createElement("div");
|
|
616
|
-
matesSectionLabel.className = "dm-user-picker-section";
|
|
617
|
-
matesSectionLabel.textContent = "Mates";
|
|
618
|
-
picker.appendChild(matesSectionLabel);
|
|
619
|
-
|
|
620
|
-
matesListEl = document.createElement("div");
|
|
621
|
-
matesListEl.className = "dm-user-picker-list dm-mates-list";
|
|
622
|
-
picker.appendChild(matesListEl);
|
|
623
|
-
|
|
624
|
-
// Update scroll gradient hint
|
|
625
|
-
function updateMatesScrollHint() {
|
|
626
|
-
var isOverflow = matesListEl.scrollHeight > matesListEl.clientHeight + 2;
|
|
627
|
-
if (!isOverflow) {
|
|
628
|
-
matesListEl.classList.add("no-overflow");
|
|
629
|
-
matesListEl.classList.remove("scrolled-bottom");
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
matesListEl.classList.remove("no-overflow");
|
|
633
|
-
var atBottom = matesListEl.scrollTop + matesListEl.clientHeight >= matesListEl.scrollHeight - 4;
|
|
634
|
-
if (atBottom) {
|
|
635
|
-
matesListEl.classList.add("scrolled-bottom");
|
|
636
|
-
} else {
|
|
637
|
-
matesListEl.classList.remove("scrolled-bottom");
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
matesListEl.addEventListener("scroll", updateMatesScrollHint);
|
|
641
|
-
|
|
642
|
-
renderMatesList = function (filter) {
|
|
643
|
-
matesListEl.innerHTML = "";
|
|
644
|
-
var allMates = cachedMates || [];
|
|
645
|
-
if (filter) {
|
|
646
|
-
var lf = filter.toLowerCase();
|
|
647
|
-
allMates = allMates.filter(function (m) {
|
|
648
|
-
var name = (m.profile && m.profile.displayName) || m.name || "";
|
|
649
|
-
return name.toLowerCase().indexOf(lf) !== -1;
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
// Build unified list: installed builtins, deleted builtins, user-created
|
|
653
|
-
var availBuiltins = store.get('cachedAvailableBuiltins') || [];
|
|
654
|
-
var entries = [];
|
|
655
|
-
// 1. Installed builtin mates
|
|
656
|
-
for (var si = 0; si < allMates.length; si++) {
|
|
657
|
-
if (allMates[si].builtinKey) entries.push({ type: "mate", data: allMates[si] });
|
|
658
|
-
}
|
|
659
|
-
// 2. Deleted builtins (only when not filtering)
|
|
660
|
-
if (!filter) {
|
|
661
|
-
for (var di = 0; di < availBuiltins.length; di++) {
|
|
662
|
-
entries.push({ type: "deleted", data: availBuiltins[di] });
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
// 3. User-created mates
|
|
666
|
-
var userMates = allMates.filter(function (m) { return !m.builtinKey; });
|
|
667
|
-
userMates.sort(function (a, b) { return (a.createdAt || 0) - (b.createdAt || 0); });
|
|
668
|
-
for (var ui = 0; ui < userMates.length; ui++) {
|
|
669
|
-
entries.push({ type: "mate", data: userMates[ui] });
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
for (var i = 0; i < entries.length; i++) {
|
|
673
|
-
var entry = entries[i];
|
|
674
|
-
if (entry.type === "deleted") {
|
|
675
|
-
// Deleted builtin: show with "+ Add" button
|
|
676
|
-
(function (b) {
|
|
677
|
-
var bItem = document.createElement("div");
|
|
678
|
-
bItem.className = "dm-user-picker-item dm-user-picker-builtin-item";
|
|
679
|
-
bItem.style.opacity = "0.7";
|
|
680
|
-
var bAv = document.createElement("img");
|
|
681
|
-
bAv.className = "dm-user-picker-avatar";
|
|
682
|
-
bAv.src = mateAvatarUrl({ avatarCustom: b.avatarCustom, avatarStyle: b.avatarStyle || "imprint", avatarSeed: b.displayName, id: b.key, avatarColor: b.avatarColor }, 28);
|
|
683
|
-
bAv.alt = b.displayName;
|
|
684
|
-
bItem.appendChild(bAv);
|
|
685
|
-
var bNameWrap = document.createElement("div");
|
|
686
|
-
bNameWrap.style.cssText = "flex:1;min-width:0;";
|
|
687
|
-
var bName = document.createElement("span");
|
|
688
|
-
bName.className = "dm-user-picker-name";
|
|
689
|
-
bName.textContent = b.displayName;
|
|
690
|
-
bNameWrap.appendChild(bName);
|
|
691
|
-
var bBio = document.createElement("div");
|
|
692
|
-
bBio.style.cssText = "font-size:11px;color:var(--text-dimmer);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;";
|
|
693
|
-
bBio.textContent = b.bio || b.displayName;
|
|
694
|
-
bNameWrap.appendChild(bBio);
|
|
695
|
-
bItem.appendChild(bNameWrap);
|
|
696
|
-
var bAddBtn = document.createElement("button");
|
|
697
|
-
bAddBtn.style.cssText = "border:none;background:none;cursor:pointer;padding:2px 6px;color:var(--accent, #6366f1);font-size:12px;font-weight:600;white-space:nowrap;";
|
|
698
|
-
bAddBtn.textContent = "+ Add";
|
|
699
|
-
bAddBtn.title = "Re-add " + b.displayName;
|
|
700
|
-
bAddBtn.addEventListener("click", function (e) {
|
|
701
|
-
e.stopPropagation();
|
|
702
|
-
sendWs({ type: "mate_readd_builtin", builtinKey: b.key });
|
|
703
|
-
closeDmUserPicker();
|
|
704
|
-
});
|
|
705
|
-
bItem.appendChild(bAddBtn);
|
|
706
|
-
bItem.addEventListener("click", function () {
|
|
707
|
-
sendWs({ type: "mate_readd_builtin", builtinKey: b.key });
|
|
708
|
-
closeDmUserPicker();
|
|
709
|
-
});
|
|
710
|
-
matesListEl.appendChild(bItem);
|
|
711
|
-
})(entry.data);
|
|
712
|
-
} else {
|
|
713
|
-
// Normal mate
|
|
714
|
-
(function (m) {
|
|
715
|
-
var mp = m.profile || {};
|
|
716
|
-
var isFav = cachedDmFavorites.indexOf(m.id) !== -1;
|
|
717
|
-
var item = document.createElement("div");
|
|
718
|
-
item.className = "dm-user-picker-item";
|
|
719
|
-
if (isFav) item.classList.add("dm-picker-fav");
|
|
720
|
-
var av = document.createElement("img");
|
|
721
|
-
av.className = "dm-user-picker-avatar";
|
|
722
|
-
av.src = mateAvatarUrl(m, 28);
|
|
723
|
-
av.alt = mp.displayName || m.name || "Mate";
|
|
724
|
-
item.appendChild(av);
|
|
725
|
-
var nameWrap = document.createElement("div");
|
|
726
|
-
nameWrap.style.cssText = "flex:1;min-width:0;";
|
|
727
|
-
var name = document.createElement("span");
|
|
728
|
-
name.className = "dm-user-picker-name";
|
|
729
|
-
name.textContent = mp.displayName || m.name || "Mate";
|
|
730
|
-
nameWrap.appendChild(name);
|
|
731
|
-
if (m.bio) {
|
|
732
|
-
var bio = document.createElement("div");
|
|
733
|
-
bio.style.cssText = "font-size:11px;color:var(--text-dimmer);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;";
|
|
734
|
-
bio.textContent = m.bio;
|
|
735
|
-
nameWrap.appendChild(bio);
|
|
736
|
-
}
|
|
737
|
-
item.appendChild(nameWrap);
|
|
738
|
-
// Delete button with inline confirm
|
|
739
|
-
var delBtn = document.createElement("button");
|
|
740
|
-
delBtn.className = "dm-picker-del-btn";
|
|
741
|
-
delBtn.innerHTML = m.builtinKey ? iconHtml("minus-circle") : iconHtml("trash-2");
|
|
742
|
-
delBtn.title = m.builtinKey ? "Remove mate" : "Delete mate";
|
|
743
|
-
delBtn.addEventListener("click", function (e) {
|
|
744
|
-
e.stopPropagation();
|
|
745
|
-
var origHtml = item.innerHTML;
|
|
746
|
-
item.innerHTML = "";
|
|
747
|
-
item.style.justifyContent = "center";
|
|
748
|
-
item.style.gap = "6px";
|
|
749
|
-
var confirmMsg = document.createElement("span");
|
|
750
|
-
confirmMsg.style.cssText = "font-size:12px;color:var(--text-dimmer);";
|
|
751
|
-
confirmMsg.textContent = m.builtinKey ? "Remove? You can add back anytime." : "Delete permanently?";
|
|
752
|
-
item.appendChild(confirmMsg);
|
|
753
|
-
var yesBtn = document.createElement("button");
|
|
754
|
-
yesBtn.style.cssText = "border:none;background:var(--danger,#e74c3c);color:#fff;padding:3px 10px;border-radius:4px;font-size:12px;cursor:pointer;";
|
|
755
|
-
yesBtn.textContent = m.builtinKey ? "Remove" : "Delete";
|
|
756
|
-
yesBtn.addEventListener("click", function (e2) {
|
|
757
|
-
e2.stopPropagation();
|
|
758
|
-
sendWs({ type: "mate_delete", mateId: m.id });
|
|
759
|
-
closeDmUserPicker();
|
|
760
|
-
});
|
|
761
|
-
item.appendChild(yesBtn);
|
|
762
|
-
var noBtn = document.createElement("button");
|
|
763
|
-
noBtn.style.cssText = "border:1px solid var(--border);background:none;color:var(--text);padding:3px 10px;border-radius:4px;font-size:12px;cursor:pointer;";
|
|
764
|
-
noBtn.textContent = "Cancel";
|
|
765
|
-
noBtn.addEventListener("click", function (e2) {
|
|
766
|
-
e2.stopPropagation();
|
|
767
|
-
item.innerHTML = origHtml;
|
|
768
|
-
item.style.justifyContent = "";
|
|
769
|
-
item.style.gap = "";
|
|
770
|
-
refreshIcons();
|
|
771
|
-
});
|
|
772
|
-
item.appendChild(noBtn);
|
|
773
|
-
});
|
|
774
|
-
item.appendChild(delBtn);
|
|
775
|
-
item.addEventListener("click", function () {
|
|
776
|
-
if (openDm) openDm(m.id);
|
|
777
|
-
if (!isFav) sendWs({ type: "dm_add_favorite", targetUserId: m.id });
|
|
778
|
-
closeDmUserPicker();
|
|
779
|
-
});
|
|
780
|
-
matesListEl.appendChild(item);
|
|
781
|
-
})(entry.data);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
if (entries.length === 0 && filter) {
|
|
786
|
-
var emptyEl = document.createElement("div");
|
|
787
|
-
emptyEl.className = "dm-user-picker-empty";
|
|
788
|
-
emptyEl.textContent = "No mates found";
|
|
789
|
-
matesListEl.appendChild(emptyEl);
|
|
790
|
-
}
|
|
791
|
-
refreshIcons();
|
|
792
|
-
requestAnimationFrame(updateMatesScrollHint);
|
|
793
|
-
};
|
|
794
|
-
|
|
795
|
-
// Create Mate option
|
|
796
|
-
var createMateEl = document.createElement("div");
|
|
797
|
-
createMateEl.className = "dm-user-picker-create-mate";
|
|
798
|
-
var hasCustomMates = (cachedMates || []).some(function (m) { return !m.builtinKey; });
|
|
799
|
-
var createMateLabel = hasCustomMates ? "Create a Mate" : "Create a Mate for what you're doing";
|
|
800
|
-
createMateEl.innerHTML = iconHtml("bot") + " <span>" + createMateLabel + "</span>";
|
|
801
|
-
createMateEl.addEventListener("click", function () {
|
|
802
|
-
closeDmUserPicker();
|
|
803
|
-
if (openMateWizard) openMateWizard();
|
|
804
|
-
});
|
|
805
|
-
picker.appendChild(createMateEl);
|
|
806
|
-
|
|
807
|
-
// Divider
|
|
808
|
-
var divider = document.createElement("div");
|
|
809
|
-
divider.style.borderTop = "1px solid var(--border, #333)";
|
|
810
|
-
divider.style.margin = "4px 0";
|
|
811
|
-
picker.appendChild(divider);
|
|
812
|
-
|
|
813
|
-
// Users section
|
|
814
|
-
var usersLabelEnabled = document.createElement("div");
|
|
815
|
-
usersLabelEnabled.className = "dm-user-picker-section";
|
|
816
|
-
usersLabelEnabled.textContent = "Users";
|
|
817
|
-
picker.appendChild(usersLabelEnabled);
|
|
818
|
-
picker.appendChild(listEl);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
function renderMatesDisabledLayout() {
|
|
822
|
-
// Users section first when Mates is off — they are the only thing
|
|
823
|
-
// a user can actually act on, so they lead.
|
|
824
|
-
var usersLabel = document.createElement("div");
|
|
825
|
-
usersLabel.className = "dm-user-picker-section";
|
|
826
|
-
usersLabel.textContent = "Users";
|
|
827
|
-
picker.appendChild(usersLabel);
|
|
828
|
-
picker.appendChild(listEl);
|
|
829
|
-
|
|
830
|
-
// Divider
|
|
831
|
-
var divider = document.createElement("div");
|
|
832
|
-
divider.style.borderTop = "1px solid var(--border, #333)";
|
|
833
|
-
divider.style.margin = "8px 0 4px";
|
|
834
|
-
picker.appendChild(divider);
|
|
835
|
-
|
|
836
|
-
// Mates discovery promo: animated avatar marquee + value prop + CTA.
|
|
837
|
-
// The marquee uses real cached mate avatars purely as decoration; we
|
|
838
|
-
// never attach click handlers, never show delete buttons, and never
|
|
839
|
-
// render a list view — turning the section into a soft invitation
|
|
840
|
-
// rather than a "list with everything greyed out" tease.
|
|
841
|
-
var promo = document.createElement("div");
|
|
842
|
-
promo.className = "dm-picker-mates-promo";
|
|
843
|
-
|
|
844
|
-
var promoLabel = document.createElement("div");
|
|
845
|
-
promoLabel.className = "dm-user-picker-section";
|
|
846
|
-
promoLabel.textContent = "Mates";
|
|
847
|
-
promo.appendChild(promoLabel);
|
|
848
|
-
|
|
849
|
-
var marqueeWrap = document.createElement("div");
|
|
850
|
-
marqueeWrap.className = "dm-picker-mates-marquee";
|
|
851
|
-
var marqueeTrack = document.createElement("div");
|
|
852
|
-
marqueeTrack.className = "dm-picker-mates-marquee-track";
|
|
853
|
-
var marqueeSource = (cachedMates && cachedMates.length > 0)
|
|
854
|
-
? cachedMates.slice(0, 8)
|
|
855
|
-
: (store.get('cachedAvailableBuiltins') || []).slice(0, 6);
|
|
856
|
-
// Duplicate the avatar set so the keyframe loop wraps seamlessly.
|
|
857
|
-
for (var copy = 0; copy < 2; copy++) {
|
|
858
|
-
for (var mi = 0; mi < marqueeSource.length; mi++) {
|
|
859
|
-
var src = marqueeSource[mi];
|
|
860
|
-
var avEl = document.createElement("img");
|
|
861
|
-
avEl.className = "dm-picker-mates-marquee-avatar";
|
|
862
|
-
avEl.alt = "";
|
|
863
|
-
avEl.setAttribute("aria-hidden", "true");
|
|
864
|
-
if (src.id) {
|
|
865
|
-
avEl.src = mateAvatarUrl(src, 32);
|
|
866
|
-
} else {
|
|
867
|
-
avEl.src = mateAvatarUrl({
|
|
868
|
-
avatarCustom: src.avatarCustom,
|
|
869
|
-
avatarStyle: src.avatarStyle || "imprint",
|
|
870
|
-
avatarColor: src.avatarColor,
|
|
871
|
-
avatarSeed: src.displayName,
|
|
872
|
-
id: src.key,
|
|
873
|
-
}, 32);
|
|
874
|
-
}
|
|
875
|
-
marqueeTrack.appendChild(avEl);
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
marqueeWrap.appendChild(marqueeTrack);
|
|
879
|
-
promo.appendChild(marqueeWrap);
|
|
880
|
-
|
|
881
|
-
var promoText = document.createElement("div");
|
|
882
|
-
promoText.className = "dm-picker-mates-promo-text";
|
|
883
|
-
promoText.textContent = "Specialist AI teammates with long-term memory across sessions. Mention with @ for design, engineering, strategy, or marketing, or build your own.";
|
|
884
|
-
promo.appendChild(promoText);
|
|
885
|
-
|
|
886
|
-
var cta = document.createElement("button");
|
|
887
|
-
cta.type = "button";
|
|
888
|
-
cta.className = "dm-picker-mates-promo-cta";
|
|
889
|
-
cta.textContent = "Click here to enable Mates";
|
|
890
|
-
cta.addEventListener("click", function () {
|
|
891
|
-
closeDmUserPicker();
|
|
892
|
-
openUserSettings('us-mates');
|
|
893
|
-
});
|
|
894
|
-
promo.appendChild(cta);
|
|
895
|
-
|
|
896
|
-
picker.appendChild(promo);
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
if (matesEnabled) {
|
|
900
|
-
renderMatesEnabledSection();
|
|
901
|
-
renderMatesList("");
|
|
902
|
-
renderPickerList("");
|
|
903
|
-
searchInput.addEventListener("input", function () {
|
|
904
|
-
var val = searchInput.value;
|
|
905
|
-
renderMatesList(val);
|
|
906
|
-
renderPickerList(val);
|
|
907
|
-
});
|
|
908
|
-
} else {
|
|
909
|
-
renderMatesDisabledLayout();
|
|
910
|
-
renderPickerList("");
|
|
911
|
-
searchInput.addEventListener("input", function () {
|
|
912
|
-
renderPickerList(searchInput.value);
|
|
913
|
-
});
|
|
914
|
-
}
|
|
410
|
+
var usersLabel = document.createElement("div");
|
|
411
|
+
usersLabel.className = "dm-user-picker-section";
|
|
412
|
+
usersLabel.textContent = "Users";
|
|
413
|
+
picker.appendChild(usersLabel);
|
|
414
|
+
picker.appendChild(listEl);
|
|
415
|
+
renderPickerList("");
|
|
416
|
+
searchInput.addEventListener("input", function () {
|
|
417
|
+
renderPickerList(searchInput.value);
|
|
418
|
+
});
|
|
915
419
|
|
|
916
420
|
// Focus search
|
|
917
421
|
setTimeout(function () { searchInput.focus(); }, 50);
|