clay-server 2.18.0-beta.7 → 2.18.0-beta.8

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/public/app.js CHANGED
@@ -29,6 +29,7 @@ import { initMateWizard, openMateWizard, closeMateWizard, handleMateCreated } fr
29
29
  import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } from './modules/command-palette.js';
30
30
  import { initLongPress } from './modules/longpress.js';
31
31
  import { initMention, handleMentionStart, handleMentionStream, handleMentionDone, handleMentionError, handleMentionActivity, renderMentionUser, renderMentionResponse } from './modules/mention.js';
32
+ import { initDebate, handleDebateStarted, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, handleDebateEnded, handleDebateError, renderDebateStarted, renderDebateTurnDone, renderDebateEnded, renderDebateCommentInjected, openDebateModal, closeDebateModal } from './modules/debate.js';
32
33
 
33
34
  // --- Base path for multi-project routing ---
34
35
  var slugMatch = location.pathname.match(/^\/p\/([a-z0-9_-]+)/);
@@ -3684,10 +3685,17 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
3684
3685
  ws.send(JSON.stringify({ type: "mate_list" }));
3685
3686
  } catch(e) {}
3686
3687
 
3687
- // Restore mate DM after hard refresh
3688
+ // Restore mate DM after hard refresh or server restart
3688
3689
  try {
3689
3690
  var savedMateDm = localStorage.getItem("clay_active_mate_dm");
3690
- if (savedMateDm && !dmMode) {
3691
+ if (savedMateDm) {
3692
+ // If dmMode is stale (server restarted while in mate DM), clean up first
3693
+ if (dmMode) {
3694
+ dmMode = false;
3695
+ savedMainWs = null;
3696
+ mateWs = null;
3697
+ document.body.classList.remove("mate-dm-active");
3698
+ }
3691
3699
  pendingMateDmRestore = true;
3692
3700
  messagesEl.innerHTML = ""; // prevent regular history flash
3693
3701
  openDm(savedMateDm);
@@ -4676,6 +4684,51 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
4676
4684
  renderMentionResponse(msg);
4677
4685
  break;
4678
4686
 
4687
+ // --- Debate ---
4688
+ case "debate_preparing":
4689
+ showDebateSticky("preparing", msg);
4690
+ break;
4691
+
4692
+ case "debate_started":
4693
+ showDebateSticky("live", msg);
4694
+ handleDebateStarted(msg);
4695
+ break;
4696
+
4697
+ case "debate_turn":
4698
+ handleDebateTurn(msg);
4699
+ if (msg.round) updateDebateRound(msg.round);
4700
+ break;
4701
+
4702
+ case "debate_activity":
4703
+ handleDebateActivity(msg);
4704
+ break;
4705
+
4706
+ case "debate_stream":
4707
+ handleDebateStream(msg);
4708
+ break;
4709
+
4710
+ case "debate_turn_done":
4711
+ handleDebateTurnDone(msg);
4712
+ break;
4713
+
4714
+ case "debate_comment_queued":
4715
+ handleDebateCommentQueued(msg);
4716
+ break;
4717
+
4718
+ case "debate_comment_injected":
4719
+ handleDebateCommentInjected(msg);
4720
+ break;
4721
+
4722
+ case "debate_ended":
4723
+ showDebateSticky("ended", msg);
4724
+ handleDebateEnded(msg);
4725
+ break;
4726
+
4727
+ case "debate_error":
4728
+ handleDebateError(msg);
4729
+ if (msg.error) showToast("Debate: " + msg.error, "error");
4730
+ break;
4731
+
4679
4732
  case "daemon_config":
4680
4733
  updateDaemonConfig(msg.config);
4681
4734
  break;
@@ -5008,6 +5061,16 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
5008
5061
  addCopyHandler: addCopyHandler,
5009
5062
  });
5010
5063
 
5064
+ // --- Debate module ---
5065
+ initDebate({
5066
+ get ws() { return ws; },
5067
+ messagesEl: messagesEl,
5068
+ scrollToBottom: scrollToBottom,
5069
+ addCopyHandler: addCopyHandler,
5070
+ matesList: function () { return cachedMatesList || []; },
5071
+ currentMateId: function () { return (dmTargetUser && dmTargetUser.isMate) ? dmTargetUser.id : null; },
5072
+ });
5073
+
5011
5074
  // --- STT module (voice input via Web Speech API) ---
5012
5075
  initSTT({
5013
5076
  inputEl: inputEl,
@@ -5499,6 +5562,13 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
5499
5562
  updateLoopBanner(loopIteration, loopMaxIterations, "running");
5500
5563
  }
5501
5564
  }
5565
+
5566
+ // Restore debate sticky on session switch
5567
+ if (debateStickyState && debateStickyState.phase) {
5568
+ showDebateSticky(debateStickyState.phase, debateStickyState.msg);
5569
+ } else {
5570
+ showDebateSticky("hide", null);
5571
+ }
5502
5572
  }
