pty-manager 1.2.5 → 1.2.7

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
  */
@@ -438,23 +508,27 @@ var PTYSession = class extends EventEmitter {
438
508
  return false;
439
509
  }
440
510
  /**
441
- * Try to match and apply auto-response rules
511
+ * Try to match and apply auto-response rules.
512
+ * Session rules are checked first, then adapter rules.
442
513
  */
443
514
  tryAutoResponse() {
444
- const rules = this.adapter.autoResponseRules;
445
- if (!rules || rules.length === 0) {
515
+ const adapterRules = this.adapter.autoResponseRules || [];
516
+ const allRules = [...this.sessionRules, ...adapterRules];
517
+ if (allRules.length === 0) {
446
518
  return false;
447
519
  }
448
- for (const rule of rules) {
520
+ for (const rule of allRules) {
449
521
  if (rule.pattern.test(this.outputBuffer)) {
450
522
  const safe = rule.safe !== false;
523
+ const isSessionRule = this.sessionRules.includes(rule);
451
524
  if (safe) {
452
525
  this.logger.info(
453
526
  {
454
527
  sessionId: this.id,
455
528
  promptType: rule.type,
456
529
  description: rule.description,
457
- response: rule.response
530
+ response: rule.response,
531
+ source: isSessionRule ? "session" : "adapter"
458
532
  },
459
533
  "Applying auto-response rule"
460
534
  );
@@ -925,6 +999,61 @@ var PTYManager = class extends EventEmitter2 {
925
999
  getSession(sessionId) {
926
1000
  return this.sessions.get(sessionId);
927
1001
  }
1002
+ // ─────────────────────────────────────────────────────────────────────────────
1003
+ // Runtime Auto-Response Rules API
1004
+ // ─────────────────────────────────────────────────────────────────────────────
1005
+ /**
1006
+ * Add an auto-response rule to a session.
1007
+ * Session rules are checked before adapter rules.
1008
+ */
1009
+ addAutoResponseRule(sessionId, rule) {
1010
+ const session = this.sessions.get(sessionId);
1011
+ if (!session) {
1012
+ throw new Error(`Session not found: ${sessionId}`);
1013
+ }
1014
+ session.addAutoResponseRule(rule);
1015
+ }
1016
+ /**
1017
+ * Remove an auto-response rule from a session by pattern.
1018
+ * Returns true if a rule was removed.
1019
+ */
1020
+ removeAutoResponseRule(sessionId, pattern) {
1021
+ const session = this.sessions.get(sessionId);
1022
+ if (!session) {
1023
+ throw new Error(`Session not found: ${sessionId}`);
1024
+ }
1025
+ return session.removeAutoResponseRule(pattern);
1026
+ }
1027
+ /**
1028
+ * Set all auto-response rules for a session, replacing existing ones.
1029
+ */
1030
+ setAutoResponseRules(sessionId, rules) {
1031
+ const session = this.sessions.get(sessionId);
1032
+ if (!session) {
1033
+ throw new Error(`Session not found: ${sessionId}`);
1034
+ }
1035
+ session.setAutoResponseRules(rules);
1036
+ }
1037
+ /**
1038
+ * Get all auto-response rules for a session.
1039
+ */
1040
+ getAutoResponseRules(sessionId) {
1041
+ const session = this.sessions.get(sessionId);
1042
+ if (!session) {
1043
+ throw new Error(`Session not found: ${sessionId}`);
1044
+ }
1045
+ return session.getAutoResponseRules();
1046
+ }
1047
+ /**
1048
+ * Clear all auto-response rules for a session.
1049
+ */
1050
+ clearAutoResponseRules(sessionId) {
1051
+ const session = this.sessions.get(sessionId);
1052
+ if (!session) {
1053
+ throw new Error(`Session not found: ${sessionId}`);
1054
+ }
1055
+ session.clearAutoResponseRules();
1056
+ }
928
1057
  };
929
1058
 
930
1059
  // src/adapters/base-adapter.ts
@@ -1011,7 +1140,7 @@ var BaseCLIAdapter = class {
1011
1140
  instructions: "Please select a project or workspace"
1012
1141
  };
1013
1142
  }
1014
- if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]/i.test(stripped) && stripped.includes("?")) {
1143
+ if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]|\(Y\)es\/\(N\)o|Yes\/No\??/i.test(stripped)) {
1015
1144
  return {
1016
1145
  detected: true,
1017
1146
  type: "unknown",
@@ -1019,7 +1148,49 @@ var BaseCLIAdapter = class {
1019
1148
  // Last 200 chars for context
1020
1149
  options: ["y", "n"],
1021
1150
  canAutoRespond: false,
1022
- instructions: "Unknown confirmation prompt detected"
1151
+ instructions: "Confirmation prompt detected"
1152
+ };
1153
+ }
1154
+ if (/^\s*[›>]?\s*[1-9]\.\s+\w+/m.test(stripped) && /\?\s*$/m.test(stripped)) {
1155
+ const optionMatches = stripped.match(/[›>]?\s*([1-9])\.\s+([^\n]+)/g);
1156
+ const options = optionMatches ? optionMatches.map((m) => m.replace(/^[›>\s]*/, "").trim()) : [];
1157
+ return {
1158
+ detected: true,
1159
+ type: "unknown",
1160
+ prompt: stripped.slice(-300),
1161
+ options: options.length > 0 ? options : void 0,
1162
+ canAutoRespond: false,
1163
+ instructions: "Menu selection prompt detected"
1164
+ };
1165
+ }
1166
+ if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(stripped)) {
1167
+ return {
1168
+ detected: true,
1169
+ type: "unknown",
1170
+ prompt: stripped.slice(-200),
1171
+ suggestedResponse: "\n",
1172
+ canAutoRespond: false,
1173
+ instructions: "Enter/confirm prompt detected"
1174
+ };
1175
+ }
1176
+ if (/trust|allow|permission|grant access/i.test(stripped) && /\?\s*$/m.test(stripped)) {
1177
+ return {
1178
+ detected: true,
1179
+ type: "permission",
1180
+ prompt: stripped.slice(-200),
1181
+ canAutoRespond: false,
1182
+ instructions: "Permission/trust prompt detected"
1183
+ };
1184
+ }
1185
+ const lines = stripped.split("\n").filter((l) => l.trim());
1186
+ const lastLine = lines[lines.length - 1] || "";
1187
+ if (/\?\s*$/.test(lastLine) && lastLine.length < 200) {
1188
+ return {
1189
+ detected: true,
1190
+ type: "unknown",
1191
+ prompt: lastLine.trim(),
1192
+ canAutoRespond: false,
1193
+ instructions: "Question prompt detected"
1023
1194
  };
1024
1195
  }
1025
1196
  return { detected: false };
@@ -1467,6 +1638,18 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
1467
1638
  this.resolvePending("list", sessions);
1468
1639
  break;
1469
1640
  }
1641
+ case "rules": {
1642
+ const serializedRules = event.rules;
1643
+ const rules = serializedRules.map((r) => ({
1644
+ pattern: new RegExp(r.pattern, r.flags || ""),
1645
+ type: r.type,
1646
+ response: r.response,
1647
+ description: r.description,
1648
+ safe: r.safe
1649
+ }));
1650
+ this.resolvePending(`getRules:${id}`, rules);
1651
+ break;
1652
+ }
1470
1653
  case "ack": {
1471
1654
  const cmd = event.cmd;
1472
1655
  const success = event.success;
@@ -1604,6 +1787,74 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
1604
1787
  this.on(`data:${id}`, handler);
1605
1788
  return () => this.off(`data:${id}`, handler);
1606
1789
  }
1790
+ // ─────────────────────────────────────────────────────────────────────────────
1791
+ // Runtime Auto-Response Rules API
1792
+ // ─────────────────────────────────────────────────────────────────────────────
1793
+ serializeRule(rule) {
1794
+ return {
1795
+ pattern: rule.pattern.source,
1796
+ flags: rule.pattern.flags || void 0,
1797
+ type: rule.type,
1798
+ response: rule.response,
1799
+ description: rule.description,
1800
+ safe: rule.safe
1801
+ };
1802
+ }
1803
+ /**
1804
+ * Add an auto-response rule to a session.
1805
+ * Session rules are checked before adapter rules.
1806
+ */
1807
+ async addAutoResponseRule(sessionId, rule) {
1808
+ await this.waitForReady();
1809
+ const serialized = this.serializeRule(rule);
1810
+ this.sendCommand({ cmd: "addRule", id: sessionId, rule: serialized });
1811
+ await this.createPending(`addRule:${sessionId}`);
1812
+ }
1813
+ /**
1814
+ * Remove an auto-response rule from a session by pattern.
1815
+ * Returns true if a rule was removed.
1816
+ */
1817
+ async removeAutoResponseRule(sessionId, pattern) {
1818
+ await this.waitForReady();
1819
+ this.sendCommand({
1820
+ cmd: "removeRule",
1821
+ id: sessionId,
1822
+ pattern: pattern.source,
1823
+ flags: pattern.flags || void 0
1824
+ });
1825
+ try {
1826
+ await this.createPending(`removeRule:${sessionId}`);
1827
+ return true;
1828
+ } catch {
1829
+ return false;
1830
+ }
1831
+ }
1832
+ /**
1833
+ * Set all auto-response rules for a session, replacing existing ones.
1834
+ */
1835
+ async setAutoResponseRules(sessionId, rules) {
1836
+ await this.waitForReady();
1837
+ const serialized = rules.map((r) => this.serializeRule(r));
1838
+ this.sendCommand({ cmd: "setRules", id: sessionId, rules: serialized });
1839
+ await this.createPending(`setRules:${sessionId}`);
1840
+ }
1841
+ /**
1842
+ * Get all auto-response rules for a session.
1843
+ */
1844
+ async getAutoResponseRules(sessionId) {
1845
+ await this.waitForReady();
1846
+ this.sendCommand({ cmd: "getRules", id: sessionId });
1847
+ const rules = await this.createPending(`getRules:${sessionId}`);
1848
+ return rules;
1849
+ }
1850
+ /**
1851
+ * Clear all auto-response rules for a session.
1852
+ */
1853
+ async clearAutoResponseRules(sessionId) {
1854
+ await this.waitForReady();
1855
+ this.sendCommand({ cmd: "clearRules", id: sessionId });
1856
+ await this.createPending(`clearRules:${sessionId}`);
1857
+ }
1607
1858
  /**
1608
1859
  * Shutdown the worker and all sessions
1609
1860
  */