Files
th-hotel-simple/scripts/start-local-replay.sh
鲨鱼辣椒 694c4317a3 checkpoint: complete recoverable V2 pre-separation baseline
Complete the selective V2 checkpoint with its minimal AgentBus, object-storage, replay persistence, and validated-workbench shared dependency closure.
2026-08-20 17:09:00 +08:00

110 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repository_root="$(cd "${script_dir}/.." && pwd)"
local_replay_env_file="${repository_root}/.env.local-replay"
if [[ -f "${local_replay_env_file}" ]]; then
set -a
# shellcheck disable=SC1090
source "${local_replay_env_file}"
set +a
echo "Loaded local replay configuration."
fi
server_dir="${repository_root}/server"
client_dir="${repository_root}/client"
server_port="${SERVER_PORT:-8082}"
backend_url="http://127.0.0.1:${server_port}"
frontend_port="${CLIENT_PORT:-5178}"
frontend_url="http://127.0.0.1:${frontend_port}"
replay_hotel_id="${VITE_RESERVATION_HOTEL_ID:-${AUTH_BOOTSTRAP_DEFAULT_HOTEL_ID:-HOTEL-LOCAL-REPLAY}}"
backend_pid=""
frontend_pid=""
# Spring profile reads SERVER_PORT from the process environment. Keep the
# value used by the health check and the value used by Spring Boot identical.
export SERVER_PORT="${server_port}"
cleanup() {
if [[ -n "${frontend_pid}" ]] && kill -0 "${frontend_pid}" 2>/dev/null; then
kill "${frontend_pid}" 2>/dev/null || true
fi
if [[ -n "${backend_pid}" ]] && kill -0 "${backend_pid}" 2>/dev/null; then
kill "${backend_pid}" 2>/dev/null || true
fi
}
trap cleanup EXIT INT TERM
is_health_endpoint_ready() {
local base_url="$1"
local response
response="$(curl --silent --show-error --fail "${base_url}/api/health" 2>/dev/null)" || return 1
[[ "${response}" == *'"status":"UP"'* ]]
}
is_replay_capabilities_endpoint_ready() {
local response
response="$(curl --silent --show-error --fail \
"${frontend_url}/api/system/debug/agentbus-eml-replays/capabilities?hotel_id=${replay_hotel_id}" \
2>/dev/null)" || return 1
[[ "${response}" == *'"replay_enabled":'* ]] \
&& [[ "${response}" == *'"strict_execution_ready":'* ]]
}
if [[ "${START_BOOKING_POSTGRES:-false}" == "true" ]]; then
compose_file="${BOOKING_POSTGRES_COMPOSE_FILE:-${repository_root}/docker-compose.booking-postgres.yml}"
if [[ ! -f "${compose_file}" ]]; then
echo "Booking PostgreSQL compose file not found: ${compose_file}" >&2
exit 66
fi
docker compose -f "${compose_file}" up -d
fi
if [[ "${TH_HOTEL_BOOKING_PG_ENABLED:-false}" == "true" ]]; then
echo "Booking PostgreSQL is enabled; this process will not invent credentials."
else
echo "Booking PostgreSQL is disabled. Strict real-agent execute remains fail-closed until configured."
fi
(
cd "${server_dir}"
exec ./mvnw spring-boot:run -Dspring-boot.run.profiles=local,local-replay
) &
backend_pid=$!
(
cd "${client_dir}"
export VITE_API_PROXY_TARGET="${VITE_API_PROXY_TARGET:-${backend_url}}"
export VITE_ENABLE_BR00_PROTOTYPE="${VITE_ENABLE_BR00_PROTOTYPE:-true}"
export VITE_RESERVATION_HOTEL_ID="${VITE_RESERVATION_HOTEL_ID:-${AUTH_BOOTSTRAP_DEFAULT_HOTEL_ID:-HOTEL-LOCAL-REPLAY}}"
exec pnpm exec vite --host 127.0.0.1 --port "${frontend_port}" --strictPort
) &
frontend_pid=$!
for attempt in $(seq 1 120); do
if ! kill -0 "${backend_pid}" 2>/dev/null; then
echo "Backend exited before /api/health became ready." >&2
exit 1
fi
if ! kill -0 "${frontend_pid}" 2>/dev/null; then
echo "Frontend exited before ${frontend_url} became ready; the requested UI port may already be in use." >&2
exit 1
fi
if is_health_endpoint_ready "${backend_url}" \
&& is_replay_capabilities_endpoint_ready; then
echo "Local replay backend ready: ${backend_url}"
echo "Local replay UI proxy ready: ${frontend_url} -> ${backend_url}"
echo "Fixed identity: LOCAL_TEST_REPLAY_OPERATOR (no saved token; local-replay profile only)"
break
fi
if [[ "${attempt}" == "120" ]]; then
echo "Backend did not become ready within 120 seconds." >&2
exit 1
fi
sleep 1
done
wait "${backend_pid}" "${frontend_pid}"