5503
5573
 
5504
5574
  // --- Skill install dialog (generic) ---
@@ -5727,6 +5797,24 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
5727
5797
  }, cb);
5728
5798
  }
5729
5799
 
5800
+ function requireClayDebateSetup(cb) {
5801
+ requireSkills({
5802
+ title: "Skill Installation Required",
5803
+ reason: "The Debate Setup skill is required to start a debate.",
5804
+ skills: [{ name: "clay-debate-setup", url: "https://github.com/chadbyte/clay-debate-setup", scope: "global" }]
5805
+ }, cb);
5806
+ }
5807
+
5808
+ // Debate button in mate sidebar
5809
+ var debateBtn = document.getElementById("mate-debate-btn");
5810
+ if (debateBtn) {
5811
+ debateBtn.addEventListener("click", function () {
5812
+ requireClayDebateSetup(function () {
5813
+ openDebateModal();
5814
+ });
5815
+ });
5816
+ }
5817
+
5730
5818
  // --- Ralph Wizard ---
5731
5819
 
5732
5820
  var wizardMode = "draft"; // "draft" or "own"
@@ -6174,6 +6262,130 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
6174
6262
  }
6175
6263
  }
6176
6264
 
6265
+ // --- Debate Sticky Banner ---
6266
+ var debateStickyState = null;
6267
+ var debateHandRaiseOpen = false;
6268
+
6269
+ function showDebateSticky(phase, msg) {
6270
+ if (phase === "ended" || phase === "hide") {
6271
+ debateStickyState = null;
6272
+ } else {
6273
+ debateStickyState = { phase: phase, msg: msg };
6274
+ }
6275
+ var stickyEl = document.getElementById("debate-sticky");
6276
+ if (!stickyEl) return;
6277
+
6278
+ if (phase === "ended" || phase === "hide") {
6279
+ stickyEl.classList.add("hidden");
6280
+ stickyEl.innerHTML = "";
6281
+ debateHandRaiseOpen = false;
6282
+ return;
6283
+ }
6284
+
6285
+ var topic = (msg && msg.topic) || "Debate";
6286
+ var truncTopic = topic.length > 30 ? topic.slice(0, 30) + "\u2026" : topic;
6287
+
6288
+ if (phase === "preparing") {
6289
+ stickyEl.innerHTML =
6290
+ '<div class="debate-sticky-inner">' +
6291
+ '<div class="debate-sticky-header">' +
6292
+ '<span class="debate-sticky-icon">' + iconHtml("mic") + '</span>' +
6293
+ '<span class="debate-sticky-label">' + escapeHtml(truncTopic) + '</span>' +
6294
+ '<span class="debate-sticky-status" id="debate-sticky-status">Setting up\u2026</span>' +
6295
+ '<button class="debate-sticky-action debate-sticky-cancel" title="Cancel debate">' + iconHtml("x") + '</button>' +
6296
+ '</div>' +
6297
+ '</div>';
6298
+ stickyEl.classList.remove("hidden");
6299
+ stickyEl.className = "debate-sticky preparing";
6300
+ refreshIcons();
6301
+
6302
+ stickyEl.querySelector(".debate-sticky-cancel").addEventListener("click", function (e) {
6303
+ e.stopPropagation();
6304
+ if (ws && ws.readyState === 1) {
6305
+ ws.send(JSON.stringify({ type: "debate_stop" }));
6306
+ }
6307
+ stickyEl.classList.add("hidden");
6308
+ stickyEl.innerHTML = "";
6309
+ });
6310
+ } else if (phase === "live") {
6311
+ stickyEl.innerHTML =
6312
+ '<div class="debate-sticky-inner">' +
6313
+ '<div class="debate-sticky-header">' +
6314
+ '<span class="debate-sticky-icon">' + iconHtml("mic") + '</span>' +
6315
+ '<span class="debate-sticky-label">' + escapeHtml(truncTopic) + '</span>' +
6316
+ '<span class="debate-sticky-status" id="debate-sticky-status">Live</span>' +
6317
+ '<span class="debate-sticky-round" id="debate-sticky-round">R1</span>' +
6318
+ '<button class="debate-sticky-action debate-sticky-hand" title="Raise hand">' + iconHtml("hand") + '</button>' +
6319
+ '<button class="debate-sticky-action debate-sticky-stop" title="Stop debate">' + iconHtml("square") + '</button>' +
6320
+ '</div>' +
6321
+ '<div class="debate-sticky-hand-input hidden" id="debate-sticky-hand-input">' +
6322
+ '<textarea id="debate-sticky-comment" rows="1" placeholder="Your comment\u2026"></textarea>' +
6323
+ '<button class="debate-sticky-send" id="debate-sticky-send">Send</button>' +
6324
+ '<button class="debate-sticky-send-cancel" id="debate-sticky-send-cancel">Cancel</button>' +
6325
+ '</div>' +
6326
+ '</div>';
6327
+ stickyEl.classList.remove("hidden");
6328
+ stickyEl.className = "debate-sticky live";
6329
+ refreshIcons();
6330
+ debateHandRaiseOpen = false;
6331
+
6332
+ stickyEl.querySelector(".debate-sticky-hand").addEventListener("click", function (e) {
6333
+ e.stopPropagation();
6334
+ toggleDebateHandRaise();
6335
+ });
6336
+
6337
+ stickyEl.querySelector(".debate-sticky-stop").addEventListener("click", function (e) {
6338
+ e.stopPropagation();
6339
+ if (ws && ws.readyState === 1) {
6340
+ ws.send(JSON.stringify({ type: "debate_stop" }));
6341
+ }
6342
+ });
6343
+
6344
+ var sendBtn = document.getElementById("debate-sticky-send");
6345
+ var cancelBtn = document.getElementById("debate-sticky-send-cancel");
6346
+ var commentInput = document.getElementById("debate-sticky-comment");
6347
+
6348
+ if (sendBtn) sendBtn.addEventListener("click", function () { sendDebateStickyComment(); });
6349
+ if (cancelBtn) cancelBtn.addEventListener("click", function () { toggleDebateHandRaise(false); });
6350
+ if (commentInput) {
6351
+ commentInput.addEventListener("keydown", function (e) {
6352
+ if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendDebateStickyComment(); }
6353
+ if (e.key === "Escape") { toggleDebateHandRaise(false); }
6354
+ });
6355
+ }
6356
+ }
6357
+ }
6358
+
6359
+ function toggleDebateHandRaise(forceState) {
6360
+ var inputWrap = document.getElementById("debate-sticky-hand-input");
6361
+ var commentInput = document.getElementById("debate-sticky-comment");
6362
+ if (!inputWrap) return;
6363
+ var show = typeof forceState === "boolean" ? forceState : !debateHandRaiseOpen;
6364
+ debateHandRaiseOpen = show;
6365
+ if (show) {
6366
+ inputWrap.classList.remove("hidden");
6367
+ if (commentInput) { commentInput.value = ""; commentInput.focus(); }
6368
+ } else {
6369
+ inputWrap.classList.add("hidden");
6370
+ }
6371
+ }
6372
+
6373
+ function sendDebateStickyComment() {
6374
+ var commentInput = document.getElementById("debate-sticky-comment");
6375
+ if (!commentInput) return;
6376
+ var text = commentInput.value.trim();
6377
+ if (!text) return;
6378
+ if (ws && ws.readyState === 1) {
6379
+ ws.send(JSON.stringify({ type: "debate_comment", text: text }));
6380
+ }
6381
+ toggleDebateHandRaise(false);
6382
+ }
6383
+
6384
+ function updateDebateRound(round) {
6385
+ var roundEl = document.getElementById("debate-sticky-round");
6386
+ if (roundEl) roundEl.textContent = "R" + round;
6387
+ }
6388
+
6177
6389
  // --- Ralph Preview Modal ---
