clay-server 2.34.0-beta.8 → 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.
@@ -82,16 +82,7 @@ function attachConnection(ctx) {
82
82
  setTimeout(function() { _loop.resumeLoop(); }, 500);
83
83
  }
84
84
 
85
- // Auto-assign owner if project has none and a user connects (e.g. IPC-added projects)
86
85
  var projectOwnerId = getProjectOwnerId();
87
- if (!projectOwnerId && ws._clayUser && ws._clayUser.id && !isMate) {
88
- setProjectOwnerId(ws._clayUser.id);
89
- projectOwnerId = ws._clayUser.id;
90
- if (opts.onProjectOwnerChanged) {
91
- opts.onProjectOwnerChanged(slug, projectOwnerId);
92
- }
93
- console.log("[project] Auto-assigned owner for " + slug + ": " + projectOwnerId);
94
- }
95
86
 
96
87
  // Send cached state
97
88
  var _userId = ws._clayUser ? ws._clayUser.id : null;
@@ -155,6 +146,7 @@ function attachConnection(ctx) {
155
146
  ownerId: s.ownerId || null,
156
147
  sessionVisibility: s.sessionVisibility || "shared",
157
148
  bookmarked: !!s.bookmarked,
149
+ favoriteOrder: typeof s.favoriteOrder === "number" ? s.favoriteOrder : null,
158
150
  };
159
151
  }),
160
152
  });
