Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

youseiushida/conch

Repository files navigation

Conch 🐚

Headless Terminal Driver for TUI Testing & Automation

CI License

πŸ‡―πŸ‡΅ ζ—₯本θͺžγƒ‰γ‚­γƒ₯γƒ‘γƒ³γƒˆγ―γ“γ‘γ‚‰

Conch is a robust library for programmatically controlling terminal applications. By combining node-pty for process management and @xterm/headless for accurate terminal emulation, Conch enables you to:

  • Test TUI Applications: Write integration tests for interactive CLI tools (vim, k9s, inquirer, etc.) with confidence.
  • Automate Terminal Tasks: Build bots that can navigate complex terminal interfaces, wait for specific states, and extract information.

Think of it as "Playwright for Terminals".

Features

  • Accurate Emulation: Uses xterm.js (headless) to maintain the exact state of the terminal screen, including cursor position, colors, and alternate buffers.
  • Flakiness-Free Waits: Built-in utilities like waitForText, waitForSilence, and waitForStable help you handle asynchronous terminal output reliably without random sleep().
  • Human-like Input: Simulate key presses (Enter, Esc, Ctrl+C) and typing naturally.
  • Snapshot Engine: Capture the "visual" state of the terminal at any moment to verify what the user actually sees.
  • TUI App Support: Built-in terminal query auto-responder (DA1, DA2, CPR, DECRQM) enables interactive TUI apps like vim, less, nano, and top to render correctly in headless mode.
  • Pluggable Backends: Supports Local PTY, Docker, and SSH. Designed for extensibility β€” tmux and WebSocket-based backends (ttyd, GoTTY) are planned.

Using Conch as an LLM/Agent Foundation (CLI/TUI that doesn’t get stuck)

LLMs are good at deciding what to do next, but they need a reliable execution substrate for terminals:

  • Observation: deterministic screen state via getSnapshot() (viewport or full scrollback)
  • Action: run(), pressAndSnapshot(), typeAndSnapshot()
  • Wait: waitForText / waitForStable / waitForSilence instead of fragile sleeps
  • Command boundaries: optional OSC 133 Shell Integration to detect prompt/command completion and exit codes

This lets you implement a robust loop: snapshot β†’ decide β†’ act β†’ wait β†’ snapshot, even for interactive TUI apps.

import { Conch } from "@ushida_yosei/conch";
const conch = await Conch.launch({
 backend: { type: "localPty", file: process.platform === "win32" ? "powershell.exe" : "bash", env: process.env },
 cols: 100,
 rows: 30,
 timeoutMs: 30_000,
 shellIntegration: { enable: true, strict: false }, // improves run() reliability
});
try {
 // (1) Bring up a TUI
 await conch.run("htop", { strict: false }); // example; pick your app
 // (2) Agent loop: observe β†’ decide β†’ act
 for (let step = 0; step < 20; step++) {
 const snap = conch.getSnapshot({ range: "viewport" });
 const screen = snap.text;
 // Your LLM/tooling decides the next key(s) from screen state
 const nextKey = screen.includes("Help") ? "F1" : "ArrowDown";
 await conch.pressAndSnapshot(nextKey, { wait: { kind: "change", timeoutMs: 5_000 } });
 }
} finally {
 conch.dispose();
}

Installation

Install from npm:

npm install @ushida_yosei/conch
# or
pnpm add @ushida_yosei/conch

Quick Start

Here is a simple example that spawns a shell, executes a command, and verifies the output.

import { Conch } from '@ushida_yosei/conch';
async function main() {
 // 1. Launch (backend + spawn + session)
 const conch = await Conch.launch({
 backend: { type: 'localPty', file: 'bash', args: [], env: process.env },
 cols: 80,
 rows: 24,
 timeoutMs: 30_000,
 });
 // 2. Execute a command
 conch.execute('echo "Hello Conch"');
 // 3. Wait for the output to appear on the virtual screen
 await conch.waitForText('Hello Conch');
 // 4. Inspect the screen state
 const snapshot = conch.getSnapshot();
 console.log('--- Terminal Screen ---');
 console.log(snapshot.text);
 // Cleanup
 conch.dispose();
}
main();

Docker Backend (DockerPty)

You can run Conch against a Docker container instead of a local PTY.

