Skip to content
This repository was archived by the owner on May 6, 2026. It is now read-only.

Commit d96af93

Browse files
author
zhuchangbiaozhu_xyl
committed
Improve Linux installer verification and launch flow
1 parent ea23946 commit d96af93

2 files changed

Lines changed: 246 additions & 50 deletions

File tree

linux/install.sh

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ fi
1919
INSTALLER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
2020
LIB_DIR="$INSTALLER_DIR/lib"
2121
AGENT_PACK_CLONE_ROOT=""
22+
AGENT_PACK_TEMP_ROOT=""
23+
24+
_ap_cleanup() {
25+
if [ -n "$AGENT_PACK_TEMP_ROOT" ] && [ -d "$AGENT_PACK_TEMP_ROOT" ]; then
26+
rm -rf "$AGENT_PACK_TEMP_ROOT"
27+
fi
28+
}
29+
30+
trap _ap_cleanup EXIT
2231

2332
# If running via curl | bash, download the full package first.
2433
# This bootstrap can't read config/defaults.json yet (we haven't fetched it),
@@ -28,6 +37,7 @@ AGENT_PACK_REPO="https://github.com/SenseTime-FVG/agent_pack.git"
2837
if [ ! -d "$LIB_DIR" ]; then
2938
echo "[*] Downloading Agent Pack installer..."
3039
TMPDIR=$(mktemp -d)
40+
AGENT_PACK_TEMP_ROOT="$TMPDIR"
3141
_cloned=0
3242
_bootstrap_try() {
3343
git clone -q --depth 1 "$1" "$TMPDIR/agent-pack" 2>/dev/null
@@ -87,7 +97,8 @@ fi
8797
# install_openclaw can share the same source tree. Runs after CN detection
8898
# so prefetch itself honors mirrors.
8999
if [ -z "$AGENT_PACK_CLONE_ROOT" ]; then
90-
AGENT_PACK_CLONE_ROOT="$(mktemp -d)/agent_pack"
100+
AGENT_PACK_TEMP_ROOT="$(mktemp -d)"
101+
AGENT_PACK_CLONE_ROOT="$AGENT_PACK_TEMP_ROOT/agent_pack"
91102
echo "[*] Pre-fetching agent_pack (shared across product installs)..."
92103
if ! bash "$_AP_SHARED_DIR/prefetch-agent-pack.sh" "$AGENT_PACK_CLONE_ROOT"; then
93104
echo "[!] Failed to pre-fetch agent_pack." >&2
@@ -106,24 +117,26 @@ echo ""
106117
# Ask up front (mirrors the Windows installer wizard) so the user is done
107118
# with interactive prompts before the long-running installs start.
108119
collect_llm_config
120+
verify_llm_config_interactive || exit 1
109121

110122
# ---- Step 2: Product Selection ----
111-
echo ""
112-
echo "Which products would you like to install?"
113-
echo " 1) Hermes Agent"
114-
echo " 2) OpenClaw"
115-
echo " 3) Both"
116-
echo ""
117-
read -rp "Choice [1]: " product_choice
118-
product_choice="${product_choice:-1}"
119-
120123
SELECTED_PRODUCTS=()
121-
case "$product_choice" in
122-
1) SELECTED_PRODUCTS=("hermes") ;;
123-
2) SELECTED_PRODUCTS=("openclaw") ;;
124-
3) SELECTED_PRODUCTS=("hermes" "openclaw") ;;
125-
*) echo "Invalid choice. Defaulting to Hermes Agent."; SELECTED_PRODUCTS=("hermes") ;;
126-
esac
124+
while true; do
125+
echo ""
126+
echo "Which products would you like to install?"
127+
echo " 1) Hermes Agent"
128+
echo " 2) OpenClaw"
129+
echo " 3) Both"
130+
echo ""
131+
read -rp "Choice [1/2/3]: " product_choice
132+
133+
case "$product_choice" in
134+
1) SELECTED_PRODUCTS=("hermes") ; break ;;
135+
2) SELECTED_PRODUCTS=("openclaw") ; break ;;
136+
3) SELECTED_PRODUCTS=("hermes" "openclaw") ; break ;;
137+
*) echo "Please choose 1, 2, or 3." ;;
138+
esac
139+
done
127140