@@ -39,7 +39,7 @@ function formatAskUserAnswerAsMessage(input, answers) {
39
39
  * sm, sdk, tm, clients,
40
40
  * send, sendTo, sendToAdmins, sendToSession, sendToSessionOthers,
41
41
  * opts, usersModule, userPresence, matesModule, pushModule,
42
- * getSessionForWs, getLinuxUserForSession, getOsUserInfoForWs,
42
+ * getSessionForWs, getLinuxUserForSession, ensureProjectAccessForSession, getOsUserInfoForWs,
43
43
  * hydrateImageRefs, onProcessingChanged, broadcastPresence,
44
44
  * adapter, getProjectList, getProjectCount, getScheduleCount,
45
45
  * moveScheduleToProject, moveAllSchedulesToProject, getHubSchedules,
@@ -70,6 +70,7 @@ function attachSessions(ctx) {
70
70
  var pushModule = ctx.pushModule;
71
71
  var getSessionForWs = ctx.getSessionForWs;
72
72
  var getLinuxUserForSession = ctx.getLinuxUserForSession;
73
+ var ensureProjectAccessForSession = ctx.ensureProjectAccessForSession;
73
74
  var getOsUserInfoForWs = ctx.getOsUserInfoForWs;
74
75
  var hydrateImageRefs = ctx.hydrateImageRefs;
75
76
  var onProcessingChanged = ctx.onProcessingChanged;
@@ -163,6 +164,39 @@ function attachSessions(ctx) {
163
164
  return true;
164
165
  }
165
166
 
167
+ if (msg.type === "reorder_session_bookmarks") {
168
+ if (typeof msg.sourceId === "number" && typeof msg.targetId === "number" && msg.sourceId !== msg.targetId) {
169
+ var source = sm.sessions.get(msg.sourceId);
170
+ var target = sm.sessions.get(msg.targetId);
171
+ if (!source || !target) return true;
172
+ if (usersModule.isMultiUser() && ws._clayUser) {
173
+ if (!usersModule.canAccessSession(ws._clayUser.id, source, { visibility: "public" })) return true;
174
+ if (!usersModule.canAccessSession(ws._clayUser.id, target, { visibility: "public" })) return true;
175
+ }
176
+ sm.reorderBookmarkedSessions(msg.sourceId, msg.targetId, msg.insertBefore !== false);
177
+ }
178
+ return true;
179
+ }
180
+
181
+ if (msg.type === "bulk_delete_sessions") {
182
+ if (!Array.isArray(msg.sessionIds) || msg.sessionIds.length === 0) return true;
183
+ var deletableIds = [];
184
+ for (var di = 0; di < msg.sessionIds.length; di++) {
185
+ var bulkId = msg.sessionIds[di];
186
+ if (typeof bulkId !== "number") continue;
187
+ var bulkTarget = sm.sessions.get(bulkId);
188
+ if (!bulkTarget) continue;
189
+ if (usersModule.isMultiUser() && ws._clayUser) {
190
+ if (!usersModule.canAccessSession(ws._clayUser.id, bulkTarget, { visibility: "public" })) continue;
191
+ }
192
+ deletableIds.push(bulkId);
193
+ }
194
+ if (deletableIds.length > 0) {
195
+ sm.deleteSessionsBulk(deletableIds, ws);
196
+ }
197
+ return true;
198
+ }
199
+
166
200
  if (msg.type === "transfer_project_owner") {
167
201
  // Home directory projects: ownership is permanently locked
168
202
  if (osUsers && osUsers.length > 0 && /^\/home\/[^/]+\//.test(cwd)) {
@@ -803,7 +837,7 @@ function attachSessions(ctx) {
803
837
  session.sentToolResults = {};
804
838
  sendToSession(session.localId, { type: "status", status: "processing" });
805
839
  if (!session.queryInstance && !session.worker) {
806
- sdk.startQuery(session, answerText, undefined, getLinuxUserForSession(session));
840
+ sdk.startQuery(session, answerText, undefined, ensureProjectAccessForSession(session));
807
841
  } else {
808
842
  sdk.pushMessage(session, answerText);
809
843
  }
@@ -932,7 +966,7 @@ function attachSessions(ctx) {
932
966
  newSession.sentToolResults = {};
933
967
  sendToSession(newSession.localId, { type: "status", status: "processing" });
934
968
  newSession.acceptEditsAfterStart = true;
935
- sdk.startQuery(newSession, planPrompt, undefined, getLinuxUserForSession(newSession));
969
+ sdk.startQuery(newSession, planPrompt, undefined, ensureProjectAccessForSession(newSession));
936
970
  } catch (e) {
937
971
  console.error("[project] Error starting plan execution:", e);
938
972
  sendTo(ws, { type: "error", text: "Failed to start plan execution: " + (e.message || e) });
@@ -963,7 +997,7 @@ function attachSessions(ctx) {
963
997
  session.sentToolResults = {};
964
998
  sendToSession(session.localId, { type: "status", status: "processing" });
965
999
  if (!session.queryInstance && !session.worker) {
966
- sdk.startQuery(session, feedback, undefined, getLinuxUserForSession(session));
1000
+ sdk.startQuery(session, feedback, undefined, ensureProjectAccessForSession(session));
967
1001
  } else {
968
1002
  sdk.pushMessage(session, feedback);
969
1003
  }
@@ -13,7 +13,7 @@ var fs = require("fs");
13
13
  * send, sendTo, sendToSession, sendToSessionOthers,
14
14
  * clients, opts,
15
15
  * usersModule, matesModule,
16
- * getSessionForWs, getLinuxUserForSession, getOsUserInfoForWs,
16
+ * getSessionForWs, getLinuxUserForSession, ensureProjectAccessForSession, getOsUserInfoForWs,
17
17
  * hydrateImageRefs, saveImageFile, imagesDir,
18
18
  * onProcessingChanged, onSessionDone,
19
19
  * _loop - { handleLoopMessage: fn(ws, msg) }
@@ -49,6 +49,7 @@ function attachUserMessage(ctx) {
49
49
 
50
50
  var getSessionForWs = ctx.getSessionForWs;
51
51
  var getLinuxUserForSession = ctx.getLinuxUserForSession;
52
+ var ensureProjectAccessForSession = ctx.ensureProjectAccessForSession;
52
53
  var getOsUserInfoForWs = ctx.getOsUserInfoForWs;
53
54
 
54
55
  var hydrateImageRefs = ctx.hydrateImageRefs;
@@ -281,7 +282,7 @@ function attachUserMessage(ctx) {
281
282
  nowSession.isProcessing = true;
282
283
  onProcessingChanged();
283
284
  sendToSession(nowSession.localId, { type: "status", status: "processing" });
284
- sdk.startQuery(nowSession, schedText, null, getLinuxUserForSession(nowSession));
285
+ sdk.startQuery(nowSession, schedText, null, ensureProjectAccessForSession(nowSession));
285
286
  sm.broadcastSessionList();
286
287
  return true;
287
288
  }
@@ -484,7 +485,7 @@ function attachUserMessage(ctx) {
484
485
  // No active query (or worker idle between queries): start a new query
485
486
  session._queryStartTs = Date.now();
486
487
  console.log("[PERF] project.js: startQuery called, localId=" + session.localId + " t=0ms");
487
- sdk.startQuery(session, finalText, msg.images, getLinuxUserForSession(session));
488
+ sdk.startQuery(session, finalText, msg.images, ensureProjectAccessForSession(session));
488
489
  } else {
489
490
  sdk.pushMessage(session, finalText, msg.images);
490
491
  }
package/lib/project.js CHANGED
@@ -9,7 +9,7 @@ var { createNotesManager } = require("./notes");
9
9
  var { fetchLatestVersion, fetchVersion, isNewer } = require("./updater");
10
10
  var { execFileSync, spawn } = require("child_process");
11
11
  var usersModule = require("./users");
12
- var { resolveOsUserInfo, fsAsUser } = require("./os-users");
12
+ var { resolveOsUserInfo, fsAsUser, grantProjectAccess } = require("./os-users");
13
13
  var crisisSafety = require("./crisis-safety");
14
14
  var matesModule = require("./mates");
15
15
  var sessionSearch = require("./session-search");
@@ -188,6 +188,14 @@ function createProjectContext(opts) {
188
188
  return user.linuxUser;
189
189
  }
190
190
 
191
+ function ensureProjectAccessForSession(session) {
192
+ var linuxUser = getLinuxUserForSession(session);
193
+ if (linuxUser) {
194
+ grantProjectAccess(cwd, linuxUser);
195
+ }
196
+ return linuxUser;
197
+ }
198
+
191
199
  function getLinuxUserForWs(ws) {
192
200
  if (!osUsers) return null;
193
201
  if (!ws._clayUser || !ws._clayUser.linuxUser) return null;
@@ -800,7 +808,7 @@ function createProjectContext(opts) {
800
808
  session.isProcessing = true;
801
809
  onProcessingChanged();
802
810
  sendToSession(session.localId, { type: "status", status: "processing" });
803
- sdk.startQuery(session, text, null, getLinuxUserForSession(session));
811
+ sdk.startQuery(session, text, null, ensureProjectAccessForSession(session));
804
812
  sm.broadcastSessionList();
805
813
  }, schedDelay),
806
814
  };
@@ -1134,6 +1142,7 @@ function createProjectContext(opts) {
1134
1142
  pushModule: pushModule,
1135
1143
  getSessionForWs: getSessionForWs,
1136
1144
  getLinuxUserForSession: getLinuxUserForSession,
1145
+ ensureProjectAccessForSession: ensureProjectAccessForSession,
1137
1146
  getOsUserInfoForWs: getOsUserInfoForWs,
1138
1147
  hydrateImageRefs: hydrateImageRefs,
1139
1148
  onProcessingChanged: onProcessingChanged,
@@ -1182,6 +1191,7 @@ function createProjectContext(opts) {
1182
1191
  matesModule: matesModule,
1183
1192
  getSessionForWs: getSessionForWs,
1184
1193
  getLinuxUserForSession: getLinuxUserForSession,
1194
+ ensureProjectAccessForSession: ensureProjectAccessForSession,
1185
1195
  getOsUserInfoForWs: getOsUserInfoForWs,
1186
1196
  hydrateImageRefs: hydrateImageRefs,
1187
1197
  saveImageFile: saveImageFile,
@@ -526,20 +526,6 @@
526
526
  white-space: nowrap;
527
527
  }
528
528
 
529
- .mobile-session-bookmark {
530
- display: inline-flex;
531
- align-items: center;
532
- color: var(--accent, #ff7b54);
533
- flex-shrink: 0;
534
- }
535
-
536
- .mobile-session-bookmark .lucide,
537
- .mobile-session-bookmark svg {
538
- width: 13px;
539
- height: 13px;
540
- display: block;
541
- }
542
-
543
529
  .mobile-session-processing {
544
530
  width: 7px;
545
531
  height: 7px;
@@ -309,45 +309,49 @@
309
309
 
310
310
  .light-theme .notif-banner-clear-all {
311
311
  background:
312
- linear-gradient(180deg, rgba(255,255,255,0.88), rgba(255,255,255,0.72)),
313
- rgba(255,255,255,0.62);
314
- border-color: rgba(24, 32, 56, 0.10);
312
+ linear-gradient(180deg, rgba(255,255,255,0.54), rgba(255,255,255,0.28)),
313
+ rgba(248,250,255,0.22);
314
+ backdrop-filter: blur(10px) saturate(1.08);
315
+ -webkit-backdrop-filter: blur(10px) saturate(1.08);
316
+ border-color: rgba(255,255,255,0.52);
315
317
  color: rgba(36, 45, 66, 0.72);
316
318
  box-shadow:
317
- inset 0 1px 0 rgba(255,255,255,0.85),
318
- 0 8px 22px rgba(31, 41, 55, 0.08);
319
+ inset 0 1px 0 rgba(255,255,255,0.78),
320
+ 0 8px 22px rgba(31, 41, 55, 0.07);
319
321
  }
320
322
 
321
323
  .light-theme .notif-banner-clear-all:hover {
322
324
  color: rgba(22, 29, 45, 0.92);
323
325
  background:
324
- linear-gradient(180deg, rgba(255,255,255,0.94), rgba(255,255,255,0.78)),
325
- rgba(255,255,255,0.7);
326
- border-color: rgba(24, 32, 56, 0.14);
326
+ linear-gradient(180deg, rgba(255,255,255,0.62), rgba(255,255,255,0.34)),
327
+ rgba(248,250,255,0.26);
328
+ border-color: rgba(255,255,255,0.6);
327
329
  }
328
330
 
329
331
  .light-theme .notif-banner {
330
332
  background:
331
- linear-gradient(180deg, rgba(255,255,255,0.92), rgba(255,255,255,0.74)),
332
- rgba(255,255,255,0.60);
333
- border-color: rgba(27, 35, 56, 0.08);
333
+ linear-gradient(180deg, rgba(255,255,255,0.58), rgba(255,255,255,0.22)),
334
+ rgba(248,250,255,0.2);
335
+ backdrop-filter: blur(12px) saturate(1.05);
336
+ -webkit-backdrop-filter: blur(12px) saturate(1.05);
337
+ border: 1px solid rgba(255,255,255,0.5);
334
338
  box-shadow:
335
- inset 0 1px 0 rgba(255,255,255,0.88),
336
- 0 10px 30px rgba(31, 41, 55, 0.10);
339
+ inset 0 1px 0 rgba(255,255,255,0.72),
340
+ 0 10px 30px rgba(31, 41, 55, 0.09);
337
341
  }
338
342
 
339
343
  .light-theme .notif-banner:hover {
340
- border-color: rgba(27, 35, 56, 0.12);
344
+ border-color: rgba(255,255,255,0.62);
341
345
  box-shadow:
342
- inset 0 1px 0 rgba(255,255,255,0.92),
343
- 0 12px 34px rgba(31, 41, 55, 0.12);
346
+ inset 0 1px 0 rgba(255,255,255,0.8),
347
+ 0 12px 34px rgba(31, 41, 55, 0.11);
344
348
  }
345
349
 
346
350
  .light-theme .notif-banner-icon {
347
- background: linear-gradient(180deg, rgba(255,255,255,0.92), rgba(244,247,252,0.82));
348
- border-color: rgba(27, 35, 56, 0.08);
351
+ background: linear-gradient(180deg, rgba(255,255,255,0.72), rgba(246,249,255,0.36));
352
+ border-color: rgba(255,255,255,0.52);
349
353
  color: var(--text-secondary);
350
- box-shadow: inset 0 1px 0 rgba(255,255,255,0.92);
354
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.78);
351
355
  }
352
356
 
353
357
  .light-theme .notif-banner-project {