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.
@@ -304,6 +304,7 @@ var PTYSession = class extends import_events.EventEmitter {
304
304
  _lastActivityAt = null;
305
305
  messageCounter = 0;
306
306
  logger;
307
+ sessionRules = [];
307
308
  id;
308
309
  config;
309
310
  get status() {
@@ -318,6 +319,75 @@ var PTYSession = class extends import_events.EventEmitter {
318
319
  get lastActivityAt() {
319
320
  return this._lastActivityAt ?? void 0;
320
321
  }
322
+ // ─────────────────────────────────────────────────────────────────────────────
323
+ // Runtime Auto-Response Rules API
324
+ // ─────────────────────────────────────────────────────────────────────────────
325
+ /**
326
+ * Add an auto-response rule to this session.
327
+ * Session rules are checked before adapter rules.
328
+ */
329
+ addAutoResponseRule(rule) {
330
+ const existingIndex = this.sessionRules.findIndex(
331
+ (r) => r.pattern.source === rule.pattern.source && r.pattern.flags === rule.pattern.flags
332
+ );
333
+ if (existingIndex >= 0) {
334
+ this.sessionRules[existingIndex] = rule;
335
+ this.logger.debug(
336
+ { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },
337
+ "Replaced existing auto-response rule"
338
+ );
339
+ } else {
340
+ this.sessionRules.push(rule);
341
+ this.logger.debug(
342
+ { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },
343
+ "Added auto-response rule"
344
+ );
345
+ }
346
+ }
347
+ /**
348
+ * Remove an auto-response rule by pattern.
349
+ * Returns true if a rule was removed.
350
+ */
351
+ removeAutoResponseRule(pattern) {
352
+ const initialLength = this.sessionRules.length;
353
+ this.sessionRules = this.sessionRules.filter(
354
+ (r) => !(r.pattern.source === pattern.source && r.pattern.flags === pattern.flags)
355
+ );
356
+ const removed = this.sessionRules.length < initialLength;
357
+ if (removed) {
358
+ this.logger.debug(
359
+ { sessionId: this.id, pattern: pattern.source },
360
+ "Removed auto-response rule"
361
+ );
362
+ }
363
+ return removed;
364
+ }
365
+ /**
366
+ * Set all session auto-response rules, replacing existing ones.
367
+ */
368
+ setAutoResponseRules(rules) {
369
+ this.sessionRules = [...rules];
370
+ this.logger.debug(
371
+ { sessionId: this.id, count: rules.length },
372
+ "Set auto-response rules"
373
+ );
374
+ }
375
+ /**
376
+ * Get all session auto-response rules.
377
+ */
378
+ getAutoResponseRules() {
379
+ return [...this.sessionRules];
380
+ }
381
+ /**
382
+ * Clear all session auto-response rules.
383
+ */
384
+ clearAutoResponseRules() {
385
+ this.sessionRules = [];
386
+ this.logger.debug({ sessionId: this.id }, "Cleared auto-response rules");
387
+ }
388
+ // ─────────────────────────────────────────────────────────────────────────────
389
+ // Lifecycle
390
+ // ─────────────────────────────────────────────────────────────────────────────
321
391
  /**
322
392
  * Start the PTY session
323
393
  */
@@ -398,7 +468,9 @@ var PTYSession = class extends import_events.EventEmitter {
398
468
  this._status = "stopped";
399
469
  this.emit("exit", exitDetection.code || 0);
400
470
  }
401
- this.tryParseOutput();
471
+ if (this._status !== "starting" && this._status !== "authenticating") {
472
+ this.tryParseOutput();
473
+ }
402
474
  });
403
475
  this.ptyProcess.onExit(({ exitCode, signal }) => {
404
476
  this._status = "stopped";
@@ -459,23 +531,27 @@ var PTYSession = class extends import_events.EventEmitter {
459
531
  return false;
460
532
  }
461
533
  /**
462
- * Try to match and apply auto-response rules
534
+ * Try to match and apply auto-response rules.
535
+ * Session rules are checked first, then adapter rules.
463
536
  */
464
537
  tryAutoResponse() {
465
- const rules = this.adapter.autoResponseRules;
466
- if (!rules || rules.length === 0) {
538
+ const adapterRules = this.adapter.autoResponseRules || [];
539
+ const allRules = [...this.sessionRules, ...adapterRules];
540
+ if (allRules.length === 0) {
467
541
  return false;
468
542
  }
469
- for (const rule of rules) {
543
+ for (const rule of allRules) {
470
544
  if (rule.pattern.test(this.outputBuffer)) {
471
545
  const safe = rule.safe !== false;
546
+ const isSessionRule = this.sessionRules.includes(rule);
472
547
  if (safe) {
473
548
  this.logger.info(
474
549
  {
475
550
  sessionId: this.id,
476
551
  promptType: rule.type,
477
552
  description: rule.description,
478
- response: rule.response
553
+ response: rule.response,
554
+ source: isSessionRule ? "session" : "adapter"
479
555
  },
480
556
  "Applying auto-response rule"
481
557
  );
@@ -946,6 +1022,61 @@ var PTYManager = class extends import_events2.EventEmitter {
946
1022
  getSession(sessionId) {
947
1023
  return this.sessions.get(sessionId);
948
1024
  }
1025
+ // ─────────────────────────────────────────────────────────────────────────────
1026
+ // Runtime Auto-Response Rules API
1027
+ // ─────────────────────────────────────────────────────────────────────────────
1028
+ /**
1029
+ * Add an auto-response rule to a session.
1030
+ * Session rules are checked before adapter rules.
1031
+ */
1032
+ addAutoResponseRule(sessionId, rule) {
1033
+ const session = this.sessions.get(sessionId);
1034
+ if (!session) {
1035
+ throw new Error(`Session not found: ${sessionId}`);
1036
+ }
1037
+ session.addAutoResponseRule(rule);
1038
+ }
1039
+ /**
1040
+ * Remove an auto-response rule from a session by pattern.
1041
+ * Returns true if a rule was removed.
1042
+ */
1043
+ removeAutoResponseRule(sessionId, pattern) {
1044
+ const session = this.sessions.get(sessionId);
1045
+ if (!session) {
1046
+ throw new Error(`Session not found: ${sessionId}`);
1047
+ }
1048
+ return session.removeAutoResponseRule(pattern);
1049
+ }
1050
+ /**
1051
+ * Set all auto-response rules for a session, replacing existing ones.
1052
+ */
1053
+ setAutoResponseRules(sessionId, rules) {
1054
+ const session = this.sessions.get(sessionId);
1055
+ if (!session) {
1056
+ throw new Error(`Session not found: ${sessionId}`);
1057
+ }
1058
+ session.setAutoResponseRules(rules);
1059
+ }
1060
+ /**
1061
+ * Get all auto-response rules for a session.
1062
+ */
1063
+ getAutoResponseRules(sessionId) {
1064
+ const session = this.sessions.get(sessionId);
1065
+ if (!session) {
1066
+ throw new Error(`Session not found: ${sessionId}`);
1067
+ }
1068
+ return session.getAutoResponseRules();
1069
+ }
1070
+ /**
1071
+ * Clear all auto-response rules for a session.
1072
+ */
1073
+ clearAutoResponseRules(sessionId) {
1074
+ const session = this.sessions.get(sessionId);
1075
+ if (!session) {
1076
+ throw new Error(`Session not found: ${sessionId}`);
1077
+ }
1078
+ session.clearAutoResponseRules();
1079
+ }
949
1080
  };
950
1081
 
951
1082
  // src/adapters/shell-adapter.ts
@@ -1209,6 +1340,69 @@ function handleRegisterAdapters(modules) {
1209
1340
  ack("registerAdapters", void 0, false, err instanceof Error ? err.message : String(err));
1210
1341
  }
1211
1342
  }
1343
+ function deserializeRule(serialized) {
1344
+ return {
1345
+ pattern: new RegExp(serialized.pattern, serialized.flags || ""),
1346
+ type: serialized.type,
1347
+ response: serialized.response,
1348
+ description: serialized.description,
1349
+ safe: serialized.safe
1350
+ };
1351
+ }
1352
+ function serializeRule(rule) {
1353
+ return {
1354
+ pattern: rule.pattern.source,
1355
+ flags: rule.pattern.flags || void 0,
1356
+ type: rule.type,
1357
+ response: rule.response,
1358
+ description: rule.description,
1359
+ safe: rule.safe
1360
+ };
1361
+ }
1362
+ function handleAddRule(id, serializedRule) {
1363
+ try {
1364
+ const rule = deserializeRule(serializedRule);
1365
+ manager.addAutoResponseRule(id, rule);
1366
+ ack("addRule", id, true);
1367
+ } catch (err) {
1368
+ ack("addRule", id, false, err instanceof Error ? err.message : String(err));
1369
+ }
1370
+ }
1371
+ function handleRemoveRule(id, pattern, flags) {
1372
+ try {
1373
+ const regex = new RegExp(pattern, flags || "");
1374
+ const removed = manager.removeAutoResponseRule(id, regex);
1375
+ ack("removeRule", id, removed, removed ? void 0 : "Rule not found");
1376
+ } catch (err) {
1377
+ ack("removeRule", id, false, err instanceof Error ? err.message : String(err));
1378
+ }
1379
+ }
1380
+ function handleSetRules(id, serializedRules) {
1381
+ try {
1382
+ const rules = serializedRules.map(deserializeRule);
1383
+ manager.setAutoResponseRules(id, rules);
1384
+ ack("setRules", id, true);
1385
+ } catch (err) {
1386
+ ack("setRules", id, false, err instanceof Error ? err.message : String(err));
1387
+ }
1388
+ }
1389
+ function handleGetRules(id) {
1390
+ try {
1391
+ const rules = manager.getAutoResponseRules(id);
1392
+ const serialized = rules.map(serializeRule);
1393
+ emit({ event: "rules", id, rules: serialized });
1394
+ } catch (err) {
1395
+ emit({ event: "error", id, message: err instanceof Error ? err.message : String(err) });
1396
+ }
1397
+ }
1398
+ function handleClearRules(id) {
1399
+ try {
1400
+ manager.clearAutoResponseRules(id);
1401
+ ack("clearRules", id, true);
1402
+ } catch (err) {
1403
+ ack("clearRules", id, false, err instanceof Error ? err.message : String(err));
1404
+ }
1405
+ }
1212
1406
  function processCommand(line) {
1213
1407
  let command;
1214
1408
  try {
@@ -1273,6 +1467,41 @@ function processCommand(line) {
1273
1467
  }
1274
1468
  handleRegisterAdapters(command.modules);
1275
1469
  break;
1470
+ case "addRule":
1471
+ if (!command.id || !command.rule) {
1472
+ ack("addRule", command.id, false, "Missing id or rule");
1473
+ return;
1474
+ }
1475
+ handleAddRule(command.id, command.rule);
1476
+ break;
1477
+ case "removeRule":
1478
+ if (!command.id || !command.pattern) {
1479
+ ack("removeRule", command.id, false, "Missing id or pattern");
1480
+ return;
1481
+ }
1482
+ handleRemoveRule(command.id, command.pattern, command.flags);
1483
+ break;
1484
+ case "setRules":
1485
+ if (!command.id || !command.rules) {
1486
+ ack("setRules", command.id, false, "Missing id or rules");
1487
+ return;
1488
+ }
1489
+ handleSetRules(command.id, command.rules);
1490
+ break;
1491
+ case "getRules":
1492
+ if (!command.id) {
1493
+ ack("getRules", command.id, false, "Missing id");
1494
+ return;
1495
+ }
1496
+ handleGetRules(command.id);
1497
+ break;
1498
+ case "clearRules":
1499
+ if (!command.id) {
1500
+ ack("clearRules", command.id, false, "Missing id");
1501
+ return;
1502
+ }
1503
+ handleClearRules(command.id);
1504
+ break;
1276
1505
  default:
1277
1506
  emit({ event: "error", message: `Unknown command: ${command.cmd}` });
1278
1507
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pty-manager",
3
- "version": "1.2.5",
3
+ "version": "1.2.8",
4
4
  "description": "PTY session manager with lifecycle management, pluggable adapters, and blocking prompt detection",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",