clay-server 5.1.0-beta.1 → 5.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/LICENSES/README.md +4 -0
- package/LICENSES/dicebear-avatars.md +16 -0
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon.js +2 -0
- package/lib/dicebear-avatar.js +62 -0
- package/lib/knowledge-db-service.js +175 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-document-index.js +49 -0
- package/lib/knowledge-draft-store.js +56 -0
- package/lib/knowledge-file-store.js +199 -0
- package/lib/knowledge-markdown.js +128 -0
- package/lib/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +36 -21
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates.js +18 -0
- package/lib/project-connection.js +36 -2
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +1 -0
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-sessions.js +39 -2
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +59 -18
- package/lib/public/app.js +73 -34
- package/lib/public/clay-studio-wordmark-bold.svg +20 -0
- package/lib/public/css/clay-workspace.css +105 -0
- package/lib/public/css/debates-workbench.css +47 -0
- package/lib/public/css/home-debate-live.css +26 -0
- package/lib/public/css/home-hub.css +3 -1
- package/lib/public/css/home-mate-model-picker.css +15 -131
- package/lib/public/css/home-mate-settings.css +168 -16
- package/lib/public/css/icon-strip.css +249 -32
- package/lib/public/css/mate-conversation.css +176 -0
- package/lib/public/css/mate-knowledge-workbench.css +118 -0
- package/lib/public/css/mate-workspace-color.css +16 -0
- package/lib/public/css/mates.css +28 -28
- package/lib/public/css/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +8 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +151 -0
- package/lib/public/css/worker-delegation.css +47 -0
- package/lib/public/css/worker-proposal.css +72 -150
- package/lib/public/css/you.css +74 -0
- package/lib/public/index.html +33 -101
- package/lib/public/modules/account-island.js +230 -0
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- package/lib/public/modules/app-header.js +106 -0
- package/lib/public/modules/app-message-router.js +12 -3
- package/lib/public/modules/app-messages.js +34 -9
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +25 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- package/lib/public/modules/cursor-sharing-preference.js +3 -3
- package/lib/public/modules/debate-controls.js +299 -0
- package/lib/public/modules/debate.js +2 -0
- package/lib/public/modules/debates-workbench.js +339 -0
- package/lib/public/modules/default-ai.js +81 -65
- package/lib/public/modules/home-debate-controls.js +18 -289
- package/lib/public/modules/home-mate-avatar-editor.js +228 -0
- package/lib/public/modules/home-mate-color-picker.js +66 -0
- package/lib/public/modules/home-mate-creation.js +1 -1
- package/lib/public/modules/home-mate-instructions.js +90 -0
- package/lib/public/modules/home-mate-model-picker.js +80 -271
- package/lib/public/modules/home-mate-profile-editor.js +72 -0
- package/lib/public/modules/home-mate-settings.js +118 -125
- package/lib/public/modules/home-shell.js +3 -0
- package/lib/public/modules/home-surface-boot.js +1 -9
- package/lib/public/modules/icon-strip-tooltip.js +95 -0
- package/lib/public/modules/knowledge-db-edit-state.js +35 -0
- package/lib/public/modules/knowledge-db-workbench.js +234 -0
- package/lib/public/modules/knowledge-history-state.js +55 -0
- package/lib/public/modules/knowledge-markdown-editor.js +57 -0
- package/lib/public/modules/knowledge-preview-links.js +70 -0
- package/lib/public/modules/knowledge-workbench-shell.js +21 -0
- package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
- package/lib/public/modules/mate-knowledge-workbench.js +500 -0
- package/lib/public/modules/mate-knowledge.js +11 -3
- package/lib/public/modules/mate-management.js +54 -10
- package/lib/public/modules/mate-sidebar.js +11 -1
- package/lib/public/modules/mate-workspace-color.js +33 -0
- package/lib/public/modules/mention.js +5 -13
- package/lib/public/modules/profile.js +51 -18
- package/lib/public/modules/project-chat-identity.js +79 -0
- package/lib/public/modules/project-debate-planning-workspace.js +250 -0
- package/lib/public/modules/project-debate-workspace.js +185 -0
- package/lib/public/modules/project-header-identity.js +127 -0
- package/lib/public/modules/project-logs-render.js +9 -4
- package/lib/public/modules/project-mate-creation-workspace.js +414 -0
- package/lib/public/modules/project-mate-navigation.js +238 -0
- package/lib/public/modules/project-session-navigation.js +29 -0
- package/lib/public/modules/project-switcher.js +6 -8
- package/lib/public/modules/projects-hub-view.js +5 -6
- package/lib/public/modules/projects-hub.js +2 -6
- package/lib/public/modules/qrcode.js +27 -8
- package/lib/public/modules/search-clay-chat.js +8 -11
- package/lib/public/modules/session-activity-tooltip.js +12 -0
- package/lib/public/modules/session-create-form.js +86 -14
- package/lib/public/modules/session-create.js +50 -7
- package/lib/public/modules/session-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +4 -1
- package/lib/public/modules/session-title-marquee.js +51 -0
- package/lib/public/modules/sidebar-mates.js +3 -50
- package/lib/public/modules/sidebar-mobile.js +63 -60
- package/lib/public/modules/sidebar-projects.js +84 -97
- package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
- package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
- package/lib/public/modules/sidebar-sessions.js +49 -50
- package/lib/public/modules/sidebar.js +11 -13
- package/lib/public/modules/thinking-lifecycle.js +7 -6
- package/lib/public/modules/tool-palette-order.js +4 -3
- package/lib/public/modules/tool-palette.js +13 -3
- package/lib/public/modules/tools.js +22 -22
- package/lib/public/modules/worker-proposal.js +42 -8
- package/lib/public/modules/worker-runtime-picker.js +115 -0
- package/lib/public/modules/you-activity.js +121 -0
- package/lib/public/modules/you.js +251 -0
- package/lib/public/style.css +16 -8
- package/lib/public/vendor/codemirror/LICENSE +21 -0
- package/lib/public/vendor/codemirror/codemirror.css +344 -0
- package/lib/public/vendor/codemirror/codemirror.js +9884 -0
- package/lib/public/vendor/codemirror/continuelist.js +101 -0
- package/lib/public/vendor/codemirror/markdown.js +886 -0
- package/lib/public/vendor/codemirror/show-hint.css +37 -0
- package/lib/public/vendor/codemirror/show-hint.js +523 -0
- package/lib/sdk-bridge.js +15 -3
- package/lib/server-admin.js +11 -0
- package/lib/server-home-chat-events.js +1 -1
- package/lib/server-home-chat.js +25 -3
- package/lib/server-home-debate-planning.js +4 -1
- package/lib/server-home-debates.js +2 -0
- package/lib/server-home-mate-creation.js +4 -1
- package/lib/server-mate-instructions.js +44 -0
- package/lib/server-mates.js +12 -3
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +65 -1
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +21 -1
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +32 -6
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +50 -0
- package/package.json +10 -1
|
@@ -12,7 +12,6 @@ import { dismissOverlayPanels, closeSidebar, updatePageTitle, spawnDustParticles
|
|
|
12
12
|
import { showConfirm } from './app-misc.js';
|
|
13
13
|
import { getUpcomingSchedules } from './scheduler.js';
|
|
14
14
|
import { refreshMobileChatSheet } from './sidebar-mobile.js';
|
|
15
|
-
import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
16
15
|
import { openGroup, openWorkerWithDriver, separateGroup } from './split-view.js';
|
|
17
16
|
import { groupedSessionIds } from './split-group-helpers.js';
|
|
18
17
|
import { resolvePreferredVendor } from './default-vendor.js';
|
|
@@ -24,6 +23,7 @@ import { renderFolderToolbar, captureFolderInputs, folderToolbarNeedsRender } fr
|
|
|
24
23
|
import { captureFolderCollapseAnimations } from './session-folder-collapse.js';
|
|
25
24
|
import { getListSearchQuery, getListSearchMatchIds, applyListSearchResults, filterItemsBySearch } from './session-list-search.js';
|
|
26
25
|
import { expectCreatedSession } from './session-create.js';
|
|
26
|
+
import { isMateWorkspace } from './project-mate-navigation.js';
|
|
27
27
|
import { describeSessionDelete } from './session-delete-scope.js';
|
|
28
28
|
import { renderSessionPresence, setSessionPresence } from './session-presence-ui.js';
|
|
29
29
|
import {
|
|
@@ -31,6 +31,9 @@ import {
|
|
|
31
31
|
renderDesktopDriverHierarchy,
|
|
32
32
|
renderDesktopOrphanHierarchy
|
|
33
33
|
} from './sidebar-session-hierarchy.js';
|
|
34
|
+
import { ordinarySessionListSessions } from './session-list-visibility.js';
|
|
35
|
+
import { formatSessionActivity } from './session-activity-tooltip.js';
|
|
36
|
+
import { bindSessionTitleMarquee } from './session-title-marquee.js';
|
|
34
37
|
import { summarizeSidebarItems } from './sidebar-session-counts.js';
|
|
35
38
|
import {
|
|
36
39
|
cancelSessionInlineRename,
|
|
@@ -272,7 +275,7 @@ function showSessionCtxMenu(anchorBtn, sessionId, title, cliSid, sessionData) {
|
|
|
272
275
|
|
|
273
276
|
|
|
274
277
|
// Session visibility toggle (only the session owner can change)
|
|
275
|
-
if (store.get('isMultiUserMode') && sessionData && sessionData.ownerId && sessionData.ownerId === store.get('myUserId')) {
|
|
278
|
+
if (!isMateWorkspace(store.snap()) && store.get('isMultiUserMode') && sessionData && !sessionData.isMate && sessionData.ownerId && sessionData.ownerId === store.get('myUserId')) {
|
|
276
279
|
var currentVis = (sessionData && sessionData.sessionVisibility) || "private";
|
|
277
280
|
var isPrivate = currentVis === "private";
|
|
278
281
|
var visItem = document.createElement("button");
|
|
@@ -514,6 +517,17 @@ function isSessionVisibleBySearch(sessionId) {
|
|
|
514
517
|
return getListSearchMatchIds().has(sessionId);
|
|
515
518
|
}
|
|
516
519
|
|
|
520
|
+
function appendSessionTitleLine(el, textSpan) {
|
|
521
|
+
var processingDot = textSpan.querySelector('.session-processing');
|
|
522
|
+
if (processingDot) processingDot.remove();
|
|
523
|
+
var titleLine = document.createElement('span');
|
|
524
|
+
titleLine.className = 'session-item-title-line';
|
|
525
|
+
titleLine.appendChild(textSpan);
|
|
526
|
+
if (processingDot) titleLine.appendChild(processingDot);
|
|
527
|
+
el.appendChild(titleLine);
|
|
528
|
+
return titleLine;
|
|
529
|
+
}
|
|
530
|
+
|
|
517
531
|
// --- Loop child / run / group rendering ---
|
|
518
532
|
|
|
519
533
|
function renderLoopChild(s) {
|
|
@@ -539,7 +553,7 @@ function renderLoopChild(s) {
|
|
|
539
553
|
textHtml += '<span class="session-loop-role-badge' + roleCls + '">' + roleName + iterSuffix + '</span>';
|
|
540
554
|
}
|
|
541
555
|
textSpan.innerHTML = textHtml;
|
|
542
|
-
el
|
|
556
|
+
appendSessionTitleLine(el, textSpan);
|
|
543
557
|
appendSessionCloseButton(el, s);
|
|
544
558
|
|
|
545
559
|
el.addEventListener("click", (function (id) {
|
|
@@ -665,7 +679,7 @@ function renderLoopGroup(loopId, children, groupKey) {
|
|
|
665
679
|
textHtml += '<span class="session-loop-count' + countClass + '">' + countLabel + '</span>';
|
|
666
680
|
}
|
|
667
681
|
textSpan.innerHTML = textHtml;
|
|
668
|
-
el
|
|
682
|
+
appendSessionTitleLine(el, textSpan);
|
|
669
683
|
|
|
670
684
|
// More button (ellipsis)
|
|
671
685
|
var moreBtn = document.createElement("button");
|
|
@@ -768,7 +782,7 @@ function renderLoopRun(parentGk, startedAtKey, sessions, isRalph) {
|
|
|
768
782
|
textHtml += '<span class="session-loop-run-time">' + escapeHtml(timeLabel) + '</span>';
|
|
769
783
|
textHtml += '<span class="session-loop-count' + (isRalph ? "" : " scheduled") + '">' + sessions.length + '</span>';
|
|
770
784
|
textSpan.innerHTML = textHtml;
|
|
771
|
-
el
|
|
785
|
+
appendSessionTitleLine(el, textSpan);
|
|
772
786
|
|
|
773
787
|
// Click row -> switch to latest session of this run
|
|
774
788
|
el.addEventListener("click", (function (id) {
|
|
@@ -799,26 +813,24 @@ function renderLoopRun(parentGk, startedAtKey, sessions, isRalph) {
|
|
|
799
813
|
|
|
800
814
|
function renderSessionItem(s, options) {
|
|
801
815
|
var itemOptions = options || {};
|
|
816
|
+
var displaySession = s;
|
|
817
|
+
if (itemOptions.promotedActive || itemOptions.promotedProcessing || itemOptions.promotedUnread !== undefined) {
|
|
818
|
+
displaySession = Object.assign({}, s, {
|
|
819
|
+
active: !!(s.active || itemOptions.promotedActive),
|
|
820
|
+
isProcessing: !!(s.isProcessing || itemOptions.promotedProcessing),
|
|
821
|
+
unread: (s.unread || 0) + (itemOptions.promotedUnread || 0),
|
|
822
|
+
});
|
|
823
|
+
}
|
|
802
824
|
var el = document.createElement("div");
|
|
803
825
|
var isMatch = getListSearchMatchIds() !== null && getListSearchMatchIds().has(s.id);
|
|
804
|
-
el.className = "session-item" + (
|
|
826
|
+
el.className = "session-item" + (displaySession.active ? " active" : "") + (isMatch ? " search-match" : "");
|
|
805
827
|
if (itemOptions.worker) el.classList.add("session-worker-item");
|
|
806
828
|
el.dataset.sessionId = s.id;
|
|
807
829
|
|
|
808
|
-
// Keep agent identity separate from the title so each row has a stable
|
|
809
|
-
// visual anchor instead of mixing a tiny inline logo into the text.
|
|
810
|
-
var itemVendor = s.vendor || "claude";
|
|
811
|
-
var vendorIcon = document.createElement("img");
|
|
812
|
-
vendorIcon.className = "session-vendor-icon session-vendor-mark";
|
|
813
|
-
vendorIcon.src = VENDOR_AVATARS[itemVendor] || VENDOR_AVATARS.claude;
|
|
814
|
-
vendorIcon.alt = "";
|
|
815
|
-
vendorIcon.title = VENDOR_NAMES[itemVendor] || itemVendor;
|
|
816
|
-
el.appendChild(vendorIcon);
|
|
817
|
-
|
|
818
830
|
var textSpan = document.createElement("span");
|
|
819
831
|
textSpan.className = "session-item-text";
|
|
820
832
|
var textHtml = "";
|
|
821
|
-
if (
|
|
833
|
+
if (displaySession.isProcessing) {
|
|
822
834
|
textHtml += '<span class="session-processing"></span>';
|
|
823
835
|
}
|
|
824
836
|
if (s.backgroundTaskCount) {
|
|
@@ -832,8 +844,12 @@ function renderSessionItem(s, options) {
|
|
|
832
844
|
}
|
|
833
845
|
textHtml += '<span class="session-item-title">' + highlightMatch(s.title || "New Session", getListSearchQuery()) + '</span>';
|
|
834
846
|
textSpan.innerHTML = textHtml;
|
|
835
|
-
|
|
836
|
-
|
|
847
|
+
textSpan.setAttribute("aria-label", s.title || "New Session");
|
|
848
|
+
var titleEl = textSpan.querySelector(".session-item-title");
|
|
849
|
+
var activityTitle = formatSessionActivity(s.lastActivity);
|
|
850
|
+
if (titleEl && activityTitle) titleEl.title = activityTitle;
|
|
851
|
+
var titleLine = appendSessionTitleLine(el, textSpan);
|
|
852
|
+
appendGithubWork(el, s, titleLine);
|
|
837
853
|
|
|
838
854
|
if (itemOptions.worker) {
|
|
839
855
|
var workerLabel = document.createElement("span");
|
|
@@ -844,13 +860,6 @@ function renderSessionItem(s, options) {
|
|
|
844
860
|
|
|
845
861
|
var trailing = document.createElement("span");
|
|
846
862
|
trailing.className = "session-row-trailing";
|
|
847
|
-
var ageText = relativeTime(s.lastActivity || 0);
|
|
848
|
-
if (ageText) {
|
|
849
|
-
var age = document.createElement("span");
|
|
850
|
-
age.className = "session-item-age";
|
|
851
|
-
age.textContent = ageText;
|
|
852
|
-
trailing.appendChild(age);
|
|
853
|
-
}
|
|
854
863
|
|
|
855
864
|
// Right-click / long-press: context menu
|
|
856
865
|
el.addEventListener("contextmenu", (function(id, title, cliSid, anchor, sData) {
|
|
@@ -865,8 +874,8 @@ function renderSessionItem(s, options) {
|
|
|
865
874
|
var unreadBadge = document.createElement("span");
|
|
866
875
|
unreadBadge.className = "session-unread-badge";
|
|
867
876
|
unreadBadge.dataset.sessionId = s.id;
|
|
868
|
-
if (
|
|
869
|
-
unreadBadge.textContent =
|
|
877
|
+
if (displaySession.unread > 0) {
|
|
878
|
+
unreadBadge.textContent = displaySession.unread > 99 ? "99+" : String(displaySession.unread);
|
|
870
879
|
unreadBadge.classList.add("has-unread");
|
|
871
880
|
}
|
|
872
881
|
el.appendChild(unreadBadge);
|
|
@@ -877,6 +886,7 @@ function renderSessionItem(s, options) {
|
|
|
877
886
|
if (isFavoriteSession(s)) el.classList.add("is-favorite");
|
|
878
887
|
}
|
|
879
888
|
appendSessionCloseButton(actions, s);
|
|
889
|
+
el.style.setProperty("--session-actions-width", (actions.childNodes.length * 18 + Math.max(0, actions.childNodes.length - 1) * 4 + 21) + "px");
|
|
880
890
|
if (actions.childNodes.length) trailing.appendChild(actions);
|
|
881
891
|
if (trailing.childNodes.length) el.appendChild(trailing);
|
|
882
892
|
|
|
@@ -898,6 +908,7 @@ function renderSessionItem(s, options) {
|
|
|
898
908
|
|
|
899
909
|
// Presence avatars (multi-user)
|
|
900
910
|
renderSessionPresence(el, String(s.id));
|
|
911
|
+
bindSessionTitleMarquee(el, textSpan.querySelector(".session-item-title"), actions);
|
|
901
912
|
if (!itemOptions.worker) setupFolderDrag(el, s);
|
|
902
913
|
|
|
903
914
|
return el;
|
|
@@ -911,14 +922,7 @@ function renderSplitGroupItem(group, members) {
|
|
|
911
922
|
|
|
912
923
|
var text = document.createElement("span");
|
|
913
924
|
text.className = "session-item-text split-group-text";
|
|
914
|
-
var html = '<span class="split-group-glyph" aria-hidden="true">' + iconHtml("columns-2") + '</span
|
|
915
|
-
for (var i = 0; i < members.length; i++) {
|
|
916
|
-
var vendor = members[i].vendor || "claude";
|
|
917
|
-
html += '<img class="session-vendor-icon split-group-vendor" src="' +
|
|
918
|
-
(VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude) + '" alt="" title="' +
|
|
919
|
-
escapeHtml(VENDOR_NAMES[vendor] || vendor) + '">';
|
|
920
|
-
}
|
|
921
|
-
html += "</span>";
|
|
925
|
+
var html = '<span class="split-group-glyph" aria-hidden="true">' + iconHtml("columns-2") + '</span>';
|
|
922
926
|
var splitProcessing = false;
|
|
923
927
|
var splitBackgroundTaskCount = 0;
|
|
924
928
|
for (var si = 0; si < members.length; si++) {
|
|
@@ -929,7 +933,7 @@ function renderSplitGroupItem(group, members) {
|
|
|
929
933
|
if (splitBackgroundTaskCount) html += '<span class="session-background-task-count">' + splitBackgroundTaskCount + '</span>';
|
|
930
934
|
html += '<span class="split-group-name">' + highlightMatch(group.name || "Split", getListSearchQuery()) + "</span>";
|
|
931
935
|
text.innerHTML = html;
|
|
932
|
-
el
|
|
936
|
+
appendSessionTitleLine(el, text);
|
|
933
937
|
|
|
934
938
|
var unread = 0;
|
|
935
939
|
for (var ui = 0; ui < members.length; ui++) unread += members[ui].unread || 0;
|
|
@@ -938,7 +942,6 @@ function renderSplitGroupItem(group, members) {
|
|
|
938
942
|
badge.dataset.splitGroupId = group.id;
|
|
939
943
|
if (unread > 0) badge.textContent = unread > 99 ? "99+" : String(unread);
|
|
940
944
|
el.appendChild(badge);
|
|
941
|
-
|
|
942
945
|
el.addEventListener("click", function () {
|
|
943
946
|
if (openGroup(group)) {
|
|
944
947
|
dismissOverlayPanels();
|
|
@@ -994,22 +997,23 @@ export function renderSessionList(sessions) {
|
|
|
994
997
|
|
|
995
998
|
// Partition: loop sessions vs normal sessions
|
|
996
999
|
// Group by loopId + date so all runs of the same task on the same day are merged
|
|
1000
|
+
var visibleSessions = ordinarySessionListSessions(cachedSessions);
|
|
997
1001
|
var splitGroups = store.get('splitGroups') || [];
|
|
998
1002
|
var groupedIds = groupedSessionIds(splitGroups);
|
|
999
|
-
var hierarchy = prepareSidebarHierarchy(
|
|
1003
|
+
var hierarchy = prepareSidebarHierarchy(visibleSessions);
|
|
1000
1004
|
var hierarchyByDriver = hierarchy.byDriver;
|
|
1001
1005
|
var hierarchySessionIds = hierarchy.sessionIds;
|
|
1002
1006
|
hierarchySessionIds.forEach(function (id) { groupedIds.delete(id); });
|
|
1003
1007
|
var sessionsById = new Map();
|
|
1004
|
-
for (var si = 0; si <
|
|
1008
|
+
for (var si = 0; si < visibleSessions.length; si++) sessionsById.set(visibleSessions[si].id, visibleSessions[si]);
|
|
1005
1009
|
var loopGroups = {}; // groupKey -> [sessions]
|
|
1006
1010
|
var normalSessions = [];
|
|
1007
|
-
for (var i = 0; i <
|
|
1008
|
-
var s =
|
|
1011
|
+
for (var i = 0; i < visibleSessions.length; i++) {
|
|
1012
|
+
var s = visibleSessions[i];
|
|
1009
1013
|
if (s.sessionRole === "worker") continue;
|
|
1010
1014
|
if (groupedIds.has(s.id)) continue;
|
|
1011
|
-
if (s.loop && s.loop.loopId && s.loop.role === "crafting" && s.loop.source !== "ralph"
|
|
1012
|
-
// Task crafting sessions live in the scheduler calendar, not the main list
|
|
1015
|
+
if (s.loop && s.loop.loopId && s.loop.role === "crafting" && s.loop.source !== "ralph") {
|
|
1016
|
+
// Task crafting sessions live in the scheduler calendar, not the main list.
|
|
1013
1017
|
continue;
|
|
1014
1018
|
} else if (s.loop && s.loop.loopId) {
|
|
1015
1019
|
var startedAt = s.loop.startedAt || 0;
|
|
@@ -1029,11 +1033,6 @@ export function renderSessionList(sessions) {
|
|
|
1029
1033
|
if (driverRoot) items.push({ type: "driver-hierarchy", root: driverRoot, data: driverRoot.driver, lastActivity: driverRoot.lastActivity });
|
|
1030
1034
|
else items.push({ type: "session", data: normalSessions[j], lastActivity: normalSessions[j].lastActivity || 0 });
|
|
1031
1035
|
}
|
|
1032
|
-
if (hierarchy.orphans.length) {
|
|
1033
|
-
var orphanActivity = 0;
|
|
1034
|
-
for (var oi = 0; oi < hierarchy.orphans.length; oi++) orphanActivity = Math.max(orphanActivity, hierarchy.orphans[oi].lastActivity || 0);
|
|
1035
|
-
items.push({ type: "orphan-workers", workers: hierarchy.orphans, lastActivity: orphanActivity });
|
|
1036
|
-
}
|
|
1037
1036
|
for (var sg = 0; sg < splitGroups.length; sg++) {
|
|
1038
1037
|
var splitGroup = splitGroups[sg];
|
|
1039
1038
|
var splitMembers = [];
|
|
@@ -1083,7 +1082,7 @@ export function renderSessionList(sessions) {
|
|
|
1083
1082
|
if (it.type === "loop") return renderLoopGroup(it.loopId, it.children, it.groupKey) || document.createElement("div");
|
|
1084
1083
|
if (it.type === "split-group") return renderSplitGroupItem(it.group, it.members);
|
|
1085
1084
|
if (it.type === "driver-hierarchy") return renderDesktopDriverHierarchy(it.root, renderSessionItem, rerender, matchIds);
|
|
1086
|
-
if (it.type === "orphan-workers") return
|
|
1085
|
+
if (it.type === "orphan-workers") return document.createElement("div");
|
|
1087
1086
|
return renderSessionItem(it.data);
|
|
1088
1087
|
},
|
|
1089
1088
|
};
|
|
@@ -62,6 +62,14 @@ export function closeSidebar() {
|
|
|
62
62
|
ctx.sidebarOverlay.classList.remove("visible");
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
export function toggleSidebarCollapse() {
|
|
66
|
+
if (!ctx) return;
|
|
67
|
+
var layout = ctx.$("layout");
|
|
68
|
+
var collapsed = layout.classList.toggle("sidebar-collapsed");
|
|
69
|
+
try { localStorage.setItem("sidebar-collapsed", collapsed ? "1" : ""); } catch (e) {}
|
|
70
|
+
setTimeout(function () { syncResizeHandles(); }, 210);
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
export function initSidebar(_ctx) {
|
|
66
74
|
ctx = _ctx;
|
|
67
75
|
|
|
@@ -87,13 +95,6 @@ export function initSidebar(_ctx) {
|
|
|
87
95
|
ctx.sidebarOverlay.addEventListener("click", closeSidebar);
|
|
88
96
|
|
|
89
97
|
// --- Desktop sidebar collapse/expand ---
|
|
90
|
-
function toggleSidebarCollapse() {
|
|
91
|
-
var layout = ctx.$("layout");
|
|
92
|
-
var collapsed = layout.classList.toggle("sidebar-collapsed");
|
|
93
|
-
try { localStorage.setItem("sidebar-collapsed", collapsed ? "1" : ""); } catch (e) {}
|
|
94
|
-
setTimeout(function () { syncUserIslandWidth(); syncResizeHandle(); }, 210);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
98
|
if (ctx.sidebarToggleBtn) ctx.sidebarToggleBtn.addEventListener("click", toggleSidebarCollapse);
|
|
98
99
|
if (ctx.sidebarExpandBtn) ctx.sidebarExpandBtn.addEventListener("click", toggleSidebarCollapse);
|
|
99
100
|
var mateSidebarToggle = document.getElementById("mate-sidebar-toggle-btn");
|
|
@@ -245,12 +246,9 @@ export function initSidebar(_ctx) {
|
|
|
245
246
|
|
|
246
247
|
function syncUserIslandWidth() {
|
|
247
248
|
if (!userIsland) return;
|
|
248
|
-
var
|
|
249
|
-
var
|
|
250
|
-
|
|
251
|
-
if (!col) return;
|
|
252
|
-
var rect = col.getBoundingClientRect();
|
|
253
|
-
userIsland.style.width = (rect.right - 8 - 8) + "px";
|
|
249
|
+
var iconStrip = document.getElementById("icon-strip");
|
|
250
|
+
var stripWidth = iconStrip ? iconStrip.getBoundingClientRect().width : 0;
|
|
251
|
+
userIsland.style.width = (stripWidth > 0 ? stripWidth : 72) + "px";
|
|
254
252
|
}
|
|
255
253
|
|
|
256
254
|
// --- Sidebar resize handle ---
|
|
@@ -3,6 +3,7 @@ import { iconHtml, refreshIcons } from './icons.js';
|
|
|
3
3
|
import { store } from './store.js';
|
|
4
4
|
import { addToMessages, keepActiveThinkingAtTail, scrollToBottom } from './chat-render-runtime.js';
|
|
5
5
|
import { prepareThinkingView, bindThinkingView, updateThinkingView, beginThinkingView, setThinkingViewLive, finishThinkingView } from './thinking-view.js';
|
|
6
|
+
import { resolveProjectAssistantIdentity, applyProjectAssistantIdentity } from './project-chat-identity.js';
|
|
6
7
|
|
|
7
8
|
function getThinkingState() {
|
|
8
9
|
return store.get('thinkingState') || null;
|
|
@@ -19,8 +20,7 @@ function updateThinkingState(state, patch) {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function isMateThinking() {
|
|
22
|
-
|
|
23
|
-
return !!(store.get('dmMode') && target && target.isMate);
|
|
23
|
+
return resolveProjectAssistantIdentity(store.snap(), store.get('currentVendor')).kind === 'mate';
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function maybeScrollToBottom() {
|
|
@@ -30,10 +30,10 @@ function maybeScrollToBottom() {
|
|
|
30
30
|
function createThinkingElement() {
|
|
31
31
|
var el = document.createElement("div");
|
|
32
32
|
el.className = "thinking-item";
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
var mateName =
|
|
36
|
-
var mateAvatar =
|
|
33
|
+
var identity = resolveProjectAssistantIdentity(store.snap(), store.get('currentVendor'));
|
|
34
|
+
if (identity.kind === 'mate') {
|
|
35
|
+
var mateName = identity.name;
|
|
36
|
+
var mateAvatar = identity.avatarUrl;
|
|
37
37
|
el.classList.add("mate-thinking");
|
|
38
38
|
el.innerHTML =
|
|
39
39
|
'<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="">' +
|
|
@@ -48,6 +48,7 @@ function createThinkingElement() {
|
|
|
48
48
|
'</div>' +
|
|
49
49
|
'<div class="thinking-content"></div>' +
|
|
50
50
|
'</div>';
|
|
51
|
+
applyProjectAssistantIdentity(el, identity);
|
|
51
52
|
} else {
|
|
52
53
|
el.innerHTML =
|
|
53
54
|
'<div class="thinking-header">' +
|
|
@@ -33,13 +33,14 @@ var MATE_TOOLS = [
|
|
|
33
33
|
{ id: "mate-memory-btn", icon: "brain", label: "Memory", countId: "mate-memory-count" },
|
|
34
34
|
{ id: "mate-knowledge-btn", icon: "book-open", label: "Knowledge", countId: "mate-knowledge-count" },
|
|
35
35
|
{ id: "mate-sticky-notes-btn", icon: "sticky-note", label: "Sticky Notes" },
|
|
36
|
-
{ id: "mate-
|
|
36
|
+
{ id: "mate-debates-btn", icon: "messages-square", label: "Debates" },
|
|
37
37
|
{ id: "mate-mcp-btn", icon: "cable", label: "MCP / Skills", countId: "mate-mcp-sidebar-count" },
|
|
38
38
|
];
|
|
39
39
|
|
|
40
40
|
export var PALETTES = {
|
|
41
41
|
session: {
|
|
42
42
|
tools: SESSION_TOOLS,
|
|
43
|
+
fixedTools: [{ id: "you-button", icon: "user-round", label: "Me", countId: "me-unread-badge", fixed: true, scope: "clay" }],
|
|
43
44
|
activeContainerId: "session-actions",
|
|
44
45
|
hiddenSectionId: "session-actions-hidden",
|
|
45
46
|
},
|
|
@@ -57,13 +58,13 @@ export var PALETTES = {
|
|
|
57
58
|
//
|
|
58
59
|
// Skills now shares the MCP / Skills entry; explicit MCP placement wins.
|
|
59
60
|
var LEGACY_SESSION_TOOL_IDS = { "skills-btn": "mcp-btn" };
|
|
60
|
-
var LEGACY_MATE_TOOL_IDS = { "mate-skills-btn": "mate-mcp-btn" };
|
|
61
|
+
var LEGACY_MATE_TOOL_IDS = { "mate-skills-btn": "mate-mcp-btn", "mate-debate-btn": "mate-debates-btn" };
|
|
61
62
|
|
|
62
63
|
// Tools withdrawn from the session palette with no replacement. Git moved to
|
|
63
64
|
// the always-visible repository placard below the tool strip, so it no longer
|
|
64
65
|
// consumes an icon slot. A saved preference naming it is dropped rather than
|
|
65
66
|
// left to linger in stored order forever.
|
|
66
|
-
var RETIRED_SESSION_TOOL_IDS = ["git-sidebar-btn", "loop-tool-btn"];
|
|
67
|
+
var RETIRED_SESSION_TOOL_IDS = ["git-sidebar-btn", "loop-tool-btn", "debates-btn"];
|
|
67
68
|
|
|
68
69
|
function indexOfId(list, id) {
|
|
69
70
|
for (var i = 0; i < list.length; i++) {
|
|
@@ -37,6 +37,8 @@ function buildPalette(name) {
|
|
|
37
37
|
var active = document.getElementById(palette.activeContainerId);
|
|
38
38
|
if (!active) return;
|
|
39
39
|
|
|
40
|
+
(palette.fixedTools || []).forEach(function (tool) { active.appendChild(buildToolButton(tool, name)); });
|
|
41
|
+
|
|
40
42
|
// Create buttons with stable IDs and append in registry order (default).
|
|
41
43
|
for (var i = 0; i < palette.tools.length; i++) {
|
|
42
44
|
active.appendChild(buildToolButton(palette.tools[i], name));
|
|
@@ -73,8 +75,11 @@ function buildToolButton(tool, paletteName) {
|
|
|
73
75
|
btn.setAttribute('aria-label', tool.label);
|
|
74
76
|
btn.dataset.toolId = tool.id;
|
|
75
77
|
btn.dataset.palette = paletteName;
|
|
76
|
-
//
|
|
78
|
+
// Ordinary tools can be reordered; fixed tools retain their first slots.
|
|
77
79
|
btn.draggable = true;
|
|
80
|
+
if (tool.fixed) { btn.draggable = false; btn.dataset.fixed = 'true'; }
|
|
81
|
+
if (tool.scope) btn.dataset.scope = tool.scope;
|
|
82
|
+
if (tool.id === 'you-button') { btn.classList.add('you-button'); btn.setAttribute('aria-pressed', 'false'); }
|
|
78
83
|
|
|
79
84
|
var icon = document.createElement('i');
|
|
80
85
|
icon.setAttribute('data-lucide', tool.icon);
|
|
@@ -89,10 +94,12 @@ function buildToolButton(tool, paletteName) {
|
|
|
89
94
|
var count = document.createElement('span');
|
|
90
95
|
count.id = tool.countId;
|
|
91
96
|
count.className = 'sidebar-badge hidden';
|
|
97
|
+
if (tool.id === 'you-button') { count.className = 'sidebar-badge me-unread-badge'; count.hidden = true; }
|
|
92
98
|
btn.appendChild(count);
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
btn.addEventListener('dragstart', function (e) {
|
|
102
|
+
if (tool.fixed) { e.preventDefault(); return; }
|
|
96
103
|
var container = btn.parentNode;
|
|
97
104
|
if (!container || container.id !== PALETTES[paletteName].activeContainerId) {
|
|
98
105
|
e.preventDefault();
|
|
@@ -122,6 +129,7 @@ function getDragAfterElement(container, x, y) {
|
|
|
122
129
|
var closest = null;
|
|
123
130
|
var closestDist = Number.POSITIVE_INFINITY;
|
|
124
131
|
for (var i = 0; i < tiles.length; i++) {
|
|
132
|
+
if (tiles[i].dataset.fixed === 'true') continue;
|
|
125
133
|
var rect = tiles[i].getBoundingClientRect();
|
|
126
134
|
// Pointer is "before" the tile if it's left of the tile's horizontal
|
|
127
135
|
// midpoint on the same row (or on a higher row).
|
|
@@ -164,7 +172,7 @@ function applyPreferences(name, prefs) {
|
|
|
164
172
|
function place(id) {
|
|
165
173
|
if (placed[id]) return;
|
|
166
174
|
var btn = document.getElementById(id);
|
|
167
|
-
if (!btn) return;
|
|
175
|
+
if (!btn || btn.dataset.fixed === 'true') return;
|
|
168
176
|
active.appendChild(btn);
|
|
169
177
|
placed[id] = true;
|
|
170
178
|
}
|
|
@@ -201,7 +209,9 @@ function savePreferences(name) {
|
|
|
201
209
|
|
|
202
210
|
var order = [];
|
|
203
211
|
var activeTiles = active.querySelectorAll('[data-tool-id]');
|
|
204
|
-
for (var i = 0; i < activeTiles.length; i++)
|
|
212
|
+
for (var i = 0; i < activeTiles.length; i++) {
|
|
213
|
+
if (activeTiles[i].dataset.fixed !== 'true') order.push(activeTiles[i].dataset.toolId);
|
|
214
|
+
}
|
|
205
215
|
|
|
206
216
|
// Every tool is visible, so the explicit order is the whole preference.
|
|
207
217
|
fetch('/api/user/tool-palettes', {
|
|
@@ -11,6 +11,7 @@ import { VENDOR_NAMES } from './app-rendering.js';
|
|
|
11
11
|
import { startThinkingSegment, appendThinkingText, stopThinkingSegment, resetThinkingTurn, clearThinkingState, saveThinkingState, restoreThinkingState, updateThinkingTokenEstimate } from './thinking-lifecycle.js';
|
|
12
12
|
import { buildElicitationCard, markElicitationCard, showElicitationError } from './elicitation-form.js';
|
|
13
13
|
import { findAskUserCard, getAskUserRequestKey, hasAskUserRequest, rememberAskUserRequest, markAskUserRequestAnswered, saveAskUserState, restoreAskUserState, resetAskUserState } from './ask-user-state.js';
|
|
14
|
+
import { getProjectAssistantPlaceholder, resolveProjectAssistantIdentity, applyProjectAssistantIdentity } from './project-chat-identity.js';
|
|
14
15
|
|
|
15
16
|
var ctx;
|
|
16
17
|
|
|
@@ -142,11 +143,11 @@ function updateToolGroupHeader(group) {
|
|
|
142
143
|
refreshIcons();
|
|
143
144
|
}
|
|
144
145
|
|
|
145
|
-
// Show group header only when 2+ visible tools (or always in
|
|
146
|
+
// Show group header only when 2+ visible tools (or always in a Mate conversation)
|
|
146
147
|
var header = group.el.querySelector(".tool-group-header");
|
|
147
148
|
var isMate = group.el.classList.contains("mate-tool-group");
|
|
148
149
|
if (isMate) {
|
|
149
|
-
// Mate
|
|
150
|
+
// Mate conversation: hide entire group when no tools, show collapsed when tools exist
|
|
150
151
|
if (group.toolCount === 0) {
|
|
151
152
|
group.el.style.display = "none";
|
|
152
153
|
} else {
|
|
@@ -248,12 +249,13 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
248
249
|
container.dataset.askUserRequestKey = requestKey;
|
|
249
250
|
rememberAskUserRequest(toolId);
|
|
250
251
|
|
|
251
|
-
// Mate
|
|
252
|
+
// Mate conversation: wrap in avatar + content layout (same as msg-assistant)
|
|
252
253
|
var mateContentWrap = null;
|
|
253
|
-
if (
|
|
254
|
+
if (resolveProjectAssistantIdentity().kind === 'mate') {
|
|
254
255
|
container.classList.add("mate-ask-user");
|
|
255
|
-
var
|
|
256
|
-
var
|
|
256
|
+
var identity = resolveProjectAssistantIdentity();
|
|
257
|
+
var mateName = identity.name;
|
|
258
|
+
var mateAvatar = identity.avatarUrl;
|
|
257
259
|
|
|
258
260
|
var avi = document.createElement("img");
|
|
259
261
|
avi.className = "dm-bubble-avatar";
|
|
@@ -393,7 +395,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
393
395
|
actions.appendChild(skipBtn);
|
|
394
396
|
container.appendChild(actions);
|
|
395
397
|
|
|
396
|
-
// Mate
|
|
398
|
+
// Mate conversation: move all content into the bubble content wrapper
|
|
397
399
|
if (mateContentWrap) {
|
|
398
400
|
var children = [];
|
|
399
401
|
for (var ci = 0; ci < container.childNodes.length; ci++) {
|
|
@@ -420,12 +422,7 @@ export function disableMainInput() {
|
|
|
420
422
|
|
|
421
423
|
export function enableMainInput() {
|
|
422
424
|
ctx.inputEl.disabled = false;
|
|
423
|
-
|
|
424
|
-
ctx.inputEl.placeholder = "Message " + document.body.dataset.mateName + "...";
|
|
425
|
-
} else {
|
|
426
|
-
var _v = store.get('currentVendor') || "claude";
|
|
427
|
-
ctx.inputEl.placeholder = "Message " + (VENDOR_NAMES[_v] || VENDOR_NAMES.claude) + "...";
|
|
428
|
-
}
|
|
425
|
+
ctx.inputEl.placeholder = getProjectAssistantPlaceholder(store.snap(), store.get('currentVendor'));
|
|
429
426
|
}
|
|
430
427
|
|
|
431
428
|
function submitAskUserAnswer(container, toolId, questions, answers, multiSelections) {
|
|
@@ -557,8 +554,8 @@ export function renderPermissionRequest(requestId, toolName, toolInput, decision
|
|
|
557
554
|
return;
|
|
558
555
|
}
|
|
559
556
|
|
|
560
|
-
// Channel layout or Mate
|
|
561
|
-
if ((
|
|
557
|
+
// Channel layout or Mate conversation: conversational "Can I ...?" style
|
|
558
|
+
if (resolveProjectAssistantIdentity().kind === "mate" || getChatLayout() === "channel") {
|
|
562
559
|
renderConversationalPermission(requestId, toolName, toolInput, mateId, vendor);
|
|
563
560
|
applyPermissionHints(pendingPermissions[requestId], hints);
|
|
564
561
|
return;
|
|
@@ -824,10 +821,11 @@ function matePermissionInfo(toolName, toolInput) {
|
|
|
824
821
|
}
|
|
825
822
|
|
|
826
823
|
function resolvePermissionIdentity(mateId, vendor) {
|
|
827
|
-
// Mate
|
|
828
|
-
if (
|
|
829
|
-
var
|
|
830
|
-
var
|
|
824
|
+
// Use the Mate bound to this session, including legacy DM targets.
|
|
825
|
+
if (resolveProjectAssistantIdentity().kind === 'mate') {
|
|
826
|
+
var identity = resolveProjectAssistantIdentity();
|
|
827
|
+
var name = identity.name;
|
|
828
|
+
var avatar = identity.avatarUrl;
|
|
831
829
|
// Override if specific mateId provided (e.g. @mention)
|
|
832
830
|
if (mateId && ctx.getMateById) {
|
|
833
831
|
var mentionMate = ctx.getMateById(mateId);
|
|
@@ -1577,7 +1575,7 @@ function updateTodoSticky() {
|
|
|
1577
1575
|
export function startThinking() {
|
|
1578
1576
|
ctx.finalizeAssistantBlock();
|
|
1579
1577
|
var el = startThinkingSegment();
|
|
1580
|
-
if (
|
|
1578
|
+
if (resolveProjectAssistantIdentity().kind !== 'mate') {
|
|
1581
1579
|
ctx.setActivity("thinking");
|
|
1582
1580
|
}
|
|
1583
1581
|
return el;
|
|
@@ -1605,7 +1603,8 @@ export function createToolItem(id, name) {
|
|
|
1605
1603
|
toolGroupCounter++;
|
|
1606
1604
|
var groupEl = document.createElement("div");
|
|
1607
1605
|
groupEl.className = "tool-group";
|
|
1608
|
-
var
|
|
1606
|
+
var identity = resolveProjectAssistantIdentity();
|
|
1607
|
+
var isMateToolGroup = identity.kind === 'mate';
|
|
1609
1608
|
if (isMateToolGroup) groupEl.classList.add("mate-tool-group");
|
|
1610
1609
|
groupEl.dataset.groupId = "g" + toolGroupCounter;
|
|
1611
1610
|
|
|
@@ -1619,7 +1618,7 @@ export function createToolItem(id, name) {
|
|
|
1619
1618
|
'<div class="tool-group-items"></div>';
|
|
1620
1619
|
|
|
1621
1620
|
if (isMateToolGroup) {
|
|
1622
|
-
var mateAvatar =
|
|
1621
|
+
var mateAvatar = identity.avatarUrl;
|
|
1623
1622
|
groupEl.innerHTML =
|
|
1624
1623
|
'<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="">' +
|
|
1625
1624
|
'<div class="dm-bubble-content">' + toolGroupInner + '</div>';
|
|
@@ -1627,6 +1626,7 @@ export function createToolItem(id, name) {
|
|
|
1627
1626
|
groupEl.innerHTML = toolGroupInner;
|
|
1628
1627
|
}
|
|
1629
1628
|
|
|
1629
|
+
applyProjectAssistantIdentity(groupEl, identity);
|
|
1630
1630
|
groupEl.querySelector(".tool-group-header").addEventListener("click", function () {
|
|
1631
1631
|
groupEl.classList.toggle("collapsed");
|
|
1632
1632
|
if (currentToolGroup) currentToolGroup.userToggled = true;
|