[Bug]: -f with an unknown format silently renders a table instead of failing
Description
-f/--format accepts any string. An unrecognised value is not rejected: render() falls through to the default: branch of its switch and prints a table, exit code 0. A script or an agent that asks for a format it believes exists gets tabular output with box-drawing characters and no indication that its request was ignored.
The closed set is advertised. --help prints choices: table, plain, json, yaml, md, csv, and that list is declared in COMMON_OPTIONS in src/help.js. Nothing enforces it.
The inconsistency is internal to the same option table: --trace, declared with choices in the same block, is enforced — by an explicit normaliser that throws ArgumentError, alongside normalizeSiteSession, normalizeBooleanOption and normalizeWindowMode in src/execution.js. --format has no equivalent.
This bites agents hardest, because the wrong output is still parseable-looking text rather than an error.
Steps to Reproduce
Reproduces on a core command, so it is not adapter-specific:
$ opencli list -f bogus
opencli/list
┌───────────────────────────────────┬───────────────────┬─── ... (a table)
$ echo $?
0
$ opencli list -f csv # for contrast
command,site,name,aliases,description,access,strategy,browser,args
...
$ echo $?
0Same on an adapter command, and next to --trace for comparison:
$ opencli eur-lex get 32024R1689 --chars 10 -f bogus
eur-lex/get
┌────────────┬────────────────┬──── ... (a table, exit 0)
$ opencli eur-lex get 32024R1689 --chars 10 --trace bogus
ok: false
error:
code: ARGUMENT
message: '--trace must be one of: off, on, retain-on-failure. Received: "bogus"'
exitCode: 2Expected Behavior
-f bogus should fail the way --trace bogus already does: ArgumentError, exit 2, and a message naming the accepted values — --format must be one of: table, plain, json, yaml, md, csv. Received: "bogus".
The list already exists in COMMON_OPTIONS, so the fix can reuse it rather than restate it, which also keeps --help and the validation from drifting apart.
Two adjacent notes, both smaller than the above:
render()also silently downgradestabletoyamlwhen stdout is not a TTY. That behaviour is reasonable and documented in the code, but it meansfooterExtradisappears in every pipe — so an answer-level value put in the footer is unreachable to any non-interactive caller. Adapters can work around it by making the value a column; worth knowing when writing the guidance for adapter authors.- Feature, separable from the bug:
jsonlwould be a welcome seventh format — one JSON object per line, no enclosing array. It is the natural shape for streaming intojq,duckdb read_ndjson_auto, or a line-oriented pipeline, and today it needs-f json | jq -c '.[]', which buffers the whole array first.renderJsonlis a four-line neighbour ofrenderCsv. Happy to open it as its own feature request if you would rather keep this issue to the bug.
OpenCLI Version
1.8.7
Environment
- Node.js v24.18.0
- Linux (WSL2), zsh
Source: jackwener/OpenCLI