@sebastienrousseau/dotfiles 0.2.520 → 0.2.521

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE-APACHE +190 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +43 -37
  5. package/install.sh +76 -10
  6. package/package.json +7 -7
  7. package/tools/README.md +49 -0
  8. package/tools/ci/install-chezmoi-verified.sh +68 -0
  9. package/docs/.vitepress/reports/localization-readability-audit.md +0 -73
  10. package/docs/AI.md +0 -179
  11. package/docs/ARCHITECTURE.md +0 -117
  12. package/docs/CNAME +0 -1
  13. package/docs/CONFIG_STRATEGY.md +0 -124
  14. package/docs/COPYRIGHT +0 -7
  15. package/docs/ECOSYSTEM.md +0 -220
  16. package/docs/GOLD-STANDARD-AUDIT.md +0 -352
  17. package/docs/GOVERNANCE.md +0 -98
  18. package/docs/MAINTAINERS.md +0 -41
  19. package/docs/MINIMUM-TOOLCHAIN.md +0 -100
  20. package/docs/NAMING_CONVENTIONS.md +0 -102
  21. package/docs/OPENCODE.md +0 -127
  22. package/docs/README.md +0 -84
  23. package/docs/STRUCTURE.md +0 -102
  24. package/docs/adr/ADR-001-ci-cd-pipeline.md +0 -118
  25. package/docs/adr/ADR-002-shell-performance.md +0 -130
  26. package/docs/adr/ADR-003-security-first.md +0 -158
  27. package/docs/adr/ADR-004-cli-architecture.md +0 -171
  28. package/docs/adr/ADR-005-chezmoi-choice.md +0 -99
  29. package/docs/adr/ADR-006-shell-selection.md +0 -124
  30. package/docs/adr/ADR-007-multi-shell-parity.md +0 -62
  31. package/docs/adr/ADR-008-alias-system-architecture.md +0 -95
  32. package/docs/adr/ADR-009-wallpaper-driven-theming.md +0 -131
  33. package/docs/adr/ADR-010-starship-transient-prompt.md +0 -144
  34. package/docs/adr/ADR-011-nushell-tier3-keep.md +0 -144
  35. package/docs/adr/ADR-012-ai-fleet-local-proxy.md +0 -79
  36. package/docs/adr/README.md +0 -40
  37. package/docs/architecture/AI_COST_OPTIMIZATION.md +0 -144
  38. package/docs/architecture/ARCHITECTURE.md +0 -20
  39. package/docs/architecture/INTEROP.md +0 -44
  40. package/docs/architecture/REPO_LAYOUT.md +0 -241
  41. package/docs/architecture/WALKTHROUGH.md +0 -86
  42. package/docs/architecture/fleet-deployment.md +0 -77
  43. package/docs/archive/EUXIS_2026_REVIEW.md +0 -127
  44. package/docs/archive/LEGACY_ROADMAP.md +0 -6
  45. package/docs/archive/MILESTONE_v0.2.493.md +0 -47
  46. package/docs/archive/PLAN.md +0 -199
  47. package/docs/archive/REPO_AUDIT.md +0 -31
  48. package/docs/articles/.pages +0 -6
  49. package/docs/articles/2026-07-05-custom-mkdocs-material-dark-theme.md +0 -216
  50. package/docs/articles/2026-07-05-fish-startup-abbr.md +0 -153
  51. package/docs/articles/2026-07-05-master-to-main-rename-runbook.md +0 -128
  52. package/docs/articles/index.md +0 -36
  53. package/docs/guides/INSTALL.md +0 -144
  54. package/docs/guides/MACOS_ICLOUD_SYMLINKS.md +0 -121
  55. package/docs/guides/NEOVIM_IDE_GUIDE.md +0 -61
  56. package/docs/guides/THEMING.md +0 -230
  57. package/docs/guides/TROUBLESHOOTING.md +0 -176
  58. package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +0 -792
  59. package/docs/index.md +0 -132
  60. package/docs/interop/A2A.md +0 -39
  61. package/docs/interop/POWERSHELL.md +0 -102
  62. package/docs/manual/00-introduction.md +0 -89
  63. package/docs/manual/01-concepts/01-architecture.md +0 -138
  64. package/docs/manual/01-concepts/02-trust-model.md +0 -183
  65. package/docs/manual/01-concepts/03-theme-engine.md +0 -186
  66. package/docs/manual/01-concepts/04-fleet.md +0 -148
  67. package/docs/manual/01-concepts/05-self-healing.md +0 -204
  68. package/docs/manual/02-tutorials/01-first-install.md +0 -197
  69. package/docs/manual/02-tutorials/02-add-wallpaper.md +0 -216
  70. package/docs/manual/02-tutorials/03-create-profile.md +0 -244
  71. package/docs/manual/02-tutorials/04-encrypt-secret.md +0 -281
  72. package/docs/manual/02-tutorials/05-deploy-fleet.md +0 -283
  73. package/docs/manual/03-reference/01-dot-cli.md +0 -475
  74. package/docs/manual/03-reference/02-config-files.md +0 -265
  75. package/docs/manual/03-reference/03-environment.md +0 -124
  76. package/docs/manual/03-reference/04-templates.md +0 -190
  77. package/docs/manual/03-reference/05-feature-flags.md +0 -187
  78. package/docs/manual/04-cookbook/01-recipes.md +0 -285
  79. package/docs/manual/04-cookbook/02-troubleshooting.md +0 -351
  80. package/docs/manual/04-cookbook/03-faq.md +0 -175
  81. package/docs/manual/05-appendices/A-platform-matrix.md +0 -101
  82. package/docs/manual/05-appendices/B-security-checklist.md +0 -85
  83. package/docs/manual/05-appendices/C-glossary.md +0 -40
  84. package/docs/manual/05-appendices/D-bibliography.md +0 -58
  85. package/docs/manual/05-appendices/E-license.md +0 -38
  86. package/docs/manual/_toc.yml +0 -58
  87. package/docs/manual/command-index.md +0 -175
  88. package/docs/manual/concept-index.md +0 -170
  89. package/docs/manual/index.md +0 -66
  90. package/docs/migration/README.md +0 -81
  91. package/docs/migration/from-bare-git-repo.md +0 -156
  92. package/docs/migration/from-gnu-stow.md +0 -165
  93. package/docs/migration/from-plain-chezmoi.md +0 -148
  94. package/docs/migration/from-yadm.md +0 -187
  95. package/docs/operations/ARCHITECTURE_ROADMAP.md +0 -7
  96. package/docs/operations/ATTESTATION.md +0 -44
  97. package/docs/operations/CI_CADENCE.md +0 -107
  98. package/docs/operations/CI_COMPOSITES.md +0 -156
  99. package/docs/operations/COMPLETIONS.md +0 -123
  100. package/docs/operations/COVERAGE.md +0 -204
  101. package/docs/operations/DRIFT.md +0 -107
  102. package/docs/operations/HARD_AUDIT_2026.md +0 -631
  103. package/docs/operations/MAINTENANCE.md +0 -63
  104. package/docs/operations/MANIFEST.md +0 -127
  105. package/docs/operations/MIGRATION.md +0 -109
  106. package/docs/operations/OPERATIONS.md +0 -188
  107. package/docs/operations/PERFORMANCE.md +0 -133
  108. package/docs/operations/PERFORMANCE_BUDGETS.md +0 -196
  109. package/docs/operations/REGISTRY.md +0 -90
  110. package/docs/operations/RELEASE_PIPELINE.md +0 -128
  111. package/docs/operations/RELIABILITY.md +0 -122
  112. package/docs/operations/RFC_v0_2_503_reorganization.md +0 -280
  113. package/docs/operations/ROADMAP.md +0 -10
  114. package/docs/operations/ROADMAP_2026.md +0 -7
  115. package/docs/operations/ROADMAP_V0_2_503.md +0 -10
  116. package/docs/operations/TESTING.md +0 -216
  117. package/docs/operations/TRACEABILITY.md +0 -44
  118. package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +0 -65
  119. package/docs/operations/VERSION_SYNC.md +0 -393
  120. package/docs/packaging.md +0 -222
  121. package/docs/reference/ALIASES.md +0 -131
  122. package/docs/reference/ALIASES_CHEATSHEET.md +0 -32
  123. package/docs/reference/ALIASES_DEPRECATIONS.md +0 -13
  124. package/docs/reference/FEATURE-MATRIX.md +0 -646
  125. package/docs/reference/FEATURES.md +0 -66
  126. package/docs/reference/FONTS.md +0 -112
  127. package/docs/reference/POWERSHELL_PARITY.md +0 -82
  128. package/docs/reference/PROFILES.md +0 -69
  129. package/docs/reference/SCREENSHOTS.md +0 -121
  130. package/docs/reference/SCRIPTS.md +0 -71
  131. package/docs/reference/SUPPORT_MATRIX.md +0 -80
  132. package/docs/reference/THEMES.md +0 -117
  133. package/docs/reference/TOOLS.md +0 -110
  134. package/docs/reference/UTILS.md +0 -243
  135. package/docs/registry.json +0 -6
  136. package/docs/schema/dot-env-v1.json +0 -110
  137. package/docs/schema/dot-registry-v1.json +0 -33
  138. package/docs/security/AI_ACT_COMPLIANCE.md +0 -94
  139. package/docs/security/AUDIT_BYPASS.md +0 -103
  140. package/docs/security/AUTOMATION_SECRETS.md +0 -26
  141. package/docs/security/CI_EGRESS_ALLOWLIST.md +0 -127
  142. package/docs/security/CI_PINNING.md +0 -129
  143. package/docs/security/COMMIT_SIGNING.md +0 -138
  144. package/docs/security/COMPLIANCE.md +0 -458
  145. package/docs/security/DEPS_DEV_EXCEPTIONS.md +0 -86
  146. package/docs/security/DISCLOSURE.md +0 -130
  147. package/docs/security/ENCRYPTION.md +0 -57
  148. package/docs/security/FMEA.md +0 -159
  149. package/docs/security/FUZZING.md +0 -209
  150. package/docs/security/HISTORY_FILTERING.md +0 -132
  151. package/docs/security/INCIDENT_RESPONSE.md +0 -579
  152. package/docs/security/INSTALL_VERIFICATION.md +0 -122
  153. package/docs/security/KEYS.md +0 -49
  154. package/docs/security/KEY_ROTATION.md +0 -303
  155. package/docs/security/MCP_POLICY.md +0 -78
  156. package/docs/security/POLICY_RELEASES.md +0 -37
  157. package/docs/security/README.md +0 -28
  158. package/docs/security/SCORECARD.md +0 -195
  159. package/docs/security/SECRETS.md +0 -158
  160. package/docs/security/SECURITY.md +0 -45
  161. package/docs/security/SECURITY_CHECKLIST.md +0 -55
  162. package/docs/security/SHELL_EXEMPTIONS.md +0 -145
  163. package/docs/security/SOUP_REGISTER.md +0 -36
  164. package/docs/security/THREAT_MODEL.md +0 -130
  165. package/docs/security/VERIFICATION_VALIDATION.md +0 -228
  166. package/docs/security/VERIFY_RELEASE.md +0 -201
  167. package/docs/security/security-pubkey.asc +0 -15
  168. package/docs/stylesheets/extra.css +0 -444
  169. package/docs/themes/README.md +0 -10
  170. package/docs/themes/VISUAL_INTEGRITY_REPORT.md +0 -30
  171. package/docs/themes/hero-shot.svg +0 -78
  172. package/scripts/README.md +0 -123
  173. package/scripts/ci/check-copyright-headers.sh +0 -8
  174. package/scripts/ci/check-shell-preamble.sh +0 -8
  175. package/scripts/ci/guard-gitleaks-checkout.sh +0 -8
  176. package/scripts/demo/record.sh +0 -43
  177. package/scripts/diagnostics/a2a-conformance.sh +0 -163
  178. package/scripts/diagnostics/alias-governance.sh +0 -165
  179. package/scripts/diagnostics/aliases-cheatsheet.sh +0 -74
  180. package/scripts/diagnostics/aliases-manifest.sh +0 -77
  181. package/scripts/diagnostics/attest-verify.sh +0 -147
  182. package/scripts/diagnostics/benchmark.sh +0 -408
  183. package/scripts/diagnostics/conflicts.sh +0 -73
  184. package/scripts/diagnostics/doctor-unified.sh +0 -43
  185. package/scripts/diagnostics/doctor.sh +0 -797
  186. package/scripts/diagnostics/drift-dashboard.sh +0 -203
  187. package/scripts/diagnostics/health.sh +0 -656
  188. package/scripts/diagnostics/history-analysis.sh +0 -86
  189. package/scripts/diagnostics/mcp-doctor.sh +0 -582
  190. package/scripts/diagnostics/perf.sh +0 -453
  191. package/scripts/diagnostics/scorecard.sh +0 -120
  192. package/scripts/diagnostics/secret-governance.sh +0 -65
  193. package/scripts/diagnostics/security-score.sh +0 -467
  194. package/scripts/diagnostics/smoke-test.sh +0 -88
  195. package/scripts/diagnostics/snapshot.sh +0 -90
  196. package/scripts/diagnostics/verify.sh +0 -108
  197. package/scripts/diagnostics/verify_state.sh +0 -73
  198. package/scripts/diagnostics/version-locks.sh +0 -94
  199. package/scripts/diagnostics/workstation-attestation.sh +0 -212
  200. package/scripts/dot/commands/agent.sh +0 -535
  201. package/scripts/dot/commands/agents.sh +0 -352
  202. package/scripts/dot/commands/ai.sh +0 -600
  203. package/scripts/dot/commands/aliases.sh +0 -277
  204. package/scripts/dot/commands/appearance.sh +0 -110
  205. package/scripts/dot/commands/completion.sh +0 -171
  206. package/scripts/dot/commands/core.sh +0 -217
  207. package/scripts/dot/commands/diagnostics.sh +0 -265
  208. package/scripts/dot/commands/env-emit.sh +0 -203
  209. package/scripts/dot/commands/fleet.sh +0 -711
  210. package/scripts/dot/commands/init.sh +0 -185
  211. package/scripts/dot/commands/lint.sh +0 -208
  212. package/scripts/dot/commands/manual.sh +0 -169
  213. package/scripts/dot/commands/meta.sh +0 -438
  214. package/scripts/dot/commands/patterns.sh +0 -55
  215. package/scripts/dot/commands/registry.sh +0 -455
  216. package/scripts/dot/commands/restore.sh +0 -232
  217. package/scripts/dot/commands/secrets.sh +0 -296
  218. package/scripts/dot/commands/security.sh +0 -102
  219. package/scripts/dot/commands/tools.sh +0 -570
  220. package/scripts/dot/data/alias-deprecations.tsv +0 -2
  221. package/scripts/dot/powershell/Dot.psm1 +0 -319
  222. package/scripts/fonts/install-nerd-fonts.sh +0 -75
  223. package/scripts/fonts/patch-fonts.sh +0 -36
  224. package/scripts/git-hooks/install.sh +0 -12
  225. package/scripts/git-hooks/pre-commit +0 -12
  226. package/scripts/git-hooks/pre-commit-audit.sh +0 -146
  227. package/scripts/git-hooks/pre-push +0 -105
  228. package/scripts/git-hooks/prepare-commit-msg +0 -29
  229. package/scripts/lib/secrets_provider.sh +0 -200
  230. package/scripts/nvim/headless-upgrade.lua +0 -81
  231. package/scripts/ops/ai-setup.sh +0 -71
  232. package/scripts/ops/bundle.sh +0 -104
  233. package/scripts/ops/chaos.sh +0 -50
  234. package/scripts/ops/chezmoi-apply.sh +0 -333
  235. package/scripts/ops/chezmoi-diff.sh +0 -16
  236. package/scripts/ops/chezmoi-remove.sh +0 -46
  237. package/scripts/ops/chezmoi-update.sh +0 -67
  238. package/scripts/ops/heal-chezmoi.sh +0 -87
  239. package/scripts/ops/heal-system.sh +0 -129
  240. package/scripts/ops/heal-tools.sh +0 -297
  241. package/scripts/ops/heal.sh +0 -223
  242. package/scripts/ops/post-apply-repair.sh +0 -107
  243. package/scripts/ops/prewarm.sh +0 -128
  244. package/scripts/ops/release.sh +0 -262
  245. package/scripts/ops/rollback.sh +0 -613
  246. package/scripts/ops/setup.sh +0 -138
  247. package/scripts/ops/teleport.sh +0 -34
  248. package/scripts/qa/check-feature-matrix.sh +0 -296
  249. package/scripts/qa/check-version-consistency.sh +0 -12
  250. package/scripts/qa/coverage-baseline.sh +0 -61
  251. package/scripts/qa/docs-coverage.sh +0 -118
  252. package/scripts/qa/examples-coverage.sh +0 -94
  253. package/scripts/qa/powershell-contract.ps1 +0 -95
  254. package/scripts/qa/reliability-audit.sh +0 -139
  255. package/scripts/qa/scorecard-snapshot.sh +0 -128
  256. package/scripts/qa/traceability-coverage.sh +0 -124
  257. package/scripts/qa/validate-examples.sh +0 -90
  258. package/scripts/qa/wsl-contract.sh +0 -12
  259. package/scripts/secrets/age-init.sh +0 -82
  260. package/scripts/secrets/create-secrets-file.sh +0 -46
  261. package/scripts/secrets/encrypt-ssh-key.sh +0 -44
  262. package/scripts/security/backup.sh +0 -58
  263. package/scripts/security/check-disclosure-key-expiry.sh +0 -111
  264. package/scripts/security/dns-doh.sh +0 -52
  265. package/scripts/security/encryption-check.sh +0 -55
  266. package/scripts/security/enforce-policies.sh +0 -552
  267. package/scripts/security/firewall.sh +0 -91
  268. package/scripts/security/lock-configs.sh +0 -67
  269. package/scripts/security/lock-screen.sh +0 -56
  270. package/scripts/security/manage-secrets.sh +0 -429
  271. package/scripts/security/ssh-cert.sh +0 -204
  272. package/scripts/security/telemetry-kill.sh +0 -51
  273. package/scripts/security/usb-safety.sh +0 -52
  274. package/scripts/theme/apply-gnome-theme.sh +0 -333
  275. package/scripts/theme/extract-heic-frames.sh +0 -115
  276. package/scripts/theme/extract-theme.py +0 -1020
  277. package/scripts/theme/install-boot-logo.sh +0 -63
  278. package/scripts/theme/install-catppuccin-themes.sh +0 -371
  279. package/scripts/theme/install-cursors.sh +0 -26
  280. package/scripts/theme/install-file-icons.sh +0 -27
  281. package/scripts/theme/install-grub-theme.sh +0 -62
  282. package/scripts/theme/install-lock-icon.sh +0 -31
  283. package/scripts/theme/merge-wallpaper.sh +0 -146
  284. package/scripts/theme/rebuild-themes.sh +0 -603
  285. package/scripts/theme/switch.sh +0 -476
  286. package/scripts/theme/wallpaper-rotate.sh +0 -137
  287. package/scripts/theme/wallpaper-sync.sh +0 -690
  288. package/scripts/tools/cmatrix.sh +0 -22
  289. package/scripts/tools/detect-collisions.py +0 -103
  290. package/scripts/tools/emoji-picker.sh +0 -49
  291. package/scripts/tools/figlet-banner.sh +0 -19
  292. package/scripts/tools/log-rotate.sh +0 -31
  293. package/scripts/tools/lolcat-wrap.sh +0 -20
  294. package/scripts/tools/pipes.sh +0 -49
  295. package/scripts/tuning/linux.sh +0 -186
  296. package/scripts/tuning/macos.sh +0 -56
  297. package/scripts/uninstall.sh +0 -86
  298. package/scripts/verify-release-versions +0 -156
  299. package/scripts/version-sync.sh +0 -714
  300. package/templates/chezmoi-data/geekom-a9.toml.example +0 -21
  301. package/templates/chezmoi-data/mac-m1.toml.example +0 -16
  302. package/templates/chezmoi-data/mac-t2-linux.toml.example +0 -21
  303. package/templates/chezmoi-data/surface-pro-7p.toml.example +0 -21
  304. package/templates/projects/go/.github/workflows/ci.yml +0 -31
  305. package/templates/projects/go/README.md +0 -7
  306. package/templates/projects/go/cmd/__PROJECT_NAME__/main.go +0 -8
  307. package/templates/projects/go/go.mod +0 -3
  308. package/templates/projects/go/go.sum +0 -0
  309. package/templates/projects/molecule/README.md +0 -7
  310. package/templates/projects/molecule/converge.yml +0 -7
  311. package/templates/projects/molecule/molecule.yml +0 -16
  312. package/templates/projects/node/.github/workflows/ci.yml +0 -30
  313. package/templates/projects/node/README.md +0 -7
  314. package/templates/projects/node/package-lock.json +0 -12
  315. package/templates/projects/node/package.json +0 -10
  316. package/templates/projects/node/src/index.js +0 -3
  317. package/templates/projects/packer/README.md +0 -15
  318. package/templates/projects/packer/main.pkr.hcl +0 -15
  319. package/templates/projects/python/.github/workflows/ci.yml +0 -34
  320. package/templates/projects/python/README.md +0 -7
  321. package/templates/projects/python/pyproject.toml +0 -25
  322. package/templates/projects/python/src/__PROJECT_NAME__/__init__.py +0 -2
  323. package/templates/projects/python/tests/test_basic.py +0 -3
