[package]
name = "apr-cli"
version.workspace = true
edition = "2021"
rust-version = "1.89"
authors = ["Noah Gift <noah@paiml.com>"]
license = "MIT"
description = "CLI tool for APR model inspection, debugging, and operations"
repository = "https://github.com/paiml/aprender"
documentation = "https://docs.rs/apr-cli"
readme = "README.md"
keywords = ["machine-learning", "model-inspection", "cli", "debugging"]
categories = ["command-line-utilities", "science"]
exclude = [
    "playbooks/snapshots/",
    "models/",
]

[lints.rust]
# Safety
unsafe_code = "deny"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] }

[lints.clippy]
# Base level
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }

# CLI-specific allows (relaxed for development velocity)
too_many_lines = "allow"
unnecessary_wraps = "allow"
uninlined_format_args = "allow"
needless_raw_string_hashes = "allow"
format_in_format_args = "allow"
cast_lossless = "allow"
cast_precision_loss = "allow"
cast_possible_truncation = "allow"
cast_possible_wrap = "allow"
cast_sign_loss = "allow"
fn_params_excessive_bools = "allow"
match_same_arms = "allow"
used_underscore_binding = "allow"
module_name_repetitions = "allow"
must_use_candidate = "allow"
doc_markdown = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
items_after_statements = "allow"
similar_names = "allow"
too_many_arguments = "allow"
struct_excessive_bools = "allow"
single_match_else = "allow"
wildcard_imports = "allow"
enum_glob_use = "allow"
unreadable_literal = "allow"
no_effect_underscore_binding = "allow"

[lib]
name = "apr_cli"
path = "src/lib.rs"

[[bin]]
name = "apr"
path = "src/main.rs"

# Task #91: dry-run scaffold for the SHIP-TWO-001 MODEL-2 corpus ingest.
# Minimal, network-free. Does not depend on any apr-cli optional feature.
[[bin]]
name = "apr-corpus-ingest"
path = "src/bin/apr-corpus-ingest.rs"

[features]
# crates.io install: minimal features (inspect, validate, lint, etc.)
# Full features enabled locally via workspace Cargo.toml default-members
default = ["hf-hub", "safetensors-compare", "inference", "training", "visualization", "zram"]
hf-hub = ["aprender/hf-hub-integration"]
# Xet CAS upload for files > 5 GiB (F-PUB-LFS-001, spec §12.8).
# Off by default: `hf-xet` adds ~4 MB to the release binary. Users who ship
# 7B+ teachers enable with `--features xet`.
xet = ["hf-hub", "aprender/xet"]
# `code` feature kept for backwards-compat but the subcommand itself is no
# longer gated — the sovereign coding assistant (`apr code` → batuta) is a
# core part of the apr-cli surface per `claude-code-parity-apr` Phase 2 plan.
# batuta is a non-optional dependency below.
code = []
dev = []  # Enable `apr mono` subcommands (publish, shims, audit, archive)
safetensors-compare = ["aprender/safetensors-compare"]
inference = ["realizar", "trueno", "tokio", "axum", "futures-util"]
cuda = ["inference", "realizar/cuda", "entrenar/cuda", "aprender-train-distill?/cuda"]
cuda-batch = ["cuda"]
# PMAT-335: WGPU backend for AMD/Intel/Apple GPU inference via Vulkan/Metal/WebGPU
wgpu = ["inference"]
visualization = ["renacer", "trueno-viz"]
zram = ["trueno-zram-core"]
training = ["dep:entrenar", "dep:entrenar-lora", "dep:aprender-train-distill", "dep:aprender-train-common", "aprender-train-distill?/shard-batch-source"]
training-gpu = ["training"]
whisper = ["whisper-apr"]
dhat-heap = ["dep:dhat"]
full = ["inference", "cuda", "cuda-batch", "visualization", "zram", "training", "training-gpu", "code", "xet"]

[target.'cfg(unix)'.dependencies]
libc = "0.2"

[dependencies]
# Core aprender library
aprender = { path = "../aprender-core", version = "0.40.1", package = "aprender-core", default-features = true, features = ["format-compression"] }

# MCP (Model Context Protocol) server — `apr mcp` subcommand
aprender-mcp = { path = "../aprender-mcp", version = "0.40.1" }
async-stream = "0.3"
provable-contracts-macros = "0.3"

# Shared formatting and system utilities (Batuta stack)
batuta-common = "0.1"

# Sovereign coding assistant (apr code → batuta agent engine) — PMAT-182.
# Non-optional since claude-code-parity-apr M150 (outcome-parity Phase 3
# requires apr code in default builds). GH-344: path dep via
# .cargo/config.toml.dev-overrides; CI uses checkout+symlink.
batuta = { workspace = true, default-features = false, features = ["agents", "agents-inference", "agents-mcp", "rag"] }

# Inference engine (workspace path dep — enables cuda/gpu feature forwarding)
# GH-573: shim (0.9.1) didn't forward cuda feature → 0.7 tok/s instead of 273 tok/s
realizar = { workspace = true, optional = true }

# Whisper speech recognition (GH-516: apr run --input audio.wav)
# Zero external deps — our own implementation in ../whisper.apr
# GH-344: path dep via .cargo/config.toml.dev-overrides when available
whisper-apr = { version = "0.2", optional = true }

