[workspace]
members = ["cqs-macros"]

[package]
name = "cqs"
version = "1.51.0"
edition = "2021"
rust-version = "1.96"
description = "Code intelligence and RAG for AI agents. Semantic search, call graphs, impact analysis, type dependencies, and smart context assembly — in single tool calls. 54 languages + L5X/L5K PLC exports. 70.7% R@5 / 47.2% R@1 / 86.7% R@20 on v3.v2 dual-judge code-search (218 queries, EmbeddingGemma-300m default with per-category SPLADE α; 2026-06-26 snapshot, scoring unchanged through v1.51.0). Daemon mode (3-19ms queries). MCP server (`cqs mcp`, 30 read tools). Local-first, GPU-accelerated."
license = "MIT"
repository = "https://github.com/jamie8johnson/cqs"
homepage = "https://github.com/jamie8johnson/cqs"
readme = "README.md"
keywords = ["code-intelligence", "rag", "code-search", "call-graph", "embeddings"]
categories = ["command-line-utilities", "development-tools"]
exclude = [
    ".claude/",
    ".githooks/",
    "CLAUDE.md",
    "PROJECT_CONTINUITY.md",
    "ROADMAP.md",
    "docs/AUDIT_*",
    "docs/DESIGN_SPEC_*",
    "docs/notes.toml",
    # Eval datasets, internal tools, and vendored forks live in the repo
    # for development and CI but are not user-facing crate content. v1.27.0
    # added v3 eval JSON (~136MB total) which pushed the package past
    # crates.io's 10MB compressed limit.
    "evals/",
    "samples/",
    "tools/",
]

[lints.rust]
# `cqs_loom` is the private cfg that gates the loom concurrency models (set via
# `RUSTFLAGS="--cfg cqs_loom"`). A private name (not the bare `loom` cfg loom's
# docs suggest) keeps the flag off the dependency graph; declaring it here keeps
# `--all-targets` clippy clean instead of warning `unexpected cfg condition name`.
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(cqs_loom)'] }

[dependencies]
# CLI
clap = { version = "4", features = ["derive", "env"] }
clap_complete = "4"

# #1366: per-variant CLI command registration via #[derive(CqsCommands)].
# Workspace-local proc-macro, not published.
cqs-macros = { path = "cqs-macros", version = "0.1.1" }

# Parsing (tree-sitter) - core is required, grammars are optional
tree-sitter = "0.26"
tree-sitter-rust = { version = "0.24", optional = true }
tree-sitter-python = { version = "0.25", optional = true }
tree-sitter-typescript = { version = "0.23", optional = true }
tree-sitter-javascript = { version = "0.25", optional = true }
tree-sitter-go = { version = "0.25", optional = true }
tree-sitter-c = { version = "0.24", optional = true }
tree-sitter-cpp = { version = "0.23", optional = true }
tree-sitter-java = { version = "0.23", optional = true }
tree-sitter-c-sharp = { version = "0.23", optional = true }
tree-sitter-fsharp = { version = "0.3", optional = true }
tree-sitter-powershell = { version = "0.26", optional = true }
tree-sitter-scala = { version = "0.26", optional = true }
tree-sitter-ruby = { version = "0.23", optional = true }
tree-sitter-bash = { version = "0.25", optional = true }
tree-sitter-hcl = { version = "1.1", optional = true }
tree-sitter-kotlin = { version = "1.1", package = "tree-sitter-kotlin-ng", optional = true }
tree-sitter-swift = { version = "0.7", optional = true }
tree-sitter-objc = { version = "3.0", optional = true }
tree-sitter-sql = { version = "0.4", package = "tree-sitter-sequel-tsql", optional = true }
tree-sitter-proto = { version = "0.4", optional = true }
tree-sitter-graphql = { version = "0.1", optional = true }
tree-sitter-php = { version = "0.24", optional = true }
tree-sitter-lua = { version = "0.5", optional = true }
tree-sitter-zig = { version = "1.1", optional = true }
tree-sitter-r = { version = "1.2", optional = true }
tree-sitter-yaml = { version = "0.7", optional = true }
tree-sitter-toml = { version = "0.7", package = "tree-sitter-toml-ng", optional = true }
tree-sitter-elixir = { version = "0.3", optional = true }
tree-sitter-erlang = { version = "0.19", optional = true }
tree-sitter-haskell = { version = "0.23", optional = true }
# tree-sitter-clojure blocked: 0.1.0 requires tree-sitter ^0.25, incompatible with 0.26
tree-sitter-ocaml = { version = "0.25", optional = true }
tree-sitter-julia = { version = "0.23", optional = true }
tree-sitter-gleam = { version = "1.0", optional = true }
tree-sitter-css = { version = "0.25", optional = true }
tree-sitter-perl = { version = "1.1", optional = true }
tree-sitter-html = { version = "0.23", optional = true }
tree-sitter-json = { version = "0.24", optional = true }
tree-sitter-xml = { version = "0.7", optional = true }
tree-sitter-ini = { version = "1.4", optional = true }
tree-sitter-nix = { version = "0.3", optional = true }
tree-sitter-make = { version = "1.1", optional = true }
tree-sitter-latex = { version = "0.6", package = "codebook-tree-sitter-latex", optional = true }
tree-sitter-solidity = { version = "1.2", optional = true }
tree-sitter-cuda = { version = "0.21", optional = true }
tree-sitter-glsl = { version = "0.2", optional = true }
tree-sitter-svelte = { version = "0.1", package = "tree-sitter-svelte-next", optional = true }
tree-sitter-razor = { version = "0.1", optional = true }
tree-sitter-vb-dotnet = { version = "0.1", optional = true }
tree-sitter-vue = { version = "0.1", package = "tree-sitter-vue-next", optional = true }
tree-sitter-structured-text = { version = "0.1", optional = true }
tree-sitter-dart = { version = "0.1", optional = true }

