|
| 1 | +#!/usr/bin/env bash |
| 2 | +# ClawOSS Linux container entrypoint. |
| 3 | +# |
| 4 | +# Responsibilities: |
| 5 | +# 1. Validate required env vars (fail fast and loudly — the whole point of |
| 6 | +# Task #5 was that silent failures waste tokens). |
| 7 | +# 2. Link the workspace into $HOME/.openclaw/ the same way setup.sh does on |
| 8 | +# the host. |
| 9 | +# 3. Run scripts/restart.sh in a Linux-aware path so config gets deployed |
| 10 | +# into $HOME/.openclaw/openclaw.json. |
| 11 | +# 4. Exec `openclaw gateway run` as PID 1 so Docker can supervise it. |
| 12 | + |
| 13 | +set -euo pipefail |
| 14 | + |
| 15 | +log() { printf '[clawoss-docker] %s\n' "$*"; } |
| 16 | +fail() { printf '[clawoss-docker][FAIL] %s\n' "$*" >&2; exit 1; } |
| 17 | + |
| 18 | +# ── 0. Required env vars ────────────────────────────────────────────── |
| 19 | +REQUIRED=(GITHUB_TOKEN LLM_API_KEY LLM_PROVIDER LLM_BASE_URL LLM_MODEL_COMPLEX LLM_MODEL_SIMPLE) |
| 20 | +MISSING=() |
| 21 | +for v in "${REQUIRED[@]}"; do |
| 22 | + if [ -z "${!v:-}" ]; then |
| 23 | + MISSING+=("$v") |
| 24 | + fi |
| 25 | +done |
| 26 | +if [ ${#MISSING[@]} -gt 0 ]; then |
| 27 | + fail "missing required env: ${MISSING[*]} (see .env.example)" |
| 28 | +fi |
| 29 | + |
| 30 | +# Optional but strongly recommended — warn, don't fail. |
| 31 | +for v in BUDGET_USD_TOTAL CLAW_API_KEY DASHBOARD_URL; do |
| 32 | + if [ -z "${!v:-}" ]; then |
| 33 | + log "[WARN] $v not set" |
| 34 | + fi |
| 35 | +done |
| 36 | + |
| 37 | +# ── 1. Link workspace ───────────────────────────────────────────────── |
| 38 | +PROJECT_DIR="/app" |
| 39 | +WORKSPACE_DIR="$PROJECT_DIR/workspace" |
| 40 | +OC_DIR="$HOME/.openclaw" |
| 41 | +mkdir -p "$OC_DIR/logs" "$OC_DIR/agents" |
| 42 | + |
| 43 | +if [ ! -L "$OC_DIR/workspace" ]; then |
| 44 | + ln -sfn "$WORKSPACE_DIR" "$OC_DIR/workspace" |
| 45 | + log "linked workspace: $OC_DIR/workspace -> $WORKSPACE_DIR" |
| 46 | +fi |
| 47 | + |
| 48 | +# ── 2. Deploy resolved openclaw.json ────────────────────────────────── |
| 49 | +# Mirrors the sed substitution in scripts/restart.sh. Kept in-entrypoint so |
| 50 | +# the container can come up without invoking the full restart.sh (which also |
| 51 | +# does macOS-specific work like launchd). |
| 52 | +RESOLVED_CONFIG=$(sed \ |
| 53 | + -e "s|__WORKSPACE_PATH__|$WORKSPACE_DIR|g" \ |
| 54 | + -e "s|__PROJECT_DIR__|$PROJECT_DIR|g" \ |
| 55 | + -e "s|__HOME_DIR__|$HOME|g" \ |
| 56 | + -e "s|__LLM_PROVIDER__|${LLM_PROVIDER}|g" \ |
| 57 | + -e "s|__LLM_BASE_URL__|${LLM_BASE_URL}|g" \ |
| 58 | + -e "s|__LLM_MODEL_COMPLEX__|${LLM_MODEL_COMPLEX}|g" \ |
| 59 | + -e "s|__LLM_MODEL_SIMPLE__|${LLM_MODEL_SIMPLE}|g" \ |
| 60 | + -e "s|__INPUT_COST_PER_M_COMPLEX__|${INPUT_COST_PER_M_COMPLEX:-${INPUT_COST_PER_M:-3.0}}|g" \ |
| 61 | + -e "s|__OUTPUT_COST_PER_M_COMPLEX__|${OUTPUT_COST_PER_M_COMPLEX:-${OUTPUT_COST_PER_M:-15.0}}|g" \ |
| 62 | + -e "s|__INPUT_COST_PER_M_SIMPLE__|${INPUT_COST_PER_M_SIMPLE:-${INPUT_COST_PER_M:-3.0}}|g" \ |
| 63 | + -e "s|__OUTPUT_COST_PER_M_SIMPLE__|${OUTPUT_COST_PER_M_SIMPLE:-${OUTPUT_COST_PER_M:-15.0}}|g" \ |
| 64 | + -e "s|__LLM_CONTEXT_WINDOW__|${LLM_CONTEXT_WINDOW:-200000}|g" \ |
| 65 | + -e "s|__LLM_MAX_TOKENS__|${LLM_MAX_TOKENS:-32000}|g" \ |
| 66 | + "$PROJECT_DIR/config/openclaw.json") |
| 67 | + |
| 68 | +# Inject env block (API key + token + budget + pricing) so openclaw has |
| 69 | +# everything it needs to authenticate. |
| 70 | +echo "$RESOLVED_CONFIG" | python3 -c " |
| 71 | +import json, os, sys |
| 72 | +merged = json.load(sys.stdin) |
| 73 | +env = merged.setdefault('env', {}) |
| 74 | +keys = [ |
| 75 | + 'LLM_API_KEY','LLM_BASE_URL','LLM_PROVIDER', |
| 76 | + 'LLM_MODEL_COMPLEX','LLM_MODEL_SIMPLE', |
| 77 | + 'GITHUB_TOKEN','GITHUB_USERNAME','GITHUB_EMAIL', |
| 78 | + 'CLAW_API_KEY','DASHBOARD_URL', |
| 79 | + 'BUDGET_USD_TOTAL','MODEL_TOKEN_BUDGETS', |
| 80 | + 'INPUT_COST_PER_M','OUTPUT_COST_PER_M', |
| 81 | + 'INPUT_COST_PER_M_COMPLEX','OUTPUT_COST_PER_M_COMPLEX', |
| 82 | + 'INPUT_COST_PER_M_SIMPLE','OUTPUT_COST_PER_M_SIMPLE', |
| 83 | +] |
| 84 | +for k in keys: |
| 85 | + v = os.environ.get(k) |
| 86 | + if v: |
| 87 | + env[k] = v |
| 88 | +merged['env'] = env |
| 89 | +json.dump(merged, open('$OC_DIR/openclaw.json','w'), indent=2) |
| 90 | +" |
| 91 | + |
| 92 | +log "deployed $OC_DIR/openclaw.json" |
| 93 | + |
| 94 | +# ── 3. GitHub CLI auth (non-interactive token login) ────────────────── |
| 95 | +if [ -n "${GITHUB_TOKEN:-}" ]; then |
| 96 | + echo "$GITHUB_TOKEN" | gh auth login --with-token >/dev/null 2>&1 || \ |
| 97 | + log "[WARN] gh auth login --with-token failed; gh commands may 401" |
| 98 | +fi |
| 99 | + |
| 100 | +# Git identity — PRs need author info. |
| 101 | +git config --global user.name "${GITHUB_USERNAME:-clawoss-bot}" |
| 102 | +git config --global user.email "${GITHUB_EMAIL:-${GITHUB_USERNAME:-clawoss-bot}@users.noreply.github.com}" |
| 103 | + |
| 104 | +# ── 4. Register agent + hand off to gateway ─────────────────────────── |
| 105 | +AGENT_MODEL="${LLM_PROVIDER}/${LLM_MODEL_SIMPLE}" |
| 106 | +if ! openclaw agents list 2>/dev/null | grep -q "^- clawoss "; then |
| 107 | + openclaw agents add clawoss \ |
| 108 | + --workspace "$WORKSPACE_DIR" \ |
| 109 | + --model "$AGENT_MODEL" \ |
| 110 | + --non-interactive |
| 111 | + log "registered agent clawoss (model=$AGENT_MODEL)" |
| 112 | +fi |
| 113 | + |
| 114 | +log "starting openclaw gateway (foreground)" |
| 115 | +exec openclaw gateway run |
0 commit comments