# Install Script Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Ship a `curl | sh` one-liner that installs the latest fafb-q binary on Linux.

**Architecture:** A single POSIX sh script (`scripts/install.sh`) that detects platform, downloads the correct tarball from Bitbucket Downloads, extracts and installs to `/usr/local/bin`. The pipeline uploads this script alongside release tarballs. README is updated to lead with the one-liner.

**Tech Stack:** POSIX sh, curl, tar, Bitbucket Downloads, Bitbucket Pipelines

**Spec:** `docs/superpowers/specs/2026-03-29-install-script-design.md`

---

## File Structure

| File | Action | Responsibility |
|------|--------|----------------|
| `scripts/install.sh` | Create | The install script itself |
| `bitbucket-pipelines.yml` | Modify (lines 57-77) | Upload `install.sh` to Bitbucket Downloads in `&upload-downloads` step |
| `README.md` | Modify (lines 10-28) | Lead with one-liner, keep manual steps as fallback |

---

### Task 1: Write the install script

**Files:**
- Create: `scripts/install.sh`

- [ ] **Step 1: Create `scripts/install.sh`**

```sh
#!/bin/sh
set -eu

BINARY_NAME="fafb-q"
INSTALL_DIR="/usr/local/bin"
BASE_URL="https://bitbucket.org/thermsio/fafb-q/downloads"

main() {
    # Check for curl
    if ! command -v curl >/dev/null 2>&1; then
        echo "Error: curl is required but not found"
        exit 1
    fi

    # Detect OS
    os="$(uname -s)"
    if [ "$os" != "Linux" ]; then
        echo "Error: unsupported OS: $os"
        echo "On macOS, install via: cargo install fafb-q"
        exit 1
    fi

    # Detect architecture
    arch="$(uname -m)"
    case "$arch" in
        x86_64)  target="x86_64-unknown-linux-musl" ;;
        aarch64|arm64) target="aarch64-unknown-linux-musl" ;;
        *)
            echo "Error: unsupported architecture: $arch"
            exit 1
            ;;
    esac

    echo "Detected: Linux $arch"

    # Create temp directory with cleanup trap
    tmpdir="$(mktemp -d)"
    trap 'rm -rf "$tmpdir"' EXIT

    # Download
    tarball="fafb-q-latest-${target}.tar.gz"
    echo "Downloading fafb-q for ${target}..."
    curl -fsSL "${BASE_URL}/${tarball}" -o "${tmpdir}/${tarball}"

    # Extract
    tar xzf "${tmpdir}/${tarball}" --strip-components=1 -C "$tmpdir"

    # Verify binary exists and is executable
    if [ ! -x "${tmpdir}/${BINARY_NAME}" ]; then
        echo "Error: binary not found or not executable after extraction"
        exit 1
    fi

    # Determine if we need sudo
    needs_sudo=""
    if [ "$(id -u)" -ne 0 ]; then
        if ! command -v sudo >/dev/null 2>&1; then
            echo "Error: permission denied. Run as root or install sudo."
            exit 1
        fi
        needs_sudo="sudo"
    fi

    # Install
    echo "Installing to ${INSTALL_DIR}/${BINARY_NAME}..."
    # shellcheck disable=SC2086
    $needs_sudo mkdir -p "$INSTALL_DIR"
    # shellcheck disable=SC2086
    $needs_sudo install -m 755 "${tmpdir}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}"

    # Smoke test
    "${INSTALL_DIR}/${BINARY_NAME}" --version

    echo "Install complete."
}

main
```

- [ ] **Step 2: Make the script executable**

Run: `chmod +x scripts/install.sh`

- [ ] **Step 3: Verify with shellcheck (if available)**

Run: `shellcheck scripts/install.sh || echo "shellcheck not installed, skipping"`
Expected: no errors (or shellcheck not installed)

- [ ] **Step 4: Commit**

```bash
git add scripts/install.sh
git commit -m "feat: add install.sh convenience script for one-liner installs"
```

