Install OpenClaw as the self-updating copy under ~/.openclaw
This commit is contained in:
1 parent
7b336b1b0d
commit
be18b324f8
9 files changed
+353
-38
No files matched your search
@@ -50,10 +50,11 @@ esac
|
||||
|
||||
agent_package=${agent_package:-$agent}
|
||||
|
||||
# Hermes and OpenClaw are not mise tools: Hermes is the desktop app's
|
||||
# self-updating runtime and OpenClaw comes from its pacman package. Each has
|
||||
# its own installer with the same --check/--now contract mise-backed agents
|
||||
# get from mise; see omarchy-install-hermes-cli and omarchy-install-openclaw-cli.
|
||||
# Hermes and OpenClaw are not mise tools: each is a self-updating runtime in
|
||||
# the user's home, Hermes the desktop app's and OpenClaw the one its Control
|
||||
# UI updates. Each has its own installer with the same --check/--now contract
|
||||
# mise-backed agents get from mise; see omarchy-install-hermes-cli and
|
||||
# omarchy-install-openclaw-cli.
|
||||
if [[ -n ${agent_installer:-} ]]; then
|
||||
# Not omarchy-cmd-present: a command on PATH says nothing about whether the
|
||||
# install behind it finished or runs the sessions omarchy-agent starts.
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
set -e
|
||||
|
||||
echo "Installing OpenClaw..."
|
||||
omarchy-pkg-add openclaw
|
||||
# The same self-updating install the default agent gets.
|
||||
omarchy-install-openclaw-cli --now
|
||||
|
||||
# The desktop app is OpenClaw's Control UI: a web app served by its own
|
||||
# gateway. The launcher entry goes through omarchy-launch-openclaw, which
|
||||
@@ -14,7 +14,7 @@ omarchy-pkg-add openclaw
|
||||
# inside the package, so nothing is fetched here.
|
||||
echo "Installing the OpenClaw web app..."
|
||||
omarchy-webapp-install OpenClaw "http://127.0.0.1:18789" \
|
||||
/usr/lib/node_modules/openclaw/dist/control-ui/apple-touch-icon.png \
|
||||
/usr/share/openclaw/openclaw.png \
|
||||
omarchy-launch-openclaw
|
||||
|
||||
# A first install runs onboarding right here: launching the app instead would
|
||||
|
||||
@@ -1,29 +1,127 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Ensure the OpenClaw CLI is installed for the default agent
|
||||
# omarchy:args=[--check|--now]
|
||||
# omarchy:summary=Install OpenClaw for the default agent as the self-updating copy under ~/.openclaw
|
||||
# omarchy:args=<--check|--now>
|
||||
# omarchy:examples=omarchy install openclaw cli --now | omarchy install openclaw cli --check
|
||||
# omarchy:requires-sudo=true
|
||||
|
||||
# OpenClaw is not a mise tool: the openclaw pacman package is the one OpenClaw
|
||||
# installation on the machine — the CLI, the gateway, and the Install > AI web
|
||||
# app all share it, and the fast ring keeps it current. The default-agent flow
|
||||
# talks to that package through the same --check/--now contract mise-backed
|
||||
# agents get from mise itself.
|
||||
# There is one OpenClaw on a machine, and it is the one under ~/.openclaw that
|
||||
# upstream's install-cli.sh makes: a private Node and the package in a prefix
|
||||
# the user owns, which `openclaw update` and the Control UI's Update button
|
||||
# replace in place. A copy in /usr belongs to pacman, and upstream's updater
|
||||
# refuses to touch it. The openclaw package is therefore the seed rather than
|
||||
# the runtime: the release Omarchy ships and the installer that came with it.
|
||||
# The CLI, the gateway service and the Install > AI web app all run this copy.
|
||||
#
|
||||
# Each mode is named outright, like omarchy-install-hermes-cli: the default
|
||||
# agent asks --check first and opens a terminal for --now only on a no.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
case "${1:---now}" in
|
||||
mode=${1:-}
|
||||
|
||||
prefix="$HOME/.openclaw"
|
||||
runtime_command="$prefix/bin/openclaw"
|
||||
command_path="$HOME/.local/bin/openclaw"
|
||||
seed=/usr/share/openclaw
|
||||
|
||||
# Usable means the command answers, not that the file is there: upstream's
|
||||
# wrapper execs the prefix's own Node, so a prefix missing either fails here.
|
||||
runtime_runs() {
|
||||
[[ -f $runtime_command && -x $runtime_command ]] &&
|
||||
timeout 30 "$runtime_command" --version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# The name on PATH is a link to the runtime's command. A link already aimed
|
||||
# there, even one left dangling by a removed runtime, is Omarchy's to rewrite;
|
||||
# anything else at the path is the user's.
|
||||
command_ours() {
|
||||
[[ ! -e $command_path && ! -L $command_path ]] || [[ $(readlink -- "$command_path") == "$runtime_command" ]]
|
||||
}
|
||||
|
||||
# What omarchy-agent, the web app and a terminal run is whichever openclaw is
|
||||
# first on PATH, and Omarchy puts /usr/bin and the mise shims ahead of
|
||||
# ~/.local/bin, so the command has to resolve to the runtime from there.
|
||||
on_path() {
|
||||
local found
|
||||
found=$(type -P openclaw) || return 1
|
||||
[[ $(realpath -m -- "$found") == "$(realpath -m -- "$runtime_command")" ]]
|
||||
}
|
||||
|
||||
installed() {
|
||||
runtime_runs && on_path
|
||||
}
|
||||
|
||||
# A service the openclaw package's own copy installed runs from
|
||||
# /usr/lib/node_modules/openclaw, which that package no longer ships. Installed
|
||||
# again from the runtime, it runs code `openclaw update` can replace; upstream
|
||||
# rewrites the unit and restarts it. A service running any other OpenClaw is
|
||||
# the user's arrangement and stays.
|
||||
rehome_services() {
|
||||
local role unit
|
||||
for role in gateway node; do
|
||||
unit="$HOME/.config/systemd/user/openclaw-$role.service"
|
||||
if [[ -f $unit ]] && grep -qF "/usr/lib/node_modules/openclaw/" "$unit"; then
|
||||
echo "Moving the OpenClaw $role service to $prefix..."
|
||||
if ! "$runtime_command" "$role" install --force; then
|
||||
echo "Could not move the OpenClaw $role service. Finish with: openclaw $role install --force" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
case "$mode" in
|
||||
--check)
|
||||
omarchy-pkg-present openclaw
|
||||
;;
|
||||
--now)
|
||||
if ! omarchy-pkg-present openclaw; then
|
||||
echo "Installing OpenClaw..."
|
||||
omarchy-pkg-add openclaw
|
||||
fi
|
||||
if installed; then exit 0; else exit 1; fi
|
||||
;;
|
||||
--now) ;;
|
||||
*)
|
||||
echo "Usage: omarchy-install-openclaw-cli [--check|--now]" >&2
|
||||
echo "Usage: omarchy-install-openclaw-cli <--check|--now>" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if (( EUID == 0 )); then
|
||||
echo "Run this command as your desktop user, without sudo." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! omarchy-pkg-present openclaw; then
|
||||
echo "Installing OpenClaw..."
|
||||
omarchy-pkg-add openclaw
|
||||
fi
|
||||
|
||||
# A runtime that already answers is never reinstalled: it may be past the
|
||||
# packaged release by its own updates, and seeding would take it back.
|
||||
if ! runtime_runs; then
|
||||
if [[ ! -r $seed/install-cli.sh || ! -r $seed/openclaw.tgz ]]; then
|
||||
echo "The installed OpenClaw package cannot set up a self-updating OpenClaw. Run 'omarchy update', then try again." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Every choice the installer reads from the environment is named, so an
|
||||
# OPENCLAW_INSTALL_METHOD or OPENCLAW_PREFIX left in a shell cannot move it.
|
||||
echo "Setting up OpenClaw in $prefix..."
|
||||
bash "$seed/install-cli.sh" --install-method npm --prefix "$prefix" --version "$seed/openclaw.tgz" --no-onboard
|
||||
if ! runtime_runs; then
|
||||
echo "OpenClaw setup did not complete. Re-run this command after resolving the installer error." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if command_ours; then
|
||||
mkdir -p "${command_path%/*}"
|
||||
ln -sfn "$runtime_command" "$command_path"
|
||||
else
|
||||
echo "$command_path is not the OpenClaw Omarchy set up. Move it aside, then run omarchy-install-openclaw-cli --now again." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rehome_services
|
||||
|
||||
if ! on_path; then
|
||||
echo "$runtime_command is ready, but 'openclaw' on PATH is $(type -P openclaw || echo missing), which is what Omarchy runs." >&2
|
||||
echo "Remove it or reorder PATH, then run omarchy-install-openclaw-cli --now again." >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -49,6 +49,19 @@ done
|
||||
|
||||
omarchy-pkg-drop openclaw
|
||||
|
||||
# The runtime omarchy-install-openclaw-cli set up lives beside the user's state
|
||||
# in ~/.openclaw: the command upstream's installer wrote, and the Node and
|
||||
# package under tools/. Only a command that execs into those tools is the
|
||||
# installer's; the link on PATH goes only when it points at that command.
|
||||
if [[ -f $HOME/.openclaw/bin/openclaw ]] && grep -qF "\"$HOME/.openclaw/tools/" "$HOME/.openclaw/bin/openclaw"; then
|
||||
rm -rf "$HOME/.openclaw/tools"
|
||||
rm -f "$HOME/.openclaw/bin/openclaw"
|
||||
rmdir "$HOME/.openclaw/bin" 2>/dev/null || true
|
||||
fi
|
||||
if [[ -L $HOME/.local/bin/openclaw && $(readlink -- "$HOME/.local/bin/openclaw") == "$HOME/.openclaw/bin/openclaw" ]]; then
|
||||
rm -f "$HOME/.local/bin/openclaw"
|
||||
fi
|
||||
|
||||
# The web app launcher and icon omarchy-install-ai-openclaw created.
|
||||
rm -f "$HOME/.local/share/applications/OpenClaw.desktop"
|
||||
rm -f "$HOME/.local/share/icons/hicolor/256x256/apps/openclaw.png"
|
||||
@@ -59,12 +72,13 @@ gtk-update-icon-cache "$HOME/.local/share/icons/hicolor" &>/dev/null || true
|
||||
# better surprise. But it also holds the plugin runtimes and caches OpenClaw
|
||||
# downloads for itself, easily hundreds of megabytes, so the choice is put in
|
||||
# front of the user with the size rather than left silent. Without a terminal
|
||||
# to ask in, keeping it is the answer.
|
||||
# to ask in, keeping it is the answer. The snapshots `openclaw update` takes
|
||||
# of that state sit beside it and go with it.
|
||||
state_removed=false
|
||||
if [[ -d $HOME/.openclaw && -t 0 ]]; then
|
||||
size=$(du -sh "$HOME/.openclaw" 2>/dev/null | cut -f1)
|
||||
if gum confirm --default=false "Also delete ~/.openclaw ($size: chats, memories, credentials, and downloaded plugins)?"; then
|
||||
rm -rf "$HOME/.openclaw"
|
||||
rm -rf "$HOME/.openclaw" "$HOME/.openclaw.update-captures"
|
||||
state_removed=true
|
||||
fi
|
||||
fi
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ The _Install > AI_ menu also carries a few graphical AI apps: the ChatGPT deskto
|
||||
|
||||
Hermes Desktop is the one to know about, because a machine has one Hermes, and it is the app's: Hermes is only ever installed through the app, and the `hermes` command the default agent runs is the app's. Choosing Hermes as the default agent installs the same thing the _Install > AI_ entry does: the package, and a Hermes runtime under `~/.hermes` set up by Hermes' own installer, which takes a few minutes the first time. That runtime is the one Hermes the terminal `hermes` command, the default agent and the app all use, and it updates itself with `hermes update` rather than waiting on an Omarchy release. Installing it also hands Hermes the Omarchy theme as a skin named `omarchy`, which every Hermes surface follows as you switch themes; pick another under Hermes' Appearance settings or with `/skin` if you'd rather it didn't, and Omarchy leaves that choice alone. Removing the app under _Remove > AI_ closes Hermes first, gateway included, takes that runtime with it, and keeps your chats, memories, and the skills Hermes wrote for itself unless you tell it otherwise: it asks, defaulting to no, whether that data and your connection settings should go too.
|
||||
|
||||
OpenClaw's desktop experience is its Control UI, which opens as a web app backed by its own local gateway. OpenClaw updates arrive through Omarchy's package updates, so skip the Control UI's own "Update Gateway" button: it would try to write into the package-managed install and fail. Removing OpenClaw under _Remove > AI_ takes the gateway service and the app with it and then asks whether `~/.openclaw` should go too, since that holds your chats and credentials alongside the plugin runtimes OpenClaw downloads for itself; the default keeps it.
|
||||
OpenClaw's desktop experience is its Control UI, which opens as a web app backed by its own local gateway. OpenClaw lives in `~/.openclaw` and updates itself: use the Control UI's "Update Gateway" button or run `openclaw update`, and the gateway restarts on the new version. Omarchy only chooses the release a fresh install starts from. Removing OpenClaw under _Remove > AI_ takes the gateway service, the app and OpenClaw itself with it and then asks whether the rest of `~/.openclaw` should go too, since that holds your chats and credentials alongside the plugin runtimes OpenClaw downloads for itself; the default keeps it.
|
||||
|
||||
### Local LLMs
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
echo "Move OpenClaw to a self-updating install under ~/.openclaw"
|
||||
|
||||
# The openclaw package used to be OpenClaw itself, installed under /usr where `openclaw update` and the Control UI's Update button cannot write. It is now the seed for a copy under ~/.openclaw that updates itself, and omarchy-install-openclaw-cli sets that copy up, points the command on PATH at it and moves a gateway service the old package installed over to it. Only machines with the package have an OpenClaw of Omarchy's to move.
|
||||
omarchy-pkg-present openclaw || exit 0
|
||||
|
||||
# Updates install packages before migrations. An older package is still the runtime and has no seed, so this stays pending until it is updated.
|
||||
if [[ ! -r /usr/share/openclaw/install-cli.sh || ! -r /usr/share/openclaw/openclaw.tgz ]]; then
|
||||
echo "Update the openclaw package before rerunning this migration." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
omarchy-install-openclaw-cli --now
|
||||
@@ -761,15 +761,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
|
||||
@@ -779,7 +780,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"
|
||||
@@ -793,7 +794,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
|
||||
@@ -805,12 +806,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
+168
@@ -0,0 +1,168 @@
|
||||
#!/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
|
||||
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.
|
||||
cat >"$seed/install-cli.sh" <<'SH'
|
||||
printf 'install-cli %s\n' "$*" >>"$OMARCHY_TEST_ROOT/events"
|
||||
prefix=$HOME/.openclaw
|
||||
mkdir -p "$prefix/bin" "$prefix/tools/node-v24.19.0"
|
||||
cat >"$prefix/bin/openclaw" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
[[ -z "${OMARCHY_TEST_INSTALL_BROKEN:-}" ]] || exit 1
|
||||
printf 'runtime %s\n' "\$*" >>"$OMARCHY_TEST_ROOT/events"
|
||||
exec true "$prefix/tools/node-v24.19.0/lib/node_modules/openclaw/dist/entry.js" "\$@"
|
||||
EOF
|
||||
chmod 755 "$prefix/bin/openclaw"
|
||||
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")"
|
||||
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"
|
||||
|
||||
# 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"
|
||||
run omarchy-install-openclaw-cli --now || fail "--now moves the old package's services" "$(cat "$test_tmp/output")"
|
||||
grep -Fxq "runtime gateway install --force" "$events" || fail "--now moves a gateway the old package installed" "$(cat "$events")"
|
||||
! grep -q "runtime node install" "$events" || fail "--now leaves a service running another OpenClaw alone" "$(cat "$events")"
|
||||
pass "a service the old package installed moves to the runtime, and only that one"
|
||||
|
||||
# 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"
|
||||
|
||||
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"
|
||||
@@ -295,6 +295,27 @@ 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 runtime omarchy-install-openclaw-cli set up sits beside that state and
|
||||
# goes; a command that is not the installer's, or a link elsewhere, stays.
|
||||
fresh_openclaw_home
|
||||
mkdir -p "$HOME/.openclaw/bin" "$HOME/.openclaw/tools/node-v24.19.0/lib" "$HOME/.local/bin"
|
||||
printf '#!/usr/bin/env bash\nexec "%s/.openclaw/tools/node/bin/node" "%s/.openclaw/tools/node-v24.19.0/lib/node_modules/openclaw/dist/entry.js" "$@"\n' "$HOME" "$HOME" >"$HOME/.openclaw/bin/openclaw"
|
||||
ln -s "$HOME/.openclaw/bin/openclaw" "$HOME/.local/bin/openclaw"
|
||||
"$ROOT/bin/omarchy-remove-ai-openclaw" >/dev/null
|
||||
for gone in .openclaw/tools .openclaw/bin .local/bin/openclaw; do
|
||||
[[ ! -e $HOME/$gone && ! -L $HOME/$gone ]] || fail "OpenClaw removal deletes the runtime it set up" "$gone"
|
||||
done
|
||||
[[ -f $HOME/.openclaw/openclaw.json ]] || fail "OpenClaw removal deletes the runtime it set up" "state went with it"
|
||||
|
||||
fresh_openclaw_home
|
||||
mkdir -p "$HOME/.openclaw/bin" "$HOME/.openclaw/tools" "$HOME/.local/bin"
|
||||
printf '#!/bin/bash\nexec /opt/openclaw/openclaw.mjs "$@"\n' >"$HOME/.openclaw/bin/openclaw"
|
||||
ln -s /opt/openclaw/openclaw "$HOME/.local/bin/openclaw"
|
||||
"$ROOT/bin/omarchy-remove-ai-openclaw" >/dev/null
|
||||
[[ -f $HOME/.openclaw/bin/openclaw && -d $HOME/.openclaw/tools && -L $HOME/.local/bin/openclaw ]] ||
|
||||
fail "OpenClaw removal deletes the runtime it set up" "someone else's install went with it"
|
||||
pass "OpenClaw removal deletes the runtime it set up, and only that"
|
||||
|
||||
# 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