@agfpd/iapeer 0.4.108 → 0.4.109
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
CHANGED
package/src/supervisor/client.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// port-deps live here + in protocol.ts: #1 TERM_RESET on EVERY exit path (incl. SIGHUP window-close,
|
|
4
4
|
// via writeSync which works inside a signal handler), and #2 backpressure is the daemon's side.
|
|
5
5
|
import { writeSync } from 'node:fs'
|
|
6
|
-
import { FRAME_DATA, FRAME_RESIZE, TERM_RESET, frame, makeFramer, sizePayload } from './protocol.ts'
|
|
6
|
+
import { FRAME_DATA, FRAME_RESIZE, TERM_ATTACH_RESET, TERM_RESET, frame, makeFramer, sizePayload } from './protocol.ts'
|
|
7
7
|
import { ownershipVerdict, pidStartToken, readPidFile, sockPath } from './paths.ts'
|
|
8
8
|
|
|
9
9
|
const DETACH = 0x1d // Ctrl-]
|
|
@@ -81,6 +81,17 @@ export async function runSupervisorClient(runDir: string, session: string): Prom
|
|
|
81
81
|
// Ready the terminal BEFORE connecting, so the repaint snapshot renders the instant it arrives.
|
|
82
82
|
if (process.stdin.isTTY) process.stdin.setRawMode(true)
|
|
83
83
|
process.stdin.resume()
|
|
84
|
+
// The daemon owns the emulated session/model; THIS client owns the physical operator viewport.
|
|
85
|
+
// Normalize that viewport before connecting so its one-time snapshot cannot be appended below a
|
|
86
|
+
// shell prompt or a prior attach's differently-wrapped frame. HOME+ED0 is intentional: unlike
|
|
87
|
+
// ED2/ED3 it does not trigger Apple Terminal's clear-to-scrollback trap (protocol.ts).
|
|
88
|
+
if (process.stdout.isTTY) {
|
|
89
|
+
try {
|
|
90
|
+
writeSync(1, TERM_ATTACH_RESET)
|
|
91
|
+
} catch {
|
|
92
|
+
/* a failed cosmetic reset must not block attach */
|
|
93
|
+
}
|
|
94
|
+
}
|
|
84
95
|
|
|
85
96
|
const curSize = (): Buffer => sizePayload(process.stdout.columns || 80, process.stdout.rows || 24)
|
|
86
97
|
const sock = await Bun.connect({
|
|
@@ -142,9 +153,9 @@ export async function runSupervisorClient(runDir: string, session: string): Prom
|
|
|
142
153
|
})
|
|
143
154
|
}
|
|
144
155
|
process.on('exit', () => restore()) // last-resort sync net
|
|
145
|
-
// NO pre-repaint attach banner:
|
|
146
|
-
//
|
|
147
|
-
//
|
|
156
|
+
// NO pre-repaint attach banner: after TERM_ATTACH_RESET, the daemon snapshot must be the first CONTENT
|
|
157
|
+
// painted into the normalized viewport. The detach key (Ctrl-]) is documented in CLI help / the attach
|
|
158
|
+
// verb, not emitted as a scrollback line.
|
|
148
159
|
// STAY ATTACHED. The client lives on its handles (raw stdin + the socket); EVERY terminal path
|
|
149
160
|
// (detach Ctrl-], session-end close(), SIGHUP/SIGTERM, socket error) calls process.exit ITSELF.
|
|
150
161
|
// This promise INTENTIONALLY never resolves: returning here would resolve runSupervisorClient the
|
package/src/supervisor/daemon.ts
CHANGED
|
@@ -399,8 +399,9 @@ export function runSupervisorDaemon(opts: SupervisorDaemonOptions): void {
|
|
|
399
399
|
* Scrollback rows are spinner-stripped; the viewport stays verbatim. The child's SIGWINCH redraw (from
|
|
400
400
|
* applyGeometry) then settles the live viewport at the client's width. Backpressure-safe
|
|
401
401
|
* (BackpressureWriter) — a large snapshot MUST NOT drop past the socket buffer (port-dep #2). Called
|
|
402
|
-
* EXACTLY ONCE per client (its first FRAME_RESIZE).
|
|
403
|
-
*
|
|
402
|
+
* EXACTLY ONCE per client (its first FRAME_RESIZE). The daemon/model sends NO clears
|
|
403
|
+
* (\x1b[2J/3J): Apple Terminal scrolls 2J into scrollback + ignores 3J. The attach client owns its
|
|
404
|
+
* physical viewport and normalizes it once with HOME+ED0 before connecting. */
|
|
404
405
|
// Await until the model has parsed ALL writes AND none arrived during the wait (stable). Awaiting a single
|
|
405
406
|
// write promise is not enough: while the client is gated (initializing, live-forward skipped) new child
|
|
406
407
|
// bytes still land in the model and bump writeSeq — loop until the sequence holds steady so the snapshot
|
|
@@ -164,6 +164,18 @@ export function keysToBytes(keys: string[], enc: KeyEncoding = {}): Buffer {
|
|
|
164
164
|
return Buffer.from(out, 'utf8')
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
// ── client terminal normalization ────────────────────────────────────────────────
|
|
168
|
+
// A (re)attach can start in an already-used Terminal.app normal buffer: the shell prompt and a prior
|
|
169
|
+
// attach's differently-wrapped frame still occupy the physical viewport. The daemon's serialized model
|
|
170
|
+
// deliberately carries NO clear (it is shared protocol data, while the stale viewport belongs to each
|
|
171
|
+
// client), so the client must home + erase the CURRENT display before the one-time snapshot arrives.
|
|
172
|
+
//
|
|
173
|
+
// Use ED0 from HOME, NOT ED2/ED3. Apple Terminal implements neither of the latter as the primitive we
|
|
174
|
+
// need: ED2 pushes the old display into native scrollback and ED3 is ignored, so repeated attaches stack
|
|
175
|
+
// broken-width dumps in history. HOME+ED0 clears the viewport in place; the daemon still sends exactly
|
|
176
|
+
// one model snapshot and later SIGWINCH resizes remain raw/live (no repeated dump).
|
|
177
|
+
export const TERM_ATTACH_RESET = '\x1b[H\x1b[J'
|
|
178
|
+
|
|
167
179
|
// ── port-dep #1: terminal reset on every client exit path ───────────────────────
|
|
168
180
|
// The child sets a STACK of app-modes on the live terminal (alt-screen, bracketed-paste,
|
|
169
181
|
// focus-events, theme-update, ALL mouse tracking, kitty-keyboard, scroll-region, hidden cursor).
|