- Setup wizard with auto-detection of OpenClaw paths and Claude CLI - Token sync watcher (inotifywait) for real-time credential updates - Auto-refresh trigger timer that runs Claude CLI every 30 min - Supports Claude CLI in Docker container or on host - Temporary ANTHROPIC_BASE_URL override for container environments - Anthropic model configuration for OpenClaw - Auth profile management (fixes key vs access field) - Systemd services and timers for both sync and trigger - Comprehensive documentation and troubleshooting guides - Re-authentication notification system Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
154 lines
4.3 KiB
Bash
Executable File
154 lines
4.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# fix-auth-profiles.sh — Fix broken Anthropic auth profiles in all OpenClaw agents
|
|
#
|
|
# Problem: Auth profiles may have {type:"oauth", key:"sk-ant-oat01-..."}
|
|
# but OpenClaw's isValidProfile() for type:"oauth" checks for "access" field, not "key"
|
|
# This causes the profile to be skipped and fall through to env var fallback
|
|
#
|
|
# Fix: Change "key" -> "access" field, clear cooldown stats
|
|
#
|
|
# Usage:
|
|
# ./fix-auth-profiles.sh # auto-detect config dir
|
|
# ./fix-auth-profiles.sh /path/to/.openclaw # custom config dir
|
|
|
|
set -euo pipefail
|
|
|
|
OPENCLAW_CONFIG_DIR="${1:-}"
|
|
LOG_PREFIX="[fix-auth-profiles]"
|
|
|
|
log() { echo "$LOG_PREFIX $*"; }
|
|
error() { echo "$LOG_PREFIX ERROR: $*" >&2; }
|
|
|
|
# Auto-detect config dir if not provided
|
|
if [ -z "$OPENCLAW_CONFIG_DIR" ]; then
|
|
if [ -d "/root/.openclaw/agents" ]; then
|
|
OPENCLAW_CONFIG_DIR="/root/.openclaw"
|
|
elif [ -d "$HOME/.openclaw/agents" ]; then
|
|
OPENCLAW_CONFIG_DIR="$HOME/.openclaw"
|
|
else
|
|
error "Cannot find OpenClaw config directory. Provide path as argument."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
log "Config directory: $OPENCLAW_CONFIG_DIR"
|
|
|
|
AGENTS_DIR="$OPENCLAW_CONFIG_DIR/agents"
|
|
if [ ! -d "$AGENTS_DIR" ]; then
|
|
error "Agents directory not found: $AGENTS_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
# Get current token from .env if available
|
|
TOKEN=""
|
|
for env_file in /root/openclaw/.env "$OPENCLAW_CONFIG_DIR/../openclaw/.env"; do
|
|
if [ -f "$env_file" ]; then
|
|
TOKEN=$(grep -oP 'ANTHROPIC_OAUTH_TOKEN="\K[^"]+' "$env_file" 2>/dev/null || true)
|
|
[ -n "$TOKEN" ] && break
|
|
fi
|
|
done
|
|
|
|
FIXED=0
|
|
SKIPPED=0
|
|
|
|
for agent_dir in "$AGENTS_DIR"/*/agent; do
|
|
agent=$(basename "$(dirname "$agent_dir")")
|
|
f="$agent_dir/auth-profiles.json"
|
|
|
|
if [ ! -f "$f" ]; then
|
|
log "SKIP $agent: no auth-profiles.json"
|
|
SKIPPED=$((SKIPPED + 1))
|
|
continue
|
|
fi
|
|
|
|
log "Checking $agent..."
|
|
|
|
python3 -c "
|
|
import json, sys
|
|
|
|
with open('$f') as fh:
|
|
data = json.load(fh)
|
|
|
|
changed = False
|
|
|
|
# Fix profile structure
|
|
if 'anthropic:default' in data.get('profiles', {}):
|
|
p = data['profiles']['anthropic:default']
|
|
|
|
# Ensure type is oauth
|
|
if p.get('type') != 'oauth':
|
|
p['type'] = 'oauth'
|
|
changed = True
|
|
|
|
# Ensure provider is anthropic
|
|
if p.get('provider') != 'anthropic':
|
|
p['provider'] = 'anthropic'
|
|
changed = True
|
|
|
|
# Move key -> access if needed
|
|
if 'key' in p and 'access' not in p:
|
|
p['access'] = p.pop('key')
|
|
changed = True
|
|
print(' Fixed: key -> access')
|
|
elif 'key' in p and 'access' in p:
|
|
del p['key']
|
|
changed = True
|
|
print(' Fixed: removed duplicate key field')
|
|
|
|
# Update token if provided
|
|
token = '$TOKEN'
|
|
if token and p.get('access') != token:
|
|
p['access'] = token
|
|
changed = True
|
|
print(f' Updated token: {token[:20]}...')
|
|
|
|
if not changed:
|
|
print(' Already correct')
|
|
else:
|
|
# Create the profile if it doesn't exist
|
|
token = '$TOKEN'
|
|
if token:
|
|
if 'profiles' not in data:
|
|
data['profiles'] = {}
|
|
data['profiles']['anthropic:default'] = {
|
|
'type': 'oauth',
|
|
'provider': 'anthropic',
|
|
'access': token
|
|
}
|
|
changed = True
|
|
print(' Created anthropic:default profile')
|
|
else:
|
|
print(' No anthropic:default profile and no token to create one')
|
|
sys.exit(0)
|
|
|
|
# Clear cooldown for anthropic profile
|
|
if 'usageStats' in data and 'anthropic:default' in data['usageStats']:
|
|
stats = data['usageStats']['anthropic:default']
|
|
for key in ['cooldownUntil', 'errorCount', 'failureCounts', 'lastFailureAt']:
|
|
if key in stats:
|
|
del stats[key]
|
|
changed = True
|
|
if changed:
|
|
print(' Cleared cooldown stats')
|
|
|
|
# Ensure lastGood points to anthropic:default
|
|
if data.get('lastGood', {}).get('anthropic') != 'anthropic:default':
|
|
if 'lastGood' not in data:
|
|
data['lastGood'] = {}
|
|
data['lastGood']['anthropic'] = 'anthropic:default'
|
|
changed = True
|
|
|
|
if changed:
|
|
with open('$f', 'w') as fh:
|
|
json.dump(data, fh, indent=2)
|
|
print(' Saved')
|
|
"
|
|
FIXED=$((FIXED + 1))
|
|
done
|
|
|
|
log ""
|
|
log "Done. Fixed: $FIXED agents, Skipped: $SKIPPED"
|
|
log ""
|
|
log "Restart gateway to apply changes:"
|
|
log " cd /root/openclaw && docker compose down openclaw-gateway && docker compose up -d openclaw-gateway"
|