128141
echo ""
129142
echo "Selected: ${SELECTED_PRODUCTS[*]}"
@@ -185,31 +198,89 @@ _ap_augment_path() {
185198
export PATH
186199
}
187200

201+
_ap_resolve_cli() {
202+
local name="$1"
203+
local candidate=""
204+
205+
hash -r 2>/dev/null || true
206+
candidate="$(command -v "$name" 2>/dev/null || true)"
207+
if [ -n "$candidate" ] && [ -x "$candidate" ]; then
208+
printf '%s\n' "$candidate"
209+
return 0
210+
fi
211+
212+
case "$name" in
213+
hermes)
214+
for candidate in \
215+
"$HOME/.local/bin/hermes" \
216+
"$HOME/.hermes/node/bin/hermes" \
217+
"$HERMES_INSTALL_DIR/node/bin/hermes" \
218+
"/usr/local/bin/hermes" \
219+
"/usr/bin/hermes"; do
220+
if [ -n "$candidate" ] && [ -x "$candidate" ]; then
221+
printf '%s\n' "$candidate"
222+
return 0
223+
fi
224+
done
225+
;;
226+
openclaw)
227+
for candidate in \
228+
"$HOME/.local/bin/openclaw" \
229+
"/usr/local/bin/openclaw" \
230+
"/usr/bin/openclaw"; do
231+
if [ -n "$candidate" ] && [ -x "$candidate" ]; then
232+
printf '%s\n' "$candidate"
233+
return 0
234+
fi
235+
done
236+
;;
237+
esac
238+
239+
return 1
240+
}
241+
188242
_ap_schedule_dashboard() {
243+
local openclaw_cli="$1"
189244
# Give the gateway a few seconds to bind before opening the browser
190245
# (dashboard itself doesn't probe, so we sleep for the user's sake).
191-
( sleep 3 && openclaw dashboard >/dev/null 2>&1 ) &
246+
( sleep 3 && "$openclaw_cli" dashboard >/dev/null 2>&1 ) &
192247
disown 2>/dev/null || true
193248
}
194249

195250
_ap_augment_path
196251

252+
_HERMES_CLI="$(_ap_resolve_cli hermes || true)"
253+
_OPENCLAW_CLI="$(_ap_resolve_cli openclaw || true)"
254+
255+
if _ap_has hermes && [ -z "$_HERMES_CLI" ]; then
256+
echo "[!] Hermes was installed but the hermes CLI could not be found." >&2
257+
exit 1
258+
fi
259+
260+
if _ap_has openclaw && [ -z "$_OPENCLAW_CLI" ]; then
261+
echo "[!] OpenClaw was installed but the openclaw CLI could not be found." >&2
262+
exit 1
263+
fi
264+
265+
trap - EXIT
266+
_ap_cleanup
267+
197268
if _ap_has openclaw && _ap_has hermes; then
198269
_openclaw_log="$HOME/.openclaw/gateway.log"
199270
mkdir -p "$(dirname "$_openclaw_log")"
200271
echo "[*] Starting openclaw gateway in the background (log: $_openclaw_log)..."
201-
nohup openclaw gateway --verbose >"$_openclaw_log" 2>&1 &
272+
nohup "$_OPENCLAW_CLI" gateway --verbose >"$_openclaw_log" 2>&1 &
202273
disown 2>/dev/null || true
203-
_ap_schedule_dashboard
274+
_ap_schedule_dashboard "$_OPENCLAW_CLI"
204275
echo "[*] Opening OpenClaw dashboard in your browser shortly..."
205276
echo "[*] Starting hermes in this window..."
206-
exec hermes
277+
exec "$_HERMES_CLI"
207278
elif _ap_has hermes; then
208279
echo "[*] Starting hermes in this window..."
209-
exec hermes
280+
exec "$_HERMES_CLI"
210281
elif _ap_has openclaw; then
211-
_ap_schedule_dashboard
282+
_ap_schedule_dashboard "$_OPENCLAW_CLI"
212283
echo "[*] Opening OpenClaw dashboard in your browser shortly..."
213284
echo "[*] Starting openclaw gateway in this window..."
214-
exec openclaw gateway --verbose
285+
exec "$_OPENCLAW_CLI" gateway --verbose
215286
fi