# SIMD compute library (for BrickProfiler in §12.11 unified profiling)
# MUST use crates.io version to match aprender's trueno dependency
# 2026-04-05 PMAT-507: bumped 0.16.0→0.17 to match aprender root Cargo.toml (was diamond dep)
trueno = { workspace = true, optional = true }

# Async runtime for server
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal", "sync"], optional = true }

# HTTP server (for serve command with inference feature)
axum = { version = "0.7", optional = true }

# Async streams for SSE
futures-util = { version = "0.3", optional = true }

# CLI framework
clap = { version = "4.5", features = ["derive", "env", "wrap_help"] }

# Stdout suppression for qualify command
gag = "1.0"

# Output formatting
colored = "2.1"
tabled = "0.16"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10"
# HELIX-IDEA-009: constant-time SHA-256 digest comparison for `apr serve`
# bearer-token auth. See contracts/apr-serve-api-key-auth-v1.yaml gate
# FALSIFY-AUTH-003.
subtle = "2.6"
rmp-serde = "1.3"

# Error handling
thiserror = "2.0"
anyhow = { workspace = true }

# Time formatting
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }

# Human-readable sizes
humansize = "2.1"

# Temporary directories (compile command)
tempfile = "3.14"

# File/directory utilities
glob = "0.3"
dirs = "5.0"
which = "7"

# Parquet input for `apr tokenize encode-corpus` — issue #1410 follow-up.
# Stack v1.2 / codeparrot Python corpora ship as parquet, not JSONL; this
# enables `apr tokenize encode-corpus --corpus <path>.parquet` end-to-end
# without a Python shim (per `feedback_stack_tool_extension_not_cli_shim.md`).
parquet = { version = "57", default-features = false, features = ["arrow", "snap", "zstd"] }
arrow-array = "57"

# HTTP client for downloads
ureq = "2.10"

# Checksum integrity (GH-213: shard manifest checksums)
blake3 = "1"

# TUI
crossterm = "0.28"
presentar-terminal = { workspace = true }
presentar-core = { workspace = true }

# Visualization (syscall tracing and charts)
renacer = { workspace = true, optional = true }
trueno-viz = { version = "0.3", optional = true }  # Not yet in monorepo

# ZRAM compression (SIMD-accelerated LZ4/ZSTD)
trueno-zram-core = { version = "0.3", optional = true }

# Model registry and caching (Ollama-like model management)
pacha = { version = "0.2.4", default-features = false, features = ["remote"] }

# PTX analysis and bug detection (trueno-explain: PtxAnalyzer + PtxBugAnalyzer)
trueno-explain = { version = "0.2.2", optional = true }

# ML tuning: LoRA/QLoRA configuration and memory planning (GH-176, PMAT-184)
entrenar-lora = { workspace = true, optional = true }
# ML training engine (workspace path dep — enables cuda feature forwarding)
entrenar = { workspace = true, optional = true }
# Distillation pipeline (SPEC-SHIP-TWO-001 §35 wire-up — replaces stub run_config_train)
aprender-train-distill = { workspace = true, optional = true }
# Distillation error types (PMAT-701 Bug B: needed for RealizarQ4KTeacher impl)
aprender-train-common = { workspace = true, optional = true }
# Heap profiling (opt-in via --features dhat-heap)
dhat = { version = "0.3", optional = true }
# Data loading, splitting, imbalance detection (apr data subcommands)
# GH-344: path dep via .cargo/config.toml.dev-overrides; CI uses checkout+symlink
alimentar = { version = "0.2.8", default-features = false, features = ["shuffle"] }
half = "2.4.1"
# YAML config parsing (distillation configs, ALB-011)
serde_yaml = { package = "serde_yaml_ng", version = "0.10" }

# Unicode normalization (NFC) for BPE corpus preprocessing (MODEL-2).
unicode-normalization = "0.1"

# CRUX-B-05 + CRUX-B-20 — shard/unshard + diff --quant-roundtrip both use safetensors.
safetensors = { workspace = true }

# Parallelism — used by `apr tokenize encode-corpus --num-workers` (issue #1547).
# Per-doc BPE encoding is independent across rows; rayon's chunked par_iter
# preserves input order via Vec<Result<...>> indexed by chunk position.
rayon = { workspace = true }

[[example]]
name = "serve_with_tracing"
required-features = ["inference"]

[[example]]
name = "gpu_chat_inference"
required-features = ["inference", "cuda"]

[[example]]
name = "ptx_parity_validation"
required-features = ["inference"]

[dev-dependencies]
assert_cmd = "2.0"
predicates = "3.1"
tempfile = "3.14"
proptest = "1.6"
jugar-probar = { version = "0.4", features = ["tui"] }
regex = "1.10"
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"] }
axum-test = "16"
tower = "0.5"
# FALSIFY-SHIP-012 — NFC normalization for tokenizer round-trip harness
unicode-normalization = "0.1"
# FALSIFY-APR-DISTILL-TRAIN-001 — SafeTensors fixture for §35 wire-up integration test
safetensors = "0.4"
bytemuck = { version = "1.24", features = ["derive"] }

