Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,25 @@ For chat and prompt to code features:

### Install

You can install it via [Homebrew](http://brew.sh/):
**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)
```
Comment on lines +92 to +96
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.

Or, if you have already cloned the repository:

```bash
bash install.sh
```

Alternatively, you can install it via [Homebrew](http://brew.sh/) directly:

```bash
brew install --cask copilot-for-xcode
```

Or install it manually, by downloading the `Copilot for Xcode.app` from the latest [release](https://github.com/intitni/CopilotForXcode/releases).
Or install it manually by downloading the `Copilot for Xcode.app` from the latest [release](https://github.com/intitni/CopilotForXcode/releases).

Please make sure the app is inside the Applications folder.

Expand Down
160 changes: 160 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/usr/bin/env bash
# install.sh — Install Copilot for Xcode on macOS
#
# Usage:
# bash install.sh
#
# The script will:
# 1. Verify prerequisites (macOS 12+, Xcode installed)
# 2. Install the app via Homebrew cask when available, or download the
# latest release from GitHub otherwise
# 3. Launch the app once so it registers its background launch agent
# 4. Print step-by-step instructions for the manual post-install tasks
# (enabling the Source Editor Extension and granting Accessibility access)

set -euo pipefail

# ── color helpers ─────────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
RESET='\033[0m'

info() { echo -e "${CYAN}[info]${RESET} $*"; }
success() { echo -e "${GREEN}[ok]${RESET} $*"; }
warn() { echo -e "${YELLOW}[warn]${RESET} $*"; }
error() { echo -e "${RED}[error]${RESET} $*" >&2; }
step() { echo -e "\n${BOLD}$*${RESET}"; }

# ── constants ─────────────────────────────────────────────────────────────────
APP_NAME="Copilot for Xcode"
APP_BUNDLE="Copilot for Xcode.app"
APP_PATH="/Applications/${APP_BUNDLE}"
BREW_CASK="copilot-for-xcode"
GITHUB_RELEASES="https://api.github.com/repos/intitni/CopilotForXcode/releases/latest"
MIN_MACOS_MAJOR=12 # macOS Monterey

# ── prerequisite checks ───────────────────────────────────────────────────────
step "1/4 Checking prerequisites"

# macOS version
os_version=$(sw_vers -productVersion 2>/dev/null || echo "0.0")
os_major=$(echo "$os_version" | cut -d. -f1)
if [[ "$os_major" -lt "$MIN_MACOS_MAJOR" ]]; then
error "${APP_NAME} requires macOS Monterey (12) or later."
error "Current version: ${os_version}"
exit 1
fi
success "macOS ${os_version} — compatible"

# 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)"

Comment on lines +52 to +59
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
# 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"

Copilot uses AI. Check for mistakes.
# ── installation ──────────────────────────────────────────────────────────────
step "2/4 Installing ${APP_NAME}"

if [[ -d "$APP_PATH" ]]; then
success "${APP_NAME} is already installed at ${APP_PATH}"
elif command -v brew &>/dev/null; then
info "Homebrew detected — installing via cask …"
brew install --cask "$BREW_CASK"
success "Installed via Homebrew"
else
warn "Homebrew not found — falling back to manual download."

# Fetch the download URL of the latest release asset
info "Fetching latest release information from GitHub …"
asset_url=$(
curl -fsSL "$GITHUB_RELEASES" \
| grep '"browser_download_url"' \
| grep '\.zip"' \
| head -1 \
| sed 's/.*"browser_download_url": "\(.*\)"/\1/'
Comment on lines +74 to +79
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
)

if [[ -z "$asset_url" ]]; then
error "Could not determine the download URL from GitHub."
error "Please download ${APP_NAME} manually from:"
error " https://github.com/intitni/CopilotForXcode/releases"
exit 1
fi

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"
Comment on lines +89 to +96
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.

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
Comment on lines +98 to +103
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.

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"
Comment on lines +105 to +109
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.

success "Installed to ${APP_PATH}"
fi

# ── launch the app once ───────────────────────────────────────────────────────
step "3/4 Launching ${APP_NAME}"

info "Opening ${APP_NAME} to register its background service …"
open -a "$APP_PATH"

# Give the app a moment to start before we print the next instructions
sleep 3
success "${APP_NAME} has been opened"

# ── post-install instructions ─────────────────────────────────────────────────
step "4/4 Post-install steps (manual)"

os_minor=$(echo "$os_version" | cut -d. -f2)

Comment on lines +127 to +128
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os_minor is computed but never used. Please remove it (or use it) to avoid dead code / confusion.

Suggested change
os_minor=$(echo "$os_version" | cut -d. -f2)

Copilot uses AI. Check for mistakes.
echo ""
echo -e "${BOLD}A) Enable the Source Editor Extension${RESET}"
if [[ "$os_major" -ge 15 ]]; then
echo " Open: System Settings → General → Login Items & Extensions"
echo " Click 'Xcode Source Editor' and tick 'Copilot for Xcode'."
elif [[ "$os_major" -eq 14 ]]; then
echo " Open: System Settings → Privacy & Security → Extensions"
echo " Click 'Xcode Source Editor' and tick 'Copilot'."
else
echo " Open: System Preferences → Extensions"
echo " Tick 'Copilot' under 'Xcode Source Editor'."
fi

echo ""
echo -e "${BOLD}B) Grant Accessibility permission${RESET}"
echo " Open: System Settings → Privacy & Security → Accessibility"
echo " Add 'CopilotForXcodeExtensionService.app' to the list."
echo " (Click 'Reveal Extension App in Finder' inside ${APP_NAME} to locate it.)"

echo ""
echo -e "${BOLD}C) Set up your AI provider${RESET}"
echo " • GitHub Copilot: navigate to 'Service → GitHub Copilot' in the host app,"
echo " click 'Install' then 'Sign In'."
echo " • Codeium: navigate to 'Service → Codeium', click 'Install' then 'Sign In'."
echo " • OpenAI / other chat models: navigate to 'Service → Chat Model'."

echo ""
echo -e "${BOLD}D) (Optional) Set up key bindings in Xcode${RESET}"
echo " Xcode → Settings → Key Bindings → search for 'copilot'"

echo ""
success "Installation complete! Enjoy ${APP_NAME} 🎉"