# Pipecat Context Hub — task runner
# https://github.com/casey/just

set dotenv-load

# List available recipes
default:
    @just --list

# ── Dev ──────────────────────────────────────────────

# Run the full test suite
test *args:
    uv run pytest tests/ -v {{args}}

# Run the live retrieval-quality benchmark against the local default index
benchmark-quality:
    PIPECAT_HUB_ENABLE_QUALITY_BENCHMARK=1 uv run pytest tests/benchmarks/test_retrieval_quality.py -m benchmark -v -s

# Run the runtime stability benchmark for repeated refresh/serve/search cycles
benchmark-stability:
    PIPECAT_HUB_ENABLE_STABILITY_BENCHMARK=1 uv run pytest tests/benchmarks/test_runtime_stability.py -m benchmark -v -s

# Run the runtime stability benchmark and persist a JSON report
benchmark-stability-report out="artifacts/benchmarks/runtime-stability.json":
    PIPECAT_HUB_ENABLE_STABILITY_BENCHMARK=1 PIPECAT_HUB_STABILITY_OUTPUT={{out}} uv run pytest tests/benchmarks/test_runtime_stability.py -m benchmark -v -s

# Run the chromadb performance benchmark and persist a JSON report
benchmark-perf-report out="artifacts/benchmarks/chromadb-perf.json":
    PIPECAT_HUB_ENABLE_PERF_BENCHMARK=1 PIPECAT_HUB_PERF_OUTPUT={{out}} uv run pytest tests/benchmarks/test_chromadb_perf.py -m benchmark -v -s

# Lint with ruff
lint:
    uv run ruff check src/ tests/

# Format check with ruff
fmt-check:
    uv run ruff format --check src/ tests/

# Auto-format with ruff
fmt:
    uv run ruff format src/ tests/

# Type check with mypy
typecheck:
    uv run mypy src/ tests/

# Run lint + format check + type check
check: lint fmt-check typecheck

# Dependency vulnerability audit
audit-deps:
    # KEEP IN SYNC with the "Dependency Audit" step in .github/workflows/ci.yml —
    # this recipe must mirror the CI gate exactly so a local `just audit-deps`
    # passes iff CI passes. The --ignore-vuln set and rationale live in ci.yml.
    # Enforced by tests/unit/test_audit_sync.py (drift fails the suite).
    #   CVE-2026-45829: chromadb HTTP-server pre-auth RCE — unreachable (embedded
    #                   PersistentClient only, no server/endpoint).
    #   CVE-2026-45830: chromadb HTTP-server cross-tenant collection read/write —
    #                   unreachable (no HTTP server, no multi-tenant auth surface).
    #   CVE-2026-45831: chromadb SimpleRBACAuthorizationProvider cross-tenant
    #                   action bypass — unreachable (no HTTP server, no RBAC
    #                   provider in play in embedded mode).
    #   CVE-2026-45833: chromadb HTTP-server code injection via
    #                   trust_remote_code — unreachable (no server, we never set
    #                   trust_remote_code).
    #   PYSEC-2026-3721: pip <=26.1.2 doubly-encoded package-URL install to an
    #                   arbitrary path — only reachable via `pip download
    #                   --only-binary` against an untrusted index; we only run
    #                   `uv sync --frozen` against locked, trusted PyPI.
    # All four chromadb CVEs affect every release through 1.5.9 (the latest);
    # no fixed version exists yet as of this writing.
    # The two torch advisories (PYSEC-2026-139, CVE-2025-3000) were dropped when
    # torch left the tree — embedding and reranking now run on ONNX Runtime.
    uv run pip-audit --local --progress-spinner off --ignore-vuln CVE-2026-45829 --ignore-vuln CVE-2026-45830 --ignore-vuln CVE-2026-45831 --ignore-vuln CVE-2026-45833 --ignore-vuln PYSEC-2026-3721

# Static security scan for Python code
audit-security:
    uv run bandit -r src

# Generate a CycloneDX SBOM from the current locked environment
sbom out="artifacts/security/sbom.json":
    mkdir -p $(dirname {{out}})
    uv run cyclonedx-py environment --output-reproducible --of JSON -o {{out}}

# Run the local security gate
audit: audit-deps audit-security

# ── Server ───────────────────────────────────────────

# Start the MCP server
serve:
    uv run pipecat-context-hub serve

# Refresh the index (pass --force for full re-ingest)
refresh *args:
    uv run pipecat-context-hub refresh {{args}}

# ── Dashboard ────────────────────────────────────────

# Refresh index + rebuild all dashboard data
dashboard-refresh *args: (refresh args)
    @echo ""
    @echo "=== Extracting embeddings + UMAP 3D projection ==="
    uv run python dashboard/scripts/extract_embeddings.py
    @echo ""
    @echo "=== Computing K-means clusters ==="
    uv run python dashboard/scripts/compute_clusters.py
    @echo ""
    @echo "=== Extracting dashboard stats ==="
    uv run python dashboard/scripts/extract_dashboard.py
    @echo ""
    @echo "Done. Run 'just dashboard-serve' to view."

# Rebuild dashboard data without refreshing the index
dashboard-build:
    uv run python dashboard/scripts/extract_embeddings.py
    uv run python dashboard/scripts/compute_clusters.py
    uv run python dashboard/scripts/extract_dashboard.py

# Serve the dashboard on localhost:8765
dashboard-serve port="8765":
    python3 -m http.server {{port}} -d dashboard/public/
