#!/usr/bin/env python3
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0

"""Cross-platform whisper.cpp (whisper-server) prebuilt installer for Unsloth Studio.

Downloads a per-platform whisper.cpp bundle published by the Unsloth fork
(``unslothai/whisper.cpp``) into an isolated ``<UNSLOTH_HOME>/whisper.cpp``,
never a system whisper.cpp. The canonical install target matches the
sidecar/build-script contract in ``stt_ggml_sidecar.py``:

    <install-dir>/build/bin/whisper-server              (Unix)
    <install-dir>/build/bin/Release/whisper-server.exe  (Windows)

Bundles are dynamically linked: ``whisper-server`` needs ``libwhisper``,
``libggml*`` and any GPU backend libraries. The binaries carry ``RUNPATH=$ORIGIN``
so the installer co-locates every shared library from the archive into the same
``build/bin`` directory and marks the server executable on Unix.

Archives are verified against the release's own ``whisper-prebuilt-sha256.json``
checksum index (same model as ``install_llama_prebuilt.py``). An asset absent
from the index, or a release without it, fails closed (setup reports the prebuilt
unavailable and local dictation uses Transformers STT). Being a same-origin
checksum it proves integrity, not authenticity; pair the release with GitHub
artifact attestations for provenance.

Release resolution prefers the download host (``github.com/<repo>/releases/...``),
fetching the manifest + checksum index with zero ``api.github.com`` calls (that
API is rate-limited to 60 req/hour unauthenticated); the GitHub API is only a
fallback on a 404 / malformed asset.

The whole component-agnostic flow (verified downloads, safe extraction, the
install lock, release resolution, checksum-index handling, the install driver,
the resolve probe) lives in ``prebuilt_core.py`` and is shared with
``install_llama_prebuilt.py``. This module keeps only the whisper specifics: the
host mapping, install-tree layout, slim pairing with the installed llama.cpp ggml
runtime, the pinned-release CPU escape hatch, the marker filename, and the CLI.
Every retained public name is a thin wrapper tests can monkeypatch so the core
observes the patch.

Selection is slim-only for current releases (v1.9.1-unsloth.2+): every published
bundle is a slim (ggml-less) whisper paired to the llama.cpp prebuilt, which
provides all ggml backends. The per-accelerator fat selection chain was deleted
with the fat bundles; the one legacy shape still honored is the published fat CPU
bundle of an explicitly pinned pre-slim release.

Mirrors ``install_node_prebuilt.py`` / ``install_llama_prebuilt.py``. Exit codes:
0 success (or already current), 1 error, 2 incompatible paired release, 3 busy. A re-run
that already matches logs "already matches" and returns 0 without downloading
(the scripts grep it).
"""

from __future__ import annotations

import argparse
import os
import re
import shutil
import subprocess
import sys
from dataclasses import dataclass, replace
from pathlib import Path
from typing import Any

# Put studio/ on sys.path so install_llama_prebuilt / prebuilt_core resolve
# whether run as a script (from any cwd) or imported by the tests.
_STUDIO_DIR = os.path.dirname(os.path.abspath(__file__))
if _STUDIO_DIR not in sys.path:
    sys.path.insert(0, _STUDIO_DIR)

import install_llama_prebuilt as llama  # noqa: E402
import prebuilt_core as core  # noqa: E402

# Shared machinery re-exported as module globals; the wrappers below resolve
# these by bare name at call time so tests can monkeypatch them here.
PrebuiltFallback = core.PrebuiltFallback
BusyInstallConflict = core.BusyInstallConflict
auth_headers = llama.auth_headers
download_bytes = llama.download_bytes
download_file = llama.download_file
fetch_json = llama.fetch_json
sha256_file = core.sha256_file
_URL_OPENER = core._URL_OPENER
install_lock = core.install_lock
install_lock_path = core.install_lock_path
parse_macos_version = core.parse_macos_version
release_asset_map = core.release_asset_map
release_asset_download_url = core.release_asset_download_url
compute_install_fingerprint = core.compute_install_fingerprint
artifact_coverage = core.artifact_coverage
emit_resolver_output = core.emit_resolver_output
_valid_sha256 = core.valid_sha256
_swap_into_place = core.swap_into_place
InstallSelection = core.InstallSelection
ReleaseBundle = core.ReleaseBundle
llama_detect_host = llama.detect_host
installed_llama_runtime = llama.installed_llama_runtime
installed_llama_ggml_tree = llama.installed_llama_ggml_tree

# Late-binding seam for prebuilt_core: name lookups hit this module's globals
# first (so monkeypatches apply), then the core defaults.
_OPS = core.ModuleOps(globals())


# Resolver mode keeps stdout to the JSON payload only (setup.sh parses it);
# main() flips this on for the install path so setup surfaces progress.
_LOG_TO_STDOUT = False


class ReleaseCompatibilityError(PrebuiltFallback):
    """A valid slim release cannot pair with this host's installed runtime."""


def log(message: str) -> None:
    print(f"[whisper-prebuilt] {message}", file = sys.stdout if _LOG_TO_STDOUT else sys.stderr)


EXIT_SUCCESS = 0
EXIT_ERROR = 1
EXIT_INCOMPATIBLE = 2
EXIT_BUSY = 3

COMPONENT = "whisper.cpp"
SCHEMA_VERSION = 1
USER_AGENT = "unsloth-studio-whisper-prebuilt"

DEFAULT_PUBLISHED_REPO = "unslothai/whisper.cpp"
# Release assets published by the fork's prebuilt CI.
MANIFEST_ASSET_NAME = "whisper-prebuilt-manifest.json"
SHA256_ASSET_NAME = "whisper-prebuilt-sha256.json"

METADATA_FILENAME = "UNSLOTH_WHISPER_PREBUILT_INFO.json"

# Backends the installer can select: accelerator identities for the slim pairing
# (which llama ggml module must exist) and the marker. Only "cpu" can match a fat
# artifact (the pinned pre-slim escape hatch).
SUPPORTED_BACKENDS = ("cpu", "cuda", "metal", "vulkan", "rocm")

# Fallback the core applies on a GPU-selection miss: retry with cpu so the slim
# bundle can pair via the llama cpu modules, or -- on a pinned pre-slim release --
# the published fat CPU bundle installs. A miss is an install error unless the
# valid slim release specifically requires a different paired llama release.
FALLBACK_BACKEND = "cpu"

# Backends whose slim (ggml-less) whisper bundle can ride the installed llama.cpp
# prebuilt's ggml runtime. All are eligible: the next whisper release ships only
# slim bundles, so cpu and metal pair like the GPUs do.
SLIM_ELIGIBLE_BACKENDS = ("cpu", "cuda", "metal", "rocm", "vulkan")

# ggml backend module the llama bin dir must provide per accelerator, keyed by
# asset os token, following llama's bundle layout / health globs. A backend with
# no glob for the host os (metal off macOS) is never slim there. llama's x64 cpu
# bundles ship per-arch libggml-cpu-<variant> modules, macOS a single
# libggml-cpu; the cpu globs cover both.
SLIM_BACKEND_MODULE_GLOBS = {
    "cpu": {
        "linux": "libggml-cpu*.so*",
        "windows": "ggml-cpu*.dll",
        "macos": "libggml-cpu*.dylib",
    },
    "cuda": {"linux": "libggml-cuda.so*", "windows": "ggml-cuda.dll"},
    "metal": {"macos": "libggml-metal*.dylib"},
    # Windows rocm must name the ggml module: the bundles also ship amdhip64,
    # hipblas and libhipblaslt, which a looser *hip*.dll would accept.
    "rocm": {"linux": "libggml-hip.so*", "windows": "ggml-hip*.dll"},
    "vulkan": {"linux": "libggml-vulkan.so*", "windows": "ggml-vulkan.dll"},
}

