Add Cursor CLI as a coding agent choice (#10465)

* Add Cursor CLI as a coding agent choice

* Launch Cursor CLI through its agent subcommand with --trust

Cursor CLI still dispatches a one-word prompt that names one of its
subcommands (update, login, help) even after a bare --, so name the agent
subcommand outright and pass the prompt behind -- there, where it also
keeps a prompt starting with a dash from being read as an option. --yolo
only auto-allows commands; the workspace trust dialog is skipped only by
--trust, and a launcher that must not stop to ask needs both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Leave an official Cursor CLI install alone

Cursor's own installer symlinks ~/.local/bin/cursor-agent, the same path the
mise wrapper takes. The migration now installs the wrapper only when no
cursor-agent command exists, and Remove Preinstalls deletes the path only
when it holds the wrapper omarchy-mise-install wrote, the way the Hermes
wrapper is handled. Selecting the agent treats an executable at that path
other than the wrapper as the user's own install and skips mise, since the
mise shims precede ~/.local/bin on PATH and a mise copy would only shadow
it. The wrapper resolves through mise's registry, which lists cursor-agent
from 2026.8.15 on.

The tests write a real cursor-agent stub before Remove Preinstalls runs,
cover the preinstall opt-out for the new migration, and check that a
symlinked official install survives removal and selection alike while a
dead file at the same path still installs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Give Cursor its brand mark and one name in the menu

Add Cursor's mark to the Omarchy icon font as U+E90D and point the agent
entry and both editor entries at it, so one brand is drawn one way across
the menu. Label the agent entry "Cursor CLI", the name the command and the
manual already use, and spell it the same in the migration and the tests.
Append the manual row after the others at the standard width.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Keep an official Cursor CLI install through a user re-provision

User setup writes every mise wrapper unconditionally, which is fine on a
fresh install but replaces the symlink Cursor's own installer leaves at the
same path when omarchy-provision-user runs again with --force. Guard that
one line the way the migration does.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: John Cavanaugh <59479+cavanaug@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-09-06 17:07:40 +02:00
1 parent 41b6cc6965
commit a62e34ea8e
11 files changed
+110 -10

No files matched your search

+8
View File
@@ -95,6 +95,14 @@ codex)
command=(codex --approve-for-me) command=(codex --approve-for-me)
[[ -n ${prompt:-} ]] && command+=(-- "$prompt") [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
;; ;;
cursor-agent)
# --yolo covers commands only; the workspace trust dialog has its own flag.
# A one-word prompt naming a subcommand (update, login, help) still runs that
# subcommand after a bare --, so the agent subcommand is named outright, and
# -- after it keeps a prompt starting with a dash from being read as an option.
command=(cursor-agent --yolo --trust)
[[ -n ${prompt:-} ]] && command+=(agent -- "$prompt")
;;
hermes) hermes)
if [[ -n ${prompt:-} ]]; then if [[ -n ${prompt:-} ]]; then
command=(env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=$prompt") command=(env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=$prompt")
+12 -4
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# omarchy:summary=Set and launch the default coding agent # omarchy:summary=Set and launch the default coding agent
# omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush] # omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush|cursor-agent]
# omarchy:examples=omarchy default agent | omarchy default agent codex | omarchy default agent claude # omarchy:examples=omarchy default agent | omarchy default agent codex | omarchy default agent claude
installing=false installing=false
@@ -36,8 +36,9 @@ openclaw) agent="openclaw"; name="OpenClaw"; agent_installer="omarchy-install-op
agy | antigravity | antigravity-cli | gemini | gemini-cli) agent="agy"; name="Antigravity"; agent_package="antigravity-cli" ;; agy | antigravity | antigravity-cli | gemini | gemini-cli) agent="agy"; name="Antigravity"; agent_package="antigravity-cli" ;;
hermes) agent="hermes"; name="Hermes"; agent_installer="omarchy-install-hermes-cli" ;; hermes) agent="hermes"; name="Hermes"; agent_installer="omarchy-install-hermes-cli" ;;
copilot | github-copilot) agent="copilot"; name="GitHub Copilot" ;; copilot | github-copilot) agent="copilot"; name="GitHub Copilot" ;;
cursor | cursor-agent) agent="cursor-agent"; name="Cursor CLI" ;;
*) *)
echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush>" echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush|cursor-agent>"
exit 1 exit 1
;; ;;
esac esac
@@ -56,8 +57,15 @@ if [[ -n ${agent_installer:-} ]]; then
agent_present() { "$agent_installer" --check; } agent_present() { "$agent_installer" --check; }
agent_install() { "$agent_installer" --now; } agent_install() { "$agent_installer" --now; }
else else
agent_present() { mise where "$agent_package" &>/dev/null; } # Anything at the wrapper's path other than the wrapper is the user's own
agent_install() { mise use -g "$agent_package"; } # install, such as the symlink Cursor's installer leaves. A mise copy would
# only shadow it, since the mise shims precede ~/.local/bin on PATH.
user_install() {
[[ -x $HOME/.local/bin/$agent ]] &&
{ [[ -L $HOME/.local/bin/$agent ]] || ! grep -q '^mise use -g' "$HOME/.local/bin/$agent"; }
}
agent_present() { user_install || mise where "$agent_package" &>/dev/null; }
agent_install() { user_install || mise use -g "$agent_package"; }
fi fi
if [[ $installing == "false" ]] && ! agent_present; then if [[ $installing == "false" ]] && ! agent_present; then
+7
View File
@@ -17,6 +17,13 @@ if gum confirm "Are you sure you want to remove all preinstalled web apps, TUI w
~/.local/bin/gh ~/.local/bin/opencode ~/.local/bin/playwright ~/.local/bin/playwright-cli ~/.local/bin/pi \ ~/.local/bin/gh ~/.local/bin/opencode ~/.local/bin/playwright ~/.local/bin/playwright-cli ~/.local/bin/pi \
~/.local/bin/omp ~/.local/bin/ori ~/.local/bin/grok ~/.local/bin/crush ~/.local/bin/ghui ~/.local/bin/hunk ~/.local/bin/omp ~/.local/bin/ori ~/.local/bin/grok ~/.local/bin/crush ~/.local/bin/ghui ~/.local/bin/hunk
# Cursor's own installer links ~/.local/bin/cursor-agent as well, so only
# the mise wrapper omarchy-mise-install wrote is a preinstall.
if [[ -f ~/.local/bin/cursor-agent && ! -L ~/.local/bin/cursor-agent ]] &&
grep -Eq '^mise use -g .*"cursor-agent"' ~/.local/bin/cursor-agent; then
rm -f ~/.local/bin/cursor-agent
fi
# Only the wrapper omarchy-install-hermes-cli wrote is a preinstall. Hermes # Only the wrapper omarchy-install-hermes-cli wrote is a preinstall. Hermes
# Desktop's command, an official install, or anything else at that path is # Desktop's command, an official install, or anything else at that path is
# the user's, so it is the installer that decides whether the wrapper is its # the user's, so it is the installer that decides whether the wrapper is its
+1
View File
@@ -15,6 +15,7 @@ The private-use glyphs in `omarchy.ttf` are:
- `U+E90A` — Hermes, Font Awesome's staff-snake (CC BY 4.0) from <https://fontawesome.com/icons/staff-snake>, the mark Hermes serves as its favicon: their app icon is a portrait that reads as a smudge at menu size - `U+E90A` — Hermes, Font Awesome's staff-snake (CC BY 4.0) from <https://fontawesome.com/icons/staff-snake>, the mark Hermes serves as its favicon: their app icon is a portrait that reads as a smudge at menu size
- `U+E90B` — Perplexity, from <https://simpleicons.org/icons/perplexity.svg> - `U+E90B` — Perplexity, from <https://simpleicons.org/icons/perplexity.svg>
- `U+E90C` — OpenClaw, traced from the lobster mascot the openclaw package ships as `dist/control-ui/favicon.svg`, since upstream publishes no monochrome SVG - `U+E90C` — OpenClaw, traced from the lobster mascot the openclaw package ships as `dist/control-ui/favicon.svg`, since upstream publishes no monochrome SVG
- `U+E90D` — Cursor, from <https://simpleicons.org/icons/cursor.svg>
The agent marks are monochrome so the menu can render them using the active The agent marks are monochrome so the menu can render them using the active
theme's foreground and selection colors. theme's foreground and selection colors.
Binary file not shown.
+3 -2
View File
@@ -140,6 +140,7 @@
"setup.default.agent.codex": {"icon":"","iconFont":"omarchy","label":"Codex","checked":"[[ \"$(omarchy-default-agent)\" == \"codex\" ]]","action":"omarchy-default-agent codex"}, "setup.default.agent.codex": {"icon":"","iconFont":"omarchy","label":"Codex","checked":"[[ \"$(omarchy-default-agent)\" == \"codex\" ]]","action":"omarchy-default-agent codex"},
"setup.default.agent.copilot": {"icon":"","label":"Copilot","checked":"[[ \"$(omarchy-default-agent)\" == \"copilot\" ]]","action":"omarchy-default-agent copilot"}, "setup.default.agent.copilot": {"icon":"","label":"Copilot","checked":"[[ \"$(omarchy-default-agent)\" == \"copilot\" ]]","action":"omarchy-default-agent copilot"},
"setup.default.agent.crush": {"icon":"󰋑","label":"Crush","checked":"[[ \"$(omarchy-default-agent)\" == \"crush\" ]]","action":"omarchy-default-agent crush"}, "setup.default.agent.crush": {"icon":"󰋑","label":"Crush","checked":"[[ \"$(omarchy-default-agent)\" == \"crush\" ]]","action":"omarchy-default-agent crush"},
"setup.default.agent.cursor-agent": {"icon":"","iconFont":"omarchy","label":"Cursor CLI","checked":"[[ \"$(omarchy-default-agent)\" == \"cursor-agent\" ]]","action":"omarchy-default-agent cursor-agent"},
"setup.default.agent.grok": {"icon":"","iconFont":"omarchy","label":"Grok","checked":"[[ \"$(omarchy-default-agent)\" == \"grok\" ]]","action":"omarchy-default-agent grok"}, "setup.default.agent.grok": {"icon":"","iconFont":"omarchy","label":"Grok","checked":"[[ \"$(omarchy-default-agent)\" == \"grok\" ]]","action":"omarchy-default-agent grok"},
"setup.default.agent.hermes": {"icon":"","iconFont":"omarchy","label":"Hermes","checked":"[[ \"$(omarchy-default-agent)\" == \"hermes\" ]]","action":"omarchy-default-agent hermes"}, "setup.default.agent.hermes": {"icon":"","iconFont":"omarchy","label":"Hermes","checked":"[[ \"$(omarchy-default-agent)\" == \"hermes\" ]]","action":"omarchy-default-agent hermes"},
"setup.default.agent.omp": {"icon":"","iconFont":"omarchy","label":"omp","checked":"[[ \"$(omarchy-default-agent)\" == \"omp\" ]]","action":"omarchy-default-agent omp"}, "setup.default.agent.omp": {"icon":"","iconFont":"omarchy","label":"omp","checked":"[[ \"$(omarchy-default-agent)\" == \"omp\" ]]","action":"omarchy-default-agent omp"},
@@ -163,7 +164,7 @@
"setup.default.editor": {"icon":"","label":"Editor","title":"Default Editor"}, "setup.default.editor": {"icon":"","label":"Editor","title":"Default Editor"},
"setup.default.editor.neovim": {"icon":"","label":"Neovim","checked":"[[ \"$(omarchy-default-editor)\" == \"nvim\" ]]","action":"omarchy-default-editor nvim"}, "setup.default.editor.neovim": {"icon":"","label":"Neovim","checked":"[[ \"$(omarchy-default-editor)\" == \"nvim\" ]]","action":"omarchy-default-editor nvim"},
"setup.default.editor.vscode": {"icon":"","label":"VSCode","checked":"[[ \"$(omarchy-default-editor)\" == \"code\" ]]","action":"omarchy-default-editor code"}, "setup.default.editor.vscode": {"icon":"","label":"VSCode","checked":"[[ \"$(omarchy-default-editor)\" == \"code\" ]]","action":"omarchy-default-editor code"},
"setup.default.editor.cursor": {"icon":"","label":"Cursor","checked":"[[ \"$(omarchy-default-editor)\" == \"cursor\" ]]","action":"omarchy-default-editor cursor"}, "setup.default.editor.cursor": {"icon":"","iconFont":"omarchy","label":"Cursor","checked":"[[ \"$(omarchy-default-editor)\" == \"cursor\" ]]","action":"omarchy-default-editor cursor"},
"setup.default.editor.zed": {"icon":"","label":"Zed","checked":"[[ \"$(omarchy-default-editor)\" == \"zeditor\" ]]","action":"omarchy-default-editor zed"}, "setup.default.editor.zed": {"icon":"","label":"Zed","checked":"[[ \"$(omarchy-default-editor)\" == \"zeditor\" ]]","action":"omarchy-default-editor zed"},
"setup.default.editor.sublime": {"icon":"","label":"Sublime Text","checked":"[[ \"$(omarchy-default-editor)\" == \"sublime_text\" ]]","action":"omarchy-default-editor sublime_text"}, "setup.default.editor.sublime": {"icon":"","label":"Sublime Text","checked":"[[ \"$(omarchy-default-editor)\" == \"sublime_text\" ]]","action":"omarchy-default-editor sublime_text"},
"setup.default.editor.helix": {"icon":"","label":"Helix","checked":"[[ \"$(omarchy-default-editor)\" == \"helix\" ]]","action":"omarchy-default-editor helix"}, "setup.default.editor.helix": {"icon":"","label":"Helix","checked":"[[ \"$(omarchy-default-editor)\" == \"helix\" ]]","action":"omarchy-default-editor helix"},
@@ -228,7 +229,7 @@
"install.service.bitwarden": {"icon":"󰟵","label":"Bitwarden","disabled":"omarchy-pkg-present bitwarden","action":"omarchy-install-and-launch Bitwarden 'bitwarden bitwarden-cli' bitwarden"}, "install.service.bitwarden": {"icon":"󰟵","label":"Bitwarden","disabled":"omarchy-pkg-present bitwarden","action":"omarchy-install-and-launch Bitwarden 'bitwarden bitwarden-cli' bitwarden"},
"install.service.chromium-account": {"icon":"","label":"Chromium Account","when":"[[ -f ~/.config/chromium-flags.conf ]]","disabled":"grep -q oauth2-client-id ~/.config/chromium-flags.conf","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-chromium-google-account"}, "install.service.chromium-account": {"icon":"","label":"Chromium Account","when":"[[ -f ~/.config/chromium-flags.conf ]]","disabled":"grep -q oauth2-client-id ~/.config/chromium-flags.conf","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-chromium-google-account"},
"install.editor.vscode": {"icon":"","label":"VSCode","disabled":"omarchy-pkg-present visual-studio-code-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-vscode"}, "install.editor.vscode": {"icon":"","label":"VSCode","disabled":"omarchy-pkg-present visual-studio-code-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-vscode"},
"install.editor.cursor": {"icon":"","label":"Cursor","disabled":"omarchy-pkg-present cursor-bin","action":"omarchy-install-and-launch Cursor cursor-bin cursor"}, "install.editor.cursor": {"icon":"","iconFont":"omarchy","label":"Cursor","disabled":"omarchy-pkg-present cursor-bin","action":"omarchy-install-and-launch Cursor cursor-bin cursor"},
"install.editor.zed": {"icon":"","label":"Zed","disabled":"omarchy-pkg-present zed","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-zed"}, "install.editor.zed": {"icon":"","label":"Zed","disabled":"omarchy-pkg-present zed","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-zed"},
"install.editor.sublime": {"icon":"","label":"Sublime Text","disabled":"omarchy-pkg-present sublime-text-4","action":"omarchy-install-and-launch 'Sublime Text' sublime-text-4 sublime_text"}, "install.editor.sublime": {"icon":"","label":"Sublime Text","disabled":"omarchy-pkg-present sublime-text-4","action":"omarchy-install-and-launch 'Sublime Text' sublime-text-4 sublime_text"},
"install.editor.helix": {"icon":"","label":"Helix","disabled":"omarchy-pkg-present helix","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-helix"}, "install.editor.helix": {"icon":"","label":"Helix","disabled":"omarchy-pkg-present helix","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-helix"},
+2
View File
@@ -9,6 +9,8 @@ omarchy-mise-install npm:playwright playwright
omarchy-mise-install pi omarchy-mise-install pi
omarchy-mise-install github:can1357/oh-my-pi omp omarchy-mise-install github:can1357/oh-my-pi omp
omarchy-mise-install npm:@xai-official/grok grok omarchy-mise-install npm:@xai-official/grok grok
# Cursor's own installer links the same path, so a re-provision keeps it.
omarchy-cmd-missing cursor-agent && omarchy-mise-install cursor-agent
omarchy-mise-install npm:@kitlangton/ghui ghui omarchy-mise-install npm:@kitlangton/ghui ghui
omarchy-mise-install aqua:modem-dev/hunk hunk omarchy-mise-install aqua:modem-dev/hunk hunk
omarchy-mise-install github:basecamp/hey-cli hey omarchy-mise-install github:basecamp/hey-cli hey
+1
View File
@@ -15,6 +15,7 @@ Omarchy treats AI coding agents as first-class citizens, but it doesn't pick a f
| `omp` | [Oh My Pi](https://github.com/can1357/oh-my-pi) | | `omp` | [Oh My Pi](https://github.com/can1357/oh-my-pi) |
| `ori` | [Ori](https://openrouter.ai/docs/guides/ori/harness), OpenRouter's harness | | `ori` | [Ori](https://openrouter.ai/docs/guides/ori/harness), OpenRouter's harness |
| `hermes` | [Hermes](https://hermes-agent.nousresearch.com/), Nous Research's agent | | `hermes` | [Hermes](https://hermes-agent.nousresearch.com/), Nous Research's agent |
| `cursor-agent` | [Cursor CLI](https://cursor.com/cli) |
`ori` is the odd one out: it runs the other harnesses against OpenRouter's whole model catalog, so `ori claude`, `ori codex`, or `ori opencode` start those agents on whichever model you point them at, and `ori code` is Ori's own agent. `ori` is the odd one out: it runs the other harnesses against OpenRouter's whole model catalog, so `ori claude`, `ori codex`, or `ori opencode` start those agents on whichever model you point them at, and `ori code` is Ori's own agent.
+8
View File
@@ -0,0 +1,8 @@
echo "Install Cursor CLI via mise wrapper"
# Cursor's own installer links ~/.local/bin/cursor-agent, so an existing
# command is the user's and stays. The wrapper resolves cursor-agent through
# mise's registry, which lists it from 2026.8.15 on.
if omarchy-cmd-missing cursor-agent && [[ ! -f $HOME/.local/state/omarchy/preinstalls-removed ]]; then
omarchy-mise-install cursor-agent
fi
+65 -2
View File
@@ -98,6 +98,7 @@ omp_package="github:can1357/oh-my-pi"
crush_package="crush" crush_package="crush"
agy_package="antigravity-cli" agy_package="antigravity-cli"
ori_package="github:OpenRouterLabs/ori-releases" ori_package="github:OpenRouterLabs/ori-releases"
cursor_agent_package="cursor-agent"
assert_lazy_stub() { assert_lazy_stub() {
local package=$1 local package=$1
@@ -116,16 +117,23 @@ assert_lazy_stub "$grok_package" grok
assert_lazy_stub "$omp_package" omp assert_lazy_stub "$omp_package" omp
assert_lazy_stub "$crush_package" crush assert_lazy_stub "$crush_package" crush
assert_lazy_stub "$ori_package" ori assert_lazy_stub "$ori_package" ori
assert_lazy_stub "$cursor_agent_package" cursor-agent
pass "custom agent lazy stubs preserve their mise packages" pass "custom agent lazy stubs preserve their mise packages"
source "$ROOT/install/user/mise.sh" OMARCHY_TEST_MISSING_COMMAND=cursor-agent source "$ROOT/install/user/mise.sh"
grep -Fx "$agy_package agy" "$stub_log" >/dev/null || fail "user setup creates the Antigravity lazy stub" grep -Fx "$agy_package agy" "$stub_log" >/dev/null || fail "user setup creates the Antigravity lazy stub"
grep -Fx "$grok_package grok" "$stub_log" >/dev/null || fail "user setup creates the Grok lazy stub" grep -Fx "$grok_package grok" "$stub_log" >/dev/null || fail "user setup creates the Grok lazy stub"
grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null || fail "user setup creates the Cursor CLI lazy stub"
grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "user setup creates the Oh My Pi lazy stub" grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "user setup creates the Oh My Pi lazy stub"
grep -Fx "$crush_package" "$stub_log" >/dev/null || fail "user setup creates the Crush lazy stub" grep -Fx "$crush_package" "$stub_log" >/dev/null || fail "user setup creates the Crush lazy stub"
grep -Fx "$ori_package ori" "$stub_log" >/dev/null || fail "user setup creates the Ori lazy stub" grep -Fx "$ori_package ori" "$stub_log" >/dev/null || fail "user setup creates the Ori lazy stub"
pass "user setup creates the custom agent lazy stubs" pass "user setup creates the custom agent lazy stubs"
: >"$stub_log"
source "$ROOT/install/user/mise.sh"
grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null && fail "user setup replaces an existing cursor-agent command"
pass "user setup keeps an existing Cursor CLI install"
: >"$stub_log" : >"$stub_log"
source "$ROOT/migrations/1785617047.sh" >/dev/null source "$ROOT/migrations/1785617047.sh" >/dev/null
grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "Oh My Pi migration creates a working lazy stub" grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "Oh My Pi migration creates a working lazy stub"
@@ -134,6 +142,17 @@ grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "Oh My Pi migration c
source "$ROOT/migrations/1787342993.sh" >/dev/null source "$ROOT/migrations/1787342993.sh" >/dev/null
grep -Fx "$ori_package ori" "$stub_log" >/dev/null || fail "Ori migration creates a working lazy stub" grep -Fx "$ori_package ori" "$stub_log" >/dev/null || fail "Ori migration creates a working lazy stub"
: >"$stub_log"
export OMARCHY_TEST_MISSING_COMMAND=cursor-agent
source "$ROOT/migrations/1788577553.sh" >/dev/null
unset OMARCHY_TEST_MISSING_COMMAND
grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null || fail "Cursor CLI migration creates a working lazy stub"
: >"$stub_log"
source "$ROOT/migrations/1788577553.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Cursor CLI migration reinstalls an existing cursor-agent command"
pass "Cursor CLI migration preserves an existing Cursor CLI install"
: >"$stub_log" : >"$stub_log"
source "$ROOT/migrations/1785846769.sh" >/dev/null source "$ROOT/migrations/1785846769.sh" >/dev/null
grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "agent migration repairs the Oh My Pi lazy stub" grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "agent migration repairs the Oh My Pi lazy stub"
@@ -216,6 +235,7 @@ touch "$test_home/.local/state/omarchy/preinstalls-removed"
source "$ROOT/migrations/1785617047.sh" >/dev/null source "$ROOT/migrations/1785617047.sh" >/dev/null
source "$ROOT/migrations/1785846769.sh" >/dev/null source "$ROOT/migrations/1785846769.sh" >/dev/null
source "$ROOT/migrations/1787342993.sh" >/dev/null source "$ROOT/migrations/1787342993.sh" >/dev/null
OMARCHY_TEST_MISSING_COMMAND=cursor-agent source "$ROOT/migrations/1788577553.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "agent migrations respect the preinstall opt-out" [[ ! -s $stub_log ]] || fail "agent migrations respect the preinstall opt-out"
[[ ! -e $test_home/.local/bin/omp ]] || fail "agent migration removes the obsolete Oh My Pi wrapper after opt-out" [[ ! -e $test_home/.local/bin/omp ]] || fail "agent migration removes the obsolete Oh My Pi wrapper after opt-out"
@@ -242,11 +262,20 @@ pass "agent migrations install working wrappers without overriding the preinstal
touch "$test_home/.local/bin/agy" "$test_home/.local/bin/ori" touch "$test_home/.local/bin/agy" "$test_home/.local/bin/ori"
omarchy-remove-preinstalls >/dev/null omarchy-remove-preinstalls >/dev/null
for command in agy omp ori grok crush; do for command in agy omp ori grok crush cursor-agent; do
[[ ! -e $test_home/.local/bin/$command ]] || fail "Remove Preinstalls deletes the $command lazy stub" [[ ! -e $test_home/.local/bin/$command ]] || fail "Remove Preinstalls deletes the $command lazy stub"
done done
pass "Remove Preinstalls deletes every optional agent lazy stub" pass "Remove Preinstalls deletes every optional agent lazy stub"
# Cursor's installer links the same path, so anything but the mise wrapper is
# the user's own install.
touch "$test_home/.local/bin/cursor-agent.official"
ln -s cursor-agent.official "$test_home/.local/bin/cursor-agent"
omarchy-remove-preinstalls >/dev/null
[[ -L $test_home/.local/bin/cursor-agent ]] || fail "Remove Preinstalls keeps an official Cursor CLI install"
rm -f "$test_home/.local/bin/cursor-agent" "$test_home/.local/bin/cursor-agent.official"
pass "Remove Preinstalls keeps an official Cursor CLI install"
[[ -z $(omarchy-default-agent) ]] || fail "default agent is unset until one is chosen" [[ -z $(omarchy-default-agent) ]] || fail "default agent is unset until one is chosen"
pass "default agent is unset until one is chosen" pass "default agent is unset until one is chosen"
@@ -307,6 +336,8 @@ declare -A expected_agents=(
[gemini-cli]="agy" [gemini-cli]="agy"
[copilot]="copilot" [copilot]="copilot"
[github-copilot]="copilot" [github-copilot]="copilot"
[cursor]="cursor-agent"
[cursor-agent]="cursor-agent"
) )
declare -A expected_packages=( declare -A expected_packages=(
@@ -320,6 +351,7 @@ declare -A expected_packages=(
[grok]="$grok_package" [grok]="$grok_package"
[agy]="$agy_package" [agy]="$agy_package"
[copilot]="copilot" [copilot]="copilot"
[cursor-agent]="$cursor_agent_package"
) )
for selection in "${!expected_agents[@]}"; do for selection in "${!expected_agents[@]}"; do
@@ -380,6 +412,35 @@ mapfile -d '' -t agent_open_args <"$agent_open_log"
fail "installed agent opens in a new terminal after selection" fail "installed agent opens in a new terminal after selection"
pass "installed agents select and open without notifications" pass "installed agents select and open without notifications"
# Cursor's installer links the wrapper's path, and the mise shims precede
# ~/.local/bin, so a mise copy would shadow the user's own install.
touch "$test_home/.local/bin/cursor-agent.official"
chmod +x "$test_home/.local/bin/cursor-agent.official"
ln -s cursor-agent.official "$test_home/.local/bin/cursor-agent"
: >"$terminal_log"
: >"$mise_log"
: >"$agent_open_log"
omarchy-default-agent cursor-agent
[[ ! -s $terminal_log ]] || fail "an official Cursor CLI install needs no install terminal"
[[ ! -s $mise_log ]] || fail "an official Cursor CLI install is left to itself by mise"
[[ $(<"$agent_file") == "cursor-agent" ]] || fail "an official Cursor CLI install becomes the default"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 1 && ${agent_open_args[0]} == "omarchy-agent" ]] ||
fail "an official Cursor CLI install opens after selection"
rm -f "$test_home/.local/bin/cursor-agent" "$test_home/.local/bin/cursor-agent.official"
printf '%s\n' copilot >"$agent_file"
pass "selecting an official Cursor CLI install skips mise"
# A file nothing can run is not an install; the wrapper is still wanted.
touch "$test_home/.local/bin/cursor-agent"
: >"$terminal_log"
omarchy-default-agent cursor-agent
mapfile -d '' -t terminal_args <"$terminal_log"
[[ ${terminal_args[*]} == "omarchy-default-agent --install cursor-agent" ]] ||
fail "a dead file at the wrapper's path still installs Cursor CLI"
rm -f "$test_home/.local/bin/cursor-agent"
pass "a dead file at the wrapper's path does not pass for an install"
: >"$agent_open_log" : >"$agent_open_log"
if omarchy-default-agent unsupported >"$test_tmp/invalid-output" 2>&1; then if omarchy-default-agent unsupported >"$test_tmp/invalid-output" 2>&1; then
fail "default agent rejects unsupported providers" fail "default agent rejects unsupported providers"
@@ -464,6 +525,7 @@ assert_launch claude claude --permission-mode auto -- "Review this project"
assert_launch codex codex --approve-for-me -- "Review this project" assert_launch codex codex --approve-for-me -- "Review this project"
assert_launch crush crush run "Review this project" assert_launch crush crush run "Review this project"
assert_launch grok grok --permission-mode bypassPermissions -- "Review this project" assert_launch grok grok --permission-mode bypassPermissions -- "Review this project"
assert_launch cursor-agent cursor-agent --yolo --trust agent -- "Review this project"
assert_launch hermes env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=Review this project" assert_launch hermes env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=Review this project"
assert_launch agy agy --dangerously-skip-permissions --prompt-interactive "Review this project" assert_launch agy agy --dangerously-skip-permissions --prompt-interactive "Review this project"
assert_launch copilot copilot --allow-all --interactive "Review this project" assert_launch copilot copilot --allow-all --interactive "Review this project"
@@ -484,6 +546,7 @@ assert_bypass claude claude --permission-mode auto
assert_bypass codex codex --approve-for-me assert_bypass codex codex --approve-for-me
assert_bypass crush crush --yolo assert_bypass crush crush --yolo
assert_bypass grok grok --permission-mode bypassPermissions assert_bypass grok grok --permission-mode bypassPermissions
assert_bypass cursor-agent cursor-agent --yolo --trust
assert_bypass hermes hermes --yolo assert_bypass hermes hermes --yolo
assert_bypass agy agy --dangerously-skip-permissions assert_bypass agy agy --dangerously-skip-permissions
assert_bypass copilot copilot --allow-all assert_bypass copilot copilot --allow-all
+3 -2
View File
@@ -228,6 +228,7 @@ const expectedAgents = {
openclaw: { icon: '\ue90c', iconFont: 'omarchy', label: 'OpenClaw' }, openclaw: { icon: '\ue90c', iconFont: 'omarchy', label: 'OpenClaw' },
copilot: { icon: '', label: 'Copilot' }, copilot: { icon: '', label: 'Copilot' },
crush: { icon: '󰋑', label: 'Crush' }, crush: { icon: '󰋑', label: 'Crush' },
'cursor-agent': { icon: '\ue90d', iconFont: 'omarchy', label: 'Cursor CLI' },
} }
assert( assert(
Object.entries(expectedAgents).every(([agent, expected]) => { Object.entries(expectedAgents).every(([agent, expected]) => {
@@ -246,7 +247,7 @@ assertDeepEqual(
defaultItems defaultItems
.filter(item => item.parent === 'setup.default.agent') .filter(item => item.parent === 'setup.default.agent')
.map(item => item.label), .map(item => item.label),
['Antigravity', 'Claude', 'Codex', 'Copilot', 'Crush', 'Grok', 'Hermes', 'omp', 'OpenClaw', 'OpenCode', 'Ori', 'Pi'], ['Antigravity', 'Claude', 'Codex', 'Copilot', 'Crush', 'Cursor CLI', 'Grok', 'Hermes', 'omp', 'OpenClaw', 'OpenCode', 'Ori', 'Pi'],
'menu sorts coding agents alphabetically' 'menu sorts coding agents alphabetically'
) )
const expectedDefaults = { const expectedDefaults = {
@@ -638,5 +639,5 @@ assert(
JS JS
font_charset=$(fc-query --format='%{charset}' "$ROOT/default/fonts/omarchy/omarchy.ttf") font_charset=$(fc-query --format='%{charset}' "$ROOT/default/fonts/omarchy/omarchy.ttf")
[[ $font_charset == *"e900-e90c"* ]] || fail "Omarchy icon font includes every custom menu glyph" [[ $font_charset == *"e900-e90d"* ]] || fail "Omarchy icon font includes every custom menu glyph"
pass "Omarchy icon font includes the official agent marks" pass "Omarchy icon font includes the official agent marks"