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