···11# pty — Development Guide
2233-A persistent terminal session manager. Run long-lived processes, detach, reconnect later — from any machine over SSH. The npm package name is `ptym`; the CLI command remains `pty`.
33+A persistent terminal session manager. Run long-lived processes, detach, reconnect later — from any machine over SSH. The npm package name is `@myobie/pty`; the CLI command remains `pty`.
4455## Objectives
66···150150151151## Testing
152152153153-Tests use **vitest** and live in `tests/`. The `ptym/testing` library (`src/testing/`) provides a `Session` class used by the tests — see [docs/testing.md](docs/testing.md) for the full API.
153153+Tests use **vitest** and live in `tests/`. The `@myobie/pty/testing` library (`src/testing/`) provides a `Session` class used by the tests — see [docs/testing.md](docs/testing.md) for the full API.
154154155155- `protocol.test.ts` — Unit tests for packet encoding, decoding, and streaming reassembly (partial reads, split packets, large payloads)
156156- `keys.test.ts` — Unit tests for key name resolution (`resolveKey`, `parseSeqValue`)
···190190 keys.ts Key name resolution (e.g. "ctrl+c" → bytes)
191191 spawn.ts Daemon spawning logic
192192 tui/ Interactive session manager UI
193193- testing/ Testing library (exported as ptym/testing)
193193+ testing/ Testing library (exported as @myobie/pty/testing)
194194 index.ts Public re-exports
195195 session.ts Session class (spawn + server backends)
196196 screenshot.ts Screenshot capture helper
+8-10
README.md
···99## Install
10101111```sh
1212-git clone https://github.com/myobie/pty.git
1313-cd pty
1414-npm install
1515-npm link
1212+npm install -g @myobie/pty
1613```
17141818-Or install directly from GitHub:
1515+Or with Nix:
19162017```sh
2121-npm install -g github:myobie/pty
1818+nix profile install github:myobie/pty # install the CLI
1919+nix develop github:myobie/pty # dev shell with node, npm, native deps
2220```
23212424-The npm package name is `ptym`. Requires Node.js. Works on macOS and Linux.
2222+Requires Node.js. Works on macOS and Linux.
25232624## Usage
2725···76747775## Testing Library
78767979-ptym includes a terminal testing library — like Playwright, but for the terminal. Spawn any process in a real PTY, send keystrokes, take screenshots, assert on visible output.
7777+@myobie/pty includes a terminal testing library — like Playwright, but for the terminal. Spawn any process in a real PTY, send keystrokes, take screenshots, assert on visible output.
80788179```typescript
8282-import { Session } from "ptym/testing";
8080+import { Session } from "@myobie/pty/testing";
83818482const session = Session.spawn("node", ["--experimental-strip-types", "my-app.ts"]);
8583await session.waitForText("Ready");
···103101104102## TUI Framework (alpha)
105103106106-ptym also includes an experimental declarative TUI framework for building terminal interfaces with reactive signals, layout, and efficient cell-buffer diffing. Import from `ptym/tui`.
104104+@myobie/pty also includes an experimental declarative TUI framework for building terminal interfaces with reactive signals, layout, and efficient cell-buffer diffing. Import from `@myobie/pty/tui`.
107105108106> **Alpha** — the TUI framework API is unstable and will change. Use it for experiments, not production.
109107
+17-17
docs/testing.md
···11-# ptym/testing
11+# @myobie/pty/testing
2233A terminal testing library — like Playwright, but for the terminal.
44···99## Install
10101111```sh
1212-npm install ptym
1212+npm install @myobie/pty
1313```
14141515-Import from `ptym/testing`:
1515+Import from `@myobie/pty/testing`:
16161717```typescript
1818-import { Session } from "ptym/testing";
1818+import { Session } from "@myobie/pty/testing";
1919```
20202121## Quick Start
22222323```typescript test
2424-import { Session } from "ptym/testing";
2424+import { Session } from "@myobie/pty/testing";
25252626const session = Session.spawn("echo", ["hello world"]);
2727const ss = await session.waitForText("hello world");
···4545- `env` — extra environment variables (merged with `process.env`)
46464747```typescript test
4848-import { Session } from "ptym/testing";
4848+import { Session } from "@myobie/pty/testing";
49495050const session = Session.spawn("sh", ["-c", "echo 'spawned!'; sleep 1"]);
5151const ss = await session.waitForText("spawned!");
···6969After creating, call `session.attach()` to start receiving output:
70707171```typescript test
7272-import { Session } from "ptym/testing";
7272+import { Session } from "@myobie/pty/testing";
73737474const session = await Session.server("sh", ["-c", "echo 'served!'; sleep 30"]);
7575await session.attach();
···8585Send raw keystrokes:
86868787```typescript test
8888-import { Session } from "ptym/testing";
8888+import { Session } from "@myobie/pty/testing";
89899090const session = Session.spawn("cat");
9191session.sendKeys("hello\n");
···9999Send a named key. Supports modifiers with `+`:
100100101101```typescript test
102102-import { Session } from "ptym/testing";
102102+import { Session } from "@myobie/pty/testing";
103103104104const session = Session.spawn("cat");
105105session.sendKeys("test line\n");
···113113Alias for `sendKeys()` — sends text character by character:
114114115115```typescript test
116116-import { Session } from "ptym/testing";
116116+import { Session } from "@myobie/pty/testing";
117117118118const session = Session.spawn("cat");
119119session.type("typed text\n");
···143143Default timeout: 5000ms.
144144145145```typescript test
146146-import { Session } from "ptym/testing";
146146+import { Session } from "@myobie/pty/testing";
147147148148const session = Session.spawn("sh", ["-c", "sleep 0.1; echo 'delayed'"]);
149149const ss = await session.waitForText("delayed", 3000);
···156156Poll until the terminal no longer contains the given text:
157157158158```typescript test
159159-import { Session } from "ptym/testing";
159159+import { Session } from "@myobie/pty/testing";
160160161161const session = Session.spawn("sh", ["-c", "echo 'gone'; sleep 0.1; printf '\\033[2J\\033[H'"]);
162162await session.waitForText("gone");
···171171Poll until a custom predicate returns true:
172172173173```typescript test
174174-import { Session } from "ptym/testing";
174174+import { Session } from "@myobie/pty/testing";
175175176176const session = Session.spawn("sh", ["-c", "echo 'line 1'; echo 'line 2'; sleep 1"]);
177177const ss = await session.waitFor(
···213213### Testing a CLI tool
214214215215```typescript test
216216-import { Session } from "ptym/testing";
216216+import { Session } from "@myobie/pty/testing";
217217218218const session = Session.spawn("sh", ["-c", "echo 'Usage: mytool [options]'; sleep 1"]);
219219const ss = await session.waitForText("Usage:");
···226226Use the `ansi` field to verify ANSI escape codes:
227227228228```typescript test
229229-import { Session } from "ptym/testing";
229229+import { Session } from "@myobie/pty/testing";
230230231231const session = Session.spawn("sh", ["-c", "printf '\\033[31mERROR\\033[0m\\n'; sleep 1"]);
232232const ss = await session.waitForText("ERROR");
···242242that launches vim, enters insert mode, types text, and verifies the result:
243243244244```typescript test
245245-import { Session } from "ptym/testing";
245245+import { Session } from "@myobie/pty/testing";
246246247247const session = Session.spawn("vim", ["--clean"], { rows: 24, cols: 80 });
248248···271271regex to detect the prompt, then send commands and assert on their output:
272272273273```typescript test
274274-import { Session } from "ptym/testing";
274274+import { Session } from "@myobie/pty/testing";
275275276276const session = Session.spawn("bash", ["--norc", "--noprofile"]);
277277
+1-1
flake.nix
···29293030 # Generated from package-lock.json.
3131 # Regenerate with: nix run nixpkgs#prefetch-npm-deps -- package-lock.json
3232- npmDepsHash = "sha256-+65s9CLTJNlPt82HKOkngir4KZF1yCy96hderY0m2qQ=";
3232+ npmDepsHash = "sha256-rl5s8czRezWu0Fri4xWoMUkazBQfVXfuUf9hvBGw3Qw=";
33333434 # node-pty has native code that needs these at build time
3535 nativeBuildInputs = with pkgs; [ python3 pkg-config ];