aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/dot_config
Commit message (Collapse)AuthorAgeFilesLines
* fix(waybar): refactor A && B || C patterns to avoid shellcheck SC2015Libravatar sommerfeld11 days3-3/+4
| | | | | | | | Older shellcheck (Ubuntu's in CI) flags '[ test ] && cmd || true' as SC2015 because, despite the intent, A && B || C is not equivalent to if-then-else (C runs when A is true but B fails). Replace with explicit 'if … fi' or split into two 'A || continue' guards. Functionally identical, lint-clean across versions.
* zsh: hm wrapper needs --impure for builtins.getEnvLibravatar sommerfeld11 days1-1/+1
| | | | | | host.nix reads HOME/USER via builtins.getEnv, which returns "" under pure-eval (nix run's default). just-nix-switch already passes --impure; match it here.
* zsh: add hm wrapper for flake-based home-managerLibravatar sommerfeld11 days1-0/+12
| | | | | | | | | | | | The standalone 'home-manager' command defaults to the legacy ~/.config/home-manager/home.nix and errors out for flake users. The wrapper auto-selects the host/vm profile by /etc/os-release ID and points at whichever dotfiles checkout exists on the machine. Usage: hm news hm switch hm generations
* drop residual Mason references after p6 migrationLibravatar sommerfeld11 days1-3/+2
| | | | | - zsh: remove ~/.local/share/nvim/mason/bin from PATH - justfile: update comments to reflect Mason removal
* fix(nix,nvim): drop nodePackages.* (removed from nixpkgs), drop ↵Libravatar sommerfeld11 days1-2/+1
| | | | | | | | | | | | | | | | | | | github-copilot-cli (broken) nodePackages was removed wholesale from nixpkgs; everything that lived under it must be referenced via its top-level name or dropped. - prettier: moved nodePackages.prettier -> prettier (top-level alias). - jsonlint: not available at top level. Dropped from nix/common.nix AND from the nvim-lint and conform-nvim configs in dot_config/nvim/lua/plugins/lsp.lua. jsonls already provides schema-aware diagnostics; jq still handles formatting. The jsonlint redundancy is acceptable to lose. - github-copilot-cli (1.0.40 in nixpkgs): buildNpmPackage derivation doesn't redirect HOME during npm postinstall, so it fails with EACCES on /var/empty/.cache on Determinate nix. Removed; install manually from https://github.com/github/copilot-cli into /usr/local/bin/ as before (current host already has it there).
* fix(nix,nvim): drop gh-actions-language-server (not in nixpkgs); export USER ↵Libravatar sommerfeld11 days1-1/+0
| | | | | | | | | | | | | | in nix-switch - gh-actions-language-server is an npm package (lttb/gh-actions-language-server) not packaged in nixpkgs. Removed from nix/common.nix and from the vim.lsp.enable list in dot_config/nvim/lua/plugins/lsp.lua. Restore later via a per-project flake.nix if working on a workflows-heavy repo. - just runs recipes with a sanitized env where $USER may be unset; home-manager's activation script dereferences it unconditionally and fails with 'USER: unbound variable'. Export USER (and HOME for symmetry) at the top of the nix-switch recipe.
* refactor(nvim,zsh): remove Mason; use Home-Manager-provisioned toolingLibravatar sommerfeld11 days5-95/+38
| | | | | | | | | | | | | | | | | | | | | | | | | LSPs, formatters, linters, and the lldb-dap debugger now come from ~/.nix-profile/bin (see nix/common.nix). lspconfig keeps the default configs; we just opt-in via vim.lsp.enable() with an explicit list. Changes: - dot_config/nvim/lua/plugins/lsp.lua: drop mason*, replace mason-lspconfig handler with explicit vim.lsp.enable({...}); drop groovy/jenkins formatters and lint entries; drop systemd lint (nginx + groovy + systemdlint tools dropped per plan). - dot_config/nvim/lua/plugins/debug.lua: drop mason-nvim-dap; drop codelldb adapter; switch dap.configurations.cpp to type='lldb' (lldb-dap is the upstream successor, ships with pkgs.lldb). - dot_config/nvim/init.lua: remove mason.nvim, mason-lspconfig.nvim, mason-tool-installer.nvim, mason-nvim-dap.nvim from vim.pack.add. - dot_config/nvim/lua/config/update.lua: remove MasonToolsUpdateSync. - dot_config/zsh/dot_zshrc: flip plugin source order — prefer ~/.nix-profile/share, fall back to /usr/share/zsh (was the other way around). - nix/bootstrap.sh: drop the uv-python3.11 step (no longer needed once Mason no longer source-builds Python LSPs on Ubuntu 20.04). Phase 6 of the nix-on-host migration plan.
* feat(zsh): prepend ~/.nix-profile/bin to PATHLibravatar sommerfeld11 days1-1/+6
| | | | | | | | | So Home-Manager-provisioned tools shadow pacman/apt across host and VM, delivering identical tool versions from the same flake.lock. Mason bin stays for now; phase p6 of the nix migration removes it together with the Mason plugins. Phase 3 of the nix-on-host migration plan.
* refactor(nix): promote remote-dev/ to nix/ with common/vm/host splitLibravatar sommerfeld11 days1-1/+1
| | | | | | | | | | | | | | | | | | | | Restructures the Home-Manager profile to support both the Arch host and the Ubuntu remote-dev VM from the same flake. - remote-dev/ → nix/ (hard rename; .chezmoiignore updated) - home.nix split into common.nix (shared), vm.nix (Mason runtime carve-outs + podman stack), host.nix (gpg scdaemon delegation to system pcscd) - flake.nix exposes homeConfigurations.{vm,host} via a mkProfile helper - rj alias in dot_zshrc updated to ~/.local/share/dotfiles/nix - bootstrap.sh / justfile updated to use #vm against the new path The split is behaviour-preserving for the VM: vm.nix + common.nix together carry the same package set as the previous home.nix. host.nix is provisioned but not yet wired into bootstrap (phase p8). Phase 1 of the nix-on-host migration plan.
* refactor(sway): remove super+o VPN OTP keybindLibravatar sommerfeld11 days1-3/+0
| | | | No longer needed.
* feat(zsh): add dj/rj aliases for dotfiles and remote-dev justfilesLibravatar sommerfeld11 days1-0/+2
| | | | | | | dj invokes ~/dotfiles/justfile and rj invokes ~/.local/share/dotfiles/remote-dev/justfile, both pinned to the justfile's directory via --working-directory so the aliases behave identically from any CWD.
* fix(nvim): wrap vim.pack.update in :PackUpdate user commandLibravatar sommerfeld11 days1-1/+3
| | | | | | | nvim_create_user_command passes the callback a table with command metadata (args, bang, ...). Newer neovim's vim.pack.update validates its first arg as a list of names — that metadata table fails the list check with 'names: expected list, got table'. Wrap it.
* refactor(git): use classic .git/hooks/ for per-clone overrideLibravatar sommerfeld12 days1-10/+9
| | | | | | | | | | | | | | | | | Switch the dispatcher's per-clone override location from the bespoke .git/hooks-local/ to the classic .git/hooks/. This is: - The untracked location git has used since forever, so no new convention to learn. - Where husky, lefthook, pre-commit-the-tool, and most other hook managers install by default — they now "just work" again under our global core.hooksPath. git init's *.sample files don't collide because the dispatcher only matches the exact hook name and the executable bit. The only behavior change is that a forgotten legacy .git/hooks/pre-commit from before core.hooksPath was set will start running again — that's arguably restoring expected git semantics, not a regression.
* feat(git): per-clone hook override at .git/hooks-local/Libravatar sommerfeld12 days1-15/+29
| | | | | | | | | | | | | | | | Adds an untracked per-clone override layer to the hook dispatcher. Lookup order is now: 1. <git-dir>/hooks-local/<name> — untracked, per-clone, ignored by git 2. <repo-top>/.githooks/<name> — tracked, shared with teammates Use case: a shared repo ships a .githooks/pre-commit you want to locally replace without modifying the tracked file. Drop your hook in .git/hooks-local/<name> (chmod +x) and the dispatcher will run it instead — the global commit-msg trailer-strip and pre-push gate still run on top. If neither override exists, only the global user-level logic runs.
* feat(git): user-level hooks auto-dispatch into <repo>/.githooks/Libravatar sommerfeld12 days5-1/+74
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Inverts the hook delegation model. Previously per-repo hooks required a project to either (a) write the entire hook themselves and lose the global signed-commit / agent-author gate, or (b) override core.hooksPath and write passthrough stubs that exec back to $HOME/.config/git/hooks/*. Both are ergonomically miserable. Now: the global hooks at ~/.config/git/hooks/ are *always* the entry point. Each one calls a shared dispatcher (_dispatch.sh) that runs <repo>/.githooks/<hookname> if it exists, propagating its exit status, and then continues with whatever the global hook itself wants to do. Projects just drop an executable file at .githooks/<name> — no core.hooksPath, no stubs, no boilerplate. Repos that don't have a .githooks/ dir keep working exactly as before. GIT_HOOK_DISPATCHED guards against re-entry so legacy repos using the old stub-and-exec pattern don't loop. pre-push tees stdin so both the repo hook and the global ref-list loop see the full push payload. Adds two new always-no-op global hooks (pre-commit, post-commit) purely so the dispatch happens for those events too — previously only commit-msg and pre-push existed globally. Refactors this dotfiles repo to use the new pattern: drops the self-delegating .githooks/pre-push stub and removes the per-repo core.hooksPath override from `just init` (now an idempotent unsetter to clean up the override from past bootstraps). The remote-dev VM's home-manager profile symlinks all four hooks plus _dispatch.sh.
* feat(git): commit-msg hook strips AI Co-authored-by trailersLibravatar sommerfeld12 days1-0/+60
| | | | | | | | | | | | | | | | | Various agentic tools (Copilot CLI, VS Code chat, etc.) auto-append `Co-authored-by: Copilot <...>` / Claude / Codex trailers, which then trip the pre-push hook's agent-coauthor check and force a manual amend before the push goes through. Scrub at commit time instead. Uses the same agent-substring list as executable_pre-push (kept in sync by comment). Triggered as commit-msg (not pre-commit — pre-commit runs before the message exists). Drops matching trailers in-place, collapses trailing blanks, and is a no-op otherwise. Also symlinks the new hook in the remote-dev home-manager config so it deploys on the Ubuntu VM. Bypass: `git commit --no-verify`.
* fix(zsh): only rename zellij tab when our pane is focusedLibravatar sommerfeld12 days1-5/+17
| | | | | | | | | | | | | | | | | `zellij action rename-tab` always targets the focused tab — there is no CLI way to bind the rename to the calling pane. On session resurrect zellij re-spawns every shell almost simultaneously while one tab is focused, so every precmd hook fires and they all race to rename that single focused tab; the last writer wins and the rest of the tabs are stuck at `Tab #N`. This is the "all tabs got the same label" bug from earlier. Guard the rename hooks behind a focused-pane check using `zellij action list-clients` (matches the `terminal_<ZELLIJ_PANE_ID>` column). Background panes silently skip the rename and update lazily the next time the user focuses them and a prompt fires. After resurrect that means untouched tabs say `Tab #N` until you visit them — but no tab gets a wrong label anymore.
* Revert "fix(paru): pin llama-cpp-vulkan via IgnoreDevel"Libravatar sommerfeld12 days1-6/+0
| | | | This reverts commit 1d7feb8d405e135dc6109052948b8b9240cf882a.
* fix(paru): pin llama-cpp-vulkan via IgnoreDevelLibravatar sommerfeld12 days1-0/+6
| | | | | | | | | | | | | | | pacman.conf's IgnorePkg only stops pkgver upgrades. paru in Devel mode runs `git ls-remote` against AUR -git sources during sysupgrade and rebuilds whenever upstream has a newer commit hash — which is exactly what was triggering the 1-2h llama-cpp-vulkan rebuild on every `just update`. IgnoreDevel is paru's purpose-built knob for skipping that devel recheck (paru.conf(5)). Manual `paru -S llama-cpp-vulkan` still works when an upgrade is intentional. (Replaces a botched first attempt that used IgnorePkg, which is not a valid paru.conf option.)
* feat(mimeapps): make teams-for-linux (xsight profile) default for msteams://Libravatar sommerfeld12 days1-0/+2
| | | | | | | | | Both teams-sii.desktop and teams-xsight.desktop already advertise `MimeType=x-scheme-handler/msteams;` so they were registered as candidates, but mimeapps.list didn't pick a default and clicking an msteams:// link did nothing useful. Pin the xsight profile as the default; the sii profile is still available via `xdg-open` chooser / direct launch.
* refactor(zsh): rename zellij tabs to dir:cmd without position prefixLibravatar sommerfeld12 days2-8/+18
| | | | | | | | | | | | | | Zellij's default 'Tab #N' name is fixed at tab creation (the N is the immutable creation index, not the live position) and never auto-updates when tabs are closed or moved, so the default is actively misleading after any tab reorg. Tmux's `renumber-windows on` has no zellij equivalent and no plugin solves this cleanly. Restore shell-side renaming but drop the position prefix `N:` — visual order in the tab bar implies position. After a session resurrect or closing a middle tab, untouched tabs still show their previous dir:cmd label until the next prompt fires there, but at least there is no misleading number to second-guess.
* fix(yazi): render markdown with glow instead of okularLibravatar sommerfeld12 days1-2/+3
| | | | | | | | | okular is installed as flatpak (org.kde.okular), not as a native binary, so the bare `okular` invocation in the opener failed silently (orphan = true hides the ENOENT). glow is already in base.txt and renders inline in the terminal — better fit for a TUI file manager. block = true keeps yazi waiting until the user quits glow, mirroring `less`-style behaviour.
* fix(yazi): rename opener rule key from `name` to `url`Libravatar sommerfeld12 days1-2/+2
| | | | | | Yazi tightened its config schema; `name` is no longer accepted for glob-based opener rules, only `url` (or `mime`). Without this fix yazi errors on startup and falls back to preset settings.
* revert: drop snxctl-chromium wrapper, snx-rs works with default browser nowLibravatar sommerfeld12 days1-11/+2
| | | | | | | | | | | | User confirms snx-rs's SAML loopback no longer needs chromium routing. Remove: - dot_local/bin/snxctl-chromium (PATH-override wrapper) - dot_local/share/snx-rs/bin/xdg-open (chromium shim) - snx-rs LibreWolf SAML note in user-overrides.js The waybar snx-vpn toggle now just runs `snxctl connect` detached, no wrapper indirection.
* fix(zsh): preserve forwarded SSH_AUTH_SOCK in SSH sessionsLibravatar sommerfeld2026-05-141-2/+6
| | | | | | | | | | zprofile unconditionally pointed SSH_AUTH_SOCK at the local gpg-agent's ssh socket. On remote machines (e.g. remote-dev VM) that clobbers ssh-agent forwarding — `ssh-add -L` reports no identities because the VM's gpg-agent has no keys. Only override when there's no forwarded socket (no $SSH_CONNECTION or no $SSH_AUTH_SOCK from sshd).
* fix(remote-dev): install basedpyright outside MasonLibravatar sommerfeld2026-05-141-1/+6
| | | | | | | | | | | | | | | | Mason's pypi distribution of basedpyright pulls nodejs-wheel-binaries which only ships manylinux_2_28 Linux wheels. uv's python-build- standalone interpreter is tagged manylinux2014 (glibc 2.17 for max portability) and rejects those wheels; pip then falls back to building Node 24 from source, which fails on Ubuntu 20.04's gcc 9.4 (needs gcc >=10 for -std=gnu++20). Provide basedpyright via the system package manager instead: - pacman on Arch (added to meta/base.txt) - pkgs.basedpyright on the VM (added to remote-dev/home.nix) Drop it from mason-tool-installer's ensure_installed; lspconfig picks it up from PATH. Document the exception in remote-dev/README.md.
* feat(nvim): wire OSC 52 clipboard provider on SSH sessionsLibravatar sommerfeld2026-05-141-2/+16
| | | | | | | | | | | | | | | Previously `clipboard` was set to empty inside SSH sessions on the assumption no clipboard tool would be reachable. That broke yank → host-clipboard on the remote-dev VM. nvim ≥0.10 ships a built-in OSC 52 provider (vim.ui.clipboard.osc52). The terminal emulator (ghostty locally, zellij forwarding inside it) handles the escape sequence and writes to the host's clipboard, so we get yank-to-host without needing wl-copy/xclip on the VM. Paste over OSC 52 is rarely supported by terminals (security), so we wire it but it's effectively a no-op; bracketed paste from the terminal still delivers clipboard contents into the buffer.
* revert(nvim)+fix(remote-dev): keep Mason authoritative, give it cargo+rustcLibravatar sommerfeld2026-05-141-57/+44
| | | | | | | | | | | | | User policy: Mason should install everything it lists regardless of host-provided versions. Revert the PATH-filtering wrapper around ensure_installed (b2f129e) — back to a plain table literal. For shellharden specifically, Mason's only install source is `cargo install`. The Arch host has cargo via base-devel/rustup; the VM previously didn't, so Mason errored "ENOENT cargo". Add `cargo` and `rustc` to the remote-dev nix profile so Mason can build it on the VM too. Drop the shellharden package from home.nix — Mason owns it now, no more provider competition with the nix-profile binary.
* fix(nvim): skip Mason install for tools already on PATHLibravatar sommerfeld2026-05-141-44/+57
| | | | | | | | | | | | | | | Mason's installer tries one source per package. For tools that we already provide via the system package manager (Arch pkgs on the host) or nix-profile (on the remote-dev VM), Mason will keep trying to (re-)install via cargo/pip/etc. and report failures — but conform.nvim/nvim-lint resolve their binary from PATH anyway, so the Mason install is redundant. Filter ensure_installed at startup against vim.fn.executable(). Keeps behaviour identical on a fresh host (Mason still pulls everything), but silences spurious failures for tools that the user has chosen to provide system-wide (shellharden via nix-profile being the immediate case).
* fix(nvim,remote-dev): fall back to PATH node + provide ↵Libravatar sommerfeld2026-05-141-6/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | JRE/shellharden/python3-venv copilot.lua was hard-coding the chezmoi-pinned Node 24 at ~/.local/share/copilot-node/bin/node, which only exists on the Arch host where chezmoi runs run_onchange_after_install-copilot-node.sh. On the remote-dev VM the path is absent, so copilot-language-server spawned with cmd[0]=<missing> and printed 'Could not determine Node.js version'. Probe the pinned path with vim.fn.executable() and fall back to 'node' from PATH otherwise. For the VM PATH 'node' to be a supported version, switch home.nix from the rolling 'nodejs' alias to 'nodejs_24' (the version the chezmoi script also pins on the host). Address the cluster of Mason install failures on the VM: - autotools-language-server, codespell, mdformat, nginx-language-server, systemdlint -- pip-installed; fail because Ubuntu's python3 ships without venv. bootstrap.sh now apt-installs python3-venv; README documents the manual command for existing VMs. - groovy-language-server -- needs a JRE. Add 'jre' to home.packages. - shellharden -- Mason's cargo fallback can't run under our leaf-tools policy. Provide the binary via nix-profile instead so Mason finds it on PATH.
* fix(zsh): make compdef guard check completion fn, also wire nix-profile fpathLibravatar sommerfeld2026-05-141-8/+19
| | | | | | | | | | | | | | | | | | Previous guard checked `$+commands[Y]` (binary present in PATH), but the `compdef: unknown command or service: Y` message comes from compdef when the *completion function* `_Y` isn't registered — on the remote-dev VM `systemctl`, `just`, `lsd` are all on PATH yet zsh has no `_systemctl` because Ubuntu's system zsh doesn't include nix-profile's share/zsh/site-functions in fpath. Two-part fix: 1. Prepend $HOME/.nix-profile/share/zsh/{site-functions,vendor-completions} to fpath (when they exist) before compinit, so the completions get loaded on the VM the same way they do on Arch. 2. Switch the compdef guard to `$+_comps[Y]` — the assoc-array compinit actually populates with every command that has a registered completion handler. Still belt-and-suspenders in case something ships a binary without a matching completion file.
* fix(zsh): guard compdef on target command being installedLibravatar sommerfeld2026-05-141-5/+11
| | | | | | | | | | | | | | On minimal hosts (remote-dev VM, fresh container) several of the `compdef alias=target` lines fail at login with messages like: compdef: unknown command or service: just compdef: unknown command or service: systemctl compdef: unknown command or service: lsd — because zsh has no `_just`/`_systemctl`/`_lsd` completion function loaded when the binary isn't on the system. Wrap each call in a small helper that checks $commands[<target>] first so absent tools just silently skip their alias completion instead of spamming the prompt.
* feat: add another work includeIfLibravatar sommerfeld2026-05-141-0/+2
|
* refactor(zsh): stop renaming zellij tabs from the shellLibravatar sommerfeld2026-05-141-9/+7
| | | | | | | | | | | | | | | | | | | The hand-rolled `N:dir:cmd` tab labels could never stay in sync: - After session resurrection, tab names are restored from disk but no shell-visible event fires, so labels stayed stale until the user hit Enter to trigger precmd. - After closing a middle tab, zellij renumbers surviving tabs but again emits no per-pane event, so the `N:` prefix on every tab to the right silently became wrong. - Once a tab has a custom name, zellij's tab-bar plugin uses it verbatim — there's no way to keep the default `Tab #N` numbering while also injecting dir/cmd info. The only plugin that addresses this (vmaerten/ zellij-tab-rename) requires zellij built from main. Dropping the hooks restores zellij's built-in `Tab #N`, which is the single label that stays correct across resurrect and renumber. The zsh prompt already shows CWD inside the pane.
* feat(sway): bspwm-style workspace back-and-forth toggleLibravatar sommerfeld2026-05-141-0/+4
| | | | | | workspace_auto_back_and_forth yes makes `workspace number N` jump back to the previously focused workspace when N is already current. Applies to both $mod+N keybinds and waybar workspace clicks.
* feat(waybar): snx-rs VPN status indicator + click toggleLibravatar sommerfeld2026-05-143-0/+57
| | | | | | | | | | | New custom/snx-vpn module sits next to custom/vpn (the wireguard one): - snx-vpn-status.sh shells out to `snxctl status` (timeout 2s) and maps the output to three states: down (grey strikethrough), connecting/MFA (amber), up (green). Tooltip shows the full status block when up. - snx-vpn-toggle.sh disconnects when up, runs snxctl-chromium detached when down (so SAML lands in the flatpak ungoogled-chromium without blocking waybar). Both paths refresh the module via SIGRTMIN+9.
* refactor(snxctl-chromium): drop daemon drop-in, override snxctl's PATHLibravatar sommerfeld2026-05-141-10/+0
| | | | | | | | | | | | snx-rs.service is a system unit, not --user, so the prior approach of overriding the daemon's PATH via a systemd drop-in could never apply. And it wasn't needed anyway: snxctl itself runs opener::open(url) in-process, so prepending the shim dir to snxctl's PATH is enough. - Drop dot_config/systemd/user/snx-rs.service.d/10-chromium-saml.conf. - snxctl-chromium now just sets PATH and exec's snxctl connect. - xdg-open shim no longer forces --new-window so chromium can reuse a warm window (faster SAML round-trip).
* feat(sway): fuzzy search in power menuLibravatar sommerfeld2026-05-141-1/+2
| | | | | Drop --hide-search and enable --matching=fuzzy --insensitive so typing 'po' jumps to Poweroff, 'su' to Suspend, etc.
* feat(sway): Super+o types VPN TOTP via wtypeLibravatar sommerfeld2026-05-142-0/+26
| | | | | | | Fetches the current code from pass-otp's vpn/totp entry and types it into the focused surface with wtype. Falls back to wl-copy + a notification when wtype isn't available or the focused surface lacks virtual-keyboard support (e.g. an Xwayland window).
* feat(git): add resign aliasLibravatar sommerfeld2026-05-141-0/+1
| | | | | | | Rebases onto @{u} re-signing each commit with the current author identity and key, while stripping any Co-authored-by lines. Hooks are disabled (core.hooksPath=/dev/null) so chezmoi's post-commit hook doesn't fire once per replayed commit.
* feat(teams): start units minimized to trayLibravatar sommerfeld2026-05-142-2/+4
| | | | | | teams-for-linux --minimized=true makes the app honor systemd autostart without popping a window on every login (parity with Signal's --start-in-tray).
* feat: teams autostart, llama-cpp-vulkan ignore, snxctl-chromium wrapperLibravatar sommerfeld2026-05-143-0/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | systemd/user/teams-{sii,xsight}.service: autostart both Teams flatpak profiles on sway-session.target login. KillMode=mixed so SIGTERM hits only the wrapper process — both instances share the same flatpak app id, so killing by app id would take down the sibling instance. A 15s SIGKILL fallback covers the case where Electron tray-hides instead of quitting. Both units listed in systemd-units/user.txt. etc/pacman.conf: IgnorePkg = llama-cpp-vulkan. The AUR package rebuilds on every llama.cpp commit (multi-hour build). Update manually with `paru -S llama-cpp-vulkan` when intended. snxctl-chromium wrapper: - dot_local/share/snx-rs/bin/xdg-open: shim that flatpak-runs ungoogled-chromium, used only by snx-rs. - dot_config/systemd/user/snx-rs.service.d/10-chromium-saml.conf: drop-in prepending that dir to the daemon's PATH so snx-rs's opener-crate call to xdg-open lands in chromium, without affecting xdg-open for any other process. - dot_local/bin/snxctl-chromium: convenience wrapper that daemon-reloads and restarts snx-rs.service if the drop-in isn't yet applied, then execs `snxctl connect`. firefox/user-overrides.js: revert the dom.security.https_only_mode. upgrade_local and network.lna.local-network-to-localhost.skip-checks prefs — they didn't actually fix the SAML flow. Replaced with a comment pointing to the wrapper instead.
* style: apply shfmt/prettier/just fmt driftLibravatar sommerfeld2026-05-146-43/+57
| | | | | | Pure formatter output from shfmt (2-space indent, '|' line breaks), prettier (KEYBINDS.md), and 'just fmt' (justfile blank line). No behavior change.
* feat(remote-dev): add zoxide/clang-tools/node/uv/AI agents; bring git+ssh; ↵Libravatar sommerfeld2026-05-142-3/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | SSH-format signing home.nix: - Add zoxide (fixes 'command not found' on shell start), clang-tools (no compiler driver), nodejs (Mason npm LSPs), uv (Mason python LSPs; does not install python3 in PATH, so Ubuntu's /usr/bin/python3 stays the system default), claude-code, github-copilot-cli. - Refine the leaf-tools policy comment: explicit denylist of build- toolchain binaries that would shadow Ubuntu's via PATH, plus a carve-out for editor/AI runtimes (node, uv, clang-tools). - Symlink ~/.config/git/{config,attributes,ignore} and ~/.ssh/config from the dotfiles tree. dot_config/zsh/dot_zshrc: guard direnv/zoxide/fzf inits with 'command -v X >/dev/null &&' so a fresh machine without one of them no longer prints a stderr error on every shell start. dot_config/git/config: append unconditional '[include] path = ~/.config/git/config.local' for machine-local overrides (used on the remote-dev VM to switch to SSH-format signing via the forwarded agent). Git silently skips missing include files. remote-dev/README.md: document the update flow (config-only vs HM rebuild), the single-shell leaf-tools policy, and the one-time VM setup for SSH-format commit signing (allowed_signers + config.local, ForwardAgent yes on the host).
* refactor(notifications): drop dismissed-state machinery; pending = visibleLibravatar sommerfeld2026-05-137-189/+29
| | | | | | | | | | | | | | | | | Set mako default-timeout=0 so notifications stay until acted upon. With auto-timeout off, mako's list IS the pending set, so the $XDG_RUNTIME_DIR/mako-dismissed bridge becomes dead weight. - mako/config: default-timeout=0; drop redundant [urgency=critical] default-timeout=0 override. - Delete dismiss-visible.sh and restore-pending.sh; sway calls makoctl directly (Mod+n=dismiss, Mod+Shift+n=dismiss --all, Mod+Ctrl+n=restore as undo). - Shrink mako-status.sh to a 20-line counter of makoctl list. - Rename mako-history.py -> notification-picker.py; lists only visible, dismisses via makoctl dismiss -n <id>. - Update waybar config.jsonc on-click path. - Update KEYBINDS.md wording (no more 'marks seen' / 'pending set').
* feat(remote-dev): add Nix Home-Manager flake for Ubuntu 22 VM dev envLibravatar sommerfeld2026-05-131-4/+27
| | | | | | | | | | | | | | | | | | | | | New remote-dev/ subdir with a Home-Manager flake that provisions a headless dev environment on a remote Ubuntu 22.04 VM accessed via SSH. Shares nvim, zellij, zsh, direnv, and ghostty configs from the same dotfiles repo via mkOutOfStoreSymlink (no rebuilds on config edits). CLI tool set mirrors the dev-tool subset of meta/base.txt; sysadmin tools (procs, gdu, duf), lazygit, and node/yarn (only needed for markdown-preview on GUI hosts) are excluded. bootstrap.sh is one-shot: installs Nix via Determinate Systems installer, clones the repo to ~/.local/share/dotfiles, runs home-manager switch, and chshes to the nix-store zsh. dot_config/zsh/dot_zshrc loses its hardcoded Arch plugin/git-prompt paths in favour of a fallback search: Arch path first, then $HOME/.nix-profile/share/. Same file works on host and VM. .chezmoiignore: exclude remote-dev/ from chezmoi deploy on the host.
* feat(ghostty): enable ssh-env and ssh-terminfo shell integrationLibravatar sommerfeld2026-05-131-1/+1
| | | | | | | | | | | | | | | Remote hosts without xterm-ghostty terminfo print 'xterm-ghostty: unknown terminal type' on connect. Ghostty's shell integration ships two features for this: - ssh-terminfo: pipes `infocmp -x xterm-ghostty` to the remote and installs it under ~/.terminfo on first connect, permanently fixing TERM recognition on hosts where you have a writable home. - ssh-env: falls back to TERM=xterm-256color (plus COLORTERM=truecolor and TERM_PROGRAM=ghostty) for the ssh subprocess, so hosts where terminfo install fails or home is read-only still get sane defaults. Both required shell-integration to be on, which it already is (zsh).
* feat(sway): enable swayr auto-tile via systemd user unitLibravatar sommerfeld2026-05-132-0/+24
| | | | | | | | | | | | | | | | | | | Vanilla sway only has splith/splitv with no auto-orientation, so new windows always split along whatever axis the parent container is set to (default splith). The result: opening a third window in a workspace that's already split horizontally just keeps stacking horizontally, even when each pane is now narrower than it is tall. swayr's daemon (swayrd) subscribes to sway IPC and, with [layout].auto_tile = true, issues splith or splitv on the focused container based on its width-vs-height before sway places the next window. The result is the i3/awesome-style spiral tiling: each new window splits the focused pane along its longest side. Run swayrd as a systemd user service bound to sway-session.target so it starts/stops with the session (matching the pattern used by waybar, swayidle, mako, etc.). No keybind changes; only the placement algorithm.
* fix(sway): launch librewolf via flatpakLibravatar sommerfeld2026-05-131-1/+1
| | | | | | | librewolf was migrated from a native package to the flatpak io.gitlab.librewolf-community in commit f5796c7; the $mod+Shift+b binding still called the native binary, so the keybind silently did nothing. Use 'flatpak run' instead.
* feat(sway): refuse keyboard-shortcut inhibit from virt-viewer/managerLibravatar sommerfeld2026-05-131-0/+6
| | | | | | | | | Spice/virt-viewer ask sway for keyboard-shortcuts-inhibit so they can forward the Super key to the guest. That swallows all $mod+... binds on the host while the VM window is focused. Refuse the inhibit for those three app_ids; sway forwards Super to the guest only when the keyboard is explicitly grabbed (click-into-VM + virt-viewer's own Ctrl+Alt toggle), not via the wm-bind shortcut.