@sebastienrousseau/dotfiles 0.2.500 → 0.2.502

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 (237) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +113 -45
  3. package/docs/.vitepress/reports/localization-readability-audit.md +4 -0
  4. package/docs/AI.md +8 -2
  5. package/docs/CNAME +1 -0
  6. package/docs/COPYRIGHT +1 -1
  7. package/docs/NAMING_CONVENTIONS.md +7 -0
  8. package/docs/README.md +4 -0
  9. package/docs/_config.yml +59 -0
  10. package/docs/adr/ADR-001-ci-cd-pipeline.md +17 -0
  11. package/docs/adr/ADR-002-shell-performance.md +9 -0
  12. package/docs/adr/ADR-003-security-first.md +18 -0
  13. package/docs/adr/ADR-004-cli-architecture.md +14 -0
  14. package/docs/adr/ADR-005-chezmoi-choice.md +10 -0
  15. package/docs/adr/ADR-006-shell-selection.md +9 -0
  16. package/docs/adr/ADR-007-multi-shell-parity.md +10 -1
  17. package/docs/adr/ADR-008-alias-system-architecture.md +10 -0
  18. package/docs/adr/ADR-009-wallpaper-driven-theming.md +131 -0
  19. package/docs/adr/ADR-010-starship-transient-prompt.md +144 -0
  20. package/docs/adr/ADR-011-nushell-tier3-keep.md +144 -0
  21. package/docs/adr/README.md +7 -0
  22. package/docs/architecture/ARCHITECTURE.md +4 -0
  23. package/docs/architecture/INTEROP.md +8 -0
  24. package/docs/architecture/REPO_LAYOUT.md +5 -1
  25. package/docs/architecture/WALKTHROUGH.md +4 -0
  26. package/docs/architecture/fleet-deployment.md +4 -0
  27. package/docs/archive/EUXIS_2026_REVIEW.md +11 -3
  28. package/docs/archive/LEGACY_ROADMAP.md +45 -27
  29. package/docs/archive/MILESTONE_v0.2.493.md +4 -0
  30. package/docs/archive/PLAN.md +46 -8
  31. package/docs/archive/REPO_AUDIT.md +8 -0
  32. package/docs/guides/INSTALL.md +4 -0
  33. package/docs/guides/NEOVIM_IDE_GUIDE.md +9 -0
  34. package/docs/guides/THEMING.md +8 -0
  35. package/docs/guides/TROUBLESHOOTING.md +28 -0
  36. package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +70 -1
  37. package/docs/index.md +6 -2
  38. package/docs/interop/A2A.md +7 -0
  39. package/docs/interop/POWERSHELL.md +102 -0
  40. package/docs/manual/00-introduction.md +5 -1
  41. package/docs/manual/01-concepts/01-architecture.md +4 -0
  42. package/docs/manual/01-concepts/02-trust-model.md +6 -2
  43. package/docs/manual/01-concepts/03-theme-engine.md +4 -0
  44. package/docs/manual/01-concepts/04-fleet.md +7 -1
  45. package/docs/manual/01-concepts/05-self-healing.md +8 -1
  46. package/docs/manual/02-tutorials/01-first-install.md +5 -0
  47. package/docs/manual/02-tutorials/02-add-wallpaper.md +5 -0
  48. package/docs/manual/02-tutorials/03-create-profile.md +6 -0
  49. package/docs/manual/02-tutorials/04-encrypt-secret.md +6 -0
  50. package/docs/manual/02-tutorials/05-deploy-fleet.md +5 -1
  51. package/docs/manual/03-reference/01-dot-cli.md +67 -45
  52. package/docs/manual/03-reference/02-config-files.md +8 -2
  53. package/docs/manual/03-reference/03-environment.md +4 -0
  54. package/docs/manual/03-reference/04-templates.md +7 -1
  55. package/docs/manual/03-reference/05-feature-flags.md +72 -3
  56. package/docs/manual/04-cookbook/01-recipes.md +4 -0
  57. package/docs/manual/04-cookbook/02-troubleshooting.md +32 -0
  58. package/docs/manual/04-cookbook/03-faq.md +8 -0
  59. package/docs/manual/05-appendices/A-platform-matrix.md +4 -0
  60. package/docs/manual/05-appendices/B-security-checklist.md +6 -0
  61. package/docs/manual/05-appendices/C-glossary.md +4 -0
  62. package/docs/manual/05-appendices/D-bibliography.md +5 -1
  63. package/docs/manual/05-appendices/E-license.md +4 -0
  64. package/docs/manual/_toc.yml +1 -1
  65. package/docs/manual/command-index.md +16 -8
  66. package/docs/manual/concept-index.md +4 -0
  67. package/docs/manual/index.md +66 -0
  68. package/docs/operations/ATTESTATION.md +5 -0
  69. package/docs/operations/CI_CADENCE.md +107 -0
  70. package/docs/operations/CI_COMPOSITES.md +156 -0
  71. package/docs/operations/COMPLETIONS.md +123 -0
  72. package/docs/operations/COVERAGE.md +182 -0
  73. package/docs/operations/DRIFT.md +107 -0
  74. package/docs/operations/HARD_AUDIT_2026.md +631 -0
  75. package/docs/operations/MAINTENANCE.md +5 -1
  76. package/docs/operations/MIGRATION.md +14 -6
  77. package/docs/operations/OPERATIONS.md +24 -0
  78. package/docs/operations/PERFORMANCE.md +133 -0
  79. package/docs/operations/REGISTRY.md +89 -0
  80. package/docs/operations/RELIABILITY.md +6 -0
  81. package/docs/operations/ROADMAP.md +36 -18
  82. package/docs/operations/ROADMAP_2026.md +665 -0
  83. package/docs/operations/TESTING.md +4 -0
  84. package/docs/operations/TRACEABILITY.md +7 -0
  85. package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +4 -0
  86. package/docs/operations/VERSION_SYNC.md +54 -5
  87. package/docs/reference/ALIASES.md +7 -0
  88. package/docs/reference/ALIASES_CHEATSHEET.md +5 -1
  89. package/docs/reference/ALIASES_DEPRECATIONS.md +5 -1
  90. package/docs/reference/FEATURES.md +4 -0
  91. package/docs/reference/FONTS.md +4 -0
  92. package/docs/reference/POWERSHELL_PARITY.md +80 -0
  93. package/docs/reference/PROFILES.md +4 -0
  94. package/docs/reference/SCREENSHOTS.md +4 -0
  95. package/docs/reference/SCRIPTS.md +4 -0
  96. package/docs/reference/SUPPORT_MATRIX.md +10 -4
  97. package/docs/reference/THEMES.md +4 -0
  98. package/docs/reference/TOOLS.md +4 -0
  99. package/docs/reference/UTILS.md +16 -12
  100. package/docs/registry.json +6 -0
  101. package/docs/security/AI_ACT_COMPLIANCE.md +4 -0
  102. package/docs/security/AUDIT_BYPASS.md +103 -0
  103. package/docs/security/AUTOMATION_SECRETS.md +4 -0
  104. package/docs/security/CI_EGRESS_ALLOWLIST.md +127 -0
  105. package/docs/security/CI_PINNING.md +113 -0
  106. package/docs/security/COMMIT_SIGNING.md +138 -0
  107. package/docs/security/COMPLIANCE.md +5 -0
  108. package/docs/security/DEPS_DEV_EXCEPTIONS.md +86 -0
  109. package/docs/security/DISCLOSURE.md +130 -0
  110. package/docs/security/ENCRYPTION.md +5 -0
  111. package/docs/security/FMEA.md +4 -0
  112. package/docs/security/HISTORY_FILTERING.md +132 -0
  113. package/docs/security/INCIDENT_RESPONSE.md +4 -0
  114. package/docs/security/INSTALL_VERIFICATION.md +122 -0
  115. package/docs/security/KEYS.md +4 -0
  116. package/docs/security/KEY_ROTATION.md +85 -1
  117. package/docs/security/MCP_POLICY.md +9 -0
  118. package/docs/security/POLICY_RELEASES.md +4 -0
  119. package/docs/security/README.md +4 -0
  120. package/docs/security/SCORECARD.md +140 -0
  121. package/docs/security/SECRETS.md +12 -0
  122. package/docs/security/SECURITY.md +4 -0
  123. package/docs/security/SECURITY_CHECKLIST.md +11 -0
  124. package/docs/security/SHELL_EXEMPTIONS.md +145 -0
  125. package/docs/security/SOUP_REGISTER.md +4 -0
  126. package/docs/security/THREAT_MODEL.md +10 -0
  127. package/docs/security/VERIFICATION_VALIDATION.md +5 -1
  128. package/docs/security/security-pubkey.asc +15 -0
  129. package/docs/themes/README.md +4 -0
  130. package/docs/themes/VISUAL_INTEGRITY_REPORT.md +4 -0
  131. package/dot_config/ai/identity.md +3 -0
  132. package/dot_config/ai/patterns/architect.md +2 -0
  133. package/dot_config/ai/patterns/hardener.md +2 -0
  134. package/dot_config/ai/patterns/refactor.md +2 -0
  135. package/dot_config/alacritty/alacritty.toml.tmpl +3 -3
  136. package/dot_config/atuin/config.toml.tmpl +47 -0
  137. package/dot_config/dotfiles/agent-card.json +1 -1
  138. package/dot_config/dotfiles/boot/README.md +2 -0
  139. package/dot_config/dotfiles/grub/README.md +2 -0
  140. package/dot_config/dotfiles/lock/README.md +2 -0
  141. package/dot_config/fish/conf.d/direnv.fish +4 -0
  142. package/dot_config/fish/conf.d/init.fish.tmpl +21 -0
  143. package/dot_config/fish/conf.d/mise-activate.fish +5 -0
  144. package/dot_config/fish/functions/_cached_eval.fish +84 -11
  145. package/dot_config/fish/functions/_cached_eval_clear.fish +17 -0
  146. package/dot_config/foot/foot.ini.tmpl +3 -3
  147. package/dot_config/fuzzel/fuzzel.ini.tmpl +2 -2
  148. package/dot_config/ghostty/config.tmpl +3 -3
  149. package/dot_config/git/hooks/executable_commit-msg +146 -0
  150. package/dot_config/goose/config.yaml +2 -2
  151. package/dot_config/gtk-3.0/gtk.css.tmpl +2 -2
  152. package/dot_config/gtk-3.0/settings.ini.tmpl +2 -2
  153. package/dot_config/gtk-4.0/gtk.css.tmpl +2 -2
  154. package/dot_config/gtk-4.0/settings.ini.tmpl +2 -2
  155. package/dot_config/kitty/kitty.conf.tmpl +3 -3
  156. package/dot_config/mise/config.toml +1 -1
  157. package/dot_config/niri/config.kdl.tmpl +2 -2
  158. package/dot_config/nushell/cached_eval.nu +80 -0
  159. package/dot_config/nushell/env.nu.tmpl +21 -13
  160. package/dot_config/shell/00-core-paths.sh.tmpl +9 -1
  161. package/dot_config/shell/05-core-safety.sh +1 -0
  162. package/dot_config/shell/10-secrets.sh +1 -0
  163. package/dot_config/shell/40-fzf-defaults.sh.tmpl +1 -0
  164. package/dot_config/shell/40-ls-colors.sh +1 -0
  165. package/dot_config/shell/50-logic-functions-core.sh.tmpl +1 -0
  166. package/dot_config/shell/50-logic-functions.sh.tmpl +1 -0
  167. package/dot_config/shell/51-logic-functions-extra.sh.tmpl +1 -0
  168. package/dot_config/shell/90-ux-aliases.sh.tmpl +1 -0
  169. package/dot_config/shell/91-ux-aliases-lazy.sh.tmpl +1 -0
  170. package/dot_config/shell/README.md +25 -8
  171. package/dot_config/starship.toml.tmpl +2 -2
  172. package/dot_config/tmux/tmux.conf.tmpl +3 -3
  173. package/dot_config/user-dirs.dirs +1 -0
  174. package/dot_config/vscode/settings.json.tmpl +2 -2
  175. package/dot_config/waybar/config.jsonc.tmpl +2 -2
  176. package/dot_config/waybar/style.css.tmpl +2 -2
  177. package/dot_config/wezterm/wezterm.lua.tmpl +3 -3
  178. package/dot_config/zsh/dot_zshrc.tmpl +207 -17
  179. package/dot_config/zsh/rc.d/00-alias-shims.zsh +28 -6
  180. package/dot_config/zsh/rc.d/30-options.zsh.tmpl +27 -7
  181. package/dot_local/bin/executable_bm +2 -0
  182. package/dot_local/bin/executable_dot +56 -9
  183. package/dot_local/bin/executable_dot-bootstrap +0 -1
  184. package/dot_local/bin/executable_dot-load-benchmark +1 -1
  185. package/dot_local/bin/executable_dot-theme-sync +8 -8
  186. package/dot_local/bin/executable_notify +2 -0
  187. package/dot_local/bin/executable_open +2 -0
  188. package/dot_local/bin/executable_tour +4 -2
  189. package/dot_local/bin/executable_up +3 -1
  190. package/dot_local/share/man/man1/dot.1 +1 -1
  191. package/dot_local/share/zsh/completions/_dot +4 -0
  192. package/install.sh +53 -38
  193. package/package.json +1 -1
  194. package/scripts/ci/check-dangerous-chmod.sh +19 -0
  195. package/scripts/ci/check-deps-dev.sh +236 -0
  196. package/scripts/ci/check-insecure-tls.sh +61 -0
  197. package/scripts/ci/check-regression-traceability.sh +67 -0
  198. package/scripts/ci/check-shell-preamble.sh +106 -0
  199. package/scripts/ci/dot-cli-startup-bench.sh +126 -0
  200. package/scripts/ci/install-chezmoi-verified.sh +4 -1
  201. package/scripts/ci/lint-reusable-pins.sh +78 -0
  202. package/scripts/ci/run-coverage.sh +451 -0
  203. package/scripts/ci/validate-chezmoidata.sh +25 -0
  204. package/scripts/ci/windows-smoke-test.ps1 +136 -0
  205. package/scripts/diagnostics/doctor.sh +203 -5
  206. package/scripts/diagnostics/drift-dashboard.sh +177 -13
  207. package/scripts/diagnostics/health.sh +21 -4
  208. package/scripts/diagnostics/perf.sh +304 -77
  209. package/scripts/diagnostics/workstation-attestation.sh +6 -1
  210. package/scripts/dot/commands/agent.sh +33 -27
  211. package/scripts/dot/commands/agents.sh +325 -0
  212. package/scripts/dot/commands/ai.sh +75 -10
  213. package/scripts/dot/commands/aliases.sh +10 -8
  214. package/scripts/dot/commands/core.sh +10 -4
  215. package/scripts/dot/commands/fleet.sh +278 -3
  216. package/scripts/dot/commands/init.sh +184 -0
  217. package/scripts/dot/commands/meta.sh +7 -4
  218. package/scripts/dot/commands/registry.sh +263 -0
  219. package/scripts/dot/commands/tools.sh +49 -1
  220. package/scripts/dot/lib/bento.sh +2 -1
  221. package/scripts/dot/lib/log.sh +6 -0
  222. package/scripts/dot/lib/platform.sh +22 -8
  223. package/scripts/dot/lib/ui.sh +145 -2
  224. package/scripts/dot/lib/utils.sh +6 -1
  225. package/scripts/git-hooks/pre-commit-audit.sh +1 -1
  226. package/scripts/git-hooks/pre-push +66 -3
  227. package/scripts/lib/secrets_provider.sh +32 -6
  228. package/scripts/ops/heal-chezmoi.sh +41 -6
  229. package/scripts/ops/rollback.sh +14 -0
  230. package/scripts/qa/powershell-contract.ps1 +95 -0
  231. package/scripts/security/check-disclosure-key-expiry.sh +110 -0
  232. package/scripts/security/lock-configs.sh +11 -2
  233. package/scripts/theme/merge-wallpaper.sh +4 -0
  234. package/scripts/theme/switch.sh +20 -10
  235. package/scripts/version-sync.sh +3 -0
  236. package/dot_config/atuin/config.toml +0 -40
  237. package/dot_local/bin/__pycache__/executable_dot-load-benchmark-ptycpython-312.pyc +0 -0
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env bash
2
+ # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # shellcheck shell=bash
4
+ #
5
+ # scripts/dot/commands/registry.sh
6
+ #
7
+ # `dot registry` — initial scaffold for the dot module registry.
8
+ #
9
+ # §3 audit roadmap: ship a registry of reusable dotfile modules
10
+ # ("rust-dev-setup", "k8s-operator-laptop") to seed network effects.
11
+ # Hosted as a GitHub-Pages-indexed JSON file to keep ops cost near
12
+ # zero.
13
+ #
14
+ # Current state: SCAFFOLD ONLY. This file ships the CLI surface and
15
+ # the JSON contract (see _registry_default_url). The registry itself
16
+ # is empty; populating it is its own roadmap item.
17
+ #
18
+ # Subcommands:
19
+ # list Show modules in the configured registry
20
+ # search <q> Filter modules by keyword (name, description, tags)
21
+ # info <name> Print full metadata for a module
22
+ # install <name> Apply a module to the current workstation (stub —
23
+ # prints what would be installed; full implementation
24
+ # needs a sandboxed apply pipeline)
25
+ # url Show the active registry URL
26
+ # set-url <u> Override the registry URL (writes to user config)
27
+ #
28
+ # Registry JSON shape:
29
+ # {
30
+ # "version": 1,
31
+ # "updated": "2026-05-15T16:00:00Z",
32
+ # "modules": [
33
+ # { "name": "rust-dev-setup",
34
+ # "description": "Rust toolchain + cargo plugins + IDE config",
35
+ # "repo": "https://github.com/example/rust-dev-setup",
36
+ # "tags": ["rust", "dev", "language"],
37
+ # "maintainer": "alice@example.com",
38
+ # "version": "1.2.0",
39
+ # "sha256": "abc123..." }
40
+ # ]
41
+ # }
42
+
43
+ set -euo pipefail
44
+
45
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
46
+ # shellcheck source=../lib/ui.sh disable=SC1091
47
+ source "$SCRIPT_DIR/../lib/ui.sh"
48
+ # shellcheck source=../lib/utils.sh disable=SC1091
49
+ source "$SCRIPT_DIR/../lib/utils.sh"
50
+
51
+ _registry_default_url() {
52
+ printf '%s\n' "https://sebastienrousseau.github.io/dotfiles/registry.json"
53
+ }
54
+
55
+ _registry_config_file() {
56
+ printf '%s/dotfiles/registry.toml\n' "${XDG_CONFIG_HOME:-$HOME/.config}"
57
+ }
58
+
59
+ _registry_url() {
60
+ if [[ -n "${DOTFILES_REGISTRY_URL:-}" ]]; then
61
+ printf '%s\n' "$DOTFILES_REGISTRY_URL"
62
+ return
63
+ fi
64
+ local cfg
65
+ cfg="$(_registry_config_file)"
66
+ if [[ -f "$cfg" ]]; then
67
+ local u
68
+ u="$(awk -F'[ \t]*=[ \t]*' '/^url[ \t]*=/{gsub(/"/,"",$2); print $2; exit}' "$cfg")"
69
+ [[ -n "$u" ]] && {
70
+ printf '%s\n' "$u"
71
+ return
72
+ }
73
+ fi
74
+ _registry_default_url
75
+ }
76
+
77
+ _registry_cache_dir() {
78
+ printf '%s/dotfiles/registry\n' "${XDG_CACHE_HOME:-$HOME/.cache}"
79
+ }
80
+
81
+ _registry_fetch() {
82
+ local url cache_dir cache_file
83
+ url="$(_registry_url)"
84
+ cache_dir="$(_registry_cache_dir)"
85
+ cache_file="$cache_dir/index.json"
86
+ mkdir -p "$cache_dir"
87
+ # Refresh if older than 6h or missing.
88
+ local now mtime
89
+ now="$(date +%s)"
90
+ if [[ -s "$cache_file" ]]; then
91
+ if mtime="$(stat -f %m "$cache_file" 2>/dev/null || stat -c %Y "$cache_file" 2>/dev/null)"; then
92
+ if ((now - mtime < 21600)); then
93
+ printf '%s\n' "$cache_file"
94
+ return 0
95
+ fi
96
+ fi
97
+ fi
98
+ if ! command -v curl >/dev/null 2>&1; then
99
+ ui_err "registry" "curl not installed"
100
+ return 127
101
+ fi
102
+ local tmp
103
+ tmp="$(mktemp "${cache_file}.XXXXXX")"
104
+ if ! curl -fsSL --max-time 15 -o "$tmp" "$url"; then
105
+ rm -f "$tmp"
106
+ if [[ -s "$cache_file" ]]; then
107
+ ui_warn "registry" "fetch failed; using stale cache at $cache_file"
108
+ printf '%s\n' "$cache_file"
109
+ return 0
110
+ fi
111
+ ui_err "registry" "could not fetch $url"
112
+ return 1
113
+ fi
114
+ mv "$tmp" "$cache_file"
115
+ printf '%s\n' "$cache_file"
116
+ }
117
+
118
+ _registry_require_jq() {
119
+ command -v jq >/dev/null 2>&1 || {
120
+ ui_err "registry" "jq is required"
121
+ return 127
122
+ }
123
+ }
124
+
125
+ cmd_registry() {
126
+ local subcommand="${1:-list}"
127
+ shift || true
128
+
129
+ case "$subcommand" in
130
+ url)
131
+ printf '%s\n' "$(_registry_url)"
132
+ ;;
133
+ set-url)
134
+ local new_url="${1:-}"
135
+ [[ -n "$new_url" ]] || {
136
+ ui_err "set-url" "missing URL"
137
+ return 1
138
+ }
139
+ # Refuse non-HTTPS schemes. The registry index is unsigned today,
140
+ # so HTTPS is the only transport that gives us cert-pinned
141
+ # integrity. The `file://` exemption is for local testing only
142
+ # (the bench-script and unit tests use it).
143
+ if [[ ! "$new_url" =~ ^(https://|file://) ]]; then
144
+ ui_err "set-url" "registry URL must use https:// (or file:// for local testing) — got: $new_url"
145
+ return 1
146
+ fi
147
+ local cfg
148
+ cfg="$(_registry_config_file)"
149
+ mkdir -p "$(dirname "$cfg")"
150
+ # Atomic write so a concurrent invocation can't read a half-
151
+ # written file. Explicit if/else (avoid SC2015 A && B || C).
152
+ local _tmp
153
+ _tmp="$(mktemp "${cfg}.XXXXXX")"
154
+ if printf 'url = "%s"\n' "$new_url" >"$_tmp"; then
155
+ if ! mv "$_tmp" "$cfg"; then
156
+ rm -f "$_tmp"
157
+ ui_err "set-url" "failed to commit $cfg"
158
+ return 1
159
+ fi
160
+ else
161
+ rm -f "$_tmp"
162
+ ui_err "set-url" "failed to write $cfg"
163
+ return 1
164
+ fi
165
+ ui_ok "registry" "set to $new_url ($cfg)"
166
+ ;;
167
+ list)
168
+ _registry_require_jq || return $?
169
+ local index
170
+ index="$(_registry_fetch)" || return $?
171
+ ui_header "Registry modules"
172
+ ui_info "Source" "$(_registry_url)"
173
+ echo ""
174
+ if ! jq -e '.modules | length > 0' "$index" >/dev/null 2>&1; then
175
+ ui_warn "registry" "no modules published yet — see docs/operations/REGISTRY.md to contribute one"
176
+ return 0
177
+ fi
178
+ ui_table_begin "Module" "Version" "Description"
179
+ while IFS=$'\t' read -r name ver desc; do
180
+ ui_table_add "$name" "v$ver" "$desc"
181
+ done < <(jq -r '.modules[] | "\(.name)\t\(.version // "-")\t\(.description // "")"' "$index")
182
+ ui_table_end
183
+ ;;
184
+ search)
185
+ _registry_require_jq || return $?
186
+ local q="${1:-}"
187
+ [[ -n "$q" ]] || {
188
+ ui_err "search" "missing query"
189
+ return 1
190
+ }
191
+ local index
192
+ index="$(_registry_fetch)" || return $?
193
+ ui_header "Registry search: $q"
194
+ echo ""
195
+ ui_table_begin "Module" "Version" "Description"
196
+ while IFS=$'\t' read -r name ver desc; do
197
+ ui_table_add "$name" "v$ver" "$desc"
198
+ done < <(jq -r --arg q "$q" '
199
+ .modules[]
200
+ | select(
201
+ (.name // "" | ascii_downcase | contains($q | ascii_downcase)) or
202
+ (.description // "" | ascii_downcase | contains($q | ascii_downcase)) or
203
+ ((.tags // []) | map(ascii_downcase) | index($q | ascii_downcase))
204
+ )
205
+ | "\(.name)\t\(.version // "-")\t\(.description // "")"
206
+ ' "$index")
207
+ ui_table_end
208
+ ;;
209
+ info)
210
+ _registry_require_jq || return $?
211
+ local name="${1:-}"
212
+ [[ -n "$name" ]] || {
213
+ ui_err "info" "missing module name"
214
+ return 1
215
+ }
216
+ local index
217
+ index="$(_registry_fetch)" || return $?
218
+ local found
219
+ found="$(jq -r --arg n "$name" '.modules[] | select(.name == $n) | "OK"' "$index" 2>/dev/null)"
220
+ if [[ "$found" != "OK" ]]; then
221
+ ui_err "info" "module not found: $name"
222
+ return 1
223
+ fi
224
+ jq -r --arg n "$name" '.modules[] | select(.name == $n) | to_entries[] | "\(.key)\t\(.value | if type == "array" then join(", ") else tostring end)"' "$index" |
225
+ while IFS=$'\t' read -r key value; do
226
+ ui_ok "$key" "$value"
227
+ done
228
+ ;;
229
+ install)
230
+ local name="${1:-}"
231
+ [[ -n "$name" ]] || {
232
+ ui_err "install" "missing module name"
233
+ return 1
234
+ }
235
+ ui_warn "install" "scaffold only — full module installer is a roadmap item"
236
+ ui_info "install" "would fetch module $name from registry and apply it as a chezmoi sub-source"
237
+ return 0
238
+ ;;
239
+ --help | -h | help)
240
+ cat <<EOF
241
+ Usage: dot registry <subcommand>
242
+
243
+ Subcommands:
244
+ list List modules in the configured registry
245
+ search <q> Filter modules by keyword (name, description, tags)
246
+ info <name> Print metadata for a single module
247
+ install <name> Install a module (scaffold — see docs/operations/REGISTRY.md)
248
+ url Show the active registry URL
249
+ set-url <url> Override the registry URL (persists to user config)
250
+
251
+ Env overrides:
252
+ DOTFILES_REGISTRY_URL One-shot override of the registry URL.
253
+
254
+ Default registry: $(_registry_default_url)
255
+ EOF
256
+ ;;
257
+ *)
258
+ ui_err "Unknown subcommand" "$subcommand"
259
+ echo "Run 'dot registry --help' for usage." >&2
260
+ return 1
261
+ ;;
262
+ esac
263
+ }
@@ -353,7 +353,55 @@ cmd_env_mise() {
353
353
  exit 1
354
354
  fi
355
355
  case "${1:-list}" in
356
- list | ls) mise ls ;;
356
+ list | ls)
357
+ if has_command jq; then
358
+ ui_table_begin "Tool" "Version" "Source" "Requested"
359
+ while IFS=$'\t' read -r tool ver source req; do
360
+ ui_table_add "$tool" "$ver" "${source/$HOME/\~}" "$req"
361
+ done < <(mise ls --json 2>/dev/null | jq -r '
362
+ to_entries[] as $t
363
+ | $t.value[]
364
+ | [
365
+ $t.key,
366
+ (.version // "-"),
367
+ (.source.path // ""),
368
+ (.requested_version // "")
369
+ ]
370
+ | @tsv
371
+ ')
372
+ ui_table_end
373
+ else
374
+ mise ls
375
+ fi
376
+ # Surface orphan installs (tool versions on disk that no active config
377
+ # claims). `--dry-run-code` exits 1 iff there is something to prune;
378
+ # the call is fast (no I/O beyond reading the tracked-configs index).
379
+ if mise prune --dry-run-code --quiet >/dev/null 2>&1; then
380
+ :
381
+ else
382
+ echo ""
383
+ ui_warn "orphan installs" "tool versions on disk are not requested by any config"
384
+ ui_info "to clean" "run 'dot env prune' (dry-run) or 'dot env prune --yes' to commit"
385
+ fi
386
+ ;;
387
+ prune)
388
+ shift
389
+ local commit=0
390
+ for arg in "$@"; do
391
+ case "$arg" in
392
+ --yes | -y) commit=1 ;;
393
+ esac
394
+ done
395
+ if ((commit)); then
396
+ mise prune
397
+ else
398
+ ui_info "dry-run" "showing what 'mise prune' would remove (pass --yes to commit)"
399
+ echo ""
400
+ mise prune --dry-run
401
+ echo ""
402
+ ui_info "next" "re-run with 'dot env prune --yes' to actually uninstall"
403
+ fi
404
+ ;;
357
405
  install)
358
406
  shift
359
407
  # Validate tool names to prevent injection
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh and dot_local/bin/executable_dot; inherits set -euo pipefail.
3
4
  # Dotfiles 2026: Atomic Intelligence Surface
4
5
  # High-fidelity, perfectly aligned, and professional.
5
6
 
@@ -30,7 +31,7 @@ _dotfiles_bento_render() {
30
31
 
31
32
  # Render a fixed-width card (42 cols) so output aligns in any terminal width
32
33
  printf "\n"
33
- printf " ${c_cyan}${c_bold}💎 D O T F I L E S${c_reset} ${c_slate}[v0.2.500]${c_reset}\n"
34
+ printf " ${c_cyan}${c_bold}💎 D O T F I L E S${c_reset} ${c_slate}[v0.2.502]${c_reset}\n"
34
35
  printf " ${c_slate}──────────────────────────────────────────${c_reset}\n"
35
36
 
36
37
  # Key system properties at a glance — answers "is my env healthy?" in 1 second
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh and scripts/diagnostics/*; inherits set -euo pipefail.
3
4
  # Structured JSON logging and metrics library.
4
5
  # Source this file to emit machine-readable logs and performance metrics.
5
6
  #
@@ -8,6 +9,11 @@
8
9
  # dot_log info "apply_start" "source=chezmoi"
9
10
  # dot_metric "shell_startup" 142 ms
10
11
 
12
+ # Re-source guard: re-sourcing would mint a new DOT_TRACE_ID and break
13
+ # correlation across modules that already captured the original.
14
+ [[ "${_DOT_LIB_LOG_LOADED:-0}" == "1" ]] && return 0
15
+ _DOT_LIB_LOG_LOADED=1
16
+
11
17
  # Correlation ID for tracing across commands in a single invocation
12
18
  DOT_TRACE_ID="${DOT_TRACE_ID:-$(date +%s%N 2>/dev/null | tail -c 12 || date +%s)}"
13
19
  export DOT_TRACE_ID
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh; inherits set -euo pipefail.
3
4
  # Dotfiles CLI Platform Abstraction
4
5
  # Unified helpers for macOS, Linux, and WSL parity.
5
6
 
@@ -38,12 +39,22 @@ dot_host_os() {
38
39
  }
39
40
 
40
41
  # Convert host-native path into Linux path when inside WSL.
42
+ #
43
+ # Contract:
44
+ # - In WSL: requires `wslpath`. Returns 2 (with a stderr error) if
45
+ # missing — callers must not silently treat a Windows-style path
46
+ # as Linux-safe.
47
+ # - Outside WSL: paths are already Linux/macOS paths; echoes the
48
+ # input unchanged and returns 0.
49
+ # - Empty input returns 1 (usage error).
41
50
  dot_path_to_unix() {
42
51
  local p="${1:-}"
43
- if [[ -z "$p" ]]; then
44
- return 1
45
- fi
46
- if dot_is_wsl && command -v wslpath >/dev/null 2>&1; then
52
+ [[ -n "$p" ]] || return 1
53
+ if dot_is_wsl; then
54
+ if ! command -v wslpath >/dev/null 2>&1; then
55
+ printf "dot_path_to_unix: wslpath required in WSL but not found\n" >&2
56
+ return 2
57
+ fi
47
58
  wslpath -u "$p"
48
59
  return
49
60
  fi
@@ -51,12 +62,15 @@ dot_path_to_unix() {
51
62
  }
52
63
 
53
64
  # Convert Linux path into host-native path when inside WSL.
65
+ # Same contract as dot_path_to_unix (see above).
54
66
  dot_path_to_native() {
55
67
  local p="${1:-}"
56
- if [[ -z "$p" ]]; then
57
- return 1
58
- fi
59
- if dot_is_wsl && command -v wslpath >/dev/null 2>&1; then
68
+ [[ -n "$p" ]] || return 1
69
+ if dot_is_wsl; then
70
+ if ! command -v wslpath >/dev/null 2>&1; then
71
+ printf "dot_path_to_native: wslpath required in WSL but not found\n" >&2
72
+ return 2
73
+ fi
60
74
  wslpath -w "$p"
61
75
  return
62
76
  fi
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh, scripts/diagnostics/*, scripts/ops/*; inherits set -euo pipefail.
3
4
  ## Dotfiles CLI UI Component Library — Single Source of Truth.
4
5
  ##
5
6
  ## All CLI output MUST go through these primitives. No raw printf with
@@ -30,6 +31,11 @@
30
31
  ## ui_header "Section Title"
31
32
  ## ui_ok "Operation succeeded"
32
33
 
34
+ # Re-source guard: re-sourcing would zero out the BOLD/RED/etc colour
35
+ # variables that ui_init() populated, breaking already-rendered output.
36
+ [[ "${_DOT_LIB_UI_LOADED:-0}" == "1" ]] && return 0
37
+ _DOT_LIB_UI_LOADED=1
38
+
33
39
  # ═══════════════════════════════════════════════════════════════════════
34
40
  # State — all zeroed before ui_init
35
41
  # ═══════════════════════════════════════════════════════════════════════
@@ -265,7 +271,12 @@ ui_spinner_stop() {
265
271
  fi
266
272
  ui_clear_line
267
273
  ui_show_cursor
274
+ # The newline is only needed when stdout is NOT a TTY. We must return
275
+ # 0 either way — without the explicit `return 0`, the function's exit
276
+ # status comes from the trailing `[[ ! -t 1 ]] && printf` chain, which
277
+ # is rc=1 on a TTY and breaks every caller running under `set -e`.
268
278
  [[ ! -t 1 ]] && printf "\n"
279
+ return 0
269
280
  }
270
281
 
271
282
  # ═══════════════════════════════════════════════════════════════════════
@@ -348,9 +359,13 @@ ui_run_cmd() {
348
359
  done
349
360
  wait "$pid" 2>/dev/null
350
361
 
351
- local rc
352
- rc=$(cat "$rc_file" 2>/dev/null || echo 1)
362
+ # Guard against the rc_file being empty (race between subshell exit
363
+ # and parent read): an unset rc would default to non-numeric "" and
364
+ # fail the `[[ == "0" ]]` check confusingly. Treat empty as failure.
365
+ local rc=""
366
+ [[ -s "$rc_file" ]] && rc="$(<"$rc_file")"
353
367
  rm -f "$rc_file"
368
+ rc="${rc:-1}"
354
369
 
355
370
  ui_clear_line
356
371
  ui_show_cursor
@@ -461,6 +476,134 @@ ui_table_sep() {
461
476
  printf '\n'
462
477
  }
463
478
 
479
+ # ═══════════════════════════════════════════════════════════════════════
480
+ # Buffered table — accumulates rows then renders via `gum table -p`
481
+ # (rounded borders) when gum is on PATH and stdout is a TTY; falls back
482
+ # to the existing printf-based ui_table_header/row otherwise.
483
+ #
484
+ # ui_table_begin "Tool" "Version" "Source" "Requested"
485
+ # ui_table_add "node" "24.14.0" "~/.dotfiles/mise.toml" "24.14.0"
486
+ # ui_table_add "node" "25.9.0" "" ""
487
+ # ui_table_end
488
+ #
489
+ # Cells may contain anything except ASCII US (0x1f), the internal row
490
+ # separator. Empty cells render as blank in both modes.
491
+ #
492
+ # Environment overrides:
493
+ # DOTFILES_NO_TUI=1 force the printf fallback even if gum is installed
494
+ # NO_COLOR=… standard convention; also forces the fallback
495
+ # ═══════════════════════════════════════════════════════════════════════
496
+ _UI_TABLE_HEADERS=()
497
+ _UI_TABLE_ROWS=()
498
+
499
+ ui_table_begin() {
500
+ _UI_TABLE_HEADERS=("$@")
501
+ _UI_TABLE_ROWS=()
502
+ }
503
+
504
+ ui_table_add() {
505
+ if [[ "${#_UI_TABLE_HEADERS[@]}" -eq 0 ]]; then
506
+ return 1
507
+ fi
508
+ local IFS=$'\x1f'
509
+ _UI_TABLE_ROWS+=("$*")
510
+ }
511
+
512
+ ui_table_end() {
513
+ if [[ "${#_UI_TABLE_HEADERS[@]}" -eq 0 ]]; then
514
+ return 0
515
+ fi
516
+
517
+ local use_gum=0
518
+ if command -v gum >/dev/null 2>&1 &&
519
+ [[ -t 1 ]] &&
520
+ [[ "${DOTFILES_NO_TUI:-0}" != "1" ]] &&
521
+ [[ -z "${NO_COLOR:-}" ]]; then
522
+ use_gum=1
523
+ fi
524
+
525
+ if ((use_gum)); then
526
+ local header_row
527
+ local IFS=$'\x1f'
528
+ header_row="${_UI_TABLE_HEADERS[*]}"
529
+ # Charm palette: 212 = hot pink (matches ui_header), 240 = muted grey.
530
+ # Cell colour intentionally left at terminal default so the table
531
+ # reads on both light and dark backgrounds.
532
+ # Override via DOTFILES_TABLE_{BORDER,HEADER}_FG env vars.
533
+ local border_fg="${DOTFILES_TABLE_BORDER_FG:-240}"
534
+ local header_fg="${DOTFILES_TABLE_HEADER_FG:-212}"
535
+ {
536
+ printf '%s\n' "$header_row"
537
+ printf '%s\n' "${_UI_TABLE_ROWS[@]}"
538
+ } | gum table --print \
539
+ --separator=$'\x1f' \
540
+ --border=rounded \
541
+ --border.foreground="$border_fg" \
542
+ --header.foreground="$header_fg" \
543
+ --padding="0 1" 2>/dev/null ||
544
+ _ui_table_printf_fallback
545
+ else
546
+ _ui_table_printf_fallback
547
+ fi
548
+
549
+ _UI_TABLE_HEADERS=()
550
+ _UI_TABLE_ROWS=()
551
+ }
552
+
553
+ _ui_table_printf_fallback() {
554
+ ui_init
555
+ # Pre-scan all buffered rows + headers to compute per-column width so
556
+ # values aren't truncated or collide. Min width 8, +2 padding.
557
+ local ncols="${#_UI_TABLE_HEADERS[@]}"
558
+ local -a widths=()
559
+ local i
560
+ for ((i = 0; i < ncols; i++)); do
561
+ widths[i]="${#_UI_TABLE_HEADERS[i]}"
562
+ done
563
+ local row
564
+ for row in "${_UI_TABLE_ROWS[@]}"; do
565
+ local -a _fields=()
566
+ local IFS=$'\x1f'
567
+ read -ra _fields <<<"$row"
568
+ for ((i = 0; i < ncols; i++)); do
569
+ local len="${#_fields[i]}"
570
+ ((len > widths[i])) && widths[i]=$len
571
+ done
572
+ done
573
+ for ((i = 0; i < ncols; i++)); do
574
+ ((widths[i] += 2))
575
+ ((widths[i] < 8)) && widths[i]=8
576
+ done
577
+
578
+ # Emit header (bold when color available), separator, then rows.
579
+ local out=" "
580
+ for ((i = 0; i < ncols; i++)); do
581
+ if [[ "$UI_COLOR" = "1" ]]; then
582
+ out+="$(printf '%s%-*s%s' "$BOLD" "${widths[i]}" "${_UI_TABLE_HEADERS[i]}" "$NORMAL")"
583
+ else
584
+ out+="$(printf '%-*s' "${widths[i]}" "${_UI_TABLE_HEADERS[i]}")"
585
+ fi
586
+ done
587
+ printf '%s\n' "$out"
588
+
589
+ local total=2
590
+ for ((i = 0; i < ncols; i++)); do ((total += widths[i])); done
591
+ printf ' '
592
+ for ((i = 0; i < total - 2; i++)); do printf '─'; done
593
+ printf '\n'
594
+
595
+ for row in "${_UI_TABLE_ROWS[@]}"; do
596
+ local -a _fields=()
597
+ local IFS=$'\x1f'
598
+ read -ra _fields <<<"$row"
599
+ out=" "
600
+ for ((i = 0; i < ncols; i++)); do
601
+ out+="$(printf '%-*s' "${widths[i]}" "${_fields[i]:-}")"
602
+ done
603
+ printf '%s\n' "$out"
604
+ done
605
+ }
606
+
464
607
  # ═══════════════════════════════════════════════════════════════════════
465
608
  # Logo
466
609
  # ═══════════════════════════════════════════════════════════════════════
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh and dot_local/bin/executable_dot; inherits set -euo pipefail.
3
4
  # Dotfiles CLI Utilities
4
5
  # Shared functions for dot command modules
5
6
 
7
+ # Re-source guard: cheap short-circuit when sourced from multiple modules.
8
+ [[ "${_DOT_LIB_UTILS_LOADED:-0}" == "1" ]] && return 0
9
+ _DOT_LIB_UTILS_LOADED=1
10
+
6
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
12
  # shellcheck source=ui.sh
8
13
  source "$SCRIPT_DIR/ui.sh"
@@ -269,7 +274,7 @@ dot_command_summary() {
269
274
  echo "Manage secrets (set/get/list/load/provider)."
270
275
  ;;
271
276
  env)
272
- echo "Load secret buckets into shell exports."
277
+ echo "List mise-managed toolchain versions and sources."
273
278
  ;;
274
279
  secrets-create)
275
280
  echo "Create a new encrypted secrets file."
@@ -140,6 +140,6 @@ if [[ $FAILED -eq 1 ]]; then
140
140
  printf '%b\\n' " (Use --no-verify to bypass if absolutely necessary)"
141
141
  exit 1
142
142
  else
143
- printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.500 standards maintained."
143
+ printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.502 standards maintained."
144
144
  exit 0
145
145
  fi