astrbbbb / scripts /start-with-neo.sh
qa1145's picture
Upload 1245 files
8ede856 verified
#!/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 "$@"