[package]
name = "duckduckgo-search-cli"
version = "0.7.3"
edition = "2021"
rust-version = "1.88"
license = "MIT OR Apache-2.0"
description = "CLI in Rust to search DuckDuckGo via pure HTTP, with structured output for LLM consumption."
authors = ["comandoaguiar"]
readme = "README.md"
keywords = ["search", "duckduckgo", "cli", "ai-agent", "llm"]
categories = ["command-line-utilities", "web-programming"]
repository = "https://github.com/daniloaguiarbr/duckduckgo-search-cli"
homepage = "https://github.com/daniloaguiarbr/duckduckgo-search-cli"
documentation = "https://docs.rs/duckduckgo-search-cli"
default-run = "duckduckgo-search-cli"
exclude = [
    ".serena/",
    ".serena/**",
    "logs/",
    "logs/**",
    "CLAUDE.md",
    "docs_prd/",
    "docs_prd/**",
    "docs_rules/",
    "docs_rules/**",
    ".claude/",
    ".claude/**",
    "projeto_duckduckgo-search-cli.md",
    ".github/",
    "tests/fixtures/",
    "*.log",
    "skill/",
    "skill/**",
    "graphrag.sqlite",
    "graphrag.sqlite-shm",
    "graphrag.sqlite-wal",
    "gaps.md",
    ".ingest-queue.sqlite",
]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[[bin]]
name = "duckduckgo-search-cli"
path = "src/main.rs"

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

[[bench]]
name = "extraction_bench"
harness = false

[dependencies]
# Async runtime — Tokio multi-threaded with full features (signal, macros, rt-multi-thread, fs, io-util, etc.)
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time", "sync", "signal", "io-util", "fs"] }
tokio-util = { version = "0.7", features = ["rt"] }

# HTTP client — wreq 6 (BoringSSL via boring2).
# v0.7.3 transition: replaced reqwest+rustls with wreq to obtain a real
# browser TLS fingerprint (JA4_o compatible with Chrome/Safari). BoringSSL
# is statically linked; build requires cmake, perl, pkg-config, libclang-dev.
# See docs/decisions/0001-tls-boring-via-wreq.md for the architectural
# decision and ADR-0001 for trade-offs.
# "cookies" pulls the cookie_store crate for in-memory cookie persistence.
# "socks" feature keeps --proxy socks5://... working via tokio-socks.
# "gzip" + "brotli" + "deflate" + "zstd" enable automatic response decompression.
wreq = { version = "6.0.0-rc", default-features = false, features = [
    "tokio-rt",
    "webpki-roots",
    "cookies",
    "gzip",
    "brotli",
    "deflate",
    "zstd",
    "socks",
    "form",
    "query",
] }
wreq-util = "3.0.0-rc"

# HTML parsing — scraper uses html5ever from Servo, tolerant of malformed HTML.
scraper = "0.20"

# CLI — clap derive for declarative parsing.
clap = { version = "4", features = ["derive"] }
clap_complete = "4"

# Serialization — serde + serde_json for JSON, toml for configuration files.
serde = { version = "1", features = ["derive"] }
serde_json = "1"
toml = "0.8"

# URL encoding/decoding (to unwrap DuckDuckGo /l/?uddg= redirects).
urlencoding = "2"

# Error handling — thiserror for typed CliError enum across all library modules.
thiserror = "2"

