npm package: @love-moon/tui-driver
Description: TUI Driver for interactive CLI tools like Claude Code and Codex
Latest version: 0.2.15

# TUI Driver

A headless TUI driver for interacting with interactive CLI tools like Claude Code and Codex.

## Requirements

- Node.js >= 18.0.0 (recommended: Node.js 20.x LTS)
- node-pty requires native compilation (Python and build tools)

**Note**: node-pty may have compatibility issues with Node.js 23+. Use Node.js 20.x LTS for best compatibility.

## Features

- **PTY Session Management**: Spawn and manage pseudo-terminal sessions
- **Headless Terminal Emulation**: Parse ANSI sequences and maintain screen buffer using @xterm/headless
- **Expect Engine**: Wait for screen conditions with stability checks and idle detection
- **State Machine**: Track interaction states (BOOT, READY, TYPING, STREAMING, etc.)
- **Output Extraction**: Extract model responses using diff-based algorithms
- **Profile System**: Configurable profiles for different TUI tools

## Installation

```bash
pnpm install
pnpm build
```

## Usage

### Basic Usage

```typescript
import { createDriver } from "@love-moon/tui-driver";

const driver = createDriver("claude-code", { debug: true });

await driver.boot();
const result = await driver.ask("What is 2 + 2?");

if (result.success) {
  console.log("Answer:", result.answer);
}

driver.kill();
```

### Advanced Usage

```typescript
import { TuiDriver, claudeCodeProfile } from "@love-moon/tui-driver";

const driver = new TuiDriver({
  profile: claudeCodeProfile,
  debug: true,
  onSnapshot: (snapshot, state) => {
    console.log(`[${state}] Hash: ${snapshot.hash}`);
  },
});

await driver.boot();

// Multiple questions in sequence
const q1 = await driver.ask("Hello!");
const q2 = await driver.ask("What can you do?");

driver.kill();
```

### Custom Profile

```typescript
import { TuiDriver, createProfile } from "@love-moon/tui-driver";

const myProfile = createProfile({
  name: "claude-code",
  command: "my-cli",
  args: ["--interactive"],
  anchors: {
    ready: [/>\s*$/m, /prompt:/i],
    busy: [/thinking/i],
  },
  keys: {
    submit: ["ENTER"],
    cancel: ["CTRL_C"],
  },
  extraction: {
    mode: "diff-scrollback",
    stripPatterns: [/^>\s*/gm],
    bottomUiLines: 2,
  },
});

const driver = new TuiDriver({ profile: myProfile });
```

## Architecture

```
src/
  pty/
    PtySession.ts       # node-pty wrapper
  term/
    HeadlessScreen.ts   # @xterm/headless wrapper
    ScreenSnapshot.ts   # Screen state snapshot
  expect/
    ExpectEngine.ts     # Wait/expect engine
    Matchers.ts         # Pattern matchers
  driver/
    TuiProfile.ts       # Profile type definitions
    TuiDriver.ts        # Main driver class
    StateMachine.ts     # State management
    profiles/
      claudeCode.profile.ts
      codex.profile.ts
  extract/
    OutputExtractor.ts  # Response extraction
    Diff.ts             # Text diff utilities
```

## API Reference

### TuiDriver

- `boot()`: Initialize and wait for TUI to be ready
- `ask(prompt)`: Send a prompt and wait for response
- `ensureReady()`: Ensure TUI is in ready state
- `snapshot()`: Get current screen snapshot
- `sendKeys(keys)`: Send key sequences
- `kill()`: Terminate the PTY session

### ExpectEngine

- `until(options)`: Wait for condition with stability
- `untilIdle(options)`: Wait for screen to stop changing
- `waitForChange(timeout)`: Wait for any screen change

### ScreenSnapshot

- `viewportText`: Current visible screen content
- `scrollbackText`: Full scrollback buffer
- `cursor`: Current cursor position
- `hash`: Screen content hash for change detection