[workspace]
members = [".", "crates/robot-kit", "crates/aardvark-sys", "apps/tauri"]
resolver = "2"

# ── cargo-dist ──────────────────────────────────────────────────────
# Generates cross-platform install shims (curl | sh, irm | iex) and a
# prebuilt-binary release matrix on tag push. The `dist` profile below
# is what cargo-dist ships.
#
# Bootstrap locally with `cargo install cargo-dist && cargo dist init`
# to generate the GitHub Actions release workflow. That run will add
# .github/workflows/release.yml — review before committing.
[workspace.metadata.dist]
cargo-dist-version = "0.22.1"
ci = "github"
installers = ["shell", "powershell"]
tap = "KumihoIO/homebrew-construct"
formula = "construct"
targets = [
    "x86_64-unknown-linux-gnu",
    "aarch64-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "aarch64-apple-darwin",
    "x86_64-pc-windows-msvc",
    "aarch64-pc-windows-msvc",
]
pr-run-mode = "plan"
install-updater = true

[patch.crates-io]
# Security backports for transitive desktop build dependencies until upstream
# releases patched compatible versions for the Tauri 2.x stack.
glib = { path = "vendor/security-patches/glib-0.18.5" }
phf_generator = { path = "vendor/security-patches/phf_generator-0.8.0" }

[package]
name = "kumiho-construct"
version = "2026.5.14"
edition = "2024"
authors = ["Kumiho Inc."]
license = "MIT OR Apache-2.0"
description = "Construct — memory-native AI agent runtime powered by Kumiho"
repository = "https://github.com/KumihoIO/construct-os"
readme = "README.md"
keywords = ["ai", "agent", "memory", "orchestration", "kumiho"]
categories = ["command-line-utilities", "development-tools"]
rust-version = "1.89"
include = [
  "/src/**/*",
  "/build.rs",
  "/Cargo.toml",
  "/Cargo.lock",
  "/LICENSE*",
  "/README.md",
  "/web/dist/**/*",
  "/tool_descriptions/**/*",
  "/resources/sidecars/*.py",
  "/operator-mcp/pyproject.toml",
  "/operator-mcp/setup.py",
  "/operator-mcp/requirements.txt",
  "/operator-mcp/README.md",
  "/operator-mcp/operator_mcp/**/*.py",
  "/operator-mcp/operator_mcp/**/*.yaml",
  "/operator-mcp/session-manager/dist/**/*",
  "/operator-mcp/session-manager/package.json",
]

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

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

[dependencies]
# CLI - minimal and fast
clap = { version = "4.5", features = ["derive"] }
clap_complete = "4.6"

# Async runtime - feature-optimized for size
tokio = { version = "1.50", default-features = false, features = ["rt-multi-thread", "macros", "time", "net", "io-util", "sync", "process", "io-std", "fs", "signal"] }
tokio-util = { version = "0.7", default-features = false }
tokio-stream = { version = "0.1.18", default-features = false, features = ["fs", "sync"] }

# HTTP client - minimal features
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "blocking", "multipart", "stream", "socks"] }

# Matrix client + E2EE decryption
matrix-sdk = { version = "0.16", optional = true, default-features = false, features = ["e2e-encryption", "rustls-tls", "markdown", "sqlite"] }

# Serialization
serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_json = { version = "1.0", default-features = false, features = ["std"] }

# Config
directories = "6.0"
toml = "1.0"
shellexpand = "3.1"

# JSON Schema generation for config export
schemars = "1.2"

# Logging - minimal
tracing = { version = "0.1", default-features = false }
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "ansi", "env-filter"] }

# Observability - Prometheus metrics (optional; requires AtomicU64, unavailable on 32-bit)
prometheus = { version = "0.14", default-features = false, optional = true }

# Base64 encoding (screenshots, image data)
base64 = "0.22"
image = { version = "0.25", default-features = false, features = ["jpeg", "png"] }

# URL encoding for web search
urlencoding = "2.1"

# HTML to plain text conversion (web_fetch tool)
nanohtml2text = "0.2"

# Optional Rust-native browser automation backend
fantoccini = { version = "0.22.1", optional = true, default-features = false, features = ["rustls-tls"] }

# Progress bars (update pipeline)
indicatif = "0.18"

# Temp files (update pipeline rollback)
tempfile = "3.26"

# Tar/gzip extraction (update pipeline)
flate2 = "1.1"
tar = "0.4"

# Zip extraction for ClawHub registry installers
zip = { version = "8.6", default-features = false, features = ["deflate-flate2"] }

# Embed built-in workflow YAMLs into the binary (seeded during onboarding)
include_dir = "0.7"

# Error handling
anyhow = "1.0"
thiserror = "2.0"

# Aardvark I2C/SPI/GPIO USB adapter (Total Phase) — stub when SDK absent
aardvark-sys = { path = "crates/aardvark-sys", version = "0.1.0" }

# UUID generation
uuid = { version = "1.22", default-features = false, features = ["v4", "std"] }

