diff --git a/frontend/app/next.config.ts b/frontend/app/next.config.ts index 7921f35..3c5eef1 100644 --- a/frontend/app/next.config.ts +++ b/frontend/app/next.config.ts @@ -1,7 +1,12 @@ import type { NextConfig } from "next"; +const allowedDevOrigins = (process.env.CLAW_ALLOWED_DEV_ORIGINS ?? "") + .split(",") + .map((origin) => origin.trim()) + .filter(Boolean); + const nextConfig: NextConfig = { - /* config options here */ + allowedDevOrigins, }; export default nextConfig; diff --git a/scripts/start-webui.sh b/scripts/start-webui.sh index bf3f4d3..98be7e2 100755 --- a/scripts/start-webui.sh +++ b/scripts/start-webui.sh @@ -8,7 +8,7 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" RUN_DIR="${ROOT_DIR}/.port_sessions" -BACKEND_HOST="${CLAW_BACKEND_HOST:-127.0.0.1}" +BACKEND_HOST="${CLAW_BACKEND_HOST:-0.0.0.0}" BACKEND_PORT="${CLAW_BACKEND_PORT:-8765}" FRONTEND_HOST="${CLAW_FRONTEND_HOST:-0.0.0.0}" FRONTEND_PORT="${CLAW_FRONTEND_PORT:-3000}" @@ -18,6 +18,15 @@ PYTHON_BIN="${CLAW_PYTHON_BIN:-${ROOT_DIR}/.venv/bin/python}" if [[ ! -x "${PYTHON_BIN}" ]]; then PYTHON_BIN="python3" fi +LOCAL_IPV4_ORIGINS="$(ifconfig 2>/dev/null | awk '/inet / && $2 !~ /^127\\./ {print $2}' | awk '!seen[$0]++' | paste -sd, -)" +DEFAULT_ALLOWED_DEV_ORIGINS="localhost,127.0.0.1,0.0.0.0" +if [[ -n "${LOCAL_IPV4_ORIGINS}" ]]; then + DEFAULT_ALLOWED_DEV_ORIGINS="${DEFAULT_ALLOWED_DEV_ORIGINS},${LOCAL_IPV4_ORIGINS}" + while IFS= read -r local_ip; do + [[ -z "${local_ip}" ]] && continue + DEFAULT_ALLOWED_DEV_ORIGINS="${DEFAULT_ALLOWED_DEV_ORIGINS},${local_ip}:${FRONTEND_PORT}" + done < <(printf "%s\n" "${LOCAL_IPV4_ORIGINS}" | tr "," "\n") +fi mkdir -p "${RUN_DIR}" @@ -87,6 +96,34 @@ wait_for_url() { return 1 } +shell_quote() { + printf "%q" "$1" +} + +start_detached_process() { + local name="$1" + local pid_file="$2" + local log_file="$3" + local work_dir="$4" + shift 4 + local command="cd $(shell_quote "${work_dir}") && echo \$\$ > $(shell_quote "${pid_file}") && exec" + local arg + for arg in "$@"; do + command+=" $(shell_quote "${arg}")" + done + command+=" >$(shell_quote "${log_file}") 2>&1" + + if command -v screen >/dev/null 2>&1; then + screen -dmS "claw-${name}" bash -lc "${command}" + else + ( + cd "${work_dir}" + nohup "$@" >"${log_file}" 2>&1 & + echo "$!" >"${pid_file}" + ) + fi +} + stop_pid_file "${RUN_DIR}/webui-frontend.pid" "frontend" stop_pid_file "${RUN_DIR}/webui-backend.pid" "backend" stop_port_listener "${FRONTEND_PORT}" "frontend" @@ -100,24 +137,23 @@ BACKEND_LOG="${RUN_DIR}/webui-backend.log" FRONTEND_LOG="${RUN_DIR}/webui-frontend.log" echo "Starting backend on ${BACKEND_URL}..." -cd "${ROOT_DIR}" -nohup "${PYTHON_BIN}" -m src.gui \ +start_detached_process "backend" "${RUN_DIR}/webui-backend.pid" "${BACKEND_LOG}" "${ROOT_DIR}" \ + "${PYTHON_BIN}" -m src.gui \ --host "${BACKEND_HOST}" \ --port "${BACKEND_PORT}" \ --cwd "${ROOT_DIR}" \ --session-dir "${RUN_DIR}/agent" \ --allow-write \ --allow-shell \ - --no-browser >"${BACKEND_LOG}" 2>&1 & -echo "$!" >"${RUN_DIR}/webui-backend.pid" + --no-browser wait_for_url "${BACKEND_URL}/api/state" "backend" "${BACKEND_LOG}" echo "Starting frontend on ${FRONTEND_URL}..." -cd "${ROOT_DIR}/frontend/app" export CLAW_API_URL="${BACKEND_URL}" -nohup npm run dev -- --hostname "${FRONTEND_HOST}" --port "${FRONTEND_PORT}" >"${FRONTEND_LOG}" 2>&1 & -echo "$!" >"${RUN_DIR}/webui-frontend.pid" +export CLAW_ALLOWED_DEV_ORIGINS="${CLAW_ALLOWED_DEV_ORIGINS:-${DEFAULT_ALLOWED_DEV_ORIGINS}}" +start_detached_process "frontend" "${RUN_DIR}/webui-frontend.pid" "${FRONTEND_LOG}" "${ROOT_DIR}/frontend/app" \ + npm run dev -- --hostname "${FRONTEND_HOST}" --port "${FRONTEND_PORT}" wait_for_url "${FRONTEND_URL}" "frontend" "${FRONTEND_LOG}"