@sebastienrousseau/dotfiles 0.2.501 → 0.2.503

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 (420) hide show
  1. package/CHANGELOG.md +155 -4
  2. package/LICENSE +21 -1283
  3. package/README.md +40 -8
  4. package/docs/CONFIG_STRATEGY.md +124 -0
  5. package/docs/COPYRIGHT +1 -1
  6. package/docs/GOVERNANCE.md +98 -0
  7. package/docs/MAINTAINERS.md +41 -0
  8. package/docs/OPENCODE.md +127 -0
  9. package/docs/README.md +2 -0
  10. package/docs/STRUCTURE.md +102 -0
  11. package/docs/adr/ADR-011-nushell-tier3-keep.md +2 -2
  12. package/docs/architecture/AI_COST_OPTIMIZATION.md +143 -0
  13. package/docs/architecture/REPO_LAYOUT.md +8 -8
  14. package/docs/archive/MILESTONE_v0.2.493.md +1 -1
  15. package/docs/index.md +2 -2
  16. package/docs/interop/POWERSHELL.md +1 -1
  17. package/docs/manual/00-introduction.md +1 -1
  18. package/docs/manual/01-concepts/02-trust-model.md +1 -1
  19. package/docs/manual/03-reference/01-dot-cli.md +63 -45
  20. package/docs/manual/03-reference/02-config-files.md +2 -2
  21. package/docs/manual/03-reference/05-feature-flags.md +62 -3
  22. package/docs/manual/_toc.yml +1 -1
  23. package/docs/manual/command-index.md +72 -55
  24. package/docs/manual/index.md +66 -0
  25. package/docs/operations/CI_COMPOSITES.md +2 -2
  26. package/docs/operations/COMPLETIONS.md +2 -2
  27. package/docs/operations/COVERAGE.md +40 -6
  28. package/docs/operations/HARD_AUDIT_2026.md +631 -0
  29. package/docs/operations/MAINTENANCE.md +3 -3
  30. package/docs/operations/MANIFEST.md +127 -0
  31. package/docs/operations/REGISTRY.md +89 -0
  32. package/docs/operations/RELEASE_PIPELINE.md +130 -0
  33. package/docs/operations/RFC_v0_2_503_reorganization.md +280 -0
  34. package/docs/operations/ROADMAP_2026.md +665 -0
  35. package/docs/operations/ROADMAP_V0_2_503.md +134 -0
  36. package/docs/operations/TESTING.md +17 -0
  37. package/docs/operations/TRACEABILITY.md +9 -3
  38. package/docs/operations/VERSION_SYNC.md +4 -4
  39. package/docs/reference/POWERSHELL_PARITY.md +81 -0
  40. package/docs/registry.json +6 -0
  41. package/docs/schema/dot-env-v1.json +110 -0
  42. package/docs/security/CI_EGRESS_ALLOWLIST.md +1 -1
  43. package/docs/security/CI_PINNING.md +121 -0
  44. package/docs/security/COMMIT_SIGNING.md +138 -0
  45. package/docs/security/DEPS_DEV_EXCEPTIONS.md +2 -2
  46. package/docs/security/DISCLOSURE.md +130 -0
  47. package/docs/security/FUZZING.md +114 -0
  48. package/docs/security/INSTALL_VERIFICATION.md +2 -2
  49. package/docs/security/KEY_ROTATION.md +81 -1
  50. package/docs/security/POLICY_RELEASES.md +2 -2
  51. package/docs/security/SCORECARD.md +130 -15
  52. package/docs/security/SHELL_EXEMPTIONS.md +4 -4
  53. package/docs/security/VERIFY_RELEASE.md +201 -0
  54. package/docs/security/security-pubkey.asc +15 -0
  55. package/install.sh +67 -38
  56. package/package.json +1 -1
  57. package/scripts/README.md +123 -0
  58. package/scripts/ci/check-copyright-headers.sh +4 -93
  59. package/scripts/ci/check-shell-preamble.sh +4 -103
  60. package/scripts/ci/guard-gitleaks-checkout.sh +4 -54
  61. package/scripts/diagnostics/a2a-conformance.sh +4 -4
  62. package/scripts/diagnostics/alias-governance.sh +1 -1
  63. package/scripts/diagnostics/aliases-cheatsheet.sh +2 -2
  64. package/scripts/diagnostics/benchmark.sh +4 -4
  65. package/scripts/diagnostics/conflicts.sh +2 -2
  66. package/scripts/diagnostics/doctor-unified.sh +2 -2
  67. package/scripts/diagnostics/doctor.sh +45 -15
  68. package/scripts/diagnostics/drift-dashboard.sh +2 -2
  69. package/scripts/diagnostics/health.sh +4 -4
  70. package/scripts/diagnostics/history-analysis.sh +2 -2
  71. package/scripts/diagnostics/mcp-doctor.sh +10 -7
  72. package/scripts/diagnostics/perf.sh +4 -4
  73. package/scripts/diagnostics/scorecard.sh +4 -4
  74. package/scripts/diagnostics/security-score.sh +2 -2
  75. package/scripts/diagnostics/smoke-test.sh +2 -2
  76. package/scripts/diagnostics/snapshot.sh +2 -2
  77. package/scripts/diagnostics/verify.sh +4 -4
  78. package/scripts/diagnostics/version-locks.sh +2 -2
  79. package/scripts/diagnostics/workstation-attestation.sh +14 -14
  80. package/scripts/dot/commands/agent.sh +27 -22
  81. package/scripts/dot/commands/agents.sh +335 -0
  82. package/scripts/dot/commands/ai.sh +144 -25
  83. package/scripts/dot/commands/aliases.sh +10 -8
  84. package/scripts/dot/commands/appearance.sh +2 -2
  85. package/scripts/dot/commands/core.sh +12 -6
  86. package/scripts/dot/commands/diagnostics.sh +5 -5
  87. package/scripts/dot/commands/env-emit.sh +202 -0
  88. package/scripts/dot/commands/fleet.sh +290 -14
  89. package/scripts/dot/commands/init.sh +184 -0
  90. package/scripts/dot/commands/lint.sh +9 -4
  91. package/scripts/dot/commands/manual.sh +3 -3
  92. package/scripts/dot/commands/meta.sh +19 -10
  93. package/scripts/dot/commands/patterns.sh +2 -2
  94. package/scripts/dot/commands/registry.sh +263 -0
  95. package/scripts/dot/commands/restore.sh +4 -4
  96. package/scripts/dot/commands/secrets.sh +4 -3
  97. package/scripts/dot/commands/security.sh +2 -2
  98. package/scripts/dot/commands/tools.sh +62 -4
  99. package/scripts/dot/powershell/Dot.psm1 +199 -0
  100. package/scripts/fonts/install-nerd-fonts.sh +2 -2
  101. package/scripts/git-hooks/pre-commit-audit.sh +2 -2
  102. package/scripts/git-hooks/pre-push +13 -0
  103. package/scripts/lib/secrets_provider.sh +32 -6
  104. package/scripts/ops/ai-setup.sh +1 -1
  105. package/scripts/ops/bundle.sh +2 -2
  106. package/scripts/ops/chaos.sh +2 -2
  107. package/scripts/ops/chezmoi-apply.sh +4 -4
  108. package/scripts/ops/heal.sh +4 -4
  109. package/scripts/ops/post-apply-repair.sh +2 -2
  110. package/scripts/ops/prewarm.sh +2 -2
  111. package/scripts/ops/release.sh +4 -4
  112. package/scripts/ops/rollback.sh +18 -4
  113. package/scripts/ops/setup.sh +2 -2
  114. package/scripts/qa/check-version-consistency.sh +123 -0
  115. package/scripts/qa/coverage-baseline.sh +1 -1
  116. package/scripts/qa/docs-coverage.sh +2 -2
  117. package/scripts/qa/powershell-contract.ps1 +1 -1
  118. package/scripts/qa/scorecard-snapshot.sh +127 -0
  119. package/scripts/security/backup.sh +2 -2
  120. package/scripts/security/check-disclosure-key-expiry.sh +110 -0
  121. package/scripts/security/dns-doh.sh +4 -4
  122. package/scripts/security/encryption-check.sh +4 -4
  123. package/scripts/security/enforce-policies.sh +2 -2
  124. package/scripts/security/firewall.sh +4 -4
  125. package/scripts/security/lock-configs.sh +11 -2
  126. package/scripts/security/lock-screen.sh +4 -4
  127. package/scripts/security/manage-secrets.sh +2 -2
  128. package/scripts/security/ssh-cert.sh +2 -2
  129. package/scripts/security/telemetry-kill.sh +4 -4
  130. package/scripts/security/usb-safety.sh +4 -4
  131. package/scripts/theme/extract-heic-frames.sh +114 -0
  132. package/scripts/theme/rebuild-themes.sh +8 -1
  133. package/scripts/theme/switch.sh +13 -6
  134. package/scripts/theme/wallpaper-sync.sh +297 -93
  135. package/scripts/tuning/linux.sh +2 -2
  136. package/scripts/tuning/macos.sh +2 -2
  137. package/scripts/version-sync.sh +58 -7
  138. package/dot_config/.module-manifest.json +0 -69
  139. package/dot_config/ai/identity.md +0 -23
  140. package/dot_config/ai/patterns/architect.md +0 -16
  141. package/dot_config/ai/patterns/hardener.md +0 -15
  142. package/dot_config/ai/patterns/refactor.md +0 -15
  143. package/dot_config/aider/aider.conf.yml +0 -32
  144. package/dot_config/alacritty/alacritty.toml.tmpl +0 -55
  145. package/dot_config/ansible/ansible.cfg +0 -11
  146. package/dot_config/atuin/config.toml.tmpl +0 -47
  147. package/dot_config/bat/config +0 -23
  148. package/dot_config/brave-flags.conf.tmpl +0 -7
  149. package/dot_config/btop/btop.conf +0 -16
  150. package/dot_config/btop/themes/tokyonight.theme +0 -34
  151. package/dot_config/bun/bunfig.toml.tmpl +0 -33
  152. package/dot_config/claude/mcp_servers.json +0 -20
  153. package/dot_config/containers/containers.conf +0 -14
  154. package/dot_config/curl/dot_curlrc +0 -18
  155. package/dot_config/dlv/config.yml +0 -39
  156. package/dot_config/docker/config.json +0 -15
  157. package/dot_config/dotfiles/agent-card.json +0 -29
  158. package/dot_config/dotfiles/agent-profiles.json +0 -92
  159. package/dot_config/dotfiles/boot/README.md +0 -13
  160. package/dot_config/dotfiles/grub/README.md +0 -13
  161. package/dot_config/dotfiles/lock/README.md +0 -13
  162. package/dot_config/dotfiles/mcp-lock.json +0 -33
  163. package/dot_config/dotfiles/mcp-policy.json +0 -52
  164. package/dot_config/dotfiles/mcp-registry.json +0 -47
  165. package/dot_config/dotfiles/model-registry.json +0 -20
  166. package/dot_config/dotfiles/policy-bundles.json +0 -38
  167. package/dot_config/dotfiles/prompt-registry.json +0 -16
  168. package/dot_config/dotfiles/versions.env +0 -18
  169. package/dot_config/duf/duf.conf +0 -6
  170. package/dot_config/duti/defaults.duti +0 -5
  171. package/dot_config/emoji/emoji.txt +0 -34
  172. package/dot_config/environment.d/50-ssh-agent.conf +0 -2
  173. package/dot_config/environment.d/90-wayland.conf +0 -19
  174. package/dot_config/fastfetch/config.jsonc +0 -28
  175. package/dot_config/firefox/user.js.tmpl +0 -58
  176. package/dot_config/fish/completions/dot-theme-sync.fish.tmpl +0 -9
  177. package/dot_config/fish/completions/dot.fish.tmpl +0 -115
  178. package/dot_config/fish/conf.d/000-perf-cache.fish +0 -56
  179. package/dot_config/fish/conf.d/aliases.fish.tmpl +0 -77
  180. package/dot_config/fish/conf.d/env.fish.tmpl +0 -48
  181. package/dot_config/fish/conf.d/functions.fish.tmpl +0 -22
  182. package/dot_config/fish/conf.d/init.fish.tmpl +0 -172
  183. package/dot_config/fish/config.fish.tmpl +0 -44
  184. package/dot_config/fish/fish_plugins +0 -1
  185. package/dot_config/fish/functions/_.fish +0 -3
  186. package/dot_config/fish/functions/_cached_eval.fish +0 -131
  187. package/dot_config/fish/functions/_cached_eval_clear.fish +0 -17
  188. package/dot_config/fish/functions/als.fish +0 -46
  189. package/dot_config/fish/functions/bg-upgrade.fish +0 -7
  190. package/dot_config/fish/functions/c.fish +0 -3
  191. package/dot_config/fish/functions/cat.fish +0 -9
  192. package/dot_config/fish/functions/d.fish +0 -7
  193. package/dot_config/fish/functions/dot.fish +0 -34
  194. package/dot_config/fish/functions/h.fish +0 -3
  195. package/dot_config/fish/functions/l.fish +0 -7
  196. package/dot_config/fish/functions/la.fish +0 -7
  197. package/dot_config/fish/functions/ll.fish +0 -7
  198. package/dot_config/fish/functions/log_error.fish +0 -13
  199. package/dot_config/fish/functions/log_info.fish +0 -13
  200. package/dot_config/fish/functions/lr.fish +0 -7
  201. package/dot_config/fish/functions/lra.fish +0 -7
  202. package/dot_config/fish/functions/ls.fish +0 -7
  203. package/dot_config/fish/functions/lt.fish +0 -7
  204. package/dot_config/fish/functions/lta.fish +0 -7
  205. package/dot_config/fish/functions/notify-run.fish +0 -11
  206. package/dot_config/fish/functions/q.fish +0 -3
  207. package/dot_config/fish/functions/silent-run.fish +0 -7
  208. package/dot_config/fish/functions/yy.fish +0 -8
  209. package/dot_config/flatpak/flatpak.list +0 -4
  210. package/dot_config/fontconfig/fonts.conf.tmpl +0 -57
  211. package/dot_config/foot/foot.ini.tmpl +0 -33
  212. package/dot_config/fuzzel/fuzzel.ini.tmpl +0 -18
  213. package/dot_config/fzf/fzf.zsh +0 -48
  214. package/dot_config/gem/gemrc +0 -9
  215. package/dot_config/gh/config.yml +0 -12
  216. package/dot_config/ghostty/config.tmpl +0 -165
  217. package/dot_config/git/allowed_signers.tmpl +0 -18
  218. package/dot_config/git/attributes +0 -12
  219. package/dot_config/git/commit-template +0 -10
  220. package/dot_config/git/hooks/executable_commit-msg +0 -146
  221. package/dot_config/git/ignore +0 -27
  222. package/dot_config/gnupg/gpg-agent.conf +0 -11
  223. package/dot_config/go/golangci.yml +0 -118
  224. package/dot_config/go/gopls.json +0 -30
  225. package/dot_config/goose/config.yaml +0 -29
  226. package/dot_config/gtk-3.0/gtk.css.tmpl +0 -184
  227. package/dot_config/gtk-3.0/settings.ini.tmpl +0 -27
  228. package/dot_config/gtk-4.0/gtk.css.tmpl +0 -252
  229. package/dot_config/gtk-4.0/settings.ini.tmpl +0 -18
  230. package/dot_config/htop/htoprc +0 -20
  231. package/dot_config/inputrc +0 -2
  232. package/dot_config/ipython/profile_default/ipython_config.py +0 -19
  233. package/dot_config/just/justfile +0 -122
  234. package/dot_config/k9s/config.yaml +0 -65
  235. package/dot_config/k9s/skins/catppuccin-mocha.yaml +0 -116
  236. package/dot_config/kanshi/config.tmpl +0 -22
  237. package/dot_config/karabiner/karabiner.json +0 -14
  238. package/dot_config/kitty/kitty.conf.tmpl +0 -53
  239. package/dot_config/lazydocker/config.yml +0 -186
  240. package/dot_config/lazygit/config.yml +0 -35
  241. package/dot_config/mako/config +0 -47
  242. package/dot_config/mas/masapps.txt +0 -5
  243. package/dot_config/micro/settings.json +0 -3
  244. package/dot_config/mimeapps.list +0 -77
  245. package/dot_config/minikube/config.json +0 -13
  246. package/dot_config/mise/config.toml +0 -99
  247. package/dot_config/mongosh/mongoshrc.js +0 -68
  248. package/dot_config/mpv/input.conf +0 -47
  249. package/dot_config/mpv/mpv.conf +0 -47
  250. package/dot_config/mycli/myclirc +0 -67
  251. package/dot_config/nano/nanorc +0 -28
  252. package/dot_config/ncdu/config +0 -12
  253. package/dot_config/niri/config.kdl.tmpl +0 -327
  254. package/dot_config/nushell/aliases.nu +0 -18
  255. package/dot_config/nushell/cached_eval.nu +0 -80
  256. package/dot_config/nushell/completions.nu.tmpl +0 -52
  257. package/dot_config/nushell/config.nu.tmpl +0 -86
  258. package/dot_config/nushell/env.nu.tmpl +0 -102
  259. package/dot_config/nushell/functions.nu.tmpl +0 -17
  260. package/dot_config/nvim/init.lua +0 -18
  261. package/dot_config/nvim/lazy-lock.json +0 -58
  262. package/dot_config/nvim/lua/config/autocmds.lua +0 -107
  263. package/dot_config/nvim/lua/config/keymaps.lua +0 -92
  264. package/dot_config/nvim/lua/config/lazy.lua +0 -44
  265. package/dot_config/nvim/lua/config/options.lua +0 -49
  266. package/dot_config/nvim/lua/plugins/ai.lua +0 -75
  267. package/dot_config/nvim/lua/plugins/coding.lua +0 -216
  268. package/dot_config/nvim/lua/plugins/completion.lua +0 -60
  269. package/dot_config/nvim/lua/plugins/dap.lua +0 -412
  270. package/dot_config/nvim/lua/plugins/editor.lua +0 -55
  271. package/dot_config/nvim/lua/plugins/git.lua +0 -10
  272. package/dot_config/nvim/lua/plugins/lsp.lua +0 -156
  273. package/dot_config/nvim/lua/plugins/markdown.lua +0 -18
  274. package/dot_config/nvim/lua/plugins/rust.lua +0 -34
  275. package/dot_config/nvim/lua/plugins/sessions.lua +0 -33
  276. package/dot_config/nvim/lua/plugins/ui.lua +0 -509
  277. package/dot_config/paru/paru.conf +0 -10
  278. package/dot_config/pip/pip.conf.tmpl +0 -32
  279. package/dot_config/powershell/Microsoft.PowerShell_profile.ps1.tmpl +0 -81
  280. package/dot_config/pueue/pueue.yml +0 -34
  281. package/dot_config/pypoetry/config.toml +0 -6
  282. package/dot_config/pyrightconfig.json +0 -5
  283. package/dot_config/raycast/README.md +0 -13
  284. package/dot_config/redis/redisclirc +0 -41
  285. package/dot_config/ripgrep/ripgreprc +0 -21
  286. package/dot_config/shell/00-core-paths.sh.tmpl +0 -134
  287. package/dot_config/shell/05-core-safety.sh +0 -48
  288. package/dot_config/shell/10-secrets.sh +0 -41
  289. package/dot_config/shell/40-fzf-defaults.sh.tmpl +0 -17
  290. package/dot_config/shell/40-ls-colors.sh +0 -49
  291. package/dot_config/shell/50-logic-functions-core.sh.tmpl +0 -11
  292. package/dot_config/shell/50-logic-functions.sh.tmpl +0 -11
  293. package/dot_config/shell/51-logic-functions-extra.sh.tmpl +0 -65
  294. package/dot_config/shell/90-ux-aliases.sh.tmpl +0 -121
  295. package/dot_config/shell/91-ux-aliases-lazy.sh.tmpl +0 -55
  296. package/dot_config/shell/Brewfile +0 -207
  297. package/dot_config/shell/Brewfile.cask +0 -92
  298. package/dot_config/shell/Brewfile.cli +0 -127
  299. package/dot_config/shell/README.md +0 -284
  300. package/dot_config/shell/als_data.txt.tmpl +0 -65
  301. package/dot_config/shell/custom/auto_ls.zsh +0 -20
  302. package/dot_config/shell/custom/context_suggest.zsh +0 -68
  303. package/dot_config/shell/custom/error_analysis.zsh +0 -45
  304. package/dot_config/sops/dot_sops.yaml +0 -23
  305. package/dot_config/starship.toml.tmpl +0 -202
  306. package/dot_config/swaylock/config +0 -43
  307. package/dot_config/systemd/user/dotfiles-maintenance.service +0 -8
  308. package/dot_config/systemd/user/dotfiles-maintenance.timer +0 -11
  309. package/dot_config/systemd/user/pueued.service +0 -12
  310. package/dot_config/systemd/user/ssh-agent.service +0 -12
  311. package/dot_config/task/Taskfile.yml +0 -86
  312. package/dot_config/tflint/tflint.hcl +0 -9
  313. package/dot_config/tmux/tmux.conf.tmpl +0 -223
  314. package/dot_config/topgrade.toml.tmpl +0 -54
  315. package/dot_config/user-dirs.dirs +0 -10
  316. package/dot_config/vscode/extensions.txt +0 -11
  317. package/dot_config/vscode/settings.json.tmpl +0 -82
  318. package/dot_config/waybar/config.jsonc.tmpl +0 -90
  319. package/dot_config/waybar/style.css.tmpl +0 -211
  320. package/dot_config/wezterm/wezterm.lua.tmpl +0 -64
  321. package/dot_config/wget/wgetrc +0 -12
  322. package/dot_config/xdg-desktop-portal/niri-portals.conf +0 -5
  323. package/dot_config/yarn/yarnrc.yml +0 -36
  324. package/dot_config/yazi/keymap.toml +0 -67
  325. package/dot_config/yazi/theme.toml +0 -102
  326. package/dot_config/yazi/yazi.toml +0 -40
  327. package/dot_config/zathura/zathurarc +0 -52
  328. package/dot_config/zellij/config.kdl.tmpl +0 -79
  329. package/dot_config/zsh/dot_zprofile +0 -7
  330. package/dot_config/zsh/dot_zshenv +0 -5
  331. package/dot_config/zsh/dot_zshrc.tmpl +0 -635
  332. package/dot_config/zsh/rc.d/00-alias-shims.zsh +0 -99
  333. package/dot_config/zsh/rc.d/05-ssh-agent.zsh +0 -18
  334. package/dot_config/zsh/rc.d/10-env.zsh.tmpl +0 -28
  335. package/dot_config/zsh/rc.d/20-zinit.zsh +0 -65
  336. package/dot_config/zsh/rc.d/30-options.zsh.tmpl +0 -214
  337. package/dot_config/zsh/rc.d/40-bell.zsh +0 -20
  338. package/dot_config/zsh/rc.d/50-login-fortune.zsh +0 -9
  339. package/dot_config/zsh/rc.d/99-alias-wrapper.zsh +0 -32
  340. package/dot_local/bin/executable_ai-update +0 -195
  341. package/dot_local/bin/executable_ai_core +0 -152
  342. package/dot_local/bin/executable_antigravity +0 -11
  343. package/dot_local/bin/executable_b64 +0 -84
  344. package/dot_local/bin/executable_bm +0 -79
  345. package/dot_local/bin/executable_cb +0 -39
  346. package/dot_local/bin/executable_dot +0 -596
  347. package/dot_local/bin/executable_dot-ai +0 -36
  348. package/dot_local/bin/executable_dot-bootstrap +0 -77
  349. package/dot_local/bin/executable_dot-launch-or-focus +0 -52
  350. package/dot_local/bin/executable_dot-load-benchmark +0 -31
  351. package/dot_local/bin/executable_dot-load-benchmark-pty +0 -77
  352. package/dot_local/bin/executable_dot-theme-sync +0 -952
  353. package/dot_local/bin/executable_dot_completion +0 -57
  354. package/dot_local/bin/executable_dtags +0 -28
  355. package/dot_local/bin/executable_epoch +0 -67
  356. package/dot_local/bin/executable_extract +0 -41
  357. package/dot_local/bin/executable_gbd +0 -52
  358. package/dot_local/bin/executable_gd +0 -42
  359. package/dot_local/bin/executable_git-ai-commit +0 -175
  360. package/dot_local/bin/executable_git-ai-diff +0 -169
  361. package/dot_local/bin/executable_gl +0 -101
  362. package/dot_local/bin/executable_hash +0 -161
  363. package/dot_local/bin/executable_hashsum +0 -160
  364. package/dot_local/bin/executable_hex +0 -115
  365. package/dot_local/bin/executable_jsonv +0 -78
  366. package/dot_local/bin/executable_jwt +0 -94
  367. package/dot_local/bin/executable_kill-port +0 -75
  368. package/dot_local/bin/executable_lorem +0 -118
  369. package/dot_local/bin/executable_mkscript +0 -35
  370. package/dot_local/bin/executable_monitor +0 -56
  371. package/dot_local/bin/executable_myip +0 -51
  372. package/dot_local/bin/executable_notify +0 -24
  373. package/dot_local/bin/executable_open +0 -38
  374. package/dot_local/bin/executable_pw +0 -27
  375. package/dot_local/bin/executable_rec-start +0 -46
  376. package/dot_local/bin/executable_rec-stop +0 -35
  377. package/dot_local/bin/executable_regex +0 -132
  378. package/dot_local/bin/executable_start-niri +0 -8
  379. package/dot_local/bin/executable_tmux-sessionizer +0 -314
  380. package/dot_local/bin/executable_tour +0 -177
  381. package/dot_local/bin/executable_up +0 -23
  382. package/dot_local/bin/executable_update +0 -142
  383. package/dot_local/bin/executable_uuid +0 -87
  384. package/dot_local/bin/executable_win +0 -32
  385. package/dot_local/bin/executable_yamlv +0 -57
  386. package/dot_local/share/bash-completion/completions/dot +0 -72
  387. package/dot_local/share/icons/hicolor/128x128/apps/rousseau.png +0 -0
  388. package/dot_local/share/icons/hicolor/16x16/apps/rousseau.png +0 -0
  389. package/dot_local/share/icons/hicolor/24x24/apps/rousseau.png +0 -0
  390. package/dot_local/share/icons/hicolor/256x256/apps/rousseau.png +0 -0
  391. package/dot_local/share/icons/hicolor/32x32/apps/rousseau.png +0 -0
  392. package/dot_local/share/icons/hicolor/48x48/apps/rousseau.png +0 -0
  393. package/dot_local/share/icons/hicolor/512x512/apps/rousseau.png +0 -0
  394. package/dot_local/share/icons/hicolor/64x64/apps/rousseau.png +0 -0
  395. package/dot_local/share/icons/hicolor/96x96/apps/rousseau.png +0 -0
  396. package/dot_local/share/icons/hicolor/scalable/apps/rousseau.png +0 -0
  397. package/dot_local/share/man/man1/dot.1 +0 -149
  398. package/dot_local/share/mise/plugins/kiro-cli/bin/executable_download +0 -64
  399. package/dot_local/share/mise/plugins/kiro-cli/bin/executable_install +0 -18
  400. package/dot_local/share/mise/plugins/kiro-cli/bin/executable_list-all +0 -13
  401. package/dot_local/share/wayland-sessions/niri.desktop.tmpl +0 -6
  402. package/dot_local/share/zsh/completions/.keep +0 -0
  403. package/dot_local/share/zsh/completions/_dot +0 -283
  404. package/scripts/ci/check-dangerous-chmod.sh +0 -19
  405. package/scripts/ci/check-deps-dev.sh +0 -236
  406. package/scripts/ci/check-insecure-tls.sh +0 -61
  407. package/scripts/ci/check-regression-traceability.sh +0 -67
  408. package/scripts/ci/install-chezmoi-verified.sh +0 -64
  409. package/scripts/ci/run-coverage.sh +0 -362
  410. package/scripts/ci/validate-chezmoidata.sh +0 -25
  411. package/scripts/ci/validate-ci-config.sh +0 -224
  412. package/scripts/docs/build-manual.sh +0 -883
  413. package/scripts/docs/check-manual.sh +0 -213
  414. package/scripts/dot/lib/bento.sh +0 -50
  415. package/scripts/dot/lib/log.sh +0 -200
  416. package/scripts/dot/lib/platform.sh +0 -99
  417. package/scripts/dot/lib/ui.sh +0 -518
  418. package/scripts/dot/lib/utils.sh +0 -377
  419. package/scripts/maintenance/check-updates.sh +0 -131
  420. package/scripts/release/package-policy-bundles.sh +0 -125
