#!/usr/bin/env bash set -euo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" commands_dir="$repo_dir/config/local/share/vicinae/scripts" work="$(mktemp -d /tmp/panama-commands.XXXXXX)" dispatch_log="$work/dispatch.log" fail() { printf 'Panama commands contract: %s\n' "$1" >&2 exit 1 } cleanup() { rm -rf "$work" } trap cleanup EXIT declare -A expected=( [open-control-center]=control-center [open-notifications]=notifications [open-calendar]=calendar [open-clipboard]=clipboard [open-mission-control]=overview [open-settings]=settings [check-system-health]=health [toggle-dnd]=dnd [toggle-caffeine]=caffeine [toggle-night-light]=night-light [start-focus]=focus-start [end-focus]=focus-end [capture]=capture [screen-intelligence]=intelligence [quick-screenshot]=screenshot [toggle-microphone]=microphone [open-prism-gallery]=gallery [restart-shell]=restart-shell ) # The per-page settings commands are generated from the settings page list, so # they are enumerated from that list rather than restated here -- a hand-written # copy would have to be edited every time a page is added, which is exactly the # kind of second list this generator exists to avoid. sidebar="$repo_dir/config/dot/quickshell/modules/settings/SettingsSidebar.qml" while read -r page; do [[ -n "$page" ]] || continue [[ "$page" == "home" ]] && continue expected[settings-$page]="settings-page $page" done < <(grep -oE '\{ page: "[a-z-]+"' "$sidebar" | sed 's/.*"\([a-z-]*\)"/\1/') (( ${#expected[@]} > 18 )) || fail 'no generated per-page commands were found; run scripts/panama-settings-commands' # Commands that do not go through panama-action, and should not. # # Every command above asks the shell to do something, so routing them through # one dispatcher is what keeps that surface small. search-web is a different # animal: it takes a query and opens a browser, and neither half needs the # shell. Sending it through panama-action would mean a web search stops working # when Quickshell is down -- which is exactly when somebody is reaching for the # launcher to look up what went wrong. # # The project commands are the same shape: they record or restore a window # layout, which is panama-project's job and involves the shell not at all. # # They are still commands, so everything else below applies to them: a title, # a description, search vocabulary, the Panama icon, and closing quietly. # # The OS-parity commands are standalone for the same reason. A power menu that # needs the shell running is a power menu you cannot reach when the shell is # what broke; the pick-lists render through `vicinae dmenu` and act through # hyprctl; reminders are systemd timers. None of them has anything to ask the # shell for, and routing them through panama-action would only add a way for # them to stop working. declare -a standalone=( search-web save-project open-project lock-screen suspend-system log-out reboot-system power-off remind-me list-reminders pick-color switch-window force-quit-window kill-process ssh-hosts recent-files copy-password ) # Generated commands must match their source. A stale command dispatches to a # page that has been renamed or removed, and the launcher reports nothing wrong. "$repo_dir/config/dot/quickshell/scripts/panama-settings-commands" --check >/dev/null \ || fail 'the generated per-page commands are stale; run scripts/panama-settings-commands' mkdir -p "$work/home/.config/quickshell/scripts" cat >"$work/home/.config/quickshell/scripts/panama-action" <<'EOF' #!/usr/bin/env bash printf '%s\n' "$*" >>"$PANAMA_COMMAND_TEST_LOG" EOF chmod +x "$work/home/.config/quickshell/scripts/panama-action" [[ -d "$commands_dir" ]] || fail 'Vicinae command directory is missing' # Every file in the directory, not a glob on an extension. These scripts carry # none: a shebang and the executable bit already select the interpreter, and an # extension is one more thing that has to stay in sync -- which it did not. mapfile -t actual_files < <(find "$commands_dir" -maxdepth 1 -type f -printf '%f\n' | sort) declared=$(( ${#expected[@]} + ${#standalone[@]} )) [[ ${#actual_files[@]} -eq $declared ]] \ || fail "expected $declared commands, found ${#actual_files[@]}" declare -A seen_titles=() for script_name in "${!expected[@]}" "${standalone[@]}"; do script="$commands_dir/$script_name" [[ -x "$script" ]] || fail "$script_name is missing or not executable" vicinae script check "$script" >/dev/null \ || fail "$script_name is rejected by Vicinae" title="$(sed -n 's/^# @vicinae.title //p' "$script")" # No product prefix: this is the desktop's own settings, not a third-party # add-on announcing itself in someone else's launcher. Uniqueness still # matters, because two commands with one title are indistinguishable there. [[ -n $title ]] || fail "$script_name has no title" [[ $title != Panama* ]] || fail "$script_name still carries the product prefix: $title" [[ -z ${seen_titles[$title]+x} ]] || fail "duplicate launcher title: $title" seen_titles[$title]=1 grep -Fxq '# @vicinae.mode silent' "$script" \ || fail "$script_name does not close quietly after success" grep -Fq '# @vicinae.description ' "$script" \ || fail "$script_name has no searchable description" grep -Fq '# @vicinae.keywords ' "$script" \ || fail "$script_name has no search vocabulary" grep -Fxq '# @vicinae.icon ../../icons/hicolor/scalable/apps/panama-settings.svg' "$script" \ || fail "$script_name does not use the Panama application identity" if [[ $script_name == check-system-health ]]; then [[ $title == 'Check System Health' ]] \ || fail "health command has the wrong title: $title" grep -Fxq '# @vicinae.schemaVersion 1' "$script" \ || fail 'health command does not use schema version 1' grep -Fxq '# @vicinae.keywords ["health", "doctor", "repair", "services"]' "$script" \ || fail 'health command has the wrong search vocabulary' grep -Fxq 'exec "$HOME/.config/quickshell/scripts/panama-action" health' "$script" \ || fail 'health command bypasses the stable dispatcher path' fi # A standalone command has nothing to dispatch, and running it would open a # browser at whoever is running the tests. if [[ -z ${expected[$script_name]+x} ]]; then if grep -Fq 'panama-action' "$script"; then fail "$script_name is listed as standalone but goes through panama-action" fi continue fi : >"$dispatch_log" HOME="$work/home" PANAMA_COMMAND_TEST_LOG="$dispatch_log" "$script" dispatched="$(cat "$dispatch_log")" [[ $dispatched == "${expected[$script_name]}" ]] \ || fail "$script_name dispatched [$dispatched], expected [${expected[$script_name]}]" done printf 'Panama commands contract: PASS (%d commands)\n' "$declared"