Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion bin/omarchy-voxtype-install
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,28 @@ set -e
# Install voxtype and configure it for use.

if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then
omarchy-pkg-add wtype voxtype-bin
# voxtype-bin is built for x86_64 only. On any other architecture, such as
# Apple Silicon, the AUR source package is the only Voxtype that installs.
if [[ $(uname -m) == "x86_64" ]]; then
omarchy-pkg-add wtype voxtype-bin
else
gum style --foreground 3 "There's no prebuilt Voxtype binary for your CPU architecture."
if ! gum confirm "Build Voxtype from source instead? This can take 10-20 minutes."; then
echo "Skipping Voxtype install."
exit 0
fi

if ! omarchy-pkg-aur-accessible; then
gum style --foreground 1 "The AUR is unreachable right now, so Voxtype can't be built from source. Try again later."
exit 1
fi

if ! omarchy-pkg-aur-add voxtype; then
gum style --foreground 1 "Building Voxtype from source failed. The build output above shows why."
exit 1
fi
omarchy-pkg-add wtype
fi

# Setup voxtype
mkdir -p ~/.config/voxtype
Expand Down
5 changes: 3 additions & 2 deletions bin/omarchy-voxtype-remove
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ if omarchy-cmd-present voxtype; then
systemctl --user disable --now voxtype.service 2>/dev/null || true
systemctl --user daemon-reload

# Remove packages and configs
omarchy-pkg-drop voxtype-bin
# Remove packages and configs. voxtype-bin is the x86_64 prebuilt binary and
# voxtype the AUR build used on other architectures; only one is installed.
omarchy-pkg-drop voxtype-bin voxtype
rm -rf ~/.config/voxtype
rm -rf ~/.local/share/voxtype
hyprctl reload >/dev/null
Expand Down
4 changes: 2 additions & 2 deletions default/omarchy/omarchy-menu.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@
"install.terminal.ghostty": {"icon":"","label":"Ghostty","when":"omarchy-install-available install.terminal.ghostty && ! omarchy-pkg-present ghostty","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-install-terminal ghostty'"},
"install.terminal.kitty": {"icon":"","label":"Kitty","when":"omarchy-install-available install.terminal.kitty && ! omarchy-pkg-present kitty","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-install-terminal kitty'"},
"install.ai.chatgpt": {"icon":"","iconFont":"omarchy","label":"ChatGPT Desktop","when":"omarchy-install-available install.ai.chatgpt && ! omarchy-pkg-present openai-codex-desktop","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-ai-chatgpt"},
"install.ai.dictation": {"icon":"","label":"Dictation","when":"omarchy-install-available install.ai.dictation && ! omarchy-pkg-present voxtype-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-install"},
"install.ai.dictation": {"icon":"","label":"Dictation","when":"omarchy-install-available install.ai.dictation && ! omarchy-cmd-present voxtype","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-install"},
"install.ai.grok-bot": {"icon":"","iconFont":"omarchy","label":"Grok Bot","when":"omarchy-install-available install.ai.grok-bot && ! omarchy-pkg-present grok-bot","action":"omarchy-install-and-launch 'Grok Bot' grok-bot grok-bot"},
"install.ai.lm-studio": {"icon":"","iconFont":"omarchy","label":"LM Studio","when":"omarchy-install-available install.ai.lm-studio && ! omarchy-pkg-present lmstudio-bin","action":"omarchy-install-app 'LM Studio' lmstudio-bin"},
"install.ai.t3-code": {"icon":"","iconFont":"omarchy","label":"T3 Code","when":"omarchy-install-available install.ai.t3-code && ! omarchy-pkg-present t3code-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-ai-t3-code"},
Expand Down Expand Up @@ -283,7 +283,7 @@
"remove.development": {"icon":"󰵮","label":"Development","title":"Remove"},
"remove.theme": {"icon":"󰸌","label":"Theme","action":"omarchy-theme-remove"},
"remove.browser": {"icon":"","label":"Browser","title":"Remove"},
"remove.dictation": {"icon":"","label":"Dictation","when":"omarchy-pkg-present voxtype-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-remove"},
"remove.dictation": {"icon":"","label":"Dictation","when":"omarchy-cmd-present voxtype","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-remove"},
"remove.gaming": {"icon":"","label":"Gaming","title":"Remove"},
"remove.service": {"icon":"","label":"Services","title":"Remove"},
"remove.windows": {"icon":"󰍲","label":"Windows","when":"[[ -f $HOME/.local/share/applications/windows-vm.desktop ]]","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-windows-vm remove'"},
Expand Down
26 changes: 21 additions & 5 deletions install/helpers/optional-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,20 @@ __omarchy_optional_load() {
__omarchy_optional_valid=true
}

