@agfpd/iapeer 0.2.84 → 0.2.85
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 +18 -20
package/package.json
CHANGED
package/src/supervisor/daemon.ts
CHANGED
|
@@ -163,11 +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
|
|
167
|
-
// FRAME_RESIZE (which runClient always sends on connect, at the real terminal size). Re-dumping
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
166
|
+
// FIRST-PAINT TRACKING (Bug B fix): a client gets the full scrollback catch-up EXACTLY ONCE — on its
|
|
167
|
+
// first FRAME_RESIZE (which runClient always sends on connect, at the real terminal size). Re-dumping
|
|
168
|
+
// on a later resize STACKS duplicate histories in a terminal that ignores \x1b[3J (Apple Terminal has
|
|
169
|
+
// NO E3 capability) → smeared/overlapping scroll-up history. After the catch-up the supervisor does
|
|
170
|
+
// NOTHING on resize — the child redraws its viewport (SIGWINCH) and the terminal reflows its own
|
|
171
|
+
// scrollback, like a directly-launched claude.
|
|
171
172
|
const painted = new WeakSet<object>()
|
|
172
173
|
// ATTACHED-CLIENT MARKER (spawn-flip Ф0b-3 slice 3c): keep `<runDir>/<session>.attached` in sync with
|
|
173
174
|
// clients.size — present iff ≥1 operator is attached. The warm-deliver path (a DIFFERENT process)
|
|
@@ -253,22 +254,18 @@ export function runSupervisorDaemon(opts: SupervisorDaemonOptions): void {
|
|
|
253
254
|
} as unknown as Parameters<typeof Bun.spawn>[1]) as unknown as PtyChild
|
|
254
255
|
xterm.onData(resp => child.terminal.write(resp)) // @xterm auto-answers DA1/DSR → back to child
|
|
255
256
|
|
|
256
|
-
/**
|
|
257
|
-
* Backpressure-safe — a ~90 KB heavy snapshot MUST NOT drop past the
|
|
257
|
+
/** Catch up a (re)attaching client to the current screen + history ONCE: clear+home, then the full
|
|
258
|
+
* grid from the headless snapshot. Backpressure-safe — a ~90 KB heavy snapshot MUST NOT drop past the
|
|
259
|
+
* socket buffer (port-dep #2). Called EXACTLY ONCE per client (its first FRAME_RESIZE). It is NEVER
|
|
260
|
+
* re-issued on a later resize: re-dumping stacks a second history copy in a terminal that ignores
|
|
261
|
+
* \x1b[3J (Apple Terminal has no E3) → smeared scroll-up history (Bug B). After the first catch-up the
|
|
262
|
+
* supervisor stops intervening: a resize just re-sizes the child (applyGeometry → SIGWINCH), and the
|
|
263
|
+
* child redraws its own viewport while the terminal reflows its own scrollback — exactly like a
|
|
264
|
+
* directly-launched claude. */
|
|
258
265
|
const repaint = (s: { write(b: Buffer): number }): void => {
|
|
259
266
|
const snap = '\x1b[2J\x1b[3J\x1b[H' + stripSpinnerScrollback(ser.serialize(), xterm.rows)
|
|
260
267
|
sendClient(s, frame(FRAME_DATA, Buffer.from(snap, 'utf8')))
|
|
261
268
|
}
|
|
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
|
-
}
|
|
272
269
|
|
|
273
270
|
// Resize the model + child pty to (c, r). Shared by client FRAME_RESIZE and the last-detach restore.
|
|
274
271
|
const applyGeometry = (c: number, r: number): void => {
|
|
@@ -305,10 +302,11 @@ export function runSupervisorDaemon(opts: SupervisorDaemonOptions): void {
|
|
|
305
302
|
applyGeometry(sz.cols, sz.rows)
|
|
306
303
|
if (!painted.has(s as object)) {
|
|
307
304
|
painted.add(s as object)
|
|
308
|
-
repaint(s) // FIRST
|
|
309
|
-
} else {
|
|
310
|
-
repaintViewport(s) // later resize: refresh the screen only — never re-dump scrollback (anti-stack)
|
|
305
|
+
repaint(s) // FIRST resize for this client = the one-time catch-up (full snapshot at its real size)
|
|
311
306
|
}
|
|
307
|
+
// LATER resizes: nothing from the supervisor. applyGeometry already SIGWINCH'd the child → it
|
|
308
|
+
// redraws its own viewport (forwarded live) and the terminal reflows its own scrollback, exactly
|
|
309
|
+
// like a directly-launched claude. Re-dumping here would stack history in a no-\x1b[3J terminal.
|
|
312
310
|
}
|
|
313
311
|
}
|
|
314
312
|
|