Commit graph

10 commits

Author SHA1 Message Date
hermes
74e5bb0536 feat: login-free Stockbit intraday and quote provider
Read Stockbit's public symbol page (__NEXT_DATA__) with a plain ureq
request and an honest user agent: `stocks intraday` (today by the
minute, any provider), `--provider stockbit` quotes with the best
bid/offer only while the market is open, and MCP `get_intraday`.

- UPSTREAMBLOCKED error (exit 4) for a CDN 403; never retried
- requests paced 1 s apart across idx processes, 5 s snapshot cache
- global --provider flag (yahoo, msn, stockbit)
- roadmap: L1 ships from Stockbit; depth stays a login follow-on
2026-10-23 04:58:32 +00:00
hermes
8e3323e4f7 chore: release 0.3.0 with idx-mcp
Bump the workspace and npm packages to 0.3.0. The release workflow
builds and attaches idx-mcp binaries next to idx, the npm launcher and
installer pick their binary from package.json so npm/idx-mcp reuses
them, and the npm smoke test covers both packages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 19:01:29 +00:00
hermes
cda12fe2db feat(mcp): add idx-mcp, a stdio MCP server over idx-core
Phase 4 of docs/DESIGN.md. Eleven grouped tools (quotes, history, screen,
company, analysis, compare, shareholders, investor holdings, search,
ownership changes, status); ownership_sync is listed only with
--allow-sync. Live results keep the Fetched envelope, errors use the CLI's
{error, code, message} body, and investor tools on an empty database
point at the sync path.

idx-core gains Period/Interval FromStr, Investor::status, a ticker
filter on changes, and Display for ErrorCode (now used by the CLI too).
CLI output and goldens are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:19:04 +00:00
hermes
1d8b615857 refactor(core): move ownership queries, import, and sync into idx-core
Phase 3c of docs/DESIGN.md. `ownership` handlers are now argument
parsing, one idx-core call, and rendering.

- investor.rs: Investor (also Idx::investor()) with releases, ticker,
  entity, search, cross_holders, concentration, flow, changes, graph,
  unresolved, map_alias, merge_entities, discover, sync, and import.
  Import orchestration (input resolution, download, SHA-256 dedup,
  PDF/XLSX/archive parsing, entity resolution, release write) moves
  from the CLI unchanged.
- Typed inputs: ImportSource, HolderSource, ConcentrationRank, and
  parse_report_family, with the same error messages.
- CoreConfig gains an ownership_db override; db::open_db_at opens an
  explicit path. idx-cli no longer depends on rusqlite, sha2, or ureq
  at runtime.
- Behavior note: an invalid `ticker --source` or `concentration --by`
  is now rejected before the database file is opened (and created);
  the error and exit code are unchanged.
- Fix: building idx-cli without the ownership feature no longer warns
  about the ownership-only `blue` style.

