Quick Start¶
Install¶
Start¶
import { Terminal } from '@johannes.latzel/terminal';
const term = new Terminal({ prompt: 'λ ' });
term.start();
Type help to list builtins and exit to quit.
Add a command¶
command() defines a leaf command and returns a Command for terminal.register():
import { Terminal, command } from '@johannes.latzel/terminal';
const term = new Terminal();
term.register(
command('greet', 'Say hello', [], (ctx) => {
ctx.stdout.write('Hello, World!\n');
})
);
term.start();
Add arguments¶
Declare with arg() and zod schemas. Read with require<T>() (values) or flag() (booleans):
import { z } from 'zod';
import { Terminal, command, arg } from '@johannes.latzel/terminal';
const term = new Terminal();
term.register(
command(
'greet',
'Say hello',
[
arg('name', 'Who to greet', z.string().min(1)),
arg('count', 'Times to greet', z.coerce.number().int().positive()),
arg('verbose', 'Show details', z.boolean())
],
async (ctx, args) => {
const name = await args.require<string>('name');
const count = args.has('count') ? await args.require<number>('count') : 1;
if (await args.flag('verbose'))
ctx.stdout.write(`Greeting ${name} ${count} time(s)...\n`);
for (let i = 0; i < count; i++) ctx.stdout.write(`Hello, ${name}!\n`);
}
)
);
term.start();
Tab completion suggests --name, --count, --verbose.
Interactive prompting¶
Missing required arguments prompt interactively when a readline is available:
Without a readline (piped input), InvalidArgumentsError is thrown instead.
Note: Use
flag()for booleans —--verbose→true,--verbose false→false, absent →false. Don't usez.coerce.boolean()—Boolean("false")istrue. Define boolean schemas asz.boolean().
Array arguments¶
Arguments with an array schema (z.array(...)) auto-split on commas. Unquoted bare tokens after --flag are grouped onto the flag:
const fields = await args.require<string[]>('fields');
// --fields id, name → ['id', 'name']
// --fields one two → ['one two'] (single array element, no comma)
Build a command tree¶
Use container() to group commands under a namespace:
import { Terminal, command, container } from '@johannes.latzel/terminal';
const term = new Terminal();
term.register(
container('config', 'Configuration', [
command('get', 'Get a value', [], (ctx) => ctx.stdout.write('value\n')),
command('set', 'Set a value', [], (ctx) => ctx.stdout.write('ok\n'))
])
);
term.start();
Lifecycle hooks¶
See Hooks for the full API.
term.hook()
.beforeParse()
.do((input) => (input.startsWith('!') ? input.slice(1) : input));
term.hook()
.onError()
.do((error) => true); // suppress default error output
Call .dispose() on the returned Hook to unregister.
Commands — class-based commands, argument definitions, advanced patterns
API Reference