///|
pub struct Options {
  pkg : Package
  directory : String?
  dry_run : Bool
  force : Bool
  skip_compat_check : Bool
}

///|
/// Multi-package CLI settings. The existing Options and install entry point
/// remain available to library callers.
pub struct BatchOptions {
  coordinates : Array[InstallCoordinate]
  directory : String?
  dry_run : Bool
  force : Bool
  skip_compat_check : Bool
  /// One target or an ordered comma-separated list produced by --targets.
  target : String?
  version : String?
  pkg_url : String?
  pkg_fmt : String?
  bin_path : String?
  module_path : String?
  manifest_path : String?
}

///|
pub fn usage() -> String {
  let msg =
    #|moon-binstall — install checksum-verified MoonBit CLI binaries
    #|
    #|Example:
    #|  moon binstall f4ah6o/dsh.mbt
    #|
    #|Usage:
    #|  moon-binstall [--module OWNER/MODULE] ... [options]
    #|  moon-binstall owner/module/package[@version]... [options]
    #|
    #|Coordinates:
    #|  owner/repo[@tag]                 2 parts: install from this GitHub
    #|                                   repository's Releases. MoonBit module
    #|                                   repositories conventionally end in
    #|                                   .mbt — f4ah6o/dsh.mbt is the dsh
    #|                                   module's repository.
    #|  owner/module/package[@version]   3 parts: install a Mooncakes package;
    #|                                   owner/module names the module fetched
    #|                                   from the registry, package is the
    #|                                   executable package inside it.
    #|  with --module, coordinate is package/path[@version]
    #|
    #|Options:
    #|  --version VERSION     select one package version (or use @VERSION per item)
    #|  --target TARGET       override linux-x86_64, linux-aarch64, darwin-x86_64,
    #|                        or darwin-aarch64
    #|  --targets TARGETS     try comma-separated targets in the given order
    #|  --bin-dir DIR         destination directory (default $HOME/.local/bin)
    #|  --bin-path PATH       exact member inside an archive (default: discover)
    #|  --pkg-url TEMPLATE    release asset URL template
    #|  --pkg-fmt FORMAT      bin, tar, tgz, tar.gz, tbz2, tar.bz2, txz,
    #|                        tar.xz, tzstd, tar.zst, or zip
    #|  --manifest-path FILE  read local moon-binstall.json and skip registry lookup
    #|  --force               replace an existing regular executable
    #|  --dry-run             resolve without installing
    #|  --skip-compat-check   install even if the binary cannot run here
    #|
    #|  moon-binstall --help
    #|  moon binstall owner/module/package[@version]... [options]
    #|  moon binstall --help
    #|
    #|Environment: MOON_BINSTALL_DIR (default $HOME/.local/bin)
    #|
    #|Requires: curl >= 8.4.0; tar and matching codecs for tar archives;
    #|          zstd for tzstd; unzip/zipinfo for zip; macOS or Linux.
    #|Every release asset must include GitHub's SHA-256 digest.
  msg
}

///|
pub fn parse_options(argv : ArrayView[String]) -> Options raise {
  let mut coordinate = ""
  let mut directory : String? = None
  let mut dry_run = false
  let mut force = false
  let mut skip_compat_check = false
  let mut idx = 0
  while idx < argv.length() {
    let arg = argv[idx]
    match arg {
      "install" if idx == 0 => ()
      "--dry-run" => dry_run = true
      "--force" => force = true
      "--skip-compat-check" => skip_compat_check = true
      "--bin-dir" => {
        idx = idx + 1
        guard idx < argv.length() && argv[idx] != "" else {
          abort_args("--bin-dir requires a directory")
        }
        directory = Some(argv[idx])
      }
      _ => {
        guard !arg.has_prefix("-") && coordinate == "" else {
          abort_args("unrecognized or duplicate argument: \{arg}")
        }
        coordinate = arg
      }
    }
    idx = idx + 1
  }
  guard coordinate != "" else { abort_args("missing repository coordinate") }
  {
    pkg: parse_package(coordinate),
    directory,
    dry_run,
    force,
    skip_compat_check,
  }
}

///|
pub fn parse_batch_options(argv : ArrayView[String]) -> BatchOptions raise {
  let raw_coordinates : Array[String] = []
  let mut directory : String? = None
  let mut target : String? = None
  let mut version : String? = None
  let mut pkg_url : String? = None
  let mut pkg_fmt : String? = None
  let mut bin_path : String? = None
  let mut module_path : String? = None
  let mut manifest_path : String? = None
  let mut dry_run = false
  let mut force = false
  let mut skip_compat_check = false
  let mut seen_target = false
  let mut seen_targets = false
  let mut seen_dry_run = false
  let mut seen_force = false
  let mut seen_skip_compat_check = false
  let mut idx = 0
  while idx < argv.length() {
    let arg = argv[idx]
    match arg {
      "install" if idx == 0 => ()
      "--dry-run" => {
        guard !seen_dry_run else { abort_args("duplicate argument: --dry-run") }
        dry_run = true
        seen_dry_run = true
      }
      "--force" => {
        guard !seen_force else { abort_args("duplicate argument: --force") }
        force = true
        seen_force = true
      }
      "--skip-compat-check" => {
        guard !seen_skip_compat_check else {
          abort_args("duplicate argument: --skip-compat-check")
        }
        skip_compat_check = true
        seen_skip_compat_check = true
      }
      "--bin-dir" => {
        idx = idx + 1
        guard idx < argv.length() && argv[idx] != "" else {
          abort_args("--bin-dir requires a directory")
        }
        guard directory is None else { abort_args("duplicate argument: --bin-dir") }
        directory = Some(argv[idx])
      }
      "--target" => {
        idx = idx + 1
        guard idx < argv.length() else { abort_args("--target requires a target") }
        guard !seen_target else { abort_args("duplicate argument: --target") }
        guard !seen_targets else {
          abort_args("--target and --targets are mutually exclusive")
        }
        seen_target = true
        validate_target(argv[idx])
        target = Some(argv[idx])
      }
      "--targets" => {
        idx = idx + 1
        guard idx < argv.length() else {
          abort_args("--targets requires a target list")
        }
        guard !seen_targets else { abort_args("duplicate argument: --targets") }
        guard !seen_target else {
          abort_args("--target and --targets are mutually exclusive")
        }
        seen_targets = true
        target = Some(parse_target_list(argv[idx]).join(","))
      }
      "--version" => {
        idx = idx + 1
        guard idx < argv.length() else { abort_args("--version requires a version") }
        guard version is None else { abort_args("duplicate argument: --version") }
        version = Some(argv[idx])
      }
      "--pkg-url" => {
        idx = idx + 1
        guard idx < argv.length() else { abort_args("--pkg-url requires a template") }
        guard pkg_url is None else { abort_args("duplicate argument: --pkg-url") }
        pkg_url = Some(argv[idx])
      }
      "--pkg-fmt" => {
        idx = idx + 1
        guard idx < argv.length() else { abort_args("--pkg-fmt requires a format") }
        guard pkg_fmt is None else { abort_args("duplicate argument: --pkg-fmt") }
        validate_archive_format(argv[idx])
        pkg_fmt = Some(argv[idx])
      }
      "--bin-path" => {
        idx = idx + 1
        guard idx < argv.length() else { abort_args("--bin-path requires a path") }
        guard bin_path is None else { abort_args("duplicate argument: --bin-path") }
        validate_member_path(argv[idx])
        bin_path = Some(argv[idx])
      }
      "--module" => {
        idx = idx + 1
        guard idx < argv.length() else {
          abort_args("--module requires owner/module")
        }
        guard module_path is None else { abort_args("duplicate argument: --module") }
        let parts = argv[idx].split("/").collect()
        guard parts.length() == 2 &&
          valid_id(parts[0].to_owned()) &&
          valid_id(parts[1].to_owned()) else {
          abort_args("--module must be owner/module")
        }
        module_path = Some(argv[idx])
      }
      "--manifest-path" => {
        idx = idx + 1
        guard idx < argv.length() && argv[idx] != "" else {
          abort_args("--manifest-path requires a file")
        }
        guard manifest_path is None else {
          abort_args("duplicate argument: --manifest-path")
        }
        manifest_path = Some(argv[idx])
      }
      _ => {
        guard !arg.has_prefix("-") else {
          abort_args("unrecognized or duplicate argument: \{arg}")
        }
        raw_coordinates.push(arg)
      }
    }
    idx = idx + 1
  }
  guard raw_coordinates.length() > 0 else { abort_args("missing package coordinate") }
  let coordinates : Array[InstallCoordinate] = []
  match module_path {
    Some(module_name) =>
      for raw in raw_coordinates {
        coordinates.push(Mooncakes(parse_module_package(module_name, raw)))
      }
    None =>
      for raw in raw_coordinates {
        coordinates.push(parse_coordinate(raw))
      }
  }
  if version is Some(_) {
    guard coordinates.length() == 1 else {
      abort_args(
        "--version applies to one package; use @VERSION on each package in a batch",
      )
    }
    match coordinates[0] {
      GitHub(pkg) =>
        if pkg.version is Some(_) {
          abort_args("cannot combine --version with @tag")
        }
      Mooncakes(pkg) =>
        if pkg.version is Some(_) {
          abort_args("cannot combine --version with @version")
        }
    }
  }
  if manifest_path is Some(_) {
    guard coordinates.length() == 1 else {
      abort_args("--manifest-path can be used with one package at a time")
    }
    guard coordinates[0] is Mooncakes(_) else {
      abort_args("--manifest-path requires a Mooncakes package coordinate")
    }
  }
  {
    coordinates,
    directory,
    dry_run,
    force,
    skip_compat_check,
    target,
    version,
    pkg_url,
    pkg_fmt,
    bin_path,
    module_path,
    manifest_path,
  }
}

///|
pub fn validate_target(target : String) -> Unit raise {
  guard target == "linux-x86_64" ||
    target == "linux-aarch64" ||
    target == "darwin-x86_64" ||
    target == "darwin-aarch64" else {
    abort_args("unsupported target: \{target}")
  }
}

///|
/// Keep the public BatchOptions shape source-compatible: --targets is stored
/// in its existing target field as a comma-separated, validated sequence.
pub fn parse_target_list(value : String) -> Array[String] raise {
  let entries = value.split(",").collect()
  guard entries.length() > 0 else { abort_args("--targets requires a target list") }
  let targets : Array[String] = []
  for entry in entries {
    let candidate = entry.trim().to_owned()
    guard candidate != "" else { abort_args("--targets contains an empty target") }
    validate_target(candidate)
    guard !targets.contains(candidate) else {
      abort_args("duplicate target in --targets: \{candidate}")
    }
    targets.push(candidate)
  }
  targets
}

///|
async fn require_platform() -> String {
  let (os_status, os_out) = @process.collect_stdout("uname", ["-s"])
  guard os_status == 0 else { abort_compat_msg("uname -s failed") }
  let (cpu_status, cpu_out) = @process.collect_stdout("uname", ["-m"])
  guard cpu_status == 0 else { abort_compat_msg("uname -m failed") }
  platform_key(
    os_out.text().trim().to_owned(),
    cpu_out.text().trim().to_owned(),
  )
}

///|
/// Destination precedence (issue 0004): --bin-dir beats MOON_BINSTALL_DIR,
/// which beats the $HOME/.local/bin default. Returns the directory with a
/// label naming the winning source for the success output.
fn target_directory_with_source(dir_override : String?) -> (String, String) raise {
  match dir_override {
    Some(dir) => {
      guard dir != "" && dir.has_prefix("/") else {
        abort_args("--bin-dir must be an absolute path")
      }
      (dir, "--bin-dir")
    }
    None =>
      match @env.get_env_var("MOON_BINSTALL_DIR") {
        Some(dir) => {
          guard dir != "" && dir.has_prefix("/") else {
            abort_args("MOON_BINSTALL_DIR must be an absolute path")
          }
          (dir, "MOON_BINSTALL_DIR")
        }
        None =>
          match @env.get_env_var("HOME") {
            Some(home) => (home + "/.local/bin", "$HOME/.local/bin")
            None => abort_args("HOME is not set; provide --bin-dir")
          }
      }
  }
}

///|
/// Absolute PATH directories that actually contain an executable named
/// `name`, in PATH order. Empty and relative PATH elements are skipped
/// (they resolve against a caller's cwd, which is not what a bare command
/// name resolves to here) — no executable is ever run to find out.
async fn path_candidates(name : String) -> Array[String] {
  let found : Array[String] = []
  let raw = match @env.get_env_var("PATH") {
    Some(value) => value
    None => ""
  }
  for entry in raw.split(":") {
    let dir = entry.to_owned()
    guard dir.has_prefix("/") else { continue }
    let candidate = dir + "/" + name
    match path_kind_no_follow(candidate) {
      Some(Regular) => found.push(candidate)
      _ => ()
    }
  }
  found
}