# Authenticated encryption (AEAD) for secret store
chacha20poly1305 = "0.10"

# HMAC for webhook signature verification
hmac = "0.12"
sha2 = "0.10"
hex = "0.4"

# CSPRNG for secure token generation
rand = "0.10"

# Portable atomic fallbacks for targets without native 64-bit atomics
portable-atomic = "1"

# Cross-platform PTY for terminal WebSocket backend
portable-pty = "0.9"

# serde-big-array for wa-rs storage (large array serialization)
serde-big-array = { version = "0.5", optional = true }

# Fast mutexes that don't poison on panic
parking_lot = "0.12"

# Async traits
async-trait = "0.1"

# HMAC-SHA256 (Zhipu/GLM JWT auth)
ring = "0.17"

# Protobuf encode/decode (Lark WS frame codec, WhatsApp storage)
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }

# Memory / persistence
# Note: rusqlite kept for non-memory uses (cron store, gateway pairing, heartbeat, etc.)
# The SQLite *memory backend* has been stripped; persistent memory uses Kumiho MCP.
rusqlite = { version = "0.37", features = ["bundled"] }
chrono = { version = "0.4", default-features = false, features = ["clock", "std", "serde"] }
chrono-tz = "0.10"
cron = "0.16"

# Interactive CLI prompts
dialoguer = { version = "0.12", features = ["fuzzy-select"] }
console = "0.16"

# Internationalization (Fluent — Mozilla's localization framework)
# Bundles for `construct onboard` are embedded at compile time from `i18n/<lang>/*.ftl`.
fluent = "0.17"
fluent-bundle = "0.16"
unic-langid = { version = "0.9", features = ["macros"] }

# Hardware discovery (device path globbing)
glob = "0.3"

# Binary discovery (init system detection)
which = "8.0"

# WebSocket client channels (Discord/Lark/DingTalk/Nostr)
tokio-tungstenite = { version = "0.29", features = ["rustls-tls-webpki-roots"] }
tokio-socks = "0.5"
futures-util = { version = "0.3", default-features = false, features = ["sink", "alloc"] }
nostr-sdk = { version = "0.44", default-features = false, features = ["nip04", "nip59"], optional = true }
regex = "1.10"
hostname = "0.4.2"
rustls = "0.23"
rustls-pemfile = "2"
rustls-pki-types = "1.14.1"
tokio-rustls = "0.26.4"
webpki-roots = "1.0.6"

# email
lettre = { version = "0.11.19", default-features = false, features = ["builder", "smtp-transport", "rustls-tls"] }
mail-parser = "0.11.2"
async-imap = { version = "0.11",features = ["runtime-tokio"], default-features = false }

# HTTP server (gateway) — replaces raw TCP for proper HTTP/1.1 compliance
axum = { version = "0.8", default-features = false, features = ["http1", "json", "tokio", "query", "ws", "macros", "multipart"] }
hyper = { version = "1", features = ["http1", "server"] }
hyper-util = { version = "0.1", features = ["tokio", "server-auto", "server-graceful"] }
tower = { version = "0.5", default-features = false, features = ["util"] }
tower-http = { version = "0.6", default-features = false, features = ["limit", "timeout"] }
http-body-util = "0.1"

# Embed frontend assets into binary (web dashboard)
rust-embed = "8"
mime_guess = "2"

# OpenTelemetry — OTLP trace + metrics export.
# Use the blocking HTTP exporter client to avoid Tokio-reactor panics in
# OpenTelemetry background batch threads when Construct emits spans/metrics from
# non-Tokio contexts.
opentelemetry = { version = "0.31", default-features = false, features = ["trace", "metrics"], optional = true }
opentelemetry_sdk = { version = "0.31", default-features = false, features = ["trace", "metrics"], optional = true }
opentelemetry-otlp = { version = "0.31", default-features = false, features = ["trace", "metrics", "http-proto", "reqwest-blocking-client", "reqwest-rustls-webpki-roots"], optional = true }

# Serial port for peripheral communication (STM32, etc.)
tokio-serial = { version = "5", default-features = false, optional = true }

# USB device enumeration (hardware discovery) — only on platforms nusb supports
# (Linux, macOS, Windows). Android/Termux uses target_os="android" and is excluded.
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))'.dependencies]
nusb = { version = "0.2", default-features = false, optional = true }

# probe-rs for STM32/Nucleo memory read (Phase B)
probe-rs = { version = "0.31", optional = true }

# PDF extraction for datasheet RAG (optional, enable with --features rag-pdf)
pdf-extract = { version = "0.10", optional = true }

# Cross-platform audio capture for voice wake word detection (optional, enable with --features voice-wake)
cpal = { version = "0.15", optional = true }

# Terminal QR rendering for WhatsApp Web pairing flow.
qrcode = { version = "0.14", optional = true }

