@sebastienrousseau/dotfiles 0.2.520 → 0.2.521

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.
Files changed (323) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE-APACHE +190 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +43 -37
  5. package/install.sh +76 -10
  6. package/package.json +7 -7
  7. package/tools/README.md +49 -0
  8. package/tools/ci/install-chezmoi-verified.sh +68 -0
  9. package/docs/.vitepress/reports/localization-readability-audit.md +0 -73
  10. package/docs/AI.md +0 -179
  11. package/docs/ARCHITECTURE.md +0 -117
  12. package/docs/CNAME +0 -1
  13. package/docs/CONFIG_STRATEGY.md +0 -124
  14. package/docs/COPYRIGHT +0 -7
  15. package/docs/ECOSYSTEM.md +0 -220
  16. package/docs/GOLD-STANDARD-AUDIT.md +0 -352
  17. package/docs/GOVERNANCE.md +0 -98
  18. package/docs/MAINTAINERS.md +0 -41
  19. package/docs/MINIMUM-TOOLCHAIN.md +0 -100
  20. package/docs/NAMING_CONVENTIONS.md +0 -102
  21. package/docs/OPENCODE.md +0 -127
  22. package/docs/README.md +0 -84
  23. package/docs/STRUCTURE.md +0 -102
  24. package/docs/adr/ADR-001-ci-cd-pipeline.md +0 -118
  25. package/docs/adr/ADR-002-shell-performance.md +0 -130
  26. package/docs/adr/ADR-003-security-first.md +0 -158
  27. package/docs/adr/ADR-004-cli-architecture.md +0 -171
  28. package/docs/adr/ADR-005-chezmoi-choice.md +0 -99
  29. package/docs/adr/ADR-006-shell-selection.md +0 -124
  30. package/docs/adr/ADR-007-multi-shell-parity.md +0 -62
  31. package/docs/adr/ADR-008-alias-system-architecture.md +0 -95
  32. package/docs/adr/ADR-009-wallpaper-driven-theming.md +0 -131
  33. package/docs/adr/ADR-010-starship-transient-prompt.md +0 -144
  34. package/docs/adr/ADR-011-nushell-tier3-keep.md +0 -144
  35. package/docs/adr/ADR-012-ai-fleet-local-proxy.md +0 -79
  36. package/docs/adr/README.md +0 -40
  37. package/docs/architecture/AI_COST_OPTIMIZATION.md +0 -144
  38. package/docs/architecture/ARCHITECTURE.md +0 -20
  39. package/docs/architecture/INTEROP.md +0 -44
  40. package/docs/architecture/REPO_LAYOUT.md +0 -241
  41. package/docs/architecture/WALKTHROUGH.md +0 -86
  42. package/docs/architecture/fleet-deployment.md +0 -77
  43. package/docs/archive/EUXIS_2026_REVIEW.md +0 -127
  44. package/docs/archive/LEGACY_ROADMAP.md +0 -6
  45. package/docs/archive/MILESTONE_v0.2.493.md +0 -47
  46. package/docs/archive/PLAN.md +0 -199
  47. package/docs/archive/REPO_AUDIT.md +0 -31
  48. package/docs/articles/.pages +0 -6
  49. package/docs/articles/2026-07-05-custom-mkdocs-material-dark-theme.md +0 -216
  50. package/docs/articles/2026-07-05-fish-startup-abbr.md +0 -153
  51. package/docs/articles/2026-07-05-master-to-main-rename-runbook.md +0 -128
  52. package/docs/articles/index.md +0 -36
  53. package/docs/guides/INSTALL.md +0 -144
  54. package/docs/guides/MACOS_ICLOUD_SYMLINKS.md +0 -121
  55. package/docs/guides/NEOVIM_IDE_GUIDE.md +0 -61
  56. package/docs/guides/THEMING.md +0 -230
  57. package/docs/guides/TROUBLESHOOTING.md +0 -176
  58. package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +0 -792
  59. package/docs/index.md +0 -132
  60. package/docs/interop/A2A.md +0 -39
  61. package/docs/interop/POWERSHELL.md +0 -102
  62. package/docs/manual/00-introduction.md +0 -89
  63. package/docs/manual/01-concepts/01-architecture.md +0 -138
  64. package/docs/manual/01-concepts/02-trust-model.md +0 -183
  65. package/docs/manual/01-concepts/03-theme-engine.md +0 -186
  66. package/docs/manual/01-concepts/04-fleet.md +0 -148
  67. package/docs/manual/01-concepts/05-self-healing.md +0 -204
  68. package/docs/manual/02-tutorials/01-first-install.md +0 -197
  69. package/docs/manual/02-tutorials/02-add-wallpaper.md +0 -216
  70. package/docs/manual/02-tutorials/03-create-profile.md +0 -244
  71. package/docs/manual/02-tutorials/04-encrypt-secret.md +0 -281
  72. package/docs/manual/02-tutorials/05-deploy-fleet.md +0 -283
  73. package/docs/manual/03-reference/01-dot-cli.md +0 -475
  74. package/docs/manual/03-reference/02-config-files.md +0 -265
  75. package/docs/manual/03-reference/03-environment.md +0 -124
  76. package/docs/manual/03-reference/04-templates.md +0 -190
  77. package/docs/manual/03-reference/05-feature-flags.md +0 -187
  78. package/docs/manual/04-cookbook/01-recipes.md +0 -285
  79. package/docs/manual/04-cookbook/02-troubleshooting.md +0 -351
  80. package/docs/manual/04-cookbook/03-faq.md +0 -175
  81. package/docs/manual/05-appendices/A-platform-matrix.md +0 -101
  82. package/docs/manual/05-appendices/B-security-checklist.md +0 -85
  83. package/docs/manual/05-appendices/C-glossary.md +0 -40
  84. package/docs/manual/05-appendices/D-bibliography.md +0 -58
  85. package/docs/manual/05-appendices/E-license.md +0 -38
  86. package/docs/manual/_toc.yml +0 -58
  87. package/docs/manual/command-index.md +0 -175
  88. package/docs/manual/concept-index.md +0 -170
  89. package/docs/manual/index.md +0 -66
  90. package/docs/migration/README.md +0 -81
  91. package/docs/migration/from-bare-git-repo.md +0 -156
  92. package/docs/migration/from-gnu-stow.md +0 -165
  93. package/docs/migration/from-plain-chezmoi.md +0 -148
  94. package/docs/migration/from-yadm.md +0 -187
  95. package/docs/operations/ARCHITECTURE_ROADMAP.md +0 -7
  96. package/docs/operations/ATTESTATION.md +0 -44
  97. package/docs/operations/CI_CADENCE.md +0 -107
  98. package/docs/operations/CI_COMPOSITES.md +0 -156
  99. package/docs/operations/COMPLETIONS.md +0 -123
  100. package/docs/operations/COVERAGE.md +0 -204
  101. package/docs/operations/DRIFT.md +0 -107
  102. package/docs/operations/HARD_AUDIT_2026.md +0 -631
  103. package/docs/operations/MAINTENANCE.md +0 -63
  104. package/docs/operations/MANIFEST.md +0 -127
  105. package/docs/operations/MIGRATION.md +0 -109
  106. package/docs/operations/OPERATIONS.md +0 -188
  107. package/docs/operations/PERFORMANCE.md +0 -133
  108. package/docs/operations/PERFORMANCE_BUDGETS.md +0 -196
  109. package/docs/operations/REGISTRY.md +0 -90
  110. package/docs/operations/RELEASE_PIPELINE.md +0 -128
  111. package/docs/operations/RELIABILITY.md +0 -122
  112. package/docs/operations/RFC_v0_2_503_reorganization.md +0 -280
  113. package/docs/operations/ROADMAP.md +0 -10
  114. package/docs/operations/ROADMAP_2026.md +0 -7
  115. package/docs/operations/ROADMAP_V0_2_503.md +0 -10
  116. package/docs/operations/TESTING.md +0 -216
  117. package/docs/operations/TRACEABILITY.md +0 -44
  118. package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +0 -65
  119. package/docs/operations/VERSION_SYNC.md +0 -393
  120. package/docs/packaging.md +0 -222
  121. package/docs/reference/ALIASES.md +0 -131
  122. package/docs/reference/ALIASES_CHEATSHEET.md +0 -32
  123. package/docs/reference/ALIASES_DEPRECATIONS.md +0 -13
  124. package/docs/reference/FEATURE-MATRIX.md +0 -646
  125. package/docs/reference/FEATURES.md +0 -66
  126. package/docs/reference/FONTS.md +0 -112
  127. package/docs/reference/POWERSHELL_PARITY.md +0 -82
  128. package/docs/reference/PROFILES.md +0 -69
  129. package/docs/reference/SCREENSHOTS.md +0 -121
  130. package/docs/reference/SCRIPTS.md +0 -71
  131. package/docs/reference/SUPPORT_MATRIX.md +0 -80
  132. package/docs/reference/THEMES.md +0 -117
  133. package/docs/reference/TOOLS.md +0 -110
  134. package/docs/reference/UTILS.md +0 -243
  135. package/docs/registry.json +0 -6
  136. package/docs/schema/dot-env-v1.json +0 -110
  137. package/docs/schema/dot-registry-v1.json +0 -33
  138. package/docs/security/AI_ACT_COMPLIANCE.md +0 -94
  139. package/docs/security/AUDIT_BYPASS.md +0 -103
  140. package/docs/security/AUTOMATION_SECRETS.md +0 -26
  141. package/docs/security/CI_EGRESS_ALLOWLIST.md +0 -127
  142. package/docs/security/CI_PINNING.md +0 -129
  143. package/docs/security/COMMIT_SIGNING.md +0 -138
  144. package/docs/security/COMPLIANCE.md +0 -458
  145. package/docs/security/DEPS_DEV_EXCEPTIONS.md +0 -86
  146. package/docs/security/DISCLOSURE.md +0 -130
  147. package/docs/security/ENCRYPTION.md +0 -57
  148. package/docs/security/FMEA.md +0 -159
  149. package/docs/security/FUZZING.md +0 -209
  150. package/docs/security/HISTORY_FILTERING.md +0 -132
  151. package/docs/security/INCIDENT_RESPONSE.md +0 -579
  152. package/docs/security/INSTALL_VERIFICATION.md +0 -122
  153. package/docs/security/KEYS.md +0 -49
  154. package/docs/security/KEY_ROTATION.md +0 -303
  155. package/docs/security/MCP_POLICY.md +0 -78
  156. package/docs/security/POLICY_RELEASES.md +0 -37
  157. package/docs/security/README.md +0 -28
  158. package/docs/security/SCORECARD.md +0 -195
  159. package/docs/security/SECRETS.md +0 -158
  160. package/docs/security/SECURITY.md +0 -45
  161. package/docs/security/SECURITY_CHECKLIST.md +0 -55
  162. package/docs/security/SHELL_EXEMPTIONS.md +0 -145
  163. package/docs/security/SOUP_REGISTER.md +0 -36
  164. package/docs/security/THREAT_MODEL.md +0 -130
  165. package/docs/security/VERIFICATION_VALIDATION.md +0 -228
  166. package/docs/security/VERIFY_RELEASE.md +0 -201
  167. package/docs/security/security-pubkey.asc +0 -15
  168. package/docs/stylesheets/extra.css +0 -444
  169. package/docs/themes/README.md +0 -10
  170. package/docs/themes/VISUAL_INTEGRITY_REPORT.md +0 -30
  171. package/docs/themes/hero-shot.svg +0 -78
  172. package/scripts/README.md +0 -123
  173. package/scripts/ci/check-copyright-headers.sh +0 -8
  174. package/scripts/ci/check-shell-preamble.sh +0 -8
  175. package/scripts/ci/guard-gitleaks-checkout.sh +0 -8
  176. package/scripts/demo/record.sh +0 -43
  177. package/scripts/diagnostics/a2a-conformance.sh +0 -163
  178. package/scripts/diagnostics/alias-governance.sh +0 -165
  179. package/scripts/diagnostics/aliases-cheatsheet.sh +0 -74
  180. package/scripts/diagnostics/aliases-manifest.sh +0 -77
  181. package/scripts/diagnostics/attest-verify.sh +0 -147
  182. package/scripts/diagnostics/benchmark.sh +0 -408
  183. package/scripts/diagnostics/conflicts.sh +0 -73
  184. package/scripts/diagnostics/doctor-unified.sh +0 -43
  185. package/scripts/diagnostics/doctor.sh +0 -797
  186. package/scripts/diagnostics/drift-dashboard.sh +0 -203
  187. package/scripts/diagnostics/health.sh +0 -656
  188. package/scripts/diagnostics/history-analysis.sh +0 -86
  189. package/scripts/diagnostics/mcp-doctor.sh +0 -582
  190. package/scripts/diagnostics/perf.sh +0 -453
  191. package/scripts/diagnostics/scorecard.sh +0 -120
  192. package/scripts/diagnostics/secret-governance.sh +0 -65
  193. package/scripts/diagnostics/security-score.sh +0 -467
  194. package/scripts/diagnostics/smoke-test.sh +0 -88
  195. package/scripts/diagnostics/snapshot.sh +0 -90
  196. package/scripts/diagnostics/verify.sh +0 -108
  197. package/scripts/diagnostics/verify_state.sh +0 -73
  198. package/scripts/diagnostics/version-locks.sh +0 -94
  199. package/scripts/diagnostics/workstation-attestation.sh +0 -212
  200. package/scripts/dot/commands/agent.sh +0 -535
  201. package/scripts/dot/commands/agents.sh +0 -352
  202. package/scripts/dot/commands/ai.sh +0 -600
  203. package/scripts/dot/commands/aliases.sh +0 -277
  204. package/scripts/dot/commands/appearance.sh +0 -110
  205. package/scripts/dot/commands/completion.sh +0 -171
  206. package/scripts/dot/commands/core.sh +0 -217
  207. package/scripts/dot/commands/diagnostics.sh +0 -265
  208. package/scripts/dot/commands/env-emit.sh +0 -203
  209. package/scripts/dot/commands/fleet.sh +0 -711
  210. package/scripts/dot/commands/init.sh +0 -185
  211. package/scripts/dot/commands/lint.sh +0 -208
  212. package/scripts/dot/commands/manual.sh +0 -169
  213. package/scripts/dot/commands/meta.sh +0 -438
  214. package/scripts/dot/commands/patterns.sh +0 -55
  215. package/scripts/dot/commands/registry.sh +0 -455
  216. package/scripts/dot/commands/restore.sh +0 -232
  217. package/scripts/dot/commands/secrets.sh +0 -296
  218. package/scripts/dot/commands/security.sh +0 -102
  219. package/scripts/dot/commands/tools.sh +0 -570
  220. package/scripts/dot/data/alias-deprecations.tsv +0 -2
  221. package/scripts/dot/powershell/Dot.psm1 +0 -319
  222. package/scripts/fonts/install-nerd-fonts.sh +0 -75
  223. package/scripts/fonts/patch-fonts.sh +0 -36
  224. package/scripts/git-hooks/install.sh +0 -12
  225. package/scripts/git-hooks/pre-commit +0 -12
  226. package/scripts/git-hooks/pre-commit-audit.sh +0 -146
  227. package/scripts/git-hooks/pre-push +0 -105
  228. package/scripts/git-hooks/prepare-commit-msg +0 -29
  229. package/scripts/lib/secrets_provider.sh +0 -200
  230. package/scripts/nvim/headless-upgrade.lua +0 -81
  231. package/scripts/ops/ai-setup.sh +0 -71
  232. package/scripts/ops/bundle.sh +0 -104
  233. package/scripts/ops/chaos.sh +0 -50
  234. package/scripts/ops/chezmoi-apply.sh +0 -333
  235. package/scripts/ops/chezmoi-diff.sh +0 -16
  236. package/scripts/ops/chezmoi-remove.sh +0 -46
  237. package/scripts/ops/chezmoi-update.sh +0 -67
  238. package/scripts/ops/heal-chezmoi.sh +0 -87
  239. package/scripts/ops/heal-system.sh +0 -129
  240. package/scripts/ops/heal-tools.sh +0 -297
  241. package/scripts/ops/heal.sh +0 -223
  242. package/scripts/ops/post-apply-repair.sh +0 -107
  243. package/scripts/ops/prewarm.sh +0 -128
  244. package/scripts/ops/release.sh +0 -262
  245. package/scripts/ops/rollback.sh +0 -613
  246. package/scripts/ops/setup.sh +0 -138
  247. package/scripts/ops/teleport.sh +0 -34
  248. package/scripts/qa/check-feature-matrix.sh +0 -296
  249. package/scripts/qa/check-version-consistency.sh +0 -12
  250. package/scripts/qa/coverage-baseline.sh +0 -61
  251. package/scripts/qa/docs-coverage.sh +0 -118
  252. package/scripts/qa/examples-coverage.sh +0 -94
  253. package/scripts/qa/powershell-contract.ps1 +0 -95
  254. package/scripts/qa/reliability-audit.sh +0 -139
  255. package/scripts/qa/scorecard-snapshot.sh +0 -128
  256. package/scripts/qa/traceability-coverage.sh +0 -124
  257. package/scripts/qa/validate-examples.sh +0 -90
  258. package/scripts/qa/wsl-contract.sh +0 -12
  259. package/scripts/secrets/age-init.sh +0 -82
  260. package/scripts/secrets/create-secrets-file.sh +0 -46
  261. package/scripts/secrets/encrypt-ssh-key.sh +0 -44
  262. package/scripts/security/backup.sh +0 -58
  263. package/scripts/security/check-disclosure-key-expiry.sh +0 -111
  264. package/scripts/security/dns-doh.sh +0 -52
  265. package/scripts/security/encryption-check.sh +0 -55
  266. package/scripts/security/enforce-policies.sh +0 -552
  267. package/scripts/security/firewall.sh +0 -91
  268. package/scripts/security/lock-configs.sh +0 -67
  269. package/scripts/security/lock-screen.sh +0 -56
  270. package/scripts/security/manage-secrets.sh +0 -429
  271. package/scripts/security/ssh-cert.sh +0 -204
  272. package/scripts/security/telemetry-kill.sh +0 -51
  273. package/scripts/security/usb-safety.sh +0 -52
  274. package/scripts/theme/apply-gnome-theme.sh +0 -333
  275. package/scripts/theme/extract-heic-frames.sh +0 -115
  276. package/scripts/theme/extract-theme.py +0 -1020
  277. package/scripts/theme/install-boot-logo.sh +0 -63
  278. package/scripts/theme/install-catppuccin-themes.sh +0 -371
  279. package/scripts/theme/install-cursors.sh +0 -26
  280. package/scripts/theme/install-file-icons.sh +0 -27
  281. package/scripts/theme/install-grub-theme.sh +0 -62
  282. package/scripts/theme/install-lock-icon.sh +0 -31
  283. package/scripts/theme/merge-wallpaper.sh +0 -146
  284. package/scripts/theme/rebuild-themes.sh +0 -603
  285. package/scripts/theme/switch.sh +0 -476
  286. package/scripts/theme/wallpaper-rotate.sh +0 -137
  287. package/scripts/theme/wallpaper-sync.sh +0 -690
  288. package/scripts/tools/cmatrix.sh +0 -22
  289. package/scripts/tools/detect-collisions.py +0 -103
  290. package/scripts/tools/emoji-picker.sh +0 -49
  291. package/scripts/tools/figlet-banner.sh +0 -19
  292. package/scripts/tools/log-rotate.sh +0 -31
  293. package/scripts/tools/lolcat-wrap.sh +0 -20
  294. package/scripts/tools/pipes.sh +0 -49
  295. package/scripts/tuning/linux.sh +0 -186
  296. package/scripts/tuning/macos.sh +0 -56
  297. package/scripts/uninstall.sh +0 -86
  298. package/scripts/verify-release-versions +0 -156
  299. package/scripts/version-sync.sh +0 -714
  300. package/templates/chezmoi-data/geekom-a9.toml.example +0 -21
  301. package/templates/chezmoi-data/mac-m1.toml.example +0 -16
  302. package/templates/chezmoi-data/mac-t2-linux.toml.example +0 -21
  303. package/templates/chezmoi-data/surface-pro-7p.toml.example +0 -21
  304. package/templates/projects/go/.github/workflows/ci.yml +0 -31
  305. package/templates/projects/go/README.md +0 -7
  306. package/templates/projects/go/cmd/__PROJECT_NAME__/main.go +0 -8
  307. package/templates/projects/go/go.mod +0 -3
  308. package/templates/projects/go/go.sum +0 -0
  309. package/templates/projects/molecule/README.md +0 -7
  310. package/templates/projects/molecule/converge.yml +0 -7
  311. package/templates/projects/molecule/molecule.yml +0 -16
  312. package/templates/projects/node/.github/workflows/ci.yml +0 -30
  313. package/templates/projects/node/README.md +0 -7
  314. package/templates/projects/node/package-lock.json +0 -12
  315. package/templates/projects/node/package.json +0 -10
  316. package/templates/projects/node/src/index.js +0 -3
  317. package/templates/projects/packer/README.md +0 -15
  318. package/templates/projects/packer/main.pkr.hcl +0 -15
  319. package/templates/projects/python/.github/workflows/ci.yml +0 -34
  320. package/templates/projects/python/README.md +0 -7
  321. package/templates/projects/python/pyproject.toml +0 -25
  322. package/templates/projects/python/src/__PROJECT_NAME__/__init__.py +0 -2
  323. package/templates/projects/python/tests/test_basic.py +0 -3