6178
6390
  function openRalphPreviewModal() {
6179
6391
  var modal = document.getElementById("ralph-preview-modal");
package/lib/sdk-bridge.js CHANGED
@@ -1118,7 +1118,7 @@ function createSDKBridge(opts) {
1118
1118
 
1119
1119
  // Mate sessions (DM): auto-approve read-only tools
1120
1120
  if (isMate || mateDisplayName) {
1121
- var mateReadTools = { Read: true, Glob: true, Grep: true };
1121
+ var mateReadTools = { Read: true, Glob: true, Grep: true, WebFetch: true, WebSearch: true };
1122
1122
  if (mateReadTools[toolName]) {
1123
1123
  return Promise.resolve({ behavior: "allow", updatedInput: input });
1124
1124
  }
@@ -1775,7 +1775,7 @@ function createSDKBridge(opts) {
1775
1775
  includePartialMessages: true,
1776
1776
  abortController: abortController,
1777
1777
  canUseTool: opts.canUseTool || function (toolName, input) {
1778
- var allowed = { Read: true, Glob: true, Grep: true };
1778
+ var allowed = { Read: true, Glob: true, Grep: true, WebFetch: true };
1779
1779
  if (allowed[toolName]) {
1780
1780
  return Promise.resolve({ behavior: "allow", updatedInput: input });
1781
1781
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.18.0-beta.7",
3
+ "version": "2.18.0-beta.8",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",