> ## Documentation Index
> Fetch the complete documentation index at: https://bun.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spawn

> 使用 `Bun.spawn` 或 `Bun.spawnSync` 创建子进程

## 创建一个进程 (`Bun.spawn()`)

提供一个字符串数组作为命令。`Bun.spawn()` 返回一个 `Bun.Subprocess` 对象。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"]);
console.log(await proc.exited); // 0
```

`Bun.spawn` 的第二个参数是一个参数对象，用来配置子进程。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"], {
  cwd: "./path/to/subdir", // 指定工作目录
  env: { ...process.env, FOO: "bar" }, // 指定环境变量
  onExit(proc, exitCode, signalCode, error) {
    // 退出处理器
  },
});

proc.pid; // 子进程的进程ID
```

## 输入流

默认情况下，子进程的输入流是 `undefined`；可以通过 `stdin` 参数进行配置。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["cat"], {
  stdin: await fetch("https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js"),
});

const text = await proc.stdout.text();
console.log(text); // "const input = "hello world".repeat(400); ..."
```

| 值                        | 描述                       |
| ------------------------ | ------------------------ |
| `null`                   | **默认。** 不向子进程提供输入        |
| `"pipe"`                 | 返回一个 `FileSink` 用于快速增量写入 |
| `"inherit"`              | 继承父进程的 `stdin`           |
| `Bun.file()`             | 从指定文件读取                  |
| `TypedArray \| DataView` | 使用二进制缓冲区作为输入             |
| `Response`               | 使用响应体 `body` 作为输入        |
| `Request`                | 使用请求体 `body` 作为输入        |
| `ReadableStream`         | 使用可读流作为输入                |
| `Blob`                   | 使用 Blob 作为输入             |
| `number`                 | 从给定文件描述符的文件读取            |

`"pipe"` 选项允许从父进程向子进程的输入流进行增量写入。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["cat"], {
  stdin: "pipe", // 返回可写的 FileSink
});

// 入队字符串数据
proc.stdin.write("hello");

// 入队二进制数据
const enc = new TextEncoder();
proc.stdin.write(enc.encode(" world!"));

// 发送缓冲数据
proc.stdin.flush();

// 关闭输入流
proc.stdin.end();
```

将一个 `ReadableStream` 传给 `stdin`，可以让你直接从 JavaScript 的 `ReadableStream` 向子进程输入流传输数据：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue("Hello from ");
    controller.enqueue("ReadableStream!");
    controller.close();
  },
});

const proc = Bun.spawn(["cat"], {
  stdin: stream,
  stdout: "pipe",
});

const output = await proc.stdout.text();
console.log(output); // "Hello from ReadableStream!"
```

## 输出流

你可以通过 `stdout` 和 `stderr` 属性读取子进程的输出。默认情况下它们是 `ReadableStream` 的实例。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"]);
const text = await proc.stdout.text();
console.log(text); // => "1.3.3\n"
```

通过向 `stdout/stderr` 传入以下值之一来配置输出流：

| 值            | 描述                                                            |
| ------------ | ------------------------------------------------------------- |
| `"pipe"`     | **`stdout` 的默认值。** 将输出导入返回的 `Subprocess` 对象的 `ReadableStream` |
| `"inherit"`  | **`stderr` 的默认值。** 继承自父进程                                     |
| `"ignore"`   | 丢弃输出                                                          |
| `Bun.file()` | 写入指定文件                                                        |
| `number`     | 写入指定文件描述符的文件                                                  |

## 退出处理

使用 `onExit` 回调监听进程退出或被杀死。

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"], {
  onExit(proc, exitCode, signalCode, error) {
    // 退出处理器
  },
});
```

为方便起见，`exited` 属性是一个在进程退出时解析的 `Promise`。

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"]);

await proc.exited; // 进程退出时解析
proc.killed; // 布尔值 — 进程是否被杀死？
proc.exitCode; // null | 数字
proc.signalCode; // null | "SIGABRT" | "SIGALRM" | ...
```

杀死进程：

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"]);
proc.kill();
proc.killed; // true

proc.kill(15); // 指定信号码
proc.kill("SIGTERM"); // 指定信号名
```

父进程 `bun` 在所有子进程退出前不会终止。使用 `proc.unref()` 可以将子进程与父进程分离。

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"]);
proc.unref();
```

## 资源使用

进程退出后，你可以获取该进程的资源使用信息：

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bun", "--version"]);
await proc.exited;

