diff --git a/README.md b/README.md index b4895525..b6d25564 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,17 @@ # Spawn -Automated sprite provisioning scripts for various tools and configurations. +Conjure your agents! ## Usage +### Claude Code Setup + +Setup a sprite with Claude Code pre-configured (via OpenRouter): + +```bash +curl https://openrouter.ai/lab/spawn/sprite/claude.sh | bash +``` + ### OpenClaw Setup Setup a sprite with openclaw pre-configured: @@ -11,25 +19,3 @@ Setup a sprite with openclaw pre-configured: ```bash curl https://openrouter.ai/lab/spawn/sprite/openclaw.sh | bash ``` - -This will: -1. Install sprite CLI if not present -2. Login to sprite to get credentials -3. Provision a new sprite with the specified name -4. Add `bun` to PATH -5. Install openclaw using bun -6. Open openrouter.ai/settings/keys to grab an API key -7. Inject API keys (OPENROUTER_API_KEY, ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL) -8. Configure openclaw to bypass initial settings - -## Development - -To test locally: - -```bash -bash sprite/openclaw.sh -``` - -## Deployment - -These scripts are served from `openrouter.ai/lab/spawn/*` via Next.js rewrites configured in `openrouter-web/projects/web/next.config.mjs`. diff --git a/sprite/.claude/rules/index.md b/sprite/.claude/rules/index.md new file mode 100644 index 00000000..196cd37b --- /dev/null +++ b/sprite/.claude/rules/index.md @@ -0,0 +1,79 @@ +--- +globs: sprite/** +--- + +# Sprite CLI Rules + +When building bash scripts that use the Sprite CLI, always follow these guidelines. + +## Documentation Reference + +Always consult the latest [Sprite CLI documentation](https://docs.sprites.dev/cli/commands/) before writing commands. + +## Key Commands + +| Command | Purpose | +|---------|---------| +| `sprite login` | Authenticate with Sprites | +| `sprite create ` | Create a new sprite | +| `sprite list` / `sprite ls` | List available sprites | +| `sprite exec -s -- ` | Execute command on sprite (non-interactive) | +| `sprite console -s ` | Connect to sprite interactively | +| `sprite destroy ` | Delete a sprite | +| `sprite checkpoint create` | Create a checkpoint | +| `sprite restore ` | Restore from checkpoint | +| `sprite proxy ` | Forward ports from sprite | + +## Rules + +1. **Use `sprite exec` for non-interactive commands** + - Run installation/setup commands with `sprite exec -s -- bash -c ""` + - Do NOT use `sprite console` for running automated commands + +2. **Use `sprite console` only for interactive sessions** + - Reserve `sprite console` for when user interaction is needed + - Place `sprite console` at the very end of setup scripts + +3. **Always specify sprite with `-s` flag** + - Use `-s ` to target a specific sprite explicitly + - Example: `sprite exec -s my-sprite -- ls -la` + +4. **Check sprite existence before creating** + - Use `sprite list | grep -q ""` to check if a sprite exists + - Only create if it doesn't exist + +5. **Handle login state properly** + - Check `sprite list &> /dev/null` to verify authentication + - Use `sprite login || true` to prevent script exit on login issues + +6. **Global flags** + - `--debug[=]` - Enable debug logging + - `-o, --org ` - Specify organization + - `-s, --sprite ` - Specify sprite + - `-h, --help` - Show help + +## Script Pattern + +```bash +# 1. Check if sprite CLI is installed +if ! command -v sprite &> /dev/null; then + curl -fsSL https://sprites.dev/install.sh | bash + export PATH="$HOME/.local/bin:$PATH" +fi + +# 2. Ensure logged in +if ! sprite list &> /dev/null; then + sprite login || true +fi + +# 3. Create sprite if needed +if ! sprite list | grep -q "$SPRITE_NAME"; then + sprite create "$SPRITE_NAME" +fi + +# 4. Run setup commands via exec +sprite exec -s "$SPRITE_NAME" -- bash -c "echo 'Setting up...'" + +# 5. Connect interactively at the very end +sprite console "$SPRITE_NAME" +``` diff --git a/sprite/claude.sh b/sprite/claude.sh new file mode 100755 index 00000000..c09936c9 --- /dev/null +++ b/sprite/claude.sh @@ -0,0 +1,271 @@ +#!/bin/bash +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo -e "${GREEN}Claude Code on Sprite${NC}" +echo "" + +# Check if sprite is installed, install if not +if ! command -v sprite &> /dev/null; then + echo -e "${YELLOW}Installing sprite CLI...${NC}" + curl -fsSL https://sprites.dev/install.sh | bash + export PATH="$HOME/.local/bin:$PATH" +fi + +# Check if already authenticated +if ! sprite org list &> /dev/null; then + echo -e "${YELLOW}Logging in to sprite...${NC}" + sprite login || true +fi + +# Ensure user provides a sprite name +read -p "Enter sprite name: " SPRITE_NAME < /dev/tty + +# Check if sprite exists, create if not +if sprite list 2>/dev/null | grep -q "^${SPRITE_NAME}$\|^${SPRITE_NAME} "; then + echo -e "${GREEN}Sprite '$SPRITE_NAME' already exists${NC}" +else + echo -e "${YELLOW}Creating sprite '$SPRITE_NAME'...${NC}" + sprite create -skip-console "$SPRITE_NAME" || true + echo -e "${YELLOW}Waiting for sprite to be ready...${NC}" + sleep 5 +fi + +# Verify sprite is accessible +echo -e "${YELLOW}Verifying sprite connectivity...${NC}" +if ! sprite exec -s "$SPRITE_NAME" -- echo "ok" >/dev/null 2>&1; then + echo -e "${YELLOW}Sprite not ready, waiting longer...${NC}" + sleep 5 +fi + +echo -e "${YELLOW}Setting up sprite environment...${NC}" + +# Helper function to run commands on sprite +run_sprite() { + sprite exec -s "$SPRITE_NAME" -- bash -c "$1" +} + +# 1. Add bun to PATH in .zshrc and .zprofile +echo -e "${YELLOW}Configuring shell environment...${NC}" + +# Create temp file with path config +PATH_TEMP=$(mktemp) +cat > "$PATH_TEMP" << 'EOF' + +# [spawn:path] +export PATH="$HOME/.bun/bin:/.sprite/languages/bun/bin:$PATH" +EOF + +# Upload and append to shell configs +sprite exec -s "$SPRITE_NAME" -file "$PATH_TEMP:/tmp/path_config" -- bash -c "cat /tmp/path_config >> ~/.zprofile && cat /tmp/path_config >> ~/.zshrc && rm /tmp/path_config" +rm "$PATH_TEMP" + +# Switch bash to zsh +BASH_TEMP=$(mktemp) +cat > "$BASH_TEMP" << 'EOF' +# [spawn:bash] +exec /usr/bin/zsh -l +EOF + +sprite exec -s "$SPRITE_NAME" -file "$BASH_TEMP:/tmp/bash_config" -- bash -c "cat /tmp/bash_config > ~/.bash_profile && cat /tmp/bash_config > ~/.bashrc && rm /tmp/bash_config" +rm "$BASH_TEMP" + +# 2. Install Claude Code using claude install (reinitializes properly) +echo -e "${YELLOW}Installing Claude Code...${NC}" +run_sprite "claude install > /dev/null 2>&1" + +# 3. Get OpenRouter API key via OAuth +echo "" +echo -e "${YELLOW}Authenticating with OpenRouter via OAuth...${NC}" + +CALLBACK_PORT=5180 +CALLBACK_URL="http://localhost:${CALLBACK_PORT}/callback" +AUTH_URL="https://openrouter.ai/auth?callback_url=${CALLBACK_URL}" + +# Create a temporary directory for the OAuth flow +OAUTH_DIR=$(mktemp -d) +CODE_FILE="$OAUTH_DIR/code" + +# Create an inline script that handles the OAuth callback +OAUTH_SCRIPT="$OAUTH_DIR/server.sh" +cat > "$OAUTH_SCRIPT" << 'SERVEREOF' +#!/bin/bash +PORT=$1 +CODE_FILE=$2 + +SUCCESS_HTML='HTTP/1.1 200 OK +Content-Type: text/html +Connection: close + +