///|
/// The absolute path of the currently running moon-binstall executable:
/// argv[0] resolved through PATH for a bare name or through the cwd for a
/// relative path. Only regular files qualify — a symlinked or otherwise
/// non-regular argv[0] yields None, as does a bare name not found on PATH.
async fn running_executable_path() -> String? {
  let argv = @env.args()
  guard argv.length() > 0 else { return None }
  let argv0 = argv[0]
  guard argv0 != "" else { return None }
  if argv0.contains("/") {
    let candidate = if argv0.has_prefix("/") {
      argv0
    } else {
      match @env.current_dir() {
        Some(cwd) => cwd + "/" + argv0
        None => return None
      }
    }
    match path_kind_no_follow(candidate) {
      Some(Regular) => Some(candidate)
      _ => None
    }
  } else {
    let found = path_candidates(argv0)
    if found.length() > 0 {
      Some(found[0])
    } else {
      None
    }
  }
}

///|
/// Whether `plan` is the installer updating itself (issue 0004): the
/// candidate binary is moon-binstall and the resolved repository or module
/// is a moon-binstall distribution point.
fn is_self_update(plan : ResolvedInstallPlan) -> Bool {
  plan.install.binary == "moon-binstall" &&
  (plan.repository.has_suffix("/moon-binstall") ||
    plan.package_key.contains("/moon-binstall/"))
}

///|
/// For a self-update without an explicit destination, the target is the
/// running executable's own directory — never a silent install elsewhere.
/// Unknown identity, symlinks and unresolvable argv[0] refuse with the
/// observed state and a --bin-dir path forward.
async fn self_update_bin_dir(plan : ResolvedInstallPlan) -> String {
  match running_executable_path() {
    Some(path) => {
      guard parent_dir(path) != "" else {
        abort_install(
          Destination, "locate the running executable", plan.install.binary,
          "the running executable has no usable directory",
          action="pass --bin-dir DIR to install elsewhere",
        )
      }
      parent_dir(path)
    }
    None =>
      abort_install(
        Destination, "locate the running executable", plan.install.binary,
        "cannot identify the running moon-binstall executable (argv[0] is bare, relative, missing from PATH, or not a regular file)",
        action="pass --bin-dir DIR to install elsewhere",
      )
  }
}

///|
/// The write-out label marking the `%{json}` transfer report on stderr.
/// Both `%{json}` and `%{header_json}` emit `{`-objects, so each payload
/// carries an explicit prefix instead of positional parsing.
fn report_prefix() -> String {
  "REPORT:"
}

///|
/// The write-out label marking a `%{header_json}` response object.
fn headers_prefix() -> String {
  "HEADERS:"
}

///|
/// Parse the `REPORT:%{json}` write-out line curl prints on stderr.
/// Returns None when no report is present (e.g. curl too old for `%{json}`
/// or the write-out never ran).
fn curl_report(stderr_text : String) -> Json? {
  let mut json_line : String? = None
  for line in stderr_text.split("\n") {
    let trimmed = line.trim().to_owned()
    if trimmed.has_prefix(report_prefix()) {
      json_line = Some(
        trimmed[report_prefix().length():].trim().to_owned(),
      )
    }
  }
  match json_line {
    Some(text) => Some(@json.parse(text)) catch { _ => None }
    None => None
  }
}

///|
/// Parse every `HEADERS:%{header_json}` object on stderr — one per
/// response when redirects were followed. `%{json}` never carries
/// response headers and `%{header_json}` needs curl >= 7.84; older curls
/// print "unknown variable" after the label, which fails JSON parsing
/// and simply yields no entry (a bare 403 is then never called a rate
/// limit, never a false claim). curl emits the object pretty-printed
/// over several lines, so lines accumulate until one parses.
fn curl_headers(stderr_text : String) -> Array[Json] {
  let headers : Array[Json] = []
  let mut pending : String? = None
  for line in stderr_text.split("\n") {
    let trimmed = line.trim().to_owned()
    if trimmed.has_prefix(headers_prefix()) {
      pending = Some(trimmed[headers_prefix().length():].to_owned())
    } else if pending is Some(text) {
      pending = Some(text + "\n" + trimmed)
    } else {
      continue
    }
    match pending {
      Some(text) =>
        try {
          headers.push(@json.parse(text))
          pending = None
        } catch {
          _ => ()
        }
      None => ()
    }
  }
  headers
}

///|
/// The HTTP status observed in a curl `%{json}` report, or None when the
/// server never produced a response (a transport-level failure).
fn curl_http_status(report : Json?) -> Int? {
  match report {
    Some({ "http_code": Number(code, ..), .. }) =>
      if code.to_int() > 0 {
        Some(code.to_int())
      } else {
        None
      }
    _ => None
  }
}

///|
/// Whether response headers report an exhausted rate limit. Only header
/// evidence is used — a bare 403 is never called a rate limit. Each
/// `%{header_json}` object maps lowercase header names to arrays of
/// strings, e.g. {"x-ratelimit-remaining":["0"]}.
fn curl_rate_limited(headers : Array[Json]) -> Bool {
  for object in headers {
    match object {
      { "x-ratelimit-remaining": Array(values), .. } =>
        for value in values {
          if value is String(remaining) &&
            remaining.trim().to_owned() == "0" {
            return true
          }
        }
      { "x-ratelimit-remaining": String(remaining), .. } =>
        if remaining.trim().to_owned() == "0" {
          return true
        }
      _ => ()
    }
  }
  false
}

///|
/// Classify an HTTP status that is neither 2xx nor a 404.
fn[T] abort_http_status(
  what : String,
  url : String,
  code : Int,
  rate_limited : Bool,
) -> T raise InstallError {
  if code == 403 && rate_limited {
    abort_install(
      Transfer, what, url,
      "the server returned HTTP 403 (rate limit reached)",
      action="wait for the rate limit to reset, then retry",
    )
  } else if code == 403 {
    abort_install(
      Transfer, what, url, "the server returned HTTP 403 (Forbidden)",
      action="check that the target is accessible, then retry",
    )
  } else if code == 429 {
    abort_install(
      Transfer, what, url, "the server returned HTTP 429 (rate limited)",
      action="wait, then retry",
    )
  } else if code >= 500 {
    abort_install(
      Transfer, what, url,
      "the server returned HTTP \{code} (server error)",
      action="retry later",
    )
  } else {
    abort_install(
      Transfer, what, url, "the server returned HTTP \{code}",
      action="check the target and retry",
    )
  }
}

///|
/// Classify a curl exit without a usable HTTP status as a communication
/// failure — never as a missing repository or a name mismatch.
fn[T] abort_transport(what : String, url : String, exit_code : Int) -> T raise InstallError {
  abort_install(
    Transfer, what, url, "communication failed (curl exit \{exit_code})",
    action="check the network connection and retry",
  )
}

///|
/// Fail if curl refuses the transfer, rather than treating a 404 body as a
/// binary. Keep every request HTTPS, redirect only to HTTPS, and bound time.
/// HTTP status and transport exit are classified separately.
async fn download(url : String, path : String) -> Unit {
  guard url.has_prefix("https://") else {
    abort_install(
      Coordinate, "prepare download", url,
      "refusing a non-HTTPS download URL",
      action="report the coordinate that produced this URL",
    )
  }
  let args = [
    "--silent", "--show-error", "--location", "--proto", "=https", "--proto-redir",
    "=https", "--max-redirs", "5", "--connect-timeout", "15", "--max-time", "300",
    "--max-filesize", "268435456", "--write-out", "%{stderr}REPORT:%{json}\n%{stderr}HEADERS:%{header_json}", "--output",
    path, url,
  ]
  let response = @shell.Cmd("curl", args).output(timeout_ms=300000)
  let exit_code = response.exit_code()
  let report = curl_report(response.stderr())
  if exit_code != 0 {
    abort_transport("download the release asset", url, exit_code)
  }
  match curl_http_status(report) {
    Some(code) if code >= 200 && code < 300 => ()
    Some(code) => abort_http_status("download the release asset", url, code, curl_rate_limited(curl_headers(response.stderr())))
    None =>
      abort_install(
        Transfer, "download the release asset", url,
        "no HTTP status was observed",
        action="check the network connection and retry",
      )
  }
  let size = @fs.file_size(path)
  guard size > 0L && size <= 268435456L else {
    abort_install(
      Transfer, "download the release asset", url,
      "the downloaded asset has an invalid size",
      action="retry; if it persists the release asset may be malformed",
    )
  }
}

///|
/// Fetch an HTTPS resource. A confirmed HTTP 404 returns None so resolvers
/// keep their "not found" control flow; any other status or a status-less
/// transport failure raises a classified error instead.
async fn fetch_text(url : String, accept_json : Bool, what : String) -> String? {
  guard url.has_prefix("https://") else {
    abort_install(
      Coordinate, "prepare request", url,
      "refusing a non-HTTPS request",
      action="report the coordinate that produced this URL",
    )
  }
  let headers = if accept_json {
    [
      "--header", "Accept: application/vnd.github+json", "--header", "User-Agent: moon-binstall/0.1",
    ]
  } else {
    ["--header", "User-Agent: moon-binstall/0.1"]
  }
  let args = [
      "--silent", "--show-error", "--location", "--proto", "=https", "--proto-redir",
      "=https", "--max-redirs", "5", "--connect-timeout", "15", "--max-time", "30",
      "--max-filesize", "16777216", "--write-out", "%{stderr}REPORT:%{json}\n%{stderr}HEADERS:%{header_json}",
    ] +
    headers +
    [url]
  let response = @shell.Cmd("curl", args).output(
    timeout_ms=30000,
    max_output_bytes=16777216,
  )
  let exit_code = response.exit_code()
  let report = curl_report(response.stderr())
  if exit_code != 0 {
    abort_transport(what, url, exit_code)
  }
  match curl_http_status(report) {
    Some(code) if code >= 200 && code < 300 =>
      Some(@utf8.decode(response.stdout_bytes()))
    Some(404) => None
    Some(code) => abort_http_status(what, url, code, curl_rate_limited(curl_headers(response.stderr())))
    None =>
      abort_install(
        Transfer, what, url, "no HTTP status was observed",
        action="check the network connection and retry",
      )
  }
}

///|
async fn verify_digest(path : String, expected : String) -> Unit {
  guard expected.has_prefix("sha256:") &&
    valid_sha256_hex(expected[7:].to_owned()) else {
    abort_digest("release asset has no valid SHA-256 digest")
  }
  let bytes = @fs.read_file(path).binary()
  let actual = "sha256:" + @crypto.bytes_to_hex_string(@crypto.sha256(bytes))
  guard actual == "sha256:" + expected[7:].to_owned().to_lower() else {
    abort_digest("SHA-256 verification failed: expected \{expected}, got \{actual}")
  }
}

///|
fn github_release_api(
  owner : String,
  repo : String,
  tag : String?,
) -> String raise {
  guard valid_id(owner) && valid_id(repo) else {
    abort_resolve("unsafe GitHub repository")
  }
  let base = "https://api.github.com/repos/\{owner}/\{repo}/releases"
  match tag {
    Some(value) => {
      guard valid_tag(value) else { abort_resolve("unsafe GitHub release tag") }
      base + "/tags/" + value
    }
    None => base + "/latest"
  }
}

///|
fn release_tag(payload : String) -> String raise {
  let document = @json.parse(payload)
  guard document is { "tag_name": String(tag), .. } && valid_tag(tag) else {
    abort_resolve("invalid GitHub release response")
  }
  tag
}

///|
fn version_from_tag(tag : String) -> String {
  if tag.has_prefix("v") {
    tag[1:].to_owned()
  } else {
    tag
  }
}

///|
fn module_leaf(module_path : String) -> String {
  let parts = module_path.split("/").collect()
  parts[parts.length() - 1].to_owned()
}

///|
pub struct ResolvedInstall {
  asset : ReleaseAsset
  binary : String
  format : String
  bin_path : String?
}

///|
/// Internal staging context keeps public ResolvedInstall unchanged while
/// carrying safe default member candidates for archive packages.
priv struct ResolvedInstallPlan {
  install : ResolvedInstall
  archive_candidates : Array[String]
  discover_archive_member : Bool
  /// Matched release target, used for compatibility pre-checks.
  target : String
  /// Publisher-declared minimum glibc version for Linux binaries.
  glibc_min : String?
  /// Resolution source + repository/module for the user-facing summary.
  source_label : String
  /// Resolved GitHub repository (owner/repo), recorded in the receipt.
  repository : String
  /// Identity of the package that owns the binary: the module/package path
  /// for Mooncakes, or the repository name for GitHub coordinates. Used to
  /// spot a different package's same-named binary on update.
  package_key : String
}