# Everything the slim wiring mirrors from the llama bin dir: the core ggml
# sonames plus every dlopen'd backend module (CPU variants included). libggml*
# matches .so and .dylib alike; ggml*.dll covers Windows. libomp* rides along
# because llama's clang-built slices (windows x64/arm64, linux arm64) link ggml
# against the LLVM OpenMP runtime and ship it in the bundle, so the loader can
# never find it on the host. Linux x64 (gcc, host libgomp.so.1) and macOS (Apple
# clang, no OpenMP) ship none, so the globs match nothing there.
SLIM_GGML_LIBRARY_GLOBS = (
    "libggml*",
    "ggml*.dll",
    "libomp*.dll",
    "libomp*.so*",
    "libomp*.dylib",
)
SLIM_ROCM_LIBRARY_GLOBS = (
    "libamd*.so*",
    "libhip*.so*",
    "libhsa*.so*",
    "libroc*.so*",
)
# Kernel catalogs a linux ROCm llama bundle can ship, mirrored into the whisper
# bin dir so the packaged libraries find their Tensile kernels beside them.
SLIM_ROCM_RUNTIME_DIRS = ("hipblaslt", "rocblas")
# Of those, the ones a paired runtime must actually carry. hipBLASLt builds no
# Tensile kernels for gfx1030 / RDNA2, so llama's linux-x64-rocm-gfx103X bundle
# ships libhipblaslt.so.1 with no hipblaslt/ catalog while every other published
# target carries one. rocblas is load-bearing: libggml-hip links librocblas
# directly and every published linux ROCm bundle ships rocblas/library. The
# llama installer copies only the catalogs the archive has, so demanding both
# here rejected a runtime llama.cpp itself runs fine on (#8364).
SLIM_ROCM_REQUIRED_RUNTIME_DIRS = ("rocblas",)
# 3: libomp*.so*/dylib joined the wiring, so version 2 installs are missing
# libomp.so.5 on linux arm64 and must re-wire.
SLIM_RUNTIME_WIRING_VERSION = 3

INSTALL_STAGING_ROOT_NAME = ".staging"

# Master switch for the staged runtime smoke test (start whisper-server + a tiny
# transcription) before the atomic activate. Off by default so a bundle whose GPU
# forward pass JIT-compiles kernels does not stall every install; the check and
# its CPU-asset retry stay intact -- set True to re-enable.
_RUN_STAGED_PREBUILT_VALIDATION = False


# ── Host detection (probes shared with install_llama_prebuilt) ──
@dataclass(frozen = True)
class HostInfo:
    system: str  # platform.system()
    machine: str  # lowered platform.machine()
    whisper_os: str  # asset token: linux | macos | windows
    whisper_arch: str  # asset token: x64 | arm64
    archive_ext: str  # .tar.gz | .zip
    is_windows: bool
    is_macos: bool
    is_apple_silicon: bool
    has_usable_nvidia: bool = False
    has_rocm: bool = False
    rocm_gfx: str | None = None
    # (major, minor) from platform.mac_ver(); None off macOS or if unparseable.
    # Enforces a macOS artifact's min_os so we never pick a bundle that cannot
    # load on this OS version.
    macos_version: tuple[int, int] | None = None


def host_from_llama(base: Any) -> HostInfo:
    """Map install_llama_prebuilt's detected host onto the whisper asset tokens.
    Raises PrebuiltFallback on an unsupported OS/arch."""
    system = base.system
    machine = base.machine.lower()
    if system == "Linux":
        whisper_os = "linux"
    elif system == "Darwin":
        whisper_os = "macos"
    elif system == "Windows":
        whisper_os = "windows"
    else:
        raise PrebuiltFallback(f"unsupported operating system for whisper.cpp prebuilt: {system}")

    if machine in {"x86_64", "amd64", "x64"}:
        whisper_arch = "x64"
    elif machine in {"arm64", "aarch64"}:
        whisper_arch = "arm64"
    else:
        raise PrebuiltFallback(f"unsupported CPU architecture for whisper.cpp prebuilt: {machine}")

    return HostInfo(
        system = system,
        machine = machine,
        whisper_os = whisper_os,
        whisper_arch = whisper_arch,
        archive_ext = ".zip" if base.is_windows else ".tar.gz",
        is_windows = base.is_windows,
        is_macos = base.is_macos,
        is_apple_silicon = base.is_macos and whisper_arch == "arm64",
        has_usable_nvidia = base.has_usable_nvidia,
        has_rocm = base.has_rocm,
        rocm_gfx = base.rocm_gfx_target,
        macos_version = base.macos_version,
    )


def detect_host() -> HostInfo:
    return host_from_llama(llama_detect_host())


def apply_host_overrides(
    host: HostInfo,
    *,
    has_rocm: bool = False,
    rocm_gfx: str | None = None,
    force_cpu: bool = False,
) -> HostInfo:
    """Apply CLI overrides (setup forwards hardware hints) onto a detected host."""
    if force_cpu:
        return replace(
            host,
            has_usable_nvidia = False,
            has_rocm = False,
            rocm_gfx = None,
            is_apple_silicon = False,
        )
    updates: dict[str, Any] = {}
    if has_rocm or rocm_gfx:
        # --rocm-gfx implies --has-rocm (llama parity); otherwise the host stays on
        # its CUDA/CPU path and never picks the ROCm bundle. Drop CUDA detection too.
        updates["has_rocm"] = True
        updates["has_usable_nvidia"] = False
    if rocm_gfx:
        updates["rocm_gfx"] = rocm_gfx
    return replace(host, **updates) if updates else host


def host_platform_tokens(host: HostInfo) -> tuple[str, str]:
    """Canonical (os, arch) asset tokens the core uses for matching/reporting."""
    return host.whisper_os, host.whisper_arch


# ── Backend selection ──
def auto_detect_backend(host: HostInfo) -> str:
    return core.auto_detect_backend(_OPS, host)


def resolve_backend(host: HostInfo, requested: str | None, *, cpu_fallback: bool) -> str:
    return core.resolve_backend(_OPS, host, requested, cpu_fallback = cpu_fallback)


# ── Asset naming (pure, unit tested) ──
def whisper_asset_name(release_tag: str, host: HostInfo, accel: str) -> str:
    """e.g. whisper-v1.9.1-unsloth.1-linux-x64-cpu.tar.gz.

    `accel` is the asset-filename accelerator token (cpu, metal, cuda12, ...),
    finer-grained than the coarse backend. An install's authoritative asset name
    comes from the release manifest; this constructor is for defaults/diagnostics.
    """
    tag = release_tag if release_tag.startswith("v") else f"v{release_tag}"
    return f"whisper-{tag}-{host.whisper_os}-{host.whisper_arch}-{accel}{host.archive_ext}"


