pty-manager 1.7.2 → 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 +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +90 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +90 -13
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +85 -7
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1202,24 +1202,71 @@ var PTYSession = class _PTYSession extends EventEmitter {
|
|
|
1202
1202
|
throw new Error("Session not started");
|
|
1203
1203
|
}
|
|
1204
1204
|
const keyList = Array.isArray(keys) ? keys : [keys];
|
|
1205
|
+
const normalized = _PTYSession.normalizeKeyList(keyList);
|
|
1205
1206
|
this._stallEmissionCount = 0;
|
|
1206
1207
|
this.resetStallTimer();
|
|
1207
|
-
for (const key of
|
|
1208
|
-
const
|
|
1209
|
-
const sequence = SPECIAL_KEYS[normalizedKey];
|
|
1208
|
+
for (const key of normalized) {
|
|
1209
|
+
const sequence = SPECIAL_KEYS[key];
|
|
1210
1210
|
if (sequence) {
|
|
1211
1211
|
this._lastActivityAt = /* @__PURE__ */ new Date();
|
|
1212
1212
|
this.ptyProcess.write(sequence);
|
|
1213
|
-
this.logger.debug({ sessionId: this.id, key
|
|
1213
|
+
this.logger.debug({ sessionId: this.id, key }, "Sent special key");
|
|
1214
1214
|
} else {
|
|
1215
1215
|
this.logger.warn(
|
|
1216
|
-
{ sessionId: this.id, key
|
|
1216
|
+
{ sessionId: this.id, key },
|
|
1217
1217
|
"Unknown special key, sending as literal"
|
|
1218
1218
|
);
|
|
1219
1219
|
this.ptyProcess.write(key);
|
|
1220
1220
|
}
|
|
1221
1221
|
}
|
|
1222
1222
|
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Normalize a list of key names for SPECIAL_KEYS lookup.
|
|
1225
|
+
*
|
|
1226
|
+
* Handles two problems:
|
|
1227
|
+
* 1. Modifier aliases: "control" → "ctrl", "command" → "meta", "option" → "alt"
|
|
1228
|
+
* 2. Comma-separated compound keys from stall classifier: ["control", "c"] → ["ctrl+c"]
|
|
1229
|
+
* A bare modifier followed by a single char/key is joined with "+".
|
|
1230
|
+
*/
|
|
1231
|
+
static normalizeKeyList(keys) {
|
|
1232
|
+
const MODIFIER_MAP = {
|
|
1233
|
+
control: "ctrl",
|
|
1234
|
+
command: "meta",
|
|
1235
|
+
cmd: "meta",
|
|
1236
|
+
option: "alt",
|
|
1237
|
+
opt: "alt"
|
|
1238
|
+
};
|
|
1239
|
+
const MODIFIER_NAMES = /* @__PURE__ */ new Set([
|
|
1240
|
+
"ctrl",
|
|
1241
|
+
"alt",
|
|
1242
|
+
"shift",
|
|
1243
|
+
"meta",
|
|
1244
|
+
// Also match the aliases so we can detect them before remapping
|
|
1245
|
+
...Object.keys(MODIFIER_MAP)
|
|
1246
|
+
]);
|
|
1247
|
+
const result = [];
|
|
1248
|
+
let i = 0;
|
|
1249
|
+
while (i < keys.length) {
|
|
1250
|
+
let key = keys[i].toLowerCase().trim();
|
|
1251
|
+
if (MODIFIER_MAP[key]) {
|
|
1252
|
+
key = MODIFIER_MAP[key];
|
|
1253
|
+
}
|
|
1254
|
+
if (MODIFIER_NAMES.has(key) && i + 1 < keys.length) {
|
|
1255
|
+
let nextKey = keys[i + 1].toLowerCase().trim();
|
|
1256
|
+
if (MODIFIER_MAP[nextKey]) {
|
|
1257
|
+
nextKey = MODIFIER_MAP[nextKey];
|
|
1258
|
+
}
|
|
1259
|
+
if (!MODIFIER_NAMES.has(nextKey)) {
|
|
1260
|
+
result.push(`${key}+${nextKey}`);
|
|
1261
|
+
i += 2;
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
result.push(key);
|
|
1266
|
+
i++;
|
|
1267
|
+
}
|
|
1268
|
+
return result;
|
|
1269
|
+
}
|
|
1223
1270
|
/**
|
|
1224
1271
|
* Select a TUI menu option by index (0-based).
|
|
1225
1272
|
* Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
|
|
@@ -2221,7 +2268,18 @@ var ShellAdapter = class {
|
|
|
2221
2268
|
return { detected: false };
|
|
2222
2269
|
}
|
|
2223
2270
|
detectReady(output) {
|
|
2224
|
-
|
|
2271
|
+
if (this.isContinuationPrompt(output)) {
|
|
2272
|
+
return false;
|
|
2273
|
+
}
|
|
2274
|
+
return this.getPromptPattern().test(this.stripAnsi(output));
|
|
2275
|
+
}
|
|
2276
|
+
/**
|
|
2277
|
+
* Detect shell continuation prompts that indicate the shell is NOT ready
|
|
2278
|
+
* for a new command (e.g., unclosed quote, heredoc, backtick).
|
|
2279
|
+
*/
|
|
2280
|
+
isContinuationPrompt(output) {
|
|
2281
|
+
const stripped = this.stripAnsi(output);
|
|
2282
|
+
return /(?:quote|dquote|heredoc|bquote|cmdsubst|pipe|then|else|do|loop)>\s*$/.test(stripped) || /(?:quote|dquote|heredoc|bquote)>\s*$/m.test(stripped);
|
|
2225
2283
|
}
|
|
2226
2284
|
detectExit(output) {
|
|
2227
2285
|
if (output.includes("exit")) {
|
|
@@ -2244,7 +2302,7 @@ var ShellAdapter = class {
|
|
|
2244
2302
|
}
|
|
2245
2303
|
getPromptPattern() {
|
|
2246
2304
|
const escaped = this.promptStr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2247
|
-
return new RegExp(`(?:${escaped}
|
|
2305
|
+
return new RegExp(`(?:${escaped}|\\$|#)\\s*$`, "m");
|
|
2248
2306
|
}
|
|
2249
2307
|
async validateInstallation() {
|
|
2250
2308
|
return { installed: true };
|
|
@@ -2340,9 +2398,6 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
|
|
|
2340
2398
|
const id = event.id;
|
|
2341
2399
|
switch (eventType) {
|
|
2342
2400
|
case "worker_ready":
|
|
2343
|
-
if (this.adapterModules.length > 0) {
|
|
2344
|
-
this.sendCommand({ cmd: "registerAdapters", modules: this.adapterModules });
|
|
2345
|
-
}
|
|
2346
2401
|
if (this._stallDetectionEnabled) {
|
|
2347
2402
|
this.sendCommand({
|
|
2348
2403
|
cmd: "configureStallDetection",
|
|
@@ -2350,9 +2405,23 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
|
|
|
2350
2405
|
timeoutMs: this._stallTimeoutMs
|
|
2351
2406
|
});
|
|
2352
2407
|
}
|
|
2353
|
-
this.
|
|
2354
|
-
|
|
2355
|
-
|
|
2408
|
+
if (this.adapterModules.length > 0) {
|
|
2409
|
+
this.sendCommand({ cmd: "registerAdapters", modules: this.adapterModules });
|
|
2410
|
+
this.createPending("registerAdapters").then(() => {
|
|
2411
|
+
this.ready = true;
|
|
2412
|
+
this.readyResolve();
|
|
2413
|
+
this.emit("ready");
|
|
2414
|
+
}).catch((err) => {
|
|
2415
|
+
this.emit("worker_error", `Failed to register adapters: ${err}`);
|
|
2416
|
+
this.ready = true;
|
|
2417
|
+
this.readyResolve();
|
|
2418
|
+
this.emit("ready");
|
|
2419
|
+
});
|
|
2420
|
+
} else {
|
|
2421
|
+
this.ready = true;
|
|
2422
|
+
this.readyResolve();
|
|
2423
|
+
this.emit("ready");
|
|
2424
|
+
}
|
|
2356
2425
|
break;
|
|
2357
2426
|
case "spawned": {
|
|
2358
2427
|
const session = {
|
|
@@ -2594,6 +2663,14 @@ var BunCompatiblePTYManager = class extends EventEmitter3 {
|
|
|
2594
2663
|
this.sendCommand({ cmd: "sendKeys", id, keys });
|
|
2595
2664
|
await this.createPending(`sendKeys:${id}`);
|
|
2596
2665
|
}
|
|
2666
|
+
/**
|
|
2667
|
+
* Write raw data to a session (bypasses adapter formatting)
|
|
2668
|
+
*/
|
|
2669
|
+
async writeRaw(id, data) {
|
|
2670
|
+
await this.waitForReady();
|
|
2671
|
+
this.sendCommand({ cmd: "writeRaw", id, data });
|
|
2672
|
+
await this.createPending(`writeRaw:${id}`);
|
|
2673
|
+
}
|
|
2597
2674
|
/**
|
|
2598
2675
|
* Paste text to a session
|
|
2599
2676
|
*/
|