///|
/// A deterministic failure a fixture transport reports for a URL: an HTTP
/// status the server returned, or a transport exit with no HTTP response.
#warnings("-unused_constructor")
priv enum FixtureFailure {
  HttpStatus(Int)
  TransportExit(Int)
}

///|
/// Private transport seam for deterministic tests. Production entry points
/// always use HTTPS; fixtures can only be supplied by same-package tests.
#warnings("-struct_never_constructed")
priv struct FixtureTransport {
  responses : Array[(String, String)]
  files : Array[(String, String)]
  failures : Array[(String, FixtureFailure)]
}

///|
#warnings("-unused_constructor")
priv enum Transport {
  Https
  Fixture(FixtureTransport)
}

///|
fn[T] fixture_lookup(
  entries : Array[(String, T)],
  key : String,
) -> T? raise {
  let mut result : T? = None
  for entry in entries {
    if entry.0 == key {
      guard result is None else {
        fail("duplicate fixture transport key: \{key}")
      }
      result = Some(entry.1)
    }
  }
  result
}

///|
async fn fetch_text_using(
  url : String,
  accept_json : Bool,
  what : String,
  transport : Transport,
) -> String? {
  match transport {
    Https => fetch_text(url, accept_json, what)
    Fixture(fixtures) =>
      match fixture_lookup(fixtures.responses, url) {
        Some(body) => Some(body)
        None =>
          match fixture_lookup(fixtures.failures, url) {
            Some(HttpStatus(404)) => None
            Some(HttpStatus(code)) =>
              abort_http_status(what, url, code, false)
            Some(TransportExit(code)) => abort_transport(what, url, code)
            None => None
          }
      }
  }
}

///|
async fn download_using(
  url : String,
  path : String,
  transport : Transport,
) -> Unit {
  match transport {
    Https => download(url, path)
    Fixture(fixtures) => {
      match fixture_lookup(fixtures.failures, url) {
        Some(HttpStatus(code)) =>
          abort_http_status("download the release asset", url, code, false)
        Some(TransportExit(code)) =>
          abort_transport("download the release asset", url, code)
        None => ()
      }
      let source = match fixture_lookup(fixtures.files, url) {
        Some(value) => value
        None => fail("fixture transport has no asset for URL: \{url}")
      }
      @fs.write_file(
        path,
        @fs.read_file(source).binary(),
        create_mode=CreateNew,
      )
    }
  }
}

///|
#warnings("-unused_value")
fn resolve_asset_for_release(
  payload : String,
  owner : String,
  repo : String,
  binary : String,
  module_name : String,
  package_path : String,
  version_value : String,
  target : String,
  config : ArtifactConfig?,
  options : BatchOptions,
) -> ResolvedInstall raise {
  let config_set = match config {
    Some(value) => Some({ base: value, overrides: [], })
    None => None
  }
  resolve_asset_plan_for_release(
    payload, owner, repo, binary, module_name, package_path, version_value, target,
    config_set, options, "github-releases \{owner}/\{repo}",
  ).install
}

///|
fn resolve_asset_plan_for_release(
  payload : String,
  owner : String,
  repo : String,
  binary : String,
  module_name : String,
  package_path : String,
  version_value : String,
  target : String,
  config_set : ArtifactConfigSet?,
  options : BatchOptions,
  source_label : String,
) -> ResolvedInstallPlan raise {
  let tag = release_tag(payload)
  let target_candidates = match options.target {
    Some(value) => parse_target_list(value)
    None => {
      validate_target(target)
      [target]
    }
  }
  match config_set {
    Some(config) =>
      validate_artifact_config_set_for_release(
        config,
        owner,
        repo,
        module_name,
        package_path,
        binary,
        version_value,
        tag,
        options.pkg_fmt,
      )
    None => ()
  }
  let mut selected_asset : (ReleaseAsset, String, ArtifactConfig?)? = None
  for candidate_target in target_candidates {
    // CLI options override a target-specific value, which in turn overrides
    // the package default. Resolve this for each ordered target independently.
    let candidate_config = match config_set {
      Some(config) => Some(artifact_config_for_target(config, candidate_target))
      None => None
    }
    let selected_template = match options.pkg_url {
      Some(value) => Some(value)
      None =>
        match candidate_config {
          Some(item) => item.pkg_url
          None => None
        }
    }
    let requested_format = match options.pkg_fmt {
      Some(value) => Some(value)
      None =>
        match candidate_config {
          Some(item) => item.pkg_fmt
          None => None
        }
    }
    let format_hint = match requested_format {
      Some(value) => value
      None =>
        match selected_template {
          Some(template) => infer_archive_format(template)
          None => "bin"
        }
    }
    let names = match selected_template {
      Some(template) => {
        let suffix = archive_suffix(format_hint)
        let expanded = expand_artifact_template(
          template, owner, repo, module_name, package_path, binary, version_value,
          candidate_target, suffix,
        )
        [artifact_url_asset_name(expanded, owner, repo, tag)]
      }
      None => {
        let names = default_artifact_names_for_format(
          binary, version_value, candidate_target, requested_format,
        )
        if module_name != binary {
          let module_names = default_artifact_names_for_format(
            module_name, version_value, candidate_target, requested_format,
          )
          for name in module_names {
            if !names.contains(name) {
              names.push(name)
            }
          }
        }
        names
      }
    }
    match
      resolve_release_names_optional(payload, owner, repo, names, Some(tag)) {
      Some(asset) => {
        selected_asset = Some((asset, candidate_target, candidate_config))
        break
      }
      None => ()
    }
  }
  let (asset, matched_target, matched_config) = match selected_asset {
    Some(value) => value
    None => abort_resolve("no matching prebuilt asset in release \{tag}")
  }
  let requested_format = match options.pkg_fmt {
    Some(value) => Some(value)
    None =>
      match matched_config {
        Some(item) => item.pkg_fmt
        None => None
      }
  }
  let format = match requested_format {
    Some(value) => value
    None => infer_archive_format(asset.name)
  }
  let bin_path_template = match options.bin_path {
    Some(value) => Some(value)
    None =>
      match matched_config {
        Some(item) => item.bin_path
        None => None
      }
  }
  let discover_archive_member = format != "bin" && bin_path_template is None
  let bin_path = if format == "bin" {
    None
  } else {
    Some(
      match bin_path_template {
        Some(value) =>
          expand_artifact_member_template(
            value,
            owner,
            repo,
            module_name,
            package_path,
            binary,
            version_value,
            matched_target,
            archive_suffix(format),
          )
        None => binary
      },
    )
  }
  if bin_path is Some(path) {
    validate_member_path(path)
  }
  let archive_candidates = if discover_archive_member {
    default_archive_member_candidates(
      module_name, package_path, binary, version_value, matched_target,
    )
  } else {
    []
  }
  {
    install: { asset, binary, format, bin_path, },
    archive_candidates,
    discover_archive_member,
    target: matched_target,
    glibc_min: match matched_config {
      Some(item) => item.glibc_min
      None => None
    },
    source_label,
    repository: "\{owner}/\{repo}",
    package_key: "\{module_name}/\{package_path}",
  }
}

///|
/// Validate every declared target template against the repository and tag,
/// even if a CLI option or an earlier target later wins selection.
fn validate_artifact_config_set_for_release(
  config_set : ArtifactConfigSet,
  owner : String,
  repo : String,
  module_name : String,
  package_path : String,
  binary : String,
  version : String,
  tag : String,
  cli_format : String?,
) -> Unit raise {
  for
    target in [
      "linux-x86_64", "linux-aarch64", "darwin-x86_64", "darwin-aarch64",
    ] {
    let config = artifact_config_for_target(config_set, target)
    let format_hint = match cli_format {
      Some(value) => value
      None =>
        match config.pkg_fmt {
          Some(value) => value
          None =>
            match config.pkg_url {
              Some(template) => infer_archive_format(template)
              None => "bin"
            }
        }
    }
    match config.pkg_url {
      Some(template) => {
        let expanded = expand_artifact_template(
          template,
          owner,
          repo,
          module_name,
          package_path,
          binary,
          version,
          target,
          archive_suffix(format_hint),
        )
        ignore(artifact_url_asset_name(expanded, owner, repo, tag))
      }
      None => ()
    }
    match config.bin_path {
      Some(template) => {
        let expanded = expand_artifact_member_template(
          template,
          owner,
          repo,
          module_name,
          package_path,
          binary,
          version,
          target,
          archive_suffix(format_hint),
        )
        validate_member_path(expanded)
      }
      None => ()
    }
  }
}

///|
#warnings("-unused_value")
async fn resolve_package(
  coordinate : InstallCoordinate,
  options : BatchOptions,
  target : String,
  workspace : String,
  index : Int,
  transport : Transport,
) -> ResolvedInstall {
  resolve_package_plan(coordinate, options, target, workspace, index, transport).install
}

///|
/// Describe a coordinate for user-facing resolution output.
fn describe_coordinate(coordinate : InstallCoordinate) -> String {
  match coordinate {
    GitHub(pkg) => {
      let suffix = match pkg.version {
        Some(tag) => "@\{tag}"
        None => ""
      }
      "\{pkg.owner}/\{pkg.repo}\{suffix}"
    }
    Mooncakes(pkg) => {
      let suffix = match pkg.version {
        Some(version) => "@\{version}"
        None => ""
      }
      "\{pkg.module_path}/\{pkg.package_path}\{suffix}"
    }
  }
}

///|
/// Read-only `.mbt` candidate check (issue 0002): only when the requested
/// repository returned a confirmed 404 does this probe `owner/repo.mbt`'s
/// latest release. A confirmed release yields a suggestion; any other
/// outcome yields none. Never auto-switches coordinates.
async fn suggest_github_repo(
  owner : String,
  repo : String,
  transport : Transport,
) -> String? {
  guard !repo.has_suffix(".mbt") else { return None }
  let candidate = repo + ".mbt"
  let url = github_release_api(owner, candidate, None)
  let payload = fetch_text_using(
    url, true, "check a repository candidate", transport,
  ) catch {
    _ => return None
  }
  match payload {
    Some(_) => Some("\{owner}/\{candidate}")
    None => None
  }
}

