@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
@@ -6,10 +6,10 @@
6
6
  set -euo pipefail
7
7
 
8
8
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
- # shellcheck source=../lib/utils.sh
10
- source "$SCRIPT_DIR/../lib/utils.sh"
11
- # shellcheck source=../lib/log.sh
12
- source "$SCRIPT_DIR/../lib/log.sh"
9
+ # shellcheck source=../../../lib/dot/utils.sh
10
+ source "$SCRIPT_DIR/../../../lib/dot/utils.sh"
11
+ # shellcheck source=../../../lib/dot/log.sh
12
+ source "$SCRIPT_DIR/../../../lib/dot/log.sh"
13
13
 
14
14
  dot_ui_command_banner "Fleet" "${1:-}"
15
15
 
@@ -18,7 +18,7 @@ _FLEET_EVENTS_FILE="$_FLEET_STATE_DIR/events.jsonl"
18
18
 
19
19
  _fleet_enabled() {
20
20
  local data_file
21
- data_file="$(resolve_source_dir)/.chezmoidata.toml"
21
+ data_file="$(resolve_chezmoi_source_dir)/.chezmoidata.toml"
22
22
  if [[ -f "$data_file" ]] && grep -q '^enabled = true' "$data_file" 2>/dev/null; then
23
23
  return 0
24
24
  fi
@@ -27,7 +27,7 @@ _fleet_enabled() {
27
27
 
28
28
  _fleet_node_id() {
29
29
  local data_file node_id=""
30
- data_file="$(resolve_source_dir)/.chezmoidata.toml"
30
+ data_file="$(resolve_chezmoi_source_dir)/.chezmoidata.toml"
31
31
  if [[ -f "$data_file" ]]; then
32
32
  node_id="$(sed -n 's/^node_id = "\(.*\)"/\1/p' "$data_file" | head -1)"
33
33
  fi
@@ -39,7 +39,7 @@ _fleet_node_id() {
39
39
 
40
40
  _fleet_namespace() {
41
41
  local data_file ns=""
42
- data_file="$(resolve_source_dir)/.chezmoidata.toml"
42
+ data_file="$(resolve_chezmoi_source_dir)/.chezmoidata.toml"
43
43
  if [[ -f "$data_file" ]]; then
44
44
  ns="$(sed -n 's/^namespace = "\(.*\)"/\1/p' "$data_file" | head -1)"
45
45
  fi
@@ -67,7 +67,7 @@ _fleet_emit_event() {
67
67
  # Forward to endpoint if configured
68
68
  local endpoint=""
69
69
  local data_file
70
- data_file="$(resolve_source_dir)/.chezmoidata.toml"
70
+ data_file="$(resolve_chezmoi_source_dir)/.chezmoidata.toml"
71
71
  if [[ -f "$data_file" ]]; then
72
72
  endpoint="$(sed -n 's/^endpoint = "\(.*\)"/\1/p' "$data_file" | head -1)"
73
73
  fi
@@ -271,7 +271,7 @@ cmd_fleet_namespace() {
271
271
  ui_ok "Active" "$ns"
272
272
 
273
273
  local data_file
274
- data_file="$(resolve_source_dir)/.chezmoidata.toml"
274
+ data_file="$(resolve_chezmoi_source_dir)/.chezmoidata.toml"
275
275
  if [[ -f "$data_file" ]]; then
276
276
  echo ""
277
277
  ui_section "Available Namespaces"
@@ -289,12 +289,23 @@ cmd_fleet_namespace() {
289
289
  [[ -n "$new_ns" ]] || die "Usage: dot fleet namespace set <name>"
290
290
  validate_name "$new_ns" "namespace"
291
291
  local data_file
292
- data_file="$(resolve_source_dir)/.chezmoidata.toml"
292
+ data_file="$(resolve_chezmoi_source_dir)/.chezmoidata.toml"
293
293
  if grep -q "^namespace = " "$data_file" 2>/dev/null; then
294
- if sed --version >/dev/null 2>&1; then
295
- sed -i "s/^namespace = \".*\"/namespace = \"$new_ns\"/" "$data_file"
294
+ # Atomic write: render into a tempfile + mv so concurrent
295
+ # `dot fleet namespace set` callers can't corrupt the TOML.
296
+ # Avoids `sed -i` portability dance (GNU `-i` vs BSD `-i ''`).
297
+ local _tmp
298
+ _tmp="$(mktemp "${data_file}.XXXXXX")" || die "Cannot create tempfile"
299
+ # Explicit if/else instead of A && B || C — the latter (SC2015)
300
+ # silently runs C when B itself fails, masking real mv errors.
301
+ if sed "s/^namespace = \".*\"/namespace = \"$new_ns\"/" "$data_file" >"$_tmp"; then
302
+ if ! mv "$_tmp" "$data_file"; then
303
+ rm -f "$_tmp"
304
+ die "Failed to commit namespace update"
305
+ fi
296
306
  else
297
- sed -i '' "s/^namespace = \".*\"/namespace = \"$new_ns\"/" "$data_file"
307
+ rm -f "$_tmp"
308
+ die "Failed to render namespace update"
298
309
  fi
299
310
  fi
300
311
  ui_ok "Namespace" "Set to '$new_ns'. Run 'dot sync' to apply."
@@ -311,7 +322,8 @@ cmd_fleet_enforce() {
311
322
  shift || true
312
323
 
313
324
  local repo_root
314
- repo_root="$(resolve_source_dir)"
325
+ repo_root="$(resolve_chezmoi_source_dir)"
326
+ [[ -z "$repo_root" ]] && repo_root="$(resolve_source_dir)"
315
327
  local profiles_file="$repo_root/dot_config/dotfiles/agent-profiles.json"
316
328
 
317
329
  case "$subcommand" in
@@ -349,6 +361,266 @@ cmd_fleet_enforce() {
349
361
  esac
350
362
  }
351
363
 
364
+ _fleet_hosts_file() {
365
+ printf '%s\n' "${DOTFILES_FLEET_HOSTS:-$HOME/.config/dotfiles/fleet.toml}"
366
+ }
367
+
368
+ # Parse the hosts file. Format:
369
+ # [hosts.laptop]
370
+ # ssh = "user@laptop.local"
371
+ # profile = "workstation"
372
+ #
373
+ # Echoes one record per line: "<name>\t<ssh-target>\t<profile>".
374
+ _fleet_hosts_iter() {
375
+ local f
376
+ f="$(_fleet_hosts_file)"
377
+ [[ -f "$f" ]] || return 0
378
+ awk '
379
+ BEGIN { name = ""; ssh = ""; profile = "" }
380
+ /^\[hosts\./ {
381
+ if (name != "") { printf "%s\t%s\t%s\n", name, ssh, profile }
382
+ gsub(/[\[\]]/, "", $0); sub(/^hosts\./, "", $0); name = $0
383
+ ssh = ""; profile = ""
384
+ next
385
+ }
386
+ /^ssh[[:space:]]*=/ { sub(/^ssh[[:space:]]*=[[:space:]]*/, ""); gsub(/"/, ""); ssh = $0; next }
387
+ /^profile[[:space:]]*=/ { sub(/^profile[[:space:]]*=[[:space:]]*/, ""); gsub(/"/, ""); profile = $0; next }
388
+ END {
389
+ if (name != "") { printf "%s\t%s\t%s\n", name, ssh, profile }
390
+ }
391
+ ' "$f"
392
+ }
393
+
394
+ # SSH-based "dot fleet apply" — push the local dotfiles state out to
395
+ # each registered host. The §3 hero-feature: nobody else owns the
396
+ # "Ansible for personal devices" niche.
397
+ cmd_fleet_apply() {
398
+ local dry_run=0 only_host="" cmd="" jobs=4 verify_hosts=0
399
+ while [[ $# -gt 0 ]]; do
400
+ case "$1" in
401
+ --dry-run | -n)
402
+ dry_run=1
403
+ shift
404
+ ;;
405
+ --verify-hosts)
406
+ # Pre-flight check that every host already has a known_hosts
407
+ # entry, closing the TOFU window before any SSH connection.
408
+ # R3 audit N4. Without this, accept-new is the default and a
409
+ # first-connection MITM can seed an attacker key.
410
+ verify_hosts=1
411
+ shift
412
+ ;;
413
+ --host)
414
+ only_host="$2"
415
+ shift 2
416
+ ;;
417
+ --cmd)
418
+ cmd="$2"
419
+ shift 2
420
+ ;;
421
+ --jobs | -j)
422
+ jobs="$2"
423
+ shift 2
424
+ ;;
425
+ --help | -h)
426
+ cat <<EOF
427
+ Usage: dot fleet apply [--host <name>] [--cmd <shell>] [--dry-run] [--jobs <n>]
428
+
429
+ Push dotfiles state to every host registered in:
430
+ ${DOTFILES_FLEET_HOSTS:-\$HOME/.config/dotfiles/fleet.toml}
431
+
432
+ Format of fleet.toml:
433
+ [hosts.laptop]
434
+ ssh = "user@laptop.local"
435
+ profile = "workstation"
436
+
437
+ Hostnames are validated against [A-Za-z0-9._@:+/-]+ before any SSH
438
+ fan-out; invalid entries abort the apply.
439
+
440
+ First-time SSH connections use StrictHostKeyChecking=accept-new (TOFU).
441
+ If your threat model requires no TOFU window, pre-populate
442
+ ~/.ssh/known_hosts before running this command.
443
+
444
+ Behavior:
445
+ By default each host runs: dot sync && dot doctor --quiet
446
+ Override with --cmd "<shell>" to run an arbitrary command on every
447
+ host (e.g. --cmd "uptime").
448
+
449
+ WARNING: --cmd is the trust boundary. Whatever string you pass
450
+ executes on every remote host with the credentials your SSH key
451
+ carries. Verify the command before running.
452
+
453
+ Flags:
454
+ --host <name> Apply to a single host only.
455
+ --cmd <shell> Run a custom command instead of 'dot sync'.
456
+ --dry-run, -n Print resolved hosts + planned command; don't SSH.
457
+ --jobs <n> Parallelism (default 4).
458
+ --verify-hosts Refuse to open any SSH connection unless every
459
+ target host already has a key in ~/.ssh/known_hosts.
460
+ Use when your threat model excludes the TOFU window.
461
+ EOF
462
+ return 0
463
+ ;;
464
+ *)
465
+ ui_err "Unknown arg" "$1"
466
+ return 1
467
+ ;;
468
+ esac
469
+ done
470
+
471
+ local hosts_file
472
+ hosts_file="$(_fleet_hosts_file)"
473
+ if [[ ! -f "$hosts_file" ]]; then
474
+ ui_err "Fleet" "no hosts file at $hosts_file"
475
+ ui_info "Hint" "create it with stanzas like '[hosts.laptop]\\nssh = \"user@laptop.local\"'"
476
+ return 1
477
+ fi
478
+
479
+ local entries
480
+ entries="$(_fleet_hosts_iter)"
481
+ if [[ -z "$entries" ]]; then
482
+ ui_err "Fleet" "hosts file is empty: $hosts_file"
483
+ return 1
484
+ fi
485
+ if [[ -n "$only_host" ]]; then
486
+ entries="$(printf '%s\n' "$entries" | awk -F'\t' -v h="$only_host" '$1 == h')"
487
+ [[ -n "$entries" ]] || {
488
+ ui_err "Fleet" "host not found: $only_host"
489
+ return 1
490
+ }
491
+ fi
492
+
493
+ local default_cmd='dot sync && dot doctor --quiet'
494
+ local effective_cmd="${cmd:-$default_cmd}"
495
+
496
+ ui_header "Fleet apply"
497
+ ui_info "Hosts file" "$hosts_file"
498
+ ui_info "Command" "$effective_cmd"
499
+ ui_info "Parallel" "$jobs"
500
+
501
+ if [[ "$dry_run" -eq 1 ]]; then
502
+ printf '%s\n' "$entries" | while IFS=$'\t' read -r name ssh profile; do
503
+ ui_info "$name" "$ssh profile=$profile cmd=$effective_cmd"
504
+ done
505
+ ui_ok "Dry-run" "no SSH connections opened"
506
+ return 0
507
+ fi
508
+
509
+ if ! command -v ssh >/dev/null 2>&1; then
510
+ ui_err "ssh" "not installed"
511
+ return 127
512
+ fi
513
+
514
+ local total=0 ok=0 fail=0
515
+ local tmpdir
516
+ # `-t` template includes PID + random, so two concurrent `dot fleet
517
+ # apply` invocations from the same user can't collide on $tmpdir.
518
+ tmpdir="$(mktemp -d -t dotfiles-fleet.XXXXXX)"
519
+ # Capture tmpdir's value at trap-definition time (via the eval-on-
520
+ # define `printf -v`), NOT at trap-fire time. A naive
521
+ # `trap 'rm -rf "$tmpdir"' RETURN` is unsafe under set -u because
522
+ # `local tmpdir` is destroyed before the RETURN trap evaluates.
523
+ # The SC2064 warning ("Use single quotes, otherwise this expands now
524
+ # rather than when signalled") is exactly the behaviour we want here —
525
+ # we explicitly want eager expansion. Suppress per-line.
526
+ local _cleanup
527
+ printf -v _cleanup 'rm -rf %q' "$tmpdir"
528
+ # shellcheck disable=SC2064
529
+ trap "$_cleanup" RETURN
530
+
531
+ # Validate every hostname against a conservative regex BEFORE fan-out.
532
+ # `user@host:port` characters only — refuses single quotes, backticks,
533
+ # `$()`, semicolons, spaces, any shell metacharacter. Closes the
534
+ # round-2 audit's hostname-injection finding.
535
+ while IFS=$'\t' read -r name ssh profile; do
536
+ [[ -n "$name" ]] || continue
537
+ if [[ ! "$ssh" =~ ^[a-zA-Z0-9._@:+/-]+$ ]]; then
538
+ ui_err "$name" "invalid ssh target ($ssh) — only [a-zA-Z0-9._@:+/-] allowed"
539
+ return 1
540
+ fi
541
+ done <<<"$entries"
542
+
543
+ # --verify-hosts: refuse the apply when any target host is missing
544
+ # from ~/.ssh/known_hosts. Closes the R3 audit N4 TOFU-window gap.
545
+ if ((verify_hosts == 1)); then
546
+ local known_hosts="${HOME}/.ssh/known_hosts"
547
+ if [[ ! -f "$known_hosts" ]]; then
548
+ ui_err "verify-hosts" "no $known_hosts — populate before --verify-hosts"
549
+ return 1
550
+ fi
551
+ local unknown_count=0
552
+ while IFS=$'\t' read -r name ssh profile; do
553
+ [[ -n "$name" && -n "$ssh" ]] || continue
554
+ # Strip `user@` prefix and `:port` suffix for the lookup.
555
+ local hostpart="${ssh#*@}"
556
+ hostpart="${hostpart%%:*}"
557
+ if ! ssh-keygen -F "$hostpart" -f "$known_hosts" >/dev/null 2>&1; then
558
+ ui_err "$name" "no known_hosts entry for $hostpart — would TOFU on first connect"
559
+ unknown_count=$((unknown_count + 1))
560
+ fi
561
+ done <<<"$entries"
562
+ if ((unknown_count > 0)); then
563
+ ui_err "verify-hosts" "$unknown_count host(s) missing from known_hosts — aborting"
564
+ return 1
565
+ fi
566
+ ui_ok "verify-hosts" "all hosts found in known_hosts"
567
+ fi
568
+
569
+ # Run one SSH per host, parallelised via background jobs with a
570
+ # semaphore. We DO NOT use `xargs -d` because that flag is GNU-only
571
+ # and the §3 hero feature must work on macOS BSD xargs too. Also
572
+ # avoids embedding `{}` substitution into a `bash -c` (the previous
573
+ # implementation had a quoting hazard around TOML hostnames).
574
+ _fleet_apply_one() {
575
+ local _name="$1" _ssh="$2" _cmd="$3" _tmp="$4"
576
+ if ssh -o BatchMode=yes -o ConnectTimeout=10 \
577
+ -o StrictHostKeyChecking=accept-new \
578
+ "$_ssh" "$_cmd" </dev/null \
579
+ >"$_tmp/$_name.out" 2>"$_tmp/$_name.err"; then
580
+ printf 'ok\n' >"$_tmp/$_name.status"
581
+ else
582
+ printf 'fail %d\n' "$?" >"$_tmp/$_name.status"
583
+ fi
584
+ }
585
+
586
+ local running=0
587
+ while IFS=$'\t' read -r name ssh profile; do
588
+ [[ -n "$name" && -n "$ssh" ]] || continue
589
+ total=$((total + 1))
590
+ while ((running >= jobs)); do
591
+ wait -n 2>/dev/null || break
592
+ running=$((running - 1))
593
+ done
594
+ _fleet_apply_one "$name" "$ssh" "$effective_cmd" "$tmpdir" &
595
+ running=$((running + 1))
596
+ done <<<"$entries"
597
+ wait
598
+
599
+ # `while < <(printf ...)` instead of `printf ... | while` — the
600
+ # pipe form runs the loop body in a subshell, so the ok/fail
601
+ # counters never propagate back to the parent. Caught by
602
+ # tests/unit/fleet/test_fleet_apply_mocked_ssh.sh which exercised
603
+ # the full apply path (the dry-run test missed this).
604
+ while IFS=$'\t' read -r name ssh profile; do
605
+ [[ -n "$name" ]] || continue
606
+ if [[ -s "$tmpdir/$name.status" ]] && head -1 "$tmpdir/$name.status" | grep -q '^ok'; then
607
+ ui_ok "$name" "$ssh"
608
+ ok=$((ok + 1))
609
+ else
610
+ local err_summary=""
611
+ [[ -s "$tmpdir/$name.err" ]] && err_summary=" — $(head -1 "$tmpdir/$name.err")"
612
+ ui_err "$name" "$ssh${err_summary}"
613
+ fail=$((fail + 1))
614
+ fi
615
+ local _evt_status="unknown"
616
+ [[ -s "$tmpdir/$name.status" ]] && _evt_status="$(head -1 "$tmpdir/$name.status")"
617
+ _fleet_emit_event "apply" "$_evt_status" "host=$name" "cmd=$effective_cmd"
618
+ done < <(printf '%s\n' "$entries")
619
+
620
+ ui_info "Summary" "$ok ok / $fail failed / $total total"
621
+ [[ "$fail" -eq 0 ]]
622
+ }
623
+
352
624
  cmd_fleet() {
353
625
  local subcommand="${1:-status}"
354
626
  if [[ "${1:-}" == --* ]] || [[ -z "${1:-}" ]]; then
@@ -373,6 +645,9 @@ cmd_fleet() {
373
645
  enforce)
374
646
  cmd_fleet_enforce "$@"
375
647
  ;;
648
+ apply | push)
649
+ cmd_fleet_apply "$@"
650
+ ;;
376
651
  *)
377
652
  ui_header "Fleet Commands"
378
653
  echo ""
@@ -383,6 +658,7 @@ cmd_fleet() {
383
658
  ui_ok "events" "Show recent fleet events"
384
659
  ui_ok "namespace" "Show or set the active namespace"
385
660
  ui_ok "enforce" "Show or set RBAC enforcement mode (advisory|strict)"
661
+ ui_ok "apply" "SSH out to every host in fleet.toml and run 'dot sync'"
386
662
  ;;
387
663
  esac
388
664
  }
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env bash
2
+ # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # shellcheck shell=bash
4
+ #
5
+ # scripts/dot/commands/init.sh
6
+ #
7
+ # `dot init <github-user>` — bootstrap a foreign dotfiles repo through
8
+ # this framework's harness. The §3 audit roadmap calls for an analogue
9
+ # to `chezmoi init <user>` that turns this tool from "one person's
10
+ # config" into a runtime for any dotfiles user.
11
+ #
12
+ # Behavior:
13
+ # dot init alice # clones github.com/alice/dotfiles via chezmoi,
14
+ # # applies through the dot harness
15
+ # dot init https://... # explicit URL
16
+ # dot init alice --dry-run # preview without writing
17
+ # dot init alice --no-apply # clone only; don't run chezmoi apply
18
+ #
19
+ # Safety:
20
+ # - Refuses to clobber an existing chezmoi source dir without --force.
21
+ # - Disclaims that the target's scripts will run with the user's
22
+ # privileges and prints the source URL for inspection.
23
+ # - Verifies the source URL is HTTPS (no plain git://) so MITM is harder.
24
+
25
+ set -euo pipefail
26
+
27
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ # shellcheck source=../../../lib/dot/ui.sh disable=SC1091
29
+ source "$SCRIPT_DIR/../../../lib/dot/ui.sh"
30
+ # shellcheck source=../../../lib/dot/utils.sh disable=SC1091
31
+ source "$SCRIPT_DIR/../../../lib/dot/utils.sh"
32
+
33
+ _init_resolve_url() {
34
+ local arg="$1"
35
+ case "$arg" in
36
+ http://*)
37
+ printf "dot init: refusing plain HTTP (use HTTPS or git+ssh)\n" >&2
38
+ return 2
39
+ ;;
40
+ https://* | git@*:*)
41
+ # Trust full URLs as-is — these are the user's explicit intent.
42
+ printf "%s\n" "$arg"
43
+ ;;
44
+ */*)
45
+ # owner/repo shorthand: validate before constructing the URL so
46
+ # a crafted argument can't smuggle shell metacharacters into
47
+ # downstream tooling (chezmoi init, git clone).
48
+ if [[ ! "$arg" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]]; then
49
+ printf "dot init: invalid owner/repo (only [A-Za-z0-9._-]+/[A-Za-z0-9._-]+ allowed): %s\n" "$arg" >&2
50
+ return 2
51
+ fi
52
+ printf "https://github.com/%s.git\n" "$arg"
53
+ ;;
54
+ *)
55
+ # Bare user shorthand: same character whitelist as the path
56
+ # segment of a GitHub URL.
57
+ if [[ ! "$arg" =~ ^[A-Za-z0-9._-]+$ ]]; then
58
+ printf "dot init: invalid user (only [A-Za-z0-9._-] allowed): %s\n" "$arg" >&2
59
+ return 2
60
+ fi
61
+ printf "https://github.com/%s/dotfiles.git\n" "$arg"
62
+ ;;
63
+ esac
64
+ }
65
+
66
+ cmd_init() {
67
+ local user_arg="" dry_run=0 apply=1 force=0
68
+ while [[ $# -gt 0 ]]; do
69
+ case "$1" in
70
+ --dry-run | -n)
71
+ dry_run=1
72
+ shift
73
+ ;;
74
+ --no-apply)
75
+ apply=0
76
+ shift
77
+ ;;
78
+ --force | -f)
79
+ force=1
80
+ shift
81
+ ;;
82
+ --help | -h)
83
+ cat <<EOF
84
+ Usage: dot init <github-user|owner/repo|url> [--dry-run] [--no-apply] [--force]
85
+
86
+ Bootstrap a foreign dotfiles repo through chezmoi + the dot harness.
87
+
88
+ Examples:
89
+ dot init alice # github.com/alice/dotfiles
90
+ dot init alice/configs # github.com/alice/configs
91
+ dot init https://example.com/repo.git
92
+ dot init alice --dry-run # preview only
93
+ dot init alice --no-apply # clone but don't apply
94
+
95
+ Flags:
96
+ --dry-run, -n Show resolved URL + target dir without cloning.
97
+ --no-apply Clone the source but skip 'chezmoi apply'.
98
+ --force, -f Overwrite an existing chezmoi source dir.
99
+ EOF
100
+ return 0
101
+ ;;
102
+ --)
103
+ shift
104
+ break
105
+ ;;
106
+ -*)
107
+ ui_err "Unknown flag" "$1"
108
+ return 1
109
+ ;;
110
+ *)
111
+ if [[ -n "$user_arg" ]]; then
112
+ ui_err "Too many arguments" "$1"
113
+ return 1
114
+ fi
115
+ user_arg="$1"
116
+ shift
117
+ ;;
118
+ esac
119
+ done
120
+
121
+ [[ -n "$user_arg" ]] || {
122
+ ui_err "init" "missing <user|repo|url>"
123
+ return 1
124
+ }
125
+
126
+ local url
127
+ url="$(_init_resolve_url "$user_arg")" || return $?
128
+
129
+ if ! command -v chezmoi >/dev/null 2>&1; then
130
+ ui_err "chezmoi" "not installed — run install.sh first"
131
+ return 127
132
+ fi
133
+
134
+ local source_dir
135
+ source_dir="${CHEZMOI_SOURCE_DIR:-$(chezmoi source-path 2>/dev/null || echo "$HOME/.local/share/chezmoi")}"
136
+
137
+ ui_header "Bootstrap dotfiles from $user_arg"
138
+ ui_info "Source URL" "$url"
139
+ ui_info "Target dir" "$source_dir"
140
+ local _apply_label="no"
141
+ [[ "$apply" -eq 1 ]] && _apply_label="yes"
142
+ ui_info "Apply after?" "$_apply_label"
143
+
144
+ if [[ "$dry_run" -eq 1 ]]; then
145
+ ui_ok "Dry-run" "no changes made"
146
+ return 0
147
+ fi
148
+
149
+ if [[ -e "$source_dir" ]] && [[ "$force" -ne 1 ]]; then
150
+ ui_err "Refusing" "$source_dir already exists; pass --force to overwrite"
151
+ return 1
152
+ fi
153
+
154
+ ui_warn "Trust" "The target repo's scripts will run with your user privileges."
155
+ ui_warn "Trust" "Inspect $url before proceeding if you don't know the author."
156
+ if [[ -t 0 ]] && [[ "${DOTFILES_NONINTERACTIVE:-0}" != "1" ]]; then
157
+ read -r -p " Continue? [y/N] " resp
158
+ case "$resp" in
159
+ [yY] | [yY][eE][sS]) ;;
160
+ *)
161
+ ui_info "Init" "aborted by user"
162
+ return 1
163
+ ;;
164
+ esac
165
+ fi
166
+
167
+ local chezmoi_args=(init --source "$source_dir")
168
+ [[ "$apply" -eq 1 ]] && chezmoi_args+=(--apply)
169
+ chezmoi_args+=("$url")
170
+
171
+ ui_info "chezmoi" "${chezmoi_args[*]}"
172
+ if chezmoi "${chezmoi_args[@]}"; then
173
+ ui_ok "Init" "complete"
174
+ if [[ "$apply" -eq 1 ]]; then
175
+ ui_info "Hint" "run 'dot doctor' to validate the new environment"
176
+ else
177
+ ui_info "Hint" "run 'chezmoi diff' then 'chezmoi apply' when ready"
178
+ fi
179
+ else
180
+ local rc=$?
181
+ ui_err "Init" "chezmoi exited $rc"
182
+ return "$rc"
183
+ fi
184
+ }
@@ -6,8 +6,8 @@
6
6
  set -euo pipefail
7
7
 
8
8
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
- # shellcheck source=../lib/utils.sh
10
- source "$SCRIPT_DIR/../lib/utils.sh"
9
+ # shellcheck source=../../../lib/dot/utils.sh
10
+ source "$SCRIPT_DIR/../../../lib/dot/utils.sh"
11
11
 
12
12
  dot_ui_command_banner "Lint" "${1:-}"
13
13
 
@@ -34,6 +34,11 @@ cmd_lint() {
34
34
  files+=("$src_dir/install.sh")
35
35
  fi
36
36
 
37
+ # Post-Phase-4b chezmoi-tracked content lives under defaults/.
38
+ local chezmoi_src
39
+ chezmoi_src="$(resolve_chezmoi_source_dir)"
40
+ [[ -z "$chezmoi_src" ]] && chezmoi_src="$src_dir"
41
+
37
42
  # dot_local/bin/executable_* scripts (shell scripts only)
38
43
  while IFS= read -r -d '' f; do
39
44
  if file "$f" 2>/dev/null | grep -qiE 'shell|bash|sh'; then
@@ -41,12 +46,12 @@ cmd_lint() {
41
46
  elif head -1 "$f" 2>/dev/null | grep -qE '^#!.*(bash|sh)'; then
42
47
  files+=("$f")
43
48
  fi
44
- done < <(find "$src_dir/dot_local/bin" -name 'executable_*' -type f -print0 2>/dev/null)
49
+ done < <(find "$chezmoi_src/dot_local/bin" -name 'executable_*' -type f -print0 2>/dev/null)
45
50
 
46
51
  # .chezmoitemplates/*.sh (non-.tmpl shell scripts)
47
52
  while IFS= read -r -d '' f; do
48
53
  files+=("$f")
49
- done < <(find "$src_dir/.chezmoitemplates" -name '*.sh' -type f -print0 2>/dev/null)
54
+ done < <(find "$chezmoi_src/.chezmoitemplates" -name '*.sh' -type f -print0 2>/dev/null)
50
55
 
51
56
  local total=${#files[@]}
52
57
  if [[ "$total" -eq 0 ]]; then
@@ -16,8 +16,8 @@
16
16
  set -euo pipefail
17
17
 
18
18
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
- # shellcheck source=../lib/utils.sh
20
- source "$SCRIPT_DIR/../lib/utils.sh"
19
+ # shellcheck source=../../../lib/dot/utils.sh
20
+ source "$SCRIPT_DIR/../../../lib/dot/utils.sh"
21
21
 
22
22
  MANUAL_URL="${DOTFILES_MANUAL_URL:-https://sebastienrousseau.github.io/dotfiles/manual}"
23
23
  CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/dotfiles/manual"
@@ -66,7 +66,7 @@ resolve_source() {
66
66
  echo "$src_dir/$fname"
67
67
  return 0
68
68
  fi
69
- ui_err "manual" "local build not found at $src_dir/$fname — run bash scripts/docs/build-manual.sh"
69
+ ui_err "manual" "local build not found at $src_dir/$fname — run bash tools/docs/build-manual.sh"
70
70
  return 1
71
71
  fi
72
72
 
@@ -6,10 +6,10 @@
6
6
  set -euo pipefail
7
7
 
8
8
  _META_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
- # shellcheck source=../lib/utils.sh
10
- source "$_META_DIR/../lib/utils.sh"
11
- # shellcheck source=../lib/log.sh
12
- source "$_META_DIR/../lib/log.sh"
9
+ # shellcheck source=../../../lib/dot/utils.sh
10
+ source "$_META_DIR/../../../lib/dot/utils.sh"
11
+ # shellcheck source=../../../lib/dot/log.sh
12
+ source "$_META_DIR/../../../lib/dot/log.sh"
13
13
  # shellcheck source=agent.sh
14
14
  source "$_META_DIR/agent.sh"
15
15
 
@@ -61,10 +61,13 @@ cmd_prewarm() {
61
61
  # Clear caches first
62
62
  ui_info "Cache" "Clearing shell initialization caches"
63
63
  local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}"
64
- rm -rf "$cache_dir/zsh"/*-init.zsh "$cache_dir/zsh"/*.zwc 2>/dev/null || true
65
- rm -rf "$cache_dir/bash"/*-init.bash 2>/dev/null || true
66
- rm -rf "$cache_dir/fish"/*-init.fish 2>/dev/null || true
67
- rm -rf "$cache_dir/nushell"/*.nu 2>/dev/null || true
64
+ # `find ... -delete` instead of `rm -rf $glob` so an unmatched literal
65
+ # pattern can't accidentally remove a real same-named directory, and
66
+ # so we don't pass `-r` on what should always be files.
67
+ [[ -d "$cache_dir/zsh" ]] && find "$cache_dir/zsh" -maxdepth 1 -type f \( -name '*-init.zsh' -o -name '*.zwc' \) -delete 2>/dev/null
68
+ [[ -d "$cache_dir/bash" ]] && find "$cache_dir/bash" -maxdepth 1 -type f -name '*-init.bash' -delete 2>/dev/null
69
+ [[ -d "$cache_dir/fish" ]] && find "$cache_dir/fish" -maxdepth 1 -type f -name '*-init.fish' -delete 2>/dev/null
70
+ [[ -d "$cache_dir/nushell" ]] && find "$cache_dir/nushell" -maxdepth 1 -type f -name '*.nu' -delete 2>/dev/null
68
71
  ui_info "Cache" "Cleared. Regenerating..."
69
72
  src_dir="$(resolve_source_dir)"
70
73
  if [ -n "$src_dir" ] && [ -f "$src_dir/scripts/ops/prewarm.sh" ]; then
@@ -89,7 +92,12 @@ cmd_docs() {
89
92
 
90
93
  cmd_learn() {
91
94
  local dot_bin
92
- dot_bin="$(dirname "${BASH_SOURCE[0]}")/../../../dot_local/bin"
95
+ # Post-Phase-4b: dot_local/ lives under defaults/. Legacy layout
96
+ # (older deployments before .chezmoiroot activation) kept it at
97
+ # repo root — probe both.
98
+ dot_bin="$(dirname "${BASH_SOURCE[0]}")/../../../defaults/dot_local/bin"
99
+ [[ -f "$dot_bin/executable_tour" ]] ||
100
+ dot_bin="$(dirname "${BASH_SOURCE[0]}")/../../../dot_local/bin"
93
101
  if [ -f "$dot_bin/executable_tour" ]; then
94
102
  exec bash "$dot_bin/executable_tour" "$@"
95
103
  fi
@@ -173,7 +181,8 @@ cmd_mcp() {
173
181
  ;;
174
182
  registry)
175
183
  local repo_root registry_file json_mode=0
176
- repo_root="$(require_source_dir)"
184
+ repo_root="$(resolve_chezmoi_source_dir)"
185
+ [[ -z "$repo_root" ]] && repo_root="$(require_source_dir)"
177
186
  registry_file="${MCP_REGISTRY_CONFIG:-$repo_root/dot_config/dotfiles/mcp-registry.json}"
178
187
  if [[ "${1:-}" == "registry" ]]; then
179
188
  shift || true