Add omarchy-crash-mute to mute and unmute one program

The mute was reachable only as `omarchy-toggle crash-ignore/<program>`, which asks whoever runs it to know the flag layout, to reduce a binary's path to the name the watcher keys on, and to have read the rule that a name climbing out of that directory writes an unrelated toggle. All of that was carried in the skill's prose, which is the wrong place for a rule that has to hold: prose is advice, and the thing being advised about is a name the crashed program chose.

So it is a command now. `omarchy crash mute hyprland` silences that program, `off` lifts it, `toggle` flips it, and no argument lists what is muted. It takes the binary's path as readily as the name and reduces it the way the watcher does, so the `Executable:` line from `coredumpctl` can be handed straight to it; it refuses what is not one component of a name, so it cannot be talked into writing outside its own directory whatever it is given; and it re-reads the flag afterwards and reports what is now true rather than what was asked for. The listing counts only regular files, because that is all the watcher honours -- anything else in there would read as muted while the crashes kept arriving. A leading `--` is consumed so a program named `-h`, which the router would otherwise answer with its own help, can still be muted.

The watcher gained an unrelated fix that this uncovered. Its fields are read with `IFS=$'\t'`, and tab is IFS whitespace, so an empty field collapsed into the next delimiter and shifted every field after it along one: a crash whose comm was empty had a path read as its pid and was discarded as somebody else's. A process can set its comm to nothing, so that was reachable. Empty fields now arrive as a dash like missing ones, and a dash joins the empty and dot cases that fall back to `unknown`.