@@ -1,656 +0,0 @@
1
- #!/usr/bin/env bash
2
- # SPDX-License-Identifier: Apache-2.0 OR MIT
3
- # Copyright (c) 2015-2026 Sebastien Rousseau
4
- # Dotfiles Health Check Dashboard
5
- # Usage: dot health [--verbose|-v] [--json|-j] [--fix|-f] [--force|-F]
6
-
7
- set -euo pipefail
8
-
9
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
- # shellcheck source=../../lib/dot/ui.sh
11
- # shellcheck disable=SC1091
12
- source "$SCRIPT_DIR/../../lib/dot/ui.sh"
13
- # shellcheck source=../../lib/dot/log.sh
14
- # shellcheck disable=SC1091
15
- source "$SCRIPT_DIR/../../lib/dot/log.sh"
16
-
17
- # Portable has_command (self-contained; no dependency on utils.sh)
18
- has_command() { command -v "$1" >/dev/null 2>&1; }
19
-
20
- # Colors (fallback when gum is unavailable; respect NO_COLOR)
21
- if [[ -z "${NO_COLOR:-}" ]] && [[ -t 1 ]]; then
22
- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m'
23
- BLUE='\033[0;34m' CYAN='\033[0;36m' GRAY='\033[0;90m' NC='\033[0m'
24
- else
25
- RED='' GREEN='' YELLOW='' BLUE='' CYAN='' GRAY='' NC=''
26
- fi
27
-
28
- # Parse arguments (VERBOSE exported for potential use by sourced scripts)
29
- export VERBOSE=false
30
- JSON_OUTPUT=false
31
- APPLY_FIX=false
32
- FORCE_FIX=false
33
- while [[ $# -gt 0 ]]; do
34
- case "$1" in
35
- --verbose | -v)
36
- VERBOSE=true
37
- shift
38
- ;;
39
- --fix | -f)
40
- APPLY_FIX=true
41
- shift
42
- ;;
43
- --force | -F)
44
- FORCE_FIX=true
45
- shift
46
- ;;
47
- --json | -j)
48
- JSON_OUTPUT=true
49
- shift
50
- ;;
51
- *) shift ;;
52
- esac
53
- done
54
-
55
- reset_stats() {
56
- TOTAL_CHECKS=0
57
- PASSED_CHECKS=0
58
- WARNINGS=0
59
- FAILURES=0
60
- }
61
-
62
- # Health check results
63
- TOTAL_CHECKS=0
64
- PASSED_CHECKS=0
65
- WARNINGS=0
66
- FAILURES=0
67
- declare -a RESULTS=()
68
- ui_init
69
- use_ui="$UI_ENABLED"
70
-
71
- header() {
72
- local text="$1"
73
- if $JSON_OUTPUT; then
74
- return
75
- fi
76
- if [[ "$use_ui" = "1" ]]; then
77
- ui_header "$text"
78
- else
79
- printf '%b\n' "${CYAN}${text}${NC}"
80
- fi
81
- }
82
-
83
- section() {
84
- local text="$1"
85
- if $JSON_OUTPUT; then
86
- return
87
- fi
88
- if [[ "$use_ui" = "1" ]]; then
89
- ui_section "$text"
90
- else
91
- printf '%b\n' "\n${BLUE}▸ $text${NC}"
92
- fi
93
- }
94
-
95
- check() {
96
- local name="$1"
97
- local status="$2"
98
- local message="${3:-}"
99
-
100
- TOTAL_CHECKS=$((TOTAL_CHECKS + 1))
101
-
102
- # Collect structured result for JSON output (escape quotes for valid JSON)
103
- local _j_name="${name//\"/\\\"}"
104
- local _j_status="${status//\"/\\\"}"
105
- local _j_message="${message//\"/\\\"}"
106
- RESULTS+=("{\"check\":\"${_j_name}\",\"status\":\"${_j_status}\",\"message\":\"${_j_message}\"}")
107
-
108
- case "$status" in
109
- pass)
110
- PASSED_CHECKS=$((PASSED_CHECKS + 1))
111
- # shellcheck disable=SC2034
112
- if ! $JSON_OUTPUT; then
113
- if [[ "$use_ui" = "1" ]]; then
114
- ui_ok "$name"
115
- else
116
- printf "${GREEN}✓${NC} %-35s ${GREEN}OK${NC}\n" "$name"
117
- fi
118
- fi
119
- ;;
120
- warn)
121
- WARNINGS=$((WARNINGS + 1))
122
- # shellcheck disable=SC2034
123
- if ! $JSON_OUTPUT; then
124
- if [[ "$use_ui" = "1" ]]; then
125
- ui_warn "$name" "$message"
126
- else
127
- printf "${YELLOW}⚠${NC} %-35s ${YELLOW}WARNING${NC}" "$name"
128
- [[ -n "$message" ]] && printf " ${GRAY}%s${NC}" "$message"
129
- printf "\n"
130
- fi
131
- fi
132
- ;;
133
- fail)
134
- FAILURES=$((FAILURES + 1))
135
- # shellcheck disable=SC2034
136
- if ! $JSON_OUTPUT; then
137
- if [[ "$use_ui" = "1" ]]; then
138
- ui_err "$name" "$message"
139
- else
140
- printf "${RED}✗${NC} %-35s ${RED}FAILED${NC}" "$name"
141
- [[ -n "$message" ]] && printf " ${GRAY}%s${NC}" "$message"
142
- printf "\n"
143
- fi
144
- fi
145
- ;;
146
- esac
147
- }
148
-
149
- print_header() {
150
- if ! $JSON_OUTPUT; then
151
- echo ""
152
- ui_dot_banner "Diagnostics"
153
- header "Dotfiles Health Dashboard"
154
- echo ""
155
- fi
156
- }
157
-
158
- check_section() {
159
- if ! $JSON_OUTPUT; then
160
- echo ""
161
- section "$1"
162
- if [[ "$use_ui" = "1" ]]; then
163
- :
164
- else
165
- echo "───────────────────────────────────────────────"
166
- fi
167
- fi
168
- }
169
-
170
- # === Focused check sub-functions ===
171
-
172
- check_dotfiles_core() {
173
- check_section "Dotfiles Core"
174
-
175
- if has_command chezmoi; then
176
- check "Chezmoi installed" "pass"
177
- if [[ -d "${HOME}/.local/share/chezmoi" ]] || [[ -d "${HOME}/.dotfiles" ]]; then
178
- check "Chezmoi source directory" "pass"
179
- else
180
- check "Chezmoi source directory" "fail" "Not found"
181
- fi
182
- else
183
- check "Chezmoi installed" "fail" "Not installed"
184
- fi
185
-
186
- if has_command git; then
187
- check "Git installed" "pass"
188
- if git config user.email >/dev/null 2>&1; then
189
- check "Git user configured" "pass"
190
- else
191
- check "Git user configured" "warn" "Email not set"
192
- fi
193
- else
194
- check "Git installed" "fail"
195
- fi
196
- }
197
-
198
- check_shell_env() {
199
- check_section "Shell Environment"
200
- local current_shell="${SHELL##*/}"
201
- local default_shell="fish"
202
- if [[ -f "$SCRIPT_DIR/../../defaults/.chezmoidata.toml" ]]; then
203
- default_shell="$(awk -F= '/^[[:space:]]*default_shell[[:space:]]*=/{split($2, value, "#"); gsub(/[ "]/, "", value[1]); print value[1]; exit}' "$SCRIPT_DIR/../../defaults/.chezmoidata.toml")"
204
- default_shell="${default_shell:-fish}"
205
- fi
206
-
207
- if has_command zsh; then
208
- check "Zsh installed" "pass"
209
- if [[ "$current_shell" =~ ^(zsh|fish|bash|nu|nushell)$ ]]; then
210
- check "Active shell" "pass" "$current_shell"
211
- else
212
- check "Active shell" "warn" "Current: $SHELL"
213
- fi
214
- else
215
- check "Zsh installed" "fail"
216
- fi
217
-
218
- if [[ -f "${ZINIT_HOME:-$HOME/.local/share/zinit/zinit.git}/zinit.zsh" ]] || [[ -d "${ZINIT_HOME:-$HOME/.local/share/zinit}" ]]; then
219
- check "Zinit plugin manager" "pass"
220
- elif [[ "$current_shell" == "zsh" && "$default_shell" == "zsh" ]]; then
221
- check "Zinit plugin manager" "warn" "Not found"
222
- else
223
- check "Zinit plugin manager" "pass" "Not required for $default_shell"
224
- fi
225
-
226
- if has_command starship; then
227
- check "Starship prompt" "pass"
228
- else
229
- check "Starship prompt" "warn" "Not installed"
230
- fi
231
- }
232
-
233
- check_dev_tools() {
234
- check_section "Development Tools"
235
-
236
- if has_command node; then
237
- local node_version
238
- # `|| true` is load-bearing under `set -e`: an assignment takes the exit
239
- # status of its command substitution, so a `node` that fails to report a
240
- # version aborts the entire health report mid-section — no Summary, no
241
- # score, rc=1. That is exactly what happened when `node` resolved to a
242
- # mise shim under a sandboxed HOME. A diagnostic tool must survive the
243
- # tools it is diagnosing.
244
- node_version=$(node --version 2>/dev/null || true)
245
- check "Node.js ($node_version)" "pass"
246
- else
247
- check "Node.js" "warn" "Not installed"
248
- fi
249
-
250
- if has_command fnm; then
251
- check "fnm (Node version manager)" "pass"
252
- elif has_command mise && has_command node; then
253
- check "Node version manager" "pass" "mise"
254
- else
255
- check "fnm" "warn" "Not installed"
256
- fi
257
-
258
- if has_command python3; then
259
- local py_version
260
- # pipefail is on, so this pipeline reports python3's failure even though
261
- # `cut` succeeds — and an assignment inherits that status, aborting the
262
- # report under `set -e`. Same hazard as node_version above.
263
- py_version=$(python3 --version 2>/dev/null | cut -d' ' -f2 || true)
264
- check "Python ($py_version)" "pass"
265
- else
266
- check "Python" "warn" "Not installed"
267
- fi
268
-
269
- if has_command rustc; then
270
- check "Rust toolchain" "pass"
271
- else
272
- check "Rust toolchain" "warn" "Not installed"
273
- fi
274
-
275
- if has_command go; then
276
- check "Go" "pass"
277
- else
278
- check "Go" "warn" "Not installed"
279
- fi
280
- }
281
-
282
- check_cli_tools() {
283
- check_section "CLI Tools"
284
-
285
- local tools=("fzf" "ripgrep:rg" "fd" "bat" "eza" "zoxide" "atuin" "delta" "jq" "yq" "sops" "mise" "just" "zellij" "hyperfine")
286
- for tool in "${tools[@]}"; do
287
- local name="${tool%%:*}"
288
- local cmd="${tool##*:}"
289
- if has_command "$cmd"; then
290
- check "$name" "pass"
291
- else
292
- check "$name" "warn" "Not installed"
293
- fi
294
- done
295
- }
296
-
297
- check_editors() {
298
- check_section "Editors"
299
-
300
- if has_command nvim; then
301
- check "Neovim" "pass"
302
- if [[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/lazy" ]]; then
303
- check "Neovim plugins (lazy.nvim)" "pass"
304
- else
305
- check "Neovim plugins" "warn" "Lazy.nvim not found"
306
- fi
307
- else
308
- check "Neovim" "warn" "Not installed"
309
- fi
310
- }
311
-
312
- check_terminal() {
313
- check_section "Terminal"
314
-
315
- if has_command ghostty || [[ -d "/Applications/Ghostty.app" ]]; then
316
- check "Ghostty terminal" "pass"
317
- else
318
- check "Ghostty terminal" "warn" "Not installed"
319
- fi
320
-
321
- local font_found=false
322
- if command -v fc-list >/dev/null 2>&1; then
323
- local fc_list_output=""
324
- fc_list_output="$(fc-list 2>/dev/null || true)"
325
- if [[ "$fc_list_output" == *"Nerd Font"* ]]; then
326
- font_found=true
327
- fi
328
- fi
329
- if [[ "$font_found" != true ]] && [[ -d "$HOME/Library/Fonts" ]] && compgen -G "$HOME/Library/Fonts/"'*Nerd*' >/dev/null 2>&1; then
330
- font_found=true
331
- elif [[ "$font_found" != true ]] && [[ -d "$HOME/.local/share/fonts" ]] && compgen -G "$HOME/.local/share/fonts/"'*Nerd*' >/dev/null 2>&1; then
332
- font_found=true
333
- fi
334
-
335
- if $font_found; then
336
- check "Nerd Font available" "pass"
337
- else
338
- check "Nerd Font available" "warn" "Not installed"
339
- fi
340
- }
341
-
342
- check_security() {
343
- check_section "Security"
344
-
345
- if has_command age; then
346
- check "Age encryption" "pass"
347
- local age_identity="${HOME}/.config/chezmoi/key.txt" configured_identity=""
348
- if has_command chezmoi && has_command jq; then
349
- configured_identity=$(chezmoi dump-config --format=json 2>/dev/null | jq -r '.age.identity // empty' 2>/dev/null || true)
350
- [[ -z "$configured_identity" ]] || age_identity="${configured_identity/#\~/$HOME}"
351
- fi
352
- if [[ -f "$age_identity" ]]; then
353
- check "Age key configured" "pass"
354
- else
355
- check "Age key configured" "warn" "Key not found"
356
- fi
357
- else
358
- check "Age encryption" "warn" "Not installed"
359
- fi
360
-
361
- local -a ssh_keys=("$HOME/.ssh/id_ed25519" "$HOME/.ssh/id_rsa" "$HOME/.ssh/id_ed25519_sk")
362
- local public_key key existing_key keys_found=false
363
- for public_key in "$HOME/.ssh/"*.pub; do
364
- [[ -f "$public_key" && -f "${public_key%.pub}" ]] || continue
365
- key="${public_key%.pub}"
366
- for existing_key in "${ssh_keys[@]}"; do
367
- [[ "$existing_key" != "$key" ]] || continue 2
368
- done
369
- ssh_keys+=("$key")
370
- done
371
- for key in "${ssh_keys[@]}"; do
372
- [[ ! -f "$key" ]] || keys_found=true
373
- done
374
- if $keys_found; then
375
- check "SSH keys present" "pass"
376
- else
377
- check "SSH keys present" "warn" "No keys found"
378
- fi
379
-
380
- # Check SSH key permissions
381
- for key in "${ssh_keys[@]}"; do
382
- if [[ -f "$key" ]]; then
383
- local perms
384
- # Same hazard as node_version above: if BOTH stat spellings fail (a
385
- # platform with neither GNU nor BSD stat), the assignment is non-zero
386
- # and `set -e` kills the report. Empty perms falls through to the
387
- # "should be 600" warning, which is the right answer when the mode
388
- # cannot be read.
389
- perms=$(stat -c '%a' "$key" 2>/dev/null || stat -f '%Lp' "$key" 2>/dev/null || true)
390
- if [[ "$perms" != "600" && "$perms" != "400" ]]; then
391
- check "SSH key perms (${key##*/})" "warn" "mode $perms (should be 600)"
392
- else
393
- check "SSH key perms (${key##*/})" "pass"
394
- fi
395
- fi
396
- done
397
-
398
- if has_command gpg; then
399
- local signing_format signing_key allowed_signers
400
- signing_format="$(git config --global gpg.format 2>/dev/null || true)"
401
- signing_key="$(git config --global user.signingkey 2>/dev/null || true)"
402
- allowed_signers="$(git config --global gpg.ssh.allowedSignersFile 2>/dev/null || echo "$HOME/.config/git/allowed_signers")"
403
-
404
- if [[ "$signing_format" == "ssh" ]] && [[ -n "$signing_key" ]] && [[ -f "${signing_key/#\~/$HOME}" ]] && [[ -f "${allowed_signers/#\~/$HOME}" ]]; then
405
- check "Git signing" "pass" "ssh"
406
- elif gpg --list-secret-keys 2>/dev/null | grep -q sec; then
407
- check "GPG keys" "pass"
408
- else
409
- check "GPG keys" "warn" "No secret keys"
410
- fi
411
- else
412
- check "GPG" "warn" "Not installed"
413
- fi
414
- }
415
-
416
- check_performance() {
417
- check_section "Performance"
418
-
419
- if has_command zsh; then
420
- local startup_time
421
- # Startup timing is diagnostic only. A user's interactive configuration
422
- # may exit non-zero or omit a `real` row, which must not abort health under
423
- # `set -euo pipefail` before the summary is printed.
424
- startup_time=$({ time zsh -i -c exit; } 2>&1 | awk '/real/ { print $2; exit }' | sed 's/[ms]//g' || true)
425
- if [[ -n "$startup_time" ]]; then
426
- check "Shell startup time" "pass"
427
- else
428
- check "Shell startup time" "warn" "Could not measure"
429
- fi
430
- fi
431
- }
432
-
433
- check_config_directories() {
434
- check_section "Config Directories"
435
-
436
- local config_dirs=(
437
- "$HOME/.config/shell"
438
- "$HOME/.config/nvim"
439
- "$HOME/.config/git"
440
- )
441
- local found=0 total=${#config_dirs[@]}
442
-
443
- for dir in "${config_dirs[@]}"; do
444
- if [[ -d "$dir" ]]; then
445
- check "Config: ${dir##*/}" "pass"
446
- found=$((found + 1))
447
- else
448
- check "Config: ${dir##*/}" "warn" "Not found"
449
- fi
450
- done
451
-
452
- if [[ $found -eq $total ]]; then
453
- check "Config directories" "pass"
454
- elif [[ $found -gt 0 ]]; then
455
- check "Config directories" "warn" "$found/$total present"
456
- else
457
- check "Config directories" "fail" "None found"
458
- fi
459
- }
460
-
461
- check_sync_status() {
462
- check_section "Sync Status"
463
-
464
- # Chezmoi status. The two-character prefix encodes both directions:
465
- # col 1 = last-applied state vs actual (was the file edited in
466
- # place since last apply?)
467
- # col 2 = actual state vs target (what `chezmoi apply`
468
- # would still change)
469
- # Only col 2 matters for "is $HOME out of sync with the source" —
470
- # col 1 alone just means the source repo has uncommitted edits,
471
- # which is normal during development and not something the user
472
- # needs warned about via the health dashboard.
473
- if has_command chezmoi; then
474
- local status_output
475
- # --exclude=always: always-run scripts are pending by design, not drift.
476
- status_output=$(chezmoi status --exclude=always 2>/dev/null || echo "")
477
- if [[ -z "$status_output" ]]; then
478
- check "Chezmoi sync" "pass"
479
- else
480
- # Count only entries where column 2 is non-space (apply would do something).
481
- local applicable
482
- applicable=$(printf '%s\n' "$status_output" | awk 'substr($0,2,1)!=" "' | wc -l | tr -d ' ')
483
- if [[ "$applicable" -eq 0 ]]; then
484
- # All drift is source-only (unstaged edits in the source repo).
485
- # That's not a sync issue; mention it but pass.
486
- local source_only
487
- source_only=$(printf '%s\n' "$status_output" | wc -l | tr -d ' ')
488
- check "Chezmoi sync" "pass" "$source_only source-only edit(s) (run 'chezmoi diff' to inspect)"
489
- else
490
- check "Chezmoi sync" "warn" "$applicable file(s) out of sync"
491
- fi
492
- fi
493
- else
494
- check "Chezmoi sync" "warn" "Not installed, skipped"
495
- fi
496
-
497
- # Git status
498
- local dotfiles_dir="${HOME}/.dotfiles"
499
- if [[ -d "$dotfiles_dir/.git" ]]; then
500
- local git_status=""
501
- git_status=$(git -C "$dotfiles_dir" status --porcelain 2>/dev/null || echo "")
502
- if [[ -z "$git_status" ]]; then
503
- check "Git working tree" "pass"
504
- else
505
- local changes
506
- changes=$(printf '%s\n' "$git_status" | wc -l | tr -d ' ')
507
- check "Git working tree" "pass" "$changes local change(s)"
508
- fi
509
- else
510
- check "Git working tree" "warn" "Not a git repo"
511
- fi
512
- }
513
-
514
- # === Orchestrator ===
515
- run_checks() {
516
- check_dotfiles_core
517
- check_shell_env
518
- check_dev_tools
519
- check_cli_tools
520
- check_editors
521
- check_terminal
522
- check_security
523
- check_config_directories
524
- check_sync_status
525
- check_performance
526
- }
527
-
528
- print_summary() {
529
- local score=$((PASSED_CHECKS * 100 / TOTAL_CHECKS))
530
-
531
- if $JSON_OUTPUT; then
532
- printf '{\n'
533
- printf ' "total": %d,\n' "$TOTAL_CHECKS"
534
- printf ' "passed": %d,\n' "$PASSED_CHECKS"
535
- printf ' "warnings": %d,\n' "$WARNINGS"
536
- printf ' "failures": %d,\n' "$FAILURES"
537
- printf ' "score": %d,\n' "$score"
538
- printf ' "results": [\n'
539
- local i=0
540
- for result in "${RESULTS[@]}"; do
541
- if [[ $i -gt 0 ]]; then
542
- printf ',\n'
543
- fi
544
- printf ' %s' "$result"
545
- i=$((i + 1))
546
- done
547
- printf '\n ]\n'
548
- printf '}\n'
549
- dot_log info "health_complete" "score=$score" "total=$TOTAL_CHECKS"
550
- dot_metric "health_score" "$score" "percent"
551
- return
552
- fi
553
-
554
- echo ""
555
- header "Summary"
556
- echo ""
557
-
558
- if [[ "$use_ui" = "1" ]]; then
559
- printf " %-12s %s\n" "Total checks:" "${TOTAL_CHECKS}"
560
- printf " %-12s %s\n" "Passed:" "$(gum style --foreground 2 "$PASSED_CHECKS")"
561
- printf " %-12s %s\n" "Warnings:" "$(gum style --foreground 3 "$WARNINGS")"
562
- printf " %-12s %s\n" "Failures:" "$(gum style --foreground 1 "$FAILURES")"
563
- else
564
- printf '%b\n' " Total checks: ${TOTAL_CHECKS}"
565
- printf '%b\n' " ${GREEN}Passed:${NC} ${PASSED_CHECKS}"
566
- printf '%b\n' " ${YELLOW}Warnings:${NC} ${WARNINGS}"
567
- printf '%b\n' " ${RED}Failures:${NC} ${FAILURES}"
568
- fi
569
- echo ""
570
-
571
- # Health score bar
572
- local bar_width=30
573
- local filled=$((score * bar_width / 100))
574
- local empty=$((bar_width - filled))
575
- local filled_bar="" empty_bar="" i
576
-
577
- for ((i = 0; i < filled; i++)); do
578
- filled_bar+="${_GL_BAR_FILL}"
579
- done
580
- for ((i = 0; i < empty; i++)); do
581
- empty_bar+="${_GL_BAR_EMPTY}"
582
- done
583
-
584
- if [[ "$use_ui" = "1" ]]; then
585
- local bar_color
586
- if [[ $score -ge 80 ]]; then
587
- bar_color=2
588
- elif [[ $score -ge 60 ]]; then
589
- bar_color=3
590
- else
591
- bar_color=1
592
- fi
593
- printf " Health Score: [%s%s] %s%%\n\n" \
594
- "$(gum style --foreground "$bar_color" "$filled_bar")" \
595
- "$empty_bar" \
596
- "$score"
597
- else
598
- printf " Health Score: ["
599
- if [[ $score -ge 80 ]]; then
600
- printf '%s' "${GREEN}"
601
- elif [[ $score -ge 60 ]]; then
602
- printf '%s' "${YELLOW}"
603
- else
604
- printf '%s' "${RED}"
605
- fi
606
- printf '%s' "$filled_bar"
607
- printf '%s' "${NC}"
608
- printf '%s' "$empty_bar"
609
- printf "] %s%%\n\n" "${score}"
610
- fi
611
-
612
- if [[ $score -ge 90 ]]; then
613
- printf '%b\n' " ${GREEN}⚡ Excellent! Your dotfiles are in great shape.${NC}"
614
- elif [[ $score -ge 70 ]]; then
615
- printf '%b\n' " ${GREEN}✓ Good! Minor improvements possible.${NC}"
616
- elif [[ $score -ge 50 ]]; then
617
- printf '%b\n' " ${YELLOW}⚠ Fair. Consider addressing warnings.${NC}"
618
- else
619
- printf '%b\n' " ${RED}✗ Needs attention. Multiple issues found.${NC}"
620
- fi
621
-
622
- echo ""
623
- if [[ $WARNINGS -gt 0 || $FAILURES -gt 0 ]]; then
624
- printf '%b\n' " ${CYAN}Tip:${NC} Run 'dot health --fix' to auto-repair common issues."
625
- echo ""
626
- fi
627
-
628
- dot_log info "health_complete" "score=$score" "total=$TOTAL_CHECKS"
629
- dot_metric "health_score" "$score" "percent"
630
- }
631
-
632
- # Main
633
- export DOT_COMMAND="health"
634
- print_header
635
- run_checks
636
- if $APPLY_FIX; then
637
- if ! $JSON_OUTPUT; then
638
- header "Auto-Remediation"
639
- echo ""
640
- fi
641
- heal_script="$SCRIPT_DIR/../ops/heal.sh"
642
- if [[ -f "$heal_script" ]]; then
643
- if $FORCE_FIX; then
644
- bash "$heal_script" --force || true
645
- else
646
- bash "$heal_script" || true
647
- fi
648
- else
649
- if ! $JSON_OUTPUT; then
650
- printf '%b\n' "${YELLOW}⚠${NC} heal.sh not found, skipping auto-fix."
651
- fi
652
- fi
653
- reset_stats
654
- run_checks
655
- fi
656
- print_summary