//! `NotesCraft` headless CLI: `info`, `search`, `read`, `write`, `append`, //! `links`, `backlinks`, `tags`, `daily`, `template`, `commands`, `run`, //! `doctor` and `mcp`, all over the same engine commands the app and MCP run //! (SPEC 10.1). //! //! Exit codes: `0` ok, `1` command error, `2` usage error, `3` vault locked, //! outside the vault or unsupported. #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] mod args; mod commands; mod error; mod output; mod text; use std::ffi::OsString; use std::process::ExitCode; fn main() -> ExitCode { let raw: Vec = std::env::args_os().skip(1).collect(); // `--json` is honoured even when the rest of the command line is wrong, so // a script always gets the same envelope shape back. let json = raw.iter().any(|arg| arg == "--json"); match args::parse(raw) { Err(error) => { output::fail(&error, json); ExitCode::from(error.exit_code()) } Ok(cli) => match commands::run(&cli) { Ok(value) => { output::ok(&cli.command, &value, cli.json); ExitCode::SUCCESS } Err(error) => { // stdout belongs to the MCP protocol, so a failure there is // reported on stderr alone. output::fail(&error, cli.json && !cli.command.owns_stdout()); ExitCode::from(error.exit_code()) } }, } }