clay-server 2.23.0-beta.4 → 2.23.0-beta.5

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
@@ -654,9 +654,8 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
654
654
  if (isMate && targetUser.projectSlug) {
655
655
  // Mate DM: switch to mate's project (same as project switching)
656
656
  showMateSidebar(targetUser.id, targetUser);
657
- connectMateProject(targetUser.projectSlug);
658
- // Close file viewer and terminal panel, hide terminal button (not relevant for mate)
659
- closeFileViewer();
657
+ // Close file viewer and terminal panel BEFORE switching WS (needs old WS still open)
658
+ try { closeFileViewer(); } catch(e) {}
660
659
  closeTerminal();
661
660
  var termBtn = document.getElementById("terminal-toggle-btn");
662
661
  if (termBtn) termBtn.style.display = "none";
@@ -706,6 +705,10 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
706
705
  color: mateColor
707
706
  });
708
707
  }
708
+ // Switch to mate project WS LAST, after all UI setup is complete.
709
+ // Must be last because connect() changes ws to CONNECTING state,
710
+ // and earlier code (closeFileViewer etc.) needs the old WS still open.
711
+ connectMateProject(targetUser.projectSlug);
709
712
  }
710
713
 
711
714
  // Hide user-island in human DM, keep visible in Mate DM
@@ -1340,28 +1343,33 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
1340
1343
  worktreeAccessible: p.worktreeAccessible !== undefined ? p.worktreeAccessible : true,
1341
1344
  };
1342
1345
  });
1343
- renderIconStrip(iconStripProjects, currentSlug);
1346
+ // In mate DM, highlight the saved main project in the icon strip (not the mate slug)
1347
+ var iconStripActiveSlug = (mateProjectSlug && savedMainSlug) ? savedMainSlug : currentSlug;
1348
+ renderIconStrip(iconStripProjects, iconStripActiveSlug);
1344
1349
  // Update title bar project name and icon if it changed
