#!/usr/bin/env bash # Coder workspace first-run CLI setup wizard. # # Meant to be `source`d from a new interactive shell (e.g. via .bashrc). It asks, # once per user per workspace, whether to install and log into a few optional # AI coding CLIs. It re-runs on every new terminal until the user lets it finish # (or explicitly skips it for good), then gets out of the way. # # VS Code / code-server extensions are intentionally NOT asked about here - # they're installed declaratively by the Coder template itself (the # `code-server` module's `extensions` input, populated from the matching # profile-templates/*.code-profile file at template-push time). # # Manual re-run: bash /opt/coder/cli-setup-wizard.sh --force set -u WIZARD_DONE_FILE="${HOME}/.cache/coder-cli-wizard/done" FORCE=0 [ "${1:-}" = "--force" ] && FORCE=1 export BUN_INSTALL="${HOME}/.bun" export PATH="${BUN_INSTALL}/bin:${HOME}/.local/bin:${PATH}" # Only bother interactive shells with a real terminal attached, and only until # the user marks the wizard as done. if [ "$FORCE" -ne 1 ]; then case "$-" in *i*) : ;; *) return 0 2>/dev/null || exit 0 ;; esac [ -t 0 ] || { return 0 2>/dev/null || exit 0; } [ -f "$WIZARD_DONE_FILE" ] && { return 0 2>/dev/null || exit 0; } fi mkdir -p "$(dirname "$WIZARD_DONE_FILE")" ask_yes_no() { local prompt="$1" reply read -r -p "$prompt [y/N] " reply case "$reply" in [Yy]*) return 0 ;; *) return 1 ;; esac } echo "" echo "===================================================================" echo " Coder workspace setup wizard" echo " Runs once per new terminal until you finish it. Ctrl+C any time" echo " to skip for now - it'll ask again next terminal." echo "===================================================================" # --- GitHub Copilot CLI --- if command -v copilot >/dev/null 2>&1; then echo "GitHub Copilot CLI already installed, skipping." elif command -v bun >/dev/null 2>&1; then if ask_yes_no "Install GitHub Copilot CLI and log in?"; then if bun install -g @github/copilot; then copilot login || echo "Install succeeded but login didn't complete. Retry any time with: copilot login" else echo "Copilot CLI install failed. Retry later with: bun install -g @github/copilot && copilot login" fi fi else echo "Skipping GitHub Copilot CLI: bun not found on this workspace image." fi # --- Google Antigravity CLI (agy) --- if command -v agy >/dev/null 2>&1; then echo "Antigravity CLI already installed, skipping." else if ask_yes_no "Install Google Antigravity CLI (agy) and log in?"; then if curl -fsSL https://antigravity.google/cli/install.sh | bash; then echo "Launching 'agy' once to complete sign-in (exit with /logout or Ctrl+D when done)..." agy || echo "Sign-in didn't complete. Retry any time by running: agy" else echo "Antigravity CLI install failed. Retry later with: curl -fsSL https://antigravity.google/cli/install.sh | bash" fi fi fi # --- Claude Code CLI --- if command -v claude >/dev/null 2>&1; then echo "Claude Code CLI already installed, skipping." elif command -v bun >/dev/null 2>&1; then if ask_yes_no "Install Claude Code CLI and log in?"; then if bun install -g @anthropic-ai/claude-code; then echo "Launching 'claude' once to complete sign-in (use /login if not prompted; Ctrl+C to exit when done)..." claude || echo "Sign-in didn't complete. Retry any time by running: claude" else echo "Claude Code CLI install failed. Retry later with: bun install -g @anthropic-ai/claude-code" fi fi else echo "Skipping Claude Code CLI: bun not found on this workspace image." fi # --- GitHub CLI (gh) --- if command -v gh >/dev/null 2>&1; then echo "GitHub CLI already installed, skipping." else if ask_yes_no "Install GitHub CLI (gh) and log in?"; then if (sudo mkdir -p -m 755 /etc/apt/keyrings \ && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null \ && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null \ && sudo apt-get update -qq && sudo apt-get install -y gh); then gh auth login || echo "Install succeeded but login didn't complete. Retry any time with: gh auth login" else echo "GitHub CLI install failed. Retry later with: gh auth login (once gh is installed)" fi fi fi # --- Gitea CLI (tea) --- if command -v tea >/dev/null 2>&1; then echo "Gitea CLI already installed, skipping." else if ask_yes_no "Install Gitea CLI (tea) and log in?"; then TEA_ARCH="$(uname -m)" case "$TEA_ARCH" in x86_64) TEA_ARCH="amd64" ;; aarch64) TEA_ARCH="arm64" ;; esac TEA_VERSION="$(curl -fsSL https://gitea.com/api/v1/repos/gitea/tea/releases/latest | grep -o '"tag_name":[^,]*' | grep -o 'v[0-9][^"]*')" mkdir -p "$HOME/.local/bin" if [ -n "$TEA_VERSION" ] \ && curl -fsSL "https://gitea.com/gitea/tea/releases/download/${TEA_VERSION}/tea-${TEA_VERSION#v}-linux-${TEA_ARCH}" -o "$HOME/.local/bin/tea" \ && chmod +x "$HOME/.local/bin/tea"; then echo "Add this Gitea instance now (e.g. https://git.octoturge.com)..." tea login add || echo "Login didn't complete. Retry any time with: tea login add" else echo "Gitea CLI install failed. Retry later from: https://gitea.com/gitea/tea/releases" rm -f "$HOME/.local/bin/tea" fi fi fi echo "" if ask_yes_no "Mark setup wizard as complete so it stops asking on new terminals?"; then touch "$WIZARD_DONE_FILE" echo "Done. Re-run any time with: bash /opt/coder/cli-setup-wizard.sh --force" else echo "OK, this'll ask again next time you open a terminal." fi return 0 2>/dev/null || exit 0