# ML (CUDA/TensorRT added for non-macOS targets below)
# `half` feature gates ort's f16 / bf16 tensor-extraction support; cqs uses
# it to consume FP16 ONNX exports (e.g. zhiqing/Qwen3-Embedding-4B-ONNX)
# whose `last_hidden_state` is `Tensor<f16>`. The embed loop converts to f32
# in software after extract — see `src/embedder/mod.rs` extraction site.
# `half` is a direct dep too because ort doesn't re-export the type.
ort = { version = "2.0.0-rc.12", features = ["half"] }
half = "2"
tokenizers = { version = "0.23", features = ["http"] }
hf-hub = "0.4.3"
ndarray = "0.17"
# cuVS requires ndarray 0.15, import separately for gpu-index
ndarray_015 = { package = "ndarray", version = "0.15", optional = true }

# Async
tokio = { version = "1", features = ["rt-multi-thread", "time", "signal"] }

# HTTP server (cqs serve — graph visualization UI, optional via `serve` feature).
# Kept behind a feature so the dep doesn't bloat default builds.
axum = { version = "0.8", default-features = false, features = ["http1", "query", "tokio", "json", "macros"], optional = true }
tower = { version = "0.5", optional = true }
tower-http = { version = "0.7", features = ["trace", "compression-gzip", "limit"], optional = true }
# #1096: per-launch auth token. `subtle` for timing-safe compare against the
# bearer/cookie value; `base64` for URL-safe encoding of the random token.
# Both are feature-gated under `serve` (see [features] below).
subtle = { version = "2", optional = true }
base64 = { version = "0.22", optional = true }

# Storage (sqlx async SQLite)
sqlx = { version = "0.9", default-features = false, features = ["runtime-tokio", "sqlite"] }

# Vector search (HNSW default, cuVS optional)
hnsw_rs = "0.3"
simsimd = "6"
cuvs = { version = "=26.6", optional = true }  # pinned — strict version coupling with conda libcuvs

# Text processing
regex = "1"
aho-corasick = "1"

# Serialization
serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1"
toml = "1.1"
# JSON Schema generation for command-core input structs (the MCP inputSchema
# source). Additive only — no schema-gen logic or server yet.
schemars = "1"

# Path canonicalization (strips Windows UNC \\?\ prefixes)
dunce = "1"

# Memory-mapped reads for the persisted SPLADE index body (avoids the
# ~59MB+ transient heap copy from read_to_end on warm loads).
memmap2 = "0.9"

# Utilities
blake3 = "1"
bytemuck = { version = "1", features = ["derive"] }
ignore = "0.4"
notify = { version = "8", features = ["serde"] }
ctrlc = { version = "3", features = ["termination"] }
rayon = "1"
crossbeam-channel = "0.5"
chrono = "0.4"
globset = "0.4"
colored = "3"
indicatif = "0.18"
shell-words = "1"
anyhow = "1"
thiserror = "2"
dirs = "6"
log = "0.4"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
rand = "0.10"
lru = "0.18"
once_cell = "1"
tempfile = "3"
similar = "3"
# Percent-decoding query keys in serve auth (P1.3 / SEC-7 redirect path).
percent-encoding = "2"

