pty-manager 1.7.3 → 1.8.0
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 +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +82 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +82 -13
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +65 -7
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -669,6 +669,15 @@ declare class PTYSession extends EventEmitter {
|
|
|
669
669
|
* @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
|
|
670
670
|
*/
|
|
671
671
|
sendKeys(keys: string | string[]): void;
|
|
672
|
+
/**
|
|
673
|
+
* Normalize a list of key names for SPECIAL_KEYS lookup.
|
|
674
|
+
*
|
|
675
|
+
* Handles two problems:
|
|
676
|
+
* 1. Modifier aliases: "control" → "ctrl", "command" → "meta", "option" → "alt"
|
|
677
|
+
* 2. Comma-separated compound keys from stall classifier: ["control", "c"] → ["ctrl+c"]
|
|
678
|
+
* A bare modifier followed by a single char/key is joined with "+".
|
|
679
|
+
*/
|
|
680
|
+
static normalizeKeyList(keys: string[]): string[];
|
|
672
681
|
/**
|
|
673
682
|
* Select a TUI menu option by index (0-based).
|
|
674
683
|
* Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
|
|
@@ -1002,6 +1011,11 @@ declare class ShellAdapter implements CLIAdapter {
|
|
|
1002
1011
|
detectLogin(_output: string): LoginDetection;
|
|
1003
1012
|
detectBlockingPrompt(_output: string): BlockingPromptDetection;
|
|
1004
1013
|
detectReady(output: string): boolean;
|
|
1014
|
+
/**
|
|
1015
|
+
* Detect shell continuation prompts that indicate the shell is NOT ready
|
|
1016
|
+
* for a new command (e.g., unclosed quote, heredoc, backtick).
|
|
1017
|
+
*/
|
|
1018
|
+
private isContinuationPrompt;
|
|
1005
1019
|
detectExit(output: string): {
|
|
1006
1020
|
exited: boolean;
|
|
1007
1021
|
code?: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -669,6 +669,15 @@ declare class PTYSession extends EventEmitter {
|
|
|
669
669
|
* @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
|
|
670
670
|
*/
|
|
671
671
|
sendKeys(keys: string | string[]): void;
|
|
672
|
+
/**
|
|
673
|
+
* Normalize a list of key names for SPECIAL_KEYS lookup.
|
|
674
|
+
*
|
|
675
|
+
* Handles two problems:
|
|
676
|
+
* 1. Modifier aliases: "control" → "ctrl", "command" → "meta", "option" → "alt"
|
|
677
|
+
* 2. Comma-separated compound keys from stall classifier: ["control", "c"] → ["ctrl+c"]
|
|
678
|
+
* A bare modifier followed by a single char/key is joined with "+".
|
|
679
|
+
*/
|
|
680
|
+
static normalizeKeyList(keys: string[]): string[];
|
|
672
681
|
/**
|
|
673
682
|
* Select a TUI menu option by index (0-based).
|
|
674
683
|
* Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
|
|
@@ -1002,6 +1011,11 @@ declare class ShellAdapter implements CLIAdapter {
|
|
|
1002
1011
|
detectLogin(_output: string): LoginDetection;
|
|
1003
1012
|
detectBlockingPrompt(_output: string): BlockingPromptDetection;
|
|
1004
1013
|
detectReady(output: string): boolean;
|
|
1014
|
+
/**
|
|
1015
|
+
* Detect shell continuation prompts that indicate the shell is NOT ready
|
|
1016
|
+
* for a new command (e.g., unclosed quote, heredoc, backtick).
|
|
1017
|
+
*/
|
|
1018
|
+
private isContinuationPrompt;
|
|
1005
1019
|
detectExit(output: string): {
|
|
1006
1020
|
exited: boolean;
|
|
1007
1021
|
code?: number;
|
package/dist/index.js
CHANGED
|
@@ -1242,24 +1242,71 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
1242
1242
|
throw new Error("Session not started");
|
|
1243
1243
|
}
|
|
1244
1244
|
const keyList = Array.isArray(keys) ? keys : [keys];
|
|
1245
|
+
const normalized = _PTYSession.normalizeKeyList(keyList);
|
|
1245
1246
|
this._stallEmissionCount = 0;
|
|
1246
1247
|
this.resetStallTimer();
|
|
1247
|
-
for (const key of
|
|
1248
|
-
const
|
|
1249
|
-
const sequence = SPECIAL_KEYS[normalizedKey];
|
|
1248
|
+
for (const key of normalized) {
|
|
1249
|
+
const sequence = SPECIAL_KEYS[key];
|
|
1250
1250
|
if (sequence) {
|
|
1251
1251
|
this._lastActivityAt = /* @__PURE__ */ new Date();
|
|
1252
1252
|
this.ptyProcess.write(sequence);
|
|
1253
|
-
this.logger.debug({ sessionId: this.id, key
|
|
1253
|
+
this.logger.debug({ sessionId: this.id, key }, "Sent special key");
|
|
1254
1254
|
} else {
|
|
1255
1255
|
this.logger.warn(
|
|
1256
|
-
{ sessionId: this.id, key
|
|
1256
|
+
{ sessionId: this.id, key },
|
|
1257
1257
|
"Unknown special key, sending as literal"
|
|
1258
1258
|
);
|
|
1259
1259
|
this.ptyProcess.write(key);
|
|
1260
1260
|
}
|
|
1261
1261
|
}
|
|
1262
1262
|
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Normalize a list of key names for SPECIAL_KEYS lookup.
|
|
1265
|
+
*
|
|
1266
|
+
* Handles two problems:
|
|
1267
|
+
* 1. Modifier aliases: "control" → "ctrl", "command" → "meta", "option" → "alt"
|
|
1268
|
+
* 2. Comma-separated compound keys from stall classifier: ["control", "c"] → ["ctrl+c"]
|
|
1269
|
+
* A bare modifier followed by a single char/key is joined with "+".
|
|
1270
|
+
*/
|
|
1271
|
+
static normalizeKeyList(keys) {
|
|
1272
|
+
const MODIFIER_MAP = {
|
|
1273
|
+
control: "ctrl",
|
|
1274
|
+
command: "meta",
|
|
1275
|
+
cmd: "meta",
|
|
1276
|
+
option: "alt",
|
|
1277
|
+
opt: "alt"
|
|
1278
|
+
};
|
|
1279
|
+
const MODIFIER_NAMES = /* @__PURE__ */ new Set([
|
|
1280
|
+
"ctrl",
|
|
1281
|
+
"alt",
|
|
1282
|
+
"shift",
|
|
1283
|
+
"meta",
|
|
1284
|
+
// Also match the aliases so we can detect them before remapping
|
|
1285
|
+
...Object.keys(MODIFIER_MAP)
|
|
1286
|
+
]);
|
|
1287
|
+
const result = [];
|
|
1288
|
+
let i = 0;
|
|
1289
|
+
while (i < keys.length) {
|
|
1290
|
+
let key = keys[i].toLowerCase().trim();
|
|
1291
|
+
if (MODIFIER_MAP[key]) {
|
|
1292
|
+
key = MODIFIER_MAP[key];
|
|
1293
|
+
}
|
|
1294
|
+
if (MODIFIER_NAMES.has(key) && i + 1 < keys.length) {
|
|
1295
|
+
let nextKey = keys[i + 1].toLowerCase().trim();
|
|
1296
|
+
if (MODIFIER_MAP[nextKey]) {
|
|
1297
|
+
nextKey = MODIFIER_MAP[nextKey];
|
|
1298
|
+
}
|
|
1299
|
+
if (!MODIFIER_NAMES.has(nextKey)) {
|
|
1300
|
+
result.push(`${key}+${nextKey}`);
|
|
1301
|
+
i += 2;
|
|
1302
|
+
continue;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
result.push(key);
|
|
1306
|
+
i++;
|
|
1307
|
+
}
|
|
1308
|
+
return result;
|
|
1309
|
+
}
|
|
1263
1310
|
/**
|
|
1264
1311
|
* Select a TUI menu option by index (0-based).
|
|
1265
1312
|
* Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
|
|
@@ -2261,7 +2308,18 @@ var ShellAdapter = class {
|
|
|
2261
2308
|
return { detected: false };
|
|
2262
2309
|
}
|
|
2263
2310
|
detectReady(output) {
|
|
2264
|
-
|
|
2311
|
+
if (this.isContinuationPrompt(output)) {
|
|
2312
|
+
return false;
|
|
2313
|
+
}
|
|
2314
|
+
return this.getPromptPattern().test(this.stripAnsi(output));
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* Detect shell continuation prompts that indicate the shell is NOT ready
|
|
2318
|
+
* for a new command (e.g., unclosed quote, heredoc, backtick).
|
|
2319
|
+
*/
|
|
2320
|
+
isContinuationPrompt(output) {
|
|
2321
|
+
const stripped = this.stripAnsi(output);
|
|
2322
|
+
return /(?:quote|dquote|heredoc|bquote|cmdsubst|pipe|then|else|do|loop)>\s*$/.test(stripped) || /(?:quote|dquote|heredoc|bquote)>\s*$/m.test(stripped);
|
|
2265
2323
|
}
|
|
2266
2324
|
detectExit(output) {
|
|
2267
2325
|
if (output.includes("exit")) {
|
|
@@ -2284,7 +2342,7 @@ var ShellAdapter = class {
|
|
|
2284
2342
|
}
|
|
2285
2343
|
getPromptPattern() {
|
|
2286
2344
|
const escaped = this.promptStr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2287
|
-
return new RegExp(`(?:${escaped}
|
|
2345
|
+
return new RegExp(`(?:${escaped}|\\$|#)\\s*$`, "m");
|
|
2288
2346
|
}
|
|
2289
2347
|
async validateInstallation() {
|
|
2290
2348
|
return { installed: true };
|
|
@@ -2380,9 +2438,6 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
|
|
|
2380
2438
|
const id = event.id;
|
|
2381
2439
|
switch (eventType) {
|
|
2382
2440
|
case "worker_ready":
|
|
2383
|
-
if (this.adapterModules.length > 0) {
|
|
2384
|
-
this.sendCommand({ cmd: "registerAdapters", modules: this.adapterModules });
|
|
2385
|
-
}
|
|
2386
2441
|
if (this._stallDetectionEnabled) {
|
|
2387
2442
|
this.sendCommand({
|
|
2388
2443
|
cmd: "configureStallDetection",
|
|
@@ -2390,9 +2445,23 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
|
|
|
2390
2445
|
timeoutMs: this._stallTimeoutMs
|
|
2391
2446
|
});
|
|
2392
2447
|
}
|
|
2393
|
-
this.
|
|
2394
|
-
|
|
2395
|
-
|
|
2448
|
+
if (this.adapterModules.length > 0) {
|
|
2449
|
+
this.sendCommand({ cmd: "registerAdapters", modules: this.adapterModules });
|
|
2450
|
+
this.createPending("registerAdapters").then(() => {
|
|
2451
|
+
this.ready = true;
|
|
2452
|
+
this.readyResolve();
|
|
2453
|
+
this.emit("ready");
|
|
2454
|
+
}).catch((err) => {
|
|
2455
|
+
this.emit("worker_error", `Failed to register adapters: ${err}`);
|
|
2456
|
+
this.ready = true;
|
|
2457
|
+
this.readyResolve();
|
|
2458
|
+
this.emit("ready");
|
|
2459
|
+
});
|
|
2460
|
+
} else {
|
|
2461
|
+
this.ready = true;
|
|
2462
|
+
this.readyResolve();
|
|
2463
|
+
this.emit("ready");
|
|
2464
|
+
}
|
|
2396
2465
|
break;
|
|
2397
2466
|
case "spawned": {
|
|
2398
2467
|
const session = {
|