im_wower
·
2026-03-29
install-mini.sh
1#!/usr/bin/env bash
2set -euo pipefail
3
4SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
5# shellcheck source=./common.sh
6source "${SCRIPT_DIR}/common.sh"
7
8usage() {
9 cat <<'EOF'
10Usage:
11 scripts/runtime/install-mini.sh [options]
12
13Options:
14 --repo-dir PATH Repo root. Defaults to the current checkout.
15 --home-dir PATH HOME used for LaunchAgents and defaults.
16 --install-dir PATH Override launchd install directory.
17 --shared-token-file PATH Preferred shared token file. Defaults to ~/.config/baa-conductor/shared-token.txt
18 --secrets-env PATH Preferred env fallback used to extract BAA_SHARED_TOKEN.
19 Defaults to ~/.config/baa-conductor/runtime-secrets.env.
20 Falls back to legacy
21 ~/.config/baa-conductor/control-api-worker.secrets.env
22 only if the default file is missing.
23 If the file also defines D1_ACCOUNT_ID,
24 D1_DATABASE_ID, and CLOUDFLARE_API_TOKEN, the
25 conductor LaunchAgent will carry D1 sync config.
26 --with-status-api Also install/restart/check the optional local status-api service.
27 --skip-build Skip pnpm build.
28 --skip-restart Skip launchd restart.
29 --skip-check Skip check-launchd/check-node verification.
30 --help Show this help text.
31
32Notes:
33 This is the single-node mini convenience wrapper. It:
34 1. bootstraps runtime directories
35 2. builds the repo
36 3. installs conductor + codexd LaunchAgents by default
37 4. restarts them
38 5. verifies the node
39 Add --with-status-api when you also want the optional local read-only observer.
40 codexd verification only treats /healthz and /v1/codexd/status as install acceptance;
41 /v1/codexd/runs* and codex exec are not part of the formal runtime contract.
42EOF
43}
44
45require_command awk
46require_command chmod
47require_command curl
48require_command mkdir
49require_command npx
50
51repo_dir="${BAA_RUNTIME_REPO_DIR_DEFAULT}"
52home_dir="$(default_home_dir)"
53install_dir=""
54shared_token_file=""
55secrets_env=""
56skip_build="0"
57skip_restart="0"
58skip_check="0"
59with_status_api="0"
60codexd_api_base="${BAA_RUNTIME_DEFAULT_CODEXD_LOCAL_API}"
61status_api_base="http://100.71.210.78:4318"
62
63while [[ $# -gt 0 ]]; do
64 case "$1" in
65 --repo-dir)
66 repo_dir="$2"
67 shift 2
68 ;;
69 --home-dir)
70 home_dir="$2"
71 shift 2
72 ;;
73 --install-dir)
74 install_dir="$2"
75 shift 2
76 ;;
77 --shared-token-file)
78 shared_token_file="$2"
79 shift 2
80 ;;
81 --secrets-env)
82 secrets_env="$2"
83 shift 2
84 ;;
85 --skip-build)
86 skip_build="1"
87 shift
88 ;;
89 --with-status-api)
90 with_status_api="1"
91 shift
92 ;;
93 --skip-restart)
94 skip_restart="1"
95 shift
96 ;;
97 --skip-check)
98 skip_check="1"
99 shift
100 ;;
101 --help)
102 usage
103 exit 0
104 ;;
105 *)
106 die "Unknown option: $1"
107 ;;
108 esac
109done
110
111if [[ -z "$install_dir" ]]; then
112 install_dir="$(default_install_dir agent "$home_dir")"
113fi
114
115if [[ -z "$shared_token_file" ]]; then
116 shared_token_file="${home_dir}/.config/baa-conductor/shared-token.txt"
117fi
118
119if [[ -z "$secrets_env" ]]; then
120 secrets_env="${home_dir}/.config/baa-conductor/runtime-secrets.env"
121fi
122
123legacy_secrets_env="${home_dir}/.config/baa-conductor/control-api-worker.secrets.env"
124
125prepare_shared_token_file() {
126 local target_path="$1"
127 local env_file="$2"
128 local legacy_env_file="$3"
129 local token=""
130 local candidate_env_file=""
131
132 if [[ -f "$target_path" ]]; then
133 token="$(tr -d '\r\n' <"$target_path")"
134 fi
135
136 if [[ -z "$token" ]]; then
137 for candidate_env_file in "$env_file" "$legacy_env_file"; do
138 if [[ -z "$candidate_env_file" || ! -f "$candidate_env_file" ]]; then
139 continue
140 fi
141
142 token="$(awk -F= '/^BAA_SHARED_TOKEN=/{sub(/^[^=]*=/, ""); print; exit}' "$candidate_env_file")"
143 if [[ -n "$token" ]]; then
144 if [[ "$candidate_env_file" == "$legacy_env_file" ]]; then
145 runtime_log "using legacy secrets env fallback: ${legacy_env_file}"
146 fi
147 break
148 fi
149 done
150 fi
151
152 if [[ -z "$token" ]]; then
153 die "Could not resolve BAA_SHARED_TOKEN. Provide ${target_path}, ${env_file}, or ${legacy_env_file}."
154 fi
155
156 ensure_directory "$(dirname "$target_path")" "700"
157 printf '%s\n' "$token" >"$target_path"
158 chmod 600 "$target_path"
159}
160
161prepare_shared_token_file "$shared_token_file" "$secrets_env" "$legacy_secrets_env"
162
163wait_for_http() {
164 local name="$1"
165 local url="$2"
166 local attempts="${3:-30}"
167 local delay="${4:-1}"
168 local index
169
170 for ((index = 1; index <= attempts; index += 1)); do
171 if curl -fsS "$url" >/dev/null 2>&1; then
172 runtime_log "${name} is ready: ${url}"
173 return 0
174 fi
175
176 sleep "$delay"
177 done
178
179 die "${name} did not become ready in time: ${url}"
180}
181
182run_or_print 0 "${SCRIPT_DIR}/bootstrap.sh" --repo-dir "$repo_dir"
183
184if [[ "$skip_build" != "1" ]]; then
185 (
186 cd "$repo_dir"
187 npx --yes pnpm -r build
188 )
189fi
190
191install_services=(
192 --service conductor
193 --service codexd
194)
195
196if [[ "$with_status_api" == "1" ]]; then
197 install_services+=(--service status-api)
198fi
199
200run_or_print 0 "${SCRIPT_DIR}/install-launchd.sh" \
201 --repo-dir "$repo_dir" \
202 --node mini \
203 "${install_services[@]}" \
204 --install-dir "$install_dir" \
205 --shared-token-file "$shared_token_file" \
206 --d1-secrets-env "$secrets_env" \
207 --local-api-base "http://100.71.210.78:4317" \
208 --local-api-allowed-hosts "100.71.210.78" \
209 --codexd-local-api-base "$codexd_api_base" \
210 --status-api-host "100.71.210.78"
211
212if [[ "$skip_restart" != "1" ]]; then
213 run_or_print 0 "${SCRIPT_DIR}/restart-launchd.sh" \
214 --install-dir "$install_dir" \
215 "${install_services[@]}"
216fi
217
218if [[ "$skip_check" != "1" ]]; then
219 wait_for_http "conductor" "http://100.71.210.78:4317/healthz"
220 wait_for_http "codexd" "${codexd_api_base}/healthz"
221
222 if [[ "$with_status_api" == "1" ]]; then
223 wait_for_http "status-api" "${status_api_base}/healthz"
224 fi
225
226 run_or_print 0 "${SCRIPT_DIR}/check-launchd.sh" \
227 --repo-dir "$repo_dir" \
228 --node mini \
229 "${install_services[@]}" \
230 --install-dir "$install_dir" \
231 --shared-token-file "$shared_token_file" \
232 --d1-secrets-env "$secrets_env" \
233 --local-api-base "http://100.71.210.78:4317" \
234 --local-api-allowed-hosts "100.71.210.78" \
235 --codexd-local-api-base "$codexd_api_base" \
236 --status-api-host "100.71.210.78" \
237 --check-loaded
238
239 run_or_print 0 "${SCRIPT_DIR}/check-node.sh" \
240 --repo-dir "$repo_dir" \
241 --node mini \
242 "${install_services[@]}" \
243 --install-dir "$install_dir" \
244 --shared-token-file "$shared_token_file" \
245 --local-api-base "http://100.71.210.78:4317" \
246 --local-api-allowed-hosts "100.71.210.78" \
247 --codexd-api-base "$codexd_api_base" \
248 --status-api-base "${status_api_base}" \
249 --status-api-host "100.71.210.78" \
250 --expected-rolez leader \
251 --check-loaded
252fi
253
254runtime_log "mini runtime install completed"