@@ -3,16 +3,26 @@
3
3
  set -euo pipefail
4
4
 
5
5
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- # shellcheck source=../dot/lib/ui.sh
6
+ # shellcheck source=../../lib/dot/ui.sh
7
7
  # shellcheck disable=SC1091
8
- source "$SCRIPT_DIR/../dot/lib/ui.sh"
8
+ source "$SCRIPT_DIR/../../lib/dot/ui.sh"
9
9
 
10
10
  ui_init
11
11
  ui_header "Wallpaper Sync"
12
12
 
13
13
  WALLPAPER_DIR="${DOTFILES_WALLPAPER_DIR:-$HOME/Pictures/Wallpapers}"
14
14
  CHEZMOI_CFG="${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.toml"
15
- DATA_FILE="${HOME}/.dotfiles/.chezmoidata.toml"
15
+
16
+ # Resolve dotfiles repo root, then descend into chezmoi source subdir if
17
+ # .chezmoiroot is present (v0.2.503+, where chezmoi files live in defaults/)
18
+ _DOTFILES_ROOT="${HOME}/.dotfiles"
19
+ [[ ! -d "$_DOTFILES_ROOT" && -d "${HOME}/.local/share/chezmoi" ]] && _DOTFILES_ROOT="${HOME}/.local/share/chezmoi"
20
+ _CHEZMOI_SRC="$_DOTFILES_ROOT"
21
+ if [[ -f "$_DOTFILES_ROOT/.chezmoiroot" ]]; then
22
+ _sub="$(head -1 "$_DOTFILES_ROOT/.chezmoiroot" | tr -d '[:space:]')"
23
+ [[ -n "$_sub" && -d "$_DOTFILES_ROOT/$_sub" ]] && _CHEZMOI_SRC="$_DOTFILES_ROOT/$_sub"
24
+ fi
25
+ DATA_FILE="${_CHEZMOI_SRC}/.chezmoidata.toml"
16
26
 
