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 suppress_tick_output: bool,
23 pub safety: SafetyContext,
24 pub sink: OutputSink,
25}
26
27impl RuntimeConfig {
28 pub fn from_cli(cli: &Cli) -> Result<Self> {
29 let safety_cfg = SafetyConfig::load().context("Failed to load safety.json")?;
30 Ok(Self {
31 mode: cli.mode,
32 output: cli.effective_output(),
33 yes: cli.yes,
34 dry_run: cli.dry_run,
35 trust: cli.trust,
36 suppress_tick_output: false,
37 safety: SafetyContext::new(safety_cfg),
38 sink: OutputSink::stdout(),
39 })
40 }
41
42 pub fn emit(&self, envelope: crate::output::ResponseEnvelope) {
43 self.sink.write(&envelope, self.output);
44 }
45
46 pub fn is_tty(&self) -> bool {
47 use std::io::{stdin, stdout, IsTerminal};
48 stdin().is_terminal() && stdout().is_terminal()
49 }
50
51 pub fn is_interactive(&self) -> bool {
53 use std::io::stdout;
54 use std::io::IsTerminal;
55 self.mode.is_human() && stdout().is_terminal()
56 }
57
58 pub fn build_api(&self) -> Result<Arc<TraderApi>> {
59 let config = ClientConfig::from_env().context("Failed to load Schwab client config")?;
60 let client = SchwabClient::new(config);
61 Ok(Arc::new(TraderApi::new(client)))
62 }
63
64 pub fn build_market_api(&self) -> Result<Arc<MarketDataApi>> {
65 let config = ClientConfig::from_env().context("Failed to load Schwab client config")?;
66 let client = SchwabClient::new(config);
67 Ok(Arc::new(MarketDataApi::new(client)))
68 }
69
70 pub fn for_agent_trading(
72 output: OutputFormat,
73 yes: bool,
74 dry_run: bool,
75 trust: bool,
76 suppress_tick_output: bool,
77 safety: SafetyContext,
78 sink: OutputSink,
79 ) -> Self {
80 Self {
81 mode: CliMode::Agent,
82 output,
83 yes,
84 dry_run,
85 trust,
86 suppress_tick_output,
87 safety,
88 sink,
89 }
90 }
91}