feat(cli): agent-native output, stdin symbols, and exit-code classes

Phase 1 of docs/DESIGN.md:

- Output format resolves -o > IDX_OUTPUT > general.output > auto; auto
  is a table on a terminal and JSON when stdout is piped or captured.
  `config init` now writes output = "auto".
- JSON is pretty only on a terminal and compact otherwise. New `-o
  jsonl` prints one array item per line with the same key order.
- No ANSI color when stdout is not a terminal (direct owo-colors calls
  now go through output::style).
- `stocks quote -` and `stocks compare -` read symbols from stdin.
- Exit codes by class: 2 invalid input/config, 3 not found or cache
  miss, 4 upstream unavailable, 5 unsupported, 1 other.

Golden changes are limited to those documented kinds and were verified
mechanically: JSON goldens are semantically identical, tables differ
only by removed ANSI codes and the column padding comfy-table had
reserved for them (cell contents identical), exit codes match each
error's class, and help/completions only gain the new --output values.
17 new golden cases cover auto, jsonl, stdin, and the new errors.

tests/cli.rs now pins IDX_OUTPUT=table in its harness (its tests assert
table text and run piped) and parses discover JSON instead of matching
pretty-printed whitespace.

Live A/B against main: 16/16 stocks cases identical; ownership discover
got IDX 403 on both binaries, now exiting 4 instead of 1 as intended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
hermes 2026-10-14 08:52:13 +00:00
commit 22b6dabaeb
119 changed files with 920 additions and 1896 deletions

View file

@ -1,67 +1,4 @@
exit: 0
--- stdout
{
"ticker": {
"id": 4,
"code": "BBCA",
"name": "BANK CENTRAL ASIA Tbk",
"sector": null
},
"ksei_as_of": "2026-08-31",
"bing_as_of": null,
"holders": [
{
"rank": 1,
"source": "ksei",
"name": "DWIMURIA INVESTAMA ANDALAN",
"entity_id": 14,
"investor_type": "CORPORATE",
"locality": "Local",
"shares": 67729950000,
"percentage_bps": 5494,
"signal": null
},
{
"rank": 2,
"source": "ksei",
"name": "ANTHONI SALIM",
"entity_id": 17,
"investor_type": "INDIVIDUAL",
"locality": "Local",
"shares": 1416306835,
"percentage_bps": 115,
"signal": null
},
{
"rank": 3,
"source": "ksei",
"name": "TRICIPTA MANDHALA GUMILANG",
"entity_id": 16,
"investor_type": "CORPORATE",
"locality": "Local",
"shares": 1313250000,
"percentage_bps": 107,
"signal": null
},
{
"rank": 4,
"source": "ksei",
"name": "CATURGUWIRATNA SUMAPALA",
"entity_id": 15,
"investor_type": "CORPORATE",
"locality": "Local",
"shares": 1261750000,
"percentage_bps": 102,
"signal": null
}
],
"concentration": {
"top1_bps": 5494,
"top3_bps": 5716,
"hhi": 3021,
"free_float_bps": 4182,
"holder_count": 4
},
"flow": null
}
{"ticker":{"id":4,"code":"BBCA","name":"BANK CENTRAL ASIA Tbk","sector":null},"ksei_as_of":"2026-08-31","bing_as_of":null,"holders":[{"rank":1,"source":"ksei","name":"DWIMURIA INVESTAMA ANDALAN","entity_id":14,"investor_type":"CORPORATE","locality":"Local","shares":67729950000,"percentage_bps":5494,"signal":null},{"rank":2,"source":"ksei","name":"ANTHONI SALIM","entity_id":17,"investor_type":"INDIVIDUAL","locality":"Local","shares":1416306835,"percentage_bps":115,"signal":null},{"rank":3,"source":"ksei","name":"TRICIPTA MANDHALA GUMILANG","entity_id":16,"investor_type":"CORPORATE","locality":"Local","shares":1313250000,"percentage_bps":107,"signal":null},{"rank":4,"source":"ksei","name":"CATURGUWIRATNA SUMAPALA","entity_id":15,"investor_type":"CORPORATE","locality":"Local","shares":1261750000,"percentage_bps":102,"signal":null}],"concentration":{"top1_bps":5494,"top3_bps":5716,"hhi":3021,"free_float_bps":4182,"holder_count":4},"flow":null}
--- stderr