@agfpd/iapeer 0.2.83 → 0.2.84
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/package.json +1 -1
- package/src/supervisor/daemon.ts +27 -2
package/package.json
CHANGED
package/src/supervisor/daemon.ts
CHANGED
|
@@ -163,6 +163,12 @@ export function runSupervisorDaemon(opts: SupervisorDaemonOptions): void {
|
|
|
163
163
|
const clients = new Set<unknown>()
|
|
164
164
|
const writers = new WeakMap<object, BackpressureWriter>()
|
|
165
165
|
const framers = new WeakMap<object, (chunk: Uint8Array) => void>()
|
|
166
|
+
// FIRST-PAINT TRACKING (Bug B fix): a client gets the full scrollback dump EXACTLY ONCE — on its first
|
|
167
|
+
// FRAME_RESIZE (which runClient always sends on connect, at the real terminal size). Re-dumping
|
|
168
|
+
// scrollback on every attach/resize STACKS duplicate histories in a terminal that ignores \x1b[3J
|
|
169
|
+
// (Apple Terminal has NO E3 capability) → smeared/overlapping scroll-up history. Subsequent resizes
|
|
170
|
+
// refresh the VIEWPORT only (repaintViewport), never the scrollback.
|
|
171
|
+
const painted = new WeakSet<object>()
|
|
166
172
|
// ATTACHED-CLIENT MARKER (spawn-flip Ф0b-3 slice 3c): keep `<runDir>/<session>.attached` in sync with
|
|
167
173
|
// clients.size — present iff ≥1 operator is attached. The warm-deliver path (a DIFFERENT process)
|
|
168
174
|
// reads it to gate the hosted busy-composer hold: hold ONLY when a human is attached (their unfinished
|
|
@@ -253,6 +259,16 @@ export function runSupervisorDaemon(opts: SupervisorDaemonOptions): void {
|
|
|
253
259
|
const snap = '\x1b[2J\x1b[3J\x1b[H' + stripSpinnerScrollback(ser.serialize(), xterm.rows)
|
|
254
260
|
sendClient(s, frame(FRAME_DATA, Buffer.from(snap, 'utf8')))
|
|
255
261
|
}
|
|
262
|
+
/** Refresh ONLY the visible viewport (current screen), never the scrollback — for a resize AFTER the
|
|
263
|
+
* first full paint. `\x1b[2J\x1b[H` clears the screen and homes WITHOUT touching scrollback (no
|
|
264
|
+
* \x1b[3J), then we write exactly the viewport rows (no scrollback segments), so nothing scrolls into
|
|
265
|
+
* the client's native scrollback. This is what keeps a mid-session resize from stacking another
|
|
266
|
+
* history copy in a terminal that ignores \x1b[3J (Bug B). */
|
|
267
|
+
const repaintViewport = (s: { write(b: Buffer): number }): void => {
|
|
268
|
+
const lines = ser.serialize().split('\r\n')
|
|
269
|
+
const viewport = lines.slice(Math.max(0, lines.length - xterm.rows)).join('\r\n')
|
|
270
|
+
sendClient(s, frame(FRAME_DATA, Buffer.from('\x1b[2J\x1b[H' + viewport, 'utf8')))
|
|
271
|
+
}
|
|
256
272
|
|
|
257
273
|
// Resize the model + child pty to (c, r). Shared by client FRAME_RESIZE and the last-detach restore.
|
|
258
274
|
const applyGeometry = (c: number, r: number): void => {
|
|
@@ -287,7 +303,12 @@ export function runSupervisorDaemon(opts: SupervisorDaemonOptions): void {
|
|
|
287
303
|
} else if (type === FRAME_RESIZE) {
|
|
288
304
|
const sz = parseSize(payload)
|
|
289
305
|
applyGeometry(sz.cols, sz.rows)
|
|
290
|
-
|
|
306
|
+
if (!painted.has(s as object)) {
|
|
307
|
+
painted.add(s as object)
|
|
308
|
+
repaint(s) // FIRST paint for this client: full snapshot (scrollback + viewport) at its real size
|
|
309
|
+
} else {
|
|
310
|
+
repaintViewport(s) // later resize: refresh the screen only — never re-dump scrollback (anti-stack)
|
|
311
|
+
}
|
|
291
312
|
}
|
|
292
313
|
}
|
|
293
314
|
|
|
@@ -303,7 +324,11 @@ export function runSupervisorDaemon(opts: SupervisorDaemonOptions): void {
|
|
|
303
324
|
framers.set(s as object, makeFramer((t, p) => onClientFrame(s, t, p)))
|
|
304
325
|
clients.add(s)
|
|
305
326
|
syncAttached() // ≥1 client now attached → marker present
|
|
306
|
-
repaint
|
|
327
|
+
// NO repaint here. A viewer's runClient sends its real terminal size as the FIRST FRAME_RESIZE on
|
|
328
|
+
// connect (client.ts open → "repaint at our size"); we paint THEN, ONCE, at the correct geometry.
|
|
329
|
+
// Painting here at the serve geometry (e.g. 220×50) would send a second, wrong-width dump that
|
|
330
|
+
// STACKS in a terminal ignoring \x1b[3J (Apple Terminal) → smeared scroll-up history (Bug B). A
|
|
331
|
+
// deliver client (deliverToHost) never resizes and ignores output → it gets no wasted paint.
|
|
307
332
|
},
|
|
308
333
|
data(s: object, d: Uint8Array) {
|
|
309
334
|
framers.get(s)?.(d)
|