# Document conversion (optional)
fast_html2md = { version = "0.0", optional = true }
walkdir = { version = "2", optional = true }
self_cell = "1"
rustyline = "18"

# LLM summaries (optional — for SQ-6 API calls to Claude)
reqwest = { version = "0.13", features = ["json", "blocking"], optional = true }
# uuid v4 for LocalProvider batch IDs (feature-gated with llm-summaries to keep dep tree lean)
uuid = { version = "1", features = ["v4"], optional = true }
tree-sitter-elm = { version = "5.9.0", optional = true }

# libc is used on unix for filesystem stat / umask / fd primitives, and on
# Windows for the POSIX-style fd redirect that suppresses hnsw_rs's stdout leak
# (the Windows libc bindings map open/dup/dup2/close onto the MSVCRT lowio layer).
[target.'cfg(any(unix, windows))'.dependencies]
libc = "0.2"

# CUDA/TensorRT only available on Linux and Windows (no prebuilt binaries for macOS)
[target.'cfg(not(target_os = "macos"))'.dependencies]
ort = { version = "2.0.0-rc.12", features = ["cuda", "tensorrt", "half"] }

[features]
default = ["lang-rust", "lang-python", "lang-typescript", "lang-javascript", "lang-go", "lang-c", "lang-cpp", "lang-java", "lang-csharp", "lang-fsharp", "lang-powershell", "lang-scala", "lang-ruby", "lang-bash", "lang-hcl", "lang-kotlin", "lang-swift", "lang-objc", "lang-sql", "lang-protobuf", "lang-graphql", "lang-php", "lang-lua", "lang-zig", "lang-r", "lang-yaml", "lang-toml", "lang-elixir", "lang-elm", "lang-erlang", "lang-haskell", "lang-ocaml", "lang-julia", "lang-gleam", "lang-css", "lang-perl", "lang-html", "lang-json", "lang-xml", "lang-ini", "lang-nix", "lang-make", "lang-latex", "lang-solidity", "lang-cuda", "lang-glsl", "lang-svelte", "lang-razor", "lang-vbnet", "lang-vue", "lang-markdown", "lang-aspx", "lang-st", "lang-l5x", "lang-dart", "convert", "llm-summaries", "serve"]

