Ship hermit binary (cst-agent symlink), ~/.config/hermit with legacy fallback, Hermit color theme and mini crab frames, plus SVG→PUA font build pipeline. Co-authored-by: Cursor <cursoragent@cursor.com>
231 lines
7.7 KiB
Bash
Executable File
231 lines
7.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Install or upgrade CST-Agent on Linux, WSL or macOS. Safe to rerun: an
|
|
# existing checkout is fast-forwarded, rebuilt and reinstalled.
|
|
#
|
|
# bootstrap_linux.sh [DIR] [--no-pull] [--release] [--source]
|
|
# cst-agent-update (installed by this script; same as rerunning it)
|
|
#
|
|
# --release downloads the static musl tarball for this host (fast; no compile).
|
|
# --source (default) builds from the checkout. CST_INSTALL_MODE=release|source
|
|
# overrides the flag.
|
|
#
|
|
# Env: CST_AGENT_PREFIX (install prefix, default ~/.local), CST_AGENT_DIR
|
|
# (checkout, default: current checkout or ~/CST-agent), CST_AGENT_REPO,
|
|
# CST_AGENT_VERSION (pin a release; default: cst_version.h or latest tag).
|
|
set -euo pipefail
|
|
|
|
ROOT_HINT="$(cd "$(dirname "$0")/.." 2>/dev/null && pwd || true)"
|
|
|
|
deps_hint() {
|
|
echo "==> deps: gcc/clang make pkg-config libcurl ncursesw"
|
|
if [[ "$(uname -s)" == Darwin ]]; then
|
|
echo " macOS: xcode-select --install && brew install ncurses curl pkg-config"
|
|
elif command -v pacman >/dev/null 2>&1; then
|
|
echo " Arch: sudo pacman -S --needed base-devel curl ncurses"
|
|
elif command -v apt-get >/dev/null 2>&1; then
|
|
echo " Debian/Ubuntu/WSL: sudo apt install build-essential pkg-config libcurl4-openssl-dev libncurses-dev"
|
|
elif command -v dnf >/dev/null 2>&1; then
|
|
echo " Fedora: sudo dnf install gcc make pkgconf libcurl-devel ncurses-devel"
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
echo " Alpine: sudo apk add build-base pkgconf curl-dev ncurses-dev"
|
|
fi
|
|
}
|
|
|
|
# On NixOS (outside a nix shell) build inside shell.nix.
|
|
run_make() {
|
|
if [[ -z "${IN_NIX_SHELL:-}" ]] && command -v nix-shell >/dev/null 2>&1 &&
|
|
[[ -f shell.nix ]]; then
|
|
nix-shell --run "make $*"
|
|
else
|
|
make "$@"
|
|
fi
|
|
}
|
|
|
|
install_bin() {
|
|
local prefix="$1" bin="$2"
|
|
mkdir -p "$prefix/bin"
|
|
install -m 0755 "$bin" "$prefix/bin/hermit"
|
|
ln -sfr "$prefix/bin/hermit" "$prefix/bin/cst-agent" 2>/dev/null || \
|
|
ln -sf hermit "$prefix/bin/cst-agent"
|
|
}
|
|
|
|
install_helpers() {
|
|
local prefix="$1" dir="$2"
|
|
mkdir -p "$prefix/bin"
|
|
cat >"$prefix/bin/cst-agent-update" <<EOF
|
|
#!$(command -v bash)
|
|
export CST_AGENT_PREFIX="\${CST_AGENT_PREFIX:-$prefix}"
|
|
exec bash "$dir/scripts/bootstrap_linux.sh" "$dir" "\$@"
|
|
EOF
|
|
chmod 0755 "$prefix/bin/cst-agent-update"
|
|
cat >"$prefix/bin/cst-agent-service" <<EOF
|
|
#!$(command -v bash)
|
|
# Manage the parliament seat service (foreground under systemd, or --service).
|
|
set -euo pipefail
|
|
BIN="$prefix/bin/hermit"
|
|
cmd="\${1:-status}"
|
|
case "\$cmd" in
|
|
status)
|
|
"\$BIN" --version
|
|
if command -v systemctl >/dev/null 2>&1 && systemctl --user is-active cst-agent-parliament.service >/dev/null 2>&1; then
|
|
systemctl --user status cst-agent-parliament.service --no-pager
|
|
else
|
|
"\$BIN" --service-stop >/dev/null 2>&1 || true
|
|
echo "parliament service: not managed by systemd --user (use --login / --service)"
|
|
fi
|
|
;;
|
|
install-unit)
|
|
make -C "$dir" install-service PREFIX="$prefix"
|
|
;;
|
|
start) systemctl --user start cst-agent-parliament.service ;;
|
|
stop) systemctl --user stop cst-agent-parliament.service; "\$BIN" --service-stop || true ;;
|
|
restart) systemctl --user restart cst-agent-parliament.service ;;
|
|
*)
|
|
echo "usage: cst-agent-service {status|install-unit|start|stop|restart}" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod 0755 "$prefix/bin/cst-agent-service"
|
|
}
|
|
|
|
# Fast path: fetch static release tarball for this machine.
|
|
install_from_release() {
|
|
local prefix="$1" dir="$2"
|
|
# shellcheck source=lib_release.sh
|
|
. "$dir/scripts/lib_release.sh"
|
|
ROOT="$dir"
|
|
local arch
|
|
arch="$(cst_host_release_arch)" || {
|
|
echo "no prebuilt release for $(uname -m); use --source" >&2
|
|
return 1
|
|
}
|
|
local ver="${CST_AGENT_VERSION:-}"
|
|
if [[ -z "$ver" ]]; then
|
|
ver="$(cst_version)"
|
|
fi
|
|
local name="hermit-$ver-linux-$arch.tar.gz"
|
|
# One-cycle legacy asset name fallback handled below if download fails.
|
|
local tmp
|
|
tmp="$(mktemp -d /tmp/cst-rel.XXXXXX)"
|
|
# shellcheck disable=SC2046
|
|
local legacy="cst-agent-$ver-linux-$arch.tar.gz"
|
|
if ! cst_fetch "$tmp/$name" $(cst_release_asset_urls "$ver" "$name"); then
|
|
if ! cst_fetch "$tmp/$legacy" $(cst_release_asset_urls "$ver" "$legacy"); then
|
|
echo "release download failed; falling back to source build" >&2
|
|
rm -rf "$tmp"
|
|
return 1
|
|
fi
|
|
name="$legacy"
|
|
fi
|
|
tar -C "$tmp" -xzf "$tmp/$name"
|
|
local bin
|
|
bin="$(find "$tmp" -type f \( -name hermit -o -name cst-agent \) | head -1)"
|
|
[[ -x "$bin" ]] || { echo "tarball missing hermit/cst-agent" >&2; rm -rf "$tmp"; return 1; }
|
|
install_bin "$prefix" "$bin"
|
|
rm -rf "$tmp"
|
|
echo "==> installed release $ver ($arch) -> $prefix/bin/cst-agent"
|
|
}
|
|
|
|
main() {
|
|
local repo_url="${CST_AGENT_REPO:-https://git.whcself.xyz/WHC/CST-agent.git}"
|
|
local prefix="${CST_AGENT_PREFIX:-$HOME/.local}"
|
|
local dir="" pull=1 changed=0 mode="${CST_INSTALL_MODE:-source}" arg
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--no-pull) pull=0 ;;
|
|
--release) mode=release ;;
|
|
--source) mode=source ;;
|
|
--rebuilt) changed=1 ;; # internal: re-exec after a pull
|
|
-h | --help)
|
|
sed -n '2,16p' "$0"
|
|
return 0
|
|
;;
|
|
*) dir="$arg" ;;
|
|
esac
|
|
done
|
|
if [[ -z "$dir" ]]; then
|
|
if [[ -n "${CST_AGENT_DIR:-}" ]]; then
|
|
dir="$CST_AGENT_DIR"
|
|
elif [[ -f Makefile && -f src/main.c && -d .git ]]; then
|
|
dir="$(pwd)"
|
|
elif [[ -n "$ROOT_HINT" && -f "$ROOT_HINT/Makefile" ]]; then
|
|
dir="$ROOT_HINT"
|
|
else
|
|
dir="$HOME/CST-agent"
|
|
fi
|
|
fi
|
|
|
|
local old="" new=""
|
|
if [[ ! -f "$dir/Makefile" ]]; then
|
|
echo "==> git clone $repo_url -> $dir"
|
|
git clone "$repo_url" "$dir"
|
|
changed=1
|
|
elif ((pull)); then
|
|
old="$(git -C "$dir" rev-parse HEAD)"
|
|
if git -C "$dir" diff --quiet && git -C "$dir" diff --cached --quiet; then
|
|
echo "==> git pull ($dir)"
|
|
git -C "$dir" pull --ff-only
|
|
else
|
|
echo "warning: $dir has local changes; skipping git pull" >&2
|
|
fi
|
|
new="$(git -C "$dir" rev-parse HEAD)"
|
|
if [[ "$old" != "$new" ]]; then
|
|
echo " $(git -C "$dir" log --oneline "$old..$new" | wc -l) new commit(s)"
|
|
# The script itself may have changed: continue with the new version.
|
|
exec bash "$dir/scripts/bootstrap_linux.sh" "$dir" --no-pull --rebuilt \
|
|
${mode:+--$mode}
|
|
fi
|
|
fi
|
|
cd "$dir"
|
|
dir="$(pwd)"
|
|
|
|
if [[ "$mode" == release ]]; then
|
|
if install_from_release "$prefix" "$dir"; then
|
|
install_helpers "$prefix" "$dir"
|
|
echo
|
|
echo "OK: $("$prefix/bin/hermit" --version) (release install)"
|
|
case ":$PATH:" in
|
|
*":$prefix/bin:"*) ;;
|
|
*) echo "Add to PATH: export PATH=\"$prefix/bin:\$PATH\"" ;;
|
|
esac
|
|
echo "Upgrade: cst-agent-update --release Rebuild from source: --source"
|
|
return 0
|
|
fi
|
|
echo "==> continuing with source build"
|
|
fi
|
|
|
|
local jobs
|
|
jobs="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)"
|
|
echo "==> build (incremental, -j$jobs)"
|
|
# Prefer incremental rebuilds. Set CST_AGENT_CLEAN=1 to force a clean tree.
|
|
if [[ "${CST_AGENT_CLEAN:-0}" == "1" ]]; then
|
|
run_make clean >/dev/null 2>&1 || true
|
|
fi
|
|
: "${changed:=0}"
|
|
if ! run_make -j"$jobs"; then
|
|
deps_hint
|
|
return 1
|
|
fi
|
|
if [[ "${CST_AGENT_SKIP_CHECK:-0}" != "1" ]]; then
|
|
run_make -j"$jobs" check >/dev/null 2>&1 || echo "warning: some tests failed (run 'make check')"
|
|
fi
|
|
|
|
echo "==> install to $prefix/bin"
|
|
install_bin "$prefix" "$dir/cst-agent"
|
|
install_helpers "$prefix" "$dir"
|
|
|
|
echo
|
|
echo "OK: $("$prefix/bin/hermit" --version)"
|
|
case ":$PATH:" in
|
|
*":$prefix/bin:"*) ;;
|
|
*) echo "Add to PATH: export PATH=\"$prefix/bin:\$PATH\"" ;;
|
|
esac
|
|
echo "Run 'hermit' (or 'cst-agent') in a project; upgrade with 'cst-agent-update'."
|
|
echo "Fast upgrade from Release: 'cst-agent-update --release'."
|
|
echo "Parliament helper: 'cst-agent-service status|install-unit'."
|
|
echo "The first start asks for the provider and its API key and saves them."
|
|
}
|
|
|
|
main "$@"
|