File size: 4,392 Bytes
5bd2d41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e1f9a64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5bd2d41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env bash
# Boot opencode's headless server for a PaaS (Hugging Face Spaces / Railway).
set -euo pipefail

# Allow `docker run <image> bash` etc. to override the server for debugging.
# PaaS hosts pass no arguments, so the normal path is unaffected.
if [ "$#" -gt 0 ]; then
  exec "$@"
fi

# --- port -------------------------------------------------------------------
# Railway injects $PORT. HF Spaces does not; 7860 must match app_port in README.md.
PORT="${PORT:-7860}"

# --- refuse to run unauthenticated -----------------------------------------
# opencode itself only warns. On a public URL an unauthenticated server means
# anyone can run shell commands and read/write files in this container, so fail
# loudly instead.
if [ -z "${OPENCODE_SERVER_PASSWORD:-}" ]; then
  cat >&2 <<'MSG'
FATAL: OPENCODE_SERVER_PASSWORD is not set.

  Every route on this server allows shell execution and file access, and basic
  auth is the only thing standing in front of it. Set the secret and redeploy:

    Hugging Face  Settings -> Variables and secrets -> New secret
    Railway       Variables -> New Variable

  Log in as $OPENCODE_SERVER_USERNAME (default "opencode") with that password.
MSG
  exit 1
fi

# --- persistence -----------------------------------------------------------
# opencode keeps sessions, provider credentials and its SQLite DB under the XDG
# dirs (packages/core/src/global.ts), so pointing those at a mounted volume is
# what makes state survive a restart.
#   HF Spaces  persistent storage is mounted at /data (paid add-on)
#   Railway    attach a volume with mount path /data
STATE_ROOT="${OPENCODE_STATE_ROOT:-/data}"

if [ -d "$STATE_ROOT" ] && [ -w "$STATE_ROOT" ]; then
  export XDG_DATA_HOME="$STATE_ROOT/share"
  export XDG_STATE_HOME="$STATE_ROOT/state"
  export XDG_CACHE_HOME="$STATE_ROOT/cache"
  export XDG_CONFIG_HOME="$STATE_ROOT/config"
  WORKSPACE="${OPENCODE_WORKSPACE:-$STATE_ROOT/workspace}"
  mkdir -p "$XDG_DATA_HOME" "$XDG_STATE_HOME" "$XDG_CACHE_HOME" "$XDG_CONFIG_HOME"
  echo "persistence: $STATE_ROOT (sessions, logins and code survive restarts)"
else
  WORKSPACE="${OPENCODE_WORKSPACE:-$HOME/workspace}"
  echo "persistence: NONE — $STATE_ROOT is not a writable mount."
  echo "             Sessions, provider logins and uncommitted code are lost on restart."
  echo "             Push to git before you walk away, or attach a volume at $STATE_ROOT."
fi

mkdir -p "$WORKSPACE"
cd "$WORKSPACE"

# Volumes and bind mounts routinely carry a different owner than uid 1000,
# which makes git refuse to touch the repo. Trust what we already control.
git config --global --add safe.directory '*' 2>/dev/null || true

# --- agent instructions ----------------------------------------------------
# opencode reads a global AGENTS.md from its config dir (global.config/AGENTS.md),
# which applies to every session regardless of which directory is open. Install
# the Hugging Face guidance there when a token is actually present, so the
# instructions never advertise a capability the container does not have.
CONFIG_DIR="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}"
if [ -n "${HF_TOKEN:-}" ] && [ -f "$HOME/agents/hf-spaces.md" ]; then
  mkdir -p "$CONFIG_DIR"
  {
    echo "<!-- Generated by entrypoint.sh on boot. Edit agents/hf-spaces.md in the"
    echo "     opencode-cloud repo instead; changes here are overwritten. -->"
    echo
    cat "$HOME/agents/hf-spaces.md"
  } > "$CONFIG_DIR/AGENTS.md"
  echo "hugging face: HF_TOKEN present, \`hf\` CLI available, agent instructions installed"
else
  rm -f "$CONFIG_DIR/AGENTS.md" 2>/dev/null || true
  echo "hugging face: no HF_TOKEN set — agent has no Hugging Face access"
fi

# --- extra CORS origins ----------------------------------------------------
# localhost, *.opencode.ai and the desktop app's oc://renderer are allowed out
# of the box (packages/server/src/cors.ts). Only a frontend you host yourself
# on some other domain needs this.
CORS_ARGS=()
if [ -n "${OPENCODE_CORS_ORIGINS:-}" ]; then
  IFS=',' read -ra origins <<<"$OPENCODE_CORS_ORIGINS"
  for origin in "${origins[@]}"; do
    origin="$(echo "$origin" | xargs)"
    [ -n "$origin" ] && CORS_ARGS+=(--cors "$origin")
  done
fi

echo "opencode $(opencode --version) starting on 0.0.0.0:$PORT (workspace: $WORKSPACE)"
exec opencode serve --hostname 0.0.0.0 --port "$PORT" "${CORS_ARGS[@]}"