cli_engine/lib.rs
1//! Build consistent, domain-oriented CLIs with a small amount of Rust.
2//!
3//! `cli_engine` provides the shared pieces that most CLI tools need:
4//! command registration, authentication provider routing, authorization hooks,
5//! audit and activity hooks, structured output, output schemas, guides, search,
6//! command tree rendering, busybox-style multi-call (`argv[0]`) dispatch, and
7//! authenticated HTTP transport helpers.
8//!
9//! The intended shape is:
10//!
11//! 1. Each team owns one or more [`Module`] values.
12//! 2. A module registers noun-based [`GroupSpec`] groups.
13//! 3. Groups contain verb-like [`CommandSpec`] leaf commands.
14//! 4. Command handlers stay focused on domain behavior while [`Middleware`]
15//! handles authentication, dry-run, audit, activity, output, and errors.
16//!
17//! # Quick Start
18//!
19//! ```no_run
20//! use clap::Arg;
21//! use cli_engine::{
22//! BuildInfo, Cli, CliConfig, CommandSpec, GroupSpec, Module,
23//! RuntimeCommandSpec, RuntimeGroupSpec,
24//! };
25//! use serde_json::json;
26//!
27//! #[tokio::main]
28//! async fn main() -> std::process::ExitCode {
29//! let list = RuntimeCommandSpec::new(
30//! CommandSpec::new("list", "List projects")
31//! .with_system("projects-api")
32//! .with_default_fields("id,name,status")
33//! .with_arg(Arg::new("team").long("team").required(true))
34//! .no_auth(true),
35//! async |_credential, args| {
36//! let team = args
37//! .get("team")
38//! .and_then(|value| value.as_str())
39//! .unwrap_or_default();
40//! Ok(cli_engine::CommandResult::new(json!([
41//! { "id": "p1", "name": "Portal", "status": "active", "team": team }
42//! ])))
43//! },
44//! );
45//!
46//! let module = Module::new("Platform Systems", move |_context| {
47//! RuntimeGroupSpec::new(GroupSpec::new("project", "Manage projects"))
48//! .with_command(list.clone())
49//! });
50//!
51//! let cli = Cli::new(
52//! CliConfig::new("example", "Example cli-engine application", "example")
53//! .with_build(BuildInfo::new(env!("CARGO_PKG_VERSION")))
54//! .with_module(module),
55//! );
56//!
57//! cli.execute().await
58//! }
59//! ```
60//!
61//! Command paths are colon-separated (`project:list`) for policy, audit,
62//! schema, and authorization compatibility with existing CLI ecosystems.
63
64// Lets `#[derive(EnvConfig)]`-generated code always emit `::cli_engine::env_config::...`
65// paths, whether the derive is used by an external consumer crate or by this
66// crate itself (e.g. `auth::pkce::OAuthSection`). The lint doesn't see through
67// macro-generated code as a "use" of the alias, so it's silenced here rather
68// than fought.
69#[allow(unused_extern_crates)]
70extern crate self as cli_engine;
71
72/// Auth provider traits, dispatch, and built-in provider commands.
73pub mod auth;
74/// CLI application assembly and execution.
75pub mod cli;
76/// Command and command-group specifications.
77pub mod command;
78/// Engine config file and credential-storage selection.
79pub mod config;
80/// Built-in `config` command group.
81pub mod config_commands;
82/// Built-in `env` command group (private; only `cli.rs` consumes it).
83mod env_commands;
84/// Declarative, attribute-driven per-environment configuration: `EnvConfig`,
85/// `ConfigSource`, and the `#[derive(EnvConfig)]` macro's runtime support.
86pub mod env_config;
87/// First-class environment definitions and layered resolution.
88pub mod environments;
89/// Shared error type and error traits.
90pub mod error;
91/// Stage-based feature flagging primitives (readiness gating), distinct from `flags`.
92pub mod feature_flags;
93/// Built-in `flags` command group (private; only `cli.rs` consumes it).
94mod flag_commands;
95/// Global framework flags and flag-extraction helpers.
96pub mod flags;
97/// Filesystem and path utilities (base dir, path-component safety, atomic write).
98pub mod fs;
99/// Embedded or file-backed guide parsing.
100pub mod guide;
101/// Cross-cutting command execution middleware.
102pub mod middleware;
103/// Domain module registration helpers.
104pub mod module;
105/// Structured output envelopes, renderers, schemas, and field projection.
106pub mod output;
107/// Search indexing for commands, guides, and extra documents.
108pub mod prompt;
109pub mod search;
110/// Command risk tiers used by authentication, authorization, and dry-run.
111pub mod tier;
112/// HTTP transport client and auth injectors.
113pub mod transport;
114/// Command tree data model and human rendering.
115pub mod tree;
116
117#[cfg(feature = "pkce-auth")]
118pub use auth::storage::{AutoStorage, KeyringStorage};
119pub use auth::storage::{
120 CredentialKey, CredentialStorage, FileStorage, default_storage, storage_for,
121};
122pub use auth::{
123 AuthLoginResult, AuthProvider, AuthStatusEntry, CACHE_TTL, Credential, CredentialRequest,
124 Dispatcher, SingleProvider, StatusEntry, auth_command_group, login_and_build,
125 login_and_build_with_scopes, logout_result, status_result, to_status_entry,
126};
127pub use cli::{
128 ApplyFlags, Argv0LinkMethod, Argv0Route, BuildInfo, Cli, CliConfig, CliRunOutput,
129 ExtraSearchDocs, InitDeps, ModuleHelpEntry, OnShutdown, PreRun, RegisterFlags, ResolveMeta,
130 RootNextActions, build_root_long,
131};
132pub use command::{
133 CommandContext, CommandFuture, CommandHandler, CommandResult, CommandResultMetadata,
134 CommandSpec, GroupSpec, PaginationConfig, RuntimeCommandSpec, RuntimeGroupSpec, StreamSender,
135 StreamingCommandFuture, StreamingCommandHandler, command_args_from_matches,
136 command_path_from_matches, command_path_from_parts, leaf_matches,
137};
138pub use config::{
139 ConfigFile, CredentialStore, CredentialsConfig, EngineConfig, ParseCredentialStoreError,
140 credential_store_env_var, resolve_credential_store, resolve_credential_store_with,
141};
142pub use config_commands::config_command_group;
143pub use env_config::{
144 ConfigSource, EnvConfig, EnvConfigError, EnvSource, EnvVarSource, SourceChain, ValueSource,
145};
146pub use environments::{EnvTable, Environments};
147pub use error::{
148 CliCoreError, DetailedError, ExitCoder, Result, exit_code_for_error, exit_code_for_exit_coder,
149};
150pub use feature_flags::{FeatureFlag, FlagEntry, FlagPolicy, FlagRegistry, Stage};
151pub use flags::{
152 GlobalFlags, InteractivityMode, app_id_env_prefix, debug_component_enabled,
153 default_output_format, derive_bool_flags, derive_value_flags, detect_interactive,
154 extract_command_path, extract_output_format, global_flags_from_matches, has_true_schema_flag,
155 min_stage_env_var, output_env_var, register_global_flags, register_reason_flag,
156 resolve_default_output_format,
157};
158pub use guide::{GuideEntry, parse_guides, parse_guides_from_markdown};
159pub use middleware::{
160 ActivityEmitter, ActivityEvent, Auditor, AuthRequirement, Authorizer, CommandMeta,
161 CredentialResolver, Middleware, MiddlewareOutput, MiddlewareRequest,
162};
163pub use module::{CommandModule, Module, ModuleContext, ModuleRegister, build_module_group};
164pub use output::{
165 Alignment, Envelope, ErrorEnvelope, FieldInfo, HumanViewDef, HumanViewFn, HumanViewRegistry,
166 HumanViewRenderer, Metadata, NextAction, NextActionParam, OutputField, OutputFormat,
167 OutputSchema, PaginationMeta, PipelineOpts, RendererFactory, SchemaInfo, SchemaRegistry,
168 TableColumn, apply_pipeline, build_detailed_error_envelope, build_error_envelope, fields_for,
169 fields_from_json_schema, filter_fields, format_help_section, get_global_schema_by_path,
170 global_human_view_registry_snapshot, global_schema_registry_snapshot, is_valid_output_format,
171 json_schema_for, json_schema_info, lookup_global_human_view_columns,
172 lookup_global_human_view_func, parse_fields, register_global_human_view,
173 register_global_human_view_func, register_global_json_schema, register_global_schema,
174 register_global_schema_fields, register_global_schema_info, render, render_data,
175 render_data_format, render_detailed_error, render_detailed_error_format, render_error,
176 render_error_format, render_format, render_human, render_human_with_registry,
177 render_human_with_registry_for_schema, render_human_with_registry_selected,
178 render_human_with_view, render_json, render_toon, write_render,
179};
180pub use search::{SearchDocument, SearchResult};
181pub use tier::Tier;
182pub use tree::{TreeNode, build_tree_from_clap, build_tree_from_parts, render_tree_human};