@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.
- package/CHANGELOG.md +200 -0
- package/LICENSE-APACHE +190 -0
- package/{LICENSE → LICENSE-MIT} +1 -1
- package/README.md +1172 -166
- package/install.sh +77 -11
- package/package.json +8 -8
- 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/CNAME +0 -1
- package/docs/CONFIG_STRATEGY.md +0 -124
- package/docs/COPYRIGHT +0 -7
- package/docs/GOVERNANCE.md +0 -98
- package/docs/MAINTAINERS.md +0 -41
- 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 -117
- 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/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 -450
- 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 -155
- package/docs/manual/concept-index.md +0 -168
- package/docs/manual/index.md +0 -66
- 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/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 -43
- package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +0 -65
- package/docs/operations/VERSION_SYNC.md +0 -393
- 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/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 -242
- 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 -114
- 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 -138
- package/scripts/diagnostics/aliases-cheatsheet.sh +0 -74
- package/scripts/diagnostics/aliases-manifest.sh +0 -77
- package/scripts/diagnostics/benchmark.sh +0 -408
- package/scripts/diagnostics/conflicts.sh +0 -73
- package/scripts/diagnostics/doctor-unified.sh +0 -39
- package/scripts/diagnostics/doctor.sh +0 -751
- package/scripts/diagnostics/drift-dashboard.sh +0 -202
- package/scripts/diagnostics/health.sh +0 -623
- 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 -119
- 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 -187
- package/scripts/dot/commands/agent.sh +0 -485
- package/scripts/dot/commands/agents.sh +0 -336
- package/scripts/dot/commands/ai.sh +0 -587
- package/scripts/dot/commands/aliases.sh +0 -277
- package/scripts/dot/commands/appearance.sh +0 -110
- package/scripts/dot/commands/completion.sh +0 -134
- 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 -688
- 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 -333
- package/scripts/dot/commands/patterns.sh +0 -55
- package/scripts/dot/commands/registry.sh +0 -419
- 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 -556
- 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 -185
- 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 -63
- 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 -604
- package/scripts/ops/setup.sh +0 -138
- package/scripts/ops/teleport.sh +0 -34
- package/scripts/qa/check-version-consistency.sh +0 -124
- package/scripts/qa/coverage-baseline.sh +0 -61
- package/scripts/qa/docs-coverage.sh +0 -112
- 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 -117
- package/scripts/qa/validate-examples.sh +0 -27
- 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 -335
- 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 -742
- 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 -544
- package/scripts/theme/switch.sh +0 -449
- 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/version-sync.sh +0 -654
- 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,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
|