repo-nexus 0.5.2 → 0.5.3

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 CHANGED
@@ -5,6 +5,18 @@ All notable changes to Repo Nexus (`rnex`) will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+ - **Explicit `git_hooks` Workspace Configuration (`rnex.yaml` & `.local.rnex.yaml`)**:
12
+ - Top-level `git_hooks: true|false` setting establishes the workspace configuration as the single source of truth for automated Git hooks.
13
+ - Two-level configuration support allowing per-workstation overrides in `.local.rnex.yaml` (e.g. keeping hooks globally enabled in `rnex.yaml` while disabling locally via `rnex hooks uninstall --local`).
14
+ - `rnex hooks install [--local]` and `rnex hooks uninstall [--local]` record preference directly to `rnex.yaml` or `.local.rnex.yaml`.
15
+ - `rnex fix` (and `rnex sync`) automatically reconciles Git's `core.hooksPath` against the resolved `git_hooks` configuration.
16
+ - Interactive `rnex init` determines and records `git_hooks` preference upfront in new workspaces.
17
+ - Workspace schema migration in `rnex update` and `rnex fix -y` non-destructively inserts `git_hooks` into older configurations.
18
+ - `rnex status` and `rnex hooks status` display configuration state alongside runtime Git hooks status.
19
+
8
20
  ## [0.5.1] - 2026-10-08
9
21
 
10
22
  ### Added
package/README.md CHANGED
@@ -245,6 +245,9 @@ The `karpathy-llm` plugin packages Andrej Karpathy's verified LLM agent design p
245
245
  # Directory for member repository clones
246
246
  repos_dir: ./repos
247
247
 
248
+ # Automated workspace Git hooks (default: true)
249
+ git_hooks: true
250
+
248
251
  # Workspace plugins
249
252
  plugins:
250
253
  karpathy-llm: {}
@@ -301,7 +304,7 @@ repos:
301
304
  | `rnex rnex-dir <enable\|disable> <name>` | Toggle `.rnex/` directory integration for a member repository |
302
305
  | `rnex fix [-y] [--quiet]` (or `sync`) | Reconcile workspace repositories, plugins, prompts, and member `.rnex/` directories |
303
306
  | `rnex update [-y]` (or `upgrade`) | Safely upgrade workspace configuration schema and routing instructions |
304
- | `rnex hooks <install\|uninstall\|status>` | Manage config-driven automated Git hooks (`.rnex/hooks`) |
307
+ | `rnex hooks <install\|uninstall\|status> [--local]` | Manage automated Git hooks (`.rnex/hooks` and `git_hooks: true\|false`) |
305
308
  | `rnex plugin <list\|info\|enable\|disable>` | Manage workspace plugins |
306
309
  | `rnex completion <bash\|zsh\|fish>` | Generate shell auto-completion script |
307
310
 
package/docs/CLI.md CHANGED
@@ -316,26 +316,35 @@ rnex rnex-dir <enable|disable> <name>
316
316
 
317
317
  ## Git Hooks Automation Commands
318
318
 
319
- Repo Nexus manages workspace-level Git hooks via `git config core.hooksPath .rnex/hooks`. The hooks are native shell scripts that dynamically evaluate configuration triggers in `rnex.yaml` and `.local.rnex.yaml`.
319
+ Repo Nexus manages workspace-level Git hooks via `git config core.hooksPath .rnex/hooks` and configuration in `rnex.yaml` (`git_hooks: true|false`). The hooks are native shell scripts that dynamically evaluate configuration triggers in `rnex.yaml` and `.local.rnex.yaml`.
320
320
 
321
321
  ```sh
322
- rnex hooks <install|uninstall|status>
322
+ rnex hooks <install|uninstall|status> [--local]
323
323
  ```
324
324
 
