aboutsummaryrefslogtreecommitdiffstats
path: root/packaging/fetch-vendor.sh
blob: 2d34b5593062ecff56a3e9aabf918b5fab81d076 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/usr/bin/env bash
# fetch-vendor.sh <vendor-dir> <bun-version> <pi-version>
#
# Downloads the pinned third-party payloads sl0ppi redistributes:
#   - bun          : the runtime that executes pi (single static binary)
#   - pi           : the agent itself, installed with its dependency tree
#
# Nothing here is committed to git; vendor/cache/ is gitignored. This script is
# what makes an offline `make package` reproducible-ish: fetch once, package
# many times.
#
# Pins live in the Makefile and FORKS.md. Checksums of whatever we actually
# downloaded are recorded in packaging/pins.sha256 -- if an entry already
# exists, a mismatch is a hard error.
set -euo pipefail

VENDOR="${1:?vendor dir}"
BUN_VERSION="${2:?bun version}"
PI_VERSION="${3:?pi version}"

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PINS="$HERE/pins.sha256"
touch "$PINS"

log() { printf '\033[36m==>\033[0m %s\n' "$*"; }

# record_or_verify <key> <file>
record_or_verify() {
    local key="$1" file="$2" have want
    have="$(sha256sum "$file" | cut -d' ' -f1)"
    want="$(awk -v k="$key" '$2 == k {print $1}' "$PINS")"
    if [ -z "$want" ]; then
        echo "$have $key" >> "$PINS"
        log "pinned $key = $have"
    elif [ "$have" != "$want" ]; then
        echo "fetch-vendor: CHECKSUM MISMATCH for $key" >&2
        echo "  expected $want (packaging/pins.sha256)" >&2
        echo "  got      $have" >&2
        exit 1
    else
        log "verified $key"
    fi
}

mkdir -p "$VENDOR"

# --- bun -------------------------------------------------------------------
BUN_DIR="$VENDOR/bun-$BUN_VERSION"
if [ ! -x "$BUN_DIR/bun" ]; then
    log "fetching bun $BUN_VERSION"
    tmp="$(mktemp -d)"
    trap 'rm -rf "$tmp"' EXIT
    # BASELINE, not the default build: bun-linux-x64.zip requires AVX2, and a
    # plain KVM guest without it dies with "Illegal instruction" the first time
    # anything runs pi -- i.e. the tarball installs fine and then does not work,
    # on exactly the kind of machine this project exists to install on. Baseline
    # costs some JS throughput we do not notice and runs everywhere.
    curl -fsSL -o "$tmp/bun.zip" \
        "https://github.com/oven-sh/bun/releases/download/bun-v$BUN_VERSION/bun-linux-x64-baseline.zip"
    record_or_verify "bun-linux-x64-baseline-$BUN_VERSION.zip" "$tmp/bun.zip"
    unzip -q -d "$tmp" "$tmp/bun.zip"
    mkdir -p "$BUN_DIR"
    install -m755 "$tmp"/bun-linux-x64-baseline/bun "$BUN_DIR/bun"
    rm -rf "$tmp"; trap - EXIT
else
    log "bun $BUN_VERSION already vendored"
fi
"$BUN_DIR/bun" --version >/dev/null || { echo "vendored bun does not run" >&2; exit 1; }

# --- pi --------------------------------------------------------------------
# npm install (not npm pack): the published tarball has no dependency tree, and
# pi ships an npm-shrinkwrap.json so the resolved tree is deterministic.
PI_DIR="$VENDOR/pi-$PI_VERSION"
if [ ! -f "$PI_DIR/node_modules/@earendil-works/pi-coding-agent/package.json" ]; then
    log "fetching pi $PI_VERSION (npm install with its shrinkwrap)"
    mkdir -p "$PI_DIR"
    npm install --silent --omit=dev --prefix "$PI_DIR" \
        "@earendil-works/pi-coding-agent@$PI_VERSION"
else
    log "pi $PI_VERSION already vendored"
fi

# sanity: the vendored runtime can run the vendored agent
got="$("$BUN_DIR/bun" \
    "$PI_DIR/node_modules/@earendil-works/pi-coding-agent/dist/cli.js" --version)"
[ "$got" = "$PI_VERSION" ] || {
    echo "vendored bun ran pi but got version '$got', expected '$PI_VERSION'" >&2
    exit 1
}
log "vendored bun runs vendored pi $got"