# Language support (opt-in, all enabled by default)
lang-rust = ["dep:tree-sitter-rust"]
lang-python = ["dep:tree-sitter-python"]
lang-typescript = ["dep:tree-sitter-typescript"]
lang-javascript = ["dep:tree-sitter-javascript"]
lang-go = ["dep:tree-sitter-go"]
lang-c = ["dep:tree-sitter-c"]
lang-cpp = ["dep:tree-sitter-cpp"]
lang-java = ["dep:tree-sitter-java"]
lang-csharp = ["dep:tree-sitter-c-sharp"]
lang-fsharp = ["dep:tree-sitter-fsharp"]
lang-powershell = ["dep:tree-sitter-powershell"]
lang-scala = ["dep:tree-sitter-scala"]
lang-ruby = ["dep:tree-sitter-ruby"]
lang-bash = ["dep:tree-sitter-bash"]
lang-hcl = ["dep:tree-sitter-hcl"]
lang-kotlin = ["dep:tree-sitter-kotlin"]
lang-swift = ["dep:tree-sitter-swift"]
lang-objc = ["dep:tree-sitter-objc"]
lang-sql = ["dep:tree-sitter-sql"]
lang-protobuf = ["dep:tree-sitter-proto"]
lang-graphql = ["dep:tree-sitter-graphql"]
lang-php = ["dep:tree-sitter-php"]
lang-lua = ["dep:tree-sitter-lua"]
lang-zig = ["dep:tree-sitter-zig"]
lang-r = ["dep:tree-sitter-r"]
lang-yaml = ["dep:tree-sitter-yaml"]
lang-toml = ["dep:tree-sitter-toml"]
lang-elixir = ["dep:tree-sitter-elixir"]
lang-elm = ["dep:tree-sitter-elm"]
lang-erlang = ["dep:tree-sitter-erlang"]
lang-haskell = ["dep:tree-sitter-haskell"]
lang-ocaml = ["dep:tree-sitter-ocaml"]
lang-julia = ["dep:tree-sitter-julia"]
lang-gleam = ["dep:tree-sitter-gleam"]
lang-css = ["dep:tree-sitter-css"]
lang-perl = ["dep:tree-sitter-perl"]
lang-html = ["dep:tree-sitter-html"]
lang-json = ["dep:tree-sitter-json"]
lang-xml = ["dep:tree-sitter-xml"]
lang-ini = ["dep:tree-sitter-ini"]
lang-nix = ["dep:tree-sitter-nix"]
lang-make = ["dep:tree-sitter-make"]
lang-latex = ["dep:tree-sitter-latex"]
lang-solidity = ["dep:tree-sitter-solidity"]
lang-cuda = ["dep:tree-sitter-cuda"]
lang-glsl = ["dep:tree-sitter-glsl"]
lang-svelte = ["dep:tree-sitter-svelte"]
lang-razor = ["dep:tree-sitter-razor"]
lang-vbnet = ["dep:tree-sitter-vb-dotnet"]
lang-vue = ["dep:tree-sitter-vue"]
lang-markdown = []  # No external deps — custom parser
lang-aspx = ["lang-csharp", "lang-vbnet"]  # Delegates to C#/VB.NET grammars
lang-st = ["dep:tree-sitter-structured-text"]
lang-l5x = ["lang-st"]  # Rockwell PLC exports — delegates to the ST grammar
lang-dart = ["dep:tree-sitter-dart"]
lang-all = ["lang-rust", "lang-python", "lang-typescript", "lang-javascript", "lang-go", "lang-c", "lang-cpp", "lang-java", "lang-csharp", "lang-fsharp", "lang-powershell", "lang-scala", "lang-ruby", "lang-bash", "lang-hcl", "lang-kotlin", "lang-swift", "lang-objc", "lang-sql", "lang-protobuf", "lang-graphql", "lang-php", "lang-lua", "lang-zig", "lang-r", "lang-yaml", "lang-toml", "lang-elixir", "lang-elm", "lang-erlang", "lang-haskell", "lang-ocaml", "lang-julia", "lang-gleam", "lang-css", "lang-perl", "lang-html", "lang-json", "lang-xml", "lang-ini", "lang-nix", "lang-make", "lang-latex", "lang-solidity", "lang-cuda", "lang-glsl", "lang-svelte", "lang-razor", "lang-vbnet", "lang-vue", "lang-markdown", "lang-aspx", "lang-st", "lang-l5x", "lang-dart"]

# Document conversion
convert = ["dep:fast_html2md", "dep:walkdir"]

# Other features
# (encrypt feature deleted — sqlx doesn't expose a SQLCipher backend, the
# feature had zero `cfg(feature = "encrypt")` callers, and the only dep it
# pulled in (`keyring`) had no consuming code. Revisit encryption strategy
# if and when sqlx grows a SQLCipher driver.)

# CAGRA (cuVS) ANN backend — CUDA-only. Issue #956 (Phase A): renamed
# from `gpu-index` to make the CUDA-specificity explicit. The legacy
# `gpu-index` name is preserved as an alias so existing build scripts
# and CLAUDE.md instructions keep working; new code should use
# `cuda-index` directly.
cuda-index = ["cuvs", "ndarray_015"]
gpu-index = ["cuda-index"]

# Tiered ANN backend (cuVS tiered index) — opt-in, behind a fork pin.
# `cuvs::tiered_index` exists only on our fork branch (cqs-tiered-26.6, pinned
# via the workspace `[patch.crates-io]` below). Requires `cuda-index`. NOT
# enabled by default and NOT implied by `cuda-index`: a plain `cuda-index`
# build never references the tiered module, so a published crates.io build
# (where `[patch]` is stripped) compiles against official cuvs 26.6 with no
# tiered symbols required. Enabling this feature requires the patched cuvs.
# Retirement: drop this feature + the patch once rapidsai/cuvs#2235 merges and
# the tiered bindings ship in an official cuvs release (the #1679 playbook).
tiered-index = ["cuda-index"]

# Issue #956 Phase B/C scaffolding: ExecutionProvider variants for
# Apple CoreML and AMD ROCm. The features only enable the variant in
# the enum and the matching probe arm in `detect_provider()`; wiring
# the actual ORT provider features (which require target-conditional
# `ort` deps) is deferred to Phase B (CoreML, GHA macOS runner) and
# Phase C (ROCm, AMD hardware).
ep-coreml = []
ep-rocm = []

