diff --git a/bin/omarchy-openclaw-onboard b/bin/omarchy-openclaw-onboard index 5bac15bd..d8665b3e 100755 --- a/bin/omarchy-openclaw-onboard +++ b/bin/omarchy-openclaw-onboard @@ -26,8 +26,12 @@ settle_seconds=${OMARCHY_OPENCLAW_ONBOARD_SETTLE_SECONDS:-3} # setup; the prompts before that take as long as the user takes. gateway_timeout=${OMARCHY_OPENCLAW_ONBOARD_GATEWAY_TIMEOUT:-180} +# Probes never get the terminal. The wizard writes its config while prompts +# remain, a probe of a gateway not yet up then hangs until the timeout, and +# OpenClaw's CLI takes a terminal on stdin out of raw mode as it is killed, +# which leaves the wizard's next prompt echoing keys instead of reading them. gateway_answers() { - timeout 10 openclaw dashboard --json 2>/dev/null | jq -e '.ok == true' >/dev/null 2>&1 + timeout 10 openclaw dashboard --json /dev/null | jq -e '.ok == true' >/dev/null 2>&1 } # A gateway already answering means OpenClaw is set up, and this run must not @@ -81,7 +85,7 @@ config_applied() { gateway_ready() { config_applied || return 1 local json port listener main_pid - json=$(timeout 10 openclaw dashboard --json 2>/dev/null) || return 1 + json=$(timeout 10 openclaw dashboard --json /dev/null) || return 1 jq -e '.ok == true' <<<"$json" >/dev/null 2>&1 || return 1 port=$(jq -r '.port // empty' <<<"$json" 2>/dev/null) [[ -n $port ]] || return 1 diff --git a/test/shell.d/openclaw-onboard-test.sh b/test/shell.d/openclaw-onboard-test.sh index 852e3e3d..1c315fdd 100755 --- a/test/shell.d/openclaw-onboard-test.sh +++ b/test/shell.d/openclaw-onboard-test.sh @@ -55,6 +55,7 @@ onboard) while :; do sleep 0.2; done ;; dashboard) + printf 'dashboard-stdin:%s\n' "$(readlink /proc/$$/fd/0)" >>"$TEST_LOG" [[ -f $HOME/.openclaw/openclaw.json ]] && echo '{"ok":true,"port":18789}' || { echo '{"ok":false}'; exit 1; } ;; esac @@ -63,7 +64,10 @@ chmod +x "$tmp_dir/bin/openclaw" start=$SECONDS rc=0 -"$ROOT/bin/omarchy-openclaw-onboard" /dev/null 2>&1 || rc=$? +# A file stands in for the terminal the wizard reads, so where each probe's +# stdin points can be told apart from it. +: >"$tmp_dir/terminal" +"$ROOT/bin/omarchy-openclaw-onboard" <"$tmp_dir/terminal" >/dev/null 2>&1 || rc=$? elapsed=$((SECONDS - start)) grep -q '^openclaw:onboard --flow quickstart --install-daemon --skip-ui$' "$TEST_LOG" || @@ -76,6 +80,14 @@ grep -q '^terminated$' "$TEST_LOG" || (( elapsed < 30 )) || fail "a wizard that lingers after the gateway is up is stopped and counts as success" "took ${elapsed}s" pass "a wizard that lingers after the gateway is up is stopped and counts as success" +# OpenClaw's CLI takes a terminal on stdin out of raw mode as the timeout kills +# it, so a probe that inherited the wizard's terminal would leave its prompts +# unable to read keys. The wizard writes its config while prompts remain. +grep -q '^dashboard-stdin:' "$TEST_LOG" || fail "gateway probes never read from the wizard's terminal" "no probe ran" +! grep '^dashboard-stdin:' "$TEST_LOG" | grep -vqx 'dashboard-stdin:/dev/null' || + fail "gateway probes never read from the wizard's terminal" "$(grep '^dashboard-stdin:' "$TEST_LOG" | sort -u)" +pass "gateway probes never read from the wizard's terminal" + # The wizard only starts being stopped once the gateway actually answers: a # stub that never writes the config is left alone and must be ended by its own # exit, not the watcher.