clay-server 3.5.1 → 3.6.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/README.md +54 -196
- package/bin/cli.js +7 -42
- package/lib/builtin-mates.js +1 -1
- package/lib/cli-wordmark.js +32 -0
- package/lib/daemon.js +7 -0
- package/lib/os-user-diagnostics-worker.js +18 -0
- package/lib/os-user-diagnostics.js +312 -0
- package/lib/os-users.js +55 -22
- package/lib/pages.js +47 -35
- package/lib/public/app.js +2 -10
- package/lib/public/apple-touch-icon.png +0 -0
- package/lib/public/clay-studio-favicon-32.png +0 -0
- package/lib/public/clay-studio-symbol.png +0 -0
- package/lib/public/clay-studio-wordmark.svg +20 -0
- package/lib/public/css/base.css +143 -61
- package/lib/public/css/filebrowser.css +132 -22
- package/lib/public/css/icon-strip.css +33 -19
- package/lib/public/css/input.css +15 -5
- package/lib/public/css/messages.css +17 -14
- package/lib/public/css/mobile-nav.css +5 -5
- package/lib/public/css/overlays.css +58 -6
- package/lib/public/css/pane.css +0 -1
- package/lib/public/css/session-actions.css +9 -3
- package/lib/public/css/sidebar.css +104 -161
- package/lib/public/css/title-bar.css +51 -18
- package/lib/public/css/user-settings.css +114 -8
- package/lib/public/icon-192.png +0 -0
- package/lib/public/icon-512.png +0 -0
- package/lib/public/index.html +44 -82
- package/lib/public/manifest.json +1 -6
- package/lib/public/modules/app-connection.js +0 -3
- package/lib/public/modules/app-favicon.js +22 -29
- package/lib/public/modules/app-messages.js +1 -2
- package/lib/public/modules/app-notifications.js +3 -3
- package/lib/public/modules/command-palette.js +1 -1
- package/lib/public/modules/filebrowser-tabs.js +42 -3
- package/lib/public/modules/filebrowser.js +78 -9
- package/lib/public/modules/server-settings.js +0 -77
- package/lib/public/modules/sidebar-projects.js +1 -1
- package/lib/public/modules/sidebar-sessions.js +18 -5
- package/lib/public/modules/sidebar.js +2 -2
- package/lib/public/modules/theme.js +88 -249
- package/lib/public/modules/user-settings.js +2 -3
- package/lib/public/style.css +10 -10
- package/lib/public/sw.js +4 -2
- package/lib/themes/clay-dark.json +11 -0
- package/lib/themes/clay-light.json +11 -0
- package/package.json +1 -1
- package/lib/public/apple-touch-icon-dark.png +0 -0
- package/lib/public/clay-logo.png +0 -0
- package/lib/public/favicon-banded-32.png +0 -0
- package/lib/public/favicon-banded.png +0 -0
- package/lib/public/favicon-dark.svg +0 -1
- package/lib/public/favicon.svg +0 -1
- package/lib/public/icon-192-dark.png +0 -0
- package/lib/public/icon-512-dark.png +0 -0
- package/lib/public/icon-banded-76.png +0 -0
- package/lib/public/icon-banded-96.png +0 -0
- package/lib/public/icon-mono.svg +0 -1
- package/lib/public/modules/ascii-logo.js +0 -442
- package/lib/public/wordmark-banded-20.png +0 -0
- package/lib/public/wordmark-banded-32.png +0 -0
- package/lib/public/wordmark-banded-64.png +0 -0
- package/lib/public/wordmark-banded-80.png +0 -0
|
@@ -30,7 +30,7 @@ import { handleFsList, handleFsRead, handleFileChanged, handleDirChanged, handle
|
|
|
30
30
|
import { beginMarkdownTurn, finishMarkdownTurn, markdownPathFromToolInput } from './markdown-live-edit.js';
|
|
31
31
|
import { forwardPaneMarkdownPresentation } from './pane-bridge.js';
|
|
32
32
|
import { isProjectSettingsOpen, handleInstructionsRead, handleInstructionsWrite, handleProjectEnv, handleProjectEnvSaved, handleProjectSharedEnv, handleProjectSharedEnvSaved, handleProjectOwnerChanged } from './project-settings.js';
|
|
33
|
-
import {
|
|
33
|
+
import { updateSettingsStats, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleInheritGroupsChanged, handleAutoContinueChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleGlobalClaudeMdRead, handleGlobalClaudeMdWrite } from './server-settings.js';
|
|
34
34
|
import { handleTermList, handleTermCreated, sendTerminalCommand, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed } from './terminal.js';
|
|
35
35
|
import { attachTuiView, detachTuiView, setTuiSuspendedView, tuiHandleTermOutput, tuiHandleTermResized, tuiHandleTermExited, tuiHandleTermClosed } from './session-tui-view.js';
|
|
36
36
|
import { handleTuiTranscriptState } from './tui-grab.js';
|
|
@@ -467,7 +467,6 @@ export function processMessage(msg) {
|
|
|
467
467
|
if (msg.vendor && !store.get('vendorSelectionLocked')) _miUpdate.currentVendor = msg.vendor;
|
|
468
468
|
if (msg.capabilities) _miUpdate.vendorCapabilities = msg.capabilities;
|
|
469
469
|
store.set(_miUpdate);
|
|
470
|
-
updateSettingsModels(_modelVal, msg.models || []);
|
|
471
470
|
break;
|
|
472
471
|
}
|
|
473
472
|
|
|
@@ -138,11 +138,11 @@ function showBanner(notif, autoDismissMs) {
|
|
|
138
138
|
: mate
|
|
139
139
|
? '<img class="notif-banner-avatar" src="' + escapeHtml(mateAvatarUrl(mate, 32)) + '" alt="' + escapeHtml(mate.displayName || mate.name || "Mate") + '">'
|
|
140
140
|
: isAuthRequired
|
|
141
|
-
? '<img src="/
|
|
141
|
+
? '<img src="/clay-studio-symbol.png" width="32" height="32" alt="Clay Studio">'
|
|
142
142
|
: projectIcon
|
|
143
143
|
? '<span class="notif-banner-emoji">' + projectIcon + '</span>'
|
|
144
144
|
: isEmpty
|
|
145
|
-
? '<img src="/
|
|
145
|
+
? '<img src="/clay-studio-symbol.png" width="32" height="32" alt="Clay Studio">'
|
|
146
146
|
: iconHtml("folder");
|
|
147
147
|
|
|
148
148
|
// Format permission title as "Can I ..." style
|
|
@@ -828,7 +828,7 @@ export function showUpdateBanner(msg) {
|
|
|
828
828
|
}
|
|
829
829
|
|
|
830
830
|
banner.innerHTML =
|
|
831
|
-
'<div class="notif-banner-icon"><img src="/
|
|
831
|
+
'<div class="notif-banner-icon"><img src="/clay-studio-symbol.png" width="32" height="32" alt="Clay Studio"></div>' +
|
|
832
832
|
'<div class="notif-banner-body">' +
|
|
833
833
|
'<div class="notif-banner-project">CLAY</div>' +
|
|
834
834
|
'<div class="notif-banner-title">v' + escapeHtml(msg.version) + ' is available</div>' +
|
|
@@ -195,7 +195,7 @@ function updateFooter() {
|
|
|
195
195
|
'<span><kbd>Enter</kbd> select</span>';
|
|
196
196
|
var versionText = cachedVersion ? "v" + cachedVersion : "";
|
|
197
197
|
footerEl.innerHTML =
|
|
198
|
-
'<a href="https://github.com/chadbyte/clay" target="_blank" rel="noopener" class="cmd-palette-brand"><img src="
|
|
198
|
+
'<a href="https://github.com/chadbyte/clay" target="_blank" rel="noopener" class="cmd-palette-brand"><img src="clay-studio-symbol.png" width="13" height="13" alt="">Clay Studio ' + versionText + '</a>' +
|
|
199
199
|
'<span class="cmd-palette-footer-shortcuts">' + shortcuts + '</span>';
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { getFileIconSvg } from './fileicons.js';
|
|
2
|
+
|
|
1
3
|
var tabs = new Map();
|
|
2
4
|
var focusedPath = null;
|
|
5
|
+
var previewPath = null;
|
|
3
6
|
var onFocus = null;
|
|
4
7
|
var onEmpty = null;
|
|
5
8
|
|
|
@@ -15,14 +18,23 @@ function render() {
|
|
|
15
18
|
tabs.forEach(function(value, path) {
|
|
16
19
|
var tab = document.createElement("button");
|
|
17
20
|
tab.type = "button";
|
|
18
|
-
tab.className = "file-viewer-tab" + (path === focusedPath ? " active" : "");
|
|
19
|
-
tab.
|
|
21
|
+
tab.className = "file-viewer-tab" + (path === focusedPath ? " active" : "") + (path === previewPath ? " preview" : "");
|
|
22
|
+
tab.setAttribute("role", "tab");
|
|
23
|
+
tab.setAttribute("aria-selected", path === focusedPath ? "true" : "false");
|
|
20
24
|
tab.title = path;
|
|
21
25
|
tab.addEventListener("click", function() { focusFileViewerTab(path); });
|
|
26
|
+
var icon = document.createElement("span");
|
|
27
|
+
icon.className = "file-viewer-tab-icon";
|
|
28
|
+
icon.innerHTML = getFileIconSvg(label(path));
|
|
29
|
+
var name = document.createElement("span");
|
|
30
|
+
name.className = "file-viewer-tab-label";
|
|
31
|
+
name.textContent = label(path);
|
|
22
32
|
var close = document.createElement("span");
|
|
23
33
|
close.className = "file-viewer-tab-close";
|
|
24
34
|
close.textContent = "×";
|
|
25
35
|
close.addEventListener("click", function(event) { event.stopPropagation(); closeFileViewerTab(path); });
|
|
36
|
+
tab.appendChild(icon);
|
|
37
|
+
tab.appendChild(name);
|
|
26
38
|
tab.appendChild(close);
|
|
27
39
|
root.appendChild(tab);
|
|
28
40
|
});
|
|
@@ -37,11 +49,37 @@ export function openFileViewerTab(path, data) {
|
|
|
37
49
|
if (!path) return false;
|
|
38
50
|
var exists = tabs.has(path);
|
|
39
51
|
tabs.set(path, Object.assign(tabs.get(path) || {}, data || {}));
|
|
52
|
+
if (path === previewPath) previewPath = null;
|
|
53
|
+
focusedPath = path;
|
|
54
|
+
render();
|
|
55
|
+
return !exists;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function previewFileViewerTab(path, data) {
|
|
59
|
+
if (!path) return false;
|
|
60
|
+
if (tabs.has(path) && path !== previewPath) {
|
|
61
|
+
focusedPath = path;
|
|
62
|
+
render();
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (previewPath && previewPath !== path) tabs.delete(previewPath);
|
|
66
|
+
var exists = tabs.has(path);
|
|
67
|
+
tabs.set(path, Object.assign(tabs.get(path) || {}, data || {}));
|
|
68
|
+
previewPath = path;
|
|
40
69
|
focusedPath = path;
|
|
41
70
|
render();
|
|
42
71
|
return !exists;
|
|
43
72
|
}
|
|
44
73
|
|
|
74
|
+
export function updateFileViewerTab(path, data) {
|
|
75
|
+
if (!path) return false;
|
|
76
|
+
if (!tabs.has(path)) return false;
|
|
77
|
+
tabs.set(path, Object.assign(tabs.get(path) || {}, data || {}));
|
|
78
|
+
if (focusedPath !== path) return false;
|
|
79
|
+
render();
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
45
83
|
export function focusFileViewerTab(path) {
|
|
46
84
|
if (!tabs.has(path)) return false;
|
|
47
85
|
focusedPath = path;
|
|
@@ -55,6 +93,7 @@ export function closeFileViewerTab(path) {
|
|
|
55
93
|
var paths = Array.from(tabs.keys());
|
|
56
94
|
var index = paths.indexOf(path);
|
|
57
95
|
tabs.delete(path);
|
|
96
|
+
if (previewPath === path) previewPath = null;
|
|
58
97
|
if (focusedPath === path) focusedPath = paths[index + 1] || paths[index - 1] || null;
|
|
59
98
|
render();
|
|
60
99
|
if (focusedPath && onFocus) onFocus(focusedPath, tabs.get(focusedPath));
|
|
@@ -62,4 +101,4 @@ export function closeFileViewerTab(path) {
|
|
|
62
101
|
}
|
|
63
102
|
|
|
64
103
|
export function focusedFileViewerTab() { return focusedPath; }
|
|
65
|
-
export function clearFileViewerTabs() { tabs.clear(); focusedPath = null; render(); }
|
|
104
|
+
export function clearFileViewerTabs() { tabs.clear(); focusedPath = null; previewPath = null; render(); }
|
|
@@ -9,7 +9,7 @@ import { copyMarkdownFormatting } from './rich-clipboard.js';
|
|
|
9
9
|
import { animateMarkdownChange, beginMarkdownPresentation, cancelMarkdownFollow, isFollowingMarkdown } from './markdown-live-edit.js';
|
|
10
10
|
import { store } from './store.js';
|
|
11
11
|
import { enterMarkdownSlides, exitMarkdownSlides, handleMarkdownSlideKey, syncMarkdownSlidesButton, toggleMarkdownSlideLevelMenu } from './markdown-slides.js';
|
|
12
|
-
import { initFileViewerTabs, openFileViewerTab, closeFileViewerTab, focusedFileViewerTab, clearFileViewerTabs } from './filebrowser-tabs.js';
|
|
12
|
+
import { initFileViewerTabs, openFileViewerTab, previewFileViewerTab, updateFileViewerTab, closeFileViewerTab, focusedFileViewerTab, clearFileViewerTabs } from './filebrowser-tabs.js';
|
|
13
13
|
|
|
14
14
|
var ctx;
|
|
15
15
|
var showDropHint = function () {};
|
|
@@ -18,6 +18,7 @@ var currentContent = null; // last read file content for copy
|
|
|
18
18
|
var currentFilePath = null; // path of the currently viewed file
|
|
19
19
|
var isRendered = false; // markdown render toggle state
|
|
20
20
|
var currentIsMarkdown = false;
|
|
21
|
+
var currentIsSvg = false;
|
|
21
22
|
var historyVisible = false;
|
|
22
23
|
var currentHistoryEntries = [];
|
|
23
24
|
var pendingNavigate = null; // { sessionLocalId, assistantUuid }
|
|
@@ -181,8 +182,12 @@ export function initFileBrowser(_ctx) {
|
|
|
181
182
|
|
|
182
183
|
// Markdown render toggle
|
|
183
184
|
document.getElementById("file-viewer-render").addEventListener("click", function () {
|
|
184
|
-
if (!currentContent || !currentIsMarkdown) return;
|
|
185
|
+
if (!currentContent || (!currentIsMarkdown && !currentIsSvg)) return;
|
|
185
186
|
isRendered = !isRendered;
|
|
187
|
+
if (currentIsSvg) {
|
|
188
|
+
renderSvgBody();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
186
191
|
if (!isRendered && isFollowingMarkdown(currentFilePath)) cancelMarkdownFollow();
|
|
187
192
|
renderBody();
|
|
188
193
|
});
|
|
@@ -377,7 +382,11 @@ function kbCollapseOrAscend() {
|
|
|
377
382
|
}
|
|
378
383
|
|
|
379
384
|
function kbActivate() {
|
|
380
|
-
if (_kbFocused)
|
|
385
|
+
if (!_kbFocused) return;
|
|
386
|
+
if (!isDirRow(_kbFocused) && _kbFocused.dataset.path) {
|
|
387
|
+
openFileViewerTab(_kbFocused.dataset.path);
|
|
388
|
+
}
|
|
389
|
+
_kbFocused.click();
|
|
381
390
|
}
|
|
382
391
|
|
|
383
392
|
function handleTreeKeyDown(e) {
|
|
@@ -500,6 +509,7 @@ export function resetFileBrowser() {
|
|
|
500
509
|
currentFilePath = null;
|
|
501
510
|
isRendered = false;
|
|
502
511
|
currentIsMarkdown = false;
|
|
512
|
+
currentIsSvg = false;
|
|
503
513
|
historyVisible = false;
|
|
504
514
|
currentHistoryEntries = [];
|
|
505
515
|
pendingNavigate = null;
|
|
@@ -541,6 +551,7 @@ export function openFile(filePath, opts) {
|
|
|
541
551
|
|
|
542
552
|
export function openWorkingTreeDiff(diff) {
|
|
543
553
|
if (!diff || !diff.path) return;
|
|
554
|
+
openFileViewerTab(diff.path);
|
|
544
555
|
pendingRenderedOpen = false;
|
|
545
556
|
pendingOpenMode = diff.binary ? null : {
|
|
546
557
|
type: "diff",
|
|
@@ -801,9 +812,14 @@ function renderFilteredTree(container, tree, depth, query) {
|
|
|
801
812
|
var prev = ctx.fileTreeEl.querySelector(".file-tree-item.active");
|
|
802
813
|
if (prev) prev.classList.remove("active");
|
|
803
814
|
rowEl.classList.add("active");
|
|
815
|
+
previewFileViewerTab(filePath);
|
|
804
816
|
requestFileContent(filePath);
|
|
805
817
|
if (window.innerWidth <= 768) closeSidebar();
|
|
806
818
|
});
|
|
819
|
+
rowEl.addEventListener("dblclick", function (e) {
|
|
820
|
+
e.stopPropagation();
|
|
821
|
+
openFileViewerTab(filePath);
|
|
822
|
+
});
|
|
807
823
|
})(entry.path, row);
|
|
808
824
|
|
|
809
825
|
container.appendChild(row);
|
|
@@ -1033,12 +1049,17 @@ function renderEntries(container, entries, depth) {
|
|
|
1033
1049
|
var prev = ctx.fileTreeEl.querySelector(".file-tree-item.active");
|
|
1034
1050
|
if (prev) prev.classList.remove("active");
|
|
1035
1051
|
rowEl.classList.add("active");
|
|
1052
|
+
previewFileViewerTab(filePath);
|
|
1036
1053
|
requestFileContent(filePath);
|
|
1037
1054
|
// Mobile: close sidebar
|
|
1038
1055
|
if (window.innerWidth <= 768) {
|
|
1039
1056
|
closeSidebar();
|
|
1040
1057
|
}
|
|
1041
1058
|
});
|
|
1059
|
+
rowEl.addEventListener("dblclick", function (e) {
|
|
1060
|
+
e.stopPropagation();
|
|
1061
|
+
openFileViewerTab(filePath);
|
|
1062
|
+
});
|
|
1042
1063
|
})(entry.path, row);
|
|
1043
1064
|
|
|
1044
1065
|
container.appendChild(row);
|
|
@@ -1050,7 +1071,7 @@ function renderEntries(container, entries, depth) {
|
|
|
1050
1071
|
// --- File viewer ---
|
|
1051
1072
|
|
|
1052
1073
|
function showFileContent(msg) {
|
|
1053
|
-
|
|
1074
|
+
if (!updateFileViewerTab(msg.path, { content: msg.content })) return;
|
|
1054
1075
|
var pathEl = document.getElementById("file-viewer-path");
|
|
1055
1076
|
var bodyEl = document.getElementById("file-viewer-body");
|
|
1056
1077
|
var renderBtn = document.getElementById("file-viewer-render");
|
|
@@ -1064,13 +1085,14 @@ function showFileContent(msg) {
|
|
|
1064
1085
|
|
|
1065
1086
|
exitMarkdownSlides();
|
|
1066
1087
|
|
|
1067
|
-
pathEl
|
|
1088
|
+
renderFileBreadcrumb(pathEl, msg.path);
|
|
1068
1089
|
var keepRenderState = pendingRefresh && msg.path === currentFilePath;
|
|
1069
1090
|
var prevRendered = isRendered;
|
|
1070
1091
|
pendingRefresh = false;
|
|
1071
1092
|
currentContent = null;
|
|
1072
1093
|
currentFilePath = msg.path;
|
|
1073
1094
|
currentIsMarkdown = false;
|
|
1095
|
+
currentIsSvg = false;
|
|
1074
1096
|
if (!keepRenderState) isRendered = false;
|
|
1075
1097
|
var requestedExt = msg.path.split(".").pop().toLowerCase();
|
|
1076
1098
|
if (pendingRenderedOpen && (requestedExt === "md" || requestedExt === "mdx")) {
|
|
@@ -1095,23 +1117,27 @@ function showFileContent(msg) {
|
|
|
1095
1117
|
currentContent = msg.content;
|
|
1096
1118
|
var ext = requestedExt;
|
|
1097
1119
|
currentIsMarkdown = (ext === "md" || ext === "mdx");
|
|
1120
|
+
currentIsSvg = ext === "svg";
|
|
1098
1121
|
if (pendingRenderedOpen && currentIsMarkdown) isRendered = true;
|
|
1099
1122
|
|
|
1100
|
-
if (currentIsMarkdown) {
|
|
1123
|
+
if (currentIsMarkdown || currentIsSvg) {
|
|
1101
1124
|
renderBtn.classList.remove("hidden");
|
|
1102
|
-
renderBtn.title = "Render markdown";
|
|
1103
|
-
copyBtn.title = "Copy Markdown source";
|
|
1125
|
+
renderBtn.title = currentIsSvg ? "Show SVG source" : "Render markdown";
|
|
1126
|
+
copyBtn.title = currentIsSvg ? "Copy SVG source" : "Copy Markdown source";
|
|
1104
1127
|
} else {
|
|
1105
1128
|
copyBtn.title = "Copy contents";
|
|
1106
1129
|
}
|
|
1107
1130
|
|
|
1108
|
-
//
|
|
1131
|
+
// Markdown starts as source; SVG starts as a safe image preview.
|
|
1109
1132
|
if (currentIsMarkdown) {
|
|
1110
1133
|
var transitionFrom = keepRenderState && prevRendered && previousWasMarkdown &&
|
|
1111
1134
|
isFollowingMarkdown(msg.path) && pathsReferToSameFile(previousPath, msg.path)
|
|
1112
1135
|
? (previousContent == null ? "" : previousContent)
|
|
1113
1136
|
: null;
|
|
1114
1137
|
renderBody(transitionFrom, refreshSlideIndex);
|
|
1138
|
+
} else if (currentIsSvg) {
|
|
1139
|
+
if (!keepRenderState) isRendered = true;
|
|
1140
|
+
renderSvgBody();
|
|
1115
1141
|
} else {
|
|
1116
1142
|
renderCodeWithLineNumbers(bodyEl, msg.content, ext);
|
|
1117
1143
|
}
|
|
@@ -1158,6 +1184,47 @@ function showFileContent(msg) {
|
|
|
1158
1184
|
}
|
|
1159
1185
|
}
|
|
1160
1186
|
|
|
1187
|
+
function renderSvgBody() {
|
|
1188
|
+
var bodyEl = document.getElementById("file-viewer-body");
|
|
1189
|
+
var renderBtn = document.getElementById("file-viewer-render");
|
|
1190
|
+
if (!bodyEl || !currentFilePath || currentContent == null) return;
|
|
1191
|
+
if (!isRendered) {
|
|
1192
|
+
renderCodeWithLineNumbers(bodyEl, currentContent, "svg");
|
|
1193
|
+
renderBtn.classList.remove("active");
|
|
1194
|
+
renderBtn.title = "Show SVG preview";
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
bodyEl.innerHTML = "";
|
|
1198
|
+
var preview = document.createElement("div");
|
|
1199
|
+
preview.className = "file-viewer-svg-preview";
|
|
1200
|
+
var image = document.createElement("img");
|
|
1201
|
+
image.src = "api/file?path=" + encodeURIComponent(currentFilePath);
|
|
1202
|
+
image.alt = currentFilePath;
|
|
1203
|
+
image.draggable = false;
|
|
1204
|
+
preview.appendChild(image);
|
|
1205
|
+
bodyEl.appendChild(preview);
|
|
1206
|
+
renderBtn.classList.add("active");
|
|
1207
|
+
renderBtn.title = "Show SVG source";
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
function renderFileBreadcrumb(root, path) {
|
|
1211
|
+
root.innerHTML = "";
|
|
1212
|
+
root.title = path;
|
|
1213
|
+
var parts = String(path || "").replace(/\\/g, "/").split("/").filter(function(part) { return part; });
|
|
1214
|
+
for (var i = 0; i < parts.length; i++) {
|
|
1215
|
+
if (i > 0) {
|
|
1216
|
+
var separator = document.createElement("span");
|
|
1217
|
+
separator.className = "file-viewer-path-separator";
|
|
1218
|
+
separator.textContent = "›";
|
|
1219
|
+
root.appendChild(separator);
|
|
1220
|
+
}
|
|
1221
|
+
var segment = document.createElement("span");
|
|
1222
|
+
segment.className = "file-viewer-path-segment" + (i === parts.length - 1 ? " current" : "");
|
|
1223
|
+
segment.textContent = parts[i];
|
|
1224
|
+
root.appendChild(segment);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1161
1228
|
function pathsReferToSameFile(left, right) {
|
|
1162
1229
|
if (!left || !right) return false;
|
|
1163
1230
|
var a = String(left).replace(/\\/g, "/");
|
|
@@ -1454,6 +1521,8 @@ function rerenderFileContent() {
|
|
|
1454
1521
|
|
|
1455
1522
|
if (currentIsMarkdown) {
|
|
1456
1523
|
renderBody();
|
|
1524
|
+
} else if (currentIsSvg) {
|
|
1525
|
+
renderSvgBody();
|
|
1457
1526
|
} else {
|
|
1458
1527
|
renderCodeWithLineNumbers(bodyEl, currentContent, ext);
|
|
1459
1528
|
}
|
|
@@ -4,7 +4,6 @@ import { showToast, copyToClipboard } from './utils.js';
|
|
|
4
4
|
import { parseEnvString, looksLikeEnv } from './project-settings.js';
|
|
5
5
|
import { checkAdminAccess, loadAdminSection } from './admin.js';
|
|
6
6
|
import { closeFileViewer } from './filebrowser.js';
|
|
7
|
-
import { renderModelList, renderModeList, renderEffortBar, renderThinkingBar, renderBetaCard, isSonnetModel } from './settings-defaults.js';
|
|
8
7
|
|
|
9
8
|
var ctx = null;
|
|
10
9
|
var settingsEl = null;
|
|
@@ -111,18 +110,6 @@ export function initServerSettings(appCtx) {
|
|
|
111
110
|
});
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
// Model item click
|
|
115
|
-
settingsEl.addEventListener("click", function (e) {
|
|
116
|
-
var modelItem = e.target.closest(".settings-model-item");
|
|
117
|
-
if (!modelItem) return;
|
|
118
|
-
var model = modelItem.dataset.model;
|
|
119
|
-
if (!model) return;
|
|
120
|
-
var ws = ctx.ws;
|
|
121
|
-
if (ws && ws.readyState === 1) {
|
|
122
|
-
ws.send(JSON.stringify({ type: "set_server_default_model", model: model }));
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
113
|
// PIN buttons
|
|
127
114
|
var pinSetBtn = document.getElementById("settings-pin-set-btn");
|
|
128
115
|
var pinRemoveBtn = document.getElementById("settings-pin-remove-btn");
|
|
@@ -348,12 +335,6 @@ function populateSettings() {
|
|
|
348
335
|
// Sync notification toggles
|
|
349
336
|
syncNotifToggles();
|
|
350
337
|
|
|
351
|
-
// Session defaults
|
|
352
|
-
updateModelList();
|
|
353
|
-
updateModeList();
|
|
354
|
-
updateEffortBar();
|
|
355
|
-
updateThinkingBar();
|
|
356
|
-
updateSsBetaCard();
|
|
357
338
|
}
|
|
358
339
|
|
|
359
340
|
function syncNotifToggles() {
|
|
@@ -369,51 +350,6 @@ function syncNotifToggles() {
|
|
|
369
350
|
}
|
|
370
351
|
}
|
|
371
352
|
|
|
372
|
-
function ssSendMsg(type, data) {
|
|
373
|
-
var ws = ctx.ws;
|
|
374
|
-
if (ws && ws.readyState === 1) {
|
|
375
|
-
var msg = Object.assign({ type: type }, data);
|
|
376
|
-
ws.send(JSON.stringify(msg));
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function ssDefaultsOpts() {
|
|
381
|
-
return {
|
|
382
|
-
models: ctx.currentModels || [],
|
|
383
|
-
currentModel: ctx.currentModel || ctx._currentModelValue || "",
|
|
384
|
-
currentMode: ctx.currentMode || "default",
|
|
385
|
-
currentEffort: ctx.currentEffort || "medium",
|
|
386
|
-
currentThinking: ctx.currentThinking || "adaptive",
|
|
387
|
-
currentThinkingBudget: ctx.currentThinkingBudget || 10000,
|
|
388
|
-
currentBetas: ctx.currentBetas || [],
|
|
389
|
-
sendMsg: ssSendMsg,
|
|
390
|
-
modelMsgType: "set_model",
|
|
391
|
-
modeMsgType: "set_server_default_mode",
|
|
392
|
-
effortMsgType: "set_server_default_effort",
|
|
393
|
-
onModelSelect: function (model) { updateSsBetaCard(model); },
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function updateModelList() {
|
|
398
|
-
renderModelList("ss", ssDefaultsOpts());
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function updateModeList() {
|
|
402
|
-
renderModeList("ss", ssDefaultsOpts());
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
function updateEffortBar() {
|
|
406
|
-
renderEffortBar("ss", ssDefaultsOpts());
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function updateThinkingBar() {
|
|
410
|
-
renderThinkingBar("ss", ssDefaultsOpts());
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function updateSsBetaCard(overrideModel) {
|
|
414
|
-
renderBetaCard("ss", Object.assign(ssDefaultsOpts(), { overrideModel: overrideModel }));
|
|
415
|
-
}
|
|
416
|
-
|
|
417
353
|
export function updateSettingsStats(data) {
|
|
418
354
|
if (!isSettingsOpen()) return;
|
|
419
355
|
var pid = document.getElementById("settings-status-pid");
|
|
@@ -429,19 +365,6 @@ export function updateSettingsStats(data) {
|
|
|
429
365
|
if (clients) clients.textContent = String(data.clients);
|
|
430
366
|
}
|
|
431
367
|
|
|
432
|
-
export function updateSettingsModels(current, models) {
|
|
433
|
-
if (!ctx) return;
|
|
434
|
-
ctx.currentModels = models;
|
|
435
|
-
ctx._currentModelValue = current;
|
|
436
|
-
if (isSettingsOpen()) {
|
|
437
|
-
updateModelList();
|
|
438
|
-
updateModeList();
|
|
439
|
-
updateEffortBar();
|
|
440
|
-
updateThinkingBar();
|
|
441
|
-
updateSsBetaCard();
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
368
|
// --- Daemon config ---
|
|
446
369
|
function requestDaemonConfig() {
|
|
447
370
|
var ws = ctx.ws;
|
|
@@ -275,7 +275,7 @@ export function initSidebarProjects() {
|
|
|
275
275
|
// Tooltip + click for home icon
|
|
276
276
|
var homeIcon = document.querySelector(".icon-strip-home");
|
|
277
277
|
if (homeIcon) {
|
|
278
|
-
homeIcon.addEventListener("mouseenter", function () { showIconTooltip(homeIcon, "Clay"); });
|
|
278
|
+
homeIcon.addEventListener("mouseenter", function () { showIconTooltip(homeIcon, "Clay Studio"); });
|
|
279
279
|
homeIcon.addEventListener("mouseleave", hideIconTooltip);
|
|
280
280
|
homeIcon.addEventListener("click", function (e) {
|
|
281
281
|
e.preventDefault();
|
|
@@ -1252,14 +1252,19 @@ function renderSessionItem(s) {
|
|
|
1252
1252
|
el.className = "session-item" + (s.active ? " active" : "") + (isMatch ? " search-match" : "");
|
|
1253
1253
|
el.dataset.sessionId = s.id;
|
|
1254
1254
|
|
|
1255
|
+
// Keep agent identity separate from the title so each row has a stable
|
|
1256
|
+
// visual anchor instead of mixing a tiny inline logo into the text.
|
|
1257
|
+
var itemVendor = s.vendor || "claude";
|
|
1258
|
+
var vendorIcon = document.createElement("img");
|
|
1259
|
+
vendorIcon.className = "session-vendor-icon session-vendor-mark";
|
|
1260
|
+
vendorIcon.src = VENDOR_AVATARS[itemVendor] || VENDOR_AVATARS.claude;
|
|
1261
|
+
vendorIcon.alt = "";
|
|
1262
|
+
vendorIcon.title = VENDOR_NAMES[itemVendor] || itemVendor;
|
|
1263
|
+
el.appendChild(vendorIcon);
|
|
1264
|
+
|
|
1255
1265
|
var textSpan = document.createElement("span");
|
|
1256
1266
|
textSpan.className = "session-item-text";
|
|
1257
1267
|
var textHtml = "";
|
|
1258
|
-
// Which agent runtime this session ran on. Legacy sessions without a
|
|
1259
|
-
// recorded vendor are Claude (pre-multi-vendor era).
|
|
1260
|
-
var itemVendor = s.vendor || "claude";
|
|
1261
|
-
textHtml += '<img class="session-vendor-icon" src="' + (VENDOR_AVATARS[itemVendor] || VENDOR_AVATARS.claude) +
|
|
1262
|
-
'" alt="" title="' + escapeHtml(VENDOR_NAMES[itemVendor] || itemVendor) + '">';
|
|
1263
1268
|
if (s.isProcessing) {
|
|
1264
1269
|
textHtml += '<span class="session-processing"></span>';
|
|
1265
1270
|
}
|
|
@@ -1276,6 +1281,14 @@ function renderSessionItem(s) {
|
|
|
1276
1281
|
textSpan.innerHTML = textHtml;
|
|
1277
1282
|
el.appendChild(textSpan);
|
|
1278
1283
|
|
|
1284
|
+
var ageText = relativeTime(s.lastActivity || 0);
|
|
1285
|
+
if (ageText) {
|
|
1286
|
+
var age = document.createElement("span");
|
|
1287
|
+
age.className = "session-item-age";
|
|
1288
|
+
age.textContent = ageText;
|
|
1289
|
+
el.appendChild(age);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1279
1292
|
// Right-click / long-press: context menu
|
|
1280
1293
|
el.addEventListener("contextmenu", (function(id, title, cliSid, anchor, sData) {
|
|
1281
1294
|
return function(e) {
|
|
@@ -46,9 +46,9 @@ export function updatePageTitle() {
|
|
|
46
46
|
if (ctx.projectName && sessionTitle) {
|
|
47
47
|
document.title = sessionTitle + " - " + ctx.projectName;
|
|
48
48
|
} else if (ctx.projectName) {
|
|
49
|
-
document.title = ctx.projectName + " - Clay";
|
|
49
|
+
document.title = ctx.projectName + " - Clay Studio";
|
|
50
50
|
} else {
|
|
51
|
-
document.title = "Clay";
|
|
51
|
+
document.title = "Clay Studio";
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|