@sebastienrousseau/dotfiles 0.2.511 → 0.2.512

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +2 -2
  3. package/docs/AI.md +2 -1
  4. package/docs/COPYRIGHT +1 -1
  5. package/docs/architecture/AI_COST_OPTIMIZATION.md +1 -0
  6. package/docs/archive/LEGACY_ROADMAP.md +4 -158
  7. package/docs/manual/00-introduction.md +1 -1
  8. package/docs/manual/02-tutorials/02-add-wallpaper.md +6 -6
  9. package/docs/manual/02-tutorials/03-create-profile.md +1 -1
  10. package/docs/manual/02-tutorials/05-deploy-fleet.md +1 -1
  11. package/docs/manual/03-reference/02-config-files.md +1 -1
  12. package/docs/manual/command-index.md +1 -0
  13. package/docs/operations/ARCHITECTURE_ROADMAP.md +5 -143
  14. package/docs/operations/COVERAGE.md +27 -4
  15. package/docs/operations/ROADMAP.md +3 -159
  16. package/docs/operations/ROADMAP_2026.md +5 -663
  17. package/docs/operations/ROADMAP_V0_2_503.md +5 -129
  18. package/docs/reference/THEMES.md +1 -1
  19. package/docs/reference/TOOLS.md +1 -0
  20. package/docs/reference/UTILS.md +1 -0
  21. package/install.sh +5 -5
  22. package/package.json +1 -1
  23. package/scripts/diagnostics/aliases-manifest.sh +33 -6
  24. package/scripts/diagnostics/benchmark.sh +27 -1
  25. package/scripts/diagnostics/doctor.sh +18 -11
  26. package/scripts/diagnostics/health.sh +8 -3
  27. package/scripts/diagnostics/mcp-doctor.sh +3 -0
  28. package/scripts/diagnostics/secret-governance.sh +7 -1
  29. package/scripts/diagnostics/security-score.sh +14 -5
  30. package/scripts/diagnostics/verify_state.sh +9 -1
  31. package/scripts/dot/commands/ai.sh +37 -30
  32. package/scripts/dot/commands/aliases.sh +28 -4
  33. package/scripts/dot/commands/appearance.sh +16 -0
  34. package/scripts/dot/commands/core.sh +17 -0
  35. package/scripts/dot/commands/diagnostics.sh +19 -0
  36. package/scripts/dot/commands/manual.sh +4 -4
  37. package/scripts/dot/commands/meta.sh +87 -12
  38. package/scripts/dot/commands/registry.sh +1 -1
  39. package/scripts/dot/commands/secrets.sh +17 -0
  40. package/scripts/dot/commands/security.sh +17 -0
  41. package/scripts/dot/commands/tools.sh +19 -0
  42. package/scripts/git-hooks/pre-commit-audit.sh +1 -1
  43. package/scripts/ops/ai-setup.sh +13 -6
  44. package/scripts/ops/bundle.sh +31 -5
  45. package/scripts/ops/chezmoi-apply.sh +5 -0
  46. package/scripts/ops/release.sh +14 -5
  47. package/scripts/qa/docs-coverage.sh +1 -1
  48. package/scripts/qa/reliability-audit.sh +2 -2
  49. package/scripts/secrets/age-init.sh +15 -4
  50. package/scripts/theme/apply-gnome-theme.sh +6 -2
  51. package/scripts/theme/extract-theme.py +97 -33
  52. package/scripts/theme/rebuild-themes.sh +240 -35
  53. package/scripts/theme/switch.sh +26 -16
  54. package/scripts/theme/wallpaper-sync.sh +95 -7
  55. package/scripts/version-sync.sh +81 -44
@@ -1,134 +1,10 @@
1
1
  ---
2
- title: "v0.2.503 Roadmap — Enterprise-Ready, Cross-Platform"
3
- date: 2026-05-17
2
+ title: "v0.2.503 Roadmap - Historical"
4
3
  ---
5
4
 
6
- # v0.2.503 — Enterprise-Ready Cross-Platform Polish
5
+ # v0.2.503 Roadmap
7
6
 
8
- ## Why this release
7
+ This v0.2.503 planning document is historical. Active roadmap content has been
8
+ consolidated into [`../../ROADMAP.md`](../../ROADMAP.md).
9
9
 
