Widget plugins
A plugin adds a prompt kind beyond the six as a widget with a required static projection; register() validates it, projectionOf() draws any kind, and npx caique check validates a plugin before it ships.
caique hosts one plugin key, widgets: how to draw a prompt kind that is not one of the
six built-ins. A plugin is the family's one plain object, so the same file can carry roundel's
tokens or flagstaff's spinners, and caique keeps the key it reads and ignores the rest.
Writing one
export default {
name: 'rating',
widgets: {
rating: {
static: (spec) => `${spec.message} (1-5)`,
sample: { running: {}, done: {} },
},
},
};A widget's static(spec) is required: it is what a pipe, an agent and a screen reader get,
the same surface projection() gives the six built-ins. frame(t, spec) is optional and
drives raw mode; sample is what check renders it with.
Registering it
import { kinds, projectionOf, register } from 'caique/plugin';
import rating from './rating.mjs';
register(rating);
console.log(kinds().join(', '));
console.log(projectionOf({ kind: 'rating', message: 'How was the install?' }));
console.log(projectionOf({ kind: 'select', message: 'Which host?', choices: [{ value: 'ora' }, { value: 'boxen' }] }));
try {
projectionOf({ kind: 'ratng', message: 'typo' });
} catch (error) {
console.log(`${error.code}: ${error.message}`);
}text, confirm, select, multiselect, password, path, rating
How was the install? (1-5)
Which host?
1) ora
2) boxen
enter a number (1-2):
E_UNKNOWN_KIND: no widget draws prompt kind "ratng" — registered kinds: ratingprojectionOf(spec) draws any kind: the six are still caique's, anything else is a registered
widget's static. A kind nobody registered is a refusal naming what is registered, so a typo
shows as a typo rather than as a text prompt where a rating should have been.
- Later wins, like flat config, and
widgets()reports who shadowed whom. - The six built-ins cannot be replaced: a widget named
passwordis refused, so a third party cannot swap the one prompt that must not echo. - A refused plugin is not registered — validation is at the door.
Refusals
A widget without static is refused with E_NO_STATIC_PROJECTION, the code flagstaff and
paratext use for the same rule, and with the fix. npx caique check shows it before the plugin
ships:
rating — 1 widgets
rating static "preview (1-5)"
rating: okexport default { name: 'stars', widgets: { stars: { frame: () => '*' } } };E_NO_STATIC_PROJECTION: plugin "stars": widget "stars" has no static projection
fix: add `static: (spec) => "…"` — it is what a pipe, an agent and a screen reader getnpx caique check loads the file without registering it and exits 0, 1 with the code and the
fix, or 2 on a usage error.
The terminal
createIo() reads lines from a real terminal and hides a password without turning echo off; askList() adds arrow keys where there is a terminal, and puts raw mode back exactly as it found it.
Why caique
caique against inquirer and clack, one capability per row, every cell linked to the test, grade or source that proves it.