@sebastienrousseau/dotfiles 0.2.510 → 0.2.512
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 +54 -0
- package/README.md +2 -2
- package/docs/AI.md +2 -1
- package/docs/COPYRIGHT +1 -1
- package/docs/architecture/AI_COST_OPTIMIZATION.md +1 -0
- package/docs/archive/LEGACY_ROADMAP.md +4 -158
- package/docs/articles/.pages +6 -0
- package/docs/articles/2026-07-05-custom-mkdocs-material-dark-theme.md +216 -0
- package/docs/articles/2026-07-05-fish-startup-abbr.md +153 -0
- package/docs/articles/2026-07-05-master-to-main-rename-runbook.md +128 -0
- package/docs/articles/index.md +36 -0
- package/docs/manual/00-introduction.md +1 -1
- package/docs/manual/02-tutorials/02-add-wallpaper.md +6 -6
- package/docs/manual/02-tutorials/03-create-profile.md +1 -1
- package/docs/manual/02-tutorials/05-deploy-fleet.md +1 -1
- package/docs/manual/03-reference/02-config-files.md +1 -1
- package/docs/manual/command-index.md +1 -0
- package/docs/operations/ARCHITECTURE_ROADMAP.md +5 -143
- package/docs/operations/COVERAGE.md +27 -4
- package/docs/operations/ROADMAP.md +3 -159
- package/docs/operations/ROADMAP_2026.md +5 -663
- package/docs/operations/ROADMAP_V0_2_503.md +5 -129
- package/docs/reference/THEMES.md +1 -1
- package/docs/reference/TOOLS.md +1 -0
- package/docs/reference/UTILS.md +1 -0
- package/install.sh +5 -5
- package/package.json +1 -1
- package/scripts/diagnostics/aliases-manifest.sh +52 -7
- package/scripts/diagnostics/benchmark.sh +27 -1
- package/scripts/diagnostics/doctor.sh +18 -11
- package/scripts/diagnostics/health.sh +8 -3
- package/scripts/diagnostics/mcp-doctor.sh +3 -0
- package/scripts/diagnostics/secret-governance.sh +7 -1
- package/scripts/diagnostics/security-score.sh +14 -5
- package/scripts/diagnostics/verify_state.sh +15 -3
- package/scripts/diagnostics/version-locks.sh +10 -6
- package/scripts/dot/commands/agent.sh +5 -1
- package/scripts/dot/commands/ai.sh +37 -30
- package/scripts/dot/commands/aliases.sh +28 -4
- package/scripts/dot/commands/appearance.sh +16 -0
- package/scripts/dot/commands/core.sh +17 -0
- package/scripts/dot/commands/diagnostics.sh +19 -0
- package/scripts/dot/commands/fleet.sh +4 -1
- package/scripts/dot/commands/manual.sh +4 -4
- package/scripts/dot/commands/meta.sh +87 -12
- package/scripts/dot/commands/registry.sh +8 -2
- package/scripts/dot/commands/secrets.sh +17 -0
- package/scripts/dot/commands/security.sh +17 -0
- package/scripts/dot/commands/tools.sh +30 -2
- package/scripts/git-hooks/pre-commit-audit.sh +1 -1
- package/scripts/ops/ai-setup.sh +13 -6
- package/scripts/ops/bundle.sh +31 -5
- package/scripts/ops/chezmoi-apply.sh +5 -0
- package/scripts/ops/release.sh +14 -5
- package/scripts/qa/docs-coverage.sh +1 -1
- package/scripts/qa/reliability-audit.sh +2 -2
- package/scripts/secrets/age-init.sh +15 -4
- package/scripts/theme/apply-gnome-theme.sh +6 -2
- package/scripts/theme/extract-theme.py +97 -33
- package/scripts/theme/rebuild-themes.sh +240 -35
- package/scripts/theme/switch.sh +26 -16
- package/scripts/theme/wallpaper-sync.sh +95 -7
- package/scripts/tools/detect-collisions.py +19 -1
- package/scripts/version-sync.sh +87 -43
package/scripts/theme/switch.sh
CHANGED
|
@@ -78,15 +78,33 @@ fi
|
|
|
78
78
|
# Theme Database
|
|
79
79
|
# =============================================================================
|
|
80
80
|
|
|
81
|
-
# Default preferences
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
# Default preferences (must be present keys in themes.toml — the theme
|
|
82
|
+
# regeneration removed the old macos-monterey-* names; bloom is the current
|
|
83
|
+
# default family and always ships a dark+light pair).
|
|
84
|
+
DEFAULT_DARK="bloom-dark"
|
|
85
|
+
DEFAULT_LIGHT="bloom-light"
|
|
86
|
+
|
|
87
|
+
# Machine-local chezmoi override (chezmoi.toml [data] theme) takes precedence
|
|
88
|
+
# over .chezmoidata.toml when rendering, so it is the authoritative "current"
|
|
89
|
+
# value. Kept in sync by dot-theme-sync's write_theme().
|
|
90
|
+
CHEZMOI_CFG="${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.toml"
|
|
84
91
|
|
|
85
92
|
# =============================================================================
|
|
86
93
|
# Theme Functions
|
|
87
94
|
# =============================================================================
|
|
88
95
|
|
|
89
96
|
current_theme() {
|
|
97
|
+
# Prefer the machine-local override (what chezmoi actually renders), so
|
|
98
|
+
# `dot theme current` never disagrees with the deployed configs. Fall back
|
|
99
|
+
# to the repo default in .chezmoidata.toml when no override is set.
|
|
100
|
+
if [[ -f "$CHEZMOI_CFG" ]]; then
|
|
101
|
+
local override
|
|
102
|
+
override="$(awk -F'"' '/^theme =/ {print $2}' "$CHEZMOI_CFG" | head -n 1)"
|
|
103
|
+
if [[ -n "$override" ]]; then
|
|
104
|
+
echo "$override"
|
|
105
|
+
return 0
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
90
108
|
awk -F'"' '/^theme =/ {print $2}' "$DATA_FILE" | head -n 1
|
|
91
109
|
}
|
|
92
110
|
|
|
@@ -124,6 +142,9 @@ paired_families() {
|
|
|
124
142
|
done < <(all_theme_names)
|
|
125
143
|
|
|
126
144
|
for family in $(printf '%s\n' "${!has_dark[@]}" | sort); do
|
|
145
|
+
# `fallback` is a synthetic safety theme (see themes.toml) that templates
|
|
146
|
+
# degrade to when .theme is unset/invalid — never a user-selectable one.
|
|
147
|
+
[[ "$family" == "fallback" ]] && continue
|
|
127
148
|
[[ -n "${has_light[$family]+x}" ]] && echo "$family"
|
|
128
149
|
done
|
|
129
150
|
}
|
|
@@ -185,12 +206,6 @@ set_theme() {
|
|
|
185
206
|
|
|
186
207
|
# Interactive theme picker
|
|
187
208
|
pick_theme() {
|
|
188
|
-
if ! command -v fzf &>/dev/null; then
|
|
189
|
-
ui_err "fzf" "required for interactive picker"
|
|
190
|
-
ui_info "Usage" "dot theme set <name>"
|
|
191
|
-
exit 1
|
|
192
|
-
fi
|
|
193
|
-
|
|
194
209
|
local current
|
|
195
210
|
current="$(current_theme)"
|
|
196
211
|
|
|
@@ -220,14 +235,9 @@ pick_theme() {
|
|
|
220
235
|
done < <(paired_families)
|
|
221
236
|
|
|
222
237
|
local selected_family
|
|
223
|
-
selected_family="$(
|
|
238
|
+
selected_family="$(printf '%s' "$theme_list" | ui_pick \
|
|
224
239
|
--header "Select wallpaper theme (current: $current_family [$current_mode])" \
|
|
225
|
-
--prompt "Theme >
|
|
226
|
-
--height 30 \
|
|
227
|
-
--reverse \
|
|
228
|
-
--no-sort \
|
|
229
|
-
--no-preview \
|
|
230
|
-
--ansi |
|
|
240
|
+
--prompt "Theme >" |
|
|
231
241
|
awk '$1 !~ /^#/ && NF >= 2 {print $2}')" || return 0
|
|
232
242
|
|
|
233
243
|
if [[ -n "$selected_family" ]]; then
|
|
@@ -43,6 +43,16 @@ detect_mode() {
|
|
|
43
43
|
esac
|
|
44
44
|
fi
|
|
45
45
|
|
|
46
|
+
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
47
|
+
# AppleInterfaceStyle is "Dark" in dark mode and unset in light mode.
|
|
48
|
+
if [[ "$(defaults read -g AppleInterfaceStyle 2>/dev/null || true)" == "Dark" ]]; then
|
|
49
|
+
echo "dark"
|
|
50
|
+
else
|
|
51
|
+
echo "light"
|
|
52
|
+
fi
|
|
53
|
+
return 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
46
56
|
if command -v gsettings &>/dev/null; then
|
|
47
57
|
local scheme
|
|
48
58
|
scheme="$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null || echo "")"
|
|
@@ -125,10 +135,16 @@ wallpaper_for_theme() {
|
|
|
125
135
|
found && /^wallpaper/ { sub(/.*= *"/, ""); sub(/".*/, ""); print; exit }
|
|
126
136
|
' "$themes_file")"
|
|
127
137
|
if [[ -n "$stored_wp" ]]; then
|
|
128
|
-
#
|
|
138
|
+
# Home-relative form (current generator): ~/Pictures/... → $HOME/Pictures/...
|
|
139
|
+
# Prefix-strip comparison avoids a quoted-tilde glob (SC2088); the tilde
|
|
140
|
+
# here is a literal leading character, not a path to expand.
|
|
141
|
+
if [[ "$stored_wp" != "${stored_wp#\~/}" ]]; then
|
|
142
|
+
stored_wp="${HOME}/${stored_wp#\~/}"
|
|
143
|
+
fi
|
|
144
|
+
# Cross-platform: resolve legacy absolute macOS paths on Linux
|
|
129
145
|
if [[ ! -f "$stored_wp" ]]; then
|
|
130
146
|
if [[ "$stored_wp" == /Users/* ]]; then
|
|
131
|
-
# /Users/<user>/Pictures/... → $HOME/Pictures/...
|
|
147
|
+
# /Users/<user>/Pictures/... → $HOME/Pictures/... (pre-relativize data)
|
|
132
148
|
stored_wp="${HOME}/${stored_wp#/Users/*/}"
|
|
133
149
|
elif [[ "$stored_wp" == /System/* ]]; then
|
|
134
150
|
# macOS system wallpapers don't exist on Linux — skip to next fallback
|
|
@@ -397,6 +413,56 @@ ensure_linux_compatible() {
|
|
|
397
413
|
printf '%s\n' "$wp"
|
|
398
414
|
}
|
|
399
415
|
|
|
416
|
+
# macOS: a dynamic appearance HEIC (two frames + apple_desktop:apr metadata)
|
|
417
|
+
# set as a plain imageFile gets pinned to a single frame and stops tracking
|
|
418
|
+
# Light/Dark — so Light mode can show the dark frame. Extract the frame that
|
|
419
|
+
# matches the requested mode (0 = light, 1 = dark, per Apple's apr convention,
|
|
420
|
+
# same as the Linux -0/-1 path) to a small single-image HEIC and apply that
|
|
421
|
+
# instead. Single-image HEICs and non-HEICs are returned unchanged.
|
|
422
|
+
macos_appearance_frame() {
|
|
423
|
+
local wp="$1" mode="$2"
|
|
424
|
+
[[ "${wp##*.}" == "heic" ]] || {
|
|
425
|
+
printf '%s\n' "$wp"
|
|
426
|
+
return
|
|
427
|
+
}
|
|
428
|
+
command -v magick &>/dev/null || {
|
|
429
|
+
printf '%s\n' "$wp"
|
|
430
|
+
return
|
|
431
|
+
}
|
|
432
|
+
local frames
|
|
433
|
+
frames="$(magick identify "$wp" 2>/dev/null | wc -l | tr -d ' ')"
|
|
434
|
+
[[ "${frames:-0}" -ge 2 ]] || {
|
|
435
|
+
printf '%s\n' "$wp"
|
|
436
|
+
return
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
local idx=0
|
|
440
|
+
[[ "$mode" == "dark" ]] && idx=1
|
|
441
|
+
local cache_dir="$WALLPAPER_DIR/.dot-frames"
|
|
442
|
+
mkdir -p "$cache_dir" 2>/dev/null || {
|
|
443
|
+
printf '%s\n' "$wp"
|
|
444
|
+
return
|
|
445
|
+
}
|
|
446
|
+
local frame
|
|
447
|
+
frame="$cache_dir/$(basename "${wp%.heic}")-${mode}.heic"
|
|
448
|
+
|
|
449
|
+
# Reuse a cached frame that is newer than its source wallpaper.
|
|
450
|
+
if [[ -f "$frame" && "$frame" -nt "$wp" ]]; then
|
|
451
|
+
printf '%s\n' "$frame"
|
|
452
|
+
return
|
|
453
|
+
fi
|
|
454
|
+
local tmp
|
|
455
|
+
tmp="$(mktemp "${frame%.heic}.XXXXXX.heic")"
|
|
456
|
+
if magick "${wp}[${idx}]" "$tmp" 2>/dev/null && [[ -s "$tmp" ]]; then
|
|
457
|
+
if mv -f "$tmp" "$frame" 2>/dev/null; then
|
|
458
|
+
printf '%s\n' "$frame"
|
|
459
|
+
return
|
|
460
|
+
fi
|
|
461
|
+
fi
|
|
462
|
+
rm -f "$tmp" 2>/dev/null
|
|
463
|
+
printf '%s\n' "$wp"
|
|
464
|
+
}
|
|
465
|
+
|
|
400
466
|
# Apply wallpaper based on platform and compositor
|
|
401
467
|
apply_wallpaper() {
|
|
402
468
|
local wp="$1"
|
|
@@ -408,6 +474,10 @@ apply_wallpaper() {
|
|
|
408
474
|
|
|
409
475
|
case "$(uname -s)" in
|
|
410
476
|
Darwin)
|
|
477
|
+
# Resolve a dynamic HEIC down to the mode-appropriate static frame so
|
|
478
|
+
# macOS renders the right appearance instead of pinning one frame.
|
|
479
|
+
wp="$(macos_appearance_frame "$wp" "$mode")"
|
|
480
|
+
|
|
411
481
|
# macOS Sonoma+ moved wallpaper state to ~/Library/Application Support/
|
|
412
482
|
# com.apple.wallpaper/Store/Index.plist, owned by WallpaperAgent. Each
|
|
413
483
|
# Space and Display has its own entry, and AppleScript's `every desktop`
|
|
@@ -494,12 +564,29 @@ if updated:
|
|
|
494
564
|
print(updated)
|
|
495
565
|
PYEOF
|
|
496
566
|
|
|
497
|
-
# Restart WallpaperAgent so it re-reads the store
|
|
498
|
-
|
|
567
|
+
# Restart WallpaperAgent so it re-reads the store and repaints EVERY
|
|
568
|
+
# Space (the store rewrite above covers all Spaces; the agent only
|
|
569
|
+
# applies it on respawn). Then BLOCK until it's actually back and the
|
|
570
|
+
# wallpaper has re-applied — the caller reports "Done" once this returns,
|
|
571
|
+
# so it must not return while Spaces are still repainting. Set
|
|
572
|
+
# DOT_THEME_SKIP_WALLPAPER_AGENT=1 to skip the restart (faster, but
|
|
573
|
+
# background Spaces won't refresh until next login).
|
|
574
|
+
if [[ "${DOT_THEME_SKIP_WALLPAPER_AGENT:-0}" != "1" ]]; then
|
|
575
|
+
killall WallpaperAgent 2>/dev/null || true
|
|
576
|
+
|
|
577
|
+
# Wait for launchd to bring WallpaperAgent back (KeepAlive respawns it
|
|
578
|
+
# within ~1s; cap the wait so a theme switch can never hang).
|
|
579
|
+
local _waited=0
|
|
580
|
+
while ! pgrep -x WallpaperAgent >/dev/null 2>&1; do
|
|
581
|
+
sleep 0.1
|
|
582
|
+
_waited=$((_waited + 1))
|
|
583
|
+
[[ "$_waited" -ge 60 ]] && break
|
|
584
|
+
done
|
|
585
|
+
fi
|
|
499
586
|
|
|
500
|
-
#
|
|
501
|
-
#
|
|
502
|
-
#
|
|
587
|
+
# Re-assert the wallpaper through the (now running) agent — covers the
|
|
588
|
+
# active Space's first paint and any screen the store rewrite missed —
|
|
589
|
+
# then give that paint a moment to finish before returning.
|
|
503
590
|
if command -v wallpaper &>/dev/null; then
|
|
504
591
|
wallpaper set "$wp" --screen all 2>/dev/null || true
|
|
505
592
|
else
|
|
@@ -511,6 +598,7 @@ tell application \"System Events\"
|
|
|
511
598
|
end repeat
|
|
512
599
|
end tell" 2>/dev/null || true
|
|
513
600
|
fi
|
|
601
|
+
sleep 0.5
|
|
514
602
|
;;
|
|
515
603
|
Linux)
|
|
516
604
|
# DMS owns wallpaper display and runs matugen for color extraction.
|
|
@@ -8,7 +8,25 @@ import os
|
|
|
8
8
|
import re
|
|
9
9
|
import sys
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# Post-Phase-4b (v0.2.503): chezmoi source is under the subdir
|
|
12
|
+
# named in .chezmoiroot (typically "defaults/"). Prefer the
|
|
13
|
+
# descended path; fall back to the old top-level layout for
|
|
14
|
+
# backwards compatibility.
|
|
15
|
+
_DOTFILES_ROOT = os.path.expanduser("~/.dotfiles")
|
|
16
|
+
_CHEZMOIROOT_FILE = os.path.join(_DOTFILES_ROOT, ".chezmoiroot")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _resolve_chezmoi_root() -> str:
|
|
20
|
+
if os.path.isfile(_CHEZMOIROOT_FILE):
|
|
21
|
+
with open(_CHEZMOIROOT_FILE, "r", encoding="utf-8") as _f:
|
|
22
|
+
sub = _f.read().strip()
|
|
23
|
+
cand = os.path.join(_DOTFILES_ROOT, sub)
|
|
24
|
+
if os.path.isdir(cand):
|
|
25
|
+
return cand
|
|
26
|
+
return _DOTFILES_ROOT
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
BASE_DIR = os.path.join(_resolve_chezmoi_root(), ".chezmoitemplates")
|
|
12
30
|
ALIASES_DIR = os.path.join(BASE_DIR, "aliases")
|
|
13
31
|
FUNCTIONS_DIR = os.path.join(BASE_DIR, "functions")
|
|
14
32
|
|
package/scripts/version-sync.sh
CHANGED
|
@@ -84,6 +84,13 @@ EXCLUDE_FILES=(
|
|
|
84
84
|
# that are NOT the current dotfiles_version. Auto-syncing
|
|
85
85
|
# rewrites them incorrectly.
|
|
86
86
|
"docs/operations/ARCHITECTURE_ROADMAP.md"
|
|
87
|
+
|
|
88
|
+
# Dated release write-ups: each article records the release it
|
|
89
|
+
# shipped in (e.g. "shipped in vX.Y.Z" + a link to that release
|
|
90
|
+
# tag). Those refs are historical fact, not current-version claims —
|
|
91
|
+
# bumping them would falsify the history.
|
|
92
|
+
"docs/articles/2026-07-05-fish-startup-abbr.md"
|
|
93
|
+
"docs/articles/2026-07-05-master-to-main-rename-runbook.md"
|
|
87
94
|
)
|
|
88
95
|
|
|
89
96
|
# shellcheck source=../lib/dot/ui.sh
|
|
@@ -149,7 +156,11 @@ get_package_version() {
|
|
|
149
156
|
fi
|
|
150
157
|
|
|
151
158
|
local version
|
|
152
|
-
|
|
159
|
+
if command -v jq &>/dev/null; then
|
|
160
|
+
version=$(jq -r '.version' "$package_file" 2>/dev/null)
|
|
161
|
+
else
|
|
162
|
+
version=$(sed -nE 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' "$package_file" | head -n 1)
|
|
163
|
+
fi
|
|
153
164
|
if [[ "$version" == "null" || -z "$version" ]]; then
|
|
154
165
|
log_error "Could not extract version from package.json"
|
|
155
166
|
exit 1
|
|
@@ -179,22 +190,32 @@ find_version_files() {
|
|
|
179
190
|
# the paths match the EXCLUDE_FILES entries (which have no "./"),
|
|
180
191
|
# otherwise excluded historical docs get rewritten.
|
|
181
192
|
cd "$PROJECT_ROOT"
|
|
182
|
-
|
|
193
|
+
if command -v rg &>/dev/null; then
|
|
194
|
+
rg -l "v?$VERSION_PATTERN" --type md . 2>/dev/null | sed 's|^\./||' >"$temp_file" || true
|
|
195
|
+
else
|
|
196
|
+
{
|
|
197
|
+
while IFS= read -r file; do
|
|
198
|
+
if grep -Eq "v?$VERSION_PATTERN" "$file" 2>/dev/null; then
|
|
199
|
+
printf '%s\n' "${file#./}"
|
|
200
|
+
fi
|
|
201
|
+
done < <(find . -type f -name '*.md' -print)
|
|
202
|
+
} >"$temp_file"
|
|
203
|
+
fi
|
|
183
204
|
|
|
184
205
|
# Add known files that should be checked even if they don't have versions yet
|
|
185
|
-
echo "README.md" >>"$temp_file"
|
|
186
|
-
echo "docs/reference/FEATURES.md" >>"$temp_file"
|
|
187
|
-
echo "docs/COPYRIGHT" >>"$temp_file"
|
|
188
|
-
|
|
189
206
|
# Non-markdown and hidden-directory surfaces rg's `--type md` scan above
|
|
190
207
|
# cannot reach: a shell script, and READMEs under the dotfile-hidden
|
|
191
208
|
# `.chezmoitemplates/` tree (rg skips dot-dirs without --hidden). These
|
|
192
209
|
# carry "current version" stamps that check-version-consistency.sh and
|
|
193
210
|
# the test_version_consistency unit test enforce, so keep them in sync.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
211
|
+
printf '%s\n' \
|
|
212
|
+
"README.md" \
|
|
213
|
+
"docs/reference/FEATURES.md" \
|
|
214
|
+
"docs/COPYRIGHT" \
|
|
215
|
+
"scripts/git-hooks/pre-commit-audit.sh" \
|
|
216
|
+
"defaults/.chezmoitemplates/README.md" \
|
|
217
|
+
"defaults/.chezmoitemplates/functions/README.md" \
|
|
218
|
+
"defaults/.chezmoitemplates/aliases/README.md" >>"$temp_file"
|
|
198
219
|
|
|
199
220
|
# Remove duplicates and filter existing files
|
|
200
221
|
sort -u "$temp_file" | while IFS= read -r file; do
|
|
@@ -261,6 +282,7 @@ update_version_references() {
|
|
|
261
282
|
log_warning "File not found: $file"
|
|
262
283
|
continue
|
|
263
284
|
fi
|
|
285
|
+
files_processed=$((files_processed + 1))
|
|
264
286
|
|
|
265
287
|
# Skip milestone and other historical files
|
|
266
288
|
if [[ "$(basename "$file")" == MILESTONE_* ]]; then
|
|
@@ -321,6 +343,7 @@ update_version_references() {
|
|
|
321
343
|
cat "$temp_file" >"$file"
|
|
322
344
|
log_success "Updated: $file"
|
|
323
345
|
fi
|
|
346
|
+
rm -f "$temp_file"
|
|
324
347
|
changes_made=$((changes_made + 1))
|
|
325
348
|
else
|
|
326
349
|
log_info "No changes needed: $file"
|
|
@@ -360,26 +383,49 @@ verify_version_consistency() {
|
|
|
360
383
|
|
|
361
384
|
# Extract only dotfiles-targeted version references (ignore unrelated tool versions).
|
|
362
385
|
local versions_in_file=()
|
|
363
|
-
|
|
364
|
-
while IFS= read -r
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
386
|
+
if command -v rg &>/dev/null; then
|
|
387
|
+
while IFS= read -r match; do
|
|
388
|
+
while IFS= read -r version; do
|
|
389
|
+
versions_in_file+=("$version")
|
|
390
|
+
done < <(printf "%s\n" "$match" | rg -o "v?$VERSION_PATTERN" || true)
|
|
391
|
+
done < <(
|
|
392
|
+
rg -v "MILESTONE" "$file" 2>/dev/null | rg -o \
|
|
393
|
+
-e "Version-v$VERSION_PATTERN" \
|
|
394
|
+
-e "/releases/tag/v$VERSION_PATTERN" \
|
|
395
|
+
-e "/dotfiles/v$VERSION_PATTERN/" \
|
|
396
|
+
-e "\\*\\*Version\\*\\*:[[:space:]]*v?$VERSION_PATTERN" \
|
|
397
|
+
-e "\\*\\*Dotfiles Version\\*\\*:[[:space:]]*v?$VERSION_PATTERN" \
|
|
398
|
+
-e "(^|[[:space:]])Version:[[:space:]]*v?$VERSION_PATTERN" \
|
|
399
|
+
-e "(^|[[:space:]])Dotfiles Version:[[:space:]]*v?$VERSION_PATTERN" \
|
|
400
|
+
-e "Version[[:space:]]*\`v?$VERSION_PATTERN\`" \
|
|
401
|
+
-e "\\(v$VERSION_PATTERN\\)" \
|
|
402
|
+
-e "/v$VERSION_PATTERN/" \
|
|
403
|
+
-e "v$VERSION_PATTERN\\b" \
|
|
404
|
+
-e "dotfiles:v?$VERSION_PATTERN" \
|
|
405
|
+
-e "notes — v$VERSION_PATTERN" || true
|
|
406
|
+
)
|
|
407
|
+
else
|
|
408
|
+
while IFS= read -r match; do
|
|
409
|
+
while IFS= read -r version; do
|
|
410
|
+
versions_in_file+=("$version")
|
|
411
|
+
done < <(printf "%s\n" "$match" | grep -Eo "v?$VERSION_PATTERN" || true)
|
|
412
|
+
done < <(
|
|
413
|
+
grep -Ev "MILESTONE" "$file" 2>/dev/null | grep -Eo \
|
|
414
|
+
-e "Version-v$VERSION_PATTERN" \
|
|
415
|
+
-e "/releases/tag/v$VERSION_PATTERN" \
|
|
416
|
+
-e "/dotfiles/v$VERSION_PATTERN/" \
|
|
417
|
+
-e "\\*\\*Version\\*\\*:[[:space:]]*v?$VERSION_PATTERN" \
|
|
418
|
+
-e "\\*\\*Dotfiles Version\\*\\*:[[:space:]]*v?$VERSION_PATTERN" \
|
|
419
|
+
-e "(^|[[:space:]])Version:[[:space:]]*v?$VERSION_PATTERN" \
|
|
420
|
+
-e "(^|[[:space:]])Dotfiles Version:[[:space:]]*v?$VERSION_PATTERN" \
|
|
421
|
+
-e "Version[[:space:]]*\`v?$VERSION_PATTERN\`" \
|
|
422
|
+
-e "\\(v$VERSION_PATTERN\\)" \
|
|
423
|
+
-e "/v$VERSION_PATTERN/" \
|
|
424
|
+
-e "v$VERSION_PATTERN([^0-9.]|$)" \
|
|
425
|
+
-e "dotfiles:v?$VERSION_PATTERN" \
|
|
426
|
+
-e "notes — v$VERSION_PATTERN" || true
|
|
427
|
+
)
|
|
428
|
+
fi
|
|
383
429
|
|
|
384
430
|
if [[ ${#versions_in_file[@]} -eq 0 ]]; then
|
|
385
431
|
continue
|
|
@@ -450,6 +496,12 @@ main() {
|
|
|
450
496
|
esac
|
|
451
497
|
done
|
|
452
498
|
|
|
499
|
+
if [[ -n "${DOTFILES_COV_TMPDIR:-}" && "${DOTFILES_ALLOW_COVERAGE_WRITES:-0}" != "1" ]]; then
|
|
500
|
+
dry_run="true"
|
|
501
|
+
create_backup_flag="false"
|
|
502
|
+
log_info "Coverage sandbox detected; forcing --dry-run"
|
|
503
|
+
fi
|
|
504
|
+
|
|
453
505
|
# Change to project root
|
|
454
506
|
cd "$PROJECT_ROOT"
|
|
455
507
|
|
|
@@ -463,8 +515,11 @@ main() {
|
|
|
463
515
|
fi
|
|
464
516
|
|
|
465
517
|
# Find files with version references
|
|
466
|
-
local version_files
|
|
467
|
-
|
|
518
|
+
local version_files=()
|
|
519
|
+
local version_file
|
|
520
|
+
while IFS= read -r version_file; do
|
|
521
|
+
version_files+=("$version_file")
|
|
522
|
+
done < <(find_version_files)
|
|
468
523
|
|
|
469
524
|
if [[ ${#version_files[@]} -eq 0 ]]; then
|
|
470
525
|
log_warning "No files with version references found"
|
|
@@ -567,16 +622,5 @@ EOF
|
|
|
567
622
|
fi
|
|
568
623
|
}
|
|
569
624
|
|
|
570
|
-
# Ensure we have required tools
|
|
571
|
-
if ! command -v jq &>/dev/null; then
|
|
572
|
-
log_warning "jq is not installed — skipping version sync"
|
|
573
|
-
exit 0
|
|
574
|
-
fi
|
|
575
|
-
|
|
576
|
-
if ! command -v rg &>/dev/null; then
|
|
577
|
-
log_warning "ripgrep (rg) is not installed — skipping version sync"
|
|
578
|
-
exit 0
|
|
579
|
-
fi
|
|
580
|
-
|
|
581
625
|
# Run main function
|
|
582
626
|
main "$@"
|