pty-manager 1.2.19 → 1.2.21
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 +71 -1
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +17 -1
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +17 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@ PTY session manager with lifecycle management, pluggable adapters, and blocking
|
|
|
7
7
|
- **Multi-session management** - Spawn and manage multiple PTY sessions concurrently
|
|
8
8
|
- **Pluggable adapters** - Built-in shell adapter, easy to create custom adapters for Docker, SSH, or any CLI tool
|
|
9
9
|
- **Blocking prompt detection** - Detect login prompts, confirmations, and interactive prompts
|
|
10
|
-
- **Auto-response rules** - Automatically respond to known prompts
|
|
10
|
+
- **Auto-response rules** - Automatically respond to known prompts with text or key sequences
|
|
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
|
|
11
13
|
- **Terminal attachment** - Attach to sessions for raw I/O streaming
|
|
12
14
|
- **Special key support** - Send Ctrl, Alt, Shift, and function key combinations via `sendKeys()`
|
|
13
15
|
- **Bracketed paste** - Proper paste handling with bracketed paste mode support
|
|
@@ -366,6 +368,9 @@ Commands (stdin → worker):
|
|
|
366
368
|
- `{ "cmd": "spawn", "id": "...", "config": {...} }`
|
|
367
369
|
- `{ "cmd": "send", "id": "...", "data": "..." }`
|
|
368
370
|
- `{ "cmd": "sendKeys", "id": "...", "keys": ["ctrl+c"] }`
|
|
371
|
+
- `{ "cmd": "selectMenuOption", "id": "...", "optionIndex": 2 }`
|
|
372
|
+
- `{ "cmd": "addRules", "id": "...", "rules": [...] }`
|
|
373
|
+
- `{ "cmd": "clearRules", "id": "..." }`
|
|
369
374
|
- `{ "cmd": "kill", "id": "..." }`
|
|
370
375
|
- `{ "cmd": "list" }`
|
|
371
376
|
- `{ "cmd": "shutdown" }`
|
|
@@ -374,6 +379,8 @@ Events (worker → stdout):
|
|
|
374
379
|
- `{ "event": "output", "id": "...", "data": "..." }`
|
|
375
380
|
- `{ "event": "ready", "id": "..." }`
|
|
376
381
|
- `{ "event": "exit", "id": "...", "code": 0 }`
|
|
382
|
+
- `{ "event": "blocking_prompt", "id": "...", "promptInfo": {...}, "autoResponded": true }`
|
|
383
|
+
- `{ "event": "login_required", "id": "...", "instructions": "..." }`
|
|
377
384
|
|
|
378
385
|
## Built-in Adapters
|
|
379
386
|
|
|
@@ -390,6 +397,69 @@ const adapter = new ShellAdapter({
|
|
|
390
397
|
});
|
|
391
398
|
```
|
|
392
399
|
|
|
400
|
+
## Auto-Response Rules
|
|
401
|
+
|
|
402
|
+
Auto-response rules let adapters automatically handle known prompts. Rules support two response modes: **text** (for traditional `[y/n]` prompts) and **keys** (for TUI arrow-key menus).
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
interface AutoResponseRule {
|
|
406
|
+
pattern: RegExp; // Pattern to match in output
|
|
407
|
+
type: BlockingPromptType; // Prompt category
|
|
408
|
+
response: string; // Text to send (for responseType: 'text')
|
|
409
|
+
responseType?: 'text' | 'keys'; // How to deliver (default: 'text')
|
|
410
|
+
keys?: string[]; // Key names for responseType: 'keys'
|
|
411
|
+
description: string; // Human-readable description
|
|
412
|
+
safe?: boolean; // Whether safe to auto-respond (default: true)
|
|
413
|
+
once?: boolean; // Fire at most once per session
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Text response** — sends `response + '\r'` via raw write (for CLIs like Aider that use `[y/n]` prompts):
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
{ pattern: /create new file\?/i, type: 'permission', response: 'y', responseType: 'text', description: 'Allow file creation', safe: true }
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Key sequence response** — sends key presses via `sendKeys()` (for TUI menus in Codex, Gemini, Claude):
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
{ pattern: /update available/i, type: 'config', response: '', responseType: 'keys', keys: ['down', 'enter'], description: 'Skip update (select second option)', safe: true, once: true }
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### TUI Menu Navigation
|
|
430
|
+
|
|
431
|
+
Adapters can declare `usesTuiMenus: true` to indicate they use arrow-key menus instead of text prompts. When set, rules without an explicit `responseType` default to sending Enter via `sendKeys()` instead of raw text.
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
// Navigate to the Nth option in a TUI menu (0-indexed)
|
|
435
|
+
await session.selectMenuOption(2); // Sends Down, Down, Enter with 50ms delays
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Stall Detection
|
|
439
|
+
|
|
440
|
+
Content-based stall detection monitors sessions for output that stops changing. When a stall is detected, the session emits a `stall_detected` event with the buffered output for external classification.
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
// Enable stall detection with a pluggable classifier
|
|
444
|
+
const session = await manager.spawn({
|
|
445
|
+
name: 'agent',
|
|
446
|
+
type: 'claude',
|
|
447
|
+
stallDetection: {
|
|
448
|
+
enabled: true,
|
|
449
|
+
timeoutMs: 15000,
|
|
450
|
+
classify: async (output, stallDurationMs) => {
|
|
451
|
+
// Use an LLM or heuristics to classify the stalled output
|
|
452
|
+
return {
|
|
453
|
+
type: 'blocking_prompt',
|
|
454
|
+
confidence: 0.9,
|
|
455
|
+
suggestedResponse: 'keys:enter', // or plain text like 'y'
|
|
456
|
+
reasoning: 'Trust folder dialog detected',
|
|
457
|
+
};
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
});
|
|
461
|
+
```
|
|
462
|
+
|
|
393
463
|
## Blocking Prompt Types
|
|
394
464
|
|
|
395
465
|
The library recognizes these blocking prompt types:
|
package/dist/index.d.mts
CHANGED
|
@@ -37,6 +37,11 @@ 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 or disable specific adapter auto-response rules for this session.
|
|
41
|
+
* Keys are regex source strings (from rule.pattern.source).
|
|
42
|
+
* - null value disables that rule entirely
|
|
43
|
+
* - Object value merges fields into the matching adapter rule */
|
|
44
|
+
ruleOverrides?: Record<string, Partial<Omit<AutoResponseRule, 'pattern'>> | null>;
|
|
40
45
|
}
|
|
41
46
|
/**
|
|
42
47
|
* Handle to a running session
|
|
@@ -420,6 +425,8 @@ declare class PTYSession extends EventEmitter {
|
|
|
420
425
|
private sessionRules;
|
|
421
426
|
private _firedOnceRules;
|
|
422
427
|
private _lastBlockingPromptHash;
|
|
428
|
+
private _ruleOverrides;
|
|
429
|
+
private _disabledRulePatterns;
|
|
423
430
|
private _stallTimer;
|
|
424
431
|
private _stallTimeoutMs;
|
|
425
432
|
private _stallDetectionEnabled;
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ 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 or disable specific adapter auto-response rules for this session.
|
|
41
|
+
* Keys are regex source strings (from rule.pattern.source).
|
|
42
|
+
* - null value disables that rule entirely
|
|
43
|
+
* - Object value merges fields into the matching adapter rule */
|
|
44
|
+
ruleOverrides?: Record<string, Partial<Omit<AutoResponseRule, 'pattern'>> | null>;
|
|
40
45
|
}
|
|
41
46
|
/**
|
|
42
47
|
* Handle to a running session
|
|
@@ -420,6 +425,8 @@ declare class PTYSession extends EventEmitter {
|
|
|
420
425
|
private sessionRules;
|
|
421
426
|
private _firedOnceRules;
|
|
422
427
|
private _lastBlockingPromptHash;
|
|
428
|
+
private _ruleOverrides;
|
|
429
|
+
private _disabledRulePatterns;
|
|
423
430
|
private _stallTimer;
|
|
424
431
|
private _stallTimeoutMs;
|
|
425
432
|
private _stallDetectionEnabled;
|
package/dist/index.js
CHANGED
|
@@ -315,6 +315,15 @@ var PTYSession = class 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
|
+
if (config.ruleOverrides) {
|
|
319
|
+
for (const [key, value] of Object.entries(config.ruleOverrides)) {
|
|
320
|
+
if (value === null) {
|
|
321
|
+
this._disabledRulePatterns.add(key);
|
|
322
|
+
} else {
|
|
323
|
+
this._ruleOverrides.set(key, value);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
318
327
|
}
|
|
319
328
|
ptyProcess = null;
|
|
320
329
|
outputBuffer = "";
|
|
@@ -326,6 +335,8 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
326
335
|
sessionRules = [];
|
|
327
336
|
_firedOnceRules = /* @__PURE__ */ new Set();
|
|
328
337
|
_lastBlockingPromptHash = null;
|
|
338
|
+
_ruleOverrides = /* @__PURE__ */ new Map();
|
|
339
|
+
_disabledRulePatterns = /* @__PURE__ */ new Set();
|
|
329
340
|
// Stall detection
|
|
330
341
|
_stallTimer = null;
|
|
331
342
|
_stallTimeoutMs;
|
|
@@ -548,6 +559,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
548
559
|
this.writeRaw(resp + "\r");
|
|
549
560
|
}
|
|
550
561
|
this.emit("blocking_prompt", promptInfo, true);
|
|
562
|
+
this.outputBuffer = "";
|
|
551
563
|
} else {
|
|
552
564
|
this.emit("blocking_prompt", promptInfo, false);
|
|
553
565
|
}
|
|
@@ -717,6 +729,7 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
717
729
|
this.writeRaw(resp + "\r");
|
|
718
730
|
}
|
|
719
731
|
this._lastBlockingPromptHash = null;
|
|
732
|
+
this.outputBuffer = "";
|
|
720
733
|
this.emit("blocking_prompt", promptInfo, true);
|
|
721
734
|
return true;
|
|
722
735
|
}
|
|
@@ -744,7 +757,10 @@ var PTYSession = class extends import_events.EventEmitter {
|
|
|
744
757
|
* Session rules are checked first, then adapter rules.
|
|
745
758
|
*/
|
|
746
759
|
tryAutoResponse() {
|
|
747
|
-
const adapterRules = this.adapter.autoResponseRules || []
|
|
760
|
+
const adapterRules = (this.adapter.autoResponseRules || []).filter((r) => !this._disabledRulePatterns.has(r.pattern.source)).map((r) => {
|
|
761
|
+
const override = this._ruleOverrides.get(r.pattern.source);
|
|
762
|
+
return override ? { ...r, ...override } : r;
|
|
763
|
+
});
|
|
748
764
|
const allRules = [...this.sessionRules, ...adapterRules];
|
|
749
765
|
if (allRules.length === 0) {
|
|
750
766
|
return false;
|