325
+ ### Configuration (`rnex.yaml` / `.local.rnex.yaml`)
326
+ ```yaml
327
+ # Enable or disable automated Git hooks
328
+ git_hooks: true # default: true (when in a Git repository)
329
+ ```
330
+ - When `git_hooks: true`, `rnex fix` ensures hooks are installed and up to date.
331
+ - When `git_hooks: false`, `rnex fix` disables and uninstalls hooks from Git.
332
+ - Overrides can be placed in `.local.rnex.yaml` to disable hooks locally without modifying team config.
333
+
325
334
  ### Subcommands
326
335
 
327
- #### `rnex hooks install`
328
- Installs native hook dispatchers into `.rnex/hooks/` and configures Git:
336
+ #### `rnex hooks install [--local]`
337
+ Installs native hook dispatchers into `.rnex/hooks/`, sets `core.hooksPath = .rnex/hooks`, and records `git_hooks: true` in `rnex.yaml` (or `.local.rnex.yaml` if `--local` is passed):
329
338
  - **`post-merge`**: Automatically runs `rnex fix -y --quiet` whenever you run `git pull` or merge upstream changes, ensuring new repositories or plugin additions sync instantly.
330
339
  - **`post-commit`**: Evaluates `lint_trigger: git-post-commit`. If `/raw/` or `/wiki/` files were committed, alerts the user to run maintenance workflows.
331
340
  - **`pre-commit`**: Evaluates `lint_trigger: git-pre-commit`. Validates staged files before committing.
332
341
  - **`pre-push`**: Evaluates `lint_trigger: git-pre-push`. Validates changes before pushing to remote.
333
342
 
334
343
  #### `rnex hooks status`
335
- Displays the active `core.hooksPath`, installed hook scripts, and plugin triggers detected in `rnex.yaml`.
344
+ Displays the configuration setting (`git_hooks: true/false`), active `core.hooksPath`, installed hook scripts, and plugin triggers detected in `rnex.yaml`.
336
345
 
337
- #### `rnex hooks uninstall`
338
- Unsets `core.hooksPath` in Git configuration and removes `.rnex/hooks/`.
346
+ #### `rnex hooks uninstall [--local]`
347
+ Unsets `core.hooksPath` in Git configuration, removes `.rnex/hooks/`, and records `git_hooks: false` in `rnex.yaml` (or `.local.rnex.yaml` if `--local` is passed).
339
348
 
340
349
  ---
341
350
 
@@ -59,6 +59,20 @@ ai_instructions: AGENTS.md
59
59
  #
60
60
  code_workspace: false
61
61
 
62
+ # ------------------------------------------------------------------------------
63
+ # git_hooks — Automated workspace Git hooks
64
+ # ------------------------------------------------------------------------------
65
+ # Enables automated Git hooks in `.rnex/hooks/` (post-merge auto-sync and
66
+ # optional plugin triggers like Karpathy wiki lint on commit/push).
67
+ #
68
+ # Default: true (when initialized in a Git repository)
69
+ #
70
+ # Examples:
71
+ # git_hooks: true # active (core.hooksPath = .rnex/hooks)
72
+ # git_hooks: false # disabled
73
+ #
74
+ git_hooks: true
75
+
62
76
  # ------------------------------------------------------------------------------
63
77
  # plugins — Workspace plugins and AI instruction packs
64
78
  # ------------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repo-nexus",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Lightweight, zero-dependency Virtual Meta-Repo companion for multi-repo workspaces and shared AI context (no git submodules)",
