pty-manager 1.5.0 → 1.6.1
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 +56 -5
- package/dist/index.d.mts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +50 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +50 -12
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +50 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@ PTY session manager with lifecycle management, pluggable adapters, and blocking
|
|
|
9
9
|
- **Blocking prompt detection** - Detect login prompts, confirmations, and interactive prompts
|
|
10
10
|
- **Auto-response rules** - Automatically respond to known prompts with text or key sequences
|
|
11
11
|
- **TUI menu navigation** - Navigate arrow-key menus via `selectMenuOption()` and key-sequence rules
|
|
12
|
-
- **Stall detection** - Content-based stall detection with pluggable external classifiers
|
|
13
|
-
- **Task completion detection** -
|
|
12
|
+
- **Stall detection** - Content-based stall detection with pluggable external classifiers, loading suppression, and exponential backoff
|
|
13
|
+
- **Task completion detection** - Settle-based fast-path that short-circuits the LLM stall classifier when the CLI returns to its idle prompt, resilient to decorative TUI rendering after the prompt
|
|
14
14
|
- **Terminal attachment** - Attach to sessions for raw I/O streaming
|
|
15
15
|
- **Special key support** - Send Ctrl, Alt, Shift, and function key combinations via `sendKeys()`
|
|
16
16
|
- **Bracketed paste** - Proper paste handling with bracketed paste mode support
|
|
@@ -136,6 +136,11 @@ class MyCLIAdapter extends BaseCLIAdapter {
|
|
|
136
136
|
return /done in \d+s/.test(output) && /ready>/.test(output);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
// Optional: detect active loading state (suppresses stall detection)
|
|
140
|
+
detectLoading(output) {
|
|
141
|
+
return /processing|loading/i.test(output);
|
|
142
|
+
}
|
|
143
|
+
|
|
139
144
|
parseOutput(output) {
|
|
140
145
|
return {
|
|
141
146
|
type: 'response',
|
|
@@ -210,6 +215,7 @@ interface SpawnConfig {
|
|
|
210
215
|
cols?: number; // Terminal columns (default: 120)
|
|
211
216
|
rows?: number; // Terminal rows (default: 40)
|
|
212
217
|
timeout?: number; // Session timeout in ms
|
|
218
|
+
readySettleMs?: number; // Override adapter's ready settle delay
|
|
213
219
|
}
|
|
214
220
|
```
|
|
215
221
|
|
|
@@ -457,13 +463,27 @@ class MyCLIAdapter extends BaseCLIAdapter {
|
|
|
457
463
|
}
|
|
458
464
|
```
|
|
459
465
|
|
|
466
|
+
The settle delay can also be overridden per-spawn via `SpawnConfig.readySettleMs`, which takes precedence over the adapter default. This lets orchestrators tune the delay for varying environments (CI, remote containers, local dev) without forking adapters:
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
const handle = await manager.spawn({
|
|
470
|
+
name: 'agent',
|
|
471
|
+
type: 'claude',
|
|
472
|
+
readySettleMs: 1000, // Slow CI environment — wait longer
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
460
476
|
## Stall Detection & Task Completion
|
|
461
477
|
|
|
462
|
-
Content-based stall detection monitors sessions for output that stops changing. The content hash strips the full buffer first, then slices the last 500 characters of the normalized text — this ensures identical visual content always produces the same hash regardless of how many raw escape sequences surround it. The normalization strips ANSI escape codes, TUI spinner characters, and countdown/duration text (e.g. `8m 17s` → constant) so that live timers and
|
|
478
|
+
Content-based stall detection monitors sessions for output that stops changing. The content hash strips the full buffer first, then slices the last 500 characters of the normalized text — this ensures identical visual content always produces the same hash regardless of how many raw escape sequences surround it. The normalization strips ANSI escape codes, carriage returns (`\r`), non-breaking spaces (`\xa0`), TUI spinner characters, and countdown/duration text (e.g. `8m 17s` → constant) so that live timers, TUI line-overwrites, and redraws don't perpetually reset the stall timer. All detection work (ready, blocking prompt, login, exit, stall) runs in a deferred `setImmediate()` tick so that node-pty's synchronous data delivery cannot starve the event loop — timers and I/O callbacks always get a chance to run between data bursts. The output buffer is capped at 100 KB to prevent unbounded growth during long tasks.
|
|
479
|
+
|
|
480
|
+
### Task Completion Fast-Path (Settle Pattern)
|
|
463
481
|
|
|
464
|
-
When a
|
|
482
|
+
When a busy session's output matches the adapter's `detectReady()` pattern, a `task_complete` debounce timer starts. TUI agents like Claude Code continue rendering decorative output after the prompt — update notices, shortcut hints, status bar updates. Instead of cancelling the timer on each new data chunk (which would prevent the event from ever firing), the session uses a **settle pattern**: the debounce timer resets on each new chunk but is never cancelled. The timer callback re-verifies `detectReady()` before transitioning, so stale triggers are safe.
|
|
465
483
|
|
|
466
|
-
|
|
484
|
+
This mirrors the `readySettlePending` pattern used for startup ready detection, and ensures the `task_complete` event fires reliably even when TUI chrome continues rendering after the agent has finished its task.
|
|
485
|
+
|
|
486
|
+
If the fast-path timer doesn't fire (e.g. the prompt indicator disappears from the buffer), the session falls back to stall detection which emits `stall_detected` for external classification.
|
|
467
487
|
|
|
468
488
|
```typescript
|
|
469
489
|
// Enable stall detection with a pluggable classifier
|
|
@@ -510,6 +530,37 @@ The default `BaseCLIAdapter` implementation delegates to `detectReady()`. Coding
|
|
|
510
530
|
| Codex | `Worked for 1m 05s` separator + `›` prompt |
|
|
511
531
|
| Aider | `Aider is waiting for your input`, mode prompts with edit markers |
|
|
512
532
|
|
|
533
|
+
### Loading Pattern Suppression
|
|
534
|
+
|
|
535
|
+
Adapters can implement `detectLoading(output)` to detect when the CLI is actively working — thinking spinners, file reading progress, model streaming indicators. When `detectLoading()` returns `true`, stall detection is suppressed entirely because the agent is provably working, just not producing new visible text.
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
class MyCLIAdapter extends BaseCLIAdapter {
|
|
539
|
+
detectLoading(output: string): boolean {
|
|
540
|
+
// Match loading indicators specific to this CLI
|
|
541
|
+
return /esc to interrupt/i.test(output) || /Reading \d+ files/i.test(output);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
This avoids unnecessary LLM classifier calls during normal operation and prevents false stall alerts when agents are thinking or reading files.
|
|
547
|
+
|
|
548
|
+
### Stall Backoff
|
|
549
|
+
|
|
550
|
+
When the external stall classifier returns `still_working` (or `null`), the next stall check interval doubles exponentially instead of repeating at the base rate. This prevents hammering the classifier every few seconds during long-running tasks.
|
|
551
|
+
|
|
552
|
+
- Base interval: `stallTimeoutMs` (default: 8000ms)
|
|
553
|
+
- After each `still_working`: interval doubles (8s → 16s → 30s cap)
|
|
554
|
+
- Maximum interval: 30 seconds
|
|
555
|
+
- Reset: backoff resets to the base interval whenever new real content arrives (content hash changes)
|
|
556
|
+
|
|
557
|
+
```
|
|
558
|
+
First stall check: 8s → classifier says "still_working"
|
|
559
|
+
Second check: 16s → classifier says "still_working"
|
|
560
|
+
Third check: 30s → (capped at 30s)
|
|
561
|
+
New output arrives: → backoff resets to 8s
|
|
562
|
+
```
|
|
563
|
+
|
|
513
564
|
## Blocking Prompt Types
|
|
514
565
|
|
|
515
566
|
The library recognizes these blocking prompt types:
|
package/dist/index.d.mts
CHANGED
|
@@ -37,6 +37,9 @@ interface SpawnConfig {
|
|
|
37
37
|
adapterConfig?: Record<string, unknown>;
|
|
38
38
|
/** Per-session stall timeout in ms. Overrides PTYManagerConfig.stallTimeoutMs. */
|
|
39
39
|
stallTimeoutMs?: number;
|
|
40
|
+
/** Override adapter's readySettleMs for this session.
|
|
41
|
+
* Ms of output silence after detectReady match before emitting session_ready. */
|
|
42
|
+
readySettleMs?: number;
|
|
40
43
|
/** Override or disable specific adapter auto-response rules for this session.
|
|
41
44
|
* Keys are regex source strings (from rule.pattern.source).
|
|
42
45
|
* - null value disables that rule entirely
|
|
@@ -353,6 +356,15 @@ interface CLIAdapter {
|
|
|
353
356
|
}>;
|
|
354
357
|
/** Ms of output silence after detectReady match before emitting session_ready (default: 100) */
|
|
355
358
|
readonly readySettleMs?: number;
|
|
359
|
+
/**
|
|
360
|
+
* Optional: Detect if the CLI is actively loading/processing (thinking spinner,
|
|
361
|
+
* file reading, model streaming, etc.). When true, stall detection is suppressed
|
|
362
|
+
* because the agent is provably working — just not producing new visible text.
|
|
363
|
+
*
|
|
364
|
+
* Patterns should match active loading indicators like "esc to interrupt",
|
|
365
|
+
* "Reading N files", "Waiting for LLM", etc.
|
|
366
|
+
*/
|
|
367
|
+
detectLoading?(output: string): boolean;
|
|
356
368
|
/**
|
|
357
369
|
* Optional: Get health check command
|
|
358
370
|
*/
|
|
@@ -446,7 +458,10 @@ declare class PTYSession extends EventEmitter {
|
|
|
446
458
|
private _lastStallHash;
|
|
447
459
|
private _stallStartedAt;
|
|
448
460
|
private _lastContentHash;
|
|
461
|
+
private _stallBackoffMs;
|
|
462
|
+
private static readonly MAX_STALL_BACKOFF_MS;
|
|
449
463
|
private _taskCompleteTimer;
|
|
464
|
+
private _taskCompletePending;
|
|
450
465
|
private static readonly TASK_COMPLETE_DEBOUNCE_MS;
|
|
451
466
|
private _readySettleTimer;
|
|
452
467
|
private _readySettlePending;
|
|
@@ -522,8 +537,12 @@ declare class PTYSession extends EventEmitter {
|
|
|
522
537
|
handleStallClassification(classification: StallClassification | null): void;
|
|
523
538
|
/**
|
|
524
539
|
* Schedule a task_complete transition after a debounce period.
|
|
525
|
-
*
|
|
526
|
-
*
|
|
540
|
+
* Uses a settle pattern: each call resets the debounce timer instead of
|
|
541
|
+
* being a no-op when already scheduled. This allows TUI agents that
|
|
542
|
+
* continue rendering decorative output (status bar, update notices) after
|
|
543
|
+
* the prompt to eventually settle, rather than having the timer cancelled
|
|
544
|
+
* by every new data chunk. The callback re-verifies detectReady() before
|
|
545
|
+
* transitioning, so stale triggers are safe.
|
|
527
546
|
*/
|
|
528
547
|
private scheduleTaskComplete;
|
|
529
548
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,9 @@ interface SpawnConfig {
|
|
|
37
37
|
adapterConfig?: Record<string, unknown>;
|
|
38
38
|
/** Per-session stall timeout in ms. Overrides PTYManagerConfig.stallTimeoutMs. */
|
|
39
39
|
stallTimeoutMs?: number;
|
|
40
|
+
/** Override adapter's readySettleMs for this session.
|
|
41
|
+
* Ms of output silence after detectReady match before emitting session_ready. */
|
|
42
|
+
readySettleMs?: number;
|
|
40
43
|
/** Override or disable specific adapter auto-response rules for this session.
|
|
41
44
|
* Keys are regex source strings (from rule.pattern.source).
|
|
42
45
|
* - null value disables that rule entirely
|
|
@@ -353,6 +356,15 @@ interface CLIAdapter {
|
|
|
353
356
|
}>;
|
|
354
357
|
/** Ms of output silence after detectReady match before emitting session_ready (default: 100) */
|
|
355
358
|
readonly readySettleMs?: number;
|
|
359
|
+
/**
|
|
360
|
+
* Optional: Detect if the CLI is actively loading/processing (thinking spinner,
|
|
361
|
+
* file reading, model streaming, etc.). When true, stall detection is suppressed
|
|
362
|
+
* because the agent is provably working — just not producing new visible text.
|
|
363
|
+
*
|
|
364
|
+
* Patterns should match active loading indicators like "esc to interrupt",
|
|
365
|
+
* "Reading N files", "Waiting for LLM", etc.
|
|
366
|
+
*/
|
|
367
|
+
detectLoading?(output: string): boolean;
|
|
356
368
|
/**
|
|
357
369
|
* Optional: Get health check command
|
|
358
370
|
*/
|
|
@@ -446,7 +458,10 @@ declare class PTYSession extends EventEmitter {
|
|
|
446
458
|
private _lastStallHash;
|
|
447
459
|
private _stallStartedAt;
|
|
448
460
|
private _lastContentHash;
|
|
461
|
+
private _stallBackoffMs;
|
|
462
|
+
private static readonly MAX_STALL_BACKOFF_MS;
|
|
449
463
|
private _taskCompleteTimer;
|
|
464
|
+
private _taskCompletePending;
|
|
450
465
|
private static readonly TASK_COMPLETE_DEBOUNCE_MS;
|
|
451
466
|
private _readySettleTimer;
|
|
452
467
|
private _readySettlePending;
|
|
@@ -522,8 +537,12 @@ declare class PTYSession extends EventEmitter {
|
|
|
522
537
|
handleStallClassification(classification: StallClassification | null): void;
|
|
523
538
|
/**
|
|
524
539
|
* Schedule a task_complete transition after a debounce period.
|
|
525
|
-
*
|
|
526
|
-
*
|
|
540
|
+
* Uses a settle pattern: each call resets the debounce timer instead of
|
|
541
|
+
* being a no-op when already scheduled. This allows TUI agents that
|
|
542
|
+
* continue rendering decorative output (status bar, update notices) after
|
|
543
|
+
* the prompt to eventually settle, rather than having the timer cancelled
|
|
544
|
+
* by every new data chunk. The callback re-verifies detectReady() before
|
|
545
|
+
* transitioning, so stale triggers are safe.
|
|
527
546
|
*/
|
|
528
547
|
private scheduleTaskComplete;
|
|
529
548
|
/**
|
package/dist/index.js
CHANGED
|
@@ -315,6 +315,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
315
315
|
this.logger = logger || consoleLogger;
|
|
316
316
|
this._stallDetectionEnabled = stallDetectionEnabled ?? false;
|
|
317
317
|
this._stallTimeoutMs = config.stallTimeoutMs ?? defaultStallTimeoutMs ?? 8e3;
|
|
318
|
+
this._stallBackoffMs = this._stallTimeoutMs;
|
|
318
319
|
if (config.ruleOverrides) {
|
|
319
320
|
for (const [key, value] of Object.entries(config.ruleOverrides)) {
|
|
320
321
|
if (value === null) {
|
|
@@ -344,8 +345,12 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
344
345
|
_lastStallHash = null;
|
|
345
346
|
_stallStartedAt = null;
|
|
346
347
|
_lastContentHash = null;
|
|
348
|
+
_stallBackoffMs = 0;
|
|
349
|
+
// Initialized in constructor from _stallTimeoutMs
|
|
350
|
+
static MAX_STALL_BACKOFF_MS = 3e4;
|
|
347
351
|
// Task completion detection (idle detection when busy)
|
|
348
352
|
_taskCompleteTimer = null;
|
|
353
|
+
_taskCompletePending = false;
|
|
349
354
|
static TASK_COMPLETE_DEBOUNCE_MS = 1500;
|
|
350
355
|
// Ready detection settle delay — defers session_ready until output goes quiet
|
|
351
356
|
_readySettleTimer = null;
|
|
@@ -466,6 +471,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
466
471
|
}
|
|
467
472
|
this._stallStartedAt = Date.now();
|
|
468
473
|
this._lastStallHash = null;
|
|
474
|
+
this._stallBackoffMs = this._stallTimeoutMs;
|
|
469
475
|
this._stallTimer = setTimeout(() => {
|
|
470
476
|
this.onStallTimerFired();
|
|
471
477
|
}, this._stallTimeoutMs);
|
|
@@ -480,6 +486,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
480
486
|
}
|
|
481
487
|
this._stallStartedAt = null;
|
|
482
488
|
this._lastContentHash = null;
|
|
489
|
+
this._stallBackoffMs = this._stallTimeoutMs;
|
|
483
490
|
}
|
|
484
491
|
/**
|
|
485
492
|
* Called when the stall timer fires (no output for stallTimeoutMs).
|
|
@@ -488,10 +495,18 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
488
495
|
if (this._status !== "busy" && this._status !== "authenticating") {
|
|
489
496
|
return;
|
|
490
497
|
}
|
|
498
|
+
if (this.adapter.detectLoading?.(this.outputBuffer)) {
|
|
499
|
+
this.logger.debug(
|
|
500
|
+
{ sessionId: this.id },
|
|
501
|
+
"Loading pattern detected \u2014 suppressing stall emission"
|
|
502
|
+
);
|
|
503
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
491
506
|
const tail = this.outputBuffer.slice(-500);
|
|
492
507
|
const hash = this.simpleHash(tail);
|
|
493
508
|
if (hash === this._lastStallHash) {
|
|
494
|
-
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this.
|
|
509
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
495
510
|
return;
|
|
496
511
|
}
|
|
497
512
|
this._lastStallHash = hash;
|
|
@@ -516,7 +531,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
516
531
|
"Stall detected"
|
|
517
532
|
);
|
|
518
533
|
this.emit("stall_detected", recentOutput, stallDurationMs);
|
|
519
|
-
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this.
|
|
534
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
520
535
|
}
|
|
521
536
|
/**
|
|
522
537
|
* Promise-based delay helper.
|
|
@@ -548,7 +563,8 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
548
563
|
result = result.replace(/\x1b\[\d*(?:;\d+)?[Hf]/g, " ");
|
|
549
564
|
result = result.replace(/\x1b\[\d*[JK]/g, " ");
|
|
550
565
|
result = result.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
551
|
-
result = result.replace(/[\x00-\x08\x0b
|
|
566
|
+
result = result.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
|
|
567
|
+
result = result.replace(/\xa0/g, " ");
|
|
552
568
|
result = result.replace(/[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥]/g, " ");
|
|
553
569
|
result = result.replace(/\d+[hms](?:\s+\d+[hms])*/g, "0s");
|
|
554
570
|
result = result.replace(/ {2,}/g, " ");
|
|
@@ -563,8 +579,21 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
563
579
|
return;
|
|
564
580
|
}
|
|
565
581
|
if (!classification || classification.state === "still_working") {
|
|
582
|
+
this._stallBackoffMs = Math.min(
|
|
583
|
+
this._stallBackoffMs * 2,
|
|
584
|
+
_PTYSession.MAX_STALL_BACKOFF_MS
|
|
585
|
+
);
|
|
586
|
+
this.logger.debug(
|
|
587
|
+
{ sessionId: this.id, nextCheckMs: this._stallBackoffMs },
|
|
588
|
+
"Still working \u2014 backing off stall check interval"
|
|
589
|
+
);
|
|
566
590
|
this._lastContentHash = null;
|
|
567
|
-
this.
|
|
591
|
+
this._lastStallHash = null;
|
|
592
|
+
if (this._stallTimer) {
|
|
593
|
+
clearTimeout(this._stallTimer);
|
|
594
|
+
this._stallTimer = null;
|
|
595
|
+
}
|
|
596
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
568
597
|
return;
|
|
569
598
|
}
|
|
570
599
|
switch (classification.state) {
|
|
@@ -612,13 +641,21 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
612
641
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
613
642
|
/**
|
|
614
643
|
* Schedule a task_complete transition after a debounce period.
|
|
615
|
-
*
|
|
616
|
-
*
|
|
644
|
+
* Uses a settle pattern: each call resets the debounce timer instead of
|
|
645
|
+
* being a no-op when already scheduled. This allows TUI agents that
|
|
646
|
+
* continue rendering decorative output (status bar, update notices) after
|
|
647
|
+
* the prompt to eventually settle, rather than having the timer cancelled
|
|
648
|
+
* by every new data chunk. The callback re-verifies detectReady() before
|
|
649
|
+
* transitioning, so stale triggers are safe.
|
|
617
650
|
*/
|
|
618
651
|
scheduleTaskComplete() {
|
|
619
|
-
if (this._taskCompleteTimer)
|
|
652
|
+
if (this._taskCompleteTimer) {
|
|
653
|
+
clearTimeout(this._taskCompleteTimer);
|
|
654
|
+
}
|
|
655
|
+
this._taskCompletePending = true;
|
|
620
656
|
this._taskCompleteTimer = setTimeout(() => {
|
|
621
657
|
this._taskCompleteTimer = null;
|
|
658
|
+
this._taskCompletePending = false;
|
|
622
659
|
if (this._status !== "busy") return;
|
|
623
660
|
if (!this.adapter.detectReady(this.outputBuffer)) return;
|
|
624
661
|
this._status = "ready";
|
|
@@ -639,6 +676,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
639
676
|
clearTimeout(this._taskCompleteTimer);
|
|
640
677
|
this._taskCompleteTimer = null;
|
|
641
678
|
}
|
|
679
|
+
this._taskCompletePending = false;
|
|
642
680
|
}
|
|
643
681
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
644
682
|
// Ready Detection Settle Delay
|
|
@@ -654,7 +692,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
654
692
|
if (this._readySettleTimer) {
|
|
655
693
|
clearTimeout(this._readySettleTimer);
|
|
656
694
|
}
|
|
657
|
-
const settleMs = this.adapter.readySettleMs ?? 100;
|
|
695
|
+
const settleMs = this.config.readySettleMs ?? this.adapter.readySettleMs ?? 100;
|
|
658
696
|
this._readySettleTimer = setTimeout(() => {
|
|
659
697
|
this._readySettleTimer = null;
|
|
660
698
|
this._readySettlePending = false;
|
|
@@ -780,10 +818,10 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
780
818
|
this.scheduleReadySettle();
|
|
781
819
|
return;
|
|
782
820
|
}
|
|
783
|
-
if (this._status === "busy"
|
|
784
|
-
this.
|
|
785
|
-
|
|
786
|
-
|
|
821
|
+
if (this._status === "busy") {
|
|
822
|
+
if (this._taskCompletePending || this.adapter.detectReady(this.outputBuffer)) {
|
|
823
|
+
this.scheduleTaskComplete();
|
|
824
|
+
}
|
|
787
825
|
}
|
|
788
826
|
const blockingPrompt = this.detectAndHandleBlockingPrompt();
|
|
789
827
|
if (blockingPrompt) {
|