pty-manager 1.2.14 → 1.2.16

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 CHANGED
@@ -125,6 +125,10 @@ interface AutoResponseRule {
125
125
  type: BlockingPromptType;
126
126
  /** Response to send automatically */
127
127
  response: string;
128
+ /** How to deliver the response: 'text' writes raw text + CR, 'keys' sends key sequences (default: 'text') */
129
+ responseType?: 'text' | 'keys';
130
+ /** Key names to send when responseType is 'keys' (e.g. ['down', 'enter']) */
131
+ keys?: string[];
128
132
  /** Human-readable description of what this does */
129
133
  description: string;
130
134
  /** Whether this is safe to auto-respond (default: true) */
@@ -271,6 +275,12 @@ interface CLIAdapter {
271
275
  * These are applied automatically during startup and execution.
272
276
  */
273
277
  readonly autoResponseRules?: AutoResponseRule[];
278
+ /**
279
+ * Whether this CLI uses TUI menus that require arrow-key navigation.
280
+ * When true, auto-response rules without an explicit responseType
281
+ * default to sending Enter via sendKeys instead of writeRaw.
282
+ */
283
+ readonly usesTuiMenus?: boolean;
274
284
  /**
275
285
  * Get the CLI command to execute
276
286
  */
@@ -443,7 +453,7 @@ declare class PTYSession extends EventEmitter {
443
453
  clearAutoResponseRules(): void;
444
454
  /**
445
455
  * Start or reset the stall detection timer.
446
- * Only active when status is "busy" and stall detection is enabled.
456
+ * Active when status is "busy" or "authenticating" and stall detection is enabled.
447
457
  */
448
458
  private resetStallTimer;
449
459
  /**
@@ -454,6 +464,10 @@ declare class PTYSession extends EventEmitter {
454
464
  * Called when the stall timer fires (no output for stallTimeoutMs).
455
465
  */
456
466
  private onStallTimerFired;
467
+ /**
468
+ * Promise-based delay helper.
469
+ */
470
+ private delay;
457
471
  /**
458
472
  * Simple string hash for deduplication.
459
473
  */
@@ -523,6 +537,16 @@ declare class PTYSession extends EventEmitter {
523
537
  * @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
524
538
  */
525
539
  sendKeys(keys: string | string[]): void;
540
+ /**
541
+ * Select a TUI menu option by index (0-based).
542
+ * Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
543
+ */
544
+ selectMenuOption(optionIndex: number): Promise<void>;
545
+ /**
546
+ * Send a sequence of keys with staggered timing.
547
+ * Each key is sent 50ms apart using setTimeout to keep the caller synchronous.
548
+ */
549
+ private sendKeySequence;
526
550
  /**
527
551
  * Paste text using bracketed paste mode
528
552
  *
@@ -689,6 +713,11 @@ declare abstract class BaseCLIAdapter implements CLIAdapter {
689
713
  * Subclasses should override this to add CLI-specific rules.
690
714
  */
691
715
  readonly autoResponseRules: AutoResponseRule[];
716
+ /**
717
+ * Whether this CLI uses TUI menus requiring arrow-key navigation.
718
+ * Defaults to false; coding agent adapters override to true.
719
+ */
720
+ readonly usesTuiMenus: boolean;
692
721
  abstract getCommand(): string;
693
722
  abstract getArgs(config: SpawnConfig): string[];
694
723
  abstract getEnv(config: SpawnConfig): Record<string, string>;
@@ -926,6 +955,10 @@ declare class BunCompatiblePTYManager extends EventEmitter {
926
955
  * Get all auto-response rules for a session.
927
956
  */
928
957
  getAutoResponseRules(sessionId: string): Promise<AutoResponseRule[]>;
958
+ /**
959
+ * Select a TUI menu option by index (0-based) in a session.
960
+ */
961
+ selectMenuOption(id: string, optionIndex: number): Promise<void>;
929
962
  /**
930
963
  * Clear all auto-response rules for a session.
931
964
  */
package/dist/index.d.ts CHANGED
@@ -125,6 +125,10 @@ interface AutoResponseRule {
125
125
  type: BlockingPromptType;
126
126
  /** Response to send automatically */
127
127
  response: string;
128
+ /** How to deliver the response: 'text' writes raw text + CR, 'keys' sends key sequences (default: 'text') */
129
+ responseType?: 'text' | 'keys';
130
+ /** Key names to send when responseType is 'keys' (e.g. ['down', 'enter']) */
131
+ keys?: string[];
128
132
  /** Human-readable description of what this does */
129
133
  description: string;
130
134
  /** Whether this is safe to auto-respond (default: true) */
@@ -271,6 +275,12 @@ interface CLIAdapter {
271
275
  * These are applied automatically during startup and execution.
272
276
  */
273
277
  readonly autoResponseRules?: AutoResponseRule[];
278
+ /**
279
+ * Whether this CLI uses TUI menus that require arrow-key navigation.
280
+ * When true, auto-response rules without an explicit responseType
281
+ * default to sending Enter via sendKeys instead of writeRaw.
282
+ */
283
+ readonly usesTuiMenus?: boolean;
274
284
  /**
275
285
  * Get the CLI command to execute
276
286
  */
@@ -443,7 +453,7 @@ declare class PTYSession extends EventEmitter {
443
453
  clearAutoResponseRules(): void;
444
454
  /**
445
455
  * Start or reset the stall detection timer.
446
- * Only active when status is "busy" and stall detection is enabled.
456
+ * Active when status is "busy" or "authenticating" and stall detection is enabled.
447
457
  */
448
458
  private resetStallTimer;
449
459
  /**
@@ -454,6 +464,10 @@ declare class PTYSession extends EventEmitter {
454
464
  * Called when the stall timer fires (no output for stallTimeoutMs).
455
465
  */
456
466
  private onStallTimerFired;
467
+ /**
468
+ * Promise-based delay helper.
469
+ */
470
+ private delay;
457
471
  /**
458
472
  * Simple string hash for deduplication.
459
473
  */
@@ -523,6 +537,16 @@ declare class PTYSession extends EventEmitter {
523
537
  * @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
524
538
  */
525
539
  sendKeys(keys: string | string[]): void;
540
+ /**
541
+ * Select a TUI menu option by index (0-based).
542
+ * Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
543
+ */
544
+ selectMenuOption(optionIndex: number): Promise<void>;
545
+ /**
546
+ * Send a sequence of keys with staggered timing.
547
+ * Each key is sent 50ms apart using setTimeout to keep the caller synchronous.
548
+ */
549
+ private sendKeySequence;
526
550
  /**
527
551
  * Paste text using bracketed paste mode
528
552
  *
@@ -689,6 +713,11 @@ declare abstract class BaseCLIAdapter implements CLIAdapter {
689
713
  * Subclasses should override this to add CLI-specific rules.
690
714
  */
691
715
  readonly autoResponseRules: AutoResponseRule[];
716
+ /**
717
+ * Whether this CLI uses TUI menus requiring arrow-key navigation.
718
+ * Defaults to false; coding agent adapters override to true.
719
+ */
720
+ readonly usesTuiMenus: boolean;
692
721
  abstract getCommand(): string;
693
722
  abstract getArgs(config: SpawnConfig): string[];
694
723
  abstract getEnv(config: SpawnConfig): Record<string, string>;
@@ -926,6 +955,10 @@ declare class BunCompatiblePTYManager extends EventEmitter {
926
955
  * Get all auto-response rules for a session.
927
956
  */
928
957
  getAutoResponseRules(sessionId: string): Promise<AutoResponseRule[]>;
958
+ /**
959
+ * Select a TUI menu option by index (0-based) in a session.
960
+ */
961
+ selectMenuOption(id: string, optionIndex: number): Promise<void>;
929
962
  /**
930
963
  * Clear all auto-response rules for a session.
931
964
  */
package/dist/index.js CHANGED
@@ -416,11 +416,11 @@ var PTYSession = class extends import_events.EventEmitter {
416
416
  // ─────────────────────────────────────────────────────────────────────────────
417
417
  /**
418
418
  * Start or reset the stall detection timer.
419
- * Only active when status is "busy" and stall detection is enabled.
419
+ * Active when status is "busy" or "authenticating" and stall detection is enabled.
420
420
  */
421
421
  resetStallTimer() {
422
422
  this.clearStallTimer();
423
- if (!this._stallDetectionEnabled || this._status !== "busy") {
423
+ if (!this._stallDetectionEnabled || this._status !== "busy" && this._status !== "authenticating") {
424
424
  return;
425
425
  }
426
426
  this._stallStartedAt = Date.now();
@@ -443,7 +443,7 @@ var PTYSession = class extends import_events.EventEmitter {
443
443
  * Called when the stall timer fires (no output for stallTimeoutMs).
444
444
  */
445
445
  onStallTimerFired() {
446
- if (this._status !== "busy") {
446
+ if (this._status !== "busy" && this._status !== "authenticating") {
447
447
  return;
448
448
  }
449
449
  const tail = this.outputBuffer.slice(-500);
@@ -463,6 +463,12 @@ var PTYSession = class extends import_events.EventEmitter {
463
463
  this.emit("stall_detected", recentOutput, stallDurationMs);
464
464
  this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallTimeoutMs);
465
465
  }
466
+ /**
467
+ * Promise-based delay helper.
468
+ */
469
+ delay(ms) {
470
+ return new Promise((resolve) => setTimeout(resolve, ms));
471
+ }
466
472
  /**
467
473
  * Simple string hash for deduplication.
468
474
  */
@@ -488,7 +494,7 @@ var PTYSession = class extends import_events.EventEmitter {
488
494
  * Called by the manager after onStallClassify resolves.
489
495
  */
490
496
  handleStallClassification(classification) {
491
- if (this._status !== "busy") {
497
+ if (this._status !== "busy" && this._status !== "authenticating") {
492
498
  return;
493
499
  }
494
500
  if (!classification || classification.state === "still_working") {
@@ -507,7 +513,13 @@ var PTYSession = class extends import_events.EventEmitter {
507
513
  { sessionId: this.id, response: classification.suggestedResponse },
508
514
  "Auto-responding to stall-classified prompt"
509
515
  );
510
- this.writeRaw(classification.suggestedResponse + "\r");
516
+ const resp = classification.suggestedResponse;
517
+ if (resp.startsWith("keys:")) {
518
+ const keys = resp.slice(5).split(",").map((k) => k.trim());
519
+ this.sendKeySequence(keys);
520
+ } else {
521
+ this.writeRaw(resp + "\r");
522
+ }
511
523
  this.emit("blocking_prompt", promptInfo, true);
512
524
  } else {
513
525
  this.emit("blocking_prompt", promptInfo, false);
@@ -586,10 +598,14 @@ var PTYSession = class extends import_events.EventEmitter {
586
598
  this.ptyProcess.onData((data) => {
587
599
  this._lastActivityAt = /* @__PURE__ */ new Date();
588
600
  this.outputBuffer += data;
589
- if (this._status === "busy") {
601
+ if (this._status === "busy" || this._status === "authenticating") {
590
602
  this.resetStallTimer();
591
603
  }
592
604
  this.emit("output", data);
605
+ const blockingPrompt = this.detectAndHandleBlockingPrompt();
606
+ if (blockingPrompt) {
607
+ return;
608
+ }
593
609
  if ((this._status === "starting" || this._status === "authenticating") && this.adapter.detectReady(this.outputBuffer)) {
594
610
  this._status = "ready";
595
611
  this._lastBlockingPromptHash = null;
@@ -599,10 +615,6 @@ var PTYSession = class extends import_events.EventEmitter {
599
615
  this.logger.info({ sessionId: this.id }, "Session ready");
600
616
  return;
601
617
  }
602
- const blockingPrompt = this.detectAndHandleBlockingPrompt();
603
- if (blockingPrompt) {
604
- return;
605
- }
606
618
  if (this._status !== "ready" && this._status !== "busy") {
607
619
  const loginDetection = this.adapter.detectLogin(this.outputBuffer);
608
620
  if (loginDetection.required && this._status !== "authenticating") {
@@ -670,7 +682,13 @@ var PTYSession = class extends import_events.EventEmitter {
670
682
  },
671
683
  "Auto-responding to blocking prompt"
672
684
  );
673
- this.writeRaw(detection.suggestedResponse + "\r");
685
+ const resp = detection.suggestedResponse;
686
+ if (resp.startsWith("keys:")) {
687
+ const keys = resp.slice(5).split(",").map((k) => k.trim());
688
+ this.sendKeySequence(keys);
689
+ } else {
690
+ this.writeRaw(resp + "\r");
691
+ }
674
692
  this._lastBlockingPromptHash = null;
675
693
  this.emit("blocking_prompt", promptInfo, true);
676
694
  return true;
@@ -722,7 +740,15 @@ var PTYSession = class extends import_events.EventEmitter {
722
740
  },
723
741
  "Applying auto-response rule"
724
742
  );
725
- this.writeRaw(rule.response + "\r");
743
+ const useKeys = rule.keys && rule.keys.length > 0;
744
+ const isTuiDefault = !rule.responseType && !rule.keys && this.adapter.usesTuiMenus;
745
+ if (useKeys) {
746
+ this.sendKeySequence(rule.keys);
747
+ } else if (isTuiDefault) {
748
+ this.sendKeys("enter");
749
+ } else {
750
+ this.writeRaw(rule.response + "\r");
751
+ }
726
752
  this.outputBuffer = this.outputBuffer.replace(rule.pattern, "");
727
753
  const promptInfo = {
728
754
  type: rule.type,
@@ -852,6 +878,26 @@ var PTYSession = class extends import_events.EventEmitter {
852
878
  }
853
879
  }
854
880
  }
881
+ /**
882
+ * Select a TUI menu option by index (0-based).
883
+ * Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
884
+ */
885
+ async selectMenuOption(optionIndex) {
886
+ for (let i = 0; i < optionIndex; i++) {
887
+ this.sendKeys("down");
888
+ await this.delay(50);
889
+ }
890
+ this.sendKeys("enter");
891
+ }
892
+ /**
893
+ * Send a sequence of keys with staggered timing.
894
+ * Each key is sent 50ms apart using setTimeout to keep the caller synchronous.
895
+ */
896
+ sendKeySequence(keys) {
897
+ keys.forEach((key, i) => {
898
+ setTimeout(() => this.sendKeys(key), i * 50);
899
+ });
900
+ }
855
901
  /**
856
902
  * Paste text using bracketed paste mode
857
903
  *
@@ -1308,6 +1354,11 @@ var BaseCLIAdapter = class {
1308
1354
  * Subclasses should override this to add CLI-specific rules.
1309
1355
  */
1310
1356
  autoResponseRules = [];
1357
+ /**
1358
+ * Whether this CLI uses TUI menus requiring arrow-key navigation.
1359
+ * Defaults to false; coding agent adapters override to true.
1360
+ */
1361
+ usesTuiMenus = false;
1311
1362
  /**
1312
1363
  * Default exit detection - look for common exit patterns
1313
1364
  */
@@ -1928,6 +1979,8 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
1928
1979
  pattern: new RegExp(r.pattern, r.flags || ""),
1929
1980
  type: r.type,
1930
1981
  response: r.response,
1982
+ responseType: r.responseType,
1983
+ keys: r.keys,
1931
1984
  description: r.description,
1932
1985
  safe: r.safe
1933
1986
  }));
@@ -2080,6 +2133,8 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
2080
2133
  flags: rule.pattern.flags || void 0,
2081
2134
  type: rule.type,
2082
2135
  response: rule.response,
2136
+ responseType: rule.responseType,
2137
+ keys: rule.keys,
2083
2138
  description: rule.description,
2084
2139
  safe: rule.safe
2085
2140
  };
@@ -2131,6 +2186,14 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
2131
2186
  const rules = await this.createPending(`getRules:${sessionId}`);
2132
2187
  return rules;
2133
2188
  }
2189
+ /**
2190
+ * Select a TUI menu option by index (0-based) in a session.
2191
+ */
2192
+ async selectMenuOption(id, optionIndex) {
2193
+ await this.waitForReady();
2194
+ this.sendCommand({ cmd: "selectMenuOption", id, optionIndex });
2195
+ await this.createPending(`selectMenuOption:${id}`);
2196
+ }
2134
2197
  /**
2135
2198
  * Clear all auto-response rules for a session.
2136
2199
  */