# ── Manifest (release-side artifact catalogue; generic parser in the core) ──
def validate_schema_version(payload: dict[str, Any], *, label: str) -> None:
    core.validate_schema_version(
        payload, label = label, schema_version = SCHEMA_VERSION, error = PrebuiltFallback
    )


def parse_manifest(payload: Any, *, label: str = MANIFEST_ASSET_NAME) -> dict[str, Any]:
    return core.parse_manifest(_OPS, payload, label = label)


def _macos_min_os_ok(host: HostInfo, min_os: Any) -> bool:
    return core.macos_min_os_ok(_OPS, host, min_os)


def macos_min_os_ok(host: HostInfo, min_os: Any) -> bool:
    return _macos_min_os_ok(host, min_os)


def _artifacts_for_host(
    manifest: dict[str, Any], host: HostInfo, backend: str
) -> list[dict[str, Any]]:
    return core.artifacts_for_host(_OPS, manifest, host, backend)


def artifacts_for_host(
    manifest: dict[str, Any], host: HostInfo, backend: str
) -> list[dict[str, Any]]:
    return _artifacts_for_host(manifest, host, backend)


# ── Slim selection (paired with the installed llama.cpp ggml runtime) ──
def _llama_ggml_commit(tag: str) -> str | None:
    """The "-mix-" suffix of a fork tag "b<upstream_build>-mix-<suffix>".

    Despite the name this is NOT a ggml commit: it hashes the pinned PR set and
    stays constant while the base tag, and ggml with it, moves (one value covered
    b9909..b10001, whose ggml trees differ). Fallback for releases predating
    ggml_tree."""
    marker = "-mix-"
    idx = tag.rfind(marker)
    end = idx + len(marker)
    return tag[end:] if idx >= 0 and end < len(tag) else None


def llama_runtime_pairs(
    installed_tag: str,
    required_tag: Any,
    *,
    installed_ggml_tree: Any = None,
    required_ggml_tree: Any = None,
) -> bool:
    """Whether an installed llama tag can back a slim bundle needing required_tag.
    An exact tag always pairs; otherwise the ggml tree ids decide, since they
    change exactly when ggml does. The "-mix-" suffix does not track ggml at all
    (see _llama_ggml_commit) and is only used when either tree is missing.
    requires_ggml_sonames stays the per-file ABI gate."""
    if not isinstance(required_tag, str):
        return False
    if installed_tag == required_tag:
        return True
    # Only decidable with both trees. Refusing when the install predates
    # ggml_tree would strand it: nothing can backfill a tree-less marker
    # without a llama release to install.
    if (
        isinstance(installed_ggml_tree, str)
        and installed_ggml_tree
        and isinstance(required_ggml_tree, str)
        and required_ggml_tree
    ):
        return installed_ggml_tree == required_ggml_tree
    commit = _llama_ggml_commit(installed_tag)
    return commit is not None and commit == _llama_ggml_commit(required_tag)


def _ships_windows_gpu_ggml_module(llama_bin_dir: Path) -> bool:
    """Whether a paired Windows llama runtime carries a GPU ggml backend module.
    Only the cpu bundle links ggml against libomp, and bundle_profile cannot tell
    the two apart: it is absent on both the published rocm artifacts and every
    upstream-sourced install, so the files on disk decide."""
    for backend, per_os in SLIM_BACKEND_MODULE_GLOBS.items():
        glob = per_os.get("windows")
        if backend != "cpu" and glob and any(llama_bin_dir.glob(glob)):
            return True
    return False


def slim_pairing_for_artifact(
    artifact: dict[str, Any], host: HostInfo, backend: str
) -> tuple[Path, str] | None:
    """(llama bin dir, llama release tag) when the installed llama runtime can
    back this slim artifact, else None. Each failed gate logs why; the caller
    then retries via CPU or reports the prebuilt unavailable."""
    asset = artifact.get("asset")
    runtime = installed_llama_runtime()
    if runtime is None:
        log(f"slim_selection: {asset} skipped: no managed llama.cpp prebuilt install")
        return None
    llama_bin_dir, llama_tag, _profile = runtime
    requires_tag = artifact.get("requires_llama_tag")
    if not llama_runtime_pairs(
        llama_tag,
        requires_tag,
        installed_ggml_tree = installed_llama_ggml_tree(),
        required_ggml_tree = artifact.get("requires_ggml_tree"),
    ):
        log(
            f"slim_selection: {asset} skipped: installed llama tag {llama_tag!r} "
            f"does not pair with required {requires_tag!r}"
        )
        return None
    sonames = artifact.get("requires_ggml_sonames")
    if not isinstance(sonames, list) or not sonames:
        log(f"slim_selection: {asset} skipped: manifest lists no requires_ggml_sonames")
        return None
    required_sonames = [str(name) for name in sonames]
    if host.is_windows and _ships_windows_gpu_ggml_module(llama_bin_dir):
        # The shared Windows manifest lists libomp only because the cpu bundle's
        # ggml links against it; a GPU bundle neither ships nor imports it, so
        # requiring it there only mis-rejects. link_ggml_runtime still wires it.
        # This drops libomp140.aarch64.dll as readily as the x64 name, which is
        # safe only while llama publishes no Windows arm64 GPU bundle: that slice
        # is clang-built and its ggml really does need LLVM OpenMP (see
        # SLIM_GGML_LIBRARY_GLOBS). Re-check this gate before adding one.
        required_sonames = [
            name
            for name in required_sonames
            if not (name.lower().startswith("libomp") and name.lower().endswith(".dll"))
        ]
    missing = [name for name in required_sonames if not (llama_bin_dir / name).is_file()]
    if missing:
        log(f"slim_selection: {asset} skipped: llama runtime missing {', '.join(missing)}")
        return None
    module_glob = SLIM_BACKEND_MODULE_GLOBS.get(backend, {}).get(host.whisper_os)
    if module_glob is None:
        log(f"slim_selection: {asset} skipped: no {backend} ggml module on {host.whisper_os}")
        return None
    if not any(path.is_file() for path in llama_bin_dir.glob(module_glob)):
        log(f"slim_selection: {asset} skipped: llama runtime has no {module_glob} module")
        return None
    log(f"slim_selection: selected {asset} paired with llama {llama_tag} at {llama_bin_dir}")
    return llama_bin_dir, llama_tag


def select_slim_artifact(
    manifest: dict[str, Any], host: HostInfo, backend: str
) -> dict[str, Any] | None:
    """The paired slim artifact for any backend (cpu and metal included), or None.
    Slim assets carry backend "slim" so the CPU escape hatch's fat os/arch/backend
    matching never sees them. When the release ships slim candidates but none
    pair, log the actionable reason: on a slim-only release nothing else selects,
    setup reports the prebuilt unavailable, and local dictation stays on
    Transformers STT."""
    if backend not in SLIM_ELIGIBLE_BACKENDS:
        return None
    os_token, arch_token = host_platform_tokens(host)
    candidates = [
        artifact
        for artifact in manifest.get("artifacts", [])
        if artifact.get("os") == os_token
        and artifact.get("arch") == arch_token
        and artifact.get("backend") == "slim"
        and artifact.get("install_kind") == "slim"
        and (not host.is_macos or _macos_min_os_ok(host, artifact.get("min_os")))
    ]
    for artifact in candidates:
        if slim_pairing_for_artifact(artifact, host, backend) is not None:
            return artifact
    if candidates:
        required_tag = candidates[0].get("requires_llama_tag")
        log(f"slim bundle requires llama.cpp {required_tag}; install or update llama.cpp first")
    return None


