Skip to main content

apr_cli/
lib.rs

1//! apr-cli library
2//!
3//! This library is the foundation for the apr CLI binary.
4//! Exports CLI structures for testing and reuse.
5
6// APR-MONO: Clippy pedantic allows for monorepo transition.
7// unwrap() eliminated (524 → expect()). Style lints from 20 merged crates
8// are suppressed at crate level. Will be incrementally addressed.
9#![allow(clippy::all, clippy::pedantic, clippy::disallowed_methods)]
10#![allow(
11    unreachable_code,
12    unused_variables,
13    unused_imports,
14    dead_code,
15    unused_assignments
16)]
17
18use clap::{Parser, Subcommand};
19use std::path::{Path, PathBuf};
20
21// Contract assertions from YAML (pv codegen)
22#[macro_use]
23#[allow(unused_macros, clippy::duplicated_attributes)]
24mod generated_contracts;
25
26mod commands;
27pub mod error;
28mod output;
29pub mod pipe;
30
31pub use error::CliError;
32
33// Public re-exports for integration tests
34pub mod qa_types {
35    pub use crate::commands::qa::{GateResult, QaReport, SystemInfo};
36}
37
38// Public re-exports for downstream crates (whisper-apr proxies these)
39pub mod model_pull {
40    pub use crate::commands::pull::{list, run};
41}
42
43#[cfg(feature = "inference")]
44pub mod federation;
45
46// Commands are crate-private, used internally by execute_command
47use commands::{
48    bench, canary, canary::CanaryCommands, cbtop, chat, compare_hf, compile, convert, data, debug,
49    diagnose, diff, distill, eval, explain, export, flow, hex, import, inspect, lint, mcp, merge,
50    oracle, pipeline, probar, profile, prune, publish, pull, qa, qualify, quantize, rosetta,
51    rosetta::RosettaCommands, run, serve, showcase, tensors, tokenize, trace, tree, tui, validate,
52    validate_manifest,
53};
54#[cfg(feature = "training")]
55use commands::{finetune, gpu, train, tune};
56
57/// apr - APR Model Operations Tool
58///
59/// Inspect, debug, and manage .apr model files.
60/// Toyota Way: Genchi Genbutsu - Go and see the actual data.
61#[derive(Parser, Debug)]
62#[command(name = "apr")]
63#[command(author, version = concat!(env!("CARGO_PKG_VERSION"), " (", env!("APR_GIT_SHA"), ")"), about, long_about = None)]
64#[command(propagate_version = true)]
65pub struct Cli {
66    #[command(subcommand)]
67    pub command: Box<Commands>,
68
69    /// Output as JSON
70    #[arg(long, global = true)]
71    pub json: bool,
72
73    /// Verbose output
74    #[arg(short, long, global = true)]
75    pub verbose: bool,
76
77    /// Quiet mode (errors only)
78    #[arg(short, long, global = true)]
79    pub quiet: bool,
80
81    /// Disable network access (Sovereign AI compliance, Section 9)
82    #[arg(long, global = true)]
83    pub offline: bool,
84
85    /// Skip tensor contract validation (PMAT-237: use with diagnostic tooling)
86    #[arg(long, global = true)]
87    pub skip_contract: bool,
88}
89
90include!("commands_enum.rs");
91include!("model_ops_commands.rs");
92include!("extended_commands.rs");
93include!("tool_commands.rs");
94include!("data_commands.rs");
95#[cfg(feature = "training")]
96include!("train_commands.rs");
97include!("serve_commands.rs");
98include!("tokenize_commands.rs");
99include!("pipeline_commands.rs");
100include!("validate.rs");
101include!("dispatch_run.rs");
102include!("dispatch.rs");
103include!("dispatch_analysis.rs");
104include!("lib_07.rs");
105
106/// Full CLI entry point for `cargo install aprender`.
107///
108/// This function encapsulates the complete `apr` binary logic so that
109/// the `aprender` facade crate can produce the same binary via
110/// `cargo install aprender` (in addition to `cargo install apr-cli`).
111pub fn cli_main() -> std::process::ExitCode {
112    // GH-667: Reset SIGPIPE to default so piping to head/less doesn't panic.
113    #[cfg(unix)]
114    #[allow(unsafe_code)]
115    unsafe {
116        libc::signal(libc::SIGPIPE, libc::SIG_DFL);
117    }
118
119    // GH-646: Clear FPCR.FZ16 on aarch64 so f16 subnormals work.
120    #[cfg(target_arch = "aarch64")]
121    #[allow(unsafe_code)]
122    unsafe {
123        let fpcr: u64;
124        core::arch::asm!("mrs {}, fpcr", out(reg) fpcr);
125        if fpcr & (1 << 19) != 0 {
126            let new_fpcr = fpcr & !(1 << 19);
127            core::arch::asm!("msr fpcr, {}", in(reg) new_fpcr);
128        }
129    }
130
131    // GH-662: Respect NO_COLOR env var and non-TTY output.
132    let no_color = std::env::var("NO_COLOR").is_ok();
133    let is_tty = std::io::IsTerminal::is_terminal(&std::io::stdout());
134    if no_color || !is_tty {
135        colored::control::set_override(false);
136    }
137
138    let cli = Cli::parse();
139    match execute_command(&cli) {
140        Ok(()) => std::process::ExitCode::SUCCESS,
141        Err(e) => {
142            eprintln!("error: {e}");
143            e.exit_code()
144        }
145    }
146}