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

# PTY

PTY(伪终端)是一种虚拟终端接口,让程序可以像连接真实终端一样与 shell 交互。使用 `sandbox.pty` 模块可以创建交互式终端会话,用于运行命令、接收输入,并可在运行中调整大小——适用于 REPL 和调试器、需要提示输入的交互式 CLI,以及需要监控的长时间运行进程。

<Note>
  **注意:** PTY 由其进程 ID(`pid`)标识,该 ID 由 `create()` 返回句柄上提供。发送输入、调整大小、连接和终止时都需传入该 `pid`。输出以原始字节形式传递给回调函数。
</Note>

| 操作   | JavaScript / TypeScript            | Python                              |
| ---- | ---------------------------------- | ----------------------------------- |
| 创建   | `sandbox.pty.create(opts)`         | `sandbox.pty.create(size, ...)`     |
| 连接   | `sandbox.pty.connect(pid, opts?)`  | `sandbox.pty.connect(pid, ...)`     |
| 发送输入 | `sandbox.pty.sendInput(pid, data)` | `sandbox.pty.send_stdin(pid, data)` |
| 调整大小 | `sandbox.pty.resize(pid, size)`    | `sandbox.pty.resize(pid, size)`     |
| 终止   | `sandbox.pty.kill(pid)`            | `sandbox.pty.kill(pid)`             |

***

## 创建 PTY

创建一个 PTY,并通过回调接收其输出。它会返回一个句柄,其 `pid` 用于标识该 PTY。

| 选项                      | 类型                         | 说明                                          |
| ----------------------- | -------------------------- | ------------------------------------------- |
| `cols` / `rows`         | number                     | 终端尺寸(Python:`PtySize(cols=…, rows=…)`)      |
| `onData`(JS)            | (data: Uint8Array) => void | PTY 输出的回调。Python 通过 `wait(on_pty=...)` 传递输出 |
| `user`                  | string(可选)                 | 运行 PTY 所使用的用户                               |
| `cwd`                   | string(可选)                 | 工作目录                                        |
| `envs`                  | object / dict(可选)          | 环境变量(`TERM`、`LANG`、`LC_ALL` 有默认值)           |
| `timeoutMs` / `timeout` | number(默认 60000 ms / 60 s) | PTY 超时时间;JS 使用毫秒,Python 使用秒                 |

<CodeGroup>
  ```python Python theme={null}
  from ppio_sandbox import PPIO, PtySize

  ppio = PPIO()

  sandbox = ppio.sandbox.create()

  def on_pty(data: bytes):
      print(data.decode('utf-8', errors='replace'), end='')

  # PtySize 接受关键字参数 cols / rows
  pty = sandbox.pty.create(PtySize(cols=120, rows=30), cwd='/home/user', envs={'TERM': 'xterm-256color'})
  print('PTY pid:', pty.pid)
  ```

  ```javascript JavaScript & TypeScript theme={null}
  import { PPIO } from 'ppio-sandbox'

  const ppio = new PPIO()

  const sandbox = await ppio.sandbox.create()

  const pty = await sandbox.pty.create({
    cols: 120,
    rows: 30,
    cwd: '/home/user',
    envs: { TERM: 'xterm-256color' },
    onData: (data) => {
      process.stdout.write(new TextDecoder().decode(data))
    },
  })

  console.log('PTY pid:', pty.pid)
  ```
</CodeGroup>

***

## 发送输入

通过 `pid` 向运行中的 PTY 发送输入。数据为原始字节。

<CodeGroup>
  ```python Python theme={null}
  sandbox.pty.send_stdin(pty.pid, b'echo hello\n')
  sandbox.pty.send_stdin(pty.pid, b'exit\n')
  ```

  ```javascript JavaScript & TypeScript theme={null}
  const enc = new TextEncoder()
  await sandbox.pty.sendInput(pty.pid, enc.encode('echo hello\n'))
  await sandbox.pty.sendInput(pty.pid, enc.encode('exit\n'))
  ```
</CodeGroup>

***

## 调整 PTY 大小

当终端窗口尺寸发生变化时,调用 `resize`。

<CodeGroup>
  ```python Python theme={null}
  sandbox.pty.resize(pty.pid, PtySize(cols=150, rows=40))
  ```

  ```javascript JavaScript & TypeScript theme={null}
  await sandbox.pty.resize(pty.pid, { cols: 150, rows: 40 })
  ```
</CodeGroup>

***

## 连接到运行中的 PTY

通过 `pid` 连接到已在运行的 PTY。可以通过 `sandbox.commands.list()` 获取正在运行的进程。返回的句柄会通过回调接收后续输出。

<CodeGroup>
  ```python Python theme={null}
  handle = sandbox.pty.connect(pty.pid)
  ```

  ```javascript JavaScript & TypeScript theme={null}
  const handle = await sandbox.pty.connect(pty.pid, {
    onData: (data) => process.stdout.write(new TextDecoder().decode(data)),
  })
  ```
</CodeGroup>

***

## 终止 PTY

`kill` 使用 `SIGKILL` 终止 PTY。如果 PTY 被成功终止则返回 `true`;如果找不到对应 `pid` 的 PTY 则返回 `false`。

<CodeGroup>
  ```python Python theme={null}
  killed = sandbox.pty.kill(pty.pid)
  print('killed:', killed)

  sandbox.kill()
  ```

  ```javascript JavaScript & TypeScript theme={null}
  const killed = await sandbox.pty.kill(pty.pid)
  console.log('killed:', killed)

  await sandbox.kill()
  ```
</CodeGroup>

***

## 交互式示例

创建一个 PTY,发送一条需要提示输入的交互式命令,然后等待其结束并读取退出码。在 Python 中,`wait(on_pty=...)` 会将输出流式传递给回调并返回结果。

```python theme={null}
from ppio_sandbox import PPIO, PtySize

ppio = PPIO()

sandbox = ppio.sandbox.create()

output = []

def on_pty(data: bytes):
    output.append(data.decode('utf-8', errors='replace'))

terminal = sandbox.pty.create(PtySize(cols=80, rows=24), envs={'ABC': '123'}, cwd='/')

# 发送命令并退出
sandbox.pty.send_stdin(terminal.pid, b'echo $ABC\nexit\n')

# 流式输出并等待完成
result = terminal.wait(on_pty=on_pty)
print('exit code:', result.exit_code)
print(''.join(output))

sandbox.kill()
```