///|
async fn resolve_package_plan(
  coordinate : InstallCoordinate,
  options : BatchOptions,
  target : String,
  workspace : String,
  index : Int,
  transport : Transport,
) -> ResolvedInstallPlan {
  match coordinate {
    GitHub(pkg) => {
      let version = match options.version {
        Some(value) => Some(value)
        None => pkg.version
      }
      let api = github_release_api(pkg.owner, pkg.repo, version)
      let payload = match
        fetch_text_using(api, true, "query the GitHub release", transport) {
        Some(value) => value
        None => {
          let suggestion = match
            suggest_github_repo(pkg.owner, pkg.repo, transport) {
            Some(candidate) => "\n  hint: did you mean \{candidate}?"
            None => ""
          }
          abort_install(
            Resolve, "query the GitHub release", api,
            "no release was confirmed for \{pkg.owner}/\{pkg.repo}\{suggestion}",
            action="check the repository name and tag, then retry",
          )
        }
      }
      let tag = release_tag(payload)
      match version {
        Some(expected) if tag != expected =>
          abort_install(
            Resolve, "query the GitHub release", api,
            "GitHub returned tag \{tag}, expected \{expected}",
            action="check the requested tag, then retry",
          )
        _ => ()
      }
      let version_for_template = version_from_tag(tag)
      resolve_asset_plan_for_release(
        payload,
        pkg.owner,
        pkg.repo,
        pkg.binary,
        pkg.repo,
        pkg.repo,
        version_for_template,
        target,
        None,
        options,
        "github-releases \{pkg.owner}/\{pkg.repo}",
      )
    }
    Mooncakes(pkg) => {
      let local_manifest = match options.manifest_path {
        Some(path) => Some(@fs.read_file(path).text())
        None => None
      }
      let (owner, repo, version, config_set) = match local_manifest {
        Some(payload) => {
          let repository = manifest_repository(payload, pkg.module_path)
          let (owner, repo) = parse_github_repository(repository)
          let version = match options.version {
            Some(value) => Some(value)
            None =>
              match pkg.version {
                Some(value) => Some(value)
                None => manifest_version(payload)
              }
          }
          let config_set = parse_artifact_config_set(
            payload,
            pkg.package_path,
            pkg.binary,
          )
          (owner, repo, version, config_set)
        }
        None => {
          let requested_version = match options.version {
            Some(value) => Some(value)
            None => pkg.version
          }
          let metadata_url = mooncakes_manifest_url(
            pkg.module_path,
            requested_version,
          )
          let metadata_payload = match
            fetch_text_using(
              metadata_url, false, "query the Mooncakes registry", transport,
            ) {
            Some(value) => value
            None =>
              abort_install(
                Resolve, "query the Mooncakes registry", metadata_url,
                "the Mooncakes module release was not found",
                action="check the module path and version, then retry",
              )
          }
          let registry_release = resolve_registry_release(
            metadata_payload,
            pkg.module_path,
            requested_version,
          )
          let (owner, repo) = parse_github_repository(
            registry_release.repository,
          )
          let source_path = workspace + "/module-\{index}.zip"
          download_using(
            mooncakes_source_url(pkg.module_path, registry_release.version),
            source_path,
            transport,
          )
          verify_sha256_hex(source_path, registry_release.checksum)
          let config_bytes = read_zip_member_optional_with_limit(
            source_path, "moon-binstall.json", 1048576,
          )
          let config_set = match config_bytes {
            Some(bytes) =>
              parse_artifact_config_set(
                @utf8.decode(bytes),
                pkg.package_path,
                pkg.binary,
              )
            None => None
          }
          (owner, repo, Some(registry_release.version), config_set)
        }
      }
      let binary = match config_set {
        Some(item) => item.base.binary
        None => pkg.binary
      }
      match version {
        Some(value) => {
          let preferred = if value.has_prefix("v") {
            value
          } else {
            "v" + value
          }
          let preferred_url = github_release_api(owner, repo, Some(preferred))
          let (payload, expected_tag) = match
            fetch_text_using(
              preferred_url, true, "query the GitHub release", transport,
            ) {
            Some(payload) => (payload, preferred)
            None => {
              if preferred == value {
                abort_install(
                  Resolve, "query the GitHub release", preferred_url,
                  "no GitHub release was found for \{pkg.module_path}@\{value}",
                  action="check the coordinate and version, then retry",
                )
              }
              let fallback_url = github_release_api(owner, repo, Some(value))
              match
                fetch_text_using(
                  fallback_url, true, "query the GitHub release", transport,
                ) {
                Some(payload) => (payload, value)
                None =>
                  abort_install(
                    Resolve, "query the GitHub release", fallback_url,
                    "no GitHub release was found for \{pkg.module_path}@\{value}",
                    action="check the coordinate and version, then retry",
                  )
              }
            }
          }
          let actual_tag = release_tag(payload)
          guard actual_tag == expected_tag else {
            abort_install(
              Resolve, "query the GitHub release", preferred_url,
              "GitHub returned tag \{actual_tag}, expected \{expected_tag}",
              action="check the requested tag, then retry",
            )
          }
          resolve_asset_plan_for_release(
            payload,
            owner,
            repo,
            binary,
            module_leaf(pkg.module_path),
            pkg.package_path,
            version_from_tag(actual_tag),
            target,
            config_set,
            options,
            "mooncakes+github-releases \{pkg.module_path}/\{pkg.package_path} (repository \{owner}/\{repo})",
          )
        }
        None => {
          let api = github_release_api(owner, repo, None)
          let payload = match
            fetch_text_using(api, true, "query the GitHub release", transport) {
            Some(value) => value
            None =>
              abort_install(
                Resolve, "query the GitHub release", api,
                "no GitHub release was found for \{pkg.module_path}",
                action="check the coordinate, then retry",
              )
          }
          let tag = release_tag(payload)
          resolve_asset_plan_for_release(
            payload,
            owner,
            repo,
            binary,
            module_leaf(pkg.module_path),
            pkg.package_path,
            version_from_tag(tag),
            target,
            config_set,
            options,
            "mooncakes+github-releases \{pkg.module_path}/\{pkg.package_path} (repository \{owner}/\{repo})",
          )
        }
      }
    }
  }
}

///|
async fn path_kind_no_follow(path : String) -> @fs.FileKind? {
  Some(@fs.kind(path, follow_symlink=false)) catch {
    @os_error.OSError(_) as err if err.is_ENOENT() => None
    err => raise err
  }
}

///|
/// File kind following symlinks — what a shell's exec resolution sees.
async fn path_kind(path : String) -> @fs.FileKind? {
  Some(@fs.kind(path)) catch {
    @os_error.OSError(_) as err if err.is_ENOENT() => None
    err => raise err
  }
}

///|
async fn check_destination(path : String, force : Bool) -> Unit {
  match path_kind_no_follow(path) {
    Some(Regular) if force => ()
    Some(Regular) => abort_dest("already exists: \{path} (use --force to replace)")
    Some(_) => abort_dest("refusing to replace a non-regular file: \{path}")
    None => ()
  }
}

///|
pub struct StagedInstall {
  destination : String
  staging : String
  staging_dir : String
  binary_digest : String
}

///|
/// Create an exclusive private directory beside the destination. Renaming
/// from this directory stays on the destination filesystem and never shares
/// staging paths between concurrent invocations.
async fn create_staging_directory_at(
  bin_dir : String,
  index : Int,
  stamp : String,
) -> String {
  let mut attempt = 0
  while attempt < 10000 {
    let path = bin_dir + "/.moon-binstall-stage-\{stamp}-\{index}-\{attempt}"
    try {
      @fs.mkdir(path, permission=0o700, allow_exist=false)
      return path
    } catch {
      @os_error.OSError(_) as err if err.is_EEXIST() => attempt = attempt + 1
      err => raise err
    }
  }
  abort_fs("could not allocate a private staging directory")
}

///|
/// Return the ELF machine type when `binary` is a little-endian ELF file,
/// or None for other formats. e_machine sits at offset 18.
fn elf_machine(binary : Bytes) -> Int? {
  guard binary.length() >= 20 &&
    binary[0].to_int() == 0x7f &&
    binary[1] == b'E' &&
    binary[2] == b'L' &&
    binary[3] == b'F' &&
    binary[5].to_int() == 1 else {
    return None
  }
  Some(binary[18].to_int() | (binary[19].to_int() << 8))
}

///|
/// Dependencies extracted from a little-endian ELF64 file without executing
/// it: the PT_INTERP loader path, DT_NEEDED sonames, DT_RUNPATH/DT_RPATH
/// search paths, required symbol versions by provider library, and the
/// version names this file itself defines.
priv struct ElfDeps {
  interp : String?
  needed : Array[String]
  mut runpath : String?
  // True when `runpath` came from DT_RPATH because DT_RUNPATH is absent —
  // legacy RPATH is searched before LD_LIBRARY_PATH, RUNPATH after it.
  mut rpath_first : Bool
  verneed : Array[(String, String)]
  verdef : Array[String]
  // The object's own DT_SONAME when it declares one: the loader registers
  // a loaded shared object under this name, so later dependencies that
  // request it reuse the object even though the original lookup name
  // differed.
  mut soname : String?
}

///|
fn elf_u16le(binary : Bytes, offset : Int) -> Int {
  binary[offset].to_int() | (binary[offset + 1].to_int() << 8)
}

///|
fn elf_u32le(binary : Bytes, offset : Int) -> Int {
  binary[offset].to_int() |
  (binary[offset + 1].to_int() << 8) |
  (binary[offset + 2].to_int() << 16) |
  (binary[offset + 3].to_int() << 24)
}

///|
fn elf_u64le(binary : Bytes, offset : Int) -> Int64 {
  let mut value = 0L
  for i = 0; i < 8; i = i + 1 {
    value = value | (binary[offset + i].to_int().to_int64() << (i * 8))
  }
  value
}

///|
fn elf_cstr(binary : Bytes, offset : Int) -> String {
  let bytes : Array[Byte] = []
  let mut cursor = offset
  while cursor < binary.length() && binary[cursor].to_int() != 0 {
    bytes.push(binary[cursor])
    cursor = cursor + 1
  }
  @utf8.decode_lossy(Bytes::from_array(bytes))
}

///|
/// Map an ELF virtual address to a file offset through the PT_LOAD segments.
fn elf_vaddr_offset(
  loads : Array[(Int64, Int64, Int64)],
  target : Int64,
) -> Int64? {
  for segment in loads {
    let (vaddr, offset, filesz) = segment
    if target >= vaddr && target < vaddr + filesz {
      return Some(offset + (target - vaddr))
    }
  }
  None
}

///|
/// Parse a little-endian ELF64 file's program headers and .dynamic section
/// for its runtime dependencies, or None for other formats. Malformed or
/// truncated input yields None rather than an error — the caller then
/// skips the check instead of rejecting the artifact.
fn parse_elf64_deps(binary : Bytes) -> ElfDeps? {
  guard binary.length() >= 64 &&
    binary[0].to_int() == 0x7f &&
    binary[1] == b'E' &&
    binary[2] == b'L' &&
    binary[3] == b'F' &&
    binary[4].to_int() == 2 &&
    binary[5].to_int() == 1 else {
    return None
  }
  let phoff = elf_u64le(binary, 32).to_int()
  let phentsize = elf_u16le(binary, 54)
  let phnum = elf_u16le(binary, 56)
  guard phoff >= 0 && phnum > 0 && phnum < 4096 && phentsize >= 56 else {
    return None
  }
  let loads : Array[(Int64, Int64, Int64)] = []
  let mut interp : String? = None
  let mut dyn_offset = -1
  let mut dyn_size = 0L
  for i = 0; i < phnum; i = i + 1 {
    let p = phoff + i * phentsize
    guard p + 56 <= binary.length() else { return None }
    let ptype = elf_u32le(binary, p)
    if ptype == 1 {
      loads.push(
        (
          elf_u64le(binary, p + 16),
          elf_u64le(binary, p + 8),
          elf_u64le(binary, p + 32),
        ),
      )
    } else if ptype == 3 {
      let offset = elf_u64le(binary, p + 8)
      let size = elf_u64le(binary, p + 32)
      if size > 0L &&
        offset >= 0L &&
        offset + size <= binary.length().to_int64() {
        interp = Some(elf_cstr(binary, offset.to_int()))
      }
    } else if ptype == 2 {
      dyn_offset = elf_u64le(binary, p + 8).to_int()
      dyn_size = elf_u64le(binary, p + 32)
    }
  }
  let deps : ElfDeps = {
    interp,
    needed: [],
    runpath: None,
    rpath_first: false,
    verneed: [],
    verdef: [],
    soname: None,
  }
  if dyn_offset >= 0 {
    parse_dynamic_deps(binary, dyn_offset, dyn_size, loads, deps)
  }
  Some(deps)
}

///|
/// Walk the .dynamic entries for DT_NEEDED, DT_STRTAB, DT_RPATH,
/// DT_RUNPATH, DT_VERNEED/NUM and DT_VERDEF/NUM, resolving string-table
/// references through PT_LOAD segments into `deps`.
fn parse_dynamic_deps(
  binary : Bytes,
  dyn_offset : Int,
  dyn_size : Int64,
  loads : Array[(Int64, Int64, Int64)],
  deps : ElfDeps,
) -> Unit {
  let needed_offsets : Array[Int] = []
  let mut soname_offset = -1L
  let mut strtab_vaddr = -1L
  let mut rpath_offset = -1L
  let mut runpath_offset = -1L
  let mut verneed_vaddr = -1L
  let mut verneed_num = 0L
  let mut verdef_vaddr = -1L
  let mut verdef_num = 0L
  let count = (dyn_size / 16).to_int()
  for i = 0; i < count; i = i + 1 {
    let entry = dyn_offset + i * 16
    if entry + 16 > binary.length() {
      break
    }
    let tag = elf_u64le(binary, entry)
    let value = elf_u64le(binary, entry + 8)
    if tag == 0L {
      break
    } else if tag == 1L {
      needed_offsets.push(value.to_int())
    } else if tag == 5L {
      strtab_vaddr = value
    } else if tag == 14L {
      // DT_SONAME
      soname_offset = value
    } else if tag == 15L {
      // DT_RPATH
      rpath_offset = value
    } else if tag == 29L {
      // DT_RUNPATH
      runpath_offset = value
    } else if tag == 1879048188L {
      // DT_VERDEF (0x6ffffffc)
      verdef_vaddr = value
    } else if tag == 1879048189L {
      // DT_VERDEFNUM (0x6ffffffd)
      verdef_num = value
    } else if tag == 1879048190L {
      // DT_VERNEED (0x6ffffffe)
      verneed_vaddr = value
    } else if tag == 1879048191L {
      // DT_VERNEEDNUM (0x6fffffff)
      verneed_num = value
    }
  }
  guard strtab_vaddr >= 0L else { return }
  let strtab = match elf_vaddr_offset(loads, strtab_vaddr) {
    Some(base) => base.to_int()
    None => return
  }
  for offset in needed_offsets {
    deps.needed.push(elf_cstr(binary, strtab + offset))
  }
  if soname_offset >= 0L {
    let soname = elf_cstr(binary, strtab + soname_offset.to_int())
    if soname != "" {
      deps.soname = Some(soname)
    }
  }
  // DT_RUNPATH supersedes DT_RPATH in the loader search order.
  if runpath_offset >= 0L {
    deps.runpath = Some(elf_cstr(binary, strtab + runpath_offset.to_int()))
  } else if rpath_offset >= 0L {
    deps.runpath = Some(elf_cstr(binary, strtab + rpath_offset.to_int()))
    deps.rpath_first = true
  }
  if verneed_vaddr >= 0L {
    match elf_vaddr_offset(loads, verneed_vaddr) {
      Some(base) =>
        collect_verneed(
          binary,
          base.to_int(),
          verneed_num.to_int(),
          strtab,
          deps.verneed,
        )
      None => ()
    }
  }
  if verdef_vaddr >= 0L {
    match elf_vaddr_offset(loads, verdef_vaddr) {
      Some(base) =>
        collect_verdef(
          binary,
          base.to_int(),
          verdef_num.to_int(),
          strtab,
          deps.verdef,
        )
      None => ()
    }
  }
}