llm-summaries = ["dep:reqwest", "dep:uuid"]
tree-sitter-elm = ["dep:tree-sitter-elm"]

# `cqs serve` — graph visualization web UI. Adds axum + tower + tower-http.
# Bundled separately so the default binary stays lean for users who only
# need the CLI.
serve = ["dep:axum", "dep:tower", "dep:tower-http", "dep:subtle", "dep:base64"]

# Slow integration tests excluded from PR-time CI. Two reasons a binary
# lands here:
#   (a) Subprocess-spawning CLI tests that cold-load the embedder per
#       invocation. Originally 16 such binaries; 5 were migrated to the
#       in-process `InProcessFixture` harness on 2026-04-23 and the old
#       `.github/workflows/slow-tests.yml` cron was deleted alongside.
#       11 still gated: cli_blame_test, cli_brief_test,
#       cli_chat_completer_test, cli_chat_format_test, cli_doctor_fix_test,
#       cli_drift_diff_test, cli_envelope_test, cli_neighbors_test,
#       cli_reconstruct_test, cli_review_test, cli_train_review_test.
#       Tracked as follow-up to #980; convert when re-touching the code
#       they test. See docs/plans/2026-04-22-cqs-slow-tests-elimination.md
#       for the conversion pattern.
#   (b) End-to-end binaries with high per-test cost. Added 2026-05-02
#       under #1286 Phase 2: `onboard_test` (~6.6 min, full index pipeline
#       per test) and `eval_subcommand_test` (~5.3 min, `cqs eval` subprocess
#       per test). Together these were 12 min / 35% of regular-CI test time
#       (CI workflow `25227697806`).
# Run nightly via `.github/workflows/ci-slow.yml` (`slow-tests-feature` job).
# Locally: `cargo test --features slow-tests`.
slow-tests = []

[dev-dependencies]
insta = "1"
proptest = "1"
assert_cmd = "2"
predicates = "3"
serial_test = "3"
# Mock HTTP server for LocalProvider unit + integration tests (OpenAI-compat).
# Used only under `cfg(test)` behind the `llm-summaries` feature.
httpmock = "0.8"

# Permutation/model checker for the concurrency models (#1826 interleaving-auditor).
# Pulled in ONLY under our private `--cfg cqs_loom` so a normal build/test never
# compiles it; the loom models live in `*_interleaving_model.rs` modules (each
# `#![cfg(cqs_loom)]`-gated). A PRIVATE cfg name (not the bare `loom` loom docs
# suggest) is deliberate: the bare `loom` cfg propagates through RUSTFLAGS to the
# whole dependency graph and breaks crates with their own `cfg(loom)` paths
# (concurrent-queue). Run:
#   RUSTFLAGS="--cfg cqs_loom" cargo test --features cuda-index --bin cqs reconcile_interleaving_model
[target.'cfg(cqs_loom)'.dev-dependencies]
loom = "0.7"

[profile.release]
lto = "thin"
codegen-units = 1
panic = "abort"
strip = true

# ── Tiered-index fork pin (opt-in) ───────────────────────────────────────────
# The `tiered-index` feature needs `cuvs::tiered_index`, which exists ONLY on
# our fork branch `cqs-tiered-26.6` (jamie8johnson/cuvs), pinned to crate
# version 26.6.0 so this `[patch.crates-io]` is version-compatible with the
# official `cuvs = "=26.6"` it replaces.
#
# It is intentionally COMMENTED OUT so that:
#   * a plain `--features cuda-index` build (and every crates.io consumer, who
#     never sees `[patch]` anyway) resolves the OFFICIAL cuvs 26.6 — the
#     tiered module is `#[cfg(feature = "tiered-index")]`-gated and absent, so
#     no tiered symbols are required (the HARD RAIL).
#   * `--features tiered-index` builds work once you uncomment the two lines
#     below (the fork supplies `cuvs::tiered_index`).
#
# Fork branch SHA: see CONTRIBUTING.md "Tiered-index fork pin". Retire this
# block when rapidsai/cuvs#2235 lands in an official release (#1679 playbook).
#
# [patch.crates-io]
# cuvs = { git = "https://github.com/jamie8johnson/cuvs.git", branch = "cqs-tiered-26.6" }
