clay-server 2.31.0 → 2.32.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser-mcp-server.js +32 -44
- package/lib/codex-defaults.js +18 -0
- package/lib/debate-mcp-server.js +14 -31
- package/lib/mcp-local.js +31 -1
- package/lib/project-connection.js +9 -6
- package/lib/project-debate.js +8 -0
- package/lib/project-filesystem.js +47 -1
- package/lib/project-http.js +75 -8
- package/lib/project-mate-interaction.js +102 -16
- package/lib/project-mcp.js +4 -0
- package/lib/project-notifications.js +9 -0
- package/lib/project-sessions.js +94 -51
- package/lib/project-user-message.js +12 -7
- package/lib/project.js +234 -99
- package/lib/public/app.js +135 -454
- 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 +338 -104
- 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 +26 -0
- package/lib/public/css/tooltip.css +47 -0
- package/lib/public/index.html +78 -26
- 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 +175 -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 +199 -153
- package/lib/public/modules/app-misc.js +23 -12
- package/lib/public/modules/app-notifications.js +119 -9
- package/lib/public/modules/app-panels.js +203 -49
- package/lib/public/modules/app-projects.js +161 -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 +102 -66
- package/lib/public/modules/dom-refs.js +21 -0
- package/lib/public/modules/filebrowser.js +173 -2
- package/lib/public/modules/input.js +122 -0
- package/lib/public/modules/markdown.js +5 -1
- 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 +79 -35
- 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/terminal.js +12 -0
- package/lib/public/modules/tools.js +18 -13
- package/lib/public/modules/tooltip.js +32 -5
- package/lib/sdk-bridge.js +562 -1114
- package/lib/sdk-message-processor.js +150 -135
- package/lib/sdk-worker.js +4 -0
- package/lib/server-dm.js +1 -0
- package/lib/server.js +86 -1
- package/lib/sessions.js +81 -37
- package/lib/ws-schema.js +2 -0
- package/lib/yoke/adapters/claude-worker.js +559 -0
- package/lib/yoke/adapters/claude.js +1483 -0
- package/lib/yoke/adapters/codex.js +1121 -0
- package/lib/yoke/adapters/gemini.js +709 -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 +98 -0
- package/lib/yoke/mcp-bridge-server.js +294 -0
- package/lib/yoke/package.json +7 -0
- package/package.json +3 -1
|
@@ -13,6 +13,9 @@ var _extRequestCallbacks = {};
|
|
|
13
13
|
|
|
14
14
|
// Queue for extension messages that arrived before WS was ready
|
|
15
15
|
var _pendingExtMessages = [];
|
|
16
|
+
// Cache last extension state so we can resend on WS reconnect (server restart)
|
|
17
|
+
var _lastTabListMsg = null;
|
|
18
|
+
var _lastMcpServersMsg = null;
|
|
16
19
|
|
|
17
20
|
function sendOrQueue(msgObj) {
|
|
18
21
|
var ws = getWs();
|
|
@@ -24,14 +27,20 @@ function sendOrQueue(msgObj) {
|
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
export function flushPendingExtMessages() {
|
|
27
|
-
if (_pendingExtMessages.length === 0) return;
|
|
28
30
|
var ws = getWs();
|
|
29
31
|
if (!ws || ws.readyState !== 1) return;
|
|
30
|
-
|
|
31
|
-
_pendingExtMessages
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// Flush queued messages from before WS was ready
|
|
33
|
+
if (_pendingExtMessages.length > 0) {
|
|
34
|
+
var queued = _pendingExtMessages.slice();
|
|
35
|
+
_pendingExtMessages = [];
|
|
36
|
+
for (var i = 0; i < queued.length; i++) {
|
|
37
|
+
ws.send(JSON.stringify(queued[i]));
|
|
38
|
+
}
|
|
34
39
|
}
|
|
40
|
+
// Resend cached extension state on every WS reconnect so the server
|
|
41
|
+
// re-registers _extensionWs and rebuilds MCP proxy servers
|
|
42
|
+
if (_lastTabListMsg) ws.send(JSON.stringify(_lastTabListMsg));
|
|
43
|
+
if (_lastMcpServersMsg) ws.send(JSON.stringify(_lastMcpServersMsg));
|
|
35
44
|
}
|
|
36
45
|
|
|
37
46
|
export function initMisc() {
|
|
@@ -121,11 +130,9 @@ export function initMisc() {
|
|
|
121
130
|
if (msg.type === "clay_ext_tab_list") {
|
|
122
131
|
setExtensionConnected(true);
|
|
123
132
|
updateBrowserTabList(msg.tabs);
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
tabs: msg.tabs
|
|
128
|
-
});
|
|
133
|
+
// Cache and send (or queue) - resent on WS reconnect via flushPendingExtMessages
|
|
134
|
+
_lastTabListMsg = { type: "browser_tab_list", tabs: msg.tabs };
|
|
135
|
+
sendOrQueue(_lastTabListMsg);
|
|
129
136
|
}
|
|
130
137
|
if (msg.type === "clay_ext_result") {
|
|
131
138
|
handleExtensionResult(msg.requestId, msg.result);
|
|
@@ -135,12 +142,14 @@ export function initMisc() {
|
|
|
135
142
|
}
|
|
136
143
|
|
|
137
144
|
// MCP bridge: extension reports available MCP servers (queue if WS not ready yet)
|
|
145
|
+
// Cache for resend on WS reconnect (server restart loses _availableServers)
|
|
138
146
|
if (msg.type === "mcp_servers_available") {
|
|
139
|
-
|
|
147
|
+
_lastMcpServersMsg = {
|
|
140
148
|
type: "mcp_servers_available",
|
|
141
149
|
servers: msg.servers,
|
|
142
150
|
hostConnected: msg.hostConnected
|
|
143
|
-
}
|
|
151
|
+
};
|
|
152
|
+
sendOrQueue(_lastMcpServersMsg);
|
|
144
153
|
}
|
|
145
154
|
|
|
146
155
|
// MCP bridge: tool result from extension (tool results should not be queued,
|
|
@@ -161,6 +170,7 @@ export function initMisc() {
|
|
|
161
170
|
|
|
162
171
|
// Forward an MCP tool call from the server to the Chrome extension
|
|
163
172
|
export function forwardMcpToolCall(msg) {
|
|
173
|
+
console.log("[mcp] forwarding to extension:", msg.callId, msg.server, msg.method);
|
|
164
174
|
window.postMessage({
|
|
165
175
|
source: "clay-page",
|
|
166
176
|
payload: {
|
|
@@ -185,6 +195,7 @@ export function setHttpMcpServers(servers) {
|
|
|
185
195
|
}
|
|
186
196
|
|
|
187
197
|
export function handleMcpToolCallMessage(msg) {
|
|
198
|
+
console.log("[mcp] tool call received from server:", msg.callId, msg.server, msg.params && msg.params.name);
|
|
188
199
|
var httpUrl = _httpMcpServers[msg.server];
|
|
189
200
|
if (httpUrl) {
|
|
190
201
|
// HTTP transport: call directly via fetch
|
|
@@ -9,12 +9,19 @@ import { getWs } from './ws-ref.js';
|
|
|
9
9
|
import { openDm } from './app-dm.js';
|
|
10
10
|
import { getCachedProjects } from './app-projects.js';
|
|
11
11
|
import { switchProject } from './app-projects.js';
|
|
12
|
+
import { mateAvatarUrl } from './avatar.js';
|
|
12
13
|
var notifications = [];
|
|
13
14
|
var unreadCount = 0;
|
|
14
15
|
var bannerContainer = null;
|
|
15
16
|
var bellBtn = null;
|
|
16
17
|
var badgeEl = null;
|
|
17
18
|
|
|
19
|
+
// --- Update available banner state ---
|
|
20
|
+
// Server pushes update_available on an hourly boundary; dismissal is
|
|
21
|
+
// per-banner-instance and doesn't need to persist. The next server push
|
|
22
|
+
// (next hour) acts as a fresh ping.
|
|
23
|
+
var pendingUpdateMsg = null;
|
|
24
|
+
|
|
18
25
|
// ========================================================
|
|
19
26
|
// Init
|
|
20
27
|
// ========================================================
|
|
@@ -44,7 +51,12 @@ function showAllBanners() {
|
|
|
44
51
|
// Clear existing banners first
|
|
45
52
|
if (bannerContainer) bannerContainer.innerHTML = "";
|
|
46
53
|
|
|
47
|
-
if (
|
|
54
|
+
// Re-add update banner if present (may be suppressed by recent dismiss)
|
|
55
|
+
if (pendingUpdateMsg) showUpdateBanner(pendingUpdateMsg);
|
|
56
|
+
|
|
57
|
+
// Check if any banner actually got rendered (update banner can be suppressed)
|
|
58
|
+
var hasVisibleBanner = bannerContainer.children.length > 0;
|
|
59
|
+
if (notifications.length === 0 && !hasVisibleBanner) {
|
|
48
60
|
showBanner({
|
|
49
61
|
id: "_empty",
|
|
50
62
|
type: "info",
|
|
@@ -71,14 +83,17 @@ function showBanner(notif, autoDismissMs) {
|
|
|
71
83
|
var projectIcon = isEmpty ? null : getProjectIcon(notif.slug);
|
|
72
84
|
var projectName = isEmpty ? "" : getProjectName(notif.slug);
|
|
73
85
|
var isPermission = notif.type === "permission_request" && notif.meta && notif.meta.requestId;
|
|
86
|
+
var mate = isEmpty ? null : getMateForNotification(notif);
|
|
74
87
|
|
|
75
88
|
var banner = document.createElement("div");
|
|
76
89
|
banner.className = "notif-banner" + (isPermission ? " notif-banner-permission" : "");
|
|
77
90
|
if (!isEmpty) banner.setAttribute("data-notif-id", notif.id);
|
|
78
91
|
|
|
79
|
-
var iconHtmlStr =
|
|
80
|
-
? '<
|
|
81
|
-
:
|
|
92
|
+
var iconHtmlStr = mate
|
|
93
|
+
? '<img class="notif-banner-avatar" src="' + escapeHtml(mateAvatarUrl(mate, 32)) + '" alt="' + escapeHtml(mate.displayName || mate.name || "Mate") + '">'
|
|
94
|
+
: projectIcon
|
|
95
|
+
? '<span class="notif-banner-emoji">' + projectIcon + '</span>'
|
|
96
|
+
: iconHtml(isEmpty ? "check-circle" : "folder");
|
|
82
97
|
|
|
83
98
|
// Format permission title as "Can I ..." style
|
|
84
99
|
if (isPermission && notif.meta) {
|
|
@@ -93,7 +108,7 @@ function showBanner(notif, autoDismissMs) {
|
|
|
93
108
|
actionsHtml =
|
|
94
109
|
'<div class="notif-banner-actions">' +
|
|
95
110
|
'<button class="notif-banner-allow">Sure</button>' +
|
|
96
|
-
'<button class="notif-banner-always">
|
|
111
|
+
'<button class="notif-banner-always">Allow for session</button>' +
|
|
97
112
|
'<button class="notif-banner-deny">No</button>' +
|
|
98
113
|
'<button class="notif-banner-goto" title="Go to session">' + iconHtml("external-link") + '</button>' +
|
|
99
114
|
'</div>';
|
|
@@ -237,7 +252,7 @@ export function handleNotificationCreated(msg) {
|
|
|
237
252
|
var notif = msg.notification;
|
|
238
253
|
|
|
239
254
|
// Auto-dismiss if it's for the session the user is currently viewing
|
|
240
|
-
var activeSession = store.
|
|
255
|
+
var activeSession = store.get('activeSessionId') || null;
|
|
241
256
|
console.log("[notif] created:", notif.type, "sessionId=" + notif.sessionId + "(" + typeof notif.sessionId + ")", "active=" + activeSession + "(" + typeof activeSession + ")", "match=" + (notif.sessionId == activeSession));
|
|
242
257
|
if (notif.sessionId && String(notif.sessionId) === String(activeSession)) {
|
|
243
258
|
dismissNotif(notif.id);
|
|
@@ -292,12 +307,16 @@ function updateBadge() {
|
|
|
292
307
|
// ========================================================
|
|
293
308
|
|
|
294
309
|
function navigateToNotification(notif) {
|
|
295
|
-
|
|
296
|
-
|
|
310
|
+
var mateId = notif.mateId || deriveMateIdFromNotification(notif);
|
|
311
|
+
if (mateId) {
|
|
312
|
+
if (notif.sessionId) {
|
|
313
|
+
try { sessionStorage.setItem("pending-notif-session", notif.sessionId); } catch (e) {}
|
|
314
|
+
}
|
|
315
|
+
openDm(mateId);
|
|
297
316
|
return;
|
|
298
317
|
}
|
|
299
318
|
|
|
300
|
-
var currentSlug = store.
|
|
319
|
+
var currentSlug = store.get('currentSlug') || "";
|
|
301
320
|
var needsProjectSwitch = notif.slug && notif.slug !== currentSlug;
|
|
302
321
|
|
|
303
322
|
if (needsProjectSwitch) {
|
|
@@ -314,6 +333,97 @@ function navigateToNotification(notif) {
|
|
|
314
333
|
}
|
|
315
334
|
}
|
|
316
335
|
|
|
336
|
+
function deriveMateIdFromNotification(notif) {
|
|
337
|
+
if (!notif) return null;
|
|
338
|
+
if (typeof notif.slug === "string" && notif.slug.indexOf("mate-") === 0) {
|
|
339
|
+
return notif.slug.substring(5) || null;
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function getMateForNotification(notif) {
|
|
345
|
+
var mateId = notif && notif.meta ? notif.meta.avatarMateId : null;
|
|
346
|
+
if (!mateId) mateId = deriveMateIdFromNotification(notif);
|
|
347
|
+
if (!mateId) return null;
|
|
348
|
+
var mates = store.get('cachedMatesList') || [];
|
|
349
|
+
for (var i = 0; i < mates.length; i++) {
|
|
350
|
+
if (mates[i] && mates[i].id === mateId) return mates[i];
|
|
351
|
+
}
|
|
352
|
+
return { id: mateId };
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ========================================================
|
|
356
|
+
// Update available banner
|
|
357
|
+
// ========================================================
|
|
358
|
+
|
|
359
|
+
export function showUpdateBanner(msg) {
|
|
360
|
+
if (!msg || !msg.version) return;
|
|
361
|
+
pendingUpdateMsg = msg;
|
|
362
|
+
if (!bannerContainer) return;
|
|
363
|
+
|
|
364
|
+
// Remove any existing update banner
|
|
365
|
+
var existing = bannerContainer.querySelector('[data-notif-id="_update"]');
|
|
366
|
+
if (existing) removeBanner(existing);
|
|
367
|
+
|
|
368
|
+
var isHeadless = store.get('isHeadlessMode');
|
|
369
|
+
var updTag = msg.version.indexOf("-beta") !== -1 ? "beta" : "latest";
|
|
370
|
+
|
|
371
|
+
var banner = document.createElement("div");
|
|
372
|
+
banner.className = "notif-banner notif-banner-update";
|
|
373
|
+
banner.setAttribute("data-notif-id", "_update");
|
|
374
|
+
|
|
375
|
+
var actionsHtml = '';
|
|
376
|
+
if (!isHeadless) {
|
|
377
|
+
actionsHtml =
|
|
378
|
+
'<div class="notif-banner-actions">' +
|
|
379
|
+
'<button class="notif-banner-update-now">Update now</button>' +
|
|
380
|
+
'</div>';
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
banner.innerHTML =
|
|
384
|
+
'<div class="notif-banner-icon"><img src="/icon-banded-76.png" width="32" height="32" alt="Clay" style="border-radius:8px"></div>' +
|
|
385
|
+
'<div class="notif-banner-body">' +
|
|
386
|
+
'<div class="notif-banner-project">CLAY</div>' +
|
|
387
|
+
'<div class="notif-banner-title">v' + escapeHtml(msg.version) + ' is available</div>' +
|
|
388
|
+
(isHeadless
|
|
389
|
+
? '<div class="notif-banner-text">Run: npx clay-server@' + escapeHtml(updTag) + '</div>'
|
|
390
|
+
: '') +
|
|
391
|
+
actionsHtml +
|
|
392
|
+
'</div>' +
|
|
393
|
+
'<button class="notif-banner-close">' + iconHtml("x") + '</button>';
|
|
394
|
+
|
|
395
|
+
bannerContainer.appendChild(banner);
|
|
396
|
+
refreshIcons();
|
|
397
|
+
|
|
398
|
+
requestAnimationFrame(function () {
|
|
399
|
+
banner.classList.add("show");
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// "Update now" button
|
|
403
|
+
var updateBtn = banner.querySelector(".notif-banner-update-now");
|
|
404
|
+
if (updateBtn) {
|
|
405
|
+
updateBtn.addEventListener("click", function (e) {
|
|
406
|
+
e.stopPropagation();
|
|
407
|
+
var ws = getWs();
|
|
408
|
+
if (ws && ws.readyState === 1) {
|
|
409
|
+
ws.send(JSON.stringify({ type: "update_now" }));
|
|
410
|
+
updateBtn.textContent = "Updating...";
|
|
411
|
+
updateBtn.disabled = true;
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Close button -> dismiss. No local throttle; the server pushes a new
|
|
417
|
+
// update_available on the next hour boundary, which re-shows naturally.
|
|
418
|
+
var closeBtn = banner.querySelector(".notif-banner-close");
|
|
419
|
+
if (closeBtn) {
|
|
420
|
+
closeBtn.addEventListener("click", function (e) {
|
|
421
|
+
e.stopPropagation();
|
|
422
|
+
removeBanner(banner);
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
317
427
|
// ========================================================
|
|
318
428
|
// Helpers
|
|
319
429
|
// ========================================================
|