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.d.mts +70 -1
- package/dist/index.d.ts +70 -1
- package/dist/index.js +261 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +261 -8
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +235 -6
- package/package.json +1 -1
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.
|
|
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
|
|
445
|
-
|
|
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
|
|
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\]
|
|
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: "
|
|
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
|
*/
|