const usage = proc.resourceUsage();
console.log(`最大内存使用量: ${usage.maxRSS} 字节`);
console.log(`CPU 时间（用户态）: ${usage.cpuTime.user} 微秒`);
console.log(`CPU 时间（内核态）: ${usage.cpuTime.system} 微秒`);
```

## 使用 AbortSignal

你可以使用 `AbortSignal` 中止子进程：

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const controller = new AbortController();
const { signal } = controller;

const proc = Bun.spawn({
  cmd: ["sleep", "100"],
  signal,
});

// 后续中止进程：
controller.abort();
```

## 使用 timeout 和 killSignal

你可以为子进程设置超时时间，超时后自动终止进程：

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
// 5秒后杀死进程
const proc = Bun.spawn({
  cmd: ["sleep", "10"],
  timeout: 5000, // 5秒，单位毫秒
});

await proc.exited; // 5秒后解析
```

默认情况下，超时进程会使用 `SIGTERM` 信号被杀死。你可以通过 `killSignal` 选项指定不同信号：

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
// 5秒后使用 SIGKILL 杀死进程
const proc = Bun.spawn({
  cmd: ["sleep", "10"],
  timeout: 5000,
  killSignal: "SIGKILL", // 可为信号名称或信号编号
});
```

`killSignal` 选项也控制在 `AbortSignal` 触发时发送的信号。

## 使用 maxBuffer

对于 spawnSync，你可以限制输出的最大字节数，超过则杀死进程：

```ts index.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
// ‘yes’ 进程输出超过100字节后被杀死
const result = Bun.spawnSync({
  cmd: ["yes"], // Windows 下使用 ["bun", "exec", "yes"]
  maxBuffer: 100,
});
// 进程退出
```

## 进程间通信 (IPC)

Bun 支持在两个 `bun` 进程间建立直接的进程间通信通道。要从被创建的 Bun 子进程接收消息，请指定 `ipc` 处理器。

```ts parent.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const child = Bun.spawn(["bun", "child.ts"], {
  ipc(message) {
    /**
     * 从子进程收到的消息
     **/
  },
});
```

父进程可通过返回的 `Subprocess` 对象上的 `.send()` 方法向子进程发送消息。子进程在 `ipc` 处理器第二个参数中获得发送者引用。

```ts parent.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
const childProc = Bun.spawn(["bun", "child.ts"], {
  ipc(message, childProc) {
    /**
     * 从子进程收到的消息
     **/
    childProc.send("Respond to child");
  },
});

childProc.send("I am your father"); // 父进程也可向子进程发送消息
```

子进程可用 `process.send()` 向父进程发送消息，用 `process.on("message")` 接收消息。这与 Node.js 中 `child_process.fork()` 使用的 API 相同。

```ts child.ts theme={"theme":{"light":"github-light","dark":"dracula"}}
process.send("Hello from child as string");
process.send({ message: "Hello from child as object" });

process.on("message", message => {
  // 打印来自父进程的消息
  console.log(message);
});
```

```ts child.ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 发送字符串消息
process.send("Hello from child as string");

// 发送对象消息
process.send({ message: "Hello from child as object" });
```

`serialization` 选项控制两进程间通信的序列化格式：

* `advanced`：（默认）消息使用 JSC 的 `serialize` API 序列化，支持克隆[所有 `structuredClone` 支持的类型](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) ，但不支持对象所有权转移。
* `json`：消息使用 `JSON.stringify` 和 `JSON.parse` 序列化，支持对象类型比 `advanced` 少。

断开与父进程的 IPC 通道可调用：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
childProc.disconnect();
```

### Bun 与 Node.js 之间的 IPC

要在 `bun` 和 Node.js 进程间使用 IPC，请在 `Bun.spawn` 设置 `serialization: "json"`。这是因为 Node.js 和 Bun 使用不同的 JS 引擎及不同的对象序列化格式。

```js bun-node-ipc.js icon="file-code" theme={"theme":{"light":"github-light","dark":"dracula"}}
if (typeof Bun !== "undefined") {
  const prefix = `[bun ${process.versions.bun} 🐇]`;
  const node = Bun.spawn({
    cmd: ["node", __filename],
    ipc({ message }) {
      console.log(message);
      node.send({ message: `${prefix} 👋 hey node` });
      node.kill();
    },
    stdio: ["inherit", "inherit", "inherit"],
    serialization: "json",
  });

  node.send({ message: `${prefix} 👋 hey node` });
} else {
  const prefix = `[node ${process.version}]`;
  process.on("message", ({ message }) => {
    console.log(message);
    process.send({ message: `${prefix} 👋 hey bun` });
  });
}
```

***

## 终端（PTY）支持

对于交互式终端应用，可以使用 `terminal` 选项为子进程附加伪终端（PTY）。这让子进程认为自己运行在真实终端中，启用彩色输出、光标移动和交互式提示等功能。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawn(["bash"], {
  terminal: {
    cols: 80,
    rows: 24,
    data(terminal, data) {
      // 终端接收数据时被调用
      process.stdout.write(data);
    },
  },
});

// 向终端写数据
proc.terminal.write("echo hello\n");

// 等待进程退出
await proc.exited;

// 关闭终端
proc.terminal.close();
```