---

### Task 2: Add install.sh upload to pipeline

**Files:**
- Modify: `bitbucket-pipelines.yml:57-77` (the `&upload-downloads` step)

- [ ] **Step 1: Add install.sh upload after the tarball upload loop**

In the `&upload-downloads` step, after the `for artifact ... done` loop (line 77), add:

```yaml
          # Upload the install script (stable URL, always overwritten)
          - |
            echo "Uploading install.sh..."
            curl -X POST "$UPLOAD_URL" \
              --user "$ATLASSIAN_ACCOUNT_EMAIL:$ATLASSIAN_API_TOKEN" \
              --form files=@"scripts/install.sh" \
              --fail --show-error
```

The full `&upload-downloads` step script section becomes:

```yaml
    - step: &upload-downloads
        name: Upload to Bitbucket Downloads
        script:
          - UPLOAD_URL="https://api.bitbucket.org/2.0/repositories/$BITBUCKET_REPO_OWNER/$BITBUCKET_REPO_SLUG/downloads"
          - |
            for artifact in target/release-artifacts/*.tar.gz; do
              echo "Uploading $(basename "$artifact")..."
              curl -X POST "$UPLOAD_URL" \
                --user "$ATLASSIAN_ACCOUNT_EMAIL:$ATLASSIAN_API_TOKEN" \
                --form files=@"$artifact" \
                --fail --show-error

              # Upload a "latest" copy so README URLs never go stale
              latest_name=$(basename "$artifact" | sed 's/fafb-q-v[0-9.]*-/fafb-q-latest-/; s/fafb-q-dev-[a-f0-9]*-/fafb-q-latest-/')
              cp "$artifact" "target/release-artifacts/$latest_name"
              echo "Uploading $latest_name..."
              curl -X POST "$UPLOAD_URL" \
                --user "$ATLASSIAN_ACCOUNT_EMAIL:$ATLASSIAN_API_TOKEN" \
                --form files=@"target/release-artifacts/$latest_name" \
                --fail --show-error
            done
          # Upload the install script (stable URL, always overwritten)
          - |
            echo "Uploading install.sh..."
            curl -X POST "$UPLOAD_URL" \
              --user "$ATLASSIAN_ACCOUNT_EMAIL:$ATLASSIAN_API_TOKEN" \
              --form files=@"scripts/install.sh" \
              --fail --show-error
```

- [ ] **Step 2: Commit**

```bash
git add bitbucket-pipelines.yml
git commit -m "ci: upload install.sh to Bitbucket Downloads in release pipeline"
```

---

### Task 3: Update README

**Files:**
- Modify: `README.md:10-28` (Installation section)

- [ ] **Step 1: Replace the pre-built binaries section**

Replace lines 12-28 of `README.md` with:

```markdown
### Pre-built binaries (recommended)

Statically linked binaries with no runtime dependencies:

```bash
curl -fsSL https://bitbucket.org/thermsio/fafb-q/downloads/install.sh | sh
```

Or manually:

```bash
# Linux x86_64
curl -LO https://bitbucket.org/thermsio/fafb-q/downloads/fafb-q-latest-x86_64-unknown-linux-musl.tar.gz
tar xzf fafb-q-latest-x86_64-unknown-linux-musl.tar.gz --strip-components=1
sudo cp fafb-q /usr/local/bin/

# Linux ARM64
curl -LO https://bitbucket.org/thermsio/fafb-q/downloads/fafb-q-latest-aarch64-unknown-linux-musl.tar.gz
tar xzf fafb-q-latest-aarch64-unknown-linux-musl.tar.gz --strip-components=1
sudo cp fafb-q /usr/local/bin/
```

Versioned downloads are also available at [Bitbucket Downloads](https://bitbucket.org/thermsio/fafb-q/downloads/).
```

- [ ] **Step 2: Commit**

```bash
git add README.md
git commit -m "docs: add one-liner install command to README"
```
