shadok-ai 0.16.12 → 0.16.13

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/index.html +23 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadok-ai",
3
- "version": "0.16.12",
3
+ "version": "0.16.13",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test --test-timeout=120000 test/*.ts context/*/test/*.test.mjs",
package/public/index.html CHANGED
@@ -7887,11 +7887,25 @@
7887
7887
  // reloads onto the new build quickly instead of waiting out a backoff.
7888
7888
  reloadExpectedUntil = Date.now() + 90_000;
7889
7889
  break;
7890
- case "history":
7890
+ case "history": {
7891
7891
  // Full replay from the transcript (source of truth). Clear first so a
7892
7892
  // reconnect (laptop wake / dropped link) rebuilds the transcript instead
7893
7893
  // of appending a second copy of the whole history.
7894
- t.transcriptEl.innerHTML = "";
7894
+ //
7895
+ // Hold the reader's place across the wipe+rebuild. On a RECONNECT the
7896
+ // transcript already carries the conversation, and tearing it down to
7897
+ // rebuild it snaps the view to the top UNLESS the browser's scroll
7898
+ // anchoring happens to save us — which it does not when the tab was in
7899
+ // the background while the replay ran (anchoring needs a live layout),
7900
+ // and does not in Safari. That is the reported "the chat jumps back up
7901
+ // when I come back". The replay is the same messages in the same order,
7902
+ // appended bottom-first, so we restore deterministically: pinned to the
7903
+ // bottom if they were following live, otherwise holding the same
7904
+ // distance from the bottom so what they were reading stays in view.
7905
+ const el = t.transcriptEl;
7906
+ const wasStick = el._stickBottom !== false;
7907
+ const fromBottom = Math.max(0, el.scrollHeight - el.scrollTop - el.clientHeight);
7908
+ el.innerHTML = "";
7895
7909
  t.unreadSep = null; // the separator element went with the wipe
7896
7910
  addTurn(t, "system", "", "— resumed session history —");
7897
7911
  for (const h of msg.turns) {
@@ -7923,7 +7937,14 @@
7923
7937
  if (h.afterInternal) b.parentElement.classList.add("after-gap");
7924
7938
  }
7925
7939
  }
7940
+ // Restore the reader's place deterministically — never trust the
7941
+ // browser's implicit scroll anchoring for a full teardown.
7942
+ el._stickBottom = wasStick;
7943
+ el.scrollTop = wasStick
7944
+ ? el.scrollHeight
7945
+ : Math.max(0, el.scrollHeight - el.clientHeight - fromBottom);
7926
7946
  break;
7947
+ }
7927
7948
  case "ready":
7928
7949
  // The server just named the instance it is. If it's not the one this
7929
7950
  // page was loaded from, the port was taken over — stop writing, prompt a