clay-server 2.27.0-beta.1 → 2.27.0-beta.11

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/daemon.js CHANGED
@@ -151,7 +151,7 @@ var relay = createServer({
151
151
  }
152
152
  var slugs = config.projects.map(function (p) { return p.slug; });
153
153
  var slug = generateSlug(absPath, slugs);
154
- relay.addProject(absPath, slug);
154
+ relay.addProject(absPath, slug, null, null, wsUser ? wsUser.id : null);
155
155
  var projectEntry = { path: absPath, slug: slug, addedAt: Date.now(), visibility: "private" };
156
156
  // The user who adds a project always becomes the owner
157
157
  if (wsUser && wsUser.id) {
@@ -233,7 +233,7 @@ var relay = createServer({
233
233
  if (wsUser && wsUser.id) {
234
234
  projectEntry.ownerId = wsUser.id;
235
235
  }
236
- relay.addProject(targetDir, slug);
236
+ relay.addProject(targetDir, slug, null, null, wsUser ? wsUser.id : null);
237
237
  config.projects.push(projectEntry);
238
238
  saveConfig(config);
239
239
  try { syncClayrc(config.projects); } catch (e) {}
@@ -299,6 +299,10 @@ function attachDebate(ctx) {
299
299
  }),
300
300
  };
301
301
  ctx.sendToSession(session.localId, briefReadyMsg);
302
+ // Also send to setup session if client switched there (quickStart flow)
303
+ if (debate.setupSessionId && debate.setupSessionId !== session.localId) {
304
+ ctx.sendToSession(debate.setupSessionId, briefReadyMsg);
305
+ }
302
306
  } else {
303
307
  console.log("[debate] Brief picked up, transitioning to live. Topic:", debate.topic);
304
308
  // Transition to live (standard flow via modal/skill)
@@ -530,6 +534,8 @@ function attachDebate(ctx) {
530
534
  ctx.sm.switchSession(setupSession.localId, null, ctx.hydrateImageRefs);
531
535
  debate.setupSessionId = setupSession.localId;
532
536
  debate.setupStartedAt = setupSession.loop.startedAt;
537
+ // Share debate state with setup session so confirm_brief works from either
538
+ setupSession._debate = debate;
533
539
 
534
540
  // Build DM conversation context for the moderator
535
541
  var dmContext = msg.dmContext || "";
@@ -715,6 +721,13 @@ function attachDebate(ctx) {
715
721
  ctx.send({ type: "mention_processing", mateId: mateId, active: active });
716
722
  }
717
723
 
724
+ // Persist a debate message to session history and send to clients
725
+ function debateSendAndRecord(session, msg) {
726
+ session.history.push(msg);
727
+ ctx.sm.appendToSessionFile(session, msg);
728
+ ctx.sendToSession(session.localId, msg);
729
+ }
730
+
718
731
  // --- Live debate ---
719
732
 
720
733
  function startDebateLive(session) {
@@ -765,7 +778,7 @@ function attachDebate(ctx) {
765
778
 
766
779
  // Signal moderator's first turn
767
780
  debateMateProcessing(debate.moderatorId, true);
768
- ctx.sendToSession(debateSession.localId, {
781
+ debateSendAndRecord(debateSession, {
769
782
  type: "debate_turn",
770
783
  mateId: debate.moderatorId,
771
784
  mateName: moderatorProfile.name,
@@ -792,7 +805,7 @@ function attachDebate(ctx) {
792
805
  },
793
806
  onDelta: function (delta) {
794
807
  if (debateSession._debate && debateSession._debate.phase !== "ended") {
795
- ctx.sendToSession(debateSession.localId, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
808
+ debateSendAndRecord(debateSession, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
796
809
  }
797
810
  },
798
811
  onDone: function (fullText) {
@@ -900,7 +913,7 @@ function attachDebate(ctx) {
900
913
 
901
914
  // Notify clients of new turn
902
915
  debateMateProcessing(mateId, true);
903
- ctx.sendToSession(session.localId, {
916
+ debateSendAndRecord(session, {
904
917
  type: "debate_turn",
905
918
  mateId: mateId,
906
919
  mateName: profile.name,
@@ -920,7 +933,7 @@ function attachDebate(ctx) {
920
933
  onDelta: function (delta) {
921
934
  if (session._debate && session._debate.phase !== "ended") {
922
935
  debate._currentTurnText += delta;
923
- ctx.sendToSession(session.localId, { type: "debate_stream", mateId: mateId, mateName: profile.name, delta: delta });
936
+ debateSendAndRecord(session, { type: "debate_stream", mateId: mateId, mateName: profile.name, delta: delta });
924
937
  }
925
938
  },
926
939
  onDone: function (fullText) {
@@ -1065,7 +1078,7 @@ function attachDebate(ctx) {
1065
1078
 
1066
1079
  // Notify clients of moderator turn
1067
1080
  debateMateProcessing(debate.moderatorId, true);
1068
- ctx.sendToSession(session.localId, {
1081
+ debateSendAndRecord(session, {
1069
1082
  type: "debate_turn",
1070
1083
  mateId: debate.moderatorId,
1071
1084
  mateName: moderatorProfile.name,
@@ -1095,7 +1108,7 @@ function attachDebate(ctx) {
1095
1108
  },
1096
1109
  onDelta: function (delta) {
1097
1110
  if (session._debate && session._debate.phase !== "ended") {
1098
- ctx.sendToSession(session.localId, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
1111
+ debateSendAndRecord(session, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
1099
1112
  }
1100
1113
  },
1101
1114
  onDone: function (fullText) {
@@ -1162,7 +1175,7 @@ function attachDebate(ctx) {
1162
1175
  debate.turnInProgress = true;
1163
1176
  var moderatorProfile = ctx.getMateProfile(debate.mateCtx, debate.moderatorId);
1164
1177
 
1165
- ctx.sendToSession(session.localId, {
1178
+ debateSendAndRecord(session, {
1166
1179
  type: "debate_turn",
1167
1180
  mateId: debate.moderatorId,
1168
1181
  mateName: moderatorProfile.name,
@@ -1201,7 +1214,7 @@ function attachDebate(ctx) {
1201
1214
  debate.turnInProgress = true;
1202
1215
  var moderatorProfile = ctx.getMateProfile(debate.mateCtx, debate.moderatorId);
1203
1216
 
1204
- ctx.sendToSession(session.localId, {
1217
+ debateSendAndRecord(session, {
1205
1218
  type: "debate_turn",
1206
1219
  mateId: debate.moderatorId,
1207
1220
  mateName: moderatorProfile.name,
@@ -1232,7 +1245,7 @@ function attachDebate(ctx) {
1232
1245
  },
1233
1246
  onDelta: function (delta) {
1234
1247
  if (session._debate && session._debate.phase !== "ended") {
1235
- ctx.sendToSession(session.localId, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
1248
+ debateSendAndRecord(session, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
1236
1249
  }
1237
1250
  },
1238
1251
  onDone: function (fullText) {
@@ -1281,7 +1294,7 @@ function attachDebate(ctx) {
1281
1294
  var moderatorProfile = ctx.getMateProfile(debate.mateCtx, debate.moderatorId);
1282
1295
 
1283
1296
  debateMateProcessing(debate.moderatorId, true);
1284
- ctx.sendToSession(session.localId, {
1297
+ debateSendAndRecord(session, {
1285
1298
  type: "debate_turn",
1286
1299
  mateId: debate.moderatorId,
1287
1300
  mateName: moderatorProfile.name,
@@ -1471,7 +1484,7 @@ function attachDebate(ctx) {
1471
1484
 
1472
1485
  debate.turnInProgress = true;
1473
1486
  debateMateProcessing(debate.moderatorId, true);
1474
- ctx.sendToSession(session.localId, {
1487
+ debateSendAndRecord(session, {
1475
1488
  type: "debate_turn",
1476
1489
  mateId: debate.moderatorId,
1477
1490
  mateName: moderatorProfile.name,
@@ -1519,7 +1532,7 @@ function attachDebate(ctx) {
1519
1532
  },
1520
1533
  onDelta: function (delta) {
1521
1534
  if (session._debate && session._debate.phase !== "ended") {
1522
- ctx.sendToSession(session.localId, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
1535
+ debateSendAndRecord(session, { type: "debate_stream", mateId: debate.moderatorId, mateName: moderatorProfile.name, delta: delta });
1523
1536
  }
1524
1537
  },
1525
1538
  onDone: function (fullText) {
package/lib/project.js CHANGED
@@ -886,6 +886,7 @@ function createProjectContext(opts) {
886
886
  matesModule: matesModule,
887
887
  getSessionForWs: getSessionForWs,
888
888
  getLinuxUserForSession: getLinuxUserForSession,
889
+ getOsUserInfoForWs: getOsUserInfoForWs,
889
890
  hydrateImageRefs: hydrateImageRefs,
890
891
  saveImageFile: saveImageFile,
891
892
  imagesDir: imagesDir,
@@ -893,6 +894,7 @@ function createProjectContext(opts) {
893
894
  _loop: _loop,
894
895
  browserState: { _browserTabList: _browserTabList, _extensionWs: _extensionWs, pendingExtensionRequests: pendingExtensionRequests },
895
896
  sendExtensionCommandAny: sendExtensionCommandAny,
897
+ requestTabContext: requestTabContext,
896
898
  scheduleMessage: scheduleMessage,
897
899
  cancelScheduledMessage: cancelScheduledMessage,
898
900
  loadContextSources: loadContextSources,
package/lib/public/app.js CHANGED
@@ -5518,11 +5518,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
5518
5518
 
5519
5519
  case "debate_turn_done":
5520
5520
  if (msg.round) updateDebateRound(msg.round);
5521
- if (replayingHistory) {
5522
- renderDebateTurnDone(msg);
5523
- } else {
5524
- handleDebateTurnDone(msg);
5525
- }
5521
+ handleDebateTurnDone(msg);
5526
5522
  break;
5527
5523
 
5528
5524
  case "debate_hand_raised":
@@ -7531,6 +7527,17 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
7531
7527
  document.getElementById("debate-bottom-stop").addEventListener("click", function () {
7532
7528
  if (ws && ws.readyState === 1) {
7533
7529
  ws.send(JSON.stringify({ type: "debate_stop" }));
7530
+ var stopBtn = document.getElementById("debate-bottom-stop");
7531
+ if (stopBtn) {
7532
+ stopBtn.disabled = true;
7533
+ stopBtn.innerHTML = iconHtml("loader") + " Stopping...";
7534
+ refreshIcons();
7535
+ }
7536
+ var waitingEl = document.getElementById("debate-bottom-waiting");
7537
+ if (waitingEl) {
7538
+ waitingEl.textContent = "Stopping after current turn...";
7539
+ waitingEl.classList.remove("hidden");
7540
+ }
7534
7541
  }
7535
7542
  });
7536
7543
  }
@@ -1225,16 +1225,33 @@ function renderDebateBriefCard(msg, resolved) {
1225
1225
  topicHtml += '<div class="debate-brief-context">' + escapeHtml(msg.context) + '</div>';
1226
1226
  }
1227
1227
 
1228
- topicHtml += '<div class="debate-brief-moderator">' +
1229
- iconHtml("mic") + ' <strong>Moderator:</strong> ' + escapeHtml(msg.moderatorName || "Unknown") +
1230
- '</div>';
1228
+ // Resolve mate avatars from matesList
1229
+ var mates = ctx.matesList ? ctx.matesList() : [];
1230
+ var mateMap = {};
1231
+ for (var mi = 0; mi < mates.length; mi++) {
1232
+ mateMap[mates[mi].id] = mates[mi];
1233
+ }
1234
+
1235
+ var modMate = msg.moderatorId ? mateMap[msg.moderatorId] : null;
1236
+ var modAvatarSrc = modMate ? mateAvatarUrl(modMate, 24) : "";
1237
+ topicHtml += '<div class="debate-brief-moderator" style="display:flex;align-items:center;gap:8px;">' +
1238
+ iconHtml("mic") + ' <strong>Moderator:</strong> ';
1239
+ if (modAvatarSrc) {
1240
+ topicHtml += '<img src="' + escapeHtml(modAvatarSrc) + '" width="24" height="24" style="border-radius:50%;flex-shrink:0;">';
1241
+ }
1242
+ topicHtml += escapeHtml(msg.moderatorName || "Unknown") + '</div>';
1231
1243
 
1232
1244
  topicHtml += '<div class="debate-brief-panelists-label">' + iconHtml("users") + ' <strong>Panelists:</strong></div>';
1233
1245
  topicHtml += '<div class="debate-brief-panelists">';
1234
1246
  if (msg.panelists) {
1235
1247
  for (var i = 0; i < msg.panelists.length; i++) {
1236
1248
  var p = msg.panelists[i];
1237
- topicHtml += '<div class="debate-brief-panelist">';
1249
+ var mate = p.mateId ? mateMap[p.mateId] : null;
1250
+ var avatarSrc = mate ? mateAvatarUrl(mate, 24) : "";
1251
+ topicHtml += '<div class="debate-brief-panelist" style="display:flex;align-items:center;gap:8px;">';
1252
+ if (avatarSrc) {
1253
+ topicHtml += '<img src="' + escapeHtml(avatarSrc) + '" width="24" height="24" style="border-radius:50%;flex-shrink:0;">';
1254
+ }
1238
1255
  topicHtml += '<span class="debate-brief-panelist-name">' + escapeHtml(p.name || "Unknown") + '</span>';
1239
1256
  if (p.role) {
1240
1257
  topicHtml += '<span class="debate-brief-panelist-role">' + escapeHtml(p.role) + '</span>';
package/lib/sdk-bridge.js CHANGED
@@ -2375,9 +2375,9 @@ function createSDKBridge(opts) {
2375
2375
  includePartialMessages: true,
2376
2376
  abortController: abortController,
2377
2377
  canUseTool: opts.canUseTool || function (toolName, input) {
2378
- var allowed = { Read: true, Glob: true, Grep: true, WebFetch: true, WebSearch: true };
2379
- if (allowed[toolName]) {
2380
- return Promise.resolve({ behavior: "allow", updatedInput: input });
2378
+ var whitelisted = checkToolWhitelist(toolName, input);
2379
+ if (whitelisted) {
2380
+ return Promise.resolve(whitelisted);
2381
2381
  }
2382
2382
  return Promise.resolve({
2383
2383
  behavior: "deny",
@@ -2386,6 +2386,7 @@ function createSDKBridge(opts) {
2386
2386
  },
2387
2387
  };
2388
2388
  if (opts.model) mentionQueryOptions.model = opts.model;
2389
+ if (opts.includeMcpServers && mcpServers) mentionQueryOptions.mcpServers = mcpServers;
2389
2390
  query = sdk.query({
2390
2391
  prompt: mq,
2391
2392
  options: mentionQueryOptions,