File size: 10,758 Bytes
8ede856
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#!/usr/bin/env bash
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# start-with-neo.sh โ€” ไธ€้”ฎๅฏๅŠจ Shipyard Neo Bay + AstrBot
#
# Usage:
#   bash scripts/start-with-neo.sh            # ้ป˜่ฎค Bay :8114
#   BAY_PORT=9000 bash scripts/start-with-neo.sh  # ่‡ชๅฎšไน‰็ซฏๅฃ
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
set -euo pipefail

# โ”€โ”€ ่ทฏๅพ„ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ASTRBOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shipyard-neo mono-repo root is one level above AstrBot
NEO_ROOT="$(cd "$ASTRBOT_DIR/.." && pwd)"
BAY_DIR="$NEO_ROOT/pkgs/bay"

BAY_PORT="${BAY_PORT:-8114}"
BAY_HOST="0.0.0.0"
BAY_PID=""
BAY_API_KEY=""  # Populated after Bay starts from credentials.json

# โ”€โ”€ ้ขœ่‰ฒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

log()  { echo -e "${CYAN}[neo]${NC} $*"; }
ok()   { echo -e "${GREEN}[neo]${NC} $*"; }
warn() { echo -e "${YELLOW}[neo]${NC} $*"; }
err()  { echo -e "${RED}[neo]${NC} $*" >&2; }

# โ”€โ”€ ๆธ…็†ๅ‡ฝๆ•ฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
cleanup() {
    log "Shutting down..."
    if [[ -n "$BAY_PID" ]] && kill -0 "$BAY_PID" 2>/dev/null; then
        log "Stopping Bay (PID $BAY_PID)..."
        kill "$BAY_PID" 2>/dev/null || true
        wait "$BAY_PID" 2>/dev/null || true
    fi
    ok "All services stopped."
}
trap cleanup EXIT INT TERM

# โ”€โ”€ ๆฃ€ๆŸฅๅ‰็ฝฎๆกไปถ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
check_prerequisites() {
    log "Checking prerequisites..."

    if [[ ! -d "$BAY_DIR" ]]; then
        err "Bay directory not found: $BAY_DIR"
        err "Expected shipyard-neo mono-repo at: $NEO_ROOT"
        exit 1
    fi

    if ! command -v uv &>/dev/null; then
        err "'uv' is not installed. Please install it first."
        exit 1
    fi

    # Check Docker access (try without sudo first, then with sudo)
    if docker info &>/dev/null 2>&1; then
        ok "Docker is accessible."
    elif sudo docker info &>/dev/null 2>&1; then
        warn "Docker requires sudo. Bay may need socket permissions."
        warn "If Bay fails to connect to Docker, run: sudo chmod 666 /var/run/docker.sock"
    else
        err "Docker is not accessible. Please install Docker or fix permissions."
        exit 1
    fi

    # Check Bay venv
    if [[ ! -d "$BAY_DIR/.venv" ]]; then
        log "Bay venv not found. Running 'uv sync' in $BAY_DIR ..."
        (cd "$BAY_DIR" && uv sync)
    fi

    ok "Prerequisites OK."
}

# โ”€โ”€ ็”Ÿๆˆ Bay config.yaml๏ผˆๅฆ‚ไธๅญ˜ๅœจ๏ผ‰โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
ensure_bay_config() {
    local config_file="$BAY_DIR/config.yaml"

    if [[ -f "$config_file" ]]; then
        ok "Bay config.yaml already exists."
        return
    fi

    log "Generating Bay config.yaml for local development..."

    cat > "$config_file" << 'BAYCONFIG'
# Bay Local Development Config (auto-generated by start-with-neo.sh)
# For full reference see config.yaml.example

server:
  host: "0.0.0.0"
  port: 8114

database:
  url: "sqlite+aiosqlite:///./bay.db"
  echo: false

driver:
  type: docker
  image_pull_policy: if_not_present
  docker:
    socket: "unix:///var/run/docker.sock"
    connect_mode: host_port
    host_address: "127.0.0.1"
    publish_ports: true
    host_port: null
    network: null

cargo:
  root_path: "/var/lib/bay/cargos"
  default_size_limit_mb: 1024
  mount_path: "/workspace"

# Security: auto-provision mode
# Bay generates sk-bay-* key on first boot โ†’ credentials.json
security:
  allow_anonymous: false

profiles:
  - id: python-default
    description: "Standard Python sandbox"
    image: "ghcr.io/astrbotdevs/shipyard-neo-ship:latest"
    runtime_type: ship
    runtime_port: 8123
    resources:
      cpus: 1.0
      memory: "1g"
    capabilities:
      - filesystem
      - shell
      - python
    idle_timeout: 1800
    env: {}

gc:
  enabled: true
  run_on_startup: true
  interval_seconds: 300
  idle_session:
    enabled: true
  expired_sandbox:
    enabled: true
  orphan_cargo:
    enabled: true
  orphan_container:
    enabled: false
BAYCONFIG

    ok "Bay config.yaml created at $config_file"
}

# โ”€โ”€ ๆ‹‰ๅ– Ship ้•œๅƒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
ensure_ship_image() {
    local image="ghcr.io/astrbotdevs/shipyard-neo-ship:latest"
    log "Checking Ship image: $image ..."

    if docker image inspect "$image" &>/dev/null 2>&1 || \
       sudo docker image inspect "$image" &>/dev/null 2>&1; then
        ok "Ship image is available locally."
    else
        log "Pulling Ship image (this may take a while)..."
        if docker pull "$image" 2>/dev/null || sudo docker pull "$image" 2>/dev/null; then
            ok "Ship image pulled successfully."
        else
            warn "Failed to pull Ship image. Bay will try to pull it on first sandbox creation."
        fi
    fi
}

