#!/bin/sh # bootstrap-local.sh — prepares ./local/ for `docker run` smoke testing. # # Slurps Anthropic OAuth tokens out of a Claude install and prompts for Matrix # bot credentials. Source path can come from: # # 1. first positional arg ./bootstrap-local.sh ~/.claude-priv # 2. $CLAUDE_CONFIG_DIR env var CLAUDE_CONFIG_DIR=~/.claude-work ./bootstrap-local.sh # 3. default ~/.claude # # Idempotent. Safe to re-run after a token refresh. set -eu CLAUDE_DIR="${1:-${CLAUDE_CONFIG_DIR:-$HOME/.claude}}" CREDS="$CLAUDE_DIR/.credentials.json" if ! command -v jq >/dev/null 2>&1; then echo "error: jq not installed" >&2 exit 1 fi if [ ! -f "$CREDS" ]; then echo "error: $CREDS not found" >&2 echo "" >&2 echo "Override the Claude config dir if your install is elsewhere:" >&2 echo " $0 ~/.claude-priv" >&2 echo " CLAUDE_CONFIG_DIR=\$HOME/.claude-work $0" >&2 exit 1 fi if ! jq -e '.claudeAiOauth.accessToken' "$CREDS" >/dev/null 2>&1; then echo "error: $CREDS missing .claudeAiOauth.accessToken — is this a Claude credentials file?" >&2 exit 1 fi # Determine project root (so the script works from anywhere) ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" echo "Using Claude credentials from: $CREDS" echo "Writing to: $ROOT/local/" echo "" mkdir -p local/oauth-tokens local/matrix-bot local/state # --- Anthropic OAuth tokens --- jq -r .claudeAiOauth.accessToken "$CREDS" > local/oauth-tokens/accessToken jq -r .claudeAiOauth.refreshToken "$CREDS" > local/oauth-tokens/refreshToken jq -r .claudeAiOauth.expiresAt "$CREDS" > local/oauth-tokens/expiresAt # --- Matrix bot credentials (interactive) --- existing_hs="" [ -f local/matrix-bot/homeserver_url ] && existing_hs=$(cat local/matrix-bot/homeserver_url 2>/dev/null || true) existing_uid="" [ -f local/matrix-bot/user_id ] && existing_uid=$(cat local/matrix-bot/user_id 2>/dev/null || true) existing_did="" [ -f local/matrix-bot/device_id ] && existing_did=$(cat local/matrix-bot/device_id 2>/dev/null || true) echo "Matrix bot credentials (press Enter to keep existing values shown in brackets)" # Prompt for a value, storing the result in $REPLY_VALUE. Using a global instead of # command substitution because $() captures the prompt itself, hiding it from the user. prompt_value() { # $1 = label, $2 = current/default label="$1" default="$2" if [ -n "$default" ]; then printf " %s [%s]: " "$label" "$default" else printf " %s: " "$label" fi read -r REPLY_VALUE if [ -z "$REPLY_VALUE" ]; then REPLY_VALUE="$default" fi } prompt_value "homeserver_url" "$existing_hs"; hs="$REPLY_VALUE" prompt_value "user_id" "$existing_uid"; uid="$REPLY_VALUE" printf " access_token (will not echo, Enter to keep existing): " stty -echo 2>/dev/null || true read -r at stty echo 2>/dev/null || true printf "\n" if [ -z "$at" ] && [ -f local/matrix-bot/access_token ]; then at=$(cat local/matrix-bot/access_token) fi prompt_value "device_id" "$existing_did"; did="$REPLY_VALUE" if [ -z "$hs" ] || [ -z "$uid" ] || [ -z "$at" ] || [ -z "$did" ]; then echo "error: all four Matrix fields are required" >&2 exit 1 fi printf "%s" "$hs" > local/matrix-bot/homeserver_url printf "%s" "$uid" > local/matrix-bot/user_id printf "%s" "$at" > local/matrix-bot/access_token printf "%s" "$did" > local/matrix-bot/device_id chmod 600 local/oauth-tokens/* local/matrix-bot/* echo "" echo "Local bootstrap ready in $ROOT/local/" echo "Run:" echo " docker run --rm -e LOCAL_MODE=1 -e MATRIX_ROOM_ID='!yourroom:hs' \\" echo " -v \"\$PWD/local/oauth-tokens:/var/run/secrets/oauth-tokens\" \\" echo " -v \"\$PWD/local/matrix-bot:/var/run/secrets/matrix-bot:ro\" \\" echo " -v \"\$PWD/local/state:/state\" \\" echo " claude-matrix-bot:dev"