From a9e1c01ee9344e495a04b4b1a949391286144bae Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 6 Sep 2026 17:07:40 +0200 Subject: [PATCH] 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 * 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 * 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 * 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 --------- Co-authored-by: John Cavanaugh <59479+cavanaug@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 (cherry picked from commit a62e34ea8e04f0aadb68e9ab6136b7fd475ad06d) (cherry picked from commit 1c05f141f158b3521c193b66f03350aa94719d95) --- bin/omarchy-agent | 8 ++++ bin/omarchy-default-agent | 16 +++++-- bin/omarchy-remove-preinstalls | 7 +++ default/fonts/omarchy/README.md | 1 + default/fonts/omarchy/omarchy.ttf | Bin 5316 -> 5012 bytes default/omarchy/omarchy-menu.jsonc | 5 +- install/user/mise.sh | 2 + manual/17-ai.md | 2 +- migrations/1788577553.sh | 8 ++++ test/shell.d/default-agent-test.sh | 67 ++++++++++++++++++++++++++- test/shell.d/menu-test.sh | 5 +- test/shell.d/release-ai-port-test.sh | 2 +- 12 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 migrations/1788577553.sh diff --git a/bin/omarchy-agent b/bin/omarchy-agent index 4c12562f..ad8c14e4 100755 --- a/bin/omarchy-agent +++ b/bin/omarchy-agent @@ -95,6 +95,14 @@ codex) command=(codex --approve-for-me) [[ -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) if [[ -n ${prompt:-} ]]; then command=(env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=$prompt") diff --git a/bin/omarchy-default-agent b/bin/omarchy-default-agent index 515514d2..c4a567db 100755 --- a/bin/omarchy-default-agent +++ b/bin/omarchy-default-agent @@ -1,7 +1,7 @@ #!/bin/bash # omarchy:summary=Set and launch the default coding agent -# omarchy:args=[pi|omp|opencode|claude|codex|grok|gemini|openclaw|hermes|copilot|crush] +# omarchy:args=[pi|omp|opencode|claude|codex|grok|gemini|openclaw|hermes|copilot|crush|cursor-agent] # omarchy:examples=omarchy default agent | omarchy default agent codex | omarchy default agent claude installing=false @@ -35,8 +35,9 @@ gemini | gemini-cli) agent="gemini"; name="Gemini" ;; openclaw) agent="openclaw"; name="OpenClaw"; agent_installer="omarchy-install-openclaw-cli" ;; hermes) agent="hermes"; name="Hermes"; agent_installer="omarchy-install-hermes-cli" ;; copilot | github-copilot) agent="copilot"; name="GitHub Copilot" ;; +cursor | cursor-agent) agent="cursor-agent"; name="Cursor CLI" ;; *) - echo "Usage: omarchy-default-agent " + echo "Usage: omarchy-default-agent " exit 1 ;; esac @@ -55,8 +56,15 @@ if [[ -n ${agent_installer:-} ]]; then agent_present() { "$agent_installer" --check; } agent_install() { "$agent_installer" --now; } else - agent_present() { mise where "$agent_package" &>/dev/null; } - agent_install() { mise use -g "$agent_package"; } + # Anything at the wrapper's path other than the wrapper is the user's own + # 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 if [[ $installing == "false" ]] && ! agent_present; then diff --git a/bin/omarchy-remove-preinstalls b/bin/omarchy-remove-preinstalls index fa058e7e..5cee9516 100755 --- a/bin/omarchy-remove-preinstalls +++ b/bin/omarchy-remove-preinstalls @@ -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/omp ~/.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 # 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 diff --git a/default/fonts/omarchy/README.md b/default/fonts/omarchy/README.md index c6f0ee34..51486feb 100644 --- a/default/fonts/omarchy/README.md +++ b/default/fonts/omarchy/README.md @@ -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 , 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 - `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 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 29519250d7ca94f5d511f1b22a5463bd3a6876be..c6b76994effec2b771f1a38be1bbff2c00ce63a3 100644 GIT binary patch delta 704 zcma))O=uHQ5Xb+Mw;xHGm~PT!1tD#*?fLrKhatD!`+jnw9CFcy~8w3I3N&pJnQ716MnIAUtD58uCZeUqLlJrO+ z6{$*1>e4IyazF-Tu-D@~|Gl>Nob74vQO{v}Xp-rTnclxlXVOgFx#WpDlj5**PPt8R zwv}o2`^ri7aW&!0sk?-&u$B-UW_)R#>$e6!vCkTh8y+lST09VK7#QZ`nQF{5G+ouK z@d?XFrN@Zc@JulAxx^Z0%5y??&f_kdCyck5T@MlKHmS`lbpb8M@epGp1V zy_?LC!-7Ft8^=GHy^dF{B_1m;xqgxJ!>(VlI?Lu$uFr7Z?^(5g_R%^DpxrF=PFbG) z_Uo4gApMPtUI+ekb+){+1$1x`9)NhILgC=i?4-D3W(nennT;o#dPdw$_lO*giH~Mq z155BwY}y*H>lnpNE{-uOGr(xfQnM5^%&I(mfPJ#5YnWo+1(OvW7D{mVL?0E@Lxe_{ ziXwjhuTEhyilWshy&A1V_anhJ*G=69AbOR~hP*P34(vjTBj90kMKiNFmdHJ&7CL*U zMV!6YLXP0KP}o;m$noke_|A|+i5x9t@*#^zaKbZ6xEX}}za-oiLT*dK4T5y>$=oA; znC5>`RE)kO_}eaW(=*)3bLF=7IX0&E=(G93$*cyKN*u*&2YWx>hHY@(L%-Vq diff --git a/default/omarchy/omarchy-menu.jsonc b/default/omarchy/omarchy-menu.jsonc index a2f7daac..a3a2943d 100644 --- a/default/omarchy/omarchy-menu.jsonc +++ b/default/omarchy/omarchy-menu.jsonc @@ -134,6 +134,7 @@ "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.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.gemini": {"icon":"󰫢","label":"Gemini","checked":"[[ \"$(omarchy-default-agent)\" == \"gemini\" ]]","action":"omarchy-default-agent gemini"}, "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"}, @@ -157,7 +158,7 @@ "setup.default.editor": {"icon":"","label":"Editor","title":"Default Editor"}, "setup.default.editor.neovim": {"icon":"","label":"Neovim","when":"omarchy-cmd-present nvim","checked":"[[ \"$(omarchy-default-editor)\" == \"nvim\" ]]","action":"omarchy-default-editor nvim"}, "setup.default.editor.vscode": {"icon":"","label":"VSCode","when":"omarchy-cmd-present code","checked":"[[ \"$(omarchy-default-editor)\" == \"code\" ]]","action":"omarchy-default-editor code"}, - "setup.default.editor.cursor": {"icon":"","label":"Cursor","when":"omarchy-cmd-present cursor","checked":"[[ \"$(omarchy-default-editor)\" == \"cursor\" ]]","action":"omarchy-default-editor cursor"}, + "setup.default.editor.cursor": {"icon":"","iconFont":"omarchy","label":"Cursor","when":"omarchy-cmd-present cursor","checked":"[[ \"$(omarchy-default-editor)\" == \"cursor\" ]]","action":"omarchy-default-editor cursor"}, "setup.default.editor.zed": {"icon":"","label":"Zed","when":"omarchy-cmd-present zeditor","checked":"[[ \"$(omarchy-default-editor)\" == \"zeditor\" ]]","action":"omarchy-default-editor zed"}, "setup.default.editor.sublime": {"icon":"","label":"Sublime Text","when":"omarchy-cmd-present sublime_text","checked":"[[ \"$(omarchy-default-editor)\" == \"sublime_text\" ]]","action":"omarchy-default-editor sublime_text"}, "setup.default.editor.helix": {"icon":"","label":"Helix","when":"omarchy-cmd-present helix","checked":"[[ \"$(omarchy-default-editor)\" == \"helix\" ]]","action":"omarchy-default-editor helix"}, @@ -222,7 +223,7 @@ "install.service.bitwarden": {"icon":"󰟵","label":"Bitwarden","when":"! 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 ]] && ! 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","when":"! omarchy-pkg-present visual-studio-code-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-vscode"}, - "install.editor.cursor": {"icon":"","label":"Cursor","when":"! omarchy-pkg-present cursor-bin","action":"omarchy-install-and-launch Cursor cursor-bin cursor"}, + "install.editor.cursor": {"icon":"","iconFont":"omarchy","label":"Cursor","when":"! omarchy-pkg-present cursor-bin","action":"omarchy-install-and-launch Cursor cursor-bin cursor"}, "install.editor.zed": {"icon":"","label":"Zed","when":"! omarchy-pkg-present zed","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-zed"}, "install.editor.sublime": {"icon":"","label":"Sublime Text","when":"! omarchy-pkg-present sublime-text-4","action":"omarchy-install-and-launch 'Sublime Text' sublime-text-4 sublime_text"}, "install.editor.helix": {"icon":"","label":"Helix","when":"! omarchy-pkg-present helix","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-editor-helix"}, diff --git a/install/user/mise.sh b/install/user/mise.sh index d71905c9..bee5ec82 100644 --- a/install/user/mise.sh +++ b/install/user/mise.sh @@ -13,6 +13,8 @@ omarchy-mise-install npm:playwright playwright omarchy-mise-install pi omarchy-mise-install github:can1357/oh-my-pi omp 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 aqua:modem-dev/hunk hunk # Every line above writes a stub and cannot fail. This one can: it exits diff --git a/manual/17-ai.md b/manual/17-ai.md index 918822f3..bd85671b 100644 --- a/manual/17-ai.md +++ b/manual/17-ai.md @@ -13,8 +13,8 @@ Omarchy treats AI coding agents as first-class citizens, but it doesn't pick a f | `grok` | Grok CLI from xAI | | `pi` | [Mario Zechner's Pi](https://github.com/badlogic/pi-mono) | | `omp` | [Oh My Pi](https://github.com/can1357/oh-my-pi) | - | `hermes` | [Hermes](https://hermes-agent.nousresearch.com/), Nous Research's agent | +| `cursor-agent` | [Cursor CLI](https://cursor.com/cli) | To wrap an additional CLI the same way, run `omarchy-mise-install [command-name]`. The stubs are kept current along with everything else mise manages when you run `omarchy update` (or the `mup` alias). diff --git a/migrations/1788577553.sh b/migrations/1788577553.sh new file mode 100644 index 00000000..cc1a54ad --- /dev/null +++ b/migrations/1788577553.sh @@ -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 diff --git a/test/shell.d/default-agent-test.sh b/test/shell.d/default-agent-test.sh index f2640ef7..652d97c2 100644 --- a/test/shell.d/default-agent-test.sh +++ b/test/shell.d/default-agent-test.sh @@ -95,6 +95,7 @@ export OMARCHY_TEST_AGENT_MENU_LOG="$menu_log" grok_package="npm:@xai-official/grok" omp_package="github:can1357/oh-my-pi" crush_package="crush" +cursor_agent_package="cursor-agent" assert_lazy_stub() { local package=$1 @@ -112,18 +113,36 @@ assert_lazy_stub() { assert_lazy_stub "$grok_package" grok assert_lazy_stub "$omp_package" omp assert_lazy_stub "$crush_package" crush +assert_lazy_stub "$cursor_agent_package" cursor-agent 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 "$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 "$crush_package" "$stub_log" >/dev/null || fail "user setup creates the Crush lazy stub" 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" 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" +: >"$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" 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" @@ -136,6 +155,7 @@ touch "$test_home/.local/state/omarchy/preinstalls-removed" : >"$stub_log" source "$ROOT/migrations/1785617047.sh" >/dev/null source "$ROOT/migrations/1785846769.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" [[ ! -e $test_home/.local/bin/omp ]] || fail "agent migration removes the obsolete Oh My Pi wrapper after opt-out" @@ -160,11 +180,20 @@ rm "$test_home/.local/state/omarchy/preinstalls-removed" pass "agent migrations install working wrappers without overriding the preinstall opt-out" omarchy-remove-preinstalls >/dev/null -for command in omp grok crush; do +for command in omp grok crush cursor-agent; do [[ ! -e $test_home/.local/bin/$command ]] || fail "Remove Preinstalls deletes the $command lazy stub" done 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" pass "default agent is unset until one is chosen" @@ -220,6 +249,8 @@ declare -A expected_agents=( [gemini-cli]="gemini" [copilot]="copilot" [github-copilot]="copilot" + [cursor]="cursor-agent" + [cursor-agent]="cursor-agent" ) declare -A expected_packages=( @@ -232,6 +263,7 @@ declare -A expected_packages=( [grok]="$grok_package" [gemini]="gemini" [copilot]="copilot" + [cursor-agent]="$cursor_agent_package" ) for selection in "${!expected_agents[@]}"; do @@ -292,6 +324,35 @@ mapfile -d '' -t agent_open_args <"$agent_open_log" fail "installed agent opens in a new terminal after selection" 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" if omarchy-default-agent unsupported >"$test_tmp/invalid-output" 2>&1; then fail "default agent rejects unsupported providers" @@ -376,6 +437,7 @@ assert_launch codex codex --approve-for-me -- "Review this project" assert_launch crush crush run "Review this project" assert_launch grok grok --permission-mode bypassPermissions -- "Review this project" assert_launch gemini gemini --yolo --prompt-interactive "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 copilot copilot --allow-all --interactive "Review this project" pass "agent launcher adapts initial prompts for every supported agent" @@ -395,6 +457,7 @@ assert_bypass codex codex --approve-for-me assert_bypass crush crush --yolo assert_bypass grok grok --permission-mode bypassPermissions assert_bypass gemini gemini --yolo +assert_bypass cursor-agent cursor-agent --yolo --trust assert_bypass hermes hermes --yolo assert_bypass copilot copilot --allow-all pass "agent launcher skips permission prompts for every supported agent" diff --git a/test/shell.d/menu-test.sh b/test/shell.d/menu-test.sh index f5d051f7..5eb00b69 100644 --- a/test/shell.d/menu-test.sh +++ b/test/shell.d/menu-test.sh @@ -207,6 +207,7 @@ const expectedAgents = { openclaw: { icon: '\ue90c', iconFont: 'omarchy', label: 'OpenClaw' }, copilot: { icon: '', label: 'Copilot' }, crush: { icon: '󰋑', label: 'Crush' }, + 'cursor-agent': { icon: '\ue90d', iconFont: 'omarchy', label: 'Cursor CLI' }, } assert( Object.entries(expectedAgents).every(([agent, expected]) => { @@ -225,7 +226,7 @@ assertDeepEqual( defaultItems .filter(item => item.parent === 'setup.default.agent') .map(item => item.label), - ['Claude', 'Codex', 'Copilot', 'Crush', 'Gemini', 'Grok', 'Hermes', 'omp', 'OpenClaw', 'OpenCode', 'Pi'], + ['Claude', 'Codex', 'Copilot', 'Crush', 'Cursor CLI', 'Gemini', 'Grok', 'Hermes', 'omp', 'OpenClaw', 'OpenCode', 'Pi'], 'menu sorts coding agents alphabetically' ) assert(!defaultById['install.ai.crush'], 'menu removes Crush from Install > AI') @@ -516,5 +517,5 @@ assert( JS font_charset=$(fc-query --format='%{charset}' "$ROOT/default/fonts/omarchy/omarchy.ttf") -[[ $font_charset == *"e900-e908 e90a-e90c"* ]] || fail "Omarchy icon font includes every custom menu glyph" +[[ $font_charset == *"e900-e908 e90a-e90d"* ]] || fail "Omarchy icon font includes every custom menu glyph" pass "Omarchy icon font includes the official agent marks" diff --git a/test/shell.d/release-ai-port-test.sh b/test/shell.d/release-ai-port-test.sh index 76d4aefd..d9996149 100644 --- a/test/shell.d/release-ai-port-test.sh +++ b/test/shell.d/release-ai-port-test.sh @@ -24,7 +24,7 @@ for (const [id, [pkg, glyph]] of Object.entries(selected)) { assert(fs.existsSync(path.join(root, `bin/omarchy-remove-ai-${id}`)), `${id} remover exists`) } assertDeepEqual(Object.keys(rows).filter(k => k.startsWith('remove.ai.')).sort(), Object.keys(selected).map(k => `remove.ai.${k}`).sort(), 'removal prerequisite imports no unselected apps') -assertDeepEqual(Object.keys(rows).filter(k => k.startsWith('setup.default.agent.')).map(k => k.split('.').pop()).sort(), ['claude', 'codex', 'copilot', 'crush', 'gemini', 'grok', 'hermes', 'omp', 'openclaw', 'opencode', 'pi'], 'baseline agent choices survive with only Hermes and OpenClaw added') +assertDeepEqual(Object.keys(rows).filter(k => k.startsWith('setup.default.agent.')).map(k => k.split('.').pop()).sort(), ['claude', 'codex', 'copilot', 'crush', 'cursor-agent', 'gemini', 'grok', 'hermes', 'omp', 'openclaw', 'opencode', 'pi'], 'baseline agent choices survive with only selected release agents added') assert(!fs.existsSync(path.join(root, 'bin/omarchy-theme-set-openclaw')), 'deferred OpenClaw theming is absent') JS