fe27bc4cf2
- Added support for braced escape sequences (\p{...}, \P{...}, \x{...}, \u{...}) in regex pattern sanitization to properly preserve unicode property escapes and hex escapes.
- Improved LSP client message writing by simplifying header encoding and refactoring abort signal handling with the untilAborted utility.
- Enhanced native addon installation script to dynamically fetch release tags from GitHub API instead of using hardcoded versions.
- Relaxed native addon validation to only error when no addons are found rather than when any are missing, improving flexibility in addon availability.
285 lines
7.6 KiB
Bash
Executable File
285 lines
7.6 KiB
Bash
Executable File
#!/bin/sh
|
|
set -e
|
|
|
|
# OMP Coding Agent Installer
|
|
# Usage: curl -fsSL https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.sh | sh
|
|
#
|
|
# Options:
|
|
# --source Install via bun (installs bun if needed)
|
|
# --binary Always install prebuilt binary
|
|
# --ref <ref> Install specific tag/commit/branch
|
|
# -r <ref> Shorthand for --ref
|
|
|
|
REPO="can1357/oh-my-pi"
|
|
PACKAGE="@oh-my-pi/pi-coding-agent"
|
|
INSTALL_DIR="${PI_INSTALL_DIR:-$HOME/.local/bin}"
|
|
MIN_BUN_VERSION="1.3.7"
|
|
|
|
# Parse arguments
|
|
MODE=""
|
|
REF=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--source)
|
|
MODE="source"
|
|
shift
|
|
;;
|
|
--binary)
|
|
MODE="binary"
|
|
shift
|
|
;;
|
|
--ref)
|
|
shift
|
|
if [ -z "$1" ]; then
|
|
echo "Missing value for --ref"
|
|
exit 1
|
|
fi
|
|
REF="$1"
|
|
shift
|
|
;;
|
|
--ref=*)
|
|
REF="${1#*=}"
|
|
if [ -z "$REF" ]; then
|
|
echo "Missing value for --ref"
|
|
exit 1
|
|
fi
|
|
shift
|
|
;;
|
|
-r)
|
|
shift
|
|
if [ -z "$1" ]; then
|
|
echo "Missing value for -r"
|
|
exit 1
|
|
fi
|
|
REF="$1"
|
|
shift
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# If a ref is provided, default to source install
|
|
if [ -n "$REF" ] && [ -z "$MODE" ]; then
|
|
MODE="source"
|
|
fi
|
|
|
|
# Check if bun is available
|
|
has_bun() {
|
|
command -v bun >/dev/null 2>&1
|
|
}
|
|
|
|
version_ge() {
|
|
current="$1"
|
|
minimum="$2"
|
|
|
|
current_major="${current%%.*}"
|
|
current_rest="${current#*.}"
|
|
current_minor="${current_rest%%.*}"
|
|
current_patch="${current_rest#*.}"
|
|
current_patch="${current_patch%%.*}"
|
|
|
|
minimum_major="${minimum%%.*}"
|
|
minimum_rest="${minimum#*.}"
|
|
minimum_minor="${minimum_rest%%.*}"
|
|
minimum_patch="${minimum_rest#*.}"
|
|
minimum_patch="${minimum_patch%%.*}"
|
|
|
|
if [ "$current_major" -ne "$minimum_major" ]; then
|
|
[ "$current_major" -gt "$minimum_major" ]
|
|
return $?
|
|
fi
|
|
|
|
if [ "$current_minor" -ne "$minimum_minor" ]; then
|
|
[ "$current_minor" -gt "$minimum_minor" ]
|
|
return $?
|
|
fi
|
|
|
|
[ "$current_patch" -ge "$minimum_patch" ]
|
|
}
|
|
|
|
require_bun_version() {
|
|
version_raw=$(bun --version 2>/dev/null || true)
|
|
if [ -z "$version_raw" ]; then
|
|
echo "Failed to read bun version"
|
|
exit 1
|
|
fi
|
|
|
|
version_clean=${version_raw%%-*}
|
|
if ! version_ge "$version_clean" "$MIN_BUN_VERSION"; then
|
|
echo "Bun ${MIN_BUN_VERSION} or newer is required. Current version: ${version_clean}"
|
|
echo "Upgrade Bun at https://bun.sh/docs/installation"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Check if git is available
|
|
has_git() {
|
|
command -v git >/dev/null 2>&1
|
|
}
|
|
|
|
# Install bun
|
|
install_bun() {
|
|
echo "Installing bun..."
|
|
if command -v bash >/dev/null 2>&1; then
|
|
curl -fsSL https://bun.sh/install | bash
|
|
else
|
|
echo "bash not found; attempting install with sh..."
|
|
curl -fsSL https://bun.sh/install | sh
|
|
fi
|
|
export BUN_INSTALL="$HOME/.bun"
|
|
export PATH="$BUN_INSTALL/bin:$PATH"
|
|
require_bun_version
|
|
}
|
|
|
|
# Check if git-lfs is available
|
|
has_git_lfs() {
|
|
command -v git-lfs >/dev/null 2>&1
|
|
}
|
|
|
|
# Install via bun
|
|
install_via_bun() {
|
|
echo "Installing via bun..."
|
|
if [ -n "$REF" ]; then
|
|
if ! has_git; then
|
|
echo "git is required for --ref when installing from source"
|
|
exit 1
|
|
fi
|
|
|
|
TMP_DIR="$(mktemp -d)"
|
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
|
|
if git clone --depth 1 --branch "$REF" "https://github.com/${REPO}.git" "$TMP_DIR" >/dev/null 2>&1; then
|
|
:
|
|
else
|
|
git clone "https://github.com/${REPO}.git" "$TMP_DIR"
|
|
(cd "$TMP_DIR" && git checkout "$REF")
|
|
fi
|
|
|
|
# Pull LFS files
|
|
if has_git_lfs; then
|
|
(cd "$TMP_DIR" && git lfs pull)
|
|
fi
|
|
|
|
if [ ! -d "$TMP_DIR/packages/coding-agent" ]; then
|
|
echo "Expected package at ${TMP_DIR}/packages/coding-agent"
|
|
exit 1
|
|
fi
|
|
|
|
bun install -g "$TMP_DIR/packages/coding-agent" || {
|
|
echo "Failed to install from source"
|
|
exit 1
|
|
}
|
|
else
|
|
bun install -g "$PACKAGE" || {
|
|
echo "Failed to install $PACKAGE"
|
|
exit 1
|
|
}
|
|
fi
|
|
echo ""
|
|
echo "✓ Installed omp via bun"
|
|
echo "Run 'omp' to get started!"
|
|
}
|
|
|
|
# Install binary from GitHub releases
|
|
install_binary() {
|
|
# Detect platform
|
|
OS="$(uname -s)"
|
|
ARCH="$(uname -m)"
|
|
|
|
case "$OS" in
|
|
Linux) PLATFORM="linux" ;;
|
|
Darwin) PLATFORM="darwin" ;;
|
|
*) echo "Unsupported OS: $OS"; exit 1 ;;
|
|
esac
|
|
|
|
case "$ARCH" in
|
|
x86_64|amd64) ARCH="x64" ;;
|
|
arm64|aarch64) ARCH="arm64" ;;
|
|
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
|
|
esac
|
|
|
|
BINARY="omp-${PLATFORM}-${ARCH}"
|
|
# Get release tag
|
|
if [ -n "$REF" ]; then
|
|
echo "Fetching release $REF..."
|
|
if RELEASE_JSON=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/tags/${REF}"); then
|
|
LATEST=$(echo "$RELEASE_JSON" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
|
else
|
|
echo "Release tag not found: $REF"
|
|
echo "For branch/commit installs, use --source with --ref."
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Fetching latest release..."
|
|
RELEASE_JSON=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest")
|
|
LATEST=$(echo "$RELEASE_JSON" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
|
fi
|
|
|
|
if [ -z "$LATEST" ]; then
|
|
echo "Failed to fetch release tag"
|
|
exit 1
|
|
fi
|
|
echo "Using version: $LATEST"
|
|
|
|
mkdir -p "$INSTALL_DIR"
|
|
# Download binary
|
|
BINARY_URL="https://github.com/${REPO}/releases/download/${LATEST}/${BINARY}"
|
|
echo "Downloading ${BINARY}..."
|
|
curl -fsSL "$BINARY_URL" -o "${INSTALL_DIR}/omp"
|
|
chmod +x "${INSTALL_DIR}/omp"
|
|
downloaded_native=0
|
|
if [ "$ARCH" = "x64" ]; then
|
|
for variant in modern baseline; do
|
|
NATIVE_ADDON="pi_natives.${PLATFORM}-${ARCH}-${variant}.node"
|
|
NATIVE_URL="https://github.com/${REPO}/releases/download/${LATEST}/${NATIVE_ADDON}"
|
|
echo "Downloading ${NATIVE_ADDON}..."
|
|
curl -fsSL "$NATIVE_URL" -o "${INSTALL_DIR}/${NATIVE_ADDON}" || {
|
|
echo "Failed to download ${NATIVE_ADDON}"
|
|
exit 1
|
|
}
|
|
downloaded_native=$((downloaded_native + 1))
|
|
done
|
|
else
|
|
NATIVE_ADDON="pi_natives.${PLATFORM}-${ARCH}.node"
|
|
NATIVE_URL="https://github.com/${REPO}/releases/download/${LATEST}/${NATIVE_ADDON}"
|
|
echo "Downloading ${NATIVE_ADDON}..."
|
|
curl -fsSL "$NATIVE_URL" -o "${INSTALL_DIR}/${NATIVE_ADDON}"
|
|
downloaded_native=1
|
|
fi
|
|
echo ""
|
|
echo "✓ Installed omp to ${INSTALL_DIR}/omp"
|
|
echo "✓ Installed ${downloaded_native} native addon file(s) to ${INSTALL_DIR}"
|
|
|
|
# Check if in PATH
|
|
case ":$PATH:" in
|
|
*":$INSTALL_DIR:"*) echo "Run 'omp' to get started!" ;;
|
|
*) echo "Add ${INSTALL_DIR} to your PATH, then run 'omp'" ;;
|
|
esac
|
|
}
|
|
|
|
# Main logic
|
|
case "$MODE" in
|
|
source)
|
|
if ! has_bun; then
|
|
install_bun
|
|
fi
|
|
require_bun_version
|
|
install_via_bun
|
|
;;
|
|
binary)
|
|
install_binary
|
|
;;
|
|
*)
|
|
# Default: use bun if available, otherwise binary
|
|
if has_bun; then
|
|
require_bun_version
|
|
install_via_bun
|
|
else
|
|
install_binary
|
|
fi
|
|
;;
|
|
esac
|