1mod ask;
4mod ask_client;
5mod ask_sources;
6mod changes;
7mod init;
8mod inspect;
9mod meta;
10mod read;
11mod recall;
12mod related;
13mod search;
14pub(crate) mod secrets;
15mod status;
16mod sync;
17
18use crate::cli::{Cli, Commands};
19use crate::mcp::state::{ConfigState, McpServerState};
20use crate::mcp::transport::run_jsonrpc_loop_with_state;
21use crate::output::OutputMode;
22use eyre::{Result, bail};
23use std::io::{self, BufReader};
24use std::sync::Arc;
25
26pub async fn run(cli: &Cli) -> Result<()> {
32 if cli.skill {
33 use std::io::Write as _;
34 writeln!(io::stdout().lock(), "{}", crate::SKILL_MD)?;
35 return Ok(());
36 }
37
38 let Some(cmd) = &cli.command else {
39 bail!("missing command; try `talon --help`");
40 };
41
42 match cmd {
43 Commands::Mcp => {
44 crate::mcp::diagnostics::install_panic_hook();
45 let _ready_guard = crate::mcp::diagnostics::ready_guard();
46 let config = crate::config::load_config(cli.config_file.as_deref())?;
47 let vault_path = config.vault_path.clone();
48 let db_path = config.db_path.clone();
49 let config_path = config.config_file_path.clone();
50 let config_state = ConfigState {
51 config,
52 config_path,
53 vault_path,
54 db_path,
55 };
56 let state = McpServerState::new(config_state);
57 let vault_path_for_watcher = state.config.vault_path.clone();
58 crate::mcp::background::watcher::spawn_watcher(
59 vault_path_for_watcher,
60 Arc::clone(&state),
61 );
62 crate::mcp::background::embed::spawn_embed_ticker(Arc::clone(&state));
63 let stdin = io::stdin();
64 let stdout = io::stdout();
65 let outcome = tokio::task::block_in_place(|| {
69 run_jsonrpc_loop_with_state(BufReader::new(stdin.lock()), stdout.lock(), &state)
70 })?;
71 let _ = outcome;
72 crate::mcp::diagnostics::clear_ready();
73 Ok(())
74 }
75 Commands::Init(args) => init::emit(args),
76 Commands::Search(args) => search::emit(args, cli).await,
77 Commands::Ask(args) => ask::emit(args, cli).await,
78 Commands::Read(args) => read::emit(args, cli).await,
79 Commands::Sync(args) => sync::emit(args, cli).await,
80 Commands::Related(args) => related::emit(args, cli).await,
81 Commands::Status(args) => status::emit(args, cli),
82 Commands::Meta(args) => meta::emit(args, cli).await,
83 Commands::Changes(args) => changes::emit(args, cli).await,
84 Commands::Inspect(args) => inspect::emit(args, cli).await,
85 Commands::Recall(args) => recall::emit(args, cli).await,
86 Commands::Secrets(args) => secrets::emit(&args.subcommand),
87 }
88}
89
90pub(super) const fn output_mode(cli: &Cli) -> OutputMode {
91 if cli.agent {
92 OutputMode::Agent
93 } else if cli.json {
94 OutputMode::JsonPretty
95 } else {
96 OutputMode::Human
97 }
98}
99
100pub(super) fn should_spin(cli: &Cli) -> bool {
101 !cli.agent && !cli.json && crate::platform::stderr_is_tty()
102}