#!/bin/sh
# K.ai Terminal installer — https://usek.ai/install.sh
#
#     curl -fsSL https://usek.ai/install.sh | sh
#
# Detects the platform, downloads the matching signed release, verifies the
# sha256 (and the PGP-signed manifest when gpg is available), and runs the
# tarball's own install.sh: binaries into ~/.local/bin, the daemon service
# for this machine's supervisor. User-level only — no root, no curl-to-sudo.
# Pin a version with KAI_VERSION=…; point elsewhere with KAI_BASE_URL=….
set -eu

base="${KAI_BASE_URL:-https://usek.ai}"
# The release signing key's fingerprint, baked in so a swapped key served
# from the same origin cannot pass verification (Codex 2026-08-29). Matches
# web/downloads/kai-release-key-fingerprint.txt.
release_fpr="3F7E774037BA41E070D9130B39281EE75977E465"

say() { printf '%s\n' "$*"; }
die() { printf 'kai install: %s\n' "$*" >&2; exit 1; }

fetch() {
    # fetch URL FILE
    if command -v curl >/dev/null 2>&1; then
        curl -fsSL "$1" -o "$2" || return 1
    elif command -v wget >/dev/null 2>&1; then
        wget -q "$1" -O "$2" || return 1
    else
        die "need curl or wget"
    fi
}

sha256() {
    if command -v sha256sum >/dev/null 2>&1; then
        sha256sum "$1" | cut -d' ' -f1
    else
        shasum -a 256 "$1" | cut -d' ' -f1
    fi
}

case "$(uname -s)" in
    Darwin) platform="darwin-universal" ;;
    Linux)
        case "$(uname -m)" in
            x86_64|amd64) platform="linux-x86_64" ;;
            aarch64|arm64) platform="linux-aarch64" ;;
            *) die "unsupported Linux architecture: $(uname -m)" ;;
        esac
        ;;
    *) die "unsupported platform: $(uname -s) — releases cover macOS and Linux" ;;
esac

tmp="$(mktemp -d "${TMPDIR:-/tmp}/kai-install.XXXXXX")"
trap 'rm -rf "$tmp"' EXIT INT TERM

fetch "$base/downloads/latest.txt" "$tmp/latest.txt" || die "cannot reach $base"
version="${KAI_VERSION:-$(sed -n 's/^version=//p' "$tmp/latest.txt")}"
[ -n "$version" ] || die "no version in $base/downloads/latest.txt"
line="$(sed -n "s/^$platform=//p" "$tmp/latest.txt")"
[ -n "$line" ] || die "no $platform build published yet — see $base/download.html"
file="${line%% *}"
expected="$(printf '%s\n' "$line" | sed -n 's/.*sha256=//p' | cut -d' ' -f1)"
if [ -n "${KAI_VERSION:-}" ]; then
    # A pinned version bypasses latest.txt's hash; the signed manifest
    # below is then the only verification, so gpg becomes required.
    file="kai-$version-$platform.tar.gz"
    expected=""
    command -v gpg >/dev/null 2>&1 || die "KAI_VERSION needs gpg to verify (no hash in latest.txt for $version)"
else
    # A normal install must carry exactly one 64-hex hash. A malformed or
    # truncated line otherwise leaves it empty and, without gpg, would skip
    # verification while claiming success (Codex 2026-08-29).
    case "$expected" in
        [0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]) ;;
        *) die "no valid sha256 for $platform in latest.txt — refusing to install" ;;
    esac
fi

say "K.ai Terminal $version ($platform)"
releases="$base/downloads/releases"
fetch "$releases/$file" "$tmp/$file" || die "download failed: $releases/$file"

actual="$(sha256 "$tmp/$file")"
if [ -n "$expected" ] && [ "$actual" != "$expected" ]; then
    die "sha256 mismatch for $file — refusing to install"
fi

# Strongest chain when gpg is present: the release key signs the manifest,
# the manifest names this tarball's hash.
manifest="kai-$version-manifest.txt"
if command -v gpg >/dev/null 2>&1; then
    if fetch "$releases/$manifest" "$tmp/$manifest" \
        && fetch "$releases/$manifest.asc" "$tmp/$manifest.asc" \
        && fetch "$base/downloads/kai-release-public-key.asc" "$tmp/key.asc"; then
        export GNUPGHOME="$tmp/gnupg"
        mkdir -p "$GNUPGHOME"
        chmod 700 "$GNUPGHOME"
        gpg -q --import "$tmp/key.asc" 2>/dev/null \
            || die "the served release key is not valid OpenPGP data — refusing to install"
        # The imported key must BE the release key, not just any key served
        # from this origin — otherwise a swapped key+manifest+archive would
        # all verify together (Codex 2026-08-29).
        gpg --with-colons --fingerprint 2>/dev/null \
            | grep -q "^fpr:::::::::$release_fpr:" \
            || die "the served signing key is not the K.ai release key — refusing to install"
        gpg -q --trust-model always --verify "$tmp/$manifest.asc" "$tmp/$manifest" 2>/dev/null \
            || die "PGP verification of the release manifest FAILED"
        # Whole-line match on the exact "hash␠␠file" the manifest records —
        # not a substring, which a crafted filename could satisfy.
        grep -qxF "$actual  $file" "$tmp/$manifest" \
            || die "$file's hash is not in the signed manifest — refusing to install"
        say "· verified: sha256 + PGP-signed manifest"
    else
        # With gpg present, the signed manifest IS the verification. Falling
        # back to the sha256 from latest.txt would let anyone who can block
        # just these three fetches strip the signature check — the hash and
        # the tarball ride the same origin, so nothing independent would be
        # left (audit M5). Refuse instead; a transient fetch failure re-runs.
        die "cannot fetch the signed manifest for $version — refusing to downgrade to checksum-only"
    fi
else
    say "· verified: sha256 (install gpg to also check the signed manifest)"
fi

tar -xzf "$tmp/$file" -C "$tmp"
"$tmp/kai-$version-$platform/install.sh"

say ""
say "Done. Try:"
say "    kai login       # paste an API key from usek.ai/chat.html"
say "    kai brain add ~/notes"
say "    kai             # the session; kai chat --agent adds file & shell tools"
case ":$PATH:" in
    *":$HOME/.local/bin:"*) ;;
    *) say "PATH note: add ~/.local/bin to your PATH to run kai by name." ;;
esac