Co-Authored-By: Codex XHigh <noreply@openai.com>
This commit is contained in:
Omarchybot
2026-08-27 11:26:28 +02:00
committed by David Heinemeier Hansson
co-authored by Codex XHigh
parent eeb4206c7b
commit ea6ee9440a
6 changed files with 264 additions and 43 deletions
+146 -6
View File
@@ -122,8 +122,12 @@ run_watch() {
fail "the watcher exited $status rather than carrying on, so a mute takes the service down with it"
}
# Through the real command rather than writing the flag by hand: these assertions
# are then the guard that the thing the diagnosis runs and the thing the watcher
# reads have not drifted apart.
mute() {
HOME="$watch_home" "$ROOT/bin/omarchy-toggle" "crash-ignore/$1" "$2"
HOME="$watch_home" PATH="$ROOT/bin:$PATH" \
"$ROOT/bin/omarchy-crash-mute" "$1" "$2" >/dev/null
}
announced() {
@@ -214,6 +218,19 @@ for empty_comm in / a/ . ..; do
done
pass "a comm that strips down to nothing or a dot still announces under a name a mute can use"
# An empty comm is not a missing entry. Tab is IFS whitespace, so an empty field
# collapses and every field after it shifts along one -- the pid becomes a path,
# the crash reads as somebody else's, and it is dropped without a word.
reset_entries
crash_entry "" -
crash_entry nautilus /usr/bin/nautilus
run_watch
announced unknown ||
fail "a crash whose comm is empty is dropped instead of announced, because the empty field shifted every field after it"
announced nautilus ||
fail "an empty comm derails the rest of the journal entry"
pass "an empty comm is announced rather than parsed into the next field"
# Only "." and ".." are special. A leading dot is an ordinary filename, and
# folding those into the fallback would have one program's mute silence another.
for dotted_comm in .hidden ...; do
@@ -235,12 +252,135 @@ run_watch
pass "the fallback name can be muted like any other"
mute unknown off
# What omarchy-crash-mute does on its own. That it agrees with the watcher is
# already covered above, which drives it for every mute it makes.
mute_home="$TMPDIR/mute-home"
mkdir -p "$mute_home"
crash_mute() {
HOME="$mute_home" PATH="$ROOT/bin:$PATH" "$ROOT/bin/omarchy-crash-mute" "$@"
}
mute_flag() {
[[ $1 == "--" ]] && shift
printf '%s' "$mute_home/.local/state/omarchy/toggles/crash-ignore/$1"
}
crash_mute | grep -Fq "No programs muted" ||
fail "an empty mute list prints nothing, so a user cannot tell it from a broken command"
pass "the command says so when nothing is muted"
crash_mute hyprland >/dev/null
crash_mute | grep -Fqx hyprland ||
fail "a muted program is missing from the list, so a mute cannot be found again to lift it"
pass "the command lists what it muted"
# The watcher keys on the basename, so the command has to take the path a crash
# recorded and land on the same flag the watcher will look for.
crash_mute /usr/lib/chromium/chromium-browser >/dev/null
[[ -f $(mute_flag chromium-browser) ]] ||
fail "a binary's path is muted verbatim rather than by name, so the watcher never sees that flag"
pass "the command reduces a path to the name the watcher checks"
crash_mute hyprland off >/dev/null
[[ ! -f $(mute_flag hyprland) ]] ||
fail "off leaves the program muted, making the mute a one-way door"
pass "the command un-mutes"
# Muting is not flipping. The diagnosis offers this on a program the user may
# already have muted, and asking for a mute twice has to leave it muted.
crash_mute hyprland >/dev/null
crash_mute hyprland >/dev/null
[[ -f $(mute_flag hyprland) ]] ||
fail "muting an already-muted program un-mutes it, so offering the mute a second time turns it back on"
pass "asking to mute twice leaves it muted"
# A program may legitimately be called .hidden, and a mute nobody can see is a
# mute nobody can lift.
crash_mute .hidden >/dev/null
crash_mute | grep -Fqx .hidden ||
fail "a mute on a dotted name is missing from the list, so it can never be found and lifted"
pass "the list shows a name that begins with a dot"
# It turns what it is given into a path, so it has to refuse whatever is not one
# component of one.
for bad_name in . .. /; do
! crash_mute "$bad_name" >/dev/null 2>&1 ||
fail "'$bad_name' is taken as a program name, and the flag that writes is not one the watcher will ever read"
done
pass "the command refuses a name that is not a name"
! crash_mute hyprland sideways >/dev/null 2>&1 ||
fail "an action it does not know is treated as a mute, so a typo silences a program"
pass "the command refuses an action it does not know"
# And says what it refused, or the user retypes the same thing. Captured rather
# than piped: the command exits non-zero here, which pipefail would surface as
# the pipeline's status and read as a failed assertion.
refusal=$(crash_mute hyprland sideways 2>&1) || true
grep -Fq "Not an action" <<<"$refusal" ||
fail "an unknown action is refused without naming it, leaving the user nothing to correct"
pass "the command names the action it refused"
crash_mute ../bar-off >/dev/null
[[ ! -e "$mute_home/.local/state/omarchy/toggles/bar-off" ]] ||
fail "a name that climbs out writes a sibling toggle, so muting a crash could turn off the bar instead"
pass "the command cannot be talked into writing outside crash-ignore/"
# A program may be called -h, and the router answers that with its own help
# before the command runs. A leading -- is the way through, so it has to be
# consumed rather than taken for the program name.
crash_mute -- -h >/dev/null 2>&1 ||
fail "a leading -- is refused rather than consumed, so a program named like a flag cannot be muted at all"
[[ -f $(mute_flag -- -h) ]] ||
fail "a leading -- is taken for the program name, so muting -h mutes something else"
pass "a leading -- lets a program named like a flag be muted"
# toggle is advertised, so it has to flip both ways rather than quietly mute.
crash_mute toggler off >/dev/null
crash_mute toggler toggle >/dev/null
[[ -f $(mute_flag toggler) ]] ||
fail "toggle does not mute an un-muted program"
crash_mute toggler toggle >/dev/null
[[ ! -f $(mute_flag toggler) ]] ||
fail "toggle mutes but never un-mutes, so the advertised action only goes one way"
pass "toggle flips a mute both ways"
# The listing means what the watcher means, and the watcher honours a regular
# file. Anything else in there is not a mute, however much it looks like one.
mkdir -p "$(mute_flag notactuallymuted)"
! crash_mute | grep -Fqx notactuallymuted ||
fail "a directory is reported as muted while that program's crashes keep arriving"
pass "the listing counts only the flags the watcher honours"
rmdir "$(mute_flag notactuallymuted)"
# A mute that could not be written must not be reported as one. Without this the
# command can print success for a flag that was never created.
failing_bin="$TMPDIR/failing-bin"
mkdir -p "$failing_bin"
cat >"$failing_bin/omarchy-toggle" <<'SH'
#!/bin/bash
exit 1
SH
chmod +x "$failing_bin/omarchy-toggle"
status=0
refusal=$(HOME="$mute_home" PATH="$failing_bin:$ROOT/bin:$PATH" \
"$ROOT/bin/omarchy-crash-mute" hyprland 2>&1) || status=$?
(( status != 0 )) ||
fail "a mute that could not be written exits zero, so nothing downstream learns it failed"
! grep -Fq "Muted crash notifications" <<<"$refusal" ||
fail "a mute that could not be written still reports success, so the user believes a program is silenced when it is not"
pass "a mute that could not be written is not reported as one"
skill="$ROOT/default/agents/skills/diagnose-crash/SKILL.md"
grep -Fq 'crash-ignore/' "$skill" ||
fail "the diagnosis no longer offers the mute under the name the watcher reads, so the two have drifted apart"
grep -Fq 'crash-ignore/$name' "$ROOT/bin/omarchy-crash-watch" ||
fail "the watcher no longer reads the flag the diagnosis offers to write"
pass "the diagnosis and the watcher name the same flag"
grep -Fq 'omarchy-crash-mute' "$skill" ||
fail "the diagnosis no longer names the command that mutes, so the offer it makes cannot be carried out"
pass "the diagnosis names the command that mutes"
grep -Fq 'GROUP_DESCRIPTIONS[crash]' "$ROOT/bin/omarchy" ||
fail "the crash group has no description, so the router lists a group it cannot describe"
pass "the crash group is described in the router"
run_node_test <<'JS'
const fs = require('fs')