5
5
  "bin": {
6
6
  "repo-nexus": "rnex",
package/rnex CHANGED
@@ -146,6 +146,7 @@ require_workspace() {
146
146
  _load_repos_dir
147
147
  _load_ai_instructions_file
148
148
  _load_code_workspace
149
+ _load_git_hooks
149
150
  log_info "Using workspace at ${_BOLD}$NEXUS_DIR${_NC} ${_DIM}(via config: $WORKSPACE_YAML)${_NC}"
150
151
  return 0
151
152
  fi
@@ -175,6 +176,7 @@ require_workspace() {
175
176
  _load_repos_dir
176
177
  _load_ai_instructions_file
177
178
  _load_code_workspace
179
+ _load_git_hooks
178
180
 
179
181
  log_info "Using workspace at ${_BOLD}$NEXUS_DIR${_NC} ${_DIM}($(basename "$WORKSPACE_YAML") found)${_NC}"
180
182
  }
@@ -254,6 +256,18 @@ _load_code_workspace() {
254
256
  esac
255
257
  }
256
258
 
259
+ _load_git_hooks() {
260
+ _gh=""
261
+ if [ -f "$WORKSPACE_LOCAL_YAML" ]; then
262
+ _gh="$(awk '/^(git_hooks|hooks):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_LOCAL_YAML")"
263
+ fi
264
+ if [ -z "$_gh" ] && [ -f "$WORKSPACE_YAML" ]; then
265
+ _gh="$(awk '/^(git_hooks|hooks):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_YAML")"
266
+ fi
267
+ _gh="$(echo "$_gh" | tr -d " \t\r\n'\"")"
268
+ GIT_HOOKS_CONFIG="$_gh"
269
+ }
270
+
257
271
  # ---- YAML Parser / Manipulator (for rnex.yaml & .local.rnex.yaml) ----------
258
272
 
259
273
  _yaml_list_plugins_from_file() {
@@ -575,6 +589,60 @@ EOF
575
589
  _yaml_set_in_file "$WORKSPACE_LOCAL_YAML" "$_repo" "$_field" "$_value"
576
590
  }
577
591
 
592
+ _yaml_set_top_level_in_file() {
593
+ _file="$1"
594
+ _key="$2"
595
+ _val="$3"
596
+ [ -f "$_file" ] || return 0
597
+ _tmp="$(mktemp)"
598
+ if grep -q "^[ ]*${_key}:" "$_file" 2>/dev/null; then
599
+ awk -v key="$_key" -v val="$_val" '
600
+ $0 ~ ("^[ ]*" key ":") {
601
+ print key ": " val
602
+ next
603
+ }
604
+ { print }
605
+ ' "$_file" > "$_tmp" && mv "$_tmp" "$_file"
606
+ else
607
+ awk -v key="$_key" -v val="$_val" '
608
+ BEGIN { inserted=0 }
609
+ /^[ ]*(plugins|repos):/ && !inserted {
610
+ print key ": " val
611
+ print ""
612
+ inserted=1
613
+ }
614
+ { print }
615
+ END {
616
+ if (!inserted) {
617
+ print ""
618
+ print key ": " val
619
+ }
620
+ }
621
+ ' "$_file" > "$_tmp" && mv "$_tmp" "$_file"
622
+ fi
623
+ rm -f "$_tmp"
624
+ }
625
+
626
+ yaml_set_top_level() {
627
+ _key="$1"; _val="$2"
628
+ _yaml_set_top_level_in_file "$WORKSPACE_YAML" "$_key" "$_val"
629
+ }
630
+
631
+ yaml_set_top_level_local() {
632
+ _key="$1"; _val="$2"
633
+ if [ ! -f "$WORKSPACE_LOCAL_YAML" ]; then
634
+ cat <<'EOF' > "$WORKSPACE_LOCAL_YAML"
635
+ # ==============================================================================
636
+ # .local.rnex.yaml — Repo Nexus Local Configuration (Machine-Specific)
637
+ # ==============================================================================
638
+ # This file is gitignored. Use it to specify local repository paths, overrides,
639
+ # and enable/disable states for this workstation.
640
+
641
+ EOF
642
+ fi
643
+ _yaml_set_top_level_in_file "$WORKSPACE_LOCAL_YAML" "$_key" "$_val"
644
+ }
645
+
578
646
  # ---- Physical Repository Path Resolution ----------------------------------
579
647
 
