aboutsummaryrefslogtreecommitdiff
path: root/menubar/model.swift
AgeCommit message (Collapse)Author
8 dayspi: a failed run says so: a 'failed' alert with the error, and the error in ↵Igor Soarez
red until seen
10 daysshow each pi agent's context use: a meter in the panel and search, text in ↵Igor Soarez
the menu
12 daysshow what pi agents cost today, this week and this month, counting forked ↵Igor Soarez
replies once
14 daysmark forgotten drafts in pi agents' input boxes, and keep them across a ↵Igor Soarez
crash or restore
14 daysreload pi agents on an old extension: versioned extension, control socket, ↵Igor Soarez
menu item and reload-agents
2026-10-27menu, panel, search: a peach ! in a column of its own; low dimmed moreIgor Soarez
the ! was the color of the name, read as part of it, and pushed high names two characters out of line. it is now peach (herdr's palette, no status uses it) in a fixed-width column every row has, so names line up. a low agent's name is dimmed to 0.5 (0.7 was hard to see).
2026-10-27mark as unread: make an idle agent done again, to come back to itIgor Soarez
like "mark as unread" in mail: an agent you have seen (idle) becomes done again, last among done agents of its importance, with no sound or notification. it stays done until you come back to it: leave its tmux window and return, or jump to it. marked while you look at it, it holds until you look away (`held`); a new turn clears it. only idle agents can be marked. - daemon: `pane.mark_unread` on the hook socket; the watcher applies it after the tick's observations (mark_unread, advance's hold rule). - `dingger unread [--pane]`: refuses done, working, blocked, and panes without an agent; returns once the agent shows as done. - pi: /unread (refused while the agent works or is blocked). - panel: right-click an idle agent in the full list, "Mark as unread". - search: ⌘U or right-click marks the selected idle agent; the footer offers ⌘U when it applies; search stays open. tests: unit (hold, jump, new turn, idle only), e2e step 22 (queue position, hold, look away and back, jump, refusals, no sound, menu, the extension), pi-live in real pi 1.4 (a mark, not a turn: an unknown command would also end done), swift selftest (menu only for idle, footer).
2026-10-26importance: mark an agent high, normal, or lowIgor Soarez
within a status, more important agents are listed first, and so jumped to first; status stays first. a high agent shows a bold ! before its name, a low agent's name is lightly dimmed with "low" on its second line, and it makes no sound (it still notifies and waits in line). in pi, /importance high|normal|low (completes the levels; none once one is typed out, so Enter runs it). the extension saves it in the session as a custom entry (dingger-importance), so /reload, restarts, /resume and restore bring it back; /new starts at normal. it shows a level other than normal in pi's footer, emits dingger:importance { level } for other extensions, and sends it with every report. for other agents, `dingger importance [level] [--pane]`; it refuses a pi that reports itself, whose saved level would win. the daemon stays the one writer of pane state: it writes @dingger_importance (unset for normal), which goes with the agent and survives a daemon restart. `dingger status` marks high and low. tests: e2e step 21 (order, the option, no sound for low, the menu bar, the command, the extension through a harness that now matches pi's extension API), a DINGGER_SOUND seam so sounds are observable, and a status-line check that read the counts once (flaky) now polls. pi-live: /importance in real pi 1.4, its footer and session entry, and the level after a restore; every pi there now uses the test's agent directory (a restored pi read the user's). negative controls fail each part.
2026-10-23session groups: list each pane once, save each group onceIgor Soarez
a pane in several sessions (a session group, `new-session -t`, or a linked window) was listed once per session: every agent of a group showed twice in the menu, panel, search, `dingger status`, and the counts. and snapshots saved each session of a group with its own copy of the windows, so restore would have rebuilt them twice and resumed each agent twice on one session file. - a pane keeps its first listing (tmux lists sessions by name) and is attended if the user looks at it through any session of the group. - snapshots keep the first session of each group; the others are not restored. e2e step 19 covers both; the previous binaries fail it. two checks (step 11's and this one) waited for idle after a turn that started from idle, which passed before the turn was even processed: they now wait for working first, and the negative control for group attendance fails as it should. step 18 now waits for the snapshot it later restores from.
2026-10-23list working and idle agents most recent firstIgor Soarez
within a status, the menu, panel, search, and `dingger status` listed done and blocked agents oldest first (the queue), and the rest by place. now working and idle agents are most recent first: the first idle row is the agent that finished, or that the user looked at, last. @dingger_since now means when the pane entered its current status, for every status (it was set only while the pane needed the user), and survives a daemon restart. the queue selects done and blocked panes by status, no longer by having a stamp. one ordering rule each in Rust (watcher::list_order) and Swift (listedBefore), with tests that fail on the old order; e2e step 11 makes an agent finish while watched and checks it moves to the top of the idle rows. agents idle since before this change share one stamp and keep their place order until they next change.
2026-10-23restore, step 3: offer it in the panel, menu, and status lineIgor Soarez
when tmux stops (and its sessions are missing from the running server, or no server runs), the daemon publishes the restore offer: offer.json for the menu bar app and @dingger_restore for the status line, withdrawn once restored or dismissed. - panel: a first row "↺ Restore 9 sessions · 22 agents" with when it was saved and how many agents were mid-turn; clicking restores, "Not now" dismisses. an offer shows the panel like a waiting agent; off stays off. - menu: the offer on top; restore all, one session, or not now. - status line: a clickable blue ↺N before the clock. - restore runs through the user's login shell, as a terminal starts tmux, so restored panes get a real environment, not launchd's; --report writes restore.log and notifies a summary. restore --dismiss. - commands log only warnings by default; SIGPIPE ends them quietly. e2e: the offer through the real menu bar binary, the summary notification, the offer clearing, a restore with no tmux running, and not now staying dismissed when a terminal starts tmux. the second test daemon is started directly (it leaked through a function's $! before, and dozens of leaked daemons fought over the test socket and loaded the machine); each run uses its own socket and checks its daemons stop.
2026-10-22agent search: spotlight-style fuzzy finder on ctrl+opt+cmd+shift+uIgor Soarez
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.
2026-10-20fix clicks from the menu bar app: find tmux without homebrew on PATHIgor Soarez
launchd starts the menu bar app with PATH=/usr/bin:/bin:/usr/sbin:/sbin, so the `dingger focus` it runs for every click (panel rows, menu rows, the jump shortcut) could not find homebrew's tmux and failed with a misleading "no tmux client attached"; the app discarded the error. dingger now finds tmux on PATH or in the usual install locations (DINGGER_TMUX overrides), reports a missing tmux as such, and the app logs failed jumps. also: panel rows own every click inside them (labels took the clicks and counted as window-drag background). e2e step 14 repeats the menu bar row click and dingger focus under launchd's environment; both fail with the previous binaries.
2026-10-20panel: readable everywhere, compact/full toggle, change-driven; jump shortcutIgor Soarez
- contrast: the summary used attributed-string colors (never vibrant) and the subtitles a vibrant system color, so they blended differently over light and dark desktops. the panel now uses herdr's mocha colors explicitly over a dark tint, identical on any background. - layout: compact in "when agents are waiting"; in "always" a show all / show less toggle switches to the full list (waiting, separator, rest). - rows are single-line with a trailing ellipsis instead of wrapping. - render only when the content changes, and log each render, instead of rebuilding every view every second. - --snapshot-panel renders the real panel offscreen over white and black after a different first render (stale content would show). - jump shortcut ctrl+opt+cmd+u (jump_hotkey) runs dingger focus; shortcuts are registered by id. an unedited first config file is upgraded. selftest covers the layout rules and content; e2e step 13 checks the full list, its separator, and the toggle labels.
2026-10-20floating panel: always-on-top agent HUD with a global shortcutIgor Soarez
a non-activating HUD panel (every Space, over full-screen apps, never takes focus) listing the agents waiting for you, with working and idle summarized on one line; rows jump to the agent, drag moves the panel and it remembers its place. modes: when agents are waiting (default), always, off; ctrl+opt+ cmd+e shows or hides it on top of the mode, and a manual hide lasts until another agent starts waiting. the shortcut is a carbon hotkey (no accessibility permission; clashes are reported in the menu) configured in ~/.config/dingger/config.toml, reloaded on save. the menu bar app is split into model, panel, hotkey and main. tested: --selftest checks the visibility rules (it fails if a newly waiting agent no longer re-shows a dismissed panel); e2e step 13 checks the panel content through the real binary.