<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--
  Takumi Agent installer distribution (#19039).

  This file is a TEMPLATE. build-pkg.sh substitutes every __GUARD_*__ placeholder
  below from properties of the build it actually produced, and refuses to package
  if any survives — a distribution shipped with its placeholders intact would
  admit nothing (hostArchitectures) and refuse every Mac (the installation check).

  WHAT THIS FILE DECIDES, AND WHAT IT DOES NOT.

  The pkg is a productbuild distribution rather than a flat component pkg so that
  three things the GUI cannot express any other way become properties of the
  package itself:

    - <domains enable_localSystem="true"/> and nothing else. The installer offers
      no volume choice at all, so on a single-volume Mac the flow is
      Introduction -> Install -> Summary. sysextd activates a System Extension
      only from /Applications on the boot volume, so any other destination could
      only surface later as an activation error with the payload already written.
    - The supported-platform gate, expressed declaratively. Installer evaluates
      the installation check BEFORE any script runs and refuses with words we
      choose, where a preinstall refusal can only produce the generic "The
      installer encountered an error".
    - Welcome and conclusion panes, which list every macOS approval that follows
      the copy, in the order setup raises them (#19134).

  The gate here is a SECOND expression of pkg-scripts/preinstall's rule, never a
  replacement for it: `installer(8)` on the command line does not evaluate a
  distribution's installation check the way the GUI does, so the preinstall stays
  the authoritative refusal and this pane is what makes the refusal legible. The
  two are held equal by build-pkg.sh, which stamps both from the same values, and
  by pkgarch_pin_test.go.
-->
<installer-gui-script minSpecVersion="2">
    <title>Takumi Agent</title>
    <organization>tech.flatt</organization>
    <!--
      The boot volume, and no choice about it. enable_anywhere and
      enable_currentUserHome are stated explicitly rather than left to their
      defaults, because those defaults are what would put a volume-selection
      step back in front of the developer.
    -->
    <domains enable_anywhere="false" enable_currentUserHome="false" enable_localSystem="true"/>
    <!--
      customize="never": there is one payload and no reason to show a package
      list. allow-external-scripts="no": nothing outside the pkg may run.
      hostArchitectures is stamped from the slices this build actually carries,
      which is what makes Installer refuse an ineligible Mac.
    -->
    <options customize="never" allow-external-scripts="no" require-scripts="true" hostArchitectures="arm64"/>
    <welcome file="welcome.html" mime-type="text/html"/>
    <conclusion file="conclusion.html" mime-type="text/html"/>
    <installation-check script="guardPlatformCheck()"/>
    <script><![CDATA[
// The values below are stamped by build-pkg.sh from the same sources the
// preinstall's are: the slices lipo found in the built binaries, and the
// preinstall's own MIN_OS_MAJOR. Neither may be edited here.
var guardAllowedArchs = "arm64".split(" ");
var guardMinOSMajor = parseInt("13", 10);

// guardSysctl reads one sysctl as a string, or "" when the OID does not exist
// on this Mac (hw.optional.arm64 is unknown on Intel, where the read throws).
function guardSysctl(name) {
    try {
        var value = system.sysctl(name);
        return value === null || value === undefined ? "" : String(value);
    } catch (e) {
        return "";
    }
}

// guardArch resolves the architecture of the HARDWARE, mirroring the preinstall
// exactly: hw.optional.arm64 is the direct reading, sysctl.proc_translated=1
// corroborates it (Rosetta exists only on Apple silicon) and still answers when
// the first read fails, and hw.machine — which reports the calling process, so
// it says x86_64 under translation — is consulted last, as the only reading a
// Mac without those OIDs has. Returns "" when nothing answered.
function guardArch() {
    if (guardSysctl("hw.optional.arm64") === "1" || guardSysctl("sysctl.proc_translated") === "1") {
        return "arm64";
    }
    return guardSysctl("hw.machine");
}

// guardOSVersion reads this Mac's macOS version, or "" when it cannot be read.
// It goes through the same try/catch every other probe does, deliberately: the
// documented rule is that an unreadable version ADMITS, and an exception thrown
// out of the check is not an admission — Installer would treat the failed check
// as a refusal, turning the one probe that is supposed to fail open into the
// harshest possible failure. "" parses to NaN below, which admits.
function guardOSVersion() {
    try {
        var version = system.version.ProductVersion;
        return version === null || version === undefined ? "" : String(version);
    } catch (e) {
        return "";
    }
}

// guardLocalized resolves one refusal string from the distribution's
// Localizable.strings for the system language (ja ships one; #19202), falling
// back to the inline English — which stays the source of truth — when no
// table answers, when the key comes back unresolved, or when the host (the
// test harness's stub `system`) has no localizedString at all.
function guardLocalized(key, fallback) {
    try {
        var localized = system.localizedString(key);
        if (localized && localized !== key) {
            return String(localized);
        }
    } catch (e) {
        // fall through
    }
    return fallback;
}

// guardFill substitutes @TOKEN@ markers in a refusal template. Replacement by
// token rather than printf keeps the templates readable to a translator and
// needs nothing Installer's JS lacks.
function guardFill(template, values) {
    var out = template;
    for (var token in values) {
        out = out.split("@" + token + "@").join(values[token]);
    }
    return out;
}

function guardRefuse(title, message) {
    my.result.type = "Fatal";
    my.result.title = title;
    my.result.message = message;
    return false;
}

// guardPlatformCheck fails in the same two directions as the preinstall: an
// architecture no probe could read refuses (arm64-only code is not something to
// hand to a machine that cannot be identified), while a macOS version that
// cannot be parsed admits (an unreadable version is evidence of nothing, and
// refusing a supported Mac over a broken probe is the worse error).
function guardPlatformCheck() {
    var arch = guardArch();
    var archList = guardAllowedArchs.join(" or ");

    if (arch === "") {
        return guardRefuse(guardLocalized("UNSUPPORTED_MAC", "Unsupported Mac"),
            guardFill(guardLocalized("ARCH_UNREADABLE",
                "This Mac's processor architecture could not be read. Takumi Agent ships as @ARCHS@ code only, so it is not being installed."),
                { ARCHS: archList }));
    }

    var allowed = false;
    for (var i = 0; i < guardAllowedArchs.length; i++) {
        if (arch === guardAllowedArchs[i]) {
            allowed = true;
        }
    }
    if (!allowed) {
        return guardRefuse(guardLocalized("UNSUPPORTED_MAC", "Unsupported Mac"),
            guardFill(guardLocalized("ARCH_MISMATCH",
                "This Mac is @ARCH@. Takumi Agent ships as @ARCHS@ code only, so nothing in this package could run here."),
                { ARCH: arch, ARCHS: archList }));
    }

    var osVersion = guardOSVersion();
    var osMajor = parseInt(osVersion.split(".")[0], 10);
    if (!isNaN(osMajor) && osMajor < guardMinOSMajor) {
        return guardRefuse(guardLocalized("UNSUPPORTED_OS", "Unsupported macOS version"),
            guardFill(guardLocalized("OS_TOO_OLD",
                "This Mac runs macOS @VERSION@. Takumi Agent requires macOS @MIN@ (Ventura) or later."),
                { VERSION: osVersion, MIN: String(guardMinOSMajor) }));
    }

    return true;
}
    ]]></script>
    <choices-outline>
        <line choice="default"/>
    </choices-outline>
    <choice id="default" title="Takumi Agent">
        <pkg-ref id="tech.flatt.takumi-agent.pkg"/>
    </choice>
    <pkg-ref id="tech.flatt.takumi-agent.pkg" version="0.1.88" auth="root" installKBytes="20247" updateKBytes="0">#TakumiAgent.pkg</pkg-ref>
    <pkg-ref id="tech.flatt.takumi-agent.pkg">
        <bundle-version>
            <bundle CFBundleShortVersionString="0.1.88" CFBundleVersion="1088" id="tech.flatt.takumi-agent" path="TakumiAgent.app"/>
            <bundle CFBundleShortVersionString="0.1.88" CFBundleVersion="1088" id="tech.flatt.takumi-agent.sysext" path="TakumiAgent.app/Contents/Library/SystemExtensions/tech.flatt.takumi-agent.sysext.systemextension"/>
        </bundle-version>
    </pkg-ref>
</installer-gui-script>