10
- The R4 audit (`HARD_AUDIT_2026.md` Part 8) ranked the framework
11
- 9.0/10 on internal quality but only 7.5/10 on adoption readiness.
12
- The gap is **distribution + cross-platform polish + visible
13
- organisation** — not feature surface. v0.2.503 closes that gap
14
- without breaking existing user installs.
15
-
16
- Reference target: <https://github.com/Debian/aws-cli> — the Debian
17
- packaging of AWS CLI, often cited as a model of simple, focused
18
- top-level structure. We will not blindly copy its layout (it ships
19
- a Python project, we ship a chezmoi-managed shell framework), but
20
- we will adopt its discipline: every top-level path has a clear
21
- purpose, contributors orient in under 30 seconds.
22
-
23
- ## Scope (non-breaking; v0.2.503)
24
-
25
- ### A — Visible structure (no file moves)
26
-
27
- | | |
28
- |---|---|
29
- | `STRUCTURE.md` at root | Single-page map of every top-level path, why it exists, and what it deploys to. Answers "what is `dot_config/`?", "why are there 25 root files?", "where is the CLI?" — in under 30 seconds. |
30
- | `scripts/README.md` | Map of `scripts/{ci,diagnostics,dot,lib,maintenance,ops,security,tools,tuning}` subtrees. |
31
- | Root `dot_*` files explained | The 20+ `dot_*` / `executable_*` / `private_*` prefixed files at root are not clutter — they are required by chezmoi to render at the corresponding `~/.X` path. STRUCTURE.md makes this contract visible. |
32
-
33
- ### B — UX polish
34
-
35
- | | |
36
- |---|---|
37
- | Sweep remaining tabular `dot` commands through `ui_table_begin/add/end` | Already done: `dot env`, `dot agents list`, `dot registry list/search`, `dot aliases list/search`. Identify any other listing commands not yet on the helper and convert. |
38
- | `dot doctor` rendering | Today emits 100+ lines of `ui_ok / ui_warn / ui_err`. Group into bordered sections with totals at the foot. |
39
- | `dot help` two-column table | The grouped help index could become a gum-table by section. |
40
- | `dot fleet status` widening | Use the table helper for the per-node status block. |
41
-
42
- ### C — Performance
43
-
44
- | | |
45
- |---|---|
46
- | `_cached_eval` coverage audit | Find every `eval "$(<tool> init <shell>)"` in `rc.d/` not already wrapped; add to cache layer. |
47
- | Shell startup p50/p95 in CI | New `dot-cli-bench` workflow exists for the CLI cold-start gate; add an equivalent zsh/bash/fish startup-time gate (sub-150ms cold). |
48
- | Cross-shell `_cached_eval` parity | bash + fish + nu implementations exist; confirm they all do the realpath sidecar pin + suspicious-output check that zsh added. |
49
-
50
- ### D — Cross-platform CI parity
51
-
52
- | | |
53
- |---|---|
54
- | Windows-native smoke test expansion | `tools/ci/windows-smoke-test.ps1` exists but only covers a few commands. Add `dot version / dot help / dot agents check / dot doctor` Windows-native runs. |
55
- | Real `ubuntu-latest` + `macos-latest` + `windows-latest` matrix for the test runner | Currently `ubuntu` + `macos` only; add `windows-latest` to the regular test workflow. |
56
- | `chezmoi apply --dry-run` on all three OSes | Verify our templates render on every platform on every PR. |
57
-
58
- ### E — Code dedup + refactor (in-place)
59
-
60
- | | |
61
- |---|---|
62
- | Audit `scripts/dot/lib/*` for cross-file duplication | Many small helpers may exist in 2+ places. Consolidate. |
63
- | Consistent error-exit codes | Document the canonical exit-code map (1 = bad usage, 2 = no provider, 3 = empty, etc. — `dot secrets` already follows this). Audit other commands for drift. |
64
- | `set -euo pipefail` header lint | Make sure every script under `scripts/` has the canonical header. |
65
-
66
- ### F — Distribution + discoverability (R4 Top-5 work)
67
-
68
- | | |
69
- |---|---|
70
- | Homebrew tap stub | Create `install/homebrew/dot.rb` formula scaffold. Real publication still needs the v0.3 reorganization. |
71
- | Scoop manifest stub | Same for `install/scoop/dot.json`. |
72
- | `awesome-dotfiles` PR draft | One-line entry + screenshot. Land it after v0.2.503 ships. |
73
-
74
- ### G — OpenSSF Scorecard 10/10 across every check
75
-
76
- Target the [public Scorecard report](https://scorecard.dev/viewer/?uri=github.com/sebastienrousseau/dotfiles) and drive every check to 10/10:
77
-
78
- | Check | Today (baseline) | Path to 10 |
79
- |---|---|---|
80
- | **Binary-Artifacts** | 10 (no binaries committed) | Maintain — pre-commit guard rejecting any committed binary. |
81
- | **Branch-Protection** | needs token | Already configured on `main` (required reviews, signed commits, status-check gating, linear history). Verify in `gh api repos/.../branches/main/protection` and document in `docs/security/`. |
82
- | **CI-Tests** | 10 (CI passes on every PR) | Maintain — current 75-check matrix is comprehensive. |
83
- | **CII-Best-Practices** / OpenSSF Best Practices badge | not present | Apply for the badge at [bestpractices.coreinfrastructure.org](https://www.bestpractices.dev/) and embed the badge in README. |
84
- | **Code-Review** | needs verification | Already enforced via branch protection; document in CONTRIBUTING.md. |
85
- | **Contributors** | low (solo) | Acknowledge — solo-maintained framework. Add `MAINTAINERS.md` + `GOVERNANCE.md` documenting the single-maintainer model and contribution path. |
86
- | **Dangerous-Workflow** | 10 (no `pull_request_target` with checkout-then-build) | Maintain — `.github/workflows/` is already audited. |
87
- | **Dependency-Update-Tool** | 10 (Dependabot + Renovate configured) | Maintain. |
88
- | **Fuzzing** | partial (1 fuzz harness for `install.sh`) | Add OSS-Fuzz integration **OR** expand `tests/fuzz/` coverage (URL parsers, manifest validators, secret-bucket loaders). |
89
- | **License** | 10 (MIT, top-level `LICENSE`) | Maintain. |
90
- | **Maintained** | high (active commits weekly) | Maintain. |
91
- | **Packaging** | low (no distro package) | Address via the Homebrew tap / Scoop manifest / AUR PKGBUILD in §F. SLSA-attested release artefacts now exist (v0.2.502 backfill confirmed). |
92
- | **Pinned-Dependencies** | 9 (one tag-pinned reusable workflow — SLSA, documented exception) | Already documented; verify Scorecard accepts the SLSA exception. |
93
- | **SAST** | 10 (CodeQL + Semgrep + Codacy in CI) | Maintain. |
94
- | **Security-Policy** | 10 (`.github/SECURITY.md` + WKD-published GPG key + disclosure-key-expiry monitor) | Maintain. |
95
- | **Signed-Releases** | 8–10 (Cosign-signed SBOM + SLSA provenance now landing per v0.2.502 backfill) | Verify Scorecard re-scrapes the v0.2.502 release post-backfill; should bump to 10. |
96
- | **Token-Permissions** | 10 (top-level `permissions: contents: read`; per-job overrides) | Maintain — set during R3 hardening. |
97
- | **Vulnerabilities** | 10 (osv-scanner + Dependabot keep open count at 0) | Maintain. |
98
- | **Webhooks** | n/a | No org-level webhooks; check not applicable. |
99
-
100
- **Action items:**
101
-
102
- 1. Run `scorecard` locally with the official Docker image, snapshot current scores into `docs/security/SCORECARD.md`.
103
- 2. Apply for OpenSSF Best Practices badge (≤30-min form).
104
- 3. Add `MAINTAINERS.md` + `GOVERNANCE.md`.
105
- 4. Re-trigger Scorecard workflow after v0.2.502 backfill so the dashboard reflects the fixed Signed-Releases score.
106
- 5. Track every sub-10 score with a follow-up issue tagged `scorecard`.
107
-
108
- ## Reorganisation now in-scope (was deferred — see RFC)
109
-
110
- Pulled forward from v0.3.0 into this PR per maintainer request.
111
- The R4 audit identified the framework / user-config intermingling
112
- as the highest-leverage structural gap. Implementation is phased
113
- per `RFC_v0_2_503_reorganization.md`; each phase is independently
114
- atomic.
115
-
116
- | Move | Why it's breaking |
117
- |------|-------------------|
118
- | `dot_config/` → `defaults/` (with chezmoi `.chezmoiroot`) | Every existing user's chezmoi source-state would need to re-bootstrap. |
119
- | `bin/dot` → `bin/dot` | Same; `~/.local/bin/dot` would be removed before the new path is installed. |
120
- | Split `framework/` (CLI + lib) from user-facing defaults | Major restructuring; needs RFC + migration tool + 2-version deprecation window. |
121
-
122
- These will land in v0.2.503 as a coordinated single PR with a
123
- `migrate-v0_2-to-v0_3.sh` script.
124
-
125
- ## Success criteria (v0.2.503)
126
-
127
- - [ ] New contributor can answer "where is the CLI?" / "what is `dot_config/`?" / "how do I add a new command?" in under 30 seconds using only the root `STRUCTURE.md` + `scripts/README.md`.
128
- - [ ] `dot lint` reports 328+ files clean.
129
- - [ ] Shell startup p50 ≤ 100ms in CI on all three OSes.
130
- - [ ] `dot env list` / `dot agents list` / `dot registry list` render with gorgeous gum tables (already done — bake into screenshot for README).
131
- - [ ] `windows-latest` is in the regular test matrix.
132
- - [ ] Pre-existing CI infrastructure failures (SLSA, etc.) stay green after the v0.2.502 fix series.
133
- - [ ] **OpenSSF Scorecard reports 10/10 on every applicable check** at <https://scorecard.dev/viewer/?uri=github.com/sebastienrousseau/dotfiles>.
134
- - [ ] OpenSSF Best Practices badge displayed in README.
10
+ Release history remains in [`../../CHANGELOG.md`](../../CHANGELOG.md).
@@ -54,7 +54,7 @@ Examples (depend on what's present on your system):
54
54
  |:---|:---|
55
55
  | `~/Pictures/Wallpapers/tahoe.heic` (dynamic HEIC, 2 frames) | `tahoe-dark`, `tahoe-light` |
56
56
  | `/System/Library/Desktop Pictures/Sonoma.heic` | `sonoma-dark`, `sonoma-light` |
57
- | `/System/Library/Desktop Pictures/.thumbnails/Dome Dark.heic` + `Dome Light.heic` | `dome-dark`, `dome-light` |
57
+ | `/System/Library/Desktop Pictures/.thumbnails/Monterey Dark.heic` + `Monterey Light.heic` | `monterey-dark`, `monterey-light` |
58
58
 
59
59
  Only paired themes (with both dark and light variants) appear in `dot theme` and `dot theme list`.
60
60
 
@@ -98,6 +98,7 @@ Detailed guide: [AI.md](../AI.md).
98
98
  | **Aider** | Git-native AI pair programming |
99
99
  | **Claude CLI** | Anthropic's terminal assistant |
100
100
  | **Copilot CLI** | GitHub Copilot in the terminal |
101
+ | **Kimi CLI** | Moonshot AI Kimi Code terminal coding agent |
101
102
  | **Kiro CLI** | Agentic AI terminal assistant |
102
103
  | **Antigravity CLI** | Google's Antigravity CLI (`agy`) |
103
104
  | **Mods/Fabric** | Pipeline-friendly AI processing |
@@ -124,6 +124,7 @@ prints a one-line hint. See [AI.md](../AI.md) for the full surface.
124
124
  |---------|-------------|
125
125
  | `dot cl` | Claude Code with context injection — use `dot ai claude` |
126
126
  | `dot copilot` | GitHub Copilot CLI — use `dot ai copilot` |
127
+ | `dot kimi` | Kimi CLI — use `dot ai kimi` |
127
128
  | `dot agy` | Antigravity CLI — use `dot ai agy` |
128
129
  | `dot kiro` | Kiro CLI — use `dot ai kiro` |
129
130
  | `dot sgpt` | Shell-GPT — use `dot ai sgpt` |
package/install.sh CHANGED
@@ -71,7 +71,7 @@ show_help() {
71
71
  Usage: install.sh [version] [options]
72
72
 
73
73
  Arguments:
74
- version The version (tag or branch) to install (default: v0.2.511)
74
+ version The version (tag or branch) to install (default: v0.2.512)
75
75
 
76
76
  Options:
77
77
  --help Show this help message
@@ -87,7 +87,7 @@ EOF
87
87
  }
88
88
 
89
89
  main() {
90
- local version="v0.2.511"
90
+ local version="v0.2.512"
91
91
  local version_set=0
92
92
  local minimal=0
93
93
  local provision="${DOTFILES_PROVISION:-0}"
@@ -117,7 +117,7 @@ main() {
117
117
  # like `foobar` doesn't trigger a 30s+ network download attempt.
118
118
  # Caught by the install.sh fuzz harness (#881).
119
119
  if [[ ! "$arg" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+([-+][a-zA-Z0-9.-]+)?$ ]]; then
120
- error "Unrecognized positional argument '$arg' — expected a semver version (e.g. v0.2.511)."
120
+ error "Unrecognized positional argument '$arg' — expected a semver version (e.g. v0.2.512)."
121
121
  fi
122
122
  version="$arg"
123
123
  version_set=1
@@ -362,7 +362,7 @@ main() {
362
362
  # 6. Initialize & Apply
363
363
  step "Applying Configuration..."
364
364
 
365
- # ── Auto-migration for v0.2.511 reorg ─────────────────────────────────
365
+ # ── Auto-migration for v0.2.512 reorg ─────────────────────────────────
366
366
  # If the user is upgrading from a pre-0.2.503 install, run the
367
367
  # migration script BEFORE `chezmoi apply` so the reorg's source-
368
368
  # path moves don't cause chezmoi to delete deployed files.
@@ -371,7 +371,7 @@ main() {
371
371
  for migrate_src in "$SOURCE_DIR" "$LEGACY_SOURCE_DIR"; do
372
372
  migrate_script="$migrate_src/install/migrate/migrate-v0_2-to-v0_2_503.sh"
373
373
  if [[ -x "$migrate_script" ]]; then
374
- echo " Running v0.2.511 migration (idempotent; safe on fresh installs)..."
374
+ echo " Running v0.2.512 migration (idempotent; safe on fresh installs)..."
375
375
  "$migrate_script" || echo " migration exited non-zero — continuing apply"
376
376
  break
377
377
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebastienrousseau/dotfiles",
3
- "version": "0.2.511",
3
+ "version": "0.2.512",
4
4
  "description": "The Trusted Shell Platform — Universal dotfiles managed by Chezmoi. Features Bash & Zsh for macOS, Linux & WSL. Rust modern tooling & enterprise-grade security.",
5
5
  "main": "install.sh",
6
6
  "bin": {
@@ -6,6 +6,15 @@
6
6
 
7
7
  set -euo pipefail
8
8
 
9
+ usage() {
10
+ cat <<'EOF'
11
+ Usage: aliases-manifest.sh [chezmoi-source-dir]
12
+
13
+ Emit alias definitions as tab-separated rows:
14
+ name<TAB>value<TAB>file<TAB>line
15
+ EOF
16
+ }
17
+
9
18
  resolve_source_dir() {
10
19
  if [[ -n "${CHEZMOI_SOURCE_DIR:-}" && -d "${CHEZMOI_SOURCE_DIR}" ]]; then
11
20
  printf "%s\n" "${CHEZMOI_SOURCE_DIR}"
@@ -39,12 +48,30 @@ resolve_chezmoi_source_dir() {
39
48
  printf "%s\n" "$root"
40
49
  }
41
50
 
51
+ case "${1:-}" in
52
+ -h | --help)
53
+ usage
54
+ exit 0
55
+ ;;
56
+ -*)
57
+ printf 'Unknown option: %s\n' "$1" >&2
58
+ usage >&2
59
+ exit 2
60
+ ;;
61
+ esac
62
+
42
63
  src_root="${1:-$(resolve_source_dir)}"
43
64
  src_dir="$(resolve_chezmoi_source_dir "$src_root")"
44
65
 
45
- rg -n \
46
- -e '^[[:space:]]*alias[[:space:]]+[A-Za-z0-9_.:-]+=' \
47
- -e '^[[:space:]]*[^#"'\'']*&&[[:space:]]*alias[[:space:]]+[A-Za-z0-9_.:-]+=' \
48
- "$src_dir/.chezmoitemplates/aliases" \
49
- "$src_dir/.chezmoitemplates/functions" |
50
- sed -E 's#^([^:]+):([0-9]+):.*alias[[:space:]]+([A-Za-z0-9_.:-]+)=(.*)$#\3\t\4\t\1\t\2#'
66
+ alias_pattern='^[[:space:]]*alias[[:space:]]+[A-Za-z0-9_.:-]+='
67
+ conditional_alias_pattern='^[[:space:]]*[^#"'\'']*&&[[:space:]]*alias[[:space:]]+[A-Za-z0-9_.:-]+='
68
+ search_paths=(
69
+ "$src_dir/.chezmoitemplates/aliases"
70
+ "$src_dir/.chezmoitemplates/functions"
71
+ )
72
+
73
+ if command -v rg >/dev/null 2>&1; then
74
+ rg -n -e "$alias_pattern" -e "$conditional_alias_pattern" "${search_paths[@]}"
75
+ else
76
+ grep -rEn -e "$alias_pattern" -e "$conditional_alias_pattern" "${search_paths[@]}"
77
+ fi | sed -E 's#^([^:]+):([0-9]+):.*alias[[:space:]]+([A-Za-z0-9_.:-]+)=(.*)$#\3\t\4\t\1\t\2#'
@@ -56,6 +56,19 @@ export DOT_COMMAND="benchmark"
56
56
  BENCHMARK_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/dotfiles/benchmarks"
57
57
  mkdir -p "$BENCHMARK_DIR"
58
58
 
59
+ usage() {
60
+ cat <<'EOF'
61
+ Usage: dot benchmark [--detailed] [--profile] [--compare] [--waterfall]
62
+
63
+ Options:
64
+ -d, --detailed Show per-component timing before the benchmark
65
+ -p, --profile Run zsh zprof analysis
66
+ -c, --compare Compare recent benchmark history
67
+ -w, --waterfall Show an ASCII component waterfall
68
+ -h, --help Show this help
69
+ EOF
70
+ }
71
+
59
72
  # Parse arguments
60
73
  DETAILED=false
61
74
  PROFILE=false
@@ -79,11 +92,24 @@ while [[ $# -gt 0 ]]; do
79
92
  WATERFALL=true
80
93
  shift
81
94
  ;;
82
- *) shift ;;
95
+ --help | -h)
96
+ usage
97
+ exit 0
98
+ ;;
99
+ *)
100
+ printf 'Unknown option: %s\n' "$1" >&2
101
+ usage >&2
102
+ exit 2
103
+ ;;
83
104
  esac
84
105
  done
85
106
 
86
107
  ui_init
108
+ GREEN="${GREEN:-}"
109
+ YELLOW="${YELLOW:-}"
110
+ RED="${RED:-}"
111
+ CYAN="${CYAN:-}"
112
+ NC="${NC:-}"
87
113
 
88
114
  print_header() {
89
115
  echo ""
@@ -169,7 +169,7 @@ fi
169
169
 
170
170
  # --- AI CLIs ---
171
171
  _section "AI CLIs"
172
- for cmd in claude copilot agy sgpt ollama opencode aider kiro-cli; do
172
+ for cmd in claude copilot kimi agy sgpt ollama opencode aider kiro-cli; do
173
173
  if check_cmd "$cmd"; then
174
174
  _ok "$cmd" "$(pretty_path "$(get_cmd_path "$cmd")")"
175
175
  else
@@ -226,6 +226,9 @@ fi
226
226
 
227
227
  # --- OS-specific detection ---
228
228
  _os="" _host="" _cpu="" _cpu_cores="" _gpu="" _mem="" _resolution="" _packages="" _de=""
229
+ os_release_file="${DOT_DOCTOR_OS_RELEASE:-/etc/os-release}"
230
+ proc_root="${DOT_DOCTOR_PROC_ROOT:-/proc}"
231
+ sys_root="${DOT_DOCTOR_SYS_ROOT:-/sys}"
229
232
 
230
233
  if [[ "$_os_name" == "Darwin" ]]; then
231
234
  # macOS
@@ -243,33 +246,37 @@ if [[ "$_os_name" == "Darwin" ]]; then
243
246
  _packages="$(brew list --formula 2>/dev/null | wc -l | tr -d ' ') (brew)"
244
247
  _de="Aqua"
245
248
 
246
- elif [[ -r /etc/os-release ]]; then
249
+ elif [[ -r "$os_release_file" ]]; then
247
250
  # Linux (Debian, Ubuntu, Arch, Fedora, RHEL, etc.)
248
251
  # shellcheck disable=SC1091
249
- . /etc/os-release
252
+ . "$os_release_file"
250
253
  _os="${PRETTY_NAME:-$ID}"
251
254
 
252
- _host="$(cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null || cat /sys/firmware/devicetree/base/model 2>/dev/null || echo "Linux")"
255
+ _host="$(cat "$sys_root/devices/virtual/dmi/id/product_name" 2>/dev/null || cat "$sys_root/firmware/devicetree/base/model" 2>/dev/null || echo "Linux")"
253
256
 
254
257
  if command -v lscpu >/dev/null 2>&1; then
255
258
  _cpu="$(lscpu | awk -F': +' '/Model name/{print $2}')"
256
259
  _cpu_cores="$(lscpu | awk -F': +' '/^CPU\(s\):/{print $2}')"
257
260
  else
258
- _cpu="$(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ //' || uname -p)"
259
- _cpu_cores="$(grep -c '^processor' /proc/cpuinfo 2>/dev/null || echo "?")"
261
+ _cpu="$(grep -m1 'model name' "$proc_root/cpuinfo" 2>/dev/null | cut -d: -f2 | sed 's/^ //' || uname -p)"
262
+ _cpu_cores="$(grep -c '^processor' "$proc_root/cpuinfo" 2>/dev/null || echo "?")"
260
263
  fi
261
264
 
262
265
  if command -v lspci >/dev/null 2>&1; then
263
- _gpu="$(lspci 2>/dev/null | grep -iE 'vga|3d|display' | head -1 | sed 's/.*: //')"
266
+ # Headless hosts (VMs, containers, CI runners) expose no display
267
+ # controller, so `grep` exits 1 and — under `set -euo pipefail` —
268
+ # would abort the whole report mid-section. Absorb the miss.
269
+ _gpu="$(lspci 2>/dev/null | grep -iE 'vga|3d|display' | head -1 | sed 's/.*: //' || true)"
270
+ _gpu="${_gpu:-n/a}"
264
271
  else
265
272
  _gpu="n/a"
266
273
  fi
267
274
 
268
275
  if command -v free >/dev/null 2>&1; then
269
276
  _mem="$(free -b | awk '/Mem:/{printf "%.2f GiB / %.2f GiB", $3/1073741824, $2/1073741824}')"
270
- elif [[ -r /proc/meminfo ]]; then
271
- _mem_total_kb="$(awk '/MemTotal/{print $2}' /proc/meminfo)"
272
- _mem_avail_kb="$(awk '/MemAvailable/{print $2}' /proc/meminfo)"
277
+ elif [[ -r "$proc_root/meminfo" ]]; then
278
+ _mem_total_kb="$(awk '/MemTotal/{print $2}' "$proc_root/meminfo")"
279
+ _mem_avail_kb="$(awk '/MemAvailable/{print $2}' "$proc_root/meminfo")"
273
280
  _mem_used_kb=$((_mem_total_kb - _mem_avail_kb))
274
281
  _mem="$(awk "BEGIN{printf \"%.2f GiB / %.2f GiB\", ${_mem_used_kb}/1048576, ${_mem_total_kb}/1048576}")"
275
282
  else
@@ -319,7 +326,7 @@ fi
319
326
 
320
327
  # WSL detection and overrides
321
328
  _wsl=""
322
- if [[ -f /proc/version ]] && grep -qi microsoft /proc/version 2>/dev/null; then
329
+ if [[ -f "$proc_root/version" ]] && grep -qi microsoft "$proc_root/version" 2>/dev/null; then
323
330
  _wsl="yes"
324
331
  _os="${_os} (WSL)"
325
332
  _de="Windows Desktop (WSL)"
@@ -198,6 +198,11 @@ check_dotfiles_core() {
198
198
  check_shell_env() {
199
199
  check_section "Shell Environment"
200
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
201
206
 
202
207
  if has_command zsh; then
203
208
  check "Zsh installed" "pass"
@@ -210,12 +215,12 @@ check_shell_env() {
210
215
  check "Zsh installed" "fail"
211
216
  fi
212
217
 
213
- if [[ -d "${ZINIT_HOME:-$HOME/.local/share/zinit}" ]]; then
218
+ if [[ -f "${ZINIT_HOME:-$HOME/.local/share/zinit/zinit.git}/zinit.zsh" ]] || [[ -d "${ZINIT_HOME:-$HOME/.local/share/zinit}" ]]; then
214
219
  check "Zinit plugin manager" "pass"
215
- elif [[ "$current_shell" == "zsh" ]]; then
220
+ elif [[ "$current_shell" == "zsh" && "$default_shell" == "zsh" ]]; then
216
221
  check "Zinit plugin manager" "warn" "Not found"
217
222
  else
218
- check "Zinit plugin manager" "pass" "Not required for $current_shell"
223
+ check "Zinit plugin manager" "pass" "Not required for $default_shell"
219
224
  fi
220
225
 
221
226
  if has_command starship; then
@@ -77,12 +77,14 @@ log_success() {
77
77
  if [[ "$JSON_MODE" -ne 1 ]]; then
78
78
  ui_ok "$1" "${2:-}"
79
79
  fi
80
+ return 0
80
81
  }
81
82
  log_fail() {
82
83
  if [[ "$JSON_MODE" -ne 1 ]]; then
83
84
  ui_err "$1" "${2:-}"
84
85
  fi
85
86
  Errors=$((Errors + 1))
87
+ return 0
86
88
  }
87
89
  log_warn() {
88
90
  if [[ "$JSON_MODE" -ne 1 ]]; then
@@ -91,6 +93,7 @@ log_warn() {
91
93
  Warnings=$((Warnings + 1))
92
94
  # In strict mode, warnings become errors
93
95
  [[ "$STRICT_MODE" -eq 1 ]] && Errors=$((Errors + 1))
96
+ return 0
94
97
  }
95
98
 
96
99
  MCP_CONFIG="${MCP_CONFIG:-$HOME/.config/claude/mcp_servers.json}"
@@ -13,7 +13,13 @@ STRICT="${DOTFILES_ALIAS_STRICT_MODE:-${DOTFILES_SECRETS_STRICT_MODE:-0}}"
13
13
 
14
14
  cd "$REPO_ROOT"
15
15
 
16
- mapfile -t staged_files < <(git diff --cached --name-only --diff-filter=ACM || true)
16
+ # Portable read `mapfile` is bash 4 only, and this runs from the
17
+ # pre-commit hook on macOS where /bin/bash is 3.2. Without this the
18
+ # hook exits 127 and the secret scan is skipped entirely.
19
+ staged_files=()
20
+ while IFS= read -r _line; do
21
+ [[ -n "$_line" ]] && staged_files+=("$_line")
22
+ done < <(git diff --cached --name-only --diff-filter=ACM || true)
17
23
  if [[ "${#staged_files[@]}" -eq 0 ]]; then
18
24
  echo "Secret governance: no staged files."
19
25
  exit 0
@@ -171,13 +171,20 @@ check_encryption() {
171
171
  add_points "encryption" 0 5 "SOPS secrets manager"
172
172
  fi
173
173
 
174
- # GPG available
174
+ # Signing key material: this repo uses SSH ED25519 signing by default, with
175
+ # GPG still accepted for users who prefer it.
176
+ local signing_format signing_key
177
+ signing_format="$(git config --global gpg.format 2>/dev/null || true)"
178
+ signing_key="$(git config --global user.signingkey 2>/dev/null || true)"
179
+ signing_key="${signing_key/#\~/$HOME}"
175
180
  if command -v gpg >/dev/null 2>&1 && gpg --list-secret-keys 2>/dev/null | grep -q sec; then
176
- add_points "encryption" 10 10 "GPG keys configured"
181
+ add_points "encryption" 10 10 "Signing key configured (GPG)"
182
+ elif [[ "$signing_format" == "ssh" && -n "$signing_key" && -f "$signing_key" ]]; then
183
+ add_points "encryption" 10 10 "Signing key configured (SSH)"
177
184
  elif command -v gpg >/dev/null 2>&1; then
178
- add_points "encryption" 3 10 "GPG keys configured"
185
+ add_points "encryption" 3 10 "Signing key configured"
179
186
  else
180
- add_points "encryption" 0 10 "GPG keys configured"
187
+ add_points "encryption" 0 10 "Signing key configured"
181
188
  fi
182
189
  }
183
190
 
@@ -286,6 +293,8 @@ check_system() {
286
293
  if [[ "$(uname)" == "Darwin" ]]; then
287
294
  if fdesetup status 2>/dev/null | grep -q "FileVault is On"; then
288
295
  add_points "system" 10 10 "Disk encryption (FileVault)"
296
+ elif diskutil apfs list 2>/dev/null | grep -q "FileVault:[[:space:]]*Yes"; then
297
+ add_points "system" 10 10 "Disk encryption (APFS FileVault)"
289
298
  else
290
299
  add_points "system" 0 10 "Disk encryption (FileVault)"
291
300
  fi
@@ -323,7 +332,7 @@ check_secrets() {
323
332
  local secrets_found=false
324
333
  local match=""
325
334
  # Check for common secret patterns, ignore templates/placeholders and variable expansions.
326
- match=$(grep -rE "(api_key|api_secret|password|token)[[:space:]]*=[[:space:]]*['\"][^'\"]+['\"]" \
335
+ match=$(grep -rE "^[[:space:]]*(export[[:space:]]+)?[A-Za-z_]*(api_key|api_secret|password|token)[A-Za-z_]*[[:space:]]*=[[:space:]]*['\"][^'\"]+['\"]" \
327
336
  "${HOME}/.dotfiles" --include="*.sh" --include="*.zsh" --include="*.toml" 2>/dev/null |
328
337
  grep -v "example\\|template\\|placeholder" | grep -F -v "\${" | head -1 || true)
329
338
  if [[ -n "$match" ]]; then
@@ -12,6 +12,8 @@ set -euo pipefail
12
12
  echo " Starting Final Environment Verification..."
13
13
 
14
14
  Errors=0
15
+ ALIASES_CONFIG="$HOME/.config/shell/aliases.sh"
16
+ AliasesConfigReported=0
15
17
 
16
18
  check_file() {
17
19
  if [[ ! -f "$1" ]]; then
@@ -23,7 +25,13 @@ check_file() {
23
25
  }
24
26
 
25
27
  check_alias_in_config() {
26
- if ! grep -q "$1" "$HOME/.config/shell/aliases.sh"; then
28
+ if [[ ! -f "$ALIASES_CONFIG" ]]; then
29
+ if [[ "$AliasesConfigReported" -eq 0 ]]; then
30
+ echo " Missing aliases config: $ALIASES_CONFIG"
31
+ Errors=$((Errors + 1))
32
+ AliasesConfigReported=1
33
+ fi
34
+ elif ! grep -q "$1" "$ALIASES_CONFIG"; then
27
35
  echo " Missing alias definition '$1' in built config"
28
36
  Errors=$((Errors + 1))
29
37
  else