def select_artifact(
    manifest: dict[str, Any], host: HostInfo, backend: str
) -> dict[str, Any] | None:
    """Slim-only: every backend resolves to the paired slim artifact. The one
    legacy shape still honored is the published fat CPU bundle of a pinned pre-slim
    release, reached by a GPU-backend miss through the core's CPU fallback retry.
    No other fat artifact is ever selected."""
    slim = select_slim_artifact(manifest, host, backend)
    if slim is not None:
        return slim
    if backend != "cpu":
        return None
    candidates = _artifacts_for_host(manifest, host, "cpu")
    return candidates[0] if candidates else None


def select_artifact_with_cpu_fallback(
    manifest: dict[str, Any], host: HostInfo, backend: str
) -> tuple[dict[str, Any], str, bool]:
    try:
        return core.select_artifact_with_fallback(_OPS, manifest, host, backend)
    except PrebuiltFallback as exc:
        reason = _slim_release_incompatibility(manifest, host)
        if reason is not None:
            raise ReleaseCompatibilityError(reason) from exc
        raise


def _slim_release_incompatibility(manifest: dict[str, Any], host: HostInfo) -> str | None:
    """Explain a valid platform slim release that this runtime cannot pair.

    This intentionally excludes missing files, malformed manifests, checksum
    failures, and unsupported platforms. Those are operational errors and must
    never be converted into the update path's kept-existing-runtime success.
    """
    os_token, arch_token = host_platform_tokens(host)
    candidates = [
        artifact
        for artifact in manifest.get("artifacts", [])
        if artifact.get("os") == os_token
        and artifact.get("arch") == arch_token
        and artifact.get("backend") == "slim"
        and artifact.get("install_kind") == "slim"
    ]
    if not candidates:
        return None
    os_compatible = [
        artifact
        for artifact in candidates
        if not host.is_macos or _macos_min_os_ok(host, artifact.get("min_os"))
    ]
    if not os_compatible:
        required = candidates[0].get("min_os")
        return f"slim bundle requires macOS {required}; this host is older"
    runtime = installed_llama_runtime()
    if runtime is None:
        return None
    installed_tag = runtime[1]
    installed_tree = installed_llama_ggml_tree()
    # Normalise the tree: llama_runtime_pairs treats a non-string as absent, but
    # an unhashable one (list/dict) would blow up the set first.
    required_pairs = {
        (
            artifact.get("requires_llama_tag"),
            artifact["requires_ggml_tree"]
            if isinstance(artifact.get("requires_ggml_tree"), str)
            else None,
        )
        for artifact in os_compatible
        if isinstance(artifact.get("requires_llama_tag"), str)
    }
    required_tags = {tag for tag, _tree in required_pairs}
    if required_tags and not any(
        llama_runtime_pairs(
            installed_tag, tag, installed_ggml_tree = installed_tree, required_ggml_tree = tree
        )
        for tag, tree in required_pairs
    ):
        required_tag = sorted(required_tags)[0]
        return (
            f"slim bundle requires llama.cpp {required_tag}; installed llama.cpp is {installed_tag}"
        )
    return None


def select_artifact_with_fallback(
    manifest: dict[str, Any], host: HostInfo, backend: str
) -> tuple[dict[str, Any], str, bool]:
    return select_artifact_with_cpu_fallback(manifest, host, backend)


# ── Release checksum index (trust anchor: the release's own sha256 asset) ──
def parse_release_checksums(repo: str, release_tag: str, payload: Any) -> dict[str, str]:
    return core.parse_release_checksums(_OPS, repo, release_tag, payload)


def fetch_release_checksums(bundle: ReleaseBundle) -> dict[str, str]:
    return core.fetch_release_checksums(_OPS, bundle)


def expected_sha256_for(
    checksums: dict[str, str],
    asset_name: str,
    *,
    manifest_sha256: str | None = None,
) -> str:
    return core.expected_sha256_for(_OPS, checksums, asset_name, manifest_sha256 = manifest_sha256)


# ── Verified download (retries once on checksum mismatch) ──
def download_file_verified(
    url: str, destination: Path, *, expected_sha256: str, label: str
) -> None:
    core.download_file_verified_strict(
        _OPS, url, destination, expected_sha256 = expected_sha256, label = label
    )


# ── GitHub release resolution ──
def github_release(repo: str, tag: str) -> dict[str, Any]:
    return core.github_release(_OPS, repo, tag, error = PrebuiltFallback)


def fetch_release_bundle(repo: str, release_tag: str) -> ReleaseBundle:
    return core.fetch_release_bundle(_OPS, repo, release_tag)


def asset_download_url(bundle: ReleaseBundle, asset_name: str) -> str:
    return core.asset_download_url(_OPS, bundle, asset_name)


# ── Download-host fast path (resolve + fetch the JSON assets with no GitHub API) ──
def _download_host_latest_release_tag(repo: str) -> str | None:
    return core.download_host_latest_release_tag(_OPS, repo)


def _download_host_json(url: str) -> Any:
    return core.fetch_download_host_json(_OPS, url)


def _resolve_release_via_download_host(
    repo: str, published_release_tag: str | None
) -> tuple[ReleaseBundle, dict[str, str]] | None:
    return core.resolve_release_via_download_host(_OPS, repo, published_release_tag)


# ── Archive extraction (core's guarded extractor + tar exec-bit restore) ──
def extract_archive(archive_path: Path, destination: Path) -> None:
    """Shared guarded extraction, then restore tar exec bits (the extractor writes
    plain files; whisper-server must stay executable)."""
    core.extract_archive(archive_path, destination)
    core.restore_tar_exec_bits(archive_path, destination)


# ── Install layout ──
def server_binary_name(host: HostInfo) -> str:
    return "whisper-server.exe" if host.is_windows else "whisper-server"


def runtime_bin_dir(install_dir: Path, host: HostInfo) -> Path:
    """Canonical directory holding whisper-server + its co-located libs."""
    if host.is_windows:
        return install_dir / "build" / "bin" / "Release"
    return install_dir / "build" / "bin"


def whisper_server_path(install_dir: Path, host: HostInfo) -> Path:
    return runtime_bin_dir(install_dir, host) / server_binary_name(host)


def installed_server_path(install_dir: Path, host: HostInfo) -> Path:
    return whisper_server_path(install_dir, host)


def _locate_server_in_tree(root: Path, host: HostInfo) -> Path:
    return core.locate_server_in_tree(_OPS, root, host)


def locate_server_in_tree(root: Path, host: HostInfo) -> Path:
    return _locate_server_in_tree(root, host)


