From 9ace84e6c3d47d3a04acdf8ac806837c8adeabbe Mon Sep 17 00:00:00 2001 From: Spencer Bull Date: Mon, 28 Sep 2026 01:40:39 -0500 Subject: [PATCH] Keep OpenClaw's gateway probes off the wizard's terminal The wizard writes its config while prompts remain, so the watcher starts probing a gateway that is not up yet; each probe hangs until its 10 second timeout, and OpenClaw's CLI, killed by it, takes the terminal it inherited on stdin out of raw mode on the way out. The wizard does not set raw mode again, so from then on its prompts echo keys instead of reading them: the first letter typed at the channel search landed and the next one was printed below the prompt. The probes now read from /dev/null. This is the change reverted earlier on a test that only ever saw probes that exited on their own, never one the timeout killed. --- bin/omarchy-openclaw-onboard | 8 ++++++-- test/shell.d/openclaw-onboard-test.sh | 14 +++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) 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.