@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.
- package/CHANGELOG.md +18 -0
- package/LICENSE-APACHE +190 -0
- package/LICENSE-MIT +21 -0
- package/README.md +43 -37
- package/install.sh +76 -10
- package/package.json +7 -7
- package/tools/README.md +49 -0
- package/tools/ci/install-chezmoi-verified.sh +68 -0
- package/docs/.vitepress/reports/localization-readability-audit.md +0 -73
- package/docs/AI.md +0 -179
- package/docs/ARCHITECTURE.md +0 -117
- package/docs/CNAME +0 -1
- package/docs/CONFIG_STRATEGY.md +0 -124
- package/docs/COPYRIGHT +0 -7
- package/docs/ECOSYSTEM.md +0 -220
- package/docs/GOLD-STANDARD-AUDIT.md +0 -352
- package/docs/GOVERNANCE.md +0 -98
- package/docs/MAINTAINERS.md +0 -41
- package/docs/MINIMUM-TOOLCHAIN.md +0 -100
- package/docs/NAMING_CONVENTIONS.md +0 -102
- package/docs/OPENCODE.md +0 -127
- package/docs/README.md +0 -84
- package/docs/STRUCTURE.md +0 -102
- package/docs/adr/ADR-001-ci-cd-pipeline.md +0 -118
- package/docs/adr/ADR-002-shell-performance.md +0 -130
- package/docs/adr/ADR-003-security-first.md +0 -158
- package/docs/adr/ADR-004-cli-architecture.md +0 -171
- package/docs/adr/ADR-005-chezmoi-choice.md +0 -99
- package/docs/adr/ADR-006-shell-selection.md +0 -124
- package/docs/adr/ADR-007-multi-shell-parity.md +0 -62
- package/docs/adr/ADR-008-alias-system-architecture.md +0 -95
- package/docs/adr/ADR-009-wallpaper-driven-theming.md +0 -131
- package/docs/adr/ADR-010-starship-transient-prompt.md +0 -144
- package/docs/adr/ADR-011-nushell-tier3-keep.md +0 -144
- package/docs/adr/ADR-012-ai-fleet-local-proxy.md +0 -79
- package/docs/adr/README.md +0 -40
- package/docs/architecture/AI_COST_OPTIMIZATION.md +0 -144
- package/docs/architecture/ARCHITECTURE.md +0 -20
- package/docs/architecture/INTEROP.md +0 -44
- package/docs/architecture/REPO_LAYOUT.md +0 -241
- package/docs/architecture/WALKTHROUGH.md +0 -86
- package/docs/architecture/fleet-deployment.md +0 -77
- package/docs/archive/EUXIS_2026_REVIEW.md +0 -127
- package/docs/archive/LEGACY_ROADMAP.md +0 -6
- package/docs/archive/MILESTONE_v0.2.493.md +0 -47
- package/docs/archive/PLAN.md +0 -199
- package/docs/archive/REPO_AUDIT.md +0 -31
- package/docs/articles/.pages +0 -6
- package/docs/articles/2026-07-05-custom-mkdocs-material-dark-theme.md +0 -216
- package/docs/articles/2026-07-05-fish-startup-abbr.md +0 -153
- package/docs/articles/2026-07-05-master-to-main-rename-runbook.md +0 -128
- package/docs/articles/index.md +0 -36
- package/docs/guides/INSTALL.md +0 -144
- package/docs/guides/MACOS_ICLOUD_SYMLINKS.md +0 -121
- package/docs/guides/NEOVIM_IDE_GUIDE.md +0 -61
- package/docs/guides/THEMING.md +0 -230
- package/docs/guides/TROUBLESHOOTING.md +0 -176
- package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +0 -792
- package/docs/index.md +0 -132
- package/docs/interop/A2A.md +0 -39
- package/docs/interop/POWERSHELL.md +0 -102
- package/docs/manual/00-introduction.md +0 -89
- package/docs/manual/01-concepts/01-architecture.md +0 -138
- package/docs/manual/01-concepts/02-trust-model.md +0 -183
- package/docs/manual/01-concepts/03-theme-engine.md +0 -186
- package/docs/manual/01-concepts/04-fleet.md +0 -148
- package/docs/manual/01-concepts/05-self-healing.md +0 -204
- package/docs/manual/02-tutorials/01-first-install.md +0 -197
- package/docs/manual/02-tutorials/02-add-wallpaper.md +0 -216
- package/docs/manual/02-tutorials/03-create-profile.md +0 -244
- package/docs/manual/02-tutorials/04-encrypt-secret.md +0 -281
- package/docs/manual/02-tutorials/05-deploy-fleet.md +0 -283
- package/docs/manual/03-reference/01-dot-cli.md +0 -475
- package/docs/manual/03-reference/02-config-files.md +0 -265
- package/docs/manual/03-reference/03-environment.md +0 -124
- package/docs/manual/03-reference/04-templates.md +0 -190
- package/docs/manual/03-reference/05-feature-flags.md +0 -187
- package/docs/manual/04-cookbook/01-recipes.md +0 -285
- package/docs/manual/04-cookbook/02-troubleshooting.md +0 -351
- package/docs/manual/04-cookbook/03-faq.md +0 -175
- package/docs/manual/05-appendices/A-platform-matrix.md +0 -101
- package/docs/manual/05-appendices/B-security-checklist.md +0 -85
- package/docs/manual/05-appendices/C-glossary.md +0 -40
- package/docs/manual/05-appendices/D-bibliography.md +0 -58
- package/docs/manual/05-appendices/E-license.md +0 -38
- package/docs/manual/_toc.yml +0 -58
- package/docs/manual/command-index.md +0 -175
- package/docs/manual/concept-index.md +0 -170
- package/docs/manual/index.md +0 -66
- package/docs/migration/README.md +0 -81
- package/docs/migration/from-bare-git-repo.md +0 -156
- package/docs/migration/from-gnu-stow.md +0 -165
- package/docs/migration/from-plain-chezmoi.md +0 -148
- package/docs/migration/from-yadm.md +0 -187
- package/docs/operations/ARCHITECTURE_ROADMAP.md +0 -7
- package/docs/operations/ATTESTATION.md +0 -44
- package/docs/operations/CI_CADENCE.md +0 -107
- package/docs/operations/CI_COMPOSITES.md +0 -156
- package/docs/operations/COMPLETIONS.md +0 -123
- package/docs/operations/COVERAGE.md +0 -204
- package/docs/operations/DRIFT.md +0 -107
- package/docs/operations/HARD_AUDIT_2026.md +0 -631
- package/docs/operations/MAINTENANCE.md +0 -63
- package/docs/operations/MANIFEST.md +0 -127
- package/docs/operations/MIGRATION.md +0 -109
- package/docs/operations/OPERATIONS.md +0 -188
- package/docs/operations/PERFORMANCE.md +0 -133
- package/docs/operations/PERFORMANCE_BUDGETS.md +0 -196
- package/docs/operations/REGISTRY.md +0 -90
- package/docs/operations/RELEASE_PIPELINE.md +0 -128
- package/docs/operations/RELIABILITY.md +0 -122
- package/docs/operations/RFC_v0_2_503_reorganization.md +0 -280
- package/docs/operations/ROADMAP.md +0 -10
- package/docs/operations/ROADMAP_2026.md +0 -7
- package/docs/operations/ROADMAP_V0_2_503.md +0 -10
- package/docs/operations/TESTING.md +0 -216
- package/docs/operations/TRACEABILITY.md +0 -44
- package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +0 -65
- package/docs/operations/VERSION_SYNC.md +0 -393
- package/docs/packaging.md +0 -222
- package/docs/reference/ALIASES.md +0 -131
- package/docs/reference/ALIASES_CHEATSHEET.md +0 -32
- package/docs/reference/ALIASES_DEPRECATIONS.md +0 -13
- package/docs/reference/FEATURE-MATRIX.md +0 -646
- package/docs/reference/FEATURES.md +0 -66
- package/docs/reference/FONTS.md +0 -112
- package/docs/reference/POWERSHELL_PARITY.md +0 -82
- package/docs/reference/PROFILES.md +0 -69
- package/docs/reference/SCREENSHOTS.md +0 -121
- package/docs/reference/SCRIPTS.md +0 -71
- package/docs/reference/SUPPORT_MATRIX.md +0 -80
- package/docs/reference/THEMES.md +0 -117
- package/docs/reference/TOOLS.md +0 -110
- package/docs/reference/UTILS.md +0 -243
- package/docs/registry.json +0 -6
- package/docs/schema/dot-env-v1.json +0 -110
- package/docs/schema/dot-registry-v1.json +0 -33
- package/docs/security/AI_ACT_COMPLIANCE.md +0 -94
- package/docs/security/AUDIT_BYPASS.md +0 -103
- package/docs/security/AUTOMATION_SECRETS.md +0 -26
- package/docs/security/CI_EGRESS_ALLOWLIST.md +0 -127
- package/docs/security/CI_PINNING.md +0 -129
- package/docs/security/COMMIT_SIGNING.md +0 -138
- package/docs/security/COMPLIANCE.md +0 -458
- package/docs/security/DEPS_DEV_EXCEPTIONS.md +0 -86
- package/docs/security/DISCLOSURE.md +0 -130
- package/docs/security/ENCRYPTION.md +0 -57
- package/docs/security/FMEA.md +0 -159
- package/docs/security/FUZZING.md +0 -209
- package/docs/security/HISTORY_FILTERING.md +0 -132
- package/docs/security/INCIDENT_RESPONSE.md +0 -579
- package/docs/security/INSTALL_VERIFICATION.md +0 -122
- package/docs/security/KEYS.md +0 -49
- package/docs/security/KEY_ROTATION.md +0 -303
- package/docs/security/MCP_POLICY.md +0 -78
- package/docs/security/POLICY_RELEASES.md +0 -37
- package/docs/security/README.md +0 -28
- package/docs/security/SCORECARD.md +0 -195
- package/docs/security/SECRETS.md +0 -158
- package/docs/security/SECURITY.md +0 -45
- package/docs/security/SECURITY_CHECKLIST.md +0 -55
- package/docs/security/SHELL_EXEMPTIONS.md +0 -145
- package/docs/security/SOUP_REGISTER.md +0 -36
- package/docs/security/THREAT_MODEL.md +0 -130
- package/docs/security/VERIFICATION_VALIDATION.md +0 -228
- package/docs/security/VERIFY_RELEASE.md +0 -201
- package/docs/security/security-pubkey.asc +0 -15
- package/docs/stylesheets/extra.css +0 -444
- package/docs/themes/README.md +0 -10
- package/docs/themes/VISUAL_INTEGRITY_REPORT.md +0 -30
- package/docs/themes/hero-shot.svg +0 -78
- package/scripts/README.md +0 -123
- package/scripts/ci/check-copyright-headers.sh +0 -8
- package/scripts/ci/check-shell-preamble.sh +0 -8
- package/scripts/ci/guard-gitleaks-checkout.sh +0 -8
- package/scripts/demo/record.sh +0 -43
- package/scripts/diagnostics/a2a-conformance.sh +0 -163
- package/scripts/diagnostics/alias-governance.sh +0 -165
- package/scripts/diagnostics/aliases-cheatsheet.sh +0 -74
- package/scripts/diagnostics/aliases-manifest.sh +0 -77
- package/scripts/diagnostics/attest-verify.sh +0 -147
- package/scripts/diagnostics/benchmark.sh +0 -408
- package/scripts/diagnostics/conflicts.sh +0 -73
- package/scripts/diagnostics/doctor-unified.sh +0 -43
- package/scripts/diagnostics/doctor.sh +0 -797
- package/scripts/diagnostics/drift-dashboard.sh +0 -203
- package/scripts/diagnostics/health.sh +0 -656
- package/scripts/diagnostics/history-analysis.sh +0 -86
- package/scripts/diagnostics/mcp-doctor.sh +0 -582
- package/scripts/diagnostics/perf.sh +0 -453
- package/scripts/diagnostics/scorecard.sh +0 -120
- package/scripts/diagnostics/secret-governance.sh +0 -65
- package/scripts/diagnostics/security-score.sh +0 -467
- package/scripts/diagnostics/smoke-test.sh +0 -88
- package/scripts/diagnostics/snapshot.sh +0 -90
- package/scripts/diagnostics/verify.sh +0 -108
- package/scripts/diagnostics/verify_state.sh +0 -73
- package/scripts/diagnostics/version-locks.sh +0 -94
- package/scripts/diagnostics/workstation-attestation.sh +0 -212
- package/scripts/dot/commands/agent.sh +0 -535
- package/scripts/dot/commands/agents.sh +0 -352
- package/scripts/dot/commands/ai.sh +0 -600
- package/scripts/dot/commands/aliases.sh +0 -277
- package/scripts/dot/commands/appearance.sh +0 -110
- package/scripts/dot/commands/completion.sh +0 -171
- package/scripts/dot/commands/core.sh +0 -217
- package/scripts/dot/commands/diagnostics.sh +0 -265
- package/scripts/dot/commands/env-emit.sh +0 -203
- package/scripts/dot/commands/fleet.sh +0 -711
- package/scripts/dot/commands/init.sh +0 -185
- package/scripts/dot/commands/lint.sh +0 -208
- package/scripts/dot/commands/manual.sh +0 -169
- package/scripts/dot/commands/meta.sh +0 -438
- package/scripts/dot/commands/patterns.sh +0 -55
- package/scripts/dot/commands/registry.sh +0 -455
- package/scripts/dot/commands/restore.sh +0 -232
- package/scripts/dot/commands/secrets.sh +0 -296
- package/scripts/dot/commands/security.sh +0 -102
- package/scripts/dot/commands/tools.sh +0 -570
- package/scripts/dot/data/alias-deprecations.tsv +0 -2
- package/scripts/dot/powershell/Dot.psm1 +0 -319
- package/scripts/fonts/install-nerd-fonts.sh +0 -75
- package/scripts/fonts/patch-fonts.sh +0 -36
- package/scripts/git-hooks/install.sh +0 -12
- package/scripts/git-hooks/pre-commit +0 -12
- package/scripts/git-hooks/pre-commit-audit.sh +0 -146
- package/scripts/git-hooks/pre-push +0 -105
- package/scripts/git-hooks/prepare-commit-msg +0 -29
- package/scripts/lib/secrets_provider.sh +0 -200
- package/scripts/nvim/headless-upgrade.lua +0 -81
- package/scripts/ops/ai-setup.sh +0 -71
- package/scripts/ops/bundle.sh +0 -104
- package/scripts/ops/chaos.sh +0 -50
- package/scripts/ops/chezmoi-apply.sh +0 -333
- package/scripts/ops/chezmoi-diff.sh +0 -16
- package/scripts/ops/chezmoi-remove.sh +0 -46
- package/scripts/ops/chezmoi-update.sh +0 -67
- package/scripts/ops/heal-chezmoi.sh +0 -87
- package/scripts/ops/heal-system.sh +0 -129
- package/scripts/ops/heal-tools.sh +0 -297
- package/scripts/ops/heal.sh +0 -223
- package/scripts/ops/post-apply-repair.sh +0 -107
- package/scripts/ops/prewarm.sh +0 -128
- package/scripts/ops/release.sh +0 -262
- package/scripts/ops/rollback.sh +0 -613
- package/scripts/ops/setup.sh +0 -138
- package/scripts/ops/teleport.sh +0 -34
- package/scripts/qa/check-feature-matrix.sh +0 -296
- package/scripts/qa/check-version-consistency.sh +0 -12
- package/scripts/qa/coverage-baseline.sh +0 -61
- package/scripts/qa/docs-coverage.sh +0 -118
- package/scripts/qa/examples-coverage.sh +0 -94
- package/scripts/qa/powershell-contract.ps1 +0 -95
- package/scripts/qa/reliability-audit.sh +0 -139
- package/scripts/qa/scorecard-snapshot.sh +0 -128
- package/scripts/qa/traceability-coverage.sh +0 -124
- package/scripts/qa/validate-examples.sh +0 -90
- package/scripts/qa/wsl-contract.sh +0 -12
- package/scripts/secrets/age-init.sh +0 -82
- package/scripts/secrets/create-secrets-file.sh +0 -46
- package/scripts/secrets/encrypt-ssh-key.sh +0 -44
- package/scripts/security/backup.sh +0 -58
- package/scripts/security/check-disclosure-key-expiry.sh +0 -111
- package/scripts/security/dns-doh.sh +0 -52
- package/scripts/security/encryption-check.sh +0 -55
- package/scripts/security/enforce-policies.sh +0 -552
- package/scripts/security/firewall.sh +0 -91
- package/scripts/security/lock-configs.sh +0 -67
- package/scripts/security/lock-screen.sh +0 -56
- package/scripts/security/manage-secrets.sh +0 -429
- package/scripts/security/ssh-cert.sh +0 -204
- package/scripts/security/telemetry-kill.sh +0 -51
- package/scripts/security/usb-safety.sh +0 -52
- package/scripts/theme/apply-gnome-theme.sh +0 -333
- package/scripts/theme/extract-heic-frames.sh +0 -115
- package/scripts/theme/extract-theme.py +0 -1020
- package/scripts/theme/install-boot-logo.sh +0 -63
- package/scripts/theme/install-catppuccin-themes.sh +0 -371
- package/scripts/theme/install-cursors.sh +0 -26
- package/scripts/theme/install-file-icons.sh +0 -27
- package/scripts/theme/install-grub-theme.sh +0 -62
- package/scripts/theme/install-lock-icon.sh +0 -31
- package/scripts/theme/merge-wallpaper.sh +0 -146
- package/scripts/theme/rebuild-themes.sh +0 -603
- package/scripts/theme/switch.sh +0 -476
- package/scripts/theme/wallpaper-rotate.sh +0 -137
- package/scripts/theme/wallpaper-sync.sh +0 -690
- package/scripts/tools/cmatrix.sh +0 -22
- package/scripts/tools/detect-collisions.py +0 -103
- package/scripts/tools/emoji-picker.sh +0 -49
- package/scripts/tools/figlet-banner.sh +0 -19
- package/scripts/tools/log-rotate.sh +0 -31
- package/scripts/tools/lolcat-wrap.sh +0 -20
- package/scripts/tools/pipes.sh +0 -49
- package/scripts/tuning/linux.sh +0 -186
- package/scripts/tuning/macos.sh +0 -56
- package/scripts/uninstall.sh +0 -86
- package/scripts/verify-release-versions +0 -156
- package/scripts/version-sync.sh +0 -714
- package/templates/chezmoi-data/geekom-a9.toml.example +0 -21
- package/templates/chezmoi-data/mac-m1.toml.example +0 -16
- package/templates/chezmoi-data/mac-t2-linux.toml.example +0 -21
- package/templates/chezmoi-data/surface-pro-7p.toml.example +0 -21
- package/templates/projects/go/.github/workflows/ci.yml +0 -31
- package/templates/projects/go/README.md +0 -7
- package/templates/projects/go/cmd/__PROJECT_NAME__/main.go +0 -8
- package/templates/projects/go/go.mod +0 -3
- package/templates/projects/go/go.sum +0 -0
- package/templates/projects/molecule/README.md +0 -7
- package/templates/projects/molecule/converge.yml +0 -7
- package/templates/projects/molecule/molecule.yml +0 -16
- package/templates/projects/node/.github/workflows/ci.yml +0 -30
- package/templates/projects/node/README.md +0 -7
- package/templates/projects/node/package-lock.json +0 -12
- package/templates/projects/node/package.json +0 -10
- package/templates/projects/node/src/index.js +0 -3
- package/templates/projects/packer/README.md +0 -15
- package/templates/projects/packer/main.pkr.hcl +0 -15
- package/templates/projects/python/.github/workflows/ci.yml +0 -34
- package/templates/projects/python/README.md +0 -7
- package/templates/projects/python/pyproject.toml +0 -25
- package/templates/projects/python/src/__PROJECT_NAME__/__init__.py +0 -2
- 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
|