linux/lib/configure-llm.sh

Lines changed: 152 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -105,42 +105,167 @@ collect_llm_config() {
105105
LLM_API_KEY="$api_key"
106106
}
107107

108-
# Called once per session (first time apply_llm_config_for runs). Tracks
109-
# state so re-calling for a second product doesn't re-verify the same key.
110-
_LLM_VERIFIED_THIS_SESSION=0
111-
_llm_verify_once() {
112-
if [ "$_LLM_VERIFIED_THIS_SESSION" -eq 1 ]; then
113-
return 0
114-
fi
115-
_LLM_VERIFIED_THIS_SESSION=1
108+
_LLM_VERIFY_CMD=()
109+
_llm_prepare_verify_cmd() {
110+
_LLM_VERIFY_CMD=()
116111

117112
if [ "${DISTRO_ID:-}" = "macos" ] && command -v curl &>/dev/null \
118113
&& [ -f "$SHARED_DIR/verify-llm-curl.sh" ]; then
119-
echo "[*] Verifying API connection..."
120-
if bash "$SHARED_DIR/verify-llm-curl.sh" \
121-
--provider "$LLM_PROVIDER" \
122-
--api-key "$LLM_API_KEY" \
123-
--base-url "$LLM_BASE_URL" \
124-
--model "$LLM_MODEL"; then
125-
echo "[OK] Connection verified!"
126-
else
127-
echo "WARNING: Could not verify connection. Saving config anyway."
128-
fi
114+
_LLM_VERIFY_CMD=(
115+
bash "$SHARED_DIR/verify-llm-curl.sh"
116+
--provider "$LLM_PROVIDER"
117+
--api-key "$LLM_API_KEY"
118+
--base-url "$LLM_BASE_URL"
119+
--model "$LLM_MODEL"
120+
)
129121
return 0
130122
fi
131123

132124
local python_cmd="${PYTHON_CMD:-python3}"
133125
if command -v "$python_cmd" &>/dev/null && [ -f "$SHARED_DIR/verify-llm.py" ]; then
134-
echo "[*] Verifying API connection..."
135-
if "$python_cmd" "$SHARED_DIR/verify-llm.py" \
136-
--provider "$LLM_PROVIDER" \
137-
--api-key "$LLM_API_KEY" \
138-
--base-url "$LLM_BASE_URL" \
139-
--model "$LLM_MODEL"; then
140-
echo "[OK] Connection verified!"
141-
else
142-
echo "WARNING: Could not verify connection. Saving config anyway."
126+
_LLM_VERIFY_CMD=(
127+
"$python_cmd" "$SHARED_DIR/verify-llm.py"
128+
--provider "$LLM_PROVIDER"
129+
--api-key "$LLM_API_KEY"
130+
--base-url "$LLM_BASE_URL"
131+
--model "$LLM_MODEL"
132+
)
133+
return 0
134+
fi
135+
136+
if command -v curl &>/dev/null && [ -f "$SHARED_DIR/verify-llm-curl.sh" ]; then
137+
_LLM_VERIFY_CMD=(
138+
bash "$SHARED_DIR/verify-llm-curl.sh"
139+
--provider "$LLM_PROVIDER"
140+
--api-key "$LLM_API_KEY"
141+
--base-url "$LLM_BASE_URL"
142+
--model "$LLM_MODEL"
143+
)
144+
return 0
145+
fi
146+
147+
return 1
148+
}
149+
150+
_llm_run_verify() {
151+
local output="" rc=0
152+
153+
if ! _llm_prepare_verify_cmd; then
154+
echo "WARNING: No LLM verification helper is available on this machine." >&2
155+
return 2
156+
fi
157+
158+
set +e
159+
output="$("${_LLM_VERIFY_CMD[@]}" 2>&1)"
160+
rc=$?
161+
set -e
162+
163+
if [ -n "$output" ]; then
164+
printf '%s\n' "$output"
165+
fi
166+
167+
return "$rc"
168+
}
169+
170+
verify_llm_config_interactive() {
171+
local provider_name choice fail_choice
172+
173+
if [ -z "$LLM_API_KEY" ]; then
174+
echo "[*] No API key entered — skipping pre-install verification."
175+
return 0
176+
fi
177+
178+
provider_name="$(_cfg "['llm_providers']['$LLM_PROVIDER']['name']")"
179+
if [ -z "$provider_name" ]; then
180+
provider_name="$LLM_PROVIDER"
181+
fi
182+
183+
while true; do
184+
echo ""
185+
echo "----------------------------------------"
186+
echo " Verify LLM Connection"
187+
echo "----------------------------------------"
188+
echo " Provider: $provider_name"
189+
echo " Model: $LLM_MODEL"
190+
if [ -n "$LLM_BASE_URL" ]; then
191+
echo " Base URL: $LLM_BASE_URL"
143192
fi
193+
echo ""
194+
read -rp "Verify the connection now? [Y/n/e=edit/c=cancel]: " choice
195+
choice="${choice:-y}"
196+
197+
case "${choice,,}" in
198+
y|yes)
199+
echo "[*] Verifying API connection..."
200+
if _llm_run_verify; then
201+
echo "[OK] Connection verified!"
202+
_LLM_VERIFIED_THIS_SESSION=1
203+
return 0
204+
fi
205+
206+
echo ""
207+
read -rp "Verification failed. [r]etry, [e]dit settings, [c]ontinue anyway, or [q]uit? [r]: " fail_choice
208+
fail_choice="${fail_choice:-r}"
209+
case "${fail_choice,,}" in
210+
e|edit)
211+
collect_llm_config
212+
if [ -z "$LLM_API_KEY" ]; then
213+
echo "[*] No API key entered — skipping pre-install verification."
214+
return 0
215+
fi
216+
provider_name="$(_cfg "['llm_providers']['$LLM_PROVIDER']['name']")"
217+
[ -z "$provider_name" ] && provider_name="$LLM_PROVIDER"
218+
;;
219+
c|continue)
220+
echo "[!] Continuing without a successful verification."
221+
return 0
222+
;;
223+
q|quit)
224+
echo "[!] Installation canceled."
225+
return 1
226+
;;
227+
*)
228+
;;
229+
esac
230+
;;
231+
n|no)
232+
echo "[*] Skipping pre-install verification."
233+
return 0
234+
;;
235+
e|edit)
236+
collect_llm_config
237+
if [ -z "$LLM_API_KEY" ]; then
238+
echo "[*] No API key entered — skipping pre-install verification."
239+
return 0
240+
fi
241+
provider_name="$(_cfg "['llm_providers']['$LLM_PROVIDER']['name']")"
242+
[ -z "$provider_name" ] && provider_name="$LLM_PROVIDER"
243+
;;
244+
c|cancel|q|quit)
245+
echo "[!] Installation canceled."
246+
return 1
247+
;;
248+
*)
249+
echo "Please answer y, n, e, or c."
250+
;;
251+
esac
252+
done
253+
}
254+
255+
# Called once per session (first time apply_llm_config_for runs). Tracks
256+
# state so re-calling for a second product doesn't re-verify the same key.
257+
_LLM_VERIFIED_THIS_SESSION=0
258+
_llm_verify_once() {
259+
if [ "$_LLM_VERIFIED_THIS_SESSION" -eq 1 ]; then
260+
return 0
261+
fi
262+
_LLM_VERIFIED_THIS_SESSION=1
263+
264+
echo "[*] Verifying API connection..."
265+
if _llm_run_verify; then
266+
echo "[OK] Connection verified!"
267+
else
268+
echo "WARNING: Could not verify connection. Saving config anyway."
144269
fi
145270
}
146271

0 commit comments

Comments
 (0)