pty-manager 1.2.5 → 1.2.8

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
@@ -283,6 +283,7 @@ var PTYSession = class extends EventEmitter {
283
283
  _lastActivityAt = null;
284
284
  messageCounter = 0;
285
285
  logger;
286
+ sessionRules = [];
286
287
  id;
287
288
  config;
288
289
  get status() {
@@ -297,6 +298,75 @@ var PTYSession = class extends EventEmitter {
297
298
  get lastActivityAt() {
298
299
  return this._lastActivityAt ?? void 0;
299
300
  }
301
+ // ─────────────────────────────────────────────────────────────────────────────
302
+ // Runtime Auto-Response Rules API
303
+ // ─────────────────────────────────────────────────────────────────────────────
304
+ /**
305
+ * Add an auto-response rule to this session.
306
+ * Session rules are checked before adapter rules.
307
+ */
308
+ addAutoResponseRule(rule) {
309
+ const existingIndex = this.sessionRules.findIndex(
310
+ (r) => r.pattern.source === rule.pattern.source && r.pattern.flags === rule.pattern.flags
311
+ );
312
+ if (existingIndex >= 0) {
313
+ this.sessionRules[existingIndex] = rule;
314
+ this.logger.debug(
315
+ { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },
316
+ "Replaced existing auto-response rule"
317
+ );
318
+ } else {
319
+ this.sessionRules.push(rule);
320
+ this.logger.debug(
321
+ { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },
322
+ "Added auto-response rule"
323
+ );
324
+ }
325
+ }
326
+ /**
327
+ * Remove an auto-response rule by pattern.
328
+ * Returns true if a rule was removed.
329
+ */
330
+ removeAutoResponseRule(pattern) {
331
+ const initialLength = this.sessionRules.length;
332
+ this.sessionRules = this.sessionRules.filter(
333
+ (r) => !(r.pattern.source === pattern.source && r.pattern.flags === pattern.flags)
334
+ );
335
+ const removed = this.sessionRules.length < initialLength;
336
+ if (removed) {
337
+ this.logger.debug(
338
+ { sessionId: this.id, pattern: pattern.source },
339
+ "Removed auto-response rule"
340
+ );
341
+ }
342
+ return removed;
343
+ }
344
+ /**
345
+ * Set all session auto-response rules, replacing existing ones.
346
+ */
347
+ setAutoResponseRules(rules) {
348
+ this.sessionRules = [...rules];
349
+ this.logger.debug(
350
+ { sessionId: this.id, count: rules.length },
351
+ "Set auto-response rules"
352
+ );
353
+ }
354
+ /**
355
+ * Get all session auto-response rules.
356
+ */
357
+ getAutoResponseRules() {
358
+ return [...this.sessionRules];
359
+ }
360
+ /**
361
+ * Clear all session auto-response rules.
362
+ */
363
+ clearAutoResponseRules() {
364
+ this.sessionRules = [];
365
+ this.logger.debug({ sessionId: this.id }, "Cleared auto-response rules");
366
+ }
367
+ // ─────────────────────────────────────────────────────────────────────────────
368
+ // Lifecycle
369
+ // ─────────────────────────────────────────────────────────────────────────────
300
370
  /**
301
371
  * Start the PTY session
302
372
  */
@@ -377,7 +447,9 @@ var PTYSession = class extends EventEmitter {
377
447
  this._status = "stopped";
378
448
  this.emit("exit", exitDetection.code || 0);
379
449
  }
380
- this.tryParseOutput();
450
+ if (this._status !== "starting" && this._status !== "authenticating") {
451
+ this.tryParseOutput();
452
+ }
381
453
  });
382
454
  this.ptyProcess.onExit(({ exitCode, signal }) => {
383
455
  this._status = "stopped";
@@ -438,23 +510,27 @@ var PTYSession = class extends EventEmitter {
438
510
  return false;
439
511
  }
440
512
  /**
441
- * Try to match and apply auto-response rules
513
+ * Try to match and apply auto-response rules.
514
+ * Session rules are checked first, then adapter rules.
442
515
  */
443
516
  tryAutoResponse() {
444
- const rules = this.adapter.autoResponseRules;
445
- if (!rules || rules.length === 0) {
517
+ const adapterRules = this.adapter.autoResponseRules || [];
518
+ const allRules = [...this.sessionRules, ...adapterRules];
519
+ if (allRules.length === 0) {
446
520
  return false;
447
521
  }
448
- for (const rule of rules) {
522
+ for (const rule of allRules) {
449
523
  if (rule.pattern.test(this.outputBuffer)) {
450
524
  const safe = rule.safe !== false;
525
+ const isSessionRule = this.sessionRules.includes(rule);
451
526
  if (safe) {
452
527
  this.logger.info(
453
528
  {
454
529
  sessionId: this.id,
455
530
  promptType: rule.type,
456
531
  description: rule.description,
457
- response: rule.response
532
+ response: rule.response,
533
+ source: isSessionRule ? "session" : "adapter"
458
534
  },
459
535
  "Applying auto-response rule"
460
536
  );
@@ -925,6 +1001,61 @@ var PTYManager = class extends EventEmitter2 {
925
1001
  getSession(sessionId) {
926
1002
  return this.sessions.get(sessionId);
927
1003
  }
1004
+ // ─────────────────────────────────────────────────────────────────────────────
1005
+ // Runtime Auto-Response Rules API
1006
+ // ─────────────────────────────────────────────────────────────────────────────
1007
+ /**
1008
+ * Add an auto-response rule to a session.
1009
+ * Session rules are checked before adapter rules.
1010
+ */
1011
+ addAutoResponseRule(sessionId, rule) {
1012
+ const session = this.sessions.get(sessionId);
1013
+ if (!session) {
1014
+ throw new Error(`Session not found: ${sessionId}`);
1015
+ }
1016
+ session.addAutoResponseRule(rule);
1017
+ }
1018
+ /**
1019
+ * Remove an auto-response rule from a session by pattern.
1020
+ * Returns true if a rule was removed.
1021
+ */
1022
+ removeAutoResponseRule(sessionId, pattern) {
1023
+ const session = this.sessions.get(sessionId);
1024
+ if (!session) {
1025
+ throw new Error(`Session not found: ${sessionId}`);
1026
+ }
1027
+ return session.removeAutoResponseRule(pattern);
1028
+ }
1029
+ /**
1030
+ * Set all auto-response rules for a session, replacing existing ones.
1031
+ */
1032
+ setAutoResponseRules(sessionId, rules) {
1033
+ const session = this.sessions.get(sessionId);
1034
+ if (!session) {
1035
+ throw new Error(`Session not found: ${sessionId}`);
1036
+ }
1037
+ session.setAutoResponseRules(rules);
1038
+ }
1039
+ /**
1040
+ * Get all auto-response rules for a session.
1041
+ */
1042
+ getAutoResponseRules(sessionId) {
1043
+ const session = this.sessions.get(sessionId);
1044
+ if (!session) {
1045
+ throw new Error(`Session not found: ${sessionId}`);
1046
+ }
1047
+ return session.getAutoResponseRules();
1048
+ }
1049
+ /**
1050
+ * Clear all auto-response rules for a session.
1051
+ */
1052
+ clearAutoResponseRules(sessionId) {
1053
+ const session = this.sessions.get(sessionId);
1054
+ if (!session) {
1055
+ throw new Error(`Session not found: ${sessionId}`);
1056
+ }
1057
+ session.clearAutoResponseRules();
1058
+ }
928
1059
  };
929
1060
 
930
1061
  // src/adapters/base-adapter.ts
@@ -1011,7 +1142,7 @@ var BaseCLIAdapter = class {
1011
1142
  instructions: "Please select a project or workspace"
1012
1143
  };
1013
1144
  }
1014
- if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]/i.test(stripped) && stripped.includes("?")) {
1145
+ if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]|\(Y\)es\/\(N\)o|Yes\/No\??/i.test(stripped)) {
1015
1146
  return {
1016
1147
  detected: true,
1017
1148
  type: "unknown",
@@ -1019,7 +1150,49 @@ var BaseCLIAdapter = class {
1019
1150
  // Last 200 chars for context
1020
1151
  options: ["y", "n"],
1021
1152
  canAutoRespond: false,
1022
- instructions: "Unknown confirmation prompt detected"
1153
+ instructions: "Confirmation prompt detected"
1154
+ };
1155
+ }
1156
+ if (/^\s*[›>]?\s*[1-9]\.\s+\w+/m.test(stripped) && /\?\s*$/m.test(stripped)) {
1157
+ const optionMatches = stripped.match(/[›>]?\s*([1-9])\.\s+([^\n]+)/g);
1158
+ const options = optionMatches ? optionMatches.map((m) => m.replace(/^[›>\s]*/, "").trim()) : [];
1159
+ return {
1160
+ detected: true,
1161
+ type: "unknown",
1162
+ prompt: stripped.slice(-300),
1163
+ options: options.length > 0 ? options : void 0,
1164
+ canAutoRespond: false,
1165
+ instructions: "Menu selection prompt detected"
1166
+ };
1167
+ }
1168
+ if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(stripped)) {
1169
+ return {
1170
+ detected: true,
1171
+ type: "unknown",
1172
+ prompt: stripped.slice(-200),
1173
+ suggestedResponse: "\n",
1174
+ canAutoRespond: false,
1175
+ instructions: "Enter/confirm prompt detected"
1176
+ };
1177
+ }
1178
+ if (/trust|allow|permission|grant access/i.test(stripped) && /\?\s*$/m.test(stripped)) {
1179
+ return {
1180
+ detected: true,
1181
+ type: "permission",
1182
+ prompt: stripped.slice(-200),
1183
+ canAutoRespond: false,
1184
+ instructions: "Permission/trust prompt detected"
1185
+ };
1186
+ }
1187
+ const lines = stripped.split("\n").filter((l) => l.trim());
1188
+ const lastLine = lines[lines.length - 1] || "";
1189
+ if (/\?\s*$/.test(lastLine) && lastLine.length < 200) {
1190
+ return {
1191
+ detected: true,
1192
+ type: "unknown",
1193
+ prompt: lastLine.trim(),
1194
+ canAutoRespond: false,
1195
+ instructions: "Question prompt detected"
1023
1196
  };
1024
1197
  }
1025
1198
  return { detected: false };
@@ -1467,6 +1640,18 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
1467
1640
  this.resolvePending("list", sessions);
1468
1641
  break;
1469
1642
  }
1643
+ case "rules": {
1644
+ const serializedRules = event.rules;
1645
+ const rules = serializedRules.map((r) => ({
1646
+ pattern: new RegExp(r.pattern, r.flags || ""),
1647
+ type: r.type,
1648
+ response: r.response,
1649
+ description: r.description,
1650
+ safe: r.safe
1651
+ }));
1652
+ this.resolvePending(`getRules:${id}`, rules);
1653
+ break;
1654
+ }
1470
1655
  case "ack": {
1471
1656
  const cmd = event.cmd;
1472
1657
  const success = event.success;
@@ -1604,6 +1789,74 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
1604
1789
  this.on(`data:${id}`, handler);
1605
1790
  return () => this.off(`data:${id}`, handler);
1606
1791
  }
1792
+ // ─────────────────────────────────────────────────────────────────────────────
1793
+ // Runtime Auto-Response Rules API
1794
+ // ─────────────────────────────────────────────────────────────────────────────
1795
+ serializeRule(rule) {
1796
+ return {
1797
+ pattern: rule.pattern.source,
1798
+ flags: rule.pattern.flags || void 0,
1799
+ type: rule.type,
1800
+ response: rule.response,
1801
+ description: rule.description,
1802
+ safe: rule.safe
1803
+ };
1804
+ }
1805
+ /**
1806
+ * Add an auto-response rule to a session.
1807
+ * Session rules are checked before adapter rules.
1808
+ */
1809
+ async addAutoResponseRule(sessionId, rule) {
1810
+ await this.waitForReady();
1811
+ const serialized = this.serializeRule(rule);
1812
+ this.sendCommand({ cmd: "addRule", id: sessionId, rule: serialized });
1813
+ await this.createPending(`addRule:${sessionId}`);
1814
+ }
1815
+ /**
1816
+ * Remove an auto-response rule from a session by pattern.
1817
+ * Returns true if a rule was removed.
1818
+ */
1819
+ async removeAutoResponseRule(sessionId, pattern) {
1820
+ await this.waitForReady();
1821
+ this.sendCommand({
1822
+ cmd: "removeRule",
1823
+ id: sessionId,
1824
+ pattern: pattern.source,
1825
+ flags: pattern.flags || void 0
1826
+ });
1827
+ try {
1828
+ await this.createPending(`removeRule:${sessionId}`);
1829
+ return true;
1830
+ } catch {
1831
+ return false;
1832
+ }
1833
+ }
1834
+ /**
1835
+ * Set all auto-response rules for a session, replacing existing ones.
1836
+ */
1837
+ async setAutoResponseRules(sessionId, rules) {
1838
+ await this.waitForReady();
1839
+ const serialized = rules.map((r) => this.serializeRule(r));
1840
+ this.sendCommand({ cmd: "setRules", id: sessionId, rules: serialized });
1841
+ await this.createPending(`setRules:${sessionId}`);
1842
+ }
1843
+ /**
1844
+ * Get all auto-response rules for a session.
1845
+ */
1846
+ async getAutoResponseRules(sessionId) {
1847
+ await this.waitForReady();
1848
+ this.sendCommand({ cmd: "getRules", id: sessionId });
1849
+ const rules = await this.createPending(`getRules:${sessionId}`);
1850
+ return rules;
1851
+ }
1852
+ /**
1853
+ * Clear all auto-response rules for a session.
1854
+ */
1855
+ async clearAutoResponseRules(sessionId) {
1856
+ await this.waitForReady();
1857
+ this.sendCommand({ cmd: "clearRules", id: sessionId });
1858
+ await this.createPending(`clearRules:${sessionId}`);
1859
+ }
1607
1860
  /**
1608
1861
  * Shutdown the worker and all sessions
1609
1862
  */