import { Conch } from "@ushida_yosei/conch";
const conch = await Conch.launch({
 backend: {
 type: "docker",
 image: "alpine:latest",
 cmd: ["/bin/sh"], // default
 autoRemove: true,
 },
 cols: 80,
 rows: 24,
 timeoutMs: 30_000,
});
try {
 const r = await conch.run('echo "hello from docker"', { strict: false });
 console.log(r.outputText);
} finally {
 conch.dispose();
}

Notes:

  • Requires a reachable Docker daemon (Docker Desktop / dockerd).
  • In TTY mode, stdout/stderr are combined into a single stream.
  • Shell Integration (OSC 133) in Docker usually requires an image with bash and cmd: ["bash"] (default is /bin/sh).

SSH Backend (SshPty)

You can run Conch against a remote server via SSH.

import { Conch } from "@ushida_yosei/conch";
import { readFileSync } from "fs";
const conch = await Conch.launch({
 backend: {
 type: "ssh",
 host: "example.com",
 username: "user",
 privateKey: readFileSync("/path/to/key"),
 // or: password: "secret",
 // or: agent: process.env.SSH_AUTH_SOCK,
 },
 cols: 80,
 rows: 24,
 timeoutMs: 30_000,
 shellIntegration: { enable: true, strict: false },
});
try {
 const r = await conch.run('echo "hello from SSH"');
 console.log(r.outputText); // "hello from SSH"
 console.log(r.exitCode); // 0
} finally {
 conch.dispose();
}

Notes:

  • Requires ssh2 as a peer dependency: npm install ssh2
  • Supports password, private key (with passphrase), and SSH agent authentication.
  • Connection loss is treated as a fatal error (no auto-reconnect). Create a new instance to reconnect.
  • Shell Integration (OSC 133) works over SSH when the remote shell is bash.
  • Host key verification is disabled by default (automation use case). Pass hostVerifier for strict checking.

TUI Application Support

Conch can drive interactive TUI applications (vim, less, nano, top, tmux) in headless mode. A built-in terminal query auto-responder handles the DA/CPR/DECRQM sequences that these apps send on startup.

const conch = await Conch.launch({
 backend: { type: "localPty", file: "bash", env: process.env },
 cols: 80,
 rows: 24,
 timeoutMs: 30_000,
});
// Open vim, type text, save and quit
conch.execute('vim --cmd "set t_RV=" /tmp/test.txt');
await conch.waitForText("~", { timeoutMs: 5_000 }); // wait for vim UI
conch.press("i"); // insert mode
conch.type("Hello from Conch!");
conch.press("Escape");
conch.type(":wq");
conch.press("Enter");
await conch.waitForStable({ durationMs: 500 });
conch.dispose();
Program Status Notes
vim/vi βœ… Use --cmd "set t_RV=" for instant rendering (otherwise ~4s delay due to PTY buffering)
less βœ… Alternate buffer, search, PageDown all work
nano βœ… Alternate buffer, text input, Ctrl+X quit all work
top βœ… Batch mode (-b -n 1) works. Interactive mode works with delay
tmux βœ… Session create/attach, commands inside tmux, session cleanup

Documentation

Roadmap

Implemented

  • Shell Integration (OSC 133): Full A/B/C/D marker support for command boundary detection and exit codes.
  • SSH Backend (SshPty): Connect to remote hosts via SSH with password, key, or agent authentication.

In Progress / Planned

  • TmuxPty Backend: Connect to tmux sessions with dispose() = detach semantics. Combines Conch's xterm.js precision with tmux's session persistence. Human debugging via tmux attach.
  • Press Modifier Keys: Full support for Alt+D, Ctrl+Shift+A, Shift+ArrowUp, etc. (~170 lines)
  • OSC 133 Library Extraction: Extract pure parsing/script logic into @ushida_yosei/exec-detector for reuse outside Conch.
  • WebSocket Backends: TtydPty (ttyd), GoTTYPty (GoTTY) for browser-based terminal sharing tools.
  • CLI (conch run): One-shot command execution with JSON output. Full xterm.js + OSC 133 support, no tmux required. For session persistence, use tmux directly.
  • KubernetesPty Backend: Direct connection to Kubernetes pods via the exec API (WebSocket + channel multiplexing).
  • Mouse Events: Click, scroll, drag simulation for TUI apps that support mouse input.
  • Visual Snapshot: Render terminal screen as SVG/PNG with color and attribute information.

License

MIT

About

Playwright for Terminals: A robust headless terminal driver for automating and testing TUI applications.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /