[package]
name = "llmlint"
version = "0.3.6"
edition = "2021"
rust-version = "1.85"
description = "LLM-as-judge linter: enforce code-quality checks deterministic linters can't express, by driving real coding harnesses through oneharness."
license = "MIT"
repository = "https://github.com/nickderobertis/llmlint"
homepage = "https://github.com/nickderobertis/llmlint"
readme = "README.md"
keywords = ["cli", "linter", "llm", "code-review", "oneharness"]
categories = ["command-line-utilities", "development-tools"]
# Package only what a crates.io consumer needs: the sources, manifest, readme,
# license, and the `assets/` embedded via `include_str!`. This keeps the
# published crate small and excludes the CLAUDE.md/AGENTS.md symlink (crates.io
# rejects symlinks), CI config, scripts, and the e2e tests + mock-oneharness
# fixture — a feature-gated, test-only bin that never builds in a default
# `cargo install`/`cargo publish`.
include = [
    "src/**/*.rs",
    "Cargo.toml",
    "README.md",
    "LICENSE",
    "assets/*",
]

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

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

# Test-only fixture: a fake `oneharness` the e2e tests drive via the
# `--oneharness-bin` override, so the spawn/parse/vote path is proven
# hermetically and cross-platform. Gated behind a feature so it never ships in
# `cargo install`.
[[bin]]
name = "llmlint-mock-oneharness"
path = "tests/support/mock_oneharness.rs"
required-features = ["mock-oneharness"]

[features]
# Builds the mock-oneharness fixture. Enabled by `just test`/`just check` and CI.
mock-oneharness = []

[dependencies]
clap = { version = "4.6", features = ["derive"] }
# ANSI styling for the human report (red FAIL / green PASS). Tiny and dependency-
# free — already in the tree via clap — so it adds color without growing the
# `cargo deny` surface. Pure style definitions; the TTY/`NO_COLOR`/`--color`
# decision lives in the command layer, not here.
anstyle = "1"
# The platform-correct sink for the colored report. `AutoStream` passes ANSI
# straight through on a VT-capable terminal but, on a *legacy* Windows console
# (no virtual-terminal processing), enables VT or translates the SGR codes into
# Win32 console attribute calls (`anstyle-wincon`) — so the colors render instead
# of printing as raw `←[31m` escapes. Already in the tree via clap (with its
# `wincon` default feature), so it adds no new `cargo deny` surface; the command
# layer still owns the `--color`/`NO_COLOR`/TTY decision and hands this a concrete
# on/off choice.
anstream = "1"
# The ephemeral live-progress view (rules resolving as judges return), drawn to
# stderr for an interactive human. indicatif self-hides on a non-terminal — piping
# to a file or CI produces no escape-code spam — which is exactly the "don't
# corrupt captured output" property this view needs; the command layer owns the
# `--progress`/agent/CI decision and hands it a concrete draw target. Default
# features only (its `console` backend handles Windows VT/legacy consoles too).
indicatif = "0.17"
serde = { version = "1", features = ["derive"] }
# `preserve_order` keeps JSON object keys in insertion order, so the structured-
# output schema can present each rule's fields in the exact order the judge
# should emit them (name -> rationale -> result). Used everywhere we hand-build
# JSON (schema, report) and round-trip configs.
serde_json = { version = "1", features = ["preserve_order"] }
serde_yaml_ng = "0.10"
minijinja = "2"
ignore = "0.4"
globset = "0.4"
thiserror = "2"
wait-timeout = "0.2"
tempfile = "3"
# HTTPS client for fetching remote `plugins` URLs. Pure Rust (rustls) so the
# binary stays self-contained and cross-platform with no external tools (no
# `curl`) and no system TLS/OpenSSL link. Minimal features: the rustls backend
# with bundled Mozilla roots — no gzip/json/cookies/charset.
ureq = { version = "3", default-features = false, features = ["rustls", "rustls-webpki-roots"] }
# Derives the public config JSON Schema (`assets/llmlint.schema.json`) straight
# from the `Config` model, so the schema referenced by `llmlint init` can never
# drift from the Rust types. Default features only (derive + std); emits 2020-12.
schemars = "1"

[dev-dependencies]
assert_cmd = "2"
predicates = "3"
# Enable indicatif's `in_memory` feature in test builds only: it provides
# `InMemoryTerm` (a `vt100`-backed terminal emulator) so the progress renderer is
# asserted on the *rendered screen grid* — deterministically, cross-platform, with
# no real TTY. Feature-unified into the normal `indicatif` dep for test/bench
# builds; `cargo build`/`cargo install` never pulls it.
indicatif = { version = "0.17", features = ["in_memory"] }
# Statistical micro-benchmarks of the pure engine (see `benches/`). Default
# features (plotters HTML reports, rayon) are dropped to keep the dependency
# tree — and the `cargo deny` surface — small; `cargo_bench_support` is the only
# feature `cargo bench` needs, and it still emits the per-bench `estimates.json`
# that `critcmp` diffs.
criterion = { version = "0.5", default-features = false, features = ["cargo_bench_support"] }

[[test]]
name = "e2e"
path = "tests/e2e/main.rs"

# Statistical micro-benchmarks of the pure engine hot paths (config parse, plan,
# template render, schema, vote, report). `harness = false` hands `main` to
# Criterion instead of libtest, so `cargo nextest`/coverage never pick it up —
# it is measured, not gated. `cargo clippy --all-targets` still type-checks it,
# so it cannot rot.
[[bench]]
name = "engine"
harness = false

# Deterministic allocation tallies for the same hot paths: a plain `main` with a
# counting global allocator, no Criterion. Exact counts compare across runs and
# commits without statistics; informational like every bench target.
[[bench]]
name = "engine_allocs"
harness = false

# A CLI binary: optimize for a small, fast-starting artifact.
[profile.release]
strip = true
lto = "thin"
codegen-units = 1

# Profiling builds: the shipped release artifact exactly, but with symbols kept
# so `samply` (see `scripts/profile.sh`) can attribute time to functions, and
# `cachegrind`/`callgrind` (see `scripts/bench-instructions.sh`) can be annotated
# afterwards. Never affects the published binary — `just profile` builds
# `--profile profiling` into `target/profiling/` while `[profile.release]` stays
# stripped.
[profile.profiling]
inherits = "release"
debug = true
strip = false
