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