clay-server 2.26.0-beta.10 → 2.26.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.
@@ -157,14 +157,15 @@ function attachDebate(ctx) {
157
157
  round: d.round || 1,
158
158
  awaitingConcludeConfirm: !!d.awaitingConcludeConfirm,
159
159
  awaitingUserFloor: !!d.awaitingUserFloor,
160
+ ownerId: d.ownerId || null,
160
161
  };
161
162
  ctx.sm.saveSessionFile(session);
162
163
  }
163
164
 
164
- function restoreDebateFromState(session) {
165
+ function restoreDebateFromState(session, restoreUserId) {
165
166
  var ds = session.debateState;
166
167
  if (!ds) return null;
167
- var userId = null; // Will be set when WS connects
168
+ var userId = restoreUserId || ds.ownerId || null;
168
169
  var mateCtx = matesModule.buildMateCtx(userId);
169
170
  var debate = {
170
171
  phase: ds.phase,
@@ -188,6 +189,7 @@ function attachDebate(ctx) {
188
189
  briefPath: ds.briefPath || null,
189
190
  awaitingConcludeConfirm: !!ds.awaitingConcludeConfirm,
190
191
  awaitingUserFloor: !!ds.awaitingUserFloor,
192
+ ownerId: ds.ownerId || userId,
191
193
  };
192
194
 
193
195
  // Fallback: if awaitingConcludeConfirm was not persisted, detect from history
@@ -334,8 +336,8 @@ function attachDebate(ctx) {
334
336
  var phase = session.debateState.phase;
335
337
  if (phase !== "preparing" && phase !== "reviewing" && phase !== "live") return;
336
338
 
337
- // Restore _debate from persisted state
338
- var debate = restoreDebateFromState(session);
339
+ // Restore _debate from persisted state (pass userId for correct mateCtx)
340
+ var debate = restoreDebateFromState(session, userId);
339
341
  if (!debate) return;
340
342
 
341
343
  // Update mateCtx with the connected user's context
@@ -463,6 +465,7 @@ function attachDebate(ctx) {
463
465
  setupSessionId: null,
464
466
  debateId: debateId,
465
467
  briefPath: briefPath,
468
+ ownerId: mateCtx.userId || null,
466
469
  };
467
470
  debate.nameMap = buildDebateNameMap(debate.panelists, mateCtx);
468
471
  session._debate = debate;
@@ -550,6 +553,7 @@ function attachDebate(ctx) {
550
553
  round: 1,
551
554
  history: [],
552
555
  setupSessionId: null,
556
+ ownerId: userId,
553
557
  };
554
558
  session._debate = debate;
555
559
 
@@ -577,7 +581,8 @@ function attachDebate(ctx) {
577
581
  var debateId = debate.debateId;
578
582
 
579
583
  // Create setup session (still needed for session grouping)
580
- var setupSession = ctx.sm.createSession();
584
+ var setupOpts = debate.ownerId ? { ownerId: debate.ownerId } : null;
585
+ var setupSession = ctx.sm.createSession(setupOpts);
581
586
  setupSession.title = "Debate Setup: " + (msg.topic || "Quick").slice(0, 40);
582
587
  setupSession.debateSetupMode = true;
583
588
  setupSession.loop = { active: true, iteration: 0, role: "crafting", loopId: debateId, name: (msg.topic || "Quick").slice(0, 40), source: "debate", startedAt: Date.now() };
@@ -702,7 +707,8 @@ function attachDebate(ctx) {
702
707
  var debateId = debate.debateId;
703
708
 
704
709
  // Create a new session for the setup skill (like Ralph crafting)
705
- var setupSession = ctx.sm.createSession();
710
+ var skillSetupOpts = debate.ownerId ? { ownerId: debate.ownerId } : null;
711
+ var setupSession = ctx.sm.createSession(skillSetupOpts);
706
712
  setupSession.title = "Debate Setup: " + msg.topic.slice(0, 40);
707
713
  setupSession.debateSetupMode = true;
708
714
  setupSession.loop = { active: true, iteration: 0, role: "crafting", loopId: debateId, name: msg.topic.slice(0, 40), source: "debate", startedAt: Date.now() };
@@ -762,6 +768,13 @@ function attachDebate(ctx) {
762
768
  ctx.sdk.startQuery(setupSession, craftingPrompt, undefined, ctx.getLinuxUserForSession(setupSession));
763
769
  }
764
770
 
771
+ // --- Mate strip processing indicator ---
772
+ // Broadcast mention_processing so the correct mate's active dot lights up
773
+ // on the mate strip during debate turns (instead of always the moderator's).
774
+ function debateMateProcessing(mateId, active) {
775
+ ctx.send({ type: "mention_processing", mateId: mateId, active: active });
776
+ }
777
+
765
778
  // --- Live debate ---
766
779
 
767
780
  function startDebateLive(session) {
@@ -776,7 +789,8 @@ function attachDebate(ctx) {
776
789
  var moderatorProfile = ctx.getMateProfile(mateCtx, debate.moderatorId);
777
790
 
778
791
  // Create a dedicated debate session, grouped with the setup session
779
- var debateSession = ctx.sm.createSession();
792
+ var liveOpts = debate.ownerId ? { ownerId: debate.ownerId } : null;
793
+ var debateSession = ctx.sm.createSession(liveOpts);
780
794
  debateSession.title = debate.topic.slice(0, 50);
781
795
  debateSession.loop = { active: true, iteration: 1, role: "debate", loopId: debate.debateId, name: debate.topic.slice(0, 40), source: "debate", startedAt: debate.setupStartedAt || Date.now() };
782
796
  ctx.sm.saveSessionFile(debateSession);
@@ -810,6 +824,7 @@ function attachDebate(ctx) {
810
824
  ctx.sendToSession(debateSession.localId, debateStartEntry);
811
825
 
812
826
  // Signal moderator's first turn
827
+ debateMateProcessing(debate.moderatorId, true);
813
828
  ctx.sendToSession(debateSession.localId, {
814
829
  type: "debate_turn",
815
830
  mateId: debate.moderatorId,
@@ -864,6 +879,7 @@ function attachDebate(ctx) {
864
879
  var debate = session._debate;
865
880
  if (!debate || debate.phase === "ended") return;
866
881
 
882
+ debateMateProcessing(debate.moderatorId, false);
867
883
  debate.turnInProgress = false;
868
884
 
869
885
  // Record in debate history
@@ -935,6 +951,7 @@ function attachDebate(ctx) {
935
951
  }
936
952
  if (!panelistInfo) {
937
953
  console.error("[debate] Panelist not found:", mateId);
954
+ debateMateProcessing(mateId, false);
938
955
  debate._currentTurnMateId = null;
939
956
  // Feed error back to moderator
940
957
  feedBackToModerator(session, mateId, "[This panelist is not part of the debate panel.]");
@@ -942,6 +959,7 @@ function attachDebate(ctx) {
942
959
  }
943
960
 
944
961
  // Notify clients of new turn
962
+ debateMateProcessing(mateId, true);
945
963
  ctx.sendToSession(session.localId, {
946
964
  type: "debate_turn",
947
965
  mateId: mateId,
@@ -970,6 +988,7 @@ function attachDebate(ctx) {
970
988
  },
971
989
  onError: function (errMsg) {
972
990
  console.error("[debate] Panelist error for " + mateId + ":", errMsg);
991
+ debateMateProcessing(mateId, false);
973
992
  debate.turnInProgress = false;
974
993
  // Feed error back to moderator so the debate can continue
975
994
  feedBackToModerator(session, mateId, "[" + profile.name + " encountered an error and could not respond. Please continue with other panelists or wrap up.]");
@@ -1030,6 +1049,7 @@ function attachDebate(ctx) {
1030
1049
  }
1031
1050
  }).catch(function (err) {
1032
1051
  console.error("[debate] Failed to create panelist session for " + mateId + ":", err.message || err);
1052
+ debateMateProcessing(mateId, false);
1033
1053
  debate.turnInProgress = false;
1034
1054
  feedBackToModerator(session, mateId, "[" + profile.name + " is unavailable. Please continue with other panelists or wrap up.]");
1035
1055
  });
@@ -1040,6 +1060,7 @@ function attachDebate(ctx) {
1040
1060
  var debate = session._debate;
1041
1061
  if (!debate || debate.phase === "ended") return;
1042
1062
 
1063
+ debateMateProcessing(mateId, false);
1043
1064
  debate.turnInProgress = false;
1044
1065
  debate._currentTurnMateId = null;
1045
1066
  debate._currentTurnText = "";
@@ -1103,6 +1124,7 @@ function attachDebate(ctx) {
1103
1124
  var moderatorProfile = ctx.getMateProfile(debate.mateCtx, debate.moderatorId);
1104
1125
 
1105
1126
  // Notify clients of moderator turn
1127
+ debateMateProcessing(debate.moderatorId, true);
1106
1128
  ctx.sendToSession(session.localId, {
1107
1129
  type: "debate_turn",
1108
1130
  mateId: debate.moderatorId,
@@ -1318,6 +1340,7 @@ function attachDebate(ctx) {
1318
1340
  debate.turnInProgress = true;
1319
1341
  var moderatorProfile = ctx.getMateProfile(debate.mateCtx, debate.moderatorId);
1320
1342
 
1343
+ debateMateProcessing(debate.moderatorId, true);
1321
1344
  ctx.sendToSession(session.localId, {
1322
1345
  type: "debate_turn",
1323
1346
  mateId: debate.moderatorId,
@@ -1507,6 +1530,7 @@ function attachDebate(ctx) {
1507
1530
  ctx.sendToSession(session.localId, resumedMsg);
1508
1531
 
1509
1532
  debate.turnInProgress = true;
1533
+ debateMateProcessing(debate.moderatorId, true);
1510
1534
  ctx.sendToSession(session.localId, {
1511
1535
  type: "debate_turn",
1512
1536
  mateId: debate.moderatorId,
@@ -1580,6 +1604,12 @@ function attachDebate(ctx) {
1580
1604
  var debate = session._debate;
1581
1605
  if (!debate || debate.phase === "ended") return;
1582
1606
 
1607
+ // Clear all mate strip processing dots
1608
+ debateMateProcessing(debate.moderatorId, false);
1609
+ for (var ei = 0; ei < debate.panelists.length; ei++) {
1610
+ debateMateProcessing(debate.panelists[ei].mateId, false);
1611
+ }
1612
+
1583
1613
  debate.phase = "ended";
1584
1614
  debate.turnInProgress = false;
1585
1615
  persistDebateState(session);
@@ -437,6 +437,39 @@
437
437
  font-size: 13px;
438
438
  text-align: center;
439
439
  }
440
+ .context-picker-ext-notice {
441
+ padding: 10px 12px;
442
+ display: flex;
443
+ flex-direction: column;
444
+ gap: 8px;
445
+ }
446
+ .context-picker-ext-notice-text {
447
+ font-size: 12px;
448
+ color: var(--text-dimmer);
449
+ line-height: 1.4;
450
+ }
451
+ .context-picker-ext-btn {
452
+ display: inline-flex;
453
+ align-items: center;
454
+ gap: 5px;
455
+ padding: 5px 10px;
456
+ font-size: 12px;
457
+ font-weight: 500;
458
+ color: var(--text);
459
+ background: var(--bg-hover, rgba(255,255,255,0.06));
460
+ border: 1px solid var(--border);
461
+ border-radius: 6px;
462
+ cursor: pointer;
463
+ transition: background 0.15s;
464
+ width: fit-content;
465
+ }
466
+ .context-picker-ext-btn:hover {
467
+ background: var(--bg-active, rgba(255,255,255,0.1));
468
+ }
469
+ .context-picker-ext-btn .lucide {
470
+ width: 13px;
471
+ height: 13px;
472
+ }
440
473
 
441
474
  .context-picker-favicon {
442
475
  width: 14px;
@@ -223,12 +223,27 @@ function renderPicker() {
223
223
  var tabSection = document.getElementById("context-picker-tabs");
224
224
  tabSection.innerHTML = "";
225
225
 
226
- if (browserTabList.length > 0) {
227
- var tabLabel = document.createElement("div");
228
- tabLabel.className = "context-picker-section-label";
229
- tabLabel.textContent = "Browser Tabs";
230
- tabSection.appendChild(tabLabel);
231
-
226
+ var tabLabel = document.createElement("div");
227
+ tabLabel.className = "context-picker-section-label";
228
+ tabLabel.textContent = "Browser Tabs";
229
+ tabSection.appendChild(tabLabel);
230
+
231
+ if (browserTabList.length === 0) {
232
+ // Extension not connected: show notice with setup button
233
+ var notice = document.createElement("div");
234
+ notice.className = "context-picker-ext-notice";
235
+ notice.innerHTML =
236
+ '<span class="context-picker-ext-notice-text">Chrome extension required to access browser tabs.</span>' +
237
+ '<button class="context-picker-ext-btn" type="button"><i data-lucide="puzzle"></i> Setup Extension</button>';
238
+ var setupBtn = notice.querySelector(".context-picker-ext-btn");
239
+ setupBtn.addEventListener("click", function (e) {
240
+ e.stopPropagation();
241
+ closePicker();
242
+ var extPill = document.getElementById("ext-pill");
243
+ if (extPill) extPill.click();
244
+ });
245
+ tabSection.appendChild(notice);
246
+ } else {
232
247
  for (var j = 0; j < browserTabList.length; j++) {
233
248
  var tab = browserTabList[j];
234
249
  var tabSourceId = "tab:" + tab.id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.26.0-beta.10",
3
+ "version": "2.26.0-beta.11",
4
4
  "description": "Self-hosted Claude Code in your browser. Multi-session, multi-user, push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",