pi-sdk-web 0.5.7 → 0.5.9

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.
@@ -879,6 +879,11 @@ class PiWebClient {
879
879
  // ------------------------------------------------------------------
880
880
 
881
881
  renderEvent(ev) {
882
+ // Capture stickiness BEFORE the handler mutates the DOM: updates that
883
+ // grow content (message_update, tool deltas) increase scrollHeight, so
884
+ // checking wasAtBottom() after the fact would miss "user was already at
885
+ // the bottom" and stop following the stream.
886
+ const wasAtBottom = this.wasAtBottom();
882
887
  switch (ev.type) {
883
888
  case 'agent_start':
884
889
  this.status.working++;
@@ -964,9 +969,9 @@ class PiWebClient {
964
969
  default:
965
970
  break;
966
971
  }
967
- // Only auto-scroll when the user is already at the bottom (reading
968
- // history must not be yanked down by incoming events).
969
- if (this.wasAtBottom()) this.scrollToBottom();
972
+ // Auto-scroll only if the user was at the bottom before the event
973
+ // (reading history must not be yanked down by incoming events).
974
+ if (wasAtBottom) this.scrollToBottom();
970
975
  }
971
976
 
972
977
  onMessageStart(message) {
@@ -196,11 +196,38 @@ export class WebUIContext {
196
196
  // evaluate with a no-op tui stub and broadcast as text lines - the
197
197
  // browser renders them (with ANSI colors) in the widgets panel.
198
198
  try {
199
- const stubTui = { requestRender: () => { }, invalidate: () => { } };
200
- const component = content(stubTui, this.webTheme);
199
+ const width = 78;
200
+ let component;
201
+ const stubTui = {
202
+ // TUI semantics: after registration, updates flow through
203
+ // tui.requestRender() -> the component's render() is re-invoked
204
+ // with CURRENT state. Without this a widget is frozen at its
205
+ // first-registration content (magic-context's todos overlay
206
+ // updates via requestRender, never via setWidget, so the browser
207
+ // kept showing the initial todo list).
208
+ requestRender: () => {
209
+ if (!component || typeof component.render !== "function")
210
+ return;
211
+ let fresh;
212
+ try {
213
+ const out = component.render(width);
214
+ if (Array.isArray(out))
215
+ fresh = out.map((l) => String(l));
216
+ }
217
+ catch {
218
+ // A throwing render must not wipe the widget: keep last lines.
219
+ return;
220
+ }
221
+ this.broadcastWidget(key, fresh, options?.placement);
222
+ },
223
+ invalidate: () => {
224
+ // TUI calls invalidate while tearing the widget down; the web
225
+ // host never tears a widget down on its own.
226
+ },
227
+ };
228
+ component = content(stubTui, this.webTheme);
201
229
  const render = component && component.render;
202
230
  if (typeof render === "function") {
203
- const width = 78;
204
231
  const out = render(width);
205
232
  if (Array.isArray(out))
206
233
  lines = out.map((l) => String(l));
@@ -210,16 +237,20 @@ export class WebUIContext {
210
237
  // fall through with no lines - widget renders empty
211
238
  }
212
239
  }
240
+ this.broadcastWidget(key, lines, options?.placement);
241
+ }
242
+ /** Broadcast a widget update and store it as the snapshot for new clients. */
243
+ broadcastWidget(key, lines, placement) {
213
244
  this.sink({
214
245
  type: "extension_ui_request",
215
246
  id: crypto.randomUUID(),
216
247
  method: "setWidget",
217
248
  widgetKey: key,
218
249
  widgetLines: lines,
219
- widgetPlacement: options?.placement,
250
+ widgetPlacement: placement,
220
251
  });
221
252
  // Store for late-connecting browsers (replayed on WS connect).
222
- this.widgetMap.set(key, { lines, placement: options?.placement });
253
+ this.widgetMap.set(key, { lines, placement });
223
254
  }
224
255
  // ------------------------------------------------------------------
225
256
  // Terminal-specific features: no-op in web mode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-sdk-web",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "Browser Web access for Pi (AI coding agent) via the Pi SDK - standalone module, zero modification to Pi itself",
5
5
  "type": "module",
6
6
  "bin": {