///|
/// Collect (provider soname, required version) pairs from .gnu.version_r.
/// Each Elf64_Verneed is 16 bytes (vn_file/vn_aux/vn_next are u32) and each
/// Elf64_Vernaux is 16 bytes (vna_name/vna_next are u32). All version
/// namespaces are recorded — GLIBCXX_*, CXXABI_* and others, not just GLIBC_*.
fn collect_verneed(
  binary : Bytes,
  offset : Int,
  count : Int,
  strtab : Int,
  out : Array[(String, String)],
) -> Unit {
  let mut cursor = offset
  for i = 0; i < count; i = i + 1 {
    if cursor + 16 > binary.length() {
      break
    }
    let vn_cnt = elf_u16le(binary, cursor + 2)
    let provider = elf_cstr(binary, strtab + elf_u32le(binary, cursor + 4))
    let vn_aux = elf_u32le(binary, cursor + 8)
    let vn_next = elf_u32le(binary, cursor + 12)
    let mut aux = cursor + vn_aux
    for j = 0; j < vn_cnt; j = j + 1 {
      if aux + 16 > binary.length() {
        break
      }
      let version = elf_cstr(binary, strtab + elf_u32le(binary, aux + 8))
      if version != "" {
        out.push((provider, version))
      }
      let vna_next = elf_u32le(binary, aux + 12)
      if vna_next == 0 {
        break
      }
      aux = aux + vna_next
    }
    if vn_next == 0 {
      break
    }
    cursor = cursor + vn_next
  }
}

///|
/// Collect the version names a file defines in .gnu.version_d. Each
/// Elf64_Verdef is 20 bytes (vd_aux/vd_next are u32) and each Elf64_Verdaux
/// is 8 bytes (vda_name/vda_next are u32).
fn collect_verdef(
  binary : Bytes,
  offset : Int,
  count : Int,
  strtab : Int,
  out : Array[String],
) -> Unit {
  let mut cursor = offset
  for i = 0; i < count; i = i + 1 {
    if cursor + 20 > binary.length() {
      break
    }
    let vd_cnt = elf_u16le(binary, cursor + 6)
    let vd_aux = elf_u32le(binary, cursor + 12)
    let vd_next = elf_u32le(binary, cursor + 16)
    let mut aux = cursor + vd_aux
    for j = 0; j < vd_cnt; j = j + 1 {
      if aux + 8 > binary.length() {
        break
      }
      let name = elf_cstr(binary, strtab + elf_u32le(binary, aux))
      if name != "" {
        out.push(name)
      }
      let vda_next = elf_u32le(binary, aux + 4)
      if vda_next == 0 {
        break
      }
      aux = aux + vda_next
    }
    if vd_next == 0 {
      break
    }
    cursor = cursor + vd_next
  }
}

///|
/// The host Linux kernel identifier (true when `uname -s` reports Linux).
async fn host_linux() -> Bool {
  let (status, out) = @process.collect_stdout("uname", ["-s"]) catch {
    _ => return false
  }
  status == 0 && out.text().trim() == "Linux"
}

///|
/// The host ELF e_machine value for the architectures moon-binstall ships,
/// or None on other platforms.
async fn host_machine() -> Int? {
  let (status, out) = @process.collect_stdout("uname", ["-m"]) catch {
    _ => return None
  }
  guard status == 0 else { return None }
  match out.text().trim() {
    "x86_64" | "amd64" => Some(62)
    "aarch64" | "arm64" => Some(183)
    _ => None
  }
}

///|
/// musl loader paths for the architectures moon-binstall ships. Their
/// presence means the host runs musl even when no `ldd` exists.
fn musl_loader_paths() -> Array[String] {
  [
    "/lib/ld-musl-x86_64.so.1", "/lib/ld-musl-aarch64.so.1", "/lib/libc.musl-x86_64.so.1",
    "/lib/libc.musl-aarch64.so.1",
  ]
}

///|
async fn musl_by_loader() -> String? {
  for path in musl_loader_paths() {
    if @fs.exists(path) {
      return Some("musl")
    }
  }
  None
}

///|
/// Identify the host libc: "musl", or a glibc version like "2.35".
/// `ldd --version` output is read from both streams because musl's ldd
/// prints its banner on stderr and exits nonzero. When ldd is absent or
/// unhelpful, known musl loader paths are probed instead — no executable
/// under inspection is ever run.
async fn host_libc() -> String? {
  let output = @shell.Cmd("ldd", ["--version"]).output(
    timeout_ms=15000,
    max_output_bytes=65536,
  ) catch {
    _ => return musl_by_loader()
  }
  match parse_host_libc(output.stdout() + "\n" + output.stderr()) {
    Some(value) => Some(value)
    None => musl_by_loader()
  }
}

///|
/// Soname → candidate paths of the host loader cache (`ldconfig -p`,
/// non-executing — it only reads /etc/ld.so.cache). One soname can map to
/// several ABI variants on multilib hosts (e.g. x86-64 and i386 libc.so.6),
/// so every candidate is kept in listed order for ABI-aware selection.
async fn ldconfig_map() -> Map[String, Array[String]] {
  let map : Map[String, Array[String]] = Map([])
  let output = @shell.Cmd("ldconfig", ["-p"]).output(
    timeout_ms=15000,
    max_output_bytes=4194304,
  ) catch {
    _ => return map
  }
  for line in output.stdout().split("\n") {
    let text = line.trim().to_owned()
    if !text.contains("=>") {
      continue
    }
    let parts = text.split("=>").collect()
    let soname = parts[0].trim().split(" ").iter().next().unwrap_or("")
    let path = parts[1].trim().to_owned()
    if soname != "" && path != "" {
      match map.get(soname.to_owned()) {
        Some(list) => if !list.contains(path) { list.push(path) }
        None => map[soname.to_owned()] = [path]
      }
    }
  }
  map
}

///|
/// Library directories checked when no ldconfig cache is available.
async fn library_dirs() -> Array[String] {
  let dirs = ["/lib", "/usr/lib", "/usr/local/lib", "/lib64", "/usr/lib64"]
  let (status, out) = @process.collect_stdout("uname", ["-m"]) catch {
    _ => return dirs
  }
  if status == 0 {
    let triplet = match out.text().trim() {
      "x86_64" | "amd64" => "x86_64-linux-gnu"
      "aarch64" | "arm64" => "aarch64-linux-gnu"
      _ => ""
    }
    if triplet != "" {
      dirs.push("/lib/" + triplet)
      dirs.push("/usr/lib/" + triplet)
    }
  }
  dirs
}

///|
/// The single directory name `$LIB`/`${LIB}` expands to on this host.
/// glibc substitutes exactly one distro-specific value — "lib/"
/// on Debian multiarch, "lib64" on Fedora-style layouts — so probing
/// which layout directory exists picks the same expansion the real
/// loader would make; offering several candidates would accept a
/// library the loader cannot actually find.
async fn lib_token_names(host : Int) -> Array[String] {
  let triplet = match host {
    62 => "x86_64-linux-gnu"
    183 => "aarch64-linux-gnu"
    _ => ""
  }
  if triplet != "" && @fs.exists("/lib/" + triplet) {
    return ["lib/" + triplet]
  }
  if @fs.exists("/lib64") {
    return ["lib64"]
  }
  ["lib"]
}

///|
/// Expand the DT_RUNPATH/DT_RPATH search list into directories to probe.
/// `$ORIGIN` and the equivalent `${ORIGIN}` resolve against the directory
/// the object will live in (the binary's final install directory, or the
/// directory of a resolved transitive provider). `$LIB`/`${LIB}` expands
/// to each `lib_tokens` directory name in turn. Entries still containing
/// other `$` tokens ($PLATFORM) or relative paths are ignored — they
/// resolve against an unknown context.
fn expand_runpath(
  runpath : String?,
  origin : String,
  lib_tokens : Array[String],
) -> Array[String] {
  let dirs : Array[String] = []
  let value = match runpath {
    Some(text) => text
    None => return dirs
  }
  for entry in value.split(":") {
    let dir = entry.trim().to_owned()
    if dir == "" {
      continue
    }
    if dir.contains("$") {
      let expanded = dir
        .replace_all(old="${ORIGIN}", new=origin)
        .replace_all(old="$ORIGIN", new=origin)
      if expanded.contains("${LIB}") || expanded.contains("$LIB") {
        // One rpath entry becomes several candidate directories, one per
        // plausible $LIB value, kept in preference order.
        for token in lib_tokens {
          let candidate = expanded
            .replace_all(old="${LIB}", new=token)
            .replace_all(old="$LIB", new=token)
          if !candidate.contains("$") && candidate.has_prefix("/") {
            dirs.push(candidate)
          }
        }
      } else if !expanded.contains("$") && expanded.has_prefix("/") {
        dirs.push(expanded)
      }
    } else if dir.has_prefix("/") {
      dirs.push(dir)
    }
  }
  dirs
}

///|
/// Merge the DT_RPATH tier, LD_LIBRARY_PATH and the DT_RUNPATH tier in
/// the loader's order: the RPATH tier (the object's own DT_RPATH followed
/// by the ancestors' it inherited) is searched first, then the
/// environment, then the object's own DT_RUNPATH. Returns a fresh list —
/// callers iterate it for several sonames.
fn library_search_dirs(
  rpath_dirs : Array[String],
  env_dirs : Array[String],
  runpath_dirs : Array[String],
) -> Array[String] {
  let merged : Array[String] = []
  for dir in rpath_dirs {
    merged.push(dir)
  }
  for dir in env_dirs {
    merged.push(dir)
  }
  for dir in runpath_dirs {
    merged.push(dir)
  }
  merged
}

///|
/// Whether `head` — at least `phoff + phnum * phentsize` bytes of a file
/// of `file_size` bytes — describes a usable little-endian ELF64 shared
/// object for e_machine `host`: a complete ELF header and program-header
/// table plus at least one PT_LOAD segment lying fully inside the file.
/// A truncated or wrong-architecture ELF, a 32-bit ELF, a non-ELF file and
/// an ET_REL/ET_EXEC object all fail the real loader too, so they fail here.
fn elf64_usable(head : Bytes, file_size : Int64, host : Int) -> Bool {
  if head.length() < 64 {
    return false
  }
  if head[0].to_int() != 0x7f ||
    head[1] != b'E' ||
    head[2] != b'L' ||
    head[3] != b'F' ||
    head[4].to_int() != 2 ||
    head[5].to_int() != 1 ||
    // ET_DYN: both ld.so loaders and shared libraries.
    elf_u16le(head, 16) != 3 ||
    elf_u16le(head, 18) != host ||
    elf_u16le(head, 52) != 64 {
    return false
  }
  let phoff = elf_u64le(head, 32)
  let phentsize = elf_u16le(head, 54)
  let phnum = elf_u16le(head, 56)
  let table_end = phoff + phnum.to_int64() * phentsize.to_int64()
  if phoff <= 0L ||
    phnum < 1 ||
    phnum >= 4096 ||
    phentsize < 56 ||
    table_end > head.length().to_int64() ||
    table_end > file_size {
    return false
  }
  let mut loads = 0
  for i = 0; i < phnum; i = i + 1 {
    let p = phoff.to_int() + i * phentsize
    if elf_u32le(head, p) == 1 {
      loads = loads + 1
      let offset = elf_u64le(head, p + 8)
      let filesz = elf_u64le(head, p + 32)
      if filesz <= 0L || offset < 0L || offset + filesz > file_size {
        return false
      }
    }
  }
  loads > 0
}

///|
/// Whether the file at `path` is a usable host-architecture ELF64 shared
/// object — required of both the PT_INTERP loader and resolved DT_NEEDED
/// libraries. The complete program-header table and the PT_LOAD ranges are
/// validated against the open file's size (fstat, so symlinks to a loader
/// report their target's size), so a truncated loader does not slip
/// through on its first bytes alone. The regular-file check happens before
/// open: a FIFO or device named by an untrusted DT_NEEDED or PT_INTERP
/// string could block a read-only open.
async fn elf_file_usable(path : String, host : Int) -> Bool {
  guard @fs.kind(path) is Regular else { return false }
  let file = @fs.open(path, mode=ReadOnly) catch { _ => return false }
  let size = file.size() catch {
    _ => {
      file.close()
      return false
    }
  }
  let header = file.read_exactly_at(64, position=0L) catch {
    _ => {
      file.close()
      return false
    }
  }
  // Size the full header+phdr read from the declared table bounds.
  let phoff = elf_u64le(header, 32)
  let phentsize = elf_u16le(header, 54)
  let phnum = elf_u16le(header, 56)
  let needed = phoff + phnum.to_int64() * phentsize.to_int64()
  if needed <= 0L || needed > size || needed > 1048576L {
    file.close()
    return false
  }
  let head = file.read_exactly_at(needed.to_int(), position=0L) catch {
    _ => {
      file.close()
      return false
    }
  }
  file.close()
  elf64_usable(head, size, host)
}

