Merge pull request #13296 from omacom/openclaw-self-updating
Install OpenClaw as a self-updating copy under ~/.openclaw
This commit is contained in:
11 files changed
+681
-44
No files matched your search
@@ -874,15 +874,16 @@ grep -F "missing is not installed" "$test_tmp/missing-output" >/dev/null ||
|
||||
fail "agent launcher explains when the default command is missing"
|
||||
pass "agent launcher reports a missing default command"
|
||||
|
||||
# OpenClaw comes from its pacman package, not mise: choosing it must route
|
||||
# OpenClaw is its own self-updating runtime, not mise's: choosing it must route
|
||||
# through omarchy-install-openclaw-cli and never touch a mise environment.
|
||||
cat >"$mock_bin/omarchy-pkg-present" <<'SH'
|
||||
# openclaw-cli-test.sh covers the installer itself.
|
||||
cat >"$mock_bin/omarchy-install-openclaw-cli" <<'SH'
|
||||
#!/bin/bash
|
||||
[[ $1 == openclaw && ${OMARCHY_TEST_OPENCLAW_INSTALLED:-false} == "true" ]]
|
||||
SH
|
||||
cat >"$mock_bin/omarchy-pkg-add" <<'SH'
|
||||
#!/bin/bash
|
||||
printf '%s\n' "pkg-add $*" >>"$OMARCHY_TEST_STUB_LOG"
|
||||
if [[ $1 == "--check" ]]; then
|
||||
[[ ${OMARCHY_TEST_OPENCLAW_INSTALLED:-false} == "true" ]]
|
||||
else
|
||||
printf '%s\n' "install-openclaw-cli $*" >>"$OMARCHY_TEST_STUB_LOG"
|
||||
fi
|
||||
SH
|
||||
cat >"$mock_bin/omarchy-launch-openclaw" <<'SH'
|
||||
#!/bin/bash
|
||||
@@ -892,7 +893,7 @@ cat >"$mock_bin/openclaw" <<'SH'
|
||||
#!/bin/bash
|
||||
exit 0
|
||||
SH
|
||||
chmod +x "$mock_bin/omarchy-pkg-present" "$mock_bin/omarchy-pkg-add" \
|
||||
chmod +x "$mock_bin/omarchy-install-openclaw-cli" \
|
||||
"$mock_bin/omarchy-launch-openclaw" "$mock_bin/openclaw"
|
||||
|
||||
: >"$launch_log"
|
||||
@@ -906,7 +907,7 @@ mapfile -d '' -t launch_args <"$launch_log"
|
||||
fail "choosing OpenClaw launches its terminal UI"
|
||||
[[ ! -s $terminal_log ]] || fail "an installed OpenClaw needs no install terminal"
|
||||
! grep -q 'use -g openclaw' "$mise_history" || fail "OpenClaw never installs through mise"
|
||||
pass "choosing OpenClaw uses the package and launches its terminal UI"
|
||||
pass "choosing OpenClaw uses its runtime and launches its terminal UI"
|
||||
|
||||
: >"$terminal_log"
|
||||
OMARCHY_TEST_OPENCLAW_INSTALLED=false omarchy-default-agent openclaw
|
||||
@@ -918,12 +919,12 @@ pass "a missing OpenClaw routes through the install terminal"
|
||||
: >"$stub_log"
|
||||
: >"$inline_log"
|
||||
OMARCHY_TEST_OPENCLAW_INSTALLED=false omarchy-default-agent --install openclaw >/dev/null
|
||||
grep -Fx "pkg-add openclaw" "$stub_log" >/dev/null ||
|
||||
fail "installing OpenClaw as default agent adds its package"
|
||||
grep -Fx "install-openclaw-cli --now" "$stub_log" >/dev/null ||
|
||||
fail "installing OpenClaw as default agent sets up its runtime"
|
||||
mapfile -d '' -t inline_args <"$inline_log"
|
||||
[[ ${inline_args[*]} == "omarchy-launch-openclaw --tui" ]] ||
|
||||
fail "installing OpenClaw as default agent hands over to its terminal UI"
|
||||
pass "installing OpenClaw as default agent adds its package"
|
||||
pass "installing OpenClaw as default agent sets up its runtime"
|
||||
|
||||
: >"$launch_log"
|
||||
omarchy agent prompt "Review this project"
|
||||
|
||||
Executable
+333
@@ -0,0 +1,333 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
test_tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$test_tmp"' EXIT
|
||||
|
||||
mock_bin="$test_tmp/bin"
|
||||
seed="$test_tmp/share"
|
||||
events="$test_tmp/events"
|
||||
mkdir -p "$mock_bin" "$seed"
|
||||
|
||||
cat >"$mock_bin/omarchy-pkg-present" <<'SH'
|
||||
#!/bin/bash
|
||||
[[ $1 == openclaw && -e $OMARCHY_TEST_ROOT/package-installed ]]
|
||||
SH
|
||||
cat >"$mock_bin/omarchy-pkg-add" <<'SH'
|
||||
#!/bin/bash
|
||||
printf 'pkg-add %s\n' "$*" >>"$OMARCHY_TEST_ROOT/events"
|
||||
touch "$OMARCHY_TEST_ROOT/package-installed"
|
||||
SH
|
||||
# The user manager, as far as these tests need one: a service is active while
|
||||
# a marker says so, and enabled likewise. Stopping clears it, except for the
|
||||
# unit named in OMARCHY_TEST_STOP_FAIL.
|
||||
cat >"$mock_bin/systemctl" <<'SH'
|
||||
#!/bin/bash
|
||||
case "$2" in
|
||||
stop)
|
||||
printf 'systemctl %s\n' "$*" >>"$OMARCHY_TEST_ROOT/events"
|
||||
[[ ${OMARCHY_TEST_STOP_FAIL:-} != "$3" ]] || exit 1
|
||||
rm -f "$HOME/active-$3"
|
||||
;;
|
||||
is-active) [[ -e $HOME/active-$4 ]] ;;
|
||||
is-enabled) [[ -e $HOME/enabled-$4 ]] ;;
|
||||
disable)
|
||||
printf 'systemctl %s\n' "$*" >>"$OMARCHY_TEST_ROOT/events"
|
||||
rm -f "$HOME/enabled-$3"
|
||||
;;
|
||||
esac
|
||||
SH
|
||||
chmod +x "$mock_bin/"*
|
||||
|
||||
# Stands in for upstream's install-cli.sh: it writes the command the way the
|
||||
# real one does, execing into the prefix's tools, and that command logs what
|
||||
# it is asked. OMARCHY_TEST_INSTALL_BROKEN leaves a command that cannot run.
|
||||
# Like upstream, `<role> install --force` rewrites the unit onto the runtime
|
||||
# and starts it, OMARCHY_TEST_START_FAIL making the start fail, and the
|
||||
# installer does that itself for a gateway it finds loaded. As upstream does
|
||||
# since 2026.9.6, a rewrite keeps the Node the unit already ran unless
|
||||
# --runtime-path pins one.
|
||||
cat >"$seed/install-cli.sh" <<'SH'
|
||||
printf 'install-cli %s%s\n' "$*" "${OPENCLAW_PROFILE:+ profile=$OPENCLAW_PROFILE}" >>"$OMARCHY_TEST_ROOT/events"
|
||||
prefix=$HOME/.openclaw
|
||||
mkdir -p "$prefix/bin" "$prefix/tools/node-v24.19.0/bin"
|
||||
touch "$prefix/tools/node-v24.19.0/bin/node"
|
||||
ln -sfn "$prefix/tools/node-v24.19.0" "$prefix/tools/node"
|
||||
cat >"$prefix/bin/openclaw" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
[[ -z "\${OMARCHY_TEST_INSTALL_BROKEN:-}" ]] || exit 1
|
||||
printf 'runtime %s%s\n' "\$*" "\${OPENCLAW_PROFILE:+ profile=\$OPENCLAW_PROFILE}" >>"$OMARCHY_TEST_ROOT/events"
|
||||
if [[ \${2:-} == "install" ]]; then
|
||||
unit="\$HOME/.config/systemd/user/openclaw-\$1.service"
|
||||
node=$prefix/tools/node-v24.19.0/bin/node
|
||||
if [[ \${4:-} == "--runtime-path" ]]; then
|
||||
node=\$5
|
||||
elif [[ -f \$unit ]]; then
|
||||
node=\$(sed -n 's/^ExecStart=\([^ ]*\).*/\1/p' "\$unit")
|
||||
fi
|
||||
printf 'ExecStart=%s $prefix/tools/node-v24.19.0/lib/node_modules/openclaw/dist/index.js %s\n' "\$node" "\$1" >"\$unit"
|
||||
[[ -z "\${OMARCHY_TEST_START_FAIL:-}" ]] || exit 1
|
||||
touch "\$HOME/active-openclaw-\$1.service" "\$HOME/enabled-openclaw-\$1.service"
|
||||
fi
|
||||
exec true "$prefix/tools/node-v24.19.0/lib/node_modules/openclaw/dist/entry.js" "\$@"
|
||||
EOF
|
||||
chmod 755 "$prefix/bin/openclaw"
|
||||
if [[ -f $HOME/.config/systemd/user/openclaw-gateway.service ]]; then
|
||||
"$prefix/bin/openclaw" gateway install --force || true
|
||||
fi
|
||||
SH
|
||||
touch "$seed/openclaw.tgz"
|
||||
|
||||
# Scratch copies of the actual scripts, with only the package's path swapped.
|
||||
for script in bin/omarchy-install-openclaw-cli migrations/1790397381.sh; do
|
||||
sed "s|/usr/share/openclaw|$seed|g" "$ROOT/$script" >"$mock_bin/${script##*/}"
|
||||
done
|
||||
mv "$mock_bin/1790397381.sh" "$test_tmp/migration.sh"
|
||||
chmod +x "$mock_bin/omarchy-install-openclaw-cli"
|
||||
|
||||
new_home() {
|
||||
test_home="$test_tmp/$1"
|
||||
runtime="$test_home/.openclaw/bin/openclaw"
|
||||
command="$test_home/.local/bin/openclaw"
|
||||
mkdir -p "$test_home/.local/bin"
|
||||
rm -f "$test_tmp/package-installed"
|
||||
: >"$events"
|
||||
}
|
||||
|
||||
# PATH puts a directory ahead of ~/.local/bin the way Omarchy's does, where a
|
||||
# test can drop another openclaw.
|
||||
mkdir -p "$test_tmp/usr-bin"
|
||||
run() {
|
||||
HOME="$test_home" OMARCHY_TEST_ROOT="$test_tmp" PATH="$test_tmp/usr-bin:$mock_bin:$test_home/.local/bin:$PATH" \
|
||||
"$@" >"$test_tmp/output" 2>&1
|
||||
}
|
||||
|
||||
new_home usage
|
||||
run omarchy-install-openclaw-cli && fail "no mode is a usage error"
|
||||
[[ ! -s $events ]] || fail "no mode installs nothing" "$(cat "$events")"
|
||||
pass "every mode is named outright"
|
||||
|
||||
new_home fresh
|
||||
run omarchy-install-openclaw-cli --check && fail "--check calls a machine without OpenClaw installed"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now sets OpenClaw up" "$(cat "$test_tmp/output")"
|
||||
grep -Fxq "pkg-add openclaw" "$events" || fail "--now installs the package" "$(cat "$events")"
|
||||
grep -Fxq "install-cli --install-method npm --prefix $test_home/.openclaw --version $seed/openclaw.tgz --no-onboard" "$events" ||
|
||||
fail "--now seeds the runtime from the packaged release" "$(cat "$events")"
|
||||
[[ -L $command && $(readlink -- "$command") == "$runtime" ]] || fail "--now points the command on PATH at the runtime"
|
||||
run omarchy-install-openclaw-cli --check || fail "--check follows a finished install"
|
||||
pass "--now seeds a self-updating OpenClaw from the packaged release"
|
||||
|
||||
: >"$events"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now accepts a finished install" "$(cat "$test_tmp/output")"
|
||||
! grep -q '^install-cli\|^pkg-add' "$events" || fail "a runtime that answers is never reseeded" "$(cat "$events")"
|
||||
pass "a runtime that answers is never reseeded, whatever version its updates reached"
|
||||
|
||||
rm -f "$command"
|
||||
ln -s "$runtime" "$command.tmp" && mv "$command.tmp" "$command"
|
||||
mv "$test_home/.openclaw" "$test_home/.openclaw.gone"
|
||||
run omarchy-install-openclaw-cli --check && fail "--check calls a dangling link installed"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now reseeds behind its own dangling link" "$(cat "$test_tmp/output")"
|
||||
[[ -x $runtime && $(readlink -- "$command") == "$runtime" ]] || fail "--now reseeds behind its own dangling link"
|
||||
pass "a link Omarchy left behind is rewritten, and a missing runtime reseeded"
|
||||
|
||||
new_home old-package
|
||||
touch "$test_tmp/package-installed"
|
||||
mv "$seed" "$seed.old"
|
||||
run omarchy-install-openclaw-cli --now && fail "a package with no seed cannot set OpenClaw up"
|
||||
grep -q "Run 'omarchy update'" "$test_tmp/output" || fail "a package with no seed says to update" "$(cat "$test_tmp/output")"
|
||||
[[ ! -e $test_home/.openclaw && ! -e $command ]] || fail "a package with no seed leaves the home untouched"
|
||||
mv "$seed.old" "$seed"
|
||||
pass "a package that is still the runtime is refused before anything is touched"
|
||||
|
||||
new_home broken
|
||||
OMARCHY_TEST_INSTALL_BROKEN=1 run omarchy-install-openclaw-cli --now && fail "a runtime that does not run is not a finished install"
|
||||
grep -q "did not complete" "$test_tmp/output" || fail "a failed setup says so" "$(cat "$test_tmp/output")"
|
||||
[[ ! -e $command ]] || fail "a failed setup puts nothing on PATH"
|
||||
pass "a runtime that does not run fails the install"
|
||||
|
||||
new_home foreign
|
||||
printf '#!/bin/bash\necho mine\n' >"$command"
|
||||
chmod +x "$command"
|
||||
run omarchy-install-openclaw-cli --now && fail "a command that is the user's is not replaced"
|
||||
grep -q "Move it aside" "$test_tmp/output" || fail "a command that is the user's is named" "$(cat "$test_tmp/output")"
|
||||
[[ ! -L $command ]] && grep -q mine "$command" || fail "a command that is the user's is kept"
|
||||
run omarchy-install-openclaw-cli --check && fail "--check calls the runtime installed while the command is somebody else's"
|
||||
pass "a command at the path that is the user's is kept and named"
|
||||
|
||||
new_home shadowed
|
||||
printf '#!/bin/bash\n' >"$test_tmp/usr-bin/openclaw"
|
||||
chmod +x "$test_tmp/usr-bin/openclaw"
|
||||
run omarchy-install-openclaw-cli --now && fail "an openclaw earlier on PATH fails the install"
|
||||
grep -q "on PATH is $test_tmp/usr-bin/openclaw" "$test_tmp/output" || fail "an openclaw earlier on PATH is named" "$(cat "$test_tmp/output")"
|
||||
[[ ! -e $test_home/.openclaw && ! -e $command ]] || fail "an openclaw earlier on PATH is refused before anything is touched"
|
||||
rm "$test_tmp/usr-bin/openclaw"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now follows once nothing shadows the runtime" "$(cat "$test_tmp/output")"
|
||||
printf '#!/bin/bash\n' >"$test_tmp/usr-bin/openclaw"
|
||||
chmod +x "$test_tmp/usr-bin/openclaw"
|
||||
run omarchy-install-openclaw-cli --check && fail "--check calls a shadowed runtime installed"
|
||||
rm "$test_tmp/usr-bin/openclaw"
|
||||
run omarchy-install-openclaw-cli --check || fail "--check follows once nothing shadows the runtime"
|
||||
pass "the runtime has to be the openclaw PATH finds, and anything else is refused before it is set up"
|
||||
|
||||
# A runtime that answers without the package still leaves --now a pacman step,
|
||||
# which the default agent must not run outside a terminal.
|
||||
rm "$test_tmp/package-installed"
|
||||
run omarchy-install-openclaw-cli --check && fail "--check calls a runtime without its package installed"
|
||||
pass "--check needs the package too, so --now never has a password to ask for unseen"
|
||||
|
||||
# Upstream's installer rewrites a loaded gateway service to the copy it has
|
||||
# just made, so a gateway running another OpenClaw stops the seeding first.
|
||||
new_home foreign-gateway
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'Environment=OPENCLAW_CONFIG_PATH=%s/.openclaw/openclaw.json\nExecStart=/opt/node %s/openclaw/dist/index.js gateway --config %s/.openclaw/openclaw.json\n' "$test_home" "$test_home" "$test_home" \
|
||||
>"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
run omarchy-install-openclaw-cli --now && fail "a gateway running another OpenClaw stops the install"
|
||||
grep -q "runs another OpenClaw" "$test_tmp/output" || fail "a gateway running another OpenClaw is named" "$(cat "$test_tmp/output")"
|
||||
! grep -q '^install-cli' "$events" && [[ ! -e $test_home/.openclaw ]] ||
|
||||
fail "a gateway running another OpenClaw is refused before anything is set up" "$(cat "$events")"
|
||||
pass "a gateway running another OpenClaw is refused before upstream's installer can take it over"
|
||||
|
||||
# A gateway the old package installed runs from /usr/lib/node_modules, which
|
||||
# the seed package no longer ships; one running any other OpenClaw stays.
|
||||
new_home services
|
||||
units="$test_home/.config/systemd/user"
|
||||
mkdir -p "$units"
|
||||
printf 'ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' >"$units/openclaw-gateway.service"
|
||||
printf 'ExecStart=/opt/node /home/someone/openclaw/dist/index.js node run\n' >"$units/openclaw-node.service"
|
||||
touch "$test_home/active-openclaw-gateway.service" "$test_home/enabled-openclaw-gateway.service"
|
||||
OPENCLAW_PROFILE=work run omarchy-install-openclaw-cli --now || fail "--now moves the old package's services" "$(cat "$test_tmp/output")"
|
||||
order=$(grep -n -e '^systemctl --user stop openclaw-gateway.service$' -e '^install-cli ' -e '^runtime gateway install --force$' "$events" | cut -d: -f2- | cut -c1-11)
|
||||
[[ $order == $'systemctl -\ninstall-cli\nruntime gat' ]] ||
|
||||
fail "--now stops a gateway the old package installed before seeding, then moves it" "$(cat "$events")"
|
||||
! grep -q "runtime node install\|openclaw-node" "$events" || fail "--now leaves a service running another OpenClaw alone" "$(cat "$events")"
|
||||
! grep -q "profile=work" <(grep -v -e '^runtime --version' "$events") ||
|
||||
fail "--now seeds and moves the default unit whatever profile the shell selects" "$(cat "$events")"
|
||||
sed -n 's/^ExecStart=\([^ ]*\).*/\1/p' "$units/openclaw-gateway.service" | grep -qx "$test_home/.openclaw/tools/node-v24.19.0/bin/node" ||
|
||||
fail "--now leaves the moved gateway on the runtime's own Node" "$(cat "$units/openclaw-gateway.service")"
|
||||
grep -Fxq "runtime gateway install --force --runtime-path $test_home/.openclaw/tools/node-v24.19.0/bin/node" "$events" ||
|
||||
fail "--now pins the runtime's Node when the installer kept the system one" "$(cat "$events")"
|
||||
pass "a service the old package installed moves to the runtime, and only that one"
|
||||
|
||||
# Installing a service enables and starts it, so one the user had left stopped
|
||||
# and disabled is moved and then put back that way.
|
||||
new_home dormant
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now moves a dormant gateway" "$(cat "$test_tmp/output")"
|
||||
runs=$(sed -n 's/^ExecStart=\([^ ]*\).*/\1/p' "$test_home/.config/systemd/user/openclaw-gateway.service")
|
||||
[[ $runs == "$test_home/.openclaw/tools/node-v24.19.0/bin/node" && ! -e $test_home/active-openclaw-gateway.service && ! -e $test_home/enabled-openclaw-gateway.service ]] ||
|
||||
fail "--now moves a dormant gateway and leaves it stopped and disabled" "$(cat "$events")"
|
||||
pass "a gateway the user left stopped and disabled is moved and stays that way"
|
||||
|
||||
new_home stop-fails
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
OMARCHY_TEST_STOP_FAIL=openclaw-gateway.service run omarchy-install-openclaw-cli --now && fail "a gateway that will not stop stops the install"
|
||||
grep -q "Could not stop the OpenClaw gateway service" "$test_tmp/output" || fail "a gateway that will not stop is named" "$(cat "$test_tmp/output")"
|
||||
! grep -q '^install-cli' "$events" && [[ ! -e $test_home/.openclaw ]] ||
|
||||
fail "a gateway that will not stop leaves the runtime unseeded" "$(cat "$events")"
|
||||
pass "a gateway that will not stop stops the install before anything is seeded"
|
||||
|
||||
new_home stop-partial
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
for role in gateway node; do
|
||||
printf 'ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js %s\n' "$role" >"$test_home/.config/systemd/user/openclaw-$role.service"
|
||||
touch "$test_home/active-openclaw-$role.service"
|
||||
done
|
||||
OMARCHY_TEST_STOP_FAIL=openclaw-node.service run omarchy-install-openclaw-cli --now && fail "a node host that will not stop stops the install"
|
||||
grep -q "gateway service was stopped for this and is not running now" "$test_tmp/output" ||
|
||||
fail "a gateway stopped before a later stop failed is named as stopped" "$(cat "$test_tmp/output")"
|
||||
pass "a service this run stopped is named whenever the run then fails"
|
||||
|
||||
# Upstream's installer rewrites the gateway itself and only warns when it will
|
||||
# not start again, so a gateway that was running has to be running afterwards.
|
||||
new_home start-fails
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
touch "$test_home/active-openclaw-gateway.service"
|
||||
OMARCHY_TEST_START_FAIL=1 run omarchy-install-openclaw-cli --now && fail "a moved gateway that does not start fails the install"
|
||||
grep -q "Could not move the OpenClaw gateway service" "$test_tmp/output" && grep -q "is not running now" "$test_tmp/output" ||
|
||||
fail "a moved gateway that does not start is named, and so is its being stopped" "$(cat "$test_tmp/output")"
|
||||
pass "a gateway that was running is running again from the runtime, or the install fails saying it is stopped"
|
||||
|
||||
# With the runtime already in place nothing is seeded, so the move is Omarchy's.
|
||||
new_home runtime-first
|
||||
run omarchy-install-openclaw-cli --now || fail "--now sets OpenClaw up" "$(cat "$test_tmp/output")"
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
touch "$test_home/active-openclaw-gateway.service"
|
||||
: >"$events"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now moves a gateway beside a runtime that already runs" "$(cat "$test_tmp/output")"
|
||||
! grep -q '^install-cli' "$events" && grep -Fxq "runtime gateway install --force --runtime-path $test_home/.openclaw/tools/node-v24.19.0/bin/node" "$events" && [[ -e $test_home/active-openclaw-gateway.service ]] ||
|
||||
fail "--now moves a gateway beside a runtime that already runs" "$(cat "$events")"
|
||||
pass "a gateway beside a runtime that already runs is moved without seeding"
|
||||
|
||||
# A move that stopped halfway left the runtime's code on the old package's
|
||||
# /usr/bin/node; the next run finishes it, and moves a node host the same way.
|
||||
new_home half-moved
|
||||
run omarchy-install-openclaw-cli --now || fail "--now sets OpenClaw up" "$(cat "$test_tmp/output")"
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'ExecStart=/usr/bin/node %s/.openclaw/tools/node-v24.19.0/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' "$test_home" >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
printf 'ExecStart=/usr/bin/node %s/.openclaw/tools/node-v24.19.0/lib/node_modules/openclaw/dist/index.js node run\n' "$test_home" >"$test_home/.config/systemd/user/openclaw-node.service"
|
||||
touch "$test_home/active-openclaw-gateway.service" "$test_home/active-openclaw-node.service"
|
||||
: >"$events"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now finishes a half-moved gateway" "$(cat "$test_tmp/output")"
|
||||
for role in gateway node; do
|
||||
grep -Fxq "runtime $role install --force --runtime-path $test_home/.openclaw/tools/node-v24.19.0/bin/node" "$events" &&
|
||||
sed -n 's/^ExecStart=\([^ ]*\).*/\1/p' "$test_home/.config/systemd/user/openclaw-$role.service" | grep -qx "$test_home/.openclaw/tools/node-v24.19.0/bin/node" ||
|
||||
fail "--now finishes a half-moved $role on the runtime's own Node" "$(cat "$events")"
|
||||
done
|
||||
pass "a half-moved gateway and a node host end up on the runtime's own Node"
|
||||
|
||||
# The runtime run by any other Node or by Bun is the user's choice, not the old
|
||||
# package's dependency.
|
||||
new_home bun
|
||||
run omarchy-install-openclaw-cli --now || fail "--now sets OpenClaw up" "$(cat "$test_tmp/output")"
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'ExecStart=/usr/bin/bun %s/.openclaw/tools/node-v24.19.0/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' "$test_home" >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
cp "$test_home/.config/systemd/user/openclaw-gateway.service" "$test_tmp/bun-unit"
|
||||
: >"$events"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now leaves a Bun gateway alone" "$(cat "$test_tmp/output")"
|
||||
! grep -q "install --force\|^systemctl" "$events" && cmp -s "$test_tmp/bun-unit" "$test_home/.config/systemd/user/openclaw-gateway.service" ||
|
||||
fail "--now leaves a Bun gateway alone" "$(cat "$events")"
|
||||
printf 'ExecStart=/usr/bin/node %s/.openclaw/custom/bridge.js\n' "$test_home" >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
cp "$test_home/.config/systemd/user/openclaw-gateway.service" "$test_tmp/own-unit"
|
||||
: >"$events"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now leaves a script of the user's alone" "$(cat "$test_tmp/output")"
|
||||
! grep -q "install --force\|^systemctl" "$events" && cmp -s "$test_tmp/own-unit" "$test_home/.config/systemd/user/openclaw-gateway.service" ||
|
||||
fail "--now leaves a script of the user's alone" "$(cat "$events")"
|
||||
pass "a gateway the user runs on Bun, or a script of their own on /usr/bin/node, is left alone"
|
||||
|
||||
# The migration moves only machines that have the package, and waits for the
|
||||
# package that seeds.
|
||||
new_home migration-none
|
||||
run bash -euo pipefail "$test_tmp/migration.sh" || fail "a machine without OpenClaw has nothing to move" "$(cat "$test_tmp/output")"
|
||||
[[ ! -s $events && ! -e $test_home/.openclaw ]] || fail "a machine without OpenClaw is untouched" "$(cat "$events")"
|
||||
|
||||
new_home migration-old
|
||||
touch "$test_tmp/package-installed"
|
||||
mv "$seed" "$seed.old"
|
||||
run bash -euo pipefail "$test_tmp/migration.sh" && fail "an old package keeps the migration pending"
|
||||
[[ ! -e $test_home/.openclaw ]] || fail "an old package leaves the home untouched"
|
||||
mv "$seed.old" "$seed"
|
||||
|
||||
new_home migration
|
||||
touch "$test_tmp/package-installed"
|
||||
mkdir -p "$test_home/.config/systemd/user"
|
||||
printf 'ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789\n' >"$test_home/.config/systemd/user/openclaw-gateway.service"
|
||||
run bash -euo pipefail "$test_tmp/migration.sh" || fail "the migration moves OpenClaw" "$(cat "$test_tmp/output")"
|
||||
grep -q "^install-cli " "$events" && grep -Fxq "runtime gateway install --force" "$events" ||
|
||||
fail "the migration seeds the runtime and moves the gateway to it" "$(cat "$events")"
|
||||
[[ $(readlink -- "$command") == "$runtime" ]] || fail "the migration points the command at the runtime"
|
||||
sed -n 's/^ExecStart=\([^ ]*\).*/\1/p' "$test_home/.config/systemd/user/openclaw-gateway.service" | grep -qx "$test_home/.openclaw/tools/node-v24.19.0/bin/node" ||
|
||||
fail "the migration leaves the gateway on the runtime's own Node, not the old package's system Node" "$(cat "$test_home/.config/systemd/user/openclaw-gateway.service")"
|
||||
|
||||
new_home migration-foreign
|
||||
touch "$test_tmp/package-installed"
|
||||
printf '#!/bin/bash\n' >"$command"
|
||||
run bash -euo pipefail "$test_tmp/migration.sh" && fail "a migration that cannot finish stays pending"
|
||||
pass "the migration moves a packaged OpenClaw to its runtime, and stays pending until it can"
|
||||
@@ -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 >/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.
|
||||
|
||||
@@ -245,6 +245,8 @@ fresh_openclaw_home() {
|
||||
"$HOME/.local/share/applications" "$HOME/.local/share/icons/hicolor/256x256/apps"
|
||||
touch "$HOME/.config/systemd/user/openclaw-gateway.service" \
|
||||
"$HOME/.config/systemd/user/openclaw-gateway.service.bak" \
|
||||
"$HOME/.config/systemd/user/openclaw-gateway.service.reconcile-0f1e.bak" \
|
||||
"$HOME/.config/systemd/user/openclaw-gateway.service.reconcile-0f1e.receipt.bak" \
|
||||
"$HOME/.config/systemd/user/openclaw-node.service" \
|
||||
"$HOME/.openclaw/openclaw.json" \
|
||||
"$HOME/.local/share/applications/OpenClaw.desktop" \
|
||||
@@ -269,6 +271,8 @@ fresh_openclaw_home
|
||||
|
||||
for gone in .config/systemd/user/openclaw-gateway.service \
|
||||
.config/systemd/user/openclaw-gateway.service.bak \
|
||||
.config/systemd/user/openclaw-gateway.service.reconcile-0f1e.bak \
|
||||
.config/systemd/user/openclaw-gateway.service.reconcile-0f1e.receipt.bak \
|
||||
.config/systemd/user/default.target.wants/openclaw-gateway.service \
|
||||
.config/systemd/user/openclaw-node.service \
|
||||
.config/systemd/user/default.target.wants/openclaw-node.service \
|
||||
@@ -295,6 +299,24 @@ pass "OpenClaw removal stops the gateway service"
|
||||
fail "OpenClaw removal keeps the user's agent state" "asked about ~/.openclaw without a terminal"
|
||||
pass "OpenClaw removal keeps the user's agent state"
|
||||
|
||||
# The command on PATH goes; the OpenClaw it pointed at stays with the state,
|
||||
# since only that copy is sure to open it. A link somewhere else is not Omarchy's.
|
||||
fresh_openclaw_home
|
||||
mkdir -p "$HOME/.openclaw/bin" "$HOME/.openclaw/tools/node-v24.19.0/lib" "$HOME/.local/bin"
|
||||
printf '#!/usr/bin/env bash\n' >"$HOME/.openclaw/bin/openclaw"
|
||||
ln -s "$HOME/.openclaw/bin/openclaw" "$HOME/.local/bin/openclaw"
|
||||
"$ROOT/bin/omarchy-remove-ai-openclaw" >/dev/null
|
||||
[[ ! -e $HOME/.local/bin/openclaw && ! -L $HOME/.local/bin/openclaw ]] || fail "OpenClaw removal takes openclaw off PATH"
|
||||
[[ -f $HOME/.openclaw/bin/openclaw && -d $HOME/.openclaw/tools && -f $HOME/.openclaw/openclaw.json ]] ||
|
||||
fail "OpenClaw removal keeps the OpenClaw that can open the state"
|
||||
|
||||
fresh_openclaw_home
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
ln -s /opt/openclaw/openclaw "$HOME/.local/bin/openclaw"
|
||||
"$ROOT/bin/omarchy-remove-ai-openclaw" >/dev/null
|
||||
[[ -L $HOME/.local/bin/openclaw ]] || fail "OpenClaw removal takes openclaw off PATH" "someone else's link went with it"
|
||||
pass "OpenClaw removal takes openclaw off PATH and keeps the copy that can open the state"
|
||||
|
||||
# A CLI that knows `gateway uninstall` owns the teardown; the manual systemd
|
||||
# fallback must not run.
|
||||
cat >"$tmp_dir/bin/openclaw" <<'SCRIPT'
|
||||
|
||||
Reference in new issue
Block a user