← Back to task

Commit e8acd7f2

commit e8acd7f28f5ca156ab12b173b07aab699d2c4bda
Author: Ben Sima <ben@bensima.com>
Date:   Wed Dec 31 00:03:16 2025

    Omni/Ide/hooks: Make hooks defensive about missing env
    
    Add ensure-env.sh helper that hooks source to set up environment:
    - Sets CODEROOT from git repo root
    - Adds essential paths to PATH
    - Optionally loads direnv environment
    - Handles errors gracefully
    
    Hooks now work for users without direnv auto-loaded (e.g., Ava).
    Non-critical checks are skipped with a warning if env unavailable.
    
    Task-Id: t-298.4

diff --git a/Omni/Ide/hooks/commit-msg b/Omni/Ide/hooks/commit-msg
index a91b651d..6566f79d 100755
--- a/Omni/Ide/hooks/commit-msg
+++ b/Omni/Ide/hooks/commit-msg
@@ -1,4 +1,11 @@
 #!/usr/bin/env bash
+
+# Ensure environment is loaded (for users without direnv auto-hook)
+source "$(dirname "$0")/ensure-env.sh" || {
+  echo "warn: commit-msg: environment not available, skipping gitlint check"
+  exit 0
+}
+
 if ! gitlint --ignore-stdin --staged --msg-filename "$1" run-hook; then
   backup="$CODEROOT"/.git/COMMIT_EDITMSG.backup
   cp "$1" "$backup"
diff --git a/Omni/Ide/hooks/ensure-env.sh b/Omni/Ide/hooks/ensure-env.sh
new file mode 100755
index 00000000..d0c645c3
--- /dev/null
+++ b/Omni/Ide/hooks/ensure-env.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+#
+# Helper script sourced by git hooks to ensure environment is available.
+# This makes hooks work for users who don't have direnv auto-loaded (e.g., Ava).
+#
+# Usage: source "$(dirname "$0")/ensure-env.sh"
+##
+
+# If CODEROOT is already set, environment is good
+if [[ -n "${CODEROOT:-}" ]]; then
+  return 0 2>/dev/null || exit 0
+fi
+
+# Find the repo root (where .envrc lives)
+repo_root="$(git rev-parse --show-toplevel 2>/dev/null)"
+if [[ -z "$repo_root" ]]; then
+  echo "warn: hooks/ensure-env.sh: not in a git repository" >&2
+  return 1 2>/dev/null || exit 1
+fi
+
+# Check if .envrc exists
+if [[ ! -f "$repo_root/.envrc" ]]; then
+  echo "warn: hooks/ensure-env.sh: no .envrc found at $repo_root" >&2
+  return 1 2>/dev/null || exit 1
+fi
+
+# Set CODEROOT directly from repo root (matching what .envrc does)
+export CODEROOT="$repo_root"
+
+# Add essential paths that .envrc sets
+export PATH="$CODEROOT/Omni/Ide:$CODEROOT/_/bin:$CODEROOT/node_modules/.bin:$PATH"
+export TMPDIR="$CODEROOT/_/tmp"
+
+# Try to load full direnv environment if available
+# This is optional - we've set the minimum needed above
+if command -v direnv &>/dev/null; then
+  # Use direnv exec to run in the environment, but we're sourcing so just try export
+  eval "$(direnv export bash 2>/dev/null)" || true
+fi
+
+return 0 2>/dev/null || exit 0
diff --git a/Omni/Ide/hooks/post-checkout b/Omni/Ide/hooks/post-checkout
index a360517c..2c344c15 100755
--- a/Omni/Ide/hooks/post-checkout
+++ b/Omni/Ide/hooks/post-checkout
@@ -1,18 +1,28 @@
 #!/usr/bin/env bash
 set -e