def _assemble_install_tree(bundle_root: Path, staged_root: Path, host: HostInfo) -> Path:
    """Lay out staged_root as a full install: build/bin/<server + libs>.

    Everything beside the server in the archive (shared libs, backend kernel
    subdirs, license/build-info) is co-located into the canonical bin dir so the
    server's RUNPATH=$ORIGIN resolves its libs.
    """
    bin_dir = runtime_bin_dir(staged_root, host)
    bin_dir.mkdir(parents = True, exist_ok = True)
    for entry in sorted(bundle_root.iterdir()):
        if entry.name == METADATA_FILENAME:
            continue
        dest = bin_dir / entry.name
        if entry.is_dir() and not entry.is_symlink():
            shutil.copytree(entry, dest, symlinks = True)
        else:
            shutil.copy2(entry, dest, follow_symlinks = False)
    server = bin_dir / server_binary_name(host)
    if not server.exists():
        raise PrebuiltFallback("staged install is missing the whisper-server binary")
    if not host.is_windows:
        os.chmod(server, server.stat().st_mode | 0o111)
    return server


def assemble_install_tree(bundle_root: Path, staged_root: Path, host: HostInfo) -> Path:
    return _assemble_install_tree(bundle_root, staged_root, host)


def _validate_staged_server(staged_root: Path, host: HostInfo) -> None:
    """Optional pre-activate smoke test. Gated off by default (see the switch)."""
    if not _RUN_STAGED_PREBUILT_VALIDATION:
        return
    server = whisper_server_path(staged_root, host)
    env = os.environ.copy()
    bin_dir = str(runtime_bin_dir(staged_root, host))
    for var in ("LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"):
        env[var] = bin_dir + (os.pathsep + env[var] if env.get(var) else "")
    try:
        result = subprocess.run(
            [str(server), "--help"],
            capture_output = True,
            text = True,
            timeout = 60,
            env = env,
            **llama.windows_hidden_subprocess_kwargs(),
        )
    except (OSError, subprocess.SubprocessError) as exc:
        raise PrebuiltFallback(f"staged whisper-server failed to launch: {exc}") from exc
    if result.returncode != 0:
        raise PrebuiltFallback(
            f"staged whisper-server --help exited {result.returncode}: {result.stderr.strip()}"
        )


def validate_staged_server(staged_root: Path, host: HostInfo) -> None:
    _validate_staged_server(staged_root, host)


# ── Slim install wiring (llama ggml runtime into the whisper bin dir) ──
def _elf_needed(path: Path) -> set[str] | None:
    """Read ELF DT_NEEDED names when a standard inspection tool is available."""
    commands = (("readelf", "-d"), ("objdump", "-p"))
    for command in commands:
        try:
            result = subprocess.run(
                [*command, str(path)], capture_output = True, text = True, timeout = 10
            )
        except (OSError, subprocess.SubprocessError):
            continue
        if result.returncode != 0:
            continue
        needed: set[str] = set()
        for line in result.stdout.splitlines():
            match = re.search(r"\(NEEDED\).*\[([^]]+)\]", line)
            if match:
                needed.add(match.group(1))
                continue
            match = re.match(r"\s*NEEDED\s+(\S+)", line)
            if match:
                needed.add(match.group(1))
        return needed
    return None


def _runtime_library_sources(llama_bin_dir: Path, backend: str | None) -> list[Path]:
    patterns = list(SLIM_GGML_LIBRARY_GLOBS)
    sources = {
        path for pattern in patterns for path in llama_bin_dir.glob(pattern) if path.is_file()
    }
    if backend == "rocm":
        # Windows llama HIP/ROCm prebuilts use a flat *.dll runtime overlay.
        # Mirror that complete no-SDK closure, not only filenames containing
        # ggml, hip, or roc: transitive runtime DLLs can have unrelated names.
        windows_dlls = {path for path in llama_bin_dir.glob("*.dll") if path.is_file()}
        if windows_dlls:
            sources.update(windows_dlls)
            return sorted(sources)

        # Linux can inspect DT_NEEDED and copy the exact packaged closure. Fall
        # back to the ROCm globs only when standard ELF tools are unavailable.
        by_name = {path.name: path for path in llama_bin_dir.iterdir() if path.is_file()}
        pending = list(sources)
        inspected_hip = False
        system_libraries = {
            "libc.so.6",
            "libdl.so.2",
            "libgcc_s.so.1",
            "libm.so.6",
            "libpthread.so.0",
            "librt.so.1",
            "libstdc++.so.6",
        }
        while pending:
            source = pending.pop()
            needed = _elf_needed(source)
            if needed is None:
                continue
            if source.name.startswith("libggml-hip"):
                inspected_hip = True
            for name in needed - system_libraries:
                dependency = by_name.get(name)
                if dependency is not None and dependency not in sources:
                    sources.add(dependency)
                    pending.append(dependency)
        if not inspected_hip:
            sources.update(
                path
                for pattern in SLIM_ROCM_LIBRARY_GLOBS
                for path in llama_bin_dir.glob(pattern)
                if path.is_file()
            )
    return sorted(sources)


def _link_or_copy(source: Path, destination: Path) -> None:
    destination.parent.mkdir(parents = True, exist_ok = True)
    if destination.exists() or destination.is_symlink():
        destination.unlink()
    try:
        os.link(source, destination)
    except OSError:
        shutil.copy2(source, destination)


def link_ggml_runtime(
    llama_bin_dir: Path,
    whisper_bin_dir: Path,
    *,
    backend: str | None = None,
) -> list[str]:
    """Hardlink every ggml library from the llama runtime into the whisper bin
    dir; returns the wired filenames (sorted) for the marker / sidecar launch guard.

    Hardlinks (not symlinks) on purpose: when the llama updater atomically swaps
    its install dir, the old inodes stay alive under these links, so a
    not-yet-updated whisper keeps running the exact ggml build it was installed
    against. Falls back to a copy where linking is unsupported or crosses devices.
    Re-run on every install/update so the links track the current pairing.
    """
    sources = _runtime_library_sources(llama_bin_dir, backend)
    if not any(source.name.startswith(("libggml", "ggml")) for source in sources):
        raise PrebuiltFallback(
            f"no ggml libraries found in {llama_bin_dir} to pair the slim whisper install"
        )
    whisper_bin_dir.mkdir(parents = True, exist_ok = True)
    for source in sources:
        # Follows a libggml.so.0 -> libggml.so.0.x symlink to its inode, so every
        # created name is a real hardlink surviving a dir swap.
        _link_or_copy(source, whisper_bin_dir / source.name)
    return [source.name for source in sources]


def link_runtime_directories(
    llama_bin_dir: Path, whisper_bin_dir: Path, *, backend: str, host: HostInfo
) -> list[str]:
    """Mirror GPU kernel catalogs that packaged ROCm libraries load at runtime."""
    # Windows ROCm prebuilts are a flat DLL overlay. The hipblaslt/rocblas
    # catalog directories are part of the Linux ROCm bundle layout only.
    if backend != "rocm" or host.is_windows:
        return []
    linked: list[str] = []
    for name in SLIM_ROCM_RUNTIME_DIRS:
        source_root = llama_bin_dir / name
        required = name in SLIM_ROCM_REQUIRED_RUNTIME_DIRS
        files = (
            [path for path in source_root.rglob("*") if path.is_file()]
            if source_root.is_dir()
            else []
        )
        if not files:
            if not required:
                # hipBLASLt has no kernels for this target; llama pairs without
                # the catalog and runs, so whisper must pair the same way.
                log(f"slim install: paired ROCm runtime ships no {name} kernel catalog; skipping")
                continue
            missing = "is missing its" if not source_root.is_dir() else "has an empty"
            raise PrebuiltFallback(f"paired ROCm runtime {missing} {name} kernel catalog")
        for source in files:
            _link_or_copy(source, whisper_bin_dir / name / source.relative_to(source_root))
        linked.append(name)
    return linked


