clay-server 2.13.0-beta.2 → 2.13.0-beta.4
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/bin/cli.js +48 -0
- package/lib/daemon.js +16 -3
- package/lib/notes.js +1 -1
- package/lib/project.js +275 -7
- package/lib/public/app.js +250 -34
- package/lib/public/css/admin.css +71 -0
- package/lib/public/css/command-palette.css +319 -0
- package/lib/public/css/icon-strip.css +19 -3
- package/lib/public/css/input.css +2 -1
- package/lib/public/css/loop.css +26 -0
- package/lib/public/css/mates.css +73 -0
- package/lib/public/css/overlays.css +3 -0
- package/lib/public/css/scheduler.css +29 -5
- package/lib/public/css/sidebar.css +28 -6
- package/lib/public/css/sticky-notes.css +61 -12
- package/lib/public/css/title-bar.css +24 -30
- package/lib/public/index.html +48 -13
- package/lib/public/modules/admin.js +109 -1
- package/lib/public/modules/command-palette.js +549 -0
- package/lib/public/modules/input.js +10 -2
- package/lib/public/modules/mate-wizard.js +17 -6
- package/lib/public/modules/scheduler.js +56 -64
- package/lib/public/modules/session-search.js +6 -2
- package/lib/public/modules/sidebar.js +128 -72
- package/lib/public/modules/sticky-notes.js +37 -0
- package/lib/public/style.css +1 -0
- package/lib/scheduler.js +4 -0
- package/lib/sdk-bridge.js +10 -8
- package/lib/server.js +334 -7
- package/lib/sessions.js +5 -0
- package/lib/users.js +64 -0
- package/lib/worktree.js +2 -2
- package/package.json +1 -1
|
@@ -8,47 +8,41 @@
|
|
|
8
8
|
background: var(--sidebar-bg);
|
|
9
9
|
display: flex;
|
|
10
10
|
align-items: center;
|
|
11
|
-
justify-content: center;
|
|
12
11
|
padding: calc(var(--safe-top) + 0px) 0 0;
|
|
13
12
|
position: relative;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.top-bar-center {
|
|
17
|
-
display: flex;
|
|
18
|
-
align-items: center;
|
|
19
13
|
gap: 8px;
|
|
20
14
|
}
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
/* --- Update banner --- */
|
|
17
|
+
.top-bar-update {
|
|
18
|
+
position: absolute;
|
|
19
|
+
left: 10px;
|
|
20
|
+
top: 0;
|
|
21
|
+
bottom: 0;
|
|
23
22
|
display: flex;
|
|
24
23
|
align-items: center;
|
|
25
|
-
gap: 5px;
|
|
26
|
-
font-family: "Nunito", sans-serif;
|
|
27
|
-
font-size: 13px;
|
|
28
|
-
font-weight: 700;
|
|
29
|
-
color: var(--text-muted);
|
|
30
|
-
text-decoration: none;
|
|
31
|
-
-webkit-app-region: no-drag;
|
|
32
|
-
transition: color 0.15s;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.top-bar-title:hover {
|
|
36
|
-
color: var(--text);
|
|
37
24
|
}
|
|
38
25
|
|
|
39
|
-
.top-bar-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
26
|
+
.top-bar-update-btn {
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: 4px;
|
|
30
|
+
background: color-mix(in srgb, var(--success) 12%, transparent);
|
|
31
|
+
color: var(--success);
|
|
32
|
+
border: none;
|
|
33
|
+
border-radius: 10px;
|
|
34
|
+
padding: 2px 10px;
|
|
35
|
+
font-family: inherit;
|
|
36
|
+
font-size: 11px;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
line-height: 1;
|
|
41
|
+
transition: background 0.15s;
|
|
47
42
|
}
|
|
48
43
|
|
|
49
|
-
.top-bar-
|
|
50
|
-
|
|
51
|
-
}
|
|
44
|
+
.top-bar-update-btn .lucide { width: 12px; height: 12px; }
|
|
45
|
+
.top-bar-update-btn:hover { background: color-mix(in srgb, var(--success) 20%, transparent); }
|
|
52
46
|
|
|
53
47
|
/* --- Top bar actions (right-aligned group) --- */
|
|
54
48
|
.top-bar-actions {
|
package/lib/public/index.html
CHANGED
|
@@ -30,14 +30,12 @@
|
|
|
30
30
|
<!-- === Top Bar (full width, forms reverse-ㄱ with icon strip) === -->
|
|
31
31
|
<div id="top-bar">
|
|
32
32
|
<button id="pwa-install-pill" class="top-bar-install-btn hidden" title="Install app"><i data-lucide="download"></i></button>
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
<div id="update-
|
|
38
|
-
|
|
39
|
-
<div class="popover-row"><div class="popover-label">Or run manually:</div><div class="popover-cmd"><code id="update-manual-cmd">npx clay-server@latest</code><button class="popover-copy" title="Copy"><i data-lucide="copy"></i></button></div></div>
|
|
40
|
-
</div>
|
|
33
|
+
<button id="cmd-palette-btn" class="cmd-palette-searchbar" title="Command palette"><i data-lucide="search"></i><span class="cmd-palette-searchbar-text">Search sessions, projects, and commands</span><kbd class="cmd-palette-searchbar-kbd"></kbd></button>
|
|
34
|
+
<div id="update-pill-wrap" class="top-bar-update hidden">
|
|
35
|
+
<button id="update-pill" class="top-bar-update-btn"><i data-lucide="arrow-up-circle"></i> <span id="update-version"></span> is available. Update now</button>
|
|
36
|
+
<div id="update-popover" class="top-bar-popover">
|
|
37
|
+
<div class="popover-row"><button id="update-now" class="popover-action popover-action-primary"><i data-lucide="download"></i> Update now</button></div>
|
|
38
|
+
<div class="popover-row"><div class="popover-label">Or run manually:</div><div class="popover-cmd"><code id="update-manual-cmd">npx clay-server@latest</code><button class="popover-copy" title="Copy"><i data-lucide="copy"></i></button></div></div>
|
|
41
39
|
</div>
|
|
42
40
|
</div>
|
|
43
41
|
<div class="top-bar-actions">
|
|
@@ -141,6 +139,7 @@
|
|
|
141
139
|
<i data-lucide="chevron-down" class="title-bar-chevron"></i>
|
|
142
140
|
</button>
|
|
143
141
|
<span id="sidebar-presence" class="sidebar-presence"></span>
|
|
142
|
+
<button id="sidebar-toggle-btn" class="sidebar-collapse-btn" title="Collapse sidebar"><i data-lucide="panel-left-close"></i></button>
|
|
144
143
|
</div>
|
|
145
144
|
<div id="sidebar">
|
|
146
145
|
<div id="sidebar-tools">
|
|
@@ -1244,9 +1243,23 @@
|
|
|
1244
1243
|
</div>
|
|
1245
1244
|
<div class="ralph-step" data-step="2">
|
|
1246
1245
|
<h3>What do you want to build?</h3>
|
|
1247
|
-
<
|
|
1248
|
-
|
|
1249
|
-
|
|
1246
|
+
<div class="ralph-mode-tabs">
|
|
1247
|
+
<button class="ralph-mode-tab active" data-mode="draft">Let Clay draft it</button>
|
|
1248
|
+
<button class="ralph-mode-tab" data-mode="own">I have my own</button>
|
|
1249
|
+
</div>
|
|
1250
|
+
<div class="ralph-mode-panel active" data-mode="draft">
|
|
1251
|
+
<p class="ralph-hint">Write a rough idea, Clay will refine it into detailed instructions. You can review and edit everything before the loop starts.</p>
|
|
1252
|
+
<label class="ralph-field-label" for="ralph-task">Task description <span class="ralph-field-req">*</span></label>
|
|
1253
|
+
<textarea id="ralph-task" rows="5" placeholder="e.g. Add dark mode toggle to the settings page"></textarea>
|
|
1254
|
+
</div>
|
|
1255
|
+
<div class="ralph-mode-panel" data-mode="own">
|
|
1256
|
+
<p class="ralph-hint">Paste your PROMPT.md content. JUDGE.md is optional; if omitted, Clay will generate it for you.</p>
|
|
1257
|
+
<label class="ralph-field-label" for="ralph-prompt-input">PROMPT.md <span class="ralph-field-req">*</span></label>
|
|
1258
|
+
<textarea id="ralph-prompt-input" rows="5" placeholder="Paste your PROMPT.md content here"></textarea>
|
|
1259
|
+
<label class="ralph-field-label" for="ralph-judge-input" style="margin-top: 8px;">JUDGE.md <span class="ralph-field-opt">(optional)</span></label>
|
|
1260
|
+
<p class="ralph-hint" style="margin-top: 2px; margin-bottom: 6px;">The judge reviews each iteration and decides pass/fail. Only needed for multi-iteration loops. For single-run tasks, you can skip this.</p>
|
|
1261
|
+
<textarea id="ralph-judge-input" rows="4" placeholder="Paste your JUDGE.md content here (optional)"></textarea>
|
|
1262
|
+
</div>
|
|
1250
1263
|
</div>
|
|
1251
1264
|
<input type="hidden" id="ralph-max-iterations" value="25">
|
|
1252
1265
|
</div>
|
|
@@ -1294,8 +1307,23 @@
|
|
|
1294
1307
|
<span class="mate-dot" data-step="4"></span>
|
|
1295
1308
|
</div>
|
|
1296
1309
|
<div class="mate-wizard-steps">
|
|
1310
|
+
<!-- Step 0: Intro -->
|
|
1311
|
+
<div class="mate-step active" data-step="0">
|
|
1312
|
+
<div class="mate-intro">
|
|
1313
|
+
<div class="mate-intro-icon">✨</div>
|
|
1314
|
+
<h2 class="mate-intro-title">Meet your Mate.</h2>
|
|
1315
|
+
<p class="mate-intro-tagline">AI agents are built for tasks. A Mate is built for you.</p>
|
|
1316
|
+
<p class="mate-intro-body">Your Mate remembers what you've talked about, learns how you think, and grows with you over time. It's not just what it can do. It's what it learns about you.</p>
|
|
1317
|
+
<div class="mate-intro-steps">
|
|
1318
|
+
<div class="mate-intro-step"><span class="mate-intro-step-num">1</span> Pick a relationship type</div>
|
|
1319
|
+
<div class="mate-intro-step"><span class="mate-intro-step-num">2</span> Have a short interview where your Mate gets to know you</div>
|
|
1320
|
+
<div class="mate-intro-step"><span class="mate-intro-step-num">3</span> Start talking</div>
|
|
1321
|
+
</div>
|
|
1322
|
+
<p class="mate-intro-privacy">Mates run on Claude Code. No separate API keys or external services needed. Your conversations stay on your Clay server and are never stored elsewhere.</p>
|
|
1323
|
+
</div>
|
|
1324
|
+
</div>
|
|
1297
1325
|
<!-- Step 1: Relationship -->
|
|
1298
|
-
<div class="mate-step
|
|
1326
|
+
<div class="mate-step" data-step="1">
|
|
1299
1327
|
<h3>What kind of relationship?</h3>
|
|
1300
1328
|
<p class="mate-hint">Pick the role that best fits what you need. You can refine this later in the interview.</p>
|
|
1301
1329
|
<div class="mate-card-grid">
|
|
@@ -1611,7 +1639,14 @@
|
|
|
1611
1639
|
<!-- Bottom bar -->
|
|
1612
1640
|
<div class="sched-create-bottom">
|
|
1613
1641
|
<div class="sched-create-bottom-left">
|
|
1614
|
-
<
|
|
1642
|
+
<div class="sched-create-run-mode">
|
|
1643
|
+
<button type="button" class="sched-run-mode-btn active" data-mode="single" title="Run once without iteration"><i data-lucide="play"></i> Single run</button>
|
|
1644
|
+
<button type="button" class="sched-run-mode-btn" data-mode="multi" title="Run multiple iterations with a judge reviewing each round"><i data-lucide="repeat"></i> Multi-round</button>
|
|
1645
|
+
<label class="sched-create-iter-label hidden" id="sched-create-iter-group">
|
|
1646
|
+
<input type="number" id="sched-create-iterations" min="2" max="100" value="3" class="sched-create-iter-input">
|
|
1647
|
+
<span class="sched-create-iter-hint">rounds</span>
|
|
1648
|
+
</label>
|
|
1649
|
+
</div>
|
|
1615
1650
|
</div>
|
|
1616
1651
|
<div class="sched-create-bottom-right">
|
|
1617
1652
|
<button class="sched-create-delete-btn hidden" id="sched-create-delete" title="Delete"><i data-lucide="trash-2"></i></button>
|
|
@@ -134,6 +134,9 @@ function renderUsersTab(body) {
|
|
|
134
134
|
html += '</div>';
|
|
135
135
|
if (!isMe) {
|
|
136
136
|
html += '<div style="display:flex;align-items:center;gap:2px">';
|
|
137
|
+
if (u.role !== "admin") {
|
|
138
|
+
html += '<button class="admin-remove-btn admin-perms-btn" data-user-id="' + u.id + '" title="Permissions">' + iconHtml("shield") + '</button>';
|
|
139
|
+
}
|
|
137
140
|
html += '<button class="admin-remove-btn admin-reset-pin-btn" data-user-id="' + u.id + '" title="Reset PIN">' + iconHtml("key-round") + '</button>';
|
|
138
141
|
if (u.role !== "admin") {
|
|
139
142
|
html += '<button class="admin-remove-btn" data-user-id="' + u.id + '" title="Remove user">' + iconHtml("trash-2") + '</button>';
|
|
@@ -177,8 +180,19 @@ function renderUsersTab(body) {
|
|
|
177
180
|
});
|
|
178
181
|
}
|
|
179
182
|
|
|
183
|
+
// Bind permissions buttons
|
|
184
|
+
var permsBtns = body.querySelectorAll(".admin-perms-btn");
|
|
185
|
+
for (var p = 0; p < permsBtns.length; p++) {
|
|
186
|
+
permsBtns[p].addEventListener("click", function (e) {
|
|
187
|
+
e.stopPropagation();
|
|
188
|
+
var userId = this.dataset.userId;
|
|
189
|
+
var user = cachedUsers.find(function (u) { return u.id === userId; });
|
|
190
|
+
if (user) showPermissionsModal(user, body);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
180
194
|
// Bind remove buttons
|
|
181
|
-
var removeBtns = body.querySelectorAll(".admin-remove-btn:not(.admin-reset-pin-btn)");
|
|
195
|
+
var removeBtns = body.querySelectorAll(".admin-remove-btn:not(.admin-reset-pin-btn):not(.admin-perms-btn)");
|
|
182
196
|
for (var k = 0; k < removeBtns.length; k++) {
|
|
183
197
|
removeBtns[k].addEventListener("click", function () {
|
|
184
198
|
var userId = this.dataset.userId;
|
|
@@ -191,6 +205,98 @@ function renderUsersTab(body) {
|
|
|
191
205
|
}
|
|
192
206
|
}
|
|
193
207
|
|
|
208
|
+
var PERM_LABELS = [
|
|
209
|
+
{ key: "terminal", label: "Terminal", desc: "Access the web terminal" },
|
|
210
|
+
{ key: "fileBrowser", label: "File Browser", desc: "Browse and manage files" },
|
|
211
|
+
{ key: "createProject", label: "Create Projects", desc: "Create or clone new projects" },
|
|
212
|
+
{ key: "deleteProject", label: "Delete Projects", desc: "Remove projects" },
|
|
213
|
+
{ key: "skills", label: "Skills", desc: "View and install skills" },
|
|
214
|
+
{ key: "sessionDelete", label: "Delete Sessions", desc: "Delete chat sessions" },
|
|
215
|
+
{ key: "scheduledTasks", label: "Scheduled Tasks", desc: "Create and manage scheduled tasks" },
|
|
216
|
+
{ key: "projectSettings", label: "Project Settings", desc: "Access project settings" },
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
var DEFAULT_PERMISSIONS = {
|
|
220
|
+
terminal: false,
|
|
221
|
+
fileBrowser: false,
|
|
222
|
+
createProject: true,
|
|
223
|
+
deleteProject: false,
|
|
224
|
+
skills: true,
|
|
225
|
+
sessionDelete: false,
|
|
226
|
+
scheduledTasks: false,
|
|
227
|
+
projectSettings: false,
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
function showPermissionsModal(user, body) {
|
|
231
|
+
var perms = {};
|
|
232
|
+
var keys = PERM_LABELS.map(function (p) { return p.key; });
|
|
233
|
+
for (var i = 0; i < keys.length; i++) {
|
|
234
|
+
var k = keys[i];
|
|
235
|
+
perms[k] = (user.permissions && user.permissions[k] !== undefined) ? user.permissions[k] : DEFAULT_PERMISSIONS[k];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
var modal = document.createElement("div");
|
|
239
|
+
modal.className = "admin-modal-overlay";
|
|
240
|
+
var html = '<div class="admin-modal">' +
|
|
241
|
+
'<div class="admin-modal-header">' +
|
|
242
|
+
'<h3>Permissions: ' + escapeHtml(user.displayName || user.username) + '</h3>' +
|
|
243
|
+
'<button class="admin-modal-close">×</button>' +
|
|
244
|
+
'</div>' +
|
|
245
|
+
'<div class="admin-modal-body">' +
|
|
246
|
+
'<div class="admin-perms-list">';
|
|
247
|
+
|
|
248
|
+
for (var j = 0; j < PERM_LABELS.length; j++) {
|
|
249
|
+
var p = PERM_LABELS[j];
|
|
250
|
+
var checked = perms[p.key] ? " checked" : "";
|
|
251
|
+
html += '<label class="admin-perm-row">' +
|
|
252
|
+
'<div class="admin-perm-info">' +
|
|
253
|
+
'<span class="admin-perm-label">' + p.label + '</span>' +
|
|
254
|
+
'<span class="admin-perm-desc">' + p.desc + '</span>' +
|
|
255
|
+
'</div>' +
|
|
256
|
+
'<input type="checkbox" class="admin-perm-toggle" data-perm="' + p.key + '"' + checked + '>' +
|
|
257
|
+
'</label>';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
html += '</div></div>' +
|
|
261
|
+
'<div class="admin-modal-footer">' +
|
|
262
|
+
'<button class="admin-modal-save" id="admin-perms-save">Save</button>' +
|
|
263
|
+
'<button class="admin-modal-cancel">Cancel</button>' +
|
|
264
|
+
'</div></div>';
|
|
265
|
+
|
|
266
|
+
modal.innerHTML = html;
|
|
267
|
+
document.body.appendChild(modal);
|
|
268
|
+
refreshIcons(modal);
|
|
269
|
+
|
|
270
|
+
modal.querySelector(".admin-modal-close").addEventListener("click", function () { modal.remove(); });
|
|
271
|
+
modal.querySelector(".admin-modal-cancel").addEventListener("click", function () { modal.remove(); });
|
|
272
|
+
modal.addEventListener("click", function (e) { if (e.target === modal) modal.remove(); });
|
|
273
|
+
|
|
274
|
+
modal.querySelector("#admin-perms-save").addEventListener("click", function () {
|
|
275
|
+
var toggles = modal.querySelectorAll(".admin-perm-toggle");
|
|
276
|
+
var newPerms = {};
|
|
277
|
+
for (var t = 0; t < toggles.length; t++) {
|
|
278
|
+
newPerms[toggles[t].dataset.perm] = toggles[t].checked;
|
|
279
|
+
}
|
|
280
|
+
apiPut("/api/admin/users/" + user.id + "/permissions", { permissions: newPerms }).then(function (data) {
|
|
281
|
+
if (data.ok) {
|
|
282
|
+
showToast("Permissions updated");
|
|
283
|
+
modal.remove();
|
|
284
|
+
// Update cached user
|
|
285
|
+
for (var c = 0; c < cachedUsers.length; c++) {
|
|
286
|
+
if (cachedUsers[c].id === user.id) {
|
|
287
|
+
cachedUsers[c].permissions = data.permissions;
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
showToast(data.error || "Failed to update permissions");
|
|
293
|
+
}
|
|
294
|
+
}).catch(function () {
|
|
295
|
+
showToast("Failed to update permissions");
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
194
300
|
function showAddUserModal(body) {
|
|
195
301
|
var modal = document.createElement("div");
|
|
196
302
|
modal.className = "admin-modal-overlay";
|
|
@@ -658,6 +764,8 @@ function renderSmtpTab(body, cfg) {
|
|
|
658
764
|
// --- Projects ---
|
|
659
765
|
function loadProjectsTab(body) {
|
|
660
766
|
var projectList = (ctx && ctx.projectList) || [];
|
|
767
|
+
// Exclude worktree projects (they inherit parent settings)
|
|
768
|
+
projectList = projectList.filter(function (p) { return !p.isWorktree; });
|
|
661
769
|
cachedProjects = projectList;
|
|
662
770
|
|
|
663
771
|
if (projectList.length === 0) {
|