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,175 +1,4 @@
exit: 0
--- stdout
[
{
"entity": {
"id": 11,
"canonical_name": "ASTRA INTERNATIONAL",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 7968
},
{
"entity": {
"id": 14,
"canonical_name": "DWIMURIA INVESTAMA ANDALAN",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 5494
},
{
"entity": {
"id": 4,
"canonical_name": "ADARO STRATEGIC INVESTMENTS",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 4110
},
{
"entity": {
"id": 5,
"canonical_name": "ALAMTRI RESOURCES INDONESIA TBK PT",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 1537
},
{
"entity": {
"id": 7,
"canonical_name": "GARIBALDI THOHIR",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 583
},
{
"entity": {
"id": 2,
"canonical_name": "SARATOGA INVESTAMA SEDAYA",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 438
},
{
"entity": {
"id": 9,
"canonical_name": "EDWIN SOERYADJAYA",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 352
},
{
"entity": {
"id": 8,
"canonical_name": "IR. T. PERMADI RACHMAT",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 348
},
{
"entity": {
"id": 13,
"canonical_name": "YAYASAN ABDI BANGSA",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 283
},
{
"entity": {
"id": 10,
"canonical_name": "SANDIAGA SALAHUDDIN UNO",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 204
},
{
"entity": {
"id": 1,
"canonical_name": "PERSADA CAPITAL INVESTAMA",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 154
},
{
"entity": {
"id": 12,
"canonical_name": "YAYASAN BINA SEJAHTERA WARGA BULOG",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 135
},
{
"entity": {
"id": 6,
"canonical_name": "FTAG INVESTMENT BANK",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 129
},
{
"entity": {
"id": 17,
"canonical_name": "ANTHONI SALIM",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 115
},
{
"entity": {
"id": 3,
"canonical_name": "TRINUGRAHA THOHIR",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 115
},
{
"entity": {
"id": 16,
"canonical_name": "TRICIPTA MANDHALA GUMILANG",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 107
},
{
"entity": {
"id": 15,
"canonical_name": "CATURGUWIRATNA SUMAPALA",
"entity_type": null,
"country": null
},
"ticker_count": 1,
"total_bps": 102
}
]
[{"entity":{"id":11,"canonical_name":"ASTRA INTERNATIONAL","entity_type":null,"country":null},"ticker_count":1,"total_bps":7968},{"entity":{"id":14,"canonical_name":"DWIMURIA INVESTAMA ANDALAN","entity_type":null,"country":null},"ticker_count":1,"total_bps":5494},{"entity":{"id":4,"canonical_name":"ADARO STRATEGIC INVESTMENTS","entity_type":null,"country":null},"ticker_count":1,"total_bps":4110},{"entity":{"id":5,"canonical_name":"ALAMTRI RESOURCES INDONESIA TBK PT","entity_type":null,"country":null},"ticker_count":1,"total_bps":1537},{"entity":{"id":7,"canonical_name":"GARIBALDI THOHIR","entity_type":null,"country":null},"ticker_count":1,"total_bps":583},{"entity":{"id":2,"canonical_name":"SARATOGA INVESTAMA SEDAYA","entity_type":null,"country":null},"ticker_count":1,"total_bps":438},{"entity":{"id":9,"canonical_name":"EDWIN SOERYADJAYA","entity_type":null,"country":null},"ticker_count":1,"total_bps":352},{"entity":{"id":8,"canonical_name":"IR. T. PERMADI RACHMAT","entity_type":null,"country":null},"ticker_count":1,"total_bps":348},{"entity":{"id":13,"canonical_name":"YAYASAN ABDI BANGSA","entity_type":null,"country":null},"ticker_count":1,"total_bps":283},{"entity":{"id":10,"canonical_name":"SANDIAGA SALAHUDDIN UNO","entity_type":null,"country":null},"ticker_count":1,"total_bps":204},{"entity":{"id":1,"canonical_name":"PERSADA CAPITAL INVESTAMA","entity_type":null,"country":null},"ticker_count":1,"total_bps":154},{"entity":{"id":12,"canonical_name":"YAYASAN BINA SEJAHTERA WARGA BULOG","entity_type":null,"country":null},"ticker_count":1,"total_bps":135},{"entity":{"id":6,"canonical_name":"FTAG INVESTMENT BANK","entity_type":null,"country":null},"ticker_count":1,"total_bps":129},{"entity":{"id":17,"canonical_name":"ANTHONI SALIM","entity_type":null,"country":null},"ticker_count":1,"total_bps":115},{"entity":{"id":3,"canonical_name":"TRINUGRAHA THOHIR","entity_type":null,"country":null},"ticker_count":1,"total_bps":115},{"entity":{"id":16,"canonical_name":"TRICIPTA MANDHALA GUMILANG","entity_type":null,"country":null},"ticker_count":1,"total_bps":107},{"entity":{"id":15,"canonical_name":"CATURGUWIRATNA SUMAPALA","entity_type":null,"country":null},"ticker_count":1,"total_bps":102}]
--- stderr