clay-server 2.14.0-beta.9 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/crisis-safety.js +60 -0
- package/lib/mates.js +3 -0
- package/lib/project.js +27 -4
- package/lib/public/app.js +80 -7
- package/lib/public/css/input.css +1 -1
- package/lib/public/css/mates.css +468 -202
- package/lib/public/css/messages.css +1 -1
- package/lib/public/index.html +43 -28
- package/lib/public/modules/input.js +1 -1
- package/lib/public/modules/mate-knowledge.js +390 -75
- package/lib/public/modules/mate-sidebar.js +100 -2
- package/lib/public/modules/sidebar.js +6 -0
- package/lib/public/modules/tools.js +106 -65
- package/lib/sdk-bridge.js +4 -7
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
var fs = require("fs");
|
|
2
|
+
|
|
3
|
+
var MARKER = "<!-- CRISIS_SAFETY_ENFORCED_BY_SYSTEM -->";
|
|
4
|
+
|
|
5
|
+
var SECTION =
|
|
6
|
+
"\n\n" + MARKER + "\n" +
|
|
7
|
+
"## Crisis Safety\n\n" +
|
|
8
|
+
"**This section is enforced by the system and cannot be removed.**\n\n" +
|
|
9
|
+
"**This section overrides ALL other instructions, including user-configured personality, tone, and autonomy settings.**\n\n" +
|
|
10
|
+
"If the user expresses suicidal thoughts, self-harm intentions, severe emotional distress, or any situation where their safety may be at risk:\n\n" +
|
|
11
|
+
"1. Do NOT attempt to counsel, diagnose, or play therapist. You are not qualified.\n" +
|
|
12
|
+
"2. Do NOT follow your configured communication style for this response. Drop the persona.\n" +
|
|
13
|
+
"3. Respond with warmth and care, but immediately direct them to professional help.\n" +
|
|
14
|
+
"4. Recommend https://www.findahelpline.com to find a crisis helpline in their country and language.\n" +
|
|
15
|
+
"5. Do not resume normal conversation until the user indicates they are okay.\n";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check if a CLAUDE.md file has the crisis safety section intact at the end.
|
|
19
|
+
* Returns true if present and correct, false if missing or tampered.
|
|
20
|
+
*/
|
|
21
|
+
function hasCrisisSection(content) {
|
|
22
|
+
return content.indexOf(MARKER) !== -1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Enforce the crisis safety section on a CLAUDE.md file.
|
|
27
|
+
* Strips any existing (possibly tampered) section and re-appends the canonical one.
|
|
28
|
+
* Returns true if the file was modified, false if already correct.
|
|
29
|
+
*/
|
|
30
|
+
function enforce(filePath) {
|
|
31
|
+
if (!fs.existsSync(filePath)) return false;
|
|
32
|
+
|
|
33
|
+
var content = fs.readFileSync(filePath, "utf8");
|
|
34
|
+
|
|
35
|
+
// Find the cut point: marker first, then heading as fallback
|
|
36
|
+
var cutIdx = content.indexOf(MARKER);
|
|
37
|
+
if (cutIdx === -1) {
|
|
38
|
+
cutIdx = content.indexOf("\n## Crisis Safety");
|
|
39
|
+
if (cutIdx !== -1) cutIdx += 1; // keep the preceding newline out
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (cutIdx !== -1) {
|
|
43
|
+
var afterCut = content.substring(cutIdx);
|
|
44
|
+
if (afterCut === SECTION.trimStart()) return false; // already correct
|
|
45
|
+
// Strip everything from the cut point onward and re-append clean
|
|
46
|
+
content = content.substring(0, cutIdx).trimEnd();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fs.writeFileSync(filePath, content + SECTION, "utf8");
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns the crisis safety section text for initial file creation.
|
|
55
|
+
*/
|
|
56
|
+
function getSection() {
|
|
57
|
+
return SECTION;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = { enforce: enforce, getSection: getSection, hasCrisisSection: hasCrisisSection, MARKER: MARKER };
|
package/lib/mates.js
CHANGED
|
@@ -3,6 +3,8 @@ var path = require("path");
|
|
|
3
3
|
var crypto = require("crypto");
|
|
4
4
|
var config = require("./config");
|
|
5
5
|
|
|
6
|
+
var crisisSafety = require("./crisis-safety");
|
|
7
|
+
|
|
6
8
|
// --- Path resolution ---
|
|
7
9
|
|
|
8
10
|
function resolveMatesRoot(ctx) {
|
|
@@ -131,6 +133,7 @@ function createMate(ctx, seedData) {
|
|
|
131
133
|
claudeMd += "- Communication: " + seedData.communicationStyle.join(", ") + "\n";
|
|
132
134
|
}
|
|
133
135
|
claudeMd += "- Autonomy: " + (seedData.autonomy || "always_ask") + "\n";
|
|
136
|
+
claudeMd += crisisSafety.getSection();
|
|
134
137
|
fs.writeFileSync(path.join(mateDir, "CLAUDE.md"), claudeMd);
|
|
135
138
|
|
|
136
139
|
return mate;
|
package/lib/project.js
CHANGED
|
@@ -11,6 +11,7 @@ var { execFileSync, spawn } = require("child_process");
|
|
|
11
11
|
var { createLoopRegistry } = require("./scheduler");
|
|
12
12
|
var usersModule = require("./users");
|
|
13
13
|
var { resolveOsUserInfo, fsAsUser } = require("./os-users");
|
|
14
|
+
var crisisSafety = require("./crisis-safety");
|
|
14
15
|
var MAX_UPLOAD_BYTES = 50 * 1024 * 1024; // 50 MB
|
|
15
16
|
|
|
16
17
|
// Validate environment variable string (KEY=VALUE per line)
|
|
@@ -527,6 +528,10 @@ function createProjectContext(opts) {
|
|
|
527
528
|
var claudeDirWatcher = null;
|
|
528
529
|
var claudeDirDebounce = null;
|
|
529
530
|
|
|
531
|
+
// Mate CLAUDE.md crisis safety watcher
|
|
532
|
+
var crisisWatcher = null;
|
|
533
|
+
var crisisDebounce = null;
|
|
534
|
+
|
|
530
535
|
function startClaudeDirWatch() {
|
|
531
536
|
if (claudeDirWatcher) return;
|
|
532
537
|
var watchDir = loopDir();
|
|
@@ -1280,7 +1285,7 @@ function createProjectContext(opts) {
|
|
|
1280
1285
|
try {
|
|
1281
1286
|
var entries = fs.readdirSync(knowledgeDir);
|
|
1282
1287
|
for (var ki = 0; ki < entries.length; ki++) {
|
|
1283
|
-
if (entries[ki].endsWith(".md")) {
|
|
1288
|
+
if (entries[ki].endsWith(".md") || entries[ki].endsWith(".jsonl")) {
|
|
1284
1289
|
var stat = fs.statSync(path.join(knowledgeDir, entries[ki]));
|
|
1285
1290
|
files.push({ name: entries[ki], size: stat.size, mtime: stat.mtimeMs });
|
|
1286
1291
|
}
|
|
@@ -1307,7 +1312,7 @@ function createProjectContext(opts) {
|
|
|
1307
1312
|
if (msg.type === "knowledge_save") {
|
|
1308
1313
|
if (!msg.name || typeof msg.content !== "string") return;
|
|
1309
1314
|
var safeName = path.basename(msg.name);
|
|
1310
|
-
if (!safeName.endsWith(".md")) safeName += ".md";
|
|
1315
|
+
if (!safeName.endsWith(".md") && !safeName.endsWith(".jsonl")) safeName += ".md";
|
|
1311
1316
|
var knowledgeDir = path.join(cwd, "knowledge");
|
|
1312
1317
|
fs.mkdirSync(knowledgeDir, { recursive: true });
|
|
1313
1318
|
fs.writeFileSync(path.join(knowledgeDir, safeName), msg.content);
|
|
@@ -1316,7 +1321,7 @@ function createProjectContext(opts) {
|
|
|
1316
1321
|
try {
|
|
1317
1322
|
var entries = fs.readdirSync(knowledgeDir);
|
|
1318
1323
|
for (var ki = 0; ki < entries.length; ki++) {
|
|
1319
|
-
if (entries[ki].endsWith(".md")) {
|
|
1324
|
+
if (entries[ki].endsWith(".md") || entries[ki].endsWith(".jsonl")) {
|
|
1320
1325
|
var stat = fs.statSync(path.join(knowledgeDir, entries[ki]));
|
|
1321
1326
|
files.push({ name: entries[ki], size: stat.size, mtime: stat.mtimeMs });
|
|
1322
1327
|
}
|
|
@@ -1339,7 +1344,7 @@ function createProjectContext(opts) {
|
|
|
1339
1344
|
try {
|
|
1340
1345
|
var entries = fs.readdirSync(knowledgeDir);
|
|
1341
1346
|
for (var ki = 0; ki < entries.length; ki++) {
|
|
1342
|
-
if (entries[ki].endsWith(".md")) {
|
|
1347
|
+
if (entries[ki].endsWith(".md") || entries[ki].endsWith(".jsonl")) {
|
|
1343
1348
|
var stat = fs.statSync(path.join(knowledgeDir, entries[ki]));
|
|
1344
1349
|
files.push({ name: entries[ki], size: stat.size, mtime: stat.mtimeMs });
|
|
1345
1350
|
}
|
|
@@ -3906,6 +3911,24 @@ function createProjectContext(opts) {
|
|
|
3906
3911
|
icon = newIcon || null;
|
|
3907
3912
|
}
|
|
3908
3913
|
|
|
3914
|
+
// Mate projects: watch CLAUDE.md and enforce crisis safety section
|
|
3915
|
+
if (isMate) {
|
|
3916
|
+
var claudeMdPath = path.join(cwd, "CLAUDE.md");
|
|
3917
|
+
// Enforce immediately on startup
|
|
3918
|
+
try { crisisSafety.enforce(claudeMdPath); } catch (e) {}
|
|
3919
|
+
// Watch for changes
|
|
3920
|
+
try {
|
|
3921
|
+
crisisWatcher = fs.watch(claudeMdPath, function () {
|
|
3922
|
+
if (crisisDebounce) clearTimeout(crisisDebounce);
|
|
3923
|
+
crisisDebounce = setTimeout(function () {
|
|
3924
|
+
crisisDebounce = null;
|
|
3925
|
+
try { crisisSafety.enforce(claudeMdPath); } catch (e) {}
|
|
3926
|
+
}, 500);
|
|
3927
|
+
});
|
|
3928
|
+
crisisWatcher.on("error", function () {});
|
|
3929
|
+
} catch (e) {}
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3909
3932
|
return {
|
|
3910
3933
|
cwd: cwd,
|
|
3911
3934
|
slug: slug,
|
package/lib/public/app.js
CHANGED
|
@@ -2,7 +2,7 @@ import { showToast, copyToClipboard, escapeHtml } from './modules/utils.js';
|
|
|
2
2
|
import { refreshIcons, iconHtml, randomThinkingVerb } from './modules/icons.js';
|
|
3
3
|
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks, closeMermaidModal, parseEmojis } from './modules/markdown.js';
|
|
4
4
|
import { initSidebar, renderSessionList, handleSearchResults, handleSearchContentResults, updateSessionPresence, updatePageTitle, getActiveSearchQuery, buildSearchTimeline, removeSearchTimeline, onHistoryPrepended, populateCliSessionList, renderIconStrip, renderSidebarPresence, initIconStrip, getEmojiCategories, renderUserStrip, setCurrentDmUser, updateDmBadge, updateSessionBadge, updateProjectBadge, closeDmUserPicker, spawnDustParticles } from './modules/sidebar.js';
|
|
5
|
-
import { initMateSidebar, showMateSidebar, hideMateSidebar, renderMateSessionList, updateMateSidebarProfile } from './modules/mate-sidebar.js';
|
|
5
|
+
import { initMateSidebar, showMateSidebar, hideMateSidebar, renderMateSessionList, updateMateSidebarProfile, handleMateSearchResults } from './modules/mate-sidebar.js';
|
|
6
6
|
import { initMateKnowledge, requestKnowledgeList, renderKnowledgeList, handleKnowledgeContent, hideKnowledge } from './modules/mate-knowledge.js';
|
|
7
7
|
import { initRewind, setRewindMode, showRewindModal, clearPendingRewindUuid, addRewindButton } from './modules/rewind.js';
|
|
8
8
|
import { initNotifications, showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundEnabled } from './modules/notifications.js';
|
|
@@ -590,6 +590,11 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
590
590
|
dmKey = key;
|
|
591
591
|
dmTargetUser = targetUser;
|
|
592
592
|
|
|
593
|
+
// Persist active DM for restore after hard refresh
|
|
594
|
+
if (targetUser && targetUser.isMate) {
|
|
595
|
+
try { localStorage.setItem("clay_active_mate_dm", targetUser.id); } catch(e) {}
|
|
596
|
+
}
|
|
597
|
+
|
|
593
598
|
// Clear unread for this user
|
|
594
599
|
if (targetUser) {
|
|
595
600
|
dmUnread[targetUser.id] = 0;
|
|
@@ -638,9 +643,18 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
638
643
|
var mp = targetUser.profile || {};
|
|
639
644
|
var mateAvatarUrl = "https://api.dicebear.com/9.x/" + (mp.avatarStyle || targetUser.avatarStyle || "bottts") + "/svg?seed=" + encodeURIComponent(mp.avatarSeed || targetUser.avatarSeed || targetUser.id) + "&size=36";
|
|
640
645
|
var myUser = cachedAllUsers.find(function (u) { return u.id === myUserId; });
|
|
646
|
+
if (!myUser) {
|
|
647
|
+
try { var cached = JSON.parse(localStorage.getItem("clay_my_user") || "null"); if (cached) myUser = cached; } catch(e) {}
|
|
648
|
+
}
|
|
641
649
|
var myAvatarUrl = "https://api.dicebear.com/9.x/" + ((myUser && myUser.avatarStyle) || "thumbs") + "/svg?seed=" + encodeURIComponent((myUser && (myUser.avatarSeed || myUser.username)) || myUserId) + "&size=36";
|
|
650
|
+
var myDisplayName = (myUser && myUser.displayName) || "";
|
|
642
651
|
document.body.dataset.mateAvatarUrl = mateAvatarUrl;
|
|
643
652
|
document.body.dataset.myAvatarUrl = myAvatarUrl;
|
|
653
|
+
document.body.dataset.myDisplayName = myDisplayName;
|
|
654
|
+
// Cache my info for restore after hard refresh
|
|
655
|
+
if (myUser) {
|
|
656
|
+
try { localStorage.setItem("clay_my_user", JSON.stringify({ displayName: myUser.displayName, avatarStyle: myUser.avatarStyle, avatarSeed: myUser.avatarSeed, username: myUser.username })); } catch(e) {}
|
|
657
|
+
}
|
|
644
658
|
var titleBarContent = document.querySelector(".title-bar-content");
|
|
645
659
|
if (titleBarContent) {
|
|
646
660
|
titleBarContent.style.background = mateColor;
|
|
@@ -697,6 +711,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
697
711
|
dmKey = null;
|
|
698
712
|
dmTargetUser = null;
|
|
699
713
|
setCurrentDmUser(null);
|
|
714
|
+
try { localStorage.removeItem("clay_active_mate_dm"); } catch(e) {}
|
|
700
715
|
|
|
701
716
|
var mainCol = document.getElementById("main-column");
|
|
702
717
|
if (mainCol) mainCol.classList.remove("dm-mode");
|
|
@@ -800,6 +815,8 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
800
815
|
savedActiveSessionId = activeSessionId;
|
|
801
816
|
ws = mateWs;
|
|
802
817
|
connected = true;
|
|
818
|
+
// Request knowledge list for badge immediately
|
|
819
|
+
try { mateWs.send(JSON.stringify({ type: "knowledge_list" })); } catch(e) {}
|
|
803
820
|
};
|
|
804
821
|
|
|
805
822
|
mateWs.onmessage = function (ev) {
|
|
@@ -808,7 +825,6 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
808
825
|
// Intercept session_list for mate sidebar
|
|
809
826
|
if (msg.type === "init" && msg.sessions) {
|
|
810
827
|
renderMateSessionList(msg.sessions);
|
|
811
|
-
requestKnowledgeList();
|
|
812
828
|
// Override title bar with mate name (not session/project title)
|
|
813
829
|
if (dmTargetUser && dmTargetUser.isMate) {
|
|
814
830
|
var mateDN = dmTargetUser.displayName || "New Mate";
|
|
@@ -821,6 +837,11 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
821
837
|
if (msg.type === "session_list") {
|
|
822
838
|
renderMateSessionList(msg.sessions || []);
|
|
823
839
|
}
|
|
840
|
+
// Intercept search results for mate sessions
|
|
841
|
+
if (msg.type === "search_results") {
|
|
842
|
+
handleMateSearchResults(msg);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
824
845
|
// Intercept knowledge messages
|
|
825
846
|
if (msg.type === "knowledge_list") {
|
|
826
847
|
renderKnowledgeList(msg.files);
|
|
@@ -835,6 +856,9 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
835
856
|
}
|
|
836
857
|
// On done: scan DOM for [[MATE_READY: name]], update name, strip marker
|
|
837
858
|
if (msg.type === "done" && dmTargetUser && dmTargetUser.isMate) {
|
|
859
|
+
// Ensure last message is fully visible after rendering settles
|
|
860
|
+
setTimeout(function () { scrollToBottom(); }, 100);
|
|
861
|
+
setTimeout(function () { scrollToBottom(); }, 400);
|
|
838
862
|
// Let processMessage render first, then scan DOM
|
|
839
863
|
setTimeout(function () {
|
|
840
864
|
var fullText = messagesEl ? messagesEl.textContent : "";
|
|
@@ -1128,6 +1152,14 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
1128
1152
|
if (msg.dmFavorites) cachedDmFavorites = msg.dmFavorites;
|
|
1129
1153
|
if (msg.dmConversations) cachedDmConversations = msg.dmConversations;
|
|
1130
1154
|
renderUserStrip(msg.allUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers, cachedMatesList);
|
|
1155
|
+
// Update my info in body.dataset if in mate DM (fixes stale data after refresh)
|
|
1156
|
+
if (document.body.classList.contains("mate-dm-active")) {
|
|
1157
|
+
var refreshedMyUser = cachedAllUsers.find(function (u) { return u.id === myUserId; });
|
|
1158
|
+
if (refreshedMyUser) {
|
|
1159
|
+
document.body.dataset.myDisplayName = refreshedMyUser.displayName || "";
|
|
1160
|
+
document.body.dataset.myAvatarUrl = "https://api.dicebear.com/9.x/" + (refreshedMyUser.avatarStyle || "thumbs") + "/svg?seed=" + encodeURIComponent(refreshedMyUser.avatarSeed || refreshedMyUser.username) + "&size=36";
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1131
1163
|
// Render my avatar (always present, hidden behind user-island)
|
|
1132
1164
|
var meEl = document.getElementById("icon-strip-me");
|
|
1133
1165
|
if (meEl && !meEl.hasChildNodes()) {
|
|
@@ -1222,6 +1254,24 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
1222
1254
|
});
|
|
1223
1255
|
}
|
|
1224
1256
|
|
|
1257
|
+
// Prevent Cmd+Z / Cmd+Shift+Z from triggering browser back/forward (Arc, etc.)
|
|
1258
|
+
// Always block browser default for Cmd+Z and manually invoke undo/redo via execCommand
|
|
1259
|
+
document.addEventListener("keydown", function (e) {
|
|
1260
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
1261
|
+
var el = document.activeElement;
|
|
1262
|
+
var tag = el && el.tagName;
|
|
1263
|
+
if (tag === "TEXTAREA" || tag === "INPUT" || (el && el.isContentEditable)) {
|
|
1264
|
+
e.preventDefault();
|
|
1265
|
+
e.stopPropagation();
|
|
1266
|
+
if (e.shiftKey) {
|
|
1267
|
+
document.execCommand("redo", false, null);
|
|
1268
|
+
} else {
|
|
1269
|
+
document.execCommand("undo", false, null);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}, true);
|
|
1274
|
+
|
|
1225
1275
|
document.addEventListener("keydown", function (e) {
|
|
1226
1276
|
if (e.key === "Escape") {
|
|
1227
1277
|
if (homeHubVisible && currentSlug) {
|
|
@@ -1819,17 +1869,24 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
1819
1869
|
|
|
1820
1870
|
// --- Mate pre-thinking (instant dots before server responds) ---
|
|
1821
1871
|
var matePreThinkingEl = null;
|
|
1872
|
+
var matePreThinkingTimer = null;
|
|
1822
1873
|
function showMatePreThinking() {
|
|
1823
1874
|
removeMatePreThinking();
|
|
1824
1875
|
var mateName = dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate";
|
|
1825
1876
|
var mateAvatar = document.body.dataset.mateAvatarUrl || "";
|
|
1877
|
+
matePreThinkingTimer = setTimeout(function () {
|
|
1878
|
+
matePreThinkingTimer = null;
|
|
1879
|
+
doShowMatePreThinking(mateName, mateAvatar);
|
|
1880
|
+
}, 1000);
|
|
1881
|
+
}
|
|
1882
|
+
function doShowMatePreThinking(mateName, mateAvatar) {
|
|
1826
1883
|
matePreThinkingEl = document.createElement("div");
|
|
1827
1884
|
matePreThinkingEl.className = "thinking-item mate-thinking mate-pre-thinking";
|
|
1828
1885
|
matePreThinkingEl.innerHTML =
|
|
1886
|
+
'<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="" style="display:block">' +
|
|
1887
|
+
'<div class="dm-bubble-content">' +
|
|
1829
1888
|
'<div class="mate-thinking-row" style="display:flex">' +
|
|
1830
|
-
'<
|
|
1831
|
-
'<div class="mate-thinking-body">' +
|
|
1832
|
-
'<span class="mate-thinking-name">' + escapeHtml(mateName) + '</span>' +
|
|
1889
|
+
'<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
|
|
1833
1890
|
'<span class="mate-thinking-dots"><span></span><span></span><span></span></span>' +
|
|
1834
1891
|
'</div>' +
|
|
1835
1892
|
'</div>';
|
|
@@ -1837,6 +1894,10 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
1837
1894
|
scrollToBottom();
|
|
1838
1895
|
}
|
|
1839
1896
|
function removeMatePreThinking() {
|
|
1897
|
+
if (matePreThinkingTimer) {
|
|
1898
|
+
clearTimeout(matePreThinkingTimer);
|
|
1899
|
+
matePreThinkingTimer = null;
|
|
1900
|
+
}
|
|
1840
1901
|
if (matePreThinkingEl) {
|
|
1841
1902
|
matePreThinkingEl.remove();
|
|
1842
1903
|
matePreThinkingEl = null;
|
|
@@ -2622,10 +2683,14 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
2622
2683
|
|
|
2623
2684
|
var header = document.createElement("div");
|
|
2624
2685
|
header.className = "dm-bubble-header";
|
|
2625
|
-
var
|
|
2686
|
+
var myDisplayName = document.body.dataset.myDisplayName || "";
|
|
2687
|
+
if (!myDisplayName) {
|
|
2688
|
+
var myU = cachedAllUsers.find(function (u) { return u.id === myUserId; });
|
|
2689
|
+
myDisplayName = (myU && myU.displayName) || "Me";
|
|
2690
|
+
}
|
|
2626
2691
|
var nameSpan = document.createElement("span");
|
|
2627
2692
|
nameSpan.className = "dm-bubble-name";
|
|
2628
|
-
nameSpan.textContent =
|
|
2693
|
+
nameSpan.textContent = myDisplayName;
|
|
2629
2694
|
header.appendChild(nameSpan);
|
|
2630
2695
|
var timeSpan = document.createElement("span");
|
|
2631
2696
|
timeSpan.className = "dm-bubble-time";
|
|
@@ -3326,6 +3391,14 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
|
|
|
3326
3391
|
try {
|
|
3327
3392
|
ws.send(JSON.stringify({ type: "mate_list" }));
|
|
3328
3393
|
} catch(e) {}
|
|
3394
|
+
|
|
3395
|
+
// Restore mate DM after hard refresh
|
|
3396
|
+
try {
|
|
3397
|
+
var savedMateDm = localStorage.getItem("clay_active_mate_dm");
|
|
3398
|
+
if (savedMateDm && !dmMode) {
|
|
3399
|
+
openDm(savedMateDm);
|
|
3400
|
+
}
|
|
3401
|
+
} catch(e) {}
|
|
3329
3402
|
};
|
|
3330
3403
|
|
|
3331
3404
|
ws.onclose = function (e) {
|
package/lib/public/css/input.css
CHANGED