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.mjs CHANGED
@@ -378,11 +378,11 @@ var PTYSession = class extends EventEmitter {
378
378
  // ─────────────────────────────────────────────────────────────────────────────
379
379
  /**
380
380
  * Start or reset the stall detection timer.
381
- * Only active when status is "busy" and stall detection is enabled.
381
+ * Active when status is "busy" or "authenticating" and stall detection is enabled.
382
382
  */
383
383
  resetStallTimer() {
384
384
  this.clearStallTimer();
385
- if (!this._stallDetectionEnabled || this._status !== "busy") {
385
+ if (!this._stallDetectionEnabled || this._status !== "busy" && this._status !== "authenticating") {
386
386
  return;
387
387
  }
388
388
  this._stallStartedAt = Date.now();
@@ -405,7 +405,7 @@ var PTYSession = class extends EventEmitter {
405
405
  * Called when the stall timer fires (no output for stallTimeoutMs).
406
406
  */
407
407
  onStallTimerFired() {
408
- if (this._status !== "busy") {
408
+ if (this._status !== "busy" && this._status !== "authenticating") {
409
409
  return;
410
410
  }
411
411
  const tail = this.outputBuffer.slice(-500);
@@ -425,6 +425,12 @@ var PTYSession = class extends EventEmitter {
425
425
  this.emit("stall_detected", recentOutput, stallDurationMs);
426
426
  this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallTimeoutMs);
427
427
  }
428
+ /**
429
+ * Promise-based delay helper.
430
+ */
431
+ delay(ms) {
432
+ return new Promise((resolve) => setTimeout(resolve, ms));
433
+ }
428
434
  /**
429
435
  * Simple string hash for deduplication.
430
436
  */
@@ -450,7 +456,7 @@ var PTYSession = class extends EventEmitter {
450
456
  * Called by the manager after onStallClassify resolves.
451
457
  */
452
458
  handleStallClassification(classification) {
453
- if (this._status !== "busy") {
459
+ if (this._status !== "busy" && this._status !== "authenticating") {
454
460
  return;
455
461
  }
456
462
  if (!classification || classification.state === "still_working") {
@@ -469,7 +475,13 @@ var PTYSession = class extends EventEmitter {
469
475
  { sessionId: this.id, response: classification.suggestedResponse },
470
476
  "Auto-responding to stall-classified prompt"
471
477
  );
472
- this.writeRaw(classification.suggestedResponse + "\r");
478
+ const resp = classification.suggestedResponse;
479
+ if (resp.startsWith("keys:")) {
480
+ const keys = resp.slice(5).split(",").map((k) => k.trim());
481
+ this.sendKeySequence(keys);
482
+ } else {
483
+ this.writeRaw(resp + "\r");
484
+ }
473
485
  this.emit("blocking_prompt", promptInfo, true);
474
486
  } else {
475
487
  this.emit("blocking_prompt", promptInfo, false);
@@ -548,10 +560,14 @@ var PTYSession = class extends EventEmitter {
548
560
  this.ptyProcess.onData((data) => {
549
561
  this._lastActivityAt = /* @__PURE__ */ new Date();
550
562
  this.outputBuffer += data;
551
- if (this._status === "busy") {
563
+ if (this._status === "busy" || this._status === "authenticating") {
552
564
  this.resetStallTimer();
553
565
  }
554
566
  this.emit("output", data);
567
+ const blockingPrompt = this.detectAndHandleBlockingPrompt();
568
+ if (blockingPrompt) {
569
+ return;
570
+ }
555
571
  if ((this._status === "starting" || this._status === "authenticating") && this.adapter.detectReady(this.outputBuffer)) {
556
572
  this._status = "ready";
557
573
  this._lastBlockingPromptHash = null;
@@ -561,10 +577,6 @@ var PTYSession = class extends EventEmitter {
561
577
  this.logger.info({ sessionId: this.id }, "Session ready");
562
578
  return;
563
579
  }
564
- const blockingPrompt = this.detectAndHandleBlockingPrompt();
565
- if (blockingPrompt) {
566
- return;
567
- }
568
580
  if (this._status !== "ready" && this._status !== "busy") {
569
581
  const loginDetection = this.adapter.detectLogin(this.outputBuffer);
570
582
  if (loginDetection.required && this._status !== "authenticating") {
@@ -632,7 +644,13 @@ var PTYSession = class extends EventEmitter {
632
644
  },
633
645
  "Auto-responding to blocking prompt"
634
646
  );
635
- this.writeRaw(detection.suggestedResponse + "\r");
647
+ const resp = detection.suggestedResponse;
648
+ if (resp.startsWith("keys:")) {
649
+ const keys = resp.slice(5).split(",").map((k) => k.trim());
650
+ this.sendKeySequence(keys);
651
+ } else {
652
+ this.writeRaw(resp + "\r");
653
+ }
636
654
  this._lastBlockingPromptHash = null;
637
655
  this.emit("blocking_prompt", promptInfo, true);
638
656
  return true;
@@ -684,7 +702,15 @@ var PTYSession = class extends EventEmitter {
684
702
  },
685
703
  "Applying auto-response rule"
686
704
  );
687
- this.writeRaw(rule.response + "\r");
705
+ const useKeys = rule.keys && rule.keys.length > 0;
706
+ const isTuiDefault = !rule.responseType && !rule.keys && this.adapter.usesTuiMenus;
707
+ if (useKeys) {
708
+ this.sendKeySequence(rule.keys);
709
+ } else if (isTuiDefault) {
710
+ this.sendKeys("enter");
711
+ } else {
712
+ this.writeRaw(rule.response + "\r");
713
+ }
688
714
  this.outputBuffer = this.outputBuffer.replace(rule.pattern, "");
689
715
  const promptInfo = {
690
716
  type: rule.type,
@@ -814,6 +840,26 @@ var PTYSession = class extends EventEmitter {
814
840
  }
815
841
  }
816
842
  }
843
+ /**
844
+ * Select a TUI menu option by index (0-based).
845
+ * Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
846
+ */
847
+ async selectMenuOption(optionIndex) {
848
+ for (let i = 0; i < optionIndex; i++) {
849
+ this.sendKeys("down");
850
+ await this.delay(50);
851
+ }
852
+ this.sendKeys("enter");
853
+ }
854
+ /**
855
+ * Send a sequence of keys with staggered timing.
856
+ * Each key is sent 50ms apart using setTimeout to keep the caller synchronous.
857
+ */
858
+ sendKeySequence(keys) {
859
+ keys.forEach((key, i) => {
860
+ setTimeout(() => this.sendKeys(key), i * 50);
861
+ });
862
+ }
817
863
  /**
818
864
  * Paste text using bracketed paste mode
819
865
  *
@@ -1270,6 +1316,11 @@ var BaseCLIAdapter = class {
1270
1316
  * Subclasses should override this to add CLI-specific rules.
1271
1317
  */
1272
1318
  autoResponseRules = [];
1319
+ /**
1320
+ * Whether this CLI uses TUI menus requiring arrow-key navigation.
1321
+ * Defaults to false; coding agent adapters override to true.
1322
+ */
1323
+ usesTuiMenus = false;
1273
1324
  /**
1274
1325
  * Default exit detection - look for common exit patterns
1275
1326
  */
@@ -1890,6 +1941,8 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
1890
1941
  pattern: new RegExp(r.pattern, r.flags || ""),
1891
1942
  type: r.type,
1892
1943
  response: r.response,
1944
+ responseType: r.responseType,
1945
+ keys: r.keys,
1893
1946
  description: r.description,
1894
1947
  safe: r.safe
1895
1948
  }));
@@ -2042,6 +2095,8 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
2042
2095
  flags: rule.pattern.flags || void 0,
2043
2096
  type: rule.type,
2044
2097
  response: rule.response,
2098
+ responseType: rule.responseType,
2099
+ keys: rule.keys,
2045
2100
  description: rule.description,
2046
2101
  safe: rule.safe
2047
2102
  };
@@ -2093,6 +2148,14 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
2093
2148
  const rules = await this.createPending(`getRules:${sessionId}`);
2094
2149
  return rules;
2095
2150
  }
2151
+ /**
2152
+ * Select a TUI menu option by index (0-based) in a session.
2153
+ */
2154
+ async selectMenuOption(id, optionIndex) {
2155
+ await this.waitForReady();
2156
+ this.sendCommand({ cmd: "selectMenuOption", id, optionIndex });
2157
+ await this.createPending(`selectMenuOption:${id}`);
2158
+ }
2096
2159
  /**
2097
2160
  * Clear all auto-response rules for a session.
2098
2161
  */