def prepare_runtime_payload(staged_root: Path, host: HostInfo, selection: Any) -> Any:
    """Slim installs wire the paired llama ggml runtime into the staged bin dir
    before validation so the activated tree is self-contained; the returned
    selection carries the wired filenames for the marker. Fat installs need
    nothing (the archive carries its ggml) and return None."""
    if getattr(selection, "install_kind", None) != "slim" or not selection.linked_from:
        return None
    source = Path(selection.linked_from)
    destination = runtime_bin_dir(staged_root, host)
    linked = link_ggml_runtime(source, destination, backend = selection.backend)
    linked_dirs = link_runtime_directories(
        source,
        destination,
        backend = selection.backend,
        host = host,
    )
    log(f"slim install: hardlinked {len(linked)} ggml libraries from {selection.linked_from}")
    return replace(
        selection,
        linked_libraries = tuple(linked),
        runtime_wiring_version = SLIM_RUNTIME_WIRING_VERSION,
        linked_runtime_directories = tuple(linked_dirs),
    )


# ── Metadata / marker ──
def metadata_path(install_dir: Path) -> Path:
    return install_dir / METADATA_FILENAME


def selection_from_artifact(
    *,
    published_repo: str,
    release_tag: str,
    manifest: dict[str, Any],
    artifact: dict[str, Any],
    backend: str,
    asset_sha256: str,
) -> InstallSelection:
    selection = core.selection_from_artifact(
        _OPS,
        published_repo = published_repo,
        release_tag = release_tag,
        manifest = manifest,
        artifact = artifact,
        backend = backend,
        asset_sha256 = asset_sha256,
    )
    if artifact.get("install_kind") != "slim":
        return selection
    # A slim selection carries its pairing so the install wiring and marker know
    # which llama runtime provides the ggml libraries.
    runtime = installed_llama_runtime()
    if runtime is None or not llama_runtime_pairs(
        runtime[1],
        artifact.get("requires_llama_tag"),
        installed_ggml_tree = installed_llama_ggml_tree(),
        required_ggml_tree = artifact.get("requires_ggml_tree"),
    ):
        raise PrebuiltFallback(
            "the paired llama.cpp runtime changed underneath the slim whisper selection"
        )
    llama_bin_dir, llama_tag, _profile = runtime
    return replace(
        selection,
        install_kind = "slim",
        paired_llama_tag = llama_tag,
        linked_from = str(llama_bin_dir),
    )


def write_prebuilt_metadata(install_dir: Path, selection: InstallSelection) -> None:
    core.write_prebuilt_metadata(_OPS, install_dir, selection)


def load_whisper_prebuilt_metadata(install_dir: Path) -> dict[str, Any] | None:
    return core.load_prebuilt_metadata(_OPS, install_dir)


def load_prebuilt_metadata(install_dir: Path) -> dict[str, Any] | None:
    return load_whisper_prebuilt_metadata(install_dir)


def existing_install_matches(
    install_dir: Path, host: HostInfo, selection: InstallSelection
) -> bool:
    """Core fingerprint match, hardened for repairability: a marker-matching
    install is only "current" when the server is executable (the sidecar refuses
    non-executable binaries, so setup must repair not skip) and, for slim
    installs, every wired ggml library is still present (else a deleted/moved
    llama dir leaves dictation broken while update reports up to date)."""
    if not core.existing_install_matches(_OPS, install_dir, host, selection):
        return False
    server = installed_server_path(install_dir, host)
    if not host.is_windows and not os.access(server, os.X_OK):
        log(f"existing install at {install_dir} has a non-executable server; reinstalling")
        return False
    marker = load_prebuilt_metadata(install_dir) or {}
    if marker.get("install_kind") == "slim":
        bin_dir = server.parent
        if marker.get("runtime_wiring_version") != SLIM_RUNTIME_WIRING_VERSION:
            log(f"existing slim install at {install_dir} has stale runtime wiring; reinstalling")
            return False
        linked_libraries = marker.get("linked_libraries")
        if (
            not isinstance(linked_libraries, list)
            or not linked_libraries
            or not all(
                isinstance(name, str) and name and Path(name).name == name
                for name in linked_libraries
            )
        ):
            log(f"existing slim install at {install_dir} has invalid runtime wiring; reinstalling")
            return False
        missing = [name for name in linked_libraries if not (bin_dir / name).is_file()]
        if missing:
            log(
                f"existing slim install at {install_dir} is missing wired ggml "
                f"libraries ({', '.join(missing[:4])}); reinstalling"
            )
            return False
        runtime_dirs = marker.get("linked_runtime_directories")
        # Subset plus required, not equality: a target without hipBLASLt kernels
        # wires rocblas alone and is complete (#8364), while an unknown name or
        # a missing rocblas still means stale or hand-edited wiring.
        if (
            marker.get("backend") == "rocm"
            and not host.is_windows
            and (
                not isinstance(runtime_dirs, list)
                or not set(runtime_dirs) <= set(SLIM_ROCM_RUNTIME_DIRS)
                or not set(SLIM_ROCM_REQUIRED_RUNTIME_DIRS) <= set(runtime_dirs)
            )
        ):
            log(f"existing ROCm install at {install_dir} lacks kernel catalogs; reinstalling")
            return False
        missing_dirs = [
            name
            for name in runtime_dirs or []
            if not isinstance(name, str)
            or not (bin_dir / name).is_dir()
            or not any(path.is_file() for path in (bin_dir / name).rglob("*"))
        ]
        if missing_dirs:
            log(
                f"existing slim install at {install_dir} is missing runtime directories "
                f"({', '.join(str(name) for name in missing_dirs[:4])}); reinstalling"
            )
            return False
    return True


# ── Orchestration ──
def resolve_newest_release_tag(repo: str) -> str:
    return core.resolve_newest_release_tag(_OPS, repo)


def resolve_release_tag(published_repo: str, *, published_release_tag: str | None) -> str:
    return core.resolve_release_tag(
        _OPS, published_repo, published_release_tag = published_release_tag
    )


def fetch_release_for_install(
    repo: str, *, published_release_tag: str | None
) -> tuple[ReleaseBundle, dict[str, str]]:
    return core.fetch_release_for_install(_OPS, repo, published_release_tag = published_release_tag)


@dataclass(frozen = True)
class WhisperReleasePlan:
    bundle: ReleaseBundle
    selection: InstallSelection | None
    artifact: dict[str, Any]
    resolved_backend: str
    used_fallback: bool


def _normalized_upstream_tag(value: str) -> str:
    value = value.strip()
    return value[1:] if value[:1].lower() == "v" else value


def _bundle_matches_whisper_tag(bundle: ReleaseBundle, whisper_tag: str) -> bool:
    requested = whisper_tag.strip()
    if not requested or requested.lower() == "latest":
        return True
    upstream = bundle.manifest.get("upstream_tag")
    return isinstance(upstream, str) and _normalized_upstream_tag(
        upstream
    ) == _normalized_upstream_tag(requested)


