Skip to main content

schwab_cli/
config.rs

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    /// Explicit trusted agent mode — required with --yes for autonomous trading.
20    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    /// Human-mode guided prompts (account pickers, etc.).
49    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}