All 143 goldens unchanged; 170 core + 7 CLI unit tests and 62 CLI tests
pass; clippy clean for default, release, testing, and no-default
feature sets. Live A/B against main: 16/16 stocks identical; ownership
discover got IDX 403 on both (exit 4 vs 1 is the phase 1 change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:52:17 +00:00
hermes
86cb1b4b7c refactor(core): move stocks fetching, caching, and analysis into idx-core
Phase 3b of docs/DESIGN.md. `stocks` handlers are now argument parsing,
one idx-core call, and rendering.

- Idx (client.rs) is the entry point: Idx::new(CoreConfig) with
  market(), financial(), and analysis(). Live lookups return
  Fetched<T> { data, source, fetched_at, stale } and take a CachePolicy
  (Default | Offline | Refresh, from the --offline/--no-cache flags).
- One cached_fetch replaces the CLI's three cache flows; they differed
  only in whether a fresh entry is read via get or get_offline when
  offline, which yields the same data and diagnostics. Report-building
  errors (technical) still skip the stale-cache fallback.
- market.rs: quotes, history (history_source is resolved first so the
  CLI's fallback note keeps its position), and a typed screener
  (ScreenFilter/ScreenRegion with the same error messages).
- financial.rs: profile, statements, earnings, sentiment, insights,
  news, with StatementFilter/EarningsFilter.
- analysis: TechnicalReport moves to analysis::report; Analysis offers
  technical, growth, valuation, risk, fundamental, and compare.
- CoreConfig::load() owns provider/exchange/TTL settings from
  config.toml and IDX_*; the CLI's IdxConfig adds output and color.
  With two different invalid settings at once, the reported one may
  differ from before; every single-error message is unchanged.
- Cache gains fresh/any/offline accessors returning fetch metadata.

Unit tests moved with their code (core 157 -> 168, CLI 17 -> 7). All
143 goldens unchanged; live A/B against main: 16/16 stocks identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:41:31 +00:00
hermes
e78d9fcecd refactor(core): compile the mock provider only with a testing feature
Phase 3a of docs/DESIGN.md. MockProvider moves to api/mock.rs, and it,
the embedded MSN fixture bodies, and the IDX_MOCK_* hooks compile only
with idx-core's new `testing` feature. idx-cli enables it as a
dev-dependency, so `cargo test` keeps the fixture-backed provider while
release binaries no longer embed fixture data or honor
IDX_USE_MOCK_PROVIDER. Parser helpers used only by the mock are gated
the same way.

The packaged-cli flake check no longer relies on the mock; it checks
an offline cache miss (JSON CACHEMISS, exit 3) instead.

Goldens unchanged; clippy is clean with and without `testing`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:31:12 +00:00
hermes
15947de51a refactor: split into idx-core library and idx-cli binary workspace
Phase 2 of docs/DESIGN.md, no behavior change:

- crates/idx-core (library): api, analysis, cache, config file handling
  and provider selection, curl_impersonate, error, ownership, runtime,
  plus the shared test fixtures. clap derives are behind an optional
  `clap` feature so the library does not require clap.
- crates/idx-cli (binary `idx`): cli/, output/, and IdxConfig (output
  format and color resolution). Package and binary names are unchanged.
- config.rs is split: file read/write and validation move to core; a
  CLI test keeps core's OUTPUT_VALUES in sync with OutputSetting.
- ownership::db::open_db/db_path drop their unused IdxConfig argument.
- One workspace version; shared dependency versions; no third-party
  version changes in Cargo.lock. LICENSE is symlinked into each crate.
- flake: workspace version, new source paths, and a per-crate package
  check (idx-cli is built from its tarball against packaged idx-core,
  since idx-core is not on crates.io yet). CI cache key, release path
  filter, and the golden whitespace-hook exclusion follow the new layout.

Parity: all 143 golden outputs match byte for byte without
regeneration; 157 core + 17 CLI unit tests (173 before plus the new
OUTPUT_VALUES sync test), 62 CLI tests pass. Live A/B against main:
16/16 stocks cases identical; ownership discover got IDX 403 on both
(exit 4 vs 1 is the phase 1 exit-code change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:13:46 +00:00
hermes
22b6dabaeb 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>
2026-10-14 08:52:13 +00:00
hermes
fe627496dd test: add golden output parity gate and live A/B compare
Phase 0 of docs/DESIGN.md, before any refactor code:

- tests/golden.rs runs every case in tests/golden/cases.toml (126
  outputs across help, completions, config, cache, all stocks commands
  on MSN and Yahoo mocks, error paths, and ownership queries on a seeded
  fixture DB) and compares exit code, stdout, and stderr byte for byte.
  Regenerate only with UPDATE_GOLDEN=1 for a reviewed output change.
- scripts/live-smoke.sh --compare <old-idx> runs each live case with
  both binaries and fails on differing exit codes, added/missing/retyped
  JSON keys, or changed values for slow-moving data.
- Exclude golden files from the whitespace/EOF pre-commit fixers, which
  would otherwise rewrite pinned help output.

Both gates were fault-injected: a one-word table change fails exactly
the three history goldens, and a binary dropping profile.long_name fails
only the profile live comparison.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:33:25 +00:00
hermes
535ef64a0c docs: add idx-core / idx-mcp system design
Accepted design for extracting idx-core as the shared data layer, the
agent-native CLI output contract, idx-mcp tools, packaging, and the
parity gates (golden output tests plus live A/B check) that the
refactor must pass before merging to main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:18:17 +00:00