Authentication Successful!

You can close this window and return to your terminal.

' + +# Listen for the callback and respond +while true; do + # Create a temp file for this request + REQ_FILE=$(mktemp) + + # Use bash's /dev/tcp to handle the connection (works on macOS and Linux) + exec 3<>/dev/tcp/localhost/$PORT 2>/dev/null || { + # /dev/tcp not available, fall back to nc with response + { echo "$SUCCESS_HTML"; cat; } | nc -l $PORT > "$REQ_FILE" 2>/dev/null + REQUEST=$(head -1 "$REQ_FILE") + rm -f "$REQ_FILE" + + if [[ "$REQUEST" == *"/callback?code="* ]]; then + CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p') + echo "$CODE" > "$CODE_FILE" + exit 0 + fi + continue + } +done +SERVEREOF +chmod +x "$OAUTH_SCRIPT" + +echo -e "${YELLOW}Starting local OAuth server on port ${CALLBACK_PORT}...${NC}" + +# Use a simpler nc approach - pipe response while capturing request +( + SUCCESS_RESPONSE='HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n

Authentication Successful!

You can close this window and return to your terminal.

' + + while true; do + # Listen and capture just the first line of the request, then respond + RESPONSE_FILE=$(mktemp) + echo -e "$SUCCESS_RESPONSE" > "$RESPONSE_FILE" + + REQUEST=$(nc -l "$CALLBACK_PORT" < "$RESPONSE_FILE" 2>/dev/null | head -1) + rm -f "$RESPONSE_FILE" + + if [[ "$REQUEST" == *"/callback?code="* ]]; then + CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p') + echo "$CODE" > "$CODE_FILE" + break + fi + done +) /dev/null; then + open "$AUTH_URL" /dev/null; then + xdg-open "$AUTH_URL" /dev/null || true +wait $SERVER_PID 2>/dev/null || true + +if [[ ! -f "$CODE_FILE" ]]; then + echo -e "${RED}Timed out waiting for OAuth callback${NC}" + rm -rf "$OAUTH_DIR" + exit 1 +fi + +OAUTH_CODE=$(cat "$CODE_FILE") +rm -rf "$OAUTH_DIR" + +# Exchange the code for an API key +echo -e "${YELLOW}Exchanging OAuth code for API key...${NC}" +KEY_RESPONSE=$(curl -s -X POST "https://openrouter.ai/api/v1/auth/keys" \ + -H "Content-Type: application/json" \ + -d "{\"code\": \"$OAUTH_CODE\"}") + +OPENROUTER_API_KEY=$(echo "$KEY_RESPONSE" | grep -o '"key":"[^"]*"' | sed 's/"key":"//;s/"$//') + +if [[ -z "$OPENROUTER_API_KEY" ]]; then + echo -e "${RED}Failed to obtain API key: ${KEY_RESPONSE}${NC}" + exit 1 +fi + +echo -e "${GREEN}Successfully obtained OpenRouter API key!${NC}" + +# 4. Inject environment variables +echo -e "${YELLOW}Setting up environment variables...${NC}" + +# Create temp file with env config +ENV_TEMP=$(mktemp) +cat > "$ENV_TEMP" << EOF + +# [spawn:env] +export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}" +export ANTHROPIC_BASE_URL="https://openrouter.ai/api" +export ANTHROPIC_AUTH_TOKEN="${OPENROUTER_API_KEY}" +export ANTHROPIC_API_KEY="" +export CLAUDE_CODE_SKIP_ONBOARDING="1" +export CLAUDE_CODE_ENABLE_TELEMETRY="0" +EOF + +# Upload and append to zshrc +sprite exec -s "$SPRITE_NAME" -file "$ENV_TEMP:/tmp/env_config" -- bash -c "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +# 5. Setup Claude Code settings to bypass initial setup +echo -e "${YELLOW}Configuring Claude Code...${NC}" + +run_sprite "mkdir -p ~/.claude" + +# Create Claude settings.json via file upload +SETTINGS_TEMP=$(mktemp) +cat > "$SETTINGS_TEMP" << EOF +{ + "theme": "dark", + "editor": "vim", + "env": { + "CLAUDE_CODE_ENABLE_TELEMETRY": "0", + "ANTHROPIC_BASE_URL": "https://openrouter.ai/api", + "ANTHROPIC_AUTH_TOKEN": "${OPENROUTER_API_KEY}" + }, + "permissions": { + "defaultMode": "bypassPermissions", + "dangerouslySkipPermissions": true + } +} +EOF + +sprite exec -s "$SPRITE_NAME" -file "$SETTINGS_TEMP:/tmp/claude_settings" -- bash -c "mv /tmp/claude_settings ~/.claude/settings.json" +rm "$SETTINGS_TEMP" + +# Create ~/.claude.json global state to skip onboarding and trust dialogs +GLOBAL_STATE_TEMP=$(mktemp) +cat > "$GLOBAL_STATE_TEMP" << EOF +{ + "hasCompletedOnboarding": true, + "bypassPermissionsModeAccepted": true +} +EOF + +sprite exec -s "$SPRITE_NAME" -file "$GLOBAL_STATE_TEMP:/tmp/claude_global" -- bash -c "mv /tmp/claude_global ~/.claude.json" +rm "$GLOBAL_STATE_TEMP" + +# Create empty CLAUDE.md to prevent first-run prompts +run_sprite "touch ~/.claude/CLAUDE.md" + +echo "" +echo -e "${GREEN}✅ Sprite setup completed successfully!${NC}" +echo "" + +# Start Claude Code immediately +echo -e "${YELLOW}Starting Claude Code...${NC}" +sleep 1 +clear +sprite exec -s "$SPRITE_NAME" -tty -- zsh -c "source ~/.zshrc && claude" diff --git a/sprite/openclaw.sh b/sprite/openclaw.sh old mode 100644 new mode 100755 index df892638..18ffaa2b --- a/sprite/openclaw.sh +++ b/sprite/openclaw.sh @@ -7,112 +7,251 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color -echo -e "${GREEN}🚀 Spawnor - OpenClaw Sprite Setup${NC}" +echo -e "${GREEN}🚀 Spawn an OpenClaw agent on Sprite${NC}" echo "" -# Check if sprite is installed +# Check if sprite is installed, install if not if ! command -v sprite &> /dev/null; then echo -e "${YELLOW}Installing sprite CLI...${NC}" - curl -fsSL https://fly.io/install.sh | sh - export PATH="$HOME/.fly/bin:$PATH" + curl -fsSL https://sprites.dev/install.sh | bash + export PATH="$HOME/.local/bin:$PATH" fi -# Login to sprite if not already logged in -if ! sprite auth whoami &> /dev/null; then - echo -e "${YELLOW}Please login to sprite:${NC}" - sprite auth login +# Check if already authenticated +if ! sprite org list &> /dev/null; then + echo -e "${YELLOW}Logging in to sprite...${NC}" + sprite login || true fi -# Get sprite name from user -read -p "Enter sprite name: " SPRITE_NAME +# Ensure user provides a sprite name +read -p "Enter sprite name: " SPRITE_NAME < /dev/tty # Check if sprite exists, create if not -if sprite list | grep -q "$SPRITE_NAME"; then +if sprite list | grep -qx "$SPRITE_NAME"; then echo -e "${GREEN}Sprite '$SPRITE_NAME' already exists${NC}" else echo -e "${YELLOW}Creating sprite '$SPRITE_NAME'...${NC}" - sprite create "$SPRITE_NAME" + sprite create -skip-console "$SPRITE_NAME" || true + echo -e "${YELLOW}Waiting for sprite to be ready...${NC}" + sleep 3 fi echo -e "${YELLOW}Setting up sprite environment...${NC}" # Helper function to run commands on sprite run_sprite() { - sprite exec "$SPRITE_NAME" -- bash -c "$1" + sprite exec -s "$SPRITE_NAME" -- bash -c "$1" } # 1. Add bun to PATH in .zshrc and .zprofile echo -e "${YELLOW}Configuring shell environment...${NC}" -PATH_CONFIG=' -# [spawnor:path] +# Create temp file with path config +PATH_TEMP=$(mktemp) +cat > "$PATH_TEMP" << 'EOF' + +# [spawn:path] export PATH="$HOME/.bun/bin:/.sprite/languages/bun/bin:$PATH" -' +EOF -# Add to .zprofile for login shells -run_sprite "grep -q '\[spawnor:path\]' ~/.zprofile 2>/dev/null || echo '$PATH_CONFIG' >> ~/.zprofile" - -# Add to .zshrc for interactive shells -run_sprite "grep -q '\[spawnor:path\]' ~/.zshrc 2>/dev/null || echo '$PATH_CONFIG' >> ~/.zshrc" +# Upload and append to shell configs +sprite exec -s "$SPRITE_NAME" -file "$PATH_TEMP:/tmp/path_config" -- bash -c "cat /tmp/path_config >> ~/.zprofile && cat /tmp/path_config >> ~/.zshrc && rm /tmp/path_config" +rm "$PATH_TEMP" # Switch bash to zsh -BASH_CONFIG=' -# [spawnor:bash] +BASH_TEMP=$(mktemp) +cat > "$BASH_TEMP" << 'EOF' +# [spawn:bash] exec /usr/bin/zsh -l -' +EOF -run_sprite "grep -q '\[spawnor:bash\]' ~/.bash_profile 2>/dev/null || echo '$BASH_CONFIG' > ~/.bash_profile" -run_sprite "grep -q '\[spawnor:bash\]' ~/.bashrc 2>/dev/null || echo '$BASH_CONFIG' > ~/.bashrc" +sprite exec -s "$SPRITE_NAME" -file "$BASH_TEMP:/tmp/bash_config" -- bash -c "cat /tmp/bash_config > ~/.bash_profile && cat /tmp/bash_config > ~/.bashrc && rm /tmp/bash_config" +rm "$BASH_TEMP" # 2. Install openclaw using bun echo -e "${YELLOW}Installing openclaw...${NC}" run_sprite "/.sprite/languages/bun/bin/bun install -g openclaw" -# 3. Get OpenRouter API key +# 3. Get OpenRouter API key via OAuth echo "" -echo -e "${YELLOW}Opening openrouter.ai/settings/keys to grab API key...${NC}" -echo -e "${YELLOW}Please copy your API key and paste it below${NC}" +echo -e "${YELLOW}Authenticating with OpenRouter via OAuth...${NC}" -# Try to open the browser +CALLBACK_PORT=5180 +CALLBACK_URL="http://localhost:${CALLBACK_PORT}/callback" +AUTH_URL="https://openrouter.ai/auth?callback_url=${CALLBACK_URL}" + +# Create a temporary directory for the OAuth flow +OAUTH_DIR=$(mktemp -d) +CODE_FILE="$OAUTH_DIR/code" + +# Create an inline script that handles the OAuth callback +OAUTH_SCRIPT="$OAUTH_DIR/server.sh" +cat > "$OAUTH_SCRIPT" << 'SERVEREOF' +#!/bin/bash +PORT=$1 +CODE_FILE=$2 + +SUCCESS_HTML='HTTP/1.1 200 OK +Content-Type: text/html +Connection: close + +

