Improve wizard UX: CLI install/sign-in flow, user-controlled installs, ROOH credit
- Add ROOH credit (www.rooh.red) to banner, summary, and README - Step 1: Offer to install python3 and curl instead of hard-failing - Step 3: Detect missing Claude CLI and offer to install via npm - Step 3: Detect not-signed-in CLI and offer interactive OAuth sign-in - Step 3: Provide clear instructions and exit paths at every decision point - Update README with correct git clone URL and wizard capabilities - All install steps now require user confirmation before proceeding Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
22731fff60
commit
32a4e739dc
34
README.md
34
README.md
@ -1,5 +1,7 @@
|
||||
# OAuth Fix for OpenClaw + Claude Max
|
||||
|
||||
> Created by **ROOH** — [www.rooh.red](https://www.rooh.red)
|
||||
|
||||
Automatic Anthropic OAuth token refresh for OpenClaw. Keeps your Claude Max tokens alive indefinitely.
|
||||
|
||||
## The Problem
|
||||
@ -26,19 +28,22 @@ Timer (every 30min) Claude Code CLI sync-oauth-token.sh Op
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USER/oauth-fix-openclaw-final.git
|
||||
cd oauth-fix-openclaw-final
|
||||
git clone https://git.eeqj.de/ROOH/openclaw_oauth_sync.git
|
||||
cd openclaw_oauth_sync
|
||||
sudo ./setup.sh
|
||||
```
|
||||
|
||||
The interactive wizard will:
|
||||
1. Detect your OpenClaw installation paths
|
||||
2. Find Claude CLI credentials
|
||||
3. Configure the Anthropic model (if not already set up)
|
||||
4. Install the token sync watcher (inotifywait)
|
||||
5. Detect Claude CLI (container or host) and install the auto-refresh trigger
|
||||
6. Test the CLI invocation to confirm it works
|
||||
7. Verify everything works
|
||||
1. Check prerequisites (offers to install python3, curl, inotify-tools if missing)
|
||||
2. Detect your OpenClaw installation paths
|
||||
3. Find Claude CLI credentials (offers to install CLI and help with sign-in if needed)
|
||||
4. Configure the Anthropic model (if not already set up)
|
||||
5. Install the token sync watcher (inotifywait or timer fallback)
|
||||
6. Detect Claude CLI (container or host) and install the auto-refresh trigger
|
||||
7. Test the CLI invocation to confirm it works
|
||||
8. Verify everything works
|
||||
|
||||
Every install step asks for your confirmation first — you have full control over what gets installed.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@ -46,9 +51,10 @@ The interactive wizard will:
|
||||
- **Docker** + **Docker Compose v2**
|
||||
- **OpenClaw** installed and running
|
||||
- **Claude Max subscription** with OAuth credentials
|
||||
- **Claude Code CLI** — either in a Docker container or installed on the host
|
||||
- **python3**
|
||||
- **inotify-tools** (optional, installed by wizard if missing)
|
||||
- **Claude Code CLI** — either in a Docker container or installed on the host (wizard can install it)
|
||||
- **python3** (wizard offers to install if missing)
|
||||
- **curl** (wizard offers to install if missing)
|
||||
- **inotify-tools** (optional, wizard offers to install if missing)
|
||||
|
||||
## How It Works
|
||||
|
||||
@ -257,6 +263,10 @@ See [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) for common issues:
|
||||
- [Token Refresh](docs/HOW-TOKEN-REFRESH-WORKS.md) — How Claude CLI refreshes tokens
|
||||
- [Field Mapping](docs/FIELD-MAPPING.md) — Credential format reference
|
||||
|
||||
## Author
|
||||
|
||||
**ROOH** — [www.rooh.red](https://www.rooh.red)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
249
setup.sh
249
setup.sh
@ -68,6 +68,8 @@ echo " ╔═══════════════════════
|
||||
echo " ║ OAuth Fix for OpenClaw + Claude Max ║"
|
||||
echo " ║ Automatic Anthropic Token Refresh ║"
|
||||
echo " ║ v${VERSION} ║"
|
||||
echo " ║ ║"
|
||||
echo " ║ Created by ROOH — www.rooh.red ║"
|
||||
echo " ╚══════════════════════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
echo -e "${DIM} Keeps your Anthropic OAuth tokens fresh by syncing"
|
||||
@ -81,11 +83,12 @@ header "Step 1: Checking Prerequisites"
|
||||
|
||||
MISSING=0
|
||||
|
||||
for cmd in docker python3 curl systemctl; do
|
||||
# --- Required (cannot be installed by wizard) ---
|
||||
for cmd in systemctl docker; do
|
||||
if command -v "$cmd" &>/dev/null; then
|
||||
success "$cmd found"
|
||||
else
|
||||
error "$cmd not found"
|
||||
error "$cmd not found — required, cannot be installed by this wizard"
|
||||
MISSING=$((MISSING + 1))
|
||||
fi
|
||||
done
|
||||
@ -94,19 +97,57 @@ done
|
||||
if docker compose version &>/dev/null; then
|
||||
success "docker compose found ($(docker compose version --short 2>/dev/null || echo 'v2'))"
|
||||
else
|
||||
error "docker compose v2 not found"
|
||||
error "docker compose v2 not found — required"
|
||||
MISSING=$((MISSING + 1))
|
||||
fi
|
||||
|
||||
# Check inotifywait
|
||||
# --- python3 (offer to install) ---
|
||||
if command -v python3 &>/dev/null; then
|
||||
success "python3 found"
|
||||
else
|
||||
warn "python3 not found (required for JSON processing)"
|
||||
if confirm " Install python3 now?" "Y"; then
|
||||
apt-get install -y python3 2>&1 | tail -3
|
||||
if command -v python3 &>/dev/null; then
|
||||
success "python3 installed"
|
||||
else
|
||||
error "python3 installation failed"
|
||||
MISSING=$((MISSING + 1))
|
||||
fi
|
||||
else
|
||||
error "python3 is required — install it manually and re-run"
|
||||
MISSING=$((MISSING + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- curl (offer to install) ---
|
||||
if command -v curl &>/dev/null; then
|
||||
success "curl found"
|
||||
else
|
||||
warn "curl not found"
|
||||
if confirm " Install curl now?" "Y"; then
|
||||
apt-get install -y curl 2>&1 | tail -3
|
||||
if command -v curl &>/dev/null; then
|
||||
success "curl installed"
|
||||
else
|
||||
error "curl installation failed"
|
||||
MISSING=$((MISSING + 1))
|
||||
fi
|
||||
else
|
||||
error "curl is required — install it manually and re-run"
|
||||
MISSING=$((MISSING + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- inotifywait (offer to install, optional) ---
|
||||
if command -v inotifywait &>/dev/null; then
|
||||
success "inotifywait found"
|
||||
USE_INOTIFY=true
|
||||
else
|
||||
warn "inotifywait not found (inotify-tools package)"
|
||||
echo -e " ${DIM}Install with: apt install inotify-tools${NC}"
|
||||
echo -e " ${DIM}Provides real-time credential sync. Without it, a 6-hour timer is used instead.${NC}"
|
||||
if confirm " Install inotify-tools now?" "Y"; then
|
||||
apt-get install -y inotify-tools 2>&1 | tail -1
|
||||
apt-get install -y inotify-tools 2>&1 | tail -3
|
||||
if command -v inotifywait &>/dev/null; then
|
||||
success "inotifywait installed"
|
||||
USE_INOTIFY=true
|
||||
@ -197,17 +238,22 @@ OPENCLAW_OAUTH_FILE="$OPENCLAW_CONFIG_DIR/credentials/oauth.json"
|
||||
success "OAuth file: $OPENCLAW_OAUTH_FILE"
|
||||
|
||||
# ============================================================================
|
||||
# STEP 3: Detect Claude CLI Credentials
|
||||
# STEP 3: Claude CLI & Credentials
|
||||
# ============================================================================
|
||||
header "Step 3: Detecting Claude CLI Credentials"
|
||||
header "Step 3: Claude CLI & Credentials"
|
||||
|
||||
CLAUDE_CREDS_FILE=""
|
||||
EARLY_CLI_MODE=""
|
||||
EARLY_CLI_CONTAINER=""
|
||||
CLI_INSTALLED=false
|
||||
|
||||
# Strategy 1: Find claude-proxy or similar container
|
||||
# --- Phase 1: Search for existing credentials ---
|
||||
info "Searching for Claude CLI credentials..."
|
||||
|
||||
# Strategy 1: Find claude container and check mounts
|
||||
CLAUDE_CONTAINER=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -i 'claude' | head -1)
|
||||
if [ -n "$CLAUDE_CONTAINER" ]; then
|
||||
info "Found Claude container: $CLAUDE_CONTAINER"
|
||||
# Get its volume mounts and find credentials
|
||||
MOUNT_SOURCE=$(docker inspect "$CLAUDE_CONTAINER" --format '{{range .Mounts}}{{if or (eq .Destination "/root") (eq .Destination "/root/.claude") (eq .Destination "/home/node/.claude")}}{{.Source}}{{end}}{{end}}' 2>/dev/null)
|
||||
if [ -n "$MOUNT_SOURCE" ]; then
|
||||
for suffix in "/.claude/.credentials.json" "/.credentials.json"; do
|
||||
@ -241,16 +287,185 @@ if [ -z "$CLAUDE_CREDS_FILE" ]; then
|
||||
done
|
||||
fi
|
||||
|
||||
# --- Phase 2: If no credentials found, detect CLI and help user ---
|
||||
if [ -z "$CLAUDE_CREDS_FILE" ] || [ ! -f "$CLAUDE_CREDS_FILE" ]; then
|
||||
warn "Could not auto-detect Claude CLI credentials"
|
||||
CLAUDE_CREDS_FILE=$(ask "Enter path to Claude CLI .credentials.json")
|
||||
if [ ! -f "$CLAUDE_CREDS_FILE" ]; then
|
||||
error "File not found: $CLAUDE_CREDS_FILE"
|
||||
exit 1
|
||||
warn "No Claude CLI credentials found"
|
||||
echo ""
|
||||
|
||||
# Detect if Claude CLI is installed
|
||||
if [ -n "$CLAUDE_CONTAINER" ] && docker exec "$CLAUDE_CONTAINER" which claude &>/dev/null; then
|
||||
CLI_INSTALLED=true
|
||||
EARLY_CLI_MODE="container"
|
||||
EARLY_CLI_CONTAINER="$CLAUDE_CONTAINER"
|
||||
info "Claude Code CLI found in container: $CLAUDE_CONTAINER"
|
||||
elif command -v claude &>/dev/null; then
|
||||
CLI_INSTALLED=true
|
||||
EARLY_CLI_MODE="host"
|
||||
info "Claude Code CLI found on host: $(which claude)"
|
||||
fi
|
||||
|
||||
# --- CLI not installed: offer to install ---
|
||||
if ! $CLI_INSTALLED; then
|
||||
echo -e " ${BOLD}Claude Code CLI is not installed.${NC}"
|
||||
echo " It's required for automatic OAuth token refresh."
|
||||
echo ""
|
||||
echo " Options:"
|
||||
echo " 1) Install Claude Code CLI now (requires npm/Node.js)"
|
||||
echo " 2) Show me the install instructions (exit wizard)"
|
||||
echo " 3) Skip — I'll provide the credentials path manually"
|
||||
CHOICE=$(ask "Select" "1")
|
||||
case "$CHOICE" in
|
||||
1)
|
||||
if command -v npm &>/dev/null; then
|
||||
info "Installing Claude Code CLI via npm..."
|
||||
npm install -g @anthropic-ai/claude-code 2>&1 | tail -5
|
||||
if command -v claude &>/dev/null; then
|
||||
success "Claude Code CLI installed successfully"
|
||||
CLI_INSTALLED=true
|
||||
EARLY_CLI_MODE="host"
|
||||
else
|
||||
error "Installation failed. Check npm/Node.js setup."
|
||||
fi
|
||||
else
|
||||
warn "npm not found. Node.js is required to install Claude Code CLI."
|
||||
echo ""
|
||||
echo " Install Node.js first:"
|
||||
echo " curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -"
|
||||
echo " apt install -y nodejs"
|
||||
echo ""
|
||||
if confirm " Install Node.js + Claude Code CLI now?" "N"; then
|
||||
info "Installing Node.js LTS..."
|
||||
curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - 2>&1 | tail -3
|
||||
apt-get install -y nodejs 2>&1 | tail -3
|
||||
if command -v npm &>/dev/null; then
|
||||
info "Installing Claude Code CLI..."
|
||||
npm install -g @anthropic-ai/claude-code 2>&1 | tail -5
|
||||
if command -v claude &>/dev/null; then
|
||||
success "Claude Code CLI installed successfully"
|
||||
CLI_INSTALLED=true
|
||||
EARLY_CLI_MODE="host"
|
||||
else
|
||||
error "Claude CLI installation failed"
|
||||
fi
|
||||
else
|
||||
error "Node.js installation failed"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
2)
|
||||
echo ""
|
||||
info "Install Claude Code CLI:"
|
||||
echo ""
|
||||
echo " # Option A: npm (recommended)"
|
||||
echo " npm install -g @anthropic-ai/claude-code"
|
||||
echo ""
|
||||
echo " # Option B: Run directly with npx"
|
||||
echo " npx @anthropic-ai/claude-code"
|
||||
echo ""
|
||||
echo " # More info:"
|
||||
echo " https://docs.anthropic.com/en/docs/claude-code"
|
||||
echo ""
|
||||
info "After installing and signing in, re-run: sudo ./setup.sh"
|
||||
exit 0
|
||||
;;
|
||||
3)
|
||||
info "Continuing without Claude CLI..."
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# --- CLI installed but no credentials: offer sign-in ---
|
||||
if $CLI_INSTALLED && ([ -z "$CLAUDE_CREDS_FILE" ] || [ ! -f "$CLAUDE_CREDS_FILE" ]); then
|
||||
echo ""
|
||||
warn "Claude Code CLI is installed but not signed in (no OAuth credentials)."
|
||||
info "You need to authenticate with your Claude Max subscription."
|
||||
info "This will open an OAuth flow — you'll get a URL to visit in your browser."
|
||||
echo ""
|
||||
if confirm " Launch Claude CLI now to sign in?" "Y"; then
|
||||
echo ""
|
||||
echo -e " ${BOLD}Complete the OAuth sign-in in your browser.${NC}"
|
||||
echo -e " ${BOLD}After signing in, press Ctrl+C or type /exit to return here.${NC}"
|
||||
echo ""
|
||||
if [ "$EARLY_CLI_MODE" = "container" ]; then
|
||||
docker exec -it "$EARLY_CLI_CONTAINER" claude || true
|
||||
else
|
||||
claude || true
|
||||
fi
|
||||
echo ""
|
||||
info "Checking for credentials after sign-in..."
|
||||
|
||||
# Re-search for credentials
|
||||
for path in \
|
||||
/root/.claude/.credentials.json \
|
||||
"$HOME/.claude/.credentials.json"; do
|
||||
if [ -f "$path" ]; then
|
||||
CLAUDE_CREDS_FILE="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Also check container mounts again
|
||||
if [ -z "$CLAUDE_CREDS_FILE" ] && [ -n "$CLAUDE_CONTAINER" ]; then
|
||||
MOUNT_SOURCE=$(docker inspect "$CLAUDE_CONTAINER" --format '{{range .Mounts}}{{if or (eq .Destination "/root") (eq .Destination "/root/.claude") (eq .Destination "/home/node/.claude")}}{{.Source}}{{end}}{{end}}' 2>/dev/null)
|
||||
if [ -n "$MOUNT_SOURCE" ]; then
|
||||
for suffix in "/.claude/.credentials.json" "/.credentials.json"; do
|
||||
if [ -f "${MOUNT_SOURCE}${suffix}" ]; then
|
||||
CLAUDE_CREDS_FILE="${MOUNT_SOURCE}${suffix}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Last resort: ask for manual path ---
|
||||
if [ -z "$CLAUDE_CREDS_FILE" ] || [ ! -f "$CLAUDE_CREDS_FILE" ]; then
|
||||
echo ""
|
||||
warn "Could not find credentials automatically."
|
||||
CLAUDE_CREDS_FILE=$(ask "Enter path to .credentials.json (or 'quit' to exit)")
|
||||
if [ "$CLAUDE_CREDS_FILE" = "quit" ] || [ "$CLAUDE_CREDS_FILE" = "q" ]; then
|
||||
echo ""
|
||||
info "To set up credentials:"
|
||||
info " 1. Install Claude Code CLI: npm install -g @anthropic-ai/claude-code"
|
||||
info " 2. Sign in: claude"
|
||||
info " 3. Re-run this wizard: sudo ./setup.sh"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$CLAUDE_CREDS_FILE" ]; then
|
||||
error "File not found: $CLAUDE_CREDS_FILE"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate credentials
|
||||
# --- Phase 3: Validate credentials ---
|
||||
HAS_OAUTH=$(python3 -c "
|
||||
import json
|
||||
with open('$CLAUDE_CREDS_FILE') as f:
|
||||
d = json.load(f)
|
||||
oauth = d.get('claudeAiOauth', {})
|
||||
print('yes' if oauth.get('accessToken') else 'no')
|
||||
" 2>/dev/null || echo "no")
|
||||
|
||||
if [ "$HAS_OAUTH" != "yes" ]; then
|
||||
error "Credentials file exists but contains no OAuth tokens."
|
||||
info "Claude CLI may not be signed in with a Claude Max subscription."
|
||||
echo ""
|
||||
if $CLI_INSTALLED; then
|
||||
info "Sign in to Claude CLI and re-run this wizard:"
|
||||
info " claude # sign in with OAuth"
|
||||
info " sudo ./setup.sh # re-run wizard"
|
||||
else
|
||||
info "Install Claude Code CLI, sign in, and re-run:"
|
||||
info " npm install -g @anthropic-ai/claude-code"
|
||||
info " claude # sign in with OAuth"
|
||||
info " sudo ./setup.sh # re-run wizard"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOKEN_INFO=$(python3 -c "
|
||||
import json, time
|
||||
with open('$CLAUDE_CREDS_FILE') as f:
|
||||
@ -850,3 +1065,5 @@ fi
|
||||
echo " ./scripts/verify.sh # Health check"
|
||||
echo " ./setup.sh --uninstall # Remove everything"
|
||||
echo ""
|
||||
echo -e " ${DIM}Created by ROOH — www.rooh.red${NC}"
|
||||
echo ""
|
||||
|
||||
Loading…
Reference in New Issue
Block a user