@sebastienrousseau/dotfiles 0.2.500 → 0.2.501

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 (204) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +82 -44
  3. package/docs/.vitepress/reports/localization-readability-audit.md +4 -0
  4. package/docs/AI.md +8 -2
  5. package/docs/CNAME +1 -0
  6. package/docs/COPYRIGHT +1 -1
  7. package/docs/NAMING_CONVENTIONS.md +7 -0
  8. package/docs/README.md +4 -0
  9. package/docs/_config.yml +59 -0
  10. package/docs/adr/ADR-001-ci-cd-pipeline.md +17 -0
  11. package/docs/adr/ADR-002-shell-performance.md +9 -0
  12. package/docs/adr/ADR-003-security-first.md +18 -0
  13. package/docs/adr/ADR-004-cli-architecture.md +14 -0
  14. package/docs/adr/ADR-005-chezmoi-choice.md +10 -0
  15. package/docs/adr/ADR-006-shell-selection.md +9 -0
  16. package/docs/adr/ADR-007-multi-shell-parity.md +10 -1
  17. package/docs/adr/ADR-008-alias-system-architecture.md +10 -0
  18. package/docs/adr/ADR-009-wallpaper-driven-theming.md +131 -0
  19. package/docs/adr/ADR-010-starship-transient-prompt.md +144 -0
  20. package/docs/adr/ADR-011-nushell-tier3-keep.md +144 -0
  21. package/docs/adr/README.md +7 -0
  22. package/docs/architecture/ARCHITECTURE.md +4 -0
  23. package/docs/architecture/INTEROP.md +8 -0
  24. package/docs/architecture/REPO_LAYOUT.md +5 -1
  25. package/docs/architecture/WALKTHROUGH.md +4 -0
  26. package/docs/architecture/fleet-deployment.md +4 -0
  27. package/docs/archive/EUXIS_2026_REVIEW.md +11 -3
  28. package/docs/archive/LEGACY_ROADMAP.md +45 -27
  29. package/docs/archive/MILESTONE_v0.2.493.md +4 -0
  30. package/docs/archive/PLAN.md +46 -8
  31. package/docs/archive/REPO_AUDIT.md +8 -0
  32. package/docs/guides/INSTALL.md +4 -0
  33. package/docs/guides/NEOVIM_IDE_GUIDE.md +9 -0
  34. package/docs/guides/THEMING.md +8 -0
  35. package/docs/guides/TROUBLESHOOTING.md +28 -0
  36. package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +70 -1
  37. package/docs/index.md +6 -2
  38. package/docs/interop/A2A.md +7 -0
  39. package/docs/interop/POWERSHELL.md +102 -0
  40. package/docs/manual/00-introduction.md +5 -1
  41. package/docs/manual/01-concepts/01-architecture.md +4 -0
  42. package/docs/manual/01-concepts/02-trust-model.md +6 -2
  43. package/docs/manual/01-concepts/03-theme-engine.md +4 -0
  44. package/docs/manual/01-concepts/04-fleet.md +7 -1
  45. package/docs/manual/01-concepts/05-self-healing.md +8 -1
  46. package/docs/manual/02-tutorials/01-first-install.md +5 -0
  47. package/docs/manual/02-tutorials/02-add-wallpaper.md +5 -0
  48. package/docs/manual/02-tutorials/03-create-profile.md +6 -0
  49. package/docs/manual/02-tutorials/04-encrypt-secret.md +6 -0
  50. package/docs/manual/02-tutorials/05-deploy-fleet.md +5 -1
  51. package/docs/manual/03-reference/01-dot-cli.md +4 -0
  52. package/docs/manual/03-reference/02-config-files.md +8 -2
  53. package/docs/manual/03-reference/03-environment.md +4 -0
  54. package/docs/manual/03-reference/04-templates.md +7 -1
  55. package/docs/manual/03-reference/05-feature-flags.md +10 -0
  56. package/docs/manual/04-cookbook/01-recipes.md +4 -0
  57. package/docs/manual/04-cookbook/02-troubleshooting.md +32 -0
  58. package/docs/manual/04-cookbook/03-faq.md +8 -0
  59. package/docs/manual/05-appendices/A-platform-matrix.md +4 -0
  60. package/docs/manual/05-appendices/B-security-checklist.md +6 -0
  61. package/docs/manual/05-appendices/C-glossary.md +4 -0
  62. package/docs/manual/05-appendices/D-bibliography.md +5 -1
  63. package/docs/manual/05-appendices/E-license.md +4 -0
  64. package/docs/manual/_toc.yml +1 -1
  65. package/docs/manual/command-index.md +4 -0
  66. package/docs/manual/concept-index.md +4 -0
  67. package/docs/operations/ATTESTATION.md +5 -0
  68. package/docs/operations/CI_CADENCE.md +107 -0
  69. package/docs/operations/CI_COMPOSITES.md +156 -0
  70. package/docs/operations/COMPLETIONS.md +123 -0
  71. package/docs/operations/COVERAGE.md +148 -0
  72. package/docs/operations/DRIFT.md +107 -0
  73. package/docs/operations/MAINTENANCE.md +5 -1
  74. package/docs/operations/MIGRATION.md +14 -6
  75. package/docs/operations/OPERATIONS.md +24 -0
  76. package/docs/operations/PERFORMANCE.md +133 -0
  77. package/docs/operations/RELIABILITY.md +6 -0
  78. package/docs/operations/ROADMAP.md +36 -18
  79. package/docs/operations/TESTING.md +4 -0
  80. package/docs/operations/TRACEABILITY.md +4 -0
  81. package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +4 -0
  82. package/docs/operations/VERSION_SYNC.md +54 -5
  83. package/docs/reference/ALIASES.md +7 -0
  84. package/docs/reference/ALIASES_CHEATSHEET.md +5 -1
  85. package/docs/reference/ALIASES_DEPRECATIONS.md +5 -1
  86. package/docs/reference/FEATURES.md +4 -0
  87. package/docs/reference/FONTS.md +4 -0
  88. package/docs/reference/PROFILES.md +4 -0
  89. package/docs/reference/SCREENSHOTS.md +4 -0
  90. package/docs/reference/SCRIPTS.md +4 -0
  91. package/docs/reference/SUPPORT_MATRIX.md +10 -4
  92. package/docs/reference/THEMES.md +4 -0
  93. package/docs/reference/TOOLS.md +4 -0
  94. package/docs/reference/UTILS.md +16 -12
  95. package/docs/security/AI_ACT_COMPLIANCE.md +4 -0
  96. package/docs/security/AUDIT_BYPASS.md +103 -0
  97. package/docs/security/AUTOMATION_SECRETS.md +4 -0
  98. package/docs/security/CI_EGRESS_ALLOWLIST.md +127 -0
  99. package/docs/security/COMPLIANCE.md +5 -0
  100. package/docs/security/DEPS_DEV_EXCEPTIONS.md +86 -0
  101. package/docs/security/ENCRYPTION.md +5 -0
  102. package/docs/security/FMEA.md +4 -0
  103. package/docs/security/HISTORY_FILTERING.md +132 -0
  104. package/docs/security/INCIDENT_RESPONSE.md +4 -0
  105. package/docs/security/INSTALL_VERIFICATION.md +122 -0
  106. package/docs/security/KEYS.md +4 -0
  107. package/docs/security/KEY_ROTATION.md +4 -0
  108. package/docs/security/MCP_POLICY.md +9 -0
  109. package/docs/security/POLICY_RELEASES.md +4 -0
  110. package/docs/security/README.md +4 -0
  111. package/docs/security/SCORECARD.md +80 -0
  112. package/docs/security/SECRETS.md +12 -0
  113. package/docs/security/SECURITY.md +4 -0
  114. package/docs/security/SECURITY_CHECKLIST.md +11 -0
  115. package/docs/security/SHELL_EXEMPTIONS.md +145 -0
  116. package/docs/security/SOUP_REGISTER.md +4 -0
  117. package/docs/security/THREAT_MODEL.md +10 -0
  118. package/docs/security/VERIFICATION_VALIDATION.md +5 -1
  119. package/docs/themes/README.md +4 -0
  120. package/docs/themes/VISUAL_INTEGRITY_REPORT.md +4 -0
  121. package/dot_config/ai/identity.md +3 -0
  122. package/dot_config/ai/patterns/architect.md +2 -0
  123. package/dot_config/ai/patterns/hardener.md +2 -0
  124. package/dot_config/ai/patterns/refactor.md +2 -0
  125. package/dot_config/alacritty/alacritty.toml.tmpl +3 -3
  126. package/dot_config/atuin/config.toml.tmpl +47 -0
  127. package/dot_config/dotfiles/agent-card.json +1 -1
  128. package/dot_config/dotfiles/boot/README.md +2 -0
  129. package/dot_config/dotfiles/grub/README.md +2 -0
  130. package/dot_config/dotfiles/lock/README.md +2 -0
  131. package/dot_config/fish/conf.d/init.fish.tmpl +21 -0
  132. package/dot_config/fish/functions/_cached_eval.fish +84 -11
  133. package/dot_config/fish/functions/_cached_eval_clear.fish +17 -0
  134. package/dot_config/foot/foot.ini.tmpl +3 -3
  135. package/dot_config/fuzzel/fuzzel.ini.tmpl +2 -2
  136. package/dot_config/ghostty/config.tmpl +3 -3
  137. package/dot_config/git/hooks/executable_commit-msg +146 -0
  138. package/dot_config/goose/config.yaml +2 -2
  139. package/dot_config/gtk-3.0/gtk.css.tmpl +2 -2
  140. package/dot_config/gtk-3.0/settings.ini.tmpl +2 -2
  141. package/dot_config/gtk-4.0/gtk.css.tmpl +2 -2
  142. package/dot_config/gtk-4.0/settings.ini.tmpl +2 -2
  143. package/dot_config/kitty/kitty.conf.tmpl +3 -3
  144. package/dot_config/mise/config.toml +1 -1
  145. package/dot_config/niri/config.kdl.tmpl +2 -2
  146. package/dot_config/nushell/cached_eval.nu +80 -0
  147. package/dot_config/nushell/env.nu.tmpl +21 -13
  148. package/dot_config/shell/00-core-paths.sh.tmpl +1 -0
  149. package/dot_config/shell/05-core-safety.sh +1 -0
  150. package/dot_config/shell/10-secrets.sh +1 -0
  151. package/dot_config/shell/40-fzf-defaults.sh.tmpl +1 -0
  152. package/dot_config/shell/40-ls-colors.sh +1 -0
  153. package/dot_config/shell/50-logic-functions-core.sh.tmpl +1 -0
  154. package/dot_config/shell/50-logic-functions.sh.tmpl +1 -0
  155. package/dot_config/shell/51-logic-functions-extra.sh.tmpl +1 -0
  156. package/dot_config/shell/90-ux-aliases.sh.tmpl +1 -0
  157. package/dot_config/shell/91-ux-aliases-lazy.sh.tmpl +1 -0
  158. package/dot_config/shell/README.md +25 -8
  159. package/dot_config/starship.toml.tmpl +2 -2
  160. package/dot_config/tmux/tmux.conf.tmpl +3 -3
  161. package/dot_config/user-dirs.dirs +1 -0
  162. package/dot_config/vscode/settings.json.tmpl +2 -2
  163. package/dot_config/waybar/config.jsonc.tmpl +2 -2
  164. package/dot_config/waybar/style.css.tmpl +2 -2
  165. package/dot_config/wezterm/wezterm.lua.tmpl +3 -3
  166. package/dot_config/zsh/dot_zshrc.tmpl +154 -17
  167. package/dot_config/zsh/rc.d/00-alias-shims.zsh +28 -6
  168. package/dot_config/zsh/rc.d/30-options.zsh.tmpl +26 -6
  169. package/dot_local/bin/executable_bm +2 -0
  170. package/dot_local/bin/executable_dot +9 -2
  171. package/dot_local/bin/executable_dot-load-benchmark +1 -1
  172. package/dot_local/bin/executable_notify +2 -0
  173. package/dot_local/bin/executable_open +2 -0
  174. package/dot_local/bin/executable_tour +4 -2
  175. package/dot_local/bin/executable_up +3 -1
  176. package/install.sh +12 -4
  177. package/package.json +1 -1
  178. package/scripts/ci/check-dangerous-chmod.sh +19 -0
  179. package/scripts/ci/check-deps-dev.sh +236 -0
  180. package/scripts/ci/check-insecure-tls.sh +61 -0
  181. package/scripts/ci/check-regression-traceability.sh +67 -0
  182. package/scripts/ci/check-shell-preamble.sh +106 -0
  183. package/scripts/ci/run-coverage.sh +362 -0
  184. package/scripts/ci/validate-chezmoidata.sh +25 -0
  185. package/scripts/diagnostics/doctor.sh +173 -5
  186. package/scripts/diagnostics/drift-dashboard.sh +177 -13
  187. package/scripts/diagnostics/health.sh +21 -4
  188. package/scripts/diagnostics/perf.sh +304 -77
  189. package/scripts/diagnostics/workstation-attestation.sh +6 -1
  190. package/scripts/dot/commands/agent.sh +14 -5
  191. package/scripts/dot/commands/ai.sh +75 -10
  192. package/scripts/dot/lib/bento.sh +2 -1
  193. package/scripts/dot/lib/log.sh +6 -0
  194. package/scripts/dot/lib/platform.sh +1 -0
  195. package/scripts/dot/lib/ui.sh +11 -0
  196. package/scripts/dot/lib/utils.sh +5 -0
  197. package/scripts/git-hooks/pre-commit-audit.sh +1 -1
  198. package/scripts/git-hooks/pre-push +66 -3
  199. package/scripts/ops/heal-chezmoi.sh +41 -6
  200. package/scripts/qa/powershell-contract.ps1 +95 -0
  201. package/scripts/theme/merge-wallpaper.sh +4 -0
  202. package/scripts/theme/switch.sh +20 -10
  203. package/dot_config/atuin/config.toml +0 -40
  204. package/dot_local/bin/__pycache__/executable_dot-load-benchmark-ptycpython-312.pyc +0 -0
