From 64d47934715959c6d52172c68ac6f15d1cb0b954 Mon Sep 17 00:00:00 2001 From: sommerfeld Date: Thu, 17 Sep 2026 15:05:36 +0100 Subject: Manage AI agent releases and shared settings --- nix/update-releases.sh | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 nix/update-releases.sh (limited to 'nix/update-releases.sh') diff --git a/nix/update-releases.sh b/nix/update-releases.sh new file mode 100644 index 0000000..661bec5 --- /dev/null +++ b/nix/update-releases.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash +set -euo pipefail + +if ! command -v nix >/dev/null 2>&1; then + echo "nix not installed; skipping release update" >&2 + exit 0 +fi + +repo_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) +lockfile="$repo_root/nix/releases.json" +tmp=$(mktemp) +trap 'rm -f "$tmp"' EXIT + +fetch_url() { + local response + if response=$(curl --fail-with-body -sSL "$1"); then + printf '%s\n' "$response" + else + printf 'Failed to fetch %s\n%s\n' "$1" "$response" >&2 + return 1 + fi +} + +github_api() { + if command -v gh >/dev/null 2>&1 && gh auth token --hostname github.com >/dev/null 2>&1; then + gh api --hostname github.com "$1" + else + fetch_url "https://api.github.com/$1" || { + echo 'For a GitHub rate limit, wait for reset or authenticate with: gh auth login --hostname github.com' >&2 + return 1 + } + fi +} + +github_asset() { + local repository=$1 + local asset=$2 + local release + + release=$(github_api "repos/$repository/releases/latest") || return + jq -er --arg asset "$asset" ' + . as $release + | .assets[] + | select(.name == $asset) + | [$release.tag_name, .browser_download_url, .digest] + | @tsv + ' <<<"$release" +} + +sri_hash() { + local digest=${1#sha256:} + nix hash convert --hash-algo sha256 --to sri "$digest" +} + +claude_base=https://downloads.claude.ai/claude-code-releases +claude_version=$(fetch_url "$claude_base/latest") +claude_manifest=$(fetch_url "$claude_base/$claude_version/manifest.zst.json") +claude_binary=$(jq -er '.platforms["linux-x64"].binary' <<<"$claude_manifest") +claude_digest=$(jq -er '.platforms["linux-x64"].checksum' <<<"$claude_manifest") +claude_url="$claude_base/$claude_version/linux-x64/$claude_binary" +asset_info=$(github_asset openai/codex codex-package-x86_64-unknown-linux-musl.tar.gz) +read -r codex_tag codex_url codex_digest <<<"$asset_info" +asset_info=$(github_asset github/copilot-cli copilot-linux-x64.tar.gz) +read -r copilot_tag copilot_url copilot_digest <<<"$asset_info" +hermes_release=$(github_api repos/NousResearch/hermes-agent/releases/latest) +hermes_tag=$(jq -er .tag_name <<<"$hermes_release") +hermes_version=$(jq -er '.name | capture("^Hermes Agent v(?[0-9]+\\.[0-9]+\\.[0-9]+)").version' <<<"$hermes_release") +hermes_rev=$( + github_api "repos/NousResearch/hermes-agent/commits/$hermes_tag" | + jq -er .sha +) +asset_info=$(github_asset can1357/oh-my-pi omp-linux-x64) +read -r omp_tag omp_url omp_digest <<<"$asset_info" +asset_info=$(github_asset anomalyco/opencode opencode-linux-x64.tar.gz) +read -r opencode_tag opencode_url opencode_digest <<<"$asset_info" +asset_info=$(github_asset OpenRouterLabs/ori-releases ori-linux-x64) +read -r ori_tag ori_url ori_digest <<<"$asset_info" + +codex_version=${codex_tag#rust-v} +copilot_version=${copilot_tag#v} +omp_version=${omp_tag#v} +opencode_version=${opencode_tag#v} +ori_version=${ori_tag#cli-} +ori_version=${ori_version/-/+} +if [[ ! $claude_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ || + $codex_version == "$codex_tag" || + $copilot_version == "$copilot_tag" || + ! $hermes_tag =~ ^v[0-9]{4}\.[0-9]{1,2}\.[0-9]{1,2}$ || + ! $hermes_rev =~ ^[0-9a-f]{40}$ || + $omp_version == "$omp_tag" || + $opencode_version == "$opencode_tag" || + $ori_version == "$ori_tag" ]]; then + echo "unexpected release tag" >&2 + exit 1 +fi +claude_hash=$(sri_hash "$claude_digest") +codex_hash=$(sri_hash "$codex_digest") +copilot_hash=$(sri_hash "$copilot_digest") +omp_hash=$(sri_hash "$omp_digest") +opencode_hash=$(sri_hash "$opencode_digest") +ori_hash=$(sri_hash "$ori_digest") + +jq -n \ + --arg claude_version "$claude_version" \ + --arg claude_url "$claude_url" \ + --arg claude_hash "$claude_hash" \ + --arg codex_version "$codex_version" \ + --arg codex_url "$codex_url" \ + --arg codex_hash "$codex_hash" \ + --arg copilot_version "$copilot_version" \ + --arg copilot_url "$copilot_url" \ + --arg copilot_hash "$copilot_hash" \ + --arg hermes_version "$hermes_version" \ + --arg hermes_tag "$hermes_tag" \ + --arg hermes_rev "$hermes_rev" \ + --arg omp_version "$omp_version" \ + --arg omp_url "$omp_url" \ + --arg omp_hash "$omp_hash" \ + --arg opencode_version "$opencode_version" \ + --arg opencode_url "$opencode_url" \ + --arg opencode_hash "$opencode_hash" \ + --arg ori_version "$ori_version" \ + --arg ori_url "$ori_url" \ + --arg ori_hash "$ori_hash" \ + '{ + claude: {version: $claude_version, url: $claude_url, hash: $claude_hash}, + codex: {version: $codex_version, url: $codex_url, hash: $codex_hash}, + copilot: {version: $copilot_version, url: $copilot_url, hash: $copilot_hash}, + hermes: {version: $hermes_version, tag: $hermes_tag, rev: $hermes_rev}, + omp: {version: $omp_version, url: $omp_url, hash: $omp_hash}, + opencode: {version: $opencode_version, url: $opencode_url, hash: $opencode_hash}, + ori: {version: $ori_version, url: $ori_url, hash: $ori_hash} + }' >"$tmp" + +if cmp -s "$tmp" "$lockfile"; then + echo "release lock is current" + exit 0 +fi + +chmod 0644 "$tmp" +mv "$tmp" "$lockfile" +echo "updated: nix/releases.json" -- cgit v1.3.1