///|
/// Directories from a colon-separated LD_LIBRARY_PATH value. Empty entries
/// and relative paths are skipped: they resolve against the eventual
/// runtime working directory, which the installer cannot know.
fn ld_library_dirs(value : String?) -> Array[String] {
  let dirs : Array[String] = []
  let text = match value {
    Some(env) => env
    None => return dirs
  }
  for entry in text.split(":") {
    let dir = entry.trim().to_owned()
    if dir != "" && dir.has_prefix("/") {
      dirs.push(dir)
    }
  }
  dirs
}

///|
/// Pick the first candidate library the host can actually load, like
/// ld.so skipping an incompatible file (wrong e_machine, not an ELF64
/// ET_DYN) it meets on the search path. The first regular-but-unusable
/// path seen is recorded into `first_unusable` rather than returned: a
/// foreign-architecture file in an early search location must not shadow
/// a compatible library that exists in a later search tier.
async fn pick_usable(
  paths : Array[String],
  host : Int,
  first_unusable : Ref[String?],
) -> String? {
  for path in paths {
    if !(@fs.exists(path) && @fs.kind(path) is Regular) {
      continue
    }
    if first_unusable.val is None {
      first_unusable.val = Some(path)
    }
    if elf_file_usable(path, host) {
      return Some(path)
    }
  }
  None
}

///|
/// Resolve a DT_NEEDED soname to a host path. `search_dirs` already merges
/// the RPATH tier, LD_LIBRARY_PATH and the object's RUNPATH directories in
/// loader order; then the ldconfig cache (which can hold several ABI
/// variants of one soname), and finally the usual library directories. In
/// every location an incompatible ELF is skipped just like ld.so skips it,
/// and the unusable-file fallback is deferred until all tiers have been
/// searched so an ABI-incompatible hit early on cannot shadow a usable
/// library found later. Only regular files count: a FIFO or device at a
/// candidate path could block on open.
async fn resolve_soname(
  soname : String,
  search_dirs : Array[String],
  cache : Map[String, Array[String]],
  dirs : Array[String],
  host : Int,
) -> String? {
  if soname.contains("/") {
    let usable = @fs.exists(soname) && @fs.kind(soname) is Regular
    return if usable { Some(soname) } else { None }
  }
  let first_unusable : Ref[String?] = { val: None, }
  let searched : Array[String] = []
  for dir in search_dirs {
    searched.push(dir + "/" + soname)
  }
  match pick_usable(searched, host, first_unusable) {
    Some(found) => return Some(found)
    None => ()
  }
  match cache.get(soname) {
    Some(candidates) =>
      match pick_usable(candidates, host, first_unusable) {
        Some(found) => return Some(found)
        None => ()
      }
    None => ()
  }
  let defaults : Array[String] = []
  for dir in dirs {
    defaults.push(dir + "/" + soname)
  }
  match pick_usable(defaults, host, first_unusable) {
    Some(found) => return Some(found)
    None => ()
  }
  // Every candidate in every tier was unusable for this host: report the
  // first so the caller can reject it as an unusable library.
  first_unusable.val
}

///|
/// Sonames the kernel itself provides, so no filesystem resolution is
/// needed: the vDSO family is mapped into every process by the loader.
fn kernel_object_sonames() -> Array[String] {
  ["linux-vdso.so.1", "linux-vdso32.so.1", "linux-gate.so.1"]
}

///|
/// The directory component of a path ("/a/b/c.so" -> "/a/b").
fn dirname_of(path : String) -> String {
  let parts = path.split("/").collect()
  if parts.length() <= 1 {
    return "."
  }
  let dir = parts[:parts.length() - 1].iter().join("/")
  if dir == "" {
    "/"
  } else {
    dir
  }
}

///|
/// Parsed runtime dependencies of a resolved provider library, or None
/// when the file cannot be read as ELF64. The regular-file check precedes
/// the read so an untrusted soname path can never block on a FIFO.
async fn library_deps(path : String) -> ElfDeps? {
  guard @fs.kind(path) is Regular else { return None }
  let bytes = @fs.read_file(path).binary() catch { _ => return None }
  parse_elf64_deps(bytes)
}

///|
/// The version names a library file defines in .gnu.version_d, or None
/// when the file cannot be read or parsed as ELF64. An empty result means
/// the library parses but defines no versions (for example a musl libc).
async fn library_defined_versions(path : String) -> Array[String]? {
  // An untrusted DT_NEEDED string can name a FIFO or device: refuse to
  // open anything but a regular file.
  guard @fs.kind(path) is Regular else { return None }
  let bytes = @fs.read_file(path).binary() catch { _ => return None }
  let deps = match parse_elf64_deps(bytes) {
    Some(value) => value
    None => return None
  }
  Some(deps.verdef)
}

///|
/// Walk the transitive DT_NEEDED closure of the root object's dependencies
/// breadth-first, resolving each object's own soname list with its own
/// RUNPATH/RPATH context (`$ORIGIN` is the directory of the object holding
/// the dependency, so a provider's private $ORIGIN neighbors are honored).
/// `visited` guards dependency cycles like libA -> libB -> libA. An
/// object whose needed soname cannot be located, resolves to a file the
/// host cannot load, or requires a symbol version its provider does not
/// define aborts the install — exactly the cases where the real loader
/// would refuse to start the process. `owner` in each queue entry is only
/// used to make failure messages name the object holding the dependency.
async fn check_library_closure(
  name : String,
  root : ElfDeps,
  root_dir : String,
  env_dirs : Array[String],
  cache : Map[String, Array[String]],
  dirs : Array[String],
  host : Int,
  lib_tokens : Array[String],
) -> Unit {
  let visited : Map[String, Bool] = Map([])
  // The loader's link map: every object already loaded under a soname
  // identity is reused for later lookups — ld.so does not search the
  // filesystem again when a transitive DT_NEEDED names a soname that an
  // earlier object already provided (e.g. the executable's own direct
  // dependency). Without this a provider's narrower search context
  // would report an already-loaded library as missing.
  let loaded : Map[String, String] = Map([])
  // Parsed .dynamic data for each resolved file, filled on first read
  // so providers are never opened twice during the walk.
  let parsed : Map[String, ElfDeps] = Map([])
  // Each entry carries the DT_RPATH directories inherited from the
  // ancestor chain: legacy RPATH propagates to indirect dependencies
  // (nearest ancestor's first), unlike DT_RUNPATH.
  let queue : Array[(String, String, ElfDeps, Array[String])] = [
    ("installed binary \{name}", root_dir, root, []),
  ]
  let mut cursor = 0
  while cursor < queue.length() {
    let (owner, objdir, objdeps, inherited) = queue[cursor]
    cursor = cursor + 1
    // This object's own DT_RPATH heads the RPATH tier, followed by the
    // ancestors'; the whole tier is searched before LD_LIBRARY_PATH.
    let rpath_tier : Array[String] = []
    if objdeps.rpath_first {
      for dir in expand_runpath(objdeps.runpath, objdir, lib_tokens) {
        rpath_tier.push(dir)
      }
    }
    for dir in inherited {
      rpath_tier.push(dir)
    }
    // DT_RUNPATH applies only to this object's own dependencies and is
    // searched after LD_LIBRARY_PATH.
    let runpath_dirs = if !objdeps.rpath_first {
      expand_runpath(objdeps.runpath, objdir, lib_tokens)
    } else {
      []
    }
    let search_dirs = library_search_dirs(rpath_tier, env_dirs, runpath_dirs)
    let resolved : Map[String, String] = Map([])
    let missing : Array[String] = []
    let unusable : Array[String] = []
    for soname in objdeps.needed {
      // Kernel-supplied objects have no file to check: the loader always
      // satisfies them (the vDSO is mapped into every process).
      if kernel_object_sonames().contains(soname) {
        continue
      }
      // Reuse an object the loader already mapped under this soname
      // before searching again — the loaded object wins even when this
      // object's own search context could not find it.
      let found = match loaded.get(soname) {
        Some(found) => Some(found)
        None => resolve_soname(soname, search_dirs, cache, dirs, host)
      }
      match found {
        None => missing.push(soname)
        Some(path) => {
          resolved[soname] = path
          loaded[soname] = path
          // Register the embedded DT_SONAME immediately, at load time —
          // a LATER entry in this same needed list may request it. The
          // first loaded object wins on a SONAME collision.
          if parsed.get(path) is None {
            match library_deps(path) {
              Some(child) => {
                parsed[path] = child
                match child.soname {
                  Some(soname_alias) =>
                    if loaded.get(soname_alias) is None {
                      loaded[soname_alias] = path
                    }
                  None => ()
                }
              }
              None => ()
            }
          }
          // Existence is not enough: the loader also refuses a provider
          // that is not a host-architecture ELF shared object.
          if !elf_file_usable(path, host) {
            unusable.push(soname)
          }
        }
      }
    }
    guard missing.is_empty() else {
      let list = missing.join(", ")
      abort_compat_msg(
        "\{owner} cannot run on this system: unresolved libraries \{list}. Build it from source instead, or pass --skip-compat-check to install anyway.",
      )
    }
    guard unusable.is_empty() else {
      let list = unusable.join(", ")
      abort_compat_msg(
        "\{owner} cannot run on this system: unusable libraries \{list} (not loadable ELF64 shared objects for this architecture). Build it from source instead, or pass --skip-compat-check to install anyway.",
      )
    }
    // Queue each resolved provider so its own DT_NEEDED chain is checked
    // too — a missing transitive library stops the real loader as well.
    // Children inherit this object's complete RPATH tier, which already
    // ends with the ancestors' entries.
    for soname in objdeps.needed {
      match resolved.get(soname) {
        Some(found) =>
          if !visited.contains(found) {
            visited[found] = true
            match parsed.get(found) {
              Some(child) =>
                queue.push(
                  ("library \{found}", dirname_of(found), child, rpath_tier),
                )
              None =>
                abort_compat_msg(
                  "\{owner} cannot run on this system: library \{found} is not a parseable ELF64 object. Build it from source instead, or pass --skip-compat-check to install anyway.",
                )
            }
          }
        None => ()
      }
    }
    for requirement in objdeps.verneed {
      let (provider, version) = requirement
      let provider_path = match resolved.get(provider) {
        Some(found) => Some(found)
        None =>
          match loaded.get(provider) {
            Some(found) => Some(found)
            None => resolve_soname(provider, search_dirs, cache, dirs, host)
          }
      }
      match provider_path {
        None =>
          abort_compat_msg(
            "\{owner} cannot run on this system: it requires symbol version \{version} from \{provider}, which cannot be located. Build it from source instead, or pass --skip-compat-check to install anyway.",
          )
        Some(found) =>
          if !elf_file_usable(found, host) {
            abort_compat_msg(
              "\{owner} cannot run on this system: it requires symbol version \{version} from \{provider}, but \{found} is not a usable ELF shared object. Build it from source instead, or pass --skip-compat-check to install anyway.",
            )
          } else {
            match library_defined_versions(found) {
              // Only a provider that DOES define versions can be checked:
              // a file with no .gnu.version_d at all binds the symbol with
              // a "no version information available" warning — the loader
              // still runs it (e.g. musl libc, or a library relinked
              // without its version script). An unparseable provider is
              // left to the runtime loader the same way.
              Some(defined) =>
                if !defined.is_empty() && !defined.contains(version) {
                  abort_compat_msg(
                    "\{owner} cannot run on this system: it requires symbol version \{version} from \{provider}, which the installed \{found} does not provide. Build it from source instead, or pass --skip-compat-check to install anyway.",
                  )
                }
              None => ()
            }
            if !visited.contains(found) {
              visited[found] = true
              let child = match parsed.get(found) {
                Some(value) => Some(value)
                None => library_deps(found)
              }
              match child {
                Some(child) => {
                  parsed[found] = child
                  match child.soname {
                    Some(soname_alias) =>
                      if loaded.get(soname_alias) is None {
                        loaded[soname_alias] = found
                      }
                    None => ()
                  }
                  queue.push(
                    ("library \{found}", dirname_of(found), child, rpath_tier),
                  )
                }
                None => ()
              }
            }
          }
      }
    }
  }
}

