pty-manager 1.4.0 → 1.6.0
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 +63 -2
- package/dist/index.d.mts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +82 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +82 -9
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +82 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ 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
|
|
12
|
+
- **Stall detection** - Content-based stall detection with pluggable external classifiers, loading suppression, and exponential backoff
|
|
13
13
|
- **Task completion detection** - Adapter-level fast-path that short-circuits the LLM stall classifier when the CLI returns to its idle 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()`
|
|
@@ -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',
|
|
@@ -188,7 +193,7 @@ class PTYManager extends EventEmitter {
|
|
|
188
193
|
| Event | Payload | Description |
|
|
189
194
|
|-------|---------|-------------|
|
|
190
195
|
| `session_started` | `SessionHandle` | Session spawn initiated |
|
|
191
|
-
| `session_ready` | `SessionHandle` | Session ready for input |
|
|
196
|
+
| `session_ready` | `SessionHandle` | Session ready for input (after settle delay) |
|
|
192
197
|
| `session_stopped` | `SessionHandle, reason` | Session terminated |
|
|
193
198
|
| `session_error` | `SessionHandle, error` | Error occurred |
|
|
194
199
|
| `login_required` | `SessionHandle, instructions?, url?` | Auth required |
|
|
@@ -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
|
|
|
@@ -443,6 +449,30 @@ Adapters can declare `usesTuiMenus: true` to indicate they use arrow-key menus i
|
|
|
443
449
|
await session.selectMenuOption(2); // Sends Down, Down, Enter with 50ms delays
|
|
444
450
|
```
|
|
445
451
|
|
|
452
|
+
## Ready Detection Settle Delay
|
|
453
|
+
|
|
454
|
+
When an adapter's `detectReady()` first matches during startup, `session_ready` is **not** emitted immediately. Instead, the session waits for output to go quiet for `readySettleMs` (default: 100ms) before firing the event. This prevents the orchestrator from sending input while a TUI agent is still rendering (status bar, keyboard shortcuts, update notices).
|
|
455
|
+
|
|
456
|
+
Adapters can override `readySettleMs` to tune the delay for their CLI's rendering speed. If new output arrives during the settle window, the timer resets. If the ready indicator disappears (e.g. a blocking prompt appears), the settle is cancelled.
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
class MyCLIAdapter extends BaseCLIAdapter {
|
|
460
|
+
// Heavy TUI rendering — wait longer before declaring ready
|
|
461
|
+
readonly readySettleMs = 500;
|
|
462
|
+
// ...
|
|
463
|
+
}
|
|
464
|
+
```
|
|
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
|
+
|
|
446
476
|
## Stall Detection & Task Completion
|
|
447
477
|
|
|
448
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, TUI spinner characters, and countdown/duration text (e.g. `8m 17s` → constant) so that live timers and TUI 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.
|
|
@@ -496,6 +526,37 @@ The default `BaseCLIAdapter` implementation delegates to `detectReady()`. Coding
|
|
|
496
526
|
| Codex | `Worked for 1m 05s` separator + `›` prompt |
|
|
497
527
|
| Aider | `Aider is waiting for your input`, mode prompts with edit markers |
|
|
498
528
|
|
|
529
|
+
### Loading Pattern Suppression
|
|
530
|
+
|
|
531
|
+
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.
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
class MyCLIAdapter extends BaseCLIAdapter {
|
|
535
|
+
detectLoading(output: string): boolean {
|
|
536
|
+
// Match loading indicators specific to this CLI
|
|
537
|
+
return /esc to interrupt/i.test(output) || /Reading \d+ files/i.test(output);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
This avoids unnecessary LLM classifier calls during normal operation and prevents false stall alerts when agents are thinking or reading files.
|
|
543
|
+
|
|
544
|
+
### Stall Backoff
|
|
545
|
+
|
|
546
|
+
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.
|
|
547
|
+
|
|
548
|
+
- Base interval: `stallTimeoutMs` (default: 8000ms)
|
|
549
|
+
- After each `still_working`: interval doubles (8s → 16s → 30s cap)
|
|
550
|
+
- Maximum interval: 30 seconds
|
|
551
|
+
- Reset: backoff resets to the base interval whenever new real content arrives (content hash changes)
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
First stall check: 8s → classifier says "still_working"
|
|
555
|
+
Second check: 16s → classifier says "still_working"
|
|
556
|
+
Third check: 30s → (capped at 30s)
|
|
557
|
+
New output arrives: → backoff resets to 8s
|
|
558
|
+
```
|
|
559
|
+
|
|
499
560
|
## Blocking Prompt Types
|
|
500
561
|
|
|
501
562
|
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
|
|
@@ -351,6 +354,17 @@ interface CLIAdapter {
|
|
|
351
354
|
version?: string;
|
|
352
355
|
error?: string;
|
|
353
356
|
}>;
|
|
357
|
+
/** Ms of output silence after detectReady match before emitting session_ready (default: 100) */
|
|
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;
|
|
354
368
|
/**
|
|
355
369
|
* Optional: Get health check command
|
|
356
370
|
*/
|
|
@@ -444,8 +458,12 @@ declare class PTYSession extends EventEmitter {
|
|
|
444
458
|
private _lastStallHash;
|
|
445
459
|
private _stallStartedAt;
|
|
446
460
|
private _lastContentHash;
|
|
461
|
+
private _stallBackoffMs;
|
|
462
|
+
private static readonly MAX_STALL_BACKOFF_MS;
|
|
447
463
|
private _taskCompleteTimer;
|
|
448
464
|
private static readonly TASK_COMPLETE_DEBOUNCE_MS;
|
|
465
|
+
private _readySettleTimer;
|
|
466
|
+
private _readySettlePending;
|
|
449
467
|
private _processScheduled;
|
|
450
468
|
private static readonly MAX_OUTPUT_BUFFER;
|
|
451
469
|
readonly id: string;
|
|
@@ -527,6 +545,18 @@ declare class PTYSession extends EventEmitter {
|
|
|
527
545
|
* doesn't match the idle prompt, so the agent is still working).
|
|
528
546
|
*/
|
|
529
547
|
private cancelTaskComplete;
|
|
548
|
+
/**
|
|
549
|
+
* Schedule or reset the ready-settle timer.
|
|
550
|
+
* Defers emitting session_ready until output goes quiet for readySettleMs
|
|
551
|
+
* after detectReady first matches. This prevents sending input while
|
|
552
|
+
* TUI agents are still rendering (status bar, shortcuts, update notices).
|
|
553
|
+
*/
|
|
554
|
+
private scheduleReadySettle;
|
|
555
|
+
/**
|
|
556
|
+
* Cancel a pending ready-settle timer (ready indicator disappeared
|
|
557
|
+
* or session status changed).
|
|
558
|
+
*/
|
|
559
|
+
private cancelReadySettle;
|
|
530
560
|
/**
|
|
531
561
|
* Start the PTY session
|
|
532
562
|
*/
|
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
|
|
@@ -351,6 +354,17 @@ interface CLIAdapter {
|
|
|
351
354
|
version?: string;
|
|
352
355
|
error?: string;
|
|
353
356
|
}>;
|
|
357
|
+
/** Ms of output silence after detectReady match before emitting session_ready (default: 100) */
|
|
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;
|
|
354
368
|
/**
|
|
355
369
|
* Optional: Get health check command
|
|
356
370
|
*/
|
|
@@ -444,8 +458,12 @@ declare class PTYSession extends EventEmitter {
|
|
|
444
458
|
private _lastStallHash;
|
|
445
459
|
private _stallStartedAt;
|
|
446
460
|
private _lastContentHash;
|
|
461
|
+
private _stallBackoffMs;
|
|
462
|
+
private static readonly MAX_STALL_BACKOFF_MS;
|
|
447
463
|
private _taskCompleteTimer;
|
|
448
464
|
private static readonly TASK_COMPLETE_DEBOUNCE_MS;
|
|
465
|
+
private _readySettleTimer;
|
|
466
|
+
private _readySettlePending;
|
|
449
467
|
private _processScheduled;
|
|
450
468
|
private static readonly MAX_OUTPUT_BUFFER;
|
|
451
469
|
readonly id: string;
|
|
@@ -527,6 +545,18 @@ declare class PTYSession extends EventEmitter {
|
|
|
527
545
|
* doesn't match the idle prompt, so the agent is still working).
|
|
528
546
|
*/
|
|
529
547
|
private cancelTaskComplete;
|
|
548
|
+
/**
|
|
549
|
+
* Schedule or reset the ready-settle timer.
|
|
550
|
+
* Defers emitting session_ready until output goes quiet for readySettleMs
|
|
551
|
+
* after detectReady first matches. This prevents sending input while
|
|
552
|
+
* TUI agents are still rendering (status bar, shortcuts, update notices).
|
|
553
|
+
*/
|
|
554
|
+
private scheduleReadySettle;
|
|
555
|
+
/**
|
|
556
|
+
* Cancel a pending ready-settle timer (ready indicator disappeared
|
|
557
|
+
* or session status changed).
|
|
558
|
+
*/
|
|
559
|
+
private cancelReadySettle;
|
|
530
560
|
/**
|
|
531
561
|
* Start the PTY session
|
|
532
562
|
*/
|
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,9 +345,15 @@ 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;
|
|
349
353
|
static TASK_COMPLETE_DEBOUNCE_MS = 1500;
|
|
354
|
+
// Ready detection settle delay — defers session_ready until output goes quiet
|
|
355
|
+
_readySettleTimer = null;
|
|
356
|
+
_readySettlePending = false;
|
|
350
357
|
// Deferred output processing — prevents node-pty's synchronous data
|
|
351
358
|
// delivery from starving the event loop (timers, I/O callbacks, etc.)
|
|
352
359
|
_processScheduled = false;
|
|
@@ -463,6 +470,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
463
470
|
}
|
|
464
471
|
this._stallStartedAt = Date.now();
|
|
465
472
|
this._lastStallHash = null;
|
|
473
|
+
this._stallBackoffMs = this._stallTimeoutMs;
|
|
466
474
|
this._stallTimer = setTimeout(() => {
|
|
467
475
|
this.onStallTimerFired();
|
|
468
476
|
}, this._stallTimeoutMs);
|
|
@@ -477,6 +485,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
477
485
|
}
|
|
478
486
|
this._stallStartedAt = null;
|
|
479
487
|
this._lastContentHash = null;
|
|
488
|
+
this._stallBackoffMs = this._stallTimeoutMs;
|
|
480
489
|
}
|
|
481
490
|
/**
|
|
482
491
|
* Called when the stall timer fires (no output for stallTimeoutMs).
|
|
@@ -485,10 +494,18 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
485
494
|
if (this._status !== "busy" && this._status !== "authenticating") {
|
|
486
495
|
return;
|
|
487
496
|
}
|
|
497
|
+
if (this.adapter.detectLoading?.(this.outputBuffer)) {
|
|
498
|
+
this.logger.debug(
|
|
499
|
+
{ sessionId: this.id },
|
|
500
|
+
"Loading pattern detected \u2014 suppressing stall emission"
|
|
501
|
+
);
|
|
502
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
488
505
|
const tail = this.outputBuffer.slice(-500);
|
|
489
506
|
const hash = this.simpleHash(tail);
|
|
490
507
|
if (hash === this._lastStallHash) {
|
|
491
|
-
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this.
|
|
508
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
492
509
|
return;
|
|
493
510
|
}
|
|
494
511
|
this._lastStallHash = hash;
|
|
@@ -513,7 +530,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
513
530
|
"Stall detected"
|
|
514
531
|
);
|
|
515
532
|
this.emit("stall_detected", recentOutput, stallDurationMs);
|
|
516
|
-
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this.
|
|
533
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
517
534
|
}
|
|
518
535
|
/**
|
|
519
536
|
* Promise-based delay helper.
|
|
@@ -560,8 +577,21 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
560
577
|
return;
|
|
561
578
|
}
|
|
562
579
|
if (!classification || classification.state === "still_working") {
|
|
580
|
+
this._stallBackoffMs = Math.min(
|
|
581
|
+
this._stallBackoffMs * 2,
|
|
582
|
+
_PTYSession.MAX_STALL_BACKOFF_MS
|
|
583
|
+
);
|
|
584
|
+
this.logger.debug(
|
|
585
|
+
{ sessionId: this.id, nextCheckMs: this._stallBackoffMs },
|
|
586
|
+
"Still working \u2014 backing off stall check interval"
|
|
587
|
+
);
|
|
563
588
|
this._lastContentHash = null;
|
|
564
|
-
this.
|
|
589
|
+
this._lastStallHash = null;
|
|
590
|
+
if (this._stallTimer) {
|
|
591
|
+
clearTimeout(this._stallTimer);
|
|
592
|
+
this._stallTimer = null;
|
|
593
|
+
}
|
|
594
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
565
595
|
return;
|
|
566
596
|
}
|
|
567
597
|
switch (classification.state) {
|
|
@@ -638,6 +668,45 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
638
668
|
}
|
|
639
669
|
}
|
|
640
670
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
671
|
+
// Ready Detection Settle Delay
|
|
672
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
673
|
+
/**
|
|
674
|
+
* Schedule or reset the ready-settle timer.
|
|
675
|
+
* Defers emitting session_ready until output goes quiet for readySettleMs
|
|
676
|
+
* after detectReady first matches. This prevents sending input while
|
|
677
|
+
* TUI agents are still rendering (status bar, shortcuts, update notices).
|
|
678
|
+
*/
|
|
679
|
+
scheduleReadySettle() {
|
|
680
|
+
this._readySettlePending = true;
|
|
681
|
+
if (this._readySettleTimer) {
|
|
682
|
+
clearTimeout(this._readySettleTimer);
|
|
683
|
+
}
|
|
684
|
+
const settleMs = this.config.readySettleMs ?? this.adapter.readySettleMs ?? 100;
|
|
685
|
+
this._readySettleTimer = setTimeout(() => {
|
|
686
|
+
this._readySettleTimer = null;
|
|
687
|
+
this._readySettlePending = false;
|
|
688
|
+
if (this._status !== "starting" && this._status !== "authenticating") return;
|
|
689
|
+
if (!this.adapter.detectReady(this.outputBuffer)) return;
|
|
690
|
+
this._status = "ready";
|
|
691
|
+
this._lastBlockingPromptHash = null;
|
|
692
|
+
this.outputBuffer = "";
|
|
693
|
+
this.clearStallTimer();
|
|
694
|
+
this.emit("ready");
|
|
695
|
+
this.logger.info({ sessionId: this.id }, "Session ready (after settle)");
|
|
696
|
+
}, settleMs);
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Cancel a pending ready-settle timer (ready indicator disappeared
|
|
700
|
+
* or session status changed).
|
|
701
|
+
*/
|
|
702
|
+
cancelReadySettle() {
|
|
703
|
+
if (this._readySettleTimer) {
|
|
704
|
+
clearTimeout(this._readySettleTimer);
|
|
705
|
+
this._readySettleTimer = null;
|
|
706
|
+
}
|
|
707
|
+
this._readySettlePending = false;
|
|
708
|
+
}
|
|
709
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
641
710
|
// Lifecycle
|
|
642
711
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
643
712
|
/**
|
|
@@ -726,13 +795,16 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
726
795
|
if (this._status === "busy" || this._status === "authenticating") {
|
|
727
796
|
this.resetStallTimer();
|
|
728
797
|
}
|
|
798
|
+
if (this._readySettlePending) {
|
|
799
|
+
if ((this._status === "starting" || this._status === "authenticating") && this.adapter.detectReady(this.outputBuffer)) {
|
|
800
|
+
this.scheduleReadySettle();
|
|
801
|
+
} else {
|
|
802
|
+
this.cancelReadySettle();
|
|
803
|
+
}
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
729
806
|
if ((this._status === "starting" || this._status === "authenticating") && this.adapter.detectReady(this.outputBuffer)) {
|
|
730
|
-
this.
|
|
731
|
-
this._lastBlockingPromptHash = null;
|
|
732
|
-
this.outputBuffer = "";
|
|
733
|
-
this.clearStallTimer();
|
|
734
|
-
this.emit("ready");
|
|
735
|
-
this.logger.info({ sessionId: this.id }, "Session ready");
|
|
807
|
+
this.scheduleReadySettle();
|
|
736
808
|
return;
|
|
737
809
|
}
|
|
738
810
|
if (this._status === "busy" && this.adapter.detectReady(this.outputBuffer)) {
|
|
@@ -1068,6 +1140,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
1068
1140
|
this._status = "stopping";
|
|
1069
1141
|
this.clearStallTimer();
|
|
1070
1142
|
this.cancelTaskComplete();
|
|
1143
|
+
this.cancelReadySettle();
|
|
1071
1144
|
this.ptyProcess.kill(signal);
|
|
1072
1145
|
this.logger.info({ sessionId: this.id, signal }, "Killing PTY session");
|
|
1073
1146
|
}
|