@@ -1,603 +0,0 @@
1
- #!/usr/bin/env bash
2
- # SPDX-License-Identifier: Apache-2.0 OR MIT
3
- # Copyright (c) 2015-2026 Sebastien Rousseau
4
- # rebuild-themes.sh — Discover wallpapers and generate themes.toml dynamically.
5
- #
6
- # Scans system wallpaper directories and ~/Pictures/Wallpapers/ for images,
7
- # extracts dominant colors via extract-theme.py, and assembles themes.toml.
8
- # Custom wallpapers override system wallpapers with the same name.
9
- #
10
- # Usage:
11
- # bash rebuild-themes.sh # Rebuild themes.toml
12
- # bash rebuild-themes.sh --force # Force regeneration (ignore cache)
13
- # bash rebuild-themes.sh --list # List discovered wallpapers without rebuilding
14
- set -euo pipefail
15
-
16
- # This script relies on associative arrays (`declare -A`) and `wait -n`,
17
- # both of which need bash >= 4. macOS ships /bin/bash 3.2, where it would
18
- # otherwise fail with cryptic "invalid option" / "bad array subscript"
19
- # errors mid-run. Re-exec under a newer bash when one is available
20
- # (Homebrew, MacPorts, mise), and fail with a clear, actionable message
21
- # otherwise rather than corrupting a half-built themes.toml.
22
- if ((BASH_VERSINFO[0] < 4)); then
23
- for _newer_bash in \
24
- /opt/homebrew/bin/bash \
25
- /usr/local/bin/bash \
26
- "${HOMEBREW_PREFIX:-}/bin/bash" \
27
- "$(command -v bash 2>/dev/null || true)"; do
28
- if [[ -n "$_newer_bash" && -x "$_newer_bash" ]] &&
29
- "$_newer_bash" -c '((BASH_VERSINFO[0] >= 4))' 2>/dev/null; then
30
- exec "$_newer_bash" "$0" "$@"
31
- fi
32
- done
33
- echo "Error: 'dot theme rebuild' needs bash >= 4 (macOS ships bash 3.2)." >&2
34
- echo " Install a newer bash and retry: brew install bash" >&2
35
- exit 1
36
- fi
37
-
38
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
39
- EXTRACT_SCRIPT="$SCRIPT_DIR/extract-theme.py"
40
- DOTFILES_DIR="${HOME}/.dotfiles"
41
-
42
- # Descend into the chezmoi source subdir when .chezmoiroot is present (post-reorg, chezmoi files under defaults/)
43
- CHEZMOI_SRC="$DOTFILES_DIR"
44
- if [[ -f "$DOTFILES_DIR/.chezmoiroot" ]]; then
45
- _sub="$(head -1 "$DOTFILES_DIR/.chezmoiroot" | tr -d '[:space:]')"
46
- [[ -n "$_sub" && -d "$DOTFILES_DIR/$_sub" ]] && CHEZMOI_SRC="$DOTFILES_DIR/$_sub"
47
- fi
48
- THEMES_FILE="$CHEZMOI_SRC/.chezmoidata/themes.toml"
49
- CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/dotfiles/themes"
50
- CUSTOM_DIR="${DOTFILES_WALLPAPER_DIR:-$HOME/Pictures/Wallpapers}"
51
-
52
- FORCE=false
53
- LIST_ONLY=false
54
-
55
- for arg in "$@"; do
56
- case "$arg" in
57
- --force) FORCE=true ;;
58
- --list) LIST_ONLY=true ;;
59
- esac
60
- done
61
-
62
- # ---------------------------------------------------------------------------
63
- # Discover wallpapers from all sources
64
- # ---------------------------------------------------------------------------
65
-
66
- declare -A WALLPAPERS # name -> path (custom overrides system)
67
- declare -A WP_SOURCE # name -> "system" | "custom"
68
-
69
- discover_macos_system() {
70
- local sys_dir="/System/Library/Desktop Pictures"
71
- [[ -d "$sys_dir" ]] || return 0
72
-
73
- # Register top-level system wallpapers (will be deduped later if thumbnails have dark/light)
74
- local file name
75
- for file in "$sys_dir"/*.heic; do
76
- [[ -f "$file" ]] || continue
77
- name="$(basename "$file" .heic)"
78
- name="$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
79
- name="${name//[^a-z0-9-]/}"
80
- WALLPAPERS["$name"]="$file"
81
- WP_SOURCE["$name"]="system"
82
- done
83
-
84
- # Also check .thumbnails for wallpapers with Dark/Light variants
85
- local thumb_dir="$sys_dir/.thumbnails"
86
- if [[ -d "$thumb_dir" ]]; then
87
- # First pass: register all thumbnails
88
- for file in "$thumb_dir"/*.heic; do
89
- [[ -f "$file" ]] || continue
90
- local base
91
- base="$(basename "$file" .heic)"
92
- name="$(echo "$base" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
93
- name="${name//[^a-z0-9-]/}"
94
- if [[ -z "${WALLPAPERS[$name]+x}" ]]; then
95
- WALLPAPERS["$name"]="$file"
96
- WP_SOURCE["$name"]="system"
97
- fi
98
- done
99
-
100
- # Second pass: remove base wallpapers that have explicit dark/light variants
101
- # e.g. if "big-sur-graphic-dark" exists, remove "big-sur-graphic"
102
- local check_name
103
- for name in "${!WALLPAPERS[@]}"; do
104
- if [[ "${name}" != *-dark && "${name}" != *-light ]]; then
105
- check_name="${name}-dark"
106
- if [[ -n "${WALLPAPERS[$check_name]+x}" ]]; then
107
- unset "WALLPAPERS[$name]"
108
- unset "WP_SOURCE[$name]"
109
- continue
110
- fi
111
- check_name="${name}-light"
112
- if [[ -n "${WALLPAPERS[$check_name]+x}" ]]; then
113
- unset "WALLPAPERS[$name]"
114
- unset "WP_SOURCE[$name]"
115
- fi
116
- fi
117
- done
118
- fi
119
- }
120
-
121
- discover_linux_system() {
122
- local dirs=(
123
- /usr/share/backgrounds
124
- /usr/share/wallpapers
125
- )
126
-
127
- local dir file name variant
128
- for dir in "${dirs[@]}"; do
129
- [[ -d "$dir" ]] || continue
130
- while IFS= read -r file; do
131
- name="$(basename "$file")"
132
- name="${name%.*}"
133
- name="$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr ' _' '--')"
134
- name="${name//[^a-z0-9-]/}"
135
- while [[ "$name" == *--* ]]; do name="${name//--/-}"; done
136
- name="${name#-}"
137
- name="${name%-}"
138
- [[ -n "$name" ]] || continue
139
- # Static system images carry no mode; theme them in both modes so
140
- # they show as a pair (unless the file is already a -dark/-light).
141
- if [[ "$name" == *-dark || "$name" == *-light ]]; then
142
- [[ -z "${WALLPAPERS[$name]+x}" ]] && {
143
- WALLPAPERS["$name"]="$file"
144
- WP_SOURCE["$name"]="system"
145
- }
146
- continue
147
- fi
148
- local key
149
- for variant in dark light; do
150
- key="${name}-${variant}"
151
- if [[ -z "${WALLPAPERS[$key]+x}" ]]; then
152
- WALLPAPERS["$key"]="$file"
153
- WP_SOURCE["$key"]="system"
154
- fi
155
- done
156
- done < <(find "$dir" -maxdepth 3 -type f \
157
- \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \
158
- -o -iname '*.heic' -o -iname '*.webp' -o -iname '*.tiff' \) 2>/dev/null | sort)
159
- done
160
- }
161
-
162
- discover_custom() {
163
- [[ -d "$CUSTOM_DIR" ]] || return 0
164
-
165
- local file base name ext frame_count
166
- # Case-insensitive, wide extension match. The old fixed-glob loop
167
- # (`*.heic *.jpg *.png`) silently dropped `.jpeg`, `.webp`, `.tiff`
168
- # and every uppercase variant (`.JPG`, `.HEIC`, …), so those
169
- # wallpapers never made it into the theme table.
170
- while IFS= read -r file; do
171
- [[ -f "$file" ]] || continue
172
- base="$(basename "$file")"
173
- base="${base%.*}"
174
- ext="$(echo "${file##*.}" | tr '[:upper:]' '[:lower:]')"
175
-
176
- # Normalize to the [a-z0-9-] namespace that themes.toml and the
177
- # `dot theme list` picker regex both require — a raw name with
178
- # spaces/uppercase would generate a section the picker can't match.
179
- name="$(echo "$base" | tr '[:upper:]' '[:lower:]' | tr ' _' '--')"
180
- name="${name//[^a-z0-9-]/}"
181
- while [[ "$name" == *--* ]]; do name="${name//--/-}"; done
182
- name="${name#-}"
183
- name="${name%-}"
184
- [[ -n "$name" ]] || continue
185
-
186
- # Dynamic HEIC (multi-frame = light+dark packed in one file).
187
- if [[ "$ext" == "heic" ]]; then
188
- frame_count="$(magick identify "$file" 2>/dev/null | wc -l | tr -d ' ')"
189
- if [[ "$frame_count" -ge 2 && "$name" != *-dark && "$name" != *-light ]]; then
190
- WALLPAPERS["${name}-light"]="${file}[0]"
191
- WP_SOURCE["${name}-light"]="custom"
192
- WALLPAPERS["${name}-dark"]="${file}[1]"
193
- WP_SOURCE["${name}-dark"]="custom"
194
- # Store the original file path for wallpaper-sync.
195
- WALLPAPERS["${name}"]="$file"
196
- WP_SOURCE["${name}"]="custom-dynamic"
197
- continue
198
- fi
199
- fi
200
-
201
- # Explicitly-named single-mode variant (foo-dark.jpg / foo-light.jpg):
202
- # honour the author's mode, register the one variant as-is.
203
- if [[ "$name" == *-dark || "$name" == *-light ]]; then
204
- WALLPAPERS["$name"]="$file"
205
- WP_SOURCE["$name"]="custom"
206
- continue
207
- fi
208
-
209
- # Static single image: theme it in BOTH modes (extract-theme forces
210
- # the mode from the -dark/-light suffix) so it appears as a light/dark
211
- # pair in `dot theme list`. Previously a static produced only one
212
- # variant and paired_families() hid it entirely.
213
- WALLPAPERS["${name}-dark"]="$file"
214
- WP_SOURCE["${name}-dark"]="custom"
215
- WALLPAPERS["${name}-light"]="$file"
216
- WP_SOURCE["${name}-light"]="custom"
217
- done < <(find "$CUSTOM_DIR" -maxdepth 1 -type f \
218
- \( -iname '*.heic' -o -iname '*.jpg' -o -iname '*.jpeg' \
219
- -o -iname '*.png' -o -iname '*.webp' -o -iname '*.tiff' \) 2>/dev/null | sort)
220
- }
221
-
222
- # Remove dynamic base entries (keep only the -dark/-light variants for theme gen)
223
- cleanup_dynamic_entries() {
224
- for name in "${!WP_SOURCE[@]}"; do
225
- if [[ "${WP_SOURCE[$name]}" == "custom-dynamic" ]]; then
226
- unset "WALLPAPERS[$name]"
227
- unset "WP_SOURCE[$name]"
228
- fi
229
- done
230
- }
231
-
232
- # Discover in order: system first, custom overrides. System (OS-shipped)
233
- # wallpapers are opt-in — most users only want themes from their own
234
- # wallpapers. Enable the ~100 built-in ones with DOTFILES_THEME_SYSTEM=1.
235
- if [[ "${DOTFILES_THEME_SYSTEM:-0}" == "1" ]]; then
236
- case "$(uname -s)" in
237
- Darwin) discover_macos_system ;;
238
- Linux) discover_linux_system ;;
239
- esac
240
- fi
241
- discover_custom
242
- cleanup_dynamic_entries
243
-
244
- # ---------------------------------------------------------------------------
245
- # List mode
246
- # ---------------------------------------------------------------------------
247
-
248
- if [[ "$LIST_ONLY" == "true" ]]; then
249
- printf '%-40s %-8s %s\n' "NAME" "SOURCE" "PATH"
250
- printf '%-40s %-8s %s\n' "----" "------" "----"
251
- for name in $(printf '%s\n' "${!WALLPAPERS[@]}" | sort); do
252
- printf '%-40s %-8s %s\n' "$name" "${WP_SOURCE[$name]}" "${WALLPAPERS[$name]}"
253
- done
254
- echo ""
255
- echo "Total: ${#WALLPAPERS[@]} wallpapers"
256
- exit 0
257
- fi
258
-
259
- # ---------------------------------------------------------------------------
260
- # Check dependencies
261
- # ---------------------------------------------------------------------------
262
-
263
- if [[ ! -f "$EXTRACT_SCRIPT" ]]; then
264
- echo "Error: extract-theme.py not found at $EXTRACT_SCRIPT" >&2
265
- exit 1
266
- fi
267
-
268
- if ! command -v python3 &>/dev/null; then
269
- echo "Error: python3 required" >&2
270
- exit 1
271
- fi
272
-
273
- if ! command -v magick &>/dev/null; then
274
- echo "Error: ImageMagick (magick) required" >&2
275
- exit 1
276
- fi
277
-
278
- mkdir -p "$CACHE_DIR"
279
-
280
- # ---------------------------------------------------------------------------
281
- # Invalidate the cache when the generator itself changes
282
- #
283
- # A cache entry is only valid for the extract-theme.py that produced it, but
284
- # the freshness check below compares the entry against its *wallpaper* alone.
285
- # So a wallpaper that never changes keeps serving whatever the generator
286
- # emitted the first time, indefinitely — while every other theme silently
287
- # moves on.
288
- #
289
- # That is not hypothetical: catalina and sonoma shipped in themes.toml with
290
- # blocks generated in June/July, months after the rest. They carried an
291
- # absolute /Users/<name>/ wallpaper path (predating the `~/` normalisation)
292
- # and a c15 of #181818 in a *light* theme (predating the structural-ramp fix),
293
- # which failed the WCAG AAA gate in CI. Two real defects, both invisible here
294
- # because those two wallpapers had simply not been touched since.
295
- #
296
- # Keyed on the generator's CONTENT, not its mtime: `git checkout` rewrites
297
- # mtimes without changing behaviour, and mtime alone would force a full
298
- # rebuild of every theme on each checkout.
299
- generator_digest() {
300
- if command -v shasum >/dev/null 2>&1; then
301
- shasum -a 256 "$1" | awk '{print $1}'
302
- elif command -v sha256sum >/dev/null 2>&1; then
303
- sha256sum "$1" | awk '{print $1}'
304
- else
305
- # No digest tool: fall back to always regenerating rather than risk
306
- # serving stale blocks. Correctness over speed.
307
- echo "no-digest-tool-$(date +%s)"
308
- fi
309
- }
310
-
311
- GENERATOR_STAMP="$CACHE_DIR/.extract-theme.sha256"
312
- GENERATOR_HASH="$(generator_digest "$EXTRACT_SCRIPT")"
313
- GENERATOR_STALE=false
314
- if [[ ! -f "$GENERATOR_STAMP" || "$(cat "$GENERATOR_STAMP")" != "$GENERATOR_HASH" ]]; then
315
- GENERATOR_STALE=true
316
- echo "Generator changed since the cache was written — rebuilding all themes."
317
- fi
318
-
319
- # Clean orphaned cache files (wallpapers that no longer exist)
320
- for cache_file in "$CACHE_DIR"/*.toml; do
321
- [[ -f "$cache_file" ]] || continue
322
- cached_name="$(basename "$cache_file" .toml)"
323
- if [[ -z "${WALLPAPERS[$cached_name]+x}" ]]; then
324
- rm -f "$cache_file"
325
- fi
326
- done
327
-
328
- # ---------------------------------------------------------------------------
329
- # Generate themes
330
- # ---------------------------------------------------------------------------
331
-
332
- # Report distinct WALLPAPERS (families), not theme sections. Every
333
- # wallpaper — a dynamic HEIC (light+dark frames) or a static image —
334
- # yields a `-light` and a `-dark` theme, so a raw section count is ~2x
335
- # the file count and reads as wrong ("74 files → 148 custom"). Collapse
336
- # -dark/-light back to the family so the numbers match what's on disk
337
- # and what `dot theme list` shows, and report the theme total separately.
338
- # Explicit empty init: a `declare -A x` that never gets a key still trips
339
- # `set -u` on ${#x[@]} (even in bash 5) — happens now that system wallpapers
340
- # are opt-in and sys_fam can stay empty.
341
- declare -A sys_fam=() cust_fam=()
342
- for name in "${!WP_SOURCE[@]}"; do
343
- family="${name%-dark}"
344
- family="${family%-light}"
345
- case "${WP_SOURCE[$name]}" in
346
- system) sys_fam["$family"]=1 ;;
347
- custom) cust_fam["$family"]=1 ;;
348
- esac
349
- done
350
- sys_count=${#sys_fam[@]}
351
- cust_count=${#cust_fam[@]}
352
- echo "Discovering wallpapers..."
353
- echo " Found: $sys_count system, $cust_count custom wallpapers" \
354
- "($((sys_count + cust_count)) total → ${#WALLPAPERS[@]} light/dark themes)"
355
- echo ""
356
-
357
- GENERATED=0
358
- CACHED=0
359
- FAILED=0
360
-
361
- echo "Generating themes..."
362
-
363
- # Build work list (skip cached)
364
- WORK=()
365
- for name in $(printf '%s\n' "${!WALLPAPERS[@]}" | sort); do
366
- [[ -n "${WALLPAPERS[$name]+x}" ]] || continue
367
- wp_path="${WALLPAPERS[$name]}"
368
- cache_file="$CACHE_DIR/${name}.toml"
369
-
370
- if [[ "$FORCE" != "true" && "$GENERATOR_STALE" != "true" &&
371
- -f "$cache_file" && "$cache_file" -nt "$wp_path" ]]; then
372
- CACHED=$((CACHED + 1))
373
- continue
374
- fi
375
- WORK+=("$name")
376
- done
377
-
378
- # Process in parallel (up to 4 jobs)
379
- JOBS=4
380
- TOTAL_WORK=${#WORK[@]}
381
- if [[ $TOTAL_WORK -gt 0 ]]; then
382
- echo " Processing $TOTAL_WORK wallpapers ($JOBS parallel jobs)..."
383
- for name in "${WORK[@]}"; do
384
- wp_path="${WALLPAPERS[$name]}"
385
- cache_file="$CACHE_DIR/${name}.toml"
386
- source_type="${WP_SOURCE[$name]}"
387
-
388
- (
389
- if python3 "$EXTRACT_SCRIPT" "$wp_path" --name "$name" --source "$source_type" >"$cache_file" 2>/dev/null; then
390
- printf " %-40s [%s] ✓\n" "$name" "$source_type"
391
- else
392
- rm -f "$cache_file"
393
- printf " %-40s [%s] ✗\n" "$name" "$source_type"
394
- fi
395
- ) &
396
-
397
- # Limit parallel jobs (bash >= 4 guaranteed by the guard at the top).
398
- while [[ $(jobs -r | wc -l) -ge $JOBS ]]; do
399
- wait -n 2>/dev/null || true
400
- done
401
- done
402
- wait
403
- fi
404
-
405
- # Count results — how many of THIS run's work items produced a cache file.
406
- # (The old `find -newer "$0"` counted every cache file newer than the script,
407
- # so when everything was cached FAILED went negative.)
408
- GENERATED=0
409
- FAILED=0
410
- for name in "${WORK[@]}"; do
411
- if [[ -f "$CACHE_DIR/${name}.toml" ]]; then
412
- GENERATED=$((GENERATED + 1))
413
- else
414
- FAILED=$((FAILED + 1))
415
- fi
416
- done
417
- echo ""
418
- echo "Results: $GENERATED generated, $CACHED cached, $FAILED failed"
419
-
420
- # ---------------------------------------------------------------------------
421
- # Assemble themes.toml
422
- # ---------------------------------------------------------------------------
423
-
424
- echo ""
425
- echo "Assembling themes.toml..."
426
-
427
- {
428
- cat <<'HEADER'
429
- # ============================================================================
430
- # Theme Manifest — Auto-generated from wallpaper dominant colors
431
- # ============================================================================
432
- # Generated by: scripts/theme/rebuild-themes.sh
433
- # Algorithm: K-Means clustering in CIELAB color space
434
- # Do not edit manually — run `dot theme rebuild` to regenerate.
435
- #
436
- # Sources:
437
- # System: /System/Library/Desktop Pictures/ (macOS)
438
- # /usr/share/backgrounds/ (Linux)
439
- # Custom: ~/Pictures/Wallpapers/
440
-
441
- HEADER
442
-
443
- # Assemble ONLY the wallpapers discovered this run, not every file left in
444
- # the cache. This drops themes for wallpapers no longer present (e.g. system
445
- # wallpapers once DOTFILES_THEME_SYSTEM is turned off) instead of letting
446
- # stale cache entries pile up in themes.toml.
447
- for name in $(printf '%s\n' "${!WALLPAPERS[@]}" | sort); do
448
- cache_file="$CACHE_DIR/${name}.toml"
449
- [[ -f "$cache_file" ]] || continue
450
- echo ""
451
- cat "$cache_file"
452
- done
453
-
454
- # Synthetic fallback themes — always emitted, never wallpaper-derived.
455
- # Every theme template degrades to `fallback-dark` when `.theme` is unset or
456
- # names a theme absent from this file. Because these are re-emitted on every
457
- # rebuild, a regeneration that drops any wallpaper theme can never break the
458
- # fallback (unlike hardcoding a wallpaper theme like the old big-sur-dark).
459
- # switch.sh hides the `fallback` family from user-facing theme lists.
460
- cat <<'FALLBACK'
461
-
462
- # ─────────────────────────────────────────────────────────────────────
463
- # Synthetic fallback themes (NOT wallpaper-derived, NEVER user-selectable).
464
- # ─────────────────────────────────────────────────────────────────────
465
-
466
- [themes.fallback-dark]
467
- mode = "dark"
468
- family = "fallback"
469
- macos_accent = 4
470
- wallpaper = ""
471
- source = "custom"
472
-
473
- [themes.fallback-dark.term]
474
- bg = "#1e1e2e"
475
- fg = "#d4d4d4"
476
- cursor = "#455c67"
477
- cursor_text = "#1e1e2e"
478
- sel_bg = "#394145"
479
- sel_fg = "#d4d4d4"
480
- c0 = "#3c3c4d"
481
- c1 = "#997d7a"
482
- c2 = "#479174"
483
- c3 = "#8a836f"
484
- c4 = "#5f86b7"
485
- c5 = "#917e8e"
486
- c6 = "#5c8d82"
487
- c7 = "#b9b8bb"
488
- c8 = "#605f72"
489
- c9 = "#bf9b97"
490
- c10 = "#67b293"
491
- c11 = "#aba389"
492
- c12 = "#7fa6d9"
493
- c13 = "#b49cb0"
494
- c14 = "#7bada1"
495
- c15 = "#e2e2e3"
496
-
497
- [themes.fallback-dark.ui]
498
- accent = "#455c67"
499
- accent_text = "#ffffff"
500
- error = "#997d7a"
501
- warning = "#8a836f"
502
- success = "#479174"
503
- info = "#5f86b7"
504
- panel = "#242435"
505
- border = "#302f38"
506
- secondary = "#2d5987"
507
- tertiary = "#16654b"
508
- text_muted = "#9898a5"
509
- accent_on_surface = "#819dab"
510
- secondary_on_surface = "#7b9bc4"
511
- tertiary_on_surface = "#53a987"
512
-
513
- [themes.fallback-dark.app]
514
- nvim = "tokyonight"
515
- nvim_style = "night"
516
- lualine = "tokyonight"
517
- gtk_theme = "Adwaita-dark"
518
- gtk_icon = "Papirus-Dark"
519
- gnome_shell = ""
520
- gnome_gtk = "Adwaita-dark"
521
- vscode = "Catppuccin Mocha"
522
- vscode_dark = "Catppuccin Mocha"
523
- vscode_light = "Catppuccin Latte"
524
- vscode_icons = "catppuccin-mocha"
525
- cat_wallpaper = ""
526
- starship_palette = "catppuccin_mocha"
527
-
528
-
529
- [themes.fallback-light]
530
- mode = "light"
531
- family = "fallback"
532
- macos_accent = 4
533
- wallpaper = ""
534
- source = "custom"
535
-
536
- [themes.fallback-light.term]
537
- bg = "#fbf1c7"
538
- fg = "#3c3836"
539
- cursor = "#2c5989"
540
- cursor_text = "#fbf1c7"
541
- sel_bg = "#c6cfe0"
542
- sel_fg = "#3c3836"
543
- c0 = "#2e2c26"
544
- c1 = "#7d3d39"
545
- c2 = "#205a48"
546
- c3 = "#5b501d"
547
- c4 = "#2b527d"
548
- c5 = "#6e4069"
549
- c6 = "#25554c"
550
- c7 = "#6f6d67"
551
- c8 = "#54524b"
552
- c9 = "#853733"
553
- c10 = "#025c46"
554
- c11 = "#5b500b"
555
- c12 = "#0d5388"
556
- c13 = "#743b6f"
557
- c14 = "#15564b"
558
- c15 = "#979693"
559
-
560
- [themes.fallback-light.ui]
561
- accent = "#2c5989"
562
- accent_text = "#ffffff"
563
- error = "#7d3d39"
564
- warning = "#5b501d"
565
- success = "#205a48"
566
- info = "#2b527d"
567
- panel = "#f2e8bf"
568
- border = "#e3e0d3"
569
- secondary = "#85443e"
570
- tertiary = "#29623e"
571
- text_muted = "#686256"
572
- accent_on_surface = "#2c5989"
573
- secondary_on_surface = "#2b527d"
574
- tertiary_on_surface = "#205a48"
575
-
576
- [themes.fallback-light.app]
577
- nvim = "catppuccin"
578
- nvim_style = "latte"
579
- lualine = "catppuccin"
580
- gtk_theme = "Adwaita"
581
- gtk_icon = "Papirus-Light"
582
- gnome_shell = ""
583
- gnome_gtk = "Adwaita"
584
- vscode = "Catppuccin Latte"
585
- vscode_dark = "Catppuccin Mocha"
586
- vscode_light = "Catppuccin Latte"
587
- vscode_icons = "catppuccin-latte"
588
- cat_wallpaper = ""
589
- starship_palette = "catppuccin_latte"
590
- FALLBACK
591
- } >"$THEMES_FILE"
592
-
593
- # Count top-level [themes.NAME] blocks only — not the .term/.ui/.app
594
- # subsections (which inflated the tally ~4x).
595
- theme_count=$(grep -cE '^\[themes\.[a-z0-9-]+\]$' "$THEMES_FILE")
596
- echo " Written: $THEMES_FILE ($theme_count themes)"
597
-
598
- # Record which generator produced this cache. Written only now, after the file
599
- # has been assembled: stamping earlier would mark the cache current even if the
600
- # run died partway, so the next run would trust half-regenerated blocks.
601
- printf '%s\n' "$GENERATOR_HASH" >"$GENERATOR_STAMP"
602
- echo ""
603
- echo "Done. Run 'dot theme list' to see available themes."