17
27
  WALLPAPER_DIR_EXISTS=true
18
28
  if [ ! -d "$WALLPAPER_DIR" ]; then
@@ -44,8 +54,6 @@ detect_mode() {
44
54
  fi
45
55
  }
46
56
 
47
- MODE="$(detect_mode)"
48
-
49
57
  current_theme() {
50
58
  if [[ -f "$CHEZMOI_CFG" ]]; then
51
59
  local chezmoi_theme
@@ -70,23 +78,26 @@ wallpaper_for_theme() {
70
78
  [[ -n "$theme" ]] || return 1
71
79
  [[ -n "$mode" ]] || return 1
72
80
 
73
- # 1. Check themes.toml for stored wallpaper path (set by extract-theme.py)
74
- local themes_file="${HOME}/.dotfiles/.chezmoidata/themes.toml"
75
- if [[ -f "$themes_file" ]]; then
76
- local stored_wp
77
- stored_wp="$(awk -v n="$theme" '
78
- $0 == "[themes." n "]" { found=1; next }
79
- /^\[/ { found=0 }
80
- found && /^wallpaper/ { sub(/.*= *"/, ""); sub(/".*/, ""); print; exit }
81
- ' "$themes_file")"
82
- if [[ -n "$stored_wp" && -f "$stored_wp" ]]; then
83
- printf '%s\n' "$stored_wp"
81
+ family="${theme%-dark}"
82
+ if [[ "$family" == "$theme" ]]; then
83
+ family="${theme%-light}"
84
+ fi
85
+
86
+ # 1. Prefer pre-extracted frames (fast, no conversion needed).
87
+ # Convention: {family}-0.png = light, {family}-1.png = dark.
88
+ # These are created externally (e.g. ImageMagick/ffmpeg from dynamic HEIC).
89
+ local frame_idx=0
90
+ [[ "$mode" == "dark" ]] && frame_idx=1
91
+ for ext in png jpg webp; do
92
+ candidate="$WALLPAPER_DIR/${family}-${frame_idx}.${ext}"
93
+ if [[ -f "$candidate" ]]; then
94
+ printf '%s\n' "$candidate"
84
95
  return 0
85
96
  fi
86
- fi
97
+ done
87
98
 
88
- # 2. Check custom wallpaper directory
89
- for ext in heic jpg png; do
99
+ # 2. Check exact theme name (e.g. hello-dark.png)
100
+ for ext in png jpg webp heic; do
90
101
  candidate="$WALLPAPER_DIR/${theme}.${ext}"
91
102
  if [[ -f "$candidate" ]]; then
92
103
  printf '%s\n' "$candidate"
@@ -94,11 +105,8 @@ wallpaper_for_theme() {
94
105
  fi
95
106
  done
96
107
 
97
- family="${theme%-dark}"
98
- if [[ "$family" == "$theme" ]]; then
99
- family="${theme%-light}"
100
- fi
101
- for ext in heic jpg png; do
108
+ # 3. Check family-mode variant (e.g. hello-dark.png)
109
+ for ext in png jpg webp heic; do
102
110
  candidate="$WALLPAPER_DIR/${family}-${mode}.${ext}"
103
111
  if [[ -f "$candidate" ]]; then
104
112
  printf '%s\n' "$candidate"
@@ -106,6 +114,58 @@ wallpaper_for_theme() {
106
114
  fi
107
115
  done
108
116
 
117
+ # 4. Check themes.toml stored wallpaper path (set by extract-theme.py)
118
+ local themes_file="${_CHEZMOI_SRC}/.chezmoidata/themes.toml"
119
+ if [[ -f "$themes_file" ]]; then
120
+ local stored_wp
121
+ stored_wp="$(awk -v n="$theme" '
122
+ $0 == "[themes." n "]" { found=1; next }
123
+ /^\[/ { found=0 }
124
+ found && /^wallpaper/ { sub(/.*= *"/, ""); sub(/".*/, ""); print; exit }
125
+ ' "$themes_file")"
126
+ if [[ -n "$stored_wp" ]]; then
127
+ # Cross-platform: resolve macOS paths on Linux
128
+ if [[ ! -f "$stored_wp" ]]; then
129
+ if [[ "$stored_wp" == /Users/* ]]; then
130
+ # /Users/<user>/Pictures/... → $HOME/Pictures/...
131
+ stored_wp="${HOME}/${stored_wp#/Users/*/}"
132
+ elif [[ "$stored_wp" == /System/* ]]; then
133
+ # macOS system wallpapers don't exist on Linux — skip to next fallback
134
+ stored_wp=""
135
+ fi
136
+ fi
137
+ if [[ -n "$stored_wp" && -f "$stored_wp" ]]; then
138
+ printf '%s\n' "$stored_wp"
139
+ return 0
140
+ fi
141
+ fi
142
+ fi
143
+
144
+ # 5. Check family-only file (e.g. hello.heic — dynamic wallpaper).
145
+ # For HEIC on Linux, extract frames first then return the correct one.
146
+ for ext in png jpg webp; do
147
+ candidate="$WALLPAPER_DIR/${family}.${ext}"
148
+ if [[ -f "$candidate" ]]; then
149
+ printf '%s\n' "$candidate"
150
+ return 0
151
+ fi
152
+ done
153
+ candidate="$WALLPAPER_DIR/${family}.heic"
154
+ if [[ -f "$candidate" ]] && [[ "$(uname -s)" == "Linux" ]]; then
155
+ # Extract frames from HEIC then return the mode-appropriate one
156
+ ensure_linux_compatible "$candidate" >/dev/null
157
+ # Re-check for extracted frames
158
+ for fext in png jpg; do
159
+ if [[ -f "$WALLPAPER_DIR/${family}-${frame_idx}.${fext}" ]]; then
160
+ printf '%s\n' "$WALLPAPER_DIR/${family}-${frame_idx}.${fext}"
161
+ return 0
162
+ fi
163
+ done
164
+ elif [[ -f "$candidate" ]]; then
165
+ printf '%s\n' "$candidate"
166
+ return 0
167
+ fi
168
+
109
169
  return 1
110
170
  }
111
171
 
@@ -122,24 +182,27 @@ system_wallpaper_for_theme() {
122
182
 
123
183
  [[ -n "$theme" ]] || return 1
124
184
 
125
- # macOS: map theme names to Apple system wallpapers
185
+ # macOS: map theme names to Apple system wallpapers.
186
+ # Plain case statement (not `local -A`) because macOS still ships
187
+ # /bin/bash 3.2 which doesn't support associative arrays. Users who
188
+ # have brew bash get the same behaviour; first-run users with stock
189
+ # bash do too.
126
190
  if [[ "$(uname -s)" == "Darwin" && -d "$SYS_MAC" ]]; then
127
- local -A mac_map=(
128
- [macos - sonoma]="$SYS_MAC/Sonoma.heic"
129
- [macos - blue]="$SYS_MAC/Mac Blue.heic"
130
- [macos - pink]="$SYS_MAC/Mac Pink.heic"
131
- [macos - purple]="$SYS_MAC/Mac Purple.heic"
132
- [macos - yellow]="$SYS_MAC/Mac Yellow.heic"
133
- [macos - orange]="$SYS_MAC/iMac Orange.heic"
134
- [macos - green]="$SYS_MAC/iMac Green.heic"
135
- [macos - silver]="$SYS_MAC/iMac Silver.heic"
136
- )
137
-
138
191
  # Extract family from theme name (strip -dark/-light)
139
192
  local family="${theme%-dark}"
140
193
  [[ "$family" == "$theme" ]] && family="${theme%-light}"
141
194
 
142
- local sys_wp="${mac_map[$family]:-}"
195
+ local sys_wp=""
196
+ case "$family" in
197
+ "macos - sonoma") sys_wp="$SYS_MAC/Sonoma.heic" ;;
198
+ "macos - blue") sys_wp="$SYS_MAC/Mac Blue.heic" ;;
199
+ "macos - pink") sys_wp="$SYS_MAC/Mac Pink.heic" ;;
200
+ "macos - purple") sys_wp="$SYS_MAC/Mac Purple.heic" ;;
201
+ "macos - yellow") sys_wp="$SYS_MAC/Mac Yellow.heic" ;;
202
+ "macos - orange") sys_wp="$SYS_MAC/iMac Orange.heic" ;;
203
+ "macos - green") sys_wp="$SYS_MAC/iMac Green.heic" ;;
204
+ "macos - silver") sys_wp="$SYS_MAC/iMac Silver.heic" ;;
205
+ esac
143
206
  if [[ -n "$sys_wp" && -f "$sys_wp" ]]; then
144
207
  printf '%s\n' "$sys_wp"
145
208
  return 0
@@ -155,7 +218,7 @@ system_wallpaper_for_theme() {
155
218
  for dir in "${SYS_LINUX_DIRS[@]}"; do
156
219
  [[ -d "$dir" ]] || continue
157
220
  local match
158
- match="$(find "$dir" -maxdepth 3 -type f \( -name "*.jpg" -o -name "*.png" \) \
221
+ match="$(find "$dir" -maxdepth 3 -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.webp" \) \
159
222
  -iname "*${keyword}*" 2>/dev/null | head -1)"
160
223
  if [[ -n "$match" ]]; then
161
224
  printf '%s\n' "$match"
@@ -208,7 +271,16 @@ pick_wallpaper() {
208
271
 
209
272
  while IFS= read -r line; do
210
273
  files+=("$line")
211
- done < <(find "$WALLPAPER_DIR" -maxdepth 1 -type f \( -iname "*-${mode}.jpg" -o -iname "*-${mode}.png" -o -iname "*-${mode}.heic" \) | sort)
274
+ done < <(find "$WALLPAPER_DIR" -maxdepth 1 -type f \( -iname "*-${mode}.jpg" -o -iname "*-${mode}.png" -o -iname "*-${mode}.webp" -o -iname "*-${mode}.heic" \) | sort)
275
+
276
+ # Fallback: search for extracted frames (-0 = light, -1 = dark)
277
+ if [[ ${#files[@]} -eq 0 ]]; then
278
+ local frame_suffix=0
279
+ [[ "$mode" == "dark" ]] && frame_suffix=1
280
+ while IFS= read -r line; do
281
+ files+=("$line")
282
+ done < <(find "$WALLPAPER_DIR" -maxdepth 1 -type f \( -iname "*-${frame_suffix}.jpg" -o -iname "*-${frame_suffix}.png" -o -iname "*-${frame_suffix}.webp" \) | sort)
283
+ fi
212
284
 
213
285
  if [[ ${#files[@]} -eq 0 ]]; then
214
286
  return 1
@@ -223,6 +295,17 @@ pick_wallpaper() {
223
295
  }
224
296
 
225
297
  THEME="$(current_theme || true)"
298
+
299
+ # Derive mode from theme name (authoritative) instead of querying DMS
300
+ # which may have just restarted and report stale state.
301
+ if [[ "$THEME" == *-dark ]]; then
302
+ MODE="dark"
303
+ elif [[ "$THEME" == *-light ]]; then
304
+ MODE="light"
305
+ else
306
+ MODE="$(detect_mode)"
307
+ fi
308
+
226
309
  WALLPAPER=""
227
310
  if [[ "$WALLPAPER_DIR_EXISTS" == "true" ]]; then
228
311
  WALLPAPER="$(pick_wallpaper "$MODE" "$THEME" || true)"
@@ -254,28 +337,61 @@ ensure_linux_compatible() {
254
337
  }
255
338
 
256
339
  local png="${wp%.heic}.png"
340
+ # Use cached PNG only if it exists, is newer than source, and is > 1MB
341
+ # (corrupt/truncated conversions produce tiny files that crash matugen).
257
342
  if [[ -f "$png" ]] && [[ "$png" -nt "$wp" ]]; then
258
- printf '%s\n' "$png"
259
- return
343
+ local fsize
344
+ fsize="$(stat -c%s "$png" 2>/dev/null || stat -f%z "$png" 2>/dev/null || echo 0)"
345
+ if [[ "$fsize" -gt 1000000 ]]; then
346
+ printf '%s\n' "$png"
347
+ return
348
+ fi
260
349
  fi
261
350
 
351
+ # Write to temp file then atomic move — prevents DMS/matugen from
352
+ # reading a partially-written PNG during multi-frame HEIC extraction.
353
+ local tmp_png
354
+ tmp_png="$(mktemp "${png%.png}.XXXXXX.png")"
355
+
262
356
  if command -v magick &>/dev/null; then
263
- magick "$wp" -quality 95 "$png" 2>/dev/null && {
264
- printf '%s\n' "$png"
357
+ magick "$wp" -quality 95 "$tmp_png" 2>/dev/null && {
358
+ # Multi-frame HEIC: magick creates {name}-0.png, {name}-1.png etc.
359
+ # Move each extracted frame to its final location atomically.
360
+ local tmp_base="${tmp_png%.png}"
361
+ local final_base="${png%.png}"
362
+ if [[ -f "${tmp_base}-0.png" ]]; then
363
+ for f in "${tmp_base}"-*.png; do
364
+ local suffix="${f#"$tmp_base"}"
365
+ mv -f "$f" "${final_base}${suffix}" 2>/dev/null
366
+ done
367
+ rm -f "$tmp_png" 2>/dev/null
368
+ # Return the correct frame: -0 = light, -1 = dark
369
+ if [[ -f "${final_base}-0.png" ]]; then
370
+ printf '%s\n' "${final_base}-0.png"
371
+ else
372
+ printf '%s\n' "$png"
373
+ fi
374
+ else
375
+ mv -f "$tmp_png" "$png" 2>/dev/null
376
+ printf '%s\n' "$png"
377
+ fi
265
378
  return
266
379
  }
267
380
  elif command -v heif-convert &>/dev/null; then
268
- heif-convert "$wp" "$png" 2>/dev/null && {
381
+ heif-convert "$wp" "$tmp_png" 2>/dev/null && {
382
+ mv -f "$tmp_png" "$png" 2>/dev/null
269
383
  printf '%s\n' "$png"
270
384
  return
271
385
  }
272
386
  elif command -v convert &>/dev/null; then
273
- convert "$wp" "$png" 2>/dev/null && {
387
+ convert "$wp" "$tmp_png" 2>/dev/null && {
388
+ mv -f "$tmp_png" "$png" 2>/dev/null
274
389
  printf '%s\n' "$png"
275
390
  return
276
391
  }
277
392
  fi
278
393
 
394
+ rm -f "$tmp_png" 2>/dev/null
279
395
  # Fallback: use original and hope the DE supports it
280
396
  printf '%s\n' "$wp"
281
397
  }
@@ -291,72 +407,160 @@ apply_wallpaper() {
291
407
 
292
408
  case "$(uname -s)" in
293
409
  Darwin)
294
- osascript -e "tell application \"System Events\" to set picture of every desktop to POSIX file \"$wp\"" || true
410
+ # macOS Sonoma+ moved wallpaper state to ~/Library/Application Support/
411
+ # com.apple.wallpaper/Store/Index.plist, owned by WallpaperAgent. Each
412
+ # Space and Display has its own entry, and AppleScript's `every desktop`
413
+ # only sees the active Space — so the only reliable way to cover all
414
+ # desktops is to rewrite each entry in Index.plist directly.
415
+ #
416
+ # The Configuration field of each choice is itself a nested binary plist
417
+ # of the form: {type: 'imageFile', url: {relative: 'file:///path'}}
418
+ # The store has several shapes: Spaces[uuid].Default.Desktop (per-Space
419
+ # wallpaper), Spaces[uuid].Default.Linked (desktop + screensaver share
420
+ # one image), and per-display nesting under Spaces[uuid].Displays[uuid].
421
+ # Walk the tree and patch any node that holds a wallpaper Choice list.
422
+ # After updating, killall WallpaperAgent so launchd respawns it and it
423
+ # re-reads the store.
424
+ python3 - "$wp" <<'PYEOF' 2>/dev/null || true
425
+ import plistlib, os, sys
426
+ wp = sys.argv[1]
427
+ uri = "file://" + wp
428
+ store = os.path.expanduser(
429
+ "~/Library/Application Support/com.apple.wallpaper/Store/Index.plist"
430
+ )
431
+ if not os.path.exists(store):
432
+ sys.exit(0)
433
+
434
+ def make_config(uri):
435
+ return plistlib.dumps(
436
+ {"type": "imageFile", "url": {"relative": uri}},
437
+ fmt=plistlib.FMT_BINARY,
438
+ )
439
+
440
+ def patch_node(node, uri):
441
+ """Patch a Desktop/Linked node in-place. Returns 1 if patched."""
442
+ content = node.get("Content")
443
+ if not isinstance(content, dict):
444
+ return 0
445
+ choices = content.get("Choices")
446
+ if not isinstance(choices, list) or not choices:
447
+ return 0
448
+ first = choices[0]
449
+ if not isinstance(first, dict):
450
+ return 0
451
+ first["Configuration"] = make_config(uri)
452
+ first["Provider"] = "com.apple.wallpaper.choice.image"
453
+ first["Files"] = []
454
+ content["Choices"] = [first]
455
+ content["Shuffle"] = "$null"
456
+ # Leave EncodedOptionValues alone — it stores crop/color and is per-image.
457
+ return 1
458
+
459
+ # Recursively patch every wallpaper-bearing node. A node qualifies when it
460
+ # has a Content.Choices list — this matches Desktop and Linked entries
461
+ # wherever they appear (top-level Displays, AllSpacesAndDisplays, Spaces[*]
462
+ # .Default, Spaces[*].Displays[*], etc.) and ignores Idle (screensaver) so
463
+ # we don't clobber the user's lock-screen wallpaper.
464
+ def walk(node, uri, key=None):
465
+ count = 0
466
+ if isinstance(node, dict):
467
+ if key in ("Desktop", "Linked") and "Content" in node:
468
+ count += patch_node(node, uri)
469
+ else:
470
+ for k, v in node.items():
471
+ count += walk(v, uri, k)
472
+ elif isinstance(node, list):
473
+ for item in node:
474
+ count += walk(item, uri)
475
+ return count
476
+
477
+ with open(store, "rb") as f:
478
+ data = plistlib.load(f)
479
+
480
+ # Safety backup before mutating.
481
+ try:
482
+ with open(store + ".dot-bak", "wb") as f:
483
+ plistlib.dump(data, f, fmt=plistlib.FMT_BINARY)
484
+ except Exception:
485
+ pass
486
+
487
+ updated = walk(data, uri)
488
+
489
+ if updated:
490
+ with open(store, "wb") as f:
491
+ plistlib.dump(data, f, fmt=plistlib.FMT_BINARY)
492
+
493
+ print(updated)
494
+ PYEOF
495
+
496
+ # Restart WallpaperAgent so it re-reads the store. launchd respawns it.
497
+ killall WallpaperAgent 2>/dev/null || true
498
+
499
+ # Also nudge the active Space via the public API. This covers the
500
+ # initial render before WallpaperAgent comes back, and handles screens
501
+ # the Index.plist rewrite somehow missed.
502
+ if command -v wallpaper &>/dev/null; then
503
+ wallpaper set "$wp" --screen all 2>/dev/null || true
504
+ else
505
+ osascript -e "
506
+ tell application \"System Events\"
507
+ set theFile to POSIX file \"${wp}\"
508
+ repeat with d in (get every desktop)
509
+ set picture of d to theFile
510
+ end repeat
511
+ end tell" 2>/dev/null || true
512
+ fi
295
513
  ;;
296
514
  Linux)
297
- # Niri + DMS/Quickshell uses its own wallpaper state.
515
+ # DMS owns wallpaper display and runs matugen for color extraction.
516
+ # Set the wallpaper ONCE for the current mode — DMS handles the rest.
517
+ # Multiple IPC calls (pair-setting, mode switching) cause matugen
518
+ # worker crashes and slow transitions. Keep it simple.
298
519
  if command -v dms &>/dev/null; then
299
- local dms_result current_outputs output current_dms_mode light_wp dark_wp
520
+ local dms_result current_outputs output
300
521
  dms_result="$(dms ipc wallpaper set "$wp" 2>/dev/null || true)"
301
522
  if [[ "$dms_result" == SUCCESS:* ]]; then
302
- ui_info "Applied via" "dms ipc wallpaper set"
523
+ ui_info "Applied via" "dms ipc"
303
524
  elif [[ "$dms_result" == ERROR:\ Per-monitor\ mode\ enabled* ]]; then
304
525
  current_outputs="$(dms ipc outputs current 2>/dev/null | tr -d '[]"')"
305
526
  for output in ${current_outputs//,/ }; do
306
527
  [[ -n "$output" ]] || continue
307
528
  dms ipc wallpaper setFor "$output" "$wp" >/dev/null 2>&1 || true
308
529
  done
309
- ui_info "Applied via" "dms ipc wallpaper setFor"
310
- else
311
- ui_warn "DMS wallpaper" "set failed, falling back"
312
- fi
313
-
314
- # Keep DMS light/dark wallpaper slots aligned with the theme family.
315
- if [[ -n "${THEME:-}" ]] && mapfile -t _pair < <(theme_wallpaper_pair "$THEME"); then
316
- light_wp="${_pair[0]:-}"
317
- dark_wp="${_pair[1]:-}"
318
- current_dms_mode="$(dms ipc theme getMode 2>/dev/null || printf '%s\n' "$mode")"
319
-
320
- if [[ -n "$light_wp" && -n "$dark_wp" ]]; then
321
- dms ipc theme light >/dev/null 2>&1 || true
322
- dms ipc wallpaper set "$light_wp" >/dev/null 2>&1 || true
323
-
324
- dms ipc theme dark >/dev/null 2>&1 || true
325
- dms ipc wallpaper set "$dark_wp" >/dev/null 2>&1 || true
326
-
327
- if [[ "$current_dms_mode" == "light" ]]; then
328
- dms ipc theme light >/dev/null 2>&1 || true
329
- else
330
- dms ipc theme dark >/dev/null 2>&1 || true
331
- fi
332
- ui_info "DMS pair" "$(basename "$light_wp"), $(basename "$dark_wp")"
333
- fi
530
+ ui_info "Applied via" "dms ipc (per-monitor)"
334
531
  fi
335
532
  fi
336
533
 
337
534
  # gsettings-based desktop state for GTK/freedesktop consumers
338
535
  if command -v gsettings &>/dev/null; then
339
- # Find the matching pair for picture-uri and picture-uri-dark
340
- local light_wp dark_wp base ext
536
+ # Find the matching pair for picture-uri and picture-uri-dark.
537
+ # Wallpapers use two naming conventions:
538
+ # -light/-dark (e.g. hello-light.png, hello-dark.png)
539
+ # -0/-1 (e.g. hello-0.png = light, hello-1.png = dark)
540
+ local light_wp="" dark_wp="" base ext family_base
341
541
  ext="${wp##*.}"
542
+ # Strip -light/-dark suffix to get family base
342
543
  base="${wp%-${mode}.${ext}}"
343
- if [[ -f "${base}-light.${ext}" ]] && [[ -f "${base}-dark.${ext}" ]]; then
344
- light_wp="${base}-light.${ext}"
345
- dark_wp="${base}-dark.${ext}"
346
- elif [[ -f "${base}-light.heic" ]] && [[ -f "${base}-dark.heic" ]]; then
347
- light_wp="${base}-light.heic"
348
- dark_wp="${base}-dark.heic"
349
- elif [[ -f "${base}-light.jpg" ]] && [[ -f "${base}-dark.jpg" ]]; then
350
- light_wp="${base}-light.jpg"
351
- dark_wp="${base}-dark.jpg"
352
- elif [[ -f "${base}-light.png" ]] && [[ -f "${base}-dark.png" ]]; then
353
- light_wp="${base}-light.png"
354
- dark_wp="${base}-dark.png"
355
- else
356
- light_wp=""
357
- dark_wp=""
544
+ # Strip -0/-1 suffix to get family base for frame naming
545
+ family_base="${wp%-[01].${ext}}"
546
+ # If neither pattern matched, both equal $wp — derive family from theme
547
+ if [[ "$family_base" == "$wp" && "$base" == "$wp" ]]; then
548
+ family_base="${WALLPAPER_DIR}/${THEME%-dark}"
549
+ [[ "$family_base" == "${WALLPAPER_DIR}/${THEME}" ]] && family_base="${WALLPAPER_DIR}/${THEME%-light}"
550
+ base="$family_base"
358
551
  fi
359
552
 
553
+ for try_ext in "$ext" png jpg webp heic; do
554
+ [[ -z "$light_wp" ]] || break
555
+ if [[ -f "${base}-light.${try_ext}" ]] && [[ -f "${base}-dark.${try_ext}" ]]; then
556
+ light_wp="${base}-light.${try_ext}"
557
+ dark_wp="${base}-dark.${try_ext}"
558
+ elif [[ -f "${family_base}-0.${try_ext}" ]] && [[ -f "${family_base}-1.${try_ext}" ]]; then
559
+ light_wp="${family_base}-0.${try_ext}"
560
+ dark_wp="${family_base}-1.${try_ext}"
561
+ fi
562
+ done
563
+
360
564
  if [[ -n "$light_wp" ]] && [[ -n "$dark_wp" ]]; then
361
565
  light_wp="$(ensure_linux_compatible "$light_wp")"
362
566
  dark_wp="$(ensure_linux_compatible "$dark_wp")"
@@ -391,7 +595,7 @@ apply_wallpaper() {
391
595
 
392
596
  apply_wallpaper "$WALLPAPER" "$MODE"
393
597
  if [[ -n "$THEME" ]]; then
394
- ui_ok "Wallpaper applied (${MODE})" "$(basename "$WALLPAPER") ← $THEME"
598
+ ui_ok "Applied wallpaper (${MODE})" "$(basename "$WALLPAPER") ← $THEME"
395
599
  else
396
- ui_ok "Wallpaper applied (${MODE})" "$(basename "$WALLPAPER")"
600
+ ui_ok "Applied wallpaper (${MODE})" "$(basename "$WALLPAPER")"
397
601
  fi
@@ -9,9 +9,9 @@
9
9
  set -euo pipefail
10
10
 
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
- # shellcheck source=../dot/lib/ui.sh
12
+ # shellcheck source=../../lib/dot/ui.sh
13
13
  # shellcheck disable=SC1091
14
- source "$SCRIPT_DIR/../dot/lib/ui.sh"
14
+ source "$SCRIPT_DIR/../../lib/dot/ui.sh"
15
15
 
16
16
  ui_init
17
17
  ui_header "Linux Tuning"
@@ -5,9 +5,9 @@
5
5
  set -euo pipefail
6
6
 
7
7
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- # shellcheck source=../dot/lib/ui.sh
8
+ # shellcheck source=../../lib/dot/ui.sh
9
9
  # shellcheck disable=SC1091
10
- source "$SCRIPT_DIR/../dot/lib/ui.sh"
10
+ source "$SCRIPT_DIR/../../lib/dot/ui.sh"
11
11
 
12
12
  ui_init
13
13
  ui_header "macOS Tuning"
@@ -16,16 +16,61 @@ VERSION_PATTERN='[0-9]+\.[0-9]+\.[0-9]+'
16
16
  SED_VERSION_PATTERN='[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*'
17
17
  BACKUP_DIR="$PROJECT_ROOT/.version-sync-backup"
18
18
  EXCLUDE_FILES=(
19
+ # Historical / referential docs — version refs inside are intentional
20
+ # pointers at prior versions, not "this is the current version" claims.
19
21
  "CHANGELOG.md"
20
22
  "docs/security/COMPLIANCE.md"
21
23
  "docs/reference/FONTS.md"
22
24
  "docs/archive/LEGACY_ROADMAP.md"
23
25
  "docs/archive/PLAN.md"
26
+
27
+ # Roadmap + audit narratives — describe per-version work; refs to
28
+ # prior versions are intentional and historical.
29
+ "docs/operations/ROADMAP_V0_2_503.md"
30
+ "docs/operations/VERSION_SYNC.md"
31
+ "docs/operations/RFC_v0_2_503_reorganization.md"
32
+ "docs/operations/HARD_AUDIT_2026.md"
33
+ "docs/reference/ALIASES_DEPRECATIONS.md"
34
+
35
+ # Security docs — INSTALL_VERIFICATION + CI_PINNING + SCORECARD
36
+ # carry per-release hash tables / closed-cycle logs. The "current"
37
+ # version inside these is tracked by hand, not by version-sync.
38
+ "docs/security/CI_PINNING.md"
39
+ "docs/security/INSTALL_VERIFICATION.md"
40
+ "docs/security/SCORECARD.md"
41
+
42
+ # Release-verification recipes use an example pinned tag
43
+ # that intentionally stays at a known-published release.
44
+ "docs/security/VERIFY_RELEASE.md"
45
+
46
+ # Example bundles — version refs in README'd examples are illustrative.
47
+ "examples/mise-plugin-dot/README.md"
48
+
49
+ # MANIFEST + MIGRATION docs — describe per-version manifests &
50
+ # cross-version migration paths; intentional references to other tags.
51
+ "docs/operations/MANIFEST.md"
52
+ "docs/operations/MIGRATION.md"
53
+
54
+ # ADR + architecture + manual + operations narratives — every
55
+ # version reference inside is dated context, not a "current version"
56
+ # claim. The single source-of-truth is .chezmoidata.toml (plus
57
+ # README, package.json — which version-sync DOES rewrite).
58
+ "docs/adr/ADR-007-multi-shell-parity.md"
59
+ "docs/architecture/REPO_LAYOUT.md"
60
+ "docs/manual/01-concepts/04-fleet.md"
61
+ "docs/manual/01-concepts/05-self-healing.md"
62
+ "docs/manual/02-tutorials/05-deploy-fleet.md"
63
+ "docs/manual/05-appendices/D-bibliography.md"
64
+ "docs/operations/MAINTENANCE.md"
65
+
66
+ # CI_COMPOSITES.md cites third-party action versions (e.g. v5.0.5),
67
+ # not dotfiles_version. False-positive pattern match.
68
+ "docs/operations/CI_COMPOSITES.md"
24
69
  )
25
70
 
26
- # shellcheck source=dot/lib/ui.sh
71
+ # shellcheck source=../lib/dot/ui.sh
27
72
  # shellcheck disable=SC1091
28
- source "$SCRIPT_DIR/dot/lib/ui.sh"
73
+ source "$SCRIPT_DIR/../lib/dot/ui.sh"
29
74
  ui_init
30
75
 
31
76
  # Functions — delegate to shared ui.sh (redirect to stderr for script output)
@@ -142,6 +187,8 @@ sed_in_place() {
142
187
  fi
143
188
  }
144
189
 
190
+ # LCOV_EXCL_START — rm -rf BACKUP_DIR + cp of real release files;
191
+ # only run during a real release flow, not safe under coverage.
145
192
  create_backup() {
146
193
  local files=("$@")
147
194
 
@@ -166,6 +213,7 @@ create_backup() {
166
213
 
167
214
  log_success "Backed up $backup_count files"
168
215
  }
216
+ # LCOV_EXCL_STOP
169
217
 
170
218
  update_version_references() {
171
219
  local target_version="$1"
@@ -395,21 +443,24 @@ main() {
395
443
  create_backup "${version_files[@]}"
396
444
  fi
397
445
 
398
- # Sync chezmoidata.toml (single source of truth for template files)
399
- local chezmoidata="$PROJECT_ROOT/.chezmoidata.toml"
446
+ # Sync chezmoidata.toml (single source of truth for template files).
447
+ # Post-Phase-4b lives under defaults/ — kept old root location as a
448
+ # fallback so this script is forward- and backward-compatible.
449
+ local chezmoidata="$PROJECT_ROOT/defaults/.chezmoidata.toml"
450
+ [[ -f "$chezmoidata" ]] || chezmoidata="$PROJECT_ROOT/.chezmoidata.toml"
400
451
  if [[ -f "$chezmoidata" ]]; then
401
452
  if [[ "$dry_run" == "true" ]]; then
402
- log_info "Would update .chezmoidata.toml: dotfiles_version = \"$target_version\""
453
+ log_info "Would update ${chezmoidata#"$PROJECT_ROOT/"}: dotfiles_version = \"$target_version\""
403
454
  else
404
455
  sed_in_place "$chezmoidata" \
405
456
  "s|^dotfiles_version = \"$SED_VERSION_PATTERN\"|dotfiles_version = \"$target_version\"|"
406
- log_success "Updated .chezmoidata.toml"
457
+ log_success "Updated ${chezmoidata#"$PROJECT_ROOT/"}"
407
458
  fi
408
459
  fi
409
460
 
410
461
  # Sync non-template script files that embed the version
411
462
  local script_files=(
412
- "dot_local/bin/executable_dot"
463
+ "bin/dot"
413
464
  "dot_local/bin/executable_tour"
414
465
  "install.sh"
415
466
  )