@phenx-inc/ctlsurf 0.1.8 → 0.1.10

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.
@@ -3641,14 +3641,15 @@ var CtlsurfApi = class {
3641
3641
  var import_headless = __toESM(require_xterm_headless());
3642
3642
  var ConversationBridge = class {
3643
3643
  wsClient = null;
3644
- flushTimer = null;
3645
- flushIntervalMs = 3e3;
3646
3644
  sessionActive = false;
3647
3645
  inputBuffer = "";
3646
+ bytesAccumulated = 0;
3648
3647
  // Virtual terminal for processing escape sequences into rendered text
3649
3648
  terminal;
3650
- lastSnapshotLines = 0;
3651
- pendingWrites = 0;
3649
+ lastSnapshot = "";
3650
+ // Flush after accumulating enough data or on a timer
3651
+ FLUSH_BYTES = 2e3;
3652
+ flushTimer = null;
3652
3653
  constructor() {
3653
3654
  this.terminal = new import_headless.Terminal({ cols: 120, rows: 50, scrollback: 1e4 });
3654
3655
  }
@@ -3657,10 +3658,12 @@ var ConversationBridge = class {
3657
3658
  }
3658
3659
  startSession() {
3659
3660
  this.terminal.reset();
3660
- this.lastSnapshotLines = 0;
3661
- this.pendingWrites = 0;
3661
+ this.lastSnapshot = "";
3662
+ this.bytesAccumulated = 0;
3662
3663
  this.inputBuffer = "";
3663
3664
  this.sessionActive = true;
3665
+ if (this.flushTimer) clearInterval(this.flushTimer);
3666
+ this.flushTimer = setInterval(() => this.flush(), 5e3);
3664
3667
  console.log("[bridge] Session started");
3665
3668
  }
3666
3669
  /**
@@ -3670,17 +3673,11 @@ var ConversationBridge = class {
3670
3673
  */
3671
3674
  feedOutput(data) {
3672
3675
  if (!this.sessionActive) return;
3673
- this.pendingWrites++;
3674
- this.terminal.write(data, () => {
3675
- this.pendingWrites--;
3676
- this.scheduleFlush();
3677
- });
3678
- }
3679
- scheduleFlush() {
3680
- if (this.flushTimer) {
3681
- clearTimeout(this.flushTimer);
3676
+ this.terminal.write(data);
3677
+ this.bytesAccumulated += data.length;
3678
+ if (this.bytesAccumulated >= this.FLUSH_BYTES) {
3679
+ this.flush();
3682
3680
  }
3683
- this.flushTimer = setTimeout(() => this.flush(), this.flushIntervalMs);
3684
3681
  }
3685
3682
  feedInput(data) {
3686
3683
  if (!this.sessionActive) return;
@@ -3701,23 +3698,25 @@ var ConversationBridge = class {
3701
3698
  * Only flushes when all pending writes have completed.
3702
3699
  */
3703
3700
  flush() {
3704
- if (this.pendingWrites > 0) {
3705
- this.scheduleFlush();
3706
- return;
3707
- }
3708
3701
  const buf = this.terminal.buffer.active;
3709
- const totalLines = buf.baseY + buf.cursorY + 1;
3710
- if (totalLines <= this.lastSnapshotLines) return;
3711
- const newLines = [];
3712
- for (let i = this.lastSnapshotLines; i < totalLines; i++) {
3702
+ const totalLines = buf.baseY + this.terminal.rows;
3703
+ const allLines = [];
3704
+ for (let i = 0; i < totalLines; i++) {
3713
3705
  const line = buf.getLine(i);
3714
3706
  if (line) {
3715
- newLines.push(line.translateToString(true));
3707
+ allLines.push(line.translateToString(true));
3716
3708
  }
3717
3709
  }
3718
- this.lastSnapshotLines = totalLines;
3719
- const content = newLines.join("\n");
3720
- const cleaned = content.replace(/\n{3,}/g, "\n\n").trim();
3710
+ const currentSnapshot = allLines.join("\n");
3711
+ let newContent;
3712
+ if (currentSnapshot.startsWith(this.lastSnapshot)) {
3713
+ newContent = currentSnapshot.slice(this.lastSnapshot.length);
3714
+ } else {
3715
+ newContent = currentSnapshot;
3716
+ }
3717
+ this.lastSnapshot = currentSnapshot;
3718
+ const cleaned = newContent.replace(/\n{3,}/g, "\n\n").trim();
3719
+ this.bytesAccumulated = 0;
3721
3720
  if (cleaned.length === 0) return;
3722
3721
  this.sendEntry("terminal_output", cleaned);
3723
3722
  }
@@ -3729,15 +3728,11 @@ var ConversationBridge = class {
3729
3728
  content
3730
3729
  });
3731
3730
  }
3732
- async endSession() {
3731
+ endSession() {
3733
3732
  if (!this.sessionActive) return;
3734
- if (this.pendingWrites > 0) {
3735
- await new Promise((resolve) => setTimeout(resolve, 500));
3736
- }
3737
- this.pendingWrites = 0;
3738
3733
  this.flush();
3739
3734
  if (this.flushTimer) {
3740
- clearTimeout(this.flushTimer);
3735
+ clearInterval(this.flushTimer);
3741
3736
  this.flushTimer = null;
3742
3737
  }
3743
3738
  this.sessionActive = false;
@@ -4236,7 +4231,7 @@ var Orchestrator = class {
4236
4231
  // ─── PTY & Agent ────────────────────────────────
4237
4232
  async spawnAgent(agent, cwd) {
4238
4233
  if (this.ptyManager) {
4239
- await this.bridge.endSession();
4234
+ this.bridge.endSession();
4240
4235
  this.ptyManager.kill();
4241
4236
  }
4242
4237
  this.currentAgent = agent;
@@ -4254,7 +4249,7 @@ var Orchestrator = class {
4254
4249
  const thisPtyManager = this.ptyManager;
4255
4250
  this.ptyManager.onExit(async (exitCode) => {
4256
4251
  this.events.onPtyExit(exitCode);
4257
- await this.bridge.endSession();
4252
+ this.bridge.endSession();
4258
4253
  if (thisPtyManager === this.ptyManager && this.currentAgent && isCodingAgent(this.currentAgent)) {
4259
4254
  this.workerWs.disconnect();
4260
4255
  }
@@ -4277,7 +4272,7 @@ var Orchestrator = class {
4277
4272
  this.workerWs.sendTerminalResize(cols, rows);
4278
4273
  }
4279
4274
  async killAgent() {
4280
- await this.bridge.endSession();
4275
+ this.bridge.endSession();
4281
4276
  this.ptyManager?.kill();
4282
4277
  this.ptyManager = null;
4283
4278
  if (this.currentAgent && isCodingAgent(this.currentAgent)) {
@@ -4326,7 +4321,7 @@ var Orchestrator = class {
4326
4321
  }
4327
4322
  // ─── Shutdown ───────────────────────────────────
4328
4323
  async shutdown() {
4329
- await this.bridge.endSession();
4324
+ this.bridge.endSession();
4330
4325
  this.ptyManager?.kill();
4331
4326
  this.ptyManager = null;
4332
4327
  this.workerWs.disconnect();