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    /// When true, agent ticks do not print to stdout (watch TUI mode).
22    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    /// Human-mode guided prompts (account pickers, etc.).
52    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    /// Agent-mode runtime for order execution (used by `schwab-trader`).
71    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}