diff --git a/bin/omarchy-remove-ai-perplexity b/bin/omarchy-remove-ai-perplexity index c2388738..93859484 100755 --- a/bin/omarchy-remove-ai-perplexity +++ b/bin/omarchy-remove-ai-perplexity @@ -1,6 +1,6 @@ #!/bin/bash -# omarchy:summary=Remove the Perplexity desktop app along with its configuration and caches. +# omarchy:summary=Remove the Perplexity desktop app along with its runtime caches. # omarchy:requires-sudo=true # -u so an unset HOME is an error rather than a set of rm -rf paths rooted at /. @@ -8,14 +8,42 @@ set -euo pipefail omarchy-pkg-drop perplexity -# Of the perplexity-* dirs under ~/.cache, only the rpc-server runtime is the -# desktop app's own download; the rest belong to Perplexity products that -# outlive the desktop app. +# The runtime the app downloads for itself: llama.cpp builds and local models +# under ~/.local/share, the older download location under ~/.cache. Of the +# perplexity-* dirs these are the only ones the desktop app owns; the rest +# belong to Perplexity products that outlive it. rm -rf \ - "$HOME/.config/Perplexity" \ "$HOME/.cache/Perplexity" \ - "$HOME/.cache/perplexity-rpc-server" -rm -f "$HOME/.config/perplexity-flags.conf" + "$HOME/.cache/perplexity-rpc-server" \ + "$HOME/.local/share/perplexity-rpc-server" + +# What is left is the user's: the logins and session in ~/.config/Perplexity, +# the secret vault and device identity in ~/.local/state/perplexity, and the +# launcher flags. Keeping them stays the default -- they are small, and being +# signed in after a reinstall is the better surprise -- but a removal meant to +# be complete should not leave credentials behind either, so the choice is put +# in front of the user, default no. Without a terminal to ask in, keeping it +# is the answer -- and gum draws the prompt on stderr, so a redirected stderr +# would block on a question nobody can see. +data_removed=false +if [[ -t 0 && -t 2 ]]; then + # du answers non-zero when a directory is missing, and pipefail would turn + # that into an aborted removal; the size is worth no such thing. + size=$(du -shc "$HOME/.config/Perplexity" "$HOME/.local/state/perplexity" 2>/dev/null | tail -1 | cut -f1 || true) + if gum confirm --default=false "Also delete your Perplexity data ($size: logins, settings, secret vault and device identity)?"; then + rm -rf \ + "$HOME/.config/Perplexity" \ + "$HOME/.local/state/perplexity" + rm -f "$HOME/.config/perplexity-flags.conf" + data_removed=true + fi +fi echo "" echo "Perplexity has been removed." +if [[ $data_removed == "true" ]]; then + echo "Its logins, settings, secret vault, and device identity are gone too." +else + echo "Nothing of yours was touched: not the logins in ~/.config/Perplexity," + echo "nor the secret vault and device identity in ~/.local/state/perplexity." +fi diff --git a/test/shell.d/remove-ai-test.sh b/test/shell.d/remove-ai-test.sh index 99558353..9d518318 100644 --- a/test/shell.d/remove-ai-test.sh +++ b/test/shell.d/remove-ai-test.sh @@ -15,6 +15,22 @@ printf 'drop:%s\n' "$*" >>"$TEST_LOG" SCRIPT chmod +x "$tmp_dir/bin/omarchy-pkg-drop" +# omarchy-remove-ai-perplexity asks through gum whether the user's data goes +# too. The stub answers "no" unless a test says otherwise and logs the call: a +# real gum would hang the run, and one that answered "yes" on its own would be +# the data loss the default-no exists to prevent. It logs to its own file +# because the OpenClaw section below greps TEST_LOG to prove gum was never +# reached, and the pty runs here call it on purpose. +cat >"$tmp_dir/bin/gum" <<'SCRIPT' +#!/bin/bash +printf 'gum:%s\n' "$*" >>"$TEST_GUM_LOG" +exit "${TEST_GUM_STATUS:-1}" +SCRIPT +chmod +x "$tmp_dir/bin/gum" + +export TEST_GUM_LOG="$tmp_dir/gum-log" +touch "$TEST_GUM_LOG" + export TEST_LOG="$tmp_dir/log" export PATH="$tmp_dir/bin:$PATH" @@ -75,27 +91,84 @@ for kept in .grok .claude.json .npm .local/share/opencode; do done pass "T3 Code removal keeps the agent state it bootstrapped" -# Perplexity's other products (the CLI, Comet) share the perplexity-* cache -# prefix; only the rpc-server runtime is the desktop app's own. -fresh_home -mkdir -p "$HOME/.config/Perplexity" "$HOME/.cache/Perplexity" "$HOME/.cache/perplexity-rpc-server" "$HOME/.cache/perplexity-personal-computer-poc" -touch "$HOME/.config/perplexity-flags.conf" -"$ROOT/bin/omarchy-remove-ai-perplexity" >/dev/null +# Perplexity's other products (the CLI, Comet) share the perplexity-* prefix; +# the desktop app owns only its rpc-server runtime and Electron caches. The +# logins, vault, and flags are the user's and only go when a terminal said so. +seed_perplexity() { + fresh_home + mkdir -p "$HOME/.config/Perplexity" "$HOME/.cache/Perplexity" \ + "$HOME/.cache/perplexity-rpc-server" "$HOME/.local/share/perplexity-rpc-server" \ + "$HOME/.local/state/perplexity" "$HOME/.cache/perplexity-personal-computer-poc" + touch "$HOME/.config/perplexity-flags.conf" +} -for gone in .config/Perplexity .cache/Perplexity .cache/perplexity-rpc-server .config/perplexity-flags.conf; do - [[ ! -e $HOME/$gone ]] || fail "Perplexity removal deletes the desktop app's own data" "$gone" +# /dev/null + +for gone in .cache/Perplexity .cache/perplexity-rpc-server .local/share/perplexity-rpc-server; do + [[ ! -e $HOME/$gone ]] || fail "Perplexity removal deletes the app's runtime and caches" "$gone" done -pass "Perplexity removal deletes the desktop app's own data" +pass "Perplexity removal deletes the app's runtime and caches" -[[ -d $HOME/.cache/perplexity-personal-computer-poc ]] || fail "Perplexity removal keeps other Perplexity products' caches" -pass "Perplexity removal keeps other Perplexity products' caches" +for kept in .config/Perplexity .local/state/perplexity .config/perplexity-flags.conf .cache/perplexity-personal-computer-poc; do + [[ -e $HOME/$kept ]] || fail "Perplexity removal keeps the user's data and other products' caches" "$kept" +done +pass "Perplexity removal keeps the user's data and other products' caches" grep -qx 'drop:perplexity' "$TEST_LOG" || fail "Perplexity removal drops the perplexity package" pass "Perplexity removal drops the perplexity package" +# Without a terminal there is nobody to ask, so gum must not even be reached: +# one that answered "yes" on its own would be a data loss. +! grep -q '^gum:' "$TEST_GUM_LOG" || fail "Perplexity removal keeps the user's data unasked when there is no terminal" +pass "Perplexity removal keeps the user's data unasked when there is no terminal" + +# script(1) puts the remover on a pty, the only way -t 0 answers true in a +# test; the stubbed gum then supplies the answer. +seed_perplexity +script -qec "'$ROOT/bin/omarchy-remove-ai-perplexity'" /dev/null >/dev/null 2>&1 + +[[ -d $HOME/.config/Perplexity && -d $HOME/.local/state/perplexity && -f $HOME/.config/perplexity-flags.conf ]] || + fail "Perplexity removal keeps the user's data when the answer is no" +pass "Perplexity removal keeps the user's data when the answer is no" + +# The stub answers "no" on its own, so only the logged arguments prove the +# real gum would not default to yes on a bare Enter. +grep -q '^gum:confirm --default=false ' "$TEST_GUM_LOG" || + fail "Perplexity removal asks with the destructive answer defaulted off" +pass "Perplexity removal asks with the destructive answer defaulted off" + +# A partial install has no user data to measure; du failing must not abort +# the removal between the package and the prompt. +seed_perplexity +rm -rf "$HOME/.config/Perplexity" "$HOME/.local/state/perplexity" +script -qec "'$ROOT/bin/omarchy-remove-ai-perplexity'" /dev/null >/dev/null 2>&1 || + fail "Perplexity removal survives user-data directories that are already gone" +pass "Perplexity removal survives user-data directories that are already gone" + +# gum draws its prompt on stderr; with stderr redirected the question would be +# invisible, so the remover must keep the data instead of blocking on it. +seed_perplexity +gum_calls_before=$(wc -l <"$TEST_GUM_LOG") +script -qec "'$ROOT/bin/omarchy-remove-ai-perplexity' 2>/dev/null" /dev/null >/dev/null 2>&1 || + fail "Perplexity removal completes when stderr is not a terminal" +[[ -d $HOME/.config/Perplexity ]] && (( $(wc -l <"$TEST_GUM_LOG") == gum_calls_before )) || + fail "Perplexity removal keeps the user's data unasked when stderr is not a terminal" +pass "Perplexity removal keeps the user's data unasked when stderr is not a terminal" + +seed_perplexity +TEST_GUM_STATUS=0 script -qec "'$ROOT/bin/omarchy-remove-ai-perplexity'" /dev/null >/dev/null 2>&1 + +for gone in .config/Perplexity .local/state/perplexity .config/perplexity-flags.conf; do + [[ ! -e $HOME/$gone ]] || fail "Perplexity removal deletes the user's data on an explicit yes" "$gone" +done +pass "Perplexity removal deletes the user's data on an explicit yes" + # Without HOME the rm -rf paths would degrade to /-rooted ones; -u makes that a # refusal instead. -if env -u HOME "$ROOT/bin/omarchy-remove-ai-perplexity" >/dev/null 2>&1; then +if env -u HOME "$ROOT/bin/omarchy-remove-ai-perplexity" /dev/null 2>&1; then fail "Perplexity removal refuses to run without HOME" fi pass "Perplexity removal refuses to run without HOME"