aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/dot_config
Commit message (Collapse)AuthorAgeFilesLines
...
* fix(swayidle): screen off at 5min, lock 30s later, lock on suspendLibravatar sommerfeld2026-05-131-8/+3
|
* refactor(swayidle): drop bespoke post-resume grace scriptLibravatar sommerfeld2026-05-132-42/+6
| | | | | | | | | | Replaces the resume-lock-grace.sh + after-resume hook from the previous commit with the simpler observation that sway already provides a wake grace for free: it pauses the idle counter during suspend and resets it on the first input event post-resume, so the existing timeout 300 lock naturally gives ~5min to interact before locking. Just dropping the before-sleep lock is enough; the script and after-resume directive were overcomplicating it.
* feat(sway): browser-aware idle inhibits + post-resume lock graceLibravatar sommerfeld2026-05-133-2/+58
| | | | | | | | | | | | | | | | | | | | | | Two related session-idle improvements: 1. ScreenSaver inhibit bridge. Browsers (LibreWolf/Chromium flatpaks) ask the session not to idle via the legacy org.freedesktop.ScreenSaver D-Bus API during video calls and fullscreen video; swayidle only honors logind's BlockInhibited property. Add inhibridge as a user unit to translate the former into the latter, so e.g. a Google Meet tab now keeps the screen from locking, dimming and (downstream) suspending. 2. Post-resume grace period. Locking on before-sleep meant every wake demanded the password even for a quick check. Replace with: before-sleep -> only pause media after-resume -> resume-lock-grace.sh 30 The grace script runs a one-shot swayidle that locks iff the user stays idle for 30s after the wake, with a watchdog that exits as soon as swaylock comes up (or after a hard cap) so it never lingers alongside the main swayidle. The 5-min main idle-lock and explicit loginctl lock-session paths are unchanged.
* fix(sudoers-rs,waybar): pass DIFFPROG (and friends) through sudo-rsLibravatar sommerfeld2026-05-132-5/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The previous fix sidestepped sudo-rs's env scrubbing by setting DIFFPROG inside a nested root shell. That works but it's the wrong shape — every command that wants to honour a user UX env var would have to do the same dance. Configure the policy once instead. etc/sudoers-rs: Defaults env_keep += "DIFFPROG" Defaults env_keep += "EDITOR VISUAL SUDO_EDITOR GIT_EDITOR" Defaults env_keep += "PAGER MANPAGER GIT_PAGER SYSTEMD_PAGER" Defaults env_keep += "LESS LESSOPEN SYSTEMD_LESS" env_keep is the unconditional pass-through list, so no '-E' is needed on the call site — `DIFFPROG='nvim -d' sudo pacdiff` Just Works, same as it does for `EDITOR=nvim sudo systemctl edit foo`, `PAGER=less sudo journalctl …`, etc. None of these vars influence privilege boundaries; they only configure user-facing program behaviour, so widening env_keep to cover them carries no security trade-off worth accounting for. The existing per-visudo env_keep lines are kept for documentation value (they're now subsumed by the global rule but make the intent explicit at the visudo call sites). The waybar pacdiff click handler reverts to the canonical form `DIFFPROG='nvim -d' sudo pacdiff`, matching the recipe pacman.git ships in /usr/share/doc/pacman/. Will take effect after the next `chezmoi apply` redeploys /etc/sudoers-rs (the run_onchange_after_deploy-etc.sh.tmpl script re-installs it with mode 0440 whenever its hash changes).
* fix(waybar): pacdiff click — set DIFFPROG inside the root shellLibravatar sommerfeld2026-05-132-3/+5
| | | | | | | | | | | | | sudo-rs scrubs the env by default, so neither `DIFFPROG=… sudo pacdiff` nor `sudo DIFFPROG=… pacdiff` reaches pacdiff with the variable set. Sidestep the env-policy question entirely by running sudo sh -c 'DIFFPROG="nvim -d" pacdiff' so the assignment happens inside the privileged shell, after the env-scrubbing boundary. No sudoers-rs change required, and the same form works identically under stock sudo if the user ever switches back.
* feat(waybar,systemd-units): wire up new system-health modules and timersLibravatar sommerfeld2026-05-132-1/+61
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Bar layout: insert the four new modules between custom/update and custom/thunderbird so that all 'something needs your attention' indicators live as a contiguous group on the right side, in roughly escalating actionability: custom/notifications -- mako history (always present, gray baseline) custom/update -- '`just update` was N hours/days ago' custom/pacdiff -- '.pacnew/.pacsave waiting' custom/arch-audit -- 'fixable CVE in installed package' custom/failed-units -- 'systemd unit failed' custom/lostfiles -- 'unowned files under tracked dirs' custom/thunderbird -- 'unread mail' Click handlers all use the floating-ghostty + 'press enter to close' idiom established by the existing update module so output stays inspectable. arch-audit and lostfiles open their /run report in `nvim -R` (read-only) since the source of truth lives in those files. style.css: extend the shared 6px-padding selector list, the .fresh zero-padding rule (so empty-state modules disappear cleanly), and add .warn/.critical color rules consistent with the rest of the palette (yellow #fabd2f for 'review when convenient', red #fb4934 for 'review soon'). systemd-units/system.txt: enable the three new system timers - btrfs-balance@-.timer (monthly partial balance on /) - arch-audit.timer (daily CVE report refresh) - lostfiles.timer (weekly unowned-files report refresh) Picked up automatically on the next `just unit-apply`.
* feat(waybar): pacdiff + failed-units remindersLibravatar sommerfeld2026-05-132-0/+105
| | | | | | | | | | | | | | | | | | | | | | | | | Two live waybar modules — no timer/state-file pipeline because the inputs are cheap to compute on every poll: custom/pacdiff (interval 300s) Counts unresolved .pacnew / .pacsave files via `pacdiff -o` (output mode — lists only, takes no action). Hidden at zero. Yellow 'pacdiff N' otherwise. Mako fires once on the 0→N transition, so you get exactly one nudge per upgrade wave, not a sustained re-nag for files you've decided to defer. Click runs `sudo DIFFPROG='nvim -d' pacdiff` in a floating ghostty. custom/failed-units (interval 30s) Sums `systemctl --failed` (system) and `systemctl --user --failed` counts. Hidden at zero. Red 'failed N' otherwise. Mako fires only on upward transition (count went up since last poll), so already-known failures don't keep paging you while you investigate. Click prints both `systemctl --failed` outputs in a floating ghostty. Both modules use the same $XDG_RUNTIME_DIR/waybar-X-prev pattern as the update reminder for state, which makes 'reboot resets the nag' the default behaviour — exactly the right semantics for both: a fresh boot deserves a fresh look at pending pacdiffs and any failed units.
* feat(lostfiles): weekly unowned-files refresh + waybar reminderLibravatar sommerfeld2026-05-131-0/+48
| | | | | | | | | | | | | | | | Wiring (mirrors arch-audit, with weekly cadence and Nice=19/idle I/O): lostfiles.timer (weekly, Persistent=true, RandomizedDelaySec=1h) → lostfiles.service → /run/lostfiles.txt (default mode — strict produces too many false positives for a passive reminder) → custom/lostfiles waybar module (interval 600s) → mako 'normal' once/7d while count > 0 → on-click: `ghostty -e nvim -R /run/lostfiles.txt` Default mode (no `strict` argument) is intentional: it already filters the package's curated false-positive list at /etc/lostfiles.conf, which is what we want for a low-noise weekly nudge. Switching to `strict` is a one-line change in lostfiles.service if signal-vs-noise tilts later.
* feat(arch-audit): daily CVE refresh + waybar reminderLibravatar sommerfeld2026-05-131-0/+46
| | | | | | | | | | | | | | | | | | | | | | | Wiring: arch-audit.timer (daily, RandomizedDelaySec=1h, Persistent=true) → arch-audit.service (After=network-online.target) → /run/arch-audit.txt ('--upgradable' output, atomic via .tmp+mv) → custom/arch-audit waybar module (interval 300s) → mako 'critical' once/24h while count > 0 → on-click: `ghostty -e nvim -R /run/arch-audit.txt` The bar entry stays hidden when there are no fixable CVEs, fades in as red 'CVE N' the moment arch-audit finds at least one, and the throttled mako means you'll see exactly one notification per day instead of one per waybar poll. No -Sy refresh and no auto-update — this only reports the gap between what's installed and what's already in the repos. Why /run and not the user's runtime dir: the producer is a system unit (needs the system's pacman db on the network-online path), the consumer is a user-scope waybar that just reads it; /run is the canonical 'fast, volatile, world-readable' system-tmpfs and survives the reboot cycle in exactly the way we want — fresh empty file on every boot, repopulated on the next timer fire.
* feat(zsh): rebuild PATH hash on every completionLibravatar sommerfeld2026-05-131-0/+1
| | | | | | | | | | | | | `zstyle ':completion:*' rehash true` makes zle re-scan $PATH directories on every TAB instead of caching the hash table at shell startup. Cost is trivial (one stat() per PATH entry per completion), benefit is that newly installed binaries — from paru, cargo install, pip install --user, npm install -g, manual /usr/local/bin drops, anything — show up immediately without an explicit `hash -r` or new shell. The pacman-hook alternative at https://wiki.archlinux.org/title/Zsh#Persistent_rehash only catches paru/pacman installs, missing cargo/pip/manual; rehash=true catches them all for the same negligible cost.
* feat(waybar,nvim): update-staleness reminder; nvim update visibleLibravatar sommerfeld2026-05-134-5/+108
| | | | | | | | | | | | | | | | | | | | | | | | | | | Two related changes around the 'just update' UX: 1. nvim-update no longer runs --headless. The diff buffer that vim.pack.update opens *is* the per-plugin changelog, and that was being thrown away under headless. Drop --headless from the justfile recipe and the trailing :qa! from config.update.run() so the buffer stays open until the user reviews and quits manually. Mason output was already visible because mason-tool-installer print()s. 2. New waybar 'custom/update' module + matching mako notification as a gentle staleness reminder, replacing any temptation to run unattended pacman -Syu (a bad idea on Arch: rolling, news-driven manual interventions, AUR rebuilds, partial-upgrade hazards). Source of truth: /var/log/pacman.log — last '[PACMAN] starting full system upgrade'. No daemon, no -Sy poll, no extra state file beyond a per-session notify-throttle stamp in $XDG_RUNTIME_DIR. Tiers (hours since last full upgrade): < 24h hidden (":empty" via #custom-update.fresh padding 0) 24-168h yellow + normal-urgency mako, throttled to 1/24h >= 168h red + critical-urgency mako, throttled to 1/24h Click runs 'just update' in a floating ghostty.
* feat(sway): non-XF86 alternatives for media/hardware keybindsLibravatar sommerfeld2026-05-131-0/+25
| | | | | | | | | | | | | | | | | | | | | Every sway action that was reachable only via an XF86 keysym now has a Super-based alternative, so all bindings work on keyboards without a multimedia row. Frequent (direct binds, vim-direction layout on Super+Ctrl): Super+Ctrl+k/j = volume +/- Super+Ctrl+space = play/pause Super+Ctrl+l/h = next/previous track Super+Ctrl+]/[ = brightness +/- Rare (submode 'system' via Super+x; one letter runs and exits): b bluetooth · w wifi · r rfkill · s suspend · d display v pulsemixer · k KEYBINDS viewer · m mako history Escape/Return exits Existing Super+m / Super+Shift+m / Super+Shift+s already covered mic-mute / sink-mute / lock; XF86 binds untouched so the laptop's Fn-row keeps working. KEYBINDS.md updated.
* feat(git): pre-push checks Co-authored-by trailers for agentsLibravatar sommerfeld2026-05-131-5/+14
| | | | | | | | | | | | | | Same substring blacklist (copilot, claude, codex, ...) is now also applied to every Co-authored-by trailer in the commit message, not just the author header. Agents commonly slip in via that route. Trailers extracted with %(trailers:key=Co-authored-by,valueonly, unfold,separator=%x1f) and split in awk on \037, which can't appear in identity strings, so the tab-delimited record format stays unambiguous. To fix a flagged trailer use git commit --amend / interactive rebase to drop the Co-authored-by line; --reset-author won't help here.
* feat(git): pre-push also rejects coding-agent authorsLibravatar sommerfeld2026-05-131-14/+42
| | | | | | | | | | | | | | Block commits where the author name/email contains any of: copilot, claude, codex, chatgpt, cursor, aider, devin, [bot], @openai., @anthropic. Use plain index() substring matching in awk to dodge regex-escaping pitfalls (an earlier draft using regex turned \[bot\] into a char class via -v escape processing and false-matched 'o' in 'com'). Fix: rebase with --reset-author re-stamps you as author while keeping the agent as it was (or drop them entirely). Documented in the failure message.
* feat(git): pre-push also rejects commits with foreign committerLibravatar sommerfeld2026-05-131-8/+34
| | | | | | | | | | | | | Now flags any commit whose committer name+email doesn't match the local user.name / user.email (which respects the includeIf rules in ~/.config/git/config, so per-tree work/personal identities work). Author is left free: pulling someone else's commit and rebasing it locally re-stamps the committer to you, satisfies this gate, and the original author is preserved in the commit metadata. Both checks (signature + committer) run in one rev-list pass with tab-separated fields so awk parses unambiguously.
* feat(git): global pre-push hook rejecting unsigned commitsLibravatar sommerfeld2026-05-132-0/+60
| | | | | | | | | | | | | | Activated via core.hooksPath = ~/.config/git/hooks in the global git config. The hook walks each ref being pushed (range: remote..local or, for new branches, local --not --remotes) and checks %G? on every commit. Accepts G/U/X/Y (good signature variants), rejects N/B/E/R (no signature, bad, missing key, revoked). Bypass: git push --no-verify This repo overrides hooksPath to .githooks/ for its just-check pre-commit gate, so a thin .githooks/pre-push delegates to the global hook to keep the policy enforced here too.
* feat(sway,waybar): scratch nvim+ipython binds; bolder VPN visualsLibravatar sommerfeld2026-05-133-4/+10
| | | | | | | | | | | | | | | | | VPN module: - Pango markup colours the text directly so up/down is visually unambiguous even without CSS classes (green shield up, dim strikethrough down) - .down also gets a faint red background tint for at-a-glance scan Sway: - Super+Shift+t -> floating ghostty with nvim editing a fresh $XDG_RUNTIME_DIR/scratch-<epoch>.txt (auto-cleared on reboot via tmpfs) - Super+c -> floating ghostty with ipython (quick calculator / python scratch) KEYBINDS.md updated.
* feat(waybar,sway): htop click handler, app keybinds, VPN toggleLibravatar sommerfeld2026-05-135-0/+54
| | | | | | | | | | | | | | | | | | | | waybar: - cpu / custom/memory: on-click opens floating ghostty with htop - new custom/vpn module between custom/memory and network#bond: shows 'VPN' coloured by interface UP flag (green up, dim down); on-click toggles networkctl up/down hodor; SIGRTMIN+8 used for instant refresh after toggle sway: - Super+Shift+Return -> ghostty -e yazi - Super+Shift+b -> librewolf vpn-toggle.sh runs networkctl (no sudo) thanks to a new polkit rule allowing wheel-group members to invoke org.freedesktop.network1.* without a password prompt. systemd-networkd's polkit gate is a separate path from sudoers, so this is the idiomatic fix. KEYBINDS.md updated for both new sway bindings.
* feat(mako-history): reopen picker after each selectionLibravatar sommerfeld2026-05-131-22/+25
| | | | | | After Enter copies+dismisses an entry, reopen the wofi window so the remaining notifications can be processed without re-triggering the keybind. Esc closes the loop.
* fix(mako-history): drop Alt-d; Enter copies+dismissesLibravatar sommerfeld2026-05-131-20/+7
| | | | | | | | wofi's key_custom_N only stages an exit code; it does not actually exit on the keybind, so Alt-d alone did nothing visible. Drop the custom keybind entirely and let Enter copy+dismiss in one stroke. Esc cancels. Since dismissed entries are now hidden, walking the list with Enter is a workable replacement for the dropped "dismiss without copy" path.
* fix(webcam-status): silence SC2086 on intentional word-splittingLibravatar sommerfeld2026-05-131-0/+1
|
* feat(mako-history): hide dismissed entries; consolidate keybindsLibravatar sommerfeld2026-05-131-41/+38
| | | | | | | | | | | | | | | | | Two behaviour changes: - Hide entries that were previously dismissed via the picker (the state file now acts as a hide-list, not a marker). The list shrinks as you process it; no more grey ' ' rows clogging the view. - Drop the secondary Alt-c custom key. wofi's '--define key_custom_N' appears unreliable past N=0, so Alt-c and Alt-d both silently failed. Reduce to a single custom slot (Alt-d) and remap actions: Enter -> copy + dismiss (was: re-emit + mark seen) Alt-d -> dismiss without copy Re-emit was rarely useful given mako already shows the bubble on arrival; copying is the common need. KEYBINDS.md updated to reflect the new action set.
* chore: drop dot_copilot tree; format clangd configLibravatar sommerfeld2026-05-131-6/+6
| | | | | - Remove dot_copilot/ entirely (no longer needed). - Run prettier on dot_config/clangd/config.yaml.
* style: apply formatter drift across repoLibravatar sommerfeld2026-05-1310-41/+54
| | | | | | | Pre-existing whitespace/style drift caught by `just check`. Touch nothing semantic — pure formatter output (shfmt -i 2 -ci -s, ruff, prettier, taplo). Excludes dot_config/clangd/config.yaml whose manual indentation is intentionally preserved.
* feat(privesc): migrate from opendoas to sudo-rsLibravatar sommerfeld2026-05-133-15/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | doas's one-shot password and absent 'sudo -v' kept wasting hour-long paru AUR builds. sudo-rs is a memory-safe Rust rewrite (ISRG/Ferrous Systems), drop-in CLI compatible, and the same one Ubuntu 25.10 ships as default. We follow the Arch wiki 'Using sudo-rs without the sudo package' recipe verbatim — no custom shims. - meta/base.txt: -doas-sudo-shim +sudo-rs - etc/sudoers-rs (mode 0440): wiki minimal config + NOPASSWD reboot/poweroff - etc/pam.d/sudo: 4-line copy of upstream sudo's PAM file - run_onchange_after_deploy-etc.sh.tmpl: use real sudo, deploy sudoers-rs at 0440, create /etc/pam.d/sudo-i and /usr/local/bin/{sudo,sudoedit, su,visudo} → sudo-rs symlinks idempotently - delete etc/doas.conf, dot_local/bin/{doasedit,sudo} - zshrc: drop sudo=doas/sudoedit=doasedit aliases; rewrite ss/gimme/ pacdiff/ssys to call sudo - justfile: s/doas/sudo/g (status/diff/restore helpers) - nvim: rename :DoasWrite → :SudoWrite (uses sudo -S) - sway config: reboot/poweroff buttons call sudo - bootstrap.sh: update step-5 comment - README/KEYBINDS/copilot-instructions: flip the privesc convention No Defaults overrides: sudo's defaults (passwd_tries=3, timestamp_timeout=5) already fix the doas pain, and paru SudoLoop (kept) refreshes the 5-min window via real sudo -v.
* feat(doas): smarter sudo shim + paru SudoLoopLibravatar sommerfeld2026-05-131-1/+1
| | | | | | | | | | | | | | | | | | | The packaged doas-sudo-shim is just 'exec doas "$@"', which means 'sudo -v' (used by paru --sudoloop to keep the auth timestamp fresh during long AUR builds) hits doas, which doesn't implement -v, and the loop dies. Then when the build finally finishes and tries the real install, the cached timestamp has long expired, so we reprompt — and opendoas only allows one attempt before bailing, so a single mistype throws an hour of compilation away. Replace it (per-user, via $HOME/.local/bin precedence) with a shim that translates: -v -> doas true (refresh persist timestamp) -k / -K -> doas -L (clear) -E -H -i -S etc -> dropped (no doas equivalent) rest -> doas "$@" Then enable SudoLoop in paru.conf so the timestamp stays fresh.
* style(waybar): use real anchor U+2693 (⚓) for dock indicatorLibravatar sommerfeld2026-05-131-1/+1
| | | | | Plain Unicode anchor renders via the system emoji font everywhere instead of the nerd-font private-use-area glyph.
* style(waybar): swap dock glyph to anchor (nf-md-anchor)Libravatar sommerfeld2026-05-131-1/+1
| | | | | Pun on "ship docked at port" — and just looks better than the dock_window glyph at small sizes.
* feat(waybar): add dock indicator next to batteryLibravatar sommerfeld2026-05-133-0/+40
| | | | | | | | | | Detects the ThinkPad USB-C Dock Gen2 by its built-in ethernet adapter (USB 17ef:a387) — the dock's USB hubs share product IDs with internal ThinkPad hubs but the ethernet only exists when the dock is attached. The custom/dock module sits to the left of battery; collapses to empty text when undocked so the bar stays clean on the go. Green dock glyph when docked.
* fix(emoji): split skin-tone filter into its own picker scriptLibravatar sommerfeld2026-05-132-5/+10
| | | | | | | | The previous one-liner stuffed an inline pipeline into BEMOJI_PICKER_CMD via 'sh -c' with three layers of nested quoting, which broke under bemoji's eval ("grep: 1: Syntax error: Unterminated quoted string"). Move the filter+wofi pipeline into emoji-wofi.sh and point the env var directly at it. No more quoting gymnastics.
* feat(emoji): filter out skin-tone variants in bemoji pickerLibravatar sommerfeld2026-05-132-1/+12
| | | | | | | | Skin-tone modifiers (U+1F3FB..U+1F3FF) clutter search results with five near-duplicates per people-emoji. New ~/.config/sway/emoji-picker.sh wraps bemoji and pipes its emoji list through grep -vP before handing it to wofi. Quoting was getting hairy inline in sway's exec, so the wrapper script makes it readable.
* fix(wofi): allow fuzzy search in emoji pickerLibravatar sommerfeld2026-05-132-11/+8
| | | | | | | | | The bemoji invocation passed --hide-search, and the shared wofi stylesheet additionally forced #input opacity to 0, so even without the flag the search box was unusable. Drop --hide-search from bemoji's picker cmd and replace the CSS hack with a normal styled input. Pickers that want arrow-only UI (mako-history, clip-picker) keep --hide-search and continue to render without an input row.
* feat: vim nav in wofi, bemoji, clip picker, webcam glyph fixLibravatar sommerfeld2026-05-134-3/+46
| | | | | | | | | | | | | | | | | | | | | | | - wofi config: key_up/key_down accept Up,k / Down,j; Ctrl-u/Ctrl-d for page jumps. Picker scripts auto-load this since they only pass --style. - waybar webcam glyph: U+F0D5D (camera/photo, looked Instagram-y) -> U+F0567 nf-md-video (handheld video camera). - Clipboard picker migrated from fuzzel to wofi for consistency with the notification picker. New driver dot_config/waybar/clip-picker.sh: pick (Mod+p) Enter pastes, Alt-d deletes delete (Mod+Shift+p) Enter deletes No clipboard "read" indicator: Wayland has no API for observing reads. - Emoji picker: bemoji on Mod+period, driven through wofi (so vim nav applies there too) and configured to type + copy via wtype. - LibreWolf flatpak: --device=all override so v4l2 webcams work. Flatpak has no finer-grained device flag. - KEYBINDS.md updated: Mod+p / Mod+Shift+p now describe wofi behavior; Mod+period documented.
* fix(waybar): dismiss/restore wrappers parse mako text formatLibravatar sommerfeld2026-05-132-3/+11
| | | | | | | | | | Same -f-doesn't-exist regression as 3205afc / d76ff3c. Without -f the inner pipeline produced no ids, so the dismissed-set never grew and notifications stayed pending forever after Mod+n. Switch to sed extraction of 'Notification N:' lines for both dismiss-visible.sh (list) and restore-pending.sh (history). Verified the dismissed-set is populated correctly for top/all modes.
* fix(waybar): mako-status counts ids by parsing text dumpLibravatar sommerfeld2026-05-131-9/+11
| | | | | | | | Same root cause as 3205afc: this makoctl version has no -f flag, so the '%i' lookup silently produced no ids and the bar always showed empty. Switch to a sed extraction of 'Notification N:' lines from list+history. Verified against simulated input matching the user's real makoctl output: 0/some/all dismissed all render correctly.
* fix(waybar): parse real makoctl text format (no -f support)Libravatar sommerfeld2026-05-131-24/+44
| | | | | | | | | | | | This makoctl version doesn't accept -f. Drop that path and parse the actual text dump: Notification N: <summary> <- summary on the same line App name: <app> [Category: <cat>] [Body: ...] <- absent on this version, kept anyway Urgency: <urgency> Verified against the user's pasted output.
* fix(waybar): use makoctl -f format for history pickerLibravatar sommerfeld2026-05-131-33/+25
| | | | | | | | | | The text-mode parser was looking for 'Notification N:' on a line by itself, but makoctl prints 'Notification N: <summary>' with the summary inline — so every record was dropped and the picker came up empty. Switch to makoctl list/history -f '%i\t%a\t%s\t%b' which emits one clean tab-separated record per notification (mako >= 1.4). Multi-line bodies are folded back into the previous record.
* fix(waybar): notification picker also lists currently-visible bubblesLibravatar sommerfeld2026-05-131-5/+21
| | | | | | | makoctl list and makoctl history are disjoint — visible notifications aren't in history yet. The picker was only reading history, so it came up empty whenever the bar showed pending bubbles that were still on screen. Merge both lists, dedupe by id, visible first.
* feat(notifications): persistent-pending model + wofi history pickerLibravatar sommerfeld2026-05-138-45/+298
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Notifications now behave like a phone: pop briefly, auto-disappear, and remain "pending" until the user explicitly acknowledges them. The waybar count reflects pending only; idle uses a quieter glyph. State model: pending = ids in mako history/list MINUS dismissed-set state file: $XDG_RUNTIME_DIR/mako-dismissed (per-session id list) Glyph change: idle (0 pending) bell_outline U+F009C has pending bell_ring U+F009E (the previous bell_check_outline U+F11E8 "history present but nothing pending" branch is gone — there is no separate history concept now) Bindings (all now go through wrappers that maintain the dismissed-set): Super+n dismiss top visible + mark seen Super+Shift+n dismiss all visible + mark seen Super+Ctrl+n restore most recent + pop it from dismissed-set XF86Favorites history picker (rewritten on wofi) History picker (dot_config/waybar/executable_mako-history.py): - wofi --hide-search: arrow-only navigation, no fuzzy input - lines tagged [pending] / [seen] with app + summary + body - Enter re-emit via notify-send (re-shows the bubble) + mark seen - Alt-c copy "summary\nbody" to clipboard via wl-copy - Alt-d mark seen without re-showing - empty history shows a sentinel, no-op on Enter New scripts: executable_dismiss-visible.sh capture id(s) then makoctl dismiss executable_restore-pending.sh capture top-of-history id, restore, then drop that id from dismissed-set executable_mako-history.py Python rewrite (parses makoctl text output, drives wofi) Other: meta/wayland.txt add wofi (only used by this picker) dot_config/wofi/style.css minimal gruvbox style; hides input row as belt-and-suspenders even though --hide-search already does it
* style(waybar): swap obvious literal labels for Nerd Font glyphsLibravatar sommerfeld2026-05-136-29/+33
| | | | | | | | | | | | | | | | | | | | | | | Numeric/identity labels stay (CPU, MEM, °C, network arrows, clock). Iconic labels are replaced with codepoints from ttf-noto-nerd: battery BAT/CHR/PLG -> nf-md-battery_*, _charging, power_plug (U+F0079..F0084, U+F06A5) pulseaudio VOL/MUTE -> nf-md-volume_low/medium/high/off (U+F057E..F0581) bluetooth BT on/off -> nf-md-bluetooth/_off/_connect (U+F00AF/B0/B2) idle_inhib. INH/IDL -> nf-md-eye_off_outline/_outline (U+F06D1, F06D0) custom/wifi text only -> prefix nf-md-wifi/_off (U+F05A9, F05AA) custom/webcam CAM -> nf-md-camera (U+F0D5D) custom/notif. NTF -> nf-md-bell_outline/_check_outline/_ring (U+F009C, F11E8, F009E) custom/tb MAIL -> nf-md-email/_alert (U+F01EE, F0D42) style.css font-family widened from 'mono' to a declarative fallback chain so glyph rendering doesn't depend on fontconfig auto-fallback.
* feat(waybar): add webcam privacy indicatorLibravatar sommerfeld2026-05-133-0/+31
| | | | | | | | | | V4L2 capture goes directly through /dev/videoN and never traverses the PipeWire portal, so the built-in privacy module misses it. New custom/webcam module polls fuser on /dev/video* every 2s and shows a red 'CAM' badge when any device is held open. Empty text when idle, so the slot collapses and stays out of the way when the webcam is unused (i.e. always, on a usual day).
* fix(sway): call doas with absolute paths for reboot/poweroffLibravatar sommerfeld2026-05-131-2/+2
| | | | | | | | | | | doas matches the 'cmd' rule literally against argv[0], not against the resolved PATH lookup. With 'cmd /usr/bin/poweroff' in doas.conf, 'doas poweroff' is denied silently — works only as 'doas /usr/bin/poweroff'. The interactive shell aliases sudo->doas and was hiding the issue when typing the bare command in a terminal (PATH expansion happens in the shell before doas sees argv[0]... only when explicitly typed with absolute path).
* feat(sway): replace exit prompt with full session menu; drop fuzzel $PATH ↵Libravatar sommerfeld2026-05-132-3/+6
| | | | | | | | | | | listing - Mod+Shift+e: swaynag now offers Lock / Logout / Reboot / Poweroff instead of just 'Exit sway? Yes'. Reboot+Poweroff use doas; that's already nopass-permitted for wheel in etc/doas.conf - fuzzel.ini: drop list-executables-in-path=yes (back to upstream default). The launcher now shows only .desktop entries; power actions live in the Mod+Shift+e menu
* feat(waybar+sway): bluetooth module + unify wifi/bt toggle pathsLibravatar sommerfeld2026-05-134-8/+35
| | | | | | | | | | | | | | | - systemd-units/system/bt.txt: new file pairing the meta/bt.txt group; enables bluetooth.service via 'just unit-apply' - waybar: add the built-in bluetooth module; on-click runs the same bt-toggle.sh that XF86Bluetooth has always invoked. Status colors: blue when adapter is up, green when a device is connected, gray off - sway: XF86WLAN now runs wifi-toggle.sh (iwd D-Bus) instead of 'rfkill toggle wifi'. The latter required rfkill group membership (user is in wheel only), and aligning on the busctl path means the keybind and the waybar click drive the same code XF86RFKill (panic-disable all radios) keeps using 'rfkill toggle all' — that scope is genuinely rfkill-shaped.
* style(waybar): tighten right cluster — tray rightmost, drop disk, compact ↵Libravatar sommerfeld2026-05-132-17/+8
| | | | | | | | | | | | | MEM, drop LOAD label - modules-right: tray moved past clock to the rightmost slot; disk dropped (used% on btrfs is ambiguous and the value rarely moves) - custom/memory: drop the available-side readout, output 'MEM 3.2G 40%' instead of 'MEM 3.2G (40%) / 4.5G (56%)' - cpu: drop the 'LOAD' literal — bare '{load:0.2f}' next to the usage% is unambiguous in context The disk module config block is left intact for easy reactivation.
* style(waybar): group clickable modules on the right edgeLibravatar sommerfeld2026-05-131-3/+3
| | | | | | | Read-only stats (cpu, temp, memory, disk, network, battery, privacy) on the left half of modules-right; interactive ones (pulseaudio mute, wifi toggle, idle_inhibitor, mako history, thunderbird, tray, clock) clustered on the right.
* feat(waybar): more clickable modules + load avg in CPU readoutLibravatar sommerfeld2026-05-132-6/+34
| | | | | | | | | | | | | - cpu: append 'LOAD {load:0.2f}' (1-min load average) to every state - custom/wifi: left click toggles iwd Powered via D-Bus (new wifi-toggle.sh) - custom/notifications: left click opens fuzzel history picker (mako-history.sh, previously bound to middle-click); the awkward per-click 'makoctl dismiss' is dropped — dismiss-all stays on right, restore stays on middle - clock: left click runs tb-toggle.sh (closest practical proxy for 'open Calendar tab' — Thunderbird hasn't shipped a -calendar CLI flag since Lightning was integrated, so the user lands on whatever tab TB was last on)
* fix(sway): bump tb-autostart post-IMAP grace period 5s -> 10sLibravatar sommerfeld2026-05-131-1/+1
| | | | | 5s still wasn't enough on cold boot — Thunderbird kept racing the SMTP listener and showing the connection-failure dialog.
* fix(sway): import PASSWORD_STORE_DIR into user manager + dbus envLibravatar sommerfeld2026-05-131-2/+2
| | | | | | | | | | | | | zprofile sets PASSWORD_STORE_DIR to $XDG_DATA_HOME/password-store, but systemd-user-launched services (notably waybar's tb-unread.sh, which calls 'pass show') don't inherit it. Sway is started from the login shell so the var is in its environment — propagate it to the user manager and dbus activation env, same pattern as the XDG_SESSION_* vars. Resolves the same problem already worked around for protonmail-bridge.service via a drop-in override; that override is now redundant but kept as belt-and-braces.
* feat(waybar): add Thunderbird inbox-unread moduleLibravatar sommerfeld2026-05-133-1/+74
| | | | | | | | | | | Polls the protonmail-bridge IMAP socket every 60s with STATUS INBOX (UNSEEN), displays the count next to the tray, and clicking the badge runs tb-toggle.sh to bring TB out of the scratchpad (or launch it). Setup: store bridge credentials in pass at email/protonmail-bridge/{user, pass}. The bridge surfaces them via 'protonmail-bridge --cli' -> 'info'. With no entries (or with the bridge unreachable) the module shows 'MAIL ?' in red and is otherwise inert.