agent-relay-orchestrator 0.10.24 → 0.10.25

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/src/api.ts +13 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-orchestrator",
3
- "version": "0.10.24",
3
+ "version": "0.10.25",
4
4
  "description": "Agent Relay orchestrator — manages agent lifecycle across hosts",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api.ts CHANGED
@@ -597,8 +597,14 @@ function startTerminalSocket(ws: TerminalSocket): void {
597
597
  }
598
598
  }
599
599
 
600
- // Resize the pane to the viewer's dimensions, capture the matching backfill, and
601
- // release the queued live bytes. Idempotent-safe: only the first call backfills.
600
+ // Resize the pane to the viewer's dimensions and capture the matching backfill.
601
+ //
602
+ // Claude's TUI streams pure *relative* cursor deltas (no absolute positioning), so
603
+ // the backfill snapshot already reflects every byte emitted up to the capture moment.
604
+ // The capture is synchronous (spawnSync), so no live byte is processed during it —
605
+ // which means the queued bytes are all PRE-capture and already baked into the snapshot.
606
+ // Replaying them would double-apply every delta and stack a garbled ghost frame, so we
607
+ // discard the queue here and only forward bytes that arrive after the capture.
602
608
  function syncAndBackfill(ws: TerminalSocket, cols?: number, rows?: number): void {
603
609
  if (ws.data.syncTimer) {
604
610
  clearTimeout(ws.data.syncTimer);
@@ -606,14 +612,8 @@ function syncAndBackfill(ws: TerminalSocket, cols?: number, rows?: number): void
606
612
  }
607
613
  ws.data.synced = true;
608
614
  sendBackfill(ws, cols, rows);
609
- ws.data.ready = true;
610
- const queued = ws.data.queue ?? [];
611
615
  ws.data.queue = [];
612
- for (const bytes of queued) {
613
- try {
614
- ws.send(bytes);
615
- } catch {}
616
- }
616
+ ws.data.ready = true;
617
617
  }
618
618
 
619
619
  // Send a full reset: a control frame with current geometry/status, then the
@@ -634,11 +634,14 @@ function sendBackfill(ws: TerminalSocket, cols?: number, rows?: number): void {
634
634
  capturedAt: snapshot.capturedAt,
635
635
  }));
636
636
  if (snapshot.content) {
637
+ // Strip the single trailing newline capture-pane appends. Left in, it scrolls xterm
638
+ // one extra row so the whole screen sits one row too high — and the cursor-park below
639
+ // then lands a row off, offsetting every relative statusline redraw (bottom-box ghost).
640
+ let content = snapshot.content.replace(/\n$/, "");
637
641
  // Park the cursor where tmux actually has it (screen-relative). Without this the
638
642
  // cursor sits at the end of the captured text, so the TUI's first relative redraw
639
643
  // (cursor-up + rewrite of its prompt/statusline) lands at the wrong row and stacks
640
644
  // a ghost copy into scrollback.
641
- let content = snapshot.content;
642
645
  if (snapshot.cursorX != null && snapshot.cursorY != null) {
643
646
  content += `\x1b[${snapshot.cursorY + 1};${snapshot.cursorX + 1}H`;
644
647
  }