| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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`.
|
| |
|
|
|
|
|
|
|
|
| |
`dot_config/git/hooks/executable_pre-push` only loses the
`executable_` chezmoi attribute prefix during `chezmoi apply`. On
remote-dev we use raw home-manager symlinks, so a directory symlink
gave git a file literally named `executable_pre-push` — which is not
a valid hook name and was silently ignored. Symlink each hook to its
stripped target name (executable bit comes from the working-tree mode,
which git follows through the symlink).
|
| |
|
|
|
|
|
|
|
|
|
|
| |
home.sessionVariables get written to hm-session-vars.sh, which HM only
auto-sources when programs.bash/zsh.enable = true (it injects a snippet
into the rc file) or via ~/.profile (which zsh login shells don't
read). We use a ZDOTDIR redirect and no HM-managed shells, so
PODMAN_IGNORE_CGROUPSV1_WARNING (and any future session var) was never
reaching the shell.
Source it explicitly from the generated ~/.zshenv before redirecting
to ZDOTDIR.
|
| |
|
|
|
|
|
|
| |
Ubuntu 20.04 still defaults to cgroups v1; podman 5 emits a deprecation
warning on every single invocation. Flipping the host to v2 is a reboot
that affects every workload and only matters if we need rootless
--memory/--cpus, so just silence the warning via the documented
PODMAN_IGNORE_CGROUPSV1_WARNING env var on the home-manager side.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`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.
|
| |
|
|
|
|
| |
The AUR package is named with a dot, not a dash: `llama.cpp-vulkan`.
The IgnorePkg entry used the wrong spelling, so it never matched and
the package was upgraded on every -Syu.
|
| |
|
|
| |
This reverts commit 1d7feb8d405e135dc6109052948b8b9240cf882a.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.)
|
| |
|
|
| |
This reverts commit eb0f9d71ed9527b5de5c82c9acce7c04bbec71e7.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Pacman's IgnorePkg only applies to -Sy{u} upgrade operations; explicit
`paru -S <pkg>` bypasses it entirely. `pkg-apply` and `pkg-fix` both
pipe the meta/*.txt package lists into `paru -S --needed`, so every
sync was reinstalling AUR pins (most painfully llama-cpp-vulkan, a
1-2h rebuild on every llama.cpp commit) whenever the AUR had a newer
version, defeating the whole point of pinning.
Parse IgnorePkg out of /etc/pacman.conf and strip those names from the
list before piping to paru. `pkg-add` is intentionally left
unfiltered: explicitly naming a package on the CLI is a deliberate
opt-in that should still work for pinned entries.
`pkg-update` (which is plain `paru -Syu`) already honors IgnorePkg
via pacman itself — no change needed there.
|
| |
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
| |
Affects the whole host and requires a reboot — only worth doing if you
need rootless --memory/--cpus limits. Rootless podman otherwise runs
fine on cgroups v1.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Adds podman + helpers (crun, conmon, netavark, aardvark-dns,
slirp4netns, passt) to the home-manager profile, plus rootless-sane
registries.conf, storage.conf (overlay driver, kernel-native — VM
kernel 5.15 supports rootless overlay since 5.13, no fuse-overlayfs
needed), and policy.json.
Documents host-side prerequisites in remote-dev/README.md: install
uidmap, ensure subuid/subgid entries for the user, and enable cgroups
v2 (systemd.unified_cgroup_hierarchy=1) so rootless resource limits
work on Ubuntu 20.04.
|
| |
|
|
|
| |
git config defines a mergiraf merge driver; install it on the VM so
.gitattributes references actually resolve.
|
| |
|
|
|
|
|
|
|
| |
mkOutOfStoreSymlink exposes the working-tree file's perms. Under
Ubuntu's default umask 002, git checks out private_dot_ssh/config
as 0664; OpenSSH refuses any group-writable ssh_config.
Replace the home.file symlink with a home-manager activation step
that copies the file to a real ~/.ssh/config with 0600.
|
| |
|
|
|
|
|
|
|
|
| |
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).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The deadsnakes PPA may not be reachable on every VM (corporate apt
proxy, Ubuntu derivatives that add-apt-repository misdetects, etc.).
`uv python install 3.11` works on any distro: it fetches a portable
python-build-standalone CPython into ~/.local/share/uv/python/, which
is manylinux-wheel-compatible.
Symlink the resulting binary to ~/.local/bin/python3.11 (already on
PATH from zprofile). Move the step to after `home-manager switch`
since uv comes from the nix profile.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Nix's python rejects manylinux wheels by design (its libc is patched),
which forced pip in Mason's per-pkg venvs to compile nodejs-wheel-binaries
(pulled in by basedpyright) from source. That source build then failed on
Ubuntu 20.04's gcc 9.4 — Node 24 requires C++20 (g++ >= 12.2.0).
Replace the nix python311-versioned-only derivation with an Ubuntu-native
python3.11 from the deadsnakes PPA. It satisfies Mason's >=3.10 version
requirement, accepts manylinux wheels, and the versioned binary name
leaves /usr/bin/python3 untouched (leaf-tools policy preserved).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Ubuntu 20.04's stock python3 is 3.8.10, which fails Mason's pep440
checks for autotools-language-server, codespell, mdformat,
nginx-language-server, systemdlint, yamllint (all want >=3.9 or
>=3.10).
Mason's pypi installer (verified against upstream
lua/mason-core/installer/managers/pypi.lua) probes python3.6 through
python3.14 in PATH in addition to plain python3, so providing
python3.11 alone (without python3) is enough.
Add a thin runCommand derivation that symlinks ONLY
pkgs.python311/bin/python3.11 into the profile — not python3 or
python — so we don't shadow Ubuntu's /usr/bin/python3 and keep the
leaf-tools policy intact.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Wraps the bootstrap-day-2 incantations so you don't have to remember
`home-manager switch --impure --flake '.#vm' -b backup` and its zsh
quoting gotcha. Recipes:
- `just update` — pull + switch (the everyday one)
- `just pull` — config-only changes, no nix rebuild
- `just switch` — rebuild HM from the current checkout
- `just gc` — expire HM generations >7d and gc the nix store
README updated to use these.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
| |
The flake set `allowUnfree = false` so `home-manager switch` failed
with "Refusing to evaluate package 'claude-code-...' because it has
an unfree license". Switch to `allowUnfreePredicate` with an explicit
name allowlist — keeps the door closed for everything else while
permitting just the two AI agents we actually want.
|
| |
|
|
|
|
| |
`home-manager switch --flake .#vm` fails under our zsh (which sets
`extendedglob`) because `#` then becomes a glob qualifier and `.#vm`
parses as an unmatched pattern. Quoting the ref sidesteps it.
|
| |
|
|
|
| |
So the dotfiles `justfile` (and any in-tree project justfiles the user
checks out on the VM) work without falling back to make/scripts.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
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).
|
| |
|
|
|
| |
Drop --hide-search and enable --matching=fuzzy --insensitive so typing
'po' jumps to Poweroff, 'su' to Suspend, etc.
|
| |
|
|
|
|
|
| |
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).
|
| |
|
|
|
| |
Enables `pass otp insert/show` for TOTP secrets, used as the source
for the ungoogled-chromium VPN OTP autofill keybind.
|
| | |
|
| |
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
| |
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).
|