///|
/// Reject a staged binary that cannot run on this host — inspected without
/// executing the downloaded file or running `ldd` on it, so hostile or
/// corrupted artifacts stay inert. A host-architecture ELF64 is rejected
/// when it is not an executable (e.g. a relocatable object), its program
/// headers are malformed, its PT_INTERP loader is absent or missing, a
/// DT_NEEDED library cannot be resolved through LD_LIBRARY_PATH and its
/// RUNPATH/RPATH, the ldconfig cache and the usual library directories
/// (checked transitively, since a provider's own missing dependency
/// stops the loader too), or a required symbol version (GLIBC_*,
/// GLIBCXX_*, ...) is not defined by the resolved provider library.
/// Other formats and foreign architectures are skipped — they may be
/// fetched on purpose for a different machine. `install_dir` is the
/// binary's final destination directory, used to expand `$ORIGIN`.
async fn verify_binary_compat(
  path : String,
  binary : Bytes,
  skip_compat_check : Bool,
  install_dir : String,
) -> Unit {
  if skip_compat_check {
    return
  }
  let machine = match elf_machine(binary) {
    Some(value) => value
    None => return
  }
  guard host_linux() else { return }
  let host = match host_machine() {
    Some(value) => value
    None => return
  }
  guard machine == host else { return }
  let name = path.split("/").last().unwrap_or(path)
  // e_type: only ET_EXEC (2) and ET_DYN (3) can be executed; a host-arch
  // ET_REL object file must not slip through as "unknown format".
  let etype = elf_u16le(binary, 16)
  guard etype == 2 || etype == 3 else {
    abort_compat_msg(
      "installed binary \{name} cannot run on this system: ELF type \{etype} is not executable. Build it from source instead, or pass --skip-compat-check to install anyway.",
    )
  }
  // Only ELF64 is parsed; other classes (e.g. a 32-bit binary) fall
  // through unverified rather than being rejected as malformed.
  guard binary[4].to_int() == 2 else { return }
  let deps = match parse_elf64_deps(binary) {
    Some(value) => value
    None =>
      abort_compat_msg(
        "installed binary \{name} cannot run on this system: malformed ELF64 program headers. Build it from source instead, or pass --skip-compat-check to install anyway.",
      )
  }
  match deps.interp {
    Some(interp) =>
      if interp != "" {
        // An existing path is not enough: the kernel refuses a PT_INTERP
        // that is not a regular executable host-architecture ELF loader.
        let usable = @fs.exists(interp) &&
          @fs.kind(interp) is Regular &&
          @fs.can_execute(interp) &&
          elf_file_usable(interp, host)
        if !usable {
          abort_compat_msg(
            "installed binary \{name} cannot run on this system: ELF interpreter \{interp} is missing or is not an executable ELF loader for this architecture. Build it from source instead, or pass --skip-compat-check to install anyway.",
          )
        }
      }
    None =>
      if !deps.needed.is_empty() {
        abort_compat_msg(
          "installed binary \{name} cannot run on this system: it needs shared libraries but has no ELF interpreter. Build it from source instead, or pass --skip-compat-check to install anyway.",
        )
      }
  }
  let env_dirs = ld_library_dirs(@env.get_env_var("LD_LIBRARY_PATH"))
  let cache = ldconfig_map()
  let dirs = library_dirs()
  let lib_tokens = lib_token_names(host)
  check_library_closure(
    name.to_owned(),
    deps,
    install_dir,
    env_dirs,
    cache,
    dirs,
    host,
    lib_tokens,
  )
}

///|
async fn create_staging_directory(bin_dir : String, index : Int) -> String {
  create_staging_directory_at(bin_dir, index, @async.now().to_string())
}

///|
async fn stage_install(
  plan : ResolvedInstallPlan,
  bin_dir : String,
  workspace : String,
  index : Int,
  force : Bool,
  skip_compat_check : Bool,
  transport : Transport,
) -> StagedInstall {
  let item = plan.install
  let destination = bin_dir + "/" + item.binary
  // Replacement eligibility was already decided per-plan; this re-check only
  // keeps the non-regular/symlink refusal (TOCTOU guard).
  check_destination(destination, true)
  ignore(force)
  let archive_path = workspace + "/asset-\{index}"
  download_using(item.asset.url, archive_path, transport)
  verify_digest(archive_path, item.asset.digest)
  let binary = if plan.discover_archive_member {
    read_artifact_binary_from_candidates(
      archive_path,
      item.format,
      plan.archive_candidates,
    )
  } else {
    read_artifact_binary(archive_path, item.format, item.bin_path)
  }
  let staging_dir = create_staging_directory(bin_dir, index)
  let mut ownership_transferred = false
  defer (if !ownership_transferred {
    @fs.rmdir(staging_dir, recursive=true) catch {
      _ => ()
    }
  })
  let staging = staging_dir + "/" + item.binary
  @fs.write_file(staging, binary, create_mode=CreateNew, permission=0o600)
  @fs.chmod(staging, 0o755)
  verify_binary_compat(staging, binary, skip_compat_check, bin_dir)
  ownership_transferred = true
  { destination, staging, staging_dir, binary_digest: bytes_sha256(binary), }
}

///|
pub async fn install_many(options : BatchOptions) -> Unit {
  install_many_using(options, Https)
}

///|
/// The action decided for a resolved plan (issue 0001): skip an identical
/// install, place a fresh binary, update a managed one, or verify an unmanaged
/// executable against a downloaded archive member before adopting it.
priv enum InstallDecision {
  Skip
  Install
  Update(String)
  /// Without a receipt, an archive's asset digest cannot identify the
  /// installed executable. Compare its verified member before adopting it.
  VerifyExisting(String)
  /// Preserve the digest proven against the candidate until receipt commit.
  AdoptVerified(String)
}

///|
/// SHA-256 of bytes, in the `sha256:hex` release form.
fn bytes_sha256(bytes : Bytes) -> String {
  "sha256:" + @crypto.bytes_to_hex_string(@crypto.sha256(bytes))
}

///|
/// SHA-256 of a file's current content, in the `sha256:hex` release form.
async fn file_sha256(path : String) -> String {
  bytes_sha256(@fs.read_file(path).binary())
}

///|
/// Decide what to do at `destination` for `plan` without writing anything
/// (issue 0001). An existing regular file is only replaced when it is
/// provably ours: its stored receipt digest matches its current content and
/// the package identity matches the new candidate. Identical verified
/// content always skips; unmanaged or modified content refuses with a
/// `--force` path; downgrades and incomparable versions refuse the same way.
/// Unmanaged archive installs defer the content comparison until extraction.
async fn decide_install(
  plan : ResolvedInstallPlan,
  bin_dir : String,
  force : Bool,
) -> InstallDecision {
  let binary = plan.install.binary
  let destination = bin_dir + "/" + binary
  // Do not install anything if receipt metadata points through a symlink.
  validate_receipt_location(receipt_path(bin_dir, binary))
  match path_kind_no_follow(destination) {
    None => Install
    Some(Regular) => {
      if force {
        return Install
      }
      let existing_digest = file_sha256(destination)
      let candidate_digest = plan.install.asset.digest.to_lower()
      let receipt = read_receipt_file(receipt_path(bin_dir, binary))
      match receipt {
        // Managed and unmodified: the stored BINARY digest matches the
        // file's current content. The asset (archive) digest never
        // touches the file (issue 0001).
        Some(stored) if stored.binary_digest == existing_digest => {
          guard stored.binary == binary &&
            stored.repository == plan.repository &&
            stored.package_key == plan.package_key &&
            stored.target == plan.target &&
            stored.destination == destination else {
            abort_install(
              Destination, "check the destination", destination,
              "this executable was installed from a different package, target or destination (\{stored.package_key}); refusing to replace it",
              action="choose another --bin-dir, or pass --force to replace it anyway",
            )
          }
          // Same verified release asset → the extracted binary is the
          // same too; skip without downloading (works for zip/tar
          // archives whose bytes differ from the executable).
          if candidate_digest == stored.asset_digest {
            return Skip
          }
          match semver_compare(plan.install.asset.tag, stored.tag) {
            Some(1) => Update(stored.tag)
            Some(0) =>
              abort_install(
                Destination, "check the destination", destination,
                "the candidate has the same version (\{stored.tag}) but different content",
                action="pass --force to replace it anyway",
              )
            Some(_) =>
              abort_install(
                Destination, "check the destination", destination,
                "the candidate (\{plan.install.asset.tag}) is older than the installed version (\{stored.tag}); refusing to downgrade",
                action="pass --force to downgrade anyway",
              )
            None =>
              abort_install(
                Destination, "check the destination", destination,
                "cannot compare versions (\{stored.tag} -> \{plan.install.asset.tag}); refusing to guess",
                action="pass --force to replace it anyway",
              )
          }
        }
        Some(_) =>
          abort_install(
            Destination, "check the destination", destination,
            "the installed binary was modified after install; refusing to guess its provenance",
            action="pass --force to replace it anyway",
          )
        None =>
          if plan.install.format != "bin" {
            VerifyExisting(existing_digest)
          } else if candidate_digest == existing_digest {
            AdoptVerified(existing_digest)
          } else {
            abort_install(
              Destination, "check the destination", destination,
              "an existing executable not installed by moon-binstall is in the way",
              action="inspect it and pass --force to replace it, or choose another --bin-dir",
            )
          }
      }
    }
    Some(_) =>
      abort_install(
        Destination, "check the destination", destination,
        "refusing to replace a non-regular file",
        action="remove it or choose another --bin-dir",
      )
  }
}

///|
/// Adoption only records provenance for identical executable bytes. A
/// mismatching archive member never grants permission to replace the file.
async fn verify_existing_binary(
  item : StagedInstall,
  existing_digest : String,
) -> Unit {
  guard item.binary_digest == existing_digest else {
    abort_install(
      Destination,
      "check the destination",
      item.destination,
      "an existing executable not installed by moon-binstall differs from the verified archive binary",
      action="inspect it and pass --force to replace it, or choose another --bin-dir",
    )
  }
  validate_adoption_destination(item.destination, existing_digest)
}

///|
/// Recheck an adoption against the digest already proven by the candidate.
/// A new hash is evidence to compare, never new provenance to record.
async fn validate_adoption_destination(
  destination : String,
  verified_digest : String,
) -> Unit {
  // The download/extraction can take time; do not adopt a missing, linked,
  // or changed file based on the digest observed during initial planning.
  guard path_kind_no_follow(destination) is Some(Regular) &&
    file_sha256(destination) == verified_digest else {
    abort_install(
      Destination,
      "check the destination",
      destination,
      "the existing executable changed while verifying the install",
      action="inspect the destination and retry",
    )
  }
}

///|
/// Record the install receipt for a successfully placed binary: the
/// asset digest identifies the release, the binary digest identifies
/// the installed file (issue 0001).
async fn record_install_receipt(
  plan : ResolvedInstallPlan,
  coordinate : String,
  bin_dir : String,
  binary_digest : String,
) -> Unit {
  write_receipt(
    InstallReceipt::{
      coordinate,
      source: plan.source_label,
      repository: plan.repository,
      package_key: plan.package_key,
      binary: plan.install.binary,
      target: plan.target,
      tag: plan.install.asset.tag,
      asset_digest: plan.install.asset.digest.to_lower(),
      binary_digest,
      destination: bin_dir + "/" + plan.install.binary,
    },
  )
}

///|
/// Parse the host libc from `ldd --version` output: "musl" on musl systems,
/// the dotted version on glibc systems, or None when it cannot be told.
fn parse_host_libc(output : String) -> String? {
  if output.contains("musl") {
    return Some("musl")
  }
  // GNU ldd prints e.g. "ldd (Ubuntu GLIBC 2.35-0ubuntu3.14) 2.35" and ends
  // the first line with the version number.
  match output.split("\n").iter().next() {
    None => None
    Some(first_line) => {
      let mut version : String? = None
      for token in first_line.split(" ") {
        let text = token.trim().to_owned()
        if text != "" && text[0] >= '0' && text[0] <= '9' && text.contains(".") {
          version = Some(text)
        }
      }
      version
    }
  }
}

///|
/// Compare dotted numeric versions componentwise: "2.9" < "2.35".
fn version_lt(left : String, right : String) -> Bool {
  let a = left.split(".").collect()
  let b = right.split(".").collect()
  let n = if a.length() > b.length() { a.length() } else { b.length() }
  for i = 0; i < n; i = i + 1 {
    let x = if i < a.length() { parse_digits(a[i]) } else { 0 }
    let y = if i < b.length() { parse_digits(b[i]) } else { 0 }
    if x != y {
      return x < y
    }
  }
  false
}

///|
fn parse_digits(text : StringView) -> Int {
  let mut value = 0
  for c in text {
    if c >= '0' && c <= '9' {
      value = value * 10 + (c.to_int() - '0'.to_int())
    } else {
      break
    }
  }
  value
}

