rterm-backend 3.2.0 → 3.2.2

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/bin/gybackend.cjs +70 -15
  2. package/package.json +2 -2
package/bin/gybackend.cjs CHANGED
@@ -295047,7 +295047,7 @@ var normalizeTerminalResizeTarget = (cols, rows) => {
295047
295047
  rows: Math.max(1, Math.floor(rows))
295048
295048
  };
295049
295049
  };
295050
- var TerminalService = class {
295050
+ var TerminalService = class _TerminalService {
295051
295051
  backends = /* @__PURE__ */ new Map();
295052
295052
  terminals = /* @__PURE__ */ new Map();
295053
295053
  terminalConfigs = /* @__PURE__ */ new Map();
@@ -295055,6 +295055,11 @@ var TerminalService = class {
295055
295055
  pendingResizeByTerminal = /* @__PURE__ */ new Map();
295056
295056
  buffers = /* @__PURE__ */ new Map();
295057
295057
  headlessPtys = /* @__PURE__ */ new Map();
295058
+ /** Buffered writes for terminals that aren't writable yet (prevents keystroke loss during reconnection). */
295059
+ pendingWrites = /* @__PURE__ */ new Map();
295060
+ pendingWriteTimers = /* @__PURE__ */ new Map();
295061
+ pendingWriteRetries = /* @__PURE__ */ new Map();
295062
+ static MAX_WRITE_RETRIES = 3;
295058
295063
  selectionByTerminal = /* @__PURE__ */ new Map();
295059
295064
  tasksByTerminal = /* @__PURE__ */ new Map();
295060
295065
  activeTaskByTerminal = /* @__PURE__ */ new Map();
@@ -295616,21 +295621,28 @@ var TerminalService = class {
295616
295621
  handleData(terminalId, data) {
295617
295622
  const sanitizedData = stripInternalControlMarkers(data);
295618
295623
  const tab = this.terminals.get(terminalId);
295619
- const recordingId = this.activeRecordings.get(terminalId);
295620
- if (recordingId && this.sessionRecorder && sanitizedData) {
295621
- try {
295622
- this.sessionRecorder.out(recordingId, sanitizedData);
295623
- } catch {
295624
- }
295625
- }
295626
- if (this.sessionLogger && tab) {
295627
- if (!this.sessionLogStarted.has(terminalId)) {
295628
- this.sessionLogStarted.add(terminalId);
295629
- const cfg = this.terminalConfigs.get(terminalId);
295630
- this.sessionLogger.start(terminalId, { title: tab.title || terminalId, type: tab.type });
295631
- void cfg;
295624
+ if (sanitizedData) {
295625
+ const recordingId = this.activeRecordings.get(terminalId);
295626
+ if (recordingId || this.sessionLogger && tab) {
295627
+ const captureData = sanitizedData;
295628
+ const captureTab = tab;
295629
+ const captureId = recordingId;
295630
+ setImmediate(() => {
295631
+ if (captureId && this.sessionRecorder) {
295632
+ try {
295633
+ this.sessionRecorder.out(captureId, captureData);
295634
+ } catch {
295635
+ }
295636
+ }
295637
+ if (this.sessionLogger && captureTab) {
295638
+ if (!this.sessionLogStarted.has(terminalId)) {
295639
+ this.sessionLogStarted.add(terminalId);
295640
+ this.sessionLogger.start(terminalId, { title: captureTab.title || terminalId, type: captureTab.type });
295641
+ }
295642
+ this.sessionLogger.write(terminalId, captureData);
295643
+ }
295644
+ });
295632
295645
  }
295633
- this.sessionLogger.write(terminalId, sanitizedData);
295634
295646
  }
295635
295647
  if (tab) {
295636
295648
  let shouldPublishTabsChanged = false;
@@ -295949,6 +295961,42 @@ ${promptPrefix}`;
295949
295961
  if (terminal && this.canWriteToTerminal(terminal)) {
295950
295962
  const backend = this.getBackend(terminal.type);
295951
295963
  backend.write(terminal.ptyId, data);
295964
+ this.pendingWriteRetries.delete(terminalId);
295965
+ } else if (terminal) {
295966
+ if (terminal.runtimeState === "exited") {
295967
+ this.pendingWrites.delete(terminalId);
295968
+ this.pendingWriteRetries.delete(terminalId);
295969
+ const timer = this.pendingWriteTimers.get(terminalId);
295970
+ if (timer) {
295971
+ clearTimeout(timer);
295972
+ this.pendingWriteTimers.delete(terminalId);
295973
+ }
295974
+ return;
295975
+ }
295976
+ const retries = this.pendingWriteRetries.get(terminalId) ?? 0;
295977
+ if (retries >= _TerminalService.MAX_WRITE_RETRIES) {
295978
+ this.pendingWrites.delete(terminalId);
295979
+ this.pendingWriteRetries.delete(terminalId);
295980
+ return;
295981
+ }
295982
+ const pending = this.pendingWrites.get(terminalId) ?? "";
295983
+ this.pendingWrites.set(terminalId, pending + data);
295984
+ if (!this.pendingWriteTimers.has(terminalId)) {
295985
+ const timer = setTimeout(() => {
295986
+ this.pendingWriteTimers.delete(terminalId);
295987
+ const term = this.terminals.get(terminalId);
295988
+ const buffered = this.pendingWrites.get(terminalId);
295989
+ if (term && buffered && this.canWriteToTerminal(term)) {
295990
+ this.pendingWrites.delete(terminalId);
295991
+ this.pendingWriteRetries.delete(terminalId);
295992
+ const b = this.getBackend(term.type);
295993
+ b.write(term.ptyId, buffered);
295994
+ } else {
295995
+ this.pendingWriteRetries.set(terminalId, retries + 1);
295996
+ }
295997
+ }, 500);
295998
+ this.pendingWriteTimers.set(terminalId, timer);
295999
+ }
295952
296000
  }
295953
296001
  }
295954
296002
  /**
@@ -296003,6 +296051,13 @@ ${promptPrefix}`;
296003
296051
  }
296004
296052
  kill(terminalId) {
296005
296053
  this.pendingResizeByTerminal.delete(terminalId);
296054
+ this.pendingWrites.delete(terminalId);
296055
+ this.pendingWriteRetries.delete(terminalId);
296056
+ const writeTimer = this.pendingWriteTimers.get(terminalId);
296057
+ if (writeTimer) {
296058
+ clearTimeout(writeTimer);
296059
+ this.pendingWriteTimers.delete(terminalId);
296060
+ }
296006
296061
  this.autoReconnect.clear(terminalId);
296007
296062
  const terminal = this.terminals.get(terminalId);
296008
296063
  if (terminal) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rterm-backend",
3
- "version": "3.2.0",
4
- "description": "Headless AI-native backend for RTerm / neuralOS — v3.2.0: production-ready Synapse dispatch (skip JetStream ack, multi-mesh, 600s timeout). 11 plugins, 55 plugin tools wired, full-duplex Synapse agent. Transports (SSH/serial/local), SQLite, and NATS libs install automatically.",
3
+ "version": "3.2.2",
4
+ "description": "Headless AI-native backend for RTerm / neuralOS — v3.2.2: 5 edge case fixes (session-busy race, heavy output batching, stop-during-approval, stop debounce, write-retry limit). 11 plugins, 55 plugin tools wired. Transports (SSH/serial/local), SQLite, and NATS libs install automatically.",
5
5
  "main": "bin/gybackend.cjs",
6
6
  "bin": { "gybackend": "bin/gybackend.cjs" },
7
7
  "license": "MIT",