pty-manager 1.3.1 → 1.3.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.
- package/README.md +3 -1
- package/dist/index.d.mts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +64 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -41
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +64 -41
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -309,6 +309,12 @@ var PTYSession = class _PTYSession extends EventEmitter {
|
|
|
309
309
|
// Task completion detection (idle detection when busy)
|
|
310
310
|
_taskCompleteTimer = null;
|
|
311
311
|
static TASK_COMPLETE_DEBOUNCE_MS = 1500;
|
|
312
|
+
// Deferred output processing — prevents node-pty's synchronous data
|
|
313
|
+
// delivery from starving the event loop (timers, I/O callbacks, etc.)
|
|
314
|
+
_processScheduled = false;
|
|
315
|
+
// Output buffer cap — prevents unbounded growth during long tasks
|
|
316
|
+
static MAX_OUTPUT_BUFFER = 1e5;
|
|
317
|
+
// 100 KB
|
|
312
318
|
id;
|
|
313
319
|
config;
|
|
314
320
|
get status() {
|
|
@@ -651,49 +657,16 @@ var PTYSession = class _PTYSession extends EventEmitter {
|
|
|
651
657
|
this.ptyProcess.onData((data) => {
|
|
652
658
|
this._lastActivityAt = /* @__PURE__ */ new Date();
|
|
653
659
|
this.outputBuffer += data;
|
|
654
|
-
if (this.
|
|
655
|
-
this.
|
|
660
|
+
if (this.outputBuffer.length > _PTYSession.MAX_OUTPUT_BUFFER) {
|
|
661
|
+
this.outputBuffer = this.outputBuffer.slice(-_PTYSession.MAX_OUTPUT_BUFFER);
|
|
656
662
|
}
|
|
657
663
|
this.emit("output", data);
|
|
658
|
-
if (
|
|
659
|
-
this.
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
this.logger.info({ sessionId: this.id }, "Session ready");
|
|
665
|
-
return;
|
|
666
|
-
}
|
|
667
|
-
if (this._status === "busy" && this.adapter.detectReady(this.outputBuffer)) {
|
|
668
|
-
this.scheduleTaskComplete();
|
|
669
|
-
} else {
|
|
670
|
-
this.cancelTaskComplete();
|
|
671
|
-
}
|
|
672
|
-
const blockingPrompt = this.detectAndHandleBlockingPrompt();
|
|
673
|
-
if (blockingPrompt) {
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
if (this._status !== "ready" && this._status !== "busy") {
|
|
677
|
-
const loginDetection = this.adapter.detectLogin(this.outputBuffer);
|
|
678
|
-
if (loginDetection.required && this._status !== "authenticating") {
|
|
679
|
-
this._status = "authenticating";
|
|
680
|
-
this.clearStallTimer();
|
|
681
|
-
this.emit("login_required", loginDetection.instructions, loginDetection.url);
|
|
682
|
-
this.logger.warn(
|
|
683
|
-
{ sessionId: this.id, loginType: loginDetection.type },
|
|
684
|
-
"Login required"
|
|
685
|
-
);
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
const exitDetection = this.adapter.detectExit(this.outputBuffer);
|
|
690
|
-
if (exitDetection.exited) {
|
|
691
|
-
this._status = "stopped";
|
|
692
|
-
this.clearStallTimer();
|
|
693
|
-
this.emit("exit", exitDetection.code || 0);
|
|
694
|
-
}
|
|
695
|
-
if (this._status !== "starting" && this._status !== "authenticating") {
|
|
696
|
-
this.tryParseOutput();
|
|
664
|
+
if (!this._processScheduled) {
|
|
665
|
+
this._processScheduled = true;
|
|
666
|
+
setImmediate(() => {
|
|
667
|
+
this._processScheduled = false;
|
|
668
|
+
this.processOutputBuffer();
|
|
669
|
+
});
|
|
697
670
|
}
|
|
698
671
|
});
|
|
699
672
|
this.ptyProcess.onExit(({ exitCode, signal }) => {
|
|
@@ -706,6 +679,56 @@ var PTYSession = class _PTYSession extends EventEmitter {
|
|
|
706
679
|
this.emit("exit", exitCode);
|
|
707
680
|
});
|
|
708
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Process the accumulated output buffer.
|
|
684
|
+
* Called via setImmediate() from the onData handler so that heavy regex
|
|
685
|
+
* work runs in its own event-loop tick, not inside node-pty's native callback.
|
|
686
|
+
*/
|
|
687
|
+
processOutputBuffer() {
|
|
688
|
+
if (this._status === "busy" || this._status === "authenticating") {
|
|
689
|
+
this.resetStallTimer();
|
|
690
|
+
}
|
|
691
|
+
if ((this._status === "starting" || this._status === "authenticating") && this.adapter.detectReady(this.outputBuffer)) {
|
|
692
|
+
this._status = "ready";
|
|
693
|
+
this._lastBlockingPromptHash = null;
|
|
694
|
+
this.outputBuffer = "";
|
|
695
|
+
this.clearStallTimer();
|
|
696
|
+
this.emit("ready");
|
|
697
|
+
this.logger.info({ sessionId: this.id }, "Session ready");
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (this._status === "busy" && this.adapter.detectReady(this.outputBuffer)) {
|
|
701
|
+
this.scheduleTaskComplete();
|
|
702
|
+
} else {
|
|
703
|
+
this.cancelTaskComplete();
|
|
704
|
+
}
|
|
705
|
+
const blockingPrompt = this.detectAndHandleBlockingPrompt();
|
|
706
|
+
if (blockingPrompt) {
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
if (this._status !== "ready" && this._status !== "busy") {
|
|
710
|
+
const loginDetection = this.adapter.detectLogin(this.outputBuffer);
|
|
711
|
+
if (loginDetection.required && this._status !== "authenticating") {
|
|
712
|
+
this._status = "authenticating";
|
|
713
|
+
this.clearStallTimer();
|
|
714
|
+
this.emit("login_required", loginDetection.instructions, loginDetection.url);
|
|
715
|
+
this.logger.warn(
|
|
716
|
+
{ sessionId: this.id, loginType: loginDetection.type },
|
|
717
|
+
"Login required"
|
|
718
|
+
);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
const exitDetection = this.adapter.detectExit(this.outputBuffer);
|
|
723
|
+
if (exitDetection.exited) {
|
|
724
|
+
this._status = "stopped";
|
|
725
|
+
this.clearStallTimer();
|
|
726
|
+
this.emit("exit", exitDetection.code || 0);
|
|
727
|
+
}
|
|
728
|
+
if (this._status !== "starting" && this._status !== "authenticating") {
|
|
729
|
+
this.tryParseOutput();
|
|
730
|
+
}
|
|
731
|
+
}
|
|
709
732
|
/**
|
|
710
733
|
* Detect blocking prompts and handle them with auto-responses or user notification.
|
|
711
734
|
* Deduplicates emissions - won't re-emit the same blocking prompt repeatedly.
|