# Probe the architecture once per process, shared by every row that needs it.
__omarchy_optional_load_arch() {
if ! $__omarchy_arch_loaded; then
__omarchy_optional_arch=$(uname -m) || return 1
__omarchy_arch_loaded=true
fi
}

# Return the complete selected sync targets in an array without a subprocess.
# Xbox's mandatory headers follow the installer's hardware predicate, not uname.
# Dictation's prebuilt voxtype-bin is x86_64-only; elsewhere the installer
# builds voxtype from the AUR, so only its remaining sync targets must resolve.
__omarchy_optional_targets() {
local id=${1:-} headers=linux-headers
local id=${1:-} headers=linux-headers package
__omarchy_optional_load || return 1
[[ -n $id && -n ${__omarchy_optional_sync[$id]-} ]] || return 1
read -ra __omarchy_requested_packages <<<"${__omarchy_optional_sync[$id]}"
Expand All @@ -72,6 +82,15 @@ __omarchy_optional_targets() {
headers=$(omarchy-hw-apple-kernel)-headers
fi
__omarchy_requested_packages=("$headers" "${__omarchy_requested_packages[@]}")
elif [[ $id == "install.ai.dictation" ]]; then
__omarchy_optional_load_arch || return 1
if [[ $__omarchy_optional_arch != "x86_64" ]]; then
local -a sync_packages=()
for package in "${__omarchy_requested_packages[@]}"; do
[[ $package == "voxtype-bin" ]] || sync_packages+=("$package")
done
__omarchy_requested_packages=("${sync_packages[@]}")
fi
fi
}

Expand All @@ -80,10 +99,7 @@ omarchy-install-available() {
[[ -n $id ]] || return 1
__omarchy_optional_load || return 1
if [[ -n ${__omarchy_optional_aur[$id]-} ]]; then
if ! $__omarchy_arch_loaded; then
__omarchy_optional_arch=$(uname -m) || return 1
__omarchy_arch_loaded=true
fi
__omarchy_optional_load_arch || return 1
[[ " ${__omarchy_optional_aur[$id]} " == *" $__omarchy_optional_arch "* ]]
else
__omarchy_optional_targets "$id" || return 1
Expand Down
2 changes: 2 additions & 0 deletions manual/11-text-extraction-dictation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ This is very helpful for grabbing addresses out of image footers or phone number

Omarchy offers AI dictation via [Voxtype](https://voxtype.io/). You install it via _Install > AI > Dictation_ through the Omarchy menu. By default, it'll load a base English model that takes up 150MB. But you can tweak which model you'd like to use by running `voxtype setup model` in the terminal. And you can tweak all the settings via `~/.config/voxtype/config.toml`.

The prebuilt Voxtype binary is x86_64 only. On other architectures, such as Apple Silicon, the installer offers to build Voxtype from source via the AUR instead, which takes 10-20 minutes.

Once installed, you dictate by holding down `F9` or by toggling with `Super + Ctrl + X`, and the dictated text will appear in the focused input area.
2 changes: 1 addition & 1 deletion test/generate-optional-transactions
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ declare -A override_ids=(
[install.terminal.foot]=foot
[install.terminal.ghostty]=ghostty
[install.terminal.kitty]=kitty
[install.ai.dictation]=voxtype-bin
[install.ai.dictation]="voxtype-bin wtype"
[install.development.rails]="libyaml"
[install.development.php.php]="php composer php-sqlite xdebug"
[install.development.php.laravel]="php composer php-sqlite xdebug"
Expand Down
10 changes: 8 additions & 2 deletions test/shell.d/optional-availability-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ cat >"$test_tmp/bin/pacman" <<'STUB'
printf '%s\n' "$*" >>"$CALLS"
case $1 in
-Slq)
printf '%s\n' primary secondary zed omazed xpadneo-dkms linux-headers linux-asahi-headers | while read -r p; do
printf '%s\n' primary secondary zed omazed xpadneo-dkms linux-headers linux-asahi-headers voxtype-bin wtype | while read -r p; do
[[ $p == "${MISSING:-}" ]] || echo "$p"
done ;;
-Sp)
Expand Down Expand Up @@ -66,6 +66,12 @@ for arch in x86_64 aarch64; do
check 1 omarchy-pkg-available missing
check 0 omarchy-install-available install.editor.zed
MISSING=omazed check 1 omarchy-install-available install.editor.zed
# voxtype-bin is x86_64-only; elsewhere dictation builds voxtype from the AUR.
prebuilt_expected=1
[[ $arch == x86_64 ]] || prebuilt_expected=0
check 0 omarchy-install-available install.ai.dictation
MISSING=voxtype-bin check "$prebuilt_expected" omarchy-install-available install.ai.dictation
MISSING=wtype check 1 omarchy-install-available install.ai.dictation
for apple in 0 1; do
export APPLE=$apple
selected=linux-headers
Expand All @@ -79,7 +85,7 @@ done
ARCH=riscv64 check 1 omarchy-install-available install.browser.chrome
check 1 omarchy-install-available install.unknown
: >"$CALLS"
bash -c "$prelude"$'\n''omarchy-pkg-available primary provided; omarchy-pkg-available secondary provided; omarchy-install-available install.browser.chrome; omarchy-install-available install.browser.brave'
bash -c "$prelude"$'\n''omarchy-pkg-available primary provided; omarchy-pkg-available secondary provided; omarchy-install-available install.browser.chrome; omarchy-install-available install.browser.brave; omarchy-install-available install.ai.dictation'
[[ $(grep -c -- '^-Slq$' "$CALLS") == 1 ]] || fail 'one sync snapshot per batch'
[[ $(grep -c -- '^-Sp .*provided$' "$CALLS") == 1 ]] || fail 'provided results cached per batch'
[[ $(grep -c '^uname$' "$CALLS") == 1 ]] || fail 'one architecture probe per batch'
Expand Down
1 change: 1 addition & 0 deletions test/shell.d/optional-transactions-drift-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const items = menu.parseMenuJsonc(fs.readFileSync(path.join(root, 'default/omarc
// Recipes whose package name is a variable resolved at runtime carry their
// base package here; the menu action itself is what would drift.
const overrides = {
'install.ai.dictation': ['voxtype-bin', 'wtype'],
'install.ai.ollama': ['ollama'],
'install.terminal.alacritty': ['alacritty'],
'install.terminal.foot': ['foot'],
Expand Down
129 changes: 129 additions & 0 deletions test/shell.d/voxtype-install-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/bin/bash

set -euo pipefail

source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"

test_home=$(mktemp -d)
test_bin=$(mktemp -d)
test_omarchy_path=$(mktemp -d)
log_file=$(mktemp)
confirm_queue=$(mktemp)

cleanup() {
rm -rf "$test_home" "$test_bin" "$test_omarchy_path"
rm -f "$log_file" "$confirm_queue"
}
trap cleanup EXIT

mkdir -p "$test_omarchy_path/default/voxtype"
echo "# stub config" >"$test_omarchy_path/default/voxtype/config.toml"

# gum answers confirm prompts in order from the queue, one yes/no per line, and
# ignores every other subcommand.
cat >"$test_bin/gum" <<'EOF'
#!/bin/bash
if [[ $1 == "confirm" ]]; then
echo "confirm:$2" >>"$TEST_LOG"
answer=$(head -n1 "$CONFIRM_QUEUE")
sed -i '1d' "$CONFIRM_QUEUE"
[[ $answer == "yes" ]]
exit $?
fi
exit 0
EOF

for cmd in omarchy-pkg-add omarchy-pkg-aur-add omarchy-restart-shell omarchy-notification-send voxtype; do
cat >"$test_bin/$cmd" <<EOF
#!/bin/bash
echo "$cmd:\$*" >>"\$TEST_LOG"
EOF
done

cat >"$test_bin/omarchy-pkg-aur-add" <<'EOF'
#!/bin/bash
echo "omarchy-pkg-aur-add:$*" >>"$TEST_LOG"
exit "${AUR_BUILD_STATUS:-0}"
EOF

cat >"$test_bin/omarchy-pkg-aur-accessible" <<'EOF'
#!/bin/bash
exit "${AUR_ACCESSIBLE:-0}"
EOF

cat >"$test_bin/omarchy-hw-vulkan" <<'EOF'
#!/bin/bash
exit 1
EOF

cat >"$test_bin/hyprctl" <<'EOF'
#!/bin/bash
exit 0
EOF

cat >"$test_bin/uname" <<'EOF'
#!/bin/bash
if [[ $1 == "-m" ]]; then
echo "$TEST_UNAME_M"
else
exec /usr/bin/uname "$@"
fi
EOF

chmod +x "$test_bin/"*

install_status=0
run_install() {
local arch=$1 answers=$2 aur_accessible=${3:-0} aur_build_status=${4:-0}
: >"$log_file"
printf '%s\n' $answers >"$confirm_queue"
install_status=0
HOME="$test_home" OMARCHY_PATH="$test_omarchy_path" PATH="$test_bin:$ROOT/bin:$PATH" \
TEST_LOG="$log_file" CONFIRM_QUEUE="$confirm_queue" AUR_ACCESSIBLE="$aur_accessible" AUR_BUILD_STATUS="$aur_build_status" \
TEST_UNAME_M="$arch" bash "$ROOT/bin/omarchy-voxtype-install" >/dev/null || install_status=$?
}

assert_status() {
(( install_status == $1 )) || fail "$2" "exited $install_status, expected $1"
}

run_install x86_64 "yes"
assert_status 0 "an x86_64 install succeeds"
grep -qx 'omarchy-pkg-add:wtype voxtype-bin' "$log_file" || fail "x86_64 installs the prebuilt voxtype-bin"
grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "x86_64 does not build from the AUR"
grep -q '^omarchy-notification-send:' "$log_file" || fail "x86_64 install sends the ready notification"
pass "x86_64 installs the prebuilt voxtype-bin"

run_install aarch64 "yes yes"
assert_status 0 "an aarch64 source build succeeds"
grep -qxF 'confirm:Build Voxtype from source instead? This can take 10-20 minutes.' "$log_file" ||
fail "aarch64 asks before starting the source build"
grep -qx 'omarchy-pkg-add:wtype' "$log_file" || fail "aarch64 installs wtype from the repositories"
grep -qx 'omarchy-pkg-aur-add:voxtype' "$log_file" || fail "aarch64 builds voxtype from the AUR"
grep -q 'voxtype-bin' "$log_file" && fail "aarch64 never requests the x86_64-only voxtype-bin"
grep -qx 'voxtype:setup systemd' "$log_file" || fail "aarch64 install finishes Voxtype setup"
pass "aarch64 builds voxtype from the AUR instead of voxtype-bin"

run_install aarch64 "yes no"
assert_status 0 "declining the source build is not an error"
grep -q '^omarchy-pkg-' "$log_file" && fail "declining the source build installs nothing"
grep -q '^voxtype:' "$log_file" && fail "declining the source build runs no Voxtype setup"
pass "declining the aarch64 source build installs nothing"

run_install aarch64 "yes yes" 1
assert_status 1 "an unreachable AUR fails the install"
grep -q '^omarchy-pkg-' "$log_file" && fail "an unreachable AUR installs nothing"
pass "an unreachable AUR stops the aarch64 install before any package change"

run_install aarch64 "yes yes" 0 1
assert_status 1 "a failed source build fails the install"
grep -qx 'omarchy-pkg-aur-add:voxtype' "$log_file" || fail "a failed source build was attempted"
grep -q '^omarchy-pkg-add:' "$log_file" && fail "a failed source build leaves wtype uninstalled"
grep -q '^voxtype:' "$log_file" && fail "a failed source build runs no Voxtype setup"
pass "a failed aarch64 source build stops before wtype and Voxtype setup"

run_install aarch64 "no"
assert_status 0 "declining the install is not an error"
[[ $(grep -c '^confirm:' "$log_file") == 1 ]] || fail "declining the install asks nothing further"
grep -q '^omarchy-pkg-' "$log_file" && fail "declining the install installs nothing"
pass "declining the install changes nothing"