@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,333 +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
|
-
# shellcheck source=../../lib/dot/log.sh
|
|
11
|
-
# shellcheck disable=SC1091
|
|
12
|
-
source "$SCRIPT_DIR/../../lib/dot/log.sh"
|
|
13
|
-
# shellcheck source=../../lib/dot/ai-install.sh
|
|
14
|
-
# shellcheck disable=SC1091
|
|
15
|
-
source "$SCRIPT_DIR/../../lib/dot/ai-install.sh"
|
|
16
|
-
export DOT_COMMAND="apply"
|
|
17
|
-
|
|
18
|
-
# Temp file cleanup. `set +u` guards the array expansion: on bash 3.2
|
|
19
|
-
# (macOS) expanding an empty array under `set -u` is an "unbound
|
|
20
|
-
# variable" error, which would fire on every clean `dot sync`.
|
|
21
|
-
_TMPFILES=()
|
|
22
|
-
_LOCK_DIR=""
|
|
23
|
-
cleanup() {
|
|
24
|
-
set +u
|
|
25
|
-
rm -f "${_TMPFILES[@]}" 2>/dev/null
|
|
26
|
-
[[ -n "$_LOCK_DIR" ]] && rmdir "$_LOCK_DIR" 2>/dev/null
|
|
27
|
-
set -u
|
|
28
|
-
}
|
|
29
|
-
trap cleanup EXIT
|
|
30
|
-
|
|
31
|
-
# Help flag
|
|
32
|
-
case "${1:-}" in
|
|
33
|
-
-h | --help)
|
|
34
|
-
cat <<HELP
|
|
35
|
-
chezmoi-apply.sh - Apply dotfiles with enhanced diagnostics
|
|
36
|
-
|
|
37
|
-
Usage:
|
|
38
|
-
dot apply [OPTIONS] [-- CHEZMOI_ARGS]
|
|
39
|
-
|
|
40
|
-
Environment Variables:
|
|
41
|
-
DOTFILES_CHEZMOI_APPLY_FLAGS Extra flags for chezmoi apply
|
|
42
|
-
DOTFILES_CHEZMOI_VERBOSE=1 Enable verbose output
|
|
43
|
-
DOTFILES_CHEZMOI_KEEP_GOING=1 Continue on errors
|
|
44
|
-
DOTFILES_NONINTERACTIVE=1 Skip interactive menus (AI provider installer)
|
|
45
|
-
DOTFILES_INTERACTIVE_APPLY=1 Re-enable chezmoi overwrite prompts
|
|
46
|
-
(apply is unattended/--force by default)
|
|
47
|
-
DOTFILES_ALIAS_STRICT_MODE=1 Run alias governance checks
|
|
48
|
-
DOTFILES_SNAPSHOT_ON_APPLY=1 Create baseline snapshot (default)
|
|
49
|
-
DOTFILES_POST_APPLY_REPAIR=1 Run post-apply repairs (default)
|
|
50
|
-
DOTFILES_CHEZMOI_STATUS=1 Show status after apply (default)
|
|
51
|
-
HELP
|
|
52
|
-
exit 0
|
|
53
|
-
;;
|
|
54
|
-
esac
|
|
55
|
-
|
|
56
|
-
args=("$@")
|
|
57
|
-
if [[ -n "${DOTFILES_CHEZMOI_APPLY_FLAGS:-}" ]]; then
|
|
58
|
-
# Safely parse space-separated flags into array
|
|
59
|
-
read -ra flag_array <<<"$DOTFILES_CHEZMOI_APPLY_FLAGS"
|
|
60
|
-
args+=("${flag_array[@]}")
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
if [[ "${DOTFILES_CHEZMOI_VERBOSE:-0}" = "1" ]]; then
|
|
64
|
-
args+=("--verbose")
|
|
65
|
-
fi
|
|
66
|
-
|
|
67
|
-
if [[ "${DOTFILES_CHEZMOI_KEEP_GOING:-0}" = "1" ]]; then
|
|
68
|
-
args+=("--keep-going")
|
|
69
|
-
fi
|
|
70
|
-
|
|
71
|
-
has_flag() {
|
|
72
|
-
local needle="$1"
|
|
73
|
-
local arg
|
|
74
|
-
# Guard the expansion: on bash 3.2 (macOS) iterating an empty array
|
|
75
|
-
# under `set -u` is an unbound-variable error.
|
|
76
|
-
[[ ${#args[@]} -eq 0 ]] && return 1
|
|
77
|
-
for arg in "${args[@]}"; do
|
|
78
|
-
[[ "$arg" == "$needle" ]] && return 0
|
|
79
|
-
done
|
|
80
|
-
return 1
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
# Apply unattended by default, like an OS package manager. chezmoi is
|
|
84
|
-
# always run below under `gum spin` or with its output captured, so it
|
|
85
|
-
# never has a controlling TTY; its "<file> has changed since chezmoi last
|
|
86
|
-
# wrote it" confirmation prompt therefore cannot be answered and aborts
|
|
87
|
-
# the run with "could not open a new TTY". Passing --force applies the
|
|
88
|
-
# canonical source without prompting, so local drift to *managed* files
|
|
89
|
-
# yields to the source — exactly how `apt`/system updates behave. Keep
|
|
90
|
-
# machine-specific tweaks in the unmanaged ~/.zshrc.local or
|
|
91
|
-
# ~/.config/zsh/rc.d.local/*.zsh, which chezmoi never overwrites.
|
|
92
|
-
# Opt back into chezmoi's prompts with DOTFILES_INTERACTIVE_APPLY=1.
|
|
93
|
-
if [[ "${DOTFILES_INTERACTIVE_APPLY:-0}" != "1" ]] && ! has_flag "--force"; then
|
|
94
|
-
args+=("--force")
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
# Whether interactive menus (the optional AI-provider installer below) may
|
|
98
|
-
# prompt. Suppressed without a TTY, under CI, or when non-interactive is
|
|
99
|
-
# requested — so unattended runs never hang waiting on input.
|
|
100
|
-
INTERACTIVE=1
|
|
101
|
-
if [[ "${DOTFILES_NONINTERACTIVE:-0}" == "1" ]] || [[ -n "${CI:-}" ]] || [[ ! -t 0 ]] || [[ ! -t 1 ]]; then
|
|
102
|
-
INTERACTIVE=0
|
|
103
|
-
fi
|
|
104
|
-
|
|
105
|
-
ui_init
|
|
106
|
-
|
|
107
|
-
# Prevent concurrent execution. flock(1) is Linux-only — it does not exist
|
|
108
|
-
# on macOS, where `! flock` previously took the "already running" branch and
|
|
109
|
-
# made `dot apply` a silent no-op. Use flock where present, otherwise fall
|
|
110
|
-
# back to an atomic mkdir lock (portable to macOS/BSD).
|
|
111
|
-
_lock_base="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/dotfiles-chezmoi-apply"
|
|
112
|
-
if command -v flock >/dev/null 2>&1; then
|
|
113
|
-
exec 9>"${_lock_base}.lock"
|
|
114
|
-
if ! flock -n 9; then
|
|
115
|
-
ui_warn "Already running" "Another instance is active"
|
|
116
|
-
exit 0
|
|
117
|
-
fi
|
|
118
|
-
elif ! mkdir "${_lock_base}.lock.d" 2>/dev/null; then
|
|
119
|
-
ui_warn "Already running" "Another instance is active"
|
|
120
|
-
exit 0
|
|
121
|
-
else
|
|
122
|
-
_LOCK_DIR="${_lock_base}.lock.d" # removed by cleanup() on exit
|
|
123
|
-
fi
|
|
124
|
-
|
|
125
|
-
run_step() {
|
|
126
|
-
local title="$1"
|
|
127
|
-
shift
|
|
128
|
-
local out
|
|
129
|
-
out="$(umask 077 && mktemp)"
|
|
130
|
-
_TMPFILES+=("$out")
|
|
131
|
-
if [[ "$UI_ENABLED" = "1" ]]; then
|
|
132
|
-
if gum spin --spinner dot --title "$title" -- "$@" >"$out" 2>&1; then
|
|
133
|
-
ui_ok "$title"
|
|
134
|
-
if [[ "${DOTFILES_CHEZMOI_VERBOSE:-0}" = "1" ]] && [[ -s "$out" ]]; then
|
|
135
|
-
cat "$out"
|
|
136
|
-
fi
|
|
137
|
-
else
|
|
138
|
-
ui_err "$title"
|
|
139
|
-
cat "$out"
|
|
140
|
-
rm -f "$out"
|
|
141
|
-
exit 1
|
|
142
|
-
fi
|
|
143
|
-
else
|
|
144
|
-
echo "$title..."
|
|
145
|
-
if "$@" >"$out" 2>&1; then
|
|
146
|
-
if [[ "${DOTFILES_CHEZMOI_VERBOSE:-0}" = "1" ]] && [[ -s "$out" ]]; then
|
|
147
|
-
cat "$out"
|
|
148
|
-
fi
|
|
149
|
-
else
|
|
150
|
-
cat "$out"
|
|
151
|
-
rm -f "$out"
|
|
152
|
-
exit 1
|
|
153
|
-
fi
|
|
154
|
-
fi
|
|
155
|
-
rm -f "$out"
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
dot_log info "apply_start"
|
|
159
|
-
_apply_start=$(date +%s)
|
|
160
|
-
ui_header "Applying dotfiles"
|
|
161
|
-
if [[ "${DOTFILES_ALIAS_STRICT_MODE:-0}" == "1" ]]; then
|
|
162
|
-
governance_script="$SCRIPT_DIR/../diagnostics/alias-governance.sh"
|
|
163
|
-
if [[ -f "$governance_script" ]]; then
|
|
164
|
-
run_step "Alias governance (strict)" env DOTFILES_ALIAS_POLICY=strict bash "$governance_script"
|
|
165
|
-
fi
|
|
166
|
-
fi
|
|
167
|
-
run_step "Chezmoi apply" chezmoi apply "${args[@]}"
|
|
168
|
-
|
|
169
|
-
if [[ "${DOTFILES_SNAPSHOT_ON_APPLY:-1}" = "1" ]]; then
|
|
170
|
-
snapshot_script="$SCRIPT_DIR/../diagnostics/snapshot.sh"
|
|
171
|
-
snapshot_dir="${XDG_STATE_HOME:-$HOME/.local/state}/dotfiles/snapshots"
|
|
172
|
-
snapshot_file="${snapshot_dir}/baseline.json"
|
|
173
|
-
if [[ -f "$snapshot_script" && ! -f "$snapshot_file" ]]; then
|
|
174
|
-
mkdir -p "$snapshot_dir"
|
|
175
|
-
bash "$snapshot_script" --baseline >/dev/null 2>&1 || true
|
|
176
|
-
fi
|
|
177
|
-
fi
|
|
178
|
-
|
|
179
|
-
check_cmd() {
|
|
180
|
-
local cmd="$1"
|
|
181
|
-
if command -v "$cmd" &>/dev/null; then
|
|
182
|
-
return 0
|
|
183
|
-
fi
|
|
184
|
-
if command -v mise &>/dev/null; then
|
|
185
|
-
if mise ls --installed 2>/dev/null | grep -qE "($cmd|aqua:.*$cmd)"; then
|
|
186
|
-
return 0
|
|
187
|
-
fi
|
|
188
|
-
fi
|
|
189
|
-
return 1
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
echo ""
|
|
193
|
-
ui_header "AI provider CLI checks (optional)"
|
|
194
|
-
|
|
195
|
-
# binary|mise_package|label (claude uses the native installer, not mise)
|
|
196
|
-
_AI_PROVIDERS=(
|
|
197
|
-
"claude|native|Claude Code"
|
|
198
|
-
"codex|npm:@openai/codex|Codex CLI"
|
|
199
|
-
"copilot|npm:@github/copilot|Copilot CLI"
|
|
200
|
-
"goose|native|Goose"
|
|
201
|
-
"agy|native|Antigravity CLI"
|
|
202
|
-
"kimi|native|Kimi CLI"
|
|
203
|
-
"sgpt|pipx:shell-gpt|Shell-GPT"
|
|
204
|
-
"ollama|aqua:ollama/ollama|Ollama"
|
|
205
|
-
"opencode|npm:opencode-ai|OpenCode"
|
|
206
|
-
"aider|pipx:aider-chat|Aider"
|
|
207
|
-
"kiro-cli|kiro-cli|Kiro CLI"
|
|
208
|
-
"autohand|npm:autohand-cli|Autohand Code"
|
|
209
|
-
"vibe|pipx:mistral-vibe|Mistral Vibe"
|
|
210
|
-
"qwen|npm:@qwen-code/qwen-code|Qwen Code"
|
|
211
|
-
"zai|npm:@guizmo-ai/zai-cli|ZAI"
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
_ai_missing=()
|
|
215
|
-
for _entry in "${_AI_PROVIDERS[@]}"; do
|
|
216
|
-
IFS='|' read -r _bin _pkg _label <<<"$_entry"
|
|
217
|
-
if check_cmd "$_bin"; then
|
|
218
|
-
ui_ok "$_label"
|
|
219
|
-
else
|
|
220
|
-
ui_info "$_label" "not installed"
|
|
221
|
-
_ai_missing+=("$_entry")
|
|
222
|
-
fi
|
|
223
|
-
done
|
|
224
|
-
|
|
225
|
-
if [[ ${#_ai_missing[@]} -gt 0 ]] && [[ "$INTERACTIVE" == "1" ]]; then
|
|
226
|
-
if command -v mise &>/dev/null; then
|
|
227
|
-
echo ""
|
|
228
|
-
_ai_install_action=""
|
|
229
|
-
if command -v gum &>/dev/null; then
|
|
230
|
-
_ai_install_action=$(printf '%s\n' "Install all" "Choose which to install" "Skip" |
|
|
231
|
-
gum choose --header "Missing AI providers — install via mise?") || _ai_install_action=""
|
|
232
|
-
else
|
|
233
|
-
ui_info "Tip" "Install all missing AI providers with: mise install"
|
|
234
|
-
ui_info "Tip" "Or individually: mise use -g <package>@latest"
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
|
-
_ai_to_install=()
|
|
238
|
-
case "$_ai_install_action" in
|
|
239
|
-
"Install all")
|
|
240
|
-
_ai_to_install=("${_ai_missing[@]}")
|
|
241
|
-
;;
|
|
242
|
-
"Choose which to install")
|
|
243
|
-
_ai_pick_choices=()
|
|
244
|
-
for _entry in "${_ai_missing[@]}"; do
|
|
245
|
-
IFS='|' read -r _bin _pkg _label <<<"$_entry"
|
|
246
|
-
_ai_pick_choices+=("$_label")
|
|
247
|
-
done
|
|
248
|
-
_ai_picked=$(printf '%s\n' "${_ai_pick_choices[@]}" |
|
|
249
|
-
gum choose --no-limit --header "Select providers to install (Space to toggle, Enter to confirm)") || _ai_picked=""
|
|
250
|
-
if [[ -n "$_ai_picked" ]]; then
|
|
251
|
-
while IFS= read -r _selected; do
|
|
252
|
-
[[ -z "$_selected" ]] && continue
|
|
253
|
-
for _entry in "${_ai_missing[@]}"; do
|
|
254
|
-
IFS='|' read -r _bin _pkg _label <<<"$_entry"
|
|
255
|
-
if [[ "$_label" == "$_selected" ]]; then
|
|
256
|
-
_ai_to_install+=("$_entry")
|
|
257
|
-
fi
|
|
258
|
-
done
|
|
259
|
-
done <<<"$_ai_picked"
|
|
260
|
-
fi
|
|
261
|
-
;;
|
|
262
|
-
esac
|
|
263
|
-
|
|
264
|
-
if [[ ${#_ai_to_install[@]} -gt 0 ]]; then
|
|
265
|
-
echo ""
|
|
266
|
-
for _entry in "${_ai_to_install[@]}"; do
|
|
267
|
-
IFS='|' read -r _bin _pkg _label <<<"$_entry"
|
|
268
|
-
if [[ "$_bin" == "claude" ]]; then
|
|
269
|
-
install_claude_native "$_label"
|
|
270
|
-
continue
|
|
271
|
-
fi
|
|
272
|
-
if [[ "$_bin" == "goose" ]]; then
|
|
273
|
-
install_goose_native "$_label"
|
|
274
|
-
continue
|
|
275
|
-
fi
|
|
276
|
-
if [[ "$_bin" == "agy" ]]; then
|
|
277
|
-
install_agy_native "$_label"
|
|
278
|
-
continue
|
|
279
|
-
fi
|
|
280
|
-
if [[ "$_bin" == "kimi" ]]; then
|
|
281
|
-
install_kimi_native "$_label"
|
|
282
|
-
continue
|
|
283
|
-
fi
|
|
284
|
-
if command -v gum &>/dev/null; then
|
|
285
|
-
if gum spin --spinner dot --title "Installing $_label ($_pkg)" -- \
|
|
286
|
-
mise use -g "$_pkg@latest" 2>&1; then
|
|
287
|
-
ui_ok "$_label" "installed"
|
|
288
|
-
else
|
|
289
|
-
ui_warn "$_label" "install failed (continuing)"
|
|
290
|
-
fi
|
|
291
|
-
else
|
|
292
|
-
ui_info "Installing" "$_label via mise ($_pkg)"
|
|
293
|
-
mise use -g "$_pkg@latest" 2>&1 || ui_warn "$_label" "install failed (continuing)"
|
|
294
|
-
fi
|
|
295
|
-
done
|
|
296
|
-
fi
|
|
297
|
-
else
|
|
298
|
-
ui_warn "mise" "not found — install mise first to manage AI providers"
|
|
299
|
-
fi
|
|
300
|
-
fi
|
|
301
|
-
|
|
302
|
-
if [[ "${DOTFILES_CHEZMOI_STATUS:-1}" = "1" ]]; then
|
|
303
|
-
printf "\n"
|
|
304
|
-
ui_header "Status"
|
|
305
|
-
status_out="$(chezmoi status || true)"
|
|
306
|
-
if [[ -z "$status_out" ]]; then
|
|
307
|
-
ui_ok "Clean"
|
|
308
|
-
else
|
|
309
|
-
printf "%s\n" "$status_out"
|
|
310
|
-
fi
|
|
311
|
-
fi
|
|
312
|
-
|
|
313
|
-
if [[ "${DOTFILES_POST_APPLY_REPAIR:-1}" = "1" ]]; then
|
|
314
|
-
post_apply_script="$SCRIPT_DIR/post-apply-repair.sh"
|
|
315
|
-
if [[ -f "$post_apply_script" ]]; then
|
|
316
|
-
printf "\n"
|
|
317
|
-
bash "$post_apply_script" || true
|
|
318
|
-
fi
|
|
319
|
-
fi
|
|
320
|
-
|
|
321
|
-
if [[ "${DOTFILES_PREWARM_ON_APPLY:-1}" = "1" ]]; then
|
|
322
|
-
prewarm_script="$SCRIPT_DIR/prewarm.sh"
|
|
323
|
-
if [[ -f "$prewarm_script" ]]; then
|
|
324
|
-
printf "\n"
|
|
325
|
-
run_step "Pre-warming shell caches" bash "$prewarm_script"
|
|
326
|
-
fi
|
|
327
|
-
fi
|
|
328
|
-
|
|
329
|
-
printf "\n"
|
|
330
|
-
_apply_end=$(date +%s)
|
|
331
|
-
dot_log info "apply_end" "duration_s=$((_apply_end - _apply_start))"
|
|
332
|
-
dot_metric "chezmoi_apply_duration" "$((_apply_end - _apply_start))" "s"
|
|
333
|
-
ui_info "Shell reload" "Run 'exec zsh' or restart your terminal to reload aliases/functions."
|
|
@@ -1,16 +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
|
-
excludes=(scripts)
|
|
7
|
-
if [[ -n "${DOTFILES_CHEZMOI_DIFF_EXCLUDES:-}" ]]; then
|
|
8
|
-
IFS=',' read -r -a excludes <<<"${DOTFILES_CHEZMOI_DIFF_EXCLUDES}"
|
|
9
|
-
fi
|
|
10
|
-
|
|
11
|
-
args=()
|
|
12
|
-
for ex in "${excludes[@]}"; do
|
|
13
|
-
args+=("--exclude" "$ex")
|
|
14
|
-
done
|
|
15
|
-
|
|
16
|
-
chezmoi diff "${args[@]}" "$@"
|
|
@@ -1,46 +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
|
-
if [[ $# -lt 1 ]]; then
|
|
7
|
-
echo "Usage: dot remove <path> [--source] [--dry-run]" >&2
|
|
8
|
-
exit 1
|
|
9
|
-
fi
|
|
10
|
-
|
|
11
|
-
remove_source=0
|
|
12
|
-
args=()
|
|
13
|
-
paths=()
|
|
14
|
-
|
|
15
|
-
for arg in "$@"; do
|
|
16
|
-
case "$arg" in
|
|
17
|
-
--source)
|
|
18
|
-
remove_source=1
|
|
19
|
-
;;
|
|
20
|
-
--dry-run)
|
|
21
|
-
args+=("--dry-run")
|
|
22
|
-
;;
|
|
23
|
-
*)
|
|
24
|
-
paths+=("$arg")
|
|
25
|
-
;;
|
|
26
|
-
esac
|
|
27
|
-
done
|
|
28
|
-
|
|
29
|
-
if [[ ${#paths[@]} -eq 0 ]]; then
|
|
30
|
-
echo "No path provided." >&2
|
|
31
|
-
exit 1
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
# shellcheck disable=SC1091
|
|
35
|
-
if [[ $remove_source -eq 0 ]]; then
|
|
36
|
-
args+=("--keep-source")
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
printf "About to run: chezmoi remove %s %s\n" "${args[*]}" "${paths[*]}"
|
|
40
|
-
read -r -p "Proceed? [y/N] " confirm
|
|
41
|
-
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
|
|
42
|
-
echo "Aborted."
|
|
43
|
-
exit 1
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
chezmoi remove "${args[@]}" "${paths[@]}"
|
|
@@ -1,63 +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
|
-
args=()
|
|
7
|
-
if [[ -n "${DOTFILES_CHEZMOI_UPDATE_FLAGS:-}" ]]; then
|
|
8
|
-
# Safely parse space-separated flags into array
|
|
9
|
-
read -ra flag_array <<<"$DOTFILES_CHEZMOI_UPDATE_FLAGS"
|
|
10
|
-
args+=("${flag_array[@]}")
|
|
11
|
-
fi
|
|
12
|
-
|
|
13
|
-
if [[ "${DOTFILES_CHEZMOI_VERBOSE:-0}" = "1" ]]; then
|
|
14
|
-
args+=("--verbose")
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# Apply unattended by default (see chezmoi-apply.sh). `chezmoi update` runs
|
|
18
|
-
# `apply` internally, so without --force it blocks on the "<file> has
|
|
19
|
-
# changed since chezmoi last wrote it" prompt — and `dot update` is often
|
|
20
|
-
# run from cron/CI/--async with no TTY, where that prompt aborts the run.
|
|
21
|
-
# --force makes updates land like an OS package-manager update; opt back
|
|
22
|
-
# into prompting with DOTFILES_INTERACTIVE_APPLY=1.
|
|
23
|
-
if [[ "${DOTFILES_INTERACTIVE_APPLY:-0}" != "1" ]]; then
|
|
24
|
-
_has_force=0
|
|
25
|
-
if [[ ${#args[@]} -gt 0 ]]; then
|
|
26
|
-
for _a in "${args[@]}"; do [[ "$_a" == "--force" ]] && _has_force=1; done
|
|
27
|
-
fi
|
|
28
|
-
[[ "$_has_force" == "0" ]] && args+=("--force")
|
|
29
|
-
fi
|
|
30
|
-
|
|
31
|
-
ASYNC=false
|
|
32
|
-
if [[ "${DOTFILES_ASYNC_UPDATE:-0}" = "1" ]]; then
|
|
33
|
-
ASYNC=true
|
|
34
|
-
fi
|
|
35
|
-
if [[ "${1:-}" == "--async" ]]; then
|
|
36
|
-
ASYNC=true
|
|
37
|
-
shift
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/dotfiles/update"
|
|
41
|
-
mkdir -p "$STATE_DIR"
|
|
42
|
-
LOG_FILE="$STATE_DIR/last.log"
|
|
43
|
-
STATUS_FILE="$STATE_DIR/last.status"
|
|
44
|
-
NOTICE_FILE="$STATE_DIR/notice"
|
|
45
|
-
|
|
46
|
-
run_update() {
|
|
47
|
-
echo "Updating dotfiles..."
|
|
48
|
-
chezmoi update "${args[@]}"
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if $ASYNC; then
|
|
52
|
-
echo "Update running in background..."
|
|
53
|
-
{
|
|
54
|
-
run_update
|
|
55
|
-
echo $? >"$STATUS_FILE"
|
|
56
|
-
} >"$LOG_FILE" 2>&1 &
|
|
57
|
-
date -u +%Y-%m-%dT%H:%M:%SZ >"$NOTICE_FILE"
|
|
58
|
-
disown || true
|
|
59
|
-
exit 0
|
|
60
|
-
fi
|
|
61
|
-
|
|
62
|
-
run_update
|
|
63
|
-
echo $? >"$STATUS_FILE"
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2015-2026 Sebastien Rousseau
|
|
4
|
-
# shellcheck disable=SC2034
|
|
5
|
-
# =============================================================================
|
|
6
|
-
# heal-chezmoi.sh — Chezmoi drift and backup repair functions for heal.sh
|
|
7
|
-
# Sourced by heal.sh; inherits set -euo pipefail, ui.sh, and shared variables.
|
|
8
|
-
# =============================================================================
|
|
9
|
-
|
|
10
|
-
create_pre_heal_backup() {
|
|
11
|
-
local rollback_script="$REPO_ROOT/scripts/ops/rollback.sh"
|
|
12
|
-
if [[ -f "$rollback_script" ]]; then
|
|
13
|
-
log_info "Creating backup before heal..."
|
|
14
|
-
bash "$rollback_script" backup --force 2>/dev/null || true
|
|
15
|
-
else
|
|
16
|
-
# Minimal inline backup
|
|
17
|
-
local timestamp
|
|
18
|
-
timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
19
|
-
local backup_path="$BACKUP_DIR/backup_${timestamp}_pre_heal"
|
|
20
|
-
mkdir -p "$backup_path"
|
|
21
|
-
for f in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do
|
|
22
|
-
if [[ -f "$f" ]]; then
|
|
23
|
-
cp -a "$f" "$backup_path/" 2>/dev/null || true
|
|
24
|
-
fi
|
|
25
|
-
done
|
|
26
|
-
log_info "Backup created at $backup_path"
|
|
27
|
-
fi
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
heal_chezmoi_drift() {
|
|
31
|
-
if ! command -v chezmoi >/dev/null 2>&1; then return 0; fi
|
|
32
|
-
|
|
33
|
-
local status_output
|
|
34
|
-
status_output=$(chezmoi status 2>/dev/null || echo "")
|
|
35
|
-
|
|
36
|
-
if [[ -z "$status_output" ]]; then
|
|
37
|
-
printf ' \033[38;5;42m✓\033[0m chezmoi state\n'
|
|
38
|
-
return 0
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
# Partition the drift: column 2 is what `chezmoi apply` would fix
|
|
42
|
-
# (destination differs from source). Column 1 is source-only drift
|
|
43
|
-
# (unstaged edits in the chezmoi source tree). Apply can't help with
|
|
44
|
-
# the second case — that needs `git commit` in the source repo.
|
|
45
|
-
local applicable
|
|
46
|
-
local source_only
|
|
47
|
-
applicable=$(printf '%s\n' "$status_output" | awk 'substr($0,2,1)!=" "' | wc -l | tr -d ' ')
|
|
48
|
-
source_only=$(printf '%s\n' "$status_output" | awk 'substr($0,1,1)!=" " && substr($0,2,1)==" "' | wc -l | tr -d ' ')
|
|
49
|
-
|
|
50
|
-
ISSUES_FOUND=$((ISSUES_FOUND + 1))
|
|
51
|
-
|
|
52
|
-
if [[ "$DRY_RUN" == "1" ]]; then
|
|
53
|
-
log_dry "run 'chezmoi apply --force' to re-sync ($applicable file(s))"
|
|
54
|
-
return 0
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
# Skip the apply if every file is source-only drift; nothing to fix.
|
|
58
|
-
if [[ "$applicable" -eq 0 ]]; then
|
|
59
|
-
printf ' \033[38;5;220m⚠\033[0m chezmoi state %s file(s) modified in source only — commit or revert in the source repo\n' "$source_only"
|
|
60
|
-
return 0
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
# Capture apply output so we can surface failure reasons.
|
|
64
|
-
local apply_log
|
|
65
|
-
apply_log=$(mktemp)
|
|
66
|
-
if chezmoi apply --force >"$apply_log" 2>&1; then
|
|
67
|
-
FIXES_APPLIED=$((FIXES_APPLIED + 1))
|
|
68
|
-
CHEZMOI_APPLIED=1
|
|
69
|
-
persist_log "HEAL: chezmoi apply --force"
|
|
70
|
-
|
|
71
|
-
# Verify: did apply actually clean the drift?
|
|
72
|
-
local remaining
|
|
73
|
-
remaining=$(chezmoi status 2>/dev/null | awk 'substr($0,2,1)!=" "' | wc -l | tr -d ' ')
|
|
74
|
-
if [[ "$remaining" -eq 0 ]]; then
|
|
75
|
-
printf ' \033[38;5;42m✓\033[0m chezmoi re-apply %s file(s) synced\n' "$applicable"
|
|
76
|
-
else
|
|
77
|
-
# shellcheck disable=SC2016
|
|
78
|
-
printf ' \033[38;5;220m⚠\033[0m chezmoi re-apply %s applied, %s still drifted — run `chezmoi diff` to inspect\n' \
|
|
79
|
-
"$((applicable - remaining))" "$remaining"
|
|
80
|
-
fi
|
|
81
|
-
else
|
|
82
|
-
printf ' \033[38;5;196m✗\033[0m chezmoi re-apply failed; see %s\n' "$apply_log"
|
|
83
|
-
tail -5 "$apply_log" | sed 's/^/ /'
|
|
84
|
-
return 1
|
|
85
|
-
fi
|
|
86
|
-
rm -f "$apply_log"
|
|
87
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2015-2026 Sebastien Rousseau
|
|
4
|
-
# shellcheck disable=SC2034
|
|
5
|
-
# =============================================================================
|
|
6
|
-
# heal-system.sh — System-level repair functions for heal.sh
|
|
7
|
-
# Sourced by heal.sh; inherits set -euo pipefail, ui.sh, and shared variables.
|
|
8
|
-
# =============================================================================
|
|
9
|
-
|
|
10
|
-
heal_broken_symlinks() {
|
|
11
|
-
local broken=()
|
|
12
|
-
|
|
13
|
-
while IFS= read -r -d '' link; do
|
|
14
|
-
local filename
|
|
15
|
-
filename=$(basename "$link")
|
|
16
|
-
|
|
17
|
-
# Skip known false positives (e.g., Chrome lock files in backups)
|
|
18
|
-
[[ "$link" == *"google-chrome-backup"* ]] && continue
|
|
19
|
-
[[ "$filename" == "SingletonLock" || "$filename" == "SingletonCookie" || "$filename" == "SingletonSocket" ]] && continue
|
|
20
|
-
|
|
21
|
-
if [[ ! -e "$link" ]]; then
|
|
22
|
-
broken+=("$link")
|
|
23
|
-
fi
|
|
24
|
-
done < <(find "$HOME" -maxdepth 3 -type l -print0 2>/dev/null || true)
|
|
25
|
-
|
|
26
|
-
# Special handling for common transient/app locks that dot doctor reported
|
|
27
|
-
local lock_patterns=("SingletonLock" "SingletonCookie")
|
|
28
|
-
|
|
29
|
-
if [[ ${#broken[@]} -eq 0 ]]; then
|
|
30
|
-
printf ' \033[38;5;42m✓\033[0m symlinks\n'
|
|
31
|
-
return 0
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
ISSUES_FOUND=$((ISSUES_FOUND + ${#broken[@]}))
|
|
35
|
-
|
|
36
|
-
for link in "${broken[@]}"; do
|
|
37
|
-
local target
|
|
38
|
-
target=$(readlink "$link" 2>/dev/null || echo "unknown")
|
|
39
|
-
local filename
|
|
40
|
-
filename=$(basename "$link")
|
|
41
|
-
|
|
42
|
-
local is_lock=0
|
|
43
|
-
for pat in "${lock_patterns[@]}"; do
|
|
44
|
-
if [[ "$filename" == *"$pat"* ]]; then
|
|
45
|
-
is_lock=1
|
|
46
|
-
break
|
|
47
|
-
fi
|
|
48
|
-
done
|
|
49
|
-
|
|
50
|
-
if [[ "$DRY_RUN" == "1" ]]; then
|
|
51
|
-
log_dry "remove broken symlink: $link -> $target"
|
|
52
|
-
else
|
|
53
|
-
if [[ "$is_lock" == "0" ]] && [[ "$FORCE" != "1" ]] && [[ "${DOTFILES_NONINTERACTIVE:-0}" != "1" ]]; then
|
|
54
|
-
read -rp "Remove broken symlink $link -> $target? [y/N] " response
|
|
55
|
-
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
|
56
|
-
continue
|
|
57
|
-
fi
|
|
58
|
-
fi
|
|
59
|
-
if rm -f "$link" 2>/dev/null; then
|
|
60
|
-
printf ' \033[38;5;42m✓\033[0m removed %s\n' "$link"
|
|
61
|
-
FIXES_APPLIED=$((FIXES_APPLIED + 1))
|
|
62
|
-
persist_log "HEAL: removed broken symlink $link"
|
|
63
|
-
else
|
|
64
|
-
printf ' \033[38;5;214m⚠\033[0m could not remove %s\n' "$link"
|
|
65
|
-
fi
|
|
66
|
-
fi
|
|
67
|
-
done
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
heal_missing_critical_files() {
|
|
71
|
-
local critical_files=("$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.profile")
|
|
72
|
-
local missing=()
|
|
73
|
-
|
|
74
|
-
for file in "${critical_files[@]}"; do
|
|
75
|
-
if [[ ! -f "$file" ]] && [[ ! -L "$file" ]]; then
|
|
76
|
-
missing+=("$file")
|
|
77
|
-
ISSUES_FOUND=$((ISSUES_FOUND + 1))
|
|
78
|
-
fi
|
|
79
|
-
done
|
|
80
|
-
|
|
81
|
-
if [[ ${#missing[@]} -eq 0 ]]; then
|
|
82
|
-
printf ' \033[38;5;42m✓\033[0m shell configs\n'
|
|
83
|
-
return 0
|
|
84
|
-
fi
|
|
85
|
-
|
|
86
|
-
if ! command -v chezmoi >/dev/null 2>&1; then return 1; fi
|
|
87
|
-
|
|
88
|
-
if [[ "$DRY_RUN" == "1" ]]; then
|
|
89
|
-
log_dry "regenerate missing files via chezmoi"
|
|
90
|
-
elif [[ "$CHEZMOI_APPLIED" != "1" ]]; then
|
|
91
|
-
if _pkg_install "shell configs" 0 1 chezmoi apply --force; then
|
|
92
|
-
CHEZMOI_APPLIED=1
|
|
93
|
-
local restored=0
|
|
94
|
-
for file in "${missing[@]}"; do
|
|
95
|
-
if [[ -f "$file" ]] || [[ -L "$file" ]]; then
|
|
96
|
-
restored=$((restored + 1))
|
|
97
|
-
fi
|
|
98
|
-
done
|
|
99
|
-
FIXES_APPLIED=$((FIXES_APPLIED + restored))
|
|
100
|
-
persist_log "HEAL: regenerated $restored critical file(s)"
|
|
101
|
-
fi
|
|
102
|
-
fi
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
heal_missing_xdg_dirs() {
|
|
106
|
-
local xdg_dirs=("$HOME/.config/shell" "$HOME/.config/nvim" "$HOME/.config/git")
|
|
107
|
-
local missing=()
|
|
108
|
-
|
|
109
|
-
for dir in "${xdg_dirs[@]}"; do
|
|
110
|
-
[[ -d "$dir" ]] || missing+=("$dir")
|
|
111
|
-
done
|
|
112
|
-
|
|
113
|
-
if [[ ${#missing[@]} -eq 0 ]]; then
|
|
114
|
-
printf ' \033[38;5;42m✓\033[0m xdg directories\n'
|
|
115
|
-
return 0
|
|
116
|
-
fi
|
|
117
|
-
|
|
118
|
-
ISSUES_FOUND=$((ISSUES_FOUND + ${#missing[@]}))
|
|
119
|
-
for dir in "${missing[@]}"; do
|
|
120
|
-
if [[ "$DRY_RUN" == "1" ]]; then
|
|
121
|
-
log_dry "create directory: $dir"
|
|
122
|
-
else
|
|
123
|
-
mkdir -p "$dir"
|
|
124
|
-
printf ' \033[38;5;42m✓\033[0m %s\n' "$(basename "$dir")"
|
|
125
|
-
FIXES_APPLIED=$((FIXES_APPLIED + 1))
|
|
126
|
-
persist_log "HEAL: created directory $dir"
|
|
127
|
-
fi
|
|
128
|
-
done
|
|
129
|
-
}
|