clay-server 2.29.3 → 2.29.4-beta.2

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.
@@ -311,7 +311,11 @@ export function renderProjectList() {
311
311
  }
312
312
  }
313
313
  }
314
- // Re-apply current socket status to the active icon's dot
314
+ // Clear stale socket status from all project dots, then re-apply to active
315
+ var allDots = document.querySelectorAll("#icon-strip-projects .icon-strip-status");
316
+ for (var di = 0; di < allDots.length; di++) {
317
+ allDots[di].classList.remove("connected", "processing");
318
+ }
315
319
  var dot = _ctx.getStatusDot();
316
320
  if (dot) {
317
321
  if (_ctx.connected && _ctx.processing) { dot.classList.add("connected"); dot.classList.add("processing"); }
@@ -1198,6 +1198,11 @@ export function renderIconStrip(projects, currentSlug) {
1198
1198
  for (var fi = 0; fi < items.length; fi++) {
1199
1199
  var isNowActive = items[fi].dataset.slug === currentSlug && !currentDmUserId2;
1200
1200
  items[fi].classList.toggle("active", isNowActive);
1201
+ // Clear stale socket status dot from inactive items
1202
+ if (!isNowActive) {
1203
+ var statusDot = items[fi].querySelector(".icon-strip-status");
1204
+ if (statusDot) statusDot.classList.remove("connected", "processing");
1205
+ }
1201
1206
  // Update unread badge visibility (active items hide their badge)
1202
1207
  var badge = items[fi].querySelector(".icon-strip-project-badge");
1203
1208
  if (badge && badge.classList.contains("has-unread") && isNowActive) {
@@ -13,6 +13,22 @@ var altActive = false;
13
13
  var isTouchDevice = "ontouchstart" in window;
14
14
  var viewportHandler = null;
15
15
  var resizeObserver = null;
16
+
17
+ function disposeTab(tab) {
18
+ if (tab._webglAddon) {
19
+ try { tab._webglAddon.dispose(); } catch (e) {}
20
+ tab._webglAddon = null;
21
+ }
22
+ if (tab.xterm) {
23
+ tab.xterm.dispose();
24
+ tab.xterm = null;
25
+ }
26
+ tab.fitAddon = null;
27
+ if (tab.bodyEl && tab.bodyEl.parentNode) {
28
+ tab.bodyEl.parentNode.removeChild(tab.bodyEl);
29
+ tab.bodyEl = null;
30
+ }
31
+ }
16
32
  var toolbarBound = false;
17
33
  var termCtxMenu = null;
18
34
 
@@ -356,7 +372,13 @@ function createXtermForTab(tab) {
356
372
  // Must be loaded after xterm.open() so the rendering context is available.
357
373
  if (typeof WebglAddon !== "undefined") {
358
374
  try {
359
- xterm.loadAddon(new WebglAddon.WebglAddon());
375
+ var webgl = new WebglAddon.WebglAddon();
376
+ webgl.onContextLoss(function () {
377
+ webgl.dispose();
378
+ tab._webglAddon = null;
379
+ });
380
+ xterm.loadAddon(webgl);
381
+ tab._webglAddon = webgl;
360
382
  } catch (e) {
361
383
  // WebGL not available, fall back to DOM renderer
362
384
  }
@@ -663,12 +685,7 @@ export function handleTermList(msg) {
663
685
  for (var id of tabs.keys()) {
664
686
  if (!serverIds.has(id)) {
665
687
  var removed = tabs.get(id);
666
- if (removed.xterm) {
667
- removed.xterm.dispose();
668
- }
669
- if (removed.bodyEl && removed.bodyEl.parentNode) {
670
- removed.bodyEl.parentNode.removeChild(removed.bodyEl);
671
- }
688
+ disposeTab(removed);
672
689
  tabs.delete(id);
673
690
  }
674
691
  }
@@ -733,10 +750,7 @@ export function handleTermClosed(msg) {
733
750
  if (!msg.id) return;
734
751
  var tab = tabs.get(msg.id);
735
752
  if (tab) {
736
- if (tab.xterm) tab.xterm.dispose();
737
- if (tab.bodyEl && tab.bodyEl.parentNode) {
738
- tab.bodyEl.parentNode.removeChild(tab.bodyEl);
739
- }
753
+ disposeTab(tab);
740
754
  tabs.delete(msg.id);
741
755
 
742
756
  if (activeTabId === msg.id) {
@@ -760,15 +774,7 @@ export function handleTermClosed(msg) {
760
774
  export function resetTerminals() {
761
775
  // Dispose all xterm instances (server state survives, client re-syncs via term_list)
762
776
  for (var tab of tabs.values()) {
763
- if (tab.xterm) {
764
- tab.xterm.dispose();
765
- tab.xterm = null;
766
- tab.fitAddon = null;
767
- }
768
- if (tab.bodyEl && tab.bodyEl.parentNode) {
769
- tab.bodyEl.parentNode.removeChild(tab.bodyEl);
770
- tab.bodyEl = null;
771
- }
777
+ disposeTab(tab);
772
778
  }
773
779
  tabs.clear();
774
780
  activeTabId = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.29.3",
3
+ "version": "2.29.4-beta.2",
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",