#!/bin/sh # Installs knotless: `knotless`, `git-remote-knotless` and `knotless-mcp`, # and `knotless-run`, `knotless-triage`, `knotless-agent` and # `knotless-claude-review` for running a runner, labeller or reviewer, # from the releases of the knotless-serve that handed out this script. # # curl -fsSL __KNOTLESS_URL__/install.sh | sh # # KNOTLESS_INSTALL_DIR is where they go ($HOME/.local/bin), and # KNOTLESS_VERSION which release (the latest). set -eu releases="__KNOTLESS_URL__/releases" dir="${KNOTLESS_INSTALL_DIR:-$HOME/.local/bin}" fail() { echo "knotless: $*" >&2 exit 1 } case "$(uname -s)" in Darwin) os=apple-darwin ;; Linux) os=unknown-linux-musl ;; *) fail "no build for $(uname -s): build from a clone with cargo install --path crates/knotless" ;; esac case "$(uname -m)" in arm64 | aarch64) arch=aarch64 ;; x86_64 | amd64) arch=x86_64 ;; *) fail "no build for $(uname -m): build from a clone with cargo install --path crates/knotless" ;; esac target="$arch-$os" # $1 into the file $2, or to stdout with none. fetch() { if command -v curl >/dev/null; then curl -fsSL "$1" -o "${2:--}" elif command -v wget >/dev/null; then wget -q "$1" -O "${2:--}" else fail "needs curl or wget" fi } sha256() { if command -v sha256sum >/dev/null; then sha256sum "$1" | cut -d' ' -f1 else shasum -a 256 "$1" | cut -d' ' -f1 fi } version="${KNOTLESS_VERSION:-$(fetch "$releases/latest")}" || fail "no release at $releases" name="knotless-$version-$target" tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT echo "knotless: installing $version for $target into $dir" fetch "$releases/$version/$name.tar.gz" "$tmp/$name.tar.gz" || fail "no $name at $releases" fetch "$releases/$version/$name.tar.gz.sha256" "$tmp/sum" || fail "no checksum for $name" [ "$(sha256 "$tmp/$name.tar.gz")" = "$(cut -d' ' -f1 "$tmp/sum")" ] || fail "$name.tar.gz does not match its checksum" tar -xzf "$tmp/$name.tar.gz" -C "$tmp" mkdir -p "$dir" for bin in knotless git-remote-knotless knotless-mcp \ knotless-run knotless-triage knotless-agent knotless-claude-review; do # A release from before these shipped has only the first three. case "$bin" in knotless | git-remote-knotless | knotless-mcp) ;; *) [ -f "$tmp/$name/$bin" ] || continue ;; esac # Moved into place, so a running copy is replaced rather than written over. cp "$tmp/$name/$bin" "$dir/.$bin.new" chmod 755 "$dir/.$bin.new" mv -f "$dir/.$bin.new" "$dir/$bin" done command -v git >/dev/null || echo "knotless: git is not installed, and git-remote-knotless needs it" case ":$PATH:" in *":$dir:"*) ;; *) echo "knotless: $dir is not on your PATH; add it, for git to find git-remote-knotless" ;; esac cat <