From cb3909f052e926f488160a33b0fc5ef36caa3b55 Mon Sep 17 00:00:00 2001 From: Timothy Wright Date: Thu, 8 Oct 2026 15:50:44 -0400 Subject: [PATCH] Automate Grok Bot releases (#583) * Automate Grok Bot releases * Refresh Grok Bot to apt 0.66.0 and harden upstream.sh Bump both architectures to Cursor apt 0.66.0 with matching SHA256s, introduce a versioned _pool URL helper, and filter Packages stanzas by Package: grok-bot so sync stays correct if the index grows. * grok-bot: bump to 0.68.1, drop manual hold, validate pool filename Bump both architectures to Cursor apt 0.68.1 with the SHA256s from the amd64/arm64 Packages indexes (verified against the downloaded debs). Drop grok-bot from the manual holds list in docs/upstream-sources.md and have upstream.sh check that the newest stanza's Filename is the versioned pool path the PKGBUILD downloads from. Both additions come from #848. --- docs/upstream-sources.md | 2 +- pkgbuilds/grok-bot/.omarchy/package.json | 2 +- pkgbuilds/grok-bot/.omarchy/upstream.sh | 84 ++++++++++++++++++++++++ pkgbuilds/grok-bot/PKGBUILD | 14 ++-- pkgbuilds/grok-bot/update-pkgver.sh | 49 -------------- 5 files changed, 94 insertions(+), 57 deletions(-) create mode 100755 pkgbuilds/grok-bot/.omarchy/upstream.sh delete mode 100755 pkgbuilds/grok-bot/update-pkgver.sh diff --git a/docs/upstream-sources.md b/docs/upstream-sources.md index 025dab39..eb9d2207 100644 --- a/docs/upstream-sources.md +++ b/docs/upstream-sources.md @@ -219,7 +219,7 @@ in `origin` and has no effect on release selection. ## Existing manual holds -`grok-bot`, `libfprint-git`, `libretro-cap32-git`, `libretro-database-git`, `libretro-fbneo-git`, `libretro-uae-git`, `libretro-vice-git`, `quickshell-git`, `supergfxctl`. +`libfprint-git`, `libretro-cap32-git`, `libretro-database-git`, `libretro-fbneo-git`, `libretro-uae-git`, `libretro-vice-git`, `quickshell-git`, `supergfxctl`. These packages were already excluded from automatic AUR updates. The migration preserves that policy. diff --git a/pkgbuilds/grok-bot/.omarchy/package.json b/pkgbuilds/grok-bot/.omarchy/package.json index 2e8b0897..5a61bc6f 100644 --- a/pkgbuilds/grok-bot/.omarchy/package.json +++ b/pkgbuilds/grok-bot/.omarchy/package.json @@ -1,6 +1,6 @@ { "source": "local", - "sync": false, + "release_ring": "fast", "origin": { "aur": "grok-bot", "commit": "05eb78fca06b482affda28b26223cbf249d4bbcd" diff --git a/pkgbuilds/grok-bot/.omarchy/upstream.sh b/pkgbuilds/grok-bot/.omarchy/upstream.sh new file mode 100755 index 00000000..12b6249c --- /dev/null +++ b/pkgbuilds/grok-bot/.omarchy/upstream.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# Cursor publishes Grok Bot from its own Debian repository, one index per +# architecture. Each index carries the version and the SHA256, so an update +# is two small HTTP requests instead of downloading the debs, and the pool +# URL is keyed by version. bin/sync-upstream can rewrite pkgver and the +# checksums; it cannot rewrite a commit id embedded in the old +# downloads.cursor.com/grokbot/stable// URL. +set -euo pipefail + +BASE_URL="https://downloads.cursor.com/aptrepo" +declare -A DEB_ARCHES=([x86_64]=amd64 [aarch64]=arm64) + +# Print " " for the newest grok-bot stanza. Newest is +# vercmp's opinion, which is the one bin/sync-upstream and pacman both use; +# sort -V disagrees with it over versions like 1.0a. The winner's Filename +# must be the versioned pool path the PKGBUILD downloads from. +newest_release() { + local index="$1" debarch="$2" + local version sha256 filename best_version="" best_sha256="" best_filename="" + + while read -r version sha256 filename; do + [[ -n "$version" && -n "$sha256" ]] || continue + if [[ -z "$best_version" ]] || [[ "$(vercmp "$version" "$best_version")" -gt 0 ]]; then + best_version="$version" + best_sha256="$sha256" + best_filename="$filename" + fi + done < <(awk ' + { sub(/\r$/, "") } + /^Package:/ { package = $2 } + /^Version:/ { version = $2 } + /^SHA256:/ { sha256 = $2 } + /^Filename:/ { filename = $2 } + /^$/ { + if (package == "grok-bot" && version && sha256) print version, sha256, filename + package = version = sha256 = filename = "" + } + END { + if (package == "grok-bot" && version && sha256) print version, sha256, filename + } + ' <<<"$index") + + [[ -n "$best_version" ]] || return 1 + + local expected="pool/grok-bot/g/gr/grok-bot_${best_version}_${debarch}.deb" + if [[ "$best_filename" != "$expected" ]]; then + echo "Unexpected Grok Bot $best_version $debarch Filename: '${best_filename}' (expected $expected)" >&2 + return 1 + fi + + echo "$best_version $best_sha256" +} + +versions=() +declare -A checksums=() + +for arch in "${!DEB_ARCHES[@]}"; do + index=$(curl -fsSL "$BASE_URL/dists/grok-bot/main/binary-${DEB_ARCHES[$arch]}/Packages") + + read -r version sha256 <<<"$(newest_release "$index" "${DEB_ARCHES[$arch]}")" + if [[ -z "${version:-}" || -z "${sha256:-}" ]]; then + echo "No usable Grok Bot release found for $arch" >&2 + exit 1 + fi + + versions+=("$version") + checksums[$arch]="$sha256" +done + +# A release can land one architecture at a time. Wait until both agree so one +# pkgver always describes both artifacts. +for version in "${versions[@]}"; do + if [[ "$version" != "${versions[0]}" ]]; then + echo "Upstream architectures are mid-release (${versions[*]}); skipping" >&2 + echo '{}' + exit 0 + fi +done + +jq -n \ + --arg pkgver "${versions[0]}" \ + --arg x86_64 "${checksums[x86_64]}" \ + --arg aarch64 "${checksums[aarch64]}" \ + '{pkgver: $pkgver, sha256sums: {x86_64: [$x86_64], aarch64: [$aarch64]}}' diff --git a/pkgbuilds/grok-bot/PKGBUILD b/pkgbuilds/grok-bot/PKGBUILD index bcc57979..5a82f651 100644 --- a/pkgbuilds/grok-bot/PKGBUILD +++ b/pkgbuilds/grok-bot/PKGBUILD @@ -2,9 +2,8 @@ # Contributor: Omarchy pkgname=grok-bot -pkgver=0.47.0 +pkgver=0.68.1 pkgrel=1 -_commit=c1e7d7a46549956d25f53e9c0b9f59666e03aa3a pkgdesc='Grok Bot desktop agent' arch=('x86_64' 'aarch64') url='https://x.ai/bot' @@ -30,20 +29,23 @@ install=grok-bot.install _deb_x86_64="grok-bot_${pkgver}_amd64.deb" _deb_aarch64="grok-bot_${pkgver}_arm64.deb" +# Versioned pool paths — Packages indexes carry SHA256 so upstream.sh +# can bump pkgver without embedding a Cursor commit id. +_pool="https://downloads.cursor.com/aptrepo/pool/grok-bot/g/gr" source=( 'grok-bot.sh' 'grok-bot.desktop' ) source_x86_64=( - "${_deb_x86_64}::https://downloads.cursor.com/grokbot/stable/${_commit}/linux/x64/${_deb_x86_64}" + "${_deb_x86_64}::${_pool}/${_deb_x86_64}" ) source_aarch64=( - "${_deb_aarch64}::https://downloads.cursor.com/grokbot/stable/${_commit}/linux/arm64/${_deb_aarch64}" + "${_deb_aarch64}::${_pool}/${_deb_aarch64}" ) sha256sums=('6dfa6c305941afa6cbaefbeaae06d05ab5a88f31630005d25a819a160c20c7a3' '3e2a2461ea58d17ac1777616be9ba660f7cb9ceefa9292016e36c55758bf78dd') -sha256sums_x86_64=('11ca0f51a535b97af51a352adf9c0f9ecd2e1b0430a69ae9451b688a7a065808') -sha256sums_aarch64=('836f8d19d3826c6573c31ac45c7a9b797abc73381ae0d2b1e7a8dae5410e7e46') +sha256sums_x86_64=('b2be8106d2b3eae07d983d5f1ca77b657accde666dc440db2a409421ecff3359') +sha256sums_aarch64=('3f85fbe2ba3c1d122aa16f8be672076bc19146e07e9d431f37a93b85fa75a93f') noextract=("${_deb_x86_64}" "${_deb_aarch64}") package() { diff --git a/pkgbuilds/grok-bot/update-pkgver.sh b/pkgbuilds/grok-bot/update-pkgver.sh deleted file mode 100755 index 40e9474e..00000000 --- a/pkgbuilds/grok-bot/update-pkgver.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -# Resolve current Grok Bot stable from Cursor's update feed and pin PKGBUILD. -# Linux has no latest alias (linux-x64 feed returns 204). The darwin-arm64 -# sand feed publishes version + commit; the Linux .deb lives at the same commit. -# Darwin can ship first — HEAD-check the Linux URL and fail loudly if 404. -set -euo pipefail - -PKGBUILD_PATH="${1:-PKGBUILD}" -[[ -f "${PKGBUILD_PATH}" ]] || { echo "Error: PKGBUILD not found at '${PKGBUILD_PATH}'" >&2; exit 1; } - -FEED='https://api2.cursor.sh/updates/api/update/darwin-arm64/sand/0.0.0/00000000-0000-0000-0000-000000000000/stable' -json="$(curl -fsSL -H 'cache-control: no-cache' "${FEED}")" - -ver="$(jq -er '.name // .version' <<<"${json}")" -feed_url="$(jq -er '.url' <<<"${json}")" -commit="$(sed -nE 's@.*/(grokbot|sand)/stable/([0-9a-f]{40})/.*@\2@p' <<<"${feed_url}")" - -[[ -n "${ver}" && -n "${commit}" ]] || { - echo "Error: could not parse version/commit from feed: ${json}" >&2 - exit 1 -} - -deb_url="https://downloads.cursor.com/grokbot/stable/${commit}/linux/x64/Grok_Bot_${ver}.deb" -code="$(curl -fsSIL -o /dev/null -w '%{http_code}' "${deb_url}")" -[[ "${code}" == "200" ]] || { - echo "Error: Linux deb not fetchable (${code}): ${deb_url}" >&2 - exit 1 -} - -tmp="$(mktemp)" -trap 'rm -f "${tmp}"' EXIT -curl -fL --retry 3 -o "${tmp}" "${deb_url}" -sum="$(sha256sum "${tmp}" | awk '{print $1}')" - -current_ver="$(sed -nE 's/^pkgver=([^[:space:]#]+).*/\1/p' "${PKGBUILD_PATH}" | head -n1)" - -sed -i -E \ - -e "s/^_commit=.*/_commit=${commit}/" \ - -e "s/^pkgver=.*/pkgver=${ver}/" \ - -e "0,/^[[:space:]]*'[0-9a-f]{64}'/s// '${sum}'/" \ - "${PKGBUILD_PATH}" - -if [[ "${ver}" != "${current_ver}" ]]; then - sed -i -E 's/^pkgrel=.*/pkgrel=1/' "${PKGBUILD_PATH}" -fi - -echo "${ver} ${commit}" -echo "${deb_url}" -echo "${sum}"