Plain output for agents and CI
Wire --json and --no-color through the runtime so an agent, a CI log and a user who opts out all get plain text, from one fly() at startup.
An agent reading your CLI's output, a CI log and a user who typed --no-color all want the
same thing: no escape codes. Hand the policy what it needs — the environment, the arguments and
whether stdout is a terminal — and pass { json } when the run asked for structured output.
Nothing else in the program has to check.
import process from 'node:process';
import { fly } from 'roundel/theme';
import { error, ok } from 'roundel/tokens';
const argv = process.argv.slice(2);
const json = argv.includes('--json');
fly({}, { env: process.env, argv, isTTY: { stdout: process.stdout.isTTY === true } }, { json });
const results = [
['api', true],
['web', false],
];
if (json) console.log(JSON.stringify(Object.fromEntries(results)));
else for (const [name, passed] of results) console.log(JSON.stringify(`${name} ${passed ? ok('passed') : error('failed')}`));"api \u001b[32mpassed\u001b[39m"
"web \u001b[91mfailed\u001b[39m""api passed"
"web failed"{"api":true,"web":false}(JSON.stringify around each line only makes the escape codes visible here.)
--no-color wins over the FORCE_COLOR=1 a CI configuration exported, because it was typed
for this run. --json would be plain even if a token slipped into the structured output,
because the level under --json is always 0.
A program built on burgee gets all of this without the
wiring: burgee hands roundel its runtime and its --json flag.
Coming from chalk
A chalk alternative with a drop-in path: import chalk from roundel/chalk, graded 58 / 58 by chalk's own test suite — then semantic tokens that go plain on a pipe, under NO_COLOR and under --json.
Testing coloured output
Assert what your CLI prints at each colour level by flying a literal runtime — no environment patching, no fake terminal.