pty-manager 1.2.21 → 1.2.22
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/dist/index.d.mts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +76 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +76 -7
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +71 -7
- package/package.json +1 -1
package/dist/pty-worker.js
CHANGED
|
@@ -289,7 +289,7 @@ var SPECIAL_KEYS = {
|
|
|
289
289
|
};
|
|
290
290
|
var BRACKETED_PASTE_START = "\x1B[200~";
|
|
291
291
|
var BRACKETED_PASTE_END = "\x1B[201~";
|
|
292
|
-
var PTYSession = class extends import_events.EventEmitter {
|
|
292
|
+
var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
293
293
|
constructor(adapter, config, logger, stallDetectionEnabled, defaultStallTimeoutMs) {
|
|
294
294
|
super();
|
|
295
295
|
this.adapter = adapter;
|
|
@@ -327,6 +327,9 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
327
327
|
_lastStallHash = null;
|
|
328
328
|
_stallStartedAt = null;
|
|
329
329
|
_lastContentHash = null;
|
|
330
|
+
// Task completion detection (idle detection when busy)
|
|
331
|
+
_taskCompleteTimer = null;
|
|
332
|
+
static TASK_COMPLETE_DEBOUNCE_MS = 1500;
|
|
330
333
|
id;
|
|
331
334
|
config;
|
|
332
335
|
get status() {
|
|
@@ -502,10 +505,12 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
502
505
|
* word boundaries — e.g. "Do\x1b[5Cyou" becomes "Do you", not "Doyou".
|
|
503
506
|
*/
|
|
504
507
|
stripAnsiForStall(str) {
|
|
505
|
-
let result = str.replace(/\x1b\[\d*[
|
|
508
|
+
let result = str.replace(/\x1b\[\d*[CDABGdEF]/g, " ");
|
|
506
509
|
result = result.replace(/\x1b\[\d*(?:;\d+)?[Hf]/g, " ");
|
|
510
|
+
result = result.replace(/\x1b\[\d*[JK]/g, " ");
|
|
507
511
|
result = result.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
508
|
-
result = result.replace(/[
|
|
512
|
+
result = result.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
513
|
+
result = result.replace(/[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥]/g, " ");
|
|
509
514
|
result = result.replace(/ {2,}/g, " ");
|
|
510
515
|
return result;
|
|
511
516
|
}
|
|
@@ -563,6 +568,39 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
563
568
|
}
|
|
564
569
|
}
|
|
565
570
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
571
|
+
// Task Completion Detection
|
|
572
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
573
|
+
/**
|
|
574
|
+
* Schedule a task_complete transition after a debounce period.
|
|
575
|
+
* If new non-whitespace output arrives before the timer fires,
|
|
576
|
+
* the timer is cancelled (by cancelTaskComplete in onData).
|
|
577
|
+
*/
|
|
578
|
+
scheduleTaskComplete() {
|
|
579
|
+
if (this._taskCompleteTimer) return;
|
|
580
|
+
this._taskCompleteTimer = setTimeout(() => {
|
|
581
|
+
this._taskCompleteTimer = null;
|
|
582
|
+
if (this._status !== "busy") return;
|
|
583
|
+
if (!this.adapter.detectReady(this.outputBuffer)) return;
|
|
584
|
+
this._status = "ready";
|
|
585
|
+
this._lastBlockingPromptHash = null;
|
|
586
|
+
this.outputBuffer = "";
|
|
587
|
+
this.clearStallTimer();
|
|
588
|
+
this.emit("status_changed", "ready");
|
|
589
|
+
this.emit("task_complete");
|
|
590
|
+
this.logger.info({ sessionId: this.id }, "Task complete \u2014 agent returned to idle prompt");
|
|
591
|
+
}, _PTYSession.TASK_COMPLETE_DEBOUNCE_MS);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Cancel a pending task_complete timer (new output arrived that
|
|
595
|
+
* doesn't match the idle prompt, so the agent is still working).
|
|
596
|
+
*/
|
|
597
|
+
cancelTaskComplete() {
|
|
598
|
+
if (this._taskCompleteTimer) {
|
|
599
|
+
clearTimeout(this._taskCompleteTimer);
|
|
600
|
+
this._taskCompleteTimer = null;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
566
604
|
// Lifecycle
|
|
567
605
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
568
606
|
/**
|
|
@@ -624,10 +662,6 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
624
662
|
this.resetStallTimer();
|
|
625
663
|
}
|
|
626
664
|
this.emit("output", data);
|
|
627
|
-
const blockingPrompt = this.detectAndHandleBlockingPrompt();
|
|
628
|
-
if (blockingPrompt) {
|
|
629
|
-
return;
|
|
630
|
-
}
|
|
631
665
|
if ((this._status === "starting" || this._status === "authenticating") && this.adapter.detectReady(this.outputBuffer)) {
|
|
632
666
|
this._status = "ready";
|
|
633
667
|
this._lastBlockingPromptHash = null;
|
|
@@ -637,6 +671,15 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
637
671
|
this.logger.info({ sessionId: this.id }, "Session ready");
|
|
638
672
|
return;
|
|
639
673
|
}
|
|
674
|
+
if (this._status === "busy" && this.adapter.detectReady(this.outputBuffer)) {
|
|
675
|
+
this.scheduleTaskComplete();
|
|
676
|
+
} else {
|
|
677
|
+
this.cancelTaskComplete();
|
|
678
|
+
}
|
|
679
|
+
const blockingPrompt = this.detectAndHandleBlockingPrompt();
|
|
680
|
+
if (blockingPrompt) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
640
683
|
if (this._status !== "ready" && this._status !== "busy") {
|
|
641
684
|
const loginDetection = this.adapter.detectLogin(this.outputBuffer);
|
|
642
685
|
if (loginDetection.required && this._status !== "authenticating") {
|
|
@@ -859,6 +902,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
859
902
|
*/
|
|
860
903
|
send(message) {
|
|
861
904
|
this._status = "busy";
|
|
905
|
+
this.emit("status_changed", "busy");
|
|
862
906
|
this.resetStallTimer();
|
|
863
907
|
const msg = {
|
|
864
908
|
id: `${this.id}-msg-${++this.messageCounter}`,
|
|
@@ -969,6 +1013,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
969
1013
|
if (this.ptyProcess) {
|
|
970
1014
|
this._status = "stopping";
|
|
971
1015
|
this.clearStallTimer();
|
|
1016
|
+
this.cancelTaskComplete();
|
|
972
1017
|
this.ptyProcess.kill(signal);
|
|
973
1018
|
this.logger.info({ sessionId: this.id, signal }, "Killing PTY session");
|
|
974
1019
|
}
|
|
@@ -1122,6 +1167,12 @@ var PTYManager = class extends import_events2.EventEmitter {
|
|
|
1122
1167
|
session.on("error", (error) => {
|
|
1123
1168
|
this.emit("session_error", session.toHandle(), error.message);
|
|
1124
1169
|
});
|
|
1170
|
+
session.on("status_changed", () => {
|
|
1171
|
+
this.emit("session_status_changed", session.toHandle());
|
|
1172
|
+
});
|
|
1173
|
+
session.on("task_complete", () => {
|
|
1174
|
+
this.emit("task_complete", session.toHandle());
|
|
1175
|
+
});
|
|
1125
1176
|
session.on("stall_detected", (recentOutput, stallDurationMs) => {
|
|
1126
1177
|
const handle = session.toHandle();
|
|
1127
1178
|
this.emit("stall_detected", handle, recentOutput, stallDurationMs);
|
|
@@ -1512,6 +1563,19 @@ manager.on("question", (handle, question) => {
|
|
|
1512
1563
|
question
|
|
1513
1564
|
});
|
|
1514
1565
|
});
|
|
1566
|
+
manager.on("session_status_changed", (handle) => {
|
|
1567
|
+
emit({
|
|
1568
|
+
event: "status_changed",
|
|
1569
|
+
id: handle.id,
|
|
1570
|
+
status: handle.status
|
|
1571
|
+
});
|
|
1572
|
+
});
|
|
1573
|
+
manager.on("task_complete", (handle) => {
|
|
1574
|
+
emit({
|
|
1575
|
+
event: "task_complete",
|
|
1576
|
+
id: handle.id
|
|
1577
|
+
});
|
|
1578
|
+
});
|
|
1515
1579
|
manager.on("stall_detected", (handle, recentOutput, stallDurationMs) => {
|
|
1516
1580
|
emit({
|
|
1517
1581
|
event: "stall_detected",
|
package/package.json
CHANGED