pty-manager 1.6.2 → 1.6.4
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 +51 -1
- package/dist/index.d.mts +78 -3
- package/dist/index.d.ts +78 -3
- package/dist/index.js +254 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +252 -6
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +82 -5
- package/package.json +1 -1
package/dist/pty-worker.js
CHANGED
|
@@ -331,6 +331,8 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
331
331
|
_stallBackoffMs = 0;
|
|
332
332
|
// Initialized in constructor from _stallTimeoutMs
|
|
333
333
|
static MAX_STALL_BACKOFF_MS = 3e4;
|
|
334
|
+
_stallEmissionCount = 0;
|
|
335
|
+
static MAX_STALL_EMISSIONS = 5;
|
|
334
336
|
// Task completion detection (idle detection when busy)
|
|
335
337
|
_taskCompleteTimer = null;
|
|
336
338
|
_taskCompletePending = false;
|
|
@@ -448,6 +450,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
448
450
|
return;
|
|
449
451
|
}
|
|
450
452
|
this._lastContentHash = hash;
|
|
453
|
+
this._stallEmissionCount = 0;
|
|
451
454
|
if (this._stallTimer) {
|
|
452
455
|
clearTimeout(this._stallTimer);
|
|
453
456
|
this._stallTimer = null;
|
|
@@ -470,6 +473,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
470
473
|
this._stallStartedAt = null;
|
|
471
474
|
this._lastContentHash = null;
|
|
472
475
|
this._stallBackoffMs = this._stallTimeoutMs;
|
|
476
|
+
this._stallEmissionCount = 0;
|
|
473
477
|
}
|
|
474
478
|
/**
|
|
475
479
|
* Called when the stall timer fires (no output for stallTimeoutMs).
|
|
@@ -506,6 +510,15 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
506
510
|
);
|
|
507
511
|
return;
|
|
508
512
|
}
|
|
513
|
+
this._stallEmissionCount++;
|
|
514
|
+
if (this._stallEmissionCount > _PTYSession.MAX_STALL_EMISSIONS) {
|
|
515
|
+
this.logger.warn(
|
|
516
|
+
{ sessionId: this.id, count: this._stallEmissionCount },
|
|
517
|
+
"Max stall emissions reached \u2014 suspending stall detection for this task"
|
|
518
|
+
);
|
|
519
|
+
this.clearStallTimer();
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
509
522
|
const recentRaw = this.outputBuffer.slice(-2e3);
|
|
510
523
|
const recentOutput = this.stripAnsiForStall(recentRaw);
|
|
511
524
|
const stallDurationMs = this._stallStartedAt ? Date.now() - this._stallStartedAt : this._stallTimeoutMs;
|
|
@@ -545,6 +558,8 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
545
558
|
let result = str.replace(/\x1b\[\d*[CDABGdEF]/g, " ");
|
|
546
559
|
result = result.replace(/\x1b\[\d*(?:;\d+)?[Hf]/g, " ");
|
|
547
560
|
result = result.replace(/\x1b\[\d*[JK]/g, " ");
|
|
561
|
+
result = result.replace(/\x1b\](?:[^\x07\x1b]|\x1b[^\\])*(?:\x07|\x1b\\)/g, "");
|
|
562
|
+
result = result.replace(/\x1bP(?:[^\x1b]|\x1b[^\\])*\x1b\\/g, "");
|
|
548
563
|
result = result.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
549
564
|
result = result.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
|
|
550
565
|
result = result.replace(/\xa0/g, " ");
|
|
@@ -628,10 +643,15 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
628
643
|
* being a no-op when already scheduled. This allows TUI agents that
|
|
629
644
|
* continue rendering decorative output (status bar, update notices) after
|
|
630
645
|
* the prompt to eventually settle, rather than having the timer cancelled
|
|
631
|
-
* by every new data chunk. The callback re-verifies
|
|
632
|
-
* transitioning, so stale triggers are safe.
|
|
646
|
+
* by every new data chunk. The callback re-verifies the task-complete
|
|
647
|
+
* signal before transitioning, so stale triggers are safe.
|
|
633
648
|
*/
|
|
634
649
|
scheduleTaskComplete() {
|
|
650
|
+
const wasPending = this._taskCompletePending;
|
|
651
|
+
this.traceTaskCompletion("debounce_schedule", {
|
|
652
|
+
wasPending,
|
|
653
|
+
debounceMs: _PTYSession.TASK_COMPLETE_DEBOUNCE_MS
|
|
654
|
+
});
|
|
635
655
|
if (this._taskCompleteTimer) {
|
|
636
656
|
clearTimeout(this._taskCompleteTimer);
|
|
637
657
|
}
|
|
@@ -639,17 +659,72 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
639
659
|
this._taskCompleteTimer = setTimeout(() => {
|
|
640
660
|
this._taskCompleteTimer = null;
|
|
641
661
|
this._taskCompletePending = false;
|
|
642
|
-
|
|
643
|
-
|
|
662
|
+
const signal = this.isTaskCompleteSignal(this.outputBuffer);
|
|
663
|
+
this.traceTaskCompletion("debounce_fire", { signal });
|
|
664
|
+
if (this._status !== "busy") {
|
|
665
|
+
this.traceTaskCompletion("debounce_reject_status", { signal });
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
if (!signal) {
|
|
669
|
+
this.traceTaskCompletion("debounce_reject_signal", { signal });
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
644
672
|
this._status = "ready";
|
|
645
673
|
this._lastBlockingPromptHash = null;
|
|
646
674
|
this.outputBuffer = "";
|
|
647
675
|
this.clearStallTimer();
|
|
648
676
|
this.emit("status_changed", "ready");
|
|
649
677
|
this.emit("task_complete");
|
|
678
|
+
this.traceTaskCompletion("transition_ready", { signal: true });
|
|
650
679
|
this.logger.info({ sessionId: this.id }, "Task complete \u2014 agent returned to idle prompt");
|
|
651
680
|
}, _PTYSession.TASK_COMPLETE_DEBOUNCE_MS);
|
|
652
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Adapter-level task completion check with compatibility fallback.
|
|
684
|
+
* Prefer detectTaskComplete() because detectReady() may be broad for TUIs.
|
|
685
|
+
*/
|
|
686
|
+
isTaskCompleteSignal(output) {
|
|
687
|
+
if (this.adapter.detectTaskComplete) {
|
|
688
|
+
return this.adapter.detectTaskComplete(output);
|
|
689
|
+
}
|
|
690
|
+
return this.adapter.detectReady(output);
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Claude-oriented task completion traces for PTY debugging.
|
|
694
|
+
* Enabled by config.traceTaskCompletion, otherwise defaults to enabled for Claude.
|
|
695
|
+
*/
|
|
696
|
+
traceTaskCompletion(event, ctx = {}) {
|
|
697
|
+
if (!this.shouldTraceTaskCompletion()) return;
|
|
698
|
+
const output = this.outputBuffer;
|
|
699
|
+
const detectTaskComplete = this.adapter.detectTaskComplete ? this.adapter.detectTaskComplete(output) : void 0;
|
|
700
|
+
const detectReady = this.adapter.detectReady(output);
|
|
701
|
+
const detectLoading = this.adapter.detectLoading ? this.adapter.detectLoading(output) : void 0;
|
|
702
|
+
const normalizedTail = this.stripAnsiForStall(output.slice(-280));
|
|
703
|
+
this.logger.debug(
|
|
704
|
+
{
|
|
705
|
+
sessionId: this.id,
|
|
706
|
+
adapterType: this.adapter.adapterType,
|
|
707
|
+
event,
|
|
708
|
+
status: this._status,
|
|
709
|
+
taskCompletePending: this._taskCompletePending,
|
|
710
|
+
signal: ctx.signal,
|
|
711
|
+
wasPending: ctx.wasPending,
|
|
712
|
+
debounceMs: ctx.debounceMs,
|
|
713
|
+
detectTaskComplete,
|
|
714
|
+
detectReady,
|
|
715
|
+
detectLoading,
|
|
716
|
+
tailHash: this.simpleHash(normalizedTail),
|
|
717
|
+
tailSnippet: normalizedTail.slice(-140)
|
|
718
|
+
},
|
|
719
|
+
"Task completion trace"
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
shouldTraceTaskCompletion() {
|
|
723
|
+
if (typeof this.config.traceTaskCompletion === "boolean") {
|
|
724
|
+
return this.config.traceTaskCompletion;
|
|
725
|
+
}
|
|
726
|
+
return this.adapter.adapterType === "claude";
|
|
727
|
+
}
|
|
653
728
|
/**
|
|
654
729
|
* Cancel a pending task_complete timer (new output arrived that
|
|
655
730
|
* doesn't match the idle prompt, so the agent is still working).
|
|
@@ -802,7 +877,9 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
802
877
|
return;
|
|
803
878
|
}
|
|
804
879
|
if (this._status === "busy") {
|
|
805
|
-
|
|
880
|
+
const signal = this.isTaskCompleteSignal(this.outputBuffer);
|
|
881
|
+
if (this._taskCompletePending || signal) {
|
|
882
|
+
this.traceTaskCompletion("busy_signal", { signal });
|
|
806
883
|
this.scheduleTaskComplete();
|
|
807
884
|
}
|
|
808
885
|
}
|
package/package.json
CHANGED