clay-server 2.37.0-beta.1 → 2.37.0-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.
@@ -175,14 +175,37 @@ export function addToMessages(el) {
175
175
 
176
176
  export function scrollToBottom() {
177
177
  if (prependAnchor) return;
178
- var newMsgBtn = document.getElementById("new-msg-btn");
179
- if (isUserScrolledUp) {
180
- newMsgBtn.textContent = NEW_MSG_BTN_ACTIVITY;
181
- newMsgBtn.classList.remove("hidden");
178
+ var messagesEl = getMessagesEl();
179
+ if (!messagesEl) return;
180
+ // Compute the user's current scroll position from the DOM rather than
181
+ // the cached isUserScrolledUp flag. The flag is updated by an async
182
+ // scroll-event listener; if a delta arrives between the user's wheel
183
+ // input and that listener firing, the cached flag is still false and
184
+ // we'd snap them back to the bottom against their intent. Reading
185
+ // scrollTop/scrollHeight here is synchronous and race-free.
186
+ var distFromBottom = messagesEl.scrollHeight - messagesEl.scrollTop - messagesEl.clientHeight;
187
+ if (distFromBottom > 150 || isUserScrolledUp) {
188
+ // Keep the flag and the "New activity" button in sync even when the
189
+ // scroll-listener hasn't fired yet, so other call sites observing
190
+ // isUserScrolledUp see the truth too.
191
+ if (distFromBottom > 150) isUserScrolledUp = true;
192
+ var newMsgBtn = document.getElementById("new-msg-btn");
193
+ if (newMsgBtn) {
194
+ newMsgBtn.textContent = NEW_MSG_BTN_ACTIVITY;
195
+ newMsgBtn.classList.remove("hidden");
196
+ }
182
197
  return;
183
198
  }
184
- var messagesEl = getMessagesEl();
185
199
  requestAnimationFrame(function () {
200
+ // Re-check just before the actual write — the user may have scrolled
201
+ // up during the frame between the synchronous gate above and this rAF
202
+ // firing. Without this re-check the snap-back race re-emerges at a
203
+ // single-frame granularity.
204
+ var dist = messagesEl.scrollHeight - messagesEl.scrollTop - messagesEl.clientHeight;
205
+ if (dist > 150) {
206
+ isUserScrolledUp = true;
207
+ return;
208
+ }
186
209
  messagesEl.scrollTop = messagesEl.scrollHeight;
187
210
  });
188
211
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.37.0-beta.1",
3
+ "version": "2.37.0-beta.2",
4
4
  "description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",