Skip to main content

skiff_cli/
lib.rs

1//! skiff — turn any MCP server, OpenAPI spec, or GraphQL endpoint into a CLI.
2//!
3//! Library entry is [`run`]. The binary is a thin wrapper; session daemons reuse
4//! the same binary via the hidden `__session_daemon <config-path>` argv form.
5//!
6//! Inspired by <https://github.com/knowsuchagency/mcp2cli> (Python prior art).
7
8pub mod bake;
9pub mod cache;
10pub mod cli;
11pub mod coerce;
12pub mod error;
13pub mod filter;
14pub mod fsutil;
15pub mod graphql;
16pub mod mcp;
17pub mod model;
18pub mod oauth;
19pub mod openapi;
20pub mod output;
21pub mod paths;
22pub mod session;
23pub mod spool;
24pub mod tools_index;
25pub mod usage;
26
27pub use error::{Error, Result};
28pub use model::{CommandDef, ParamDef, ParamLocation, ParamType};
29
30use std::ffi::OsString;
31use std::path::PathBuf;
32
33/// Run the CLI with `argv` (no program name). Returns [`Error`] for exit mapping.
34pub fn run(args: impl IntoIterator<Item = OsString>) -> Result<()> {
35    let args: Vec<OsString> = args.into_iter().collect();
36    // Hidden daemon entry: skiff __session_daemon <config-path>
37    if args.first().and_then(|a| a.to_str()) == Some("__session_daemon") {
38        #[cfg(unix)]
39        {
40            let path = args
41                .get(1)
42                .map(PathBuf::from)
43                .ok_or_else(|| Error::usage("__session_daemon requires a config path"))?;
44            return session::run_session_daemon(path);
45        }
46        #[cfg(not(unix))]
47        {
48            return Err(session::sessions_unsupported());
49        }
50    }
51    match cli::dispatch(args) {
52        Err(Error::Usage(msg)) if msg == "__printed__" || msg == "__help__" => Ok(()),
53        other => other,
54    }
55}