@cjwddz/termctl
v1.0.0
Published
Session-aware terminal CLI for LLM Agents
Maintainers
Readme
@cjwddz/termctl
A minimalist, session-aware terminal CLI tool designed for LLM Agent interaction with PTY-based persistent shell sessions.
Features
- Session as First-Class Citizen: Each session has a unique name as the primary key
- PTY-Based: Uses
node-ptyfor real pseudo-terminal sessions - Incremental Output Reading: Default incremental read with
readCursortracking - Concurrent Safe: Mutex-based operation serialization per session
- Agent Friendly: Minimal abstraction, predictable behavior, no semantic inference
- Clean Shutdown: Automatic process cleanup on exit, no zombie processes
Requirements
- Node.js 18+
- macOS or Linux
- TypeScript 5+
Installation
npm install -g @cjwddz/termctlCLI Usage
Create a Session
termctl create <name> [--shell <shell>]- Creates a new PTY session with unique name
- Returns error if name exists and status is
running - Uses system default shell (
process.env.SHELL) by default
Example:
termctl create devResponse:
{
"name": "dev",
"status": "running",
"createdAt": 1710000000
}List Sessions
termctl listReturns all sessions with minimal fields:
[
{
"name": "dev",
"status": "running",
"createdAt": 1710000000
}
]Write Command to Session
termctl write <name> "<command>"- Writes command to PTY and appends newline
- Non-blocking operation
- Updates internal
lastActivetimestamp
Example:
termctl write dev "echo hello world"Response:
{
"success": true
}Read Output from Session
termctl read <name> [--full] [--tail <n>]Default behavior (incremental):
- Returns new output since last read
- Updates
readCursorinternally
Options:
--full: Return all output (does not changereadCursor)--tail=n: Return last n lines (does not changereadCursor)
Example:
# Incremental read (default)
termctl read dev
# Read full output
termctl read dev --full
# Read last 10 lines
termctl read dev --tail 10Response:
{
"output": "new output text",
"hasMore": false
}Delete Sessions
termctl delete <name1> <name2> ... [--all]Behavior:
- Sends SIGTERM to PTY process
- Waits up to 2 seconds
- If not exited, sends SIGKILL
- Cleans up memory and persistent state
- Sets status to
closed
Options:
--all: Delete all non-running sessions
Examples:
# Delete specific sessions
termctl delete dev test
# Delete all non-running sessions
termctl delete --allResponse:
{
"success": true,
"deleted": ["dev", "test"]
}API Usage
import { SessionManager } from "@cjwddz/termctl";
const manager = new SessionManager();
// Initialize
await manager.init();
// Create session
const session = await manager.create({
name: "dev",
shell: "/bin/bash",
});
// List sessions
const sessions = await manager.list();
// Write command
await manager.write({
name: "dev",
command: "echo hello",
});
// Read output (incremental)
const { output, hasMore } = await manager.read({
name: "dev",
});
// Read full output
const fullOutput = await manager.read({
name: "dev",
full: true,
});
// Delete session
await manager.delete("dev");
// Cleanup
await manager.cleanup();Design Principles
- Session is First-Class: Everything revolves around sessions
- No Extra Fields: No description, role, metadata, or semantic pollution
- No Auto-Inference: Predictable behavior, no smart guessing
- Idempotent: Operations are safe to repeat
- Minimal Abstraction: Thin wrapper over node-pty
- Agent Runtime Focused: Designed for LLM agents, not human interaction
Output Buffer
- Maximum buffer size: 5MB
- Old data is discarded when buffer exceeds limit
readCursoris adjusted when truncation occurs
Process Cleanup
On CLI exit (SIGINT, normal exit, or crash):
- All running PTY processes receive SIGTERM
- Wait 2 seconds, then SIGKILL if needed
- Persistent state is cleaned up
Error Handling
All errors are output to stderr with non-zero exit code:
termctl create existing-session
# Error: Session "existing-session" already exists and is running
# (exit code: 1)License
MIT
