Skip to content
sursaonePublic

About

Fork pseudoterminals in Bun

Topics

Resources

Contributing

Stars

74 stars

Watchers

2 watching

Forks

Latest commit

Β 

History

85 Commits

Folders and files

Repository files navigation

bun-pty

NPM Version License: MIT Bun Compatible

A cross-platform pseudo-terminal (PTY) implementation for Bun, powered by Rust's portable-pty library and Bun's FFI capabilities.

πŸš€ Features

  • Cross-platform - Works on macOS, Linux, and Windows
  • Simple API - Clean Promise-based API similar to node-pty
  • Type-safe - Complete TypeScript definitions included
  • Efficient - Rust backend with proper error handling and multithreading
  • Zero dependencies - No external JavaScript dependencies required
  • Modern - Built specifically for Bun using its FFI capabilities

πŸ“¦ Installation

bun add bun-pty

βš™οΈ Requirements

  • Bun 1.4.0 or higher (bun-pty uses the engine-native bun:ffi added in Bun 1.4)
  • Rust is only needed if you're building from source (the npm package includes pre-built binaries)

πŸ“‹ Platform Support

Platform Status Notes
macOS βœ… Fully supported
Linux βœ… Fully supported
Windows βœ… Fully supported

πŸ†š bun-pty or Bun.Terminal?

Bun 1.4 has a built-in PTY, Bun.Terminal (Bun.spawn({ terminal })). If you are writing new code and only need Bun's own API, try it first: it needs no native library.

bun-pty is the better fit when you want:

  • The core of the node-pty API - spawn(), write(), onData, onExit, resize() and kill(), with node-pty's option and event shapes, so code that sticks to these ports with little or no change. Not supported: the uid, gid, encoding, handleFlowControl and useConpty options, and pause(), resume() and clear()
  • node-pty's environment rules - env is the child's whole environment, TERM comes from name, and PWD follows cwd
  • The same backend on every platform - one Rust (portable-pty) implementation on macOS, Linux (glibc and musl) and Windows (x64 and ARM64)

🚦 Usage

Basic Example

import { spawn } from "bun-pty";

// Create a new terminal
const terminal = spawn("bash", [], {
  name: "xterm-256color",
  cols: 80,
  rows: 24
});

// Handle data from the terminal
terminal.onData((data) => {
  console.log("Received:", data);
});

// Handle terminal exit
terminal.onExit(({ exitCode, signal }) => {
  console.log(`Process exited with code ${exitCode} and signal ${signal}`);
});

// Write to the terminal
terminal.write("echo Hello from Bun PTY\n");

// Resize the terminal
terminal.resize(100, 40);

// Kill the process when done
setTimeout(() => {
  terminal.kill();
}, 5000);

TypeScript Usage

The library includes complete TypeScript definitions. Here's how to use it with full type safety:

import { spawn } from "bun-pty";
import type { IPty, IExitEvent, IPtyForkOptions } from "bun-pty";

// Create typed options
const options: IPtyForkOptions = {
  name: "xterm-256color",
  cols: 100,
  rows: 30,
  cwd: process.cwd()
};

// Create a terminal with proper typing
const terminal: IPty = spawn("bash", [], options);

// Typed event handlers
const dataHandler = terminal.onData((data: string) => {
  process.stdout.write(data);
});

const exitHandler = terminal.onExit((event: IExitEvent) => {
  console.log(`Process exited with code: ${event.exitCode}`);
});

// Clean up when done
dataHandler.dispose();
exitHandler.dispose();

Interactive Shell Example

import { spawn } from "bun-pty";
import { createInterface } from "node:readline";

// Create a PTY running bash
const pty = spawn("bash", [], {
  name: "xterm-256color",
  cwd: process.cwd()
});

// Forward PTY output to stdout
pty.onData((data) => {
  process.stdout.write(data);
});

// Send user input to the PTY
process.stdin.on("data", (data) => {
  pty.write(data.toString());
});

// Handle PTY exit
pty.onExit(() => {
  console.log("Terminal session ended");
  process.exit(0);
});

// Handle SIGINT (Ctrl+C)
process.on("SIGINT", () => {
  pty.kill();
});

πŸ“– API Reference

spawn(file: string, args: string[], options: IPtyForkOptions): IPty

Creates and spawns a new pseudoterminal.

  • file: The executable to launch
  • args: Arguments to pass to the executable
  • options: Configuration options
    • name: Terminal type (e.g., "xterm-256color"), set as TERM in the child's environment on Unix (default: TERM from env, then "xterm")
    • cols: Number of columns (default: 80)
    • rows: Number of rows (default: 24)
    • cwd: Working directory (default: process.cwd())
    • env: The child's whole environment, as in node-pty (default: process.env). It replaces the parent's environment, so pass { ...process.env, FOO: "bar" } to add variables. Entries whose value is undefined are skipped. On Windows, a map with no entries keeps the parent's environment, as in node-pty. On Unix, PWD is set from cwd, and when the child inherits process.env, variables from the parent's tmux or screen session (TMUX, STY, ...) are dropped

Returns an IPty instance.

IPty Interface

interface IPty {
  // Properties
  readonly pid: number;        // Process ID
  readonly cols: number;       // Current columns
  readonly rows: number;       // Current rows
  readonly process: string;    // Process name
  
  // Events
  onData: (listener: (data: string) => void) => IDisposable;  // The first listener (and any added in the same tick) also gets output from before it subscribed (up to 512 KiB), just after onData() returns
  onExit: (listener: (event: IExitEvent) => void) => IDisposable;
  
  // Methods
  write(data: string): void;   // Write data to terminal
  resize(cols: number, rows: number): void;  // Resize terminal
  kill(signal?: string): void;  // Kill the process
}

Event Types

interface IExitEvent {
  exitCode: number;
  signal?: number | string;
}

interface IDisposable {
  dispose(): void;
}

πŸ§ͺ Testing

bun-pty uses Bun's built-in test runner for fast, Jest-compatible testing.

# Run all tests
bun test

# Run unit tests only
bun run test:unit

# Run integration tests (requires Rust library)
bun run test:integration

# View test coverage
bun run test:coverage

# Type check the sources and tests (bun check, Bun 1.4.3+)
bun run typecheck

πŸ”§ Building from Source

If you want to build the package from source:

# Clone the repository
git clone https://github.com/sursaone/bun-pty.git
cd bun-pty

# Install dependencies
bun install

# Build Rust library and TypeScript
bun run build

# Run tests
bun test

❓ Troubleshooting

Prebuilt Binaries

The npm package includes prebuilt binaries for macOS, Linux, and Windows. If you encounter issues with the prebuilt binaries, you can build from source:

# In your project directory
bun add bun-pty
cd node_modules/bun-pty
bun run build

Common Issues

  • Error: Unable to load shared library: Make sure you have the necessary system libraries installed.
  • Process spawn fails: Check if you have the required permissions and paths.

πŸ“š Documentation

πŸ“„ License

This project is licensed under the MIT License.

πŸ™ Credits

  • Built specifically for Bun
  • Uses portable-pty from WezTerm for cross-platform PTY support
  • Inspired by node-pty for the API design

About

Fork pseudoterminals in Bun

Topics

Resources

Contributing

Stars

74 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages