@sebastienrousseau/dotfiles 0.2.503 → 0.2.504
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -1
- package/README.md +3 -3
- package/docs/COPYRIGHT +1 -1
- package/docs/OPENCODE.md +1 -1
- package/docs/index.md +2 -2
- package/docs/manual/00-introduction.md +1 -1
- package/install.sh +96 -5
- package/package.json +1 -1
- package/scripts/README.md +3 -3
- package/scripts/ci/check-copyright-headers.sh +1 -1
- package/scripts/ci/check-shell-preamble.sh +1 -1
- package/scripts/ci/guard-gitleaks-checkout.sh +1 -1
- package/scripts/diagnostics/benchmark.sh +1 -1
- package/scripts/diagnostics/doctor-unified.sh +1 -1
- package/scripts/diagnostics/perf.sh +1 -1
- package/scripts/diagnostics/security-score.sh +23 -4
- package/scripts/diagnostics/version-locks.sh +11 -1
- package/scripts/dot/commands/ai.sh +12 -12
- package/scripts/dot/commands/fleet.sh +10 -5
- package/scripts/git-hooks/pre-commit-audit.sh +2 -2
- package/scripts/ops/bundle.sh +1 -1
- package/scripts/ops/chezmoi-apply.sh +8 -2
- package/scripts/theme/rebuild-themes.sh +24 -2
- package/scripts/theme/switch.sh +1 -1
- package/scripts/theme/wallpaper-sync.sh +1 -1
- package/scripts/version-sync.sh +19 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
This file documents all notable changes to this project.
|
|
4
4
|
|
|
5
|
-
## v0.2.
|
|
5
|
+
## v0.2.504 — 2026-06-03
|
|
6
|
+
|
|
7
|
+
First-class **stock-macOS** support: the installer and the entire `dot` CLI
|
|
8
|
+
now run correctly under the system `/bin/bash` 3.2, and the mise↔chezmoi
|
|
9
|
+
ownership conflict is resolved structurally. Found by performing a clean
|
|
10
|
+
end-to-end install and exercising every command. Full suite: 4821/4821.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **macOS bash 3.2 compatibility** across the CLI, which had assumed bash 4+:
|
|
15
|
+
- iTerm2 profile `run_onchange` used `declare -A` and aborted `chezmoi apply`; rewritten with indexed arrays.
|
|
16
|
+
- `dot ai` used `local -n` namerefs + `declare -A`; now passes arrays by value and reads probe results from the cached TSV via `awk`.
|
|
17
|
+
- `dot security-score` and the `matrix` effect dropped `declare -A` (parallel arrays / `case`).
|
|
18
|
+
- `dot fleet apply` replaced the bash-4.3 `wait -n` throttle with a portable PID-FIFO; `dot theme rebuild` now requires bash 4 and re-execs under a newer bash when available.
|
|
19
|
+
- `dot perf` / `dot bundle` / `dot benchmark` / `dot doctor` / `dot sync` and the pre-commit hook: empty-array `"${arr[@]}"` under `set -u` aborted on bash 3.2; cleanup traps now use the `set +u` idiom.
|
|
20
|
+
- `.bashrc` guards bash-4-only `shopt` options (`globstar`, `dirspell`, `autocd`).
|
|
21
|
+
- **Installer:** backup loop no longer recurses into live `~/.ssh/agent` sockets; seeds git identity from `git config --global` and prints a hint when none is set. The v0.2.503 migration no longer exits non-zero under `set -e`.
|
|
22
|
+
- **mise:** the chezmoi-managed base config moved to `conf.d/00-dotfiles.toml`; `~/.config/mise/config.toml` is now mise's `.chezmoiignore`'d writable global, so `mise use -g` no longer drifts the source. An absent `gh` token no longer breaks the whole config, and the x86_64-only hyperfine aqua package (unrunnable on Apple Silicon) is no longer managed by mise. `version-sync.sh` no longer hangs on a non-TTY stdin (rg now searches the tree, not stdin) and respects `EXCLUDE_FILES`.
|
|
23
|
+
- **`Brewfile.cli`:** add `zellij` and `sops` (checked by `dot doctor`, previously absent).
|
|
24
|
+
- **`dot version-locks`** is `.chezmoiroot`-aware again (had reported "config not found" since the v0.2.503 reorg).
|
|
25
|
+
- **Tests:** robust large-HEIC wallpaper dimension probe (`-ping`); `test_perf_percentiles` trusts mise in its isolated environment.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Homebrew/Scoop release installers now actually install (sha256 substitution, Scoop `extract_dir` + Windows entrypoint).
|
|
30
|
+
|
|
31
|
+
## v0.2.503 — 2026-05-30
|
|
6
32
|
|
|
7
33
|
Polish + cross-platform + Scorecard release **plus** the
|
|
8
34
|
incremental repo reorganisation per
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://github.com/sebastienrousseau/dotfiles/actions"><img src="https://img.shields.io/github/actions/workflow/status/sebastienrousseau/dotfiles/ci.yml?style=for-the-badge&logo=github" alt="Build" /></a>
|
|
13
|
-
<a href="https://github.com/sebastienrousseau/dotfiles/releases/latest"><img src="https://img.shields.io/badge/Version-v0.2.
|
|
13
|
+
<a href="https://github.com/sebastienrousseau/dotfiles/releases/latest"><img src="https://img.shields.io/badge/Version-v0.2.504-blue?style=for-the-badge" alt="Version" /></a>
|
|
14
14
|
<a href="https://github.com/sebastienrousseau/dotfiles/releases"><img src="https://img.shields.io/github/downloads/sebastienrousseau/dotfiles/total?style=for-the-badge" alt="Downloads" /></a>
|
|
15
15
|
<a href="https://codespaces.new/sebastienrousseau/dotfiles"><img src="https://img.shields.io/badge/Open%20in-Codespaces-blue?style=for-the-badge&logo=github" alt="Open in GitHub Codespaces" /></a>
|
|
16
16
|
<a href="https://scorecard.dev/viewer/?uri=github.com/sebastienrousseau/dotfiles"><img src="https://img.shields.io/ossf-scorecard/github.com/sebastienrousseau/dotfiles?style=for-the-badge&label=OpenSSF%20Scorecard" alt="OpenSSF Scorecard" /></a>
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
curl -fsSL -o /tmp/dotfiles-install.sh \
|
|
55
|
-
https://raw.githubusercontent.com/sebastienrousseau/dotfiles/v0.2.
|
|
56
|
-
echo "
|
|
55
|
+
https://raw.githubusercontent.com/sebastienrousseau/dotfiles/v0.2.504/install.sh
|
|
56
|
+
echo "d5a04c5e2813a93a63c8ecce9655cf3d107f6068862c6eba84a92cf22f801c7e /tmp/dotfiles-install.sh" \
|
|
57
57
|
| shasum -a 256 -c
|
|
58
58
|
bash /tmp/dotfiles-install.sh
|
|
59
59
|
```
|
package/docs/COPYRIGHT
CHANGED
package/docs/OPENCODE.md
CHANGED
|
@@ -117,7 +117,7 @@ install.sh # Bootstrap installer
|
|
|
117
117
|
### Key Data Files
|
|
118
118
|
|
|
119
119
|
- `.chezmoidata.toml` — All configuration: profiles, feature flags, tool settings
|
|
120
|
-
- `dot_config/mise/
|
|
120
|
+
- `dot_config/mise/conf.d/00-dotfiles.toml` — mise tool versions (node, python, go, rust, etc.); the writable `~/.config/mise/config.toml` is mise-owned and not chezmoi-managed
|
|
121
121
|
- `dot_config/starship.toml.tmpl` — Prompt configuration
|
|
122
122
|
|
|
123
123
|
### Testing
|
package/docs/index.md
CHANGED
|
@@ -7,7 +7,7 @@ render_with_liquid: false
|
|
|
7
7
|
Cross-platform, signed, local-first dotfiles for macOS, Linux, and WSL.
|
|
8
8
|
|
|
9
9
|
[](https://github.com/sebastienrousseau/dotfiles/actions)
|
|
10
|
-
[](https://github.com/sebastienrousseau/dotfiles/releases/tag/v0.2.504)
|
|
11
11
|
[](https://github.com/sebastienrousseau/dotfiles/releases)
|
|
12
12
|
|
|
13
13
|
This site is published from the `docs/` directory on `master` and tracks the current workstation baseline, operational guidance, and security material for the repository.
|
|
@@ -38,6 +38,6 @@ This site is published from the `docs/` directory on `master` and tracks the cur
|
|
|
38
38
|
|
|
39
39
|
## Current Release
|
|
40
40
|
|
|
41
|
-
- Current tagged release: [`v0.2.
|
|
41
|
+
- Current tagged release: [`v0.2.504`](https://github.com/sebastienrousseau/dotfiles/releases/tag/v0.2.504)
|
|
42
42
|
- Latest release feed: [GitHub releases](https://github.com/sebastienrousseau/dotfiles/releases/latest)
|
|
43
43
|
- Source repository: [sebastienrousseau/dotfiles](https://github.com/sebastienrousseau/dotfiles)
|
|
@@ -4,7 +4,7 @@ render_with_liquid: false
|
|
|
4
4
|
|
|
5
5
|
# Introduction
|
|
6
6
|
|
|
7
|
-
This manual describes `.dotfiles` v0.2.
|
|
7
|
+
This manual describes `.dotfiles` v0.2.504 — a trusted agent workstation baseline for macOS, Linux, and WSL.
|
|
8
8
|
|
|
9
9
|
The repository is more than a personal dotfiles collection. It ships as workstation infrastructure: signed, attested, multi-platform, AI-aware, and self-healing. Chezmoi handles templating and platform differences. The `dot` CLI sits on top and coordinates lifecycle operations.
|
|
10
10
|
|
package/install.sh
CHANGED
|
@@ -59,21 +59,26 @@ show_help() {
|
|
|
59
59
|
Usage: install.sh [version] [options]
|
|
60
60
|
|
|
61
61
|
Arguments:
|
|
62
|
-
version The version (tag or branch) to install (default: v0.2.
|
|
62
|
+
version The version (tag or branch) to install (default: v0.2.504)
|
|
63
63
|
|
|
64
64
|
Options:
|
|
65
65
|
--help Show this help message
|
|
66
66
|
--force Non-interactive mode (sets DOTFILES_NONINTERACTIVE=1)
|
|
67
67
|
--silent Quiet mode (sets DOTFILES_SILENT=1)
|
|
68
68
|
--minimal Minimal profile (disable nvim, tmux, zellij)
|
|
69
|
+
--provision After applying configs, install the toolchain (packages,
|
|
70
|
+
fonts, language tools) via the install/provision scripts.
|
|
71
|
+
Also enabled by DOTFILES_PROVISION=1. Opt-in because it
|
|
72
|
+
installs packages and may change OS defaults.
|
|
69
73
|
|
|
70
74
|
EOF
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
main() {
|
|
74
|
-
local version="v0.2.
|
|
78
|
+
local version="v0.2.504"
|
|
75
79
|
local version_set=0
|
|
76
80
|
local minimal=0
|
|
81
|
+
local provision="${DOTFILES_PROVISION:-0}"
|
|
77
82
|
local _cleanup_files=()
|
|
78
83
|
trap 'set +u; rm -f "${_cleanup_files[@]}" 2>/dev/null; set -u' EXIT
|
|
79
84
|
|
|
@@ -86,6 +91,7 @@ main() {
|
|
|
86
91
|
--silent) export DOTFILES_SILENT=1 ;;
|
|
87
92
|
--force) export DOTFILES_NONINTERACTIVE=1 ;;
|
|
88
93
|
--minimal) minimal=1 ;;
|
|
94
|
+
--provision) provision=1 ;;
|
|
89
95
|
-*)
|
|
90
96
|
# Catch single-dash and double-dash unknowns the same way.
|
|
91
97
|
error "Unknown option: $arg"
|
|
@@ -99,7 +105,7 @@ main() {
|
|
|
99
105
|
# like `foobar` doesn't trigger a 30s+ network download attempt.
|
|
100
106
|
# Caught by the install.sh fuzz harness (#881).
|
|
101
107
|
if [[ ! "$arg" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+([-+][a-zA-Z0-9.-]+)?$ ]]; then
|
|
102
|
-
error "Unrecognized positional argument '$arg' — expected a semver version (e.g. v0.2.
|
|
108
|
+
error "Unrecognized positional argument '$arg' — expected a semver version (e.g. v0.2.504)."
|
|
103
109
|
fi
|
|
104
110
|
version="$arg"
|
|
105
111
|
version_set=1
|
|
@@ -257,6 +263,35 @@ main() {
|
|
|
257
263
|
sed_in_place 's/^zellij = true/zellij = false/' "$data_file"
|
|
258
264
|
}
|
|
259
265
|
|
|
266
|
+
# Carry the user's existing global git identity into chezmoi's data.
|
|
267
|
+
#
|
|
268
|
+
# This installer sets up chezmoi via sourceDir rather than `chezmoi init`,
|
|
269
|
+
# so the config template's prompts for git_name / git_email never run. The
|
|
270
|
+
# gitconfig template coalesces git_name->name->"" (likewise email,
|
|
271
|
+
# signingkey) and only emits a [user] block when non-empty — so without
|
|
272
|
+
# this, a fresh install produces a ~/.gitconfig with no identity at all,
|
|
273
|
+
# and commits fail with "Author identity unknown". Seed name/email/
|
|
274
|
+
# signingkey from `git config --global` when present. Idempotent: skips if
|
|
275
|
+
# the config already carries a [data] block.
|
|
276
|
+
toml_escape() { printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'; }
|
|
277
|
+
seed_git_identity() {
|
|
278
|
+
local cfg="$CHEZMOI_CONFIG_FILE"
|
|
279
|
+
[[ -f "$cfg" ]] || return 0
|
|
280
|
+
grep -q '^\[data\]' "$cfg" 2>/dev/null && return 0
|
|
281
|
+
local gname gemail gkey
|
|
282
|
+
gname="$(git config --global user.name 2>/dev/null || true)"
|
|
283
|
+
gemail="$(git config --global user.email 2>/dev/null || true)"
|
|
284
|
+
gkey="$(git config --global user.signingkey 2>/dev/null || true)"
|
|
285
|
+
[[ -z "$gname" && -z "$gemail" ]] && return 0
|
|
286
|
+
{
|
|
287
|
+
printf '\n[data]\n'
|
|
288
|
+
[[ -n "$gname" ]] && printf 'name = "%s"\n' "$(toml_escape "$gname")"
|
|
289
|
+
[[ -n "$gemail" ]] && printf 'email = "%s"\n' "$(toml_escape "$gemail")"
|
|
290
|
+
[[ -n "$gkey" ]] && printf 'signingkey = "%s"\n' "$(toml_escape "$gkey")"
|
|
291
|
+
} >>"$cfg"
|
|
292
|
+
echo " Seeded git identity ($gname <$gemail>) into chezmoi data."
|
|
293
|
+
}
|
|
294
|
+
|
|
260
295
|
# 5. Backup existing dotfiles that chezmoi will overwrite
|
|
261
296
|
step "Backing up existing dotfiles..."
|
|
262
297
|
BACKUP_DIR="$HOME/.dotfiles.bak.$(date +"%Y%m%d_%H%M%S")"
|
|
@@ -273,6 +308,17 @@ main() {
|
|
|
273
308
|
if command -v chezmoi >/dev/null && [[ -f "$CHEZMOI_CONFIG_FILE" ]]; then
|
|
274
309
|
while IFS= read -r file; do
|
|
275
310
|
[[ -z "$file" ]] && continue
|
|
311
|
+
# Skip managed *directories*: chezmoi apply never clobbers a
|
|
312
|
+
# directory's existing contents, so they don't need backing up, and
|
|
313
|
+
# `cp -a` on one recurses into things it can't copy — e.g. the live
|
|
314
|
+
# ssh-agent sockets under ~/.ssh/agent, which spew
|
|
315
|
+
# "is a socket (not copied)" warnings. The managed files chezmoi
|
|
316
|
+
# would actually overwrite are listed (and backed up) individually.
|
|
317
|
+
# `-d` without `-L` excludes only real dirs; symlinks are copied as
|
|
318
|
+
# links by `cp -a`, so they never recurse.
|
|
319
|
+
if [[ -d "$file" && ! -L "$file" ]]; then
|
|
320
|
+
continue
|
|
321
|
+
fi
|
|
276
322
|
if [[ -e "$file" ]]; then
|
|
277
323
|
rel="${file#"$HOME"/}"
|
|
278
324
|
mkdir -p "$BACKUP_DIR/$(dirname "$rel")"
|
|
@@ -304,7 +350,7 @@ main() {
|
|
|
304
350
|
# 6. Initialize & Apply
|
|
305
351
|
step "Applying Configuration..."
|
|
306
352
|
|
|
307
|
-
# ── Auto-migration for v0.2.
|
|
353
|
+
# ── Auto-migration for v0.2.504 reorg ─────────────────────────────────
|
|
308
354
|
# If the user is upgrading from a pre-0.2.503 install, run the
|
|
309
355
|
# migration script BEFORE `chezmoi apply` so the reorg's source-
|
|
310
356
|
# path moves don't cause chezmoi to delete deployed files.
|
|
@@ -313,7 +359,7 @@ main() {
|
|
|
313
359
|
for migrate_src in "$SOURCE_DIR" "$LEGACY_SOURCE_DIR"; do
|
|
314
360
|
migrate_script="$migrate_src/install/migrate/migrate-v0_2-to-v0_2_503.sh"
|
|
315
361
|
if [[ -x "$migrate_script" ]]; then
|
|
316
|
-
echo " Running v0.2.
|
|
362
|
+
echo " Running v0.2.504 migration (idempotent; safe on fresh installs)..."
|
|
317
363
|
"$migrate_script" || echo " migration exited non-zero — continuing apply"
|
|
318
364
|
break
|
|
319
365
|
fi
|
|
@@ -323,6 +369,7 @@ main() {
|
|
|
323
369
|
if [[ -d "$SOURCE_DIR/.git" ]]; then
|
|
324
370
|
echo " Applying from local source: $SOURCE_DIR"
|
|
325
371
|
ensure_chezmoi_source "$SOURCE_DIR"
|
|
372
|
+
seed_git_identity
|
|
326
373
|
APPLY_FLAGS=()
|
|
327
374
|
if [[ "${DOTFILES_NONINTERACTIVE:-0}" = "1" ]]; then
|
|
328
375
|
APPLY_FLAGS=(--force --no-tty)
|
|
@@ -332,6 +379,7 @@ main() {
|
|
|
332
379
|
echo " Migrating from legacy source: $LEGACY_SOURCE_DIR"
|
|
333
380
|
mv "$LEGACY_SOURCE_DIR" "$SOURCE_DIR"
|
|
334
381
|
ensure_chezmoi_source "$SOURCE_DIR"
|
|
382
|
+
seed_git_identity
|
|
335
383
|
APPLY_FLAGS=()
|
|
336
384
|
if [[ "${DOTFILES_NONINTERACTIVE:-0}" = "1" ]]; then
|
|
337
385
|
APPLY_FLAGS=(--force --no-tty)
|
|
@@ -362,6 +410,7 @@ main() {
|
|
|
362
410
|
fi
|
|
363
411
|
|
|
364
412
|
ensure_chezmoi_source "$SOURCE_DIR"
|
|
413
|
+
seed_git_identity
|
|
365
414
|
APPLY_FLAGS=()
|
|
366
415
|
if [[ "${DOTFILES_NONINTERACTIVE:-0}" = "1" ]]; then
|
|
367
416
|
APPLY_FLAGS=(--force --no-tty)
|
|
@@ -369,7 +418,49 @@ main() {
|
|
|
369
418
|
chezmoi apply "${APPLY_FLAGS[@]}"
|
|
370
419
|
fi
|
|
371
420
|
|
|
421
|
+
# Toolchain provisioning (opt-in). The install/provision/ scripts (package
|
|
422
|
+
# managers, fonts, language + AI tools) are chezmoi run_ scripts, but they
|
|
423
|
+
# live OUTSIDE the .chezmoiroot source dir (defaults/), so `chezmoi apply`
|
|
424
|
+
# never runs them — a fresh install otherwise ships configs but zero tools.
|
|
425
|
+
# Run them here only when explicitly requested: they install packages and
|
|
426
|
+
# can change OS defaults, so we never do it implicitly (CI / Docker /
|
|
427
|
+
# unattended automation must opt in via --provision or DOTFILES_PROVISION=1).
|
|
428
|
+
if [[ "$provision" = "1" && $minimal -eq 0 ]]; then
|
|
429
|
+
step "Provisioning toolchain (packages, fonts, tools)..."
|
|
430
|
+
local prov_dir="$SOURCE_DIR/install/provision"
|
|
431
|
+
if [[ -d "$prov_dir" ]]; then
|
|
432
|
+
local script
|
|
433
|
+
# run_once_install_* (shells) first, then numbered run_onchange_* in order.
|
|
434
|
+
while IFS= read -r script; do
|
|
435
|
+
[[ -f "$script" ]] || continue
|
|
436
|
+
echo " → $(basename "$script")"
|
|
437
|
+
if [[ "$script" == *.tmpl ]]; then
|
|
438
|
+
chezmoi execute-template <"$script" | bash ||
|
|
439
|
+
echo " (step exited non-zero — continuing)"
|
|
440
|
+
else
|
|
441
|
+
bash "$script" || echo " (step exited non-zero — continuing)"
|
|
442
|
+
fi
|
|
443
|
+
done < <(ls "$prov_dir"/run_once_install_* "$prov_dir"/run_onchange_* 2>/dev/null | sort)
|
|
444
|
+
fi
|
|
445
|
+
elif [[ $minimal -eq 0 ]]; then
|
|
446
|
+
step "Configs deployed. To also install the toolchain (packages, fonts, tools):"
|
|
447
|
+
echo " bash \"$SOURCE_DIR/install.sh\" --provision # or DOTFILES_PROVISION=1"
|
|
448
|
+
echo " (or: brew bundle --file ~/.config/shell/Brewfile.cli)"
|
|
449
|
+
fi
|
|
450
|
+
|
|
372
451
|
success "Configuration loaded. Please restart your shell."
|
|
452
|
+
|
|
453
|
+
# If no git identity ended up configured, commits will fail with
|
|
454
|
+
# "Author identity unknown". Point the user at the one-line fix rather
|
|
455
|
+
# than letting them discover it on their first commit.
|
|
456
|
+
if [[ -z "$(git config --global user.email 2>/dev/null || true)" ]] &&
|
|
457
|
+
! grep -q '^email' "$CHEZMOI_CONFIG_FILE" 2>/dev/null; then
|
|
458
|
+
step "No git identity detected. Set yours so commits are attributed:"
|
|
459
|
+
echo " git config --global user.name \"Your Name\""
|
|
460
|
+
echo " git config --global user.email \"you@example.com\""
|
|
461
|
+
echo " then re-run: chezmoi apply"
|
|
462
|
+
fi
|
|
463
|
+
|
|
373
464
|
step "Run 'dot learn' for an interactive tour of your new dotfiles."
|
|
374
465
|
}
|
|
375
466
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebastienrousseau/dotfiles",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.504",
|
|
4
4
|
"description": "The Trusted Shell Platform — Universal dotfiles managed by Chezmoi. Features Bash & Zsh for macOS, Linux & WSL. Rust modern tooling & enterprise-grade security.",
|
|
5
5
|
"main": "install.sh",
|
|
6
6
|
"bin": {
|
package/scripts/README.md
CHANGED
|
@@ -7,7 +7,7 @@ workflows, by `chezmoi apply` hooks, or by hand.
|
|
|
7
7
|
|
|
8
8
|
## Subtree map
|
|
9
9
|
|
|
10
|
-
Per the
|
|
10
|
+
Per the repository reorg (RFC `docs/operations/RFC_v0_2_503_reorganization.md`),
|
|
11
11
|
**repo-only ops** (CI, release, maintenance, docs-generation) have
|
|
12
12
|
moved to the top-level `tools/` tree. `scripts/` retains the
|
|
13
13
|
**runtime-invoked** scripts that the `dot` CLI dispatches to plus a
|
|
@@ -17,7 +17,7 @@ few specialised subtrees.
|
|
|
17
17
|
|
|
18
18
|
| Path | Purpose | Touched by |
|
|
19
19
|
|---|---|---|
|
|
20
|
-
| `scripts/dot/commands/` | Per-subcommand handlers for the `dot` CLI. Sources `lib/dot/*.sh` (moved out of this tree in
|
|
20
|
+
| `scripts/dot/commands/` | Per-subcommand handlers for the `dot` CLI. Sources `lib/dot/*.sh` (moved out of this tree in the Phase 1 reorg). | Dispatched by `bin/dot` |
|
|
21
21
|
| `scripts/dot/powershell/` | Native PowerShell module (`Dot.psm1`) exporting `Get-DotVersion` / `Invoke-DotHelp` / `Test-DotAgentsSync`. | `bin/dot.ps1` |
|
|
22
22
|
| `scripts/dot/data/` | Per-command static data (registry seeds, palette tables). | `scripts/dot/commands/*` |
|
|
23
23
|
| `scripts/lib/` | Cross-cutting library helpers reused across multiple scripts. Example: `secrets_provider.sh` (keychain / pass / age dispatch). | `scripts/dot/commands/*`, ops scripts |
|
|
@@ -49,7 +49,7 @@ few specialised subtrees.
|
|
|
49
49
|
The `dot` CLI is implemented as `bin/dot`
|
|
50
50
|
(dispatcher) + `scripts/dot/commands/<cmd>.sh` (per-command
|
|
51
51
|
handlers) + `lib/dot/*.sh` (shared helpers — moved out of
|
|
52
|
-
`scripts/dot/lib/` in
|
|
52
|
+
`scripts/dot/lib/` in the Phase 1 reorg per the
|
|
53
53
|
[reorganisation RFC](../docs/operations/RFC_v0_2_503_reorganization.md)).
|
|
54
54
|
|
|
55
55
|
| Path | Purpose |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Copyright (c) 2015-2026 Dotfiles. All rights reserved.
|
|
3
|
-
# Compat shim: the canonical script moved to tools/ci/
|
|
3
|
+
# Compat shim: the canonical script moved to tools/ci/ during the repo reorg.
|
|
4
4
|
# Pinned reusable workflows on master still reference the old path;
|
|
5
5
|
# this delegates so they keep working until the next pin bump.
|
|
6
6
|
set -euo pipefail
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Copyright (c) 2015-2026 Dotfiles. All rights reserved.
|
|
3
|
-
# Compat shim: the canonical script moved to tools/ci/
|
|
3
|
+
# Compat shim: the canonical script moved to tools/ci/ during the repo reorg.
|
|
4
4
|
# Pinned reusable workflows on master still reference the old path;
|
|
5
5
|
# this delegates so they keep working until the next pin bump.
|
|
6
6
|
set -euo pipefail
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Copyright (c) 2015-2026 Dotfiles. All rights reserved.
|
|
3
|
-
# Compat shim: the canonical script moved to tools/ci/
|
|
3
|
+
# Compat shim: the canonical script moved to tools/ci/ during the repo reorg.
|
|
4
4
|
# Pinned reusable workflows on master still reference the old path;
|
|
5
5
|
# this delegates so they keep working until the next pin bump.
|
|
6
6
|
set -euo pipefail
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
set -euo pipefail
|
|
42
42
|
|
|
43
43
|
_cleanup_files=()
|
|
44
|
-
trap 'rm -f "${_cleanup_files[@]}"' EXIT
|
|
44
|
+
trap 'set +u; rm -f "${_cleanup_files[@]}" 2>/dev/null; set -u' EXIT
|
|
45
45
|
|
|
46
46
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
47
47
|
# shellcheck source=../../lib/dot/ui.sh
|
|
@@ -64,7 +64,25 @@ YELLOW="${YELLOW:-}"
|
|
|
64
64
|
# Scoring
|
|
65
65
|
TOTAL_POINTS=0
|
|
66
66
|
MAX_POINTS=0
|
|
67
|
-
declare -A
|
|
67
|
+
# Parallel indexed arrays instead of `declare -A` (bash 4+; macOS ships
|
|
68
|
+
# bash 3.2). CAT_NAMES[i] holds a category name, CAT_SCORES[i] its running
|
|
69
|
+
# total. Category names can contain spaces, so an emulation via dynamic
|
|
70
|
+
# variable names wouldn't work — a linear scan over the handful of
|
|
71
|
+
# categories is fine.
|
|
72
|
+
CAT_NAMES=()
|
|
73
|
+
CAT_SCORES=()
|
|
74
|
+
|
|
75
|
+
_cat_add() {
|
|
76
|
+
local name="$1" pts="$2" i
|
|
77
|
+
for ((i = 0; i < ${#CAT_NAMES[@]}; i++)); do
|
|
78
|
+
if [[ "${CAT_NAMES[$i]}" == "$name" ]]; then
|
|
79
|
+
CAT_SCORES[i]=$((CAT_SCORES[i] + pts))
|
|
80
|
+
return 0
|
|
81
|
+
fi
|
|
82
|
+
done
|
|
83
|
+
CAT_NAMES+=("$name")
|
|
84
|
+
CAT_SCORES+=("$pts")
|
|
85
|
+
}
|
|
68
86
|
|
|
69
87
|
add_points() {
|
|
70
88
|
local category="$1"
|
|
@@ -74,7 +92,7 @@ add_points() {
|
|
|
74
92
|
|
|
75
93
|
TOTAL_POINTS=$((TOTAL_POINTS + points))
|
|
76
94
|
MAX_POINTS=$((MAX_POINTS + max))
|
|
77
|
-
|
|
95
|
+
_cat_add "$category" "$points"
|
|
78
96
|
|
|
79
97
|
if ! $JSON_OUTPUT && $VERBOSE; then
|
|
80
98
|
local icon
|
|
@@ -339,10 +357,11 @@ print_summary() {
|
|
|
339
357
|
echo " \"grade\": \"$(get_grade $score)\","
|
|
340
358
|
echo " \"categories\": {"
|
|
341
359
|
local first=true
|
|
342
|
-
|
|
360
|
+
local _ci
|
|
361
|
+
for ((_ci = 0; _ci < ${#CAT_NAMES[@]}; _ci++)); do
|
|
343
362
|
$first || echo ","
|
|
344
363
|
first=false
|
|
345
|
-
printf " \"%s\": %d" "$
|
|
364
|
+
printf " \"%s\": %d" "${CAT_NAMES[$_ci]}" "${CAT_SCORES[$_ci]}"
|
|
346
365
|
done
|
|
347
366
|
echo ""
|
|
348
367
|
echo " }"
|
|
@@ -30,10 +30,20 @@ resolve_source_dir() {
|
|
|
30
30
|
|
|
31
31
|
src_dir=$(resolve_source_dir)
|
|
32
32
|
|
|
33
|
+
# resolve_source_dir returns the repo root, but since the defaults/ reorg the
|
|
34
|
+
# deployable tree lives under the .chezmoiroot subdir (defaults/). Descend
|
|
35
|
+
# into it so paths like dot_config/... resolve. (Without this the mise lookup
|
|
36
|
+
# below silently reported "config not found" on every run.)
|
|
37
|
+
cm_src="$src_dir"
|
|
38
|
+
if [[ -f "$src_dir/.chezmoiroot" ]]; then
|
|
39
|
+
_cm_root="$(tr -d '[:space:]' <"$src_dir/.chezmoiroot")"
|
|
40
|
+
[[ -n "$_cm_root" && -d "$src_dir/$_cm_root" ]] && cm_src="$src_dir/$_cm_root"
|
|
41
|
+
fi
|
|
42
|
+
|
|
33
43
|
ui_header "Version Locks"
|
|
34
44
|
|
|
35
45
|
ui_section "mise toolchain"
|
|
36
|
-
mise_config="$
|
|
46
|
+
mise_config="$cm_src/dot_config/mise/conf.d/00-dotfiles.toml"
|
|
37
47
|
if [[ -f "$mise_config" ]]; then
|
|
38
48
|
awk -F= '
|
|
39
49
|
/^\[tools\]/ {in_tools=1; next}
|
|
@@ -53,7 +53,8 @@ _ai_extract_version() {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
_ai_refresh_status_cache() {
|
|
56
|
-
local -n
|
|
56
|
+
# Entries passed by value (not a `local -n` nameref — bash 4.3+; macOS bash is 3.2).
|
|
57
|
+
local ai_entries=("$@")
|
|
57
58
|
local tmp_file
|
|
58
59
|
tmp_file="$(mktemp)"
|
|
59
60
|
mkdir -p "$AI_CACHE_DIR"
|
|
@@ -134,6 +135,12 @@ _ai_get_cached_status() {
|
|
|
134
135
|
cat "$AI_STATUS_CACHE_FILE"
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
# Look up field $2 (2=present 0/1, 3=version) for binary $1 from the
|
|
139
|
+
# cached TSV. Replaces a bash-4 associative array for macOS bash 3.2.
|
|
140
|
+
_ai_status_field() {
|
|
141
|
+
awk -F'\t' -v b="$1" -v f="$2" '$1==b{print $f;exit}' "$AI_STATUS_CACHE_FILE" 2>/dev/null
|
|
142
|
+
}
|
|
143
|
+
|
|
137
144
|
# binary -> mise package mapping
|
|
138
145
|
_ai_mise_pkg() {
|
|
139
146
|
case "$1" in
|
|
@@ -177,17 +184,9 @@ cmd_ai_status() {
|
|
|
177
184
|
)
|
|
178
185
|
|
|
179
186
|
if ! _ai_cache_fresh "$AI_STATUS_CACHE_FILE"; then
|
|
180
|
-
_ai_refresh_status_cache ai_clis
|
|
187
|
+
_ai_refresh_status_cache "${ai_clis[@]}"
|
|
181
188
|
fi
|
|
182
189
|
|
|
183
|
-
declare -A ai_present=()
|
|
184
|
-
declare -A ai_version=()
|
|
185
|
-
local cached_bin cached_present cached_version
|
|
186
|
-
while IFS=$'\t' read -r cached_bin cached_present cached_version; do
|
|
187
|
-
ai_present["$cached_bin"]="$cached_present"
|
|
188
|
-
ai_version["$cached_bin"]="$cached_version"
|
|
189
|
-
done < <(_ai_get_cached_status)
|
|
190
|
-
|
|
191
190
|
local -a installed=()
|
|
192
191
|
local -a missing=()
|
|
193
192
|
local current_category=""
|
|
@@ -199,8 +198,9 @@ cmd_ai_status() {
|
|
|
199
198
|
ui_section "$category"
|
|
200
199
|
current_category="$category"
|
|
201
200
|
fi
|
|
202
|
-
if [[ "$
|
|
203
|
-
ver="$
|
|
201
|
+
if [[ "$(_ai_status_field "$bin" 2)" == "1" ]]; then
|
|
202
|
+
ver="$(_ai_status_field "$bin" 3)"
|
|
203
|
+
[[ -z "$ver" ]] && ver="installed"
|
|
204
204
|
[[ "$bin" == "claude" ]] && ver="${ver%% *}"
|
|
205
205
|
ui_ok "$name" "$ver — $desc"
|
|
206
206
|
installed+=("$name|$bin|$role")
|
|
@@ -583,16 +583,21 @@ EOF
|
|
|
583
583
|
fi
|
|
584
584
|
}
|
|
585
585
|
|
|
586
|
-
|
|
586
|
+
# Throttle to `jobs` concurrent workers. `wait -n` (wait for the next
|
|
587
|
+
# job to finish) is bash 4.3+, but macOS ships bash 3.2 — there it
|
|
588
|
+
# silently fails and the throttle collapses to unbounded parallelism.
|
|
589
|
+
# Track PIDs and block on the oldest when at capacity instead; works on
|
|
590
|
+
# bash 3.2 and 4+ alike.
|
|
591
|
+
local _pids=()
|
|
587
592
|
while IFS=$'\t' read -r name ssh profile; do
|
|
588
593
|
[[ -n "$name" && -n "$ssh" ]] || continue
|
|
589
594
|
total=$((total + 1))
|
|
590
|
-
while ((
|
|
591
|
-
wait
|
|
592
|
-
|
|
595
|
+
while ((${#_pids[@]} >= jobs)); do
|
|
596
|
+
wait "${_pids[0]}" 2>/dev/null || true
|
|
597
|
+
_pids=("${_pids[@]:1}")
|
|
593
598
|
done
|
|
594
599
|
_fleet_apply_one "$name" "$ssh" "$effective_cmd" "$tmpdir" &
|
|
595
|
-
|
|
600
|
+
_pids+=("$!")
|
|
596
601
|
done <<<"$entries"
|
|
597
602
|
wait
|
|
598
603
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
|
|
8
8
|
_cleanup_files=()
|
|
9
|
-
trap 'rm -f "${_cleanup_files[@]}"' EXIT
|
|
9
|
+
trap 'set +u; rm -f "${_cleanup_files[@]}" 2>/dev/null; set -u' EXIT
|
|
10
10
|
|
|
11
11
|
# ANSI Colors
|
|
12
12
|
RED='\033[0;31m'
|
|
@@ -140,6 +140,6 @@ if [[ $FAILED -eq 1 ]]; then
|
|
|
140
140
|
printf '%b\\n' " (Use --no-verify to bypass if absolutely necessary)"
|
|
141
141
|
exit 1
|
|
142
142
|
else
|
|
143
|
-
printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.
|
|
143
|
+
printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.504 standards maintained."
|
|
144
144
|
exit 0
|
|
145
145
|
fi
|
package/scripts/ops/bundle.sh
CHANGED
|
@@ -11,9 +11,15 @@ source "$SCRIPT_DIR/../../lib/dot/ui.sh"
|
|
|
11
11
|
source "$SCRIPT_DIR/../../lib/dot/log.sh"
|
|
12
12
|
export DOT_COMMAND="apply"
|
|
13
13
|
|
|
14
|
-
# Temp file cleanup
|
|
14
|
+
# Temp file cleanup. `set +u` guards the array expansion: on bash 3.2
|
|
15
|
+
# (macOS) expanding an empty array under `set -u` is an "unbound
|
|
16
|
+
# variable" error, which would fire on every clean `dot sync`.
|
|
15
17
|
_TMPFILES=()
|
|
16
|
-
cleanup() {
|
|
18
|
+
cleanup() {
|
|
19
|
+
set +u
|
|
20
|
+
rm -f "${_TMPFILES[@]}" 2>/dev/null
|
|
21
|
+
set -u
|
|
22
|
+
}
|
|
17
23
|
trap cleanup EXIT
|
|
18
24
|
|
|
19
25
|
# Help flag
|
|
@@ -12,11 +12,33 @@
|
|
|
12
12
|
# bash rebuild-themes.sh --list # List discovered wallpapers without rebuilding
|
|
13
13
|
set -euo pipefail
|
|
14
14
|
|
|
15
|
+
# This script relies on associative arrays (`declare -A`) and `wait -n`,
|
|
16
|
+
# both of which need bash >= 4. macOS ships /bin/bash 3.2, where it would
|
|
17
|
+
# otherwise fail with cryptic "invalid option" / "bad array subscript"
|
|
18
|
+
# errors mid-run. Re-exec under a newer bash when one is available
|
|
19
|
+
# (Homebrew, MacPorts, mise), and fail with a clear, actionable message
|
|
20
|
+
# otherwise rather than corrupting a half-built themes.toml.
|
|
21
|
+
if ((BASH_VERSINFO[0] < 4)); then
|
|
22
|
+
for _newer_bash in \
|
|
23
|
+
/opt/homebrew/bin/bash \
|
|
24
|
+
/usr/local/bin/bash \
|
|
25
|
+
"${HOMEBREW_PREFIX:-}/bin/bash" \
|
|
26
|
+
"$(command -v bash 2>/dev/null || true)"; do
|
|
27
|
+
if [[ -n "$_newer_bash" && -x "$_newer_bash" ]] &&
|
|
28
|
+
"$_newer_bash" -c '((BASH_VERSINFO[0] >= 4))' 2>/dev/null; then
|
|
29
|
+
exec "$_newer_bash" "$0" "$@"
|
|
30
|
+
fi
|
|
31
|
+
done
|
|
32
|
+
echo "Error: 'dot theme rebuild' needs bash >= 4 (macOS ships bash 3.2)." >&2
|
|
33
|
+
echo " Install a newer bash and retry: brew install bash" >&2
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
15
37
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
38
|
EXTRACT_SCRIPT="$SCRIPT_DIR/extract-theme.py"
|
|
17
39
|
DOTFILES_DIR="${HOME}/.dotfiles"
|
|
18
40
|
|
|
19
|
-
# Descend into the chezmoi source subdir when .chezmoiroot is present (
|
|
41
|
+
# Descend into the chezmoi source subdir when .chezmoiroot is present (post-reorg, chezmoi files under defaults/)
|
|
20
42
|
CHEZMOI_SRC="$DOTFILES_DIR"
|
|
21
43
|
if [[ -f "$DOTFILES_DIR/.chezmoiroot" ]]; then
|
|
22
44
|
_sub="$(head -1 "$DOTFILES_DIR/.chezmoiroot" | tr -d '[:space:]')"
|
|
@@ -266,7 +288,7 @@ if [[ $TOTAL_WORK -gt 0 ]]; then
|
|
|
266
288
|
fi
|
|
267
289
|
) &
|
|
268
290
|
|
|
269
|
-
# Limit parallel jobs
|
|
291
|
+
# Limit parallel jobs (bash >= 4 guaranteed by the guard at the top).
|
|
270
292
|
while [[ $(jobs -r | wc -l) -ge $JOBS ]]; do
|
|
271
293
|
wait -n 2>/dev/null || true
|
|
272
294
|
done
|
package/scripts/theme/switch.sh
CHANGED
|
@@ -58,7 +58,7 @@ if [ -z "$SRC_DIR" ]; then
|
|
|
58
58
|
exit 1
|
|
59
59
|
fi
|
|
60
60
|
|
|
61
|
-
# Descend into the chezmoi source subdir when .chezmoiroot is present (
|
|
61
|
+
# Descend into the chezmoi source subdir when .chezmoiroot is present (post-reorg, chezmoi files under defaults/)
|
|
62
62
|
CHEZMOI_SRC="$SRC_DIR"
|
|
63
63
|
if [[ -f "$SRC_DIR/.chezmoiroot" ]]; then
|
|
64
64
|
_sub="$(head -1 "$SRC_DIR/.chezmoiroot" | tr -d '[:space:]')"
|
|
@@ -14,7 +14,7 @@ WALLPAPER_DIR="${DOTFILES_WALLPAPER_DIR:-$HOME/Pictures/Wallpapers}"
|
|
|
14
14
|
CHEZMOI_CFG="${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.toml"
|
|
15
15
|
|
|
16
16
|
# Resolve dotfiles repo root, then descend into chezmoi source subdir if
|
|
17
|
-
# .chezmoiroot is present (
|
|
17
|
+
# .chezmoiroot is present (where chezmoi files live in defaults/)
|
|
18
18
|
_DOTFILES_ROOT="${HOME}/.dotfiles"
|
|
19
19
|
[[ ! -d "$_DOTFILES_ROOT" && -d "${HOME}/.local/share/chezmoi" ]] && _DOTFILES_ROOT="${HOME}/.local/share/chezmoi"
|
|
20
20
|
_CHEZMOI_SRC="$_DOTFILES_ROOT"
|
package/scripts/version-sync.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
|
|
9
9
|
_cleanup_files=()
|
|
10
|
-
trap 'rm -f "${_cleanup_files[@]}"' EXIT
|
|
10
|
+
trap 'set +u; rm -f "${_cleanup_files[@]}" 2>/dev/null; set -u' EXIT
|
|
11
11
|
|
|
12
12
|
# Configuration
|
|
13
13
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
@@ -63,6 +63,17 @@ EXCLUDE_FILES=(
|
|
|
63
63
|
"docs/manual/05-appendices/D-bibliography.md"
|
|
64
64
|
"docs/operations/MAINTENANCE.md"
|
|
65
65
|
|
|
66
|
+
# Release-process / structural docs that reference *historical* dotfiles
|
|
67
|
+
# versions (the repo reorg, past release tags, migration scenarios).
|
|
68
|
+
# Bumping these each release would corrupt accurate history.
|
|
69
|
+
"docs/operations/RELEASE_PIPELINE.md"
|
|
70
|
+
"docs/operations/TESTING.md"
|
|
71
|
+
"docs/STRUCTURE.md"
|
|
72
|
+
"install/migrate/README.md"
|
|
73
|
+
"install/README.md"
|
|
74
|
+
"tools/README.md"
|
|
75
|
+
"defaults/README.md"
|
|
76
|
+
|
|
66
77
|
# CI_COMPOSITES.md cites third-party action versions (e.g. v5.0.5),
|
|
67
78
|
# not dotfiles_version. False-positive pattern match.
|
|
68
79
|
"docs/operations/CI_COMPOSITES.md"
|
|
@@ -154,9 +165,14 @@ find_version_files() {
|
|
|
154
165
|
|
|
155
166
|
log_info "Scanning for markdown files with version references..."
|
|
156
167
|
|
|
157
|
-
# Find all markdown files with version patterns
|
|
168
|
+
# Find all markdown files with version patterns.
|
|
169
|
+
# The "." path is required: with no path and a non-TTY stdin (CI, pipes,
|
|
170
|
+
# background jobs) rg reads from stdin instead of searching the tree, so
|
|
171
|
+
# the whole script hangs forever. The `sed` strips rg's leading "./" so
|
|
172
|
+
# the paths match the EXCLUDE_FILES entries (which have no "./"),
|
|
173
|
+
# otherwise excluded historical docs get rewritten.
|
|
158
174
|
cd "$PROJECT_ROOT"
|
|
159
|
-
rg -l "v?$VERSION_PATTERN" --type md
|
|
175
|
+
rg -l "v?$VERSION_PATTERN" --type md . 2>/dev/null | sed 's|^\./||' >"$temp_file" || true
|
|
160
176
|
|
|
161
177
|
# Add known files that should be checked even if they don't have versions yet
|
|
162
178
|
echo "README.md" >>"$temp_file"
|