Source of truth so far has been c:\Users\smoido\projects\cli on the Windows box, which has no git history of its own. This is that tree copied verbatim over SSH, minus dist/ - the PowerShell build, the POSIX port under linux/, and the presets both share. Recorded as its own commit so that everything after it is a reviewable diff rather than an undifferentiated first drop.
97 lines
3.9 KiB
Bash
97 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
|
# claude-mode bootstrap installer for Linux and macOS.
|
|
#
|
|
# Served by the Arkylx Index and run as a one-liner:
|
|
#
|
|
# curl -fsSL https://index.arkylx.com/tools/claude-mode/install.sh | bash
|
|
#
|
|
# Downloads the payload, verifies its SHA-256 against the manifest, unpacks it to
|
|
# a temp directory and runs the bundled install.sh. Nothing is written outside
|
|
# ~/.claude-mode, ~/.local/bin and your shell rc.
|
|
#
|
|
# Environment overrides:
|
|
# ARKYLX_CLAUDE_MODE_BASE base URL (default: index.arkylx.com)
|
|
# ARKYLX_CLAUDE_MODE_VERSION pin a version instead of "latest"
|
|
# ARKYLX_CODE enrolment code; reports the install to the Index
|
|
|
|
set -euo pipefail
|
|
|
|
BASE="${ARKYLX_CLAUDE_MODE_BASE:-https://index.arkylx.com/tools/claude-mode}"
|
|
BASE="${BASE%/}"
|
|
VERSION="${ARKYLX_CLAUDE_MODE_VERSION:-latest}"
|
|
|
|
green() { printf ' \033[32mok \033[0m %s\n' "$*"; }
|
|
warn() { printf ' \033[33mwarn\033[0m %s\n' "$*"; }
|
|
fail() { printf ' \033[31mFAIL\033[0m %s\n' "$*" >&2; }
|
|
|
|
printf '\n \033[36mclaude-mode installer\033[0m\n'
|
|
printf ' \033[90msource: %s (%s)\033[0m\n\n' "$BASE" "$VERSION"
|
|
|
|
# --- preflight -------------------------------------------------------------
|
|
need() { command -v "$1" >/dev/null 2>&1 || { fail "$1 is required but not installed"; exit 1; }; }
|
|
need curl
|
|
need tar
|
|
PY="${CLAUDE_MODE_PYTHON:-python3}"
|
|
command -v "$PY" >/dev/null 2>&1 || {
|
|
fail "python3 is required (claude-mode uses it for JSON handling)"
|
|
fail " Debian/Ubuntu: sudo apt install python3"
|
|
fail " Fedora/RHEL: sudo dnf install python3"
|
|
fail " macOS: xcode-select --install (or brew install python)"
|
|
exit 1
|
|
}
|
|
|
|
sha256_of() {
|
|
if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1
|
|
elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | cut -d' ' -f1
|
|
else fail 'no sha256sum or shasum available - cannot verify the download'; exit 1
|
|
fi
|
|
}
|
|
|
|
WORK="$(mktemp -d 2>/dev/null || mktemp -d -t claude-mode)"
|
|
cleanup() { rm -rf "$WORK"; }
|
|
trap cleanup EXIT
|
|
|
|
# --- manifest --------------------------------------------------------------
|
|
curl -fsSL --max-time 30 "$BASE/$VERSION/manifest.posix.json" -o "$WORK/manifest.json" || {
|
|
fail "could not fetch $BASE/$VERSION/manifest.posix.json"; exit 1; }
|
|
|
|
read_field() { "$PY" -c "import json,sys;print(json.load(open(sys.argv[1])).get(sys.argv[2],''))" "$WORK/manifest.json" "$1"; }
|
|
PKG="$(read_field package)"
|
|
EXPECTED="$(read_field sha256)"
|
|
PKGVER="$(read_field version)"
|
|
[ -n "$PKG" ] && [ -n "$EXPECTED" ] || { fail 'manifest is missing package/sha256'; exit 1; }
|
|
|
|
# --- payload ---------------------------------------------------------------
|
|
printf ' downloading %s (%s)\n' "$PKG" "$PKGVER"
|
|
curl -fsSL --max-time 120 "$BASE/$VERSION/$PKG" -o "$WORK/$PKG" || { fail 'download failed'; exit 1; }
|
|
|
|
ACTUAL="$(sha256_of "$WORK/$PKG")"
|
|
if [ "$ACTUAL" != "$EXPECTED" ]; then
|
|
fail 'checksum mismatch - refusing to install'
|
|
fail "expected $EXPECTED"
|
|
fail "actual $ACTUAL"
|
|
exit 1
|
|
fi
|
|
green 'checksum verified'
|
|
|
|
mkdir -p "$WORK/src"
|
|
tar -xzf "$WORK/$PKG" -C "$WORK/src"
|
|
[ -f "$WORK/src/linux/install.sh" ] || { fail 'package does not contain linux/install.sh'; exit 1; }
|
|
chmod +x "$WORK/src/linux/install.sh"
|
|
|
|
printf '\n'
|
|
"$WORK/src/linux/install.sh" "$@"
|
|
|
|
# --- optional report -------------------------------------------------------
|
|
# Best-effort: a failure here must never make a good install look broken.
|
|
if [ -n "${ARKYLX_CODE:-}" ] && [ "${ARKYLX_CLAUDE_MODE_REPORT:-1}" != "0" ]; then
|
|
if curl -fsS --max-time 10 -X POST "$BASE/report" \
|
|
-H 'content-type: application/json' \
|
|
-d "{\"code\":\"$ARKYLX_CODE\",\"tool\":\"claude-mode\",\"version\":\"$PKGVER\",\"hostname\":\"$(hostname 2>/dev/null || echo unknown)\",\"os\":\"$(uname -sr 2>/dev/null || echo unknown)\"}" \
|
|
>/dev/null 2>&1; then
|
|
green 'reported install to the Arkylx Index'
|
|
else
|
|
warn 'could not report to the Index (install is fine)'
|
|
fi
|
|
fi
|