pty-manager 1.2.20 → 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 +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +93 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +93 -8
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +88 -8
- 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;
|
|
@@ -298,6 +298,15 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
298
298
|
this.logger = logger || consoleLogger;
|
|
299
299
|
this._stallDetectionEnabled = stallDetectionEnabled ?? false;
|
|
300
300
|
this._stallTimeoutMs = config.stallTimeoutMs ?? defaultStallTimeoutMs ?? 8e3;
|
|
301
|
+
if (config.ruleOverrides) {
|
|
302
|
+
for (const [key, value] of Object.entries(config.ruleOverrides)) {
|
|
303
|
+
if (value === null) {
|
|
304
|
+
this._disabledRulePatterns.add(key);
|
|
305
|
+
} else {
|
|
306
|
+
this._ruleOverrides.set(key, value);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
301
310
|
}
|
|
302
311
|
ptyProcess = null;
|
|
303
312
|
outputBuffer = "";
|
|
@@ -309,6 +318,8 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
309
318
|
sessionRules = [];
|
|
310
319
|
_firedOnceRules = /* @__PURE__ */ new Set();
|
|
311
320
|
_lastBlockingPromptHash = null;
|
|
321
|
+
_ruleOverrides = /* @__PURE__ */ new Map();
|
|
322
|
+
_disabledRulePatterns = /* @__PURE__ */ new Set();
|
|
312
323
|
// Stall detection
|
|
313
324
|
_stallTimer = null;
|
|
314
325
|
_stallTimeoutMs;
|
|
@@ -316,6 +327,9 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
316
327
|
_lastStallHash = null;
|
|
317
328
|
_stallStartedAt = null;
|
|
318
329
|
_lastContentHash = null;
|
|
330
|
+
// Task completion detection (idle detection when busy)
|
|
331
|
+
_taskCompleteTimer = null;
|
|
332
|
+
static TASK_COMPLETE_DEBOUNCE_MS = 1500;
|
|
319
333
|
id;
|
|
320
334
|
config;
|
|
321
335
|
get status() {
|
|
@@ -491,10 +505,12 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
491
505
|
* word boundaries — e.g. "Do\x1b[5Cyou" becomes "Do you", not "Doyou".
|
|
492
506
|
*/
|
|
493
507
|
stripAnsiForStall(str) {
|
|
494
|
-
let result = str.replace(/\x1b\[\d*[
|
|
508
|
+
let result = str.replace(/\x1b\[\d*[CDABGdEF]/g, " ");
|
|
495
509
|
result = result.replace(/\x1b\[\d*(?:;\d+)?[Hf]/g, " ");
|
|
510
|
+
result = result.replace(/\x1b\[\d*[JK]/g, " ");
|
|
496
511
|
result = result.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
497
|
-
result = result.replace(/[
|
|
512
|
+
result = result.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
513
|
+
result = result.replace(/[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥]/g, " ");
|
|
498
514
|
result = result.replace(/ {2,}/g, " ");
|
|
499
515
|
return result;
|
|
500
516
|
}
|
|
@@ -531,6 +547,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
531
547
|
this.writeRaw(resp + "\r");
|
|
532
548
|
}
|
|
533
549
|
this.emit("blocking_prompt", promptInfo, true);
|
|
550
|
+
this.outputBuffer = "";
|
|
534
551
|
} else {
|
|
535
552
|
this.emit("blocking_prompt", promptInfo, false);
|
|
536
553
|
}
|
|
@@ -551,6 +568,39 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
551
568
|
}
|
|
552
569
|
}
|
|
553
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
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
554
604
|
// Lifecycle
|
|
555
605
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
556
606
|
/**
|
|
@@ -612,10 +662,6 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
612
662
|
this.resetStallTimer();
|
|
613
663
|
}
|
|
614
664
|
this.emit("output", data);
|
|
615
|
-
const blockingPrompt = this.detectAndHandleBlockingPrompt();
|
|
616
|
-
if (blockingPrompt) {
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
665
|
if ((this._status === "starting" || this._status === "authenticating") && this.adapter.detectReady(this.outputBuffer)) {
|
|
620
666
|
this._status = "ready";
|
|
621
667
|
this._lastBlockingPromptHash = null;
|
|
@@ -625,6 +671,15 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
625
671
|
this.logger.info({ sessionId: this.id }, "Session ready");
|
|
626
672
|
return;
|
|
627
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
|
+
}
|
|
628
683
|
if (this._status !== "ready" && this._status !== "busy") {
|
|
629
684
|
const loginDetection = this.adapter.detectLogin(this.outputBuffer);
|
|
630
685
|
if (loginDetection.required && this._status !== "authenticating") {
|
|
@@ -700,6 +755,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
700
755
|
this.writeRaw(resp + "\r");
|
|
701
756
|
}
|
|
702
757
|
this._lastBlockingPromptHash = null;
|
|
758
|
+
this.outputBuffer = "";
|
|
703
759
|
this.emit("blocking_prompt", promptInfo, true);
|
|
704
760
|
return true;
|
|
705
761
|
}
|
|
@@ -727,7 +783,10 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
727
783
|
* Session rules are checked first, then adapter rules.
|
|
728
784
|
*/
|
|
729
785
|
tryAutoResponse() {
|
|
730
|
-
const adapterRules = this.adapter.autoResponseRules || []
|
|
786
|
+
const adapterRules = (this.adapter.autoResponseRules || []).filter((r) => !this._disabledRulePatterns.has(r.pattern.source)).map((r) => {
|
|
787
|
+
const override = this._ruleOverrides.get(r.pattern.source);
|
|
788
|
+
return override ? { ...r, ...override } : r;
|
|
789
|
+
});
|
|
731
790
|
const allRules = [...this.sessionRules, ...adapterRules];
|
|
732
791
|
if (allRules.length === 0) {
|
|
733
792
|
return false;
|
|
@@ -843,6 +902,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
843
902
|
*/
|
|
844
903
|
send(message) {
|
|
845
904
|
this._status = "busy";
|
|
905
|
+
this.emit("status_changed", "busy");
|
|
846
906
|
this.resetStallTimer();
|
|
847
907
|
const msg = {
|
|
848
908
|
id: `${this.id}-msg-${++this.messageCounter}`,
|
|
@@ -953,6 +1013,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
953
1013
|
if (this.ptyProcess) {
|
|
954
1014
|
this._status = "stopping";
|
|
955
1015
|
this.clearStallTimer();
|
|
1016
|
+
this.cancelTaskComplete();
|
|
956
1017
|
this.ptyProcess.kill(signal);
|
|
957
1018
|
this.logger.info({ sessionId: this.id, signal }, "Killing PTY session");
|
|
958
1019
|
}
|
|
@@ -1106,6 +1167,12 @@ var PTYManager = class extends import_events2.EventEmitter {
|
|
|
1106
1167
|
session.on("error", (error) => {
|
|
1107
1168
|
this.emit("session_error", session.toHandle(), error.message);
|
|
1108
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
|
+
});
|
|
1109
1176
|
session.on("stall_detected", (recentOutput, stallDurationMs) => {
|
|
1110
1177
|
const handle = session.toHandle();
|
|
1111
1178
|
this.emit("stall_detected", handle, recentOutput, stallDurationMs);
|
|
@@ -1496,6 +1563,19 @@ manager.on("question", (handle, question) => {
|
|
|
1496
1563
|
question
|
|
1497
1564
|
});
|
|
1498
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
|
+
});
|
|
1499
1579
|
manager.on("stall_detected", (handle, recentOutput, stallDurationMs) => {
|
|
1500
1580
|
emit({
|
|
1501
1581
|
event: "stall_detected",
|
package/package.json
CHANGED