@@ -9,6 +9,9 @@ set -euo pipefail
9
9
 
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_ROOT="${REPO_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
12
+ # Export so child processes (the mcp-doctor subprocess below) inherit it
13
+ # without the env-prefix dance that confuses shellcheck (SC2097/SC2098).
14
+ export REPO_ROOT
12
15
 
13
16
  # shellcheck source=../dot/lib/ui.sh
14
17
  source "$SCRIPT_DIR/../dot/lib/ui.sh"
@@ -91,7 +94,9 @@ if [[ -z "$current_profile" ]] && [[ -f "$agent_profile_file" ]]; then
91
94
  current_profile="$(jq -r '.defaultProfile // "ask"' "$agent_profile_file")"
92
95
  fi
93
96
 
94
- mcp_summary="$(REPO_ROOT="$REPO_ROOT" MCP_CONFIG="$REPO_ROOT/dot_config/claude/mcp_servers.json" bash "$REPO_ROOT/scripts/diagnostics/mcp-doctor.sh" --strict --json)"
97
+ MCP_CONFIG="$REPO_ROOT/dot_config/claude/mcp_servers.json"
98
+ export MCP_CONFIG
99
+ mcp_summary="$(bash "$REPO_ROOT/scripts/diagnostics/mcp-doctor.sh" --strict --json)"
95
100
 