580
648
  resolve_repo_path() {
@@ -1159,6 +1227,31 @@ upgrade_workspace_config() {
1159
1227
  ' "$_f" > "$_tmp" && mv "$_tmp" "$_f"
1160
1228
  fi
1161
1229
 
1230
+ # 4. Add git_hooks if missing
1231
+ if ! grep -q '^[ ]*\(git_hooks\|hooks\):' "$_f" 2>/dev/null; then
1232
+ _def_gh="false"
1233
+ _cur_hp="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
1234
+ if [ "$_cur_hp" = ".rnex/hooks" ] || [ "$_cur_hp" = "$NEXUS_DIR/.rnex/hooks" ]; then
1235
+ _def_gh="true"
1236
+ fi
1237
+ awk -v def_gh="$_def_gh" '
1238
+ BEGIN { inserted=0 }
1239
+ /^[ ]*(plugins|repos):/ && !inserted {
1240
+ print "# Automated workspace Git hooks (default: true; e.g. post-merge auto-sync, plugin triggers)"
1241
+ print "git_hooks: " def_gh
1242
+ print ""
1243
+ inserted=1
1244
+ }
1245
+ { print }
1246
+ END {
1247
+ if (!inserted) {
1248
+ print ""
1249
+ print "git_hooks: " def_gh
1250
+ }
1251
+ }
1252
+ ' "$_f" > "$_tmp" && mv "$_tmp" "$_f"
1253
+ fi
1254
+
1162
1255
  rm -f "$_tmp"
1163
1256
  }
1164
1257
 
@@ -1212,11 +1305,43 @@ cmd_hooks() {
1212
1305
  case "${1:-status}" in
1213
1306
  install)
1214
1307
  require_workspace
1308
+ _local=0
1309
+ shift || true
1310
+ while [ $# -gt 0 ]; do
1311
+ case "$1" in
1312
+ --local) _local=1 ;;
1313
+ esac
1314
+ shift
1315
+ done
1215
1316
  cmd_hooks_install_dir "$NEXUS_DIR"
1317
+ if [ "$_local" -eq 1 ]; then
1318
+ yaml_set_top_level_local "git_hooks" "true"
1319
+ log_dim "Recorded git_hooks: true in $RNEX_LOCAL_CONFIG_FILE"
1320
+ else
1321
+ yaml_set_top_level "git_hooks" "true"
1322
+ log_dim "Recorded git_hooks: true in $RNEX_CONFIG_FILE"
1323
+ fi
1324
+ _load_git_hooks
1216
1325
  ;;
1217
1326
  uninstall)
1218
1327
  require_workspace
1328
+ _local=0
1329
+ shift || true
1330
+ while [ $# -gt 0 ]; do
1331
+ case "$1" in
1332
+ --local) _local=1 ;;
1333
+ esac
1334
+ shift
1335
+ done
1219
1336
  cmd_hooks_uninstall_dir "$NEXUS_DIR"
1337
+ if [ "$_local" -eq 1 ]; then
1338
+ yaml_set_top_level_local "git_hooks" "false"
1339
+ log_dim "Recorded git_hooks: false in $RNEX_LOCAL_CONFIG_FILE"
1340
+ else
1341
+ yaml_set_top_level "git_hooks" "false"
1342
+ log_dim "Recorded git_hooks: false in $RNEX_CONFIG_FILE"
1343
+ fi
1344
+ _load_git_hooks
1220
1345
  ;;
1221
1346
  status)
1222
1347
  require_workspace
@@ -1224,6 +1349,13 @@ cmd_hooks() {
1224
1349
  printf '=%.0s' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
1225
1350
  printf '\n\n'
1226
1351
 
1352
+ printf ' %b●%b Configuration: ' "$_DIM" "$_NC"
1353
+ case "$GIT_HOOKS_CONFIG" in
1354
+ true|yes|1) printf '%bgit_hooks: true%b %b(enabled in config)%b\n' "$_G" "$_NC" "$_DIM" "$_NC" ;;
1355
+ false|no|0) printf '%bgit_hooks: false%b %b(disabled in config)%b\n' "$_Y" "$_NC" "$_DIM" "$_NC" ;;
1356
+ *) printf '%bnot configured%b %b(defaults to active if git repo)%b\n' "$_DIM" "$_NC" "$_DIM" "$_NC" ;;
1357
+ esac
1358
+
1227
1359
  _hp="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
1228
1360
  if [ "$_hp" = ".rnex/hooks" ] || [ "$_hp" = "$NEXUS_DIR/.rnex/hooks" ]; then
