clay-server 2.31.0 → 2.32.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/browser-mcp-server.js +32 -44
- package/lib/debate-mcp-server.js +14 -31
- package/lib/mcp-local.js +31 -1
- package/lib/project-connection.js +4 -2
- package/lib/project-filesystem.js +47 -1
- package/lib/project-http.js +75 -8
- package/lib/project-mcp.js +4 -0
- package/lib/project-sessions.js +88 -51
- package/lib/project-user-message.js +12 -7
- package/lib/project.js +204 -90
- package/lib/public/app.js +123 -448
- package/lib/public/codex-avatar.png +0 -0
- package/lib/public/css/debate.css +3 -2
- package/lib/public/css/filebrowser.css +91 -1
- package/lib/public/css/icon-strip.css +21 -5
- package/lib/public/css/input.css +181 -100
- package/lib/public/css/mates.css +43 -0
- package/lib/public/css/mention.css +48 -4
- package/lib/public/css/menus.css +1 -1
- package/lib/public/css/messages.css +2 -0
- package/lib/public/css/notifications-center.css +19 -0
- package/lib/public/index.html +46 -24
- package/lib/public/modules/app-connection.js +138 -37
- package/lib/public/modules/app-cursors.js +18 -17
- package/lib/public/modules/app-debate-ui.js +9 -9
- package/lib/public/modules/app-dm.js +170 -131
- package/lib/public/modules/app-favicon.js +28 -26
- package/lib/public/modules/app-header.js +79 -68
- package/lib/public/modules/app-home-hub.js +55 -47
- package/lib/public/modules/app-loop-ui.js +34 -18
- package/lib/public/modules/app-loop-wizard.js +6 -6
- package/lib/public/modules/app-messages.js +195 -152
- package/lib/public/modules/app-misc.js +23 -12
- package/lib/public/modules/app-notifications.js +97 -3
- package/lib/public/modules/app-panels.js +203 -49
- package/lib/public/modules/app-projects.js +159 -150
- package/lib/public/modules/app-rate-limit.js +5 -4
- package/lib/public/modules/app-rendering.js +149 -101
- package/lib/public/modules/app-skills-install.js +4 -4
- package/lib/public/modules/context-sources.js +12 -41
- package/lib/public/modules/dom-refs.js +21 -0
- package/lib/public/modules/filebrowser.js +173 -2
- package/lib/public/modules/input.js +86 -0
- package/lib/public/modules/mate-sidebar.js +38 -0
- package/lib/public/modules/mention.js +24 -6
- package/lib/public/modules/scheduler.js +1 -1
- package/lib/public/modules/sidebar-mates.js +66 -34
- package/lib/public/modules/sidebar-mobile.js +34 -30
- package/lib/public/modules/sidebar-projects.js +60 -57
- package/lib/public/modules/sidebar-sessions.js +75 -69
- package/lib/public/modules/sidebar.js +12 -20
- package/lib/public/modules/skills.js +8 -9
- package/lib/public/modules/sticky-notes.js +1 -2
- package/lib/public/modules/store.js +9 -2
- package/lib/public/modules/stt.js +4 -1
- package/lib/public/modules/tools.js +14 -9
- package/lib/sdk-bridge.js +511 -1113
- package/lib/sdk-message-processor.js +123 -134
- package/lib/sdk-worker.js +4 -0
- package/lib/server-dm.js +1 -0
- package/lib/server.js +86 -1
- package/lib/sessions.js +47 -36
- package/lib/ws-schema.js +2 -0
- package/lib/yoke/adapters/claude-worker.js +559 -0
- package/lib/yoke/adapters/claude.js +1418 -0
- package/lib/yoke/adapters/codex.js +968 -0
- package/lib/yoke/adapters/gemini.js +668 -0
- package/lib/yoke/codex-app-server.js +307 -0
- package/lib/yoke/index.js +199 -0
- package/lib/yoke/instructions.js +62 -0
- package/lib/yoke/interface.js +92 -0
- package/lib/yoke/mcp-bridge-server.js +294 -0
- package/lib/yoke/package.json +7 -0
- package/package.json +3 -1
|
@@ -2,8 +2,31 @@
|
|
|
2
2
|
// Extracted from app.js (PR-28)
|
|
3
3
|
|
|
4
4
|
import { store } from './store.js';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { getWs } from './ws-ref.js';
|
|
6
|
+
import { getMessagesEl, getInputEl, getSendBtn } from './dom-refs.js';
|
|
7
|
+
import { escapeHtml, copyToClipboard } from './utils.js';
|
|
8
|
+
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks } from './markdown.js';
|
|
9
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
10
|
+
import { openTerminal } from './terminal.js';
|
|
11
|
+
import { userAvatarUrl } from './avatar.js';
|
|
12
|
+
import { closeToolGroup } from './tools.js';
|
|
13
|
+
import { showImageModal, showPasteModal } from './app-misc.js';
|
|
14
|
+
import { sendMessage } from './input.js';
|
|
15
|
+
import { getChatLayout } from './theme.js';
|
|
16
|
+
import { getScheduledMsgEl } from './app-rate-limit.js';
|
|
17
|
+
|
|
18
|
+
export var VENDOR_AVATARS = {
|
|
19
|
+
claude: "/claude-code-avatar.png",
|
|
20
|
+
codex: "/codex-avatar.png",
|
|
21
|
+
gemini: "/claude-code-avatar.png",
|
|
22
|
+
};
|
|
23
|
+
export var VENDOR_NAMES = {
|
|
24
|
+
claude: "Claude Code",
|
|
25
|
+
codex: "Codex",
|
|
26
|
+
gemini: "Gemini",
|
|
27
|
+
};
|
|
28
|
+
var NEW_MSG_BTN_DEFAULT = "\u2193 Latest";
|
|
29
|
+
var NEW_MSG_BTN_ACTIVITY = "\u2193 New activity";
|
|
7
30
|
|
|
8
31
|
// --- Module-owned state (not in store) ---
|
|
9
32
|
var turnCounter = 0;
|
|
@@ -16,8 +39,16 @@ var streamDrainTimer = null;
|
|
|
16
39
|
var isUserScrolledUp = false;
|
|
17
40
|
var scrollThreshold = 150;
|
|
18
41
|
|
|
19
|
-
export function initRendering(
|
|
20
|
-
|
|
42
|
+
export function initRendering() {
|
|
43
|
+
// Update input placeholder when vendor changes
|
|
44
|
+
store.subscribe(function (state, prev) {
|
|
45
|
+
if (state.currentVendor !== prev.currentVendor) {
|
|
46
|
+
var inputEl = document.getElementById("input");
|
|
47
|
+
if (inputEl) {
|
|
48
|
+
inputEl.placeholder = "Message " + (VENDOR_NAMES[state.currentVendor] || VENDOR_NAMES.claude) + "...";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
21
52
|
}
|
|
22
53
|
|
|
23
54
|
// --- State accessors (module-local, not in store) ---
|
|
@@ -33,10 +64,10 @@ export function setIsUserScrolledUp(v) { isUserScrolledUp = v; }
|
|
|
33
64
|
// --- Rendering functions ---
|
|
34
65
|
|
|
35
66
|
export function addToMessages(el) {
|
|
36
|
-
var messagesEl =
|
|
67
|
+
var messagesEl = getMessagesEl();
|
|
37
68
|
if (prependAnchor) messagesEl.insertBefore(el, prependAnchor);
|
|
38
69
|
else messagesEl.appendChild(el);
|
|
39
|
-
var _sme =
|
|
70
|
+
var _sme = getScheduledMsgEl();
|
|
40
71
|
if (_sme && el !== _sme && _sme.parentNode === messagesEl) {
|
|
41
72
|
messagesEl.appendChild(_sme);
|
|
42
73
|
}
|
|
@@ -44,12 +75,13 @@ export function addToMessages(el) {
|
|
|
44
75
|
|
|
45
76
|
export function scrollToBottom() {
|
|
46
77
|
if (prependAnchor) return;
|
|
78
|
+
var newMsgBtn = document.getElementById("new-msg-btn");
|
|
47
79
|
if (isUserScrolledUp) {
|
|
48
|
-
|
|
49
|
-
|
|
80
|
+
newMsgBtn.textContent = NEW_MSG_BTN_ACTIVITY;
|
|
81
|
+
newMsgBtn.classList.remove("hidden");
|
|
50
82
|
return;
|
|
51
83
|
}
|
|
52
|
-
var messagesEl =
|
|
84
|
+
var messagesEl = getMessagesEl();
|
|
53
85
|
requestAnimationFrame(function () {
|
|
54
86
|
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
55
87
|
});
|
|
@@ -58,16 +90,17 @@ export function scrollToBottom() {
|
|
|
58
90
|
export function forceScrollToBottom() {
|
|
59
91
|
if (prependAnchor) return;
|
|
60
92
|
isUserScrolledUp = false;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
93
|
+
var newMsgBtn = document.getElementById("new-msg-btn");
|
|
94
|
+
newMsgBtn.classList.add("hidden");
|
|
95
|
+
newMsgBtn.textContent = NEW_MSG_BTN_DEFAULT;
|
|
96
|
+
var messagesEl = getMessagesEl();
|
|
64
97
|
requestAnimationFrame(function () {
|
|
65
98
|
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
66
99
|
});
|
|
67
100
|
}
|
|
68
101
|
|
|
69
102
|
export function getMsgTime() {
|
|
70
|
-
var _ts = store.
|
|
103
|
+
var _ts = store.get('currentMsgTs');
|
|
71
104
|
var d = _ts ? new Date(_ts) : new Date();
|
|
72
105
|
var time = String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
|
|
73
106
|
var now = new Date();
|
|
@@ -78,9 +111,9 @@ export function getMsgTime() {
|
|
|
78
111
|
}
|
|
79
112
|
|
|
80
113
|
export function shouldGroupMessage(senderClass) {
|
|
81
|
-
var _s = store.
|
|
114
|
+
var _s = store.snap();
|
|
82
115
|
if (_s.replayingHistory && !_s.currentMsgTs) return false;
|
|
83
|
-
var prev =
|
|
116
|
+
var prev = getMessagesEl().lastElementChild;
|
|
84
117
|
if (!prev || !prev.classList.contains(senderClass)) return false;
|
|
85
118
|
var prevTime = prev.querySelector(".dm-bubble-time");
|
|
86
119
|
if (!prevTime) return false;
|
|
@@ -88,7 +121,7 @@ export function shouldGroupMessage(senderClass) {
|
|
|
88
121
|
}
|
|
89
122
|
|
|
90
123
|
export function ensureAssistantBlock() {
|
|
91
|
-
var _el = store.
|
|
124
|
+
var _el = store.get('currentMsgEl');
|
|
92
125
|
if (!_el) {
|
|
93
126
|
_el = document.createElement("div");
|
|
94
127
|
_el.className = "msg-assistant";
|
|
@@ -98,9 +131,10 @@ export function ensureAssistantBlock() {
|
|
|
98
131
|
if (grouped) _el.classList.add("grouped");
|
|
99
132
|
|
|
100
133
|
var _isDm2 = document.body.classList.contains("mate-dm-active") && document.body.dataset.mateAvatarUrl;
|
|
134
|
+
var vendor = store.get('currentVendor') || "claude";
|
|
101
135
|
var avi = document.createElement("img");
|
|
102
136
|
avi.className = "dm-bubble-avatar dm-bubble-avatar-mate";
|
|
103
|
-
avi.src = _isDm2 ? document.body.dataset.mateAvatarUrl :
|
|
137
|
+
avi.src = _isDm2 ? document.body.dataset.mateAvatarUrl : (VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude);
|
|
104
138
|
_el.appendChild(avi);
|
|
105
139
|
|
|
106
140
|
var contentWrap = document.createElement("div");
|
|
@@ -110,7 +144,8 @@ export function ensureAssistantBlock() {
|
|
|
110
144
|
header.className = "dm-bubble-header";
|
|
111
145
|
var nameSpan = document.createElement("span");
|
|
112
146
|
nameSpan.className = "dm-bubble-name";
|
|
113
|
-
|
|
147
|
+
var dmTarget = store.get('dmTargetUser');
|
|
148
|
+
nameSpan.textContent = _isDm2 ? ((dmTarget && dmTarget.displayName) || "Mate") : (VENDOR_NAMES[vendor] || VENDOR_NAMES.claude);
|
|
114
149
|
header.appendChild(nameSpan);
|
|
115
150
|
var timeSpan = document.createElement("span");
|
|
116
151
|
timeSpan.className = "dm-bubble-time";
|
|
@@ -124,7 +159,7 @@ export function ensureAssistantBlock() {
|
|
|
124
159
|
contentWrap.appendChild(mdDiv);
|
|
125
160
|
_el.appendChild(contentWrap);
|
|
126
161
|
addToMessages(_el);
|
|
127
|
-
store.
|
|
162
|
+
store.set({ currentMsgEl: _el, currentFullText: "" });
|
|
128
163
|
}
|
|
129
164
|
return _el;
|
|
130
165
|
}
|
|
@@ -159,7 +194,7 @@ export function addCopyHandler(msgEl, rawText) {
|
|
|
159
194
|
resetTimer = setTimeout(reset, 3000);
|
|
160
195
|
} else {
|
|
161
196
|
clearTimeout(resetTimer);
|
|
162
|
-
|
|
197
|
+
copyToClipboard(rawText).then(function () {
|
|
163
198
|
msgEl.classList.remove("copy-primed");
|
|
164
199
|
msgEl.classList.add("copy-done");
|
|
165
200
|
hint.textContent = "Grabbed!";
|
|
@@ -183,7 +218,7 @@ export function appendDelta(text) {
|
|
|
183
218
|
|
|
184
219
|
function drainStreamTick() {
|
|
185
220
|
streamDrainTimer = null;
|
|
186
|
-
var _s = store.
|
|
221
|
+
var _s = store.snap();
|
|
187
222
|
if (!_s.currentMsgEl || streamBuffer.length === 0) return;
|
|
188
223
|
|
|
189
224
|
var n;
|
|
@@ -197,14 +232,14 @@ function drainStreamTick() {
|
|
|
197
232
|
var chunk = streamBuffer.slice(0, n);
|
|
198
233
|
streamBuffer = streamBuffer.slice(n);
|
|
199
234
|
var newText = _s.currentFullText + chunk;
|
|
200
|
-
store.
|
|
235
|
+
store.set({ currentFullText: newText });
|
|
201
236
|
|
|
202
237
|
var contentEl = _s.currentMsgEl.querySelector(".md-content");
|
|
203
|
-
contentEl.innerHTML =
|
|
238
|
+
contentEl.innerHTML = renderMarkdown(newText);
|
|
204
239
|
|
|
205
240
|
if (highlightTimer) clearTimeout(highlightTimer);
|
|
206
241
|
highlightTimer = setTimeout(function () {
|
|
207
|
-
|
|
242
|
+
highlightCodeBlocks(contentEl);
|
|
208
243
|
}, 150);
|
|
209
244
|
|
|
210
245
|
scrollToBottom();
|
|
@@ -217,39 +252,40 @@ function drainStreamTick() {
|
|
|
217
252
|
export function flushStreamBuffer() {
|
|
218
253
|
if (streamDrainTimer) { cancelAnimationFrame(streamDrainTimer); streamDrainTimer = null; }
|
|
219
254
|
if (streamBuffer.length > 0) {
|
|
220
|
-
store.
|
|
255
|
+
store.set({ currentFullText: store.get('currentFullText') + streamBuffer });
|
|
221
256
|
streamBuffer = "";
|
|
222
257
|
}
|
|
223
|
-
var _s = store.
|
|
258
|
+
var _s = store.snap();
|
|
224
259
|
if (_s.currentMsgEl) {
|
|
225
260
|
var contentEl = _s.currentMsgEl.querySelector(".md-content");
|
|
226
261
|
if (contentEl) {
|
|
227
|
-
contentEl.innerHTML =
|
|
228
|
-
|
|
262
|
+
contentEl.innerHTML = renderMarkdown(_s.currentFullText);
|
|
263
|
+
highlightCodeBlocks(contentEl);
|
|
229
264
|
}
|
|
230
265
|
}
|
|
231
266
|
}
|
|
232
267
|
|
|
233
268
|
export function finalizeAssistantBlock() {
|
|
234
269
|
flushStreamBuffer();
|
|
235
|
-
var _s = store.
|
|
270
|
+
var _s = store.snap();
|
|
236
271
|
if (_s.currentMsgEl) {
|
|
237
272
|
var contentEl = _s.currentMsgEl.querySelector(".md-content");
|
|
238
273
|
if (contentEl) {
|
|
239
|
-
|
|
240
|
-
|
|
274
|
+
highlightCodeBlocks(contentEl);
|
|
275
|
+
renderMermaidBlocks(contentEl);
|
|
241
276
|
}
|
|
242
277
|
if (_s.currentFullText) {
|
|
243
278
|
addCopyHandler(_s.currentMsgEl, _s.currentFullText);
|
|
244
279
|
}
|
|
245
|
-
|
|
280
|
+
closeToolGroup();
|
|
246
281
|
}
|
|
247
|
-
store.
|
|
282
|
+
store.set({ currentMsgEl: null, currentFullText: "" });
|
|
248
283
|
}
|
|
249
284
|
|
|
250
285
|
export function addUserMessage(text, images, pastes, fromUserId, fromUserName) {
|
|
251
286
|
if (!text && (!images || images.length === 0) && (!pastes || pastes.length === 0)) return;
|
|
252
|
-
var
|
|
287
|
+
var myUserId = store.get('myUserId');
|
|
288
|
+
var isOtherUser = fromUserId && fromUserId !== myUserId;
|
|
253
289
|
var div = document.createElement("div");
|
|
254
290
|
div.className = "msg-user" + (isOtherUser ? " msg-user-other" : "");
|
|
255
291
|
div.dataset.turn = ++turnCounter;
|
|
@@ -270,7 +306,7 @@ export function addUserMessage(text, images, pastes, fromUserId, fromUserName) {
|
|
|
270
306
|
}
|
|
271
307
|
img.loading = "lazy";
|
|
272
308
|
img.className = "bubble-img";
|
|
273
|
-
img.addEventListener("click", function () {
|
|
309
|
+
img.addEventListener("click", function () { showImageModal(this.src); });
|
|
274
310
|
img.addEventListener("error", function () {
|
|
275
311
|
var placeholder = document.createElement("div");
|
|
276
312
|
placeholder.className = "bubble-img-expired";
|
|
@@ -291,10 +327,10 @@ export function addUserMessage(text, images, pastes, fromUserId, fromUserName) {
|
|
|
291
327
|
chip.className = "bubble-paste";
|
|
292
328
|
var preview = pasteText.substring(0, 60).replace(/\n/g, " ");
|
|
293
329
|
if (pasteText.length > 60) preview += "...";
|
|
294
|
-
chip.innerHTML = '<span class="bubble-paste-preview">' +
|
|
330
|
+
chip.innerHTML = '<span class="bubble-paste-preview">' + escapeHtml(preview) + '</span><span class="bubble-paste-label">PASTED</span>';
|
|
295
331
|
chip.addEventListener("click", function (e) {
|
|
296
332
|
e.stopPropagation();
|
|
297
|
-
|
|
333
|
+
showPasteModal(pasteText);
|
|
298
334
|
});
|
|
299
335
|
pasteRow.appendChild(chip);
|
|
300
336
|
})(pastes[p]);
|
|
@@ -309,13 +345,14 @@ export function addUserMessage(text, images, pastes, fromUserId, fromUserName) {
|
|
|
309
345
|
}
|
|
310
346
|
|
|
311
347
|
|
|
348
|
+
var cachedAllUsers = store.get('cachedAllUsers');
|
|
312
349
|
var _targetUser;
|
|
313
350
|
var _displayName;
|
|
314
351
|
if (isOtherUser) {
|
|
315
|
-
_targetUser =
|
|
352
|
+
_targetUser = cachedAllUsers.find(function (u) { return u.id === fromUserId; });
|
|
316
353
|
_displayName = fromUserName || (_targetUser && (_targetUser.displayName || _targetUser.username)) || "User";
|
|
317
354
|
} else {
|
|
318
|
-
_targetUser =
|
|
355
|
+
_targetUser = cachedAllUsers.find(function (u) { return u.id === myUserId; });
|
|
319
356
|
if (!_targetUser) {
|
|
320
357
|
try { _targetUser = JSON.parse(localStorage.getItem("clay_my_user") || "null"); } catch(e) {}
|
|
321
358
|
}
|
|
@@ -328,8 +365,8 @@ export function addUserMessage(text, images, pastes, fromUserId, fromUserName) {
|
|
|
328
365
|
var avi = document.createElement("img");
|
|
329
366
|
avi.className = "dm-bubble-avatar" + (isOtherUser ? " dm-bubble-avatar-other" : " dm-bubble-avatar-me");
|
|
330
367
|
avi.src = isOtherUser
|
|
331
|
-
?
|
|
332
|
-
: (document.body.dataset.myAvatarUrl ||
|
|
368
|
+
? userAvatarUrl(_targetUser || { id: fromUserId }, 36)
|
|
369
|
+
: (document.body.dataset.myAvatarUrl || userAvatarUrl(_targetUser || { id: myUserId }, 36));
|
|
333
370
|
div.appendChild(avi);
|
|
334
371
|
|
|
335
372
|
var contentWrap = document.createElement("div");
|
|
@@ -353,22 +390,22 @@ export function addUserMessage(text, images, pastes, fromUserId, fromUserName) {
|
|
|
353
390
|
actions.className = "msg-actions";
|
|
354
391
|
actions.innerHTML =
|
|
355
392
|
'<span class="msg-action-time">' + getMsgTime() + '</span>' +
|
|
356
|
-
'<button class="msg-action-btn msg-action-copy" type="button" title="Copy">' +
|
|
357
|
-
'<button class="msg-action-btn msg-action-fork" type="button" title="Fork">' +
|
|
358
|
-
'<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' +
|
|
359
|
-
'<button class="msg-action-btn msg-action-hidden msg-action-edit" type="button" title="Edit">' +
|
|
393
|
+
'<button class="msg-action-btn msg-action-copy" type="button" title="Copy">' + iconHtml("copy") + '</button>' +
|
|
394
|
+
'<button class="msg-action-btn msg-action-fork" type="button" title="Fork">' + iconHtml("git-branch") + '</button>' +
|
|
395
|
+
(((store.get('vendorCapabilities') || {}).rewind !== false) ? '<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' + iconHtml("rotate-ccw") + '</button>' : '') +
|
|
396
|
+
'<button class="msg-action-btn msg-action-hidden msg-action-edit" type="button" title="Edit">' + iconHtml("pencil") + '</button>';
|
|
360
397
|
div.appendChild(actions);
|
|
361
398
|
|
|
362
399
|
actions.querySelector(".msg-action-copy").addEventListener("click", function () {
|
|
363
400
|
var self = this;
|
|
364
|
-
|
|
365
|
-
self.innerHTML =
|
|
366
|
-
|
|
367
|
-
setTimeout(function () { self.innerHTML =
|
|
401
|
+
copyToClipboard(text || "");
|
|
402
|
+
self.innerHTML = iconHtml("check");
|
|
403
|
+
refreshIcons();
|
|
404
|
+
setTimeout(function () { self.innerHTML = iconHtml("copy"); refreshIcons(); }, 1200);
|
|
368
405
|
});
|
|
369
406
|
|
|
370
407
|
addToMessages(div);
|
|
371
|
-
|
|
408
|
+
refreshIcons();
|
|
372
409
|
forceScrollToBottom();
|
|
373
410
|
}
|
|
374
411
|
|
|
@@ -416,7 +453,7 @@ export function addConflictMessage(msg) {
|
|
|
416
453
|
killBtn.setAttribute("data-pid", p.pid);
|
|
417
454
|
killBtn.addEventListener("click", function() {
|
|
418
455
|
var pid = parseInt(this.getAttribute("data-pid"), 10);
|
|
419
|
-
|
|
456
|
+
getWs().send(JSON.stringify({ type: "kill_process", pid: pid }));
|
|
420
457
|
this.disabled = true;
|
|
421
458
|
this.textContent = "Killing...";
|
|
422
459
|
});
|
|
@@ -446,7 +483,7 @@ export function addContextOverflowMessage(msg) {
|
|
|
446
483
|
btn.className = "context-overflow-btn";
|
|
447
484
|
btn.textContent = "New Conversation";
|
|
448
485
|
btn.addEventListener("click", function() {
|
|
449
|
-
|
|
486
|
+
getWs().send(JSON.stringify({ type: "new_session" }));
|
|
450
487
|
});
|
|
451
488
|
div.appendChild(btn);
|
|
452
489
|
|
|
@@ -458,9 +495,13 @@ export function addAuthRequiredMessage(msg) {
|
|
|
458
495
|
var div = document.createElement("div");
|
|
459
496
|
div.className = "auth-required-msg";
|
|
460
497
|
|
|
498
|
+
var vendor = msg.vendor || "claude";
|
|
499
|
+
var loginCmd = msg.loginCommand || (vendor === "codex" ? "codex --login" : "claude login");
|
|
500
|
+
var vendorName = msg.text || "Claude Code is not logged in.";
|
|
501
|
+
|
|
461
502
|
var header = document.createElement("div");
|
|
462
503
|
header.className = "auth-required-header";
|
|
463
|
-
header.textContent =
|
|
504
|
+
header.textContent = vendorName;
|
|
464
505
|
div.appendChild(header);
|
|
465
506
|
|
|
466
507
|
var hint = document.createElement("div");
|
|
@@ -476,7 +517,11 @@ export function addAuthRequiredMessage(msg) {
|
|
|
476
517
|
|
|
477
518
|
var guide = document.createElement("div");
|
|
478
519
|
guide.className = "auth-required-guide";
|
|
479
|
-
|
|
520
|
+
if (vendor === "codex") {
|
|
521
|
+
guide.textContent = "Run the login command in the terminal and follow the instructions to authenticate.";
|
|
522
|
+
} else {
|
|
523
|
+
guide.textContent = "When a login URL appears in the terminal, click it to open in your browser. Do not press 'c' as it will try to open the browser on the server.";
|
|
524
|
+
}
|
|
480
525
|
div.appendChild(guide);
|
|
481
526
|
|
|
482
527
|
var sessionHint = document.createElement("div");
|
|
@@ -484,13 +529,14 @@ export function addAuthRequiredMessage(msg) {
|
|
|
484
529
|
sessionHint.textContent = "After logging in, start a new session to continue.";
|
|
485
530
|
div.appendChild(sessionHint);
|
|
486
531
|
|
|
532
|
+
var termCommand = loginCmd + "\n";
|
|
487
533
|
var loginBtn = document.createElement("button");
|
|
488
534
|
loginBtn.className = "auth-required-btn";
|
|
489
535
|
loginBtn.textContent = "Open terminal & log in";
|
|
490
536
|
loginBtn.addEventListener("click", function () {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
537
|
+
store.set({ pendingTermCommand: termCommand });
|
|
538
|
+
getWs().send(JSON.stringify({ type: "term_create", cols: 80, rows: 24 }));
|
|
539
|
+
openTerminal();
|
|
494
540
|
});
|
|
495
541
|
div.appendChild(loginBtn);
|
|
496
542
|
|
|
@@ -500,34 +546,39 @@ export function addAuthRequiredMessage(msg) {
|
|
|
500
546
|
var inputArea = document.getElementById("input-area");
|
|
501
547
|
if (inputArea) inputArea.classList.add("hidden");
|
|
502
548
|
|
|
503
|
-
if (!store.
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
549
|
+
if (!store.get('replayingHistory')) {
|
|
550
|
+
store.set({ pendingTermCommand: termCommand });
|
|
551
|
+
getWs().send(JSON.stringify({ type: "term_create", cols: 80, rows: 24 }));
|
|
552
|
+
openTerminal();
|
|
507
553
|
}
|
|
508
554
|
} else {
|
|
509
|
-
|
|
555
|
+
var adminVendorName = vendor.charAt(0).toUpperCase() + vendor.slice(1);
|
|
556
|
+
hint.textContent = "Please ask an administrator to log in to " + adminVendorName + ".";
|
|
510
557
|
div.appendChild(hint);
|
|
511
558
|
addToMessages(div);
|
|
512
559
|
scrollToBottom();
|
|
513
560
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
561
|
+
var inputEl = getInputEl();
|
|
562
|
+
inputEl.disabled = true;
|
|
563
|
+
inputEl.placeholder = "Login required. Start a new session after logging in.";
|
|
564
|
+
getSendBtn().disabled = true;
|
|
517
565
|
}
|
|
518
566
|
}
|
|
519
567
|
|
|
520
568
|
// --- Pre-thinking (instant dots before server responds) ---
|
|
521
569
|
|
|
522
570
|
export function showClaudePreThinking() {
|
|
523
|
-
if (
|
|
524
|
-
var
|
|
525
|
-
|
|
571
|
+
if (getChatLayout() !== "channel") return;
|
|
572
|
+
var vendor = store.get('currentVendor') || "claude";
|
|
573
|
+
var vendorAvatar = VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude;
|
|
574
|
+
var vendorName = VENDOR_NAMES[vendor] || VENDOR_NAMES.claude;
|
|
575
|
+
doShowMatePreThinking(vendorName, vendorAvatar);
|
|
526
576
|
}
|
|
527
577
|
|
|
528
578
|
export function showMatePreThinking() {
|
|
529
579
|
removeMatePreThinking();
|
|
530
|
-
var
|
|
580
|
+
var dmTarget = store.get('dmTargetUser');
|
|
581
|
+
var mateName = dmTarget ? (dmTarget.displayName || "Mate") : "Mate";
|
|
531
582
|
var mateAvatar = document.body.dataset.mateAvatarUrl || "";
|
|
532
583
|
doShowMatePreThinking(mateName, mateAvatar);
|
|
533
584
|
}
|
|
@@ -536,18 +587,18 @@ function doShowMatePreThinking(mateName, mateAvatar) {
|
|
|
536
587
|
var _el = document.createElement("div");
|
|
537
588
|
_el.className = "thinking-item mate-thinking mate-pre-thinking";
|
|
538
589
|
_el.innerHTML =
|
|
539
|
-
'<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' +
|
|
590
|
+
'<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="" style="display:block">' +
|
|
540
591
|
'<div class="dm-bubble-content">' +
|
|
541
|
-
'<div class="dm-bubble-header"><span class="dm-bubble-name">' +
|
|
592
|
+
'<div class="dm-bubble-header"><span class="dm-bubble-name">' + escapeHtml(mateName) + '</span></div>' +
|
|
542
593
|
'<div class="mate-thinking-dots"><span></span><span></span><span></span></div>' +
|
|
543
594
|
'</div>';
|
|
544
|
-
store.
|
|
595
|
+
store.set({ matePreThinkingEl: _el });
|
|
545
596
|
if (activityEl && activityEl.parentNode) {
|
|
546
597
|
activityEl.parentNode.insertBefore(_el, activityEl);
|
|
547
598
|
} else {
|
|
548
599
|
addToMessages(_el);
|
|
549
600
|
}
|
|
550
|
-
|
|
601
|
+
refreshIcons();
|
|
551
602
|
scrollToBottom();
|
|
552
603
|
}
|
|
553
604
|
|
|
@@ -556,42 +607,39 @@ export function removeMatePreThinking() {
|
|
|
556
607
|
clearTimeout(matePreThinkingTimer);
|
|
557
608
|
matePreThinkingTimer = null;
|
|
558
609
|
}
|
|
559
|
-
var _el = store.
|
|
610
|
+
var _el = store.get('matePreThinkingEl');
|
|
560
611
|
if (_el) {
|
|
561
612
|
_el.remove();
|
|
562
|
-
store.
|
|
613
|
+
store.set({ matePreThinkingEl: null });
|
|
563
614
|
}
|
|
564
615
|
}
|
|
565
616
|
|
|
566
|
-
// ---
|
|
617
|
+
// --- Ghost suggestion (prompt recommendation as ghost text) ---
|
|
618
|
+
|
|
619
|
+
var _ghostSuggestionText = "";
|
|
620
|
+
|
|
621
|
+
export function getGhostSuggestion() {
|
|
622
|
+
return _ghostSuggestionText;
|
|
623
|
+
}
|
|
567
624
|
|
|
568
625
|
export function showSuggestionChips(suggestion) {
|
|
569
|
-
if (!suggestion ||
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
});
|
|
580
|
-
_ctx.suggestionChipsEl.appendChild(chip);
|
|
581
|
-
_ctx.suggestionChipsEl.classList.remove("hidden");
|
|
582
|
-
_ctx.refreshIcons();
|
|
583
|
-
var messagesEl = _ctx.messagesEl;
|
|
584
|
-
requestAnimationFrame(function () {
|
|
585
|
-
var chipHeight = _ctx.suggestionChipsEl.offsetHeight || 0;
|
|
586
|
-
if (chipHeight > 0) {
|
|
587
|
-
messagesEl.style.paddingBottom = chipHeight + "px";
|
|
588
|
-
scrollToBottom();
|
|
589
|
-
}
|
|
590
|
-
});
|
|
626
|
+
if (!suggestion || store.get('processing')) return;
|
|
627
|
+
var inputEl = getInputEl();
|
|
628
|
+
// Only show ghost text if input is empty
|
|
629
|
+
if (inputEl && inputEl.value.trim()) return;
|
|
630
|
+
_ghostSuggestionText = suggestion;
|
|
631
|
+
var ghostEl = document.getElementById("ghost-suggestion");
|
|
632
|
+
if (!ghostEl) return;
|
|
633
|
+
ghostEl.innerHTML = escapeHtml(suggestion) +
|
|
634
|
+
' <span class="ghost-hint"><kbd>Enter</kbd> to send</span>';
|
|
635
|
+
ghostEl.classList.remove("hidden");
|
|
591
636
|
}
|
|
592
637
|
|
|
593
638
|
export function hideSuggestionChips() {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
639
|
+
_ghostSuggestionText = "";
|
|
640
|
+
var ghostEl = document.getElementById("ghost-suggestion");
|
|
641
|
+
if (ghostEl) {
|
|
642
|
+
ghostEl.innerHTML = "";
|
|
643
|
+
ghostEl.classList.add("hidden");
|
|
644
|
+
}
|
|
597
645
|
}
|
|
@@ -54,7 +54,7 @@ export function initSkillInstall() {
|
|
|
54
54
|
for (var j = 0; j < pendingSkillInstalls.length; j++) {
|
|
55
55
|
var s = pendingSkillInstalls[j];
|
|
56
56
|
if (s.installed) continue;
|
|
57
|
-
fetch(store.
|
|
57
|
+
fetch(store.get('basePath') + "api/install-skill", {
|
|
58
58
|
method: "POST",
|
|
59
59
|
headers: { "Content-Type": "application/json" },
|
|
60
60
|
body: JSON.stringify({ url: s.url, skill: s.name, scope: s.scope || "global" }),
|
|
@@ -151,9 +151,9 @@ export function handleSkillInstallWs(msg) {
|
|
|
151
151
|
if (pendingSkillInstalls[i].name === msg.skill) {
|
|
152
152
|
if (msg.success) {
|
|
153
153
|
pendingSkillInstalls[i].installed = true;
|
|
154
|
-
var _kis = Object.assign({}, store.
|
|
154
|
+
var _kis = Object.assign({}, store.get('knownInstalledSkills'));
|
|
155
155
|
_kis[msg.skill] = true;
|
|
156
|
-
store.
|
|
156
|
+
store.set({ knownInstalledSkills: _kis });
|
|
157
157
|
} else {
|
|
158
158
|
skillInstalling = false;
|
|
159
159
|
skillInstallOk.disabled = false;
|
|
@@ -189,7 +189,7 @@ export function handleSkillInstallWs(msg) {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
export function requireSkills(opts, cb) {
|
|
192
|
-
fetch(store.
|
|
192
|
+
fetch(store.get('basePath') + "api/check-skill-updates", {
|
|
193
193
|
method: "POST",
|
|
194
194
|
headers: { "Content-Type": "application/json" },
|
|
195
195
|
body: JSON.stringify({ skills: opts.skills }),
|
|
@@ -181,51 +181,22 @@ function removeSource(sourceId) {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
function renderChips() {
|
|
184
|
-
|
|
185
|
-
container.innerHTML = "";
|
|
186
|
-
|
|
187
|
-
for (var id of activeSourceIds) {
|
|
188
|
-
var chip = document.createElement("div");
|
|
189
|
-
chip.className = "context-chip";
|
|
190
|
-
|
|
191
|
-
var label = getSourceLabel(id);
|
|
192
|
-
var iconName = getSourceIcon(id);
|
|
193
|
-
|
|
194
|
-
var labelEl = document.createElement("span");
|
|
195
|
-
labelEl.className = "context-chip-label";
|
|
196
|
-
labelEl.innerHTML =
|
|
197
|
-
'<i data-lucide="' + iconName + '"></i>' +
|
|
198
|
-
'<span>' + escapeHtml(label) + '</span>';
|
|
199
|
-
chip.appendChild(labelEl);
|
|
200
|
-
|
|
201
|
-
var removeBtn = document.createElement("button");
|
|
202
|
-
removeBtn.type = "button";
|
|
203
|
-
removeBtn.className = "context-chip-remove";
|
|
204
|
-
removeBtn.title = "Remove";
|
|
205
|
-
removeBtn.innerHTML = '<i data-lucide="minus"></i>';
|
|
206
|
-
removeBtn.setAttribute("data-source-id", id);
|
|
207
|
-
removeBtn.addEventListener("click", function(e) {
|
|
208
|
-
e.stopPropagation();
|
|
209
|
-
removeSource(this.getAttribute("data-source-id"));
|
|
210
|
-
if (typeof lucide !== "undefined") lucide.createIcons();
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
chip.appendChild(removeBtn);
|
|
214
|
-
container.appendChild(chip);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Update add button label
|
|
184
|
+
// Update add button — show badge count when sources are active
|
|
218
185
|
var addBtn = document.getElementById("context-sources-add");
|
|
219
|
-
var labelSpan = addBtn.querySelector("
|
|
186
|
+
var labelSpan = addBtn.querySelector(".ctx-label");
|
|
187
|
+
var existingBadge = addBtn.querySelector(".ctx-badge");
|
|
220
188
|
if (activeSourceIds.size > 0) {
|
|
221
|
-
labelSpan.
|
|
222
|
-
|
|
189
|
+
if (labelSpan) labelSpan.style.display = "none";
|
|
190
|
+
if (!existingBadge) {
|
|
191
|
+
existingBadge = document.createElement("span");
|
|
192
|
+
existingBadge.className = "ctx-badge";
|
|
193
|
+
addBtn.appendChild(existingBadge);
|
|
194
|
+
}
|
|
195
|
+
existingBadge.textContent = activeSourceIds.size;
|
|
223
196
|
} else {
|
|
224
|
-
labelSpan.
|
|
225
|
-
|
|
197
|
+
if (labelSpan) { labelSpan.style.display = ""; }
|
|
198
|
+
if (existingBadge) existingBadge.remove();
|
|
226
199
|
}
|
|
227
|
-
|
|
228
|
-
if (typeof lucide !== "undefined") lucide.createIcons();
|
|
229
200
|
}
|
|
230
201
|
|
|
231
202
|
function renderPicker() {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// dom-refs.js - Shared DOM element references
|
|
2
|
+
// Lazy-cached getElementById lookups for elements used across multiple modules.
|
|
3
|
+
// Same pattern as ws-ref.js: infrastructure singleton, not state.
|
|
4
|
+
|
|
5
|
+
var _cache = {};
|
|
6
|
+
|
|
7
|
+
function ref(id) {
|
|
8
|
+
if (!_cache[id]) _cache[id] = document.getElementById(id);
|
|
9
|
+
return _cache[id];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getMessagesEl() { return ref("messages"); }
|
|
13
|
+
export function getInputEl() { return ref("input"); }
|
|
14
|
+
export function getSendBtn() { return ref("send-btn"); }
|
|
15
|
+
export function getSessionListEl() { return ref("session-list"); }
|
|
16
|
+
|
|
17
|
+
export function getStatusDot() {
|
|
18
|
+
return document.querySelector("#icon-strip-projects .icon-strip-item.active .icon-strip-status") ||
|
|
19
|
+
document.querySelector("#icon-strip-projects .icon-strip-wt-item.active .icon-strip-status") ||
|
|
20
|
+
document.querySelector("#icon-strip-users .icon-strip-mate.active .icon-strip-status");
|
|
21
|
+
}
|