pty-manager 1.1.0 → 1.2.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/README.md +65 -0
- package/dist/index.d.mts +112 -1
- package/dist/index.d.ts +112 -1
- package/dist/index.js +315 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +301 -1
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +1206 -0
- package/package.json +10 -1
- package/scripts/postinstall.js +33 -0
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ PTY session manager with lifecycle management, pluggable adapters, and blocking
|
|
|
11
11
|
- **Terminal attachment** - Attach to sessions for raw I/O streaming
|
|
12
12
|
- **Special key support** - Send Ctrl, Alt, Shift, and function key combinations via `sendKeys()`
|
|
13
13
|
- **Bracketed paste** - Proper paste handling with bracketed paste mode support
|
|
14
|
+
- **Bun compatible** - Worker-based adapter for non-Node runtimes like Bun
|
|
14
15
|
- **Event-driven** - Rich event system for session lifecycle
|
|
15
16
|
- **TypeScript-first** - Full type definitions included
|
|
16
17
|
|
|
@@ -310,6 +311,70 @@ console.log(SPECIAL_KEYS['up']); // '\x1b[A'
|
|
|
310
311
|
console.log(Object.keys(SPECIAL_KEYS).length); // 130+
|
|
311
312
|
```
|
|
312
313
|
|
|
314
|
+
## Bun Compatibility
|
|
315
|
+
|
|
316
|
+
Since Bun doesn't fully support Node.js native addons like `node-pty`, this package includes a worker-based solution that spawns a Node.js child process to handle PTY operations.
|
|
317
|
+
|
|
318
|
+
### BunCompatiblePTYManager
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { BunCompatiblePTYManager, isBun } from 'pty-manager';
|
|
322
|
+
|
|
323
|
+
// Create manager (works from Bun or Node.js)
|
|
324
|
+
const manager = new BunCompatiblePTYManager({
|
|
325
|
+
nodePath: 'node', // Path to Node.js executable
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Wait for worker to be ready
|
|
329
|
+
await manager.waitForReady();
|
|
330
|
+
|
|
331
|
+
// Spawn a session
|
|
332
|
+
const session = await manager.spawn({
|
|
333
|
+
id: 'my-session',
|
|
334
|
+
name: 'shell',
|
|
335
|
+
type: 'shell',
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Listen for output
|
|
339
|
+
manager.onSessionData('my-session', (data) => {
|
|
340
|
+
console.log('Output:', data);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Send commands
|
|
344
|
+
await manager.send('my-session', 'echo "Hello from Bun!"\n');
|
|
345
|
+
|
|
346
|
+
// Send special keys
|
|
347
|
+
await manager.sendKeys('my-session', 'ctrl+c');
|
|
348
|
+
|
|
349
|
+
// Paste with bracketed paste mode
|
|
350
|
+
await manager.paste('my-session', 'some text');
|
|
351
|
+
|
|
352
|
+
// Shutdown
|
|
353
|
+
await manager.shutdown();
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### How it works
|
|
357
|
+
|
|
358
|
+
1. `BunCompatiblePTYManager` spawns a Node.js child process running `pty-worker.js`
|
|
359
|
+
2. Commands are sent as JSON over stdin
|
|
360
|
+
3. Events (output, ready, exit) come back as JSON over stdout
|
|
361
|
+
4. The worker uses the full `PTYManager` internally
|
|
362
|
+
|
|
363
|
+
### Worker Protocol
|
|
364
|
+
|
|
365
|
+
Commands (stdin → worker):
|
|
366
|
+
- `{ "cmd": "spawn", "id": "...", "config": {...} }`
|
|
367
|
+
- `{ "cmd": "send", "id": "...", "data": "..." }`
|
|
368
|
+
- `{ "cmd": "sendKeys", "id": "...", "keys": ["ctrl+c"] }`
|
|
369
|
+
- `{ "cmd": "kill", "id": "..." }`
|
|
370
|
+
- `{ "cmd": "list" }`
|
|
371
|
+
- `{ "cmd": "shutdown" }`
|
|
372
|
+
|
|
373
|
+
Events (worker → stdout):
|
|
374
|
+
- `{ "event": "output", "id": "...", "data": "..." }`
|
|
375
|
+
- `{ "event": "ready", "id": "..." }`
|
|
376
|
+
- `{ "event": "exit", "id": "...", "code": 0 }`
|
|
377
|
+
|
|
313
378
|
## Built-in Adapters
|
|
314
379
|
|
|
315
380
|
### ShellAdapter
|
package/dist/index.d.mts
CHANGED
|
@@ -669,4 +669,115 @@ declare class ShellAdapter implements CLIAdapter {
|
|
|
669
669
|
private stripAnsi;
|
|
670
670
|
}
|
|
671
671
|
|
|
672
|
-
|
|
672
|
+
/**
|
|
673
|
+
* Bun-Compatible PTY Manager
|
|
674
|
+
*
|
|
675
|
+
* A wrapper that spawns a Node.js worker process to handle PTY operations,
|
|
676
|
+
* allowing pty-manager to work from Bun or other non-Node runtimes.
|
|
677
|
+
*/
|
|
678
|
+
|
|
679
|
+
interface WorkerSessionHandle {
|
|
680
|
+
id: string;
|
|
681
|
+
pid: number | undefined;
|
|
682
|
+
status: 'starting' | 'ready' | 'stopped' | 'error';
|
|
683
|
+
cols: number;
|
|
684
|
+
rows: number;
|
|
685
|
+
}
|
|
686
|
+
interface BunPTYManagerOptions {
|
|
687
|
+
/** Path to node executable (default: 'node') */
|
|
688
|
+
nodePath?: string;
|
|
689
|
+
/** Path to worker script (default: auto-detected) */
|
|
690
|
+
workerPath?: string;
|
|
691
|
+
/** Environment variables for worker process */
|
|
692
|
+
env?: Record<string, string>;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* PTY Manager that works with Bun and other non-Node runtimes
|
|
696
|
+
* by spawning a Node.js worker process.
|
|
697
|
+
*/
|
|
698
|
+
declare class BunCompatiblePTYManager extends EventEmitter {
|
|
699
|
+
private worker;
|
|
700
|
+
private sessions;
|
|
701
|
+
private pending;
|
|
702
|
+
private ready;
|
|
703
|
+
private readyPromise;
|
|
704
|
+
private readyResolve;
|
|
705
|
+
private nodePath;
|
|
706
|
+
private workerPath;
|
|
707
|
+
private env;
|
|
708
|
+
constructor(options?: BunPTYManagerOptions);
|
|
709
|
+
private findWorkerPath;
|
|
710
|
+
private startWorker;
|
|
711
|
+
private handleWorkerMessage;
|
|
712
|
+
private sendCommand;
|
|
713
|
+
private createPending;
|
|
714
|
+
private resolvePending;
|
|
715
|
+
/**
|
|
716
|
+
* Wait for the worker to be ready
|
|
717
|
+
*/
|
|
718
|
+
waitForReady(): Promise<void>;
|
|
719
|
+
/**
|
|
720
|
+
* Check if worker is ready
|
|
721
|
+
*/
|
|
722
|
+
isReady(): boolean;
|
|
723
|
+
/**
|
|
724
|
+
* Spawn a new PTY session
|
|
725
|
+
*/
|
|
726
|
+
spawn(config: SpawnConfig & {
|
|
727
|
+
id: string;
|
|
728
|
+
}): Promise<WorkerSessionHandle>;
|
|
729
|
+
/**
|
|
730
|
+
* Send data to a session
|
|
731
|
+
*/
|
|
732
|
+
send(id: string, data: string): Promise<void>;
|
|
733
|
+
/**
|
|
734
|
+
* Send special keys to a session
|
|
735
|
+
*/
|
|
736
|
+
sendKeys(id: string, keys: string | string[]): Promise<void>;
|
|
737
|
+
/**
|
|
738
|
+
* Paste text to a session
|
|
739
|
+
*/
|
|
740
|
+
paste(id: string, text: string, bracketed?: boolean): Promise<void>;
|
|
741
|
+
/**
|
|
742
|
+
* Resize a session
|
|
743
|
+
*/
|
|
744
|
+
resize(id: string, cols: number, rows: number): Promise<void>;
|
|
745
|
+
/**
|
|
746
|
+
* Kill a session
|
|
747
|
+
*/
|
|
748
|
+
kill(id: string, signal?: string): Promise<void>;
|
|
749
|
+
/**
|
|
750
|
+
* Get a session by ID
|
|
751
|
+
*/
|
|
752
|
+
get(id: string): WorkerSessionHandle | undefined;
|
|
753
|
+
/**
|
|
754
|
+
* List all sessions
|
|
755
|
+
*/
|
|
756
|
+
list(): Promise<WorkerSessionHandle[]>;
|
|
757
|
+
/**
|
|
758
|
+
* Check if a session exists
|
|
759
|
+
*/
|
|
760
|
+
has(id: string): boolean;
|
|
761
|
+
/**
|
|
762
|
+
* Subscribe to output from a specific session
|
|
763
|
+
*/
|
|
764
|
+
onSessionData(id: string, callback: (data: string) => void): () => void;
|
|
765
|
+
/**
|
|
766
|
+
* Shutdown the worker and all sessions
|
|
767
|
+
*/
|
|
768
|
+
shutdown(): Promise<void>;
|
|
769
|
+
/**
|
|
770
|
+
* Restart the worker process
|
|
771
|
+
*/
|
|
772
|
+
restart(): Promise<void>;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Detect if running in Bun
|
|
776
|
+
*/
|
|
777
|
+
declare function isBun(): boolean;
|
|
778
|
+
/**
|
|
779
|
+
* Create the appropriate PTY manager based on runtime
|
|
780
|
+
*/
|
|
781
|
+
declare function createPTYManager(options?: BunPTYManagerOptions): BunCompatiblePTYManager;
|
|
782
|
+
|
|
783
|
+
export { type AdapterFactoryConfig, AdapterRegistry, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptInfo, type BlockingPromptType, BunCompatiblePTYManager, type BunPTYManagerOptions, type CLIAdapter, type LogOptions, type Logger, type LoginDetection, type MessageType, PTYManager, type PTYManagerConfig, type PTYManagerEvents, PTYSession, type PTYSessionEvents, type ParsedOutput, SPECIAL_KEYS, type SessionFilter, type SessionHandle, type SessionMessage, type SessionStatus, ShellAdapter, type ShellAdapterOptions, type SpawnConfig, type StopOptions, type TerminalAttachment, type WorkerSessionHandle, createAdapter, createPTYManager, isBun };
|
package/dist/index.d.ts
CHANGED
|
@@ -669,4 +669,115 @@ declare class ShellAdapter implements CLIAdapter {
|
|
|
669
669
|
private stripAnsi;
|
|
670
670
|
}
|
|
671
671
|
|
|
672
|
-
|
|
672
|
+
/**
|
|
673
|
+
* Bun-Compatible PTY Manager
|
|
674
|
+
*
|
|
675
|
+
* A wrapper that spawns a Node.js worker process to handle PTY operations,
|
|
676
|
+
* allowing pty-manager to work from Bun or other non-Node runtimes.
|
|
677
|
+
*/
|
|
678
|
+
|
|
679
|
+
interface WorkerSessionHandle {
|
|
680
|
+
id: string;
|
|
681
|
+
pid: number | undefined;
|
|
682
|
+
status: 'starting' | 'ready' | 'stopped' | 'error';
|
|
683
|
+
cols: number;
|
|
684
|
+
rows: number;
|
|
685
|
+
}
|
|
686
|
+
interface BunPTYManagerOptions {
|
|
687
|
+
/** Path to node executable (default: 'node') */
|
|
688
|
+
nodePath?: string;
|
|
689
|
+
/** Path to worker script (default: auto-detected) */
|
|
690
|
+
workerPath?: string;
|
|
691
|
+
/** Environment variables for worker process */
|
|
692
|
+
env?: Record<string, string>;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* PTY Manager that works with Bun and other non-Node runtimes
|
|
696
|
+
* by spawning a Node.js worker process.
|
|
697
|
+
*/
|
|
698
|
+
declare class BunCompatiblePTYManager extends EventEmitter {
|
|
699
|
+
private worker;
|
|
700
|
+
private sessions;
|
|
701
|
+
private pending;
|
|
702
|
+
private ready;
|
|
703
|
+
private readyPromise;
|
|
704
|
+
private readyResolve;
|
|
705
|
+
private nodePath;
|
|
706
|
+
private workerPath;
|
|
707
|
+
private env;
|
|
708
|
+
constructor(options?: BunPTYManagerOptions);
|
|
709
|
+
private findWorkerPath;
|
|
710
|
+
private startWorker;
|
|
711
|
+
private handleWorkerMessage;
|
|
712
|
+
private sendCommand;
|
|
713
|
+
private createPending;
|
|
714
|
+
private resolvePending;
|
|
715
|
+
/**
|
|
716
|
+
* Wait for the worker to be ready
|
|
717
|
+
*/
|
|
718
|
+
waitForReady(): Promise<void>;
|
|
719
|
+
/**
|
|
720
|
+
* Check if worker is ready
|
|
721
|
+
*/
|
|
722
|
+
isReady(): boolean;
|
|
723
|
+
/**
|
|
724
|
+
* Spawn a new PTY session
|
|
725
|
+
*/
|
|
726
|
+
spawn(config: SpawnConfig & {
|
|
727
|
+
id: string;
|
|
728
|
+
}): Promise<WorkerSessionHandle>;
|
|
729
|
+
/**
|
|
730
|
+
* Send data to a session
|
|
731
|
+
*/
|
|
732
|
+
send(id: string, data: string): Promise<void>;
|
|
733
|
+
/**
|
|
734
|
+
* Send special keys to a session
|
|
735
|
+
*/
|
|
736
|
+
sendKeys(id: string, keys: string | string[]): Promise<void>;
|
|
737
|
+
/**
|
|
738
|
+
* Paste text to a session
|
|
739
|
+
*/
|
|
740
|
+
paste(id: string, text: string, bracketed?: boolean): Promise<void>;
|
|
741
|
+
/**
|
|
742
|
+
* Resize a session
|
|
743
|
+
*/
|
|
744
|
+
resize(id: string, cols: number, rows: number): Promise<void>;
|
|
745
|
+
/**
|
|
746
|
+
* Kill a session
|
|
747
|
+
*/
|
|
748
|
+
kill(id: string, signal?: string): Promise<void>;
|
|
749
|
+
/**
|
|
750
|
+
* Get a session by ID
|
|
751
|
+
*/
|
|
752
|
+
get(id: string): WorkerSessionHandle | undefined;
|
|
753
|
+
/**
|
|
754
|
+
* List all sessions
|
|
755
|
+
*/
|
|
756
|
+
list(): Promise<WorkerSessionHandle[]>;
|
|
757
|
+
/**
|
|
758
|
+
* Check if a session exists
|
|
759
|
+
*/
|
|
760
|
+
has(id: string): boolean;
|
|
761
|
+
/**
|
|
762
|
+
* Subscribe to output from a specific session
|
|
763
|
+
*/
|
|
764
|
+
onSessionData(id: string, callback: (data: string) => void): () => void;
|
|
765
|
+
/**
|
|
766
|
+
* Shutdown the worker and all sessions
|
|
767
|
+
*/
|
|
768
|
+
shutdown(): Promise<void>;
|
|
769
|
+
/**
|
|
770
|
+
* Restart the worker process
|
|
771
|
+
*/
|
|
772
|
+
restart(): Promise<void>;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Detect if running in Bun
|
|
776
|
+
*/
|
|
777
|
+
declare function isBun(): boolean;
|
|
778
|
+
/**
|
|
779
|
+
* Create the appropriate PTY manager based on runtime
|
|
780
|
+
*/
|
|
781
|
+
declare function createPTYManager(options?: BunPTYManagerOptions): BunCompatiblePTYManager;
|
|
782
|
+
|
|
783
|
+
export { type AdapterFactoryConfig, AdapterRegistry, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptInfo, type BlockingPromptType, BunCompatiblePTYManager, type BunPTYManagerOptions, type CLIAdapter, type LogOptions, type Logger, type LoginDetection, type MessageType, PTYManager, type PTYManagerConfig, type PTYManagerEvents, PTYSession, type PTYSessionEvents, type ParsedOutput, SPECIAL_KEYS, type SessionFilter, type SessionHandle, type SessionMessage, type SessionStatus, ShellAdapter, type ShellAdapterOptions, type SpawnConfig, type StopOptions, type TerminalAttachment, type WorkerSessionHandle, createAdapter, createPTYManager, isBun };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -22,11 +32,14 @@ var index_exports = {};
|
|
|
22
32
|
__export(index_exports, {
|
|
23
33
|
AdapterRegistry: () => AdapterRegistry,
|
|
24
34
|
BaseCLIAdapter: () => BaseCLIAdapter,
|
|
35
|
+
BunCompatiblePTYManager: () => BunCompatiblePTYManager,
|
|
25
36
|
PTYManager: () => PTYManager,
|
|
26
37
|
PTYSession: () => PTYSession,
|
|
27
38
|
SPECIAL_KEYS: () => SPECIAL_KEYS,
|
|
28
39
|
ShellAdapter: () => ShellAdapter,
|
|
29
|
-
createAdapter: () => createAdapter
|
|
40
|
+
createAdapter: () => createAdapter,
|
|
41
|
+
createPTYManager: () => createPTYManager,
|
|
42
|
+
isBun: () => isBun
|
|
30
43
|
});
|
|
31
44
|
module.exports = __toCommonJS(index_exports);
|
|
32
45
|
|
|
@@ -1309,14 +1322,314 @@ var ShellAdapter = class {
|
|
|
1309
1322
|
return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
1310
1323
|
}
|
|
1311
1324
|
};
|
|
1325
|
+
|
|
1326
|
+
// src/bun-compat.ts
|
|
1327
|
+
var import_child_process2 = require("child_process");
|
|
1328
|
+
var import_events3 = require("events");
|
|
1329
|
+
var path = __toESM(require("path"));
|
|
1330
|
+
var readline = __toESM(require("readline"));
|
|
1331
|
+
var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
|
|
1332
|
+
worker = null;
|
|
1333
|
+
sessions = /* @__PURE__ */ new Map();
|
|
1334
|
+
pending = /* @__PURE__ */ new Map();
|
|
1335
|
+
ready = false;
|
|
1336
|
+
readyPromise;
|
|
1337
|
+
readyResolve;
|
|
1338
|
+
nodePath;
|
|
1339
|
+
workerPath;
|
|
1340
|
+
env;
|
|
1341
|
+
constructor(options = {}) {
|
|
1342
|
+
super();
|
|
1343
|
+
this.nodePath = options.nodePath || "node";
|
|
1344
|
+
this.workerPath = options.workerPath || this.findWorkerPath();
|
|
1345
|
+
this.env = options.env || {};
|
|
1346
|
+
this.readyPromise = new Promise((resolve) => {
|
|
1347
|
+
this.readyResolve = resolve;
|
|
1348
|
+
});
|
|
1349
|
+
this.startWorker();
|
|
1350
|
+
}
|
|
1351
|
+
findWorkerPath() {
|
|
1352
|
+
const possiblePaths = [
|
|
1353
|
+
path.join(__dirname, "pty-worker.js"),
|
|
1354
|
+
path.join(__dirname, "..", "dist", "pty-worker.js"),
|
|
1355
|
+
path.join(__dirname, "..", "src", "pty-worker.js")
|
|
1356
|
+
];
|
|
1357
|
+
return possiblePaths[0];
|
|
1358
|
+
}
|
|
1359
|
+
startWorker() {
|
|
1360
|
+
this.worker = (0, import_child_process2.spawn)(this.nodePath, [this.workerPath], {
|
|
1361
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1362
|
+
env: { ...process.env, ...this.env }
|
|
1363
|
+
});
|
|
1364
|
+
if (!this.worker.stdout || !this.worker.stdin) {
|
|
1365
|
+
throw new Error("Failed to create worker process pipes");
|
|
1366
|
+
}
|
|
1367
|
+
const rl = readline.createInterface({
|
|
1368
|
+
input: this.worker.stdout,
|
|
1369
|
+
terminal: false
|
|
1370
|
+
});
|
|
1371
|
+
rl.on("line", (line) => this.handleWorkerMessage(line));
|
|
1372
|
+
this.worker.stderr?.on("data", (data) => {
|
|
1373
|
+
this.emit("worker_error", data.toString());
|
|
1374
|
+
});
|
|
1375
|
+
this.worker.on("exit", (code, signal) => {
|
|
1376
|
+
this.ready = false;
|
|
1377
|
+
this.worker = null;
|
|
1378
|
+
this.emit("worker_exit", { code, signal });
|
|
1379
|
+
for (const [key, op] of this.pending) {
|
|
1380
|
+
clearTimeout(op.timeout);
|
|
1381
|
+
op.reject(new Error("Worker process exited"));
|
|
1382
|
+
this.pending.delete(key);
|
|
1383
|
+
}
|
|
1384
|
+
for (const session of this.sessions.values()) {
|
|
1385
|
+
session.status = "stopped";
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1388
|
+
this.worker.on("error", (err) => {
|
|
1389
|
+
this.emit("worker_error", err);
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
handleWorkerMessage(line) {
|
|
1393
|
+
let event;
|
|
1394
|
+
try {
|
|
1395
|
+
event = JSON.parse(line);
|
|
1396
|
+
} catch {
|
|
1397
|
+
this.emit("worker_error", `Invalid JSON from worker: ${line}`);
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const eventType = event.event;
|
|
1401
|
+
const id = event.id;
|
|
1402
|
+
switch (eventType) {
|
|
1403
|
+
case "worker_ready":
|
|
1404
|
+
this.ready = true;
|
|
1405
|
+
this.readyResolve();
|
|
1406
|
+
this.emit("ready");
|
|
1407
|
+
break;
|
|
1408
|
+
case "spawned": {
|
|
1409
|
+
const session = {
|
|
1410
|
+
id,
|
|
1411
|
+
pid: event.pid,
|
|
1412
|
+
status: "starting",
|
|
1413
|
+
cols: 80,
|
|
1414
|
+
rows: 24
|
|
1415
|
+
};
|
|
1416
|
+
this.sessions.set(id, session);
|
|
1417
|
+
this.emit("session_started", session);
|
|
1418
|
+
break;
|
|
1419
|
+
}
|
|
1420
|
+
case "output":
|
|
1421
|
+
this.emit("data", { id, data: event.data });
|
|
1422
|
+
this.emit(`data:${id}`, event.data);
|
|
1423
|
+
break;
|
|
1424
|
+
case "ready": {
|
|
1425
|
+
const session = this.sessions.get(id);
|
|
1426
|
+
if (session) {
|
|
1427
|
+
session.status = "ready";
|
|
1428
|
+
this.emit("session_ready", session);
|
|
1429
|
+
}
|
|
1430
|
+
break;
|
|
1431
|
+
}
|
|
1432
|
+
case "exit": {
|
|
1433
|
+
const session = this.sessions.get(id);
|
|
1434
|
+
if (session) {
|
|
1435
|
+
session.status = "stopped";
|
|
1436
|
+
this.emit("session_stopped", session, event.code, event.signal);
|
|
1437
|
+
this.sessions.delete(id);
|
|
1438
|
+
}
|
|
1439
|
+
break;
|
|
1440
|
+
}
|
|
1441
|
+
case "error":
|
|
1442
|
+
if (id) {
|
|
1443
|
+
const session = this.sessions.get(id);
|
|
1444
|
+
if (session) {
|
|
1445
|
+
session.status = "error";
|
|
1446
|
+
}
|
|
1447
|
+
this.emit("session_error", { id, error: event.message });
|
|
1448
|
+
} else {
|
|
1449
|
+
this.emit("worker_error", event.message);
|
|
1450
|
+
}
|
|
1451
|
+
break;
|
|
1452
|
+
case "list":
|
|
1453
|
+
this.resolvePending("list", event.sessions);
|
|
1454
|
+
break;
|
|
1455
|
+
case "ack": {
|
|
1456
|
+
const cmd = event.cmd;
|
|
1457
|
+
const success = event.success;
|
|
1458
|
+
const pendingKey = id ? `${cmd}:${id}` : cmd;
|
|
1459
|
+
const pending = this.pending.get(pendingKey);
|
|
1460
|
+
if (pending) {
|
|
1461
|
+
clearTimeout(pending.timeout);
|
|
1462
|
+
this.pending.delete(pendingKey);
|
|
1463
|
+
if (success) {
|
|
1464
|
+
pending.resolve(true);
|
|
1465
|
+
} else {
|
|
1466
|
+
pending.reject(new Error(event.error));
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
break;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
sendCommand(cmd) {
|
|
1474
|
+
if (!this.worker?.stdin) {
|
|
1475
|
+
throw new Error("Worker not available");
|
|
1476
|
+
}
|
|
1477
|
+
this.worker.stdin.write(JSON.stringify(cmd) + "\n");
|
|
1478
|
+
}
|
|
1479
|
+
createPending(key, timeoutMs = 3e4) {
|
|
1480
|
+
return new Promise((resolve, reject) => {
|
|
1481
|
+
const timeout = setTimeout(() => {
|
|
1482
|
+
this.pending.delete(key);
|
|
1483
|
+
reject(new Error(`Operation ${key} timed out`));
|
|
1484
|
+
}, timeoutMs);
|
|
1485
|
+
this.pending.set(key, { resolve, reject, timeout });
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
resolvePending(key, value) {
|
|
1489
|
+
const pending = this.pending.get(key);
|
|
1490
|
+
if (pending) {
|
|
1491
|
+
clearTimeout(pending.timeout);
|
|
1492
|
+
this.pending.delete(key);
|
|
1493
|
+
pending.resolve(value);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Wait for the worker to be ready
|
|
1498
|
+
*/
|
|
1499
|
+
async waitForReady() {
|
|
1500
|
+
return this.readyPromise;
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Check if worker is ready
|
|
1504
|
+
*/
|
|
1505
|
+
isReady() {
|
|
1506
|
+
return this.ready;
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Spawn a new PTY session
|
|
1510
|
+
*/
|
|
1511
|
+
async spawn(config) {
|
|
1512
|
+
await this.waitForReady();
|
|
1513
|
+
const { id } = config;
|
|
1514
|
+
this.sendCommand({ cmd: "spawn", id, config });
|
|
1515
|
+
await this.createPending(`spawn:${id}`);
|
|
1516
|
+
return this.sessions.get(id);
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Send data to a session
|
|
1520
|
+
*/
|
|
1521
|
+
async send(id, data) {
|
|
1522
|
+
await this.waitForReady();
|
|
1523
|
+
this.sendCommand({ cmd: "send", id, data });
|
|
1524
|
+
await this.createPending(`send:${id}`);
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Send special keys to a session
|
|
1528
|
+
*/
|
|
1529
|
+
async sendKeys(id, keys) {
|
|
1530
|
+
await this.waitForReady();
|
|
1531
|
+
this.sendCommand({ cmd: "sendKeys", id, keys });
|
|
1532
|
+
await this.createPending(`sendKeys:${id}`);
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* Paste text to a session
|
|
1536
|
+
*/
|
|
1537
|
+
async paste(id, text, bracketed = true) {
|
|
1538
|
+
await this.waitForReady();
|
|
1539
|
+
this.sendCommand({ cmd: "paste", id, text, bracketed });
|
|
1540
|
+
await this.createPending(`paste:${id}`);
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Resize a session
|
|
1544
|
+
*/
|
|
1545
|
+
async resize(id, cols, rows) {
|
|
1546
|
+
await this.waitForReady();
|
|
1547
|
+
this.sendCommand({ cmd: "resize", id, cols, rows });
|
|
1548
|
+
const session = this.sessions.get(id);
|
|
1549
|
+
if (session) {
|
|
1550
|
+
session.cols = cols;
|
|
1551
|
+
session.rows = rows;
|
|
1552
|
+
}
|
|
1553
|
+
await this.createPending(`resize:${id}`);
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* Kill a session
|
|
1557
|
+
*/
|
|
1558
|
+
async kill(id, signal) {
|
|
1559
|
+
await this.waitForReady();
|
|
1560
|
+
this.sendCommand({ cmd: "kill", id, signal });
|
|
1561
|
+
await this.createPending(`kill:${id}`);
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Get a session by ID
|
|
1565
|
+
*/
|
|
1566
|
+
get(id) {
|
|
1567
|
+
return this.sessions.get(id);
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* List all sessions
|
|
1571
|
+
*/
|
|
1572
|
+
async list() {
|
|
1573
|
+
await this.waitForReady();
|
|
1574
|
+
this.sendCommand({ cmd: "list" });
|
|
1575
|
+
const sessions = await this.createPending("list");
|
|
1576
|
+
return sessions;
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Check if a session exists
|
|
1580
|
+
*/
|
|
1581
|
+
has(id) {
|
|
1582
|
+
return this.sessions.has(id);
|
|
1583
|
+
}
|
|
1584
|
+
/**
|
|
1585
|
+
* Subscribe to output from a specific session
|
|
1586
|
+
*/
|
|
1587
|
+
onSessionData(id, callback) {
|
|
1588
|
+
const handler = (data) => callback(data);
|
|
1589
|
+
this.on(`data:${id}`, handler);
|
|
1590
|
+
return () => this.off(`data:${id}`, handler);
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Shutdown the worker and all sessions
|
|
1594
|
+
*/
|
|
1595
|
+
async shutdown() {
|
|
1596
|
+
if (!this.worker) return;
|
|
1597
|
+
this.sendCommand({ cmd: "shutdown" });
|
|
1598
|
+
await this.createPending("shutdown", 1e4).catch(() => {
|
|
1599
|
+
this.worker?.kill("SIGKILL");
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Restart the worker process
|
|
1604
|
+
*/
|
|
1605
|
+
async restart() {
|
|
1606
|
+
await this.shutdown();
|
|
1607
|
+
this.sessions.clear();
|
|
1608
|
+
this.ready = false;
|
|
1609
|
+
this.readyPromise = new Promise((resolve) => {
|
|
1610
|
+
this.readyResolve = resolve;
|
|
1611
|
+
});
|
|
1612
|
+
this.startWorker();
|
|
1613
|
+
await this.waitForReady();
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
function isBun() {
|
|
1617
|
+
return typeof process !== "undefined" && "Bun" in process.versions;
|
|
1618
|
+
}
|
|
1619
|
+
function createPTYManager(options) {
|
|
1620
|
+
return new BunCompatiblePTYManager(options);
|
|
1621
|
+
}
|
|
1312
1622
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1313
1623
|
0 && (module.exports = {
|
|
1314
1624
|
AdapterRegistry,
|
|
1315
1625
|
BaseCLIAdapter,
|
|
1626
|
+
BunCompatiblePTYManager,
|
|
1316
1627
|
PTYManager,
|
|
1317
1628
|
PTYSession,
|
|
1318
1629
|
SPECIAL_KEYS,
|
|
1319
1630
|
ShellAdapter,
|
|
1320
|
-
createAdapter
|
|
1631
|
+
createAdapter,
|
|
1632
|
+
createPTYManager,
|
|
1633
|
+
isBun
|
|
1321
1634
|
});
|
|
1322
1635
|
//# sourceMappingURL=index.js.map
|