1229
1361
  printf ' %b●%b core.hooksPath: %s %b(active)%b\n' "$_G" "$_NC" "$_hp" "$_DIM" "$_NC"
@@ -1373,6 +1505,29 @@ cmd_init() {
1373
1505
  fi
1374
1506
  mkdir -p "$_target_dir"
1375
1507
 
1508
+ _is_git_ws=0
1509
+ if git -C "$_target_dir" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
1510
+ _is_git_ws=1
1511
+ fi
1512
+
1513
+ _init_git_hooks="false"
1514
+ if [ "$_is_git_ws" -eq 1 ]; then
1515
+ if [ "$_cli_no_hooks" -eq 1 ] || [ "$_cli_hooks" = "false" ]; then
1516
+ _init_git_hooks="false"
1517
+ elif [ "$_cli_hooks" = "true" ] || [ "$_non_interactive" -eq 1 ]; then
1518
+ _init_git_hooks="true"
1519
+ elif [ -t 0 ]; then
1520
+ printf '%bConfigure automated Git hooks (post-merge auto-sync & wiki triggers)? [Y/n]: %b' "$_BOLD" "$_NC"
1521
+ read -r _h_ans
1522
+ case "$_h_ans" in
1523
+ n*|N*) _init_git_hooks="false" ;;
1524
+ *) _init_git_hooks="true" ;;
1525
+ esac
1526
+ else
1527
+ _init_git_hooks="true"
1528
+ fi
1529
+ fi
1530
+
1376
1531
  # ---- 1. Create config file if none exists ---------------------------------
1377
1532
  _config_created=0
1378
1533
  if [ -f "$_target_yaml" ]; then
@@ -1396,6 +1551,9 @@ ai_instructions: ${_cli_ai_instructions:-AGENTS.md}
1396
1551
  # VS Code / Cursor multi-root workspace file (default: false; e.g. true or workspace.code-workspace)
1397
1552
  code_workspace: ${_cli_code_workspace:-false}
1398
1553
 
1554
+ # Automated workspace Git hooks (default: true; e.g. post-merge auto-sync, plugin triggers)
1555
+ git_hooks: $_init_git_hooks
1556
+
1399
1557
  # Workspace plugins
1400
1558
  plugins:
1401
1559
 
@@ -1479,22 +1637,11 @@ YAML_EOF
1479
1637
  fi
1480
1638
 
1481
1639
  # ---- 7. Setup automated Git hooks if inside a Git repository ------------
1482
- if git -C "$_target_dir" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
1483
- if [ "$_cli_no_hooks" -eq 1 ] || [ "$_cli_hooks" = "false" ]; then
1484
- log_dim "Skipping Git hooks setup (--no-hooks specified)"
1485
- elif [ "$_cli_hooks" = "true" ] || [ "$_non_interactive" -eq 1 ]; then
1640
+ if [ "$_is_git_ws" -eq 1 ]; then
1641
+ if [ "$_init_git_hooks" = "true" ]; then
1486
1642
  cmd_hooks_install_dir "$_target_dir"
1487
1643
  else
1488
- if [ -t 0 ]; then
1489
- printf '%bConfigure automated Git hooks (post-merge auto-sync & wiki triggers)? [Y/n]: %b' "$_BOLD" "$_NC"
1490
- read -r _h_ans
1491
- case "$_h_ans" in
1492
- n*|N*) log_dim "Skipping Git hooks setup (run 'rnex hooks install' later)" ;;
1493
- *) cmd_hooks_install_dir "$_target_dir" ;;
1494
- esac
1495
- else
1496
- cmd_hooks_install_dir "$_target_dir"
1497
- fi
1644
+ log_dim "Skipping Git hooks setup (run 'rnex hooks install' later to enable)"
1498
1645
  fi
1499
1646
  fi
1500
1647
 
