clay-server 3.0.0 → 3.1.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/mates-prompts.js +3 -2
- package/lib/notes.js +6 -0
- package/lib/project-http.js +3 -6
- package/lib/project-session-notes.js +217 -0
- package/lib/project.js +84 -18
- package/lib/public/app.js +1 -4
- package/lib/public/css/icon-strip.css +190 -0
- package/lib/public/css/messages.css +104 -2
- package/lib/public/css/mobile-nav.css +0 -4
- package/lib/public/css/pane.css +27 -0
- package/lib/public/css/rewind.css +10 -0
- package/lib/public/css/sticky-notes.css +43 -0
- package/lib/public/css/title-bar.css +0 -169
- package/lib/public/index.html +0 -6
- package/lib/public/modules/app-favicon.js +10 -1
- package/lib/public/modules/app-home-hub.js +0 -2
- package/lib/public/modules/app-messages.js +18 -6
- package/lib/public/modules/app-projects.js +30 -43
- package/lib/public/modules/app-rendering.js +42 -3
- package/lib/public/modules/dom-refs.js +1 -0
- package/lib/public/modules/input.js +13 -0
- package/lib/public/modules/project-switcher.js +1 -2
- package/lib/public/modules/sidebar-mobile.js +6 -19
- package/lib/public/modules/sidebar-projects.js +232 -63
- package/lib/public/modules/split-pair-ui.js +30 -0
- package/lib/public/modules/sticky-note-markdown.js +89 -0
- package/lib/public/modules/sticky-notes.js +56 -103
- package/lib/sdk-bridge.js +25 -1
- package/lib/session-notes-mcp-server.js +39 -0
- package/lib/ws-schema.js +1 -0
- package/lib/yoke/adapters/codex.js +44 -8
- package/lib/yoke/mcp-bridge-server.js +7 -7
- package/package.json +1 -1
- package/lib/public/modules/branch-switcher.js +0 -178
- package/lib/public/modules/worktree-family.js +0 -60
|
@@ -20,7 +20,7 @@ import { renderMemoryList } from './mate-memory.js';
|
|
|
20
20
|
import { handlePaletteSessionSwitch, setPaletteVersion } from './command-palette.js';
|
|
21
21
|
import { handleFindInSessionResults } from './session-search.js';
|
|
22
22
|
import { syncPaneTitles, maybeRestoreSplitGroup, openGroup } from './split-view.js';
|
|
23
|
-
import { showPairDialog, handlePairCreated, handleSplitDelegation } from './split-pair-ui.js';
|
|
23
|
+
import { showPairDialog, handlePairCreated, handleSplitDelegation, showWorkerDelegationNotice, hideWorkerDelegationNotice } from './split-pair-ui.js';
|
|
24
24
|
import { handleInputSync, autoResize, builtinCommands, setScheduleBtnDisabled } from './input.js';
|
|
25
25
|
import { startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, closeToolGroup, removeToolFromGroup, resetToolState, getTools, getPlanContent, setPlanContent, renderPlanBanner, renderPlanCard, getTodoTools, handleTodoWrite, handleTaskCreate, handleTaskUpdate, applyDeadSessionTodoCompaction, isPlanFilePath, enableMainInput, addTurnMeta, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, initSubagentStop, updateSubagentProgress, updateSubagentTaskStatus, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionCancelled, markPermissionResolved, renderElicitationRequest, markElicitationResolved, renderUserDialogRequest, markUserDialogResolved, updateThinkingTokens } from './tools.js';
|
|
26
26
|
import { showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundEnabled } from './notifications.js';
|
|
@@ -33,7 +33,7 @@ import { handleTuiTranscriptState } from './tui-grab.js';
|
|
|
33
33
|
import { tuiModalHandleTermOutput, tuiModalHandleTermResized, tuiModalHandleTermExited, tuiModalHandleTermClosed, openTuiModal } from './tui-attention.js';
|
|
34
34
|
import { updateTerminalList, handleContextSourcesState, updateEmailAccountList, updateEmailUnreadCounts, handleEmailTestResult, handleEmailAddResult, handleEmailRemoveResult, handleEmailDefaults } from './context-sources.js';
|
|
35
35
|
import { refreshEmailSettings } from './user-settings.js';
|
|
36
|
-
import { handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted } from './sticky-notes.js';
|
|
36
|
+
import { handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, handleNoteWritten } from './sticky-notes.js';
|
|
37
37
|
import { handleSkillInstalled, handleSkillUninstalled } from './skills.js';
|
|
38
38
|
import { showRewindModal, onRewindComplete, setRewindMode, onRewindError, clearPendingRewindUuid, addRewindButton } from './rewind.js';
|
|
39
39
|
import { checkAdminAccess } from './admin.js';
|
|
@@ -50,7 +50,7 @@ import { handleWhatsNewState, handleWhatsNewSeenResult, setKnownEntries as setWh
|
|
|
50
50
|
import { closeArticle as closeWhatsNewArticle } from './whats-new-article.js';
|
|
51
51
|
import { resolvePaneSession, resolveSwitchedVendor } from './pane-session.js';
|
|
52
52
|
import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateContext, updateContextPanel, renderCtxPopover, updateStatusPanel } from './app-panels.js';
|
|
53
|
-
import { updateProjectList,
|
|
53
|
+
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress } from './app-projects.js';
|
|
54
54
|
import { updateHistorySentinel, prependOlderHistory } from './app-header.js';
|
|
55
55
|
import { hideHomeHub, handleHubSchedules } from './app-home-hub.js';
|
|
56
56
|
import { openDm, enterDmMode, exitDmMode, handleMateCreatedInApp, updateMateIconStatus, appendDmMessage, showDmTypingIndicator, buildMateInterviewPrompt } from './app-dm.js';
|
|
@@ -85,7 +85,8 @@ export function processMessage(msg) {
|
|
|
85
85
|
// Override title bar with mate name and re-apply color
|
|
86
86
|
var _mdn = (store.get('dmTargetUser').displayName || "New Mate");
|
|
87
87
|
if (headerTitleEl) headerTitleEl.textContent = _mdn;
|
|
88
|
-
|
|
88
|
+
var _tbpn = document.getElementById("title-bar-project-name");
|
|
89
|
+
if (_tbpn) _tbpn.textContent = _mdn;
|
|
89
90
|
var _mc2 = (store.get('dmTargetUser').profile && store.get('dmTargetUser').profile.avatarColor) || store.get('dmTargetUser').avatarColor || "#7c3aed";
|
|
90
91
|
var _tbc2 = document.querySelector(".title-bar-content");
|
|
91
92
|
if (_tbc2) { _tbc2.style.background = _mc2; _tbc2.classList.add("mate-dm-active"); }
|
|
@@ -298,7 +299,8 @@ export function processMessage(msg) {
|
|
|
298
299
|
if (store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate) {
|
|
299
300
|
var _mateDN = store.get('dmTargetUser').displayName || "New Mate";
|
|
300
301
|
headerTitleEl.textContent = _mateDN;
|
|
301
|
-
|
|
302
|
+
var tbProjectName = document.getElementById("title-bar-project-name");
|
|
303
|
+
if (tbProjectName) tbProjectName.textContent = _mateDN;
|
|
302
304
|
// Re-apply mate title bar styling (may be lost during project switch)
|
|
303
305
|
var _mc = (store.get('dmTargetUser').profile && store.get('dmTargetUser').profile.avatarColor) || store.get('dmTargetUser').avatarColor || "#7c3aed";
|
|
304
306
|
var _tbc = document.querySelector(".title-bar-content");
|
|
@@ -306,7 +308,8 @@ export function processMessage(msg) {
|
|
|
306
308
|
document.body.classList.add("mate-dm-active");
|
|
307
309
|
} else {
|
|
308
310
|
headerTitleEl.textContent = store.get('projectName');
|
|
309
|
-
|
|
311
|
+
var tbProjectName = document.getElementById("title-bar-project-name");
|
|
312
|
+
if (tbProjectName) tbProjectName.textContent = msg.title || store.get('projectName');
|
|
310
313
|
}
|
|
311
314
|
updatePageTitle();
|
|
312
315
|
if (msg.version) {
|
|
@@ -788,6 +791,9 @@ export function processMessage(msg) {
|
|
|
788
791
|
} else {
|
|
789
792
|
addUserMessage(msg.text, msg.images || null, msg.pastes || null, msg.from, msg.fromName, msg.delegated ? msg : null);
|
|
790
793
|
}
|
|
794
|
+
// Worker pane: a delegated instruction starts (or replays into) a
|
|
795
|
+
// driven turn; surface the composer notice. Cleared on "done".
|
|
796
|
+
if (msg.delegated) showWorkerDelegationNotice(msg.delegatedByTitle || null);
|
|
791
797
|
break;
|
|
792
798
|
|
|
793
799
|
case "plan_content":
|
|
@@ -1108,6 +1114,7 @@ export function processMessage(msg) {
|
|
|
1108
1114
|
removeMatePreThinking();
|
|
1109
1115
|
setActivity(null);
|
|
1110
1116
|
stopThinking();
|
|
1117
|
+
hideWorkerDelegationNotice();
|
|
1111
1118
|
markAllToolsDone();
|
|
1112
1119
|
closeToolGroup();
|
|
1113
1120
|
finalizeAssistantBlock();
|
|
@@ -1441,6 +1448,11 @@ export function processMessage(msg) {
|
|
|
1441
1448
|
handleNoteUpdated(msg);
|
|
1442
1449
|
break;
|
|
1443
1450
|
|
|
1451
|
+
case "note_written":
|
|
1452
|
+
showToast((msg.byTitle || "Agent") + ' left a note: "' + (msg.preview || "") + '"');
|
|
1453
|
+
handleNoteWritten(msg);
|
|
1454
|
+
break;
|
|
1455
|
+
|
|
1444
1456
|
case "note_deleted":
|
|
1445
1457
|
handleNoteDeleted(msg);
|
|
1446
1458
|
break;
|
|
@@ -32,7 +32,6 @@ import { resetRateLimitState } from './app-rate-limit.js';
|
|
|
32
32
|
import { closeSessionInfoPopover } from './app-header.js';
|
|
33
33
|
import { resetDebateState } from './debate.js';
|
|
34
34
|
import { removeDebateBottomBar } from './app-debate-ui.js';
|
|
35
|
-
import { familyOf as deriveFamily, displayProject } from './worktree-family.js';
|
|
36
35
|
|
|
37
36
|
// --- Module-owned state ---
|
|
38
37
|
var cachedProjects = [];
|
|
@@ -202,32 +201,6 @@ export function setCachedProjectCount(v) { cachedProjectCount = v; }
|
|
|
202
201
|
export function getCachedRemovedProjects() { return cachedRemovedProjects; }
|
|
203
202
|
export function setCachedRemovedProjects(v) { cachedRemovedProjects = v; }
|
|
204
203
|
|
|
205
|
-
export function familyOf(slug) { return deriveFamily(cachedProjects, slug); }
|
|
206
|
-
export function currentFamily() { return familyOf(store.get('currentSlug')); }
|
|
207
|
-
|
|
208
|
-
export function updateTitleBarProjectIdentity(fallbackName, fallbackIcon) {
|
|
209
|
-
if (store.get('dmMode') || store.get('mateProjectSlug')) {
|
|
210
|
-
var dmNameEl = document.getElementById("title-bar-project-name");
|
|
211
|
-
if (dmNameEl && fallbackName) dmNameEl.textContent = fallbackName;
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
var identity = displayProject(cachedProjects, store.get('currentSlug'));
|
|
215
|
-
var name = identity ? (identity.title || identity.project || identity.slug) : fallbackName;
|
|
216
|
-
var icon = identity ? (identity.icon || null) : (fallbackIcon || null);
|
|
217
|
-
var nameEl = document.getElementById("title-bar-project-name");
|
|
218
|
-
if (nameEl && name) nameEl.textContent = name;
|
|
219
|
-
var iconEl = document.getElementById("title-bar-project-icon");
|
|
220
|
-
if (!iconEl) return;
|
|
221
|
-
if (icon) {
|
|
222
|
-
iconEl.textContent = icon;
|
|
223
|
-
parseEmojis(iconEl);
|
|
224
|
-
iconEl.classList.add("has-icon");
|
|
225
|
-
} else {
|
|
226
|
-
iconEl.textContent = "";
|
|
227
|
-
iconEl.classList.remove("has-icon");
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
204
|
// --- Functions ---
|
|
232
205
|
|
|
233
206
|
export function updateProjectList(msg) {
|
|
@@ -242,7 +215,6 @@ export function updateProjectList(msg) {
|
|
|
242
215
|
_lastProjectsJson = projectsJson;
|
|
243
216
|
}
|
|
244
217
|
cachedProjects = msg.projects;
|
|
245
|
-
store.set({ projects: cachedProjects });
|
|
246
218
|
}
|
|
247
219
|
if (msg.removedProjects) cachedRemovedProjects = msg.removedProjects;
|
|
248
220
|
else if (msg.removedProjects === undefined) { /* keep cached */ }
|
|
@@ -354,12 +326,31 @@ export function renderProjectList() {
|
|
|
354
326
|
});
|
|
355
327
|
var st = store.snap();
|
|
356
328
|
var iconStripActiveSlug = (st.mateProjectSlug && st.savedMainSlug) ? st.savedMainSlug : st.currentSlug;
|
|
357
|
-
var activeFamily = deriveFamily(cachedProjects, iconStripActiveSlug);
|
|
358
|
-
if (activeFamily.parent) iconStripActiveSlug = activeFamily.parent.slug;
|
|
359
329
|
renderIconStrip(iconStripProjects, iconStripActiveSlug);
|
|
360
330
|
// Update title bar project name and icon if it changed
|
|
361
331
|
if (!st.mateProjectSlug) {
|
|
362
|
-
|
|
332
|
+
for (var pi = 0; pi < cachedProjects.length; pi++) {
|
|
333
|
+
if (cachedProjects[pi].slug === st.currentSlug) {
|
|
334
|
+
var updatedName = cachedProjects[pi].title || cachedProjects[pi].project;
|
|
335
|
+
var tbName = document.getElementById("title-bar-project-name");
|
|
336
|
+
if (tbName && updatedName) tbName.textContent = updatedName;
|
|
337
|
+
var tbIcon = document.getElementById("title-bar-project-icon");
|
|
338
|
+
if (tbIcon) {
|
|
339
|
+
var pIcon = cachedProjects[pi].icon || null;
|
|
340
|
+
if (pIcon) {
|
|
341
|
+
tbIcon.textContent = pIcon;
|
|
342
|
+
parseEmojis(tbIcon);
|
|
343
|
+
tbIcon.classList.add("has-icon");
|
|
344
|
+
try { localStorage.setItem("clay-project-icon-" + (st.currentSlug || "default"), pIcon); } catch (e) {}
|
|
345
|
+
} else {
|
|
346
|
+
tbIcon.textContent = "";
|
|
347
|
+
tbIcon.classList.remove("has-icon");
|
|
348
|
+
try { localStorage.removeItem("clay-project-icon-" + (st.currentSlug || "default")); } catch (e) {}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
363
354
|
}
|
|
364
355
|
// Re-apply current socket status to the active icon's dot
|
|
365
356
|
var dot = getStatusDot();
|
|
@@ -566,13 +557,9 @@ function showRemoveProjectTaskDialog(slug, name, taskCount) {
|
|
|
566
557
|
export function handleRemoveProjectResult(msg) {
|
|
567
558
|
if (msg.ok) {
|
|
568
559
|
var currentSlug = store.get('currentSlug');
|
|
569
|
-
var removedProj = null;
|
|
570
|
-
for (var ri = 0; ri < cachedProjects.length; ri++) {
|
|
571
|
-
if (cachedProjects[ri].slug === msg.slug) { removedProj = cachedProjects[ri]; break; }
|
|
572
|
-
}
|
|
573
|
-
var isWorktree = removedProj ? !!removedProj.isWorktree : msg.slug.indexOf("--") !== -1;
|
|
574
560
|
if (msg.slug === currentSlug) {
|
|
575
|
-
var
|
|
561
|
+
var isWorktree = msg.slug.indexOf("--") !== -1;
|
|
562
|
+
var parentSlug = isWorktree ? msg.slug.split("--")[0] : null;
|
|
576
563
|
|
|
577
564
|
showToast(isWorktree ? "Worktree removed" : "Project removed", "success");
|
|
578
565
|
|
|
@@ -583,6 +570,10 @@ export function handleRemoveProjectResult(msg) {
|
|
|
583
570
|
store.set({ connected: false });
|
|
584
571
|
document.getElementById("connect-overlay").classList.add("hidden");
|
|
585
572
|
if (!isWorktree) {
|
|
573
|
+
var removedProj = null;
|
|
574
|
+
for (var ri = 0; ri < cachedProjects.length; ri++) {
|
|
575
|
+
if (cachedProjects[ri].slug === msg.slug) { removedProj = cachedProjects[ri]; break; }
|
|
576
|
+
}
|
|
586
577
|
if (removedProj) {
|
|
587
578
|
cachedRemovedProjects.push({
|
|
588
579
|
path: removedProj.path || "",
|
|
@@ -594,7 +585,7 @@ export function handleRemoveProjectResult(msg) {
|
|
|
594
585
|
}
|
|
595
586
|
cachedProjects = cachedProjects.filter(function (p) { return p.slug !== msg.slug; });
|
|
596
587
|
cachedProjectCount = cachedProjects.length;
|
|
597
|
-
store.set({ currentSlug: null
|
|
588
|
+
store.set({ currentSlug: null });
|
|
598
589
|
renderProjectList();
|
|
599
590
|
resetClientState();
|
|
600
591
|
|
|
@@ -604,11 +595,7 @@ export function handleRemoveProjectResult(msg) {
|
|
|
604
595
|
showHomeHub();
|
|
605
596
|
}
|
|
606
597
|
} else {
|
|
607
|
-
showToast(
|
|
608
|
-
cachedProjects = cachedProjects.filter(function (p) { return p.slug !== msg.slug; });
|
|
609
|
-
cachedProjectCount = cachedProjects.length;
|
|
610
|
-
store.set({ projects: cachedProjects });
|
|
611
|
-
renderProjectList();
|
|
598
|
+
showToast(msg.slug.indexOf("--") !== -1 ? "Worktree removed" : "Project removed", "success");
|
|
612
599
|
}
|
|
613
600
|
} else {
|
|
614
601
|
showToast(msg.error || "Failed to remove project", "error");
|
|
@@ -430,6 +430,35 @@ export function addUserMessage(text, images, pastes, fromUserId, fromUserName, d
|
|
|
430
430
|
bubble.className = "bubble";
|
|
431
431
|
bubble.dir = "auto";
|
|
432
432
|
|
|
433
|
+
// Delegated work orders render as a self-contained card: identity lives
|
|
434
|
+
// in an in-card header strip (the generic bubble avatar/header are hidden
|
|
435
|
+
// via CSS) and the body is clean markdown on a neutral background.
|
|
436
|
+
if (isDelegated) {
|
|
437
|
+
var cardHead = document.createElement("div");
|
|
438
|
+
cardHead.className = "delegated-card-head";
|
|
439
|
+
var cardAvi = document.createElement("img");
|
|
440
|
+
cardAvi.className = "delegated-card-avatar";
|
|
441
|
+
cardAvi.src = VENDOR_AVATARS[delegatedMeta.delegatedByVendor] || VENDOR_AVATARS.claude;
|
|
442
|
+
cardAvi.alt = "";
|
|
443
|
+
cardHead.appendChild(cardAvi);
|
|
444
|
+
var cardHeadText = document.createElement("div");
|
|
445
|
+
cardHeadText.className = "delegated-card-headtext";
|
|
446
|
+
var eyebrow = document.createElement("span");
|
|
447
|
+
eyebrow.className = "delegated-card-eyebrow";
|
|
448
|
+
eyebrow.textContent = "Delegated task";
|
|
449
|
+
cardHeadText.appendChild(eyebrow);
|
|
450
|
+
var cardFrom = document.createElement("span");
|
|
451
|
+
cardFrom.className = "delegated-card-from";
|
|
452
|
+
cardFrom.textContent = delegatedMeta.delegatedByTitle || "Driver";
|
|
453
|
+
cardHeadText.appendChild(cardFrom);
|
|
454
|
+
cardHead.appendChild(cardHeadText);
|
|
455
|
+
var cardTime = document.createElement("span");
|
|
456
|
+
cardTime.className = "delegated-card-time";
|
|
457
|
+
cardTime.textContent = getMsgTime();
|
|
458
|
+
cardHead.appendChild(cardTime);
|
|
459
|
+
bubble.appendChild(cardHead);
|
|
460
|
+
}
|
|
461
|
+
|
|
433
462
|
if (images && images.length > 0) {
|
|
434
463
|
var imgRow = document.createElement("div");
|
|
435
464
|
imgRow.className = "bubble-images";
|
|
@@ -475,9 +504,19 @@ export function addUserMessage(text, images, pastes, fromUserId, fromUserName, d
|
|
|
475
504
|
}
|
|
476
505
|
|
|
477
506
|
if (text) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
507
|
+
if (isDelegated) {
|
|
508
|
+
// Delegated instructions are agent-authored work orders: render them
|
|
509
|
+
// as markdown (headings, lists, code) instead of a plain text blob.
|
|
510
|
+
var mdEl = document.createElement("div");
|
|
511
|
+
mdEl.className = "md-content delegated-brief";
|
|
512
|
+
mdEl.innerHTML = renderMarkdown(text);
|
|
513
|
+
highlightCodeBlocks(mdEl);
|
|
514
|
+
bubble.appendChild(mdEl);
|
|
515
|
+
} else {
|
|
516
|
+
var textEl = document.createElement("span");
|
|
517
|
+
textEl.textContent = text;
|
|
518
|
+
bubble.appendChild(textEl);
|
|
519
|
+
}
|
|
481
520
|
}
|
|
482
521
|
|
|
483
522
|
|
|
@@ -16,5 +16,6 @@ export function getSessionListEl() { return ref("session-list"); }
|
|
|
16
16
|
|
|
17
17
|
export function getStatusDot() {
|
|
18
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") ||
|
|
19
20
|
document.querySelector("#icon-strip-users .icon-strip-mate.active .icon-strip-status");
|
|
20
21
|
}
|
|
@@ -6,6 +6,7 @@ import { store } from './store.js';
|
|
|
6
6
|
import { mateAvatarUrl } from './avatar.js';
|
|
7
7
|
import { tuiIsActive, tuiSubmitText } from './session-tui-view.js';
|
|
8
8
|
import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
9
|
+
import { showToast } from './utils.js';
|
|
9
10
|
|
|
10
11
|
var ctx;
|
|
11
12
|
|
|
@@ -284,6 +285,18 @@ export function sendMessage() {
|
|
|
284
285
|
if (_selVendor) payload.vendor = _selVendor;
|
|
285
286
|
ctx.ws.send(JSON.stringify(payload));
|
|
286
287
|
|
|
288
|
+
// A turn blocked on an unanswered tool-permission request looks like a
|
|
289
|
+
// black hole: the new message queues silently while the dots keep
|
|
290
|
+
// bouncing, so users re-send the same text (and both copies land once
|
|
291
|
+
// the permission is answered). Point them at the pending card instead.
|
|
292
|
+
var pendingPerm = document.querySelector("#messages .permission-container:not(.resolved)");
|
|
293
|
+
if (pendingPerm) {
|
|
294
|
+
pendingPerm.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
295
|
+
pendingPerm.classList.add("permission-attention");
|
|
296
|
+
setTimeout(function () { pendingPerm.classList.remove("permission-attention"); }, 2600);
|
|
297
|
+
showToast("A tool permission request is still waiting — your message is queued until you answer it.", "error");
|
|
298
|
+
}
|
|
299
|
+
|
|
287
300
|
// First message commits the vendor and bumps the session into
|
|
288
301
|
// has-history state. The server won't re-fire session_switched after a
|
|
289
302
|
// message, so mirror the vendor-toggle/active-indicator swap locally:
|
|
@@ -19,7 +19,6 @@ import { getCachedProjects, switchProject } from './app-projects.js';
|
|
|
19
19
|
import { openDm } from './app-dm.js';
|
|
20
20
|
import { mateAvatarUrl } from './avatar.js';
|
|
21
21
|
import { parseEmojis } from './markdown.js';
|
|
22
|
-
import { switcherProjectName } from './worktree-family.js';
|
|
23
22
|
|
|
24
23
|
var _projectMru = []; // project slugs, most recent first
|
|
25
24
|
var _mateMru = []; // mate ids (mate_XXX), most recent first
|
|
@@ -264,7 +263,7 @@ function buildProjectEntries() {
|
|
|
264
263
|
var unreachable = p.isWorktree && p.worktreeAccessible === false;
|
|
265
264
|
return {
|
|
266
265
|
key: p.slug,
|
|
267
|
-
title:
|
|
266
|
+
title: p.title || p.project || p.slug,
|
|
268
267
|
icon: p.icon || null,
|
|
269
268
|
fallbackIcon: 'folder',
|
|
270
269
|
isCurrent: p.slug === store.get('currentSlug'),
|
|
@@ -38,7 +38,6 @@ import { showHomeHub } from './app-home-hub.js';
|
|
|
38
38
|
import { openTerminal } from './terminal.js';
|
|
39
39
|
import { requestKnowledgeList } from './mate-knowledge.js';
|
|
40
40
|
import { loadRootDirectory } from './filebrowser.js';
|
|
41
|
-
import { aggregateFamily, familyOf, parentProjects } from './worktree-family.js';
|
|
42
41
|
|
|
43
42
|
// --- Mobile state ---
|
|
44
43
|
var mobileChatSheetOpen = false;
|
|
@@ -148,22 +147,10 @@ function closeMobileSheet() {
|
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
function renderSheetProjects(listEl) {
|
|
151
|
-
var
|
|
152
|
-
var parents = parentProjects(projects);
|
|
153
|
-
var activeFamily = familyOf(projects, getCachedCurrentSlug());
|
|
154
|
-
var activeSlug = activeFamily.parent ? activeFamily.parent.slug : getCachedCurrentSlug();
|
|
155
|
-
|
|
156
|
-
for (var i = 0; i < parents.length; i++) {
|
|
150
|
+
for (var i = 0; i < getCachedProjectList().length; i++) {
|
|
157
151
|
(function (p) {
|
|
158
|
-
var family = familyOf(projects, p.slug);
|
|
159
|
-
var displayProject = aggregateFamily(p, family.worktrees);
|
|
160
|
-
var hasWorktreeUnread = family.worktrees.some(function (worktree) { return worktree.unread > 0; });
|
|
161
|
-
var hasWorktreePending = family.worktrees.some(function (worktree) { return worktree.pendingPermissions > 0; });
|
|
162
152
|
var el = document.createElement("button");
|
|
163
|
-
el.className = "mobile-project-item" + (p.slug ===
|
|
164
|
-
if ((displayProject.pendingPermissions > 0 && p.slug !== activeSlug) || hasWorktreePending) {
|
|
165
|
-
el.classList.add("has-pending-perm");
|
|
166
|
-
}
|
|
153
|
+
el.className = "mobile-project-item" + (p.slug === getCachedCurrentSlug() ? " active" : "");
|
|
167
154
|
|
|
168
155
|
var abbrev = document.createElement("span");
|
|
169
156
|
abbrev.className = "mobile-project-abbrev";
|
|
@@ -180,16 +167,16 @@ function renderSheetProjects(listEl) {
|
|
|
180
167
|
name.textContent = p.name;
|
|
181
168
|
el.appendChild(name);
|
|
182
169
|
|
|
183
|
-
if (
|
|
170
|
+
if (p.isProcessing) {
|
|
184
171
|
var dot = document.createElement("span");
|
|
185
172
|
dot.className = "mobile-project-processing";
|
|
186
173
|
el.appendChild(dot);
|
|
187
174
|
}
|
|
188
175
|
|
|
189
|
-
if (
|
|
176
|
+
if (p.unread > 0 && p.slug !== getCachedCurrentSlug()) {
|
|
190
177
|
var mBadge = document.createElement("span");
|
|
191
178
|
mBadge.className = "mobile-project-unread";
|
|
192
|
-
mBadge.textContent =
|
|
179
|
+
mBadge.textContent = p.unread > 99 ? "99+" : String(p.unread);
|
|
193
180
|
el.appendChild(mBadge);
|
|
194
181
|
}
|
|
195
182
|
|
|
@@ -199,7 +186,7 @@ function renderSheetProjects(listEl) {
|
|
|
199
186
|
});
|
|
200
187
|
|
|
201
188
|
listEl.appendChild(el);
|
|
202
|
-
})(
|
|
189
|
+
})(getCachedProjectList()[i]);
|
|
203
190
|
}
|
|
204
191
|
}
|
|
205
192
|
|