///|
/// Fail before downloading when the publisher declares a glibc minimum that
/// the host cannot satisfy (musl hosts and older glibc). Only applies when
/// the install targets a Linux binary for this host's own architecture —
/// a cross-architecture fetch is left to the post-download ELF check,
/// which inspects the real binary.
async fn check_declared_glibc(
  glibc_min : String?,
  target : String,
  binary : String,
  skip_compat_check : Bool,
) -> Unit {
  if skip_compat_check {
    return
  }
  let min = match glibc_min {
    Some(value) => value
    None => return
  }
  let target_machine = match target {
    "linux-x86_64" => 62
    "linux-aarch64" => 183
    _ => return
  }
  guard host_linux() else { return }
  let host = match host_machine() {
    Some(value) => value
    None => return
  }
  guard host == target_machine else { return }
  match host_libc() {
    Some("musl") =>
      abort_compat_msg(
        "installed binary \{binary} requires glibc >= \{min} but this system uses musl libc. Build it from source instead, or pass --skip-compat-check to install anyway.",
      )
    Some(version) =>
      if version_lt(version, min) {
        abort_compat_msg(
          "installed binary \{binary} requires glibc >= \{min} but this system has glibc \{version}. Build it from source instead, or pass --skip-compat-check to install anyway.",
        )
      }
    None => ()
  }
}

///|
async fn install_many_using(
  options : BatchOptions,
  transport : Transport,
) -> Unit {
  let target = match options.target {
    Some(value) => parse_target_list(value)[0]
    None => require_platform()
  }
  let workspace = @fs.tmpdir(prefix="moon-binstall")
  defer (@fs.rmdir(workspace, recursive=true) catch { _ => () })
  let resolved : Array[ResolvedInstallPlan] = []
  let binary_names : Array[String] = []
  for i = 0; i < options.coordinates.length(); i = i + 1 {
    let item = resolve_package_plan(
      options.coordinates[i],
      options,
      target,
      workspace,
      i,
      transport,
    ) catch {
      // Batch installs name the coordinate whose stage failed (issue 0003).
      InstallError(stage~, what~, target~, reason~, action~) =>
        raise InstallError(
          stage~,
          what~,
          target~,
          reason="\{describe_coordinate(options.coordinates[i])}: \{reason}",
          action~,
        )
      err => raise err
    }
    // Safe binary names are ASCII, so lowercase keys are portable. Apply the
    // check everywhere because default macOS filesystems are case-insensitive.
    let binary_key = item.install.binary.to_lower()
    guard !binary_names.contains(binary_key) else {
      abort_resolve(
        "multiple packages resolve to the same executable name (case-insensitive): \{item.install.binary}",
      )
    }
    binary_names.push(binary_key)
    resolved.push(item)
    println(
      "Resolved \{describe_coordinate(options.coordinates[i])}: source=\{item.source_label} tag=\{item.install.asset.tag} asset=\{item.install.asset.name} binary=\{item.install.binary} target=\{item.target}",
    )
  }
  // Self-update without an explicit destination targets the running
  // executable's directory (issue 0004); otherwise --bin-dir >
  // MOON_BINSTALL_DIR > $HOME/.local/bin, and the winning source is shown.
  let (bin_dir, dir_source) = if resolved.length() == 1 &&
    is_self_update(resolved[0]) &&
    options.directory is None &&
    @env.get_env_var("MOON_BINSTALL_DIR") is None {
    (self_update_bin_dir(resolved[0]), "running executable (self-update)")
  } else {
    target_directory_with_source(options.directory)
  }
  // Plan every replacement before staging (issue 0001). Deferred archive
  // comparisons also finish before any destination or receipt is changed.
  let decisions : Array[InstallDecision] = []
  for i = 0; i < resolved.length(); i = i + 1 {
    decisions.push(decide_install(resolved[i], bin_dir, options.force))
  }
  if options.dry_run {
    for i = 0; i < resolved.length(); i = i + 1 {
      let item = resolved[i].install
      let verb = match decisions[i] {
        Skip | AdoptVerified(_) => "skip (already installed)"
        Install => "install"
        Update(old) => "update (replaces \{old})"
        VerifyExisting(_) => "verify the archive binary against the existing file"
      }
      println("Would \{verb} \{item.asset.url} -> \{bin_dir}/\{item.binary}")
    }
    println("Destination: \{bin_dir} (\{dir_source})")
    report_path_diagnostics(bin_dir, resolved)
    return
  }
  @fs.mkdir(bin_dir, recursive=true, allow_exist=true)
  for plan in resolved {
    check_declared_glibc(
      plan.glibc_min,
      plan.target,
      plan.install.binary,
      options.skip_compat_check,
    )
  }
  let staged : Array[StagedInstall] = []
  let staged_index : Array[Int] = []
  let pending : Array[Bool] = []
  defer (for i = 0; i < staged.length(); i = i + 1 {
    if pending[i] {
      @fs.remove(staged[i].staging) catch {
        _ => ()
      }
      @fs.rmdir(staged[i].staging_dir, recursive=true) catch {
        _ => ()
      }
    }
  })
  for i = 0; i < resolved.length(); i = i + 1 {
    // An identical verified binary is never downloaded again (issue 0001).
    if decisions[i] is Skip || decisions[i] is AdoptVerified(_) {
      continue
    }
    try {
      let item = stage_install(
        resolved[i],
        bin_dir,
        workspace,
        i,
        options.force,
        options.skip_compat_check,
        transport,
      )
      staged.push(item)
      staged_index.push(i)
      pending.push(true)
      if decisions[i] is VerifyExisting(existing_digest) {
        verify_existing_binary(item, existing_digest)
        decisions[i] = AdoptVerified(item.binary_digest)
      }
    } catch {
      InstallError(stage~, what~, target~, reason~, action~) =>
        raise InstallError(
          stage~,
          what~,
          target~,
          reason="\{describe_coordinate(options.coordinates[i])}: \{reason}",
          action~,
        )
      err => raise err
    }
  }
  // Later downloads/extractions may outlast an earlier adoption check.
  // Revalidate every adoption before the first binary or receipt commit.
  for i = 0; i < resolved.length(); i = i + 1 {
    if decisions[i] is AdoptVerified(verified_digest) {
      let binary = resolved[i].install.binary
      try {
        validate_receipt_location(receipt_path(bin_dir, binary))
        validate_adoption_destination(bin_dir + "/" + binary, verified_digest)
      } catch {
        InstallError(stage~, what~, target~, reason~, action~) =>
          raise InstallError(
            stage~,
            what~,
            target~,
            reason="\{describe_coordinate(options.coordinates[i])}: \{reason}",
            action~,
          )
        err => raise err
      }
    }
  }
  for i = 0; i < staged.length(); i = i + 1 {
    // Verified unmanaged archive binaries are adopted without replacing
    // the existing file. Their unused staging directories are cleaned up
    // by the same deferred cleanup used for a failed batch.
    if decisions[staged_index[i]] is AdoptVerified(_) {
      continue
    }
    let item = staged[i]
    @fs.rename(item.staging, item.destination, replace=true)
    pending[i] = false
    @fs.rmdir(item.staging_dir, recursive=true) catch {
      _ => ()
    }
    let plan_index = staged_index[i]
    record_install_receipt(
      resolved[plan_index],
      describe_coordinate(options.coordinates[plan_index]),
      bin_dir,
      item.binary_digest,
    )
    let tag = resolved[plan_index].install.asset.tag
    match decisions[plan_index] {
      Update(old) =>
        println("Updated \{item.destination} (\{old} -> \{tag})")
      _ => println("Installed \{item.destination} (\{tag})")
    }
  }
  // Skipped managed items retain their receipts. Adopted items record only
  // the digest verified against the candidate, never a newly observed hash.
  for i = 0; i < resolved.length(); i = i + 1 {
    if decisions[i] is Skip || decisions[i] is AdoptVerified(_) {
      let item = resolved[i].install
      if decisions[i] is AdoptVerified(verified_digest) {
        record_install_receipt(
          resolved[i],
          describe_coordinate(options.coordinates[i]),
          bin_dir,
          verified_digest,
        )
      }
      println("Already installed \{bin_dir}/\{item.binary} (\{item.asset.tag})")
    }
  }
  println("Destination: \{bin_dir} (\{dir_source})")
  report_path_diagnostics(bin_dir, resolved)
}

///|
/// Where a bare `name` resolves for a shell user, in PATH order. Unlike
/// the self-update lookup, this mirrors what exec actually does: empty
/// and relative PATH entries resolve against the current working
/// directory, symlinks are followed to regular files, and the candidate
/// must carry an executable bit — no file is ever invoked.
async fn path_resolved_candidates(name : String) -> Array[String] {
  let found : Array[String] = []
  let raw = match @env.get_env_var("PATH") {
    Some(value) => value
    None => ""
  }
  let cwd = @env.current_dir()
  for entry in raw.split(":") {
    let text = entry.to_owned()
    let dir = if text.has_prefix("/") {
      text
    } else {
      match cwd {
        Some(cwd_dir) =>
          if text == "" {
            cwd_dir
          } else {
            cwd_dir + "/" + text
          }
        None => continue
      }
    }
    let candidate = dir + "/" + name
    match path_kind(candidate) {
      Some(Regular) => if @fs.can_execute(candidate) { found.push(candidate) }
      _ => ()
    }
  }
  found
}

///|
/// Show how PATH resolves each installed binary (issue 0004): the first
/// PATH hit is the next executable a bare name runs. A shadowed or absent
/// destination is a stderr warning — the install still succeeded. Only
/// filesystem lookups are used; no executable is ever invoked.
async fn report_path_diagnostics(
  bin_dir : String,
  resolved : Array[ResolvedInstallPlan],
) -> Unit {
  let seen : Array[String] = []
  for plan in resolved {
    let name = plan.install.binary
    if seen.contains(name) {
      continue
    }
    seen.push(name)
    let destination = bin_dir + "/" + name
    let candidates = path_resolved_candidates(name)
    if candidates.length() == 0 {
      eprintln(
        "moon-binstall: note: '\{name}' is not on PATH (installed at '\{destination}')",
      )
      eprintln(
        "moon-binstall: hint: add '\{bin_dir}' to PATH, then check 'command -v \{name}' or 'type -a \{name}'",
      )
    } else if candidates[0] != destination {
      eprintln(
        "moon-binstall: note: '\{name}' on PATH resolves to '\{candidates[0]}', which shadows the new install at '\{destination}'",
      )
      eprintln(
        "moon-binstall: hint: check with 'command -v \{name}' or 'type -a \{name}'",
      )
    } else {
      println("PATH resolves '\{name}' to '\{destination}'")
    }
  }
}

///|
pub async fn install(config : Options) -> Unit {
  install_many({
    coordinates: [GitHub(config.pkg)],
    directory: config.directory,
    dry_run: config.dry_run,
    force: config.force,
    skip_compat_check: config.skip_compat_check,
    target: None,
    version: None,
    pkg_url: None,
    pkg_fmt: None,
    bin_path: None,
    module_path: None,
    manifest_path: None,
  })
}

///|
pub async fn install_from_asset_file(
  asset_path : String,
  digest : String,
  format : String,
  bin_path : String?,
  binary : String,
  bin_dir : String,
  force : Bool,
) -> Unit {
  guard safe_binary_name(binary) else { abort_args("unsafe executable name") }
  guard bin_dir.has_prefix("/") else {
    abort_args("--bin-dir must be an absolute path")
  }
  @fs.mkdir(bin_dir, recursive=true, allow_exist=true)
  let destination = bin_dir + "/" + binary
  check_destination(destination, force)
  verify_digest(asset_path, digest)
  let content = read_artifact_binary(asset_path, format, bin_path)
  let staging_dir = create_staging_directory(bin_dir, 0)
  let mut owns_directory = true
  defer (if owns_directory {
    @fs.rmdir(staging_dir, recursive=true) catch {
      _ => ()
    }
  })
  let staging = staging_dir + "/" + binary
  @fs.write_file(staging, content, create_mode=CreateNew, permission=0o600)
  @fs.chmod(staging, 0o755)
  verify_binary_compat(staging, content, false, bin_dir)
  @fs.rename(staging, destination, replace=force)
  owns_directory = false
  @fs.rmdir(staging_dir, recursive=true) catch {
    _ => ()
  }
}

///|
pub async fn execute(argv : ArrayView[String]) -> Int {
  if argv.length() == 0 ||
    (
      argv.length() == 1 &&
      (argv[0] == "--help" || argv[0] == "-h" || argv[0] == "help")
    ) {
    println(usage())
    return 0
  }
  if argv.length() == 1 && argv[0] == "--version" {
    println("moon-binstall 0.1.7")
    return 0
  }
  let config = parse_batch_options(argv)
  install_many(config)
  0
}