@sebastienrousseau/dotfiles 0.2.519 → 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 (306) hide show
  1. package/CHANGELOG.md +200 -0
  2. package/LICENSE-APACHE +190 -0
  3. package/{LICENSE → LICENSE-MIT} +1 -1
  4. package/README.md +1172 -166
  5. package/install.sh +77 -11
  6. package/package.json +8 -8
  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/CNAME +0 -1
  12. package/docs/CONFIG_STRATEGY.md +0 -124
  13. package/docs/COPYRIGHT +0 -7
  14. package/docs/GOVERNANCE.md +0 -98
  15. package/docs/MAINTAINERS.md +0 -41
  16. package/docs/NAMING_CONVENTIONS.md +0 -102
  17. package/docs/OPENCODE.md +0 -127
  18. package/docs/README.md +0 -84
  19. package/docs/STRUCTURE.md +0 -102
  20. package/docs/adr/ADR-001-ci-cd-pipeline.md +0 -118
  21. package/docs/adr/ADR-002-shell-performance.md +0 -130
  22. package/docs/adr/ADR-003-security-first.md +0 -158
  23. package/docs/adr/ADR-004-cli-architecture.md +0 -171
  24. package/docs/adr/ADR-005-chezmoi-choice.md +0 -99
  25. package/docs/adr/ADR-006-shell-selection.md +0 -124
  26. package/docs/adr/ADR-007-multi-shell-parity.md +0 -62
  27. package/docs/adr/ADR-008-alias-system-architecture.md +0 -95
  28. package/docs/adr/ADR-009-wallpaper-driven-theming.md +0 -131
  29. package/docs/adr/ADR-010-starship-transient-prompt.md +0 -144
  30. package/docs/adr/ADR-011-nushell-tier3-keep.md +0 -144
  31. package/docs/adr/ADR-012-ai-fleet-local-proxy.md +0 -79
  32. package/docs/adr/README.md +0 -40
  33. package/docs/architecture/AI_COST_OPTIMIZATION.md +0 -144
  34. package/docs/architecture/ARCHITECTURE.md +0 -117
  35. package/docs/architecture/INTEROP.md +0 -44
  36. package/docs/architecture/REPO_LAYOUT.md +0 -241
  37. package/docs/architecture/WALKTHROUGH.md +0 -86
  38. package/docs/architecture/fleet-deployment.md +0 -77
  39. package/docs/archive/EUXIS_2026_REVIEW.md +0 -127
  40. package/docs/archive/LEGACY_ROADMAP.md +0 -6
  41. package/docs/archive/MILESTONE_v0.2.493.md +0 -47
  42. package/docs/archive/PLAN.md +0 -199
  43. package/docs/archive/REPO_AUDIT.md +0 -31
  44. package/docs/articles/.pages +0 -6
  45. package/docs/articles/2026-07-05-custom-mkdocs-material-dark-theme.md +0 -216
  46. package/docs/articles/2026-07-05-fish-startup-abbr.md +0 -153
  47. package/docs/articles/2026-07-05-master-to-main-rename-runbook.md +0 -128
  48. package/docs/articles/index.md +0 -36
  49. package/docs/guides/INSTALL.md +0 -144
  50. package/docs/guides/NEOVIM_IDE_GUIDE.md +0 -61
  51. package/docs/guides/THEMING.md +0 -230
  52. package/docs/guides/TROUBLESHOOTING.md +0 -176
  53. package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +0 -792
  54. package/docs/index.md +0 -132
  55. package/docs/interop/A2A.md +0 -39
  56. package/docs/interop/POWERSHELL.md +0 -102
  57. package/docs/manual/00-introduction.md +0 -89
  58. package/docs/manual/01-concepts/01-architecture.md +0 -138
  59. package/docs/manual/01-concepts/02-trust-model.md +0 -183
  60. package/docs/manual/01-concepts/03-theme-engine.md +0 -186
  61. package/docs/manual/01-concepts/04-fleet.md +0 -148
  62. package/docs/manual/01-concepts/05-self-healing.md +0 -204
  63. package/docs/manual/02-tutorials/01-first-install.md +0 -197
  64. package/docs/manual/02-tutorials/02-add-wallpaper.md +0 -216
  65. package/docs/manual/02-tutorials/03-create-profile.md +0 -244
  66. package/docs/manual/02-tutorials/04-encrypt-secret.md +0 -281
  67. package/docs/manual/02-tutorials/05-deploy-fleet.md +0 -283
  68. package/docs/manual/03-reference/01-dot-cli.md +0 -450
  69. package/docs/manual/03-reference/02-config-files.md +0 -265
  70. package/docs/manual/03-reference/03-environment.md +0 -124
  71. package/docs/manual/03-reference/04-templates.md +0 -190
  72. package/docs/manual/03-reference/05-feature-flags.md +0 -187
  73. package/docs/manual/04-cookbook/01-recipes.md +0 -285
  74. package/docs/manual/04-cookbook/02-troubleshooting.md +0 -351
  75. package/docs/manual/04-cookbook/03-faq.md +0 -175
  76. package/docs/manual/05-appendices/A-platform-matrix.md +0 -101
  77. package/docs/manual/05-appendices/B-security-checklist.md +0 -85
  78. package/docs/manual/05-appendices/C-glossary.md +0 -40
  79. package/docs/manual/05-appendices/D-bibliography.md +0 -58
  80. package/docs/manual/05-appendices/E-license.md +0 -38
  81. package/docs/manual/_toc.yml +0 -58
  82. package/docs/manual/command-index.md +0 -155
  83. package/docs/manual/concept-index.md +0 -168
  84. package/docs/manual/index.md +0 -66
  85. package/docs/operations/ARCHITECTURE_ROADMAP.md +0 -7
  86. package/docs/operations/ATTESTATION.md +0 -44
  87. package/docs/operations/CI_CADENCE.md +0 -107
  88. package/docs/operations/CI_COMPOSITES.md +0 -156
  89. package/docs/operations/COMPLETIONS.md +0 -123
  90. package/docs/operations/COVERAGE.md +0 -204
  91. package/docs/operations/DRIFT.md +0 -107
  92. package/docs/operations/HARD_AUDIT_2026.md +0 -631
  93. package/docs/operations/MAINTENANCE.md +0 -63
  94. package/docs/operations/MANIFEST.md +0 -127
  95. package/docs/operations/MIGRATION.md +0 -109
  96. package/docs/operations/OPERATIONS.md +0 -188
  97. package/docs/operations/PERFORMANCE.md +0 -133
  98. package/docs/operations/REGISTRY.md +0 -90
  99. package/docs/operations/RELEASE_PIPELINE.md +0 -128
  100. package/docs/operations/RELIABILITY.md +0 -122
  101. package/docs/operations/RFC_v0_2_503_reorganization.md +0 -280
  102. package/docs/operations/ROADMAP.md +0 -10
  103. package/docs/operations/ROADMAP_2026.md +0 -7
  104. package/docs/operations/ROADMAP_V0_2_503.md +0 -10
  105. package/docs/operations/TESTING.md +0 -216
  106. package/docs/operations/TRACEABILITY.md +0 -43
  107. package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +0 -65
  108. package/docs/operations/VERSION_SYNC.md +0 -393
  109. package/docs/reference/ALIASES.md +0 -131
  110. package/docs/reference/ALIASES_CHEATSHEET.md +0 -32
  111. package/docs/reference/ALIASES_DEPRECATIONS.md +0 -13
  112. package/docs/reference/FEATURES.md +0 -66
  113. package/docs/reference/FONTS.md +0 -112
  114. package/docs/reference/POWERSHELL_PARITY.md +0 -82
  115. package/docs/reference/PROFILES.md +0 -69
  116. package/docs/reference/SCREENSHOTS.md +0 -121
  117. package/docs/reference/SCRIPTS.md +0 -71
  118. package/docs/reference/SUPPORT_MATRIX.md +0 -80
  119. package/docs/reference/THEMES.md +0 -117
  120. package/docs/reference/TOOLS.md +0 -110
  121. package/docs/reference/UTILS.md +0 -242
  122. package/docs/registry.json +0 -6
  123. package/docs/schema/dot-env-v1.json +0 -110
  124. package/docs/schema/dot-registry-v1.json +0 -33
  125. package/docs/security/AI_ACT_COMPLIANCE.md +0 -94
  126. package/docs/security/AUDIT_BYPASS.md +0 -103
  127. package/docs/security/AUTOMATION_SECRETS.md +0 -26
  128. package/docs/security/CI_EGRESS_ALLOWLIST.md +0 -127
  129. package/docs/security/CI_PINNING.md +0 -129
  130. package/docs/security/COMMIT_SIGNING.md +0 -138
  131. package/docs/security/COMPLIANCE.md +0 -458
  132. package/docs/security/DEPS_DEV_EXCEPTIONS.md +0 -86
  133. package/docs/security/DISCLOSURE.md +0 -130
  134. package/docs/security/ENCRYPTION.md +0 -57
  135. package/docs/security/FMEA.md +0 -159
  136. package/docs/security/FUZZING.md +0 -114
  137. package/docs/security/HISTORY_FILTERING.md +0 -132
  138. package/docs/security/INCIDENT_RESPONSE.md +0 -579
  139. package/docs/security/INSTALL_VERIFICATION.md +0 -122
  140. package/docs/security/KEYS.md +0 -49
  141. package/docs/security/KEY_ROTATION.md +0 -303
  142. package/docs/security/MCP_POLICY.md +0 -78
  143. package/docs/security/POLICY_RELEASES.md +0 -37
  144. package/docs/security/README.md +0 -28
  145. package/docs/security/SCORECARD.md +0 -195
  146. package/docs/security/SECRETS.md +0 -158
  147. package/docs/security/SECURITY.md +0 -45
  148. package/docs/security/SECURITY_CHECKLIST.md +0 -55
  149. package/docs/security/SHELL_EXEMPTIONS.md +0 -145
  150. package/docs/security/SOUP_REGISTER.md +0 -36
  151. package/docs/security/THREAT_MODEL.md +0 -130
  152. package/docs/security/VERIFICATION_VALIDATION.md +0 -228
  153. package/docs/security/VERIFY_RELEASE.md +0 -201
  154. package/docs/security/security-pubkey.asc +0 -15
  155. package/docs/stylesheets/extra.css +0 -444
  156. package/docs/themes/README.md +0 -10
  157. package/docs/themes/VISUAL_INTEGRITY_REPORT.md +0 -30
  158. package/docs/themes/hero-shot.svg +0 -78
  159. package/scripts/README.md +0 -123
  160. package/scripts/ci/check-copyright-headers.sh +0 -8
  161. package/scripts/ci/check-shell-preamble.sh +0 -8
  162. package/scripts/ci/guard-gitleaks-checkout.sh +0 -8
  163. package/scripts/demo/record.sh +0 -43
  164. package/scripts/diagnostics/a2a-conformance.sh +0 -163
  165. package/scripts/diagnostics/alias-governance.sh +0 -138
  166. package/scripts/diagnostics/aliases-cheatsheet.sh +0 -74
  167. package/scripts/diagnostics/aliases-manifest.sh +0 -77
  168. package/scripts/diagnostics/benchmark.sh +0 -408
  169. package/scripts/diagnostics/conflicts.sh +0 -73
  170. package/scripts/diagnostics/doctor-unified.sh +0 -39
  171. package/scripts/diagnostics/doctor.sh +0 -751
  172. package/scripts/diagnostics/drift-dashboard.sh +0 -202
  173. package/scripts/diagnostics/health.sh +0 -623
  174. package/scripts/diagnostics/history-analysis.sh +0 -86
  175. package/scripts/diagnostics/mcp-doctor.sh +0 -582
  176. package/scripts/diagnostics/perf.sh +0 -453
  177. package/scripts/diagnostics/scorecard.sh +0 -119
  178. package/scripts/diagnostics/secret-governance.sh +0 -65
  179. package/scripts/diagnostics/security-score.sh +0 -467
  180. package/scripts/diagnostics/smoke-test.sh +0 -88
  181. package/scripts/diagnostics/snapshot.sh +0 -90
  182. package/scripts/diagnostics/verify.sh +0 -108
  183. package/scripts/diagnostics/verify_state.sh +0 -73
  184. package/scripts/diagnostics/version-locks.sh +0 -94
  185. package/scripts/diagnostics/workstation-attestation.sh +0 -187
  186. package/scripts/dot/commands/agent.sh +0 -485
  187. package/scripts/dot/commands/agents.sh +0 -336
  188. package/scripts/dot/commands/ai.sh +0 -587
  189. package/scripts/dot/commands/aliases.sh +0 -277
  190. package/scripts/dot/commands/appearance.sh +0 -110
  191. package/scripts/dot/commands/completion.sh +0 -134
  192. package/scripts/dot/commands/core.sh +0 -217
  193. package/scripts/dot/commands/diagnostics.sh +0 -265
  194. package/scripts/dot/commands/env-emit.sh +0 -203
  195. package/scripts/dot/commands/fleet.sh +0 -688
  196. package/scripts/dot/commands/init.sh +0 -185
  197. package/scripts/dot/commands/lint.sh +0 -208
  198. package/scripts/dot/commands/manual.sh +0 -169
  199. package/scripts/dot/commands/meta.sh +0 -333
  200. package/scripts/dot/commands/patterns.sh +0 -55
  201. package/scripts/dot/commands/registry.sh +0 -419
  202. package/scripts/dot/commands/restore.sh +0 -232
  203. package/scripts/dot/commands/secrets.sh +0 -296
  204. package/scripts/dot/commands/security.sh +0 -102
  205. package/scripts/dot/commands/tools.sh +0 -556
  206. package/scripts/dot/data/alias-deprecations.tsv +0 -2
  207. package/scripts/dot/powershell/Dot.psm1 +0 -319
  208. package/scripts/fonts/install-nerd-fonts.sh +0 -75
  209. package/scripts/fonts/patch-fonts.sh +0 -36
  210. package/scripts/git-hooks/install.sh +0 -12
  211. package/scripts/git-hooks/pre-commit +0 -12
  212. package/scripts/git-hooks/pre-commit-audit.sh +0 -146
  213. package/scripts/git-hooks/pre-push +0 -105
  214. package/scripts/git-hooks/prepare-commit-msg +0 -29
  215. package/scripts/lib/secrets_provider.sh +0 -185
  216. package/scripts/ops/ai-setup.sh +0 -71
  217. package/scripts/ops/bundle.sh +0 -104
  218. package/scripts/ops/chaos.sh +0 -50
  219. package/scripts/ops/chezmoi-apply.sh +0 -333
  220. package/scripts/ops/chezmoi-diff.sh +0 -16
  221. package/scripts/ops/chezmoi-remove.sh +0 -46
  222. package/scripts/ops/chezmoi-update.sh +0 -63
  223. package/scripts/ops/heal-chezmoi.sh +0 -87
  224. package/scripts/ops/heal-system.sh +0 -129
  225. package/scripts/ops/heal-tools.sh +0 -297
  226. package/scripts/ops/heal.sh +0 -223
  227. package/scripts/ops/post-apply-repair.sh +0 -107
  228. package/scripts/ops/prewarm.sh +0 -128
  229. package/scripts/ops/release.sh +0 -262
  230. package/scripts/ops/rollback.sh +0 -604
  231. package/scripts/ops/setup.sh +0 -138
  232. package/scripts/ops/teleport.sh +0 -34
  233. package/scripts/qa/check-version-consistency.sh +0 -124
  234. package/scripts/qa/coverage-baseline.sh +0 -61
  235. package/scripts/qa/docs-coverage.sh +0 -112
  236. package/scripts/qa/examples-coverage.sh +0 -94
  237. package/scripts/qa/powershell-contract.ps1 +0 -95
  238. package/scripts/qa/reliability-audit.sh +0 -139
  239. package/scripts/qa/scorecard-snapshot.sh +0 -128
  240. package/scripts/qa/traceability-coverage.sh +0 -117
  241. package/scripts/qa/validate-examples.sh +0 -27
  242. package/scripts/qa/wsl-contract.sh +0 -12
  243. package/scripts/secrets/age-init.sh +0 -82
  244. package/scripts/secrets/create-secrets-file.sh +0 -46
  245. package/scripts/secrets/encrypt-ssh-key.sh +0 -44
  246. package/scripts/security/backup.sh +0 -58
  247. package/scripts/security/check-disclosure-key-expiry.sh +0 -111
  248. package/scripts/security/dns-doh.sh +0 -52
  249. package/scripts/security/encryption-check.sh +0 -55
  250. package/scripts/security/enforce-policies.sh +0 -335
  251. package/scripts/security/firewall.sh +0 -91
  252. package/scripts/security/lock-configs.sh +0 -67
  253. package/scripts/security/lock-screen.sh +0 -56
  254. package/scripts/security/manage-secrets.sh +0 -429
  255. package/scripts/security/ssh-cert.sh +0 -204
  256. package/scripts/security/telemetry-kill.sh +0 -51
  257. package/scripts/security/usb-safety.sh +0 -52
  258. package/scripts/theme/apply-gnome-theme.sh +0 -333
  259. package/scripts/theme/extract-heic-frames.sh +0 -115
  260. package/scripts/theme/extract-theme.py +0 -742
  261. package/scripts/theme/install-boot-logo.sh +0 -63
  262. package/scripts/theme/install-catppuccin-themes.sh +0 -371
  263. package/scripts/theme/install-cursors.sh +0 -26
  264. package/scripts/theme/install-file-icons.sh +0 -27
  265. package/scripts/theme/install-grub-theme.sh +0 -62
  266. package/scripts/theme/install-lock-icon.sh +0 -31
  267. package/scripts/theme/merge-wallpaper.sh +0 -146
  268. package/scripts/theme/rebuild-themes.sh +0 -544
  269. package/scripts/theme/switch.sh +0 -449
  270. package/scripts/theme/wallpaper-rotate.sh +0 -137
  271. package/scripts/theme/wallpaper-sync.sh +0 -690
  272. package/scripts/tools/cmatrix.sh +0 -22
  273. package/scripts/tools/detect-collisions.py +0 -103
  274. package/scripts/tools/emoji-picker.sh +0 -49
  275. package/scripts/tools/figlet-banner.sh +0 -19
  276. package/scripts/tools/log-rotate.sh +0 -31
  277. package/scripts/tools/lolcat-wrap.sh +0 -20
  278. package/scripts/tools/pipes.sh +0 -49
  279. package/scripts/tuning/linux.sh +0 -186
  280. package/scripts/tuning/macos.sh +0 -56
  281. package/scripts/uninstall.sh +0 -86
  282. package/scripts/version-sync.sh +0 -654
  283. package/templates/chezmoi-data/geekom-a9.toml.example +0 -21
  284. package/templates/chezmoi-data/mac-m1.toml.example +0 -16
  285. package/templates/chezmoi-data/mac-t2-linux.toml.example +0 -21
  286. package/templates/chezmoi-data/surface-pro-7p.toml.example +0 -21
  287. package/templates/projects/go/.github/workflows/ci.yml +0 -31
  288. package/templates/projects/go/README.md +0 -7
  289. package/templates/projects/go/cmd/__PROJECT_NAME__/main.go +0 -8
  290. package/templates/projects/go/go.mod +0 -3
  291. package/templates/projects/go/go.sum +0 -0
  292. package/templates/projects/molecule/README.md +0 -7
  293. package/templates/projects/molecule/converge.yml +0 -7
  294. package/templates/projects/molecule/molecule.yml +0 -16
  295. package/templates/projects/node/.github/workflows/ci.yml +0 -30
  296. package/templates/projects/node/README.md +0 -7
  297. package/templates/projects/node/package-lock.json +0 -12
  298. package/templates/projects/node/package.json +0 -10
  299. package/templates/projects/node/src/index.js +0 -3
  300. package/templates/projects/packer/README.md +0 -15
  301. package/templates/projects/packer/main.pkr.hcl +0 -15
  302. package/templates/projects/python/.github/workflows/ci.yml +0 -34
  303. package/templates/projects/python/README.md +0 -7
  304. package/templates/projects/python/pyproject.toml +0 -25
  305. package/templates/projects/python/src/__PROJECT_NAME__/__init__.py +0 -2
  306. package/templates/projects/python/tests/test_basic.py +0 -3
