feat(devops): add interactive WSL CLI installer script

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Saravanakumar D 2026-05-29 16:04:17 -07:00
parent af1bc6904e
commit 58773ac108

274
install_clis_wsl.sh Executable file
View File

@ -0,0 +1,274 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
LOG="$HOME/cli-install-wsl.log"
REPORT="$HOME/cli-install-report.md"
BACKUP_DIR="$HOME/cli-install-backups-wsl-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
exec > >(tee -a "$LOG") 2>&1
echo "=== CLI install script (interactive) ==="
echo "Log: $LOG"
echo
# Helpers
prompt_yesno() {
local msg="$1"
local ans
while true; do
read -rp "$msg [y/n]: " ans
case "$ans" in
[Yy]*) return 0 ;;
[Nn]*) return 1 ;;
*) echo "Please answer y or n." ;;
esac
done
}
preview_url() {
local url="$1"
echo
echo "Previewing first 200 lines of $url"
echo "---- BEGIN PREVIEW ----"
curl -fsSL "$url" 2>/dev/null | sed -n '1,200p'
echo "---- END PREVIEW ----"
echo
}
safe_run_pipe_installer() {
# $1 = url, $2 = shell (bash|sh)
local url="$1"; local shellcmd="${2:-bash}"
echo "About to run installer from: $url"
if ! prompt_yesno "Have you reviewed the preview and want to execute it now?"; then
echo "Skipping $url"
return 1
fi
# Execute installer (interactive; sudo prompts will show)
curl -fsSL "$url" | $shellcmd
}
# 0) WSL check
if grep -qi microsoft /proc/version 2>/dev/null || grep -qi microsoft /proc/sys/kernel/osrelease 2>/dev/null; then
echo "Running inside WSL (or WSL2). Proceeding."
else
echo "Warning: This script is intended for WSL/Ubuntu. Continue only if you know what you are doing."
if ! prompt_yesno "Continue anyway?"; then
echo "Aborting."
exit 1
fi
fi
# 1) Detect environment
echo "== Environment =="
uname -a
if command -v lsb_release >/dev/null 2>&1; then lsb_release -a || true; else cat /etc/os-release || true; fi
echo "Shell: $SHELL"
echo "User: $USER"
echo "Home: $HOME"
echo "PATH: $PATH"
echo "Arch: $(uname -m)"
echo
# 2) Back up shell configs
echo "Backing up shell configs to $BACKUP_DIR"
for f in "$HOME/.bashrc" "$HOME/.profile" "$HOME/.zshrc"; do
if [ -f "$f" ]; then
cp -a "$f" "$BACKUP_DIR/$(basename "$f").bak" || true
echo "Backed up $f"
else
echo "No file: $f"
fi
done
echo
# 3) Install prerequisites
if prompt_yesno "Install apt prerequisites (curl ca-certificates git unzip gnupg lsb-release build-essential)?"; then
sudo apt-get update
sudo apt-get install -y curl ca-certificates git unzip gnupg lsb-release build-essential apt-transport-https
else
echo "Skipping prerequisites install. Ensure required tools exist."
fi
echo
# 4) Node check and optional install (Node 20 recommended)
NEED_NODE_INSTALL=0
if command -v node >/dev/null 2>&1; then
NV="$(node -v 2>/dev/null || true)"
echo "Found node: $NV"
MAJ="$(echo "$NV" | sed -E 's/v([0-9]+).*/\1/')" || MAJ=0
if [ -z "$MAJ" ] || [ "$MAJ" -lt 18 ]; then
NEED_NODE_INSTALL=1
echo "Node major version $MAJ is older than 18; Node 20 is recommended."
fi
else
NEED_NODE_INSTALL=1
echo "Node not found."
fi
if [ "$NEED_NODE_INSTALL" -eq 1 ]; then
if prompt_yesno "Install Node 20 via NodeSource (recommended) now?"; then
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
else
echo "Skipping Node install. Codex npm installer may require Node >=18."
fi
fi
echo "Node version: $(node -v 2>/dev/null || echo 'none')"
echo "npm version: $(npm -v 2>/dev/null || echo 'none')"
echo
# 5) Ensure npm global prefix writable (user-level)
CUR_PREFIX="$(npm config get prefix 2>/dev/null || echo '')"
echo "Current npm prefix: $CUR_PREFIX"
if [ -z "$CUR_PREFIX" ] || [ ! -w "$CUR_PREFIX" ] || [ "$CUR_PREFIX" = "/usr" ]; then
echo "Configuring user npm global prefix at ~/.npm-global"
mkdir -p "$HOME/.npm-global"
npm config set prefix "$HOME/.npm-global"
if ! grep -q '\.npm-global' "$HOME/.profile" 2>/dev/null; then
printf '\n# npm global bin\nexport PATH="$HOME/.npm-global/bin:$HOME/.local/bin:$PATH"\n' >> "$HOME/.profile"
echo "Appended npm PATH to ~/.profile"
fi
export PATH="$HOME/.npm-global/bin:$HOME/.local/bin:$PATH"
fi
echo "Effective PATH now contains: $HOME/.npm-global/bin (if present)"
echo
# 6) Claude Code CLI (official)
CLAUDE_URL="https://claude.ai/install.sh"
echo "Claude Code installer (official): $CLAUDE_URL"
preview_url "$CLAUDE_URL"
if prompt_yesno "Install Claude Code CLI now?"; then
safe_run_pipe_installer "$CLAUDE_URL" bash || echo "Claude installer failed or was skipped."
else
echo "Skipped Claude install."
fi
echo
# 7) OpenAI Codex CLI (official)
echo "OpenAI Codex CLI preferred method: npm i -g @openai/codex"
if prompt_yesno "Attempt npm global install @openai/codex now?"; then
if npm i -g @openai/codex --no-progress; then
echo "Codex npm install succeeded."
else
echo "npm global install failed. You can choose to run the official installer fallback."
if prompt_yesno "Attempt official fallback installer (curl https://chatgpt.com/codex/install.sh | sh)?"; then
preview_url "https://chatgpt.com/codex/install.sh"
safe_run_pipe_installer "https://chatgpt.com/codex/install.sh" sh || echo "Codex fallback failed or skipped."
fi
fi
else
echo "Skipped Codex npm install."
fi
echo
# 8) Devin CLI (official)
DEVIN_URL="https://cli.devin.ai/install.sh"
echo "Devin CLI official installer: $DEVIN_URL"
preview_url "$DEVIN_URL"
if prompt_yesno "Install Devin CLI now?"; then
safe_run_pipe_installer "$DEVIN_URL" bash || echo "Devin installer failed or was skipped."
else
echo "Skipped Devin install."
fi
echo
# 9) Antigravity (agy) — manual only
ANTIGRAVITY_PAGE="https://antigravity.google/product/antigravity-cli"
echo "Antigravity CLI official docs page: $ANTIGRAVITY_PAGE"
echo "This script will not auto-run installers from Antigravity. Review the official page and follow their instructions."
if prompt_yesno "Fetch and preview the Antigravity docs page snippet?"; then
echo "Previewing page snippet (first 300 lines):"
curl -fsSL "$ANTIGRAVITY_PAGE" | sed -n '1,300p' || echo "Failed to fetch Antigravity page."
echo
echo "If the page specifies an official installer URL you trust, run it manually (example placeholder):"
echo " curl -fsSL <official-agy-install-url> | bash"
fi
echo
# 10) Reload profile and PATH
echo "Reloading ~/.profile (if present) to pick PATH changes"
if [ -f "$HOME/.profile" ]; then
# shellcheck disable=SC1090
source "$HOME/.profile" || true
fi
export PATH="$HOME/.npm-global/bin:$HOME/.local/bin:$PATH"
echo "PATH now: $PATH"
echo
# 11) Verification
echo "=== Verification ==="
declare -A RESULTS
for cmd in claude codex agy devin; do
echo "---- $cmd ----"
if command -v "$cmd" >/dev/null 2>&1; then
p="$(command -v "$cmd")"
out="$($cmd --version 2>&1 || $cmd --help 2>&1 || echo 'no-version-output')"
echo "Found: $p"
echo "Output: $out"
RESULTS["$cmd"]="installed|$out|$p"
else
echo "Not found in PATH."
RESULTS["$cmd"]="not-installed||"
fi
echo
done
# Also verify in a clean non-login shell
echo "=== Clean shell checks ==="
bash -lc 'command -v claude && claude --version 2>&1 || echo "claude: not-found"'
bash -lc 'command -v codex && codex --version 2>&1 || echo "codex: not-found"'
bash -lc 'command -v devin && (devin --version 2>&1 || devin --help 2>&1) || echo "devin: not-found"'
bash -lc 'command -v agy && agy --version 2>&1 || echo "agy: not-found"'
# 12) Create report
echo "Writing report to $REPORT"
cat > "$REPORT" <<EOF
# CLI install report (WSL)
Generated: $(date)
OS: $(lsb_release -d -s 2>/dev/null || grep PRETTY_NAME /etc/os-release | cut -d= -f2-)
User: $USER
Home: $HOME
Install summary:
EOF
for key in claude codex devin agy; do
val="${RESULTS[$key]:-not-installed||}"
IFS='|' read -r inst ver path <<< "$val"
if [ "$inst" = "installed" ] || [ "$inst" = "installed_npm" ] || [ "$inst" = "installed_fallback" ]; then
status="yes"
elif [ "$inst" = "not-installed" ]; then
status="no"
else
status="$inst"
fi
{
echo
echo "## $key"
echo "Installed?: $status"
echo "Path: ${path:-}"
echo "Version/Output: ${ver:-}"
} >> "$REPORT"
done
cat >> "$REPORT" <<EOF
Antigravity (agy): Manual verification required. Official page: $ANTIGRAVITY_PAGE
PATH changes:
- If npm prefix was adjusted, ~/.npm-global/bin was added to ~/.profile
Notes:
- No auth performed by this script. Use each CLI's documented login command (do not put API keys in shell profiles).
- Backups saved to: $BACKUP_DIR
Log file: $LOG
EOF
echo
echo "DONE. Report: $REPORT"
echo "Tail of log:"
tail -n 50 "$LOG" || true
echo
echo "If any install failed, paste the log or report and I will help debug."
# End of script