提供 `terminal` 选项时：

* 子进程中 `process.stdout.isTTY` 为 `true`
* `stdin`、`stdout` 和 `stderr` 都绑定到终端
* `proc.stdin`、`proc.stdout` 和 `proc.stderr` 返回 `null` —— 使用终端对象代替
* 可通过 `proc.terminal` 访问终端

### 终端选项

| 选项      | 描述                                                                                        | 默认值                |
| ------- | ----------------------------------------------------------------------------------------- | ------------------ |
| `cols`  | 列数                                                                                        | `80`               |
| `rows`  | 行数                                                                                        | `24`               |
| `name`  | PTY 配置的终端类型（通过 `env` 选项单独设置 `TERM` 环境变量）                                                  | `"xterm-256color"` |
| `data`  | 接收数据时回调 `(terminal, data) => void`                                                        | —                  |
| `exit`  | PTY 流关闭时回调（EOF 或错误）。`exitCode` 是 PTY 生命周期状态（0为EOF，1为错误），而非子进程退出码。使用 `proc.exited` 监听进程退出。 | —                  |
| `drain` | 可写流准备好接收更多数据时回调 `(terminal) => void`                                                      | —                  |

### 终端方法

`proc.terminal` 返回的 `Terminal` 对象具有以下方法：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 向终端写入数据
proc.terminal.write("echo hello\n");

// 调整终端大小
proc.terminal.resize(120, 40);

// 设置原生模式（禁用行缓冲与回显）
proc.terminal.setRawMode(true);

// 保持事件循环活动直到终端关闭
proc.terminal.ref();
proc.terminal.unref();

// 关闭终端
proc.terminal.close();
```

### 可复用终端

你可以独立创建一个终端对象并在多个子进程间重用：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
await using terminal = new Bun.Terminal({
  cols: 80,
  rows: 24,
  data(term, data) {
    process.stdout.write(data);
  },
});

// 创建第一个进程
const proc1 = Bun.spawn(["echo", "first"], { terminal });
await proc1.exited;

// 复用终端启动另一个进程
const proc2 = Bun.spawn(["echo", "second"], { terminal });
await proc2.exited;

// 终端会被 `await using` 自动关闭
```

传入已有的 `Terminal` 对象时：

* 终端可跨多个进程复用
* 你负责何时关闭终端
* `exit` 回调在调用 `terminal.close()` 时触发，而非每个子进程退出时
* 使用 `proc.exited` 侦测每个子进程退出

这适合在同一终端会话中顺序运行多个命令。

### 平台差异

`Bun.Terminal` 在 Linux 和 macOS 上使用 `openpty()`，在 Windows 上使用 ConPTY（`CreatePseudoConsole`）。核心行为——子进程看到的是 TTY、`write()` 会到达子进程的 stdin、子进程输出会到达 `data` 回调、`resize()` 会更新子进程视图——在所有平台上都相同。但有一些细节不同：