# WhatsApp Web client (wa-rs) — optional, enable with --features whatsapp-web
# Uses wa-rs for Bot and Client, wa-rs-core for storage traits, custom rusqlite backend avoids Diesel conflict.
wa-rs = { version = "0.2", optional = true, default-features = false }
wa-rs-core = { version = "0.2", optional = true, default-features = false }
wa-rs-binary = { version = "0.2", optional = true, default-features = false }
wa-rs-proto = { version = "0.2", optional = true, default-features = false }
wa-rs-ureq-http = { version = "0.2", optional = true }
wa-rs-tokio-transport = { version = "0.2", optional = true, default-features = false }

# Raspberry Pi GPIO / Landlock (Linux only) — target-specific to avoid compile failure on macOS
[target.'cfg(target_os = "linux")'.dependencies]
rppal = { version = "0.22", optional = true }
landlock = { version = "0.4", optional = true }

# Unix-specific dependencies (for root check, etc.)
[target.'cfg(unix)'.dependencies]
libc = "0.2"

[features]
default = ["observability-prometheus", "skill-creation"]
channel-nostr = ["dep:nostr-sdk"]
hardware = ["nusb", "tokio-serial"]
channel-matrix = ["dep:matrix-sdk"]
channel-lark = ["dep:prost"]
channel-feishu = ["channel-lark"]  # Alias for Feishu users (Lark and Feishu are the same platform)
observability-prometheus = ["dep:prometheus"]
observability-otel = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp"]
peripheral-rpi = ["rppal"]
# Browser backend feature alias used by cfg(feature = "browser-native")
browser-native = ["dep:fantoccini"]
# Backward-compatible alias for older invocations
fantoccini = ["browser-native"]
# Sandbox feature aliases used by cfg(feature = "sandbox-*")
sandbox-landlock = ["dep:landlock"]
sandbox-bubblewrap = []
# Backward-compatible alias for older invocations
landlock = ["sandbox-landlock"]
# Prometheus metrics observer (requires 64-bit atomics; disable on 32-bit targets)
metrics = ["observability-prometheus"]
# probe = probe-rs for Nucleo memory read (adds ~50 deps; optional)
probe = ["dep:probe-rs"]
# rag-pdf = PDF ingestion for datasheet RAG
rag-pdf = ["dep:pdf-extract"]
# skill-creation = Autonomous skill creation from successful multi-step tasks
skill-creation = []
# whatsapp-web = Native WhatsApp Web client with custom rusqlite storage backend
whatsapp-web = ["dep:wa-rs", "dep:wa-rs-core", "dep:wa-rs-binary", "dep:wa-rs-proto", "dep:wa-rs-ureq-http", "dep:wa-rs-tokio-transport", "dep:serde-big-array", "dep:prost", "dep:qrcode"]
# voice-wake = Voice wake word detection via microphone (cpal)
voice-wake = ["dep:cpal"]
# WASM plugin system. Runtime execution is intentionally not wired until the
# plugin runtime dependency is on a patched security baseline.
plugins-wasm = []
# WebAuthn / FIDO2 hardware key authentication
webauthn = []
# Meta-feature for CI: all features except those requiring system C libraries
# not available on standard CI runners (e.g., voice-wake needs libasound2-dev).
ci-all = [
    "channel-nostr",
    "hardware",
    "channel-matrix",
    "channel-lark",
    "observability-prometheus",
    "observability-otel",
    "peripheral-rpi",
    "browser-native",
    "sandbox-landlock",
    "sandbox-bubblewrap",
    "probe",
    "rag-pdf",
    "skill-creation",
    "whatsapp-web",
    "plugins-wasm",
]

[profile.dev]
incremental = true
opt-level = 1

[profile.release]
opt-level = "z"      # Optimize for size
lto = "fat"          # Maximum cross-crate optimization for smaller binaries
codegen-units = 1    # Serialized codegen for low-memory devices (e.g., Raspberry Pi 3 with 1GB RAM)
                     # Higher values (e.g., 8) compile faster but require more RAM during compilation
strip = true          # Remove debug symbols
panic = "abort"      # Reduce binary size

[profile.release-fast]
inherits = "release"
codegen-units = 8    # Parallel codegen for faster builds on powerful machines (16GB+ RAM recommended)
                     # Use: cargo build --profile release-fast

[profile.ci]
inherits = "release"
lto = "thin"         # Much faster than fat LTO; still catches release-mode issues
codegen-units = 16   # Full parallelism for CI runners

[profile.dist]
inherits = "release"
opt-level = "z"
lto = "fat"
codegen-units = 1
strip = true
panic = "abort"

[dev-dependencies]
tempfile = "3.26"
criterion = { version = "0.8", features = ["async_tokio"] }
wiremock = "0.6"
scopeguard = "1.2"
rcgen = "0.13"

[[test]]
name = "component"
path = "tests/test_component.rs"

[[test]]
name = "integration"
path = "tests/test_integration.rs"

[[test]]
name = "system"
path = "tests/test_system.rs"

[[test]]
name = "live"
path = "tests/test_live.rs"

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