mirror of
https://github.com/trevorsandy/ai-suite.git
synced 2026-10-01 14:05:14 +02:00
OpenClaw refactor native setup with sandbox
This commit is contained in:
Vendored
+11
@@ -20,6 +20,17 @@
|
||||
"program": "${command:SelectScriptName}",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"type": "bashdb",
|
||||
"request": "launch",
|
||||
"name": "Bash-Debug (openclaw_ctl)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/openclaw_ctl",
|
||||
"args": ["--gateway", "--sandbox"],
|
||||
//"args": ["--configuration", "--sandbox"]
|
||||
//"args": ["--onboarding", "--sandbox"]
|
||||
//"args": ["--setenv", "--sandbox"]
|
||||
},
|
||||
{
|
||||
"name": "PowerShell Launch Current File",
|
||||
"type": "PowerShell",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Trevor SANDY
|
||||
# Last Update April, 09 2026
|
||||
# Last Update April, 28 2026
|
||||
# Copyright (C) 2026 by Trevor SANDY
|
||||
#
|
||||
# Auto-configure, with user prompts, self-hosted AI-Suite with Caddy/Nginx proxy and
|
||||
@@ -1874,12 +1874,13 @@ if [[ -f "$openclaw_compose_path" ]]; then
|
||||
# Rebuild OpenClaw services
|
||||
# shellcheck disable=SC2016
|
||||
openclaw_service_yaml='
|
||||
. as $root |
|
||||
{
|
||||
"name": "openclaw",
|
||||
"services": (
|
||||
$root.services
|
||||
| to_entries
|
||||
"name": "openclaw"
|
||||
}
|
||||
+
|
||||
(
|
||||
.services |= (
|
||||
to_entries
|
||||
| map(
|
||||
.value = (
|
||||
{
|
||||
@@ -1897,7 +1898,7 @@ if [[ -f "$openclaw_compose_path" ]]; then
|
||||
)
|
||||
| from_entries
|
||||
)
|
||||
}
|
||||
)
|
||||
'
|
||||
update_yaml_file "$openclaw_service_yaml" "$openclaw_compose_path"
|
||||
fi
|
||||
|
||||
+201
-71
@@ -1,12 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Trevor SANDY
|
||||
# Last Update April, 24 2026
|
||||
# Last Update April, 30 2026
|
||||
# Copyright (C) 2026 by Trevor SANDY
|
||||
#
|
||||
# Change Updates
|
||||
# https://github.com/openclaw/openclaw/blob/main/scripts/docker/setup.sh
|
||||
# 66f4b52 - 28/04/2026
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
: "${APP_NAME:="AI-Suite"}"
|
||||
: "${APP_NAME:='AI-Suite'}"
|
||||
: "${DEBUG_ON:=false}"
|
||||
: "${PLATFORM:='unknown'}"
|
||||
: "${PRIMARY_ARG:=''}"
|
||||
: "${ENV_MODE:=''}"
|
||||
: "${SILENT:=0}"
|
||||
|
||||
# Reset BASH time counter
|
||||
@@ -163,6 +170,11 @@ log_warning() { log WARNING "$*"; }
|
||||
log_debug() { log DEBUG "$*"; }
|
||||
log_info() { log INFO "$*"; }
|
||||
|
||||
fail() {
|
||||
log_critical "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
strip_sgr() {
|
||||
local line sgr=$'\033'
|
||||
while IFS= read -r line; do
|
||||
@@ -204,56 +216,137 @@ finish_elapsed_time() {
|
||||
printf '%s\n' "${INFO} ${GREEN}-------------------------------------------${END}"
|
||||
}
|
||||
|
||||
completion=''
|
||||
# shellcheck disable=SC2329
|
||||
completion='Success!'
|
||||
finish () {
|
||||
local header="${END}✅ ${HEADER}"
|
||||
local action="Set .env"
|
||||
local status="Completed"
|
||||
|
||||
if [ "$completion" == "Success!" ]; then
|
||||
:
|
||||
elif [ "$completion" == "Partial!" ]; then
|
||||
case "$PRIMARY_ARG" in
|
||||
--setenv) : ;;
|
||||
--onboarding) action="Onboarding" ;;
|
||||
--configuration) action="Configuration" ;;
|
||||
--gateway) action="Gateway" ;;
|
||||
*) action="Unknown" ;;
|
||||
esac
|
||||
case "$completion" in
|
||||
Success!) : ;;
|
||||
Partial!)
|
||||
header="${END}⚠️ ${HEADER}"
|
||||
status="Finished"
|
||||
else
|
||||
;;
|
||||
*)
|
||||
header="${END}❌ ${SGR}${BOLD}${UNDERLINE}91m"
|
||||
status="Terminated"
|
||||
fi
|
||||
|
||||
log_info "${header}Configuration $status"
|
||||
;;
|
||||
esac
|
||||
log_info "${header}OpenClaw - $action $status"
|
||||
#-------------------------------------------
|
||||
finish_elapsed_time
|
||||
}
|
||||
|
||||
trap finish EXIT
|
||||
|
||||
########################################
|
||||
# ENVIRONMENT
|
||||
########################################
|
||||
log_info "${HEADER}OpenClaw - Environment"
|
||||
#-------------------------------------------
|
||||
detect_arch() {
|
||||
local -n _ref=$1
|
||||
case $(uname -m) in
|
||||
x86_64) _ref='amd64' ;;
|
||||
aarch64 | arm64) _ref='arm64' ;;
|
||||
armv7l) _ref='arm' ;;
|
||||
i686 | i386) _ref='386' ;;
|
||||
*) _ref='err' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
detect_os() {
|
||||
local -n _ref=$1
|
||||
case $(uname | tr '[:upper:]' '[:lower:]') in
|
||||
linux*) _ref='linux' ;;
|
||||
darwin*) _ref='darwin' ;;
|
||||
*) _ref='err' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
is_wsl() {
|
||||
case "$(uname -r)" in
|
||||
*icrosoft*WSL2 | *icrosoft*wsl2) return ;;
|
||||
*icrosoft) fail "Microsoft WSL1 is not supported. Use WSL2 with 'wsl --set-version <distro> 2'" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
os=''
|
||||
detect_os os
|
||||
case "$os" in
|
||||
linux*)
|
||||
if is_wsl; then
|
||||
PLATFORM="wsl"
|
||||
else
|
||||
PLATFORM="linux"
|
||||
fi
|
||||
;;
|
||||
darwin*) PLATFORM="mac" ;;
|
||||
err) fail "Unsupported platform." ;;
|
||||
esac
|
||||
|
||||
arch=''
|
||||
detect_arch arch
|
||||
if [[ "$arch" == "err" ]]; then fail "Unsupported CPU architecture"; fi
|
||||
|
||||
log_info "${BODY}OS:${END} ${WHITE}$os"
|
||||
log_info "${BODY}PLATFORM:${END} ${WHITE}$PLATFORM"
|
||||
log_info "${BODY}ARCHITECTURE:${END} ${WHITE}$arch"
|
||||
|
||||
########################################
|
||||
# ROOT / CONFIG
|
||||
########################################
|
||||
log_info "${HEADER}ROOT / CONFIG VARIABLES"
|
||||
log_info "${HEADER}OpenClaw - Variables"
|
||||
#-------------------------------------------
|
||||
ROOT_DIR="$(pwd)"
|
||||
OPENCLAW_DIR=""
|
||||
log_info "${BODY}ROOT_DIR:${END} ${WHITE}$ROOT_DIR"
|
||||
OPENCLAW_DIR="$(cd "$ROOT_DIR/openclaw" && pwd)"
|
||||
case "$(basename "$ROOT_DIR")" in
|
||||
openclaw)
|
||||
OPENCLAW_DIR="${ROOT_DIR}"
|
||||
ROOT_DIR="$(cd "$ROOT_DIR/../" && pwd)"
|
||||
;;
|
||||
ai-suite)
|
||||
OPENCLAW_DIR="$(cd "$ROOT_DIR/openclaw" && pwd)"
|
||||
;;
|
||||
*) fail "Must be run from 'openclaw' or 'ai-suite'." ;;
|
||||
esac
|
||||
log_info "${BODY}OPENCLAW_DIR:${END} ${WHITE}$OPENCLAW_DIR"
|
||||
# shellcheck disable=SC1091
|
||||
source "$OPENCLAW_DIR/scripts/lib/docker-build.sh"
|
||||
|
||||
COMPOSE_FILE="$OPENCLAW_DIR/docker-compose.yml"
|
||||
EXTRA_COMPOSE_FILE="$OPENCLAW_DIR/docker-compose.extra.yml"
|
||||
SANDBOX_COMPOSE_FILE="$OPENCLAW_DIR/docker-compose.sandbox.yml"
|
||||
PRIVATE_COMPOSE_FILE="$ROOT_DIR/docker-compose.override.private.yml"
|
||||
PUBLIC_COMPOSE_FILE="$ROOT_DIR/docker-compose.override.public.yml"
|
||||
#PRIVATE_COMPOSE_FILE="$ROOT_DIR/docker-compose.override.private.yml"
|
||||
#PUBLIC_COMPOSE_FILE="$ROOT_DIR/docker-compose.override.public.yml"
|
||||
|
||||
IMAGE_NAME="${OPENCLAW_IMAGE:-ghcr.io/openclaw/openclaw:latest}"
|
||||
EXTRA_MOUNTS="${OPENCLAW_EXTRA_MOUNTS:-}"
|
||||
HOME_VOLUME_NAME="${OPENCLAW_HOME_VOLUME:-}"
|
||||
DOCKER_SOCKET_PATH="${OPENCLAW_DOCKER_SOCKET:-}"
|
||||
ENV_FILE="$OPENCLAW_DIR/.env"
|
||||
BUILD="${BUILD:-}"
|
||||
TIMEZONE="${OPENCLAW_TZ:-}"
|
||||
PERMISSIONS="${PERMISSIONS:-}"
|
||||
|
||||
OPENCLAW_CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}"
|
||||
OPENCLAW_WORKSPACE_DIR="${OPENCLAW_WORKSPACE_DIR:-$HOME/.openclaw/workspace}"
|
||||
HOME_DIR="$HOME"
|
||||
[[ "$PLATFORM" == "wsl" ]] && \
|
||||
HOME_DIR="$(wslpath "$(cmd.exe /c "<nul set /p=%USERPROFILE%" 2>/dev/null)")"
|
||||
OPENCLAW_CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME_DIR/.openclaw}"
|
||||
log_info "${BODY}OPENCLAW_CONFIG_DIR:${END} ${WHITE}$OPENCLAW_CONFIG_DIR"
|
||||
OPENCLAW_WORKSPACE_DIR="${OPENCLAW_WORKSPACE_DIR:-$HOME_DIR/.openclaw/workspace}"
|
||||
log_info "${BODY}OPENCLAW_WORKSPACE_DIR:${END} ${WHITE}$OPENCLAW_WORKSPACE_DIR"
|
||||
OPENCLAW_GATEWAY_PORT="${OPENCLAW_GATEWAY_PORT:-18789}"
|
||||
OPENCLAW_GATEWAY_BIND="${OPENCLAW_GATEWAY_BIND:-lan}"
|
||||
|
||||
OPENCLAW_DOCKER_GID=""
|
||||
OPENCLAW_INSTALL_DOCKER_CLI=""
|
||||
@@ -262,18 +355,17 @@ OPENCLAW_INSTALL_DOCKER_CLI=""
|
||||
# ARGUMENT PARSING (single primary arg)
|
||||
########################################
|
||||
|
||||
PRIMARY_ARG=""
|
||||
if [[ $# -gt 0 ]]; then
|
||||
log_info "${header}Parse Arguments"
|
||||
log_info "${HEADER}OpenClaw - Arguments"
|
||||
#-------------------------------------------
|
||||
PRIMARY_ARG="$1"
|
||||
log_info "${BODY}Primary Argument:${END} ${WHITE}$PRIMARY_ARG"
|
||||
shift || true
|
||||
fi
|
||||
|
||||
ENV_MODE=""
|
||||
case "$PRIMARY_ARG" in
|
||||
--setenv) ENV_MODE="1" ;;
|
||||
--onboarding|--configuration|--gateway) ;;
|
||||
--onboarding|--configuration|--gateway) : ;;
|
||||
*) echo -e "${ERROR} ${RED}Unknown primary argument.${END}" >&2 ;;
|
||||
esac
|
||||
|
||||
@@ -282,17 +374,16 @@ SANDBOX_ENABLED="${OPENCLAW_SANDBOX:-0}"
|
||||
ENVIRONMENT="${ENVIRONMENT:-private}"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--build) BUILD="1" ;;
|
||||
--debug) DEBUG_ON="true" ;;
|
||||
--sandbox) OPENCLAW_SANDBOX="1" ;;
|
||||
--environment)
|
||||
shift
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo -e "${WARNING} ${YELLOW}--environment option requires 'public/private' argument.${END}"
|
||||
else
|
||||
ENVIRONMENT="$1"
|
||||
fi
|
||||
;;
|
||||
# --environment)
|
||||
# shift
|
||||
# if [[ $# -eq 0 ]]; then
|
||||
# echo -e "${WARNING} ${YELLOW}--environment option requires 'public/private' argument.${END}"
|
||||
# else
|
||||
# ENVIRONMENT="$1"
|
||||
# fi
|
||||
# ;;
|
||||
*)
|
||||
echo -e "${NOTICE} Extra argument ignored: ${WHITE}$1${END}" >&2
|
||||
;;
|
||||
@@ -304,11 +395,6 @@ done
|
||||
# UTILITIES
|
||||
########################################
|
||||
|
||||
fail() {
|
||||
log_critical "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
fail "Missing dependency: $1"
|
||||
@@ -494,7 +580,9 @@ sync_gateway_config() {
|
||||
fi
|
||||
batch_json+="]"
|
||||
|
||||
run_prestart_cli config set --batch-json "$batch_json" >/dev/null
|
||||
if ! run_prestart_cli config set --batch-json "$batch_json" >/dev/null; then
|
||||
: #fail "Could not complete run configuration"
|
||||
fi
|
||||
log_info "${GREEN}Pinned gateway.mode=local and gateway.bind=${END}${WHITE}$OPENCLAW_GATEWAY_BIND for Docker setup."
|
||||
if [[ -n "$allowed_origin_json" ]]; then
|
||||
if [[ -z "$current_allowed_origins" || "$current_allowed_origins" == "null" || "$current_allowed_origins" == "[]" ]]; then
|
||||
@@ -509,7 +597,7 @@ sync_gateway_config() {
|
||||
|
||||
is_env_mode() {
|
||||
if is_truthy_value "$ENV_MODE"; then
|
||||
log_info "${header}Query Mode"
|
||||
log_info "${HEADER}OpenClaw - Set .env"
|
||||
#-------------------------------------------
|
||||
return 0
|
||||
fi
|
||||
@@ -533,6 +621,7 @@ upsert_env() {
|
||||
for k in "${keys[@]}"; do
|
||||
if [[ "$key" == "$k" ]]; then
|
||||
printf '%s=%s\n' "$k" "${!k-}" >>"$tmp"
|
||||
log_info "${BODY}$k:${END} ${WHITE}${!k-}"
|
||||
seen="$seen$k "
|
||||
replaced=true
|
||||
break
|
||||
@@ -547,21 +636,41 @@ upsert_env() {
|
||||
for k in "${keys[@]}"; do
|
||||
if [[ "$seen" != *" $k "* ]]; then
|
||||
printf '%s=%s\n' "$k" "${!k-}" >>"$tmp"
|
||||
log_info "${BODY}$k:${END} ${WHITE}${!k-}"
|
||||
fi
|
||||
done
|
||||
|
||||
mv "$tmp" "$file"
|
||||
}
|
||||
|
||||
run_create_env() {
|
||||
run_set_env() {
|
||||
export OPENCLAW_CONFIG_DIR
|
||||
export OPENCLAW_WORKSPACE_DIR
|
||||
export OPENCLAW_DISABLE_BONJOUR="${OPENCLAW_DISABLE_BONJOUR:-}"
|
||||
export OPENCLAW_DOCKER_APT_PACKAGES="${OPENCLAW_DOCKER_APT_PACKAGES:-}"
|
||||
export OPENCLAW_EXTENSIONS="${OPENCLAW_EXTENSIONS:-}"
|
||||
export OPENCLAW_EXTRA_MOUNTS="$EXTRA_MOUNTS"
|
||||
export OPENCLAW_HOME_VOLUME="$HOME_VOLUME_NAME"
|
||||
export OPENCLAW_ALLOW_INSECURE_PRIVATE_WS="${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS:-}"
|
||||
export OPENCLAW_SANDBOX="$SANDBOX_ENABLED"
|
||||
export OPENCLAW_DOCKER_SOCKET="$DOCKER_SOCKET_PATH"
|
||||
export OPENCLAW_DOCKER_SETUP=1
|
||||
export OPENCLAW_TZ="$TIMEZONE"
|
||||
export COMPOSE_IGNORE_ORPHANS="${COMPOSE_IGNORE_ORPHANS:-'true'}"
|
||||
export OTEL_EXPORTER_OTLP_ENDPOINT="${OTEL_EXPORTER_OTLP_ENDPOINT:-}"
|
||||
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:-}"
|
||||
export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT="${OTEL_EXPORTER_OTLP_METRICS_ENDPOINT:-}"
|
||||
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="${OTEL_EXPORTER_OTLP_LOGS_ENDPOINT:-}"
|
||||
export OTEL_EXPORTER_OTLP_PROTOCOL="${OTEL_EXPORTER_OTLP_PROTOCOL:-}"
|
||||
export OTEL_SERVICE_NAME="${OTEL_SERVICE_NAME:-}"
|
||||
export OTEL_SEMCONV_STABILITY_OPT_IN="${OTEL_SEMCONV_STABILITY_OPT_IN:-}"
|
||||
export OPENCLAW_OTEL_PRELOADED="${OPENCLAW_OTEL_PRELOADED:-}"
|
||||
|
||||
upsert_env "$ENV_FILE" \
|
||||
OPENCLAW_CONFIG_DIR \
|
||||
OPENCLAW_WORKSPACE_DIR \
|
||||
OPENCLAW_GATEWAY_PORT \
|
||||
OPENCLAW_BRIDGE_PORT \
|
||||
OPENCLAW_GATEWAY_BIND \
|
||||
OPENCLAW_DISABLE_BONJOUR \
|
||||
OPENCLAW_GATEWAY_TOKEN \
|
||||
OPENCLAW_IMAGE \
|
||||
OPENCLAW_EXTRA_MOUNTS \
|
||||
OPENCLAW_HOME_VOLUME \
|
||||
OPENCLAW_DOCKER_APT_PACKAGES \
|
||||
@@ -571,7 +680,17 @@ run_create_env() {
|
||||
OPENCLAW_DOCKER_GID \
|
||||
OPENCLAW_INSTALL_DOCKER_CLI \
|
||||
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS \
|
||||
OPENCLAW_TZ
|
||||
OPENCLAW_TZ \
|
||||
COMPOSE_IGNORE_ORPHANS \
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT \
|
||||
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT \
|
||||
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT \
|
||||
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT \
|
||||
OTEL_EXPORTER_OTLP_PROTOCOL \
|
||||
OTEL_SERVICE_NAME \
|
||||
OTEL_SEMCONV_STABILITY_OPT_IN \
|
||||
OPENCLAW_OTEL_PRELOADED
|
||||
completion='Success!'
|
||||
}
|
||||
|
||||
########################################
|
||||
@@ -581,7 +700,7 @@ run_create_env() {
|
||||
# Dockerfile uses BuildKit-only syntax (RUN --mount=type=cache). Force
|
||||
# BuildKit so hosts defaulting to the legacy builder do not fail.
|
||||
run_docker_build() {
|
||||
DOCKER_BUILDKIT=1 docker build "$@"
|
||||
docker_build_exec "$@"
|
||||
}
|
||||
|
||||
run_prestart_gateway() {
|
||||
@@ -621,30 +740,44 @@ run_runtime_cli() {
|
||||
}
|
||||
|
||||
run_onboarding() {
|
||||
fix_permissions
|
||||
if ! fix_permissions; then
|
||||
log_error "Could not fix permissions for run onboarding."
|
||||
fi
|
||||
log_info ""
|
||||
log_info "${BLUE}==>${END} ${GREEN}Onboarding (interactive)"
|
||||
log_info "Docker setup pins Gateway mode to local."
|
||||
log_info "Gateway runtime bind comes from OPENCLAW_GATEWAY_BIND (default: lan)."
|
||||
log_info "Current runtime bind: $OPENCLAW_GATEWAY_BIND"
|
||||
log_info "Gateway token: $OPENCLAW_GATEWAY_TOKEN"
|
||||
log_info "Tailscale exposure: Off (use host-level tailnet/Tailscale setup separately)."
|
||||
log_info "Install Gateway daemon: No (managed by Docker Compose)"
|
||||
log_info "${GREEN}Docker setup pins Gateway mode to local."
|
||||
log_info "${GREEN}Gateway runtime bind comes from OPENCLAW_GATEWAY_BIND (default: lan)."
|
||||
log_info "${GREEN}Current runtime bind:${END} ${WHITE}$OPENCLAW_GATEWAY_BIND"
|
||||
if is_truthy_value "$OPENCLAW_DISABLE_BONJOUR"; then
|
||||
log_info "${GREEN}Bonjour/mDNS advertising:${END} ${WHITE}force disabled (OPENCLAW_DISABLE_BONJOUR=$OPENCLAW_DISABLE_BONJOUR)."
|
||||
elif [[ -z "$OPENCLAW_DISABLE_BONJOUR" ]]; then
|
||||
log_info "${GREEN}Bonjour/mDNS advertising:${END} ${WHITE}auto (disabled inside the Gateway container unless explicitly enabled)."
|
||||
else
|
||||
log_info "${GREEN}Bonjour/mDNS advertising:${END} ${WHITE}explicitly enabled (OPENCLAW_DISABLE_BONJOUR=$OPENCLAW_DISABLE_BONJOUR)."
|
||||
fi
|
||||
log_info "${GREEN}Gateway token:${END} ${WHITE}$OPENCLAW_GATEWAY_TOKEN"
|
||||
log_info "${GREEN}Tailscale exposure:${END} ${WHITE}Off (use host-level tailnet/Tailscale setup separately)."
|
||||
log_info "${GREEN}Install Gateway daemon:${END} ${WHITE}No (managed by Docker Compose)"
|
||||
log_info ""
|
||||
run_prestart_cli onboard --mode local --no-install-daemon
|
||||
}
|
||||
|
||||
run_configuration() {
|
||||
[[ -z "$PERMISSIONS" ]] && \
|
||||
fix_permissions
|
||||
if ! fix_permissions; then
|
||||
log_error "Could not fix permissions for run configuration."
|
||||
fi
|
||||
log_info ""
|
||||
log_info "${BLUE}==>${END} ${GREEN}Docker gateway defaults"
|
||||
sync_gateway_config
|
||||
completion='Success!'
|
||||
}
|
||||
|
||||
run_gateway() {
|
||||
[[ -z "$PERMISSIONS" ]] && \
|
||||
fix_permissions
|
||||
if ! fix_permissions; then
|
||||
log_error "Could not fix permissions for run gateway."
|
||||
fi
|
||||
log_info ""
|
||||
log_info "${BLUE}==>${END} ${GREEN}Provider setup (optional)"
|
||||
log_info "${GREEN}WhatsApp (QR):"
|
||||
@@ -654,17 +787,13 @@ run_gateway() {
|
||||
log_info "${GREEN}Discord (bot token):"
|
||||
log_info " ${WHITE}${COMPOSE_HINT} run --rm openclaw-cli channels add --channel discord --token <token>"
|
||||
log_info "${GREEN}Docs:${END} ${WHITE}https://docs.openclaw.ai/channels"
|
||||
|
||||
log_info ""
|
||||
log_info "${BLUE}==>${END} ${GREEN}Starting gateway"
|
||||
[[ -n "$BUILD" ]] && \
|
||||
COMPOSE_ARGS+=("--build")
|
||||
docker compose "${COMPOSE_ARGS[@]}" up -d openclaw-gateway
|
||||
|
||||
if [[ -n "$SANDBOX_ENABLED" ]]; then
|
||||
enable_sandbox
|
||||
fi
|
||||
|
||||
log_info ""
|
||||
log_info "${GREEN}Gateway running with host port mapping."
|
||||
log_info "${GREEN}Access from tailnet devices via the host's tailnet IP."
|
||||
@@ -675,10 +804,11 @@ run_gateway() {
|
||||
log_info "${GREEN}Commands:"
|
||||
log_info " ${WHITE}${COMPOSE_HINT} logs -f openclaw-gateway"
|
||||
log_info " ${WHITE}${COMPOSE_HINT} exec openclaw-gateway node dist/index.js health --token \"$OPENCLAW_GATEWAY_TOKEN\""
|
||||
completion='Success!'
|
||||
}
|
||||
|
||||
########################################
|
||||
# EXTRA COMPOSE BUILD
|
||||
# EXTRA COMPOSE
|
||||
########################################
|
||||
|
||||
write_extra_compose() {
|
||||
@@ -887,15 +1017,17 @@ if [[ -z "${OPENCLAW_GATEWAY_TOKEN:-}" ]]; then
|
||||
EXISTING_CONFIG_TOKEN="$(read_config_gateway_token || true)"
|
||||
if [[ -n "$EXISTING_CONFIG_TOKEN" ]]; then
|
||||
OPENCLAW_GATEWAY_TOKEN="$EXISTING_CONFIG_TOKEN"
|
||||
log_info "${GREEN}Reusing gateway token from $OPENCLAW_CONFIG_DIR/openclaw.json"
|
||||
log_info "${BODY}Reusing gateway token from:${END} ${WHITE}$OPENCLAW_CONFIG_DIR/openclaw.json"
|
||||
else
|
||||
DOTENV_GATEWAY_TOKEN="$(read_env_gateway_token "$OPENCLAW_DIR/.env" || true)"
|
||||
if [[ -n "$DOTENV_GATEWAY_TOKEN" ]]; then
|
||||
OPENCLAW_GATEWAY_TOKEN="$DOTENV_GATEWAY_TOKEN"
|
||||
log_info "${GREEN}Reusing gateway token from $OPENCLAW_DIR/.env"
|
||||
log_info "${BODY}Reusing gateway token from:${END} ${WHITE}$OPENCLAW_DIR/.env"
|
||||
elif command -v openssl >/dev/null 2>&1; then
|
||||
log_info "${BODY}Generating gateway token from:${END} ${WHITE}openssl rand -hex 32"
|
||||
OPENCLAW_GATEWAY_TOKEN="$(openssl rand -hex 32)"
|
||||
else
|
||||
log_info "${BODY}Generating gateway token from:${END} ${WHITE}Python secrets.token_hex(32)"
|
||||
OPENCLAW_GATEWAY_TOKEN="$(python3 - <<'PY'
|
||||
import secrets
|
||||
print(secrets.token_hex(32))
|
||||
@@ -930,10 +1062,10 @@ if [[ -n "$SANDBOX_ENABLED" ]]; then
|
||||
fi
|
||||
|
||||
if is_env_mode; then
|
||||
run_create_env
|
||||
run_set_env
|
||||
exit 0
|
||||
else
|
||||
log_info "${header}Execution Mode"
|
||||
log_info "${HEADER}OpenClaw - Execution Mode"
|
||||
#-------------------------------------------
|
||||
fi
|
||||
|
||||
@@ -975,14 +1107,12 @@ mkdir -p "$OPENCLAW_CONFIG_DIR/agents/main/agent"
|
||||
mkdir -p "$OPENCLAW_CONFIG_DIR/agents/main/sessions"
|
||||
|
||||
COMPOSE_FILES=("$COMPOSE_FILE")
|
||||
COMPOSE_ARGS=("-p" "ai-suite" "-f" "$COMPOSE_FILE")
|
||||
if [[ "$ENVIRONMENT" == "public" ]]; then
|
||||
COMPOSE_ARGS+=("-f" "$PUBLIC_COMPOSE_FILE")
|
||||
COMPOSE_FILES+=("$PUBLIC_COMPOSE_FILE")
|
||||
else
|
||||
COMPOSE_ARGS+=("-f" "$PRIVATE_COMPOSE_FILE")
|
||||
COMPOSE_FILES+=("$PRIVATE_COMPOSE_FILE")
|
||||
fi
|
||||
COMPOSE_ARGS=("-p" "ai-suite")
|
||||
# if [[ "$ENVIRONMENT" == "public" ]]; then
|
||||
# COMPOSE_FILES+=("$PUBLIC_COMPOSE_FILE")
|
||||
# else
|
||||
# COMPOSE_FILES+=("$PRIVATE_COMPOSE_FILE")
|
||||
# fi
|
||||
|
||||
VALID_MOUNTS=()
|
||||
if [[ -n "$EXTRA_MOUNTS" ]]; then
|
||||
|
||||
+86
-30
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Trevor SANDY
|
||||
Last Update April 17, 2026
|
||||
Last Update April 29, 2026
|
||||
Copyright (c) 2025-Present by Trevor SANDY
|
||||
|
||||
AI-Suite uses this script for the installation command that handles the AI-Suite
|
||||
@@ -314,7 +314,7 @@ LSH.setFormatter(LSHF)
|
||||
LSH.setLevel(logging.NOTSET)
|
||||
|
||||
|
||||
def run_command(cmd, cwd=None):
|
||||
def run_command(cmd, cwd=None, re_raise=None):
|
||||
"""Run a shell command and print it."""
|
||||
raw_msg = " ".join([log_run_cmd, " ".join(cmd)])
|
||||
log.info(raw_msg, extra=LSHF.style(header=log_run_cmd, msg=" ".join(cmd)))
|
||||
@@ -328,6 +328,8 @@ def run_command(cmd, cwd=None):
|
||||
log.error(f"{result.stderr.strip()}")
|
||||
except Exception as e:
|
||||
log.error(f"Exception: {e}.")
|
||||
if re_raise:
|
||||
raise
|
||||
|
||||
def run_pkg_command(cmd):
|
||||
"""Run a package shell command and print it."""
|
||||
@@ -469,6 +471,13 @@ def is_root_user():
|
||||
except (subprocess.CalledProcessError, ValueError):
|
||||
return False
|
||||
|
||||
def to_wsl_path(path: pathlib.Path) -> str:
|
||||
path_str = path.resolve().as_posix()
|
||||
if path.drive:
|
||||
drive = path.drive[0].lower()
|
||||
return f"/mnt/{drive}{path_str[2:]}"
|
||||
return path_str
|
||||
|
||||
def sudo_user():
|
||||
if system == "Windows":
|
||||
if not is_wsl2():
|
||||
@@ -1578,6 +1587,7 @@ def clone_openclaw_repo():
|
||||
git("sparse-checkout", "init", "--cone")
|
||||
git("sparse-checkout", "set",
|
||||
"scripts/docker/setup.sh",
|
||||
"scripts/lib/docker-build.sh",
|
||||
"scripts/clawdock",
|
||||
"docs"
|
||||
)
|
||||
@@ -1682,6 +1692,10 @@ def prepare_openclaw_env(cwd):
|
||||
home_dir = pathlib.Path.home()
|
||||
config_dir = home_dir / ".openclaw"
|
||||
workspace_dir = config_dir / "workspace"
|
||||
if is_wsl2():
|
||||
home_dir = to_wsl_path(home_dir)
|
||||
config_dir = to_wsl_path(config_dir)
|
||||
workspace_dir = to_wsl_path(workspace_dir)
|
||||
gateway_port = 18789
|
||||
bridge_port = 18790
|
||||
gateway_bind = "lan"
|
||||
@@ -1694,12 +1708,16 @@ def prepare_openclaw_env(cwd):
|
||||
output_path=os.path.join(cwd, ".env")
|
||||
add_home_dir = True
|
||||
add_config_dir = True
|
||||
add_config_path = True
|
||||
add_workspace_dir = True
|
||||
add_state_dir = True
|
||||
add_gateway_port = True
|
||||
add_bridge_port = True
|
||||
add_gateway_bind = True
|
||||
add_gateway_token = True
|
||||
add_remote_image = True
|
||||
add_gateway_password = True
|
||||
add_openai_api_key = True
|
||||
add_extra_mounts = True
|
||||
add_home_volume = True
|
||||
add_sandbox = True
|
||||
@@ -1710,58 +1728,65 @@ def prepare_openclaw_env(cwd):
|
||||
sandbox = False
|
||||
update_env = False
|
||||
log.info(f"Writing .env file to {output_path}...")
|
||||
debug_style = LSHF.style(logging.WARNING)
|
||||
try:
|
||||
with open(example_path, "r", newline="\n") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
modified_line = line.strip()
|
||||
if modified_line.startswith("# OPENCLAW_HOME="):
|
||||
add_home_dir = False
|
||||
if modified_line.startswith("# OpenClaw .env example"):
|
||||
modified_lines.append("# OpenClaw .env (from .env.example)\n")
|
||||
elif modified_line.startswith("# 1) Copy this file to `.env`"):
|
||||
modified_lines.append("# 1) Copied to `./openclaw/.env` (for local runs from repo)\n")
|
||||
elif modified_line.startswith("OPENCLAW_HOME="):
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_home_dir = False
|
||||
modified_lines.append(f"OPENCLAW_HOME={home_dir}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("OPENCLAW_CONFIG_DIR="):
|
||||
add_config_dir = False
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_config_dir = False
|
||||
modified_lines.append(f"OPENCLAW_CONFIG_DIR={config_dir}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("OPENCLAW_WORKSPACE_DIR=\n"):
|
||||
add_workspace_dir = False
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_workspace_dir = False
|
||||
modified_lines.append(f"OPENCLAW_WORKSPACE_DIR={workspace_dir}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("OPENCLAW_GATEWAY_PORT="):
|
||||
add_gateway_port = False
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_gateway_port = False
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_PORT={gateway_port}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("OPENCLAW_BRIDGE_PORT="):
|
||||
add_bridge_port = False
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_bridge_port = False
|
||||
modified_lines.append(f"OPENCLAW_BRIDGE_PORT={bridge_port}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("OPENCLAW_GATEWAY_BIND="): # Foo
|
||||
add_gateway_bind = False
|
||||
elif modified_line.startswith("OPENCLAW_GATEWAY_BIND="):
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_gateway_bind = False
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_BIND={gateway_bind}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("OPENCLAW_GATEWAY_TOKEN="):
|
||||
add_gateway_token = False
|
||||
add_gateway_password = False
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_gateway_token = False
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_TOKEN={gateway_token}\n")
|
||||
log.debug(f"OPENCLAW_GATEWAY_TOKEN={elide(gateway_token)}", extra=debug_style)
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("OPENCLAW_IMAGE="):
|
||||
@@ -1771,15 +1796,19 @@ def prepare_openclaw_env(cwd):
|
||||
modified_lines.append(f"OPENCLAW_IMAGE={openclaw_image}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("# OPENCLAW_GATEWAY_PASSWORD="):
|
||||
elif modified_line.startswith("OPENCLAW_GATEWAY_PASSWORD="):
|
||||
add_gateway_token = False
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_gateway_password = False
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_PASSWORD={gateway_password}\n")
|
||||
log.debug(f"OPENCLAW_GATEWAY_PASSWORD={elide(gateway_password)}", extra=debug_style)
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
elif modified_line.startswith("# OPENAI_API_KEY="):
|
||||
elif modified_line.startswith("OPENAI_API_KEY="):
|
||||
key_value = modified_line.split('=', 1)
|
||||
if len(key_value) == 2 and not key_value[1]:
|
||||
add_openai_api_key = False
|
||||
modified_lines.append(f"OPENAI_API_KEY={openapi_key}\n")
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
@@ -1824,12 +1853,15 @@ def prepare_openclaw_env(cwd):
|
||||
if add_remote_image or default_paths:
|
||||
lines = modified_lines
|
||||
modified_lines = []
|
||||
section_header = False
|
||||
for line in lines:
|
||||
modified_line = line.strip()
|
||||
section_header = modified_line.startswith("# ----------------------------")
|
||||
if modified_line.startswith("# ----------------------------"):
|
||||
section_header = True
|
||||
default_path_insert = modified_line.startswith("# Optional path overrides ")
|
||||
auto_configure_settings = modified_line.startswith("# OPENCLAW_HOME=")
|
||||
auto_configure_settings = modified_line.startswith("# Model provider API keys ")
|
||||
if section_header and add_remote_image:
|
||||
section_header = False
|
||||
add_remote_image = False
|
||||
modified_lines.append("# " + "-" * 77 + "\n")
|
||||
modified_lines.append("# Prebuilt Image\n")
|
||||
@@ -1841,19 +1873,35 @@ def prepare_openclaw_env(cwd):
|
||||
elif default_paths and default_path_insert:
|
||||
modified_lines.append("# Default mount paths.\n")
|
||||
if add_config_dir:
|
||||
add_config_path = False
|
||||
modified_lines.append(f"OPENCLAW_CONFIG_DIR={config_dir}\n")
|
||||
if add_workspace_dir:
|
||||
add_state_dir = False
|
||||
modified_lines.append(f"OPENCLAW_WORKSPACE_DIR={workspace_dir}\n")
|
||||
elif add_gateway_password and modified_line.startswith("# OPENCLAW_GATEWAY_PASSWORD="):
|
||||
add_gateway_password = False
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_PASSWORD={gateway_password}\n")
|
||||
log.debug(f"OPENCLAW_GATEWAY_PASSWORD={elide(gateway_password)}", extra=debug_style)
|
||||
elif add_openai_api_key and modified_line.startswith("# OPENAI_API_KEY="):
|
||||
add_openai_api_key = False
|
||||
modified_lines.append(f"OPENAI_API_KEY={openapi_key}\n")
|
||||
elif modified_line.startswith("# OPENCLAW_STATE_DIR="):
|
||||
continue
|
||||
if add_state_dir:
|
||||
modified_lines.append(f"OPENCLAW_STATE_DIR={workspace_dir}\n")
|
||||
else:
|
||||
continue
|
||||
elif modified_line.startswith("# OPENCLAW_CONFIG_PATH="):
|
||||
continue
|
||||
elif auto_configure_settings:
|
||||
modified_lines.append(line)
|
||||
modified_lines.append("\n")
|
||||
if add_config_path:
|
||||
modified_lines.append(f"OPENCLAW_CONFIG_PATH={config_dir}\n")
|
||||
else:
|
||||
continue
|
||||
elif add_home_dir and modified_line.startswith("# OPENCLAW_HOME="):
|
||||
add_home_dir = False
|
||||
modified_lines.append(f"OPENCLAW_HOME={home_dir}\n")
|
||||
elif section_header and auto_configure_settings:
|
||||
section_header = False
|
||||
modified_lines.append("# Auto-configure settings\n")
|
||||
if add_home_dir:
|
||||
modified_lines.append(f"OPENCLAW_HOME={home_dir}\n")
|
||||
modified_lines.append("# " + "-" * 77 + "\n")
|
||||
if add_gateway_port:
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_PORT={gateway_port}\n")
|
||||
if add_bridge_port:
|
||||
@@ -1862,6 +1910,7 @@ def prepare_openclaw_env(cwd):
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_BIND={gateway_bind}\n")
|
||||
if add_gateway_token:
|
||||
modified_lines.append(f"OPENCLAW_GATEWAY_TOKEN={gateway_token}\n")
|
||||
log.debug(f"OPENCLAW_GATEWAY_TOKEN={elide(gateway_token)}", extra=debug_style)
|
||||
if add_extra_mounts:
|
||||
update_env = True
|
||||
modified_lines.append("OPENCLAW_EXTRA_MOUNTS=\n")
|
||||
@@ -1883,8 +1932,15 @@ def prepare_openclaw_env(cwd):
|
||||
if add_timezone:
|
||||
update_env = True
|
||||
modified_lines.append("OPENCLAW_TZ=\n")
|
||||
modified_lines.append("\n")
|
||||
modified_lines.append("# " + "-" * 77 + "\n")
|
||||
modified_lines.append(line)
|
||||
else:
|
||||
modified_lines.append(line)
|
||||
modified_lines.append("\n")
|
||||
modified_lines.append("# " + "-" * 77 + "\n")
|
||||
modified_lines.append("# Additional settings\n")
|
||||
modified_lines.append("# " + "-" * 77 + "\n")
|
||||
with open(output_path, "w", newline="\n") as f:
|
||||
f.writelines(modified_lines)
|
||||
except Exception as e:
|
||||
@@ -1907,8 +1963,6 @@ def prepare_openclaw_env(cwd):
|
||||
f'{oc_script} --setenv {" ".join(cmd_args)}'
|
||||
]
|
||||
run_command(env_cmd)
|
||||
log.info(f".env file created at {output_path}", extra=log_bright)
|
||||
debug_style = LSHF.style(logging.WARNING)
|
||||
log.debug(f"OPENCLAW_IMAGE={openclaw_image}", extra=debug_style)
|
||||
log.debug(f"OPENCLAW_HOME={home_dir}", extra=debug_style)
|
||||
log.debug(f"OPENCLAW_CONFIG_DIR={config_dir}", extra=debug_style)
|
||||
@@ -1916,9 +1970,9 @@ def prepare_openclaw_env(cwd):
|
||||
log.debug(f"OPENCLAW_GATEWAY_PORT={gateway_port}", extra=debug_style)
|
||||
log.debug(f"OPENCLAW_BRIDGE_PORT={bridge_port}", extra=debug_style)
|
||||
log.debug(f"OPENCLAW_GATEWAY_BIND={gateway_bind}", extra=debug_style)
|
||||
log.debug(f"OPENCLAW_GATEWAY_TOKEN={elide(gateway_token)}", extra=debug_style)
|
||||
log.debug(f"OPENCLAW_GATEWAY_PASSWORD={elide(gateway_password)}", extra=debug_style)
|
||||
log.debug(f"OPENAI_API_KEY={openapi_key}", extra=debug_style)
|
||||
log.info(f".env file created at {output_path}", extra=log_bright)
|
||||
|
||||
return True
|
||||
|
||||
def prepare_openclaw_config(cwd, env_vars):
|
||||
@@ -2055,6 +2109,8 @@ def prepare_openclaw_config(cwd, env_vars):
|
||||
backup_path = dst_path.with_name(f"openclaw.json.bak.{timestamp}")
|
||||
log.info(f"Creating backup: {backup_path}")
|
||||
shutil.copy(dst_path, backup_path)
|
||||
dst_dir = pathlib.Path.home() / ".openclaw" / "workspace"
|
||||
dst_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
try:
|
||||
log.info(f"Writing config to {dst_path}")
|
||||
@@ -2329,11 +2385,13 @@ def start_openclaw(
|
||||
if system == 'Windows':
|
||||
convert_line_endings(oc_script)
|
||||
oc_script = oc_script.replace("\\", "/")
|
||||
oc_script = "".join(["./", oc_script])
|
||||
oc_prefix = "../" if cwd else "./"
|
||||
oc_script = "".join([oc_prefix, oc_script])
|
||||
if system == "Windows":
|
||||
cmd = ["wsl", "-e"] + cmd
|
||||
cmd_args = ["--sandbox"]
|
||||
if build:
|
||||
cmd_args.append("--build")
|
||||
if onboard_store['b']:
|
||||
# --- Onboarding + Configuration loop ---
|
||||
onboarding_cmd = cmd + [
|
||||
@@ -2363,8 +2421,6 @@ def start_openclaw(
|
||||
# --- Gateway start ---
|
||||
if environment == "public":
|
||||
cmd_args.extend(["--environment", "public"])
|
||||
if build:
|
||||
cmd.append("--build")
|
||||
gateway_cmd = cmd + [
|
||||
f'{oc_script} --gateway {" ".join(cmd_args)}'
|
||||
]
|
||||
@@ -2420,7 +2476,7 @@ def _openclaw_run_with_retries(
|
||||
attempts = 0
|
||||
while attempts < max_attempts:
|
||||
try:
|
||||
run_command(cmd, cwd=cwd)
|
||||
run_command(cmd, cwd=cwd, re_raise=True)
|
||||
log.info(f"{action_name} completed successfully.")
|
||||
return 0 # success → exit loop
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user