Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 35 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,19 @@ This fork of [opencode-manager](https://github.com/chriswritescode-dev/opencode-
| **E2E Voice Tests** | ✅ Browser + API tests | ❌ Not included |
| **Large Output Fix** | ✅ Context overflow prevention | ❌ Uses official OpenCode |

**Quick Start:**
**Quick Start (one line):**
```bash
# Install globally
bun install -g github:dzianisv/opencode-manager
curl -fsSL https://raw.githubusercontent.com/dzianisv/opencode-manager/main/scripts/setup.sh | bash
```

# Run as system service (auto-starts on boot, includes tunnel)
opencode-manager install-service
This installs Bun, OpenCode, cloudflared, and opencode-manager, then registers it as a system service with a Cloudflare tunnel. Credentials and tunnel URL are printed at the end.

# Or run manually
opencode-manager start
Options: `curl ... | bash -s -- --no-tunnel` (local only) or `--skip-service` (CLI only, no service).

# Access from anywhere via Cloudflare tunnel URL
**Or install manually:**
```bash
bun install -g github:dzianisv/opencode-manager
opencode-manager install-service
cat ~/.local/run/opencode-manager/endpoints.json
```

Expand Down Expand Up @@ -233,7 +234,28 @@ Use `@qa-tester` in OpenCode or run `scripts/qa-test.sh` for quick tests.

## Installation

### Option 1: npm/bun (Recommended for Local Use)
### Option 1: One-Line Setup (Recommended)

Install everything and start as a system service with a single command:

```bash
curl -fsSL https://raw.githubusercontent.com/dzianisv/opencode-manager/main/scripts/setup.sh | bash
```

This automatically installs all prerequisites (Bun, OpenCode, cloudflared), installs opencode-manager, registers it as a system service, and starts a Cloudflare tunnel for remote access. Credentials and tunnel URL are printed at the end.

**Options:**
```bash
# Without Cloudflare tunnel (local access only)
curl -fsSL https://raw.githubusercontent.com/dzianisv/opencode-manager/main/scripts/setup.sh | bash -s -- --no-tunnel

# Install CLI only, don't register as system service
curl -fsSL https://raw.githubusercontent.com/dzianisv/opencode-manager/main/scripts/setup.sh | bash -s -- --skip-service
```

**Supported platforms:** macOS (launchd) and Linux (systemd).

### Option 2: Manual Install (npm/bun)

Install OpenCode Manager as a global CLI tool directly from GitHub:

Expand Down Expand Up @@ -332,7 +354,7 @@ All configuration is stored in `~/.local/run/opencode-manager/`:

On first run, credentials are automatically generated and saved. Use these to authenticate when accessing the web UI.

### Option 2: Docker (Recommended for Servers)
### Option 3: Docker (Recommended for Servers)

```bash
# Simple one-liner
Expand Down Expand Up @@ -417,7 +439,7 @@ OpenCode Manager creates a default `AGENTS.md` file in the workspace config dire

This file is merged with any repository-specific `AGENTS.md` files, with repository instructions taking precedence for their respective codebases.

### Option 3: Azure VM Deployment (Quick Start)
### Option 4: Azure VM Deployment (Quick Start)

Deploy OpenCode Manager to an Azure VM with a single command. Includes automatic HTTPS via Cloudflare tunnel and Basic Auth protection.

Expand Down Expand Up @@ -536,7 +558,7 @@ ssh azureuser@<VM_IP> "sudo docker logs opencode-manager -f"
- Standard_D2s_v5 (2 vCPU, 8GB RAM): ~$70/month
- Use `--destroy` when not in use to avoid charges

### Option 4: Native Local Development (macOS)
### Option 5: Native Local Development (macOS)

Run OpenCode Manager natively on macOS without Docker. This is ideal for development or when you want the web UI to connect to an existing OpenCode instance running in your terminal.

Expand Down Expand Up @@ -791,7 +813,7 @@ bun scripts/start-native.ts --port 3000
bun scripts/start-native.ts --client --port 3000
```

### Option 5: Local Development (Hot Reload)
### Option 6: Local Development (Hot Reload)

```bash
# Clone the repository
Expand Down
227 changes: 227 additions & 0 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
#!/bin/bash
set -e

REPO="dzianisv/opencode-manager"
NO_TUNNEL=false
SKIP_SERVICE=false

for arg in "$@"; do
case "$arg" in
--no-tunnel) NO_TUNNEL=true ;;
--skip-service) SKIP_SERVICE=true ;;
--help|-h)
echo "Usage: curl -fsSL https://raw.githubusercontent.com/$REPO/main/scripts/setup.sh | bash"
echo ""
echo "Options (pass via: curl ... | bash -s -- --no-tunnel):"
echo " --no-tunnel Install without Cloudflare tunnel"
echo " --skip-service Install CLI only, don't register as system service"
echo " -h, --help Show this help"
exit 0
;;
esac
done

info() { echo "==> $*"; }
warn() { echo "WARNING: $*" >&2; }
fail() { echo "ERROR: $*" >&2; exit 1; }

command_exists() { command -v "$1" >/dev/null 2>&1; }

OS="$(uname -s)"
ARCH="$(uname -m)"

case "$OS" in
Darwin) PLATFORM="macOS" ;;
Linux) PLATFORM="Linux" ;;
*) fail "Unsupported OS: $OS. Only macOS and Linux are supported." ;;
esac

info "Setting up OpenCode Manager on $PLATFORM ($ARCH)"
echo ""

# --- Bun ---
if ! command_exists bun; then
info "Installing Bun..."
curl -fsSL https://bun.sh/install | bash
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"
if ! command_exists bun; then
fail "Bun installation failed. Install manually: https://bun.sh"
fi
info "Bun installed: $(bun --version)"
else
info "Bun found: $(bun --version)"
fi

# --- OpenCode ---
if ! command_exists opencode; then
info "Installing OpenCode..."
curl -fsSL https://opencode.ai/install | bash
export PATH="$HOME/.opencode/bin:$PATH"
if ! command_exists opencode; then
warn "OpenCode installation failed. Install manually: https://opencode.ai"
warn "Continuing anyway - you can install it later."
else
info "OpenCode installed: $(opencode version 2>/dev/null || echo 'ok')"
fi
else
info "OpenCode found: $(opencode version 2>/dev/null || echo 'ok')"
fi

# --- cloudflared (optional) ---
if [ "$NO_TUNNEL" = false ]; then
if ! command_exists cloudflared; then
info "Installing cloudflared for Cloudflare tunnel..."
case "$PLATFORM" in
macOS)
if command_exists brew; then
brew install cloudflared
else
warn "Homebrew not found. Install cloudflared manually: brew install cloudflared"
warn "Continuing without tunnel support."
NO_TUNNEL=true
fi
;;
Linux)
if command_exists apt-get; then
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs 2>/dev/null || echo stable) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list >/dev/null
sudo apt-get update -qq && sudo apt-get install -y -qq cloudflared
elif command_exists yum; then
sudo yum install -y cloudflared 2>/dev/null || {
warn "Could not install cloudflared via yum."
warn "Install manually: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/"
NO_TUNNEL=true
}
else
warn "No supported package manager found for cloudflared."
warn "Install manually: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/"
NO_TUNNEL=true
fi
;;
esac
if [ "$NO_TUNNEL" = false ] && command_exists cloudflared; then
info "cloudflared installed: $(cloudflared --version 2>&1 | head -1)"
fi
else
info "cloudflared found: $(cloudflared --version 2>&1 | head -1)"
fi
fi

echo ""

# --- opencode-manager ---
info "Installing opencode-manager..."
bun remove -g opencode-manager 2>/dev/null || true
bun install -g "github:$REPO"

GLOBAL_DIR="$(bun pm ls -g 2>/dev/null | head -1 | sed 's/ .*//' || echo "$HOME/.bun/install/global")"
if [ -d "$GLOBAL_DIR" ]; then
(cd "$GLOBAL_DIR" && bun pm trust opencode-manager 2>/dev/null || true)
fi

if ! command_exists opencode-manager; then
export PATH="$HOME/.bun/bin:$PATH"
if ! command_exists opencode-manager; then
fail "opencode-manager not found in PATH after installation."
fi
fi

info "opencode-manager installed"

# --- Install as service ---
if [ "$SKIP_SERVICE" = true ]; then
echo ""
info "Setup complete (service installation skipped)."
echo ""
echo "Run manually:"
echo " opencode-manager start # Start the server"
echo " opencode-manager start --tunnel # Start with Cloudflare tunnel"
echo " opencode-manager install-service # Install as system service"
exit 0
fi

echo ""
SERVICE_ARGS=""
if [ "$NO_TUNNEL" = true ]; then
SERVICE_ARGS="--no-tunnel"
fi
info "Installing as system service..."
opencode-manager install-service $SERVICE_ARGS

echo ""
info "Waiting for service to start (up to 120s)..."

AUTH_FILE="$HOME/.local/run/opencode-manager/auth.json"
CURL_AUTH=""
if [ -f "$AUTH_FILE" ]; then
CURL_AUTH="-u $(jq -r '"\(.username):\(.password)"' "$AUTH_FILE" 2>/dev/null || true)"
fi

HEALTHY=false
for i in $(seq 1 40); do
if curl -sf $CURL_AUTH http://localhost:5001/api/health 2>/dev/null | grep -q '"status":"healthy"'; then
HEALTHY=true
break
fi
printf "."
sleep 3
done
echo ""

if [ "$HEALTHY" = true ]; then
info "Service is healthy!"
echo ""

ENDPOINTS_FILE="$HOME/.local/run/opencode-manager/endpoints.json"
if [ "$NO_TUNNEL" = false ]; then
info "Waiting for tunnel URL (up to 30s)..."
for j in $(seq 1 10); do
if [ -f "$ENDPOINTS_FILE" ] && jq -e '.endpoints[] | select(.type == "tunnel")' "$ENDPOINTS_FILE" >/dev/null 2>&1; then
TUNNEL_URL=$(jq -r '.endpoints[] | select(.type == "tunnel") | .url' "$ENDPOINTS_FILE" | tail -1)
echo ""
echo "============================================"
echo " OpenCode Manager is ready!"
echo ""
echo " Local: http://localhost:5001"
echo " Tunnel: $TUNNEL_URL"
echo ""
if [ -f "$AUTH_FILE" ]; then
echo " Username: $(jq -r '.username' "$AUTH_FILE")"
echo " Password: $(jq -r '.password' "$AUTH_FILE")"
fi
echo ""
echo " Status: opencode-manager status"
echo " Logs: opencode-manager logs"
echo " Uninstall: opencode-manager uninstall-service"
echo "============================================"
exit 0
fi
printf "."
sleep 3
done
echo ""
warn "Tunnel not available yet. Check later: opencode-manager status"
fi

echo ""
echo "============================================"
echo " OpenCode Manager is ready!"
echo ""
echo " Local: http://localhost:5001"
if [ -f "$AUTH_FILE" ]; then
echo ""
echo " Username: $(jq -r '.username' "$AUTH_FILE")"
echo " Password: $(jq -r '.password' "$AUTH_FILE")"
fi
echo ""
echo " Status: opencode-manager status"
echo " Logs: opencode-manager logs"
echo " Uninstall: opencode-manager uninstall-service"
echo "============================================"
else
warn "Service did not become healthy within 120s."
echo "Check status: opencode-manager status"
echo "Check logs: opencode-manager logs"
exit 1
fi