96
101
  attestation_json="$(
97
102
  jq -n \
@@ -76,11 +76,20 @@ _agent_checkpoint_file() {
76
76
  _agent_apply_profile_env() {
77
77
  local name="$1"
78
78
  export DOT_AGENT_PROFILE="$name"
79
- export DOT_AGENT_APPROVAL="$(_agent_profile_field "$name" "approval")"
80
- export DOT_AGENT_FILESYSTEM="$(_agent_profile_field "$name" "filesystem")"
81
- export DOT_AGENT_NETWORK="$(_agent_profile_field "$name" "network")"
82
- export DOT_AGENT_MCP_PROFILE="$(_agent_profile_field "$name" "mcpProfile")"
83
- export DOT_AGENT_MAX_STEPS="$(_agent_profile_field "$name" "maxSteps")"
79
+ # Split declare-and-assign to avoid masking the field-getter's exit
80
+ # code (SC2155). If the profile JSON is malformed, the assignment
81
+ # now fails the function instead of silently exporting an empty value.
82
+ local approval filesystem network mcp_profile max_steps
83
+ approval="$(_agent_profile_field "$name" "approval")"
84
+ filesystem="$(_agent_profile_field "$name" "filesystem")"
85
+ network="$(_agent_profile_field "$name" "network")"
86
+ mcp_profile="$(_agent_profile_field "$name" "mcpProfile")"
87
+ max_steps="$(_agent_profile_field "$name" "maxSteps")"
88
+ export DOT_AGENT_APPROVAL="$approval"
89
+ export DOT_AGENT_FILESYSTEM="$filesystem"
90
+ export DOT_AGENT_NETWORK="$network"
91
+ export DOT_AGENT_MCP_PROFILE="$mcp_profile"
92
+ export DOT_AGENT_MAX_STEPS="$max_steps"
84
93
  }
85
94
 
86
95
  _agent_rbac_enforcement() {
@@ -28,9 +28,10 @@ if [[ ! -d "$PATTERN_DIR" ]]; then
28
28
  fi
29
29
 
30
30
  _show_ai_bridge_usage() {
31
- echo "Usage: dot cl|copilot|gemini|kiro|autohand|vibe|qwen|zai --pattern [name] \"prompt\""
31
+ echo "Usage: dot cl|codex|copilot|gemini|goose|kiro|autohand|vibe|qwen|zai --pattern [name] \"prompt\""
32
32
  echo ""
33
33
  echo "Available Patterns:"
34
+ # shellcheck disable=SC2012
34
35
  ls -1 "$PATTERN_DIR" 2>/dev/null | sed 's/\.md$//' | sed 's/^/ - /' || echo " (none)"
35
36
  }
36
37
 
@@ -57,18 +58,72 @@ _ai_refresh_status_cache() {
57
58
  tmp_file="$(mktemp)"
58
59
  mkdir -p "$AI_CACHE_DIR"
59
60
 
60
- local entry category role name bin desc present version
61
+ local total=${#ai_entries[@]}
62
+
63
+ # Cold-cache refresh runs `$bin --version` for every tool — node-
64
+ # based ones are slow to start, so the total can hit 15-30s. Show a
65
+ # spinner so the user has feedback.
66
+ ui_spinner_start "Probing $total AI tools (cached for ${AI_STATUS_TTL}s)"
67
+
68
+ local jobs="${DOTFILES_AI_PROBE_JOBS:-$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
69
+ local probe_dir
70
+ probe_dir="$(mktemp -d)"
71
+
72
+ # Probe via xargs -P. The probe logic lives INLINE in the bash -c
73
+ # string rather than as an exported function, because `export -f`
74
+ # doesn't always survive across bash invocations on every platform
75
+ # (notably macOS bash 3.2 needs the BASH_FUNC_*() env-var format,
76
+ # which subtly breaks for some shells in PATH). Inlining sidesteps
77
+ # the inheritance question entirely.
78
+ local i=0
79
+ local entry
80
+ local indexed=()
61
81
  for entry in "${ai_entries[@]}"; do
62
- IFS='|' read -r category role name bin desc <<<"$entry"
63
- if has_command "$bin"; then
64
- present=1
65
- version=$(_ai_extract_version "$bin")
82
+ indexed+=("$i|$entry")
83
+ i=$((i + 1))
84
+ done
85
+ # shellcheck disable=SC2016
86
+ local probe_script='
87
+ payload="$1"
88
+ out_dir="$2"
89
+ i="${payload%%|*}"
90
+ entry="${payload#*|}"
91
+ IFS="|" read -r category role name bin desc <<<"$entry"
92
+ if command -v "$bin" >/dev/null 2>&1; then
93
+ output=$("$bin" --version 2>/dev/null | head -1) || true
94
+ version=$(printf "%s" "$output" | sed "s/^[^0-9]*//" | sed "s/[[:space:]]*$//" | sed "s/\.$//")
95
+ printf "%s\t1\t%s\n" "$bin" "$version" >"$out_dir/$i"
66
96
  else
67
- present=0
68
- version=""
97
+ printf "%s\t0\t\n" "$bin" >"$out_dir/$i"
69
98
  fi
70
- printf '%s\t%s\t%s\n' "$bin" "$present" "$version" >>"$tmp_file"
99
+ '
100
+ # NOTE: `-I{}` already implies one input line per invocation. Adding
101
+ # `-n1` on top triggers a BSD-xargs quirk where the input line is
102
+ # word-split on whitespace ("0|Agents (autonomous)|..." → multiple
103
+ # entries). Use only `-I{}`.
104
+ #
105
+ # ALSO: feed null-delimited records (`-0`) so apostrophes and
106
+ # other quote-like characters in the descriptions ("Block's coding
107
+ # agent") don't trigger xargs's "unterminated quote" parser.
108
+ printf '%s\0' "${indexed[@]}" |
109
+ xargs -0 -I{} -P"$jobs" \
110
+ bash -c "$probe_script" _ {} "$probe_dir" \
111
+ 2>/dev/null || true
112
+
113
+ # Re-assemble in original entry order.
114
+ local n
115
+ for ((n = 0; n < i; n++)); do
116
+ [[ -f "$probe_dir/$n" ]] && cat "$probe_dir/$n" >>"$tmp_file"
71
117
  done
118
+ rm -rf "$probe_dir"
119
+
120
+ # Guard with `|| true` because ui_spinner_stop's last line evaluates
121
+ # to rc=1 when stdout is a TTY (the `[[ ! -t 1 ]] && printf` short-
122
+ # circuit). Under `set -euo pipefail` that rc would kill the script
123
+ # right before we get to write the cache, leaving the user with a
124
+ # silent broken cold-cache run. Defence in depth — the function
125
+ # now also has an explicit `return 0` upstream.
126
+ ui_spinner_stop || true
72
127
 
73
128
  mv "$tmp_file" "$AI_STATUS_CACHE_FILE"
74
129
  }
@@ -81,7 +136,9 @@ _ai_get_cached_status() {
81
136
  _ai_mise_pkg() {
82
137
  case "$1" in
83
138
  claude) echo "npm:@anthropic-ai/claude-code" ;;
139
+ codex) echo "npm:@openai/codex" ;;
84
140
  copilot) echo "npm:@github/copilot" ;;
141
+ goose) echo "pipx:goose-ai" ;;
85
142
  aider) echo "pipx:aider-chat" ;;
