clay-server 2.18.0-beta.6 → 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_-]+)/);
@@ -62,6 +63,7 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
62
63
 
63
64
  // --- DM Mode ---
64
65
  var dmMode = false;
66
+ var pendingMateDmRestore = false; // suppress regular history while restoring mate DM
65
67
  var dmKey = null;
66
68
  var dmTargetUser = null;
67
69
  var dmUnread = {}; // { otherUserId: count }
@@ -741,6 +743,7 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
741
743
  function exitDmMode() {
742
744
  if (!dmMode) return;
743
745
  dmMode = false;
746
+ pendingMateDmRestore = false;
744
747
  dmKey = null;
745
748
  dmTargetUser = null;
746
749
  setCurrentDmUser(null);
@@ -3682,10 +3685,19 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
3682
3685
  ws.send(JSON.stringify({ type: "mate_list" }));
3683
3686
  } catch(e) {}
3684
3687
 
3685
- // Restore mate DM after hard refresh
3688
+ // Restore mate DM after hard refresh or server restart
3686
3689
  try {
3687
3690
  var savedMateDm = localStorage.getItem("clay_active_mate_dm");
3688
- 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
+ }
3699
+ pendingMateDmRestore = true;
3700
+ messagesEl.innerHTML = ""; // prevent regular history flash
3689
3701
  openDm(savedMateDm);
3690
3702
  }
3691
3703
  } catch(e) {}
@@ -3743,6 +3755,15 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
3743
3755
  }
3744
3756
 
3745
3757
  function processMessage(msg) {
3758
+ // Suppress regular project messages while restoring mate DM
3759
+ if (pendingMateDmRestore) {
3760
+ if (msg.type === "dm_history" || msg.type === "dm_list" || msg.type === "mate_list" || msg.type === "mate_created" || msg.type === "info") {
3761
+ // Let these through
3762
+ } else {
3763
+ return; // skip regular session messages
3764
+ }
3765
+ }
3766
+
3746
3767
  switch (msg.type) {
3747
3768
  case "history_meta":
3748
3769
  historyFrom = msg.from;
@@ -4507,6 +4528,7 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
4507
4528
 
4508
4529
  // --- DM ---
4509
4530
  case "dm_history":
4531
+ pendingMateDmRestore = false; // DM data arrived, resume normal processing
4510
4532
  // Attach projectSlug to targetUser for mate DMs
4511
4533
  if (msg.projectSlug && msg.targetUser) {
4512
4534
  msg.targetUser.projectSlug = msg.projectSlug;
@@ -4662,6 +4684,51 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
4662
4684
  renderMentionResponse(msg);
4663
4685
  break;
4664
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
+
4665
4732
  case "daemon_config":
4666
4733
  updateDaemonConfig(msg.config);
4667
4734
  break;
@@ -4994,6 +5061,16 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
4994
5061
  addCopyHandler: addCopyHandler,
4995
5062
  });
4996
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
+
4997
5074
  // --- STT module (voice input via Web Speech API) ---
4998
5075
  initSTT({
4999
5076
  inputEl: inputEl,
@@ -5485,6 +5562,13 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
5485
5562
  updateLoopBanner(loopIteration, loopMaxIterations, "running");
5486
5563
  }
5487
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
+ }
5488
5572
  }
5489
5573
 
5490
5574
  // --- Skill install dialog (generic) ---
@@ -5713,6 +5797,24 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
5713
5797
  }, cb);
5714
5798
  }
5715
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
+
5716
5818
  // --- Ralph Wizard ---
5717
5819
 
5718
5820
  var wizardMode = "draft"; // "draft" or "own"
@@ -6160,6 +6262,130 @@ import { initMention, handleMentionStart, handleMentionStream, handleMentionDone
6160
6262
  }
6161
6263
  }
6162
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
+
6163
6389
  // --- Ralph Preview Modal ---
6164
6390
  function openRalphPreviewModal() {
6165
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.6",
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",