diff --git a/AGENTS.md b/AGENTS.md index 44b3559..07bc565 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -100,7 +100,7 @@ If you touch installer code, preserve these: ## Provisioning suite (`provision/`) -Debian-only headless server bootstrap, separate from `install.sh`. `provision/run-all.sh` runs the modules in order (`upgrade base workflow claude tailscale ssh gh github sshd`) and stops at the first failure; every module is also runnable standalone and idempotent. Shared helpers live in `provision/lib.sh` (`require_debian`, `require_sudo`, `apt_update`, `apt_install`, `ensure_cmd`). `provision/test/run.sh` runs the modules in a `debian:stable` container; CI runs it when `provision/**` changes. +Debian-only headless server bootstrap, separate from `install.sh`. `provision/run-all.sh` runs the modules in order (`upgrade base workflow claude herdr tailscale ssh gh github sshd`) and stops at the first failure; every module is also runnable standalone and idempotent. Shared helpers live in `provision/lib.sh` (`require_debian`, `require_sudo`, `apt_update`, `apt_install`, `ensure_cmd`). `provision/test/run.sh` runs the modules in a `debian:stable` container; CI runs it when `provision/**` changes. If you touch provisioning code, preserve these: diff --git a/provision/herdr.sh b/provision/herdr.sh new file mode 100755 index 0000000..7fc84ec --- /dev/null +++ b/provision/herdr.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# herdr via the official install script. User-level: installs into +# ~/.local/bin, so no sudo unless curl is missing. +# Upgrades are `herdr update`, not a rerun of this. + +set -euo pipefail +source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" + +require_debian + +# Checked directly as well as by name: a fresh install is not on the calling +# shell's PATH yet, same as claude.sh. +HERDR_BIN="$HOME/.local/bin/herdr" + +if has_cmd herdr; then + log_warn "herdr already installed at $(command -v herdr); skipping install" +elif [ -x "$HERDR_BIN" ]; then + log_warn "herdr already installed at $HERDR_BIN (not on PATH); skipping install" +else + log_info "Installing herdr via official install script" + ensure_cmd curl + curl -fsSL https://herdr.dev/install.sh | sh + log_ok "herdr installed" +fi + +# Resolved through PATH, not $HERDR_BIN: this doubles as the check that a fresh +# install is actually reachable by name (lib.sh adds ~/.local/bin). +show_versions herdr diff --git a/provision/run-all.sh b/provision/run-all.sh index 4fdd73a..a27e0c8 100755 --- a/provision/run-all.sh +++ b/provision/run-all.sh @@ -6,7 +6,7 @@ set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" source ./lib.sh -MODULES=(upgrade base workflow claude tailscale ssh gh github sshd) +MODULES=(upgrade base workflow claude herdr tailscale ssh gh github sshd) require_debian require_sudo diff --git a/provision/test/inside.sh b/provision/test/inside.sh index 2643189..75f16a2 100755 --- a/provision/test/inside.sh +++ b/provision/test/inside.sh @@ -30,6 +30,7 @@ for round in 1 2; do ./provision/ssh.sh < /dev/null ./provision/gh.sh < /dev/null ./provision/claude.sh < /dev/null + ./provision/herdr.sh < /dev/null done # gh must actually be installed and runnable after the rounds @@ -94,6 +95,13 @@ out="$(env PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ grep -q "already installed at $HOME/.local/bin/claude" <<< "$out" \ || fail "lib.sh did not put ~/.local/bin on PATH for a caller that lacks it" +# Same for herdr: skip on rerun, and report a version through PATH. +out="$(./provision/herdr.sh < /dev/null)" +grep -q "already installed" <<< "$out" \ + || fail "herdr.sh rerun did not take the skip path" +grep -q "herdr: " <<< "$out" || fail "herdr.sh did not report a herdr version" +! grep -q ': ?' <<< "$out" || fail "herdr.sh could not read the herdr version" + # A bypass flag set to a value that reads as "off" must keep verification on. out="$(PROVISION_SKIP_CLAUDE_VERIFY=0 ./provision/claude.sh < /dev/null)" grep -q "signed release manifest" <<< "$out" \