86
143
  opencode) echo "npm:opencode-ai" ;;
87
144
  sgpt) echo "pipx:shell-gpt" ;;
@@ -102,7 +159,9 @@ cmd_ai_status() {
102
159
  # category|role|name|binary|description
103
160
  local -a ai_clis=(
104
161
  "Agents (autonomous)|agent|Claude Code|claude|Anthropic CLI agent"
162
+ "Agents (autonomous)|agent|Codex CLI|codex|OpenAI Codex agent"
105
163
  "Agents (autonomous)|agent|Copilot CLI|copilot|GitHub Copilot CLI"
164
+ "Agents (autonomous)|agent|Goose|goose|Block's coding agent"
106
165
  "Coding (interactive)|coding|Aider|aider|AI pair programmer"
107
166
  "Coding (interactive)|coding|OpenCode|opencode|Terminal coding assistant"
108
167
  "Coding (interactive)|coding|Autohand Code|autohand|Autohand coding agent"
@@ -350,12 +409,18 @@ ${prompt}"
350
409
  cl | claude)
351
410
  printf "%s" "$full_prompt" | claude
352
411
  ;;
412
+ codex)
413
+ printf "%s" "$full_prompt" | codex
414
+ ;;
353
415
  copilot)
354
416
  copilot -sp "$full_prompt"
