1use std::sync::Arc;
2
3use anyhow::{Context, Result};
4use schwab_api::{ClientConfig, SchwabClient, TraderApi};
5use schwab_market_data::MarketDataApi;
6
7use crate::cli::Cli;
8use crate::mode::CliMode;
9use crate::output::{OutputFormat, OutputSink};
10use crate::safety::SafetyContext;
11use crate::safety_config::SafetyConfig;
12
13#[derive(Debug, Clone)]
14pub struct RuntimeConfig {
15 pub mode: CliMode,
16 pub output: OutputFormat,
17 pub yes: bool,
18 pub dry_run: bool,
19 pub trust: bool,
21 pub safety: SafetyContext,
22 pub sink: OutputSink,
23}
24
25impl RuntimeConfig {
26 pub fn from_cli(cli: &Cli) -> Result<Self> {
27 let safety_cfg = SafetyConfig::load().context("Failed to load safety.json")?;
28 Ok(Self {
29 mode: cli.mode,
30 output: cli.effective_output(),
31 yes: cli.yes,
32 dry_run: cli.dry_run,
33 trust: cli.trust,
34 safety: SafetyContext::new(safety_cfg),
35 sink: OutputSink::stdout(),
36 })
37 }
38
39 pub fn emit(&self, envelope: crate::output::ResponseEnvelope) {
40 self.sink.write(&envelope, self.output);
41 }
42
43 pub fn is_tty(&self) -> bool {
44 use std::io::{stdin, stdout, IsTerminal};
45 stdin().is_terminal() && stdout().is_terminal()
46 }
47
48 pub fn is_interactive(&self) -> bool {
50 use std::io::stdout;
51 use std::io::IsTerminal;
52 self.mode.is_human() && stdout().is_terminal()
53 }
54
55 pub fn build_api(&self) -> Result<Arc<TraderApi>> {
56 let config = ClientConfig::from_env().context("Failed to load Schwab client config")?;
57 let client = SchwabClient::new(config);
58 Ok(Arc::new(TraderApi::new(client)))
59 }
60
61 pub fn build_market_api(&self) -> Result<Arc<MarketDataApi>> {
62 let config = ClientConfig::from_env().context("Failed to load Schwab client config")?;
63 let client = SchwabClient::new(config);
64 Ok(Arc::new(MarketDataApi::new(client)))
65 }
66}