# Logging — tracing + tracing-subscriber with env-filter for RUST_LOG.
tracing = { version = "0.1", features = ["release_max_level_info"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

# Random User-Agent selection.
# Upgraded to 0.10 in v0.7.1: dev-deps like proptest 1.11+ require rand 0.9, and
# the ecosystem is migrating to 0.10+ for the new APIs (random_range, random_bool,
# IndexedRandom::choose). Code uses 0.10 APIs throughout (methods live in RngExt).
rand = "0.10"

# Pinned in v0.7.1 to >=0.3.47 to resolve RUSTSEC-2026-0009 (denial-of-service
# via stack exhaustion when parsing RFC 2822 date headers). The previous 0.3.40
# was pulled transitively by cookie_store 0.22.0 -> reqwest 0.12.28 in v0.7.0.
# v0.7.3 removed reqwest but the pin remains to ensure no transitive dep drags
# in a vulnerable 0.3.40 via another path. Bumped MSRV to 1.88 because time
# 0.3.47+ requires it.
time = "0.3.47"

# WS-25: ProgressBar for long crawls (--fetch-content --parallel).
# TTY detection is automatic — bars are silently hidden in pipes.
indicatif = "0.18"

# RFC 3339 timestamps for JSON metadata.
chrono = { version = "0.4", features = ["serde"] }

# XDG cross-platform for configuration directories.
dirs = "5"

# Hashing for selectors_hash in metadata.
blake3 = "1"

# URL canonicalization for deep-research dedup (gap 2.3 of v0.7.0 audit).
url = "2"

# Regex for query decomposition templates in deep-research (heuristic fan-out).
regex = "1"

# Encoding detection for non-UTF-8 pages (only used in fetch-content in upcoming iterations;
# declared now because the specification lists it as an MVP dependency).
encoding_rs = "0.8"

# Optional dependencies for the chrome feature (NOT compiled in MVP — only declared for the next iteration).
# The "fetcher" feature of chromiumoxide requires the companion crate chromiumoxide_fetcher which currently
# has an import bug in 0.7.0; therefore we only enable "tokio-runtime" here. The Chromium auto-download
# functionality can be added via an explicit dependency when implementing fetch-content in iteration 5.
chromiumoxide = { version = "0.7", features = ["tokio-runtime"], optional = true }
tempfile = { version = "3", optional = true }
futures = { version = "0.3", optional = true }

# Optional: tokio-console for runtime task debugging.
console-subscriber = { version = "0.4", optional = true }

# Windows-conditional — SetConsoleOutputCP for UTF-8 in cmd.exe and legacy PowerShell console.
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59", features = ["Win32_System_Console"] }

[dev-dependencies]
# Performance benchmarks — criterion for statistically valid measurements.
criterion = { version = "0.5", features = ["html_reports"] }

# Mock HTTP server for integration tests without real network calls.
# Chosen in 2026-04 per trustScore 9.3 on context7; compatible with tokio runtime.
wiremock = "0.6"
# E2E tests of the compiled binary via assert_cmd + predicates (section 20.2 of rules_rust.md).
assert_cmd = "2"
predicates = "3"
# Property-based tests for deep-research decomposition templates (gap 3.7 of v0.7.0 audit).
proptest = "1"
# TempDir for E2E tests (even without chrome feature).
tempfile = "3"

# Loom for concurrency interleaving tests (AtomicBool rate-limit flag).
# NOTE: loom does NOT support tokio::sync::Semaphore — only std primitives.
# Run with: RUSTFLAGS="--cfg loom" cargo test --test loom_atomics --release
[target.'cfg(loom)'.dev-dependencies]
loom = "0.7"

[features]
default = []
# Chrome feature gate — enables headless Chrome fallback for --fetch-content in future iterations.
chrome = ["chromiumoxide", "tempfile", "futures"]
# Enable tokio-console for runtime task debugging during development.
# Run with: cargo run --features console
console = ["dep:console-subscriber"]

[lints.rust]
improper_ctypes = "deny"
improper_ctypes_definitions = "deny"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(loom)', 'cfg(tokio_unstable)'] }

[lints.clippy]
doc_markdown = "warn"
missing_errors_doc = "warn"
missing_panics_doc = "warn"
missing_safety_doc = "deny"

[badges.maintenance]
status = "actively-developed"

[profile.release]
opt-level = 3
lto = true
codegen-units = 1
strip = "symbols"
panic = "abort"

[profile.dev.package."*"]
opt-level = 2