355
417
  ;;
356
418
  gemini)
357
419
  printf "%s" "$full_prompt" | gemini chat
358
420
  ;;
421
+ goose)
422
+ printf "%s" "$full_prompt" | goose session start
423
+ ;;
359
424
  kiro | kiro-cli)
360
425
  printf "%s" "$full_prompt" | kiro-cli chat
361
426
  ;;
@@ -404,7 +469,7 @@ case "${1:-}" in
404
469
  shift
405
470
  cmd_ai_query "$@"
406
471
  ;;
407
- cl | claude | copilot | gemini | kiro | sgpt | ollama | opencode | aider | autohand | vibe | qwen | zai)
472
+ cl | claude | codex | copilot | gemini | goose | kiro | sgpt | ollama | opencode | aider | autohand | vibe | qwen | zai)
408
473
  tool="$1"
409
474
  shift
410
475
  run_ai_with_context "$tool" "$@"
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh and dot_local/bin/executable_dot; inherits set -euo pipefail.
3
4
  # Dotfiles 2026: Atomic Intelligence Surface
4
5
  # High-fidelity, perfectly aligned, and professional.
5
6
 
@@ -30,7 +31,7 @@ _dotfiles_bento_render() {
30
31
 
31
32
  # Render a fixed-width card (42 cols) so output aligns in any terminal width
32
33
  printf "\n"
33
- printf " ${c_cyan}${c_bold}💎 D O T F I L E S${c_reset} ${c_slate}[v0.2.500]${c_reset}\n"
34
+ printf " ${c_cyan}${c_bold}💎 D O T F I L E S${c_reset} ${c_slate}[v0.2.501]${c_reset}\n"
34
35
  printf " ${c_slate}──────────────────────────────────────────${c_reset}\n"
35
36
 
36
37
  # Key system properties at a glance — answers "is my env healthy?" in 1 second
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh and scripts/diagnostics/*; inherits set -euo pipefail.
3
4
  # Structured JSON logging and metrics library.
4
5
  # Source this file to emit machine-readable logs and performance metrics.
5
6
  #
@@ -8,6 +9,11 @@
8
9
  # dot_log info "apply_start" "source=chezmoi"
9
10
  # dot_metric "shell_startup" 142 ms
10
11
 
12
+ # Re-source guard: re-sourcing would mint a new DOT_TRACE_ID and break
13
+ # correlation across modules that already captured the original.
14
+ [[ "${_DOT_LIB_LOG_LOADED:-0}" == "1" ]] && return 0
15
+ _DOT_LIB_LOG_LOADED=1
16
+
11
17
  # Correlation ID for tracing across commands in a single invocation
12
18
  DOT_TRACE_ID="${DOT_TRACE_ID:-$(date +%s%N 2>/dev/null | tail -c 12 || date +%s)}"
13
19
  export DOT_TRACE_ID
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh; inherits set -euo pipefail.
3
4
  # Dotfiles CLI Platform Abstraction
4
5
  # Unified helpers for macOS, Linux, and WSL parity.
5
6
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh, scripts/diagnostics/*, scripts/ops/*; inherits set -euo pipefail.
3
4
  ## Dotfiles CLI UI Component Library — Single Source of Truth.
4
5
  ##
5
6
  ## All CLI output MUST go through these primitives. No raw printf with
@@ -30,6 +31,11 @@
30
31
  ## ui_header "Section Title"
31
32
  ## ui_ok "Operation succeeded"
32
33
 
34
+ # Re-source guard: re-sourcing would zero out the BOLD/RED/etc colour
35
+ # variables that ui_init() populated, breaking already-rendered output.
36
+ [[ "${_DOT_LIB_UI_LOADED:-0}" == "1" ]] && return 0
37
+ _DOT_LIB_UI_LOADED=1
38
+
33
39
  # ═══════════════════════════════════════════════════════════════════════
34
40
  # State — all zeroed before ui_init
35
41
  # ═══════════════════════════════════════════════════════════════════════
@@ -265,7 +271,12 @@ ui_spinner_stop() {
265
271
  fi
266
272
  ui_clear_line
267
273
  ui_show_cursor
274
+ # The newline is only needed when stdout is NOT a TTY. We must return
275
+ # 0 either way — without the explicit `return 0`, the function's exit
276
+ # status comes from the trailing `[[ ! -t 1 ]] && printf` chain, which
277
+ # is rc=1 on a TTY and breaks every caller running under `set -e`.
268
278
  [[ ! -t 1 ]] && printf "\n"
279
+ return 0
269
280
  }
270
281
 
271
282
  # ═══════════════════════════════════════════════════════════════════════
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env bash
2
2
  # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # Sourced by scripts/dot/commands/*.sh and dot_local/bin/executable_dot; inherits set -euo pipefail.
3
4
  # Dotfiles CLI Utilities
4
5
  # Shared functions for dot command modules
5
6
 
7
+ # Re-source guard: cheap short-circuit when sourced from multiple modules.
8
+ [[ "${_DOT_LIB_UTILS_LOADED:-0}" == "1" ]] && return 0
9
+ _DOT_LIB_UTILS_LOADED=1
10
+
6
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
12
  # shellcheck source=ui.sh
8
13
  source "$SCRIPT_DIR/ui.sh"
@@ -140,6 +140,6 @@ if [[ $FAILED -eq 1 ]]; then
140
140
  printf '%b\\n' " (Use --no-verify to bypass if absolutely necessary)"
141
141
  exit 1
142
142
  else
143
- printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.500 standards maintained."
143
+ printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.501 standards maintained."
144
144
  exit 0
145
145
  fi
@@ -1,8 +1,26 @@
1
1
  #!/usr/bin/env bash
2
+ # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # =============================================================================
4
+ # pre-push hook
5
+ #
6
+ # 1. Refuses to push any commit that is not GPG/SSH-signed.
7
+ # 2. Runs `scripts/qa/reliability-audit.sh --quick`. The audit is mandatory
8
+ # by default; explicit per-push bypass requires `DOTFILES_ALLOW_UNSKIPPED_PUSH=1`,
9
+ # and every bypass is logged to `~/.local/share/dotfiles/audit-bypass.log`.
10
+ #
11
+ # The legacy `DOTFILES_SKIP_PRE_PUSH_AUDIT=1` env var (opt-out) is rejected
12
+ # with a migration message. The new variable is intentionally awkwardly
13
+ # named so that setting it requires deliberate intent. See
14
+ # `docs/security/AUDIT_BYPASS.md`.
15
+ # =============================================================================
16
+
2
17
  set -euo pipefail
3
18
 
4
19
  repo_root="$(git rev-parse --show-toplevel)"
5
20
 
21
+ # -----------------------------------------------------------------------------
22
+ # Step 1 — signed-commit enforcement (unchanged)
23
+ # -----------------------------------------------------------------------------
6
24
  while read -r local_ref local_sha remote_ref remote_sha; do
7
25
  [ "$local_sha" = "0000000000000000000000000000000000000000" ] && continue
8
26
 
@@ -18,12 +36,57 @@ while read -r local_ref local_sha remote_ref remote_sha; do
18
36
 
19
37
  for c in $(git rev-list "$range"); do
20
38
  if ! git verify-commit "$c" >/dev/null 2>&1; then
21
- echo "Blocked: unsigned commit $c"
39
+ echo "Blocked: unsigned commit $c" >&2
22
40
  exit 1
23
41
  fi
24
42
  done
25
43
  done
26
44
 
27
- if [ "${DOTFILES_SKIP_PRE_PUSH_AUDIT:-0}" != "1" ]; then
28
- bash "$repo_root/scripts/qa/reliability-audit.sh" --quick
45
+ # -----------------------------------------------------------------------------
46
+ # Step 2 — reject the legacy opt-out variable
47
+ # -----------------------------------------------------------------------------
48
+ if [ "${DOTFILES_SKIP_PRE_PUSH_AUDIT:-}" = "1" ]; then
49
+ cat >&2 <<'EOF'
50
+ ERROR: DOTFILES_SKIP_PRE_PUSH_AUDIT is no longer honored.
51
+
52
+ The pre-push audit was previously opt-out — setting one env var was enough
53
+ to skip it. That made bypass invisible and routine. Effective with #871,
54
+ the policy is fail-closed: the audit always runs unless you explicitly
55
+ authorize a bypass for this single push.
56
+
57
+ To bypass for one push:
58
+ DOTFILES_ALLOW_UNSKIPPED_PUSH=1 git push
59
+
60
+ Every bypass is recorded to ~/.local/share/dotfiles/audit-bypass.log
61
+ and surfaced by `dot doctor` if any are recent.
62
+
63
+ See: docs/security/AUDIT_BYPASS.md
64
+ EOF
65
+ exit 1
29
66
  fi
67
+
68
+ # -----------------------------------------------------------------------------
69
+ # Step 3 — run the audit (or log + skip if explicitly bypassed)
70
+ # -----------------------------------------------------------------------------
71
+ if [ "${DOTFILES_ALLOW_UNSKIPPED_PUSH:-}" = "1" ]; then
72
+ bypass_log_dir="${XDG_STATE_HOME:-$HOME/.local/state}/dotfiles"
73
+ # The audit-bypass log lives under XDG_STATE_HOME (user state — never
74
+ # checked in, never deployed by chezmoi to other locations).
75
+ mkdir -p "$bypass_log_dir"
76
+ bypass_log="$bypass_log_dir/audit-bypass.log"
77
+
78
+ ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
79
+ branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
80
+ remote="$(git remote get-url --push @{upstream} 2>/dev/null ||
81
+ git config --get remote.origin.url 2>/dev/null ||
82
+ echo unknown)"
83
+ reason="${DOTFILES_BYPASS_REASON:-no reason given}"
84
+
85
+ printf '%s\tbranch=%s\tremote=%s\treason=%s\n' \
86
+ "$ts" "$branch" "$remote" "$reason" >>"$bypass_log"
87
+
88
+ echo "WARN: pre-push audit bypassed (logged to $bypass_log)" >&2
89
+ exit 0
90
+ fi
91
+
92
+ bash "$repo_root/scripts/qa/reliability-audit.sh" --quick
@@ -37,15 +37,50 @@ heal_chezmoi_drift() {
37
37
  return 0
38
38
  fi
39
39
 
40
+ # Partition the drift: column 2 is what `chezmoi apply` would fix
41
+ # (destination differs from source). Column 1 is source-only drift
42
+ # (unstaged edits in the chezmoi source tree). Apply can't help with
43
+ # the second case — that needs `git commit` in the source repo.
44
+ local applicable
45
+ local source_only
46
+ applicable=$(printf '%s\n' "$status_output" | awk 'substr($0,2,1)!=" "' | wc -l | tr -d ' ')
47
+ source_only=$(printf '%s\n' "$status_output" | awk 'substr($0,1,1)!=" " && substr($0,2,1)==" "' | wc -l | tr -d ' ')
48
+
40
49
  ISSUES_FOUND=$((ISSUES_FOUND + 1))
41
50
 
42
51
  if [[ "$DRY_RUN" == "1" ]]; then
43
- log_dry "run 'chezmoi apply --force' to re-sync"
44
- else
45
- if _pkg_install "chezmoi re-apply" 0 1 chezmoi apply --force; then
46
- FIXES_APPLIED=$((FIXES_APPLIED + 1))
47
- CHEZMOI_APPLIED=1
48
- persist_log "HEAL: chezmoi apply --force"
52
+ log_dry "run 'chezmoi apply --force' to re-sync ($applicable file(s))"
53
+ return 0
54
+ fi
55
+
56
+ # Skip the apply if every file is source-only drift; nothing to fix.
57
+ if [[ "$applicable" -eq 0 ]]; then
58
+ 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"
59
+ return 0
60
+ fi
61
+
62
+ # Capture apply output so we can surface failure reasons.
63
+ local apply_log
64
+ apply_log=$(mktemp)
65
+ if chezmoi apply --force >"$apply_log" 2>&1; then
66
+ FIXES_APPLIED=$((FIXES_APPLIED + 1))
67
+ CHEZMOI_APPLIED=1
68
+ persist_log "HEAL: chezmoi apply --force"
69
+
70
+ # Verify: did apply actually clean the drift?
71
+ local remaining
72
+ remaining=$(chezmoi status 2>/dev/null | awk 'substr($0,2,1)!=" "' | wc -l | tr -d ' ')
73
+ if [[ "$remaining" -eq 0 ]]; then
74
+ printf ' \033[38;5;42m✓\033[0m chezmoi re-apply %s file(s) synced\n' "$applicable"
75
+ else
76
+ # shellcheck disable=SC2016
77
+ printf ' \033[38;5;220m⚠\033[0m chezmoi re-apply %s applied, %s still drifted — run `chezmoi diff` to inspect\n' \
78
+ "$((applicable - remaining))" "$remaining"
49
79
  fi
80
+ else
81
+ printf ' \033[38;5;196m✗\033[0m chezmoi re-apply failed; see %s\n' "$apply_log"
82
+ tail -5 "$apply_log" | sed 's/^/ /'
83
+ return 1
50
84
  fi
85
+ rm -f "$apply_log"
51
86
  }
@@ -0,0 +1,95 @@
1
+ # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
2
+ #
3
+ # PowerShell parity contract — smoke test for the dotfiles PowerShell
4
+ # profile. Run by the windows-latest CI job (#860). Asserts that:
5
+ #
6
+ # 1. The profile parses + loads without throwing.
7
+ # 2. Core function shims (`dot`, `ll`, `la`, `cat`) are defined.
8
+ # 3. PSScriptAnalyzer reports no errors against the profile (warnings
9
+ # surface but don't fail the gate; tighten later).
10
+ #
11
+ # Exit codes:
12
+ # 0 contract intact.
13
+ # 1 any check failed; details printed to host.
14
+
15
+ $ErrorActionPreference = 'Stop'
16
+ $Failures = New-Object System.Collections.Generic.List[string]
17
+
18
+ $RepoRoot = if ($env:GITHUB_WORKSPACE) { $env:GITHUB_WORKSPACE } else { (Get-Location).Path }
19
+ $ProfileSrc = Join-Path $RepoRoot 'dot_config/powershell/Microsoft.PowerShell_profile.ps1.tmpl'
20
+
21
+ if (-not (Test-Path $ProfileSrc)) {
22
+ Write-Output "FAIL: profile source not found at $ProfileSrc"
23
+ exit 1
24
+ }
25
+
26
+ # Step 1 — chezmoi-render the template into a real .ps1 we can dot-source.
27
+ # In CI, chezmoi is on PATH (installed by setup-chezmoi composite).
28
+ $Rendered = Join-Path $env:TEMP 'Microsoft.PowerShell_profile.ps1'
29
+ if (Get-Command chezmoi -ErrorAction SilentlyContinue) {
30
+ & chezmoi execute-template --init --promptString version=0.2.501 `
31
+ --in $ProfileSrc | Set-Content -Path $Rendered -NoNewline
32
+ } else {
33
+ # Fallback: strip chezmoi template syntax with a simple regex so the
34
+ # contract still runs locally without chezmoi installed.
35
+ (Get-Content $ProfileSrc -Raw) -replace '\{\{[^}]+\}\}', '0.0.0-fallback' |
36
+ Set-Content -Path $Rendered -NoNewline
37
+ }
38
+
39
+ if (-not (Test-Path $Rendered)) {
40
+ $Failures.Add("profile template did not render to $Rendered")
41
+ }
42
+
43
+ # Step 2 — dot-source the rendered profile and verify it didn't throw.
44
+ $loadOk = $false
45
+ try {
46
+ . $Rendered
47
+ $loadOk = $true
48
+ Write-Output "OK: profile dot-sourced"
49
+ } catch {
50
+ Write-Output "FAIL: profile threw during load: $_"
51
+ $Failures.Add("profile load: $_")
52
+ }
53
+
54
+ # Step 3 — verify required function shims are defined.
55
+ $RequiredFunctions = @('dot', 'd', 'll', 'la', 'cat')
56
+ foreach ($fn in $RequiredFunctions) {
57
+ if (Get-Command $fn -CommandType Function -ErrorAction SilentlyContinue) {
58
+ Write-Output "OK: function $fn defined"
59
+ } else {
60
+ Write-Output "FAIL: function $fn not defined"
61
+ $Failures.Add("missing function: $fn")
62
+ }
63
+ }
64
+
65
+ # Step 4 — PSScriptAnalyzer (static analysis). Pre-installed on the
66
+ # windows-latest GitHub-hosted runner; install on demand if missing.
67
+ if (-not (Get-Module -ListAvailable -Name PSScriptAnalyzer)) {
68
+ Write-Output "Installing PSScriptAnalyzer..."
69
+ Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser -ErrorAction SilentlyContinue | Out-Null
70
+ }
71
+
72
+ if (Get-Module -ListAvailable -Name PSScriptAnalyzer) {
73
+ Import-Module PSScriptAnalyzer -Force
74
+ $Findings = Invoke-ScriptAnalyzer -Path $Rendered -Severity 'Error' -ErrorAction SilentlyContinue
75
+ if ($Findings) {
76
+ foreach ($f in $Findings) {
77
+ Write-Output "FAIL: PSScriptAnalyzer error: $($f.RuleName) at line $($f.Line): $($f.Message)"
78
+ $Failures.Add("PSScriptAnalyzer error: $($f.RuleName)")
79
+ }
80
+ } else {
81
+ Write-Output "OK: PSScriptAnalyzer clean (Error severity)"
82
+ }
83
+ } else {
84
+ Write-Output "WARN: PSScriptAnalyzer not available — static analysis skipped"
85
+ }
86
+
87
+ Write-Output ""
88
+ if ($Failures.Count -eq 0) {
89
+ Write-Output "PowerShell contract: PASS"
90
+ exit 0
91
+ } else {
92
+ Write-Output "PowerShell contract: FAIL ($($Failures.Count) issue(s))"
93
+ foreach ($f in $Failures) { Write-Output " - $f" }
94
+ exit 1
95
+ }
@@ -81,6 +81,10 @@ merge_pair() {
81
81
 
82
82
  local tmpdir
83
83
  tmpdir="$(mktemp -d)"
84
+ # Single-quotes prevent the variable expanding at trap-definition time;
85
+ # `$tmpdir` resolves when the trap fires (still scoped to this function
86
+ # because RETURN is per-function).
87
+ # shellcheck disable=SC2064 # intentionally expand $tmpdir at trap time within this function scope
84
88
  trap "rm -rf '$tmpdir'" RETURN
85
89
 
86
90
  # Convert both to JPEG for heif-enc input (it handles JPEG best)
@@ -184,7 +184,7 @@ pick_theme() {
184
184
  fi
185
185
 
186
186
  local current
187
- local current="$(current_theme)"
187
+ current="$(current_theme)"
188
188
 
189
189
  if [[ ! -f "$THEMES_FILE" ]]; then
190
190
  ui_err "Missing" "$THEMES_FILE"
@@ -234,7 +234,8 @@ pick_theme() {
234
234
  }
235
235
 
236
236
  list_themes() {
237
- local current="$(current_theme)"
237
+ local current
238
+ current="$(current_theme)"
238
239
  local current_family="${current%-dark}"
239
240
  [[ "$current_family" != "$current" ]] || current_family="${current%-light}"
240
241
 
@@ -260,7 +261,8 @@ list_themes() {
260
261
 
261
262
  # Toggle between light and dark within the same family, or switch families
262
263
  toggle_theme() {
263
- local current="$(current_theme)"
264
+ local current
265
+ current="$(current_theme)"
264
266
 
265
267
  if is_dark_theme "$current"; then
266
268
  if [[ "$current" == *-dark ]]; then
@@ -279,8 +281,9 @@ toggle_theme() {
279
281
 
280
282
  # Switch to the next wallpaper family while preserving mode.
281
283
  switch_family() {
282
- local current="$(current_theme)"
283
- local family="$(get_theme_family "$current")"
284
+ local current family
285
+ current="$(current_theme)"
286
+ family="$(get_theme_family "$current")"
284
287
  local mode="dark"
285
288
  local families=()
286
289
  local idx=0
@@ -316,8 +319,9 @@ switch_family() {
316
319
 
317
320
  # Show current theme info
318
321
  show_current() {
319
- local current="$(current_theme)"
320
- local family="$(get_theme_family "$current")"
322
+ local current family
323
+ current="$(current_theme)"
324
+ family="$(get_theme_family "$current")"
321
325
  local mode="dark"
322
326
  if ! is_dark_theme "$current" 2>/dev/null; then
323
327
  mode="light"
@@ -338,8 +342,13 @@ sync_theme() {
338
342
  ;;
339
343
  Linux)
340
344
  if command -v gsettings >/dev/null 2>&1; then
341
- # Check GNOME color scheme
342
- local scheme=scheme=$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null | tr -d "'")
345
+ # Check GNOME color scheme. Fixes a long-standing bug where the
346
+ # variable was declared as `local scheme=scheme=$(...)` the
347
+ # extra `scheme=` prefix made the value always start with that
348
+ # literal, so the `prefer-light` test below could never match
349
+ # and the system always fell through to the dark branch.
350
+ local scheme
351
+ scheme=$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null | tr -d "'")
343
352
  if [[ "$scheme" == "prefer-light" ]]; then
344
353
  os_mode="light"
345
354
  else
@@ -349,7 +358,8 @@ sync_theme() {
349
358
  ;;
350
359
  esac
351
360
 
352
- local current="$(current_theme)"
361
+ local current
362
+ current="$(current_theme)"
353
363
  if is_dark_theme "$current" && [[ "$os_mode" == "light" ]]; then
354
364
  ui_info "Sync" "System is light, switching dotfiles to light..."
355
365
  toggle_theme
@@ -1,40 +0,0 @@
1
- # Atuin Configuration (~/.config/atuin/config.toml)
2
- # https://atuin.sh/docs/config
3
-
4
- # Core
5
- update_check = false
6
- db_path = "~/.local/share/atuin/history.db"
7
- key_path = "~/.local/share/atuin/key"
8
- session_path = "~/.local/share/atuin/session"
9
-
10
- # Sync
11
- auto_sync = true
12
- sync_frequency = "10m"
13
- sync_address = "https://api.atuin.sh"
14
-
15
- # UI
16
- style = "compact"
17
- inline_height = 20
18
- show_preview = true
19
- enter_accept = true
20
-
21
- # Search
22
- search_mode = "fuzzy"
23
- filter_mode = "global"
24
- workspaces = true
25
-
26
- # Privacy: skip commands that may contain secrets
27
- history_filter = [
28
- "^export (SECRET|TOKEN|PASSWORD|API_KEY|AWS_)",
29
- "^PASSWORD=",
30
- "^ssh-keygen",
31
- "^(aws|gcloud|az|kubectl).*(configure|auth|login|-k |--kubeconfig)",
32
- "curl.*-H.*[Aa]uthorization",
33
- "git clone.*https://.*:.*@",
34
- "^vault ",
35
- "^op (read|inject|run)",
36
- ]
37
-
38
- # Skip ephemeral directories
39
- secrets_filter = true
40
- network_timeout = 30