clay-server 2.34.0-beta.9 → 2.34.0
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/project-connection.js +1 -0
- package/lib/project-sessions.js +33 -0
- package/lib/public/css/mobile-nav.css +0 -14
- package/lib/public/css/notifications-center.css +23 -19
- package/lib/public/css/sidebar.css +326 -101
- package/lib/public/index.html +7 -10
- package/lib/public/modules/diff.js +21 -7
- package/lib/public/modules/sidebar-mobile.js +10 -20
- package/lib/public/modules/sidebar-sessions.js +490 -113
- package/lib/public/modules/sidebar.js +8 -6
- package/lib/public/modules/tools.js +37 -10
- package/lib/public/sw.js +1 -1
- package/lib/sessions.js +90 -0
- package/lib/ws-schema.js +2 -0
- package/lib/yoke/adapters/codex.js +31 -4
- package/package.json +1 -1
|
@@ -94,12 +94,14 @@ export function initSidebar(_ctx) {
|
|
|
94
94
|
}
|
|
95
95
|
} catch (e) {}
|
|
96
96
|
|
|
97
|
-
ctx.newSessionBtn
|
|
98
|
-
|
|
99
|
-
ctx.ws
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
if (ctx.newSessionBtn) {
|
|
98
|
+
ctx.newSessionBtn.addEventListener("click", function () {
|
|
99
|
+
if (ctx.ws && ctx.connected) {
|
|
100
|
+
ctx.ws.send(JSON.stringify({ type: "new_session" }));
|
|
101
|
+
closeSidebar();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
103
105
|
|
|
104
106
|
// --- Loop (Ralph wizard) tool-palette tile ---
|
|
105
107
|
// The tile is rendered by tool-palette.js at the stable id
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { escapeHtml, copyToClipboard } from './utils.js';
|
|
2
2
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
3
3
|
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks } from './markdown.js';
|
|
4
|
-
import { renderUnifiedDiff, renderSplitDiff, renderPatchDiff } from './diff.js';
|
|
4
|
+
import { renderUnifiedDiff, renderSplitDiff, renderPatchDiff, reconstructPatchSources } from './diff.js';
|
|
5
5
|
import { openFile } from './filebrowser.js';
|
|
6
6
|
import { mateAvatarUrl } from './avatar.js';
|
|
7
7
|
import { getChatLayout } from './theme.js';
|
|
@@ -1740,12 +1740,12 @@ export function updateToolExecuting(id, name, input) {
|
|
|
1740
1740
|
ctx.scrollToBottom();
|
|
1741
1741
|
}
|
|
1742
1742
|
|
|
1743
|
-
|
|
1743
|
+
// Shared chrome (filename header + unified/split toggle) for diff renderings.
|
|
1744
|
+
// makeUnified and makeSplit are factories that return a fresh body element.
|
|
1745
|
+
function buildDiffChrome(filePath, linkOldStr, linkNewStr, makeUnified, makeSplit) {
|
|
1744
1746
|
var wrapper = document.createElement("div");
|
|
1745
1747
|
wrapper.className = "edit-diff";
|
|
1746
|
-
var lang = getLanguageFromPath(filePath);
|
|
1747
1748
|
|
|
1748
|
-
// Header with file path and split toggle (desktop only)
|
|
1749
1749
|
var header = document.createElement("div");
|
|
1750
1750
|
header.className = "edit-diff-header";
|
|
1751
1751
|
|
|
@@ -1758,7 +1758,7 @@ function renderEditDiff(oldStr, newStr, filePath) {
|
|
|
1758
1758
|
e.stopPropagation();
|
|
1759
1759
|
openFile(fp, { diff: { oldStr: os || "", newStr: ns || "" } });
|
|
1760
1760
|
});
|
|
1761
|
-
})(filePath,
|
|
1761
|
+
})(filePath, linkOldStr, linkNewStr);
|
|
1762
1762
|
}
|
|
1763
1763
|
header.appendChild(pathSpan);
|
|
1764
1764
|
|
|
@@ -1784,7 +1784,7 @@ function renderEditDiff(oldStr, newStr, filePath) {
|
|
|
1784
1784
|
|
|
1785
1785
|
wrapper.appendChild(header);
|
|
1786
1786
|
|
|
1787
|
-
var currentBody =
|
|
1787
|
+
var currentBody = makeUnified();
|
|
1788
1788
|
wrapper.appendChild(currentBody);
|
|
1789
1789
|
|
|
1790
1790
|
unifiedBtn.addEventListener("click", function (e) {
|
|
@@ -1794,7 +1794,7 @@ function renderEditDiff(oldStr, newStr, filePath) {
|
|
|
1794
1794
|
unifiedBtn.classList.add("active");
|
|
1795
1795
|
splitBtn.classList.remove("active");
|
|
1796
1796
|
wrapper.removeChild(currentBody);
|
|
1797
|
-
currentBody =
|
|
1797
|
+
currentBody = makeUnified();
|
|
1798
1798
|
wrapper.appendChild(currentBody);
|
|
1799
1799
|
refreshIcons();
|
|
1800
1800
|
});
|
|
@@ -1806,7 +1806,7 @@ function renderEditDiff(oldStr, newStr, filePath) {
|
|
|
1806
1806
|
splitBtn.classList.add("active");
|
|
1807
1807
|
unifiedBtn.classList.remove("active");
|
|
1808
1808
|
wrapper.removeChild(currentBody);
|
|
1809
|
-
currentBody =
|
|
1809
|
+
currentBody = makeSplit();
|
|
1810
1810
|
wrapper.appendChild(currentBody);
|
|
1811
1811
|
refreshIcons();
|
|
1812
1812
|
});
|
|
@@ -1814,6 +1814,29 @@ function renderEditDiff(oldStr, newStr, filePath) {
|
|
|
1814
1814
|
return wrapper;
|
|
1815
1815
|
}
|
|
1816
1816
|
|
|
1817
|
+
function renderEditDiff(oldStr, newStr, filePath) {
|
|
1818
|
+
var lang = getLanguageFromPath(filePath);
|
|
1819
|
+
return buildDiffChrome(
|
|
1820
|
+
filePath,
|
|
1821
|
+
oldStr,
|
|
1822
|
+
newStr,
|
|
1823
|
+
function () { return renderUnifiedDiff(oldStr, newStr, lang); },
|
|
1824
|
+
function () { return renderSplitDiff(oldStr, newStr, lang); }
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
function renderPatchDiffBlock(patchText, filePath) {
|
|
1829
|
+
var lang = getLanguageFromPath(filePath);
|
|
1830
|
+
var sources = reconstructPatchSources(patchText);
|
|
1831
|
+
return buildDiffChrome(
|
|
1832
|
+
filePath,
|
|
1833
|
+
sources.oldStr,
|
|
1834
|
+
sources.newStr,
|
|
1835
|
+
function () { return renderPatchDiff(patchText, lang); },
|
|
1836
|
+
function () { return renderSplitDiff(sources.oldStr, sources.newStr, lang); }
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1817
1840
|
function isDiffContent(text) {
|
|
1818
1841
|
var lines = text.split("\n");
|
|
1819
1842
|
var hasHunkHeader = false;
|
|
@@ -1921,8 +1944,12 @@ export function updateToolResult(id, content, isError, images) {
|
|
|
1921
1944
|
if (hasEditDiff) {
|
|
1922
1945
|
resultBlock.appendChild(renderEditDiff(tool.input.old_string, tool.input.new_string, tool.input.file_path));
|
|
1923
1946
|
} else if (!isError && isDiffContent(displayContent)) {
|
|
1924
|
-
var
|
|
1925
|
-
|
|
1947
|
+
var patchFilePath = tool.input && tool.input.file_path ? tool.input.file_path : null;
|
|
1948
|
+
if (patchFilePath) {
|
|
1949
|
+
resultBlock.appendChild(renderPatchDiffBlock(displayContent, patchFilePath));
|
|
1950
|
+
} else {
|
|
1951
|
+
resultBlock.appendChild(renderPatchDiff(displayContent, null));
|
|
1952
|
+
}
|
|
1926
1953
|
} else if (!isError && tool.name === "Read" && tool.input && tool.input.file_path && isImagePath(tool.input.file_path)) {
|
|
1927
1954
|
// Image file: show inline preview
|
|
1928
1955
|
var imgWrap = document.createElement("div");
|
package/lib/public/sw.js
CHANGED
package/lib/sessions.js
CHANGED
|
@@ -96,6 +96,7 @@ function createSessionManager(opts) {
|
|
|
96
96
|
if (session.vendor) metaObj.vendor = session.vendor;
|
|
97
97
|
if (session.sessionVisibility) metaObj.sessionVisibility = session.sessionVisibility;
|
|
98
98
|
if (session.bookmarked) metaObj.bookmarked = true;
|
|
99
|
+
if (typeof session.favoriteOrder === "number") metaObj.favoriteOrder = session.favoriteOrder;
|
|
99
100
|
if (session.lastRewindUuid) metaObj.lastRewindUuid = session.lastRewindUuid;
|
|
100
101
|
if (session.loop) metaObj.loop = session.loop;
|
|
101
102
|
if (session.debateState) metaObj.debateState = session.debateState;
|
|
@@ -202,6 +203,7 @@ function createSessionManager(opts) {
|
|
|
202
203
|
if (m.ownerId) session.ownerId = m.ownerId;
|
|
203
204
|
session.sessionVisibility = m.sessionVisibility || "shared";
|
|
204
205
|
session.bookmarked = !!m.bookmarked;
|
|
206
|
+
session.favoriteOrder = typeof m.favoriteOrder === "number" ? m.favoriteOrder : null;
|
|
205
207
|
sessions.set(localId, session);
|
|
206
208
|
}
|
|
207
209
|
}
|
|
@@ -241,6 +243,7 @@ function createSessionManager(opts) {
|
|
|
241
243
|
ownerId: s.ownerId || null,
|
|
242
244
|
sessionVisibility: s.sessionVisibility || "shared",
|
|
243
245
|
bookmarked: !!s.bookmarked,
|
|
246
|
+
favoriteOrder: typeof s.favoriteOrder === "number" ? s.favoriteOrder : null,
|
|
244
247
|
unread: unreadMap[s.localId] || 0,
|
|
245
248
|
vendor: s.vendor || null,
|
|
246
249
|
};
|
|
@@ -303,6 +306,7 @@ function createSessionManager(opts) {
|
|
|
303
306
|
ownerId: (sessionOpts && sessionOpts.ownerId) || null,
|
|
304
307
|
sessionVisibility: (sessionOpts && sessionOpts.sessionVisibility) || "shared",
|
|
305
308
|
bookmarked: false,
|
|
309
|
+
favoriteOrder: null,
|
|
306
310
|
vendor: (sessionOpts && sessionOpts.vendor) || null,
|
|
307
311
|
};
|
|
308
312
|
sessions.set(localId, session);
|
|
@@ -334,6 +338,7 @@ function createSessionManager(opts) {
|
|
|
334
338
|
ownerId: (sessionOpts && sessionOpts.ownerId) || null,
|
|
335
339
|
sessionVisibility: (sessionOpts && sessionOpts.sessionVisibility) || "shared",
|
|
336
340
|
bookmarked: false,
|
|
341
|
+
favoriteOrder: null,
|
|
337
342
|
vendor: (sessionOpts && sessionOpts.vendor) || null,
|
|
338
343
|
};
|
|
339
344
|
sessions.set(localId, session);
|
|
@@ -525,6 +530,38 @@ function createSessionManager(opts) {
|
|
|
525
530
|
sessions.delete(localId);
|
|
526
531
|
}
|
|
527
532
|
|
|
533
|
+
function deleteSessionsBulk(localIds, targetWs) {
|
|
534
|
+
if (!Array.isArray(localIds) || localIds.length === 0) return;
|
|
535
|
+
|
|
536
|
+
var seen = {};
|
|
537
|
+
var ids = [];
|
|
538
|
+
for (var i = 0; i < localIds.length; i++) {
|
|
539
|
+
var id = localIds[i];
|
|
540
|
+
if (typeof id !== "number" || seen[id] || !sessions.has(id)) continue;
|
|
541
|
+
seen[id] = true;
|
|
542
|
+
ids.push(id);
|
|
543
|
+
}
|
|
544
|
+
if (ids.length === 0) return;
|
|
545
|
+
|
|
546
|
+
var deletedActive = false;
|
|
547
|
+
for (var j = 0; j < ids.length; j++) {
|
|
548
|
+
if (ids[j] === activeSessionId) deletedActive = true;
|
|
549
|
+
deleteSessionQuiet(ids[j]);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (sessions.size === 0) {
|
|
553
|
+
createSession(null, targetWs);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (deletedActive) {
|
|
558
|
+
var remaining = [...sessions.keys()];
|
|
559
|
+
switchSession(remaining[remaining.length - 1], targetWs);
|
|
560
|
+
} else {
|
|
561
|
+
broadcastSessionList();
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
528
565
|
function doSendToSession(session, obj) {
|
|
529
566
|
// Send to active clients without recording to history/disk (ephemeral data)
|
|
530
567
|
if (sendEach) {
|
|
@@ -622,6 +659,7 @@ function createSessionManager(opts) {
|
|
|
622
659
|
history: cliHistory,
|
|
623
660
|
messageUUIDs: [],
|
|
624
661
|
bookmarked: false,
|
|
662
|
+
favoriteOrder: null,
|
|
625
663
|
};
|
|
626
664
|
sessions.set(localId, session);
|
|
627
665
|
saveSessionFile(session);
|
|
@@ -843,6 +881,7 @@ function createSessionManager(opts) {
|
|
|
843
881
|
switchSession: switchSession,
|
|
844
882
|
deleteSession: deleteSession,
|
|
845
883
|
deleteSessionQuiet: deleteSessionQuiet,
|
|
884
|
+
deleteSessionsBulk: deleteSessionsBulk,
|
|
846
885
|
resumeSession: resumeSession,
|
|
847
886
|
broadcastSessionList: broadcastSessionList,
|
|
848
887
|
getTotalUnread: function (ws) {
|
|
@@ -876,10 +915,61 @@ function createSessionManager(opts) {
|
|
|
876
915
|
var session = sessions.get(localId);
|
|
877
916
|
if (!session) return { error: "Session not found" };
|
|
878
917
|
session.bookmarked = !!bookmarked;
|
|
918
|
+
if (session.bookmarked) {
|
|
919
|
+
var maxOrder = -1;
|
|
920
|
+
sessions.forEach(function (s) {
|
|
921
|
+
if (s.bookmarked && typeof s.favoriteOrder === "number" && s.favoriteOrder > maxOrder) {
|
|
922
|
+
maxOrder = s.favoriteOrder;
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
session.favoriteOrder = maxOrder + 1;
|
|
926
|
+
} else {
|
|
927
|
+
session.favoriteOrder = null;
|
|
928
|
+
}
|
|
879
929
|
saveSessionFile(session);
|
|
880
930
|
broadcastSessionList();
|
|
881
931
|
return { ok: true };
|
|
882
932
|
},
|
|
933
|
+
reorderBookmarkedSessions: function (sourceId, targetId, insertBefore) {
|
|
934
|
+
var source = sessions.get(sourceId);
|
|
935
|
+
var target = sessions.get(targetId);
|
|
936
|
+
if (!source || !target) return { error: "Session not found" };
|
|
937
|
+
if (!source.bookmarked || !target.bookmarked) return { error: "Only favorites can be reordered" };
|
|
938
|
+
|
|
939
|
+
var favorites = [];
|
|
940
|
+
sessions.forEach(function (s) {
|
|
941
|
+
if (s.bookmarked) favorites.push(s);
|
|
942
|
+
});
|
|
943
|
+
favorites.sort(function (a, b) {
|
|
944
|
+
var ao = typeof a.favoriteOrder === "number" ? a.favoriteOrder : Number.MAX_SAFE_INTEGER;
|
|
945
|
+
var bo = typeof b.favoriteOrder === "number" ? b.favoriteOrder : Number.MAX_SAFE_INTEGER;
|
|
946
|
+
if (ao !== bo) return ao - bo;
|
|
947
|
+
return (b.lastActivity || 0) - (a.lastActivity || 0);
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
var reordered = [];
|
|
951
|
+
for (var i = 0; i < favorites.length; i++) {
|
|
952
|
+
if (favorites[i].localId !== sourceId) reordered.push(favorites[i]);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
var targetIdx = -1;
|
|
956
|
+
for (var j = 0; j < reordered.length; j++) {
|
|
957
|
+
if (reordered[j].localId === targetId) {
|
|
958
|
+
targetIdx = j;
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
if (targetIdx === -1) return { error: "Target favorite not found" };
|
|
963
|
+
if (!insertBefore) targetIdx++;
|
|
964
|
+
reordered.splice(targetIdx, 0, source);
|
|
965
|
+
|
|
966
|
+
for (var k = 0; k < reordered.length; k++) {
|
|
967
|
+
reordered[k].favoriteOrder = k;
|
|
968
|
+
saveSessionFile(reordered[k]);
|
|
969
|
+
}
|
|
970
|
+
broadcastSessionList();
|
|
971
|
+
return { ok: true };
|
|
972
|
+
},
|
|
883
973
|
setSessionOwner: function (localId, ownerId) {
|
|
884
974
|
var session = sessions.get(localId);
|
|
885
975
|
if (!session) return { error: "Session not found" };
|
package/lib/ws-schema.js
CHANGED
|
@@ -21,6 +21,8 @@ var schema = {
|
|
|
21
21
|
"delete_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Delete a session by ID" },
|
|
22
22
|
"rename_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Rename a session" },
|
|
23
23
|
"set_session_bookmark": { direction: "c2s", handler: "lib/project-sessions.js", description: "Bookmark or unbookmark a session in the sidebar" },
|
|
24
|
+
"reorder_session_bookmarks": { direction: "c2s", handler: "lib/project-sessions.js", description: "Reorder favorited sessions within the favorites area" },
|
|
25
|
+
"bulk_delete_sessions": { direction: "c2s", handler: "lib/project-sessions.js", description: "Delete a group of sessions at once" },
|
|
24
26
|
"resume_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Resume a CLI session by its CLI session ID" },
|
|
25
27
|
"set_session_visibility": { direction: "c2s", handler: "lib/project-sessions.js", description: "Show or hide a session in the sidebar" },
|
|
26
28
|
"search_sessions": { direction: "c2s", handler: "lib/project-sessions.js", description: "Search session titles" },
|
|
@@ -793,10 +793,37 @@ function createCodexQueryHandle(appServer, queryOpts) {
|
|
|
793
793
|
|
|
794
794
|
// --- Main query loop ---
|
|
795
795
|
async function runQueryLoop(initialMessage) {
|
|
796
|
-
// Prepend system prompt (project instructions from YOKE layer) to first message
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
796
|
+
// Prepend system prompt (project instructions from YOKE layer) to first message.
|
|
797
|
+
// initialMessage may be a string (text-only) or an array of content items
|
|
798
|
+
// (e.g. [{ type: "text", text: "..." }, ...] when images/attachments are present).
|
|
799
|
+
// Naive string concatenation on an array coerces it via toString(), producing
|
|
800
|
+
// "[object Object]" inside the prompt, so we must branch on the shape.
|
|
801
|
+
var currentMessage;
|
|
802
|
+
if (!systemPrompt) {
|
|
803
|
+
currentMessage = initialMessage;
|
|
804
|
+
} else if (typeof initialMessage === "string") {
|
|
805
|
+
currentMessage = systemPrompt + "\n\n" + initialMessage;
|
|
806
|
+
} else if (Array.isArray(initialMessage)) {
|
|
807
|
+
// Prepend systemPrompt to the first text item; if none exists, insert one.
|
|
808
|
+
var cloned = initialMessage.slice();
|
|
809
|
+
var injected = false;
|
|
810
|
+
for (var i = 0; i < cloned.length; i++) {
|
|
811
|
+
if (cloned[i] && cloned[i].type === "text") {
|
|
812
|
+
cloned[i] = {
|
|
813
|
+
type: "text",
|
|
814
|
+
text: systemPrompt + "\n\n" + (cloned[i].text || ""),
|
|
815
|
+
};
|
|
816
|
+
injected = true;
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
if (!injected) {
|
|
821
|
+
cloned.unshift({ type: "text", text: systemPrompt });
|
|
822
|
+
}
|
|
823
|
+
currentMessage = cloned;
|
|
824
|
+
} else {
|
|
825
|
+
currentMessage = initialMessage;
|
|
826
|
+
}
|
|
800
827
|
|
|
801
828
|
try {
|
|
802
829
|
// Set event handler on app-server
|