Prompts an agent can answer
Declare each prompt on the option it fills, so an agent answers on the command line, --json refuses instead of asking, and the refusal tells the agent exactly what to pass.
An agent driving your CLI cannot type into a prompt. It can pass a flag, and it can act on an error that names one. Declaring the prompt on the option it fills gives it both:
import process from 'node:process';
import { processRuntime } from 'caique';
import { resolvePrompts } from 'caique/binding';
import { createIo } from 'caique/terminal';
const argv = process.argv.slice(2);
const json = argv.includes('--json');
const name = argv.find((a) => a.startsWith('--name='))?.slice('--name='.length);
const io = createIo();
const { values, failure } = await resolvePrompts({
options: { name: { required: true, prompt: { kind: 'text', message: 'Project name?' } } },
values: { name },
runtime: processRuntime(),
flags: { json },
io,
});
io.close();
if (failure) {
if (json) console.log(JSON.stringify({ ok: false, error: { code: failure.code, message: failure.message, fix: failure.fix } }));
else console.error(`${failure.message}\n fix: ${failure.fix}`);
process.exitCode = 2;
} else {
console.log(json ? JSON.stringify({ ok: true, name: values.name }) : `created ${values.name}`);
}{"ok":false,"error":{"code":"USAGE","message":"--name is required under --json","fix":"pass --name; --json means no one is here to answer \"Project name?\""}}{"ok":true,"name":"demo"}The refusal is structured, carries the flag and quotes the question, and the second call is the
one an agent makes after reading it. The same program asks a person on a terminal, and under
--json never does, terminal or not.
A CLI on burgee gets this without the wiring: its
--json envelope already carries code, message and fix.
Coming from clack
A clack (@clack/prompts) alternative with two ways across: caique/clack, clack's prompts under clack's names on caique's own engine, graded by clack's own suite; or caique's flag-first prompts, where a non-TTY caller gets an error naming the flag instead of a hang.
Confirmations in CI
Let --yes answer a destructive confirm in CI and scripts, while a required text or select with no value still refuses — --yes never invents an answer to a question with more than two.