| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
| |
The .ics feed URLs are secret tokens, so I keep them in the encrypted store instead of a plaintext config. Emacs calendar-sync looks them up at sync time through auth-source on the calendar-google, calendar-proton, and calendar-deepsat hosts. They travel across machines now with the rest of authinfo.
|
| | |
|
| |
|
|
| |
Super+M now toggles the touchpad (M for Mouse), and the monitor scratchpad moves to Super+R (R for Resources, since btop is a resource monitor). The touchpad toggle was on Super+F9, which is now free. Super+Shift+M still switches to the monocle layout.
|
| |
|
|
|
|
| |
I added an A/B/C/D priority scheme to the task list: what each level means, the assignment criteria, and the rule that an [#A] task needs a scheduled or deadline date so priorities stay grounded in time.
I also closed two finished tasks: the rm -rf path guard (done, with a pointer to the safe_rm_rf helper and its tests) and the touchpad toggle indicator (spec, implementation, and deploy record).
|
| |
|
|
|
|
|
|
| |
The $mod+F9 toggle and the toggle-touchpad / touchpad-auto scripts already worked, but the scripts lived only in ~/.local/bin and were never committed, and there was no way to see the touchpad's state at a glance.
I committed both scripts into the repo so stow installs them, and added a waybar indicator: a waybar-touchpad status script and a custom/touchpad module that shows a mouse glyph when the touchpad is on and a mouse-off glyph (in the dupre orange) when it's off. The scripts signal the module with pkill -RTMIN+9 waybar after each state change, so the icon updates the moment the touchpad toggles. touchpad-auto now runs at login via exec-once.
The waybar-touchpad script has unit tests under tests/waybar-touchpad/ covering the enabled, disabled, and missing-state-file cases.
|
| |
|
|
|
|
|
|
| |
Three rm -rf sites in archsetup delete paths built from variables: $state_dir for --fresh, and $source_dir/$prog_name for the git and AUR clone-retry cleanups. If a path variable were empty or malformed (preflight skipped, a degenerate git URL), the delete could expand to a top-level or otherwise unintended directory.
I added a safe_rm_rf <path> <allowed_prefix> helper that refuses to run unless the target is absolute, free of '..', deeper than a bare top-level dir, strictly inside the allowed prefix, and a real directory rather than a symlink. On the happy path it delegates to rm -rf, so successful installs are unchanged. The helper is self-contained and defined before the top-level --fresh handler, which runs before the logging helpers exist.
I covered the guard with unit tests under tests/safe-rm-rf/ that source the real function and exercise normal, boundary, and error cases against temp directories.
|
| |
|
|
|
|
| |
I removed three dead `file:` links in todo.org. They pointed at docs that were never written: testing-strategy.org, firmware-cleanup.org, and PLAN-browser-themes.org. Each task body already carries that content inline, so the links were dead weight. I also reworded the Testinfra task's lead-in that claimed the testing-strategy doc exists.
I filed three resolved reference docs into assets/outbox/: the calendar-sync scrub note, the tmux copy-mode handoff, and the 2026-05-19 lint follow-up report.
|
| |
|
|
| |
Recorded the git-history scrub of the private calendar config and added a follow-up to rotate the three exposed feed URLs once I'm at ratio's GUI. Also closed the testing-docs and shellcheck tasks that shipped this round.
|
| |
|
|
|
|
| |
init runs under #!/bin/sh but used $(<file) to read /etc/hostname, a bashism that breaks on a strict POSIX sh. I switched it to $(cat) and quoted $interface_up in the same script.
The two VM_IP assignments in the test scripts are read by the sourced validation.sh, which shellcheck can't follow, so they now carry a documented disable=SC2034 instead of a bare suppression. The rest of the shellcheck findings across the scripts are intentional (word-splitting on $SSH_OPTS, integer tests in [ ]) or already accepted, so I left them alone.
|
| |
|
|
|
|
| |
The README only covered the VM integration harness. The unit suites under tests/ (one directory per script, fake binaries on PATH) went unmentioned, so a contributor adding a .local/bin script had no way to know they existed or how to run them.
I added a make test-unit target that runs every tests/*/test_*.py suite explicitly. unittest discover can't find them because the per-script directory names are hyphenated and aren't valid package paths. Then I split the README Testing section into Unit and VM-integration layers, added a guide for adding a suite, and pointed Contributing at test-unit for script changes.
|
| |
|
|
|
|
| |
Two updates in todo.org. I marked the two dconf entries in the `[#B] Fix install errors` parent body as RESOLVED in `dc06895`, since the system-wide dconf db migration verified clean in last night's VM run.
I converted the `*** TODO [#B] AUR exit-0 logged as error` sub-task into a dated event-log entry. The root cause was a bash if-compound semantics trap in `retry_install` (the if-compound exits 0 when no condition tested true, overwriting the eval's actual exit code that `last_exit_code=$?` was trying to capture). Today's VM run verified the fix: `mkinitcpio-firmware` and `tidaler` now report `error code: 1` instead of the misleading `error code: 0`.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
tmux-util rename closes out the original six-subcommand plan. The flow:
1. fzf-pick a session from the list.
2. Prompt for a new name on stdin.
3. Bail with a useful message on empty input, same-as-old, or conflict with an existing session.
4. Otherwise `tmux rename-session -t <old> <new>` and confirm.
The conflict check uses `tmux has-session -t =<new>` with the same `=`-prefix exact-match guard as the go subcommand. Without it, tmux's default prefix matching would let `rename foo` succeed even when a session named `foobar` already exists, then surprise the user later.
5 new tests cover Normal cases (pick + rename happy path) and Boundary cases (no sessions, fzf cancel, empty new name, same-as-old no-op, conflict with existing session). The test harness's run_script grew an `stdin=` param so tests can feed the prompt input. fake-tmux picked up a rename-session handler that mutates the state file. Total suite: 48 tests, all green.
Six subcommands shipped: go, pick, ls, find, reap, rename. The original "no args prints help" requirement still holds, and the stub-test for unimplemented subcommands got removed since everything's wired now.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
tmux-util pick lists every session ("attached"/"detached" plus name), pipes it through fzf, and attaches or switch-clients to the chosen one (matching the go subcommand's inside-vs-outside-tmux discipline).
If the user cancels fzf (Ctrl-C, Esc, empty selection), the pipeline returns empty and pick exits 0 without touching tmux state.
The new fake-fzf testing fake is driven by env vars:
- FAKE_FZF_CHOICE_LINE=<N>: return the Nth line of stdin as the selection
- FAKE_FZF_CHOICE=<string>: return the literal string (ignores stdin)
- (neither): exit 130 to simulate cancel
4 new tests cover Normal cases (pick second line, inside/outside tmux behavior) and Boundary cases (no sessions, user cancellation). Total suite: 43 tests, all green.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
tmux-util find <pattern> walks every pane across every session, queries each pane's foreground command (`#{pane_current_command}`), and prints the location of any pane whose command matches the pattern. Output format: `<session>:<window>.<pane> <command>`, one per line.
Pattern is a basic ERE (passed through `grep -E`), so anchors and alternation work. Substring matching is the common case.
Exit code:
- 0 with output: matches found
- 1 with no output: no matches (lets you script around it)
- 2 with usage on stderr: missing or empty pattern
7 new tests cover Normal cases (single match, multi-match across sessions, format verification) and Boundary cases (no matches, no sessions, missing pattern, empty pattern). fake-tmux now parses pid:cmd entries in the state file so panes can carry a synthetic command name. Total suite: 39 tests, all green.
|
| |
|
|
|
|
|
|
|
|
|
| |
tmux-util go <name> attaches to a session named <name> if it exists, creates it otherwise. Behavior depends on whether the caller is already inside tmux:
- Outside tmux: `tmux attach-session -t <name>` (existing) or `tmux new-session -s <name> -c $PWD` (new).
- Inside tmux (TMUX env set): `tmux switch-client -t <name>` (existing) or `tmux new-session -d -s <name> -c $PWD` followed by `switch-client` (new). Attaching from inside tmux would nest sessions and break the outer view, so the inside path uses switch-client instead.
The existence check uses `tmux has-session -t =<name>` with the leading `=` to force exact-match. Without it, tmux does prefix matching, which would let `go foo` resolve to a session named `foobar`.
I added 6 new tests covering both inside/outside-tmux paths, both create/attach paths, plus error handling for missing or empty name arguments. fake-tmux picked up handlers for new-session (mutates state), attach-session and switch-client (record-only), and the `=`-prefix form of has-session. Total suite: 32 tests, all green.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
tmux-util ls is an opinionated replacement for `tmux ls` with columns for state (attached/detached), name, idle time (humanized), window count, and the current pane's cwd (tilde-fied if it sits under $HOME).
The cwd query goes through `tmux display -p -t <session> '#{pane_current_path}'`, which returns the cwd of the active pane of the active window. That's close enough to "what the session is about" for a one-line summary.
Idle calculation reads `date +%s` by default and accepts an override via the TMUX_UTIL_NOW env var so tests can pin "now" to a known epoch.
12 new tests cover Normal cases (attached / detached, multiple sessions) and Boundary cases (no sessions, idle exactly at minute / hour / day boundaries, $HOME tilde). One existing dispatch test got reworked because the original stub target (`ls`) is no longer unimplemented. Total suite is 26 tests, all green.
The fake-tmux harness picked up two things along the way: real format-string parsing for `list-sessions -F` and a new handler for `display -p`. The state file format extended to include activity epoch, window count, and cwd, with sensible defaults for older 3-tuple test inputs so the reap tests keep passing untouched.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
A new utility in dotfiles/common/.local/bin/ for managing tmux sessions. The eventual plan covers six subcommands (go, pick, ls, find, reap, rename). This commit ships the skeleton, the dispatch + help, and the first subcommand: reap.
reap walks every unattached tmux session whose name doesn't match $TMUX_UTIL_REAP_SKIP (default `^aiv-`), sends SIGHUP to each pane's PID (the same signal that fires when you close a terminal window), waits up to three seconds for the session to wind down, and falls back to `tmux kill-session` if anything's still alive.
Tests live under tests/tmux-util/ with the same fake-binary-on-PATH pattern layout-navigate uses. fake-tmux reads canned session state from a file and records every invocation. fake-kill records signal calls without sending them. fake-sleep is a no-op so tests don't actually wait. 14 tests cover Normal / Boundary cases for dispatch + reap. Run them with:
cd tests && python3 -m unittest tmux-util.test_tmux_util
The other five subcommands stub out for now and exit non-zero with "not implemented yet" so future TDD turns can drop them in one at a time.
|
| |
|
|
|
|
| |
`retry_install` was logging "error code: 0" for every retry-exhausted install (6 AUR packages on the 2026-05-16 run, 2 on the 2026-05-18 run). Root cause: `last_exit_code=$?` ran AFTER an `if eval ...; then return 0; fi` block. Bash defines an if-compound's exit status as zero when no condition tested true. With no else clause and a failing eval, that's exactly what happens, so `$?` captures 0 instead of eval's actual exit code.
Now eval runs unconditionally, `$?` lands in `last_exit_code` right after it, and the if just compares against the captured value. Same control flow, accurate codes in the summary. Verified with a small bash test: the old pattern reports `$?=0` after a failing if, the new pattern reports the real exit.
|
| |
|
|
|
|
| |
Two updates in todo.org. I closed the LICENSE-file subtask as a dated event-log entry. The canonical GPL-3 text landed at `LICENSE` in 028f144 on 2026-05-11. The SPDX/NOTICE-headers follow-up splits into its own subtask for the eventual public release.
I also logged the 7cd7392 emacs-stow fix verification under `[#B] Fix install errors`. The 2026-05-18 `make test` exercised the new three-branch path (git init + fetch + checkout -B main against a stow-populated `~/.emacs.d`) and the exit-128 error is gone from the Error Summary.
|
| |
|
|
| |
CLAUDE.md listed `capitaine-cursors-light`, but every other place in the repo names `Bibata-Modern-Ice`: `hyprland.conf` XCURSOR_THEME, the three Xresources files, `gtk-3.0/settings.ini`, the dconf defaults block in `archsetup`, and the `aur_install bibata-cursor-theme-bin` line. I fixed CLAUDE.md to match.
|
| |
|
|
|
|
| |
The previous block ran two `sudo -u $user dbus-launch dconf write …` calls during install to set GTK file-chooser and GNOME interface defaults. Both exited 1 on a headless install. The user had no real session bus, so dconf couldn't create `~/.config/dconf/user`. They also showed up in the 2026-05-11 / 16 / 18 VM-run error summaries.
I rewrote the block to compile a system-wide dconf db under `/etc/dconf/db/site.d/`. `dconf update` runs as root and needs no D-Bus. Settings apply to every user and can still be overridden per-user. Bonus: portal-gtk reads these on first login without the ~50s settings-proxy timeout the prior code aimed to prevent but couldn't deliver, since the per-user writes failed during install.
|
| |
|
|
|
|
| |
Lint flagged the **NOTE:** marker as a possibly-misplaced heading
(double-asterisk at start of line). Switching to single-asterisk
italic keeps the visual emphasis without the heading collision.
|
| |
|
|
|
|
|
|
|
|
| |
Pyprland 3.4+ applies `group deny` to scratchpads, which routes their
border through col.nogroup_border* instead of col.*_border. Set
col.nogroup_border_active to #daa520 (same as col.active_border) so
the scratchpad and tiled active borders read identically.
Also drop `pseudotile = true` from the unused dwindle{} block — this
config uses layout = master, so the dwindle settings never take effect.
|
| |
|
|
|
|
|
|
|
| |
`copy-selection' writes only to tmux's internal paste buffer, so a paste
in any other app got stale content. Switch the M-w binding to
`copy-pipe-no-clear "wl-copy"' (same engine as the existing y binding,
minus the -and-cancel so M-w stays in copy-mode for repeated grabs).
The selection stays visible after copy to make multi-range copying
easier to follow.
|
| |
|
|
|
|
|
|
|
|
|
| |
M-w copies and stays in mode so multiple selections can be grabbed in a row
(was copy-selection-and-cancel). C-g exits (was clear-selection). Enter is
unbound so RET has no copy-and-exit shortcut. q and Escape already cancel
by default and are kept as-is.
Mirrors the cj/vterm-tmux-history and vterm-copy-mode story on the Emacs
side, so all three surfaces for lifting text out of a vterm share one key
story.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The 2026-05-16 VM run surfaced `setting up emacs configuration files
(error code: 128)` with `fatal: not a git repository`. Root cause:
`dotfiles/common/.emacs.d/calendar-sync.local.el` lives in the stow
tree, so by the time the dotemacs clone step runs, `~/.emacs.d/`
already exists with a stowed symlink inside. The previous two-branch
check `[ -d "$emacs_dir" ]` then took the `git pull` path and failed
because the dir isn't a git checkout.
I replaced the check with three branches:
- `.git` exists → `git pull --recurse-submodules` (the existing
upgrade path).
- Dir missing or empty → `git clone --recurse-submodules` (the fresh
install path).
- Dir exists with content but no `.git` (the stow case, today's bug)
→ `git init` + `remote add origin` + `fetch --recurse-submodules` +
`checkout -B main origin/main` + `submodule update --init
--recursive`. This pulls the tree in on top of the stowed file
without losing it.
The one-line `[ -d ]` → `[ -d .git ]` fix wouldn't have been enough on
its own: the clone branch would still fail because `git clone` refuses
a non-empty target.
`bash -n archsetup` is clean. The VM test run that surfaced the bug
exercised the old two-branch path. The new third branch wants a fresh
`make test` to verify before this lands on a real machine.
todo.org picks up two things this commit touches. The stale
gitrepos.sh reference under "Remove/template personal info from
scripts" comes out. A new sub-TODO under `[#B] Fix install errors`
expands the existing tidaler item: the same "AUR exit 0 logged as
error" pattern now hits six packages instead of one (tidaler,
mkinitcpio-firmware, speedtest-go-bin, rar, masterpdfeditor,
zsh-fast-syntax-highlighting-git). The recommendation points at
`aur_install` and the error-summary aggregator as trace targets.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Two real bugs and a sweep of hygiene across the harness. `make test`
passed cleanly on this branch with the same 52/0/5 profile as the
2026-05-11 run, so the wiring is verified end-to-end.
Real bugs:
- `lib/vm-utils.sh` `snapshot_exists` was running
`qemu-img snapshot -l | grep -q "$snapshot_name"`, which matches the
name as a substring anywhere in the output — including inside dates
or filenames in other fields. Replaced with an awk field extraction
on the TAG column plus `grep -Fxq` for a whole-line literal match.
- `run-test-baremetal.sh` was setting `VALIDATION_PASSED=true|false`
after validation, but `validation.sh` already uses
`VALIDATION_PASSED` as a pass counter. The test report then
referenced `$VALIDATION_PASSED_COUNT`, which is defined nowhere.
Renamed the boolean to `TEST_PASSED` (matching run-test.sh's
pattern) and report the actual counter.
Cleanup traps and arg validation:
- `run-test.sh` now installs a top-level EXIT trap that, on abort,
kills QEMU and restores the clean-install snapshot. A
`CLEANUP_DONE=1` sentinel keeps the existing normal-path cleanup
from double-firing. This is the recurring pain from 2026-05-11
where two failed runs left orphaned QEMU processes and dirty base
disks behind.
- `create-base-vm.sh` and `debug-vm.sh` got the same kind of trap, plus
`debug-vm.sh` now rejects non-`.qcow2` paths up front instead of
letting QEMU fail later.
- `run-test.sh`, `run-test-baremetal.sh`, and `cleanup-tests.sh` now
validate that options with required values actually receive one
(`${var:?msg}` for `--script`/`--snapshot`/`--host`/`--password`,
numeric check for `--keep`).
- `run-test-baremetal.sh` traps the temp git bundle for cleanup if the
script aborts before its explicit `rm`. The ZFS rollback loop now
uses `while IFS= read -r ds` and quotes `$ds` inside the ssh_cmd so
dataset names with whitespace wouldn't break it.
Smaller hygiene:
- `vm-utils.sh` `check_ovmf` also checks `OVMF_VARS_TEMPLATE`; `start_qemu`
validates disk and ISO paths before building the QEMU command;
numeric tests quoted.
- `cleanup-tests.sh` find expression for temp disks wrapped in
`\( ... -o ... \)`, all `while read` loops use `IFS= read -r`,
orphaned QEMU cleanup tries SIGTERM with a 2s sleep before SIGKILL.
- `create-base-vm.sh` moved the "Copy an archangel-*.iso" info line
before its `fatal` instead of after (unreachable), and added the
serial-log path to the final summary.
- `lib/logging.sh` `stop_timer` no longer produces `$((end - ))` when
the named timer was never started.
- `lib/network-diagnostics.sh` `read` → `IFS= read -r`.
- `setup-testing-env.sh` now installs all missing pacman packages in
one transaction instead of one-at-a-time (avoids half-installed
state if package N fails). KVM check also verifies the user has
read+write on `/dev/kvm` and prints the `gpasswd -a $(id -un) kvm`
fix if not.
A few items from the review I deliberately skipped: replacing the
codebase-wide unquoted `$SSH_OPTS` string with an array (cosmetic, would
need to be done everywhere at once), `set -e` adds where the existing
fall-through-on-failure is intentional, and a `--force` gate on
`create-base-vm.sh` (would break the expected workflow).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three things were wrong with the old script:
- One line had a duplicate `flathub` argument (`flatpak install ...
flathub flathub org.gnome.Crosswords`). Flatpak tolerated it; still
a typo.
- Nothing added the flathub remote, so a fresh machine without it would
fail on every line.
- 24 nearly identical `flatpak install` lines with no central handling
if one app failed.
I moved the app IDs into a single `APPS=()` array (sorted) and looped.
The script now runs `flatpak remote-add --if-not-exists --user flathub
https://flathub.org/repo/flathub.flatpakrepo` up front, collects any
failed apps into a `failed` array, and prints a summary plus a non-zero
exit at the end if anything didn't install. I used `set -uo pipefail`
rather than `-euo` on purpose so a single failed install doesn't abort
the rest of the run.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The "verifying Bridge is listening" check used a regex
`127\.0\.0\.1:(1143|1025)` against `ss -ltn` output. That matches if
*either* port is listening, but the success message claims both are. So
a half-broken Bridge (IMAP up, SMTP down or vice versa) would pass the
check.
I split the check into two greps and report which port is missing.
When the check fails, the script now also prints the last 10 lines of
`systemctl --user status protonmail-bridge` to stderr so the operator
sees the service state immediately instead of being told to go run the
command themselves.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
gitrepos.sh did the same `~/.dotfiles` / `~/.emacs.d` remote swap that
post-install.sh already had, plus a `git pull --set-upstream origin main`
follow-on that post-install was missing. I folded the pull into the
post-install remote-rewrite block and dropped gitrepos.sh.
While in the file, I also:
- Quoted every variable (`"$logfile"`, `"$HOME"` paths, `"$(whoami)"`).
- Sent the remote-rewrite block to the log file like the other blocks
do (was leaking to stdout).
- Made the remote-rewrite idempotent. A re-run used to break the
`cd && remote remove && remote add` chain because remove fails when
origin is already the desired URL. The loop now uses
`git -C "$dir" remote set-url` when origin exists and `remote add`
when it does not.
- Pre-created `~/sync`, `~/pictures`, `~/code`, `~/projects` so the
clones don't fail on missing parent dirs.
- Wrapped each `git clone` in a `clone_if_missing` helper so a re-run
skips destinations that already exist instead of erroring out.
README.md picks up the gitrepos.sh removal in the forking note.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Audit pass: each of these had no references anywhere in the repo
(excluding self-references and review notes).
- wip-bootcandy.sh — "wip" prefix, non-executable. Comments mention a
boot animation but the script only installs ly and disables
getty@tty2.
- protonmail-bridge.sh — `pacman_install protonmail-bridge` (the package
landed in extra) plus cmail-setup-finish.sh now cover this.
- wireguard-proton.sh — hardcoded USGA tunnel and a relative
`../assets/wireguard-config/*.conf` path that depends on the caller's
pwd.
- create-archiso-zfs.sh — one-off ISO build snippet, non-executable.
- scripts/testing/lib/finalize-base-vm.sh — libvirt-era leftover. The
test stack moved to direct QEMU and nothing sources or calls it.
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I locked the URL (https://git.cjennings.net/dotfiles.git), the bare
repo path (/var/git/dotfiles.git), and the Phase 1 scope. Added
environment.d/envvars.conf (rofi path stripped) and
systemd/user/emacs.service to the minimal/ tree. Promoted the
DESKTOP_ENV=none VM test from optional to required. Made Phase 2's
clone explicit (sudo -u, not chown-after). Tightened Phase 3's order
so unstow and restow happen without a Hyprland reload between them.
Added a note that the new dotfiles repo can't go on GitHub until the
secrets cleanup ships, plus the post-install update flow in Step 3.3.
Replaced the "Before starting" question block with a Status table
since all five open questions are now resolved.
|
| |
|
|
|
|
|
| |
Pypr was sending stderr to /dev/null. So when its keybind clients
emitted red `hyprctl notify` banners after the daemon got stuck,
there was no trace to read. I followed the waybar / dunst /
hypridle / gammastep pattern already in the same exec-once block.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
I added a shell function that wraps `claude` and exports
CLAUDE_REMOTE_CONTROL_SESSION_NAME_PREFIX as "<short-hostname>/<cwd-basename>"
on every call. The prefix shows up in FleetView and `claude agents` so I can
tell sessions apart when several are open across projects and hosts.
I picked a function over a plain .zshrc export because $PWD has to re-evaluate
each call, not once at shell init. I picked it over an alias because the
function form is greppable and reads cleanly in `type` output.
Only affects Remote Control mode. Plain interactive `claude` is unchanged.
|
| |
|
|
| |
Covers extracting dotfiles/ into a standalone repo, adding a minimal/ stow target for headless installs, and a three-phase plan with commit boundaries. todo.org tracks the review as a sub-task.
|
| |
|
|
|
|
|
|
| |
I extended cmail-setup-finish.sh with two boot-cleanliness fixes for the systemd --user Bridge service.
The autostart cleanup removes ~/.config/autostart/Proton Mail Bridge.desktop, which double-launches Bridge and throws an "orphan instance" dialog every login.
The wait-for-dns drop-in installs an ExecStartPre loop that waits up to 30 seconds for DNS before Bridge's first API call. User-instance systemd doesn't carry network-online.target, so After=network.target doesn't imply the resolver is up. The leading '-' makes the pre-step non-fatal so an offline boot still starts the unit.
|
| |
|
|
| |
I set cursor:inactive_timeout to 2.0 so the cursor disappears after a couple of seconds without motion and reappears on the next move.
|
| |
|
|
| |
I set cursor:no_warps to true so super+j/k and other keyboard focus moves stop teleporting the cursor to the center of the newly focused window.
|
| | |
|
| |
|
|
| |
I added a [#C] task with one child per validation warning from the 18:36 VM test, each with the check it comes from and a recommendation. Most are headless-VM or QEMU-slirp false positives the test harness should skip. The lingering and Docker ones have a small real angle: logind health in the VM, and "systemctl enable docker" vs "enable --now".
|
| | |
|
| |
|
|
| |
The `validate_config()` repo check I just added used a scheme allowlist (`http(s)://`, `git://`, `ssh://`, `user@host:path`), which rejected `ARCHSETUP_REPO=/tmp/archsetup-test` in `scripts/testing/archsetup-vm.conf`. That broke the VM test: archsetup exited during validation before logging anything, and `run-test.sh` reported "ArchSetup process not found after launch". `git clone` accepts local paths and `file://` URLs fine, so the allowlist was wrong. I replaced it with a security-only check: reject a leading dash (which `git` would parse as an option) plus whitespace and control characters, allow everything else. Smoke-tested against the test config and a matrix of repo forms.
|
| |
|
|
|
|
|
|
| |
A new `validate_config()` runs whenever `--config-file` is used and rejects bad values up front instead of letting the install run partway and die: `DESKTOP_ENV` must be dwm/hyprland/none (previously only caught in the display-server step), `AUTOLOGIN`/`NO_GPU_DRIVERS` must be yes/no (previously silently ignored), `LOCALE` gets a basic shape check, and the six `*_REPO` URLs get a scheme plus no-whitespace/no-leading-dash check before they reach `git clone`.
I also pulled the username regex and reserved-names check out of `preflight_checks()` into a `validate_username()` helper, and call it from both `preflight_checks()` and `validate_config()`. That closes a gap: the old inline check only ran when the username was prompted, so a config-supplied `USERNAME=root` went through unchecked.
This is not a security boundary: `load_config` sources the config as bash, so a hostile config can already do anything. It is about catching typos with a clear message. Verified with `bash -n` and a smoke-test matrix. The next `make test` run confirms valid configs still install.
|
| |
|
|
|
|
| |
The 2026-05-11 VM test surfaced three exit-127 / "dbus-launch returned 1" errors very early in the run: `fc-cache` and the two `dconf` writes in `user_customizations()`. The function runs as step 4 of 13 (before `aur_installer`, the DE step, and most of the package installs), so the binaries the function calls are not on PATH yet.
I added `pacman_install fontconfig` and `pacman_install dconf` right before their use, mirroring the existing `pacman_install desktop-file-utils` pattern in the same function. Both are idempotent. Verified by `bash -n`. The next `make test` run confirms the behavior in the VM.
|
| |
|
|
|
|
| |
I added a TODO for the 7 errors logged during the run. A few look real: fc-cache and dconf hit exit 127, and gamemode failed for the user. A couple look like VM/nf_tables artifacts I want to confirm on bare metal.
I moved the rlwrap-not-installed investigation to Resolved (DONE). rlwrap installs cleanly in a fresh VM, so the ratio glitch does not reproduce. The test-infra fix from the previous commit is also logged as DONE in Resolved.
|
| |
|
|
|
|
| |
validate_hyprland_plugins and validate_hyprpm_hook checked for the hyprland-plugins-setup script and the hyprpm pacman hook, both removed in 4a3056a (Hyprland 0.54 brings the layouts into core). I deleted the two functions and their calls in validate_window_manager.
I also disabled errexit in run-test.sh from the validation phase onward, so one failed check is counted in VALIDATION_FAILED instead of aborting the run before the report or VM cleanup. About 16 validations across the file do a bare `return 1` after `validation_fail`; any of them firing under the previous behavior would have killed the harness mid-run.
|