aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/justfile
Commit message (Collapse)AuthorAgeFilesLines
* fix(just): chsh to nix-managed zsh after nix-switchLibravatar sommerfeld10 days1-0/+14
| | | | | | | | | | | | | | zsh now lives in nix/common.nix instead of meta/base.txt. Removing the pacman zsh package leaves /etc/passwd dangling at /usr/bin/zsh, so new login terminals die with 'shell not found'. Mirror the chsh logic from nix/bootstrap.sh (which only runs on the VM during first-time provisioning) into the nix-switch recipe so every `just sync` / `just init` re-asserts the login shell — and the host gets the same treatment as the VM. Idempotent: skips when the shell already matches, skips when ~/.nix-profile/bin/zsh is missing (pre-bootstrap state).
* refactor(pkg): drop provider-resolution fallback in mark_explicitLibravatar sommerfeld10 days1-9/+4
| | | | | | | | | Now that meta/*.txt is conventionally required to list installed package names (not virtual providers — see preceding commit dropping ttf-font-awesome in favour of the already-declared otf-font-awesome), the intersection with pacman -Qq is unnecessary. Failing loudly on a virtual-provider entry is actually useful: it surfaces a data-entry mistake instead of silently masking it.
* fix(pkg): skip mark-explicit for packages resolved to a different providerLibravatar sommerfeld10 days1-1/+9
| | | | | | | | | | paru may resolve a declared name to a provider with a different package name (e.g. ttf-font-awesome -> otf-font-awesome). Calling `pacman -D --asexplicit` on the declared name then fails with 'could not find or read package' and aborts the recipe. Intersect the declared list with `pacman -Qq` before bumping reasons; names not present in the local DB are silently skipped.
* fix(pkg): mark declared packages as explicit on applyLibravatar sommerfeld10 days1-2/+16
| | | | | | | | | | | | | | | `paru -S --needed` skips packages already on disk, so anything pulled in transitively first and *later* added to meta/*.txt stays marked as 'installed as a dependency' in the local pacman DB — and keeps showing up under `pacopt`. After each install pass, force the declared set to 'explicitly installed' via `pacman -D --asexplicit`. This treats meta/*.txt as the source of truth for install reason: anything listed there is explicit, anything else is a transitive dep. Idempotent on already-explicit packages (pacman just prints 'install reason is already explicit', which we discard).
* style(justfile): apply just --fmt (blank line between nix-update doc comments)Libravatar sommerfeld11 days1-0/+1
| | | | | | Just's formatter inserts a blank line so only the immediately-adjacent comment serves as the recipe's doc string. Pre-existing drift, surfaced when CI added 'just check-fmt' to the pipeline.
* justfile: add nix-update recipe, wire into updateLibravatar sommerfeld11 days1-2/+15
| | | | | | Refreshes flake.lock (nixpkgs + home-manager) and re-activates the profile. Plugged into the existing 'just update' aggregate so a weekly 'just update' bumps pacman/AUR + flatpak + nix in one go.
* drop residual Mason references after p6 migrationLibravatar sommerfeld11 days1-2/+2
| | | | | - zsh: remove ~/.local/share/nvim/mason/bin from PATH - justfile: update comments to reflect Mason removal
* fix(nix,nvim): drop gh-actions-language-server (not in nixpkgs); export USER ↵Libravatar sommerfeld11 days1-0/+4
| | | | | | | | | | | | | | 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.
* feat(bootstrap): install nix + Home-Manager on Arch host (p8)Libravatar sommerfeld11 days1-4/+23
| | | | | | | | | | | | | | | | | Append two steps to the root bootstrap.sh: 5a. install nix via the Determinate Systems multi-user installer (same as remote-dev/nix; gives us a proper nix-daemon.service). 5b. chsh to ~/.nix-profile/bin/zsh after appending to /etc/shells. Add a 'just nix-switch' recipe that auto-picks the host vs vm profile based on /etc/os-release ID, and wire it into 'just init' and 'just sync' so day-to-day reconciliation also re-applies Home-Manager. The recipe is a no-op when nix isn't installed, so it stays safe for pre-bootstrap states and for hosts where the user opts out. Phase 8 of the nix-on-host migration plan.
* feat(git): user-level hooks auto-dispatch into <repo>/.githooks/Libravatar sommerfeld12 days1-1/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* Revert "fix(just): honor IgnorePkg in pkg-apply / pkg-fix"Libravatar sommerfeld12 days1-14/+3
| | | | This reverts commit eb0f9d71ed9527b5de5c82c9acce7c04bbec71e7.
* fix(just): honor IgnorePkg in pkg-apply / pkg-fixLibravatar sommerfeld12 days1-3/+14
| | | | | | | | | | | | | | | | | 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.
* style: apply shfmt/prettier/just fmt driftLibravatar sommerfeld2026-05-141-0/+1
| | | | | | Pure formatter output from shfmt (2-space indent, '|' line breaks), prettier (KEYBINDS.md), and 'just fmt' (justfile blank line). No behavior change.
* fix(lostfiles): emit parent directories alongside tracked filesLibravatar sommerfeld2026-05-131-1/+1
| | | | | | | | | | | lostfiles flags directories whose parent is pacman-owned but the dir itself is not (drop-in dirs like /etc/systemd/{logind,system,user}.conf.d, /etc/systemd/system/getty@.service.d, /etc/pacman.d/hooks). Previous template only emitted tracked files, missing these. Walk each tracked path emitting every ancestor up to /etc, then sort -u. Over-emission of pacman-owned parents (e.g. /etc, /etc/systemd) is harmless: grep -vFx simply finds no match for those lines.
* feat(secrets): add pass-secret-service for libsecret bridgeLibravatar sommerfeld2026-05-131-1/+1
| | | | | | | | | Signal Desktop (and any libsecret consumer) wants to talk to the org.freedesktop.secrets D-Bus service. pass-secret-service implements that API on top of the existing pass store -- secrets land under ~/.password-store/secret-service/ encrypted with the same GPG key, so no separate keyring to manage. The service is D-Bus activated, no systemd unit needed.
* fix(nvim-update): cd $HOME so auto-session's suppressed_dirs kicks inLibravatar sommerfeld2026-05-131-2/+4
| | | | | | | | The 'nvim-update' just recipe runs an admin chore, not a project edit; loading and saving a session for it is wrong. session.lua already treats $HOME and / as suppressed_dirs, so a leading 'cd &&' (which defaults to $HOME) gives us the right behaviour without touching nvim config or adding a special-case flag.
* feat(waybar,nvim): update-staleness reminder; nvim update visibleLibravatar sommerfeld2026-05-131-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* chore(python): add basedpyright type-checkingLibravatar sommerfeld2026-05-131-2/+4
| | | | ruff (format + check) was already wired into fmt/check-fmt/lint. Add basedpyright as the type-checker for python so 'just lint' covers correctness too. Pyright config sets standard mode (lenient enough to not flood on stdlib edges) and excludes ipython_config.py whose 'c' is injected by IPython at config load time.
* refactor(meta): flatten groups; only break out optional/hw-specificLibravatar sommerfeld2026-05-131-91/+84
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Drop the per-domain group fragmentation in meta/ and the parallel group-per-file structure in systemd-units/. meta/ (18 -> 6 groups): keep base, flatpak (magic), intel, nvidia, work, btc fold browser, bt, cpp, dev, extra, fonts, mail, media, nix, sound, wayland -> base (with `# --- section ---` comments preserving at-a-glance structure) drop fortran (niche; install ad-hoc when needed) systemd-units/: flatten to a single system.txt + user.txt; .ignore files move up one level; group concept and pairing rule removed. justfile: unit-list/unit-apply/unit-status no longer take a group argument. unit-add/unit-forget infer scope by probing `systemctl [--user] cat <unit>` (system wins on tie). Top-level add/forget dispatcher updated: any unit-suffixed arg routes to unit-* without requiring a leading GROUP. docs: .github/copilot-instructions.md and README.md updated to describe the new flat layout. Pairing rule and group-token grammar gone. Pure layout refactor - no package contents change.
* feat(privesc): migrate from opendoas to sudo-rsLibravatar sommerfeld2026-05-131-17/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | 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(flatpak): support .flatpak bundle URLs; migrate autenticacao-gov-ptLibravatar sommerfeld2026-05-131-34/+83
| | | | | | | | | | | | | | | | | | | | | | | | Extend meta/flatpak.txt format to allow per-line URL for non-Flathub .flatpak bundles. Lines are now either '<id>' (Flathub) or '<id> <url>' (downloaded + installed via 'flatpak install <file>'). Bundle entries are skipped on pkg-apply/pkg-fix when already installed, and re-fetched on flatpak-update only when the version embedded in the URL differs from the installed version. Use this to migrate Portuguese Citizen Card (pteid-mw) off the AUR 'autenticacao-gov-pt-bin' pseudo-flatpak unpack to the upstream-shipped flatpak bundle from amagovpt/autenticacao.gov GitHub releases — same codebase the AUR PKGBUILD already vendors, but properly sandboxed. Refactors duplicated install logic in pkg-apply/pkg-fix into a private _flatpak-install helper. ID-only contexts (pkg-status, undeclared, pkg-list) now extract the first whitespace-separated token instead of treating each line as a single ID. Caveat: PKCS#11-based Citizen Card web auth in the LibreWolf flatpak remains unsolved — the .so lives inside the autenticacao-gov sandbox and would need a 'flatpak override' + 'modutil' bridge to be loaded across sandboxes. The CLI/GUI eID app works as expected.
* refactor(packages): drop gaming, manage select GUI apps via flatpak groupLibravatar sommerfeld2026-05-131-13/+81
| | | | | | | | | | | | | | | - Delete meta/gaming.txt entirely (no longer used; takes discord with it) - Delete now-empty meta/office.txt; LibreOffice and Okular move to flatpak - Trim meta/browser.txt: chromium and torbrowser-launcher now flatpaks - New meta/flatpak.txt: 4 Flathub app IDs (chromium, okular, libreoffice, torbrowser-launcher), under --user scope - Add flatpak runtime to meta/extra.txt - Teach pkg-apply / pkg-list / pkg-fix / pkg-add / pkg-status / undeclared to branch on the magic 'flatpak' group name (no parallel recipe namespace) - New flatpak-update recipe; update aggregate now refreshes flatpaks too - _active-packages now skips flatpak.txt (it remains pacman-only) - pkg-apply (no args) installs pacman groups together, then flatpaks - First flatpak install auto-adds the flathub --user remote
* refactor(etc): narrow etc-status to tracked-file driftLibravatar sommerfeld2026-05-131-31/+17
| | | | | | | | | | | | | | | | The old etc-status scanned all of /etc (pacman -Qkk for modified backup configs, then 'find /etc | xargs pacman -Qo' for unowned files), producing a discovery report of things we might want to track. That was useful when seeding the repo but is slow and misaligned with dotfiles-status, which only reports drift on files chezmoi already manages. Rewrite etc-status to mirror that model: iterate etc/, render .tmpl sources, and cmp against the live /etc file. Report 'modified' or 'missing' per tracked path. Runs in under a second and matches the semantics of 'just status'. Drop the now-unused etc/.ignore and update README.
* refactor(units): split systemd-units into system/ and user/ treesLibravatar sommerfeld2026-05-131-53/+105
| | | | | | | | | | | | | | | Move the three existing files into systemd-units/system/ and seed systemd-units/user/ with a .ignore stub. Teach the unit-* recipes a user:/system: group-token prefix (bare names keep system semantics for back-compat). unit-apply and unit-status now walk both scopes; user units go through 'systemctl --user' (no sudo), system units via 'sudo systemctl' as before. Soft-fail per unit preserved for both scopes. Top-level add/forget dispatchers need no changes: the unit-extension sniff already routes anything ending in .service/.timer/etc to unit-*, and user:base passes through as the group token. Docs updated in README.md and .github/copilot-instructions.md.
* feat(etc): template kernel cmdline, derive LUKS UUID from partition nameLibravatar sommerfeld2026-05-131-5/+27
| | | | | | | | | | | | | | | | | Prompt once at 'chezmoi init' time for the LUKS root partition (e.g. nvme0n1p2) and store it under [data].luksRootPartition in the per-machine chezmoi config. etc/kernel/cmdline.tmpl resolves the UUID at apply time via lsblk, so reinstalls only require re-entering the partition name. The etc deploy script now renders *.tmpl sources through 'chezmoi execute-template' and installs them without the suffix. The resolved UUID is folded into the onchange hash so the script re-runs when the UUID changes even if etc/ content is unchanged. just etc-status/diff transparently handle .tmpl sources (strip suffix for the live-path mapping, render before diffing). etc-re-add skips .tmpl files since template sources can't be reverse-rendered from the live file.
* fix(just): unit-status handles template instances and static unitsLibravatar sommerfeld2026-05-131-1/+11
| | | | | | | | - use systemctl is-enabled per curated unit (list-unit-files does not show instantiated template units like btrfs-scrub@-.timer) - accept static/indirect/generated/alias states in addition to enabled - drop pkgstats.timer from curated (no [Install] section) - ignore systemd-oomd.socket (distro default)
* feat(just): add 'update' recipe — system + nvim plugins + masonLibravatar sommerfeld2026-05-131-0/+15
| | | | | | | | | | | | | | | New recipes (new 'Updates' section after 'Day-to-day'): - update: pkg-update nvim-update - pkg-update: paru -Syu - nvim-update: nvim --headless +'lua require("config.update").run()' New dot_config/nvim/lua/config/update.lua drives the headless session: clean orphan plugins, vim.pack.update with force=true (skips the confirm buffer since this is unattended; changes still go to nvim-pack.log), then :MasonToolsUpdateSync — the blocking variant intended for headless Interactive :PackSync stays unchanged (confirm buffer remains visible for reviewed updates).
* fix(justfile): strip inline '# ...' comments in meta/ and systemd-units/ parsingLibravatar sommerfeld2026-04-211-10/+10
| | | | | | | | | | The grep-based filter only dropped lines starting with '#' and blank lines, so 'xorg-xwayland # note' got passed to paru verbatim and failed with 'could not find all required packages'. Replace all 11 call sites with a single sed that strips trailing '# ...' comments AND blank lines, so both full-line and inline comments are supported consistently across pkg-apply, pkg-add, pkg-forget, pkg-status, pkg-list, and unit-apply / unit-list / unit-status.
* refactor(justfile): streamline recipes to DOMAIN-VERB scheme with shape ↵Libravatar sommerfeld2026-04-211-120/+338
| | | | | | | | | | | | | | | | | | | | | dispatchers Adopt chezmoi-aligned vocabulary (add, forget, re-add, apply, diff, merge, status) uniformly across four domains (dotfiles, etc, pkg, unit). Add top-level dispatchers that sniff argument shape and delegate: - contains '/': path -> etc-* (^/?etc) or dotfiles-* - ends with .service/.timer/.socket/.mount/.target/.path: unit-* - bare words: pkg-* Fill in missing recipes: dotfiles-add/forget/re-add/diff/merge/status, etc-merge, etc-forget (was etc-rm), unit-add/forget. Rename: services-* -> unit-*, *-drift -> *-status, install/install-all -> pkg-apply, fix -> pkg-fix, groups -> pkg-list, readd -> re-add, add/remove -> pkg-add/forget, etc -> etc-status, etc-readd -> etc-re-add. Top-level apply stays monolithic (chezmoi apply deploys dotfiles + /etc atomically via the onchange template). sync = apply + pkg-fix + unit-apply.
* refactor(justfile): extract fmt/lint helpers into just-lib.sh; add doctor recipeLibravatar sommerfeld2026-04-211-90/+20
|
* feat(justfile): add check-fmt and check recipes; pre-commit hookLibravatar sommerfeld2026-04-211-9/+93
| | | | | | | | | | Split concerns: fmt-check (check-fmt) from lint. check-fmt mirrors fmt with each tool's --check/-d flag. check runs both as a single quality gate. A new .githooks/pre-commit runs 'just check' on every commit; bypass with git commit --no-verify. Also drop just --fmt --check and prettier --check from the lint recipe (they're format checks, belong in check-fmt).
* feat(justfile): add fmt and lint recipesLibravatar sommerfeld2026-04-211-0/+179
| | | | | | | | | | | | | | | | | | | | | | Two recipes with matching shape: just fmt # format the whole repo just fmt <path> # format one file (dispatch by ext/filename/shebang) just lint # lint the whole repo just lint <path> # lint one file Dispatch: .lua stylua / selene *.sh + sh shebang shfmt / shellcheck .zshrc/.zprofile (no fmt) / shellcheck --shell=bash (best-effort) .py ruff format / ruff check justfile just --fmt / just --fmt --check .toml taplo format / taplo lint .md/.json/.jsonc/.yaml/.yml/.css prettier --write / --check If a required tool is missing, the recipe aborts with an install hint naming the package. Whole-repo mode aggregates non-zero exits in lint so you see every issue in one pass.
* fix(etc-restore): preserve mtime so pacman -Qkk sees file as unmodifiedLibravatar sommerfeld2026-04-211-1/+3
| | | | | | | | | | 'bsdtar -xOf | doas tee' wrote pristine content but with mtime=now, which caused 'pacman -Qkk' (and therefore 'just etc') to still flag the file as drifted — pacman compares stored metadata, not content. Switch to 'doas bsdtar -xpf <archive> -C / <file>', which extracts the single file in place with its original owner, mode, and mtime from the package archive.
* feat(etc-restore): reset live /etc/<path> to pristine without repo round-tripLibravatar sommerfeld2026-04-211-0/+35
| | | | | | | | | | Sibling to etc-reset but operates directly on /etc (via doas tee) and never touches the repo. Use when a live file has drifted from pristine but you don't want to track it: just etc-restore /etc/systemd/resolved.conf Previously this required a 2-step dance (etc-add + etc-untrack).
* chore(justfile): include services-drift in statusLibravatar sommerfeld2026-04-211-2/+2
|
* feat(etc,readd): rename etc-drift to etc; add etc-readd + readdLibravatar sommerfeld2026-04-211-3/+53
| | | | | | | | | | | - etc-drift → etc (the main entry point to the /etc subsystem). - New etc-readd: pull changes from live /etc back into tracked repo files (the /etc analog of 'chezmoi re-add'). No args refreshes all tracked files; explicit paths error if the file isn't already tracked (use etc-add to adopt). Skips unchanged files silently; runs 'just apply' only when something changed. - New top-level readd: 'chezmoi re-add' + 'just etc-readd'. One command to mirror live state back into the repo.
* feat(etc): auto-apply in etc-reset/etc-rm + add etc-untrackLibravatar sommerfeld2026-04-211-5/+8
| | | | | | | | | | - etc-reset and etc-rm now chain 'just apply' at the end, so a single invocation leaves both repo and /etc consistent. - New etc-untrack recipe = etc-reset + etc-rm. One command to cleanly stop tracking an owned /etc file: before: just etc-reset X && just apply && just etc-rm X && just apply after : just etc-untrack X (etc-untrack doesn't apply to unowned files — use etc-rm.)
* feat(justfile): add etc-rm recipeLibravatar sommerfeld2026-04-211-0/+23
| | | | | | | | | | | Removes one or more files from the repo's etc/ tree and tidies any now-empty parent directories (bounded to inside etc/). Leaves the live /etc copy untouched. Composes with etc-reset to stop tracking a file cleanly: just etc-reset /etc/foo.conf # repo → pristine just apply # deploy pristine to /etc just etc-rm etc/foo.conf # stop tracking; /etc unchanged
* refactor(etc-reset): write pristine into repo, not /etcLibravatar sommerfeld2026-04-211-39/+27
| | | | | | | | | | | Operating on /etc directly created a two-source-of-truth problem: chezmoi apply would just redeploy the repo copy anyway, so we had to either refuse managed paths or bolt on a --force flag. New semantics: etc-reset overwrites etc/<path> in the repo with the pristine package contents (no doas needed, no /etc touched). User then runs 'just apply' to deploy. Unowned files are now an error (nothing to reset to) — remove them from the repo manually.
* perf(etc-diff,etc-upstream-diff): default to repo files, avoid doas when ↵Libravatar sommerfeld2026-04-211-17/+25
| | | | | | | | | | | readable - etc-upstream-diff: default to iterating over repo-managed etc/ files instead of running full 'pacman -Qkk' (scans every installed package). Upstream drift only matters for files I actually track. - both recipes: read live /etc via plain cat when the file is world-readable; only fall back to 'doas cat' for restricted files (e.g. /etc/doas.conf 0600). Cuts doas round-trips for the common case.
* refactor(just): reorder status to dotfile-drift, pkg-drift, etc-driftLibravatar sommerfeld2026-04-211-1/+1
| | | | | dotfile-drift is fastest so it gives immediate feedback; etc-drift is slowest (full pacman -Qkk pass) so it runs last.
* feat(just): include etc in status & diff recipesLibravatar sommerfeld2026-04-211-4/+15
| | | | | | | - status now runs etc-drift alongside pkg-drift and dotfile-drift - diff routes /etc/* paths to etc-diff; with no arg, runs both chezmoi diff and etc-diff so drift in /etc is visible alongside $HOME dotfiles.
* fix(etc-diff,etc-upstream-diff): use doas cat for root-only live filesLibravatar sommerfeld2026-04-211-4/+5
| | | | | | | /etc/doas.conf (0600) and similar mode-restricted files triggered 'Permission denied' when diff tried to read them as the user. Read via 'doas cat' on the live side; keep the repo/pristine side as the user since those are readable.
* feat(etc): diff/upstream-diff/add/reset recipes + ignore fstabLibravatar sommerfeld2026-04-211-7/+149
| | | | | | | | | | | | | - etc-diff: diff repo-managed etc/<path> vs live /etc (defaults to all) - etc-upstream-diff: diff live /etc vs pristine pacman archive (defaults to pacman -Qkk modified set) - etc-add: copy /etc/<path> into the repo's etc/ tree - etc-reset: restore pristine via bsdtar -xpf, or rm if unowned; refuses managed paths without --force - ignore /etc/fstab (host-specific UUIDs/layout) - path-traversal guards on all recipe inputs - regular-file-only enforcement (no symlinks/dirs) - fail-fast with clear message if mirror can't supply installed version
* fix(etc-drift): match real pacman -Qkk "backup file:" prefix formatLibravatar sommerfeld2026-04-211-1/+1
| | | | | | | | | Pacman emits lines like "backup file: <pkg>: <path> (<reason>)", not the "(Modified backup file)" suffix format. Anchor the path extraction to /etc/ to avoid catching stderr warnings interleaved into a line. Also extend etc/.ignore with /etc/{passwd,group,shells} — system-managed identity files that surfaced in the new drift output.
* fix(etc-drift): use pacman -Qkk for reliable modified-file detectionLibravatar sommerfeld2026-04-211-1/+1
| | | | | | | The old -Qii regex "MODIFIED\s+/\S+" accidentally matched UNMODIFIED lines (no word boundary), which hid truly-modified configs like pacman.conf from the drift report. Switch to -Qkk which uses an explicit "Modified backup file" / "Altered backup file" tag that is unambiguous.
* fix(etc-drift): while loop must not exit with keep filter statusLibravatar sommerfeld2026-04-211-2/+2
|
* fix(etc-drift): tolerate no-match grep and whitespace-separated MODIFIEDLibravatar sommerfeld2026-04-211-3/+3
| | | | | | | - grep exits 1 when pattern has no matches; under pipefail that killed the recipe. Wrap both pipelines in `{ ...; } || true`. - pacman -Qii can separate MODIFIED from the path with spaces or a tab depending on formatting; use \s+ instead of \t.
* feat(etc): drift detection + auto-enumerating deploy templateLibravatar sommerfeld2026-04-211-0/+42
| | | | | | | | | | | - `just etc-drift` reports /etc files modified from pacman defaults (via pacman -Qii) and user-created files (via pacman -Qo), subtracting already-managed paths and patterns listed in etc/.ignore. - Refactor run_onchange_after_deploy-etc.sh.tmpl to enumerate files under etc/ automatically via find; single combined hash via chezmoi output + sha256sum, so new files only need to be dropped into etc/. - etc/.ignore seeds noise filters: machine-id, ssh host keys, pacman keyring, mirrorlist, shadow/passwd backups, sbctl keys, ca-certs.
* feat(services): add .ignore list for distro-default noiseLibravatar sommerfeld2026-04-211-1/+6
| | | | | | | | | | systemd-units/.ignore is a user-maintainable list of units to suppress from 'just services-drift' uncurated output. Starts with three systemd presets that are harmless noise: remote-fs.target, systemd-network-generator.service, systemd-userdbd.socket. The dotfile is outside the *.txt glob so services / services-enable don't accidentally pick it up.