all repos — dingger @ f4a7346fd32f906ccc814364462c18afb3f10616

Watches the AI coding agents in your tmux panes on macOS and tells you which need you, from the menu bar, a floating panel, the status line and notifications; jumps to them, and restores tmux sessions and agents after a crash

agent search: spotlight-style fuzzy finder on ctrl+opt+cmd+shift+u

a centered, non-activating key panel that lists every agent and jumps to
the chosen one through the same dingger focus path as a row click.

- fzf-style matching: each word must match one of name, session, window,
  harness, status, or directory, letters in order; the best alignment wins
  (word starts and consecutive runs score higher), matched title letters
  are highlighted.
- empty query keeps the menu's order, so enter jumps to the top waiting
  agent.
- the selection follows the agent, not the position, as states change;
  the list scrolls to keep it visible.
- keys: arrows, ctrl+n/p, ctrl+j/k, enter, esc, ctrl+u; the shortcut again
  or clicking elsewhere closes it.
- search_hotkey setting; an unedited config file is upgraded. menu item
  "Search Agents...". rows carry the pane's directory.
- --print-search and --snapshot-search debug flags; the panel's background
  and snapshot code are shared.

selftest covers matching, ranking, highlighting, and selection; e2e step
15 checks queries through the real binary (fails when search only looks at
titles). e2e resolves relative binary paths, which tmux hooks need.
Igor Soarez igor@soarez.org
Thu, 22 Oct 2026 18:01:04 +0300
commit

f4a7346fd32f906ccc814364462c18afb3f10616

parent

7649396bf30a65096fc3944e1404835e661f00af

M README.md → README.md

@@ -49,8 +49,16 @@ then shows it for 3 seconds so you see it is armed; compact) or *Always*

(with a "Show all / Show less" toggle for the full list). The panel is always dark, in herdr's palette, so it reads the same over any desktop. - **Jump shortcut**: **⌃⌥⌘U** jumps to the top waiting agent from anywhere, - like clicking the tmux status line. Both shortcuts live in - `~/.config/dingger/config.toml` (menu bar, Settings…), reloaded on save. + like clicking the tmux status line. +- **Agent search**: **⌃⌥⇧⌘U** opens a Spotlight-style search over every + agent. Type to fuzzy-filter (each word must match, letters in order, the + name, session, window, harness, status, or directory); ↑↓ or ⌃N ⌃P / ⌃J ⌃K + select, ↩ or a click jumps, esc closes, ⌃U clears. With nothing typed, + agents are in the menu's order, so ↩ jumps to the top waiting agent. It + takes the keyboard without activating dingger, so focus returns where it + was. +- All shortcuts live in `~/.config/dingger/config.toml` (menu bar, + Settings…), reloaded on save. - **tmux status line** (`packaging/tmux/dingger.tmux`): the same summary after the clock. Clicking it jumps to the top waiting agent (the menu's top row), skipping the window you already look at.

@@ -108,7 +116,8 @@ 30 s, so everything asserted must arrive through events), fake agents driven

over the hook protocol, and a real tmux client whose focus it controls. It asserts every status transition, attendance by navigation, both click paths (including the real menu bar binary), the floating panel's visibility and -layout rules and content (compact, full, toggle), the status-line segment, latency with a +layout rules and content (compact, full, toggle), agent search (matching, +ranking, selection), the status-line segment, latency with a deliberately slow notifier, and state surviving a daemon restart. It never touches your tmux server.
M tests/e2e.sh → tests/e2e.sh

@@ -18,6 +18,9 @@

ROOT=$(cd "$(dirname "$0")/.." && pwd) DINGGER="${1:-$ROOT/target/release/dingger}" MENUBAR="${2:-$ROOT/target/dingger-menu}" +# tmux hooks run these from other directories: make them absolute. +case "$DINGGER" in /*) ;; *) DINGGER="$PWD/$DINGGER" ;; esac +case "$MENUBAR" in /*) ;; *) MENUBAR="$PWD/$MENUBAR" ;; esac SOCK=dingger-e2e DIR=$(mktemp -d /tmp/dingger-e2e.XXXXXX) HOOK="$DIR/agent.sock"

@@ -326,6 +329,21 @@ hook "$A2" working; hook "$A2" idle

expect "A2 done" "opt $A2 @agent_state" done launchd_env "$DINGGER" focus expect "dingger focus (jump shortcut) jumps, under launchd's PATH" "client_window" wa2 + +# --- 15. agent search ---------------------------------------------------------- +echo "15. agent search" +if [ -x "$MENUBAR" ]; then + mb() { DINGGER_TMUX_SOCKET="$SOCK" DINGGER_BIN="$DINGGER" "$MENUBAR" "$@"; } + expect "empty query lists every agent" "mb --print-search '' | tail -1 | cut -d' ' -f1,2" "4 agents" + expect "fuzzy name match, selected" "mb --print-search 'rvw42' | head -1 | cut -f1,2" "› ○ idle Review PR 42" + expect "every word must match" "mb --print-search 'deploy 42' | head -1" "No agents match 'deploy 42'" + expect "finds an agent by its window" "mb --print-search wc1 | head -1 | cut -f3" "c · wc1 · pi" + expect "finds agents by directory" "mb --print-search \"$(basename "$DIR")\" | tail -1 | cut -d' ' -f1,2" "4 agents" + hook "$A2" working + expect "status word ranks first" "mb --print-search working | head -1 | cut -f1" "› ◐ working" +else + fail "menu bar binary not found at $MENUBAR" +fi echo echo "$PASSES passed, $FAILS failed"