#!/usr/bin/env bash # # setup.sh - the one command: opencode + session pushing, from scratch, on this # Cloud Shell VM. # # bash <(curl -fsSL https://.pages.dev/setup.sh) # # It: # 1. logs this VM into GitHub with a token you paste (or GH_TOKEN if already set) # 2. installs opencode (once) and starts it in tmux, on port PORT # 3. installs sessions.sh, creates new1 + new2 and the private repo, takes the # first snapshot and starts the 3-minute push daemon # # Safe to re-run: a running opencode, existing auth, repo, folders and daemon # are all reused. # # Optional environment variables: # GH_TOKEN GitHub token; when unset you are prompted to paste one # (stdin only - never argv, a file or history) # PORT opencode port [default: 4096] # OC_VERSION opencode-ai npm version [default: 1.18.35] # BACKUP_REPO private repo name [default: cloudshell-sessions] # BACKUP_REMOTE full remote URL; skips `gh repo create` # BACKUP_INTERVAL seconds between passes [default: 180] # IDLE_LIMIT idle passes before pausing [default: 3] # # NEVER add `set -x` to this script: it would echo GH_TOKEN. set -euo pipefail BASE_URL="${BASE_URL:-https://opencode-cloudshell-vwb6.pages.dev}" log() { printf '%s\n' "$*"; } warn() { printf 'warning: %s\n' "$*" >&2; } die() { printf 'error: %s\n' "$*" >&2; exit 1; } # Everything below assumes the Cloud Shell VM, not a laptop. if [ ! -d /google/devshell ] && [ -z "${DEVSHELL_PROJECT_ID:-}" ]; then die "run this inside a Cloud Shell terminal. From your own machine use install.sh instead: bash <(curl -fsSL $BASE_URL/install.sh)" fi command -v tmux >/dev/null 2>&1 || die "tmux is missing on this VM." command -v git >/dev/null 2>&1 || die "git is missing on this VM." tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT fetch() { local name="$1" curl -fsSL "$BASE_URL/$name" -o "$tmp/$name" || die "could not download $BASE_URL/$name" bash -n "$tmp/$name" || die "$name failed its syntax check" } log "== 1/3 GitHub ==" if command -v gh >/dev/null 2>&1; then if [ -z "${GH_TOKEN:-}" ] && gh auth status >/dev/null 2>&1; then log "GitHub: already authenticated as $(gh api user --jq .login 2>/dev/null || echo unknown)." elif [ -z "${GH_TOKEN:-}" ] && [ ! -t 0 ]; then warn "gh is not authenticated and there is no terminal to prompt on." warn "set GH_TOKEN and run this command again." else if [ -z "${GH_TOKEN:-}" ]; then printf 'GitHub token (repo scope, input hidden): ' >&2 IFS= read -rs token || token="" printf '\n' >&2 [ -n "$token" ] || die "no token entered." else token="$GH_TOKEN" fi if printf '%s\n' "$token" | gh auth login --with-token; then unset token gh auth setup-git >/dev/null 2>&1 || warn "gh auth setup-git failed." log "GitHub: token accepted." else unset token die "GitHub rejected the token (needs 'repo' scope to create the private repo)." fi fi else warn "the gh CLI is missing; sessions.sh needs it to create the private repo." warn "set BACKUP_REMOTE= to skip repo creation." fi log "" log "== 2/3 opencode ==" fetch cloudshell.sh if bash "$tmp/cloudshell.sh" --status >/dev/null 2>&1; then log "opencode is already running; leaving it alone." else # stdin from /dev/null so cloudshell.sh does not attach and block this script. bash "$tmp/cloudshell.sh" folder is being pushed." log " sessions status: ~/.local/bin/cloudshell-sessions --status" log " sessions log: ~/.local/bin/cloudshell-sessions --logs" log " opencode: tmux attach -t opencode (Ctrl-B then D to leave)"