Skip to main content

eli_cli/
args.rs

1#[derive(Parser, Debug)]
2#[command(name = "market-search", version, about = "Market Search: MCP server for finance data + a terminal coding agent")]
3struct Cli {
4    #[command(subcommand)]
5    cmd: Option<Command>,
6
7    /// Provider: openrouter | openai | anthropic | ollama | mock
8    #[arg(long, global = true)]
9    provider: Option<String>,
10
11    /// Model name (provider-specific)
12    #[arg(long, global = true)]
13    model: Option<String>,
14}
15
16#[derive(Subcommand, Debug)]
17enum Command {
18    /// Interactive setup - configure provider, model, and API key
19    Setup,
20
21    /// Create a default config file (if missing)
22    Init,
23
24    /// Print or set config values
25    Config {
26        /// Set a config value: provider, model, mem_steps, key, sec_user_agent, compact, compact_trigger, compact_keep, summary_model, parallel_commands, parallel_subagents, scrollback_max_lines
27        #[arg(long)]
28        set: Option<String>,
29
30        /// Value to set
31        #[arg(long)]
32        value: Option<String>,
33    },
34
35    /// Emit JSON schema for a CLI subcommand (hidden)
36    #[command(hide = true)]
37    ToolInfo {
38        /// Subcommand path (e.g., finance timeseries)
39        #[arg(value_name = "PATH", num_args = 0..)]
40        path: Vec<String>,
41    },
42
43    /// Financial data tools (for raw time-series exploration)
44    Finance {
45        #[command(subcommand)]
46        cmd: FinanceCommand,
47    },
48
49    /// Web tools (crawl, search, read)
50    Web {
51        #[command(subcommand)]
52        cmd: WebCommand,
53    },
54
55    /// Start MCP (Model Context Protocol) server — exposes market-search tools as native Claude Code tools via JSON-RPC stdio.
56    Mcp(McpArgs),
57
58    /// Log research picks for a report to track performance over time.
59    Picks {
60        #[command(subcommand)]
61        cmd: PicksCommand,
62    },
63}
64
65#[derive(Subcommand, Debug)]
66enum PicksCommand {
67    /// Record ticker/market picks at current prices for a given report.
68    Log(PicksLogArgs),
69}
70
71#[derive(clap::Args, Debug)]
72struct PicksLogArgs {
73    /// Path to the HTML report file (supports ~/).
74    #[arg(long)]
75    report: String,
76
77    /// Equity ticker(s) to track at current price (comma-separated or repeatable).
78    #[arg(long, value_delimiter = ',')]
79    ticker: Vec<String>,
80
81    /// Prediction market slug(s) to track at current probability (comma-separated or repeatable).
82    #[arg(long, value_delimiter = ',')]
83    market: Vec<String>,
84}
85
86#[derive(clap::Args, Debug)]
87struct McpArgs {
88    #[command(subcommand)]
89    cmd: Option<McpSubcommand>,
90
91    /// Run as HTTP server instead of stdio (MCP Streamable HTTP transport).
92    #[arg(long, default_value_t = false)]
93    http: bool,
94
95    /// Port for HTTP mode.
96    #[arg(long, default_value = "8484")]
97    port: u16,
98}
99
100#[derive(Subcommand, Debug)]
101enum McpSubcommand {
102    /// Get a public HTTPS /mcp URL (boots local HTTP MCP + spawns a tunnel).
103    Share(ShareArgs),
104}
105
106#[derive(clap::Args, Debug)]
107struct ShareArgs {
108    /// Tunnel provider: tunnelmole | cloudflare | ngrok | self-host
109    #[arg(long, default_value = "tunnelmole")]
110    provider: String,
111
112    /// Local port the MCP HTTP server is bound to.
113    #[arg(long, default_value = "8484")]
114    port: u16,
115
116    /// For ngrok: reserved subdomain (e.g. mysub.ngrok-free.dev or just mysub).
117    #[arg(long)]
118    domain: Option<String>,
119
120    /// For ngrok: authtoken if not already configured globally.
121    #[arg(long)]
122    authtoken: Option<String>,
123}
124
125#[derive(clap::Args, Debug)]
126struct ServeArgs {
127    /// Port to listen on.
128    #[arg(long, default_value = "3333")]
129    port: u16,
130
131    /// Directory containing HTML and MD reports.
132    #[arg(long, default_value = "~/Downloads/eli-code/eli_research/reports/html")]
133    reports_dir: String,
134
135    /// Sentinel state directory for subscriptions, packets, and daemon status.
136    #[arg(long)]
137    sentinel_dir: Option<PathBuf>,
138
139    /// Open browser after starting.
140    #[arg(long, default_value_t = false)]
141    open: bool,
142}
143
144#[derive(Subcommand, Debug)]
145enum FinanceCommand {
146    /// Fetch OHLCV time-series for one or more tickers.
147    Timeseries(FinanceTimeseriesArgs),
148    /// Current snapshot of income/balance/cashflow + 32 trailing ratios + company profile (sector, industry, employees). Single ticker returns object; multi-ticker returns array.
149    Fundamentals(FinanceFundamentalsArgs),
150    /// Search for ticker symbols or macro series IDs.
151    Search(FinanceSearchArgs),
152    /// Fetch recent SEC filings (8-K, 10-K, 10-Q) for a ticker.
153    Filings(FinanceFilingsArgs),
154    /// Alias for filings.
155    Sec(FinanceFilingsArgs),
156    /// Fetch earnings and macro release schedules (no-auth public endpoints).
157    Schedule(FinanceScheduleArgs),
158    /// Aggregate implied Fed policy trajectory from local prediction-market cache.
159    RatePath(FinanceRatePathArgs),
160    /// Prediction market discovery + pricing (Kalshi default; falls back to Polymarket).
161    Odds(FinanceOddsArgs),
162    /// Listed options chains with IV/skew summaries (Yahoo Finance).
163    Options(FinanceOptionsArgs),
164    /// Deprecated alias for `finance odds sync` (canonical). Same flags, same backend; kept for cron compatibility.
165    Sync(FinanceSyncArgs),
166    /// Local paper trading sandbox using live Kalshi/Polymarket prices.
167    Paper(FinancePaperArgs),
168    /// Interactive Brokers via local TWS / IB Gateway.
169    Ibkr(FinanceIbkrArgs),
170    /// Recent US Treasury auction results (bid-to-cover, tails, bidder breakdown).
171    Auctions(FinanceAuctionsArgs),
172    /// CFTC Commitment of Traders positioning (spec vs commercial, weekly).
173    Cot(FinanceCotArgs),
174    /// Futures term structure (forward curve) for commodities.
175    Curve(FinanceCurveArgs),
176    /// NY Fed Markets: overnight rates (SOFR/EFFR), reverse repo, SOMA holdings, dealer positions.
177    Nyfed(FinanceNyfedArgs),
178    /// CBOE volatility indices / term structure: VIX, VVIX, OVX, GVZ, SKEW.
179    #[command(name = "volatility", visible_alias = "volsurface")]
180    Volsurface(FinanceVolsurfaceArgs),
181    /// OFR Financial Stress Index: composite + credit/equity/funding/vol decomposition.
182    Stress(FinanceStressArgs),
183    /// Treasury fiscal data: national debt, daily statement, average interest rates.
184    Fiscal(FinanceFiscalArgs),
185    /// ECB Statistical Data Warehouse: EUR/USD, Euro STR, M3, EURIBOR, yield curve, balance sheet.
186    Ecb(FinanceEcbArgs),
187    /// EIA: US petroleum inventories (crude, gasoline, distillate), natural gas storage.
188    Eia(FinanceEiaArgs),
189    /// BIS: global central bank policy rates, total assets, credit-to-GDP gaps, property prices.
190    Bis(FinanceBisArgs),
191    /// BOJ: Bank of Japan monetary base, balance sheet, TANKAN, call rate, money stock.
192    Boj(FinanceBojArgs),
193    /// BOE: Bank of England Bank Rate, SONIA, gilt yields, M4, GBP FX rates.
194    Boe(FinanceBoeArgs),
195}
196
197#[derive(Subcommand, Debug)]
198enum WebCommand {
199    /// Crawl a website and extract content from all discovered pages.
200    Crawl(WebCrawlArgs),
201    /// Ingestion-focused web search for URL candidates + diagnostics.
202    Search(WebSearchArgs),
203    /// Read and extract content from one or many URLs.
204    Read(WebReadArgs),
205    /// Extract key facts from content (URL, file, or text).
206    Extract(WebExtractArgs),
207}
208
209#[derive(Subcommand, Debug)]
210enum AgentCommand {
211    /// Generate a market intelligence report (JSON + HTML) using Eli tools and optional model synthesis.
212    Report(AgentReportArgs),
213    /// Run a single Eli worker from a natural-language task.
214    Run(AgentRunArgs),
215    /// Run many Eli workers in parallel from a task template and vars file.
216    Fanout(AgentFanoutArgs),
217    /// Chunk a large input and orchestrate map/reduce/critic swarm synthesis.
218    Swarm(AgentSwarmArgs),
219    /// Critique a lead thesis/report using worker fanout.
220    Critique(AgentModeArgs),
221    /// Find additional evidence for/against a thesis via worker fanout.
222    Evidence(AgentModeArgs),
223    /// Run competitive workers to find the best answer.
224    Compete(AgentModeArgs),
225    /// Run worker debate and synthesize consensus.
226    Debate(AgentModeArgs),
227}
228
229#[derive(Subcommand, Debug)]
230enum SentinelCommand {
231    /// Start the sentinel daemon in the background.
232    Start(SentinelStartArgs),
233    /// Stop the sentinel daemon.
234    Stop(SentinelStopArgs),
235    /// Print sentinel daemon status.
236    Status(SentinelStatusArgs),
237    /// Register a new sentinel trigger subscription.
238    Subscribe(SentinelSubscribeArgs),
239    /// Remove a sentinel subscription by id or name.
240    Unsubscribe(SentinelUnsubscribeArgs),
241    /// List configured sentinel subscriptions.
242    List(SentinelListArgs),
243    /// Emit a synthetic alert packet for wiring tests.
244    Test(SentinelTestArgs),
245    /// Replay recent packets from queue file.
246    Replay(SentinelReplayArgs),
247    /// Internal daemon process entrypoint.
248    #[command(hide = true)]
249    DaemonRun(SentinelDaemonRunArgs),
250}
251
252#[derive(Debug, Serialize)]
253struct RustFileSummary {
254    items_total: usize,
255    functions: usize,
256    function_names: Vec<String>,
257    /// Full signatures: "pub async fn name(param: Type) -> ReturnType"
258    /// Lets an AI caller understand the API contract without reading source.
259    function_signatures: Vec<String>,
260    structs: usize,
261    struct_names: Vec<String>,
262    /// Per-struct field list: {struct_name: ["field: Type", ...]}
263    struct_fields: std::collections::BTreeMap<String, Vec<String>>,
264    enums: usize,
265    enum_names: Vec<String>,
266    impls: usize,
267    impl_targets: Vec<String>,
268    /// Methods per impl block: {"LlmAdapter for AnthropicAdapter": ["pub async fn chat(...)  -> ..."]}
269    impl_methods: std::collections::BTreeMap<String, Vec<String>>,
270    traits: usize,
271    trait_names: Vec<String>,
272    modules: usize,
273    module_names: Vec<String>,
274    uses: usize,
275    use_paths: Vec<String>,
276    consts: usize,
277    const_names: Vec<String>,
278    statics: usize,
279    type_aliases: usize,
280    type_alias_names: Vec<String>,
281    macros: usize,
282    others: usize,
283}
284
285#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
286enum CrawlViewMode {
287    Summary,
288    Raw,
289    Path,
290}
291
292#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
293enum CrawlSaveMode {
294    Auto,
295    Off,
296}
297
298#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
299enum WebSearchModeArg {
300    Auto,
301    News,
302    Finance,
303    Research,
304    Tech,
305    Encyclopedia,
306}
307
308#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
309enum WebSearchRecencyArg {
310    Day,
311    Week,
312    Month,
313    Year,
314}
315
316#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
317enum FinancePaperCommandArg {
318    Trade,
319    Positions,
320    Trades,
321    Mark,
322    Reset,
323}
324
325#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
326enum FinancePaperModeArg {
327    Simulated,
328    #[value(alias = "live_like")]
329    LiveLike,
330    #[value(alias = "kalshi_demo")]
331    KalshiDemo,
332    #[value(alias = "polymarket_demo")]
333    PolymarketDemo,
334}
335
336#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
337enum FinancePaperSideArg {
338    Yes,
339    No,
340}
341
342#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
343enum FinancePaperOrderActionArg {
344    Buy,
345    Sell,
346}
347
348#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
349enum FinanceIbkrCommandArg {
350    Snapshot,
351    Timeseries,
352    AccountSummary,
353    Positions,
354    Portfolio,
355    OpenOrders,
356    PlaceOrder,
357    CancelOrder,
358}
359
360#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
361enum SentinelSeverityArg {
362    Low,
363    Medium,
364    High,
365    Critical,
366}
367
368#[derive(Copy, Clone, Debug, ValueEnum, Eq, PartialEq)]
369enum SentinelSpawnTargetArg {
370    Default,
371    Codex,
372    Claude,
373    Gemini,
374    Both,
375}
376
377#[derive(clap::Args, Debug)]
378struct SentinelPathArgs {
379    /// Sentinel root directory.
380    #[arg(long = "sentinel-dir")]
381    sentinel_dir: Option<PathBuf>,
382
383    /// Queue JSONL file override.
384    #[arg(long = "queue-file")]
385    queue_file: Option<PathBuf>,
386
387    /// Intelligence packets JSONL file override.
388    #[arg(long = "packets-file")]
389    packets_file: Option<PathBuf>,
390}
391
392#[derive(clap::Args, Debug)]
393struct SentinelStartArgs {
394    #[command(flatten)]
395    paths: SentinelPathArgs,
396
397    /// Daemon evaluation interval in seconds.
398    #[arg(long = "interval-secs", default_value_t = 15)]
399    interval_secs: u64,
400}
401
402#[derive(clap::Args, Debug)]
403struct SentinelStopArgs {
404    #[command(flatten)]
405    paths: SentinelPathArgs,
406}
407
408#[derive(clap::Args, Debug)]
409struct SentinelStatusArgs {
410    #[command(flatten)]
411    paths: SentinelPathArgs,
412}
413
414#[derive(clap::Args, Debug)]
415struct SentinelSubscribeArgs {
416    #[command(flatten)]
417    paths: SentinelPathArgs,
418
419    /// Human-readable subscription name (internal slug).
420    #[arg(long)]
421    name: String,
422
423    /// Human-readable prediction statement shown in the UI.
424    /// Example: "Gold will reach 5200 before Friday close"
425    #[arg(long)]
426    title: Option<String>,
427
428    /// Title of the report that authored this prediction.
429    #[arg(long = "source-report")]
430    source_report_title: Option<String>,
431
432    /// Date of the source report (ISO format, e.g. 2026-03-06).
433    #[arg(long = "source-date")]
434    source_report_date: Option<String>,
435
436    /// Filename of the source report (relative to reports_dir) for opening in the UI.
437    #[arg(long = "source-file")]
438    source_report_file: Option<String>,
439
440    /// Key evidence snippet or quote from the source report justifying this prediction.
441    #[arg(long = "source-evidence")]
442    source_evidence: Option<String>,
443
444    /// Trigger expression, e.g. \"pyth_wti > 80 && poly_hormuz_yes > 0.50\".
445    /// Optional when --fire-at is set (defaults to "true" for pure checkpoint daemons).
446    #[arg(long)]
447    expr: Option<String>,
448
449    /// Optional variable mapping (repeatable): var=provider:query
450    #[arg(long = "var")]
451    vars: Vec<String>,
452
453    /// Why this alert matters (stored in packet/playbook).
454    #[arg(long = "why")]
455    why: Option<String>,
456
457    /// Prompt template for the follow-up playbook.
458    #[arg(long = "prompt-template")]
459    prompt_template: Option<String>,
460
461    /// Alert severity.
462    #[arg(long, value_enum, default_value = "medium")]
463    severity: SentinelSeverityArg,
464
465    /// Cooldown between repeated triggers (seconds).
466    #[arg(long = "cooldown-secs", default_value_t = 300)]
467    cooldown_secs: u64,
468
469    /// Start enabled (default true).
470    #[arg(long, default_value_t = true)]
471    enabled: bool,
472
473    /// Spawn headless AI agent (claude/codex) when this subscription triggers.
474    #[arg(long = "spawn-agent", default_value_t = false)]
475    spawn_agent: bool,
476
477    /// Which headless writer(s) should fire when this subscription triggers.
478    #[arg(long = "spawn-target", value_enum, default_value = "default")]
479    spawn_target: SentinelSpawnTargetArg,
480
481    /// Legacy spawn cooldown field retained for compatibility with existing subscriptions.
482    /// Spawn routing now uses rolling per-hour budgets instead.
483    #[arg(long = "spawn-cooldown-secs", default_value_t = 14400, hide = true)]
484    spawn_cooldown_secs: u64,
485
486    /// Human-readable prediction thesis this daemon encodes.
487    /// When set, fires on HIT (condition met) OR MISS (deadline elapsed without condition met).
488    #[arg(long = "prediction")]
489    prediction: Option<String>,
490
491    /// Which variable name in --expr to track as the prediction target (e.g., "pyth_wti").
492    #[arg(long = "target-var")]
493    target_var: Option<String>,
494
495    /// Predicted numeric target for target-var (e.g., 90.0).
496    #[arg(long = "target-value")]
497    target_value: Option<f64>,
498
499    /// Prediction deadline in RFC3339 format (e.g., 2026-04-01T00:00:00Z).
500    /// Fires MISS if condition not met by this time.
501    #[arg(long = "deadline")]
502    deadline: Option<String>,
503
504    /// Scheduled fire time in RFC3339 format (e.g., 2026-03-12T16:03:00Z).
505    /// Daemon fires ONCE at this exact time. Expr is evaluated at that moment for HIT/MISS.
506    /// Omit --expr for a pure checkpoint (always fires, no condition).
507    #[arg(long = "fire-at")]
508    fire_at: Option<String>,
509}
510
511#[derive(clap::Args, Debug)]
512struct SentinelUnsubscribeArgs {
513    #[command(flatten)]
514    paths: SentinelPathArgs,
515
516    /// Subscription id or exact name.
517    #[arg(long = "id")]
518    id_or_name: String,
519}
520
521#[derive(clap::Args, Debug)]
522struct SentinelListArgs {
523    #[command(flatten)]
524    paths: SentinelPathArgs,
525}
526
527#[derive(clap::Args, Debug)]
528struct SentinelTestArgs {
529    #[command(flatten)]
530    paths: SentinelPathArgs,
531
532    /// Synthetic test scenario.
533    #[arg(long, default_value = "generic")]
534    scenario: String,
535}
536
537#[derive(clap::Args, Debug)]
538struct SentinelReplayArgs {
539    #[command(flatten)]
540    paths: SentinelPathArgs,
541
542    /// Number of recent queue lines to replay.
543    #[arg(long = "max-lines", default_value_t = 50)]
544    max_lines: usize,
545}
546
547#[derive(clap::Args, Debug)]
548struct SentinelDaemonRunArgs {
549    #[command(flatten)]
550    paths: SentinelPathArgs,
551
552    /// Daemon evaluation interval in seconds.
553    #[arg(long = "interval-secs", default_value_t = 15)]
554    interval_secs: u64,
555}
556
557#[derive(clap::Args, Debug)]
558struct AgentReportArgs {
559    /// Report objective/prompt. Defaults to Eli three-pillar research framework.
560    #[arg(long)]
561    prompt: Option<String>,
562
563    /// Comma-separated market tickers for snapshot/timeseries.
564    #[arg(
565        long,
566        value_delimiter = ',',
567        default_value = "SPY,QQQ,IWM,DIA,^VIX,BTC-USD,ETH-USD,SOL-USD,DX-Y.NYB,GC=F,CL=F"
568    )]
569    tickers: Vec<String>,
570
571    /// Historical lookback span for timeseries (e.g. 14d, 30d, 3mo).
572    #[arg(long, default_value = "14d")]
573    lookback: String,
574
575    /// Timeseries granularity (e.g. 15min, 1h, 1d).
576    #[arg(long, default_value = "1h")]
577    granularity: String,
578
579    /// Lock clock-sensitive tools to N minutes before report start.
580    #[arg(long = "lock-minutes", conflicts_with = "as_of")]
581    lock_minutes: Option<u64>,
582
583    /// Explicit report anchor time (RFC3339 or YYYY-MM-DD).
584    #[arg(long = "as-of", conflicts_with = "lock_minutes")]
585    as_of: Option<String>,
586
587    /// Comma-separated odds search queries.
588    #[arg(
589        long,
590        value_delimiter = ',',
591        default_value = "recession,fed,inflation,iran,oil,china,taiwan"
592    )]
593    odds_queries: Vec<String>,
594
595    /// Number of top markets per odds query.
596    #[arg(long, default_value_t = 8)]
597    top: usize,
598
599    /// Comma-separated web queries for narrative context.
600    #[arg(
601        long,
602        value_delimiter = ',',
603        default_value = "stock market today,treasury yields today,fed policy outlook,oil geopolitical risk"
604    )]
605    web_queries: Vec<String>,
606
607    /// Max runtime budget per command invocation (milliseconds).
608    #[arg(long = "max-ms", default_value_t = 45000)]
609    max_ms: u64,
610
611    /// Comma-separated fallback models for synthesis worker.
612    #[arg(long = "fallback-models", value_delimiter = ',')]
613    fallback_models: Vec<String>,
614
615    /// Optional explicit HTML output path.
616    #[arg(long = "html-out")]
617    html_out: Option<PathBuf>,
618
619    /// Output JSON path for the report envelope.
620    #[arg(long)]
621    out: Option<PathBuf>,
622}
623
624#[derive(clap::Args, Debug)]
625struct AgentRunArgs {
626    /// Natural-language task for the worker.
627    #[arg(long)]
628    task: String,
629
630    /// Output file path (JSON).
631    #[arg(long)]
632    out: Option<PathBuf>,
633
634    /// Comma-separated fallback models (used on worker failure).
635    #[arg(long = "fallback-models", value_delimiter = ',')]
636    fallback_models: Vec<String>,
637
638    /// Max runtime budget per worker (milliseconds).
639    #[arg(long = "max-ms", default_value_t = 45000)]
640    max_ms: u64,
641
642    /// Max total attempts per worker across primary + fallbacks.
643    #[arg(long = "max-attempts", default_value_t = 4)]
644    max_attempts: usize,
645
646    /// Require the final report to cite these path prefixes (comma-separated).
647    #[arg(long = "must-cite", value_delimiter = ',')]
648    must_cite: Vec<String>,
649}
650
651#[derive(clap::Args, Debug)]
652struct AgentFanoutArgs {
653    /// Task template. Use placeholders like {{ticker}} or {{stance}}.
654    #[arg(long = "task-template")]
655    task_template: String,
656
657    /// JSON file containing an array of objects for template vars.
658    #[arg(long)]
659    vars: PathBuf,
660
661    /// Optional shared artifact manifest path all workers should read first.
662    #[arg(long = "shared-manifest")]
663    shared_manifest: Option<PathBuf>,
664
665    /// Max workers to run at once.
666    #[arg(long, default_value = "4")]
667    max_parallel: usize,
668
669    /// Output file path (JSON).
670    #[arg(long)]
671    out: Option<PathBuf>,
672
673    /// Comma-separated fallback models (used on worker failure).
674    #[arg(long = "fallback-models", value_delimiter = ',')]
675    fallback_models: Vec<String>,
676
677    /// Max runtime budget per worker (milliseconds).
678    #[arg(long = "max-ms", default_value_t = 45000)]
679    max_ms: u64,
680
681    /// Max total attempts per worker across primary + fallbacks.
682    #[arg(long = "max-attempts", default_value_t = 4)]
683    max_attempts: usize,
684
685    /// Require each successful worker report to cite these path prefixes (comma-separated).
686    #[arg(long = "must-cite", value_delimiter = ',')]
687    must_cite: Vec<String>,
688}
689
690#[derive(clap::Args, Debug)]
691struct AgentSwarmArgs {
692    /// High-level goal for the swarm.
693    #[arg(long)]
694    task: String,
695
696    /// Input file to process (txt/md/json/csv/ndjson/pdf).
697    #[arg(long)]
698    input: PathBuf,
699
700    /// Optional explicit number of chunk workers (X swarms).
701    #[arg(long)]
702    chunks: Option<usize>,
703
704    /// Approximate characters per chunk when --chunks is not provided.
705    #[arg(long = "chunk-chars", default_value_t = 20_000)]
706    chunk_chars: usize,
707
708    /// Character overlap between chunks to reduce boundary loss.
709    #[arg(long = "overlap-chars", default_value_t = 500)]
710    overlap_chars: usize,
711
712    /// Hard cap on produced chunks.
713    #[arg(long = "max-chunks", default_value_t = 64)]
714    max_chunks: usize,
715
716    /// Max workers to run at once for map stage.
717    #[arg(long, default_value = "4")]
718    max_parallel: usize,
719
720    /// Output file path (JSON).
721    #[arg(long)]
722    out: Option<PathBuf>,
723
724    /// Comma-separated fallback models (used on worker failure).
725    #[arg(long = "fallback-models", value_delimiter = ',')]
726    fallback_models: Vec<String>,
727
728    /// Max runtime budget per worker (milliseconds).
729    #[arg(long = "max-ms", default_value_t = 120_000)]
730    max_ms: u64,
731
732    /// Max total attempts per worker across primary + fallbacks.
733    #[arg(long = "max-attempts", default_value_t = 4)]
734    max_attempts: usize,
735
736    /// Require successful stage reports to cite these path prefixes (comma-separated).
737    #[arg(long = "must-cite", value_delimiter = ',')]
738    must_cite: Vec<String>,
739}
740
741#[derive(clap::Args, Debug)]
742struct AgentModeArgs {
743    /// User objective for this report mode.
744    #[arg(long)]
745    prompt: String,
746
747    /// Optional lead report or thesis file path.
748    #[arg(long)]
749    lead: Option<PathBuf>,
750
751    /// JSON file containing an array of worker objects (name/model/role/etc).
752    #[arg(long)]
753    vars: PathBuf,
754
755    /// Optional shared artifact manifest path all workers should read first.
756    #[arg(long = "shared-manifest")]
757    shared_manifest: Option<PathBuf>,
758
759    /// Allow workers to reference peer output in compete/debate modes.
760    #[arg(long, default_value_t = false)]
761    allow_cheat: bool,
762
763    /// Max workers to run at once.
764    #[arg(long, default_value = "4")]
765    max_parallel: usize,
766
767    /// Output file path (JSON).
768    #[arg(long)]
769    out: Option<PathBuf>,
770
771    /// Comma-separated fallback models (used on worker failure).
772    #[arg(long = "fallback-models", value_delimiter = ',')]
773    fallback_models: Vec<String>,
774
775    /// Max runtime budget per worker (milliseconds).
776    #[arg(long = "max-ms", default_value_t = 120_000)]
777    max_ms: u64,
778
779    /// Max total attempts per worker across primary + fallbacks.
780    #[arg(long = "max-attempts", default_value_t = 2)]
781    max_attempts: usize,
782
783    /// Require each successful worker report to cite these path prefixes (comma-separated).
784    #[arg(long = "must-cite", value_delimiter = ',')]
785    must_cite: Vec<String>,
786}
787
788#[derive(clap::Args, Debug)]
789struct CodeArgs {
790    /// Path to Rust source file or directory to analyze.
791    path: PathBuf,
792
793    /// Also generate code (e.g., getter methods for structs).
794    #[arg(long, default_value_t = false)]
795    generate: bool,
796
797    /// Minimum line count filter (directory mode only).
798    #[arg(long, default_value_t = 0)]
799    min_loc: usize,
800
801    /// Maximum number of files to analyze after sorting by path (directory mode only).
802    #[arg(long)]
803    max_files: Option<usize>,
804
805    /// Parallel worker count for Rust parsing (directory mode only).
806    #[arg(long)]
807    workers: Option<usize>,
808
809    /// Number of rows to include for each hotspot ranking (directory mode only).
810    #[arg(long, default_value_t = 20)]
811    top: usize,
812
813    /// Include per-file metrics in response (directory mode only).
814    #[arg(long, default_value_t = false)]
815    include_files: bool,
816
817    /// Search for symbol usages across all .rs files in path (comma-separated).
818    /// Uses multi-pattern matching. Returns every line containing any of the symbols
819    /// with file path and line number. Works on files and directories.
820    #[arg(long, value_delimiter = ',')]
821    find: Vec<String>,
822
823    /// Emit the complete public API surface for a directory: every pub fn (with full
824    /// signature), pub struct (with field types), pub enum (with variants), pub trait
825    /// (with method signatures), grouped by file. Ideal for understanding a module's
826    /// contract before writing new code.
827    #[arg(long, default_value_t = false)]
828    pub_api: bool,
829
830    /// Optional output file for JSON response.
831    #[arg(long)]
832    out: Option<PathBuf>,
833}
834
835#[derive(clap::Args, Debug)]
836struct WebCrawlArgs {
837    /// URL to start crawling from.
838    #[arg(long)]
839    url: String,
840
841    /// Maximum number of pages to crawl (default: 50).
842    #[arg(long, default_value = "50")]
843    max_pages: usize,
844
845    /// Respect robots.txt (default: true).
846    #[arg(long, default_value = "true")]
847    respect_robots: bool,
848
849    /// Include subdomains in crawl (default: false).
850    #[arg(long, default_value = "false")]
851    subdomains: bool,
852
853    /// Crawl via sitemap discovery mode.
854    #[arg(long, default_value = "false")]
855    sitemap: bool,
856
857    /// Smart crawl mode: HTTP first, render JS only when needed.
858    #[arg(long, default_value = "false", conflicts_with = "sitemap")]
859    smart: bool,
860
861    /// Terminal output view.
862    #[arg(long, value_enum, default_value_t = CrawlViewMode::Summary)]
863    view: CrawlViewMode,
864
865    /// Save policy when --out is not provided.
866    #[arg(long, value_enum, default_value_t = CrawlSaveMode::Auto)]
867    save: CrawlSaveMode,
868
869    /// Output file path (JSON).
870    #[arg(long)]
871    out: Option<PathBuf>,
872}
873
874#[derive(clap::Args, Debug)]
875struct WebSearchArgs {
876    /// Search query.
877    #[arg(long)]
878    query: String,
879
880    /// Search mode tuned for different ingestion workflows.
881    #[arg(long, value_enum, default_value_t = WebSearchModeArg::Auto)]
882    mode: WebSearchModeArg,
883
884    /// Include only these domains (comma-separated).
885    #[arg(long, value_delimiter = ',')]
886    domains: Vec<String>,
887
888    /// Exclude these domains (comma-separated).
889    #[arg(long = "exclude-domains", value_delimiter = ',')]
890    exclude_domains: Vec<String>,
891
892    /// Recency hint (day, week, month, year).
893    #[arg(long, value_enum)]
894    recency: Option<WebSearchRecencyArg>,
895
896    /// Earliest publication date (YYYY-MM-DD).
897    #[arg(long)]
898    since: Option<String>,
899
900    /// Latest publication date (YYYY-MM-DD).
901    #[arg(long)]
902    until: Option<String>,
903
904    /// Maximum items to return.
905    #[arg(long, default_value_t = 15)]
906    top: usize,
907
908    /// Number of top results to probe with web read diagnostics.
909    #[arg(long = "probe-top", default_value_t = 4)]
910    probe_top: usize,
911
912    /// Maximum parallel network operations.
913    #[arg(long = "max-parallel", default_value_t = 6)]
914    max_parallel: usize,
915
916    /// Optional run-tracking key for delta comparisons.
917    #[arg(long = "track-key")]
918    track_key: Option<String>,
919
920    /// Emit full verbose payload (snippets + detailed score components).
921    #[arg(long, default_value_t = false)]
922    full: bool,
923
924    /// Output file path (JSON).
925    #[arg(long)]
926    out: Option<PathBuf>,
927}
928
929#[derive(clap::Args, Debug)]
930struct WebReadArgs {
931    /// URL(s) to read content from (repeatable or comma-separated).
932    #[arg(long = "url", value_delimiter = ',')]
933    url: Vec<String>,
934
935    /// Optional file containing URLs (one per line, '#' comments allowed).
936    #[arg(long = "urls-file")]
937    urls_file: Option<PathBuf>,
938
939    /// Maximum parallel URL fetches.
940    #[arg(long = "max-parallel", default_value_t = 6)]
941    max_parallel: usize,
942
943    /// Max chars to keep per article text in default compact mode.
944    #[arg(long = "max-chars", default_value_t = 2400)]
945    max_chars: usize,
946
947    /// Emit full verbose payload (full text + attempt details).
948    #[arg(long, default_value_t = false)]
949    full: bool,
950
951    /// Output file path (JSON).
952    #[arg(long)]
953    out: Option<PathBuf>,
954}
955
956#[derive(clap::Args, Debug)]
957struct WebExtractArgs {
958    /// URL to fetch and extract from.
959    #[arg(long)]
960    url: Option<String>,
961
962    /// File path to extract from.
963    #[arg(long)]
964    file: Option<PathBuf>,
965
966    /// Inline text to extract from (use heredoc for large content).
967    #[arg(long)]
968    text: Option<String>,
969
970    /// Number of bullet points to extract (default: 10).
971    #[arg(long, default_value = "10")]
972    bullets: usize,
973
974    /// Focus extraction on specific topic.
975    #[arg(long)]
976    focus: Option<String>,
977
978    /// Output file path (JSON).
979    #[arg(long)]
980    out: Option<PathBuf>,
981}
982
983#[derive(clap::Args, Debug)]
984pub struct FinanceScheduleArgs {
985    /// Schedule kind: earnings | macro | all.
986    #[arg(long, default_value = "all")]
987    pub kind: String,
988    /// Single date (YYYY-MM-DD). If set, overrides --from/--to.
989    #[arg(long)]
990    pub date: Option<String>,
991    /// Start date (YYYY-MM-DD).
992    #[arg(long = "from")]
993    pub from: Option<String>,
994    /// End date (YYYY-MM-DD).
995    #[arg(long = "to")]
996    pub to: Option<String>,
997    /// Optional ticker filter for earnings rows (repeatable or comma-separated).
998    #[arg(long, visible_alias = "tickers", value_delimiter = ',')]
999    pub ticker: Vec<String>,
1000    /// Macro-only: keep only major US releases (CPI, PCE, GDP, jobs, FOMC, claims).
1001    #[arg(long, default_value_t = false)]
1002    pub major: bool,
1003    /// Minimum market cap for earnings (e.g. 10B, 500M, 1T).
1004    #[arg(long = "min-cap")]
1005    pub min_cap: Option<String>,
1006    /// Filter earnings by report time: pre-market | after-hours.
1007    #[arg(long)]
1008    pub time: Option<String>,
1009    /// Macro filtering profile: broad | market | major.
1010    #[arg(long = "macro-profile", default_value = "market")]
1011    pub macro_profile: String,
1012    /// Output format (json only).
1013    #[arg(long, default_value = "json")]
1014    pub format: String,
1015    /// Write full JSON output to a file instead of stdout.
1016    #[arg(long)]
1017    pub out: Option<PathBuf>,
1018}
1019
1020#[derive(clap::Args, Debug)]
1021pub struct FinanceRatePathArgs {
1022    /// Optional cache directory for prediction-market CSVs.
1023    #[arg(long)]
1024    pub cache_dir: Option<PathBuf>,
1025    /// DEPRECATED: accepted for backwards compatibility but ignored. The live
1026    /// API path always dominates; the CSV cache is only used when the live
1027    /// fetch fails. The auto/meeting/fallback distinction was a no-op.
1028    #[arg(long, default_value = "auto", hide = true)]
1029    pub source_mode: String,
1030    /// Output format (json only).
1031    #[arg(long, default_value = "json")]
1032    pub format: String,
1033    /// Output file path.
1034    #[arg(long)]
1035    pub out: Option<PathBuf>,
1036}
1037
1038#[derive(clap::Args, Debug)]
1039pub struct FinanceAuctionsArgs {
1040    /// Filter by security type: bill, note, bond, tips, frn, or all.
1041    #[arg(long, default_value = "all")]
1042    pub security_type: String,
1043    /// Number of recent auctions to return.
1044    #[arg(long, default_value_t = 50)]
1045    pub limit: usize,
1046    /// Output format (json only).
1047    #[arg(long, default_value = "json")]
1048    pub format: String,
1049    /// Output file path.
1050    #[arg(long)]
1051    pub out: Option<PathBuf>,
1052}
1053
1054#[derive(clap::Args, Debug)]
1055pub struct FinanceCotArgs {
1056    /// Search query to filter by contract name (e.g. "gold", "crude oil", "10y note").
1057    #[arg(long)]
1058    pub query: Option<String>,
1059    /// Number of weeks of data to fetch. Default 12.
1060    #[arg(long, default_value_t = 12)]
1061    pub weeks: usize,
1062    /// Report type: auto (detect from query), disaggregated (commodities), or financial (rates/FX/equity).
1063    #[arg(long, default_value = "auto")]
1064    pub report: String,
1065    /// Max number of distinct contracts to return (default 15).
1066    #[arg(long)]
1067    pub limit: Option<usize>,
1068    /// Output format (json only).
1069    #[arg(long, default_value = "json")]
1070    pub format: String,
1071    /// Output file path.
1072    #[arg(long)]
1073    pub out: Option<PathBuf>,
1074}
1075
1076#[derive(clap::Args, Debug)]
1077pub struct FinanceCurveArgs {
1078    /// Commodity to chart (e.g. oil, gold, natgas, silver, copper). Use --list to see all.
1079    #[arg(long)]
1080    pub commodity: Option<String>,
1081    /// Number of forward months to include (default 12, max 24).
1082    #[arg(long, default_value_t = 12)]
1083    pub months: usize,
1084    /// List supported commodities.
1085    #[arg(long, default_value_t = false)]
1086    pub list: bool,
1087    /// Output file path.
1088    #[arg(long)]
1089    pub out: Option<PathBuf>,
1090}
1091
1092#[derive(clap::Args, Debug)]
1093pub struct FinanceNyfedArgs {
1094    /// Endpoint: rates | rrp | soma | dealers
1095    #[arg(long, default_value = "rates")]
1096    pub kind: String,
1097    #[arg(long, default_value = "json")]
1098    pub format: String,
1099    #[arg(long)]
1100    pub out: Option<PathBuf>,
1101}
1102
1103#[derive(clap::Args, Debug)]
1104pub struct FinanceVolsurfaceArgs {
1105    /// Comma-separated CBOE index symbols (default: all 9). Options: VIX,VIX9D,VIX3M,VIX6M,VIX1Y,VVIX,OVX,GVZ,SKEW
1106    #[arg(long)]
1107    pub symbols: Option<String>,
1108    /// Number of historical trading days (default: latest only)
1109    #[arg(long)]
1110    pub history: Option<usize>,
1111    #[arg(long, default_value = "json")]
1112    pub format: String,
1113    #[arg(long)]
1114    pub out: Option<PathBuf>,
1115}
1116
1117#[derive(clap::Args, Debug)]
1118pub struct FinanceStressArgs {
1119    /// Days of history (default: 30)
1120    #[arg(long, default_value_t = 30)]
1121    pub range: usize,
1122    #[arg(long, default_value = "json")]
1123    pub format: String,
1124    #[arg(long)]
1125    pub out: Option<PathBuf>,
1126}
1127
1128#[derive(clap::Args, Debug)]
1129pub struct FinanceFiscalArgs {
1130    /// Endpoint: debt | statement | interest
1131    #[arg(long, default_value = "debt")]
1132    pub kind: String,
1133    #[arg(long, default_value = "json")]
1134    pub format: String,
1135    #[arg(long)]
1136    pub out: Option<PathBuf>,
1137}
1138
1139#[derive(clap::Args, Debug)]
1140pub struct FinanceEcbArgs {
1141    /// Preset: eurusd | fx_majors | estr | m3 | euribor | yield_curve | balance_sheet
1142    #[arg(long)]
1143    pub preset: Option<String>,
1144    /// SDMX dataset (e.g. EXR, BSI, FM, EST, YC). Use with --key.
1145    #[arg(long)]
1146    pub dataset: Option<String>,
1147    /// SDMX dimension key (e.g. D.USD.EUR.SP00.A). Use with --dataset.
1148    #[arg(long)]
1149    pub key: Option<String>,
1150    /// Start period (YYYY-MM-DD or YYYY-MM or YYYY).
1151    #[arg(long, default_value = "2025-01-01")]
1152    pub start: String,
1153    /// End period.
1154    #[arg(long)]
1155    pub end: Option<String>,
1156    #[arg(long, default_value = "json")]
1157    pub format: String,
1158    #[arg(long)]
1159    pub out: Option<PathBuf>,
1160}
1161
1162#[derive(clap::Args, Debug)]
1163pub struct FinanceEiaArgs {
1164    /// Preset: crude | gasoline | distillate | all | nat_gas
1165    #[arg(long)]
1166    pub preset: Option<String>,
1167    /// Custom API route (e.g. petroleum/stoc/wstk/data/).
1168    #[arg(long)]
1169    pub route: Option<String>,
1170    /// Start date (YYYY-MM-DD).
1171    #[arg(long)]
1172    pub start: Option<String>,
1173    /// Max observations to return (default 52 = ~1 year weekly).
1174    #[arg(long, default_value = "52")]
1175    pub length: usize,
1176    #[arg(long, default_value = "json")]
1177    pub format: String,
1178    #[arg(long)]
1179    pub out: Option<PathBuf>,
1180}
1181
1182#[derive(clap::Args, Debug)]
1183pub struct FinanceBisArgs {
1184    /// Preset: policy_rates | assets | credit_gap | property | eer
1185    #[arg(long)]
1186    pub preset: Option<String>,
1187    /// SDMX dataset (e.g. WS_CBPOL). Use with --key.
1188    #[arg(long)]
1189    pub dataset: Option<String>,
1190    /// SDMX key (e.g. M.US+XM+JP+GB). Use with --dataset.
1191    #[arg(long)]
1192    pub key: Option<String>,
1193    /// Country codes (comma-separated, e.g. US,XM,JP,GB).
1194    #[arg(long)]
1195    pub countries: Option<String>,
1196    /// Start period (YYYY-MM).
1197    #[arg(long, default_value = "2020-01")]
1198    pub start: String,
1199    #[arg(long, default_value = "json")]
1200    pub format: String,
1201    #[arg(long)]
1202    pub out: Option<PathBuf>,
1203}
1204
1205#[derive(clap::Args, Debug)]
1206pub struct FinanceBojArgs {
1207    /// Preset: policy_rate | call_rate | monetary_base | balance_sheet | money_stock | tankan | fx
1208    #[arg(long)]
1209    pub preset: Option<String>,
1210    /// BOJ database name (e.g. IR01, FM01, BS01, CO). Use with --codes.
1211    #[arg(long)]
1212    pub db: Option<String>,
1213    /// BOJ series codes (comma-separated).
1214    #[arg(long)]
1215    pub codes: Option<String>,
1216    /// Start date (YYYYMM format for BOJ).
1217    #[arg(long, default_value = "202401")]
1218    pub start: String,
1219    #[arg(long, default_value = "json")]
1220    pub format: String,
1221    #[arg(long)]
1222    pub out: Option<PathBuf>,
1223}
1224
1225#[derive(clap::Args, Debug)]
1226pub struct FinanceBoeArgs {
1227    /// Preset: bank_rate | sonia | gilts | m4 | fx | all
1228    #[arg(long)]
1229    pub preset: Option<String>,
1230    /// Series codes (comma-separated, e.g. IUDBEDR,IUDSOIA).
1231    #[arg(long)]
1232    pub codes: Option<String>,
1233    /// Start date (DD/Mon/YYYY format, e.g. 01/Jan/2025).
1234    #[arg(long, default_value = "01/Jan/2025")]
1235    pub start: String,
1236    /// End date (DD/Mon/YYYY or "now").
1237    #[arg(long, default_value = "now")]
1238    pub end: String,
1239    #[arg(long, default_value = "json")]
1240    pub format: String,
1241    #[arg(long)]
1242    pub out: Option<PathBuf>,
1243}
1244
1245#[derive(clap::Args, Debug)]
1246struct FinanceFundamentalsArgs {
1247    /// Tickers to fetch (repeatable or comma-separated).
1248    #[arg(long, visible_alias = "ticker", value_delimiter = ',')]
1249    tickers: Vec<String>,
1250
1251    /// Output format (currently: json).
1252    #[arg(long, default_value = "json")]
1253    format: String,
1254
1255    /// Write full JSON output to a file instead of stdout.
1256    #[arg(long)]
1257    out: Option<PathBuf>,
1258}
1259
1260#[derive(clap::Args, Debug)]
1261struct FinanceSearchArgs {
1262    /// Search query (e.g. "Apple" or "Inflation").
1263    #[arg(long, required = false)]
1264    query: Option<String>,
1265
1266    /// Search query (positional alternative to --query).
1267    #[arg(index = 1, required = false)]
1268    query_positional: Option<String>,
1269
1270    /// Data provider (yahoo | ibkr).
1271    #[arg(long, default_value = "yahoo")]
1272    provider: String,
1273
1274    /// Optional IBKR account code (e.g. U1234567). Used when --provider ibkr.
1275    #[arg(long)]
1276    ibkr_account: Option<String>,
1277
1278    /// Optional IBKR host override.
1279    #[arg(long)]
1280    ibkr_host: Option<String>,
1281
1282    /// Optional IBKR port override.
1283    #[arg(long)]
1284    ibkr_port: Option<u16>,
1285
1286    /// Optional IBKR client id override.
1287    #[arg(long)]
1288    ibkr_client_id: Option<i32>,
1289
1290    /// Optional IBKR market data type: 1 live, 2 frozen, 3 delayed, 4 delayed-frozen.
1291    #[arg(long)]
1292    ibkr_market_data_type: Option<i32>,
1293
1294    /// Output format (currently: json).
1295    #[arg(long, default_value = "json")]
1296    format: String,
1297
1298    /// Optional policy file override.
1299    #[arg(long = "policy-file")]
1300    policy_file: Option<PathBuf>,
1301
1302    /// Policy mode: observe | assist | enforce.
1303    #[arg(long = "policy-mode", default_value = "observe")]
1304    policy_mode: String,
1305
1306    /// Write full JSON output to a file instead of stdout.
1307    #[arg(long)]
1308    out: Option<PathBuf>,
1309}
1310
1311#[derive(clap::Args, Debug)]
1312struct FinanceOddsArgs {
1313    #[command(subcommand)]
1314    action: Option<FinanceOddsAction>,
1315
1316    /// Data source: kalshi (default), polymarket, or auto (kalshi then polymarket).
1317    #[arg(long)]
1318    provider: Option<String>,
1319    /// Kalshi series ticker.
1320    #[arg(long)]
1321    series: Option<String>,
1322
1323    /// Event ticker.
1324    #[arg(long)]
1325    event: Option<String>,
1326
1327    /// Market ticker.
1328    #[arg(long)]
1329    market: Option<String>,
1330
1331    /// Filter by status (e.g. open).
1332    #[arg(long)]
1333    status: Option<String>,
1334
1335    /// Page size limit.
1336    #[arg(long)]
1337    limit: Option<usize>,
1338
1339    /// Pagination cursor.
1340    #[arg(long)]
1341    cursor: Option<String>,
1342
1343    /// Max pages to fetch (Kalshi list endpoints).
1344    #[arg(long)]
1345    max_pages: Option<usize>,
1346
1347    /// List series (Kalshi only).
1348    #[arg(long)]
1349    list_series: bool,
1350
1351    /// List events.
1352    #[arg(long)]
1353    list_events: bool,
1354
1355    /// List markets.
1356    #[arg(long)]
1357    list_markets: bool,
1358
1359    /// List tags (Polymarket only).
1360    #[arg(long)]
1361    list_tags: bool,
1362
1363    /// Category filter (Kalshi list endpoints, and local CSV search when --search is used).
1364    #[arg(long)]
1365    category: Option<String>,
1366
1367    /// Case-insensitive literal substring match (titles/tickers/slugs).
1368    #[arg(long, alias = "query")]
1369    search: Option<String>,
1370
1371    /// Optional country filter for local CSV search (v1: US only).
1372    #[arg(long)]
1373    country: Option<String>,
1374
1375    /// Minimum market volume in USD (local CSV search).
1376    #[arg(long = "min-volume")]
1377    min_volume: Option<f64>,
1378
1379    /// Return top N markets after ranking (local CSV search).
1380    #[arg(long)]
1381    top: Option<usize>,
1382
1383    /// Ranking for local CSV search output.
1384    /// Options: relevance, volume, delta_prob, delta_yes_price, delta_volume.
1385    #[arg(long = "sort-by", default_value = "relevance")]
1386    sort_by: String,
1387    /// Query profile: auto | macro | broad.
1388    #[arg(long, default_value = "auto")]
1389    profile: String,
1390
1391    /// Optional policy file override.
1392    #[arg(long = "policy-file")]
1393    policy_file: Option<PathBuf>,
1394
1395    /// Policy mode: observe | assist | enforce.
1396    #[arg(long = "policy-mode", default_value = "observe")]
1397    policy_mode: String,
1398
1399    /// Only include markets that changed since the last sync (requires sync delta index).
1400    #[arg(long, default_value_t = false)]
1401    deltas_only: bool,
1402
1403    /// Minimum absolute probability move (percentage points) since last sync.
1404    /// Requires sync delta index.
1405    #[arg(long = "min-delta-pp")]
1406    min_delta_pp: Option<f64>,
1407
1408    /// Include compact ranking explanations in local CSV search output.
1409    #[arg(long, default_value_t = false)]
1410    explain: bool,
1411
1412    /// Upgrade CSV search results to live API prices (fresh bid/ask/volume).
1413    #[arg(long, default_value_t = false)]
1414    live: bool,
1415
1416    /// Include mention/speech-prediction markets (filtered by default).
1417    #[arg(long, default_value_t = false)]
1418    include_mentions: bool,
1419
1420    /// Include orderbook depth (heavier call; Polymarket orderbook supported).
1421    #[arg(long)]
1422    orderbook: bool,
1423
1424    /// Orderbook depth (levels).
1425    #[arg(long)]
1426    depth: Option<usize>,
1427
1428    /// Output format (currently: json).
1429    #[arg(long, default_value = "json")]
1430    format: String,
1431
1432    /// Write full JSON output to a file instead of stdout.
1433    #[arg(long)]
1434    out: Option<PathBuf>,
1435}
1436
1437#[derive(Subcommand, Debug)]
1438enum FinanceOddsAction {
1439    /// Sync prediction markets (Kalshi + Polymarket) to a local CSV cache.
1440    Sync(FinanceSyncArgs),
1441
1442    /// Print local cache paths for odds CSVs.
1443    Where(FinanceOddsWhereArgs),
1444}
1445
1446#[derive(clap::Args, Debug)]
1447struct FinanceOddsWhereArgs {
1448    /// Override cache directory (defaults to the same cache used by `eli finance sync`).
1449    #[arg(long)]
1450    cache_dir: Option<PathBuf>,
1451}
1452
1453#[derive(clap::Args, Debug)]
1454struct FinanceOptionsArgs {
1455    /// Underlying ticker (e.g. INTC).
1456    #[arg(long, visible_alias = "tickers")]
1457    ticker: String,
1458
1459    /// Expiration date (YYYY-MM-DD). If omitted, summary mode uses the first usable future expiry.
1460    #[arg(long)]
1461    expiry: Option<String>,
1462
1463    /// Target days to expiry. If set and --expiry is omitted, picks the closest listed expiry.
1464    #[arg(long = "target-dte")]
1465    target_dte: Option<i64>,
1466
1467    /// Filter: calls | puts | both (default: both).
1468    #[arg(long = "type", value_name = "calls|puts|both")]
1469    option_type: Option<String>,
1470
1471    /// Only return strikes within this percentage of the underlying (e.g. 10 = +/-10%).
1472    #[arg(long = "near-money")]
1473    near_money: Option<f64>,
1474
1475    /// Return summary metrics only (no full chain).
1476    #[arg(long)]
1477    summary: bool,
1478
1479    /// List available expirations only.
1480    #[arg(long)]
1481    expirations: bool,
1482
1483    /// Fetch ALL expirations and compute cross-expiry analytics.
1484    /// Dumps full chain to --out file, prints term structure summary to stdout.
1485    #[arg(long)]
1486    all: bool,
1487
1488    /// Data provider (yahoo | ibkr).
1489    #[arg(long, default_value = "yahoo")]
1490    provider: String,
1491
1492    /// Optional IBKR account code (e.g. U1234567). Used when --provider ibkr.
1493    #[arg(long)]
1494    ibkr_account: Option<String>,
1495
1496    /// Optional IBKR host override.
1497    #[arg(long)]
1498    ibkr_host: Option<String>,
1499
1500    /// Optional IBKR port override.
1501    #[arg(long)]
1502    ibkr_port: Option<u16>,
1503
1504    /// Optional IBKR client id override.
1505    #[arg(long)]
1506    ibkr_client_id: Option<i32>,
1507
1508    /// Optional IBKR market data type: 1 live, 2 frozen, 3 delayed, 4 delayed-frozen.
1509    #[arg(long)]
1510    ibkr_market_data_type: Option<i32>,
1511
1512    /// Output format (currently: json).
1513    #[arg(long, default_value = "json")]
1514    format: String,
1515
1516    /// Write full JSON output to a file instead of stdout.
1517    #[arg(long)]
1518    out: Option<PathBuf>,
1519}
1520
1521#[derive(clap::Args, Debug)]
1522struct FinanceSyncArgs {
1523    /// Sources to sync: kalshi, polymarket (comma-separated). Default: both.
1524    #[arg(long, value_delimiter = ',')]
1525    sources: Vec<String>,
1526
1527    /// Debug only: frontier-sample page cap per source. Hides coverage and is not a normal sync control.
1528    #[arg(long)]
1529    max_pages: Option<usize>,
1530
1531    /// Fail if pagination/coverage checks indicate incomplete source exhaustion.
1532    #[arg(long)]
1533    strict: bool,
1534
1535    /// Include sports markets/events in sync output (default: false).
1536    #[arg(long)]
1537    include_sports: bool,
1538
1539    /// Include Kalshi historical markets (archived/settled tier). Default: false.
1540    #[arg(long, hide = true)]
1541    include_historical: bool,
1542
1543    /// Fast refresh from Kalshi websocket ticker stream using cached baseline (no full re-pagination).
1544    #[arg(long)]
1545    stream_refresh: bool,
1546
1547    /// Breadth heartbeat in hours for stream refresh mode. If cached baseline is older, force strict REST anchor sync (default: 6).
1548    #[arg(long, hide = true)]
1549    refresh_heartbeat_hours: Option<u64>,
1550
1551    /// WebSocket listen window in seconds for stream refresh mode (default: 300).
1552    #[arg(long, hide = true)]
1553    stream_refresh_timeout_secs: Option<u64>,
1554
1555    /// Cache directory for CSV files (defaults to platform cache dir).
1556    #[arg(long)]
1557    cache_dir: Option<PathBuf>,
1558
1559    /// Output format (currently: json).
1560    #[arg(long, default_value = "json", hide = true)]
1561    format: String,
1562
1563    /// Emit full verbose payload on stdout (default is compact/token-efficient).
1564    #[arg(long, hide = true)]
1565    full: bool,
1566
1567    /// Optional policy file override.
1568    #[arg(long = "policy-file", hide = true)]
1569    policy_file: Option<PathBuf>,
1570
1571    /// Policy mode: observe | assist | enforce.
1572    #[arg(long = "policy-mode", default_value = "observe", hide = true)]
1573    policy_mode: String,
1574
1575    /// Write full JSON output to a file instead of stdout.
1576    #[arg(long)]
1577    out: Option<PathBuf>,
1578}
1579
1580#[derive(clap::Args, Debug)]
1581struct FinancePaperArgs {
1582    /// Command: trade | positions | trades | mark | reset
1583    #[arg(long, value_enum, default_value = "trade")]
1584    command: FinancePaperCommandArg,
1585
1586    /// Execution mode (v1: simulated local fills)
1587    #[arg(long, value_enum, default_value = "simulated")]
1588    mode: FinancePaperModeArg,
1589
1590    /// Paper account name.
1591    #[arg(long, default_value = "default")]
1592    account: String,
1593
1594    /// Provider for trade/mark pricing (kalshi|polymarket).
1595    #[arg(long)]
1596    provider: Option<String>,
1597
1598    /// Market ticker or market id (required for --command trade).
1599    #[arg(long)]
1600    market: Option<String>,
1601
1602    /// Side (yes|no) for --command trade.
1603    #[arg(long, value_enum)]
1604    side: Option<FinancePaperSideArg>,
1605
1606    /// Order action (buy|sell) for --command trade.
1607    #[arg(long, value_enum)]
1608    action: Option<FinancePaperOrderActionArg>,
1609
1610    /// Quantity/contracts for --command trade.
1611    #[arg(long)]
1612    qty: Option<f64>,
1613
1614    /// Optional manual fill price in probability units [0,1]. If omitted, uses live midpoint.
1615    #[arg(long)]
1616    price: Option<f64>,
1617
1618    /// Starting paper cash for account init/reset (default: 10000).
1619    #[arg(long)]
1620    starting_cash: Option<f64>,
1621
1622    /// Trade history limit for --command trades (default: 50).
1623    #[arg(long)]
1624    limit: Option<usize>,
1625
1626    /// Optional custom cache dir or full state file path.
1627    #[arg(long)]
1628    cache_dir: Option<PathBuf>,
1629
1630    /// Output format (json only).
1631    #[arg(long, default_value = "json")]
1632    format: String,
1633
1634    /// Write full JSON output to a file instead of stdout.
1635    #[arg(long)]
1636    out: Option<PathBuf>,
1637}
1638
1639#[derive(clap::Args, Debug)]
1640struct FinanceFilingsArgs {
1641    /// Ticker to fetch filings for.
1642    #[arg(long, visible_alias = "tickers")]
1643    ticker: String,
1644
1645    /// Form types to include (comma-separated), e.g. 8-K,10-K,10-Q. Defaults to 8-K,10-K,10-Q.
1646    #[arg(long, value_delimiter = ',')]
1647    forms: Vec<String>,
1648
1649    /// Max number of filings to return.
1650    #[arg(long, default_value_t = 5)]
1651    limit: usize,
1652
1653    /// Download primary documents, save to cache, and include a text excerpt inline.
1654    #[arg(long)]
1655    include_text: bool,
1656
1657    /// Max chars for the inline excerpt (full text is still written to disk when --include-text is set).
1658    #[arg(long)]
1659    max_chars: Option<usize>,
1660
1661    /// Override cache directory (defaults to Eli's cache dir).
1662    #[arg(long)]
1663    cache_dir: Option<PathBuf>,
1664
1665    /// Output format (currently: json).
1666    #[arg(long, default_value = "json")]
1667    format: String,
1668
1669    /// Write full JSON output to a file instead of stdout.
1670    #[arg(long)]
1671    out: Option<PathBuf>,
1672}
1673
1674#[derive(clap::Args, Debug)]
1675struct FinanceTimeseriesArgs {
1676    /// Preset ticker group (macro, forex_majors, yield_curve, liquidity, crypto).
1677    /// Expands to predefined tickers with default range/granularity. User flags override defaults.
1678    #[arg(long)]
1679    preset: Option<String>,
1680
1681    /// Tickers to fetch (repeatable or comma-separated).
1682    #[arg(long, visible_alias = "ticker", value_delimiter = ',')]
1683    tickers: Vec<String>,
1684
1685    /// Optional file with tickers (one per line).
1686    #[arg(long)]
1687    tickers_file: Option<PathBuf>,
1688
1689    /// Lookback range (e.g. 1d, 12mo, 5y).
1690    #[arg(long, default_value = "1y")]
1691    range: String,
1692
1693    /// Candle size / sampling granularity (e.g. 10m, 1h, 1d, 1w, 1mo).
1694    #[arg(long, default_value = "1d")]
1695    granularity: String,
1696
1697    /// Explicit window start (RFC3339 or YYYY-MM-DD). Must be used with --end.
1698    #[arg(long)]
1699    start: Option<String>,
1700
1701    /// Explicit window end (RFC3339 or YYYY-MM-DD). Must be used with --start.
1702    #[arg(long)]
1703    end: Option<String>,
1704
1705    /// End timestamp for the window (RFC3339). If you pass YYYY-MM-DD, it's treated as end-of-day UTC. Defaults to now (UTC).
1706    #[arg(long)]
1707    as_of: Option<String>,
1708
1709    /// Data provider (auto | yahoo | fred | ibkr | pyth | binance). "auto" routes by ticker prefix: PYTH:/CLEV:/IBKR:/BN:/FRED: → matching provider; numeric (Polymarket) and KX*-prefix (Kalshi) auto-detected; bare names → Yahoo, with FRED fallback for macro-style IDs.
1710    #[arg(long, default_value = "auto")]
1711    provider: String,
1712
1713    /// Optional IBKR account code (e.g. U1234567). Used when --provider ibkr.
1714    #[arg(long)]
1715    ibkr_account: Option<String>,
1716
1717    /// Optional IBKR host override.
1718    #[arg(long)]
1719    ibkr_host: Option<String>,
1720
1721    /// Optional IBKR port override.
1722    #[arg(long)]
1723    ibkr_port: Option<u16>,
1724
1725    /// Optional IBKR client id override.
1726    #[arg(long)]
1727    ibkr_client_id: Option<i32>,
1728
1729    /// Optional IBKR market data type: 1 live, 2 frozen, 3 delayed, 4 delayed-frozen.
1730    #[arg(long)]
1731    ibkr_market_data_type: Option<i32>,
1732
1733    /// Optional explicit prediction market provider to include as a timeseries series (kalshi | polymarket).
1734    #[arg(long)]
1735    odds_provider: Option<String>,
1736
1737    /// Optional prediction market identifier. Kalshi: market ticker. Polymarket: market ID or slug.
1738    #[arg(long)]
1739    odds_market: Option<String>,
1740
1741    /// Prediction market side to include for --odds-market (yes | no). Defaults to yes.
1742    #[arg(long, default_value = "yes")]
1743    odds_side: String,
1744
1745    /// Safety cap for points per ticker.
1746    #[arg(long)]
1747    max_points_per_ticker: Option<usize>,
1748
1749    /// Override cache directory (defaults to Eli's cache dir).
1750    #[arg(long)]
1751    cache_dir: Option<PathBuf>,
1752
1753    /// Output format (currently: json).
1754    #[arg(long, default_value = "json")]
1755    format: String,
1756
1757    /// Write full JSON output to a file instead of stdout.
1758    #[arg(long)]
1759    out: Option<PathBuf>,
1760}
1761
1762#[derive(clap::Args, Debug)]
1763struct FinanceIbkrArgs {
1764    /// IBKR command surface.
1765    #[arg(long, value_enum)]
1766    command: FinanceIbkrCommandArg,
1767
1768    /// Optional IBKR account code (e.g. U1234567).
1769    #[arg(long)]
1770    account: Option<String>,
1771
1772    /// Optional IBKR host override.
1773    #[arg(long)]
1774    host: Option<String>,
1775
1776    /// Optional IBKR port override.
1777    #[arg(long)]
1778    port: Option<u16>,
1779
1780    /// Optional IBKR client id override.
1781    #[arg(long)]
1782    client_id: Option<i32>,
1783
1784    /// Optional IBKR market data type: 1 live, 2 frozen, 3 delayed, 4 delayed-frozen.
1785    #[arg(long)]
1786    market_data_type: Option<i32>,
1787
1788    /// Optional timeout in seconds for the bridge request.
1789    #[arg(long)]
1790    timeout_secs: Option<u64>,
1791
1792    /// Tickers for snapshot / timeseries commands (repeatable or comma-separated).
1793    #[arg(long, value_delimiter = ',')]
1794    tickers: Vec<String>,
1795
1796    /// Range for timeseries requests (e.g. 1d, 1mo, 1y).
1797    #[arg(long, default_value = "1mo")]
1798    range: String,
1799
1800    /// Granularity for timeseries requests (e.g. 1min, 5min, 1h, 1d).
1801    #[arg(long, default_value = "1day")]
1802    granularity: String,
1803
1804    /// Contract symbol for order placement.
1805    #[arg(long)]
1806    symbol: Option<String>,
1807
1808    /// Contract security type for orders (default: STK).
1809    #[arg(long)]
1810    sec_type: Option<String>,
1811
1812    /// Contract exchange (default: SMART).
1813    #[arg(long)]
1814    exchange: Option<String>,
1815
1816    /// Contract primary exchange.
1817    #[arg(long)]
1818    primary_exchange: Option<String>,
1819
1820    /// Contract currency (default: USD).
1821    #[arg(long)]
1822    currency: Option<String>,
1823
1824    /// Contract expiry / contract month (e.g. 20260320).
1825    #[arg(long)]
1826    expiry: Option<String>,
1827
1828    /// Contract strike price.
1829    #[arg(long)]
1830    strike: Option<f64>,
1831
1832    /// Contract right (C/P).
1833    #[arg(long)]
1834    right: Option<String>,
1835
1836    /// Contract multiplier.
1837    #[arg(long)]
1838    multiplier: Option<String>,
1839
1840    /// Trading class.
1841    #[arg(long)]
1842    trading_class: Option<String>,
1843
1844    /// Order side for place-order (BUY or SELL).
1845    #[arg(long)]
1846    side: Option<String>,
1847
1848    /// Order type for place-order (MKT, LMT, STP, STP LMT).
1849    #[arg(long)]
1850    order_type: Option<String>,
1851
1852    /// Quantity for place-order.
1853    #[arg(long)]
1854    quantity: Option<f64>,
1855
1856    /// Limit price for limit orders.
1857    #[arg(long)]
1858    limit_price: Option<f64>,
1859
1860    /// Stop price for stop orders.
1861    #[arg(long)]
1862    stop_price: Option<f64>,
1863
1864    /// Time in force (default: DAY).
1865    #[arg(long)]
1866    tif: Option<String>,
1867
1868    /// Order id for cancel-order.
1869    #[arg(long)]
1870    order_id: Option<i32>,
1871
1872    /// Optional account summary tag filter.
1873    #[arg(long)]
1874    tags: Option<String>,
1875
1876    /// Output format (json only).
1877    #[arg(long, default_value = "json")]
1878    format: String,
1879
1880    /// Write full JSON output to a file instead of stdout.
1881    #[arg(long)]
1882    out: Option<PathBuf>,
1883}