@@ -1820,19 +1967,50 @@ cmd_status() {
1820
1967
  fi
1821
1968
 
1822
1969
  _hooks_path="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
1970
+ _gh_active=0
1823
1971
  if [ "$_hooks_path" = ".rnex/hooks" ] || [ "$_hooks_path" = "$NEXUS_DIR/.rnex/hooks" ]; then
1824
- _active_trigger=""
1825
- if yaml_has_plugin "karpathy-llm"; then
1826
- _active_trigger="$(yaml_plugin_get "karpathy-llm" "lint_trigger")"
1827
- fi
1828
- if [ -n "$_active_trigger" ]; then
1829
- printf ' %b✓%b Git Hooks: active (.rnex/hooks — post-merge auto-sync, %s)\n' "$_G" "$_NC" "$_active_trigger"
1830
- else
1831
- printf ' %b✓%b Git Hooks: active (.rnex/hooks — post-merge auto-sync)\n' "$_G" "$_NC"
1832
- fi
1833
- else
1834
- printf ' %b○%b Git Hooks: not configured (run "rnex hooks install" to enable)\n' "$_DIM" "$_NC"
1972
+ _gh_active=1
1835
1973
  fi
1974
+
1975
+ case "$GIT_HOOKS_CONFIG" in
1976
+ false|no|0)
1977
+ if [ "$_gh_active" -eq 1 ]; then
1978
+ printf ' %b!%b Git Hooks: active in Git, but disabled in config (git_hooks: false; run "rnex fix" to reconcile)\n' "$_Y" "$_NC"
1979
+ else
1980
+ printf ' %b○%b Git Hooks: disabled in configuration (git_hooks: false)\n' "$_DIM" "$_NC"
1981
+ fi
1982
+ ;;
1983
+ true|yes|1)
1984
+ if [ "$_gh_active" -eq 1 ]; then
1985
+ _active_trigger=""
1986
+ if yaml_has_plugin "karpathy-llm"; then
1987
+ _active_trigger="$(yaml_plugin_get "karpathy-llm" "lint_trigger")"
1988
+ fi
1989
+ if [ -n "$_active_trigger" ]; then
1990
+ printf ' %b✓%b Git Hooks: active (git_hooks: true, .rnex/hooks — %s)\n' "$_G" "$_NC" "$_active_trigger"
1991
+ else
1992
+ printf ' %b✓%b Git Hooks: active (git_hooks: true, .rnex/hooks — post-merge auto-sync)\n' "$_G" "$_NC"
1993
+ fi
1994
+ else
1995
+ printf ' %b!%b Git Hooks: enabled in config (git_hooks: true), but not active in Git (run "rnex fix")\n' "$_Y" "$_NC"
1996
+ fi
1997
+ ;;
1998
+ *)
1999
+ if [ "$_gh_active" -eq 1 ]; then
2000
+ _active_trigger=""
2001
+ if yaml_has_plugin "karpathy-llm"; then
2002
+ _active_trigger="$(yaml_plugin_get "karpathy-llm" "lint_trigger")"
2003
+ fi
2004
+ if [ -n "$_active_trigger" ]; then
2005
+ printf ' %b✓%b Git Hooks: active (.rnex/hooks — post-merge auto-sync, %s)\n' "$_G" "$_NC" "$_active_trigger"
2006
+ else
2007
+ printf ' %b✓%b Git Hooks: active (.rnex/hooks — post-merge auto-sync)\n' "$_G" "$_NC"
2008
+ fi
2009
+ else
2010
+ printf ' %b○%b Git Hooks: not configured (run "rnex hooks install" to enable)\n' "$_DIM" "$_NC"
2011
+ fi
2012
+ ;;
2013
+ esac
1836
2014
  printf '\n'
1837
2015
 
1838
2016
  printf '%bWorkspace AI Context (Routing):%b\n' "$_BOLD" "$_NC"
