| #!/usr/bin/env bash |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| _CLR_RESET='\033[0m' |
| _CLR_BOLD='\033[1m' |
| _CLR_DIM='\033[2m' |
| _CLR_GREEN='\033[0;32m' |
| _CLR_YELLOW='\033[1;33m' |
| _CLR_BLUE='\033[0;34m' |
| _CLR_MAGENTA='\033[0;35m' |
| _CLR_CYAN='\033[0;36m' |
| _CLR_RED='\033[0;31m' |
|
|
| |
| _clr_cmd() { |
| echo -e "${_CLR_GREEN}${_CLR_BOLD}$1${_CLR_RESET}" |
| } |
|
|
| |
| _cmd() { |
| echo "${_CLR_GREEN}${_CLR_BOLD}$1${_CLR_RESET}" |
| } |
|
|
| |
| |
| |
| CLAWDOCK_CONFIG="${HOME}/.clawdock/config" |
|
|
| |
| CLAWDOCK_COMMON_PATHS=( |
| "${HOME}/openclaw" |
| "${HOME}/workspace/openclaw" |
| "${HOME}/projects/openclaw" |
| "${HOME}/dev/openclaw" |
| "${HOME}/code/openclaw" |
| "${HOME}/src/openclaw" |
| ) |
|
|
| _clawdock_filter_warnings() { |
| grep -v "^WARN\|^time=" |
| } |
|
|
| _clawdock_trim_quotes() { |
| local value="$1" |
| value="${value#\"}" |
| value="${value%\"}" |
| printf "%s" "$value" |
| } |
|
|
| _clawdock_read_config_dir() { |
| if [[ ! -f "$CLAWDOCK_CONFIG" ]]; then |
| return 1 |
| fi |
| local raw |
| raw=$(sed -n 's/^CLAWDOCK_DIR=//p' "$CLAWDOCK_CONFIG" | head -n 1) |
| if [[ -z "$raw" ]]; then |
| return 1 |
| fi |
| _clawdock_trim_quotes "$raw" |
| } |
|
|
| |
| _clawdock_ensure_dir() { |
| |
| if [[ -n "$CLAWDOCK_DIR" && -f "${CLAWDOCK_DIR}/docker-compose.yml" ]]; then |
| return 0 |
| fi |
|
|
| |
| local config_dir |
| config_dir=$(_clawdock_read_config_dir) |
| if [[ -n "$config_dir" && -f "${config_dir}/docker-compose.yml" ]]; then |
| CLAWDOCK_DIR="$config_dir" |
| return 0 |
| fi |
|
|
| |
| local found_path="" |
| for path in "${CLAWDOCK_COMMON_PATHS[@]}"; do |
| if [[ -f "${path}/docker-compose.yml" ]]; then |
| found_path="$path" |
| break |
| fi |
| done |
|
|
| if [[ -n "$found_path" ]]; then |
| echo "" |
| echo "π¦ Found OpenClaw at: $found_path" |
| echo -n " Use this location? [Y/n] " |
| read -r response |
| if [[ "$response" =~ ^[Nn] ]]; then |
| echo "" |
| echo "Set CLAWDOCK_DIR manually:" |
| echo " export CLAWDOCK_DIR=/path/to/openclaw" |
| return 1 |
| fi |
| CLAWDOCK_DIR="$found_path" |
| else |
| echo "" |
| echo "β OpenClaw not found in common locations." |
| echo "" |
| echo "Clone it first:" |
| echo "" |
| echo " git clone https://github.com/openclaw/openclaw.git ~/openclaw" |
| echo " cd ~/openclaw && ./docker-setup.sh" |
| echo "" |
| echo "Or set CLAWDOCK_DIR if it's elsewhere:" |
| echo "" |
| echo " export CLAWDOCK_DIR=/path/to/openclaw" |
| echo "" |
| return 1 |
| fi |
|
|
| |
| if [[ ! -d "${HOME}/.clawdock" ]]; then |
| /bin/mkdir -p "${HOME}/.clawdock" |
| fi |
| echo "CLAWDOCK_DIR=\"$CLAWDOCK_DIR\"" > "$CLAWDOCK_CONFIG" |
| echo "β
Saved to $CLAWDOCK_CONFIG" |
| echo "" |
| return 0 |
| } |
|
|
| |
| _clawdock_compose() { |
| _clawdock_ensure_dir || return 1 |
| local compose_args=(-f "${CLAWDOCK_DIR}/docker-compose.yml") |
| if [[ -f "${CLAWDOCK_DIR}/docker-compose.extra.yml" ]]; then |
| compose_args+=(-f "${CLAWDOCK_DIR}/docker-compose.extra.yml") |
| fi |
| command docker compose "${compose_args[@]}" "$@" |
| } |
|
|
| _clawdock_read_env_token() { |
| _clawdock_ensure_dir || return 1 |
| if [[ ! -f "${CLAWDOCK_DIR}/.env" ]]; then |
| return 1 |
| fi |
| local raw |
| raw=$(sed -n 's/^OPENCLAW_GATEWAY_TOKEN=//p' "${CLAWDOCK_DIR}/.env" | head -n 1) |
| if [[ -z "$raw" ]]; then |
| return 1 |
| fi |
| _clawdock_trim_quotes "$raw" |
| } |
|
|
| |
| clawdock-start() { |
| _clawdock_compose up -d openclaw-gateway |
| } |
|
|
| clawdock-stop() { |
| _clawdock_compose down |
| } |
|
|
| clawdock-restart() { |
| _clawdock_compose restart openclaw-gateway |
| } |
|
|
| clawdock-logs() { |
| _clawdock_compose logs -f openclaw-gateway |
| } |
|
|
| clawdock-status() { |
| _clawdock_compose ps |
| } |
|
|
| |
| clawdock-cd() { |
| _clawdock_ensure_dir || return 1 |
| cd "${CLAWDOCK_DIR}" |
| } |
|
|
| clawdock-config() { |
| cd ~/.openclaw |
| } |
|
|
| clawdock-workspace() { |
| cd ~/.openclaw/workspace |
| } |
|
|
| |
| clawdock-shell() { |
| _clawdock_compose exec openclaw-gateway \ |
| bash -c 'echo "alias openclaw=\"./openclaw.mjs\"" > /tmp/.bashrc_openclaw && bash --rcfile /tmp/.bashrc_openclaw' |
| } |
|
|
| clawdock-exec() { |
| _clawdock_compose exec openclaw-gateway "$@" |
| } |
|
|
| clawdock-cli() { |
| _clawdock_compose run --rm openclaw-cli "$@" |
| } |
|
|
| |
| clawdock-rebuild() { |
| _clawdock_compose build openclaw-gateway |
| } |
|
|
| clawdock-clean() { |
| _clawdock_compose down -v --remove-orphans |
| } |
|
|
| |
| clawdock-health() { |
| _clawdock_ensure_dir || return 1 |
| local token |
| token=$(_clawdock_read_env_token) |
| if [[ -z "$token" ]]; then |
| echo "β Error: Could not find gateway token" |
| echo " Check: ${CLAWDOCK_DIR}/.env" |
| return 1 |
| fi |
| _clawdock_compose exec -e "OPENCLAW_GATEWAY_TOKEN=$token" openclaw-gateway \ |
| node dist/index.js health |
| } |
|
|
| |
| clawdock-token() { |
| _clawdock_read_env_token |
| } |
|
|
| |
| clawdock-fix-token() { |
| _clawdock_ensure_dir || return 1 |
|
|
| echo "π§ Configuring gateway token..." |
| local token |
| token=$(clawdock-token) |
| if [[ -z "$token" ]]; then |
| echo "β Error: Could not find gateway token" |
| echo " Check: ${CLAWDOCK_DIR}/.env" |
| return 1 |
| fi |
|
|
| echo "π Setting token: ${token:0:20}..." |
|
|
| _clawdock_compose exec -e "TOKEN=$token" openclaw-gateway \ |
| bash -c './openclaw.mjs config set gateway.remote.token "$TOKEN" && ./openclaw.mjs config set gateway.auth.token "$TOKEN"' 2>&1 | _clawdock_filter_warnings |
|
|
| echo "π Verifying token was saved..." |
| local saved_token |
| saved_token=$(_clawdock_compose exec openclaw-gateway \ |
| bash -c "./openclaw.mjs config get gateway.remote.token 2>/dev/null" 2>&1 | _clawdock_filter_warnings | tr -d '\r\n' | head -c 64) |
|
|
| if [[ "$saved_token" == "$token" ]]; then |
| echo "β
Token saved correctly!" |
| else |
| echo "β οΈ Token mismatch detected" |
| echo " Expected: ${token:0:20}..." |
| echo " Got: ${saved_token:0:20}..." |
| fi |
|
|
| echo "π Restarting gateway..." |
| _clawdock_compose restart openclaw-gateway 2>&1 | _clawdock_filter_warnings |
|
|
| echo "β³ Waiting for gateway to start..." |
| sleep 5 |
|
|
| echo "β
Configuration complete!" |
| echo -e " Try: $(_cmd clawdock-devices)" |
| } |
|
|
| |
| clawdock-dashboard() { |
| _clawdock_ensure_dir || return 1 |
|
|
| echo "π¦ Getting dashboard URL..." |
| local output exit_status url |
| output=$(_clawdock_compose run --rm openclaw-cli dashboard --no-open 2>&1) |
| exit_status=$? |
| url=$(printf "%s\n" "$output" | _clawdock_filter_warnings | grep -o 'http[s]\?://[^[:space:]]*' | head -n 1) |
| if [[ $exit_status -ne 0 ]]; then |
| echo "β Failed to get dashboard URL" |
| echo -e " Try restarting: $(_cmd clawdock-restart)" |
| return 1 |
| fi |
|
|
| if [[ -n "$url" ]]; then |
| echo "β
Opening: $url" |
| open "$url" 2>/dev/null || xdg-open "$url" 2>/dev/null || echo " Please open manually: $url" |
| echo "" |
| echo -e "${_CLR_CYAN}π‘ If you see 'pairing required' error:${_CLR_RESET}" |
| echo -e " 1. Run: $(_cmd clawdock-devices)" |
| echo " 2. Copy the Request ID from the Pending table" |
| echo -e " 3. Run: $(_cmd 'clawdock-approve <request-id>')" |
| else |
| echo "β Failed to get dashboard URL" |
| echo -e " Try restarting: $(_cmd clawdock-restart)" |
| fi |
| } |
|
|
| |
| clawdock-devices() { |
| _clawdock_ensure_dir || return 1 |
|
|
| echo "π Checking device pairings..." |
| local output exit_status |
| output=$(_clawdock_compose exec openclaw-gateway node dist/index.js devices list 2>&1) |
| exit_status=$? |
| printf "%s\n" "$output" | _clawdock_filter_warnings |
| if [ $exit_status -ne 0 ]; then |
| echo "" |
| echo -e "${_CLR_CYAN}π‘ If you see token errors above:${_CLR_RESET}" |
| echo -e " 1. Verify token is set: $(_cmd clawdock-token)" |
| echo " 2. Try manual config inside container:" |
| echo -e " $(_cmd clawdock-shell)" |
| echo -e " $(_cmd 'openclaw config get gateway.remote.token')" |
| return 1 |
| fi |
|
|
| echo "" |
| echo -e "${_CLR_CYAN}π‘ To approve a pairing request:${_CLR_RESET}" |
| echo -e " $(_cmd 'clawdock-approve <request-id>')" |
| } |
|
|
| |
| clawdock-approve() { |
| _clawdock_ensure_dir || return 1 |
|
|
| if [[ -z "$1" ]]; then |
| echo -e "β Usage: $(_cmd 'clawdock-approve <request-id>')" |
| echo "" |
| echo -e "${_CLR_CYAN}π‘ How to approve a device:${_CLR_RESET}" |
| echo -e " 1. Run: $(_cmd clawdock-devices)" |
| echo " 2. Find the Request ID in the Pending table (long UUID)" |
| echo -e " 3. Run: $(_cmd 'clawdock-approve <that-request-id>')" |
| echo "" |
| echo "Example:" |
| echo -e " $(_cmd 'clawdock-approve 6f9db1bd-a1cc-4d3f-b643-2c195262464e')" |
| return 1 |
| fi |
|
|
| echo "β
Approving device: $1" |
| _clawdock_compose exec openclaw-gateway \ |
| node dist/index.js devices approve "$1" 2>&1 | _clawdock_filter_warnings |
|
|
| echo "" |
| echo "β
Device approved! Refresh your browser." |
| } |
|
|
| |
| clawdock-help() { |
| echo -e "\n${_CLR_BOLD}${_CLR_CYAN}π¦ ClawDock - Docker Helpers for OpenClaw${_CLR_RESET}\n" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_MAGENTA}β‘ Basic Operations${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-start) ${_CLR_DIM}Start the gateway${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-stop) ${_CLR_DIM}Stop the gateway${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-restart) ${_CLR_DIM}Restart the gateway${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-status) ${_CLR_DIM}Check container status${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-logs) ${_CLR_DIM}View live logs (follows)${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_MAGENTA}π Container Access${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-shell) ${_CLR_DIM}Shell into container (openclaw alias ready)${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-cli) ${_CLR_DIM}Run CLI commands (e.g., clawdock-cli status)${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-exec) ${_CLR_CYAN}<cmd>${_CLR_RESET} ${_CLR_DIM}Execute command in gateway container${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_MAGENTA}π Web UI & Devices${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-dashboard) ${_CLR_DIM}Open web UI in browser ${_CLR_CYAN}(auto-guides you)${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-devices) ${_CLR_DIM}List device pairings ${_CLR_CYAN}(auto-guides you)${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-approve) ${_CLR_CYAN}<id>${_CLR_RESET} ${_CLR_DIM}Approve device pairing ${_CLR_CYAN}(with examples)${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_MAGENTA}βοΈ Setup & Configuration${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-fix-token) ${_CLR_DIM}Configure gateway token ${_CLR_CYAN}(run once)${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_MAGENTA}π§ Maintenance${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-rebuild) ${_CLR_DIM}Rebuild Docker image${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-clean) ${_CLR_RED}β οΈ Remove containers & volumes (nuclear)${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_MAGENTA}π οΈ Utilities${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-health) ${_CLR_DIM}Run health check${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-token) ${_CLR_DIM}Show gateway auth token${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-cd) ${_CLR_DIM}Jump to openclaw project directory${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-config) ${_CLR_DIM}Open config directory (~/.openclaw)${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-workspace) ${_CLR_DIM}Open workspace directory${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_CYAN}ββββββββββββββββββββββββββββββββββββββββββββββββββββββ${_CLR_RESET}" |
| echo -e "${_CLR_BOLD}${_CLR_GREEN}π First Time Setup${_CLR_RESET}" |
| echo -e "${_CLR_CYAN} 1.${_CLR_RESET} $(_cmd clawdock-start) ${_CLR_DIM}# Start the gateway${_CLR_RESET}" |
| echo -e "${_CLR_CYAN} 2.${_CLR_RESET} $(_cmd clawdock-fix-token) ${_CLR_DIM}# Configure token${_CLR_RESET}" |
| echo -e "${_CLR_CYAN} 3.${_CLR_RESET} $(_cmd clawdock-dashboard) ${_CLR_DIM}# Open web UI${_CLR_RESET}" |
| echo -e "${_CLR_CYAN} 4.${_CLR_RESET} $(_cmd clawdock-devices) ${_CLR_DIM}# If pairing needed${_CLR_RESET}" |
| echo -e "${_CLR_CYAN} 5.${_CLR_RESET} $(_cmd clawdock-approve) ${_CLR_CYAN}<id>${_CLR_RESET} ${_CLR_DIM}# Approve pairing${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_GREEN}π¬ WhatsApp Setup${_CLR_RESET}" |
| echo -e " $(_cmd clawdock-shell)" |
| echo -e " ${_CLR_BLUE}>${_CLR_RESET} $(_cmd 'openclaw channels login --channel whatsapp')" |
| echo -e " ${_CLR_BLUE}>${_CLR_RESET} $(_cmd 'openclaw status')" |
| echo "" |
|
|
| echo -e "${_CLR_BOLD}${_CLR_CYAN}ββββββββββββββββββββββββββββββββββββββββββββββββββββββ${_CLR_RESET}" |
| echo "" |
|
|
| echo -e "${_CLR_CYAN}π‘ All commands guide you through next steps!${_CLR_RESET}" |
| echo -e "${_CLR_BLUE}π Docs: ${_CLR_RESET}${_CLR_CYAN}https://docs.openclaw.ai${_CLR_RESET}" |
| echo "" |
| } |
|
|