# โ”€โ”€ ๅฏๅŠจ Bay โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
start_bay() {
    log "Starting Bay on :$BAY_PORT ..."

    (cd "$BAY_DIR" && BAY_DATA_DIR="$BAY_DIR" uv run uvicorn app.main:app \
        --host "$BAY_HOST" \
        --port "$BAY_PORT" \
        --reload \
        2>&1 | sed "s/^/  ${CYAN}[bay]${NC} /") &
    BAY_PID=$!

    log "Bay started (PID $BAY_PID), waiting for health check..."

    # Wait for Bay to become healthy
    local max_wait=30
    local waited=0
    while [[ $waited -lt $max_wait ]]; do
        if curl -sf "http://127.0.0.1:$BAY_PORT/health" &>/dev/null; then
            ok "Bay is healthy at http://127.0.0.1:$BAY_PORT"
            return
        fi
        # Check if process is still alive
        if ! kill -0 "$BAY_PID" 2>/dev/null; then
            err "Bay process died unexpectedly. Check the output above."
            exit 1
        fi
        sleep 1
        waited=$((waited + 1))
    done

    err "Bay did not become healthy within ${max_wait}s."
    err "It may still be starting โ€” check http://127.0.0.1:$BAY_PORT/health"
}

# โ”€โ”€ ่ฏปๅ– Bay ่‡ชๅŠจ็”Ÿๆˆ็š„ๅ‡ญ่ฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
read_bay_credentials() {
    local cred_file="$BAY_DIR/credentials.json"

    # Wait briefly for credentials.json to appear (Bay writes it during startup)
    local max_wait=5
    local waited=0
    while [[ $waited -lt $max_wait ]]; do
        if [[ -f "$cred_file" ]]; then
            break
        fi
        sleep 1
        waited=$((waited + 1))
    done

    if [[ -f "$cred_file" ]]; then
        # Extract api_key using python (always available) โ€” no jq dependency
        BAY_API_KEY=$(python3 -c "
import json, sys
try:
    d = json.load(open('$cred_file'))
    print(d.get('api_key', ''))
except Exception:
    print('')
" 2>/dev/null || echo "")

        if [[ -n "$BAY_API_KEY" ]]; then
            ok "Auto-provisioned API key loaded from credentials.json"
        else
            warn "credentials.json found but api_key is empty"
        fi
    else
        warn "credentials.json not found โ€” Bay may be using an existing key or anonymous mode"
        warn "Check Bay logs above for the API key, or look at: $cred_file"
    fi
}

# โ”€โ”€ ๆ‰“ๅฐ AstrBot ้…็ฝฎๆ็คบ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
print_astrbot_config_hint() {
    echo ""
    echo -e "${GREEN}โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${NC}"
    echo -e "${GREEN}  Shipyard Neo Bay is running at http://127.0.0.1:$BAY_PORT ${NC}"
    echo -e "${GREEN}โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${NC}"
    echo ""
    if [[ -n "$BAY_API_KEY" ]]; then
        echo -e "  ${CYAN}Bay API Key (auto-generated):${NC}"
        echo -e "  ${YELLOW}$BAY_API_KEY${NC}"
        echo ""
    fi
    echo -e "  ${CYAN}AstrBot Dashboard ้…็ฝฎๆŒ‡ๅผ•๏ผš${NC}"
    echo -e "  1. AI ้…็ฝฎ โ†’ Agent Computer Use"
    echo -e "     โ€ข Computer Use Runtime โ†’ ${YELLOW}ๆฒ™็ฎฑ${NC}"
    echo -e "     โ€ข ๆฒ™็ฎฑ็Žฏๅขƒ้ฉฑๅŠจๅ™จ        โ†’ ${YELLOW}Shipyard Neo${NC}"
    echo -e "     โ€ข Shipyard Neo API Endpoint โ†’ ${YELLOW}http://127.0.0.1:$BAY_PORT${NC}"
    if [[ -n "$BAY_API_KEY" ]]; then
        echo -e "     โ€ข Shipyard Neo Access Token โ†’ ${YELLOW}$BAY_API_KEY${NC}"
    else
        echo -e "     โ€ข Shipyard Neo Access Token โ†’ ${YELLOW}๏ผˆๆŸฅ็œ‹ Bay ๆ—ฅๅฟ—่Žทๅ– key๏ผ‰${NC}"
    fi
    echo -e "     โ€ข Shipyard Neo Profile     โ†’ ${YELLOW}python-default${NC}"
    echo ""
}

# โ”€โ”€ ๅฏๅŠจ AstrBot โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
start_astrbot() {
    log "Starting AstrBot..."
    cd "$ASTRBOT_DIR"
    uv run main.py
}

# โ”€โ”€ ไธปๆต็จ‹ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
main() {
    echo ""
    echo -e "${CYAN}โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—${NC}"
    echo -e "${CYAN}โ•‘   Shipyard Neo + AstrBot Quick Start    โ•‘${NC}"
    echo -e "${CYAN}โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${NC}"
    echo ""

    check_prerequisites
    ensure_bay_config
    ensure_ship_image
    start_bay
    read_bay_credentials
    print_astrbot_config_hint
    start_astrbot
}

main "$@"