@@ -1969,6 +2147,7 @@ cmd_fix() {
1969
2147
  _load_repos_dir
1970
2148
  _load_ai_instructions_file
1971
2149
  _load_code_workspace
2150
+ _load_git_hooks
1972
2151
  [ "$_fix_quiet" -eq 0 ] && log_ok "Upgraded workspace configuration and routing instructions to v$RNEX_VERSION"
1973
2152
  fi
1974
2153
  fi
@@ -1985,15 +2164,39 @@ cmd_fix() {
1985
2164
  # 3. Sync standard prompts to .rnex/prompts/
1986
2165
  sync_prompts
1987
2166
 
1988
- # 4. If Git hooks are installed, ensure hook scripts are up to date
1989
- _cur_hp="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
1990
- if [ "$_cur_hp" = ".rnex/hooks" ] || [ "$_cur_hp" = "$NEXUS_DIR/.rnex/hooks" ]; then
1991
- _hooks_dir="$NEXUS_DIR/.rnex/hooks"
1992
- _create_hook_script "$_hooks_dir/post-merge" "post-merge"
1993
- _create_hook_script "$_hooks_dir/post-commit" "post-commit"
1994
- _create_hook_script "$_hooks_dir/pre-commit" "pre-commit"
1995
- _create_hook_script "$_hooks_dir/pre-push" "pre-push"
1996
- fi
2167
+ # 4. Reconcile Git hooks according to configuration
2168
+ case "$GIT_HOOKS_CONFIG" in
2169
+ false|no|0)
2170
+ _cur_hp="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
2171
+ if [ "$_cur_hp" = ".rnex/hooks" ] || [ "$_cur_hp" = "$NEXUS_DIR/.rnex/hooks" ]; then
2172
+ cmd_hooks_uninstall_dir "$NEXUS_DIR"
2173
+ fi
2174
+ ;;
2175
+ true|yes|1)
2176
+ if git -C "$NEXUS_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
2177
+ _cur_hp="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
2178
+ if [ "$_cur_hp" != ".rnex/hooks" ] && [ "$_cur_hp" != "$NEXUS_DIR/.rnex/hooks" ]; then
2179
+ cmd_hooks_install_dir "$NEXUS_DIR"
2180
+ else
2181
+ _hooks_dir="$NEXUS_DIR/.rnex/hooks"
2182
+ _create_hook_script "$_hooks_dir/post-merge" "post-merge"
2183
+ _create_hook_script "$_hooks_dir/post-commit" "post-commit"
2184
+ _create_hook_script "$_hooks_dir/pre-commit" "pre-commit"
2185
+ _create_hook_script "$_hooks_dir/pre-push" "pre-push"
2186
+ fi
2187
+ fi
2188
+ ;;
2189
+ *)
2190
+ _cur_hp="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
2191
+ if [ "$_cur_hp" = ".rnex/hooks" ] || [ "$_cur_hp" = "$NEXUS_DIR/.rnex/hooks" ]; then
2192
+ _hooks_dir="$NEXUS_DIR/.rnex/hooks"
2193
+ _create_hook_script "$_hooks_dir/post-merge" "post-merge"
2194
+ _create_hook_script "$_hooks_dir/post-commit" "post-commit"
2195
+ _create_hook_script "$_hooks_dir/pre-commit" "pre-commit"
2196
+ _create_hook_script "$_hooks_dir/pre-push" "pre-push"
2197
+ fi
2198
+ ;;
2199
+ esac
1997
2200
 
1998
2201
  # 5. Reconcile plugins
1999
2202
  sync_plugins
@@ -2404,8 +2607,8 @@ cmd_help() {
2404
2607
  install [dir] Install rnex & repo-nexus globally into ~/.local/bin (or custom dir)
2405
2608
  fix [-y] [--quiet] Reconcile workspace, plugins, prompts & member .rnex/ (alias: sync)
2406
2609
  update [-y] Upgrade workspace configuration and routing instructions (alias: upgrade)
2407
- hooks <install|uninstall|status>
2408
- Manage config-driven automated Git hooks (.rnex/hooks)
2610
+ hooks <install|uninstall|status> [--local]
2611
+ Manage automated Git hooks (--local writes to .local.rnex.yaml)
2409
2612
  completion <shell> Generate shell completion script (bash, zsh, fish)
2410
2613
 
2411
2614
  REPO MANAGEMENT