1345
- for (var pi = 0; pi < cachedProjects.length; pi++) {
1346
- if (cachedProjects[pi].slug === currentSlug) {
1347
- var updatedName = cachedProjects[pi].title || cachedProjects[pi].project;
1348
- var tbName = document.getElementById("title-bar-project-name");
1349
- if (tbName && updatedName) tbName.textContent = updatedName;
1350
- var tbIcon = document.getElementById("title-bar-project-icon");
1351
- if (tbIcon) {
1352
- var pIcon = cachedProjects[pi].icon || null;
1353
- if (pIcon) {
1354
- tbIcon.textContent = pIcon;
1355
- parseEmojis(tbIcon);
1356
- tbIcon.classList.add("has-icon");
1357
- try { localStorage.setItem("clay-project-icon-" + (currentSlug || "default"), pIcon); } catch (e) {}
1358
- } else {
1359
- tbIcon.textContent = "";
1360
- tbIcon.classList.remove("has-icon");
1361
- try { localStorage.removeItem("clay-project-icon-" + (currentSlug || "default")); } catch (e) {}
1350
+ // Skip when in mate DM mode (mate name/color is managed by enterDmMode)
1351
+ if (!mateProjectSlug) {
1352
+ for (var pi = 0; pi < cachedProjects.length; pi++) {
1353
+ if (cachedProjects[pi].slug === currentSlug) {
1354
+ var updatedName = cachedProjects[pi].title || cachedProjects[pi].project;
1355
+ var tbName = document.getElementById("title-bar-project-name");
1356
+ if (tbName && updatedName) tbName.textContent = updatedName;
1357
+ var tbIcon = document.getElementById("title-bar-project-icon");
1358
+ if (tbIcon) {
1359
+ var pIcon = cachedProjects[pi].icon || null;
1360
+ if (pIcon) {
1361
+ tbIcon.textContent = pIcon;
1362
+ parseEmojis(tbIcon);
1363
+ tbIcon.classList.add("has-icon");
1364
+ try { localStorage.setItem("clay-project-icon-" + (currentSlug || "default"), pIcon); } catch (e) {}
1365
+ } else {
1366
+ tbIcon.textContent = "";
1367
+ tbIcon.classList.remove("has-icon");
1368
+ try { localStorage.removeItem("clay-project-icon-" + (currentSlug || "default")); } catch (e) {}
1369
+ }
1362
1370
  }
1371
+ break;
1363
1372
  }
1364
- break;
1365
1373
  }
1366
1374
  }
1367
1375
  // Re-apply current socket status to the active icon's dot
@@ -3811,7 +3819,23 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3811
3819
 
3812
3820
  ws.onerror = function () {};
3813
3821
 
3814
- function showUpdateAvailable(msg) {
3822
+ ws.onmessage = function (event) {
3823
+ // If this WS is stashed while in mate DM, only allow skill_installed through
3824
+ // Backup: if we're receiving messages, we're connected
3825
+ if (!connected) {
3826
+ setStatus("connected");
3827
+ reconnectDelay = 1000;
3828
+ if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
3829
+ }
3830
+
3831
+ blinkIO();
3832
+ var msg;
3833
+ try { msg = JSON.parse(event.data); } catch (e) { return; }
3834
+ processMessage(msg);
3835
+ };
3836
+ }
3837
+
3838
+ function showUpdateAvailable(msg) {
3815
3839
  var updatePillWrap = $("update-pill-wrap");
3816
3840
  var updateVersion = $("update-version");
3817
3841
  if (updatePillWrap && updateVersion && msg.version) {
@@ -3853,22 +3877,6 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3853
3877
  }
3854
3878
  }
3855
3879
 
3856
- ws.onmessage = function (event) {
3857
- // If this WS is stashed while in mate DM, only allow skill_installed through
3858
- // Backup: if we're receiving messages, we're connected
3859
- if (!connected) {
3860
- setStatus("connected");
3861
- reconnectDelay = 1000;
3862
- if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
3863
- }
3864
-
3865
- blinkIO();
3866
- var msg;
3867
- try { msg = JSON.parse(event.data); } catch (e) { return; }
3868
- processMessage(msg);
3869
- };
3870
- }
3871
-
3872
3880
  function processMessage(msg) {
3873
3881
  var isMateDm = dmMode && dmTargetUser && dmTargetUser.isMate;
3874
3882
 
@@ -3884,12 +3892,15 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3884
3892
  if (isMateDm) {
3885
3893
  if (msg.type === "session_list") {
3886
3894
  renderMateSessionList(msg.sessions || []);
3887
- // Also override title bar with mate name
3895
+ // Override title bar with mate name and re-apply color
3888
3896
  var _mdn = (dmTargetUser.displayName || "New Mate");
3889
3897
  if (headerTitleEl) headerTitleEl.textContent = _mdn;
3890
3898
  var _tbpn = document.getElementById("title-bar-project-name");
3891
3899
  if (_tbpn) _tbpn.textContent = _mdn;
3892
- updatePageTitle();
3900
+ var _mc2 = (dmTargetUser.profile && dmTargetUser.profile.avatarColor) || dmTargetUser.avatarColor || "#7c3aed";
3901
+ var _tbc2 = document.querySelector(".title-bar-content");
3902
+ if (_tbc2) { _tbc2.style.background = _mc2; _tbc2.classList.add("mate-dm-active"); }
3903
+ document.body.classList.add("mate-dm-active");
3893
3904
  // Still let normal session_list handler run below
3894
3905
  }
3895
3906
  if (msg.type === "search_results") {
@@ -3999,9 +4010,11 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3999
4010
  case "restore_mate_dm":
4000
4011
  if (msg.mateId && !returningFromMateDm) {
4001
4012
  // Server-driven mate DM restore on reconnect
4013
+ // Note: do NOT remove mate-dm-active here; openDm is async (skill check)
4014
+ // and removing the class causes a flash where mate UI is lost.
4015
+ // enterDmMode will properly set/reset the class when DM is entered.
4002
4016
  if (dmMode) {
4003
4017
  dmMode = false;
4004
- document.body.classList.remove("mate-dm-active");
4005
4018
  }
4006
4019
  messagesEl.innerHTML = "";
4007
4020
  openDm(msg.mateId);
@@ -4023,12 +4036,17 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
4023
4036
  projectName = msg.project || msg.cwd;
4024
4037
  if (msg.slug) currentSlug = msg.slug;
4025
4038
  try { localStorage.setItem("clay-project-name-" + (currentSlug || "default"), projectName); } catch (e) {}
4026
- // In mate DM, keep title as mate name (not project/session title)
4039
+ // In mate DM, keep title as mate name and re-apply mate color
4027
4040
  if (dmMode && dmTargetUser && dmTargetUser.isMate) {
4028
4041
  var _mateDN = dmTargetUser.displayName || "New Mate";
4029
4042
  headerTitleEl.textContent = _mateDN;
4030
4043
  var tbProjectName = $("title-bar-project-name");
4031
4044
  if (tbProjectName) tbProjectName.textContent = _mateDN;
4045
+ // Re-apply mate title bar styling (may be lost during project switch)
4046
+ var _mc = (dmTargetUser.profile && dmTargetUser.profile.avatarColor) || dmTargetUser.avatarColor || "#7c3aed";
4047
+ var _tbc = document.querySelector(".title-bar-content");
4048
+ if (_tbc) { _tbc.style.background = _mc; _tbc.classList.add("mate-dm-active"); }
4049
+ document.body.classList.add("mate-dm-active");
4032
4050
  } else {
4033
4051
  headerTitleEl.textContent = projectName;
4034
4052
  var tbProjectName = $("title-bar-project-name");
@@ -14,6 +14,7 @@
14
14
 
15
15
  .title-bar-content.mate-dm-active {
16
16
  border-bottom: none;
17
+ background: var(--mate-color);
17
18
  }
18
19
 
19
20
  .title-bar-content.mate-dm-active #header-left,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.23.0-beta.4",
3
+ "version": "2.23.0-beta.5",
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",