mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 01:35:36 +00:00
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>
This commit is contained in:
parent
e78d9fcecd
commit
86cb1b4b7c
16 changed files with 1613 additions and 1301 deletions
|
|
@ -4,16 +4,18 @@
|
|||
|
||||
The repo is a Cargo workspace with one shared version:
|
||||
|
||||
- `crates/idx-core` (library): providers (`api/`), `analysis/`, `cache`, config
|
||||
file handling and provider selection (`config`), `ownership/` (SQLite, parsers,
|
||||
discovery, snapshot sync), `error`, and `runtime` (quiet/info/warn). It owns the
|
||||
shared test fixtures in `tests/fixtures/`.
|
||||
- `crates/idx-core` (library): the `Idx` entry point with `market()`,
|
||||
`financial()`, and `analysis()` (cache policy and `Fetched<T>` in `client.rs`),
|
||||
providers (`api/`), `analysis/`, `cache`, `config` (`CoreConfig`),
|
||||
`ownership/` (SQLite, parsers, discovery, snapshot sync), `error`, and
|
||||
`runtime` (quiet/info/warn). It owns the shared test fixtures in
|
||||
`tests/fixtures/`; the fixture-backed mock provider needs the `testing` feature.
|
||||
- `crates/idx-cli` (binary `idx`): clap commands (`cli/`), output format and
|
||||
color resolution (`config.rs`, `IdxConfig`), and rendering (`output/`). Its
|
||||
`tests/` hold the CLI integration and golden output suites.
|
||||
|
||||
Some fetch/cache orchestration still lives in `crates/idx-cli/src/cli/` until
|
||||
phase 3 of `docs/DESIGN.md` moves it into idx-core.
|
||||
Ownership import/sync orchestration still lives in
|
||||
`crates/idx-cli/src/cli/ownership.rs` until phase 3c of `docs/DESIGN.md`.
|
||||
|
||||
## Domain Map
|
||||
|
||||
|
|
|
|||
|
|
@ -59,21 +59,25 @@ A single entry point holds configuration, providers, cache, and the DB path.
|
|||
Domain methods hang off it.
|
||||
|
||||
```rust
|
||||
let idx = Idx::builder()
|
||||
.config(CoreConfig::load()?) // provider, TTLs, paths; no output settings
|
||||
.build()?;
|
||||
let idx = Idx::new(CoreConfig::load()?)?; // provider, TTLs, cache dir; no output settings
|
||||
let policy = CachePolicy::Default;
|
||||
|
||||
// market
|
||||
let quotes: Fetched<Vec<Quote>> = idx.market().quotes(&["BBCA", "BBRI"], CachePolicy::Default)?;
|
||||
let candles: Fetched<Vec<Ohlc>> = idx.market().history("BBCA", Period::M3, Interval::D1, CachePolicy::Default)?;
|
||||
let screen: Fetched<Vec<Quote>> = idx.market().screen(ScreenQuery { filter, region, limit })?;
|
||||
let quotes: Vec<Fetched<Quote>> = idx.market().quotes(&["BBCA", "BBRI"], policy)?;
|
||||
let source = idx.market().history_source(None); // which provider serves history
|
||||
let candles: Fetched<Vec<Ohlc>> =
|
||||
idx.market().history("BBCA", &Period::ThreeMonths, &Interval::Day, source, policy)?;
|
||||
let screen: Fetched<Vec<Quote>> = idx.market().screen(&ScreenQuery { filter, region, limit }, policy)?;
|
||||
|
||||
// financial
|
||||
let report: Fetched<FinancialStatements> = idx.financial().statements("BBCA", StatementFilter::all())?;
|
||||
let earnings: Fetched<EarningsReport> = idx.financial().earnings("BBCA", EarningsFilter::default())?;
|
||||
let report: Fetched<FinancialStatements> =
|
||||
idx.financial().statements("BBCA", &StatementFilter::all(), policy)?;
|
||||
let earnings: Fetched<EarningsReport> =
|
||||
idx.financial().earnings("BBCA", EarningsFilter::default(), policy)?;
|
||||
|
||||
// analysis (fetches its own inputs through the same cache)
|
||||
let tech: Fetched<TechnicalReport> = idx.analysis().technical("BBCA")?;
|
||||
let tech: Fetched<TechnicalReport> = idx.analysis().technical("BBCA", source, policy)?;
|
||||
let compared: Comparison = idx.analysis().compare(&["BBCA", "BBRI"], policy)?;
|
||||
|
||||
// investor (local DB)
|
||||
let holders: TickerOwnership = idx.investor().ticker("BBCA")?;
|
||||
|
|
@ -86,14 +90,18 @@ Key decisions:
|
|||
- **Blocking API.** `ureq` and `rusqlite` are blocking, and so is the CLI.
|
||||
Async frontends (MCP, HTTP) call core through `spawn_blocking`. Revisit only
|
||||
if an HTTP API needs high concurrency.
|
||||
- **`Fetched<T>` envelope** for live data: `{ data, source, fetched_at, stale }`.
|
||||
This replaces today's stderr-only stale-cache warning, which an agent or API
|
||||
client cannot see.
|
||||
- **`Fetched<T>` envelope** for live data: `{ data, source, fetched_at, stale }`,
|
||||
so agents and API clients can see freshness. idx-core still emits the
|
||||
stale-cache warnings through `runtime` (which `set_quiet` silences) so CLI
|
||||
stderr stays identical.
|
||||
- **`CachePolicy`**: `Default | Offline | Refresh` replaces the `--offline` /
|
||||
`--no-cache` flag handling now spread through `cli/stocks.rs`.
|
||||
- **Explicit configuration.** Core reads no environment variables. `IDX_*` env
|
||||
parsing, `config.toml` loading, and XDG resolution move to a `CoreConfig::load()`
|
||||
helper that frontends call; tests construct `CoreConfig` directly.
|
||||
- **Explicit configuration.** `CoreConfig::load()` is the one place idx-core reads
|
||||
provider, exchange, and TTL settings from `config.toml` and `IDX_*`; other
|
||||
frontends and tests construct `CoreConfig` directly (`cache_dir` overrides the
|
||||
XDG default). Remaining environment hooks: XDG paths for the config file and
|
||||
ownership DB, `IDX_CURL_IMPERSONATE_BIN`, the IDX discovery URL overrides, and
|
||||
the `testing`-only mock variables.
|
||||
- **Mock provider behind a `testing` feature.** Done: `MockProvider` and the
|
||||
embedded MSN fixtures compile only with idx-core's `testing` feature, which
|
||||
idx-cli enables as a dev-dependency.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue