@sebastienrousseau/dotfiles 0.2.519 → 0.2.521

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