mirror of
https://github.com/bigbeartechworld/big-bear-scripts.git
synced 2026-03-31 06:33:56 -04:00
🐻 feat(install-cursor): Add script to install Cursor AI (#41)
This commit adds a new script `run.sh` to the `install-cursor` directory. The script automates the process of downloading and installing the Cursor AI application for various platforms (macOS, Linux, and Windows). The key changes include: - Fetching the latest version information from a JSON file - Detecting the user's operating system and architecture - Downloading the appropriate binary for the detected platform - Verifying the binary's signature and notarization status on macOS - Installing the application on the user's system This script aims to simplify the installation process and ensure a smooth user experience when setting up the Cursor AI application.
This commit is contained in:
135
install-cursor/README.md
Normal file
135
install-cursor/README.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Install Cursor (Cross-Platform Installer)
|
||||
|
||||
Easily download and install any version of [Cursor](https://www.cursor.com/) on **macOS**, **Linux**, or **Windows** from the command line.
|
||||
This script is part of the [big-bear-scripts](https://github.com/bigbeartechworld/big-bear-scripts) collection.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Interactive version picker** – choose any available Cursor version, or install the latest by default.
|
||||
- **Cross-platform** – supports macOS (Intel & Apple Silicon), Linux (x86_64 & ARM64), and Windows.
|
||||
- **Security checks** – verifies download sources and (on macOS) checks app signature and notarization.
|
||||
- **Automatic installation** – handles mounting, copying, and permissions for you.
|
||||
- **Safe cleanup** – removes temporary files after installation.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
Run the installer directly from your terminal:
|
||||
|
||||
```bash
|
||||
bash -c "$(wget -qLO - https://raw.githubusercontent.com/bigbeartechworld/big-bear-scripts/master/install-cursor/run.sh)"
|
||||
```
|
||||
|
||||
Or, using `curl`:
|
||||
|
||||
```bash
|
||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/bigbeartechworld/big-bear-scripts/master/install-cursor/run.sh)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **curl** (for downloading files)
|
||||
- **jq** (for parsing JSON)
|
||||
- **wget** (optional, for the quick start command)
|
||||
- **macOS only:**
|
||||
- `hdiutil`, `codesign`, `spctl`, and `sudo` (for DMG mounting, signature, and notarization checks)
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Fetches** the latest Cursor version list from the official source.
|
||||
2. **Prompts** you to pick a version (or defaults to the latest).
|
||||
3. **Detects** your platform and downloads the correct binary.
|
||||
4. **Verifies** the download source for safety.
|
||||
5. **Installs** Cursor:
|
||||
- **macOS:** Mounts DMG, verifies signature, installs to `/Applications`.
|
||||
- **Linux:** Saves AppImage to `~/Applications/`.
|
||||
- **Windows:** Saves installer to `~/Downloads/` (run manually).
|
||||
6. **Cleans up** all temporary files.
|
||||
|
||||
---
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
📥 Fetching version list...
|
||||
🧭 Available Cursor Versions:
|
||||
1) Latest (default)
|
||||
2) 0.22.2
|
||||
3) 0.22.1
|
||||
#? 1
|
||||
🆕 Using latest version: 0.22.2
|
||||
🔗 Downloading: https://downloads.cursor.com/...
|
||||
💿 Mounting DMG...
|
||||
🔍 Verifying app signature...
|
||||
✅ App is properly signed and verified.
|
||||
🛡️ Checking notarization status with spctl...
|
||||
✅ App is notarized and passes Gatekeeper checks.
|
||||
🔐 Requesting admin rights to install to /Applications...
|
||||
✅ Installed Cursor 0.22.2 to /Applications
|
||||
🎉 Done!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
- **Download host and JSON source are validated** before proceeding.
|
||||
- **macOS:** App signature and notarization are checked for extra safety.
|
||||
- **Linux/Windows:** No signature check; always verify the source if you have concerns.
|
||||
|
||||
---
|
||||
|
||||
## Testing Status
|
||||
|
||||
| Platform | Testing Status |
|
||||
| -------- | -------------- |
|
||||
| macOS | Fully Tested |
|
||||
| Windows | Not Tested |
|
||||
| Linux | Not Tested |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Missing dependencies?**
|
||||
Install them with:
|
||||
- macOS: `brew install jq`
|
||||
- Linux: `sudo apt-get install jq`
|
||||
- **Permission denied?**
|
||||
On macOS, you may be prompted for your password to install to `/Applications`.
|
||||
- **Unsupported OS or architecture?**
|
||||
The script will exit with a clear error message.
|
||||
|
||||
If you encounter any issues, particularly on Windows or Linux, please let us know by opening an issue or visiting the community forum.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
---
|
||||
|
||||
## Credits
|
||||
|
||||
Script by [BigBearTechWorld](https://github.com/bigbeartechworld) community contributors.
|
||||
Special thanks to the [oslook/cursor-ai-downloads](https://github.com/oslook/cursor-ai-downloads) repository for providing the Cursor version history data.
|
||||
Not affiliated with Cursor.
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
If this script is helpful to you, consider supporting the project on [Ko-fi](https://ko-fi.com/bigbeartechworld)!
|
||||
|
||||
---
|
||||
|
||||
**Enjoy your new Cursor install!**
|
||||
For issues, suggestions, or support, please visit the [BigBearTechWorld Community Forum](https://community.bigbeartechworld.com) or open an issue in the [big-bear-scripts repo](https://github.com/bigbeartechworld/big-bear-scripts/issues).
|
||||
166
install-cursor/run.sh
Normal file
166
install-cursor/run.sh
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
# === Constants ===
|
||||
JSON_URL="https://raw.githubusercontent.com/oslook/cursor-ai-downloads/refs/heads/main/version-history.json"
|
||||
EXPECTED_JSON_HOST="raw.githubusercontent.com"
|
||||
EXPECTED_DOWNLOAD_HOST="downloads.cursor.com"
|
||||
TMP_DIR=$(mktemp -d)
|
||||
|
||||
# === Validate JSON host ===
|
||||
JSON_HOST=$(echo "$JSON_URL" | awk -F/ '{print $3}')
|
||||
if [ "$JSON_HOST" != "$EXPECTED_JSON_HOST" ]; then
|
||||
echo "❌ Error: Unexpected JSON host: $JSON_HOST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# === Download JSON ===
|
||||
echo "📥 Fetching version list..."
|
||||
curl -fsSL "$JSON_URL" -o "$TMP_DIR/version-history.json"
|
||||
|
||||
# === Show versions and prompt ===
|
||||
echo "🧭 Available Cursor Versions:"
|
||||
VERSIONS=$(jq -r '.versions[].version' "$TMP_DIR/version-history.json")
|
||||
VERSION_ARRAY=($VERSIONS) # convert to bash array
|
||||
|
||||
# Insert "Latest (default)" at the top visually
|
||||
PS3=$'\n#? '
|
||||
select USER_CHOICE in "Latest (default)" "${VERSION_ARRAY[@]}"; do
|
||||
if [[ "$REPLY" == "1" || -z "$REPLY" ]]; then
|
||||
VERSION="${VERSION_ARRAY[0]}"
|
||||
echo "🆕 Using latest version: $VERSION"
|
||||
break
|
||||
elif [[ "$REPLY" =~ ^[0-9]+$ && "$REPLY" -le $((${#VERSION_ARRAY[@]} + 1)) ]]; then
|
||||
VERSION="${VERSION_ARRAY[$((REPLY-2))]}"
|
||||
echo "📦 Using version: $VERSION"
|
||||
break
|
||||
else
|
||||
echo "❌ Invalid selection. Try again."
|
||||
fi
|
||||
done
|
||||
|
||||
# === Detect platform ===
|
||||
UNAME_OUT="$(uname -s)"
|
||||
ARCH_OUT="$(uname -m)"
|
||||
OS=""
|
||||
PLATFORM=""
|
||||
|
||||
case "$UNAME_OUT" in
|
||||
Darwin)
|
||||
OS="macos"
|
||||
case "$ARCH_OUT" in
|
||||
arm64) PLATFORM="darwin-arm64" ;;
|
||||
x86_64) PLATFORM="darwin-x64" ;;
|
||||
*) PLATFORM="darwin-universal" ;;
|
||||
esac
|
||||
;;
|
||||
Linux)
|
||||
OS="linux"
|
||||
case "$ARCH_OUT" in
|
||||
x86_64) PLATFORM="linux-x64" ;;
|
||||
aarch64|arm64) PLATFORM="linux-arm64" ;;
|
||||
*) echo "❌ Unsupported Linux architecture: $ARCH_OUT"; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
MINGW*|MSYS*|CYGWIN*)
|
||||
OS="windows"
|
||||
case "$ARCH_OUT" in
|
||||
x86_64) PLATFORM="win32-x64-user" ;;
|
||||
aarch64|arm64) PLATFORM="win32-arm64-user" ;;
|
||||
*) echo "❌ Unsupported Windows architecture: $ARCH_OUT"; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "❌ Unsupported OS: $UNAME_OUT"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# === Extract URL ===
|
||||
VERSION_INDEX=$(jq ".versions | map(.version == \"$VERSION\") | index(true)" "$TMP_DIR/version-history.json")
|
||||
DOWNLOAD_URL=$(jq -r ".versions[$VERSION_INDEX].platforms[\"$PLATFORM\"]" "$TMP_DIR/version-history.json")
|
||||
|
||||
if [[ -z "$DOWNLOAD_URL" || "$DOWNLOAD_URL" == "null" ]]; then
|
||||
echo "❌ No binary for $PLATFORM in version $VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DOWNLOAD_HOST=$(echo "$DOWNLOAD_URL" | awk -F/ '{print $3}')
|
||||
if [ "$DOWNLOAD_HOST" != "$EXPECTED_DOWNLOAD_HOST" ]; then
|
||||
echo "❌ Untrusted host: $DOWNLOAD_HOST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔗 Downloading: $DOWNLOAD_URL"
|
||||
|
||||
# === Download binary ===
|
||||
FILENAME="${TMP_DIR}/cursor_download"
|
||||
curl -fsSL "$DOWNLOAD_URL" -o "$FILENAME"
|
||||
|
||||
# === Install ===
|
||||
if [ "$OS" == "macos" ]; then
|
||||
echo "💿 Mounting DMG..."
|
||||
MOUNT_POINT="/Volumes/CursorInstaller"
|
||||
hdiutil attach "$FILENAME" -mountpoint "$MOUNT_POINT" -nobrowse -quiet
|
||||
APP_PATH=$(find "$MOUNT_POINT" -name "*.app" | head -n 1)
|
||||
|
||||
echo "🔍 Verifying app signature..."
|
||||
codesign --verify --deep --strict --verbose=2 "$APP_PATH"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Signature verification failed. Aborting install."
|
||||
hdiutil detach "$MOUNT_POINT" -quiet
|
||||
exit 1
|
||||
else
|
||||
echo "✅ App is properly signed and verified."
|
||||
fi
|
||||
|
||||
echo "🛡️ Checking notarization status with spctl..."
|
||||
spctl --assess --type execute --verbose=4 "$APP_PATH"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "⚠️ Warning: App failed notarization check (spctl). It may still run, but could be blocked by Gatekeeper."
|
||||
else
|
||||
echo "✅ App is notarized and passes Gatekeeper checks."
|
||||
fi
|
||||
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "❌ .app not found"
|
||||
hdiutil detach "$MOUNT_POINT" -quiet
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔐 Requesting admin rights to install to /Applications..."
|
||||
echo "🧼 Cleaning up existing installation (if any)..."
|
||||
sudo rm -rf "/Applications/$(basename "$APP_PATH")"
|
||||
echo "📦 Installing with ditto..."
|
||||
sudo ditto "$APP_PATH" "/Applications/$(basename "$APP_PATH")"
|
||||
|
||||
if [ -d "/Applications/$(basename "$APP_PATH")" ]; then
|
||||
echo "✅ Installed Cursor $VERSION to /Applications"
|
||||
else
|
||||
hdiutil detach "$MOUNT_POINT" -quiet
|
||||
echo "❌ Something went wrong — installation incomplete."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
hdiutil detach "$MOUNT_POINT" -quiet
|
||||
echo "✅ Installed Cursor $VERSION to /Applications"
|
||||
elif [ "$OS" == "linux" ]; then
|
||||
mkdir -p "$HOME/Applications"
|
||||
FINAL_PATH="$HOME/Applications/Cursor-${VERSION}.AppImage"
|
||||
mv "$FILENAME" "$FINAL_PATH"
|
||||
chmod +x "$FINAL_PATH"
|
||||
echo "✅ Saved AppImage to $FINAL_PATH"
|
||||
elif [ "$OS" == "windows" ]; then
|
||||
FINAL_PATH="$HOME/Downloads/$(basename "$DOWNLOAD_URL")"
|
||||
mv "$FILENAME" "$FINAL_PATH"
|
||||
echo "📥 Saved installer to $FINAL_PATH"
|
||||
echo "💡 Please run it manually."
|
||||
else
|
||||
echo "❌ Unknown platform"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# === Cleanup ===
|
||||
rm -rf "$TMP_DIR"
|
||||
echo "🎉 Done!"
|
||||
Reference in New Issue
Block a user