Authentication Successful!

You can close this window and return to your terminal.

' + +# Listen for the callback and respond +while true; do + # Create a temp file for this request + REQ_FILE=$(mktemp) + + # Use bash's /dev/tcp to handle the connection (works on macOS and Linux) + exec 3<>/dev/tcp/localhost/$PORT 2>/dev/null || { + # /dev/tcp not available, fall back to nc with response + { echo "$SUCCESS_HTML"; cat; } | nc -l $PORT > "$REQ_FILE" 2>/dev/null + REQUEST=$(head -1 "$REQ_FILE") + rm -f "$REQ_FILE" + + if [[ "$REQUEST" == *"/callback?code="* ]]; then + CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p') + echo "$CODE" > "$CODE_FILE" + exit 0 + fi + continue + } +done +SERVEREOF +chmod +x "$OAUTH_SCRIPT" + +echo -e "${YELLOW}Starting local OAuth server on port ${CALLBACK_PORT}...${NC}" + +# Use a simpler nc approach - pipe response while capturing request +( + SUCCESS_RESPONSE='HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n

Authentication Successful!

You can close this window and return to your terminal.

' + + while true; do + # Listen and capture just the first line of the request, then respond + RESPONSE_FILE=$(mktemp) + echo -e "$SUCCESS_RESPONSE" > "$RESPONSE_FILE" + + REQUEST=$(nc -l "$CALLBACK_PORT" < "$RESPONSE_FILE" 2>/dev/null | head -1) + rm -f "$RESPONSE_FILE" + + if [[ "$REQUEST" == *"/callback?code="* ]]; then + CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p') + echo "$CODE" > "$CODE_FILE" + break + fi + done +) /dev/null; then - open "https://openrouter.ai/settings/keys" + open "$AUTH_URL" /dev/null; then - xdg-open "https://openrouter.ai/settings/keys" + xdg-open "$AUTH_URL" /dev/null || true +wait $SERVER_PID 2>/dev/null || true + +if [[ ! -f "$CODE_FILE" ]]; then + echo -e "${RED}Timed out waiting for OAuth callback${NC}" + rm -rf "$OAUTH_DIR" + exit 1 +fi + +OAUTH_CODE=$(cat "$CODE_FILE") +rm -rf "$OAUTH_DIR" + +# Exchange the code for an API key +echo -e "${YELLOW}Exchanging OAuth code for API key...${NC}" +KEY_RESPONSE=$(curl -s -X POST "https://openrouter.ai/api/v1/auth/keys" \ + -H "Content-Type: application/json" \ + -d "{\"code\": \"$OAUTH_CODE\"}") + +OPENROUTER_API_KEY=$(echo "$KEY_RESPONSE" | grep -o '"key":"[^"]*"' | sed 's/"key":"//;s/"$//') + +if [[ -z "$OPENROUTER_API_KEY" ]]; then + echo -e "${RED}Failed to obtain API key: ${KEY_RESPONSE}${NC}" + exit 1 +fi + +echo -e "${GREEN}Successfully obtained OpenRouter API key!${NC}" + +# Get model preference echo "" +echo -e "${YELLOW}Browse models at: https://openrouter.ai/models${NC}" +echo -e "${YELLOW}Which model would you like to use?${NC}" +read -p "Enter model ID [openrouter/auto]: " MODEL_ID < /dev/tty +MODEL_ID="${MODEL_ID:-openrouter/auto}" # 4. Inject environment variables echo -e "${YELLOW}Setting up environment variables...${NC}" -ENV_CONFIG=" -# [spawnor:env] -export OPENROUTER_API_KEY=\"$OPENROUTER_API_KEY\" -export ANTHROPIC_API_KEY=\"$OPENROUTER_API_KEY\" -export ANTHROPIC_BASE_URL=\"https://openrouter.ai/api\" -" +# Create temp file with env config +ENV_TEMP=$(mktemp) +cat > "$ENV_TEMP" << EOF -run_sprite "grep -q '\[spawnor:env\]' ~/.zshrc 2>/dev/null || echo '$ENV_CONFIG' >> ~/.zshrc" +# [spawn:env] +export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}" +export ANTHROPIC_API_KEY="${OPENROUTER_API_KEY}" +export ANTHROPIC_BASE_URL="https://openrouter.ai/api" +EOF + +# Upload and append to zshrc +sprite exec -s "$SPRITE_NAME" -file "$ENV_TEMP:/tmp/env_config" -- bash -c "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" # 5. Setup openclaw to bypass initial settings echo -e "${YELLOW}Configuring openclaw...${NC}" -run_sprite "mkdir -p ~/.config/openclaw" +# Remove old config and create fresh +run_sprite "rm -rf ~/.openclaw && mkdir -p ~/.openclaw" + +# Generate a random gateway token +GATEWAY_TOKEN=$(openssl rand -hex 16) OPENCLAW_CONFIG='{ - "hasCompletedOnboarding": true, - "defaultProvider": "openrouter", - "apiKey": "'"$OPENROUTER_API_KEY"'", - "baseUrl": "https://openrouter.ai/api" + "env": { + "OPENROUTER_API_KEY": "'"$OPENROUTER_API_KEY"'" + }, + "gateway": { + "mode": "local", + "auth": { + "token": "'"$GATEWAY_TOKEN"'" + } + }, + "agents": { + "defaults": { + "model": { + "primary": "openrouter/'"$MODEL_ID"'" + } + } + } }' -run_sprite "echo '$OPENCLAW_CONFIG' > ~/.config/openclaw/config.json" +run_sprite "echo '$OPENCLAW_CONFIG' > ~/.openclaw/openclaw.json" echo "" echo -e "${GREEN}✅ Sprite setup completed successfully!${NC}" echo "" -echo -e "Connect to your sprite with: ${YELLOW}sprite console $SPRITE_NAME${NC}" -echo "" + +# Start openclaw gateway in background and run openclaw tui +echo -e "${YELLOW}Starting openclaw...${NC}" +sprite exec -s "$SPRITE_NAME" -- zsh -c "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" +sleep 2 +sprite exec -s "$SPRITE_NAME" -tty -- zsh -c "source ~/.zshrc && openclaw tui"