-function MakeTags {
-  ${CODEROOT:?}/Omni/Ide/MakeTags.py
-}
-old=$1
-new=$2
-# filter out only the changed haskell files
-mapfile -t changed < <(git diff --diff-filter=d --name-only "$old" "$new" -- '*.hs')
-if [[ ! -r tags ]] || [[ ! -r TAGS ]]
-then
-    MakeTags "$CODEROOT"/**/*
-elif [[ ${#changed[@]} -gt 0 ]]
-then
-    MakeTags "${changed[@]}"
+
+# Ensure environment is loaded (for users without direnv auto-hook)
+# Note: We don't exit on failure here because branchless hooks should still run
+env_loaded=true
+source "$(dirname "$0")/ensure-env.sh" || env_loaded=false
+
+if [[ "$env_loaded" == "true" ]]; then
+  function MakeTags {
+    "${CODEROOT}"/Omni/Ide/MakeTags.py
+  }
+  old=$1
+  new=$2
+  # filter out only the changed haskell files
+  mapfile -t changed < <(git diff --diff-filter=d --name-only "$old" "$new" -- '*.hs')
+  if [[ ! -r tags ]] || [[ ! -r TAGS ]]
+  then
+      MakeTags "$CODEROOT"/**/*
+  elif [[ ${#changed[@]} -gt 0 ]]
+  then
+      MakeTags "${changed[@]}"
+  fi
+else
+  echo "warn: post-checkout: environment not available, skipping tag generation"
 fi
 
 ## START BRANCHLESS CONFIG
diff --git a/Omni/Ide/hooks/post-merge b/Omni/Ide/hooks/post-merge
index bf0e9961..d2d9c7e2 100755
--- a/Omni/Ide/hooks/post-merge
+++ b/Omni/Ide/hooks/post-merge
@@ -1,5 +1,15 @@
 #!/usr/bin/env bash
-"${CODEROOT:?}"/Omni/Ide/hooks/post-checkout 'HEAD@{1}' HEAD
+
+# Ensure environment is loaded (for users without direnv auto-hook)
+# Note: We don't exit on failure here because branchless hooks should still run
+source "$(dirname "$0")/ensure-env.sh" || {
+  echo "warn: post-merge: environment not available, skipping post-checkout call"
+  # Still run branchless hooks
+  git branchless hook post-merge "$@"
+  exit 0
+}
+
+"${CODEROOT}"/Omni/Ide/hooks/post-checkout 'HEAD@{1}' HEAD
 
 ## START BRANCHLESS CONFIG
 
diff --git a/Omni/Ide/hooks/pre-commit b/Omni/Ide/hooks/pre-commit
index 06f17163..f0a73987 100755
--- a/Omni/Ide/hooks/pre-commit
+++ b/Omni/Ide/hooks/pre-commit
@@ -4,10 +4,17 @@
 # - guard against lint errors
 ##
   set -e
+
+  # Ensure environment is loaded (for users without direnv auto-hook)
+  source "$(dirname "$0")/ensure-env.sh" || {
+    echo "warn: pre-commit: environment not available, skipping checks"
+    exit 0
+  }
+
   mapfile -t changed < <(git diff-index --cached --name-only HEAD)
   for ns in "${changed[@]}"
   do
-    version=$("${CODEROOT:?}"/Omni/Ide/version.sh "$ns")
+    version=$("${CODEROOT}"/Omni/Ide/version.sh "$ns")
     if [[ $version -eq -1 ]]; then
       echo "info:  version:  $ns:  deleted"
     elif [[ $version -lt 1 ]]; then
diff --git a/Omni/Ide/hooks/pre-push b/Omni/Ide/hooks/pre-push
index 86e6e3c6..711fb344 100755
--- a/Omni/Ide/hooks/pre-push
+++ b/Omni/Ide/hooks/pre-push
@@ -1,6 +1,12 @@
 #!/usr/bin/env bash
 set -euo pipefail
 
+# Ensure environment is loaded (for users without direnv auto-hook)
+source "$(dirname "$0")/ensure-env.sh" || {
+  echo "warn: pre-push: environment not available, skipping checks"
+  exit 0
+}
+
 # Task manager: Ensure tasks are exported before push
 if [ -d .tasks ]; then
     task export --flush 2>/dev/null || true