Add install.sh: automated macOS installer for Copilot for Xcode#2
Add install.sh: automated macOS installer for Copilot for Xcode#2
Conversation
Co-authored-by: luisespersonal-byte <249453885+luisespersonal-byte@users.noreply.github.com>
Co-authored-by: luisespersonal-byte <249453885+luisespersonal-byte@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a streamlined CLI installation path for Copilot for Xcode by introducing a macOS installer script and updating the README to promote it alongside existing Homebrew/manual options.
Changes:
- Added
install.shto automate prerequisite checks, installation (Homebrew cask or GitHub Releases fallback), first launch, and post-install guidance. - Updated
README.mdinstall section to lead with a curl-based one-liner and include a “run from clone” variant.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| install.sh | New automated installer script with Homebrew-first install and GitHub Releases fallback plus post-install instructions. |
| README.md | Promotes the one-line installer and retains existing Homebrew/manual install paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Xcode installed (look for the app bundle or xcode-select path) | ||
| if ! xcode-select -p &>/dev/null || [[ ! -d "$(xcode-select -p)" ]]; then | ||
| error "Xcode does not appear to be installed." | ||
| error "Install Xcode from the Mac App Store, then re-run this script." | ||
| exit 1 | ||
| fi | ||
| success "Xcode found at $(xcode-select -p)" | ||
|
|
There was a problem hiding this comment.
The Xcode check currently accepts Command Line Tools-only setups because xcode-select -p can point to /Library/Developer/CommandLineTools. Since the product is an Xcode Source Editor extension, it likely needs the full Xcode.app. Consider verifying that xcode-select -p resolves under an actual Xcode.app/Contents/Developer (or that /Applications/Xcode.app exists) and emitting a clearer error if only CLT is installed.
| # Xcode installed (look for the app bundle or xcode-select path) | |
| if ! xcode-select -p &>/dev/null || [[ ! -d "$(xcode-select -p)" ]]; then | |
| error "Xcode does not appear to be installed." | |
| error "Install Xcode from the Mac App Store, then re-run this script." | |
| exit 1 | |
| fi | |
| success "Xcode found at $(xcode-select -p)" | |
| # Xcode installed (require full Xcode, not just Command Line Tools) | |
| xcode_path="$(xcode-select -p 2>/dev/null || true)" | |
| if [[ -z "$xcode_path" || ! -d "$xcode_path" ]]; then | |
| error "Xcode does not appear to be installed." | |
| error "Install Xcode from the Mac App Store, then re-run this script." | |
| exit 1 | |
| fi | |
| # Detect Command Line Tools-only setup and prefer the full Xcode.app if present | |
| if [[ "$xcode_path" == /Library/Developer/CommandLineTools* ]]; then | |
| if [[ -d "/Applications/Xcode.app/Contents/Developer" ]]; then | |
| xcode_path="/Applications/Xcode.app/Contents/Developer" | |
| else | |
| error "Only Xcode Command Line Tools were detected at: $xcode_path" | |
| error "${APP_NAME} requires the full Xcode.app (including Source Editor Extensions)." | |
| error "Install Xcode from the Mac App Store, then re-run this script." | |
| exit 1 | |
| fi | |
| fi | |
| success "Xcode found at $xcode_path" |
| asset_url=$( | ||
| curl -fsSL "$GITHUB_RELEASES" \ | ||
| | grep '"browser_download_url"' \ | ||
| | grep '\.zip"' \ | ||
| | head -1 \ | ||
| | sed 's/.*"browser_download_url": "\(.*\)"/\1/' |
There was a problem hiding this comment.
The GitHub Releases lookup runs inside a command substitution with set -e + pipefail, so if the API call fails (rate limit/network, 403/404), the script will exit immediately without printing the friendly fallback errors below. Consider capturing the curl output/exit code explicitly (or retrying / surfacing the HTTP error) so users get a clear message and manual-download link instead of a silent abort.
| asset_url=$( | |
| curl -fsSL "$GITHUB_RELEASES" \ | |
| | grep '"browser_download_url"' \ | |
| | grep '\.zip"' \ | |
| | head -1 \ | |
| | sed 's/.*"browser_download_url": "\(.*\)"/\1/' | |
| # Fetch release JSON from GitHub, handling HTTP/network errors explicitly | |
| if ! release_json=$(curl -fsSL "$GITHUB_RELEASES"); then | |
| error "Failed to contact GitHub Releases API." | |
| error "Please download ${APP_NAME} manually from:" | |
| error " https://github.com/intitni/CopilotForXcode/releases" | |
| exit 1 | |
| fi | |
| # Extract the first .zip asset URL from the release JSON | |
| asset_url=$( | |
| printf '%s\n' "$release_json" \ | |
| | grep '"browser_download_url"' \ | |
| | grep '\.zip"' \ | |
| | head -1 \ | |
| | sed 's/.*"browser_download_url": "\(.*\)"/\1/' \ | |
| || true |
| extracted_app=$(find "$tmp_dir" -maxdepth 3 -name "*.app" | head -1) | ||
| if [[ -z "$extracted_app" ]]; then | ||
| error "Could not find the .app bundle inside the downloaded archive." | ||
| rm -rf "$tmp_dir" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
find ... -name "*.app" | head -1 can select the wrong bundle if the extracted archive contains multiple .apps (e.g., helper apps inside the main app bundle). Prefer selecting the expected bundle name (e.g., ${APP_BUNDLE}) and/or limiting the search depth so you always install the host app.
| info "Moving ${APP_BUNDLE} to /Applications …" | ||
| # Remove a stale copy if present (handles re-install after failed attempt) | ||
| [[ -d "$APP_PATH" ]] && rm -rf "$APP_PATH" | ||
| cp -R "$extracted_app" "$APP_PATH" | ||
| rm -rf "$tmp_dir" |
There was a problem hiding this comment.
Copying/removing under /Applications often requires admin privileges. As written, rm -rf / cp -R will fail with a permission error for many users (and set -e will exit without guidance). Consider detecting writability of /Applications (or $APP_PATH) and using sudo when needed, with a clear prompt/message.
| tmp_dir=$(mktemp -d) | ||
| zip_path="${tmp_dir}/CopilotForXcode.zip" | ||
|
|
||
| info "Downloading ${APP_NAME} …" | ||
| curl -fL --progress-bar "$asset_url" -o "$zip_path" | ||
|
|
||
| info "Extracting …" | ||
| unzip -q "$zip_path" -d "$tmp_dir" |
There was a problem hiding this comment.
The temp directory is only cleaned up on the success path and a couple of specific error branches. If curl, unzip, or the copy step fails, tmp_dir will be left behind. Consider using a trap to ensure cleanup on any exit (success or failure).
| os_minor=$(echo "$os_version" | cut -d. -f2) | ||
|
|
There was a problem hiding this comment.
os_minor is computed but never used. Please remove it (or use it) to avoid dead code / confusion.
| os_minor=$(echo "$os_version" | cut -d. -f2) |
| **One-line installer** — runs the bundled `install.sh` script which handles the download, moves the app to `/Applications`, and prints the remaining manual steps: | ||
|
|
||
| ```bash | ||
| bash <(curl -fsSL https://raw.githubusercontent.com/intitni/CopilotForXcode/main/install.sh) | ||
| ``` |
There was a problem hiding this comment.
The one-liner installs by executing install.sh fetched from the main branch via raw.githubusercontent.com, not a locally "bundled" script. Consider rewording to avoid implying it runs a script shipped with a downloaded release/clone, and (optionally) note that it always pulls the latest script from main rather than a pinned release for reproducibility.
No streamlined CLI install path exists — users must know the Homebrew cask name or navigate GitHub releases manually.
install.sh(new)xcode-selectbrew install --cask copilot-for-xcodewhen Homebrew is available; falls back to GitHub Releases API → ZIP download → extract → copy to/Applicationsbash <(curl -fsSL https://raw.githubusercontent.com/intitni/CopilotForXcode/main/install.sh)README.md💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.