@@ -1,146 +0,0 @@
1
- #!/usr/bin/env bash
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2015-2026 Sebastien Rousseau
4
- # merge-wallpaper.sh — Merge dark+light wallpapers into a single dynamic HEIC.
5
- #
6
- # Creates an Apple-compatible dynamic HEIC with appearance metadata so macOS
7
- # automatically shows the correct variant based on Light/Dark mode.
8
- #
9
- # Usage:
10
- # bash merge-wallpaper.sh # Merge all pairs in ~/Pictures/Wallpapers/
11
- # bash merge-wallpaper.sh <family> # Merge a specific family (e.g. macos-tahoe)
12
- # bash merge-wallpaper.sh --dry-run # Show what would be merged
13
- set -euo pipefail
14
-
15
- WALLPAPER_DIR="${DOTFILES_WALLPAPER_DIR:-$HOME/Pictures/Wallpapers}"
16
- DRY_RUN=false
17
- TARGET=""
18
-
19
- for arg in "$@"; do
20
- case "$arg" in
21
- --dry-run) DRY_RUN=true ;;
22
- --help | -h)
23
- echo "Usage: merge-wallpaper.sh [--dry-run] [family-name]"
24
- echo ""
25
- echo "Merges *-dark.heic + *-light.heic into a single dynamic HEIC"
26
- echo "that switches appearance automatically on macOS."
27
- exit 0
28
- ;;
29
- *) TARGET="$arg" ;;
30
- esac
31
- done
32
-
33
- if ! command -v heif-enc &>/dev/null; then
34
- echo "Error: heif-enc required (brew install libheif)" >&2
35
- exit 1
36
- fi
37
-
38
- if ! command -v magick &>/dev/null; then
39
- echo "Error: ImageMagick (magick) required" >&2
40
- exit 1
41
- fi
42
-
43
- # Generate the Apple desktop appearance XMP metadata.
44
- # Format: bplist with {l: 0, d: 1} meaning image 0 = light, image 1 = dark.
45
- generate_xmp() {
46
- local apr_b64="YnBsaXN0MDDSAQIDBFFsUWQQABABCA0PERMAAAAAAAABAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAFQ=="
47
- cat <<XMPEOF
48
- <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
49
- <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="dotfiles">
50
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
51
- <rdf:Description rdf:about=""
52
- xmlns:apple_desktop="http://ns.apple.com/namespace/1.0/"
53
- apple_desktop:apr="${apr_b64}"/>
54
- </rdf:RDF>
55
- </x:xmpmeta>
56
- <?xpacket end="w"?>
57
- XMPEOF
58
- }
59
-
60
- merge_pair() {
61
- local family="$1"
62
- local dark_file=""
63
- local light_file=""
64
-
65
- # Find dark and light files
66
- for ext in heic jpg png; do
67
- [[ -z "$dark_file" && -f "$WALLPAPER_DIR/${family}-dark.${ext}" ]] && dark_file="$WALLPAPER_DIR/${family}-dark.${ext}"
68
- [[ -z "$light_file" && -f "$WALLPAPER_DIR/${family}-light.${ext}" ]] && light_file="$WALLPAPER_DIR/${family}-light.${ext}"
69
- done
70
-
71
- if [[ -z "$dark_file" || -z "$light_file" ]]; then
72
- echo " ✗ $family — missing dark or light variant"
73
- return 1
74
- fi
75
-
76
- local output="$WALLPAPER_DIR/${family}.heic"
77
-
78
- if [[ "$DRY_RUN" == "true" ]]; then
79
- echo " ○ $family — would merge $(basename "$light_file") + $(basename "$dark_file") → $(basename "$output")"
80
- return 0
81
- fi
82
-
83
- local tmpdir
84
- tmpdir="$(mktemp -d)"
85
- # Single-quotes prevent the variable expanding at trap-definition time;
86
- # `$tmpdir` resolves when the trap fires (still scoped to this function
87
- # because RETURN is per-function).
88
- # shellcheck disable=SC2064 # intentionally expand $tmpdir at trap time within this function scope
89
- trap "rm -rf '$tmpdir'" RETURN
90
-
91
- # Convert both to JPEG for heif-enc input (it handles JPEG best)
92
- magick "$light_file" -quality 95 "$tmpdir/light.jpg" 2>/dev/null
93
- magick "$dark_file" -quality 95 "$tmpdir/dark.jpg" 2>/dev/null
94
-
95
- # Generate XMP metadata file
96
- generate_xmp >"$tmpdir/xmp.xml"
97
-
98
- # Encode as multi-image HEIC: image 0 = light (primary), image 1 = dark
99
- if heif-enc \
100
- -q 90 \
101
- "$tmpdir/light.jpg" \
102
- "$tmpdir/dark.jpg" \
103
- -o "$tmpdir/merged.heic" 2>/dev/null; then
104
-
105
- # Inject Apple desktop appearance XMP
106
- if command -v exiftool &>/dev/null; then
107
- exiftool -overwrite_original -XMP="<=$tmpdir/xmp.xml" "$tmpdir/merged.heic" 2>/dev/null || true
108
- fi
109
-
110
- # Replace the pair with the merged file
111
- mv "$tmpdir/merged.heic" "$output"
112
- rm -f "$dark_file" "$light_file"
113
- echo " ✓ $family — merged → $(basename "$output")"
114
- return 0
115
- else
116
- echo " ✗ $family — heif-enc failed"
117
- return 1
118
- fi
119
- }
120
-
121
- echo "Dynamic wallpaper merger"
122
- echo ""
123
-
124
- if [[ -n "$TARGET" ]]; then
125
- merge_pair "$TARGET"
126
- else
127
- # Find all families with dark+light pairs
128
- merged=0
129
- failed=0
130
- for dark_file in "$WALLPAPER_DIR"/*-dark.heic "$WALLPAPER_DIR"/*-dark.jpg "$WALLPAPER_DIR"/*-dark.png; do
131
- [[ -f "$dark_file" ]] || continue
132
- base="$(basename "$dark_file")"
133
- family="${base%-dark.*}"
134
- if merge_pair "$family"; then
135
- merged=$((merged + 1))
136
- else
137
- failed=$((failed + 1))
138
- fi
139
- done
140
- echo ""
141
- echo "Done: $merged merged, $failed failed"
142
- if [[ "$DRY_RUN" != "true" && $merged -gt 0 ]]; then
143
- echo ""
144
- echo "Run 'dot theme rebuild --force' to regenerate themes for merged wallpapers."
145
- fi
146
- fi
@@ -1,544 +0,0 @@
1
- #!/usr/bin/env bash
2
- # SPDX-License-Identifier: 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
- # Clean orphaned cache files (wallpapers that no longer exist)
281
- for cache_file in "$CACHE_DIR"/*.toml; do
282
- [[ -f "$cache_file" ]] || continue
283
- cached_name="$(basename "$cache_file" .toml)"
284
- if [[ -z "${WALLPAPERS[$cached_name]+x}" ]]; then
285
- rm -f "$cache_file"
286
- fi
287
- done
288
-
289
- # ---------------------------------------------------------------------------
290
- # Generate themes
291
- # ---------------------------------------------------------------------------
292
-
293
- # Report distinct WALLPAPERS (families), not theme sections. Every
294
- # wallpaper — a dynamic HEIC (light+dark frames) or a static image —
295
- # yields a `-light` and a `-dark` theme, so a raw section count is ~2x
296
- # the file count and reads as wrong ("74 files → 148 custom"). Collapse
297
- # -dark/-light back to the family so the numbers match what's on disk
298
- # and what `dot theme list` shows, and report the theme total separately.
299
- # Explicit empty init: a `declare -A x` that never gets a key still trips
300
- # `set -u` on ${#x[@]} (even in bash 5) — happens now that system wallpapers
301
- # are opt-in and sys_fam can stay empty.
302
- declare -A sys_fam=() cust_fam=()
303
- for name in "${!WP_SOURCE[@]}"; do
304
- family="${name%-dark}"
305
- family="${family%-light}"
306
- case "${WP_SOURCE[$name]}" in
307
- system) sys_fam["$family"]=1 ;;
308
- custom) cust_fam["$family"]=1 ;;
309
- esac
310
- done
311
- sys_count=${#sys_fam[@]}
312
- cust_count=${#cust_fam[@]}
313
- echo "Discovering wallpapers..."
314
- echo " Found: $sys_count system, $cust_count custom wallpapers" \
315
- "($((sys_count + cust_count)) total → ${#WALLPAPERS[@]} light/dark themes)"
316
- echo ""
317
-
318
- GENERATED=0
319
- CACHED=0
320
- FAILED=0
321
-
322
- echo "Generating themes..."
323
-
324
- # Build work list (skip cached)
325
- WORK=()
326
- for name in $(printf '%s\n' "${!WALLPAPERS[@]}" | sort); do
327
- [[ -n "${WALLPAPERS[$name]+x}" ]] || continue
328
- wp_path="${WALLPAPERS[$name]}"
329
- cache_file="$CACHE_DIR/${name}.toml"
330
-
331
- if [[ "$FORCE" != "true" && -f "$cache_file" && "$cache_file" -nt "$wp_path" ]]; then
332
- CACHED=$((CACHED + 1))
333
- continue
334
- fi
335
- WORK+=("$name")
336
- done
337
-
338
- # Process in parallel (up to 4 jobs)
339
- JOBS=4
340
- TOTAL_WORK=${#WORK[@]}
341
- if [[ $TOTAL_WORK -gt 0 ]]; then
342
- echo " Processing $TOTAL_WORK wallpapers ($JOBS parallel jobs)..."
343
- for name in "${WORK[@]}"; do
344
- wp_path="${WALLPAPERS[$name]}"
345
- cache_file="$CACHE_DIR/${name}.toml"
346
- source_type="${WP_SOURCE[$name]}"
347
-
348
- (
349
- if python3 "$EXTRACT_SCRIPT" "$wp_path" --name "$name" --source "$source_type" >"$cache_file" 2>/dev/null; then
350
- printf " %-40s [%s] ✓\n" "$name" "$source_type"
351
- else
352
- rm -f "$cache_file"
353
- printf " %-40s [%s] ✗\n" "$name" "$source_type"
354
- fi
355
- ) &
356
-
357
- # Limit parallel jobs (bash >= 4 guaranteed by the guard at the top).
358
- while [[ $(jobs -r | wc -l) -ge $JOBS ]]; do
359
- wait -n 2>/dev/null || true
360
- done
361
- done
362
- wait
363
- fi
364
-
365
- # Count results — how many of THIS run's work items produced a cache file.
366
- # (The old `find -newer "$0"` counted every cache file newer than the script,
367
- # so when everything was cached FAILED went negative.)
368
- GENERATED=0
369
- FAILED=0
370
- for name in "${WORK[@]}"; do
371
- if [[ -f "$CACHE_DIR/${name}.toml" ]]; then
372
- GENERATED=$((GENERATED + 1))
373
- else
374
- FAILED=$((FAILED + 1))
375
- fi
376
- done
377
- echo ""
378
- echo "Results: $GENERATED generated, $CACHED cached, $FAILED failed"
379
-
380
- # ---------------------------------------------------------------------------
381
- # Assemble themes.toml
382
- # ---------------------------------------------------------------------------
383
-
384
- echo ""
385
- echo "Assembling themes.toml..."
386
-
387
- {
388
- cat <<'HEADER'
389
- # ============================================================================
390
- # Theme Manifest — Auto-generated from wallpaper dominant colors
391
- # ============================================================================
392
- # Generated by: scripts/theme/rebuild-themes.sh
393
- # Algorithm: K-Means clustering in CIELAB color space
394
- # Do not edit manually — run `dot theme rebuild` to regenerate.
395
- #
396
- # Sources:
397
- # System: /System/Library/Desktop Pictures/ (macOS)
398
- # /usr/share/backgrounds/ (Linux)
399
- # Custom: ~/Pictures/Wallpapers/
400
-
401
- HEADER
402
-
403
- # Assemble ONLY the wallpapers discovered this run, not every file left in
404
- # the cache. This drops themes for wallpapers no longer present (e.g. system
405
- # wallpapers once DOTFILES_THEME_SYSTEM is turned off) instead of letting
406
- # stale cache entries pile up in themes.toml.
407
- for name in $(printf '%s\n' "${!WALLPAPERS[@]}" | sort); do
408
- cache_file="$CACHE_DIR/${name}.toml"
409
- [[ -f "$cache_file" ]] || continue
410
- echo ""
411
- cat "$cache_file"
412
- done
413
-
414
- # Synthetic fallback themes — always emitted, never wallpaper-derived.
415
- # Every theme template degrades to `fallback-dark` when `.theme` is unset or
416
- # names a theme absent from this file. Because these are re-emitted on every
417
- # rebuild, a regeneration that drops any wallpaper theme can never break the
418
- # fallback (unlike hardcoding a wallpaper theme like the old big-sur-dark).
419
- # switch.sh hides the `fallback` family from user-facing theme lists.
420
- cat <<'FALLBACK'
421
-
422
- # ─────────────────────────────────────────────────────────────────────
423
- # Synthetic fallback themes (NOT wallpaper-derived, NEVER user-selectable).
424
- # ─────────────────────────────────────────────────────────────────────
425
-
426
- [themes.fallback-dark]
427
- mode = "dark"
428
- family = "fallback"
429
- macos_accent = 4
430
- wallpaper = ""
431
- source = "custom"
432
-
433
- [themes.fallback-dark.term]
434
- bg = "#1e1e2e"
435
- fg = "#d4d4d4"
436
- cursor = "#455c67"
437
- cursor_text = "#1e1e2e"
438
- sel_bg = "#394145"
439
- sel_fg = "#d4d4d4"
440
- c0 = "#3c3c4d"
441
- c1 = "#997d7a"
442
- c2 = "#479174"
443
- c3 = "#8a836f"
444
- c4 = "#5f86b7"
445
- c5 = "#917e8e"
446
- c6 = "#5c8d82"
447
- c7 = "#b9b8bb"
448
- c8 = "#605f72"
449
- c9 = "#bf9b97"
450
- c10 = "#67b293"
451
- c11 = "#aba389"
452
- c12 = "#7fa6d9"
453
- c13 = "#b49cb0"
454
- c14 = "#7bada1"
455
- c15 = "#e2e2e3"
456
-
457
- [themes.fallback-dark.ui]
458
- accent = "#455c67"
459
- accent_text = "#ffffff"
460
- error = "#997d7a"
461
- warning = "#8a836f"
462
- success = "#479174"
463
- info = "#5f86b7"
464
- panel = "#242435"
465
- border = "#302f38"
466
-
467
- [themes.fallback-dark.app]
468
- nvim = "tokyonight"
469
- nvim_style = "night"
470
- lualine = "tokyonight"
471
- gtk_theme = "Adwaita-dark"
472
- gtk_icon = "Papirus-Dark"
473
- gnome_shell = ""
474
- gnome_gtk = "Adwaita-dark"
475
- vscode = "Tokyonight Mocha"
476
- vscode_dark = "Tokyonight Mocha"
477
- vscode_light = "Tokyonight Latte"
478
- cat_wallpaper = ""
479
- starship_palette = "catppuccin_mocha"
480
-
481
-
482
- [themes.fallback-light]
483
- mode = "light"
484
- family = "fallback"
485
- macos_accent = 4
486
- wallpaper = ""
487
- source = "custom"
488
-
489
- [themes.fallback-light.term]
490
- bg = "#fbf1c7"
491
- fg = "#3c3836"
492
- cursor = "#2c5989"
493
- cursor_text = "#fbf1c7"
494
- sel_bg = "#c6cfe0"
495
- sel_fg = "#3c3836"
496
- c0 = "#2e2c26"
497
- c1 = "#7d3d39"
498
- c2 = "#205a48"
499
- c3 = "#5b501d"
500
- c4 = "#2b527d"
501
- c5 = "#6e4069"
502
- c6 = "#25554c"
503
- c7 = "#6f6d67"
504
- c8 = "#54524b"
505
- c9 = "#853733"
506
- c10 = "#025c46"
507
- c11 = "#5b500b"
508
- c12 = "#0d5388"
509
- c13 = "#743b6f"
510
- c14 = "#15564b"
511
- c15 = "#979693"
512
-
513
- [themes.fallback-light.ui]
514
- accent = "#2c5989"
515
- accent_text = "#ffffff"
516
- error = "#7d3d39"
517
- warning = "#5b501d"
518
- success = "#205a48"
519
- info = "#2b527d"
520
- panel = "#f2e8bf"
521
- border = "#e3e0d3"
522
-
523
- [themes.fallback-light.app]
524
- nvim = "catppuccin"
525
- nvim_style = "latte"
526
- lualine = "catppuccin"
527
- gtk_theme = "Adwaita"
528
- gtk_icon = "Papirus-Light"
529
- gnome_shell = ""
530
- gnome_gtk = "Adwaita"
531
- vscode = "Catppuccin Latte"
532
- vscode_dark = "Catppuccin Mocha"
533
- vscode_light = "Catppuccin Latte"
534
- cat_wallpaper = ""
535
- starship_palette = "catppuccin_latte"
536
- FALLBACK
537
- } >"$THEMES_FILE"
538
-
539
- # Count top-level [themes.NAME] blocks only — not the .term/.ui/.app
540
- # subsections (which inflated the tally ~4x).
541
- theme_count=$(grep -cE '^\[themes\.[a-z0-9-]+\]$' "$THEMES_FILE")
542
- echo " Written: $THEMES_FILE ($theme_count themes)"
543
- echo ""
544
- echo "Done. Run 'dot theme list' to see available themes."