def _published_release_tags(repo: str) -> list[str]:
    """Published release tags in newest-first order for compatibility search."""
    payload = fetch_json(f"https://api.github.com/repos/{repo}/releases?per_page=100")
    if not isinstance(payload, list):
        raise PrebuiltFallback(f"unexpected releases payload for {repo}")
    releases = [
        release
        for release in payload
        if isinstance(release, dict)
        and not release.get("draft")
        and not release.get("prerelease")
        and isinstance(release.get("tag_name"), str)
        and release.get("tag_name")
    ]
    releases.sort(key = lambda release: release.get("published_at") or "", reverse = True)
    return [str(release["tag_name"]) for release in releases]


def _fetch_release_candidate(repo: str, release_tag: str) -> ReleaseBundle:
    """Fetch one candidate manifest by its deterministic download-host URL."""
    manifest_url = release_asset_download_url(repo, release_tag, MANIFEST_ASSET_NAME)
    try:
        payload = _download_host_json(manifest_url)
        manifest = parse_manifest(payload, label = f"{MANIFEST_ASSET_NAME} in {repo}@{release_tag}")
    except Exception as exc:
        raise PrebuiltFallback(
            f"could not read {MANIFEST_ASSET_NAME} from {repo}@{release_tag}: {exc}"
        ) from exc
    asset_names = {MANIFEST_ASSET_NAME, SHA256_ASSET_NAME}
    asset_names.update(
        str(artifact["asset"])
        for artifact in manifest.get("artifacts", [])
        if isinstance(artifact, dict) and artifact.get("asset")
    )
    asset_urls = {name: release_asset_download_url(repo, release_tag, name) for name in asset_names}
    return ReleaseBundle(
        repo = repo,
        release_tag = release_tag,
        manifest = manifest,
        asset_urls = asset_urls,
    )


def _plan_bundle(
    host: HostInfo,
    bundle: ReleaseBundle,
    checksums: dict[str, str],
    *,
    published_repo: str,
    requested_backend: str,
    verify_checksums: bool,
) -> WhisperReleasePlan:
    artifact, resolved_backend, used_fallback = select_artifact_with_cpu_fallback(
        bundle.manifest, host, requested_backend
    )
    selection = (
        plan_selection(
            host,
            bundle,
            published_repo = published_repo,
            backend = requested_backend,
            checksums = checksums,
        )
        if verify_checksums
        else None
    )
    return WhisperReleasePlan(
        bundle = bundle,
        selection = selection,
        artifact = artifact,
        resolved_backend = resolved_backend,
        used_fallback = used_fallback,
    )


def _release_plan_for_host(
    host: HostInfo,
    *,
    published_repo: str,
    published_release_tag: str | None,
    whisper_tag: str,
    requested_backend: str,
    verify_checksums: bool = True,
) -> WhisperReleasePlan:
    """Select the requested or newest host-compatible published release.

    Explicit published release pins never walk. An upstream ``whisper_tag``
    searches published manifests for that exact upstream version. An unpinned
    macOS install may walk older published releases only when the newest
    manifest has no host-compatible artifact. Checksum and archive failures are
    outside this search and remain hard failures.
    """
    requested_specific_tag = whisper_tag.strip().lower() not in ("", "latest")
    first_bundle: ReleaseBundle | None = None
    first_error: PrebuiltFallback | None = None
    # An upstream version pin searches manifests directly. It must not depend
    # on the unrelated newest release or its checksum index being healthy.
    if not requested_specific_tag or published_release_tag:
        first_bundle, first_checksums = fetch_release_for_install(
            published_repo, published_release_tag = published_release_tag
        )
        if not _bundle_matches_whisper_tag(first_bundle, whisper_tag):
            first_error = PrebuiltFallback(
                f"{published_repo}@{first_bundle.release_tag} targets whisper.cpp "
                f"{first_bundle.manifest.get('upstream_tag')}, not requested {whisper_tag}"
            )
        else:
            try:
                select_artifact_with_cpu_fallback(first_bundle.manifest, host, requested_backend)
            except PrebuiltFallback as exc:
                first_error = exc
            else:
                # Integrity validation happens only after compatibility succeeds.
                # Its failures are never eligible for release walkback.
                return _plan_bundle(
                    host,
                    first_bundle,
                    first_checksums,
                    published_repo = published_repo,
                    requested_backend = requested_backend,
                    verify_checksums = verify_checksums,
                )

    if published_release_tag:
        assert first_error is not None
        raise first_error

    if not requested_specific_tag and not host.is_macos:
        assert first_error is not None
        raise first_error

    for release_tag in _published_release_tags(published_repo):
        if first_bundle is not None and release_tag == first_bundle.release_tag:
            continue
        try:
            bundle = _fetch_release_candidate(published_repo, release_tag)
        except PrebuiltFallback:
            continue
        if not _bundle_matches_whisper_tag(bundle, whisper_tag):
            continue
        try:
            # Establish host compatibility before fetching or trusting this
            # candidate's checksum index. Once selected, integrity failures must
            # stop the install rather than silently downgrade again.
            select_artifact_with_cpu_fallback(bundle.manifest, host, requested_backend)
        except PrebuiltFallback:
            continue
        checksums = fetch_release_checksums(bundle) if verify_checksums else {}
        plan = _plan_bundle(
            host,
            bundle,
            checksums,
            published_repo = published_repo,
            requested_backend = requested_backend,
            verify_checksums = verify_checksums,
        )
        log(
            f"selected compatible published release {bundle.release_tag} "
            f"(upstream {bundle.manifest.get('upstream_tag')})"
        )
        return plan

    if requested_specific_tag:
        raise PrebuiltFallback(
            f"no published {COMPONENT} release for upstream tag {whisper_tag} supports this host"
        )
    assert first_error is not None
    raise first_error


def _install_from_bundle(
    install_dir: Path, host: HostInfo, bundle: ReleaseBundle, selection: InstallSelection
) -> None:
    core.install_from_bundle(_OPS, install_dir, host, bundle, selection)


def plan_selection(
    host: HostInfo,
    bundle: ReleaseBundle,
    *,
    published_repo: str,
    backend: str,
    checksums: dict[str, str],
) -> InstallSelection:
    return core.plan_selection(
        _OPS,
        host,
        bundle,
        published_repo = published_repo,
        backend = backend,
        checksums = checksums,
    )


def install_prebuilt(
    install_dir: Path,
    *,
    whisper_tag: str = "latest",
    published_repo: str = DEFAULT_PUBLISHED_REPO,
    published_release_tag: str | None = None,
    backend: str | None = "auto",
    has_rocm: bool = False,
    rocm_gfx: str | None = None,
    cpu_fallback: bool = False,
    force: bool = False,
) -> int:
    host = apply_host_overrides(
        detect_host(), has_rocm = has_rocm, rocm_gfx = rocm_gfx, force_cpu = cpu_fallback
    )
    requested_backend = resolve_backend(host, backend, cpu_fallback = cpu_fallback)
    os_token, arch_token = host_platform_tokens(host)
    log(
        f"target {COMPONENT} from {published_repo} "
        f"({os_token}-{arch_token}, backend {requested_backend})"
    )
    plan = _release_plan_for_host(
        host,
        published_repo = published_repo,
        published_release_tag = published_release_tag,
        whisper_tag = whisper_tag,
        requested_backend = requested_backend,
    )
    if plan.selection is None:  # pragma: no cover - install plans always verify
        raise PrebuiltFallback("install plan did not validate its checksum entry")
    return core.install_selected_prebuilt(
        _OPS,
        install_dir,
        host = host,
        bundle = plan.bundle,
        selection = plan.selection,
        force = force,
    )