* **Windows 上没有 termios。** `inputFlags`、`outputFlags`、`localFlags` 和 `controlFlags` 始终读作 `0`，设置它们不会产生效果。`setRawMode()` 会记录该标志，但对子进程没有影响；子进程控制自己的控制台模式。
* **Windows 上没有子进程时不会回显。** 在 POSIX 上，即使没有附加进程，内核行规程也会把 `write()` 输入回显到 `data` 回调。ConPTY 没有行规程；输入会被缓冲，等待下一个读取者。如果需要回显，请启动一个会回显的进程。
* **ConPTY 会重新编码输出。** ConPTY 会将子进程输出渲染到虚拟屏幕，并发出描述结果的 VT 序列，因此 `data` 回调收到的是语义等价但字节不完全相同的转义序列。颜色和文本会保留；光标定位和重置序列可能会被重新排序或合并。ConPTY 还会在任何子进程输出之前发出一段短的 VT 初始化序列（`\x1b[?9001h\x1b[?1004h…`）。
* **Windows 上输入 `\r` 不会被转换为 `\n`。** POSIX 的 `ICRNL` 会在输入时把回车映射为换行；ConPTY 会原样传递 `\r`。
* **子进程中的 `process.on('SIGWINCH')` 在 ConPTY 下不会触发**，除非子进程以原始模式读取 stdin。`process.stdout.columns`/`rows` 会在 `resize()` 后更新。这是一个 libuv 限制，影响所有基于 libuv 的子进程（包括 Node.js）。
* 在 Windows 11 24H2（build 26100）之前，`terminal.close()` 可能不会立即终止仍在运行的子进程，因为在这些版本上 [`ClosePseudoConsole`](https://learn.microsoft.com/en-us/windows/console/closepseudoconsole) 会阻塞，直到 conhost 将其输出通过管道刷新完毕。如果你需要在子进程运行时拆除环境，请先杀死附加的进程。

***

## 阻塞式 API (`Bun.spawnSync()`)

Bun 提供了 `Bun.spawn` 的同步版本 `Bun.spawnSync`。这是一个阻塞 API，支持与 `Bun.spawn` 相同的输入和参数。它返回一个 `SyncSubprocess` 对象，与 `Subprocess` 有几点不同：

1. 含有表示进程是否以零退出码退出的 `success` 属性。
2. `stdout` 和 `stderr` 是 `Buffer` 实例，而非 `ReadableStream`。
3. 没有 `stdin` 属性。若需增量写入输入流，请使用 `Bun.spawn`。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const proc = Bun.spawnSync(["echo", "hello"]);

console.log(proc.stdout.toString());
// => "hello\n"
```

原则上，异步的 `Bun.spawn` 适合 HTTP 服务器和应用，`Bun.spawnSync` 更适合构建命令行工具。

***

## 性能基准

<Note>
  ⚡️ 底层，`Bun.spawn` 和 `Bun.spawnSync` 使用
  [`posix_spawn(3)`](https://man7.org/linux/man-pages/man3/posix_spawn.3.html) 系统调用。
</Note>

Bun 的 `spawnSync` 比 Node.js 的 `child_process` 模块快 60%。

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun spawn.mjs
```

```txt theme={"theme":{"light":"github-light","dark":"dracula"}}
cpu: Apple M1 Max
runtime: bun 1.x (arm64-darwin)

benchmark              time (avg)             (min … max)       p75       p99      p995
--------------------------------------------------------- -----------------------------
spawnSync echo hi  888.14 µs/iter    (821.83 µs … 1.2 ms) 905.92 µs      1 ms   1.03 ms
```

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
node spawn.node.mjs
```

```txt theme={"theme":{"light":"github-light","dark":"dracula"}}
cpu: Apple M1 Max
runtime: node v18.9.1 (arm64-darwin)

benchmark              time (avg)             (min … max)       p75       p99      p995
--------------------------------------------------------- -----------------------------
spawnSync echo hi    1.47 ms/iter     (1.14 ms … 2.64 ms)   1.57 ms   2.37 ms   2.52 ms
```

***

## 参考

下面是 Spawn API 及类型的参考。真实的类型中包含复杂泛型以根据 `Bun.spawn` 和 `Bun.spawnSync` 传入的选项严密类型化 `Subprocess` 流。完整细节参见 [bun.d.ts](https://github.com/oven-sh/bun/blob/main/packages/bun-types/bun.d.ts) 中的定义。

```ts See Typescript Definitions expandable theme={"theme":{"light":"github-light","dark":"dracula"}}
interface Bun {
  spawn(command: string[], options?: SpawnOptions.OptionsObject): Subprocess;
  spawnSync(command: string[], options?: SpawnOptions.OptionsObject): SyncSubprocess;

  spawn(options: { cmd: string[] } & SpawnOptions.OptionsObject): Subprocess;
  spawnSync(options: { cmd: string[] } & SpawnOptions.OptionsObject): SyncSubprocess;
}

namespace SpawnOptions {
  interface OptionsObject {
    cwd?: string;
    env?: Record<string, string | undefined>;
    stdio?: [Writable, Readable, Readable];
    stdin?: Writable;
    stdout?: Readable;
    stderr?: Readable;
    onExit?(
      subprocess: Subprocess,
      exitCode: number | null,
      signalCode: number | null,
      error?: ErrorLike,
    ): void | Promise<void>;
    ipc?(message: any, subprocess: Subprocess): void;
    serialization?: "json" | "advanced";
    windowsHide?: boolean;
    windowsVerbatimArguments?: boolean;
    argv0?: string;
    signal?: AbortSignal;
    timeout?: number;
    killSignal?: string | number;
    maxBuffer?: number;
    terminal?: TerminalOptions; // PTY（POSIX）/ConPTY（Windows）支持
  }

  type Readable =
    | "pipe"
    | "inherit"
    | "ignore"
    | null // 等价于 "ignore"
    | undefined // 使用默认值
    | BunFile
    | ArrayBufferView
    | number;

  type Writable =
    | "pipe"
    | "inherit"
    | "ignore"
    | null // 等价于 "ignore"
    | undefined // 使用默认值
    | BunFile
    | ArrayBufferView
    | number
    | ReadableStream
    | Blob
    | Response
    | Request;
}

interface Subprocess extends AsyncDisposable {
  readonly stdin: FileSink | number | undefined | null;
  readonly stdout: ReadableStream<Uint8Array<ArrayBuffer>> | number | undefined | null;
  readonly stderr: ReadableStream<Uint8Array<ArrayBuffer>> | number | undefined | null;
  readonly readable: ReadableStream<Uint8Array<ArrayBuffer>> | number | undefined | null;
  readonly terminal: Terminal | undefined;
  readonly pid: number;
  readonly exited: Promise<number>;
  readonly exitCode: number | null;
  readonly signalCode: NodeJS.Signals | null;
  readonly killed: boolean;

  kill(exitCode?: number | NodeJS.Signals): void;
  ref(): void;
  unref(): void;

  send(message: any): void;
  disconnect(): void;
  resourceUsage(): ResourceUsage | undefined;
}

interface SyncSubprocess {
  stdout: Buffer | undefined;
  stderr: Buffer | undefined;
  exitCode: number;
  success: boolean;
  resourceUsage: ResourceUsage;
  signalCode?: string;
  exitedDueToTimeout?: true;
  pid: number;
}

interface TerminalOptions {
  cols?: number;
  rows?: number;
  name?: string;
  data?: (terminal: Terminal, data: Uint8Array<ArrayBuffer>) => void;
  /** PTY 流关闭时调用（EOF 或错误）。exitCode 是 PTY 生命周期状态（0=EOF，1=错误），非子进程退出码。 */
  exit?: (terminal: Terminal, exitCode: number, signal: string | null) => void;
  drain?: (terminal: Terminal) => void;
}

interface Terminal extends AsyncDisposable {
  readonly stdin: number;
  readonly stdout: number;
  readonly closed: boolean;
  write(data: string | BufferSource): number;
  resize(cols: number, rows: number): void;
  setRawMode(enabled: boolean): void;
  ref(): void;
  unref(): void;
  close(): void;
}

interface ResourceUsage {
  contextSwitches: {
    voluntary: number;
    involuntary: number;
  };

  cpuTime: {
    user: number;
    system: number;
    total: number;
  };
  maxRSS: number;

  messages: {
    sent: number;
    received: number;
  };
  ops: {
    in: number;
    out: number;
  };
  shmSize: number;
  signalCount: number;
  swapCount: number;
}

type Signal =
  | "SIGABRT"
  | "SIGALRM"
  | "SIGBUS"
  | "SIGCHLD"
  | "SIGCONT"
  | "SIGFPE"
  | "SIGHUP"
  | "SIGILL"
  | "SIGINT"
  | "SIGIO"
  | "SIGIOT"
  | "SIGKILL"
  | "SIGPIPE"
  | "SIGPOLL"
  | "SIGPROF"
  | "SIGPWR"
  | "SIGQUIT"
  | "SIGSEGV"
  | "SIGSTKFLT"
  | "SIGSTOP"
  | "SIGSYS"
  | "SIGTERM"
  | "SIGTRAP"
  | "SIGTSTP"
  | "SIGTTIN"
  | "SIGTTOU"
  | "SIGUNUSED"
  | "SIGURG"
  | "SIGUSR1"
  | "SIGUSR2"
  | "SIGVTALRM"
  | "SIGWINCH"
  | "SIGXCPU"
  | "SIGXFSZ"
  | "SIGBREAK"
  | "SIGLOST"
  | "SIGINFO";
```
