From fa60a8b9bffc2a48707e6e323edd7155914b8852 Mon Sep 17 00:00:00 2001 From: Spencer Bull Date: Tue, 1 Sep 2026 09:26:38 -0500 Subject: [PATCH 1/2] Add the Perplexity desktop app to Install > AI Follows the T3 Code / Grok Bot flow: the Install > AI entry runs omarchy-install-and-launch, so picking it installs the perplexity package on demand and launches the app when the install finishes. Remove > AI drops the package along with the app's own config, flags file, and rpc-server runtime cache, keeping the perplexity-* caches that belong to Perplexity's other products. Like the Hermes remover, it sets -u so an unset HOME is a refusal rather than rm -rf paths rooted at /. The menu mark is a new U+E90B glyph in the Omarchy icon font, so it reaches desktops through the next omarchy-settings release. Co-Authored-By: Fable 5 Co-Authored-By: Codex XHigh --- bin/omarchy-remove-ai-perplexity | 21 +++++++++++++++++++++ default/fonts/omarchy/README.md | 3 ++- default/fonts/omarchy/omarchy.ttf | Bin 5284 -> 5492 bytes default/omarchy/omarchy-menu.jsonc | 2 ++ manual/17-ai.md | 2 +- test/shell.d/menu-test.sh | 2 +- test/shell.d/remove-ai-test.sh | 25 +++++++++++++++++++++++++ 7 files changed, 52 insertions(+), 3 deletions(-) create mode 100755 bin/omarchy-remove-ai-perplexity diff --git a/bin/omarchy-remove-ai-perplexity b/bin/omarchy-remove-ai-perplexity new file mode 100755 index 00000000..c2388738 --- /dev/null +++ b/bin/omarchy-remove-ai-perplexity @@ -0,0 +1,21 @@ +#!/bin/bash + +# omarchy:summary=Remove the Perplexity desktop app along with its configuration and caches. +# omarchy:requires-sudo=true + +# -u so an unset HOME is an error rather than a set of rm -rf paths rooted at /. +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. +rm -rf \ + "$HOME/.config/Perplexity" \ + "$HOME/.cache/Perplexity" \ + "$HOME/.cache/perplexity-rpc-server" +rm -f "$HOME/.config/perplexity-flags.conf" + +echo "" +echo "Perplexity has been removed." diff --git a/default/fonts/omarchy/README.md b/default/fonts/omarchy/README.md index a4ab6935..e538684d 100644 --- a/default/fonts/omarchy/README.md +++ b/default/fonts/omarchy/README.md @@ -13,7 +13,8 @@ The private-use glyphs in `omarchy.ttf` are: - `U+E908` — T3 Code, traced from the app icon in , since upstream publishes no monochrome SVG - `U+E909` — Ori, from , OpenRouter's own mark: Ori ships no separate logo and its product page uses this one - `U+E90A` — Hermes, Font Awesome's staff-snake (CC BY 4.0) from , the mark Hermes serves as its favicon: their app icon is a portrait that reads as a smudge at menu size -- `U+E90C` — OpenClaw, traced from the lobster mascot the openclaw package ships as `dist/control-ui/favicon.svg`, since upstream publishes no monochrome SVG; `E90B` is left for the Perplexity mark already in flight on another branch +- `U+E90B` — Perplexity, from +- `U+E90C` — OpenClaw, traced from the lobster mascot the openclaw package ships as `dist/control-ui/favicon.svg`, since upstream publishes no monochrome SVG The agent marks are monochrome so the menu can render them using the active theme's foreground and selection colors. diff --git a/default/fonts/omarchy/omarchy.ttf b/default/fonts/omarchy/omarchy.ttf index fb9d22a74a6638b60b4f3a701a081a36169fe3db..7a26ed1deacde7f421ccbd80fec05fde1ec369f2 100644 GIT binary patch delta 610 zcmXYtPiPZC6vn@|n>2qd-6oqf6l+5gQftuSnp!+XJg8Odp`{luu4y#Fu32gh2^8uf z2Ty8Q@gRbS2vQIU1gcUG#ft?I{DZVu@F0sJ)m&^3qPX!TbROTl`F%6InR$;7?vCCK zE#egbZEE_+(b*4YPXjc$j6*(a( zQ6=qEl4AOJR7yxLSxzLSa3C6%6|th(cFMLjjf4~p%-YY_?Y@x<=@_4a delta 412 zcmZ9GKS%;m9LK-!-I;MI)p=Qzkc35w6l6q1L$pK?I2h6BW!6D=os@%44lPYlJgI1E zXp9nWX)vKV8iK~AhRSFNa|jyjr(-<6zu)_Qet+JpM=rvL{(?3Qz>FuxCsrO87Xa4u z$&{sM%JX~6y1{bBe-O zY5tV_tZAoo?YHX$kbcNVEIpTDBdmlNSRaAlwr-^#-d>A9H$BMiGxl!w=B4ru_|B<* z3`UW~Vy@&?L}+TxZ{Hb8JNQvEQ-x@NitDFf~H+0i4-MK8;Y$B zU;(1d?NQ1~i_0)5`_V AI_ menu also carries a few graphical AI apps: the ChatGPT desktop app, Grok Bot for chatting with xAI's models, Hermes Desktop, and OpenClaw. +The _Install > AI_ menu also carries a few graphical AI apps: the ChatGPT desktop app, Grok Bot for chatting with xAI's models, Hermes Desktop, OpenClaw, and the Perplexity desktop app. Hermes Desktop is the one to know about, because there is only ever one Hermes on a machine. The app only runs against a runtime built from its own commit, so it installs one of its own under `~/.hermes` on first launch, which takes a few minutes and shows its own progress. From then on that is the Hermes the terminal `hermes` command and the default agent use too, whichever order you installed them in. Removing the app under _Remove > AI_ takes that runtime with it, and keeps your chats, memories, and the skills Hermes wrote for itself. diff --git a/test/shell.d/menu-test.sh b/test/shell.d/menu-test.sh index 3907a8e2..c65ec000 100644 --- a/test/shell.d/menu-test.sh +++ b/test/shell.d/menu-test.sh @@ -638,5 +638,5 @@ assert( JS font_charset=$(fc-query --format='%{charset}' "$ROOT/default/fonts/omarchy/omarchy.ttf") -[[ $font_charset == *"e900-e90a"* && $font_charset == *"e90c"* ]] || fail "Omarchy icon font includes every custom menu glyph" +[[ $font_charset == *"e900-e90c"* ]] || fail "Omarchy icon font includes every custom menu glyph" pass "Omarchy icon font includes the official agent marks" diff --git a/test/shell.d/remove-ai-test.sh b/test/shell.d/remove-ai-test.sh index a10bc3b6..99558353 100644 --- a/test/shell.d/remove-ai-test.sh +++ b/test/shell.d/remove-ai-test.sh @@ -75,6 +75,31 @@ 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 + +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" +done +pass "Perplexity removal deletes the desktop app's own data" + +[[ -d $HOME/.cache/perplexity-personal-computer-poc ]] || fail "Perplexity removal keeps other Perplexity products' caches" +pass "Perplexity removal keeps other Perplexity products' caches" + +grep -qx 'drop:perplexity' "$TEST_LOG" || fail "Perplexity removal drops the perplexity package" +pass "Perplexity removal drops the perplexity package" + +# 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 + fail "Perplexity removal refuses to run without HOME" +fi +pass "Perplexity removal refuses to run without HOME" + # ~/.grok belongs to the Grok CLI that omarchy-default-agent installs. fresh_home mkdir -p "$HOME/.config/Grok Bot" "$HOME/.grokbot" "$HOME/.grok" From eea678b480c31b93c93593fa6733eaddb8bb1f23 Mon Sep 17 00:00:00 2001 From: Spencer Bull Date: Sat, 5 Sep 2026 08:59:46 -0500 Subject: [PATCH 2/2] Ask, default no, before Remove Perplexity deletes the user's data Perplexity 26.9.1 keeps the secret vault and device identity in ~/.local/state/perplexity and its runtime downloads in ~/.local/share/perplexity-rpc-server; the remover knew neither path, so it deleted the logins unconditionally while leaving the credentials behind. Now the runtime and Electron caches always go, and the logins, vault, and launcher flags go only on an explicit yes at a terminal, default no, the same choice Remove OpenClaw puts in front of the user. The prompt needs stderr on the terminal too: gum draws it there, so a redirected stderr means keeping the data, not blocking on a question nobody can see. Co-Authored-By: Codex XHigh Co-Authored-By: Sonnet 5 --- bin/omarchy-remove-ai-perplexity | 42 +++++++++++--- test/shell.d/remove-ai-test.sh | 97 ++++++++++++++++++++++++++++---- 2 files changed, 120 insertions(+), 19 deletions(-) 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"