clay-server 2.20.0-beta.1 → 2.20.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/builtin-mates.js +360 -0
- package/lib/mates.js +108 -0
- package/lib/project.js +53 -44
- package/lib/public/app.js +91 -55
- package/lib/public/css/icon-strip.css +55 -2
- package/lib/public/css/input.css +50 -30
- package/lib/public/index.html +1 -0
- package/lib/public/mates/ally.png +0 -0
- package/lib/public/mates/sage.jpg +0 -0
- package/lib/public/mates/scout.png +0 -0
- package/lib/public/modules/input.js +147 -13
- package/lib/public/modules/sidebar.js +223 -15
- package/lib/sdk-bridge.js +8 -26
- package/lib/server.js +125 -7
- package/lib/users.js +63 -0
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ var slashActiveIdx = -1;
|
|
|
13
13
|
var slashFiltered = [];
|
|
14
14
|
var isComposing = false;
|
|
15
15
|
var isRemoteInput = false;
|
|
16
|
+
var scheduleDelayMs = 0; // 0 = no schedule, >0 = delay in ms
|
|
16
17
|
|
|
17
18
|
export function hasSendableContent() {
|
|
18
19
|
return !!(
|
|
@@ -23,6 +24,36 @@ export function hasSendableContent() {
|
|
|
23
24
|
);
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
export function getScheduleDelay() {
|
|
28
|
+
return scheduleDelayMs;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function clearScheduleDelay() {
|
|
32
|
+
scheduleDelayMs = 0;
|
|
33
|
+
var btn = document.getElementById("schedule-btn");
|
|
34
|
+
if (btn) {
|
|
35
|
+
btn.classList.remove("schedule-active", "schedule-expanded");
|
|
36
|
+
var lbl = btn.querySelector(".schedule-delay-label");
|
|
37
|
+
if (lbl) lbl.remove();
|
|
38
|
+
var inp = btn.querySelector(".schedule-inline-input");
|
|
39
|
+
if (inp) inp.remove();
|
|
40
|
+
btn.title = "Schedule message";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function setScheduleBtnDisabled(disabled) {
|
|
45
|
+
var btn = document.getElementById("schedule-btn");
|
|
46
|
+
if (!btn) return;
|
|
47
|
+
btn.disabled = disabled;
|
|
48
|
+
if (disabled) {
|
|
49
|
+
btn.style.opacity = "0.3";
|
|
50
|
+
btn.style.pointerEvents = "none";
|
|
51
|
+
} else {
|
|
52
|
+
btn.style.opacity = "";
|
|
53
|
+
btn.style.pointerEvents = "";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
26
57
|
export var builtinCommands = [
|
|
27
58
|
{ name: "clear", desc: "Clear conversation" },
|
|
28
59
|
{ name: "context", desc: "Context window usage" },
|
|
@@ -131,19 +162,17 @@ export function sendMessage() {
|
|
|
131
162
|
|
|
132
163
|
var pastes = pendingPastes.map(function (p) { return p.text; });
|
|
133
164
|
|
|
134
|
-
//
|
|
135
|
-
if (
|
|
136
|
-
var resetsAt =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
165
|
+
// Scheduled message: queue message with timer delay
|
|
166
|
+
if (scheduleDelayMs > 0) {
|
|
167
|
+
var resetsAt = Date.now() + scheduleDelayMs;
|
|
168
|
+
ctx.ws.send(JSON.stringify({ type: "schedule_message", text: text || "", resetsAt: resetsAt }));
|
|
169
|
+
clearScheduleDelay();
|
|
170
|
+
ctx.inputEl.value = "";
|
|
171
|
+
sendInputSync();
|
|
172
|
+
clearPendingImages();
|
|
173
|
+
autoResize();
|
|
174
|
+
ctx.inputEl.focus();
|
|
175
|
+
return;
|
|
147
176
|
}
|
|
148
177
|
|
|
149
178
|
ctx.addUserMessage(text, images.length > 0 ? images : null, pastes.length > 0 ? pastes : null);
|
|
@@ -578,6 +607,111 @@ export function initInput(_ctx) {
|
|
|
578
607
|
});
|
|
579
608
|
}
|
|
580
609
|
|
|
610
|
+
// Schedule button — inline expand with minute input
|
|
611
|
+
var scheduleBtn = document.getElementById("schedule-btn");
|
|
612
|
+
var scheduleInlineInput = null;
|
|
613
|
+
var scheduleInlineLabel = null;
|
|
614
|
+
var scheduleOutsideHandler = null;
|
|
615
|
+
|
|
616
|
+
function formatDelayLabel(ms) {
|
|
617
|
+
var mins = Math.round(ms / 60000);
|
|
618
|
+
if (mins < 60) return mins + "m";
|
|
619
|
+
var hrs = Math.floor(mins / 60);
|
|
620
|
+
var rem = mins % 60;
|
|
621
|
+
return rem > 0 ? hrs + "h " + rem + "m" : hrs + "h";
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function collapseScheduleBtn() {
|
|
625
|
+
if (!scheduleBtn) return;
|
|
626
|
+
scheduleBtn.classList.remove("schedule-expanded");
|
|
627
|
+
if (scheduleInlineInput) { scheduleInlineInput.remove(); scheduleInlineInput = null; }
|
|
628
|
+
if (scheduleInlineLabel) { scheduleInlineLabel.remove(); scheduleInlineLabel = null; }
|
|
629
|
+
if (scheduleOutsideHandler) {
|
|
630
|
+
document.removeEventListener("mousedown", scheduleOutsideHandler);
|
|
631
|
+
scheduleOutsideHandler = null;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function setScheduleDelay(ms) {
|
|
636
|
+
scheduleDelayMs = ms;
|
|
637
|
+
if (!scheduleBtn) return;
|
|
638
|
+
collapseScheduleBtn();
|
|
639
|
+
if (ms > 0) {
|
|
640
|
+
scheduleBtn.classList.add("schedule-active", "schedule-expanded");
|
|
641
|
+
scheduleBtn.title = "Scheduled: " + formatDelayLabel(ms) + " (click to clear)";
|
|
642
|
+
scheduleInlineLabel = document.createElement("span");
|
|
643
|
+
scheduleInlineLabel.className = "schedule-delay-label";
|
|
644
|
+
scheduleInlineLabel.textContent = formatDelayLabel(ms);
|
|
645
|
+
scheduleBtn.appendChild(scheduleInlineLabel);
|
|
646
|
+
} else {
|
|
647
|
+
scheduleBtn.classList.remove("schedule-active", "schedule-expanded");
|
|
648
|
+
scheduleBtn.title = "Schedule message";
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function expandScheduleInput() {
|
|
653
|
+
if (!scheduleBtn) return;
|
|
654
|
+
scheduleBtn.classList.add("schedule-expanded");
|
|
655
|
+
scheduleInlineInput = document.createElement("input");
|
|
656
|
+
scheduleInlineInput.type = "number";
|
|
657
|
+
scheduleInlineInput.min = "1";
|
|
658
|
+
scheduleInlineInput.max = "1440";
|
|
659
|
+
scheduleInlineInput.placeholder = "min";
|
|
660
|
+
scheduleInlineInput.className = "schedule-inline-input";
|
|
661
|
+
scheduleBtn.appendChild(scheduleInlineInput);
|
|
662
|
+
|
|
663
|
+
setTimeout(function () { scheduleInlineInput.focus(); }, 0);
|
|
664
|
+
|
|
665
|
+
scheduleInlineInput.addEventListener("click", function (e) { e.stopPropagation(); });
|
|
666
|
+
scheduleInlineInput.addEventListener("keydown", function (e) {
|
|
667
|
+
if (e.key === "Enter") {
|
|
668
|
+
e.preventDefault();
|
|
669
|
+
var val = parseInt(scheduleInlineInput.value, 10);
|
|
670
|
+
if (val >= 1 && val <= 1440) {
|
|
671
|
+
setScheduleDelay(val * 60000);
|
|
672
|
+
} else {
|
|
673
|
+
collapseScheduleBtn();
|
|
674
|
+
}
|
|
675
|
+
} else if (e.key === "Escape") {
|
|
676
|
+
collapseScheduleBtn();
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
// Close on outside click
|
|
681
|
+
setTimeout(function () {
|
|
682
|
+
scheduleOutsideHandler = function (ev) {
|
|
683
|
+
if (!scheduleBtn.contains(ev.target)) {
|
|
684
|
+
if (scheduleInlineInput) {
|
|
685
|
+
var val = parseInt(scheduleInlineInput.value, 10);
|
|
686
|
+
if (val >= 1 && val <= 1440) {
|
|
687
|
+
setScheduleDelay(val * 60000);
|
|
688
|
+
} else {
|
|
689
|
+
collapseScheduleBtn();
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
document.removeEventListener("mousedown", scheduleOutsideHandler);
|
|
693
|
+
scheduleOutsideHandler = null;
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
document.addEventListener("mousedown", scheduleOutsideHandler);
|
|
697
|
+
}, 0);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (scheduleBtn) {
|
|
701
|
+
scheduleBtn.addEventListener("click", function (e) {
|
|
702
|
+
e.stopPropagation();
|
|
703
|
+
if (scheduleDelayMs > 0) {
|
|
704
|
+
setScheduleDelay(0);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (scheduleInlineInput) {
|
|
708
|
+
collapseScheduleBtn();
|
|
709
|
+
} else {
|
|
710
|
+
expandScheduleInput();
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
|
|
581
715
|
// Paste handler
|
|
582
716
|
document.addEventListener("paste", function (e) {
|
|
583
717
|
// Don't intercept paste when typing in modals or other non-chat inputs
|
|
@@ -961,7 +961,19 @@ function renderSheetSessions(listEl) {
|
|
|
961
961
|
})(cachedProjectList[ci]);
|
|
962
962
|
}
|
|
963
963
|
|
|
964
|
-
|
|
964
|
+
var favoriteChipMates = cachedMates.filter(function (m) {
|
|
965
|
+
if (cachedDmRemovedUsers[m.id]) return false;
|
|
966
|
+
if (cachedDmFavorites.indexOf(m.id) !== -1) return true;
|
|
967
|
+
if (cachedDmUnread[m.id] && cachedDmUnread[m.id] > 0) return true;
|
|
968
|
+
return false;
|
|
969
|
+
});
|
|
970
|
+
var sortedChipMates = favoriteChipMates.sort(function (a, b) {
|
|
971
|
+
var aBuiltin = a.builtinKey ? 1 : 0;
|
|
972
|
+
var bBuiltin = b.builtinKey ? 1 : 0;
|
|
973
|
+
if (aBuiltin !== bBuiltin) return bBuiltin - aBuiltin;
|
|
974
|
+
return (a.createdAt || 0) - (b.createdAt || 0);
|
|
975
|
+
});
|
|
976
|
+
for (var mi = 0; mi < sortedChipMates.length; mi++) {
|
|
965
977
|
(function (mate) {
|
|
966
978
|
var mp = mate.profile || {};
|
|
967
979
|
var chip = document.createElement("button");
|
|
@@ -1000,7 +1012,7 @@ function renderSheetSessions(listEl) {
|
|
|
1000
1012
|
}
|
|
1001
1013
|
|
|
1002
1014
|
chips.push(chip);
|
|
1003
|
-
})(
|
|
1015
|
+
})(sortedChipMates[mi]);
|
|
1004
1016
|
}
|
|
1005
1017
|
|
|
1006
1018
|
for (var i = 0; i < chips.length; i++) {
|
|
@@ -2419,15 +2431,13 @@ function showMateCtxMenu(anchorEl, mate) {
|
|
|
2419
2431
|
menu.appendChild(editItem);
|
|
2420
2432
|
|
|
2421
2433
|
var removeItem = document.createElement("button");
|
|
2422
|
-
removeItem.className = "project-ctx-item
|
|
2423
|
-
removeItem.innerHTML = iconHtml("
|
|
2434
|
+
removeItem.className = "project-ctx-item";
|
|
2435
|
+
removeItem.innerHTML = iconHtml("star-off") + " <span>Remove from favorites</span>";
|
|
2424
2436
|
removeItem.addEventListener("click", function (e) {
|
|
2425
2437
|
e.stopPropagation();
|
|
2426
|
-
var iconRect = anchorEl.getBoundingClientRect();
|
|
2427
|
-
spawnDustParticles(iconRect.left + iconRect.width / 2, iconRect.top + iconRect.height / 2);
|
|
2428
2438
|
closeUserCtxMenu();
|
|
2429
2439
|
if (ctx.sendWs) {
|
|
2430
|
-
ctx.sendWs({ type: "
|
|
2440
|
+
ctx.sendWs({ type: "dm_remove_favorite", targetUserId: mate.id });
|
|
2431
2441
|
}
|
|
2432
2442
|
});
|
|
2433
2443
|
menu.appendChild(removeItem);
|
|
@@ -3800,8 +3810,20 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
3800
3810
|
}
|
|
3801
3811
|
}
|
|
3802
3812
|
|
|
3803
|
-
// Render mates
|
|
3804
|
-
|
|
3813
|
+
// Render mates (only favorites, built-in first, then user-created)
|
|
3814
|
+
var favoriteMates = cachedMates.filter(function (m) {
|
|
3815
|
+
if (cachedDmRemovedUsers[m.id]) return false;
|
|
3816
|
+
if (cachedDmFavorites.indexOf(m.id) !== -1) return true;
|
|
3817
|
+
if (cachedDmUnread[m.id] && cachedDmUnread[m.id] > 0) return true;
|
|
3818
|
+
return false;
|
|
3819
|
+
});
|
|
3820
|
+
var sortedMates = favoriteMates.sort(function (a, b) {
|
|
3821
|
+
var aBuiltin = a.builtinKey ? 1 : 0;
|
|
3822
|
+
var bBuiltin = b.builtinKey ? 1 : 0;
|
|
3823
|
+
if (aBuiltin !== bBuiltin) return bBuiltin - aBuiltin;
|
|
3824
|
+
return (a.createdAt || 0) - (b.createdAt || 0);
|
|
3825
|
+
});
|
|
3826
|
+
for (var mi = 0; mi < sortedMates.length; mi++) {
|
|
3805
3827
|
(function (mate) {
|
|
3806
3828
|
var mp = mate.profile || {};
|
|
3807
3829
|
var mateSlug = "mate-" + mate.id;
|
|
@@ -3876,7 +3898,7 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
3876
3898
|
});
|
|
3877
3899
|
|
|
3878
3900
|
container.appendChild(el);
|
|
3879
|
-
})(
|
|
3901
|
+
})(sortedMates[mi]);
|
|
3880
3902
|
}
|
|
3881
3903
|
|
|
3882
3904
|
// Show container if we have mates even with no other users
|
|
@@ -3913,13 +3935,12 @@ function toggleDmUserPicker(anchorEl) {
|
|
|
3913
3935
|
var searchInput = document.createElement("input");
|
|
3914
3936
|
searchInput.className = "dm-user-picker-search";
|
|
3915
3937
|
searchInput.type = "text";
|
|
3916
|
-
searchInput.placeholder = "Search users...";
|
|
3938
|
+
searchInput.placeholder = "Search mates and users...";
|
|
3917
3939
|
picker.appendChild(searchInput);
|
|
3918
3940
|
|
|
3919
|
-
//
|
|
3941
|
+
// User list element (appended later, after USERS label)
|
|
3920
3942
|
var listEl = document.createElement("div");
|
|
3921
3943
|
listEl.className = "dm-user-picker-list";
|
|
3922
|
-
picker.appendChild(listEl);
|
|
3923
3944
|
|
|
3924
3945
|
// Position the picker above the + button
|
|
3925
3946
|
document.body.appendChild(picker);
|
|
@@ -3976,10 +3997,193 @@ function toggleDmUserPicker(anchorEl) {
|
|
|
3976
3997
|
}
|
|
3977
3998
|
}
|
|
3978
3999
|
|
|
4000
|
+
// --- MATES section ---
|
|
4001
|
+
var matesSectionLabel = document.createElement("div");
|
|
4002
|
+
matesSectionLabel.className = "dm-user-picker-section";
|
|
4003
|
+
matesSectionLabel.textContent = "Mates";
|
|
4004
|
+
picker.appendChild(matesSectionLabel);
|
|
4005
|
+
|
|
4006
|
+
var matesListEl = document.createElement("div");
|
|
4007
|
+
matesListEl.className = "dm-user-picker-list dm-mates-list";
|
|
4008
|
+
picker.appendChild(matesListEl);
|
|
4009
|
+
|
|
4010
|
+
// Update scroll gradient hint
|
|
4011
|
+
function updateMatesScrollHint() {
|
|
4012
|
+
var isOverflow = matesListEl.scrollHeight > matesListEl.clientHeight + 2;
|
|
4013
|
+
if (!isOverflow) {
|
|
4014
|
+
matesListEl.classList.add("no-overflow");
|
|
4015
|
+
matesListEl.classList.remove("scrolled-bottom");
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
4018
|
+
matesListEl.classList.remove("no-overflow");
|
|
4019
|
+
var atBottom = matesListEl.scrollTop + matesListEl.clientHeight >= matesListEl.scrollHeight - 4;
|
|
4020
|
+
if (atBottom) {
|
|
4021
|
+
matesListEl.classList.add("scrolled-bottom");
|
|
4022
|
+
} else {
|
|
4023
|
+
matesListEl.classList.remove("scrolled-bottom");
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
matesListEl.addEventListener("scroll", updateMatesScrollHint);
|
|
4027
|
+
|
|
4028
|
+
function renderMatesList(filter) {
|
|
4029
|
+
matesListEl.innerHTML = "";
|
|
4030
|
+
var allMates = cachedMates || [];
|
|
4031
|
+
if (filter) {
|
|
4032
|
+
var lf = filter.toLowerCase();
|
|
4033
|
+
allMates = allMates.filter(function (m) {
|
|
4034
|
+
var name = (m.profile && m.profile.displayName) || m.name || "";
|
|
4035
|
+
return name.toLowerCase().indexOf(lf) !== -1;
|
|
4036
|
+
});
|
|
4037
|
+
}
|
|
4038
|
+
// Build unified list: installed builtins, deleted builtins, user-created
|
|
4039
|
+
var availBuiltins = (ctx.availableBuiltins && ctx.availableBuiltins()) || [];
|
|
4040
|
+
var entries = [];
|
|
4041
|
+
// 1. Installed builtin mates
|
|
4042
|
+
for (var si = 0; si < allMates.length; si++) {
|
|
4043
|
+
if (allMates[si].builtinKey) entries.push({ type: "mate", data: allMates[si] });
|
|
4044
|
+
}
|
|
4045
|
+
// 2. Deleted builtins (only when not filtering)
|
|
4046
|
+
if (!filter) {
|
|
4047
|
+
for (var di = 0; di < availBuiltins.length; di++) {
|
|
4048
|
+
entries.push({ type: "deleted", data: availBuiltins[di] });
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
// 3. User-created mates
|
|
4052
|
+
var userMates = allMates.filter(function (m) { return !m.builtinKey; });
|
|
4053
|
+
userMates.sort(function (a, b) { return (a.createdAt || 0) - (b.createdAt || 0); });
|
|
4054
|
+
for (var ui = 0; ui < userMates.length; ui++) {
|
|
4055
|
+
entries.push({ type: "mate", data: userMates[ui] });
|
|
4056
|
+
}
|
|
4057
|
+
|
|
4058
|
+
for (var i = 0; i < entries.length; i++) {
|
|
4059
|
+
var entry = entries[i];
|
|
4060
|
+
if (entry.type === "deleted") {
|
|
4061
|
+
// Deleted builtin: show with "+ Add" button
|
|
4062
|
+
(function (b) {
|
|
4063
|
+
var bItem = document.createElement("div");
|
|
4064
|
+
bItem.className = "dm-user-picker-item dm-user-picker-builtin-item";
|
|
4065
|
+
bItem.style.opacity = "0.5";
|
|
4066
|
+
var bAv = document.createElement("img");
|
|
4067
|
+
bAv.className = "dm-user-picker-avatar";
|
|
4068
|
+
bAv.src = b.avatarCustom || "";
|
|
4069
|
+
bAv.alt = b.displayName;
|
|
4070
|
+
bItem.appendChild(bAv);
|
|
4071
|
+
var bNameWrap = document.createElement("div");
|
|
4072
|
+
bNameWrap.style.cssText = "flex:1;min-width:0;";
|
|
4073
|
+
var bName = document.createElement("span");
|
|
4074
|
+
bName.className = "dm-user-picker-name";
|
|
4075
|
+
bName.textContent = b.displayName;
|
|
4076
|
+
bNameWrap.appendChild(bName);
|
|
4077
|
+
var bBio = document.createElement("div");
|
|
4078
|
+
bBio.style.cssText = "font-size:11px;color:var(--text-dimmer);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;";
|
|
4079
|
+
bBio.textContent = "Deleted";
|
|
4080
|
+
bNameWrap.appendChild(bBio);
|
|
4081
|
+
bItem.appendChild(bNameWrap);
|
|
4082
|
+
var bAddBtn = document.createElement("button");
|
|
4083
|
+
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;";
|
|
4084
|
+
bAddBtn.textContent = "+ Add";
|
|
4085
|
+
bAddBtn.title = "Re-add " + b.displayName;
|
|
4086
|
+
bAddBtn.addEventListener("click", function (e) {
|
|
4087
|
+
e.stopPropagation();
|
|
4088
|
+
if (ctx.sendWs) ctx.sendWs({ type: "mate_readd_builtin", builtinKey: b.key });
|
|
4089
|
+
closeDmUserPicker();
|
|
4090
|
+
});
|
|
4091
|
+
bItem.appendChild(bAddBtn);
|
|
4092
|
+
bItem.addEventListener("click", function () {
|
|
4093
|
+
if (ctx.sendWs) ctx.sendWs({ type: "mate_readd_builtin", builtinKey: b.key });
|
|
4094
|
+
closeDmUserPicker();
|
|
4095
|
+
});
|
|
4096
|
+
matesListEl.appendChild(bItem);
|
|
4097
|
+
})(entry.data);
|
|
4098
|
+
} else {
|
|
4099
|
+
// Normal mate
|
|
4100
|
+
(function (m) {
|
|
4101
|
+
var mp = m.profile || {};
|
|
4102
|
+
var isFav = cachedDmFavorites.indexOf(m.id) !== -1;
|
|
4103
|
+
var item = document.createElement("div");
|
|
4104
|
+
item.className = "dm-user-picker-item";
|
|
4105
|
+
if (isFav) item.classList.add("dm-picker-fav");
|
|
4106
|
+
var av = document.createElement("img");
|
|
4107
|
+
av.className = "dm-user-picker-avatar";
|
|
4108
|
+
av.src = mateAvatarUrl(m, 28);
|
|
4109
|
+
av.alt = mp.displayName || m.name || "Mate";
|
|
4110
|
+
item.appendChild(av);
|
|
4111
|
+
var nameWrap = document.createElement("div");
|
|
4112
|
+
nameWrap.style.cssText = "flex:1;min-width:0;";
|
|
4113
|
+
var name = document.createElement("span");
|
|
4114
|
+
name.className = "dm-user-picker-name";
|
|
4115
|
+
name.textContent = mp.displayName || m.name || "Mate";
|
|
4116
|
+
nameWrap.appendChild(name);
|
|
4117
|
+
if (m.bio) {
|
|
4118
|
+
var bio = document.createElement("div");
|
|
4119
|
+
bio.style.cssText = "font-size:11px;color:var(--text-dimmer);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;";
|
|
4120
|
+
bio.textContent = m.bio;
|
|
4121
|
+
nameWrap.appendChild(bio);
|
|
4122
|
+
}
|
|
4123
|
+
item.appendChild(nameWrap);
|
|
4124
|
+
// Delete button with inline confirm
|
|
4125
|
+
var delBtn = document.createElement("button");
|
|
4126
|
+
delBtn.className = "dm-picker-del-btn";
|
|
4127
|
+
delBtn.innerHTML = iconHtml("trash-2");
|
|
4128
|
+
delBtn.title = "Delete mate";
|
|
4129
|
+
delBtn.addEventListener("click", function (e) {
|
|
4130
|
+
e.stopPropagation();
|
|
4131
|
+
var origHtml = item.innerHTML;
|
|
4132
|
+
item.innerHTML = "";
|
|
4133
|
+
item.style.justifyContent = "center";
|
|
4134
|
+
item.style.gap = "6px";
|
|
4135
|
+
var confirmMsg = document.createElement("span");
|
|
4136
|
+
confirmMsg.style.cssText = "font-size:12px;color:var(--text-dimmer);";
|
|
4137
|
+
confirmMsg.textContent = m.builtinKey ? "Delete? You can re-add later." : "Delete permanently?";
|
|
4138
|
+
item.appendChild(confirmMsg);
|
|
4139
|
+
var yesBtn = document.createElement("button");
|
|
4140
|
+
yesBtn.style.cssText = "border:none;background:var(--danger,#e74c3c);color:#fff;padding:3px 10px;border-radius:4px;font-size:12px;cursor:pointer;";
|
|
4141
|
+
yesBtn.textContent = "Delete";
|
|
4142
|
+
yesBtn.addEventListener("click", function (e2) {
|
|
4143
|
+
e2.stopPropagation();
|
|
4144
|
+
if (ctx.sendWs) ctx.sendWs({ type: "mate_delete", mateId: m.id });
|
|
4145
|
+
closeDmUserPicker();
|
|
4146
|
+
});
|
|
4147
|
+
item.appendChild(yesBtn);
|
|
4148
|
+
var noBtn = document.createElement("button");
|
|
4149
|
+
noBtn.style.cssText = "border:1px solid var(--border);background:none;color:var(--text);padding:3px 10px;border-radius:4px;font-size:12px;cursor:pointer;";
|
|
4150
|
+
noBtn.textContent = "Cancel";
|
|
4151
|
+
noBtn.addEventListener("click", function (e2) {
|
|
4152
|
+
e2.stopPropagation();
|
|
4153
|
+
item.innerHTML = origHtml;
|
|
4154
|
+
item.style.justifyContent = "";
|
|
4155
|
+
item.style.gap = "";
|
|
4156
|
+
refreshIcons();
|
|
4157
|
+
});
|
|
4158
|
+
item.appendChild(noBtn);
|
|
4159
|
+
});
|
|
4160
|
+
item.appendChild(delBtn);
|
|
4161
|
+
item.addEventListener("click", function () {
|
|
4162
|
+
if (ctx.openDm) ctx.openDm(m.id);
|
|
4163
|
+
if (!isFav && ctx.sendWs) ctx.sendWs({ type: "dm_add_favorite", targetUserId: m.id });
|
|
4164
|
+
closeDmUserPicker();
|
|
4165
|
+
});
|
|
4166
|
+
matesListEl.appendChild(item);
|
|
4167
|
+
})(entry.data);
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
|
|
4171
|
+
if (entries.length === 0 && filter) {
|
|
4172
|
+
var emptyEl = document.createElement("div");
|
|
4173
|
+
emptyEl.className = "dm-user-picker-empty";
|
|
4174
|
+
emptyEl.textContent = "No mates found";
|
|
4175
|
+
matesListEl.appendChild(emptyEl);
|
|
4176
|
+
}
|
|
4177
|
+
refreshIcons();
|
|
4178
|
+
requestAnimationFrame(updateMatesScrollHint);
|
|
4179
|
+
}
|
|
4180
|
+
|
|
3979
4181
|
// Create Mate option
|
|
3980
4182
|
var createMateEl = document.createElement("div");
|
|
3981
4183
|
createMateEl.className = "dm-user-picker-create-mate";
|
|
3982
|
-
|
|
4184
|
+
var hasCustomMates = (cachedMates || []).some(function (m) { return !m.builtinKey; });
|
|
4185
|
+
var createMateLabel = hasCustomMates ? "Create a Mate" : "Create a Mate for what you're doing";
|
|
4186
|
+
createMateEl.innerHTML = iconHtml("bot") + " <span>" + createMateLabel + "</span>";
|
|
3983
4187
|
createMateEl.addEventListener("click", function () {
|
|
3984
4188
|
closeDmUserPicker();
|
|
3985
4189
|
if (ctx.openMateWizard) ctx.openMateWizard();
|
|
@@ -3997,10 +4201,14 @@ function toggleDmUserPicker(anchorEl) {
|
|
|
3997
4201
|
sectionLabel.className = "dm-user-picker-section";
|
|
3998
4202
|
sectionLabel.textContent = "Users";
|
|
3999
4203
|
picker.appendChild(sectionLabel);
|
|
4204
|
+
picker.appendChild(listEl);
|
|
4000
4205
|
|
|
4206
|
+
renderMatesList("");
|
|
4001
4207
|
renderPickerList("");
|
|
4002
4208
|
searchInput.addEventListener("input", function () {
|
|
4003
|
-
|
|
4209
|
+
var val = searchInput.value;
|
|
4210
|
+
renderMatesList(val);
|
|
4211
|
+
renderPickerList(val);
|
|
4004
4212
|
});
|
|
4005
4213
|
|
|
4006
4214
|
// Focus search
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -999,23 +999,14 @@ function createSDKBridge(opts) {
|
|
|
999
999
|
var workerACEnabled = session.onQueryComplete || (typeof opts.getAutoContinueSetting === "function" && opts.getAutoContinueSetting(session));
|
|
1000
1000
|
if (session.rateLimitResetsAt && session.rateLimitResetsAt > Date.now()
|
|
1001
1001
|
&& workerACEnabled && !session.destroying) {
|
|
1002
|
-
var wacDelay = session.rateLimitResetsAt - Date.now() + 3000;
|
|
1003
1002
|
var wacResetsAt = session.rateLimitResetsAt;
|
|
1004
1003
|
session.rateLimitResetsAt = null;
|
|
1005
1004
|
session.rateLimitAutoContinuePending = true;
|
|
1006
1005
|
workerDidScheduleAC = true;
|
|
1007
|
-
console.log("[sdk-bridge] Rate limited (worker), scheduling auto-continue
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
session.rateLimitAutoContinuePending = false;
|
|
1012
|
-
if (session.destroying) return;
|
|
1013
|
-
console.log("[sdk-bridge] Auto-continue (worker) firing for session " + session.localId);
|
|
1014
|
-
session.isProcessing = true;
|
|
1015
|
-
onProcessingChanged();
|
|
1016
|
-
sendAndRecord(session, { type: "auto_continue_fired" });
|
|
1017
|
-
startQuery(session, "continue", null, session.lastLinuxUser || null);
|
|
1018
|
-
}, wacDelay);
|
|
1006
|
+
console.log("[sdk-bridge] Rate limited (worker), scheduling auto-continue via scheduleMessage for session " + session.localId);
|
|
1007
|
+
if (typeof opts.scheduleMessage === "function") {
|
|
1008
|
+
opts.scheduleMessage(session, "continue", wacResetsAt);
|
|
1009
|
+
}
|
|
1019
1010
|
}
|
|
1020
1011
|
if (session.onQueryComplete && !workerDidScheduleAC) {
|
|
1021
1012
|
try { session.onQueryComplete(session); } catch (err) {
|
|
@@ -1439,23 +1430,14 @@ function createSDKBridge(opts) {
|
|
|
1439
1430
|
var acEnabled = session.onQueryComplete || (typeof opts.getAutoContinueSetting === "function" && opts.getAutoContinueSetting(session));
|
|
1440
1431
|
if (session.rateLimitResetsAt && session.rateLimitResetsAt > Date.now()
|
|
1441
1432
|
&& acEnabled && !session.destroying) {
|
|
1442
|
-
var acDelay = session.rateLimitResetsAt - Date.now() + 3000;
|
|
1443
1433
|
var acResetsAt = session.rateLimitResetsAt;
|
|
1444
1434
|
session.rateLimitResetsAt = null;
|
|
1445
1435
|
session.rateLimitAutoContinuePending = true;
|
|
1446
1436
|
didScheduleAutoContinue = true;
|
|
1447
|
-
console.log("[sdk-bridge] Rate limited, scheduling auto-continue
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
session.rateLimitAutoContinuePending = false;
|
|
1452
|
-
if (session.destroying) return;
|
|
1453
|
-
console.log("[sdk-bridge] Auto-continue firing for session " + session.localId);
|
|
1454
|
-
session.isProcessing = true;
|
|
1455
|
-
onProcessingChanged();
|
|
1456
|
-
sendAndRecord(session, { type: "auto_continue_fired" });
|
|
1457
|
-
startQuery(session, "continue", null, session.lastLinuxUser || null);
|
|
1458
|
-
}, acDelay);
|
|
1437
|
+
console.log("[sdk-bridge] Rate limited, scheduling auto-continue via scheduleMessage for session " + session.localId);
|
|
1438
|
+
if (typeof opts.scheduleMessage === "function") {
|
|
1439
|
+
opts.scheduleMessage(session, "continue", acResetsAt);
|
|
1440
|
+
}
|
|
1459
1441
|
}
|
|
1460
1442
|
|
|
1461
1443
|
// Ralph Loop: notify completion so loop orchestrator can proceed
|