forked from openai/euphony
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstart.sh
More file actions
executable file
·143 lines (120 loc) · 4.43 KB
/
start.sh
File metadata and controls
executable file
·143 lines (120 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env bash
set -euo pipefail
# Resolve the repository root from the script location so the script works even
# when it is launched from another directory.
ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
# Resolve the requested run mode up front. The default is a production-style
# local launch that only starts the backend server against the existing `dist/`
# build. Passing `dev` as the first positional argument, or setting MODE=dev,
# switches to the full hot-reload workflow with both backend and frontend.
MODE="${MODE:-${1:-prod}}"
# Allow callers to override the ports without editing the script.
BACKEND_HOST="${BACKEND_HOST:-127.0.0.1}"
BACKEND_PORT="${BACKEND_PORT:-8020}"
FRONTEND_HOST="${FRONTEND_HOST:-127.0.0.1}"
FRONTEND_PORT="${FRONTEND_PORT:-3000}"
BACKEND_PID=""
FRONTEND_PID=""
require_command() {
local command_name="$1"
if ! command -v "${command_name}" >/dev/null 2>&1; then
printf 'Missing required command: %s\n' "${command_name}" >&2
exit 1
fi
}
cleanup() {
# Shut child processes down when the user presses Ctrl+C or when the script
# exits for any other reason. `kill` can fail if a process already stopped,
# so ignore those cases quietly.
if [[ -n "${FRONTEND_PID}" ]]; then
kill "${FRONTEND_PID}" >/dev/null 2>&1 || true
fi
if [[ -n "${BACKEND_PID}" ]]; then
kill "${BACKEND_PID}" >/dev/null 2>&1 || true
fi
}
normalize_mode() {
local value="${1:-prod}"
case "${value}" in
prod|production)
printf 'prod'
;;
dev|development)
printf 'dev'
;;
*)
printf 'Unsupported mode: %s\nExpected one of: prod, dev\n' "${value}" >&2
exit 1
;;
esac
}
wait_for_process_exit() {
local pid="$1"
local label="$2"
local exit_code="0"
if [[ -n "${pid}" ]] && ! kill -0 "${pid}" >/dev/null 2>&1; then
# Capture the child exit status explicitly so `set -e` does not terminate
# the script before we can print which background task stopped.
if wait "${pid}"; then
exit_code="0"
else
exit_code="$?"
fi
printf '\n%s stopped with exit code %s.\n' "${label}" "${exit_code}" >&2
exit "${exit_code}"
fi
}
require_command uv
trap cleanup EXIT INT TERM
cd "${ROOT_DIR}"
MODE="$(normalize_mode "${MODE}")"
# Production mode serves the already-built frontend from FastAPI, so warn
# early if the caller has not built the assets yet. This keeps the default
# startup fast while still making the missing prerequisite obvious.
if [[ "${MODE}" == "prod" ]] && [[ ! -f "${ROOT_DIR}/dist/index.html" ]]; then
printf 'Missing built frontend assets in dist/. Run `npm run build` first or start with `./start.sh dev`.\n' >&2
exit 1
fi
if [[ "${MODE}" == "dev" ]]; then
require_command npm
fi
# Build the uvicorn argument list incrementally so production mode starts a
# plain backend process while development mode adds file watching cleanly.
BACKEND_COMMAND=(
uv run python -m uvicorn fastapi-main:app
--app-dir server
--host "${BACKEND_HOST}"
--port "${BACKEND_PORT}"
)
if [[ "${MODE}" == "dev" ]]; then
BACKEND_COMMAND+=(--reload)
fi
printf 'Starting backend on http://%s:%s\n' "${BACKEND_HOST}" "${BACKEND_PORT}"
"${BACKEND_COMMAND[@]}" &
BACKEND_PID="$!"
if [[ "${MODE}" == "dev" ]]; then
# Pass the backend URL into Vite so the frontend dev server still talks to
# the matching API port when callers override BACKEND_PORT.
printf 'Starting frontend dev server on http://%s:%s\n' "${FRONTEND_HOST}" "${FRONTEND_PORT}"
VITE_EUPHONY_API_URL="http://${BACKEND_HOST}:${BACKEND_PORT}/" \
npm run dev -- --host "${FRONTEND_HOST}" --port "${FRONTEND_PORT}" &
FRONTEND_PID="$!"
fi
printf '\n'
printf 'Mode: %s\n' "${MODE}"
printf 'Euphony backend: http://%s:%s\n' "${BACKEND_HOST}" "${BACKEND_PORT}"
printf 'Codex sessions: http://%s:%s/sessions.html\n' "${BACKEND_HOST}" "${BACKEND_PORT}"
if [[ "${MODE}" == "dev" ]]; then
printf 'Euphony frontend: http://%s:%s\n' "${FRONTEND_HOST}" "${FRONTEND_PORT}"
else
printf 'Euphony frontend: served by backend from `dist/`\n'
fi
printf '\nPress Ctrl+C to stop all started processes.\n\n'
# `wait -n` is unavailable in the older Bash 3.2 that ships with macOS, so use
# a small polling loop that exits as soon as any child process stops. The
# subsequent `wait` call still captures the real exit status of that process.
while true; do
wait_for_process_exit "${BACKEND_PID}" "Backend server"
wait_for_process_exit "${FRONTEND_PID}" "Frontend dev server"
sleep 1
done