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
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
// app-projects.js - Project list, switching, add/remove project modals
|
|
2
2
|
// Extracted from app.js (PR-29)
|
|
3
3
|
|
|
4
|
-
import { escapeHtml } from './utils.js';
|
|
4
|
+
import { escapeHtml, showToast } from './utils.js';
|
|
5
5
|
import { refreshIcons } from './icons.js';
|
|
6
6
|
import { parseEmojis } from './markdown.js';
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { store } from './store.js';
|
|
8
|
+
import { getWs, setWs } from './ws-ref.js';
|
|
9
|
+
import { getMessagesEl, getStatusDot } from './dom-refs.js';
|
|
10
|
+
import { userAvatarUrl } from './avatar.js';
|
|
11
|
+
import { showConfirm } from './app-misc.js';
|
|
12
|
+
// renderUserStrip is now reactive via store subscriber in sidebar-mates.js
|
|
13
|
+
import { renderIconStrip } from './sidebar-projects.js';
|
|
14
|
+
import { updateCrossProjectBlink, stopUrgentBlink, setActivity } from './app-favicon.js';
|
|
15
|
+
import { spawnDustParticles } from './sidebar.js';
|
|
16
|
+
import { isSearchOpen, closeSearch } from './session-search.js';
|
|
17
|
+
import { exitDmMode } from './app-dm.js';
|
|
18
|
+
import { isHomeHubVisible, hideHomeHub, showHomeHub } from './app-home-hub.js';
|
|
19
|
+
import { resetFileBrowser } from './filebrowser.js';
|
|
20
|
+
import { closeArchive } from './sticky-notes.js';
|
|
21
|
+
import { hideMemory } from './mate-memory.js';
|
|
22
|
+
import { isSchedulerOpen, closeScheduler, resetScheduler } from './scheduler.js';
|
|
23
|
+
import { connect, cancelReconnect, setStatus } from './app-connection.js';
|
|
24
|
+
import { setTurnCounter, setPrependAnchor, setActivityEl, setIsUserScrolledUp, hideSuggestionChips } from './app-rendering.js';
|
|
25
|
+
import { resetToolState, enableMainInput, resetTurnMetaCost } from './tools.js';
|
|
26
|
+
import { clearPendingImages } from './input.js';
|
|
27
|
+
import { clearAllMentionActive } from './sidebar-mates.js';
|
|
28
|
+
import { setRewindMode } from './rewind.js';
|
|
29
|
+
import { resetUsage, resetContext } from './app-panels.js';
|
|
30
|
+
import { resetRateLimitState } from './app-rate-limit.js';
|
|
31
|
+
import { closeSessionInfoPopover } from './app-header.js';
|
|
32
|
+
import { resetDebateState } from './debate.js';
|
|
33
|
+
import { removeDebateBottomBar } from './app-debate-ui.js';
|
|
9
34
|
|
|
10
35
|
// --- Module-owned state ---
|
|
11
36
|
var cachedProjects = [];
|
|
@@ -33,9 +58,7 @@ var addProjectDebounce = null;
|
|
|
33
58
|
var addProjectActiveIdx = -1;
|
|
34
59
|
var addProjectMode = "existing";
|
|
35
60
|
|
|
36
|
-
export function initProjects(
|
|
37
|
-
_ctx = ctx;
|
|
38
|
-
|
|
61
|
+
export function initProjects() {
|
|
39
62
|
// Init add-project modal DOM refs
|
|
40
63
|
addProjectModal = document.getElementById("add-project-modal");
|
|
41
64
|
addProjectInput = document.getElementById("add-project-input");
|
|
@@ -160,7 +183,7 @@ export function initProjects(ctx) {
|
|
|
160
183
|
});
|
|
161
184
|
|
|
162
185
|
// Project list add button
|
|
163
|
-
var projectListAddBtn =
|
|
186
|
+
var projectListAddBtn = document.getElementById("project-list-add");
|
|
164
187
|
if (projectListAddBtn) {
|
|
165
188
|
projectListAddBtn.addEventListener("click", function () {
|
|
166
189
|
openAddProjectModal();
|
|
@@ -197,12 +220,13 @@ export function updateProjectList(msg) {
|
|
|
197
220
|
else cachedRemovedProjects = [];
|
|
198
221
|
|
|
199
222
|
// Only re-render project strip + title bar if data or active slug changed
|
|
200
|
-
var
|
|
223
|
+
var currentSlug = store.get('currentSlug');
|
|
224
|
+
var slugChanged = currentSlug !== _lastRenderedSlug;
|
|
201
225
|
if (projectsChanged || slugChanged) {
|
|
202
|
-
_lastRenderedSlug =
|
|
226
|
+
_lastRenderedSlug = currentSlug;
|
|
203
227
|
var count = cachedProjectCount || 0;
|
|
204
228
|
renderProjectList();
|
|
205
|
-
var projectHint =
|
|
229
|
+
var projectHint = document.getElementById("project-hint");
|
|
206
230
|
if (count === 1 && projectHint) {
|
|
207
231
|
try {
|
|
208
232
|
if (!localStorage.getItem("clay-project-hint-dismissed")) {
|
|
@@ -217,40 +241,35 @@ export function updateProjectList(msg) {
|
|
|
217
241
|
// Update topbar with server-wide presence (renderTopbarPresence has its own guard)
|
|
218
242
|
if (msg.serverUsers) {
|
|
219
243
|
var newOnlineIds = msg.serverUsers.map(function (u) { return u.id; });
|
|
220
|
-
var prevOnlineIds =
|
|
221
|
-
|
|
244
|
+
var prevOnlineIds = store.get('cachedOnlineIds') || [];
|
|
245
|
+
store.set({ cachedOnlineIds: newOnlineIds });
|
|
222
246
|
renderTopbarPresence(msg.serverUsers);
|
|
223
|
-
//
|
|
224
|
-
if (!msg.allUsers && _ctx.cachedAllUsers.length > 0) {
|
|
225
|
-
var onlineChanged = newOnlineIds.length !== prevOnlineIds.length || newOnlineIds.some(function (id, i) { return id !== prevOnlineIds[i]; });
|
|
226
|
-
if (onlineChanged) {
|
|
227
|
-
_ctx.renderUserStrip(_ctx.cachedAllUsers, newOnlineIds, _ctx.myUserId, _ctx.cachedDmFavorites, _ctx.cachedDmConversations, _ctx.dmUnread, _ctx.dmRemovedUsers, _ctx.cachedMatesList);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
247
|
+
// renderUserStrip is handled by the store subscriber (fingerprint-guarded)
|
|
230
248
|
}
|
|
231
249
|
|
|
232
250
|
// Update user strip (DM targets) - renderUserStrip has its own fingerprint guard
|
|
233
251
|
if (msg.allUsers) {
|
|
234
|
-
|
|
235
|
-
if (msg.dmFavorites)
|
|
236
|
-
if (msg.dmConversations)
|
|
237
|
-
|
|
252
|
+
store.set({ cachedAllUsers: msg.allUsers });
|
|
253
|
+
if (msg.dmFavorites) store.set({ cachedDmFavorites: msg.dmFavorites });
|
|
254
|
+
if (msg.dmConversations) store.set({ cachedDmConversations: msg.dmConversations });
|
|
255
|
+
// renderUserStrip is handled by the store subscriber
|
|
256
|
+
var st2 = store.snap();
|
|
238
257
|
if (document.body.classList.contains("mate-dm-active") || document.body.classList.contains("wide-view")) {
|
|
239
|
-
var refreshedMyUser =
|
|
258
|
+
var refreshedMyUser = st2.cachedAllUsers.find(function (u) { return u.id === st2.myUserId; });
|
|
240
259
|
if (refreshedMyUser) {
|
|
241
260
|
document.body.dataset.myDisplayName = refreshedMyUser.displayName || refreshedMyUser.username || "";
|
|
242
|
-
document.body.dataset.myAvatarUrl =
|
|
261
|
+
document.body.dataset.myAvatarUrl = userAvatarUrl(refreshedMyUser, 36);
|
|
243
262
|
try { localStorage.setItem("clay_my_user", JSON.stringify({ displayName: refreshedMyUser.displayName, username: refreshedMyUser.username, avatarStyle: refreshedMyUser.avatarStyle, avatarSeed: refreshedMyUser.avatarSeed, avatarCustom: refreshedMyUser.avatarCustom })); } catch(e) {}
|
|
244
263
|
}
|
|
245
264
|
}
|
|
246
265
|
// Render my avatar (always present, hidden behind user-island)
|
|
247
266
|
var meEl = document.getElementById("icon-strip-me");
|
|
248
267
|
if (meEl && !meEl.hasChildNodes()) {
|
|
249
|
-
var myUser =
|
|
268
|
+
var myUser = st2.cachedAllUsers.find(function (u) { return u.id === st2.myUserId; });
|
|
250
269
|
if (myUser) {
|
|
251
270
|
var meAvatar = document.createElement("img");
|
|
252
271
|
meAvatar.className = "icon-strip-me-avatar";
|
|
253
|
-
meAvatar.src =
|
|
272
|
+
meAvatar.src = userAvatarUrl(myUser, 34);
|
|
254
273
|
meEl.appendChild(meAvatar);
|
|
255
274
|
}
|
|
256
275
|
}
|
|
@@ -273,7 +292,7 @@ export function renderTopbarPresence(serverUsers) {
|
|
|
273
292
|
var cu = serverUsers[cui];
|
|
274
293
|
var cuImg = document.createElement("img");
|
|
275
294
|
cuImg.className = "client-avatar";
|
|
276
|
-
cuImg.src =
|
|
295
|
+
cuImg.src = userAvatarUrl(cu, 24);
|
|
277
296
|
cuImg.alt = cu.displayName;
|
|
278
297
|
cuImg.dataset.tip = cu.displayName + " (@" + cu.username + ")";
|
|
279
298
|
if (cui > 0) cuImg.style.marginLeft = "-6px";
|
|
@@ -304,12 +323,13 @@ export function renderProjectList() {
|
|
|
304
323
|
worktreeAccessible: p.worktreeAccessible !== undefined ? p.worktreeAccessible : true,
|
|
305
324
|
};
|
|
306
325
|
});
|
|
307
|
-
var
|
|
308
|
-
|
|
326
|
+
var st = store.snap();
|
|
327
|
+
var iconStripActiveSlug = (st.mateProjectSlug && st.savedMainSlug) ? st.savedMainSlug : st.currentSlug;
|
|
328
|
+
renderIconStrip(iconStripProjects, iconStripActiveSlug);
|
|
309
329
|
// Update title bar project name and icon if it changed
|
|
310
|
-
if (!
|
|
330
|
+
if (!st.mateProjectSlug) {
|
|
311
331
|
for (var pi = 0; pi < cachedProjects.length; pi++) {
|
|
312
|
-
if (cachedProjects[pi].slug ===
|
|
332
|
+
if (cachedProjects[pi].slug === st.currentSlug) {
|
|
313
333
|
var updatedName = cachedProjects[pi].title || cachedProjects[pi].project;
|
|
314
334
|
var tbName = document.getElementById("title-bar-project-name");
|
|
315
335
|
if (tbName && updatedName) tbName.textContent = updatedName;
|
|
@@ -320,11 +340,11 @@ export function renderProjectList() {
|
|
|
320
340
|
tbIcon.textContent = pIcon;
|
|
321
341
|
parseEmojis(tbIcon);
|
|
322
342
|
tbIcon.classList.add("has-icon");
|
|
323
|
-
try { localStorage.setItem("clay-project-icon-" + (
|
|
343
|
+
try { localStorage.setItem("clay-project-icon-" + (st.currentSlug || "default"), pIcon); } catch (e) {}
|
|
324
344
|
} else {
|
|
325
345
|
tbIcon.textContent = "";
|
|
326
346
|
tbIcon.classList.remove("has-icon");
|
|
327
|
-
try { localStorage.removeItem("clay-project-icon-" + (
|
|
347
|
+
try { localStorage.removeItem("clay-project-icon-" + (st.currentSlug || "default")); } catch (e) {}
|
|
328
348
|
}
|
|
329
349
|
}
|
|
330
350
|
break;
|
|
@@ -332,49 +352,51 @@ export function renderProjectList() {
|
|
|
332
352
|
}
|
|
333
353
|
}
|
|
334
354
|
// Re-apply current socket status to the active icon's dot
|
|
335
|
-
var dot =
|
|
355
|
+
var dot = getStatusDot();
|
|
336
356
|
if (dot) {
|
|
337
|
-
if (
|
|
338
|
-
else if (
|
|
357
|
+
if (st.connected && st.processing) { dot.classList.add("connected"); dot.classList.add("processing"); }
|
|
358
|
+
else if (st.connected) { dot.classList.add("connected"); }
|
|
339
359
|
}
|
|
340
|
-
|
|
360
|
+
updateCrossProjectBlink();
|
|
341
361
|
}
|
|
342
362
|
|
|
343
363
|
export function resetClientState() {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
364
|
+
if (isSearchOpen()) closeSearch();
|
|
365
|
+
getMessagesEl().innerHTML = "";
|
|
366
|
+
store.set({ currentMsgEl: null });
|
|
367
|
+
store.set({ currentFullText: "" });
|
|
368
|
+
resetToolState();
|
|
369
|
+
clearPendingImages();
|
|
370
|
+
clearAllMentionActive();
|
|
371
|
+
setActivityEl(null);
|
|
372
|
+
store.set({ processing: false });
|
|
373
|
+
setTurnCounter(0);
|
|
374
|
+
store.set({ messageUuidMap: [] });
|
|
375
|
+
store.set({ historyFrom: 0 });
|
|
376
|
+
store.set({ historyTotal: 0 });
|
|
377
|
+
setPrependAnchor(null);
|
|
378
|
+
store.set({ loadingMore: false });
|
|
379
|
+
setIsUserScrolledUp(false);
|
|
380
|
+
document.getElementById("new-msg-btn").classList.add("hidden");
|
|
381
|
+
setRewindMode(false);
|
|
382
|
+
setActivity(null);
|
|
383
|
+
setStatus("connected");
|
|
384
|
+
if (!store.get('loopActive')) enableMainInput();
|
|
385
|
+
resetUsage();
|
|
386
|
+
resetTurnMetaCost();
|
|
387
|
+
resetContext();
|
|
388
|
+
resetRateLimitState();
|
|
389
|
+
var headerCtx = store.get('headerContextEl');
|
|
390
|
+
if (headerCtx) { headerCtx.remove(); store.set({ headerContextEl: null }); }
|
|
391
|
+
hideSuggestionChips();
|
|
392
|
+
closeSessionInfoPopover();
|
|
393
|
+
stopUrgentBlink();
|
|
372
394
|
// Clear debate UI and state from previous session
|
|
373
|
-
|
|
374
|
-
|
|
395
|
+
store.set({ debateStickyState: null });
|
|
396
|
+
resetDebateState();
|
|
375
397
|
var debateBadges = document.querySelectorAll(".debate-header-badge");
|
|
376
398
|
for (var dbi = 0; dbi < debateBadges.length; dbi++) debateBadges[dbi].remove();
|
|
377
|
-
|
|
399
|
+
removeDebateBottomBar();
|
|
378
400
|
var handBar = document.getElementById("debate-hand-raise-bar");
|
|
379
401
|
if (handBar) handBar.remove();
|
|
380
402
|
var debateSticky = document.getElementById("debate-sticky");
|
|
@@ -385,63 +407,41 @@ export function resetClientState() {
|
|
|
385
407
|
|
|
386
408
|
export function switchProject(slug) {
|
|
387
409
|
if (!slug) return;
|
|
388
|
-
var
|
|
389
|
-
var
|
|
390
|
-
|
|
391
|
-
if (
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
410
|
+
var st = store.snap();
|
|
411
|
+
var wasDm = st.dmMode;
|
|
412
|
+
var wasMate = st.dmMode && st.dmTargetUser && st.dmTargetUser.isMate;
|
|
413
|
+
if (st.dmMode) exitDmMode(wasMate);
|
|
414
|
+
if (isHomeHubVisible()) {
|
|
415
|
+
hideHomeHub();
|
|
416
|
+
if (slug === store.get('currentSlug')) return;
|
|
417
|
+
}
|
|
418
|
+
if (slug === store.get('currentSlug')) {
|
|
419
|
+
var ws = getWs();
|
|
420
|
+
if (wasDm && ws && ws.readyState === 1) {
|
|
421
|
+
ws.send(JSON.stringify({ type: "switch_session", id: store.get('activeSessionId') }));
|
|
398
422
|
}
|
|
399
423
|
return;
|
|
400
424
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
if (
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
425
|
+
resetFileBrowser();
|
|
426
|
+
closeArchive();
|
|
427
|
+
hideMemory();
|
|
428
|
+
if (isSchedulerOpen()) closeScheduler();
|
|
429
|
+
resetScheduler(slug);
|
|
430
|
+
store.set({ currentSlug: slug });
|
|
431
|
+
store.set({ basePath: "/p/" + slug + "/" });
|
|
432
|
+
store.set({ wsPath: "/p/" + slug + "/ws" });
|
|
409
433
|
if (document.documentElement.classList.contains("pwa-standalone")) {
|
|
410
434
|
history.replaceState(null, "", "/p/" + slug + "/");
|
|
411
435
|
} else {
|
|
412
436
|
history.pushState(null, "", "/p/" + slug + "/");
|
|
413
437
|
}
|
|
414
438
|
resetClientState();
|
|
415
|
-
|
|
439
|
+
connect();
|
|
416
440
|
}
|
|
417
441
|
|
|
418
442
|
export function showUpdateAvailable(msg) {
|
|
419
|
-
|
|
420
|
-
var
|
|
421
|
-
var updateVersion = $("update-version");
|
|
422
|
-
if (updatePillWrap && updateVersion && msg.version) {
|
|
423
|
-
updateVersion.textContent = "v" + msg.version;
|
|
424
|
-
updatePillWrap.classList.remove("hidden");
|
|
425
|
-
var updPill = $("update-pill");
|
|
426
|
-
var updResetBtn = $("update-now");
|
|
427
|
-
if (_ctx.isHeadlessMode) {
|
|
428
|
-
if (updPill) updPill.innerHTML = '<i data-lucide="arrow-up-circle"></i> <span id="update-version">v' + msg.version + '</span> available. Update manually';
|
|
429
|
-
if (updResetBtn) updResetBtn.style.display = "none";
|
|
430
|
-
} else {
|
|
431
|
-
if (updResetBtn) {
|
|
432
|
-
updResetBtn.innerHTML = '<i data-lucide="download"></i> Update now';
|
|
433
|
-
updResetBtn.disabled = false;
|
|
434
|
-
updResetBtn.style.display = "";
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
var updManualCmd = $("update-manual-cmd");
|
|
438
|
-
if (updManualCmd) {
|
|
439
|
-
var updTag = msg.version.indexOf("-beta") !== -1 ? "beta" : "latest";
|
|
440
|
-
updManualCmd.textContent = "npx clay-server@" + updTag;
|
|
441
|
-
}
|
|
442
|
-
refreshIcons();
|
|
443
|
-
}
|
|
444
|
-
var settingsUpdBtn = $("settings-update-check");
|
|
443
|
+
// Update the settings panel button only (top bar pill replaced by notification center)
|
|
444
|
+
var settingsUpdBtn = document.getElementById("settings-update-check");
|
|
445
445
|
if (settingsUpdBtn && msg.version) {
|
|
446
446
|
settingsUpdBtn.innerHTML = "";
|
|
447
447
|
var ic = document.createElement("i");
|
|
@@ -459,8 +459,9 @@ export function showUpdateAvailable(msg) {
|
|
|
459
459
|
export function confirmRemoveProject(slug, name) {
|
|
460
460
|
pendingRemoveSlug = slug;
|
|
461
461
|
pendingRemoveName = name;
|
|
462
|
-
|
|
463
|
-
|
|
462
|
+
var ws = getWs();
|
|
463
|
+
if (ws && ws.readyState === 1) {
|
|
464
|
+
ws.send(JSON.stringify({ type: "remove_project_check", slug: slug }));
|
|
464
465
|
}
|
|
465
466
|
}
|
|
466
467
|
|
|
@@ -476,15 +477,16 @@ export function handleRemoveProjectCheckResult(msg) {
|
|
|
476
477
|
var confirmMsg = isWt
|
|
477
478
|
? 'Delete worktree "' + name + '"? The branch and working directory will be removed from disk.'
|
|
478
479
|
: 'Remove "' + name + '"? You can re-add it later.';
|
|
479
|
-
|
|
480
|
+
showConfirm(confirmMsg, function () {
|
|
480
481
|
var iconEl = document.querySelector('.icon-strip-item[data-slug="' + slug + '"]');
|
|
481
482
|
if (iconEl) {
|
|
482
483
|
var rect = iconEl.getBoundingClientRect();
|
|
483
|
-
|
|
484
|
+
spawnDustParticles(rect.left + rect.width / 2, rect.top + rect.height / 2);
|
|
484
485
|
}
|
|
485
486
|
setTimeout(function () {
|
|
486
|
-
|
|
487
|
-
|
|
487
|
+
var ws = getWs();
|
|
488
|
+
if (ws && ws.readyState === 1) {
|
|
489
|
+
ws.send(JSON.stringify({ type: "remove_project", slug: slug }));
|
|
488
490
|
}
|
|
489
491
|
}, 1000);
|
|
490
492
|
}, "Remove", true);
|
|
@@ -533,16 +535,18 @@ function showRemoveProjectTaskDialog(slug, name, taskCount) {
|
|
|
533
535
|
if (moveBtn) {
|
|
534
536
|
moveBtn.addEventListener("click", function () {
|
|
535
537
|
var targetSlug = selectEl ? selectEl.value : null;
|
|
536
|
-
|
|
537
|
-
|
|
538
|
+
var ws = getWs();
|
|
539
|
+
if (ws && ws.readyState === 1 && targetSlug) {
|
|
540
|
+
ws.send(JSON.stringify({ type: "remove_project", slug: slug, moveTasksTo: targetSlug }));
|
|
538
541
|
}
|
|
539
542
|
close();
|
|
540
543
|
});
|
|
541
544
|
}
|
|
542
545
|
|
|
543
546
|
deleteBtn.addEventListener("click", function () {
|
|
544
|
-
|
|
545
|
-
|
|
547
|
+
var ws = getWs();
|
|
548
|
+
if (ws && ws.readyState === 1) {
|
|
549
|
+
ws.send(JSON.stringify({ type: "remove_project", slug: slug }));
|
|
546
550
|
}
|
|
547
551
|
close();
|
|
548
552
|
});
|
|
@@ -550,18 +554,19 @@ function showRemoveProjectTaskDialog(slug, name, taskCount) {
|
|
|
550
554
|
|
|
551
555
|
export function handleRemoveProjectResult(msg) {
|
|
552
556
|
if (msg.ok) {
|
|
553
|
-
|
|
557
|
+
var currentSlug = store.get('currentSlug');
|
|
558
|
+
if (msg.slug === currentSlug) {
|
|
554
559
|
var isWorktree = msg.slug.indexOf("--") !== -1;
|
|
555
560
|
var parentSlug = isWorktree ? msg.slug.split("--")[0] : null;
|
|
556
561
|
|
|
557
|
-
|
|
562
|
+
showToast(isWorktree ? "Worktree removed" : "Project removed", "success");
|
|
558
563
|
|
|
559
564
|
// Suppress disconnect overlay and reconnect by detaching the WS
|
|
560
|
-
var ws =
|
|
561
|
-
if (ws) { ws.onclose = null; ws.onerror = null; ws.close();
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
+
var ws = getWs();
|
|
566
|
+
if (ws) { ws.onclose = null; ws.onerror = null; ws.close(); setWs(null); }
|
|
567
|
+
cancelReconnect();
|
|
568
|
+
store.set({ connected: false });
|
|
569
|
+
document.getElementById("connect-overlay").classList.add("hidden");
|
|
565
570
|
if (!isWorktree) {
|
|
566
571
|
var removedProj = null;
|
|
567
572
|
for (var ri = 0; ri < cachedProjects.length; ri++) {
|
|
@@ -578,20 +583,20 @@ export function handleRemoveProjectResult(msg) {
|
|
|
578
583
|
}
|
|
579
584
|
cachedProjects = cachedProjects.filter(function (p) { return p.slug !== msg.slug; });
|
|
580
585
|
cachedProjectCount = cachedProjects.length;
|
|
581
|
-
|
|
586
|
+
store.set({ currentSlug: null });
|
|
582
587
|
renderProjectList();
|
|
583
588
|
resetClientState();
|
|
584
589
|
|
|
585
590
|
if (parentSlug) {
|
|
586
591
|
switchProject(parentSlug);
|
|
587
592
|
} else {
|
|
588
|
-
|
|
593
|
+
showHomeHub();
|
|
589
594
|
}
|
|
590
595
|
} else {
|
|
591
|
-
|
|
596
|
+
showToast(msg.slug.indexOf("--") !== -1 ? "Worktree removed" : "Project removed", "success");
|
|
592
597
|
}
|
|
593
598
|
} else {
|
|
594
|
-
|
|
599
|
+
showToast(msg.error || "Failed to remove project", "error");
|
|
595
600
|
}
|
|
596
601
|
}
|
|
597
602
|
|
|
@@ -647,9 +652,10 @@ export function openAddProjectModal() {
|
|
|
647
652
|
addProjectActiveIdx = -1;
|
|
648
653
|
addProjectOk.disabled = false;
|
|
649
654
|
var existingBtn = addProjectModal.querySelector('.add-project-mode-btn[data-mode="existing"]');
|
|
650
|
-
|
|
655
|
+
var st = store.snap();
|
|
656
|
+
if (st.isOsUsers) {
|
|
651
657
|
existingBtn.disabled = false;
|
|
652
|
-
var myUser =
|
|
658
|
+
var myUser = st.cachedAllUsers.find(function (u) { return u.id === st.myUserId; });
|
|
653
659
|
var isAdmin = myUser && myUser.role === "admin";
|
|
654
660
|
if (!isAdmin && myUser && myUser.linuxUser) {
|
|
655
661
|
// Non-admin: lock prefix to home directory
|
|
@@ -692,14 +698,15 @@ function renderRemovedProjectsList() {
|
|
|
692
698
|
item.dataset.path = rp.path;
|
|
693
699
|
item.addEventListener("click", function () {
|
|
694
700
|
var p = this.dataset.path;
|
|
695
|
-
|
|
696
|
-
|
|
701
|
+
var ws = getWs();
|
|
702
|
+
if (ws && ws.readyState === 1) {
|
|
703
|
+
ws.send(JSON.stringify({ type: "add_project", path: p }));
|
|
697
704
|
}
|
|
698
705
|
closeAddProjectModal();
|
|
699
706
|
});
|
|
700
707
|
var iconEl = document.createElement("span");
|
|
701
708
|
iconEl.className = "add-project-removed-icon";
|
|
702
|
-
iconEl.textContent = rp.icon || "
|
|
709
|
+
iconEl.textContent = rp.icon || "\uD83D\uDCC1";
|
|
703
710
|
item.appendChild(iconEl);
|
|
704
711
|
var info = document.createElement("div");
|
|
705
712
|
info.className = "add-project-removed-info";
|
|
@@ -744,8 +751,9 @@ function stripPrefix(fullPath) {
|
|
|
744
751
|
}
|
|
745
752
|
|
|
746
753
|
function requestBrowseDir(val) {
|
|
747
|
-
|
|
748
|
-
|
|
754
|
+
var ws = getWs();
|
|
755
|
+
if (!ws || ws.readyState !== 1) return;
|
|
756
|
+
ws.send(JSON.stringify({ type: "browse_dir", path: getFullPath(val) }));
|
|
749
757
|
}
|
|
750
758
|
|
|
751
759
|
export function handleBrowseDirResult(msg) {
|
|
@@ -785,10 +793,10 @@ export function handleAddProjectResult(msg) {
|
|
|
785
793
|
if (msg.ok) {
|
|
786
794
|
closeAddProjectModal();
|
|
787
795
|
if (msg.existing) {
|
|
788
|
-
|
|
796
|
+
showToast("Project already registered", "info");
|
|
789
797
|
} else {
|
|
790
798
|
var toastMsg = addProjectMode === "create" ? "Project created" : addProjectMode === "clone" ? "Project cloned" : "Project added";
|
|
791
|
-
|
|
799
|
+
showToast(toastMsg, "success");
|
|
792
800
|
if (msg.slug) {
|
|
793
801
|
switchProject(msg.slug);
|
|
794
802
|
}
|
|
@@ -826,20 +834,23 @@ function submitAddProject() {
|
|
|
826
834
|
if (addProjectMode === "existing") {
|
|
827
835
|
var val = getFullPath(addProjectInput.value).replace(/\/+$/, "");
|
|
828
836
|
if (!val) { addProjectOk.disabled = false; return; }
|
|
829
|
-
|
|
830
|
-
|
|
837
|
+
var ws = getWs();
|
|
838
|
+
if (ws && ws.readyState === 1) {
|
|
839
|
+
ws.send(JSON.stringify({ type: "add_project", path: val }));
|
|
831
840
|
}
|
|
832
841
|
} else if (addProjectMode === "create") {
|
|
833
842
|
var name = addProjectCreateInput.value.trim();
|
|
834
843
|
if (!name) { addProjectOk.disabled = false; return; }
|
|
835
|
-
|
|
836
|
-
|
|
844
|
+
var ws2 = getWs();
|
|
845
|
+
if (ws2 && ws2.readyState === 1) {
|
|
846
|
+
ws2.send(JSON.stringify({ type: "create_project", name: name }));
|
|
837
847
|
}
|
|
838
848
|
} else if (addProjectMode === "clone") {
|
|
839
849
|
var url = addProjectCloneInput.value.trim();
|
|
840
850
|
if (!url) { addProjectOk.disabled = false; return; }
|
|
841
|
-
|
|
842
|
-
|
|
851
|
+
var ws3 = getWs();
|
|
852
|
+
if (ws3 && ws3.readyState === 1) {
|
|
853
|
+
ws3.send(JSON.stringify({ type: "clone_project", url: url }));
|
|
843
854
|
}
|
|
844
855
|
}
|
|
845
856
|
}
|
|
@@ -210,10 +210,11 @@ export function updateRateLimitUsage(msg) {
|
|
|
210
210
|
rateLimitUsageEl = document.createElement("a");
|
|
211
211
|
rateLimitUsageEl.id = "rate-limit-usage-link";
|
|
212
212
|
rateLimitUsageEl.className = "top-bar-pill pill-dim usage-check-link";
|
|
213
|
-
|
|
213
|
+
var vendor = store.get('currentVendor') || "claude";
|
|
214
|
+
rateLimitUsageEl.href = vendor === "codex" ? "https://chatgpt.com/admin/usage" : "https://claude.ai/settings/usage";
|
|
214
215
|
rateLimitUsageEl.target = "_blank";
|
|
215
216
|
rateLimitUsageEl.rel = "noopener";
|
|
216
|
-
rateLimitUsageEl.title = "Check usage on claude.ai";
|
|
217
|
+
rateLimitUsageEl.title = vendor === "codex" ? "Check usage on ChatGPT" : "Check usage on claude.ai";
|
|
217
218
|
var ref = document.getElementById("skip-perms-pill");
|
|
218
219
|
topBarActions.insertBefore(rateLimitUsageEl, ref);
|
|
219
220
|
}
|
|
@@ -254,13 +255,13 @@ export function addScheduledMessageBubble(text, resetsAt) {
|
|
|
254
255
|
|
|
255
256
|
if (isChannel) {
|
|
256
257
|
// Channel mode: avatar + header with scheduled badge + message
|
|
257
|
-
var _me = store.
|
|
258
|
+
var _me = store.get('cachedAllUsers').find(function (u) { return u.id === store.get('myUserId'); });
|
|
258
259
|
if (!_me) { try { _me = JSON.parse(localStorage.getItem("clay_my_user") || "null"); } catch(e) {} }
|
|
259
260
|
var _myName = document.body.dataset.myDisplayName || (_me && (_me.displayName || _me.username)) || "Me";
|
|
260
261
|
|
|
261
262
|
var avi = document.createElement("img");
|
|
262
263
|
avi.className = "dm-bubble-avatar dm-bubble-avatar-me";
|
|
263
|
-
avi.src = document.body.dataset.myAvatarUrl || userAvatarUrl(_me || { id: store.
|
|
264
|
+
avi.src = document.body.dataset.myAvatarUrl || userAvatarUrl(_me || { id: store.get('myUserId') }, 36);
|
|
264
265
|
wrap.appendChild(avi);
|
|
265
266
|
|
|
266
267
|
var content = document.createElement("div");
|