def resolver_payload_extra(artifact: dict[str, Any]) -> dict[str, Any]:
    """Additive --resolve-prebuilt field: whether the selected asset installs
    slim (paired with the llama ggml runtime) or fat (self-contained)."""
    return {"install_kind": "slim" if artifact.get("install_kind") == "slim" else "fat"}


def resolve_prebuilt(
    host: HostInfo,
    *,
    published_repo: str,
    published_release_tag: str | None,
    whisper_tag: str = "latest",
    backend: str | None,
    cpu_fallback: bool,
) -> dict[str, Any]:
    requested_backend = resolve_backend(host, backend, cpu_fallback = cpu_fallback)
    try:
        plan = _release_plan_for_host(
            host,
            published_repo = published_repo,
            published_release_tag = published_release_tag,
            whisper_tag = whisper_tag,
            requested_backend = requested_backend,
            verify_checksums = False,
        )
    except PrebuiltFallback:
        return {"prebuilt_available": False, "repo": published_repo}
    os_token, arch_token = host_platform_tokens(host)
    payload = {
        "prebuilt_available": True,
        "repo": published_repo,
        "release_tag": plan.bundle.release_tag,
        "upstream_tag": plan.bundle.manifest.get("upstream_tag"),
        "backend": plan.resolved_backend,
        "requested_backend": requested_backend,
        "cpu_fallback": plan.used_fallback,
        "asset": str(plan.artifact.get("asset")),
        "os": os_token,
        "arch": arch_token,
        "runtime_line": plan.artifact.get("runtime_line"),
    }
    payload.update(resolver_payload_extra(plan.artifact))
    return payload


# The whisper component descriptor: the declarative form of everything above,
# for descriptor-driven consumers (shared tests, future tooling). The shipped CLI
# runs through this module's wrappers so monkeypatch seams stay intact.
DESCRIPTOR = core.ComponentDescriptor(
    component = COMPONENT,
    log_prefix = "whisper-prebuilt",
    published_repo = DEFAULT_PUBLISHED_REPO,
    manifest_asset_name = MANIFEST_ASSET_NAME,
    sha256_asset_name = SHA256_ASSET_NAME,
    metadata_filename = METADATA_FILENAME,
    user_agent = USER_AGENT,
    supported_backends = SUPPORTED_BACKENDS,
    schema_version = SCHEMA_VERSION,
    fallback_backend = FALLBACK_BACKEND,
    detect_host = detect_host,
    host_platform_tokens = host_platform_tokens,
    server_binary_name = server_binary_name,
    runtime_bin_dir = runtime_bin_dir,
)


def build_arg_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        description = "Install a prebuilt whisper.cpp (whisper-server) for Unsloth Studio"
    )
    parser.add_argument(
        "--install-dir",
        default = None,
        help = (
            "managed whisper.cpp directory, e.g. <UNSLOTH_HOME>/whisper.cpp. Required for an "
            "install; omit it only with --resolve-prebuilt (a read-only probe)."
        ),
    )
    parser.add_argument(
        "--whisper-tag",
        default = os.environ.get("UNSLOTH_WHISPER_TAG", "latest"),
        help = "upstream whisper.cpp tag hint (default 'latest' or $UNSLOTH_WHISPER_TAG)",
    )
    parser.add_argument(
        "--published-repo",
        default = DEFAULT_PUBLISHED_REPO,
        help = f"GitHub repo publishing the prebuilt releases (default {DEFAULT_PUBLISHED_REPO})",
    )
    parser.add_argument(
        "--published-release-tag",
        default = os.environ.get("UNSLOTH_WHISPER_RELEASE_TAG") or None,
        help = "explicit release tag to install (default: the newest published release)",
    )
    parser.add_argument(
        "--backend",
        default = os.environ.get("UNSLOTH_WHISPER_BACKEND", "auto"),
        choices = ("auto", *SUPPORTED_BACKENDS),
        help = "accelerator backend; 'auto' detects from hardware",
    )
    parser.add_argument("--has-rocm", action = "store_true", help = "treat this host as ROCm-capable")
    parser.add_argument("--rocm-gfx", default = None, help = "ROCm gfx target override, e.g. gfx1100")
    parser.add_argument(
        "--cpu-fallback", action = "store_true", help = "force the CPU asset regardless of hardware"
    )
    parser.add_argument(
        "--resolve-prebuilt",
        nargs = "?",
        const = "latest",
        default = None,
        help = "report whether a prebuilt exists for this host without downloading",
    )
    parser.add_argument(
        "--output-format",
        choices = ("plain", "json"),
        default = "plain",
        help = "resolver output format (default plain)",
    )
    parser.add_argument(
        "--force", action = "store_true", help = "reinstall even if the install already matches"
    )
    return parser


def main(argv: list[str] | None = None) -> int:
    global _LOG_TO_STDOUT
    parser = build_arg_parser()
    args = parser.parse_args(argv)

    if args.resolve_prebuilt is not None:
        # Read-only probe: stdout is only the JSON/asset line (setup.sh and
        # whisper_cpp_update.py parse it), so force diagnostics to stderr and map
        # any failure to "not available" rather than a traceback.
        _LOG_TO_STDOUT = False
        try:
            host = apply_host_overrides(
                detect_host(),
                has_rocm = args.has_rocm,
                rocm_gfx = args.rocm_gfx,
                force_cpu = args.cpu_fallback,
            )
            payload = resolve_prebuilt(
                host,
                published_repo = args.published_repo,
                published_release_tag = args.published_release_tag,
                whisper_tag = args.resolve_prebuilt,
                backend = args.backend,
                cpu_fallback = args.cpu_fallback,
            )
        except PrebuiltFallback:
            payload = {"prebuilt_available": False, "repo": args.published_repo}
        except Exception as exc:  # noqa: BLE001 - probe must never crash the caller
            log(f"resolve failed: {exc}")
            payload = {"prebuilt_available": False, "repo": args.published_repo}
        emit_resolver_output(payload, output_format = args.output_format)
        return EXIT_SUCCESS

    # Install path: progress logs go to stdout so setup surfaces them.
    _LOG_TO_STDOUT = True

    if not args.install_dir:
        parser.error("--install-dir is required unless --resolve-prebuilt is used")
    install_dir = Path(args.install_dir).expanduser().resolve()
    try:
        return install_prebuilt(
            install_dir,
            whisper_tag = args.whisper_tag,
            published_repo = args.published_repo,
            published_release_tag = args.published_release_tag,
            backend = args.backend,
            has_rocm = args.has_rocm,
            rocm_gfx = args.rocm_gfx,
            cpu_fallback = args.cpu_fallback,
            force = args.force,
        )
    except BusyInstallConflict as exc:
        log(str(exc))
        return EXIT_BUSY
    except ReleaseCompatibilityError as exc:
        log(f"incompatible release: {exc}")
        return EXIT_INCOMPATIBLE
    except PrebuiltFallback as exc:
        log(f"prebuilt install failed: {exc}")
        return EXIT_ERROR
    except Exception as exc:  # noqa: BLE001
        log(f"unexpected error: {exc}")
        return EXIT_ERROR


if __name__ == "__main__":
    raise SystemExit(main())
