#!/usr/bin/env bash set -euo pipefail # Fail fast on broken Space metadata, duplicate templates, or stale cache artifacts. python3 /home/user/app/scripts/preflight.py # ============================================================ # Required non-model settings # ============================================================ : "${CODEWHALE_RUNTIME_TOKEN:?Missing CODEWHALE_RUNTIME_TOKEN secret}" : "${MARINE_API_URL:?Missing MARINE_API_URL variable}" # ============================================================ # Model key # # We do NOT require or use DEEPSEEK_API_KEY. # Prefer the dedicated OpenCode Go secret. # Fall back to OPENAI_API_KEY only if you chose to store the same # OpenCode Go key under that name in Hugging Face. # ============================================================ MODEL_API_KEY="${OPENCODE_GO_API_KEY:-${OPENAI_API_KEY:-}}" if [ -z "${MODEL_API_KEY}" ]; then echo "[startup] ERROR: no OpenCode Go key was injected." echo "[startup] Expected one of: OPENCODE_GO_API_KEY or OPENAI_API_KEY" echo "[startup] Available environment variable names containing KEY/API:" env | cut -d= -f1 | grep -E 'KEY|API' | sort || true exit 1 fi # ============================================================ # Force CodeWhale to OpenCode Go -> GLM-5.3 # ============================================================ export OPENCODE_GO_API_KEY="${MODEL_API_KEY}" export CODEWHALE_PROVIDER="opencode-go" export CODEWHALE_MODEL="glm-5.2" export OPENCODE_GO_MODEL="glm-5.2" unset OPENAI_BASE_URL OPENAI_MODEL CODEWHALE_BASE_URL || true export OPENCODE_GO_BASE_URL="https://opencode.ai/zen/go/v1" # ============================================================ # Web / Runtime # ============================================================ export PORT="${PORT:-7860}" export CODEWHALE_INTERNAL_URL="http://127.0.0.1:7878" export FISHERIES_EXPORT_ROOT="${FISHERIES_EXPORT_ROOT:-/tmp/squid_fisheries_exports}" export HF_FISHERIES_CACHE_ROOT="${HF_FISHERIES_CACHE_ROOT:-/tmp/squid_hf_fisheries_cache}" if [ -z "${PUBLIC_BASE_URL:-}" ] && [ -n "${SPACE_HOST:-}" ]; then export PUBLIC_BASE_URL="https://${SPACE_HOST}" fi # ============================================================ # Build private Marine MCP runtime configuration # ============================================================ RUNTIME_MCP_CONFIG="/tmp/codewhale-marine-mcp.json" export RUNTIME_MCP_CONFIG python3 - <<'PY_MCP_CONFIG' import json import os from pathlib import Path env = { "MARINE_API_URL": os.environ["MARINE_API_URL"], "HF_SQUID_DATASET_REPO": ( os.environ.get("HF_SQUID_DATASET_REPO") or os.environ.get("HF_DATASET_REPO") or "globalsquiddatabase/squid_dataset" ), "HF_TUNA_DATASET_REPO": ( os.environ.get("HF_TUNA_DATASET_REPO") or "globalsquiddatabase/Tuna-Fisheries-Dataset" ), "FISHERIES_EXPORT_ROOT": os.environ.get( "FISHERIES_EXPORT_ROOT", "/tmp/squid_fisheries_exports" ), "HF_FISHERIES_CACHE_ROOT": os.environ.get( "HF_FISHERIES_CACHE_ROOT", "/tmp/squid_hf_fisheries_cache" ), "HF_SQUID_DATASET_REVISION": ( os.environ.get("HF_SQUID_DATASET_REVISION") or os.environ.get("HF_DATASET_REVISION", "") ), "HF_TUNA_DATASET_REVISION": os.environ.get("HF_TUNA_DATASET_REVISION", ""), "PUBLIC_BASE_URL": os.environ.get("PUBLIC_BASE_URL", ""), } hf_token = os.environ.get("HF_TOKEN", "").strip() if hf_token: env["HF_TOKEN"] = hf_token cfg = { "timeouts": { "connect_timeout": 15, "execute_timeout": 900, "read_timeout": 900, }, "servers": { "marine": { "command": "python3", "args": ["/home/user/app/marine_mcp.py"], "disabled": False, "required": False, "env": env, } }, } p = Path(os.environ["RUNTIME_MCP_CONFIG"]) p.write_text( json.dumps(cfg, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", ) p.chmod(0o600) print("[startup] private Marine MCP runtime config ready") PY_MCP_CONFIG # Legacy CodeWhale MCP-config variable name. # This only points to the MCP config file; it does NOT select DeepSeek. export DEEPSEEK_MCP_CONFIG="${RUNTIME_MCP_CONFIG}" # ============================================================ # Startup information # ============================================================ echo "[startup] CodeWhale:" codewhale --version echo "[startup] provider=${CODEWHALE_PROVIDER}" echo "[startup] model=${CODEWHALE_MODEL}" echo "[startup] endpoint=${OPENAI_BASE_URL:-}" echo "[startup] OpenCode Go key present=yes" # ============================================================ # Start CodeWhale Runtime # ============================================================ codewhale app-server --http \ --host 127.0.0.1 \ --port 7878 \ --auth-token "${CODEWHALE_RUNTIME_TOKEN}" & CW_PID=$! trap 'kill "$CW_PID" 2>/dev/null || true' EXIT INT TERM for i in $(seq 1 60); do if curl -fsS --max-time 2 \ http://127.0.0.1:7878/health \ >/dev/null 2>&1; then echo "[startup] private CodeWhale Runtime ready" break fi kill -0 "$CW_PID" 2>/dev/null || { echo "[startup] CodeWhale exited" exit 1 } sleep 1 done # ============================================================ # Marine API health check # ============================================================ curl -fsS --max-time 12 "${MARINE_API_URL%/}/health" || true echo # ============================================================ # Start Squid Agent Web UI # ============================================================ exec uvicorn ui_server:app \ --host 0.0.0.0 \ --port "${PORT}" \ --proxy-headers